diff options
Diffstat (limited to 'src')
37 files changed, 413 insertions, 234 deletions
diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 61f188467f..cff2d2a034 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -181,10 +181,10 @@ int is_kernel_thread(pid_t pid) { bool eof; FILE *f; - if (pid == 0) + if (pid == 0 || pid == 1) /* pid 1, and we ourselves certainly aren't a kernel thread */ return 0; - assert(pid > 0); + assert(pid > 1); p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); diff --git a/src/basic/util.c b/src/basic/util.c index f752595ca1..737f2a221c 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -4273,7 +4273,7 @@ bool is_locale_utf8(void) { /* Check result, but ignore the result if C was set * explicitly. */ cached_answer = - streq(set, "C") && + STR_IN_SET(set, "C", "POSIX") && !getenv("LC_ALL") && !getenv("LC_CTYPE") && !getenv("LANG"); @@ -5754,40 +5754,39 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra switch (state) { case START: - if (c == 0) { - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + + if (c == 0) goto finish_force_terminate; - } else if (strchr(separators, c)) { + else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; (*p) ++; goto finish_force_next; } break; } + /* We found a non-blank character, so we will always + * want to return a string (even if it is empty), + * allocate it here. */ + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + state = VALUE; /* fallthrough */ case VALUE: if (c == 0) goto finish_force_terminate; - else if (c == '\'' && (flags & EXTRACT_QUOTES)) { - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - + else if (c == '\'' && (flags & EXTRACT_QUOTES)) state = SINGLE_QUOTE; - } else if (c == '\\') + else if (c == '\\') state = VALUE_ESCAPE; - else if (c == '\"' && (flags & EXTRACT_QUOTES)) { - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - + else if (c == '\"' && (flags & EXTRACT_QUOTES)) state = DOUBLE_QUOTE; - } else if (strchr(separators, c)) { + else if (strchr(separators, c)) { if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { (*p) ++; goto finish_force_next; @@ -5891,8 +5890,6 @@ end_escape: case SEPARATOR: if (c == 0) goto finish_force_terminate; - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) - goto finish_force_next; if (!strchr(separators, c)) goto finish; break; diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index fae9398aa5..a8d910d532 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -160,7 +160,7 @@ static int get_cgroup_root(char **ret) { &error, ret); if (r < 0) - return log_error_errno(r, "Failed to query unit control group path: %m"); + return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r)); return 0; } @@ -263,7 +263,7 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - printf("Control group %s:\n", root); + printf("Control group %s:\n", isempty(root) ? "/" : root); fflush(stdout); r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags); diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 26b104f111..06a43d15e4 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -30,6 +30,7 @@ #include "path-util.h" #include "terminal-util.h" +#include "process-util.h" #include "util.h" #include "hashmap.h" #include "cgroup-util.h" @@ -64,6 +65,8 @@ static unsigned arg_iterations = (unsigned) -1; static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; +static bool arg_kernel_threads = false; +static bool arg_recursive = true; static enum { ORDER_PATH, @@ -107,7 +110,14 @@ static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, off_t return format_bytes(buf, l, t); } -static int process(const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration) { +static int process( + const char *controller, + const char *path, + Hashmap *a, + Hashmap *b, + unsigned iteration, + Group **ret) { + Group *g; int r; @@ -154,8 +164,13 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap return r; g->n_tasks = 0; - while (cg_read_pid(f, &pid) > 0) + while (cg_read_pid(f, &pid) > 0) { + + if (!arg_kernel_threads && is_kernel_thread(pid) > 0) + continue; + g->n_tasks++; + } if (g->n_tasks > 0) g->n_tasks_valid = true; @@ -296,6 +311,9 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap g->io_iteration = iteration; } + if (ret) + *ret = g; + return 0; } @@ -305,9 +323,11 @@ static int refresh_one( Hashmap *a, Hashmap *b, unsigned iteration, - unsigned depth) { + unsigned depth, + Group **ret) { _cleanup_closedir_ DIR *d = NULL; + Group *ours; int r; assert(controller); @@ -317,7 +337,7 @@ static int refresh_one( if (depth > arg_depth) return 0; - r = process(controller, path, a, b, iteration); + r = process(controller, path, a, b, iteration, &ours); if (r < 0) return r; @@ -329,10 +349,13 @@ static int refresh_one( for (;;) { _cleanup_free_ char *fn = NULL, *p = NULL; + Group *child = NULL; r = cg_read_subgroup(d, &fn); - if (r <= 0) + if (r < 0) return r; + if (r == 0) + break; p = strjoin(path, "/", fn, NULL); if (!p) @@ -340,29 +363,47 @@ static int refresh_one( path_kill_slashes(p); - r = refresh_one(controller, p, a, b, iteration, depth + 1); + r = refresh_one(controller, p, a, b, iteration, depth + 1, &child); if (r < 0) return r; + + if (arg_recursive && + child && + child->n_tasks_valid && + streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { + + /* Recursively sum up processes */ + + if (ours->n_tasks_valid) + ours->n_tasks += child->n_tasks; + else { + ours->n_tasks = child->n_tasks; + ours->n_tasks_valid = true; + } + } } - return r; + if (ret) + *ret = ours; + + return 1; } -static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) { +static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration) { int r; assert(a); - r = refresh_one(SYSTEMD_CGROUP_CONTROLLER, "/", a, b, iteration, 0); + r = refresh_one(SYSTEMD_CGROUP_CONTROLLER, root, a, b, iteration, 0, NULL); if (r < 0) return r; - r = refresh_one("cpuacct", "/", a, b, iteration, 0); + r = refresh_one("cpuacct", root, a, b, iteration, 0, NULL); if (r < 0) return r; - r = refresh_one("memory", "/", a, b, iteration, 0); + r = refresh_one("memory", root, a, b, iteration, 0, NULL); if (r < 0) return r; - r = refresh_one("blkio", "/", a, b, iteration, 0); + r = refresh_one("blkio", root, a, b, iteration, 0, NULL); if (r < 0) return r; @@ -372,11 +413,11 @@ static int refresh(Hashmap *a, Hashmap *b, unsigned iteration) { static int group_compare(const void*a, const void *b) { const Group *x = *(Group**)a, *y = *(Group**)b; - if (arg_order != ORDER_TASKS) { + if (arg_order != ORDER_TASKS || arg_recursive) { /* Let's make sure that the parent is always before - * the child. Except when ordering by tasks, since - * that is actually not accumulative for all - * children. */ + * the child. Except when ordering by tasks and + * recursive summing is off, since that is actually + * not accumulative for all children. */ if (path_startswith(y->path, x->path)) return -1; @@ -453,7 +494,7 @@ static int group_compare(const void*a, const void *b) { #define ON ANSI_HIGHLIGHT_ON #define OFF ANSI_HIGHLIGHT_OFF -static int display(Hashmap *a) { +static void display(Hashmap *a) { Iterator i; Group *g; Group **array; @@ -548,8 +589,6 @@ static int display(Hashmap *a) { putchar('\n'); } - - return 0; } static void help(void) { @@ -565,6 +604,8 @@ static void help(void) { " -r --raw Provide raw (not human-readable) numbers\n" " --cpu=percentage Show CPU usage as percentage (default)\n" " --cpu=time Show CPU usage as time\n" + " -k Include kernel threads in task count\n" + " --recursive=BOOL Sum up task count recursively\n" " -d --delay=DELAY Delay between updates\n" " -n --iterations=N Run for N iterations before exiting\n" " -b --batch Run in batch mode, accepting no input\n" @@ -579,28 +620,29 @@ static int parse_argv(int argc, char *argv[]) { ARG_DEPTH, ARG_CPU_TYPE, ARG_ORDER, + ARG_RECURSIVE, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "delay", required_argument, NULL, 'd' }, - { "iterations", required_argument, NULL, 'n' }, - { "batch", no_argument, NULL, 'b' }, - { "raw", no_argument, NULL, 'r' }, - { "depth", required_argument, NULL, ARG_DEPTH }, - { "cpu", optional_argument, NULL, ARG_CPU_TYPE }, - { "order", required_argument, NULL, ARG_ORDER }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "delay", required_argument, NULL, 'd' }, + { "iterations", required_argument, NULL, 'n' }, + { "batch", no_argument, NULL, 'b' }, + { "raw", no_argument, NULL, 'r' }, + { "depth", required_argument, NULL, ARG_DEPTH }, + { "cpu", optional_argument, NULL, ARG_CPU_TYPE }, + { "order", required_argument, NULL, ARG_ORDER }, + { "recursive", required_argument, NULL, ARG_RECURSIVE }, {} }; - int c; - int r; + int c, r; assert(argc >= 1); assert(argv); - while ((c = getopt_long(argc, argv, "hptcmin:brd:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hptcmin:brd:k", options, NULL)) >= 0) switch (c) { @@ -700,6 +742,20 @@ static int parse_argv(int argc, char *argv[]) { } break; + case 'k': + arg_kernel_threads = true; + break; + + case ARG_RECURSIVE: + r = parse_boolean(optarg); + if (r < 0) { + log_error("Failed to parse --recursive= argument: %s", optarg); + return r; + } + + arg_recursive = r; + break; + case '?': return -EINVAL; @@ -721,6 +777,7 @@ int main(int argc, char *argv[]) { unsigned iteration = 0; usec_t last_refresh = 0; bool quit = false, immediate_refresh = false; + _cleanup_free_ char *root = NULL; log_parse_environment(); log_open(); @@ -729,6 +786,12 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; + r = cg_get_root_path(&root); + if (r < 0) { + log_error_errno(r, "Failed to get root control group path: %m"); + goto finish; + } + a = hashmap_new(&string_hash_ops); b = hashmap_new(&string_hash_ops); if (!a || !b) { @@ -751,9 +814,11 @@ int main(int argc, char *argv[]) { if (t >= last_refresh + arg_delay || immediate_refresh) { - r = refresh(a, b, iteration++); - if (r < 0) + r = refresh(root, a, b, iteration++); + if (r < 0) { + log_error_errno(r, "Failed to refresh: %m"); goto finish; + } group_hashmap_clear(b); @@ -765,9 +830,7 @@ int main(int argc, char *argv[]) { immediate_refresh = false; } - r = display(b); - if (r < 0) - goto finish; + display(b); if (arg_iterations && iteration >= arg_iterations) break; @@ -777,7 +840,7 @@ int main(int argc, char *argv[]) { fflush(stdout); if (arg_batch) - usleep(last_refresh + arg_delay - t); + (void) usleep(last_refresh + arg_delay - t); else { r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL); if (r == -ETIMEDOUT) @@ -830,6 +893,20 @@ int main(int argc, char *argv[]) { arg_cpu_type = arg_cpu_type == CPU_TIME ? CPU_PERCENT : CPU_TIME; break; + case 'k': + arg_kernel_threads = !arg_kernel_threads; + fprintf(stdout, "\nCounting kernel threads: %s.", yes_no(arg_kernel_threads)); + fflush(stdout); + sleep(1); + break; + + case 'r': + arg_recursive = !arg_recursive; + fprintf(stdout, "\nRecursive task counting: %s", yes_no(arg_recursive)); + fflush(stdout); + sleep(1); + break; + case '+': if (arg_delay < USEC_PER_SEC) arg_delay += USEC_PER_MSEC*250; @@ -858,8 +935,8 @@ int main(int argc, char *argv[]) { case 'h': fprintf(stdout, "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n" - "\t<" ON "+" OFF "> Increase delay; <" ON "-" OFF "> Decrease delay; <" ON "%%" OFF "> Toggle time\n" - "\t<" ON "q" OFF "> Quit; <" ON "SPACE" OFF "> Refresh"); + "\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n" + "\t<" ON "k" OFF "> Count kernel threads; <" ON "r" OFF "> Count recursively; <" ON "q" OFF "> Quit"); fflush(stdout); sleep(3); break; @@ -881,10 +958,5 @@ finish: group_hashmap_free(a); group_hashmap_free(b); - if (r < 0) { - log_error_errno(r, "Exiting with failure: %m"); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 6474e08bd2..c26807ba2b 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -806,12 +806,9 @@ static void unit_queue_siblings(Unit *u) { } int unit_realize_cgroup(Unit *u) { - CGroupContext *c; - assert(u); - c = unit_get_cgroup_context(u); - if (!c) + if (!UNIT_HAS_CGROUP_CONTEXT(u)) return 0; /* So, here's the deal: when realizing the cgroups for this diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 42bb653cc1..1e6291e762 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -965,38 +965,39 @@ static int bus_unit_set_transient_property( return 1; - } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) { + } else if (streq(name, "Slice")) { + Unit *slice; const char *s; + if (!UNIT_HAS_CGROUP_CONTEXT(u)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups."); + if (u->type == UNIT_SLICE) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units."); + r = sd_bus_message_read(message, "s", &s); if (r < 0) return r; - if (!unit_name_is_valid(s, UNIT_NAME_PLAIN) || !endswith(s, ".slice")) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s); + if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s); - if (isempty(s)) { - if (mode != UNIT_CHECK) { - unit_ref_unset(&u->slice); - unit_remove_drop_in(u, mode, name); - } - } else { - Unit *slice; + r = manager_load_unit(u->manager, s, NULL, error, &slice); + if (r < 0) + return r; + + if (slice->type != UNIT_SLICE) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s); - r = manager_load_unit(u->manager, s, NULL, error, &slice); + if (mode != UNIT_CHECK) { + r = unit_set_slice(u, slice); if (r < 0) return r; - if (slice->type != UNIT_SLICE) - return -EINVAL; - - if (mode != UNIT_CHECK) { - unit_ref_set(&u->slice, slice); - unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s); - } + unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s); } return 1; + } else if (STR_IN_SET(name, "Requires", "RequiresOverridable", "Requisite", "RequisiteOverridable", diff --git a/src/core/dbus.c b/src/core/dbus.c index d091aa5419..7ad16aa42b 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -381,7 +381,7 @@ static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *inter if (!streq_ptr(interface, unit_dbus_interface_from_type(u->type))) return 0; - if (!unit_get_cgroup_context(u)) + if (!UNIT_HAS_CGROUP_CONTEXT(u)) return 0; *found = u; diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b3bf8bdb40..745291c5c6 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2602,7 +2602,7 @@ int config_parse_unit_slice( void *userdata) { _cleanup_free_ char *k = NULL; - Unit *u = userdata, *slice; + Unit *u = userdata, *slice = NULL; int r; assert(filename); @@ -2611,29 +2611,23 @@ int config_parse_unit_slice( assert(u); r = unit_name_printf(u, rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s. Ignoring.", rvalue); - if (!k) { - k = strdup(rvalue); - if (!k) - return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue); + return 0; } r = manager_load_unit(u->manager, k, NULL, NULL, &slice); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to load slice unit %s. Ignoring.", k); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load slice unit %s. Ignoring.", k); return 0; } - if (slice->type != UNIT_SLICE) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Slice unit %s is not a slice. Ignoring.", k); + r = unit_set_slice(u, slice); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id); return 0; } - unit_ref_set(&u->slice, slice); return 0; } @@ -3603,6 +3597,11 @@ int unit_load_fragment(Unit *u) { assert(u->load_state == UNIT_STUB); assert(u->id); + if (u->transient) { + u->load_state = UNIT_LOADED; + return 0; + } + /* First, try to find the unit under its id. We always look * for unit files in the default directories, to make it easy * to override things by placing things in /etc/systemd/system */ diff --git a/src/core/main.c b/src/core/main.c index 87b97aa883..e232be88c0 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1391,8 +1391,7 @@ int main(int argc, char *argv[]) { /* clear the kernel timestamp, * because we are not PID 1 */ - kernel_timestamp.monotonic = 0ULL; - kernel_timestamp.realtime = 0ULL; + kernel_timestamp = DUAL_TIMESTAMP_NULL; } /* Initialize default unit */ diff --git a/src/core/manager.c b/src/core/manager.c index ecea89c377..ede2a9910d 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -250,8 +250,8 @@ static int manager_dispatch_ask_password_fd(sd_event_source *source, static void manager_close_ask_password(Manager *m) { assert(m); - m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd); m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source); + m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd); m->have_ask_password = -EINVAL; } diff --git a/src/core/mount.c b/src/core/mount.c index 7e19e66a51..2b81d17b9c 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -521,7 +521,7 @@ static int mount_add_extras(Mount *m) { if (r < 0) return r; - r = unit_add_default_slice(u, &m->cgroup_context); + r = unit_set_default_slice(u); if (r < 0) return r; diff --git a/src/core/scope.c b/src/core/scope.c index bf89936153..c594ab5294 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -164,7 +164,7 @@ static int scope_load(Unit *u) { if (r < 0) return r; - r = unit_add_default_slice(u, &s->cgroup_context); + r = unit_set_default_slice(u); if (r < 0) return r; diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index a4678500e6..e5b457643b 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -34,6 +34,7 @@ #include "log.h" #ifdef HAVE_SELINUX +_printf_(2,3) static int null_log(int type, const char *fmt, ...) { return 0; } diff --git a/src/core/service.c b/src/core/service.c index 097e7c710c..3c4232417d 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -556,7 +556,7 @@ static int service_add_extras(Service *s) { if (r < 0) return r; - r = unit_add_default_slice(UNIT(s), &s->cgroup_context); + r = unit_set_default_slice(UNIT(s)); if (r < 0) return r; diff --git a/src/core/socket.c b/src/core/socket.c index 08efc3754c..1014fad626 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -345,7 +345,7 @@ static int socket_add_extras(Socket *s) { if (r < 0) return r; - r = unit_add_default_slice(u, &s->cgroup_context); + r = unit_set_default_slice(u); if (r < 0) return r; } @@ -839,7 +839,7 @@ static void socket_apply_socket_options(Socket *s, int fd) { if (s->keep_alive_cnt) { int value = s->keep_alive_cnt; - if (setsockopt(fd, SOL_SOCKET, TCP_KEEPCNT, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &value, sizeof(value)) < 0) log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPCNT failed: %m"); } diff --git a/src/core/swap.c b/src/core/swap.c index 349fd6f7b9..4f3ddc9f04 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -326,7 +326,7 @@ static int swap_load(Unit *u) { if (r < 0) return r; - r = unit_add_default_slice(u, &s->cgroup_context); + r = unit_set_default_slice(u); if (r < 0) return r; diff --git a/src/core/unit.c b/src/core/unit.c index 43a5ca1064..5f602bdf5f 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -405,17 +405,17 @@ static void unit_remove_transient(Unit *u) { return; if (u->fragment_path) - unlink(u->fragment_path); + (void) unlink(u->fragment_path); STRV_FOREACH(i, u->dropin_paths) { _cleanup_free_ char *p = NULL; int r; - unlink(*i); + (void) unlink(*i); r = path_get_parent(*i, &p); if (r >= 0) - rmdir(p); + (void) rmdir(p); } } @@ -1122,7 +1122,7 @@ static int unit_add_target_dependencies(Unit *u) { static int unit_add_slice_dependencies(Unit *u) { assert(u); - if (!unit_get_cgroup_context(u)) + if (!UNIT_HAS_CGROUP_CONTEXT(u)) return 0; if (UNIT_ISSET(u->slice)) @@ -2424,14 +2424,42 @@ char *unit_default_cgroup_path(Unit *u) { return strjoin(u->manager->cgroup_root, "/", escaped, NULL); } -int unit_add_default_slice(Unit *u, CGroupContext *c) { +int unit_set_slice(Unit *u, Unit *slice) { + assert(u); + assert(slice); + + /* Sets the unit slice if it has not been set before. Is extra + * careful, to only allow this for units that actually have a + * cgroup context. Also, we don't allow to set this for slices + * (since the parent slice is derived from the name). Make + * sure the unit we set is actually a slice. */ + + if (!UNIT_HAS_CGROUP_CONTEXT(u)) + return -EOPNOTSUPP; + + if (u->type == UNIT_SLICE) + return -EINVAL; + + if (slice->type != UNIT_SLICE) + return -EINVAL; + + if (UNIT_DEREF(u->slice) == slice) + return 0; + + if (UNIT_ISSET(u->slice)) + return -EBUSY; + + unit_ref_set(&u->slice, slice); + return 1; +} + +int unit_set_default_slice(Unit *u) { _cleanup_free_ char *b = NULL; const char *slice_name; Unit *slice; int r; assert(u); - assert(c); if (UNIT_ISSET(u->slice)) return 0; @@ -2471,8 +2499,7 @@ int unit_add_default_slice(Unit *u, CGroupContext *c) { if (r < 0) return r; - unit_ref_set(&u->slice, slice); - return 0; + return unit_set_slice(u, slice); } const char *unit_slice_name(Unit *u) { @@ -3108,17 +3135,17 @@ int unit_kill_common( int r = 0; - if (who == KILL_MAIN && main_pid <= 0) { + if (who == KILL_MAIN) { if (main_pid < 0) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type)); - else + else if (main_pid == 0) return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill"); } - if (who == KILL_CONTROL && control_pid <= 0) { + if (who == KILL_CONTROL) { if (control_pid < 0) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type)); - else + else if (control_pid == 0) return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill"); } @@ -3317,6 +3344,8 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) { } static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) { + assert(u); + if (u->manager->running_as == MANAGER_USER) { int r; @@ -3324,9 +3353,9 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, r = user_config_home(dir); else r = user_runtime_dir(dir); - if (r == 0) return -ENOENT; + return r; } @@ -3340,8 +3369,7 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, return 0; } -static int unit_drop_in_file(Unit *u, - UnitSetPropertiesMode mode, const char *name, char **p, char **q) { +static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) { _cleanup_free_ char *dir = NULL; int r; @@ -3475,40 +3503,17 @@ int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) { } int unit_make_transient(Unit *u) { - int r; - assert(u); + if (!UNIT_VTABLE(u)->can_transient) + return -EOPNOTSUPP; + u->load_state = UNIT_STUB; u->load_error = 0; u->transient = true; + u->fragment_path = mfree(u->fragment_path); - free(u->fragment_path); - u->fragment_path = NULL; - - if (u->manager->running_as == MANAGER_USER) { - _cleanup_free_ char *c = NULL; - - r = user_runtime_dir(&c); - if (r < 0) - return r; - if (r == 0) - return -ENOENT; - - u->fragment_path = strjoin(c, "/", u->id, NULL); - if (!u->fragment_path) - return -ENOMEM; - - mkdir_p(c, 0755); - } else { - u->fragment_path = strappend("/run/systemd/system/", u->id); - if (!u->fragment_path) - return -ENOMEM; - - mkdir_p("/run/systemd/system", 0755); - } - - return write_string_file_atomic_label(u->fragment_path, "# Transient stub"); + return 0; } int unit_kill_context( diff --git a/src/core/unit.h b/src/core/unit.h index f53b7f6da1..bc26653247 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -439,6 +439,10 @@ extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX]; /* For casting the various unit types into a unit */ #define UNIT(u) (&(u)->meta) +#define UNIT_HAS_EXEC_CONTEXT(u) (UNIT_VTABLE(u)->exec_context_offset > 0) +#define UNIT_HAS_CGROUP_CONTEXT(u) (UNIT_VTABLE(u)->cgroup_context_offset > 0) +#define UNIT_HAS_KILL_CONTEXT(u) (UNIT_VTABLE(u)->kill_context_offset > 0) + #define UNIT_TRIGGER(u) ((Unit*) set_first((u)->dependencies[UNIT_TRIGGERS])) DEFINE_CAST(SERVICE, Service); @@ -490,7 +494,8 @@ int unit_load_fragment_and_dropin(Unit *u); int unit_load_fragment_and_dropin_optional(Unit *u); int unit_load(Unit *unit); -int unit_add_default_slice(Unit *u, CGroupContext *c); +int unit_set_slice(Unit *u, Unit *slice); +int unit_set_default_slice(Unit *u); const char *unit_description(Unit *u) _pure_; diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 268210fc50..5dc3c7aa26 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -57,8 +57,9 @@ struct sd_dhcp_server { int ifindex; be32_t address; be32_t netmask; - be32_t pool_start; - size_t pool_size; + be32_t subnet; + uint32_t pool_offset; + uint32_t pool_size; char *timezone; @@ -67,6 +68,7 @@ struct sd_dhcp_server { Hashmap *leases_by_client_id; DHCPLease **bound_leases; + DHCPLease invalid_lease; uint32_t max_lease_time, default_lease_time; }; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index b96cee4830..1f167485e3 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -22,6 +22,7 @@ #include <sys/ioctl.h> +#include "in-addr-util.h" #include "siphash24.h" #include "sd-dhcp-server.h" @@ -31,38 +32,63 @@ #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) -int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, - struct in_addr *address, - size_t size) { +/* configures the server's address and subnet, and optionally the pool's size and offset into the subnet + * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address + * moreover, the server's own address may be in the pool, and is in that case reserved in order not to + * accidentally hand it out */ +int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size) { + struct in_addr netmask_addr; + be32_t netmask; + uint32_t server_off, broadcast_off, size_max; + assert_return(server, -EINVAL); assert_return(address, -EINVAL); - assert_return(address->s_addr, -EINVAL); - assert_return(size, -EINVAL); - assert_return(server->pool_start == htobe32(INADDR_ANY), -EBUSY); - assert_return(!server->pool_size, -EBUSY); - assert_return(!server->bound_leases, -EBUSY); + assert_return(address->s_addr != INADDR_ANY, -EINVAL); + assert_return(prefixlen <= 32, -ERANGE); + assert_return(server->address == INADDR_ANY, -EBUSY); + + assert_se(in_addr_prefixlen_to_netmask(&netmask_addr, prefixlen)); + netmask = netmask_addr.s_addr; + + server_off = be32toh(address->s_addr & ~netmask); + broadcast_off = be32toh(~netmask); + + /* the server address cannot be the subnet address */ + assert_return(server_off != 0, -ERANGE); + + /* nor the broadcast address */ + assert_return(server_off != broadcast_off, -ERANGE); + + /* 0 offset means we should set a default, we skip the first (subnet) address + and take the next one */ + if (offset == 0) + offset = 1; + + size_max = (broadcast_off + 1) /* the number of addresses in the subnet */ + - offset /* exclude the addresses before the offset */ + - 1; /* exclude the last (broadcast) address */ + + /* The pool must contain at least one address */ + assert_return(size_max >= 1, -ERANGE); + + if (size != 0) + assert_return(size <= size_max, -ERANGE); + else + size = size_max; server->bound_leases = new0(DHCPLease*, size); if (!server->bound_leases) return -ENOMEM; - server->pool_start = address->s_addr; + server->pool_offset = offset; server->pool_size = size; - return 0; -} - -int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address, - unsigned char prefixlen) { - assert_return(server, -EINVAL); - assert_return(address, -EINVAL); - assert_return(address->s_addr, -EINVAL); - assert_return(prefixlen <= 32, -ERANGE); - assert_return(server->address == htobe32(INADDR_ANY), -EBUSY); - assert_return(server->netmask == htobe32(INADDR_ANY), -EBUSY); - server->address = address->s_addr; - server->netmask = htobe32(0xfffffffflu << (32 - prefixlen)); + server->netmask = netmask; + server->subnet = address->s_addr & netmask; + + if (server_off >= offset && server_off - offset < size) + server->bound_leases[server_off - offset] = &server->invalid_lease; return 0; } @@ -661,12 +687,11 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) { if (!server->pool_size) return -EINVAL; - if (be32toh(requested_ip) < be32toh(server->pool_start) || - be32toh(requested_ip) >= be32toh(server->pool_start) + - + server->pool_size) - return -EINVAL; + if (be32toh(requested_ip) < (be32toh(server->subnet) | server->pool_offset) || + be32toh(requested_ip) >= (be32toh(server->subnet) | (server->pool_offset + server->pool_size))) + return -ERANGE; - return be32toh(requested_ip) - be32toh(server->pool_start); + return be32toh(requested_ip & ~server->netmask) - server->pool_offset; } #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30) @@ -718,7 +743,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, if (existing_lease) address = existing_lease->address; else { - size_t next_offer; + uint32_t next_offer; /* even with no persistence of leases, we try to offer the same client the same IP address. we do this by using the hash of the client id @@ -728,7 +753,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, for (i = 0; i < server->pool_size; i++) { if (!server->bound_leases[next_offer]) { - address = htobe32(be32toh(server->pool_start) + next_offer); + address = server->subnet | htobe32(server->pool_offset + next_offer); break; } else next_offer = (next_offer + 1) % server->pool_size; @@ -1022,7 +1047,7 @@ int sd_dhcp_server_forcerenew(sd_dhcp_server *server) { for (i = 0; i < server->pool_size; i++) { DHCPLease *lease = server->bound_leases[i]; - if (!lease) + if (!lease || lease == &server->invalid_lease) continue; r = server_send_forcerenew(server, lease->address, diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 9f60ab761e..7d8a1f6bd9 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -28,6 +28,14 @@ #include "sd-dhcp-server.h" #include "dhcp-server-internal.h" +static void test_pool(struct in_addr *address, unsigned size, int ret) { + _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; + + assert_se(sd_dhcp_server_new(&server, 1) >= 0); + + assert_se(sd_dhcp_server_configure_pool(server, address, 8, 0, size) == ret); +} + static int test_basic(sd_event *event) { _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; struct in_addr address_lo = { @@ -54,15 +62,14 @@ static int test_basic(sd_event *event) { assert_se(!sd_dhcp_server_unref(server)); assert_se(sd_dhcp_server_start(server) == -EUNATCH); - assert_se(sd_dhcp_server_set_address(server, &address_any, 28) == -EINVAL); - assert_se(sd_dhcp_server_set_address(server, &address_lo, 38) == -ERANGE); - assert_se(sd_dhcp_server_set_address(server, &address_lo, 8) >= 0); - assert_se(sd_dhcp_server_set_address(server, &address_lo, 8) == -EBUSY); - assert_se(sd_dhcp_server_set_lease_pool(server, &address_any, 1) == -EINVAL); - assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 0) == -EINVAL); - assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) >= 0); - assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 1) == -EBUSY); + assert_se(sd_dhcp_server_configure_pool(server, &address_any, 28, 0, 0) == -EINVAL); + assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 38, 0, 0) == -ERANGE); + assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); + assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) == -EBUSY); + + test_pool(&address_any, 1, -EINVAL); + test_pool(&address_lo, 1, 0); r = sd_dhcp_server_start(server); @@ -119,12 +126,10 @@ static void test_message_handler(void) { }; assert_se(sd_dhcp_server_new(&server, 1) >= 0); - assert_se(sd_dhcp_server_set_address(server, &address_lo, 8) >= 0); + assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0); assert_se(sd_dhcp_server_start(server) >= 0); - assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); - assert_se(sd_dhcp_server_set_lease_pool(server, &address_lo, 10) >= 0); assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.end = 0; diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 2b83f439a7..7234e7926a 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -932,7 +932,7 @@ fail: } char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) { - _cleanup_free_ FILE *f = NULL; + _cleanup_fclose_ FILE *f = NULL; char *buffer = NULL; size_t size = 0; unsigned i; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 0e33ced342..c419be820a 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -481,7 +481,8 @@ static void source_io_unregister(sd_event_source *s) { return; r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); - assert_log(r >= 0); + if (r < 0) + log_debug_errno(errno, "Failed to remove source %s from epoll: %m", strna(s->description)); s->io.registered = false; } diff --git a/src/locale/localed.c b/src/locale/localed.c index e9489f04c2..4fa84df8c0 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -1092,6 +1092,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro } #ifdef HAVE_XKBCOMMON +_printf_(3, 0) static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) { const char *fmt; diff --git a/src/login/70-power-switch.rules b/src/login/70-power-switch.rules index 71f9fe6c72..36d2a3eb40 100644 --- a/src/login/70-power-switch.rules +++ b/src/login/70-power-switch.rules @@ -11,6 +11,7 @@ SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="acpi", TAG+="power-switch" SUBSYSTEM=="input", KERNEL=="event*", KERNELS=="thinkpad_acpi", TAG+="power-switch" SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="twl4030_pwrbutton", TAG+="power-switch" SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="tps65217_pwr_but", TAG+="power-switch" +SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="* WMI hotkeys", TAG+="power-switch" SUBSYSTEM=="input", KERNEL=="event*", \ SUBSYSTEMS=="platform", DRIVERS=="gpio-keys", ATTRS{keys}=="116", TAG+="power-switch" diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index f83d18b035..71c84d8e0a 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -179,24 +179,37 @@ static int export_legacy_dbus_address( const char *runtime) { _cleanup_free_ char *s = NULL; - int r; + int r = PAM_BUF_ERR; - /* skip export if kdbus is not active */ - if (!is_kdbus_available()) - return PAM_SUCCESS; + if (is_kdbus_available()) { + if (asprintf(&s, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, runtime) < 0) + goto error; + } else { + /* FIXME: We *realy* should move the access() check into the + * daemons that spawn dbus-daemon, instead of forcing + * DBUS_SESSION_BUS_ADDRESS= here. */ + + s = strjoin(runtime, "/bus", NULL); + if (!s) + goto error; + + if (access(s, F_OK) < 0) + return PAM_SUCCESS; - if (asprintf(&s, KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT, uid, runtime) < 0) { - pam_syslog(handle, LOG_ERR, "Failed to set bus variable."); - return PAM_BUF_ERR; + s = mfree(s); + if (asprintf(&s, UNIX_USER_BUS_ADDRESS_FMT, runtime) < 0) + goto error; } r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0); - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set bus variable."); - return r; - } + if (r != PAM_SUCCESS) + goto error; return PAM_SUCCESS; + +error: + pam_syslog(handle, LOG_ERR, "Failed to set bus variable."); + return r; } _public_ PAM_EXTERN int pam_sm_open_session( diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 82bd727c3a..1dc9db0fca 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -730,7 +730,6 @@ static int link_enter_set_addresses(Link *link) { /* now that we can figure out a default address for the dhcp server, start it */ if (link_dhcp4_server_enabled(link)) { - struct in_addr pool_start; Address *address; Link *uplink = NULL; bool acquired_uplink = false; @@ -742,16 +741,9 @@ static int link_enter_set_addresses(Link *link) { return 0; } - r = sd_dhcp_server_set_address(link->dhcp_server, - &address->in_addr.in, - address->prefixlen); - if (r < 0) - return r; - - /* offer 32 addresses starting from the address following the server address */ - pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1); - r = sd_dhcp_server_set_lease_pool(link->dhcp_server, - &pool_start, 32); + /* use the server address' subnet as the pool */ + r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen, + link->network->dhcp_server_pool_offset, link->network->dhcp_server_pool_size); if (r < 0) return r; @@ -760,11 +752,6 @@ static int link_enter_set_addresses(Link *link) { &main_address->in_addr.in); if (r < 0) return r; - - r = sd_dhcp_server_set_prefixlen(link->dhcp_server, - main_address->prefixlen); - if (r < 0) - return r; */ if (link->network->dhcp_server_max_lease_time_usec > 0) { diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 9469160eba..e0bd0e024a 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -39,6 +39,7 @@ Tunnel.DiscoverPathMTU, config_parse_bool, 0, Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode) Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel) Tunnel.CopyDSCP, config_parse_bool, 0, offsetof(Tunnel, copy_dscp) +Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit) Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer) Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer) VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id) diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 265e67b7e3..a906e473b6 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -284,6 +284,12 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl if (t->copy_dscp) t->flags |= IP6_TNL_F_RCV_DSCP_COPY; + if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) { + r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m"); + } + r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m"); @@ -442,6 +448,45 @@ int config_parse_ipv6_flowlabel(const char* unit, return 0; } +int config_parse_encap_limit(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) { + Tunnel *t = userdata; + int k = 0; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (streq(rvalue, "none")) + t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; + else { + r = safe_atoi(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue); + return 0; + } + + if (k > 255 || k < 0) + log_syntax(unit, LOG_ERR, filename, line, k, "Invalid Tunnel Encapsulation value, ignoring: %d", k); + else { + t->encap_limit = k; + t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; + } + } + + return 0; +} + static void ipip_init(NetDev *n) { Tunnel *t = IPIP(n); diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index e4fa74aef4..fa7decce18 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -95,3 +95,9 @@ int config_parse_ipv6_flowlabel(const char *unit, const char *filename, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_encap_limit(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/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 108e892fb8..10ca9dae35 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -82,6 +82,8 @@ DHCPServer.EmitNTP, config_parse_bool, 0 DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0 DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone) DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) +DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset) +DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size) Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) Bridge.UseBPDU, config_parse_bool, 0, offsetof(Network, use_bpdu) Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index d691cc3a45..c3439a70ba 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -102,6 +102,8 @@ struct Network { bool dhcp_server_emit_timezone; char *dhcp_server_timezone; usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec; + uint32_t dhcp_server_pool_offset; + uint32_t dhcp_server_pool_size; /* IPV4LL Support */ AddressFamilyBoolean link_local; diff --git a/src/shared/Makefile b/src/shared/Makefile new file mode 120000 index 0000000000..d0b0e8e008 --- /dev/null +++ b/src/shared/Makefile @@ -0,0 +1 @@ +../Makefile
\ No newline at end of file diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index d99aa1d6e9..1f4aea6d6b 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -450,6 +450,7 @@ int config_parse_many(const char *conf_file, DEFINE_PARSER(int, int, safe_atoi) DEFINE_PARSER(long, long, safe_atoli) +DEFINE_PARSER(uint32, uint32_t, safe_atou32) DEFINE_PARSER(uint64, uint64_t, safe_atou64) DEFINE_PARSER(unsigned, unsigned, safe_atou) DEFINE_PARSER(double, double, safe_atod) diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 6152ee33b9..66c80890d3 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -104,6 +104,7 @@ int config_parse_many(const char *conf_file, /* possibly NULL */ int config_parse_int(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unsigned(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_long(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_uint32(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_uint64(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_double(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_iec_size(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/shared/pager.c b/src/shared/pager.c index 85f8fa5b39..3992f9c837 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -82,7 +82,7 @@ int pager_open(bool jump_to_end) { /* In the child start the pager */ if (pager_pid == 0) { - const char* less_opts; + const char* less_opts, *less_charset; (void) reset_all_signal_handlers(); (void) reset_signal_mask(); @@ -90,6 +90,7 @@ int pager_open(bool jump_to_end) { dup2(fd[0], STDIN_FILENO); safe_close_pair(fd); + /* Initialize a good set of less options */ less_opts = getenv("SYSTEMD_LESS"); if (!less_opts) less_opts = "FRSXMK"; @@ -97,6 +98,15 @@ int pager_open(bool jump_to_end) { less_opts = strjoina(less_opts, " +G"); setenv("LESS", less_opts, 1); + /* Initialize a good charset for less. This is + * particularly important if we output UTF-8 + * characters. */ + less_charset = getenv("SYSTEMD_LESSCHARSET"); + if (!less_charset && is_locale_utf8()) + less_charset = "utf-8"; + if (less_charset) + setenv("LESSCHARSET", less_charset, 1); + /* Make sure the pager goes away when the parent dies */ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) _exit(EXIT_FAILURE); diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 7e4f2ffb30..4b0c7a1852 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -44,8 +44,7 @@ bool sd_dhcp_server_is_running(sd_dhcp_server *server); int sd_dhcp_server_start(sd_dhcp_server *server); int sd_dhcp_server_stop(sd_dhcp_server *server); -int sd_dhcp_server_set_address(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen); -int sd_dhcp_server_set_lease_pool(sd_dhcp_server *server, struct in_addr *start, size_t size); +int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *address, unsigned char prefixlen, uint32_t offset, uint32_t size); int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone); int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n); |