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