1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010-2012 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 /* When we include libgen.h because we need dirname() we immediately
30 * undefine basename() since libgen.h defines it as a macro to the
31 * POSIX version which is really broken. We prefer GNU basename(). */
35 #include "alloc-util.h"
36 #include "extract-word.h"
38 //#include "glob-util.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "stat-util.h"
45 #include "string-util.h"
47 #include "time-util.h"
49 bool path_is_absolute(const char *p) {
53 bool is_path(const char *p) {
54 return !!strchr(p, '/');
57 #if 0 /// UNNEEDED by elogind
58 int path_split_and_make_absolute(const char *p, char ***ret) {
65 l = strv_split(p, ":");
69 r = path_strv_make_absolute_cwd(l);
79 char *path_make_absolute(const char *p, const char *prefix) {
82 /* Makes every item in the list an absolute path by prepending
83 * the prefix, if specified and necessary */
85 if (path_is_absolute(p) || isempty(prefix))
88 if (endswith(prefix, "/"))
89 return strjoin(prefix, p);
91 return strjoin(prefix, "/", p);
95 int safe_getcwd(char **ret) {
98 cwd = get_current_dir_name();
100 return negative_errno();
102 /* Let's make sure the directory is really absolute, to protect us from the logic behind
103 * CVE-2018-1000001 */
113 int path_make_absolute_cwd(const char *p, char **ret) {
120 /* Similar to path_make_absolute(), but prefixes with the
121 * current working directory. */
123 if (path_is_absolute(p))
126 _cleanup_free_ char *cwd = NULL;
128 r = safe_getcwd(&cwd);
132 if (endswith(cwd, "/"))
135 c = strjoin(cwd, "/", p);
144 #if 0 /// UNNEEDED by elogind
145 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
153 /* Strips the common part, and adds ".." elements as necessary. */
155 if (!path_is_absolute(from_dir))
158 if (!path_is_absolute(to_path))
161 /* Skip the common part. */
165 from_dir += strspn(from_dir, "/");
166 to_path += strspn(to_path, "/");
170 /* from_dir equals to_path. */
173 /* from_dir is a parent directory of to_path. */
178 path_kill_slashes(r);
187 a = strcspn(from_dir, "/");
188 b = strcspn(to_path, "/");
193 if (memcmp(from_dir, to_path, a) != 0)
200 /* If we're here, then "from_dir" has one or more elements that need to
201 * be replaced with "..". */
203 /* Count the number of necessary ".." elements. */
204 for (n_parents = 0;;) {
207 from_dir += strspn(from_dir, "/");
212 w = strcspn(from_dir, "/");
214 /* If this includes ".." we can't do a simple series of "..", refuse */
215 if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.')
218 /* Count number of elements, except if they are "." */
219 if (w != 1 || from_dir[0] != '.')
225 r = new(char, n_parents * 3 + strlen(to_path) + 1);
229 for (p = r; n_parents > 0; n_parents--)
230 p = mempcpy(p, "../", 3);
233 path_kill_slashes(r);
239 int path_strv_make_absolute_cwd(char **l) {
243 /* Goes through every item in the string list and makes it
244 * absolute. This works in place and won't rollback any
245 * changes on failure. */
250 r = path_make_absolute_cwd(*s, &t);
254 path_kill_slashes(t);
255 free_and_replace(*s, t);
262 char **path_strv_resolve(char **l, const char *root) {
271 /* Goes through every item in the string list and canonicalize
272 * the path. This works in place and won't rollback any
273 * changes on failure. */
276 _cleanup_free_ char *orig = NULL;
279 if (!path_is_absolute(*s)) {
286 t = prefix_root(root, orig);
294 r = chase_symlinks(t, root, 0, &u);
312 x = path_startswith(u, root);
314 /* restore the slash if it was lost */
315 if (!startswith(x, "/"))
326 /* canonicalized path goes outside of
327 * prefix, keep the original path instead */
328 free_and_replace(u, orig);
344 char **path_strv_resolve_uniq(char **l, const char *root) {
349 if (!path_strv_resolve(l, root))
355 char *path_kill_slashes(char *path) {
359 /* Removes redundant inner and trailing slashes. Modifies the
360 * passed string in-place.
362 * ///foo///bar/ becomes /foo/bar
365 for (f = path, t = path; *f; f++) {
380 /* Special rule, if we are talking of the root directory, a
381 trailing slash is good */
383 if (t == path && slash)
390 char* path_startswith(const char *path, const char *prefix) {
394 /* Returns a pointer to the start of the first component after the parts matched by
396 * - both paths are absolute or both paths are relative,
398 * - each component in prefix in turn matches a component in path at the same position.
399 * An empty string will be returned when the prefix and path are equivalent.
401 * Returns NULL otherwise.
404 if ((path[0] == '/') != (prefix[0] == '/'))
410 path += strspn(path, "/");
411 prefix += strspn(prefix, "/");
419 a = strcspn(path, "/");
420 b = strcspn(prefix, "/");
425 if (memcmp(path, prefix, a) != 0)
433 int path_compare(const char *a, const char *b) {
439 /* A relative path and an abolute path must not compare as equal.
440 * Which one is sorted before the other does not really matter.
441 * Here a relative path is ordered before an absolute path. */
442 d = (a[0] == '/') - (b[0] == '/');
452 if (*a == 0 && *b == 0)
455 /* Order prefixes first: "/foo" before "/foo/bar" */
464 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
465 d = memcmp(a, b, MIN(j, k));
467 return (d > 0) - (d < 0); /* sign of d */
469 /* Sort "/foo/a" before "/foo/aaa" */
470 d = (j > k) - (j < k); /* sign of (j - k) */
479 bool path_equal(const char *a, const char *b) {
480 return path_compare(a, b) == 0;
483 bool path_equal_or_files_same(const char *a, const char *b, int flags) {
484 return path_equal(a, b) || files_same(a, b, flags) > 0;
487 char* path_join(const char *root, const char *path, const char *rest) {
491 return strjoin(root, endswith(root, "/") ? "" : "/",
492 path[0] == '/' ? path+1 : path,
493 rest ? (endswith(path, "/") ? "" : "/") : NULL,
494 rest && rest[0] == '/' ? rest+1 : rest);
497 rest ? (endswith(path, "/") ? "" : "/") : NULL,
498 rest && rest[0] == '/' ? rest+1 : rest);
501 int find_binary(const char *name, char **ret) {
508 if (access(name, X_OK) < 0)
512 r = path_make_absolute_cwd(name, ret);
521 * Plain getenv, not secure_getenv, because we want
522 * to actually allow the user to pick the binary.
528 last_error = -ENOENT;
531 _cleanup_free_ char *j = NULL, *element = NULL;
533 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
539 if (!path_is_absolute(element))
542 j = strjoin(element, "/", name);
546 if (access(j, X_OK) >= 0) {
550 *ret = path_kill_slashes(j);
563 #if 0 /// UNNEEDED by elogind
564 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
565 bool changed = false;
566 const char* const* i;
573 STRV_FOREACH(i, paths) {
577 if (stat(*i, &stats) < 0)
580 u = timespec_load(&stats.st_mtim);
586 log_debug("timestamp of '%s' changed", *i);
588 /* update timestamp */
599 static int binary_is_good(const char *binary) {
600 _cleanup_free_ char *p = NULL, *d = NULL;
603 r = find_binary(binary, &p);
609 /* An fsck that is linked to /bin/true is a non-existent
612 r = readlink_malloc(p, &d);
613 if (r == -EINVAL) /* not a symlink */
618 return !PATH_IN_SET(d, "true"
624 int fsck_exists(const char *fstype) {
629 if (streq(fstype, "auto"))
632 checker = strjoina("fsck.", fstype);
633 return binary_is_good(checker);
636 int mkfs_exists(const char *fstype) {
641 if (streq(fstype, "auto"))
644 mkfs = strjoina("mkfs.", fstype);
645 return binary_is_good(mkfs);
649 char *prefix_root(const char *root, const char *path) {
653 /* If root is passed, prefixes path with it. Otherwise returns
658 /* First, drop duplicate prefixing slashes from the path */
659 while (path[0] == '/' && path[1] == '/')
662 if (isempty(root) || path_equal(root, "/"))
665 l = strlen(root) + 1 + strlen(path) + 1;
673 while (p > n && p[-1] == '/')
683 #if 0 /// UNNEEDED by elogind
684 int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
689 * This function is intended to be used in command line
690 * parsers, to handle paths that are passed in. It makes the
691 * path absolute, and reduces it to NULL if omitted or
692 * root (the latter optionally).
694 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
695 * SUCCESS! Hence, do not pass in uninitialized pointers.
703 r = path_make_absolute_cwd(path, &p);
705 return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
707 path_kill_slashes(p);
708 if (suppress_root && path_equal(p, "/"))
717 char* dirname_malloc(const char *path) {
718 char *d, *dir, *dir2;
738 const char *last_path_component(const char *path) {
739 /* Finds the last component of the path, preserving the
740 * optional trailing slash that signifies a directory.
747 * This is different than basename, which returns "" when
748 * a trailing slash is present.
753 l = k = strlen(path);
754 if (l == 0) /* special case — an empty string */
757 while (k > 0 && path[k-1] == '/')
760 if (k == 0) /* the root directory */
763 while (k > 0 && path[k-1] != '/')
769 bool filename_is_valid(const char *p) {
775 if (dot_or_dot_dot(p))
778 e = strchrnul(p, '/');
782 if (e - p > FILENAME_MAX)
788 bool path_is_normalized(const char *p) {
793 if (dot_or_dot_dot(p))
796 if (startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
799 if (strlen(p)+1 > PATH_MAX)
802 if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
811 char *file_in_same_dir(const char *path, const char *filename) {
818 /* This removes the last component of path and appends
819 * filename, unless the latter is absolute anyway or the
822 if (path_is_absolute(filename))
823 return strdup(filename);
825 e = strrchr(path, '/');
827 return strdup(filename);
829 k = strlen(filename);
830 ret = new(char, (e + 1 - path) + k + 1);
834 memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
838 bool hidden_or_backup_file(const char *filename) {
843 if (filename[0] == '.' ||
844 streq(filename, "lost+found") ||
845 streq(filename, "aquota.user") ||
846 streq(filename, "aquota.group") ||
847 endswith(filename, "~"))
850 p = strrchr(filename, '.');
854 /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
855 * with always new suffixes and that everybody else should just adjust to that, then it really should be on
856 * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
857 * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
858 * string. Specifically: there's now:
860 * The generic suffixes "~" and ".bak" for backup files
861 * The generic prefix "." for hidden files
863 * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
864 * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
867 return STR_IN_SET(p + 1,
887 #if 0 /// UNNEEDED by elogind
888 bool is_device_path(const char *path) {
890 /* Returns true on paths that refer to a device, either in
891 * sysfs or in /dev */
893 return path_startswith(path, "/dev/") ||
894 path_startswith(path, "/sys/");
897 bool is_deviceallow_pattern(const char *path) {
898 return path_startswith(path, "/dev/") ||
899 startswith(path, "block-") ||
900 startswith(path, "char-");
903 int systemd_installation_has_version(const char *root, unsigned minimal_version) {
907 /* Try to guess if systemd installation is later than the specified version. This
908 * is hacky and likely to yield false negatives, particularly if the installation
909 * is non-standard. False positives should be relatively rare.
912 NULSTR_FOREACH(pattern,
913 /* /lib works for systems without usr-merge, and for systems with a sane
914 * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
915 * for Gentoo which does a merge without making /lib a symlink.
917 "lib/systemd/libsystemd-shared-*.so\0"
918 "lib64/systemd/libsystemd-shared-*.so\0"
919 "usr/lib/systemd/libsystemd-shared-*.so\0"
920 "usr/lib64/systemd/libsystemd-shared-*.so\0") {
922 _cleanup_strv_free_ char **names = NULL;
923 _cleanup_free_ char *path = NULL;
926 path = prefix_root(root, pattern);
930 r = glob_extend(&names, path);
936 assert_se((c = endswith(path, "*.so")));
937 *c = '\0'; /* truncate the glob part */
939 STRV_FOREACH(name, names) {
940 /* This is most likely to run only once, hence let's not optimize anything. */
944 t = startswith(*name, path);
948 t2 = endswith(t, ".so");
952 t2[0] = '\0'; /* truncate the suffix */
954 r = safe_atou(t, &version);
956 log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
960 log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
962 version >= minimal_version ? "OK" : "too old");
963 if (version >= minimal_version)
972 bool dot_or_dot_dot(const char *path) {