summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/architecture.h16
-rw-r--r--src/shared/ask-password-api.c364
-rw-r--r--src/shared/ask-password-api.h25
-rw-r--r--src/shared/base-filesystem.c12
-rw-r--r--src/shared/bus-util.c161
-rw-r--r--src/shared/bus-util.h10
-rw-r--r--src/shared/conf-parser.c117
-rw-r--r--src/shared/conf-parser.h7
-rw-r--r--src/shared/dns-domain.c11
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/shared/dropin.c5
-rw-r--r--src/shared/fstab-util.c16
-rw-r--r--src/shared/fstab-util.h1
-rw-r--r--src/shared/install.c3
-rw-r--r--src/shared/logs-show.c12
-rw-r--r--src/shared/machine-image.c119
-rw-r--r--src/shared/pager.c27
-rw-r--r--src/shared/path-lookup.c6
-rw-r--r--src/shared/pty.c633
-rw-r--r--src/shared/pty.h72
-rw-r--r--src/shared/ptyfwd.c49
-rw-r--r--src/shared/ptyfwd.h12
-rw-r--r--src/shared/sleep-config.c2
-rw-r--r--src/shared/spawn-ask-password-agent.c12
-rw-r--r--src/shared/sysctl-util.c13
25 files changed, 692 insertions, 1015 deletions
diff --git a/src/shared/architecture.h b/src/shared/architecture.h
index f5bbf65a90..61d067cad7 100644
--- a/src/shared/architecture.h
+++ b/src/shared/architecture.h
@@ -78,9 +78,11 @@ int uname_architecture(void);
#if defined(__x86_64__)
# define native_architecture() ARCHITECTURE_X86_64
# define LIB_ARCH_TUPLE "x86_64-linux-gnu"
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__i386__)
# define native_architecture() ARCHITECTURE_X86
# define LIB_ARCH_TUPLE "i386-linux-gnu"
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__powerpc64__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_PPC64
@@ -89,6 +91,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_PPC64_LE
# define LIB_ARCH_TUPLE "powerpc64le-linux-gnu"
# endif
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__powerpc__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_PPC
@@ -97,15 +100,18 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_PPC_LE
# error "Missing LIB_ARCH_TUPLE for PPCLE"
# endif
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__ia64__)
# define native_architecture() ARCHITECTURE_IA64
# define LIB_ARCH_TUPLE "ia64-linux-gnu"
#elif defined(__hppa64__)
# define native_architecture() ARCHITECTURE_PARISC64
# error "Missing LIB_ARCH_TUPLE for HPPA64"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__hppa__)
# define native_architecture() ARCHITECTURE_PARISC
# define LIB_ARCH_TUPLE "hppa‑linux‑gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__s390x__)
# define native_architecture() ARCHITECTURE_S390X
# define LIB_ARCH_TUPLE "s390x-linux-gnu"
@@ -115,9 +121,11 @@ int uname_architecture(void);
#elif defined(__sparc64__)
# define native_architecture() ARCHITECTURE_SPARC64
# define LIB_ARCH_TUPLE "sparc64-linux-gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__sparc__)
# define native_architecture() ARCHITECTURE_SPARC
# define LIB_ARCH_TUPLE "sparc-linux-gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__mips64__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_MIPS64
@@ -126,6 +134,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_MIPS64_LE
# error "Missing LIB_ARCH_TUPLE for MIPS64_LE"
# endif
+# define PROC_CPUINFO_MODEL "cpu model"
#elif defined(__mips__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_MIPS
@@ -134,6 +143,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_MIPS_LE
# define LIB_ARCH_TUPLE "mipsel-linux-gnu"
# endif
+# define PROC_CPUINFO_MODEL "cpu model"
#elif defined(__alpha__)
# define native_architecture() ARCHITECTURE_ALPHA
# define LIB_ARCH_TUPLE "alpha-linux-gnu"
@@ -169,6 +179,7 @@ int uname_architecture(void);
# define LIB_ARCH_TUPLE "arm-linux-gnu"
# endif
# endif
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__sh64__)
# define native_architecture() ARCHITECTURE_SH64
# error "Missing LIB_ARCH_TUPLE for SH64"
@@ -188,5 +199,10 @@ int uname_architecture(void);
# error "Please register your architecture here!"
#endif
+#ifndef PROC_CPUINFO_MODEL
+#warning "PROC_CPUINFO_MODEL not defined for your architecture"
+#define PROC_CPUINFO_MODEL "model name"
+#endif
+
const char *architecture_to_string(int a) _const_;
int architecture_from_string(const char *s) _pure_;
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index f5cff6fc56..f8cf11b297 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -18,28 +18,158 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
-#include <termios.h>
-#include <unistd.h>
-#include <poll.h>
-#include <sys/inotify.h>
+
#include <errno.h>
#include <fcntl.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <sys/un.h>
+#include <poll.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <string.h>
+#include <sys/inotify.h>
#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <termios.h>
+#include <unistd.h>
-#include "util.h"
#include "formats-util.h"
+#include "missing.h"
#include "mkdir.h"
-#include "strv.h"
#include "random-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "util.h"
#include "ask-password-api.h"
+#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
+
+static int lookup_key(const char *keyname, key_serial_t *ret) {
+ key_serial_t serial;
+
+ assert(keyname);
+ assert(ret);
+
+ serial = request_key("user", keyname, NULL, 0);
+ if (serial == -1)
+ return -errno;
+
+ *ret = serial;
+ return 0;
+}
+
+static int retrieve_key(key_serial_t serial, char ***ret) {
+ _cleanup_free_ char *p = NULL;
+ long m = 100, n;
+ char **l;
+
+ assert(ret);
+
+ for (;;) {
+ p = new(char, m);
+ if (!p)
+ return -ENOMEM;
+
+ n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
+ if (n < 0)
+ return -errno;
+
+ if (n < m)
+ break;
+
+ free(p);
+ m *= 2;
+ }
+
+ l = strv_parse_nulstr(p, n);
+ if (!l)
+ return -ENOMEM;
+
+ *ret = l;
+ return 0;
+}
+
+static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_free_ char *p = NULL;
+ key_serial_t serial;
+ size_t n;
+ int r;
+
+ assert(keyname);
+ assert(passwords);
+
+ if (!(flags & ASK_PASSWORD_PUSH_CACHE))
+ return 0;
+
+ r = lookup_key(keyname, &serial);
+ if (r >= 0) {
+ r = retrieve_key(serial, &l);
+ if (r < 0)
+ return r;
+ } else if (r != -ENOKEY)
+ return r;
+
+ r = strv_extend_strv(&l, passwords, true);
+ if (r <= 0)
+ return r;
+
+ r = strv_make_nulstr(l, &p, &n);
+ if (r < 0)
+ return r;
+
+ /* Truncate trailing NUL */
+ assert(n > 0);
+ assert(p[n-1] == 0);
+
+ serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING);
+ if (serial == -1)
+ return -errno;
+
+ if (keyctl(KEYCTL_SET_TIMEOUT,
+ (unsigned long) serial,
+ (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
+ log_debug_errno(errno, "Failed to adjust timeout: %m");
+
+ log_debug("Added key to keyring as %" PRIi32 ".", serial);
+
+ return 1;
+}
+
+static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
+ int r;
+
+ assert(keyname);
+ assert(passwords);
+
+ r = add_to_keyring(keyname, flags, passwords);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add password to keyring: %m");
+
+ return 0;
+}
+
+int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
+
+ key_serial_t serial;
+ int r;
+
+ assert(keyname);
+ assert(ret);
+
+ if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
+ return -EUNATCH;
+
+ r = lookup_key(keyname, &serial);
+ if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
+ return -ENOKEY;
+ if (r < 0)
+ return r;
+
+ return retrieve_key(serial, ret);
+}
+
static void backspace_chars(int ttyfd, size_t p) {
if (ttyfd < 0)
@@ -54,10 +184,11 @@ static void backspace_chars(int ttyfd, size_t p) {
int ask_password_tty(
const char *message,
+ const char *keyname,
usec_t until,
- bool echo,
+ AskPasswordFlags flags,
const char *flag_file,
- char **_passphrase) {
+ char **ret) {
struct termios old_termios, new_termios;
char passphrase[LINE_MAX], *x;
@@ -66,15 +197,19 @@ int ask_password_tty(
_cleanup_close_ int ttyfd = -1, notify = -1;
struct pollfd pollfd[2];
bool reset_tty = false;
- bool silent_mode = false;
bool dirty = false;
enum {
POLL_TTY,
POLL_INOTIFY
};
- assert(message);
- assert(_passphrase);
+ assert(ret);
+
+ if (flags & ASK_PASSWORD_NO_TTY)
+ return -EUNATCH;
+
+ if (!message)
+ message = "Password:";
if (flag_file) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
@@ -97,10 +232,10 @@ int ask_password_tty(
goto finish;
}
- loop_write(ttyfd, ANSI_HIGHLIGHT_ON, sizeof(ANSI_HIGHLIGHT_ON)-1, false);
+ loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false);
loop_write(ttyfd, message, strlen(message), false);
loop_write(ttyfd, " ", 1, false);
- loop_write(ttyfd, ANSI_HIGHLIGHT_OFF, sizeof(ANSI_HIGHLIGHT_OFF)-1, false);
+ loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false);
new_termios = old_termios;
new_termios.c_lflag &= ~(ICANON|ECHO);
@@ -145,7 +280,7 @@ int ask_password_tty(
goto finish;
}
- k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
+ k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
if (k < 0) {
if (errno == EINTR)
continue;
@@ -157,7 +292,7 @@ int ask_password_tty(
goto finish;
}
- if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
+ if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
flush_fd(notify);
if (pollfd[POLL_TTY].revents == 0)
@@ -178,7 +313,7 @@ int ask_password_tty(
break;
else if (c == 21) { /* C-u */
- if (!silent_mode)
+ if (!(flags & ASK_PASSWORD_SILENT))
backspace_chars(ttyfd, p);
p = 0;
@@ -186,28 +321,28 @@ int ask_password_tty(
if (p > 0) {
- if (!silent_mode)
+ if (!(flags & ASK_PASSWORD_SILENT))
backspace_chars(ttyfd, 1);
p--;
- } else if (!dirty && !silent_mode) {
+ } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
- silent_mode = true;
+ flags |= ASK_PASSWORD_SILENT;
/* There are two ways to enter silent
* mode. Either by pressing backspace
- * as first key (and only as first key),
- * or ... */
+ * as first key (and only as first
+ * key), or ... */
if (ttyfd >= 0)
loop_write(ttyfd, "(no echo) ", 10, false);
} else if (ttyfd >= 0)
loop_write(ttyfd, "\a", 1, false);
- } else if (c == '\t' && !silent_mode) {
+ } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
backspace_chars(ttyfd, p);
- silent_mode = true;
+ flags |= ASK_PASSWORD_SILENT;
/* ... or by pressing TAB at any time. */
@@ -221,8 +356,8 @@ int ask_password_tty(
passphrase[p++] = c;
- if (!silent_mode && ttyfd >= 0)
- loop_write(ttyfd, echo ? &c : "*", 1, false);
+ if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0)
+ loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
dirty = true;
}
@@ -234,7 +369,10 @@ int ask_password_tty(
goto finish;
}
- *_passphrase = x;
+ if (keyname)
+ (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x));
+
+ *ret = x;
r = 0;
finish:
@@ -247,52 +385,38 @@ finish:
}
static int create_socket(char **name) {
- int fd;
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa = {
+ union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
- int one = 1;
- int r = 0;
+ _cleanup_close_ int fd = -1;
+ static const int one = 1;
char *c;
+ int r;
assert(name);
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
- return log_error_errno(errno, "socket() failed: %m");
+ return -errno;
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
RUN_WITH_UMASK(0177) {
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- }
-
- if (r < 0) {
- r = -errno;
- log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
- goto fail;
+ if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ return -errno;
}
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
- r = -errno;
- log_error_errno(errno, "SO_PASSCRED failed: %m");
- goto fail;
- }
+ if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
+ return -errno;
c = strdup(sa.un.sun_path);
- if (!c) {
- r = log_oom();
- goto fail;
- }
+ if (!c)
+ return -ENOMEM;
*name = c;
- return fd;
-fail:
- safe_close(fd);
+ r = fd;
+ fd = -1;
return r;
}
@@ -301,10 +425,10 @@ int ask_password_agent(
const char *message,
const char *icon,
const char *id,
+ const char *keyname,
usec_t until,
- bool echo,
- bool accept_cached,
- char ***_passphrases) {
+ AskPasswordFlags flags,
+ char ***ret) {
enum {
FD_SOCKET,
@@ -312,35 +436,38 @@ int ask_password_agent(
_FD_MAX
};
+ _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
char final[sizeof(temp)] = "";
- _cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *socket_name = NULL;
- _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
- sigset_t mask, oldmask;
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
struct pollfd pollfd[_FD_MAX];
+ sigset_t mask, oldmask;
int r;
- assert(_passphrases);
+ assert(ret);
+
+ if (flags & ASK_PASSWORD_NO_AGENT)
+ return -EUNATCH;
assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
- mkdir_p_label("/run/systemd/ask-password", 0755);
+ (void) mkdir_p_label("/run/systemd/ask-password", 0755);
fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
- r = log_error_errno(errno,
- "Failed to create password file: %m");
+ r = -errno;
goto finish;
}
- fchmod(fd, 0644);
+ (void) fchmod(fd, 0644);
f = fdopen(fd, "w");
if (!f) {
- r = log_error_errno(errno, "Failed to allocate FILE: %m");
+ r = -errno;
goto finish;
}
@@ -348,7 +475,7 @@ int ask_password_agent(
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0) {
- r = log_error_errno(errno, "signalfd(): %m");
+ r = -errno;
goto finish;
}
@@ -367,8 +494,8 @@ int ask_password_agent(
"NotAfter="USEC_FMT"\n",
getpid(),
socket_name,
- accept_cached ? 1 : 0,
- echo ? 1 : 0,
+ (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
+ (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
until);
if (message)
@@ -381,10 +508,8 @@ int ask_password_agent(
fprintf(f, "Id=%s\n", id);
r = fflush_and_check(f);
- if (r < 0) {
- log_error_errno(r, "Failed to write query file: %m");
+ if (r < 0)
goto finish;
- }
memcpy(final, temp, sizeof(temp));
@@ -393,7 +518,7 @@ int ask_password_agent(
final[sizeof(final)-9] = 'k';
if (rename(temp, final) < 0) {
- r = log_error_errno(errno, "Failed to rename query file: %m");
+ r = -errno;
goto finish;
}
@@ -419,7 +544,6 @@ int ask_password_agent(
t = now(CLOCK_MONOTONIC);
if (until > 0 && until <= t) {
- log_notice("Timed out");
r = -ETIME;
goto finish;
}
@@ -429,12 +553,11 @@ int ask_password_agent(
if (errno == EINTR)
continue;
- r = log_error_errno(errno, "poll() failed: %m");
+ r = -errno;
goto finish;
}
if (k <= 0) {
- log_notice("Timed out");
r = -ETIME;
goto finish;
}
@@ -445,7 +568,6 @@ int ask_password_agent(
}
if (pollfd[FD_SOCKET].revents != POLLIN) {
- log_error("Unexpected poll() event.");
r = -EIO;
goto finish;
}
@@ -467,14 +589,14 @@ int ask_password_agent(
errno == EINTR)
continue;
- r = log_error_errno(errno, "recvmsg() failed: %m");
+ r = -errno;
goto finish;
}
cmsg_close_all(&msghdr);
if (n <= 0) {
- log_error("Message too short");
+ log_debug("Message too short");
continue;
}
@@ -482,84 +604,100 @@ int ask_password_agent(
control.cmsghdr.cmsg_level != SOL_SOCKET ||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
- log_warning("Received message without credentials. Ignoring.");
+ log_debug("Received message without credentials. Ignoring.");
continue;
}
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
if (ucred->uid != 0) {
- log_warning("Got request from unprivileged user. Ignoring.");
+ log_debug("Got request from unprivileged user. Ignoring.");
continue;
}
if (passphrase[0] == '+') {
- char **l;
-
+ /* An empty message refers to the empty password */
if (n == 1)
l = strv_new("", NULL);
else
l = strv_parse_nulstr(passphrase+1, n-1);
- /* An empty message refers to the empty password */
-
if (!l) {
r = -ENOMEM;
goto finish;
}
if (strv_length(l) <= 0) {
- strv_free(l);
- log_error("Invalid packet");
+ l = strv_free(l);
+ log_debug("Invalid packet");
continue;
}
- *_passphrases = l;
+ break;
+ }
- } else if (passphrase[0] == '-') {
+ if (passphrase[0] == '-') {
r = -ECANCELED;
goto finish;
- } else {
- log_error("Invalid packet");
- continue;
}
- break;
+ log_debug("Invalid packet");
}
+ if (keyname)
+ (void) add_to_keyring_and_log(keyname, flags, l);
+
+ *ret = l;
+ l = NULL;
r = 0;
finish:
if (socket_name)
- unlink(socket_name);
+ (void) unlink(socket_name);
- unlink(temp);
+ (void) unlink(temp);
if (final[0])
- unlink(final);
+ (void) unlink(final);
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
-
return r;
}
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases) {
- assert(message);
- assert(_passphrases);
+int ask_password_auto(
+ const char *message,
+ const char *icon,
+ const char *id,
+ const char *keyname,
+ usec_t until,
+ AskPasswordFlags flags,
+ char ***ret) {
- if (isatty(STDIN_FILENO)) {
- int r;
+ int r;
+
+ assert(ret);
+
+ if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
+ r = ask_password_keyring(keyname, flags, ret);
+ if (r != -ENOKEY)
+ return r;
+ }
+
+ if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) {
char *s = NULL, **l = NULL;
- r = ask_password_tty(message, until, false, NULL, &s);
+ r = ask_password_tty(message, keyname, until, flags, NULL, &s);
if (r < 0)
return r;
r = strv_consume(&l, s);
if (r < 0)
- return r;
+ return -ENOMEM;
- *_passphrases = l;
- return r;
- } else
- return ask_password_agent(message, icon, id, until, false, accept_cached, _passphrases);
+ *ret = l;
+ return 0;
+ }
+
+ if (!(flags & ASK_PASSWORD_NO_AGENT))
+ return ask_password_agent(message, icon, id, keyname, until, flags, ret);
+
+ return -EUNATCH;
}
diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h
index 0954e072be..913cad9f8a 100644
--- a/src/shared/ask-password-api.h
+++ b/src/shared/ask-password-api.h
@@ -21,11 +21,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-int ask_password_tty(const char *message, usec_t until, bool echo, const char *flag_file, char **_passphrase);
-
-int ask_password_agent(const char *message, const char *icon, const char *id,
- usec_t until, bool echo, bool accept_cached, char ***_passphrases);
-
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases);
+#include <stdbool.h>
+
+#include "time-util.h"
+
+typedef enum AskPasswordFlags {
+ ASK_PASSWORD_ACCEPT_CACHED = 1,
+ ASK_PASSWORD_PUSH_CACHE = 2,
+ ASK_PASSWORD_ECHO = 4, /* show the password literally while reading, instead of "*" */
+ ASK_PASSWORD_SILENT = 8, /* do no show any password at all while reading */
+ ASK_PASSWORD_NO_TTY = 16,
+ ASK_PASSWORD_NO_AGENT = 32,
+} AskPasswordFlags;
+
+int ask_password_tty(const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char **ret);
+int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
+int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret);
+int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index ab6fc171b0..48492ed13d 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -34,12 +34,13 @@ typedef struct BaseFilesystem {
mode_t mode;
const char *target;
const char *exists;
+ bool ignore_failure;
} BaseFilesystem;
static const BaseFilesystem table[] = {
{ "bin", 0, "usr/bin\0", NULL },
{ "lib", 0, "usr/lib\0", NULL },
- { "root", 0755, NULL, NULL },
+ { "root", 0755, NULL, NULL, true },
{ "sbin", 0, "usr/sbin\0", NULL },
{ "usr", 0755, NULL, NULL },
{ "var", 0755, NULL, NULL },
@@ -104,8 +105,13 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
RUN_WITH_UMASK(0000)
r = mkdirat(fd, table[i].dir, table[i].mode);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(errno, "Failed to create directory at %s/%s: %m", root, table[i].dir);
+ if (r < 0 && errno != EEXIST) {
+ log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to create directory at %s/%s: %m", root, table[i].dir);
+
+ if (!table[i].ignore_failure)
+ return -errno;
+ }
if (uid != UID_INVALID || gid != UID_INVALID) {
if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 64a810fc8f..a5d6edbba9 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -23,22 +23,24 @@
#include "sd-daemon.h"
#include "sd-event.h"
-#include "util.h"
-#include "strv.h"
-#include "macro.h"
+#include "sd-bus.h"
+
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-label.h"
+#include "bus-message.h"
+#include "cgroup-util.h"
#include "def.h"
-#include "path-util.h"
+#include "macro.h"
#include "missing.h"
+#include "path-util.h"
#include "set.h"
#include "signal-util.h"
+#include "strv.h"
#include "unit-name.h"
+#include "util.h"
-#include "sd-bus.h"
-#include "bus-error.h"
-#include "bus-label.h"
-#include "bus-message.h"
#include "bus-util.h"
-#include "bus-internal.h"
static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
sd_event *e = userdata;
@@ -572,14 +574,14 @@ int bus_check_peercred(sd_bus *c) {
return 1;
}
-int bus_open_system_systemd(sd_bus **_bus) {
+int bus_connect_system_systemd(sd_bus **_bus) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
int r;
assert(_bus);
if (geteuid() != 0)
- return sd_bus_open_system(_bus);
+ return sd_bus_default_system(_bus);
/* If we are root and kdbus is not available, then let's talk
* directly to the system instance, instead of going via the
@@ -614,7 +616,7 @@ int bus_open_system_systemd(sd_bus **_bus) {
r = sd_bus_start(bus);
if (r < 0)
- return sd_bus_open_system(_bus);
+ return sd_bus_default_system(_bus);
r = bus_check_peercred(bus);
if (r < 0)
@@ -626,7 +628,7 @@ int bus_open_system_systemd(sd_bus **_bus) {
return 0;
}
-int bus_open_user_systemd(sd_bus **_bus) {
+int bus_connect_user_systemd(sd_bus **_bus) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
_cleanup_free_ char *ee = NULL;
const char *e;
@@ -656,7 +658,7 @@ int bus_open_user_systemd(sd_bus **_bus) {
e = secure_getenv("XDG_RUNTIME_DIR");
if (!e)
- return sd_bus_open_user(_bus);
+ return sd_bus_default_user(_bus);
ee = bus_address_escape(e);
if (!ee)
@@ -672,7 +674,7 @@ int bus_open_user_systemd(sd_bus **_bus) {
r = sd_bus_start(bus);
if (r < 0)
- return sd_bus_open_user(_bus);
+ return sd_bus_default_user(_bus);
r = bus_check_peercred(bus);
if (r < 0)
@@ -1207,7 +1209,7 @@ int bus_map_all_properties(
return bus_message_map_all_properties(m, map, userdata);
}
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
int r;
assert(transport >= 0);
@@ -1242,7 +1244,7 @@ int bus_open_transport(BusTransport transport, const char *host, bool user, sd_b
return r;
}
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
int r;
assert(transport >= 0);
@@ -1256,9 +1258,9 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us
case BUS_TRANSPORT_LOCAL:
if (user)
- r = bus_open_user_systemd(bus);
+ r = bus_connect_user_systemd(bus);
else
- r = bus_open_system_systemd(bus);
+ r = bus_connect_system_systemd(bus);
break;
@@ -1421,9 +1423,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return bus_log_create_error(r);
if (STR_IN_SET(field,
- "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
+ "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
- "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit")) {
+ "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
+ "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
+ "SyslogLevelPrefix")) {
r = parse_boolean(eq);
if (r < 0) {
@@ -1436,18 +1440,48 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else if (streq(field, "MemoryLimit")) {
uint64_t bytes;
- r = parse_size(eq, 1024, &bytes);
+ if (isempty(eq) || streq(eq, "infinity"))
+ bytes = (uint64_t) -1;
+ else {
+ r = parse_size(eq, 1024, &bytes);
+ if (r < 0) {
+ log_error("Failed to parse bytes specification %s", assignment);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "t", bytes);
+
+ } else if (streq(field, "TasksMax")) {
+ uint64_t n;
+
+ if (isempty(eq) || streq(eq, "infinity"))
+ n = (uint64_t) -1;
+ else {
+ r = safe_atou64(eq, &n);
+ if (r < 0) {
+ log_error("Failed to parse maximum tasks specification %s", assignment);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "t", n);
+
+ } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
+ uint64_t u;
+
+ r = cg_cpu_shares_parse(eq, &u);
if (r < 0) {
- log_error("Failed to parse bytes specification %s", assignment);
+ log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
- r = sd_bus_message_append(m, "v", "t", bytes);
+ r = sd_bus_message_append(m, "v", "t", u);
- } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
+ } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
uint64_t u;
- r = safe_atou64(eq, &u);
+ r = cg_cpu_shares_parse(eq, &u);
if (r < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
@@ -1459,10 +1493,33 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"User", "Group", "DevicePolicy", "KillMode",
"UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
"StandardInput", "StandardOutput", "StandardError",
- "Description", "Slice", "Type"))
+ "Description", "Slice", "Type", "WorkingDirectory",
+ "RootDirectory", "SyslogIdentifier"))
r = sd_bus_message_append(m, "v", "s", eq);
- else if (streq(field, "DeviceAllow")) {
+ else if (streq(field, "SyslogLevel")) {
+ int level;
+
+ level = log_level_from_string(eq);
+ if (level < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", level);
+
+ } else if (streq(field, "SyslogFacility")) {
+ int facility;
+
+ facility = log_facility_unshifted_from_string(eq);
+ if (facility < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", facility);
+
+ } else if (streq(field, "DeviceAllow")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(ss)", 0);
@@ -1598,7 +1655,16 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
}
r = sd_bus_message_append(m, "v", "t", u);
+ } else if (streq(field, "TimerSlackNSec")) {
+ nsec_t n;
+ r = parse_nsec(eq, &n);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", n);
} else {
log_error("Unknown assignment %s.", assignment);
return -EINVAL;
@@ -2103,3 +2169,42 @@ bool is_kdbus_available(void) {
return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
}
+
+int bus_property_get_rlimit(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ struct rlimit *rl;
+ uint64_t u;
+ rlim_t x;
+
+ assert(bus);
+ assert(reply);
+ assert(userdata);
+
+ rl = *(struct rlimit**) userdata;
+ if (rl)
+ x = rl->rlim_max;
+ else {
+ struct rlimit buf = {};
+ int z;
+
+ z = rlimit_from_string(strstr(property, "Limit"));
+ assert(z >= 0);
+
+ getrlimit(z, &buf);
+ x = buf.rlim_max;
+ }
+
+ /* rlim_t might have different sizes, let's map
+ * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
+ * all archs */
+ u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
+
+ return sd_bus_message_append(reply, "t", u);
+}
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index d2b2d701ce..fd70842b9e 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -65,11 +65,11 @@ int bus_test_polkit(sd_bus_message *call, int capability, const char *action, co
int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error);
void bus_verify_polkit_async_registry_free(Hashmap *registry);
-int bus_open_system_systemd(sd_bus **_bus);
-int bus_open_user_systemd(sd_bus **_bus);
+int bus_connect_system_systemd(sd_bus **_bus);
+int bus_connect_user_systemd(sd_bus **_bus);
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
+int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
+int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
int bus_print_property(const char *name, sd_bus_message *property, bool all);
int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
@@ -200,3 +200,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send
bool is_kdbus_wanted(void);
bool is_kdbus_available(void);
+
+int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 946eac6823..c282fb1231 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -147,8 +147,7 @@ static int next_assignment(const char *unit,
/* Warn about unknown non-extension fields. */
if (!relaxed && !startswith(lvalue, "X-"))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Unknown lvalue '%s' in section '%s'", lvalue, section);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
return 0;
}
@@ -196,8 +195,7 @@ static int parse_line(const char* unit,
* Support for them should be eventually removed. */
if (!allow_include) {
- log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
- ".include not allowed here. Ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
return 0;
}
@@ -216,8 +214,7 @@ static int parse_line(const char* unit,
assert(k > 0);
if (l[k-1] != ']') {
- log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
- "Invalid section header '%s'", l);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
return -EBADMSG;
}
@@ -228,8 +225,7 @@ static int parse_line(const char* unit,
if (sections && !nulstr_contains(sections, n)) {
if (!relaxed && !startswith(n, "X-"))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Unknown section '%s'. Ignoring.", n);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
free(n);
*section = mfree(*section);
@@ -248,16 +244,15 @@ static int parse_line(const char* unit,
if (sections && !*section) {
if (!relaxed && !*section_ignored)
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Assignment outside of section. Ignoring.");
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
return 0;
}
e = strchr(l, '=');
if (!e) {
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
- return -EBADMSG;
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
+ return -EINVAL;
}
*e = 0;
@@ -420,16 +415,17 @@ int config_parse_many(const char *conf_file,
}
#define DEFINE_PARSER(type, vartype, conv_func) \
- int config_parse_##type(const char *unit, \
- const char *filename, \
- unsigned line, \
- const char *section, \
- unsigned section_line, \
- const char *lvalue, \
- int ltype, \
- const char *rvalue, \
- void *data, \
- void *userdata) { \
+ int config_parse_##type( \
+ const char *unit, \
+ const char *filename, \
+ unsigned line, \
+ const char *section, \
+ unsigned section_line, \
+ const char *lvalue, \
+ int ltype, \
+ const char *rvalue, \
+ void *data, \
+ void *userdata) { \
\
vartype *i = data; \
int r; \
@@ -441,21 +437,23 @@ int config_parse_many(const char *conf_file,
\
r = conv_func(rvalue, i); \
if (r < 0) \
- log_syntax(unit, LOG_ERR, filename, line, -r, \
+ log_syntax(unit, LOG_ERR, filename, line, r, \
"Failed to parse %s value, ignoring: %s", \
#type, rvalue); \
\
return 0; \
- }
-
-DEFINE_PARSER(int, int, safe_atoi)
-DEFINE_PARSER(long, long, safe_atoli)
-DEFINE_PARSER(uint32, uint32_t, safe_atou32)
-DEFINE_PARSER(uint64, uint64_t, safe_atou64)
-DEFINE_PARSER(unsigned, unsigned, safe_atou)
-DEFINE_PARSER(double, double, safe_atod)
-DEFINE_PARSER(nsec, nsec_t, parse_nsec)
-DEFINE_PARSER(sec, usec_t, parse_sec)
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+DEFINE_PARSER(int, int, safe_atoi);
+DEFINE_PARSER(long, long, safe_atoli);
+DEFINE_PARSER(uint32, uint32_t, safe_atou32);
+DEFINE_PARSER(uint64, uint64_t, safe_atou64);
+DEFINE_PARSER(unsigned, unsigned, safe_atou);
+DEFINE_PARSER(double, double, safe_atod);
+DEFINE_PARSER(nsec, nsec_t, parse_nsec);
+DEFINE_PARSER(sec, usec_t, parse_sec);
+DEFINE_PARSER(mode, mode_t, parse_mode);
int config_parse_iec_size(const char* unit,
const char *filename,
@@ -479,7 +477,7 @@ int config_parse_iec_size(const char* unit,
r = parse_size(rvalue, 1024, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
@@ -509,7 +507,7 @@ int config_parse_si_size(const char* unit,
r = parse_size(rvalue, 1000, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
@@ -564,8 +562,7 @@ int config_parse_bool(const char* unit,
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse boolean value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
@@ -626,7 +623,7 @@ int config_parse_string(
assert(data);
if (!utf8_is_valid(rvalue)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
@@ -664,12 +661,12 @@ int config_parse_path(
assert(data);
if (!utf8_is_valid(rvalue)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
if (!path_is_absolute(rvalue)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
return 0;
}
@@ -730,7 +727,7 @@ int config_parse_strv(const char *unit,
return log_oom();
if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
free(n);
continue;
}
@@ -740,35 +737,7 @@ int config_parse_strv(const char *unit,
return log_oom();
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-int config_parse_mode(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- mode_t *m = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (parse_mode(rvalue, m) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
- return 0;
- }
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -795,7 +764,7 @@ int config_parse_log_facility(
x = log_facility_unshifted_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
return 0;
}
@@ -826,7 +795,7 @@ int config_parse_log_level(
x = log_level_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
return 0;
}
@@ -855,7 +824,7 @@ int config_parse_signal(
r = signal_from_string_try_harder(rvalue);
if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse signal name, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
return 0;
}
@@ -884,7 +853,7 @@ int config_parse_personality(
p = personality_from_string(rvalue);
if (p == PERSONALITY_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse personality, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 4efed138c9..fb0234baae 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -123,13 +123,6 @@ int config_parse_log_level(const char *unit, const char *filename, unsigned line
int config_parse_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-#define log_invalid_utf8(unit, level, config_file, config_line, error, rvalue) \
- do { \
- _cleanup_free_ char *_p = utf8_escape_invalid(rvalue); \
- log_syntax(unit, level, config_file, config_line, error, \
- "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \
- } while(false)
-
#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
int function(const char *unit, \
const char *filename, \
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 6dc04d51e4..5680f01bd9 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -379,9 +379,8 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
return 0;
}
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
+void dns_name_hash_func(const void *s, struct siphash *state) {
const char *p = s;
- unsigned long ul = hash_key[0];
int r;
assert(p);
@@ -400,13 +399,17 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
if (k > 0)
r = k;
+ if (r == 0)
+ break;
+
label[r] = 0;
ascii_strlower(label);
- ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
+ string_hash_func(label, state);
}
- return ul;
+ /* enforce that all names are terminated by the empty label */
+ string_hash_func("", state);
}
int dns_name_compare_func(const void *a, const void *b) {
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 8e73d9c20f..1f0d242c18 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -54,7 +54,7 @@ static inline int dns_name_is_valid(const char *s) {
return 1;
}
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]);
+void dns_name_hash_func(const void *s, struct siphash *state);
int dns_name_compare_func(const void *a, const void *b);
extern const struct hash_ops dns_name_hash_ops;
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index 963d05d32e..1845068adb 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -78,7 +78,7 @@ int write_drop_in(const char *dir, const char *unit, unsigned level,
if (r < 0)
return r;
- mkdir_p(p, 0755);
+ (void) mkdir_p(p, 0755);
return write_string_file_atomic_label(q, data);
}
@@ -132,8 +132,7 @@ static int iterate_dir(
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open directory %s: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to open directory %s: %m", path);
}
for (;;) {
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index e231a0ff80..c065adcfdf 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -20,9 +20,25 @@
***/
#include "fstab-util.h"
+#include "path-util.h"
#include "strv.h"
#include "util.h"
+bool fstab_is_mount_point(const char *mount) {
+ _cleanup_endmntent_ FILE *f = NULL;
+ struct mntent *m;
+
+ f = setmntent("/etc/fstab", "r");
+ if (!f)
+ return false;
+
+ while ((m = getmntent(f)))
+ if (path_equal(m->mnt_dir, mount))
+ return true;
+
+ return false;
+}
+
int fstab_filter_options(const char *opts, const char *names,
const char **namefound, char **value, char **filtered) {
const char *name, *n = NULL, *x;
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index 387c562a96..872b2363cd 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -25,6 +25,7 @@
#include <stddef.h>
#include "macro.h"
+bool fstab_is_mount_point(const char *mount);
int fstab_filter_options(const char *opts, const char *names,
const char **namefound, char **value, char **filtered);
diff --git a/src/shared/install.c b/src/shared/install.c
index 3d2b5ae77f..238433c808 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -949,8 +949,7 @@ static int config_parse_also(
return r;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 7790c1a3c8..dbc07aa7ad 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -117,11 +117,11 @@ static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, Output
if (flags & OUTPUT_COLOR) {
if (priority <= LOG_ERR) {
- color_on = ANSI_HIGHLIGHT_RED_ON;
- color_off = ANSI_HIGHLIGHT_OFF;
+ color_on = ANSI_HIGHLIGHT_RED;
+ color_off = ANSI_NORMAL;
} else if (priority <= LOG_NOTICE) {
- color_on = ANSI_HIGHLIGHT_ON;
- color_off = ANSI_HIGHLIGHT_OFF;
+ color_on = ANSI_HIGHLIGHT;
+ color_off = ANSI_NORMAL;
}
}
@@ -455,8 +455,8 @@ static int output_verbose(
fieldlen = c - (const char*) data;
if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
- on = ANSI_HIGHLIGHT_ON;
- off = ANSI_HIGHLIGHT_OFF;
+ on = ANSI_HIGHLIGHT;
+ off = ANSI_NORMAL;
}
if (flags & OUTPUT_SHOW_ALL ||
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index 70220bdd14..9c1e4d5e13 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -19,16 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/statfs.h>
-#include <linux/fs.h>
#include <fcntl.h>
+#include <linux/fs.h>
+#include <sys/statfs.h>
-#include "utf8.h"
#include "btrfs-util.h"
-#include "path-util.h"
#include "copy.h"
#include "mkdir.h"
+#include "path-util.h"
#include "rm-rf.h"
+#include "strv.h"
+#include "utf8.h"
+
#include "machine-image.h"
static const char image_search_path[] =
@@ -47,6 +49,38 @@ Image *image_unref(Image *i) {
return NULL;
}
+static char **image_settings_path(Image *image) {
+ _cleanup_strv_free_ char **l = NULL;
+ char **ret;
+ const char *fn, *s;
+ unsigned i = 0;
+
+ assert(image);
+
+ l = new0(char*, 4);
+ if (!l)
+ return NULL;
+
+ fn = strjoina(image->name, ".nspawn");
+
+ FOREACH_STRING(s, "/etc/systemd/nspawn/", "/run/systemd/nspawn/") {
+ l[i] = strappend(s, fn);
+ if (!l[i])
+ return NULL;
+
+ i++;
+ }
+
+ l[i] = file_in_same_dir(image->path, fn);
+ if (!l[i])
+ return NULL;
+
+ ret = l;
+ l = NULL;
+
+ return ret;
+}
+
static int image_new(
ImageType t,
const char *pretty,
@@ -341,6 +375,8 @@ void image_hashmap_free(Hashmap *map) {
int image_remove(Image *i) {
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
+ _cleanup_strv_free_ char **settings = NULL;
+ char **j;
int r;
assert(i);
@@ -349,6 +385,10 @@ int image_remove(Image *i) {
path_startswith(i->path, "/usr"))
return -EROFS;
+ settings = image_settings_path(i);
+ if (!settings)
+ return -ENOMEM;
+
/* Make sure we don't interfere with a running nspawn */
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
@@ -357,28 +397,56 @@ int image_remove(Image *i) {
switch (i->type) {
case IMAGE_SUBVOLUME:
- return btrfs_subvol_remove(i->path, true);
+ r = btrfs_subvol_remove(i->path, true);
+ if (r < 0)
+ return r;
+ break;
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
(void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
- return rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ if (r < 0)
+ return r;
+
+ break;
case IMAGE_RAW:
if (unlink(i->path) < 0)
return -errno;
-
- return 0;
+ break;
default:
return -EOPNOTSUPP;
}
+
+ STRV_FOREACH(j, settings) {
+ if (unlink(*j) < 0 && errno != ENOENT)
+ log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
+ }
+
+ return 0;
+}
+
+static int rename_settings_file(const char *path, const char *new_name) {
+ _cleanup_free_ char *rs = NULL;
+ const char *fn;
+
+ fn = strjoina(new_name, ".nspawn");
+
+ rs = file_in_same_dir(path, fn);
+ if (!rs)
+ return -ENOMEM;
+
+ return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
}
int image_rename(Image *i, const char *new_name) {
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
_cleanup_free_ char *new_path = NULL, *nn = NULL;
+ _cleanup_strv_free_ char **settings = NULL;
unsigned file_attr = 0;
+ char **j;
int r;
assert(i);
@@ -390,6 +458,10 @@ int image_rename(Image *i, const char *new_name) {
path_startswith(i->path, "/usr"))
return -EROFS;
+ settings = image_settings_path(i);
+ if (!settings)
+ return -ENOMEM;
+
/* Make sure we don't interfere with a running nspawn */
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
@@ -458,12 +530,33 @@ int image_rename(Image *i, const char *new_name) {
i->name = nn;
nn = NULL;
+ STRV_FOREACH(j, settings) {
+ r = rename_settings_file(*j, new_name);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
+ }
+
return 0;
}
+static int clone_settings_file(const char *path, const char *new_name) {
+ _cleanup_free_ char *rs = NULL;
+ const char *fn;
+
+ fn = strjoina(new_name, ".nspawn");
+
+ rs = file_in_same_dir(path, fn);
+ if (!rs)
+ return -ENOMEM;
+
+ return copy_file_atomic(path, rs, 0664, false, 0);
+}
+
int image_clone(Image *i, const char *new_name, bool read_only) {
_cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT;
+ _cleanup_strv_free_ char **settings = NULL;
const char *new_path;
+ char **j;
int r;
assert(i);
@@ -471,6 +564,10 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
if (!image_name_is_valid(new_name))
return -EINVAL;
+ settings = image_settings_path(i);
+ if (!settings)
+ return -ENOMEM;
+
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
* time we take possesion of it */
@@ -506,6 +603,12 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
if (r < 0)
return r;
+ STRV_FOREACH(j, settings) {
+ r = clone_settings_file(*j, new_name);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
+ }
+
return 0;
}
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 41da820938..d8f0fb404d 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -48,24 +48,27 @@ noreturn static void pager_fallback(void) {
}
int pager_open(bool jump_to_end) {
- int fd[2];
+ _cleanup_close_pair_ int fd[2] = { -1, -1 };
const char *pager;
pid_t parent_pid;
- int r;
if (pager_pid > 0)
return 1;
- if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER")))
- if (!*pager || streq(pager, "cat"))
- return 0;
-
if (!on_tty())
return 0;
+ pager = getenv("SYSTEMD_PAGER");
+ if (!pager)
+ pager = getenv("PAGER");
+
+ /* If the pager is explicitly turned off, honour it */
+ if (pager && (pager[0] == 0 || streq(pager, "cat")))
+ return 0;
+
/* Determine and cache number of columns before we spawn the
* pager so that we get the value from the actual tty */
- columns();
+ (void) columns();
if (pipe(fd) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
@@ -73,11 +76,8 @@ int pager_open(bool jump_to_end) {
parent_pid = getpid();
pager_pid = fork();
- if (pager_pid < 0) {
- r = log_error_errno(errno, "Failed to fork pager: %m");
- safe_close_pair(fd);
- return r;
- }
+ if (pager_pid < 0)
+ return log_error_errno(errno, "Failed to fork pager: %m");
/* In the child start the pager */
if (pager_pid == 0) {
@@ -86,7 +86,7 @@ int pager_open(bool jump_to_end) {
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
- dup2(fd[0], STDIN_FILENO);
+ (void) dup2(fd[0], STDIN_FILENO);
safe_close_pair(fd);
/* Initialize a good set of less options */
@@ -141,7 +141,6 @@ int pager_open(bool jump_to_end) {
if (dup2(fd[1], STDERR_FILENO) < 0)
return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
- safe_close_pair(fd);
return 1;
}
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index d803bbe07e..34eec959ef 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -181,7 +181,7 @@ static char** user_dirs(
if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) config_unit_paths) < 0)
+ if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
return NULL;
if (runtime_dir)
@@ -203,7 +203,7 @@ static char** user_dirs(
if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) data_unit_paths) < 0)
+ if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
return NULL;
if (generator_late)
@@ -318,7 +318,7 @@ int lookup_paths_init(
if (!unit_path)
return -ENOMEM;
- r = strv_extend_strv(&p->unit_path, unit_path);
+ r = strv_extend_strv(&p->unit_path, unit_path, false);
if (r < 0)
return r;
}
diff --git a/src/shared/pty.c b/src/shared/pty.c
deleted file mode 100644
index 35d9ff5f4d..0000000000
--- a/src/shared/pty.c
+++ /dev/null
@@ -1,633 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- 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/>.
-***/
-
-/*
- * PTY
- * A PTY object represents a single PTY connection between a master and a
- * child. The child process is fork()ed so the caller controls what program
- * will be run.
- *
- * Programs like /bin/login tend to perform a vhangup() on their TTY
- * before running the login procedure. This also causes the pty master
- * to get a EPOLLHUP event as long as no client has the TTY opened.
- * This means, we cannot use the TTY connection as reliable way to track
- * the client. Instead, we _must_ rely on the PID of the client to track
- * them.
- * However, this has the side effect that if the client forks and the
- * parent exits, we loose them and restart the client. But this seems to
- * be the expected behavior so we implement it here.
- *
- * Unfortunately, epoll always polls for EPOLLHUP so as long as the
- * vhangup() is ongoing, we will _always_ get EPOLLHUP and cannot sleep.
- * This gets worse if the client closes the TTY but doesn't exit.
- * Therefore, the fd must be edge-triggered in the epoll-set so we
- * only get the events once they change.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include "barrier.h"
-#include "macro.h"
-#include "ring.h"
-#include "util.h"
-#include "signal-util.h"
-#include "pty.h"
-
-#define PTY_BUFSIZE 4096
-
-enum {
- PTY_ROLE_UNKNOWN,
- PTY_ROLE_PARENT,
- PTY_ROLE_CHILD,
-};
-
-struct Pty {
- unsigned long ref;
- Barrier barrier;
- int fd;
- pid_t child;
- sd_event_source *fd_source;
- sd_event_source *child_source;
-
- char in_buf[PTY_BUFSIZE];
- Ring out_buf;
-
- pty_event_t event_fn;
- void *event_fn_userdata;
-
- bool needs_requeue : 1;
- unsigned int role : 2;
-};
-
-int pty_new(Pty **out) {
- _pty_unref_ Pty *pty = NULL;
- int r;
-
- assert_return(out, -EINVAL);
-
- pty = new0(Pty, 1);
- if (!pty)
- return -ENOMEM;
-
- pty->ref = 1;
- pty->fd = -1;
- pty->barrier = (Barrier) BARRIER_NULL;
-
- pty->fd = posix_openpt(O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK);
- if (pty->fd < 0)
- return -errno;
-
- /*
- * The slave-node is initialized to uid/gid of the caller of
- * posix_openpt(). Only if devpts is mounted with fixed uid/gid this is
- * skipped. In that case, grantpt() can overwrite these, but then you
- * have to be root to use chown() (or a pt_chown helper has to be
- * present). In those cases grantpt() really does something,
- * otherwise it's a no-op. We call grantpt() here to try supporting
- * those cases, even though no-one uses that, I guess. If you need other
- * access-rights, set them yourself after this call returns (no, this is
- * not racy, it looks racy, but races regarding your own UID are never
- * important as an attacker could ptrace you; and the slave-pty is also
- * still locked).
- */
- r = grantpt(pty->fd);
- if (r < 0)
- return -errno;
-
- r = barrier_create(&pty->barrier);
- if (r < 0)
- return r;
-
- *out = pty;
- pty = NULL;
- return 0;
-}
-
-Pty *pty_ref(Pty *pty) {
- if (!pty || pty->ref < 1)
- return NULL;
-
- ++pty->ref;
- return pty;
-}
-
-Pty *pty_unref(Pty *pty) {
- if (!pty || pty->ref < 1 || --pty->ref > 0)
- return NULL;
-
- pty_close(pty);
- pty->child_source = sd_event_source_unref(pty->child_source);
- barrier_destroy(&pty->barrier);
- ring_clear(&pty->out_buf);
- free(pty);
-
- return NULL;
-}
-
-Barrier *pty_get_barrier(Pty *pty) {
- assert(pty);
- return &pty->barrier;
-}
-
-bool pty_is_unknown(Pty *pty) {
- return pty && pty->role == PTY_ROLE_UNKNOWN;
-}
-
-bool pty_is_parent(Pty *pty) {
- return pty && pty->role == PTY_ROLE_PARENT;
-}
-
-bool pty_is_child(Pty *pty) {
- return pty && pty->role == PTY_ROLE_CHILD;
-}
-
-bool pty_has_child(Pty *pty) {
- return pty_is_parent(pty) && pty->child > 0;
-}
-
-pid_t pty_get_child(Pty *pty) {
- return pty_has_child(pty) ? pty->child : -ECHILD;
-}
-
-bool pty_is_open(Pty *pty) {
- return pty && pty->fd >= 0;
-}
-
-int pty_get_fd(Pty *pty) {
- assert_return(pty, -EINVAL);
-
- return pty_is_open(pty) ? pty->fd : -EPIPE;
-}
-
-int pty_make_child(Pty *pty) {
- _cleanup_free_ char *slave_name = NULL;
- int r, fd;
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_unknown(pty), -EALREADY);
-
- r = ptsname_malloc(pty->fd, &slave_name);
- if (r < 0)
- return -errno;
-
- fd = open(slave_name, O_RDWR | O_CLOEXEC | O_NOCTTY);
- if (fd < 0)
- return -errno;
-
- safe_close(pty->fd);
- pty->fd = fd;
- pty->child = getpid();
- pty->role = PTY_ROLE_CHILD;
- barrier_set_role(&pty->barrier, BARRIER_CHILD);
-
- return 0;
-}
-
-int pty_make_parent(Pty *pty, pid_t child) {
- assert_return(pty, -EINVAL);
- assert_return(pty_is_unknown(pty), -EALREADY);
-
- pty->child = child;
- pty->role = PTY_ROLE_PARENT;
-
- return 0;
-}
-
-int pty_unlock(Pty *pty) {
- assert_return(pty, -EINVAL);
- assert_return(pty_is_unknown(pty) || pty_is_parent(pty), -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
-
- return unlockpt(pty->fd) < 0 ? -errno : 0;
-}
-
-int pty_setup_child(Pty *pty) {
- struct termios attr;
- pid_t pid;
- int r;
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_child(pty), -EINVAL);
- assert_return(pty_is_open(pty), -EALREADY);
-
- r = reset_signal_mask();
- if (r < 0)
- return r;
-
- r = reset_all_signal_handlers();
- if (r < 0)
- return r;
-
- pid = setsid();
- if (pid < 0 && errno != EPERM)
- return -errno;
-
- r = ioctl(pty->fd, TIOCSCTTY, 0);
- if (r < 0)
- return -errno;
-
- r = tcgetattr(pty->fd, &attr);
- if (r < 0)
- return -errno;
-
- /* erase character should be normal backspace, PLEASEEE! */
- attr.c_cc[VERASE] = 010;
- /* always set UTF8 flag */
- attr.c_iflag |= IUTF8;
-
- r = tcsetattr(pty->fd, TCSANOW, &attr);
- if (r < 0)
- return -errno;
-
- if (dup2(pty->fd, STDIN_FILENO) != STDIN_FILENO ||
- dup2(pty->fd, STDOUT_FILENO) != STDOUT_FILENO ||
- dup2(pty->fd, STDERR_FILENO) != STDERR_FILENO)
- return -errno;
-
- /* only close FD if it's not a std-fd */
- pty->fd = (pty->fd > 2) ? safe_close(pty->fd) : -1;
-
- return 0;
-}
-
-void pty_close(Pty *pty) {
- if (!pty_is_open(pty))
- return;
-
- pty->fd_source = sd_event_source_unref(pty->fd_source);
- pty->fd = safe_close(pty->fd);
-}
-
-/*
- * Drain input-queue and dispatch data via the event-handler. Returns <0 on
- * error, 0 if queue is empty and 1 if we couldn't empty the input queue fast
- * enough and there's still data left.
- */
-static int pty_dispatch_read(Pty *pty) {
- unsigned int i;
- ssize_t len;
- int r;
-
- /*
- * We're edge-triggered, means we need to read the whole queue. This,
- * however, might cause us to stall if the writer is faster than we
- * are. Therefore, try reading as much as 8 times (32KiB) and only
- * bail out then.
- */
-
- for (i = 0; i < 8; ++i) {
- len = read(pty->fd, pty->in_buf, sizeof(pty->in_buf) - 1);
- if (len < 0) {
- if (errno == EINTR)
- continue;
-
- return (errno == EAGAIN) ? 0 : -errno;
- } else if (len == 0)
- continue;
-
- /* set terminating zero for debugging safety */
- pty->in_buf[len] = 0;
- r = pty->event_fn(pty, pty->event_fn_userdata, PTY_DATA, pty->in_buf, len);
- if (r < 0)
- return r;
- }
-
- /* still data left, make sure we're queued again */
- pty->needs_requeue = true;
-
- return 1;
-}
-
-/*
- * Drain output-queue by writing data to the pty. Returns <0 on error, 0 if the
- * output queue is empty now and 1 if we couldn't empty the output queue fast
- * enough and there's still data left.
- */
-static int pty_dispatch_write(Pty *pty) {
- struct iovec vec[2];
- unsigned int i;
- ssize_t len;
- size_t num;
-
- /*
- * Same as pty_dispatch_read(), we're edge-triggered so we need to call
- * write() until either all data is written or it returns EAGAIN. We
- * call it twice and if it still writes successfully, we reschedule.
- */
-
- for (i = 0; i < 2; ++i) {
- num = ring_peek(&pty->out_buf, vec);
- if (num < 1)
- return 0;
-
- len = writev(pty->fd, vec, (int)num);
- if (len < 0) {
- if (errno == EINTR)
- continue;
-
- return (errno == EAGAIN) ? 1 : -errno;
- } else if (len == 0)
- continue;
-
- ring_pull(&pty->out_buf, (size_t)len);
- }
-
- /* still data left, make sure we're queued again */
- if (ring_get_size(&pty->out_buf) > 0) {
- pty->needs_requeue = true;
- return 1;
- }
-
- return 0;
-}
-
-static int pty_fd_fn(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Pty *pty = userdata;
- int r_hup = 0, r_write = 0, r_read = 0, r;
-
- /*
- * Whenever we encounter I/O errors, we have to make sure to drain the
- * input queue first, before we handle any HUP. A child might send us
- * a message and immediately close the queue. We must not handle the
- * HUP first or we loose data.
- * Therefore, if we read a message successfully, we always return
- * success and wait for the next event-loop iteration. Furthermore,
- * whenever there is a write-error, we must try reading from the input
- * queue even if EPOLLIN is not set. The input might have arrived in
- * between epoll_wait() and write(). Therefore, write-errors are only
- * ever handled if the input-queue is empty. In all other cases they
- * are ignored until either reading fails or the input queue is empty.
- */
-
- if (revents & (EPOLLHUP | EPOLLERR))
- r_hup = -EPIPE;
-
- if (revents & EPOLLOUT)
- r_write = pty_dispatch_write(pty);
-
- /* Awesome! Kernel signals HUP without IN but queues are not empty.. */
- if ((revents & EPOLLIN) || r_hup < 0 || r_write < 0) {
- r_read = pty_dispatch_read(pty);
- if (r_read > 0)
- return 0; /* still data left to fetch next round */
- }
-
- if (r_hup < 0 || r_write < 0 || r_read < 0) {
- /* PTY closed and input-queue drained */
- pty_close(pty);
- r = pty->event_fn(pty, pty->event_fn_userdata, PTY_HUP, NULL, 0);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int pty_fd_prepare_fn(sd_event_source *source, void *userdata) {
- Pty *pty = userdata;
- int r;
-
- if (pty->needs_requeue) {
- /*
- * We're edge-triggered. In case we couldn't handle all events
- * or in case new write-data is queued, we set needs_requeue.
- * Before going asleep, we set the io-events *again*. sd-event
- * notices that we're edge-triggered and forwards the call to
- * the kernel even if the events didn't change. The kernel will
- * check the events and re-queue us on the ready queue in case
- * an event is pending.
- */
- r = sd_event_source_set_io_events(source, EPOLLHUP | EPOLLERR | EPOLLIN | EPOLLOUT | EPOLLET);
- if (r >= 0)
- pty->needs_requeue = false;
- }
-
- return 0;
-}
-
-static int pty_child_fn(sd_event_source *source, const siginfo_t *si, void *userdata) {
- Pty *pty = userdata;
- int r;
-
- pty->child = 0;
-
- r = pty->event_fn(pty, pty->event_fn_userdata, PTY_CHILD, si, sizeof(*si));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int pty_attach_event(Pty *pty, sd_event *event, pty_event_t event_fn, void *event_fn_userdata) {
- int r;
-
- assert_return(pty, -EINVAL);
- assert_return(event, -EINVAL);
- assert_return(event_fn, -EINVAL);
- assert_return(pty_is_parent(pty), -EINVAL);
-
- pty_detach_event(pty);
-
- if (pty_is_open(pty)) {
- r = sd_event_add_io(event,
- &pty->fd_source,
- pty->fd,
- EPOLLHUP | EPOLLERR | EPOLLIN | EPOLLOUT | EPOLLET,
- pty_fd_fn,
- pty);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_prepare(pty->fd_source, pty_fd_prepare_fn);
- if (r < 0)
- goto error;
- }
-
- if (pty_has_child(pty)) {
- r = sd_event_add_child(event,
- &pty->child_source,
- pty->child,
- WEXITED,
- pty_child_fn,
- pty);
- if (r < 0)
- goto error;
- }
-
- pty->event_fn = event_fn;
- pty->event_fn_userdata = event_fn_userdata;
-
- return 0;
-
-error:
- pty_detach_event(pty);
- return r;
-}
-
-void pty_detach_event(Pty *pty) {
- if (!pty)
- return;
-
- pty->child_source = sd_event_source_unref(pty->child_source);
- pty->fd_source = sd_event_source_unref(pty->fd_source);
- pty->event_fn = NULL;
- pty->event_fn_userdata = NULL;
-}
-
-int pty_write(Pty *pty, const void *buf, size_t size) {
- bool was_empty;
- int r;
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
- assert_return(pty_is_parent(pty), -ENODEV);
-
- if (size < 1)
- return 0;
-
- /*
- * Push @buf[0..@size] into the output ring-buffer. In case the
- * ring-buffer wasn't empty beforehand, we're already waiting for
- * EPOLLOUT and we're done. If it was empty, we have to re-queue the
- * FD for EPOLLOUT as we're edge-triggered and wouldn't get any new
- * EPOLLOUT event.
- */
-
- was_empty = ring_get_size(&pty->out_buf) < 1;
-
- r = ring_push(&pty->out_buf, buf, size);
- if (r < 0)
- return r;
-
- if (was_empty)
- pty->needs_requeue = true;
-
- return 0;
-}
-
-int pty_signal(Pty *pty, int sig) {
- assert_return(pty, -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
- assert_return(pty_is_parent(pty), -ENODEV);
-
- return ioctl(pty->fd, TIOCSIG, sig) < 0 ? -errno : 0;
-}
-
-int pty_resize(Pty *pty, unsigned short term_width, unsigned short term_height) {
- struct winsize ws = {
- .ws_col = term_width,
- .ws_row = term_height,
- };
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
- assert_return(pty_is_parent(pty), -ENODEV);
-
- /*
- * This will send SIGWINCH to the pty slave foreground process group.
- * We will also get one, but we don't need it.
- */
- return ioctl(pty->fd, TIOCSWINSZ, &ws) < 0 ? -errno : 0;
-}
-
-pid_t pty_fork(Pty **out, sd_event *event, pty_event_t event_fn, void *event_fn_userdata, unsigned short initial_term_width, unsigned short initial_term_height) {
- _pty_unref_ Pty *pty = NULL;
- int r;
- pid_t pid;
-
- assert_return(out, -EINVAL);
- assert_return((event && event_fn) || (!event && !event_fn), -EINVAL);
-
- r = pty_new(&pty);
- if (r < 0)
- return r;
-
- r = pty_unlock(pty);
- if (r < 0)
- return r;
-
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
- /* child */
-
- r = pty_make_child(pty);
- if (r < 0)
- _exit(-r);
-
- r = pty_setup_child(pty);
- if (r < 0)
- _exit(-r);
-
- /* sync with parent */
- if (!barrier_place_and_sync(&pty->barrier))
- _exit(1);
-
- /* fallthrough and return the child's PTY object */
- } else {
- /* parent */
-
- r = pty_make_parent(pty, pid);
- if (r < 0)
- goto parent_error;
-
- r = pty_resize(pty, initial_term_width, initial_term_height);
- if (r < 0)
- goto parent_error;
-
- if (event) {
- r = pty_attach_event(pty, event, event_fn, event_fn_userdata);
- if (r < 0)
- goto parent_error;
- }
-
- /* sync with child */
- if (!barrier_place_and_sync(&pty->barrier)) {
- r = -ECHILD;
- goto parent_error;
- }
-
- /* fallthrough and return the parent's PTY object */
- }
-
- *out = pty;
- pty = NULL;
- return pid;
-
-parent_error:
- barrier_abort(&pty->barrier);
- waitpid(pty->child, NULL, 0);
- pty->child = 0;
- return r;
-}
diff --git a/src/shared/pty.h b/src/shared/pty.h
deleted file mode 100644
index 63c7db2833..0000000000
--- a/src/shared/pty.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <unistd.h>
-
-#include "barrier.h"
-#include "macro.h"
-#include "sd-event.h"
-
-typedef struct Pty Pty;
-
-enum {
- PTY_CHILD,
- PTY_HUP,
- PTY_DATA,
-};
-
-typedef int (*pty_event_t) (Pty *pty, void *userdata, unsigned int event, const void *ptr, size_t size);
-
-int pty_new(Pty **out);
-Pty *pty_ref(Pty *pty);
-Pty *pty_unref(Pty *pty);
-
-#define _pty_unref_ _cleanup_(pty_unrefp)
-DEFINE_TRIVIAL_CLEANUP_FUNC(Pty*, pty_unref);
-
-Barrier *pty_get_barrier(Pty *pty);
-
-bool pty_is_unknown(Pty *pty);
-bool pty_is_parent(Pty *pty);
-bool pty_is_child(Pty *pty);
-bool pty_has_child(Pty *pty);
-pid_t pty_get_child(Pty *pty);
-
-bool pty_is_open(Pty *pty);
-int pty_get_fd(Pty *pty);
-
-int pty_make_child(Pty *pty);
-int pty_make_parent(Pty *pty, pid_t child);
-int pty_unlock(Pty *pty);
-int pty_setup_child(Pty *pty);
-void pty_close(Pty *pty);
-
-int pty_attach_event(Pty *pty, sd_event *event, pty_event_t event_fn, void *event_fn_userdata);
-void pty_detach_event(Pty *pty);
-
-int pty_write(Pty *pty, const void *buf, size_t size);
-int pty_signal(Pty *pty, int sig);
-int pty_resize(Pty *pty, unsigned short term_width, unsigned short term_height);
-
-pid_t pty_fork(Pty **out, sd_event *event, pty_event_t event_fn, void *event_fn_userdata, unsigned short initial_term_width, unsigned short initial_term_height);
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 789f217efc..7749f20540 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -32,6 +32,8 @@ struct PTYForward {
int master;
+ PTYForwardFlags flags;
+
sd_event_source *stdin_event_source;
sd_event_source *stdout_event_source;
sd_event_source *master_event_source;
@@ -41,8 +43,6 @@ struct PTYForward {
struct termios saved_stdin_attr;
struct termios saved_stdout_attr;
- bool read_only:1;
-
bool saved_stdin:1;
bool saved_stdout:1;
@@ -54,8 +54,7 @@ struct PTYForward {
bool master_writable:1;
bool master_hangup:1;
- /* Continue reading after hangup? */
- bool ignore_vhangup:1;
+ bool read_from_master:1;
bool last_char_set:1;
char last_char;
@@ -100,6 +99,18 @@ static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
return false;
}
+static bool ignore_vhangup(PTYForward *f) {
+ assert(f);
+
+ if (f->flags & PTY_FORWARD_IGNORE_VHANGUP)
+ return true;
+
+ if ((f->flags & PTY_FORWARD_IGNORE_INITIAL_VHANGUP) && !f->read_from_master)
+ return true;
+
+ return false;
+}
+
static int shovel(PTYForward *f) {
ssize_t k;
@@ -179,7 +190,7 @@ static int shovel(PTYForward *f) {
* EAGAIN here and try again, unless
* ignore_vhangup is off. */
- if (errno == EAGAIN || (errno == EIO && f->ignore_vhangup))
+ if (errno == EAGAIN || (errno == EIO && ignore_vhangup(f)))
f->master_readable = false;
else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) {
f->master_readable = f->master_writable = false;
@@ -190,8 +201,10 @@ static int shovel(PTYForward *f) {
log_error_errno(errno, "read(): %m");
return sd_event_exit(f->event, EXIT_FAILURE);
}
- } else
+ } else {
+ f->read_from_master = true;
f->out_buffer_full += (size_t) k;
+ }
}
if (f->stdout_writable && f->out_buffer_full > 0) {
@@ -302,8 +315,7 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *
int pty_forward_new(
sd_event *event,
int master,
- bool ignore_vhangup,
- bool read_only,
+ PTYForwardFlags flags,
PTYForward **ret) {
_cleanup_(pty_forward_freep) PTYForward *f = NULL;
@@ -314,8 +326,7 @@ int pty_forward_new(
if (!f)
return -ENOMEM;
- f->read_only = read_only;
- f->ignore_vhangup = ignore_vhangup;
+ f->flags = flags;
if (event)
f->event = sd_event_ref(event);
@@ -325,7 +336,7 @@ int pty_forward_new(
return r;
}
- if (!read_only) {
+ if (!(flags & PTY_FORWARD_READ_ONLY)) {
r = fd_nonblock(STDIN_FILENO, true);
if (r < 0)
return r;
@@ -344,7 +355,7 @@ int pty_forward_new(
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
(void) ioctl(master, TIOCSWINSZ, &ws);
- if (!read_only) {
+ if (!(flags & PTY_FORWARD_READ_ONLY)) {
if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
struct termios raw_stdin_attr;
@@ -429,16 +440,20 @@ int pty_forward_get_last_char(PTYForward *f, char *ch) {
return 0;
}
-int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) {
+int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) {
int r;
assert(f);
- if (f->ignore_vhangup == ignore_vhangup)
+ if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b)
return 0;
- f->ignore_vhangup = ignore_vhangup;
- if (!f->ignore_vhangup) {
+ if (b)
+ f->flags |= PTY_FORWARD_IGNORE_VHANGUP;
+ else
+ f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP;
+
+ if (!ignore_vhangup(f)) {
/* We shall now react to vhangup()s? Let's check
* immediately if we might be in one */
@@ -455,5 +470,5 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) {
int pty_forward_get_ignore_vhangup(PTYForward *f) {
assert(f);
- return f->ignore_vhangup;
+ return !!(f->flags & PTY_FORWARD_IGNORE_VHANGUP);
}
diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h
index 6f84e4036a..9b3214221b 100644
--- a/src/shared/ptyfwd.h
+++ b/src/shared/ptyfwd.h
@@ -27,7 +27,17 @@
typedef struct PTYForward PTYForward;
-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, bool read_only, PTYForward **f);
+typedef enum PTYForwardFlags {
+ PTY_FORWARD_READ_ONLY = 1,
+
+ /* Continue reading after hangup? */
+ PTY_FORWARD_IGNORE_VHANGUP = 2,
+
+ /* Continue reading after hangup but only if we never read anything else? */
+ PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 4,
+} PTYForwardFlags;
+
+int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **f);
PTYForward *pty_forward_free(PTYForward *f);
int pty_forward_get_last_char(PTYForward *f, char *ch);
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 1064fd5cbd..3dedbd1f62 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -226,7 +226,7 @@ static bool enough_memory_for_hibernation(void) {
if (r < 0)
return false;
- r = get_status_field("/proc/meminfo", "\nActive(anon):", &active);
+ r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active);
if (r < 0) {
log_error_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
return false;
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
index 70466d17e5..29db855c67 100644
--- a/src/shared/spawn-ask-password-agent.c
+++ b/src/shared/spawn-ask-password-agent.c
@@ -19,13 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
-#include <signal.h>
#include "log.h"
-#include "util.h"
#include "process-util.h"
+#include "util.h"
#include "spawn-ask-password-agent.h"
static pid_t agent_pid = 0;
@@ -46,9 +46,9 @@ int ask_password_agent_open(void) {
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
if (r < 0)
- log_error_errno(r, "Failed to fork TTY ask password agent: %m");
+ return log_error_errno(r, "Failed to fork TTY ask password agent: %m");
- return r;
+ return 1;
}
void ask_password_agent_close(void) {
@@ -57,8 +57,8 @@ void ask_password_agent_close(void) {
return;
/* Inform agent that we are done */
- kill(agent_pid, SIGTERM);
- kill(agent_pid, SIGCONT);
+ (void) kill(agent_pid, SIGTERM);
+ (void) kill(agent_pid, SIGCONT);
(void) wait_for_terminate(agent_pid, NULL);
agent_pid = 0;
}
diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c
index 1de0b94fd5..b2cab948ef 100644
--- a/src/shared/sysctl-util.c
+++ b/src/shared/sysctl-util.c
@@ -19,18 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fileio.h"
#include "log.h"
#include "util.h"
-#include "fileio.h"
-#include "build.h"
#include "sysctl-util.h"
char *sysctl_normalize(char *s) {