]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/path-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / path-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010-2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 /* When we include libgen.h because we need dirname() we immediately
30 * undefine basename() since libgen.h defines it as a macro to the
31 * POSIX version which is really broken. We prefer GNU basename(). */
32 #include <libgen.h>
33 #undef basename
34
35 #include "alloc-util.h"
36 #include "extract-word.h"
37 #include "fs-util.h"
38 #include "glob-util.h"
39 #include "log.h"
40 #include "macro.h"
41 #include "missing.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "stat-util.h"
45 #include "string-util.h"
46 #include "strv.h"
47 #include "time-util.h"
48
49 bool path_is_absolute(const char *p) {
50 return p[0] == '/';
51 }
52
53 bool is_path(const char *p) {
54 return !!strchr(p, '/');
55 }
56
57 int path_split_and_make_absolute(const char *p, char ***ret) {
58 char **l;
59 int r;
60
61 assert(p);
62 assert(ret);
63
64 l = strv_split(p, ":");
65 if (!l)
66 return -ENOMEM;
67
68 r = path_strv_make_absolute_cwd(l);
69 if (r < 0) {
70 strv_free(l);
71 return r;
72 }
73
74 *ret = l;
75 return r;
76 }
77
78 char *path_make_absolute(const char *p, const char *prefix) {
79 assert(p);
80
81 /* Makes every item in the list an absolute path by prepending
82 * the prefix, if specified and necessary */
83
84 if (path_is_absolute(p) || !prefix)
85 return strdup(p);
86
87 return strjoin(prefix, "/", p);
88 }
89
90 int path_make_absolute_cwd(const char *p, char **ret) {
91 char *c;
92
93 assert(p);
94 assert(ret);
95
96 /* Similar to path_make_absolute(), but prefixes with the
97 * current working directory. */
98
99 if (path_is_absolute(p))
100 c = strdup(p);
101 else {
102 _cleanup_free_ char *cwd = NULL;
103
104 cwd = get_current_dir_name();
105 if (!cwd)
106 return negative_errno();
107
108 c = strjoin(cwd, "/", p);
109 }
110 if (!c)
111 return -ENOMEM;
112
113 *ret = c;
114 return 0;
115 }
116
117 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
118 char *r, *p;
119 unsigned n_parents;
120
121 assert(from_dir);
122 assert(to_path);
123 assert(_r);
124
125 /* Strips the common part, and adds ".." elements as necessary. */
126
127 if (!path_is_absolute(from_dir))
128 return -EINVAL;
129
130 if (!path_is_absolute(to_path))
131 return -EINVAL;
132
133 /* Skip the common part. */
134 for (;;) {
135 size_t a, b;
136
137 from_dir += strspn(from_dir, "/");
138 to_path += strspn(to_path, "/");
139
140 if (!*from_dir) {
141 if (!*to_path)
142 /* from_dir equals to_path. */
143 r = strdup(".");
144 else
145 /* from_dir is a parent directory of to_path. */
146 r = strdup(to_path);
147 if (!r)
148 return -ENOMEM;
149
150 path_kill_slashes(r);
151
152 *_r = r;
153 return 0;
154 }
155
156 if (!*to_path)
157 break;
158
159 a = strcspn(from_dir, "/");
160 b = strcspn(to_path, "/");
161
162 if (a != b)
163 break;
164
165 if (memcmp(from_dir, to_path, a) != 0)
166 break;
167
168 from_dir += a;
169 to_path += b;
170 }
171
172 /* If we're here, then "from_dir" has one or more elements that need to
173 * be replaced with "..". */
174
175 /* Count the number of necessary ".." elements. */
176 for (n_parents = 0;;) {
177 size_t w;
178
179 from_dir += strspn(from_dir, "/");
180
181 if (!*from_dir)
182 break;
183
184 w = strcspn(from_dir, "/");
185
186 /* If this includes ".." we can't do a simple series of "..", refuse */
187 if (w == 2 && from_dir[0] == '.' && from_dir[1] == '.')
188 return -EINVAL;
189
190 /* Count number of elements, except if they are "." */
191 if (w != 1 || from_dir[0] != '.')
192 n_parents++;
193
194 from_dir += w;
195 }
196
197 r = new(char, n_parents * 3 + strlen(to_path) + 1);
198 if (!r)
199 return -ENOMEM;
200
201 for (p = r; n_parents > 0; n_parents--)
202 p = mempcpy(p, "../", 3);
203
204 strcpy(p, to_path);
205 path_kill_slashes(r);
206
207 *_r = r;
208 return 0;
209 }
210
211 int path_strv_make_absolute_cwd(char **l) {
212 char **s;
213 int r;
214
215 /* Goes through every item in the string list and makes it
216 * absolute. This works in place and won't rollback any
217 * changes on failure. */
218
219 STRV_FOREACH(s, l) {
220 char *t;
221
222 r = path_make_absolute_cwd(*s, &t);
223 if (r < 0)
224 return r;
225
226 free(*s);
227 *s = t;
228 }
229
230 return 0;
231 }
232
233 char **path_strv_resolve(char **l, const char *root) {
234 char **s;
235 unsigned k = 0;
236 bool enomem = false;
237 int r;
238
239 if (strv_isempty(l))
240 return l;
241
242 /* Goes through every item in the string list and canonicalize
243 * the path. This works in place and won't rollback any
244 * changes on failure. */
245
246 STRV_FOREACH(s, l) {
247 _cleanup_free_ char *orig = NULL;
248 char *t, *u;
249
250 if (!path_is_absolute(*s)) {
251 free(*s);
252 continue;
253 }
254
255 if (root) {
256 orig = *s;
257 t = prefix_root(root, orig);
258 if (!t) {
259 enomem = true;
260 continue;
261 }
262 } else
263 t = *s;
264
265 r = chase_symlinks(t, root, 0, &u);
266 if (r == -ENOENT) {
267 if (root) {
268 u = orig;
269 orig = NULL;
270 free(t);
271 } else
272 u = t;
273 } else if (r < 0) {
274 free(t);
275
276 if (r == -ENOMEM)
277 enomem = true;
278
279 continue;
280 } else if (root) {
281 char *x;
282
283 free(t);
284 x = path_startswith(u, root);
285 if (x) {
286 /* restore the slash if it was lost */
287 if (!startswith(x, "/"))
288 *(--x) = '/';
289
290 t = strdup(x);
291 free(u);
292 if (!t) {
293 enomem = true;
294 continue;
295 }
296 u = t;
297 } else {
298 /* canonicalized path goes outside of
299 * prefix, keep the original path instead */
300 free_and_replace(u, orig);
301 }
302 } else
303 free(t);
304
305 l[k++] = u;
306 }
307
308 l[k] = NULL;
309
310 if (enomem)
311 return NULL;
312
313 return l;
314 }
315
316 char **path_strv_resolve_uniq(char **l, const char *root) {
317
318 if (strv_isempty(l))
319 return l;
320
321 if (!path_strv_resolve(l, root))
322 return NULL;
323
324 return strv_uniq(l);
325 }
326
327 char *path_kill_slashes(char *path) {
328 char *f, *t;
329 bool slash = false;
330
331 /* Removes redundant inner and trailing slashes. Modifies the
332 * passed string in-place.
333 *
334 * ///foo///bar/ becomes /foo/bar
335 */
336
337 for (f = path, t = path; *f; f++) {
338
339 if (*f == '/') {
340 slash = true;
341 continue;
342 }
343
344 if (slash) {
345 slash = false;
346 *(t++) = '/';
347 }
348
349 *(t++) = *f;
350 }
351
352 /* Special rule, if we are talking of the root directory, a
353 trailing slash is good */
354
355 if (t == path && slash)
356 *(t++) = '/';
357
358 *t = 0;
359 return path;
360 }
361
362 char* path_startswith(const char *path, const char *prefix) {
363 assert(path);
364 assert(prefix);
365
366 /* Returns a pointer to the start of the first component after the parts matched by
367 * the prefix, iff
368 * - both paths are absolute or both paths are relative,
369 * and
370 * - each component in prefix in turn matches a component in path at the same position.
371 * An empty string will be returned when the prefix and path are equivalent.
372 *
373 * Returns NULL otherwise.
374 */
375
376 if ((path[0] == '/') != (prefix[0] == '/'))
377 return NULL;
378
379 for (;;) {
380 size_t a, b;
381
382 path += strspn(path, "/");
383 prefix += strspn(prefix, "/");
384
385 if (*prefix == 0)
386 return (char*) path;
387
388 if (*path == 0)
389 return NULL;
390
391 a = strcspn(path, "/");
392 b = strcspn(prefix, "/");
393
394 if (a != b)
395 return NULL;
396
397 if (memcmp(path, prefix, a) != 0)
398 return NULL;
399
400 path += a;
401 prefix += b;
402 }
403 }
404
405 int path_compare(const char *a, const char *b) {
406 int d;
407
408 assert(a);
409 assert(b);
410
411 /* A relative path and an abolute path must not compare as equal.
412 * Which one is sorted before the other does not really matter.
413 * Here a relative path is ordered before an absolute path. */
414 d = (a[0] == '/') - (b[0] == '/');
415 if (d != 0)
416 return d;
417
418 for (;;) {
419 size_t j, k;
420
421 a += strspn(a, "/");
422 b += strspn(b, "/");
423
424 if (*a == 0 && *b == 0)
425 return 0;
426
427 /* Order prefixes first: "/foo" before "/foo/bar" */
428 if (*a == 0)
429 return -1;
430 if (*b == 0)
431 return 1;
432
433 j = strcspn(a, "/");
434 k = strcspn(b, "/");
435
436 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
437 d = memcmp(a, b, MIN(j, k));
438 if (d != 0)
439 return (d > 0) - (d < 0); /* sign of d */
440
441 /* Sort "/foo/a" before "/foo/aaa" */
442 d = (j > k) - (j < k); /* sign of (j - k) */
443 if (d != 0)
444 return d;
445
446 a += j;
447 b += k;
448 }
449 }
450
451 bool path_equal(const char *a, const char *b) {
452 return path_compare(a, b) == 0;
453 }
454
455 bool path_equal_or_files_same(const char *a, const char *b, int flags) {
456 return path_equal(a, b) || files_same(a, b, flags) > 0;
457 }
458
459 char* path_join(const char *root, const char *path, const char *rest) {
460 assert(path);
461
462 if (!isempty(root))
463 return strjoin(root, endswith(root, "/") ? "" : "/",
464 path[0] == '/' ? path+1 : path,
465 rest ? (endswith(path, "/") ? "" : "/") : NULL,
466 rest && rest[0] == '/' ? rest+1 : rest);
467 else
468 return strjoin(path,
469 rest ? (endswith(path, "/") ? "" : "/") : NULL,
470 rest && rest[0] == '/' ? rest+1 : rest);
471 }
472
473 int find_binary(const char *name, char **ret) {
474 int last_error, r;
475 const char *p;
476
477 assert(name);
478
479 if (is_path(name)) {
480 if (access(name, X_OK) < 0)
481 return -errno;
482
483 if (ret) {
484 r = path_make_absolute_cwd(name, ret);
485 if (r < 0)
486 return r;
487 }
488
489 return 0;
490 }
491
492 /**
493 * Plain getenv, not secure_getenv, because we want
494 * to actually allow the user to pick the binary.
495 */
496 p = getenv("PATH");
497 if (!p)
498 p = DEFAULT_PATH;
499
500 last_error = -ENOENT;
501
502 for (;;) {
503 _cleanup_free_ char *j = NULL, *element = NULL;
504
505 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
506 if (r < 0)
507 return r;
508 if (r == 0)
509 break;
510
511 if (!path_is_absolute(element))
512 continue;
513
514 j = strjoin(element, "/", name);
515 if (!j)
516 return -ENOMEM;
517
518 if (access(j, X_OK) >= 0) {
519 /* Found it! */
520
521 if (ret) {
522 *ret = path_kill_slashes(j);
523 j = NULL;
524 }
525
526 return 0;
527 }
528
529 last_error = -errno;
530 }
531
532 return last_error;
533 }
534
535 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
536 bool changed = false;
537 const char* const* i;
538
539 assert(timestamp);
540
541 if (paths == NULL)
542 return false;
543
544 STRV_FOREACH(i, paths) {
545 struct stat stats;
546 usec_t u;
547
548 if (stat(*i, &stats) < 0)
549 continue;
550
551 u = timespec_load(&stats.st_mtim);
552
553 /* first check */
554 if (*timestamp >= u)
555 continue;
556
557 log_debug("timestamp of '%s' changed", *i);
558
559 /* update timestamp */
560 if (update) {
561 *timestamp = u;
562 changed = true;
563 } else
564 return true;
565 }
566
567 return changed;
568 }
569
570 static int binary_is_good(const char *binary) {
571 _cleanup_free_ char *p = NULL, *d = NULL;
572 int r;
573
574 r = find_binary(binary, &p);
575 if (r == -ENOENT)
576 return 0;
577 if (r < 0)
578 return r;
579
580 /* An fsck that is linked to /bin/true is a non-existent
581 * fsck */
582
583 r = readlink_malloc(p, &d);
584 if (r == -EINVAL) /* not a symlink */
585 return 1;
586 if (r < 0)
587 return r;
588
589 return !PATH_IN_SET(d, "true"
590 "/bin/true",
591 "/usr/bin/true",
592 "/dev/null");
593 }
594
595 int fsck_exists(const char *fstype) {
596 const char *checker;
597
598 assert(fstype);
599
600 if (streq(fstype, "auto"))
601 return -EINVAL;
602
603 checker = strjoina("fsck.", fstype);
604 return binary_is_good(checker);
605 }
606
607 int mkfs_exists(const char *fstype) {
608 const char *mkfs;
609
610 assert(fstype);
611
612 if (streq(fstype, "auto"))
613 return -EINVAL;
614
615 mkfs = strjoina("mkfs.", fstype);
616 return binary_is_good(mkfs);
617 }
618
619 char *prefix_root(const char *root, const char *path) {
620 char *n, *p;
621 size_t l;
622
623 /* If root is passed, prefixes path with it. Otherwise returns
624 * it as is. */
625
626 assert(path);
627
628 /* First, drop duplicate prefixing slashes from the path */
629 while (path[0] == '/' && path[1] == '/')
630 path++;
631
632 if (isempty(root) || path_equal(root, "/"))
633 return strdup(path);
634
635 l = strlen(root) + 1 + strlen(path) + 1;
636
637 n = new(char, l);
638 if (!n)
639 return NULL;
640
641 p = stpcpy(n, root);
642
643 while (p > n && p[-1] == '/')
644 p--;
645
646 if (path[0] != '/')
647 *(p++) = '/';
648
649 strcpy(p, path);
650 return n;
651 }
652
653 int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
654 char *p;
655 int r;
656
657 /*
658 * This function is intended to be used in command line
659 * parsers, to handle paths that are passed in. It makes the
660 * path absolute, and reduces it to NULL if omitted or
661 * root (the latter optionally).
662 *
663 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
664 * SUCCESS! Hence, do not pass in uninitialized pointers.
665 */
666
667 if (isempty(path)) {
668 *arg = mfree(*arg);
669 return 0;
670 }
671
672 r = path_make_absolute_cwd(path, &p);
673 if (r < 0)
674 return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
675
676 path_kill_slashes(p);
677 if (suppress_root && path_equal(p, "/"))
678 p = mfree(p);
679
680 free(*arg);
681 *arg = p;
682 return 0;
683 }
684
685 char* dirname_malloc(const char *path) {
686 char *d, *dir, *dir2;
687
688 assert(path);
689
690 d = strdup(path);
691 if (!d)
692 return NULL;
693
694 dir = dirname(d);
695 assert(dir);
696
697 if (dir == d)
698 return d;
699
700 dir2 = strdup(dir);
701 free(d);
702
703 return dir2;
704 }
705
706 bool filename_is_valid(const char *p) {
707 const char *e;
708
709 if (isempty(p))
710 return false;
711
712 if (dot_or_dot_dot(p))
713 return false;
714
715 e = strchrnul(p, '/');
716 if (*e != 0)
717 return false;
718
719 if (e - p > FILENAME_MAX)
720 return false;
721
722 return true;
723 }
724
725 bool path_is_safe(const char *p) {
726
727 if (isempty(p))
728 return false;
729
730 if (dot_or_dot_dot(p))
731 return false;
732
733 if (startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
734 return false;
735
736 if (strlen(p)+1 > PATH_MAX)
737 return false;
738
739 /* The following two checks are not really dangerous, but hey, they still are confusing */
740 if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
741 return false;
742
743 if (strstr(p, "//"))
744 return false;
745
746 return true;
747 }
748
749 char *file_in_same_dir(const char *path, const char *filename) {
750 char *e, *ret;
751 size_t k;
752
753 assert(path);
754 assert(filename);
755
756 /* This removes the last component of path and appends
757 * filename, unless the latter is absolute anyway or the
758 * former isn't */
759
760 if (path_is_absolute(filename))
761 return strdup(filename);
762
763 e = strrchr(path, '/');
764 if (!e)
765 return strdup(filename);
766
767 k = strlen(filename);
768 ret = new(char, (e + 1 - path) + k + 1);
769 if (!ret)
770 return NULL;
771
772 memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1);
773 return ret;
774 }
775
776 bool hidden_or_backup_file(const char *filename) {
777 const char *p;
778
779 assert(filename);
780
781 if (filename[0] == '.' ||
782 streq(filename, "lost+found") ||
783 streq(filename, "aquota.user") ||
784 streq(filename, "aquota.group") ||
785 endswith(filename, "~"))
786 return true;
787
788 p = strrchr(filename, '.');
789 if (!p)
790 return false;
791
792 /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
793 * with always new suffixes and that everybody else should just adjust to that, then it really should be on
794 * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
795 * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
796 * string. Specifically: there's now:
797 *
798 * The generic suffixes "~" and ".bak" for backup files
799 * The generic prefix "." for hidden files
800 *
801 * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
802 * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
803 */
804
805 return STR_IN_SET(p + 1,
806 "rpmnew",
807 "rpmsave",
808 "rpmorig",
809 "dpkg-old",
810 "dpkg-new",
811 "dpkg-tmp",
812 "dpkg-dist",
813 "dpkg-bak",
814 "dpkg-backup",
815 "dpkg-remove",
816 "ucf-new",
817 "ucf-old",
818 "ucf-dist",
819 "swp",
820 "bak",
821 "old",
822 "new");
823 }
824
825 bool is_device_path(const char *path) {
826
827 /* Returns true on paths that refer to a device, either in
828 * sysfs or in /dev */
829
830 return path_startswith(path, "/dev/") ||
831 path_startswith(path, "/sys/");
832 }
833
834 bool is_deviceallow_pattern(const char *path) {
835 return path_startswith(path, "/dev/") ||
836 startswith(path, "block-") ||
837 startswith(path, "char-");
838 }
839
840 int systemd_installation_has_version(const char *root, unsigned minimal_version) {
841 const char *pattern;
842 int r;
843
844 /* Try to guess if systemd installation is later than the specified version. This
845 * is hacky and likely to yield false negatives, particularly if the installation
846 * is non-standard. False positives should be relatively rare.
847 */
848
849 NULSTR_FOREACH(pattern,
850 /* /lib works for systems without usr-merge, and for systems with a sane
851 * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
852 * for Gentoo which does a merge without making /lib a symlink.
853 */
854 "lib/systemd/libsystemd-shared-*.so\0"
855 "usr/lib/systemd/libsystemd-shared-*.so\0") {
856
857 _cleanup_strv_free_ char **names = NULL;
858 _cleanup_free_ char *path = NULL;
859 char *c, **name;
860
861 path = prefix_root(root, pattern);
862 if (!path)
863 return -ENOMEM;
864
865 r = glob_extend(&names, path);
866 if (r == -ENOENT)
867 continue;
868 if (r < 0)
869 return r;
870
871 assert_se((c = endswith(path, "*.so")));
872 *c = '\0'; /* truncate the glob part */
873
874 STRV_FOREACH(name, names) {
875 /* This is most likely to run only once, hence let's not optimize anything. */
876 char *t, *t2;
877 unsigned version;
878
879 t = startswith(*name, path);
880 if (!t)
881 continue;
882
883 t2 = endswith(t, ".so");
884 if (!t2)
885 continue;
886
887 t2[0] = '\0'; /* truncate the suffix */
888
889 r = safe_atou(t, &version);
890 if (r < 0) {
891 log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
892 continue;
893 }
894
895 log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
896 *name, version,
897 version >= minimal_version ? "OK" : "too old");
898 if (version >= minimal_version)
899 return true;
900 }
901 }
902
903 return false;
904 }
905
906 bool dot_or_dot_dot(const char *path) {
907 if (!path)
908 return false;
909 if (path[0] != '.')
910 return false;
911 if (path[1] == 0)
912 return true;
913 if (path[1] != '.')
914 return false;
915
916 return path[2] == 0;
917 }