]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/canonicalize.c
2 * canonicalize.c -- canonicalize pathname by removing symlinks
4 * This file may be distributed under the terms of the
5 * GNU Lesser General Public License.
7 * Copyright (C) 2009-2013 Karel Zak <kzak@redhat.com>
15 #include <sys/types.h>
19 #include "canonicalize.h"
20 #include "pathnames.h"
25 * Converts private "dm-N" names to "/dev/mapper/<name>"
27 * Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
28 * provides the real DM device names in /sys/block/<ptname>/dm/name
30 char *__canonicalize_dm_name(const char *prefix
, const char *ptname
)
34 char path
[256], name
[sizeof(path
) - sizeof(_PATH_DEV_MAPPER
)], *res
= NULL
;
36 if (!ptname
|| !*ptname
)
42 snprintf(path
, sizeof(path
), "%s/sys/block/%s/dm/name", prefix
, ptname
);
43 if (!(f
= fopen(path
, "r" UL_CLOEXECSTR
)))
46 /* read "<name>\n" from sysfs */
47 if (fgets(name
, sizeof(name
), f
) && (sz
= strlen(name
)) > 1) {
49 snprintf(path
, sizeof(path
), _PATH_DEV_MAPPER
"/%s", name
);
51 if ((prefix
&& *prefix
) || access(path
, F_OK
) == 0)
58 char *canonicalize_dm_name(const char *ptname
)
60 return __canonicalize_dm_name(NULL
, ptname
);
63 static int is_dm_devname(char *canonical
, char **name
)
66 char *p
= strrchr(canonical
, '/');
71 || strncmp(p
, "/dm-", 4) != 0
73 || stat(canonical
, &sb
) != 0
74 || !S_ISBLK(sb
.st_mode
))
82 * This function does not canonicalize the path! It just prepends CWD before a
83 * relative path. If the path is no relative than returns NULL. The path does
86 char *absolute_path(const char *path
)
88 char cwd
[PATH_MAX
], *res
, *p
;
91 if (!is_relative_path(path
)) {
95 if (!getcwd(cwd
, sizeof(cwd
)))
99 if (startswith(path
, "./"))
101 else if (strcmp(path
, ".") == 0)
110 p
= res
= malloc(csz
+ 1 + psz
+ 1);
114 p
= mempcpy(p
, cwd
, csz
);
116 memcpy(p
, path
, psz
+ 1);
121 char *canonicalize_path(const char *path
)
123 char *canonical
, *dmname
;
128 canonical
= realpath(path
, NULL
);
132 if (is_dm_devname(canonical
, &dmname
)) {
133 char *dm
= canonicalize_dm_name(dmname
);
143 char *canonicalize_path_restricted(const char *path
)
145 char *canonical
= NULL
;
154 if (pipe(pipes
) != 0)
158 * To accurately assume identity of getuid() we must use setuid()
159 * but if we do that, we lose ability to reassume euid of 0, so
160 * we fork to do the check to keep euid intact.
167 return NULL
; /* fork error */
169 close(pipes
[0]); /* close unused end */
173 if (drop_permissions() != 0)
174 canonical
= NULL
; /* failed */
178 canonical
= realpath(path
, NULL
);
179 if (canonical
&& is_dm_devname(canonical
, &dmname
)) {
180 char *dm
= canonicalize_dm_name(dmname
);
188 len
= canonical
? (ssize_t
) strlen(canonical
) :
189 errno
? -errno
: -EINVAL
;
191 /* send length or errno */
192 write_all(pipes
[1], (char *) &len
, sizeof(len
));
194 write_all(pipes
[1], canonical
, len
);
200 close(pipes
[1]); /* close unused end */
203 /* read size or -errno */
204 if (read_all(pipes
[0], (char *) &len
, sizeof(len
)) != sizeof(len
))
211 canonical
= malloc(len
+ 1);
217 if (read_all(pipes
[0], canonical
, len
) != len
) {
221 canonical
[len
] = '\0';
229 /* We make a best effort to reap child */
230 ignore_result( waitpid(pid
, NULL
, 0) );
237 #ifdef TEST_PROGRAM_CANONICALIZE
238 int main(int argc
, char **argv
)
241 fprintf(stderr
, "usage: %s <device>\n", argv
[0]);
245 fprintf(stdout
, "orig: %s\n", argv
[1]);
246 fprintf(stdout
, "real: %s\n", canonicalize_path(argv
[1]));