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) {
53 if ((r = strrchr(p, '/')))
59 int path_get_parent(const char *path, char **_r) {
60 const char *e, *a = NULL, *b = NULL, *p;
70 for (e = path; *e; e++) {
72 if (!slash && *e == '/') {
76 } else if (slash && *e != '/')
91 r = strndup(path, p-path);
100 char **path_split_and_make_absolute(const char *p) {
104 if (!(l = strv_split(p, ":")))
107 if (!path_strv_make_absolute_cwd(l)) {
115 char *path_make_absolute(const char *p, const char *prefix) {
118 /* Makes every item in the list an absolute path by prepending
119 * the prefix, if specified and necessary */
121 if (path_is_absolute(p) || !prefix)
124 return strjoin(prefix, "/", p, NULL);
127 char *path_make_absolute_cwd(const char *p) {
132 /* Similar to path_make_absolute(), but prefixes with the
133 * current working directory. */
135 if (path_is_absolute(p))
138 if (!(cwd = get_current_dir_name()))
141 r = path_make_absolute(p, cwd);
147 char **path_strv_make_absolute_cwd(char **l) {
150 /* Goes through every item in the string list and makes it
151 * absolute. This works in place and won't rollback any
152 * changes on failure. */
157 if (!(t = path_make_absolute_cwd(*s)))
167 char **path_strv_canonicalize(char **l) {
175 /* Goes through every item in the string list and canonicalize
176 * the path. This works in place and won't rollback any
177 * changes on failure. */
182 t = path_make_absolute_cwd(*s);
191 u = canonicalize_file_name(t);
195 if (errno == ENOMEM || !errno)
212 char **path_strv_remove_empty(char **l) {
218 for (f = t = l; *f; f++) {
220 if (dir_is_empty(*f) > 0) {
232 char *path_kill_slashes(char *path) {
236 /* Removes redundant inner and trailing slashes. Modifies the
237 * passed string in-place.
239 * ///foo///bar/ becomes /foo/bar
242 for (f = path, t = path; *f; f++) {
257 /* Special rule, if we are talking of the root directory, a
258 trailing slash is good */
260 if (t == path && slash)
267 char* path_startswith(const char *path, const char *prefix) {
271 if ((path[0] == '/') != (prefix[0] == '/'))
277 path += strspn(path, "/");
278 prefix += strspn(prefix, "/");
286 a = strcspn(path, "/");
287 b = strcspn(prefix, "/");
292 if (memcmp(path, prefix, a) != 0)
300 bool path_equal(const char *a, const char *b) {
304 if ((a[0] == '/') != (b[0] == '/'))
313 if (*a == 0 && *b == 0)
316 if (*a == 0 || *b == 0)
325 if (memcmp(a, b, j) != 0)
333 int path_is_mount_point(const char *t, bool allow_symlink) {
336 struct file_handle *h;
337 int mount_id, mount_id_parent;
340 /* We are not actually interested in the file handles, but
341 * name_to_handle_at() also passes us the mount ID, hence use
342 * it but throw the handle away */
344 if (path_equal(t, "/"))
347 h = alloca(MAX_HANDLE_SZ);
348 h->handle_bytes = MAX_HANDLE_SZ;
350 r = name_to_handle_at(AT_FDCWD, t, h, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0);
352 if (errno == ENOSYS || errno == ENOTSUP)
353 /* This kernel or file system does not support
354 * name_to_handle_at(), hence fallback to the
355 * traditional stat() logic */
364 r = path_get_parent(t, &parent);
368 h->handle_bytes = MAX_HANDLE_SZ;
369 r = name_to_handle_at(AT_FDCWD, parent, h, &mount_id_parent, 0);
373 /* The parent can't do name_to_handle_at() but the
374 * directory we are interested in can? If so, it must
375 * be a mount point */
376 if (errno == ENOTSUP)
382 return mount_id != mount_id_parent;
397 r = path_get_parent(t, &parent);
401 r = lstat(parent, &b);
407 return a.st_dev != b.st_dev;
410 int path_is_read_only_fs(const char *path) {
415 if (statvfs(path, &st) < 0)
418 return !!(st.f_flag & ST_RDONLY);