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/>.
27 #include <sys/statvfs.h>
30 /* When we include libgen.h because we need dirname() we immediately
31 * undefine basename() since libgen.h defines it as a macro to the
32 * POSIX version which is really broken. We prefer GNU basename(). */
36 #include "alloc-util.h"
43 #include "parse-util.h"
44 #include "path-util.h"
45 #include "stat-util.h"
46 #include "string-util.h"
50 bool path_is_absolute(const char *p) {
54 bool is_path(const char *p) {
55 return !!strchr(p, '/');
58 #if 0 /// UNNEEDED by elogind
59 int path_split_and_make_absolute(const char *p, char ***ret) {
66 l = strv_split(p, ":");
70 r = path_strv_make_absolute_cwd(l);
80 char *path_make_absolute(const char *p, const char *prefix) {
83 /* Makes every item in the list an absolute path by prepending
84 * the prefix, if specified and necessary */
86 if (path_is_absolute(p) || !prefix)
89 return strjoin(prefix, "/", p, NULL);
93 int path_make_absolute_cwd(const char *p, char **ret) {
99 /* Similar to path_make_absolute(), but prefixes with the
100 * current working directory. */
102 if (path_is_absolute(p))
105 _cleanup_free_ char *cwd = NULL;
107 cwd = get_current_dir_name();
111 c = strjoin(cwd, "/", p, NULL);
120 #if 0 /// UNNEEDED by elogind
121 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
129 /* Strips the common part, and adds ".." elements as necessary. */
131 if (!path_is_absolute(from_dir))
134 if (!path_is_absolute(to_path))
137 /* Skip the common part. */
142 from_dir += strspn(from_dir, "/");
143 to_path += strspn(to_path, "/");
147 /* from_dir equals to_path. */
150 /* from_dir is a parent directory of to_path. */
156 path_kill_slashes(r);
165 a = strcspn(from_dir, "/");
166 b = strcspn(to_path, "/");
171 if (memcmp(from_dir, to_path, a) != 0)
178 /* If we're here, then "from_dir" has one or more elements that need to
179 * be replaced with "..". */
181 /* Count the number of necessary ".." elements. */
182 for (n_parents = 0;;) {
183 from_dir += strspn(from_dir, "/");
188 from_dir += strcspn(from_dir, "/");
192 r = malloc(n_parents * 3 + strlen(to_path) + 1);
196 for (p = r; n_parents > 0; n_parents--, p += 3)
200 path_kill_slashes(r);
206 int path_strv_make_absolute_cwd(char **l) {
210 /* Goes through every item in the string list and makes it
211 * absolute. This works in place and won't rollback any
212 * changes on failure. */
217 r = path_make_absolute_cwd(*s, &t);
229 char **path_strv_resolve(char **l, const char *prefix) {
237 /* Goes through every item in the string list and canonicalize
238 * the path. This works in place and won't rollback any
239 * changes on failure. */
243 _cleanup_free_ char *orig = NULL;
245 if (!path_is_absolute(*s)) {
252 t = strappend(prefix, orig);
261 u = canonicalize_file_name(t);
263 if (errno == ENOENT) {
272 if (errno == ENOMEM || errno == 0)
281 x = path_startswith(u, prefix);
283 /* restore the slash if it was lost */
284 if (!startswith(x, "/"))
295 /* canonicalized path goes outside of
296 * prefix, keep the original path instead */
315 char **path_strv_resolve_uniq(char **l, const char *prefix) {
320 if (!path_strv_resolve(l, prefix))
326 char *path_kill_slashes(char *path) {
330 /* Removes redundant inner and trailing slashes. Modifies the
331 * passed string in-place.
333 * ///foo///bar/ becomes /foo/bar
336 for (f = path, t = path; *f; f++) {
351 /* Special rule, if we are talking of the root directory, a
352 trailing slash is good */
354 if (t == path && slash)
361 char* path_startswith(const char *path, const char *prefix) {
365 if ((path[0] == '/') != (prefix[0] == '/'))
371 path += strspn(path, "/");
372 prefix += strspn(prefix, "/");
380 a = strcspn(path, "/");
381 b = strcspn(prefix, "/");
386 if (memcmp(path, prefix, a) != 0)
394 int path_compare(const char *a, const char *b) {
400 /* A relative path and an abolute path must not compare as equal.
401 * Which one is sorted before the other does not really matter.
402 * Here a relative path is ordered before an absolute path. */
403 d = (a[0] == '/') - (b[0] == '/');
413 if (*a == 0 && *b == 0)
416 /* Order prefixes first: "/foo" before "/foo/bar" */
425 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
426 d = memcmp(a, b, MIN(j, k));
428 return (d > 0) - (d < 0); /* sign of d */
430 /* Sort "/foo/a" before "/foo/aaa" */
431 d = (j > k) - (j < k); /* sign of (j - k) */
440 bool path_equal(const char *a, const char *b) {
441 return path_compare(a, b) == 0;
444 bool path_equal_or_files_same(const char *a, const char *b) {
445 return path_equal(a, b) || files_same(a, b) > 0;
448 #if 0 /// UNNEEDED by elogind
449 char* path_join(const char *root, const char *path, const char *rest) {
453 return strjoin(root, endswith(root, "/") ? "" : "/",
454 path[0] == '/' ? path+1 : path,
455 rest ? (endswith(path, "/") ? "" : "/") : NULL,
456 rest && rest[0] == '/' ? rest+1 : rest,
460 rest ? (endswith(path, "/") ? "" : "/") : NULL,
461 rest && rest[0] == '/' ? rest+1 : rest,
465 #if 0 /// UNNEEDED by elogind
467 int find_binary(const char *name, char **ret) {
474 if (access(name, X_OK) < 0)
478 r = path_make_absolute_cwd(name, ret);
487 * Plain getenv, not secure_getenv, because we want
488 * to actually allow the user to pick the binary.
494 last_error = -ENOENT;
497 _cleanup_free_ char *j = NULL, *element = NULL;
499 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
505 if (!path_is_absolute(element))
508 j = strjoin(element, "/", name, NULL);
512 if (access(j, X_OK) >= 0) {
516 *ret = path_kill_slashes(j);
529 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
530 bool changed = false;
531 const char* const* i;
538 STRV_FOREACH(i, paths) {
542 if (stat(*i, &stats) < 0)
545 u = timespec_load(&stats.st_mtim);
551 log_debug("timestamp of '%s' changed", *i);
553 /* update timestamp */
564 static int binary_is_good(const char *binary) {
565 _cleanup_free_ char *p = NULL, *d = NULL;
568 r = find_binary(binary, &p);
574 /* An fsck that is linked to /bin/true is a non-existent
577 r = readlink_malloc(p, &d);
578 if (r == -EINVAL) /* not a symlink */
583 return !path_equal(d, "true") &&
584 !path_equal(d, "/bin/true") &&
585 !path_equal(d, "/usr/bin/true") &&
586 !path_equal(d, "/dev/null");
589 int fsck_exists(const char *fstype) {
594 if (streq(fstype, "auto"))
597 checker = strjoina("fsck.", fstype);
598 return binary_is_good(checker);
601 int mkfs_exists(const char *fstype) {
606 if (streq(fstype, "auto"))
609 mkfs = strjoina("mkfs.", fstype);
610 return binary_is_good(mkfs);
613 char *prefix_root(const char *root, const char *path) {
617 /* If root is passed, prefixes path with it. Otherwise returns
622 /* First, drop duplicate prefixing slashes from the path */
623 while (path[0] == '/' && path[1] == '/')
626 if (isempty(root) || path_equal(root, "/"))
629 l = strlen(root) + 1 + strlen(path) + 1;
637 while (p > n && p[-1] == '/')
647 int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
652 * This function is intended to be used in command line
653 * parsers, to handle paths that are passed in. It makes the
654 * path absolute, and reduces it to NULL if omitted or
655 * root (the latter optionally).
657 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
658 * SUCCESS! Hence, do not pass in uninitialized pointers.
666 r = path_make_absolute_cwd(path, &p);
668 return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
670 path_kill_slashes(p);
671 if (suppress_root && path_equal(p, "/"))
680 char* dirname_malloc(const char *path) {
681 char *d, *dir, *dir2;
701 bool filename_is_valid(const char *p) {
713 e = strchrnul(p, '/');
717 if (e - p > FILENAME_MAX)
723 bool path_is_safe(const char *p) {
728 if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
731 if (strlen(p)+1 > PATH_MAX)
734 /* The following two checks are not really dangerous, but hey, they still are confusing */
735 if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
744 char *file_in_same_dir(const char *path, const char *filename) {
751 /* This removes the last component of path and appends
752 * filename, unless the latter is absolute anyway or the
755 if (path_is_absolute(filename))
756 return strdup(filename);
758 e = strrchr(path, '/');
760 return strdup(filename);
762 k = strlen(filename);
763 ret = new(char, (e + 1 - path) + k + 1);
767 memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
771 bool hidden_file_allow_backup(const char *filename) {
775 filename[0] == '.' ||
776 streq(filename, "lost+found") ||
777 streq(filename, "aquota.user") ||
778 streq(filename, "aquota.group") ||
779 endswith(filename, ".rpmnew") ||
780 endswith(filename, ".rpmsave") ||
781 endswith(filename, ".rpmorig") ||
782 endswith(filename, ".dpkg-old") ||
783 endswith(filename, ".dpkg-new") ||
784 endswith(filename, ".dpkg-tmp") ||
785 endswith(filename, ".dpkg-dist") ||
786 endswith(filename, ".dpkg-bak") ||
787 endswith(filename, ".dpkg-backup") ||
788 endswith(filename, ".dpkg-remove") ||
789 endswith(filename, ".swp");
792 bool hidden_file(const char *filename) {
795 if (endswith(filename, "~"))
798 return hidden_file_allow_backup(filename);
801 #if 0 /// UNNEEDED by elogind
802 bool is_device_path(const char *path) {
804 /* Returns true on paths that refer to a device, either in
805 * sysfs or in /dev */
808 path_startswith(path, "/dev/") ||
809 path_startswith(path, "/sys/");