]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/basic/path-util.c
ci: enable build/unit test jobs on ppc64le
[thirdparty/systemd.git] / src / basic / path-util.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <fnmatch.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7
8#include "alloc-util.h"
9#include "chase.h"
10#include "errno-util.h"
11#include "extract-word.h"
12#include "fd-util.h"
13#include "fs-util.h"
14#include "glob-util.h"
15#include "log.h"
16#include "path-util.h"
17#include "stat-util.h"
18#include "string-util.h"
19#include "strv.h"
20#include "time-util.h"
21
22bool is_path(const char *p) {
23 if (!p) /* A NULL pointer is definitely not a path */
24 return false;
25
26 return strchr(p, '/');
27}
28
29int path_split_and_make_absolute(const char *p, char ***ret) {
30 _cleanup_strv_free_ char **l = NULL;
31 int r;
32
33 assert(p);
34 assert(ret);
35
36 l = strv_split(p, ":");
37 if (!l)
38 return -ENOMEM;
39
40 r = path_strv_make_absolute_cwd(l);
41 if (r < 0)
42 return r;
43
44 *ret = TAKE_PTR(l);
45 return r;
46}
47
48char* path_make_absolute(const char *p, const char *prefix) {
49 assert(p);
50
51 /* Makes every item in the list an absolute path by prepending
52 * the prefix, if specified and necessary */
53
54 if (path_is_absolute(p) || isempty(prefix))
55 return strdup(p);
56
57 return path_join(prefix, p);
58}
59
60int safe_getcwd(char **ret) {
61 _cleanup_free_ char *cwd = NULL;
62
63 cwd = get_current_dir_name();
64 if (!cwd)
65 return negative_errno();
66
67 /* Let's make sure the directory is really absolute, to protect us from the logic behind
68 * CVE-2018-1000001 */
69 if (cwd[0] != '/')
70 return -ENOMEDIUM;
71
72 if (ret)
73 *ret = TAKE_PTR(cwd);
74
75 return 0;
76}
77
78int path_make_absolute_cwd(const char *p, char **ret) {
79 char *c;
80 int r;
81
82 assert(p);
83 assert(ret);
84
85 /* Similar to path_make_absolute(), but prefixes with the
86 * current working directory. */
87
88 if (path_is_absolute(p))
89 c = strdup(p);
90 else {
91 _cleanup_free_ char *cwd = NULL;
92
93 r = safe_getcwd(&cwd);
94 if (r < 0)
95 return r;
96
97 c = path_join(cwd, p);
98 }
99 if (!c)
100 return -ENOMEM;
101
102 *ret = c;
103 return 0;
104}
105
106int path_make_relative(const char *from, const char *to, char **ret) {
107 _cleanup_free_ char *result = NULL;
108 unsigned n_parents;
109 const char *f, *t;
110 int r, k;
111 char *p;
112
113 assert(from);
114 assert(to);
115 assert(ret);
116
117 /* Strips the common part, and adds ".." elements as necessary. */
118
119 if (!path_is_absolute(from) || !path_is_absolute(to))
120 return -EINVAL;
121
122 for (;;) {
123 r = path_find_first_component(&from, true, &f);
124 if (r < 0)
125 return r;
126
127 k = path_find_first_component(&to, true, &t);
128 if (k < 0)
129 return k;
130
131 if (r == 0) {
132 /* end of 'from' */
133 if (k == 0) {
134 /* from and to are equivalent. */
135 result = strdup(".");
136 if (!result)
137 return -ENOMEM;
138 } else {
139 /* 'to' is inside of 'from'. */
140 r = path_simplify_alloc(t, &result);
141 if (r < 0)
142 return r;
143
144 if (!path_is_valid(result))
145 return -EINVAL;
146 }
147
148 *ret = TAKE_PTR(result);
149 return 0;
150 }
151
152 if (r != k || !strneq(f, t, r))
153 break;
154 }
155
156 /* If we're here, then "from_dir" has one or more elements that need to
157 * be replaced with "..". */
158
159 for (n_parents = 1;; n_parents++) {
160 /* If this includes ".." we can't do a simple series of "..". */
161 r = path_find_first_component(&from, false, &f);
162 if (r < 0)
163 return r;
164 if (r == 0)
165 break;
166 }
167
168 if (isempty(t) && n_parents * 3 > PATH_MAX)
169 /* PATH_MAX is counted *with* the trailing NUL byte */
170 return -EINVAL;
171
172 result = new(char, n_parents * 3 + !isempty(t) + strlen_ptr(t));
173 if (!result)
174 return -ENOMEM;
175
176 for (p = result; n_parents > 0; n_parents--)
177 p = mempcpy(p, "../", 3);
178
179 if (isempty(t)) {
180 /* Remove trailing slash and terminate string. */
181 *(--p) = '\0';
182 *ret = TAKE_PTR(result);
183 return 0;
184 }
185
186 strcpy(p, t);
187
188 path_simplify(result);
189
190 if (!path_is_valid(result))
191 return -EINVAL;
192
193 *ret = TAKE_PTR(result);
194 return 0;
195}
196
197int path_make_relative_parent(const char *from_child, const char *to, char **ret) {
198 _cleanup_free_ char *from = NULL;
199 int r;
200
201 assert(from_child);
202 assert(to);
203 assert(ret);
204
205 /* Similar to path_make_relative(), but provides the relative path from the parent directory of
206 * 'from_child'. This may be useful when creating relative symlink.
207 *
208 * E.g.
209 * - from = "/path/to/aaa", to = "/path/to/bbb"
210 * path_make_relative(from, to) = "../bbb"
211 * path_make_relative_parent(from, to) = "bbb"
212 *
213 * - from = "/path/to/aaa/bbb", to = "/path/to/ccc/ddd"
214 * path_make_relative(from, to) = "../../ccc/ddd"
215 * path_make_relative_parent(from, to) = "../ccc/ddd"
216 */
217
218 r = path_extract_directory(from_child, &from);
219 if (r < 0)
220 return r;
221
222 return path_make_relative(from, to, ret);
223}
224
225char* path_startswith_strv(const char *p, char * const *strv) {
226 assert(p);
227
228 STRV_FOREACH(s, strv) {
229 char *t;
230
231 t = path_startswith(p, *s);
232 if (t)
233 return t;
234 }
235
236 return NULL;
237}
238
239int path_strv_make_absolute_cwd(char **l) {
240 int r;
241
242 /* Goes through every item in the string list and makes it
243 * absolute. This works in place and won't rollback any
244 * changes on failure. */
245
246 STRV_FOREACH(s, l) {
247 char *t;
248
249 r = path_make_absolute_cwd(*s, &t);
250 if (r < 0)
251 return r;
252
253 path_simplify(t);
254 free_and_replace(*s, t);
255 }
256
257 return 0;
258}
259
260char** path_strv_resolve(char **l, const char *root) {
261 unsigned k = 0;
262 bool enomem = false;
263 int r;
264
265 if (strv_isempty(l))
266 return l;
267
268 /* Goes through every item in the string list and canonicalize
269 * the path. This works in place and won't rollback any
270 * changes on failure. */
271
272 STRV_FOREACH(s, l) {
273 _cleanup_free_ char *orig = NULL;
274 char *t, *u;
275
276 if (!path_is_absolute(*s)) {
277 free(*s);
278 continue;
279 }
280
281 if (root) {
282 orig = *s;
283 t = path_join(root, orig);
284 if (!t) {
285 enomem = true;
286 continue;
287 }
288 } else
289 t = *s;
290
291 r = chase(t, root, 0, &u, NULL);
292 if (r == -ENOENT) {
293 if (root) {
294 u = TAKE_PTR(orig);
295 free(t);
296 } else
297 u = t;
298 } else if (r < 0) {
299 free(t);
300
301 if (r == -ENOMEM)
302 enomem = true;
303
304 continue;
305 } else if (root) {
306 char *x;
307
308 free(t);
309 x = path_startswith(u, root);
310 if (x) {
311 /* restore the slash if it was lost */
312 if (!startswith(x, "/"))
313 *(--x) = '/';
314
315 t = strdup(x);
316 free(u);
317 if (!t) {
318 enomem = true;
319 continue;
320 }
321 u = t;
322 } else {
323 /* canonicalized path goes outside of
324 * prefix, keep the original path instead */
325 free_and_replace(u, orig);
326 }
327 } else
328 free(t);
329
330 l[k++] = u;
331 }
332
333 l[k] = NULL;
334
335 if (enomem)
336 return NULL;
337
338 return l;
339}
340
341char** path_strv_resolve_uniq(char **l, const char *root) {
342
343 if (strv_isempty(l))
344 return l;
345
346 if (!path_strv_resolve(l, root))
347 return NULL;
348
349 return strv_uniq(l);
350}
351
352char* skip_leading_slash(const char *p) {
353 return skip_leading_chars(p, "/");
354}
355
356char* path_simplify_full(char *path, PathSimplifyFlags flags) {
357 bool add_slash = false, keep_trailing_slash, absolute, beginning = true;
358 char *f = path;
359 int r;
360
361 /* Removes redundant inner and trailing slashes. Also removes unnecessary dots.
362 * Modifies the passed string in-place.
363 *
364 * ///foo//./bar/. becomes /foo/bar
365 * .//./foo//./bar/. becomes foo/bar
366 * /../foo/bar becomes /foo/bar
367 * /../foo/bar/.. becomes /foo/bar/..
368 */
369
370 if (isempty(path))
371 return path;
372
373 keep_trailing_slash = FLAGS_SET(flags, PATH_SIMPLIFY_KEEP_TRAILING_SLASH) && endswith(path, "/");
374
375 absolute = path_is_absolute(path);
376 f += absolute; /* Keep leading /, if present. */
377
378 for (const char *p = f;;) {
379 const char *e;
380
381 r = path_find_first_component(&p, true, &e);
382 if (r == 0)
383 break;
384
385 if (r > 0 && absolute && beginning && path_startswith(e, ".."))
386 /* If we're at the beginning of an absolute path, we can safely skip ".." */
387 continue;
388
389 beginning = false;
390
391 if (add_slash)
392 *f++ = '/';
393
394 if (r < 0) {
395 /* if path is invalid, then refuse to simplify the remaining part. */
396 memmove(f, p, strlen(p) + 1);
397 return path;
398 }
399
400 memmove(f, e, r);
401 f += r;
402
403 add_slash = true;
404 }
405
406 /* Special rule, if we stripped everything, we need a "." for the current directory. */
407 if (f == path)
408 *f++ = '.';
409
410 if (*(f-1) != '/' && keep_trailing_slash)
411 *f++ = '/';
412
413 *f = '\0';
414 return path;
415}
416
417int path_simplify_alloc(const char *path, char **ret) {
418 assert(ret);
419
420 if (!path) {
421 *ret = NULL;
422 return 0;
423 }
424
425 char *t = strdup(path);
426 if (!t)
427 return -ENOMEM;
428
429 *ret = path_simplify(t);
430 return 0;
431}
432
433char* path_startswith_full(const char *original_path, const char *prefix, PathStartWithFlags flags) {
434 assert(original_path);
435 assert(prefix);
436
437 /* Returns a pointer to the start of the first component after the parts matched by
438 * the prefix, iff
439 * - both paths are absolute or both paths are relative,
440 * and
441 * - each component in prefix in turn matches a component in path at the same position.
442 * An empty string will be returned when the prefix and path are equivalent.
443 *
444 * Returns NULL otherwise.
445 */
446
447 const char *path = original_path;
448
449 if ((path[0] == '/') != (prefix[0] == '/'))
450 return NULL;
451
452 for (;;) {
453 const char *p, *q;
454 int m, n;
455
456 m = path_find_first_component(&path, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &p);
457 if (m < 0)
458 return NULL;
459
460 n = path_find_first_component(&prefix, !FLAGS_SET(flags, PATH_STARTSWITH_REFUSE_DOT_DOT), &q);
461 if (n < 0)
462 return NULL;
463
464 if (n == 0) {
465 if (!p)
466 p = path;
467
468 if (FLAGS_SET(flags, PATH_STARTSWITH_RETURN_LEADING_SLASH)) {
469
470 if (p <= original_path)
471 return NULL;
472
473 p--;
474
475 if (*p != '/')
476 return NULL;
477 }
478
479 return (char*) p;
480 }
481
482 if (m != n)
483 return NULL;
484
485 if (!strneq(p, q, m))
486 return NULL;
487 }
488}
489
490int path_compare(const char *a, const char *b) {
491 int r;
492
493 /* Order NULL before non-NULL */
494 r = CMP(!!a, !!b);
495 if (r != 0)
496 return r;
497
498 /* A relative path and an absolute path must not compare as equal.
499 * Which one is sorted before the other does not really matter.
500 * Here a relative path is ordered before an absolute path. */
501 r = CMP(path_is_absolute(a), path_is_absolute(b));
502 if (r != 0)
503 return r;
504
505 for (;;) {
506 const char *aa, *bb;
507 int j, k;
508
509 j = path_find_first_component(&a, true, &aa);
510 k = path_find_first_component(&b, true, &bb);
511
512 if (j < 0 || k < 0) {
513 /* When one of paths is invalid, order invalid path after valid one. */
514 r = CMP(j < 0, k < 0);
515 if (r != 0)
516 return r;
517
518 /* fallback to use strcmp() if both paths are invalid. */
519 return strcmp(a, b);
520 }
521
522 /* Order prefixes first: "/foo" before "/foo/bar" */
523 if (j == 0) {
524 if (k == 0)
525 return 0;
526 return -1;
527 }
528 if (k == 0)
529 return 1;
530
531 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
532 r = memcmp(aa, bb, MIN(j, k));
533 if (r != 0)
534 return r;
535
536 /* Sort "/foo/a" before "/foo/aaa" */
537 r = CMP(j, k);
538 if (r != 0)
539 return r;
540 }
541}
542
543int path_compare_filename(const char *a, const char *b) {
544 _cleanup_free_ char *fa = NULL, *fb = NULL;
545 int r, j, k;
546
547 /* Order NULL before non-NULL */
548 r = CMP(!!a, !!b);
549 if (r != 0)
550 return r;
551
552 j = path_extract_filename(a, &fa);
553 k = path_extract_filename(b, &fb);
554
555 /* When one of paths is "." or root, then order it earlier. */
556 r = CMP(j != -EADDRNOTAVAIL, k != -EADDRNOTAVAIL);
557 if (r != 0)
558 return r;
559
560 /* When one of paths is invalid (or we get OOM), order invalid path after valid one. */
561 r = CMP(j < 0, k < 0);
562 if (r != 0)
563 return r;
564
565 /* fallback to use strcmp() if both paths are invalid. */
566 if (j < 0)
567 return strcmp(a, b);
568
569 return strcmp(fa, fb);
570}
571
572int path_equal_or_inode_same_full(const char *a, const char *b, int flags) {
573 /* Returns true if paths are of the same entry, false if not, <0 on error. */
574
575 if (path_equal(a, b))
576 return 1;
577
578 if (!a || !b)
579 return 0;
580
581 return inode_same(a, b, flags);
582}
583
584char* path_extend_internal(char **x, ...) {
585 size_t sz, old_sz;
586 char *q, *nx;
587 const char *p;
588 va_list ap;
589 bool slash;
590
591 /* Joins all listed strings until the sentinel and places a "/" between them unless the strings
592 * end/begin already with one so that it is unnecessary. Note that slashes which are already
593 * duplicate won't be removed. The string returned is hence always equal to or longer than the sum of
594 * the lengths of the individual strings.
595 *
596 * The first argument may be an already allocated string that is extended via realloc() if
597 * non-NULL. path_extend() and path_join() are macro wrappers around this function, making use of the
598 * first parameter to distinguish the two operations.
599 *
600 * Note: any listed empty string is simply skipped. This can be useful for concatenating strings of
601 * which some are optional.
602 *
603 * Examples:
604 *
605 * path_join("foo", "bar") → "foo/bar"
606 * path_join("foo/", "bar") → "foo/bar"
607 * path_join("", "foo", "", "bar", "") → "foo/bar" */
608
609 sz = old_sz = x ? strlen_ptr(*x) : 0;
610 va_start(ap, x);
611 while ((p = va_arg(ap, char*)) != POINTER_MAX) {
612 size_t add;
613
614 if (isempty(p))
615 continue;
616
617 add = 1 + strlen(p);
618 if (sz > SIZE_MAX - add) { /* overflow check */
619 va_end(ap);
620 return NULL;
621 }
622
623 sz += add;
624 }
625 va_end(ap);
626
627 nx = realloc(x ? *x : NULL, GREEDY_ALLOC_ROUND_UP(sz+1));
628 if (!nx)
629 return NULL;
630 if (x)
631 *x = nx;
632
633 if (old_sz > 0)
634 slash = nx[old_sz-1] == '/';
635 else {
636 nx[old_sz] = 0;
637 slash = true; /* no need to generate a slash anymore */
638 }
639
640 q = nx + old_sz;
641
642 va_start(ap, x);
643 while ((p = va_arg(ap, char*)) != POINTER_MAX) {
644 if (isempty(p))
645 continue;
646
647 if (!slash && p[0] != '/')
648 *(q++) = '/';
649
650 q = stpcpy(q, p);
651 slash = endswith(p, "/");
652 }
653 va_end(ap);
654
655 return nx;
656}
657
658int open_and_check_executable(const char *name, const char *root, char **ret_path, int *ret_fd) {
659 _cleanup_close_ int fd = -EBADF;
660 _cleanup_free_ char *resolved = NULL;
661 int r;
662
663 assert(name);
664
665 /* Function chase() is invoked only when root is not NULL, as using it regardless of
666 * root value would alter the behavior of existing callers for example: /bin/sleep would become
667 * /usr/bin/sleep when find_executables is called. Hence, this function should be invoked when
668 * needed to avoid unforeseen regression or other complicated changes. */
669 if (root) {
670 /* prefix root to name in case full paths are not specified */
671 r = chase(name, root, CHASE_PREFIX_ROOT, &resolved, &fd);
672 if (r < 0)
673 return r;
674
675 name = resolved;
676 } else {
677 /* We need to use O_PATH because there may be executables for which we have only exec permissions,
678 * but not read (usually suid executables). */
679 fd = open(name, O_PATH|O_CLOEXEC);
680 if (fd < 0)
681 return -errno;
682 }
683
684 r = fd_verify_regular(fd);
685 if (r < 0)
686 return r;
687
688 r = access_fd(fd, X_OK);
689 if (r == -ENOSYS)
690 /* /proc/ is not mounted. Fall back to access(). */
691 r = RET_NERRNO(access(name, X_OK));
692 if (r < 0)
693 return r;
694
695 if (ret_path) {
696 if (resolved)
697 *ret_path = TAKE_PTR(resolved);
698 else {
699 r = path_make_absolute_cwd(name, ret_path);
700 if (r < 0)
701 return r;
702
703 path_simplify(*ret_path);
704 }
705 }
706
707 if (ret_fd)
708 *ret_fd = TAKE_FD(fd);
709
710 return 0;
711}
712
713int find_executable_full(
714 const char *name,
715 const char *root,
716 char * const *exec_search_path,
717 bool use_path_envvar,
718 char **ret_filename,
719 int *ret_fd) {
720
721 int last_error = -ENOENT, r = 0;
722
723 assert(name);
724
725 if (is_path(name))
726 return open_and_check_executable(name, root, ret_filename, ret_fd);
727
728 if (exec_search_path) {
729 STRV_FOREACH(element, exec_search_path) {
730 _cleanup_free_ char *full_path = NULL;
731
732 if (!path_is_absolute(*element)) {
733 log_debug("Exec search path '%s' isn't absolute, ignoring.", *element);
734 continue;
735 }
736
737 full_path = path_join(*element, name);
738 if (!full_path)
739 return -ENOMEM;
740
741 r = open_and_check_executable(full_path, root, ret_filename, ret_fd);
742 if (r >= 0)
743 return 0;
744 if (r != -EACCES)
745 last_error = r;
746 }
747 return last_error;
748 }
749
750 const char *p = NULL;
751
752 if (use_path_envvar)
753 /* Plain getenv, not secure_getenv, because we want to actually allow the user to pick the
754 * binary. */
755 p = getenv("PATH");
756 if (!p)
757 p = default_PATH();
758
759 /* Resolve a single-component name to a full path */
760 for (;;) {
761 _cleanup_free_ char *element = NULL;
762
763 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
764 if (r < 0)
765 return r;
766 if (r == 0)
767 break;
768
769 if (!path_is_absolute(element)) {
770 log_debug("Exec search path '%s' isn't absolute, ignoring.", element);
771 continue;
772 }
773
774 if (!path_extend(&element, name))
775 return -ENOMEM;
776
777 r = open_and_check_executable(element, root, ret_filename, ret_fd);
778 if (r >= 0) /* Found it! */
779 return 0;
780 /* PATH entries which we don't have access to are ignored, as per tradition. */
781 if (r != -EACCES)
782 last_error = r;
783 }
784
785 return last_error;
786}
787
788bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
789 bool changed = false, originally_unset;
790
791 assert(timestamp);
792
793 if (!paths)
794 return false;
795
796 originally_unset = *timestamp == 0;
797
798 STRV_FOREACH(i, paths) {
799 struct stat stats;
800 usec_t u;
801
802 if (stat(*i, &stats) < 0)
803 continue;
804
805 u = timespec_load(&stats.st_mtim);
806
807 /* check first */
808 if (*timestamp >= u)
809 continue;
810
811 log_debug(originally_unset ? "Loaded timestamp for '%s'." : "Timestamp of '%s' changed.", *i);
812
813 /* update timestamp */
814 if (update) {
815 *timestamp = u;
816 changed = true;
817 } else
818 return true;
819 }
820
821 return changed;
822}
823
824static int executable_is_good(const char *executable) {
825 _cleanup_free_ char *p = NULL, *d = NULL;
826 int r;
827
828 r = find_executable(executable, &p);
829 if (r == -ENOENT)
830 return 0;
831 if (r < 0)
832 return r;
833
834 /* An fsck that is linked to /bin/true is a non-existent fsck */
835
836 r = readlink_malloc(p, &d);
837 if (r == -EINVAL) /* not a symlink */
838 return 1;
839 if (r < 0)
840 return r;
841
842 return !PATH_IN_SET(d, "true"
843 "/bin/true",
844 "/usr/bin/true",
845 "/dev/null");
846}
847
848int fsck_exists(void) {
849 return executable_is_good("fsck");
850}
851
852int fsck_exists_for_fstype(const char *fstype) {
853 const char *checker;
854 int r;
855
856 assert(fstype);
857
858 if (streq(fstype, "auto"))
859 return -EINVAL;
860
861 r = fsck_exists();
862 if (r <= 0)
863 return r;
864
865 checker = strjoina("fsck.", fstype);
866 return executable_is_good(checker);
867}
868
869static const char* skip_slash_or_dot(const char *p) {
870 for (; !isempty(p); p++) {
871 if (*p == '/')
872 continue;
873 if (startswith(p, "./")) {
874 p++;
875 continue;
876 }
877 break;
878 }
879 return p;
880}
881
882int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret) {
883 const char *q, *first, *end_first, *next;
884 size_t len;
885
886 assert(p);
887
888 /* When a path is input, then returns the pointer to the first component and its length, and
889 * move the input pointer to the next component or nul. This skips both over any '/'
890 * immediately *before* and *after* the first component before returning.
891 *
892 * Examples
893 * Input: p: "//.//aaa///bbbbb/cc"
894 * Output: p: "bbbbb///cc"
895 * ret: "aaa///bbbbb/cc"
896 * return value: 3 (== strlen("aaa"))
897 *
898 * Input: p: "aaa//"
899 * Output: p: (pointer to NUL)
900 * ret: "aaa//"
901 * return value: 3 (== strlen("aaa"))
902 *
903 * Input: p: "/", ".", ""
904 * Output: p: (pointer to NUL)
905 * ret: NULL
906 * return value: 0
907 *
908 * Input: p: NULL
909 * Output: p: NULL
910 * ret: NULL
911 * return value: 0
912 *
913 * Input: p: "(too long component)"
914 * Output: return value: -EINVAL
915 *
916 * (when accept_dot_dot is false)
917 * Input: p: "//..//aaa///bbbbb/cc"
918 * Output: return value: -EINVAL
919 */
920
921 q = *p;
922
923 first = skip_slash_or_dot(q);
924 if (isempty(first)) {
925 *p = first;
926 if (ret)
927 *ret = NULL;
928 return 0;
929 }
930 if (streq(first, ".")) {
931 *p = first + 1;
932 if (ret)
933 *ret = NULL;
934 return 0;
935 }
936
937 end_first = strchrnul(first, '/');
938 len = end_first - first;
939
940 if (len > NAME_MAX)
941 return -EINVAL;
942 if (!accept_dot_dot && len == 2 && first[0] == '.' && first[1] == '.')
943 return -EINVAL;
944
945 next = skip_slash_or_dot(end_first);
946
947 *p = next + streq(next, ".");
948 if (ret)
949 *ret = first;
950 return len;
951}
952
953static const char* skip_slash_or_dot_backward(const char *path, const char *q) {
954 assert(path);
955 assert(!q || q >= path);
956
957 for (; q; q = PTR_SUB1(q, path)) {
958 if (*q == '/')
959 continue;
960 if (q > path && strneq(q - 1, "/.", 2))
961 continue;
962 if (q == path && *q == '.')
963 continue;
964 break;
965 }
966 return q;
967}
968
969int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret) {
970 const char *q, *last_end, *last_begin;
971 size_t len;
972
973 /* Similar to path_find_first_component(), but search components from the end.
974 *
975 * Examples
976 * Input: path: "//.//aaa///bbbbb/cc//././"
977 * next: NULL
978 * Output: next: "/cc//././"
979 * ret: "cc//././"
980 * return value: 2 (== strlen("cc"))
981 *
982 * Input: path: "//.//aaa///bbbbb/cc//././"
983 * next: "/cc//././"
984 * Output: next: "///bbbbb/cc//././"
985 * ret: "bbbbb/cc//././"
986 * return value: 5 (== strlen("bbbbb"))
987 *
988 * Input: path: "//.//aaa///bbbbb/cc//././"
989 * next: "///bbbbb/cc//././"
990 * Output: next: "//.//aaa///bbbbb/cc//././" (next == path)
991 * ret: "aaa///bbbbb/cc//././"
992 * return value: 3 (== strlen("aaa"))
993 *
994 * Input: path: "/", ".", "", or NULL
995 * Output: next: equivalent to path
996 * ret: NULL
997 * return value: 0
998 *
999 * Input: path: "(too long component)"
1000 * Output: return value: -EINVAL
1001 *
1002 * (when accept_dot_dot is false)
1003 * Input: path: "//..//aaa///bbbbb/cc/..//"
1004 * Output: return value: -EINVAL
1005 */
1006
1007 if (isempty(path)) {
1008 if (next)
1009 *next = path;
1010 if (ret)
1011 *ret = NULL;
1012 return 0;
1013 }
1014
1015 if (next && *next) {
1016 if (*next < path || *next > path + strlen(path))
1017 return -EINVAL;
1018 if (*next == path) {
1019 if (ret)
1020 *ret = NULL;
1021 return 0;
1022 }
1023 if (!IN_SET(**next, '\0', '/'))
1024 return -EINVAL;
1025 q = *next - 1;
1026 } else
1027 q = path + strlen(path) - 1;
1028
1029 q = skip_slash_or_dot_backward(path, q);
1030 if (!q || /* the root directory */
1031 (q == path && *q == '.')) { /* path is "." or "./" */
1032 if (next)
1033 *next = path;
1034 if (ret)
1035 *ret = NULL;
1036 return 0;
1037 }
1038
1039 last_end = q + 1;
1040
1041 while (q && *q != '/')
1042 q = PTR_SUB1(q, path);
1043
1044 last_begin = q ? q + 1 : path;
1045 len = last_end - last_begin;
1046
1047 if (len > NAME_MAX)
1048 return -EINVAL;
1049 if (!accept_dot_dot && len == 2 && strneq(last_begin, "..", 2))
1050 return -EINVAL;
1051
1052 if (next) {
1053 q = skip_slash_or_dot_backward(path, q);
1054 *next = q ? q + 1 : path;
1055 }
1056
1057 if (ret)
1058 *ret = last_begin;
1059 return len;
1060}
1061
1062const char* last_path_component(const char *path) {
1063
1064 /* Finds the last component of the path, preserving the optional trailing slash that signifies a directory.
1065 *
1066 * a/b/c → c
1067 * a/b/c/ → c/
1068 * x → x
1069 * x/ → x/
1070 * /y → y
1071 * /y/ → y/
1072 * / → /
1073 * // → /
1074 * /foo/a → a
1075 * /foo/a/ → a/
1076 *
1077 * Also, the empty string is mapped to itself.
1078 *
1079 * This is different than basename(), which returns "" when a trailing slash is present.
1080 *
1081 * This always succeeds (except if you pass NULL in which case it returns NULL, too).
1082 */
1083
1084 unsigned l, k;
1085
1086 if (!path)
1087 return NULL;
1088
1089 l = k = strlen(path);
1090 if (l == 0) /* special case — an empty string */
1091 return path;
1092
1093 while (k > 0 && path[k-1] == '/')
1094 k--;
1095
1096 if (k == 0) /* the root directory */
1097 return path + l - 1;
1098
1099 while (k > 0 && path[k-1] != '/')
1100 k--;
1101
1102 return path + k;
1103}
1104
1105int path_extract_filename(const char *path, char **ret) {
1106 _cleanup_free_ char *a = NULL;
1107 const char *c, *next = NULL;
1108 int r;
1109
1110 /* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
1111 * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing
1112 * slashes. Returns:
1113 *
1114 * -EINVAL → if the path is not valid
1115 * -EADDRNOTAVAIL → if only a directory was specified, but no filename, i.e. the root dir
1116 * itself or "." is specified
1117 * -ENOMEM → no memory
1118 *
1119 * Returns >= 0 on success. If the input path has a trailing slash, returns O_DIRECTORY, to
1120 * indicate the referenced file must be a directory.
1121 *
1122 * This function guarantees to return a fully valid filename, i.e. one that passes
1123 * filename_is_valid() – this means "." and ".." are not accepted. */
1124
1125 if (!path_is_valid(path))
1126 return -EINVAL;
1127
1128 r = path_find_last_component(path, false, &next, &c);
1129 if (r < 0)
1130 return r;
1131 if (r == 0) /* root directory */
1132 return -EADDRNOTAVAIL;
1133
1134 a = strndup(c, r);
1135 if (!a)
1136 return -ENOMEM;
1137
1138 *ret = TAKE_PTR(a);
1139 return strlen(c) > (size_t) r ? O_DIRECTORY : 0;
1140}
1141
1142int path_extract_directory(const char *path, char **ret) {
1143 const char *c, *next = NULL;
1144 int r;
1145
1146 /* The inverse of path_extract_filename(), i.e. returns the directory path prefix. Returns:
1147 *
1148 * -EINVAL → if the path is not valid
1149 * -EDESTADDRREQ → if no directory was specified in the passed in path, i.e. only a filename was passed
1150 * -EADDRNOTAVAIL → if the passed in parameter had no filename but did have a directory, i.e.
1151 * the root dir itself or "." was specified
1152 * -ENOMEM → no memory (surprise!)
1153 *
1154 * This function guarantees to return a fully valid path, i.e. one that passes path_is_valid().
1155 */
1156
1157 r = path_find_last_component(path, false, &next, &c);
1158 if (r < 0)
1159 return r;
1160 if (r == 0) /* empty or root */
1161 return isempty(path) ? -EINVAL : -EADDRNOTAVAIL;
1162 if (next == path) {
1163 if (*path != '/') /* filename only */
1164 return -EDESTADDRREQ;
1165
1166 return strdup_to(ret, "/");
1167 }
1168
1169 _cleanup_free_ char *a = strndup(path, next - path);
1170 if (!a)
1171 return -ENOMEM;
1172
1173 path_simplify(a);
1174
1175 if (!path_is_valid(a))
1176 return -EINVAL;
1177
1178 if (ret)
1179 *ret = TAKE_PTR(a);
1180
1181 return 0;
1182}
1183
1184bool filename_part_is_valid(const char *p) {
1185 const char *e;
1186
1187 /* Checks f the specified string is OK to be *part* of a filename. This is different from
1188 * filename_is_valid() as "." and ".." and "" are OK by this call, but not by filename_is_valid(). */
1189
1190 if (!p)
1191 return false;
1192
1193 e = strchrnul(p, '/');
1194 if (*e != 0)
1195 return false;
1196
1197 if (e - p > NAME_MAX) /* NAME_MAX is counted *without* the trailing NUL byte */
1198 return false;
1199
1200 return true;
1201}
1202
1203bool filename_is_valid(const char *p) {
1204
1205 if (isempty(p))
1206 return false;
1207
1208 if (dot_or_dot_dot(p)) /* Yes, in this context we consider "." and ".." invalid */
1209 return false;
1210
1211 return filename_part_is_valid(p);
1212}
1213
1214bool path_is_valid_full(const char *p, bool accept_dot_dot) {
1215 if (isempty(p))
1216 return false;
1217
1218 for (const char *e = p;;) {
1219 int r;
1220
1221 r = path_find_first_component(&e, accept_dot_dot, NULL);
1222 if (r < 0)
1223 return false;
1224
1225 if (e - p >= PATH_MAX) /* Already reached the maximum length for a path? (PATH_MAX is counted
1226 * *with* the trailing NUL byte) */
1227 return false;
1228 if (*e == 0) /* End of string? Yay! */
1229 return true;
1230 }
1231}
1232
1233bool path_is_normalized(const char *p) {
1234 if (!path_is_safe(p))
1235 return false;
1236
1237 if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
1238 return false;
1239
1240 if (strstr(p, "//"))
1241 return false;
1242
1243 return true;
1244}
1245
1246int file_in_same_dir(const char *path, const char *filename, char **ret) {
1247 _cleanup_free_ char *b = NULL;
1248 int r;
1249
1250 assert(path);
1251 assert(filename);
1252 assert(ret);
1253
1254 /* This removes the last component of path and appends filename, unless the latter is absolute anyway
1255 * or the former isn't */
1256
1257 if (path_is_absolute(filename))
1258 b = strdup(filename);
1259 else {
1260 _cleanup_free_ char *dn = NULL;
1261
1262 r = path_extract_directory(path, &dn);
1263 if (r == -EDESTADDRREQ) /* no path prefix */
1264 b = strdup(filename);
1265 else if (r < 0)
1266 return r;
1267 else
1268 b = path_join(dn, filename);
1269 }
1270 if (!b)
1271 return -ENOMEM;
1272
1273 *ret = TAKE_PTR(b);
1274 return 0;
1275}
1276
1277bool hidden_or_backup_file(const char *filename) {
1278 assert(filename);
1279
1280 if (filename[0] == '.' ||
1281 STR_IN_SET(filename,
1282 "lost+found",
1283 "aquota.user",
1284 "aquota.group") ||
1285 endswith(filename, "~"))
1286 return true;
1287
1288 const char *dot = strrchr(filename, '.');
1289 if (!dot)
1290 return false;
1291
1292 /* Please, let's not add more entries to the list below. If external projects think it's a good idea
1293 * to come up with always new suffixes and that everybody else should just adjust to that, then it
1294 * really should be on them. Hence, in future, let's not add any more entries. Instead, let's ask
1295 * those packages to instead adopt one of the generic suffixes/prefixes for hidden files or backups,
1296 * possibly augmented with an additional string. Specifically: there's now:
1297 *
1298 * The generic suffixes "~" and ".bak" for backup files
1299 * The generic prefix "." for hidden files
1300 *
1301 * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old",
1302 * ".foopkg-dist" or so registered, let's refuse that and ask them to use ".foopkg.new",
1303 * ".foopkg.old" or ".foopkg~" instead.
1304 */
1305
1306 return STR_IN_SET(dot + 1,
1307 "rpmnew",
1308 "rpmsave",
1309 "rpmorig",
1310 "dpkg-old",
1311 "dpkg-new",
1312 "dpkg-tmp",
1313 "dpkg-dist",
1314 "dpkg-bak",
1315 "dpkg-backup",
1316 "dpkg-remove",
1317 "ucf-new",
1318 "ucf-old",
1319 "ucf-dist",
1320 "swp",
1321 "bak",
1322 "old",
1323 "new");
1324}
1325
1326bool is_device_path(const char *path) {
1327
1328 /* Returns true for paths that likely refer to a device, either by path in sysfs or to something in
1329 * /dev. This accepts any path that starts with /dev/ or /sys/ and has something after that prefix.
1330 * It does not actually resolve the path.
1331 *
1332 * Examples:
1333 * /dev/sda, /dev/sda/foo, /sys/class, /dev/.., /sys/.., /./dev/foo → yes.
1334 * /../dev/sda, /dev, /sys, /usr/path, /usr/../dev/sda → no.
1335 */
1336
1337 const char *p = PATH_STARTSWITH_SET(ASSERT_PTR(path), "/dev/", "/sys/");
1338 return !isempty(p);
1339}
1340
1341bool valid_device_node_path(const char *path) {
1342
1343 /* Some superficial checks whether the specified path is a valid device node path, all without
1344 * looking at the actual device node. */
1345
1346 if (!PATH_STARTSWITH_SET(path, "/dev/", "/run/systemd/inaccessible/"))
1347 return false;
1348
1349 if (endswith(path, "/")) /* can't be a device node if it ends in a slash */
1350 return false;
1351
1352 return path_is_normalized(path);
1353}
1354
1355bool valid_device_allow_pattern(const char *path) {
1356 assert(path);
1357
1358 /* Like valid_device_node_path(), but also allows full-subsystem expressions like those accepted by
1359 * DeviceAllow= and DeviceDeny=. */
1360
1361 if (STARTSWITH_SET(path, "block-", "char-"))
1362 return true;
1363
1364 return valid_device_node_path(path);
1365}
1366
1367bool dot_or_dot_dot(const char *path) {
1368 if (!path)
1369 return false;
1370 if (path[0] != '.')
1371 return false;
1372 if (path[1] == 0)
1373 return true;
1374 if (path[1] != '.')
1375 return false;
1376
1377 return path[2] == 0;
1378}
1379
1380bool path_implies_directory(const char *path) {
1381
1382 /* Sometimes, if we look at a path we already know it must refer to a directory, because it is
1383 * suffixed with a slash, or its last component is "." or ".." */
1384
1385 if (!path)
1386 return false;
1387
1388 if (dot_or_dot_dot(path))
1389 return true;
1390
1391 return ENDSWITH_SET(path, "/", "/.", "/..");
1392}
1393
1394bool empty_or_root(const char *path) {
1395
1396 /* For operations relative to some root directory, returns true if the specified root directory is
1397 * redundant, i.e. either / or NULL or the empty string or any equivalent. */
1398
1399 if (isempty(path))
1400 return true;
1401
1402 return path_equal(path, "/");
1403}
1404
1405const char* empty_to_root(const char *path) {
1406 return isempty(path) ? "/" : path;
1407}
1408
1409int empty_or_root_harder_to_null(const char **path) {
1410 int r;
1411
1412 assert(path);
1413
1414 /* This nullifies the input path when the path is empty or points to "/". */
1415
1416 if (empty_or_root(*path)) {
1417 *path = NULL;
1418 return 0;
1419 }
1420
1421 r = path_is_root(*path);
1422 if (r < 0)
1423 return r;
1424 if (r > 0)
1425 *path = NULL;
1426
1427 return 0;
1428}
1429
1430bool path_strv_contains(char * const *l, const char *path) {
1431 assert(path);
1432
1433 STRV_FOREACH(i, l)
1434 if (path_equal(*i, path))
1435 return true;
1436
1437 return false;
1438}
1439
1440bool prefixed_path_strv_contains(char * const *l, const char *path) {
1441 assert(path);
1442
1443 STRV_FOREACH(i, l) {
1444 const char *j = *i;
1445
1446 if (*j == '-')
1447 j++;
1448 if (*j == '+')
1449 j++;
1450
1451 if (path_equal(j, path))
1452 return true;
1453 }
1454
1455 return false;
1456}
1457
1458int path_glob_can_match(const char *pattern, const char *prefix, char **ret) {
1459 assert(pattern);
1460 assert(prefix);
1461
1462 for (const char *a = pattern, *b = prefix;;) {
1463 _cleanup_free_ char *g = NULL, *h = NULL;
1464 const char *p, *q;
1465 int r, s;
1466
1467 r = path_find_first_component(&a, /* accept_dot_dot = */ false, &p);
1468 if (r < 0)
1469 return r;
1470
1471 s = path_find_first_component(&b, /* accept_dot_dot = */ false, &q);
1472 if (s < 0)
1473 return s;
1474
1475 if (s == 0) {
1476 /* The pattern matches the prefix. */
1477 if (ret) {
1478 char *t;
1479
1480 t = path_join(prefix, p);
1481 if (!t)
1482 return -ENOMEM;
1483
1484 *ret = t;
1485 }
1486 return true;
1487 }
1488
1489 if (r == 0)
1490 break;
1491
1492 if (r == s && strneq(p, q, r))
1493 continue; /* common component. Check next. */
1494
1495 g = strndup(p, r);
1496 if (!g)
1497 return -ENOMEM;
1498
1499 if (!string_is_glob(g))
1500 break;
1501
1502 /* We found a glob component. Check if the glob pattern matches the prefix component. */
1503
1504 h = strndup(q, s);
1505 if (!h)
1506 return -ENOMEM;
1507
1508 r = fnmatch(g, h, 0);
1509 if (r == FNM_NOMATCH)
1510 break;
1511 if (r != 0) /* Failure to process pattern? */
1512 return -EINVAL;
1513 }
1514
1515 /* The pattern does not match the prefix. */
1516 if (ret)
1517 *ret = NULL;
1518 return false;
1519}
1520
1521const char* default_PATH(void) {
1522#if HAVE_SPLIT_BIN
1523 static int split = -1;
1524 int r;
1525
1526 /* Check whether /usr/sbin is not a symlink and return the appropriate $PATH.
1527 * On error fall back to the safe value with both directories as configured… */
1528
1529 if (split < 0)
1530 STRV_FOREACH_PAIR(bin, sbin, STRV_MAKE("/usr/bin", "/usr/sbin",
1531 "/usr/local/bin", "/usr/local/sbin")) {
1532 r = inode_same(*bin, *sbin, AT_NO_AUTOMOUNT);
1533 if (r > 0 || r == -ENOENT)
1534 continue;
1535 if (r < 0)
1536 log_debug_errno(r, "Failed to compare \"%s\" and \"%s\", using compat $PATH: %m",
1537 *bin, *sbin);
1538 split = true;
1539 break;
1540 }
1541 if (split < 0)
1542 split = false;
1543 if (split)
1544 return DEFAULT_PATH_WITH_SBIN;
1545#endif
1546 return DEFAULT_PATH_WITHOUT_SBIN;
1547}