1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010-2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/statvfs.h>
34 #include "path-util.h"
38 bool path_is_absolute(const char *p) {
42 bool is_path(const char *p) {
43 return !!strchr(p, '/');
46 int path_get_parent(const char *path, char **_r) {
47 const char *e, *a = NULL, *b = NULL, *p;
57 for (e = path; *e; e++) {
59 if (!slash && *e == '/') {
63 } else if (slash && *e != '/')
78 r = strndup(path, p-path);
87 char **path_split_and_make_absolute(const char *p) {
91 l = strv_split(p, ":");
95 if (!path_strv_make_absolute_cwd(l)) {
103 char *path_make_absolute(const char *p, const char *prefix) {
106 /* Makes every item in the list an absolute path by prepending
107 * the prefix, if specified and necessary */
109 if (path_is_absolute(p) || !prefix)
112 return strjoin(prefix, "/", p, NULL);
115 char *path_make_absolute_cwd(const char *p) {
116 _cleanup_free_ char *cwd = NULL;
120 /* Similar to path_make_absolute(), but prefixes with the
121 * current working directory. */
123 if (path_is_absolute(p))
126 cwd = get_current_dir_name();
130 return strjoin(cwd, "/", p, NULL);
133 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
141 /* Strips the common part, and adds ".." elements as necessary. */
143 if (!path_is_absolute(from_dir))
146 if (!path_is_absolute(to_path))
149 /* Skip the common part. */
154 from_dir += strspn(from_dir, "/");
155 to_path += strspn(to_path, "/");
159 /* from_dir equals to_path. */
162 /* from_dir is a parent directory of to_path. */
168 path_kill_slashes(r);
177 a = strcspn(from_dir, "/");
178 b = strcspn(to_path, "/");
183 if (memcmp(from_dir, to_path, a) != 0)
190 /* If we're here, then "from_dir" has one or more elements that need to
191 * be replaced with "..". */
193 /* Count the number of necessary ".." elements. */
194 for (n_parents = 0;;) {
195 from_dir += strspn(from_dir, "/");
200 from_dir += strcspn(from_dir, "/");
204 r = malloc(n_parents * 3 + strlen(to_path) + 1);
208 for (p = r; n_parents > 0; n_parents--, p += 3)
212 path_kill_slashes(r);
218 char **path_strv_make_absolute_cwd(char **l) {
221 /* Goes through every item in the string list and makes it
222 * absolute. This works in place and won't rollback any
223 * changes on failure. */
228 t = path_make_absolute_cwd(*s);
239 char **path_strv_resolve(char **l, const char *prefix) {
247 /* Goes through every item in the string list and canonicalize
248 * the path. This works in place and won't rollback any
249 * changes on failure. */
253 _cleanup_free_ char *orig = NULL;
255 if (!path_is_absolute(*s)) {
262 t = strappend(prefix, orig);
271 u = canonicalize_file_name(t);
273 if (errno == ENOENT) {
282 if (errno == ENOMEM || errno == 0)
291 x = path_startswith(u, prefix);
293 /* restore the slash if it was lost */
294 if (!startswith(x, "/"))
305 /* canonicalized path goes outside of
306 * prefix, keep the original path instead */
325 char **path_strv_resolve_uniq(char **l, const char *prefix) {
330 if (!path_strv_resolve(l, prefix))
336 char *path_kill_slashes(char *path) {
340 /* Removes redundant inner and trailing slashes. Modifies the
341 * passed string in-place.
343 * ///foo///bar/ becomes /foo/bar
346 for (f = path, t = path; *f; f++) {
361 /* Special rule, if we are talking of the root directory, a
362 trailing slash is good */
364 if (t == path && slash)
371 char* path_startswith(const char *path, const char *prefix) {
375 if ((path[0] == '/') != (prefix[0] == '/'))
381 path += strspn(path, "/");
382 prefix += strspn(prefix, "/");
390 a = strcspn(path, "/");
391 b = strcspn(prefix, "/");
396 if (memcmp(path, prefix, a) != 0)
404 int path_compare(const char *a, const char *b) {
410 /* A relative path and an abolute path must not compare as equal.
411 * Which one is sorted before the other does not really matter.
412 * Here a relative path is ordered before an absolute path. */
413 d = (a[0] == '/') - (b[0] == '/');
423 if (*a == 0 && *b == 0)
426 /* Order prefixes first: "/foo" before "/foo/bar" */
435 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
436 d = memcmp(a, b, MIN(j, k));
438 return (d > 0) - (d < 0); /* sign of d */
440 /* Sort "/foo/a" before "/foo/aaa" */
441 d = (j > k) - (j < k); /* sign of (j - k) */
450 bool path_equal(const char *a, const char *b) {
451 return path_compare(a, b) == 0;
454 bool path_equal_or_files_same(const char *a, const char *b) {
455 return path_equal(a, b) || files_same(a, b) > 0;
458 char* path_join(const char *root, const char *path, const char *rest) {
462 return strjoin(root, endswith(root, "/") ? "" : "/",
463 path[0] == '/' ? path+1 : path,
464 rest ? (endswith(path, "/") ? "" : "/") : NULL,
465 rest && rest[0] == '/' ? rest+1 : rest,
469 rest ? (endswith(path, "/") ? "" : "/") : NULL,
470 rest && rest[0] == '/' ? rest+1 : rest,
474 static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
475 char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
476 _cleanup_free_ char *fdinfo = NULL;
477 _cleanup_close_ int subfd = -1;
481 if ((flags & AT_EMPTY_PATH) && isempty(filename))
482 xsprintf(path, "/proc/self/fdinfo/%i", fd);
484 subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
488 xsprintf(path, "/proc/self/fdinfo/%i", subfd);
491 r = read_full_file(path, &fdinfo, NULL);
492 if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
497 p = startswith(fdinfo, "mnt_id:");
499 p = strstr(fdinfo, "\nmnt_id:");
500 if (!p) /* The mnt_id field is a relatively new addition */
506 p += strspn(p, WHITESPACE);
507 p[strcspn(p, WHITESPACE)] = 0;
509 return safe_atoi(p, mnt_id);
512 int fd_is_mount_point(int fd, const char *filename, int flags) {
513 union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
514 int mount_id = -1, mount_id_parent = -1;
515 bool nosupp = false, check_st_dev = true;
522 /* First we will try the name_to_handle_at() syscall, which
523 * tells us the mount id and an opaque file "handle". It is
524 * not supported everywhere though (kernel compile-time
525 * option, not all file systems are hooked up). If it works
526 * the mount id is usually good enough to tell us whether
527 * something is a mount point.
529 * If that didn't work we will try to read the mount id from
530 * /proc/self/fdinfo/<fd>. This is almost as good as
531 * name_to_handle_at(), however, does not return the
532 * opaque file handle. The opaque file handle is pretty useful
533 * to detect the root directory, which we should always
534 * consider a mount point. Hence we use this only as
535 * fallback. Exporting the mnt_id in fdinfo is a pretty recent
538 * As last fallback we do traditional fstat() based st_dev
539 * comparisons. This is how things were traditionally done,
540 * but unionfs breaks breaks this since it exposes file
541 * systems with a variety of st_dev reported. Also, btrfs
542 * subvolumes have different st_dev, even though they aren't
543 * real mounts of their own. */
545 r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
548 /* This kernel does not support name_to_handle_at()
549 * fall back to simpler logic. */
550 goto fallback_fdinfo;
551 else if (errno == EOPNOTSUPP)
552 /* This kernel or file system does not support
553 * name_to_handle_at(), hence let's see if the
554 * upper fs supports it (in which case it is a
555 * mount point), otherwise fallback to the
556 * traditional stat() logic */
562 r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
564 if (errno == EOPNOTSUPP) {
566 /* Neither parent nor child do name_to_handle_at()?
567 We have no choice but to fall back. */
568 goto fallback_fdinfo;
570 /* The parent can't do name_to_handle_at() but the
571 * directory we are interested in can?
572 * If so, it must be a mount point. */
578 /* The parent can do name_to_handle_at() but the
579 * directory we are interested in can't? If so, it
580 * must be a mount point. */
584 /* If the file handle for the directory we are
585 * interested in and its parent are identical, we
586 * assume this is the root directory, which is a mount
589 if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
590 h.handle.handle_type == h_parent.handle.handle_type &&
591 memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
594 return mount_id != mount_id_parent;
597 r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
598 if (r == -EOPNOTSUPP)
603 r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
607 if (mount_id != mount_id_parent)
610 /* Hmm, so, the mount ids are the same. This leaves one
611 * special case though for the root file system. For that,
612 * let's see if the parent directory has the same inode as we
613 * are interested in. Hence, let's also do fstat() checks now,
614 * too, but avoid the st_dev comparisons, since they aren't
615 * that useful on unionfs mounts. */
616 check_st_dev = false;
619 /* yay for fstatat() taking a different set of flags than the other
621 if (flags & AT_SYMLINK_FOLLOW)
622 flags &= ~AT_SYMLINK_FOLLOW;
624 flags |= AT_SYMLINK_NOFOLLOW;
625 if (fstatat(fd, filename, &a, flags) < 0)
628 if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
631 /* A directory with same device and inode as its parent? Must
632 * be the root directory */
633 if (a.st_dev == b.st_dev &&
634 a.st_ino == b.st_ino)
637 return check_st_dev && (a.st_dev != b.st_dev);
640 /* flags can be AT_SYMLINK_FOLLOW or 0 */
641 int path_is_mount_point(const char *t, int flags) {
642 _cleanup_close_ int fd = -1;
643 _cleanup_free_ char *canonical = NULL, *parent = NULL;
648 if (path_equal(t, "/"))
651 /* we need to resolve symlinks manually, we can't just rely on
652 * fd_is_mount_point() to do that for us; if we have a structure like
653 * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
654 * look at needs to be /usr, not /. */
655 if (flags & AT_SYMLINK_FOLLOW) {
656 canonical = canonicalize_file_name(t);
661 r = path_get_parent(canonical ?: t, &parent);
665 fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
669 return fd_is_mount_point(fd, basename(canonical ?: t), flags);
672 int path_is_read_only_fs(const char *path) {
677 if (statvfs(path, &st) < 0)
680 if (st.f_flag & ST_RDONLY)
683 /* On NFS, statvfs() might not reflect whether we can actually
684 * write to the remote share. Let's try again with
685 * access(W_OK) which is more reliable, at least sometimes. */
686 if (access(path, W_OK) < 0 && errno == EROFS)
692 int path_is_os_tree(const char *path) {
696 /* We use /usr/lib/os-release as flag file if something is an OS */
697 p = strjoina(path, "/usr/lib/os-release");
703 /* Also check for the old location in /etc, just in case. */
704 p = strjoina(path, "/etc/os-release");
710 int find_binary(const char *name, bool local, char **filename) {
714 if (local && access(name, X_OK) < 0)
720 p = path_make_absolute_cwd(name);
730 const char *word, *state;
734 * Plain getenv, not secure_getenv, because we want
735 * to actually allow the user to pick the binary.
737 path = getenv("PATH");
741 FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
742 _cleanup_free_ char *p = NULL;
744 if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
747 if (access(p, X_OK) < 0)
751 *filename = path_kill_slashes(p);
762 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
763 bool changed = false;
764 const char* const* i;
771 STRV_FOREACH(i, paths) {
775 if (stat(*i, &stats) < 0)
778 u = timespec_load(&stats.st_mtim);
784 log_debug("timestamp of '%s' changed", *i);
786 /* update timestamp */
797 int fsck_exists(const char *fstype) {
798 _cleanup_free_ char *p = NULL, *d = NULL;
802 checker = strjoina("fsck.", fstype);
804 r = find_binary(checker, true, &p);
808 /* An fsck that is linked to /bin/true is a non-existent
811 r = readlink_malloc(p, &d);
813 (path_equal(d, "/bin/true") ||
814 path_equal(d, "/usr/bin/true") ||
815 path_equal(d, "/dev/null")))
821 char *prefix_root(const char *root, const char *path) {
825 /* If root is passed, prefixes path with it. Otherwise returns
830 /* First, drop duplicate prefixing slashes from the path */
831 while (path[0] == '/' && path[1] == '/')
834 if (isempty(root) || path_equal(root, "/"))
837 l = strlen(root) + 1 + strlen(path) + 1;
845 while (p > n && p[-1] == '/')