1/*
2 * realpath.c - realpath() aware of device mapper
3 * Originated from the util-linux project.
4 */
5
6#ifdef HAVE_CONFIG_H
7#include "config.h"
8#endif
9
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
13
14#ifdef HAVE_LIMITS_H
15#include <limits.h>
16#endif
17#ifdef HAVE_CTYPE_H
18#include <ctype.h>
19#endif
20
21#include "param.h"
22#include "realpath.h"
23
24/* If there is no realpath() on the system, provide a dummy one. */
25#ifndef HAVE_REALPATH
26char *ntfs_realpath(const char *path, char *resolved_path)
27{
28       strncpy(resolved_path, path, PATH_MAX);
29       resolved_path[PATH_MAX] = '\0';
30       return resolved_path;
31}
32#endif
33
34
35#ifdef linux
36
37/*
38 * Converts private "dm-N" names to "/dev/mapper/<name>"
39 *
40 * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
41 * provides the real DM device names in /sys/block/<ptname>/dm/name
42 */
43static char *
44canonicalize_dm_name(const char *ptname, char *canonical)
45{
46	FILE	*f;
47	size_t	sz;
48	char	name[MAPPERNAMELTH + 16];
49	char	path[sizeof(name) + 16];
50	char	*res = NULL;
51
52	snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
53	if (!(f = fopen(path, "r")))
54		return NULL;
55
56	/* read "<name>\n" from sysfs */
57	if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
58		name[sz - 1] = '\0';
59		snprintf(path, sizeof(path), "/dev/mapper/%s", name);
60		res = strcpy(canonical, path);
61	}
62	fclose(f);
63	return res;
64}
65
66/*
67 *		Canonicalize a device path
68 *
69 *	Workaround from "basinilya" for fixing device mapper paths.
70 *
71 *  Background (Phillip Susi, 2011-04-09)
72 *	- ntfs-3g canonicalizes the device name so that if you mount with
73 *	  /dev/mapper/foo, the device name listed in mtab is /dev/dm-n,
74 *	  so you can not umount /dev/mapper/foo
75 *	- umount won't even recognize and translate /dev/dm-n to the mount
76 *	  point, apparently because of the '-' involved. Editing mtab and
77 *	  removing the '-' allows you to umount /dev/dmn successfully.
78 *
79 *	This code restores the devmapper name after canonicalization,
80 *	until a proper fix is implemented.
81 */
82
83char *ntfs_realpath_canonicalize(const char *path, char *canonical)
84{
85	char *p;
86
87	if (path == NULL)
88		return NULL;
89
90	if (!ntfs_realpath(path, canonical))
91		return NULL;
92
93	p = strrchr(canonical, '/');
94	if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
95		p = canonicalize_dm_name(p+1, canonical);
96		if (p)
97			return p;
98	}
99
100	return canonical;
101}
102
103#endif
104