From 17f29d7bac86dc6e42c8ea728a2b7d1dc873b3dc Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Tue, 17 Feb 2009 01:01:35 +0100 Subject: [PATCH] mount: generic blkid/volume_id wrapper, use blkid_evaluate_* * moves the generic libblkid/libvolume_id wrapper (fsprobe.c) from mount/ to lib/. We'll use the wrapper in cfdisk and fsck. The wrapper supports: - obsolete volume_id (udev) - obsolete libblkid (e2fsprogs) - libblkid (util-linux-ng) * mount, umount and swapon when linked against the new libblkid use - low-level probing code to read LABEL, UUID or FSTYPE from a device - high-level blkid_evaluate_spec() to convert LABEL/UUID to devname Signed-off-by: Karel Zak --- configure.ac | 1 + include/fsprobe.h | 23 +++ lib/fsprobe.c | 388 +++++++++++++++++++++++++++++++++++++++ mount/Makefile.am | 16 +- mount/devname.c | 15 ++ mount/devname.h | 6 + mount/fsprobe.c | 228 ----------------------- mount/fsprobe.h | 46 ----- mount/fsprobe_blkid.c | 82 --------- mount/fsprobe_volumeid.c | 144 --------------- mount/fstab.c | 3 +- mount/mount.c | 181 +++++++++++++++++- mount/sundries.c | 36 ---- mount/sundries.h | 2 - mount/swapon.c | 9 +- 15 files changed, 618 insertions(+), 562 deletions(-) create mode 100644 include/fsprobe.h create mode 100644 lib/fsprobe.c create mode 100644 mount/devname.c create mode 100644 mount/devname.h delete mode 100644 mount/fsprobe.c delete mode 100644 mount/fsprobe.h delete mode 100644 mount/fsprobe_blkid.c delete mode 100644 mount/fsprobe_volumeid.c diff --git a/configure.ac b/configure.ac index 04c1f611..3952e83f 100644 --- a/configure.ac +++ b/configure.ac @@ -190,6 +190,7 @@ elif test "x$with_fsprobe" = xvolume_id; then elif test "x$with_fsprobe" = xbuiltin; then have_blkid=yes AC_DEFINE(HAVE_LIBBLKID,1,[Define to 1 if you have the -lblkid.]) + AC_DEFINE(HAVE_BLKID_EVALUATE_SPEC,1,[Define to 1 if you have the blkid_evaluate_spec().]) AM_CONDITIONAL(HAVE_BLKID, true) AM_CONDITIONAL(BUILD_LIBBLKID, true) fi diff --git a/include/fsprobe.h b/include/fsprobe.h new file mode 100644 index 00000000..ed2cce14 --- /dev/null +++ b/include/fsprobe.h @@ -0,0 +1,23 @@ +#ifndef FSPROBE_H +#define FSPROBE_H +/* + * This is the generic interface for filesystem guessing libraries. + * Implementations are provided by + */ +extern void fsprobe_init(void); +extern void fsprobe_exit(void); + +extern int fsprobe_parse_spec(const char *spec, char **name, char **value); + +extern const char *fsprobe_get_devname_by_uuid(const char *uuid); +extern const char *fsprobe_get_devname_by_label(const char *label); +extern const char *fsprobe_get_devname_by_spec(const char *spec); + +extern const char *fsprobe_get_label_by_devname(const char *devname); +extern const char *fsprobe_get_uuid_by_devname(const char *devname); +extern const char *fsprobe_get_fstype_by_devname(const char *devname); + + +extern int fsprobe_known_fstype(const char *fstype); + +#endif /* FSPROBE_H */ diff --git a/lib/fsprobe.c b/lib/fsprobe.c new file mode 100644 index 00000000..d8d927d7 --- /dev/null +++ b/lib/fsprobe.c @@ -0,0 +1,388 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* TODO: , -I/usr/include/blkid */ + +#include "blkdev.h" +#include "canonicalize.h" +#include "pathnames.h" +#include "fsprobe.h" + +/* ask kernel developers why we need such ugly open() method... */ +static int +open_device(const char *devname) +{ + int retries = 0; + + do { + int fd = open(devname, O_RDONLY); + if (fd >= 0) + return fd; + if (errno != ENOMEDIUM) + break; + if (retries >= CRDOM_NOMEDIUM_RETRIES) + break; + ++retries; + sleep(3); + } while(1); + + return -1; +} + +/* + * Parses NAME=value, returns -1 on parse error, 0 success. The success is also + * when the 'spec' doesn't contain name=value pair (because the spec could be + * a devname too). In particular case the pointer 'name' is set to NULL. + + * The result is a new allocated string (the 'name' pointer). + */ +int +fsprobe_parse_spec(const char *spec, char **name, char **value) +{ + char *vl, *tk, *cp; + + *name = NULL; + *value = NULL; + + if (!(cp = strchr(spec, '='))) + return 0; /* no name= */ + + tk = strdup(spec); + vl = tk + (cp - spec); + *vl++ = '\0'; + + if (*vl == '"' || *vl == '\'') { + if (!(cp = strrchr(vl+1, *vl))) { + free(tk); + return -1; /* parse error */ + } + vl++; + *cp = '\0'; + } + + *name = tk; + *value = vl; + return 0; +} + +const char * +fsprobe_get_devname_by_spec(const char *spec) +{ + char *name, *value; + + if (!spec) + return NULL; + if (fsprobe_parse_spec(spec, &name, &value) != 0) + return NULL; /* parse error */ + if (name) { + const char *nspec = NULL; + + if (!strcmp(name,"LABEL")) + nspec = fsprobe_get_devname_by_label(value); + else if (!strcmp(name,"UUID")) + nspec = fsprobe_get_devname_by_uuid(value); + + free((void *) name); + return nspec; + } + + return canonicalize_path(spec); +} + +#ifdef HAVE_LIBBLKID +static blkid_cache blcache; + +void +fsprobe_init(void) +{ + blcache = NULL; +} + +int +fsprobe_known_fstype(const char *fstype) +{ + return blkid_known_fstype(fstype); +} + +#ifdef HAVE_BLKID_EVALUATE_SPEC +/* + * libblkid from util-linux-ng + * -- recommended + */ +static blkid_probe blprobe; + +void +fsprobe_exit(void) +{ + if (blprobe) + blkid_free_probe(blprobe); + if (blcache) + blkid_put_cache(blcache); +} + +/* returns device LABEL, UUID, FSTYPE, ... by low-level + * probing interface + */ +static const char * +fsprobe_get_value(const char *name, const char *devname) +{ + int fd; + unsigned char *data = NULL; + + if (!devname || !name) + return NULL; + fd = open_device(devname); + if (fd < 0) + return NULL; + if (!blprobe) + blprobe = blkid_new_probe(); + if (!blprobe) + goto done; + if (blkid_probe_set_device(blprobe, fd, 0, 0)) + goto done; + if (blkid_probe_set_request(blprobe, BLKID_PROBREQ_LABEL | + BLKID_PROBREQ_UUID | BLKID_PROBREQ_TYPE )) + goto done; + if (blkid_do_safeprobe(blprobe)) + goto done; + if (blkid_probe_lookup_value(blprobe, name, &data, NULL)) + goto done; +done: + close(fd); + return data ? strdup((char *) data) : NULL; +} + +const char * +fsprobe_get_label_by_devname(const char *devname) +{ + return fsprobe_get_value("LABEL", devname); +} + +const char * +fsprobe_get_uuid_by_devname(const char *devname) +{ + return fsprobe_get_value("UUID", devname); +} + +const char * +fsprobe_get_fstype_by_devname(const char *devname) +{ + return fsprobe_get_value("TYPE", devname); +} + +const char * +fsprobe_get_devname_by_uuid(const char *uuid) +{ + return blkid_evaluate_spec("UUID", uuid, &blcache); +} + +const char * +fsprobe_get_devname_by_label(const char *label) +{ + return blkid_evaluate_spec("LABEL", label, &blcache); +} + +#else /* !HAVE_BLKID_EVALUATE_SPEC */ + +/* + * Classic libblkid (from e2fsprogs) without blkid_evaluate_spec() + * -- deprecated + */ +#define BLKID_EMPTY_CACHE "/dev/null" + +void +fsprobe_exit(void) +{ + if (blcache) + blkid_put_cache(blcache); +} + +const char * +fsprobe_get_devname_by_uuid(const char *uuid) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_devname(blcache, "UUID", uuid); +} + +const char * +fsprobe_get_devname_by_label(const char *label) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_devname(blcache, "LABEL", label); +} + +const char * +fsprobe_get_fstype_by_devname(const char *devname) +{ + blkid_cache c; + const char *tp; + + if (blcache) + return blkid_get_tag_value(blcache, "TYPE", devname); + + /* The cache is not initialized yet. Use empty cache rather than waste + * time with /etc/blkid.tab. It seems that probe FS is faster than + * parse the cache file. -- kzak (17-May-2007) + */ + blkid_get_cache(&c, BLKID_EMPTY_CACHE); + tp = blkid_get_tag_value(c, "TYPE", devname); + blkid_put_cache(c); + + return tp; +} + +const char * +fsprobe_get_label_by_devname(const char *devname) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_tag_value(blcache, "LABEL", devname); +} + +const char * +fsprobe_get_uuid_by_devname(const char *devname) +{ + if (!blcache) + blkid_get_cache(&blcache, NULL); + + return blkid_get_tag_value(blcache, "UUID", devname); +} + +#endif /* !HAVE_BLKID_EVALUATE_SPEC */ +#else /* !HAVE_LIBBLKID */ + +/* + * libvolume_id from udev + * -- deprecated + */ +#include + +enum probe_type { + VOLUME_ID_NONE, + VOLUME_ID_LABEL, + VOLUME_ID_UUID, + VOLUME_ID_TYPE, +}; + +static char +*probe(const char *device, enum probe_type type) +{ + int fd; + uint64_t size; + struct volume_id *id; + const char *val; + char *value = NULL; + int retries = 0; + + fd = open_device(devname); + if (fd < 0) + return NULL; + id = volume_id_open_fd(fd); + if (!id) { + close(fd); + return NULL; + } + if (blkdev_get_size(fd, &size) != 0) + size = 0; + if (volume_id_probe_all(id, 0, size) == 0) { + switch(type) { + case VOLUME_ID_LABEL: + if (volume_id_get_label(id, &val)) + value = xstrdup(val); + break; + case VOLUME_ID_UUID: + if (volume_id_get_uuid(id, &val)) + value = xstrdup(val); + break; + case VOLUME_ID_TYPE: + if (volume_id_get_type(id, &val)) + value = xstrdup(val); + break; + default: + break; + } + } + volume_id_close(id); + close(fd); + return value; +} + +void +fsprobe_init(void) +{ +} + +void +fsprobe_exit(void) +{ +} + +int +fsprobe_known_fstype(const char *fstype) +{ + if (volume_id_get_prober_by_type(fstype) != NULL) + return 1; + return 0; +} + +const char * +fsprobe_get_uuid_by_devname(const char *devname) +{ + return probe(devname, VOLUME_ID_UUID); +} + +const char * +fsprobe_get_label_by_devname(const char *devname) +{ + return probe(devname, VOLUME_ID_LABEL); +} + +const char * +fsprobe_get_fstype_by_devname(const char *devname) +{ + return probe(devname, VOLUME_ID_TYPE); +} + +const char * +fsprobe_get_devname_by_uuid(const char *uuid) +{ + char dev[PATH_MAX]; + size_t len; + + if (!uuid) + return NULL; + + strcpy(dev, _PATH_DEV_BYUUID "/"); + len = strlen(_PATH_DEV_BYUUID "/"); + if (!volume_id_encode_string(uuid, &dev[len], sizeof(dev) - len)) + return NULL; + return canonicalize_path(dev); +} + +const char * +fsprobe_get_devname_by_label(const char *label) +{ + char dev[PATH_MAX]; + size_t len; + + if (!label) + return NULL; + strcpy(dev, _PATH_DEV_BYLABEL "/"); + len = strlen(_PATH_DEV_BYLABEL "/"); + if (!volume_id_encode_string(label, &dev[len], sizeof(dev) - len)) + return NULL; + return canonicalize_path(dev); +} + +#endif /* HAVE_LIBVOLUME_ID */ diff --git a/mount/Makefile.am b/mount/Makefile.am index 1128fa85..261b8c9a 100644 --- a/mount/Makefile.am +++ b/mount/Makefile.am @@ -11,12 +11,12 @@ srcs_common = sundries.c xmalloc.c ../lib/canonicalize.c # generic header for mount and umount hdrs_mount = fstab.h mount_mntent.h mount_constants.h \ - lomount.h fsprobe.h xmalloc.h getusername.h loop.h sundries.h + lomount.h xmalloc.h getusername.h loop.h sundries.h # generic sources for mount and umount -srcs_mount = fstab.c mount_mntent.c getusername.c lomount.c \ +srcs_mount = fstab.c mount_mntent.c getusername.c lomount.c devname.c devname.h \ $(srcs_common) $(hdrs_mount) ../lib/env.c ../lib/linux_version.c \ - ../lib/blkdev.c fsprobe.c + ../lib/blkdev.c ../lib/fsprobe.c # generic flags for all programs (except losetup) # -- note that pkg-config autoconf macros (pkg.m4) does not differentiate @@ -38,8 +38,8 @@ umount_CFLAGS = $(SUID_CFLAGS) $(AM_CFLAGS) $(cflags_common) umount_LDFLAGS = $(SUID_LDFLAGS) $(AM_LDFLAGS) umount_LDADD = $(ldadd_common) -swapon_SOURCES = swapon.c swap_constants.h $(srcs_common) \ - ../lib/linux_version.c ../lib/blkdev.c fsprobe.c +swapon_SOURCES = swapon.c swap_constants.h $(srcs_common) devname.c devname.h \ + ../lib/linux_version.c ../lib/blkdev.c ../lib/fsprobe.c swapon_CFLAGS = $(cflags_common) swapon_LDADD = $(ldadd_common) @@ -51,6 +51,7 @@ mount_static_LDADD = if HAVE_STATIC_MOUNT bin_PROGRAMS += mount.static mount_static_SOURCES = $(mount_SOURCES) +mount_static_CFLAGS = $(cflags_common) mount_static_LDFLAGS = $(ldflags_static) mount_static_LDADD += $(ldadd_static) endif @@ -58,6 +59,7 @@ endif if HAVE_STATIC_UMOUNT bin_PROGRAMS += umount.static umount_static_SOURCES = $(umount_SOURCES) +umount_static_CFLAGS = $(cflags_common) umount_static_LDFLAGS = $(ldflags_static) umount_static_LDADD = $(ldadd_static) endif @@ -70,8 +72,6 @@ losetup_static_CPPFLAGS = -DMAIN $(AM_CPPFLAGS) endif if HAVE_BLKID -srcs_mount += fsprobe_blkid.c -swapon_SOURCES += fsprobe_blkid.c if BUILD_LIBBLKID ldadd_common += $(ul_libblkid_la) ldadd_static += $(ul_libblkid_la) @@ -84,8 +84,6 @@ endif endif if HAVE_VOLUME_ID -srcs_mount += fsprobe_volumeid.c -swapon_SOURCES += fsprobe_volumeid.c ldadd_common += $(VOLUMEID_LIBS) ldadd_static += $(VOLUMEID_LIBS_STATIC) cflags_common += $(VOLUMEID_CFLAGS) diff --git a/mount/devname.c b/mount/devname.c new file mode 100644 index 00000000..585d259f --- /dev/null +++ b/mount/devname.c @@ -0,0 +1,15 @@ +#include "fsprobe.h" + +#include "devname.h" +#include "sundries.h" /* for xstrdup */ + +const char * +spec_to_devname(const char *spec) +{ + if (!spec) + return NULL; + if (is_pseudo_fs(spec)) + return xstrdup(spec); + return fsprobe_get_devname_by_spec(spec); +} + diff --git a/mount/devname.h b/mount/devname.h new file mode 100644 index 00000000..d6adeff7 --- /dev/null +++ b/mount/devname.h @@ -0,0 +1,6 @@ +#ifndef MOUNT_DEVNAME_H +#define MOUNT_DEVNAME_H + +extern const char *spec_to_devname(const char *spec); + +#endif diff --git a/mount/fsprobe.c b/mount/fsprobe.c deleted file mode 100644 index 04e267f3..00000000 --- a/mount/fsprobe.c +++ /dev/null @@ -1,228 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "pathnames.h" -#include "fsprobe.h" -#include "sundries.h" /* for xstrdup */ -#include "nls.h" - -/* list of already tested filesystems by fsprobe_procfsloop_mount() */ -static struct tried { - struct tried *next; - char *type; -} *tried = NULL; - -static int -was_tested(const char *fstype) { - struct tried *t; - - if (fsprobe_known_fstype(fstype)) - return 1; - for (t = tried; t; t = t->next) { - if (!strcmp(t->type, fstype)) - return 1; - } - return 0; -} - -static void -set_tested(const char *fstype) { - struct tried *t = xmalloc(sizeof(struct tried)); - - t->next = tried; - t->type = xstrdup(fstype); - tried = t; -} - -static void -free_tested(void) { - struct tried *t, *tt; - - t = tried; - while(t) { - free(t->type); - tt = t->next; - free(t); - t = tt; - } - tried = NULL; -} - -static char * -procfsnext(FILE *procfs) { - char line[100]; - char fsname[100]; - - while (fgets(line, sizeof(line), procfs)) { - if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue; - if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue; - return xstrdup(fsname); - } - return 0; -} - -/* Only use /proc/filesystems here, this is meant to test what - the kernel knows about, so /etc/filesystems is irrelevant. - Return: 1: yes, 0: no, -1: cannot open procfs */ -int -fsprobe_known_fstype_in_procfs(const char *type) -{ - FILE *procfs; - char *fsname; - int ret = -1; - - procfs = fopen(_PATH_PROC_FILESYSTEMS, "r"); - if (procfs) { - ret = 0; - while ((fsname = procfsnext(procfs)) != NULL) - if (!strcmp(fsname, type)) { - ret = 1; - break; - } - fclose(procfs); - procfs = NULL; - } - return ret; -} - -/* Try all types in FILESYSTEMS, except those in *types, - in case *types starts with "no" */ -/* return: 0: OK, -1: error in errno, 1: type not found */ -/* when 0 or -1 is returned, *types contains the type used */ -/* when 1 is returned, *types is NULL */ -int -fsprobe_procfsloop_mount(int (*mount_fn)(struct mountargs *, int *, int *), - struct mountargs *args, - const char **types, - int *special, int *status) -{ - char *files[2] = { _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS }; - FILE *procfs; - char *fsname; - const char *notypes = NULL; - int no = 0; - int ret = 1; - int errsv = 0; - int i; - - if (*types && !strncmp(*types, "no", 2)) { - no = 1; - notypes = (*types) + 2; - } - *types = NULL; - - /* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS - * (/etc/filesystems) does not exist. In some cases trying a - * filesystem that the kernel knows about on the wrong data will crash - * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the - * filesystems that we are allowed to try, and in the order they should - * be tried. End _PATH_FILESYSTEMS with a line containing a single '*' - * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards. - */ - for (i=0; i<2; i++) { - procfs = fopen(files[i], "r"); - if (!procfs) - continue; - while ((fsname = procfsnext(procfs)) != NULL) { - if (!strcmp(fsname, "*")) { - fclose(procfs); - goto nexti; - } - if (was_tested (fsname)) - continue; - if (no && matching_type(fsname, notypes)) - continue; - set_tested (fsname); - args->type = fsname; - if (verbose) - printf(_("Trying %s\n"), fsname); - if ((*mount_fn) (args, special, status) == 0) { - *types = fsname; - ret = 0; - break; - } else if (errno != EINVAL && - fsprobe_known_fstype_in_procfs(fsname) == 1) { - *types = "guess"; - ret = -1; - errsv = errno; - break; - } - } - free_tested(); - fclose(procfs); - errno = errsv; - return ret; - nexti:; - } - return 1; -} - -const char * -fsprobe_get_devname_for_mounting(const char *spec) -{ - char *name, *value; - - if (!spec) - return NULL; - - if (is_pseudo_fs(spec)) - return xstrdup(spec); - - if (parse_spec(spec, &name, &value) != 0) - return NULL; /* parse error */ - - if (name) { - const char *nspec = NULL; - - if (!strcmp(name,"LABEL")) - nspec = fsprobe_get_devname_by_label(value); - else if (!strcmp(name,"UUID")) - nspec = fsprobe_get_devname_by_uuid(value); - - if (nspec && verbose > 1) - printf(_("mount: going to mount %s by %s\n"), spec, name); - - free((void *) name); - return nspec; - } - - /* no LABEL, no UUID, .. probably a path */ - if (verbose > 1) - printf(_("mount: no LABEL=, no UUID=, going to mount %s by path\n"), spec); - - return canonicalize(spec); -} - -/* like fsprobe_get_devname_for_mounting(), but without verbose messages */ -const char * -fsprobe_get_devname(const char *spec) -{ - char *name, *value; - - if (!spec) - return NULL; - if (is_pseudo_fs(spec)) - return xstrdup(spec); - - if (parse_spec(spec, &name, &value) != 0) - return NULL; /* parse error */ - - if (name) { - const char *nspec = NULL; - - if (!strcmp(name,"LABEL")) - nspec = fsprobe_get_devname_by_label(value); - else if (!strcmp(name,"UUID")) - nspec = fsprobe_get_devname_by_uuid(value); - - free((void *) name); - return nspec; - } - - return canonicalize(spec); -} - diff --git a/mount/fsprobe.h b/mount/fsprobe.h deleted file mode 100644 index 1c50e1a7..00000000 --- a/mount/fsprobe.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef MOUNT_FSPROBE_H -#define MOUNT_FSPROBE_H -/* - * This is the generic interface for filesystem guessing libraries. - * Implementations are provided by - * - * fsprobe_blkid.c for libblkid from e2fsprogs - * fsprobe_volumeid.c for libvolume_id from udev - * - * Copyright (C) 2007 Kay Sievers - * Copyright (C) 2007 Matthias Koenig - * Copyright (C) 2007 Karel Zak - */ - -extern void fsprobe_init(void); -extern void fsprobe_exit(void); - -extern const char *fsprobe_get_devname_by_uuid(const char *uuid); -extern const char *fsprobe_get_devname_by_label(const char *label); - -extern const char *fsprobe_get_label_by_devname(const char *devname); -extern const char *fsprobe_get_uuid_by_devname(const char *devname); -extern const char *fsprobe_get_fstype_by_devname(const char *devname); - -extern const char *fsprobe_get_devname(const char *spec); -extern const char *fsprobe_get_devname_for_mounting(const char *spec); - -extern int fsprobe_known_fstype(const char *fstype); - -struct mountargs { - const char *spec; - const char *node; - const char *type; - int flags; - void *data; -}; - -extern int fsprobe_known_fstype_in_procfs(const char *type); - -extern int fsprobe_procfsloop_mount( - int (*mount_fn)(struct mountargs *, int *, int *), - struct mountargs *args, - const char **types, - int *special, int *status); - -#endif /* MOUNT_FSPROBE_H */ diff --git a/mount/fsprobe_blkid.c b/mount/fsprobe_blkid.c deleted file mode 100644 index 4d288972..00000000 --- a/mount/fsprobe_blkid.c +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include -#include "fsprobe.h" - -#define BLKID_EMPTY_CACHE "/dev/null" -static blkid_cache blkid; - -void -fsprobe_init(void) -{ - blkid = NULL; -} - -void -fsprobe_exit(void) -{ - if (blkid) - blkid_put_cache(blkid); -} - -const char * -fsprobe_get_label_by_devname(const char *devname) -{ - if (!blkid) - blkid_get_cache(&blkid, NULL); - - return blkid_get_tag_value(blkid, "LABEL", devname); -} - -const char * -fsprobe_get_uuid_by_devname(const char *devname) -{ - if (!blkid) - blkid_get_cache(&blkid, NULL); - - return blkid_get_tag_value(blkid, "UUID", devname); -} - -const char * -fsprobe_get_devname_by_uuid(const char *uuid) -{ - if (!blkid) - blkid_get_cache(&blkid, NULL); - - return blkid_get_devname(blkid, "UUID", uuid); -} - -const char * -fsprobe_get_devname_by_label(const char *label) -{ - if (!blkid) - blkid_get_cache(&blkid, NULL); - - return blkid_get_devname(blkid, "LABEL", label); -} - -int -fsprobe_known_fstype(const char *fstype) -{ - return blkid_known_fstype(fstype); -} - -const char * -fsprobe_get_fstype_by_devname(const char *devname) -{ - blkid_cache c; - const char *tp; - - if (blkid) - return blkid_get_tag_value(blkid, "TYPE", devname); - - /* The cache is not initialized yet. Use empty cache rather than waste - * time with /etc/blkid.tab. It seems that probe FS is faster than - * parse the cache file. -- kzak (17-May-2007) - */ - blkid_get_cache(&c, BLKID_EMPTY_CACHE); - tp = blkid_get_tag_value(c, "TYPE", devname); - blkid_put_cache(c); - - return tp; -} - diff --git a/mount/fsprobe_volumeid.c b/mount/fsprobe_volumeid.c deleted file mode 100644 index a5c92823..00000000 --- a/mount/fsprobe_volumeid.c +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "blkdev.h" - -#include "fsprobe.h" -#include "pathnames.h" -#include "sundries.h" - -enum probe_type { - VOLUME_ID_NONE, - VOLUME_ID_LABEL, - VOLUME_ID_UUID, - VOLUME_ID_TYPE, -}; - -static char -*probe(const char *device, enum probe_type type) -{ - int fd; - uint64_t size; - struct volume_id *id; - const char *val; - char *value = NULL; - int retries = 0; - -retry: - fd = open(device, O_RDONLY); - if (fd < 0) { - if (errno == ENOMEDIUM && retries < CRDOM_NOMEDIUM_RETRIES) { - ++retries; - sleep(3); - goto retry; - } - return NULL; - } - - id = volume_id_open_fd(fd); - if (!id) { - close(fd); - return NULL; - } - - if (blkdev_get_size(fd, &size) != 0) - size = 0; - - if (volume_id_probe_all(id, 0, size) == 0) { - switch(type) { - case VOLUME_ID_LABEL: - if (volume_id_get_label(id, &val)) - value = xstrdup(val); - break; - case VOLUME_ID_UUID: - if (volume_id_get_uuid(id, &val)) - value = xstrdup(val); - break; - case VOLUME_ID_TYPE: - if (volume_id_get_type(id, &val)) - value = xstrdup(val); - break; - default: - break; - } - } - - volume_id_close(id); - close(fd); - return value; -} - -void -fsprobe_init(void) -{ -} - -void -fsprobe_exit(void) -{ -} - -int -fsprobe_known_fstype(const char *fstype) -{ - if (volume_id_get_prober_by_type(fstype) != NULL) - return 1; - return 0; -} - -const char * -fsprobe_get_uuid_by_devname(const char *devname) -{ - return probe(devname, VOLUME_ID_UUID); -} - -const char * -fsprobe_get_label_by_devname(const char *devname) -{ - return probe(devname, VOLUME_ID_LABEL); -} - -const char * -fsprobe_get_fstype_by_devname(const char *devname) -{ - return probe(devname, VOLUME_ID_TYPE); -} - -const char * -fsprobe_get_devname_by_uuid(const char *uuid) -{ - char dev[PATH_MAX]; - size_t len; - - if (!uuid) - return NULL; - - strcpy(dev, _PATH_DEV_BYUUID "/"); - len = strlen(_PATH_DEV_BYUUID "/"); - if (!volume_id_encode_string(uuid, &dev[len], sizeof(dev) - len)) - return NULL; - return canonicalize(dev); -} - -const char * -fsprobe_get_devname_by_label(const char *label) -{ - char dev[PATH_MAX]; - size_t len; - - if (!label) - return NULL; - strcpy(dev, _PATH_DEV_BYLABEL "/"); - len = strlen(_PATH_DEV_BYLABEL "/"); - if (!volume_id_encode_string(label, &dev[len], sizeof(dev) - len)) - return NULL; - return canonicalize(dev); -} diff --git a/mount/fstab.c b/mount/fstab.c index bcbc3a9d..57954598 100644 --- a/mount/fstab.c +++ b/mount/fstab.c @@ -394,7 +394,7 @@ getfs_by_spec (const char *spec) { if (!spec) return NULL; - if (parse_spec(spec, &name, &value) != 0) + if (fsprobe_parse_spec(spec, &name, &value) != 0) return NULL; /* parse error */ if (name) { @@ -918,6 +918,7 @@ update_mtab (const char *dir, struct my_mntent *instead) { /* dummy */ const char *fsprobe_get_label_by_devname(const char *spec) { return NULL; } const char *fsprobe_get_uuid_by_devname(const char *spec) { return NULL; } +int fsprobe_parse_spec(const char *spec, char **name, char **value) { return 0; } struct my_mntent *my_getmntent (mntFILE *mfp) { return NULL; } mntFILE *my_setmntent (const char *file, char *mode) { return NULL; } void my_endmntent (mntFILE *mfp) { } diff --git a/mount/mount.c b/mount/mount.c index e04dbdb5..3f0b0c61 100644 --- a/mount/mount.c +++ b/mount/mount.c @@ -29,6 +29,7 @@ #include "pathnames.h" #include "fsprobe.h" +#include "devname.h" #include "mount_constants.h" #include "sundries.h" #include "xmalloc.h" @@ -85,6 +86,15 @@ static int restricted = 1; /* Contains the fd to read the passphrase from, if any. */ static int pfd = -1; +/* mount(2) options */ +struct mountargs { + const char *spec; + const char *node; + const char *type; + int flags; + void *data; +}; + /* Map from -o and fstab option strings to the flag argument to mount(2). */ struct opt_map { const char *opt; /* option name */ @@ -241,7 +251,7 @@ print_one (const struct my_mntent *me) { if (me->mnt_opts != NULL) printf (" (%s)", me->mnt_opts); if (list_with_volumelabel && is_pseudo_fs(me->mnt_type) == 0) { - const char *devname = fsprobe_get_devname(me->mnt_fsname); + const char *devname = spec_to_devname(me->mnt_fsname); if (devname) { const char *label; @@ -547,7 +557,7 @@ create_mtab (void) { char *extra_opts; parse_opts (fstab->m.mnt_opts, &flags, &extra_opts); mnt.mnt_dir = "/"; - mnt.mnt_fsname = fsprobe_get_devname(fstab->m.mnt_fsname); + mnt.mnt_fsname = spec_to_devname(fstab->m.mnt_fsname); mnt.mnt_type = fstab->m.mnt_type; mnt.mnt_opts = fix_opts_string (flags, extra_opts, NULL); mnt.mnt_freq = mnt.mnt_passno = 0; @@ -696,6 +706,157 @@ check_special_mountprog(const char *spec, const char *node, const char *type, in } +/* list of already tested filesystems by procfsloop_mount() */ +static struct tried { + struct tried *next; + char *type; +} *tried = NULL; + +static int +was_tested(const char *fstype) { + struct tried *t; + + if (fsprobe_known_fstype(fstype)) + return 1; + for (t = tried; t; t = t->next) { + if (!strcmp(t->type, fstype)) + return 1; + } + return 0; +} + +static void +set_tested(const char *fstype) { + struct tried *t = xmalloc(sizeof(struct tried)); + + t->next = tried; + t->type = xstrdup(fstype); + tried = t; +} + +static void +free_tested(void) { + struct tried *t, *tt; + + t = tried; + while(t) { + free(t->type); + tt = t->next; + free(t); + t = tt; + } + tried = NULL; +} + +static char * +procfsnext(FILE *procfs) { + char line[100]; + char fsname[100]; + + while (fgets(line, sizeof(line), procfs)) { + if (sscanf (line, "nodev %[^\n]\n", fsname) == 1) continue; + if (sscanf (line, " %[^ \n]\n", fsname) != 1) continue; + return xstrdup(fsname); + } + return 0; +} + +/* Only use /proc/filesystems here, this is meant to test what + the kernel knows about, so /etc/filesystems is irrelevant. + Return: 1: yes, 0: no, -1: cannot open procfs */ +static int +known_fstype_in_procfs(const char *type) +{ + FILE *procfs; + char *fsname; + int ret = -1; + + procfs = fopen(_PATH_PROC_FILESYSTEMS, "r"); + if (procfs) { + ret = 0; + while ((fsname = procfsnext(procfs)) != NULL) + if (!strcmp(fsname, type)) { + ret = 1; + break; + } + fclose(procfs); + procfs = NULL; + } + return ret; +} + +/* Try all types in FILESYSTEMS, except those in *types, + in case *types starts with "no" */ +/* return: 0: OK, -1: error in errno, 1: type not found */ +/* when 0 or -1 is returned, *types contains the type used */ +/* when 1 is returned, *types is NULL */ +static int +procfsloop_mount(int (*mount_fn)(struct mountargs *, int *, int *), + struct mountargs *args, + const char **types, + int *special, int *status) +{ + char *files[2] = { _PATH_FILESYSTEMS, _PATH_PROC_FILESYSTEMS }; + FILE *procfs; + char *fsname; + const char *notypes = NULL; + int no = 0; + int ret = 1; + int errsv = 0; + int i; + + if (*types && !strncmp(*types, "no", 2)) { + no = 1; + notypes = (*types) + 2; + } + *types = NULL; + + /* Use _PATH_PROC_FILESYSTEMS only when _PATH_FILESYSTEMS + * (/etc/filesystems) does not exist. In some cases trying a + * filesystem that the kernel knows about on the wrong data will crash + * the kernel; in such cases _PATH_FILESYSTEMS can be used to list the + * filesystems that we are allowed to try, and in the order they should + * be tried. End _PATH_FILESYSTEMS with a line containing a single '*' + * only, if _PATH_PROC_FILESYSTEMS should be tried afterwards. + */ + for (i=0; i<2; i++) { + procfs = fopen(files[i], "r"); + if (!procfs) + continue; + while ((fsname = procfsnext(procfs)) != NULL) { + if (!strcmp(fsname, "*")) { + fclose(procfs); + goto nexti; + } + if (was_tested (fsname)) + continue; + if (no && matching_type(fsname, notypes)) + continue; + set_tested (fsname); + args->type = fsname; + if (verbose) + printf(_("Trying %s\n"), fsname); + if ((*mount_fn) (args, special, status) == 0) { + *types = fsname; + ret = 0; + break; + } else if (errno != EINVAL && + known_fstype_in_procfs(fsname) == 1) { + *types = "guess"; + ret = -1; + errsv = errno; + break; + } + } + free_tested(); + fclose(procfs); + errno = errsv; + return ret; + nexti:; + } + return 1; +} + static const char * guess_fstype_by_devname(const char *devname) { @@ -769,7 +930,7 @@ guess_fstype_and_mount(const char *spec, const char *node, const char **types, return do_mount (&args, special, status); } - return fsprobe_procfsloop_mount(do_mount, &args, types, special, status); + return procfsloop_mount(do_mount, &args, types, special, status); } /* @@ -1296,7 +1457,7 @@ mount_retry: error (_("mount: %s: can't read superblock"), spec); break; case ENODEV: { - int pfs = fsprobe_known_fstype_in_procfs(types); + int pfs = known_fstype_in_procfs(types); if (pfs == 1 || !strcmp(types, "guess")) error(_("mount: %s: unknown device"), spec); @@ -1315,13 +1476,13 @@ mount_retry: u++; } } - if (u && fsprobe_known_fstype_in_procfs(lowtype) == 1) + if (u && known_fstype_in_procfs(lowtype) == 1) error (_("mount: probably you meant %s"), lowtype); else if (!strncmp(lowtype, "iso", 3) && - fsprobe_known_fstype_in_procfs("iso9660") == 1) + known_fstype_in_procfs("iso9660") == 1) error (_("mount: maybe you meant 'iso9660'?")); else if (!strncmp(lowtype, "fat", 3) && - fsprobe_known_fstype_in_procfs("vfat") == 1) + known_fstype_in_procfs("vfat") == 1) error (_("mount: maybe you meant 'vfat'?")); free(lowtype); } else @@ -1499,7 +1660,7 @@ mount_one (const char *spec, const char *node, const char *types, if (types == NULL || (strncmp(types, "nfs", 3) && strncmp(types, "cifs", 4) && strncmp(types, "smbfs", 5))) { - nspec = fsprobe_get_devname_for_mounting(spec); + nspec = spec_to_devname(spec); if (nspec) spec = nspec; } @@ -1515,7 +1676,7 @@ mounted (const char *spec0, const char *node0) { int ret = 0; /* Handle possible UUID= and LABEL= in spec */ - spec = fsprobe_get_devname(spec0); + spec = spec_to_devname(spec0); if (!spec) return ret; @@ -1791,7 +1952,7 @@ getfs(const char *spec, const char *uuid, const char *label) else if (label) devname = fsprobe_get_devname_by_label(label); else - devname = fsprobe_get_devname(spec); + devname = spec_to_devname(spec); if (devname) mc = getfs_by_devname(devname); diff --git a/mount/sundries.c b/mount/sundries.c index bdaf1172..3980f81a 100644 --- a/mount/sundries.c +++ b/mount/sundries.c @@ -242,42 +242,6 @@ matching_opts (const char *options, const char *test_opts) { return 1; } -/* - * Parses NAME=value, returns -1 on parse error, 0 success. The success is also - * when the 'spec' doesn't contain name=value pair (because the spec could be - * a devname too). In particular case the pointer 'name' is set to NULL. - - * The result is a new allocated string (the 'name' pointer). - */ -int -parse_spec(const char *spec, char **name, char **value) -{ - char *vl, *tk, *cp; - - *name = NULL; - *value = NULL; - - if (!(cp = strchr(spec, '='))) - return 0; /* no name= */ - - tk = xstrdup(spec); - vl = tk + (cp - spec); - *vl++ = '\0'; - - if (*vl == '"' || *vl == '\'') { - if (!(cp = strrchr(vl+1, *vl))) { - free(tk); - return -1; /* parse error */ - } - vl++; - *cp = '\0'; - } - - *name = tk; - *value = vl; - return 0; -} - int is_pseudo_fs(const char *type) { diff --git a/mount/sundries.h b/mount/sundries.h index c8570128..6d576e9d 100644 --- a/mount/sundries.h +++ b/mount/sundries.h @@ -35,8 +35,6 @@ char *xstrndup (const char *s, int n); char *xstrconcat3 (char *, const char *, const char *); char *xstrconcat4 (char *, const char *, const char *, const char *); -int parse_spec(const char *spec, char **name, char **value); - int is_pseudo_fs(const char *type); char *canonicalize (const char *path); diff --git a/mount/swapon.c b/mount/swapon.c index c50c32ae..8cdb7fb1 100644 --- a/mount/swapon.c +++ b/mount/swapon.c @@ -20,6 +20,7 @@ #include "swap_constants.h" #include "nls.h" #include "fsprobe.h" +#include "devname.h" #include "pathnames.h" #include "sundries.h" #include "swapheader.h" @@ -362,7 +363,7 @@ do_swapon(const char *orig_special, int prio, int canonic) { printf(_("%s on %s\n"), progname, orig_special); if (!canonic) { - special = fsprobe_get_devname(orig_special); + special = spec_to_devname(orig_special); if (!special) return cannot_find(orig_special); } @@ -475,7 +476,7 @@ do_swapoff(const char *orig_special, int quiet, int canonic) { printf(_("%s on %s\n"), progname, orig_special); if (!canonic) { - special = fsprobe_get_devname(orig_special); + special = spec_to_devname(orig_special); if (!special) return cannot_find(orig_special); } @@ -546,7 +547,7 @@ swapon_all(void) { if (skip) continue; - special = fsprobe_get_devname(fstab->mnt_fsname); + special = spec_to_devname(fstab->mnt_fsname); if (!special) { if (!ifexists) status |= cannot_find(fstab->mnt_fsname); @@ -727,7 +728,7 @@ main_swapoff(int argc, char *argv[]) { if (!streq(fstab->mnt_type, MNTTYPE_SWAP)) continue; - special = fsprobe_get_devname(fstab->mnt_fsname); + special = spec_to_devname(fstab->mnt_fsname); if (!special) continue; -- 2.39.5