/* * 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