diff options
Diffstat (limited to 'src/shared')
94 files changed, 0 insertions, 26774 deletions
diff --git a/src/shared/Makefile b/src/shared/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/shared/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c deleted file mode 100644 index d1eb6f2268..0000000000 --- a/src/shared/acl-util.c +++ /dev/null @@ -1,68 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 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 <assert.h> -#include <sys/acl.h> -#include <acl/libacl.h> -#include <errno.h> -#include <stdbool.h> - -#include "acl-util.h" - -int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { - acl_entry_t i; - int found; - - assert(acl); - assert(entry); - - for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); - found > 0; - found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { - - acl_tag_t tag; - uid_t *u; - bool b; - - if (acl_get_tag_type(i, &tag) < 0) - return -errno; - - if (tag != ACL_USER) - continue; - - u = acl_get_qualifier(i); - if (!u) - return -errno; - - b = *u == uid; - acl_free(u); - - if (b) { - *entry = i; - return 1; - } - } - - if (found < 0) - return -errno; - - return 0; -} diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h deleted file mode 100644 index 31fbbcd510..0000000000 --- a/src/shared/acl-util.h +++ /dev/null @@ -1,24 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2011 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/>. -***/ - -int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry); diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c deleted file mode 100644 index 8a0fb89a84..0000000000 --- a/src/shared/ask-password-api.c +++ /dev/null @@ -1,576 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <stdbool.h> -#include <termios.h> -#include <unistd.h> -#include <sys/poll.h> -#include <sys/inotify.h> -#include <errno.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <string.h> -#include <sys/un.h> -#include <stddef.h> -#include <sys/signalfd.h> - -#include "util.h" -#include "mkdir.h" -#include "strv.h" - -#include "ask-password-api.h" - -static void backspace_chars(int ttyfd, size_t p) { - - if (ttyfd < 0) - return; - - while (p > 0) { - p--; - - loop_write(ttyfd, "\b \b", 3, false); - } -} - -int ask_password_tty( - const char *message, - usec_t until, - const char *flag_file, - char **_passphrase) { - - struct termios old_termios, new_termios; - char passphrase[LINE_MAX]; - size_t p = 0; - int r, 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); - - if (flag_file) { - if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { - r = -errno; - goto finish; - } - - if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) { - r = -errno; - goto finish; - } - } - - if ((ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC)) >= 0) { - - if (tcgetattr(ttyfd, &old_termios) < 0) { - r = -errno; - goto finish; - } - - loop_write(ttyfd, ANSI_HIGHLIGHT_ON, sizeof(ANSI_HIGHLIGHT_ON)-1, 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); - - new_termios = old_termios; - new_termios.c_lflag &= ~(ICANON|ECHO); - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - - if (tcsetattr(ttyfd, TCSADRAIN, &new_termios) < 0) { - r = -errno; - goto finish; - } - - reset_tty = true; - } - - zero(pollfd); - - pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO; - pollfd[POLL_TTY].events = POLLIN; - pollfd[POLL_INOTIFY].fd = notify; - pollfd[POLL_INOTIFY].events = POLLIN; - - for (;;) { - char c; - int sleep_for = -1, k; - ssize_t n; - - if (until > 0) { - usec_t y; - - y = now(CLOCK_MONOTONIC); - - if (y > until) { - r = -ETIME; - goto finish; - } - - sleep_for = (int) ((until - y) / USEC_PER_MSEC); - } - - if (flag_file) - if (access(flag_file, F_OK) < 0) { - r = -errno; - goto finish; - } - - if ((k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for)) < 0) { - - if (errno == EINTR) - continue; - - r = -errno; - goto finish; - } else if (k == 0) { - r = -ETIME; - goto finish; - } - - if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) - flush_fd(notify); - - if (pollfd[POLL_TTY].revents == 0) - continue; - - if ((n = read(ttyfd >= 0 ? ttyfd : STDIN_FILENO, &c, 1)) < 0) { - - if (errno == EINTR || errno == EAGAIN) - continue; - - r = -errno; - goto finish; - - } else if (n == 0) - break; - - if (c == '\n') - break; - else if (c == 21) { /* C-u */ - - if (!silent_mode) - backspace_chars(ttyfd, p); - p = 0; - - } else if (c == '\b' || c == 127) { - - if (p > 0) { - - if (!silent_mode) - backspace_chars(ttyfd, 1); - - p--; - } else if (!dirty && !silent_mode) { - - silent_mode = true; - - /* There are two ways to enter silent - * mode. Either by pressing backspace - * 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) { - - backspace_chars(ttyfd, p); - silent_mode = true; - - /* ... or by pressing TAB at any time. */ - - if (ttyfd >= 0) - loop_write(ttyfd, "(no echo) ", 10, false); - } else { - passphrase[p++] = c; - - if (!silent_mode && ttyfd >= 0) - loop_write(ttyfd, "*", 1, false); - - dirty = true; - } - } - - passphrase[p] = 0; - - if (!(*_passphrase = strdup(passphrase))) { - r = -ENOMEM; - goto finish; - } - - r = 0; - -finish: - if (notify >= 0) - close_nointr_nofail(notify); - - if (ttyfd >= 0) { - - if (reset_tty) { - loop_write(ttyfd, "\n", 1, false); - tcsetattr(ttyfd, TCSADRAIN, &old_termios); - } - - close_nointr_nofail(ttyfd); - } - - return r; -} - -static int create_socket(char **name) { - int fd; - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa; - int one = 1, r; - char *c; - mode_t u; - - assert(name); - - if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) { - log_error("socket() failed: %m"); - return -errno; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%llu", random_ull()); - - u = umask(0177); - r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); - umask(u); - - if (r < 0) { - r = -errno; - log_error("bind() failed: %m"); - goto fail; - } - - if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { - r = -errno; - log_error("SO_PASSCRED failed: %m"); - goto fail; - } - - if (!(c = strdup(sa.un.sun_path))) { - r = log_oom(); - goto fail; - } - - *name = c; - return fd; - -fail: - close_nointr_nofail(fd); - - return r; -} - -int ask_password_agent( - const char *message, - const char *icon, - usec_t until, - bool accept_cached, - char ***_passphrases) { - - enum { - FD_SOCKET, - FD_SIGNAL, - _FD_MAX - }; - - char temp[] = "/run/systemd/ask-password/tmp.XXXXXX"; - char final[sizeof(temp)] = ""; - int fd = -1, r; - FILE *f = NULL; - char *socket_name = NULL; - int socket_fd = -1, signal_fd = -1; - sigset_t mask, oldmask; - struct pollfd pollfd[_FD_MAX]; - mode_t u; - - assert(_passphrases); - - assert_se(sigemptyset(&mask) == 0); - sigset_add_many(&mask, SIGINT, SIGTERM, -1); - assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); - - mkdir_p_label("/run/systemd/ask-password", 0755); - - u = umask(0022); - fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY); - umask(u); - - if (fd < 0) { - log_error("Failed to create password file: %m"); - r = -errno; - goto finish; - } - - fchmod(fd, 0644); - - if (!(f = fdopen(fd, "w"))) { - log_error("Failed to allocate FILE: %m"); - r = -errno; - goto finish; - } - - fd = -1; - - if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) { - log_error("signalfd(): %m"); - r = -errno; - goto finish; - } - - if ((socket_fd = create_socket(&socket_name)) < 0) { - r = socket_fd; - goto finish; - } - - fprintf(f, - "[Ask]\n" - "PID=%lu\n" - "Socket=%s\n" - "AcceptCached=%i\n" - "NotAfter=%llu\n", - (unsigned long) getpid(), - socket_name, - accept_cached ? 1 : 0, - (unsigned long long) until); - - if (message) - fprintf(f, "Message=%s\n", message); - - if (icon) - fprintf(f, "Icon=%s\n", icon); - - fflush(f); - - if (ferror(f)) { - log_error("Failed to write query file: %m"); - r = -errno; - goto finish; - } - - memcpy(final, temp, sizeof(temp)); - - final[sizeof(final)-11] = 'a'; - final[sizeof(final)-10] = 's'; - final[sizeof(final)-9] = 'k'; - - if (rename(temp, final) < 0) { - log_error("Failed to rename query file: %m"); - r = -errno; - goto finish; - } - - zero(pollfd); - pollfd[FD_SOCKET].fd = socket_fd; - pollfd[FD_SOCKET].events = POLLIN; - pollfd[FD_SIGNAL].fd = signal_fd; - pollfd[FD_SIGNAL].events = POLLIN; - - for (;;) { - char passphrase[LINE_MAX+1]; - struct msghdr msghdr; - struct iovec iovec; - struct ucred *ucred; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred))]; - } control; - ssize_t n; - int k; - usec_t t; - - t = now(CLOCK_MONOTONIC); - - if (until > 0 && until <= t) { - log_notice("Timed out"); - r = -ETIME; - goto finish; - } - - if ((k = poll(pollfd, _FD_MAX, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1)) < 0) { - - if (errno == EINTR) - continue; - - log_error("poll() failed: %m"); - r = -errno; - goto finish; - } - - if (k <= 0) { - log_notice("Timed out"); - r = -ETIME; - goto finish; - } - - if (pollfd[FD_SIGNAL].revents & POLLIN) { - r = -EINTR; - goto finish; - } - - if (pollfd[FD_SOCKET].revents != POLLIN) { - log_error("Unexpected poll() event."); - r = -EIO; - goto finish; - } - - zero(iovec); - iovec.iov_base = passphrase; - iovec.iov_len = sizeof(passphrase); - - zero(control); - zero(msghdr); - msghdr.msg_iov = &iovec; - msghdr.msg_iovlen = 1; - msghdr.msg_control = &control; - msghdr.msg_controllen = sizeof(control); - - if ((n = recvmsg(socket_fd, &msghdr, 0)) < 0) { - - if (errno == EAGAIN || - errno == EINTR) - continue; - - log_error("recvmsg() failed: %m"); - r = -errno; - goto finish; - } - - if (n <= 0) { - log_error("Message too short"); - continue; - } - - if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) || - 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."); - continue; - } - - ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); - if (ucred->uid != 0) { - log_warning("Got request from unprivileged user. Ignoring."); - continue; - } - - if (passphrase[0] == '+') { - char **l; - - 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"); - continue; - } - - *_passphrases = l; - - } else if (passphrase[0] == '-') { - r = -ECANCELED; - goto finish; - } else { - log_error("Invalid packet"); - continue; - } - - break; - } - - r = 0; - -finish: - if (fd >= 0) - close_nointr_nofail(fd); - - if (socket_name) { - unlink(socket_name); - free(socket_name); - } - - if (socket_fd >= 0) - close_nointr_nofail(socket_fd); - - if (signal_fd >= 0) - close_nointr_nofail(signal_fd); - - if (f) - fclose(f); - - unlink(temp); - - if (final[0]) - unlink(final); - - assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0); - - return r; -} - -int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases) { - assert(message); - assert(_passphrases); - - if (isatty(STDIN_FILENO)) { - int r; - char *s = NULL, **l = NULL; - - if ((r = ask_password_tty(message, until, NULL, &s)) < 0) - return r; - - l = strv_new(s, NULL); - free(s); - - if (!l) - return -ENOMEM; - - *_passphrases = l; - return r; - - } else - return ask_password_agent(message, icon, until, accept_cached, _passphrases); -} diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h deleted file mode 100644 index 288a0f48cf..0000000000 --- a/src/shared/ask-password-api.h +++ /dev/null @@ -1,30 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 "util.h" - -int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase); - -int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases); - -int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases); diff --git a/src/shared/audit.c b/src/shared/audit.c deleted file mode 100644 index e5c483ab08..0000000000 --- a/src/shared/audit.c +++ /dev/null @@ -1,118 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <ctype.h> -#include <sys/prctl.h> -#include <sys/capability.h> - -#include "macro.h" -#include "audit.h" -#include "util.h" -#include "log.h" - -int audit_session_from_pid(pid_t pid, uint32_t *id) { - char *s; - uint32_t u; - int r; - - assert(id); - - if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0) - return -ENOENT; - - if (pid == 0) - r = read_one_line_file("/proc/self/sessionid", &s); - else { - char *p; - - if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0) - return -ENOMEM; - - r = read_one_line_file(p, &s); - free(p); - } - - if (r < 0) - return r; - - r = safe_atou32(s, &u); - free(s); - - if (r < 0) - return r; - - if (u == (uint32_t) -1 || u <= 0) - return -ENOENT; - - *id = u; - return 0; -} - -int audit_loginuid_from_pid(pid_t pid, uid_t *uid) { - char *s; - uid_t u; - int r; - - assert(uid); - - /* Only use audit login uid if we are executed with sufficient - * capabilities so that pam_loginuid could do its job. If we - * are lacking the CAP_AUDIT_CONTROL capabality we most likely - * are being run in a container and /proc/self/loginuid is - * useless since it probably contains a uid of the host - * system. */ - - if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0) - return -ENOENT; - - if (pid == 0) - r = read_one_line_file("/proc/self/loginuid", &s); - else { - char *p; - - if (asprintf(&p, "/proc/%lu/loginuid", (unsigned long) pid) < 0) - return -ENOMEM; - - r = read_one_line_file(p, &s); - free(p); - } - - if (r < 0) - return r; - - r = parse_uid(s, &u); - free(s); - - if (r < 0) - return r; - - if (u == (uid_t) -1) - return -ENOENT; - - *uid = (uid_t) u; - return 0; -} diff --git a/src/shared/audit.h b/src/shared/audit.h deleted file mode 100644 index 490a0b0320..0000000000 --- a/src/shared/audit.h +++ /dev/null @@ -1,32 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooaudithfoo -#define fooaudithfoo - -/*** - 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 <sys/types.h> - -#include "capability.h" - -int audit_session_from_pid(pid_t pid, uint32_t *id); -int audit_loginuid_from_pid(pid_t pid, uid_t *uid); - -#endif diff --git a/src/shared/capability.c b/src/shared/capability.c deleted file mode 100644 index 9b743e86d0..0000000000 --- a/src/shared/capability.c +++ /dev/null @@ -1,224 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdio.h> -#include <sys/types.h> -#include <stdarg.h> -#include <ctype.h> -#include <sys/capability.h> -#include <sys/prctl.h> - -#include "macro.h" -#include "capability.h" -#include "util.h" -#include "log.h" - -int have_effective_cap(int value) { - cap_t cap; - cap_flag_value_t fv; - int r; - - cap = cap_get_proc(); - if (!cap) - return -errno; - - if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0) - r = -errno; - else - r = fv == CAP_SET; - - cap_free(cap); - return r; -} - -unsigned long cap_last_cap(void) { - static __thread unsigned long saved; - static __thread bool valid = false; - unsigned long p; - - if (valid) - return saved; - - p = (unsigned long) CAP_LAST_CAP; - - if (prctl(PR_CAPBSET_READ, p) < 0) { - - /* Hmm, look downwards, until we find one that - * works */ - for (p--; p > 0; p --) - if (prctl(PR_CAPBSET_READ, p) >= 0) - break; - - } else { - - /* Hmm, look upwards, until we find one that doesn't - * work */ - for (;; p++) - if (prctl(PR_CAPBSET_READ, p+1) < 0) - break; - } - - saved = p; - valid = true; - - return p; -} - -int capability_bounding_set_drop(uint64_t drop, bool right_now) { - unsigned long i; - cap_t after_cap = NULL, temp_cap = NULL; - cap_flag_value_t fv; - int r; - - /* If we are run as PID 1 we will lack CAP_SETPCAP by default - * in the effective set (yes, the kernel drops that when - * executing init!), so get it back temporarily so that we can - * call PR_CAPBSET_DROP. */ - - after_cap = cap_get_proc(); - if (!after_cap) - return -errno; - - if (cap_get_flag(after_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0) { - cap_free(after_cap); - return -errno; - } - - if (fv != CAP_SET) { - static const cap_value_t v = CAP_SETPCAP; - - temp_cap = cap_dup(after_cap); - if (!temp_cap) { - r = -errno; - goto finish; - } - - if (cap_set_flag(temp_cap, CAP_EFFECTIVE, 1, &v, CAP_SET) < 0) { - r = -errno; - goto finish; - } - - if (cap_set_proc(temp_cap) < 0) { - r = -errno; - goto finish; - } - } - - for (i = 0; i <= cap_last_cap(); i++) { - - if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { - cap_value_t v; - - /* Drop it from the bounding set */ - if (prctl(PR_CAPBSET_DROP, i) < 0) { - r = -errno; - goto finish; - } - v = i; - - /* Also drop it from the inheritable set, so - * that anything we exec() loses the - * capability for good. */ - if (cap_set_flag(after_cap, CAP_INHERITABLE, 1, &v, CAP_CLEAR) < 0) { - r = -errno; - goto finish; - } - - /* If we shall apply this right now drop it - * also from our own capability sets. */ - if (right_now) { - if (cap_set_flag(after_cap, CAP_PERMITTED, 1, &v, CAP_CLEAR) < 0 || - cap_set_flag(after_cap, CAP_EFFECTIVE, 1, &v, CAP_CLEAR) < 0) { - r = -errno; - goto finish; - } - } - } - } - - r = 0; - -finish: - if (temp_cap) - cap_free(temp_cap); - - if (after_cap) { - cap_set_proc(after_cap); - cap_free(after_cap); - } - - return r; -} - -static int drop_from_file(const char *fn, uint64_t drop) { - int r, k; - uint32_t hi, lo; - uint64_t current, after; - char *p; - - r = read_one_line_file(fn, &p); - if (r < 0) - return r; - - assert_cc(sizeof(hi) == sizeof(unsigned)); - assert_cc(sizeof(lo) == sizeof(unsigned)); - - k = sscanf(p, "%u %u", &lo, &hi); - free(p); - - if (k != 2) - return -EIO; - - current = (uint64_t) lo | ((uint64_t) hi << 32ULL); - after = current & ~drop; - - if (current == after) - return 0; - - lo = (unsigned) (after & 0xFFFFFFFFULL); - hi = (unsigned) ((after >> 32ULL) & 0xFFFFFFFFULL); - - if (asprintf(&p, "%u %u", lo, hi) < 0) - return -ENOMEM; - - r = write_one_line_file(fn, p); - free(p); - - return r; -} - -int capability_bounding_set_drop_usermode(uint64_t drop) { - int r; - - r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop); - if (r < 0) - return r; - - r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop); - if (r < 0) - return r; - - return r; -} diff --git a/src/shared/capability.h b/src/shared/capability.h deleted file mode 100644 index 6cb31bb510..0000000000 --- a/src/shared/capability.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foocapabilityhfoo -#define foocapabilityhfoo - -/*** - 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 <inttypes.h> -#include <stdbool.h> - -unsigned long cap_last_cap(void); -int have_effective_cap(int value); -int capability_bounding_set_drop(uint64_t drop, bool right_now); -int capability_bounding_set_drop_usermode(uint64_t drop); - -#endif diff --git a/src/shared/cgroup-label.c b/src/shared/cgroup-label.c deleted file mode 100644 index beeeec5830..0000000000 --- a/src/shared/cgroup-label.c +++ /dev/null @@ -1,82 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <errno.h> -#include <unistd.h> -#include <signal.h> -#include <string.h> -#include <stdlib.h> -#include <dirent.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <ftw.h> - -#include "cgroup-util.h" -#include "log.h" -#include "set.h" -#include "macro.h" -#include "util.h" -#include "mkdir.h" - -int cg_create(const char *controller, const char *path) { - char *fs; - int r; - - assert(controller); - assert(path); - - r = cg_get_path_and_check(controller, path, NULL, &fs); - if (r < 0) - return r; - - r = mkdir_parents_label(fs, 0755); - - if (r >= 0) { - if (mkdir(fs, 0755) >= 0) - r = 1; - else if (errno == EEXIST) - r = 0; - else - r = -errno; - } - - free(fs); - - return r; -} - -int cg_create_and_attach(const char *controller, const char *path, pid_t pid) { - int r, q; - - assert(controller); - assert(path); - assert(pid >= 0); - - if ((r = cg_create(controller, path)) < 0) - return r; - - if ((q = cg_attach(controller, path, pid)) < 0) - return q; - - /* This does not remove the cgroup on failure */ - - return r; -} diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c deleted file mode 100644 index 437d09711b..0000000000 --- a/src/shared/cgroup-show.c +++ /dev/null @@ -1,351 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <stdio.h> -#include <string.h> -#include <dirent.h> -#include <errno.h> - -#include "util.h" -#include "macro.h" -#include "path-util.h" -#include "cgroup-util.h" -#include "cgroup-show.h" - -static int compare(const void *a, const void *b) { - const pid_t *p = a, *q = b; - - if (*p < *q) - return -1; - if (*p > *q) - return 1; - return 0; -} - -static unsigned ilog10(unsigned long ul) { - int n = 0; - - while (ul > 0) { - n++; - ul /= 10; - } - - return n; -} - -static void show_pid_array(int pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads) { - unsigned i, m, pid_width; - pid_t biggest = 0; - - /* Filter duplicates */ - m = 0; - for (i = 0; i < n_pids; i++) { - unsigned j; - - if (pids[i] > biggest) - biggest = pids[i]; - - for (j = i+1; j < n_pids; j++) - if (pids[i] == pids[j]) - break; - - if (j >= n_pids) - pids[m++] = pids[i]; - } - n_pids = m; - pid_width = ilog10(biggest); - - /* And sort */ - qsort(pids, n_pids, sizeof(pid_t), compare); - - if (n_columns > pid_width+2) - n_columns -= pid_width+2; - else - n_columns = 20; - - for (i = 0; i < n_pids; i++) { - char *t = NULL; - - get_process_cmdline(pids[i], n_columns, true, &t); - - printf("%s%s%*lu %s\n", - prefix, - draw_special_char(extra ? DRAW_TRIANGULAR_BULLET : - ((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)), - pid_width, - (unsigned long) pids[i], - strna(t)); - - free(t); - } -} - - -static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads) { - char *fn; - FILE *f; - size_t n = 0, n_allocated = 0; - pid_t *pids = NULL; - char *p; - pid_t pid; - int r; - - r = cg_fix_path(path, &p); - if (r < 0) - return r; - - r = asprintf(&fn, "%s/cgroup.procs", p); - free(p); - if (r < 0) - return -ENOMEM; - - f = fopen(fn, "re"); - free(fn); - if (!f) - return -errno; - - while ((r = cg_read_pid(f, &pid)) > 0) { - - if (!kernel_threads && is_kernel_thread(pid) > 0) - continue; - - if (n >= n_allocated) { - pid_t *npids; - - n_allocated = MAX(16U, n*2U); - - npids = realloc(pids, sizeof(pid_t) * n_allocated); - if (!npids) { - r = -ENOMEM; - goto finish; - } - - pids = npids; - } - - assert(n < n_allocated); - pids[n++] = pid; - } - - if (r < 0) - goto finish; - - if (n > 0) - show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads); - - r = 0; - -finish: - free(pids); - - if (f) - fclose(f); - - return r; -} - -int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) { - DIR *d; - char *last = NULL; - char *p1 = NULL, *p2 = NULL, *fn = NULL, *gn = NULL; - bool shown_pids = false; - int r; - - assert(path); - - if (n_columns <= 0) - n_columns = columns(); - - if (!prefix) - prefix = ""; - - r = cg_fix_path(path, &fn); - if (r < 0) - return r; - - d = opendir(fn); - if (!d) { - free(fn); - return -errno; - } - - while ((r = cg_read_subgroup(d, &gn)) > 0) { - char *k; - - r = asprintf(&k, "%s/%s", fn, gn); - free(gn); - if (r < 0) { - r = -ENOMEM; - goto finish; - } - - if (!all && cg_is_empty_recursive(NULL, k, false) > 0) { - free(k); - continue; - } - - if (!shown_pids) { - show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads); - shown_pids = true; - } - - if (last) { - printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), - path_get_file_name(last)); - - if (!p1) { - p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERT)); - if (!p1) { - free(k); - r = -ENOMEM; - goto finish; - } - } - - show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, all); - free(last); - } - - last = k; - } - - if (r < 0) - goto finish; - - if (!shown_pids) - show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads); - - if (last) { - printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), - path_get_file_name(last)); - - if (!p2) { - p2 = strappend(prefix, " "); - if (!p2) { - r = -ENOMEM; - goto finish; - } - } - - show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, all); - } - - r = 0; - -finish: - free(p1); - free(p2); - free(last); - free(fn); - - closedir(d); - - return r; -} - -int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all) { - char *p; - int r; - - assert(controller); - assert(path); - - r = cg_get_path(controller, path, NULL, &p); - if (r < 0) - return r; - - r = show_cgroup_by_path(p, prefix, n_columns, kernel_threads, all); - free(p); - - return r; -} - -static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids) { - pid_t *copy; - unsigned i, j; - int r; - - assert(controller); - assert(path); - - if (n_pids <= 0) - return 0; - - if (n_columns <= 0) - n_columns = columns(); - - if (!prefix) - prefix = ""; - - copy = new(pid_t, n_pids); - if (!copy) - return -ENOMEM; - - for (i = 0, j = 0; i < n_pids; i++) { - char *k; - - r = cg_get_by_pid(controller, pids[i], &k); - if (r < 0) { - free(copy); - return r; - } - - if (path_startswith(k, path)) - continue; - - copy[j++] = pids[i]; - } - - show_pid_array(copy, j, prefix, n_columns, true, false, false); - - free(copy); - return 0; -} - -int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids) { - int r; - - assert(controller); - assert(path); - - r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, all); - if (r < 0) - return r; - - return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids); -} - -int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids) { - int r; - char *controller, *path; - - assert(spec); - - r = cg_split_spec(spec, &controller, &path); - if (r < 0) - return r; - - r = show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, all, extra_pids, n_extra_pids); - free(controller); - free(path); - - return r; -} diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h deleted file mode 100644 index dba900a153..0000000000 --- a/src/shared/cgroup-show.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foocgroupshowhfoo -#define foocgroupshowhfoo - -/*** - 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 <stdbool.h> -#include <sys/types.h> - -int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all); -int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, bool all); - -int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids); -int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, bool all, const pid_t extra_pids[], unsigned n_extra_pids); - -#endif diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c deleted file mode 100644 index b0d378de5a..0000000000 --- a/src/shared/cgroup-util.c +++ /dev/null @@ -1,1256 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <errno.h> -#include <unistd.h> -#include <signal.h> -#include <string.h> -#include <stdlib.h> -#include <dirent.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <ftw.h> - -#include "cgroup-util.h" -#include "log.h" -#include "set.h" -#include "macro.h" -#include "util.h" -#include "path-util.h" -#include "strv.h" - -int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { - char *fs; - int r; - FILE *f; - - assert(path); - assert(_f); - - r = cg_get_path(controller, path, "cgroup.procs", &fs); - if (r < 0) - return r; - - f = fopen(fs, "re"); - free(fs); - - if (!f) - return -errno; - - *_f = f; - return 0; -} - -int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) { - char *fs; - int r; - FILE *f; - - assert(path); - assert(_f); - - r = cg_get_path(controller, path, "tasks", &fs); - if (r < 0) - return r; - - f = fopen(fs, "re"); - free(fs); - - if (!f) - return -errno; - - *_f = f; - return 0; -} - -int cg_read_pid(FILE *f, pid_t *_pid) { - unsigned long ul; - - /* Note that the cgroup.procs might contain duplicates! See - * cgroups.txt for details. */ - - errno = 0; - if (fscanf(f, "%lu", &ul) != 1) { - - if (feof(f)) - return 0; - - return errno ? -errno : -EIO; - } - - if (ul <= 0) - return -EIO; - - *_pid = (pid_t) ul; - return 1; -} - -int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) { - char *fs; - int r; - DIR *d; - - assert(path); - assert(_d); - - /* This is not recursive! */ - - r = cg_get_path(controller, path, NULL, &fs); - if (r < 0) - return r; - - d = opendir(fs); - free(fs); - - if (!d) - return -errno; - - *_d = d; - return 0; -} - -int cg_read_subgroup(DIR *d, char **fn) { - struct dirent *de; - - assert(d); - - errno = 0; - while ((de = readdir(d))) { - char *b; - - if (de->d_type != DT_DIR) - continue; - - if (streq(de->d_name, ".") || - streq(de->d_name, "..")) - continue; - - if (!(b = strdup(de->d_name))) - return -ENOMEM; - - *fn = b; - return 1; - } - - if (errno) - return -errno; - - return 0; -} - -int cg_rmdir(const char *controller, const char *path, bool honour_sticky) { - char *p; - int r; - - r = cg_get_path(controller, path, NULL, &p); - if (r < 0) - return r; - - if (honour_sticky) { - char *tasks; - - /* If the sticky bit is set don't remove the directory */ - - tasks = strappend(p, "/tasks"); - if (!tasks) { - free(p); - return -ENOMEM; - } - - r = file_is_priv_sticky(tasks); - free(tasks); - - if (r > 0) { - free(p); - return 0; - } - } - - r = rmdir(p); - free(p); - - return (r < 0 && errno != ENOENT) ? -errno : 0; -} - -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) { - bool done = false; - int r, ret = 0; - pid_t my_pid; - FILE *f = NULL; - Set *allocated_set = NULL; - - assert(controller); - assert(path); - assert(sig >= 0); - - /* This goes through the tasks list and kills them all. This - * is repeated until no further processes are added to the - * tasks list, to properly handle forking processes */ - - if (!s) - if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - my_pid = getpid(); - - do { - pid_t pid = 0; - done = true; - - if ((r = cg_enumerate_processes(controller, path, &f)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - - goto finish; - } - - while ((r = cg_read_pid(f, &pid)) > 0) { - - if (pid == my_pid && ignore_self) - continue; - - if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) - continue; - - /* If we haven't killed this process yet, kill - * it */ - if (kill(pid, sig) < 0) { - if (ret >= 0 && errno != ESRCH) - ret = -errno; - } else if (ret == 0) { - - if (sigcont) - kill(pid, SIGCONT); - - ret = 1; - } - - done = false; - - if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - } - - if (r < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - - fclose(f); - f = NULL; - - /* To avoid racing against processes which fork - * quicker than we can kill them we repeat this until - * no new pids need to be killed. */ - - } while (!done); - -finish: - if (allocated_set) - set_free(allocated_set); - - if (f) - fclose(f); - - return ret; -} - -int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) { - int r, ret = 0; - DIR *d = NULL; - char *fn; - Set *allocated_set = NULL; - - assert(path); - assert(controller); - assert(sig >= 0); - - if (!s) - if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - ret = cg_kill(controller, path, sig, sigcont, ignore_self, s); - - if ((r = cg_enumerate_subgroups(controller, path, &d)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - - goto finish; - } - - while ((r = cg_read_subgroup(d, &fn)) > 0) { - char *p = NULL; - - r = asprintf(&p, "%s/%s", path, fn); - free(fn); - - if (r < 0) { - if (ret >= 0) - ret = -ENOMEM; - - goto finish; - } - - r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s); - free(p); - - if (r != 0 && ret >= 0) - ret = r; - } - - if (r < 0 && ret >= 0) - ret = r; - - if (rem) - if ((r = cg_rmdir(controller, path, true)) < 0) { - if (ret >= 0 && - r != -ENOENT && - r != -EBUSY) - ret = r; - } - -finish: - if (d) - closedir(d); - - if (allocated_set) - set_free(allocated_set); - - return ret; -} - -int cg_kill_recursive_and_wait(const char *controller, const char *path, bool rem) { - unsigned i; - - assert(path); - assert(controller); - - /* This safely kills all processes; first it sends a SIGTERM, - * then checks 8 times after 200ms whether the group is now - * empty, then kills everything that is left with SIGKILL and - * finally checks 5 times after 200ms each whether the group - * is finally empty. */ - - for (i = 0; i < 15; i++) { - int sig, r; - - if (i <= 0) - sig = SIGTERM; - else if (i == 9) - sig = SIGKILL; - else - sig = 0; - - if ((r = cg_kill_recursive(controller, path, sig, true, true, rem, NULL)) <= 0) - return r; - - usleep(200 * USEC_PER_MSEC); - } - - return 0; -} - -int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) { - bool done = false; - Set *s; - int r, ret = 0; - pid_t my_pid; - FILE *f = NULL; - - assert(controller); - assert(from); - assert(to); - - if (!(s = set_new(trivial_hash_func, trivial_compare_func))) - return -ENOMEM; - - my_pid = getpid(); - - do { - pid_t pid = 0; - done = true; - - if ((r = cg_enumerate_tasks(controller, from, &f)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - - goto finish; - } - - while ((r = cg_read_pid(f, &pid)) > 0) { - - /* This might do weird stuff if we aren't a - * single-threaded program. However, we - * luckily know we are not */ - if (pid == my_pid && ignore_self) - continue; - - if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid)) - continue; - - if ((r = cg_attach(controller, to, pid)) < 0) { - if (ret >= 0 && r != -ESRCH) - ret = r; - } else if (ret == 0) - ret = 1; - - done = false; - - if ((r = set_put(s, LONG_TO_PTR(pid))) < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - } - - if (r < 0) { - if (ret >= 0) - ret = r; - - goto finish; - } - - fclose(f); - f = NULL; - - } while (!done); - -finish: - set_free(s); - - if (f) - fclose(f); - - return ret; -} - -int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool rem) { - int r, ret = 0; - DIR *d = NULL; - char *fn; - - assert(controller); - assert(from); - assert(to); - - ret = cg_migrate(controller, from, to, ignore_self); - - if ((r = cg_enumerate_subgroups(controller, from, &d)) < 0) { - if (ret >= 0 && r != -ENOENT) - ret = r; - goto finish; - } - - while ((r = cg_read_subgroup(d, &fn)) > 0) { - char *p = NULL; - - r = asprintf(&p, "%s/%s", from, fn); - free(fn); - - if (r < 0) { - if (ret >= 0) - ret = -ENOMEM; - - goto finish; - } - - r = cg_migrate_recursive(controller, p, to, ignore_self, rem); - free(p); - - if (r != 0 && ret >= 0) - ret = r; - } - - if (r < 0 && ret >= 0) - ret = r; - - if (rem) - if ((r = cg_rmdir(controller, from, true)) < 0) { - if (ret >= 0 && - r != -ENOENT && - r != -EBUSY) - ret = r; - } - -finish: - if (d) - closedir(d); - - return ret; -} - -static const char *normalize_controller(const char *controller) { - - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) - return "systemd"; - else if (startswith(controller, "name=")) - return controller + 5; - else - return controller; -} - -static int join_path(const char *controller, const char *path, const char *suffix, char **fs) { - char *t = NULL; - - if (!(controller || path)) - return -EINVAL; - - if (controller) { - if (path && suffix) - t = strjoin("/sys/fs/cgroup/", controller, "/", path, "/", suffix, NULL); - else if (path) - t = strjoin("/sys/fs/cgroup/", controller, "/", path, NULL); - else if (suffix) - t = strjoin("/sys/fs/cgroup/", controller, "/", suffix, NULL); - else - t = strjoin("/sys/fs/cgroup/", controller, NULL); - } else { - if (path && suffix) - t = strjoin(path, "/", suffix, NULL); - else if (path) - t = strdup(path); - } - - if (!t) - return -ENOMEM; - - path_kill_slashes(t); - - *fs = t; - return 0; -} - -int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs) { - const char *p; - static __thread bool good = false; - - assert(fs); - - if (_unlikely_(!good)) { - int r; - - r = path_is_mount_point("/sys/fs/cgroup", false); - if (r <= 0) - return r < 0 ? r : -ENOENT; - - /* Cache this to save a few stat()s */ - good = true; - } - - p = controller ? normalize_controller(controller) : NULL; - return join_path(p, path, suffix, fs); -} - -static int check(const char *p) { - char *cc; - - assert(p); - - /* Check if this controller actually really exists */ - cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p)); - strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p); - if (access(cc, F_OK) < 0) - return -errno; - - return 0; -} - -int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) { - const char *p; - int r; - - assert(controller); - assert(fs); - - if (isempty(controller)) - return -EINVAL; - - /* Normalize the controller syntax */ - p = normalize_controller(controller); - - /* Check if this controller actually really exists */ - r = check(p); - if (r < 0) - return r; - - return join_path(p, path, suffix, fs); -} - -static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { - char *p; - bool is_sticky; - - if (typeflag != FTW_DP) - return 0; - - if (ftwbuf->level < 1) - return 0; - - p = strappend(path, "/tasks"); - if (!p) { - errno = ENOMEM; - return 1; - } - - is_sticky = file_is_priv_sticky(p) > 0; - free(p); - - if (is_sticky) - return 0; - - rmdir(path); - return 0; -} - -int cg_trim(const char *controller, const char *path, bool delete_root) { - char *fs; - int r = 0; - - assert(controller); - assert(path); - - r = cg_get_path(controller, path, NULL, &fs); - if (r < 0) - return r; - - errno = 0; - if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0) - r = errno ? -errno : -EIO; - - if (delete_root) { - bool is_sticky; - char *p; - - p = strappend(fs, "/tasks"); - if (!p) { - free(fs); - return -ENOMEM; - } - - is_sticky = file_is_priv_sticky(p) > 0; - free(p); - - if (!is_sticky) - if (rmdir(fs) < 0 && errno != ENOENT) { - if (r == 0) - r = -errno; - } - } - - free(fs); - - return r; -} - -int cg_delete(const char *controller, const char *path) { - char *parent; - int r; - - assert(controller); - assert(path); - - if ((r = path_get_parent(path, &parent)) < 0) - return r; - - r = cg_migrate_recursive(controller, path, parent, false, true); - free(parent); - - return r == -ENOENT ? 0 : r; -} - -int cg_attach(const char *controller, const char *path, pid_t pid) { - char *fs; - int r; - char c[32]; - - assert(controller); - assert(path); - assert(pid >= 0); - - r = cg_get_path_and_check(controller, path, "tasks", &fs); - if (r < 0) - return r; - - if (pid == 0) - pid = getpid(); - - snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid); - char_array_0(c); - - r = write_one_line_file(fs, c); - free(fs); - - return r; -} - -int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid) { - char *fs; - int r; - - assert(controller); - assert(path); - - if (mode != (mode_t) -1) - mode &= 0777; - - r = cg_get_path(controller, path, NULL, &fs); - if (r < 0) - return r; - - r = chmod_and_chown(fs, mode, uid, gid); - free(fs); - - return r; -} - -int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky) { - char *fs; - int r; - - assert(controller); - assert(path); - - if (mode == (mode_t) -1 && uid == (uid_t) -1 && gid == (gid_t) -1 && sticky < 0) - return 0; - - if (mode != (mode_t) -1) - mode &= 0666; - - r = cg_get_path(controller, path, "tasks", &fs); - if (r < 0) - return r; - - if (sticky >= 0 && mode != (mode_t) -1) - /* Both mode and sticky param are passed */ - mode |= (sticky ? S_ISVTX : 0); - else if ((sticky >= 0 && mode == (mode_t) -1) || - (mode != (mode_t) -1 && sticky < 0)) { - struct stat st; - - /* Only one param is passed, hence read the current - * mode from the file itself */ - - r = lstat(fs, &st); - if (r < 0) { - free(fs); - return -errno; - } - - if (mode == (mode_t) -1) - /* No mode set, we just shall set the sticky bit */ - mode = (st.st_mode & ~S_ISVTX) | (sticky ? S_ISVTX : 0); - else - /* Only mode set, leave sticky bit untouched */ - mode = (st.st_mode & ~0777) | mode; - } - - r = chmod_and_chown(fs, mode, uid, gid); - free(fs); - - return r; -} - -int cg_get_by_pid(const char *controller, pid_t pid, char **path) { - int r; - char *p = NULL; - FILE *f; - char *fs; - size_t cs; - - assert(controller); - assert(path); - assert(pid >= 0); - - if (pid == 0) - pid = getpid(); - - if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0) - return -ENOMEM; - - f = fopen(fs, "re"); - free(fs); - - if (!f) - return errno == ENOENT ? -ESRCH : -errno; - - cs = strlen(controller); - - while (!feof(f)) { - char line[LINE_MAX]; - char *l; - - errno = 0; - if (!(fgets(line, sizeof(line), f))) { - if (feof(f)) - break; - - r = errno ? -errno : -EIO; - goto finish; - } - - truncate_nl(line); - - if (!(l = strchr(line, ':'))) - continue; - - l++; - if (strncmp(l, controller, cs) != 0) - continue; - - if (l[cs] != ':') - continue; - - if (!(p = strdup(l + cs + 1))) { - r = -ENOMEM; - goto finish; - } - - *path = p; - r = 0; - goto finish; - } - - r = -ENOENT; - -finish: - fclose(f); - - return r; -} - -int cg_install_release_agent(const char *controller, const char *agent) { - char *fs = NULL, *contents = NULL, *line = NULL, *sc; - int r; - - assert(controller); - assert(agent); - - if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0) - return r; - - if ((r = read_one_line_file(fs, &contents)) < 0) - goto finish; - - sc = strstrip(contents); - if (sc[0] == 0) { - - if (asprintf(&line, "%s\n", agent) < 0) { - r = -ENOMEM; - goto finish; - } - - if ((r = write_one_line_file(fs, line)) < 0) - goto finish; - - } else if (!streq(sc, agent)) { - r = -EEXIST; - goto finish; - } - - free(fs); - fs = NULL; - if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0) - goto finish; - - free(contents); - contents = NULL; - if ((r = read_one_line_file(fs, &contents)) < 0) - goto finish; - - sc = strstrip(contents); - - if (streq(sc, "0")) { - if ((r = write_one_line_file(fs, "1\n")) < 0) - goto finish; - - r = 1; - } else if (!streq(sc, "1")) { - r = -EIO; - goto finish; - } else - r = 0; - -finish: - free(fs); - free(contents); - free(line); - - return r; -} - -int cg_is_empty(const char *controller, const char *path, bool ignore_self) { - pid_t pid = 0, self_pid; - int r; - FILE *f = NULL; - bool found = false; - - assert(path); - - r = cg_enumerate_tasks(controller, path, &f); - if (r < 0) - return r == -ENOENT ? 1 : r; - - self_pid = getpid(); - - while ((r = cg_read_pid(f, &pid)) > 0) { - - if (ignore_self && pid == self_pid) - continue; - - found = true; - break; - } - - fclose(f); - - if (r < 0) - return r; - - return !found; -} - -int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) { - int r; - DIR *d = NULL; - char *fn; - - assert(path); - - r = cg_is_empty(controller, path, ignore_self); - if (r <= 0) - return r; - - r = cg_enumerate_subgroups(controller, path, &d); - if (r < 0) - return r == -ENOENT ? 1 : r; - - while ((r = cg_read_subgroup(d, &fn)) > 0) { - char *p = NULL; - - r = asprintf(&p, "%s/%s", path, fn); - free(fn); - - if (r < 0) { - r = -ENOMEM; - goto finish; - } - - r = cg_is_empty_recursive(controller, p, ignore_self); - free(p); - - if (r <= 0) - goto finish; - } - - if (r >= 0) - r = 1; - -finish: - - if (d) - closedir(d); - - return r; -} - -int cg_split_spec(const char *spec, char **controller, char **path) { - const char *e; - char *t = NULL, *u = NULL; - - assert(spec); - assert(controller || path); - - if (*spec == '/') { - - if (path) { - if (!(t = strdup(spec))) - return -ENOMEM; - - *path = t; - } - - if (controller) - *controller = NULL; - - return 0; - } - - if (!(e = strchr(spec, ':'))) { - - if (strchr(spec, '/') || spec[0] == 0) - return -EINVAL; - - if (controller) { - if (!(t = strdup(spec))) - return -ENOMEM; - - *controller = t; - } - - if (path) - *path = NULL; - - return 0; - } - - if (e[1] != '/' || - e == spec || - memchr(spec, '/', e-spec)) - return -EINVAL; - - if (controller) - if (!(t = strndup(spec, e-spec))) - return -ENOMEM; - - if (path) - if (!(u = strdup(e+1))) { - free(t); - return -ENOMEM; - } - - if (controller) - *controller = t; - - if (path) - *path = u; - - return 0; -} - -int cg_join_spec(const char *controller, const char *path, char **spec) { - assert(controller); - assert(path); - - if (!path_is_absolute(path) || - controller[0] == 0 || - strchr(controller, ':') || - strchr(controller, '/')) - return -EINVAL; - - if (asprintf(spec, "%s:%s", controller, path) < 0) - return -ENOMEM; - - return 0; -} - -int cg_fix_path(const char *path, char **result) { - char *t, *c, *p; - int r; - - assert(path); - assert(result); - - /* First check if it already is a filesystem path */ - if (path_startswith(path, "/sys/fs/cgroup") && - access(path, F_OK) >= 0) { - - t = strdup(path); - if (!t) - return -ENOMEM; - - *result = t; - return 0; - } - - /* Otherwise treat it as cg spec */ - r = cg_split_spec(path, &c, &p); - if (r < 0) - return r; - - r = cg_get_path(c ? c : SYSTEMD_CGROUP_CONTROLLER, p ? p : "/", NULL, result); - free(c); - free(p); - - return r; -} - -int cg_get_user_path(char **path) { - char *root, *p; - - assert(path); - - /* Figure out the place to put user cgroups below. We use the - * same as PID 1 has but with the "/system" suffix replaced by - * "/user" */ - - if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0) - p = strdup("/user"); - else { - if (endswith(root, "/system")) - root[strlen(root) - 7] = 0; - else if (streq(root, "/")) - root[0] = 0; - - p = strappend(root, "/user"); - free(root); - } - - if (!p) - return -ENOMEM; - - *path = p; - return 0; -} - -char **cg_shorten_controllers(char **controllers) { - char **f, **t; - - controllers = strv_uniq(controllers); - - if (!controllers) - return controllers; - - for (f = controllers, t = controllers; *f; f++) { - int r; - const char *p; - - if (streq(*f, "systemd") || streq(*f, SYSTEMD_CGROUP_CONTROLLER)) { - free(*f); - continue; - } - - p = normalize_controller(*f); - - r = check(p); - if (r < 0) { - log_debug("Controller %s is not available, removing from controllers list.", *f); - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return controllers; -} - -int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup) { - char *cg_process, *cg_init, *p; - int r; - - assert(pid >= 0); - - if (pid == 0) - pid = getpid(); - - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process); - if (r < 0) - return r; - - r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init); - if (r < 0) { - free(cg_process); - return r; - } - - if (endswith(cg_init, "/system")) - cg_init[strlen(cg_init)-7] = 0; - else if (streq(cg_init, "/")) - cg_init[0] = 0; - - if (startswith(cg_process, cg_init)) - p = cg_process + strlen(cg_init); - else - p = cg_process; - - free(cg_init); - - if (cgroup) { - char* c; - - c = strdup(p); - if (!c) { - free(cg_process); - return -ENOMEM; - } - - *cgroup = c; - } - - if (root) { - cg_process[p-cg_process] = 0; - *root = cg_process; - } else - free(cg_process); - - return 0; -} - -int cg_pid_get_unit(pid_t pid, char **unit) { - int r; - char *cgroup, *p, *at, *b; - size_t k; - - assert(pid >= 0); - assert(unit); - - r = cg_pid_get_cgroup(pid, NULL, &cgroup); - if (r < 0) - return r; - - if (!startswith(cgroup, "/system/")) { - free(cgroup); - return -ENOENT; - } - - p = cgroup + 8; - k = strcspn(p, "/"); - - at = memchr(p, '@', k); - if (at && at[1] == '.') { - size_t j; - - /* This is a templated service */ - if (p[k] != '/') { - free(cgroup); - return -EIO; - } - - j = strcspn(p+k+1, "/"); - - b = malloc(k + j + 1); - - if (b) { - memcpy(b, p, at - p + 1); - memcpy(b + (at - p) + 1, p + k + 1, j); - memcpy(b + (at - p) + 1 + j, at + 1, k - (at - p) - 1); - b[k+j] = 0; - } - } else - b = strndup(p, k); - - free(cgroup); - - if (!b) - return -ENOMEM; - - *unit = b; - return 0; - -} diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h deleted file mode 100644 index 697669deba..0000000000 --- a/src/shared/cgroup-util.h +++ /dev/null @@ -1,74 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <sys/types.h> -#include <stdio.h> -#include <dirent.h> - -#include "set.h" -#include "def.h" - -int cg_enumerate_processes(const char *controller, const char *path, FILE **_f); -int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f); -int cg_read_pid(FILE *f, pid_t *_pid); - -int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d); -int cg_read_subgroup(DIR *d, char **fn); - -int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s); -int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool remove, Set *s); -int cg_kill_recursive_and_wait(const char *controller, const char *path, bool remove); - -int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self); -int cg_migrate_recursive(const char *controller, const char *from, const char *to, bool ignore_self, bool remove); - -int cg_split_spec(const char *spec, char **controller, char **path); -int cg_join_spec(const char *controller, const char *path, char **spec); -int cg_fix_path(const char *path, char **result); - -int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs); -int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs); -int cg_get_by_pid(const char *controller, pid_t pid, char **path); - -int cg_trim(const char *controller, const char *path, bool delete_root); - -int cg_rmdir(const char *controller, const char *path, bool honour_sticky); -int cg_delete(const char *controller, const char *path); - -int cg_create(const char *controller, const char *path); -int cg_attach(const char *controller, const char *path, pid_t pid); -int cg_create_and_attach(const char *controller, const char *path, pid_t pid); - -int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); -int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid, int sticky); - -int cg_install_release_agent(const char *controller, const char *agent); - -int cg_is_empty(const char *controller, const char *path, bool ignore_self); -int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self); - -int cg_get_user_path(char **path); -int cg_pid_get_cgroup(pid_t pid, char **root, char **cgroup); -int cg_pid_get_unit(pid_t pid, char **unit); - -char **cg_shorten_controllers(char **controllers); diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c deleted file mode 100644 index 34b86293d3..0000000000 --- a/src/shared/conf-files.c +++ /dev/null @@ -1,153 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/stat.h> -#include <dirent.h> - -#include "macro.h" -#include "util.h" -#include "missing.h" -#include "log.h" -#include "strv.h" -#include "path-util.h" -#include "hashmap.h" -#include "conf-files.h" - -static int files_add(Hashmap *h, const char *path, const char *suffix) { - DIR *dir; - int r = 0; - - dir = opendir(path); - if (!dir) { - if (errno == ENOENT) - return 0; - return -errno; - } - - for (;;) { - struct dirent *de; - union dirent_storage buf; - int k; - char *p; - - k = readdir_r(dir, &buf.de, &de); - if (k != 0) { - r = -k; - goto finish; - } - - if (!de) - break; - - if (!dirent_is_file_with_suffix(de, suffix)) - continue; - - if (asprintf(&p, "%s/%s", path, de->d_name) < 0) { - r = -ENOMEM; - goto finish; - } - - if (hashmap_put(h, path_get_file_name(p), p) <= 0) { - log_debug("Skip overridden file: %s.", p); - free(p); - } - } - -finish: - closedir(dir); - return r; -} - -static int base_cmp(const void *a, const void *b) { - const char *s1, *s2; - - s1 = *(char * const *)a; - s2 = *(char * const *)b; - return strcmp(path_get_file_name(s1), path_get_file_name(s2)); -} - -int conf_files_list_strv(char ***strv, const char *suffix, const char **dirs) { - Hashmap *fh = NULL; - char **files = NULL; - const char **p; - int r; - - assert(dirs); - - fh = hashmap_new(string_hash_func, string_compare_func); - if (!fh) { - r = -ENOMEM; - goto finish; - } - - STRV_FOREACH(p, dirs) { - r = files_add(fh, *p, suffix); - if (r < 0) - log_warning("Failed to search for files in %s: %s", - *p, strerror(-r)); - } - - files = hashmap_get_strv(fh); - if (files == NULL) { - log_error("Failed to compose list of files."); - r = -ENOMEM; - goto finish; - } - qsort(files, hashmap_size(fh), sizeof(char *), base_cmp); - r = 0; - -finish: - hashmap_free(fh); - *strv = files; - return r; -} - -int conf_files_list(char ***strv, const char *suffix, const char *dir, ...) { - char **dirs = NULL; - va_list ap; - int r; - - va_start(ap, dir); - dirs = strv_new_ap(dir, ap); - va_end(ap); - if (!dirs) { - r = -ENOMEM; - goto finish; - } - - if (!path_strv_canonicalize(dirs)) { - r = -ENOMEM; - goto finish; - } - strv_uniq(dirs); - - r = conf_files_list_strv(strv, suffix, (const char **)dirs); - -finish: - strv_free(dirs); - return r; -} diff --git a/src/shared/conf-files.h b/src/shared/conf-files.h deleted file mode 100644 index f37ee1f3db..0000000000 --- a/src/shared/conf-files.h +++ /dev/null @@ -1,31 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef fooconffileshfoo -#define fooconffileshfoo - -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - Copyright 2010-2012 Kay Sievers - - 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 "macro.h" - -int conf_files_list(char ***strv, const char *suffix, const char *dir, ...); -int conf_files_list_strv(char ***strv, const char *suffix, const char **dirs); - -#endif diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c deleted file mode 100644 index 9f5c07c761..0000000000 --- a/src/shared/conf-parser.c +++ /dev/null @@ -1,1007 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <string.h> -#include <stdio.h> -#include <errno.h> -#include <assert.h> -#include <stdlib.h> - -#include "conf-parser.h" -#include "util.h" -#include "macro.h" -#include "strv.h" -#include "log.h" -#include "utf8.h" -#include "path-util.h" -#include "set.h" -#include "exit-status.h" - -int config_item_table_lookup( - void *table, - const char *section, - const char *lvalue, - ConfigParserCallback *func, - int *ltype, - void **data, - void *userdata) { - - ConfigTableItem *t; - - assert(table); - assert(lvalue); - assert(func); - assert(ltype); - assert(data); - - for (t = table; t->lvalue; t++) { - - if (!streq(lvalue, t->lvalue)) - continue; - - if (!streq_ptr(section, t->section)) - continue; - - *func = t->parse; - *ltype = t->ltype; - *data = t->data; - return 1; - } - - return 0; -} - -int config_item_perf_lookup( - void *table, - const char *section, - const char *lvalue, - ConfigParserCallback *func, - int *ltype, - void **data, - void *userdata) { - - ConfigPerfItemLookup lookup = (ConfigPerfItemLookup) table; - const ConfigPerfItem *p; - - assert(table); - assert(lvalue); - assert(func); - assert(ltype); - assert(data); - - if (!section) - p = lookup(lvalue, strlen(lvalue)); - else { - char *key; - - key = strjoin(section, ".", lvalue, NULL); - if (!key) - return -ENOMEM; - - p = lookup(key, strlen(key)); - free(key); - } - - if (!p) - return 0; - - *func = p->parse; - *ltype = p->ltype; - *data = (uint8_t*) userdata + p->offset; - return 1; -} - -/* Run the user supplied parser for an assignment */ -static int next_assignment( - const char *filename, - unsigned line, - ConfigItemLookup lookup, - void *table, - const char *section, - const char *lvalue, - const char *rvalue, - bool relaxed, - void *userdata) { - - ConfigParserCallback func = NULL; - int ltype = 0; - void *data = NULL; - int r; - - assert(filename); - assert(line > 0); - assert(lookup); - assert(lvalue); - assert(rvalue); - - r = lookup(table, section, lvalue, &func, <ype, &data, userdata); - if (r < 0) - return r; - - if (r > 0) { - if (func) - return func(filename, line, section, lvalue, ltype, rvalue, data, userdata); - - return 0; - } - - /* Warn about unknown non-extension fields. */ - if (!relaxed && !startswith(lvalue, "X-")) - log_info("[%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring.", filename, line, lvalue, section); - - return 0; -} - -/* Parse a variable assignment line */ -static int parse_line( - const char *filename, - unsigned line, - const char *sections, - ConfigItemLookup lookup, - void *table, - bool relaxed, - char **section, - char *l, - void *userdata) { - - char *e; - - assert(filename); - assert(line > 0); - assert(lookup); - assert(l); - - l = strstrip(l); - - if (!*l) - return 0; - - if (strchr(COMMENTS, *l)) - return 0; - - if (startswith(l, ".include ")) { - char *fn; - int r; - - fn = file_in_same_dir(filename, strstrip(l+9)); - if (!fn) - return -ENOMEM; - - r = config_parse(fn, NULL, sections, lookup, table, relaxed, userdata); - free(fn); - - return r; - } - - if (*l == '[') { - size_t k; - char *n; - - k = strlen(l); - assert(k > 0); - - if (l[k-1] != ']') { - log_error("[%s:%u] Invalid section header.", filename, line); - return -EBADMSG; - } - - n = strndup(l+1, k-2); - if (!n) - return -ENOMEM; - - if (sections && !nulstr_contains(sections, n)) { - - if (!relaxed) - log_info("[%s:%u] Unknown section '%s'. Ignoring.", filename, line, n); - - free(n); - *section = NULL; - } else { - free(*section); - *section = n; - } - - return 0; - } - - if (sections && !*section) { - - if (!relaxed) - log_info("[%s:%u] Assignment outside of section. Ignoring.", filename, line); - - return 0; - } - - e = strchr(l, '='); - if (!e) { - log_error("[%s:%u] Missing '='.", filename, line); - return -EBADMSG; - } - - *e = 0; - e++; - - return next_assignment( - filename, - line, - lookup, - table, - *section, - strstrip(l), - strstrip(e), - relaxed, - userdata); -} - -/* Go through the file and parse each line */ -int config_parse( - const char *filename, - FILE *f, - const char *sections, - ConfigItemLookup lookup, - void *table, - bool relaxed, - void *userdata) { - - unsigned line = 0; - char *section = NULL; - int r; - bool ours = false; - char *continuation = NULL; - - assert(filename); - assert(lookup); - - if (!f) { - f = fopen(filename, "re"); - if (!f) { - r = -errno; - log_error("Failed to open configuration file '%s': %s", filename, strerror(-r)); - goto finish; - } - - ours = true; - } - - while (!feof(f)) { - char l[LINE_MAX], *p, *c = NULL, *e; - bool escaped = false; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - r = -errno; - log_error("Failed to read configuration file '%s': %s", filename, strerror(-r)); - goto finish; - } - - truncate_nl(l); - - if (continuation) { - c = strappend(continuation, l); - if (!c) { - r = -ENOMEM; - goto finish; - } - - free(continuation); - continuation = NULL; - p = c; - } else - p = l; - - for (e = p; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - } - - if (escaped) { - *(e-1) = ' '; - - if (c) - continuation = c; - else { - continuation = strdup(l); - if (!continuation) { - r = -ENOMEM; - goto finish; - } - } - - continue; - } - - r = parse_line(filename, - ++line, - sections, - lookup, - table, - relaxed, - §ion, - p, - userdata); - free(c); - - if (r < 0) - goto finish; - } - - r = 0; - -finish: - free(section); - free(continuation); - - if (f && ours) - fclose(f); - - return r; -} - -int config_parse_int( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int *i = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atoi(rvalue, i)) < 0) { - log_error("[%s:%u] Failed to parse numeric value, ingoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_long( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - long *i = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atoli(rvalue, i)) < 0) { - log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_uint64( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - uint64_t *u = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atou64(rvalue, u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_unsigned( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - unsigned *u = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((r = safe_atou(rvalue, u)) < 0) { - log_error("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue); - return r; - } - - return 0; -} - -int config_parse_bytes_size( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - size_t *sz = data; - off_t o; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (parse_bytes(rvalue, &o) < 0 || (off_t) (size_t) o != o) { - log_error("[%s:%u] Failed to parse byte value, ignoring: %s", filename, line, rvalue); - return 0; - } - - *sz = (size_t) o; - return 0; -} - - -int config_parse_bytes_off( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - off_t *bytes = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - assert_cc(sizeof(off_t) == sizeof(uint64_t)); - - if (parse_bytes(rvalue, bytes) < 0) { - log_error("[%s:%u] Failed to parse bytes value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_bool( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int k; - bool *b = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if ((k = parse_boolean(rvalue)) < 0) { - log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue); - return 0; - } - - *b = !!k; - return 0; -} - -int config_parse_tristate( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - int k; - int *b = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - /* Tristates are like booleans, but can also take the 'default' value, i.e. "-1" */ - - k = parse_boolean(rvalue); - if (k < 0) { - log_error("[%s:%u] Failed to parse boolean value, ignoring: %s", filename, line, rvalue); - return 0; - } - - *b = !!k; - return 0; -} - -int config_parse_string( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - char *n; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return -ENOMEM; - - if (!utf8_is_valid(n)) { - log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); - free(n); - return 0; - } - - free(*s); - if (*n) - *s = n; - else { - free(n); - *s = NULL; - } - - return 0; -} - -int config_parse_path( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - char *n; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (!utf8_is_valid(rvalue)) { - log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); - return 0; - } - - if (!path_is_absolute(rvalue)) { - log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); - return 0; - } - - n = strdup(rvalue); - if (!n) - return -ENOMEM; - - path_kill_slashes(n); - - free(*s); - *s = n; - - return 0; -} - -int config_parse_strv( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char*** sv = data; - char **n; - char *w; - unsigned k; - size_t l; - char *state; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - k = strv_length(*sv); - FOREACH_WORD_QUOTED(w, l, rvalue, state) - k++; - - n = new(char*, k+1); - if (!n) - return -ENOMEM; - - if (*sv) - for (k = 0; (*sv)[k]; k++) - n[k] = (*sv)[k]; - else - k = 0; - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - n[k] = cunescape_length(w, l); - if (!n[k]) { - r = -ENOMEM; - goto fail; - } - - if (!utf8_is_valid(n[k])) { - log_error("[%s:%u] String is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); - free(n[k]); - continue; - } - - k++; - } - - n[k] = NULL; - free(*sv); - *sv = n; - - return 0; - -fail: - for (; k > 0; k--) - free(n[k-1]); - free(n); - - return r; -} - -int config_parse_path_strv( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char*** sv = data; - char **n; - char *w; - unsigned k; - size_t l; - char *state; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - k = strv_length(*sv); - FOREACH_WORD_QUOTED(w, l, rvalue, state) - k++; - - n = new(char*, k+1); - if (!n) - return -ENOMEM; - - k = 0; - if (*sv) - for (; (*sv)[k]; k++) - n[k] = (*sv)[k]; - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - n[k] = strndup(w, l); - if (!n[k]) { - r = -ENOMEM; - goto fail; - } - - if (!utf8_is_valid(n[k])) { - log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue); - free(n[k]); - continue; - } - - if (!path_is_absolute(n[k])) { - log_error("[%s:%u] Not an absolute path, ignoring: %s", filename, line, rvalue); - free(n[k]); - continue; - } - - path_kill_slashes(n[k]); - k++; - } - - n[k] = NULL; - free(*sv); - *sv = n; - - return 0; - -fail: - for (; k > 0; k--) - free(n[k-1]); - free(n); - - return r; -} - -int config_parse_usec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - usec_t *usec = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (parse_usec(rvalue, usec) < 0) { - log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_nsec( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - nsec_t *nsec = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (parse_nsec(rvalue, nsec) < 0) { - log_error("[%s:%u] Failed to parse time value, ignoring: %s", filename, line, rvalue); - return 0; - } - - return 0; -} - -int config_parse_mode( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - mode_t *m = data; - long l; - char *x = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - errno = 0; - l = strtol(rvalue, &x, 8); - if (!x || x == rvalue || *x || errno) { - log_error("[%s:%u] Failed to parse mode value, ignoring: %s", filename, line, rvalue); - return 0; - } - - if (l < 0000 || l > 07777) { - log_error("[%s:%u] mode value out of range, ignoring: %s", filename, line, rvalue); - return 0; - } - - *m = (mode_t) l; - return 0; -} - -int config_parse_facility( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - - int *o = data, x; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - x = log_facility_unshifted_from_string(rvalue); - if (x < 0) { - log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue); - return 0; - } - - *o = (x << 3) | LOG_PRI(*o); - - return 0; -} - -int config_parse_level( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - - int *o = data, x; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - x = log_level_from_string(rvalue); - if (x < 0) { - log_error("[%s:%u] Failed to parse log level, ignoring: %s", filename, line, rvalue); - return 0; - } - - *o = (*o & LOG_FACMASK) | x; - return 0; -} - -int config_parse_set_status( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char *w; - size_t l; - char *state; - int r; - ExitStatusSet *status_set = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - FOREACH_WORD(w, l, rvalue, state) { - int val; - char *temp; - - temp = strndup(w, l); - if (!temp) - return log_oom(); - - r = safe_atoi(temp, &val); - if (r < 0) { - val = signal_from_string_try_harder(temp); - free(temp); - - if (val > 0) { - r = set_ensure_allocated(&status_set->signal, trivial_hash_func, trivial_compare_func); - if (r < 0) - return log_oom(); - - r = set_put(status_set->signal, INT_TO_PTR(val)); - if (r < 0) { - log_error("[%s:%u] Unable to store: %s", filename, line, w); - return r; - } - } else { - log_error("[%s:%u] Failed to parse value, ignoring: %s", filename, line, w); - return 0; - } - } else { - free(temp); - - if (val < 0 || val > 255) - log_warning("[%s:%u] Value %d is outside range 0-255, ignoring", filename, line, val); - else { - r = set_ensure_allocated(&status_set->code, trivial_hash_func, trivial_compare_func); - if (r < 0) - return log_oom(); - - r = set_put(status_set->code, INT_TO_PTR(val)); - if (r < 0) { - log_error("[%s:%u] Unable to store: %s", filename, line, w); - return r; - } - } - } - } - - return 0; -} diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h deleted file mode 100644 index 56ffc2f8a8..0000000000 --- a/src/shared/conf-parser.h +++ /dev/null @@ -1,136 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdio.h> -#include <stdbool.h> - -/* An abstract parser for simple, line based, shallow configuration - * files consisting of variable assignments only. */ - -/* Prototype for a parser for a specific configuration setting */ -typedef int (*ConfigParserCallback)( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -/* Wraps information for parsing a specific configuration variable, to - * be stored in a simple array */ -typedef struct ConfigTableItem { - const char *section; /* Section */ - const char *lvalue; /* Name of the variable */ - ConfigParserCallback parse; /* Function that is called to parse the variable's value */ - int ltype; /* Distinguish different variables passed to the same callback */ - void *data; /* Where to store the variable's data */ -} ConfigTableItem; - -/* Wraps information for parsing a specific configuration variable, to - * ve srored in a gperf perfect hashtable */ -typedef struct ConfigPerfItem { - const char *section_and_lvalue; /* Section + "." + name of the variable */ - ConfigParserCallback parse; /* Function that is called to parse the variable's value */ - int ltype; /* Distinguish different variables passed to the same callback */ - size_t offset; /* Offset where to store data, from the beginning of userdata */ -} ConfigPerfItem; - -/* Prototype for a low-level gperf lookup function */ -typedef const ConfigPerfItem* (*ConfigPerfItemLookup)(const char *section_and_lvalue, unsigned length); - -/* Prototype for a generic high-level lookup function */ -typedef int (*ConfigItemLookup)( - void *table, - const char *section, - const char *lvalue, - ConfigParserCallback *func, - int *ltype, - void **data, - void *userdata); - -/* Linear table search implementation of ConfigItemLookup, based on - * ConfigTableItem arrays */ -int config_item_table_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); - -/* gperf implementation of ConfigItemLookup, based on gperf - * ConfigPerfItem tables */ -int config_item_perf_lookup(void *table, const char *section, const char *lvalue, ConfigParserCallback *func, int *ltype, void **data, void *userdata); - -int config_parse( - const char *filename, - FILE *f, - const char *sections, /* nulstr */ - ConfigItemLookup lookup, - void *table, - bool relaxed, - void *userdata); - -/* Generic parsers */ -int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_long(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_uint64(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_bytes_size(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_bytes_off(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_tristate(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_usec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_nsec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_facility(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_level(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_set_status(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ - int function( \ - const char *filename, \ - unsigned line, \ - const char *section, \ - const char *lvalue, \ - int ltype, \ - const char *rvalue, \ - void *data, \ - void *userdata) { \ - \ - type *i = data, x; \ - \ - assert(filename); \ - assert(lvalue); \ - assert(rvalue); \ - assert(data); \ - \ - if ((x = name##_from_string(rvalue)) < 0) { \ - log_error("[%s:%u] " msg ", ignoring: %s", filename, line, rvalue); \ - return 0; \ - } \ - \ - *i = x; \ - \ - return 0; \ - } diff --git a/src/shared/dbus-common.c b/src/shared/dbus-common.c deleted file mode 100644 index ee281e57f4..0000000000 --- a/src/shared/dbus-common.c +++ /dev/null @@ -1,1326 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <sys/socket.h> -#include <errno.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <dbus/dbus.h> -#include <string.h> -#include <sys/epoll.h> - -#include "log.h" -#include "dbus-common.h" -#include "util.h" -#include "missing.h" -#include "def.h" -#include "strv.h" - -int bus_check_peercred(DBusConnection *c) { - int fd; - struct ucred ucred; - socklen_t l; - - assert(c); - - assert_se(dbus_connection_get_unix_fd(c, &fd)); - - l = sizeof(struct ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) { - log_error("SO_PEERCRED failed: %m"); - return -errno; - } - - if (l != sizeof(struct ucred)) { - log_error("SO_PEERCRED returned wrong size."); - return -E2BIG; - } - - if (ucred.uid != 0 && ucred.uid != geteuid()) - return -EPERM; - - return 1; -} - -static int sync_auth(DBusConnection *bus, DBusError *error) { - usec_t begin, tstamp; - - assert(bus); - - /* This complexity should probably move into D-Bus itself: - * - * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */ - - begin = tstamp = now(CLOCK_MONOTONIC); - for (;;) { - - if (tstamp > begin + DEFAULT_TIMEOUT_USEC) - break; - - if (dbus_connection_get_is_authenticated(bus)) - break; - - if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC)) - break; - - tstamp = now(CLOCK_MONOTONIC); - } - - if (!dbus_connection_get_is_connected(bus)) { - dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication."); - return -ECONNREFUSED; - } - - if (!dbus_connection_get_is_authenticated(bus)) { - dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time."); - return -EACCES; - } - - return 0; -} - -int bus_connect(DBusBusType t, DBusConnection **_bus, bool *_private, DBusError *error) { - DBusConnection *bus = NULL; - int r; - bool private = true; - - assert(_bus); - - if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) { - /* If we are root, then let's talk directly to the - * system instance, instead of going via the bus */ - - bus = dbus_connection_open_private("unix:path=/run/systemd/private", error); - if (!bus) - return -EIO; - - } else { - if (t == DBUS_BUS_SESSION) { - const char *e; - - /* If we are supposed to talk to the instance, - * try via XDG_RUNTIME_DIR first, then - * fallback to normal bus access */ - - e = secure_getenv("XDG_RUNTIME_DIR"); - if (e) { - char *p; - - if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) - return -ENOMEM; - - bus = dbus_connection_open_private(p, NULL); - free(p); - } - } - - if (!bus) { - bus = dbus_bus_get_private(t, error); - if (!bus) - return -EIO; - - private = false; - } - } - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (private) { - if (bus_check_peercred(bus) < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - - dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus."); - return -EACCES; - } - } - - r = sync_auth(bus, error); - if (r < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (_private) - *_private = private; - - *_bus = bus; - return 0; -} - -int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) { - DBusConnection *bus; - char *p = NULL; - int r; - - assert(_bus); - assert(user || host); - - if (user && host) - asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host); - else if (user) - asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user); - else if (host) - asprintf(&p, "unixexec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host); - - if (!p) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return -ENOMEM; - } - - bus = dbus_connection_open_private(p, error); - free(p); - - if (!bus) - return -EIO; - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if ((r = sync_auth(bus, error)) < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (!dbus_bus_register(bus, error)) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - *_bus = bus; - return 0; -} - -int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) { - DBusConnection *bus; - int r; - - assert(_bus); - - /* Don't bother with PolicyKit if we are root */ - if (geteuid() == 0) - return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error); - - bus = dbus_connection_open_private("unixexec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error); - if (!bus) - return -EIO; - - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - r = sync_auth(bus, error); - if (r < 0) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - if (!dbus_bus_register(bus, error)) { - dbus_connection_close(bus); - dbus_connection_unref(bus); - return r; - } - - *_bus = bus; - return 0; -} - -const char *bus_error_message(const DBusError *error) { - if (!error) - return NULL; - - /* Sometimes the D-Bus server is a little bit too verbose with - * its error messages, so let's override them here */ - if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED)) - return "Access denied"; - - return error->message; -} - -const char *bus_error_message_or_strerror(const DBusError *error, int err) { - - if (error && dbus_error_is_set(error)) - return bus_error_message(error); - - return strerror(err); -} - -DBusHandlerResult bus_default_message_handler( - DBusConnection *c, - DBusMessage *message, - const char *introspection, - const char *interfaces, - const BusBoundProperties *bound_properties) { - - DBusError error; - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - int r; - - assert(c); - assert(message); - - dbus_error_init(&error); - - if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") && introspection) { - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Get") && bound_properties) { - const char *interface, *property; - const BusBoundProperties *bp; - const BusProperty *p; - void *data; - DBusMessageIter iter, sub; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_STRING, &property, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(c, message, &error, -EINVAL); - - for (bp = bound_properties; bp->interface; bp++) { - if (!streq(bp->interface, interface)) - continue; - - for (p = bp->properties; p->property; p++) - if (streq(p->property, property)) - goto get_prop; - } - - /* no match */ - if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(c, message, &error, -EINVAL); - -get_prop: - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, p->signature, &sub)) - goto oom; - - data = (char*)bp->base + p->offset; - if (p->indirect) - data = *(void**)data; - - r = p->append(&sub, property, data); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(c, message, NULL, r); - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && bound_properties) { - const char *interface; - const BusBoundProperties *bp; - const BusProperty *p; - DBusMessageIter iter, sub, sub2, sub3; - - if (!dbus_message_get_args( - message, - &error, - DBUS_TYPE_STRING, &interface, - DBUS_TYPE_INVALID)) - return bus_send_error_reply(c, message, &error, -EINVAL); - - if (interface[0] && !nulstr_contains(interfaces, interface)) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - dbus_message_iter_init_append(reply, &iter); - - if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub)) - goto oom; - - for (bp = bound_properties; bp->interface; bp++) { - if (interface[0] && !streq(bp->interface, interface)) - continue; - - for (p = bp->properties; p->property; p++) { - void *data; - - if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_DICT_ENTRY, NULL, &sub2) || - !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &p->property) || - !dbus_message_iter_open_container(&sub2, DBUS_TYPE_VARIANT, p->signature, &sub3)) - goto oom; - - data = (char*)bp->base + p->offset; - if (p->indirect) - data = *(void**)data; - r = p->append(&sub3, p->property, data); - if (r == -ENOMEM) - goto oom; - if (r < 0) - return bus_send_error_reply(c, message, NULL, r); - - if (!dbus_message_iter_close_container(&sub2, &sub3) || - !dbus_message_iter_close_container(&sub, &sub2)) - goto oom; - } - } - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && bound_properties) { - const char *interface, *property; - DBusMessageIter iter; - const BusBoundProperties *bp; - const BusProperty *p; - DBusMessageIter sub; - char *sig; - void *data; - DBusMessage *changed; - - if (!dbus_message_iter_init(message, &iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &interface); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - dbus_message_iter_get_basic(&iter, &property); - - if (!dbus_message_iter_next(&iter) || - dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT || - dbus_message_iter_has_next(&iter)) - return bus_send_error_reply(c, message, NULL, -EINVAL); - - for (bp = bound_properties; bp->interface; bp++) { - if (!streq(bp->interface, interface)) - continue; - - for (p = bp->properties; p->property; p++) - if (streq(p->property, property)) - goto set_prop; - } - - /* no match */ - if (!nulstr_contains(interfaces, interface)) - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - else - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property"); - - return bus_send_error_reply(c, message, &error, -EINVAL); - -set_prop: - if (!p->set) { - dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - - dbus_message_iter_recurse(&iter, &sub); - - sig = dbus_message_iter_get_signature(&sub); - if (!sig) - goto oom; - - if (!streq(sig, p->signature)) { - dbus_free(sig); - return bus_send_error_reply(c, message, NULL, -EINVAL); - } - dbus_free(sig); - - data = (uint8_t*) bp->base + p->offset; - if (p->indirect) - data = *(void**)data; - - r = p->set(&sub, property, data); - if (r == -ENOMEM) - goto oom; - else if (r < 0) - return bus_send_error_reply(c, message, NULL, r); - - reply = dbus_message_new_method_return(message); - if (!reply) - goto oom; - - /* Send out a signal about this, but it doesn't really - * matter if this fails, so eat all errors */ - changed = bus_properties_changed_one_new( - dbus_message_get_path(message), - interface, - property); - if (changed) { - dbus_connection_send(c, changed, NULL); - dbus_message_unref(changed); - } - - - } else { - const char *interface = dbus_message_get_interface(message); - - if (!interface || !nulstr_contains(interfaces, interface)) { - dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface"); - return bus_send_error_reply(c, message, &error, -EINVAL); - } - } - - if (reply) { - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - -oom: - dbus_error_free(&error); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -int bus_property_append_string(DBusMessageIter *i, const char *property, void *data) { - const char *t = data; - - assert(i); - assert(property); - - if (!t) - t = ""; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data) { - char **t = data; - - assert(i); - assert(property); - - return bus_append_strv_iter(i, t); -} - -int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data) { - bool *b = data; - dbus_bool_t db; - - assert(i); - assert(property); - assert(b); - - db = *b; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data) { - int *b = data; - dbus_bool_t db; - - assert(i); - assert(property); - assert(b); - - db = *b > 0; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &db)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - /* Let's ensure that usec_t is actually 64bit, and hence this - * function can be used for usec_t */ - assert_cc(sizeof(uint64_t) == sizeof(usec_t)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - /* Let's ensure that pid_t, mode_t, uid_t, gid_t are actually - * 32bit, and hence this function can be used for - * pid_t/mode_t/uid_t/gid_t */ - assert_cc(sizeof(uint32_t) == sizeof(pid_t)); - assert_cc(sizeof(uint32_t) == sizeof(mode_t)); - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - assert_cc(sizeof(uint32_t) == sizeof(uid_t)); - assert_cc(sizeof(uint32_t) == sizeof(gid_t)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data) { - assert(i); - assert(property); - assert(data); - - assert_cc(sizeof(int32_t) == sizeof(int)); - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, data)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_size(DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(size_t*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data) { - uint64_t u; - - assert(i); - assert(property); - assert(data); - - u = (uint64_t) *(unsigned long*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u)) - return -ENOMEM; - - return 0; -} - -int bus_property_append_long(DBusMessageIter *i, const char *property, void *data) { - int64_t l; - - assert(i); - assert(property); - assert(data); - - l = (int64_t) *(long*) data; - - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT64, &l)) - return -ENOMEM; - - return 0; -} - -int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data) { - uint64_t *t = data; - - assert(i); - assert(property); - - dbus_message_iter_get_basic(i, t); - return 0; -} - -const char *bus_errno_to_dbus(int error) { - - switch(error) { - - case -EINVAL: - return DBUS_ERROR_INVALID_ARGS; - - case -ENOMEM: - return DBUS_ERROR_NO_MEMORY; - - case -EPERM: - case -EACCES: - return DBUS_ERROR_ACCESS_DENIED; - - case -ESRCH: - return DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN; - - case -ENOENT: - return DBUS_ERROR_FILE_NOT_FOUND; - - case -EEXIST: - return DBUS_ERROR_FILE_EXISTS; - - case -ETIMEDOUT: - case -ETIME: - return DBUS_ERROR_TIMEOUT; - - case -EIO: - return DBUS_ERROR_IO_ERROR; - - case -ENETRESET: - case -ECONNABORTED: - case -ECONNRESET: - return DBUS_ERROR_DISCONNECTED; - } - - return DBUS_ERROR_FAILED; -} - -DBusHandlerResult bus_send_error_reply(DBusConnection *c, DBusMessage *message, DBusError *berror, int error) { - _cleanup_dbus_message_unref_ DBusMessage *reply = NULL; - const char *name, *text; - - if (berror && dbus_error_is_set(berror)) { - name = berror->name; - text = berror->message; - } else { - name = bus_errno_to_dbus(error); - text = strerror(-error); - } - - reply = dbus_message_new_error(message, name, text); - if (!reply) - goto oom; - - if (!dbus_connection_send(c, reply, NULL)) - goto oom; - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_HANDLED; - -oom: - if (reply) - dbus_message_unref(reply); - - if (berror) - dbus_error_free(berror); - - return DBUS_HANDLER_RESULT_NEED_MEMORY; -} - -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties) { - DBusMessage *m; - DBusMessageIter iter, sub; - const char *i; - - assert(interface); - assert(properties); - - m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); - if (!m) - goto oom; - - dbus_message_iter_init_append(m, &iter); - - /* We won't send any property values, since they might be - * large and sometimes not cheap to generated */ - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) - goto oom; - - NULSTR_FOREACH(i, properties) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &i)) - goto oom; - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - return m; - -oom: - if (m) - dbus_message_unref(m); - - return NULL; -} - -DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property) { - DBusMessage *m; - DBusMessageIter iter, sub; - - assert(interface); - assert(property); - - m = dbus_message_new_signal(path, "org.freedesktop.DBus.Properties", "PropertiesChanged"); - if (!m) - goto oom; - - dbus_message_iter_init_append(m, &iter); - - /* We won't send any property values, since they might be - * large and sometimes not cheap to generated */ - - if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &sub) || - !dbus_message_iter_close_container(&iter, &sub) || - !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) - goto oom; - - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &property)) - goto oom; - - if (!dbus_message_iter_close_container(&iter, &sub)) - goto oom; - - return m; - -oom: - if (m) - dbus_message_unref(m); - - return NULL; -} - -uint32_t bus_flags_to_events(DBusWatch *bus_watch) { - unsigned flags; - uint32_t events = 0; - - assert(bus_watch); - - /* no watch flags for disabled watches */ - if (!dbus_watch_get_enabled(bus_watch)) - return 0; - - flags = dbus_watch_get_flags(bus_watch); - - if (flags & DBUS_WATCH_READABLE) - events |= EPOLLIN; - if (flags & DBUS_WATCH_WRITABLE) - events |= EPOLLOUT; - - return events | EPOLLHUP | EPOLLERR; -} - -unsigned bus_events_to_flags(uint32_t events) { - unsigned flags = 0; - - if (events & EPOLLIN) - flags |= DBUS_WATCH_READABLE; - if (events & EPOLLOUT) - flags |= DBUS_WATCH_WRITABLE; - if (events & EPOLLHUP) - flags |= DBUS_WATCH_HANGUP; - if (events & EPOLLERR) - flags |= DBUS_WATCH_ERROR; - - return flags; -} - -int bus_parse_strv(DBusMessage *m, char ***_l) { - DBusMessageIter iter; - - assert(m); - assert(_l); - - if (!dbus_message_iter_init(m, &iter)) - return -EINVAL; - - return bus_parse_strv_iter(&iter, _l); -} - -int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l) { - DBusMessageIter sub; - unsigned n = 0, i = 0; - char **l; - - assert(iter); - assert(_l); - - if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(iter) != DBUS_TYPE_STRING) - return -EINVAL; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - n++; - dbus_message_iter_next(&sub); - } - - l = new(char*, n+1); - if (!l) - return -ENOMEM; - - dbus_message_iter_recurse(iter, &sub); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert_se(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - - if (!(l[i++] = strdup(s))) { - strv_free(l); - return -ENOMEM; - } - - dbus_message_iter_next(&sub); - } - - assert(i == n); - l[i] = NULL; - - if (_l) - *_l = l; - - return 0; -} - -int bus_append_strv_iter(DBusMessageIter *iter, char **l) { - DBusMessageIter sub; - - assert(iter); - - if (!dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &sub)) - return -ENOMEM; - - STRV_FOREACH(l, l) - if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, l)) - return -ENOMEM; - - if (!dbus_message_iter_close_container(iter, &sub)) - return -ENOMEM; - - return 0; -} - -int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next) { - - assert(iter); - assert(data); - - if (dbus_message_iter_get_arg_type(iter) != type) - return -EIO; - - dbus_message_iter_get_basic(iter, data); - - if (!dbus_message_iter_next(iter) != !next) - return -EIO; - - return 0; -} - -int generic_print_property(const char *name, DBusMessageIter *iter, bool all) { - assert(name); - assert(iter); - - switch (dbus_message_iter_get_arg_type(iter)) { - - case DBUS_TYPE_STRING: { - const char *s; - dbus_message_iter_get_basic(iter, &s); - - if (all || !isempty(s)) - printf("%s=%s\n", name, s); - - return 1; - } - - case DBUS_TYPE_BOOLEAN: { - dbus_bool_t b; - - dbus_message_iter_get_basic(iter, &b); - printf("%s=%s\n", name, yes_no(b)); - - return 1; - } - - case DBUS_TYPE_UINT64: { - uint64_t u; - dbus_message_iter_get_basic(iter, &u); - - /* Yes, heuristics! But we can change this check - * should it turn out to not be sufficient */ - - if (endswith(name, "Timestamp")) { - char timestamp[FORMAT_TIMESTAMP_MAX], *t; - - t = format_timestamp(timestamp, sizeof(timestamp), u); - if (t || all) - printf("%s=%s\n", name, strempty(t)); - - } else if (strstr(name, "USec")) { - char timespan[FORMAT_TIMESPAN_MAX]; - - printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u)); - } else - printf("%s=%llu\n", name, (unsigned long long) u); - - return 1; - } - - case DBUS_TYPE_UINT32: { - uint32_t u; - dbus_message_iter_get_basic(iter, &u); - - if (strstr(name, "UMask") || strstr(name, "Mode")) - printf("%s=%04o\n", name, u); - else - printf("%s=%u\n", name, (unsigned) u); - - return 1; - } - - case DBUS_TYPE_INT32: { - int32_t i; - dbus_message_iter_get_basic(iter, &i); - - printf("%s=%i\n", name, (int) i); - return 1; - } - - case DBUS_TYPE_DOUBLE: { - double d; - dbus_message_iter_get_basic(iter, &d); - - printf("%s=%g\n", name, d); - return 1; - } - - case DBUS_TYPE_ARRAY: - - if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) { - DBusMessageIter sub; - bool space = false; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - const char *s; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING); - dbus_message_iter_get_basic(&sub, &s); - printf("%s%s", space ? " " : "", s); - - space = true; - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - uint8_t u; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE); - dbus_message_iter_get_basic(&sub, &u); - printf("%02x", u); - - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - - } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_UINT32) { - DBusMessageIter sub; - - dbus_message_iter_recurse(iter, &sub); - if (all || - dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - printf("%s=", name); - - while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { - uint32_t u; - - assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32); - dbus_message_iter_get_basic(&sub, &u); - printf("%08x", u); - - dbus_message_iter_next(&sub); - } - - puts(""); - } - - return 1; - } - - break; - } - - return 0; -} - -static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) { - DBusMessage *reply; - DBusConnection *bus = userdata; - - assert_se(reply = dbus_pending_call_steal_reply(pending)); - dbus_message_unref(reply); - - dbus_connection_close(bus); -} - -void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) { - _cleanup_dbus_message_unref_ DBusMessage *m = NULL; - DBusPendingCall *pending = NULL; - - assert(bus); - - /* We unregister the name here, but we continue to process - * requests, until we get the response for it, so that all - * requests are guaranteed to be processed. */ - - m = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "ReleaseName"); - if (!m) - goto oom; - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, - &name, - DBUS_TYPE_INVALID)) - goto oom; - - if (!dbus_connection_send_with_reply(bus, m, &pending, -1)) - goto oom; - - if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL)) - goto oom; - - dbus_pending_call_unref(pending); - - return; - -oom: - log_oom(); - - if (pending) { - dbus_pending_call_cancel(pending); - dbus_pending_call_unref(pending); - } -} - -DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) { - usec_t *remain_until = userdata; - - assert(bus); - assert(m); - assert(remain_until); - - /* Every time we get a new message we reset out timeout */ - *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; - - if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) - dbus_connection_close(bus); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -/* This mimics dbus_bus_get_unix_user() */ -pid_t bus_get_unix_process_id( - DBusConnection *connection, - const char *name, - DBusError *error) { - - _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL; - uint32_t pid = 0; - - m = dbus_message_new_method_call( - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID"); - if (!m) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return 0; - } - - if (!dbus_message_append_args( - m, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) { - dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL); - return 0; - } - - reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error); - if (!reply) - return 0; - - if (dbus_set_error_from_message(error, reply)) - return 0; - - if (!dbus_message_get_args( - reply, error, - DBUS_TYPE_UINT32, &pid, - DBUS_TYPE_INVALID)) - return 0; - - return (pid_t) pid; -} - -bool bus_error_is_no_service(const DBusError *error) { - assert(error); - - if (!dbus_error_is_set(error)) - return false; - - if (dbus_error_has_name(error, DBUS_ERROR_NAME_HAS_NO_OWNER)) - return true; - - if (dbus_error_has_name(error, DBUS_ERROR_SERVICE_UNKNOWN)) - return true; - - return startswith(error->name, "org.freedesktop.DBus.Error.Spawn."); -} - -int bus_method_call_with_reply( - DBusConnection *bus, - const char *destination, - const char *path, - const char *interface, - const char *method, - DBusMessage **return_reply, - DBusError *return_error, - int first_arg_type, ...) { - - DBusError error; - _cleanup_dbus_message_unref_ DBusMessage *m = NULL; - DBusMessage *reply; - va_list ap; - int r = 0; - - dbus_error_init(&error); - assert(bus); - - m = dbus_message_new_method_call(destination, path, interface, method); - if (!m) { - r = log_oom(); - goto finish; - } - - va_start(ap, first_arg_type); - if (!dbus_message_append_args_valist(m, first_arg_type, ap)) { - va_end(ap); - r = log_oom(); - goto finish; - } - va_end(ap); - - reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error); - if (!reply) { - if (!return_error) - log_error("Failed to issue method call: %s", bus_error_message(&error)); - - if (bus_error_is_no_service(&error)) - r = -ENOENT; - else if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) - r = -EACCES; - else if (dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) - r = -ETIMEDOUT; - else - r = -EIO; - goto finish; - } - - if (return_reply) - *return_reply = reply; - else - dbus_message_unref(reply); - -finish: - if (return_error) - *return_error = error; - else - dbus_error_free(&error); - - return r; -} - -void bus_message_unrefp(DBusMessage **reply) { - if (!reply) - return; - - if (!*reply) - return; - - dbus_message_unref(*reply); -} - -const char *bus_message_get_sender_with_fallback(DBusMessage *m) { - const char *s; - - assert(m); - - s = dbus_message_get_sender(m); - if (s) - return s; - - /* When the message came in from a direct connection the - * message will have no sender. We fix that here. */ - - return ":no-sender"; -} diff --git a/src/shared/dbus-common.h b/src/shared/dbus-common.h deleted file mode 100644 index 005a715d0a..0000000000 --- a/src/shared/dbus-common.h +++ /dev/null @@ -1,222 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <dbus/dbus.h> -#include <inttypes.h> - -#ifndef DBUS_ERROR_UNKNOWN_OBJECT -#define DBUS_ERROR_UNKNOWN_OBJECT "org.freedesktop.DBus.Error.UnknownObject" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_INTERFACE -#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface" -#endif - -#ifndef DBUS_ERROR_UNKNOWN_PROPERTY -#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty" -#endif - -#ifndef DBUS_ERROR_PROPERTY_READ_ONLY -#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly" -#endif - -#define BUS_PROPERTIES_INTERFACE \ - " <interface name=\"org.freedesktop.DBus.Properties\">\n" \ - " <method name=\"Get\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"value\" direction=\"out\" type=\"v\"/>\n" \ - " </method>\n" \ - " <method name=\"GetAll\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"properties\" direction=\"out\" type=\"a{sv}\"/>\n" \ - " </method>\n" \ - " <method name=\"Set\">\n" \ - " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"property\" direction=\"in\" type=\"s\"/>\n" \ - " <arg name=\"value\" direction=\"in\" type=\"v\"/>\n" \ - " </method>\n" \ - " <signal name=\"PropertiesChanged\">\n" \ - " <arg type=\"s\" name=\"interface\"/>\n" \ - " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n" \ - " <arg type=\"as\" name=\"invalidated_properties\"/>\n" \ - " </signal>\n" \ - " </interface>\n" - -#define BUS_INTROSPECTABLE_INTERFACE \ - " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" \ - " <method name=\"Introspect\">\n" \ - " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" \ - " </method>\n" \ - " </interface>\n" - -#define BUS_PEER_INTERFACE \ - "<interface name=\"org.freedesktop.DBus.Peer\">\n" \ - " <method name=\"Ping\"/>\n" \ - " <method name=\"GetMachineId\">\n" \ - " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n" \ - " </method>\n" \ - "</interface>\n" - -#define BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.DBus.Properties\0" \ - "org.freedesktop.DBus.Introspectable\0" \ - "org.freedesktop.DBus.Peer\0" - -int bus_check_peercred(DBusConnection *c); - -int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error); - -int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error); -int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error); - -const char *bus_error_message(const DBusError *error); -const char *bus_error_message_or_strerror(const DBusError *error, int err); - -typedef int (*BusPropertyCallback)(DBusMessageIter *iter, const char *property, void *data); -typedef int (*BusPropertySetCallback)(DBusMessageIter *iter, const char *property, void *data); - -typedef struct BusProperty { - const char *property; /* name of the property */ - BusPropertyCallback append; /* Function that is called to serialize this property */ - const char *signature; - const uint16_t offset; /* Offset from BusBoundProperties::base address to the property data. - * uint16_t is sufficient, because we have no structs too big. - * -Werror=overflow will catch it if this does not hold. */ - bool indirect; /* data is indirect, ie. not base+offset, but *(base+offset) */ - BusPropertySetCallback set; /* Optional: Function that is called to set this property */ -} BusProperty; - -typedef struct BusBoundProperties { - const char *interface; /* interface of the properties */ - const BusProperty *properties; /* array of properties, ended by a NULL-filled element */ - const void *const base; /* base pointer to which the offset must be added to reach data */ -} BusBoundProperties; - -DBusHandlerResult bus_send_error_reply( - DBusConnection *c, - DBusMessage *message, - DBusError *bus_error, - int error); - -DBusHandlerResult bus_default_message_handler( - DBusConnection *c, - DBusMessage *message, - const char *introspection, - const char *interfaces, - const BusBoundProperties *bound_properties); - -int bus_property_append_string(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_strv(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_bool(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_tristate_false(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_int32(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint32(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_uint64(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_size(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_ul(DBusMessageIter *i, const char *property, void *data); -int bus_property_append_long(DBusMessageIter *i, const char *property, void *data); - -#define bus_property_append_int bus_property_append_int32 -#define bus_property_append_pid bus_property_append_uint32 -#define bus_property_append_uid bus_property_append_uint32 -#define bus_property_append_gid bus_property_append_uint32 -#define bus_property_append_mode bus_property_append_uint32 -#define bus_property_append_unsigned bus_property_append_uint32 -#define bus_property_append_usec bus_property_append_uint64 - -int bus_property_set_uint64(DBusMessageIter *i, const char *property, void *data); -#define bus_property_set_usec bus_property_set_uint64 - -#define DEFINE_BUS_PROPERTY_APPEND_ENUM(function,name,type) \ - int function(DBusMessageIter *i, const char *property, void *data) { \ - const char *value; \ - type *field = data; \ - \ - assert(i); \ - assert(property); \ - \ - value = strempty(name##_to_string(*field)); \ - \ - if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &value)) \ - return -ENOMEM; \ - \ - return 0; \ - } - -#define DEFINE_BUS_PROPERTY_SET_ENUM(function,name,type) \ - int function(DBusMessageIter *i, const char *property, void *data) { \ - const char *value; \ - type f, *field = data; \ - \ - assert(i); \ - assert(property); \ - \ - dbus_message_iter_get_basic(i, &value); \ - \ - f = name##_from_string(value); \ - if (f < 0) \ - return f; \ - \ - *field = f; \ - return 0; \ - } - -const char *bus_errno_to_dbus(int error); - -DBusMessage* bus_properties_changed_new(const char *path, const char *interface, const char *properties); -DBusMessage* bus_properties_changed_one_new(const char *path, const char *interface, const char *property); - -uint32_t bus_flags_to_events(DBusWatch *bus_watch); -unsigned bus_events_to_flags(uint32_t events); - -int bus_parse_strv(DBusMessage *m, char ***_l); -int bus_parse_strv_iter(DBusMessageIter *iter, char ***_l); - -int bus_append_strv_iter(DBusMessageIter *iter, char **l); - -int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, bool next); - -int generic_print_property(const char *name, DBusMessageIter *iter, bool all); - -void bus_async_unregister_and_exit(DBusConnection *bus, const char *name); - -DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata); - -pid_t bus_get_unix_process_id(DBusConnection *connection, const char *name, DBusError *error); - -bool bus_error_is_no_service(const DBusError *error); -int bus_method_call_with_reply(DBusConnection *bus, - const char *destination, - const char *path, - const char *interface, - const char *method, - DBusMessage **return_reply, - DBusError *return_error, - int first_arg_type, ...); - -const char *bus_message_get_sender_with_fallback(DBusMessage *m); - -void bus_message_unrefp(DBusMessage **reply); - -#define _cleanup_dbus_message_unref_ __attribute__((cleanup(bus_message_unrefp))) diff --git a/src/shared/dbus-loop.c b/src/shared/dbus-loop.c deleted file mode 100644 index da0a00443a..0000000000 --- a/src/shared/dbus-loop.c +++ /dev/null @@ -1,263 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdbool.h> -#include <assert.h> -#include <sys/epoll.h> -#include <string.h> -#include <errno.h> -#include <sys/timerfd.h> -#include <unistd.h> - -#include "dbus-loop.h" -#include "dbus-common.h" -#include "util.h" - -/* Minimal implementation of the dbus loop which integrates all dbus - * events into a single epoll fd which we can triviall integrate with - * other loops. Note that this is not used in the main systemd daemon - * since we run a more elaborate mainloop there. */ - -typedef struct EpollData { - int fd; - void *object; - bool is_timeout:1; - bool fd_is_dupped:1; -} EpollData; - -static dbus_bool_t add_watch(DBusWatch *watch, void *data) { - EpollData *e; - struct epoll_event ev; - - assert(watch); - - e = new0(EpollData, 1); - if (!e) - return FALSE; - - e->fd = dbus_watch_get_unix_fd(watch); - e->object = watch; - e->is_timeout = false; - - zero(ev); - ev.events = bus_flags_to_events(watch); - ev.data.ptr = e; - - if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) { - - if (errno != EEXIST) { - free(e); - return FALSE; - } - - /* Hmm, bloody D-Bus creates multiple watches on the - * same fd. epoll() does not like that. As a dirty - * hack we simply dup() the fd and hence get a second - * one we can safely add to the epoll(). */ - - e->fd = dup(e->fd); - if (e->fd < 0) { - free(e); - return FALSE; - } - - if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) { - close_nointr_nofail(e->fd); - free(e); - return FALSE; - } - - e->fd_is_dupped = true; - } - - dbus_watch_set_data(watch, e, NULL); - - return TRUE; -} - -static void remove_watch(DBusWatch *watch, void *data) { - EpollData *e; - - assert(watch); - - e = dbus_watch_get_data(watch); - if (!e) - return; - - assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0); - - if (e->fd_is_dupped) - close_nointr_nofail(e->fd); - - free(e); -} - -static void toggle_watch(DBusWatch *watch, void *data) { - EpollData *e; - struct epoll_event ev; - - assert(watch); - - e = dbus_watch_get_data(watch); - if (!e) - return; - - zero(ev); - ev.events = bus_flags_to_events(watch); - ev.data.ptr = e; - - assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_MOD, e->fd, &ev) == 0); -} - -static int timeout_arm(EpollData *e) { - struct itimerspec its; - - assert(e); - assert(e->is_timeout); - - zero(its); - - if (dbus_timeout_get_enabled(e->object)) { - timespec_store(&its.it_value, dbus_timeout_get_interval(e->object) * USEC_PER_MSEC); - its.it_interval = its.it_value; - } - - if (timerfd_settime(e->fd, 0, &its, NULL) < 0) - return -errno; - - return 0; -} - -static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) { - EpollData *e; - struct epoll_event ev; - - assert(timeout); - - e = new0(EpollData, 1); - if (!e) - return FALSE; - - e->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); - if (e->fd < 0) - goto fail; - - e->object = timeout; - e->is_timeout = true; - - if (timeout_arm(e) < 0) - goto fail; - - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = e; - - if (epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_ADD, e->fd, &ev) < 0) - goto fail; - - dbus_timeout_set_data(timeout, e, NULL); - - return TRUE; - -fail: - if (e->fd >= 0) - close_nointr_nofail(e->fd); - - free(e); - return FALSE; -} - -static void remove_timeout(DBusTimeout *timeout, void *data) { - EpollData *e; - - assert(timeout); - - e = dbus_timeout_get_data(timeout); - if (!e) - return; - - assert_se(epoll_ctl(PTR_TO_INT(data), EPOLL_CTL_DEL, e->fd, NULL) >= 0); - close_nointr_nofail(e->fd); - free(e); -} - -static void toggle_timeout(DBusTimeout *timeout, void *data) { - EpollData *e; - int r; - - assert(timeout); - - e = dbus_timeout_get_data(timeout); - if (!e) - return; - - r = timeout_arm(e); - if (r < 0) - log_error("Failed to rearm timer: %s", strerror(-r)); -} - -int bus_loop_open(DBusConnection *c) { - int fd; - - assert(c); - - fd = epoll_create1(EPOLL_CLOEXEC); - if (fd < 0) - return -errno; - - if (!dbus_connection_set_watch_functions(c, add_watch, remove_watch, toggle_watch, INT_TO_PTR(fd), NULL) || - !dbus_connection_set_timeout_functions(c, add_timeout, remove_timeout, toggle_timeout, INT_TO_PTR(fd), NULL)) { - close_nointr_nofail(fd); - return -ENOMEM; - } - - return fd; -} - -int bus_loop_dispatch(int fd) { - int n; - struct epoll_event event; - EpollData *d; - - assert(fd >= 0); - - zero(event); - - n = epoll_wait(fd, &event, 1, 0); - if (n < 0) - return errno == EAGAIN || errno == EINTR ? 0 : -errno; - - assert_se(d = event.data.ptr); - - if (d->is_timeout) { - DBusTimeout *t = d->object; - - if (dbus_timeout_get_enabled(t)) - dbus_timeout_handle(t); - } else { - DBusWatch *w = d->object; - - if (dbus_watch_get_enabled(w)) - dbus_watch_handle(w, bus_events_to_flags(event.events)); - } - - return 0; -} diff --git a/src/shared/dbus-loop.h b/src/shared/dbus-loop.h deleted file mode 100644 index a5e768d931..0000000000 --- a/src/shared/dbus-loop.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2011 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 <dbus/dbus.h> - -int bus_loop_open(DBusConnection *c); -int bus_loop_dispatch(int fd); diff --git a/src/shared/def.h b/src/shared/def.h deleted file mode 100644 index 5ba170f965..0000000000 --- a/src/shared/def.h +++ /dev/null @@ -1,35 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 "util.h" - -#define DEFAULT_TIMEOUT_USEC (90*USEC_PER_SEC) -#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC) -#define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC) - -#define DEFAULT_EXIT_USEC (5*USEC_PER_MINUTE) - -#define SYSTEMD_CGROUP_CONTROLLER "name=systemd" - -#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT -#define SIGNALS_IGNORE SIGKILL,SIGPIPE diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c deleted file mode 100644 index b0ac02d461..0000000000 --- a/src/shared/dev-setup.c +++ /dev/null @@ -1,78 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010-2012 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 <errno.h> -#include <sys/stat.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <unistd.h> - -#include "dev-setup.h" -#include "log.h" -#include "macro.h" -#include "util.h" -#include "label.h" - -static int symlink_and_label(const char *old_path, const char *new_path) { - int r; - - assert(old_path); - assert(new_path); - - r = label_context_set(new_path, S_IFLNK); - if (r < 0) - return r; - - if (symlink(old_path, new_path) < 0) - r = -errno; - - label_context_clear(); - - return r; -} - -void dev_setup(const char *prefix) { - const char *j, *k; - - static const char symlinks[] = - "/proc/kcore\0" "/dev/core\0" - "/proc/self/fd\0" "/dev/fd\0" - "/proc/self/fd/0\0" "/dev/stdin\0" - "/proc/self/fd/1\0" "/dev/stdout\0" - "/proc/self/fd/2\0" "/dev/stderr\0"; - - NULSTR_FOREACH_PAIR(j, k, symlinks) { - - if (prefix) { - char *linkname; - - if (asprintf(&linkname, "%s/%s", prefix, k) < 0) { - log_oom(); - break; - } - - symlink_and_label(j, linkname); - free(linkname); - } else - symlink_and_label(j, k); - } -} diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h deleted file mode 100644 index 320c0b30ba..0000000000 --- a/src/shared/dev-setup.h +++ /dev/null @@ -1,24 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010-2012 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/>. -***/ - -void dev_setup(const char *pathprefix); diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c deleted file mode 100644 index 45131f2b2a..0000000000 --- a/src/shared/exit-status.c +++ /dev/null @@ -1,192 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <stdlib.h> -#include <sys/wait.h> - -#include "exit-status.h" -#include "set.h" -#include "macro.h" - -const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { - - /* We cast to int here, so that -Wenum doesn't complain that - * EXIT_SUCCESS/EXIT_FAILURE aren't in the enum */ - - switch ((int) status) { - - case EXIT_SUCCESS: - return "SUCCESS"; - - case EXIT_FAILURE: - return "FAILURE"; - } - - - if (level == EXIT_STATUS_SYSTEMD || level == EXIT_STATUS_LSB) { - switch ((int) status) { - - case EXIT_CHDIR: - return "CHDIR"; - - case EXIT_NICE: - return "NICE"; - - case EXIT_FDS: - return "FDS"; - - case EXIT_EXEC: - return "EXEC"; - - case EXIT_MEMORY: - return "MEMORY"; - - case EXIT_LIMITS: - return "LIMITS"; - - case EXIT_OOM_ADJUST: - return "OOM_ADJUST"; - - case EXIT_SIGNAL_MASK: - return "SIGNAL_MASK"; - - case EXIT_STDIN: - return "STDIN"; - - case EXIT_STDOUT: - return "STDOUT"; - - case EXIT_CHROOT: - return "CHROOT"; - - case EXIT_IOPRIO: - return "IOPRIO"; - - case EXIT_TIMERSLACK: - return "TIMERSLACK"; - - case EXIT_SECUREBITS: - return "SECUREBITS"; - - case EXIT_SETSCHEDULER: - return "SETSCHEDULER"; - - case EXIT_CPUAFFINITY: - return "CPUAFFINITY"; - - case EXIT_GROUP: - return "GROUP"; - - case EXIT_USER: - return "USER"; - - case EXIT_CAPABILITIES: - return "CAPABILITIES"; - - case EXIT_CGROUP: - return "CGROUP"; - - case EXIT_SETSID: - return "SETSID"; - - case EXIT_CONFIRM: - return "CONFIRM"; - - case EXIT_STDERR: - return "STDERR"; - - case EXIT_TCPWRAP: - return "TCPWRAP"; - - case EXIT_PAM: - return "PAM"; - - case EXIT_NETWORK: - return "NETWORK"; - - case EXIT_NAMESPACE: - return "NAMESPACE"; - - case EXIT_NO_NEW_PRIVILEGES: - return "NO_NEW_PRIVILEGES"; - - case EXIT_SECCOMP: - return "SECCOMP"; - } - } - - if (level == EXIT_STATUS_LSB) { - switch ((int) status) { - - case EXIT_INVALIDARGUMENT: - return "INVALIDARGUMENT"; - - case EXIT_NOTIMPLEMENTED: - return "NOTIMPLEMENTED"; - - case EXIT_NOPERMISSION: - return "NOPERMISSION"; - - case EXIT_NOTINSTALLED: - return "NOTINSSTALLED"; - - case EXIT_NOTCONFIGURED: - return "NOTCONFIGURED"; - - case EXIT_NOTRUNNING: - return "NOTRUNNING"; - } - } - - return NULL; -} - - -bool is_clean_exit(int code, int status, ExitStatusSet *success_status) { - - if (code == CLD_EXITED) - return status == 0 || - (success_status && - set_contains(success_status->code, INT_TO_PTR(status))); - - /* If a daemon does not implement handlers for some of the - * signals that's not considered an unclean shutdown */ - if (code == CLD_KILLED) - return - status == SIGHUP || - status == SIGINT || - status == SIGTERM || - status == SIGPIPE || - (success_status && - set_contains(success_status->signal, INT_TO_PTR(status))); - - return false; -} - -bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) { - - if (is_clean_exit(code, status, success_status)) - return true; - - return - code == CLD_EXITED && - (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED); -} diff --git a/src/shared/exit-status.h b/src/shared/exit-status.h deleted file mode 100644 index d3b548fc96..0000000000 --- a/src/shared/exit-status.h +++ /dev/null @@ -1,88 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdbool.h> -#include "set.h" -typedef enum ExitStatus { - /* EXIT_SUCCESS defined by libc */ - /* EXIT_FAILURE defined by libc */ - EXIT_INVALIDARGUMENT = 2, - EXIT_NOTIMPLEMENTED = 3, - EXIT_NOPERMISSION = 4, - EXIT_NOTINSTALLED = 5, - EXIT_NOTCONFIGURED = 6, - EXIT_NOTRUNNING = 7, - - /* The LSB suggests that error codes >= 200 are "reserved". We - * use them here under the assumption that they hence are - * unused by init scripts. - * - * http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */ - - EXIT_CHDIR = 200, - EXIT_NICE, - EXIT_FDS, - EXIT_EXEC, - EXIT_MEMORY, - EXIT_LIMITS, - EXIT_OOM_ADJUST, - EXIT_SIGNAL_MASK, - EXIT_STDIN, - EXIT_STDOUT, - EXIT_CHROOT, /* 210 */ - EXIT_IOPRIO, - EXIT_TIMERSLACK, - EXIT_SECUREBITS, - EXIT_SETSCHEDULER, - EXIT_CPUAFFINITY, - EXIT_GROUP, - EXIT_USER, - EXIT_CAPABILITIES, - EXIT_CGROUP, - EXIT_SETSID, /* 220 */ - EXIT_CONFIRM, - EXIT_STDERR, - EXIT_TCPWRAP, - EXIT_PAM, - EXIT_NETWORK, - EXIT_NAMESPACE, - EXIT_NO_NEW_PRIVILEGES, - EXIT_SECCOMP -} ExitStatus; - -typedef enum ExitStatusLevel { - EXIT_STATUS_MINIMAL, - EXIT_STATUS_SYSTEMD, - EXIT_STATUS_LSB, - EXIT_STATUS_FULL = EXIT_STATUS_LSB -} ExitStatusLevel; - -typedef struct ExitStatusSet { - Set *code; - Set *signal; -} ExitStatusSet; - -const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level); - -bool is_clean_exit(int code, int status, ExitStatusSet *success_status); -bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status); diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c deleted file mode 100644 index dcfbb67228..0000000000 --- a/src/shared/hashmap.c +++ /dev/null @@ -1,835 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "util.h" -#include "hashmap.h" -#include "macro.h" - -#define NBUCKETS 127 - -struct hashmap_entry { - const void *key; - void *value; - struct hashmap_entry *bucket_next, *bucket_previous; - struct hashmap_entry *iterate_next, *iterate_previous; -}; - -struct Hashmap { - hash_func_t hash_func; - compare_func_t compare_func; - - struct hashmap_entry *iterate_list_head, *iterate_list_tail; - unsigned n_entries; - - bool from_pool; -}; - -#define BY_HASH(h) ((struct hashmap_entry**) ((uint8_t*) (h) + ALIGN(sizeof(Hashmap)))) - -struct pool { - struct pool *next; - unsigned n_tiles; - unsigned n_used; -}; - -static struct pool *first_hashmap_pool = NULL; -static void *first_hashmap_tile = NULL; - -static struct pool *first_entry_pool = NULL; -static void *first_entry_tile = NULL; - -static void* allocate_tile(struct pool **first_pool, void **first_tile, size_t tile_size) { - unsigned i; - - if (*first_tile) { - void *r; - - r = *first_tile; - *first_tile = * (void**) (*first_tile); - return r; - } - - if (_unlikely_(!*first_pool) || _unlikely_((*first_pool)->n_used >= (*first_pool)->n_tiles)) { - unsigned n; - size_t size; - struct pool *p; - - n = *first_pool ? (*first_pool)->n_tiles : 0; - n = MAX(512U, n * 2); - size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*tile_size); - n = (size - ALIGN(sizeof(struct pool))) / tile_size; - - p = malloc(size); - if (!p) - return NULL; - - p->next = *first_pool; - p->n_tiles = n; - p->n_used = 0; - - *first_pool = p; - } - - i = (*first_pool)->n_used++; - - return ((uint8_t*) (*first_pool)) + ALIGN(sizeof(struct pool)) + i*tile_size; -} - -static void deallocate_tile(void **first_tile, void *p) { - * (void**) p = *first_tile; - *first_tile = p; -} - -#ifndef __OPTIMIZE__ - -static void drop_pool(struct pool *p) { - while (p) { - struct pool *n; - n = p->next; - free(p); - p = n; - } -} - -__attribute__((destructor)) static void cleanup_pool(void) { - /* Be nice to valgrind */ - - drop_pool(first_hashmap_pool); - drop_pool(first_entry_pool); -} - -#endif - -unsigned string_hash_func(const void *p) { - unsigned hash = 5381; - const signed char *c; - - /* DJB's hash function */ - - for (c = p; *c; c++) - hash = (hash << 5) + hash + (unsigned) *c; - - return hash; -} - -int string_compare_func(const void *a, const void *b) { - return strcmp(a, b); -} - -unsigned trivial_hash_func(const void *p) { - return PTR_TO_UINT(p); -} - -int trivial_compare_func(const void *a, const void *b) { - return a < b ? -1 : (a > b ? 1 : 0); -} - -unsigned uint64_hash_func(const void *p) { - uint64_t u; - - assert_cc(sizeof(uint64_t) == 2*sizeof(unsigned)); - - u = *(const uint64_t*) p; - - return (unsigned) ((u >> 32) ^ u); -} - -int uint64_compare_func(const void *_a, const void *_b) { - uint64_t a, b; - - a = *(const uint64_t*) _a; - b = *(const uint64_t*) _b; - - return a < b ? -1 : (a > b ? 1 : 0); -} - -Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func) { - bool b; - Hashmap *h; - size_t size; - - b = is_main_thread(); - - size = ALIGN(sizeof(Hashmap)) + NBUCKETS * sizeof(struct hashmap_entry*); - - if (b) { - h = allocate_tile(&first_hashmap_pool, &first_hashmap_tile, size); - if (!h) - return NULL; - - memset(h, 0, size); - } else { - h = malloc0(size); - - if (!h) - return NULL; - } - - h->hash_func = hash_func ? hash_func : trivial_hash_func; - h->compare_func = compare_func ? compare_func : trivial_compare_func; - - h->n_entries = 0; - h->iterate_list_head = h->iterate_list_tail = NULL; - - h->from_pool = b; - - return h; -} - -int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func) { - assert(h); - - if (*h) - return 0; - - if (!(*h = hashmap_new(hash_func, compare_func))) - return -ENOMEM; - - return 0; -} - -static void link_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { - assert(h); - assert(e); - - /* Insert into hash table */ - e->bucket_next = BY_HASH(h)[hash]; - e->bucket_previous = NULL; - if (BY_HASH(h)[hash]) - BY_HASH(h)[hash]->bucket_previous = e; - BY_HASH(h)[hash] = e; - - /* Insert into iteration list */ - e->iterate_previous = h->iterate_list_tail; - e->iterate_next = NULL; - if (h->iterate_list_tail) { - assert(h->iterate_list_head); - h->iterate_list_tail->iterate_next = e; - } else { - assert(!h->iterate_list_head); - h->iterate_list_head = e; - } - h->iterate_list_tail = e; - - h->n_entries++; - assert(h->n_entries >= 1); -} - -static void unlink_entry(Hashmap *h, struct hashmap_entry *e, unsigned hash) { - assert(h); - assert(e); - - /* Remove from iteration list */ - if (e->iterate_next) - e->iterate_next->iterate_previous = e->iterate_previous; - else - h->iterate_list_tail = e->iterate_previous; - - if (e->iterate_previous) - e->iterate_previous->iterate_next = e->iterate_next; - else - h->iterate_list_head = e->iterate_next; - - /* Remove from hash table bucket list */ - if (e->bucket_next) - e->bucket_next->bucket_previous = e->bucket_previous; - - if (e->bucket_previous) - e->bucket_previous->bucket_next = e->bucket_next; - else - BY_HASH(h)[hash] = e->bucket_next; - - assert(h->n_entries >= 1); - h->n_entries--; -} - -static void remove_entry(Hashmap *h, struct hashmap_entry *e) { - unsigned hash; - - assert(h); - assert(e); - - hash = h->hash_func(e->key) % NBUCKETS; - - unlink_entry(h, e, hash); - - if (h->from_pool) - deallocate_tile(&first_entry_tile, e); - else - free(e); -} - -void hashmap_free(Hashmap*h) { - - /* Free the hashmap, but nothing in it */ - - if (!h) - return; - - hashmap_clear(h); - - if (h->from_pool) - deallocate_tile(&first_hashmap_tile, h); - else - free(h); -} - -void hashmap_free_free(Hashmap *h) { - - /* Free the hashmap and all data objects in it, but not the - * keys */ - - if (!h) - return; - - hashmap_clear_free(h); - hashmap_free(h); -} - -void hashmap_clear(Hashmap *h) { - if (!h) - return; - - while (h->iterate_list_head) - remove_entry(h, h->iterate_list_head); -} - -void hashmap_clear_free(Hashmap *h) { - void *p; - - if (!h) - return; - - while ((p = hashmap_steal_first(h))) - free(p); -} - -static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { - struct hashmap_entry *e; - assert(h); - assert(hash < NBUCKETS); - - for (e = BY_HASH(h)[hash]; e; e = e->bucket_next) - if (h->compare_func(e->key, key) == 0) - return e; - - return NULL; -} - -int hashmap_put(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - assert(h); - - hash = h->hash_func(key) % NBUCKETS; - - e = hash_scan(h, hash, key); - if (e) { - - if (e->value == value) - return 0; - - return -EEXIST; - } - - if (h->from_pool) - e = allocate_tile(&first_entry_pool, &first_entry_tile, sizeof(struct hashmap_entry)); - else - e = new(struct hashmap_entry, 1); - - if (!e) - return -ENOMEM; - - e->key = key; - e->value = value; - - link_entry(h, e, hash); - - return 1; -} - -int hashmap_replace(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - assert(h); - - hash = h->hash_func(key) % NBUCKETS; - e = hash_scan(h, hash, key); - if (e) { - e->key = key; - e->value = value; - return 0; - } - - return hashmap_put(h, key, value); -} - -int hashmap_update(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - assert(h); - - hash = h->hash_func(key) % NBUCKETS; - e = hash_scan(h, hash, key); - if (!e) - return -ENOENT; - - e->value = value; - return 0; -} - -void* hashmap_get(Hashmap *h, const void *key) { - unsigned hash; - struct hashmap_entry *e; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - e = hash_scan(h, hash, key); - if (!e) - return NULL; - - return e->value; -} - -void* hashmap_get2(Hashmap *h, const void *key, void **key2) { - unsigned hash; - struct hashmap_entry *e; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - e = hash_scan(h, hash, key); - if (!e) - return NULL; - - if (key2) - *key2 = (void*) e->key; - - return e->value; -} - -bool hashmap_contains(Hashmap *h, const void *key) { - unsigned hash; - - if (!h) - return false; - - hash = h->hash_func(key) % NBUCKETS; - - if (!hash_scan(h, hash, key)) - return false; - - return true; -} - -void* hashmap_remove(Hashmap *h, const void *key) { - struct hashmap_entry *e; - unsigned hash; - void *data; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - - if (!(e = hash_scan(h, hash, key))) - return NULL; - - data = e->value; - remove_entry(h, e); - - return data; -} - -int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) { - struct hashmap_entry *e; - unsigned old_hash, new_hash; - - if (!h) - return -ENOENT; - - old_hash = h->hash_func(old_key) % NBUCKETS; - if (!(e = hash_scan(h, old_hash, old_key))) - return -ENOENT; - - new_hash = h->hash_func(new_key) % NBUCKETS; - if (hash_scan(h, new_hash, new_key)) - return -EEXIST; - - unlink_entry(h, e, old_hash); - - e->key = new_key; - e->value = value; - - link_entry(h, e, new_hash); - - return 0; -} - -int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) { - struct hashmap_entry *e, *k; - unsigned old_hash, new_hash; - - if (!h) - return -ENOENT; - - old_hash = h->hash_func(old_key) % NBUCKETS; - if (!(e = hash_scan(h, old_hash, old_key))) - return -ENOENT; - - new_hash = h->hash_func(new_key) % NBUCKETS; - - if ((k = hash_scan(h, new_hash, new_key))) - if (e != k) - remove_entry(h, k); - - unlink_entry(h, e, old_hash); - - e->key = new_key; - e->value = value; - - link_entry(h, e, new_hash); - - return 0; -} - -void* hashmap_remove_value(Hashmap *h, const void *key, void *value) { - struct hashmap_entry *e; - unsigned hash; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - - if (!(e = hash_scan(h, hash, key))) - return NULL; - - if (e->value != value) - return NULL; - - remove_entry(h, e); - - return value; -} - -void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) { - struct hashmap_entry *e; - - assert(i); - - if (!h) - goto at_end; - - if (*i == ITERATOR_LAST) - goto at_end; - - if (*i == ITERATOR_FIRST && !h->iterate_list_head) - goto at_end; - - e = *i == ITERATOR_FIRST ? h->iterate_list_head : (struct hashmap_entry*) *i; - - if (e->iterate_next) - *i = (Iterator) e->iterate_next; - else - *i = ITERATOR_LAST; - - if (key) - *key = e->key; - - return e->value; - -at_end: - *i = ITERATOR_LAST; - - if (key) - *key = NULL; - - return NULL; -} - -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key) { - struct hashmap_entry *e; - - assert(i); - - if (!h) - goto at_beginning; - - if (*i == ITERATOR_FIRST) - goto at_beginning; - - if (*i == ITERATOR_LAST && !h->iterate_list_tail) - goto at_beginning; - - e = *i == ITERATOR_LAST ? h->iterate_list_tail : (struct hashmap_entry*) *i; - - if (e->iterate_previous) - *i = (Iterator) e->iterate_previous; - else - *i = ITERATOR_FIRST; - - if (key) - *key = e->key; - - return e->value; - -at_beginning: - *i = ITERATOR_FIRST; - - if (key) - *key = NULL; - - return NULL; -} - -void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i) { - unsigned hash; - struct hashmap_entry *e; - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - - if (!(e = hash_scan(h, hash, key))) - return NULL; - - *i = (Iterator) e; - - return e->value; -} - -void* hashmap_first(Hashmap *h) { - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - return h->iterate_list_head->value; -} - -void* hashmap_first_key(Hashmap *h) { - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - return (void*) h->iterate_list_head->key; -} - -void* hashmap_last(Hashmap *h) { - - if (!h) - return NULL; - - if (!h->iterate_list_tail) - return NULL; - - return h->iterate_list_tail->value; -} - -void* hashmap_steal_first(Hashmap *h) { - void *data; - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - data = h->iterate_list_head->value; - remove_entry(h, h->iterate_list_head); - - return data; -} - -void* hashmap_steal_first_key(Hashmap *h) { - void *key; - - if (!h) - return NULL; - - if (!h->iterate_list_head) - return NULL; - - key = (void*) h->iterate_list_head->key; - remove_entry(h, h->iterate_list_head); - - return key; -} - -unsigned hashmap_size(Hashmap *h) { - - if (!h) - return 0; - - return h->n_entries; -} - -bool hashmap_isempty(Hashmap *h) { - - if (!h) - return true; - - return h->n_entries == 0; -} - -int hashmap_merge(Hashmap *h, Hashmap *other) { - struct hashmap_entry *e; - - assert(h); - - if (!other) - return 0; - - for (e = other->iterate_list_head; e; e = e->iterate_next) { - int r; - - if ((r = hashmap_put(h, e->key, e->value)) < 0) - if (r != -EEXIST) - return r; - } - - return 0; -} - -void hashmap_move(Hashmap *h, Hashmap *other) { - struct hashmap_entry *e, *n; - - assert(h); - - /* The same as hashmap_merge(), but every new item from other - * is moved to h. This function is guaranteed to succeed. */ - - if (!other) - return; - - for (e = other->iterate_list_head; e; e = n) { - unsigned h_hash, other_hash; - - n = e->iterate_next; - - h_hash = h->hash_func(e->key) % NBUCKETS; - - if (hash_scan(h, h_hash, e->key)) - continue; - - other_hash = other->hash_func(e->key) % NBUCKETS; - - unlink_entry(other, e, other_hash); - link_entry(h, e, h_hash); - } -} - -int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { - unsigned h_hash, other_hash; - struct hashmap_entry *e; - - if (!other) - return 0; - - assert(h); - - h_hash = h->hash_func(key) % NBUCKETS; - if (hash_scan(h, h_hash, key)) - return -EEXIST; - - other_hash = other->hash_func(key) % NBUCKETS; - if (!(e = hash_scan(other, other_hash, key))) - return -ENOENT; - - unlink_entry(other, e, other_hash); - link_entry(h, e, h_hash); - - return 0; -} - -Hashmap *hashmap_copy(Hashmap *h) { - Hashmap *copy; - - assert(h); - - if (!(copy = hashmap_new(h->hash_func, h->compare_func))) - return NULL; - - if (hashmap_merge(copy, h) < 0) { - hashmap_free(copy); - return NULL; - } - - return copy; -} - -char **hashmap_get_strv(Hashmap *h) { - char **sv; - Iterator it; - char *item; - int n; - - sv = new(char*, h->n_entries+1); - if (!sv) - return NULL; - - n = 0; - HASHMAP_FOREACH(item, h, it) - sv[n++] = item; - sv[n] = NULL; - - return sv; -} - -void *hashmap_next(Hashmap *h, const void *key) { - unsigned hash; - struct hashmap_entry *e; - - assert(h); - assert(key); - - if (!h) - return NULL; - - hash = h->hash_func(key) % NBUCKETS; - e = hash_scan(h, hash, key); - if (!e) - return NULL; - - e = e->iterate_next; - if (!e) - return NULL; - - return e->value; -} diff --git a/src/shared/hashmap.h b/src/shared/hashmap.h deleted file mode 100644 index 6fd71cf519..0000000000 --- a/src/shared/hashmap.h +++ /dev/null @@ -1,98 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdbool.h> - -/* Pretty straightforward hash table implementation. As a minor - * optimization a NULL hashmap object will be treated as empty hashmap - * for all read operations. That way it is not necessary to - * instantiate an object for each Hashmap use. */ - -typedef struct Hashmap Hashmap; -typedef struct _IteratorStruct _IteratorStruct; -typedef _IteratorStruct* Iterator; - -#define ITERATOR_FIRST ((Iterator) 0) -#define ITERATOR_LAST ((Iterator) -1) - -typedef unsigned (*hash_func_t)(const void *p); -typedef int (*compare_func_t)(const void *a, const void *b); - -unsigned string_hash_func(const void *p); -int string_compare_func(const void *a, const void *b); - -unsigned trivial_hash_func(const void *p); -int trivial_compare_func(const void *a, const void *b); - -unsigned uint64_hash_func(const void *p); -int uint64_compare_func(const void *a, const void *b); - -Hashmap *hashmap_new(hash_func_t hash_func, compare_func_t compare_func); -void hashmap_free(Hashmap *h); -void hashmap_free_free(Hashmap *h); -Hashmap *hashmap_copy(Hashmap *h); -int hashmap_ensure_allocated(Hashmap **h, hash_func_t hash_func, compare_func_t compare_func); - -int hashmap_put(Hashmap *h, const void *key, void *value); -int hashmap_update(Hashmap *h, const void *key, void *value); -int hashmap_replace(Hashmap *h, const void *key, void *value); -void* hashmap_get(Hashmap *h, const void *key); -void* hashmap_get2(Hashmap *h, const void *key, void **rkey); -bool hashmap_contains(Hashmap *h, const void *key); -void* hashmap_remove(Hashmap *h, const void *key); -void* hashmap_remove_value(Hashmap *h, const void *key, void *value); -int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); -int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); - -int hashmap_merge(Hashmap *h, Hashmap *other); -void hashmap_move(Hashmap *h, Hashmap *other); -int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key); - -unsigned hashmap_size(Hashmap *h); -bool hashmap_isempty(Hashmap *h); - -void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key); -void *hashmap_iterate_backwards(Hashmap *h, Iterator *i, const void **key); -void *hashmap_iterate_skip(Hashmap *h, const void *key, Iterator *i); - -void hashmap_clear(Hashmap *h); -void hashmap_clear_free(Hashmap *h); - -void *hashmap_steal_first(Hashmap *h); -void *hashmap_steal_first_key(Hashmap *h); -void* hashmap_first(Hashmap *h); -void* hashmap_first_key(Hashmap *h); -void* hashmap_last(Hashmap *h); - -void *hashmap_next(Hashmap *h, const void *key); - -char **hashmap_get_strv(Hashmap *h); - -#define HASHMAP_FOREACH(e, h, i) \ - for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); (e); (e) = hashmap_iterate((h), &(i), NULL)) - -#define HASHMAP_FOREACH_KEY(e, k, h, i) \ - for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(i), (const void**) &(k))) - -#define HASHMAP_FOREACH_BACKWARDS(e, h, i) \ - for ((i) = ITERATOR_LAST, (e) = hashmap_iterate_backwards((h), &(i), NULL); (e); (e) = hashmap_iterate_backwards((h), &(i), NULL)) diff --git a/src/shared/hwclock.c b/src/shared/hwclock.c deleted file mode 100644 index f9adf0369e..0000000000 --- a/src/shared/hwclock.c +++ /dev/null @@ -1,240 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010-2012 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <signal.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <stdarg.h> -#include <ctype.h> -#include <sys/prctl.h> -#include <sys/time.h> -#include <linux/rtc.h> - -#include "macro.h" -#include "util.h" -#include "log.h" -#include "strv.h" -#include "hwclock.h" - -static int rtc_open(int flags) { - int fd; - DIR *d; - - /* First, we try to make use of the /dev/rtc symlink. If that - * doesn't exist, we open the first RTC which has hctosys=1 - * set. If we don't find any we just take the first RTC that - * exists at all. */ - - fd = open("/dev/rtc", flags); - if (fd >= 0) - return fd; - - d = opendir("/sys/class/rtc"); - if (!d) - goto fallback; - - for (;;) { - char *p, *v; - struct dirent *de; - union dirent_storage buf; - int r; - - r = readdir_r(d, &buf.de, &de); - if (r != 0) - goto fallback; - - if (!de) - goto fallback; - - if (ignore_file(de->d_name)) - continue; - - p = strjoin("/sys/class/rtc/", de->d_name, "/hctosys", NULL); - if (!p) { - closedir(d); - return -ENOMEM; - } - - r = read_one_line_file(p, &v); - free(p); - - if (r < 0) - continue; - - r = parse_boolean(v); - free(v); - - if (r <= 0) - continue; - - p = strappend("/dev/", de->d_name); - if (!p) { - closedir(d); - return -ENOMEM; - } - - fd = open(p, flags); - free(p); - - if (fd >= 0) { - closedir(d); - return fd; - } - } - -fallback: - if (d) - closedir(d); - - fd = open("/dev/rtc0", flags); - if (fd < 0) - return -errno; - - return fd; -} - -int hwclock_get_time(struct tm *tm) { - int fd; - int err = 0; - - assert(tm); - - fd = rtc_open(O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - /* This leaves the timezone fields of struct tm - * uninitialized! */ - if (ioctl(fd, RTC_RD_TIME, tm) < 0) - err = -errno; - - /* We don't know daylight saving, so we reset this in order not - * to confused mktime(). */ - tm->tm_isdst = -1; - - close_nointr_nofail(fd); - - return err; -} - -int hwclock_set_time(const struct tm *tm) { - int fd; - int err = 0; - - assert(tm); - - fd = rtc_open(O_RDONLY|O_CLOEXEC); - if (fd < 0) - return -errno; - - if (ioctl(fd, RTC_SET_TIME, tm) < 0) - err = -errno; - - close_nointr_nofail(fd); - - return err; -} - -int hwclock_is_localtime(void) { - FILE *f; - bool local = false; - - /* - * The third line of adjtime is "UTC" or "LOCAL" or nothing. - * # /etc/adjtime - * 0.0 0 0 - * 0 - * UTC - */ - f = fopen("/etc/adjtime", "re"); - if (f) { - char line[LINE_MAX]; - bool b; - - b = fgets(line, sizeof(line), f) && - fgets(line, sizeof(line), f) && - fgets(line, sizeof(line), f); - - fclose(f); - - if (!b) - return -EIO; - - truncate_nl(line); - local = streq(line, "LOCAL"); - - } else if (errno != -ENOENT) - return -errno; - - return local; -} - -int hwclock_set_timezone(int *min) { - const struct timeval *tv_null = NULL; - struct timespec ts; - struct tm *tm; - int minutesdelta; - struct timezone tz; - - assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); - assert_se(tm = localtime(&ts.tv_sec)); - minutesdelta = tm->tm_gmtoff / 60; - - tz.tz_minuteswest = -minutesdelta; - tz.tz_dsttime = 0; /* DST_NONE*/ - - /* - * If the hardware clock does not run in UTC, but in local time: - * The very first time we set the kernel's timezone, it will warp - * the clock so that it runs in UTC instead of local time. - */ - if (settimeofday(tv_null, &tz) < 0) - return -errno; - if (min) - *min = minutesdelta; - return 0; -} - -int hwclock_reset_timezone(void) { - const struct timeval *tv_null = NULL; - struct timezone tz; - - tz.tz_minuteswest = 0; - tz.tz_dsttime = 0; /* DST_NONE*/ - - /* - * The very first time we set the kernel's timezone, it will warp - * the clock. Do a dummy call here, so the time warping is sealed - * and we set only the time zone with next call. - */ - if (settimeofday(tv_null, &tz) < 0) - return -errno; - - return 0; -} diff --git a/src/shared/hwclock.h b/src/shared/hwclock.h deleted file mode 100644 index b2bdc78f0c..0000000000 --- a/src/shared/hwclock.h +++ /dev/null @@ -1,31 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foohwclockhfoo -#define foohwclockhfoo - -/*** - This file is part of systemd. - - Copyright 2010-2012 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/>. -***/ - -int hwclock_is_localtime(void); -int hwclock_set_timezone(int *min); -int hwclock_reset_timezone(void); -int hwclock_get_time(struct tm *tm); -int hwclock_set_time(const struct tm *tm); - -#endif diff --git a/src/shared/install.c b/src/shared/install.c deleted file mode 100644 index a9d75f3b7c..0000000000 --- a/src/shared/install.c +++ /dev/null @@ -1,2059 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 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 <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <string.h> -#include <fnmatch.h> - -#include "util.h" -#include "mkdir.h" -#include "hashmap.h" -#include "set.h" -#include "path-util.h" -#include "path-lookup.h" -#include "strv.h" -#include "unit-name.h" -#include "install.h" -#include "conf-parser.h" -#include "conf-files.h" - -typedef struct { - char *name; - char *path; - - char **aliases; - char **wanted_by; - char **required_by; -} InstallInfo; - -typedef struct { - Hashmap *will_install; - Hashmap *have_installed; -} InstallContext; - -static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope) { - assert(paths); - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(*paths); - - return lookup_paths_init(paths, - scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER, - scope == UNIT_FILE_USER, - NULL, NULL, NULL); -} - -static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { - char *p = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(ret); - - switch (scope) { - - case UNIT_FILE_SYSTEM: - - if (root_dir && runtime) - asprintf(&p, "%s/run/systemd/system", root_dir); - else if (runtime) - p = strdup("/run/systemd/system"); - else if (root_dir) - asprintf(&p, "%s/%s", root_dir, SYSTEM_CONFIG_UNIT_PATH); - else - p = strdup(SYSTEM_CONFIG_UNIT_PATH); - - break; - - case UNIT_FILE_GLOBAL: - - if (root_dir) - return -EINVAL; - - if (runtime) - p = strdup("/run/systemd/user"); - else - p = strdup(USER_CONFIG_UNIT_PATH); - break; - - case UNIT_FILE_USER: - - if (root_dir || runtime) - return -EINVAL; - - r = user_config_home(&p); - if (r <= 0) - return r < 0 ? r : -ENOENT; - - break; - - default: - assert_not_reached("Bad scope"); - } - - if (!p) - return -ENOMEM; - - *ret = p; - return 0; -} - -static int add_file_change( - UnitFileChange **changes, - unsigned *n_changes, - UnitFileChangeType type, - const char *path, - const char *source) { - - UnitFileChange *c; - unsigned i; - - assert(path); - assert(!changes == !n_changes); - - if (!changes) - return 0; - - c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); - if (!c) - return -ENOMEM; - - *changes = c; - i = *n_changes; - - c[i].type = type; - c[i].path = strdup(path); - if (!c[i].path) - return -ENOMEM; - - if (source) { - c[i].source = strdup(source); - if (!c[i].source) { - free(c[i].path); - return -ENOMEM; - } - } else - c[i].source = NULL; - - *n_changes = i+1; - return 0; -} - -static int mark_symlink_for_removal( - Set **remove_symlinks_to, - const char *p) { - - char *n; - int r; - - assert(p); - - r = set_ensure_allocated(remove_symlinks_to, string_hash_func, string_compare_func); - if (r < 0) - return r; - - n = strdup(p); - if (!n) - return -ENOMEM; - - path_kill_slashes(n); - - r = set_put(*remove_symlinks_to, n); - if (r < 0) { - free(n); - return r == -EEXIST ? 0 : r; - } - - return 0; -} - -static int remove_marked_symlinks_fd( - Set *remove_symlinks_to, - int fd, - const char *path, - const char *config_path, - bool *deleted, - UnitFileChange **changes, - unsigned *n_changes, - char** files) { - - int r = 0; - DIR *d; - - assert(remove_symlinks_to); - assert(fd >= 0); - assert(path); - assert(config_path); - assert(deleted); - - d = fdopendir(fd); - if (!d) { - close_nointr_nofail(fd); - return -errno; - } - - rewinddir(d); - - for (;;) { - struct dirent *de; - union dirent_storage buf; - int k; - - k = readdir_r(d, &buf.de, &de); - if (k != 0) { - r = -errno; - break; - } - - if (!de) - break; - - if (ignore_file(de->d_name)) - continue; - - dirent_ensure_type(d, de); - - if (de->d_type == DT_DIR) { - int nfd, q; - char *p; - - nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (nfd < 0) { - if (errno == ENOENT) - continue; - - if (r == 0) - r = -errno; - continue; - } - - p = path_make_absolute(de->d_name, path); - if (!p) { - close_nointr_nofail(nfd); - r = -ENOMEM; - break; - } - - /* This will close nfd, regardless whether it succeeds or not */ - q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, files); - free(p); - - if (r == 0) - r = q; - - } else if (de->d_type == DT_LNK) { - char *p, *dest; - int q; - bool found; - - p = path_make_absolute(de->d_name, path); - if (!p) { - r = -ENOMEM; - break; - } - - q = readlink_and_canonicalize(p, &dest); - if (q < 0) { - free(p); - - if (q == -ENOENT) - continue; - - if (r == 0) - r = q; - continue; - } - - found = - set_get(remove_symlinks_to, dest) || - set_get(remove_symlinks_to, path_get_file_name(dest)); - - if (unit_name_is_instance(p)) - found = found && strv_contains(files, path_get_file_name(p)); - - if (found) { - - if (unlink(p) < 0 && errno != ENOENT) { - - if (r == 0) - r = -errno; - } else { - rmdir_parents(p, config_path); - path_kill_slashes(p); - - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); - - if (!set_get(remove_symlinks_to, p)) { - - q = mark_symlink_for_removal(&remove_symlinks_to, p); - if (q < 0) { - if (r == 0) - r = q; - } else - *deleted = true; - } - } - } - - free(p); - free(dest); - } - } - - closedir(d); - - return r; -} - -static int remove_marked_symlinks( - Set *remove_symlinks_to, - const char *config_path, - UnitFileChange **changes, - unsigned *n_changes, - char** files) { - - int fd, r = 0; - bool deleted; - - assert(config_path); - - if (set_size(remove_symlinks_to) <= 0) - return 0; - - fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (fd < 0) - return -errno; - - do { - int q, cfd; - deleted = false; - - cfd = dup(fd); - if (cfd < 0) { - r = -errno; - break; - } - - /* This takes possession of cfd and closes it */ - q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, files); - if (r == 0) - r = q; - } while (deleted); - - close_nointr_nofail(fd); - - return r; -} - -static int find_symlinks_fd( - const char *name, - int fd, - const char *path, - const char *config_path, - bool *same_name_link) { - - int r = 0; - DIR *d; - - assert(name); - assert(fd >= 0); - assert(path); - assert(config_path); - assert(same_name_link); - - d = fdopendir(fd); - if (!d) { - close_nointr_nofail(fd); - return -errno; - } - - for (;;) { - int k; - struct dirent *de; - union dirent_storage buf; - - k = readdir_r(d, &buf.de, &de); - if (k != 0) { - r = -errno; - break; - } - - if (!de) - break; - - if (ignore_file(de->d_name)) - continue; - - dirent_ensure_type(d, de); - - if (de->d_type == DT_DIR) { - int nfd, q; - char *p; - - nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (nfd < 0) { - if (errno == ENOENT) - continue; - - if (r == 0) - r = -errno; - continue; - } - - p = path_make_absolute(de->d_name, path); - if (!p) { - close_nointr_nofail(nfd); - r = -ENOMEM; - break; - } - - /* This will close nfd, regardless whether it succeeds or not */ - q = find_symlinks_fd(name, nfd, p, config_path, same_name_link); - free(p); - - if (q > 0) { - r = 1; - break; - } - - if (r == 0) - r = q; - - } else if (de->d_type == DT_LNK) { - char *p, *dest; - bool found_path, found_dest, b = false; - int q; - - /* Acquire symlink name */ - p = path_make_absolute(de->d_name, path); - if (!p) { - r = -ENOMEM; - break; - } - - /* Acquire symlink destination */ - q = readlink_and_canonicalize(p, &dest); - if (q < 0) { - free(p); - - if (q == -ENOENT) - continue; - - if (r == 0) - r = q; - continue; - } - - /* Check if the symlink itself matches what we - * are looking for */ - if (path_is_absolute(name)) - found_path = path_equal(p, name); - else - found_path = streq(de->d_name, name); - - /* Check if what the symlink points to - * matches what we are looking for */ - if (path_is_absolute(name)) - found_dest = path_equal(dest, name); - else - found_dest = streq(path_get_file_name(dest), name); - - free(dest); - - if (found_path && found_dest) { - char *t; - - /* Filter out same name links in the main - * config path */ - t = path_make_absolute(name, config_path); - if (!t) { - free(p); - r = -ENOMEM; - break; - } - - b = path_equal(t, p); - free(t); - } - - free(p); - - if (b) - *same_name_link = true; - else if (found_path || found_dest) { - r = 1; - break; - } - } - } - - closedir(d); - - return r; -} - -static int find_symlinks( - const char *name, - const char *config_path, - bool *same_name_link) { - - int fd; - - assert(name); - assert(config_path); - assert(same_name_link); - - fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (fd < 0) { - if (errno == ENOENT) - return 0; - return -errno; - } - - /* This takes possession of fd and closes it */ - return find_symlinks_fd(name, fd, config_path, config_path, same_name_link); -} - -static int find_symlinks_in_scope( - UnitFileScope scope, - const char *root_dir, - const char *name, - UnitFileState *state) { - - int r; - char _cleanup_free_ *path = NULL; - bool same_name_link_runtime = false, same_name_link = false; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - if (scope == UNIT_FILE_SYSTEM || scope == UNIT_FILE_GLOBAL) { - - /* First look in runtime config path */ - r = get_config_path(scope, true, root_dir, &path); - if (r < 0) - return r; - - r = find_symlinks(name, path, &same_name_link_runtime); - if (r < 0) - return r; - else if (r > 0) { - *state = UNIT_FILE_ENABLED_RUNTIME; - return r; - } - } - - /* Then look in the normal config path */ - r = get_config_path(scope, false, root_dir, &path); - if (r < 0) - return r; - - r = find_symlinks(name, path, &same_name_link); - if (r < 0) - return r; - else if (r > 0) { - *state = UNIT_FILE_ENABLED; - return r; - } - - /* Hmm, we didn't find it, but maybe we found the same name - * link? */ - if (same_name_link_runtime) { - *state = UNIT_FILE_LINKED_RUNTIME; - return 1; - } else if (same_name_link) { - *state = UNIT_FILE_LINKED; - return 1; - } - - return 0; -} - -int unit_file_mask( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **i; - char _cleanup_free_ *prefix; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = get_config_path(scope, runtime, root_dir, &prefix); - if (r < 0) - return r; - - STRV_FOREACH(i, files) { - char _cleanup_free_ *path = NULL; - - if (!unit_name_is_valid(*i, true)) { - if (r == 0) - r = -EINVAL; - continue; - } - - path = path_make_absolute(*i, prefix); - if (!path) { - r = -ENOMEM; - break; - } - - if (symlink("/dev/null", path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); - - continue; - } - - if (errno == EEXIST) { - - if (null_or_empty_path(path) > 0) - continue; - - if (force) { - unlink(path); - - if (symlink("/dev/null", path) >= 0) { - - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); - - continue; - } - } - - if (r == 0) - r = -EEXIST; - } else { - if (r == 0) - r = -errno; - } - } - - return r; -} - -int unit_file_unmask( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - UnitFileChange **changes, - unsigned *n_changes) { - - char **i, *config_path = NULL; - int r, q; - Set *remove_symlinks_to = NULL; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - char *path; - - if (!unit_name_is_valid(*i, true)) { - if (r == 0) - r = -EINVAL; - continue; - } - - path = path_make_absolute(*i, config_path); - if (!path) { - r = -ENOMEM; - break; - } - - q = null_or_empty_path(path); - if (q > 0) { - if (unlink(path) >= 0) { - mark_symlink_for_removal(&remove_symlinks_to, path); - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - - free(path); - continue; - } - - q = -errno; - } - - if (q != -ENOENT && r == 0) - r = q; - - free(path); - } - - -finish: - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); - if (r == 0) - r = q; - - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -int unit_file_link( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - char **i, *config_path = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - char *path, *fn; - struct stat st; - - fn = path_get_file_name(*i); - - if (!path_is_absolute(*i) || - !unit_name_is_valid(fn, true)) { - if (r == 0) - r = -EINVAL; - continue; - } - - if (lstat(*i, &st) < 0) { - if (r == 0) - r = -errno; - continue; - } - - if (!S_ISREG(st.st_mode)) { - r = -ENOENT; - continue; - } - - q = in_search_path(*i, paths.unit_path); - if (q < 0) { - r = q; - break; - } - - if (q > 0) - continue; - - path = path_make_absolute(fn, config_path); - if (!path) { - r = -ENOMEM; - break; - } - - if (symlink(*i, path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); - - free(path); - continue; - } - - if (errno == EEXIST) { - char *dest = NULL; - - q = readlink_and_make_absolute(path, &dest); - - if (q < 0 && errno != ENOENT) { - free(path); - - if (r == 0) - r = q; - - continue; - } - - if (q >= 0 && path_equal(dest, *i)) { - free(dest); - free(path); - continue; - } - - free(dest); - - if (force) { - unlink(path); - - if (symlink(*i, path) >= 0) { - - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); - - free(path); - continue; - } - } - - if (r == 0) - r = -EEXIST; - } else { - if (r == 0) - r = -errno; - } - - free(path); - } - - finish: - lookup_paths_free(&paths); - free(config_path); - - return r; -} - -void unit_file_list_free(Hashmap *h) { - UnitFileList *i; - - while ((i = hashmap_steal_first(h))) { - free(i->path); - free(i); - } - - hashmap_free(h); -} - -void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { - unsigned i; - - assert(changes || n_changes == 0); - - if (!changes) - return; - - for (i = 0; i < n_changes; i++) { - free(changes[i].path); - free(changes[i].source); - } - - free(changes); -} - -static void install_info_free(InstallInfo *i) { - assert(i); - - free(i->name); - free(i->path); - strv_free(i->aliases); - strv_free(i->wanted_by); - strv_free(i->required_by); - free(i); -} - -static void install_info_hashmap_free(Hashmap *m) { - InstallInfo *i; - - if (!m) - return; - - while ((i = hashmap_steal_first(m))) - install_info_free(i); - - hashmap_free(m); -} - -static void install_context_done(InstallContext *c) { - assert(c); - - install_info_hashmap_free(c->will_install); - install_info_hashmap_free(c->have_installed); - - c->will_install = c->have_installed = NULL; -} - -static int install_info_add( - InstallContext *c, - const char *name, - const char *path) { - InstallInfo *i = NULL; - int r; - - assert(c); - assert(name || path); - - if (!name) - name = path_get_file_name(path); - - if (!unit_name_is_valid(name, true)) - return -EINVAL; - - if (hashmap_get(c->have_installed, name) || - hashmap_get(c->will_install, name)) - return 0; - - r = hashmap_ensure_allocated(&c->will_install, string_hash_func, string_compare_func); - if (r < 0) - return r; - - i = new0(InstallInfo, 1); - if (!i) - return -ENOMEM; - - i->name = strdup(name); - if (!i->name) { - r = -ENOMEM; - goto fail; - } - - if (path) { - i->path = strdup(path); - if (!i->path) { - r = -ENOMEM; - goto fail; - } - } - - r = hashmap_put(c->will_install, i->name, i); - if (r < 0) - goto fail; - - return 0; - -fail: - if (i) - install_info_free(i); - - return r; -} - -static int install_info_add_auto( - InstallContext *c, - const char *name_or_path) { - - assert(c); - assert(name_or_path); - - if (path_is_absolute(name_or_path)) - return install_info_add(c, NULL, name_or_path); - else - return install_info_add(c, name_or_path, NULL); -} - -static int config_parse_also( - const char *filename, - unsigned line, - const char *section, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char *w; - size_t l; - char *state; - InstallContext *c = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - - FOREACH_WORD_QUOTED(w, l, rvalue, state) { - char *n; - int r; - - n = strndup(w, l); - if (!n) - return -ENOMEM; - - r = install_info_add(c, n, NULL); - if (r < 0) { - free(n); - return r; - } - - free(n); - } - - return 0; -} - -static int unit_file_load( - InstallContext *c, - InstallInfo *info, - const char *path, - bool allow_symlink) { - - const ConfigTableItem items[] = { - { "Install", "Alias", config_parse_strv, 0, &info->aliases }, - { "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by }, - { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by }, - { "Install", "Also", config_parse_also, 0, c }, - { NULL, NULL, NULL, 0, NULL } - }; - - int fd; - FILE *f; - int r; - - assert(c); - assert(info); - assert(path); - - fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW)); - if (fd < 0) - return -errno; - - f = fdopen(fd, "re"); - if (!f) { - close_nointr_nofail(fd); - return -ENOMEM; - } - - r = config_parse(path, f, NULL, config_item_table_lookup, (void*) items, true, info); - fclose(f); - if (r < 0) - return r; - - return - strv_length(info->aliases) + - strv_length(info->wanted_by) + - strv_length(info->required_by); -} - -static int unit_file_search( - InstallContext *c, - InstallInfo *info, - LookupPaths *paths, - const char *root_dir, - bool allow_symlink) { - - char **p; - int r; - - assert(c); - assert(info); - assert(paths); - - if (info->path) - return unit_file_load(c, info, info->path, allow_symlink); - - assert(info->name); - - STRV_FOREACH(p, paths->unit_path) { - char *path = NULL; - - if (isempty(root_dir)) - asprintf(&path, "%s/%s", *p, info->name); - else - asprintf(&path, "%s/%s/%s", root_dir, *p, info->name); - - if (!path) - return -ENOMEM; - - r = unit_file_load(c, info, path, allow_symlink); - - if (r >= 0) - info->path = path; - else { - if (r == -ENOENT && unit_name_is_instance(info->name)) { - /* unit file doesn't exist, however instance enablement was request */ - /* we will check if it is possible to load template unit file */ - char *template = NULL, - *template_path = NULL, - *template_dir = NULL; - - template = unit_name_template(info->name); - if (!template) { - free(path); - return -ENOMEM; - } - - /* we will reuse path variable since we don't need it anymore */ - template_dir = path; - *(strrchr(path, '/') + 1) = '\0'; - - template_path = strjoin(template_dir, template, NULL); - if (!template_path) { - free(path); - free(template); - return -ENOMEM; - } - - /* let's try to load template unit */ - r = unit_file_load(c, info, template_path, allow_symlink); - if (r >= 0) { - info->path = strdup(template_path); - if (!info->path) { - free(path); - free(template); - free(template_path); - return -ENOMEM; - } - } - - free(template); - free(template_path); - } - free(path); - } - - if (r != -ENOENT && r != -ELOOP) - return r; - } - - return -ENOENT; -} - -static int unit_file_can_install( - LookupPaths *paths, - const char *root_dir, - const char *name, - bool allow_symlink) { - - InstallContext c; - InstallInfo *i; - int r; - - assert(paths); - assert(name); - - zero(c); - - r = install_info_add_auto(&c, name); - if (r < 0) - return r; - - assert_se(i = hashmap_first(c.will_install)); - - r = unit_file_search(&c, i, paths, root_dir, allow_symlink); - - if (r >= 0) - r = - strv_length(i->aliases) + - strv_length(i->wanted_by) + - strv_length(i->required_by); - - install_context_done(&c); - - return r; -} - -static int create_symlink( - const char *old_path, - const char *new_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char *dest; - int r; - - assert(old_path); - assert(new_path); - - mkdir_parents_label(new_path, 0755); - - if (symlink(old_path, new_path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); - return 0; - } - - if (errno != EEXIST) - return -errno; - - r = readlink_and_make_absolute(new_path, &dest); - if (r < 0) - return r; - - if (path_equal(dest, old_path)) { - free(dest); - return 0; - } - - free(dest); - - if (!force) - return -EEXIST; - - unlink(new_path); - - if (symlink(old_path, new_path) >= 0) { - add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); - add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); - return 0; - } - - return -errno; -} - -static int install_info_symlink_alias( - InstallInfo *i, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **s; - int r = 0, q; - - assert(i); - assert(config_path); - - STRV_FOREACH(s, i->aliases) { - char *alias_path; - - alias_path = path_make_absolute(*s, config_path); - - if (!alias_path) - return -ENOMEM; - - q = create_symlink(i->path, alias_path, force, changes, n_changes); - free(alias_path); - - if (r == 0) - r = q; - } - - return r; -} - -static int install_info_symlink_wants( - InstallInfo *i, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **s; - int r = 0, q; - - assert(i); - assert(config_path); - - STRV_FOREACH(s, i->wanted_by) { - char *path; - - if (!unit_name_is_valid(*s, true)) { - r = -EINVAL; - continue; - } - - if (asprintf(&path, "%s/%s.wants/%s", config_path, *s, i->name) < 0) - return -ENOMEM; - - q = create_symlink(i->path, path, force, changes, n_changes); - free(path); - - if (r == 0) - r = q; - } - - return r; -} - -static int install_info_symlink_requires( - InstallInfo *i, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **s; - int r = 0, q; - - assert(i); - assert(config_path); - - STRV_FOREACH(s, i->required_by) { - char *path; - - if (!unit_name_is_valid(*s, true)) { - r = -EINVAL; - continue; - } - - if (asprintf(&path, "%s/%s.requires/%s", config_path, *s, i->name) < 0) - return -ENOMEM; - - q = create_symlink(i->path, path, force, changes, n_changes); - free(path); - - if (r == 0) - r = q; - } - - return r; -} - -static int install_info_symlink_link( - InstallInfo *i, - LookupPaths *paths, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - int r; - char *path; - - assert(i); - assert(paths); - assert(config_path); - assert(i->path); - - r = in_search_path(i->path, paths->unit_path); - if (r != 0) - return r; - - if (asprintf(&path, "%s/%s", config_path, i->name) < 0) - return -ENOMEM; - - r = create_symlink(i->path, path, force, changes, n_changes); - free(path); - - return r; -} - -static int install_info_apply( - InstallInfo *i, - LookupPaths *paths, - const char *config_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - int r, q; - - assert(i); - assert(paths); - assert(config_path); - - r = install_info_symlink_alias(i, config_path, force, changes, n_changes); - - q = install_info_symlink_wants(i, config_path, force, changes, n_changes); - if (r == 0) - r = q; - - q = install_info_symlink_requires(i, config_path, force, changes, n_changes); - if (r == 0) - r = q; - - q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes); - if (r == 0) - r = q; - - return r; -} - -static int install_context_apply( - InstallContext *c, - LookupPaths *paths, - const char *config_path, - const char *root_dir, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - InstallInfo *i; - int r = 0, q; - - assert(c); - assert(paths); - assert(config_path); - - while ((i = hashmap_first(c->will_install))) { - - q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); - if (q < 0) - return q; - - assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); - - q = unit_file_search(c, i, paths, root_dir, false); - if (q < 0) { - if (r >= 0) - r = q; - - return r; - } else if (r >= 0) - r += q; - - q = install_info_apply(i, paths, config_path, force, changes, n_changes); - if (r >= 0 && q < 0) - r = q; - } - - return r; -} - -static int install_context_mark_for_removal( - InstallContext *c, - LookupPaths *paths, - Set **remove_symlinks_to, - const char *config_path, - const char *root_dir) { - - InstallInfo *i; - int r = 0, q; - - assert(c); - assert(paths); - assert(config_path); - - /* Marks all items for removal */ - - while ((i = hashmap_first(c->will_install))) { - - q = hashmap_ensure_allocated(&c->have_installed, string_hash_func, string_compare_func); - if (q < 0) - return q; - - assert_se(hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); - - q = unit_file_search(c, i, paths, root_dir, false); - if (q < 0) { - if (r >= 0) - r = q; - - return r; - } else if (r >= 0) - r += q; - - if (unit_name_is_instance(i->name)) { - char *unit_file = NULL; - - unit_file = path_get_file_name(i->path); - - if (unit_name_is_instance(unit_file)) - /* unit file named as instance exists, thus all symlinks pointing to it, will be removed */ - q = mark_symlink_for_removal(remove_symlinks_to, i->name); - else - /* does not exist, thus we will mark for removal symlinks to template unit file */ - q = mark_symlink_for_removal(remove_symlinks_to, unit_file); - } else - q = mark_symlink_for_removal(remove_symlinks_to, i->name); - - if (r >= 0 && q < 0) - r = q; - } - - return r; -} - -int unit_file_enable( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext c; - char **i, *config_path = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(c); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - r = install_info_add_auto(&c, *i); - if (r < 0) - goto finish; - } - - /* This will return the number of symlink rules that were - supposed to be created, not the ones actually created. This is - useful to determine whether the passed files had any - installation data at all. */ - r = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); - -finish: - install_context_done(&c); - lookup_paths_free(&paths); - free(config_path); - - return r; -} - -int unit_file_disable( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext c; - char **i, *config_path = NULL; - Set *remove_symlinks_to = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(c); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - r = install_info_add_auto(&c, *i); - if (r < 0) - goto finish; - } - - r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir); - - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); - if (r == 0) - r = q; - -finish: - install_context_done(&c); - lookup_paths_free(&paths); - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -int unit_file_reenable( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext c; - char **i, *config_path = NULL; - Set *remove_symlinks_to = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(c); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - r = mark_symlink_for_removal(&remove_symlinks_to, *i); - if (r < 0) - goto finish; - - r = install_info_add_auto(&c, *i); - if (r < 0) - goto finish; - } - - r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); - - /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); - if (r == 0) - r = q; - -finish: - lookup_paths_free(&paths); - install_context_done(&c); - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -UnitFileState unit_file_get_state( - UnitFileScope scope, - const char *root_dir, - const char *name) { - - LookupPaths paths; - UnitFileState state = _UNIT_FILE_STATE_INVALID; - char **i, *path = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - zero(paths); - - if (root_dir && scope != UNIT_FILE_SYSTEM) - return -EINVAL; - - if (!unit_name_is_valid(name, true)) - return -EINVAL; - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - STRV_FOREACH(i, paths.unit_path) { - struct stat st; - - free(path); - path = NULL; - - if (root_dir) - asprintf(&path, "%s/%s/%s", root_dir, *i, name); - else - asprintf(&path, "%s/%s", *i, name); - - if (!path) { - r = -ENOMEM; - goto finish; - } - - if (lstat(path, &st) < 0) { - r = -errno; - if (errno == ENOENT) - continue; - - goto finish; - } - - if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { - r = -ENOENT; - goto finish; - } - - r = null_or_empty_path(path); - if (r < 0 && r != -ENOENT) - goto finish; - else if (r > 0) { - state = path_startswith(*i, "/run") ? - UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; - r = 0; - goto finish; - } - - r = find_symlinks_in_scope(scope, root_dir, name, &state); - if (r < 0) { - goto finish; - } else if (r > 0) { - r = 0; - goto finish; - } - - r = unit_file_can_install(&paths, root_dir, path, true); - if (r < 0 && errno != -ENOENT) - goto finish; - else if (r > 0) { - state = UNIT_FILE_DISABLED; - r = 0; - goto finish; - } else if (r == 0) { - state = UNIT_FILE_STATIC; - r = 0; - goto finish; - } - } - -finish: - lookup_paths_free(&paths); - free(path); - - return r < 0 ? r : state; -} - -int unit_file_query_preset(UnitFileScope scope, const char *name) { - char **files, **i; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(name); - - if (scope == UNIT_FILE_SYSTEM) - r = conf_files_list(&files, ".preset", - "/etc/systemd/system-preset", - "/usr/local/lib/systemd/system-preset", - "/usr/lib/systemd/system-preset", -#ifdef HAVE_SPLIT_USR - "/lib/systemd/system-preset", -#endif - NULL); - else if (scope == UNIT_FILE_GLOBAL) - r = conf_files_list(&files, ".preset", - "/etc/systemd/user-preset", - "/usr/local/lib/systemd/user-preset", - "/usr/lib/systemd/user-preset", - NULL); - else - return 1; - - if (r < 0) - return r; - - STRV_FOREACH(i, files) { - FILE *f; - - f = fopen(*i, "re"); - if (!f) { - if (errno == ENOENT) - continue; - - r = -errno; - goto finish; - } - - for (;;) { - char line[LINE_MAX], *l; - - if (!fgets(line, sizeof(line), f)) - break; - - l = strstrip(line); - if (!*l) - continue; - - if (strchr(COMMENTS, *l)) - continue; - - if (first_word(l, "enable")) { - l += 6; - l += strspn(l, WHITESPACE); - - if (fnmatch(l, name, FNM_NOESCAPE) == 0) { - r = 1; - fclose(f); - goto finish; - } - } else if (first_word(l, "disable")) { - l += 7; - l += strspn(l, WHITESPACE); - - if (fnmatch(l, name, FNM_NOESCAPE) == 0) { - r = 0; - fclose(f); - goto finish; - } - } else - log_debug("Couldn't parse line '%s'", l); - } - - fclose(f); - } - - /* Default is "enable" */ - r = 1; - -finish: - strv_free(files); - - return r; -} - -int unit_file_preset( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char *files[], - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - LookupPaths paths; - InstallContext plus, minus; - char **i, *config_path = NULL; - Set *remove_symlinks_to = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - zero(paths); - zero(plus); - zero(minus); - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - - if (!unit_name_is_valid(*i, true)) { - r = -EINVAL; - goto finish; - } - - r = unit_file_query_preset(scope, *i); - if (r < 0) - goto finish; - - if (r) - r = install_info_add_auto(&plus, *i); - else - r = install_info_add_auto(&minus, *i); - - if (r < 0) - goto finish; - } - - r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); - - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); - if (r == 0) - r = q; - - /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); - if (r == 0) - r = q; - -finish: - lookup_paths_free(&paths); - install_context_done(&plus); - install_context_done(&minus); - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -int unit_file_get_list( - UnitFileScope scope, - const char *root_dir, - Hashmap *h) { - - LookupPaths paths; - char **i, *buf = NULL; - DIR *d = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(h); - - zero(paths); - - if (root_dir && scope != UNIT_FILE_SYSTEM) - return -EINVAL; - - r = lookup_paths_init_from_scope(&paths, scope); - if (r < 0) - return r; - - STRV_FOREACH(i, paths.unit_path) { - const char *units_dir; - - free(buf); - buf = NULL; - - if (root_dir) { - if (asprintf(&buf, "%s/%s", root_dir, *i) < 0) { - r = -ENOMEM; - goto finish; - } - units_dir = buf; - } else - units_dir = *i; - - if (d) - closedir(d); - - d = opendir(units_dir); - if (!d) { - if (errno == ENOENT) - continue; - - r = -errno; - goto finish; - } - - for (;;) { - struct dirent *de; - union dirent_storage buffer; - UnitFileList *f; - - r = readdir_r(d, &buffer.de, &de); - if (r != 0) { - r = -r; - goto finish; - } - - if (!de) - break; - - if (ignore_file(de->d_name)) - continue; - - if (!unit_name_is_valid(de->d_name, true)) - continue; - - if (hashmap_get(h, de->d_name)) - continue; - - r = dirent_ensure_type(d, de); - if (r < 0) { - if (r == -ENOENT) - continue; - - goto finish; - } - - if (de->d_type != DT_LNK && de->d_type != DT_REG) - continue; - - f = new0(UnitFileList, 1); - if (!f) { - r = -ENOMEM; - goto finish; - } - - f->path = path_make_absolute(de->d_name, units_dir); - if (!f->path) { - free(f); - r = -ENOMEM; - goto finish; - } - - r = null_or_empty_path(f->path); - if (r < 0 && r != -ENOENT) { - free(f->path); - free(f); - goto finish; - } else if (r > 0) { - f->state = - path_startswith(*i, "/run") ? - UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; - goto found; - } - - r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state); - if (r < 0) { - free(f->path); - free(f); - goto finish; - } else if (r > 0) { - f->state = UNIT_FILE_ENABLED; - goto found; - } - - r = unit_file_can_install(&paths, root_dir, f->path, true); - if (r == -EINVAL || /* Invalid setting? */ - r == -EBADMSG || /* Invalid format? */ - r == -ENOENT /* Included file not found? */) - f->state = UNIT_FILE_INVALID; - else if (r < 0) { - free(f->path); - free(f); - goto finish; - } else if (r > 0) - f->state = UNIT_FILE_DISABLED; - else - f->state = UNIT_FILE_STATIC; - - found: - r = hashmap_put(h, path_get_file_name(f->path), f); - if (r < 0) { - free(f->path); - free(f); - goto finish; - } - } - } - -finish: - lookup_paths_free(&paths); - free(buf); - - if (d) - closedir(d); - - return r; -} - -static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { - [UNIT_FILE_ENABLED] = "enabled", - [UNIT_FILE_ENABLED_RUNTIME] = "enabled-runtime", - [UNIT_FILE_LINKED] = "linked", - [UNIT_FILE_LINKED_RUNTIME] = "linked-runtime", - [UNIT_FILE_MASKED] = "masked", - [UNIT_FILE_MASKED_RUNTIME] = "masked-runtime", - [UNIT_FILE_STATIC] = "static", - [UNIT_FILE_DISABLED] = "disabled", - [UNIT_FILE_INVALID] = "invalid", -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); - -static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = { - [UNIT_FILE_SYMLINK] = "symlink", - [UNIT_FILE_UNLINK] = "unlink", -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); diff --git a/src/shared/install.h b/src/shared/install.h deleted file mode 100644 index 55249914b1..0000000000 --- a/src/shared/install.h +++ /dev/null @@ -1,87 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2011 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 "hashmap.h" - -typedef enum UnitFileScope { - UNIT_FILE_SYSTEM, - UNIT_FILE_GLOBAL, - UNIT_FILE_USER, - _UNIT_FILE_SCOPE_MAX, - _UNIT_FILE_SCOPE_INVALID = -1 -} UnitFileScope; - -typedef enum UnitFileState { - UNIT_FILE_ENABLED, - UNIT_FILE_ENABLED_RUNTIME, - UNIT_FILE_LINKED, - UNIT_FILE_LINKED_RUNTIME, - UNIT_FILE_MASKED, - UNIT_FILE_MASKED_RUNTIME, - UNIT_FILE_STATIC, - UNIT_FILE_DISABLED, - UNIT_FILE_INVALID, - _UNIT_FILE_STATE_MAX, - _UNIT_FILE_STATE_INVALID = -1 -} UnitFileState; - -typedef enum UnitFileChangeType { - UNIT_FILE_SYMLINK, - UNIT_FILE_UNLINK, - _UNIT_FILE_CHANGE_TYPE_MAX, - _UNIT_FILE_CHANGE_TYPE_INVALID = -1 -} UnitFileChangeType; - -typedef struct UnitFileChange { - UnitFileChangeType type; - char *path; - char *source; -} UnitFileChange; - -typedef struct UnitFileList { - char *path; - UnitFileState state; -} UnitFileList; - -int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes); -int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes); -int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes); - -UnitFileState unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename); - -int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); - -void unit_file_list_free(Hashmap *h); -void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes); - -int unit_file_query_preset(UnitFileScope scope, const char *name); - -const char *unit_file_state_to_string(UnitFileState s); -UnitFileState unit_file_state_from_string(const char *s); - -const char *unit_file_change_type_to_string(UnitFileChangeType s); -UnitFileChangeType unit_file_change_type_from_string(const char *s); diff --git a/src/shared/ioprio.h b/src/shared/ioprio.h deleted file mode 100644 index 9800fc2553..0000000000 --- a/src/shared/ioprio.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef IOPRIO_H -#define IOPRIO_H - -/* This is minimal version of Linux' linux/ioprio.h header file, which - * is licensed GPL2 */ - -#include <unistd.h> -#include <sys/syscall.h> - -/* - * Gives us 8 prio classes with 13-bits of data for each class - */ -#define IOPRIO_BITS (16) -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) - -#define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE) - -/* - * These are the io priority groups as implemented by CFQ. RT is the realtime - * class, it always gets premium service. BE is the best-effort scheduling - * class, the default for any process. IDLE is the idle scheduling class, it - * is only served when no one else is using the disk. - */ -enum { - IOPRIO_CLASS_NONE, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -/* - * 8 best effort priority levels are supported - */ -#define IOPRIO_BE_NR (8) - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; - -static inline int ioprio_set(int which, int who, int ioprio) -{ - return syscall(__NR_ioprio_set, which, who, ioprio); -} - -static inline int ioprio_get(int which, int who) -{ - return syscall(__NR_ioprio_get, which, who); -} - -#endif diff --git a/src/shared/label.c b/src/shared/label.c deleted file mode 100644 index d353da57ec..0000000000 --- a/src/shared/label.c +++ /dev/null @@ -1,382 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <errno.h> -#include <sys/stat.h> -#include <unistd.h> -#include <malloc.h> -#include <sys/socket.h> -#include <sys/un.h> - -#include "label.h" -#include "util.h" -#include "path-util.h" - -#ifdef HAVE_SELINUX -#include "selinux-util.h" -#include <selinux/selinux.h> -#include <selinux/label.h> - -static struct selabel_handle *label_hnd = NULL; - -#endif - -int label_init(const char *prefix) { - int r = 0; - -#ifdef HAVE_SELINUX - usec_t before_timestamp, after_timestamp; - struct mallinfo before_mallinfo, after_mallinfo; - - if (!use_selinux()) - return 0; - - if (label_hnd) - return 0; - - before_mallinfo = mallinfo(); - before_timestamp = now(CLOCK_MONOTONIC); - - if (prefix) { - struct selinux_opt options[] = { - { .type = SELABEL_OPT_SUBSET, .value = prefix }, - }; - - label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); - } else - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - - if (!label_hnd) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Failed to initialize SELinux context: %m"); - r = security_getenforce() == 1 ? -errno : 0; - } else { - char timespan[FORMAT_TIMESPAN_MAX]; - int l; - - after_timestamp = now(CLOCK_MONOTONIC); - after_mallinfo = mallinfo(); - - l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0; - - log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.", - format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp), - (l+1023)/1024); - } -#endif - - return r; -} - -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { - int r = 0; - -#ifdef HAVE_SELINUX - struct stat st; - security_context_t fcon; - - if (!use_selinux() || !label_hnd) - return 0; - - r = lstat(path, &st); - if (r == 0) { - r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode); - - /* If there's no label to set, then exit without warning */ - if (r < 0 && errno == ENOENT) - return 0; - - if (r == 0) { - r = lsetfilecon(path, fcon); - freecon(fcon); - - /* If the FS doesn't support labels, then exit without warning */ - if (r < 0 && errno == ENOTSUP) - return 0; - } - } - - if (r < 0) { - /* Ignore ENOENT in some cases */ - if (ignore_enoent && errno == ENOENT) - return 0; - - if (ignore_erofs && errno == EROFS) - return 0; - - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Unable to fix label of %s: %m", path); - r = security_getenforce() == 1 ? -errno : 0; - } -#endif - - return r; -} - -void label_finish(void) { - -#ifdef HAVE_SELINUX - if (use_selinux() && label_hnd) - selabel_close(label_hnd); -#endif -} - -int label_get_create_label_from_exe(const char *exe, char **label) { - - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t mycon = NULL, fcon = NULL; - security_class_t sclass; - - if (!use_selinux()) { - *label = NULL; - return 0; - } - - r = getcon(&mycon); - if (r < 0) - goto fail; - - r = getfilecon(exe, &fcon); - if (r < 0) - goto fail; - - sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); - if (r == 0) - log_debug("SELinux Socket context for %s will be set to %s", exe, *label); - -fail: - if (r < 0 && security_getenforce() == 1) - r = -errno; - - freecon(mycon); - freecon(fcon); -#endif - - return r; -} - -int label_context_set(const char *path, mode_t mode) { - int r = 0; - -#ifdef HAVE_SELINUX - security_context_t filecon = NULL; - - if (!use_selinux() || !label_hnd) - return 0; - - r = selabel_lookup_raw(label_hnd, &filecon, path, mode); - if (r < 0 && errno != ENOENT) - r = -errno; - else if (r == 0) { - r = setfscreatecon(filecon); - if (r < 0) { - log_error("Failed to set SELinux file context on %s: %m", path); - r = -errno; - } - - freecon(filecon); - } - - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif - - return r; -} - -int label_socket_set(const char *label) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return 0; - - if (setsockcreatecon((security_context_t) label) < 0) { - log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, - "Failed to set SELinux context (%s) on socket: %m", label); - - if (security_getenforce() == 1) - return -errno; - } -#endif - - return 0; -} - -void label_context_clear(void) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - setfscreatecon(NULL); -#endif -} - -void label_socket_clear(void) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - setsockcreatecon(NULL); -#endif -} - -void label_free(const char *label) { - -#ifdef HAVE_SELINUX - if (!use_selinux()) - return; - - freecon((security_context_t) label); -#endif -} - -int label_mkdir(const char *path, mode_t mode, bool apply) { - - /* Creates a directory and labels it according to the SELinux policy */ -#ifdef HAVE_SELINUX - int r; - security_context_t fcon = NULL; - - if (!apply || !use_selinux() || !label_hnd) - goto skipped; - - if (path_is_absolute(path)) - r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFDIR); - else { - char *newpath; - - newpath = path_make_absolute_cwd(path); - if (!newpath) - return -ENOMEM; - - r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFDIR); - free(newpath); - } - - if (r == 0) - r = setfscreatecon(fcon); - - if (r < 0 && errno != ENOENT) { - log_error("Failed to set security context %s for %s: %m", fcon, path); - - if (security_getenforce() == 1) { - r = -errno; - goto finish; - } - } - - r = mkdir(path, mode); - if (r < 0) - r = -errno; - -finish: - setfscreatecon(NULL); - freecon(fcon); - - return r; - -skipped: -#endif - return mkdir(path, mode) < 0 ? -errno : 0; -} - -int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { - - /* Binds a socket and label its file system object according to the SELinux policy */ - -#ifdef HAVE_SELINUX - int r; - security_context_t fcon = NULL; - const struct sockaddr_un *un; - char *path = NULL; - - assert(fd >= 0); - assert(addr); - assert(addrlen >= sizeof(sa_family_t)); - - if (!use_selinux() || !label_hnd) - goto skipped; - - /* Filter out non-local sockets */ - if (addr->sa_family != AF_UNIX) - goto skipped; - - /* Filter out anonymous sockets */ - if (addrlen < sizeof(sa_family_t) + 1) - goto skipped; - - /* Filter out abstract namespace sockets */ - un = (const struct sockaddr_un*) addr; - if (un->sun_path[0] == 0) - goto skipped; - - path = strndup(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path)); - if (!path) - return -ENOMEM; - - if (path_is_absolute(path)) - r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); - else { - char *newpath; - - newpath = path_make_absolute_cwd(path); - - if (!newpath) { - free(path); - return -ENOMEM; - } - - r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); - free(newpath); - } - - if (r == 0) - r = setfscreatecon(fcon); - - if (r < 0 && errno != ENOENT) { - log_error("Failed to set security context %s for %s: %m", fcon, path); - - if (security_getenforce() == 1) { - r = -errno; - goto finish; - } - } - - r = bind(fd, addr, addrlen); - if (r < 0) - r = -errno; - -finish: - setfscreatecon(NULL); - freecon(fcon); - free(path); - - return r; - -skipped: -#endif - return bind(fd, addr, addrlen) < 0 ? -errno : 0; -} diff --git a/src/shared/label.h b/src/shared/label.h deleted file mode 100644 index 1220b18965..0000000000 --- a/src/shared/label.h +++ /dev/null @@ -1,47 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <sys/types.h> -#include <stdbool.h> -#include <sys/socket.h> - -int label_init(const char *prefix); -void label_finish(void); - -int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs); - -int label_socket_set(const char *label); -void label_socket_clear(void); - -int label_context_set(const char *path, mode_t mode); -void label_context_clear(void); - -void label_free(const char *label); - -int label_get_create_label_from_exe(const char *exe, char **label); - -int label_mkdir(const char *path, mode_t mode, bool apply); - -void label_retest_selinux(void); - -int label_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); diff --git a/src/shared/linux/Makefile b/src/shared/linux/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/shared/linux/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/shared/linux/auto_dev-ioctl.h b/src/shared/linux/auto_dev-ioctl.h deleted file mode 100644 index 850f39b33e..0000000000 --- a/src/shared/linux/auto_dev-ioctl.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2008 Red Hat, Inc. All rights reserved. - * Copyright 2008 Ian Kent <raven@themaw.net> - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - */ - -#ifndef _LINUX_AUTO_DEV_IOCTL_H -#define _LINUX_AUTO_DEV_IOCTL_H - -#include <linux/auto_fs.h> - -#ifdef __KERNEL__ -#include <linux/string.h> -#else -#include <string.h> -#endif /* __KERNEL__ */ - -#define AUTOFS_DEVICE_NAME "autofs" - -#define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1 -#define AUTOFS_DEV_IOCTL_VERSION_MINOR 0 - -#define AUTOFS_DEVID_LEN 16 - -#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl) - -/* - * An ioctl interface for autofs mount point control. - */ - -struct args_protover { - __u32 version; -}; - -struct args_protosubver { - __u32 sub_version; -}; - -struct args_openmount { - __u32 devid; -}; - -struct args_ready { - __u32 token; -}; - -struct args_fail { - __u32 token; - __s32 status; -}; - -struct args_setpipefd { - __s32 pipefd; -}; - -struct args_timeout { - __u64 timeout; -}; - -struct args_requester { - __u32 uid; - __u32 gid; -}; - -struct args_expire { - __u32 how; -}; - -struct args_askumount { - __u32 may_umount; -}; - -struct args_ismountpoint { - union { - struct args_in { - __u32 type; - } in; - struct args_out { - __u32 devid; - __u32 magic; - } out; - }; -}; - -/* - * All the ioctls use this structure. - * When sending a path size must account for the total length - * of the chunk of memory otherwise is is the size of the - * structure. - */ - -struct autofs_dev_ioctl { - __u32 ver_major; - __u32 ver_minor; - __u32 size; /* total size of data passed in - * including this struct */ - __s32 ioctlfd; /* automount command fd */ - - /* Command parameters */ - - union { - struct args_protover protover; - struct args_protosubver protosubver; - struct args_openmount openmount; - struct args_ready ready; - struct args_fail fail; - struct args_setpipefd setpipefd; - struct args_timeout timeout; - struct args_requester requester; - struct args_expire expire; - struct args_askumount askumount; - struct args_ismountpoint ismountpoint; - }; - - char path[0]; -}; - -static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in) -{ - memset(in, 0, sizeof(struct autofs_dev_ioctl)); - in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; - in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; - in->size = sizeof(struct autofs_dev_ioctl); - in->ioctlfd = -1; - return; -} - -/* - * If you change this make sure you make the corresponding change - * to autofs-dev-ioctl.c:lookup_ioctl() - */ -enum { - /* Get various version info */ - AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71, - AUTOFS_DEV_IOCTL_PROTOVER_CMD, - AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, - - /* Open mount ioctl fd */ - AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, - - /* Close mount ioctl fd */ - AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, - - /* Mount/expire status returns */ - AUTOFS_DEV_IOCTL_READY_CMD, - AUTOFS_DEV_IOCTL_FAIL_CMD, - - /* Activate/deactivate autofs mount */ - AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, - AUTOFS_DEV_IOCTL_CATATONIC_CMD, - - /* Expiry timeout */ - AUTOFS_DEV_IOCTL_TIMEOUT_CMD, - - /* Get mount last requesting uid and gid */ - AUTOFS_DEV_IOCTL_REQUESTER_CMD, - - /* Check for eligible expire candidates */ - AUTOFS_DEV_IOCTL_EXPIRE_CMD, - - /* Request busy status */ - AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, - - /* Check if path is a mountpoint */ - AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, -}; - -#define AUTOFS_IOCTL 0x93 - -#define AUTOFS_DEV_IOCTL_VERSION \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_PROTOVER \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_PROTOSUBVER \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_OPENMOUNT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_READY \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_FAIL \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_SETPIPEFD \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_CATATONIC \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_TIMEOUT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_REQUESTER \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_EXPIRE \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_ASKUMOUNT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl) - -#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \ - _IOWR(AUTOFS_IOCTL, \ - AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl) - -#endif /* _LINUX_AUTO_DEV_IOCTL_H */ diff --git a/src/shared/linux/fanotify.h b/src/shared/linux/fanotify.h deleted file mode 100644 index 63531a6b4d..0000000000 --- a/src/shared/linux/fanotify.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef _LINUX_FANOTIFY_H -#define _LINUX_FANOTIFY_H - -#include <linux/types.h> - -/* the following events that user-space can register for */ -#define FAN_ACCESS 0x00000001 /* File was accessed */ -#define FAN_MODIFY 0x00000002 /* File was modified */ -#define FAN_CLOSE_WRITE 0x00000008 /* Unwrittable file closed */ -#define FAN_CLOSE_NOWRITE 0x00000010 /* Writtable file closed */ -#define FAN_OPEN 0x00000020 /* File was opened */ - -#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */ - -/* FIXME currently Q's have no limit.... */ -#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ - -#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ -#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ - -/* helper events */ -#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */ - -/* flags used for fanotify_init() */ -#define FAN_CLOEXEC 0x00000001 -#define FAN_NONBLOCK 0x00000002 - -#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK) - -/* flags used for fanotify_modify_mark() */ -#define FAN_MARK_ADD 0x00000001 -#define FAN_MARK_REMOVE 0x00000002 -#define FAN_MARK_DONT_FOLLOW 0x00000004 -#define FAN_MARK_ONLYDIR 0x00000008 -#define FAN_MARK_MOUNT 0x00000010 -#define FAN_MARK_IGNORED_MASK 0x00000020 -#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040 -#define FAN_MARK_FLUSH 0x00000080 - -#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ - FAN_MARK_REMOVE |\ - FAN_MARK_DONT_FOLLOW |\ - FAN_MARK_ONLYDIR |\ - FAN_MARK_MOUNT |\ - FAN_MARK_IGNORED_MASK |\ - FAN_MARK_IGNORED_SURV_MODIFY) - -/* - * All of the events - we build the list by hand so that we can add flags in - * the future and not break backward compatibility. Apps will get only the - * events that they originally wanted. Be sure to add new events here! - */ -#define FAN_ALL_EVENTS (FAN_ACCESS |\ - FAN_MODIFY |\ - FAN_CLOSE |\ - FAN_OPEN) - -/* - * All events which require a permission response from userspace - */ -#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\ - FAN_ACCESS_PERM) - -#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\ - FAN_ALL_PERM_EVENTS |\ - FAN_Q_OVERFLOW) - -#define FANOTIFY_METADATA_VERSION 2 - -struct fanotify_event_metadata { - __u32 event_len; - __u32 vers; - __u64 mask; - __s32 fd; - __s32 pid; -} __attribute__ ((packed)); - -struct fanotify_response { - __s32 fd; - __u32 response; -} __attribute__ ((packed)); - -/* Legit userspace responses to a _PERM event */ -#define FAN_ALLOW 0x01 -#define FAN_DENY 0x02 - -/* Helper functions to deal with fanotify_event_metadata buffers */ -#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) - -#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \ - (struct fanotify_event_metadata*)(((char *)(meta)) + \ - (meta)->event_len)) - -#define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \ - (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \ - (long)(meta)->event_len <= (long)(len)) - -#endif /* _LINUX_FANOTIFY_H */ diff --git a/src/shared/linux/seccomp-bpf.h b/src/shared/linux/seccomp-bpf.h deleted file mode 100644 index 1e3d136739..0000000000 --- a/src/shared/linux/seccomp-bpf.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * seccomp example for x86 (32-bit and 64-bit) with BPF macros - * - * Copyright (c) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org> - * Authors: - * Will Drewry <wad@chromium.org> - * Kees Cook <keescook@chromium.org> - * - * The code may be used by anyone for any purpose, and can serve as a - * starting point for developing applications using mode 2 seccomp. - */ -#ifndef _SECCOMP_BPF_H_ -#define _SECCOMP_BPF_H_ - -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <errno.h> -#include <signal.h> -#include <string.h> -#include <unistd.h> - -#include <sys/prctl.h> - -#include <linux/unistd.h> -#include <linux/audit.h> -#include <linux/filter.h> -#include <linux/seccomp.h> - -#ifndef SECCOMP_MODE_FILTER -# define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ -# define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ -# define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ -# define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ -struct seccomp_data { - int nr; - __u32 arch; - __u64 instruction_pointer; - __u64 args[6]; -}; -#endif -#ifndef SYS_SECCOMP -# define SYS_SECCOMP 1 -#endif - -#define syscall_nr (offsetof(struct seccomp_data, nr)) -#define arch_nr (offsetof(struct seccomp_data, arch)) - -#if defined(__i386__) -# define REG_SYSCALL REG_EAX -# define ARCH_NR AUDIT_ARCH_I386 -#elif defined(__x86_64__) -# define REG_SYSCALL REG_RAX -# define ARCH_NR AUDIT_ARCH_X86_64 -#else -# warning "Platform does not support seccomp filter yet" -# define REG_SYSCALL 0 -# define ARCH_NR 0 -#endif - -#define VALIDATE_ARCHITECTURE \ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, arch_nr), \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARCH_NR, 1, 0), \ - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) - -#define EXAMINE_SYSCALL \ - BPF_STMT(BPF_LD+BPF_W+BPF_ABS, syscall_nr) - -#define ALLOW_SYSCALL(name) \ - BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_##name, 0, 1), \ - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) - -#define _KILL_PROCESS \ - BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL) - -#endif /* _SECCOMP_BPF_H_ */ diff --git a/src/shared/linux/seccomp.h b/src/shared/linux/seccomp.h deleted file mode 100644 index 9c03683fa0..0000000000 --- a/src/shared/linux/seccomp.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _LINUX_SECCOMP_H -#define _LINUX_SECCOMP_H - - -#include <linux/types.h> - - -/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, <mode>) */ -#define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */ -#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ -#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ - -/* - * All BPF programs must return a 32-bit value. - * The bottom 16-bits are for optional return data. - * The upper 16-bits are ordered from least permissive values to most. - * - * The ordering ensures that a min_t() over composed return values always - * selects the least permissive choice. - */ -#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ -#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ -#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ -#define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ -#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ - -/* Masks for the return value sections. */ -#define SECCOMP_RET_ACTION 0x7fff0000U -#define SECCOMP_RET_DATA 0x0000ffffU - -/** - * struct seccomp_data - the format the BPF program executes over. - * @nr: the system call number - * @arch: indicates system call convention as an AUDIT_ARCH_* value - * as defined in <linux/audit.h>. - * @instruction_pointer: at the time of the system call. - * @args: up to 6 system call arguments always stored as 64-bit values - * regardless of the architecture. - */ -struct seccomp_data { - int nr; - __u32 arch; - __u64 instruction_pointer; - __u64 args[6]; -}; - -#endif /* _LINUX_SECCOMP_H */ diff --git a/src/shared/list.h b/src/shared/list.h deleted file mode 100644 index 47f275a019..0000000000 --- a/src/shared/list.h +++ /dev/null @@ -1,125 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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/>. -***/ - -/* The head of the linked list. Use this in the structure that shall - * contain the head of the linked list */ -#define LIST_HEAD(t,name) \ - t *name - -/* The pointers in the linked list's items. Use this in the item structure */ -#define LIST_FIELDS(t,name) \ - t *name##_next, *name##_prev - -/* Initialize the list's head */ -#define LIST_HEAD_INIT(t,head) \ - do { \ - (head) = NULL; } \ - while(false) - -/* Initialize a list item */ -#define LIST_INIT(t,name,item) \ - do { \ - t *_item = (item); \ - assert(_item); \ - _item->name##_prev = _item->name##_next = NULL; \ - } while(false) - -/* Prepend an item to the list */ -#define LIST_PREPEND(t,name,head,item) \ - do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if ((_item->name##_next = *_head)) \ - _item->name##_next->name##_prev = _item; \ - _item->name##_prev = NULL; \ - *_head = _item; \ - } while(false) - -/* Remove an item from the list */ -#define LIST_REMOVE(t,name,head,item) \ - do { \ - t **_head = &(head), *_item = (item); \ - assert(_item); \ - if (_item->name##_next) \ - _item->name##_next->name##_prev = _item->name##_prev; \ - if (_item->name##_prev) \ - _item->name##_prev->name##_next = _item->name##_next; \ - else { \ - assert(*_head == _item); \ - *_head = _item->name##_next; \ - } \ - _item->name##_next = _item->name##_prev = NULL; \ - } while(false) - -/* Find the head of the list */ -#define LIST_FIND_HEAD(t,name,item,head) \ - do { \ - t *_item = (item); \ - assert(_item); \ - while (_item->name##_prev) \ - _item = _item->name##_prev; \ - (head) = _item; \ - } while (false) - -/* Find the head of the list */ -#define LIST_FIND_TAIL(t,name,item,tail) \ - do { \ - t *_item = (item); \ - assert(_item); \ - while (_item->name##_next) \ - _item = _item->name##_next; \ - (tail) = _item; \ - } while (false) - -/* Insert an item after another one (a = where, b = what) */ -#define LIST_INSERT_AFTER(t,name,head,a,b) \ - do { \ - t **_head = &(head), *_a = (a), *_b = (b); \ - assert(_b); \ - if (!_a) { \ - if ((_b->name##_next = *_head)) \ - _b->name##_next->name##_prev = _b; \ - _b->name##_prev = NULL; \ - *_head = _b; \ - } else { \ - if ((_b->name##_next = _a->name##_next)) \ - _b->name##_next->name##_prev = _b; \ - _b->name##_prev = _a; \ - _a->name##_next = _b; \ - } \ - } while(false) - -#define LIST_JUST_US(name,item) \ - (!(item)->name##_prev && !(item)->name##_next) \ - -#define LIST_FOREACH(name,i,head) \ - for ((i) = (head); (i); (i) = (i)->name##_next) - -#define LIST_FOREACH_SAFE(name,i,n,head) \ - for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) - -#define LIST_FOREACH_BEFORE(name,i,p) \ - for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev) - -#define LIST_FOREACH_AFTER(name,i,p) \ - for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next) diff --git a/src/shared/log.c b/src/shared/log.c deleted file mode 100644 index 63578683ab..0000000000 --- a/src/shared/log.c +++ /dev/null @@ -1,885 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <stdarg.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <stddef.h> -#include <printf.h> - -#include "log.h" -#include "util.h" -#include "missing.h" -#include "macro.h" -#include "socket-util.h" - -#define SNDBUF_SIZE (8*1024*1024) - -static LogTarget log_target = LOG_TARGET_CONSOLE; -static int log_max_level = LOG_INFO; -static int log_facility = LOG_DAEMON; - -static int console_fd = STDERR_FILENO; -static int syslog_fd = -1; -static int kmsg_fd = -1; -static int journal_fd = -1; - -static bool syslog_is_stream = false; - -static bool show_color = false; -static bool show_location = false; - -/* Akin to glibc's __abort_msg; which is private and we hence cannot - * use here. */ -static char *log_abort_msg = NULL; - -void log_close_console(void) { - - if (console_fd < 0) - return; - - if (getpid() == 1) { - if (console_fd >= 3) - close_nointr_nofail(console_fd); - - console_fd = -1; - } -} - -static int log_open_console(void) { - - if (console_fd >= 0) - return 0; - - if (getpid() == 1) { - console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (console_fd < 0) - return console_fd; - } else - console_fd = STDERR_FILENO; - - return 0; -} - -void log_close_kmsg(void) { - - if (kmsg_fd < 0) - return; - - close_nointr_nofail(kmsg_fd); - kmsg_fd = -1; -} - -static int log_open_kmsg(void) { - - if (kmsg_fd >= 0) - return 0; - - kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (kmsg_fd < 0) - return -errno; - - return 0; -} - -void log_close_syslog(void) { - - if (syslog_fd < 0) - return; - - close_nointr_nofail(syslog_fd); - syslog_fd = -1; -} - -static int create_log_socket(int type) { - int fd; - - /* All output to the syslog/journal fds we do asynchronously, - * and if the buffers are full we just drop the messages */ - - fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (fd < 0) - return -errno; - - fd_inc_sndbuf(fd, SNDBUF_SIZE); - - return fd; -} - -static int log_open_syslog(void) { - union sockaddr_union sa; - int r; - - if (syslog_fd >= 0) - return 0; - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path)); - - syslog_fd = create_log_socket(SOCK_DGRAM); - if (syslog_fd < 0) { - r = syslog_fd; - goto fail; - } - - if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { - close_nointr_nofail(syslog_fd); - - /* Some legacy syslog systems still use stream - * sockets. They really shouldn't. But what can we - * do... */ - syslog_fd = create_log_socket(SOCK_STREAM); - if (syslog_fd < 0) { - r = syslog_fd; - goto fail; - } - - if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { - r = -errno; - goto fail; - } - - syslog_is_stream = true; - } else - syslog_is_stream = false; - - return 0; - -fail: - log_close_syslog(); - return r; -} - -void log_close_journal(void) { - - if (journal_fd < 0) - return; - - close_nointr_nofail(journal_fd); - journal_fd = -1; -} - -static int log_open_journal(void) { - union sockaddr_union sa; - int r; - - if (journal_fd >= 0) - return 0; - - journal_fd = create_log_socket(SOCK_DGRAM); - if (journal_fd < 0) { - r = journal_fd; - goto fail; - } - - zero(sa); - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path)); - - if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) { - r = -errno; - goto fail; - } - - return 0; - -fail: - log_close_journal(); - return r; -} - -int log_open(void) { - int r; - - /* If we don't use the console we close it here, to not get - * killed by SAK. If we don't use syslog we close it here so - * that we are not confused by somebody deleting the socket in - * the fs. If we don't use /dev/kmsg we still keep it open, - * because there is no reason to close it. */ - - if (log_target == LOG_TARGET_NULL) { - log_close_journal(); - log_close_syslog(); - log_close_console(); - return 0; - } - - if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) || - getpid() == 1 || - isatty(STDERR_FILENO) <= 0) { - - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_JOURNAL) { - r = log_open_journal(); - if (r >= 0) { - log_close_syslog(); - log_close_console(); - return r; - } - } - - if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_SYSLOG) { - r = log_open_syslog(); - if (r >= 0) { - log_close_journal(); - log_close_console(); - return r; - } - } - - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SAFE || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_KMSG) { - r = log_open_kmsg(); - if (r >= 0) { - log_close_journal(); - log_close_syslog(); - log_close_console(); - return r; - } - } - } - - log_close_journal(); - log_close_syslog(); - - /* Get the real /dev/console if we are PID=1, hence reopen */ - log_close_console(); - return log_open_console(); -} - -void log_set_target(LogTarget target) { - assert(target >= 0); - assert(target < _LOG_TARGET_MAX); - - log_target = target; -} - -void log_close(void) { - log_close_journal(); - log_close_syslog(); - log_close_kmsg(); - log_close_console(); -} - -void log_forget_fds(void) { - console_fd = kmsg_fd = syslog_fd = journal_fd = -1; -} - -void log_set_max_level(int level) { - assert((level & LOG_PRIMASK) == level); - - log_max_level = level; -} - -void log_set_facility(int facility) { - log_facility = facility; -} - -static int write_to_console( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char location[64]; - struct iovec iovec[5]; - unsigned n = 0; - bool highlight; - - if (console_fd < 0) - return 0; - - highlight = LOG_PRI(level) <= LOG_ERR && show_color; - - zero(iovec); - - if (show_location) { - snprintf(location, sizeof(location), "(%s:%u) ", file, line); - char_array_0(location); - IOVEC_SET_STRING(iovec[n++], location); - } - - if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON); - IOVEC_SET_STRING(iovec[n++], buffer); - if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); - IOVEC_SET_STRING(iovec[n++], "\n"); - - if (writev(console_fd, iovec, n) < 0) - return -errno; - - return 1; -} - -static int write_to_syslog( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char header_priority[16], header_time[64], header_pid[16]; - struct iovec iovec[5]; - struct msghdr msghdr; - time_t t; - struct tm *tm; - - if (syslog_fd < 0) - return 0; - - snprintf(header_priority, sizeof(header_priority), "<%i>", level); - char_array_0(header_priority); - - t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC); - if (!(tm = localtime(&t))) - return -EINVAL; - - if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0) - return -EINVAL; - - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); - char_array_0(header_pid); - - zero(iovec); - IOVEC_SET_STRING(iovec[0], header_priority); - IOVEC_SET_STRING(iovec[1], header_time); - IOVEC_SET_STRING(iovec[2], program_invocation_short_name); - IOVEC_SET_STRING(iovec[3], header_pid); - IOVEC_SET_STRING(iovec[4], buffer); - - /* When using syslog via SOCK_STREAM separate the messages by NUL chars */ - if (syslog_is_stream) - iovec[4].iov_len++; - - zero(msghdr); - msghdr.msg_iov = iovec; - msghdr.msg_iovlen = ELEMENTSOF(iovec); - - for (;;) { - ssize_t n; - - n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL); - if (n < 0) - return -errno; - - if (!syslog_is_stream || - (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec))) - break; - - IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n); - } - - return 1; -} - -static int write_to_kmsg( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char header_priority[16], header_pid[16]; - struct iovec iovec[5]; - - if (kmsg_fd < 0) - return 0; - - snprintf(header_priority, sizeof(header_priority), "<%i>", level); - char_array_0(header_priority); - - snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid()); - char_array_0(header_pid); - - zero(iovec); - IOVEC_SET_STRING(iovec[0], header_priority); - IOVEC_SET_STRING(iovec[1], program_invocation_short_name); - IOVEC_SET_STRING(iovec[2], header_pid); - IOVEC_SET_STRING(iovec[3], buffer); - IOVEC_SET_STRING(iovec[4], "\n"); - - if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0) - return -errno; - - return 1; -} - -static int write_to_journal( - int level, - const char*file, - int line, - const char *func, - const char *buffer) { - - char header[LINE_MAX]; - struct iovec iovec[3]; - struct msghdr mh; - - if (journal_fd < 0) - return 0; - - snprintf(header, sizeof(header), - "PRIORITY=%i\n" - "SYSLOG_FACILITY=%i\n" - "CODE_FILE=%s\n" - "CODE_LINE=%i\n" - "CODE_FUNCTION=%s\n" - "SYSLOG_IDENTIFIER=%s\n" - "MESSAGE=", - LOG_PRI(level), - LOG_FAC(level), - file, - line, - func, - program_invocation_short_name); - - char_array_0(header); - - zero(iovec); - IOVEC_SET_STRING(iovec[0], header); - IOVEC_SET_STRING(iovec[1], buffer); - IOVEC_SET_STRING(iovec[2], "\n"); - - zero(mh); - mh.msg_iov = iovec; - mh.msg_iovlen = ELEMENTSOF(iovec); - - if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0) - return -errno; - - return 1; -} - -static int log_dispatch( - int level, - const char*file, - int line, - const char *func, - char *buffer) { - - int r = 0; - - if (log_target == LOG_TARGET_NULL) - return 0; - - /* Patch in LOG_DAEMON facility if necessary */ - if ((level & LOG_FACMASK) == 0) - level = log_facility | LOG_PRI(level); - - do { - char *e; - int k = 0; - - buffer += strspn(buffer, NEWLINE); - - if (buffer[0] == 0) - break; - - if ((e = strpbrk(buffer, NEWLINE))) - *(e++) = 0; - - if (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_JOURNAL) { - - k = write_to_journal(level, file, line, func, buffer); - if (k < 0) { - if (k != -EAGAIN) - log_close_journal(); - log_open_kmsg(); - } else if (k > 0) - r++; - } - - if (log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_SYSLOG) { - - k = write_to_syslog(level, file, line, func, buffer); - if (k < 0) { - if (k != -EAGAIN) - log_close_syslog(); - log_open_kmsg(); - } else if (k > 0) - r++; - } - - if (k <= 0 && - (log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_SAFE || - log_target == LOG_TARGET_SYSLOG_OR_KMSG || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_KMSG)) { - - k = write_to_kmsg(level, file, line, func, buffer); - if (k < 0) { - log_close_kmsg(); - log_open_console(); - } else if (k > 0) - r++; - } - - if (k <= 0) { - k = write_to_console(level, file, line, func, buffer); - if (k < 0) - return k; - } - - buffer = e; - } while (buffer); - - return r; -} - -int log_dump_internal( - int level, - const char*file, - int line, - const char *func, - char *buffer) { - - int saved_errno, r; - - /* This modifies the buffer... */ - - if (_likely_(LOG_PRI(level) > log_max_level)) - return 0; - - saved_errno = errno; - r = log_dispatch(level, file, line, func, buffer); - errno = saved_errno; - - return r; -} - -int log_metav( - int level, - const char*file, - int line, - const char *func, - const char *format, - va_list ap) { - - char buffer[LINE_MAX]; - int saved_errno, r; - - if (_likely_(LOG_PRI(level) > log_max_level)) - return 0; - - saved_errno = errno; - vsnprintf(buffer, sizeof(buffer), format, ap); - char_array_0(buffer); - - r = log_dispatch(level, file, line, func, buffer); - errno = saved_errno; - - return r; -} - -int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) { - - int r; - va_list ap; - - va_start(ap, format); - r = log_metav(level, file, line, func, format, ap); - va_end(ap); - - return r; -} - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wformat-nonliteral" -_noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) { - static char buffer[LINE_MAX]; - - snprintf(buffer, sizeof(buffer), format, text, file, line, func); - - char_array_0(buffer); - log_abort_msg = buffer; - - log_dispatch(LOG_CRIT, file, line, func, buffer); - abort(); -} -#pragma GCC diagnostic pop - -_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) { - log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); -} - -_noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) { - log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); -} - -int log_oom_internal(const char *file, int line, const char *func) { - log_meta(LOG_ERR, file, line, func, "Out of memory."); - return -ENOMEM; -} - -int log_struct_internal( - int level, - const char *file, - int line, - const char *func, - const char *format, ...) { - - int saved_errno; - va_list ap; - int r; - - if (_likely_(LOG_PRI(level) > log_max_level)) - return 0; - - if (log_target == LOG_TARGET_NULL) - return 0; - - if ((level & LOG_FACMASK) == 0) - level = log_facility | LOG_PRI(level); - - saved_errno = errno; - - if ((log_target == LOG_TARGET_AUTO || - log_target == LOG_TARGET_JOURNAL_OR_KMSG || - log_target == LOG_TARGET_JOURNAL) && - journal_fd >= 0) { - - char header[LINE_MAX]; - struct iovec iovec[17]; - unsigned n = 0, i; - struct msghdr mh; - const char nl = '\n'; - - /* If the journal is available do structured logging */ - - snprintf(header, sizeof(header), - "PRIORITY=%i\n" - "SYSLOG_FACILITY=%i\n" - "CODE_FILE=%s\n" - "CODE_LINE=%i\n" - "CODE_FUNCTION=%s\n" - "SYSLOG_IDENTIFIER=%s\n", - LOG_PRI(level), - LOG_FAC(level), - file, - line, - func, - program_invocation_short_name); - char_array_0(header); - - zero(iovec); - IOVEC_SET_STRING(iovec[n++], header); - - va_start(ap, format); - while (format && n + 1 < ELEMENTSOF(iovec)) { - char *buf; - va_list aq; - - /* We need to copy the va_list structure, - * since vasprintf() leaves it afterwards at - * an undefined location */ - - va_copy(aq, ap); - if (vasprintf(&buf, format, aq) < 0) { - va_end(aq); - r = -ENOMEM; - goto finish; - } - va_end(aq); - - /* Now, jump enough ahead, so that we point to - * the next format string */ - VA_FORMAT_ADVANCE(format, ap); - - IOVEC_SET_STRING(iovec[n++], buf); - - iovec[n].iov_base = (char*) &nl; - iovec[n].iov_len = 1; - n++; - - format = va_arg(ap, char *); - } - - zero(mh); - mh.msg_iov = iovec; - mh.msg_iovlen = n; - - if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0) - r = -errno; - else - r = 1; - - finish: - va_end(ap); - for (i = 1; i < n; i += 2) - free(iovec[i].iov_base); - - } else { - char buf[LINE_MAX]; - bool found = false; - - /* Fallback if journal logging is not available */ - - va_start(ap, format); - while (format) { - va_list aq; - - va_copy(aq, ap); - vsnprintf(buf, sizeof(buf), format, aq); - va_end(aq); - char_array_0(buf); - - if (startswith(buf, "MESSAGE=")) { - found = true; - break; - } - - VA_FORMAT_ADVANCE(format, ap); - - format = va_arg(ap, char *); - } - va_end(ap); - - if (found) - r = log_dispatch(level, file, line, func, buf + 8); - else - r = -EINVAL; - } - - errno = saved_errno; - return r; -} - -int log_set_target_from_string(const char *e) { - LogTarget t; - - t = log_target_from_string(e); - if (t < 0) - return -EINVAL; - - log_set_target(t); - return 0; -} - -int log_set_max_level_from_string(const char *e) { - int t; - - t = log_level_from_string(e); - if (t < 0) - return t; - - log_set_max_level(t); - return 0; -} - -void log_parse_environment(void) { - const char *e; - - e = secure_getenv("SYSTEMD_LOG_TARGET"); - if (e && log_set_target_from_string(e) < 0) - log_warning("Failed to parse log target %s. Ignoring.", e); - - e = secure_getenv("SYSTEMD_LOG_LEVEL"); - if (e && log_set_max_level_from_string(e) < 0) - log_warning("Failed to parse log level %s. Ignoring.", e); - - e = secure_getenv("SYSTEMD_LOG_COLOR"); - if (e && log_show_color_from_string(e) < 0) - log_warning("Failed to parse bool %s. Ignoring.", e); - - e = secure_getenv("SYSTEMD_LOG_LOCATION"); - if (e && log_show_location_from_string(e) < 0) - log_warning("Failed to parse bool %s. Ignoring.", e); -} - -LogTarget log_get_target(void) { - return log_target; -} - -int log_get_max_level(void) { - return log_max_level; -} - -void log_show_color(bool b) { - show_color = b; -} - -void log_show_location(bool b) { - show_location = b; -} - -int log_show_color_from_string(const char *e) { - int t; - - t = parse_boolean(e); - if (t < 0) - return t; - - log_show_color(t); - return 0; -} - -int log_show_location_from_string(const char *e) { - int t; - - t = parse_boolean(e); - if (t < 0) - return t; - - log_show_location(t); - return 0; -} - -bool log_on_console(void) { - if (log_target == LOG_TARGET_CONSOLE) - return true; - - return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0; -} - -static const char *const log_target_table[] = { - [LOG_TARGET_CONSOLE] = "console", - [LOG_TARGET_KMSG] = "kmsg", - [LOG_TARGET_JOURNAL] = "journal", - [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg", - [LOG_TARGET_SYSLOG] = "syslog", - [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", - [LOG_TARGET_AUTO] = "auto", - [LOG_TARGET_SAFE] = "safe", - [LOG_TARGET_NULL] = "null" -}; - -DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); diff --git a/src/shared/log.h b/src/shared/log.h deleted file mode 100644 index 1bd9dbf27a..0000000000 --- a/src/shared/log.h +++ /dev/null @@ -1,139 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <syslog.h> -#include <stdbool.h> -#include <stdarg.h> -#include <errno.h> - -#include "macro.h" - -typedef enum LogTarget{ - LOG_TARGET_CONSOLE, - LOG_TARGET_KMSG, - LOG_TARGET_JOURNAL, - LOG_TARGET_JOURNAL_OR_KMSG, - LOG_TARGET_SYSLOG, - LOG_TARGET_SYSLOG_OR_KMSG, - LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */ - LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */ - LOG_TARGET_NULL, - _LOG_TARGET_MAX, - _LOG_TARGET_INVALID = -1 -} LogTarget; - -void log_set_target(LogTarget target); -void log_set_max_level(int level); -void log_set_facility(int facility); - -int log_set_target_from_string(const char *e); -int log_set_max_level_from_string(const char *e); - -void log_show_color(bool b); -void log_show_location(bool b); - -int log_show_color_from_string(const char *e); -int log_show_location_from_string(const char *e); - -LogTarget log_get_target(void); -int log_get_max_level(void); - -int log_open(void); -void log_close(void); -void log_forget_fds(void); - -void log_close_syslog(void); -void log_close_journal(void); -void log_close_kmsg(void); -void log_close_console(void); - -void log_parse_environment(void); - -int log_meta( - int level, - const char*file, - int line, - const char *func, - const char *format, ...) _printf_attr_(5,6); - -int log_metav( - int level, - const char*file, - int line, - const char *func, - const char *format, - va_list ap); - -int log_struct_internal( - int level, - const char *file, - int line, - const char *func, - const char *format, ...) _sentinel_; - -int log_oom_internal( - const char *file, - int line, - const char *func); - -/* This modifies the buffer passed! */ -int log_dump_internal( - int level, - const char*file, - int line, - const char *func, - char *buffer); - -_noreturn_ void log_assert_failed( - const char *text, - const char *file, - int line, - const char *func); - -_noreturn_ void log_assert_failed_unreachable( - const char *text, - const char *file, - int line, - const char *func); - -#define log_full(level, ...) log_meta(level, __FILE__, __LINE__, __func__, __VA_ARGS__) - -#define log_debug(...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_info(...) log_meta(LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_notice(...) log_meta(LOG_NOTICE, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_warning(...) log_meta(LOG_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__) -#define log_error(...) log_meta(LOG_ERR, __FILE__, __LINE__, __func__, __VA_ARGS__) - -#define log_struct(level, ...) log_struct_internal(level, __FILE__, __LINE__, __func__, __VA_ARGS__) - -#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__) - -/* This modifies the buffer passed! */ -#define log_dump(level, buffer) log_dump_internal(level, __FILE__, __LINE__, __func__, buffer) - -bool log_on_console(void); - -const char *log_target_to_string(LogTarget target); -LogTarget log_target_from_string(const char *s); - -#define MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x) diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c deleted file mode 100644 index 36cce73550..0000000000 --- a/src/shared/logs-show.c +++ /dev/null @@ -1,904 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 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 <time.h> -#include <assert.h> -#include <errno.h> -#include <sys/poll.h> -#include <string.h> - -#include "logs-show.h" -#include "log.h" -#include "util.h" -#include "utf8.h" -#include "hashmap.h" - -#define PRINT_THRESHOLD 128 -#define JSON_THRESHOLD 4096 - -static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) { - size_t fl, nl; - void *buf; - - assert(data); - assert(field); - assert(target); - assert(target_size); - - fl = strlen(field); - if (length < fl) - return 0; - - if (memcmp(data, field, fl)) - return 0; - - nl = length - fl; - buf = malloc(nl+1); - if (!buf) - return log_oom(); - - memcpy(buf, (const char*) data + fl, nl); - ((char*)buf)[nl] = 0; - - free(*target); - *target = buf; - *target_size = nl; - - return 1; -} - -static bool shall_print(const char *p, size_t l, OutputFlags flags) { - assert(p); - - if (flags & OUTPUT_SHOW_ALL) - return true; - - if (l > PRINT_THRESHOLD) - return false; - - if (!utf8_is_printable_n(p, l)) - return false; - - return true; -} - -static int output_short( - FILE *f, - sd_journal *j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags) { - - int r; - const void *data; - size_t length; - size_t n = 0; - _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL; - size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0, priority_len = 0; - int p = LOG_INFO; - const char *color_on = "", *color_off = ""; - - assert(f); - assert(j); - - SD_JOURNAL_FOREACH_DATA(j, data, length) { - - r = parse_field(data, length, "PRIORITY=", &priority, &priority_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "_COMM=", &comm, &comm_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "_PID=", &pid, &pid_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len); - if (r < 0) - return r; - else if (r > 0) - continue; - - r = parse_field(data, length, "MESSAGE=", &message, &message_len); - if (r < 0) - return r; - } - - if (!message) - return 0; - - if (priority_len == 1 && *priority >= '0' && *priority <= '7') - p = *priority - '0'; - - if (mode == OUTPUT_SHORT_MONOTONIC) { - uint64_t t; - sd_id128_t boot_id; - - r = -ENOENT; - - if (monotonic) - r = safe_atou64(monotonic, &t); - - if (r < 0) - r = sd_journal_get_monotonic_usec(j, &t, &boot_id); - - if (r < 0) { - log_error("Failed to get monotonic: %s", strerror(-r)); - return r; - } - - fprintf(f, "[%5llu.%06llu]", - (unsigned long long) (t / USEC_PER_SEC), - (unsigned long long) (t % USEC_PER_SEC)); - - n += 1 + 5 + 1 + 6 + 1; - - } else { - char buf[64]; - uint64_t x; - time_t t; - struct tm tm; - - r = -ENOENT; - - if (realtime) - r = safe_atou64(realtime, &x); - - if (r < 0) - r = sd_journal_get_realtime_usec(j, &x); - - if (r < 0) { - log_error("Failed to get realtime: %s", strerror(-r)); - return r; - } - - t = (time_t) (x / USEC_PER_SEC); - if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) { - log_error("Failed to format time."); - return r; - } - - fputs(buf, f); - n += strlen(buf); - } - - if (hostname && shall_print(hostname, hostname_len, flags)) { - fprintf(f, " %.*s", (int) hostname_len, hostname); - n += hostname_len + 1; - } - - if (identifier && shall_print(identifier, identifier_len, flags)) { - fprintf(f, " %.*s", (int) identifier_len, identifier); - n += identifier_len + 1; - } else if (comm && shall_print(comm, comm_len, flags)) { - fprintf(f, " %.*s", (int) comm_len, comm); - n += comm_len + 1; - } else - fputc(' ', f); - - if (pid && shall_print(pid, pid_len, flags)) { - fprintf(f, "[%.*s]", (int) pid_len, pid); - n += pid_len + 2; - } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) { - fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid); - n += fake_pid_len + 2; - } - - if (flags & OUTPUT_COLOR) { - if (p <= LOG_ERR) { - color_on = ANSI_HIGHLIGHT_RED_ON; - color_off = ANSI_HIGHLIGHT_OFF; - } else if (p <= LOG_NOTICE) { - color_on = ANSI_HIGHLIGHT_ON; - color_off = ANSI_HIGHLIGHT_OFF; - } - } - - if (flags & OUTPUT_SHOW_ALL) - fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off); - else if (!utf8_is_printable_n(message, message_len)) { - char bytes[FORMAT_BYTES_MAX]; - fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len)); - } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns)) - fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off); - else if (n < n_columns && n_columns - n - 2 >= 3) { - char *e; - - e = ellipsize_mem(message, message_len, n_columns - n - 2, 90); - - if (!e) - fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off); - else - fprintf(f, ": %s%s%s\n", color_on, e, color_off); - - free(e); - } else - fputs("\n", f); - - return 0; -} - -static int output_verbose( - FILE *f, - sd_journal *j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags) { - - const void *data; - size_t length; - char *cursor; - uint64_t realtime; - char ts[FORMAT_TIMESTAMP_MAX]; - int r; - - assert(f); - assert(j); - - r = sd_journal_get_realtime_usec(j, &realtime); - if (r < 0) { - log_error("Failed to get realtime timestamp: %s", strerror(-r)); - return r; - } - - r = sd_journal_get_cursor(j, &cursor); - if (r < 0) { - log_error("Failed to get cursor: %s", strerror(-r)); - return r; - } - - fprintf(f, "%s [%s]\n", - format_timestamp(ts, sizeof(ts), realtime), - cursor); - - free(cursor); - - SD_JOURNAL_FOREACH_DATA(j, data, length) { - if (!shall_print(data, length, flags)) { - const char *c; - char bytes[FORMAT_BYTES_MAX]; - - c = memchr(data, '=', length); - if (!c) { - log_error("Invalid field."); - return -EINVAL; - } - - fprintf(f, "\t%.*s=[%s blob data]\n", - (int) (c - (const char*) data), - (const char*) data, - format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1)); - } else - fprintf(f, "\t%.*s\n", (int) length, (const char*) data); - } - - return 0; -} - -static int output_export( - FILE *f, - sd_journal *j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags) { - - sd_id128_t boot_id; - char sid[33]; - int r; - usec_t realtime, monotonic; - char *cursor; - const void *data; - size_t length; - - assert(j); - - r = sd_journal_get_realtime_usec(j, &realtime); - if (r < 0) { - log_error("Failed to get realtime timestamp: %s", strerror(-r)); - return r; - } - - r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id); - if (r < 0) { - log_error("Failed to get monotonic timestamp: %s", strerror(-r)); - return r; - } - - r = sd_journal_get_cursor(j, &cursor); - if (r < 0) { - log_error("Failed to get cursor: %s", strerror(-r)); - return r; - } - - fprintf(f, - "__CURSOR=%s\n" - "__REALTIME_TIMESTAMP=%llu\n" - "__MONOTONIC_TIMESTAMP=%llu\n" - "_BOOT_ID=%s\n", - cursor, - (unsigned long long) realtime, - (unsigned long long) monotonic, - sd_id128_to_string(boot_id, sid)); - - free(cursor); - - SD_JOURNAL_FOREACH_DATA(j, data, length) { - - /* We already printed the boot id, from the data in - * the header, hence let's suppress it here */ - if (length >= 9 && - memcmp(data, "_BOOT_ID=", 9) == 0) - continue; - - if (!utf8_is_printable_n(data, length)) { - const char *c; - uint64_t le64; - - c = memchr(data, '=', length); - if (!c) { - log_error("Invalid field."); - return -EINVAL; - } - - fwrite(data, c - (const char*) data, 1, f); - fputc('\n', f); - le64 = htole64(length - (c - (const char*) data) - 1); - fwrite(&le64, sizeof(le64), 1, f); - fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f); - } else - fwrite(data, length, 1, f); - - fputc('\n', f); - } - - fputc('\n', f); - - return 0; -} - -void json_escape( - FILE *f, - const char* p, - size_t l, - OutputFlags flags) { - - assert(f); - assert(p); - - if (!(flags & OUTPUT_SHOW_ALL) && l > JSON_THRESHOLD) - - fputs("null", f); - - else if (!utf8_is_printable_n(p, l)) { - bool not_first = false; - - fputs("[ ", f); - - while (l > 0) { - if (not_first) - fprintf(f, ", %u", (uint8_t) *p); - else { - not_first = true; - fprintf(f, "%u", (uint8_t) *p); - } - - p++; - l--; - } - - fputs(" ]", f); - } else { - fputc('\"', f); - - while (l > 0) { - if (*p == '"' || *p == '\\') { - fputc('\\', f); - fputc(*p, f); - } else if (*p < ' ') - fprintf(f, "\\u%04x", *p); - else - fputc(*p, f); - - p++; - l--; - } - - fputc('\"', f); - } -} - -static int output_json( - FILE *f, - sd_journal *j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags) { - - uint64_t realtime, monotonic; - char *cursor, *k; - const void *data; - size_t length; - sd_id128_t boot_id; - char sid[33]; - int r; - Hashmap *h = NULL; - bool done, separator; - - assert(j); - - r = sd_journal_get_realtime_usec(j, &realtime); - if (r < 0) { - log_error("Failed to get realtime timestamp: %s", strerror(-r)); - return r; - } - - r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id); - if (r < 0) { - log_error("Failed to get monotonic timestamp: %s", strerror(-r)); - return r; - } - - r = sd_journal_get_cursor(j, &cursor); - if (r < 0) { - log_error("Failed to get cursor: %s", strerror(-r)); - return r; - } - - if (mode == OUTPUT_JSON_PRETTY) - fprintf(f, - "{\n" - "\t\"__CURSOR\" : \"%s\",\n" - "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n" - "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n" - "\t\"_BOOT_ID\" : \"%s\"", - cursor, - (unsigned long long) realtime, - (unsigned long long) monotonic, - sd_id128_to_string(boot_id, sid)); - else { - if (mode == OUTPUT_JSON_SSE) - fputs("data: ", f); - - fprintf(f, - "{ \"__CURSOR\" : \"%s\", " - "\"__REALTIME_TIMESTAMP\" : \"%llu\", " - "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", " - "\"_BOOT_ID\" : \"%s\"", - cursor, - (unsigned long long) realtime, - (unsigned long long) monotonic, - sd_id128_to_string(boot_id, sid)); - } - free(cursor); - - h = hashmap_new(string_hash_func, string_compare_func); - if (!h) - return -ENOMEM; - - /* First round, iterate through the entry and count how often each field appears */ - SD_JOURNAL_FOREACH_DATA(j, data, length) { - const char *eq; - char *n; - unsigned u; - - if (length >= 9 && - memcmp(data, "_BOOT_ID=", 9) == 0) - continue; - - eq = memchr(data, '=', length); - if (!eq) - continue; - - n = strndup(data, eq - (const char*) data); - if (!n) { - r = -ENOMEM; - goto finish; - } - - u = PTR_TO_UINT(hashmap_get(h, n)); - if (u == 0) { - r = hashmap_put(h, n, UINT_TO_PTR(1)); - if (r < 0) { - free(n); - goto finish; - } - } else { - r = hashmap_update(h, n, UINT_TO_PTR(u + 1)); - free(n); - if (r < 0) - goto finish; - } - } - - separator = true; - do { - done = true; - - SD_JOURNAL_FOREACH_DATA(j, data, length) { - const char *eq; - char *kk, *n; - size_t m; - unsigned u; - - /* We already printed the boot id, from the data in - * the header, hence let's suppress it here */ - if (length >= 9 && - memcmp(data, "_BOOT_ID=", 9) == 0) - continue; - - eq = memchr(data, '=', length); - if (!eq) - continue; - - if (separator) { - if (mode == OUTPUT_JSON_PRETTY) - fputs(",\n\t", f); - else - fputs(", ", f); - } - - m = eq - (const char*) data; - - n = strndup(data, m); - if (!n) { - r = -ENOMEM; - goto finish; - } - - u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk)); - if (u == 0) { - /* We already printed this, let's jump to the next */ - free(n); - separator = false; - - continue; - } else if (u == 1) { - /* Field only appears once, output it directly */ - - json_escape(f, data, m, flags); - fputs(" : ", f); - - json_escape(f, eq + 1, length - m - 1, flags); - - hashmap_remove(h, n); - free(kk); - free(n); - - separator = true; - - continue; - - } else { - /* Field appears multiple times, output it as array */ - json_escape(f, data, m, flags); - fputs(" : [ ", f); - json_escape(f, eq + 1, length - m - 1, flags); - - /* Iterate through the end of the list */ - - while (sd_journal_enumerate_data(j, &data, &length) > 0) { - if (length < m + 1) - continue; - - if (memcmp(data, n, m) != 0) - continue; - - if (((const char*) data)[m] != '=') - continue; - - fputs(", ", f); - json_escape(f, (const char*) data + m + 1, length - m - 1, flags); - } - - fputs(" ]", f); - - hashmap_remove(h, n); - free(kk); - free(n); - - /* Iterate data fields form the beginning */ - done = false; - separator = true; - - break; - } - } - - } while (!done); - - if (mode == OUTPUT_JSON_PRETTY) - fputs("\n}\n", f); - else if (mode == OUTPUT_JSON_SSE) - fputs("}\n\n", f); - else - fputs(" }\n", f); - - r = 0; - -finish: - while ((k = hashmap_steal_first_key(h))) - free(k); - - hashmap_free(h); - - return r; -} - -static int output_cat( - FILE *f, - sd_journal *j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags) { - - const void *data; - size_t l; - int r; - - assert(j); - assert(f); - - r = sd_journal_get_data(j, "MESSAGE", &data, &l); - if (r < 0) { - /* An entry without MESSAGE=? */ - if (r == -ENOENT) - return 0; - - log_error("Failed to get data: %s", strerror(-r)); - return r; - } - - assert(l >= 8); - - fwrite((const char*) data + 8, 1, l - 8, f); - fputc('\n', f); - - return 0; -} - -static int (*output_funcs[_OUTPUT_MODE_MAX])( - FILE *f, - sd_journal*j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags) = { - - [OUTPUT_SHORT] = output_short, - [OUTPUT_SHORT_MONOTONIC] = output_short, - [OUTPUT_VERBOSE] = output_verbose, - [OUTPUT_EXPORT] = output_export, - [OUTPUT_JSON] = output_json, - [OUTPUT_JSON_PRETTY] = output_json, - [OUTPUT_JSON_SSE] = output_json, - [OUTPUT_CAT] = output_cat -}; - -int output_journal( - FILE *f, - sd_journal *j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags) { - - int ret; - assert(mode >= 0); - assert(mode < _OUTPUT_MODE_MAX); - - if (n_columns <= 0) - n_columns = columns(); - - ret = output_funcs[mode](f, j, mode, n_columns, flags); - fflush(stdout); - return ret; -} - -int show_journal_by_unit( - FILE *f, - const char *unit, - OutputMode mode, - unsigned n_columns, - usec_t not_before, - unsigned how_many, - OutputFlags flags) { - - _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL; - sd_journal *j = NULL; - int r; - unsigned line = 0; - bool need_seek = false; - int warn_cutoff = flags & OUTPUT_WARN_CUTOFF; - - assert(mode >= 0); - assert(mode < _OUTPUT_MODE_MAX); - assert(unit); - - if (!endswith(unit, ".service") && - !endswith(unit, ".socket") && - !endswith(unit, ".mount") && - !endswith(unit, ".swap")) - return 0; - - if (how_many <= 0) - return 0; - - if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 || - asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 || - asprintf(&m3, "UNIT=%s", unit) < 0) { - r = -ENOMEM; - goto finish; - } - - r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY); - if (r < 0) - goto finish; - - /* Look for messages from the service itself */ - r = sd_journal_add_match(j, m1, 0); - if (r < 0) - goto finish; - - /* Look for coredumps of the service */ - r = sd_journal_add_disjunction(j); - if (r < 0) - goto finish; - r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0); - if (r < 0) - goto finish; - r = sd_journal_add_match(j, m2, 0); - if (r < 0) - goto finish; - - /* Look for messages from PID 1 about this service */ - r = sd_journal_add_disjunction(j); - if (r < 0) - goto finish; - r = sd_journal_add_match(j, "_PID=1", 0); - if (r < 0) - goto finish; - r = sd_journal_add_match(j, m3, 0); - if (r < 0) - goto finish; - - /* Seek to end */ - r = sd_journal_seek_tail(j); - if (r < 0) - goto finish; - - r = sd_journal_previous_skip(j, how_many); - if (r < 0) - goto finish; - - for (;;) { - for (;;) { - usec_t usec; - - if (need_seek) { - r = sd_journal_next(j); - if (r < 0) - goto finish; - } - - if (r == 0) - break; - - need_seek = true; - - if (not_before > 0) { - r = sd_journal_get_monotonic_usec(j, &usec, NULL); - - /* -ESTALE is returned if the - timestamp is not from this boot */ - if (r == -ESTALE) - continue; - else if (r < 0) - goto finish; - - if (usec < not_before) - continue; - } - - line ++; - - r = output_journal(f, j, mode, n_columns, flags); - if (r < 0) - goto finish; - } - - if (warn_cutoff && line < how_many && not_before > 0) { - sd_id128_t boot_id; - usec_t cutoff; - - /* Check whether the cutoff line is too early */ - - r = sd_id128_get_boot(&boot_id); - if (r < 0) - goto finish; - - r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL); - if (r < 0) - goto finish; - - if (r > 0 && not_before < cutoff) - fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n"); - - warn_cutoff = false; - } - - if (!(flags & OUTPUT_FOLLOW)) - break; - - r = sd_journal_wait(j, (usec_t) -1); - if (r < 0) - goto finish; - - } - -finish: - if (j) - sd_journal_close(j); - - return r; -} - -static const char *const output_mode_table[_OUTPUT_MODE_MAX] = { - [OUTPUT_SHORT] = "short", - [OUTPUT_SHORT_MONOTONIC] = "short-monotonic", - [OUTPUT_VERBOSE] = "verbose", - [OUTPUT_EXPORT] = "export", - [OUTPUT_JSON] = "json", - [OUTPUT_JSON_PRETTY] = "json-pretty", - [OUTPUT_JSON_SSE] = "json-sse", - [OUTPUT_CAT] = "cat" -}; - -DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode); diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h deleted file mode 100644 index 06082800c8..0000000000 --- a/src/shared/logs-show.h +++ /dev/null @@ -1,74 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdbool.h> - -#include <systemd/sd-journal.h> - -#include "util.h" - -typedef enum OutputMode { - OUTPUT_SHORT, - OUTPUT_SHORT_MONOTONIC, - OUTPUT_VERBOSE, - OUTPUT_EXPORT, - OUTPUT_JSON, - OUTPUT_JSON_PRETTY, - OUTPUT_JSON_SSE, - OUTPUT_CAT, - _OUTPUT_MODE_MAX, - _OUTPUT_MODE_INVALID = -1 -} OutputMode; - -typedef enum OutputFlags { - OUTPUT_SHOW_ALL = 1 << 0, - OUTPUT_FOLLOW = 1 << 1, - OUTPUT_WARN_CUTOFF = 1 << 2, - OUTPUT_FULL_WIDTH = 1 << 3, - OUTPUT_COLOR = 1 << 4 -} OutputFlags; - -int output_journal( - FILE *f, - sd_journal *j, - OutputMode mode, - unsigned n_columns, - OutputFlags flags); - -int show_journal_by_unit( - FILE *f, - const char *unit, - OutputMode mode, - unsigned n_columns, - usec_t not_before, - unsigned how_many, - OutputFlags flags); - -void json_escape( - FILE *f, - const char* p, - size_t l, - OutputFlags flags); - -const char* output_mode_to_string(OutputMode m); -OutputMode output_mode_from_string(const char *s); diff --git a/src/shared/macro.h b/src/shared/macro.h deleted file mode 100644 index e930fdab53..0000000000 --- a/src/shared/macro.h +++ /dev/null @@ -1,242 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <assert.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/uio.h> -#include <inttypes.h> - -#define _printf_attr_(a,b) __attribute__ ((format (printf, a, b))) -#define _sentinel_ __attribute__ ((sentinel)) -#define _noreturn_ __attribute__((noreturn)) -#define _unused_ __attribute__ ((unused)) -#define _destructor_ __attribute__ ((destructor)) -#define _pure_ __attribute__ ((pure)) -#define _const_ __attribute__ ((const)) -#define _deprecated_ __attribute__ ((deprecated)) -#define _packed_ __attribute__ ((packed)) -#define _malloc_ __attribute__ ((malloc)) -#define _weak_ __attribute__ ((weak)) -#define _likely_(x) (__builtin_expect(!!(x),1)) -#define _unlikely_(x) (__builtin_expect(!!(x),0)) -#define _public_ __attribute__ ((visibility("default"))) -#define _hidden_ __attribute__ ((visibility("hidden"))) -#define _weakref_(x) __attribute__((weakref(#x))) -#define _introspect_(x) __attribute__((section("introspect." x))) -#define _alignas_(x) __attribute__((aligned(__alignof(x)))) - -#define XSTRINGIFY(x) #x -#define STRINGIFY(x) XSTRINGIFY(x) - -/* Rounds up */ -#define ALIGN(l) ALIGN_TO((l), sizeof(void*)) -static inline size_t ALIGN_TO(size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); -} - -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) - -/* - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#ifndef MAX -#define MAX(a,b) \ - __extension__ ({ \ - typeof(a) _a = (a); \ - typeof(b) _b = (b); \ - _a > _b ? _a : _b; \ - }) -#endif - -#define MAX3(a,b,c) \ - MAX(MAX(a,b),c) - -#ifndef MIN -#define MIN(a,b) \ - __extension__ ({ \ - typeof(a) _a = (a); \ - typeof(b) _b = (b); \ - _a < _b ? _a : _b; \ - }) -#endif - -#define MIN3(a,b,c) \ - MIN(MIN(a,b),c) - -#define CLAMP(x, low, high) \ - __extension__ ({ \ - typeof(x) _x = (x); \ - typeof(low) _low = (low); \ - typeof(high) _high = (high); \ - ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \ - }) - -#define assert_se(expr) \ - do { \ - if (_unlikely_(!(expr))) \ - log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) \ - -/* We override the glibc assert() here. */ -#undef assert -#ifdef NDEBUG -#define assert(expr) do {} while(false) -#else -#define assert(expr) assert_se(expr) -#endif - -#define assert_not_reached(t) \ - do { \ - log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) - -#define assert_cc(expr) \ - do { \ - switch (0) { \ - case 0: \ - case !!(expr): \ - ; \ - } \ - } while (false) - -#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) -#define UINT_TO_PTR(u) ((void*) ((uintptr_t) (u))) - -#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) -#define UINT32_TO_PTR(u) ((void*) ((uintptr_t) (u))) - -#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) -#define ULONG_TO_PTR(u) ((void*) ((uintptr_t) (u))) - -#define PTR_TO_INT(p) ((int) ((intptr_t) (p))) -#define INT_TO_PTR(u) ((void*) ((intptr_t) (u))) - -#define TO_INT32(p) ((int32_t) ((intptr_t) (p))) -#define INT32_TO_PTR(u) ((void*) ((intptr_t) (u))) - -#define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) -#define LONG_TO_PTR(u) ((void*) ((intptr_t) (u))) - -#define memzero(x,l) (memset((x), 0, (l))) -#define zero(x) (memzero(&(x), sizeof(x))) - -#define char_array_0(x) x[sizeof(x)-1] = 0; - -#define IOVEC_SET_STRING(i, s) \ - do { \ - struct iovec *_i = &(i); \ - char *_s = (char *)(s); \ - _i->iov_base = _s; \ - _i->iov_len = strlen(_s); \ - } while(false) - -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; - - for (j = 0; j < n; j++) - r += i[j].iov_len; - - return r; -} - -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; - - for (j = 0; j < n; j++) { - size_t sub; - - if (_unlikely_(k <= 0)) - break; - - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t*) i[j].iov_base + sub; - k -= sub; - } - - return k; -} - -#define _cleanup_free_ __attribute__((cleanup(freep))) -#define _cleanup_fclose_ __attribute__((cleanup(fclosep))) -#define _cleanup_close_ __attribute__((cleanup(closep))) -#define _cleanup_closedir_ __attribute__((cleanup(closedirp))) -#define _cleanup_umask_ __attribute__((cleanup(umaskp))) -#define _cleanup_strv_free_ __attribute__((cleanup(strv_freep))) - -#define VA_FORMAT_ADVANCE(format, ap) \ -do { \ - int _argtypes[128]; \ - size_t _i, _k; \ - _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ - assert(_k < ELEMENTSOF(_argtypes)); \ - for (_i = 0; _i < _k; _i++) { \ - if (_argtypes[_i] & PA_FLAG_PTR) { \ - (void) va_arg(ap, void*); \ - continue; \ - } \ - \ - switch (_argtypes[_i]) { \ - case PA_INT: \ - case PA_INT|PA_FLAG_SHORT: \ - case PA_CHAR: \ - (void) va_arg(ap, int); \ - break; \ - case PA_INT|PA_FLAG_LONG: \ - (void) va_arg(ap, long int); \ - break; \ - case PA_INT|PA_FLAG_LONG_LONG: \ - (void) va_arg(ap, long long int); \ - break; \ - case PA_WCHAR: \ - (void) va_arg(ap, wchar_t); \ - break; \ - case PA_WSTRING: \ - case PA_STRING: \ - case PA_POINTER: \ - (void) va_arg(ap, void*); \ - break; \ - case PA_FLOAT: \ - case PA_DOUBLE: \ - (void) va_arg(ap, double); \ - break; \ - case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ - (void) va_arg(ap, long double); \ - break; \ - default: \ - assert_not_reached("Unknown format string argument."); \ - } \ - } \ -} while(false) - -#include "log.h" diff --git a/src/shared/missing.h b/src/shared/missing.h deleted file mode 100644 index 3777cf69b2..0000000000 --- a/src/shared/missing.h +++ /dev/null @@ -1,255 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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/>. -***/ - -/* Missing glibc definitions to access certain kernel APIs */ - -#include <sys/resource.h> -#include <sys/syscall.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <linux/oom.h> - -#ifdef HAVE_AUDIT -#include <libaudit.h> -#endif - -#include "macro.h" - -#ifdef ARCH_MIPS -#include <asm/sgidefs.h> -#endif - -#ifndef RLIMIT_RTTIME -#define RLIMIT_RTTIME 15 -#endif - -#ifndef F_LINUX_SPECIFIC_BASE -#define F_LINUX_SPECIFIC_BASE 1024 -#endif - -#ifndef F_SETPIPE_SZ -#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) -#endif - -#ifndef F_GETPIPE_SZ -#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) -#endif - -#ifndef IP_FREEBIND -#define IP_FREEBIND 15 -#endif - -#ifndef OOM_SCORE_ADJ_MIN -#define OOM_SCORE_ADJ_MIN (-1000) -#endif - -#ifndef OOM_SCORE_ADJ_MAX -#define OOM_SCORE_ADJ_MAX 1000 -#endif - -#ifndef AUDIT_SERVICE_START -#define AUDIT_SERVICE_START 1130 /* Service (daemon) start */ -#endif - -#ifndef AUDIT_SERVICE_STOP -#define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */ -#endif - -#ifndef TIOCVHANGUP -#define TIOCVHANGUP 0x5437 -#endif - -#ifndef IP_TRANSPARENT -#define IP_TRANSPARENT 19 -#endif - -#if !HAVE_DECL_PIVOT_ROOT -static inline int pivot_root(const char *new_root, const char *put_old) { - return syscall(SYS_pivot_root, new_root, put_old); -} -#endif - -#ifdef __x86_64__ -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 300 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 301 -# endif -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 4336 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 4337 -# endif -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 6300 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 6301 -# endif -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 5295 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 5296 -# endif -# endif -#else -# ifndef __NR_fanotify_init -# define __NR_fanotify_init 338 -# endif -# ifndef __NR_fanotify_mark -# define __NR_fanotify_mark 339 -# endif -#endif - -#ifndef HAVE_FANOTIFY_INIT -static inline int fanotify_init(unsigned int flags, unsigned int event_f_flags) { - return syscall(__NR_fanotify_init, flags, event_f_flags); -} -#endif - -#ifndef HAVE_FANOTIFY_MARK -static inline int fanotify_mark(int fanotify_fd, unsigned int flags, uint64_t mask, - int dfd, const char *pathname) { -#if defined _MIPS_SIM && _MIPS_SIM == _MIPS_SIM_ABI32 || defined __powerpc__ && !defined __powerpc64__ - union { - uint64_t _64; - uint32_t _32[2]; - } _mask; - _mask._64 = mask; - - return syscall(__NR_fanotify_mark, fanotify_fd, flags, - _mask._32[0], _mask._32[1], dfd, pathname); -#else - return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname); -#endif -} -#endif - -#ifndef BTRFS_IOCTL_MAGIC -#define BTRFS_IOCTL_MAGIC 0x94 -#endif - -#ifndef BTRFS_PATH_NAME_MAX -#define BTRFS_PATH_NAME_MAX 4087 -#endif - -struct btrfs_ioctl_vol_args { - int64_t fd; - char name[BTRFS_PATH_NAME_MAX + 1]; -}; - -#ifndef BTRFS_IOC_DEFRAG -#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, struct btrfs_ioctl_vol_args) -#endif - -#ifndef BTRFS_SUPER_MAGIC -#define BTRFS_SUPER_MAGIC 0x9123683E -#endif - -#ifndef MS_MOVE -#define MS_MOVE 8192 -#endif - -#ifndef MS_PRIVATE -#define MS_PRIVATE (1 << 18) -#endif - -#if !HAVE_DECL_GETTID -static inline pid_t gettid(void) { - return (pid_t) syscall(SYS_gettid); -} -#endif - -#ifndef SCM_SECURITY -#define SCM_SECURITY 0x03 -#endif - -#ifndef MS_STRICTATIME -#define MS_STRICTATIME (1<<24) -#endif - -#ifndef PR_SET_NO_NEW_PRIVS -#define PR_SET_NO_NEW_PRIVS 38 -#endif - -#ifndef PR_SET_CHILD_SUBREAPER -#define PR_SET_CHILD_SUBREAPER 36 -#endif - -#ifndef MAX_HANDLE_SZ -#define MAX_HANDLE_SZ 128 -#endif - -#if defined __x86_64__ -# ifndef __NR_name_to_handle_at -# define __NR_name_to_handle_at 303 -# endif -#elif defined __i386__ -# ifndef __NR_name_to_handle_at -# define __NR_name_to_handle_at 341 -# endif -#elif defined __arm__ -# ifndef __NR_name_to_handle_at -# define __NR_name_to_handle_at 370 -# endif -#elif defined __powerpc__ -# ifndef __NR_name_to_handle_at -# define __NR_name_to_handle_at 345 -# endif -#else -# ifndef __NR_name_to_handle_at -# error __NR_name_to_handle_at is not defined -# endif -#endif - -#if !HAVE_DECL_NAME_TO_HANDLE_AT -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { - return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); -} -#endif - -#ifndef HAVE_SECURE_GETENV -# ifdef HAVE___SECURE_GETENV -# define secure_getenv __secure_getenv -# else -# error neither secure_getenv nor __secure_getenv are available -# endif -#endif - -#ifndef CIFS_MAGIC_NUMBER -#define CIFS_MAGIC_NUMBER 0xFF534D42 -#endif diff --git a/src/shared/mkdir.c b/src/shared/mkdir.c deleted file mode 100644 index 0e51b64f69..0000000000 --- a/src/shared/mkdir.c +++ /dev/null @@ -1,147 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> - -#include "mkdir.h" -#include "label.h" -#include "util.h" - -int mkdir_label(const char *path, mode_t mode) { - return label_mkdir(path, mode, true); -} - -static int makedir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool apply) { - struct stat st; - - if (label_mkdir(path, mode, apply) >= 0) - if (chmod_and_chown(path, mode, uid, gid) < 0) - return -errno; - - if (lstat(path, &st) < 0) - return -errno; - - if ((st.st_mode & 0777) != mode || - st.st_uid != uid || - st.st_gid != gid || - !S_ISDIR(st.st_mode)) { - errno = EEXIST; - return -errno; - } - - return 0; -} - -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) { - return makedir_safe(path, mode, uid, gid, false); -} - -int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) { - return makedir_safe(path, mode, uid, gid, true); -} - -static int makedir_parents(const char *path, mode_t mode, bool apply) { - struct stat st; - const char *p, *e; - - assert(path); - - /* return immediately if directory exists */ - e = strrchr(path, '/'); - if (!e) - return -EINVAL; - p = strndupa(path, e - path); - if (stat(p, &st) >= 0) { - if ((st.st_mode & S_IFMT) == S_IFDIR) - return 0; - else - return -ENOTDIR; - } - - /* create every parent directory in the path, except the last component */ - p = path + strspn(path, "/"); - for (;;) { - int r; - char *t; - - e = p + strcspn(p, "/"); - p = e + strspn(e, "/"); - - /* Is this the last component? If so, then we're - * done */ - if (*p == 0) - return 0; - - t = strndup(path, e - path); - if (!t) - return -ENOMEM; - - r = label_mkdir(t, mode, apply); - free(t); - - if (r < 0 && errno != EEXIST) - return -errno; - } -} - -int mkdir_parents(const char *path, mode_t mode) { - return makedir_parents(path, mode, false); -} - -int mkdir_parents_label(const char *path, mode_t mode) { - return makedir_parents(path, mode, true); -} - -static int is_dir(const char* path) { - struct stat st; - if (stat(path, &st) < 0) - return -errno; - return S_ISDIR(st.st_mode); -} - -static int makedir_p(const char *path, mode_t mode, bool apply) { - int r; - - /* Like mkdir -p */ - - r = makedir_parents(path, mode, apply); - if (r < 0) - return r; - - r = label_mkdir(path, mode, apply); - if (r < 0 && (errno != EEXIST || is_dir(path) <= 0)) - return -errno; - - return 0; -} - -int mkdir_p(const char *path, mode_t mode) { - return makedir_p(path, mode, false); -} - -int mkdir_p_label(const char *path, mode_t mode) { - return makedir_p(path, mode, true); -} diff --git a/src/shared/mkdir.h b/src/shared/mkdir.h deleted file mode 100644 index ce1c35e9ba..0000000000 --- a/src/shared/mkdir.h +++ /dev/null @@ -1,32 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foomkdirhfoo -#define foomkdirhfoo - -/*** - 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/>. -***/ - -int mkdir_label(const char *path, mode_t mode); -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid); -int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid); -int mkdir_parents(const char *path, mode_t mode); -int mkdir_parents_label(const char *path, mode_t mode); -int mkdir_p(const char *path, mode_t mode); -int mkdir_p_label(const char *path, mode_t mode); -#endif diff --git a/src/shared/pager.c b/src/shared/pager.c deleted file mode 100644 index 488a12c763..0000000000 --- a/src/shared/pager.c +++ /dev/null @@ -1,143 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <sys/types.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <sys/prctl.h> - -#include "pager.h" -#include "util.h" -#include "macro.h" - -static pid_t pager_pid = 0; - -_noreturn_ static void pager_fallback(void) { - ssize_t n; - do { - n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0); - } while (n > 0); - if (n < 0) { - log_error("Internal pager failed: %m"); - _exit(EXIT_FAILURE); - } - _exit(EXIT_SUCCESS); -} - -int pager_open(void) { - int fd[2]; - 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; - - /* Determine and cache number of columns before we spawn the - * pager so that we get the value from the actual tty */ - columns(); - - if (pipe(fd) < 0) { - log_error("Failed to create pager pipe: %m"); - return -errno; - } - - parent_pid = getpid(); - - pager_pid = fork(); - if (pager_pid < 0) { - r = -errno; - log_error("Failed to fork pager: %m"); - close_pipe(fd); - return r; - } - - /* In the child start the pager */ - if (pager_pid == 0) { - - dup2(fd[0], STDIN_FILENO); - close_pipe(fd); - - setenv("LESS", "FRSX", 0); - - /* Make sure the pager goes away when the parent dies */ - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) - _exit(EXIT_FAILURE); - - /* Check whether our parent died before we were able - * to set the death signal */ - if (getppid() != parent_pid) - _exit(EXIT_SUCCESS); - - if (pager) { - execlp(pager, pager, NULL); - execl("/bin/sh", "sh", "-c", pager, NULL); - } - - /* Debian's alternatives command for pagers is - * called 'pager'. Note that we do not call - * sensible-pagers here, since that is just a - * shell script that implements a logic that - * is similar to this one anyway, but is - * Debian-specific. */ - execlp("pager", "pager", NULL); - - execlp("less", "less", NULL); - execlp("more", "more", NULL); - - pager_fallback(); - /* not reached */ - } - - /* Return in the parent */ - if (dup2(fd[1], STDOUT_FILENO) < 0) { - log_error("Failed to duplicate pager pipe: %m"); - return -errno; - } - - close_pipe(fd); - return 1; -} - -void pager_close(void) { - - if (pager_pid <= 0) - return; - - /* Inform pager that we are done */ - fclose(stdout); - kill(pager_pid, SIGCONT); - wait_for_terminate(pager_pid, NULL); - pager_pid = 0; -} - -bool pager_have(void) { - return pager_pid > 0; -} diff --git a/src/shared/pager.h b/src/shared/pager.h deleted file mode 100644 index 5e7b5ab91e..0000000000 --- a/src/shared/pager.h +++ /dev/null @@ -1,28 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdbool.h> - -int pager_open(void); -void pager_close(void); -bool pager_have(void); diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c deleted file mode 100644 index 6e5529e0c7..0000000000 --- a/src/shared/path-lookup.c +++ /dev/null @@ -1,430 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include "util.h" -#include "mkdir.h" -#include "strv.h" -#include "path-util.h" -#include "path-lookup.h" - -static const char* const systemd_running_as_table[_SYSTEMD_RUNNING_AS_MAX] = { - [SYSTEMD_SYSTEM] = "system", - [SYSTEMD_USER] = "user" -}; - -DEFINE_STRING_TABLE_LOOKUP(systemd_running_as, SystemdRunningAs); - -int user_config_home(char **config_home) { - const char *e; - - e = getenv("XDG_CONFIG_HOME"); - if (e) { - if (asprintf(config_home, "%s/systemd/user", e) < 0) - return -ENOMEM; - - return 1; - } else { - const char *home; - - home = getenv("HOME"); - if (home) { - if (asprintf(config_home, "%s/.config/systemd/user", home) < 0) - return -ENOMEM; - - return 1; - } - } - - return 0; -} - -static char** user_dirs( - const char *generator, - const char *generator_early, - const char *generator_late) { - - const char * const config_unit_paths[] = { - USER_CONFIG_UNIT_PATH, - "/etc/systemd/user", - "/run/systemd/user", - NULL - }; - - const char * const data_unit_paths[] = { - "/usr/local/lib/systemd/user", - "/usr/local/share/systemd/user", - USER_DATA_UNIT_PATH, - "/usr/lib/systemd/user", - "/usr/share/systemd/user", - NULL - }; - - const char *home, *e; - char *config_home = NULL, *data_home = NULL; - char **config_dirs = NULL, **data_dirs = NULL; - char **r = NULL, **t; - - /* Implement the mechanisms defined in - * - * http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html - * - * We look in both the config and the data dirs because we - * want to encourage that distributors ship their unit files - * as data, and allow overriding as configuration. - */ - - if (user_config_home(&config_home) < 0) - goto fail; - - home = getenv("HOME"); - - e = getenv("XDG_CONFIG_DIRS"); - if (e) { - config_dirs = strv_split(e, ":"); - if (!config_dirs) - goto fail; - } - - /* We don't treat /etc/xdg/systemd here as the spec - * suggests because we assume that that is a link to - * /etc/systemd/ anyway. */ - - e = getenv("XDG_DATA_HOME"); - if (e) { - if (asprintf(&data_home, "%s/systemd/user", e) < 0) - goto fail; - - } else if (home) { - if (asprintf(&data_home, "%s/.local/share/systemd/user", home) < 0) - goto fail; - - /* There is really no need for two unit dirs in $HOME, - * except to be fully compliant with the XDG spec. We - * now try to link the two dirs, so that we can - * minimize disk seeks a little. Further down we'll - * then filter out this link, if it is actually is - * one. */ - - mkdir_parents_label(data_home, 0777); - (void) symlink("../../../.config/systemd/user", data_home); - } - - e = getenv("XDG_DATA_DIRS"); - if (e) - data_dirs = strv_split(e, ":"); - else - data_dirs = strv_new("/usr/local/share", - "/usr/share", - NULL); - if (!data_dirs) - goto fail; - - /* Now merge everything we found. */ - if (generator_early) { - t = strv_append(r, generator_early); - if (!t) - goto fail; - strv_free(r); - r = t; - } - - if (config_home) { - t = strv_append(r, config_home); - if (!t) - goto fail; - strv_free(r); - r = t; - } - - if (!strv_isempty(config_dirs)) { - t = strv_merge_concat(r, config_dirs, "/systemd/user"); - if (!t) - goto finish; - strv_free(r); - r = t; - } - - t = strv_merge(r, (char**) config_unit_paths); - if (!t) - goto fail; - strv_free(r); - r = t; - - if (generator) { - t = strv_append(r, generator); - if (!t) - goto fail; - strv_free(r); - r = t; - } - - if (data_home) { - t = strv_append(r, data_home); - if (!t) - goto fail; - strv_free(r); - r = t; - } - - if (!strv_isempty(data_dirs)) { - t = strv_merge_concat(r, data_dirs, "/systemd/user"); - if (!t) - goto fail; - strv_free(r); - r = t; - } - - t = strv_merge(r, (char**) data_unit_paths); - if (!t) - goto fail; - strv_free(r); - r = t; - - if (generator_late) { - t = strv_append(r, generator_late); - if (!t) - goto fail; - strv_free(r); - r = t; - } - - if (!path_strv_make_absolute_cwd(r)) - goto fail; - -finish: - free(config_home); - strv_free(config_dirs); - free(data_home); - strv_free(data_dirs); - - return r; - -fail: - strv_free(r); - r = NULL; - goto finish; -} - -int lookup_paths_init( - LookupPaths *p, - SystemdRunningAs running_as, - bool personal, - const char *generator, - const char *generator_early, - const char *generator_late) { - - const char *e; - char *t; - - assert(p); - - /* First priority is whatever has been passed to us via env - * vars */ - e = getenv("SYSTEMD_UNIT_PATH"); - if (e) { - p->unit_path = path_split_and_make_absolute(e); - if (!p->unit_path) - return -ENOMEM; - } else - p->unit_path = NULL; - - if (strv_isempty(p->unit_path)) { - /* Nothing is set, so let's figure something out. */ - strv_free(p->unit_path); - - /* For the user units we include share/ in the search - * path in order to comply with the XDG basedir - * spec. For the system stuff we avoid such - * nonsense. OTOH we include /lib in the search path - * for the system stuff but avoid it for user - * stuff. */ - - if (running_as == SYSTEMD_USER) { - - if (personal) - p->unit_path = user_dirs(generator, generator_early, generator_late); - else - p->unit_path = strv_new( - /* If you modify this you also want to modify - * systemduserunitpath= in systemd.pc.in, and - * the arrays in user_dirs() above! */ - STRV_IFNOTNULL(generator_early), - USER_CONFIG_UNIT_PATH, - "/etc/systemd/user", - "/run/systemd/user", - STRV_IFNOTNULL(generator), - "/usr/local/lib/systemd/user", - "/usr/local/share/systemd/user", - USER_DATA_UNIT_PATH, - "/usr/lib/systemd/user", - "/usr/share/systemd/user", - STRV_IFNOTNULL(generator_late), - NULL); - - if (!p->unit_path) - return -ENOMEM; - - } else { - p->unit_path = strv_new( - /* If you modify this you also want to modify - * systemdsystemunitpath= in systemd.pc.in! */ - STRV_IFNOTNULL(generator_early), - SYSTEM_CONFIG_UNIT_PATH, - "/etc/systemd/system", - "/run/systemd/system", - STRV_IFNOTNULL(generator), - "/usr/local/lib/systemd/system", - SYSTEM_DATA_UNIT_PATH, - "/usr/lib/systemd/system", -#ifdef HAVE_SPLIT_USR - "/lib/systemd/system", -#endif - STRV_IFNOTNULL(generator_late), - NULL); - - if (!p->unit_path) - return -ENOMEM; - } - } - - if (!path_strv_canonicalize(p->unit_path)) - return -ENOMEM; - - strv_uniq(p->unit_path); - path_strv_remove_empty(p->unit_path); - - if (!strv_isempty(p->unit_path)) { - - t = strv_join(p->unit_path, "\n\t"); - if (!t) - return -ENOMEM; - log_debug("Looking for unit files in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring unit files."); - strv_free(p->unit_path); - p->unit_path = NULL; - } - - if (running_as == SYSTEMD_SYSTEM) { -#ifdef HAVE_SYSV_COMPAT - /* /etc/init.d/ compatibility does not matter to users */ - - e = getenv("SYSTEMD_SYSVINIT_PATH"); - if (e) { - p->sysvinit_path = path_split_and_make_absolute(e); - if (!p->sysvinit_path) - return -ENOMEM; - } else - p->sysvinit_path = NULL; - - if (strv_isempty(p->sysvinit_path)) { - strv_free(p->sysvinit_path); - - p->sysvinit_path = strv_new( - SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */ - NULL); - if (!p->sysvinit_path) - return -ENOMEM; - } - - e = getenv("SYSTEMD_SYSVRCND_PATH"); - if (e) { - p->sysvrcnd_path = path_split_and_make_absolute(e); - if (!p->sysvrcnd_path) - return -ENOMEM; - } else - p->sysvrcnd_path = NULL; - - if (strv_isempty(p->sysvrcnd_path)) { - strv_free(p->sysvrcnd_path); - - p->sysvrcnd_path = strv_new( - SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */ - NULL); - if (!p->sysvrcnd_path) - return -ENOMEM; - } - - if (!path_strv_canonicalize(p->sysvinit_path)) - return -ENOMEM; - - if (!path_strv_canonicalize(p->sysvrcnd_path)) - return -ENOMEM; - - strv_uniq(p->sysvinit_path); - strv_uniq(p->sysvrcnd_path); - path_strv_remove_empty(p->sysvinit_path); - path_strv_remove_empty(p->sysvrcnd_path); - - if (!strv_isempty(p->sysvinit_path)) { - - t = strv_join(p->sysvinit_path, "\n\t"); - if (!t) - return -ENOMEM; - log_debug("Looking for SysV init scripts in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring SysV init scripts."); - strv_free(p->sysvinit_path); - p->sysvinit_path = NULL; - } - - if (!strv_isempty(p->sysvrcnd_path)) { - - t = strv_join(p->sysvrcnd_path, "\n\t"); - if (!t) - return -ENOMEM; - - log_debug("Looking for SysV rcN.d links in:\n\t%s", t); - free(t); - } else { - log_debug("Ignoring SysV rcN.d links."); - strv_free(p->sysvrcnd_path); - p->sysvrcnd_path = NULL; - } -#else - log_debug("Disabled SysV init scripts and rcN.d links support"); -#endif - } - - return 0; -} - -void lookup_paths_free(LookupPaths *p) { - assert(p); - - strv_free(p->unit_path); - p->unit_path = NULL; - -#ifdef HAVE_SYSV_COMPAT - strv_free(p->sysvinit_path); - strv_free(p->sysvrcnd_path); - p->sysvinit_path = p->sysvrcnd_path = NULL; -#endif -} diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h deleted file mode 100644 index baef62228a..0000000000 --- a/src/shared/path-lookup.h +++ /dev/null @@ -1,45 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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/>. -***/ - -typedef struct LookupPaths { - char **unit_path; -#ifdef HAVE_SYSV_COMPAT - char **sysvinit_path; - char **sysvrcnd_path; -#endif -} LookupPaths; - -typedef enum SystemdRunningAs { - SYSTEMD_SYSTEM, - SYSTEMD_USER, - _SYSTEMD_RUNNING_AS_MAX, - _SYSTEMD_RUNNING_AS_INVALID = -1 -} SystemdRunningAs; - -const char* systemd_running_as_to_string(SystemdRunningAs i); -SystemdRunningAs systemd_running_as_from_string(const char *s); - -int user_config_home(char **config_home); - -int lookup_paths_init(LookupPaths *p, SystemdRunningAs running_as, bool personal, const char *generator, const char *generator_early, const char *generator_late); -void lookup_paths_free(LookupPaths *p); diff --git a/src/shared/path-util.c b/src/shared/path-util.c deleted file mode 100644 index 70c8a8af06..0000000000 --- a/src/shared/path-util.c +++ /dev/null @@ -1,419 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010-2012 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <signal.h> -#include <stdio.h> -#include <fcntl.h> -#include <dirent.h> -#include <sys/statvfs.h> - -#include "macro.h" -#include "util.h" -#include "log.h" -#include "strv.h" -#include "path-util.h" -#include "missing.h" - -bool path_is_absolute(const char *p) { - return p[0] == '/'; -} - -bool is_path(const char *p) { - return !!strchr(p, '/'); -} - -char *path_get_file_name(const char *p) { - char *r; - - assert(p); - - if ((r = strrchr(p, '/'))) - return r + 1; - - return (char*) p; -} - -int path_get_parent(const char *path, char **_r) { - const char *e, *a = NULL, *b = NULL, *p; - char *r; - bool slash = false; - - assert(path); - assert(_r); - - if (!*path) - return -EINVAL; - - for (e = path; *e; e++) { - - if (!slash && *e == '/') { - a = b; - b = e; - slash = true; - } else if (slash && *e != '/') - slash = false; - } - - if (*(e-1) == '/') - p = a; - else - p = b; - - if (!p) - return -EINVAL; - - if (p == path) - r = strdup("/"); - else - r = strndup(path, p-path); - - if (!r) - return -ENOMEM; - - *_r = r; - return 0; -} - -char **path_split_and_make_absolute(const char *p) { - char **l; - assert(p); - - if (!(l = strv_split(p, ":"))) - return NULL; - - if (!path_strv_make_absolute_cwd(l)) { - strv_free(l); - return NULL; - } - - return l; -} - -char *path_make_absolute(const char *p, const char *prefix) { - assert(p); - - /* Makes every item in the list an absolute path by prepending - * the prefix, if specified and necessary */ - - if (path_is_absolute(p) || !prefix) - return strdup(p); - - return strjoin(prefix, "/", p, NULL); -} - -char *path_make_absolute_cwd(const char *p) { - char *cwd, *r; - - assert(p); - - /* Similar to path_make_absolute(), but prefixes with the - * current working directory. */ - - if (path_is_absolute(p)) - return strdup(p); - - if (!(cwd = get_current_dir_name())) - return NULL; - - r = path_make_absolute(p, cwd); - free(cwd); - - return r; -} - -char **path_strv_make_absolute_cwd(char **l) { - char **s; - - /* Goes through every item in the string list and makes it - * absolute. This works in place and won't rollback any - * changes on failure. */ - - STRV_FOREACH(s, l) { - char *t; - - if (!(t = path_make_absolute_cwd(*s))) - return NULL; - - free(*s); - *s = t; - } - - return l; -} - -char **path_strv_canonicalize(char **l) { - char **s; - unsigned k = 0; - bool enomem = false; - - if (strv_isempty(l)) - return l; - - /* Goes through every item in the string list and canonicalize - * the path. This works in place and won't rollback any - * changes on failure. */ - - STRV_FOREACH(s, l) { - char *t, *u; - - t = path_make_absolute_cwd(*s); - free(*s); - - if (!t) { - enomem = true; - continue; - } - - errno = 0; - u = canonicalize_file_name(t); - free(t); - - if (!u) { - if (errno == ENOMEM || !errno) - enomem = true; - - continue; - } - - l[k++] = u; - } - - l[k] = NULL; - - if (enomem) - return NULL; - - return l; -} - -char **path_strv_remove_empty(char **l) { - char **f, **t; - - if (!l) - return NULL; - - for (f = t = l; *f; f++) { - - if (dir_is_empty(*f) > 0) { - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return l; -} - -char *path_kill_slashes(char *path) { - char *f, *t; - bool slash = false; - - /* Removes redundant inner and trailing slashes. Modifies the - * passed string in-place. - * - * ///foo///bar/ becomes /foo/bar - */ - - for (f = path, t = path; *f; f++) { - - if (*f == '/') { - slash = true; - continue; - } - - if (slash) { - slash = false; - *(t++) = '/'; - } - - *(t++) = *f; - } - - /* Special rule, if we are talking of the root directory, a - trailing slash is good */ - - if (t == path && slash) - *(t++) = '/'; - - *t = 0; - return path; -} - -char* path_startswith(const char *path, const char *prefix) { - assert(path); - assert(prefix); - - if ((path[0] == '/') != (prefix[0] == '/')) - return NULL; - - for (;;) { - size_t a, b; - - path += strspn(path, "/"); - prefix += strspn(prefix, "/"); - - if (*prefix == 0) - return (char*) path; - - if (*path == 0) - return NULL; - - a = strcspn(path, "/"); - b = strcspn(prefix, "/"); - - if (a != b) - return NULL; - - if (memcmp(path, prefix, a) != 0) - return NULL; - - path += a; - prefix += b; - } -} - -bool path_equal(const char *a, const char *b) { - assert(a); - assert(b); - - if ((a[0] == '/') != (b[0] == '/')) - return false; - - for (;;) { - size_t j, k; - - a += strspn(a, "/"); - b += strspn(b, "/"); - - if (*a == 0 && *b == 0) - return true; - - if (*a == 0 || *b == 0) - return false; - - j = strcspn(a, "/"); - k = strcspn(b, "/"); - - if (j != k) - return false; - - if (memcmp(a, b, j) != 0) - return false; - - a += j; - b += k; - } -} - -int path_is_mount_point(const char *t, bool allow_symlink) { - char *parent; - int r; - struct file_handle *h; - int mount_id, mount_id_parent; - struct stat a, b; - - /* 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 */ - - if (path_equal(t, "/")) - return 1; - - h = alloca(MAX_HANDLE_SZ); - h->handle_bytes = MAX_HANDLE_SZ; - - r = name_to_handle_at(AT_FDCWD, t, h, &mount_id, allow_symlink ? AT_SYMLINK_FOLLOW : 0); - if (r < 0) { - if (errno == ENOSYS || errno == ENOTSUP) - /* This kernel or file system does not support - * name_to_handle_at(), hence fallback to the - * traditional stat() logic */ - goto fallback; - - if (errno == ENOENT) - return 0; - - return -errno; - } - - r = path_get_parent(t, &parent); - if (r < 0) - return r; - - h->handle_bytes = MAX_HANDLE_SZ; - r = name_to_handle_at(AT_FDCWD, parent, h, &mount_id_parent, 0); - free(parent); - - if (r < 0) { - /* The parent can't do name_to_handle_at() but the - * directory we are interested in can? If so, it must - * be a mount point */ - if (errno == ENOTSUP) - return 1; - - return -errno; - } - - return mount_id != mount_id_parent; - -fallback: - if (allow_symlink) - r = stat(t, &a); - else - r = lstat(t, &a); - - if (r < 0) { - if (errno == ENOENT) - return 0; - - return -errno; - } - - r = path_get_parent(t, &parent); - if (r < 0) - return r; - - r = lstat(parent, &b); - free(parent); - - if (r < 0) - return -errno; - - return a.st_dev != b.st_dev; -} - -int path_is_read_only_fs(const char *path) { - struct statvfs st; - - assert(path); - - if (statvfs(path, &st) < 0) - return -errno; - - return !!(st.f_flag & ST_RDONLY); -} diff --git a/src/shared/path-util.h b/src/shared/path-util.h deleted file mode 100644 index e81821a28f..0000000000 --- a/src/shared/path-util.h +++ /dev/null @@ -1,45 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foopathutilhfoo -#define foopathutilhfoo - -/*** - This file is part of systemd. - - Copyright 2010-2012 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "stdbool.h" - -bool is_path(const char *p); -char **path_split_and_make_absolute(const char *p); -char *path_get_file_name(const char *p); -int path_get_parent(const char *path, char **parent); -bool path_is_absolute(const char *p); -char *path_make_absolute(const char *p, const char *prefix); -char *path_make_absolute_cwd(const char *p); -char *path_kill_slashes(char *path); -char *path_startswith(const char *path, const char *prefix); -bool path_equal(const char *a, const char *b); - -char **path_strv_make_absolute_cwd(char **l); -char **path_strv_canonicalize(char **l); -char **path_strv_remove_empty(char **l); - -int path_is_mount_point(const char *path, bool allow_symlink); -int path_is_read_only_fs(const char *path); - -#endif diff --git a/src/shared/polkit.c b/src/shared/polkit.c deleted file mode 100644 index 126096e64f..0000000000 --- a/src/shared/polkit.c +++ /dev/null @@ -1,163 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <sys/types.h> - -#include <errno.h> - -#include "util.h" -#include "dbus-common.h" -#include "polkit.h" - -int verify_polkit( - DBusConnection *c, - DBusMessage *request, - const char *action, - bool interactive, - bool *_challenge, - DBusError *error) { - - DBusMessage *m = NULL, *reply = NULL; - const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = ""; - const char *sender; - uint32_t flags = interactive ? 1 : 0; - pid_t pid_raw; - uint32_t pid_u32; - unsigned long long starttime_raw; - uint64_t starttime_u64; - DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant; - int r; - dbus_bool_t authorized = FALSE, challenge = FALSE; - unsigned long ul; - - assert(c); - assert(request); - - sender = dbus_message_get_sender(request); - if (!sender) - return -EINVAL; - - ul = dbus_bus_get_unix_user(c, sender, error); - if (ul == (unsigned long) -1) - return -EINVAL; - - /* Shortcut things for root, to avoid the PK roundtrip and dependency */ - if (ul == 0) - return 1; - - pid_raw = bus_get_unix_process_id(c, sender, error); - if (pid_raw == 0) - return -EINVAL; - - r = get_starttime_of_pid(pid_raw, &starttime_raw); - if (r < 0) - return r; - - m = dbus_message_new_method_call( - "org.freedesktop.PolicyKit1", - "/org/freedesktop/PolicyKit1/Authority", - "org.freedesktop.PolicyKit1.Authority", - "CheckAuthorization"); - if (!m) - return -ENOMEM; - - dbus_message_iter_init_append(m, &iter_msg); - - pid_u32 = (uint32_t) pid_raw; - starttime_u64 = (uint64_t) starttime_raw; - - if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) || - !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) || - !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) || - !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) || - !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) || - !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) || - !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) || - !dbus_message_iter_close_container(&iter_dict, &iter_variant) || - !dbus_message_iter_close_container(&iter_array, &iter_dict) || - !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) || - !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) || - !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) || - !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) || - !dbus_message_iter_close_container(&iter_dict, &iter_variant) || - !dbus_message_iter_close_container(&iter_array, &iter_dict) || - !dbus_message_iter_close_container(&iter_struct, &iter_array) || - !dbus_message_iter_close_container(&iter_msg, &iter_struct) || - !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) || - !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) || - !dbus_message_iter_close_container(&iter_msg, &iter_array) || - !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) || - !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) { - r = -ENOMEM; - goto finish; - } - - reply = dbus_connection_send_with_reply_and_block(c, m, -1, error); - if (!reply) { - r = -EIO; - goto finish; - } - - if (dbus_set_error_from_message(error, reply)) { - r = -EIO; - goto finish; - } - - if (!dbus_message_iter_init(reply, &iter_msg) || - dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) { - r = -EIO; - goto finish; - } - - dbus_message_iter_recurse(&iter_msg, &iter_struct); - - if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) { - r = -EIO; - goto finish; - } - - dbus_message_iter_get_basic(&iter_struct, &authorized); - - if (!dbus_message_iter_next(&iter_struct) || - dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) { - r = -EIO; - goto finish; - } - - dbus_message_iter_get_basic(&iter_struct, &challenge); - - if (authorized) - r = 1; - else if (_challenge) { - *_challenge = !!challenge; - r = 0; - } else - r = -EPERM; - -finish: - if (m) - dbus_message_unref(m); - - if (reply) - dbus_message_unref(reply); - - return r; -} diff --git a/src/shared/polkit.h b/src/shared/polkit.h deleted file mode 100644 index 6255d1f617..0000000000 --- a/src/shared/polkit.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdbool.h> -#include <dbus/dbus.h> - -int verify_polkit( - DBusConnection *c, - DBusMessage *request, - const char *action, - bool interactive, - bool *challenge, - DBusError *error); diff --git a/src/shared/ratelimit.c b/src/shared/ratelimit.c deleted file mode 100644 index 1054d52f97..0000000000 --- a/src/shared/ratelimit.c +++ /dev/null @@ -1,57 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> - -#include "ratelimit.h" -#include "log.h" - -/* Modelled after Linux' lib/ratelimit.c by Dave Young - * <hidave.darkstar@gmail.com>, which is licensed GPLv2. */ - -bool ratelimit_test(RateLimit *r) { - usec_t ts; - - assert(r); - - if (r->interval <= 0 || r->burst <= 0) - return true; - - ts = now(CLOCK_MONOTONIC); - - if (r->begin <= 0 || - r->begin + r->interval < ts) { - r->begin = ts; - - /* Reset counter */ - r->num = 0; - goto good; - } - - if (r->num <= r->burst) - goto good; - - return false; - -good: - r->num++; - return true; -} diff --git a/src/shared/ratelimit.h b/src/shared/ratelimit.h deleted file mode 100644 index 58efca7df1..0000000000 --- a/src/shared/ratelimit.h +++ /dev/null @@ -1,57 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 "util.h" - -typedef struct RateLimit { - usec_t interval; - usec_t begin; - unsigned burst; - unsigned num; -} RateLimit; - -#define RATELIMIT_DEFINE(_name, _interval, _burst) \ - RateLimit _name = { \ - .interval = (_interval), \ - .burst = (_burst), \ - .num = 0, \ - .begin = 0 \ - } - -#define RATELIMIT_INIT(v, _interval, _burst) \ - do { \ - RateLimit *_r = &(v); \ - _r->interval = (_interval); \ - _r->burst = (_burst); \ - _r->num = 0; \ - _r->begin = 0; \ - } while (false) - -#define RATELIMIT_RESET(v) \ - do { \ - RateLimit *_r = &(v); \ - _r->num = 0; \ - _r->begin = 0; \ - } while (false) - -bool ratelimit_test(RateLimit *r); diff --git a/src/shared/replace-var.c b/src/shared/replace-var.c deleted file mode 100644 index e11c57a43d..0000000000 --- a/src/shared/replace-var.c +++ /dev/null @@ -1,110 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 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 <string.h> - -#include "macro.h" -#include "util.h" -#include "replace-var.h" - -/* - * Generic infrastructure for replacing @FOO@ style variables in - * strings. Will call a callback for each replacement. - */ - -static int get_variable(const char *b, char **r) { - size_t k; - char *t; - - assert(b); - assert(r); - - if (*b != '@') - return 0; - - k = strspn(b + 1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_"); - if (k <= 0 || b[k+1] != '@') - return 0; - - t = strndup(b + 1, k); - if (!t) - return -ENOMEM; - - *r = t; - return 1; -} - -char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata) { - char *r, *t; - const char *f; - size_t l; - - assert(text); - assert(lookup); - - l = strlen(text); - r = new(char, l+1); - if (!r) - return NULL; - - f = text; - t = r; - while (*f) { - _cleanup_free_ char *v = NULL, *n = NULL; - char *a; - int k; - size_t skip, d, nl; - - k = get_variable(f, &v); - if (k < 0) - goto oom; - if (k == 0) { - *(t++) = *(f++); - continue; - } - - n = lookup(v, userdata); - if (!n) - goto oom; - - skip = strlen(v) + 2; - - d = t - r; - nl = l - skip + strlen(n); - a = realloc(r, nl + 1); - if (!a) - goto oom; - - l = nl; - r = a; - t = r + d; - - t = stpcpy(t, n); - f += skip; - } - - *t = 0; - return r; - -oom: - free(r); - return NULL; -} diff --git a/src/shared/replace-var.h b/src/shared/replace-var.h deleted file mode 100644 index 7eaee93a3e..0000000000 --- a/src/shared/replace-var.h +++ /dev/null @@ -1,24 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 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/>. -***/ - -char *replace_var(const char *text, char *(*lookup)(const char *variable, void*userdata), void *userdata); diff --git a/src/shared/selinux-util.c b/src/shared/selinux-util.c deleted file mode 100644 index ff3375607f..0000000000 --- a/src/shared/selinux-util.c +++ /dev/null @@ -1,42 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 "selinux-util.h" - -#ifdef HAVE_SELINUX - -#include <selinux/selinux.h> - -static int use_selinux_cached = -1; - -bool use_selinux(void) { - - if (use_selinux_cached < 0) - use_selinux_cached = is_selinux_enabled() > 0; - - return use_selinux_cached; -} - -void retest_selinux(void) { - use_selinux_cached = -1; -} - -#endif diff --git a/src/shared/selinux-util.h b/src/shared/selinux-util.h deleted file mode 100644 index 4b81202741..0000000000 --- a/src/shared/selinux-util.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdbool.h> - -bool use_selinux(void); -void retest_selinux(void); diff --git a/src/shared/set.c b/src/shared/set.c deleted file mode 100644 index 5f83c50839..0000000000 --- a/src/shared/set.c +++ /dev/null @@ -1,130 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <stdlib.h> - -#include "set.h" -#include "hashmap.h" - -#define MAKE_SET(h) ((Set*) (h)) -#define MAKE_HASHMAP(s) ((Hashmap*) (s)) - -/* For now this is not much more than a wrapper around a hashmap */ - -Set *set_new(hash_func_t hash_func, compare_func_t compare_func) { - return MAKE_SET(hashmap_new(hash_func, compare_func)); -} - -void set_free(Set* s) { - hashmap_free(MAKE_HASHMAP(s)); -} - -void set_free_free(Set *s) { - hashmap_free_free(MAKE_HASHMAP(s)); -} - -int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func) { - return hashmap_ensure_allocated((Hashmap**) s, hash_func, compare_func); -} - -int set_put(Set *s, void *value) { - return hashmap_put(MAKE_HASHMAP(s), value, value); -} - -int set_replace(Set *s, void *value) { - return hashmap_replace(MAKE_HASHMAP(s), value, value); -} - -void *set_get(Set *s, void *value) { - return hashmap_get(MAKE_HASHMAP(s), value); -} - -bool set_contains(Set *s, void *value) { - return hashmap_contains(MAKE_HASHMAP(s), value); -} - -void *set_remove(Set *s, void *value) { - return hashmap_remove(MAKE_HASHMAP(s), value); -} - -int set_remove_and_put(Set *s, void *old_value, void *new_value) { - return hashmap_remove_and_put(MAKE_HASHMAP(s), old_value, new_value, new_value); -} - -unsigned set_size(Set *s) { - return hashmap_size(MAKE_HASHMAP(s)); -} - -bool set_isempty(Set *s) { - return hashmap_isempty(MAKE_HASHMAP(s)); -} - -void *set_iterate(Set *s, Iterator *i) { - return hashmap_iterate(MAKE_HASHMAP(s), i, NULL); -} - -void *set_iterate_backwards(Set *s, Iterator *i) { - return hashmap_iterate_backwards(MAKE_HASHMAP(s), i, NULL); -} - -void *set_iterate_skip(Set *s, void *value, Iterator *i) { - return hashmap_iterate_skip(MAKE_HASHMAP(s), value, i); -} - -void *set_steal_first(Set *s) { - return hashmap_steal_first(MAKE_HASHMAP(s)); -} - -void* set_first(Set *s) { - return hashmap_first(MAKE_HASHMAP(s)); -} - -void* set_last(Set *s) { - return hashmap_last(MAKE_HASHMAP(s)); -} - -int set_merge(Set *s, Set *other) { - return hashmap_merge(MAKE_HASHMAP(s), MAKE_HASHMAP(other)); -} - -void set_move(Set *s, Set *other) { - return hashmap_move(MAKE_HASHMAP(s), MAKE_HASHMAP(other)); -} - -int set_move_one(Set *s, Set *other, void *value) { - return hashmap_move_one(MAKE_HASHMAP(s), MAKE_HASHMAP(other), value); -} - -Set* set_copy(Set *s) { - return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s))); -} - -void set_clear(Set *s) { - hashmap_clear(MAKE_HASHMAP(s)); -} - -void set_clear_free(Set *s) { - hashmap_clear_free(MAKE_HASHMAP(s)); -} - -char **set_get_strv(Set *s) { - return hashmap_get_strv(MAKE_HASHMAP(s)); -} diff --git a/src/shared/set.h b/src/shared/set.h deleted file mode 100644 index 9162e2ae80..0000000000 --- a/src/shared/set.h +++ /dev/null @@ -1,71 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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/>. -***/ - -/* Pretty straightforward set implementation. Internally based on the - * hashmap. That means that as a minor optimization a NULL set - * object will be treated as empty set for all read - * operations. That way it is not necessary to instantiate an object - * for each set use. */ - -#include "hashmap.h" - -typedef struct Set Set; - -Set *set_new(hash_func_t hash_func, compare_func_t compare_func); -void set_free(Set* s); -void set_free_free(Set *s); -Set* set_copy(Set *s); -int set_ensure_allocated(Set **s, hash_func_t hash_func, compare_func_t compare_func); - -int set_put(Set *s, void *value); -int set_replace(Set *s, void *value); -void *set_get(Set *s, void *value); -bool set_contains(Set *s, void *value); -void *set_remove(Set *s, void *value); -int set_remove_and_put(Set *s, void *old_value, void *new_value); - -int set_merge(Set *s, Set *other); -void set_move(Set *s, Set *other); -int set_move_one(Set *s, Set *other, void *value); - -unsigned set_size(Set *s); -bool set_isempty(Set *s); - -void *set_iterate(Set *s, Iterator *i); -void *set_iterate_backwards(Set *s, Iterator *i); -void *set_iterate_skip(Set *s, void *value, Iterator *i); - -void set_clear(Set *s); -void set_clear_free(Set *s); - -void *set_steal_first(Set *s); -void* set_first(Set *s); -void* set_last(Set *s); - -char **set_get_strv(Set *s); - -#define SET_FOREACH(e, s, i) \ - for ((i) = ITERATOR_FIRST, (e) = set_iterate((s), &(i)); (e); (e) = set_iterate((s), &(i))) - -#define SET_FOREACH_BACKWARDS(e, s, i) \ - for ((i) = ITERATOR_LAST, (e) = set_iterate_backwards((s), &(i)); (e); (e) = set_iterate_backwards((s), &(i))) diff --git a/src/shared/socket-label.c b/src/shared/socket-label.c deleted file mode 100644 index ff212de825..0000000000 --- a/src/shared/socket-label.c +++ /dev/null @@ -1,143 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <net/if.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <stddef.h> -#include <sys/ioctl.h> - -#include "macro.h" -#include "util.h" -#include "mkdir.h" -#include "socket-util.h" -#include "missing.h" -#include "label.h" - -int socket_address_listen( - const SocketAddress *a, - int backlog, - SocketAddressBindIPv6Only only, - const char *bind_to_device, - bool free_bind, - bool transparent, - mode_t directory_mode, - mode_t socket_mode, - const char *label, - int *ret) { - - int r, fd, one; - assert(a); - assert(ret); - - if ((r = socket_address_verify(a)) < 0) - return r; - - if (socket_address_family(a) == AF_INET6 && !socket_ipv6_is_supported()) - return -EAFNOSUPPORT; - - r = label_socket_set(label); - if (r < 0) - return r; - - fd = socket(socket_address_family(a), a->type | SOCK_NONBLOCK | SOCK_CLOEXEC, a->protocol); - r = fd < 0 ? -errno : 0; - - label_socket_clear(); - - if (r < 0) - return r; - - if (socket_address_family(a) == AF_INET6 && only != SOCKET_ADDRESS_DEFAULT) { - int flag = only == SOCKET_ADDRESS_IPV6_ONLY; - - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag)) < 0) - goto fail; - } - - if (socket_address_family(a) == AF_INET || socket_address_family(a) == AF_INET6) { - if (bind_to_device) - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0) - goto fail; - - if (free_bind) { - one = 1; - if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) - log_warning("IP_FREEBIND failed: %m"); - } - - if (transparent) { - one = 1; - if (setsockopt(fd, IPPROTO_IP, IP_TRANSPARENT, &one, sizeof(one)) < 0) - log_warning("IP_TRANSPARENT failed: %m"); - } - } - - one = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) - goto fail; - - if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { - mode_t old_mask; - - /* Create parents */ - mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); - - /* Enforce the right access mode for the socket*/ - old_mask = umask(~ socket_mode); - - /* Include the original umask in our mask */ - umask(~socket_mode | old_mask); - - r = label_bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0 && errno == EADDRINUSE) { - /* Unlink and try again */ - unlink(a->sockaddr.un.sun_path); - r = bind(fd, &a->sockaddr.sa, a->size); - } - - umask(old_mask); - } else - r = bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0) - goto fail; - - if (socket_address_can_accept(a)) - if (listen(fd, backlog) < 0) - goto fail; - - *ret = fd; - return 0; - -fail: - r = -errno; - close_nointr_nofail(fd); - return r; -} diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c deleted file mode 100644 index 49ea75880d..0000000000 --- a/src/shared/socket-util.c +++ /dev/null @@ -1,544 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <arpa/inet.h> -#include <stdio.h> -#include <net/if.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <stddef.h> -#include <sys/ioctl.h> - -#include "macro.h" -#include "util.h" -#include "mkdir.h" -#include "path-util.h" -#include "socket-util.h" -#include "missing.h" - -int socket_address_parse(SocketAddress *a, const char *s) { - int r; - char *e, *n; - unsigned u; - - assert(a); - assert(s); - - zero(*a); - a->type = SOCK_STREAM; - - if (*s == '[') { - /* IPv6 in [x:.....:z]:p notation */ - - if (!socket_ipv6_is_supported()) { - log_warning("Binding to IPv6 address not available since kernel does not support IPv6."); - return -EAFNOSUPPORT; - } - - if (!(e = strchr(s+1, ']'))) - return -EINVAL; - - if (!(n = strndup(s+1, e-s-1))) - return -ENOMEM; - - errno = 0; - if (inet_pton(AF_INET6, n, &a->sockaddr.in6.sin6_addr) <= 0) { - free(n); - return errno != 0 ? -errno : -EINVAL; - } - - free(n); - - e++; - if (*e != ':') - return -EINVAL; - - e++; - if ((r = safe_atou(e, &u)) < 0) - return r; - - if (u <= 0 || u > 0xFFFF) - return -EINVAL; - - a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); - a->size = sizeof(struct sockaddr_in6); - - } else if (*s == '/') { - /* AF_UNIX socket */ - - size_t l; - - l = strlen(s); - if (l >= sizeof(a->sockaddr.un.sun_path)) - return -EINVAL; - - a->sockaddr.un.sun_family = AF_UNIX; - memcpy(a->sockaddr.un.sun_path, s, l); - a->size = offsetof(struct sockaddr_un, sun_path) + l + 1; - - } else if (*s == '@') { - /* Abstract AF_UNIX socket */ - size_t l; - - l = strlen(s+1); - if (l >= sizeof(a->sockaddr.un.sun_path) - 1) - return -EINVAL; - - a->sockaddr.un.sun_family = AF_UNIX; - memcpy(a->sockaddr.un.sun_path+1, s+1, l); - a->size = offsetof(struct sockaddr_un, sun_path) + 1 + l; - - } else { - - if ((e = strchr(s, ':'))) { - - if ((r = safe_atou(e+1, &u)) < 0) - return r; - - if (u <= 0 || u > 0xFFFF) - return -EINVAL; - - if (!(n = strndup(s, e-s))) - return -ENOMEM; - - /* IPv4 in w.x.y.z:p notation? */ - if ((r = inet_pton(AF_INET, n, &a->sockaddr.in4.sin_addr)) < 0) { - free(n); - return -errno; - } - - if (r > 0) { - /* Gotcha, it's a traditional IPv4 address */ - free(n); - - a->sockaddr.in4.sin_family = AF_INET; - a->sockaddr.in4.sin_port = htons((uint16_t) u); - a->size = sizeof(struct sockaddr_in); - } else { - unsigned idx; - - if (strlen(n) > IF_NAMESIZE-1) { - free(n); - return -EINVAL; - } - - /* Uh, our last resort, an interface name */ - idx = if_nametoindex(n); - free(n); - - if (idx == 0) - return -EINVAL; - - if (!socket_ipv6_is_supported()) { - log_warning("Binding to interface is not available since kernel does not support IPv6."); - return -EAFNOSUPPORT; - } - - a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); - a->sockaddr.in6.sin6_scope_id = idx; - a->sockaddr.in6.sin6_addr = in6addr_any; - a->size = sizeof(struct sockaddr_in6); - } - } else { - - /* Just a port */ - r = safe_atou(s, &u); - if (r < 0) - return r; - - if (u <= 0 || u > 0xFFFF) - return -EINVAL; - - if (socket_ipv6_is_supported()) { - a->sockaddr.in6.sin6_family = AF_INET6; - a->sockaddr.in6.sin6_port = htons((uint16_t) u); - a->sockaddr.in6.sin6_addr = in6addr_any; - a->size = sizeof(struct sockaddr_in6); - } else { - a->sockaddr.in4.sin_family = AF_INET; - a->sockaddr.in4.sin_port = htons((uint16_t) u); - a->sockaddr.in4.sin_addr.s_addr = INADDR_ANY; - a->size = sizeof(struct sockaddr_in); - } - } - } - - return 0; -} - -int socket_address_parse_netlink(SocketAddress *a, const char *s) { - int family; - unsigned group = 0; - _cleanup_free_ char *sfamily = NULL; - assert(a); - assert(s); - - zero(*a); - a->type = SOCK_RAW; - - errno = 0; - if (sscanf(s, "%ms %u", &sfamily, &group) < 1) - return errno ? -errno : -EINVAL; - - family = netlink_family_from_string(sfamily); - if (family < 0) - return -EINVAL; - - a->sockaddr.nl.nl_family = AF_NETLINK; - a->sockaddr.nl.nl_groups = group; - - a->type = SOCK_RAW; - a->size = sizeof(struct sockaddr_nl); - a->protocol = family; - - return 0; -} - -int socket_address_verify(const SocketAddress *a) { - assert(a); - - switch (socket_address_family(a)) { - - case AF_INET: - if (a->size != sizeof(struct sockaddr_in)) - return -EINVAL; - - if (a->sockaddr.in4.sin_port == 0) - return -EINVAL; - - if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) - return -EINVAL; - - return 0; - - case AF_INET6: - if (a->size != sizeof(struct sockaddr_in6)) - return -EINVAL; - - if (a->sockaddr.in6.sin6_port == 0) - return -EINVAL; - - if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM) - return -EINVAL; - - return 0; - - case AF_UNIX: - if (a->size < offsetof(struct sockaddr_un, sun_path)) - return -EINVAL; - - if (a->size > offsetof(struct sockaddr_un, sun_path)) { - - if (a->sockaddr.un.sun_path[0] != 0) { - char *e; - - /* path */ - if (!(e = memchr(a->sockaddr.un.sun_path, 0, sizeof(a->sockaddr.un.sun_path)))) - return -EINVAL; - - if (a->size != offsetof(struct sockaddr_un, sun_path) + (e - a->sockaddr.un.sun_path) + 1) - return -EINVAL; - } - } - - if (a->type != SOCK_STREAM && a->type != SOCK_DGRAM && a->type != SOCK_SEQPACKET) - return -EINVAL; - - return 0; - - case AF_NETLINK: - - if (a->size != sizeof(struct sockaddr_nl)) - return -EINVAL; - - if (a->type != SOCK_RAW && a->type != SOCK_DGRAM) - return -EINVAL; - - return 0; - - default: - return -EAFNOSUPPORT; - } -} - -int socket_address_print(const SocketAddress *a, char **p) { - int r; - assert(a); - assert(p); - - if ((r = socket_address_verify(a)) < 0) - return r; - - switch (socket_address_family(a)) { - - case AF_INET: { - char *ret; - - if (!(ret = new(char, INET_ADDRSTRLEN+1+5+1))) - return -ENOMEM; - - if (!inet_ntop(AF_INET, &a->sockaddr.in4.sin_addr, ret, INET_ADDRSTRLEN)) { - free(ret); - return -errno; - } - - sprintf(strchr(ret, 0), ":%u", ntohs(a->sockaddr.in4.sin_port)); - *p = ret; - return 0; - } - - case AF_INET6: { - char *ret; - - if (!(ret = new(char, 1+INET6_ADDRSTRLEN+2+5+1))) - return -ENOMEM; - - ret[0] = '['; - if (!inet_ntop(AF_INET6, &a->sockaddr.in6.sin6_addr, ret+1, INET6_ADDRSTRLEN)) { - free(ret); - return -errno; - } - - sprintf(strchr(ret, 0), "]:%u", ntohs(a->sockaddr.in6.sin6_port)); - *p = ret; - return 0; - } - - case AF_UNIX: { - char *ret; - - if (a->size <= offsetof(struct sockaddr_un, sun_path)) { - - if (!(ret = strdup("<unnamed>"))) - return -ENOMEM; - - } else if (a->sockaddr.un.sun_path[0] == 0) { - /* abstract */ - - /* FIXME: We assume we can print the - * socket path here and that it hasn't - * more than one NUL byte. That is - * actually an invalid assumption */ - - if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1))) - return -ENOMEM; - - ret[0] = '@'; - memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1); - ret[sizeof(a->sockaddr.un.sun_path)] = 0; - - } else { - - if (!(ret = strdup(a->sockaddr.un.sun_path))) - return -ENOMEM; - } - - *p = ret; - return 0; - } - - case AF_NETLINK: { - char _cleanup_free_ *sfamily = NULL; - - r = netlink_family_to_string_alloc(a->protocol, &sfamily); - if (r < 0) - return r; - r = asprintf(p, "%s %u", sfamily, a->sockaddr.nl.nl_groups); - - return 0; - } - - default: - return -EINVAL; - } -} - -bool socket_address_can_accept(const SocketAddress *a) { - assert(a); - - return - a->type == SOCK_STREAM || - a->type == SOCK_SEQPACKET; -} - -bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) { - assert(a); - assert(b); - - /* Invalid addresses are unequal to all */ - if (socket_address_verify(a) < 0 || - socket_address_verify(b) < 0) - return false; - - if (a->type != b->type) - return false; - - if (a->size != b->size) - return false; - - if (socket_address_family(a) != socket_address_family(b)) - return false; - - switch (socket_address_family(a)) { - - case AF_INET: - if (a->sockaddr.in4.sin_addr.s_addr != b->sockaddr.in4.sin_addr.s_addr) - return false; - - if (a->sockaddr.in4.sin_port != b->sockaddr.in4.sin_port) - return false; - - break; - - case AF_INET6: - if (memcmp(&a->sockaddr.in6.sin6_addr, &b->sockaddr.in6.sin6_addr, sizeof(a->sockaddr.in6.sin6_addr)) != 0) - return false; - - if (a->sockaddr.in6.sin6_port != b->sockaddr.in6.sin6_port) - return false; - - break; - - case AF_UNIX: - - if ((a->sockaddr.un.sun_path[0] == 0) != (b->sockaddr.un.sun_path[0] == 0)) - return false; - - if (a->sockaddr.un.sun_path[0]) { - if (strncmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, sizeof(a->sockaddr.un.sun_path)) != 0) - return false; - } else { - if (memcmp(a->sockaddr.un.sun_path, b->sockaddr.un.sun_path, a->size) != 0) - return false; - } - - break; - - case AF_NETLINK: - - if (a->protocol != b->protocol) - return false; - - if (a->sockaddr.nl.nl_groups != b->sockaddr.nl.nl_groups) - return false; - - break; - - default: - /* Cannot compare, so we assume the addresses are different */ - return false; - } - - return true; -} - -bool socket_address_is(const SocketAddress *a, const char *s, int type) { - struct SocketAddress b; - - assert(a); - assert(s); - - if (socket_address_parse(&b, s) < 0) - return false; - - b.type = type; - - return socket_address_equal(a, &b); -} - -bool socket_address_is_netlink(const SocketAddress *a, const char *s) { - struct SocketAddress b; - - assert(a); - assert(s); - - if (socket_address_parse_netlink(&b, s) < 0) - return false; - - return socket_address_equal(a, &b); -} - -bool socket_address_needs_mount(const SocketAddress *a, const char *prefix) { - assert(a); - - if (socket_address_family(a) != AF_UNIX) - return false; - - if (a->sockaddr.un.sun_path[0] == 0) - return false; - - return path_startswith(a->sockaddr.un.sun_path, prefix); -} - -bool socket_ipv6_is_supported(void) { - char *l = 0; - bool enabled; - - if (access("/sys/module/ipv6", F_OK) != 0) - return 0; - - /* If we can't check "disable" parameter, assume enabled */ - if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0) - return 1; - - /* If module was loaded with disable=1 no IPv6 available */ - enabled = l[0] == '0'; - free(l); - - return enabled; -} - -static const char* const netlink_family_table[] = { - [NETLINK_ROUTE] = "route", - [NETLINK_FIREWALL] = "firewall", - [NETLINK_INET_DIAG] = "inet-diag", - [NETLINK_NFLOG] = "nflog", - [NETLINK_XFRM] = "xfrm", - [NETLINK_SELINUX] = "selinux", - [NETLINK_ISCSI] = "iscsi", - [NETLINK_AUDIT] = "audit", - [NETLINK_FIB_LOOKUP] = "fib-lookup", - [NETLINK_CONNECTOR] = "connector", - [NETLINK_NETFILTER] = "netfilter", - [NETLINK_IP6_FW] = "ip6-fw", - [NETLINK_DNRTMSG] = "dnrtmsg", - [NETLINK_KOBJECT_UEVENT] = "kobject-uevent", - [NETLINK_GENERIC] = "generic", - [NETLINK_SCSITRANSPORT] = "scsitransport", - [NETLINK_ECRYPTFS] = "ecryptfs" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX); - -static const char* const socket_address_bind_ipv6_only_table[_SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX] = { - [SOCKET_ADDRESS_DEFAULT] = "default", - [SOCKET_ADDRESS_BOTH] = "both", - [SOCKET_ADDRESS_IPV6_ONLY] = "ipv6-only" -}; - -DEFINE_STRING_TABLE_LOOKUP(socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); diff --git a/src/shared/socket-util.h b/src/shared/socket-util.h deleted file mode 100644 index 04cfb83f5a..0000000000 --- a/src/shared/socket-util.h +++ /dev/null @@ -1,99 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <sys/socket.h> -#include <netinet/in.h> -#include <sys/un.h> -#include <net/if.h> -#include <asm/types.h> -#include <linux/netlink.h> - -#include "macro.h" -#include "util.h" - -union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in4; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_nl nl; - struct sockaddr_storage storage; -}; - -typedef struct SocketAddress { - union sockaddr_union sockaddr; - - /* We store the size here explicitly due to the weird - * sockaddr_un semantics for abstract sockets */ - socklen_t size; - - /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */ - int type; - - /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */ - int protocol; -} SocketAddress; - -typedef enum SocketAddressBindIPv6Only { - SOCKET_ADDRESS_DEFAULT, - SOCKET_ADDRESS_BOTH, - SOCKET_ADDRESS_IPV6_ONLY, - _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX, - _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1 -} SocketAddressBindIPv6Only; - -#define socket_address_family(a) ((a)->sockaddr.sa.sa_family) - -int socket_address_parse(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); - -bool socket_address_can_accept(const SocketAddress *a); - -int socket_address_listen( - const SocketAddress *a, - int backlog, - SocketAddressBindIPv6Only only, - const char *bind_to_device, - bool free_bind, - bool transparent, - mode_t directory_mode, - mode_t socket_mode, - const char *label, - int *ret); - -bool socket_address_is(const SocketAddress *a, const char *s, int type); -bool socket_address_is_netlink(const SocketAddress *a, const char *s); - -bool socket_address_equal(const SocketAddress *a, const SocketAddress *b); - -bool socket_address_needs_mount(const SocketAddress *a, const char *prefix); - -const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b); -SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s); - -int netlink_family_to_string_alloc(int b, char **s); -int netlink_family_from_string(const char *s); - -bool socket_ipv6_is_supported(void); diff --git a/src/shared/sparse-endian.h b/src/shared/sparse-endian.h deleted file mode 100644 index eb4dbf3615..0000000000 --- a/src/shared/sparse-endian.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (c) 2012 Josh Triplett <josh@joshtriplett.org> - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef SPARSE_ENDIAN_H -#define SPARSE_ENDIAN_H - -#include <endian.h> -#include <stdint.h> - -#ifdef __CHECKER__ -#define __bitwise __attribute__((bitwise)) -#define __force __attribute__((force)) -#else -#define __bitwise -#define __force -#endif - -typedef uint16_t __bitwise le16_t; -typedef uint16_t __bitwise be16_t; -typedef uint32_t __bitwise le32_t; -typedef uint32_t __bitwise be32_t; -typedef uint64_t __bitwise le64_t; -typedef uint64_t __bitwise be64_t; - -#undef htobe16 -#undef htole16 -#undef be16toh -#undef le16toh -#undef htobe32 -#undef htole32 -#undef be32toh -#undef le32toh -#undef htobe64 -#undef htole64 -#undef be64toh -#undef le64toh - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define bswap_16_on_le(x) __bswap_16(x) -#define bswap_32_on_le(x) __bswap_32(x) -#define bswap_64_on_le(x) __bswap_64(x) -#define bswap_16_on_be(x) (x) -#define bswap_32_on_be(x) (x) -#define bswap_64_on_be(x) (x) -#elif __BYTE_ORDER == __BIG_ENDIAN -#define bswap_16_on_le(x) (x) -#define bswap_32_on_le(x) (x) -#define bswap_64_on_le(x) (x) -#define bswap_16_on_be(x) __bswap_16(x) -#define bswap_32_on_be(x) __bswap_32(x) -#define bswap_64_on_be(x) __bswap_64(x) -#endif - -static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } -static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } -static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } - -static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } -static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } -static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } - -static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } -static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } -static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } - -static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } -static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } -static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } - -#endif /* SPARSE_ENDIAN_H */ diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c deleted file mode 100644 index c1a9c58681..0000000000 --- a/src/shared/spawn-ask-password-agent.c +++ /dev/null @@ -1,67 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <sys/types.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <sys/prctl.h> -#include <signal.h> -#include <fcntl.h> - -#include "log.h" -#include "util.h" -#include "spawn-ask-password-agent.h" - -static pid_t agent_pid = 0; - -int ask_password_agent_open(void) { - int r; - - if (agent_pid > 0) - return 0; - - /* We check STDIN here, not STDOUT, since this is about input, - * not output */ - if (!isatty(STDIN_FILENO)) - return 0; - - r = fork_agent(&agent_pid, - NULL, 0, - SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, - SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL); - if (r < 0) - log_error("Failed to fork TTY ask password agent: %s", strerror(-r)); - - return r; -} - -void ask_password_agent_close(void) { - - if (agent_pid <= 0) - return; - - /* Inform agent that we are done */ - kill(agent_pid, SIGTERM); - kill(agent_pid, SIGCONT); - wait_for_terminate(agent_pid, NULL); - agent_pid = 0; -} diff --git a/src/shared/spawn-ask-password-agent.h b/src/shared/spawn-ask-password-agent.h deleted file mode 100644 index 31b4beab58..0000000000 --- a/src/shared/spawn-ask-password-agent.h +++ /dev/null @@ -1,25 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2011 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/>. -***/ - -int ask_password_agent_open(void); -void ask_password_agent_close(void); diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c deleted file mode 100644 index fcb3722ddf..0000000000 --- a/src/shared/spawn-polkit-agent.c +++ /dev/null @@ -1,86 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <sys/types.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <sys/prctl.h> -#include <signal.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/poll.h> - -#include "log.h" -#include "util.h" -#include "spawn-polkit-agent.h" - -static pid_t agent_pid = 0; - -int polkit_agent_open(void) { - int r; - int pipe_fd[2]; - char notify_fd[10 + 1]; - - if (agent_pid > 0) - return 0; - - /* We check STDIN here, not STDOUT, since this is about input, - * not output */ - if (!isatty(STDIN_FILENO)) - return 0; - - if (pipe2(pipe_fd, 0) < 0) - return -errno; - - snprintf(notify_fd, sizeof(notify_fd), "%i", pipe_fd[1]); - char_array_0(notify_fd); - - r = fork_agent(&agent_pid, - &pipe_fd[1], 1, - POLKIT_AGENT_BINARY_PATH, - POLKIT_AGENT_BINARY_PATH, "--notify-fd", notify_fd, "--fallback", NULL); - - /* Close the writing side, because that's the one for the agent */ - close_nointr_nofail(pipe_fd[1]); - - if (r < 0) - log_error("Failed to fork TTY ask password agent: %s", strerror(-r)); - else - /* Wait until the agent closes the fd */ - fd_wait_for_event(pipe_fd[0], POLLHUP, (usec_t) -1); - - close_nointr_nofail(pipe_fd[0]); - - return r; -} - -void polkit_agent_close(void) { - - if (agent_pid <= 0) - return; - - /* Inform agent that we are done */ - kill(agent_pid, SIGTERM); - kill(agent_pid, SIGCONT); - wait_for_terminate(agent_pid, NULL); - agent_pid = 0; -} diff --git a/src/shared/spawn-polkit-agent.h b/src/shared/spawn-polkit-agent.h deleted file mode 100644 index b91d20f120..0000000000 --- a/src/shared/spawn-polkit-agent.h +++ /dev/null @@ -1,28 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foospawnpolkitagenthfoo -#define foospawnpolkitagenthfoo - -/*** - This file is part of systemd. - - Copyright 2012 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/>. -***/ - -int polkit_agent_open(void); -void polkit_agent_close(void); - -#endif diff --git a/src/shared/specifier.c b/src/shared/specifier.c deleted file mode 100644 index 599027cd47..0000000000 --- a/src/shared/specifier.c +++ /dev/null @@ -1,111 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <string.h> - -#include "macro.h" -#include "util.h" -#include "specifier.h" - -/* - * Generic infrastructure for replacing %x style specifiers in - * strings. Will call a callback for each replacement. - * - */ - -char *specifier_printf(const char *text, const Specifier table[], void *userdata) { - char *r, *t; - const char *f; - bool percent = false; - size_t l; - - assert(text); - assert(table); - - l = strlen(text); - r = new(char, l+1); - if (!r) - return NULL; - - t = r; - - for (f = text; *f; f++, l--) { - - if (percent) { - if (*f == '%') - *(t++) = '%'; - else { - const Specifier *i; - - for (i = table; i->specifier; i++) - if (i->specifier == *f) - break; - - if (i->lookup) { - char *n, *w; - size_t k, j; - - w = i->lookup(i->specifier, i->data, userdata); - if (!w) { - free(r); - return NULL; - } - - j = t - r; - k = strlen(w); - - n = new(char, j + k + l + 1); - if (!n) { - free(r); - free(w); - return NULL; - } - - memcpy(n, r, j); - memcpy(n + j, w, k); - - free(r); - free(w); - - r = n; - t = n + j + k; - } else { - *(t++) = '%'; - *(t++) = *f; - } - } - - percent = false; - } else if (*f == '%') - percent = true; - else - *(t++) = *f; - } - - *t = 0; - return r; -} - -/* Generic handler for simple string replacements */ - -char* specifier_string(char specifier, void *data, void *userdata) { - return strdup(strempty(data)); -} diff --git a/src/shared/specifier.h b/src/shared/specifier.h deleted file mode 100644 index 25a27a423f..0000000000 --- a/src/shared/specifier.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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/>. -***/ - -typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata); - -typedef struct Specifier { - const char specifier; - const SpecifierCallback lookup; - void *data; -} Specifier; - -char *specifier_printf(const char *text, const Specifier table[], void *userdata); - -char* specifier_string(char specifier, void *data, void *userdata); diff --git a/src/shared/strbuf.c b/src/shared/strbuf.c deleted file mode 100644 index 915cd3ac99..0000000000 --- a/src/shared/strbuf.c +++ /dev/null @@ -1,176 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 Kay Sievers <kay@vrfy.org> - - 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 <stdlib.h> -#include <string.h> - -#include "util.h" -#include "strbuf.h" - -/* - * Strbuf stores given strings in a single continous allocated memory - * area. Identical strings are de-duplicated and return the same offset - * as the first string stored. If the tail of a string already exists - * in the buffer, the tail is returned. - * - * A trie (http://en.wikipedia.org/wiki/Trie) is used to maintain the - * information about the stored strings. - * - * Example of udev rules: - * $ ./udevadm test . - * ... - * read rules file: /usr/lib/udev/rules.d/99-systemd.rules - * rules contain 196608 bytes tokens (16384 * 12 bytes), 39742 bytes strings - * 23939 strings (207859 bytes), 20404 de-duplicated (171653 bytes), 3536 trie nodes used - * ... - */ - -struct strbuf *strbuf_new(void) { - struct strbuf *str; - - str = new0(struct strbuf, 1); - if (!str) - return NULL; - - str->buf = new0(char, 1); - if (!str->buf) - goto err; - str->len = 1; - - str->root = new0(struct strbuf_node, 1); - if (!str->root) - goto err; - str->nodes_count = 1; - return str; -err: - free(str->buf); - free(str->root); - free(str); - return NULL; -} - -static void strbuf_node_cleanup(struct strbuf_node *node) { - size_t i; - - for (i = 0; i < node->children_count; i++) - strbuf_node_cleanup(node->children[i].child); - free(node->children); - free(node); -} - -/* clean up trie data, leave only the string buffer */ -void strbuf_complete(struct strbuf *str) { - if (!str) - return; - if (str->root) - strbuf_node_cleanup(str->root); - str->root = NULL; -} - -/* clean up everything */ -void strbuf_cleanup(struct strbuf *str) { - if (!str) - return; - if (str->root) - strbuf_node_cleanup(str->root); - free(str->buf); - free(str); -} - -static int strbuf_children_cmp(const void *v1, const void *v2) { - const struct strbuf_child_entry *n1 = v1; - const struct strbuf_child_entry *n2 = v2; - - return n1->c - n2->c; -} - -/* add string, return the index/offset into the buffer */ -ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) { - uint8_t c; - struct strbuf_node *node; - size_t depth; - char *buf_new; - struct strbuf_child_entry *child; - struct strbuf_node *node_child; - ssize_t off; - - if (!str->root) - return -EINVAL; - - /* search string; start from last character to find possibly matching tails */ - if (len == 0) - return 0; - str->in_count++; - str->in_len += len; - - node = str->root; - c = s[len-1]; - for (depth = 0; depth <= len; depth++) { - struct strbuf_child_entry search; - - /* match against current node */ - off = node->value_off + node->value_len - len; - if (depth == len || (node->value_len >= len && memcmp(str->buf + off, s, len) == 0)) { - str->dedup_len += len; - str->dedup_count++; - return off; - } - - /* lookup child node */ - c = s[len - 1 - depth]; - search.c = c; - child = bsearch(&search, node->children, node->children_count, sizeof(struct strbuf_child_entry), - strbuf_children_cmp); - if (!child) - break; - node = child->child; - } - - /* add new string */ - buf_new = realloc(str->buf, str->len + len+1); - if (!buf_new) - return -ENOMEM; - str->buf = buf_new; - off = str->len; - memcpy(str->buf + off, s, len); - str->len += len; - str->buf[str->len++] = '\0'; - - /* new node */ - node_child = new0(struct strbuf_node, 1); - if (!node_child) - return -ENOMEM; - str->nodes_count++; - node_child->value_off = off; - node_child->value_len = len; - - /* extend array, add new entry, sort for bisection */ - child = realloc(node->children, (node->children_count + 1) * sizeof(struct strbuf_child_entry)); - if (!child) - return -ENOMEM; - node->children = child; - node->children[node->children_count].c = c; - node->children[node->children_count].child = node_child; - node->children_count++; - qsort(node->children, node->children_count, sizeof(struct strbuf_child_entry), strbuf_children_cmp); - - return off; -} diff --git a/src/shared/strbuf.h b/src/shared/strbuf.h deleted file mode 100644 index 2347fd4328..0000000000 --- a/src/shared/strbuf.h +++ /dev/null @@ -1,56 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 Kay Sievers <kay@vrfy.org> - - 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 <stdarg.h> -#include <stdint.h> -#include <stdbool.h> - -struct strbuf { - char *buf; - size_t len; - struct strbuf_node *root; - - size_t nodes_count; - size_t in_count; - size_t in_len; - size_t dedup_len; - size_t dedup_count; -}; - -struct strbuf_node { - size_t value_off; - size_t value_len; - - struct strbuf_child_entry *children; - uint8_t children_count; -}; - -struct strbuf_child_entry { - uint8_t c; - struct strbuf_node *child; -}; - -struct strbuf *strbuf_new(void); -ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len); -void strbuf_complete(struct strbuf *str); -void strbuf_cleanup(struct strbuf *str); diff --git a/src/shared/strv.c b/src/shared/strv.c deleted file mode 100644 index 6b76d0eaef..0000000000 --- a/src/shared/strv.c +++ /dev/null @@ -1,750 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> - -#include "util.h" -#include "strv.h" - -char *strv_find(char **l, const char *name) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (streq(*i, name)) - return *i; - - return NULL; -} - -char *strv_find_prefix(char **l, const char *name) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (startswith(*i, name)) - return *i; - - return NULL; -} - -void strv_free(char **l) { - char **k; - - if (!l) - return; - - for (k = l; *k; k++) - free(*k); - - free(l); -} - -void strv_freep(char ***l) { - if (!l) - return; - - strv_free(*l); - *l = NULL; -} - -char **strv_copy(char **l) { - char **r, **k; - - k = r = new(char*, strv_length(l) + 1); - if (!r) - return NULL; - - if (l) - for (; *l; k++, l++) { - *k = strdup(*l); - if (!*k) { - strv_free(r); - return NULL; - } - } - - *k = NULL; - return r; -} - -unsigned strv_length(char **l) { - unsigned n = 0; - - if (!l) - return 0; - - for (; *l; l++) - n++; - - return n; -} - -char **strv_new_ap(const char *x, va_list ap) { - const char *s; - char **a; - unsigned n = 0, i = 0; - va_list aq; - - /* As a special trick we ignore all listed strings that equal - * (const char*) -1. This is supposed to be used with the - * STRV_IFNOTNULL() macro to include possibly NULL strings in - * the string list. */ - - if (x) { - n = x == (const char*) -1 ? 0 : 1; - - va_copy(aq, ap); - while ((s = va_arg(aq, const char*))) { - if (s == (const char*) -1) - continue; - - n++; - } - - va_end(aq); - } - - a = new(char*, n+1); - if (!a) - return NULL; - - if (x) { - if (x != (const char*) -1) { - a[i] = strdup(x); - if (!a[i]) - goto fail; - i++; - } - - while ((s = va_arg(ap, const char*))) { - - if (s == (const char*) -1) - continue; - - a[i] = strdup(s); - if (!a[i]) - goto fail; - - i++; - } - } - - a[i] = NULL; - - return a; - -fail: - strv_free(a); - return NULL; -} - -char **strv_new(const char *x, ...) { - char **r; - va_list ap; - - va_start(ap, x); - r = strv_new_ap(x, ap); - va_end(ap); - - return r; -} - -char **strv_merge(char **a, char **b) { - char **r, **k; - - if (!a) - return strv_copy(b); - - if (!b) - return strv_copy(a); - - r = new(char*, strv_length(a) + strv_length(b) + 1); - if (!r) - return NULL; - - for (k = r; *a; k++, a++) { - *k = strdup(*a); - if (!*k) - goto fail; - } - - for (; *b; k++, b++) { - *k = strdup(*b); - if (!*k) - goto fail; - } - - *k = NULL; - return r; - -fail: - strv_free(r); - return NULL; -} - -char **strv_merge_concat(char **a, char **b, const char *suffix) { - char **r, **k; - - /* Like strv_merge(), but appends suffix to all strings in b, before adding */ - - if (!b) - return strv_copy(a); - - r = new(char*, strv_length(a) + strv_length(b) + 1); - if (!r) - return NULL; - - k = r; - if (a) - for (; *a; k++, a++) { - *k = strdup(*a); - if (!*k) - goto fail; - } - - for (; *b; k++, b++) { - *k = strappend(*b, suffix); - if (!*k) - goto fail; - } - - *k = NULL; - return r; - -fail: - strv_free(r); - return NULL; - -} - -char **strv_split(const char *s, const char *separator) { - char *state; - char *w; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_SEPARATOR(w, l, s, separator, state) - n++; - - r = new(char*, n+1); - if (!r) - return NULL; - - i = 0; - FOREACH_WORD_SEPARATOR(w, l, s, separator, state) { - r[i] = strndup(w, l); - if (!r[i]) { - strv_free(r); - return NULL; - } - - i++; - } - - r[i] = NULL; - return r; -} - -char **strv_split_quoted(const char *s) { - char *state; - char *w; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_QUOTED(w, l, s, state) - n++; - - r = new(char*, n+1); - if (!r) - return NULL; - - i = 0; - FOREACH_WORD_QUOTED(w, l, s, state) { - r[i] = cunescape_length(w, l); - if (!r[i]) { - strv_free(r); - return NULL; - } - i++; - } - - r[i] = NULL; - return r; -} - -char *strv_join(char **l, const char *separator) { - char *r, *e; - char **s; - size_t n, k; - - if (!separator) - separator = " "; - - k = strlen(separator); - - n = 0; - STRV_FOREACH(s, l) { - if (n != 0) - n += k; - n += strlen(*s); - } - - r = new(char, n+1); - if (!r) - return NULL; - - e = r; - STRV_FOREACH(s, l) { - if (e != r) - e = stpcpy(e, separator); - - e = stpcpy(e, *s); - } - - *e = 0; - - return r; -} - -char **strv_append(char **l, const char *s) { - char **r, **k; - - if (!l) - return strv_new(s, NULL); - - if (!s) - return strv_copy(l); - - r = new(char*, strv_length(l)+2); - if (!r) - return NULL; - - for (k = r; *l; k++, l++) { - *k = strdup(*l); - if (!*k) - goto fail; - } - - k[0] = strdup(s); - if (!k[0]) - goto fail; - - k[1] = NULL; - return r; - -fail: - strv_free(r); - return NULL; -} - -char **strv_uniq(char **l) { - char **i; - - /* Drops duplicate entries. The first identical string will be - * kept, the others dropped */ - - STRV_FOREACH(i, l) - strv_remove(i+1, *i); - - return l; -} - -char **strv_remove(char **l, const char *s) { - char **f, **t; - - if (!l) - return NULL; - - assert(s); - - /* Drops every occurrence of s in the string list, edits - * in-place. */ - - for (f = t = l; *f; f++) { - - if (streq(*f, s)) { - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return l; -} - -char **strv_remove_prefix(char **l, const char *s) { - char **f, **t; - - if (!l) - return NULL; - - assert(s); - - /* Drops every occurrence of a string prefixed with s in the - * string list, edits in-place. */ - - for (f = t = l; *f; f++) { - - if (startswith(*f, s)) { - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return l; -} - -static int env_append(char **r, char ***k, char **a) { - assert(r); - assert(k); - - if (!a) - return 0; - - /* Add the entries of a to *k unless they already exist in *r - * in which case they are overridden instead. This assumes - * there is enough space in the r array. */ - - for (; *a; a++) { - char **j; - size_t n; - - n = strcspn(*a, "="); - - if ((*a)[n] == '=') - n++; - - for (j = r; j < *k; j++) - if (strncmp(*j, *a, n) == 0) - break; - - if (j >= *k) - (*k)++; - else - free(*j); - - *j = strdup(*a); - if (!*j) - return -ENOMEM; - } - - return 0; -} - -char **strv_env_merge(unsigned n_lists, ...) { - size_t n = 0; - char **l, **k, **r; - va_list ap; - unsigned i; - - /* Merges an arbitrary number of environment sets */ - - va_start(ap, n_lists); - for (i = 0; i < n_lists; i++) { - l = va_arg(ap, char**); - n += strv_length(l); - } - va_end(ap); - - r = new(char*, n+1); - if (!r) - return NULL; - - k = r; - - va_start(ap, n_lists); - for (i = 0; i < n_lists; i++) { - l = va_arg(ap, char**); - if (env_append(r, &k, l) < 0) - goto fail; - } - va_end(ap); - - *k = NULL; - - return r; - -fail: - va_end(ap); - strv_free(r); - - return NULL; -} - -static bool env_match(const char *t, const char *pattern) { - assert(t); - assert(pattern); - - /* pattern a matches string a - * a matches a= - * a matches a=b - * a= matches a= - * a=b matches a=b - * a= does not match a - * a=b does not match a= - * a=b does not match a - * a=b does not match a=c */ - - if (streq(t, pattern)) - return true; - - if (!strchr(pattern, '=')) { - size_t l = strlen(pattern); - - return strncmp(t, pattern, l) == 0 && t[l] == '='; - } - - return false; -} - -char **strv_env_delete(char **x, unsigned n_lists, ...) { - size_t n, i = 0; - char **k, **r; - va_list ap; - - /* Deletes every entry from x that is mentioned in the other - * string lists */ - - n = strv_length(x); - - r = new(char*, n+1); - if (!r) - return NULL; - - STRV_FOREACH(k, x) { - unsigned v; - - va_start(ap, n_lists); - for (v = 0; v < n_lists; v++) { - char **l, **j; - - l = va_arg(ap, char**); - STRV_FOREACH(j, l) - if (env_match(*k, *j)) - goto skip; - } - va_end(ap); - - r[i] = strdup(*k); - if (!r[i]) { - strv_free(r); - return NULL; - } - - i++; - continue; - - skip: - va_end(ap); - } - - r[i] = NULL; - - assert(i <= n); - - return r; -} - -char **strv_env_unset(char **l, const char *p) { - - char **f, **t; - - if (!l) - return NULL; - - assert(p); - - /* Drops every occurrence of the env var setting p in the - * string list. edits in-place. */ - - for (f = t = l; *f; f++) { - - if (env_match(*f, p)) { - free(*f); - continue; - } - - *(t++) = *f; - } - - *t = NULL; - return l; -} - -char **strv_env_set(char **x, const char *p) { - - char **k, **r; - char* m[2] = { (char*) p, NULL }; - - /* Overrides the env var setting of p, returns a new copy */ - - r = new(char*, strv_length(x)+2); - if (!r) - return NULL; - - k = r; - if (env_append(r, &k, x) < 0) - goto fail; - - if (env_append(r, &k, m) < 0) - goto fail; - - *k = NULL; - - return r; - -fail: - strv_free(r); - return NULL; - -} - -char *strv_env_get_with_length(char **l, const char *name, size_t k) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (strncmp(*i, name, k) == 0 && - (*i)[k] == '=') - return *i + k + 1; - - return NULL; -} - -char *strv_env_get(char **l, const char *name) { - return strv_env_get_with_length(l, name, strlen(name)); -} - -char **strv_env_clean(char **l) { - char **r, **ret; - - for (r = ret = l; *l; l++) { - const char *equal; - - equal = strchr(*l, '='); - - if (equal && equal[1] == 0) { - free(*l); - continue; - } - - *(r++) = *l; - } - - *r = NULL; - - return ret; -} - -char **strv_parse_nulstr(const char *s, size_t l) { - const char *p; - unsigned c = 0, i = 0; - char **v; - - assert(s || l <= 0); - - if (l <= 0) - return strv_new(NULL, NULL); - - for (p = s; p < s + l; p++) - if (*p == 0) - c++; - - if (s[l-1] != 0) - c++; - - v = new0(char*, c+1); - if (!v) - return NULL; - - p = s; - while (p < s + l) { - const char *e; - - e = memchr(p, 0, s + l - p); - - v[i] = strndup(p, e ? e - p : s + l - p); - if (!v[i]) { - strv_free(v); - return NULL; - } - - i++; - - if (!e) - break; - - p = e + 1; - } - - assert(i == c); - - return v; -} - -bool strv_overlap(char **a, char **b) { - char **i, **j; - - STRV_FOREACH(i, a) { - STRV_FOREACH(j, b) { - if (streq(*i, *j)) - return true; - } - } - - return false; -} - -static int str_compare(const void *_a, const void *_b) { - const char **a = (const char**) _a, **b = (const char**) _b; - - return strcmp(*a, *b); -} - -char **strv_sort(char **l) { - - if (strv_isempty(l)) - return l; - - qsort(l, strv_length(l), sizeof(char*), str_compare); - return l; -} diff --git a/src/shared/strv.h b/src/shared/strv.h deleted file mode 100644 index 45558d8960..0000000000 --- a/src/shared/strv.h +++ /dev/null @@ -1,84 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdarg.h> -#include <stdbool.h> - -#include "macro.h" - -char *strv_find(char **l, const char *name); -char *strv_find_prefix(char **l, const char *name); - -void strv_free(char **l); -void strv_freep(char ***l); -char **strv_copy(char **l) _malloc_; -unsigned strv_length(char **l); - -char **strv_merge(char **a, char **b); -char **strv_merge_concat(char **a, char **b, const char *suffix); -char **strv_append(char **l, const char *s); - -char **strv_remove(char **l, const char *s); -char **strv_remove_prefix(char **l, const char *s); -char **strv_uniq(char **l); - -#define strv_contains(l, s) (!!strv_find((l), (s))) - -char **strv_new(const char *x, ...) _sentinel_ _malloc_; -char **strv_new_ap(const char *x, va_list ap) _malloc_; - -static inline const char* STRV_IFNOTNULL(const char *x) { - return x ? x : (const char *) -1; -} - -static inline bool strv_isempty(char **l) { - return !l || !*l; -} - -char **strv_split(const char *s, const char *separator) _malloc_; -char **strv_split_quoted(const char *s) _malloc_; - -char *strv_join(char **l, const char *separator) _malloc_; - -char **strv_env_merge(unsigned n_lists, ...); -char **strv_env_delete(char **x, unsigned n_lists, ...); - -char **strv_env_set(char **x, const char *p); -char **strv_env_unset(char **l, const char *p); - -char *strv_env_get_with_length(char **l, const char *name, size_t k); -char *strv_env_get(char **x, const char *n); - -char **strv_env_clean(char **l); - -char **strv_parse_nulstr(const char *s, size_t l); - -bool strv_overlap(char **a, char **b); - -#define STRV_FOREACH(s, l) \ - for ((s) = (l); (s) && *(s); (s)++) - -#define STRV_FOREACH_BACKWARDS(s, l) \ - for (; (l) && ((s) >= (l)); (s)--) - -char **strv_sort(char **l); diff --git a/src/shared/time-dst.c b/src/shared/time-dst.c deleted file mode 100644 index afc893cccc..0000000000 --- a/src/shared/time-dst.c +++ /dev/null @@ -1,341 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Timezone file reading code from glibc 2.16. - - Copyright (C) 1991-2012 Free Software Foundation, Inc. - Copyright 2012 Kay Sievers - - 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 <ctype.h> -#include <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <endian.h> -#include <byteswap.h> -#include <assert.h> -#include <limits.h> -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> -#include <sys/stat.h> - -#include "time-dst.h" - -/* - * If tzh_version is '2' or greater, the above is followed by a second instance - * of tzhead and a second instance of the data in which each coded transition - * time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style - * string for use in handling instants after the last transition time stored in - * the file * (with nothing between the newlines if there is no POSIX - * representation for such instants). - */ -#define TZ_MAGIC "TZif" -struct tzhead { - char tzh_magic[4]; /* TZ_MAGIC */ - char tzh_version[1]; /* '\0' or '2' as of 2005 */ - char tzh_reserved[15]; /* reserved--must be zero */ - char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ - char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ - char tzh_leapcnt[4]; /* coded number of leap seconds */ - char tzh_timecnt[4]; /* coded number of transition times */ - char tzh_typecnt[4]; /* coded number of local time types */ - char tzh_charcnt[4]; /* coded number of abbr. chars */ -}; - -struct ttinfo { - long int offset; /* Seconds east of GMT. */ - unsigned char isdst; /* Used to set tm_isdst. */ - unsigned char idx; /* Index into `zone_names'. */ - unsigned char isstd; /* Transition times are in standard time. */ - unsigned char isgmt; /* Transition times are in GMT. */ -}; - -struct leap { - time_t transition; /* Time the transition takes effect. */ - long int change; /* Seconds of correction to apply. */ -}; - -static inline int decode(const void *ptr) { - return be32toh(*(int *)ptr); -} - -static inline int64_t decode64(const void *ptr) { - return be64toh(*(int64_t *)ptr); -} - -int time_get_dst(time_t date, const char *tzfile, - time_t *switch_cur, char **zone_cur, bool *dst_cur, - time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next) { - time_t *transitions = NULL; - size_t num_transitions = 0; - unsigned char *type_idxs = 0; - size_t num_types = 0; - struct ttinfo *types = NULL; - char *zone_names = NULL; - struct stat st; - size_t num_isstd, num_isgmt; - FILE *f; - struct tzhead tzhead; - size_t chars; - size_t i; - size_t total_size; - size_t types_idx; - int trans_width = 4; - size_t tzspec_len; - size_t num_leaps; - size_t lo, hi; - int err = -EINVAL; - - f = fopen(tzfile, "re"); - if (f == NULL) - return -errno; - - if (fstat(fileno(f), &st) < 0) { - err = -errno; - fclose(f); - return err; - } - -read_again: - if (fread((void *)&tzhead, sizeof(tzhead), 1, f) != 1 || - memcmp(tzhead.tzh_magic, TZ_MAGIC, sizeof(tzhead.tzh_magic)) != 0) - goto lose; - - num_transitions = (size_t)decode(tzhead.tzh_timecnt); - num_types = (size_t)decode(tzhead.tzh_typecnt); - chars = (size_t)decode(tzhead.tzh_charcnt); - num_leaps = (size_t)decode(tzhead.tzh_leapcnt); - num_isstd = (size_t)decode(tzhead.tzh_ttisstdcnt); - num_isgmt = (size_t)decode(tzhead.tzh_ttisgmtcnt); - - /* For platforms with 64-bit time_t we use the new format if available. */ - if (sizeof(time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') { - size_t to_skip; - - /* We use the 8-byte format. */ - trans_width = 8; - - /* Position the stream before the second header. */ - to_skip = (num_transitions * (4 + 1) - + num_types * 6 - + chars - + num_leaps * 8 + num_isstd + num_isgmt); - if (fseek(f, to_skip, SEEK_CUR) != 0) - goto lose; - - goto read_again; - } - - if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1))) - goto lose; - - total_size = num_transitions * (sizeof(time_t) + 1); - total_size = ((total_size + __alignof__(struct ttinfo) - 1) & ~(__alignof__(struct ttinfo) - 1)); - types_idx = total_size; - if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo)) - goto lose; - - total_size += num_types * sizeof(struct ttinfo); - if (chars > SIZE_MAX - total_size) - goto lose; - - total_size += chars; - if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size) - goto lose; - - total_size = ((total_size + __alignof__(struct leap) - 1) & ~(__alignof__(struct leap) - 1)); - if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct leap)) - goto lose; - - total_size += num_leaps * sizeof(struct leap); - tzspec_len = 0; - if (sizeof(time_t) == 8 && trans_width == 8) { - off_t rem = st.st_size - ftello(f); - - if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars)) - goto lose; - tzspec_len = (size_t) rem - (num_transitions * (8 + 1) + num_types * 6 + chars); - if (num_leaps > SIZE_MAX / 12 || tzspec_len < num_leaps * 12) - goto lose; - tzspec_len -= num_leaps * 12; - if (tzspec_len < num_isstd) - goto lose; - tzspec_len -= num_isstd; - if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt) - goto lose; - tzspec_len -= num_isgmt + 1; - if (SIZE_MAX - total_size < tzspec_len) - goto lose; - } - - transitions = (time_t *)calloc(total_size + tzspec_len, 1); - if (transitions == NULL) - goto lose; - - type_idxs = (unsigned char *)transitions + (num_transitions - * sizeof(time_t)); - types = (struct ttinfo *)((char *)transitions + types_idx); - zone_names = (char *)types + num_types * sizeof(struct ttinfo); - - if (sizeof(time_t) == 4 || trans_width == 8) { - if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions) - goto lose; - } else { - if (fread(transitions, 4, num_transitions, f) != num_transitions || - fread(type_idxs, 1, num_transitions, f) != num_transitions) - goto lose; - } - - /* Check for bogus indices in the data file, so we can hereafter - safely use type_idxs[T] as indices into `types' and never crash. */ - for (i = 0; i < num_transitions; ++i) - if (type_idxs[i] >= num_types) - goto lose; - - if ((BYTE_ORDER != BIG_ENDIAN && (sizeof(time_t) == 4 || trans_width == 4)) || - (BYTE_ORDER == BIG_ENDIAN && sizeof(time_t) == 8 && trans_width == 4)) { - /* Decode the transition times, stored as 4-byte integers in - network (big-endian) byte order. We work from the end of - the array so as not to clobber the next element to be - processed when sizeof (time_t) > 4. */ - i = num_transitions; - while (i-- > 0) - transitions[i] = decode((char *)transitions + i * 4); - } else if (BYTE_ORDER != BIG_ENDIAN && sizeof(time_t) == 8) { - /* Decode the transition times, stored as 8-byte integers in - network (big-endian) byte order. */ - for (i = 0; i < num_transitions; ++i) - transitions[i] = decode64((char *)transitions + i * 8); - } - - for (i = 0; i < num_types; ++i) { - unsigned char x[4]; - int c; - - if (fread(x, 1, sizeof(x), f) != sizeof(x)) - goto lose; - c = getc(f); - if ((unsigned int)c > 1u) - goto lose; - types[i].isdst = c; - c = getc(f); - if ((size_t) c > chars) - /* Bogus index in data file. */ - goto lose; - types[i].idx = c; - types[i].offset = (long int)decode(x); - } - - if (fread(zone_names, 1, chars, f) != chars) - goto lose; - - for (i = 0; i < num_isstd; ++i) { - int c = getc(f); - if (c == EOF) - goto lose; - types[i].isstd = c != 0; - } - - while (i < num_types) - types[i++].isstd = 0; - - for (i = 0; i < num_isgmt; ++i) { - int c = getc(f); - if (c == EOF) - goto lose; - types[i].isgmt = c != 0; - } - - while (i < num_types) - types[i++].isgmt = 0; - - if (num_transitions == 0) - goto lose; - - if (date < transitions[0] || date >= transitions[num_transitions - 1]) - goto lose; - - /* Find the first transition after TIMER, and - then pick the type of the transition before it. */ - lo = 0; - hi = num_transitions - 1; - - /* Assume that DST is changing twice a year and guess initial - search spot from it. - Half of a gregorian year has on average 365.2425 * 86400 / 2 - = 15778476 seconds. */ - i = (transitions[num_transitions - 1] - date) / 15778476; - if (i < num_transitions) { - i = num_transitions - 1 - i; - if (date < transitions[i]) { - if (i < 10 || date >= transitions[i - 10]) { - /* Linear search. */ - while (date < transitions[i - 1]) - i--; - goto found; - } - hi = i - 10; - } else { - if (i + 10 >= num_transitions || date < transitions[i + 10]) { - /* Linear search. */ - while (date >= transitions[i]) - i++; - goto found; - } - lo = i + 10; - } - } - - /* Binary search. */ - while (lo + 1 < hi) { - i = (lo + hi) / 2; - if (date < transitions[i]) - hi = i; - else - lo = i; - } - i = hi; - -found: - if (switch_cur) - *switch_cur = transitions[i-1]; - if (zone_cur) - *zone_cur = strdup(&zone_names[types[type_idxs[i - 1]].idx]); - if (dst_cur) - *dst_cur = types[type_idxs[i-1]].isdst; - - if (switch_next) - *switch_next = transitions[i]; - if (delta_next) - *delta_next = (types[type_idxs[i]].offset - types[type_idxs[i-1]].offset) / 60; - if (zone_next) - *zone_next = strdup(&zone_names[types[type_idxs[i]].idx]); - if (dst_next) - *dst_next = types[type_idxs[i]].isdst; - - free(transitions); - fclose(f); - return 0; -lose: - free(transitions); - fclose(f); - return err; -} diff --git a/src/shared/time-dst.h b/src/shared/time-dst.h deleted file mode 100644 index 536b6bbdfb..0000000000 --- a/src/shared/time-dst.h +++ /dev/null @@ -1,26 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 Kay Sievers - - 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/>. -***/ - -int time_get_dst(time_t date, const char *tzfile, - time_t *switch_cur, char **zone_cur, bool *dst_cur, - time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next); diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c deleted file mode 100644 index 50031e608e..0000000000 --- a/src/shared/unit-name.c +++ /dev/null @@ -1,519 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <errno.h> -#include <string.h> -#include <assert.h> - -#include "path-util.h" -#include "util.h" -#include "unit-name.h" - -#define VALID_CHARS \ - "0123456789" \ - "abcdefghijklmnopqrstuvwxyz" \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - ":-_.\\" - -static const char* const unit_type_table[_UNIT_TYPE_MAX] = { - [UNIT_SERVICE] = "service", - [UNIT_SOCKET] = "socket", - [UNIT_TARGET] = "target", - [UNIT_DEVICE] = "device", - [UNIT_MOUNT] = "mount", - [UNIT_AUTOMOUNT] = "automount", - [UNIT_SNAPSHOT] = "snapshot", - [UNIT_TIMER] = "timer", - [UNIT_SWAP] = "swap", - [UNIT_PATH] = "path", -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType); - -static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { - [UNIT_STUB] = "stub", - [UNIT_LOADED] = "loaded", - [UNIT_ERROR] = "error", - [UNIT_MERGED] = "merged", - [UNIT_MASKED] = "masked" -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); - -bool unit_name_is_valid(const char *n, bool template_ok) { - const char *e, *i, *at; - - /* Valid formats: - * - * string@instance.suffix - * string.suffix - */ - - assert(n); - - if (strlen(n) >= UNIT_NAME_MAX) - return false; - - e = strrchr(n, '.'); - if (!e || e == n) - return false; - - if (unit_type_from_string(e + 1) < 0) - return false; - - for (i = n, at = NULL; i < e; i++) { - - if (*i == '@' && !at) - at = i; - - if (!strchr("@" VALID_CHARS, *i)) - return false; - } - - if (at) { - if (at == n) - return false; - - if (!template_ok && at+1 == e) - return false; - } - - return true; -} - -bool unit_instance_is_valid(const char *i) { - assert(i); - - /* The max length depends on the length of the string, so we - * don't really check this here. */ - - if (i[0] == 0) - return false; - - /* We allow additional @ in the instance string, we do not - * allow them in the prefix! */ - - for (; *i; i++) - if (!strchr("@" VALID_CHARS, *i)) - return false; - - return true; -} - -bool unit_prefix_is_valid(const char *p) { - - /* We don't allow additional @ in the instance string */ - - if (p[0] == 0) - return false; - - for (; *p; p++) - if (!strchr(VALID_CHARS, *p)) - return false; - - return true; -} - -int unit_name_to_instance(const char *n, char **instance) { - const char *p, *d; - char *i; - - assert(n); - assert(instance); - - /* Everything past the first @ and before the last . is the instance */ - p = strchr(n, '@'); - if (!p) { - *instance = NULL; - return 0; - } - - assert_se(d = strrchr(n, '.')); - assert(p < d); - - i = strndup(p+1, d-p-1); - if (!i) - return -ENOMEM; - - *instance = i; - return 0; -} - -char *unit_name_to_prefix_and_instance(const char *n) { - const char *d; - - assert(n); - - assert_se(d = strrchr(n, '.')); - - return strndup(n, d - n); -} - -char *unit_name_to_prefix(const char *n) { - const char *p; - - p = strchr(n, '@'); - if (p) - return strndup(n, p - n); - - return unit_name_to_prefix_and_instance(n); -} - -char *unit_name_change_suffix(const char *n, const char *suffix) { - char *e, *r; - size_t a, b; - - assert(n); - assert(unit_name_is_valid(n, true)); - assert(suffix); - - assert_se(e = strrchr(n, '.')); - a = e - n; - b = strlen(suffix); - - r = new(char, a + b + 1); - if (!r) - return NULL; - - memcpy(r, n, a); - memcpy(r+a, suffix, b+1); - - return r; -} - -char *unit_name_build(const char *prefix, const char *instance, const char *suffix) { - assert(prefix); - assert(unit_prefix_is_valid(prefix)); - assert(!instance || unit_instance_is_valid(instance)); - assert(suffix); - - if (!instance) - return strappend(prefix, suffix); - - return strjoin(prefix, "@", instance, suffix, NULL); -} - -static char *do_escape_char(char c, char *t) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(c >> 4); - *(t++) = hexchar(c); - return t; -} - -static char *do_escape(const char *f, char *t) { - assert(f); - assert(t); - - /* do not create units with a leading '.', like for "/.dotdir" mount points */ - if (*f == '.') { - t = do_escape_char(*f, t); - f++; - } - - for (; *f; f++) { - if (*f == '/') - *(t++) = '-'; - else if (*f == '-' || *f == '\\' || !strchr(VALID_CHARS, *f)) - t = do_escape_char(*f, t); - else - *(t++) = *f; - } - - return t; -} - -char *unit_name_escape(const char *f) { - char *r, *t; - - r = new(char, strlen(f)*4+1); - if (!r) - return NULL; - - t = do_escape(f, r); - *t = 0; - - return r; -} - -char *unit_name_unescape(const char *f) { - char *r, *t; - - assert(f); - - r = strdup(f); - if (!r) - return NULL; - - for (t = r; *f; f++) { - if (*f == '-') - *(t++) = '/'; - else if (*f == '\\') { - int a, b; - - if (f[1] != 'x' || - (a = unhexchar(f[2])) < 0 || - (b = unhexchar(f[3])) < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - } else { - *(t++) = (char) ((a << 4) | b); - f += 3; - } - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *unit_name_path_escape(const char *f) { - char *p, *e; - - assert(f); - - p = strdup(f); - if (!p) - return NULL; - - path_kill_slashes(p); - - if (streq(p, "/")) { - free(p); - return strdup("-"); - } - - e = unit_name_escape(p[0] == '/' ? p + 1 : p); - free(p); - - return e; -} - -char *unit_name_path_unescape(const char *f) { - char *e; - - assert(f); - - e = unit_name_unescape(f); - if (!e) - return NULL; - - if (e[0] != '/') { - char *w; - - w = strappend("/", e); - free(e); - - return w; - } - - return e; -} - -bool unit_name_is_template(const char *n) { - const char *p; - - assert(n); - - p = strchr(n, '@'); - if (!p) - return false; - - return p[1] == '.'; -} - -bool unit_name_is_instance(const char *n) { - const char *p; - - assert(n); - - p = strchr(n, '@'); - if (!p) - return false; - - return p[1] != '.'; -} - -char *unit_name_replace_instance(const char *f, const char *i) { - const char *p, *e; - char *r, *k; - size_t a, b; - - assert(f); - - p = strchr(f, '@'); - if (!p) - return strdup(f); - - e = strrchr(f, '.'); - if (!e) - assert_se(e = strchr(f, 0)); - - a = p - f; - b = strlen(i); - - r = new(char, a + 1 + b + strlen(e) + 1); - if (!r) - return NULL; - - k = mempcpy(r, f, a + 1); - k = mempcpy(k, i, b); - strcpy(k, e); - - return r; -} - -char *unit_name_template(const char *f) { - const char *p, *e; - char *r; - size_t a; - - p = strchr(f, '@'); - if (!p) - return strdup(f); - - assert_se(e = strrchr(f, '.')); - a = p - f + 1; - - r = new(char, a + strlen(e) + 1); - if (!r) - return NULL; - - strcpy(mempcpy(r, f, a), e); - return r; - -} - -char *unit_name_from_path(const char *path, const char *suffix) { - char *p, *r; - - assert(path); - assert(suffix); - - p = unit_name_path_escape(path); - if (!p) - return NULL; - - r = strappend(p, suffix); - free(p); - - return r; -} - -char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix) { - char *p, *r; - - assert(prefix); - assert(path); - assert(suffix); - - p = unit_name_path_escape(path); - if (!p) - return NULL; - - r = strjoin(prefix, "@", p, suffix, NULL); - free(p); - - return r; -} - -char *unit_name_to_path(const char *name) { - char *w, *e; - - assert(name); - - w = unit_name_to_prefix(name); - if (!w) - return NULL; - - e = unit_name_path_unescape(w); - free(w); - - return e; -} - -char *unit_dbus_path_from_name(const char *name) { - char *e, *p; - - assert(name); - - e = bus_path_escape(name); - if (!e) - return NULL; - - p = strappend("/org/freedesktop/systemd1/unit/", e); - free(e); - - return p; -} - -char *unit_name_mangle(const char *name) { - char *r, *t; - const char *f; - - assert(name); - - /* Try to turn a string that might not be a unit name into a - * sensible unit name. */ - - if (is_device_path(name)) - return unit_name_from_path(name, ".device"); - - if (path_is_absolute(name)) - return unit_name_from_path(name, ".mount"); - - /* We'll only escape the obvious characters here, to play - * safe. */ - - r = new(char, strlen(name) * 4 + 1 + sizeof(".service")-1); - if (!r) - return NULL; - - for (f = name, t = r; *f; f++) { - if (*f == '/') - *(t++) = '-'; - else if (!strchr("@" VALID_CHARS, *f)) - t = do_escape_char(*f, t); - else - *(t++) = *f; - } - - if (unit_name_to_type(name) < 0) - strcpy(t, ".service"); - else - *t = 0; - - return r; -} - -UnitType unit_name_to_type(const char *n) { - const char *e; - - assert(n); - - e = strrchr(n, '.'); - if (!e) - return _UNIT_TYPE_INVALID; - - return unit_type_from_string(e + 1); -} diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h deleted file mode 100644 index 7be346590e..0000000000 --- a/src/shared/unit-name.h +++ /dev/null @@ -1,94 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <stdbool.h> - -#define UNIT_NAME_MAX 256 - -typedef enum UnitType UnitType; -typedef enum UnitLoadState UnitLoadState; - -enum UnitType { - UNIT_SERVICE = 0, - UNIT_SOCKET, - UNIT_TARGET, - UNIT_DEVICE, - UNIT_MOUNT, - UNIT_AUTOMOUNT, - UNIT_SNAPSHOT, - UNIT_TIMER, - UNIT_SWAP, - UNIT_PATH, - _UNIT_TYPE_MAX, - _UNIT_TYPE_INVALID = -1 -}; - -enum UnitLoadState { - UNIT_STUB, - UNIT_LOADED, - UNIT_ERROR, - UNIT_MERGED, - UNIT_MASKED, - _UNIT_LOAD_STATE_MAX, - _UNIT_LOAD_STATE_INVALID = -1 -}; - -const char *unit_type_to_string(UnitType i); -UnitType unit_type_from_string(const char *s); - -const char *unit_load_state_to_string(UnitLoadState i); -UnitLoadState unit_load_state_from_string(const char *s); - -int unit_name_to_instance(const char *n, char **instance); -char* unit_name_to_prefix(const char *n); -char* unit_name_to_prefix_and_instance(const char *n); - -bool unit_name_is_valid(const char *n, bool template_ok); -bool unit_prefix_is_valid(const char *p); -bool unit_instance_is_valid(const char *i); - -UnitType unit_name_to_type(const char *n); - -char *unit_name_change_suffix(const char *n, const char *suffix); - -char *unit_name_build(const char *prefix, const char *instance, const char *suffix); - -char *unit_name_escape(const char *f); -char *unit_name_unescape(const char *f); -char *unit_name_path_escape(const char *f); -char *unit_name_path_unescape(const char *f); - -bool unit_name_is_template(const char *n); -bool unit_name_is_instance(const char *n); - -char *unit_name_replace_instance(const char *f, const char *i); - -char *unit_name_template(const char *f); - -char *unit_name_from_path(const char *path, const char *suffix); -char *unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix); -char *unit_name_to_path(const char *name); - -char *unit_dbus_path_from_name(const char *name); - -char *unit_name_mangle(const char *name); diff --git a/src/shared/utf8.c b/src/shared/utf8.c deleted file mode 100644 index 5f9f3c60c5..0000000000 --- a/src/shared/utf8.c +++ /dev/null @@ -1,286 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 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/>. -***/ - -/* This file is based on the GLIB utf8 validation functions. The - * original license text follows. */ - -/* gutf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library 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 of the License, or (at your option) any later version. - * - * This library 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 this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include <errno.h> -#include <stdlib.h> -#include <inttypes.h> -#include <string.h> -#include <stdbool.h> - -#include "utf8.h" - -#define FILTER_CHAR '_' - -static inline bool is_unicode_valid(uint32_t ch) { - - if (ch >= 0x110000) /* End of unicode space */ - return false; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return false; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return false; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return false; - - return true; -} - -static inline bool is_continuation_char(uint8_t ch) { - if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ - return false; - return true; -} - -static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { - *u_ch <<= 6; - *u_ch |= ch & 0x3f; -} - -static bool is_unicode_control(uint32_t ch) { - - /* - 0 to ' '-1 is the C0 range. - DEL=0x7F, and DEL+1 to 0x9F is C1 range. - '\t' is in C0 range, but more or less harmless and commonly used. - */ - - return (ch < ' ' && ch != '\t') || - (0x7F <= ch && ch <= 0x9F); -} - -char* utf8_is_printable_n(const char* str, size_t length) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p; - - assert(str); - - for (p = (const uint8_t*) str; length; p++, length--) { - if (*p < 128) { - val = *p; - } else { - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - min = 128; - val = (uint32_t) (*p & 0x1e); - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - min = (1 << 11); - val = (uint32_t) (*p & 0x0f); - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - min = (1 << 16); - val = (uint32_t) (*p & 0x07); - } else - goto error; - - p++; - length--; - if (!length || !is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - TWO_REMAINING: - p++; - length--; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - ONE_REMAINING: - p++; - length--; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - if (val < min) - goto error; - } - - if (is_unicode_control(val)) - goto error; - } - - return (char*) str; - -error: - return NULL; -} - -static char* utf8_validate(const char *str, char *output) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p, *last; - int size; - uint8_t *o; - - assert(str); - - o = (uint8_t*) output; - for (p = (const uint8_t*) str; *p; p++) { - if (*p < 128) { - if (o) - *o = *p; - } else { - last = p; - - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - size = 2; - min = 128; - val = (uint32_t) (*p & 0x1e); - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - size = 3; - min = (1 << 11); - val = (uint32_t) (*p & 0x0f); - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - size = 4; - min = (1 << 16); - val = (uint32_t) (*p & 0x07); - } else - goto error; - - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - TWO_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - ONE_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - if (val < min) - goto error; - - if (!is_unicode_valid(val)) - goto error; - - if (o) { - memcpy(o, last, (size_t) size); - o += size; - } - - continue; - - error: - if (o) { - *o = FILTER_CHAR; - p = last; /* We retry at the next character */ - } else - goto failure; - } - - if (o) - o++; - } - - if (o) { - *o = '\0'; - return output; - } - - return (char*) str; - -failure: - return NULL; -} - -char* utf8_is_valid (const char *str) { - return utf8_validate(str, NULL); -} - -char* utf8_filter (const char *str) { - char *new_str; - - assert(str); - - new_str = malloc(strlen(str) + 1); - if (!new_str) - return NULL; - - return utf8_validate(str, new_str); -} - -char *ascii_is_valid(const char *str) { - const char *p; - - assert(str); - - for (p = str; *p; p++) - if ((unsigned char) *p >= 128) - return NULL; - - return (char*) str; -} - -char *ascii_filter(const char *str) { - const char *s; - char *r, *d; - size_t l; - - assert(str); - - l = strlen(str); - r = malloc(l + 1); - if (!r) - return NULL; - - for (s = str, d = r; *s; s++) - if ((unsigned char) *s < 128) - *(d++) = *s; - - *d = 0; - - return r; -} diff --git a/src/shared/utf8.h b/src/shared/utf8.h deleted file mode 100644 index 13d2f6a980..0000000000 --- a/src/shared/utf8.h +++ /dev/null @@ -1,32 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 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 "macro.h" - -char *utf8_is_valid(const char *s) _pure_; -char *ascii_is_valid(const char *s) _pure_; - -char *utf8_is_printable_n(const char* str, size_t length) _pure_; - -char *utf8_filter(const char *s); -char *ascii_filter(const char *s); diff --git a/src/shared/util.c b/src/shared/util.c deleted file mode 100644 index 6d826b6f5e..0000000000 --- a/src/shared/util.c +++ /dev/null @@ -1,6215 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <assert.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <signal.h> -#include <stdio.h> -#include <syslog.h> -#include <sched.h> -#include <sys/resource.h> -#include <linux/sched.h> -#include <sys/types.h> -#include <sys/stat.h> -#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 <sys/inotify.h> -#include <sys/poll.h> -#include <libgen.h> -#include <ctype.h> -#include <sys/prctl.h> -#include <sys/utsname.h> -#include <pwd.h> -#include <netinet/ip.h> -#include <linux/kd.h> -#include <dlfcn.h> -#include <sys/wait.h> -#include <sys/time.h> -#include <glob.h> -#include <grp.h> -#include <sys/mman.h> -#include <sys/vfs.h> -#include <linux/magic.h> -#include <limits.h> -#include <langinfo.h> -#include <locale.h> - -#include "macro.h" -#include "util.h" -#include "ioprio.h" -#include "missing.h" -#include "log.h" -#include "strv.h" -#include "label.h" -#include "path-util.h" -#include "exit-status.h" -#include "hashmap.h" - -int saved_argc = 0; -char **saved_argv = NULL; - -static volatile unsigned cached_columns = 0; -static volatile unsigned cached_lines = 0; - -bool is_efiboot(void) { - return access("/sys/firmware/efi", F_OK) >= 0; -} - -size_t page_size(void) { - static __thread size_t pgsz = 0; - long r; - - if (_likely_(pgsz > 0)) - return pgsz; - - r = sysconf(_SC_PAGESIZE); - assert(r > 0); - - pgsz = (size_t) r; - return pgsz; -} - -bool streq_ptr(const char *a, const char *b) { - - /* Like streq(), but tries to make sense of NULL pointers */ - - if (a && b) - return streq(a, b); - - if (!a && !b) - return true; - - return false; -} - -usec_t now(clockid_t clock_id) { - struct timespec ts; - - assert_se(clock_gettime(clock_id, &ts) == 0); - - return timespec_load(&ts); -} - -dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { - assert(ts); - - ts->realtime = now(CLOCK_REALTIME); - ts->monotonic = now(CLOCK_MONOTONIC); - - return ts; -} - -dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { - int64_t delta; - assert(ts); - - ts->realtime = u; - - if (u == 0) - ts->monotonic = 0; - else { - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - - ts->monotonic = now(CLOCK_MONOTONIC); - - if ((int64_t) ts->monotonic > delta) - ts->monotonic -= delta; - else - ts->monotonic = 0; - } - - return ts; -} - -usec_t timespec_load(const struct timespec *ts) { - assert(ts); - - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) - return (usec_t) -1; - - if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) - return (usec_t) -1; - - return - (usec_t) ts->tv_sec * USEC_PER_SEC + - (usec_t) ts->tv_nsec / NSEC_PER_USEC; -} - -struct timespec *timespec_store(struct timespec *ts, usec_t u) { - assert(ts); - - if (u == (usec_t) -1) { - ts->tv_sec = (time_t) -1; - ts->tv_nsec = (long) -1; - return ts; - } - - ts->tv_sec = (time_t) (u / USEC_PER_SEC); - ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); - - return ts; -} - -usec_t timeval_load(const struct timeval *tv) { - assert(tv); - - if (tv->tv_sec == (time_t) -1 && - tv->tv_usec == (suseconds_t) -1) - return (usec_t) -1; - - if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC) - return (usec_t) -1; - - return - (usec_t) tv->tv_sec * USEC_PER_SEC + - (usec_t) tv->tv_usec; -} - -struct timeval *timeval_store(struct timeval *tv, usec_t u) { - assert(tv); - - if (u == (usec_t) -1) { - tv->tv_sec = (time_t) -1; - tv->tv_usec = (suseconds_t) -1; - return tv; - } - - tv->tv_sec = (time_t) (u / USEC_PER_SEC); - tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC); - - return tv; -} - -char* endswith(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 (memcmp(s + sl - pl, postfix, pl) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -char* startswith(const char *s, const char *prefix) { - const char *a, *b; - - assert(s); - assert(prefix); - - a = s, b = prefix; - for (;;) { - if (*b == 0) - return (char*) a; - if (*a != *b) - return NULL; - - a++, b++; - } -} - -char* startswith_no_case(const char *s, const char *prefix) { - const char *a, *b; - - assert(s); - assert(prefix); - - a = s, b = prefix; - for (;;) { - if (*b == 0) - return (char*) a; - if (tolower(*a) != tolower(*b)) - return NULL; - - a++, b++; - } -} - -bool first_word(const char *s, const char *word) { - size_t sl, wl; - - assert(s); - assert(word); - - sl = strlen(s); - wl = strlen(word); - - if (sl < wl) - return false; - - if (wl == 0) - return true; - - if (memcmp(s, word, wl) != 0) - return false; - - return s[wl] == 0 || - strchr(WHITESPACE, s[wl]); -} - -int close_nointr(int fd) { - assert(fd >= 0); - - for (;;) { - int r; - - r = close(fd); - if (r >= 0) - return r; - - if (errno != EINTR) - return -errno; - } -} - -void close_nointr_nofail(int fd) { - int saved_errno = errno; - - /* like close_nointr() but cannot fail, and guarantees errno - * is unchanged */ - - assert_se(close_nointr(fd) == 0); - - errno = saved_errno; -} - -void close_many(const int fds[], unsigned n_fd) { - unsigned i; - - for (i = 0; i < n_fd; i++) - close_nointr_nofail(fds[i]); -} - -int parse_boolean(const char *v) { - assert(v); - - if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) - return 1; - else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) - return 0; - - return -EINVAL; -} - -int parse_pid(const char *s, pid_t* ret_pid) { - unsigned long ul = 0; - pid_t pid; - int r; - - assert(s); - assert(ret_pid); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - pid = (pid_t) ul; - - if ((unsigned long) pid != ul) - return -ERANGE; - - if (pid <= 0) - return -ERANGE; - - *ret_pid = pid; - return 0; -} - -int parse_uid(const char *s, uid_t* ret_uid) { - unsigned long ul = 0; - uid_t uid; - int r; - - assert(s); - assert(ret_uid); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - uid = (uid_t) ul; - - if ((unsigned long) uid != ul) - return -ERANGE; - - *ret_uid = uid; - return 0; -} - -int safe_atou(const char *s, unsigned *ret_u) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret_u); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - if ((unsigned long) (unsigned) l != l) - return -ERANGE; - - *ret_u = (unsigned) l; - return 0; -} - -int safe_atoi(const char *s, int *ret_i) { - char *x = NULL; - long l; - - assert(s); - assert(ret_i); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - if ((long) (int) l != l) - return -ERANGE; - - *ret_i = (int) l; - return 0; -} - -int safe_atollu(const char *s, long long unsigned *ret_llu) { - char *x = NULL; - unsigned long long l; - - assert(s); - assert(ret_llu); - - errno = 0; - l = strtoull(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_llu = l; - return 0; -} - -int safe_atolli(const char *s, long long int *ret_lli) { - char *x = NULL; - long long l; - - assert(s); - assert(ret_lli); - - errno = 0; - l = strtoll(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_lli = l; - return 0; -} - -/* Split a string into words. */ -char *split(const char *c, size_t *l, const char *separator, char **state) { - char *current; - - current = *state ? *state : (char*) c; - - if (!*current || *c == 0) - return NULL; - - current += strspn(current, separator); - *l = strcspn(current, separator); - *state = current+*l; - - return (char*) current; -} - -/* Split a string into words, but consider strings enclosed in '' and - * "" as words even if they include spaces. */ -char *split_quoted(const char *c, size_t *l, char **state) { - char *current, *e; - bool escaped = false; - - current = *state ? *state : (char*) c; - - if (!*current || *c == 0) - return NULL; - - current += strspn(current, WHITESPACE); - - if (*current == '\'') { - current ++; - - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\'') - break; - } - - *l = e-current; - *state = *e == 0 ? e : e+1; - } else if (*current == '\"') { - current ++; - - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (*e == '\"') - break; - } - - *l = e-current; - *state = *e == 0 ? e : e+1; - } else { - for (e = current; *e; e++) { - if (escaped) - escaped = false; - else if (*e == '\\') - escaped = true; - else if (strchr(WHITESPACE, *e)) - break; - } - *l = e-current; - *state = e; - } - - return (char*) current; -} - -int get_parent_of_pid(pid_t pid, pid_t *_ppid) { - int r; - _cleanup_fclose_ FILE *f = NULL; - char fn[PATH_MAX], line[LINE_MAX], *p; - long unsigned ppid; - - assert(pid > 0); - assert(_ppid); - - assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); - char_array_0(fn); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (!fgets(line, sizeof(line), f)) { - r = feof(f) ? -EIO : -errno; - fclose(f); - 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; -} - -int get_starttime_of_pid(pid_t pid, unsigned long long *st) { - _cleanup_fclose_ FILE *f = NULL; - char fn[PATH_MAX], line[LINE_MAX], *p; - - assert(pid > 0); - assert(st); - - assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1)); - char_array_0(fn); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (!fgets(line, sizeof(line), f)) { - if (ferror(f)) - return -errno; - - return -EIO; - } - - /* 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 */ - "%*d " /* ppid */ - "%*d " /* pgrp */ - "%*d " /* session */ - "%*d " /* tty_nr */ - "%*d " /* tpgid */ - "%*u " /* flags */ - "%*u " /* minflt */ - "%*u " /* cminflt */ - "%*u " /* majflt */ - "%*u " /* cmajflt */ - "%*u " /* utime */ - "%*u " /* stime */ - "%*d " /* cutime */ - "%*d " /* cstime */ - "%*d " /* priority */ - "%*d " /* nice */ - "%*d " /* num_threads */ - "%*d " /* itrealvalue */ - "%llu " /* starttime */, - st) != 1) - return -EIO; - - return 0; -} - -int write_one_line_file(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - - assert(fn); - assert(line); - - f = fopen(fn, "we"); - if (!f) - return -errno; - - errno = 0; - if (fputs(line, f) < 0) - return errno ? -errno : -EIO; - - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; -} - -int fchmod_umask(int fd, mode_t m) { - mode_t u; - int r; - - u = umask(0777); - r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; - umask(u); - - return r; -} - -int write_one_line_file_atomic(const char *fn, const char *line) { - FILE *f; - int r; - char *p; - - assert(fn); - assert(line); - - r = fopen_temporary(fn, &f, &p); - if (r < 0) - return r; - - fchmod_umask(fileno(f), 0644); - - errno = 0; - if (fputs(line, f) < 0) { - r = -errno; - goto finish; - } - - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) { - if (errno != 0) - r = -errno; - else - r = -EIO; - } else { - if (rename(p, fn) < 0) - r = -errno; - else - r = 0; - } - -finish: - if (r < 0) - unlink(p); - - fclose(f); - free(p); - - return r; -} - -int read_one_line_file(const char *fn, char **line) { - _cleanup_fclose_ FILE *f = NULL; - char t[LINE_MAX], *c; - - assert(fn); - assert(line); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (!fgets(t, sizeof(t), f)) { - - if (ferror(f)) - return errno ? -errno : -EIO; - - t[0] = 0; - } - - c = strdup(t); - if (!c) - return -ENOMEM; - truncate_nl(c); - - *line = c; - return 0; -} - -int read_full_file(const char *fn, char **contents, size_t *size) { - _cleanup_fclose_ FILE *f = NULL; - size_t n, l; - _cleanup_free_ char *buf = NULL; - struct stat st; - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (fstat(fileno(f), &st) < 0) - return -errno; - - /* Safety check */ - if (st.st_size > 4*1024*1024) - return -E2BIG; - - n = st.st_size > 0 ? st.st_size : LINE_MAX; - l = 0; - - for (;;) { - char *t; - size_t k; - - t = realloc(buf, n+1); - if (!t) - return -ENOMEM; - - buf = t; - k = fread(buf + l, 1, n - l, f); - - if (k <= 0) { - if (ferror(f)) - return -errno; - - break; - } - - l += k; - n *= 2; - - /* Safety check */ - if (n > 4*1024*1024) - return -E2BIG; - } - - buf[l] = 0; - *contents = buf; - buf = NULL; - - if (size) - *size = l; - - return 0; -} - -int parse_env_file( - const char *fname, - const char *separator, ...) { - - int r = 0; - char *contents = NULL, *p; - - assert(fname); - assert(separator); - - if ((r = read_full_file(fname, &contents, NULL)) < 0) - return r; - - p = contents; - for (;;) { - const char *key = NULL; - - p += strspn(p, separator); - p += strspn(p, WHITESPACE); - - if (!*p) - break; - - if (!strchr(COMMENTS, *p)) { - va_list ap; - char **value; - - va_start(ap, separator); - while ((key = va_arg(ap, char *))) { - size_t n; - char *v; - - value = va_arg(ap, char **); - - n = strlen(key); - if (strncmp(p, key, n) != 0 || - p[n] != '=') - continue; - - p += n + 1; - n = strcspn(p, separator); - - if (n >= 2 && - strchr(QUOTES, p[0]) && - p[n-1] == p[0]) - v = strndup(p+1, n-2); - else - v = strndup(p, n); - - if (!v) { - r = -ENOMEM; - va_end(ap); - goto fail; - } - - if (v[0] == '\0') { - /* return empty value strings as NULL */ - free(v); - v = NULL; - } - - free(*value); - *value = v; - - p += n; - - r ++; - break; - } - va_end(ap); - } - - if (!key) - p += strcspn(p, separator); - } - -fail: - free(contents); - return r; -} - -int load_env_file( - const char *fname, - char ***rl) { - - FILE *f; - char **m = NULL; - int r; - - assert(fname); - assert(rl); - - if (!(f = fopen(fname, "re"))) - return -errno; - - while (!feof(f)) { - char l[LINE_MAX], *p, *u; - char **t; - - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; - - r = -errno; - goto finish; - } - - p = strstrip(l); - - if (!*p) - continue; - - if (strchr(COMMENTS, *p)) - continue; - - if (!(u = normalize_env_assignment(p))) { - r = log_oom(); - goto finish; - } - - t = strv_append(m, u); - free(u); - - if (!t) { - r = log_oom(); - goto finish; - } - - strv_free(m); - m = t; - } - - r = 0; - - *rl = m; - m = NULL; - -finish: - if (f) - fclose(f); - - strv_free(m); - - return r; -} - -int write_env_file(const char *fname, char **l) { - char **i, *p; - FILE *f; - int r; - - r = fopen_temporary(fname, &f, &p); - if (r < 0) - return r; - - fchmod_umask(fileno(f), 0644); - - errno = 0; - STRV_FOREACH(i, l) { - fputs(*i, f); - fputc('\n', f); - } - - fflush(f); - - if (ferror(f)) { - if (errno != 0) - r = -errno; - else - r = -EIO; - } else { - if (rename(p, fname) < 0) - r = -errno; - else - r = 0; - } - - if (r < 0) - unlink(p); - - fclose(f); - free(p); - - return r; -} - -char *truncate_nl(char *s) { - assert(s); - - s[strcspn(s, NEWLINE)] = 0; - return s; -} - -int get_process_comm(pid_t pid, char **name) { - int r; - - assert(name); - - if (pid == 0) - r = read_one_line_file("/proc/self/comm", name); - else { - char *p; - if (asprintf(&p, "/proc/%lu/comm", (unsigned long) pid) < 0) - return -ENOMEM; - - r = read_one_line_file(p, name); - free(p); - } - - return r; -} - -int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { - char *r, *k; - int c; - bool space = false; - size_t left; - FILE *f; - - assert(max_length > 0); - assert(line); - - if (pid == 0) - f = fopen("/proc/self/cmdline", "re"); - else { - char *p; - if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0) - return -ENOMEM; - - f = fopen(p, "re"); - free(p); - } - - if (!f) - return -errno; - - r = new(char, max_length); - if (!r) { - fclose(f); - 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; - - fclose(f); - - /* Kernel threads have no argv[] */ - if (r[0] == 0) { - char *t; - int h; - - free(r); - - if (!comm_fallback) - return -ENOENT; - - h = get_process_comm(pid, &t); - if (h < 0) - return h; - - r = strjoin("[", t, "]", NULL); - free(t); - - if (!r) - return -ENOMEM; - } - - *line = r; - return 0; -} - -int is_kernel_thread(pid_t pid) { - char *p; - size_t count; - char c; - bool eof; - FILE *f; - - if (pid == 0) - return 0; - - if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0) - return -ENOMEM; - - f = fopen(p, "re"); - free(p); - - 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_exe(pid_t pid, char **name) { - int r; - - assert(name); - - if (pid == 0) - r = readlink_malloc("/proc/self/exe", name); - else { - char *p; - if (asprintf(&p, "/proc/%lu/exe", (unsigned long) pid) < 0) - return -ENOMEM; - - r = readlink_malloc(p, name); - free(p); - } - - return r; -} - -static int get_process_id(pid_t pid, const char *field, uid_t *uid) { - char *p; - FILE *f; - int r; - - assert(uid); - - if (pid == 0) - return getuid(); - - if (asprintf(&p, "/proc/%lu/status", (unsigned long) pid) < 0) - return -ENOMEM; - - f = fopen(p, "re"); - free(p); - - if (!f) - return -errno; - - while (!feof(f)) { - char line[LINE_MAX], *l; - - if (!fgets(line, sizeof(line), f)) { - if (feof(f)) - break; - - r = -errno; - goto finish; - } - - l = strstrip(line); - - if (startswith(l, field)) { - l += strlen(field); - l += strspn(l, WHITESPACE); - - l[strcspn(l, WHITESPACE)] = 0; - - r = parse_uid(l, uid); - goto finish; - } - } - - r = -EIO; - -finish: - fclose(f); - - return r; -} - -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) { - return get_process_id(pid, "Gid:", gid); -} - -char *strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - - if (!s) - return strndup(suffix, b); - - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - if (b > ((size_t) -1) - a) - return NULL; - - r = new(char, a+b+1); - if (!r) - return NULL; - - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; - - return r; -} - -char *strappend(const char *s, const char *suffix) { - return strnappend(s, suffix, suffix ? strlen(suffix) : 0); -} - -int readlink_malloc(const char *p, char **r) { - size_t l = 100; - - assert(p); - assert(r); - - for (;;) { - char *c; - ssize_t n; - - if (!(c = new(char, l))) - return -ENOMEM; - - if ((n = readlink(p, c, l-1)) < 0) { - int ret = -errno; - free(c); - return ret; - } - - if ((size_t) n < l-1) { - c[n] = 0; - *r = c; - return 0; - } - - free(c); - l *= 2; - } -} - -int readlink_and_make_absolute(const char *p, char **r) { - char *target, *k; - int j; - - assert(p); - assert(r); - - if ((j = readlink_malloc(p, &target)) < 0) - return j; - - k = file_in_same_dir(p, target); - free(target); - - if (!k) - return -ENOMEM; - - *r = k; - return 0; -} - -int readlink_and_canonicalize(const char *p, char **r) { - char *t, *s; - int j; - - assert(p); - assert(r); - - j = readlink_and_make_absolute(p, &t); - if (j < 0) - return j; - - s = canonicalize_file_name(t); - if (s) { - free(t); - *r = s; - } else - *r = t; - - path_kill_slashes(*r); - - return 0; -} - -int reset_all_signal_handlers(void) { - int sig; - - for (sig = 1; sig < _NSIG; sig++) { - struct sigaction sa; - - if (sig == SIGKILL || sig == SIGSTOP) - continue; - - zero(sa); - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_RESTART; - - /* 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) - return -errno; - } - - return 0; -} - -char *strstrip(char *s) { - char *e; - - /* Drops trailing whitespace. Modifies the string in - * place. Returns pointer to first non-space character */ - - s += strspn(s, WHITESPACE); - - for (e = strchr(s, 0); e > s; e --) - if (!strchr(WHITESPACE, e[-1])) - break; - - *e = 0; - - return s; -} - -char *delete_chars(char *s, const char *bad) { - char *f, *t; - - /* Drops all whitespace, regardless where in the string */ - - for (f = s, t = s; *f; f++) { - if (strchr(bad, *f)) - continue; - - *(t++) = *f; - } - - *t = 0; - - return s; -} - -bool in_charset(const char *s, const char* charset) { - const char *i; - - assert(s); - assert(charset); - - for (i = s; *i; i++) - if (!strchr(charset, *i)) - return false; - - return true; -} - -char *file_in_same_dir(const char *path, const char *filename) { - char *e, *r; - size_t k; - - assert(path); - assert(filename); - - /* This removes the last component of path and appends - * filename, unless the latter is absolute anyway or the - * former isn't */ - - if (path_is_absolute(filename)) - return strdup(filename); - - if (!(e = strrchr(path, '/'))) - return strdup(filename); - - k = strlen(filename); - if (!(r = new(char, e-path+1+k+1))) - return NULL; - - memcpy(r, path, e-path+1); - memcpy(r+(e-path)+1, filename, k+1); - - return r; -} - -int rmdir_parents(const char *path, const char *stop) { - size_t l; - int r = 0; - - assert(path); - assert(stop); - - l = strlen(path); - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - while (l > 0) { - char *t; - - /* Skip last component */ - while (l > 0 && path[l-1] != '/') - l--; - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - if (l <= 0) - break; - - if (!(t = strndup(path, l))) - return -ENOMEM; - - if (path_startswith(stop, t)) { - free(t); - return 0; - } - - r = rmdir(t); - free(t); - - if (r < 0) - if (errno != ENOENT) - return -errno; - } - - return 0; -} - - -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; - - return table[x & 15]; -} - -int unhexchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - return -1; -} - -char octchar(int x) { - return '0' + (x & 7); -} - -int unoctchar(char c) { - - if (c >= '0' && c <= '7') - return c - '0'; - - return -1; -} - -char decchar(int x) { - return '0' + (x % 10); -} - -int undecchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - return -1; -} - -char *cescape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Does C style string escaping. */ - - r = new(char, strlen(s)*4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) - - switch (*f) { - - case '\a': - *(t++) = '\\'; - *(t++) = 'a'; - break; - case '\b': - *(t++) = '\\'; - *(t++) = 'b'; - break; - case '\f': - *(t++) = '\\'; - *(t++) = 'f'; - break; - case '\n': - *(t++) = '\\'; - *(t++) = 'n'; - break; - case '\r': - *(t++) = '\\'; - *(t++) = 'r'; - break; - case '\t': - *(t++) = '\\'; - *(t++) = 't'; - break; - case '\v': - *(t++) = '\\'; - *(t++) = 'v'; - break; - case '\\': - *(t++) = '\\'; - *(t++) = '\\'; - break; - case '"': - *(t++) = '\\'; - *(t++) = '"'; - break; - case '\'': - *(t++) = '\\'; - *(t++) = '\''; - break; - - default: - /* For special chars we prefer octal over - * hexadecimal encoding, simply because glib's - * g_strescape() does the same */ - if ((*f < ' ') || (*f >= 127)) { - *(t++) = '\\'; - *(t++) = octchar((unsigned char) *f >> 6); - *(t++) = octchar((unsigned char) *f >> 3); - *(t++) = octchar((unsigned char) *f); - } else - *(t++) = *f; - break; - } - - *t = 0; - - return r; -} - -char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) { - char *r, *t; - const char *f; - size_t pl; - - assert(s); - - /* Undoes C style string escaping, and optionally prefixes it. */ - - pl = prefix ? strlen(prefix) : 0; - - r = new(char, pl+length+1); - if (!r) - return r; - - if (prefix) - memcpy(r, prefix, pl); - - for (f = s, t = r + pl; f < s + length; f++) { - - if (*f != '\\') { - *(t++) = *f; - continue; - } - - f++; - - switch (*f) { - - case 'a': - *(t++) = '\a'; - break; - case 'b': - *(t++) = '\b'; - break; - case 'f': - *(t++) = '\f'; - break; - case 'n': - *(t++) = '\n'; - break; - case 'r': - *(t++) = '\r'; - break; - case 't': - *(t++) = '\t'; - break; - case 'v': - *(t++) = '\v'; - break; - case '\\': - *(t++) = '\\'; - break; - case '"': - *(t++) = '"'; - break; - case '\'': - *(t++) = '\''; - break; - - case 's': - /* This is an extension of the XDG syntax files */ - *(t++) = ' '; - break; - - case 'x': { - /* hexadecimal encoding */ - int a, b; - - a = unhexchar(f[1]); - b = unhexchar(f[2]); - - if (a < 0 || b < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = 'x'; - } else { - *(t++) = (char) ((a << 4) | b); - f += 2; - } - - break; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - /* octal encoding */ - int a, b, c; - - a = unoctchar(f[0]); - b = unoctchar(f[1]); - c = unoctchar(f[2]); - - if (a < 0 || b < 0 || c < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = f[0]; - } else { - *(t++) = (char) ((a << 6) | (b << 3) | c); - f += 2; - } - - break; - } - - case 0: - /* premature end of string.*/ - *(t++) = '\\'; - goto finish; - - default: - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = *f; - break; - } - } - -finish: - *t = 0; - return r; -} - -char *cunescape_length(const char *s, size_t length) { - return cunescape_length_with_prefix(s, length, NULL); -} - -char *cunescape(const char *s) { - assert(s); - - return cunescape_length(s, strlen(s)); -} - -char *xescape(const char *s, const char *bad) { - char *r, *t; - const char *f; - - /* Escapes all chars in bad, in addition to \ and all special - * chars, in \xFF style escaping. May be reversed with - * cunescape. */ - - r = new(char, strlen(s) * 4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) { - - if ((*f < ' ') || (*f >= 127) || - (*f == '\\') || strchr(bad, *f)) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *bus_path_escape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Escapes all chars that D-Bus' object path cannot deal - * with. Can be reverse with bus_path_unescape() */ - - if (!(r = new(char, strlen(s)*3+1))) - return NULL; - - for (f = s, t = r; *f; f++) { - - if (!(*f >= 'A' && *f <= 'Z') && - !(*f >= 'a' && *f <= 'z') && - !(*f >= '0' && *f <= '9')) { - *(t++) = '_'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *bus_path_unescape(const char *f) { - char *r, *t; - - assert(f); - - if (!(r = strdup(f))) - return NULL; - - for (t = r; *f; f++) { - - if (*f == '_') { - int a, b; - - if ((a = unhexchar(f[1])) < 0 || - (b = unhexchar(f[2])) < 0) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '_'; - } else { - *(t++) = (char) ((a << 4) | b); - f += 2; - } - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *ascii_strlower(char *t) { - char *p; - - assert(t); - - for (p = t; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; - - return t; -} - -static bool ignore_file_allow_backup(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".swp"); -} - -bool ignore_file(const char *filename) { - assert(filename); - - if (endswith(filename, "~")) - return false; - - return ignore_file_allow_backup(filename); -} - -int fd_nonblock(int fd, bool nonblock) { - int flags; - - assert(fd >= 0); - - if ((flags = fcntl(fd, F_GETFL, 0)) < 0) - return -errno; - - if (nonblock) - flags |= O_NONBLOCK; - else - flags &= ~O_NONBLOCK; - - if (fcntl(fd, F_SETFL, flags) < 0) - return -errno; - - return 0; -} - -int fd_cloexec(int fd, bool cloexec) { - int flags; - - assert(fd >= 0); - - if ((flags = fcntl(fd, F_GETFD, 0)) < 0) - return -errno; - - if (cloexec) - flags |= FD_CLOEXEC; - else - flags &= ~FD_CLOEXEC; - - if (fcntl(fd, F_SETFD, flags) < 0) - return -errno; - - return 0; -} - -static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { - unsigned i; - - assert(n_fdset == 0 || fdset); - - for (i = 0; i < n_fdset; i++) - if (fdset[i] == fd) - return true; - - return false; -} - -int close_all_fds(const int except[], unsigned n_except) { - DIR *d; - struct dirent *de; - int r = 0; - - assert(n_except == 0 || except); - - d = opendir("/proc/self/fd"); - if (!d) { - int fd; - struct rlimit rl; - - /* When /proc isn't available (for example in chroots) - * the fallback is brute forcing through the fd - * table */ - - assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - for (fd = 3; fd < (int) rl.rlim_max; fd ++) { - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) - if (errno != EBADF && r == 0) - r = -errno; - } - - return r; - } - - while ((de = readdir(d))) { - int fd = -1; - - if (ignore_file(de->d_name)) - continue; - - if (safe_atoi(de->d_name, &fd) < 0) - /* Let's better ignore this, just in case */ - continue; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) { - /* Valgrind has its own FD and doesn't want to have it closed */ - if (errno != EBADF && r == 0) - r = -errno; - } - } - - closedir(d); - return r; -} - -bool chars_intersect(const char *a, const char *b) { - const char *p; - - /* Returns true if any of the chars in a are in b. */ - for (p = a; *p; p++) - if (strchr(b, *p)) - return true; - - return false; -} - -char *format_timestamp(char *buf, size_t l, usec_t t) { - struct tm tm; - time_t sec; - - assert(buf); - assert(l > 0); - - if (t <= 0) - return NULL; - - sec = (time_t) (t / USEC_PER_SEC); - - if (strftime(buf, l, "%a, %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) <= 0) - return NULL; - - return buf; -} - -char *format_timestamp_pretty(char *buf, size_t l, usec_t t) { - usec_t n, d; - - n = now(CLOCK_REALTIME); - - if (t <= 0 || t > n || t + USEC_PER_DAY*7 <= t) - return NULL; - - d = n - t; - - if (d >= USEC_PER_YEAR) - snprintf(buf, l, "%llu years and %llu months ago", - (unsigned long long) (d / USEC_PER_YEAR), - (unsigned long long) ((d % USEC_PER_YEAR) / USEC_PER_MONTH)); - else if (d >= USEC_PER_MONTH) - snprintf(buf, l, "%llu months and %llu days ago", - (unsigned long long) (d / USEC_PER_MONTH), - (unsigned long long) ((d % USEC_PER_MONTH) / USEC_PER_DAY)); - else if (d >= USEC_PER_WEEK) - snprintf(buf, l, "%llu weeks and %llu days ago", - (unsigned long long) (d / USEC_PER_WEEK), - (unsigned long long) ((d % USEC_PER_WEEK) / USEC_PER_DAY)); - else if (d >= 2*USEC_PER_DAY) - snprintf(buf, l, "%llu days ago", (unsigned long long) (d / USEC_PER_DAY)); - else if (d >= 25*USEC_PER_HOUR) - snprintf(buf, l, "1 day and %lluh ago", - (unsigned long long) ((d - USEC_PER_DAY) / USEC_PER_HOUR)); - else if (d >= 6*USEC_PER_HOUR) - snprintf(buf, l, "%lluh ago", - (unsigned long long) (d / USEC_PER_HOUR)); - else if (d >= USEC_PER_HOUR) - snprintf(buf, l, "%lluh %llumin ago", - (unsigned long long) (d / USEC_PER_HOUR), - (unsigned long long) ((d % USEC_PER_HOUR) / USEC_PER_MINUTE)); - else if (d >= 5*USEC_PER_MINUTE) - snprintf(buf, l, "%llumin ago", - (unsigned long long) (d / USEC_PER_MINUTE)); - else if (d >= USEC_PER_MINUTE) - snprintf(buf, l, "%llumin %llus ago", - (unsigned long long) (d / USEC_PER_MINUTE), - (unsigned long long) ((d % USEC_PER_MINUTE) / USEC_PER_SEC)); - else if (d >= USEC_PER_SEC) - snprintf(buf, l, "%llus ago", - (unsigned long long) (d / USEC_PER_SEC)); - else if (d >= USEC_PER_MSEC) - snprintf(buf, l, "%llums ago", - (unsigned long long) (d / USEC_PER_MSEC)); - else if (d > 0) - snprintf(buf, l, "%lluus ago", - (unsigned long long) d); - else - snprintf(buf, l, "now"); - - buf[l-1] = 0; - return buf; -} - -char *format_timespan(char *buf, size_t l, usec_t t) { - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "w", USEC_PER_WEEK }, - { "d", USEC_PER_DAY }, - { "h", USEC_PER_HOUR }, - { "min", USEC_PER_MINUTE }, - { "s", USEC_PER_SEC }, - { "ms", USEC_PER_MSEC }, - { "us", 1 }, - }; - - unsigned i; - char *p = buf; - - assert(buf); - assert(l > 0); - - if (t == (usec_t) -1) - return NULL; - - if (t == 0) { - snprintf(p, l, "0"); - p[l-1] = 0; - return p; - } - - /* The result of this function can be parsed with parse_usec */ - - for (i = 0; i < ELEMENTSOF(table); i++) { - int k; - size_t n; - - if (t < table[i].usec) - continue; - - if (l <= 1) - break; - - k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix); - n = MIN((size_t) k, l); - - l -= n; - p += n; - - t %= table[i].usec; - } - - *p = 0; - - return buf; -} - -bool fstype_is_network(const char *fstype) { - static const char table[] = - "cifs\0" - "smbfs\0" - "ncpfs\0" - "nfs\0" - "nfs4\0" - "gfs\0" - "gfs2\0"; - - 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; - char 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_t) -1) { - 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_t) -1) - if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) - return -ETIMEDOUT; - - if (!fgets(line, sizeof(line), f)) - return -EIO; - - truncate_nl(line); - - if (strlen(line) != 1) - return -EBADMSG; - - if (need_nl) - *need_nl = false; - - *ret = line[0]; - return 0; -} - -int ask(char *ret, const char *replies, const char *text, ...) { - - assert(ret); - assert(replies); - assert(text); - - for (;;) { - va_list ap; - char c; - int r; - 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_t) -1, &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 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) { - int fd, r; - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - r = reset_terminal_fd(fd, true); - close_nointr_nofail(fd); - - return r; -} - -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 - */ - - for (;;) { - fd = open(name, mode); - if (fd >= 0) - break; - - if (errno != EIO) - return -errno; - - /* Max 1s in total */ - if (c >= 20) - return -errno; - - usleep(50 * USEC_PER_MSEC); - c++; - } - - if (fd < 0) - return -errno; - - r = isatty(fd); - if (r < 0) { - close_nointr_nofail(fd); - return -errno; - } - - if (!r) { - close_nointr_nofail(fd); - return -ENOTTY; - } - - return fd; -} - -int flush_fd(int fd) { - struct pollfd pollfd; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLIN; - - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; - - if ((r = poll(&pollfd, 1, 0)) < 0) { - - if (errno == EINTR) - continue; - - return -errno; - } - - if (r == 0) - return 0; - - if ((l = read(fd, buf, sizeof(buf))) < 0) { - - if (errno == EINTR) - continue; - - if (errno == EAGAIN) - return 0; - - return -errno; - } - - if (l <= 0) - return 0; - } -} - -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; - struct sigaction sa_old, sa_new; - - 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_t) -1) - ts = now(CLOCK_MONOTONIC); - - if (!fail && !force) { - notify = inotify_init1(IN_CLOEXEC | (timeout != (usec_t) -1 ? 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 (;;) { - 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. */ - zero(sa_new); - sa_new.sa_handler = SIG_IGN; - sa_new.sa_flags = SA_RESTART; - 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 (;;) { - uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; - ssize_t l; - struct inotify_event *e; - - if (timeout != (usec_t) -1) { - 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, inotify_buffer, sizeof(inotify_buffer)); - if (l < 0) { - - if (errno == EINTR || errno == EAGAIN) - continue; - - r = -errno; - goto fail; - } - - e = (struct inotify_event*) inotify_buffer; - - while (l > 0) { - size_t step; - - if (e->wd != wd || !(e->mask & IN_CLOSE)) { - r = -EIO; - goto fail; - } - - step = sizeof(struct inotify_event) + e->len; - assert(step <= (size_t) l); - - e = (struct inotify_event*) ((uint8_t*) e + step); - l -= step; - } - - 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. */ - close_nointr_nofail(fd); - } - - if (notify >= 0) - close_nointr_nofail(notify); - - r = reset_terminal_fd(fd, true); - if (r < 0) - log_warning("Failed to reset terminal: %s", strerror(-r)); - - return fd; - -fail: - if (fd >= 0) - close_nointr_nofail(fd); - - if (notify >= 0) - close_nointr_nofail(notify); - - return r; -} - -int release_terminal(void) { - int r = 0, fd; - struct sigaction sa_old, sa_new; - - if ((fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC)) < 0) - return -errno; - - /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed - * by our own TIOCNOTTY */ - - zero(sa_new); - sa_new.sa_handler = SIG_IGN; - sa_new.sa_flags = SA_RESTART; - assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); - - if (ioctl(fd, TIOCNOTTY) < 0) - r = -errno; - - assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); - - close_nointr_nofail(fd); - 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; - va_list ap; - int r = 0; - - zero(sa); - sa.sa_handler = SIG_IGN; - sa.sa_flags = SA_RESTART; - - 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; - va_list ap; - int r = 0; - - zero(sa); - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_RESTART; - - 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 close_pipe(int p[]) { - int a = 0, b = 0; - - assert(p); - - if (p[0] >= 0) { - a = close_nointr(p[0]); - p[0] = -1; - } - - if (p[1] >= 0) { - b = close_nointr(p[1]); - p[1] = -1; - } - - return a < 0 ? a : b; -} - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - p = buf; - - while (nbytes > 0) { - ssize_t k; - - if ((k = read(fd, p, nbytes)) <= 0) { - - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - struct pollfd pollfd; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLIN; - - if (poll(&pollfd, 1, -1) < 0) { - if (errno == EINTR) - continue; - - return n > 0 ? n : -errno; - } - - if (pollfd.revents != POLLIN) - return n > 0 ? n : -EIO; - - continue; - } - - return n > 0 ? n : (k < 0 ? -errno : 0); - } - - p += k; - nbytes -= k; - n += k; - } - - return n; -} - -ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { - const uint8_t *p; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - p = buf; - - while (nbytes > 0) { - ssize_t k; - - k = write(fd, p, nbytes); - if (k <= 0) { - - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - struct pollfd pollfd; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLOUT; - - if (poll(&pollfd, 1, -1) < 0) { - if (errno == EINTR) - continue; - - return n > 0 ? n : -errno; - } - - if (pollfd.revents != POLLOUT) - return n > 0 ? n : -EIO; - - continue; - } - - return n > 0 ? n : (k < 0 ? -errno : 0); - } - - p += k; - nbytes -= k; - n += k; - } - - return n; -} - -int parse_usec(const char *t, usec_t *usec) { - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "seconds", USEC_PER_SEC }, - { "second", USEC_PER_SEC }, - { "sec", USEC_PER_SEC }, - { "s", USEC_PER_SEC }, - { "minutes", USEC_PER_MINUTE }, - { "minute", USEC_PER_MINUTE }, - { "min", USEC_PER_MINUTE }, - { "months", USEC_PER_MONTH }, - { "month", USEC_PER_MONTH }, - { "msec", USEC_PER_MSEC }, - { "ms", USEC_PER_MSEC }, - { "m", USEC_PER_MINUTE }, - { "hours", USEC_PER_HOUR }, - { "hour", USEC_PER_HOUR }, - { "hr", USEC_PER_HOUR }, - { "h", USEC_PER_HOUR }, - { "days", USEC_PER_DAY }, - { "day", USEC_PER_DAY }, - { "d", USEC_PER_DAY }, - { "weeks", USEC_PER_WEEK }, - { "week", USEC_PER_WEEK }, - { "w", USEC_PER_WEEK }, - { "years", USEC_PER_YEAR }, - { "year", USEC_PER_YEAR }, - { "y", USEC_PER_YEAR }, - { "usec", 1ULL }, - { "us", 1ULL }, - { "", USEC_PER_SEC }, /* default is sec */ - }; - - const char *p; - usec_t r = 0; - - assert(t); - assert(usec); - - p = t; - do { - long long l; - char *e; - unsigned i; - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno != 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - r += (usec_t) l * table[i].usec; - p = e + strlen(table[i].suffix); - break; - } - - if (i >= ELEMENTSOF(table)) - return -EINVAL; - - } while (*p != 0); - - *usec = r; - - return 0; -} - -int parse_nsec(const char *t, nsec_t *nsec) { - static const struct { - const char *suffix; - nsec_t nsec; - } table[] = { - { "seconds", NSEC_PER_SEC }, - { "second", NSEC_PER_SEC }, - { "sec", NSEC_PER_SEC }, - { "s", NSEC_PER_SEC }, - { "minutes", NSEC_PER_MINUTE }, - { "minute", NSEC_PER_MINUTE }, - { "min", NSEC_PER_MINUTE }, - { "months", NSEC_PER_MONTH }, - { "month", NSEC_PER_MONTH }, - { "msec", NSEC_PER_MSEC }, - { "ms", NSEC_PER_MSEC }, - { "m", NSEC_PER_MINUTE }, - { "hours", NSEC_PER_HOUR }, - { "hour", NSEC_PER_HOUR }, - { "hr", NSEC_PER_HOUR }, - { "h", NSEC_PER_HOUR }, - { "days", NSEC_PER_DAY }, - { "day", NSEC_PER_DAY }, - { "d", NSEC_PER_DAY }, - { "weeks", NSEC_PER_WEEK }, - { "week", NSEC_PER_WEEK }, - { "w", NSEC_PER_WEEK }, - { "years", NSEC_PER_YEAR }, - { "year", NSEC_PER_YEAR }, - { "y", NSEC_PER_YEAR }, - { "usec", NSEC_PER_USEC }, - { "us", NSEC_PER_USEC }, - { "nsec", 1ULL }, - { "ns", 1ULL }, - { "", 1ULL }, /* default is nsec */ - }; - - const char *p; - nsec_t r = 0; - - assert(t); - assert(nsec); - - p = t; - do { - long long l; - char *e; - unsigned i; - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno != 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - r += (nsec_t) l * table[i].nsec; - p = e + strlen(table[i].suffix); - break; - } - - if (i >= ELEMENTSOF(table)) - return -EINVAL; - - } while (*p != 0); - - *nsec = r; - - return 0; -} - -int parse_bytes(const char *t, off_t *bytes) { - static const struct { - const char *suffix; - off_t factor; - } table[] = { - { "B", 1 }, - { "K", 1024ULL }, - { "M", 1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "", 1 }, - }; - - const char *p; - off_t r = 0; - - assert(t); - assert(bytes); - - p = t; - do { - long long l; - char *e; - unsigned i; - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno != 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - r += (off_t) l * table[i].factor; - p = e + strlen(table[i].suffix); - break; - } - - if (i >= ELEMENTSOF(table)) - return -EINVAL; - - } while (*p != 0); - - *bytes = r; - - return 0; -} - -int make_stdio(int fd) { - int r, s, t; - - assert(fd >= 0); - - r = dup3(fd, STDIN_FILENO, 0); - s = dup3(fd, STDOUT_FILENO, 0); - t = dup3(fd, STDERR_FILENO, 0); - - if (fd >= 3) - close_nointr_nofail(fd); - - if (r < 0 || s < 0 || t < 0) - return -errno; - - /* We rely here that the new fd has O_CLOEXEC not set */ - - 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 - * sysfs or in /dev */ - - return - path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); -} - -int dir_is_empty(const char *path) { - _cleanup_closedir_ DIR *d; - int r; - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - union dirent_storage buf; - - r = readdir_r(d, &buf.de, &de); - if (r > 0) - return -r; - - if (!de) - return 1; - - if (!ignore_file(de->d_name)) - return 0; - } -} - -unsigned long long random_ull(void) { - _cleanup_close_ int fd; - uint64_t ull; - ssize_t r; - - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - goto fallback; - - r = loop_read(fd, &ull, sizeof(ull), true); - if (r != sizeof(ull)) - goto fallback; - - return ull; - -fallback: - return random() * RAND_MAX + random(); -} - -void rename_process(const char name[8]) { - assert(name); - - /* This is a like a poor man's setproctitle(). It changes the - * comm field, argv[0], and also the glibc's internally used - * name of the process. For the first one a limit of 16 chars - * applies, to the second one usually one of 10 (i.e. length - * of "/sbin/init"), to the third one one of 7 (i.e. length of - * "systemd"). If you pass a longer string it will be - * truncated */ - - prctl(PR_SET_NAME, name); - - if (program_invocation_name) - strncpy(program_invocation_name, name, strlen(program_invocation_name)); - - if (saved_argc > 0) { - int i; - - if (saved_argv[0]) - strncpy(saved_argv[0], name, strlen(saved_argv[0])); - - for (i = 1; i < saved_argc; i++) { - if (!saved_argv[i]) - break; - - memset(saved_argv[i], 0, strlen(saved_argv[i])); - } - } -} - -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); -} - -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)"); -} - -static char *lookup_uid(uid_t uid) { - long bufsize; - char *name; - _cleanup_free_ char *buf = NULL; - struct passwd pwbuf, *pw = NULL; - - /* Shortcut things to avoid NSS lookups */ - if (uid == 0) - return strdup("root"); - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize <= 0) - bufsize = 4096; - - buf = malloc(bufsize); - if (!buf) - return NULL; - - if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) - return strdup(pw->pw_name); - - if (asprintf(&name, "%lu", (unsigned long) uid) < 0) - return NULL; - - return name; -} - -char* getlogname_malloc(void) { - uid_t uid; - struct stat st; - - if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) - uid = st.st_uid; - else - uid = getuid(); - - return lookup_uid(uid); -} - -char *getusername_malloc(void) { - const char *e; - - e = getenv("USER"); - if (e) - return strdup(e); - - return lookup_uid(getuid()); -} - -int getttyname_malloc(int fd, char **r) { - char path[PATH_MAX], *c; - int k; - - assert(r); - - k = ttyname_r(fd, path, sizeof(path)); - if (k != 0) - return -k; - - char_array_0(path); - - c = strdup(startswith(path, "/dev/") ? path + 5 : path); - if (!c) - return -ENOMEM; - - *r = c; - return 0; -} - -int getttyname_harder(int fd, char **r) { - int k; - char *s; - - 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 k; - char line[LINE_MAX], *p, *fn; - unsigned long ttynr; - FILE *f; - - if (asprintf(&fn, "/proc/%lu/stat", (unsigned long) (pid <= 0 ? getpid() : pid)) < 0) - return -ENOMEM; - - f = fopen(fn, "re"); - free(fn); - if (!f) - return -errno; - - if (!fgets(line, sizeof(line), f)) { - k = feof(f) ? -EIO : -errno; - fclose(f); - return k; - } - - fclose(f); - - 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; - - *d = (dev_t) ttynr; - return 0; -} - -int get_ctty(pid_t pid, dev_t *_devnr, char **r) { - int k; - char fn[PATH_MAX], *s, *b, *p; - dev_t devnr; - - assert(r); - - k = get_ctty_devnr(pid, &devnr); - if (k < 0) - return k; - - snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr)); - char_array_0(fn); - - if ((k = readlink_malloc(fn, &s)) < 0) { - - if (k != -ENOENT) - return k; - - /* This is an ugly hack */ - if (major(devnr) == 136) { - if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; - } - - /* Probably something like the ptys which have no - * symlink in /dev/char. Let's return something - * vaguely useful. */ - - if (!(b = strdup(fn + 5))) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; - } - - if (startswith(s, "/dev/")) - p = s + 5; - else if (startswith(s, "../")) - p = s + 3; - else - p = s; - - b = strdup(p); - free(s); - - if (!b) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; -} - -int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) { - DIR *d; - int ret = 0; - - assert(fd >= 0); - - /* This returns the first error we run into, but nevertheless - * tries to go on. This closes the passed fd. */ - - d = fdopendir(fd); - if (!d) { - close_nointr_nofail(fd); - - return errno == ENOENT ? 0 : -errno; - } - - for (;;) { - struct dirent *de; - union dirent_storage buf; - bool is_dir, keep_around; - struct stat st; - int r; - - r = readdir_r(d, &buf.de, &de); - if (r != 0 && ret == 0) { - ret = -r; - break; - } - - if (!de) - break; - - if (streq(de->d_name, ".") || streq(de->d_name, "..")) - continue; - - if (de->d_type == DT_UNKNOWN || - honour_sticky || - (de->d_type == DT_DIR && root_dev)) { - if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; - } - - is_dir = S_ISDIR(st.st_mode); - keep_around = - honour_sticky && - (st.st_uid == 0 || st.st_uid == getuid()) && - (st.st_mode & S_ISVTX); - } else { - is_dir = de->d_type == DT_DIR; - keep_around = false; - } - - if (is_dir) { - int subdir_fd; - - /* if root_dev is set, remove subdirectories only, if device is same as dir */ - if (root_dev && st.st_dev != root_dev->st_dev) - continue; - - subdir_fd = openat(fd, de->d_name, - O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); - if (subdir_fd < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; - } - - r = rm_rf_children_dangerous(subdir_fd, only_dirs, honour_sticky, root_dev); - if (r < 0 && ret == 0) - ret = r; - - if (!keep_around) - if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - } - - } else if (!only_dirs && !keep_around) { - - if (unlinkat(fd, de->d_name, 0) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - } - } - } - - closedir(d); - - return ret; -} - -int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) { - struct statfs s; - - assert(fd >= 0); - - if (fstatfs(fd, &s) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - /* We refuse to clean disk file systems with this call. This - * is extra paranoia just to be sure we never ever remove - * non-state data */ - - if (s.f_type != TMPFS_MAGIC && - s.f_type != RAMFS_MAGIC) { - log_error("Attempted to remove disk file system, and we can't allow that."); - close_nointr_nofail(fd); - return -EPERM; - } - - return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev); -} - -static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) { - int fd, r; - struct statfs s; - - assert(path); - - /* We refuse to clean the root file system with this - * call. This is extra paranoia to never cause a really - * seriously broken system. */ - if (path_equal(path, "/")) { - log_error("Attempted to remove entire root file system, and we can't allow that."); - return -EPERM; - } - - fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); - if (fd < 0) { - - if (errno != ENOTDIR) - return -errno; - - if (!dangerous) { - if (statfs(path, &s) < 0) - return -errno; - - if (s.f_type != TMPFS_MAGIC && - s.f_type != RAMFS_MAGIC) { - log_error("Attempted to remove disk file system, and we can't allow that."); - return -EPERM; - } - } - - if (delete_root && !only_dirs) - if (unlink(path) < 0 && errno != ENOENT) - return -errno; - - return 0; - } - - if (!dangerous) { - if (fstatfs(fd, &s) < 0) { - close_nointr_nofail(fd); - return -errno; - } - - if (s.f_type != TMPFS_MAGIC && - s.f_type != RAMFS_MAGIC) { - log_error("Attempted to remove disk file system, and we can't allow that."); - close_nointr_nofail(fd); - return -EPERM; - } - } - - r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL); - if (delete_root) { - - if (honour_sticky && file_is_priv_sticky(path) > 0) - return r; - - if (rmdir(path) < 0 && errno != ENOENT) { - if (r == 0) - r = -errno; - } - } - - return r; -} - -int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) { - return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false); -} - -int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) { - return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true); -} - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { - assert(path); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != (mode_t) -1) - if (chmod(path, mode) < 0) - return -errno; - - if (uid != (uid_t) -1 || gid != (gid_t) -1) - if (chown(path, uid, gid) < 0) - return -errno; - - return 0; -} - -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { - assert(fd >= 0); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (fchmod(fd, mode) < 0) - return -errno; - - if (fchown(fd, uid, gid) < 0) - return -errno; - - return 0; -} - -cpu_set_t* cpu_set_malloc(unsigned *ncpus) { - cpu_set_t *r; - unsigned n = 1024; - - /* Allocates the cpuset in the right size */ - - for (;;) { - if (!(r = CPU_ALLOC(n))) - return NULL; - - if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) { - CPU_ZERO_S(CPU_ALLOC_SIZE(n), r); - - if (ncpus) - *ncpus = n; - - return r; - } - - CPU_FREE(r); - - if (errno != EINVAL) - return NULL; - - n *= 2; - } -} - -int status_vprintf(const char *status, bool ellipse, 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[5]; - int n = 0; - - 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, 75); - if (e) { - free(s); - s = e; - } - } - - zero(iovec); - - 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); - IOVEC_SET_STRING(iovec[n++], "\n"); - - if (writev(fd, iovec, n) < 0) - return -errno; - - return 0; -} - -int status_printf(const char *status, bool ellipse, const char *format, ...) { - va_list ap; - int r; - - assert(format); - - va_start(ap, format); - r = status_vprintf(status, ellipse, format, ap); - va_end(ap); - - return r; -} - -int status_welcome(void) { - int r; - _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL; - - r = parse_env_file("/etc/os-release", NEWLINE, - "PRETTY_NAME", &pretty_name, - "ANSI_COLOR", &ansi_color, - NULL); - if (r < 0 && r != -ENOENT) - log_warning("Failed to read /etc/os-release: %s", strerror(-r)); - - return status_printf(NULL, false, - "\nWelcome to \x1B[%sm%s\x1B[0m!\n", - isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); -} - -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 == '{') { - if (!(k = strnappend(r, word, e-word-1))) - goto fail; - - free(r); - r = k; - - word = e-1; - state = VARIABLE; - - } else if (*e == '$') { - if (!(k = strnappend(r, word, e-word))) - goto fail; - - free(r); - r = k; - - word = e+1; - state = WORD; - } else - state = WORD; - break; - - case VARIABLE: - if (*e == '}') { - const char *t; - - if (!(t = strv_env_get_with_length(env, word+2, e-word-2))) - t = ""; - - if (!(k = strappend(r, t))) - goto fail; - - free(r); - r = k; - - word = e+1; - state = WORD; - } - break; - } - } - - if (!(k = strnappend(r, word, e-word))) - goto fail; - - free(r); - return k; - -fail: - free(r); - return NULL; -} - -char **replace_env_argv(char **argv, char **env) { - char **r, **i; - unsigned k = 0, l = 0; - - l = strv_length(argv); - - if (!(r = new(char*, l+1))) - 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; - unsigned q; - - if ((e = strv_env_get(env, *i+1))) { - - if (!(m = strv_split_quoted(e))) { - r[k] = NULL; - strv_free(r); - return NULL; - } - } else - m = NULL; - - q = strv_length(m); - l = l + q - 1; - - if (!(w = realloc(r, sizeof(char*) * (l+1)))) { - r[k] = NULL; - strv_free(r); - strv_free(m); - return NULL; - } - - r = w; - if (m) { - memcpy(r + 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 */ - if (!(r[k++] = replace_env(*i, env))) { - strv_free(r); - return NULL; - } - } - - r[k] = NULL; - return r; -} - -int fd_columns(int fd) { - struct winsize ws; - zero(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; - unsigned c; - - if (_likely_(cached_columns > 0)) - return cached_columns; - - c = 0; - e = getenv("COLUMNS"); - if (e) - safe_atou(e, &c); - - if (c <= 0) - c = fd_columns(STDOUT_FILENO); - - if (c <= 0) - c = 80; - - cached_columns = c; - return c; -} - -int fd_lines(int fd) { - struct winsize ws; - zero(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; - unsigned l; - - if (_likely_(cached_lines > 0)) - return cached_lines; - - l = 0; - e = getenv("LINES"); - if (e) - safe_atou(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 running_in_chroot(void) { - struct stat a, b; - - zero(a); - zero(b); - - /* Only works as root */ - - if (stat("/proc/1/root", &a) < 0) - return -errno; - - if (stat("/", &b) < 0) - return -errno; - - return - a.st_dev != b.st_dev || - a.st_ino != b.st_ino; -} - -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *r; - - assert(s); - assert(percent <= 100); - assert(new_length >= 3); - - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - r = new0(char, new_length+1); - if (!r) - return r; - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; - - memcpy(r, s, x); - r[x] = '.'; - r[x+1] = '.'; - r[x+2] = '.'; - memcpy(r + x + 3, - s + old_length - (new_length - x - 3), - new_length - x - 3); - - return r; -} - -char *ellipsize(const char *s, size_t length, unsigned percent) { - return ellipsize_mem(s, strlen(s), length, percent); -} - -int touch(const char *path) { - int fd; - - assert(path); - - /* This just opens the file for writing, ensuring it - * exists. It doesn't call utimensat() the way /usr/bin/touch - * does it. */ - - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644); - if (fd < 0) - return -errno; - - close_nointr_nofail(fd); - return 0; -} - -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...*/ - - l = strlen(s); - if (l < 2) - return strdup(s); - - if (strchr(quotes, s[0]) && s[l-1] == s[0]) - return strndup(s+1, l-2); - - return strdup(s); -} - -char *normalize_env_assignment(const char *s) { - _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL; - char *eq, *r; - - eq = strchr(s, '='); - if (!eq) { - char *t; - - r = strdup(s); - if (!r) - return NULL; - - t = strstrip(r); - if (t == r) - return r; - - memmove(r, t, strlen(t) + 1); - return r; - } - - name = strndup(s, eq - s); - if (!name) - return NULL; - - p = strdup(eq + 1); - if (!p) - return NULL; - - value = unquote(strstrip(p), QUOTES); - if (!value) - return NULL; - - if (asprintf(&r, "%s=%s", strstrip(name), value) < 0) - r = NULL; - - return r; -} - -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; - } -} - -int wait_for_terminate_and_warn(const char *name, pid_t pid) { - int r; - siginfo_t status; - - assert(name); - assert(pid > 1); - - r = wait_for_terminate(pid, &status); - if (r < 0) { - log_warning("Failed to wait for %s: %s", name, strerror(-r)); - return r; - } - - if (status.si_code == CLD_EXITED) { - if (status.si_status != 0) { - log_warning("%s failed with error code %i.", name, status.si_status); - return status.si_status; - } - - log_debug("%s succeeded.", name); - return 0; - - } 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 */ - close_all_fds(NULL, 0); - - sync(); - - for (;;) - pause(); -} - -bool null_or_empty(struct stat *st) { - assert(st); - - if (S_ISREG(st->st_mode) && st->st_size <= 0) - return true; - - if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - return true; - - return false; -} - -int null_or_empty_path(const char *fn) { - struct stat st; - - assert(fn); - - if (stat(fn, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -DIR *xopendirat(int fd, const char *name, int flags) { - int nfd; - DIR *d; - - nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags); - if (nfd < 0) - return NULL; - - d = fdopendir(nfd); - if (!d) { - close_nointr_nofail(nfd); - return NULL; - } - - 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; -} - -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { - - assert(f); - assert(name); - assert(t); - - if (!dual_timestamp_is_set(t)) - return; - - fprintf(f, "%s=%llu %llu\n", - name, - (unsigned long long) t->realtime, - (unsigned long long) t->monotonic); -} - -void dual_timestamp_deserialize(const char *value, dual_timestamp *t) { - unsigned long long a, b; - - assert(value); - assert(t); - - if (sscanf(value, "%lli %llu", &a, &b) != 2) - log_debug("Failed to parse finish timestamp value %s", value); - else { - t->realtime = a; - t->monotonic = b; - } -} - -static char *tag_to_udev_node(const char *tagvalue, const char *by) { - char *dn, *t, *u; - int r; - - /* FIXME: to follow udev's logic 100% we need to leave valid - * UTF8 chars unescaped */ - - u = unquote(tagvalue, "\"\'"); - if (u == NULL) - return NULL; - - t = xescape(u, "/ "); - free(u); - - if (t == NULL) - return NULL; - - r = asprintf(&dn, "/dev/disk/by-%s/%s", by, t); - free(t); - - if (r < 0) - return NULL; - - return dn; -} - -char *fstab_node_to_udev_node(const char *p) { - assert(p); - - if (startswith(p, "LABEL=")) - return tag_to_udev_node(p+6, "label"); - - if (startswith(p, "UUID=")) - return tag_to_udev_node(p+5, "uuid"); - - if (startswith(p, "PARTUUID=")) - return tag_to_udev_node(p+9, "partuuid"); - - if (startswith(p, "PARTLABEL=")) - return tag_to_udev_node(p+10, "partlabel"); - - return strdup(p); -} - -bool tty_is_vc(const char *tty) { - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - 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; -} - -bool tty_is_vc_resolve(const char *tty) { - char *active = NULL; - bool b; - - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - /* 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 (streq(tty, "console") && path_is_read_only_fs("/sys") <= 0) - if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) { - /* If multiple log outputs are configured the - * last one is what /dev/console points to */ - tty = strrchr(active, ' '); - if (tty) - tty++; - else - tty = active; - } - - b = tty_is_vc(tty); - free(active); - - return b; -} - -const char *default_term_for_tty(const char *tty) { - assert(tty); - - return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102"; -} - -bool dirent_is_file(const struct dirent *de) { - assert(de); - - if (ignore_file(de->d_name)) - return false; - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - return true; -} - -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { - assert(de); - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - if (ignore_file_allow_backup(de->d_name)) - return false; - - return endswith(de->d_name, suffix); -} - -void execute_directory(const char *directory, DIR *d, char *argv[]) { - DIR *_d = NULL; - struct dirent *de; - Hashmap *pids = NULL; - - assert(directory); - - /* Executes all binaries in a directory in parallel and waits - * until all they all finished. */ - - if (!d) { - if (!(_d = opendir(directory))) { - - if (errno == ENOENT) - return; - - log_error("Failed to enumerate directory %s: %m", directory); - return; - } - - d = _d; - } - - if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) { - log_error("Failed to allocate set."); - goto finish; - } - - while ((de = readdir(d))) { - char *path; - pid_t pid; - int k; - - if (!dirent_is_file(de)) - continue; - - if (asprintf(&path, "%s/%s", directory, de->d_name) < 0) { - log_oom(); - continue; - } - - if ((pid = fork()) < 0) { - log_error("Failed to fork: %m"); - free(path); - continue; - } - - if (pid == 0) { - char *_argv[2]; - /* Child */ - - if (!argv) { - _argv[0] = path; - _argv[1] = NULL; - argv = _argv; - } else - argv[0] = path; - - execv(path, argv); - - log_error("Failed to execute %s: %m", path); - _exit(EXIT_FAILURE); - } - - log_debug("Spawned %s as %lu", path, (unsigned long) pid); - - if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) { - log_error("Failed to add PID to set: %s", strerror(-k)); - free(path); - } - } - - while (!hashmap_isempty(pids)) { - pid_t pid = PTR_TO_UINT(hashmap_first_key(pids)); - siginfo_t si; - char *path; - - zero(si); - if (waitid(P_PID, pid, &si, WEXITED) < 0) { - - if (errno == EINTR) - continue; - - log_error("waitid() failed: %m"); - goto finish; - } - - if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) { - if (!is_clean_exit(si.si_code, si.si_status, NULL)) { - if (si.si_code == CLD_EXITED) - log_error("%s exited with exit status %i.", path, si.si_status); - else - log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status)); - } else - log_debug("%s exited successfully.", path); - - free(path); - } - } - -finish: - if (_d) - closedir(_d); - - if (pids) - hashmap_free_free(pids); -} - -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; - - if (!nulstr) - return false; - - NULSTR_FOREACH(i, nulstr) - if (streq(i, needle)) - return true; - - return false; -} - -bool plymouth_running(void) { - return access("/run/plymouth/pid", F_OK) >= 0; -} - -char* strshorten(char *s, size_t l) { - assert(s); - - if (l < strlen(s)) - s[l] = 0; - - return s; -} - -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; - - if (isempty(s)) - return false; - - for (p = s; *p; p++) - if (!hostname_valid_char(*p)) - return false; - - if (p-s > HOST_NAME_MAX) - return false; - - return true; -} - -char* hostname_cleanup(char *s) { - char *p, *d; - - for (p = s, d = s; *p; p++) - if ((*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z') || - (*p >= '0' && *p <= '9') || - *p == '-' || - *p == '_' || - *p == '.') - *(d++) = *p; - - *d = 0; - - strshorten(s, HOST_NAME_MAX); - return s; -} - -int pipe_eof(int fd) { - struct pollfd pollfd; - int r; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLIN|POLLHUP; - - r = poll(&pollfd, 1, 0); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents & POLLHUP; -} - -int fd_wait_for_event(int fd, int event, usec_t t) { - struct pollfd pollfd; - int r; - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = event; - - r = poll(&pollfd, 1, t == (usec_t) -1 ? -1 : (int) (t / USEC_PER_MSEC)); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents; -} - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { - FILE *f; - char *t; - const char *fn; - size_t k; - int fd; - - assert(path); - assert(_f); - assert(_temp_path); - - t = new(char, strlen(path) + 1 + 6 + 1); - if (!t) - return -ENOMEM; - - fn = path_get_file_name(path); - k = fn-path; - memcpy(t, path, k); - t[k] = '.'; - stpcpy(stpcpy(t+k+1, fn), "XXXXXX"); - - fd = mkostemp(t, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - free(t); - return -errno; - } - - f = fdopen(fd, "we"); - if (!f) { - unlink(t); - free(t); - return -errno; - } - - *_f = f; - *_temp_path = t; - - return 0; -} - -int terminal_vhangup_fd(int fd) { - assert(fd >= 0); - - if (ioctl(fd, TIOCVHANGUP) < 0) - return -errno; - - return 0; -} - -int terminal_vhangup(const char *name) { - int fd, r; - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - r = terminal_vhangup_fd(fd); - close_nointr_nofail(fd); - - return r; -} - -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); - close_nointr_nofail(fd); - - return 0; - } - - if (!startswith(name, "/dev/tty")) - return -EINVAL; - - r = safe_atou(name+8, &u); - 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); - close_nointr_nofail(fd); - - if (r >= 0) - return 0; - - if (errno != EBUSY) - 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); - close_nointr_nofail(fd); - - return 0; -} - -int copy_file(const char *from, const char *to) { - int r, fdf, fdt; - - assert(from); - assert(to); - - fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fdf < 0) - return -errno; - - fdt = open(to, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOCTTY, 0644); - if (fdt < 0) { - close_nointr_nofail(fdf); - return -errno; - } - - for (;;) { - char buf[PIPE_BUF]; - ssize_t n, k; - - n = read(fdf, buf, sizeof(buf)); - if (n < 0) { - r = -errno; - - close_nointr_nofail(fdf); - close_nointr(fdt); - unlink(to); - - return r; - } - - if (n == 0) - break; - - errno = 0; - k = loop_write(fdt, buf, n, false); - if (n != k) { - r = k < 0 ? k : (errno ? -errno : -EIO); - - close_nointr_nofail(fdf); - close_nointr(fdt); - - unlink(to); - return r; - } - } - - close_nointr_nofail(fdf); - r = close_nointr(fdt); - - if (r < 0) { - unlink(to); - return r; - } - - return 0; -} - -int symlink_atomic(const char *from, const char *to) { - char *x; - _cleanup_free_ char *t; - const char *fn; - size_t k; - unsigned long long ull; - unsigned i; - int r; - - assert(from); - assert(to); - - t = new(char, strlen(to) + 1 + 16 + 1); - if (!t) - return -ENOMEM; - - fn = path_get_file_name(to); - k = fn-to; - memcpy(t, to, k); - t[k] = '.'; - x = stpcpy(t+k+1, fn); - - ull = random_ull(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(ull & 0xF); - ull >>= 4; - } - - *x = 0; - - if (symlink(from, t) < 0) - return -errno; - - if (rename(t, to) < 0) { - r = -errno; - unlink(t); - return r; - } - - return 0; -} - -bool display_is_local(const char *display) { - assert(display); - - return - display[0] == ':' && - display[1] >= '0' && - display[1] <= '9'; -} - -int socket_from_display(const char *display, char **path) { - size_t k; - char *f, *c; - - assert(display); - assert(path); - - if (!display_is_local(display)) - return -EINVAL; - - k = strspn(display+1, "0123456789"); - - f = new(char, sizeof("/tmp/.X11-unix/X") + k); - if (!f) - return -ENOMEM; - - c = stpcpy(f, "/tmp/.X11-unix/X"); - memcpy(c, display+1, k); - c[k] = 0; - - *path = f; - - return 0; -} - -int get_user_creds( - const char **username, - uid_t *uid, gid_t *gid, - const char **home, - const char **shell) { - - struct passwd *p; - uid_t u; - - assert(username); - assert(*username); - - /* We enforce some special rules for uid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*username, "root") || streq(*username, "0")) { - *username = "root"; - - if (uid) - *uid = 0; - - if (gid) - *gid = 0; - - if (home) - *home = "/root"; - - if (shell) - *shell = "/bin/sh"; - - return 0; - } - - if (parse_uid(*username, &u) >= 0) { - errno = 0; - p = getpwuid(u); - - /* If there are multiple users with the same id, make - * sure to leave $USER to the configured value instead - * of the first occurrence in the database. However if - * the uid was configured by a numeric uid, then let's - * pick the real username from /etc/passwd. */ - if (p) - *username = p->pw_name; - } else { - errno = 0; - p = getpwnam(*username); - } - - if (!p) - return errno != 0 ? -errno : -ESRCH; - - if (uid) - *uid = p->pw_uid; - - if (gid) - *gid = p->pw_gid; - - if (home) - *home = p->pw_dir; - - if (shell) - *shell = p->pw_shell; - - return 0; -} - -int get_group_creds(const char **groupname, gid_t *gid) { - struct group *g; - gid_t id; - - assert(groupname); - - /* We enforce some special rules for gid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*groupname, "root") || streq(*groupname, "0")) { - *groupname = "root"; - - if (gid) - *gid = 0; - - return 0; - } - - if (parse_gid(*groupname, &id) >= 0) { - errno = 0; - g = getgrgid(id); - - if (g) - *groupname = g->gr_name; - } else { - errno = 0; - g = getgrnam(*groupname); - } - - if (!g) - return errno != 0 ? -errno : -ESRCH; - - if (gid) - *gid = g->gr_gid; - - return 0; -} - -int in_group(const char *name) { - gid_t gid, *gids; - int ngroups_max, r, i; - - r = get_group_creds(&name, &gid); - if (r < 0) - return r; - - if (getgid() == gid) - return 1; - - if (getegid() == gid) - return 1; - - ngroups_max = sysconf(_SC_NGROUPS_MAX); - assert(ngroups_max > 0); - - gids = alloca(sizeof(gid_t) * ngroups_max); - - r = getgroups(ngroups_max, gids); - if (r < 0) - return -errno; - - for (i = 0; i < r; i++) - if (gids[i] == gid) - return 1; - - return 0; -} - -int glob_exists(const char *path) { - glob_t g; - int r, k; - - assert(path); - - zero(g); - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - r = 0; - else if (k == GLOB_NOSPACE) - r = -ENOMEM; - else if (k == 0) - r = !strv_isempty(g.gl_pathv); - else - r = errno ? -errno : -EIO; - - globfree(&g); - - return r; -} - -int dirent_ensure_type(DIR *d, struct dirent *de) { - struct stat st; - - assert(d); - assert(de); - - if (de->d_type != DT_UNKNOWN) - return 0; - - if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) - return -errno; - - de->d_type = - S_ISREG(st.st_mode) ? DT_REG : - S_ISDIR(st.st_mode) ? DT_DIR : - S_ISLNK(st.st_mode) ? DT_LNK : - S_ISFIFO(st.st_mode) ? DT_FIFO : - S_ISSOCK(st.st_mode) ? DT_SOCK : - S_ISCHR(st.st_mode) ? DT_CHR : - S_ISBLK(st.st_mode) ? DT_BLK : - DT_UNKNOWN; - - return 0; -} - -int in_search_path(const char *path, char **search) { - char **i, *parent; - int r; - - r = path_get_parent(path, &parent); - if (r < 0) - return r; - - r = 0; - - STRV_FOREACH(i, search) { - if (path_equal(parent, *i)) { - r = 1; - break; - } - } - - free(parent); - - return r; -} - -int get_files_in_directory(const char *path, char ***list) { - DIR *d; - int r = 0; - unsigned n = 0; - char **l = NULL; - - assert(path); - - /* Returns all files in a directory in *list, and the number - * of files as return value. If list is NULL returns only the - * number */ - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - union dirent_storage buf; - int k; - - k = readdir_r(d, &buf.de, &de); - if (k != 0) { - r = -k; - goto finish; - } - - if (!de) - break; - - dirent_ensure_type(d, de); - - if (!dirent_is_file(de)) - continue; - - if (list) { - if ((unsigned) r >= n) { - char **t; - - n = MAX(16, 2*r); - t = realloc(l, sizeof(char*) * n); - if (!t) { - r = -ENOMEM; - goto finish; - } - - l = t; - } - - assert((unsigned) r < n); - - l[r] = strdup(de->d_name); - if (!l[r]) { - r = -ENOMEM; - goto finish; - } - - l[++r] = NULL; - } else - r++; - } - -finish: - if (d) - closedir(d); - - if (r >= 0) { - if (list) - *list = l; - } else - strv_free(l); - - return r; -} - -char *strjoin(const char *x, ...) { - va_list ap; - size_t l; - char *r, *p; - - va_start(ap, x); - - if (x) { - l = strlen(x); - - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - } else - l = 0; - - va_end(ap); - - r = new(char, l+1); - if (!r) - return NULL; - - if (x) { - p = stpcpy(r, x); - - va_start(ap, x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - - va_end(ap); - } else - r[0] = 0; - - return r; -} - -bool is_main_thread(void) { - static __thread int cached = 0; - - if (_unlikely_(cached == 0)) - cached = getpid() == gettid() ? 1 : -1; - - return cached > 0; -} - -int block_get_whole_disk(dev_t d, dev_t *ret) { - char *p, *s; - int r; - unsigned n, m; - - assert(ret); - - /* If it has a queue this is good enough for us */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { - *ret = d; - return 0; - } - - /* If it is a partition find the originating device */ - if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r < 0) - return -ENOENT; - - /* Get parent dev_t */ - if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) - return -ENOMEM; - - r = read_one_line_file(p, &s); - free(p); - - if (r < 0) - return r; - - r = sscanf(s, "%u:%u", &m, &n); - free(s); - - if (r != 2) - return -EINVAL; - - /* Only return this if it is really good enough for us. */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { - *ret = makedev(m, n); - return 0; - } - - return -ENOENT; -} - -int file_is_priv_sticky(const char *p) { - struct stat st; - - assert(p); - - if (lstat(p, &st) < 0) - return -errno; - - return - (st.st_uid == 0 || st.st_uid == getuid()) && - (st.st_mode & S_ISVTX); -} - -static const char *const ioprio_class_table[] = { - [IOPRIO_CLASS_NONE] = "none", - [IOPRIO_CLASS_RT] = "realtime", - [IOPRIO_CLASS_BE] = "best-effort", - [IOPRIO_CLASS_IDLE] = "idle" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); - -static const char *const sigchld_code_table[] = { - [CLD_EXITED] = "exited", - [CLD_KILLED] = "killed", - [CLD_DUMPED] = "dumped", - [CLD_TRAPPED] = "trapped", - [CLD_STOPPED] = "stopped", - [CLD_CONTINUED] = "continued", -}; - -DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); - -static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { - [LOG_FAC(LOG_KERN)] = "kern", - [LOG_FAC(LOG_USER)] = "user", - [LOG_FAC(LOG_MAIL)] = "mail", - [LOG_FAC(LOG_DAEMON)] = "daemon", - [LOG_FAC(LOG_AUTH)] = "auth", - [LOG_FAC(LOG_SYSLOG)] = "syslog", - [LOG_FAC(LOG_LPR)] = "lpr", - [LOG_FAC(LOG_NEWS)] = "news", - [LOG_FAC(LOG_UUCP)] = "uucp", - [LOG_FAC(LOG_CRON)] = "cron", - [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", - [LOG_FAC(LOG_FTP)] = "ftp", - [LOG_FAC(LOG_LOCAL0)] = "local0", - [LOG_FAC(LOG_LOCAL1)] = "local1", - [LOG_FAC(LOG_LOCAL2)] = "local2", - [LOG_FAC(LOG_LOCAL3)] = "local3", - [LOG_FAC(LOG_LOCAL4)] = "local4", - [LOG_FAC(LOG_LOCAL5)] = "local5", - [LOG_FAC(LOG_LOCAL6)] = "local6", - [LOG_FAC(LOG_LOCAL7)] = "local7" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); - -static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", - [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); - -static const char* const sched_policy_table[] = { - [SCHED_OTHER] = "other", - [SCHED_BATCH] = "batch", - [SCHED_IDLE] = "idle", - [SCHED_FIFO] = "fifo", - [SCHED_RR] = "rr" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); - -static const char* const rlimit_table[] = { - [RLIMIT_CPU] = "LimitCPU", - [RLIMIT_FSIZE] = "LimitFSIZE", - [RLIMIT_DATA] = "LimitDATA", - [RLIMIT_STACK] = "LimitSTACK", - [RLIMIT_CORE] = "LimitCORE", - [RLIMIT_RSS] = "LimitRSS", - [RLIMIT_NOFILE] = "LimitNOFILE", - [RLIMIT_AS] = "LimitAS", - [RLIMIT_NPROC] = "LimitNPROC", - [RLIMIT_MEMLOCK] = "LimitMEMLOCK", - [RLIMIT_LOCKS] = "LimitLOCKS", - [RLIMIT_SIGPENDING] = "LimitSIGPENDING", - [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", - [RLIMIT_NICE] = "LimitNICE", - [RLIMIT_RTPRIO] = "LimitRTPRIO", - [RLIMIT_RTTIME] = "LimitRTTIME" -}; - -DEFINE_STRING_TABLE_LOOKUP(rlimit, int); - -static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", - [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", -}; - -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 char buf[12]; - const char *name; - - name = __signal_to_string(signo); - if (name) - return name; - - if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf) - 1, "RTMIN+%d", signo - SIGRTMIN); - else - snprintf(buf, sizeof(buf) - 1, "%d", signo); - char_array_0(buf); - 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 -1; -} - -bool kexec_loaded(void) { - bool loaded = false; - char *s; - - if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { - if (s[0] == '1') - loaded = true; - free(s); - } - return loaded; -} - -int strdup_or_null(const char *a, char **b) { - char *c; - - assert(b); - - if (!a) { - *b = NULL; - return 0; - } - - c = strdup(a); - if (!c) - return -ENOMEM; - - *b = c; - return 0; -} - -int prot_from_flags(int flags) { - - switch (flags & O_ACCMODE) { - - case O_RDONLY: - return PROT_READ; - - case O_WRONLY: - return PROT_WRITE; - - case O_RDWR: - return PROT_READ|PROT_WRITE; - - default: - return -EINVAL; - } -} - -char *format_bytes(char *buf, size_t l, off_t t) { - unsigned i; - - static const struct { - const char *suffix; - off_t factor; - } table[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, - }; - - for (i = 0; i < ELEMENTSOF(table); i++) { - - if (t >= table[i].factor) { - snprintf(buf, l, - "%llu.%llu%s", - (unsigned long long) (t / table[i].factor), - (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL), - table[i].suffix); - - goto finish; - } - } - - snprintf(buf, l, "%lluB", (unsigned long long) t); - -finish: - buf[l-1] = 0; - return buf; - -} - -void* memdup(const void *p, size_t l) { - void *r; - - assert(p); - - r = malloc(l); - if (!r) - return NULL; - - memcpy(r, p, l); - return r; -} - -int fd_inc_sndbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && - l == sizeof(value) && - (size_t) value >= n*2) - return 0; - - value = (int) n; - r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)); - if (r < 0) - return -errno; - - return 1; -} - -int fd_inc_rcvbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && - l == sizeof(value) && - (size_t) value >= n*2) - return 0; - - value = (int) n; - r = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)); - if (r < 0) - return -errno; - - return 1; -} - -int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { - pid_t parent_pid, agent_pid; - int fd; - bool stdout_is_tty, stderr_is_tty; - unsigned n, i; - va_list ap; - char **l; - - assert(pid); - assert(path); - - parent_pid = getpid(); - - /* Spawns a temporary TTY agent, making sure it goes away when - * we go away */ - - agent_pid = fork(); - if (agent_pid < 0) - return -errno; - - if (agent_pid != 0) { - *pid = agent_pid; - return 0; - } - - /* In the child: - * - * Make sure the agent goes away when the parent dies */ - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) - _exit(EXIT_FAILURE); - - /* Check whether our parent died before we were able - * to set the death signal */ - if (getppid() != parent_pid) - _exit(EXIT_SUCCESS); - - /* Don't leak fds to the agent */ - close_all_fds(except, n_except); - - stdout_is_tty = isatty(STDOUT_FILENO); - stderr_is_tty = isatty(STDERR_FILENO); - - if (!stdout_is_tty || !stderr_is_tty) { - /* Detach from stdout/stderr. and reopen - * /dev/tty for them. This is important to - * ensure that when systemctl is started via - * popen() or a similar call that expects to - * read EOF we actually do generate EOF and - * not delay this indefinitely by because we - * keep an unused copy of stdin around. */ - fd = open("/dev/tty", O_WRONLY); - if (fd < 0) { - log_error("Failed to open /dev/tty: %m"); - _exit(EXIT_FAILURE); - } - - if (!stdout_is_tty) - dup2(fd, STDOUT_FILENO); - - if (!stderr_is_tty) - dup2(fd, STDERR_FILENO); - - if (fd > 2) - close(fd); - } - - /* Count arguments */ - va_start(ap, path); - for (n = 0; va_arg(ap, char*); n++) - ; - va_end(ap); - - /* Allocate strv */ - l = alloca(sizeof(char *) * (n + 1)); - - /* Fill in arguments */ - va_start(ap, path); - for (i = 0; i <= n; i++) - l[i] = va_arg(ap, char*); - va_end(ap); - - execv(path, l); - _exit(EXIT_FAILURE); -} - -int setrlimit_closest(int resource, const struct rlimit *rlim) { - struct rlimit highest, fixed; - - assert(rlim); - - if (setrlimit(resource, rlim) >= 0) - return 0; - - if (errno != EPERM) - return -errno; - - /* So we failed to set the desired setrlimit, then let's try - * to get as close as we can */ - assert_se(getrlimit(resource, &highest) == 0); - - fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); - fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); - - if (setrlimit(resource, &fixed) < 0) - return -errno; - - return 0; -} - -int getenv_for_pid(pid_t pid, const char *field, char **_value) { - char path[sizeof("/proc/")-1+10+sizeof("/environ")], *value = NULL; - int r; - FILE *f; - bool done = false; - size_t l; - - assert(field); - assert(_value); - - if (pid == 0) - pid = getpid(); - - snprintf(path, sizeof(path), "/proc/%lu/environ", (unsigned long) pid); - char_array_0(path); - - 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) { - r = -ENOMEM; - break; - } - - r = 1; - break; - } - - } while (!done); - - fclose(f); - - if (r >= 0) - *_value = value; - - return r; -} - -int can_sleep(const char *type) { - char *w, *state; - size_t l, k; - int r; - _cleanup_free_ char *p = NULL; - - assert(type); - - r = read_one_line_file("/sys/power/state", &p); - if (r < 0) - return r == -ENOENT ? 0 : r; - - k = strlen(type); - FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) - if (l == k && memcmp(w, type, l) == 0) - return true; - - return false; -} - -int can_sleep_disk(const char *type) { - char *w, *state; - size_t l, k; - int r; - _cleanup_free_ char *p = NULL; - - assert(type); - - r = read_one_line_file("/sys/power/disk", &p); - if (r < 0) - return r == -ENOENT ? 0 : r; - - k = strlen(type); - FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) { - if (l == k && memcmp(w, type, l) == 0) - return true; - - if (l == k + 2 && w[0] == '[' && memcmp(w + 1, type, l - 2) == 0 && w[l-1] == ']') - return true; - } - - return false; -} - -bool is_valid_documentation_url(const char *url) { - assert(url); - - if (startswith(url, "http://") && url[7]) - return true; - - if (startswith(url, "https://") && url[8]) - return true; - - if (startswith(url, "file:") && url[5]) - return true; - - if (startswith(url, "info:") && url[5]) - return true; - - if (startswith(url, "man:") && url[4]) - return true; - - return false; -} - -bool in_initrd(void) { - static __thread int saved = -1; - struct statfs s; - - if (saved >= 0) - return saved; - - /* We make two checks here: - * - * 1. the flag file /etc/initrd-release must exist - * 2. the root file system must be a memory file system - * - * The second check is extra paranoia, since misdetecting an - * initrd can have bad bad consequences due the initrd - * emptying when transititioning to the main systemd. - */ - - saved = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - (s.f_type == TMPFS_MAGIC || s.f_type == RAMFS_MAGIC); - - 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_t) -1); - if (fd < 0) { - log_error("Failed to acquire terminal: %s", strerror(-fd)); - return fd; - } - - r = make_stdio(fd); - if (r < 0) { - log_error("Failed to duplicate terminal fd: %s", strerror(-r)); - return r; - } - - return 0; -} - -int get_home_dir(char **_h) { - char *h; - const char *e; - uid_t u; - struct passwd *p; - - assert(_h); - - /* Take the user specified one */ - e = getenv("HOME"); - if (e) { - h = strdup(e); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - h = strdup("/root"); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_dir)) - return -EINVAL; - - h = strdup(p->pw_dir); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; -} - -int get_shell(char **_sh) { - char *sh; - const char *e; - uid_t u; - struct passwd *p; - - assert(_sh); - - /* Take the user specified one */ - e = getenv("SHELL"); - if (e) { - sh = strdup(e); - if (!sh) - return -ENOMEM; - - *_sh = sh; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - sh = strdup("/bin/sh"); - if (!sh) - return -ENOMEM; - - *_sh = sh; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_shell)) - return -EINVAL; - - sh = strdup(p->pw_shell); - if (!sh) - return -ENOMEM; - - *_sh = sh; - return 0; -} - -void freep(void *p) { - free(*(void**) p); -} - -void fclosep(FILE **f) { - if (*f) - fclose(*f); -} - -void closep(int *fd) { - if (*fd >= 0) - close_nointr_nofail(*fd); -} - -void closedirp(DIR **d) { - if (*d) - closedir(*d); -} - -void umaskp(mode_t *u) { - umask(*u); -} - -bool filename_is_safe(const char *p) { - - if (isempty(p)) - return false; - - if (strchr(p, '/')) - return false; - - if (streq(p, ".")) - return false; - - if (streq(p, "..")) - return false; - - if (strlen(p) > FILENAME_MAX) - return false; - - return true; -} - -bool string_is_safe(const char *p) { - const char *t; - - assert(p); - - for (t = p; *t; t++) { - if (*t > 0 && *t < ' ') - return false; - - if (strchr("\\\"\'", *t)) - return false; - } - - return true; -} - -int parse_timestamp(const char *t, usec_t *usec) { - const char *k; - struct tm tm, copy; - time_t x; - usec_t plus = 0, minus = 0, ret; - int r; - - /* - * Allowed syntaxes: - * - * 2012-09-22 16:34:22 - * 2012-09-22 16:34 (seconds will be set to 0) - * 2012-09-22 (time will be set to 00:00:00) - * 16:34:22 (date will be set to today) - * 16:34 (date will be set to today, seconds to 0) - * now - * yesterday (time is set to 00:00:00) - * today (time is set to 00:00:00) - * tomorrow (time is set to 00:00:00) - * +5min - * -5days - * - */ - - assert(t); - assert(usec); - - x = time(NULL); - assert_se(localtime_r(&x, &tm)); - - if (streq(t, "now")) - goto finish; - - else if (streq(t, "today")) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "yesterday")) { - tm.tm_mday --; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "tomorrow")) { - tm.tm_mday ++; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (t[0] == '+') { - - r = parse_usec(t+1, &plus); - if (r < 0) - return r; - - goto finish; - } else if (t[0] == '-') { - - r = parse_usec(t+1, &minus); - if (r < 0) - return r; - - goto finish; - } - - copy = tm; - k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - return -EINVAL; - -finish: - x = mktime(&tm); - if (x == (time_t) -1) - return -EINVAL; - - ret = (usec_t) x * USEC_PER_SEC; - - ret += plus; - if (ret > minus) - ret -= minus; - else - ret = 0; - - *usec = ret; - - return 0; -} - -/* hey glibc, APIs with callbacks without a user pointer are so useless */ -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar) (const void *, const void *, void *), void *arg) { - size_t l, u, idx; - const void *p; - int comparison; - - l = 0; - u = nmemb; - while (l < u) { - idx = (l + u) / 2; - p = (void *)(((const char *) base) + (idx * size)); - comparison = compar(key, p, arg); - if (comparison < 0) - u = idx; - else if (comparison > 0) - l = idx + 1; - else - return (void *)p; - } - return NULL; -} - -bool is_locale_utf8(void) { - const char *set; - static int cached_answer = -1; - - if (cached_answer >= 0) - goto out; - - if (!setlocale(LC_ALL, "")) { - cached_answer = true; - goto out; - } - - set = nl_langinfo(CODESET); - if (!set) { - cached_answer = true; - goto out; - } - - cached_answer = streq(set, "UTF-8"); -out: - return (bool)cached_answer; -} - -const char *draw_special_char(DrawSpecialChar ch) { - static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { - /* UTF-8 */ { - [DRAW_TREE_VERT] = "\342\224\202 ", /* │ */ - [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ - [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ - [DRAW_TRIANGULAR_BULLET] = "\342\200\243 ", /* ‣ */ - }, - /* ASCII fallback */ { - [DRAW_TREE_VERT] = "| ", - [DRAW_TREE_BRANCH] = "|-", - [DRAW_TREE_RIGHT] = "`-", - [DRAW_TRIANGULAR_BULLET] = "> ", - } - }; - - return draw_table[!is_locale_utf8()][ch]; -} - -char *strreplace(const char *text, const char *old_string, const char *new_string) { - const char *f; - char *t, *r; - size_t l, old_len, new_len; - - assert(text); - assert(old_string); - assert(new_string); - - old_len = strlen(old_string); - new_len = strlen(new_string); - - l = strlen(text); - r = new(char, l+1); - if (!r) - return NULL; - - f = text; - t = r; - while (*f) { - char *a; - size_t d, nl; - - if (!startswith(f, old_string)) { - *(t++) = *(f++); - continue; - } - - d = t - r; - nl = l - old_len + new_len; - a = realloc(r, nl + 1); - if (!a) - goto oom; - - l = nl; - r = a; - t = r + d; - - t = stpcpy(t, new_string); - f += old_len; - } - - *t = 0; - return r; - -oom: - free(r); - return NULL; -} diff --git a/src/shared/util.h b/src/shared/util.h deleted file mode 100644 index a148ebbc58..0000000000 --- a/src/shared/util.h +++ /dev/null @@ -1,615 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 <inttypes.h> -#include <time.h> -#include <sys/time.h> -#include <stdarg.h> -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <signal.h> -#include <sched.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <dirent.h> -#include <sys/resource.h> -#include <stddef.h> - -#include "macro.h" - -typedef uint64_t usec_t; -typedef uint64_t nsec_t; - -typedef struct dual_timestamp { - usec_t realtime; - usec_t monotonic; -} dual_timestamp; - -union dirent_storage { - struct dirent de; - uint8_t storage[offsetof(struct dirent, d_name) + - ((NAME_MAX + 1 + sizeof(long)) & ~(sizeof(long) - 1))]; -}; - -#define MSEC_PER_SEC 1000ULL -#define USEC_PER_SEC 1000000ULL -#define USEC_PER_MSEC 1000ULL -#define NSEC_PER_SEC 1000000000ULL -#define NSEC_PER_MSEC 1000000ULL -#define NSEC_PER_USEC 1000ULL - -#define USEC_PER_MINUTE (60ULL*USEC_PER_SEC) -#define NSEC_PER_MINUTE (60ULL*NSEC_PER_SEC) -#define USEC_PER_HOUR (60ULL*USEC_PER_MINUTE) -#define NSEC_PER_HOUR (60ULL*NSEC_PER_MINUTE) -#define USEC_PER_DAY (24ULL*USEC_PER_HOUR) -#define NSEC_PER_DAY (24ULL*NSEC_PER_HOUR) -#define USEC_PER_WEEK (7ULL*USEC_PER_DAY) -#define NSEC_PER_WEEK (7ULL*NSEC_PER_DAY) -#define USEC_PER_MONTH (2629800ULL*USEC_PER_SEC) -#define NSEC_PER_MONTH (2629800ULL*NSEC_PER_SEC) -#define USEC_PER_YEAR (31557600ULL*USEC_PER_SEC) -#define NSEC_PER_YEAR (31557600ULL*NSEC_PER_SEC) - -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;\n" - -#define FORMAT_TIMESTAMP_MAX (5+11+9+4+1) -#define FORMAT_TIMESTAMP_PRETTY_MAX 256 -#define FORMAT_TIMESPAN_MAX 64 -#define FORMAT_BYTES_MAX 8 - -#define ANSI_HIGHLIGHT_ON "\x1B[1;39m" -#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m" -#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m" -#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m" -#define ANSI_HIGHLIGHT_OFF "\x1B[0m" - -bool is_efiboot(void); - -usec_t now(clockid_t clock); - -dual_timestamp* dual_timestamp_get(dual_timestamp *ts); -dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); - -#define dual_timestamp_is_set(ts) ((ts)->realtime > 0) - -usec_t timespec_load(const struct timespec *ts); -struct timespec *timespec_store(struct timespec *ts, usec_t u); - -usec_t timeval_load(const struct timeval *tv); -struct timeval *timeval_store(struct timeval *tv, usec_t u); - -size_t page_size(void); -#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) - -#define streq(a,b) (strcmp((a),(b)) == 0) -#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) - -bool streq_ptr(const char *a, const char *b); - -#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) - -#define new0(t, n) ((t*) calloc((n), sizeof(t))) - -#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) - -#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) - -#define malloc0(n) (calloc((n), 1)) - -static inline const char* yes_no(bool b) { - return b ? "yes" : "no"; -} - -static inline const char* strempty(const char *s) { - return s ? s : ""; -} - -static inline const char* strnull(const char *s) { - return s ? s : "(null)"; -} - -static inline const char *strna(const char *s) { - return s ? s : "n/a"; -} - -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - -char *endswith(const char *s, const char *postfix); -char *startswith(const char *s, const char *prefix); -char *startswith_no_case(const char *s, const char *prefix); - -bool first_word(const char *s, const char *word); - -int close_nointr(int fd); -void close_nointr_nofail(int fd); -void close_many(const int fds[], unsigned n_fd); - -int parse_boolean(const char *v); -int parse_usec(const char *t, usec_t *usec); -int parse_nsec(const char *t, nsec_t *nsec); -int parse_bytes(const char *t, off_t *bytes); -int parse_pid(const char *s, pid_t* ret_pid); -int parse_uid(const char *s, uid_t* ret_uid); -#define parse_gid(s, ret_uid) parse_uid(s, ret_uid) - -int safe_atou(const char *s, unsigned *ret_u); -int safe_atoi(const char *s, int *ret_i); - -int safe_atollu(const char *s, unsigned long long *ret_u); -int safe_atolli(const char *s, long long int *ret_i); - -#if __WORDSIZE == 32 -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(int)); - return safe_atoi(s, (int*) ret_u); -} -#else -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_u); -} -#endif - -static inline int safe_atou32(const char *s, uint32_t *ret_u) { - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} - -static inline int safe_atoi32(const char *s, int32_t *ret_i) { - assert_cc(sizeof(int32_t) == sizeof(int)); - return safe_atoi(s, (int*) ret_i); -} - -static inline int safe_atou64(const char *s, uint64_t *ret_u) { - assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} - -static inline int safe_atoi64(const char *s, int64_t *ret_i) { - assert_cc(sizeof(int64_t) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_i); -} - -char *split(const char *c, size_t *l, const char *separator, char **state); -char *split_quoted(const char *c, size_t *l, char **state); - -#define FOREACH_WORD(word, length, s, state) \ - for ((state) = NULL, (word) = split((s), &(length), WHITESPACE, &(state)); (word); (word) = split((s), &(length), WHITESPACE, &(state))) - -#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - for ((state) = NULL, (word) = split((s), &(length), (separator), &(state)); (word); (word) = split((s), &(length), (separator), &(state))) - -#define FOREACH_WORD_QUOTED(word, length, s, state) \ - for ((state) = NULL, (word) = split_quoted((s), &(length), &(state)); (word); (word) = split_quoted((s), &(length), &(state))) - -pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); -int get_starttime_of_pid(pid_t pid, unsigned long long *st); - -int write_one_line_file(const char *fn, const char *line); -int write_one_line_file_atomic(const char *fn, const char *line); -int read_one_line_file(const char *fn, char **line); -int read_full_file(const char *fn, char **contents, size_t *size); - -int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; -int load_env_file(const char *fname, char ***l); -int write_env_file(const char *fname, char **l); - -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 readlink_malloc(const char *p, char **r); -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); - -char *strstrip(char *s); -char *delete_chars(char *s, const char *bad); -char *truncate_nl(char *s); - -char *file_in_same_dir(const char *path, const char *filename); - -int rmdir_parents(const char *path, const char *stop); - -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); - -char hexchar(int x); -int unhexchar(char c); -char octchar(int x); -int unoctchar(char c); -char decchar(int x); -int undecchar(char c); - -char *cescape(const char *s); -char *cunescape(const char *s); -char *cunescape_length(const char *s, size_t length); -char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix); - -char *xescape(const char *s, const char *bad); - -char *bus_path_escape(const char *s); -char *bus_path_unescape(const char *s); - -char *ascii_strlower(char *path); - -bool dirent_is_file(const struct dirent *de); -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix); - -bool ignore_file(const char *filename); - -bool chars_intersect(const char *a, const char *b); - -char *format_timestamp(char *buf, size_t l, usec_t t); -char *format_timestamp_pretty(char *buf, size_t l, usec_t t); -char *format_timespan(char *buf, size_t l, usec_t t); - -int make_stdio(int fd); -int make_null_stdio(void); -int make_console_stdio(void); - -unsigned long long random_ull(void); - -/* For basic lookup tables with strictly enumerated entries */ -#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ - scope const char *name##_to_string(type i) { \ - if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ - return NULL; \ - return name##_table[i]; \ - } \ - scope type name##_from_string(const char *s) { \ - type i; \ - assert(s); \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ - return i; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static) - -/* For string conversions where numbers are also acceptable */ -#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ - int name##_to_string_alloc(type i, char **str) { \ - char *s; \ - int r; \ - if (i < 0 || i > max) \ - return -ERANGE; \ - if (i < (type) ELEMENTSOF(name##_table)) { \ - s = strdup(name##_table[i]); \ - if (!s) \ - return log_oom(); \ - } else { \ - r = asprintf(&s, "%u", i); \ - if (r < 0) \ - return log_oom(); \ - } \ - *str = s; \ - return 0; \ - } \ - type name##_from_string(const char *s) { \ - type i; \ - unsigned u = 0; \ - assert(s); \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ - return i; \ - if (safe_atou(s, &u) >= 0 && u <= max) \ - return (type) u; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -int fd_nonblock(int fd, bool nonblock); -int fd_cloexec(int fd, bool cloexec); - -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 *ret, const char *replies, const char *text, ...); - -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 close_pipe(int p[]); -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); -ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); - -bool is_device_path(const char *path); - -int dir_is_empty(const char *path); - -void rename_process(const char name[8]); - -void sigset_add_many(sigset_t *ss, ...); - -bool hostname_is_set(void); - -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); - -int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev); -int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev); -int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky); -int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky); - -int pipe_eof(int fd); - -cpu_set_t* cpu_set_malloc(unsigned *ncpus); - -int status_vprintf(const char *status, bool ellipse, const char *format, va_list ap); -int status_printf(const char *status, bool ellipse, const char *format, ...); -int status_welcome(void); - -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); - -int running_in_chroot(void); - -char *ellipsize(const char *s, size_t length, unsigned percent); -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent); - -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); - -_noreturn_ void freeze(void); - -bool null_or_empty(struct stat *st); -int null_or_empty_path(const char *fn); - -DIR *xopendirat(int dirfd, const char *name, int flags); - -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t); -void dual_timestamp_deserialize(const char *value, dual_timestamp *t); - -char *fstab_node_to_udev_node(const char *p); - -bool tty_is_vc(const char *tty); -bool tty_is_vc_resolve(const char *tty); -bool tty_is_console(const char *tty); -int vtnr_from_tty(const char *tty); -const char *default_term_for_tty(const char *tty); - -void execute_directory(const char *directory, DIR *_d, 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); -char* hostname_cleanup(char *s); - -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 copy_file(const char *from, const char *to); - -int symlink_atomic(const char *from, const char *to); - -int fchmod_umask(int fd, mode_t mode); - -bool display_is_local(const char *display); -int socket_from_display(const char *display, char **path); - -int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); -int get_group_creds(const char **groupname, gid_t *gid); - -int in_group(const char *name); - -int glob_exists(const char *path); - -int dirent_ensure_type(DIR *d, struct dirent *de); - -int in_search_path(const char *path, char **search); -int get_files_in_directory(const char *path, char ***list); - -char *strjoin(const char *x, ...) _sentinel_; - -bool is_main_thread(void); - -bool in_charset(const char *s, const char* charset); - -int block_get_whole_disk(dev_t d, dev_t *ret); - -int file_is_priv_sticky(const char *p); - -int strdup_or_null(const char *a, char **b); - -#define NULSTR_FOREACH(i, l) \ - for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) - -#define NULSTR_FOREACH_PAIR(i, j, l) \ - for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) - -int ioprio_class_to_string_alloc(int i, char **s); -int ioprio_class_from_string(const char *s); - -const char *sigchld_code_to_string(int i); -int sigchld_code_from_string(const char *s); - -int log_facility_unshifted_to_string_alloc(int i, char **s); -int log_facility_unshifted_from_string(const char *s); - -int log_level_to_string_alloc(int i, char **s); -int log_level_from_string(const char *s); - -int sched_policy_to_string_alloc(int i, char **s); -int sched_policy_from_string(const char *s); - -const char *rlimit_to_string(int i); -int rlimit_from_string(const char *s); - -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); -int signal_from_string(const char *s); - -int signal_from_string_try_harder(const char *s); - -extern int saved_argc; -extern char **saved_argv; - -bool kexec_loaded(void); - -int prot_from_flags(int flags); - -char *format_bytes(char *buf, size_t l, off_t t); - -int fd_wait_for_event(int fd, int event, usec_t timeout); - -void* memdup(const void *p, size_t l) _malloc_; - -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); - -int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); - -int setrlimit_closest(int resource, const struct rlimit *rlim); - -int getenv_for_pid(pid_t pid, const char *field, char **_value); - -int can_sleep(const char *type); -int can_sleep_disk(const char *type); - -bool is_valid_documentation_url(const char *url); - -bool in_initrd(void); - -void warn_melody(void); - -int get_shell(char **ret); -int get_home_dir(char **ret); - -void freep(void *p); -void fclosep(FILE **f); -void closep(int *fd); -void closedirp(DIR **d); -void umaskp(mode_t *u); - -_malloc_ static inline void *malloc_multiply(size_t a, size_t b) { - if (_unlikely_(b == 0 || a > ((size_t) -1) / b)) - return NULL; - - return malloc(a * b); -} - -_malloc_ static inline void *memdup_multiply(const void *p, size_t a, size_t b) { - if (_unlikely_(b == 0 || a > ((size_t) -1) / b)) - return NULL; - - return memdup(p, a * b); -} - -bool filename_is_safe(const char *p); -bool string_is_safe(const char *p); - -int parse_timestamp(const char *t, usec_t *usec); - -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar) (const void *, const void *, void *), - void *arg); - -bool is_locale_utf8(void); - -typedef enum DrawSpecialChar { - DRAW_TREE_VERT, - DRAW_TREE_BRANCH, - DRAW_TREE_RIGHT, - DRAW_TRIANGULAR_BULLET, - _DRAW_SPECIAL_CHAR_MAX -} DrawSpecialChar; -const char *draw_special_char(DrawSpecialChar ch); - -char *strreplace(const char *text, const char *old_string, const char *new_string); diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c deleted file mode 100644 index 046fb584fb..0000000000 --- a/src/shared/utmp-wtmp.c +++ /dev/null @@ -1,431 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - 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 <utmpx.h> -#include <errno.h> -#include <assert.h> -#include <string.h> -#include <sys/utsname.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/poll.h> - -#include "macro.h" -#include "path-util.h" -#include "utmp-wtmp.h" - -int utmp_get_runlevel(int *runlevel, int *previous) { - struct utmpx lookup, *found; - int r; - const char *e; - - assert(runlevel); - - /* If these values are set in the environment this takes - * precedence. Presumably, sysvinit does this to work around a - * race condition that would otherwise exist where we'd always - * go to disk and hence might read runlevel data that might be - * very new and does not apply to the current script being - * executed. */ - - if ((e = getenv("RUNLEVEL")) && e[0] > 0) { - *runlevel = e[0]; - - if (previous) { - /* $PREVLEVEL seems to be an Upstart thing */ - - if ((e = getenv("PREVLEVEL")) && e[0] > 0) - *previous = e[0]; - else - *previous = 0; - } - - return 0; - } - - if (utmpxname(_PATH_UTMPX) < 0) - return -errno; - - setutxent(); - - zero(lookup); - lookup.ut_type = RUN_LVL; - - if (!(found = getutxid(&lookup))) - r = -errno; - else { - int a, b; - - a = found->ut_pid & 0xFF; - b = (found->ut_pid >> 8) & 0xFF; - - if (a < 0 || b < 0) - r = -EIO; - else { - *runlevel = a; - - if (previous) - *previous = b; - r = 0; - } - } - - endutxent(); - - return r; -} - -static void init_timestamp(struct utmpx *store, usec_t t) { - assert(store); - - zero(*store); - - if (t <= 0) - t = now(CLOCK_REALTIME); - - store->ut_tv.tv_sec = t / USEC_PER_SEC; - store->ut_tv.tv_usec = t % USEC_PER_SEC; -} - -static void init_entry(struct utmpx *store, usec_t t) { - struct utsname uts; - - assert(store); - - init_timestamp(store, t); - - zero(uts); - - if (uname(&uts) >= 0) - strncpy(store->ut_host, uts.release, sizeof(store->ut_host)); - - strncpy(store->ut_line, "~", sizeof(store->ut_line)); /* or ~~ ? */ - strncpy(store->ut_id, "~~", sizeof(store->ut_id)); -} - -static int write_entry_utmp(const struct utmpx *store) { - int r; - - assert(store); - - /* utmp is similar to wtmp, but there is only one entry for - * each entry type resp. user; i.e. basically a key/value - * table. */ - - if (utmpxname(_PATH_UTMPX) < 0) - return -errno; - - setutxent(); - - if (!pututxline(store)) - r = -errno; - else - r = 0; - - endutxent(); - - return r; -} - -static int write_entry_wtmp(const struct utmpx *store) { - assert(store); - - /* wtmp is a simple append-only file where each entry is - simply appended to * the end; i.e. basically a log. */ - - errno = 0; - updwtmpx(_PATH_WTMPX, store); - return -errno; -} - -static int write_utmp_wtmp(const struct utmpx *store_utmp, const struct utmpx *store_wtmp) { - int r, s; - - r = write_entry_utmp(store_utmp); - s = write_entry_wtmp(store_wtmp); - - if (r >= 0) - r = s; - - /* If utmp/wtmp have been disabled, that's a good thing, hence - * ignore the errors */ - if (r == -ENOENT) - r = 0; - - return r; -} - -static int write_entry_both(const struct utmpx *store) { - return write_utmp_wtmp(store, store); -} - -int utmp_put_shutdown(void) { - struct utmpx store; - - init_entry(&store, 0); - - store.ut_type = RUN_LVL; - strncpy(store.ut_user, "shutdown", sizeof(store.ut_user)); - - return write_entry_both(&store); -} - -int utmp_put_reboot(usec_t t) { - struct utmpx store; - - init_entry(&store, t); - - store.ut_type = BOOT_TIME; - strncpy(store.ut_user, "reboot", sizeof(store.ut_user)); - - return write_entry_both(&store); -} - -static const char *sanitize_id(const char *id) { - size_t l; - - assert(id); - l = strlen(id); - - if (l <= sizeof(((struct utmpx*) NULL)->ut_id)) - return id; - - return id + l - sizeof(((struct utmpx*) NULL)->ut_id); -} - -int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line) { - struct utmpx store; - - assert(id); - - init_timestamp(&store, 0); - - store.ut_type = INIT_PROCESS; - store.ut_pid = pid; - store.ut_session = sid; - - strncpy(store.ut_id, sanitize_id(id), sizeof(store.ut_id)); - - if (line) - strncpy(store.ut_line, path_get_file_name(line), sizeof(store.ut_line)); - - return write_entry_both(&store); -} - -int utmp_put_dead_process(const char *id, pid_t pid, int code, int status) { - struct utmpx lookup, store, store_wtmp, *found; - - assert(id); - - setutxent(); - - zero(lookup); - lookup.ut_type = INIT_PROCESS; /* looks for DEAD_PROCESS, LOGIN_PROCESS, USER_PROCESS, too */ - strncpy(lookup.ut_id, sanitize_id(id), sizeof(lookup.ut_id)); - - if (!(found = getutxid(&lookup))) - return 0; - - if (found->ut_pid != pid) - return 0; - - memcpy(&store, found, sizeof(store)); - store.ut_type = DEAD_PROCESS; - store.ut_exit.e_termination = code; - store.ut_exit.e_exit = status; - - zero(store.ut_user); - zero(store.ut_host); - zero(store.ut_tv); - - memcpy(&store_wtmp, &store, sizeof(store_wtmp)); - /* wtmp wants the current time */ - init_timestamp(&store_wtmp, 0); - - return write_utmp_wtmp(&store, &store_wtmp); -} - - -int utmp_put_runlevel(int runlevel, int previous) { - struct utmpx store; - int r; - - assert(runlevel > 0); - - if (previous <= 0) { - /* Find the old runlevel automatically */ - - if ((r = utmp_get_runlevel(&previous, NULL)) < 0) { - if (r != -ESRCH) - return r; - - previous = 0; - } - } - - if (previous == runlevel) - return 0; - - init_entry(&store, 0); - - store.ut_type = RUN_LVL; - store.ut_pid = (runlevel & 0xFF) | ((previous & 0xFF) << 8); - strncpy(store.ut_user, "runlevel", sizeof(store.ut_user)); - - return write_entry_both(&store); -} - -#define TIMEOUT_MSEC 50 - -static int write_to_terminal(const char *tty, const char *message) { - int fd, r; - const char *p; - size_t left; - usec_t end; - - assert(tty); - assert(message); - - if ((fd = open(tty, O_WRONLY|O_NDELAY|O_NOCTTY|O_CLOEXEC)) < 0) - return -errno; - - if (!isatty(fd)) { - r = -errno; - goto finish; - } - - p = message; - left = strlen(message); - - end = now(CLOCK_MONOTONIC) + TIMEOUT_MSEC*USEC_PER_MSEC; - - while (left > 0) { - ssize_t n; - struct pollfd pollfd; - usec_t t; - int k; - - t = now(CLOCK_MONOTONIC); - - if (t >= end) { - r = -ETIME; - goto finish; - } - - zero(pollfd); - pollfd.fd = fd; - pollfd.events = POLLOUT; - - if ((k = poll(&pollfd, 1, (end - t) / USEC_PER_MSEC)) < 0) - return -errno; - - if (k <= 0) { - r = -ETIME; - goto finish; - } - - if ((n = write(fd, p, left)) < 0) { - - if (errno == EAGAIN) - continue; - - r = -errno; - goto finish; - } - - assert((size_t) n <= left); - - p += n; - left -= n; - } - - r = 0; - -finish: - close_nointr_nofail(fd); - - return r; -} - -int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) { - struct utmpx *u; - char date[FORMAT_TIMESTAMP_MAX]; - char *text = NULL, *hn = NULL, *un = NULL, *tty = NULL; - int r; - - if (!(hn = gethostname_malloc()) || - !(un = getlogname_malloc())) { - r = -ENOMEM; - goto finish; - } - - getttyname_harder(STDIN_FILENO, &tty); - - if (asprintf(&text, - "\a\r\n" - "Broadcast message from %s@%s%s%s (%s):\r\n\r\n" - "%s\r\n\r\n", - un, hn, - tty ? " on " : "", strempty(tty), - format_timestamp(date, sizeof(date), now(CLOCK_REALTIME)), - message) < 0) { - r = -ENOMEM; - goto finish; - } - - setutxent(); - - r = 0; - - while ((u = getutxent())) { - int q; - const char *path; - char *buf = NULL; - - if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0) - continue; - - if (path_startswith(u->ut_line, "/dev/")) - path = u->ut_line; - else { - if (asprintf(&buf, "/dev/%s", u->ut_line) < 0) { - r = -ENOMEM; - goto finish; - } - - path = buf; - } - - if (!match_tty || match_tty(path)) - if ((q = write_to_terminal(path, text)) < 0) - r = q; - - free(buf); - } - -finish: - free(hn); - free(un); - free(tty); - free(text); - - return r; -} diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h deleted file mode 100644 index 5924023203..0000000000 --- a/src/shared/utmp-wtmp.h +++ /dev/null @@ -1,35 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#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 "util.h" - -int utmp_get_runlevel(int *runlevel, int *previous); - -int utmp_put_shutdown(void); -int utmp_put_reboot(usec_t timestamp); -int utmp_put_runlevel(int runlevel, int previous); - -int utmp_put_dead_process(const char *id, pid_t pid, int code, int status); -int utmp_put_init_process(const char *id, pid_t pid, pid_t sid, const char *line); - -int utmp_wall(const char *message, bool (*match_tty)(const char *tty)); diff --git a/src/shared/virt.c b/src/shared/virt.c deleted file mode 100644 index fc62c72328..0000000000 --- a/src/shared/virt.c +++ /dev/null @@ -1,259 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2011 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 <string.h> -#include <errno.h> -#include <unistd.h> - -#include "util.h" -#include "virt.h" - -/* Returns a short identifier for the various VM implementations */ -int detect_vm(const char **id) { - -#if defined(__i386__) || defined(__x86_64__) - - /* Both CPUID and DMI are x86 specific interfaces... */ - - static const char *const dmi_vendors[] = { - "/sys/class/dmi/id/sys_vendor", - "/sys/class/dmi/id/board_vendor", - "/sys/class/dmi/id/bios_vendor" - }; - - static const char dmi_vendor_table[] = - "QEMU\0" "qemu\0" - /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMware\0" "vmware\0" - "VMW\0" "vmware\0" - "Microsoft Corporation\0" "microsoft\0" - "innotek GmbH\0" "oracle\0" - "Xen\0" "xen\0" - "Bochs\0" "bochs\0"; - - static const char cpuid_vendor_table[] = - "XenVMMXenVMM\0" "xen\0" - "KVMKVMKVM\0" "kvm\0" - /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMwareVMware\0" "vmware\0" - /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ - "Microsoft Hv\0" "microsoft\0"; - - uint32_t eax, ecx; - union { - uint32_t sig32[3]; - char text[13]; - } sig; - unsigned i; - const char *j, *k; - bool hypervisor; - - /* http://lwn.net/Articles/301888/ */ - zero(sig); - -#if defined (__i386__) -#define REG_a "eax" -#define REG_b "ebx" -#elif defined (__amd64__) -#define REG_a "rax" -#define REG_b "rbx" -#endif - - /* First detect whether there is a hypervisor */ - eax = 1; - __asm__ __volatile__ ( - /* ebx/rbx is being used for PIC! */ - " push %%"REG_b" \n\t" - " cpuid \n\t" - " pop %%"REG_b" \n\t" - - : "=a" (eax), "=c" (ecx) - : "0" (eax) - ); - - hypervisor = !!(ecx & 0x80000000U); - - if (hypervisor) { - - /* There is a hypervisor, see what it is */ - eax = 0x40000000U; - __asm__ __volatile__ ( - /* ebx/rbx is being used for PIC! */ - " push %%"REG_b" \n\t" - " cpuid \n\t" - " mov %%ebx, %1 \n\t" - " pop %%"REG_b" \n\t" - - : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2]) - : "0" (eax) - ); - - NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) - if (streq(sig.text, j)) { - - if (id) - *id = k; - - return 1; - } - } - - for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { - char *s; - int r; - const char *found = NULL; - - if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) { - if (r != -ENOENT) - return r; - - continue; - } - - NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) - if (startswith(s, j)) - found = k; - free(s); - - if (found) { - if (id) - *id = found; - - return 1; - } - } - - if (hypervisor) { - if (id) - *id = "other"; - - return 1; - } - -#endif - return 0; -} - -int detect_container(const char **id) { - char *e = NULL; - int r; - - /* Unfortunately many of these operations require root access - * in one way or another */ - - r = running_in_chroot(); - if (r < 0) - return r; - if (r > 0) { - - if (id) - *id = "chroot"; - - return 1; - } - - /* /proc/vz exists in container and outside of the container, - * /proc/bc only outside of the container. */ - if (access("/proc/vz", F_OK) >= 0 && - access("/proc/bc", F_OK) < 0) { - - if (id) - *id = "openvz"; - - return 1; - } - - r = getenv_for_pid(1, "container", &e); - if (r <= 0) - return r; - - /* We only recognize a selected few here, since we want to - * enforce a redacted namespace */ - if (streq(e, "lxc")) { - if (id) - *id = "lxc"; - } else if (streq(e, "lxc-libvirt")) { - if (id) - *id = "lxc-libvirt"; - } else if (streq(e, "systemd-nspawn")) { - if (id) - *id = "systemd-nspawn"; - } else { - if (id) - *id = "other"; - } - - free(e); - - return r; -} - -/* Returns a short identifier for the various VM/container implementations */ -Virtualization detect_virtualization(const char **id) { - - static __thread Virtualization cached_virt = _VIRTUALIZATION_INVALID; - static __thread const char *cached_id = NULL; - - const char *_id; - int r; - Virtualization v; - - if (_likely_(cached_virt >= 0)) { - - if (id && cached_virt > 0) - *id = cached_id; - - return cached_virt; - } - - r = detect_container(&_id); - if (r < 0) { - v = r; - goto finish; - } else if (r > 0) { - v = VIRTUALIZATION_CONTAINER; - goto finish; - } - - r = detect_vm(&_id); - if (r < 0) { - v = r; - goto finish; - } else if (r > 0) { - v = VIRTUALIZATION_VM; - goto finish; - } - - v = VIRTUALIZATION_NONE; - -finish: - if (v > 0) { - cached_id = _id; - - if (id) - *id = _id; - } - - if (v >= 0) - cached_virt = v; - - return v; -} diff --git a/src/shared/virt.h b/src/shared/virt.h deleted file mode 100644 index aa6ad35ba9..0000000000 --- a/src/shared/virt.h +++ /dev/null @@ -1,35 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2011 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/>. -***/ - -int detect_vm(const char **id); -int detect_container(const char **id); - -typedef enum Virtualization { - VIRTUALIZATION_NONE = 0, - VIRTUALIZATION_VM, - VIRTUALIZATION_CONTAINER, - _VIRTUALIZATION_MAX, - _VIRTUALIZATION_INVALID = -1 -} Virtualization; - -Virtualization detect_virtualization(const char **id); diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c deleted file mode 100644 index 13265e7692..0000000000 --- a/src/shared/watchdog.c +++ /dev/null @@ -1,169 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <sys/ioctl.h> -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <linux/watchdog.h> - -#include "watchdog.h" -#include "log.h" - -static int watchdog_fd = -1; -static usec_t watchdog_timeout = (usec_t) -1; - -static int update_timeout(void) { - int r; - - if (watchdog_fd < 0) - return 0; - - if (watchdog_timeout == (usec_t) -1) - return 0; - else if (watchdog_timeout == 0) { - int flags; - - flags = WDIOS_DISABLECARD; - r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags); - if (r < 0) { - log_warning("Failed to disable hardware watchdog: %m"); - return -errno; - } - } else { - int sec, flags; - char buf[FORMAT_TIMESPAN_MAX]; - - sec = (int) ((watchdog_timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); - r = ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec); - if (r < 0) { - log_warning("Failed to set timeout to %is: %m", sec); - return -errno; - } - - watchdog_timeout = (usec_t) sec * USEC_PER_SEC; - log_info("Set hardware watchdog to %s.", format_timespan(buf, sizeof(buf), watchdog_timeout)); - - flags = WDIOS_ENABLECARD; - r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags); - if (r < 0) { - log_warning("Failed to enable hardware watchdog: %m"); - return -errno; - } - - r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0); - if (r < 0) { - log_warning("Failed to ping hardware watchdog: %m"); - return -errno; - } - } - - return 0; -} - -static int open_watchdog(void) { - struct watchdog_info ident; - - if (watchdog_fd >= 0) - return 0; - - watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC); - if (watchdog_fd < 0) - return -errno; - - if (ioctl(watchdog_fd, WDIOC_GETSUPPORT, &ident) >= 0) - log_info("Hardware watchdog '%s', version %x", - ident.identity, - ident.firmware_version); - - return update_timeout(); -} - -int watchdog_set_timeout(usec_t *usec) { - int r; - - watchdog_timeout = *usec; - - /* If we didn't open the watchdog yet and didn't get any - * explicit timeout value set, don't do anything */ - if (watchdog_fd < 0 && watchdog_timeout == (usec_t) -1) - return 0; - - if (watchdog_fd < 0) - r = open_watchdog(); - else - r = update_timeout(); - - *usec = watchdog_timeout; - - return r; -} - -int watchdog_ping(void) { - int r; - - if (watchdog_fd < 0) { - r = open_watchdog(); - if (r < 0) - return r; - } - - r = ioctl(watchdog_fd, WDIOC_KEEPALIVE, 0); - if (r < 0) { - log_warning("Failed to ping hardware watchdog: %m"); - return -errno; - } - - return 0; -} - -void watchdog_close(bool disarm) { - int r; - - if (watchdog_fd < 0) - return; - - if (disarm) { - int flags; - - /* Explicitly disarm it */ - flags = WDIOS_DISABLECARD; - r = ioctl(watchdog_fd, WDIOC_SETOPTIONS, &flags); - if (r < 0) - log_warning("Failed to disable hardware watchdog: %m"); - - /* To be sure, use magic close logic, too */ - for (;;) { - static const char v = 'V'; - - if (write(watchdog_fd, &v, 1) > 0) - break; - - if (errno != EINTR) { - log_error("Failed to disarm watchdog timer: %m"); - break; - } - } - } - - close_nointr_nofail(watchdog_fd); - watchdog_fd = -1; -} diff --git a/src/shared/watchdog.h b/src/shared/watchdog.h deleted file mode 100644 index b748b15857..0000000000 --- a/src/shared/watchdog.h +++ /dev/null @@ -1,28 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 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 "util.h" - -int watchdog_set_timeout(usec_t *usec); -int watchdog_ping(void); -void watchdog_close(bool disarm); |