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(). */
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "string-util.h"
47 bool path_is_absolute(const char *p
) {
51 bool is_path(const char *p
) {
52 return !!strchr(p
, '/');
55 int path_split_and_make_absolute(const char *p
, char ***ret
) {
62 l
= strv_split(p
, ":");
66 r
= path_strv_make_absolute_cwd(l
);
76 char *path_make_absolute(const char *p
, const char *prefix
) {
79 /* Makes every item in the list an absolute path by prepending
80 * the prefix, if specified and necessary */
82 if (path_is_absolute(p
) || !prefix
)
85 return strjoin(prefix
, "/", p
, NULL
);
88 int path_make_absolute_cwd(const char *p
, char **ret
) {
94 /* Similar to path_make_absolute(), but prefixes with the
95 * current working directory. */
97 if (path_is_absolute(p
))
100 _cleanup_free_
char *cwd
= NULL
;
102 cwd
= get_current_dir_name();
106 c
= strjoin(cwd
, "/", p
, NULL
);
115 int path_make_relative(const char *from_dir
, const char *to_path
, char **_r
) {
123 /* Strips the common part, and adds ".." elements as necessary. */
125 if (!path_is_absolute(from_dir
))
128 if (!path_is_absolute(to_path
))
131 /* Skip the common part. */
136 from_dir
+= strspn(from_dir
, "/");
137 to_path
+= strspn(to_path
, "/");
141 /* from_dir equals to_path. */
144 /* from_dir is a parent directory of to_path. */
150 path_kill_slashes(r
);
159 a
= strcspn(from_dir
, "/");
160 b
= strcspn(to_path
, "/");
165 if (memcmp(from_dir
, to_path
, a
) != 0)
172 /* If we're here, then "from_dir" has one or more elements that need to
173 * be replaced with "..". */
175 /* Count the number of necessary ".." elements. */
176 for (n_parents
= 0;;) {
177 from_dir
+= strspn(from_dir
, "/");
182 from_dir
+= strcspn(from_dir
, "/");
186 r
= malloc(n_parents
* 3 + strlen(to_path
) + 1);
190 for (p
= r
; n_parents
> 0; n_parents
--, p
+= 3)
194 path_kill_slashes(r
);
200 int path_strv_make_absolute_cwd(char **l
) {
204 /* Goes through every item in the string list and makes it
205 * absolute. This works in place and won't rollback any
206 * changes on failure. */
211 r
= path_make_absolute_cwd(*s
, &t
);
222 char **path_strv_resolve(char **l
, const char *prefix
) {
230 /* Goes through every item in the string list and canonicalize
231 * the path. This works in place and won't rollback any
232 * changes on failure. */
236 _cleanup_free_
char *orig
= NULL
;
238 if (!path_is_absolute(*s
)) {
245 t
= strappend(prefix
, orig
);
254 u
= canonicalize_file_name(t
);
256 if (errno
== ENOENT
) {
265 if (errno
== ENOMEM
|| errno
== 0)
274 x
= path_startswith(u
, prefix
);
276 /* restore the slash if it was lost */
277 if (!startswith(x
, "/"))
288 /* canonicalized path goes outside of
289 * prefix, keep the original path instead */
308 char **path_strv_resolve_uniq(char **l
, const char *prefix
) {
313 if (!path_strv_resolve(l
, prefix
))
319 char *path_kill_slashes(char *path
) {
323 /* Removes redundant inner and trailing slashes. Modifies the
324 * passed string in-place.
326 * ///foo///bar/ becomes /foo/bar
329 for (f
= path
, t
= path
; *f
; f
++) {
344 /* Special rule, if we are talking of the root directory, a
345 trailing slash is good */
347 if (t
== path
&& slash
)
354 char* path_startswith(const char *path
, const char *prefix
) {
358 if ((path
[0] == '/') != (prefix
[0] == '/'))
364 path
+= strspn(path
, "/");
365 prefix
+= strspn(prefix
, "/");
373 a
= strcspn(path
, "/");
374 b
= strcspn(prefix
, "/");
379 if (memcmp(path
, prefix
, a
) != 0)
387 int path_compare(const char *a
, const char *b
) {
393 /* A relative path and an abolute path must not compare as equal.
394 * Which one is sorted before the other does not really matter.
395 * Here a relative path is ordered before an absolute path. */
396 d
= (a
[0] == '/') - (b
[0] == '/');
406 if (*a
== 0 && *b
== 0)
409 /* Order prefixes first: "/foo" before "/foo/bar" */
418 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
419 d
= memcmp(a
, b
, MIN(j
, k
));
421 return (d
> 0) - (d
< 0); /* sign of d */
423 /* Sort "/foo/a" before "/foo/aaa" */
424 d
= (j
> k
) - (j
< k
); /* sign of (j - k) */
433 bool path_equal(const char *a
, const char *b
) {
434 return path_compare(a
, b
) == 0;
437 bool path_equal_or_files_same(const char *a
, const char *b
) {
438 return path_equal(a
, b
) || files_same(a
, b
) > 0;
441 char* path_join(const char *root
, const char *path
, const char *rest
) {
445 return strjoin(root
, endswith(root
, "/") ? "" : "/",
446 path
[0] == '/' ? path
+1 : path
,
447 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
448 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
452 rest
? (endswith(path
, "/") ? "" : "/") : NULL
,
453 rest
&& rest
[0] == '/' ? rest
+1 : rest
,
457 int path_is_read_only_fs(const char *path
) {
462 if (statvfs(path
, &st
) < 0)
465 if (st
.f_flag
& ST_RDONLY
)
468 /* On NFS, statvfs() might not reflect whether we can actually
469 * write to the remote share. Let's try again with
470 * access(W_OK) which is more reliable, at least sometimes. */
471 if (access(path
, W_OK
) < 0 && errno
== EROFS
)
477 int path_is_os_tree(const char *path
) {
481 /* We use /usr/lib/os-release as flag file if something is an OS */
482 p
= strjoina(path
, "/usr/lib/os-release");
487 /* Also check for the old location in /etc, just in case. */
488 p
= strjoina(path
, "/etc/os-release");
494 int find_binary(const char *name
, char **ret
) {
501 if (access(name
, X_OK
) < 0)
505 r
= path_make_absolute_cwd(name
, ret
);
514 * Plain getenv, not secure_getenv, because we want
515 * to actually allow the user to pick the binary.
521 last_error
= -ENOENT
;
524 _cleanup_free_
char *j
= NULL
, *element
= NULL
;
526 r
= extract_first_word(&p
, &element
, ":", EXTRACT_RELAX
|EXTRACT_DONT_COALESCE_SEPARATORS
);
532 if (!path_is_absolute(element
))
535 j
= strjoin(element
, "/", name
, NULL
);
539 if (access(j
, X_OK
) >= 0) {
543 *ret
= path_kill_slashes(j
);
556 bool paths_check_timestamp(const char* const* paths
, usec_t
*timestamp
, bool update
) {
557 bool changed
= false;
558 const char* const* i
;
565 STRV_FOREACH(i
, paths
) {
569 if (stat(*i
, &stats
) < 0)
572 u
= timespec_load(&stats
.st_mtim
);
578 log_debug("timestamp of '%s' changed", *i
);
580 /* update timestamp */
591 static int binary_is_good(const char *binary
) {
592 _cleanup_free_
char *p
= NULL
, *d
= NULL
;
595 r
= find_binary(binary
, &p
);
601 /* An fsck that is linked to /bin/true is a non-existent
604 r
= readlink_malloc(p
, &d
);
605 if (r
== -EINVAL
) /* not a symlink */
610 return !path_equal(d
, "true") &&
611 !path_equal(d
, "/bin/true") &&
612 !path_equal(d
, "/usr/bin/true") &&
613 !path_equal(d
, "/dev/null");
616 int fsck_exists(const char *fstype
) {
621 if (streq(fstype
, "auto"))
624 checker
= strjoina("fsck.", fstype
);
625 return binary_is_good(checker
);
628 int mkfs_exists(const char *fstype
) {
633 if (streq(fstype
, "auto"))
636 mkfs
= strjoina("mkfs.", fstype
);
637 return binary_is_good(mkfs
);
640 char *prefix_root(const char *root
, const char *path
) {
644 /* If root is passed, prefixes path with it. Otherwise returns
649 /* First, drop duplicate prefixing slashes from the path */
650 while (path
[0] == '/' && path
[1] == '/')
653 if (isempty(root
) || path_equal(root
, "/"))
656 l
= strlen(root
) + 1 + strlen(path
) + 1;
664 while (p
> n
&& p
[-1] == '/')
674 int parse_path_argument_and_warn(const char *path
, bool suppress_root
, char **arg
) {
679 * This function is intended to be used in command line
680 * parsers, to handle paths that are passed in. It makes the
681 * path absolute, and reduces it to NULL if omitted or
682 * root (the latter optionally).
684 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
685 * SUCCESS! Hence, do not pass in uninitialized pointers.
693 r
= path_make_absolute_cwd(path
, &p
);
695 return log_error_errno(r
, "Failed to parse path \"%s\" and make it absolute: %m", path
);
697 path_kill_slashes(p
);
698 if (suppress_root
&& path_equal(p
, "/"))
706 char* dirname_malloc(const char *path
) {
707 char *d
, *dir
, *dir2
;
727 bool filename_is_valid(const char *p
) {
739 e
= strchrnul(p
, '/');
743 if (e
- p
> FILENAME_MAX
)
749 bool path_is_safe(const char *p
) {
754 if (streq(p
, "..") || startswith(p
, "../") || endswith(p
, "/..") || strstr(p
, "/../"))
757 if (strlen(p
)+1 > PATH_MAX
)
760 /* The following two checks are not really dangerous, but hey, they still are confusing */
761 if (streq(p
, ".") || startswith(p
, "./") || endswith(p
, "/.") || strstr(p
, "/./"))
770 char *file_in_same_dir(const char *path
, const char *filename
) {
777 /* This removes the last component of path and appends
778 * filename, unless the latter is absolute anyway or the
781 if (path_is_absolute(filename
))
782 return strdup(filename
);
784 e
= strrchr(path
, '/');
786 return strdup(filename
);
788 k
= strlen(filename
);
789 ret
= new(char, (e
+ 1 - path
) + k
+ 1);
793 memcpy(mempcpy(ret
, path
, e
+ 1 - path
), filename
, k
+ 1);
797 bool hidden_file_allow_backup(const char *filename
) {
801 filename
[0] == '.' ||
802 streq(filename
, "lost+found") ||
803 streq(filename
, "aquota.user") ||
804 streq(filename
, "aquota.group") ||
805 endswith(filename
, ".rpmnew") ||
806 endswith(filename
, ".rpmsave") ||
807 endswith(filename
, ".rpmorig") ||
808 endswith(filename
, ".dpkg-old") ||
809 endswith(filename
, ".dpkg-new") ||
810 endswith(filename
, ".dpkg-tmp") ||
811 endswith(filename
, ".dpkg-dist") ||
812 endswith(filename
, ".dpkg-bak") ||
813 endswith(filename
, ".dpkg-backup") ||
814 endswith(filename
, ".dpkg-remove") ||
815 endswith(filename
, ".swp");
818 bool hidden_file(const char *filename
) {
821 if (endswith(filename
, "~"))
824 return hidden_file_allow_backup(filename
);
827 bool is_device_path(const char *path
) {
829 /* Returns true on paths that refer to a device, either in
830 * sysfs or in /dev */
833 path_startswith(path
, "/dev/") ||
834 path_startswith(path
, "/sys/");