path-util.c revision b7def684941808600c344f0be7a2b9fcdda97e0f
0075453649960d576af62968ed97edb682a5c5ccAllan Foster/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster/***
0075453649960d576af62968ed97edb682a5c5ccAllan Foster This file is part of systemd.
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster Copyright 2010-2012 Lennart Poettering
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster systemd is free software; you can redistribute it and/or modify it
0075453649960d576af62968ed97edb682a5c5ccAllan Foster under the terms of the GNU Lesser General Public License as published by
0075453649960d576af62968ed97edb682a5c5ccAllan Foster the Free Software Foundation; either version 2.1 of the License, or
0075453649960d576af62968ed97edb682a5c5ccAllan Foster (at your option) any later version.
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster systemd is distributed in the hope that it will be useful, but
0075453649960d576af62968ed97edb682a5c5ccAllan Foster WITHOUT ANY WARRANTY; without even the implied warranty of
0075453649960d576af62968ed97edb682a5c5ccAllan Foster MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0075453649960d576af62968ed97edb682a5c5ccAllan Foster Lesser General Public License for more details.
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster You should have received a copy of the GNU Lesser General Public License
0075453649960d576af62968ed97edb682a5c5ccAllan Foster along with systemd; If not, see <http://www.gnu.org/licenses/>.
0075453649960d576af62968ed97edb682a5c5ccAllan Foster***/
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <assert.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <string.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <unistd.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <errno.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <stdlib.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <signal.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <stdio.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <fcntl.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <dirent.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include <sys/statvfs.h>
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include "macro.h"
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include "util.h"
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include "log.h"
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include "strv.h"
0075453649960d576af62968ed97edb682a5c5ccAllan Foster#include "path-util.h"
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Fosterbool path_is_absolute(const char *p) {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return p[0] == '/';
0075453649960d576af62968ed97edb682a5c5ccAllan Foster}
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Fosterbool is_path(const char *p) {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return !!strchr(p, '/');
0075453649960d576af62968ed97edb682a5c5ccAllan Foster}
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Fosterchar *path_get_file_name(const char *p) {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster char *r;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster assert(p);
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if ((r = strrchr(p, '/')))
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return r + 1;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return (char*) p;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster}
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Fosterint path_get_parent(const char *path, char **_r) {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster const char *e, *a = NULL, *b = NULL, *p;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster char *r;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster bool slash = false;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster assert(path);
0075453649960d576af62968ed97edb682a5c5ccAllan Foster assert(_r);
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (!*path)
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return -EINVAL;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster for (e = path; *e; e++) {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (!slash && *e == '/') {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster a = b;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster b = e;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster slash = true;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster } else if (slash && *e != '/')
0075453649960d576af62968ed97edb682a5c5ccAllan Foster slash = false;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster }
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (*(e-1) == '/')
0075453649960d576af62968ed97edb682a5c5ccAllan Foster p = a;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster else
0075453649960d576af62968ed97edb682a5c5ccAllan Foster p = b;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (!p)
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return -EINVAL;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (p == path)
0075453649960d576af62968ed97edb682a5c5ccAllan Foster r = strdup("/");
0075453649960d576af62968ed97edb682a5c5ccAllan Foster else
0075453649960d576af62968ed97edb682a5c5ccAllan Foster r = strndup(path, p-path);
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (!r)
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return -ENOMEM;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster *_r = r;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return 0;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster}
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Fosterchar **path_split_and_make_absolute(const char *p) {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster char **l;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster assert(p);
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (!(l = strv_split(p, ":")))
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return NULL;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster if (!path_strv_make_absolute_cwd(l)) {
0075453649960d576af62968ed97edb682a5c5ccAllan Foster strv_free(l);
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return NULL;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster }
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Foster return l;
0075453649960d576af62968ed97edb682a5c5ccAllan Foster}
0075453649960d576af62968ed97edb682a5c5ccAllan Foster
0075453649960d576af62968ed97edb682a5c5ccAllan Fosterchar *path_make_absolute(const char *p, const char *prefix) {
assert(p);
/* Makes every item in the list an absolute path by prepending
* the prefix, if specified and necessary */
if (path_is_absolute(p) || !prefix)
return strdup(p);
return strjoin(prefix, "/", p, NULL);
}
char *path_make_absolute_cwd(const char *p) {
char *cwd, *r;
assert(p);
/* Similar to path_make_absolute(), but prefixes with the
* current working directory. */
if (path_is_absolute(p))
return strdup(p);
if (!(cwd = get_current_dir_name()))
return NULL;
r = path_make_absolute(p, cwd);
free(cwd);
return r;
}
char **path_strv_make_absolute_cwd(char **l) {
char **s;
/* Goes through every item in the string list and makes it
* absolute. This works in place and won't rollback any
* changes on failure. */
STRV_FOREACH(s, l) {
char *t;
if (!(t = path_make_absolute_cwd(*s)))
return NULL;
free(*s);
*s = t;
}
return l;
}
char **path_strv_canonicalize(char **l) {
char **s;
unsigned k = 0;
bool enomem = false;
if (strv_isempty(l))
return l;
/* Goes through every item in the string list and canonicalize
* the path. This works in place and won't rollback any
* changes on failure. */
STRV_FOREACH(s, l) {
char *t, *u;
t = path_make_absolute_cwd(*s);
free(*s);
if (!t) {
enomem = true;
continue;
}
errno = 0;
u = canonicalize_file_name(t);
free(t);
if (!u) {
if (errno == ENOMEM || !errno)
enomem = true;
continue;
}
l[k++] = u;
}
l[k] = NULL;
if (enomem)
return NULL;
return l;
}
char **path_strv_remove_empty(char **l) {
char **f, **t;
if (!l)
return NULL;
for (f = t = l; *f; f++) {
if (dir_is_empty(*f) > 0) {
free(*f);
continue;
}
*(t++) = *f;
}
*t = NULL;
return l;
}
char *path_kill_slashes(char *path) {
char *f, *t;
bool slash = false;
/* Removes redundant inner and trailing slashes. Modifies the
* passed string in-place.
*
* ///foo///bar/ becomes /foo/bar
*/
for (f = path, t = path; *f; f++) {
if (*f == '/') {
slash = true;
continue;
}
if (slash) {
slash = false;
*(t++) = '/';
}
*(t++) = *f;
}
/* Special rule, if we are talking of the root directory, a
trailing slash is good */
if (t == path && slash)
*(t++) = '/';
*t = 0;
return path;
}
bool path_startswith(const char *path, const char *prefix) {
assert(path);
assert(prefix);
if ((path[0] == '/') != (prefix[0] == '/'))
return false;
for (;;) {
size_t a, b;
path += strspn(path, "/");
prefix += strspn(prefix, "/");
if (*prefix == 0)
return true;
if (*path == 0)
return false;
a = strcspn(path, "/");
b = strcspn(prefix, "/");
if (a != b)
return false;
if (memcmp(path, prefix, a) != 0)
return false;
path += a;
prefix += b;
}
}
bool path_equal(const char *a, const char *b) {
assert(a);
assert(b);
if ((a[0] == '/') != (b[0] == '/'))
return false;
for (;;) {
size_t j, k;
a += strspn(a, "/");
b += strspn(b, "/");
if (*a == 0 && *b == 0)
return true;
if (*a == 0 || *b == 0)
return false;
j = strcspn(a, "/");
k = strcspn(b, "/");
if (j != k)
return false;
if (memcmp(a, b, j) != 0)
return false;
a += j;
b += k;
}
}
int path_is_mount_point(const char *t, bool allow_symlink) {
struct stat a, b;
char *parent;
int r;
if (allow_symlink)
r = stat(t, &a);
else
r = lstat(t, &a);
if (r < 0) {
if (errno == ENOENT)
return 0;
return -errno;
}
r = path_get_parent(t, &parent);
if (r < 0)
return r;
r = lstat(parent, &b);
free(parent);
if (r < 0)
return -errno;
return a.st_dev != b.st_dev;
}
int path_is_read_only_fs(const char *path) {
struct statvfs st;
assert(path);
if (statvfs(path, &st) < 0)
return -errno;
return !!(st.f_flag & ST_RDONLY);
}