]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/path-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010-2012 Lennart Poettering
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.
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.
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/>.
31 #include <sys/statvfs.h>
37 #include "path-util.h"
40 bool path_is_absolute(const char *p
) {
44 bool is_path(const char *p
) {
45 return !!strchr(p
, '/');
48 char *path_get_file_name(const char *p
) {
60 int path_get_parent(const char *path
, char **_r
) {
61 const char *e
, *a
= NULL
, *b
= NULL
, *p
;
71 for (e
= path
; *e
; e
++) {
73 if (!slash
&& *e
== '/') {
77 } else if (slash
&& *e
!= '/')
92 r
= strndup(path
, p
-path
);
101 char **path_split_and_make_absolute(const char *p
) {
105 if (!(l
= strv_split(p
, ":")))
108 if (!path_strv_make_absolute_cwd(l
)) {
116 char *path_make_absolute(const char *p
, const char *prefix
) {
119 /* Makes every item in the list an absolute path by prepending
120 * the prefix, if specified and necessary */
122 if (path_is_absolute(p
) || !prefix
)
125 return strjoin(prefix
, "/", p
, NULL
);
128 char *path_make_absolute_cwd(const char *p
) {
133 /* Similar to path_make_absolute(), but prefixes with the
134 * current working directory. */
136 if (path_is_absolute(p
))
139 cwd
= get_current_dir_name();
143 r
= path_make_absolute(p
, cwd
);
149 char **path_strv_make_absolute_cwd(char **l
) {
152 /* Goes through every item in the string list and makes it
153 * absolute. This works in place and won't rollback any
154 * changes on failure. */
159 if (!(t
= path_make_absolute_cwd(*s
)))
169 char **path_strv_canonicalize(char **l
) {
177 /* Goes through every item in the string list and canonicalize
178 * the path. This works in place and won't rollback any
179 * changes on failure. */
184 t
= path_make_absolute_cwd(*s
);
194 u
= canonicalize_file_name(t
);
200 if (errno
== ENOMEM
|| !errno
)
219 char **path_strv_canonicalize_uniq(char **l
) {
223 if (!path_strv_canonicalize(l
))
229 char *path_kill_slashes(char *path
) {
233 /* Removes redundant inner and trailing slashes. Modifies the
234 * passed string in-place.
236 * ///foo///bar/ becomes /foo/bar
239 for (f
= path
, t
= path
; *f
; f
++) {
254 /* Special rule, if we are talking of the root directory, a
255 trailing slash is good */
257 if (t
== path
&& slash
)
264 char* path_startswith(const char *path
, const char *prefix
) {
268 if ((path
[0] == '/') != (prefix
[0] == '/'))
274 path
+= strspn(path
, "/");
275 prefix
+= strspn(prefix
, "/");
283 a
= strcspn(path
, "/");
284 b
= strcspn(prefix
, "/");
289 if (memcmp(path
, prefix
, a
) != 0)
297 bool path_equal(const char *a
, const char *b
) {
301 if ((a
[0] == '/') != (b
[0] == '/'))
310 if (*a
== 0 && *b
== 0)
313 if (*a
== 0 || *b
== 0)
322 if (memcmp(a
, b
, j
) != 0)
330 int path_is_mount_point(const char *t
, bool allow_symlink
) {
333 struct file_handle
*h
;
334 int mount_id
, mount_id_parent
;
337 /* We are not actually interested in the file handles, but
338 * name_to_handle_at() also passes us the mount ID, hence use
339 * it but throw the handle away */
341 if (path_equal(t
, "/"))
344 h
= alloca(MAX_HANDLE_SZ
);
345 h
->handle_bytes
= MAX_HANDLE_SZ
;
347 r
= name_to_handle_at(AT_FDCWD
, t
, h
, &mount_id
, allow_symlink
? AT_SYMLINK_FOLLOW
: 0);
349 if (errno
== ENOSYS
|| errno
== ENOTSUP
)
350 /* This kernel or file system does not support
351 * name_to_handle_at(), hence fallback to the
352 * traditional stat() logic */
361 r
= path_get_parent(t
, &parent
);
365 h
->handle_bytes
= MAX_HANDLE_SZ
;
366 r
= name_to_handle_at(AT_FDCWD
, parent
, h
, &mount_id_parent
, 0);
370 /* The parent can't do name_to_handle_at() but the
371 * directory we are interested in can? If so, it must
372 * be a mount point */
373 if (errno
== ENOTSUP
)
379 return mount_id
!= mount_id_parent
;
394 r
= path_get_parent(t
, &parent
);
398 r
= lstat(parent
, &b
);
404 return a
.st_dev
!= b
.st_dev
;
407 int path_is_read_only_fs(const char *path
) {
412 if (statvfs(path
, &st
) < 0)
415 return !!(st
.f_flag
& ST_RDONLY
);
418 int path_is_os_tree(const char *path
) {
422 /* We use /etc/os-release as flag file if something is an OS */
424 p
= strappenda(path
, "/etc/os-release");
427 return r
< 0 ? 0 : 1;