From 571dbc5784af042c94ed0f025c4d2d842c591d1f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Pierre=20Andr=C3=A9?= Date: Tue, 5 Jul 2011 12:17:12 +0200 Subject: [PATCH] Fixed device path canonicalization for use by devmapper (basilinya) For some reason, when the monted device is "/dev/mapper/*", a record in the form "/dev/dm-*" ends up in /etc/mtab and the device cannot be unmounted. The reason is unclear, the /dev/mapper name is not a symlink, and the function doing the name change is not known. No detailed feedback from the users having met the issue. The patch changes the name back to the /dev/mapper name after realpath() is called, and, if there is an actual change, both the name passed to ntfs-3g and the one passed to fuse and mount are logged in the hope of getting a clue about what is happening. But ntfs-3g is probably not the right place for a fix. --- include/ntfs-3g/Makefile.am | 1 + include/ntfs-3g/param.h | 5 ++ include/ntfs-3g/realpath.h | 24 ++++++++++ libntfs-3g/Makefile.am | 1 + libntfs-3g/realpath.c | 103 +++++++++++++++++++++++++++++++++++++++++++ libntfs-3g/volume.c | 17 +------ src/lowntfs-3g.c | 13 +---- src/ntfs-3g.c | 13 +---- src/ntfs-3g_common.c | 5 ++- src/ntfs-3g_common.h | 1 + 10 files changed, 148 insertions(+), 35 deletions(-) create mode 100644 include/ntfs-3g/realpath.h create mode 100644 libntfs-3g/realpath.c diff --git a/include/ntfs-3g/Makefile.am b/include/ntfs-3g/Makefile.am index 6067346..33343df 100644 --- a/include/ntfs-3g/Makefile.am +++ b/include/ntfs-3g/Makefile.am @@ -29,6 +29,7 @@ headers = \ ntfstime.h \ object_id.h \ param.h \ + realpath.h \ reparse.h \ runlist.h \ security.h \ diff --git a/include/ntfs-3g/param.h b/include/ntfs-3g/param.h index 57d122e..985fdb7 100644 --- a/include/ntfs-3g/param.h +++ b/include/ntfs-3g/param.h @@ -63,6 +63,11 @@ enum { #define XATTRMAPPINGFILE ".NTFS-3G/XattrMapping" /* default mapping file */ +/* + * Parameters for path canonicalization + */ + +#define MAPPERNAMELTH 256 /* * Permission checking modes for high level and low level diff --git a/include/ntfs-3g/realpath.h b/include/ntfs-3g/realpath.h new file mode 100644 index 0000000..970d2af --- /dev/null +++ b/include/ntfs-3g/realpath.h @@ -0,0 +1,24 @@ +/* + * realpath.h - realpath() aware of device mapper + */ + +#ifndef REALPATH_H +#define REALPATH_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_REALPATH +#define ntfs_realpath realpath +#else +extern char *ntfs_realpath(const char *path, char *resolved_path); +#endif + +#ifdef linux +extern char *ntfs_realpath_canonicalize(const char *path, char *resolved_path); +#else +#define ntfs_realpath_canonicalize ntfs_realpath +#endif + +#endif /* REALPATH_H */ diff --git a/libntfs-3g/Makefile.am b/libntfs-3g/Makefile.am index 292233a..b84cf64 100644 --- a/libntfs-3g/Makefile.am +++ b/libntfs-3g/Makefile.am @@ -36,6 +36,7 @@ libntfs_3g_la_SOURCES = \ misc.c \ mst.c \ object_id.c \ + realpath.c \ reparse.c \ runlist.c \ security.c \ diff --git a/libntfs-3g/realpath.c b/libntfs-3g/realpath.c new file mode 100644 index 0000000..a93bc69 --- /dev/null +++ b/libntfs-3g/realpath.c @@ -0,0 +1,103 @@ +/* + * realpath.c - realpath() aware of device mapper + * Originated from the util-linux project. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_CTYPE_H +#include +#endif + +#include "param.h" +#include "realpath.h" + +/* If there is no realpath() on the system, provide a dummy one. */ +#ifndef HAVE_REALPATH +char *ntfs_realpath(const char *path, char *resolved_path) +{ + strncpy(resolved_path, path, PATH_MAX); + resolved_path[PATH_MAX] = '\0'; + return resolved_path; +} +#endif + + +#ifdef linux + +/* + * Converts private "dm-N" names to "/dev/mapper/" + * + * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs + * provides the real DM device names in /sys/block//dm/name + */ +static char * +canonicalize_dm_name(const char *ptname, char *canonical) +{ + FILE *f; + size_t sz; + char path[MAPPERNAMELTH + 24]; + char name[MAPPERNAMELTH + 16]; + char *res = NULL; + + snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname); + if (!(f = fopen(path, "r"))) + return NULL; + + /* read "\n" from sysfs */ + if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) { + name[sz - 1] = '\0'; + snprintf(path, sizeof(path), "/dev/mapper/%s", name); + res = strcpy(canonical, path); + } + fclose(f); + return res; +} + +/* + * Canonicalize a device path + * + * Workaround from "basinilya" for fixing device mapper paths. + * + * Background (Phillip Susi, 2011-04-09) + * - ntfs-3g canonicalizes the device name so that if you mount with + * /dev/mapper/foo, the device name listed in mtab is /dev/dm-n, + * so you can not umount /dev/mapper/foo + * - umount won't even recognize and translate /dev/dm-n to the mount + * point, apparently because of the '-' involved. Editing mtab and + * removing the '-' allows you to umount /dev/dmn successfully. + * + * This code restores the devmapper name after canonicalization, + * until a proper fix is implemented. + */ + +char *ntfs_realpath_canonicalize(const char *path, char *canonical) +{ + char *p; + + if (path == NULL) + return NULL; + + if (!ntfs_realpath(path, canonical)) + return NULL; + + p = strrchr(canonical, '/'); + if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) { + p = canonicalize_dm_name(p+1, canonical); + if (p) + return p; + } + + return canonical; +} + +#endif diff --git a/libntfs-3g/volume.c b/libntfs-3g/volume.c index 28e4c90..ca30585 100644 --- a/libntfs-3g/volume.c +++ b/libntfs-3g/volume.c @@ -67,6 +67,7 @@ #include "dir.h" #include "logging.h" #include "cache.h" +#include "realpath.h" #include "misc.h" const char *ntfs_home = @@ -1359,18 +1360,6 @@ int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused))) #ifdef HAVE_MNTENT_H -#ifndef HAVE_REALPATH -/** - * realpath - If there is no realpath on the system - */ -static char *realpath(const char *path, char *resolved_path) -{ - strncpy(resolved_path, path, PATH_MAX); - resolved_path[PATH_MAX] = '\0'; - return resolved_path; -} -#endif - /** * ntfs_mntent_check - desc * @@ -1394,7 +1383,7 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags) err = errno; goto exit; } - if (!realpath(file, real_file)) { + if (!ntfs_realpath_canonicalize(file, real_file)) { err = errno; goto exit; } @@ -1403,7 +1392,7 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags) goto exit; } while ((mnt = getmntent(f))) { - if (!realpath(mnt->mnt_fsname, real_fsname)) + if (!ntfs_realpath_canonicalize(mnt->mnt_fsname, real_fsname)) continue; if (!strcmp(real_file, real_fsname)) break; diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index aeadb17..9fa177f 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -3457,16 +3457,6 @@ static void usage(void) EXEC_NAME, ntfs_home); } -#ifndef HAVE_REALPATH -/* If there is no realpath() on the system, provide a dummy one. */ -static char *realpath(const char *path, char *resolved_path) -{ - strncpy(resolved_path, path, PATH_MAX); - resolved_path[PATH_MAX] = '\0'; - return resolved_path; -} -#endif - #if defined(linux) || defined(__uClinux__) static const char *dev_fuse_msg = @@ -3668,6 +3658,9 @@ static void setup_logging(char *parsed_options) ctx->seccache = (struct PERMISSIONS_CACHE*)NULL; ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version()); + if (strcmp(opts.arg_device,opts.device)) + ntfs_log_info("Requested device %s canonicalized as %s\n", + opts.arg_device,opts.device); ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n", opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", ctx->vol->vol_name, ctx->vol->major_ver, diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 80c084d..956f04d 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -3372,16 +3372,6 @@ static void usage(void) EXEC_NAME, ntfs_home); } -#ifndef HAVE_REALPATH -/* If there is no realpath() on the system, provide a dummy one. */ -static char *realpath(const char *path, char *resolved_path) -{ - strncpy(resolved_path, path, PATH_MAX); - resolved_path[PATH_MAX] = '\0'; - return resolved_path; -} -#endif - #if defined(linux) || defined(__uClinux__) static const char *dev_fuse_msg = @@ -3588,6 +3578,9 @@ static void setup_logging(char *parsed_options) ctx->seccache = (struct PERMISSIONS_CACHE*)NULL; ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version()); + if (strcmp(opts.arg_device,opts.device)) + ntfs_log_info("Requested device %s canonicalized as %s\n", + opts.arg_device,opts.device); ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n", opts.device, (ctx->ro) ? "Read-Only" : "Read-Write", ctx->vol->vol_name, ctx->vol->major_ver, diff --git a/src/ntfs-3g_common.c b/src/ntfs-3g_common.c index 1ec24e0..b246b9c 100644 --- a/src/ntfs-3g_common.c +++ b/src/ntfs-3g_common.c @@ -47,6 +47,7 @@ #include "security.h" #include "xattrs.h" #include "ntfs-3g_common.h" +#include "realpath.h" #include "misc.h" const char xattr_ntfs_3g[] = "ntfs-3g."; @@ -509,7 +510,9 @@ int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void), return -1; /* Canonicalize device name (mtab, etc) */ - if (!realpath(optarg, popts->device)) { + popts->arg_device = optarg; + if (!ntfs_realpath_canonicalize(optarg, + popts->device)) { ntfs_log_perror("%s: Failed to access " "volume '%s'", EXEC_NAME, optarg); free(popts->device); diff --git a/src/ntfs-3g_common.h b/src/ntfs-3g_common.h index 383dbe0..978569d 100644 --- a/src/ntfs-3g_common.h +++ b/src/ntfs-3g_common.h @@ -29,6 +29,7 @@ struct ntfs_options { char *mnt_point; /* Mount point */ char *options; /* Mount options */ char *device; /* Device to mount */ + char *arg_device; /* Device requested in argv */ } ; typedef enum { -- 1.7.4.1