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