Commit 00051ad7 authored by Beniamino Galvani's avatar Beniamino Galvani
Browse files

systemd: update code from upstream

This is a direct dump from systemd git on 2015-07-03, git commit
2812dcba8543.

SYSTEMD_DIR=../systemd
COMMIT=2812dcba85435c59203268ab54901a72c6c24a69

(
	cd "$SYSTEMD_DIR"
	git checkout "$COMMIT"
	git reset --hard
	git clean -fdx
)

git ls-files :/src/systemd/src/ | xargs -d '\n' rm -f
mkdir src/systemd/src/basic

cp "$SYSTEMD_DIR"/src/libsystemd/sd-id128/sd-id128.c ./src/systemd/src/libsystemd/sd-id128/sd-id128.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-identifier.c ./src/systemd/src/libsystemd-network/dhcp-identifier.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-identifier.h ./src/systemd/src/libsystemd-network/dhcp-identifier.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-internal.h ./src/systemd/src/libsystemd-network/dhcp-internal.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-lease-internal.h ./src/systemd/src/libsystemd-network/dhcp-lease-internal.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-network.c ./src/systemd/src/libsystemd-network/dhcp-network.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-option.c ./src/systemd/src/libsystemd-network/dhcp-option.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-packet.c ./src/systemd/src/libsystemd-network/dhcp-packet.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp-protocol.h ./src/systemd/src/libsystemd-network/dhcp-protocol.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp6-internal.h ./src/systemd/src/libsystemd-network/dhcp6-internal.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp6-lease-internal.h ./src/systemd/src/libsystemd-network/dhcp6-lease-internal.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp6-network.c ./src/systemd/src/libsystemd-network/dhcp6-network.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp6-option.c ./src/systemd/src/libsystemd-network/dhcp6-option.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/dhcp6-protocol.h ./src/systemd/src/libsystemd-network/dhcp6-protocol.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/network-internal.c ./src/systemd/src/libsystemd-network/network-internal.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/network-internal.h ./src/systemd/src/libsystemd-network/network-internal.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/sd-dhcp-client.c ./src/systemd/src/libsystemd-network/sd-dhcp-client.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/sd-dhcp-lease.c ./src/systemd/src/libsystemd-network/sd-dhcp-lease.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/sd-dhcp6-client.c ./src/systemd/src/libsystemd-network/sd-dhcp6-client.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/sd-dhcp6-lease.c ./src/systemd/src/libsystemd-network/sd-dhcp6-lease.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/ipv4ll-internal.h ./src/systemd/src/libsystemd-network/ipv4ll-internal.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/ipv4ll-internal.h ./src/systemd/src/libsystemd-network/ipv4ll-internal.h
cp "$SYSTEMD_DIR"/src/libsystemd-network/ipv4ll-network.c ./src/systemd/src/libsystemd-network/ipv4ll-network.c
cp "$SYSTEMD_DIR"/src/libsystemd-network//ipv4ll-packet.c ./src/systemd/src/libsystemd-network//ipv4ll-packet.c
cp "$SYSTEMD_DIR"/src/libsystemd-network/sd-ipv4ll.c ./src/systemd/src/libsystemd-network/sd-ipv4ll.c
cp "$SYSTEMD_DIR"/src/basic/async.h ./src/systemd/src/basic/async.h
cp "$SYSTEMD_DIR"/src/basic/fileio.c ./src/systemd/src/basic/fileio.c
cp "$SYSTEMD_DIR"/src/basic/fileio.h ./src/systemd/src/basic/fileio.h
cp "$SYSTEMD_DIR"/src/basic/list.h ./src/systemd/src/basic/list.h
cp "$SYSTEMD_DIR"/src/basic/log.h ./src/systemd/src/basic/log.h
cp "$SYSTEMD_DIR"/src/basic/macro.h ./src/systemd/src/basic/macro.h
cp "$SYSTEMD_DIR"/src/basic/path-util.c ./src/systemd/src/basic/path-util.c
cp "$SYSTEMD_DIR"/src/basic/path-util.h ./src/systemd/src/basic/path-util.h
cp "$SYSTEMD_DIR"/src/basic/refcnt.h ./src/systemd/src/basic/refcnt.h
cp "$SYSTEMD_DIR"/src/basic/siphash24.c ./src/systemd/src/basic/siphash24.c
cp "$SYSTEMD_DIR"/src/basic/siphash24.h ./src/systemd/src/basic/siphash24.h
cp "$SYSTEMD_DIR"/src/basic/socket-util.h ./src/systemd/src/basic/socket-util.h
cp "$SYSTEMD_DIR"/src/basic/sparse-endian.h ./src/systemd/src/basic/sparse-endian.h
cp "$SYSTEMD_DIR"/src/basic/strv.c ./src/systemd/src/basic/strv.c
cp "$SYSTEMD_DIR"/src/basic/strv.h ./src/systemd/src/basic/strv.h
cp "$SYSTEMD_DIR"/src/basic/time-util.c ./src/systemd/src/basic/time-util.c
cp "$SYSTEMD_DIR"/src/basic/time-util.h ./src/systemd/src/basic/time-util.h
cp "$SYSTEMD_DIR"/src/basic/utf8.c ./src/systemd/src/basic/utf8.c
cp "$SYSTEMD_DIR"/src/basic/utf8.h ./src/systemd/src/basic/utf8.h
cp "$SYSTEMD_DIR"/src/basic/util.c ./src/systemd/src/basic/util.c
cp "$SYSTEMD_DIR"/src/basic/util.h ./src/systemd/src/basic/util.h
cp "$SYSTEMD_DIR"/src/basic/unaligned.h ./src/systemd/src/basic/unaligned.h
cp "$SYSTEMD_DIR"/src/basic/in-addr-util.c ./src/systemd/src/basic/in-addr-util.c
cp "$SYSTEMD_DIR"/src/basic/in-addr-util.h ./src/systemd/src/basic/in-addr-util.h
cp "$SYSTEMD_DIR"/src/basic/hostname-util.c ./src/systemd/src/basic/hostname-util.c
cp "$SYSTEMD_DIR"/src/basic/hostname-util.h ./src/systemd/src/basic/hostname-util.h
cp "$SYSTEMD_DIR"/src/basic/random-util.c ./src/systemd/src/basic/random-util.c
cp "$SYSTEMD_DIR"/src/basic/random-util.h ./src/systemd/src/basic/random-util.h
cp "$SYSTEMD_DIR"/src/shared/dns-domain.c ./src/systemd/src/shared/dns-domain.c
cp "$SYSTEMD_DIR"/src/shared/dns-domain.h ./src/systemd/src/shared/dns-domain.h
cp "$SYSTEMD_DIR"/src/systemd/_sd-common.h ./src/systemd/src/systemd/_sd-common.h
cp "$SYSTEMD_DIR"/src/systemd/sd-dhcp-client.h ./src/systemd/src/systemd/sd-dhcp-client.h
cp "$SYSTEMD_DIR"/src/systemd/sd-dhcp-lease.h ./src/systemd/src/systemd/sd-dhcp-lease.h
cp "$SYSTEMD_DIR"/src/systemd/sd-dhcp6-client.h ./src/systemd/src/systemd/sd-dhcp6-client.h
cp "$SYSTEMD_DIR"/src/systemd/sd-dhcp6-lease.h ./src/systemd/src/systemd/sd-dhcp6-lease.h
cp "$SYSTEMD_DIR"/src/systemd/sd-event.h ./src/systemd/src/systemd/sd-event.h
cp "$SYSTEMD_DIR"/src/systemd/sd-id128.h ./src/systemd/src/systemd/sd-id128.h
cp "$SYSTEMD_DIR"/src/systemd/sd-ipv4ll.h ./src/systemd/src/systemd/sd-ipv4ll.h
parent eab389bd
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2015 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <sys/utsname.h>
#include <ctype.h>
#include "util.h"
#include "hostname-util.h"
bool hostname_is_set(void) {
struct utsname u;
assert_se(uname(&u) >= 0);
if (isempty(u.nodename))
return false;
/* This is the built-in kernel default host name */
if (streq(u.nodename, "(none)"))
return false;
return true;
}
char* gethostname_malloc(void) {
struct utsname u;
assert_se(uname(&u) >= 0);
if (isempty(u.nodename) || streq(u.nodename, "(none)"))
return strdup(u.sysname);
return strdup(u.nodename);
}
static bool hostname_valid_char(char c) {
return
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') ||
c == '-' ||
c == '_' ||
c == '.';
}
bool hostname_is_valid(const char *s) {
const char *p;
bool dot;
if (isempty(s))
return false;
/* Doesn't accept empty hostnames, hostnames with trailing or
* leading dots, and hostnames with multiple dots in a
* sequence. Also ensures that the length stays below
* HOST_NAME_MAX. */
for (p = s, dot = true; *p; p++) {
if (*p == '.') {
if (dot)
return false;
dot = true;
} else {
if (!hostname_valid_char(*p))
return false;
dot = false;
}
}
if (dot)
return false;
if (p-s > HOST_NAME_MAX)
return false;
return true;
}
char* hostname_cleanup(char *s, bool lowercase) {
char *p, *d;
bool dot;
assert(s);
for (p = s, d = s, dot = true; *p; p++) {
if (*p == '.') {
if (dot)
continue;
*(d++) = '.';
dot = true;
} else if (hostname_valid_char(*p)) {
*(d++) = lowercase ? tolower(*p) : *p;
dot = false;
}
}
if (dot && d > s)
d[-1] = 0;
else
*d = 0;
strshorten(s, HOST_NAME_MAX);
return s;
}
bool is_localhost(const char *hostname) {
assert(hostname);
/* This tries to identify local host and domain names
* described in RFC6761 plus the redhatism of .localdomain */
return streq(hostname, "localhost") ||
streq(hostname, "localhost.") ||
streq(hostname, "localdomain.") ||
streq(hostname, "localdomain") ||
endswith(hostname, ".localhost") ||
endswith(hostname, ".localhost.") ||
endswith(hostname, ".localdomain") ||
endswith(hostname, ".localdomain.");
}
int sethostname_idempotent(const char *s) {
char buf[HOST_NAME_MAX + 1] = {};
assert(s);
if (gethostname(buf, sizeof(buf)) < 0)
return -errno;
if (streq(buf, s))
return 0;
if (sethostname(s, strlen(s)) < 0)
return -errno;
return 1;
}
int read_hostname_config(const char *path, char **hostname) {
_cleanup_fclose_ FILE *f = NULL;
char l[LINE_MAX];
char *name = NULL;
assert(path);
assert(hostname);
f = fopen(path, "re");
if (!f)
return -errno;
/* may have comments, ignore them */
FOREACH_LINE(l, f, return -errno) {
truncate_nl(l);
if (l[0] != '\0' && l[0] != '#') {
/* found line with value */
name = hostname_cleanup(l, false);
name = strdup(name);
if (!name)
return -ENOMEM;
break;
}
}
if (!name)
/* no non-empty line found */
return -ENOENT;
*hostname = name;
return 0;
}
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#pragma once
/***
This file is part of systemd.
Copyright 2010-2015 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdbool.h>
#include "macro.h"
bool hostname_is_set(void);
char* gethostname_malloc(void);
bool hostname_is_valid(const char *s) _pure_;
char* hostname_cleanup(char *s, bool lowercase);
bool is_localhost(const char *hostname);
int sethostname_idempotent(const char *s);
int read_hostname_config(const char *path, char **hostname);
......@@ -28,8 +28,8 @@
#include <sys/signalfd.h>
#include <errno.h>
#include "macro.h"
#include "sd-id128.h"
#include "macro.h"
typedef enum LogTarget{
LOG_TARGET_CONSOLE,
......@@ -204,8 +204,26 @@ LogTarget log_target_from_string(const char *s) _pure_;
/* Helpers to prepare various fields for structured logging */
#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__
#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x)
#define LOG_ERRNO(error) "ERRNO=%i", abs(error)
void log_received_signal(int level, const struct signalfd_siginfo *si);
void log_set_upgrade_syslog_to_journal(bool b);
int log_syntax_internal(
const char *unit,
int level,
const char *config_file,
unsigned config_line,
int error,
const char *file,
int line,
const char *func,
const char *format, ...) _printf_(9, 10);
#define log_syntax(unit, level, config_file, config_line, error, ...) \
({ \
int _level = (level), _e = (error); \
(log_get_max_level() >= LOG_PRI(_level)) \
? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
: -abs(_e); \
})
......@@ -248,10 +248,20 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
REENABLE_WARNING
#endif
#define assert_log(expr) ((_likely_(expr)) \
? (true) \
: (log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__), false))
#define assert_return(expr, r) \
do { \
if (_unlikely_(!(expr))) { \
log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
if (!assert_log(expr)) \
return (r); \
} while (false)
#define assert_return_errno(expr, r, err) \
do { \
if (!assert_log(expr)) { \
errno = err; \
return (r); \
} \
} while (false)
......@@ -458,4 +468,7 @@ do { \
} \
struct __useless_struct_to_allow_trailing_semicolon__
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
#include "log.h"
......@@ -33,6 +33,7 @@
#include "strv.h"
#include "path-util.h"
#include "missing.h"
#include "fileio.h"
bool path_is_absolute(const char *p) {
return p[0] == '/';
......@@ -470,25 +471,83 @@ char* path_join(const char *root, const char *path, const char *rest) {
NULL);
}
int fd_is_mount_point(int fd) {
static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {
char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *fdinfo = NULL;
_cleanup_close_ int subfd = -1;
char *p;
int r;
if ((flags & AT_EMPTY_PATH) && isempty(filename))
xsprintf(path, "/proc/self/fdinfo/%i", fd);
else {
subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
if (subfd < 0)
return -errno;
xsprintf(path, "/proc/self/fdinfo/%i", subfd);
}
r = read_full_file(path, &fdinfo, NULL);
if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */
return -EOPNOTSUPP;
if (r < 0)
return -errno;
p = startswith(fdinfo, "mnt_id:");
if (!p) {
p = strstr(fdinfo, "\nmnt_id:");
if (!p) /* The mnt_id field is a relatively new addition */
return -EOPNOTSUPP;
p += 8;
}
p += strspn(p, WHITESPACE);
p[strcspn(p, WHITESPACE)] = 0;
return safe_atoi(p, mnt_id);
}
int fd_is_mount_point(int fd, const char *filename, int flags) {
union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT;
int mount_id = -1, mount_id_parent = -1;
bool nosupp = false;
bool nosupp = false, check_st_dev = true;
struct stat a, b;
int r;
assert(fd >= 0);
/* We are not actually interested in the file handles, but
* name_to_handle_at() also passes us the mount ID, hence use
* it but throw the handle away */
r = name_to_handle_at(fd, "", &h.handle, &mount_id, AT_EMPTY_PATH);
assert(filename);
/* First we will try the name_to_handle_at() syscall, which
* tells us the mount id and an opaque file "handle". It is
* not supported everywhere though (kernel compile-time
* option, not all file systems are hooked up). If it works
* the mount id is usually good enough to tell us whether
* something is a mount point.
*
* If that didn't work we will try to read the mount id from
* /proc/self/fdinfo/<fd>. This is almost as good as
* name_to_handle_at(), however, does not return the the
* opaque file handle. The opaque file handle is pretty useful
* to detect the root directory, which we should always
* consider a mount point. Hence we use this only as
* fallback. Exporting the mnt_id in fdinfo is a pretty recent
* kernel addition.
*
* As last fallback we do traditional fstat() based st_dev
* comparisons. This is how things were traditionally done,
* but unionfs breaks breaks this since it exposes file
* systems with a variety of st_dev reported. Also, btrfs
* subvolumes have different st_dev, even though they aren't
* real mounts of their own. */
r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags);
if (r < 0) {
if (errno == ENOSYS)
/* This kernel does not support name_to_handle_at()
* fall back to the traditional stat() logic. */
goto fallback;
* fall back to simpler logic. */
goto fallback_fdinfo;
else if (errno == EOPNOTSUPP)
/* This kernel or file system does not support
* name_to_handle_at(), hence let's see if the
......@@ -500,13 +559,13 @@ int fd_is_mount_point(int fd) {
return -errno;
}
r = name_to_handle_at(fd, "..", &h_parent.handle, &mount_id_parent, 0);
r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH);
if (r < 0) {
if (errno == EOPNOTSUPP) {
if (nosupp)
/* Neither parent nor child do name_to_handle_at()?
We have no choice but to fall back. */
goto fallback;
goto fallback_fdinfo;
else
/* The parent can't do name_to_handle_at() but the
* directory we are interested in can?
......@@ -514,32 +573,59 @@ int fd_is_mount_point(int fd) {
return 1;
} else
return -errno;
} else if (nosupp)
/* The parent can do name_to_handle_at() but the
* directory we are interested in can't? If so, it
* must be a mount point. */
}
/* The parent can do name_to_handle_at() but the
* directory we are interested in can't? If so, it
* must be a mount point. */
if (nosupp)
return 1;
else {
/* If the file handle for the directory we are
* interested in and its parent are identical, we
* assume this is the root directory, which is a mount
* point. */
if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
h.handle.handle_type == h_parent.handle.handle_type &&
memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
return 1;
return mount_id != mount_id_parent;
}
/* If the file handle for the directory we are
* interested in and its parent are identical, we
* assume this is the root directory, which is a mount
* point. */
fallback:
r = fstatat(fd, "", &a, AT_EMPTY_PATH);
if (h.handle.handle_bytes == h_parent.handle.handle_bytes &&
h.handle.handle_type == h_parent.handle.handle_type &&
memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0)
return 1;
return mount_id != mount_id_parent;
fallback_fdinfo:
r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id);
if (r == -EOPNOTSUPP)
goto fallback_fstat;
if (r < 0)
return -errno;
return r;
r = fstatat(fd, "..", &b, 0);
r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent);
if (r < 0)
return r;
if (mount_id != mount_id_parent)
return 1;
/* Hmm, so, the mount ids are the same. This leaves one
* special case though for the root file system. For that,
* let's see if the parent directory has the same inode as we
* are interested in. Hence, let's also do fstat() checks now,
* too, but avoid the st_dev comparisons, since they aren't
* that useful on unionfs mounts. */
check_st_dev = false;
fallback_fstat:
/* yay for fstatat() taking a different set of flags than the other
* _at() above */
if (flags & AT_SYMLINK_FOLLOW)
flags &= ~AT_SYMLINK_FOLLOW;
else
flags |= AT_SYMLINK_NOFOLLOW;
if (fstatat(fd, filename, &a, flags) < 0)
return -errno;
if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0)
return -errno;
/* A directory with same device and inode as its parent? Must
......@@ -548,22 +634,39 @@ fallback:
a.st_ino == b.st_ino)
return 1;
return a.st_dev != b.st_dev;
return check_st_dev && (a.st_dev != b.st_dev);
}
int path_is_mount_point(const char *t, bool allow_symlink) {
/* flags can be AT_SYMLINK_FOLLOW or 0 */
int path_is_mount_point(const char *t, int flags) {
_cleanup_close_ int fd = -1;
_cleanup_free_ char *canonical = NULL, *parent = NULL;
int r;
assert(t);
if (path_equal(t, "/"))
return 1;
fd = openat(AT_FDCWD, t, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|(allow_symlink ? 0 : O_PATH));
/* we need to resolve symlinks manually, we can't just rely on
* fd_is_mount_point() to do that for us; if we have a structure like
* /bin -> /usr/bin/ and /usr is a mount point, then the parent that we
* look at needs to be /usr, not /. */
if (flags & AT_SYMLINK_FOLLOW) {
canonical = canonicalize_file_name(t);
if (!canonical)
return -errno;
}
r = path_get_parent(canonical ?: t, &parent);
if (r < 0)
return r;
fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
if (fd < 0)
return -errno;
return fd_is_mount_point(fd);
return fd_is_mount_point(fd, basename(canonical ?: t), flags);
}
int path_is_read_only_fs(const char *path) {
......@@ -714,3 +817,37 @@ int fsck_exists(const char *fstype) {
return 0;
}
char *prefix_root(const char *root, const char *path) {
char *n, *p;
size_t l;
/* If root is passed, prefixes path with it. Otherwise returns
* it as is. */
assert(path);
/* First, drop duplicate prefixing slashes from the path */
while (path[0] == '/' && path[1] == '/')
path++;
if (isempty(root) || path_equal(root, "/"))
return strdup(path);
l = strlen(root) + 1 + strlen(path) + 1;
n = new(char, l);
if (!n)
return NULL;
p = stpcpy(n, root);
while (p > n && p[-1] == '/')
p--;
if (path[0] != '/')
*(p++) = '/';
strcpy(p, path);
return n;
}
......@@ -53,8 +53,8 @@ char** path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *prefix);
char** path_strv_resolve_uniq(char **l, const char *prefix);
int fd_is_mount_point(int fd);
int path_is_mount_point(const char *path, bool allow_symlink);
int fd_is_mount_point(int fd, const char *filename, int flags);
int path_is_mount_point(const char *path, int flags);