path-util.c revision af86c440389986ed72cb1a943a98d1aaf297f467
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen This file is part of systemd.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen Copyright 2010-2012 Lennart Poettering
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 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 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 Andersenbool path_is_absolute(const char *p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return p[0] == '/';
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenbool is_path(const char *p) {
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 for (e = path; *e; e++) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen } else if (slash && *e != '/')
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar **path_split_and_make_absolute(const char *p) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!path_strv_make_absolute_cwd(l)) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar *path_make_absolute(const char *p, const char *prefix) {
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 if (path_is_absolute(p) || !prefix)
b7e7184634d573fb73143210962acce205f37f61Michael Bieblchar *path_make_absolute_cwd(const char *p) {
b7e7184634d573fb73143210962acce205f37f61Michael Biebl /* Similar to path_make_absolute(), but prefixes with the
b7e7184634d573fb73143210962acce205f37f61Michael Biebl * current working directory. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint path_make_relative(const char *from_dir, const char *to_path, char **_r) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Strips the common part, and adds ".." elements as necessary. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!path_is_absolute(from_dir))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (!path_is_absolute(to_path))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Skip the common part. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen from_dir += strspn(from_dir, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen to_path += strspn(to_path, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* from_dir equals to_path. */
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt /* from_dir is a parent directory of to_path. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (memcmp(from_dir, to_path, a) != 0)
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 /* Count the number of necessary ".." elements. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen from_dir += strspn(from_dir, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen from_dir += strcspn(from_dir, "/");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = malloc(n_parents * 3 + strlen(to_path) + 1);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen for (p = r; n_parents > 0; n_parents--, p += 3)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar **path_strv_make_absolute_cwd(char **l) {
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 t = path_make_absolute_cwd(*s);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar **path_strv_resolve(char **l, const char *prefix) {
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 _cleanup_free_ char *orig = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen u = canonicalize_file_name(t);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (errno == ENOMEM || errno == 0)
40780877c19ef408da8ab21f4156cfc153f94b5cMartin Pitt /* restore the slash if it was lost */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* canonicalized path goes outside of
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * prefix, keep the original path instead */
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmekchar **path_strv_resolve_uniq(char **l, const char *prefix) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (!path_strv_resolve(l, prefix))
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmekchar *path_kill_slashes(char *path) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek /* Removes redundant inner and trailing slashes. Modifies the
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * passed string in-place.
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek * ///foo///bar/ becomes /foo/bar
e987f2a809c6bab7e7bae4ca8f598ea5bafd5225Zbigniew Jędrzejewski-Szmek for (f = path, t = path; *f; f++) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (*f == '/') {
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-Szmekchar* path_startswith(const char *path, const char *prefix) {
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if ((path[0] == '/') != (prefix[0] == '/'))
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmek if (memcmp(path, prefix, a) != 0)
1e2fee5f757c0bb3a6fea216b1e10ee7b3c0e12eZbigniew Jędrzejewski-Szmekint path_compare(const char *a, const char *b) {
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] == '/');
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (*a == 0 && *b == 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Order prefixes first: "/foo" before "/foo/bar" */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* Alphabetical sort: "/foo/aaa" before "/foo/b" */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return (d > 0) - (d < 0); /* sign of d */
77354c7e6f096a447245a8781c1eaa4acbe67089Martin Pitt /* Sort "/foo/a" before "/foo/aaa" */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen d = (j > k) - (j < k); /* sign of (j - k) */
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 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 Andersenchar* path_join(const char *root, const char *path, const char *rest) {
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 rest ? (endswith(path, "/") ? "" : "/") : NULL,
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen rest && rest[0] == '/' ? rest+1 : rest,
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 if ((flags & AT_EMPTY_PATH) && isempty(filename))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen xsprintf(path, "/proc/self/fdinfo/%i", fd);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen xsprintf(path, "/proc/self/fdinfo/%i", subfd);
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 p = startswith(fdinfo, "mnt_id:");
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 p[strcspn(p, WHITESPACE)] = 0;
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;
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 * 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 * 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 r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
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 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 r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
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. */
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 /* 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. */
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 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 mount_id != mount_id_parent;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (mount_id != mount_id_parent)
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 /* yay for fstatat() taking a different set of flags than the other
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (flags & AT_SYMLINK_FOLLOW)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen flags |= AT_SYMLINK_NOFOLLOW;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (fstatat(fd, filename, &a, flags) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
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 return check_st_dev && (a.st_dev != b.st_dev);
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_free_ char *canonical = NULL, *parent = NULL;
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 r = path_get_parent(canonical ?: t, &parent);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen return fd_is_mount_point(fd, basename(canonical ?: t), flags);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint path_is_read_only_fs(const char *path) {
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 Andersenint path_is_os_tree(const char *path) {
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 /* Also check for the old location in /etc, just in case. */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = strjoina(path, "/etc/os-release");
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint find_binary(const char *name, bool local, char **filename) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen if (local && access(name, X_OK) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen p = path_make_absolute_cwd(name);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen * Plain getenv, not secure_getenv, because we want
a986501b9059b72e8deced262554fbdd1ab9da17Lennart Poettering * to actually allow the user to pick the binary.
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen FOREACH_WORD_SEPARATOR(word, l, path, ":", state) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_free_ char *p = NULL;
805e5dda0a01c99d231824e1a9c4a208418bf342Lennart Poettering if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0)
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenbool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen const char* const* i;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen u = timespec_load(&stats.st_mtim);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* first check */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen log_debug("timestamp of '%s' changed", *i);
7a03974a6f4510dcb1850515a80c2063c767a80fThomas Hindoe Paaboel Andersen /* update timestamp */
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenint fsck_exists(const char *fstype) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen _cleanup_free_ char *p = NULL, *d = NULL;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen checker = strjoina("fsck.", fstype);
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen r = find_binary(checker, true, &p);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt /* An fsck that is linked to /bin/true is a non-existent
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen (path_equal(d, "/bin/true") ||
7a03974a6f4510dcb1850515a80c2063c767a80fThomas Hindoe Paaboel Andersen path_equal(d, "/usr/bin/true") ||
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersenchar *prefix_root(const char *root, const char *path) {
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen /* If root is passed, prefixes path with it. Otherwise returns
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 if (isempty(root) || path_equal(root, "/"))
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen l = strlen(root) + 1 + strlen(path) + 1;
95ed3294c632f5606327149f10cef1eb34422862Thomas Hindoe Paaboel Andersen while (p > n && p[-1] == '/')
f4f01ec146d91cb6943828851d98eee6a1ad4dd9Martin Pitt *(p++) = '/';