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