diff options
Diffstat (limited to 'src')
142 files changed, 1810 insertions, 4532 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 9583458f72..c0863e4167 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -1331,7 +1331,7 @@ int main(int argc, char *argv[]) { arg_user ? MANAGER_USER : MANAGER_SYSTEM, arg_man); else { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus); if (r < 0) { diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index c79ad6520c..c8961de946 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -415,7 +415,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - r = write_string_file(saved, value); + r = write_string_file(saved, value, WRITE_STRING_FILE_CREATE); if (r < 0) { log_error_errno(r, "Failed to write %s: %m", saved); return EXIT_FAILURE; diff --git a/src/basic/capability.c b/src/basic/capability.c index 58f00e6dae..8dbe4da5bb 100644 --- a/src/basic/capability.c +++ b/src/basic/capability.c @@ -204,7 +204,7 @@ static int drop_from_file(const char *fn, uint64_t drop) { if (asprintf(&p, "%u %u", lo, hi) < 0) return -ENOMEM; - r = write_string_file(fn, p); + r = write_string_file(fn, p, WRITE_STRING_FILE_CREATE); free(p); return r; diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 439c5516dc..34a3060509 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -646,7 +646,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid) { snprintf(c, sizeof(c), PID_FMT"\n", pid); - return write_string_file_no_create(fs, c); + return write_string_file(fs, c, 0); } int cg_attach_fallback(const char *controller, const char *path, pid_t pid) { @@ -820,7 +820,7 @@ int cg_install_release_agent(const char *controller, const char *agent) { sc = strstrip(contents); if (sc[0] == 0) { - r = write_string_file_no_create(fs, agent); + r = write_string_file(fs, agent, 0); if (r < 0) return r; } else if (!streq(sc, agent)) @@ -840,7 +840,7 @@ int cg_install_release_agent(const char *controller, const char *agent) { sc = strstrip(contents); if (streq(sc, "0")) { - r = write_string_file_no_create(fs, "1"); + r = write_string_file(fs, "1", 0); if (r < 0) return r; @@ -861,7 +861,7 @@ int cg_uninstall_release_agent(const char *controller) { if (r < 0) return r; - r = write_string_file_no_create(fs, "0"); + r = write_string_file(fs, "0", 0); if (r < 0) return r; @@ -872,7 +872,7 @@ int cg_uninstall_release_agent(const char *controller) { if (r < 0) return r; - r = write_string_file_no_create(fs, ""); + r = write_string_file(fs, "", 0); if (r < 0) return r; @@ -1708,7 +1708,7 @@ int cg_set_attribute(const char *controller, const char *path, const char *attri if (r < 0) return r; - return write_string_file_no_create(p, value); + return write_string_file(p, value, 0); } int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret) { diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c index bec988ca78..f596f1d11f 100644 --- a/src/basic/fileio-label.c +++ b/src/basic/fileio-label.c @@ -31,7 +31,7 @@ int write_string_file_atomic_label(const char *fn, const char *line) { if (r < 0) return r; - r = write_string_file_atomic(fn, line); + r = write_string_file(fn, line, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); mac_selinux_create_file_clear(); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index ff6b1a7ed7..d592bf5ac9 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -27,14 +27,14 @@ #include "ctype.h" #include "fileio.h" -int write_string_stream(FILE *f, const char *line) { +int write_string_stream(FILE *f, const char *line, bool enforce_newline) { assert(f); assert(line); errno = 0; fputs(line, f); - if (!endswith(line, "\n")) + if (enforce_newline && !endswith(line, "\n")) fputc('\n', f); fflush(f); @@ -45,42 +45,7 @@ int write_string_stream(FILE *f, const char *line) { return 0; } -int write_string_file(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - - assert(fn); - assert(line); - - f = fopen(fn, "we"); - if (!f) - return -errno; - - return write_string_stream(f, line); -} - -int write_string_file_no_create(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - int fd; - - assert(fn); - assert(line); - - /* We manually build our own version of fopen(..., "we") that - * works without O_CREAT */ - fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - f = fdopen(fd, "we"); - if (!f) { - safe_close(fd); - return -errno; - } - - return write_string_stream(f, line); -} - -int write_string_file_atomic(const char *fn, const char *line) { +static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; int r; @@ -94,7 +59,7 @@ int write_string_file_atomic(const char *fn, const char *line) { fchmod_umask(fileno(f), 0644); - r = write_string_stream(f, line); + r = write_string_stream(f, line, enforce_newline); if (r >= 0) { if (rename(p, fn) < 0) r = -errno; @@ -106,6 +71,41 @@ int write_string_file_atomic(const char *fn, const char *line) { return r; } +int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { + _cleanup_fclose_ FILE *f = NULL; + + assert(fn); + assert(line); + + if (flags & WRITE_STRING_FILE_ATOMIC) { + assert(flags & WRITE_STRING_FILE_CREATE); + + return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + } + + if (flags & WRITE_STRING_FILE_CREATE) { + f = fopen(fn, "we"); + if (!f) + return -errno; + } else { + int fd; + + /* We manually build our own version of fopen(..., "we") that + * works without O_CREAT */ + fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + f = fdopen(fd, "we"); + if (!f) { + safe_close(fd); + return -errno; + } + } + + return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); +} + int read_one_line_file(const char *fn, char **line) { _cleanup_fclose_ FILE *f = NULL; char t[LINE_MAX], *c; @@ -134,6 +134,17 @@ int read_one_line_file(const char *fn, char **line) { return 0; } +int verify_one_line_file(const char *fn, const char *line) { + _cleanup_free_ char *value = NULL; + int r; + + r = read_one_line_file(fn, &value); + if (r < 0) + return r; + + return streq(value, line); +} + int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; _cleanup_free_ char *buf = NULL; diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 5ae51c1e28..2e8148ff24 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -25,15 +25,21 @@ #include "macro.h" -int write_string_stream(FILE *f, const char *line); -int write_string_file(const char *fn, const char *line); -int write_string_file_no_create(const char *fn, const char *line); -int write_string_file_atomic(const char *fn, const char *line); +typedef enum { + WRITE_STRING_FILE_CREATE = 1, + WRITE_STRING_FILE_ATOMIC = 2, + WRITE_STRING_FILE_AVOID_NEWLINE = 4, +} WriteStringFileFlags; + +int write_string_stream(FILE *f, const char *line, bool enforce_newline); +int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags); int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size); +int verify_one_line_file(const char *fn, const char *line); + int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 537705446a..5cbfc145a4 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -528,7 +528,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { * * If that didn't work we will try to read the mount id from * /proc/self/fdinfo/<fd>. This is almost as good as - * name_to_handle_at(), however, does not return the the + * name_to_handle_at(), however, does not return the * opaque file handle. The opaque file handle is pretty useful * to detect the root directory, which we should always * consider a mount point. Hence we use this only as @@ -656,9 +656,11 @@ int path_is_mount_point(const char *t, int flags) { canonical = canonicalize_file_name(t); if (!canonical) return -errno; + + t = canonical; } - r = path_get_parent(canonical ?: t, &parent); + r = path_get_parent(t, &parent); if (r < 0) return r; @@ -666,7 +668,7 @@ int path_is_mount_point(const char *t, int flags) { if (fd < 0) return -errno; - return fd_is_mount_point(fd, basename(canonical ?: t), flags); + return fd_is_mount_point(fd, basename(t), flags); } int path_is_read_only_fs(const char *path) { diff --git a/src/basic/process-util.c b/src/basic/process-util.c index cfc876567d..2c05f2fee4 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -329,6 +329,9 @@ int get_process_environ(pid_t pid, char **env) { sz += cescape_char(c, outcome + sz); } + if (sz == 0) + return -ENOENT; + outcome[sz] = '\0'; *env = outcome; outcome = NULL; diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index 2e24b1ea99..047aa294f4 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -139,7 +139,7 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return 0; p = procfs_file_alloca(pid, "attr/current"); - r = write_string_file(p, label); + r = write_string_file(p, label, 0); if (r < 0) return r; #endif diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index cbe3ff216e..144e6fd86e 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -38,6 +38,7 @@ int socket_address_listen( int backlog, SocketAddressBindIPv6Only only, const char *bind_to_device, + bool reuse_port, bool free_bind, bool transparent, mode_t directory_mode, @@ -83,6 +84,12 @@ int socket_address_listen( if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0) return -errno; + if (reuse_port) { + one = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0) + log_warning_errno(errno, "SO_REUSEPORT failed: %m"); + } + if (free_bind) { one = 1; if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0) @@ -146,7 +153,7 @@ int make_socket_fd(int log_level, const char* address, int flags) { } fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, - NULL, false, false, 0755, 0644, NULL); + NULL, false, false, false, 0755, 0644, NULL); if (fd < 0 || log_get_max_level() >= log_level) { _cleanup_free_ char *p = NULL; diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 538cf59174..6b0ce7836f 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -80,6 +80,7 @@ int socket_address_listen( int backlog, SocketAddressBindIPv6Only only, const char *bind_to_device, + bool reuse_port, bool free_bind, bool transparent, mode_t directory_mode, diff --git a/src/basic/util.c b/src/basic/util.c index 906e4abad6..bc917ae574 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -916,32 +916,218 @@ char *hexmem(const void *p, size_t l) { return r; } -void *unhexmem(const char *p, size_t l) { - uint8_t *r, *z; +int unhexmem(const char *p, size_t l, void **mem, size_t *len) { + _cleanup_free_ uint8_t *r = NULL; + uint8_t *z; const char *x; + assert(mem); + assert(len); assert(p); z = r = malloc((l + 1) / 2 + 1); if (!r) - return NULL; + return -ENOMEM; for (x = p; x < p + l; x += 2) { int a, b; a = unhexchar(x[0]); - if (x+1 < p + l) + if (a < 0) + return a; + else if (x+1 < p + l) { b = unhexchar(x[1]); - else + if (b < 0) + return b; + } else b = 0; *(z++) = (uint8_t) a << 4 | (uint8_t) b; } *z = 0; + + *mem = r; + r = NULL; + *len = (l + 1) / 2; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-4 */ +char base64char(int x) { + static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + return table[x & 63]; +} + +int unbase64char(char c) { + unsigned offset; + + if (c >= 'A' && c <= 'Z') + return c - 'A'; + + offset = 'Z' - 'A' + 1; + + if (c >= 'a' && c <= 'z') + return c - 'a' + offset; + + offset += 'z' - 'a' + 1; + + if (c >= '0' && c <= '9') + return c - '0' + offset; + + offset += '9' - '0' + 1; + + if (c == '+') + return offset; + + offset ++; + + if (c == '/') + return offset; + + return -EINVAL; +} + +char *base64mem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + /* three input bytes makes four output bytes, padding is added so we must round up */ + z = r = malloc(4 * (l + 2) / 3 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ + *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ + } + + switch (l % 3) { + case 2: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ + *(z++) = '='; + + break; + case 1: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ + *(z++) = '='; + *(z++) = '='; + + break; + } + + *z = 0; return r; } +int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *t = NULL; + int a, b, c, d; + uint8_t *r, *z; + const char *x; + size_t len; + + assert(p); + + /* padding ensures any base63 input has input divisible by 4 */ + if (l % 4 != 0) + return -EINVAL; + + /* strip the padding */ + if (l > 0 && p[l - 1] == '=') + l --; + if (l > 0 && p[l - 1] == '=') + l --; + + /* a group of four input bytes needs three output bytes, in case of + padding we need to add two or three extra bytes */ + len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 4) * 4; x += 4) { + /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase64char(x[3]); + if (d < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + } + + switch (l % 4) { + case 3: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + /* c == 00ZZZZ00 */ + if (c & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + + break; + case 2: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 00YY0000 */ + if (b & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + + break; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + char octchar(int x) { return '0' + (x & 7); } @@ -2533,8 +2719,9 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { f = fdopen(fd, "we"); if (!f) { - unlink(t); + unlink_noerrno(t); free(t); + safe_close(fd); return -errno; } @@ -4716,7 +4903,7 @@ int update_reboot_param_file(const char *param) { if (param) { - r = write_string_file(REBOOT_PARAM_FILE, param); + r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); if (r < 0) log_error("Failed to write reboot param to " REBOOT_PARAM_FILE": %s", strerror(-r)); @@ -5925,10 +6112,9 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char if (ret >= 0) return 0; - /* Even though renameat2() exists since Linux 3.15, btrfs added - * support for it later. If it is not implemented, fallback to another - * method. */ - if (errno != EINVAL) + /* renameat2() exists since Linux 3.15, btrfs added support for it later. + * If it is not implemented, fallback to another method. */ + if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; /* The link()/unlink() fallback does not work on directories. But diff --git a/src/basic/util.h b/src/basic/util.h index a1d1dd15c3..dae43006e4 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -240,6 +240,8 @@ char octchar(int x) _const_; int unoctchar(char c) _const_; char decchar(int x) _const_; int undecchar(char c) _const_; +char base64char(int x) _const_; +int unbase64char(char c) _const_; char *cescape(const char *s); size_t cescape_char(char c, char *buf); @@ -614,7 +616,10 @@ static inline void *mempset(void *s, int c, size_t n) { } char *hexmem(const void *p, size_t l); -void *unhexmem(const char *p, size_t l); +int unhexmem(const char *p, size_t l, void **mem, size_t *len); + +char *base64mem(const void *p, size_t l); +int unbase64mem(const char *p, size_t l, void **mem, size_t *len); char *strextend(char **x, ...) _sentinel_; char *strrep(const char *s, unsigned n); diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index 6028ed68c0..1e216f52bd 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -53,7 +53,7 @@ static int delete_rule(const char *rule) { if (!fn) return log_oom(); - return write_string_file(fn, "-1"); + return write_string_file(fn, "-1", 0); } static int apply_rule(const char *rule) { @@ -61,7 +61,7 @@ static int apply_rule(const char *rule) { delete_rule(rule); - r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule); + r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, 0); if (r < 0) return log_error_errno(r, "Failed to add binary format: %m"); @@ -191,7 +191,7 @@ int main(int argc, char *argv[]) { } /* Flush out all rules */ - write_string_file("/proc/sys/fs/binfmt_misc/status", "-1"); + write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", 0); STRV_FOREACH(f, files) { k = apply_file(*f, true); diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 1e65597acf..ed69fb0cec 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -918,7 +918,7 @@ static int install_loader_config(const char *esp_path) { static int help(void) { printf("%s [COMMAND] [OPTIONS...]\n" "\n" - "Install, update or remove the sdboot EFI boot manager.\n\n" + "Install, update or remove the systemd-boot EFI boot manager.\n\n" " -h --help Show this help\n" " --version Print version\n" " --path=PATH Path to the EFI System Partition (ESP)\n" diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index eb1a4e3b66..827c11844c 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1517,6 +1517,7 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima CHAR16 *os_name = NULL; CHAR16 *os_id = NULL; CHAR16 *os_version = NULL; + CHAR16 *os_build = NULL; bufsize = sizeof(buf); err = uefi_call_wrapper(linux_dir->Read, 3, linux_dir, &bufsize, buf); @@ -1547,35 +1548,45 @@ static VOID config_entry_add_linux( Config *config, EFI_LOADED_IMAGE *loaded_ima line = content; while ((line = line_get_key_value(content, (CHAR8 *)"=", &pos, &key, &value))) { if (strcmpa((CHAR8 *)"PRETTY_NAME", key) == 0) { + FreePool(os_name); os_name = stra_to_str(value); continue; } if (strcmpa((CHAR8 *)"ID", key) == 0) { + FreePool(os_id); os_id = stra_to_str(value); continue; } if (strcmpa((CHAR8 *)"VERSION_ID", key) == 0) { + FreePool(os_version); os_version = stra_to_str(value); continue; } + + if (strcmpa((CHAR8 *)"BUILD_ID", key) == 0) { + FreePool(os_build); + os_build = stra_to_str(value); + continue; + } } - if (os_name && os_id && os_version) { + if (os_name && os_id && (os_version || os_build)) { CHAR16 *conf; CHAR16 *path; - conf = PoolPrint(L"%s-%s", os_id, os_version); + conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build); path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName); config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path); FreePool(conf); FreePool(path); - FreePool(os_name); - FreePool(os_id); - FreePool(os_version); } + FreePool(os_name); + FreePool(os_id); + FreePool(os_version); + FreePool(os_build); FreePool(content); } uefi_call_wrapper(linux_dir->Close, 1, linux_dir); diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c index 0ac1f55a91..a7ef653d5d 100644 --- a/src/bootchart/svg.c +++ b/src/bootchart/svg.c @@ -172,7 +172,7 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start, r = read_one_line_file(filename, &model); if (r < 0) - log_warning("Error reading disk model for %s: %m\n", rootbdev); + log_info("Error reading disk model for %s: %m\n", rootbdev); } /* various utsname parameters */ @@ -208,7 +208,8 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start, fprintf(of, "<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n", uts.sysname, uts.release, uts.version, uts.machine); fprintf(of, "<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n", cpu); - fprintf(of, "<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n", model); + if (model) + fprintf(of, "<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n", model); fprintf(of, "<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n", cmdline); fprintf(of, "<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n", build); fprintf(of, "<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start); diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c index 28ab1c97fc..189ee969c7 100644 --- a/src/bus-proxyd/proxy.c +++ b/src/bus-proxyd/proxy.c @@ -45,7 +45,7 @@ #include "formats-util.h" static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) { - _cleanup_bus_close_unref_ sd_bus *b = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; int r; r = sd_bus_new(&b); @@ -101,7 +101,7 @@ static int proxy_create_destination(Proxy *p, const char *destination, const cha } static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) { - _cleanup_bus_close_unref_ sd_bus *b = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; sd_id128_t server_id; int r; @@ -144,6 +144,10 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd return 0; } +/* + * dbus-1 clients receive NameOwnerChanged and directed signals without + * subscribing to them; install the matches to receive them on kdbus. + */ static int proxy_prepare_matches(Proxy *p) { _cleanup_free_ char *match = NULL; const char *unique; @@ -189,6 +193,20 @@ static int proxy_prepare_matches(Proxy *p) { if (r < 0) return log_error_errno(r, "Failed to add match for NameAcquired: %m"); + free(match); + match = strjoin("type='signal'," + "destination='", + unique, + "'", + NULL); + if (!match) + return log_oom(); + + r = sd_bus_add_match(p->destination_bus, NULL, match, NULL, NULL); + if (r < 0) + log_error_errno(r, "Failed to add match for directed signals: %m"); + /* FIXME: temporarily ignore error to support older kdbus versions */ + return 0; } @@ -238,8 +256,8 @@ Proxy *proxy_free(Proxy *p) { if (!p) return NULL; - sd_bus_close_unrefp(&p->local_bus); - sd_bus_close_unrefp(&p->destination_bus); + sd_bus_flush_close_unref(p->local_bus); + sd_bus_flush_close_unref(p->destination_bus); set_free_free(p->owned_names); free(p); @@ -494,7 +512,16 @@ static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, } /* First check if we (the sender) can send to this name */ - if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) { + if (sd_bus_message_is_signal(m, NULL, NULL)) { + /* If we forward a signal from dbus-1 to kdbus, we have + * no idea who the recipient is. Therefore, we cannot + * apply any dbus-1 policies that match on receiver + * credentials. We know sd-bus always sets + * KDBUS_MSG_SIGNAL, so the kernel applies policies to + * the message. Therefore, skip policy checks in this + * case. */ + return 0; + } else if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) { if (n) { /* If we made a receiver decision, then remember which * name's policy we used, and to which unique ID it @@ -512,19 +539,8 @@ static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, return r; } - if (sd_bus_message_is_signal(m, NULL, NULL)) { - /* If we forward a signal from dbus-1 to kdbus, - * we have no idea who the recipient is. - * Therefore, we cannot apply any dbus-1 - * receiver policies that match on receiver - * credentials. We know sd-bus always sets - * KDBUS_MSG_SIGNAL, so the kernel applies - * receiver policies to the message. Therefore, - * skip policy checks in this case. */ - return 0; - } else if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) { + if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true)) return 0; - } } /* Return an error back to the caller */ diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index c6f5485716..46a444340a 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) { int r = 0, retval = EXIT_FAILURE; int output_flags; _cleanup_free_ char *root = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; log_parse_environment(); log_open(); diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index 529e843030..612bc8fdec 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -26,7 +26,7 @@ #include "bus-util.h" int main(int argc, char *argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; if (argc != 2) { diff --git a/src/core/dbus.c b/src/core/dbus.c index 86886e6d2c..057653a8b5 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -69,13 +69,37 @@ int bus_send_queued_message(Manager *m) { } static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + const char *cgroup, *me; Manager *m = userdata; - const char *cgroup; + uid_t sender_uid; + sd_bus *bus; int r; assert(message); assert(m); + /* ignore recursive events sent by us on the system/user bus */ + bus = sd_bus_message_get_bus(message); + if (!sd_bus_is_server(bus)) { + r = sd_bus_get_unique_name(bus, &me); + if (r < 0) + return r; + + if (streq_ptr(sd_bus_message_get_sender(message), me)) + return 0; + } + + /* only accept org.freedesktop.systemd1.Agent from UID=0 */ + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); + if (r < 0) + return r; + + r = sd_bus_creds_get_euid(creds, &sender_uid); + if (r < 0 || sender_uid != 0) + return 0; + + /* parse 'cgroup-empty' notification */ r = sd_bus_message_read(message, "s", &cgroup); if (r < 0) { bus_log_parse_error(r); @@ -84,19 +108,15 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus manager_notify_cgroup_empty(m, cgroup); - /* only forward to system bus if running as system instance */ - if (m->running_as != MANAGER_SYSTEM || !m->system_bus) - return 0; - - r = sd_bus_message_rewind(message, 1); - if (r < 0) - goto exit; - - r = sd_bus_send(m->system_bus, message, NULL); + /* if running as system-instance, forward under our name */ + if (m->running_as == MANAGER_SYSTEM && m->system_bus) { + r = sd_bus_message_rewind(message, 1); + if (r >= 0) + r = sd_bus_send(m->system_bus, message, NULL); + if (r < 0) + log_warning_errno(r, "Failed to forward Released message: %m"); + } -exit: - if (r < 0) - log_warning_errno(r, "Failed to forward Released message: %m"); return 0; } diff --git a/src/core/execute.c b/src/core/execute.c index c92db51330..21721dc240 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1446,7 +1446,7 @@ static int exec_child( * shouldn't trip up over that. */ sprintf(t, "%i", context->oom_score_adjust); - r = write_string_file("/proc/self/oom_score_adj", t); + r = write_string_file("/proc/self/oom_score_adj", t, 0); if (r == -EPERM || r == -EACCES) { log_open(); log_unit_debug_errno(unit, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m"); diff --git a/src/core/job.c b/src/core/job.c index 8a047df0c3..1448e5b69a 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -452,7 +452,7 @@ static bool job_is_runnable(Job *j) { j->type == JOB_RELOAD) { /* Immediate result is that the job is or might be - * started. In this case lets wait for the + * started. In this case let's wait for the * dependencies, regardless whether they are * starting or stopping something. */ @@ -462,7 +462,7 @@ static bool job_is_runnable(Job *j) { } /* Also, if something else is being stopped and we should - * change state after it, then lets wait. */ + * change state after it, then let's wait. */ SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i) if (other->job && diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index e7a6bdc8c4..fc6d2f4acb 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -116,7 +116,7 @@ int kmod_setup(void) { else if (r == KMOD_PROBE_APPLY_BLACKLIST) log_info("Module '%s' is blacklisted", kmod_module_get_name(mod)); else { - bool print_warning = kmod_table[i].warn_if_unavailable || (r < 0 && r != -ENOSYS); + bool print_warning = kmod_table[i].warn_if_unavailable || (r < 0 && r != -ENOENT); log_full_errno(print_warning ? LOG_WARNING : LOG_DEBUG, r, "Failed to insert module '%s': %m", kmod_module_get_name(mod)); diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index b3d22840cf..8e26362546 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -260,7 +260,7 @@ int machine_id_setup(const char *root) { * /run/machine-id as a replacement */ RUN_WITH_UMASK(0022) { - r = write_string_file(run_machine_id, id); + r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE); } if (r < 0) { (void) unlink(run_machine_id); diff --git a/src/core/main.c b/src/core/main.c index 523f0ce020..6ae8b51544 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -685,6 +685,26 @@ static int parse_config_file(void) { return 0; } +static void manager_set_defaults(Manager *m) { + + assert(m); + + m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec; + m->default_std_output = arg_default_std_output; + m->default_std_error = arg_default_std_error; + m->default_timeout_start_usec = arg_default_timeout_start_usec; + m->default_timeout_stop_usec = arg_default_timeout_stop_usec; + m->default_restart_usec = arg_default_restart_usec; + m->default_start_limit_interval = arg_default_start_limit_interval; + m->default_start_limit_burst = arg_default_start_limit_burst; + m->default_cpu_accounting = arg_default_cpu_accounting; + m->default_blockio_accounting = arg_default_blockio_accounting; + m->default_memory_accounting = arg_default_memory_accounting; + + manager_set_default_rlimits(m, arg_default_rlimit); + manager_environment_add(m, NULL, arg_default_environment); +} + static int parse_argv(int argc, char *argv[]) { enum { @@ -1203,7 +1223,7 @@ static int write_container_id(void) { if (isempty(c)) return 0; - return write_string_file("/run/systemd/container", c); + return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE); } int main(int argc, char *argv[]) { @@ -1630,28 +1650,15 @@ int main(int argc, char *argv[]) { } m->confirm_spawn = arg_confirm_spawn; - m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec; - m->default_std_output = arg_default_std_output; - m->default_std_error = arg_default_std_error; - m->default_restart_usec = arg_default_restart_usec; - m->default_timeout_start_usec = arg_default_timeout_start_usec; - m->default_timeout_stop_usec = arg_default_timeout_stop_usec; - m->default_start_limit_interval = arg_default_start_limit_interval; - m->default_start_limit_burst = arg_default_start_limit_burst; - m->default_cpu_accounting = arg_default_cpu_accounting; - m->default_blockio_accounting = arg_default_blockio_accounting; - m->default_memory_accounting = arg_default_memory_accounting; m->runtime_watchdog = arg_runtime_watchdog; m->shutdown_watchdog = arg_shutdown_watchdog; - m->userspace_timestamp = userspace_timestamp; m->kernel_timestamp = kernel_timestamp; m->initrd_timestamp = initrd_timestamp; m->security_start_timestamp = security_start_timestamp; m->security_finish_timestamp = security_finish_timestamp; - manager_set_default_rlimits(m, arg_default_rlimit); - manager_environment_add(m, NULL, arg_default_environment); + manager_set_defaults(m); manager_set_show_status(m, arg_show_status); manager_set_first_boot(m, empty_etc); @@ -1763,6 +1770,13 @@ int main(int argc, char *argv[]) { case MANAGER_RELOAD: log_info("Reloading."); + + r = parse_config_file(); + if (r < 0) + log_error("Failed to parse config file."); + + manager_set_defaults(m); + r = manager_reload(m); if (r < 0) log_error_errno(r, "Failed to reload: %m"); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 42a6b952b9..1782d40720 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -27,6 +27,7 @@ #include "mount-setup.h" #include "dev-setup.h" +#include "bus-util.h" #include "log.h" #include "macro.h" #include "util.h" @@ -105,7 +106,7 @@ static const MountPoint mount_table[] = { is_efi_boot, MNT_NONE }, #endif { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, - NULL, MNT_IN_CONTAINER }, + is_kdbus_wanted, MNT_IN_CONTAINER }, }; /* These are API file systems that might be mounted by other software, diff --git a/src/core/path.c b/src/core/path.c index 6d26d89e82..20995d920c 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -426,7 +426,7 @@ static void path_set_state(Path *p, PathState state) { path_unwatch(p); if (state != old_state) - log_debug("Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state)); + log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state)); unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true); } diff --git a/src/core/service.c b/src/core/service.c index fa1e80b710..d72ff54daa 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1235,7 +1235,7 @@ static int main_pid_good(Service *s) { /* Returns 0 if the pid is dead, 1 if it is good, -1 if we * don't know */ - /* If we know the pid file, then lets just check if it is + /* If we know the pid file, then let's just check if it is * still valid */ if (s->main_pid_known) { diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index ddb02a1580..cbe7d0b4a9 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -221,7 +221,7 @@ int mac_smack_setup(bool *loaded_policy) { } #ifdef SMACK_RUN_LABEL - r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL); + r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0); if (r) log_warning("Failed to set SMACK label \"%s\" on self: %s", SMACK_RUN_LABEL, strerror(-r)); diff --git a/src/core/socket.c b/src/core/socket.c index d3178e642b..693cbc6080 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -922,12 +922,6 @@ static void socket_apply_socket_options(Socket *s, int fd) { if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0) log_unit_warning_errno(UNIT(s), errno, "TCP_CONGESTION failed: %m"); - if (s->reuse_port) { - int b = s->reuse_port; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &b, sizeof(b)) < 0) - log_unit_warning_errno(UNIT(s), errno, "SO_REUSEPORT failed: %m"); - } - if (s->smack_ip_in) { r = mac_smack_apply_ip_in_fd(fd, s->smack_ip_in); if (r < 0) @@ -1183,6 +1177,7 @@ static int socket_open_fds(Socket *s) { s->backlog, s->bind_ipv6_only, s->bind_to_device, + s->reuse_port, s->free_bind, s->transparent, s->directory_mode, diff --git a/src/escape/escape.c b/src/escape/escape.c index 9ccb015538..341453398d 100644 --- a/src/escape/escape.c +++ b/src/escape/escape.c @@ -236,5 +236,5 @@ int main(int argc, char *argv[]) { fputc('\n', stdout); finish: - return r <= 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index cda96d484a..3805b29437 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -415,7 +415,7 @@ static int process_hostname(void) { return 0; mkdir_parents(etc_hostname, 0755); - r = write_string_file(etc_hostname, arg_hostname); + r = write_string_file(etc_hostname, arg_hostname, WRITE_STRING_FILE_CREATE); if (r < 0) return log_error_errno(r, "Failed to write %s: %m", etc_hostname); @@ -436,7 +436,7 @@ static int process_machine_id(void) { return 0; mkdir_parents(etc_machine_id, 0755); - r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id)); + r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id), WRITE_STRING_FILE_CREATE); if (r < 0) return log_error_errno(r, "Failed to write machine id: %m"); diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 30254b6680..bd3051f30d 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -62,7 +62,7 @@ static const char *arg_repair = "-a"; static void start_target(const char *target) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; assert(target); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index b46e160888..da5f3b647a 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -183,7 +183,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi r = write_string_file(p, "# Automatically generated by systemd-gpt-auto-generator\n\n" "[Unit]\n" - "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */ + "JobTimeoutSec=0\n", + WRITE_STRING_FILE_CREATE); /* the binary handles timeouts anyway */ if (r < 0) return log_error_errno(r, "Failed to write device drop-in: %m"); diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index 43aac616b6..1f3b169905 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -65,7 +65,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - r = write_string_file("/sys/power/resume", major_minor); + r = write_string_file("/sys/power/resume", major_minor, WRITE_STRING_FILE_CREATE); if (r < 0) { log_error_errno(r, "Failed to write '%s' to /sys/power/resume: %m", major_minor); return EXIT_FAILURE; diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 69ecd61f60..c996fc04a0 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -509,7 +509,7 @@ static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 7ff3a4e224..e52b872a8c 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -663,7 +663,7 @@ static const sd_bus_vtable hostname_vtable[] = { }; static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; assert(c); @@ -695,7 +695,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { int main(int argc, char *argv[]) { Context context = {}; _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; log_set_target(LOG_TARGET_AUTO); diff --git a/src/import/importd.c b/src/import/importd.c index 03aede6016..dd314f5b00 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -551,8 +551,7 @@ static Manager *manager_unref(Manager *m) { bus_verify_polkit_async_registry_free(m->polkit_registry); - sd_bus_close(m->bus); - sd_bus_unref(m->bus); + m->bus = sd_bus_flush_close_unref(m->bus); sd_event_unref(m->event); free(m); diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index d9450ae8cd..9a09f401e0 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -132,7 +132,7 @@ static int request_meta_ensure_tmp(RequestMeta *m) { if (fd < 0) return fd; - m->tmp = fdopen(fd, "rw"); + m->tmp = fdopen(fd, "w+"); if (!m->tmp) { safe_close(fd); return -errno; diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 76ec0827e7..2d6ecfb750 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1719,7 +1719,7 @@ static int access_check(sd_journal *j) { static int flush_to_var(void) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_close_ int watch_fd = -1; int r; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index f7402984af..46358e1c1a 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -943,7 +943,7 @@ static int system_journal_open(Server *s, bool flush_requested) { * the machine path */ if (s->storage == STORAGE_PERSISTENT) - (void) mkdir("/var/log/journal/", 0755); + (void) mkdir_p("/var/log/journal/", 0755); fn = strjoina("/var/log/journal/", ids); (void) mkdir(fn, 0755); diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index 9e184ac4b5..6e00b1ad30 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -72,6 +72,8 @@ struct sd_dhcp_lease { char *root_path; uint8_t *client_id; size_t client_id_len; + uint8_t *vendor_specific; + size_t vendor_specific_len; }; int dhcp_lease_new(sd_dhcp_lease **ret); diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index abca9422c5..aa37e9b0b5 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -125,6 +125,7 @@ enum { DHCP_OPTION_BROADCAST = 28, DHCP_OPTION_STATIC_ROUTE = 33, DHCP_OPTION_NTP_SERVER = 42, + DHCP_OPTION_VENDOR_SPECIFIC = 43, DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, DHCP_OPTION_OVERLOAD = 52, diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index d8bc76edda..e9bf3c9fee 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -179,6 +179,21 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes return 0; } +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data, + size_t *data_len) { + assert_return(lease, -EINVAL); + assert_return(data, -EINVAL); + assert_return(data_len, -EINVAL); + + if (!lease->vendor_specific) + return -ENOENT; + + *data = lease->vendor_specific; + *data_len = lease->vendor_specific_len; + + return 0; +} + sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { if (lease) assert_se(REFCNT_INC(lease->n_ref) >= 2); @@ -194,6 +209,7 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { free(lease->ntp); free(lease->static_route); free(lease->client_id); + free(lease->vendor_specific); free(lease); } @@ -579,6 +595,17 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, return r; break; + + case DHCP_OPTION_VENDOR_SPECIFIC: + if (len >= 1) { + free(lease->vendor_specific); + lease->vendor_specific = memdup(option, len); + if (!lease->vendor_specific) + return -ENOMEM; + lease->vendor_specific_len = len; + } + + break; } return 0; @@ -603,8 +630,8 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { _cleanup_fclose_ FILE *f = NULL; struct in_addr address; const struct in_addr *addresses; - const uint8_t *client_id; - size_t client_id_len; + const uint8_t *client_id, *data; + size_t client_id_len, data_len; const char *string; uint16_t mtu; struct sd_dhcp_route *routes; @@ -690,6 +717,18 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { fprintf(f, "CLIENTID=%s\n", client_id_hex); } + r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len); + if (r >= 0) { + _cleanup_free_ char *option_hex = NULL; + + option_hex = hexmem(data, data_len); + if (!option_hex) { + r = -ENOMEM; + goto finish; + } + fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); + } + r = 0; fflush(f); @@ -712,7 +751,8 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL, *server_address = NULL, *next_server = NULL, *dns = NULL, *ntp = NULL, *mtu = NULL, - *routes = NULL, *client_id_hex = NULL; + *routes = NULL, *client_id_hex = NULL, + *vendor_specific_hex = NULL; struct in_addr addr; int r; @@ -737,6 +777,7 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "ROOT_PATH", &lease->root_path, "ROUTES", &routes, "CLIENTID", &client_id_hex, + "VENDOR_SPECIFIC", &vendor_specific_hex, NULL); if (r < 0) { if (r == -ENOENT) @@ -811,13 +852,21 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } if (client_id_hex) { - if (strlen (client_id_hex) % 2) + if (strlen(client_id_hex) % 2) return -EINVAL; - lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex)); - if (!lease->client_id) - return -ENOMEM; - lease->client_id_len = strlen (client_id_hex) / 2; + r = unhexmem(client_id_hex, strlen(client_id_hex), (void**) &lease->client_id, &lease->client_id_len); + if (r < 0) + return r; + } + + if (vendor_specific_hex) { + if (strlen(vendor_specific_hex) % 2) + return -EINVAL; + + r = unhexmem(vendor_specific_hex, strlen(vendor_specific_hex), (void**) &lease->vendor_specific, &lease->vendor_specific_len); + if (r < 0) + return r; } *ret = lease; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index fddda97f52..6a2c05185d 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -133,8 +133,6 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { lldp->statistics.stats_frames_in_total ++; - return 0; - out: if (r < 0) log_lldp("Receive frame failed: %s", strerror(-r)); diff --git a/src/libsystemd-terminal/grdev-drm.c b/src/libsystemd-terminal/grdev-drm.c index 30c1a726eb..10c13e348a 100644 --- a/src/libsystemd-terminal/grdev-drm.c +++ b/src/libsystemd-terminal/grdev-drm.c @@ -2584,7 +2584,7 @@ static int unmanaged_card_new(grdev_card **out, grdev_session *session, struct u } else { /* We might get DRM-Master implicitly on open(); drop it immediately * so we acquire it only once we're actually enabled. We don't - * really care whether this call fails or not, but lets log any + * really care whether this call fails or not, but let's log any * weird errors, anyway. */ r = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); if (r < 0 && errno != EACCES && errno != EINVAL) @@ -2777,7 +2777,7 @@ static int managed_card_resume_device_fn(sd_bus_message *signal, if (cm->card.fd < 0) { /* This shouldn't happen. We should already own an FD from - * TakeDevice(). However, lets be safe and use this FD in case + * TakeDevice(). However, let's be safe and use this FD in case * we really don't have one. There is no harm in doing this * and our code works fine this way. */ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 97005dbac3..7bf1d66dde 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -465,4 +465,5 @@ global: /* sd-bus */ sd_bus_emit_object_added; sd_bus_emit_object_removed; + sd_bus_flush_close_unref; } LIBSYSTEMD_221; diff --git a/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION b/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION index 859e2715f9..6aeb11364a 100644 --- a/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION +++ b/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION @@ -25,8 +25,8 @@ The header consists of the following: = 12 bytes -This header is then followed by the the fields array, whose first -value is a 32bit array size. +This header is then followed by the fields array, whose first value is +a 32bit array size. When using GVariant we keep the basic structure in place, only slightly alter the header, and define protocol version '2'. The new diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index b17b62ac93..0dbfbddcf6 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -58,6 +58,7 @@ #define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken" #define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress" #define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported" +#define BUS_ERROR_SESSION_BUSY "org.freedesktop.login1.SessionBusy" #define BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED "org.freedesktop.timedate1.AutomaticTimeSyncEnabled" diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 7a59702cb2..a38c5c50fc 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1219,7 +1219,7 @@ int bus_add_match_internal_kernel( size_t sz; const char *sender = NULL; size_t sender_length = 0; - uint64_t src_id = KDBUS_MATCH_ID_ANY; + uint64_t src_id = KDBUS_MATCH_ID_ANY, dst_id = KDBUS_MATCH_ID_ANY; bool using_bloom = false; unsigned i; bool matches_name_change = true; @@ -1332,13 +1332,21 @@ int bus_add_match_internal_kernel( break; } - case BUS_MATCH_DESTINATION: - /* The bloom filter does not include - the destination, since it is only - available for broadcast messages - which do not carry a destination - since they are undirected. */ + case BUS_MATCH_DESTINATION: { + /* + * Kernel only supports matching on destination IDs, but + * not on destination names. So just skip the + * destination name restriction and verify it in + * user-space on retrieval. + */ + r = bus_kernel_parse_unique_name(c->value_str, &dst_id); + if (r < 0) + return r; + else if (r > 0) + sz += ALIGN8(offsetof(struct kdbus_item, id) + sizeof(uint64_t)); + break; + } case BUS_MATCH_ROOT: case BUS_MATCH_VALUE: @@ -1365,6 +1373,13 @@ int bus_add_match_internal_kernel( item = KDBUS_ITEM_NEXT(item); } + if (dst_id != KDBUS_MATCH_ID_ANY) { + item->size = offsetof(struct kdbus_item, id) + sizeof(uint64_t); + item->type = KDBUS_ITEM_DST_ID; + item->id = dst_id; + item = KDBUS_ITEM_NEXT(item); + } + if (using_bloom) { item->size = offsetof(struct kdbus_item, data64) + bus->bloom_size; item->type = KDBUS_ITEM_BLOOM_MASK; diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index f08db2da89..e3fac01f92 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -1385,15 +1385,16 @@ int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) { r = 0; } - } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL) + if (r <= 0) + close_kdbus_msg(bus, k); + } else if (k->payload_type == KDBUS_PAYLOAD_KERNEL) { r = bus_kernel_translate_message(bus, k); - else { + close_kdbus_msg(bus, k); + } else { log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type); r = 0; - } - - if (r <= 0) close_kdbus_msg(bus, k); + } return r < 0 ? r : 1; } diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 2eaa7de306..b3cc28ee9b 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -1164,6 +1164,10 @@ static int process_get_managed_objects( if (bus->nodes_modified) return 0; + r = set_put_strdup(s, m->path); + if (r < 0) + return r; + r = sd_bus_message_new_method_return(m, &reply); if (r < 0) return r; diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index c452477566..b149ea16da 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -273,7 +273,7 @@ _public_ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *descript return free_and_strdup(&slot->description, description); } -_public_ int sd_bus_slot_get_description(sd_bus_slot *slot, char **description) { +_public_ int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description) { assert_return(slot, -EINVAL); assert_return(description, -EINVAL); assert_return(slot->description, -ENXIO); diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 322d57ddbb..735a775cb4 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -264,6 +264,8 @@ static bool line_begins(const char *s, size_t m, const char *word) { static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) { _cleanup_free_ char *token = NULL; + size_t len; + int r; if (!b->anonymous_auth) return 0; @@ -276,11 +278,12 @@ static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) { if (l % 2 != 0) return 0; - token = unhexmem(p, l); - if (!token) - return -ENOMEM; - if (memchr(token, 0, l/2)) + r = unhexmem(p, l, (void **) &token, &len); + if (r < 0) + return 0; + + if (memchr(token, 0, len)) return 0; return !!utf8_is_valid(token); @@ -288,6 +291,7 @@ static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) { static int verify_external_token(sd_bus *b, const char *p, size_t l) { _cleanup_free_ char *token = NULL; + size_t len; uid_t u; int r; @@ -307,11 +311,11 @@ static int verify_external_token(sd_bus *b, const char *p, size_t l) { if (l % 2 != 0) return 0; - token = unhexmem(p, l); - if (!token) - return -ENOMEM; + r = unhexmem(p, l, (void**) &token, &len); + if (r < 0) + return 0; - if (memchr(token, 0, l/2)) + if (memchr(token, 0, len)) return 0; r = parse_uid(token, &u); diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 39caa4e7d6..6aaaf0e5ec 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -1137,6 +1137,7 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL if (m) { dump(m, stdout); + fflush(stdout); if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected") > 0) { log_info("Connection terminated, exiting."); @@ -1973,7 +1974,7 @@ static int busctl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; log_parse_environment(); diff --git a/src/libsystemd/sd-bus/kdbus.h b/src/libsystemd/sd-bus/kdbus.h index 00a6e142c9..ecffc6b13c 100644 --- a/src/libsystemd/sd-bus/kdbus.h +++ b/src/libsystemd/sd-bus/kdbus.h @@ -374,6 +374,7 @@ enum kdbus_item_type { KDBUS_ITEM_ATTACH_FLAGS_RECV, KDBUS_ITEM_ID, KDBUS_ITEM_NAME, + KDBUS_ITEM_DST_ID, /* keep these item types in sync with KDBUS_ATTACH_* flags */ _KDBUS_ITEM_ATTACH_BASE = 0x1000, diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 5dd6468707..0ca225c617 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1428,6 +1428,17 @@ _public_ void sd_bus_close(sd_bus *bus) { * ioctl on the fd when they are freed. */ } +_public_ sd_bus* sd_bus_flush_close_unref(sd_bus *bus) { + + if (!bus) + return NULL; + + sd_bus_flush(bus); + sd_bus_close(bus); + + return sd_bus_unref(bus); +} + static void bus_enter_closing(sd_bus *bus) { assert(bus); diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index 046e999008..754335b5e7 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -262,7 +262,7 @@ fail: static void* client1(void*p) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; const char *hello; int r; @@ -361,7 +361,7 @@ static int quit_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_er static void* client2(void*p) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; bool quit = false; const char *mid; diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index 22ea00c2fb..9b7dd2e499 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -132,7 +132,7 @@ static void test_bus_gvariant_get_alignment(void) { static void test_marshal(void) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_free_ void *blob; size_t sz; int r; diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index a1687b1c7b..83cb5c62c2 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -92,7 +92,7 @@ int main(int argc, char *argv[]) { }; _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; enum bus_match_node_type i; sd_bus_slot slots[19]; int r; diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 52952603e4..1db67ecfac 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -115,14 +115,13 @@ static int set_handler(sd_bus *bus, const char *path, const char *interface, con static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { _cleanup_free_ char *s = NULL; - const char *x; int r; assert_se(asprintf(&s, "object %p, path %s", userdata, path) >= 0); r = sd_bus_message_append(reply, "s", s); assert_se(r >= 0); - assert_se(x = startswith(path, "/value/")); + assert_se(startswith(path, "/value/") != NULL || strcmp(path, "/value") == 0); assert_se(PTR_TO_UINT(userdata) == 30); diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 4aa7583d03..4026e2c341 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -93,7 +93,7 @@ struct sd_netlink { }; struct netlink_attribute { - size_t offset; /* offset from hdr to attirubte */ + size_t offset; /* offset from hdr to attribute */ bool nested:1; bool net_byteorder:1; }; diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 601839d5dc..3616f4af1f 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -667,7 +667,7 @@ static int localectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char*argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/locale/localed.c b/src/locale/localed.c index 0e59350e98..88756542fd 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -1240,7 +1240,7 @@ static const sd_bus_vtable locale_vtable[] = { }; static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; assert(c); @@ -1272,7 +1272,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { int main(int argc, char *argv[]) { _cleanup_(context_free) Context context = {}; _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; log_set_target(LOG_TARGET_AUTO); diff --git a/src/login/71-seat.rules.in b/src/login/71-seat.rules.in index ab7b66f651..de55c9a4ec 100644 --- a/src/login/71-seat.rules.in +++ b/src/login/71-seat.rules.in @@ -17,6 +17,11 @@ SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat" # 'Plugable' USB hub, sound, network, graphics adapter SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUTOSEAT}="1" +# qemu (version 2.4+) has a PCI-PCI bridge (-device pci-bridge-seat) to group +# devices belonging to one seat. See: +# http://git.qemu.org/?p=qemu.git;a=blob;f=docs/multiseat.txt +SUBSYSTEM=="pci", ATTR{vendor}=="0x1b36", ATTR{device}=="0x000a", TAG+="seat", ENV{ID_AUTOSEAT}="1" + # Mimo 720, with integrated USB hub, displaylink graphics, and e2i # touchscreen. This device carries no proper VID/PID in the USB hub, # but it does carry good ID data in the graphics component, hence we diff --git a/src/login/inhibit.c b/src/login/inhibit.c index 0e5dce5925..c53ea8add7 100644 --- a/src/login/inhibit.c +++ b/src/login/inhibit.c @@ -223,7 +223,7 @@ static int parse_argv(int argc, char *argv[]) { int main(int argc, char *argv[]) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; log_parse_environment(); diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 06208bc4b3..9709eca9bd 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -1389,7 +1389,7 @@ static int loginctl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char *argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/login/logind-core.c b/src/login/logind-core.c index a6c01f7d85..96a20e27b9 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -317,7 +317,6 @@ int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) { int r; assert(m); - assert(session); if (pid < 1) return -EINVAL; @@ -330,7 +329,8 @@ int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) { if (!s) return 0; - *session = s; + if (session) + *session = s; return 1; } diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 640ae92f7f..049e33e2a6 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -689,45 +689,26 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus return r; } - manager_get_session_by_pid(m, leader, &session); - if (session) { - _cleanup_free_ char *path = NULL; - _cleanup_close_ int fifo_fd = -1; - - /* Session already exists, client is probably - * something like "su" which changes uid but is still - * the same session */ - - fifo_fd = session_create_fifo(session); - if (fifo_fd < 0) - return fifo_fd; - - path = session_bus_path(session); - if (!path) - return -ENOMEM; - - log_debug("Sending reply about an existing session: " - "id=%s object_path=%s uid=%u runtime_path=%s " - "session_fd=%d seat=%s vtnr=%u", - session->id, - path, - (uint32_t) session->user->uid, - session->user->runtime_path, - fifo_fd, - session->seat ? session->seat->id : "", - (uint32_t) session->vtnr); - - return sd_bus_reply_method_return( - message, "soshusub", - session->id, - path, - session->user->runtime_path, - fifo_fd, - (uint32_t) session->user->uid, - session->seat ? session->seat->id : "", - (uint32_t) session->vtnr, - true); - } + r = manager_get_session_by_pid(m, leader, NULL); + if (r > 0) + return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session"); + + /* + * Old gdm and lightdm start the user-session on the same VT as + * the greeter session. But they destroy the greeter session + * after the user-session and want the user-session to take + * over the VT. We need to support this for + * backwards-compatibility, so make sure we allow new sessions + * on a VT that a greeter is running on. Furthermore, to allow + * re-logins, we have to allow a greeter to take over a used VT for + * the exact same reasons. + */ + if (c != SESSION_GREETER && + vtnr > 0 && + vtnr < m->seat0->position_count && + m->seat0->positions[vtnr] && + m->seat0->positions[vtnr]->class != SESSION_GREETER) + return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session"); audit_session_from_pid(leader, &audit_id); if (audit_id > 0) { @@ -1194,7 +1175,7 @@ static int trigger_device(Manager *m, struct udev_device *d) { if (!t) return -ENOMEM; - write_string_file(t, "change"); + write_string_file(t, "change", WRITE_STRING_FILE_CREATE); } return 0; @@ -1793,7 +1774,7 @@ static int nologin_timeout_handler( log_info("Creating /run/nologin, blocking further logins..."); - r = write_string_file_atomic("/run/nologin", "System is going down."); + r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC); if (r < 0) log_error_errno(r, "Failed to create /run/nologin: %m"); else @@ -2468,8 +2449,6 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("PowerOff", "b", NULL, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Reboot", "b", NULL, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), @@ -2477,6 +2456,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index 3c30eeaa95..9d5287ad35 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -269,7 +269,7 @@ int seat_set_active(Seat *s, Session *session) { int seat_switch_to(Seat *s, unsigned int num) { /* Public session positions skip 0 (there is only F1-F12). Maybe it * will get reassigned in the future, so return error for now. */ - if (!num) + if (num == 0) return -EINVAL; if (num >= s->position_count || !s->positions[num]) { @@ -286,12 +286,12 @@ int seat_switch_to(Seat *s, unsigned int num) { int seat_switch_to_next(Seat *s) { unsigned int start, i; - if (!s->position_count) + if (s->position_count == 0) return -EINVAL; start = 1; - if (s->active && s->active->pos > 0) - start = s->active->pos; + if (s->active && s->active->position > 0) + start = s->active->position; for (i = start + 1; i < s->position_count; ++i) if (s->positions[i]) @@ -307,12 +307,12 @@ int seat_switch_to_next(Seat *s) { int seat_switch_to_previous(Seat *s) { unsigned int start, i; - if (!s->position_count) + if (s->position_count == 0) return -EINVAL; start = 1; - if (s->active && s->active->pos > 0) - start = s->active->pos; + if (s->active && s->active->position > 0) + start = s->active->position; for (i = start - 1; i > 0; --i) if (s->positions[i]) @@ -472,21 +472,21 @@ int seat_stop_sessions(Seat *s, bool force) { void seat_evict_position(Seat *s, Session *session) { Session *iter; - unsigned int pos = session->pos; + unsigned int pos = session->position; - session->pos = 0; + session->position = 0; - if (!pos) + if (pos == 0) return; if (pos < s->position_count && s->positions[pos] == session) { s->positions[pos] = NULL; /* There might be another session claiming the same - * position (eg., during gdm->session transition), so lets look + * position (eg., during gdm->session transition), so let's look * for it and set it on the free slot. */ LIST_FOREACH(sessions_by_seat, iter, s->sessions) { - if (iter->pos == pos) { + if (iter->position == pos) { s->positions[pos] = iter; break; } @@ -504,7 +504,7 @@ void seat_claim_position(Seat *s, Session *session, unsigned int pos) { seat_evict_position(s, session); - session->pos = pos; + session->position = pos; if (pos > 0 && !s->positions[pos]) s->positions[pos] = session; } @@ -512,7 +512,7 @@ void seat_claim_position(Seat *s, Session *session, unsigned int pos) { static void seat_assign_position(Seat *s, Session *session) { unsigned int pos; - if (session->pos > 0) + if (session->position > 0) return; for (pos = 1; pos < s->position_count; ++pos) diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 6a450b02a0..45f4c09d3d 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -264,7 +264,7 @@ int session_save(Session *s) { fprintf(f, "VTNR=%u\n", s->vtnr); if (!s->vtnr) - fprintf(f, "POS=%u\n", s->pos); + fprintf(f, "POSITION=%u\n", s->position); if (s->leader > 0) fprintf(f, "LEADER="PID_FMT"\n", s->leader); @@ -302,7 +302,7 @@ int session_load(Session *s) { *seat = NULL, *vtnr = NULL, *state = NULL, - *pos = NULL, + *position = NULL, *leader = NULL, *type = NULL, *class = NULL, @@ -329,7 +329,7 @@ int session_load(Session *s) { "DESKTOP", &s->desktop, "VTNR", &vtnr, "STATE", &state, - "POS", &pos, + "POSITION", &position, "LEADER", &leader, "TYPE", &type, "CLASS", &class, @@ -388,10 +388,10 @@ int session_load(Session *s) { if (!s->seat || !seat_has_vts(s->seat)) s->vtnr = 0; - if (pos && s->seat) { + if (position && s->seat) { unsigned int npos; - safe_atou(pos, &npos); + safe_atou(position, &npos); seat_claim_position(s->seat, s, npos); } diff --git a/src/login/logind-session.h b/src/login/logind-session.h index 4bf739a44d..b8565ebf51 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -70,7 +70,7 @@ struct Session { Manager *manager; const char *id; - unsigned int pos; + unsigned int position; SessionType type; SessionClass class; diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index 0f72d70b10..36c0e8626d 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -103,11 +103,7 @@ static int property_get_sessions( } - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; - - return 1; + return sd_bus_message_close_container(reply); } static int property_get_idle_hint( diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index 0ad78802dd..d8deb7bc8b 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -90,6 +90,42 @@ <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Manager" + send_member="LockSession"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="UnlockSession"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="LockSessions"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="UnlockSessions"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="KillSession"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="KillUser"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="TerminateSession"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="TerminateUser"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="TerminateSeat"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" send_member="PowerOff"/> <allow send_destination="org.freedesktop.login1" @@ -130,6 +166,14 @@ <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Manager" + send_member="ScheduleShutdown"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" + send_member="CancelScheduledShutdown"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" send_member="CanRebootToFirmwareSetup"/> <allow send_destination="org.freedesktop.login1" @@ -146,6 +190,10 @@ <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Seat" + send_member="Terminate"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Seat" send_member="ActivateSession"/> <allow send_destination="org.freedesktop.login1" @@ -162,14 +210,30 @@ <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Session" + send_member="Terminate"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Session" send_member="Activate"/> <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Session" + send_member="Lock"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Session" + send_member="Unlock"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Session" send_member="SetIdleHint"/> <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Session" + send_member="Kill"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Session" send_member="TakeControl"/> <allow send_destination="org.freedesktop.login1" @@ -188,6 +252,14 @@ send_interface="org.freedesktop.login1.Session" send_member="PauseDeviceComplete"/> + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.User" + send_member="Terminate"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.User" + send_member="Kill"/> + <allow receive_sender="org.freedesktop.login1"/> </policy> diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index dd192b90ce..f83d18b035 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -31,6 +31,7 @@ #include <security/pam_ext.h> #include <security/pam_misc.h> +#include "bus-common-errors.h" #include "util.h" #include "audit.h" #include "macro.h" @@ -213,7 +214,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( *seat = NULL, *type = NULL, *class = NULL, *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int session_fd = -1, existing, r; bool debug = false, remote; struct passwd *pw; @@ -399,8 +400,13 @@ _public_ PAM_EXTERN int pam_sm_open_session( remote_host, 0); if (r < 0) { - pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); - return PAM_SYSTEM_ERR; + if (sd_bus_error_has_name(&error, BUS_ERROR_SESSION_BUSY)) { + pam_syslog(handle, LOG_DEBUG, "Cannot create session: %s", bus_error_message(&error, r)); + return PAM_SUCCESS; + } else { + pam_syslog(handle, LOG_ERR, "Failed to create session: %s", bus_error_message(&error, r)); + return PAM_SYSTEM_ERR; + } } r = sd_bus_message_read(reply, @@ -496,7 +502,7 @@ _public_ PAM_EXTERN int pam_sm_close_session( int argc, const char **argv) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; const void *existing = NULL; const char *id; int r; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 7813a0bcc7..dc42ffdc52 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -55,17 +55,12 @@ static int property_get_id( sd_bus_error *error) { Machine *m = userdata; - int r; assert(bus); assert(reply); assert(m); - r = sd_bus_message_append_array(reply, 'y', &m->id, 16); - if (r < 0) - return r; - - return 1; + return sd_bus_message_append_array(reply, 'y', &m->id, 16); } static int property_get_state( @@ -104,7 +99,6 @@ static int property_get_netif( sd_bus_error *error) { Machine *m = userdata; - int r; assert(bus); assert(reply); @@ -112,11 +106,7 @@ static int property_get_netif( assert_cc(sizeof(int) == sizeof(int32_t)); - r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int)); - if (r < 0) - return r; - - return 1; + return sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int)); } static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 7938aa4dbe..7cb6ce77ac 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2572,7 +2572,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char*argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 16243a5352..9550e89a15 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -116,6 +116,16 @@ static bool link_ipv6_forward_enabled(Link *link) { return link->network->ip_forward & ADDRESS_FAMILY_IPV6; } +static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) { + if (link->flags & IFF_LOOPBACK) + return _IPV6_PRIVACY_EXTENSIONS_INVALID; + + if (!link->network) + return _IPV6_PRIVACY_EXTENSIONS_INVALID; + + return link->network->ipv6_privacy_extensions; +} + #define FLAG_STRING(string, flag, old, new) \ (((old ^ new) & flag) \ ? ((old & flag) ? (" -" string) : (" +" string)) \ @@ -1360,8 +1370,7 @@ static int link_joined(Link *link) { return link_enter_set_addresses(link); } -static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, - void *userdata) { +static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -1474,35 +1483,84 @@ static int link_enter_join_netdev(Link *link) { } static int link_set_ipv4_forward(Link *link) { - const char *p = NULL; + const char *p = NULL, *v; int r; + if (link->flags & IFF_LOOPBACK) + return 0; + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) return 0; p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding"); - r = write_string_file_no_create(p, one_zero(link_ipv4_forward_enabled(link))); - if (r < 0) + v = one_zero(link_ipv4_forward_enabled(link)); + + r = write_string_file(p, v, 0); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, v) > 0) + return 0; + log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname); + } return 0; } static int link_set_ipv6_forward(Link *link) { - const char *p = NULL; + const char *p = NULL, *v = NULL; int r; /* Make this a NOP if IPv6 is not available */ if (!socket_ipv6_is_supported()) return 0; + if (link->flags & IFF_LOOPBACK) + return 0; + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) return 0; p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding"); - r = write_string_file_no_create(p, one_zero(link_ipv6_forward_enabled(link))); - if (r < 0) + v = one_zero(link_ipv6_forward_enabled(link)); + + r = write_string_file(p, v, 0); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, v) > 0) + return 0; + log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m"); + } + + return 0; +} + +static int link_set_ipv6_privacy_extensions(Link *link) { + char buf[DECIMAL_STR_MAX(unsigned) + 1]; + IPv6PrivacyExtensions s; + const char *p = NULL; + int r; + + /* Make this a NOP if IPv6 is not available */ + if (!socket_ipv6_is_supported()) + return 0; + + s = link_ipv6_privacy_extensions(link); + if (s == _IPV6_PRIVACY_EXTENSIONS_INVALID) + return 0; + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr"); + xsprintf(buf, "%u", link->network->ipv6_privacy_extensions); + + r = write_string_file(p, buf, 0); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, buf) > 0) + return 0; + + log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m"); + } return 0; } @@ -1526,6 +1584,10 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = link_set_ipv6_privacy_extensions(link); + if (r < 0) + return r; + if (link_ipv4ll_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 66ed2e013c..010c106610 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -59,6 +59,7 @@ Tun.Group, config_parse_string, 0, Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue) Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue) Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info) +Tap.VnetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr) Tap.User, config_parse_string, 0, offsetof(TunTap, user_name) Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name) Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode) diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index 378312f091..ba84e802fc 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -51,6 +51,9 @@ static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) { if (t->multi_queue) ifr->ifr_flags |= IFF_MULTI_QUEUE; + if (t->vnet_hdr) + ifr->ifr_flags |= IFF_VNET_HDR; + strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1); return 0; diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h index b804875bbb..29f8bb0ea5 100644 --- a/src/network/networkd-netdev-tuntap.h +++ b/src/network/networkd-netdev-tuntap.h @@ -33,6 +33,7 @@ struct TunTap { bool one_queue; bool multi_queue; bool packet_info; + bool vnet_hdr; }; extern const NetDevVTable tun_vtable; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index ece9ecc251..6949b403c8 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -92,10 +92,11 @@ static void netdev_cancel_callbacks(NetDev *netdev) { assert(netdev->manager); assert(netdev->manager->rtnl); - callback->callback(netdev->manager->rtnl, m, link); + callback->callback(netdev->manager->rtnl, m, callback->link); } LIST_REMOVE(callbacks, netdev->callbacks, callback); + link_unref(callback->link); free(callback); } } @@ -177,6 +178,8 @@ int netdev_get(Manager *manager, const char *name, NetDev **ret) { static int netdev_enter_failed(NetDev *netdev) { netdev->state = NETDEV_STATE_FAILED; + netdev_cancel_callbacks(netdev); + return 0; } @@ -266,12 +269,20 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call int r; assert(netdev); + assert(netdev->manager); + assert(netdev->manager->rtnl); assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND)); if (netdev->state == NETDEV_STATE_READY) { r = netdev_enslave_ready(netdev, link, callback); if (r < 0) return r; + } else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) { + _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + + r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m); + if (r >= 0) + callback(netdev->manager->rtnl, m, link); } else { /* the netdev is not yet read, save this request for when it is */ netdev_join_callback *cb; diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c index b5f8f5cfb2..5717a15327 100644 --- a/src/network/networkd-network-bus.c +++ b/src/network/networkd-network-bus.c @@ -53,11 +53,7 @@ static int property_get_ether_addrs( return r; } - r = sd_bus_message_close_container(reply); - if (r < 0) - return r; - - return 1; + return sd_bus_message_close_container(reply); } const sd_bus_vtable network_vtable[] = { diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index b05bc949f2..787fc2ff5b 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -15,69 +15,70 @@ struct ConfigPerfItem; %struct-type %includes %% -Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac) -Match.Path, config_parse_strv, 0, offsetof(Network, match_path) -Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver) -Match.Type, config_parse_strv, 0, offsetof(Network, match_type) -Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name) -Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host) -Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt) -Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel) -Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) -Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) -Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) -Network.Description, config_parse_string, 0, offsetof(Network, description) -Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) -Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) -Network.VLAN, config_parse_netdev, 0, 0 -Network.MACVLAN, config_parse_netdev, 0, 0 -Network.IPVLAN, config_parse_netdev, 0, 0 -Network.VXLAN, config_parse_netdev, 0, 0 -Network.Tunnel, config_parse_tunnel, 0, 0 -Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) -Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) -Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) -Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) -Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) -Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) -Network.Address, config_parse_address, 0, 0 -Network.Gateway, config_parse_gateway, 0, 0 -Network.Domains, config_parse_domains, 0, offsetof(Network, domains) -Network.DNS, config_parse_strv, 0, offsetof(Network, dns) -Network.LLMNR, config_parse_llmnr, 0, offsetof(Network, llmnr) -Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) -Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) -Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) -Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) -Address.Address, config_parse_address, 0, 0 -Address.Peer, config_parse_address, 0, 0 -Address.Broadcast, config_parse_broadcast, 0, 0 -Address.Label, config_parse_label, 0, 0 -Route.Gateway, config_parse_gateway, 0, 0 -Route.Destination, config_parse_destination, 0, 0 -Route.Source, config_parse_destination, 0, 0 -Route.Metric, config_parse_route_priority, 0, 0 -Route.Scope, config_parse_route_scope, 0, 0 -DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) -DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) -DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) -DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) -DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) -DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) -DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) -DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) -Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) -BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 -BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 +Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac) +Match.Path, config_parse_strv, 0, offsetof(Network, match_path) +Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver) +Match.Type, config_parse_strv, 0, offsetof(Network, match_type) +Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name) +Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host) +Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt) +Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel) +Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) +Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) +Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Network.Description, config_parse_string, 0, offsetof(Network, description) +Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) +Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) +Network.VLAN, config_parse_netdev, 0, 0 +Network.MACVLAN, config_parse_netdev, 0, 0 +Network.IPVLAN, config_parse_netdev, 0, 0 +Network.VXLAN, config_parse_netdev, 0, 0 +Network.Tunnel, config_parse_tunnel, 0, 0 +Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) +Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) +Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) +Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) +Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) +Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) +Network.Address, config_parse_address, 0, 0 +Network.Gateway, config_parse_gateway, 0, 0 +Network.Domains, config_parse_domains, 0, offsetof(Network, domains) +Network.DNS, config_parse_strv, 0, offsetof(Network, dns) +Network.LLMNR, config_parse_llmnr, 0, offsetof(Network, llmnr) +Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) +Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) +Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) +Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) +Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) +Address.Address, config_parse_address, 0, 0 +Address.Peer, config_parse_address, 0, 0 +Address.Broadcast, config_parse_broadcast, 0, 0 +Address.Label, config_parse_label, 0, 0 +Route.Gateway, config_parse_gateway, 0, 0 +Route.Destination, config_parse_destination, 0, 0 +Route.Source, config_parse_destination, 0, 0 +Route.Metric, config_parse_route_priority, 0, 0 +Route.Scope, config_parse_route_scope, 0, 0 +DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) +DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) +DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) +DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) +DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) +DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) +DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) +DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) +DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) +DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) +Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) +BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 +BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 /* backwards compatibility: do not add new entries to this section */ -Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) -DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) +Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) +DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) +DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) +DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index ec95c8661e..a8e9ef909c 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -111,6 +111,8 @@ static int network_load_one(Manager *manager, const char *filename) { network->link_local = ADDRESS_FAMILY_IPV6; + network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; + r = config_parse(NULL, filename, file, "Match\0" "Link\0" @@ -751,3 +753,59 @@ int config_parse_address_family_boolean_with_kernel( return 0; } + +static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = { + [IPV6_PRIVACY_EXTENSIONS_NO] = "no", + [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public", + [IPV6_PRIVACY_EXTENSIONS_YES] = "yes", +}; + +DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions); + +int config_parse_ipv6_privacy_extensions( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + IPv6PrivacyExtensions *ipv6_privacy_extensions = data; + int k; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(ipv6_privacy_extensions); + + /* Our enum shall be a superset of booleans, hence first try + * to parse as boolean, and then as enum */ + + k = parse_boolean(rvalue); + if (k > 0) + *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES; + else if (k == 0) + *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; + else { + IPv6PrivacyExtensions s; + + s = ipv6_privacy_extensions_from_string(rvalue); + if (s < 0) { + + if (streq(rvalue, "kernel")) + s = _IPV6_PRIVACY_EXTENSIONS_INVALID; + else { + log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue); + return 0; + } + } + + *ipv6_privacy_extensions = s; + } + + return 0; +} diff --git a/src/network/networkd.c b/src/network/networkd.c index 9fe8a5fa15..e6259043fa 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) { r = manager_rtnl_enumerate_addresses(m); if (r < 0) { - log_error_errno(r, "Could not enumerate links: %m"); + log_error_errno(r, "Could not enumerate addresses: %m"); goto out; } diff --git a/src/network/networkd.h b/src/network/networkd.h index ac6e2c8a8e..f98c640822 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -90,6 +90,15 @@ typedef enum DCHPClientIdentifier { _DHCP_CLIENT_ID_INVALID = -1, } DCHPClientIdentifier; +typedef enum IPv6PrivacyExtensions { + /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */ + IPV6_PRIVACY_EXTENSIONS_NO, + IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC, + IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */ + _IPV6_PRIVACY_EXTENSIONS_MAX, + _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, +} IPv6PrivacyExtensions; + struct FdbEntry { Network *network; unsigned section; @@ -145,6 +154,8 @@ struct Network { AddressFamilyBoolean ip_forward; bool ip_masquerade; + IPv6PrivacyExtensions ipv6_privacy_extensions; + struct ether_addr *mac; unsigned mtu; @@ -455,3 +466,10 @@ int config_parse_address_family_boolean_with_kernel(const char *unit, const char const char* link_operstate_to_string(LinkOperationalState s) _const_; LinkOperationalState link_operstate_from_string(const char *s) _pure_; + +/* IPv6 privacy extensions support */ + +const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; +IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; + +int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 7fa098bea8..3428109da4 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -341,6 +341,11 @@ static int custom_mounts_prepare(void) { for (i = 0; i < arg_n_custom_mounts; i++) { CustomMount *m = &arg_custom_mounts[i]; + if (arg_userns && arg_uid_shift == UID_INVALID && path_equal(m->destination, "/")) { + log_error("--private-users with automatic UID shift may not be combined with custom root mounts."); + return -EINVAL; + } + if (m->type != CUSTOM_MOUNT_OVERLAY) continue; @@ -751,9 +756,8 @@ static int parse_argv(int argc, char *argv[]) { /* If two parameters are specified, * the first one is the lower, the * second one the upper directory. And - * we'll also define the the - * destination mount point the same as - * the upper. */ + * we'll also define the destination + * mount point the same as the upper. */ upper = lower[1]; lower[1] = NULL; @@ -1028,6 +1032,7 @@ static int tmpfs_patch_options(const char *options, char **ret) { char *buf = NULL; if (arg_userns && arg_uid_shift != 0) { + assert(arg_uid_shift != UID_INVALID); if (options) (void) asprintf(&buf, "%s,uid=" UID_FMT ",gid=" UID_FMT, options, arg_uid_shift, arg_uid_shift); @@ -1697,7 +1702,7 @@ static int setup_boot_id(const char *dest) { id128_format_as_uuid(rnd, as_uuid); - r = write_string_file(from, as_uuid); + r = write_string_file(from, as_uuid, WRITE_STRING_FILE_CREATE); if (r < 0) return log_error_errno(r, "Failed to write boot id: %m"); @@ -2273,7 +2278,7 @@ static int drop_capabilities(void) { static int register_machine(pid_t pid, int local_ifindex) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; if (!arg_register) @@ -2430,7 +2435,7 @@ static int register_machine(pid_t pid, int local_ifindex) { static int terminate_machine(pid_t pid) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; const char *path; int r; @@ -2502,7 +2507,7 @@ static int reset_audit_loginuid(void) { if (streq(p, "4294967295")) return 0; - r = write_string_file("/proc/self/loginuid", "4294967295"); + r = write_string_file("/proc/self/loginuid", "4294967295", 0); if (r < 0) { log_error_errno(r, "Failed to reset audit login UID. This probably means that your kernel is too\n" @@ -4259,6 +4264,7 @@ static int outer_child( int pid_socket, int kmsg_socket, int rtnl_socket, + int uid_shift_socket, FDSet *fds, int argc, char *argv[]) { @@ -4313,6 +4319,20 @@ static int outer_child( if (r < 0) return r; + r = determine_uid_shift(directory); + if (r < 0) + return r; + + if (arg_userns) { + l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL); + if (l < 0) + return log_error_errno(errno, "Failed to send UID shift: %m"); + if (l != sizeof(arg_uid_shift)) { + log_error("Short write while sending UID shift."); + return -EIO; + } + } + /* Turn directory into bind mount */ if (mount(directory, directory, NULL, MS_BIND|MS_REC, NULL) < 0) return log_error_errno(errno, "Failed to make bind mount: %m"); @@ -4393,6 +4413,7 @@ static int outer_child( if (pid == 0) { pid_socket = safe_close(pid_socket); + uid_shift_socket = safe_close(uid_shift_socket); /* The inner child has all namespaces that are * requested, so that we all are owned by the user if @@ -4426,13 +4447,13 @@ static int setup_uid_map(pid_t pid) { xsprintf(uid_map, "/proc/" PID_FMT "/uid_map", pid); xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, arg_uid_shift, arg_uid_range); - r = write_string_file(uid_map, line); + r = write_string_file(uid_map, line, 0); if (r < 0) return log_error_errno(r, "Failed to write UID map: %m"); /* We always assign the same UID and GID ranges */ xsprintf(uid_map, "/proc/" PID_FMT "/gid_map", pid); - r = write_string_file(uid_map, line); + r = write_string_file(uid_map, line, 0); if (r < 0) return log_error_errno(r, "Failed to write GID map: %m"); @@ -4491,10 +4512,6 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - r = determine_uid_shift(arg_directory); - if (r < 0) - return r; - if (geteuid() != 0) { log_error("Need to be root."); r = -EPERM; @@ -4687,7 +4704,8 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }; + _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, + uid_shift_socket_pair[2] = { -1, -1 }; ContainerStatus container_status; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; static const struct sigaction sa = { @@ -4696,10 +4714,10 @@ int main(int argc, char *argv[]) { }; int ifi = 0; ssize_t l; - _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_(pty_forward_freep) PTYForward *forward = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - char last_char = 0; + _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(pty_forward_freep) PTYForward *forward = NULL; + _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + char last_char = 0; r = barrier_create(&barrier); if (r < 0) { @@ -4722,6 +4740,12 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_userns) + if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) { + r = log_error_errno(errno, "Failed to create uid shift socket pair: %m"); + goto finish; + } + /* Child can be killed before execv(), so handle SIGCHLD * in order to interrupt parent's blocking calls and * give it a chance to call wait() and terminate. */ @@ -4756,6 +4780,7 @@ int main(int argc, char *argv[]) { kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); pid_socket_pair[0] = safe_close(pid_socket_pair[0]); + uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); (void) reset_all_signal_handlers(); (void) reset_signal_mask(); @@ -4771,6 +4796,7 @@ int main(int argc, char *argv[]) { pid_socket_pair[1], kmsg_socket_pair[1], rtnl_socket_pair[1], + uid_shift_socket_pair[1], fds, argc, argv); if (r < 0) @@ -4819,6 +4845,17 @@ int main(int argc, char *argv[]) { goto finish; } + l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0); + if (l < 0) { + r = log_error_errno(errno, "Failed to read UID shift: %m"); + goto finish; + } + if (l != sizeof(arg_uid_shift)) { + log_error("Short read while reading UID shift: %m"); + r = EIO; + goto finish; + } + r = setup_uid_map(pid); if (r < 0) goto finish; diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 9476ad1694..f712033e6c 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -79,7 +79,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r( struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_free_ int *ifindices = NULL; _cleanup_free_ char *class = NULL; size_t l, ms, idx; @@ -228,7 +228,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r( char **canonp) { _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_free_ char *class = NULL; unsigned c = 0, i = 0; char *r_name, *r_aliases, *r_addr, *r_addr_list; diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index 8f181a6c72..da22f98eba 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -122,7 +122,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; const char *canonical = NULL; size_t l, ms, idx; char *r_name; @@ -305,7 +305,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; size_t l, idx, ms, alen; const char *canonical; int c, r, i = 0, ifindex; @@ -513,7 +513,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; unsigned c = 0, i = 0; size_t ms = 0, idx; const char *n; diff --git a/src/python-systemd/.gitignore b/src/python-systemd/.gitignore deleted file mode 100644 index 4124b7affd..0000000000 --- a/src/python-systemd/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/id128-constants.h -*.py[oc] diff --git a/src/python-systemd/Makefile b/src/python-systemd/Makefile deleted file mode 120000 index d0b0e8e008..0000000000 --- a/src/python-systemd/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/src/python-systemd/__init__.py b/src/python-systemd/__init__.py deleted file mode 100644 index 0d56b992f4..0000000000 --- a/src/python-systemd/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil -*- */ -# -# This file is part of systemd. -# -# Copyright 2012 David Strauss -# -# 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/>. diff --git a/src/python-systemd/_daemon.c b/src/python-systemd/_daemon.c deleted file mode 100644 index 7c5f1b2bb6..0000000000 --- a/src/python-systemd/_daemon.c +++ /dev/null @@ -1,331 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl> - - 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/>. -***/ - -#define PY_SSIZE_T_CLEAN -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wredundant-decls" -#include <Python.h> -#pragma GCC diagnostic pop - -#include <stdbool.h> -#include <assert.h> -#include <sys/socket.h> - -#include "systemd/sd-daemon.h" -#include "pyutil.h" -#include "macro.h" - -PyDoc_STRVAR(module__doc__, - "Python interface to the libsystemd-daemon library.\n\n" - "Provides _listen_fds, notify, booted, and is_* functions\n" - "which wrap sd_listen_fds, sd_notify, sd_booted, sd_is_* and\n" - "useful for socket activation and checking if the system is\n" - "running under systemd." -); - -PyDoc_STRVAR(booted__doc__, - "booted() -> bool\n\n" - "Return True iff this system is running under systemd.\n" - "Wraps sd_daemon_booted(3)." -); - -static PyObject* booted(PyObject *self, PyObject *args) { - int r; - assert(args == NULL); - - r = sd_booted(); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - -PyDoc_STRVAR(notify__doc__, - "notify(status, unset_environment=False) -> bool\n\n" - "Send a message to the init system about a status change.\n" - "Wraps sd_notify(3)."); - -static PyObject* notify(PyObject *self, PyObject *args, PyObject *keywds) { - int r; - const char* msg; - int unset = false; - - static const char* const kwlist[] = { - "status", - "unset_environment", - NULL, - }; -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3 - if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|p:notify", - (char**) kwlist, &msg, &unset)) - return NULL; -#else - PyObject *obj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|O:notify", - (char**) kwlist, &msg, &obj)) - return NULL; - if (obj != NULL) - unset = PyObject_IsTrue(obj); - if (unset < 0) - return NULL; -#endif - - r = sd_notify(unset, msg); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - - -PyDoc_STRVAR(listen_fds__doc__, - "_listen_fds(unset_environment=True) -> int\n\n" - "Return the number of descriptors passed to this process by the init system\n" - "as part of the socket-based activation logic.\n" - "Wraps sd_listen_fds(3)." -); - -static PyObject* listen_fds(PyObject *self, PyObject *args, PyObject *keywds) { - int r; - int unset = true; - - static const char* const kwlist[] = {"unset_environment", NULL}; -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 3 - if (!PyArg_ParseTupleAndKeywords(args, keywds, "|p:_listen_fds", - (char**) kwlist, &unset)) - return NULL; -#else - PyObject *obj = NULL; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O:_listen_fds", - (char**) kwlist, &obj)) - return NULL; - if (obj != NULL) - unset = PyObject_IsTrue(obj); - if (unset < 0) - return NULL; -#endif - - r = sd_listen_fds(unset); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return long_FromLong(r); -} - -PyDoc_STRVAR(is_fifo__doc__, - "_is_fifo(fd, path) -> bool\n\n" - "Returns True iff the descriptor refers to a FIFO or a pipe.\n" - "Wraps sd_is_fifo(3)." -); - - -static PyObject* is_fifo(PyObject *self, PyObject *args) { - int r; - int fd; - const char *path = NULL; - -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 - if (!PyArg_ParseTuple(args, "i|O&:_is_fifo", - &fd, Unicode_FSConverter, &path)) - return NULL; -#else - if (!PyArg_ParseTuple(args, "i|z:_is_fifo", &fd, &path)) - return NULL; -#endif - - r = sd_is_fifo(fd, path); - if (set_error(r, path, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - - -PyDoc_STRVAR(is_mq__doc__, - "_is_mq(fd, path) -> bool\n\n" - "Returns True iff the descriptor refers to a POSIX message queue.\n" - "Wraps sd_is_mq(3)." -); - -static PyObject* is_mq(PyObject *self, PyObject *args) { - int r; - int fd; - const char *path = NULL; - -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 - if (!PyArg_ParseTuple(args, "i|O&:_is_mq", - &fd, Unicode_FSConverter, &path)) - return NULL; -#else - if (!PyArg_ParseTuple(args, "i|z:_is_mq", &fd, &path)) - return NULL; -#endif - - r = sd_is_mq(fd, path); - if (set_error(r, path, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - - - -PyDoc_STRVAR(is_socket__doc__, - "_is_socket(fd, family=AF_UNSPEC, type=0, listening=-1) -> bool\n\n" - "Returns True iff the descriptor refers to a socket.\n" - "Wraps sd_is_socket(3).\n\n" - "Constants for `family` are defined in the socket module." -); - -static PyObject* is_socket(PyObject *self, PyObject *args) { - int r; - int fd, family = AF_UNSPEC, type = 0, listening = -1; - - if (!PyArg_ParseTuple(args, "i|iii:_is_socket", - &fd, &family, &type, &listening)) - return NULL; - - r = sd_is_socket(fd, family, type, listening); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - - -PyDoc_STRVAR(is_socket_inet__doc__, - "_is_socket_inet(fd, family=AF_UNSPEC, type=0, listening=-1, port=0) -> bool\n\n" - "Wraps sd_is_socket_inet(3).\n\n" - "Constants for `family` are defined in the socket module." -); - -static PyObject* is_socket_inet(PyObject *self, PyObject *args) { - int r; - int fd, family = AF_UNSPEC, type = 0, listening = -1, port = 0; - - if (!PyArg_ParseTuple(args, "i|iiii:_is_socket_inet", - &fd, &family, &type, &listening, &port)) - return NULL; - - if (port < 0 || port > UINT16_MAX) { - set_error(-EINVAL, NULL, "port must fit into uint16_t"); - return NULL; - } - - r = sd_is_socket_inet(fd, family, type, listening, (uint16_t) port); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - - -PyDoc_STRVAR(is_socket_unix__doc__, - "_is_socket_unix(fd, type, listening, path) -> bool\n\n" - "Wraps sd_is_socket_unix(3)." -); - -static PyObject* is_socket_unix(PyObject *self, PyObject *args) { - int r; - int fd, type = 0, listening = -1; - char* path = NULL; - Py_ssize_t length = 0; - -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 - _cleanup_Py_DECREF_ PyObject *_path = NULL; - if (!PyArg_ParseTuple(args, "i|iiO&:_is_socket_unix", - &fd, &type, &listening, Unicode_FSConverter, &_path)) - return NULL; - if (_path) { - assert(PyBytes_Check(_path)); - if (PyBytes_AsStringAndSize(_path, &path, &length)) - return NULL; - } -#else - if (!PyArg_ParseTuple(args, "i|iiz#:_is_socket_unix", - &fd, &type, &listening, &path, &length)) - return NULL; -#endif - - r = sd_is_socket_unix(fd, type, listening, path, length); - if (set_error(r, path, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - - -static PyMethodDef methods[] = { - { "booted", booted, METH_NOARGS, booted__doc__}, - { "notify", (PyCFunction) notify, METH_VARARGS | METH_KEYWORDS, notify__doc__}, - { "_listen_fds", (PyCFunction) listen_fds, METH_VARARGS | METH_KEYWORDS, listen_fds__doc__}, - { "_is_fifo", is_fifo, METH_VARARGS, is_fifo__doc__}, - { "_is_mq", is_mq, METH_VARARGS, is_mq__doc__}, - { "_is_socket", is_socket, METH_VARARGS, is_socket__doc__}, - { "_is_socket_inet", is_socket_inet, METH_VARARGS, is_socket_inet__doc__}, - { "_is_socket_unix", is_socket_unix, METH_VARARGS, is_socket_unix__doc__}, - { NULL, NULL, 0, NULL } /* Sentinel */ -}; - -#if PY_MAJOR_VERSION < 3 - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC init_daemon(void) { - PyObject *m; - - m = Py_InitModule3("_daemon", methods, module__doc__); - if (m == NULL) - return; - - PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START); - PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); -} -REENABLE_WARNING; - -#else - -static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "_daemon", /* name of module */ - module__doc__, /* module documentation, may be NULL */ - 0, /* size of per-interpreter state of the module */ - methods -}; - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC PyInit__daemon(void) { - PyObject *m; - - m = PyModule_Create(&module); - if (m == NULL) - return NULL; - - if (PyModule_AddIntConstant(m, "LISTEN_FDS_START", SD_LISTEN_FDS_START) || - PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { - Py_DECREF(m); - return NULL; - } - - return m; -} -REENABLE_WARNING; - -#endif diff --git a/src/python-systemd/_journal.c b/src/python-systemd/_journal.c deleted file mode 100644 index 456e4a2796..0000000000 --- a/src/python-systemd/_journal.c +++ /dev/null @@ -1,157 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2012 David Strauss <david@davidstrauss.net> - - 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 <Python.h> - -#include <alloca.h> -#include "util.h" - -#define SD_JOURNAL_SUPPRESS_LOCATION -#include "systemd/sd-journal.h" - -PyDoc_STRVAR(journal_sendv__doc__, - "sendv('FIELD=value', 'FIELD=value', ...) -> None\n\n" - "Send an entry to the journal." -); - -static PyObject *journal_sendv(PyObject *self, PyObject *args) { - struct iovec *iov = NULL; - int argc; - int i, r; - PyObject *ret = NULL; - PyObject **encoded; - - /* Allocate an array for the argument strings */ - argc = PyTuple_Size(args); - encoded = alloca0(argc * sizeof(PyObject*)); - - /* Allocate sufficient iovector space for the arguments. */ - iov = alloca(argc * sizeof(struct iovec)); - - /* Iterate through the Python arguments and fill the iovector. */ - for (i = 0; i < argc; ++i) { - PyObject *item = PyTuple_GetItem(args, i); - char *stritem; - Py_ssize_t length; - - if (PyUnicode_Check(item)) { - encoded[i] = PyUnicode_AsEncodedString(item, "utf-8", "strict"); - if (encoded[i] == NULL) - goto out; - item = encoded[i]; - } - if (PyBytes_AsStringAndSize(item, &stritem, &length)) - goto out; - - iov[i].iov_base = stritem; - iov[i].iov_len = length; - } - - /* Send the iovector to the journal. */ - r = sd_journal_sendv(iov, argc); - if (r < 0) { - errno = -r; - PyErr_SetFromErrno(PyExc_IOError); - goto out; - } - - /* End with success. */ - Py_INCREF(Py_None); - ret = Py_None; - -out: - for (i = 0; i < argc; ++i) - Py_XDECREF(encoded[i]); - - return ret; -} - -PyDoc_STRVAR(journal_stream_fd__doc__, - "stream_fd(identifier, priority, level_prefix) -> fd\n\n" - "Open a stream to journal by calling sd_journal_stream_fd(3)." -); - -static PyObject* journal_stream_fd(PyObject *self, PyObject *args) { - const char* identifier; - int priority, level_prefix; - int fd; - - if (!PyArg_ParseTuple(args, "sii:stream_fd", - &identifier, &priority, &level_prefix)) - return NULL; - - fd = sd_journal_stream_fd(identifier, priority, level_prefix); - if (fd < 0) { - errno = -fd; - return PyErr_SetFromErrno(PyExc_IOError); - } - - return PyLong_FromLong(fd); -} - -static PyMethodDef methods[] = { - { "sendv", journal_sendv, METH_VARARGS, journal_sendv__doc__ }, - { "stream_fd", journal_stream_fd, METH_VARARGS, journal_stream_fd__doc__ }, - { NULL, NULL, 0, NULL } /* Sentinel */ -}; - -#if PY_MAJOR_VERSION < 3 - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC init_journal(void) { - PyObject *m; - - m = Py_InitModule("_journal", methods); - if (m == NULL) - return; - - PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); -} -REENABLE_WARNING; - -#else - -static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "_journal", /* name of module */ - NULL, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module */ - methods -}; - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC PyInit__journal(void) { - PyObject *m; - - m = PyModule_Create(&module); - if (m == NULL) - return NULL; - - if (PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { - Py_DECREF(m); - return NULL; - } - - return m; -} -REENABLE_WARNING; - -#endif diff --git a/src/python-systemd/_reader.c b/src/python-systemd/_reader.c deleted file mode 100644 index 3a561269a7..0000000000 --- a/src/python-systemd/_reader.c +++ /dev/null @@ -1,1106 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Steven Hiscocks, Zbigniew JÄ™drzejewski-Szmek - - 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 <Python.h> -#include <structmember.h> -#include <datetime.h> -#include <time.h> -#include <stdio.h> - -#include "systemd/sd-journal.h" - -#include "pyutil.h" -#include "macro.h" -#include "util.h" -#include "strv.h" -#include "build.h" - -typedef struct { - PyObject_HEAD - sd_journal *j; -} Reader; -static PyTypeObject ReaderType; - -PyDoc_STRVAR(module__doc__, - "Class to reads the systemd journal similar to journalctl."); - - -#if PY_MAJOR_VERSION >= 3 -static PyTypeObject MonotonicType; - -PyDoc_STRVAR(MonotonicType__doc__, - "A tuple of (timestamp, bootid) for holding monotonic timestamps"); - -static PyStructSequence_Field MonotonicType_fields[] = { - {(char*) "timestamp", (char*) "Time"}, - {(char*) "bootid", (char*) "Unique identifier of the boot"}, - {} /* Sentinel */ -}; - -static PyStructSequence_Desc Monotonic_desc = { - (char*) "journal.Monotonic", - MonotonicType__doc__, - MonotonicType_fields, - 2, -}; -#endif - -/** - * Convert a Python sequence object into a strv (char**), and - * None into a NULL pointer. - */ -static int strv_converter(PyObject* obj, void *_result) { - char ***result = _result; - Py_ssize_t i, len; - - assert(result); - - if (!obj) - return 0; - - if (obj == Py_None) { - *result = NULL; - return 1; - } - - if (!PySequence_Check(obj)) - return 0; - - len = PySequence_Length(obj); - *result = new0(char*, len + 1); - if (!*result) { - set_error(-ENOMEM, NULL, NULL); - return 0; - } - - for (i = 0; i < len; i++) { - PyObject *item; -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 - int r; - PyObject *bytes; -#endif - char *s, *s2; - - item = PySequence_ITEM(obj, i); -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 - r = PyUnicode_FSConverter(item, &bytes); - if (r == 0) - goto cleanup; - - s = PyBytes_AsString(bytes); -#else - s = PyString_AsString(item); -#endif - if (!s) - goto cleanup; - - s2 = strdup(s); - if (!s2) - log_oom(); - - (*result)[i] = s2; - } - - return 1; - -cleanup: - strv_free(*result); - *result = NULL; - - return 0; -} - -static void Reader_dealloc(Reader* self) { - sd_journal_close(self->j); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -PyDoc_STRVAR(Reader__doc__, - "_Reader([flags | path | files]) -> ...\n\n" - "_Reader allows filtering and retrieval of Journal entries.\n" - "Note: this is a low-level interface, and probably not what you\n" - "want, use systemd.journal.Reader instead.\n\n" - "Argument `flags` sets open flags of the journal, which can be one\n" - "of, or ORed combination of constants: LOCAL_ONLY (default) opens\n" - "journal on local machine only; RUNTIME_ONLY opens only\n" - "volatile journal files; and SYSTEM opens journal files of\n" - "system services and the kernel, and CURRENT_USER opens files\n" - "of the current user.\n\n" - "Argument `path` is the directory of journal files.\n" - "Argument `files` is a list of files. Note that\n" - "`flags`, `path`, and `files` are exclusive.\n\n" - "_Reader implements the context manager protocol: the journal\n" - "will be closed when exiting the block."); -static int Reader_init(Reader *self, PyObject *args, PyObject *keywds) { - int flags = 0, r; - char *path = NULL; - char **files = NULL; - - static const char* const kwlist[] = {"flags", "path", "files", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "|izO&:__init__", (char**) kwlist, - &flags, &path, strv_converter, &files)) - return -1; - - if (!!flags + !!path + !!files > 1) { - PyErr_SetString(PyExc_ValueError, "cannot use more than one of flags, path, and files"); - return -1; - } - - if (!flags) - flags = SD_JOURNAL_LOCAL_ONLY; - - Py_BEGIN_ALLOW_THREADS - if (path) - r = sd_journal_open_directory(&self->j, path, 0); - else if (files) - r = sd_journal_open_files(&self->j, (const char**) files, 0); - else - r = sd_journal_open(&self->j, flags); - Py_END_ALLOW_THREADS - - return set_error(r, path, "Invalid flags or path"); -} - -PyDoc_STRVAR(Reader_fileno__doc__, - "fileno() -> int\n\n" - "Get a file descriptor to poll for changes in the journal.\n" - "This method invokes sd_journal_get_fd().\n" - "See man:sd_journal_get_fd(3)."); -static PyObject* Reader_fileno(Reader *self, PyObject *args) { - int fd; - - fd = sd_journal_get_fd(self->j); - set_error(fd, NULL, NULL); - if (fd < 0) - return NULL; - return long_FromLong(fd); -} - -PyDoc_STRVAR(Reader_reliable_fd__doc__, - "reliable_fd() -> bool\n\n" - "Returns True iff the journal can be polled reliably.\n" - "This method invokes sd_journal_reliable_fd().\n" - "See man:sd_journal_reliable_fd(3)."); -static PyObject* Reader_reliable_fd(Reader *self, PyObject *args) { - int r; - - r = sd_journal_reliable_fd(self->j); - if (set_error(r, NULL, NULL) < 0) - return NULL; - return PyBool_FromLong(r); -} - -PyDoc_STRVAR(Reader_get_events__doc__, - "get_events() -> int\n\n" - "Returns a mask of poll() events to wait for on the file\n" - "descriptor returned by .fileno().\n\n" - "See man:sd_journal_get_events(3) for further discussion."); -static PyObject* Reader_get_events(Reader *self, PyObject *args) { - int r; - - r = sd_journal_get_events(self->j); - if (set_error(r, NULL, NULL) < 0) - return NULL; - return long_FromLong(r); -} - -PyDoc_STRVAR(Reader_get_timeout__doc__, - "get_timeout() -> int or None\n\n" - "Returns a timeout value for usage in poll(), the time since the\n" - "epoch of clock_gettime(2) in microseconds, or None if no timeout\n" - "is necessary.\n\n" - "The return value must be converted to a relative timeout in\n" - "milliseconds if it is to be used as an argument for poll().\n" - "See man:sd_journal_get_timeout(3) for further discussion."); -static PyObject* Reader_get_timeout(Reader *self, PyObject *args) { - int r; - uint64_t t; - - r = sd_journal_get_timeout(self->j, &t); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - if (t == (uint64_t) -1) - Py_RETURN_NONE; - - assert_cc(sizeof(unsigned long long) == sizeof(t)); - return PyLong_FromUnsignedLongLong(t); -} - -PyDoc_STRVAR(Reader_get_timeout_ms__doc__, - "get_timeout_ms() -> int\n\n" - "Returns a timeout value suitable for usage in poll(), the value\n" - "returned by .get_timeout() converted to relative ms, or -1 if\n" - "no timeout is necessary."); -static PyObject* Reader_get_timeout_ms(Reader *self, PyObject *args) { - int r; - uint64_t t; - - r = sd_journal_get_timeout(self->j, &t); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return absolute_timeout(t); -} - -PyDoc_STRVAR(Reader_close__doc__, - "close() -> None\n\n" - "Free resources allocated by this Reader object.\n" - "This method invokes sd_journal_close().\n" - "See man:sd_journal_close(3)."); -static PyObject* Reader_close(Reader *self, PyObject *args) { - assert(self); - assert(!args); - - sd_journal_close(self->j); - self->j = NULL; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_get_usage__doc__, - "get_usage() -> int\n\n" - "Returns the total disk space currently used by journal\n" - "files (in bytes). If `SD_JOURNAL_LOCAL_ONLY` was\n" - "passed when opening the journal this value will only reflect\n" - "the size of journal files of the local host, otherwise\n" - "of all hosts.\n\n" - "This method invokes sd_journal_get_usage().\n" - "See man:sd_journal_get_usage(3)."); -static PyObject* Reader_get_usage(Reader *self, PyObject *args) { - int r; - uint64_t bytes; - - r = sd_journal_get_usage(self->j, &bytes); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - assert_cc(sizeof(unsigned long long) == sizeof(bytes)); - return PyLong_FromUnsignedLongLong(bytes); -} - -PyDoc_STRVAR(Reader___enter____doc__, - "__enter__() -> self\n\n" - "Part of the context manager protocol.\n" - "Returns self.\n"); -static PyObject* Reader___enter__(PyObject *self, PyObject *args) { - assert(self); - assert(!args); - - Py_INCREF(self); - return self; -} - -PyDoc_STRVAR(Reader___exit____doc__, - "__exit__(type, value, traceback) -> None\n\n" - "Part of the context manager protocol.\n" - "Closes the journal.\n"); -static PyObject* Reader___exit__(Reader *self, PyObject *args) { - return Reader_close(self, NULL); -} - -PyDoc_STRVAR(Reader_next__doc__, - "next([skip]) -> bool\n\n" - "Go to the next log entry. Optional skip value means to go to\n" - "the `skip`\\-th log entry.\n" - "Returns False if at end of file, True otherwise."); -static PyObject* Reader_next(Reader *self, PyObject *args) { - int64_t skip = 1LL; - int r; - - if (!PyArg_ParseTuple(args, "|L:next", &skip)) - return NULL; - - if (skip == 0LL) { - PyErr_SetString(PyExc_ValueError, "skip must be nonzero"); - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - if (skip == 1LL) - r = sd_journal_next(self->j); - else if (skip == -1LL) - r = sd_journal_previous(self->j); - else if (skip > 1LL) - r = sd_journal_next_skip(self->j, skip); - else if (skip < -1LL) - r = sd_journal_previous_skip(self->j, -skip); - else - assert_not_reached("should not be here"); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - return PyBool_FromLong(r); -} - -PyDoc_STRVAR(Reader_previous__doc__, - "previous([skip]) -> bool\n\n" - "Go to the previous log entry. Optional skip value means to \n" - "go to the `skip`\\-th previous log entry.\n" - "Returns False if at start of file, True otherwise."); -static PyObject* Reader_previous(Reader *self, PyObject *args) { - int64_t skip = 1LL; - if (!PyArg_ParseTuple(args, "|L:previous", &skip)) - return NULL; - - return PyObject_CallMethod((PyObject *)self, (char*) "_next", - (char*) "L", -skip); -} - -static int extract(const char* msg, size_t msg_len, - PyObject **key, PyObject **value) { - PyObject *k = NULL, *v; - const char *delim_ptr; - - delim_ptr = memchr(msg, '=', msg_len); - if (!delim_ptr) { - PyErr_SetString(PyExc_OSError, - "journal gave us a field without '='"); - return -1; - } - - if (key) { - k = unicode_FromStringAndSize(msg, delim_ptr - (const char*) msg); - if (!k) - return -1; - } - - if (value) { - v = PyBytes_FromStringAndSize(delim_ptr + 1, - (const char*) msg + msg_len - (delim_ptr + 1)); - if (!v) { - Py_XDECREF(k); - return -1; - } - - *value = v; - } - - if (key) - *key = k; - - return 0; -} - -PyDoc_STRVAR(Reader_get__doc__, - "get(str) -> str\n\n" - "Return data associated with this key in current log entry.\n" - "Throws KeyError is the data is not available."); -static PyObject* Reader_get(Reader *self, PyObject *args) { - const char* field; - const void* msg; - size_t msg_len; - PyObject *value; - int r; - - assert(self); - assert(args); - - if (!PyArg_ParseTuple(args, "s:get", &field)) - return NULL; - - r = sd_journal_get_data(self->j, field, &msg, &msg_len); - if (r == -ENOENT) { - PyErr_SetString(PyExc_KeyError, field); - return NULL; - } - if (set_error(r, NULL, "field name is not valid") < 0) - return NULL; - - r = extract(msg, msg_len, NULL, &value); - if (r < 0) - return NULL; - return value; -} - -PyDoc_STRVAR(Reader_get_all__doc__, - "_get_all() -> dict\n\n" - "Return dictionary of the current log entry."); -static PyObject* Reader_get_all(Reader *self, PyObject *args) { - PyObject *dict; - const void *msg; - size_t msg_len; - int r; - - dict = PyDict_New(); - if (!dict) - return NULL; - - SD_JOURNAL_FOREACH_DATA(self->j, msg, msg_len) { - _cleanup_Py_DECREF_ PyObject *key = NULL, *value = NULL; - - r = extract(msg, msg_len, &key, &value); - if (r < 0) - goto error; - - if (PyDict_Contains(dict, key)) { - PyObject *cur_value = PyDict_GetItem(dict, key); - - if (PyList_CheckExact(cur_value)) { - r = PyList_Append(cur_value, value); - if (r < 0) - goto error; - } else { - _cleanup_Py_DECREF_ PyObject *tmp_list = PyList_New(0); - if (!tmp_list) - goto error; - - r = PyList_Append(tmp_list, cur_value); - if (r < 0) - goto error; - - r = PyList_Append(tmp_list, value); - if (r < 0) - goto error; - - r = PyDict_SetItem(dict, key, tmp_list); - if (r < 0) - goto error; - } - } else { - r = PyDict_SetItem(dict, key, value); - if (r < 0) - goto error; - } - } - - return dict; - -error: - Py_DECREF(dict); - return NULL; -} - -PyDoc_STRVAR(Reader_get_realtime__doc__, - "get_realtime() -> int\n\n" - "Return the realtime timestamp for the current journal entry\n" - "in microseconds.\n\n" - "Wraps sd_journal_get_realtime_usec().\n" - "See man:sd_journal_get_realtime_usec(3)."); -static PyObject* Reader_get_realtime(Reader *self, PyObject *args) { - uint64_t timestamp; - int r; - - assert(self); - assert(!args); - - r = sd_journal_get_realtime_usec(self->j, ×tamp); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - assert_cc(sizeof(unsigned long long) == sizeof(timestamp)); - return PyLong_FromUnsignedLongLong(timestamp); -} - -PyDoc_STRVAR(Reader_get_monotonic__doc__, - "get_monotonic() -> (timestamp, bootid)\n\n" - "Return the monotonic timestamp for the current journal entry\n" - "as a tuple of time in microseconds and bootid.\n\n" - "Wraps sd_journal_get_monotonic_usec().\n" - "See man:sd_journal_get_monotonic_usec(3)."); -static PyObject* Reader_get_monotonic(Reader *self, PyObject *args) { - uint64_t timestamp; - sd_id128_t id; - PyObject *monotonic, *bootid, *tuple; - int r; - - assert(self); - assert(!args); - - r = sd_journal_get_monotonic_usec(self->j, ×tamp, &id); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - assert_cc(sizeof(unsigned long long) == sizeof(timestamp)); - monotonic = PyLong_FromUnsignedLongLong(timestamp); - bootid = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes)); -#if PY_MAJOR_VERSION >= 3 - tuple = PyStructSequence_New(&MonotonicType); -#else - tuple = PyTuple_New(2); -#endif - if (!monotonic || !bootid || !tuple) { - Py_XDECREF(monotonic); - Py_XDECREF(bootid); - Py_XDECREF(tuple); - return NULL; - } - -#if PY_MAJOR_VERSION >= 3 - PyStructSequence_SET_ITEM(tuple, 0, monotonic); - PyStructSequence_SET_ITEM(tuple, 1, bootid); -#else - PyTuple_SET_ITEM(tuple, 0, monotonic); - PyTuple_SET_ITEM(tuple, 1, bootid); -#endif - - return tuple; -} - -PyDoc_STRVAR(Reader_add_match__doc__, - "add_match(match) -> None\n\n" - "Add a match to filter journal log entries. All matches of different\n" - "fields are combined with logical AND, and matches of the same field\n" - "are automatically combined with logical OR.\n" - "Match is a string of the form \"FIELD=value\"."); -static PyObject* Reader_add_match(Reader *self, PyObject *args, PyObject *keywds) { - char *match; - int match_len, r; - if (!PyArg_ParseTuple(args, "s#:add_match", &match, &match_len)) - return NULL; - - r = sd_journal_add_match(self->j, match, match_len); - if (set_error(r, NULL, "Invalid match") < 0) - return NULL; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_add_disjunction__doc__, - "add_disjunction() -> None\n\n" - "Inserts a logical OR between matches added since previous\n" - "add_disjunction() or add_conjunction() and the next\n" - "add_disjunction() or add_conjunction().\n\n" - "See man:sd_journal_add_disjunction(3) for explanation."); -static PyObject* Reader_add_disjunction(Reader *self, PyObject *args) { - int r; - r = sd_journal_add_disjunction(self->j); - if (set_error(r, NULL, NULL) < 0) - return NULL; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_add_conjunction__doc__, - "add_conjunction() -> None\n\n" - "Inserts a logical AND between matches added since previous\n" - "add_disjunction() or add_conjunction() and the next\n" - "add_disjunction() or add_conjunction().\n\n" - "See man:sd_journal_add_disjunction(3) for explanation."); -static PyObject* Reader_add_conjunction(Reader *self, PyObject *args) { - int r; - r = sd_journal_add_conjunction(self->j); - if (set_error(r, NULL, NULL) < 0) - return NULL; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_flush_matches__doc__, - "flush_matches() -> None\n\n" - "Clear all current match filters."); -static PyObject* Reader_flush_matches(Reader *self, PyObject *args) { - sd_journal_flush_matches(self->j); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_seek_head__doc__, - "seek_head() -> None\n\n" - "Jump to the beginning of the journal.\n" - "This method invokes sd_journal_seek_head().\n" - "See man:sd_journal_seek_head(3)."); -static PyObject* Reader_seek_head(Reader *self, PyObject *args) { - int r; - Py_BEGIN_ALLOW_THREADS - r = sd_journal_seek_head(self->j); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_seek_tail__doc__, - "seek_tail() -> None\n\n" - "Jump to the end of the journal.\n" - "This method invokes sd_journal_seek_tail().\n" - "See man:sd_journal_seek_tail(3)."); -static PyObject* Reader_seek_tail(Reader *self, PyObject *args) { - int r; - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_seek_tail(self->j); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_seek_realtime__doc__, - "seek_realtime(realtime) -> None\n\n" - "Seek to nearest matching journal entry to `realtime`. Argument\n" - "`realtime` in specified in seconds."); -static PyObject* Reader_seek_realtime(Reader *self, PyObject *args) { - uint64_t timestamp; - int r; - - if (!PyArg_ParseTuple(args, "K:seek_realtime", ×tamp)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_seek_realtime_usec(self->j, timestamp); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_seek_monotonic__doc__, - "seek_monotonic(monotonic[, bootid]) -> None\n\n" - "Seek to nearest matching journal entry to `monotonic`. Argument\n" - "`monotonic` is an timestamp from boot in microseconds.\n" - "Argument `bootid` is a string representing which boot the\n" - "monotonic time is reference to. Defaults to current bootid."); -static PyObject* Reader_seek_monotonic(Reader *self, PyObject *args) { - char *bootid = NULL; - uint64_t timestamp; - sd_id128_t id; - int r; - - if (!PyArg_ParseTuple(args, "K|z:seek_monotonic", ×tamp, &bootid)) - return NULL; - - if (bootid) { - r = sd_id128_from_string(bootid, &id); - if (set_error(r, NULL, "Invalid bootid") < 0) - return NULL; - } else { - Py_BEGIN_ALLOW_THREADS - r = sd_id128_get_boot(&id); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_seek_monotonic_usec(self->j, id, timestamp); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - - Py_RETURN_NONE; -} - - -PyDoc_STRVAR(Reader_process__doc__, - "process() -> state change (integer)\n\n" - "Process events and reset the readable state of the file\n" - "descriptor returned by .fileno().\n\n" - "Will return constants: NOP if no change; APPEND if new\n" - "entries have been added to the end of the journal; and\n" - "INVALIDATE if journal files have been added or removed.\n\n" - "See man:sd_journal_process(3) for further discussion."); -static PyObject* Reader_process(Reader *self, PyObject *args) { - int r; - - assert(!args); - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_process(self->j); - Py_END_ALLOW_THREADS - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return long_FromLong(r); -} - -PyDoc_STRVAR(Reader_wait__doc__, - "wait([timeout]) -> state change (integer)\n\n" - "Wait for a change in the journal. Argument `timeout` specifies\n" - "the maximum number of microseconds to wait before returning\n" - "regardless of wheter the journal has changed. If `timeout` is -1,\n" - "then block forever.\n\n" - "Will return constants: NOP if no change; APPEND if new\n" - "entries have been added to the end of the journal; and\n" - "INVALIDATE if journal files have been added or removed.\n\n" - "See man:sd_journal_wait(3) for further discussion."); -static PyObject* Reader_wait(Reader *self, PyObject *args) { - int r; - int64_t timeout; - - if (!PyArg_ParseTuple(args, "|L:wait", &timeout)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_wait(self->j, timeout); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return long_FromLong(r); -} - -PyDoc_STRVAR(Reader_seek_cursor__doc__, - "seek_cursor(cursor) -> None\n\n" - "Seek to journal entry by given unique reference `cursor`."); -static PyObject* Reader_seek_cursor(Reader *self, PyObject *args) { - const char *cursor; - int r; - - if (!PyArg_ParseTuple(args, "s:seek_cursor", &cursor)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_seek_cursor(self->j, cursor); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, "Invalid cursor") < 0) - return NULL; - - Py_RETURN_NONE; -} - -PyDoc_STRVAR(Reader_get_cursor__doc__, - "get_cursor() -> str\n\n" - "Return a cursor string for the current journal entry.\n\n" - "Wraps sd_journal_get_cursor(). See man:sd_journal_get_cursor(3)."); -static PyObject* Reader_get_cursor(Reader *self, PyObject *args) { - _cleanup_free_ char *cursor = NULL; - int r; - - assert(self); - assert(!args); - - r = sd_journal_get_cursor(self->j, &cursor); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return unicode_FromString(cursor); -} - -PyDoc_STRVAR(Reader_test_cursor__doc__, - "test_cursor(str) -> bool\n\n" - "Test whether the cursor string matches current journal entry.\n\n" - "Wraps sd_journal_test_cursor(). See man:sd_journal_test_cursor(3)."); -static PyObject* Reader_test_cursor(Reader *self, PyObject *args) { - const char *cursor; - int r; - - assert(self); - assert(args); - - if (!PyArg_ParseTuple(args, "s:test_cursor", &cursor)) - return NULL; - - r = sd_journal_test_cursor(self->j, cursor); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return PyBool_FromLong(r); -} - -PyDoc_STRVAR(Reader_query_unique__doc__, - "query_unique(field) -> a set of values\n\n" - "Return a set of unique values appearing in journal for the\n" - "given `field`. Note this does not respect any journal matches."); -static PyObject* Reader_query_unique(Reader *self, PyObject *args) { - char *query; - int r; - const void *uniq; - size_t uniq_len; - PyObject *value_set, *key, *value; - - if (!PyArg_ParseTuple(args, "s:query_unique", &query)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_query_unique(self->j, query); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, "Invalid field name") < 0) - return NULL; - - value_set = PySet_New(0); - key = unicode_FromString(query); - - SD_JOURNAL_FOREACH_UNIQUE(self->j, uniq, uniq_len) { - const char *delim_ptr; - - delim_ptr = memchr(uniq, '=', uniq_len); - value = PyBytes_FromStringAndSize( - delim_ptr + 1, - (const char*) uniq + uniq_len - (delim_ptr + 1)); - PySet_Add(value_set, value); - Py_DECREF(value); - } - - Py_DECREF(key); - return value_set; -} - -PyDoc_STRVAR(Reader_get_catalog__doc__, - "get_catalog() -> str\n\n" - "Retrieve a message catalog entry for the current journal entry.\n" - "Will throw IndexError if the entry has no MESSAGE_ID\n" - "and KeyError is the id is specified, but hasn't been found\n" - "in the catalog.\n\n" - "Wraps man:sd_journal_get_catalog(3)."); -static PyObject* Reader_get_catalog(Reader *self, PyObject *args) { - int r; - _cleanup_free_ char *msg = NULL; - - assert(self); - assert(!args); - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_get_catalog(self->j, &msg); - Py_END_ALLOW_THREADS - - if (r == -ENOENT) { - const void* mid; - size_t mid_len; - - r = sd_journal_get_data(self->j, "MESSAGE_ID", &mid, &mid_len); - if (r == 0) { - const size_t l = sizeof("MESSAGE_ID"); - assert(mid_len > l); - PyErr_Format(PyExc_KeyError, "%.*s", (int) (mid_len - l), - (const char*) mid + l); - } else if (r == -ENOENT) - PyErr_SetString(PyExc_IndexError, "no MESSAGE_ID field"); - else - set_error(r, NULL, NULL); - return NULL; - } - - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return unicode_FromString(msg); -} - -PyDoc_STRVAR(get_catalog__doc__, - "get_catalog(id128) -> str\n\n" - "Retrieve a message catalog entry for the given id.\n" - "Wraps man:sd_journal_get_catalog_for_message_id(3)."); -static PyObject* get_catalog(PyObject *self, PyObject *args) { - int r; - char *id_ = NULL; - sd_id128_t id; - _cleanup_free_ char *msg = NULL; - - assert(args); - - if (!PyArg_ParseTuple(args, "z:get_catalog", &id_)) - return NULL; - - r = sd_id128_from_string(id_, &id); - if (set_error(r, NULL, "Invalid id128") < 0) - return NULL; - - Py_BEGIN_ALLOW_THREADS - r = sd_journal_get_catalog_for_message_id(id, &msg); - Py_END_ALLOW_THREADS - - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return unicode_FromString(msg); -} - -PyDoc_STRVAR(data_threshold__doc__, - "Threshold for field size truncation in bytes.\n\n" - "Fields longer than this will be truncated to the threshold size.\n" - "Defaults to 64Kb."); - -static PyObject* Reader_get_data_threshold(Reader *self, void *closure) { - size_t cvalue; - int r; - - r = sd_journal_get_data_threshold(self->j, &cvalue); - if (set_error(r, NULL, NULL) < 0) - return NULL; - - return long_FromSize_t(cvalue); -} - -static int Reader_set_data_threshold(Reader *self, PyObject *value, void *closure) { - int r; - - if (value == NULL) { - PyErr_SetString(PyExc_AttributeError, "Cannot delete data threshold"); - return -1; - } - - if (!long_Check(value)){ - PyErr_SetString(PyExc_TypeError, "Data threshold must be an int"); - return -1; - } - - r = sd_journal_set_data_threshold(self->j, (size_t) long_AsLong(value)); - return set_error(r, NULL, NULL); -} - -PyDoc_STRVAR(closed__doc__, - "True iff journal is closed"); -static PyObject* Reader_get_closed(Reader *self, void *closure) { - return PyBool_FromLong(self->j == NULL); -} - -static PyGetSetDef Reader_getsetters[] = { - { (char*) "data_threshold", - (getter) Reader_get_data_threshold, - (setter) Reader_set_data_threshold, - (char*) data_threshold__doc__, - NULL }, - { (char*) "closed", - (getter) Reader_get_closed, - NULL, - (char*) closed__doc__, - NULL }, - {} /* Sentinel */ -}; - -static PyMethodDef Reader_methods[] = { - {"fileno", (PyCFunction) Reader_fileno, METH_NOARGS, Reader_fileno__doc__}, - {"reliable_fd", (PyCFunction) Reader_reliable_fd, METH_NOARGS, Reader_reliable_fd__doc__}, - {"get_events", (PyCFunction) Reader_get_events, METH_NOARGS, Reader_get_events__doc__}, - {"get_timeout", (PyCFunction) Reader_get_timeout, METH_NOARGS, Reader_get_timeout__doc__}, - {"get_timeout_ms", (PyCFunction) Reader_get_timeout_ms, METH_NOARGS, Reader_get_timeout_ms__doc__}, - {"close", (PyCFunction) Reader_close, METH_NOARGS, Reader_close__doc__}, - {"get_usage", (PyCFunction) Reader_get_usage, METH_NOARGS, Reader_get_usage__doc__}, - {"__enter__", (PyCFunction) Reader___enter__, METH_NOARGS, Reader___enter____doc__}, - {"__exit__", (PyCFunction) Reader___exit__, METH_VARARGS, Reader___exit____doc__}, - {"_next", (PyCFunction) Reader_next, METH_VARARGS, Reader_next__doc__}, - {"_previous", (PyCFunction) Reader_previous, METH_VARARGS, Reader_previous__doc__}, - {"_get", (PyCFunction) Reader_get, METH_VARARGS, Reader_get__doc__}, - {"_get_all", (PyCFunction) Reader_get_all, METH_NOARGS, Reader_get_all__doc__}, - {"_get_realtime", (PyCFunction) Reader_get_realtime, METH_NOARGS, Reader_get_realtime__doc__}, - {"_get_monotonic", (PyCFunction) Reader_get_monotonic, METH_NOARGS, Reader_get_monotonic__doc__}, - {"add_match", (PyCFunction) Reader_add_match, METH_VARARGS|METH_KEYWORDS, Reader_add_match__doc__}, - {"add_disjunction", (PyCFunction) Reader_add_disjunction, METH_NOARGS, Reader_add_disjunction__doc__}, - {"add_conjunction", (PyCFunction) Reader_add_conjunction, METH_NOARGS, Reader_add_conjunction__doc__}, - {"flush_matches", (PyCFunction) Reader_flush_matches, METH_NOARGS, Reader_flush_matches__doc__}, - {"seek_head", (PyCFunction) Reader_seek_head, METH_NOARGS, Reader_seek_head__doc__}, - {"seek_tail", (PyCFunction) Reader_seek_tail, METH_NOARGS, Reader_seek_tail__doc__}, - {"seek_realtime", (PyCFunction) Reader_seek_realtime, METH_VARARGS, Reader_seek_realtime__doc__}, - {"seek_monotonic", (PyCFunction) Reader_seek_monotonic, METH_VARARGS, Reader_seek_monotonic__doc__}, - {"process", (PyCFunction) Reader_process, METH_NOARGS, Reader_process__doc__}, - {"wait", (PyCFunction) Reader_wait, METH_VARARGS, Reader_wait__doc__}, - {"seek_cursor", (PyCFunction) Reader_seek_cursor, METH_VARARGS, Reader_seek_cursor__doc__}, - {"_get_cursor", (PyCFunction) Reader_get_cursor, METH_NOARGS, Reader_get_cursor__doc__}, - {"test_cursor", (PyCFunction) Reader_test_cursor, METH_VARARGS, Reader_test_cursor__doc__}, - {"query_unique", (PyCFunction) Reader_query_unique, METH_VARARGS, Reader_query_unique__doc__}, - {"get_catalog", (PyCFunction) Reader_get_catalog, METH_NOARGS, Reader_get_catalog__doc__}, - {} /* Sentinel */ -}; - -static PyTypeObject ReaderType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "_reader._Reader", - .tp_basicsize = sizeof(Reader), - .tp_dealloc = (destructor) Reader_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = Reader__doc__, - .tp_methods = Reader_methods, - .tp_getset = Reader_getsetters, - .tp_init = (initproc) Reader_init, - .tp_new = PyType_GenericNew, -}; - -static PyMethodDef methods[] = { - { "_get_catalog", get_catalog, METH_VARARGS, get_catalog__doc__}, - {} /* Sentinel */ -}; - -#if PY_MAJOR_VERSION >= 3 -static PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "_reader", - module__doc__, - -1, - methods, -}; -#endif - -#if PY_MAJOR_VERSION >= 3 -static bool initialized = false; -#endif - -DISABLE_WARNING_MISSING_PROTOTYPES; - -PyMODINIT_FUNC -#if PY_MAJOR_VERSION >= 3 -PyInit__reader(void) -#else -init_reader(void) -#endif -{ - PyObject* m; - - PyDateTime_IMPORT; - - if (PyType_Ready(&ReaderType) < 0) -#if PY_MAJOR_VERSION >= 3 - return NULL; -#else - return; -#endif - -#if PY_MAJOR_VERSION >= 3 - m = PyModule_Create(&module); - if (m == NULL) - return NULL; - - if (!initialized) { - PyStructSequence_InitType(&MonotonicType, &Monotonic_desc); - initialized = true; - } -#else - m = Py_InitModule3("_reader", methods, module__doc__); - if (m == NULL) - return; -#endif - - Py_INCREF(&ReaderType); -#if PY_MAJOR_VERSION >= 3 - Py_INCREF(&MonotonicType); -#endif - if (PyModule_AddObject(m, "_Reader", (PyObject *) &ReaderType) || -#if PY_MAJOR_VERSION >= 3 - PyModule_AddObject(m, "Monotonic", (PyObject*) &MonotonicType) || -#endif - PyModule_AddIntConstant(m, "NOP", SD_JOURNAL_NOP) || - PyModule_AddIntConstant(m, "APPEND", SD_JOURNAL_APPEND) || - PyModule_AddIntConstant(m, "INVALIDATE", SD_JOURNAL_INVALIDATE) || - PyModule_AddIntConstant(m, "LOCAL_ONLY", SD_JOURNAL_LOCAL_ONLY) || - PyModule_AddIntConstant(m, "RUNTIME_ONLY", SD_JOURNAL_RUNTIME_ONLY) || - PyModule_AddIntConstant(m, "SYSTEM", SD_JOURNAL_SYSTEM) || - PyModule_AddIntConstant(m, "SYSTEM_ONLY", SD_JOURNAL_SYSTEM_ONLY) || - PyModule_AddIntConstant(m, "CURRENT_USER", SD_JOURNAL_CURRENT_USER) || - PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { -#if PY_MAJOR_VERSION >= 3 - Py_DECREF(m); - return NULL; -#endif - } - -#if PY_MAJOR_VERSION >= 3 - return m; -#endif -} - -REENABLE_WARNING; diff --git a/src/python-systemd/daemon.py b/src/python-systemd/daemon.py deleted file mode 100644 index 82011ca606..0000000000 --- a/src/python-systemd/daemon.py +++ /dev/null @@ -1,55 +0,0 @@ -from ._daemon import (__version__, - booted, - notify, - _listen_fds, - _is_fifo, - _is_socket, - _is_socket_inet, - _is_socket_unix, - _is_mq, - LISTEN_FDS_START) -from socket import AF_UNSPEC as _AF_UNSPEC - -def _convert_fileobj(fileobj): - try: - return fileobj.fileno() - except AttributeError: - return fileobj - -def is_fifo(fileobj, path=None): - fd = _convert_fileobj(fileobj) - return _is_fifo(fd, path) - -def is_socket(fileobj, family=_AF_UNSPEC, type=0, listening=-1): - fd = _convert_fileobj(fileobj) - return _is_socket(fd, family, type, listening) - -def is_socket_inet(fileobj, family=_AF_UNSPEC, type=0, listening=-1, port=0): - fd = _convert_fileobj(fileobj) - return _is_socket_inet(fd, family, type, listening, port) - -def is_socket_unix(fileobj, type=0, listening=-1, path=None): - fd = _convert_fileobj(fileobj) - return _is_socket_unix(fd, type, listening, path) - -def is_mq(fileobj, path=None): - fd = _convert_fileobj(fileobj) - return _is_mq(fd, path) - -def listen_fds(unset_environment=True): - """Return a list of socket activated descriptors - - Example:: - - (in primary window) - $ systemd-activate -l 2000 python3 -c \\ - 'from systemd.daemon import listen_fds; print(listen_fds())' - (in another window) - $ telnet localhost 2000 - (in primary window) - ... - Execing python3 (...) - [3] - """ - num = _listen_fds(unset_environment) - return list(range(LISTEN_FDS_START, LISTEN_FDS_START + num)) diff --git a/src/python-systemd/docs/.gitignore b/src/python-systemd/docs/.gitignore deleted file mode 100644 index b06a965e6a..0000000000 --- a/src/python-systemd/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!layout.html diff --git a/src/python-systemd/docs/conf.py b/src/python-systemd/docs/conf.py deleted file mode 100644 index 1919170bb1..0000000000 --- a/src/python-systemd/docs/conf.py +++ /dev/null @@ -1,279 +0,0 @@ -# -*- coding: utf-8 -*- -# -# python-systemd documentation build configuration file, created by -# sphinx-quickstart on Sat Feb 9 13:49:42 2013. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.viewcode'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['.'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'python-systemd' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# "<project> v<release> documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['.'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -html_show_sourcelink = False - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a <link> tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'python-systemddoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'python-systemd.tex', u'python-systemd Documentation', - None, 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'python-systemd', u'python-systemd Documentation', - [], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'python-systemd', u'python-systemd Documentation', - u'David Strauss, Zbigniew JÄ™drzejewski-Szmek, Marti Raudsepp, Steven Hiscocks', 'python-systemd', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - - -# -- Options for Epub output --------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = u'python-systemd' -epub_author = u'David Strauss, Zbigniew JÄ™drzejewski-Szmek, Marti Raudsepp, Steven Hiscocks' -epub_publisher = u'David Strauss, Zbigniew JÄ™drzejewski-Szmek, Marti Raudsepp, Steven Hiscocks' -epub_copyright = u'2013, David Strauss, Zbigniew JÄ™drzejewski-Szmek, Marti Raudsepp, Steven Hiscocks' - -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -#epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/src/python-systemd/docs/daemon.rst b/src/python-systemd/docs/daemon.rst deleted file mode 100644 index 0ad11edaf3..0000000000 --- a/src/python-systemd/docs/daemon.rst +++ /dev/null @@ -1,18 +0,0 @@ -`systemd.daemon` module -======================= - -.. automodule:: systemd.daemon - :members: - :undoc-members: - :inherited-members: - - .. autoattribute:: systemd.daemon.LISTEN_FDS_START - - .. autofunction:: _listen_fds - .. autofunction:: _is_fifo - .. autofunction:: _is_socket - .. autofunction:: _is_socket_unix - .. autofunction:: _is_socket_inet - .. autofunction:: _is_mq - .. autofunction:: notify - .. autofunction:: booted diff --git a/src/python-systemd/docs/default.css b/src/python-systemd/docs/default.css deleted file mode 100644 index 7c097d64a2..0000000000 --- a/src/python-systemd/docs/default.css +++ /dev/null @@ -1,196 +0,0 @@ -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 230px; -} - -div.body { - background-color: #ffffff; - color: #000000; - padding: 0 20px 30px 20px; -} - -div.footer { - color: #ffffff; - width: 100%; - padding: 9px 0 9px 0; - text-align: center; - font-size: 75%; -} - -div.footer a { - color: #ffffff; - text-decoration: underline; -} - -div.related { - background-color: #133f52; - line-height: 30px; - color: #ffffff; -} - -div.related a { - color: #ffffff; -} - -div.sphinxsidebar { - background-color: #dddddd; -} - -div.sphinxsidebar p.topless { - margin: 5px 10px 10px 10px; -} - -div.sphinxsidebar ul { - margin: 10px; - padding: 0; -} - -div.sphinxsidebar input { - border: 1px solid #000000; - font-family: sans-serif; - font-size: 1em; -} - - - -/* -- hyperlink styles ------------------------------------------------------ */ - -a { - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - - - -/* -- body styles ----------------------------------------------------------- */ - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Trebuchet MS', sans-serif; - background-color: #f2f2f2; - font-weight: normal; - color: #20435c; - border-bottom: 1px solid #ccc; - margin: 20px -20px 10px -20px; - padding: 3px 0 3px 10px; -} - -div.body h1 { margin-top: 0; font-size: 200%; } -div.body h2 { font-size: 160%; } -div.body h3 { font-size: 140%; } -div.body h4 { font-size: 120%; } -div.body h5 { font-size: 110%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #c60f0f; - font-size: 0.8em; - padding: 0 4px 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - background-color: #c60f0f; - color: white; -} - -div.body p, div.body dd, div.body li { - text-align: justify; - line-height: 130%; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -div.admonition p { - margin-bottom: 5px; -} - -div.admonition pre { - margin-bottom: 5px; -} - -div.admonition ul, div.admonition ol { - margin-bottom: 5px; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre { - padding: 5px; - background-color: #eeffcc; - color: #333333; - line-height: 120%; - border: 1px solid #ac9; - border-left: none; - border-right: none; -} - -tt { - background-color: #ecf0f3; - padding: 0 1px 0 1px; - font-size: 0.95em; -} - -th { - background-color: #ede; -} - -.warning tt { - background: #efc2c2; -} - -.note tt { - background: #d6d6d6; -} - -.viewcode-back { - font-family: sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} diff --git a/src/python-systemd/docs/id128.rst b/src/python-systemd/docs/id128.rst deleted file mode 100644 index 89c37f3470..0000000000 --- a/src/python-systemd/docs/id128.rst +++ /dev/null @@ -1,40 +0,0 @@ -`systemd.id128` module -====================== - -.. automodule:: systemd.id128 - :members: - :undoc-members: - :inherited-members: - - .. autoattribute:: systemd.id128.SD_MESSAGE_COREDUMP - .. autoattribute:: systemd.id128.SD_MESSAGE_FORWARD_SYSLOG_MISSED - .. autoattribute:: systemd.id128.SD_MESSAGE_HIBERNATE_KEY - .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_DROPPED - .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_MISSED - .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_START - .. autoattribute:: systemd.id128.SD_MESSAGE_JOURNAL_STOP - .. autoattribute:: systemd.id128.SD_MESSAGE_LID_CLOSED - .. autoattribute:: systemd.id128.SD_MESSAGE_LID_OPENED - .. autoattribute:: systemd.id128.SD_MESSAGE_OVERMOUNTING - .. autoattribute:: systemd.id128.SD_MESSAGE_POWER_KEY - .. autoattribute:: systemd.id128.SD_MESSAGE_SEAT_START - .. autoattribute:: systemd.id128.SD_MESSAGE_SEAT_STOP - .. autoattribute:: systemd.id128.SD_MESSAGE_SESSION_START - .. autoattribute:: systemd.id128.SD_MESSAGE_SESSION_STOP - .. autoattribute:: systemd.id128.SD_MESSAGE_SHUTDOWN - .. autoattribute:: systemd.id128.SD_MESSAGE_SLEEP_START - .. autoattribute:: systemd.id128.SD_MESSAGE_SLEEP_STOP - .. autoattribute:: systemd.id128.SD_MESSAGE_SPAWN_FAILED - .. autoattribute:: systemd.id128.SD_MESSAGE_STARTUP_FINISHED - .. autoattribute:: systemd.id128.SD_MESSAGE_SUSPEND_KEY - .. autoattribute:: systemd.id128.SD_MESSAGE_TIMEZONE_CHANGE - .. autoattribute:: systemd.id128.SD_MESSAGE_TIME_CHANGE - .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_FAILED - .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_RELOADED - .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_RELOADING - .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STARTED - .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STARTING - .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STOPPED - .. autoattribute:: systemd.id128.SD_MESSAGE_UNIT_STOPPING - .. autoattribute:: systemd.id128.SD_MESSAGE_CONFIG_ERROR - .. autoattribute:: systemd.id128.SD_MESSAGE_BOOTCHART diff --git a/src/python-systemd/docs/index.rst b/src/python-systemd/docs/index.rst deleted file mode 100644 index e78d966274..0000000000 --- a/src/python-systemd/docs/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. python-systemd documentation master file, created by - sphinx-quickstart on Sat Feb 9 13:49:42 2013. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to python-systemd's documentation! -========================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - journal - id128 - daemon - login - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/src/python-systemd/docs/journal.rst b/src/python-systemd/docs/journal.rst deleted file mode 100644 index ea74cf85c4..0000000000 --- a/src/python-systemd/docs/journal.rst +++ /dev/null @@ -1,64 +0,0 @@ -`systemd.journal` module -======================== - -.. automodule:: systemd.journal - :members: send, sendv, stream, stream_fd - :undoc-members: - -`JournalHandler` class ----------------------- - -.. autoclass:: JournalHandler - -Accessing the Journal ---------------------- - -.. autoclass:: _Reader - :undoc-members: - :inherited-members: - -.. autoclass:: Reader - :undoc-members: - :inherited-members: - - .. automethod:: __init__ - -.. autofunction:: _get_catalog -.. autofunction:: get_catalog - -.. autoclass:: Monotonic - -.. autoattribute:: systemd.journal.DEFAULT_CONVERTERS - -Example: polling for journal events -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This example shows that journal events can be waited for (using -e.g. `poll`). This makes it easy to integrate Reader in an external -event loop: - - >>> import select - >>> from systemd import journal - >>> j = journal.Reader() - >>> j.seek_tail() - >>> p = select.poll() - >>> p.register(j, j.get_events()) - >>> p.poll() - [(3, 1)] - >>> j.get_next() - - -Journal access types -~~~~~~~~~~~~~~~~~~~~ - -.. autoattribute:: systemd.journal.LOCAL_ONLY -.. autoattribute:: systemd.journal.RUNTIME_ONLY -.. autoattribute:: systemd.journal.SYSTEM -.. autoattribute:: systemd.journal.CURRENT_USER - -Journal event types -~~~~~~~~~~~~~~~~~~~ - -.. autoattribute:: systemd.journal.NOP -.. autoattribute:: systemd.journal.APPEND -.. autoattribute:: systemd.journal.INVALIDATE diff --git a/src/python-systemd/docs/layout.html b/src/python-systemd/docs/layout.html deleted file mode 100644 index 930a6a7afe..0000000000 --- a/src/python-systemd/docs/layout.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "!layout.html" %} - -{% block relbar1 %} - <a href="../man/systemd.index.html">Index </a>· - <a href="../man/systemd.directives.html">Directives </a>· - <a href="index.html">Python </a>· - <span style="float:right">systemd {{release}}</span> - <hr /> -{% endblock %} - -{# remove the lower relbar #} -{% block relbar2 %} {% endblock %} - -{# remove the footer #} -{% block footer %} {% endblock %} diff --git a/src/python-systemd/docs/login.rst b/src/python-systemd/docs/login.rst deleted file mode 100644 index 6b4de64c55..0000000000 --- a/src/python-systemd/docs/login.rst +++ /dev/null @@ -1,28 +0,0 @@ -`systemd.login` module -======================= - -.. automodule:: systemd.login - :members: - -.. autoclass:: Monitor - :undoc-members: - :inherited-members: - -Example: polling for events -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This example shows that session/uid/seat/machine events can be waited -for (using e.g. `poll`). This makes it easy to integrate Monitor in an -external event loop: - - >>> import select - >>> from systemd import login - >>> m = login.Monitor("machine") - >>> p = select.poll() - >>> p.register(m, m.get_events()) - >>> login.machine_names() - [] - >>> p.poll() - [(3, 1)] - >>> login.machine_names() - ['fedora-19.nspawn'] diff --git a/src/python-systemd/id128.c b/src/python-systemd/id128.c deleted file mode 100644 index 5ec7309a54..0000000000 --- a/src/python-systemd/id128.c +++ /dev/null @@ -1,163 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl> - - 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 <Python.h> - -#include "systemd/sd-messages.h" - -#include "pyutil.h" -#include "log.h" -#include "util.h" -#include "macro.h" - -PyDoc_STRVAR(module__doc__, - "Python interface to the libsystemd-id128 library.\n\n" - "Provides SD_MESSAGE_* constants and functions to query and generate\n" - "128-bit unique identifiers." -); - -PyDoc_STRVAR(randomize__doc__, - "randomize() -> UUID\n\n" - "Return a new random 128-bit unique identifier.\n" - "Wraps sd_id128_randomize(3)." -); - -PyDoc_STRVAR(get_machine__doc__, - "get_machine() -> UUID\n\n" - "Return a 128-bit unique identifier for this machine.\n" - "Wraps sd_id128_get_machine(3)." -); - -PyDoc_STRVAR(get_boot__doc__, - "get_boot() -> UUID\n\n" - "Return a 128-bit unique identifier for this boot.\n" - "Wraps sd_id128_get_boot(3)." -); - -static PyObject* make_uuid(sd_id128_t id) { - _cleanup_Py_DECREF_ PyObject - *uuid = NULL, *UUID = NULL, *bytes = NULL, - *args = NULL, *kwargs = NULL; - - uuid = PyImport_ImportModule("uuid"); - if (!uuid) - return NULL; - - UUID = PyObject_GetAttrString(uuid, "UUID"); - bytes = PyBytes_FromStringAndSize((const char*) &id.bytes, sizeof(id.bytes)); - args = Py_BuildValue("()"); - kwargs = PyDict_New(); - if (!UUID || !bytes || !args || !kwargs) - return NULL; - - if (PyDict_SetItemString(kwargs, "bytes", bytes) < 0) - return NULL; - - return PyObject_Call(UUID, args, kwargs); -} - -#define helper(name) \ - static PyObject *name(PyObject *self, PyObject *args) { \ - sd_id128_t id; \ - int r; \ - \ - assert(args == NULL); \ - \ - r = sd_id128_##name(&id); \ - if (r < 0) { \ - errno = -r; \ - return PyErr_SetFromErrno(PyExc_IOError); \ - } \ - \ - return make_uuid(id); \ - } - -helper(randomize) -helper(get_machine) -helper(get_boot) - -static PyMethodDef methods[] = { - { "randomize", randomize, METH_NOARGS, randomize__doc__}, - { "get_machine", get_machine, METH_NOARGS, get_machine__doc__}, - { "get_boot", get_boot, METH_NOARGS, get_boot__doc__}, - { NULL, NULL, 0, NULL } /* Sentinel */ -}; - -static int add_id(PyObject *module, const char* name, sd_id128_t id) { - PyObject *obj; - - obj = make_uuid(id); - if (!obj) - return -1; - - return PyModule_AddObject(module, name, obj); -} - -#if PY_MAJOR_VERSION < 3 - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC initid128(void) { - PyObject *m; - - m = Py_InitModule3("id128", methods, module__doc__); - if (m == NULL) - return; - - /* a series of lines like 'add_id() ;' follow */ -#define JOINER ; -#include "id128-constants.h" -#undef JOINER - PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); -} -REENABLE_WARNING; - -#else - -static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "id128", /* name of module */ - module__doc__, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module */ - methods -}; - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC PyInit_id128(void) { - PyObject *m; - - m = PyModule_Create(&module); - if (m == NULL) - return NULL; - - if ( /* a series of lines like 'add_id() ||' follow */ -#define JOINER || -#include "id128-constants.h" -#undef JOINER - PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { - Py_DECREF(m); - return NULL; - } - - return m; -} -REENABLE_WARNING; - -#endif diff --git a/src/python-systemd/journal.py b/src/python-systemd/journal.py deleted file mode 100644 index dd1f229973..0000000000 --- a/src/python-systemd/journal.py +++ /dev/null @@ -1,548 +0,0 @@ -# -*- Mode: python; coding:utf-8; indent-tabs-mode: nil -*- */ -# -# This file is part of systemd. -# -# Copyright 2012 David Strauss <david@davidstrauss.net> -# Copyright 2012 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl> -# Copyright 2012 Marti Raudsepp <marti@juffo.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/>. - -from __future__ import division - -import sys as _sys -import datetime as _datetime -import uuid as _uuid -import traceback as _traceback -import os as _os -import logging as _logging -if _sys.version_info >= (3,3): - from collections import ChainMap as _ChainMap -from syslog import (LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, - LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG) -from ._journal import __version__, sendv, stream_fd -from ._reader import (_Reader, NOP, APPEND, INVALIDATE, - LOCAL_ONLY, RUNTIME_ONLY, - SYSTEM, SYSTEM_ONLY, CURRENT_USER, - _get_catalog) -from . import id128 as _id128 - -if _sys.version_info >= (3,): - from ._reader import Monotonic -else: - Monotonic = tuple - -def _convert_monotonic(m): - return Monotonic((_datetime.timedelta(microseconds=m[0]), - _uuid.UUID(bytes=m[1]))) - -def _convert_source_monotonic(s): - return _datetime.timedelta(microseconds=int(s)) - -def _convert_realtime(t): - return _datetime.datetime.fromtimestamp(t / 1000000) - -def _convert_timestamp(s): - return _datetime.datetime.fromtimestamp(int(s) / 1000000) - -def _convert_trivial(x): - return x - -if _sys.version_info >= (3,): - def _convert_uuid(s): - return _uuid.UUID(s.decode()) -else: - _convert_uuid = _uuid.UUID - -DEFAULT_CONVERTERS = { - 'MESSAGE_ID': _convert_uuid, - '_MACHINE_ID': _convert_uuid, - '_BOOT_ID': _convert_uuid, - 'PRIORITY': int, - 'LEADER': int, - 'SESSION_ID': int, - 'USERSPACE_USEC': int, - 'INITRD_USEC': int, - 'KERNEL_USEC': int, - '_UID': int, - '_GID': int, - '_PID': int, - 'SYSLOG_FACILITY': int, - 'SYSLOG_PID': int, - '_AUDIT_SESSION': int, - '_AUDIT_LOGINUID': int, - '_SYSTEMD_SESSION': int, - '_SYSTEMD_OWNER_UID': int, - 'CODE_LINE': int, - 'ERRNO': int, - 'EXIT_STATUS': int, - '_SOURCE_REALTIME_TIMESTAMP': _convert_timestamp, - '__REALTIME_TIMESTAMP': _convert_realtime, - '_SOURCE_MONOTONIC_TIMESTAMP': _convert_source_monotonic, - '__MONOTONIC_TIMESTAMP': _convert_monotonic, - '__CURSOR': _convert_trivial, - 'COREDUMP': bytes, - 'COREDUMP_PID': int, - 'COREDUMP_UID': int, - 'COREDUMP_GID': int, - 'COREDUMP_SESSION': int, - 'COREDUMP_SIGNAL': int, - 'COREDUMP_TIMESTAMP': _convert_timestamp, -} - -_IDENT_LETTER = set('ABCDEFGHIJKLMNOPQRTSUVWXYZ_') - -def _valid_field_name(s): - return not (set(s) - _IDENT_LETTER) - -class Reader(_Reader): - """Reader allows the access and filtering of systemd journal - entries. Note that in order to access the system journal, a - non-root user must be in the `systemd-journal` group. - - Example usage to print out all informational or higher level - messages for systemd-udevd for this boot: - - >>> j = journal.Reader() - >>> j.this_boot() - >>> j.log_level(journal.LOG_INFO) - >>> j.add_match(_SYSTEMD_UNIT="systemd-udevd.service") - >>> for entry in j: - ... print(entry['MESSAGE']) - - See systemd.journal-fields(7) for more info on typical fields - found in the journal. - """ - def __init__(self, flags=0, path=None, files=None, converters=None): - """Create an instance of Reader, which allows filtering and - return of journal entries. - - Argument `flags` sets open flags of the journal, which can be one - of, or ORed combination of constants: LOCAL_ONLY (default) opens - journal on local machine only; RUNTIME_ONLY opens only - volatile journal files; and SYSTEM_ONLY opens only - journal files of system services and the kernel. - - Argument `path` is the directory of journal files. Note that - `flags` and `path` are exclusive. - - Argument `converters` is a dictionary which updates the - DEFAULT_CONVERTERS to convert journal field values. Field - names are used as keys into this dictionary. The values must - be single argument functions, which take a `bytes` object and - return a converted value. When there's no entry for a field - name, then the default UTF-8 decoding will be attempted. If - the conversion fails with a ValueError, unconverted bytes - object will be returned. (Note that ValueEror is a superclass - of UnicodeDecodeError). - - Reader implements the context manager protocol: the journal - will be closed when exiting the block. - """ - super(Reader, self).__init__(flags, path, files) - if _sys.version_info >= (3,3): - self.converters = _ChainMap() - if converters is not None: - self.converters.maps.append(converters) - self.converters.maps.append(DEFAULT_CONVERTERS) - else: - self.converters = DEFAULT_CONVERTERS.copy() - if converters is not None: - self.converters.update(converters) - - def _convert_field(self, key, value): - """Convert value using self.converters[key] - - If `key` is not present in self.converters, a standard unicode - decoding will be attempted. If the conversion (either - key-specific or the default one) fails with a ValueError, the - original bytes object will be returned. - """ - convert = self.converters.get(key, bytes.decode) - try: - return convert(value) - except ValueError: - # Leave in default bytes - return value - - def _convert_entry(self, entry): - """Convert entire journal entry utilising _covert_field""" - result = {} - for key, value in entry.items(): - if isinstance(value, list): - result[key] = [self._convert_field(key, val) for val in value] - else: - result[key] = self._convert_field(key, value) - return result - - def __iter__(self): - """Part of iterator protocol. - Returns self. - """ - return self - - def __next__(self): - """Part of iterator protocol. - Returns self.get_next() or raises StopIteration. - """ - ans = self.get_next() - if ans: - return ans - else: - raise StopIteration() - - if _sys.version_info < (3,): - next = __next__ - - def add_match(self, *args, **kwargs): - """Add one or more matches to the filter journal log entries. - All matches of different field are combined in a logical AND, - and matches of the same field are automatically combined in a - logical OR. - Matches can be passed as strings of form "FIELD=value", or - keyword arguments FIELD="value". - """ - args = list(args) - args.extend(_make_line(key, val) for key, val in kwargs.items()) - for arg in args: - super(Reader, self).add_match(arg) - - def get_next(self, skip=1): - """Return the next log entry as a mapping type, currently - a standard dictionary of fields. - - Optional skip value will return the `skip`\-th log entry. - - Entries will be processed with converters specified during - Reader creation. - """ - if super(Reader, self)._next(skip): - entry = super(Reader, self)._get_all() - if entry: - entry['__REALTIME_TIMESTAMP'] = self._get_realtime() - entry['__MONOTONIC_TIMESTAMP'] = self._get_monotonic() - entry['__CURSOR'] = self._get_cursor() - return self._convert_entry(entry) - return dict() - - def get_previous(self, skip=1): - """Return the previous log entry as a mapping type, - currently a standard dictionary of fields. - - Optional skip value will return the -`skip`\-th log entry. - - Entries will be processed with converters specified during - Reader creation. - - Equivalent to get_next(-skip). - """ - return self.get_next(-skip) - - def query_unique(self, field): - """Return unique values appearing in the journal for given `field`. - - Note this does not respect any journal matches. - - Entries will be processed with converters specified during - Reader creation. - """ - return set(self._convert_field(field, value) - for value in super(Reader, self).query_unique(field)) - - def wait(self, timeout=None): - """Wait for a change in the journal. `timeout` is the maximum - time in seconds to wait, or None, to wait forever. - - Returns one of NOP (no change), APPEND (new entries have been - added to the end of the journal), or INVALIDATE (journal files - have been added or removed). - """ - us = -1 if timeout is None else int(timeout * 1000000) - return super(Reader, self).wait(us) - - def seek_realtime(self, realtime): - """Seek to a matching journal entry nearest to `realtime` time. - - Argument `realtime` must be either an integer unix timestamp - or datetime.datetime instance. - """ - if isinstance(realtime, _datetime.datetime): - realtime = float(realtime.strftime("%s.%f")) * 1000000 - return super(Reader, self).seek_realtime(int(realtime)) - - def seek_monotonic(self, monotonic, bootid=None): - """Seek to a matching journal entry nearest to `monotonic` time. - - Argument `monotonic` is a timestamp from boot in either - seconds or a datetime.timedelta instance. Argument `bootid` - is a string or UUID representing which boot the monotonic time - is reference to. Defaults to current bootid. - """ - if isinstance(monotonic, _datetime.timedelta): - monotonic = monotonic.totalseconds() - monotonic = int(monotonic * 1000000) - if isinstance(bootid, _uuid.UUID): - bootid = bootid.hex - return super(Reader, self).seek_monotonic(monotonic, bootid) - - def log_level(self, level): - """Set maximum log `level` by setting matches for PRIORITY. - """ - if 0 <= level <= 7: - for i in range(level+1): - self.add_match(PRIORITY="%d" % i) - else: - raise ValueError("Log level must be 0 <= level <= 7") - - def messageid_match(self, messageid): - """Add match for log entries with specified `messageid`. - - `messageid` can be string of hexadicimal digits or a UUID - instance. Standard message IDs can be found in systemd.id128. - - Equivalent to add_match(MESSAGE_ID=`messageid`). - """ - if isinstance(messageid, _uuid.UUID): - messageid = messageid.hex - self.add_match(MESSAGE_ID=messageid) - - def this_boot(self, bootid=None): - """Add match for _BOOT_ID equal to current boot ID or the specified boot ID. - - If specified, bootid should be either a UUID or a 32 digit hex number. - - Equivalent to add_match(_BOOT_ID='bootid'). - """ - if bootid is None: - bootid = _id128.get_boot().hex - else: - bootid = getattr(bootid, 'hex', bootid) - self.add_match(_BOOT_ID=bootid) - - def this_machine(self, machineid=None): - """Add match for _MACHINE_ID equal to the ID of this machine. - - If specified, machineid should be either a UUID or a 32 digit hex number. - - Equivalent to add_match(_MACHINE_ID='machineid'). - """ - if machineid is None: - machineid = _id128.get_machine().hex - else: - machineid = getattr(machineid, 'hex', machineid) - self.add_match(_MACHINE_ID=machineid) - - -def get_catalog(mid): - if isinstance(mid, _uuid.UUID): - mid = mid.hex - return _get_catalog(mid) - -def _make_line(field, value): - if isinstance(value, bytes): - return field.encode('utf-8') + b'=' + value - elif isinstance(value, int): - return field + '=' + str(value) - else: - return field + '=' + value - -def send(MESSAGE, MESSAGE_ID=None, - CODE_FILE=None, CODE_LINE=None, CODE_FUNC=None, - **kwargs): - r"""Send a message to the journal. - - >>> journal.send('Hello world') - >>> journal.send('Hello, again, world', FIELD2='Greetings!') - >>> journal.send('Binary message', BINARY=b'\xde\xad\xbe\xef') - - Value of the MESSAGE argument will be used for the MESSAGE= - field. MESSAGE must be a string and will be sent as UTF-8 to - the journal. - - MESSAGE_ID can be given to uniquely identify the type of - message. It must be a string or a uuid.UUID object. - - CODE_LINE, CODE_FILE, and CODE_FUNC can be specified to - identify the caller. Unless at least on of the three is given, - values are extracted from the stack frame of the caller of - send(). CODE_FILE and CODE_FUNC must be strings, CODE_LINE - must be an integer. - - Additional fields for the journal entry can only be specified - as keyword arguments. The payload can be either a string or - bytes. A string will be sent as UTF-8, and bytes will be sent - as-is to the journal. - - Other useful fields include PRIORITY, SYSLOG_FACILITY, - SYSLOG_IDENTIFIER, SYSLOG_PID. - """ - - args = ['MESSAGE=' + MESSAGE] - - if MESSAGE_ID is not None: - id = getattr(MESSAGE_ID, 'hex', MESSAGE_ID) - args.append('MESSAGE_ID=' + id) - - if CODE_LINE == CODE_FILE == CODE_FUNC == None: - CODE_FILE, CODE_LINE, CODE_FUNC = \ - _traceback.extract_stack(limit=2)[0][:3] - if CODE_FILE is not None: - args.append('CODE_FILE=' + CODE_FILE) - if CODE_LINE is not None: - args.append('CODE_LINE={:d}'.format(CODE_LINE)) - if CODE_FUNC is not None: - args.append('CODE_FUNC=' + CODE_FUNC) - - args.extend(_make_line(key, val) for key, val in kwargs.items()) - return sendv(*args) - -def stream(identifier, priority=LOG_DEBUG, level_prefix=False): - r"""Return a file object wrapping a stream to journal. - - Log messages written to this file as simple newline sepearted - text strings are written to the journal. - - The file will be line buffered, so messages are actually sent - after a newline character is written. - - >>> stream = journal.stream('myapp') - >>> stream - <open file '<fdopen>', mode 'w' at 0x...> - >>> stream.write('message...\n') - - will produce the following message in the journal:: - - PRIORITY=7 - SYSLOG_IDENTIFIER=myapp - MESSAGE=message... - - Using the interface with print might be more convinient: - - >>> from __future__ import print_function - >>> print('message...', file=stream) - - priority is the syslog priority, one of `LOG_EMERG`, - `LOG_ALERT`, `LOG_CRIT`, `LOG_ERR`, `LOG_WARNING`, - `LOG_NOTICE`, `LOG_INFO`, `LOG_DEBUG`. - - level_prefix is a boolean. If true, kernel-style log priority - level prefixes (such as '<1>') are interpreted. See - sd-daemon(3) for more information. - """ - - fd = stream_fd(identifier, priority, level_prefix) - return _os.fdopen(fd, 'w', 1) - -class JournalHandler(_logging.Handler): - """Journal handler class for the Python logging framework. - - Please see the Python logging module documentation for an - overview: http://docs.python.org/library/logging.html. - - To create a custom logger whose messages go only to journal: - - >>> log = logging.getLogger('custom_logger_name') - >>> log.propagate = False - >>> log.addHandler(journal.JournalHandler()) - >>> log.warn("Some message: %s", detail) - - Note that by default, message levels `INFO` and `DEBUG` are - ignored by the logging framework. To enable those log levels: - - >>> log.setLevel(logging.DEBUG) - - To redirect all logging messages to journal regardless of where - they come from, attach it to the root logger: - - >>> logging.root.addHandler(journal.JournalHandler()) - - For more complex configurations when using `dictConfig` or - `fileConfig`, specify `systemd.journal.JournalHandler` as the - handler class. Only standard handler configuration options - are supported: `level`, `formatter`, `filters`. - - To attach journal MESSAGE_ID, an extra field is supported: - - >>> import uuid - >>> mid = uuid.UUID('0123456789ABCDEF0123456789ABCDEF') - >>> log.warn("Message with ID", extra={'MESSAGE_ID': mid}) - - Fields to be attached to all messages sent through this - handler can be specified as keyword arguments. This probably - makes sense only for SYSLOG_IDENTIFIER and similar fields - which are constant for the whole program: - - >>> journal.JournalHandler(SYSLOG_IDENTIFIER='my-cool-app') - - The following journal fields will be sent: - `MESSAGE`, `PRIORITY`, `THREAD_NAME`, `CODE_FILE`, `CODE_LINE`, - `CODE_FUNC`, `LOGGER` (name as supplied to getLogger call), - `MESSAGE_ID` (optional, see above), `SYSLOG_IDENTIFIER` (defaults - to sys.argv[0]). - """ - - def __init__(self, level=_logging.NOTSET, **kwargs): - super(JournalHandler, self).__init__(level) - - for name in kwargs: - if not _valid_field_name(name): - raise ValueError('Invalid field name: ' + name) - if 'SYSLOG_IDENTIFIER' not in kwargs: - kwargs['SYSLOG_IDENTIFIER'] = _sys.argv[0] - self._extra = kwargs - - def emit(self, record): - """Write record as journal event. - - MESSAGE is taken from the message provided by the - user, and PRIORITY, LOGGER, THREAD_NAME, - CODE_{FILE,LINE,FUNC} fields are appended - automatically. In addition, record.MESSAGE_ID will be - used if present. - """ - try: - msg = self.format(record) - pri = self.mapPriority(record.levelno) - mid = getattr(record, 'MESSAGE_ID', None) - send(msg, - MESSAGE_ID=mid, - PRIORITY=format(pri), - LOGGER=record.name, - THREAD_NAME=record.threadName, - CODE_FILE=record.pathname, - CODE_LINE=record.lineno, - CODE_FUNC=record.funcName, - **self._extra) - except Exception: - self.handleError(record) - - @staticmethod - def mapPriority(levelno): - """Map logging levels to journald priorities. - - Since Python log level numbers are "sparse", we have - to map numbers in between the standard levels too. - """ - if levelno <= _logging.DEBUG: - return LOG_DEBUG - elif levelno <= _logging.INFO: - return LOG_INFO - elif levelno <= _logging.WARNING: - return LOG_WARNING - elif levelno <= _logging.ERROR: - return LOG_ERR - elif levelno <= _logging.CRITICAL: - return LOG_CRIT - else: - return LOG_ALERT diff --git a/src/python-systemd/login.c b/src/python-systemd/login.c deleted file mode 100644 index e844f5fc69..0000000000 --- a/src/python-systemd/login.c +++ /dev/null @@ -1,376 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl> - - 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/>. -***/ - -#define PY_SSIZE_T_CLEAN -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wredundant-decls" -#include <Python.h> -#pragma GCC diagnostic pop - -#include "systemd/sd-login.h" -#include "pyutil.h" -#include "util.h" -#include "strv.h" - -PyDoc_STRVAR(module__doc__, - "Python interface to the libsystemd-login library." -); - -#define helper(name) \ -static PyObject* name(PyObject *self, PyObject *args) { \ - _cleanup_strv_free_ char **list = NULL; \ - int r; \ - PyObject *ans; \ - \ - assert(args == NULL); \ - \ - r = sd_get_##name(&list); \ - if (r < 0) { \ - errno = -r; \ - return PyErr_SetFromErrno(PyExc_IOError); \ - } \ - \ - ans = PyList_New(r); \ - if (!ans) \ - return NULL; \ - \ - for (r--; r >= 0; r--) { \ - PyObject *s = unicode_FromString(list[r]); \ - if (!s) { \ - Py_DECREF(ans); \ - return NULL; \ - } \ - \ - PyList_SetItem(ans, r, s); \ - } \ - \ - return ans; \ -} - -helper(seats) -helper(sessions) -helper(machine_names) -#undef helper - -static PyObject* uids(PyObject *self, PyObject *args) { - _cleanup_free_ uid_t *list = NULL; - int r; - PyObject *ans; - - assert(args == NULL); - - r = sd_get_uids(&list); - if (r < 0) { - errno = -r; - return PyErr_SetFromErrno(PyExc_IOError); - } - - ans = PyList_New(r); - if (!ans) - return NULL; - - for (r--; r >= 0; r--) { - PyObject *s = long_FromLong(list[r]); - if (!s) { - Py_DECREF(ans); - return NULL; - } - - PyList_SetItem(ans, r, s); - } - - return ans; -} - -PyDoc_STRVAR(seats__doc__, - "seats() -> list\n\n" - "Returns a list of currently available local seats.\n" - "Wraps sd_get_seats(3)." -); - -PyDoc_STRVAR(sessions__doc__, - "sessions() -> list\n\n" - "Returns a list of current login sessions.\n" - "Wraps sd_get_sessions(3)." -); - -PyDoc_STRVAR(machine_names__doc__, - "machine_names() -> list\n\n" - "Returns a list of currently running virtual machines\n" - "and containers on the system.\n" - "Wraps sd_get_machine_names(3)." -); - -PyDoc_STRVAR(uids__doc__, - "uids() -> list\n\n" - "Returns a list of uids of users who currently have login sessions.\n" - "Wraps sd_get_uids(3)." -); - -static PyMethodDef methods[] = { - { "seats", seats, METH_NOARGS, seats__doc__}, - { "sessions", sessions, METH_NOARGS, sessions__doc__}, - { "machine_names", machine_names, METH_NOARGS, machine_names__doc__}, - { "uids", uids, METH_NOARGS, uids__doc__}, - {} /* Sentinel */ -}; - - -typedef struct { - PyObject_HEAD - sd_login_monitor *monitor; -} Monitor; -static PyTypeObject MonitorType; - -static void Monitor_dealloc(Monitor* self) { - sd_login_monitor_unref(self->monitor); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -PyDoc_STRVAR(Monitor__doc__, - "Monitor([category]) -> ...\n\n" - "Monitor may be used to monitor login sessions, users, seats,\n" - "and virtual machines/containers. Monitor provides a file\n" - "descriptor which can be integrated in an external event loop.\n" - "See man:sd_login_monitor_new(3) for the details about what\n" - "can be monitored."); -static int Monitor_init(Monitor *self, PyObject *args, PyObject *keywds) { - const char *category = NULL; - int r; - - static const char* const kwlist[] = {"category", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "|z:__init__", (char**) kwlist, - &category)) - return -1; - - Py_BEGIN_ALLOW_THREADS - r = sd_login_monitor_new(category, &self->monitor); - Py_END_ALLOW_THREADS - - return set_error(r, NULL, "Invalid category"); -} - - -PyDoc_STRVAR(Monitor_fileno__doc__, - "fileno() -> int\n\n" - "Get a file descriptor to poll for events.\n" - "This method wraps sd_login_monitor_get_fd(3)."); -static PyObject* Monitor_fileno(Monitor *self, PyObject *args) { - int fd = sd_login_monitor_get_fd(self->monitor); - set_error(fd, NULL, NULL); - if (fd < 0) - return NULL; - return long_FromLong(fd); -} - - -PyDoc_STRVAR(Monitor_get_events__doc__, - "get_events() -> int\n\n" - "Returns a mask of poll() events to wait for on the file\n" - "descriptor returned by .fileno().\n\n" - "See man:sd_login_monitor_get_events(3) for further discussion."); -static PyObject* Monitor_get_events(Monitor *self, PyObject *args) { - int r = sd_login_monitor_get_events(self->monitor); - set_error(r, NULL, NULL); - if (r < 0) - return NULL; - return long_FromLong(r); -} - - -PyDoc_STRVAR(Monitor_get_timeout__doc__, - "get_timeout() -> int or None\n\n" - "Returns a timeout value for usage in poll(), the time since the\n" - "epoch of clock_gettime(2) in microseconds, or None if no timeout\n" - "is necessary.\n\n" - "The return value must be converted to a relative timeout in\n" - "milliseconds if it is to be used as an argument for poll().\n" - "See man:sd_login_monitor_get_timeout(3) for further discussion."); -static PyObject* Monitor_get_timeout(Monitor *self, PyObject *args) { - int r; - uint64_t t; - - r = sd_login_monitor_get_timeout(self->monitor, &t); - set_error(r, NULL, NULL); - if (r < 0) - return NULL; - - if (t == (uint64_t) -1) - Py_RETURN_NONE; - - assert_cc(sizeof(unsigned long long) == sizeof(t)); - return PyLong_FromUnsignedLongLong(t); -} - - -PyDoc_STRVAR(Monitor_get_timeout_ms__doc__, - "get_timeout_ms() -> int\n\n" - "Returns a timeout value suitable for usage in poll(), the value\n" - "returned by .get_timeout() converted to relative ms, or -1 if\n" - "no timeout is necessary."); -static PyObject* Monitor_get_timeout_ms(Monitor *self, PyObject *args) { - int r; - uint64_t t; - - r = sd_login_monitor_get_timeout(self->monitor, &t); - set_error(r, NULL, NULL); - if (r < 0) - return NULL; - - return absolute_timeout(t); -} - - -PyDoc_STRVAR(Monitor_close__doc__, - "close() -> None\n\n" - "Free resources allocated by this Monitor object.\n" - "This method invokes sd_login_monitor_unref().\n" - "See man:sd_login_monitor_unref(3)."); -static PyObject* Monitor_close(Monitor *self, PyObject *args) { - assert(self); - assert(!args); - - sd_login_monitor_unref(self->monitor); - self->monitor = NULL; - Py_RETURN_NONE; -} - - -PyDoc_STRVAR(Monitor_flush__doc__, - "flush() -> None\n\n" - "Reset the wakeup state of the monitor object.\n" - "This method invokes sd_login_monitor_flush().\n" - "See man:sd_login_monitor_flush(3)."); -static PyObject* Monitor_flush(Monitor *self, PyObject *args) { - assert(self); - assert(!args); - - Py_BEGIN_ALLOW_THREADS - sd_login_monitor_flush(self->monitor); - Py_END_ALLOW_THREADS - Py_RETURN_NONE; -} - - -PyDoc_STRVAR(Monitor___enter____doc__, - "__enter__() -> self\n\n" - "Part of the context manager protocol.\n" - "Returns self.\n"); -static PyObject* Monitor___enter__(PyObject *self, PyObject *args) { - assert(self); - assert(!args); - - Py_INCREF(self); - return self; -} - - -PyDoc_STRVAR(Monitor___exit____doc__, - "__exit__(type, value, traceback) -> None\n\n" - "Part of the context manager protocol.\n" - "Closes the monitor..\n"); -static PyObject* Monitor___exit__(Monitor *self, PyObject *args) { - return Monitor_close(self, args); -} - - -static PyMethodDef Monitor_methods[] = { - {"fileno", (PyCFunction) Monitor_fileno, METH_NOARGS, Monitor_fileno__doc__}, - {"get_events", (PyCFunction) Monitor_get_events, METH_NOARGS, Monitor_get_events__doc__}, - {"get_timeout", (PyCFunction) Monitor_get_timeout, METH_NOARGS, Monitor_get_timeout__doc__}, - {"get_timeout_ms", (PyCFunction) Monitor_get_timeout_ms, METH_NOARGS, Monitor_get_timeout_ms__doc__}, - {"close", (PyCFunction) Monitor_close, METH_NOARGS, Monitor_close__doc__}, - {"flush", (PyCFunction) Monitor_flush, METH_NOARGS, Monitor_flush__doc__}, - {"__enter__", (PyCFunction) Monitor___enter__, METH_NOARGS, Monitor___enter____doc__}, - {"__exit__", (PyCFunction) Monitor___exit__, METH_VARARGS, Monitor___exit____doc__}, - {} /* Sentinel */ -}; - -static PyTypeObject MonitorType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "login.Monitor", - .tp_basicsize = sizeof(Monitor), - .tp_dealloc = (destructor) Monitor_dealloc, - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = Monitor__doc__, - .tp_methods = Monitor_methods, - .tp_init = (initproc) Monitor_init, - .tp_new = PyType_GenericNew, -}; - -#if PY_MAJOR_VERSION < 3 - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC initlogin(void) { - PyObject *m; - - if (PyType_Ready(&MonitorType) < 0) - return; - - m = Py_InitModule3("login", methods, module__doc__); - if (m == NULL) - return; - - PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION); - - Py_INCREF(&MonitorType); - PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType); -} -REENABLE_WARNING; - -#else - -static struct PyModuleDef module = { - PyModuleDef_HEAD_INIT, - "login", /* name of module */ - module__doc__, /* module documentation, may be NULL */ - -1, /* size of per-interpreter state of the module */ - methods -}; - -DISABLE_WARNING_MISSING_PROTOTYPES; -PyMODINIT_FUNC PyInit_login(void) { - PyObject *m; - - if (PyType_Ready(&MonitorType) < 0) - return NULL; - - m = PyModule_Create(&module); - if (m == NULL) - return NULL; - - if (PyModule_AddStringConstant(m, "__version__", PACKAGE_VERSION)) { - Py_DECREF(m); - return NULL; - } - - Py_INCREF(&MonitorType); - if (PyModule_AddObject(m, "Monitor", (PyObject *) &MonitorType)) { - Py_DECREF(&MonitorType); - Py_DECREF(m); - return NULL; - } - - return m; -} -REENABLE_WARNING; - -#endif diff --git a/src/python-systemd/pyutil.c b/src/python-systemd/pyutil.c deleted file mode 100644 index 722c4f5b5f..0000000000 --- a/src/python-systemd/pyutil.c +++ /dev/null @@ -1,80 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl> - - 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 <Python.h> -#include "pyutil.h" - -void cleanup_Py_DECREFp(PyObject **p) { - if (!*p) - return; - - Py_DECREF(*p); -} - -PyObject* absolute_timeout(uint64_t t) { - if (t == (uint64_t) -1) - return PyLong_FromLong(-1); - else { - struct timespec ts; - uint64_t n; - int msec; - - clock_gettime(CLOCK_MONOTONIC, &ts); - n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; - msec = t > n ? (int) ((t - n + 999) / 1000) : 0; - - return PyLong_FromLong(msec); - } -} - -int set_error(int r, const char* path, const char* invalid_message) { - if (r >= 0) - return r; - if (r == -EINVAL && invalid_message) - PyErr_SetString(PyExc_ValueError, invalid_message); - else if (r == -ENOMEM) - PyErr_SetString(PyExc_MemoryError, "Not enough memory"); - else { - errno = -r; - PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); - } - return -1; -} - -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 -int Unicode_FSConverter(PyObject* obj, void *_result) { - PyObject **result = _result; - - assert(result); - - if (!obj) - /* cleanup: we don't return Py_CLEANUP_SUPPORTED, so - * we can assume that it was PyUnicode_FSConverter. */ - return PyUnicode_FSConverter(obj, result); - - if (obj == Py_None) { - *result = NULL; - return 1; - } - - return PyUnicode_FSConverter(obj, result); -} -#endif diff --git a/src/python-systemd/pyutil.h b/src/python-systemd/pyutil.h deleted file mode 100644 index 1477e7bf9c..0000000000 --- a/src/python-systemd/pyutil.h +++ /dev/null @@ -1,54 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2013 Zbigniew JÄ™drzejewski-Szmek <zbyszek@in.waw.pl> - - 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/>. -***/ - -#ifndef Py_TYPE -/* avoid duplication warnings from errors in Python 2.7 headers */ -# include <Python.h> -#endif - -void cleanup_Py_DECREFp(PyObject **p); -PyObject* absolute_timeout(uint64_t t); -int set_error(int r, const char* path, const char* invalid_message); - -#if PY_MAJOR_VERSION >=3 && PY_MINOR_VERSION >= 1 -int Unicode_FSConverter(PyObject* obj, void *_result); -#endif - -#define _cleanup_Py_DECREF_ __attribute__((cleanup(cleanup_Py_DECREFp))) - -#if PY_MAJOR_VERSION >=3 -# define unicode_FromStringAndSize PyUnicode_FromStringAndSize -# define unicode_FromString PyUnicode_FromString -# define long_FromLong PyLong_FromLong -# define long_FromSize_t PyLong_FromSize_t -# define long_Check PyLong_Check -# define long_AsLong PyLong_AsLong -#else -/* Python 3 type naming convention is used */ -# define unicode_FromStringAndSize PyString_FromStringAndSize -# define unicode_FromString PyString_FromString -# define long_FromLong PyInt_FromLong -# define long_FromSize_t PyInt_FromSize_t -# define long_Check PyInt_Check -# define long_AsLong PyInt_AsLong -#endif diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c index 068756cab1..0edba415b6 100644 --- a/src/resolve-host/resolve-host.c +++ b/src/resolve-host/resolve-host.c @@ -89,10 +89,6 @@ static int resolve_host(sd_bus *bus, const char *name) { if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_set_auto_start(req, false); - if (r < 0) - return bus_log_create_error(r); - r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags); if (r < 0) return bus_log_create_error(r); @@ -592,7 +588,7 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char **argv) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; log_parse_environment(); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index bb74b1828e..fa0516f8a0 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -166,10 +166,17 @@ int dns_packet_validate_reply(DnsPacket *p) { if (DNS_PACKET_OPCODE(p) != 0) return -EBADMSG; - /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */ - if (p->protocol == DNS_PROTOCOL_LLMNR && - DNS_PACKET_QDCOUNT(p) != 1) - return -EBADMSG; + switch (p->protocol) { + case DNS_PROTOCOL_LLMNR: + /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */ + if (DNS_PACKET_QDCOUNT(p) != 1) + return -EBADMSG; + + break; + + default: + break; + } return 1; } @@ -192,18 +199,25 @@ int dns_packet_validate_query(DnsPacket *p) { if (DNS_PACKET_TC(p)) return -EBADMSG; - /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */ - if (p->protocol == DNS_PROTOCOL_LLMNR && - DNS_PACKET_QDCOUNT(p) != 1) - return -EBADMSG; + switch (p->protocol) { + case DNS_PROTOCOL_LLMNR: + /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */ + if (DNS_PACKET_QDCOUNT(p) != 1) + return -EBADMSG; - /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */ - if (DNS_PACKET_ANCOUNT(p) > 0) - return -EBADMSG; + /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */ + if (DNS_PACKET_ANCOUNT(p) > 0) + return -EBADMSG; - /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */ - if (DNS_PACKET_NSCOUNT(p) > 0) - return -EBADMSG; + /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */ + if (DNS_PACKET_NSCOUNT(p) > 0) + return -EBADMSG; + + break; + + default: + break; + } return 1; } @@ -691,7 +705,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_uint8(p, rr->rrsig.key_tag, NULL); + r = dns_packet_append_uint16(p, rr->rrsig.key_tag, NULL); if (r < 0) goto fail; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index c5867386c6..bf998aa84e 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -99,10 +99,18 @@ static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) { #define DNS_PACKET_ID(p) DNS_PACKET_HEADER(p)->id #define DNS_PACKET_QR(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 15) & 1) #define DNS_PACKET_OPCODE(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 11) & 15) -#define DNS_PACKET_RCODE(p) (be16toh(DNS_PACKET_HEADER(p)->flags) & 15) +#define DNS_PACKET_AA(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 10) & 1) #define DNS_PACKET_TC(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 9) & 1) -#define DNS_PACKET_C(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 10) & 1) -#define DNS_PACKET_T(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 8) & 1) +#define DNS_PACKET_RD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 8) & 1) +#define DNS_PACKET_RA(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 7) & 1) +#define DNS_PACKET_AD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 5) & 1) +#define DNS_PACKET_CD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 4) & 1) +#define DNS_PACKET_RCODE(p) (be16toh(DNS_PACKET_HEADER(p)->flags) & 15) + +/* LLMNR defines some bits differently */ +#define DNS_PACKET_LLMNR_C(p) DNS_PACKET_AA(p) +#define DNS_PACKET_LLMNR_T(p) DNS_PACKET_RD(p) + #define DNS_PACKET_QDCOUNT(p) be16toh(DNS_PACKET_HEADER(p)->qdcount) #define DNS_PACKET_ANCOUNT(p) be16toh(DNS_PACKET_HEADER(p)->ancount) #define DNS_PACKET_NSCOUNT(p) be16toh(DNS_PACKET_HEADER(p)->nscount) diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index c25ac2216d..25392d21d7 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -28,6 +28,7 @@ #include "random-util.h" #include "hostname-util.h" #include "dns-domain.h" +#include "resolved-llmnr.h" #include "resolved-dns-scope.h" #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC) @@ -180,7 +181,7 @@ int dns_scope_emit(DnsScope *s, DnsPacket *p) { return -EBUSY; family = s->family; - port = 5355; + port = LLMNR_PORT; if (family == AF_INET) { addr.in = LLMNR_MULTICAST_IPV4_ADDRESS; @@ -546,7 +547,7 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { return; } - if (DNS_PACKET_C(p)) { + if (DNS_PACKET_LLMNR_C(p)) { /* Somebody notified us about a possible conflict */ dns_scope_verify_conflicts(s, p); return; @@ -760,10 +761,10 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) { if (DNS_PACKET_RRCOUNT(p) <= 0) return; - if (DNS_PACKET_C(p) != 0) + if (DNS_PACKET_LLMNR_C(p) != 0) return; - if (DNS_PACKET_T(p) != 0) + if (DNS_PACKET_LLMNR_T(p) != 0) return; if (manager_our_packet(scope->manager, p)) diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 214938986d..3f4673df7a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -21,6 +21,7 @@ #include "af-list.h" +#include "resolved-llmnr.h" #include "resolved-dns-transaction.h" #include "random-util.h" @@ -264,7 +265,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { if (r == 0) return -EINVAL; - fd = dns_scope_tcp_socket(t->scope, family, &address, 5355); + fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT); } } else return -EAFNOSUPPORT; @@ -323,7 +324,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { /* Tentative packets are not full responses but still * useful for identifying uniqueness conflicts during * probing. */ - if (DNS_PACKET_T(p)) { + if (DNS_PACKET_LLMNR_T(p)) { dns_transaction_tentative(t, p); return; } diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c new file mode 100644 index 0000000000..8afaf8db6e --- /dev/null +++ b/src/resolve/resolved-llmnr.c @@ -0,0 +1,473 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen <teg@jklm.no> + + 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 <resolv.h> +#include <netinet/in.h> + +#include "resolved-manager.h" +#include "resolved-llmnr.h" + +void manager_llmnr_stop(Manager *m) { + assert(m); + + m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source); + m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd); + + m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source); + m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd); + + m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source); + m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd); + + m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source); + m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd); +} + +int manager_llmnr_start(Manager *m) { + int r; + + assert(m); + + if (m->llmnr_support == SUPPORT_NO) + return 0; + + r = manager_llmnr_ipv4_udp_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + + r = manager_llmnr_ipv4_tcp_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + + if (socket_ipv6_is_supported()) { + r = manager_llmnr_ipv6_udp_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + + r = manager_llmnr_ipv6_tcp_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + } + + return 0; + +eaddrinuse: + log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support."); + m->llmnr_support = SUPPORT_NO; + manager_llmnr_stop(m); + + return 0; +} + +static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + DnsTransaction *t = NULL; + Manager *m = userdata; + DnsScope *scope; + int r; + + r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p); + if (r <= 0) + return r; + + scope = manager_find_scope(m, p); + if (!scope) { + log_warning("Got LLMNR UDP packet on unknown scope. Ignoring."); + return 0; + } + + if (dns_packet_validate_reply(p) > 0) { + log_debug("Got LLMNR reply packet for id %u", DNS_PACKET_ID(p)); + + dns_scope_check_conflicts(scope, p); + + t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); + if (t) + dns_transaction_process_reply(t, p); + + } else if (dns_packet_validate_query(p) > 0) { + log_debug("Got LLMNR query packet for id %u", DNS_PACKET_ID(p)); + + dns_scope_process_query(scope, NULL, p); + } else + log_debug("Invalid LLMNR UDP packet."); + + return 0; +} + +int manager_llmnr_ipv4_udp_fd(Manager *m) { + union sockaddr_union sa = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(LLMNR_PORT), + }; + static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255; + int r; + + assert(m); + + if (m->llmnr_ipv4_udp_fd >= 0) + return m->llmnr_ipv4_udp_fd; + + m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->llmnr_ipv4_udp_fd < 0) + return -errno; + + /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ + r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + /* Disable Don't-Fragment bit in the IP header */ + r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m); + if (r < 0) + goto fail; + + return m->llmnr_ipv4_udp_fd; + +fail: + m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd); + return r; +} + +int manager_llmnr_ipv6_udp_fd(Manager *m) { + union sockaddr_union sa = { + .in6.sin6_family = AF_INET6, + .in6.sin6_port = htobe16(LLMNR_PORT), + }; + static const int one = 1, ttl = 255; + int r; + + assert(m); + + if (m->llmnr_ipv6_udp_fd >= 0) + return m->llmnr_ipv6_udp_fd; + + m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->llmnr_ipv6_udp_fd < 0) + return -errno; + + r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ + r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m); + if (r < 0) { + r = -errno; + goto fail; + } + + return m->llmnr_ipv6_udp_fd; + +fail: + m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd); + return r; +} + +static int on_llmnr_stream_packet(DnsStream *s) { + DnsScope *scope; + + assert(s); + + scope = manager_find_scope(s->manager, s->read_packet); + if (!scope) { + log_warning("Got LLMNR TCP packet on unknown scope. Ignroing."); + return 0; + } + + if (dns_packet_validate_query(s->read_packet) > 0) { + log_debug("Got query packet for id %u", DNS_PACKET_ID(s->read_packet)); + + dns_scope_process_query(scope, s, s->read_packet); + + /* If no reply packet was set, we free the stream */ + if (s->write_packet) + return 0; + } else + log_debug("Invalid LLMNR TCP packet."); + + dns_stream_free(s); + return 0; +} + +static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + DnsStream *stream; + Manager *m = userdata; + int cfd, r; + + cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); + if (cfd < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + return -errno; + } + + r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd); + if (r < 0) { + safe_close(cfd); + return r; + } + + stream->on_packet = on_llmnr_stream_packet; + return 0; +} + +int manager_llmnr_ipv4_tcp_fd(Manager *m) { + union sockaddr_union sa = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(LLMNR_PORT), + }; + static const int one = 1, pmtu = IP_PMTUDISC_DONT; + int r; + + assert(m); + + if (m->llmnr_ipv4_tcp_fd >= 0) + return m->llmnr_ipv4_tcp_fd; + + m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->llmnr_ipv4_tcp_fd < 0) + return -errno; + + /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */ + r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + /* Disable Don't-Fragment bit in the IP header */ + r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m); + if (r < 0) + goto fail; + + return m->llmnr_ipv4_tcp_fd; + +fail: + m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd); + return r; +} + +int manager_llmnr_ipv6_tcp_fd(Manager *m) { + union sockaddr_union sa = { + .in6.sin6_family = AF_INET6, + .in6.sin6_port = htobe16(LLMNR_PORT), + }; + static const int one = 1; + int r; + + assert(m); + + if (m->llmnr_ipv6_tcp_fd >= 0) + return m->llmnr_ipv6_tcp_fd; + + m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->llmnr_ipv6_tcp_fd < 0) + return -errno; + + /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */ + r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m); + if (r < 0) { + r = -errno; + goto fail; + } + + return m->llmnr_ipv6_tcp_fd; + +fail: + m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd); + return r; +} diff --git a/src/resolve/resolved-llmnr.h b/src/resolve/resolved-llmnr.h new file mode 100644 index 0000000000..d489d481e8 --- /dev/null +++ b/src/resolve/resolved-llmnr.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "resolved-manager.h" + +#define LLMNR_PORT 5355 + +int manager_llmnr_ipv4_udp_fd(Manager *m); +int manager_llmnr_ipv6_udp_fd(Manager *m); +int manager_llmnr_ipv4_tcp_fd(Manager *m); +int manager_llmnr_ipv6_tcp_fd(Manager *m); + +void manager_llmnr_stop(Manager *m); +int manager_llmnr_start(Manager *m); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index dee5e61922..6785a2e3c7 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -38,6 +38,7 @@ #include "resolved-conf.h" #include "resolved-bus.h" #include "resolved-manager.h" +#include "resolved-llmnr.h" #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC) @@ -393,66 +394,6 @@ static int manager_watch_hostname(Manager *m) { return 0; } -static void manager_llmnr_stop(Manager *m) { - assert(m); - - m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source); - m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd); - - m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source); - m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd); - - m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source); - m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd); - - m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source); - m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd); -} - -static int manager_llmnr_start(Manager *m) { - int r; - - assert(m); - - if (m->llmnr_support == SUPPORT_NO) - return 0; - - r = manager_llmnr_ipv4_udp_fd(m); - if (r == -EADDRINUSE) - goto eaddrinuse; - if (r < 0) - return r; - - r = manager_llmnr_ipv4_tcp_fd(m); - if (r == -EADDRINUSE) - goto eaddrinuse; - if (r < 0) - return r; - - if (socket_ipv6_is_supported()) { - r = manager_llmnr_ipv6_udp_fd(m); - if (r == -EADDRINUSE) - goto eaddrinuse; - if (r < 0) - return r; - - r = manager_llmnr_ipv6_tcp_fd(m); - if (r == -EADDRINUSE) - goto eaddrinuse; - if (r < 0) - return r; - } - - return 0; - -eaddrinuse: - log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support."); - m->llmnr_support = SUPPORT_NO; - manager_llmnr_stop(m); - - return 0; -} - int manager_new(Manager **ret) { _cleanup_(manager_freep) Manager *m = NULL; int r; @@ -1316,393 +1257,6 @@ uint32_t manager_find_mtu(Manager *m) { return mtu; } -static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - DnsTransaction *t = NULL; - Manager *m = userdata; - DnsScope *scope; - int r; - - r = manager_recv(m, fd, DNS_PROTOCOL_LLMNR, &p); - if (r <= 0) - return r; - - scope = manager_find_scope(m, p); - if (!scope) { - log_warning("Got LLMNR UDP packet on unknown scope. Ignoring."); - return 0; - } - - if (dns_packet_validate_reply(p) > 0) { - log_debug("Got reply packet for id %u", DNS_PACKET_ID(p)); - - dns_scope_check_conflicts(scope, p); - - t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); - if (t) - dns_transaction_process_reply(t, p); - - } else if (dns_packet_validate_query(p) > 0) { - log_debug("Got query packet for id %u", DNS_PACKET_ID(p)); - - dns_scope_process_query(scope, NULL, p); - } else - log_debug("Invalid LLMNR UDP packet."); - - return 0; -} - -int manager_llmnr_ipv4_udp_fd(Manager *m) { - union sockaddr_union sa = { - .in.sin_family = AF_INET, - .in.sin_port = htobe16(5355), - }; - static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255; - int r; - - assert(m); - - if (m->llmnr_ipv4_udp_fd >= 0) - return m->llmnr_ipv4_udp_fd; - - m->llmnr_ipv4_udp_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (m->llmnr_ipv4_udp_fd < 0) - return -errno; - - /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ - r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - /* Disable Don't-Fragment bit in the IP header */ - r = setsockopt(m->llmnr_ipv4_udp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = bind(m->llmnr_ipv4_udp_fd, &sa.sa, sizeof(sa.in)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = sd_event_add_io(m->event, &m->llmnr_ipv4_udp_event_source, m->llmnr_ipv4_udp_fd, EPOLLIN, on_llmnr_packet, m); - if (r < 0) - goto fail; - - return m->llmnr_ipv4_udp_fd; - -fail: - m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd); - return r; -} - -int manager_llmnr_ipv6_udp_fd(Manager *m) { - union sockaddr_union sa = { - .in6.sin6_family = AF_INET6, - .in6.sin6_port = htobe16(5355), - }; - static const int one = 1, ttl = 255; - int r; - - assert(m); - - if (m->llmnr_ipv6_udp_fd >= 0) - return m->llmnr_ipv6_udp_fd; - - m->llmnr_ipv6_udp_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (m->llmnr_ipv6_udp_fd < 0) - return -errno; - - r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); - if (r < 0) { - r = -errno; - goto fail; - } - - /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ - r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_udp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_udp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = bind(m->llmnr_ipv6_udp_fd, &sa.sa, sizeof(sa.in6)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m); - if (r < 0) { - r = -errno; - goto fail; - } - - return m->llmnr_ipv6_udp_fd; - -fail: - m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd); - return r; -} - -static int on_llmnr_stream_packet(DnsStream *s) { - DnsScope *scope; - - assert(s); - - scope = manager_find_scope(s->manager, s->read_packet); - if (!scope) { - log_warning("Got LLMNR TCP packet on unknown scope. Ignroing."); - return 0; - } - - if (dns_packet_validate_query(s->read_packet) > 0) { - log_debug("Got query packet for id %u", DNS_PACKET_ID(s->read_packet)); - - dns_scope_process_query(scope, s, s->read_packet); - - /* If no reply packet was set, we free the stream */ - if (s->write_packet) - return 0; - } else - log_debug("Invalid LLMNR TCP packet."); - - dns_stream_free(s); - return 0; -} - -static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - DnsStream *stream; - Manager *m = userdata; - int cfd, r; - - cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); - if (cfd < 0) { - if (errno == EAGAIN || errno == EINTR) - return 0; - - return -errno; - } - - r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd); - if (r < 0) { - safe_close(cfd); - return r; - } - - stream->on_packet = on_llmnr_stream_packet; - return 0; -} - -int manager_llmnr_ipv4_tcp_fd(Manager *m) { - union sockaddr_union sa = { - .in.sin_family = AF_INET, - .in.sin_port = htobe16(5355), - }; - static const int one = 1, pmtu = IP_PMTUDISC_DONT; - int r; - - assert(m); - - if (m->llmnr_ipv4_tcp_fd >= 0) - return m->llmnr_ipv4_tcp_fd; - - m->llmnr_ipv4_tcp_fd = socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (m->llmnr_ipv4_tcp_fd < 0) - return -errno; - - /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */ - r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_TTL, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - /* Disable Don't-Fragment bit in the IP header */ - r = setsockopt(m->llmnr_ipv4_tcp_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = bind(m->llmnr_ipv4_tcp_fd, &sa.sa, sizeof(sa.in)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = listen(m->llmnr_ipv4_tcp_fd, SOMAXCONN); - if (r < 0) { - r = -errno; - goto fail; - } - - r = sd_event_add_io(m->event, &m->llmnr_ipv4_tcp_event_source, m->llmnr_ipv4_tcp_fd, EPOLLIN, on_llmnr_stream, m); - if (r < 0) - goto fail; - - return m->llmnr_ipv4_tcp_fd; - -fail: - m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd); - return r; -} - -int manager_llmnr_ipv6_tcp_fd(Manager *m) { - union sockaddr_union sa = { - .in6.sin6_family = AF_INET6, - .in6.sin6_port = htobe16(5355), - }; - static const int one = 1; - int r; - - assert(m); - - if (m->llmnr_ipv6_tcp_fd >= 0) - return m->llmnr_ipv6_tcp_fd; - - m->llmnr_ipv6_tcp_fd = socket(AF_INET6, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (m->llmnr_ipv6_tcp_fd < 0) - return -errno; - - /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */ - r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_tcp_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = setsockopt(m->llmnr_ipv6_tcp_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = bind(m->llmnr_ipv6_tcp_fd, &sa.sa, sizeof(sa.in6)); - if (r < 0) { - r = -errno; - goto fail; - } - - r = listen(m->llmnr_ipv6_tcp_fd, SOMAXCONN); - if (r < 0) { - r = -errno; - goto fail; - } - - r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m); - if (r < 0) { - r = -errno; - goto fail; - } - - return m->llmnr_ipv6_tcp_fd; - -fail: - m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd); - return r; -} - int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr) { LinkAddress *a; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 0f4ffad141..4e70a5b500 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -130,10 +130,6 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret); int manager_dns_ipv4_fd(Manager *m); int manager_dns_ipv6_fd(Manager *m); -int manager_llmnr_ipv4_udp_fd(Manager *m); -int manager_llmnr_ipv6_udp_fd(Manager *m); -int manager_llmnr_ipv4_tcp_fd(Manager *m); -int manager_llmnr_ipv6_tcp_fd(Manager *m); int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_addr); LinkAddress* manager_find_link_address(Manager *m, int family, const union in_addr_union *in_addr); diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index 5a90c778fb..904dec6bfc 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; } - r = write_string_file(saved, value); + r = write_string_file(saved, value, WRITE_STRING_FILE_CREATE); if (r < 0) { log_error_errno(r, "Failed to write %s: %m", saved); return EXIT_FAILURE; diff --git a/src/run/run.c b/src/run/run.c index 99d960a664..148854a9b5 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -1099,7 +1099,7 @@ static int start_transient_timer( } int main(int argc, char* argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; _cleanup_free_ char *description = NULL, *command = NULL; int r; diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index d8dba584d6..4ae216b7d9 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -135,22 +135,15 @@ typedef struct UnitInfo { int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); -static inline void sd_bus_close_unrefp(sd_bus **bus) { - if (*bus) { - sd_bus_flush(*bus); - sd_bus_close(*bus); - sd_bus_unref(*bus); - } -} - DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_flush_close_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_slot*, sd_bus_slot_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_track*, sd_bus_track_unref); #define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp) -#define _cleanup_bus_close_unref_ _cleanup_(sd_bus_close_unrefp) +#define _cleanup_bus_flush_close_unref_ _cleanup_(sd_bus_flush_close_unrefp) #define _cleanup_bus_slot_unref_ _cleanup_(sd_bus_slot_unrefp) #define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp) #define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp) diff --git a/src/shared/efivars.c b/src/shared/efivars.c index 0d6ecf52cf..347cd30b09 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -125,7 +125,19 @@ static int get_os_indications(uint64_t *os_indication) { return r; r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s); - if (r < 0) + if (r == -ENOENT) { + /* Some firmware implementations that do support + * OsIndications and report that with + * OsIndicationsSupported will remove the + * OsIndications variable when it is unset. Let's + * pretend it's 0 then, to hide this implementation + * detail. Note that this call will return -ENOENT + * then only if the support for OsIndications is + * missing entirely, as determined by + * efi_reboot_to_firmware_supported() above. */ + *os_indication = 0; + return 0; + } else if (r < 0) return r; else if (s != sizeof(uint64_t)) return -EINVAL; diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c index 55f4e48601..1de0b94fd5 100644 --- a/src/shared/sysctl-util.c +++ b/src/shared/sysctl-util.c @@ -66,7 +66,7 @@ int sysctl_write(const char *property, const char *value) { log_debug("Setting '%s' to '%s'", property, value); p = strjoina("/proc/sys/", property); - return write_string_file(p, value); + return write_string_file(p, value, 0); } int sysctl_read(const char *property, char **content) { diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index eee6bc8982..2b2310152d 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -42,7 +42,7 @@ static int write_mode(char **modes) { STRV_FOREACH(mode, modes) { int k; - k = write_string_file("/sys/power/disk", *mode); + k = write_string_file("/sys/power/disk", *mode, 0); if (k == 0) return 0; @@ -65,7 +65,7 @@ static int write_state(FILE **f, char **states) { STRV_FOREACH(state, states) { int k; - k = write_string_stream(*f, *state); + k = write_string_stream(*f, *state, true); if (k == 0) return 0; log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m", diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 538838b7fc..6db4d6587a 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -617,7 +617,7 @@ static int get_unit_list_recursive( return r; STRV_FOREACH(i, machines) { - _cleanup_bus_close_unref_ sd_bus *container = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *container = NULL; int k; r = sd_bus_open_system_machine(&container, *i); @@ -1709,7 +1709,7 @@ static int compare_machine_info(const void *a, const void *b) { } static int get_machine_properties(sd_bus *bus, struct machine_info *mi) { - _cleanup_bus_close_unref_ sd_bus *container = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *container = NULL; int r; assert(mi); @@ -7340,7 +7340,7 @@ static int halt_main(sd_bus *bus) { if (arg_when > 0) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_close_unref_ sd_bus *b = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; _cleanup_free_ char *m = NULL; if (avoid_bus()) { @@ -7449,7 +7449,7 @@ static int runlevel_main(void) { } int main(int argc, char*argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -7517,7 +7517,7 @@ int main(int argc, char*argv[]) { case ACTION_CANCEL_SHUTDOWN: { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_close_unref_ sd_bus *b = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; _cleanup_free_ char *m = NULL; if (avoid_bus()) { diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 57e46ced8e..5439a1903b 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -156,6 +156,7 @@ void sd_bus_close(sd_bus *bus); sd_bus *sd_bus_ref(sd_bus *bus); sd_bus *sd_bus_unref(sd_bus *bus); +sd_bus *sd_bus_flush_close_unref(sd_bus *bus); int sd_bus_is_open(sd_bus *bus); @@ -204,7 +205,7 @@ sd_bus* sd_bus_slot_get_bus(sd_bus_slot *slot); void *sd_bus_slot_get_userdata(sd_bus_slot *slot); void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata); int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description); -int sd_bus_slot_get_description(sd_bus_slot *slot, char **description); +int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description); sd_bus_message* sd_bus_slot_get_current_message(sd_bus_slot *slot); sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *bus); diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h index 4296b91d8a..5afa50a9d0 100644 --- a/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/sd-dhcp-lease.h @@ -45,6 +45,8 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn); +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data, + size_t *data_len); int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id, size_t *client_id_len); diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 0d246b1835..45b119362c 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -240,22 +240,21 @@ static bool usage_contains_reload(const char *line) { } static char *sysv_translate_name(const char *name) { - char *r; - _cleanup_free_ char *c; + _cleanup_free_ char *c = NULL; + char *res; c = strdup(name); if (!c) - return NULL; + return NULL; - r = endswith(c, ".sh"); - if (r) { - *r = '\0'; - } + res = endswith(c, ".sh"); + if (res) + *res = 0; - if (unit_name_mangle(c, UNIT_NAME_NOGLOB, &r) >= 0) - return r; - else - return NULL; + if (unit_name_mangle(c, UNIT_NAME_NOGLOB, &res) < 0) + return NULL; + + return res; } static int sysv_translate_facility(const char *name, const char *filename, char **_r) { @@ -377,8 +376,7 @@ static int handle_provides(SysvStub *s, unsigned line, const char *full_text, co if (r < 0) return log_oom(); } - } - else if (t == _UNIT_TYPE_INVALID) + } else if (t == _UNIT_TYPE_INVALID) log_warning("Unit name '%s' is invalid", m); else log_warning("Unknown unit type for unit '%s'", m); diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index 838ffcba3d..e4771c9dd7 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to make subvolume: %m"); - r = write_string_file("/xxxtest/afile", "ljsadhfljasdkfhlkjdsfha"); + r = write_string_file("/xxxtest/afile", "ljsadhfljasdkfhlkjdsfha", WRITE_STRING_FILE_CREATE); if (r < 0) log_error_errno(r, "Failed to write file: %m"); diff --git a/src/test/test-copy.c b/src/test/test-copy.c index b1385b8b87..b73c958ec5 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -43,7 +43,7 @@ static void test_copy_file(void) { assert_se(fd >= 0); close(fd); - assert_se(write_string_file(fn, "foo bar bar bar foo") == 0); + assert_se(write_string_file(fn, "foo bar bar bar foo", WRITE_STRING_FILE_CREATE) == 0); assert_se(copy_file(fn, fn_copy, 0, 0644, 0) == 0); @@ -67,7 +67,7 @@ static void test_copy_file_fd(void) { out_fd = mkostemp_safe(out_fn, O_RDWR); assert_se(out_fd >= 0); - assert_se(write_string_file(in_fn, text) == 0); + assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0); assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, true) < 0); assert_se(copy_file_fd(in_fn, out_fd, true) >= 0); assert_se(lseek(out_fd, SEEK_SET, 0) == 0); @@ -94,7 +94,7 @@ static void test_copy_tree(void) { char *f = strjoina(original_dir, *p); assert_se(mkdir_parents(f, 0755) >= 0); - assert_se(write_string_file(f, "file") == 0); + assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0); } STRV_FOREACH_PAIR(link, p, links) { diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 4c31b776bd..be3a87958f 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -302,17 +302,27 @@ static void test_write_string_stream(void) { f = fdopen(fd, "r"); assert_se(f); - assert_se(write_string_stream(f, "boohoo") < 0); + assert_se(write_string_stream(f, "boohoo", true) < 0); f = freopen(fn, "r+", f); assert_se(f); - assert_se(write_string_stream(f, "boohoo") == 0); + assert_se(write_string_stream(f, "boohoo", true) == 0); rewind(f); assert_se(fgets(buf, sizeof(buf), f)); assert_se(streq(buf, "boohoo\n")); + f = freopen(fn, "w+", f); + assert_se(f); + + assert_se(write_string_stream(f, "boohoo", false) == 0); + rewind(f); + + assert_se(fgets(buf, sizeof(buf), f)); + printf(">%s<", buf); + assert_se(streq(buf, "boohoo")); + unlink(fn); } @@ -324,7 +334,7 @@ static void test_write_string_file(void) { fd = mkostemp_safe(fn, O_RDWR); assert_se(fd >= 0); - assert_se(write_string_file(fn, "boohoo") == 0); + assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0); assert_se(read(fd, buf, sizeof(buf)) == 7); assert_se(streq(buf, "boohoo\n")); @@ -340,8 +350,8 @@ static void test_write_string_file_no_create(void) { fd = mkostemp_safe(fn, O_RDWR); assert_se(fd >= 0); - assert_se(write_string_file_no_create("/a/file/which/does/not/exists/i/guess", "boohoo") < 0); - assert_se(write_string_file_no_create(fn, "boohoo") == 0); + assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0); + assert_se(write_string_file(fn, "boohoo", 0) == 0); assert_se(read(fd, buf, sizeof(buf)) == strlen("boohoo\n")); assert_se(streq(buf, "boohoo\n")); @@ -367,8 +377,8 @@ static void test_load_env_file_pairs(void) { "ANSI_COLOR=\"0;36\"\n" "HOME_URL=\"https://www.archlinux.org/\"\n" "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n" - "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n" - ); + "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n", + WRITE_STRING_FILE_CREATE); assert_se(r == 0); f = fdopen(fd, "r"); diff --git a/src/test/test-pty.c b/src/test/test-pty.c index 3f97a64ccd..fbab3d4ebe 100644 --- a/src/test/test-pty.c +++ b/src/test/test-pty.c @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) { /* Oh, there're ugly races in the TTY layer regarding HUP vs IN. Turns * out they appear only 10% of the time. I fixed all of them and - * don't see them, anymore. But lets be safe and run this 1000 times + * don't see them, anymore. But let's be safe and run this 1000 times * so we catch any new ones, in case they appear again. */ for (i = 0; i < 1000; ++i) test_pty(); diff --git a/src/test/test-util.c b/src/test/test-util.c index ad9ea3bcce..72fbc345c2 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -390,6 +390,24 @@ static void test_unhexchar(void) { assert_se(unhexchar('0') == 0x0); } +static void test_base64char(void) { + assert_se(base64char(0) == 'A'); + assert_se(base64char(26) == 'a'); + assert_se(base64char(63) == '/'); +} + +static void test_unbase64char(void) { + assert_se(unbase64char('A') == 0); + assert_se(unbase64char('Z') == 25); + assert_se(unbase64char('a') == 26); + assert_se(unbase64char('z') == 51); + assert_se(unbase64char('0') == 52); + assert_se(unbase64char('9') == 61); + assert_se(unbase64char('+') == 62); + assert_se(unbase64char('/') == 63); + assert_se(unbase64char('=') == -EINVAL); +} + static void test_octchar(void) { assert_se(octchar(00) == '0'); assert_se(octchar(07) == '7'); @@ -410,6 +428,108 @@ static void test_undecchar(void) { assert_se(undecchar('9') == 9); } +static void test_unhexmem(void) { + const char *hex = "efa214921"; + const char *hex_invalid = "efa214921o"; + _cleanup_free_ char *hex2 = NULL; + _cleanup_free_ void *mem = NULL; + size_t len; + + assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); + assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); + assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); + + assert_se((hex2 = hexmem(mem, len))); + + free(mem); + + assert_se(memcmp(hex, hex2, strlen(hex)) == 0); + + free(hex2); + + assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); + assert_se((hex2 = hexmem(mem, len))); + assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base64mem(void) { + char *b64; + + b64 = base64mem("", strlen("")); + assert_se(b64); + assert_se(streq(b64, "")); + free(b64); + + b64 = base64mem("f", strlen("f")); + assert_se(b64); + assert_se(streq(b64, "Zg==")); + free(b64); + + b64 = base64mem("fo", strlen("fo")); + assert_se(b64); + assert_se(streq(b64, "Zm8=")); + free(b64); + + b64 = base64mem("foo", strlen("foo")); + assert_se(b64); + assert_se(streq(b64, "Zm9v")); + free(b64); + + b64 = base64mem("foob", strlen("foob")); + assert_se(b64); + assert_se(streq(b64, "Zm9vYg==")); + free(b64); + + b64 = base64mem("fooba", strlen("fooba")); + assert_se(b64); + assert_se(streq(b64, "Zm9vYmE=")); + free(b64); + + b64 = base64mem("foobar", strlen("foobar")); + assert_se(b64); + assert_se(streq(b64, "Zm9vYmFy")); + free(b64); +} + +static void test_unbase64mem(void) { + void *mem; + size_t len; + + assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); + assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); +} + static void test_cescape(void) { _cleanup_free_ char *escaped; @@ -565,14 +685,14 @@ static void test_read_hostname_config(void) { close(fd); /* simple hostname */ - write_string_file(path, "foo"); + write_string_file(path, "foo", WRITE_STRING_FILE_CREATE); assert_se(read_hostname_config(path, &hostname) == 0); assert_se(streq(hostname, "foo")); free(hostname); hostname = NULL; /* with comment */ - write_string_file(path, "# comment\nfoo"); + write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE); assert_se(read_hostname_config(path, &hostname) == 0); assert_se(hostname); assert_se(streq(hostname, "foo")); @@ -580,7 +700,7 @@ static void test_read_hostname_config(void) { hostname = NULL; /* with comment and extra whitespace */ - write_string_file(path, "# comment\n\n foo "); + write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE); assert_se(read_hostname_config(path, &hostname) == 0); assert_se(hostname); assert_se(streq(hostname, "foo")); @@ -588,7 +708,7 @@ static void test_read_hostname_config(void) { hostname = NULL; /* cleans up name */ - write_string_file(path, "!foo/bar.com"); + write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE); assert_se(read_hostname_config(path, &hostname) == 0); assert_se(hostname); assert_se(streq(hostname, "foobar.com")); @@ -597,7 +717,7 @@ static void test_read_hostname_config(void) { /* no value set */ hostname = (char*) 0x1234; - write_string_file(path, "# nothing here\n"); + write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE); assert_se(read_hostname_config(path, &hostname) == -ENOENT); assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ @@ -1191,11 +1311,11 @@ static void test_execute_directory(void) { masked = strjoina(template_lo, "/masked"); mask = strjoina(template_hi, "/masked"); - assert_se(write_string_file(name, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works") == 0); - assert_se(write_string_file(name2, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2") == 0); - assert_se(write_string_file(overridden, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed") == 0); - assert_se(write_string_file(override, "#!/bin/sh\necho 'Executing '$0") == 0); - assert_se(write_string_file(masked, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed") == 0); + assert_se(write_string_file(name, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works", WRITE_STRING_FILE_CREATE) == 0); + assert_se(write_string_file(name2, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2", WRITE_STRING_FILE_CREATE) == 0); + assert_se(write_string_file(overridden, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed", WRITE_STRING_FILE_CREATE) == 0); + assert_se(write_string_file(override, "#!/bin/sh\necho 'Executing '$0", WRITE_STRING_FILE_CREATE) == 0); + assert_se(write_string_file(masked, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed", WRITE_STRING_FILE_CREATE) == 0); assert_se(symlink("/dev/null", mask) == 0); assert_se(chmod(name, 0755) == 0); assert_se(chmod(name2, 0755) == 0); @@ -1804,10 +1924,15 @@ int main(int argc, char *argv[]) { test_in_charset(); test_hexchar(); test_unhexchar(); + test_base64char(); + test_unbase64char(); test_octchar(); test_unoctchar(); test_decchar(); test_undecchar(); + test_unhexmem(); + test_base64mem(); + test_unbase64mem(); test_cescape(); test_cunescape(); test_foreach_word(); diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 195d5f3892..240578bca0 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -154,11 +154,12 @@ static void print_status_info(const StatusInfo *i) { if (i->rtc_local) fputs("\n" ANSI_HIGHLIGHT_ON - "Warning: The system is configured to read the RTC time in the local time zone. This\n" - " mode can not be fully supported. It will create various problems with time\n" - " zone changes and daylight saving time adjustments. The RTC time is never updated,\n" - " it relies on external facilities to maintain it. If at all possible, use\n" - " RTC in UTC by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout); + "Warning: The system is configured to read the RTC time in the local time zone.\n" + " This mode can not be fully supported. It will create various problems\n" + " with time zone changes and daylight saving time adjustments. The RTC\n" + " time is never updated, it relies on external facilities to maintain it.\n" + " If at all possible, use RTC in UTC by calling\n" + " 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout); } static int show_status(sd_bus *bus, char **args, unsigned n) { @@ -490,7 +491,7 @@ static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 4e8ae94717..21d6ee4c0c 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -660,7 +660,7 @@ static const sd_bus_vtable timedate_vtable[] = { }; static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; assert(c); @@ -692,7 +692,7 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { int main(int argc, char *argv[]) { Context context = {}; _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_bus_close_unref_ sd_bus *bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; log_set_target(LOG_TARGET_AUTO); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index cf15ddf641..0661f7be00 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -398,7 +398,7 @@ static void worker_spawn(Manager *manager, struct event *event) { prctl(PR_SET_PDEATHSIG, SIGTERM); /* reset OOM score, we only protect the main daemon */ - write_string_file("/proc/self/oom_score_adj", "0"); + write_string_file("/proc/self/oom_score_adj", "0", 0); for (;;) { struct udev_event *udev_event; @@ -1091,7 +1091,7 @@ static int synthesize_change(struct udev_device *dev) { */ log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev)); strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL); - write_string_file(filename, "change"); + write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); udev_list_entry_foreach(item, udev_enumerate_get_list_entry(e)) { _cleanup_udev_device_unref_ struct udev_device *d = NULL; @@ -1106,7 +1106,7 @@ static int synthesize_change(struct udev_device *dev) { log_debug("device %s closed, synthesising partition '%s' 'change'", udev_device_get_devnode(dev), udev_device_get_devnode(d)); strscpyl(filename, sizeof(filename), udev_device_get_syspath(d), "/uevent", NULL); - write_string_file(filename, "change"); + write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); } return 0; @@ -1114,7 +1114,7 @@ static int synthesize_change(struct udev_device *dev) { log_debug("device %s closed, synthesising 'change'", udev_device_get_devnode(dev)); strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL); - write_string_file(filename, "change"); + write_string_file(filename, "change", WRITE_STRING_FILE_CREATE); return 0; } @@ -1608,8 +1608,42 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg return 0; } -int main(int argc, char *argv[]) { +static int run(int fd_ctrl, int fd_uevent, const char *cgroup) { _cleanup_(manager_freep) Manager *manager = NULL; + int r; + + r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup); + if (r < 0) { + r = log_error_errno(r, "failed to allocate manager object: %m"); + goto exit; + } + + r = udev_rules_apply_static_dev_perms(manager->rules); + if (r < 0) + log_error_errno(r, "failed to apply permissions on static device nodes: %m"); + + (void) sd_notify(false, + "READY=1\n" + "STATUS=Processing..."); + + r = sd_event_loop(manager->event); + if (r < 0) { + log_error_errno(r, "event loop failed: %m"); + goto exit; + } + + sd_event_get_exit_code(manager->event, &r); + +exit: + sd_notify(false, + "STOPPING=1\n" + "STATUS=Shutting down..."); + if (manager) + udev_ctrl_cleanup(manager->ctrl); + return r; +} + +int main(int argc, char *argv[]) { _cleanup_free_ char *cgroup = NULL; int r, fd_ctrl, fd_uevent; @@ -1625,8 +1659,10 @@ int main(int argc, char *argv[]) { if (r < 0) log_warning_errno(r, "failed to parse kernel command line, ignoring: %m"); - if (arg_debug) + if (arg_debug) { + log_set_target(LOG_TARGET_CONSOLE); log_set_max_level(LOG_DEBUG); + } if (getuid() != 0) { r = log_error_errno(EPERM, "root privileges required"); @@ -1711,38 +1747,12 @@ int main(int argc, char *argv[]) { setsid(); - write_string_file("/proc/self/oom_score_adj", "-1000"); - } - - r = manager_new(&manager, fd_ctrl, fd_uevent, cgroup); - if (r < 0) { - r = log_error_errno(r, "failed to allocate manager object: %m"); - goto exit; + write_string_file("/proc/self/oom_score_adj", "-1000", 0); } - r = udev_rules_apply_static_dev_perms(manager->rules); - if (r < 0) - log_error_errno(r, "failed to apply permissions on static device nodes: %m"); - - (void) sd_notify(false, - "READY=1\n" - "STATUS=Processing..."); - - r = sd_event_loop(manager->event); - if (r < 0) { - log_error_errno(r, "event loop failed: %m"); - goto exit; - } - - sd_event_get_exit_code(manager->event, &r); + r = run(fd_ctrl, fd_uevent, cgroup); exit: - sd_notify(false, - "STOPPING=1\n" - "STATUS=Shutting down..."); - - if (manager) - udev_ctrl_cleanup(manager->ctrl); mac_selinux_finish(); log_close(); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 1c31769fde..ddeb310c3c 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -65,7 +65,7 @@ int main(int argc, char*argv[]) { } else if (streq(argv[1], "stop")) { int r; - r = write_string_file_atomic("/run/nologin", "System is going down."); + r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC); if (r < 0) { log_error_errno(r, "Failed to create /run/nologin: %m"); return EXIT_FAILURE; diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index f7728dcfff..7bdc158ad7 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -56,7 +56,7 @@ static int disable_utf8(int fd) { if (k < 0) r = k; - k = write_string_file("/sys/module/vt/parameters/default_utf8", "0"); + k = write_string_file("/sys/module/vt/parameters/default_utf8", "0", 0); if (k < 0) r = k; @@ -89,7 +89,7 @@ static int enable_utf8(int fd) { if (k < 0) r = k; - k = write_string_file("/sys/module/vt/parameters/default_utf8", "1"); + k = write_string_file("/sys/module/vt/parameters/default_utf8", "1", 0); if (k < 0) r = k; |