xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/realpath.c (revision 002f37b0cca92e4cf72857c72ac95db5a8b09615)
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
26 char *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  */
43 static char *
44 canonicalize_dm_name(const char *ptname, char *canonical)
45 {
46 	FILE	*f;
47 	size_t	sz;
48 	char	path[MAPPERNAMELTH + 24];
49 	char	name[MAPPERNAMELTH + 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 
83 char *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