summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-06-17 16:15:35 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2015-06-17 16:15:35 +0200
commitb34e1dc2fc92a71456e48d381b85aa0dbe8127b3 (patch)
treebdc3dc9b20a0783ff97b14a3aa2ddacd570d0cc3
parentfba17e5c84b983eb1b641e4ccb36409427f408bb (diff)
parent986228ea790571fd768b8b2b16e5f9423882a713 (diff)
downloadNetworkManager-bg/systemd-20150617.tar.gz
Merge branch 'systemd' into bg/systemd-20150617bg/systemd-20150617
-rw-r--r--src/Makefile.am55
-rw-r--r--src/systemd/src/basic/async.h (renamed from src/systemd/src/shared/async.h)0
-rw-r--r--src/systemd/src/basic/fileio.c (renamed from src/systemd/src/shared/fileio.c)0
-rw-r--r--src/systemd/src/basic/fileio.h (renamed from src/systemd/src/shared/fileio.h)0
-rw-r--r--src/systemd/src/basic/hostname-util.c199
-rw-r--r--src/systemd/src/basic/hostname-util.h41
-rw-r--r--src/systemd/src/basic/in-addr-util.c (renamed from src/systemd/src/shared/in-addr-util.c)0
-rw-r--r--src/systemd/src/basic/in-addr-util.h (renamed from src/systemd/src/shared/in-addr-util.h)0
-rw-r--r--src/systemd/src/basic/list.h (renamed from src/systemd/src/shared/list.h)0
-rw-r--r--src/systemd/src/basic/log.h (renamed from src/systemd/src/shared/log.h)22
-rw-r--r--src/systemd/src/basic/macro.h (renamed from src/systemd/src/shared/macro.h)12
-rw-r--r--src/systemd/src/basic/path-util.c (renamed from src/systemd/src/shared/path-util.c)209
-rw-r--r--src/systemd/src/basic/path-util.h (renamed from src/systemd/src/shared/path-util.h)31
-rw-r--r--src/systemd/src/basic/random-util.c137
-rw-r--r--src/systemd/src/basic/random-util.h40
-rw-r--r--src/systemd/src/basic/refcnt.h (renamed from src/systemd/src/shared/refcnt.h)0
-rw-r--r--src/systemd/src/basic/siphash24.c (renamed from src/systemd/src/shared/siphash24.c)0
-rw-r--r--src/systemd/src/basic/siphash24.h (renamed from src/systemd/src/shared/siphash24.h)0
-rw-r--r--src/systemd/src/basic/socket-util.h (renamed from src/systemd/src/shared/socket-util.h)1
-rw-r--r--src/systemd/src/basic/sparse-endian.h (renamed from src/systemd/src/shared/sparse-endian.h)0
-rw-r--r--src/systemd/src/basic/strv.c (renamed from src/systemd/src/shared/strv.c)0
-rw-r--r--src/systemd/src/basic/strv.h (renamed from src/systemd/src/shared/strv.h)0
-rw-r--r--src/systemd/src/basic/time-util.c (renamed from src/systemd/src/shared/time-util.c)15
-rw-r--r--src/systemd/src/basic/time-util.h (renamed from src/systemd/src/shared/time-util.h)2
-rw-r--r--src/systemd/src/basic/unaligned.h (renamed from src/systemd/src/shared/unaligned.h)0
-rw-r--r--src/systemd/src/basic/utf8.c (renamed from src/systemd/src/shared/utf8.c)13
-rw-r--r--src/systemd/src/basic/utf8.h (renamed from src/systemd/src/shared/utf8.h)2
-rw-r--r--src/systemd/src/basic/util.c (renamed from src/systemd/src/shared/util.c)2750
-rw-r--r--src/systemd/src/basic/util.h (renamed from src/systemd/src/shared/util.h)284
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-identifier.c10
-rw-r--r--src/systemd/src/libsystemd-network/dhcp-identifier.h3
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-client.c16
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp-lease.c16
-rw-r--r--src/systemd/src/libsystemd-network/sd-dhcp6-client.c2
-rw-r--r--src/systemd/src/libsystemd-network/sd-ipv4ll.c1
-rw-r--r--src/systemd/src/libsystemd/sd-id128/sd-id128.c1
-rw-r--r--src/systemd/src/shared/dns-domain.c617
-rw-r--r--src/systemd/src/shared/dns-domain.h64
38 files changed, 1828 insertions, 2715 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3aa8b5f4f9..67b3f20715 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -57,6 +57,7 @@ noinst_LTLIBRARIES = \
SYSTEMD_NM_CFLAGS = \
-I$(top_srcdir)/src/systemd/src/systemd \
-I$(top_srcdir)/src/systemd/src/libsystemd-network \
+ -I$(top_srcdir)/src/systemd/src/basic \
-I$(top_srcdir)/src/systemd/src/shared \
-I$(top_srcdir)/src/systemd
@@ -85,30 +86,36 @@ libsystemd_nm_la_SOURCES = \
systemd/src/libsystemd-network/sd-ipv4ll.c \
systemd/src/libsystemd-network/ipv4ll-packet.c \
systemd/src/libsystemd-network/ipv4ll-network.c \
- systemd/src/shared/async.h \
- systemd/src/shared/time-util.h \
- systemd/src/shared/siphash24.h \
- systemd/src/shared/time-util.c \
- systemd/src/shared/socket-util.h \
- systemd/src/shared/sparse-endian.h \
- systemd/src/shared/macro.h \
- systemd/src/shared/refcnt.h \
- systemd/src/shared/util.c \
- systemd/src/shared/in-addr-util.c \
- systemd/src/shared/siphash24.c \
- systemd/src/shared/util.h \
- systemd/src/shared/in-addr-util.h \
- systemd/src/shared/list.h \
- systemd/src/shared/log.h \
- systemd/src/shared/fileio.h \
- systemd/src/shared/fileio.c \
- systemd/src/shared/path-util.c \
- systemd/src/shared/path-util.h \
- systemd/src/shared/strv.h \
- systemd/src/shared/strv.c \
- systemd/src/shared/unaligned.h \
- systemd/src/shared/utf8.h \
- systemd/src/shared/utf8.c \
+ systemd/src/basic/async.h \
+ systemd/src/basic/time-util.h \
+ systemd/src/basic/siphash24.h \
+ systemd/src/basic/time-util.c \
+ systemd/src/basic/socket-util.h \
+ systemd/src/basic/sparse-endian.h \
+ systemd/src/basic/macro.h \
+ systemd/src/basic/refcnt.h \
+ systemd/src/basic/util.c \
+ systemd/src/basic/in-addr-util.c \
+ systemd/src/basic/siphash24.c \
+ systemd/src/basic/util.h \
+ systemd/src/basic/in-addr-util.h \
+ systemd/src/basic/hostname-util.c \
+ systemd/src/basic/hostname-util.h \
+ systemd/src/basic/list.h \
+ systemd/src/basic/log.h \
+ systemd/src/basic/fileio.h \
+ systemd/src/basic/fileio.c \
+ systemd/src/basic/path-util.c \
+ systemd/src/basic/path-util.h \
+ systemd/src/basic/strv.h \
+ systemd/src/basic/strv.c \
+ systemd/src/basic/unaligned.h \
+ systemd/src/basic/utf8.h \
+ systemd/src/basic/utf8.c \
+ systemd/src/basic/random-util.h \
+ systemd/src/basic/random-util.c \
+ systemd/src/shared/dns-domain.h \
+ systemd/src/shared/dns-domain.c \
systemd/src/systemd/sd-dhcp-lease.h \
systemd/src/systemd/sd-dhcp-client.h \
systemd/src/systemd/sd-id128.h \
diff --git a/src/systemd/src/shared/async.h b/src/systemd/src/basic/async.h
index 44b886a661..44b886a661 100644
--- a/src/systemd/src/shared/async.h
+++ b/src/systemd/src/basic/async.h
diff --git a/src/systemd/src/shared/fileio.c b/src/systemd/src/basic/fileio.c
index d167c18cce..d167c18cce 100644
--- a/src/systemd/src/shared/fileio.c
+++ b/src/systemd/src/basic/fileio.c
diff --git a/src/systemd/src/shared/fileio.h b/src/systemd/src/basic/fileio.h
index fccea7725a..fccea7725a 100644
--- a/src/systemd/src/shared/fileio.h
+++ b/src/systemd/src/basic/fileio.h
diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c
new file mode 100644
index 0000000000..82139883eb
--- /dev/null
+++ b/src/systemd/src/basic/hostname-util.c
@@ -0,0 +1,199 @@
+/*-*- 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 "nm-sd-adapt.h"
+
+#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;
+}
+
+#if 0 /* NM_IGNORED */
+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;
+}
+#endif
+
+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.");
+}
+
+#if 0 /* NM_IGNORED */
+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;
+}
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/hostname-util.h b/src/systemd/src/basic/hostname-util.h
new file mode 100644
index 0000000000..ccd680344e
--- /dev/null
+++ b/src/systemd/src/basic/hostname-util.h
@@ -0,0 +1,41 @@
+/*-*- 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 "nm-sd-adapt.h"
+
+#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);
diff --git a/src/systemd/src/shared/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c
index 488f6d1ebd..488f6d1ebd 100644
--- a/src/systemd/src/shared/in-addr-util.c
+++ b/src/systemd/src/basic/in-addr-util.c
diff --git a/src/systemd/src/shared/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h
index 715ded330f..715ded330f 100644
--- a/src/systemd/src/shared/in-addr-util.h
+++ b/src/systemd/src/basic/in-addr-util.h
diff --git a/src/systemd/src/shared/list.h b/src/systemd/src/basic/list.h
index af121d7009..af121d7009 100644
--- a/src/systemd/src/shared/list.h
+++ b/src/systemd/src/basic/list.h
diff --git a/src/systemd/src/shared/log.h b/src/systemd/src/basic/log.h
index e9cfe1a287..0514234426 100644
--- a/src/systemd/src/shared/log.h
+++ b/src/systemd/src/basic/log.h
@@ -30,8 +30,8 @@
#include <sys/signalfd.h>
#include <errno.h>
-#include "macro.h"
#include "sd-id128.h"
+#include "macro.h"
typedef enum LogTarget{
LOG_TARGET_CONSOLE,
@@ -208,8 +208,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); \
+ })
diff --git a/src/systemd/src/shared/macro.h b/src/systemd/src/basic/macro.h
index d5cb240b3b..9738ad0b03 100644
--- a/src/systemd/src/shared/macro.h
+++ b/src/systemd/src/basic/macro.h
@@ -258,6 +258,15 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
} \
} while (false)
+#define assert_return_errno(expr, r, err) \
+ do { \
+ if (_unlikely_(!(expr))) { \
+ log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ errno = err; \
+ return (r); \
+ } \
+ } while (false)
+
#define PTR_TO_INT(p) ((int) ((intptr_t) (p)))
#define INT_TO_PTR(u) ((void *) ((intptr_t) (u)))
#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p)))
@@ -462,4 +471,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"
diff --git a/src/systemd/src/shared/path-util.c b/src/systemd/src/basic/path-util.c
index 9b12b4ad46..39ece8b6a9 100644
--- a/src/systemd/src/shared/path-util.c
+++ b/src/systemd/src/basic/path-util.c
@@ -38,6 +38,7 @@
#include "path-util.h"
#if 0 /* NM_IGNORED */
#include "missing.h"
+#include "fileio.h"
bool path_is_absolute(const char *p) {
return p[0] == '/';
@@ -477,25 +478,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
@@ -507,13 +566,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?
@@ -521,32 +580,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
@@ -555,22 +641,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) {
@@ -721,4 +824,38 @@ 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;
+}
#endif /* NM_IGNORED */
diff --git a/src/systemd/src/shared/path-util.h b/src/systemd/src/basic/path-util.h
index 3dca8192b8..26006946c4 100644
--- a/src/systemd/src/shared/path-util.h
+++ b/src/systemd/src/basic/path-util.h
@@ -55,8 +55,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);
int path_is_read_only_fs(const char *path);
int path_is_os_tree(const char *path);
@@ -75,3 +75,30 @@ int fsck_exists(const char *fstype);
/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
#define PATH_FOREACH_PREFIX_MORE(prefix, path) \
for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
+
+char *prefix_root(const char *root, const char *path);
+
+/* Similar to prefix_root(), but returns an alloca() buffer, or
+ * possibly a const pointer into the path parameter */
+#define prefix_roota(root, path) \
+ ({ \
+ const char* _path = (path), *_root = (root), *_ret; \
+ char *_p, *_n; \
+ size_t _l; \
+ while (_path[0] == '/' && _path[1] == '/') \
+ _path ++; \
+ if (isempty(_root) || path_equal(_root, "/")) \
+ _ret = _path; \
+ else { \
+ _l = strlen(_root) + 1 + strlen(_path) + 1; \
+ _n = alloca(_l); \
+ _p = stpcpy(_n, _root); \
+ while (_p > _n && _p[-1] == '/') \
+ _p--; \
+ if (_path[0] != '/') \
+ *(_p++) = '/'; \
+ strcpy(_p, _path); \
+ _ret = _n; \
+ } \
+ _ret; \
+ })
diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c
new file mode 100644
index 0000000000..bdcd2c54eb
--- /dev/null
+++ b/src/systemd/src/basic/random-util.c
@@ -0,0 +1,137 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 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 "nm-sd-adapt.h"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_SYS_AUXV_H
+#include <sys/auxv.h>
+#endif
+#include <linux/random.h>
+
+#include "random-util.h"
+#include "time-util.h"
+#if 0 /* NM_IGNORED */
+#include "missing.h"
+#endif /* NM_IGNORED */
+#include "util.h"
+
+int dev_urandom(void *p, size_t n) {
+#if 0 /* NM_IGNORED */
+ static int have_syscall = -1;
+
+ _cleanup_close_ int fd = -1;
+ int r;
+
+ /* Gathers some randomness from the kernel. This call will
+ * never block, and will always return some data from the
+ * kernel, regardless if the random pool is fully initialized
+ * or not. It thus makes no guarantee for the quality of the
+ * returned entropy, but is good enough for or usual usecases
+ * of seeding the hash functions for hashtable */
+
+ /* Use the getrandom() syscall unless we know we don't have
+ * it, or when the requested size is too large for it. */
+ if (have_syscall != 0 || (size_t) (int) n != n) {
+ r = getrandom(p, n, GRND_NONBLOCK);
+ if (r == (int) n) {
+ have_syscall = true;
+ return 0;
+ }
+
+ if (r < 0) {
+ if (errno == ENOSYS)
+ /* we lack the syscall, continue with
+ * reading from /dev/urandom */
+ have_syscall = false;
+ else if (errno == EAGAIN)
+ /* not enough entropy for now. Let's
+ * remember to use the syscall the
+ * next time, again, but also read
+ * from /dev/urandom for now, which
+ * doesn't care about the current
+ * amount of entropy. */
+ have_syscall = true;
+ else
+ return -errno;
+ } else
+ /* too short read? */
+ return -ENODATA;
+ }
+#else /* NM_IGNORED */
+ _cleanup_close_ int fd = -1;
+#endif /* NM_IGNORED */
+
+ fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ return errno == ENOENT ? -ENOSYS : -errno;
+
+ return loop_read_exact(fd, p, n, true);
+}
+
+void initialize_srand(void) {
+ static bool srand_called = false;
+ unsigned x;
+#ifdef HAVE_SYS_AUXV_H
+ void *auxv;
+#endif
+
+ if (srand_called)
+ return;
+
+ x = 0;
+
+#ifdef HAVE_SYS_AUXV_H
+ /* The kernel provides us with a bit of entropy in auxv, so
+ * let's try to make use of that to seed the pseudo-random
+ * generator. It's better than nothing... */
+
+ auxv = (void*) getauxval(AT_RANDOM);
+ if (auxv)
+ x ^= *(unsigned*) auxv;
+#endif
+
+ x ^= (unsigned) now(CLOCK_REALTIME);
+ x ^= (unsigned) gettid();
+
+ srand(x);
+ srand_called = true;
+}
+
+void random_bytes(void *p, size_t n) {
+ uint8_t *q;
+ int r;
+
+ r = dev_urandom(p, n);
+ if (r >= 0)
+ return;
+
+ /* If some idiot made /dev/urandom unavailable to us, he'll
+ * get a PRNG instead. */
+
+ initialize_srand();
+
+ for (q = p; q < (uint8_t*) p + n; q ++)
+ *q = rand();
+}
diff --git a/src/systemd/src/basic/random-util.h b/src/systemd/src/basic/random-util.h
new file mode 100644
index 0000000000..3575ee96d3
--- /dev/null
+++ b/src/systemd/src/basic/random-util.h
@@ -0,0 +1,40 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 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 "nm-sd-adapt.h"
+
+#include <stdint.h>
+
+int dev_urandom(void *p, size_t n);
+void random_bytes(void *p, size_t n);
+void initialize_srand(void);
+
+static inline uint64_t random_u64(void) {
+ uint64_t u;
+ random_bytes(&u, sizeof(u));
+ return u;
+}
+
+static inline uint32_t random_u32(void) {
+ uint32_t u;
+ random_bytes(&u, sizeof(u));
+ return u;
+}
diff --git a/src/systemd/src/shared/refcnt.h b/src/systemd/src/basic/refcnt.h
index e6e9a6bd6e..e6e9a6bd6e 100644
--- a/src/systemd/src/shared/refcnt.h
+++ b/src/systemd/src/basic/refcnt.h
diff --git a/src/systemd/src/shared/siphash24.c b/src/systemd/src/basic/siphash24.c
index a26f8e28ca..a26f8e28ca 100644
--- a/src/systemd/src/shared/siphash24.c
+++ b/src/systemd/src/basic/siphash24.c
diff --git a/src/systemd/src/shared/siphash24.h b/src/systemd/src/basic/siphash24.h
index 3450d754fe..3450d754fe 100644
--- a/src/systemd/src/shared/siphash24.h
+++ b/src/systemd/src/basic/siphash24.h
diff --git a/src/systemd/src/shared/socket-util.h b/src/systemd/src/basic/socket-util.h
index 3cbaf0f982..0a977b5690 100644
--- a/src/systemd/src/shared/socket-util.h
+++ b/src/systemd/src/basic/socket-util.h
@@ -68,6 +68,7 @@ typedef enum SocketAddressBindIPv6Only {
#define socket_address_family(a) ((a)->sockaddr.sa.sa_family)
int socket_address_parse(SocketAddress *a, const char *s);
+int socket_address_parse_and_warn(SocketAddress *a, const char *s);
int socket_address_parse_netlink(SocketAddress *a, const char *s);
int socket_address_print(const SocketAddress *a, char **p);
int socket_address_verify(const SocketAddress *a) _pure_;
diff --git a/src/systemd/src/shared/sparse-endian.h b/src/systemd/src/basic/sparse-endian.h
index 02de0feca8..02de0feca8 100644
--- a/src/systemd/src/shared/sparse-endian.h
+++ b/src/systemd/src/basic/sparse-endian.h
diff --git a/src/systemd/src/shared/strv.c b/src/systemd/src/basic/strv.c
index df44f61907..df44f61907 100644
--- a/src/systemd/src/shared/strv.c
+++ b/src/systemd/src/basic/strv.c
diff --git a/src/systemd/src/shared/strv.h b/src/systemd/src/basic/strv.h
index b583080739..b583080739 100644
--- a/src/systemd/src/shared/strv.h
+++ b/src/systemd/src/basic/strv.h
diff --git a/src/systemd/src/shared/time-util.c b/src/systemd/src/basic/time-util.c
index f1e56b6e47..66f91825bc 100644
--- a/src/systemd/src/shared/time-util.c
+++ b/src/systemd/src/basic/time-util.c
@@ -405,18 +405,21 @@ void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) {
t->monotonic);
}
-void dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
+int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
unsigned long long a, b;
assert(value);
assert(t);
- if (sscanf(value, "%llu %llu", &a, &b) != 2)
- log_debug("Failed to parse finish timestamp value %s", value);
- else {
- t->realtime = a;
- t->monotonic = b;
+ if (sscanf(value, "%llu %llu", &a, &b) != 2) {
+ log_debug("Failed to parse finish timestamp value %s.", value);
+ return -EINVAL;
}
+
+ t->realtime = a;
+ t->monotonic = b;
+
+ return 0;
}
int parse_timestamp(const char *t, usec_t *usec) {
diff --git a/src/systemd/src/shared/time-util.h b/src/systemd/src/basic/time-util.h
index 5d5aa10db4..480c39d902 100644
--- a/src/systemd/src/shared/time-util.h
+++ b/src/systemd/src/basic/time-util.h
@@ -96,7 +96,7 @@ char *format_timestamp_relative(char *buf, size_t l, usec_t t);
char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
-void dual_timestamp_deserialize(const char *value, dual_timestamp *t);
+int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
int parse_timestamp(const char *t, usec_t *usec);
diff --git a/src/systemd/src/shared/unaligned.h b/src/systemd/src/basic/unaligned.h
index 3b73a9c682..3b73a9c682 100644
--- a/src/systemd/src/shared/unaligned.h
+++ b/src/systemd/src/basic/unaligned.h
diff --git a/src/systemd/src/shared/utf8.c b/src/systemd/src/basic/utf8.c
index 7433f9b059..64f2fc3adb 100644
--- a/src/systemd/src/shared/utf8.c
+++ b/src/systemd/src/basic/utf8.c
@@ -54,7 +54,7 @@
#include "utf8.h"
#include "util.h"
-static inline bool is_unicode_valid(uint32_t ch) {
+bool unichar_is_valid(uint32_t ch) {
if (ch >= 0x110000) /* End of unicode space */
return false;
@@ -68,7 +68,7 @@ static inline bool is_unicode_valid(uint32_t ch) {
return true;
}
-static bool is_unicode_control(uint32_t ch) {
+static bool unichar_is_control(uint32_t ch) {
/*
0 to ' '-1 is the C0 range.
@@ -158,7 +158,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
val = utf8_encoded_to_unichar(p);
if (val < 0 ||
- is_unicode_control(val) ||
+ unichar_is_control(val) ||
(!newline && val == '\n'))
return false;
@@ -278,6 +278,7 @@ char *ascii_is_valid(const char *str) {
* occupy.
*/
size_t utf8_encode_unichar(char *out_utf8, uint32_t g) {
+
if (g < (1 << 7)) {
if (out_utf8)
out_utf8[0] = g & 0x7f;
@@ -303,9 +304,9 @@ size_t utf8_encode_unichar(char *out_utf8, uint32_t g) {
out_utf8[3] = 0x80 | (g & 0x3f);
}
return 4;
- } else {
- return 0;
}
+
+ return 0;
}
char *utf16_to_utf8(const void *s, size_t length) {
@@ -396,7 +397,7 @@ int utf8_encoded_valid_unichar(const char *str) {
return -EINVAL;
/* check if value has valid range */
- if (!is_unicode_valid(unichar))
+ if (!unichar_is_valid(unichar))
return -EINVAL;
return len;
diff --git a/src/systemd/src/shared/utf8.h b/src/systemd/src/basic/utf8.h
index 1fb132041e..9e6d95b1fc 100644
--- a/src/systemd/src/shared/utf8.h
+++ b/src/systemd/src/basic/utf8.h
@@ -29,6 +29,8 @@
#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
+bool unichar_is_valid(uint32_t c);
+
const char *utf8_is_valid(const char *s) _pure_;
char *ascii_is_valid(const char *s) _pure_;
diff --git a/src/systemd/src/shared/util.c b/src/systemd/src/basic/util.c
index 8e1a29a1eb..6b75962e68 100644
--- a/src/systemd/src/shared/util.c
+++ b/src/systemd/src/basic/util.c
@@ -37,9 +37,6 @@
#include <fcntl.h>
#include <dirent.h>
#include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <linux/tiocl.h>
-#include <termios.h>
#include <stdarg.h>
#include <poll.h>
#include <ctype.h>
@@ -47,7 +44,6 @@
#include <sys/utsname.h>
#include <pwd.h>
#include <netinet/ip.h>
-#include <linux/kd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <glob.h>
@@ -92,12 +88,22 @@
#include "env-util.h"
#include "fileio.h"
#include "device-nodes.h"
+#endif /* NM_IGNORED */
#include "utf8.h"
+#if 0 /* NM_IGNORED */
#include "gunicode.h"
#include "virt.h"
#include "def.h"
#include "sparse-endian.h"
+#include "formats-util.h"
+#include "random-util.h"
+#include "terminal-util.h"
+#include "signal-util.h"
#endif /* NM_IGNORED */
+#include "hostname-util.h"
+#if 0 /* NM_IGNORED */
+#include "process-util.h"
+#endif
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
@@ -106,9 +112,6 @@ assert_cc(EAGAIN == EWOULDBLOCK);
int saved_argc = 0;
char **saved_argv = NULL;
-static volatile unsigned cached_columns = 0;
-static volatile unsigned cached_lines = 0;
-
size_t page_size(void) {
static thread_local size_t pgsz = 0;
long r;
@@ -158,6 +161,27 @@ char* endswith(const char *s, const char *postfix) {
return (char*) s + sl - pl;
}
+char* endswith_no_case(const char *s, const char *postfix) {
+ size_t sl, pl;
+
+ assert(s);
+ assert(postfix);
+
+ sl = strlen(s);
+ pl = strlen(postfix);
+
+ if (pl == 0)
+ return (char*) s + sl;
+
+ if (sl < pl)
+ return NULL;
+
+ if (strcasecmp(s + sl - pl, postfix) != 0)
+ return NULL;
+
+ return (char*) s + sl - pl;
+}
+
char* first_word(const char *s, const char *word) {
size_t sl, wl;
const char *p;
@@ -192,7 +216,7 @@ char* first_word(const char *s, const char *word) {
return (char*) p;
}
-static size_t cescape_char(char c, char *buf) {
+size_t cescape_char(char c, char *buf) {
char * buf_old = buf;
switch (c) {
@@ -362,7 +386,6 @@ int parse_uid(const char *s, uid_t* ret_uid) {
int r;
assert(s);
- assert(ret_uid);
r = safe_atolu(s, &ul);
if (r < 0)
@@ -381,7 +404,9 @@ int parse_uid(const char *s, uid_t* ret_uid) {
if (uid == (uid_t) 0xFFFF)
return -ENXIO;
- *ret_uid = uid;
+ if (ret_uid)
+ *ret_uid = uid;
+
return 0;
}
#endif /* NM_IGNORED */
@@ -585,13 +610,12 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
char quotechars[2] = {*current, '\0'};
*l = strcspn_escaped(current + 1, quotechars);
- if (current[*l + 1] == '\0' ||
+ if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
(current[*l + 2] && !strchr(separator, current[*l + 2]))) {
/* right quote missing or garbage at the end */
*state = current;
return NULL;
}
- assert(current[*l + 1] == quotechars[0]);
*state = current++ + *l + 2;
} else if (quoted) {
*l = strcspn_escaped(current, separator);
@@ -609,51 +633,6 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
return current;
}
-#if 0 /* NM_IGNORED */
-int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
- int r;
- _cleanup_free_ char *line = NULL;
- long unsigned ppid;
- const char *p;
-
- assert(pid >= 0);
- assert(_ppid);
-
- if (pid == 0) {
- *_ppid = getppid();
- return 0;
- }
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- /* Let's skip the pid and comm fields. The latter is enclosed
- * in () but does not escape any () in its value, so let's
- * skip over it manually */
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " "
- "%*c " /* state */
- "%lu ", /* ppid */
- &ppid) != 1)
- return -EIO;
-
- if ((long unsigned) (pid_t) ppid != ppid)
- return -ERANGE;
-
- *_ppid = (pid_t) ppid;
-
- return 0;
-}
-#endif /* NM_IGNORED */
-
int fchmod_umask(int fd, mode_t m) {
mode_t u;
int r;
@@ -672,310 +651,6 @@ char *truncate_nl(char *s) {
return s;
}
-#if 0 /* NM_IGNORED */
-int get_process_state(pid_t pid) {
- const char *p;
- char state;
- int r;
- _cleanup_free_ char *line = NULL;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " %c", &state) != 1)
- return -EIO;
-
- return (unsigned char) state;
-}
-
-int get_process_comm(pid_t pid, char **name) {
- const char *p;
- int r;
-
- assert(name);
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "comm");
-
- r = read_one_line_file(p, name);
- if (r == -ENOENT)
- return -ESRCH;
-
- return r;
-}
-
-int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
- _cleanup_fclose_ FILE *f = NULL;
- char *r = NULL, *k;
- const char *p;
- int c;
-
- assert(line);
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "cmdline");
-
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- if (max_length == 0) {
- size_t len = 0, allocated = 0;
-
- while ((c = getc(f)) != EOF) {
-
- if (!GREEDY_REALLOC(r, allocated, len+2)) {
- free(r);
- return -ENOMEM;
- }
-
- r[len++] = isprint(c) ? c : ' ';
- }
-
- if (len > 0)
- r[len-1] = 0;
-
- } else {
- bool space = false;
- size_t left;
-
- r = new(char, max_length);
- if (!r)
- return -ENOMEM;
-
- k = r;
- left = max_length;
- while ((c = getc(f)) != EOF) {
-
- if (isprint(c)) {
- if (space) {
- if (left <= 4)
- break;
-
- *(k++) = ' ';
- left--;
- space = false;
- }
-
- if (left <= 4)
- break;
-
- *(k++) = (char) c;
- left--;
- } else
- space = true;
- }
-
- if (left <= 4) {
- size_t n = MIN(left-1, 3U);
- memcpy(k, "...", n);
- k[n] = 0;
- } else
- *k = 0;
- }
-
- /* Kernel threads have no argv[] */
- if (isempty(r)) {
- _cleanup_free_ char *t = NULL;
- int h;
-
- free(r);
-
- if (!comm_fallback)
- return -ENOENT;
-
- h = get_process_comm(pid, &t);
- if (h < 0)
- return h;
-
- r = strjoin("[", t, "]", NULL);
- if (!r)
- return -ENOMEM;
- }
-
- *line = r;
- return 0;
-}
-
-int is_kernel_thread(pid_t pid) {
- const char *p;
- size_t count;
- char c;
- bool eof;
- FILE *f;
-
- if (pid == 0)
- return 0;
-
- assert(pid > 0);
-
- p = procfs_file_alloca(pid, "cmdline");
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- count = fread(&c, 1, 1, f);
- eof = feof(f);
- fclose(f);
-
- /* Kernel threads have an empty cmdline */
-
- if (count <= 0)
- return eof ? 1 : -errno;
-
- return 0;
-}
-
-int get_process_capeff(pid_t pid, char **capeff) {
- const char *p;
-
- assert(capeff);
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "status");
-
- return get_status_field(p, "\nCapEff:", capeff);
-}
-
-static int get_process_link_contents(const char *proc_file, char **name) {
- int r;
-
- assert(proc_file);
- assert(name);
-
- r = readlink_malloc(proc_file, name);
- if (r < 0)
- return r == -ENOENT ? -ESRCH : r;
-
- return 0;
-}
-
-int get_process_exe(pid_t pid, char **name) {
- const char *p;
- char *d;
- int r;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "exe");
- r = get_process_link_contents(p, name);
- if (r < 0)
- return r;
-
- d = endswith(*name, " (deleted)");
- if (d)
- *d = '\0';
-
- return 0;
-}
-
-static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
- _cleanup_fclose_ FILE *f = NULL;
- char line[LINE_MAX];
- const char *p;
-
- assert(field);
- assert(uid);
-
- if (pid == 0)
- return getuid();
-
- p = procfs_file_alloca(pid, "status");
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- FOREACH_LINE(line, f, return -errno) {
- char *l;
-
- l = strstrip(line);
-
- if (startswith(l, field)) {
- l += strlen(field);
- l += strspn(l, WHITESPACE);
-
- l[strcspn(l, WHITESPACE)] = 0;
-
- return parse_uid(l, uid);
- }
- }
-
- return -EIO;
-}
-
-int get_process_uid(pid_t pid, uid_t *uid) {
- return get_process_id(pid, "Uid:", uid);
-}
-
-int get_process_gid(pid_t pid, gid_t *gid) {
- assert_cc(sizeof(uid_t) == sizeof(gid_t));
- return get_process_id(pid, "Gid:", gid);
-}
-
-int get_process_cwd(pid_t pid, char **cwd) {
- const char *p;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "cwd");
-
- return get_process_link_contents(p, cwd);
-}
-
-int get_process_root(pid_t pid, char **root) {
- const char *p;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "root");
-
- return get_process_link_contents(p, root);
-}
-
-int get_process_environ(pid_t pid, char **env) {
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *outcome = NULL;
- int c;
- const char *p;
- size_t allocated = 0, sz = 0;
-
- assert(pid >= 0);
- assert(env);
-
- p = procfs_file_alloca(pid, "environ");
-
- f = fopen(p, "re");
- if (!f)
- return -errno;
-
- while ((c = fgetc(f)) != EOF) {
- if (!GREEDY_REALLOC(outcome, allocated, sz + 5))
- return -ENOMEM;
-
- if (c == '\0')
- outcome[sz++] = '\n';
- else
- sz += cescape_char(c, outcome + sz);
- }
-
- outcome[sz] = '\0';
- *env = outcome;
- outcome = NULL;
-
- return 0;
-}
-#endif /* NM_IGNORED */
-
char *strnappend(const char *s, const char *suffix, size_t b) {
size_t a;
char *r;
@@ -1113,41 +788,6 @@ int readlink_and_canonicalize(const char *p, char **r) {
return 0;
}
-
-int reset_all_signal_handlers(void) {
- int sig, r = 0;
-
- for (sig = 1; sig < _NSIG; sig++) {
- struct sigaction sa = {
- .sa_handler = SIG_DFL,
- .sa_flags = SA_RESTART,
- };
-
- /* These two cannot be caught... */
- if (sig == SIGKILL || sig == SIGSTOP)
- continue;
-
- /* On Linux the first two RT signals are reserved by
- * glibc, and sigaction() will return EINVAL for them. */
- if ((sigaction(sig, &sa, NULL) < 0))
- if (errno != EINVAL && r == 0)
- r = -errno;
- }
-
- return r;
-}
-
-int reset_signal_mask(void) {
- sigset_t ss;
-
- if (sigemptyset(&ss) < 0)
- return -errno;
-
- if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
- return -errno;
-
- return 0;
-}
#endif /* NM_IGNORED */
char *strstrip(char *s) {
@@ -1352,7 +992,8 @@ char *cescape(const char *s) {
assert(s);
- /* Does C style string escaping. */
+ /* Does C style string escaping. May be reversed with
+ * cunescape(). */
r = new(char, strlen(s)*4 + 1);
if (!r)
@@ -1366,13 +1007,17 @@ char *cescape(const char *s) {
return r;
}
-static int cunescape_one(const char *p, size_t length, char *ret) {
+static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
int r = 1;
assert(p);
assert(*p);
assert(ret);
+ /* Unescapes C style. Returns the unescaped character in ret,
+ * unless we encountered a \u sequence in which case the full
+ * unicode character is returned in ret_unicode, instead. */
+
if (length != (size_t) -1 && length < 1)
return -EINVAL;
@@ -1429,15 +1074,92 @@ static int cunescape_one(const char *p, size_t length, char *ret) {
if (b < 0)
return -EINVAL;
- /* don't allow NUL bytes */
+ /* Don't allow NUL bytes */
if (a == 0 && b == 0)
return -EINVAL;
- *ret = (char) ((a << 4) | b);
+ *ret = (char) ((a << 4U) | b);
r = 3;
break;
}
+ case 'u': {
+ /* C++11 style 16bit unicode */
+
+ int a[4];
+ unsigned i;
+ uint32_t c;
+
+ if (length != (size_t) -1 && length < 5)
+ return -EINVAL;
+
+ for (i = 0; i < 4; i++) {
+ a[i] = unhexchar(p[1 + i]);
+ if (a[i] < 0)
+ return a[i];
+ }
+
+ c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
+
+ /* Don't allow 0 chars */
+ if (c == 0)
+ return -EINVAL;
+
+ if (c < 128)
+ *ret = c;
+ else {
+ if (!ret_unicode)
+ return -EINVAL;
+
+ *ret = 0;
+ *ret_unicode = c;
+ }
+
+ r = 5;
+ break;
+ }
+
+ case 'U': {
+ /* C++11 style 32bit unicode */
+
+ int a[8];
+ unsigned i;
+ uint32_t c;
+
+ if (length != (size_t) -1 && length < 9)
+ return -EINVAL;
+
+ for (i = 0; i < 8; i++) {
+ a[i] = unhexchar(p[1 + i]);
+ if (a[i] < 0)
+ return a[i];
+ }
+
+ c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
+ ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7];
+
+ /* Don't allow 0 chars */
+ if (c == 0)
+ return -EINVAL;
+
+ /* Don't allow invalid code points */
+ if (!unichar_is_valid(c))
+ return -EINVAL;
+
+ if (c < 128)
+ *ret = c;
+ else {
+ if (!ret_unicode)
+ return -EINVAL;
+
+ *ret = 0;
+ *ret_unicode = c;
+ }
+
+ r = 9;
+ break;
+ }
+
case '0':
case '1':
case '2':
@@ -1447,9 +1169,10 @@ static int cunescape_one(const char *p, size_t length, char *ret) {
case '6':
case '7': {
/* octal encoding */
- int a, b, c, m;
+ int a, b, c;
+ uint32_t m;
- if (length != (size_t) -1 && length < 4)
+ if (length != (size_t) -1 && length < 3)
return -EINVAL;
a = unoctchar(p[0]);
@@ -1469,11 +1192,11 @@ static int cunescape_one(const char *p, size_t length, char *ret) {
return -EINVAL;
/* Don't allow bytes above 255 */
- m = (a << 6) | (b << 3) | c;
+ m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
if (m > 255)
return -EINVAL;
- *ret = (char) m;
+ *ret = m;
r = 3;
break;
}
@@ -1506,6 +1229,8 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
for (f = s, t = r + pl; f < s + length; f++) {
size_t remaining;
+ uint32_t u;
+ char c;
int k;
remaining = s + length - f;
@@ -1524,10 +1249,11 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
continue;
}
+ free(r);
return -EINVAL;
}
- k = cunescape_one(f + 1, remaining - 1, t);
+ k = cunescape_one(f + 1, remaining - 1, &c, &u);
if (k < 0) {
if (flags & UNESCAPE_RELAX) {
/* Invalid escape code, let's take it literal then */
@@ -1535,11 +1261,18 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
continue;
}
+ free(r);
return k;
}
+ if (c != 0)
+ /* Non-Unicode? Let's encode this directly */
+ *(t++) = c;
+ else
+ /* Unicode? Then let's encode this in UTF-8 */
+ t += utf8_encode_unichar(t, u);
+
f += k;
- t++;
}
*t = 0;
@@ -1563,7 +1296,7 @@ char *xescape(const char *s, const char *bad) {
/* Escapes all chars in bad, in addition to \ and all special
* chars, in \xFF style escaping. May be reversed with
- * cunescape. */
+ * cunescape(). */
r = new(char, strlen(s) * 4 + 1);
if (!r)
@@ -1781,301 +1514,6 @@ bool fstype_is_network(const char *fstype) {
return nulstr_contains(table, fstype);
}
-int chvt(int vt) {
- _cleanup_close_ int fd;
-
- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- if (vt < 0) {
- int tiocl[2] = {
- TIOCL_GETKMSGREDIRECT,
- 0
- };
-
- if (ioctl(fd, TIOCLINUX, tiocl) < 0)
- return -errno;
-
- vt = tiocl[0] <= 0 ? 1 : tiocl[0];
- }
-
- if (ioctl(fd, VT_ACTIVATE, vt) < 0)
- return -errno;
-
- return 0;
-}
-
-int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
- struct termios old_termios, new_termios;
- char c, line[LINE_MAX];
-
- assert(f);
- assert(ret);
-
- if (tcgetattr(fileno(f), &old_termios) >= 0) {
- new_termios = old_termios;
-
- new_termios.c_lflag &= ~ICANON;
- new_termios.c_cc[VMIN] = 1;
- new_termios.c_cc[VTIME] = 0;
-
- if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
- size_t k;
-
- if (t != USEC_INFINITY) {
- if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
- tcsetattr(fileno(f), TCSADRAIN, &old_termios);
- return -ETIMEDOUT;
- }
- }
-
- k = fread(&c, 1, 1, f);
-
- tcsetattr(fileno(f), TCSADRAIN, &old_termios);
-
- if (k <= 0)
- return -EIO;
-
- if (need_nl)
- *need_nl = c != '\n';
-
- *ret = c;
- return 0;
- }
- }
-
- if (t != USEC_INFINITY) {
- if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
- return -ETIMEDOUT;
- }
-
- errno = 0;
- if (!fgets(line, sizeof(line), f))
- return errno ? -errno : -EIO;
-
- truncate_nl(line);
-
- if (strlen(line) != 1)
- return -EBADMSG;
-
- if (need_nl)
- *need_nl = false;
-
- *ret = line[0];
- return 0;
-}
-
-int ask_char(char *ret, const char *replies, const char *text, ...) {
- int r;
-
- assert(ret);
- assert(replies);
- assert(text);
-
- for (;;) {
- va_list ap;
- char c;
- bool need_nl = true;
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_ON, stdout);
-
- va_start(ap, text);
- vprintf(text, ap);
- va_end(ap);
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
-
- fflush(stdout);
-
- r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
- if (r < 0) {
-
- if (r == -EBADMSG) {
- puts("Bad input, please try again.");
- continue;
- }
-
- putchar('\n');
- return r;
- }
-
- if (need_nl)
- putchar('\n');
-
- if (strchr(replies, c)) {
- *ret = c;
- return 0;
- }
-
- puts("Read unexpected character, please try again.");
- }
-}
-
-int ask_string(char **ret, const char *text, ...) {
- assert(ret);
- assert(text);
-
- for (;;) {
- char line[LINE_MAX];
- va_list ap;
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_ON, stdout);
-
- va_start(ap, text);
- vprintf(text, ap);
- va_end(ap);
-
- if (on_tty())
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
-
- fflush(stdout);
-
- errno = 0;
- if (!fgets(line, sizeof(line), stdin))
- return errno ? -errno : -EIO;
-
- if (!endswith(line, "\n"))
- putchar('\n');
- else {
- char *s;
-
- if (isempty(line))
- continue;
-
- truncate_nl(line);
- s = strdup(line);
- if (!s)
- return -ENOMEM;
-
- *ret = s;
- return 0;
- }
- }
-}
-
-int reset_terminal_fd(int fd, bool switch_to_text) {
- struct termios termios;
- int r = 0;
-
- /* Set terminal to some sane defaults */
-
- assert(fd >= 0);
-
- /* We leave locked terminal attributes untouched, so that
- * Plymouth may set whatever it wants to set, and we don't
- * interfere with that. */
-
- /* Disable exclusive mode, just in case */
- ioctl(fd, TIOCNXCL);
-
- /* Switch to text mode */
- if (switch_to_text)
- ioctl(fd, KDSETMODE, KD_TEXT);
-
- /* Enable console unicode mode */
- ioctl(fd, KDSKBMODE, K_UNICODE);
-
- if (tcgetattr(fd, &termios) < 0) {
- r = -errno;
- goto finish;
- }
-
- /* We only reset the stuff that matters to the software. How
- * hardware is set up we don't touch assuming that somebody
- * else will do that for us */
-
- termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
- termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
- termios.c_oflag |= ONLCR;
- termios.c_cflag |= CREAD;
- termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
-
- termios.c_cc[VINTR] = 03; /* ^C */
- termios.c_cc[VQUIT] = 034; /* ^\ */
- termios.c_cc[VERASE] = 0177;
- termios.c_cc[VKILL] = 025; /* ^X */
- termios.c_cc[VEOF] = 04; /* ^D */
- termios.c_cc[VSTART] = 021; /* ^Q */
- termios.c_cc[VSTOP] = 023; /* ^S */
- termios.c_cc[VSUSP] = 032; /* ^Z */
- termios.c_cc[VLNEXT] = 026; /* ^V */
- termios.c_cc[VWERASE] = 027; /* ^W */
- termios.c_cc[VREPRINT] = 022; /* ^R */
- termios.c_cc[VEOL] = 0;
- termios.c_cc[VEOL2] = 0;
-
- termios.c_cc[VTIME] = 0;
- termios.c_cc[VMIN] = 1;
-
- if (tcsetattr(fd, TCSANOW, &termios) < 0)
- r = -errno;
-
-finish:
- /* Just in case, flush all crap out */
- tcflush(fd, TCIOFLUSH);
-
- return r;
-}
-
-int reset_terminal(const char *name) {
- _cleanup_close_ int fd = -1;
-
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- return reset_terminal_fd(fd, true);
-}
-
-int open_terminal(const char *name, int mode) {
- int fd, r;
- unsigned c = 0;
-
- /*
- * If a TTY is in the process of being closed opening it might
- * cause EIO. This is horribly awful, but unlikely to be
- * changed in the kernel. Hence we work around this problem by
- * retrying a couple of times.
- *
- * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
- */
-
- assert(!(mode & O_CREAT));
-
- for (;;) {
- fd = open(name, mode, 0);
- if (fd >= 0)
- break;
-
- if (errno != EIO)
- return -errno;
-
- /* Max 1s in total */
- if (c >= 20)
- return -errno;
-
- usleep(50 * USEC_PER_MSEC);
- c++;
- }
-
- r = isatty(fd);
- if (r < 0) {
- safe_close(fd);
- return -errno;
- }
-
- if (!r) {
- safe_close(fd);
- return -ENOTTY;
- }
-
- return fd;
-}
-
int flush_fd(int fd) {
struct pollfd pollfd = {
.fd = fd,
@@ -2112,238 +1550,6 @@ int flush_fd(int fd) {
}
}
-int acquire_terminal(
- const char *name,
- bool fail,
- bool force,
- bool ignore_tiocstty_eperm,
- usec_t timeout) {
-
- int fd = -1, notify = -1, r = 0, wd = -1;
- usec_t ts = 0;
-
- assert(name);
-
- /* We use inotify to be notified when the tty is closed. We
- * create the watch before checking if we can actually acquire
- * it, so that we don't lose any event.
- *
- * Note: strictly speaking this actually watches for the
- * device being closed, it does *not* really watch whether a
- * tty loses its controlling process. However, unless some
- * rogue process uses TIOCNOTTY on /dev/tty *after* closing
- * its tty otherwise this will not become a problem. As long
- * as the administrator makes sure not configure any service
- * on the same tty as an untrusted user this should not be a
- * problem. (Which he probably should not do anyway.) */
-
- if (timeout != USEC_INFINITY)
- ts = now(CLOCK_MONOTONIC);
-
- if (!fail && !force) {
- notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
- if (notify < 0) {
- r = -errno;
- goto fail;
- }
-
- wd = inotify_add_watch(notify, name, IN_CLOSE);
- if (wd < 0) {
- r = -errno;
- goto fail;
- }
- }
-
- for (;;) {
- struct sigaction sa_old, sa_new = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_RESTART,
- };
-
- if (notify >= 0) {
- r = flush_fd(notify);
- if (r < 0)
- goto fail;
- }
-
- /* We pass here O_NOCTTY only so that we can check the return
- * value TIOCSCTTY and have a reliable way to figure out if we
- * successfully became the controlling process of the tty */
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
- * if we already own the tty. */
- assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
-
- /* First, try to get the tty */
- if (ioctl(fd, TIOCSCTTY, force) < 0)
- r = -errno;
-
- assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
-
- /* Sometimes it makes sense to ignore TIOCSCTTY
- * returning EPERM, i.e. when very likely we already
- * are have this controlling terminal. */
- if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
- r = 0;
-
- if (r < 0 && (force || fail || r != -EPERM)) {
- goto fail;
- }
-
- if (r >= 0)
- break;
-
- assert(!fail);
- assert(!force);
- assert(notify >= 0);
-
- for (;;) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- if (timeout != USEC_INFINITY) {
- usec_t n;
-
- n = now(CLOCK_MONOTONIC);
- if (ts + timeout < n) {
- r = -ETIMEDOUT;
- goto fail;
- }
-
- r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
- if (r < 0)
- goto fail;
-
- if (r == 0) {
- r = -ETIMEDOUT;
- goto fail;
- }
- }
-
- l = read(notify, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
-
- r = -errno;
- goto fail;
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- if (e->wd != wd || !(e->mask & IN_CLOSE)) {
- r = -EIO;
- goto fail;
- }
- }
-
- break;
- }
-
- /* We close the tty fd here since if the old session
- * ended our handle will be dead. It's important that
- * we do this after sleeping, so that we don't enter
- * an endless loop. */
- fd = safe_close(fd);
- }
-
- safe_close(notify);
-
- r = reset_terminal_fd(fd, true);
- if (r < 0)
- log_warning_errno(r, "Failed to reset terminal: %m");
-
- return fd;
-
-fail:
- safe_close(fd);
- safe_close(notify);
-
- return r;
-}
-
-int release_terminal(void) {
- static const struct sigaction sa_new = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_RESTART,
- };
-
- _cleanup_close_ int fd = -1;
- struct sigaction sa_old;
- int r = 0;
-
- fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
- * by our own TIOCNOTTY */
- assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
-
- if (ioctl(fd, TIOCNOTTY) < 0)
- r = -errno;
-
- assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
-
- return r;
-}
-
-int sigaction_many(const struct sigaction *sa, ...) {
- va_list ap;
- int r = 0, sig;
-
- va_start(ap, sa);
- while ((sig = va_arg(ap, int)) > 0)
- if (sigaction(sig, sa, NULL) < 0)
- r = -errno;
- va_end(ap);
-
- return r;
-}
-
-int ignore_signals(int sig, ...) {
- struct sigaction sa = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_RESTART,
- };
- va_list ap;
- int r = 0;
-
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
-
- va_start(ap, sig);
- while ((sig = va_arg(ap, int)) > 0)
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
- va_end(ap);
-
- return r;
-}
-
-int default_signals(int sig, ...) {
- struct sigaction sa = {
- .sa_handler = SIG_DFL,
- .sa_flags = SA_RESTART,
- };
- va_list ap;
- int r = 0;
-
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
-
- va_start(ap, sig);
- while ((sig = va_arg(ap, int)) > 0)
- if (sigaction(sig, &sa, NULL) < 0)
- r = -errno;
- va_end(ap);
-
- return r;
-}
-
void safe_close_pair(int p[]) {
assert(p);
@@ -2418,7 +1624,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
errno = 0;
- while (nbytes > 0) {
+ do {
ssize_t k;
k = write(fd, p, nbytes);
@@ -2438,23 +1644,23 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
return -errno;
}
- if (k == 0) /* Can't really happen */
+ if (nbytes > 0 && k == 0) /* Can't really happen */
return -EIO;
p += k;
nbytes -= k;
- }
+ } while (nbytes > 0);
return 0;
}
int parse_size(const char *t, off_t base, off_t *size) {
- /* Soo, sometimes we want to parse IEC binary suffxies, and
+ /* Soo, sometimes we want to parse IEC binary suffixes, and
* sometimes SI decimal suffixes. This function can parse
* both. Which one is the right way depends on the
* context. Wikipedia suggests that SI is customary for
- * hardrware metrics and network speeds, while IEC is
+ * hardware metrics and network speeds, while IEC is
* customary for most data sizes used by software and volatile
* (RAM) memory. Hence be careful which one you pick!
*
@@ -2577,40 +1783,6 @@ int parse_size(const char *t, off_t base, off_t *size) {
return 0;
}
-int make_stdio(int fd) {
- int r, s, t;
-
- assert(fd >= 0);
-
- r = dup2(fd, STDIN_FILENO);
- s = dup2(fd, STDOUT_FILENO);
- t = dup2(fd, STDERR_FILENO);
-
- if (fd >= 3)
- safe_close(fd);
-
- if (r < 0 || s < 0 || t < 0)
- return -errno;
-
- /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
- * dup2() was a NOP and the bit hence possibly set. */
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
-
- return 0;
-}
-
-int make_null_stdio(void) {
- int null_fd;
-
- null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
- if (null_fd < 0)
- return -errno;
-
- return make_stdio(null_fd);
-}
-
bool is_device_path(const char *path) {
/* Returns true on paths that refer to a device, either in
@@ -2663,105 +1835,6 @@ char* dirname_malloc(const char *path) {
}
#endif /* NM_IGNORED */
-int dev_urandom(void *p, size_t n) {
-#if 0 /* NM_IGNORED */
- static int have_syscall = -1;
-
- _cleanup_close_ int fd = -1;
- int r;
-
- /* Gathers some randomness from the kernel. This call will
- * never block, and will always return some data from the
- * kernel, regardless if the random pool is fully initialized
- * or not. It thus makes no guarantee for the quality of the
- * returned entropy, but is good enough for or usual usecases
- * of seeding the hash functions for hashtable */
-
- /* Use the getrandom() syscall unless we know we don't have
- * it, or when the requested size is too large for it. */
- if (have_syscall != 0 || (size_t) (int) n != n) {
- r = getrandom(p, n, GRND_NONBLOCK);
- if (r == (int) n) {
- have_syscall = true;
- return 0;
- }
-
- if (r < 0) {
- if (errno == ENOSYS)
- /* we lack the syscall, continue with
- * reading from /dev/urandom */
- have_syscall = false;
- else if (errno == EAGAIN)
- /* not enough entropy for now. Let's
- * remember to use the syscall the
- * next time, again, but also read
- * from /dev/urandom for now, which
- * doesn't care about the current
- * amount of entropy. */
- have_syscall = true;
- else
- return -errno;
- } else
- /* too short read? */
- return -ENODATA;
- }
-#else /* NM IGNORED */
- _cleanup_close_ int fd = -1;
-#endif /* NM_IGNORED */
-
- fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return errno == ENOENT ? -ENOSYS : -errno;
-
- return loop_read_exact(fd, p, n, true);
-}
-
-void initialize_srand(void) {
- static bool srand_called = false;
- unsigned x;
-#ifdef HAVE_SYS_AUXV_H
- void *auxv;
-#endif
-
- if (srand_called)
- return;
-
- x = 0;
-
-#ifdef HAVE_SYS_AUXV_H
- /* The kernel provides us with a bit of entropy in auxv, so
- * let's try to make use of that to seed the pseudo-random
- * generator. It's better than nothing... */
-
- auxv = (void*) getauxval(AT_RANDOM);
- if (auxv)
- x ^= *(unsigned*) auxv;
-#endif
-
- x ^= (unsigned) now(CLOCK_REALTIME);
- x ^= (unsigned) gettid();
-
- srand(x);
- srand_called = true;
-}
-
-void random_bytes(void *p, size_t n) {
- uint8_t *q;
- int r;
-
- r = dev_urandom(p, n);
- if (r >= 0)
- return;
-
- /* If some idiot made /dev/urandom unavailable to us, he'll
- * get a PRNG instead. */
-
- initialize_srand();
-
- for (q = p; q < (uint8_t*) p + n; q ++)
- *q = rand();
-}
-
#if 0 /* NM_IGNORED */
void rename_process(const char name[8]) {
assert(name);
@@ -2794,55 +1867,6 @@ void rename_process(const char name[8]) {
}
}
-void sigset_add_many(sigset_t *ss, ...) {
- va_list ap;
- int sig;
-
- assert(ss);
-
- va_start(ap, ss);
- while ((sig = va_arg(ap, int)) > 0)
- assert_se(sigaddset(ss, sig) == 0);
- va_end(ap);
-}
-
-int sigprocmask_many(int how, ...) {
- va_list ap;
- sigset_t ss;
- int sig;
-
- assert_se(sigemptyset(&ss) == 0);
-
- va_start(ap, how);
- while ((sig = va_arg(ap, int)) > 0)
- assert_se(sigaddset(&ss, sig) == 0);
- va_end(ap);
-
- if (sigprocmask(how, &ss, NULL) < 0)
- return -errno;
-
- return 0;
-}
-
-char* gethostname_malloc(void) {
- struct utsname u;
-
- assert_se(uname(&u) >= 0);
-
- if (!isempty(u.nodename) && !streq(u.nodename, "(none)"))
- return strdup(u.nodename);
-
- return strdup(u.sysname);
-}
-
-bool hostname_is_set(void) {
- struct utsname u;
-
- assert_se(uname(&u) >= 0);
-
- return !isempty(u.nodename) && !streq(u.nodename, "(none)");
-}
-
char *lookup_uid(uid_t uid) {
long bufsize;
char *name;
@@ -2892,147 +1916,6 @@ char *getusername_malloc(void) {
return lookup_uid(getuid());
}
-int getttyname_malloc(int fd, char **ret) {
- size_t l = 100;
- int r;
-
- assert(fd >= 0);
- assert(ret);
-
- for (;;) {
- char path[l];
-
- r = ttyname_r(fd, path, sizeof(path));
- if (r == 0) {
- const char *p;
- char *c;
-
- p = startswith(path, "/dev/");
- c = strdup(p ?: path);
- if (!c)
- return -ENOMEM;
-
- *ret = c;
- return 0;
- }
-
- if (r != ERANGE)
- return -r;
-
- l *= 2;
- }
-
- return 0;
-}
-
-int getttyname_harder(int fd, char **r) {
- int k;
- char *s = NULL;
-
- k = getttyname_malloc(fd, &s);
- if (k < 0)
- return k;
-
- if (streq(s, "tty")) {
- free(s);
- return get_ctty(0, NULL, r);
- }
-
- *r = s;
- return 0;
-}
-
-int get_ctty_devnr(pid_t pid, dev_t *d) {
- int r;
- _cleanup_free_ char *line = NULL;
- const char *p;
- unsigned long ttynr;
-
- assert(pid >= 0);
-
- p = procfs_file_alloca(pid, "stat");
- r = read_one_line_file(p, &line);
- if (r < 0)
- return r;
-
- p = strrchr(line, ')');
- if (!p)
- return -EIO;
-
- p++;
-
- if (sscanf(p, " "
- "%*c " /* state */
- "%*d " /* ppid */
- "%*d " /* pgrp */
- "%*d " /* session */
- "%lu ", /* ttynr */
- &ttynr) != 1)
- return -EIO;
-
- if (major(ttynr) == 0 && minor(ttynr) == 0)
- return -ENOENT;
-
- if (d)
- *d = (dev_t) ttynr;
-
- return 0;
-}
-
-int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
- char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
- _cleanup_free_ char *s = NULL;
- const char *p;
- dev_t devnr;
- int k;
-
- assert(r);
-
- k = get_ctty_devnr(pid, &devnr);
- if (k < 0)
- return k;
-
- sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
-
- k = readlink_malloc(fn, &s);
- if (k < 0) {
-
- if (k != -ENOENT)
- return k;
-
- /* This is an ugly hack */
- if (major(devnr) == 136) {
- if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
- return -ENOMEM;
- } else {
- /* Probably something like the ptys which have no
- * symlink in /dev/char. Let's return something
- * vaguely useful. */
-
- b = strdup(fn + 5);
- if (!b)
- return -ENOMEM;
- }
- } else {
- if (startswith(s, "/dev/"))
- p = s + 5;
- else if (startswith(s, "../"))
- p = s + 3;
- else
- p = s;
-
- b = strdup(p);
- if (!b)
- return -ENOMEM;
- }
-
- *r = b;
- if (_devnr)
- *_devnr = devnr;
-
- return 0;
-}
-
bool is_temporary_fs(const struct statfs *s) {
assert(s);
@@ -3113,311 +1996,6 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
}
}
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
- static const char status_indent[] = " "; /* "[" STATUS "] " */
- _cleanup_free_ char *s = NULL;
- _cleanup_close_ int fd = -1;
- struct iovec iovec[6] = {};
- int n = 0;
- static bool prev_ephemeral;
-
- assert(format);
-
- /* This is independent of logging, as status messages are
- * optional and go exclusively to the console. */
-
- if (vasprintf(&s, format, ap) < 0)
- return log_oom();
-
- fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- if (ellipse) {
- char *e;
- size_t emax, sl;
- int c;
-
- c = fd_columns(fd);
- if (c <= 0)
- c = 80;
-
- sl = status ? sizeof(status_indent)-1 : 0;
-
- emax = c - sl - 1;
- if (emax < 3)
- emax = 3;
-
- e = ellipsize(s, emax, 50);
- if (e) {
- free(s);
- s = e;
- }
- }
-
- if (prev_ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
- prev_ephemeral = ephemeral;
-
- if (status) {
- if (!isempty(status)) {
- IOVEC_SET_STRING(iovec[n++], "[");
- IOVEC_SET_STRING(iovec[n++], status);
- IOVEC_SET_STRING(iovec[n++], "] ");
- } else
- IOVEC_SET_STRING(iovec[n++], status_indent);
- }
-
- IOVEC_SET_STRING(iovec[n++], s);
- if (!ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\n");
-
- if (writev(fd, iovec, n) < 0)
- return -errno;
-
- return 0;
-}
-
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
- va_list ap;
- int r;
-
- assert(format);
-
- va_start(ap, format);
- r = status_vprintf(status, ellipse, ephemeral, format, ap);
- va_end(ap);
-
- return r;
-}
-
-char *replace_env(const char *format, char **env) {
- enum {
- WORD,
- CURLY,
- VARIABLE
- } state = WORD;
-
- const char *e, *word = format;
- char *r = NULL, *k;
-
- assert(format);
-
- for (e = format; *e; e ++) {
-
- switch (state) {
-
- case WORD:
- if (*e == '$')
- state = CURLY;
- break;
-
- case CURLY:
- if (*e == '{') {
- k = strnappend(r, word, e-word-1);
- if (!k)
- goto fail;
-
- free(r);
- r = k;
-
- word = e-1;
- state = VARIABLE;
-
- } else if (*e == '$') {
- k = strnappend(r, word, e-word);
- if (!k)
- goto fail;
-
- free(r);
- r = k;
-
- word = e+1;
- state = WORD;
- } else
- state = WORD;
- break;
-
- case VARIABLE:
- if (*e == '}') {
- const char *t;
-
- t = strempty(strv_env_get_n(env, word+2, e-word-2));
-
- k = strappend(r, t);
- if (!k)
- goto fail;
-
- free(r);
- r = k;
-
- word = e+1;
- state = WORD;
- }
- break;
- }
- }
-
- k = strnappend(r, word, e-word);
- if (!k)
- goto fail;
-
- free(r);
- return k;
-
-fail:
- free(r);
- return NULL;
-}
-
-char **replace_env_argv(char **argv, char **env) {
- char **ret, **i;
- unsigned k = 0, l = 0;
-
- l = strv_length(argv);
-
- ret = new(char*, l+1);
- if (!ret)
- return NULL;
-
- STRV_FOREACH(i, argv) {
-
- /* If $FOO appears as single word, replace it by the split up variable */
- if ((*i)[0] == '$' && (*i)[1] != '{') {
- char *e;
- char **w, **m = NULL;
- unsigned q;
-
- e = strv_env_get(env, *i+1);
- if (e) {
- int r;
-
- r = strv_split_quoted(&m, e, UNQUOTE_RELAX);
- if (r < 0) {
- ret[k] = NULL;
- strv_free(ret);
- return NULL;
- }
- } else
- m = NULL;
-
- q = strv_length(m);
- l = l + q - 1;
-
- w = realloc(ret, sizeof(char*) * (l+1));
- if (!w) {
- ret[k] = NULL;
- strv_free(ret);
- strv_free(m);
- return NULL;
- }
-
- ret = w;
- if (m) {
- memcpy(ret + k, m, q * sizeof(char*));
- free(m);
- }
-
- k += q;
- continue;
- }
-
- /* If ${FOO} appears as part of a word, replace it by the variable as-is */
- ret[k] = replace_env(*i, env);
- if (!ret[k]) {
- strv_free(ret);
- return NULL;
- }
- k++;
- }
-
- ret[k] = NULL;
- return ret;
-}
-
-int fd_columns(int fd) {
- struct winsize ws = {};
-
- if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
- return -errno;
-
- if (ws.ws_col <= 0)
- return -EIO;
-
- return ws.ws_col;
-}
-
-unsigned columns(void) {
- const char *e;
- int c;
-
- if (_likely_(cached_columns > 0))
- return cached_columns;
-
- c = 0;
- e = getenv("COLUMNS");
- if (e)
- (void) safe_atoi(e, &c);
-
- if (c <= 0)
- c = fd_columns(STDOUT_FILENO);
-
- if (c <= 0)
- c = 80;
-
- cached_columns = c;
- return cached_columns;
-}
-
-int fd_lines(int fd) {
- struct winsize ws = {};
-
- if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
- return -errno;
-
- if (ws.ws_row <= 0)
- return -EIO;
-
- return ws.ws_row;
-}
-
-unsigned lines(void) {
- const char *e;
- int l;
-
- if (_likely_(cached_lines > 0))
- return cached_lines;
-
- l = 0;
- e = getenv("LINES");
- if (e)
- (void) safe_atoi(e, &l);
-
- if (l <= 0)
- l = fd_lines(STDOUT_FILENO);
-
- if (l <= 0)
- l = 24;
-
- cached_lines = l;
- return cached_lines;
-}
-
-/* intended to be used as a SIGWINCH sighandler */
-void columns_lines_cache_reset(int signum) {
- cached_columns = 0;
- cached_lines = 0;
-}
-
-bool on_tty(void) {
- static int cached_on_tty = -1;
-
- if (_unlikely_(cached_on_tty < 0))
- cached_on_tty = isatty(STDOUT_FILENO) > 0;
-
- return cached_on_tty;
-}
-
int files_same(const char *filea, const char *fileb) {
struct stat a, b;
@@ -3593,14 +2171,15 @@ int touch(const char *path) {
return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
}
-char *unquote(const char *s, const char* quotes) {
+static char *unquote(const char *s, const char* quotes) {
size_t l;
assert(s);
/* This is rather stupid, simply removes the heading and
* trailing quotes if there is one. Doesn't care about
- * escaping or anything. We should make this smarter one
- * day... */
+ * escaping or anything.
+ *
+ * DON'T USE THIS FOR NEW CODE ANYMORE!*/
l = strlen(s);
if (l < 2)
@@ -3612,103 +2191,6 @@ char *unquote(const char *s, const char* quotes) {
return strdup(s);
}
-char *normalize_env_assignment(const char *s) {
- _cleanup_free_ char *value = NULL;
- const char *eq;
- char *p, *name;
-
- eq = strchr(s, '=');
- if (!eq) {
- char *r, *t;
-
- r = strdup(s);
- if (!r)
- return NULL;
-
- t = strstrip(r);
- if (t != r)
- memmove(r, t, strlen(t) + 1);
-
- return r;
- }
-
- name = strndupa(s, eq - s);
- p = strdupa(eq + 1);
-
- value = unquote(strstrip(p), QUOTES);
- if (!value)
- return NULL;
-
- return strjoin(strstrip(name), "=", value, NULL);
-}
-
-int wait_for_terminate(pid_t pid, siginfo_t *status) {
- siginfo_t dummy;
-
- assert(pid >= 1);
-
- if (!status)
- status = &dummy;
-
- for (;;) {
- zero(*status);
-
- if (waitid(P_PID, pid, status, WEXITED) < 0) {
-
- if (errno == EINTR)
- continue;
-
- return -errno;
- }
-
- return 0;
- }
-}
-
-/*
- * Return values:
- * < 0 : wait_for_terminate() failed to get the state of the
- * process, the process was terminated by a signal, or
- * failed for an unknown reason.
- * >=0 : The process terminated normally, and its exit code is
- * returned.
- *
- * That is, success is indicated by a return value of zero, and an
- * error is indicated by a non-zero value.
- *
- * A warning is emitted if the process terminates abnormally,
- * and also if it returns non-zero unless check_exit_code is true.
- */
-int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code) {
- int r;
- siginfo_t status;
-
- assert(name);
- assert(pid > 1);
-
- r = wait_for_terminate(pid, &status);
- if (r < 0)
- return log_warning_errno(r, "Failed to wait for %s: %m", name);
-
- if (status.si_code == CLD_EXITED) {
- if (status.si_status != 0)
- log_full(check_exit_code ? LOG_WARNING : LOG_DEBUG,
- "%s failed with error code %i.", name, status.si_status);
- else
- log_debug("%s succeeded.", name);
-
- return status.si_status;
- } else if (status.si_code == CLD_KILLED ||
- status.si_code == CLD_DUMPED) {
-
- log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status));
- return -EPROTO;
- }
-
- log_warning("%s failed due to unknown reason.", name);
- return -EPROTO;
-}
-
noreturn void freeze(void) {
/* Make sure nobody waits for us on a socket anymore */
@@ -3773,23 +2255,11 @@ DIR *xopendirat(int fd, const char *name, int flags) {
return d;
}
-int signal_from_string_try_harder(const char *s) {
- int signo;
- assert(s);
-
- signo = signal_from_string(s);
- if (signo <= 0)
- if (startswith(s, "SIG"))
- return signal_from_string(s+3);
-
- return signo;
-}
-
static char *tag_to_udev_node(const char *tagvalue, const char *by) {
_cleanup_free_ char *t = NULL, *u = NULL;
size_t enc_len;
- u = unquote(tagvalue, "\"\'");
+ u = unquote(tagvalue, QUOTES);
if (!u)
return NULL;
@@ -3822,101 +2292,6 @@ char *fstab_node_to_udev_node(const char *p) {
return strdup(p);
}
-bool tty_is_vc(const char *tty) {
- assert(tty);
-
- return vtnr_from_tty(tty) >= 0;
-}
-
-bool tty_is_console(const char *tty) {
- assert(tty);
-
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- return streq(tty, "console");
-}
-
-int vtnr_from_tty(const char *tty) {
- int i, r;
-
- assert(tty);
-
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- if (!startswith(tty, "tty") )
- return -EINVAL;
-
- if (tty[3] < '0' || tty[3] > '9')
- return -EINVAL;
-
- r = safe_atoi(tty+3, &i);
- if (r < 0)
- return r;
-
- if (i < 0 || i > 63)
- return -EINVAL;
-
- return i;
-}
-
-char *resolve_dev_console(char **active) {
- char *tty;
-
- /* Resolve where /dev/console is pointing to, if /sys is actually ours
- * (i.e. not read-only-mounted which is a sign for container setups) */
-
- if (path_is_read_only_fs("/sys") > 0)
- return NULL;
-
- if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
- return NULL;
-
- /* If multiple log outputs are configured the last one is what
- * /dev/console points to */
- tty = strrchr(*active, ' ');
- if (tty)
- tty++;
- else
- tty = *active;
-
- if (streq(tty, "tty0")) {
- char *tmp;
-
- /* Get the active VC (e.g. tty1) */
- if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
- free(*active);
- tty = *active = tmp;
- }
- }
-
- return tty;
-}
-
-bool tty_is_vc_resolve(const char *tty) {
- _cleanup_free_ char *active = NULL;
-
- assert(tty);
-
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- if (streq(tty, "console")) {
- tty = resolve_dev_console(&active);
- if (!tty)
- return false;
- }
-
- return tty_is_vc(tty);
-}
-
-const char *default_term_for_tty(const char *tty) {
- assert(tty);
-
- return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
-}
-
bool dirent_is_file(const struct dirent *de) {
assert(de);
@@ -3953,8 +2328,8 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) {
/* We fork this all off from a child process so that we can
* somewhat cleanly make use of SIGALRM to set a time limit */
- reset_all_signal_handlers();
- reset_signal_mask();
+ (void) reset_all_signal_handlers();
+ (void) reset_signal_mask();
assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
@@ -4085,17 +2460,6 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a
wait_for_terminate_and_warn(name, executor_pid, true);
}
-int kill_and_sigcont(pid_t pid, int sig) {
- int r;
-
- r = kill(pid, sig) < 0 ? -errno : 0;
-
- if (r >= 0)
- kill(pid, SIGCONT);
-
- return r;
-}
-
bool nulstr_contains(const char*nulstr, const char *needle) {
const char *i;
@@ -4121,81 +2485,6 @@ char* strshorten(char *s, size_t l) {
return s;
}
-#endif /* NM_IGNORED */
-
-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;
-}
-
-#if 0 /* NM_IGNORED */
-char* hostname_cleanup(char *s, bool lowercase) {
- char *p, *d;
- bool dot;
-
- 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 machine_name_is_valid(const char *s) {
@@ -4260,7 +2549,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
assert(_f);
assert(_temp_path);
- r = tempfn_xxxxxx(path, &t);
+ r = tempfn_xxxxxx(path, NULL, &t);
if (r < 0)
return r;
@@ -4284,111 +2573,45 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
}
#if 0 /* NM_IGNORED */
-int terminal_vhangup_fd(int fd) {
- assert(fd >= 0);
-
- if (ioctl(fd, TIOCVHANGUP) < 0)
- return -errno;
-
- return 0;
-}
-
-int terminal_vhangup(const char *name) {
- _cleanup_close_ int fd;
-
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- return terminal_vhangup_fd(fd);
-}
-
-int vt_disallocate(const char *name) {
- int fd, r;
- unsigned u;
-
- /* Deallocate the VT if possible. If not possible
- * (i.e. because it is the active one), at least clear it
- * entirely (including the scrollback buffer) */
-
- if (!startswith(name, "/dev/"))
- return -EINVAL;
-
- if (!tty_is_vc(name)) {
- /* So this is not a VT. I guess we cannot deallocate
- * it then. But let's at least clear the screen */
-
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- loop_write(fd,
- "\033[r" /* clear scrolling region */
- "\033[H" /* move home */
- "\033[2J", /* clear screen */
- 10, false);
- safe_close(fd);
-
- return 0;
- }
+int symlink_atomic(const char *from, const char *to) {
+ _cleanup_free_ char *t = NULL;
+ int r;
- if (!startswith(name, "/dev/tty"))
- return -EINVAL;
+ assert(from);
+ assert(to);
- r = safe_atou(name+8, &u);
+ r = tempfn_random(to, NULL, &t);
if (r < 0)
return r;
- if (u <= 0)
- return -EINVAL;
-
- /* Try to deallocate */
- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- r = ioctl(fd, VT_DISALLOCATE, u);
- safe_close(fd);
-
- if (r >= 0)
- return 0;
-
- if (errno != EBUSY)
+ if (symlink(from, t) < 0)
return -errno;
- /* Couldn't deallocate, so let's clear it fully with
- * scrollback */
- fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- loop_write(fd,
- "\033[r" /* clear scrolling region */
- "\033[H" /* move home */
- "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
- 10, false);
- safe_close(fd);
+ if (rename(t, to) < 0) {
+ unlink_noerrno(t);
+ return -errno;
+ }
return 0;
}
-int symlink_atomic(const char *from, const char *to) {
- _cleanup_free_ char *t = NULL;
+int symlink_idempotent(const char *from, const char *to) {
+ _cleanup_free_ char *p = NULL;
int r;
assert(from);
assert(to);
- r = tempfn_random(to, &t);
- if (r < 0)
- return r;
+ if (symlink(from, to) < 0) {
+ if (errno != EEXIST)
+ return -errno;
- if (symlink(from, t) < 0)
- return -errno;
+ r = readlink_malloc(to, &p);
+ if (r < 0)
+ return r;
- if (rename(t, to) < 0) {
- unlink_noerrno(t);
- return -errno;
+ if (!streq(p, from))
+ return -EINVAL;
}
return 0;
@@ -4400,7 +2623,7 @@ int mknod_atomic(const char *path, mode_t mode, dev_t dev) {
assert(path);
- r = tempfn_random(path, &t);
+ r = tempfn_random(path, NULL, &t);
if (r < 0)
return r;
@@ -4421,7 +2644,7 @@ int mkfifo_atomic(const char *path, mode_t mode) {
assert(path);
- r = tempfn_random(path, &t);
+ r = tempfn_random(path, NULL, &t);
if (r < 0)
return r;
@@ -4992,81 +3215,6 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
-static const char *const __signal_table[] = {
- [SIGHUP] = "HUP",
- [SIGINT] = "INT",
- [SIGQUIT] = "QUIT",
- [SIGILL] = "ILL",
- [SIGTRAP] = "TRAP",
- [SIGABRT] = "ABRT",
- [SIGBUS] = "BUS",
- [SIGFPE] = "FPE",
- [SIGKILL] = "KILL",
- [SIGUSR1] = "USR1",
- [SIGSEGV] = "SEGV",
- [SIGUSR2] = "USR2",
- [SIGPIPE] = "PIPE",
- [SIGALRM] = "ALRM",
- [SIGTERM] = "TERM",
-#ifdef SIGSTKFLT
- [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
-#endif
- [SIGCHLD] = "CHLD",
- [SIGCONT] = "CONT",
- [SIGSTOP] = "STOP",
- [SIGTSTP] = "TSTP",
- [SIGTTIN] = "TTIN",
- [SIGTTOU] = "TTOU",
- [SIGURG] = "URG",
- [SIGXCPU] = "XCPU",
- [SIGXFSZ] = "XFSZ",
- [SIGVTALRM] = "VTALRM",
- [SIGPROF] = "PROF",
- [SIGWINCH] = "WINCH",
- [SIGIO] = "IO",
- [SIGPWR] = "PWR",
- [SIGSYS] = "SYS"
-};
-
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
-
-const char *signal_to_string(int signo) {
- static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
- const char *name;
-
- name = __signal_to_string(signo);
- if (name)
- return name;
-
- if (signo >= SIGRTMIN && signo <= SIGRTMAX)
- snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
- else
- snprintf(buf, sizeof(buf), "%d", signo);
-
- return buf;
-}
-
-int signal_from_string(const char *s) {
- int signo;
- int offset = 0;
- unsigned u;
-
- signo = __signal_from_string(s);
- if (signo > 0)
- return signo;
-
- if (startswith(s, "RTMIN+")) {
- s += 6;
- offset = SIGRTMIN;
- }
- if (safe_atou(s, &u) >= 0) {
- signo = (int) u + offset;
- if (signo > 0 && signo < _NSIG)
- return signo;
- }
- return -EINVAL;
-}
-
bool kexec_loaded(void) {
bool loaded = false;
char *s;
@@ -5229,8 +3377,8 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
/* Make sure we actually can kill the agent, if we need to, in
* case somebody invoked us from a shell script that trapped
* SIGTERM or so... */
- reset_all_signal_handlers();
- reset_signal_mask();
+ (void) reset_all_signal_handlers();
+ (void) reset_signal_mask();
/* Check whether our parent died before we were able
* to set the death signal and unblock the signals */
@@ -5312,60 +3460,6 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
return 0;
}
-int getenv_for_pid(pid_t pid, const char *field, char **_value) {
- _cleanup_fclose_ FILE *f = NULL;
- char *value = NULL;
- int r;
- bool done = false;
- size_t l;
- const char *path;
-
- assert(pid >= 0);
- assert(field);
- assert(_value);
-
- path = procfs_file_alloca(pid, "environ");
-
- f = fopen(path, "re");
- if (!f)
- return -errno;
-
- l = strlen(field);
- r = 0;
-
- do {
- char line[LINE_MAX];
- unsigned i;
-
- for (i = 0; i < sizeof(line)-1; i++) {
- int c;
-
- c = getc(f);
- if (_unlikely_(c == EOF)) {
- done = true;
- break;
- } else if (c == 0)
- break;
-
- line[i] = c;
- }
- line[i] = 0;
-
- if (memcmp(line, field, l) == 0 && line[l] == '=') {
- value = strdup(line + l + 1);
- if (!value)
- return -ENOMEM;
-
- r = 1;
- break;
- }
-
- } while (!done);
-
- *_value = value;
- return r;
-}
-
bool http_etag_is_valid(const char *etag) {
if (isempty(etag))
return false;
@@ -5442,43 +3536,6 @@ bool in_initrd(void) {
return saved;
}
-void warn_melody(void) {
- _cleanup_close_ int fd = -1;
-
- fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return;
-
- /* Yeah, this is synchronous. Kinda sucks. But well... */
-
- ioctl(fd, KIOCSOUND, (int)(1193180/440));
- usleep(125*USEC_PER_MSEC);
-
- ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- ioctl(fd, KIOCSOUND, 0);
-}
-
-int make_console_stdio(void) {
- int fd, r;
-
- /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
-
- fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
- if (fd < 0)
- return log_error_errno(fd, "Failed to acquire terminal: %m");
-
- r = make_stdio(fd);
- if (r < 0)
- return log_error_errno(r, "Failed to duplicate terminal fd: %m");
-
- return 0;
-}
-
int get_home_dir(char **_h) {
struct passwd *p;
const char *e;
@@ -5645,7 +3702,7 @@ bool path_is_safe(const char *p) {
if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
return false;
- if (strlen(p) > PATH_MAX)
+ if (strlen(p)+1 > PATH_MAX)
return false;
/* The following two checks are not really dangerous, but hey, they still are confusing */
@@ -6465,43 +4522,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
return -errno;
}
- if (setresgid(0, 0, 0) < 0)
- return -errno;
-
- if (setgroups(0, NULL) < 0)
- return -errno;
-
- if (setresuid(0, 0, 0) < 0)
- return -errno;
-
- return 0;
-}
-
-bool pid_is_unwaited(pid_t pid) {
- /* Checks whether a PID is still valid at all, including a zombie */
-
- if (pid <= 0)
- return false;
-
- if (kill(pid, 0) >= 0)
- return true;
-
- return errno != ESRCH;
-}
-
-bool pid_is_alive(pid_t pid) {
- int r;
-
- /* Checks whether a PID is still valid and not a zombie */
-
- if (pid <= 0)
- return false;
-
- r = get_process_state(pid);
- if (r == -ENOENT || r == 'Z')
- return false;
-
- return true;
+ return reset_uid_gid();
}
int getpeercred(int fd, struct ucred *ucred) {
@@ -6597,7 +4618,7 @@ int open_tmpfile(const char *path, int flags) {
#ifdef O_TMPFILE
/* Try O_TMPFILE first, if it is supported */
- fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR);
+ fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
if (fd >= 0)
return fd;
#endif
@@ -6654,10 +4675,7 @@ unsigned long personality_from_string(const char *p) {
return PER_LINUX;
#endif
- /* personality(7) documents that 0xffffffffUL is used for
- * querying the current personality, hence let's use that here
- * as error indicator. */
- return 0xffffffffUL;
+ return PERSONALITY_INVALID;
}
const char* personality_to_string(unsigned long p) {
@@ -6955,7 +4973,7 @@ int bind_remount_recursive(const char *prefix, bool ro) {
while ((x = set_steal_first(todo))) {
r = set_consume(done, x);
- if (r == -EEXIST)
+ if (r == -EEXIST || r == 0)
continue;
if (r < 0)
return r;
@@ -6993,7 +5011,7 @@ int fflush_and_check(FILE *f) {
return 0;
}
-int tempfn_xxxxxx(const char *p, char **ret) {
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
const char *fn;
char *t;
@@ -7005,25 +5023,28 @@ int tempfn_xxxxxx(const char *p, char **ret) {
* /foo/bar/waldo
*
* Into this:
- * /foo/bar/.#waldoXXXXXX
+ * /foo/bar/.#<extra>waldoXXXXXX
*/
fn = basename(p);
if (!filename_is_valid(fn))
return -EINVAL;
- t = new(char, strlen(p) + 2 + 6 + 1);
+ if (extra == NULL)
+ extra = "";
+
+ t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1);
if (!t)
return -ENOMEM;
- strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), "XXXXXX");
+ strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX");
*ret = path_kill_slashes(t);
return 0;
}
#if 0 /* NM_IGNORED */
-int tempfn_random(const char *p, char **ret) {
+int tempfn_random(const char *p, const char *extra, char **ret) {
const char *fn;
char *t, *x;
uint64_t u;
@@ -7037,18 +5058,21 @@ int tempfn_random(const char *p, char **ret) {
* /foo/bar/waldo
*
* Into this:
- * /foo/bar/.#waldobaa2a261115984a9
+ * /foo/bar/.#<extra>waldobaa2a261115984a9
*/
fn = basename(p);
if (!filename_is_valid(fn))
return -EINVAL;
- t = new(char, strlen(p) + 2 + 16 + 1);
+ if (!extra)
+ extra = "";
+
+ t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1);
if (!t)
return -ENOMEM;
- x = stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn);
+ x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn);
u = random_u64();
for (i = 0; i < 16; i++) {
@@ -7062,7 +5086,7 @@ int tempfn_random(const char *p, char **ret) {
return 0;
}
-int tempfn_random_child(const char *p, char **ret) {
+int tempfn_random_child(const char *p, const char *extra, char **ret) {
char *t, *x;
uint64_t u;
unsigned i;
@@ -7073,14 +5097,17 @@ int tempfn_random_child(const char *p, char **ret) {
/* Turns this:
* /foo/bar/waldo
* Into this:
- * /foo/bar/waldo/.#3c2b6219aa75d7d0
+ * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
*/
- t = new(char, strlen(p) + 3 + 16 + 1);
+ if (!extra)
+ extra = "";
+
+ t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1);
if (!t)
return -ENOMEM;
- x = stpcpy(stpcpy(t, p), "/.#");
+ x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra);
u = random_u64();
for (i = 0; i < 16; i++) {
@@ -7093,26 +5120,7 @@ int tempfn_random_child(const char *p, char **ret) {
*ret = path_kill_slashes(t);
return 0;
}
-#endif /* NM_IGNORED */
-
-/* make sure the hostname is not "localhost" */
-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.");
-}
-
-#if 0 /* NM_IGNORED */
int take_password_lock(const char *root) {
struct flock flock = {
@@ -7176,6 +5184,15 @@ int is_dir(const char* path, bool follow) {
return !!S_ISDIR(st.st_mode);
}
+int is_device_node(const char *path) {
+ struct stat info;
+
+ if (lstat(path, &info) < 0)
+ return -errno;
+
+ return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
+}
+
int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
@@ -7242,20 +5259,26 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
return -EINVAL;
}
- if (!GREEDY_REALLOC(s, allocated, sz+2))
+ if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
if (flags & UNQUOTE_CUNESCAPE) {
- r = cunescape_one(*p, (size_t) -1, &c);
+ uint32_t u;
+
+ r = cunescape_one(*p, (size_t) -1, &c, &u);
if (r < 0)
return -EINVAL;
(*p) += r - 1;
- }
- s[sz++] = c;
- state = VALUE;
+ if (c != 0)
+ s[sz++] = c; /* normal explicit char */
+ else
+ sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
+ } else
+ s[sz++] = c;
+ state = VALUE;
break;
case SINGLE_QUOTE:
@@ -7283,18 +5306,25 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
return -EINVAL;
}
- if (!GREEDY_REALLOC(s, allocated, sz+2))
+ if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
if (flags & UNQUOTE_CUNESCAPE) {
- r = cunescape_one(*p, (size_t) -1, &c);
+ uint32_t u;
+
+ r = cunescape_one(*p, (size_t) -1, &c, &u);
if (r < 0)
return -EINVAL;
(*p) += r - 1;
- }
- s[sz++] = c;
+ if (c != 0)
+ s[sz++] = c;
+ else
+ sz += utf8_encode_unichar(s + sz, u);
+ } else
+ s[sz++] = c;
+
state = SINGLE_QUOTE;
break;
@@ -7321,18 +5351,25 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
return -EINVAL;
}
- if (!GREEDY_REALLOC(s, allocated, sz+2))
+ if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
if (flags & UNQUOTE_CUNESCAPE) {
- r = cunescape_one(*p, (size_t) -1, &c);
+ uint32_t u;
+
+ r = cunescape_one(*p, (size_t) -1, &c, &u);
if (r < 0)
return -EINVAL;
(*p) += r - 1;
- }
- s[sz++] = c;
+ if (c != 0)
+ s[sz++] = c;
+ else
+ sz += utf8_encode_unichar(s + sz, u);
+ } else
+ s[sz++] = c;
+
state = DOUBLE_QUOTE;
break;
@@ -7425,6 +5462,9 @@ int free_and_strdup(char **p, const char *s) {
/* Replaces a string pointer with an strdup()ed new string,
* possibly freeing the old one. */
+ if (streq_ptr(*p, s))
+ return 0;
+
if (s) {
t = strdup(s);
if (!t)
@@ -7435,26 +5475,6 @@ int free_and_strdup(char **p, const char *s) {
free(*p);
*p = t;
- return 0;
-}
-
-int sethostname_idempotent(const char *s) {
- int r;
- char buf[HOST_NAME_MAX + 1] = {};
-
- assert(s);
-
- r = gethostname(buf, sizeof(buf));
- if (r < 0)
- return -errno;
-
- if (streq(buf, s))
- return 0;
-
- r = sethostname(s, strlen(s));
- if (r < 0)
- return -errno;
-
return 1;
}
@@ -7552,7 +5572,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
return -errno;
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
+ CMSG_FOREACH(cmsg, &mh)
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
int *fds;
unsigned n_fds;
@@ -7716,7 +5736,7 @@ int same_fd(int a, int b) {
/* The fds refer to the same inode on disk, let's also check
* if they have the same fd flags. This is useful to
- * distuingish the read and write side of a pipe created with
+ * distinguish the read and write side of a pipe created with
* pipe(). */
fa = fcntl(a, F_GETFL);
if (fa < 0)
@@ -7729,32 +5749,41 @@ int same_fd(int a, int b) {
return fa == fb;
}
-int chattr_fd(int fd, bool b, unsigned mask) {
+int chattr_fd(int fd, unsigned value, unsigned mask) {
unsigned old_attr, new_attr;
+ struct stat st;
assert(fd >= 0);
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ /* Explicitly check whether this is a regular file or
+ * directory. If it is anything else (such as a device node or
+ * fifo), then the ioctl will not hit the file systems but
+ * possibly drivers, where the ioctl might have different
+ * effects. Notably, DRM is using the same ioctl() number. */
+
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+ return -ENOTTY;
+
if (mask == 0)
return 0;
if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
return -errno;
- if (b)
- new_attr = old_attr | mask;
- else
- new_attr = old_attr & ~mask;
-
+ new_attr = (old_attr & ~mask) | (value & mask);
if (new_attr == old_attr)
return 0;
if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
return -errno;
- return 0;
+ return 1;
}
-int chattr_path(const char *p, bool b, unsigned mask) {
+int chattr_path(const char *p, unsigned value, unsigned mask) {
_cleanup_close_ int fd = -1;
assert(p);
@@ -7766,33 +5795,19 @@ int chattr_path(const char *p, bool b, unsigned mask) {
if (fd < 0)
return -errno;
- return chattr_fd(fd, b, mask);
+ return chattr_fd(fd, value, mask);
}
-int change_attr_fd(int fd, unsigned value, unsigned mask) {
- unsigned old_attr, new_attr;
+int read_attr_fd(int fd, unsigned *ret) {
+ struct stat st;
assert(fd >= 0);
- if (mask == 0)
- return 0;
-
- if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0)
- return -errno;
-
- new_attr = (old_attr & ~mask) |(value & mask);
-
- if (new_attr == old_attr)
- return 0;
-
- if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0)
+ if (fstat(fd, &st) < 0)
return -errno;
- return 0;
-}
-
-int read_attr_fd(int fd, unsigned *ret) {
- assert(fd >= 0);
+ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
+ return -ENOTTY;
if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0)
return -errno;
@@ -7813,128 +5828,6 @@ int read_attr_path(const char *p, unsigned *ret) {
return read_attr_fd(fd, ret);
}
-int make_lock_file(const char *p, int operation, LockFile *ret) {
- _cleanup_close_ int fd = -1;
- _cleanup_free_ char *t = NULL;
- int r;
-
- /*
- * We use UNPOSIX locks if they are available. They have nice
- * semantics, and are mostly compatible with NFS. However,
- * they are only available on new kernels. When we detect we
- * are running on an older kernel, then we fall back to good
- * old BSD locks. They also have nice semantics, but are
- * slightly problematic on NFS, where they are upgraded to
- * POSIX locks, even though locally they are orthogonal to
- * POSIX locks.
- */
-
- t = strdup(p);
- if (!t)
- return -ENOMEM;
-
- for (;;) {
- struct flock fl = {
- .l_type = (operation & ~LOCK_NB) == LOCK_EX ? F_WRLCK : F_RDLCK,
- .l_whence = SEEK_SET,
- };
- struct stat st;
-
- fd = open(p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600);
- if (fd < 0)
- return -errno;
-
- r = fcntl(fd, (operation & LOCK_NB) ? F_OFD_SETLK : F_OFD_SETLKW, &fl);
- if (r < 0) {
-
- /* If the kernel is too old, use good old BSD locks */
- if (errno == EINVAL)
- r = flock(fd, operation);
-
- if (r < 0)
- return errno == EAGAIN ? -EBUSY : -errno;
- }
-
- /* If we acquired the lock, let's check if the file
- * still exists in the file system. If not, then the
- * previous exclusive owner removed it and then closed
- * it. In such a case our acquired lock is worthless,
- * hence try again. */
-
- r = fstat(fd, &st);
- if (r < 0)
- return -errno;
- if (st.st_nlink > 0)
- break;
-
- fd = safe_close(fd);
- }
-
- ret->path = t;
- ret->fd = fd;
- ret->operation = operation;
-
- fd = -1;
- t = NULL;
-
- return r;
-}
-
-int make_lock_file_for(const char *p, int operation, LockFile *ret) {
- const char *fn;
- char *t;
-
- assert(p);
- assert(ret);
-
- fn = basename(p);
- if (!filename_is_valid(fn))
- return -EINVAL;
-
- t = newa(char, strlen(p) + 2 + 4 + 1);
- stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), ".lck");
-
- return make_lock_file(t, operation, ret);
-}
-
-void release_lock_file(LockFile *f) {
- int r;
-
- if (!f)
- return;
-
- if (f->path) {
-
- /* If we are the exclusive owner we can safely delete
- * the lock file itself. If we are not the exclusive
- * owner, we can try becoming it. */
-
- if (f->fd >= 0 &&
- (f->operation & ~LOCK_NB) == LOCK_SH) {
- static const struct flock fl = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- };
-
- r = fcntl(f->fd, F_OFD_SETLK, &fl);
- if (r < 0 && errno == EINVAL)
- r = flock(f->fd, LOCK_EX|LOCK_NB);
-
- if (r >= 0)
- f->operation = LOCK_EX|LOCK_NB;
- }
-
- if ((f->operation & ~LOCK_NB) == LOCK_EX)
- unlink_noerrno(f->path);
-
- free(f->path);
- f->path = NULL;
- }
-
- f->fd = safe_close(f->fd);
- f->operation = 0;
-}
-
static size_t nul_length(const uint8_t *p, size_t sz) {
size_t n = 0;
@@ -8069,7 +5962,7 @@ void cmsg_close_all(struct msghdr *mh) {
assert(mh);
- for (cmsg = CMSG_FIRSTHDR(mh); cmsg; cmsg = CMSG_NXTHDR(mh, cmsg))
+ CMSG_FOREACH(cmsg, mh)
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
}
@@ -8114,4 +6007,97 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
return 0;
}
+
+char *shell_maybe_quote(const char *s) {
+ const char *p;
+ char *r, *t;
+
+ assert(s);
+
+ /* Encloses a string in double quotes if necessary to make it
+ * OK as shell string. */
+
+ for (p = s; *p; p++)
+ if (*p <= ' ' ||
+ *p >= 127 ||
+ strchr(SHELL_NEED_QUOTES, *p))
+ break;
+
+ if (!*p)
+ return strdup(s);
+
+ r = new(char, 1+strlen(s)*2+1+1);
+ if (!r)
+ return NULL;
+
+ t = r;
+ *(t++) = '"';
+ t = mempcpy(t, s, p - s);
+
+ for (; *p; p++) {
+
+ if (strchr(SHELL_NEED_ESCAPE, *p))
+ *(t++) = '\\';
+
+ *(t++) = *p;
+ }
+
+ *(t++)= '"';
+ *t = 0;
+
+ return r;
+}
+
+int parse_mode(const char *s, mode_t *ret) {
+ char *x;
+ long l;
+
+ assert(s);
+ assert(ret);
+
+ errno = 0;
+ l = strtol(s, &x, 8);
+ if (errno != 0)
+ return -errno;
+
+ if (!x || x == s || *x)
+ return -EINVAL;
+ if (l < 0 || l > 07777)
+ return -ERANGE;
+
+ *ret = (mode_t) l;
+ return 0;
+}
+
+int mount_move_root(const char *path) {
+ assert(path);
+
+ if (chdir(path) < 0)
+ return -errno;
+
+ if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
+ return -errno;
+
+ if (chroot(".") < 0)
+ return -errno;
+
+ if (chdir("/") < 0)
+ return -errno;
+
+ return 0;
+}
+
+int reset_uid_gid(void) {
+
+ if (setgroups(0, NULL) < 0)
+ return -errno;
+
+ if (setresgid(0, 0, 0) < 0)
+ return -errno;
+
+ if (setresuid(0, 0, 0) < 0)
+ return -errno;
+
+ return 0;
+}
#endif /* NM_IGNORED */
diff --git a/src/systemd/src/shared/util.h b/src/systemd/src/basic/util.h
index 0c431a7b31..824a3325ba 100644
--- a/src/systemd/src/shared/util.h
+++ b/src/systemd/src/basic/util.h
@@ -31,7 +31,6 @@
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
-#include <signal.h>
#include <sched.h>
#include <limits.h>
#include <sys/types.h>
@@ -45,52 +44,10 @@
#include <sys/inotify.h>
#include <sys/statfs.h>
-#if 0 /* NM_IGNORED */
-#if SIZEOF_PID_T == 4
-# define PID_PRI PRIi32
-#elif SIZEOF_PID_T == 2
-# define PID_PRI PRIi16
-#else
-# error Unknown pid_t size
-#endif
-#define PID_FMT "%" PID_PRI
-
-#if SIZEOF_UID_T == 4
-# define UID_FMT "%" PRIu32
-#elif SIZEOF_UID_T == 2
-# define UID_FMT "%" PRIu16
-#else
-# error Unknown uid_t size
-#endif
-
-#if SIZEOF_GID_T == 4
-# define GID_FMT "%" PRIu32
-#elif SIZEOF_GID_T == 2
-# define GID_FMT "%" PRIu16
-#else
-# error Unknown gid_t size
-#endif
-
-#if SIZEOF_TIME_T == 8
-# define PRI_TIME PRIi64
-#elif SIZEOF_TIME_T == 4
-# define PRI_TIME PRIu32
-#else
-# error Unknown time_t size
-#endif
-
-#if SIZEOF_RLIM_T == 8
-# define RLIM_FMT "%" PRIu64
-#elif SIZEOF_RLIM_T == 4
-# define RLIM_FMT "%" PRIu32
-#else
-# error Unknown rlim_t size
-#endif
-#endif /* NM_IGNORED */
-
#include "macro.h"
#if 0 /* NM_IGNORED */
#include "missing.h"
+#include "formats-util.h"
#endif /* NM_IGNORED */
#include "time-util.h"
@@ -109,16 +66,6 @@
#define FORMAT_BYTES_MAX 8
-#define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
-#define ANSI_RED_ON "\x1B[31m"
-#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
-#define ANSI_GREEN_ON "\x1B[32m"
-#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
-#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
-#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m"
-#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
-#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
-
size_t page_size(void) _pure_;
#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
@@ -190,6 +137,7 @@ static inline char *startswith_no_case(const char *s, const char *prefix) {
}
char *endswith(const char *s, const char *postfix) _pure_;
+char *endswith_no_case(const char *s, const char *postfix) _pure_;
char *first_word(const char *s, const char *word) _pure_;
@@ -273,23 +221,15 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo
#define _FOREACH_WORD(word, length, s, separator, quoted, state) \
for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted)))
-pid_t get_parent_of_pid(pid_t pid, pid_t *ppid);
-
char *strappend(const char *s, const char *suffix);
char *strnappend(const char *s, const char *suffix, size_t length);
-char *replace_env(const char *format, char **env);
-char **replace_env_argv(char **argv, char **env);
-
int readlinkat_malloc(int fd, const char *p, char **ret);
int readlink_malloc(const char *p, char **r);
int readlink_value(const char *p, char **ret);
int readlink_and_make_absolute(const char *p, char **r);
int readlink_and_canonicalize(const char *p, char **r);
-int reset_all_signal_handlers(void);
-int reset_signal_mask(void);
-
char *strstrip(char *s);
char *delete_chars(char *s, const char *bad);
char *truncate_nl(char *s);
@@ -298,17 +238,6 @@ char *file_in_same_dir(const char *path, const char *filename);
int rmdir_parents(const char *path, const char *stop);
-int get_process_state(pid_t pid);
-int get_process_comm(pid_t pid, char **name);
-int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line);
-int get_process_exe(pid_t pid, char **name);
-int get_process_uid(pid_t pid, uid_t *uid);
-int get_process_gid(pid_t pid, gid_t *gid);
-int get_process_capeff(pid_t pid, char **capeff);
-int get_process_cwd(pid_t pid, char **cwd);
-int get_process_root(pid_t pid, char **root);
-int get_process_environ(pid_t pid, char **environ);
-
char hexchar(int x) _const_;
int unhexchar(char c) _const_;
char octchar(int x) _const_;
@@ -317,6 +246,7 @@ char decchar(int x) _const_;
int undecchar(char c) _const_;
char *cescape(const char *s);
+size_t cescape_char(char c, char *buf);
typedef enum UnescapeFlags {
UNESCAPE_RELAX = 1,
@@ -337,26 +267,6 @@ bool hidden_file(const char *filename) _pure_;
bool chars_intersect(const char *a, const char *b) _pure_;
-int make_stdio(int fd);
-int make_null_stdio(void);
-int make_console_stdio(void);
-
-int dev_urandom(void *p, size_t n);
-void random_bytes(void *p, size_t n);
-void initialize_srand(void);
-
-static inline uint64_t random_u64(void) {
- uint64_t u;
- random_bytes(&u, sizeof(u));
- return u;
-}
-
-static inline uint32_t random_u32(void) {
- uint32_t u;
- random_bytes(&u, sizeof(u));
- return u;
-}
-
/* For basic lookup tables with strictly enumerated entries */
#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
scope const char *name##_to_string(type i) { \
@@ -422,25 +332,8 @@ int close_all_fds(const int except[], unsigned n_except);
bool fstype_is_network(const char *fstype);
-int chvt(int vt);
-
-int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
-int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
-int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
-
-int reset_terminal_fd(int fd, bool switch_to_text);
-int reset_terminal(const char *name);
-
-int open_terminal(const char *name, int mode);
-int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout);
-int release_terminal(void);
-
int flush_fd(int fd);
-int ignore_signals(int sig, ...);
-int default_signals(int sig, ...);
-int sigaction_many(const struct sigaction *sa, ...);
-
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
@@ -452,24 +345,10 @@ bool is_device_path(const char *path);
int dir_is_empty(const char *path);
char* dirname_malloc(const char *path);
-void rename_process(const char name[8]);
-
-void sigset_add_many(sigset_t *ss, ...);
-int sigprocmask_many(int how, ...);
-
-bool hostname_is_set(void);
-
char* lookup_uid(uid_t uid);
-char* gethostname_malloc(void);
char* getlogname_malloc(void);
char* getusername_malloc(void);
-int getttyname_malloc(int fd, char **r);
-int getttyname_harder(int fd, char **r);
-
-int get_ctty_devnr(pid_t pid, dev_t *d);
-int get_ctty(pid_t, dev_t *_devnr, char **r);
-
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
@@ -480,43 +359,8 @@ int pipe_eof(int fd);
cpu_set_t* cpu_set_malloc(unsigned *ncpus);
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
-
#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
-int fd_columns(int fd);
-unsigned columns(void);
-int fd_lines(int fd);
-unsigned lines(void);
-void columns_lines_cache_reset(int _unused_ signum);
-
-bool on_tty(void);
-
-static inline const char *ansi_highlight(void) {
- return on_tty() ? ANSI_HIGHLIGHT_ON : "";
-}
-
-static inline const char *ansi_highlight_red(void) {
- return on_tty() ? ANSI_HIGHLIGHT_RED_ON : "";
-}
-
-static inline const char *ansi_highlight_green(void) {
- return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : "";
-}
-
-static inline const char *ansi_highlight_yellow(void) {
- return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : "";
-}
-
-static inline const char *ansi_highlight_blue(void) {
- return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : "";
-}
-
-static inline const char *ansi_highlight_off(void) {
- return on_tty() ? ANSI_HIGHLIGHT_OFF : "";
-}
-
int files_same(const char *filea, const char *fileb);
int running_in_chroot(void);
@@ -528,12 +372,6 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
int touch(const char *path);
-char *unquote(const char *s, const char *quotes);
-char *normalize_env_assignment(const char *s);
-
-int wait_for_terminate(pid_t pid, siginfo_t *status);
-int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
-
noreturn void freeze(void);
bool null_or_empty(struct stat *st) _pure_;
@@ -544,32 +382,17 @@ DIR *xopendirat(int dirfd, const char *name, int flags);
char *fstab_node_to_udev_node(const char *p);
-char *resolve_dev_console(char **active);
-bool tty_is_vc(const char *tty);
-bool tty_is_vc_resolve(const char *tty);
-bool tty_is_console(const char *tty) _pure_;
-int vtnr_from_tty(const char *tty);
-const char *default_term_for_tty(const char *tty);
-
void execute_directories(const char* const* directories, usec_t timeout, char *argv[]);
-int kill_and_sigcont(pid_t pid, int sig);
-
bool nulstr_contains(const char*nulstr, const char *needle);
bool plymouth_running(void);
-bool hostname_is_valid(const char *s) _pure_;
-char* hostname_cleanup(char *s, bool lowercase);
-
bool machine_name_is_valid(const char *s) _pure_;
char* strshorten(char *s, size_t l);
-int terminal_vhangup_fd(int fd);
-int terminal_vhangup(const char *name);
-
-int vt_disallocate(const char *name);
+int symlink_idempotent(const char *from, const char *to);
int symlink_atomic(const char *from, const char *to);
int mknod_atomic(const char *path, mode_t mode, dev_t dev);
@@ -635,11 +458,6 @@ int rlimit_from_string(const char *s) _pure_;
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
-const char *signal_to_string(int i) _const_;
-int signal_from_string(const char *s) _pure_;
-
-int signal_from_string_try_harder(const char *s);
-
extern int saved_argc;
extern char **saved_argv;
@@ -653,8 +471,6 @@ int fd_wait_for_event(int fd, int event, usec_t timeout);
void* memdup(const void *p, size_t l) _alloc_(2);
-int is_kernel_thread(pid_t pid);
-
int fd_inc_sndbuf(int fd, size_t n);
int fd_inc_rcvbuf(int fd, size_t n);
@@ -662,8 +478,6 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
int setrlimit_closest(int resource, const struct rlimit *rlim);
-int getenv_for_pid(pid_t pid, const char *field, char **_value);
-
bool http_url_is_valid(const char *url) _pure_;
bool documentation_url_is_valid(const char *url) _pure_;
@@ -671,8 +485,6 @@ bool http_etag_is_valid(const char *etag);
bool in_initrd(void);
-void warn_melody(void);
-
int get_home_dir(char **ret);
int get_shell(char **_ret);
@@ -940,19 +752,6 @@ int unlink_noerrno(const char *path);
_d_; \
})
-#define procfs_file_alloca(pid, field) \
- ({ \
- pid_t _pid_ = (pid); \
- const char *_r_; \
- if (_pid_ == 0) { \
- _r_ = ("/proc/self/" field); \
- } else { \
- _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \
- sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \
- } \
- _r_; \
- })
-
bool id128_is_valid(const char *s) _pure_;
int split_pair(const char *s, const char *sep, char **l, char **r);
@@ -963,12 +762,27 @@ int shall_restore_state(void);
* Normal qsort requires base to be nonnull. Here were require
* that only if nmemb > 0.
*/
-static inline void qsort_safe(void *base, size_t nmemb, size_t size,
- int (*compar)(const void *, const void *)) {
- if (nmemb) {
- assert(base);
- qsort(base, nmemb, size, compar);
- }
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) {
+ if (nmemb <= 1)
+ return;
+
+ assert(base);
+ qsort(base, nmemb, size, compar);
+}
+
+/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
+static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+
+ if (needlelen <= 0)
+ return (void*) haystack;
+
+ if (haystacklen < needlelen)
+ return NULL;
+
+ assert(haystack);
+ assert(needle);
+
+ return memmem(haystack, haystacklen, needle, needlelen);
}
int proc_cmdline(char **ret);
@@ -980,9 +794,6 @@ int container_get_leader(const char *machine, pid_t *pid);
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd);
-bool pid_is_alive(pid_t pid);
-bool pid_is_unwaited(pid_t pid);
-
#if 0 /* NM_IGNORED */
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
@@ -995,6 +806,13 @@ int open_tmpfile(const char *path, int flags);
int fd_warn_permissions(const char *path, int fd);
+#ifndef PERSONALITY_INVALID
+/* personality(7) documents that 0xffffffffUL is used for querying the
+ * current personality, hence let's use that here as error
+ * indicator. */
+#define PERSONALITY_INVALID 0xffffffffLU
+#endif
+
unsigned long personality_from_string(const char *p);
const char *personality_to_string(unsigned long);
@@ -1018,16 +836,15 @@ int bind_remount_recursive(const char *prefix, bool ro);
int fflush_and_check(FILE *f);
-int tempfn_xxxxxx(const char *p, char **ret);
-int tempfn_random(const char *p, char **ret);
-int tempfn_random_child(const char *p, char **ret);
-
-bool is_localhost(const char *hostname);
+int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
+int tempfn_random(const char *p, const char *extra, char **ret);
+int tempfn_random_child(const char *p, const char *extra, char **ret);
int take_password_lock(const char *root);
int is_symlink(const char *path);
int is_dir(const char *path, bool follow);
+int is_device_node(const char *path);
typedef enum UnquoteFlags {
UNQUOTE_RELAX = 1,
@@ -1039,8 +856,6 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_;
int free_and_strdup(char **p, const char *s);
-int sethostname_idempotent(const char *s);
-
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
@@ -1068,27 +883,12 @@ int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags);
int same_fd(int a, int b);
-int chattr_fd(int fd, bool b, unsigned mask);
-int chattr_path(const char *p, bool b, unsigned mask);
-int change_attr_fd(int fd, unsigned value, unsigned mask);
+int chattr_fd(int fd, unsigned value, unsigned mask);
+int chattr_path(const char *p, unsigned value, unsigned mask);
int read_attr_fd(int fd, unsigned *ret);
int read_attr_path(const char *p, unsigned *ret);
-typedef struct LockFile {
- char *path;
- int fd;
- int operation;
-} LockFile;
-
-int make_lock_file(const char *p, int operation, LockFile *ret);
-int make_lock_file_for(const char *p, int operation, LockFile *ret);
-void release_lock_file(LockFile *f);
-
-#define _cleanup_release_lock_file_ _cleanup_(release_lock_file)
-
-#define LOCK_FILE_INIT { .fd = -1, .path = NULL }
-
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
@@ -1101,3 +901,11 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility);
void cmsg_close_all(struct msghdr *mh);
int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath);
+
+char *shell_maybe_quote(const char *s);
+
+int parse_mode(const char *s, mode_t *ret);
+
+int mount_move_root(const char *path);
+
+int reset_uid_gid(void);
diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c
index c33761bc13..5a2abb747a 100644
--- a/src/systemd/src/libsystemd-network/dhcp-identifier.c
+++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c
@@ -51,8 +51,9 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
if (r < 0)
return r;
- duid->type = htobe16(DHCP6_DUID_EN);
- duid->en.pen = htobe32(SYSTEMD_PEN);
+ unaligned_write_be16(&duid->type, DHCP6_DUID_EN);
+ unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
+
*len = sizeof(duid->type) + sizeof(duid->en);
/* a bit of snake-oil perhaps, but no need to expose the machine-id
@@ -62,8 +63,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
return 0;
}
-
-int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id) {
+int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) {
#if 0 /* NM_IGNORED */
/* name is a pointer to memory in the udev_device struct, so must
have the same scope */
@@ -105,7 +105,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t
siphash24((uint8_t*)&id, mac, mac_len, HASH_KEY.bytes);
/* fold into 32 bits */
- *_id = (id & 0xffffffff) ^ (id >> 32);
+ unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32));
return 0;
}
diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h
index 5d4da21cb0..5046a367d9 100644
--- a/src/systemd/src/libsystemd-network/dhcp-identifier.h
+++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h
@@ -25,6 +25,7 @@
#include "macro.h"
#include "sparse-endian.h"
+#include "unaligned.h"
#include "sd-id128.h"
/* RFC 3315 section 9.1:
@@ -62,4 +63,4 @@ struct duid {
} _packed_;
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
-int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, uint32_t *_id);
+int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id);
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
index 5d63866cf7..12233242e2 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c
@@ -30,6 +30,7 @@
#include "util.h"
#include "refcnt.h"
+#include "random-util.h"
#include "async.h"
#include "dhcp-protocol.h"
@@ -39,7 +40,7 @@
#include "sd-dhcp-client.h"
#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */
-#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN
+#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
struct sd_dhcp_client {
RefCount n_ref;
@@ -1471,7 +1472,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
_cleanup_free_ DHCPMessage *message = NULL;
int buflen = 0, len, r;
const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
- bool expect_chaddr;
+ const struct ether_addr *expected_chaddr = NULL;
uint8_t expected_hlen = 0;
assert(s);
@@ -1516,11 +1517,11 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
if (client->arp_type == ARPHRD_ETHER) {
expected_hlen = ETH_ALEN;
- expect_chaddr = true;
+ expected_chaddr = (const struct ether_addr *) &client->mac_addr;
} else {
/* Non-ethernet links expect zero chaddr */
expected_hlen = 0;
- expect_chaddr = false;
+ expected_chaddr = &zero_mac;
}
if (message->hlen != expected_hlen) {
@@ -1528,10 +1529,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
return 0;
}
- if (memcmp(&message->chaddr[0], expect_chaddr ?
- (void *)&client->mac_addr :
- (void *)&zero_mac,
- ETH_ALEN)) {
+ if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
log_dhcp_client(client, "received chaddr does not match "
"expected: ignoring");
return 0;
@@ -1592,7 +1590,7 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
} else if ((size_t)len < sizeof(DHCPPacket))
return 0;
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ CMSG_FOREACH(cmsg, &msg) {
if (cmsg->cmsg_level == SOL_PACKET &&
cmsg->cmsg_type == PACKET_AUXDATA &&
cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
index ae44415df2..d92df6d529 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c
@@ -29,11 +29,12 @@
#include "fileio.h"
#include "unaligned.h"
#include "in-addr-util.h"
-
+#include "hostname-util.h"
#include "dhcp-protocol.h"
#include "dhcp-lease-internal.h"
#include "sd-dhcp-lease.h"
#include "network-internal.h"
+#include "dns-domain.h"
int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) {
assert_return(lease, -EINVAL);
@@ -537,8 +538,17 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
if (e)
*e = 0;
- if (!hostname_is_valid(domainname) || is_localhost(domainname))
+ if (is_localhost(domainname))
+ break;
+
+ r = dns_name_is_valid(domainname);
+ if (r <= 0) {
+ if (r < 0)
+ log_error_errno(r, "Failed to validate domain name: %s: %m", domainname);
+ if (r == 0)
+ log_warning("Domain name is not valid, ignoring: %s", domainname);
break;
+ }
free(lease->domainname);
lease->domainname = domainname;
@@ -726,7 +736,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r >= 0) {
_cleanup_free_ char *client_id_hex = NULL;
- client_id_hex = hexmem (client_id, client_id_len);
+ client_id_hex = hexmem(client_id, client_id_len);
if (!client_id_hex) {
r = -ENOMEM;
goto finish;
diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
index 8b29898b14..6291fa1a53 100644
--- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c
@@ -32,6 +32,7 @@
#endif /* NM_IGNORED */
#include "util.h"
#include "refcnt.h"
+#include "random-util.h"
#include "network-internal.h"
#include "sd-dhcp6-client.h"
@@ -1208,6 +1209,7 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
client_reset(client);
sd_dhcp6_client_detach_event(client);
+ sd_dhcp6_lease_unref(client->lease);
free(client->req_opts);
free(client);
diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
index ccd6bdf0b0..f67386a3a3 100644
--- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c
@@ -29,6 +29,7 @@
#include "siphash24.h"
#include "list.h"
#include "refcnt.h"
+#include "random-util.h"
#include "ipv4ll-internal.h"
#include "sd-ipv4ll.h"
diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
index 909467d696..263b1a893e 100644
--- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c
@@ -28,6 +28,7 @@
#include "util.h"
#include "macro.h"
#include "sd-id128.h"
+#include "random-util.h"
#if 0 /* NM_IGNORED */
_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c
new file mode 100644
index 0000000000..59fb3f9351
--- /dev/null
+++ b/src/systemd/src/shared/dns-domain.c
@@ -0,0 +1,617 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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 "nm-sd-adapt.h"
+
+#ifdef HAVE_LIBIDN
+#include <idna.h>
+#include <stringprep.h>
+#endif
+
+#include "dns-domain.h"
+
+int dns_label_unescape(const char **name, char *dest, size_t sz) {
+ const char *n;
+ char *d;
+ int r = 0;
+
+ assert(name);
+ assert(*name);
+ assert(dest);
+
+ n = *name;
+ d = dest;
+
+ for (;;) {
+ if (*n == '.') {
+ n++;
+ break;
+ }
+
+ if (*n == 0)
+ break;
+
+ if (sz <= 0)
+ return -ENOSPC;
+
+ if (r >= DNS_LABEL_MAX)
+ return -EINVAL;
+
+ if (*n == '\\') {
+ /* Escaped character */
+
+ n++;
+
+ if (*n == 0)
+ /* Ending NUL */
+ return -EINVAL;
+
+ else if (*n == '\\' || *n == '.') {
+ /* Escaped backslash or dot */
+ *(d++) = *(n++);
+ sz--;
+ r++;
+
+ } else if (n[0] >= '0' && n[0] <= '9') {
+ unsigned k;
+
+ /* Escaped literal ASCII character */
+
+ if (!(n[1] >= '0' && n[1] <= '9') ||
+ !(n[2] >= '0' && n[2] <= '9'))
+ return -EINVAL;
+
+ k = ((unsigned) (n[0] - '0') * 100) +
+ ((unsigned) (n[1] - '0') * 10) +
+ ((unsigned) (n[2] - '0'));
+
+ /* Don't allow CC characters or anything that doesn't fit in 8bit */
+ if (k < ' ' || k > 255 || k == 127)
+ return -EINVAL;
+
+ *(d++) = (char) k;
+ sz--;
+ r++;
+
+ n += 3;
+ } else
+ return -EINVAL;
+
+ } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) {
+
+ /* Normal character */
+ *(d++) = *(n++);
+ sz--;
+ r++;
+ } else
+ return -EINVAL;
+ }
+
+ /* Empty label that is not at the end? */
+ if (r == 0 && *n)
+ return -EINVAL;
+
+ if (sz >= 1)
+ *d = 0;
+
+ *name = n;
+ return r;
+}
+
+int dns_label_escape(const char *p, size_t l, char **ret) {
+ _cleanup_free_ char *s = NULL;
+ char *q;
+ int r;
+
+ assert(p);
+ assert(ret);
+
+ if (l > DNS_LABEL_MAX)
+ return -EINVAL;
+
+ s = malloc(l * 4 + 1);
+ if (!s)
+ return -ENOMEM;
+
+ q = s;
+ while (l > 0) {
+
+ if (*p == '.' || *p == '\\') {
+
+ /* Dot or backslash */
+ *(q++) = '\\';
+ *(q++) = *p;
+
+ } else if (*p == '_' ||
+ *p == '-' ||
+ (*p >= '0' && *p <= '9') ||
+ (*p >= 'a' && *p <= 'z') ||
+ (*p >= 'A' && *p <= 'Z')) {
+
+ /* Proper character */
+ *(q++) = *p;
+ } else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) {
+
+ /* Everything else */
+ *(q++) = '\\';
+ *(q++) = '0' + (char) ((uint8_t) *p / 100);
+ *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10);
+ *(q++) = '0' + (char) ((uint8_t) *p % 10);
+
+ } else
+ return -EINVAL;
+
+ p++;
+ l--;
+ }
+
+ *q = 0;
+ *ret = s;
+ r = q - s;
+ s = NULL;
+
+ return r;
+}
+
+int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
+#ifdef HAVE_LIBIDN
+ _cleanup_free_ uint32_t *input = NULL;
+ size_t input_size;
+ const char *p;
+ bool contains_8bit = false;
+
+ assert(encoded);
+ assert(decoded);
+ assert(decoded_max >= DNS_LABEL_MAX);
+
+ if (encoded_size <= 0)
+ return 0;
+
+ for (p = encoded; p < encoded + encoded_size; p++)
+ if ((uint8_t) *p > 127)
+ contains_8bit = true;
+
+ if (!contains_8bit)
+ return 0;
+
+ input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+ if (!input)
+ return -ENOMEM;
+
+ if (idna_to_ascii_4i(input, input_size, decoded, 0) != 0)
+ return -EINVAL;
+
+ return strlen(decoded);
+#else
+ return 0;
+#endif
+}
+
+int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
+#ifdef HAVE_LIBIDN
+ size_t input_size, output_size;
+ _cleanup_free_ uint32_t *input = NULL;
+ _cleanup_free_ char *result = NULL;
+ uint32_t *output = NULL;
+ size_t w;
+
+ /* To be invoked after unescaping */
+
+ assert(encoded);
+ assert(decoded);
+
+ if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1)
+ return 0;
+
+ if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0)
+ return 0;
+
+ input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
+ if (!input)
+ return -ENOMEM;
+
+ output_size = input_size;
+ output = newa(uint32_t, output_size);
+
+ idna_to_unicode_44i(input, input_size, output, &output_size, 0);
+
+ result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
+ if (!result)
+ return -ENOMEM;
+ if (w <= 0)
+ return 0;
+ if (w+1 > decoded_max)
+ return -EINVAL;
+
+ memcpy(decoded, result, w+1);
+ return w;
+#else
+ return 0;
+#endif
+}
+
+int dns_name_normalize(const char *s, char **_ret) {
+ _cleanup_free_ char *ret = NULL;
+ size_t n = 0, allocated = 0;
+ const char *p = s;
+ bool first = true;
+ int r;
+
+ assert(s);
+
+ for (;;) {
+ _cleanup_free_ char *t = NULL;
+ char label[DNS_LABEL_MAX];
+ int k;
+
+ r = dns_label_unescape(&p, label, sizeof(label));
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ if (*p != 0)
+ return -EINVAL;
+ break;
+ }
+
+ k = dns_label_undo_idna(label, r, label, sizeof(label));
+ if (k < 0)
+ return k;
+ if (k > 0)
+ r = k;
+
+ r = dns_label_escape(label, r, &t);
+ if (r < 0)
+ return r;
+
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
+ return -ENOMEM;
+
+ if (!first)
+ ret[n++] = '.';
+ else
+ first = false;
+
+ memcpy(ret + n, t, r);
+ n += r;
+ }
+
+ if (n > DNS_NAME_MAX)
+ return -EINVAL;
+
+ if (!GREEDY_REALLOC(ret, allocated, n + 1))
+ return -ENOMEM;
+
+ ret[n] = 0;
+
+ if (_ret) {
+ *_ret = ret;
+ ret = NULL;
+ }
+
+ return 0;
+}
+
+#if 0 /* NM_IGNORED */
+unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
+ const char *p = s;
+ unsigned long ul = hash_key[0];
+ int r;
+
+ assert(p);
+
+ while (*p) {
+ char label[DNS_LABEL_MAX+1];
+ int k;
+
+ r = dns_label_unescape(&p, label, sizeof(label));
+ if (r < 0)
+ break;
+
+ k = dns_label_undo_idna(label, r, label, sizeof(label));
+ if (k < 0)
+ break;
+ if (k > 0)
+ r = k;
+
+ label[r] = 0;
+ ascii_strlower(label);
+
+ ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
+ }
+
+ return ul;
+}
+
+int dns_name_compare_func(const void *a, const void *b) {
+ const char *x = a, *y = b;
+ int r, q, k, w;
+
+ assert(a);
+ assert(b);
+
+ for (;;) {
+ char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
+
+ if (*x == 0 && *y == 0)
+ return 0;
+
+ r = dns_label_unescape(&x, la, sizeof(la));
+ q = dns_label_unescape(&y, lb, sizeof(lb));
+ if (r < 0 || q < 0)
+ return r - q;
+
+ k = dns_label_undo_idna(la, r, la, sizeof(la));
+ w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
+ if (k < 0 || w < 0)
+ return k - w;
+ if (k > 0)
+ r = k;
+ if (w > 0)
+ r = w;
+
+ la[r] = lb[q] = 0;
+ r = strcasecmp(la, lb);
+ if (r != 0)
+ return r;
+ }
+}
+
+const struct hash_ops dns_name_hash_ops = {
+ .hash = dns_name_hash_func,
+ .compare = dns_name_compare_func
+};
+
+int dns_name_equal(const char *x, const char *y) {
+ int r, q, k, w;
+
+ assert(x);
+ assert(y);
+
+ for (;;) {
+ char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
+
+ if (*x == 0 && *y == 0)
+ return true;
+
+ r = dns_label_unescape(&x, la, sizeof(la));
+ if (r < 0)
+ return r;
+
+ k = dns_label_undo_idna(la, r, la, sizeof(la));
+ if (k < 0)
+ return k;
+ if (k > 0)
+ r = k;
+
+ q = dns_label_unescape(&y, lb, sizeof(lb));
+ if (q < 0)
+ return q;
+ w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
+ if (w < 0)
+ return w;
+ if (w > 0)
+ q = w;
+
+ la[r] = lb[q] = 0;
+ if (strcasecmp(la, lb))
+ return false;
+ }
+}
+
+int dns_name_endswith(const char *name, const char *suffix) {
+ const char *n, *s, *saved_n = NULL;
+ int r, q, k, w;
+
+ assert(name);
+ assert(suffix);
+
+ n = name;
+ s = suffix;
+
+ for (;;) {
+ char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1];
+
+ r = dns_label_unescape(&n, ln, sizeof(ln));
+ if (r < 0)
+ return r;
+ k = dns_label_undo_idna(ln, r, ln, sizeof(ln));
+ if (k < 0)
+ return k;
+ if (k > 0)
+ r = k;
+
+ if (!saved_n)
+ saved_n = n;
+
+ q = dns_label_unescape(&s, ls, sizeof(ls));
+ if (q < 0)
+ return q;
+ w = dns_label_undo_idna(ls, q, ls, sizeof(ls));
+ if (w < 0)
+ return w;
+ if (w > 0)
+ q = w;
+
+ if (r == 0 && q == 0)
+ return true;
+ if (r == 0 && saved_n == n)
+ return false;
+
+ ln[r] = ls[q] = 0;
+
+ if (r != q || strcasecmp(ln, ls)) {
+
+ /* Not the same, let's jump back, and try with the next label again */
+ s = suffix;
+ n = saved_n;
+ saved_n = NULL;
+ }
+ }
+}
+
+int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
+ const uint8_t *p;
+ int r;
+
+ assert(a);
+ assert(ret);
+
+ p = (const uint8_t*) a;
+
+ if (family == AF_INET)
+ r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
+ else if (family == AF_INET6)
+ r = asprintf(ret, "%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.ip6.arpa",
+ hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4),
+ hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4),
+ hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4),
+ hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4),
+ hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4),
+ hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4),
+ hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4),
+ hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4));
+ else
+ return -EAFNOSUPPORT;
+ if (r < 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
+int dns_name_address(const char *p, int *family, union in_addr_union *address) {
+ int r;
+
+ assert(p);
+ assert(family);
+ assert(address);
+
+ r = dns_name_endswith(p, "in-addr.arpa");
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ uint8_t a[4];
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(a); i++) {
+ char label[DNS_LABEL_MAX+1];
+
+ r = dns_label_unescape(&p, label, sizeof(label));
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EINVAL;
+ if (r > 3)
+ return -EINVAL;
+
+ r = safe_atou8(label, &a[i]);
+ if (r < 0)
+ return r;
+ }
+
+ r = dns_name_equal(p, "in-addr.arpa");
+ if (r <= 0)
+ return r;
+
+ *family = AF_INET;
+ address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
+ ((uint32_t) a[2] << 16) |
+ ((uint32_t) a[1] << 8) |
+ (uint32_t) a[0]);
+
+ return 1;
+ }
+
+ r = dns_name_endswith(p, "ip6.arpa");
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ struct in6_addr a;
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
+ char label[DNS_LABEL_MAX+1];
+ int x, y;
+
+ r = dns_label_unescape(&p, label, sizeof(label));
+ if (r <= 0)
+ return r;
+ if (r != 1)
+ return -EINVAL;
+ x = unhexchar(label[0]);
+ if (x < 0)
+ return -EINVAL;
+
+ r = dns_label_unescape(&p, label, sizeof(label));
+ if (r <= 0)
+ return r;
+ if (r != 1)
+ return -EINVAL;
+ y = unhexchar(label[0]);
+ if (y < 0)
+ return -EINVAL;
+
+ a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
+ }
+
+ r = dns_name_equal(p, "ip6.arpa");
+ if (r <= 0)
+ return r;
+
+ *family = AF_INET6;
+ address->in6 = a;
+ return 1;
+ }
+
+ return 0;
+}
+
+int dns_name_root(const char *name) {
+ char label[DNS_LABEL_MAX+1];
+ int r;
+
+ assert(name);
+
+ r = dns_label_unescape(&name, label, sizeof(label));
+ if (r < 0)
+ return r;
+
+ return r == 0 && *name == 0;
+}
+
+int dns_name_single_label(const char *name) {
+ char label[DNS_LABEL_MAX+1];
+ int r;
+
+ assert(name);
+
+ r = dns_label_unescape(&name, label, sizeof(label));
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 0;
+
+ r = dns_label_unescape(&name, label, sizeof(label));
+ if (r < 0)
+ return r;
+
+ return r == 0 && *name == 0;
+}
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h
new file mode 100644
index 0000000000..7aeada783d
--- /dev/null
+++ b/src/systemd/src/shared/dns-domain.h
@@ -0,0 +1,64 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 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/>.
+ ***/
+
+#pragma once
+
+#include "nm-sd-adapt.h"
+
+#if 0 /* NM_IGNORED */
+#include "hashmap.h"
+#endif /* NM_IGNORED */
+#include "in-addr-util.h"
+
+#define DNS_LABEL_MAX 63
+#define DNS_NAME_MAX 255
+
+int dns_label_unescape(const char **name, char *dest, size_t sz);
+int dns_label_escape(const char *p, size_t l, char **ret);
+
+int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
+int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
+
+int dns_name_normalize(const char *s, char **_ret);
+static inline int dns_name_is_valid(const char *s) {
+ int r;
+ r = dns_name_normalize(s, NULL);
+ if (r == -EINVAL)
+ return 0;
+ if (r < 0)
+ return r;
+ return 1;
+}
+
+#if 0 /* NM_IGNORED */
+unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]);
+int dns_name_compare_func(const void *a, const void *b);
+extern const struct hash_ops dns_name_hash_ops;
+
+int dns_name_equal(const char *x, const char *y);
+int dns_name_endswith(const char *name, const char *suffix);
+
+int dns_name_reverse(int family, const union in_addr_union *a, char **ret);
+int dns_name_address(const char *p, int *family, union in_addr_union *a);
+
+int dns_name_root(const char *name);
+int dns_name_single_label(const char *name);
+#endif /* NM_IGNORED */