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