mirror of https://github.com/vitalif/e2fsprogs
Integrate new blkid library.
parent
76ea3a2c7f
commit
e12f2ae74c
|
@ -1,3 +1,7 @@
|
|||
2003-01-23 Theodore Ts'o <tytso@mit.edu>
|
||||
|
||||
* Makefile.in, configure, configure.in: Integrate new blkid library.
|
||||
|
||||
2002-11-09 Theodore Ts'o <tytso@mit.edu>
|
||||
|
||||
* Release of E2fsprogs 1.32
|
||||
|
|
|
@ -65,6 +65,7 @@ LIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@
|
|||
LIBE2P = $(LIB)/libe2p@LIB_EXT@
|
||||
LIBEXT2FS = $(LIB)/libext2fs@LIB_EXT@
|
||||
LIBUUID = $(LIB)/libuuid@LIB_EXT@ @SOCKET_LIB@
|
||||
LIBBLKID = $(LIB)/libblkid@LIB_EXT@
|
||||
DEPLIBUUID = $(LIB)/libuuid@LIB_EXT@
|
||||
|
||||
STATIC_LIBSS = $(LIB)/libss@STATIC_LIB_EXT@
|
||||
|
@ -72,6 +73,7 @@ STATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@
|
|||
STATIC_LIBE2P = $(LIB)/libe2p@STATIC_LIB_EXT@
|
||||
STATIC_LIBEXT2FS = $(LIB)/libext2fs@STATIC_LIB_EXT@
|
||||
STATIC_LIBUUID = $(LIB)/libuuid@STATIC_LIB_EXT@ @SOCKET_LIB@
|
||||
STATIC_LIBBLKID = $(LIB)/libblkid@STATIC_LIB_EXT@
|
||||
DEPSTATIC_LIBUUID = $(LIB)/libuuid@STATIC_LIB_EXT@
|
||||
|
||||
PROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@
|
||||
|
@ -79,6 +81,7 @@ PROFILED_LIBCOM_ERR = $(LIB)/libcom_err@PROFILED_LIB_EXT@
|
|||
PROFILED_LIBE2P = $(LIB)/libe2p@PROFILED_LIB_EXT@
|
||||
PROFILED_LIBEXT2FS = $(LIB)/libext2fs@PROFILED_LIB_EXT@
|
||||
PROFILED_LIBUUID = $(LIB)/libuuid@PROFILED_LIB_EXT@ @SOCKET_LIB@
|
||||
PROFILED_LIBBLKID = $(LIB)/libblkid@PROFILED_LIB_EXT@
|
||||
DEPPROFILED_LIBUUID = $(LIB)/libuuid@PROFILED_LIB_EXT@
|
||||
|
||||
#
|
||||
|
|
|
@ -11,7 +11,7 @@ INSTALL = @INSTALL@
|
|||
@DEBUGFS_CMT@DEBUGFS_DIR= debugfs
|
||||
@LINUX_CMT@EVMS_DIR= lib/evms
|
||||
|
||||
LIB_SUBDIRS=lib/et lib/ss lib/e2p lib/ext2fs lib/uuid # lib/finddev
|
||||
LIB_SUBDIRS=lib/et lib/ss lib/e2p lib/ext2fs lib/uuid lib/blkid
|
||||
PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs $(EVMS_DIR)
|
||||
SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests
|
||||
|
||||
|
|
|
@ -4676,7 +4676,7 @@ EOF
|
|||
|
||||
fi
|
||||
fi
|
||||
for ac_func in chflags getrusage llseek lseek64 open64 getmntinfo strcasecmp srandom fchown mallinfo fdatasync strnlen sysconf pathconf
|
||||
for ac_func in chflags getrusage llseek lseek64 open64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen sysconf pathconf
|
||||
do
|
||||
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
|
||||
echo "configure:4683: checking for $ac_func" >&5
|
||||
|
@ -5028,7 +5028,7 @@ ac_given_INSTALL="$INSTALL"
|
|||
|
||||
trap 'rm -fr `echo "MCONFIG Makefile util/Makefile util/subst.conf lib/et/Makefile
|
||||
lib/ss/Makefile lib/ext2fs/Makefile lib/e2p/Makefile lib/uuid/Makefile
|
||||
lib/evms/Makefile
|
||||
lib/blkid/Makefile lib/blkid/blkid_types.h lib/evms/Makefile
|
||||
misc/Makefile ext2ed/Makefile e2fsck/Makefile debugfs/Makefile \
|
||||
tests/Makefile tests/progs/Makefile $rmakefile doc/Makefile
|
||||
intl/Makefile po/Makefile.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
|
||||
|
@ -5213,7 +5213,7 @@ cat >> $CONFIG_STATUS <<EOF
|
|||
|
||||
CONFIG_FILES=\${CONFIG_FILES-"MCONFIG Makefile util/Makefile util/subst.conf lib/et/Makefile
|
||||
lib/ss/Makefile lib/ext2fs/Makefile lib/e2p/Makefile lib/uuid/Makefile
|
||||
lib/evms/Makefile
|
||||
lib/blkid/Makefile lib/blkid/blkid_types.h lib/evms/Makefile
|
||||
misc/Makefile ext2ed/Makefile e2fsck/Makefile debugfs/Makefile \
|
||||
tests/Makefile tests/progs/Makefile $rmakefile doc/Makefile
|
||||
intl/Makefile po/Makefile.in"}
|
||||
|
|
|
@ -595,7 +595,7 @@ if test "$e2fsprogs_cv_struct_st_flags" = yes; then
|
|||
AC_DEFINE(HAVE_STAT_FLAGS)
|
||||
fi
|
||||
fi
|
||||
AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 getmntinfo strcasecmp srandom fchown mallinfo fdatasync strnlen sysconf pathconf)
|
||||
AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen sysconf pathconf)
|
||||
dnl
|
||||
dnl Check to see if -lsocket is required (solaris) to make something
|
||||
dnl that uses socket() to compile; this is needed for the UUID library
|
||||
|
@ -736,7 +736,7 @@ if test -d ${srcdir}/resize ; then
|
|||
fi
|
||||
AC_OUTPUT(MCONFIG Makefile util/Makefile util/subst.conf lib/et/Makefile
|
||||
lib/ss/Makefile lib/ext2fs/Makefile lib/e2p/Makefile lib/uuid/Makefile
|
||||
lib/evms/Makefile
|
||||
lib/blkid/Makefile lib/blkid/blkid_types.h lib/evms/Makefile
|
||||
misc/Makefile ext2ed/Makefile e2fsck/Makefile debugfs/Makefile \
|
||||
tests/Makefile tests/progs/Makefile $rmakefile doc/Makefile
|
||||
intl/Makefile po/Makefile.in)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
2002-10-04 Jordan Breeding <jordan.breeding@attbi.com>
|
||||
|
||||
* Forward port to e2fsprogs 1.30
|
||||
|
||||
2001-09-20 Andreas Dilger <adilger@turbolinux.com>
|
||||
|
||||
* Initial release of libblkid.
|
|
@ -0,0 +1,156 @@
|
|||
# Makefile for libblkid
|
||||
#
|
||||
# Copyright (C) 2001 Theodore Ts'o (tytso@mit.edu)
|
||||
#
|
||||
# This file can be redistributed under the terms of the
|
||||
# GNU Lesser General Public License
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_builddir = ../..
|
||||
my_dir = lib/blkid
|
||||
INSTALL = @INSTALL@
|
||||
|
||||
@MCONFIG@
|
||||
|
||||
all::
|
||||
|
||||
SMANPAGES= libblkid.3
|
||||
|
||||
OBJS= cache.o dev.o devname.o devno.o getsize.o llseek.o probe.o \
|
||||
read.o resolve.o save.o tag.o
|
||||
|
||||
SRCS= $(srcdir)/cache.c $(srcdir)/dev.c $(srcdir)/devname.c $(srcdir)/devno.c \
|
||||
$(srcdir)/getsize.c $(srcdir)/llseek.c $(srcdir)/probe.c \
|
||||
$(srcdir)/read.c $(srcdir)/resolve.c $(srcdir)/save.c $(srcdir)/tag.c
|
||||
|
||||
HFILES= blkid.h list.h
|
||||
HFILES_IN= blkid_types.h
|
||||
|
||||
LIBRARY= libblkid
|
||||
LIBDIR= blkid
|
||||
|
||||
ELF_VERSION = 2.0
|
||||
ELF_SO_VERSION = 2
|
||||
ELF_IMAGE = libblkid
|
||||
ELF_MYDIR = blkid
|
||||
ELF_INSTALL_DIR = $(root_libdir)
|
||||
ELF_OTHER_LIBS =
|
||||
|
||||
BSDLIB_VERSION = 2.0
|
||||
BSDLIB_IMAGE = libblkid
|
||||
BSDLIB_MYDIR = blkid
|
||||
BSDLIB_INSTALL_DIR = $(root_libdir)
|
||||
|
||||
@MAKEFILE_LIBRARY@
|
||||
@MAKEFILE_DLL@
|
||||
@MAKEFILE_ELF@
|
||||
@MAKEFILE_BSDLIB@
|
||||
@MAKEFILE_PROFILE@
|
||||
@MAKEFILE_CHECKER@
|
||||
|
||||
LIBS_BLKID= $(STATIC_LIBBLKID) $(STATIC_LIBUUID)
|
||||
DEPLIBS_BLKID= $(DEPSTATIC_LIBBLKID) $(DEPSTATIC_LIBUUID)
|
||||
|
||||
.c.o:
|
||||
$(CC) -Wall $(ALL_CFLAGS) -c $< -o $@
|
||||
@PROFILE_CMT@ $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
|
||||
@CHECKER_CMT@ $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
|
||||
@DLL_CMT@ (export JUMP_DIR=`pwd`/jump; $(CC) -B$(JUMP_PREFIX) $(ALL_CFLAGS) \
|
||||
@DLL_CMT@ -o jump/$*.o -c $<)
|
||||
@ELF_CMT@ $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
|
||||
@BSDLIB_CMT@ $(CC) $(ALL_CFLAGS) -fpic -o pic/$*.o -c $<
|
||||
|
||||
all:: $(SMANPAGES)
|
||||
|
||||
libblkid.3: $(DEP_SUBSTITUTE) $(srcdir)/libblkid.3.in
|
||||
$(SUBSTITUTE) $(srcdir)/libblkid.3.in libblkid.3
|
||||
|
||||
tst_cache: $(srcdir)/cache.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_cache -DTEST_PROGRAM $(srcdir)/cache.c $(LIBS_BLKID) $(LIBUUID) $(ALL_CFLAGS)
|
||||
|
||||
tst_dev: $(srcdir)/dev.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_dev -DTEST_PROGRAM $(srcdir)/dev.c $(LIBS_BLKID) $(ALL_CFLAGS)
|
||||
|
||||
tst_devname: $(srcdir)/devname.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_devname -DTEST_PROGRAM $(srcdir)/devname.c $(LIBS_BLKID) $(ALL_CFLAGS)
|
||||
|
||||
tst_devno: $(srcdir)/devno.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_devno -DTEST_PROGRAM $(srcdir)/devno.c $(LIBS_BLKID) $(ALL_CFLAGS)
|
||||
|
||||
tst_getsize: $(srcdir)/getsize.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_getsize -DTEST_PROGRAM $(srcdir)/getsize.c $(LIBS_BLKID) $(ALL_CFLAGS)
|
||||
|
||||
tst_probe: $(srcdir)/probe.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_probe -DTEST_PROGRAM $(srcdir)/probe.c $(LIBS_BLKID) $(LIBUUID) $(ALL_CFLAGS)
|
||||
|
||||
tst_read: $(srcdir)/read.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_read -DTEST_PROGRAM $(srcdir)/read.c $(LIBS_BLKID) $(ALL_CFLAGS)
|
||||
|
||||
tst_resolve: $(srcdir)/resolve.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_resolve -DTEST_PROGRAM $(srcdir)/resolve.c $(LIBS_BLKID) $(LIBUUID) $(ALL_CFLAGS)
|
||||
|
||||
tst_save: $(srcdir)/save.c $(DEPLIBS_BLKID)
|
||||
$(CC) -Wall -o tst_save -DTEST_PROGRAM $(srcdir)/save.c $(LIBS_BLKID) $(LIBUUID) $(ALL_CFLAGS)
|
||||
|
||||
check:: tst_cache tst_dev tst_devname tst_devno tst_getsize tst_probe \
|
||||
tst_read tst_resolve tst_save
|
||||
|
||||
installdirs::
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(libdir) \
|
||||
$(DESTDIR)$(includedir)/blkid
|
||||
|
||||
install:: all installdirs
|
||||
$(INSTALL_DATA) libblkid.a $(DESTDIR)$(libdir)/libblkid.a
|
||||
$(CHMOD) 644 $(DESTDIR)$(libdir)/libblkid.a
|
||||
-$(RANLIB) $(DESTDIR)$(libdir)/libblkid.a
|
||||
$(CHMOD) $(LIBMODE) $(DESTDIR)$(libdir)/libblkid.a
|
||||
set -e; for i in $(HFILES); do \
|
||||
$(INSTALL_DATA) $(srcdir)/$$i $(DESTDIR)$(includedir)/blkid/$$i; \
|
||||
done
|
||||
set -e; for i in $(HFILES_IN); do \
|
||||
$(INSTALL_DATA) $$i $(DESTDIR)$(includedir)/blkid/$$i; \
|
||||
done
|
||||
for i in $(SMANPAGES); do \
|
||||
$(INSTALL_DATA) $$i $(DESTDIR)$(man3dir)/$$i; \
|
||||
done
|
||||
|
||||
uninstall::
|
||||
$(RM) -f $(DESTDIR)$(libdir)/libblkid.a
|
||||
$(RM) -rf $(DESTDIR)$(includedir)/blkid
|
||||
for i in $(SMANPAGES); do \
|
||||
$(RM) -f $(DESTDIR)$(man3dir)/$$i; \
|
||||
done
|
||||
|
||||
clean::
|
||||
$(RM) -f \#* *.s *.o *.orig *.a *~ *.bak tst_* core profiled/* checker/*
|
||||
$(RM) -f ../libblkid.a ../libblkid_p.a $(SMANPAGES)
|
||||
|
||||
mostlyclean:: clean
|
||||
distclean:: clean
|
||||
$(RM) -f .depend Makefile $(srcdir)/TAGS $(srcdir)/Makefile.in.old
|
||||
|
||||
# +++ Dependency line eater +++
|
||||
#
|
||||
# Makefile dependencies follow. This must be the last section in
|
||||
# the Makefile.in file
|
||||
#
|
||||
cache.o: $(srcdir)/cache.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
dev.o: $(srcdir)/dev.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
devname.o: $(srcdir)/devname.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
devno.o: $(srcdir)/devno.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
getsize.o: $(srcdir)/getsize.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
llseek.o: $(srcdir)/llseek.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
read.o: $(srcdir)/read.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h $(top_srcdir)/lib/uuid/uuid.h
|
||||
save.o: $(srcdir)/save.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
||||
tag.o: $(srcdir)/tag.c $(srcdir)/blkid.h $(srcdir)/list.h \
|
||||
$(top_builddir)/lib/blkid/blkid_types.h
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* blkid.h - Interface for libblkid, a library to identify block devices
|
||||
*
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _BLKID_BLKID_H
|
||||
#define _BLKID_BLKID_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLKID_VERSION "1.2.0"
|
||||
#define BLKID_DATE "22-Nov-2001"
|
||||
|
||||
#include "blkid/list.h"
|
||||
#include "blkid/blkid_types.h"
|
||||
|
||||
typedef __s64 blkid_loff_t;
|
||||
|
||||
/*
|
||||
* This describes the attributes of a specific device.
|
||||
* We can traverse all of the tags by bid_tags (linking to the tag bit_names).
|
||||
* The bid_label and bid_uuid fields are shortcuts to the LABEL and UUID tag
|
||||
* values, if they exist.
|
||||
*/
|
||||
typedef struct blkid_dev
|
||||
{
|
||||
struct list_head bid_devs; /* All devices in the cache */
|
||||
struct list_head bid_tags; /* All tags for this device */
|
||||
char *bid_name; /* Device inode pathname */
|
||||
char *bid_type; /* Preferred device TYPE */
|
||||
blkid_loff_t bid_size; /* Filesystem size in bytes */
|
||||
blkid_loff_t bid_free; /* Filesystem free in bytes */
|
||||
blkid_loff_t bid_devsize; /* Device size in bytes */
|
||||
dev_t bid_devno; /* Device major/minor number */
|
||||
time_t bid_time; /* Last update time of device */
|
||||
unsigned int bid_id; /* Unique cache id for device */
|
||||
unsigned int bid_flags; /* Device status bitflags */
|
||||
char *bid_label; /* Shortcut to device LABEL */
|
||||
char *bid_uuid; /* Shortcut to binary UUID */
|
||||
unsigned long bid_unused[13]; /* Fields for future use */
|
||||
} blkid_dev;
|
||||
|
||||
#define BLKID_BID_FL_VERIFIED 0x0001 /* Device data validated from disk */
|
||||
#define BLKID_BID_FL_MTYPE 0x0002 /* Device has multiple type matches */
|
||||
|
||||
/*
|
||||
* Each tag defines a NAME=value pair for a particular device. The tags
|
||||
* are linked via bit_names for a single device, so that traversing the
|
||||
* names list will get you a list of all tags associated with a device.
|
||||
* They are also linked via bit_values for all devices, so one can easily
|
||||
* search all tags with a given NAME for a specific value.
|
||||
*/
|
||||
typedef struct blkid_tag
|
||||
{
|
||||
struct list_head bit_tags; /* All tags for this device */
|
||||
struct list_head bit_names; /* All tags with given NAME */
|
||||
char *bit_name; /* NAME of tag (shared) */
|
||||
char *bit_val; /* value of tag */
|
||||
struct blkid_dev *bit_dev; /* pointer to device */
|
||||
unsigned long bit_unused[9]; /* Fields for future use */
|
||||
} blkid_tag;
|
||||
|
||||
/*
|
||||
* Minimum number of seconds between device probes, even when reading
|
||||
* from the cache. This is to avoid re-probing all devices which were
|
||||
* just probed by another program that does not share the cache.
|
||||
*/
|
||||
#define BLKID_PROBE_MIN 2
|
||||
|
||||
/*
|
||||
* Time in seconds an entry remains verified in the in-memory cache
|
||||
* before being reverified (in case of long-running processes that
|
||||
* keep a cache in memory and continue to use it for a long time).
|
||||
*/
|
||||
#define BLKID_PROBE_INTERVAL 200
|
||||
|
||||
/* This describes an entire blkid cache file and probed devices.
|
||||
* We can traverse all of the found devices via bic_list.
|
||||
* We can traverse all of the tag types by bic_tags, which hold empty tags
|
||||
* for each tag type. Those tags can be used as list_heads for iterating
|
||||
* through all devices with a specific tag type (e.g. LABEL).
|
||||
*/
|
||||
typedef struct blkid_cache
|
||||
{
|
||||
struct list_head bic_devs; /* List head of all devices */
|
||||
struct list_head bic_tags; /* List head of all tag types */
|
||||
time_t bic_time; /* Last probe time */
|
||||
unsigned int bic_idmax; /* Highest ID assigned */
|
||||
unsigned int bic_flags; /* Status flags of the cache */
|
||||
unsigned long bic_unused[9]; /* Fields for future use */
|
||||
} blkid_cache;
|
||||
|
||||
#define BLKID_BIC_FL_PARSED 0x0001 /* We parsed a cache file */
|
||||
#define BLKID_BIC_FL_PROBED 0x0002 /* We probed /proc/partition devices */
|
||||
#define BLKID_BIC_FL_CHANGED 0x0004 /* Cache has changed from disk */
|
||||
|
||||
extern char *string_copy(const char *s);
|
||||
extern char *stringn_copy(const char *s, const int length);
|
||||
extern void string_free(char *s);
|
||||
extern blkid_cache *blkid_new_cache(void);
|
||||
extern void blkid_free_cache(blkid_cache *cache);
|
||||
|
||||
#define BLKID_CACHE_FILE "/etc/blkid.tab"
|
||||
extern const char *devdirs[];
|
||||
|
||||
#define BLKID_ERR_IO 5
|
||||
#define BLKID_ERR_PROC 9
|
||||
#define BLKID_ERR_MEM 12
|
||||
#define BLKID_ERR_CACHE 14
|
||||
#define BLKID_ERR_DEV 19
|
||||
#define BLKID_ERR_PARAM 22
|
||||
#define BLKID_ERR_BIG 27
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_CACHE
|
||||
#define DEBUG_DUMP
|
||||
#define DEBUG_DEV
|
||||
#define DEBUG_DEVNAME
|
||||
#define DEBUG_DEVNO
|
||||
#define DEBUG_PROBE
|
||||
#define DEBUG_READ
|
||||
#define DEBUG_RESOLVE
|
||||
#define DEBUG_SAVE
|
||||
#define DEBUG_TAG
|
||||
#define CHECK_TAG
|
||||
#endif
|
||||
|
||||
#if defined(TEST_PROGRAM) && !defined(DEBUG_DUMP)
|
||||
#define DEBUG_DUMP
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_DUMP
|
||||
static inline void DEB_DUMP_TAG(blkid_tag *tag)
|
||||
{
|
||||
if (!tag) {
|
||||
printf(" tag: NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf(" tag: %s=\"%s\"\n", tag->bit_name, tag->bit_val);
|
||||
}
|
||||
|
||||
static inline void DEB_DUMP_DEV(blkid_dev *dev)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
if (!dev) {
|
||||
printf(" dev: NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf(" dev: name = %s\n", dev->bid_name);
|
||||
printf(" dev: DEVNO=\"0x%0Lx\"\n", dev->bid_devno);
|
||||
printf(" dev: ID=\"%u\"\n", dev->bid_id);
|
||||
printf(" dev: TIME=\"%lu\"\n", dev->bid_time);
|
||||
printf(" dev: size = %Lu\n", dev->bid_size);
|
||||
printf(" dev: flags = 0x%08X\n", dev->bid_flags);
|
||||
|
||||
list_for_each(p, &dev->bid_tags) {
|
||||
blkid_tag *tag = list_entry(p, blkid_tag, bit_tags);
|
||||
DEB_DUMP_TAG(tag);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static inline void DEB_DUMP_CACHE(blkid_cache *cache)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
if (!cache) {
|
||||
printf("cache: NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("cache: time = %lu\n", cache->bic_time);
|
||||
printf("cache: idmax = %u\n", cache->bic_idmax);
|
||||
printf("cache: flags = 0x%08X\n", cache->bic_flags);
|
||||
|
||||
list_for_each(p, &cache->bic_devs) {
|
||||
blkid_dev *dev = list_entry(p, blkid_dev, bid_devs);
|
||||
DEB_DUMP_DEV(dev);
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define DEB_DUMP_TAG(tag) do {} while (0)
|
||||
#define DEB_DUMP_DEV(dev) do {} while (0)
|
||||
#define DEB_DUMP_CACHE(cache) do {} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Primitive disk functions: llseek.c, getsize.c
|
||||
*/
|
||||
extern blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence);
|
||||
extern blkid_loff_t blkid_get_dev_size(int fd);
|
||||
|
||||
/*
|
||||
* Getting data from the cache file: read.c
|
||||
*/
|
||||
int blkid_read_cache_line(blkid_cache *cache, blkid_dev **dev_p, char *cp);
|
||||
int blkid_read_cache_file(blkid_cache **cache, FILE *file);
|
||||
int blkid_read_cache(blkid_cache **cache, const char *filename);
|
||||
|
||||
/*
|
||||
* Save data to the cache file: save.c
|
||||
*/
|
||||
int blkid_save_cache_file(blkid_cache *cache, FILE *file);
|
||||
int blkid_save_cache(blkid_cache *cache, char *filename);
|
||||
|
||||
/*
|
||||
* Identify a device by inode name: probe.c
|
||||
*/
|
||||
extern blkid_dev *blkid_devname_to_dev(const char *devname,
|
||||
blkid_loff_t size);
|
||||
|
||||
/*
|
||||
* Locate a device by inode name: devname.c
|
||||
*/
|
||||
extern blkid_dev *blkid_find_devname(blkid_cache *cache, const char *devname);
|
||||
extern blkid_dev *blkid_verify_devname(blkid_cache *cache, blkid_dev *dev);
|
||||
extern blkid_dev *blkid_get_devname(blkid_cache *cache, const char *devname);
|
||||
extern int blkid_probe_all(blkid_cache **cache);
|
||||
|
||||
/*
|
||||
* Locate a device by device major/minor number: devno.c
|
||||
*/
|
||||
extern char *blkid_devno_to_devname(dev_t devno);
|
||||
extern blkid_dev *blkid_find_devno(blkid_cache *cache, dev_t devno);
|
||||
extern blkid_dev *blkid_get_devno(blkid_cache *cache, dev_t devno);
|
||||
|
||||
/*
|
||||
* Functions to create and find a specific tag type: tag.c
|
||||
*/
|
||||
extern blkid_tag *blkid_new_tag(void);
|
||||
extern void blkid_free_tag(blkid_tag *tag);
|
||||
extern int blkid_create_tag(blkid_dev *dev, blkid_tag **tag,
|
||||
const char *name, const char *value,
|
||||
const int vlength);
|
||||
extern blkid_tag *blkid_token_to_tag(const char *token);
|
||||
extern blkid_tag *blkid_find_tv_tags(blkid_tag *head, const char *value);
|
||||
extern blkid_tag *blkid_find_tag_dev(blkid_dev *dev, blkid_tag *tag);
|
||||
extern blkid_tag *blkid_find_head_cache(blkid_cache *cache, blkid_tag *tag);
|
||||
extern blkid_tag *blkid_find_tag_cache(blkid_cache *cache, blkid_tag *tag);
|
||||
extern blkid_tag *blkid_get_tag_cache(blkid_cache *cache, blkid_tag *tag);
|
||||
|
||||
/*
|
||||
* Functions to create and find a specific tag type: dev.c
|
||||
*/
|
||||
extern blkid_dev *blkid_new_dev(void);
|
||||
extern void blkid_free_dev(blkid_dev *dev);
|
||||
extern blkid_dev *blkid_add_dev_to_cache(blkid_cache *cache, blkid_dev *dev);
|
||||
|
||||
/*
|
||||
* Helper functions for primarily single use: resolve.c
|
||||
*/
|
||||
extern char *blkid_get_tagname_devname(blkid_cache *cache, const char *tagname,
|
||||
const char *devname);
|
||||
extern char *blkid_get_token(blkid_cache *cache, const char *token,
|
||||
const char *value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BLKID_BLKID_H */
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef _EXT2_TYPES_H
|
||||
#define _EXT2_TYPES_H
|
||||
|
||||
/*
|
||||
* If linux/types.h is already been included, assume it has defined
|
||||
* everything we need. (cross fingers)
|
||||
*/
|
||||
#ifndef _LINUX_TYPES_H
|
||||
|
||||
typedef unsigned char __u8;
|
||||
typedef signed char __s8;
|
||||
|
||||
#if (@SIZEOF_INT@ == 8)
|
||||
typedef int __s64;
|
||||
typedef unsigned int __u64;
|
||||
#elif (@SIZEOF_LONG@ == 8)
|
||||
typedef long __s64;
|
||||
typedef unsigned long __u64;
|
||||
#elif (@SIZEOF_LONG_LONG@ == 8)
|
||||
#if defined(__GNUC__)
|
||||
typedef __signed__ long long __s64;
|
||||
#else
|
||||
typedef signed long long __s64;
|
||||
#endif
|
||||
typedef unsigned long long __u64;
|
||||
#endif
|
||||
|
||||
#if (@SIZEOF_INT@ == 2)
|
||||
typedef int __s16;
|
||||
typedef unsigned int __u16;
|
||||
#elif (@SIZEOF_SHORT@ == 2)
|
||||
typedef short __s16;
|
||||
typedef unsigned short __u16;
|
||||
#else
|
||||
?==error: undefined 16 bit type
|
||||
#endif
|
||||
|
||||
#if (@SIZEOF_INT@ == 4)
|
||||
typedef int __s32;
|
||||
typedef unsigned int __u32;
|
||||
#elif (@SIZEOF_LONG@ == 4)
|
||||
typedef long __s32;
|
||||
typedef unsigned long __u32;
|
||||
#elif (@SIZEOF_SHORT@ == 4)
|
||||
typedef short __s32;
|
||||
typedef unsigned short __u32;
|
||||
#else
|
||||
?== error: undefined 32 bit type
|
||||
#endif
|
||||
|
||||
#endif /* LINUX_TYPES_H */
|
||||
|
||||
#endif /* EXT2_TYPES_H */
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* cache.c - allocation/initialization/free routines for cache
|
||||
*
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
#ifdef DEBUG_CACHE
|
||||
#include <stdio.h>
|
||||
#define DEB_CACHE(fmt, arg...) printf("cache: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_CACHE(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
blkid_cache *blkid_new_cache(void)
|
||||
{
|
||||
blkid_cache *cache;
|
||||
|
||||
if (!(cache = (blkid_cache *)calloc(1, sizeof(blkid_cache))))
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&cache->bic_devs);
|
||||
INIT_LIST_HEAD(&cache->bic_tags);
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void blkid_free_cache(blkid_cache *cache)
|
||||
{
|
||||
if (!cache)
|
||||
return;
|
||||
|
||||
DEB_CACHE("freeing cache struct\n");
|
||||
/* DEB_DUMP_CACHE(cache); */
|
||||
|
||||
while (!list_empty(&cache->bic_devs)) {
|
||||
blkid_dev *dev = list_entry(cache->bic_devs.next, blkid_dev,
|
||||
bid_devs);
|
||||
blkid_free_dev(dev);
|
||||
}
|
||||
|
||||
while (!list_empty(&cache->bic_tags)) {
|
||||
blkid_tag *tag = list_entry(cache->bic_tags.next, blkid_tag,
|
||||
bit_tags);
|
||||
|
||||
while (!list_empty(&tag->bit_names)) {
|
||||
blkid_tag *bad = list_entry(tag->bit_names.next,
|
||||
blkid_tag, bit_names);
|
||||
|
||||
DEB_CACHE("warning: unfreed tag %s=%s\n",
|
||||
bad->bit_name, bad->bit_val);
|
||||
blkid_free_tag(bad);
|
||||
}
|
||||
blkid_free_tag(tag);
|
||||
}
|
||||
free(cache);
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
blkid_cache *cache = NULL;
|
||||
int ret;
|
||||
|
||||
if ((argc > 2)) {
|
||||
fprintf(stderr, "Usage: %s [filename] \n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((ret = blkid_read_cache(&cache, argv[1])) < 0)
|
||||
fprintf(stderr, "error %d parsing cache file %s\n", ret,
|
||||
argv[1] ? argv[1] : BLKID_CACHE_FILE);
|
||||
else if ((ret = blkid_probe_all(&cache) < 0))
|
||||
fprintf(stderr, "error probing devices\n");
|
||||
else if ((ret = blkid_save_cache(cache, argv[1])) < 0)
|
||||
fprintf(stderr, "error %d saving cache to %s\n", ret,
|
||||
argv[1] ? argv[1] : BLKID_CACHE_FILE);
|
||||
|
||||
blkid_free_cache(cache);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
* dev.c - allocation/initialization/free routines for dev
|
||||
*
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
#ifdef DEBUG_DEV
|
||||
#include <stdio.h>
|
||||
#define DEB_DEV(fmt, arg...) printf("dev: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_DEV(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
blkid_dev *blkid_new_dev(void)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
|
||||
if (!(dev = (blkid_dev *)calloc(1, sizeof(blkid_dev))))
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&dev->bid_devs);
|
||||
INIT_LIST_HEAD(&dev->bid_tags);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void blkid_free_dev(blkid_dev *dev)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
DEB_DEV(" freeing dev %s (%s)\n", dev->bid_name, dev->bid_type);
|
||||
DEB_DUMP_DEV(dev);
|
||||
|
||||
list_del(&dev->bid_devs);
|
||||
while (!list_empty(&dev->bid_tags)) {
|
||||
blkid_tag *tag = list_entry(dev->bid_tags.next, blkid_tag,
|
||||
bit_tags);
|
||||
blkid_free_tag(tag);
|
||||
}
|
||||
if (dev->bid_name)
|
||||
string_free(dev->bid_name);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is kind of ugly, but I want to be able to compare two strings in
|
||||
* several different ways. For example, in some cases, if both strings
|
||||
* are NULL, those would be considered different, but in other cases
|
||||
* they would be considered the same. Hence the ugliness.
|
||||
*
|
||||
* Use as: "ret == SC_SAME" if both strings exist and are equal
|
||||
* this is equivalent to "!(ret & SC_DIFF)"
|
||||
* "ret & SC_SAME" if both strings being NULL is also equal
|
||||
* this is equivalent to "!(ret == SC_DIFF)"
|
||||
* "ret == SC_DIFF" if both strings exist and are different
|
||||
* this is equivalent to "!(ret & SC_SAME)"
|
||||
* "ret & SC_DIFF" if both strings being NULL is also different
|
||||
* this is equivalent to "!(ret == SC_SAME)"
|
||||
* "ret == SC_NONE" to see if both strings do not exist
|
||||
*/
|
||||
#define SC_DIFF 0x0001
|
||||
#define SC_NONE 0x0003
|
||||
#define SC_SAME 0x0002
|
||||
|
||||
int string_compare(char *s1, char *s2)
|
||||
{
|
||||
if (!s1 && !s2)
|
||||
return SC_NONE;
|
||||
|
||||
if (!s1 || !s2)
|
||||
return SC_DIFF;
|
||||
|
||||
if (strcmp(s1, s2))
|
||||
return SC_DIFF;
|
||||
|
||||
return SC_SAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a tag to the global cache tag list.
|
||||
*/
|
||||
static int add_tag_to_cache(blkid_cache *cache, blkid_tag *tag)
|
||||
{
|
||||
blkid_tag *head = NULL;
|
||||
|
||||
if (!cache || !tag)
|
||||
return 0;
|
||||
|
||||
DEB_DEV(" adding tag %s=%s to cache\n", tag->bit_name, tag->bit_val);
|
||||
|
||||
if (!(head = blkid_find_head_cache(cache, tag))) {
|
||||
head = blkid_new_tag();
|
||||
if (!head)
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
DEB_DEV(" creating new cache tag head %s\n",tag->bit_name);
|
||||
head->bit_name = string_copy(tag->bit_name);
|
||||
if (!head->bit_name) {
|
||||
blkid_free_tag(head);
|
||||
return -BLKID_ERR_MEM;
|
||||
}
|
||||
|
||||
list_add_tail(&head->bit_tags, &cache->bic_tags);
|
||||
}
|
||||
|
||||
/* Add this tag to global list */
|
||||
list_add_tail(&tag->bit_names, &head->bit_names);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a device to the global cache list, along with all its tags.
|
||||
*/
|
||||
blkid_dev *blkid_add_dev_to_cache(blkid_cache *cache, blkid_dev *dev)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
if (!cache || !dev)
|
||||
return dev;
|
||||
|
||||
if (!dev->bid_id)
|
||||
dev->bid_id = ++(cache->bic_idmax);
|
||||
|
||||
list_for_each(p, &cache->bic_devs) {
|
||||
blkid_dev *odev = list_entry(p, blkid_dev, bid_devs);
|
||||
int dup_uuid, dup_label, dup_name, dup_type;
|
||||
|
||||
dup_name = string_compare(odev->bid_name, dev->bid_name);
|
||||
dup_label = string_compare(odev->bid_label, dev->bid_label);
|
||||
dup_uuid = string_compare(odev->bid_uuid, dev->bid_uuid);
|
||||
|
||||
if (odev->bid_id == dev->bid_id)
|
||||
dev->bid_id = ++(cache->bic_idmax);
|
||||
|
||||
/* Fields different, do nothing (check more fields?) */
|
||||
if ((dup_name & SC_DIFF) && (dup_uuid & SC_DIFF) &&
|
||||
(dup_label & SC_DIFF))
|
||||
continue;
|
||||
|
||||
/* We can't simply allow duplicate fields if the bid_type is
|
||||
* different, given that a filesystem may change from ext2
|
||||
* to ext3 but it will have the same UUID and LABEL fields.
|
||||
* We need to discard the old cache entry in this case.
|
||||
*/
|
||||
|
||||
/* If the UUIDs are the same but one is unverified discard it */
|
||||
if (dup_uuid == SC_SAME) {
|
||||
DEB_DEV(" duplicate uuid %s\n", dev->bid_uuid);
|
||||
if (!(odev->bid_flags & BLKID_BID_FL_VERIFIED)) {
|
||||
dev->bid_id = odev->bid_id; /* keep old id */
|
||||
blkid_free_dev(odev);
|
||||
goto exit_new;
|
||||
} else if (!(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
|
||||
blkid_free_dev(dev);
|
||||
dev = odev;
|
||||
goto exit_old;
|
||||
}
|
||||
|
||||
/* This shouldn't happen */
|
||||
fprintf(stderr, "blkid: same UUID for %s and %s\n",
|
||||
dev->bid_name, odev->bid_name);
|
||||
}
|
||||
|
||||
/* If the device name is the same, discard one of them
|
||||
* (prefer one that has been validated, or the first one).
|
||||
*/
|
||||
if (dup_name == SC_SAME) {
|
||||
DEB_DEV(" duplicate devname %s\n", dev->bid_name);
|
||||
if (odev->bid_flags & BLKID_BID_FL_VERIFIED ||
|
||||
!(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
|
||||
if ((dup_uuid & SC_SAME) &&
|
||||
(dup_label & SC_SAME)) /* use old id */
|
||||
dev->bid_id = odev->bid_id;
|
||||
blkid_free_dev(dev);
|
||||
dev = odev;
|
||||
goto exit_old;
|
||||
} else {
|
||||
blkid_free_dev(odev);
|
||||
goto exit_new;
|
||||
}
|
||||
}
|
||||
|
||||
dup_type = string_compare(odev->bid_type, dev->bid_type);
|
||||
|
||||
if (dup_label == SC_SAME && dup_type == SC_SAME) {
|
||||
DEB_DEV(" duplicate label %s\n", dev->bid_label);
|
||||
if (!(odev->bid_flags & BLKID_BID_FL_VERIFIED)) {
|
||||
blkid_free_dev(odev);
|
||||
goto exit_new;
|
||||
} else if (!(dev->bid_flags & BLKID_BID_FL_VERIFIED)) {
|
||||
blkid_free_dev(dev);
|
||||
dev = odev;
|
||||
goto exit_old;
|
||||
}
|
||||
fprintf(stderr, "blkid: same LABEL for %s and %s\n",
|
||||
dev->bid_name, odev->bid_name);
|
||||
}
|
||||
}
|
||||
|
||||
exit_new:
|
||||
DEB_DEV(" adding new devname %s to cache\n", dev->bid_name);
|
||||
|
||||
cache->bic_flags |= BLKID_BIC_FL_CHANGED;
|
||||
|
||||
list_add_tail(&dev->bid_devs, &cache->bic_devs);
|
||||
list_for_each(p, &dev->bid_tags) {
|
||||
blkid_tag *tag = list_entry(p, blkid_tag, bit_tags);
|
||||
add_tag_to_cache(cache, tag);
|
||||
}
|
||||
return dev;
|
||||
|
||||
exit_old:
|
||||
DEB_DEV(" using old devname %s from cache\n", dev->bid_name);
|
||||
return dev;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
blkid_cache *cache;
|
||||
blkid_dev *dev, *newdev;
|
||||
|
||||
if ((argc != 3)) {
|
||||
fprintf(stderr, "Usage:\t%s dev1 dev2\n"
|
||||
"Test that adding the same device to the cache fails\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cache = blkid_new_cache();
|
||||
if (!cache) {
|
||||
perror(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
dev = blkid_devname_to_dev(argv[1], 0);
|
||||
newdev = blkid_add_dev_to_cache(cache, dev);
|
||||
if (newdev != dev)
|
||||
printf("devices changed for %s (unexpected)\n", argv[1]);
|
||||
dev = blkid_devname_to_dev(argv[2], 0);
|
||||
newdev = blkid_add_dev_to_cache(cache, dev);
|
||||
if (newdev != dev)
|
||||
printf("devices changed for %s (unexpected)\n", argv[2]);
|
||||
dev = blkid_devname_to_dev(argv[2], 0);
|
||||
newdev = blkid_add_dev_to_cache(cache, dev);
|
||||
if (newdev != dev)
|
||||
printf("devices changed for %s (expected)\n", argv[2]);
|
||||
|
||||
blkid_free_cache(cache);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* devname.c - get a dev by its device inode name
|
||||
*
|
||||
* Copyright (C) Andries Brouwer
|
||||
* Copyright (C) 1999, 2000, 2001 Theodore Ts'o
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
/* #define DEBUG_DEVNAME */
|
||||
#ifdef DEBUG_DEVNAME
|
||||
#define DEB_DEV(fmt, arg...) printf("devname: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_DEV(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Find a dev struct in the cache by device name, if available.
|
||||
*/
|
||||
blkid_dev *blkid_find_devname(blkid_cache *cache, const char *devname)
|
||||
{
|
||||
blkid_dev *dev = NULL;
|
||||
struct list_head *p;
|
||||
|
||||
if (!cache || !devname)
|
||||
return NULL;
|
||||
|
||||
list_for_each(p, &cache->bic_devs) {
|
||||
blkid_dev *tmp = list_entry(p, blkid_dev, bid_devs);
|
||||
|
||||
if (strcmp(tmp->bid_name, devname))
|
||||
continue;
|
||||
|
||||
DEB_DEV("found devname %s in cache\n", tmp->bid_name);
|
||||
dev = blkid_verify_devname(cache, tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a pointer to an dev struct, either from cache or by probing.
|
||||
*/
|
||||
blkid_dev *blkid_get_devname(blkid_cache *cache, const char *devname)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
|
||||
if ((dev = blkid_find_devname(cache, devname)))
|
||||
return dev;
|
||||
|
||||
dev = blkid_devname_to_dev(devname, 0);
|
||||
return blkid_add_dev_to_cache(cache, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe a single block device to add to the device cache.
|
||||
* If the size is not specified, it will be found in blkid_devname_to_dev().
|
||||
*/
|
||||
static blkid_dev *probe_one(blkid_cache *cache, const char *ptname,
|
||||
int major, int minor, unsigned long long size)
|
||||
{
|
||||
dev_t devno = makedev(major, minor);
|
||||
blkid_dev *dev;
|
||||
const char **dir;
|
||||
char *devname = NULL;
|
||||
|
||||
/* See if we already have this device number in the cache. */
|
||||
if ((dev = blkid_find_devno(cache, devno)))
|
||||
return dev;
|
||||
|
||||
/*
|
||||
* Take a quick look at /dev/ptname for the device number. We check
|
||||
* all of the likely device directories. If we don't find it, or if
|
||||
* the stat information doesn't check out, use blkid_devno_to_devname()
|
||||
* to find it via an exhaustive search for the device major/minor.
|
||||
*/
|
||||
for (dir = devdirs; *dir; dir++) {
|
||||
struct stat st;
|
||||
char device[256];
|
||||
|
||||
sprintf(device, "%s/%s", *dir, ptname);
|
||||
if ((dev = blkid_find_devname(cache, device)) &&
|
||||
dev->bid_devno == devno)
|
||||
return dev;
|
||||
|
||||
if (stat(device, &st) == 0 && st.st_rdev == devno) {
|
||||
devname = string_copy(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!devname) {
|
||||
devname = blkid_devno_to_devname(devno);
|
||||
if (!devname)
|
||||
return NULL;
|
||||
}
|
||||
dev = blkid_devname_to_dev(devname, size);
|
||||
string_free(devname);
|
||||
|
||||
return blkid_add_dev_to_cache(cache, dev);
|
||||
}
|
||||
|
||||
#define PROC_PARTITIONS "/proc/partitions"
|
||||
#define VG_DIR "/proc/lvm/VGs"
|
||||
|
||||
/*
|
||||
* This function initializes the UUID cache with devices from the LVM
|
||||
* proc hierarchy. We currently depend on the names of the LVM
|
||||
* hierarchy giving us the device structure in /dev. (XXX is this a
|
||||
* safe thing to do?)
|
||||
*/
|
||||
#ifdef VG_DIR
|
||||
#include <dirent.h>
|
||||
static int lvm_get_devno(const char *lvm_device, int *major, int *minor,
|
||||
blkid_loff_t *size)
|
||||
{
|
||||
FILE *lvf;
|
||||
char buf[1024];
|
||||
int ret = 1;
|
||||
|
||||
*major = *minor = 0;
|
||||
*size = 0;
|
||||
|
||||
DEB_DEV("opening %s\n", lvm_device);
|
||||
if ((lvf = fopen(lvm_device, "r")) == NULL) {
|
||||
ret = errno;
|
||||
DEB_DEV("%s: (%d) %s\n", lvm_device, ret, strerror(ret));
|
||||
return -ret;
|
||||
}
|
||||
|
||||
while (fgets(buf, sizeof(buf), lvf)) {
|
||||
if (sscanf(buf, "size: %Ld", size) == 1) { /* sectors */
|
||||
*size <<= 9;
|
||||
}
|
||||
if (sscanf(buf, "device: %d:%d", major, minor) == 2) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(lvf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lvm_probe_all(blkid_cache **cache)
|
||||
{
|
||||
DIR *vg_list;
|
||||
struct dirent *vg_iter;
|
||||
int vg_len = strlen(VG_DIR);
|
||||
|
||||
if ((vg_list = opendir(VG_DIR)) == NULL)
|
||||
return;
|
||||
|
||||
DEB_DEV("probing LVM devices under %s\n", VG_DIR);
|
||||
|
||||
while ((vg_iter = readdir(vg_list)) != NULL) {
|
||||
DIR *lv_list;
|
||||
char *vdirname;
|
||||
char *vg_name;
|
||||
struct dirent *lv_iter;
|
||||
|
||||
vg_name = vg_iter->d_name;
|
||||
if (!strcmp(vg_name, ".") || !strcmp(vg_name, ".."))
|
||||
continue;
|
||||
vdirname = malloc(vg_len + strlen(vg_name) + 8);
|
||||
if (!vdirname)
|
||||
goto exit;
|
||||
sprintf(vdirname, "%s/%s/LVs", VG_DIR, vg_name);
|
||||
|
||||
lv_list = opendir(vdirname);
|
||||
free(vdirname);
|
||||
if (lv_list == NULL)
|
||||
continue;
|
||||
|
||||
while ((lv_iter = readdir(lv_list)) != NULL) {
|
||||
char *lv_name, *lvm_device;
|
||||
int major, minor;
|
||||
blkid_loff_t size;
|
||||
|
||||
lv_name = lv_iter->d_name;
|
||||
if (!strcmp(lv_name, ".") || !strcmp(lv_name, ".."))
|
||||
continue;
|
||||
|
||||
lvm_device = malloc(vg_len + strlen(vg_name) +
|
||||
strlen(lv_name) + 8);
|
||||
if (!lvm_device) {
|
||||
closedir(lv_list);
|
||||
goto exit;
|
||||
}
|
||||
sprintf(lvm_device, "%s/%s/LVs/%s", VG_DIR, vg_name,
|
||||
lv_name);
|
||||
if (lvm_get_devno(lvm_device, &major, &minor, &size)) {
|
||||
free(lvm_device);
|
||||
continue;
|
||||
}
|
||||
sprintf(lvm_device, "%s/%s", vg_name, lv_name);
|
||||
DEB_DEV("LVM dev %s: devno 0x%02X%02X, size %Ld\n",
|
||||
lvm_device, major, minor, size);
|
||||
probe_one(*cache, lvm_device, major, minor, size);
|
||||
free(lvm_device);
|
||||
}
|
||||
closedir(lv_list);
|
||||
}
|
||||
exit:
|
||||
closedir(vg_list);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read the device data for all available block devices in the system.
|
||||
*/
|
||||
int blkid_probe_all(blkid_cache **cache)
|
||||
{
|
||||
FILE *proc;
|
||||
int firstPass;
|
||||
|
||||
if (!cache)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (!*cache)
|
||||
*cache = blkid_new_cache();
|
||||
|
||||
if (!*cache)
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
if ((*cache)->bic_flags & BLKID_BIC_FL_PROBED &&
|
||||
time(0) - (*cache)->bic_time < BLKID_PROBE_INTERVAL)
|
||||
return 0;
|
||||
|
||||
#ifdef VG_DIR
|
||||
lvm_probe_all(cache);
|
||||
#endif
|
||||
|
||||
proc = fopen(PROC_PARTITIONS, "r");
|
||||
if (!proc)
|
||||
return -BLKID_ERR_PROC;
|
||||
|
||||
for (firstPass = 1; firstPass >= 0; firstPass--) {
|
||||
char line[1024];
|
||||
char ptname0[128], ptname1[128];
|
||||
char *ptnames[2] = { ptname0, ptname1 };
|
||||
int majors[2], minors[2];
|
||||
unsigned long long sizes[2];
|
||||
int lens[2] = { 0, 0 };
|
||||
int handleOnFirst;
|
||||
int which = 0, last = 0;
|
||||
|
||||
fseek(proc, 0, SEEK_SET);
|
||||
|
||||
while (fgets(line, sizeof(line), proc)) {
|
||||
last = which;
|
||||
which ^= 1;
|
||||
|
||||
if (sscanf(line, " %d %d %Ld %128[^\n ]",
|
||||
&majors[which], &minors[which],
|
||||
&sizes[which], ptnames[which]) != 4)
|
||||
continue;
|
||||
|
||||
DEB_DEV("read partition name %s\n", ptnames[which]);
|
||||
|
||||
/* look only at md devices on first pass */
|
||||
handleOnFirst = !strncmp(ptnames[which], "md", 2);
|
||||
if (firstPass != handleOnFirst)
|
||||
continue;
|
||||
|
||||
/* Skip whole disk devs unless they have no partitions
|
||||
* If we don't have a partition on this dev, also
|
||||
* check previous dev to see if it didn't have a partn.
|
||||
* heuristic: partition name ends in a digit.
|
||||
*
|
||||
* Skip extended partitions.
|
||||
* heuristic: size is 1
|
||||
*
|
||||
* FIXME: skip /dev/{ida,cciss,rd} whole-disk devs
|
||||
*/
|
||||
|
||||
lens[which] = strlen(ptnames[which]);
|
||||
if (isdigit(ptnames[which][lens[which] - 1])) {
|
||||
DEB_DEV("partition dev %s, devno 0x%02X%02X\n",
|
||||
ptnames[which], majors[which],
|
||||
minors[which]);
|
||||
|
||||
if (sizes[which] > 1)
|
||||
probe_one(*cache, ptnames[which],
|
||||
majors[which], minors[which],
|
||||
sizes[which] << 10);
|
||||
lens[which] = 0;
|
||||
lens[last] = 0;
|
||||
} else if (lens[last] &&
|
||||
strncmp(ptnames[last], ptnames[which],
|
||||
lens[last])) {
|
||||
DEB_DEV("whole dev %s, devno 0x%02X%02X\n",
|
||||
ptnames[last], majors[last],
|
||||
minors[last]);
|
||||
probe_one(*cache, ptnames[last], majors[last],
|
||||
minors[last], sizes[last] << 10);
|
||||
lens[last] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the last device if it wasn't partitioned */
|
||||
if (lens[which])
|
||||
probe_one(*cache, ptnames[which], majors[which],
|
||||
minors[which], sizes[which] << 10);
|
||||
}
|
||||
fclose(proc);
|
||||
|
||||
(*cache)->bic_time = time(0);
|
||||
(*cache)->bic_flags |= BLKID_BIC_FL_PROBED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
blkid_cache *cache = NULL;
|
||||
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "Usage: %s\n"
|
||||
"Probe all devices and exit\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if (blkid_probe_all(&cache) < 0)
|
||||
printf("%s: error probing devices\n", argv[0]);
|
||||
|
||||
blkid_free_cache(cache);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* devno.c - find a particular device by its device number (major/minor)
|
||||
*
|
||||
* Copyright (C) 2000, 2001 Theodore Ts'o
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
#ifdef DEBUG_DEVNO
|
||||
#define DEB_DEVNO(fmt, arg...) printf("devno: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_DEVNO(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
struct dir_list {
|
||||
char *name;
|
||||
struct dir_list *next;
|
||||
};
|
||||
|
||||
char *stringn_copy(const char *s, const int length)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
ret = malloc(length + 1);
|
||||
if (ret) {
|
||||
strncpy(ret, s, length);
|
||||
ret[length] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *string_copy(const char *s)
|
||||
{
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
return stringn_copy(s, strlen(s));
|
||||
}
|
||||
|
||||
void string_free(char *s)
|
||||
{
|
||||
if (s)
|
||||
free(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function adds an entry to the directory list
|
||||
*/
|
||||
static void add_to_dirlist(const char *name, struct dir_list **list)
|
||||
{
|
||||
struct dir_list *dp;
|
||||
|
||||
dp = malloc(sizeof(struct dir_list));
|
||||
if (!dp)
|
||||
return;
|
||||
dp->name = string_copy(name);
|
||||
if (!dp->name) {
|
||||
free(dp);
|
||||
return;
|
||||
}
|
||||
dp->next = *list;
|
||||
*list = dp;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function frees a directory list
|
||||
*/
|
||||
static void free_dirlist(struct dir_list **list)
|
||||
{
|
||||
struct dir_list *dp, *next;
|
||||
|
||||
for (dp = *list; dp; dp = next) {
|
||||
next = dp->next;
|
||||
string_free(dp->name);
|
||||
free(dp);
|
||||
}
|
||||
*list = NULL;
|
||||
}
|
||||
|
||||
static int scan_dir(char *dirname, dev_t devno, struct dir_list **list,
|
||||
char **devname)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dp;
|
||||
char path[1024];
|
||||
int dirlen;
|
||||
struct stat st;
|
||||
int ret = 0;
|
||||
|
||||
dirlen = strlen(dirname);
|
||||
if ((dir = opendir(dirname)) == NULL)
|
||||
return errno;
|
||||
dp = readdir(dir);
|
||||
while (dp) {
|
||||
if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
|
||||
goto skip_to_next;
|
||||
|
||||
if (dp->d_name[0] == '.' &&
|
||||
((dp->d_name[1] == 0) ||
|
||||
((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
|
||||
goto skip_to_next;
|
||||
|
||||
sprintf(path, "%s/%s", dirname, dp->d_name);
|
||||
if (stat(path, &st) < 0)
|
||||
goto skip_to_next;
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
add_to_dirlist(path, list);
|
||||
else if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
|
||||
*devname = string_copy(path);
|
||||
DEB_DEVNO("found 0x%Lx at %s (%p)\n", devno,
|
||||
*devname, *devname);
|
||||
if (!*devname)
|
||||
ret = -BLKID_ERR_MEM;
|
||||
break;
|
||||
}
|
||||
skip_to_next:
|
||||
dp = readdir(dir);
|
||||
}
|
||||
closedir(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Directories where we will try to search for device numbers */
|
||||
const char *devdirs[] = { "/dev", "/devfs", "/devices", NULL };
|
||||
|
||||
/*
|
||||
* This function finds the pathname to a block device with a given
|
||||
* device number. It returns a pointer to allocated memory to the
|
||||
* pathname on success, and NULL on failure.
|
||||
*/
|
||||
char *blkid_devno_to_devname(dev_t devno)
|
||||
{
|
||||
struct dir_list *list = NULL, *new_list = NULL;
|
||||
char *devname = NULL;
|
||||
const char **dir;
|
||||
|
||||
/*
|
||||
* Add the starting directories to search in reverse order of
|
||||
* importance, since we are using a stack...
|
||||
*/
|
||||
for (dir = devdirs; *dir; dir++)
|
||||
/* go to end of list */;
|
||||
|
||||
do {
|
||||
--dir;
|
||||
add_to_dirlist(*dir, &list);
|
||||
} while (dir != devdirs);
|
||||
|
||||
while (list) {
|
||||
struct dir_list *current = list;
|
||||
|
||||
list = list->next;
|
||||
DEB_DEVNO("directory %s\n", current->name);
|
||||
scan_dir(current->name, devno, &new_list, &devname);
|
||||
string_free(current->name);
|
||||
free(current);
|
||||
if (devname)
|
||||
break;
|
||||
/*
|
||||
* If we're done checking at this level, descend to
|
||||
* the next level of subdirectories. (breadth-first)
|
||||
*/
|
||||
if (list == NULL) {
|
||||
list = new_list;
|
||||
new_list = NULL;
|
||||
}
|
||||
}
|
||||
free_dirlist(&list);
|
||||
free_dirlist(&new_list);
|
||||
|
||||
if (!devname)
|
||||
fprintf(stderr, "blkid: couldn't find devno 0x%04Lx\n", devno);
|
||||
else
|
||||
DEB_DEVNO("found devno 0x%04Lx as %s\n", devno, devname);
|
||||
|
||||
return devname;
|
||||
}
|
||||
|
||||
blkid_dev *blkid_find_devno(blkid_cache *cache, dev_t devno)
|
||||
{
|
||||
blkid_dev *dev = NULL;
|
||||
struct list_head *p, *n;
|
||||
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
||||
/* This cannot be a standard list_for_each() because we may be
|
||||
* deleting the referenced struct in blkid_verify_devname() and
|
||||
* pointing to another one that was probed from disk, and "p"
|
||||
* would point to freed memory.
|
||||
*/
|
||||
list_for_each_safe(p, n, &cache->bic_devs) {
|
||||
blkid_dev *tmp = list_entry(p, blkid_dev, bid_devs);
|
||||
if (tmp->bid_devno != devno)
|
||||
continue;
|
||||
|
||||
tmp = blkid_verify_devname(cache, tmp);
|
||||
if (!tmp || tmp->bid_devno != devno)
|
||||
continue;
|
||||
|
||||
dev = tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev)
|
||||
DEB_DEVNO("found devno 0x%04LX in cache as %s\n",
|
||||
devno, dev->bid_name);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
blkid_dev *blkid_get_devno(blkid_cache *cache, dev_t devno)
|
||||
{
|
||||
char *devname;
|
||||
blkid_dev *dev;
|
||||
|
||||
if (!(dev = blkid_find_devno(cache, devno)) &&
|
||||
(devname = blkid_devno_to_devname(devno))) {
|
||||
dev = blkid_get_devname(cache, devname);
|
||||
string_free(devname);
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char *devname, *tmp;
|
||||
int major, minor;
|
||||
dev_t devno;
|
||||
const char *errmsg = "Couldn't parse %s: %s\n";
|
||||
|
||||
if ((argc != 2) && (argc != 3)) {
|
||||
fprintf(stderr, "Usage:\t%s device_number\n\t%s major minor\n"
|
||||
"Resolve a device number to a device name\n",
|
||||
argv[0], argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if (argc == 2) {
|
||||
devno = strtoul(argv[1], &tmp, 0);
|
||||
if (*tmp) {
|
||||
fprintf(stderr, errmsg, "device number", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
major = strtoul(argv[1], &tmp, 0);
|
||||
if (*tmp) {
|
||||
fprintf(stderr, errmsg, "major number", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
minor = strtoul(argv[2], &tmp, 0);
|
||||
if (*tmp) {
|
||||
fprintf(stderr, errmsg, "minor number", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
devno = makedev(major, minor);
|
||||
}
|
||||
printf("Looking for device 0x%04Lx\n", devno);
|
||||
devname = blkid_devno_to_devname(devno);
|
||||
if (devname)
|
||||
string_free(devname);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* getsize.c --- get the size of a partition.
|
||||
*
|
||||
* Copyright (C) 1995, 1995 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fd.h>
|
||||
#endif /* HAVE_LINUX_FD_H */
|
||||
#ifdef HAVE_SYS_DISKLABEL_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/disklabel.h>
|
||||
#endif /* HAVE_SYS_DISKLABEL_H */
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
|
||||
#define BLKGETSIZE _IO(0x12,96) /* return device size */
|
||||
#endif
|
||||
|
||||
static int valid_offset(int fd, blkid_loff_t offset)
|
||||
{
|
||||
char ch;
|
||||
|
||||
if (blkid_llseek(fd, offset, 0) < 0)
|
||||
return 0;
|
||||
if (read(fd, &ch, 1) < 1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of blocks in a partition
|
||||
*/
|
||||
blkid_loff_t blkid_get_dev_size(int fd)
|
||||
{
|
||||
#ifdef BLKGETSIZE
|
||||
unsigned long size;
|
||||
#endif
|
||||
blkid_loff_t high, low;
|
||||
#ifdef FDGETPRM
|
||||
struct floppy_struct this_floppy;
|
||||
#endif
|
||||
#ifdef HAVE_SYS_DISKLABEL_H
|
||||
int part;
|
||||
struct disklabel lab;
|
||||
struct partition *pp;
|
||||
char ch;
|
||||
#endif /* HAVE_SYS_DISKLABEL_H */
|
||||
|
||||
#ifdef BLKGETSIZE
|
||||
if (ioctl(fd, BLKGETSIZE, &size) >= 0)
|
||||
return (blkid_loff_t)size << 9;
|
||||
#endif
|
||||
#ifdef FDGETPRM
|
||||
if (ioctl(fd, FDGETPRM, &this_floppy) >= 0)
|
||||
return (blkid_loff_t)this_floppy.size << 9;
|
||||
#endif
|
||||
#ifdef HAVE_SYS_DISKLABEL_H
|
||||
part = strlen(file) - 1;
|
||||
if (part >= 0) {
|
||||
ch = file[part];
|
||||
if (isdigit(ch))
|
||||
part = 0;
|
||||
else if (ch >= 'a' && ch <= 'h')
|
||||
part = ch - 'a';
|
||||
else
|
||||
part = -1;
|
||||
}
|
||||
if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
|
||||
pp = &lab.d_partitions[part];
|
||||
if (pp->p_size)
|
||||
return pp->p_size << 9;
|
||||
}
|
||||
#endif /* HAVE_SYS_DISKLABEL_H */
|
||||
|
||||
/*
|
||||
* OK, we couldn't figure it out by using a specialized ioctl,
|
||||
* which is generally the best way. So do binary search to
|
||||
* find the size of the partition.
|
||||
*/
|
||||
low = 0;
|
||||
for (high = 1024; valid_offset(fd, high); high *= 2)
|
||||
low = high;
|
||||
while (low < high - 1)
|
||||
{
|
||||
const blkid_loff_t mid = (low + high) / 2;
|
||||
|
||||
if (valid_offset(fd, mid))
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
return low + 1;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
blkid_loff_t bytes;
|
||||
int fd;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s device\n"
|
||||
"Determine the size of a device\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY)) < 0)
|
||||
perror(argv[0]);
|
||||
|
||||
bytes = blkid_get_dev_size(fd);
|
||||
printf("Device %s has %Ld 1k blocks.\n", argv[1], bytes >> 10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,96 @@
|
|||
.\" Copyright 2001 Andreas Dilger (adilger@turbolinux.com)
|
||||
.\"
|
||||
.\" This man page was created for libblkid.so.1.0 from e2fsprogs-1.24.
|
||||
.\"
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.\" Created Wed Sep 14 12:02:12 2001, Andreas Dilger
|
||||
.TH LIBBLKID 3 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
|
||||
.SH NAME
|
||||
libblkid \- block device identification library
|
||||
.SH SYNOPSIS
|
||||
.B #include <blkid/blkid.h>
|
||||
.sp
|
||||
.B cc
|
||||
.I file.c
|
||||
.B \-lblkid
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B libblkid
|
||||
library is used to identify block devices (disks) as to their content (e.g.
|
||||
filesystem type) as well as extracting additional information such as
|
||||
filesystem labels/volume names, unique identifiers/serial numbers, etc.
|
||||
A common use is to allow use of LABEL= and UUID= tags instead of hard-coding
|
||||
specific block device names into configuration files.
|
||||
.P
|
||||
Block device information is normally kept in a cache file
|
||||
.I /etc/blkid.tab
|
||||
and is verified to still be valid before being returned to the user
|
||||
(if the user has read permission on the raw block device, otherwise not).
|
||||
The cache file also allows unprivileged users (normally anyone other
|
||||
than root, or those not in the "disk" group) to locate devices by label/id.
|
||||
.P
|
||||
Functions with "get" in their name will first search the cache (if given)
|
||||
for the specified data, and failing that will search visible block devices
|
||||
for this information. Functions with "find" in their name will only search
|
||||
the existing cache data for the specified device.
|
||||
.P
|
||||
In situations where one is getting information about a single known device,
|
||||
it does not impact performance whether the cache is used or not (unless you
|
||||
are not able to read the block device directly). If you are dealing with
|
||||
multiple devices use of the cache is highly recommended (even if empty) as
|
||||
devices will be scanned at most one time, and the on-disk cache will be
|
||||
updated if possible. There is rarely a reason not to use the cache.
|
||||
.P
|
||||
In some cases (modular kernels), block devices are not even visible until
|
||||
after they are accessed the first time, so it is critical that there is
|
||||
some way to locate these devices without enumerating only visible devices,
|
||||
so the use of the cache file is
|
||||
.B required
|
||||
in this situation.
|
||||
.SH AUTHOR
|
||||
.B libblkid
|
||||
was written by Andreas Dilger for the ext2 filesystem utilties, with input
|
||||
from Ted Ts'o.
|
||||
.SH FILES
|
||||
.TP
|
||||
.I /etc/blkid.tab
|
||||
Caches data extracted from each recognized block device.
|
||||
.SH AVAILABILITY
|
||||
.B libblkid
|
||||
is part of the e2fsprogs package since version 1.25 and is available from
|
||||
http://e2fsprogs.sourceforge.net.
|
||||
.SH COPYING
|
||||
.B libblkid
|
||||
is available under the terms of the GNU Library General Public License (LGPL),
|
||||
version 2 (or at your discretion any later version). A copy of the LGPL
|
||||
should be included with this library in the file COPYING. If not, write to
|
||||
.RS
|
||||
Free Software Foundation, Inc.
|
||||
.br
|
||||
59 Temple Place
|
||||
.br
|
||||
Suite 330
|
||||
.br
|
||||
Boston, MA 02111-1307 USA
|
||||
.RE
|
||||
.PP
|
||||
or visit
|
||||
.UR http://www.gnu.org/licenses/licenses.html#LGPL
|
||||
http://www.gnu.org/licenses/licenses.html#LGPL
|
||||
.UE
|
||||
.SH "SEE ALSO"
|
||||
.BR blkid_read_cache (3),
|
||||
.BR blkid_save_cache (3),
|
||||
.BR blkid_free_cache (3),
|
||||
.BR blkid_get_devname (3),
|
||||
.BR blkid_get_devno (3),
|
||||
.BR blkid_probe_all (3),
|
||||
.BR blkid_token_to_tag (3),
|
||||
.BR blkid_free_dev (3),
|
||||
.BR blkid_find_tag_dev (3),
|
||||
.BR blkid_find_tag_cache (3),
|
||||
.BR blkid_get_tag_cache (3),
|
||||
.BR blkid_get_tagname_devname (3),
|
||||
.BR blkid_get_token (3),
|
||||
.BR blkid.tab (7)
|
|
@ -0,0 +1,171 @@
|
|||
#if !defined(_BLKID_LIST_H) && !defined(LIST_HEAD)
|
||||
#define _BLKID_LIST_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
|
||||
#define INIT_LIST_HEAD(ptr) do { \
|
||||
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_add(struct list_head * add,
|
||||
struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = add;
|
||||
add->next = next;
|
||||
add->prev = prev;
|
||||
prev->next = add;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @add: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static __inline__ void list_add(struct list_head *add, struct list_head *head)
|
||||
{
|
||||
__list_add(add, head, head->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @add: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static __inline__ void list_add_tail(struct list_head *add, struct list_head *head)
|
||||
{
|
||||
__list_add(add, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static __inline__ void __list_del(struct list_head * prev,
|
||||
struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
*
|
||||
* list_empty() on @entry does not return true after this, @entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static __inline__ void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del_init - deletes entry from list and reinitialize it.
|
||||
* @entry: the element to delete from the list.
|
||||
*/
|
||||
static __inline__ void list_del_init(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
INIT_LIST_HEAD(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static __inline__ int list_empty(struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_splice - join two lists
|
||||
* @list: the new list to add.
|
||||
* @head: the place to add it in the first list.
|
||||
*/
|
||||
static __inline__ void list_splice(struct list_head *list, struct list_head *head)
|
||||
{
|
||||
struct list_head *first = list->next;
|
||||
|
||||
if (first != list) {
|
||||
struct list_head *last = list->prev;
|
||||
struct list_head *at = head->next;
|
||||
|
||||
first->prev = head;
|
||||
head->next = first;
|
||||
|
||||
last->next = at;
|
||||
at->prev = last;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_struct within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over elements in a list
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over elements in a list, but don't dereference
|
||||
* pos after the body is done (in case it is freed)
|
||||
* @pos: the &struct list_head to use as a loop counter.
|
||||
* @pnext: the &struct list_head to use as a pointer to the next item.
|
||||
* @head: the head for your list (not included in iteration).
|
||||
*/
|
||||
#define list_for_each_safe(pos, pnext, head) \
|
||||
for (pos = (head)->next, pnext = pos->next; pos != (head); \
|
||||
pos = pnext, pnext = pos->next)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BLKID_LIST_H */
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* llseek.c -- stub calling the llseek system call
|
||||
*
|
||||
* Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef __MSDOS__
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
|
||||
|
||||
#define my_llseek lseek64
|
||||
|
||||
#elif defined(HAVE_LLSEEK)
|
||||
#include <syscall.h>
|
||||
|
||||
#ifndef HAVE_LLSEEK_PROTOTYPE
|
||||
extern long long llseek(int fd, long long offset, int origin);
|
||||
#endif
|
||||
|
||||
#define my_llseek llseek
|
||||
|
||||
#else /* ! HAVE_LLSEEK */
|
||||
|
||||
#if defined(__alpha__) || defined(__ia64__)
|
||||
|
||||
#define llseek lseek
|
||||
|
||||
#else /* !__alpha__ && !__ia64__*/
|
||||
|
||||
#include <linux/unistd.h>
|
||||
|
||||
#ifndef __NR__llseek
|
||||
#define __NR__llseek 140
|
||||
#endif
|
||||
|
||||
#ifndef __i386__
|
||||
static int _llseek(unsigned int, unsigned long, unsigned long,
|
||||
blkid_loff_t *, unsigned int);
|
||||
|
||||
static _syscall5(int, _llseek, unsigned int, fd, unsigned long, offset_high,
|
||||
unsigned long, offset_low, blkid_loff_t *, result,
|
||||
unsigned int, origin)
|
||||
#endif
|
||||
|
||||
static blkid_loff_t my_llseek(int fd, blkid_loff_t offset, int origin)
|
||||
{
|
||||
blkid_loff_t result;
|
||||
int retval;
|
||||
|
||||
#ifndef __i386__
|
||||
retval = _llseek(fd, ((unsigned long long) offset) >> 32,
|
||||
((unsigned long long)offset) & 0xffffffff,
|
||||
&result, origin);
|
||||
#else
|
||||
retval = syscall(__NR__llseek, fd, ((unsigned long long) offset) >> 32,
|
||||
((unsigned long long)offset) & 0xffffffff,
|
||||
&result, origin);
|
||||
#endif
|
||||
return (retval == -1 ? (blkid_loff_t) retval : result);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ || __ia64__ */
|
||||
|
||||
#endif /* HAVE_LLSEEK */
|
||||
|
||||
blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int whence)
|
||||
{
|
||||
blkid_loff_t result;
|
||||
static int do_compat = 0;
|
||||
|
||||
if ((sizeof(off_t) >= sizeof(blkid_loff_t)) ||
|
||||
(offset < ((blkid_loff_t) 1 << ((sizeof(off_t)*8) -1))))
|
||||
return lseek(fd, (off_t) offset, whence);
|
||||
|
||||
if (do_compat) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = my_llseek(fd, offset, whence);
|
||||
if (result == -1 && errno == ENOSYS) {
|
||||
/*
|
||||
* Just in case this code runs on top of an old kernel
|
||||
* which does not support the llseek system call
|
||||
*/
|
||||
do_compat++;
|
||||
errno = EOVERFLOW;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else /* !linux */
|
||||
|
||||
#ifndef EOVERFLOW
|
||||
#ifdef EXT2_ET_INVALID_ARGUMENT
|
||||
#define EOVERFLOW EXT2_ET_INVALID_ARGUMENT
|
||||
#else
|
||||
#define EOVERFLOW 112
|
||||
#endif
|
||||
#endif
|
||||
|
||||
blkid_loff_t blkid_llseek(int fd, blkid_loff_t offset, int origin)
|
||||
{
|
||||
if ((sizeof(off_t) < sizeof(blkid_loff_t)) &&
|
||||
(offset >= ((blkid_loff_t) 1 << ((sizeof(off_t)*8) - 1)))) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
return lseek(fd, (off_t) offset, origin);
|
||||
}
|
||||
|
||||
#endif /* linux */
|
||||
|
||||
|
|
@ -0,0 +1,838 @@
|
|||
/*
|
||||
* probe.c - identify a block device by its contents, and return a dev
|
||||
* struct with the details
|
||||
*
|
||||
* Copyright (C) 1999 by Andries Brouwer
|
||||
* Copyright (C) 1999, 2000 by Theodore Ts'o
|
||||
* Copyright (C) 2001 by Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include "blkid/blkid.h"
|
||||
#include "uuid/uuid.h"
|
||||
#include "probe.h"
|
||||
|
||||
/* #define DEBUG_PROBE */
|
||||
#ifdef DEBUG_PROBE
|
||||
#define DEB_PROBE(fmt, arg...) printf("probe: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_PROBE(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Do the required things for instantiating a new device. This is called if
|
||||
* there is nor a probe handler for a filesystem type, and is also called by
|
||||
* the filesystem-specific types to do common initialization tasks.
|
||||
*
|
||||
* The devname, dev_p, and id fields are required. The buf is
|
||||
* a buffer to return superblock data in.
|
||||
*/
|
||||
static int probe_default(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_loff_t offset;
|
||||
blkid_dev *dev;
|
||||
struct stat st;
|
||||
int ret;
|
||||
|
||||
if (!devname || !dev_p || !id || !buf || fd < 0)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (fstat(fd, &st) < 0 || !S_ISBLK(st.st_mode))
|
||||
return -BLKID_ERR_DEV;
|
||||
|
||||
offset = (blkid_loff_t)id->bim_kboff << 10;
|
||||
if (id->bim_kboff < 0)
|
||||
offset = (size & ~((blkid_loff_t)id->bim_align - 1)) + offset;
|
||||
|
||||
if (blkid_llseek(fd, offset, 0) < 0 ||
|
||||
read(fd, buf, id->bim_kbsize << 10) != id->bim_kbsize << 10)
|
||||
return -BLKID_ERR_IO;
|
||||
|
||||
/* Revalidate magic for blkid_validate_devname */
|
||||
if (memcmp(id->bim_magic, buf + id->bim_sboff, id->bim_len))
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
dev = blkid_new_dev();
|
||||
if (!dev)
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
dev->bid_name = string_copy(devname);
|
||||
if (!dev->bid_name) {
|
||||
ret = -BLKID_ERR_MEM;
|
||||
goto exit_dev;
|
||||
}
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
dev->bid_devno = st.st_rdev;
|
||||
dev->bid_devsize = size;
|
||||
dev->bid_time = time(0);
|
||||
dev->bid_flags |= BLKID_BID_FL_VERIFIED;
|
||||
|
||||
if (id->bim_type)
|
||||
blkid_create_tag(dev, NULL, "TYPE", id->bim_type,
|
||||
strlen(id->bim_type));
|
||||
|
||||
DEB_PROBE("%s: devno 0x%04Lx, type %s\n", devname,
|
||||
st.st_rdev, id->bim_type);
|
||||
|
||||
return 0;
|
||||
exit_dev:
|
||||
blkid_free_dev(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int probe_ext2(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct ext2_super_block *es;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
es = (struct ext2_super_block *)buf;
|
||||
|
||||
DEB_PROBE("size = %Ld, ext2_sb.compat = %08X:%08X:%08X\n", size,
|
||||
le32_to_cpu(es->s_feature_compat),
|
||||
le32_to_cpu(es->s_feature_incompat),
|
||||
le32_to_cpu(es->s_feature_ro_compat));
|
||||
|
||||
/* Make sure we don't keep re-probing as ext2 for a journaled fs */
|
||||
if (!strcmp(id->bim_type, "ext2") &&
|
||||
(le32_to_cpu(es->s_feature_compat) &
|
||||
EXT3_FEATURE_COMPAT_HAS_JOURNAL ||
|
||||
le32_to_cpu(es->s_feature_incompat) &
|
||||
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
|
||||
blkid_free_dev(dev);
|
||||
return -BLKID_ERR_PARAM;
|
||||
}
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
dev->bid_size = (blkid_loff_t)le32_to_cpu(es->s_blocks_count) <<
|
||||
(le32_to_cpu(es->s_log_block_size) + 10);
|
||||
|
||||
/* This is a safe (minimum) number, as it ignores metadata usage. */
|
||||
dev->bid_free = (blkid_loff_t)le32_to_cpu(es->s_free_blocks_count) <<
|
||||
(le32_to_cpu(es->s_log_block_size) + 10);
|
||||
|
||||
if (strlen(es->s_volume_name)) {
|
||||
blkid_create_tag(dev, NULL, "LABEL", es->s_volume_name,
|
||||
sizeof(es->s_volume_name));
|
||||
}
|
||||
|
||||
if (!uuid_is_null(es->s_uuid)) {
|
||||
unsigned char uuid[37];
|
||||
uuid_unparse(es->s_uuid, uuid);
|
||||
blkid_create_tag(dev, NULL, "UUID", uuid, sizeof(uuid));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_jbd(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct ext2_super_block *es;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_ext2(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
es = (struct ext2_super_block *)buf;
|
||||
|
||||
if (!(le32_to_cpu(es->s_feature_incompat) &
|
||||
EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
|
||||
blkid_free_dev(dev);
|
||||
return -BLKID_ERR_PARAM;
|
||||
}
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_ext3(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct ext2_super_block *es;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_ext2(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
es = (struct ext2_super_block *)buf;
|
||||
|
||||
if (!(le32_to_cpu(es->s_feature_compat) &
|
||||
EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
|
||||
blkid_free_dev(dev);
|
||||
*dev_p = NULL;
|
||||
return -BLKID_ERR_PARAM;
|
||||
}
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
if (!(le32_to_cpu(es->s_feature_incompat) &
|
||||
EXT3_FEATURE_INCOMPAT_RECOVER)) {
|
||||
blkid_create_tag(dev, NULL, "TYPE", "ext2", 4);
|
||||
dev->bid_flags |= BLKID_BID_FL_MTYPE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_vfat(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct vfat_super_block *vs;
|
||||
char serno[10];
|
||||
blkid_loff_t sectors;
|
||||
int cluster_size;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
vs = (struct vfat_super_block *)buf;
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
sectors = ((vs->vs_sectors[1] << 8) | vs->vs_sectors[0]);
|
||||
if (sectors == 0)
|
||||
sectors = vs->vs_total_sect;
|
||||
cluster_size = ((vs->vs_sector_size[1] << 8) | vs->vs_sector_size[0]);
|
||||
dev->bid_size = sectors * cluster_size;
|
||||
DEB_PROBE("%Ld %d byte sectors\n", sectors, cluster_size);
|
||||
|
||||
if (strncmp(vs->vs_label, "NO NAME", 7)) {
|
||||
unsigned char *end = vs->vs_label + sizeof(vs->vs_label) - 1;
|
||||
|
||||
while (*end == ' ' && end >= vs->vs_label)
|
||||
--end;
|
||||
if (end >= vs->vs_label)
|
||||
blkid_create_tag(dev, NULL, "LABEL", vs->vs_label,
|
||||
end - vs->vs_label + 1);
|
||||
}
|
||||
|
||||
/* We can't just print them as %04X, because they are unaligned */
|
||||
sprintf(serno, "%02X%02X-%02X%02X", vs->vs_serno[3], vs->vs_serno[2],
|
||||
vs->vs_serno[1], vs->vs_serno[0]);
|
||||
blkid_create_tag(dev, NULL, "UUID", serno, sizeof(serno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_msdos(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct msdos_super_block *ms;
|
||||
char serno[10];
|
||||
int cluster_size;
|
||||
blkid_loff_t sectors;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
ms = (struct msdos_super_block *)buf;
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
sectors = ((ms->ms_sectors[1] << 8) | ms->ms_sectors[0]);
|
||||
if (sectors == 0)
|
||||
sectors = ms->ms_total_sect;
|
||||
cluster_size = ((ms->ms_sector_size[1] << 8) | ms->ms_sector_size[0]);
|
||||
dev->bid_size = sectors * cluster_size;
|
||||
DEB_PROBE("%Ld %d byte sectors\n", sectors, cluster_size);
|
||||
|
||||
if (strncmp(ms->ms_label, "NO NAME", 7)) {
|
||||
unsigned char *end = ms->ms_label + sizeof(ms->ms_label) - 1;
|
||||
|
||||
while (*end == ' ' && end >= ms->ms_label)
|
||||
--end;
|
||||
if (end >= ms->ms_label)
|
||||
blkid_create_tag(dev, NULL, "LABEL", ms->ms_label,
|
||||
end - ms->ms_label + 1);
|
||||
}
|
||||
|
||||
/* We can't just print them as %04X, because they are unaligned */
|
||||
sprintf(serno, "%02X%02X-%02X%02X", ms->ms_serno[3], ms->ms_serno[2],
|
||||
ms->ms_serno[1], ms->ms_serno[0]);
|
||||
blkid_create_tag(dev, NULL, "UUID", serno, sizeof(serno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_xfs(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct xfs_super_block *xs;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
xs = (struct xfs_super_block *)buf;
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
/* If the filesystem size is larger than the device, this is bad */
|
||||
dev->bid_size = be64_to_cpu(xs->xs_dblocks) *
|
||||
be32_to_cpu(xs->xs_blocksize);
|
||||
dev->bid_free = be64_to_cpu(xs->xs_fdblocks) *
|
||||
be32_to_cpu(xs->xs_blocksize);
|
||||
|
||||
if (strlen(xs->xs_fname))
|
||||
blkid_create_tag(dev, NULL, "LABEL", xs->xs_fname,
|
||||
sizeof(xs->xs_fname));
|
||||
|
||||
if (!uuid_is_null(xs->xs_uuid)) {
|
||||
char uuid[37];
|
||||
uuid_unparse(xs->xs_uuid, uuid);
|
||||
blkid_create_tag(dev, NULL, "UUID", uuid, sizeof(uuid));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_reiserfs(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct reiserfs_super_block *rs;
|
||||
unsigned int blocksize;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
rs = (struct reiserfs_super_block *)buf;
|
||||
|
||||
blocksize = le16_to_cpu(rs->rs_blocksize);
|
||||
|
||||
/* If the superblock is inside the journal, we have the wrong one */
|
||||
if (id->bim_kboff/(blocksize>>10) > le32_to_cpu(rs->rs_journal_block)) {
|
||||
blkid_free_dev(dev);
|
||||
return -BLKID_ERR_BIG;
|
||||
}
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
/* If the filesystem size is larger than the device, this is bad */
|
||||
dev->bid_size = le32_to_cpu(rs->rs_blocks_count) * blocksize;
|
||||
dev->bid_free = le32_to_cpu(rs->rs_free_blocks) * blocksize;
|
||||
|
||||
/* LABEL/UUID are only valid for later versions of Reiserfs v3.6. */
|
||||
if (!strcmp(id->bim_magic, "ReIsEr2Fs") ||
|
||||
!strcmp(id->bim_magic, "ReIsEr3Fs")) {
|
||||
if (strlen(rs->rs_label)) {
|
||||
blkid_create_tag(dev, NULL, "LABEL", rs->rs_label,
|
||||
sizeof(rs->rs_label));
|
||||
}
|
||||
|
||||
if (!uuid_is_null(rs->rs_uuid)) {
|
||||
unsigned char uuid[37];
|
||||
uuid_unparse(rs->rs_uuid, uuid);
|
||||
blkid_create_tag(dev, NULL, "UUID", uuid, sizeof(uuid));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_minix(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct minix_super_block *ms;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
ms = (struct minix_super_block *)buf;
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
dev->bid_size = ms->ms_nzones << ms->ms_log_zone_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_swap(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct swap_header *sh;
|
||||
int psize;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
/* PAGE_SIZE can be found by where the magic is located */
|
||||
psize = (id->bim_kboff << 10) + (id->bim_sboff + 10);
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
sh = (struct swap_header *)buf;
|
||||
/* Is swap data in local endian format? */
|
||||
dev->bid_size = (blkid_loff_t)(sh->sh_last_page + 1) * psize;
|
||||
|
||||
/* A label can not exist on the old (128MB max) swap format */
|
||||
if (!strcmp(id->bim_magic, "SWAPSPACE2") && sh->sh_label[0]) {
|
||||
blkid_create_tag(dev, NULL, "LABEL", sh->sh_label,
|
||||
sizeof(sh->sh_label));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_mdraid(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct mdp_superblock_s *md;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
md = (struct mdp_superblock_s *)buf;
|
||||
/* What units is md->size in? Assume 512-byte sectors? */
|
||||
dev->bid_size = md->size * 512;
|
||||
|
||||
/* The MD UUID is not contiguous in the superblock, make it so */
|
||||
if (md->set_uuid0 || md->set_uuid1 || md->set_uuid2 || md->set_uuid3) {
|
||||
unsigned char md_uuid[16];
|
||||
unsigned char uuid[37];
|
||||
|
||||
memcpy(md_uuid, &md->set_uuid0, 4);
|
||||
memcpy(md_uuid + 4, &md->set_uuid1, 12);
|
||||
|
||||
uuid_unparse(md_uuid, uuid);
|
||||
blkid_create_tag(dev, NULL, "UUID", uuid, sizeof(uuid));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int probe_hfs(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
struct hfs_super_block *hfs;
|
||||
int ret;
|
||||
|
||||
if ((ret = probe_default(fd, &dev, devname, id, buf, size)) < 0)
|
||||
return ret;
|
||||
|
||||
hfs = (struct hfs_super_block *)buf;
|
||||
|
||||
if (be32_to_cpu(hfs->h_blksize) != 512)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
/* Don't set this until there is no chance of error */
|
||||
*dev_p = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BLKID_BLK_OFFS is at least as large as the highest bim_kboff defined
|
||||
* in the type_array table below + bim_kbalign. If we ever start looking for magics
|
||||
* relative to the end of a device, we can start using negative offsets
|
||||
* in type_array.
|
||||
*/
|
||||
#define BLKID_BLK_BITS (10)
|
||||
#define BLKID_BLK_KBITS (BLKID_BLK_BITS - 10)
|
||||
#define BLKID_BLK_SIZE (1024 << BLKID_BLK_KBITS)
|
||||
#define BLKID_BLK_MASK (BLKID_BLK_SIZE - 1)
|
||||
#define BLKID_BLK_OFFS 128 /* currently MDRAID kboff + align */
|
||||
|
||||
/*
|
||||
* Various filesystem magics that we can check for. Note that kboff and
|
||||
* sboff are in kilobytes and bytes respectively. All magics are in
|
||||
* byte strings so we don't worry about endian issues.
|
||||
*/
|
||||
struct blkid_magic type_array[] = {
|
||||
/* type kboff sboff len magic align kbsize probe */
|
||||
{ "MDRAID", -64, 0, 4, "\251+N\374", 65536, 4, probe_mdraid },
|
||||
/*{ "LVM", 0, 0, 4, "HM\001\000", 1, 4, probe_lvm },*/
|
||||
{ "jbd", 1, 0x38, 2, "\123\357", 1, 1, probe_jbd },
|
||||
{ "ext3", 1, 0x38, 2, "\123\357", 1, 1, probe_ext3 },
|
||||
{ "ext2", 1, 0x38, 2, "\123\357", 1, 1, probe_ext2 },
|
||||
{ "reiserfs", 8, 0x34, 8, "ReIsErFs", 1, 1, probe_reiserfs },
|
||||
{ "reiserfs", 64, 0x34, 9, "ReIsEr2Fs", 1, 1, probe_reiserfs },
|
||||
{ "reiserfs", 64, 0x34, 9, "ReIsEr3Fs", 1, 1, probe_reiserfs },
|
||||
{ "reiserfs", 64, 0x34, 8, "ReIsErFs", 1, 1, probe_reiserfs },
|
||||
{ "reiserfs", 8, 20, 8, "ReIsErFs", 1, 1, probe_reiserfs },
|
||||
{ "ntfs", 0, 3, 8, "NTFS ", 1, 1, probe_default },
|
||||
{ "vfat", 0, 0x52, 5, "MSWIN", 1, 1, probe_vfat },
|
||||
{ "vfat", 0, 0x52, 8, "FAT32 ", 1, 1, probe_vfat },
|
||||
{ "msdos", 0, 0x36, 5, "MSDOS", 1, 1, probe_msdos },
|
||||
{ "msdos", 0, 0x36, 8, "FAT16 ", 1, 1, probe_msdos },
|
||||
{ "msdos", 0, 0x36, 8, "FAT12 ", 1, 1, probe_msdos },
|
||||
{ "minix", 1, 0x10, 2, "\177\023", 1, 1, probe_minix },
|
||||
{ "minix", 1, 0x10, 2, "\217\023", 1, 1, probe_minix },
|
||||
{ "minix", 1, 0x10, 2, "\150\044", 1, 1, probe_minix },
|
||||
{ "minix", 1, 0x10, 2, "\170\044", 1, 1, probe_minix },
|
||||
{ "vxfs", 1, 0, 4, "\365\374\001\245", 1, 1, probe_default },
|
||||
{ "xfs", 0, 0, 4, "XFSB", 1, 1, probe_xfs },
|
||||
{ "romfs", 0, 0, 8, "-rom1fs-", 1, 1, probe_default },
|
||||
{ "bfs", 0, 0, 4, "\316\372\173\033", 1, 1, probe_default },
|
||||
{ "cramfs", 0, 0, 4, "E=\315\034", 1, 1, probe_default },
|
||||
{ "qnx4", 0, 4, 6, "QNX4FS", 1, 1, probe_default },
|
||||
{ "iso9660", 32, 1, 5, "CD001", 1, 1, probe_default },
|
||||
{ "iso9660", 32, 9, 5, "CDROM", 1, 1, probe_default },
|
||||
{ "udf", 32, 1, 5, "BEA01", 1, 1, probe_default },
|
||||
{ "udf", 32, 1, 5, "BOOT2", 1, 1, probe_default },
|
||||
{ "udf", 32, 1, 5, "CD001", 1, 1, probe_default },
|
||||
{ "udf", 32, 1, 5, "CDW02", 1, 1, probe_default },
|
||||
{ "udf", 32, 1, 5, "NSR02", 1, 1, probe_default },
|
||||
{ "udf", 32, 1, 5, "NSR03", 1, 1, probe_default },
|
||||
{ "udf", 32, 1, 5, "TEA01", 1, 1, probe_default },
|
||||
{ "jfs", 32, 0, 4, "JFS1", 1, 1, probe_default },
|
||||
{ "hfs", 1, 0, 2, "BD", 1, 1, probe_hfs },
|
||||
{ "ufs", 8, 0x55c, 4, "T\031\001\000", 1, 1, probe_default },
|
||||
{ "hpfs", 8, 0, 4, "I\350\225\371", 1, 1, probe_default },
|
||||
{ "sysv", 0, 0x3f8, 4, "\020~\030\375", 1, 1, probe_default },
|
||||
{ "swap", 0, 0xff6, 10, "SWAP-SPACE", 1, 4, probe_swap },
|
||||
{ "swap", 0, 0xff6, 10, "SWAPSPACE2", 1, 4, probe_swap },
|
||||
{ "swap", 0, 0x1ff6, 10, "SWAP-SPACE", 1, 8, probe_swap },
|
||||
{ "swap", 0, 0x1ff6, 10, "SWAPSPACE2", 1, 8, probe_swap },
|
||||
{ "swap", 0, 0x3ff6, 10, "SWAP-SPACE", 1, 16, probe_swap },
|
||||
{ "swap", 0, 0x3ff6, 10, "SWAPSPACE2", 1, 16, probe_swap },
|
||||
{ NULL, 0, 0, 0, NULL, 1, 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* When probing for a lot of magics, we handle everything in 1kB buffers so
|
||||
* that we don't have to worry about reading each combination of block sizes.
|
||||
*/
|
||||
static unsigned char *read_one_buf(int fd, blkid_loff_t offset)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
if (lseek(fd, offset, SEEK_SET) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!(buf = (unsigned char *)malloc(BLKID_BLK_SIZE)))
|
||||
return NULL;
|
||||
|
||||
if (read(fd, buf, BLKID_BLK_SIZE) != BLKID_BLK_SIZE) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static unsigned char *read_sb_buf(int fd, unsigned char **bufs, int kboff,
|
||||
blkid_loff_t start)
|
||||
{
|
||||
int index = kboff >> BLKID_BLK_KBITS;
|
||||
unsigned char **buf;
|
||||
|
||||
if (index > BLKID_BLK_OFFS || index < -BLKID_BLK_OFFS) {
|
||||
fprintf(stderr, "reading from invalid offset %d (%d)!\n",
|
||||
kboff, index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = bufs + index;
|
||||
if (!*buf)
|
||||
*buf = read_one_buf(fd, start);
|
||||
|
||||
return *buf;
|
||||
}
|
||||
|
||||
static struct blkid_magic *devname_to_magic(const char *devname, int fd,
|
||||
unsigned char **bufs,
|
||||
struct blkid_magic *id,
|
||||
blkid_loff_t size)
|
||||
{
|
||||
struct blkid_magic *ret = NULL;
|
||||
|
||||
if (!bufs || fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (id >= type_array + sizeof(type_array) / sizeof(*id))
|
||||
return NULL;
|
||||
|
||||
for (id = id < type_array ? type_array : id + 1; id->bim_type; ++id) {
|
||||
unsigned char *buf;
|
||||
blkid_loff_t start = 0LL;
|
||||
blkid_loff_t offset = 0LL;
|
||||
int kboff;
|
||||
|
||||
offset = ((blkid_loff_t)id->bim_kboff << 10) +
|
||||
(id->bim_sboff & ~0x3ffULL);
|
||||
/*
|
||||
* We index negative buffers by their actual offset (including
|
||||
* superblock offsets > 1kB, not the aligned offset, so that
|
||||
* we correctly access negative buffers with different
|
||||
* alignment requirements.
|
||||
*/
|
||||
if (id->bim_kboff < 0) {
|
||||
start = (size & ~((blkid_loff_t)id->bim_align - 1)) +
|
||||
offset;
|
||||
if (start < 0) /* Device too small for alignment */
|
||||
continue;
|
||||
kboff = (start - size) >> 10;
|
||||
} else {
|
||||
start = offset;
|
||||
kboff = offset >> 10;
|
||||
}
|
||||
|
||||
if ((buf =
|
||||
read_sb_buf(fd, bufs, kboff, start)) &&
|
||||
!memcmp(id->bim_magic, buf + (id->bim_sboff&0x3ffULL),
|
||||
id->bim_len)) {
|
||||
ret = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get data from a single block special device.
|
||||
*
|
||||
* Return a blkid_dev with at least the device type and size set.
|
||||
* If the passed-in size is zero, then we get the device size here.
|
||||
*/
|
||||
blkid_dev *blkid_devname_to_dev(const char *devname, blkid_loff_t size)
|
||||
{
|
||||
unsigned char *buf_array[BLKID_BLK_OFFS * 2 + 1];
|
||||
unsigned char **bufs = buf_array + BLKID_BLK_OFFS;
|
||||
blkid_dev *dev = NULL, *last = NULL;
|
||||
unsigned char *sb_buf = NULL;
|
||||
int sb_size = 0;
|
||||
struct blkid_magic *id = NULL;
|
||||
blkid_loff_t diff_last = 0xf000000000000000ULL;
|
||||
int fd;
|
||||
|
||||
if (!devname)
|
||||
return NULL;
|
||||
|
||||
fd = open(devname, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (!size)
|
||||
size = blkid_get_dev_size(fd);
|
||||
if (size < 1024)
|
||||
goto exit_fd;
|
||||
|
||||
memset(buf_array, 0, sizeof(buf_array));
|
||||
|
||||
while ((id = devname_to_magic(devname, fd, bufs, id, size)) &&
|
||||
diff_last) {
|
||||
int new_sb;
|
||||
blkid_loff_t diff_dev;
|
||||
|
||||
DEB_PROBE("found type %s (#%d) on %s, probing\n",
|
||||
id->bim_type, id - type_array, devname);
|
||||
|
||||
new_sb = id->bim_kbsize << 10;
|
||||
if (sb_size < new_sb) {
|
||||
unsigned char *sav = sb_buf;
|
||||
if (!(sb_buf = realloc(sb_buf, new_sb))) {
|
||||
sb_buf = sav;
|
||||
continue;
|
||||
}
|
||||
sb_size = new_sb;
|
||||
}
|
||||
|
||||
if (id->bim_probe(fd, &dev, devname, id, sb_buf, size) < 0)
|
||||
continue;
|
||||
|
||||
diff_dev = size - dev->bid_size;
|
||||
DEB_PROBE("size = %Lu, fs size = %Lu\n", size, dev->bid_size);
|
||||
DEB_PROBE("checking best match: old %Ld, new %Ld\n",
|
||||
diff_last, diff_dev);
|
||||
/* See which type is a better match by checking size */
|
||||
if ((diff_last < 0 && diff_dev > diff_last) ||
|
||||
(diff_last > 0 && diff_dev >= 0 && diff_dev < diff_last)) {
|
||||
if (last)
|
||||
blkid_free_dev(last);
|
||||
last = dev;
|
||||
diff_last = diff_dev;
|
||||
} else
|
||||
blkid_free_dev(dev);
|
||||
}
|
||||
|
||||
if (!last)
|
||||
DEB_PROBE("unknown device type on %s\n", devname);
|
||||
else
|
||||
DEB_DUMP_DEV(last);
|
||||
|
||||
/* Free up any buffers we allocated */
|
||||
for (bufs = buf_array; bufs - buf_array < sizeof(buf_array) /
|
||||
sizeof(buf_array[0]); bufs++) {
|
||||
if (*bufs)
|
||||
free(*bufs);
|
||||
}
|
||||
|
||||
if (sb_buf)
|
||||
free(sb_buf);
|
||||
exit_fd:
|
||||
close(fd);
|
||||
return last;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that the data in dev is consistent with what is on the actual
|
||||
* block device (using the devname field only). Normally this will be
|
||||
* called when finding items in the cache, but for long running processes
|
||||
* is also desirable to revalidate an item before use.
|
||||
*
|
||||
* If we are unable to revalidate the data, we return the old data and
|
||||
* do not set the BLKID_BID_FL_VERIFIED flag on it.
|
||||
*/
|
||||
blkid_dev *blkid_verify_devname(blkid_cache *cache, blkid_dev *dev)
|
||||
{
|
||||
blkid_loff_t size;
|
||||
struct blkid_magic *id;
|
||||
blkid_dev *new = NULL;
|
||||
char *sb_buf = NULL;
|
||||
int sb_size = 0;
|
||||
time_t diff;
|
||||
int fd;
|
||||
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
diff = time(0) - dev->bid_time;
|
||||
|
||||
if (diff < BLKID_PROBE_MIN || (dev->bid_flags & BLKID_BID_FL_VERIFIED &&
|
||||
diff < BLKID_PROBE_INTERVAL))
|
||||
return dev;
|
||||
|
||||
DEB_PROBE("need to revalidate %s\n", dev->bid_name);
|
||||
|
||||
if ((fd = open(dev->bid_name, O_RDONLY)) < 0) {
|
||||
if (errno == ENXIO || errno == ENODEV) {
|
||||
fprintf(stderr, "unable to open %s for revalidation\n",
|
||||
dev->bid_name);
|
||||
blkid_free_dev(dev);
|
||||
return NULL;
|
||||
}
|
||||
/* We don't have read permission, just return cache data. */
|
||||
DEB_PROBE("returning unverified data for %s\n", dev->bid_name);
|
||||
return dev;
|
||||
}
|
||||
|
||||
size = blkid_get_dev_size(fd);
|
||||
|
||||
/* See if we can probe this device by its existing type directly */
|
||||
for (id = type_array; id->bim_type; id++) {
|
||||
if (!strcmp(id->bim_type, dev->bid_type)) {
|
||||
int new_sb = id->bim_kbsize << 10;
|
||||
/* See if we need to allocate a larger sb buffer */
|
||||
if (sb_size < new_sb) {
|
||||
char *sav = sb_buf;
|
||||
|
||||
/* We can't revalidate, return old dev */
|
||||
if (!(sb_buf = realloc(sb_buf, new_sb))) {
|
||||
fprintf(stderr, "not enough memory for "
|
||||
"%s revalidation\n",
|
||||
dev->bid_name);
|
||||
free(sav);
|
||||
goto exit_fd;
|
||||
}
|
||||
sb_size = new_sb;
|
||||
}
|
||||
|
||||
if (id->bim_probe(fd, &new, dev->bid_name, id, sb_buf,
|
||||
size) == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sb_buf)
|
||||
free(sb_buf);
|
||||
|
||||
/* Otherwise we need to determine the device type first */
|
||||
if (new || (new = blkid_devname_to_dev(dev->bid_name, size))) {
|
||||
new->bid_id = dev->bid_id; /* save old id for cache */
|
||||
blkid_free_dev(dev);
|
||||
dev = blkid_add_dev_to_cache(cache, new);
|
||||
}
|
||||
|
||||
exit_fd:
|
||||
close(fd);
|
||||
|
||||
/* In case the cache is missing the device size */
|
||||
if (dev->bid_devsize == 0)
|
||||
dev->bid_devsize = size;
|
||||
return dev;
|
||||
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s device\n"
|
||||
"Probe a single device to determine type\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
dev = blkid_devname_to_dev(argv[1], 0);
|
||||
if (dev)
|
||||
blkid_free_dev(dev);
|
||||
else
|
||||
printf("%s: %s has an unsupported type\n", argv[0], argv[1]);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* probe.h - constants and on-disk structures for extracting device data
|
||||
*
|
||||
* Copyright (C) 1999 by Andries Brouwer
|
||||
* Copyright (C) 1999, 2000 by Theodore Ts'o
|
||||
* Copyright (C) 2001 by Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _BLKID_PROBE_H
|
||||
#define _BLKID_PROBE_H
|
||||
|
||||
#include <blkid/blkid_types.h>
|
||||
|
||||
struct blkid_magic;
|
||||
|
||||
typedef int (*blkid_probe_t)(int fd, blkid_dev **dev_p, const char *devname,
|
||||
struct blkid_magic *id, unsigned char *buf,
|
||||
blkid_loff_t size);
|
||||
|
||||
struct blkid_magic {
|
||||
const char *bim_type; /* type name for this magic */
|
||||
long bim_kboff; /* kilobyte offset of superblock */
|
||||
unsigned bim_sboff; /* byte offset within superblock */
|
||||
unsigned bim_len; /* length of magic */
|
||||
unsigned char *bim_magic; /* magic string */
|
||||
unsigned bim_align; /* byte alignment of superblock */
|
||||
unsigned bim_kbsize; /* size of superblock in kilobytes */
|
||||
blkid_probe_t bim_probe; /* probe function */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structures for each of the content types we want to extract information
|
||||
* from. We do not necessarily need the magic field here, because we have
|
||||
* already identified the content type before we get this far. It may still
|
||||
* be useful if there are probe functions which handle multiple content types.
|
||||
*/
|
||||
struct ext2_super_block {
|
||||
__u32 s_inodes_count;
|
||||
__u32 s_blocks_count;
|
||||
__u32 s_r_blocks_count;
|
||||
__u32 s_free_blocks_count;
|
||||
__u32 s_free_inodes_count;
|
||||
__u32 s_first_data_block;
|
||||
__u32 s_log_block_size;
|
||||
__u32 s_dummy3[7];
|
||||
unsigned char s_magic[2];
|
||||
__u16 s_state;
|
||||
__u32 s_dummy5[8];
|
||||
__u32 s_feature_compat;
|
||||
__u32 s_feature_incompat;
|
||||
__u32 s_feature_ro_compat;
|
||||
unsigned char s_uuid[16];
|
||||
unsigned char s_volume_name[16];
|
||||
};
|
||||
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x00000004
|
||||
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x00000004
|
||||
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x00000008
|
||||
|
||||
struct xfs_super_block {
|
||||
unsigned char xs_magic[4];
|
||||
__u32 xs_blocksize;
|
||||
__u64 xs_dblocks;
|
||||
__u64 xs_rblocks;
|
||||
__u32 xs_dummy1[8];
|
||||
unsigned char xs_uuid[16];
|
||||
__u32 xs_dummy2[15];
|
||||
unsigned char xs_fname[12];
|
||||
__u32 xs_dummy3[2];
|
||||
__u64 xs_icount;
|
||||
__u64 xs_ifree;
|
||||
__u64 xs_fdblocks;
|
||||
};
|
||||
|
||||
struct reiserfs_super_block {
|
||||
__u32 rs_blocks_count;
|
||||
__u32 rs_free_blocks;
|
||||
__u32 rs_root_block;
|
||||
__u32 rs_journal_block;
|
||||
__u32 rs_journal_dev;
|
||||
__u32 rs_orig_journal_size;
|
||||
__u32 rs_dummy2[5];
|
||||
__u16 rs_blocksize;
|
||||
__u16 rs_dummy3[3];
|
||||
unsigned char rs_magic[12];
|
||||
__u32 rs_dummy4[5];
|
||||
unsigned char rs_uuid[16];
|
||||
unsigned char rs_label[16];
|
||||
};
|
||||
|
||||
/* Yucky misaligned values */
|
||||
struct vfat_super_block {
|
||||
/* 00*/ unsigned char vs_ignored[3];
|
||||
/* 03*/ unsigned char vs_sysid[8];
|
||||
/* 0b*/ unsigned char vs_sector_size[2];
|
||||
/* 0d*/ __u8 vs_cluster_size;
|
||||
/* 0e*/ __u16 vs_reserved;
|
||||
/* 10*/ __u8 vs_fats;
|
||||
/* 11*/ unsigned char vs_dir_entries[2];
|
||||
/* 13*/ unsigned char vs_sectors[2];
|
||||
/* 15*/ unsigned char vs_media;
|
||||
/* 16*/ __u16 vs_fat_length;
|
||||
/* 18*/ __u16 vs_secs_track;
|
||||
/* 1a*/ __u16 vs_heads;
|
||||
/* 1c*/ __u32 vs_hidden;
|
||||
/* 20*/ __u32 vs_total_sect;
|
||||
/* 24*/ __u32 vs_fat32_length;
|
||||
/* 28*/ __u16 vs_flags;
|
||||
/* 2a*/ __u8 vs_version[2];
|
||||
/* 2c*/ __u32 vs_root_cluster;
|
||||
/* 30*/ __u16 vs_insfo_sector;
|
||||
/* 32*/ __u16 vs_backup_boot;
|
||||
/* 34*/ __u16 vs_reserved2[6];
|
||||
/* 40*/ unsigned char vs_unknown[3];
|
||||
/* 43*/ unsigned char vs_serno[4];
|
||||
/* 47*/ unsigned char vs_label[11];
|
||||
/* 52*/ unsigned char vs_magic[8];
|
||||
/* 5a*/ unsigned char vs_dummy2[164];
|
||||
/*1fe*/ unsigned char vs_pmagic[2];
|
||||
};
|
||||
|
||||
/* Yucky misaligned values */
|
||||
struct msdos_super_block {
|
||||
/* 00*/ unsigned char ms_ignored[3];
|
||||
/* 03*/ unsigned char ms_sysid[8];
|
||||
/* 0b*/ unsigned char ms_sector_size[2];
|
||||
/* 0d*/ __u8 ms_cluster_size;
|
||||
/* 0e*/ __u16 ms_reserved;
|
||||
/* 10*/ __u8 ms_fats;
|
||||
/* 11*/ unsigned char ms_dir_entries[2];
|
||||
/* 13*/ unsigned char ms_sectors[2];
|
||||
/* 15*/ unsigned char ms_media;
|
||||
/* 16*/ __u16 ms_fat_length;
|
||||
/* 18*/ __u16 ms_secs_track;
|
||||
/* 1a*/ __u16 ms_heads;
|
||||
/* 1c*/ __u32 ms_hidden;
|
||||
/* 20*/ __u32 ms_total_sect;
|
||||
/* 24*/ unsigned char ms_unknown[3];
|
||||
/* 27*/ unsigned char ms_serno[4];
|
||||
/* 2b*/ unsigned char ms_label[11];
|
||||
/* 36*/ unsigned char ms_magic[8];
|
||||
/* 3d*/ unsigned char ms_dummy2[192];
|
||||
/*1fe*/ unsigned char ms_pmagic[2];
|
||||
};
|
||||
|
||||
struct minix_super_block {
|
||||
__u16 ms_ninodes;
|
||||
__u16 ms_nzones;
|
||||
__u16 ms_imap_blocks;
|
||||
__u16 ms_zmap_blocks;
|
||||
__u16 ms_firstdatazone;
|
||||
__u16 ms_log_zone_size;
|
||||
__u32 ms_max_size;
|
||||
unsigned char ms_magic[2];
|
||||
__u16 ms_state;
|
||||
__u32 ms_zones;
|
||||
};
|
||||
|
||||
struct swap_header {
|
||||
char sh_bootbits[1024];
|
||||
unsigned int sh_version;
|
||||
unsigned int sh_last_page;
|
||||
unsigned int sh_nr_badpages;
|
||||
char sh_label[16];
|
||||
};
|
||||
|
||||
struct mdp_superblock_s {
|
||||
__u32 md_magic;
|
||||
__u32 major_version;
|
||||
__u32 minor_version;
|
||||
__u32 patch_version;
|
||||
__u32 gvalid_words;
|
||||
__u32 set_uuid0;
|
||||
__u32 ctime;
|
||||
__u32 level;
|
||||
__u32 size;
|
||||
__u32 nr_disks;
|
||||
__u32 raid_disks;
|
||||
__u32 md_minor;
|
||||
__u32 not_persistent;
|
||||
__u32 set_uuid1;
|
||||
__u32 set_uuid2;
|
||||
__u32 set_uuid3;
|
||||
};
|
||||
|
||||
struct hfs_super_block {
|
||||
char h_magic[2];
|
||||
char h_dummy[18];
|
||||
__u32 h_blksize;
|
||||
};
|
||||
|
||||
#ifndef le32_to_cpu /* Assume if one is defined, all are defined */
|
||||
#define X16_to_cpu(x) ((__u16)((((__u16)(x) & 0x00ffU) << 8) | \
|
||||
(((__u16)(x) & 0xff00U) >> 8)))
|
||||
#define X32_to_cpu(x) ((__u32)((((__u32)(x) & 0x000000ffU) << 24) | \
|
||||
(((__u32)(x) & 0x0000ff00U) << 8) | \
|
||||
(((__u32)(x) & 0x00ff0000U) >> 8) | \
|
||||
(((__u32)(x) & 0xff000000U) >> 24)))
|
||||
#define X64_to_cpu(x) ((__u64)((((__u64)(x) & 0x00000000000000ffULL) << 56) | \
|
||||
(((__u64)(x) & 0x000000000000ff00ULL) << 40) | \
|
||||
(((__u64)(x) & 0x0000000000ff0000ULL) << 24) | \
|
||||
(((__u64)(x) & 0x00000000ff000000ULL) << 8) | \
|
||||
(((__u64)(x) & 0x000000ff00000000ULL) >> 8) | \
|
||||
(((__u64)(x) & 0x0000ff0000000000ULL) >> 24) | \
|
||||
(((__u64)(x) & 0x00ff000000000000ULL) >> 40) | \
|
||||
(((__u64)(x) & 0xff00000000000000ULL) >> 56)))
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define le16_to_cpu(x) X16_to_cpu(x)
|
||||
#define le32_to_cpu(x) X32_to_cpu(x)
|
||||
#define le64_to_cpu(x) X64_to_cpu(x)
|
||||
#define be16_to_cpu(x) (x)
|
||||
#define be32_to_cpu(x) (x)
|
||||
#define be64_to_cpu(x) (x)
|
||||
#else
|
||||
#define le16_to_cpu(x) (x)
|
||||
#define le32_to_cpu(x) (x)
|
||||
#define le64_to_cpu(x) (x)
|
||||
#define be16_to_cpu(x) X16_to_cpu(x)
|
||||
#define be32_to_cpu(x) X32_to_cpu(x)
|
||||
#define be64_to_cpu(x) X64_to_cpu(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _BLKID_PROBE_H */
|
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* read.c - read the blkid cache from disk, to avoid scanning all devices
|
||||
*
|
||||
* Copyright (C) 2001 Theodore Y. Ts'o
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
#include "uuid/uuid.h"
|
||||
|
||||
#ifdef DEBUG_CACHE
|
||||
#define DEB_CACHE(fmt, arg...) printf("cache:" fmt, ##arg)
|
||||
#else
|
||||
#define DEB_CACHE(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRTOULL
|
||||
#define __USE_ISOC9X
|
||||
#define STRTOULL strtoull /* defined in stdlib.h if you try hard enough */
|
||||
#else
|
||||
/* FIXME: need to support real strtoull here */
|
||||
#define STRTOULL strtoul
|
||||
#endif
|
||||
|
||||
#if HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* File format:
|
||||
*
|
||||
* <device [<NAME="value"> ...]>device_name</device>
|
||||
*
|
||||
* The following tags are required for each entry:
|
||||
* <ID="id"> unique (within this file) ID number of this device
|
||||
* <TIME="time"> (ascii time_t) time this entry was last read from disk
|
||||
* <TYPE="type"> (detected) type of filesystem/data for this partition
|
||||
*
|
||||
* The following tags may be present, depending on the device contents
|
||||
* <LABEL="label"> (user supplied) label (volume name, etc)
|
||||
* <UUID="uuid"> (generated) universally unique identifier (serial no)
|
||||
*/
|
||||
|
||||
static char *skip_over_blank(char *cp)
|
||||
{
|
||||
while (*cp && isspace(*cp))
|
||||
cp++;
|
||||
return cp;
|
||||
}
|
||||
|
||||
static char *skip_over_word(char *cp)
|
||||
{
|
||||
char ch;
|
||||
|
||||
while ((ch = *cp)) {
|
||||
/* If we see a backslash, skip the next character */
|
||||
if (ch == '\\') {
|
||||
cp++;
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
cp++;
|
||||
continue;
|
||||
}
|
||||
if (isspace(ch) || ch == '<' || ch == '>')
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
static char *strip_line(char *line)
|
||||
{
|
||||
char *p;
|
||||
|
||||
line = skip_over_blank(line);
|
||||
|
||||
p = line + strlen(line) - 1;
|
||||
|
||||
while (*line) {
|
||||
if (isspace(*p))
|
||||
*p-- = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static char *parse_word(char **buf)
|
||||
{
|
||||
char *word, *next;
|
||||
|
||||
word = *buf;
|
||||
if (*word == '\0')
|
||||
return NULL;
|
||||
|
||||
word = skip_over_blank(word);
|
||||
next = skip_over_word(word);
|
||||
if (*next) {
|
||||
char *end = next - 1;
|
||||
if (*end == '"' || *end == '\'')
|
||||
*end = '\0';
|
||||
*next++ = '\0';
|
||||
}
|
||||
*buf = next;
|
||||
|
||||
if (*word == '"' || *word == '\'')
|
||||
word++;
|
||||
return word;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Start parsing a new line from the cache.
|
||||
*
|
||||
* line starts with "<device" return 1 -> continue parsing line
|
||||
* line starts with "<foo", empty, or # return 0 -> skip line
|
||||
* line starts with other, return -BLKID_ERR_CACHE -> error
|
||||
*/
|
||||
static int parse_start(char **cp)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = strip_line(*cp);
|
||||
|
||||
/* Skip comment or blank lines. We can't just NUL the first '#' char,
|
||||
* in case it is inside quotes, or escaped.
|
||||
*/
|
||||
if (*p == '\0' || *p == '#')
|
||||
return 0;
|
||||
|
||||
if (!strncmp(p, "<device", 7)) {
|
||||
DEB_CACHE("found device header: %8s\n", p);
|
||||
p += 7;
|
||||
|
||||
*cp = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (*p == '<')
|
||||
return 0;
|
||||
|
||||
return -BLKID_ERR_CACHE;
|
||||
}
|
||||
|
||||
/* Consume the remaining XML on the line (cosmetic only) */
|
||||
static int parse_end(char **cp)
|
||||
{
|
||||
*cp = skip_over_blank(*cp);
|
||||
|
||||
if (!strncmp(*cp, "</device>", 9)) {
|
||||
DEB_CACHE("found device trailer %9s\n", *cp);
|
||||
*cp += 9;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -BLKID_ERR_CACHE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new device struct with device name filled in. Will handle
|
||||
* finding the device on lines of the form:
|
||||
* <device foo=bar>devname</device>
|
||||
* <device>devname<foo>bar</foo></device>
|
||||
*/
|
||||
static int parse_dev(blkid_dev **dev, char **cp)
|
||||
{
|
||||
char **name;
|
||||
char *start, *tmp, *end;
|
||||
int ret;
|
||||
|
||||
if ((ret = parse_start(cp)) <= 0)
|
||||
return ret;
|
||||
|
||||
start = tmp = strchr(*cp, '>');
|
||||
if (!start) {
|
||||
fprintf(stderr, "blkid: short line parsing dev: %s\n", *cp);
|
||||
return -BLKID_ERR_CACHE;
|
||||
}
|
||||
start = skip_over_blank(start + 1);
|
||||
end = skip_over_word(start);
|
||||
|
||||
DEB_CACHE("device should be %*s\n", end - start, start);
|
||||
|
||||
if (**cp == '>')
|
||||
*cp = end;
|
||||
else
|
||||
(*cp)++;
|
||||
|
||||
*tmp = '\0';
|
||||
|
||||
if (!(tmp = strrchr(end, '<')) || parse_end(&tmp) < 0)
|
||||
fprintf(stderr, "blkid: missing </device> ending: %s\n", end);
|
||||
else if (tmp)
|
||||
*tmp = '\0';
|
||||
|
||||
if (end - start <= 1) {
|
||||
fprintf(stderr, "blkid: empty device name: %s\n", *cp);
|
||||
return -BLKID_ERR_CACHE;
|
||||
}
|
||||
|
||||
if (!(*dev = blkid_new_dev()))
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
name = &(*dev)->bid_name;
|
||||
*name = (char *)malloc(end - start + 1);
|
||||
if (*name == NULL) {
|
||||
blkid_free_dev(*dev);
|
||||
return -BLKID_ERR_MEM;
|
||||
}
|
||||
|
||||
memcpy(*name, start, end - start);
|
||||
(*name)[end - start] = '\0';
|
||||
|
||||
DEB_CACHE("found dev %s\n", *name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a tag of the form NAME="value" from the line.
|
||||
*/
|
||||
static int parse_token(char **name, char **value, char **cp)
|
||||
{
|
||||
char *end;
|
||||
|
||||
if (!name || !value || !cp)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (!(*value = strchr(*cp, '=')))
|
||||
return 0;
|
||||
|
||||
**value = '\0';
|
||||
*name = strip_line(*cp);
|
||||
*value = skip_over_blank(*value + 1);
|
||||
|
||||
if (**value == '"') {
|
||||
end = strchr(*value + 1, '"');
|
||||
if (!end) {
|
||||
fprintf(stderr, "unbalanced quotes at: %s\n", *value);
|
||||
*cp = *value;
|
||||
return -BLKID_ERR_CACHE;
|
||||
}
|
||||
(*value)++;
|
||||
*end = '\0';
|
||||
end++;
|
||||
} else {
|
||||
end = skip_over_word(*value);
|
||||
if (*end) {
|
||||
*end = '\0';
|
||||
end++;
|
||||
}
|
||||
}
|
||||
*cp = end;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a tag of the form <NAME>value</NAME> from the line.
|
||||
*/
|
||||
/*
|
||||
static int parse_xml(char **name, char **value, char **cp)
|
||||
{
|
||||
char *end;
|
||||
|
||||
if (!name || !value || !cp)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
*name = strip_line(*cp);
|
||||
|
||||
if ((*name)[0] != '<' || (*name)[1] == '/')
|
||||
return 0;
|
||||
|
||||
FIXME: finish this.
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
* Extract a tag from the line.
|
||||
*
|
||||
* Return 1 if a valid tag was found.
|
||||
* Return 0 if no tag found.
|
||||
* Return -ve error code.
|
||||
*/
|
||||
static int parse_tag(blkid_cache *cache, blkid_dev *dev, blkid_tag **tag,
|
||||
char **cp)
|
||||
{
|
||||
char *name;
|
||||
char *value;
|
||||
int ret;
|
||||
|
||||
if (!cache || !dev)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
*tag = NULL;
|
||||
|
||||
if ((ret = parse_token(&name, &value, cp)) <= 0 /* &&
|
||||
(ret = parse_xml(&name, &value, cp)) <= 0 */)
|
||||
return ret;
|
||||
|
||||
/* Some tags are stored directly in the device struct */
|
||||
if (!strcmp(name, "ID")) {
|
||||
dev->bid_id = (unsigned int)strtoul(value, 0, 0);
|
||||
if (dev->bid_id > cache->bic_idmax)
|
||||
cache->bic_idmax = dev->bid_id;
|
||||
} else if (!strcmp(name, "DEVNO"))
|
||||
dev->bid_devno = STRTOULL(value, 0, 0);
|
||||
else if (!strcmp(name, "DEVSIZE"))
|
||||
dev->bid_devno = STRTOULL(value, 0, 0);
|
||||
else if (!strcmp(name, "TIME"))
|
||||
/* FIXME: need to parse a long long eventually */
|
||||
dev->bid_time = strtol(value, 0, 0);
|
||||
else
|
||||
ret = blkid_create_tag(dev, tag, name, value, strlen(value));
|
||||
|
||||
return ret < 0 ? ret : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a single line of data, and return a newly allocated dev struct.
|
||||
* Add the new device to the cache struct, if one was read.
|
||||
*
|
||||
* Lines are of the form <device [TAG="value" ...]>/dev/foo</device>
|
||||
*
|
||||
* Returns -ve value on error.
|
||||
* Returns 0 otherwise.
|
||||
* If a valid device was read, *dev_p is non-NULL, otherwise it is NULL
|
||||
* (e.g. comment lines, unknown XML content, etc).
|
||||
*/
|
||||
int blkid_parse_line(blkid_cache *cache, blkid_dev **dev_p, char *cp)
|
||||
{
|
||||
blkid_dev *dev;
|
||||
blkid_tag *tag;
|
||||
int ret;
|
||||
|
||||
if (!cache || !dev_p)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
*dev_p = NULL;
|
||||
|
||||
DEB_CACHE("line: %s\n", cp);
|
||||
|
||||
if ((ret = parse_dev(dev_p, &cp)) <= 0)
|
||||
return ret;
|
||||
|
||||
dev = *dev_p;
|
||||
|
||||
while ((ret = parse_tag(cache, dev, &tag, &cp)) > 0) {
|
||||
/* Added to tags for this device struct already */
|
||||
DEB_DUMP_TAG(tag);
|
||||
}
|
||||
|
||||
if (dev->bid_type == NULL) {
|
||||
fprintf(stderr, "blkid: device %s has no TYPE\n",dev->bid_name);
|
||||
blkid_free_dev(dev);
|
||||
}
|
||||
|
||||
DEB_DUMP_DEV(dev);
|
||||
|
||||
*dev_p = blkid_add_dev_to_cache(cache, dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the given file stream for cached device data, and return it
|
||||
* in a newly allocated cache struct.
|
||||
*
|
||||
* Returns 0 on success, or -ve error value.
|
||||
*/
|
||||
int blkid_read_cache_file(blkid_cache **cache, FILE *file)
|
||||
{
|
||||
char buf[4096];
|
||||
int lineno = 0;
|
||||
|
||||
if (!file || !cache)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (!*cache)
|
||||
*cache = blkid_new_cache();
|
||||
|
||||
if (!*cache)
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
while (fgets(buf, sizeof(buf), file)) {
|
||||
blkid_dev *dev;
|
||||
|
||||
int end = strlen(buf) - 1;
|
||||
|
||||
lineno++;
|
||||
/* Continue reading next line if it ends with a backslash */
|
||||
while (buf[end] == '\\' && end < sizeof(buf) - 2 &&
|
||||
fgets(buf + end, sizeof(buf) - end, stdin)) {
|
||||
end = strlen(buf) - 1;
|
||||
lineno++;
|
||||
}
|
||||
|
||||
if (blkid_parse_line(*cache, &dev, buf) < 0) {
|
||||
fprintf(stderr, "blkid: bad format on line %d\n",
|
||||
lineno);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initially assume that we do not need to write out the cache file.
|
||||
* This would be incorrect if we probed first, and parsed the cache
|
||||
* afterwards, or parsed two caches and wanted to write it out, but
|
||||
* the alternative is to force manually marking the cache dirty when
|
||||
* any device is added, and that is also prone to error.
|
||||
*/
|
||||
(*cache)->bic_flags &= ~BLKID_BIC_FL_CHANGED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the specified filename, and return the data in the supplied or
|
||||
* a newly allocated cache struct. If the file doesn't exist, return a
|
||||
* new empty cache struct.
|
||||
*/
|
||||
int blkid_read_cache(blkid_cache **cache, const char *filename)
|
||||
{
|
||||
FILE *file;
|
||||
int ret;
|
||||
|
||||
if (!cache)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (!filename || !strlen(filename))
|
||||
filename = BLKID_CACHE_FILE;
|
||||
|
||||
DEB_CACHE("cache file %s\n", filename);
|
||||
|
||||
/* If we read the standard cache file, do not do so again */
|
||||
if (!strcmp(filename, BLKID_CACHE_FILE) && (*cache) &&
|
||||
((*cache)->bic_flags & BLKID_BIC_FL_PARSED))
|
||||
return 0;
|
||||
|
||||
if (!strcmp(filename, "-") || !strcmp(filename, "stdin"))
|
||||
file = stdin;
|
||||
else {
|
||||
/*
|
||||
* If the file doesn't exist, then we just return an empty
|
||||
* struct so that the cache can be populated.
|
||||
*/
|
||||
if (access(filename, R_OK) < 0) {
|
||||
*cache = blkid_new_cache();
|
||||
|
||||
return *cache ? 0 : -BLKID_ERR_MEM;
|
||||
}
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (!file) {
|
||||
perror(filename);
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
ret = blkid_read_cache_file(cache, file);
|
||||
|
||||
if (file != stdin)
|
||||
fclose(file);
|
||||
|
||||
/* Mark us as having read the standard cache file */
|
||||
if (!strcmp(filename, BLKID_CACHE_FILE))
|
||||
(*cache)->bic_flags |= BLKID_BIC_FL_PARSED;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
blkid_cache *cache = NULL;
|
||||
int ret;
|
||||
|
||||
if (argc > 2) {
|
||||
fprintf(stderr, "Usage: %s [filename]\n"
|
||||
"Test parsing of the cache (filename)\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if ((ret = blkid_read_cache(&cache, argv[1])) < 0)
|
||||
fprintf(stderr, "error %d reading cache file %s\n", ret,
|
||||
argv[1] ? argv[1] : BLKID_CACHE_FILE);
|
||||
|
||||
blkid_free_cache(cache);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* resolve.c - resolve names and tags into specific devices
|
||||
*
|
||||
* Copyright (C) 2001 Theodore Ts'o.
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "blkid/blkid.h"
|
||||
#include "probe.h"
|
||||
|
||||
#ifdef DEBUG_RESOLVE
|
||||
#define DEB_RESOLVE(fmt, arg...) printf("resolve: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_RESOLVE(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Find a tagname (e.g. LABEL or UUID) on a specific device.
|
||||
*/
|
||||
char *blkid_get_tagname_devname(blkid_cache *cache, const char *tagname,
|
||||
const char *devname)
|
||||
{
|
||||
blkid_tag *tag, *found;
|
||||
blkid_dev *dev;
|
||||
char *ret = NULL;
|
||||
|
||||
DEB_RESOLVE("looking for %s on %s\n", tagname, devname);
|
||||
|
||||
if (!devname)
|
||||
return NULL;
|
||||
|
||||
if (blkid_create_tag(NULL, &tag, tagname, NULL, 0) < 0)
|
||||
return NULL;
|
||||
|
||||
if (!cache)
|
||||
DEB_RESOLVE("no cache given, direct device probe\n");
|
||||
|
||||
if ((dev = blkid_get_devname(cache, devname)) &&
|
||||
(found = blkid_find_tag_dev(dev, tag)))
|
||||
ret = string_copy(found->bit_val);
|
||||
|
||||
if (!cache)
|
||||
blkid_free_dev(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate a device name from a token (NAME=value string), or (name, value)
|
||||
* pair. In the case of a token, value is ignored. If the "token" is not
|
||||
* of the form "NAME=value" and there is no value given, then it is assumed
|
||||
* to be the actual devname and a copy is returned.
|
||||
*
|
||||
* The string returned must be freed with string_free().
|
||||
*/
|
||||
char *blkid_get_token(blkid_cache *cache, const char *token,
|
||||
const char *value)
|
||||
{
|
||||
blkid_tag *tag = NULL, *found = NULL;
|
||||
blkid_cache *c = cache;
|
||||
char *name = NULL;
|
||||
|
||||
DEB_RESOLVE("looking for %s%c%s %s\n", token, value ? '=' : ' ',
|
||||
value ? value : "", cache ? "in cache" : "from disk");
|
||||
|
||||
if (!(tag = blkid_token_to_tag(token))) {
|
||||
if (!value)
|
||||
return string_copy(token);
|
||||
if (blkid_create_tag(NULL,&tag,token,value,strlen(value)) < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!cache) {
|
||||
if (blkid_read_cache(&c, NULL) < 0)
|
||||
c = blkid_new_cache();
|
||||
if (!c)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((found = blkid_get_tag_cache(c, tag)) && found->bit_dev)
|
||||
name = string_copy(found->bit_dev->bid_name);
|
||||
|
||||
if (!cache) {
|
||||
blkid_save_cache(c, NULL);
|
||||
blkid_free_cache(c);
|
||||
}
|
||||
|
||||
|
||||
blkid_free_tag(tag);
|
||||
return name;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *value;
|
||||
|
||||
if (argc != 2 && argc != 3) {
|
||||
fprintf(stderr, "Usage:\t%s tagname=value\n"
|
||||
"\t%s tagname devname\n"
|
||||
"Find which device holds a given token or\n"
|
||||
"Find what the value of a tag is in a device\n",
|
||||
argv[0], argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if (argv[2]) {
|
||||
value = blkid_get_tagname_devname(NULL, argv[1], argv[2]);
|
||||
printf("%s has tag %s=%s\n", argv[2], argv[1],
|
||||
value ? value : "<missing>");
|
||||
} else {
|
||||
value = blkid_get_token(NULL, argv[1], NULL);
|
||||
printf("%s has tag %s\n", value ? value : "<none>", argv[1]);
|
||||
}
|
||||
return value ? 0 : 1;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* save.c - write the cache struct to disk
|
||||
*
|
||||
* Copyright (C) 2001 by Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
#ifdef DEBUG_SAVE
|
||||
#define DEB_SAVE(fmt, arg...) printf("save: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_SAVE(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
static int save_dev(blkid_dev *dev, FILE *file)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
|
||||
DEB_SAVE("device %s, type %s\n", dev->bid_name, dev->bid_type);
|
||||
|
||||
fprintf(file,
|
||||
"<device TYPE=\"%s\" DEVNO=\"0x%04Lx\" ID=\"%d\" TIME=\"%Ld\"",
|
||||
dev->bid_type, dev->bid_devno,
|
||||
dev->bid_id, (long long)dev->bid_time);
|
||||
list_for_each(p, &dev->bid_tags) {
|
||||
blkid_tag *tag = list_entry(p, blkid_tag, bit_tags);
|
||||
if (strcmp(tag->bit_name, "TYPE"))
|
||||
fprintf(file, " %s=\"%s\"", tag->bit_name,tag->bit_val);
|
||||
}
|
||||
fprintf(file, ">%s</device>\n", dev->bid_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blkid_save_cache_file(blkid_cache *cache, FILE *file)
|
||||
{
|
||||
struct list_head *p;
|
||||
int ret = 0;
|
||||
|
||||
if (!cache || !file)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (list_empty(&cache->bic_devs) ||
|
||||
!cache->bic_flags & BLKID_BIC_FL_CHANGED)
|
||||
return 0;
|
||||
|
||||
list_for_each(p, &cache->bic_devs) {
|
||||
blkid_dev *dev = list_entry(p, blkid_dev, bid_devs);
|
||||
if ((ret = save_dev(dev, file)) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret >= 0) {
|
||||
cache->bic_flags &= ~BLKID_BIC_FL_CHANGED;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the cache struct to the cache file on disk.
|
||||
*/
|
||||
int blkid_save_cache(blkid_cache *cache, char *filename)
|
||||
{
|
||||
char tmp[4096] = { '\0', };
|
||||
char *opened = NULL;
|
||||
FILE *file = NULL;
|
||||
int ret;
|
||||
|
||||
if (!cache)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (list_empty(&cache->bic_devs) ||
|
||||
!(cache->bic_flags & BLKID_BIC_FL_CHANGED)) {
|
||||
DEB_SAVE("empty cache, not saving\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!filename || !strlen(filename))
|
||||
filename = BLKID_CACHE_FILE;
|
||||
|
||||
if (!strcmp(filename, "-") || !strcmp(filename, "stdout"))
|
||||
file = stdout;
|
||||
else {
|
||||
struct stat st;
|
||||
|
||||
/* If we can't write to the cache file, then don't even try */
|
||||
if (((ret = stat(filename, &st)) < 0 && errno != ENOENT) ||
|
||||
(ret == 0 && access(filename, W_OK) < 0)) {
|
||||
DEB_SAVE("can't write to cache file %s\n", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try and create a temporary file in the same directory so
|
||||
* that in case of error we don't overwrite the cache file.
|
||||
* If the cache file doesn't yet exist, it isn't a regular
|
||||
* file (e.g. /dev/null or a socket), or we couldn't create
|
||||
* a temporary file then we open it directly.
|
||||
*/
|
||||
if (ret == 0 && S_ISREG(st.st_mode)) {
|
||||
snprintf(tmp, sizeof(tmp) - 1, "%s-XXXXXX", filename);
|
||||
if (mktemp(tmp) == tmp && *tmp != '\0') {
|
||||
file = fopen(tmp, "w");
|
||||
opened = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
file = fopen(filename, "w");
|
||||
opened = filename;
|
||||
}
|
||||
|
||||
DEB_SAVE("cache file %s (really %s)\n", filename, opened);
|
||||
|
||||
if (!file) {
|
||||
perror(opened);
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
ret = blkid_save_cache_file(cache, file);
|
||||
|
||||
if (file != stdout) {
|
||||
fclose(file);
|
||||
if (opened != filename) {
|
||||
if (ret < 0) {
|
||||
unlink(opened);
|
||||
DEB_SAVE("unlinked temp cache %s\n", opened);
|
||||
} else {
|
||||
char backup[4096];
|
||||
|
||||
snprintf(backup, sizeof(backup) - 1, "%s.old",
|
||||
filename);
|
||||
unlink(backup);
|
||||
link(filename, backup);
|
||||
rename(opened, filename);
|
||||
DEB_SAVE("moved temp cache %s\n", opened);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TEST_PROGRAM
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
blkid_cache *cache = NULL;
|
||||
int ret;
|
||||
|
||||
if (argc > 2) {
|
||||
fprintf(stderr, "Usage: %s [filename]\n"
|
||||
"Test loading/saving a cache (filename)\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if ((ret = blkid_probe_all(&cache) < 0))
|
||||
fprintf(stderr, "error probing devices\n");
|
||||
else if ((ret = blkid_save_cache(cache, argv[1])) < 0)
|
||||
fprintf(stderr, "error %d saving cache to %s\n", ret,
|
||||
argv[1] ? argv[1] : BLKID_CACHE_FILE);
|
||||
|
||||
blkid_free_cache(cache);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* tag.c - allocation/initialization/free routines for tag structs
|
||||
*
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
#ifdef DEBUG_TAG
|
||||
#define DEB_TAG(fmt, arg...) printf("tag: " fmt, ## arg)
|
||||
#else
|
||||
#define DEB_TAG(fmt, arg...) do {} while (0)
|
||||
#endif
|
||||
|
||||
blkid_tag *blkid_new_tag(void)
|
||||
{
|
||||
blkid_tag *tag;
|
||||
|
||||
if (!(tag = (blkid_tag *)calloc(1, sizeof(blkid_tag))))
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&tag->bit_tags);
|
||||
INIT_LIST_HEAD(&tag->bit_names);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
void blkid_free_tag(blkid_tag *tag)
|
||||
{
|
||||
if (!tag)
|
||||
return;
|
||||
|
||||
DEB_TAG(" freeing tag %s=%s\n", tag->bit_name, tag->bit_val);
|
||||
DEB_DUMP_TAG(tag);
|
||||
|
||||
list_del(&tag->bit_tags); /* list of tags for this device */
|
||||
list_del(&tag->bit_names); /* list of tags with this type */
|
||||
|
||||
if (tag->bit_name)
|
||||
string_free(tag->bit_name);
|
||||
if (tag->bit_val)
|
||||
string_free(tag->bit_val);
|
||||
|
||||
free(tag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the desired tag on a list of tags with the same type.
|
||||
*/
|
||||
blkid_tag *blkid_find_tv_tags(blkid_tag *head, const char *value)
|
||||
{
|
||||
struct blkid_tag *tag = NULL;
|
||||
struct list_head *p;
|
||||
|
||||
if (!head || !value)
|
||||
return NULL;
|
||||
|
||||
DEB_TAG("looking for %s in %s list\n", value, head->bit_name);
|
||||
|
||||
list_for_each(p, &head->bit_names) {
|
||||
blkid_tag *tmp = list_entry(p, blkid_tag, bit_names);
|
||||
|
||||
if (!strcmp(tmp->bit_val, value)) {
|
||||
tag = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the desired tag on a device. If tag->bit_value is NULL, then the
|
||||
* first such tag is returned, otherwise return only exact tag if found.
|
||||
*/
|
||||
blkid_tag *blkid_find_tag_dev(blkid_dev *dev, blkid_tag *tag)
|
||||
{
|
||||
blkid_tag *found = NULL;
|
||||
struct list_head *p;
|
||||
|
||||
if (!dev || !tag)
|
||||
return NULL;
|
||||
|
||||
list_for_each(p, &dev->bid_tags) {
|
||||
blkid_tag *tmp = list_entry(p, blkid_tag, bit_tags);
|
||||
|
||||
if (!strcmp(tmp->bit_name, tag->bit_name) &&
|
||||
(!tag->bit_val || !strcmp(tmp->bit_val, tag->bit_val))){
|
||||
found = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the desired tag type in the cache.
|
||||
* We return the head tag for this tag type.
|
||||
*/
|
||||
blkid_tag *blkid_find_head_cache(blkid_cache *cache, blkid_tag *tag)
|
||||
{
|
||||
blkid_tag *head = NULL;
|
||||
struct list_head *p;
|
||||
|
||||
if (!cache || !tag)
|
||||
return NULL;
|
||||
|
||||
list_for_each(p, &cache->bic_tags) {
|
||||
blkid_tag *tmp = list_entry(p, blkid_tag, bit_tags);
|
||||
|
||||
if (!strcmp(tmp->bit_name, tag->bit_name)) {
|
||||
DEB_TAG(" found cache tag head %s\n", tag->bit_name);
|
||||
head = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find a specific tag value in the cache. If not found return NULL.
|
||||
*/
|
||||
blkid_tag *blkid_find_tag_cache(blkid_cache *cache, blkid_tag *tag)
|
||||
{
|
||||
blkid_tag *head;
|
||||
|
||||
DEB_TAG("looking for %s=%s in cache\n", tag->bit_name, tag->bit_val);
|
||||
|
||||
head = blkid_find_head_cache(cache, tag);
|
||||
|
||||
return blkid_find_tv_tags(head, tag->bit_val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a specific tag value in the cache. If not found return NULL.
|
||||
* If we have not already probed the devices, do so and search again.
|
||||
*/
|
||||
blkid_tag *blkid_get_tag_cache(blkid_cache *cache, blkid_tag *tag)
|
||||
{
|
||||
blkid_tag *head, *found;
|
||||
|
||||
if (!tag || !cache)
|
||||
return NULL;
|
||||
|
||||
DEB_TAG("looking for %s=%s in cache\n", tag->bit_name, tag->bit_val);
|
||||
|
||||
head = blkid_find_head_cache(cache, tag);
|
||||
found = blkid_find_tv_tags(head, tag->bit_val);
|
||||
|
||||
if ((!head || !found) && !(cache->bic_flags & BLKID_BIC_FL_PROBED)) {
|
||||
blkid_probe_all(&cache);
|
||||
if (!head)
|
||||
head = blkid_find_head_cache(cache, tag);
|
||||
found = blkid_find_tv_tags(head, tag->bit_val);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a single tag to the given device.
|
||||
* This function is not currently exported because adding arbitrary tags to
|
||||
* a device will just get lost as soon as we verify the device (which
|
||||
* uses the dev struct returned from the device probe). At some point in
|
||||
* the future it may be desirable to allow adding arbitrary tags to a device,
|
||||
* and ensure that verify keeps all such tags (maybe lower case tag names?)
|
||||
*/
|
||||
static void add_tag_to_dev(blkid_dev *dev, blkid_tag *tag)
|
||||
{
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
DEB_TAG("adding tag %s=%s\n", tag->bit_name, tag->bit_val);
|
||||
|
||||
tag->bit_dev = dev;
|
||||
|
||||
list_add_tail(&tag->bit_tags, &dev->bid_tags);
|
||||
|
||||
/* Link common tags directly to the device struct */
|
||||
if (!strcmp(tag->bit_name, "TYPE") && !dev->bid_type)
|
||||
dev->bid_type = tag->bit_val;
|
||||
else if (!strcmp(tag->bit_name, "LABEL"))
|
||||
dev->bid_label = tag->bit_val;
|
||||
else if (!strcmp(tag->bit_name, "UUID"))
|
||||
dev->bid_uuid = tag->bit_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and fill out a tag struct.
|
||||
* If dev is valid, the tag will be added to the tags for this device
|
||||
* if an identical tag does not already exist.
|
||||
* If tag is valid, the tag will be returned in this pointer.
|
||||
*/
|
||||
int blkid_create_tag(blkid_dev *dev, blkid_tag **tag, const char *name,
|
||||
const char *value, const int vlength)
|
||||
{
|
||||
blkid_tag *t, *found;
|
||||
|
||||
if (!tag && !dev)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
if (!name)
|
||||
return -BLKID_ERR_PARAM;
|
||||
|
||||
t = blkid_new_tag();
|
||||
if (!t)
|
||||
return -BLKID_ERR_MEM;
|
||||
|
||||
t->bit_name = string_copy(name);
|
||||
t->bit_val = stringn_copy(value, vlength);
|
||||
|
||||
if ((found = blkid_find_tag_dev(dev, t))) {
|
||||
if (tag)
|
||||
*tag = found;
|
||||
blkid_free_tag(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_tag_to_dev(dev, t);
|
||||
if (tag)
|
||||
*tag = t;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a NAME=value pair into a token. This is slightly different than
|
||||
* parse_token, because that will end an unquoted value at a space, while
|
||||
* this will assume that an unquoted value is the rest of the token (e.g.
|
||||
* if we are passed al alreay quoted string from the command-line we don't
|
||||
* have to both quote and escape quote so that the quotes make it to us).
|
||||
*/
|
||||
blkid_tag *blkid_token_to_tag(const char *token)
|
||||
{
|
||||
char *name, *value, *cp;
|
||||
blkid_tag *tag = NULL;
|
||||
int len;
|
||||
|
||||
DEB_TAG("trying to make '%s' into a tag\n", token);
|
||||
if (!token || !(cp = strchr(token, '=')))
|
||||
return NULL;
|
||||
|
||||
name = string_copy(token);
|
||||
value = name + (cp - token);
|
||||
*value++ = '\0';
|
||||
if (*value == '"' || *value == '\'') {
|
||||
char c = *value++;
|
||||
if (!(cp = strrchr(value, c))) {
|
||||
fprintf(stderr, "Missing close quote for %s\n", token);
|
||||
return NULL;
|
||||
}
|
||||
*cp = '\0';
|
||||
len = cp - value;
|
||||
} else
|
||||
len = strlen(value);
|
||||
|
||||
blkid_create_tag(NULL, &tag, name, value, len);
|
||||
|
||||
string_free(name);
|
||||
|
||||
return tag;
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
2003-01-23 Theodore Ts'o <tytso@mit.edu>
|
||||
|
||||
* Makefile.in: Integrate in new blkid library.
|
||||
|
||||
2003-01-22 Theodore Ts'o <tytso@mit.edu>
|
||||
|
||||
* fsck.c (parse_fstab_line, parse_escape): Add support for
|
||||
|
|
|
@ -14,10 +14,10 @@ INSTALL = @INSTALL@
|
|||
@IMAGER_CMT@E2IMAGE_PROG= e2image
|
||||
@IMAGER_CMT@E2IMAGE_MAN= e2image.8
|
||||
|
||||
SPROGS= mke2fs badblocks tune2fs dumpe2fs $(E2IMAGE_PROG) @FSCK_PROG@
|
||||
SPROGS= mke2fs badblocks tune2fs dumpe2fs blkid $(E2IMAGE_PROG) @FSCK_PROG@
|
||||
USPROGS= mklost+found
|
||||
SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \
|
||||
e2label.8 findfs.8 $(E2IMAGE_MAN) @FSCK_MAN@
|
||||
e2label.8 findfs.8 blkid.8 $(E2IMAGE_MAN) @FSCK_MAN@
|
||||
|
||||
UPROGS= chattr lsattr uuidgen
|
||||
UMANPAGES= chattr.1 lsattr.1 uuidgen.1
|
||||
|
@ -32,11 +32,12 @@ DUMPE2FS_OBJS= dumpe2fs.o
|
|||
BADBLOCKS_OBJS= badblocks.o
|
||||
E2IMAGE_OBJS= e2image.o
|
||||
FSCK_OBJS= fsck.o get_device_by_label.o base_device.o fstype.o
|
||||
BLKID_OBJS= blkid.o
|
||||
|
||||
SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c \
|
||||
$(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \
|
||||
$(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \
|
||||
$(srcdir)/uuidgen.c $(srcdir)/fstype.c
|
||||
$(srcdir)/uuidgen.c $(srcdir)/fstype.c $(srcdir)/blkid.c
|
||||
|
||||
LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
|
||||
DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
|
||||
|
@ -44,6 +45,9 @@ DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
|
|||
STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR)
|
||||
STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR)
|
||||
|
||||
LIBS_BLKID= $(LIBBLKID) $(LIBUUID)
|
||||
DEPLIBS_BLKID= $(LIBBLKID) $(LIBUUID)
|
||||
|
||||
LIBS_E2P= $(LIBEXT2FS) $(LIBE2P) $(LIBCOM_ERR)
|
||||
DEPLIBS_E2P= $(LIBEXT2FS) $(LIBE2P) $(LIBCOM_ERR)
|
||||
|
||||
|
@ -58,6 +62,9 @@ findsuper: findsuper.o
|
|||
tune2fs: $(TUNE2FS_OBJS) $(DEPLIBS_E2P) $(DEPLIBUUID)
|
||||
$(CC) $(ALL_LDFLAGS) -o tune2fs $(TUNE2FS_OBJS) $(LIBS_E2P) $(LIBUUID)
|
||||
|
||||
blkid: $(BLKID_OBJS) $(DEPLIBS_E2P) $(DEPLIBS_BLKID)
|
||||
$(CC) $(ALL_LDFLAGS) -o blkid $(BLKID_OBJS) $(LIBS_E2P) $(LIBS_BLKID)
|
||||
|
||||
e2image: $(E2IMAGE_OBJS) $(DEPLIBS)
|
||||
$(CC) $(ALL_LDFLAGS) -o e2image $(E2IMAGE_OBJS) $(LIBS)
|
||||
|
||||
|
@ -131,6 +138,9 @@ badblocks.8: $(DEP_SUBSTITUTE) $(srcdir)/badblocks.8.in
|
|||
fsck.8: $(DEP_SUBSTITUTE) $(srcdir)/fsck.8.in
|
||||
$(SUBSTITUTE) $(srcdir)/fsck.8.in fsck.8
|
||||
|
||||
blkid.8: $(DEP_SUBSTITUTE) $(srcdir)/blkid.8.in
|
||||
$(SUBSTITUTE) $(srcdir)/blkid.8.in blkid.8
|
||||
|
||||
chattr.1: $(DEP_SUBSTITUTE) $(srcdir)/chattr.1.in
|
||||
$(SUBSTITUTE) $(srcdir)/chattr.1.in chattr.1
|
||||
|
||||
|
@ -140,6 +150,9 @@ lsattr.1: $(DEP_SUBSTITUTE) $(srcdir)/lsattr.1.in
|
|||
uuidgen.1: $(DEP_SUBSTITUTE) $(srcdir)/uuidgen.1.in
|
||||
$(SUBSTITUTE) $(srcdir)/uuidgen.1.in uuidgen.1
|
||||
|
||||
blkid.1: $(DEP_SUBSTITUTE) $(srcdir)/blkid.1.in
|
||||
$(SUBSTITUTE) $(srcdir)/blkid.1.in blkid.1
|
||||
|
||||
installdirs:
|
||||
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(sbindir) \
|
||||
$(DESTDIR)$(root_sbindir) $(DESTDIR)$(bindir) \
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
.\" Copyright 2000 Andreas Dilger (adilger@turbolinux.com)
|
||||
.\"
|
||||
.\" This man page was created for blkid from e2fsprogs-1.25.
|
||||
.\"
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.\" Based on uuidgen, Mon Sep 17 10:42:12 2000, Andreas Dilger
|
||||
.TH BLKID 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
|
||||
.SH NAME
|
||||
blkid \- command\-line utility to locate/print block device attributes
|
||||
.SH SYNOPSIS
|
||||
.B blkid
|
||||
]...
|
||||
[
|
||||
.B \-h
|
||||
]
|
||||
[
|
||||
[
|
||||
.B \-c
|
||||
.I cachefile
|
||||
]
|
||||
.B \-s
|
||||
.I savecachefile
|
||||
]
|
||||
[
|
||||
.B \-p
|
||||
]
|
||||
[
|
||||
.B \-t
|
||||
.I token
|
||||
]...
|
||||
[
|
||||
.B \-v
|
||||
]
|
||||
[
|
||||
.I device ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B blkid
|
||||
program is the command-line interface to working with
|
||||
.BR libuuid (3)
|
||||
library. It can determine the type of content (e.g. filesystem, swap)
|
||||
a block device holds, and also attributes (tokens, NAME=value pairs)
|
||||
from the content metadata (e.g. LABEL or UUID fields).
|
||||
.PP
|
||||
.B blkid
|
||||
has two main forms of operation: either searching for a device with a
|
||||
specific NAME=value pair, or displaying NAME=value pairs for one or
|
||||
more devices.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-c
|
||||
.I <cachefile>
|
||||
Read from
|
||||
.I cachefile
|
||||
instead of reading from the default cache file
|
||||
.IR /etc/blkid.tab .
|
||||
If you want to start with a clean cache (i.e. don't report devices previously
|
||||
scanned but not necessarily available at this time), specify
|
||||
.IR /dev/null.
|
||||
.TP
|
||||
.B \-h
|
||||
Display a usage message and exit.
|
||||
.TP
|
||||
.B \-p
|
||||
Probe all available devices. This is the default when displaying
|
||||
tokens. When searching for a token normally the cache file is
|
||||
used to locate the device and only that device is probed (to ensure
|
||||
cache coherency) and all devices are probed only if the token cannot
|
||||
be found in the cache.
|
||||
.TP
|
||||
.B \-s
|
||||
.I tag
|
||||
.I tag
|
||||
is of the form
|
||||
.I NAME
|
||||
and the resulting token is shown for each (specified) device that has
|
||||
such a tag. It is possible to specify multiple
|
||||
.I tag
|
||||
options. If no tag is specified, then all tokens are shown for all
|
||||
(specified) devices.
|
||||
In order to just refresh the cache without showing any tokens use
|
||||
.B "-s none"
|
||||
with no other options.
|
||||
.TP
|
||||
.B \-t
|
||||
.I token
|
||||
.I token
|
||||
is of the form
|
||||
.IB NAME = value
|
||||
and that specific token is searched for in the cache or among all visible
|
||||
block devices and additionally any specified devices. If that token is
|
||||
not found, no output is shown. Common values for
|
||||
.I NAME
|
||||
include
|
||||
.BR TYPE ,
|
||||
.BR LABEL ,
|
||||
and
|
||||
.BR UUID .
|
||||
.TP
|
||||
.B \-v
|
||||
Display version number and exit.
|
||||
.SH RETURN VALUE
|
||||
The UUID of the form 1b4e28ba-2fa1-11d2-883f-b9a761bde3fb (in
|
||||
.BR printf (3)
|
||||
format "%08x-%04x-%04x-%04x-%012x") is output to the standard output.
|
||||
.TP
|
||||
.B \-w
|
||||
.I <writecachefile>
|
||||
Write the device cache to
|
||||
.I writecachefile
|
||||
instead of writing it to the default cache file
|
||||
.IR /etc/blkid.tab .
|
||||
If you don't want to save the cache to the default file, specify
|
||||
.IR /dev/null.
|
||||
If not specified it will be the same file as that given by the
|
||||
.B -c
|
||||
option.
|
||||
.TP
|
||||
.I <device>
|
||||
Display tokens from only the specified device. It is possible to
|
||||
give multiple
|
||||
.I <device>
|
||||
options on the command line. If none is given, all devices which
|
||||
appear in
|
||||
.I /proc/partitions
|
||||
are shown, if they are recognized.
|
||||
.SH "RETURN CODE"
|
||||
If the specified token was found, or if any tags were shown from (specified)
|
||||
devices 0 is returned. If the specified token was not found, or no
|
||||
(specified) devices could be identified return 2. For usage or other errors
|
||||
return 4.
|
||||
.SH AUTHOR
|
||||
.B blkid
|
||||
was written by Andreas Dilger for libblkid.
|
||||
.SH AVAILABILITY
|
||||
.B blkid
|
||||
is part the e2fsprogs package since version 1.26 and is available from
|
||||
http://e2fsprogs.sourceforge.net.
|
||||
.SH "SEE ALSO"
|
||||
.BR libblkid (3)
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* blkid.c - User command-line interface for libblkid
|
||||
*
|
||||
* Copyright (C) 2001 Andreas Dilger
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the
|
||||
* GNU Lesser General Public License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#else
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
#endif
|
||||
|
||||
#include "blkid/blkid.h"
|
||||
|
||||
char *progname = "blkid";
|
||||
void print_version(FILE *out)
|
||||
{
|
||||
fprintf(stderr, "%s %s (%s)\n", progname, BLKID_VERSION, BLKID_DATE);
|
||||
}
|
||||
|
||||
void usage(int error)
|
||||
{
|
||||
FILE *out = error ? stderr : stdout;
|
||||
|
||||
print_version(out);
|
||||
fprintf(out,
|
||||
"usage:\t%s [-c <file>] [-h] "
|
||||
"[-p] [-s <tag>] [-t <token>] [-v] [-w <file>] [dev ...]\n"
|
||||
"\t-c\tcache file (default: /etc/blkid.tab, /dev/null = none)\n"
|
||||
"\t-h\tprint this usage message and exit\n"
|
||||
"\t-s\tshow specified tag(s) (default show all tags)\n"
|
||||
"\t-t\tfind device with a specific token (NAME=value pair)\n"
|
||||
"\t-v\tprint version and exit\n"
|
||||
"\t-w\twrite cache to different file (/dev/null = no write)\n"
|
||||
"\tdev\tspecify device(s) to probe (default: all devices)\n",
|
||||
progname);
|
||||
exit(error);
|
||||
}
|
||||
|
||||
#define PT_FL_START 0x0001
|
||||
#define PT_FL_TYPE 0x0002
|
||||
|
||||
static void print_tag(blkid_dev *dev, blkid_tag *tag, int *flags)
|
||||
{
|
||||
/* Print only one "dev:" per device */
|
||||
if (!*flags & PT_FL_START) {
|
||||
printf("%s: ", dev->bid_name);
|
||||
*flags |= PT_FL_START;
|
||||
}
|
||||
/* Print only the primary TYPE per device */
|
||||
if (!strcmp(tag->bit_name, "TYPE")) {
|
||||
if (*flags & PT_FL_TYPE)
|
||||
return;
|
||||
*flags |= PT_FL_TYPE;
|
||||
}
|
||||
printf("%s=\"%s\" ", tag->bit_name, tag->bit_val);
|
||||
}
|
||||
|
||||
void print_tags(blkid_dev *dev, char *show[], int numtag)
|
||||
{
|
||||
struct list_head *p;
|
||||
int flags = 0;
|
||||
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
list_for_each(p, &dev->bid_tags) {
|
||||
blkid_tag *tag = list_entry(p, blkid_tag, bit_tags);
|
||||
int i;
|
||||
|
||||
/* Print all tokens if none is specified */
|
||||
if (numtag == 0 || !show) {
|
||||
print_tag(dev, tag, &flags);
|
||||
/* Otherwise, only print specific tokens */
|
||||
} else for (i = 0; i < numtag; i++) {
|
||||
if (!strcmp(tag->bit_name, show[i]))
|
||||
print_tag(dev, tag, &flags);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
blkid_cache *cache = NULL;
|
||||
char *devices[128] = { NULL, };
|
||||
char *show[128] = { NULL, };
|
||||
blkid_tag *tag = NULL;
|
||||
char *read = NULL;
|
||||
char *write = NULL;
|
||||
int numdev = 0, numtag = 0;
|
||||
int version = 0;
|
||||
int err = 4;
|
||||
int i;
|
||||
char c;
|
||||
|
||||
while ((c = getopt (argc, argv, "c:d:f:hps:t:w:v")) != EOF)
|
||||
switch (c) {
|
||||
case 'd': /* deprecated */
|
||||
if (numdev >= sizeof(devices) / sizeof(*devices)) {
|
||||
fprintf(stderr,
|
||||
"Too many devices specified\n");
|
||||
usage(err);
|
||||
}
|
||||
devices[numdev++] = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
if (optarg && !*optarg)
|
||||
read = NULL;
|
||||
else
|
||||
read = optarg;
|
||||
if (!write)
|
||||
write = read;
|
||||
break;
|
||||
case 's':
|
||||
if (numtag >= sizeof(show) / sizeof(*show)) {
|
||||
fprintf(stderr, "Too many tags specified\n");
|
||||
usage(err);
|
||||
}
|
||||
show[numtag++] = optarg;
|
||||
break;
|
||||
case 't':
|
||||
if (tag) {
|
||||
fprintf(stderr, "Can only search for "
|
||||
"one NAME=value pair\n");
|
||||
usage(err);
|
||||
}
|
||||
if (!(tag = blkid_token_to_tag(optarg))) {
|
||||
fprintf(stderr, "-t needs NAME=value pair\n");
|
||||
usage(err);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
version = 1;
|
||||
break;
|
||||
case 'w':
|
||||
if (optarg && !*optarg)
|
||||
write = NULL;
|
||||
else
|
||||
write = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
err = 0;
|
||||
default:
|
||||
usage(err);
|
||||
}
|
||||
|
||||
while (optind < argc)
|
||||
devices[numdev++] = argv[optind++];
|
||||
|
||||
if (version) {
|
||||
print_version(stdout);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (blkid_read_cache(&cache, read) < 0)
|
||||
goto exit;
|
||||
|
||||
err = 2;
|
||||
/* If looking for a specific NAME=value pair, print only that */
|
||||
if (tag) {
|
||||
blkid_tag *found = NULL;
|
||||
|
||||
/* Load any additional devices not in the cache */
|
||||
for (i = 0; i < numdev; i++)
|
||||
blkid_get_devname(cache, devices[i]);
|
||||
|
||||
if ((found = blkid_get_tag_cache(cache, tag))) {
|
||||
print_tags(found->bit_dev, show, numtag);
|
||||
err = 0;
|
||||
}
|
||||
/* If we didn't specify a single device, show all available devices */
|
||||
} else if (!numdev) {
|
||||
struct list_head *p;
|
||||
|
||||
blkid_probe_all(&cache);
|
||||
|
||||
list_for_each(p, &cache->bic_devs) {
|
||||
blkid_dev *dev = list_entry(p, blkid_dev, bid_devs);
|
||||
print_tags(dev, show, numtag);
|
||||
err = 0;
|
||||
}
|
||||
/* Add all specified devices to cache (optionally display tags) */
|
||||
} else for (i = 0; i < numdev; i++) {
|
||||
blkid_dev *dev = blkid_get_devname(cache, devices[i]);
|
||||
|
||||
if (dev) {
|
||||
print_tags(dev, show, numtag);
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
blkid_free_tag(tag);
|
||||
blkid_save_cache(cache, write);
|
||||
blkid_free_cache(cache);
|
||||
return err;
|
||||
}
|
Loading…
Reference in New Issue