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
--- /dev/null
+#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 */
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+#include <blkid/blkid.h> /* TODO: <blkid.h>, -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 <libvolume_id.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;
+
+ 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 */
# 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
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)
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
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
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)
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)
--- /dev/null
+#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);
+}
+
--- /dev/null
+#ifndef MOUNT_DEVNAME_H
+#define MOUNT_DEVNAME_H
+
+extern const char *spec_to_devname(const char *spec);
+
+#endif
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#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);
-}
-
+++ /dev/null
-#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 <kay.sievers@vrfy.org>
- * Copyright (C) 2007 Matthias Koenig <mkoenig@suse.de>
- * Copyright (C) 2007 Karel Zak <kzak@redhat.com>
- */
-
-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 */
+++ /dev/null
-#include <stdio.h>
-#include <blkid/blkid.h>
-#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;
-}
-
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <stddef.h>
-#include <errno.h>
-#include <sys/mount.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <libvolume_id.h>
-
-#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);
-}
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) {
/* 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) { }
#include "pathnames.h"
#include "fsprobe.h"
+#include "devname.h"
#include "mount_constants.h"
#include "sundries.h"
#include "xmalloc.h"
/* 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 */
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;
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;
}
+/* 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)
{
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);
}
/*
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);
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
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;
}
int ret = 0;
/* Handle possible UUID= and LABEL= in spec */
- spec = fsprobe_get_devname(spec0);
+ spec = spec_to_devname(spec0);
if (!spec)
return ret;
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);
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)
{
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);
#include "swap_constants.h"
#include "nls.h"
#include "fsprobe.h"
+#include "devname.h"
#include "pathnames.h"
#include "sundries.h"
#include "swapheader.h"
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);
}
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);
}
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);
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;