path-util.c revision af86c440389986ed72cb1a943a98d1aaf297f467
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen/***
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen This file is part of systemd.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen Copyright 2010-2012 Lennart Poettering
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen systemd is free software; you can redistribute it and/or modify it
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen under the terms of the GNU Lesser General Public License as published by
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen the Free Software Foundation; either version 2.1 of the License, or
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (at your option) any later version.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen systemd is distributed in the hope that it will be useful, but
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen WITHOUT ANY WARRANTY; without even the implied warranty of
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen Lesser General Public License for more details.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen You should have received a copy of the GNU Lesser General Public License
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen***/
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include <string.h>
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include <unistd.h>
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include <errno.h>
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include <stdlib.h>
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include <stdio.h>
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include <fcntl.h>
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include <sys/statvfs.h>
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "macro.h"
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "util.h"
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "log.h"
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "strv.h"
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "path-util.h"
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "missing.h"
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen#include "fileio.h"
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenbool path_is_absolute(const char *p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return p[0] == '/';
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenbool is_path(const char *p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return !!strchr(p, '/');
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint path_get_parent(const char *path, char **_r) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen const char *e, *a = NULL, *b = NULL, *p;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen bool slash = false;
d5d8429a12c4b1ef0dcd226c0904f00f4fa4898aLennart Poettering
d5d8429a12c4b1ef0dcd226c0904f00f4fa4898aLennart Poettering assert(path);
d5d8429a12c4b1ef0dcd226c0904f00f4fa4898aLennart Poettering assert(_r);
d5d8429a12c4b1ef0dcd226c0904f00f4fa4898aLennart Poettering
d5d8429a12c4b1ef0dcd226c0904f00f4fa4898aLennart Poettering if (!*path)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -EINVAL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (e = path; *e; e++) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!slash && *e == '/') {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen a = b;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen b = e;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen slash = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else if (slash && *e != '/')
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen slash = false;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (*(e-1) == '/')
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = a;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = b;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!p)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -EINVAL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (p == path)
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen r = strdup("/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = strndup(path, p-path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!r)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -ENOMEM;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *_r = r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar **path_split_and_make_absolute(const char *p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char **l;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen l = strv_split(p, ":");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!l)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!path_strv_make_absolute_cwd(l)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen strv_free(l);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return l;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar *path_make_absolute(const char *p, const char *prefix) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Makes every item in the list an absolute path by prepending
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * the prefix, if specified and necessary */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (path_is_absolute(p) || !prefix)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return strdup(p);
b7e7184634d573fb73143210962acce205f37f61Michael Biebl
b7e7184634d573fb73143210962acce205f37f61Michael Biebl return strjoin(prefix, "/", p, NULL);
b7e7184634d573fb73143210962acce205f37f61Michael Biebl}
b7e7184634d573fb73143210962acce205f37f61Michael Biebl
b7e7184634d573fb73143210962acce205f37f61Michael Bieblchar *path_make_absolute_cwd(const char *p) {
b7e7184634d573fb73143210962acce205f37f61Michael Biebl _cleanup_free_ char *cwd = NULL;
b7e7184634d573fb73143210962acce205f37f61Michael Biebl
b7e7184634d573fb73143210962acce205f37f61Michael Biebl assert(p);
b7e7184634d573fb73143210962acce205f37f61Michael Biebl
b7e7184634d573fb73143210962acce205f37f61Michael Biebl /* Similar to path_make_absolute(), but prefixes with the
b7e7184634d573fb73143210962acce205f37f61Michael Biebl * current working directory. */
b7e7184634d573fb73143210962acce205f37f61Michael Biebl
b7e7184634d573fb73143210962acce205f37f61Michael Biebl if (path_is_absolute(p))
b7e7184634d573fb73143210962acce205f37f61Michael Biebl return strdup(p);
b7e7184634d573fb73143210962acce205f37f61Michael Biebl
b7e7184634d573fb73143210962acce205f37f61Michael Biebl cwd = get_current_dir_name();
b7e7184634d573fb73143210962acce205f37f61Michael Biebl if (!cwd)
b7e7184634d573fb73143210962acce205f37f61Michael Biebl return NULL;
b7e7184634d573fb73143210962acce205f37f61Michael Biebl
b7e7184634d573fb73143210962acce205f37f61Michael Biebl return strjoin(cwd, "/", p, NULL);
b7e7184634d573fb73143210962acce205f37f61Michael Biebl}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint path_make_relative(const char *from_dir, const char *to_path, char **_r) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *r, *p;
91e7bad45dced1cb2dfaac79337bb08d6e2b74a9Andreas Henriksson unsigned n_parents;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(from_dir);
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen assert(to_path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(_r);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Strips the common part, and adds ".." elements as necessary. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!path_is_absolute(from_dir))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -EINVAL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!path_is_absolute(to_path))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -EINVAL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Skip the common part. */
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen for (;;) {
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen size_t a;
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen size_t b;
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen from_dir += strspn(from_dir, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen to_path += strspn(to_path, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!*from_dir) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!*to_path)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* from_dir equals to_path. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = strdup(".");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt /* from_dir is a parent directory of to_path. */
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt r = strdup(to_path);
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt
4e5589836c9e143796c3f3d81e67ab7a9209e2b0Martin Pitt if (!r)
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt return -ENOMEM;
9993ef2e9817b35b1d467707bef12b2a140b62dcLennart Poettering
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt path_kill_slashes(r);
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *_r = r;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return 0;
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!*to_path)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen break;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
aad0a2c80097926757d4385e5f5492082d47f006Zbigniew Jędrzejewski-Szmek a = strcspn(from_dir, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen b = strcspn(to_path, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (a != b)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen break;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (memcmp(from_dir, to_path, a) != 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen break;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen from_dir += a;
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen to_path += b;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* If we're here, then "from_dir" has one or more elements that need to
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * be replaced with "..". */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Count the number of necessary ".." elements. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (n_parents = 0;;) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen from_dir += strspn(from_dir, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!*from_dir)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen break;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen from_dir += strcspn(from_dir, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n_parents++;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
d171ed1c50ba64928b7fb30ee2ae729fdfe0826bThomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = malloc(n_parents * 3 + strlen(to_path) + 1);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!r)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -ENOMEM;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (p = r; n_parents > 0; n_parents--, p += 3)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen memcpy(p, "../", 3);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen strcpy(p, to_path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen path_kill_slashes(r);
260ad50f5b4a9795032e3119c64f838a2d03370dThomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *_r = r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 0;
31938a8560a664c32a9d72f1fc2d4347b232e6e9Michal Schmidt}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar **path_strv_make_absolute_cwd(char **l) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char **s;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Goes through every item in the string list and makes it
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * absolute. This works in place and won't rollback any
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * changes on failure. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen STRV_FOREACH(s, l) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *t;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen t = path_make_absolute_cwd(*s);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!t)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen free(*s);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *s = t;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return l;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar **path_strv_resolve(char **l, const char *prefix) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char **s;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen unsigned k = 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen bool enomem = false;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (strv_isempty(l))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return l;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Goes through every item in the string list and canonicalize
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * the path. This works in place and won't rollback any
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * changes on failure. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen STRV_FOREACH(s, l) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *t, *u;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_free_ char *orig = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!path_is_absolute(*s)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen free(*s);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen continue;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (prefix) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen orig = *s;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen t = strappend(prefix, orig);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!t) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen enomem = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen continue;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
4e4885553447f6f4c014bfa3e5b5837a76a0e612Lennart Poettering } else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen t = *s;
4e4885553447f6f4c014bfa3e5b5837a76a0e612Lennart Poettering
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen errno = 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen u = canonicalize_file_name(t);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!u) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (errno == ENOENT) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (prefix) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen u = orig;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen orig = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen free(t);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen u = t;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen free(t);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (errno == ENOMEM || errno == 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen enomem = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen continue;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else if (prefix) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *x;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen free(t);
29e0e6d8c1f7f648b7c998880d034eaa3e58c53aMartin Pitt x = path_startswith(u, prefix);
4e4885553447f6f4c014bfa3e5b5837a76a0e612Lennart Poettering if (x) {
40780877c19ef408da8ab21f4156cfc153f94b5cMartin Pitt /* restore the slash if it was lost */
3315f085178f46155fda345d9526c09083b45946Lennart Poettering if (!startswith(x, "/"))
4e4885553447f6f4c014bfa3e5b5837a76a0e612Lennart Poettering *(--x) = '/';
3315f085178f46155fda345d9526c09083b45946Lennart Poettering
3315f085178f46155fda345d9526c09083b45946Lennart Poettering t = strdup(x);
29e0e6d8c1f7f648b7c998880d034eaa3e58c53aMartin Pitt free(u);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!t) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen enomem = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen continue;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen u = t;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* canonicalized path goes outside of
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * prefix, keep the original path instead */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen free(u);
3315f085178f46155fda345d9526c09083b45946Lennart Poettering u = orig;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen orig = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen free(t);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen l[k++] = u;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen l[k] = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (enomem)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return l;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek}
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmekchar **path_strv_resolve_uniq(char **l, const char *prefix) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (strv_isempty(l))
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return l;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (!path_strv_resolve(l, prefix))
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return NULL;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek return strv_uniq(l);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek}
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmekchar *path_kill_slashes(char *path) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek char *f, *t;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek bool slash = false;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek /* Removes redundant inner and trailing slashes. Modifies the
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * passed string in-place.
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek *
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * ///foo///bar/ becomes /foo/bar
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek */
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek for (f = path, t = path; *f; f++) {
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (*f == '/') {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek slash = true;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek continue;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek }
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (slash) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek slash = false;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek *(t++) = '/';
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek }
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek *(t++) = *f;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek }
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek /* Special rule, if we are talking of the root directory, a
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek trailing slash is good */
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (t == path && slash)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek *(t++) = '/';
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek *t = 0;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return path;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek}
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmekchar* path_startswith(const char *path, const char *prefix) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek assert(path);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek assert(prefix);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if ((path[0] == '/') != (prefix[0] == '/'))
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return NULL;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek for (;;) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek size_t a, b;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek path += strspn(path, "/");
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek prefix += strspn(prefix, "/");
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (*prefix == 0)
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek return (char*) path;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (*path == 0)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return NULL;
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek a = strcspn(path, "/");
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek b = strcspn(prefix, "/");
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (a != b)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return NULL;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (memcmp(path, prefix, a) != 0)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return NULL;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek path += a;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek prefix += b;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek }
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek}
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmekint path_compare(const char *a, const char *b) {
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek int d;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek assert(a);
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek assert(b);
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek /* A relative path and an abolute path must not compare as equal.
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * Which one is sorted before the other does not really matter.
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek * Here a relative path is ordered before an absolute path. */
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek d = (a[0] == '/') - (b[0] == '/');
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek if (d)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return d;
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek for (;;) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen size_t j, k;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen a += strspn(a, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen b += strspn(b, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (*a == 0 && *b == 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Order prefixes first: "/foo" before "/foo/bar" */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (*a == 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (*b == 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen j = strcspn(a, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen k = strcspn(b, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen d = memcmp(a, b, MIN(j, k));
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (d)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return (d > 0) - (d < 0); /* sign of d */
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt /* Sort "/foo/a" before "/foo/aaa" */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen d = (j > k) - (j < k); /* sign of (j - k) */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (d)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return d;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen a += j;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen b += k;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek}
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmekbool path_equal(const char *a, const char *b) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return path_compare(a, b) == 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenbool path_equal_or_files_same(const char *a, const char *b) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return path_equal(a, b) || files_same(a, b) > 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar* path_join(const char *root, const char *path, const char *rest) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!isempty(root))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return strjoin(root, endswith(root, "/") ? "" : "/",
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen path[0] == '/' ? path+1 : path,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen rest ? (endswith(path, "/") ? "" : "/") : NULL,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen rest && rest[0] == '/' ? rest+1 : rest,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen NULL);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return strjoin(path,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen rest ? (endswith(path, "/") ? "" : "/") : NULL,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen rest && rest[0] == '/' ? rest+1 : rest,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen NULL);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenstatic int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_free_ char *fdinfo = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_close_ int subfd = -1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *p;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if ((flags & AT_EMPTY_PATH) && isempty(filename))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen xsprintf(path, "/proc/self/fdinfo/%i", fd);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (subfd < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen xsprintf(path, "/proc/self/fdinfo/%i", subfd);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = read_full_file(path, &fdinfo, NULL);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -EOPNOTSUPP;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = startswith(fdinfo, "mnt_id:");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = strstr(fdinfo, "\nmnt_id:");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!p) /* The mnt_id field is a relatively new addition */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -EOPNOTSUPP;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p += 8;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p += strspn(p, WHITESPACE);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p[strcspn(p, WHITESPACE)] = 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return safe_atoi(p, mnt_id);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint fd_is_mount_point(int fd, const char *filename, int flags) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int mount_id = -1, mount_id_parent = -1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen bool nosupp = false, check_st_dev = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen struct stat a, b;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(fd >= 0);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(filename);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering /* First we will try the name_to_handle_at() syscall, which
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * tells us the mount id and an opaque file "handle". It is
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * not supported everywhere though (kernel compile-time
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * option, not all file systems are hooked up). If it works
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * the mount id is usually good enough to tell us whether
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * something is a mount point.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * If that didn't work we will try to read the mount id from
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * /proc/self/fdinfo/<fd>. This is almost as good as
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * name_to_handle_at(), however, does not return the
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * opaque file handle. The opaque file handle is pretty useful
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * to detect the root directory, which we should always
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * consider a mount point. Hence we use this only as
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * fallback. Exporting the mnt_id in fdinfo is a pretty recent
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * kernel addition.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * As last fallback we do traditional fstat() based st_dev
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * comparisons. This is how things were traditionally done,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * but unionfs breaks breaks this since it exposes file
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * systems with a variety of st_dev reported. Also, btrfs
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * subvolumes have different st_dev, even though they aren't
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * real mounts of their own. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r < 0) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (errno == ENOSYS)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* This kernel does not support name_to_handle_at()
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * fall back to simpler logic. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen goto fallback_fdinfo;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else if (errno == EOPNOTSUPP)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* This kernel or file system does not support
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * name_to_handle_at(), hence let's see if the
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * upper fs supports it (in which case it is a
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * mount point), otherwise fallback to the
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * traditional stat() logic */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen nosupp = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r < 0) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (errno == EOPNOTSUPP) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (nosupp)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Neither parent nor child do name_to_handle_at()?
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen We have no choice but to fall back. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen goto fallback_fdinfo;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek /* The parent can't do name_to_handle_at() but the
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * directory we are interested in can?
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * If so, it must be a mount point. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* The parent can do name_to_handle_at() but the
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * directory we are interested in can't? If so, it
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * must be a mount point. */
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (nosupp)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* If the file handle for the directory we are
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * interested in and its parent are identical, we
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * assume this is the root directory, which is a mount
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * point. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen h.handle.handle_type == h_parent.handle.handle_type &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return mount_id != mount_id_parent;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenfallback_fdinfo:
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r == -EOPNOTSUPP)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen goto fallback_fstat;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (mount_id != mount_id_parent)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Hmm, so, the mount ids are the same. This leaves one
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * special case though for the root file system. For that,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * let's see if the parent directory has the same inode as we
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * are interested in. Hence, let's also do fstat() checks now,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * too, but avoid the st_dev comparisons, since they aren't
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * that useful on unionfs mounts. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen check_st_dev = false;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenfallback_fstat:
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* yay for fstatat() taking a different set of flags than the other
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * _at() above */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (flags & AT_SYMLINK_FOLLOW)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen flags &= ~AT_SYMLINK_FOLLOW;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen flags |= AT_SYMLINK_NOFOLLOW;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (fstatat(fd, filename, &a, flags) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* A directory with same device and inode as its parent? Must
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * be the root directory */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (a.st_dev == b.st_dev &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen a.st_ino == b.st_ino)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return check_st_dev && (a.st_dev != b.st_dev);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen/* flags can be AT_SYMLINK_FOLLOW or 0 */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint path_is_mount_point(const char *t, int flags) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_close_ int fd = -1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_free_ char *canonical = NULL, *parent = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(t);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (path_equal(t, "/"))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* we need to resolve symlinks manually, we can't just rely on
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * fd_is_mount_point() to do that for us; if we have a structure like
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * look at needs to be /usr, not /. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (flags & AT_SYMLINK_FOLLOW) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen canonical = canonicalize_file_name(t);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!canonical)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = path_get_parent(canonical ?: t, &parent);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (fd < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return fd_is_mount_point(fd, basename(canonical ?: t), flags);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint path_is_read_only_fs(const char *path) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen struct statvfs st;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (statvfs(path, &st) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (st.f_flag & ST_RDONLY)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* On NFS, statvfs() might not reflect whether we can actually
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * write to the remote share. Let's try again with
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * access(W_OK) which is more reliable, at least sometimes. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (access(path, W_OK) < 0 && errno == EROFS)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return false;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint path_is_os_tree(const char *path) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *p;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* We use /usr/lib/os-release as flag file if something is an OS */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = strjoina(path, "/usr/lib/os-release");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = access(p, F_OK);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r >= 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Also check for the old location in /etc, just in case. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = strjoina(path, "/etc/os-release");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = access(p, F_OK);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return r >= 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint find_binary(const char *name, bool local, char **filename) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(name);
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (is_path(name)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (local && access(name, X_OK) < 0)
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek return -errno;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (filename) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *p;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = path_make_absolute_cwd(name);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!p)
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt return -ENOMEM;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *filename = p;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return 0;
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering } else {
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering const char *path;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen const char *word, *state;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen size_t l;
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering /**
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * Plain getenv, not secure_getenv, because we want
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering * to actually allow the user to pick the binary.
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen path = getenv("PATH");
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering if (!path)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen path = DEFAULT_PATH;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_free_ char *p = NULL;
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering return -ENOMEM;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (access(p, X_OK) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen continue;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering if (filename) {
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering *filename = path_kill_slashes(p);
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering p = NULL;
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering }
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering return 0;
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering }
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt return -ENOENT;
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt }
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt}
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenbool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen bool changed = false;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen const char* const* i;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(timestamp);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (paths == NULL)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return false;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering STRV_FOREACH(i, paths) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen struct stat stats;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen usec_t u;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering if (stat(*i, &stats) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen continue;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen u = timespec_load(&stats.st_mtim);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* first check */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (*timestamp >= u)
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek continue;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_debug("timestamp of '%s' changed", *i);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
7a03974a6f4510dcb1850515a80c2063c767a80fThomas Hindoe Paaboel Andersen /* update timestamp */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (update) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen *timestamp = u;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen changed = true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return true;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen }
a8ffe6fbcbfdba39aef8dce8b298b3e0cb377c0eZbigniew Jędrzejewski-Szmek
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return changed;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint fsck_exists(const char *fstype) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_free_ char *p = NULL, *d = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen const char *checker;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen int r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen checker = strjoina("fsck.", fstype);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = find_binary(checker, true, &p);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return r;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt /* An fsck that is linked to /bin/true is a non-existent
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * fsck */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = readlink_malloc(p, &d);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (r >= 0 &&
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (path_equal(d, "/bin/true") ||
7a03974a6f4510dcb1850515a80c2063c767a80fThomas Hindoe Paaboel Andersen path_equal(d, "/usr/bin/true") ||
7a03974a6f4510dcb1850515a80c2063c767a80fThomas Hindoe Paaboel Andersen path_equal(d, "/dev/null")))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return -ENOENT;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
a34bf9db5da0fdd6bdb14459e203dbe41ee99614Lennart Poettering return 0;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar *prefix_root(const char *root, const char *path) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen char *n, *p;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen size_t l;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* If root is passed, prefixes path with it. Otherwise returns
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * it as is. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen assert(path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* First, drop duplicate prefixing slashes from the path */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen while (path[0] == '/' && path[1] == '/')
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen path++;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (isempty(root) || path_equal(root, "/"))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return strdup(path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen l = strlen(root) + 1 + strlen(path) + 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen n = new(char, l);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!n)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = stpcpy(n, root);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen while (p > n && p[-1] == '/')
8c84621c25c563c7428f3d355136fc542389aab8Thomas Hindoe Paaboel Andersen p--;
8c84621c25c563c7428f3d355136fc542389aab8Thomas Hindoe Paaboel Andersen
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt if (path[0] != '/')
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt *(p++) = '/';
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen strcpy(p, path);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return n;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen}
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen