]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/path-util.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / basic / path-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010-2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/statvfs.h>
28 #include <unistd.h>
29
30 #include "fileio.h"
31 #include "log.h"
32 #include "macro.h"
33 #include "missing.h"
34 #include "string-util.h"
35 #include "strv.h"
36 #include "util.h"
37 #include "path-util.h"
38
39 bool path_is_absolute(const char *p) {
40 return p[0] == '/';
41 }
42
43 bool is_path(const char *p) {
44 return !!strchr(p, '/');
45 }
46
47 int path_get_parent(const char *path, char **_r) {
48 const char *e, *a = NULL, *b = NULL, *p;
49 char *r;
50 bool slash = false;
51
52 assert(path);
53 assert(_r);
54
55 if (!*path)
56 return -EINVAL;
57
58 for (e = path; *e; e++) {
59
60 if (!slash && *e == '/') {
61 a = b;
62 b = e;
63 slash = true;
64 } else if (slash && *e != '/')
65 slash = false;
66 }
67
68 if (*(e-1) == '/')
69 p = a;
70 else
71 p = b;
72
73 if (!p)
74 return -EINVAL;
75
76 if (p == path)
77 r = strdup("/");
78 else
79 r = strndup(path, p-path);
80
81 if (!r)
82 return -ENOMEM;
83
84 *_r = r;
85 return 0;
86 }
87
88 int path_split_and_make_absolute(const char *p, char ***ret) {
89 char **l;
90 int r;
91
92 assert(p);
93 assert(ret);
94
95 l = strv_split(p, ":");
96 if (!l)
97 return NULL;
98
99 r = path_strv_make_absolute_cwd(l);
100 if (r < 0) {
101 strv_free(l);
102 return r;
103 }
104
105 *ret = l;
106 return r;
107 }
108
109 char *path_make_absolute(const char *p, const char *prefix) {
110 assert(p);
111
112 /* Makes every item in the list an absolute path by prepending
113 * the prefix, if specified and necessary */
114
115 if (path_is_absolute(p) || !prefix)
116 return strdup(p);
117
118 return strjoin(prefix, "/", p, NULL);
119 }
120
121 int path_make_absolute_cwd(const char *p, char **ret) {
122 char *c;
123
124 assert(p);
125 assert(ret);
126
127 /* Similar to path_make_absolute(), but prefixes with the
128 * current working directory. */
129
130 if (path_is_absolute(p))
131 c = strdup(p);
132 else {
133 _cleanup_free_ char *cwd = NULL;
134
135 cwd = get_current_dir_name();
136 if (!cwd)
137 return -errno;
138
139 c = strjoin(cwd, "/", p, NULL);
140 }
141 if (!c)
142 return -ENOMEM;
143
144 *ret = c;
145 return 0;
146 }
147
148 int path_make_relative(const char *from_dir, const char *to_path, char **_r) {
149 char *r, *p;
150 unsigned n_parents;
151
152 assert(from_dir);
153 assert(to_path);
154 assert(_r);
155
156 /* Strips the common part, and adds ".." elements as necessary. */
157
158 if (!path_is_absolute(from_dir))
159 return -EINVAL;
160
161 if (!path_is_absolute(to_path))
162 return -EINVAL;
163
164 /* Skip the common part. */
165 for (;;) {
166 size_t a;
167 size_t b;
168
169 from_dir += strspn(from_dir, "/");
170 to_path += strspn(to_path, "/");
171
172 if (!*from_dir) {
173 if (!*to_path)
174 /* from_dir equals to_path. */
175 r = strdup(".");
176 else
177 /* from_dir is a parent directory of to_path. */
178 r = strdup(to_path);
179
180 if (!r)
181 return -ENOMEM;
182
183 path_kill_slashes(r);
184
185 *_r = r;
186 return 0;
187 }
188
189 if (!*to_path)
190 break;
191
192 a = strcspn(from_dir, "/");
193 b = strcspn(to_path, "/");
194
195 if (a != b)
196 break;
197
198 if (memcmp(from_dir, to_path, a) != 0)
199 break;
200
201 from_dir += a;
202 to_path += b;
203 }
204
205 /* If we're here, then "from_dir" has one or more elements that need to
206 * be replaced with "..". */
207
208 /* Count the number of necessary ".." elements. */
209 for (n_parents = 0;;) {
210 from_dir += strspn(from_dir, "/");
211
212 if (!*from_dir)
213 break;
214
215 from_dir += strcspn(from_dir, "/");
216 n_parents++;
217 }
218
219 r = malloc(n_parents * 3 + strlen(to_path) + 1);
220 if (!r)
221 return -ENOMEM;
222
223 for (p = r; n_parents > 0; n_parents--, p += 3)
224 memcpy(p, "../", 3);
225
226 strcpy(p, to_path);
227 path_kill_slashes(r);
228
229 *_r = r;
230 return 0;
231 }
232
233 int path_strv_make_absolute_cwd(char **l) {
234 char **s;
235 int r;
236
237 /* Goes through every item in the string list and makes it
238 * absolute. This works in place and won't rollback any
239 * changes on failure. */
240
241 STRV_FOREACH(s, l) {
242 char *t;
243
244 r = path_make_absolute_cwd(*s, &t);
245 if (r < 0)
246 return r;
247
248 free(*s);
249 *s = t;
250 }
251
252 return 0;
253 }
254
255 char **path_strv_resolve(char **l, const char *prefix) {
256 char **s;
257 unsigned k = 0;
258 bool enomem = false;
259
260 if (strv_isempty(l))
261 return l;
262
263 /* Goes through every item in the string list and canonicalize
264 * the path. This works in place and won't rollback any
265 * changes on failure. */
266
267 STRV_FOREACH(s, l) {
268 char *t, *u;
269 _cleanup_free_ char *orig = NULL;
270
271 if (!path_is_absolute(*s)) {
272 free(*s);
273 continue;
274 }
275
276 if (prefix) {
277 orig = *s;
278 t = strappend(prefix, orig);
279 if (!t) {
280 enomem = true;
281 continue;
282 }
283 } else
284 t = *s;
285
286 errno = 0;
287 u = canonicalize_file_name(t);
288 if (!u) {
289 if (errno == ENOENT) {
290 if (prefix) {
291 u = orig;
292 orig = NULL;
293 free(t);
294 } else
295 u = t;
296 } else {
297 free(t);
298 if (errno == ENOMEM || errno == 0)
299 enomem = true;
300
301 continue;
302 }
303 } else if (prefix) {
304 char *x;
305
306 free(t);
307 x = path_startswith(u, prefix);
308 if (x) {
309 /* restore the slash if it was lost */
310 if (!startswith(x, "/"))
311 *(--x) = '/';
312
313 t = strdup(x);
314 free(u);
315 if (!t) {
316 enomem = true;
317 continue;
318 }
319 u = t;
320 } else {
321 /* canonicalized path goes outside of
322 * prefix, keep the original path instead */
323 free(u);
324 u = orig;
325 orig = NULL;
326 }
327 } else
328 free(t);
329
330 l[k++] = u;
331 }
332
333 l[k] = NULL;
334
335 if (enomem)
336 return NULL;
337
338 return l;
339 }
340
341 char **path_strv_resolve_uniq(char **l, const char *prefix) {
342
343 if (strv_isempty(l))
344 return l;
345
346 if (!path_strv_resolve(l, prefix))
347 return NULL;
348
349 return strv_uniq(l);
350 }
351
352 char *path_kill_slashes(char *path) {
353 char *f, *t;
354 bool slash = false;
355
356 /* Removes redundant inner and trailing slashes. Modifies the
357 * passed string in-place.
358 *
359 * ///foo///bar/ becomes /foo/bar
360 */
361
362 for (f = path, t = path; *f; f++) {
363
364 if (*f == '/') {
365 slash = true;
366 continue;
367 }
368
369 if (slash) {
370 slash = false;
371 *(t++) = '/';
372 }
373
374 *(t++) = *f;
375 }
376
377 /* Special rule, if we are talking of the root directory, a
378 trailing slash is good */
379
380 if (t == path && slash)
381 *(t++) = '/';
382
383 *t = 0;
384 return path;
385 }
386
387 char* path_startswith(const char *path, const char *prefix) {
388 assert(path);
389 assert(prefix);
390
391 if ((path[0] == '/') != (prefix[0] == '/'))
392 return NULL;
393
394 for (;;) {
395 size_t a, b;
396
397 path += strspn(path, "/");
398 prefix += strspn(prefix, "/");
399
400 if (*prefix == 0)
401 return (char*) path;
402
403 if (*path == 0)
404 return NULL;
405
406 a = strcspn(path, "/");
407 b = strcspn(prefix, "/");
408
409 if (a != b)
410 return NULL;
411
412 if (memcmp(path, prefix, a) != 0)
413 return NULL;
414
415 path += a;
416 prefix += b;
417 }
418 }
419
420 int path_compare(const char *a, const char *b) {
421 int d;
422
423 assert(a);
424 assert(b);
425
426 /* A relative path and an abolute path must not compare as equal.
427 * Which one is sorted before the other does not really matter.
428 * Here a relative path is ordered before an absolute path. */
429 d = (a[0] == '/') - (b[0] == '/');
430 if (d)
431 return d;
432
433 for (;;) {
434 size_t j, k;
435
436 a += strspn(a, "/");
437 b += strspn(b, "/");
438
439 if (*a == 0 && *b == 0)
440 return 0;
441
442 /* Order prefixes first: "/foo" before "/foo/bar" */
443 if (*a == 0)
444 return -1;
445 if (*b == 0)
446 return 1;
447
448 j = strcspn(a, "/");
449 k = strcspn(b, "/");
450
451 /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
452 d = memcmp(a, b, MIN(j, k));
453 if (d)
454 return (d > 0) - (d < 0); /* sign of d */
455
456 /* Sort "/foo/a" before "/foo/aaa" */
457 d = (j > k) - (j < k); /* sign of (j - k) */
458 if (d)
459 return d;
460
461 a += j;
462 b += k;
463 }
464 }
465
466 bool path_equal(const char *a, const char *b) {
467 return path_compare(a, b) == 0;
468 }
469
470 bool path_equal_or_files_same(const char *a, const char *b) {
471 return path_equal(a, b) || files_same(a, b) > 0;
472 }
473
474 char* path_join(const char *root, const char *path, const char *rest) {
475 assert(path);
476
477 if (!isempty(root))
478 return strjoin(root, endswith(root, "/") ? "" : "/",
479 path[0] == '/' ? path+1 : path,
480 rest ? (endswith(path, "/") ? "" : "/") : NULL,
481 rest && rest[0] == '/' ? rest+1 : rest,
482 NULL);
483 else
484 return strjoin(path,
485 rest ? (endswith(path, "/") ? "" : "/") : NULL,
486 rest && rest[0] == '/' ? rest+1 : rest,
487 NULL);
488 }
489
490 static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
491 char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
492 _cleanup_free_ char *fdinfo = NULL;
493 _cleanup_close_ int subfd = -1;
494 char *p;
495 int r;
496
497 if ((flags & AT_EMPTY_PATH) && isempty(filename))
498 xsprintf(path, "/proc/self/fdinfo/%i", fd);
499 else {
500 subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
501 if (subfd < 0)
502 return -errno;
503
504 xsprintf(path, "/proc/self/fdinfo/%i", subfd);
505 }
506
507 r = read_full_file(path, &fdinfo, NULL);
508 if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
509 return -EOPNOTSUPP;
510 if (r < 0)
511 return -errno;
512
513 p = startswith(fdinfo, "mnt_id:");
514 if (!p) {
515 p = strstr(fdinfo, "\nmnt_id:");
516 if (!p) /* The mnt_id field is a relatively new addition */
517 return -EOPNOTSUPP;
518
519 p += 8;
520 }
521
522 p += strspn(p, WHITESPACE);
523 p[strcspn(p, WHITESPACE)] = 0;
524
525 return safe_atoi(p, mnt_id);
526 }
527
528 int fd_is_mount_point(int fd, const char *filename, int flags) {
529 union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
530 int mount_id = -1, mount_id_parent = -1;
531 bool nosupp = false, check_st_dev = true;
532 struct stat a, b;
533 int r;
534
535 assert(fd >= 0);
536 assert(filename);
537
538 /* First we will try the name_to_handle_at() syscall, which
539 * tells us the mount id and an opaque file "handle". It is
540 * not supported everywhere though (kernel compile-time
541 * option, not all file systems are hooked up). If it works
542 * the mount id is usually good enough to tell us whether
543 * something is a mount point.
544 *
545 * If that didn't work we will try to read the mount id from
546 * /proc/self/fdinfo/<fd>. This is almost as good as
547 * name_to_handle_at(), however, does not return the
548 * opaque file handle. The opaque file handle is pretty useful
549 * to detect the root directory, which we should always
550 * consider a mount point. Hence we use this only as
551 * fallback. Exporting the mnt_id in fdinfo is a pretty recent
552 * kernel addition.
553 *
554 * As last fallback we do traditional fstat() based st_dev
555 * comparisons. This is how things were traditionally done,
556 * but unionfs breaks breaks this since it exposes file
557 * systems with a variety of st_dev reported. Also, btrfs
558 * subvolumes have different st_dev, even though they aren't
559 * real mounts of their own. */
560
561 r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
562 if (r < 0) {
563 if (errno == ENOSYS)
564 /* This kernel does not support name_to_handle_at()
565 * fall back to simpler logic. */
566 goto fallback_fdinfo;
567 else if (errno == EOPNOTSUPP)
568 /* This kernel or file system does not support
569 * name_to_handle_at(), hence let's see if the
570 * upper fs supports it (in which case it is a
571 * mount point), otherwise fallback to the
572 * traditional stat() logic */
573 nosupp = true;
574 else
575 return -errno;
576 }
577
578 r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
579 if (r < 0) {
580 if (errno == EOPNOTSUPP) {
581 if (nosupp)
582 /* Neither parent nor child do name_to_handle_at()?
583 We have no choice but to fall back. */
584 goto fallback_fdinfo;
585 else
586 /* The parent can't do name_to_handle_at() but the
587 * directory we are interested in can?
588 * If so, it must be a mount point. */
589 return 1;
590 } else
591 return -errno;
592 }
593
594 /* The parent can do name_to_handle_at() but the
595 * directory we are interested in can't? If so, it
596 * must be a mount point. */
597 if (nosupp)
598 return 1;
599
600 /* If the file handle for the directory we are
601 * interested in and its parent are identical, we
602 * assume this is the root directory, which is a mount
603 * point. */
604
605 if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
606 h.handle.handle_type == h_parent.handle.handle_type &&
607 memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
608 return 1;
609
610 return mount_id != mount_id_parent;
611
612 fallback_fdinfo:
613 r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
614 if (r == -EOPNOTSUPP)
615 goto fallback_fstat;
616 if (r < 0)
617 return r;
618
619 r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
620 if (r < 0)
621 return r;
622
623 if (mount_id != mount_id_parent)
624 return 1;
625
626 /* Hmm, so, the mount ids are the same. This leaves one
627 * special case though for the root file system. For that,
628 * let's see if the parent directory has the same inode as we
629 * are interested in. Hence, let's also do fstat() checks now,
630 * too, but avoid the st_dev comparisons, since they aren't
631 * that useful on unionfs mounts. */
632 check_st_dev = false;
633
634 fallback_fstat:
635 /* yay for fstatat() taking a different set of flags than the other
636 * _at() above */
637 if (flags & AT_SYMLINK_FOLLOW)
638 flags &= ~AT_SYMLINK_FOLLOW;
639 else
640 flags |= AT_SYMLINK_NOFOLLOW;
641 if (fstatat(fd, filename, &a, flags) < 0)
642 return -errno;
643
644 if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
645 return -errno;
646
647 /* A directory with same device and inode as its parent? Must
648 * be the root directory */
649 if (a.st_dev == b.st_dev &&
650 a.st_ino == b.st_ino)
651 return 1;
652
653 return check_st_dev && (a.st_dev != b.st_dev);
654 }
655
656 /* flags can be AT_SYMLINK_FOLLOW or 0 */
657 int path_is_mount_point(const char *t, int flags) {
658 _cleanup_close_ int fd = -1;
659 _cleanup_free_ char *canonical = NULL, *parent = NULL;
660 int r;
661
662 assert(t);
663
664 if (path_equal(t, "/"))
665 return 1;
666
667 /* we need to resolve symlinks manually, we can't just rely on
668 * fd_is_mount_point() to do that for us; if we have a structure like
669 * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
670 * look at needs to be /usr, not /. */
671 if (flags & AT_SYMLINK_FOLLOW) {
672 canonical = canonicalize_file_name(t);
673 if (!canonical)
674 return -errno;
675
676 t = canonical;
677 }
678
679 r = path_get_parent(t, &parent);
680 if (r < 0)
681 return r;
682
683 fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
684 if (fd < 0)
685 return -errno;
686
687 return fd_is_mount_point(fd, basename(t), flags);
688 }
689
690 int path_is_read_only_fs(const char *path) {
691 struct statvfs st;
692
693 assert(path);
694
695 if (statvfs(path, &st) < 0)
696 return -errno;
697
698 if (st.f_flag & ST_RDONLY)
699 return true;
700
701 /* On NFS, statvfs() might not reflect whether we can actually
702 * write to the remote share. Let's try again with
703 * access(W_OK) which is more reliable, at least sometimes. */
704 if (access(path, W_OK) < 0 && errno == EROFS)
705 return true;
706
707 return false;
708 }
709
710 int path_is_os_tree(const char *path) {
711 char *p;
712 int r;
713
714 /* We use /usr/lib/os-release as flag file if something is an OS */
715 p = strjoina(path, "/usr/lib/os-release");
716 r = access(p, F_OK);
717 if (r >= 0)
718 return 1;
719
720 /* Also check for the old location in /etc, just in case. */
721 p = strjoina(path, "/etc/os-release");
722 r = access(p, F_OK);
723
724 return r >= 0;
725 }
726
727 int find_binary(const char *name, char **ret) {
728 int last_error, r;
729 const char *p;
730
731 assert(name);
732
733 if (is_path(name)) {
734 if (access(name, X_OK) < 0)
735 return -errno;
736
737 if (ret) {
738 r = path_make_absolute_cwd(name, ret);
739 if (r < 0)
740 return r;
741 }
742
743 return 0;
744 }
745
746 /**
747 * Plain getenv, not secure_getenv, because we want
748 * to actually allow the user to pick the binary.
749 */
750 p = getenv("PATH");
751 if (!p)
752 p = DEFAULT_PATH;
753
754 last_error = -ENOENT;
755
756 for (;;) {
757 _cleanup_free_ char *j = NULL, *element = NULL;
758
759 r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS);
760 if (r < 0)
761 return r;
762 if (r == 0)
763 break;
764
765 if (!path_is_absolute(element))
766 continue;
767
768 j = strjoin(element, "/", name, NULL);
769 if (!j)
770 return -ENOMEM;
771
772 if (access(j, X_OK) >= 0) {
773 /* Found it! */
774
775 if (ret) {
776 *ret = path_kill_slashes(j);
777 j = NULL;
778 }
779
780 return 0;
781 }
782
783 last_error = -errno;
784 }
785
786 return last_error;
787 }
788
789 bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
790 bool changed = false;
791 const char* const* i;
792
793 assert(timestamp);
794
795 if (paths == NULL)
796 return false;
797
798 STRV_FOREACH(i, paths) {
799 struct stat stats;
800 usec_t u;
801
802 if (stat(*i, &stats) < 0)
803 continue;
804
805 u = timespec_load(&stats.st_mtim);
806
807 /* first check */
808 if (*timestamp >= u)
809 continue;
810
811 log_debug("timestamp of '%s' changed", *i);
812
813 /* update timestamp */
814 if (update) {
815 *timestamp = u;
816 changed = true;
817 } else
818 return true;
819 }
820
821 return changed;
822 }
823
824 static int binary_is_good(const char *binary) {
825 _cleanup_free_ char *p = NULL, *d = NULL;
826 int r;
827
828 r = find_binary(binary, &p);
829 if (r == -ENOENT)
830 return 0;
831 if (r < 0)
832 return r;
833
834 /* An fsck that is linked to /bin/true is a non-existent
835 * fsck */
836
837 r = readlink_malloc(p, &d);
838 if (r == -EINVAL) /* not a symlink */
839 return 1;
840 if (r < 0)
841 return r;
842
843 return !path_equal(d, "true") &&
844 !path_equal(d, "/bin/true") &&
845 !path_equal(d, "/usr/bin/true") &&
846 !path_equal(d, "/dev/null");
847 }
848
849 int fsck_exists(const char *fstype) {
850 const char *checker;
851
852 assert(fstype);
853
854 if (streq(fstype, "auto"))
855 return -EINVAL;
856
857 checker = strjoina("fsck.", fstype);
858 return binary_is_good(checker);
859 }
860
861 int mkfs_exists(const char *fstype) {
862 const char *mkfs;
863
864 assert(fstype);
865
866 if (streq(fstype, "auto"))
867 return -EINVAL;
868
869 mkfs = strjoina("mkfs.", fstype);
870 return binary_is_good(mkfs);
871 }
872
873 char *prefix_root(const char *root, const char *path) {
874 char *n, *p;
875 size_t l;
876
877 /* If root is passed, prefixes path with it. Otherwise returns
878 * it as is. */
879
880 assert(path);
881
882 /* First, drop duplicate prefixing slashes from the path */
883 while (path[0] == '/' && path[1] == '/')
884 path++;
885
886 if (isempty(root) || path_equal(root, "/"))
887 return strdup(path);
888
889 l = strlen(root) + 1 + strlen(path) + 1;
890
891 n = new(char, l);
892 if (!n)
893 return NULL;
894
895 p = stpcpy(n, root);
896
897 while (p > n && p[-1] == '/')
898 p--;
899
900 if (path[0] != '/')
901 *(p++) = '/';
902
903 strcpy(p, path);
904 return n;
905 }
906
907 int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) {
908 char *p;
909 int r;
910
911 /*
912 * This function is intended to be used in command line
913 * parsers, to handle paths that are passed in. It makes the
914 * path absolute, and reduces it to NULL if omitted or
915 * root (the latter optionally).
916 *
917 * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON
918 * SUCCESS! Hence, do not pass in uninitialized pointers.
919 */
920
921 if (isempty(path)) {
922 *arg = mfree(*arg);
923 return 0;
924 }
925
926 r = path_make_absolute_cwd(path, &p);
927 if (r < 0)
928 return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path);
929
930 path_kill_slashes(p);
931 if (suppress_root && path_equal(p, "/"))
932 p = mfree(p);
933
934 free(*arg);
935 *arg = p;
936 return 0;
937 }