]> git.proxmox.com Git - ceph.git/blob - ceph/src/mount/canonicalize.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / mount / canonicalize.c
1 /*
2 * canonicalize.c -- canonicalize pathname by removing symlinks
3 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Library Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Library Public License for more details.
14 *
15 */
16
17 /*
18 * This routine is part of libc. We include it nevertheless,
19 * since the libc version has some security flaws.
20 *
21 * TODO: use canonicalize_file_name() when exist in glibc
22 */
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <limits.h>
30
31 #ifndef MAXSYMLINKS
32 # define MAXSYMLINKS 256
33 #endif
34
35 static char *
36 myrealpath(const char *path, char *resolved_path, int maxreslth) {
37 int readlinks = 0;
38 char *npath;
39 char *link_path;
40 int n;
41 char *buf = NULL;
42
43 npath = resolved_path;
44
45 /* If it's a relative pathname use getcwd for starters. */
46 if (*path != '/') {
47 if (!getcwd(npath, maxreslth-2))
48 return NULL;
49 npath += strlen(npath);
50 if (npath[-1] != '/')
51 *npath++ = '/';
52 } else {
53 *npath++ = '/';
54 path++;
55 }
56
57 /* Expand each slash-separated pathname component. */
58 link_path = malloc(PATH_MAX+1);
59 if (!link_path)
60 return NULL;
61 while (*path != '\0') {
62 /* Ignore stray "/" */
63 if (*path == '/') {
64 path++;
65 continue;
66 }
67 if (*path == '.' && (path[1] == '\0' || path[1] == '/')) {
68 /* Ignore "." */
69 path++;
70 continue;
71 }
72 if (*path == '.' && path[1] == '.' &&
73 (path[2] == '\0' || path[2] == '/')) {
74 /* Backup for ".." */
75 path += 2;
76 while (npath > resolved_path+1 &&
77 (--npath)[-1] != '/')
78 ;
79 continue;
80 }
81 /* Safely copy the next pathname component. */
82 while (*path != '\0' && *path != '/') {
83 if (npath-resolved_path > maxreslth-2) {
84 errno = ENAMETOOLONG;
85 goto err;
86 }
87 *npath++ = *path++;
88 }
89
90 /* Protect against infinite loops. */
91 if (readlinks++ > MAXSYMLINKS) {
92 errno = ELOOP;
93 goto err;
94 }
95
96 /* See if last pathname component is a symlink. */
97 *npath = '\0';
98
99 n = readlink(resolved_path, link_path, PATH_MAX);
100 if (n < 0) {
101 /* EINVAL means the file exists but isn't a symlink. */
102 if (errno != EINVAL)
103 goto err;
104 } else {
105 int m;
106 char *newbuf;
107
108 /* Note: readlink doesn't add the null byte. */
109 link_path[n] = '\0';
110 if (*link_path == '/')
111 /* Start over for an absolute symlink. */
112 npath = resolved_path;
113 else
114 /* Otherwise back up over this component. */
115 while (*(--npath) != '/')
116 ;
117
118 /* Insert symlink contents into path. */
119 m = strlen(path);
120 newbuf = malloc(m + n + 1);
121 if (!newbuf)
122 goto err;
123 memcpy(newbuf, link_path, n);
124 memcpy(newbuf + n, path, m + 1);
125 free(buf);
126 path = buf = newbuf;
127 }
128 *npath++ = '/';
129 }
130 /* Delete trailing slash but don't whomp a lone slash. */
131 if (npath != resolved_path+1 && npath[-1] == '/')
132 npath--;
133 /* Make sure it's null terminated. */
134 *npath = '\0';
135
136 free(link_path);
137 free(buf);
138 return resolved_path;
139
140 err:
141 free(link_path);
142 free(buf);
143 return NULL;
144 }
145
146 /*
147 * Converts private "dm-N" names to "/dev/mapper/<name>"
148 *
149 * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
150 * provides the real DM device names in /sys/block/<ptname>/dm/name
151 */
152 char *
153 canonicalize_dm_name(const char *ptname)
154 {
155 FILE *f;
156 size_t sz;
157 char path[268], name[256], *res = NULL;
158
159 snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
160 if (!(f = fopen(path, "r")))
161 return NULL;
162
163 /* read "<name>\n" from sysfs */
164 if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
165 name[sz - 1] = '\0';
166 snprintf(path, sizeof(path), "/dev/mapper/%s", name);
167 res = strdup(path);
168 }
169 fclose(f);
170 return res;
171 }
172
173 char *
174 canonicalize_path(const char *path)
175 {
176 char *canonical;
177 char *p;
178
179 if (path == NULL)
180 return NULL;
181
182 canonical = malloc(PATH_MAX+2);
183 if (!canonical)
184 return NULL;
185 if (!myrealpath(path, canonical, PATH_MAX+1)) {
186 free(canonical);
187 return strdup(path);
188 }
189
190
191 p = strrchr(canonical, '/');
192 if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
193 p = canonicalize_dm_name(p+1);
194 if (p) {
195 free(canonical);
196 return p;
197 }
198 }
199
200 return canonical;
201 }
202
203