From 21b587cfd903722eef136aef9090882ad098334a Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 23 May 2016 09:33:44 -0400 Subject: man: explain what list-units does a bit better (#3324) https://bugzilla.redhat.com/show_bug.cgi?id=1338584 --- man/systemctl.xml | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'man') diff --git a/man/systemctl.xml b/man/systemctl.xml index 991e9bafaf..2288f65d16 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -150,11 +150,11 @@ - When listing units, show all loaded units, regardless - of their state, including inactive units. When showing - unit/job/manager properties, show all properties regardless - whether they are set or not. - To list all units installed on the system, use the + When listing units with list-units, also show inactive units and + units which are following other units. When showing unit/job/manager properties, show all + properties regardless whether they are set or not. + + To list all units installed in the file system, use the list-unit-files command instead. @@ -638,10 +638,13 @@ list-units PATTERN... - List known units (subject to limitations specified - with ). If one or more - PATTERNs are specified, only - units matching one of them are shown. + List units that systemd has loaded. This includes units that + are either referenced directly or through a dependency, or units that were active in the + past and have failed. By default only units which are active, have pending jobs, or have + failed are shown; this can be changed with option . If one or more + PATTERNs are specified, only units matching one of them are + shown. The units that are shown are additionally filtered by + and if those options are specified. This is the default command. @@ -970,11 +973,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service list-unit-files PATTERN... - List installed unit files and their enablement state - (as reported by is-enabled). If one or - more PATTERNs are specified, - only units whose filename (just the last component of the - path) matches one of them are shown. + List unit files installed in the file system and their enablement state + (as reported by is-enabled). If one or more + PATTERNs are specified, only units whose filename + (just the last component of the path) matches one of them are shown. -- cgit v1.2.3-54-g00ecf From da4d897e75e574911cb73ac91fdeef7d4fce8fbe Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 27 May 2016 09:10:18 -0700 Subject: core: add cgroup memory controller support on the unified hierarchy (#3315) On the unified hierarchy, memory controller implements three control knobs - low, high and max which enables more useable and versatile control over memory usage. This patch implements support for the three control knobs. * MemoryLow, MemoryHigh and MemoryMax are added for memory.low, memory.high and memory.max, respectively. * As all absolute limits on the unified hierarchy use "max" for no limit, make memory limit parse functions accept "max" in addition to "infinity" and document "max" for the new knobs. * Implement compatibility translation between MemoryMax and MemoryLimit. v2: - Fixed missing else's in config_parse_memory_limit(). - Fixed missing newline when writing out drop-ins. - Coding style updates to use "val > 0" instead of "val". - Minor updates to documentation. --- man/systemd.resource-control.xml | 71 +++++++++++++++++++++++++++++++++++ src/core/cgroup.c | 63 +++++++++++++++++++++++-------- src/core/cgroup.h | 4 ++ src/core/dbus-cgroup.c | 28 ++++++++++++++ src/core/load-fragment-gperf.gperf.m4 | 3 ++ src/core/load-fragment.c | 25 +++++++----- src/shared/bus-unit-util.c | 6 +-- src/systemctl/systemctl.c | 39 +++++++++++++++++-- 8 files changed, 206 insertions(+), 33 deletions(-) (limited to 'man') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 066f2cc19b..570619a743 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -114,6 +114,13 @@ prefixed ones. On unified hierarchy, IO resource control also applies to buffered writes. + + + + MemoryMax replaces MemoryLimit. MemoryLow + and MemoryHigh are effective only on unified hierarchy. + + @@ -212,6 +219,67 @@ + + MemoryLow=bytes + + + Specify the best-effort memory usage protection of the executed processes in this unit. If the memory + usages of this unit and all its ancestors are below their low boundaries, this unit's memory won't be + reclaimed as long as memory can be reclaimed from unprotected units. + + Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. This controls the + memory.low control group attribute. For details about this control group attribute, see + cgroup-v2.txt. + + Implies MemoryAccounting=true. + + This setting is supported only if the unified control group hierarchy is used. + + + + + MemoryHigh=bytes + + + Specify the high limit on memory usage of the executed processes in this unit. Memory usage may go + above the limit if unavoidable, but the processes are heavily slowed down and memory is taken away + aggressively in such cases. This is the main mechanism to control memory usage of a unit. + + Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the + special value max, no memory limit is applied. This controls the + memory.high control group attribute. For details about this control group attribute, see + cgroup-v2.txt. + + Implies MemoryAccounting=true. + + This setting is supported only if the unified control group hierarchy is used. + + + + + MemoryMax=bytes + + + Specify the absolute limit on memory usage of the executed processes in this unit. If memory usage + cannot be contained under the limit, out-of-memory killer is invoked inside the unit. It is recommended to + use MemoryHigh= as the main control mechanism and use MemoryMax= as the + last line of defense. + + Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the + special value max, no memory limit is applied. This controls the + memory.max control group attribute. For details about this control group attribute, see + cgroup-v2.txt. + + Implies MemoryAccounting=true. + + This setting is supported only if the unified control group hierarchy is used. Use + MemoryLimit= on systems using the legacy control group hierarchy. + + + MemoryLimit=bytes @@ -230,6 +298,9 @@ url="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt">memory.txt. Implies MemoryAccounting=true. + + This setting is supported only if the legacy control group hierarchy is used. Use + MemoryMax= on systems using the unified control group hierarchy. diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 0fb63b1bd1..fbe69df4e9 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -46,7 +46,10 @@ void cgroup_context_init(CGroupContext *c) { c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID; c->cpu_quota_per_sec_usec = USEC_INFINITY; - c->memory_limit = (uint64_t) -1; + c->memory_high = CGROUP_LIMIT_MAX; + c->memory_max = CGROUP_LIMIT_MAX; + + c->memory_limit = CGROUP_LIMIT_MAX; c->io_weight = CGROUP_WEIGHT_INVALID; c->startup_io_weight = CGROUP_WEIGHT_INVALID; @@ -147,6 +150,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { "%sStartupIOWeight=%" PRIu64 "\n" "%sBlockIOWeight=%" PRIu64 "\n" "%sStartupBlockIOWeight=%" PRIu64 "\n" + "%sMemoryLow=%" PRIu64 "\n" + "%sMemoryHigh=%" PRIu64 "\n" + "%sMemoryMax=%" PRIu64 "\n" "%sMemoryLimit=%" PRIu64 "\n" "%sTasksMax=%" PRIu64 "\n" "%sDevicePolicy=%s\n" @@ -163,6 +169,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { prefix, c->startup_io_weight, prefix, c->blockio_weight, prefix, c->startup_blockio_weight, + prefix, c->memory_low, + prefix, c->memory_high, + prefix, c->memory_max, prefix, c->memory_limit, prefix, c->tasks_max, prefix, cgroup_device_policy_to_string(c->device_policy), @@ -496,6 +505,23 @@ static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *de return n; } +static bool cgroup_context_has_unified_memory_config(CGroupContext *c) { + return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX; +} + +static void cgroup_apply_unified_memory_limit(const char *path, const char *file, uint64_t v) { + char buf[DECIMAL_STR_MAX(uint64_t) + 1] = "max"; + int r; + + if (v != CGROUP_LIMIT_MAX) + xsprintf(buf, "%" PRIu64 "\n", v); + + r = cg_set_attribute("memory", path, file, buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set %s on %s: %m", file, path); +} + void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) { bool is_root; int r; @@ -662,26 +688,30 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M } if ((mask & CGROUP_MASK_MEMORY) && !is_root) { - if (c->memory_limit != (uint64_t) -1) { - char buf[DECIMAL_STR_MAX(uint64_t) + 1]; - - sprintf(buf, "%" PRIu64 "\n", c->memory_limit); + if (cg_unified() > 0) { + uint64_t max = c->memory_max; - if (cg_unified() <= 0) - r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); + if (cgroup_context_has_unified_memory_config(c)) + max = c->memory_max; else - r = cg_set_attribute("memory", path, "memory.max", buf); + max = c->memory_limit; + cgroup_apply_unified_memory_limit(path, "memory.low", c->memory_low); + cgroup_apply_unified_memory_limit(path, "memory.high", c->memory_high); + cgroup_apply_unified_memory_limit(path, "memory.max", max); } else { - if (cg_unified() <= 0) - r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1"); + char buf[DECIMAL_STR_MAX(uint64_t) + 1]; + + if (c->memory_limit != CGROUP_LIMIT_MAX) + xsprintf(buf, "%" PRIu64 "\n", c->memory_limit); else - r = cg_set_attribute("memory", path, "memory.max", "max"); - } + xsprintf(buf, "%" PRIu64 "\n", c->memory_max); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set memory.limit_in_bytes/memory.max on %s: %m", path); + r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); + if (r < 0) + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to set memory.limit_in_bytes on %s: %m", path); + } } if ((mask & CGROUP_MASK_DEVICES) && !is_root) { @@ -778,7 +808,8 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) { mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; if (c->memory_accounting || - c->memory_limit != (uint64_t) -1) + c->memory_limit != CGROUP_LIMIT_MAX || + cgroup_context_has_unified_memory_config(c)) mask |= CGROUP_MASK_MEMORY; if (c->device_allow || diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 2b1edbafc4..ff87adfba1 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -94,6 +94,10 @@ struct CGroupContext { LIST_HEAD(CGroupIODeviceWeight, io_device_weights); LIST_HEAD(CGroupIODeviceLimit, io_device_limits); + uint64_t memory_low; + uint64_t memory_high; + uint64_t memory_max; + /* For legacy hierarchies */ uint64_t cpu_shares; uint64_t startup_cpu_shares; diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index d6053581f8..27050b4507 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -228,6 +228,9 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0), SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0), + SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0), + SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0), + SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0), SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), @@ -826,6 +829,31 @@ int bus_cgroup_set_property( return 1; + } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax")) { + uint64_t v; + + r = sd_bus_message_read(message, "t", &v); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + if (streq(name, "MemoryLow")) + c->memory_low = v; + else if (streq(name, "MemoryHigh")) + c->memory_high = v; + else + c->memory_max = v; + + unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY); + + if (v == CGROUP_LIMIT_MAX) + unit_write_drop_in_private_format(u, mode, name, "%s=max\n", name); + else + unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, v); + } + + return 1; + } else if (streq(name, "MemoryLimit")) { uint64_t limit; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 8193418980..00bdc238ce 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -117,6 +117,9 @@ $1.CPUShares, config_parse_cpu_shares, 0, $1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares) $1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context) $1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting) +$1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context) +$1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context) +$1.MemoryMax, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context) $1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context) $1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 86b4fb071b..09d3f65c77 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2793,21 +2793,26 @@ int config_parse_memory_limit( void *userdata) { CGroupContext *c = data; - uint64_t bytes; + uint64_t bytes = CGROUP_LIMIT_MAX; int r; - if (isempty(rvalue) || streq(rvalue, "infinity")) { - c->memory_limit = (uint64_t) -1; - return 0; + if (!isempty(rvalue) && !streq(rvalue, "infinity") && !streq(rvalue, "max")) { + r = parse_size(rvalue, 1024, &bytes); + if (r < 0 || bytes < 1) { + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } } - r = parse_size(rvalue, 1024, &bytes); - if (r < 0 || bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); - return 0; - } + if (streq(lvalue, "MemoryLow")) + c->memory_low = bytes; + else if (streq(lvalue, "MemoryHigh")) + c->memory_high = bytes; + else if (streq(lvalue, "MemoryMax")) + c->memory_max = bytes; + else + c->memory_limit = bytes; - c->memory_limit = bytes; return 0; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index f68c4a41ac..502e98d9dc 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -166,11 +166,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "b", r); - } else if (streq(field, "MemoryLimit")) { + } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { uint64_t bytes; - if (isempty(eq) || streq(eq, "infinity")) - bytes = (uint64_t) -1; + if (isempty(eq) || streq(eq, "max") || streq(eq, "infinity")) + bytes = CGROUP_LIMIT_MAX; else { r = parse_size(eq, 1024, &bytes); if (r < 0) { diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0500593d06..b2ee00fab3 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3493,6 +3493,9 @@ typedef struct UnitStatusInfo { /* CGroup */ uint64_t memory_current; + uint64_t memory_low; + uint64_t memory_high; + uint64_t memory_max; uint64_t memory_limit; uint64_t cpu_usage_nsec; uint64_t tasks_current; @@ -3775,10 +3778,30 @@ static void print_status_info( printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current)); - if (i->memory_limit != (uint64_t) -1) - printf(" (limit: %s)\n", format_bytes(buf, sizeof(buf), i->memory_limit)); - else - printf("\n"); + if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX || + i->memory_limit != CGROUP_LIMIT_MAX) { + const char *prefix = ""; + + printf(" ("); + if (i->memory_low > 0) { + printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low)); + prefix = " "; + } + if (i->memory_high != CGROUP_LIMIT_MAX) { + printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high)); + prefix = " "; + } + if (i->memory_max != CGROUP_LIMIT_MAX) { + printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max)); + prefix = " "; + } + if (i->memory_limit != CGROUP_LIMIT_MAX) { + printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit)); + prefix = " "; + } + printf(")"); + } + printf("\n"); } if (i->cpu_usage_nsec != (uint64_t) -1) { @@ -4007,6 +4030,12 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * i->assert_timestamp = (usec_t) u; else if (streq(name, "MemoryCurrent")) i->memory_current = u; + else if (streq(name, "MemoryLow")) + i->memory_low = u; + else if (streq(name, "MemoryHigh")) + i->memory_high = u; + else if (streq(name, "MemoryMax")) + i->memory_max = u; else if (streq(name, "MemoryLimit")) i->memory_limit = u; else if (streq(name, "TasksCurrent")) @@ -4500,6 +4529,8 @@ static int show_one( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; UnitStatusInfo info = { .memory_current = (uint64_t) -1, + .memory_high = CGROUP_LIMIT_MAX, + .memory_max = CGROUP_LIMIT_MAX, .memory_limit = (uint64_t) -1, .cpu_usage_nsec = (uint64_t) -1, .tasks_current = (uint64_t) -1, -- cgit v1.2.3-54-g00ecf From 0663a4a6ee129e9c633b990050f3610adc7dfccb Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 28 May 2016 16:43:22 -0400 Subject: man: punctuation fixes Fixes #3376. --- man/systemd-system-update-generator.xml | 2 +- man/systemd.generator.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'man') diff --git a/man/systemd-system-update-generator.xml b/man/systemd-system-update-generator.xml index e7fc95c742..58ae70f615 100644 --- a/man/systemd-system-update-generator.xml +++ b/man/systemd-system-update-generator.xml @@ -54,7 +54,7 @@ systemd-system-update-generator is a generator that automatically redirects the boot process to - system-update.target if + system-update.target, if /system-update exists. This is required to implement the logic explained in the System diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml index 4b80dab108..919c8f8080 100644 --- a/man/systemd.generator.xml +++ b/man/systemd.generator.xml @@ -166,7 +166,7 @@ process. That includes simple things such as logging to syslog3, or systemd itself (this means: no - systemctl1)!. + systemctl1)! Non-essential file systems like /var and /home are mounted after generators have run. Generators @@ -309,7 +309,7 @@ systemd-system-update-generator8 temporarily redirects default.target to - system-update.target if a system update is + system-update.target, if a system update is scheduled. Since this needs to override the default user configuration for default.target, it uses argv[2]. For details about this logic, see -- cgit v1.2.3-54-g00ecf From 49174f75514bf1033dd6916176a551a923b77dc5 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 28 May 2016 16:49:43 -0400 Subject: man: cite systemd.offline-updates(7) instead of linking to old wiki page --- man/systemd-system-update-generator.xml | 5 ++--- man/systemd.generator.xml | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'man') diff --git a/man/systemd-system-update-generator.xml b/man/systemd-system-update-generator.xml index 58ae70f615..833ed79646 100644 --- a/man/systemd-system-update-generator.xml +++ b/man/systemd-system-update-generator.xml @@ -56,9 +56,8 @@ generator that automatically redirects the boot process to system-update.target, if /system-update exists. This is required to - implement the logic explained in the System - Updates Specification. + implement the logic explained in the + systemd.offline-updates7. systemd-system-update-generator implements diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml index 919c8f8080..b268104c9d 100644 --- a/man/systemd.generator.xml +++ b/man/systemd.generator.xml @@ -313,8 +313,8 @@ scheduled. Since this needs to override the default user configuration for default.target, it uses argv[2]. For details about this logic, see - Implementing - Offline System Updates. + systemd.offline-updates7. + -- cgit v1.2.3-54-g00ecf From 008dce3875cd7074c3534ef8f4835e80f76c0ce3 Mon Sep 17 00:00:00 2001 From: Luca Bruno Date: Mon, 30 May 2016 13:43:53 +0200 Subject: man: fix recurring typo --- man/systemd.exec.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 3cf6de8256..5c47e0f329 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1160,7 +1160,7 @@ effect is inverted: only the listed system calls will result in immediate process termination (blacklisting). If running in user mode, or in system mode, but without the - CAP_SYS_ADMIN capabiblity (e.g. setting + CAP_SYS_ADMIN capability (e.g. setting User=nobody), NoNewPrivileges=yes is implied. This feature makes use of the Secure Computing Mode 2 interfaces of @@ -1222,7 +1222,7 @@ more strictly: to the architecture the system manager is compiled for). If running in user mode, or in system mode, but without the CAP_SYS_ADMIN - capabiblity (e.g. setting User=nobody), + capability (e.g. setting User=nobody), NoNewPrivileges=yes is implied. Note that setting this option to a non-empty list implies that native is included too. By default, this @@ -1254,7 +1254,7 @@ has no effect on 32-bit x86 and is ignored (but works correctly on x86-64). If running in user mode, or in system mode, but without the CAP_SYS_ADMIN - capabiblity (e.g. setting User=nobody), + capability (e.g. setting User=nobody), NoNewPrivileges=yes is implied. By default, no restriction applies, all address families are accessible to processes. If assigned the empty string, any -- cgit v1.2.3-54-g00ecf From 043cc7151278794c4f00161b81d718f9507fdb32 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Mon, 30 May 2016 16:37:07 +0200 Subject: doc: clarify systemd.exec's paths definition (#3368) Definitions of ReadWriteDirectories=, ReadOnlyDirectories=, InaccessibleDirectories=, WorkingDirectory=, and RootDirecory= were not clear. This patch specifies when they are relative to the host's root directory and when they are relative to the service's root directory. Fixes #3248 --- man/systemd.exec.xml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 5c47e0f329..4d52982b64 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -107,7 +107,8 @@ WorkingDirectory= - Takes an absolute directory path, or the + Takes a directory path relative to the service's root + directory specified by RootDirectory=, or the special value ~. Sets the working directory for executed processes. If set to ~, the home directory of the user specified in @@ -116,7 +117,10 @@ and the respective user's home directory if run as user. If the setting is prefixed with the - character, a missing working directory is not considered - fatal. Note that setting this parameter might result in + fatal. If RootDirectory= is not set, then + WorkingDirectory= is relative to the root of + the system running the service manager. + Note that setting this parameter might result in additional dependencies to be added to the unit (see above). @@ -124,7 +128,8 @@ RootDirectory= - Takes an absolute directory path. Sets the + Takes a directory path relative to the host's root directory + (i.e. the root of the system running the service manager). Sets the root directory for executed processes, with the chroot2 system call. If this is used, it must be ensured that the @@ -848,8 +853,9 @@ Sets up a new file system namespace for executed processes. These options may be used to limit access a process might have to the main file system hierarchy. Each - setting takes a space-separated list of absolute directory - paths. Directories listed in + setting takes a space-separated list of directory paths relative to + the host's root directory (i.e. the system running the service manager). + Directories listed in ReadWriteDirectories= are accessible from within the namespace with the same access rights as from outside. Directories listed in -- cgit v1.2.3-54-g00ecf From c6f8d17de0c36f94213496e2c9fd013f113ebe08 Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Mon, 30 May 2016 17:00:16 +0200 Subject: networkd: bridge add support to configure VLAN filtering (#3344) This patch implements support for IFLA_BR_VLAN_FILTERING configuration. --- man/systemd.netdev.xml | 9 +++++++++ src/network/networkd-netdev-bridge.c | 7 +++++++ src/network/networkd-netdev-bridge.h | 1 + src/network/networkd-netdev-gperf.gperf | 1 + 4 files changed, 18 insertions(+) (limited to 'man') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 8d12c305d2..cde5d65949 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -330,6 +330,15 @@ + + VLANFiltering= + + A boolean. This setting controls the IFLA_BR_VLAN_FILTERING option in the kernel. + If enabled, the bridge will be started in VLAN-filtering mode. When unset, the kernel's + default setting applies. + + + diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index 4cfd00413f..a5085d2b19 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -102,6 +102,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m"); } + if (b->vlan_filtering >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BR_VLAN_FILTERING, b->vlan_filtering); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_FILTERING attribute: %m"); + } + r = sd_netlink_message_close_container(req); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); @@ -128,6 +134,7 @@ static void bridge_init(NetDev *n) { b->mcast_querier = -1; b->mcast_snooping = -1; + b->vlan_filtering = -1; } const NetDevVTable bridge_vtable = { diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index f2ae21fc50..a637aea0a3 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -26,6 +26,7 @@ typedef struct Bridge { int mcast_querier; int mcast_snooping; + int vlan_filtering; usec_t forward_delay; usec_t hello_time; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index ba04bb0165..adc64977b9 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -100,3 +100,4 @@ Bridge.MaxAgeSec, config_parse_sec, 0, Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay) Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier) Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping) +Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering) -- cgit v1.2.3-54-g00ecf From 924e44b41932d1811e4f516adfb2840f468b33d2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 31 May 2016 01:49:57 +0200 Subject: man: document that systemctl -ff reboot does not require PID 1 to work (#3310) As suggested in https://github.com/systemd/systemd/issues/3282#issuecomment-220264509 --- man/systemctl.xml | 80 +++++++++++++++++++++++++------------------------------ 1 file changed, 37 insertions(+), 43 deletions(-) (limited to 'man') diff --git a/man/systemctl.xml b/man/systemctl.xml index 2288f65d16..914af929c8 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -481,19 +481,16 @@ When used with enable, overwrite any existing conflicting symlinks. - When used with halt, - poweroff, reboot or - kexec, execute the selected operation - without shutting down all units. However, all processes will - be killed forcibly and all file systems are unmounted or - remounted read-only. This is hence a drastic but relatively - safe option to request an immediate reboot. If - is specified twice for these - operations, they will be executed immediately without - terminating any processes or unmounting any file - systems. Warning: specifying twice - with any of these operations might result in data - loss. + When used with halt, poweroff, reboot or + kexec, execute the selected operation without shutting down all units. However, all + processes will be killed forcibly and all file systems are unmounted or remounted read-only. This is hence a + drastic but relatively safe option to request an immediate reboot. If is specified + twice for these operations (with the exception of kexec), they will be executed + immediately, without terminating any processes or unmounting any file systems. Warning: specifying + twice with any of these operations might result in data loss. Note that when + is specified twice the selected operation is executed by + systemctl itself, and the system manager is not contacted. This means the command should + succeed even when the system manager hangs or crashed. @@ -1602,48 +1599,45 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service halt - Shut down and halt the system. This is mostly equivalent to - start halt.target --job-mode=replace-irreversibly, but also - prints a wall message to all users. If combined with - , shutdown of all running services is - skipped, however all processes are killed and all file - systems are unmounted or mounted read-only, immediately - followed by the system halt. If is - specified twice, the operation is immediately executed - without terminating any processes or unmounting any file - systems. This may result in data loss. + Shut down and halt the system. This is mostly equivalent to start halt.target + --job-mode=replace-irreversibly, but also prints a wall message to all users. If combined with + , shutdown of all running services is skipped, however all processes are killed and + all file systems are unmounted or mounted read-only, immediately followed by the system halt. If + is specified twice, the operation is immediately executed without terminating any + processes or unmounting any file systems. This may result in data loss. Note that when + is specified twice the halt operation is executed by + systemctl itself, and the system manager is not contacted. This means the command should + succeed even when the system manager hangs or crashed. poweroff - Shut down and power-off the system. This is mostly - equivalent to start poweroff.target --job-mode=replace-irreversibly, - but also prints a wall message to all users. If combined with - , shutdown of all running services is - skipped, however all processes are killed and all file - systems are unmounted or mounted read-only, immediately - followed by the powering off. If is - specified twice, the operation is immediately executed - without terminating any processes or unmounting any file - systems. This may result in data loss. + Shut down and power-off the system. This is mostly equivalent to start poweroff.target + --job-mode=replace-irreversibly, but also prints a wall message to all users. If combined with + , shutdown of all running services is skipped, however all processes are killed and + all file systems are unmounted or mounted read-only, immediately followed by the powering off. If + is specified twice, the operation is immediately executed without terminating any + processes or unmounting any file systems. This may result in data loss. Note that when + is specified twice the power-off operation is executed by + systemctl itself, and the system manager is not contacted. This means the command should + succeed even when the system manager hangs or crashed. reboot arg - Shut down and reboot the system. This is mostly - equivalent to start reboot.target --job-mode=replace-irreversibly, - but also prints a wall message to all users. If combined with - , shutdown of all running services is - skipped, however all processes are killed and all file - systems are unmounted or mounted read-only, immediately - followed by the reboot. If is - specified twice, the operation is immediately executed - without terminating any processes or unmounting any file - systems. This may result in data loss. + Shut down and reboot the system. This is mostly equivalent to start reboot.target + --job-mode=replace-irreversibly, but also prints a wall message to all users. If combined with + , shutdown of all running services is skipped, however all processes are killed and + all file systems are unmounted or mounted read-only, immediately followed by the reboot. If + is specified twice, the operation is immediately executed without terminating any + processes or unmounting any file systems. This may result in data loss. Note that when + is specified twice the reboot operation is executed by + systemctl itself, and the system manager is not contacted. This means the command should + succeed even when the system manager hangs or crashed. If the optional argument arg is given, it will be passed -- cgit v1.2.3-54-g00ecf From 201c1cc22a41df1f4ef7706bde41e2536bef433f Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Wed, 1 Jun 2016 09:56:01 +0000 Subject: core: add pre-defined syscall groups to SystemCallFilter= (#3053) (#3157) Implement sets of system calls to help constructing system call filters. A set starts with '@' to distinguish from a system call. Closes: #3053, #3157 --- man/systemd.exec.xml | 73 +++++++++++++++- src/core/load-fragment.c | 95 +++++++++++--------- src/shared/seccomp-util.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++ src/shared/seccomp-util.h | 7 ++ 4 files changed, 350 insertions(+), 41 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 4d52982b64..58f18f3a9e 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1193,7 +1193,78 @@ read and write, and right after it add a blacklisting of write, then write - will be removed from the set.) + will be removed from the set.) + + As the number of possible system + calls is large, predefined sets of system calls are provided. + A set starts with @ character, followed by + name of the set. + + + Currently predefined system call sets + + + + + + + Set + Description + + + + + @clock + System calls for changing the system clock (adjtimex(), + settimeofday()) + + + @io-event + Event loop use (poll(), select(), + epoll7, + eventfd()...) + + + @ipc + SysV IPC, POSIX Message Queues or other IPC (mq_overview7, + svipc7) + + + @module + Kernel module control (create_module(), init_module()...) + + + @mount + File system mounting and unmounting (chroot(), mount()...) + + + @network-io + Socket I/O (including local AF_UNIX): + socket7, + unix7 + + + @obsolete + Unusual, obsolete or unimplemented (fattach(), gtty(), vm86()...) + + + @privileged + All system calls which need superuser capabilities (capabilities7) + + + @process + Process control, execution, namespaces (execve(), kill(), namespaces7...) + + + @raw-io + Raw I/O ports (ioperm(), iopl(), pciconfig_read()...) + + + +
+ + Note, that as new system calls are added to the kernel, additional system calls might be added to the groups + above, so the contents of the sets may change between systemd versions.
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 09d3f65c77..50ff718aab 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2396,6 +2396,55 @@ int config_parse_documentation(const char *unit, } #ifdef HAVE_SECCOMP +static int syscall_filter_parse_one( + const char *unit, + const char *filename, + unsigned line, + ExecContext *c, + bool invert, + const char *t, + bool warn) { + int r; + + if (*t == '@') { + const SystemCallFilterSet *set; + + for (set = syscall_filter_sets; set->set_name; set++) + if (streq(set->set_name, t)) { + const char *sys; + + NULSTR_FOREACH(sys, set->value) { + r = syscall_filter_parse_one(unit, filename, line, c, invert, sys, false); + if (r < 0) + return r; + } + break; + } + } else { + int id; + + id = seccomp_syscall_resolve_name(t); + if (id < 0) { + if (warn) + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); + return 0; + } + + /* If we previously wanted to forbid a syscall and now + * we want to allow it, then remove it from the list + */ + if (!invert == c->syscall_whitelist) { + r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); + if (r == 0) + return 0; + if (r < 0) + return log_oom(); + } else + set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); + } + return 0; +} + int config_parse_syscall_filter( const char *unit, const char *filename, @@ -2408,13 +2457,6 @@ int config_parse_syscall_filter( void *data, void *userdata) { - static const char default_syscalls[] = - "execve\0" - "exit\0" - "exit_group\0" - "rt_sigreturn\0" - "sigreturn\0"; - ExecContext *c = data; Unit *u = userdata; bool invert = false; @@ -2448,53 +2490,26 @@ int config_parse_syscall_filter( /* Allow everything but the ones listed */ c->syscall_whitelist = false; else { - const char *i; - /* Allow nothing but the ones listed */ c->syscall_whitelist = true; /* Accept default syscalls if we are on a whitelist */ - NULSTR_FOREACH(i, default_syscalls) { - int id; - - id = seccomp_syscall_resolve_name(i); - if (id < 0) - continue; - - r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); - if (r == 0) - continue; - if (r < 0) - return log_oom(); - } + r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false); + if (r < 0) + return r; } } FOREACH_WORD_QUOTED(word, l, rvalue, state) { _cleanup_free_ char *t = NULL; - int id; t = strndup(word, l); if (!t) return log_oom(); - id = seccomp_syscall_resolve_name(t); - if (id < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); - continue; - } - - /* If we previously wanted to forbid a syscall and now - * we want to allow it, then remove it from the list - */ - if (!invert == c->syscall_whitelist) { - r = set_put(c->syscall_filter, INT_TO_PTR(id + 1)); - if (r == 0) - continue; - if (r < 0) - return log_oom(); - } else - set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); + r = syscall_filter_parse_one(unit, filename, line, c, invert, t, true); + if (r < 0) + return r; } if (!isempty(state)) log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index cebe0fce2a..30d22d2242 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -88,3 +88,219 @@ int seccomp_add_secondary_archs(scmp_filter_ctx *c) { return 0; } + +const SystemCallFilterSet syscall_filter_sets[] = { + { + /* Clock */ + .set_name = "@clock", + .value = + "adjtimex\0" + "settimeofday\0" + }, { + /* Default list */ + .set_name = "@default", + .value = + "execve\0" + "exit\0" + "exit_group\0" + "rt_sigreturn\0" + "sigreturn\0" + }, { + /* Event loop use */ + .set_name = "@io-event", + .value = + "_newselect\0" + "epoll_create1\0" + "epoll_create\0" + "epoll_ctl\0" + "epoll_ctl_old\0" + "epoll_pwait\0" + "epoll_wait\0" + "epoll_wait_old\0" + "eventfd2\0" + "eventfd\0" + "poll\0" + "ppoll\0" + "pselect6\0" + "select\0" + }, { + /* Message queues, SYSV IPC or other IPC: unusual */ + .set_name = "@ipc", + .value = "ipc\0" + "mq_getsetattr\0" + "mq_notify\0" + "mq_open\0" + "mq_timedreceive\0" + "mq_timedsend\0" + "mq_unlink\0" + "msgctl\0" + "msgget\0" + "msgrcv\0" + "msgsnd\0" + "process_vm_readv\0" + "process_vm_writev\0" + "semctl\0" + "semget\0" + "semop\0" + "semtimedop\0" + "shmat\0" + "shmctl\0" + "shmdt\0" + "shmget\0" + }, { + /* Kernel module control */ + .set_name = "@module", + .value = + "create_module\0" + "delete_module\0" + "finit_module\0" + "init_module\0" + }, { + /* Mounting */ + .set_name = "@mount", + .value = + "chroot\0" + "mount\0" + "oldumount\0" + "pivot_root\0" + "umount2\0" + "umount\0" + }, { + /* Network or Unix socket IO, should not be needed if not network facing */ + .set_name = "@network-io", + .value = + "accept4\0" + "accept\0" + "bind\0" + "connect\0" + "getpeername\0" + "getsockname\0" + "getsockopt\0" + "listen\0" + "recv\0" + "recvfrom\0" + "recvmmsg\0" + "recvmsg\0" + "send\0" + "sendmmsg\0" + "sendmsg\0" + "sendto\0" + "setsockopt\0" + "shutdown\0" + "socket\0" + "socketcall\0" + "socketpair\0" + }, { + /* Unusual, obsolete or unimplemented, some unknown even to libseccomp */ + .set_name = "@obsolete", + .value = + "_sysctl\0" + "afs_syscall\0" + "break\0" + "fattach\0" + "fdetach\0" + "ftime\0" + "get_kernel_syms\0" + "get_mempolicy\0" + "getmsg\0" + "getpmsg\0" + "gtty\0" + "isastream\0" + "lock\0" + "madvise1\0" + "modify_ldt\0" + "mpx\0" + "pciconfig_iobase\0" + "perf_event_open\0" + "prof\0" + "profil\0" + "putmsg\0" + "putpmsg\0" + "query_module\0" + "rtas\0" + "s390_runtime_instr\0" + "security\0" + "sgetmask\0" + "ssetmask\0" + "stty\0" + "subpage_prot\0" + "switch_endian\0" + "sys_debug_setcontext\0" + "tuxcall\0" + "ulimit\0" + "uselib\0" + "vm86\0" + "vm86old\0" + "vserver\0" + }, { + /* Nice grab-bag of all system calls which need superuser capabilities */ + .set_name = "@privileged", + .value = + "@clock\0" + "@module\0" + "@raw-io\0" + "acct\0" + "bdflush\0" + "bpf\0" + "chown32\0" + "chown\0" + "chroot\0" + "fchown32\0" + "fchown\0" + "fchownat\0" + "kexec_file_load\0" + "kexec_load\0" + "lchown32\0" + "lchown\0" + "nfsservctl\0" + "pivot_root\0" + "quotactl\0" + "reboot\0" + "setdomainname\0" + "setfsuid32\0" + "setfsuid\0" + "setgroups32\0" + "setgroups\0" + "sethostname\0" + "setresuid32\0" + "setresuid\0" + "setreuid32\0" + "setreuid\0" + "setuid32\0" + "setuid\0" + "stime\0" + "swapoff\0" + "swapon\0" + "sysctl\0" + "vhangup\0" + }, { + /* Process control, execution, namespaces */ + .set_name = "@process", + .value = + "arch_prctl\0" + "clone\0" + "execve\0" + "execveat\0" + "fork\0" + "kill\0" + "prctl\0" + "setns\0" + "tgkill\0" + "tkill\0" + "unshare\0" + "vfork\0" + }, { + /* Raw I/O ports */ + .set_name = "@raw-io", + .value = + "ioperm\0" + "iopl\0" + "pciconfig_read\0" + "pciconfig_write\0" + "s390_pci_mmio_read\0" + "s390_pci_mmio_write\0" + }, { + .set_name = NULL, + .value = NULL + } +}; diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 4ed2afc1b2..be33eecb85 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -26,3 +26,10 @@ const char* seccomp_arch_to_string(uint32_t c); int seccomp_arch_from_string(const char *n, uint32_t *ret); int seccomp_add_secondary_archs(scmp_filter_ctx *c); + +typedef struct SystemCallFilterSet { + const char *set_name; + const char *value; +} SystemCallFilterSet; + +extern const SystemCallFilterSet syscall_filter_sets[]; -- cgit v1.2.3-54-g00ecf From e57c9ce169a135c0461108075a72bc2bedb299c7 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 3 Jun 2016 08:49:05 -0700 Subject: core: always use "infinity" for no upper limit instead of "max" (#3417) Recently added cgroup unified hierarchy support uses "max" in configurations for no upper limit. While consistent with what the kernel uses for no upper limit, it is inconsistent with what systemd uses for other controllers such as memory or pids. There's no point in introducing another term. Update cgroup unified hierarchy support so that "infinity" is the only term that systemd uses for no upper limit. --- man/systemd.resource-control.xml | 4 ++-- src/core/load-fragment.c | 4 ++-- src/shared/bus-unit-util.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'man') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 570619a743..d4c8fa7091 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -248,7 +248,7 @@ Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the - special value max, no memory limit is applied. This controls the + special value infinity, no memory limit is applied. This controls the memory.high control group attribute. For details about this control group attribute, see cgroup-v2.txt. @@ -269,7 +269,7 @@ Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the - special value max, no memory limit is applied. This controls the + special value infinity, no memory limit is applied. This controls the memory.max control group attribute. For details about this control group attribute, see cgroup-v2.txt. diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 50ff718aab..b53301a147 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2811,7 +2811,7 @@ int config_parse_memory_limit( uint64_t bytes = CGROUP_LIMIT_MAX; int r; - if (!isempty(rvalue) && !streq(rvalue, "infinity") && !streq(rvalue, "max")) { + if (!isempty(rvalue) && !streq(rvalue, "infinity")) { r = parse_size(rvalue, 1024, &bytes); if (r < 0 || bytes < 1) { log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); @@ -3080,7 +3080,7 @@ int config_parse_io_limit( return 0; } - if (streq("max", limit)) { + if (streq("infinity", limit)) { num = CGROUP_LIMIT_MAX; } else { r = parse_size(limit, 1000, &num); diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 502e98d9dc..bf0b2e89e3 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -169,7 +169,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) { uint64_t bytes; - if (isempty(eq) || streq(eq, "max") || streq(eq, "infinity")) + if (isempty(eq) || streq(eq, "infinity")) bytes = CGROUP_LIMIT_MAX; else { r = parse_size(eq, 1024, &bytes); @@ -306,7 +306,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } - if (streq(bandwidth, "max")) { + if (streq(bandwidth, "infinity")) { bytes = CGROUP_LIMIT_MAX; } else { r = parse_size(bandwidth, 1000, &bytes); -- cgit v1.2.3-54-g00ecf From f3e43635932c14f8f0aea078adf3bfe09a9ba683 Mon Sep 17 00:00:00 2001 From: Topi Miettinen Date: Fri, 3 Jun 2016 15:58:18 +0000 Subject: core: Restrict mmap and mprotect with PAGE_WRITE|PAGE_EXEC (#3319) (#3379) New exec boolean MemoryDenyWriteExecute, when set, installs a seccomp filter to reject mmap(2) with PAGE_WRITE|PAGE_EXEC and mprotect(2) with PAGE_EXEC. --- man/systemd.exec.xml | 16 +++++++++++ src/core/dbus-execute.c | 5 +++- src/core/execute.c | 53 +++++++++++++++++++++++++++++++++-- src/core/execute.h | 1 + src/core/load-fragment-gperf.gperf.m4 | 2 ++ src/shared/bus-unit-util.c | 2 +- 6 files changed, 75 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 58f18f3a9e..4a3dd14c39 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1388,6 +1388,22 @@ tmpfiles.d5. + + MemoryDenyWriteExecute= + + Takes a boolean argument. If set, attempts to create memory mappings that are writable and + executable at the same time, or to change existing memory mappings to become executable are prohibited. + Specifically, a system call filter is added that rejects + mmap2 + system calls with both PROT_EXEC and PROT_WRITE set + and mprotect2 + system calls with PROT_EXEC set. Note that this option is incompatible with programs + that generate program code dynamically at runtime, such as JIT execution engines, or programs compiled making + use of the code "trampoline" feature of various C compilers. This option improves service security, as it makes + harder for software exploits to change running code dynamically. + + + diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index de29d5da04..4c88c41127 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -719,6 +719,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; @@ -1056,7 +1057,7 @@ int bus_exec_context_set_transient_property( } else if (STR_IN_SET(name, "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "PrivateTmp", "PrivateDevices", "PrivateNetwork", - "NoNewPrivileges", "SyslogLevelPrefix")) { + "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute")) { int b; r = sd_bus_message_read(message, "b", &b); @@ -1080,6 +1081,8 @@ int bus_exec_context_set_transient_property( c->no_new_privileges = b; else if (streq(name, "SyslogLevelPrefix")) c->syslog_level_prefix = b; + else if (streq(name, "MemoryDenyWriteExecute")) + c->memory_deny_write_execute = b; unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b)); } diff --git a/src/core/execute.c b/src/core/execute.c index 5eb3f13695..2cef70e668 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1190,6 +1191,45 @@ finish: return r; } +static int apply_memory_deny_write_execute(const ExecContext *c) { + scmp_filter_ctx *seccomp; + int r; + + assert(c); + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return -ENOMEM; + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_KILL, + SCMP_SYS(mmap), + 1, + SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC|PROT_WRITE, PROT_EXEC|PROT_WRITE)); + if (r < 0) + goto finish; + + r = seccomp_rule_add( + seccomp, + SCMP_ACT_KILL, + SCMP_SYS(mprotect), + 1, + SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC)); + if (r < 0) + goto finish; + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; + + r = seccomp_load(seccomp); + +finish: + seccomp_release(seccomp); + return r; +} + #endif static void do_idle_pipe_dance(int idle_pipe[4]) { @@ -1912,6 +1952,13 @@ static int exec_child( } } + if (context->memory_deny_write_execute) { + r = apply_memory_deny_write_execute(context); + if (r < 0) { + *exit_status = EXIT_SECCOMP; + return r; + } + } if (use_syscall_filter) { r = apply_seccomp(context); if (r < 0) { @@ -2371,7 +2418,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sPrivateDevices: %s\n" "%sProtectHome: %s\n" "%sProtectSystem: %s\n" - "%sIgnoreSIGPIPE: %s\n", + "%sIgnoreSIGPIPE: %s\n" + "%sMemoryDenyWriteExecute: %s\n", prefix, c->umask, prefix, c->working_directory ? c->working_directory : "/", prefix, c->root_directory ? c->root_directory : "/", @@ -2381,7 +2429,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, yes_no(c->private_devices), prefix, protect_home_to_string(c->protect_home), prefix, protect_system_to_string(c->protect_system), - prefix, yes_no(c->ignore_sigpipe)); + prefix, yes_no(c->ignore_sigpipe), + prefix, yes_no(c->memory_deny_write_execute)); STRV_FOREACH(e, c->environment) fprintf(f, "%sEnvironment: %s\n", prefix, *e); diff --git a/src/core/execute.h b/src/core/execute.h index 41148bcea2..464869d226 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -197,6 +197,7 @@ struct ExecContext { bool ioprio_set:1; bool cpu_sched_set:1; bool no_new_privileges_set:1; + bool memory_deny_write_execute; }; #include "cgroup-util.h" diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 00bdc238ce..eb58586523 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -55,10 +55,12 @@ m4_ifdef(`HAVE_SECCOMP', `$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context) $1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs) $1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context) +$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute) $1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)', `$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 +$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index bf0b2e89e3..8f4f93ee0c 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -158,7 +158,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", - "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) { + "SyslogLevelPrefix", "Delegate", "RemainAfterElapse", "MemoryDenyWriteExecute")) { r = parse_boolean(eq); if (r < 0) -- cgit v1.2.3-54-g00ecf From 308253c5a2b146fc18e3789725c092ac55b10ce7 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Sun, 5 Jun 2016 19:42:37 +0200 Subject: cgtop: add option to show a single cgroup subtree (#3413) When many services are running, it was difficult to see only the interesting ones. This patch allows to show only the subtree of interest. --- man/systemd-cgtop.xml | 8 ++++++-- src/cgtop/cgtop.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml index c76f646984..be13631239 100644 --- a/man/systemd-cgtop.xml +++ b/man/systemd-cgtop.xml @@ -52,6 +52,7 @@ systemd-cgtop OPTIONS + GROUP @@ -62,7 +63,9 @@ groups of the local Linux control group hierarchy, ordered by their CPU, memory, or disk I/O load. The display is refreshed in regular intervals (by default every 1s), similar in style to - top1. + top1. + If a control group path is specified, shows only the services of + the specified control group. If systemd-cgtop is not connected to a tty, no column headers are printed and the default is to only run @@ -252,7 +255,8 @@ Limit control groups shown to the part corresponding to the container - MACHINE. + MACHINE. + This option may not be used when a control group path is specified. diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 33379eb9bd..b4a982ce38 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -72,6 +72,7 @@ static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; static char* arg_machine = NULL; +static char* arg_root = NULL; static bool arg_recursive = true; static enum { @@ -653,7 +654,7 @@ static void display(Hashmap *a) { } static void help(void) { - printf("%s [OPTIONS...]\n\n" + printf("%s [OPTIONS...] [CGROUP]\n\n" "Show top control groups by their resource usage.\n\n" " -h --help Show this help\n" " --version Show package version\n" @@ -835,7 +836,13 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } - if (optind < argc) { + if (optind == argc-1) { + if (arg_machine) { + log_error("Specifying a control group path together with the -M option is not allowed"); + return -EINVAL; + } + arg_root = argv[optind]; + } else if (optind < argc) { log_error("Too many arguments."); return -EINVAL; } @@ -864,6 +871,13 @@ static int get_cgroup_root(char **ret) { const char *m; int r; + if (arg_root) { + *ret = strdup(arg_root); + if (!*ret) + return log_oom(); + return 0; + } + if (!arg_machine) { r = cg_get_root_path(ret); if (r < 0) -- cgit v1.2.3-54-g00ecf From b2bb19bbda8f5ab3ab497165bc52a0ef952348c4 Mon Sep 17 00:00:00 2001 From: Christian Rebischke Date: Mon, 6 Jun 2016 17:06:20 +0200 Subject: machinectl: Added stop as alias for poweroff (#3406) --- man/machinectl.xml | 7 +++---- shell-completion/bash/machinectl | 2 +- shell-completion/zsh/_machinectl | 1 + src/machine/machinectl.c | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'man') diff --git a/man/machinectl.xml b/man/machinectl.xml index 4b7f9a0391..d3891332e4 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -373,8 +373,7 @@ To interactively start a container on the command line with full access to the container's console, please invoke systemd-nspawn directly. To stop a running - container use machinectl poweroff, see - below. + container use machinectl poweroff. @@ -461,8 +460,8 @@ Power off one or more containers. This will trigger a reboot by sending SIGRTMIN+4 to the container's init process, which causes systemd-compatible init systems to shut - down cleanly. This operation does not work on containers that - do not run a + down cleanly. Use stop as alias for poweroff. + This operation does not work on containers that do not run a systemd1-compatible init system, such as sysvinit. Use terminate (see below) to immediately diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl index e7829ca968..aebe48304d 100644 --- a/shell-completion/bash/machinectl +++ b/shell-completion/bash/machinectl @@ -41,7 +41,7 @@ _machinectl() { local -A VERBS=( [STANDALONE]='list list-images pull-tar pull-raw import-tar import-raw export-tar export-raw list-transfers cancel-transfer' - [MACHINES]='status show start login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit' + [MACHINES]='status show start stop login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit' ) _init_completion || return diff --git a/shell-completion/zsh/_machinectl b/shell-completion/zsh/_machinectl index 198fa28f7b..92d77109a5 100644 --- a/shell-completion/zsh/_machinectl +++ b/shell-completion/zsh/_machinectl @@ -23,6 +23,7 @@ _available_machines() { "status:Show VM/container status" "show:Show properties of one or more VMs/containers" "start:Start container as a service" + "stop:Stop container (equal to poweroff)" "login:Get a login prompt on a VM/container" "enable:Enable automatic container start at boot" "disable:Disable automatic container start at boot" diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 8e4ffa9a39..afe5026373 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -2720,6 +2720,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "terminate", 2, VERB_ANY, 0, terminate_machine }, { "reboot", 2, VERB_ANY, 0, reboot_machine }, { "poweroff", 2, VERB_ANY, 0, poweroff_machine }, + { "stop", 2, VERB_ANY, 0, poweroff_machine }, /* Convenience alias */ { "kill", 2, VERB_ANY, 0, kill_machine }, { "login", VERB_ANY, 2, 0, login_machine }, { "shell", VERB_ANY, VERB_ANY, 0, shell_machine }, -- cgit v1.2.3-54-g00ecf From 1e7a0e21c97ac1bbc743009e5ec8c12bc6200e19 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 2 Jun 2016 20:38:12 +0200 Subject: network: beef up ipv6 RA support considerably This reworks sd-ndisc and networkd substantially to support IPv6 RA much more comprehensively. Since the API is extended quite a bit networkd has been ported over too, and the patch is not as straight-forward as one could wish. The rework includes: - Support for DNSSL, RDNSS and RA routing options in sd-ndisc and networkd. Two new configuration options have been added to networkd to make this configurable. - sd-ndisc now exposes an sd_ndisc_router object that encapsulates a full RA message, and has direct, friendly acessor functions for the singleton RA properties, as well as an iterative interface to iterate through known and unsupported options. The router object may either be retrieved from the wire, or generated from raw data. In many ways the sd-ndisc API now matches the sd-lldp API, except that no implicit database of seen data is kept. (Note that sd-ndisc actually had a half-written, but unused implementaiton of such a store, which is removed now.) - sd-ndisc will now collect the reception timestamps of RA, which is useful to make sd_ndisc_router fully descriptive of what it covers. Fixes: #1079 --- Makefile.am | 4 + man/systemd.network.xml | 73 ++- src/libsystemd-network/icmp6-util.c | 7 +- src/libsystemd-network/ndisc-internal.h | 49 ++ src/libsystemd-network/ndisc-router.c | 779 +++++++++++++++++++++++++++++++ src/libsystemd-network/ndisc-router.h | 62 +++ src/libsystemd-network/sd-ndisc.c | 551 ++++++---------------- src/libsystemd-network/test-ndisc-rs.c | 163 ++++++- src/network/networkd-dhcp6.c | 15 +- src/network/networkd-link.c | 61 ++- src/network/networkd-link.h | 7 +- src/network/networkd-ndisc.c | 534 ++++++++++++++++++--- src/network/networkd-ndisc.h | 39 ++ src/network/networkd-network-gperf.gperf | 2 + src/network/networkd-network.c | 5 +- src/network/networkd-network.h | 3 + src/systemd/sd-ndisc.h | 114 +++-- 17 files changed, 1911 insertions(+), 557 deletions(-) create mode 100644 src/libsystemd-network/ndisc-internal.h create mode 100644 src/libsystemd-network/ndisc-router.c create mode 100644 src/libsystemd-network/ndisc-router.h create mode 100644 src/network/networkd-ndisc.h (limited to 'man') diff --git a/Makefile.am b/Makefile.am index c31c30c051..9a34c686d5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3430,6 +3430,9 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/network-internal.c \ src/libsystemd-network/network-internal.h \ src/libsystemd-network/sd-ndisc.c \ + src/libsystemd-network/ndisc-internal.h \ + src/libsystemd-network/ndisc-router.h \ + src/libsystemd-network/ndisc-router.c \ src/libsystemd-network/icmp6-util.h \ src/libsystemd-network/icmp6-util.c \ src/libsystemd-network/sd-dhcp6-client.c \ @@ -5462,6 +5465,7 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-ipv4ll.c \ src/network/networkd-dhcp4.c \ src/network/networkd-dhcp6.c \ + src/network/networkd-ndisc.h \ src/network/networkd-ndisc.c \ src/network/networkd-network.h \ src/network/networkd-network.c \ diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 821e22aff8..487bb2ab3f 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -528,23 +528,19 @@ IPv6AcceptRouterAdvertisements= - Force the setting of the accept_ra - (router advertisements) setting for the interface. - When unset, the kernel default is used, and router - advertisements are accepted only when local forwarding - is disabled for that interface. - When router advertisements are accepted, they will - trigger the start of the DHCPv6 client if the relevant - flags are passed, or if no routers are found on the link. - Takes a boolean. If true, router advertisements are - accepted, when false, router advertisements are ignored, - independently of the local forwarding state. - - See - ip-sysctl.txt - in the kernel documentation, but note that systemd's - setting of 1 corresponds to - kernel's setting of 2. + Enable or disable IPv6 Router Advertisement (RA) reception support for the interface. Takes + a boolean parameter. If true, RAs are accepted; if false, RAs are ignored, independently of the local + forwarding state. When not set, the kernel default is used, and RAs are accepted only when local forwarding + is disabled for that interface. When RAs are accepted, they may trigger the start of the DHCPv6 client if + the relevant flags are set in the RA data, or if no routers are found on the link. + + Further settings for the IPv6 RA support may be configured in the + [IPv6AcceptRouterAdvertisements] section, see below. + + Also see ip-sysctl.txt in the kernel + documentation regarding accept_ra, but note that systemd's setting of + 1 (i.e. true) corresponds to kernel's setting of 2. @@ -799,7 +795,7 @@ false. It is recommended to enable this option only on trusted networks, as setting this affects resolution - of all host names, in particular to single-label names. It is generally safer to use the supplied domain + of all host names, in particular of single-label names. It is generally safer to use the supplied domain only as routing domain, rather than as search domain, in order to not have it affect local resolution of single-label names. @@ -898,6 +894,47 @@ + + [IPv6AcceptRouterAdvertisements] Section Options + The [IPv6AcceptRouterAdvertisements] section configures the IPv6 Router Advertisement + (RA) client, if it is enabled with the IPv6AcceptRouterAdvertisements= setting described + above: + + + + UseDNS= + + When true (the default), the DNS servers received in the Router Advertisement will be used and take + precedence over any statically configured ones. + + This corresponds to the option in resolv.conf5. + + + + + UseDomains= + + Takes a boolean argument, or the special value route. When true, the domain name + received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to + the effect of the setting. If set to route, the domain name + received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the + effect of the setting when the argument is prefixed with + ~. Defaults to false. + + It is recommended to enable this option only on trusted networks, as setting this affects resolution + of all host names, in particular of single-label names. It is generally safer to use the supplied domain + only as routing domain, rather than as search domain, in order to not have it affect local resolution of + single-label names. + + When set to true, this setting corresponds to the option in resolv.conf5. + + + + + + [DHCPServer] Section Options The [DHCPServer] section contains diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index d81e9ebd88..c2e4b0e9e3 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -49,7 +49,8 @@ int icmp6_bind_router_solicitation(int index) { }; _cleanup_close_ int s = -1; char ifname[IF_NAMESIZE] = ""; - int r, zero = 0, one = 1, hops = 255; + static const int zero = 0, one = 1, hops = 255; + int r; s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6); if (s < 0) @@ -85,6 +86,10 @@ int icmp6_bind_router_solicitation(int index) { if (r < 0) return -errno; + r = setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)); + if (r < 0) + return -errno; + if (if_indextoname(index, ifname) == 0) return -errno; diff --git a/src/libsystemd-network/ndisc-internal.h b/src/libsystemd-network/ndisc-internal.h new file mode 100644 index 0000000000..60e183ff8c --- /dev/null +++ b/src/libsystemd-network/ndisc-internal.h @@ -0,0 +1,49 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + 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 . +***/ + +#include "log.h" + +#include "sd-ndisc.h" + +struct sd_ndisc { + unsigned n_ref; + + int ifindex; + int fd; + + sd_event *event; + int event_priority; + + struct ether_addr mac_addr; + uint8_t hop_limit; + uint32_t mtu; + + sd_event_source *recv_event_source; + sd_event_source *timeout_event_source; + + unsigned nd_sent; + + sd_ndisc_callback_t callback; + void *userdata; +}; + +#define log_ndisc_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDISC: " fmt, ##__VA_ARGS__) +#define log_ndisc(fmt, ...) log_ndisc_errno(0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c new file mode 100644 index 0000000000..d9950b638c --- /dev/null +++ b/src/libsystemd-network/ndisc-router.c @@ -0,0 +1,779 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + 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 . +***/ + +#include + +#include "sd-ndisc.h" + +#include "alloc-util.h" +#include "dns-domain.h" +#include "hostname-util.h" +#include "missing.h" +#include "ndisc-internal.h" +#include "ndisc-router.h" +#include "strv.h" + +_public_ sd_ndisc_router* sd_ndisc_router_ref(sd_ndisc_router *rt) { + if (!rt) + return NULL; + + assert(rt->n_ref > 0); + rt->n_ref++; + + return rt; +} + +_public_ sd_ndisc_router* sd_ndisc_router_unref(sd_ndisc_router *rt) { + if (!rt) + return NULL; + + assert(rt->n_ref > 0); + rt->n_ref--; + + if (rt->n_ref > 0) + return NULL; + + free(rt); + return NULL; +} + +sd_ndisc_router *ndisc_router_new(size_t raw_size) { + sd_ndisc_router *rt; + + rt = malloc0(ALIGN(sizeof(sd_ndisc_router)) + raw_size); + if (!rt) + return NULL; + + rt->raw_size = raw_size; + rt->n_ref = 1; + + return rt; +} + +_public_ int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size) { + _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL; + int r; + + assert_return(ret, -EINVAL); + assert_return(raw || raw_size <= 0, -EINVAL); + + rt = ndisc_router_new(raw_size); + if (!rt) + return -ENOMEM; + + memcpy(NDISC_ROUTER_RAW(rt), raw, raw_size); + r = ndisc_router_parse(rt); + if (r < 0) + return r; + + *ret = rt; + rt = NULL; + + return r; +} + +_public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) { + assert_return(rt, -EINVAL); + assert_return(ret_addr, -EINVAL); + + if (in6_addr_is_null(&rt->address)) + return -ENODATA; + + *ret_addr = rt->address; + return 0; +} + +_public_ int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret) { + assert_return(rt, -EINVAL); + assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); + assert_return(clock_supported(clock), -EOPNOTSUPP); + assert_return(ret, -EINVAL); + + if (!triple_timestamp_is_set(&rt->timestamp)) + return -ENODATA; + + *ret = triple_timestamp_by_clock(&rt->timestamp, clock); + return 0; +} + +_public_ int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + *ret = NDISC_ROUTER_RAW(rt); + *size = rt->raw_size; + + return 0; +} + +int ndisc_router_parse(sd_ndisc_router *rt) { + struct nd_router_advert *a; + const uint8_t *p; + bool has_mtu = false, has_flag_extension = false; + size_t left; + + assert(rt); + + if (rt->raw_size < sizeof(struct nd_router_advert)) { + log_ndisc("Too small to be a router advertisement, ignoring."); + return -EBADMSG; + } + + /* Router advertisement packets are neatly aligned to 64bit boundaries, hence we can access them directly */ + a = NDISC_ROUTER_RAW(rt); + + if (a->nd_ra_type != ND_ROUTER_ADVERT) { + log_ndisc("Received ND packet that is not a router advertisement, ignoring."); + return -EBADMSG; + } + + if (a->nd_ra_code != 0) { + log_ndisc("Received ND packet with wrong RA code, ignoring."); + return -EBADMSG; + } + + rt->hop_limit = a->nd_ra_curhoplimit; + rt->flags = a->nd_ra_flags_reserved; /* the first 8bit */ + rt->lifetime = be16toh(a->nd_ra_router_lifetime); + + rt->preference = (rt->flags >> 3) & 3; + if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH)) + rt->preference = SD_NDISC_PREFERENCE_MEDIUM; + + p = (const uint8_t*) NDISC_ROUTER_RAW(rt) + sizeof(struct nd_router_advert); + left = rt->raw_size - sizeof(struct nd_router_advert); + + for (;;) { + uint8_t type; + size_t length; + + if (left == 0) + break; + + if (left < 2) { + log_ndisc("Option lacks header, ignoring datagram."); + return -EBADMSG; + } + + type = p[0]; + length = p[1] * 8; + + if (length == 0) { + log_ndisc("Zero-length option, ignoring datagram."); + return -EBADMSG; + } + if (left < length) { + log_ndisc("Option truncated, ignoring datagram."); + return -EBADMSG; + } + + switch (type) { + + case SD_NDISC_OPTION_PREFIX_INFORMATION: + + if (length != 4*8) { + log_ndisc("Prefix option of invalid size, ignoring datagram."); + return -EBADMSG; + } + + if (p[2] > 128) { + log_ndisc("Bad prefix length, ignoring datagram."); + return -EBADMSG; + } + + break; + + case SD_NDISC_OPTION_MTU: { + uint32_t m; + + if (has_mtu) { + log_ndisc("MTU option specified twice, ignoring."); + continue; + } + + if (length != 8) { + log_ndisc("MTU option of invalid size, ignoring datagram."); + return -EBADMSG; + } + + m = be32toh(*(uint32_t*) (p + 4)); + if (m >= IPV6_MIN_MTU) /* ignore invalidly small MTUs */ + rt->mtu = m; + + has_mtu = true; + break; + } + + case SD_NDISC_OPTION_ROUTE_INFORMATION: + if (length < 1*8 || length > 3*8) { + log_ndisc("Route information option of invalid size, ignoring datagram."); + return -EBADMSG; + } + + if (p[2] > 128) { + log_ndisc("Bad route prefix length, ignoring datagram."); + return -EBADMSG; + } + + break; + + case SD_NDISC_OPTION_RDNSS: + if (length < 3*8 || (length % (2*8)) != 1*8) { + log_ndisc("RDNSS option has invalid size."); + return -EBADMSG; + } + + break; + + case SD_NDISC_OPTION_FLAGS_EXTENSION: + + if (has_flag_extension) { + log_ndisc("Flags extension option specified twice, ignoring."); + continue; + } + + if (length < 1*8) { + log_ndisc("Flags extension option has invalid size."); + return -EBADMSG; + } + + /* Add in the additional flags bits */ + rt->flags |= + ((uint64_t) p[2] << 8) | + ((uint64_t) p[3] << 16) | + ((uint64_t) p[4] << 24) | + ((uint64_t) p[5] << 32) | + ((uint64_t) p[6] << 40) | + ((uint64_t) p[7] << 48); + + has_flag_extension = true; + break; + + case SD_NDISC_OPTION_DNSSL: + if (length < 2*8) { + log_ndisc("DNSSL option has invalid size."); + return -EBADMSG; + } + + break; + } + + p += length, left -= length; + } + + rt->rindex = sizeof(struct nd_router_advert); + return 0; +} + +_public_ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = rt->hop_limit; + return 0; +} + +_public_ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) { + assert_return(rt, -EINVAL); + assert_return(ret_flags, -EINVAL); + + *ret_flags = rt->flags; + return 0; +} + +_public_ int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime) { + assert_return(rt, -EINVAL); + assert_return(ret_lifetime, -EINVAL); + + *ret_lifetime = rt->lifetime; + return 0; +} + +_public_ int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = rt->preference; + return 0; +} + +_public_ int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + if (rt->mtu <= 0) + return -ENODATA; + + *ret = rt->mtu; + return 0; +} + +_public_ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt) { + assert_return(rt, -EINVAL); + + assert(rt->raw_size >= sizeof(struct nd_router_advert)); + rt->rindex = sizeof(struct nd_router_advert); + + return rt->rindex < rt->raw_size; +} + +_public_ int sd_ndisc_router_option_next(sd_ndisc_router *rt) { + size_t length; + + assert_return(rt, -EINVAL); + + if (rt->rindex == rt->raw_size) /* EOF */ + return -ESPIPE; + + if (rt->rindex + 2 > rt->raw_size) /* Truncated message */ + return -EBADMSG; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (rt->rindex + length > rt->raw_size) + return -EBADMSG; + + rt->rindex += length; + return rt->rindex < rt->raw_size; +} + +_public_ int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret) { + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + if (rt->rindex == rt->raw_size) /* EOF */ + return -ESPIPE; + + if (rt->rindex + 2 > rt->raw_size) /* Truncated message */ + return -EBADMSG; + + *ret = NDISC_ROUTER_OPTION_TYPE(rt); + return 0; +} + +_public_ int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type) { + uint8_t k; + int r; + + assert_return(rt, -EINVAL); + + r = sd_ndisc_router_option_get_type(rt, &k); + if (r < 0) + return r; + + return type == k; +} + +_public_ int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size) { + size_t length; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + /* Note that this returns the full option, including the option header */ + + if (rt->rindex + 2 > rt->raw_size) + return -EBADMSG; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (rt->rindex + length > rt->raw_size) + return -EBADMSG; + + *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + *size = length; + + return 0; +} + +static int get_prefix_info(sd_ndisc_router *rt, struct nd_opt_prefix_info **ret) { + struct nd_opt_prefix_info *ri; + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_PREFIX_INFORMATION); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length != sizeof(struct nd_opt_prefix_info)) + return -EBADMSG; + + ri = (struct nd_opt_prefix_info*) ((uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex); + if (ri->nd_opt_pi_prefix_len > 128) + return -EBADMSG; + + *ret = ri; + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + struct nd_opt_prefix_info *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &ri); + if (r < 0) + return r; + + *ret = be32toh(ri->nd_opt_pi_valid_time); + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + *ret = be32toh(pi->nd_opt_pi_preferred_time); + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + *ret = pi->nd_opt_pi_flags_reserved; + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret_addr, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + *ret_addr = pi->nd_opt_pi_prefix; + return 0; +} + +_public_ int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) { + struct nd_opt_prefix_info *pi; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_prefix_info(rt, &pi); + if (r < 0) + return r; + + if (pi->nd_opt_pi_prefix_len > 128) + return -EBADMSG; + + *ret = pi->nd_opt_pi_prefix_len; + return 0; +} + +static int get_route_info(sd_ndisc_router *rt, uint8_t **ret) { + uint8_t *ri; + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_ROUTE_INFORMATION); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length < 1*8 || length > 3*8) + return -EBADMSG; + + ri = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + + if (ri[2] > 128) + return -EBADMSG; + + *ret = ri; + return 0; +} + +_public_ int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + *ret = be32toh(*(uint32_t*) (ri + 4)); + return 0; +} + +_public_ int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret_addr, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + zero(*ret_addr); + memcpy(ret_addr, ri + 8, NDISC_ROUTER_OPTION_LENGTH(rt) - 8); + + return 0; +} + +_public_ int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + *ret = ri[2]; + return 0; +} + +_public_ int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_route_info(rt, &ri); + if (r < 0) + return r; + + *ret = (ri[3] >> 3) & 3; + if (!IN_SET(*ret, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH)) + *ret = SD_NDISC_PREFERENCE_MEDIUM; + + return 0; +} + +static int get_rdnss_info(sd_ndisc_router *rt, uint8_t **ret) { + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_RDNSS); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length < 3*8 || (length % (2*8)) != 1*8) + return -EBADMSG; + + *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + return 0; +} + +_public_ int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_rdnss_info(rt, &ri); + if (r < 0) + return r; + + *ret = (const struct in6_addr*) (ri + 8); + return (NDISC_ROUTER_OPTION_LENGTH(rt) - 8) / 16; +} + +_public_ int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_rdnss_info(rt, &ri); + if (r < 0) + return r; + + *ret = be32toh(*(uint32_t*) (ri + 4)); + return 0; +} + +static int get_dnssl_info(sd_ndisc_router *rt, uint8_t **ret) { + size_t length; + int r; + + assert(rt); + assert(ret); + + r = sd_ndisc_router_option_is_type(rt, SD_NDISC_OPTION_DNSSL); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + + length = NDISC_ROUTER_OPTION_LENGTH(rt); + if (length < 2*8) + return -EBADMSG; + + *ret = (uint8_t*) NDISC_ROUTER_RAW(rt) + rt->rindex; + return 0; +} + +_public_ int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret) { + _cleanup_strv_free_ char **l = NULL; + _cleanup_free_ char *e = NULL; + size_t allocated = 0, n = 0, left; + uint8_t *ri, *p; + bool first = true; + int r; + unsigned k = 0; + + assert_return(rt, -EINVAL); + assert_return(ret, -EINVAL); + + r = get_dnssl_info(rt, &ri); + if (r < 0) + return r; + + p = ri + 8; + left = NDISC_ROUTER_OPTION_LENGTH(rt) - 8; + + for (;;) { + if (left == 0) { + + if (n > 0) /* Not properly NUL terminated */ + return -EBADMSG; + + break; + } + + if (*p == 0) { + /* Found NUL termination */ + + if (n > 0) { + _cleanup_free_ char *normalized = NULL; + + e[n] = 0; + r = dns_name_normalize(e, &normalized); + if (r < 0) + return r; + + /* Ignore the root domain name or "localhost" and friends */ + if (!is_localhost(normalized) && + !dns_name_is_root(normalized)) { + + if (strv_push(&l, normalized) < 0) + return -ENOMEM; + + normalized = NULL; + k++; + } + } + + n = 0; + first = true; + p++, left--; + continue; + } + + /* Check for compression (which is not allowed) */ + if (*p > 63) + return -EBADMSG; + + if (1U + *p + 1U > left) + return -EBADMSG; + + if (!GREEDY_REALLOC(e, allocated, n + !first + DNS_LABEL_ESCAPED_MAX + 1U)) + return -ENOMEM; + + if (first) + first = false; + else + e[n++] = '.'; + + r = dns_label_escape((char*) p+1, *p, e + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + + n += r; + + left -= 1 + *p; + p += 1 + *p; + } + + if (strv_isempty(l)) { + *ret = NULL; + return 0; + } + + *ret = l; + l = NULL; + + return k; +} + +_public_ int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret_sec) { + uint8_t *ri; + int r; + + assert_return(rt, -EINVAL); + assert_return(ret_sec, -EINVAL); + + r = get_dnssl_info(rt, &ri); + if (r < 0) + return r; + + *ret_sec = be32toh(*(uint32_t*) (ri + 4)); + return 0; +} diff --git a/src/libsystemd-network/ndisc-router.h b/src/libsystemd-network/ndisc-router.h new file mode 100644 index 0000000000..1fe703da63 --- /dev/null +++ b/src/libsystemd-network/ndisc-router.h @@ -0,0 +1,62 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + 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 . +***/ + +#include "sd-ndisc.h" + +#include "time-util.h" + +struct sd_ndisc_router { + unsigned n_ref; + + triple_timestamp timestamp; + struct in6_addr address; + + /* The raw packet size. The data is appended to the object, accessible via NDIS_ROUTER_RAW() */ + size_t raw_size; + + /* The current read index for the iterative option interface */ + size_t rindex; + + uint64_t flags; + unsigned preference; + uint16_t lifetime; + + uint8_t hop_limit; + uint32_t mtu; +}; + +static inline void* NDISC_ROUTER_RAW(const sd_ndisc_router *rt) { + return (uint8_t*) rt + ALIGN(sizeof(sd_ndisc_router)); +} + +static inline void *NDISC_ROUTER_OPTION_DATA(const sd_ndisc_router *rt) { + return ((uint8_t*) NDISC_ROUTER_RAW(rt)) + rt->rindex; +} + +static inline uint8_t NDISC_ROUTER_OPTION_TYPE(const sd_ndisc_router *rt) { + return ((uint8_t*) NDISC_ROUTER_OPTION_DATA(rt))[0]; +} +static inline size_t NDISC_ROUTER_OPTION_LENGTH(const sd_ndisc_router *rt) { + return ((uint8_t*) NDISC_ROUTER_OPTION_DATA(rt))[1] * 8; +} + +sd_ndisc_router *ndisc_router_new(size_t raw_size); +int ndisc_router_parse(sd_ndisc_router *rt); diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index ccb8002173..ea3fe369ce 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -19,165 +19,71 @@ #include #include -#include -#include -#include -#include #include "sd-ndisc.h" #include "alloc-util.h" -#include "async.h" +#include "fd-util.h" #include "icmp6-util.h" #include "in-addr-util.h" -#include "list.h" +#include "ndisc-internal.h" +#include "ndisc-router.h" #include "socket-util.h" #include "string-util.h" +#include "util.h" #define NDISC_ROUTER_SOLICITATION_INTERVAL (4U * USEC_PER_SEC) -#define NDISC_MAX_ROUTER_SOLICITATIONS 3U +#define NDISC_MAX_ROUTER_SOLICITATIONS 3U -enum NDiscState { - NDISC_STATE_IDLE, - NDISC_STATE_SOLICITATION_SENT, - NDISC_STATE_ADVERTISEMENT_LISTEN, - _NDISC_STATE_MAX, - _NDISC_STATE_INVALID = -1, -}; +static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event event, sd_ndisc_router *rt) { + assert(ndisc); -#define IP6_MIN_MTU 1280U -#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr)) -#define NDISC_OPT_LEN_UNITS 8U + log_ndisc("Invoking callback for '%c'.", event); -#define ND_RA_FLAG_PREF 0x18 -#define ND_RA_FLAG_PREF_LOW 0x03 -#define ND_RA_FLAG_PREF_MEDIUM 0x0 -#define ND_RA_FLAG_PREF_HIGH 0x1 -#define ND_RA_FLAG_PREF_INVALID 0x2 + if (!ndisc->callback) + return; -typedef struct NDiscPrefix NDiscPrefix; - -struct NDiscPrefix { - unsigned n_ref; - - sd_ndisc *nd; - - LIST_FIELDS(NDiscPrefix, prefixes); - - uint8_t len; - usec_t valid_until; - struct in6_addr addr; -}; - -struct sd_ndisc { - unsigned n_ref; - - enum NDiscState state; - int ifindex; - int fd; - - sd_event *event; - int event_priority; - - struct ether_addr mac_addr; - uint32_t mtu; - - LIST_HEAD(NDiscPrefix, prefixes); - - sd_event_source *recv_event_source; - sd_event_source *timeout_event_source; - - unsigned nd_sent; - - sd_ndisc_router_callback_t router_callback; - sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback; - sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback; - sd_ndisc_callback_t callback; - void *userdata; -}; - -#define log_ndisc_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__) -#define log_ndisc(p, fmt, ...) log_ndisc_errno(p, 0, fmt, ##__VA_ARGS__) - -static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) { - - if (!prefix) - return NULL; - - assert(prefix->n_ref > 0); - prefix->n_ref--; - - if (prefix->n_ref > 0) - return NULL; - - if (prefix->nd) - LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix); - - free(prefix); - - return NULL; -} - -static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) { - NDiscPrefix *prefix; - - assert(ret); - - prefix = new0(NDiscPrefix, 1); - if (!prefix) - return -ENOMEM; - - prefix->n_ref = 1; - LIST_INIT(prefixes, prefix); - prefix->nd = nd; - - *ret = prefix; - return 0; + ndisc->callback(ndisc, event, rt, ndisc->userdata); } -int sd_ndisc_set_callback( +_public_ int sd_ndisc_set_callback( sd_ndisc *nd, - sd_ndisc_router_callback_t router_callback, - sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback, - sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback, sd_ndisc_callback_t callback, void *userdata) { assert_return(nd, -EINVAL); - nd->router_callback = router_callback; - nd->prefix_onlink_callback = prefix_onlink_callback; - nd->prefix_autonomous_callback = prefix_autonomous_callback; nd->callback = callback; nd->userdata = userdata; return 0; } -int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) { +_public_ int sd_ndisc_set_ifindex(sd_ndisc *nd, int ifindex) { assert_return(nd, -EINVAL); assert_return(ifindex > 0, -EINVAL); + assert_return(nd->fd < 0, -EBUSY); nd->ifindex = ifindex; return 0; } -int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { +_public_ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { assert_return(nd, -EINVAL); if (mac_addr) - memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr)); + nd->mac_addr = *mac_addr; else zero(nd->mac_addr); return 0; - } -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { +_public_ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { int r; assert_return(nd, -EINVAL); + assert_return(nd->fd < 0, -EBUSY); assert_return(!nd->event, -EBUSY); if (event) @@ -193,21 +99,22 @@ int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) { return 0; } -int sd_ndisc_detach_event(sd_ndisc *nd) { +_public_ int sd_ndisc_detach_event(sd_ndisc *nd) { + assert_return(nd, -EINVAL); + assert_return(nd->fd < 0, -EBUSY); nd->event = sd_event_unref(nd->event); - return 0; } -sd_event *sd_ndisc_get_event(sd_ndisc *nd) { +_public_ sd_event *sd_ndisc_get_event(sd_ndisc *nd) { assert_return(nd, NULL); return nd->event; } -sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { +_public_ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { if (!nd) return NULL; @@ -221,15 +128,14 @@ sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { static int ndisc_reset(sd_ndisc *nd) { assert(nd); - nd->recv_event_source = sd_event_source_unref(nd->recv_event_source); - nd->fd = asynchronous_close(nd->fd); nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); + nd->recv_event_source = sd_event_source_unref(nd->recv_event_source); + nd->fd = safe_close(nd->fd); return 0; } -sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { - NDiscPrefix *prefix, *p; +_public_ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { if (!nd) return NULL; @@ -242,16 +148,12 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { ndisc_reset(nd); sd_ndisc_detach_event(nd); - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) - prefix = ndisc_prefix_unref(prefix); - free(nd); return NULL; } -int sd_ndisc_new(sd_ndisc **ret) { +_public_ int sd_ndisc_new(sd_ndisc **ret) { _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL; assert_return(ret, -EINVAL); @@ -261,223 +163,70 @@ int sd_ndisc_new(sd_ndisc **ret) { return -ENOMEM; nd->n_ref = 1; - nd->ifindex = -1; nd->fd = -1; - LIST_HEAD_INIT(nd->prefixes); - *ret = nd; nd = NULL; return 0; } -int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) { +_public_ int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) { assert_return(nd, -EINVAL); assert_return(mtu, -EINVAL); if (nd->mtu == 0) - return -ENOMSG; + return -ENODATA; *mtu = nd->mtu; return 0; } -static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, - const struct in6_addr *addr, - uint8_t addr_prefixlen) { - uint8_t bytes, mask, len; - - assert(prefix); - assert(addr); - - len = MIN(prefixlen, addr_prefixlen); - - bytes = len / 8; - mask = 0xff << (8 - len % 8); +_public_ int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret) { + assert_return(nd, -EINVAL); + assert_return(ret, -EINVAL); - if (memcmp(prefix, addr, bytes) != 0 || - (prefix->s6_addr[bytes] & mask) != (addr->s6_addr[bytes] & mask)) - return -EADDRNOTAVAIL; + if (nd->hop_limit == 0) + return -ENODATA; + *ret = nd->hop_limit; return 0; } -static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr, - uint8_t addr_len, NDiscPrefix **result) { - NDiscPrefix *prefix, *p; - usec_t time_now; - int r; - - assert(nd); - - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - return r; - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { - if (prefix->valid_until < time_now) { - prefix = ndisc_prefix_unref(prefix); - continue; - } - - if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) { - *result = prefix; - return 0; - } - } - - return -EADDRNOTAVAIL; -} - -static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, - const struct nd_opt_prefix_info *prefix_opt) { - NDiscPrefix *prefix; - uint32_t lifetime_valid, lifetime_preferred; - usec_t time_now; - char time_string[FORMAT_TIMESPAN_MAX]; +static int ndisc_handle_datagram(sd_ndisc *nd, sd_ndisc_router *rt) { int r; assert(nd); - assert(prefix_opt); + assert(rt); - if (len < prefix_opt->nd_opt_pi_len) - return -EBADMSG; - - if (!(prefix_opt->nd_opt_pi_flags_reserved & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO))) + r = ndisc_router_parse(rt); + if (r == -EBADMSG) /* Bad packet */ return 0; - - if (in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &prefix_opt->nd_opt_pi_prefix) > 0) - return 0; - - lifetime_valid = be32toh(prefix_opt->nd_opt_pi_valid_time); - lifetime_preferred = be32toh(prefix_opt->nd_opt_pi_preferred_time); - - if (lifetime_valid < lifetime_preferred) - return 0; - - r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix, - prefix_opt->nd_opt_pi_prefix_len, &prefix); - if (r < 0) { - if (r != -EADDRNOTAVAIL) - return r; - - /* if router advertisement prefix valid timeout is zero, the timeout - callback will be called immediately to clean up the prefix */ - - r = ndisc_prefix_new(nd, &prefix); - if (r < 0) - return r; - - prefix->len = prefix_opt->nd_opt_pi_prefix_len; - - memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix, - sizeof(prefix->addr)); - - log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime_valid, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); - - LIST_PREPEND(prefixes, nd->prefixes, prefix); - - } else { - if (prefix->len != prefix_opt->nd_opt_pi_prefix_len) { - uint8_t prefixlen; - - prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len); - - log_ndisc(nd, "Prefix length mismatch %d/%d using %d", - prefix->len, - prefix_opt->nd_opt_pi_prefix_len, - prefixlen); - - prefix->len = prefixlen; - } - - log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime_valid, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); - } - - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) - return r; - - prefix->valid_until = time_now + lifetime_valid * USEC_PER_SEC; - - if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && nd->prefix_onlink_callback) - nd->prefix_onlink_callback(nd, &prefix->addr, prefix->len, prefix->valid_until, nd->userdata); - - if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && nd->prefix_autonomous_callback) - nd->prefix_autonomous_callback(nd, &prefix->addr, prefix->len, lifetime_preferred, lifetime_valid, - nd->userdata); - - return 0; -} - -static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, size_t len) { - struct nd_opt_hdr *opt_hdr; - void *opt; - - assert(nd); - assert(ra); - - if (len < sizeof(struct nd_router_advert) + NDISC_OPT_LEN_UNITS) { - log_ndisc(nd, "Router Advertisement below minimum length"); - return -EBADMSG; - } - - len -= sizeof(struct nd_router_advert); - opt = ra + 1; - opt_hdr = opt; - - while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) { - struct nd_opt_mtu *opt_mtu; - struct nd_opt_prefix_info *opt_prefix; - uint32_t mtu; - - if (opt_hdr->nd_opt_len == 0) - return -EBADMSG; - - switch (opt_hdr->nd_opt_type) { - - case ND_OPT_MTU: - opt_mtu = opt; - - mtu = be32toh(opt_mtu->nd_opt_mtu_mtu); - - if (mtu != nd->mtu) { - nd->mtu = MAX(mtu, IP6_MIN_MTU); - log_ndisc(nd, "Router Advertisement link MTU %d using %d", mtu, nd->mtu); - } - - break; - - case ND_OPT_PREFIX_INFORMATION: - opt_prefix = opt; - ndisc_prefix_update(nd, len, opt_prefix); - break; - } + return 0; - len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS; - opt = (void*) ((uint8_t*) opt + opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS); - opt_hdr = opt; - } + /* Update global variables we keep */ + if (rt->mtu > 0) + nd->mtu = rt->mtu; + if (rt->hop_limit > 0) + nd->hop_limit = rt->hop_limit; - if (len > 0) - log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len); + log_ndisc("Received Router Advertisement: flags %s preference %s lifetime %" PRIu16 " sec", + rt->flags & ND_RA_FLAG_MANAGED ? "MANAGED" : rt->flags & ND_RA_FLAG_OTHER ? "OTHER" : "none", + rt->preference == SD_NDISC_PREFERENCE_HIGH ? "high" : rt->preference == SD_NDISC_PREFERENCE_LOW ? "low" : "medium", + rt->lifetime); + ndisc_callback(nd, SD_NDISC_EVENT_ROUTER, rt); return 0; } -static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_free_ struct nd_router_advert *ra = NULL; +static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(sd_ndisc_router_unrefp) sd_ndisc_router *rt = NULL; sd_ndisc *nd = userdata; union { struct cmsghdr cmsghdr; - uint8_t buf[CMSG_LEN(sizeof(int))]; + uint8_t buf[CMSG_SPACE(sizeof(int)) + /* ttl */ + CMSG_SPACE(sizeof(struct timeval))]; } control = {}; struct iovec iov = {}; union sockaddr_union sa = {}; @@ -490,10 +239,7 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t .msg_controllen = sizeof(control), }; struct cmsghdr *cmsg; - struct in6_addr *gw; - unsigned lifetime; ssize_t len, buflen; - int r, pref, stateful; assert(s); assert(nd); @@ -501,35 +247,47 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t buflen = next_datagram_size_fd(fd); if (buflen < 0) - return buflen; - - iov.iov_len = buflen; + return log_ndisc_errno(buflen, "Failed to determine datagram size to read: %m"); - ra = malloc(iov.iov_len); - if (!ra) + rt = ndisc_router_new(buflen); + if (!rt) return -ENOMEM; - iov.iov_base = ra; + iov.iov_base = NDISC_ROUTER_RAW(rt); + iov.iov_len = rt->raw_size; - len = recvmsg(fd, &msg, 0); + len = recvmsg(fd, &msg, MSG_DONTWAIT); if (len < 0) { if (errno == EAGAIN || errno == EINTR) return 0; - return log_ndisc_errno(nd, errno, "Could not receive message from ICMPv6 socket: %m"); + return log_ndisc_errno(errno, "Could not receive message from ICMPv6 socket: %m"); } - if ((size_t) len < sizeof(struct nd_router_advert)) { - log_ndisc(nd, "Too small to be a router advertisement: ignoring"); - return 0; + + if ((size_t) len != rt->raw_size) { + log_ndisc("Packet size mismatch."); + return -EINVAL; } - if (msg.msg_namelen == 0) - gw = NULL; /* only happens when running the test-suite over a socketpair */ - else if (msg.msg_namelen != sizeof(sa.in6)) { - log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen); - return 0; - } else - gw = &sa.in6.sin6_addr; + if (msg.msg_namelen == sizeof(struct sockaddr_in6) && + sa.in6.sin6_family == AF_INET6) { + + if (in_addr_is_link_local(AF_INET6, (union in_addr_union*) &sa.in6.sin6_addr) <= 0) { + _cleanup_free_ char *addr = NULL; + + (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &sa.in6.sin6_addr, &addr); + log_ndisc("Received RA from non-link-local address %s. Ignoring.", strna(addr)); + return 0; + } + + rt->address = sa.in6.sin6_addr; + + } else if (msg.msg_namelen > 0) { + log_ndisc("Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t) msg.msg_namelen); + return -EINVAL; + } + + /* namelen == 0 only happens when running the test-suite over a socketpair */ assert(!(msg.msg_flags & MSG_CTRUNC)); assert(!(msg.msg_flags & MSG_TRUNC)); @@ -538,61 +296,29 @@ static int ndisc_router_advertisement_recv(sd_event_source *s, int fd, uint32_t if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { - int hops = *(int*)CMSG_DATA(cmsg); + int hops = *(int*) CMSG_DATA(cmsg); if (hops != 255) { - log_ndisc(nd, "Received RA with invalid hop limit %d. Ignoring.", hops); + log_ndisc("Received RA with invalid hop limit %d. Ignoring.", hops); return 0; } - - break; } - } - if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) { - _cleanup_free_ char *addr = NULL; - - (void)in_addr_to_string(AF_INET6, (const union in_addr_union*) gw, &addr); - - log_ndisc(nd, "Received RA from non-link-local address %s. Ignoring.", strna(addr)); - return 0; + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMP && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) + triple_timestamp_from_realtime(&rt->timestamp, timeval_load(CMSG_DATA(cmsg))); } - if (ra->nd_ra_type != ND_ROUTER_ADVERT) - return 0; - - if (ra->nd_ra_code != 0) - return 0; + if (!triple_timestamp_is_set(&rt->timestamp)) + triple_timestamp_get(&rt->timestamp); nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; - - stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER); - pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3; - - if (!IN_SET(pref, ND_RA_FLAG_PREF_LOW, ND_RA_FLAG_PREF_HIGH)) - pref = ND_RA_FLAG_PREF_MEDIUM; - - lifetime = be16toh(ra->nd_ra_router_lifetime); - - log_ndisc(nd, "Received Router Advertisement: flags %s preference %s lifetime %u sec", - stateful & ND_RA_FLAG_MANAGED ? "MANAGED" : stateful & ND_RA_FLAG_OTHER ? "OTHER" : "none", - pref == ND_RA_FLAG_PREF_HIGH ? "high" : pref == ND_RA_FLAG_PREF_LOW ? "low" : "medium", - lifetime); - r = ndisc_ra_parse(nd, ra, (size_t) len); - if (r < 0) { - log_ndisc_errno(nd, r, "Could not parse Router Advertisement: %m"); - return 0; - } - - if (nd->router_callback) - nd->router_callback(nd, stateful, gw, lifetime, pref, nd->userdata); - - return 0; + return ndisc_handle_datagram(nd, rt); } -static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { +static int ndisc_timeout(sd_event_source *s, uint64_t usec, void *userdata) { sd_ndisc *nd = userdata; usec_t time_now, next_timeout; int r; @@ -601,43 +327,34 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, assert(nd); assert(nd->event); - nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); - if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) { - if (nd->callback) - nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata); - nd->state = NDISC_STATE_ADVERTISEMENT_LISTEN; - } else { - r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); - if (r < 0) { - log_ndisc_errno(nd, r, "Error sending Router Solicitation: %m"); - goto fail; - } else { - nd->state = NDISC_STATE_SOLICITATION_SENT; - log_ndisc(nd, "Sent Router Solicitation"); - } - - nd->nd_sent++; + nd->timeout_event_source = sd_event_source_unref(nd->timeout_event_source); + ndisc_callback(nd, SD_NDISC_EVENT_TIMEOUT, NULL); + return 0; + } - assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0); + r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); + if (r < 0) { + log_ndisc_errno(r, "Error sending Router Solicitation: %m"); + goto fail; + } - next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL; + log_ndisc("Sent Router Solicitation"); + nd->nd_sent++; - r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), - next_timeout, 0, - ndisc_router_solicitation_timeout, nd); - if (r < 0) { - log_ndisc_errno(nd, r, "Failed to allocate timer event: %m"); - goto fail; - } + assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0); + next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL; - r = sd_event_source_set_priority(nd->timeout_event_source, nd->event_priority); - if (r < 0) { - log_ndisc_errno(nd, r, "Cannot set timer priority: %m"); - goto fail; - } + r = sd_event_source_set_time(nd->timeout_event_source, next_timeout); + if (r < 0) { + log_ndisc_errno(r, "Error updating timer: %m"); + goto fail; + } - (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); + r = sd_event_source_set_enabled(nd->timeout_event_source, SD_EVENT_ONESHOT); + if (r < 0) { + log_ndisc_errno(r, "Error reenabling timer: %m"); + goto fail; } return 0; @@ -647,38 +364,36 @@ fail: return 0; } -int sd_ndisc_stop(sd_ndisc *nd) { +_public_ int sd_ndisc_stop(sd_ndisc *nd) { assert_return(nd, -EINVAL); - if (nd->state == NDISC_STATE_IDLE) + if (nd->fd < 0) return 0; - log_ndisc(nd, "Stopping IPv6 Router Solicitation client"); + log_ndisc("Stopping IPv6 Router Solicitation client"); ndisc_reset(nd); - nd->state = NDISC_STATE_IDLE; - - if (nd->callback) - nd->callback(nd, SD_NDISC_EVENT_STOP, nd->userdata); - - return 0; + return 1; } -int sd_ndisc_router_discovery_start(sd_ndisc *nd) { +_public_ int sd_ndisc_start(sd_ndisc *nd) { int r; assert_return(nd, -EINVAL); assert_return(nd->event, -EINVAL); assert_return(nd->ifindex > 0, -EINVAL); - assert_return(nd->state == NDISC_STATE_IDLE, -EBUSY); - r = icmp6_bind_router_solicitation(nd->ifindex); - if (r < 0) - return r; + if (nd->fd >= 0) + return 0; - nd->fd = r; + assert(!nd->recv_event_source); + assert(!nd->timeout_event_source); - r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_router_advertisement_recv, nd); + nd->fd = icmp6_bind_router_solicitation(nd->ifindex); + if (nd->fd < 0) + return nd->fd; + + r = sd_event_add_io(nd->event, &nd->recv_event_source, nd->fd, EPOLLIN, ndisc_recv, nd); if (r < 0) goto fail; @@ -688,7 +403,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { (void) sd_event_source_set_description(nd->recv_event_source, "ndisc-receive-message"); - r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_router_solicitation_timeout, nd); + r = sd_event_add_time(nd->event, &nd->timeout_event_source, clock_boottime_or_monotonic(), 0, 0, ndisc_timeout, nd); if (r < 0) goto fail; @@ -698,8 +413,8 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { (void) sd_event_source_set_description(nd->timeout_event_source, "ndisc-timeout"); - log_ndisc(ns, "Started IPv6 Router Solicitation client"); - return 0; + log_ndisc("Started IPv6 Router Solicitation client"); + return 1; fail: ndisc_reset(nd); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index 4817c968ac..d9669488be 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -18,11 +18,15 @@ ***/ #include +#include #include "sd-ndisc.h" +#include "alloc-util.h" +#include "hexdecoct.h" #include "icmp6-util.h" #include "socket-util.h" +#include "strv.h" static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} @@ -35,6 +39,144 @@ static int test_fd[2]; typedef int (*send_ra_t)(uint8_t flags); static send_ra_t send_ra_function; +static void router_dump(sd_ndisc_router *rt) { + struct in6_addr addr; + char buf[FORMAT_TIMESTAMP_MAX]; + uint8_t hop_limit; + uint64_t t, flags; + uint32_t mtu; + uint16_t lifetime; + unsigned preference; + int r; + + assert_se(rt); + + log_info("--"); + assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA); + + assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0); + log_info("Timestamp: %s", format_timestamp(buf, sizeof(buf), t)); + + assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0); + log_info("Monotonic: %" PRIu64, t); + + if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0) + log_info("No hop limit set"); + else + log_info("Hop limit: %u", hop_limit); + + assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0); + log_info("Flags: <%s|%s>", + flags & ND_RA_FLAG_OTHER ? "OTHER" : "", + flags & ND_RA_FLAG_MANAGED ? "MANAGED" : ""); + + assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0); + log_info("Preference: %s", + preference == SD_NDISC_PREFERENCE_LOW ? "low" : + preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium"); + + assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0); + log_info("Lifetime: %" PRIu16, lifetime); + + if (sd_ndisc_router_get_mtu(rt, &mtu) < 0) + log_info("No MTU set"); + else + log_info("MTU: %" PRIu32, mtu); + + r = sd_ndisc_router_option_rewind(rt); + for (;;) { + uint8_t type; + + assert_se(r >= 0); + + if (r == 0) + break; + + assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0); + + log_info(">> Option %u", type); + + switch (type) { + + case SD_NDISC_OPTION_SOURCE_LL_ADDRESS: + case SD_NDISC_OPTION_TARGET_LL_ADDRESS: { + _cleanup_free_ char *c = NULL; + const void *p; + size_t n; + + assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0); + assert_se(n > 2); + assert_se(c = hexmem((uint8_t*) p + 2, n - 2)); + + log_info("Address: %s", c); + break; + } + + case SD_NDISC_OPTION_PREFIX_INFORMATION: { + uint32_t lifetime_valid, lifetime_preferred; + unsigned prefix_len; + uint8_t pfl; + struct in6_addr a; + char buff[INET6_ADDRSTRLEN]; + + assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0); + log_info("Valid Lifetime: %" PRIu32, lifetime_valid); + + assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0); + log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred); + + assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0); + log_info("Flags: <%s|%s>", + pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "", + pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : ""); + + assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0); + log_info("Prefix Length: %u", prefix_len); + + assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0); + log_info("Prefix: %s", inet_ntop(AF_INET6, &a, buff, sizeof(buff))); + + break; + } + + case SD_NDISC_OPTION_RDNSS: { + const struct in6_addr *a; + uint32_t lt; + int n, i; + + n = sd_ndisc_router_rdnss_get_addresses(rt, &a); + assert_se(n > 0); + + for (i = 0; i < n; i++) { + char buff[INET6_ADDRSTRLEN]; + log_info("DNS: %s", inet_ntop(AF_INET6, a + i, buff, sizeof(buff))); + } + + assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, <) >= 0); + log_info("Lifetime: %" PRIu32, lt); + break; + } + + case SD_NDISC_OPTION_DNSSL: { + _cleanup_strv_free_ char **l = NULL; + uint32_t lt; + int n, i; + + n = sd_ndisc_router_dnssl_get_domains(rt, &l); + assert_se(n > 0); + + for (i = 0; i < n; i++) + log_info("Domain: %s", l[i]); + + assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, <) >= 0); + log_info("Lifetime: %" PRIu32, lt); + break; + }} + + r = sd_ndisc_router_option_next(rt); + } +} + static int test_rs_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) { assert_se(false); @@ -83,32 +225,39 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { return send_ra_function(0); } -static void test_rs_done(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { +static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) { sd_event *e = userdata; static unsigned idx = 0; - uint8_t flags_array[] = { + uint64_t flags_array[] = { 0, 0, 0, ND_RA_FLAG_OTHER, ND_RA_FLAG_MANAGED }; + uint64_t flags; uint32_t mtu; assert_se(nd); + if (event != SD_NDISC_EVENT_ROUTER) + return; + + router_dump(rt); + + assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0); assert_se(flags == flags_array[idx]); idx++; if (verbose) - printf(" got event 0x%02x\n", flags); + printf(" got event 0x%02" PRIx64 "\n", flags); if (idx < ELEMENTSOF(flags_array)) { send_ra(flags_array[idx]); return; } - assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG); + assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA); sd_event_exit(e, 0); } @@ -132,17 +281,17 @@ static void test_rs(void) { assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0); assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0); - assert_se(sd_ndisc_set_callback(nd, test_rs_done, NULL, NULL, NULL, e) >= 0); + assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0); assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), time_now + 2 *USEC_PER_SEC, 0, test_rs_hangcheck, NULL) >= 0); assert_se(sd_ndisc_stop(nd) >= 0); - assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + assert_se(sd_ndisc_start(nd) >= 0); assert_se(sd_ndisc_stop(nd) >= 0); - assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + assert_se(sd_ndisc_start(nd) >= 0); sd_event_loop(e); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 50721b1c74..15acf56a5f 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -60,10 +60,15 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, return 1; } -static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr, - uint32_t lifetime_preferred, uint32_t lifetime_valid) { - int r; +static int dhcp6_address_change( + Link *link, + struct in6_addr *ip6_addr, + uint32_t lifetime_preferred, + uint32_t lifetime_valid) { + _cleanup_address_free_ Address *addr = NULL; + char buffer[INET6_ADDRSTRLEN]; + int r; r = address_new(&addr); if (r < 0) @@ -79,8 +84,8 @@ static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr, addr->cinfo.ifa_valid = lifetime_valid; log_link_info(link, - "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", - SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6), + "DHCPv6 address %s/%d timeout preferred %d valid %d", + inet_ntop(AF_INET6, &addr->in_addr.in6, buffer, sizeof(buffer)), addr->prefixlen, lifetime_preferred, lifetime_valid); r = address_configure(addr, link, dhcp6_address_handler, true); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 90ed55d42c..11628339b9 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -28,8 +28,9 @@ #include "fileio.h" #include "netlink-util.h" #include "network-internal.h" -#include "networkd.h" #include "networkd-lldp-tx.h" +#include "networkd-ndisc.h" +#include "networkd.h" #include "set.h" #include "socket-util.h" #include "stdio-util.h" @@ -504,7 +505,10 @@ static void link_free(Link *link) { sd_ipv4ll_unref(link->ipv4ll); sd_dhcp6_client_unref(link->dhcp6_client); - sd_ndisc_unref(link->ndisc_router_discovery); + sd_ndisc_unref(link->ndisc); + + set_free_free(link->ndisc_rdnss); + set_free_free(link->ndisc_dnssl); if (link->manager) hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)); @@ -616,8 +620,8 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m"); } - if (link->ndisc_router_discovery) { - k = sd_ndisc_stop(link->ndisc_router_discovery); + if (link->ndisc) { + k = sd_ndisc_stop(link->ndisc); if (k < 0) r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m"); } @@ -1453,11 +1457,11 @@ static int link_acquire_ipv6_conf(Link *link) { } if (link_ipv6_accept_ra_enabled(link)) { - assert(link->ndisc_router_discovery); + assert(link->ndisc); log_link_debug(link, "Discovering IPv6 routers"); - r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery); + r = sd_ndisc_start(link->ndisc); if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m"); } @@ -3087,6 +3091,22 @@ int link_save(Link *link) { if (space) fputc(' ', f); serialize_in6_addrs(f, in6_addrs, r); + space = true; + } + } + + /* Make sure to flush out old entries before we use the NDISC data */ + ndisc_vacuum(link); + + if (link->network->dhcp_use_dns && link->ndisc_rdnss) { + NDiscRDNSS *dd; + + SET_FOREACH(dd, link->ndisc_rdnss, i) { + if (space) + fputc(' ', f); + + serialize_in6_addrs(f, &dd->address, 1); + space = true; } } @@ -3132,7 +3152,6 @@ int link_save(Link *link) { if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { if (link->dhcp_lease) (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname); - if (dhcp6_lease) (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains); } @@ -3140,22 +3159,34 @@ int link_save(Link *link) { fputs("DOMAINS=", f); fputstrv(f, link->network->search_domains, NULL, &space); - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp_domainname) - fputs_with_space(f, dhcp_domainname, NULL, &space); + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) { + NDiscDNSSL *dd; - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp6_domains) - fputstrv(f, dhcp6_domains, NULL, &space); + if (dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); + if (dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); + + SET_FOREACH(dd, link->ndisc_dnssl, i) + fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); + } fputc('\n', f); fputs("ROUTE_DOMAINS=", f); fputstrv(f, link->network->route_domains, NULL, NULL); - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp_domainname) - fputs_with_space(f, dhcp_domainname, NULL, &space); + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) { + NDiscDNSSL *dd; - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp6_domains) - fputstrv(f, dhcp6_domains, NULL, &space); + if (dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); + if (dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); + + SET_FOREACH(dd, link->ndisc_dnssl, i) + fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); + } fputc('\n', f); diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 5efefd27d6..7db94e79e8 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -98,6 +98,7 @@ typedef struct Link { unsigned dhcp4_messages; bool dhcp4_configured; bool dhcp6_configured; + unsigned ndisc_messages; bool ndisc_configured; @@ -111,7 +112,10 @@ typedef struct Link { sd_dhcp_server *dhcp_server; - sd_ndisc *ndisc_router_discovery; + sd_ndisc *ndisc; + Set *ndisc_rdnss; + Set *ndisc_dnssl; + sd_dhcp6_client *dhcp6_client; bool rtnl_extended_attrs; @@ -161,7 +165,6 @@ int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); int dhcp6_configure(Link *link); int dhcp6_request_address(Link *link, int ir); -int ndisc_configure(Link *link); const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index a0d4fa77d8..2a1ba2bac7 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -17,14 +17,15 @@ along with systemd; If not, see . ***/ -#include #include -#include -#include #include "sd-ndisc.h" #include "networkd.h" +#include "networkd-ndisc.h" + +#define NDISC_DNSSL_MAX 64U +#define NDISC_RDNSS_MAX 64U static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; @@ -49,19 +50,92 @@ static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void * return 1; } -static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime_preferred, unsigned lifetime_valid, void *userdata) { - _cleanup_address_free_ Address *address = NULL; - Link *link = userdata; +static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { + _cleanup_route_free_ Route *route = NULL; + struct in6_addr gateway; + uint16_t lifetime; + unsigned preference; usec_t time_now; int r; - assert(nd); assert(link); - assert(link->network); + assert(rt); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + r = sd_ndisc_router_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; + } + if (lifetime == 0) /* not a default router */ + return; + + r = sd_ndisc_router_get_address(rt, &gateway); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; + } + + r = sd_ndisc_router_get_preference(rt, &preference); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m"); + return; + } + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } + + r = route_new(&route); + if (r < 0) { + log_link_error_errno(link, r, "Could not allocate route: %m"); + return; + } + + route->family = AF_INET6; + route->table = RT_TABLE_MAIN; + route->protocol = RTPROT_RA; + route->pref = preference; + route->gw.in6 = gateway; + route->lifetime = time_now + lifetime * USEC_PER_SEC; + + r = route_configure(route, link, ndisc_netlink_handler); + if (r < 0) { + log_link_warning_errno(link, r, "Could not set default route: %m"); + link_enter_failed(link); + return; + } + + link->ndisc_messages++; +} + +static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) { + _cleanup_address_free_ Address *address = NULL; + uint32_t lifetime_valid, lifetime_preferred; + unsigned prefixlen; + int r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix length: %m"); + return; + } + + r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m"); return; + } + + r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m"); + return; + } r = address_new(&address); if (r < 0) { @@ -69,10 +143,13 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr return; } - assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); - address->family = AF_INET6; - address->in_addr.in6 = *prefix; + r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix address: %m"); + return; + } + if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0) memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8); else { @@ -102,17 +179,33 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr link->ndisc_messages++; } -static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) { +static void ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { _cleanup_route_free_ Route *route = NULL; - Link *link = userdata; usec_t time_now; + uint32_t lifetime; + unsigned prefixlen; int r; - assert(nd); assert(link); + assert(rt); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); return; + } + + r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix length: %m"); + return; + } + + r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix lifetime: %m"); + return; + } r = route_new(&route); if (r < 0) { @@ -120,16 +213,19 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre return; } - assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); - route->family = AF_INET6; route->table = RT_TABLE_MAIN; route->protocol = RTPROT_RA; route->flags = RTM_F_PREFIX; - route->dst.in6 = *prefix; route->dst_prefixlen = prefixlen; route->lifetime = time_now + lifetime * USEC_PER_SEC; + r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get prefix address: %m"); + return; + } + r = route_configure(route, link, ndisc_netlink_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set prefix route: %m"); @@ -140,32 +236,47 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre link->ndisc_messages++; } -static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { +static void ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { _cleanup_route_free_ Route *route = NULL; - Link *link = userdata; + struct in6_addr gateway; + uint32_t lifetime; + unsigned preference, prefixlen; usec_t time_now; int r; assert(link); - assert(link->network); - assert(link->manager); - assert(link->dhcp6_client); - assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + r = sd_ndisc_router_route_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; + } + if (lifetime == 0) return; - if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) { - /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */ - r = dhcp6_request_address(link, flags & ND_RA_FLAG_MANAGED ? false : true); - if (r < 0 && r != -EBUSY) - log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m"); - else - log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request"); + r = sd_ndisc_router_get_address(rt, &gateway); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m"); + return; } - if (!gateway) + r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get route prefix length: %m"); return; + } + + r = sd_ndisc_router_route_get_preference(rt, &preference); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m"); + return; + } + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } r = route_new(&route); if (r < 0) { @@ -173,18 +284,23 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a return; } - assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); - route->family = AF_INET6; route->table = RT_TABLE_MAIN; route->protocol = RTPROT_RA; - route->pref = pref; - route->gw.in6 = *gateway; + route->pref = preference; + route->gw.in6 = gateway; + route->dst_prefixlen = prefixlen; route->lifetime = time_now + lifetime * USEC_PER_SEC; + r = sd_ndisc_router_route_get_address(rt, &route->dst.in6); + if (r < 0) { + log_link_error_errno(link, r, "Failed to get route address: %m"); + return; + } + r = route_configure(route, link, ndisc_netlink_handler); if (r < 0) { - log_link_warning_errno(link, r, "Could not set default route: %m"); + log_link_warning_errno(link, r, "Could not set additional route: %m"); link_enter_failed(link); return; } @@ -192,7 +308,290 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a link->ndisc_messages++; } -static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { +static void ndisc_rdnss_hash_func(const void *p, struct siphash *state) { + const NDiscRDNSS *x = p; + + siphash24_compress(&x->address, sizeof(x->address), state); +} + +static int ndisc_rdnss_compare_func(const void *_a, const void *_b) { + const NDiscRDNSS *a = _a, *b = _b; + + return memcmp(&a->address, &b->address, sizeof(a->address)); +} + +static const struct hash_ops ndisc_rdnss_hash_ops = { + .hash = ndisc_rdnss_hash_func, + .compare = ndisc_rdnss_compare_func +}; + +static void ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { + uint32_t lifetime; + const struct in6_addr *a; + usec_t time_now; + int i, n, r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } + + r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m"); + return; + } + + n = sd_ndisc_router_rdnss_get_addresses(rt, &a); + if (n < 0) { + log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m"); + return; + } + + for (i = 0; i < n; i++) { + NDiscRDNSS d = { + .address = a[i] + }, *x; + + if (lifetime == 0) { + (void) set_remove(link->ndisc_rdnss, &d); + link_dirty(link); + continue; + } + + x = set_get(link->ndisc_rdnss, &d); + if (x) { + x->valid_until = time_now + lifetime * USEC_PER_SEC; + continue; + } + + ndisc_vacuum(link); + + if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) { + log_link_warning(link, "Too many RDNSS records per link, ignoring."); + continue; + } + + r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops); + if (r < 0) { + log_oom(); + return; + } + + x = new0(NDiscRDNSS, 1); + if (!x) { + log_oom(); + return; + } + + x->address = a[i]; + x->valid_until = time_now + lifetime * USEC_PER_SEC; + + r = set_put(link->ndisc_rdnss, x); + if (r < 0) { + free(x); + log_oom(); + return; + } + + assert(r > 0); + link_dirty(link); + } +} + +static void ndisc_dnssl_hash_func(const void *p, struct siphash *state) { + const NDiscDNSSL *x = p; + + siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state); +} + +static int ndisc_dnssl_compare_func(const void *_a, const void *_b) { + const NDiscDNSSL *a = _a, *b = _b; + + return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b)); +} + +static const struct hash_ops ndisc_dnssl_hash_ops = { + .hash = ndisc_dnssl_hash_func, + .compare = ndisc_dnssl_compare_func +}; + +static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { + _cleanup_strv_free_ char **l = NULL; + uint32_t lifetime; + usec_t time_now; + char **i; + int r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA timestamp: %m"); + return; + } + + r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m"); + return; + } + + r = sd_ndisc_router_dnssl_get_domains(rt, &l); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m"); + return; + } + + STRV_FOREACH(i, l) { + struct { + NDiscDNSSL header; + char domain[strlen(*i)]; + } s; + NDiscDNSSL *x; + + zero(s.header); + strcpy(s.domain, *i); + + if (lifetime == 0) { + (void) set_remove(link->ndisc_dnssl, &s); + link_dirty(link); + continue; + } + + x = set_get(link->ndisc_dnssl, &s); + if (x) { + x->valid_until = time_now + lifetime * USEC_PER_SEC; + continue; + } + + ndisc_vacuum(link); + + if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) { + log_link_warning(link, "Too many DNSSL records per link, ignoring."); + continue; + } + + r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops); + if (r < 0) { + log_oom(); + return; + } + + x = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1); + if (!x) { + log_oom(); + return; + } + + strcpy(NDISC_DNSSL_DOMAIN(x), *i); + x->valid_until = time_now + lifetime * USEC_PER_SEC; + + r = set_put(link->ndisc_dnssl, x); + if (r < 0) { + free(x); + log_oom(); + return; + } + + assert(r > 0); + link_dirty(link); + } +} + +static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) { + int r; + + assert(link); + assert(rt); + + r = sd_ndisc_router_option_rewind(rt); + for (;;) { + uint8_t type; + + if (r < 0) { + log_link_warning_errno(link, r, "Failed to iterate through options: %m"); + return; + } + if (r == 0) /* EOF */ + break; + + r = sd_ndisc_router_option_get_type(rt, &type); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA option type: %m"); + return; + } + + switch (type) { + + case SD_NDISC_OPTION_PREFIX_INFORMATION: { + uint8_t flags; + + r = sd_ndisc_router_prefix_get_flags(rt, &flags); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m"); + return; + } + + if (flags & ND_OPT_PI_FLAG_ONLINK) + ndisc_router_process_onlink_prefix(link, rt); + if (flags & ND_OPT_PI_FLAG_AUTO) + ndisc_router_process_autonomous_prefix(link, rt); + + break; + } + + case SD_NDISC_OPTION_ROUTE_INFORMATION: + ndisc_router_process_route(link, rt); + break; + + case SD_NDISC_OPTION_RDNSS: + ndisc_router_process_rdnss(link, rt); + break; + + case SD_NDISC_OPTION_DNSSL: + ndisc_router_process_dnssl(link, rt); + break; + } + + r = sd_ndisc_router_option_next(rt); + } +} + +static void ndisc_router_handler(Link *link, sd_ndisc_router *rt) { + uint64_t flags; + int r; + + assert(link); + assert(link->network); + assert(link->manager); + assert(rt); + + r = sd_ndisc_router_get_flags(rt, &flags); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to get RA flags: %m"); + return; + } + + if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) { + /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */ + r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED)); + if (r < 0 && r != -EBUSY) + log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m"); + else + log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request"); + } + + ndisc_router_process_default(link, rt); + ndisc_router_process_options(link, rt); +} + +static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) { Link *link = userdata; assert(link); @@ -201,12 +600,15 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { return; switch (event) { + + case SD_NDISC_EVENT_ROUTER: + ndisc_router_handler(link, rt); + break; + case SD_NDISC_EVENT_TIMEOUT: link->ndisc_configured = true; link_check_ready(link); - break; - case SD_NDISC_EVENT_STOP: break; default: log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event); @@ -216,30 +618,52 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { int ndisc_configure(Link *link) { int r; - assert_return(link, -EINVAL); + assert(link); + + r = sd_ndisc_new(&link->ndisc); + if (r < 0) + return r; - r = sd_ndisc_new(&link->ndisc_router_discovery); + r = sd_ndisc_attach_event(link->ndisc, NULL, 0); if (r < 0) return r; - r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0); + r = sd_ndisc_set_mac(link->ndisc, &link->mac); if (r < 0) return r; - r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac); + r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex); if (r < 0) return r; - r = sd_ndisc_set_ifindex(link->ndisc_router_discovery, link->ifindex); + r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link); if (r < 0) return r; - r = sd_ndisc_set_callback(link->ndisc_router_discovery, - ndisc_router_handler, - ndisc_prefix_onlink_handler, - ndisc_prefix_autonomous_handler, - ndisc_handler, - link); + return 0; +} + +void ndisc_vacuum(Link *link) { + NDiscRDNSS *r; + NDiscDNSSL *d; + Iterator i; + usec_t time_now; + + assert(link); + + /* Removes all RDNSS and DNSSL entries whose validity time has passed */ + + time_now = now(clock_boottime_or_monotonic()); + + SET_FOREACH(r, link->ndisc_rdnss, i) + if (r->valid_until < time_now) { + (void) set_remove(link->ndisc_rdnss, r); + link_dirty(link); + } - return r; + SET_FOREACH(d, link->ndisc_dnssl, i) + if (d->valid_until < time_now) { + (void) set_remove(link->ndisc_dnssl, d); + link_dirty(link); + } } diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h new file mode 100644 index 0000000000..2002f55107 --- /dev/null +++ b/src/network/networkd-ndisc.h @@ -0,0 +1,39 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Tom Gundersen + + 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 . +***/ + +#include "networkd-link.h" + +typedef struct NDiscRDNSS { + usec_t valid_until; + struct in6_addr address; +} NDiscRDNSS; + +typedef struct NDiscDNSSL { + usec_t valid_until; + /* The domain name follows immediately. */ +} NDiscDNSSL; + +static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) { + return ((char*) n) + ALIGN(sizeof(NDiscDNSSL)); +} + +int ndisc_configure(Link *link); +void ndisc_vacuum(Link *link); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 03e4e3b39f..c722db55c7 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -89,6 +89,8 @@ DHCP.DUIDRawData, config_parse_duid_rawdata, DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) +IPv6AcceptRouterAdvertisements.UseDNS config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) +IPv6AcceptRouterAdvertisements.UseDomains config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index dd89b3770c..e961db60a7 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -51,8 +51,8 @@ static int network_load_one(Manager *manager, const char *filename) { if (!file) { if (errno == ENOENT) return 0; - else - return -errno; + + return -errno; } if (null_or_empty_fd(fileno(file))) { @@ -134,6 +134,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_hop_limit = -1; network->duid.type = _DUID_TYPE_INVALID; network->proxy_arp = -1; + network->ipv6_accept_ra_use_dns = true; r = config_parse(NULL, filename, file, "Match\0" diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 91099161ce..b54616b838 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -154,6 +154,9 @@ struct Network { int ipv6_hop_limit; int proxy_arp; + bool ipv6_accept_ra_use_dns; + DHCPUseDomains ipv6_accept_ra_use_domains; + union in_addr_union ipv6_token; IPv6PrivacyExtensions ipv6_privacy_extensions; diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 2b774233b8..9f7d4ef71a 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -22,6 +22,8 @@ #include #include +#include +#include #include "sd-event.h" @@ -29,55 +31,99 @@ _SD_BEGIN_DECLARATIONS; +/* Neightbor Discovery Options, RFC 4861, Section 4.6 and + * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */ enum { - SD_NDISC_EVENT_STOP = 0, - SD_NDISC_EVENT_TIMEOUT = 1, + SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1, + SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2, + SD_NDISC_OPTION_PREFIX_INFORMATION = 3, + SD_NDISC_OPTION_MTU = 5, + SD_NDISC_OPTION_ROUTE_INFORMATION = 24, + SD_NDISC_OPTION_RDNSS = 25, + SD_NDISC_OPTION_FLAGS_EXTENSION = 26, + SD_NDISC_OPTION_DNSSL = 31, + SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, +}; + +/* Route preference, RFC 4191, Section 2.1 */ +enum { + SD_NDISC_PREFERENCE_LOW = 3U, + SD_NDISC_PREFERENCE_MEDIUM = 0U, + SD_NDISC_PREFERENCE_HIGH = 1U, }; typedef struct sd_ndisc sd_ndisc; +typedef struct sd_ndisc_router sd_ndisc_router; -typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata); -typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime, void *userdata); -typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, - unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata); -typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata); - -int sd_ndisc_set_callback(sd_ndisc *nd, - sd_ndisc_router_callback_t rcb, - sd_ndisc_prefix_onlink_callback_t plcb, - sd_ndisc_prefix_autonomous_callback_t pacb, - sd_ndisc_callback_t cb, - void *userdata); -int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); -int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); +typedef enum sd_ndisc_event { + SD_NDISC_EVENT_TIMEOUT = 't', + SD_NDISC_EVENT_ROUTER = 'r', +} sd_ndisc_event; -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); -int sd_ndisc_detach_event(sd_ndisc *nd); -sd_event *sd_ndisc_get_event(sd_ndisc *nd); +typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata); +int sd_ndisc_new(sd_ndisc **ret); sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); -int sd_ndisc_new(sd_ndisc **ret); - -int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu); +int sd_ndisc_start(sd_ndisc *nd); int sd_ndisc_stop(sd_ndisc *nd); -int sd_ndisc_router_discovery_start(sd_ndisc *nd); -#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); +int sd_ndisc_detach_event(sd_ndisc *nd); +sd_event *sd_ndisc_get_event(sd_ndisc *nd); + +int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata); +int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \ - be16toh((address).s6_addr16[0]), \ - be16toh((address).s6_addr16[1]), \ - be16toh((address).s6_addr16[2]), \ - be16toh((address).s6_addr16[3]), \ - be16toh((address).s6_addr16[4]), \ - be16toh((address).s6_addr16[5]), \ - be16toh((address).s6_addr16[6]), \ - be16toh((address).s6_addr16[7]) +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *ret); +int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret); + +int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size); +sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); +sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); + +int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); + +int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags); +int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); +int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime); +int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); + +/* Generic option access */ +int sd_ndisc_router_option_rewind(sd_ndisc_router *rt); +int sd_ndisc_router_option_next(sd_ndisc_router *rt); +int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type); +int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); + +/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */ +int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret); +int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); + +/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */ +int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); +int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); +int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); +int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret); + +/* Specific option access: SD_NDISC_OPTION_RDNSS */ +int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret); +int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); + +/* Specific option access: SD_NDISC_OPTION_DNSSL */ +int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret); +int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref); _SD_END_DECLARATIONS; -- cgit v1.2.3-54-g00ecf From 646b997c118e261c5ececc434dd40d0dbdbac4d8 Mon Sep 17 00:00:00 2001 From: Benjamin Drung Date: Mon, 6 Jun 2016 22:05:29 +0200 Subject: os-release: Add VERSION_CODENAME field (#3445) Debian and their derivatives (Ubuntu, Trisquel, etc.) use a code name for their repositories. Thus record the code name in os-release for processing. Closes systemd/systemd#3429 --- man/os-release.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'man') diff --git a/man/os-release.xml b/man/os-release.xml index 4557abc4a3..99bbb61004 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -175,6 +175,22 @@ appropriate. + + VERSION_CODENAME= + + + A lower-case string (no spaces or other characters outside of + 0–9, a–z, ".", "_" and "-") identifying the operating system + release code name, excluding any OS name information or + release version, and suitable for processing by scripts or + usage in generated filenames. This field is optional and may + not be implemented on all systems. + Examples: + VERSION_CODENAME=buster, + VERSION_CODENAME=xenial + + + VERSION_ID= -- cgit v1.2.3-54-g00ecf From f921f5739e003c5e99cd78cfedab253be884525e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jun 2016 11:19:26 +0200 Subject: networkd: rename IPv6AcceptRouterAdvertisements to IPv6AcceptRA The long name is just too hard to type. We generally should avoid using acronyms too liberally, if they aren't established enough, but it appears that "RA" is known well enough. Internally we call the option "ipv6_accept_ra" anyway, and the kernel also exposes it under this name. Hence, let's rename the IPv6AcceptRouterAdvertisements= setting and the [IPv6AcceptRouterAdvertisements] section to IPv6AcceptRA= and [IPv6AcceptRA]. The old setting IPv6AcceptRouterAdvertisements= is kept for compatibility with older configuration. (However the section [IPv6AcceptRouterAdvertisements] is not, as it was never available in a published version of systemd. --- man/systemd.network.xml | 12 ++++++------ src/network/networkd-network-gperf.gperf | 6 ++++-- src/network/networkd-network.c | 1 + test/networkd-test.py | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) (limited to 'man') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 487bb2ab3f..24deb0d1d7 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -240,7 +240,7 @@ By enabling DHCPv6 support explicitly, the DHCPv6 client will be started regardless of the presence of routers on the link, or what flags the routers pass. See - IPv6AcceptRouterAdvertisements=. + IPv6AcceptRA=. Furthermore, note that by default the domain name specified through DHCP is not used for name resolution. @@ -527,7 +527,7 @@ no. - IPv6AcceptRouterAdvertisements= + IPv6AcceptRA= Enable or disable IPv6 Router Advertisement (RA) reception support for the interface. Takes a boolean parameter. If true, RAs are accepted; if false, RAs are ignored, independently of the local forwarding state. When not set, the kernel default is used, and RAs are accepted only when local forwarding @@ -535,7 +535,7 @@ the relevant flags are set in the RA data, or if no routers are found on the link. Further settings for the IPv6 RA support may be configured in the - [IPv6AcceptRouterAdvertisements] section, see below. + [IPv6AcceptRA] section, see below. Also see ip-sysctl.txt in the kernel @@ -895,9 +895,9 @@ - [IPv6AcceptRouterAdvertisements] Section Options - The [IPv6AcceptRouterAdvertisements] section configures the IPv6 Router Advertisement - (RA) client, if it is enabled with the IPv6AcceptRouterAdvertisements= setting described + [IPv6AcceptRA] Section Options + The [IPv6AcceptRA] section configures the IPv6 Router Advertisement + (RA) client, if it is enabled with the IPv6AcceptRA= setting described above: diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index c722db55c7..d9f5b95cdf 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -55,6 +55,8 @@ Network.NTP, config_parse_strv, 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.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) +/* legacy alias for the above */ Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits) Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit) @@ -89,8 +91,8 @@ DHCP.DUIDRawData, config_parse_duid_rawdata, DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid) -IPv6AcceptRouterAdvertisements.UseDNS config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) -IPv6AcceptRouterAdvertisements.UseDomains config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) +IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) +IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index e961db60a7..c03c0f0bed 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -145,6 +145,7 @@ static int network_load_one(Manager *manager, const char *filename) { "DHCP\0" "DHCPv4\0" /* compat */ "DHCPServer\0" + "IPv6AcceptRA\0" "Bridge\0" "BridgeFDB\0", config_item_perf_lookup, network_network_gperf_lookup, diff --git a/test/networkd-test.py b/test/networkd-test.py index f94224cce2..78da0a213a 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -205,7 +205,7 @@ DHCP=%s def test_coldplug_dhcp_yes_ip4_no_ra(self): # with disabling RA explicitly things should be fast self.do_test(coldplug=True, ipv6=False, - extra_opts='IPv6AcceptRouterAdvertisements=False') + extra_opts='IPv6AcceptRA=False') def test_coldplug_dhcp_ip4_only(self): # we have a 12s timeout on RA, so we need to wait longer @@ -215,7 +215,7 @@ DHCP=%s def test_coldplug_dhcp_ip4_only_no_ra(self): # with disabling RA explicitly things should be fast self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', - extra_opts='IPv6AcceptRouterAdvertisements=False') + extra_opts='IPv6AcceptRA=False') def test_coldplug_dhcp_ip6(self): self.do_test(coldplug=True, ipv6=True) -- cgit v1.2.3-54-g00ecf From 13b498f967c5117a88d72304bed1f8c0b9c1bb87 Mon Sep 17 00:00:00 2001 From: Tobias Jungel Date: Wed, 1 Jun 2016 15:18:21 +0200 Subject: networkd: add support to configure VLAN on bridge ports --- Makefile.am | 2 + man/systemd.network.xml | 53 +++++ src/basic/macro.h | 9 + src/basic/missing.h | 8 + src/network/networkd-brvlan.c | 335 +++++++++++++++++++++++++++++++ src/network/networkd-brvlan.h | 29 +++ src/network/networkd-link.c | 16 ++ src/network/networkd-network-gperf.gperf | 4 + src/network/networkd-network.c | 3 +- src/network/networkd-network.h | 8 + 10 files changed, 466 insertions(+), 1 deletion(-) create mode 100644 src/network/networkd-brvlan.c create mode 100644 src/network/networkd-brvlan.h (limited to 'man') diff --git a/Makefile.am b/Makefile.am index d233614403..528e0ced92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5480,6 +5480,8 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-manager-bus.c \ src/network/networkd-fdb.h \ src/network/networkd-fdb.c \ + src/network/networkd-brvlan.h \ + src/network/networkd-brvlan.c \ src/network/networkd-address-pool.h \ src/network/networkd-address-pool.c \ src/network/networkd-util.h \ diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 24deb0d1d7..ea98c821fa 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1130,6 +1130,39 @@ + + [BridgeVLAN] Section Options + The [BridgeVLAN] section manages the VLAN ID configuration of a bridge port and accepts + the following keys. Specify several [BridgeVLAN] sections to configure several VLAN entries. + The VLANFiltering= option has to be enabled, see [Bridge] section in + systemd.netdev5. + + + + VLAN= + + The VLAN ID allowed on the port. This can be either a single ID or a range M-N. VLAN IDs are valid + from 1 to 4094. + + + + EgressUntagged= + + The VLAN ID specified here will be used to untag frames on egress. Configuring + EgressUntagged= implicates the use of VLAN= above and will enable the + VLAN ID for ingress as well. This can be either a single ID or a range M-N. + + + + PVID= + + The Port VLAN ID specified here is assigned to all untagged frames at ingress. + PVID= can be used only once. Configuring PVID= implicates the use of + VLAN= above and will enable the VLAN ID for ingress as well. + + + + Example @@ -1174,6 +1207,26 @@ Name=enp2s0 [Network] Bridge=bridge0 +
+ + /etc/systemd/network/25-bridge-slave-interface-vlan.network + + [Match] +Name=enp2s0 + +[Network] +Bridge=bridge0 + +[BridgeVLAN] +VLAN=1-32 +PVID=42 +EgressUntagged=42 + +[BridgeVLAN] +VLAN=100-200 + +[BridgeVLAN] +EgressUntagged=300-400 /etc/systemd/network/25-ipip.network diff --git a/src/basic/macro.h b/src/basic/macro.h index e41aa4260f..6b2aeb933f 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -89,6 +89,15 @@ #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ +/* builtins */ +#if __SIZEOF_INT__ == 4 +#define BUILTIN_FFS_U32(x) __builtin_ffs(x); +#elif __SIZEOF_LONG__ == 4 +#define BUILTIN_FFS_U32(x) __builtin_ffsl(x); +#else +#error "neither int nor long are four bytes long?!?" +#endif + /* Rounds up */ #define ALIGN4(l) (((l) + 3) & ~3) diff --git a/src/basic/missing.h b/src/basic/missing.h index 51dafcaca9..8b977871e9 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -759,6 +759,14 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif +#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN +#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */ +#endif + +#ifndef BRIDGE_VLAN_INFO_RANGE_END +#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */ +#endif + #if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID #define IFLA_BR_UNSPEC 0 #define IFLA_BR_FORWARD_DELAY 1 diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c new file mode 100644 index 0000000000..77c08d090c --- /dev/null +++ b/src/network/networkd-brvlan.c @@ -0,0 +1,335 @@ +/*** + This file is part of systemd. + + Copyright (C) 2016 BISDN GmbH. All rights reserved. + + 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 . +***/ + +#include +#include +#include + +#include "alloc-util.h" +#include "conf-parser.h" +#include "netlink-util.h" +#include "networkd-brvlan.h" +#include "networkd.h" +#include "parse-util.h" +#include "vlan-util.h" + +static bool is_bit_set(unsigned bit, uint32_t scope) { + assert(bit < sizeof(scope)*8); + return scope & (1 << bit); +} + +static inline void set_bit(unsigned nr, uint32_t *addr) { + if (nr < BRIDGE_VLAN_BITMAP_MAX) + addr[nr / 32] |= (((uint32_t) 1) << (nr % 32)); +} + +static inline int is_vid_valid(unsigned vid) { + if (vid > VLANID_MAX || vid == 0) + return -EINVAL; + return 0; +} + +static int find_next_bit(int i, uint32_t x) { + int j; + + if (i >= 32) + return -1; + + /* find first bit */ + if (i < 0) + return BUILTIN_FFS_U32(x); + + /* mask off prior finds to get next */ + j = __builtin_ffs(x >> i); + return j ? j + i : 0; +} + +static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint16_t pvid, const uint32_t *br_vid_bitmap, const uint32_t *br_untagged_bitmap) { + struct bridge_vlan_info br_vlan; + int i, j, k, r, done, cnt; + uint16_t begin, end; + bool untagged; + + assert(link); + assert(req); + assert(br_vid_bitmap); + assert(br_untagged_bitmap); + + i = cnt = -1; + + begin = end = UINT16_MAX; + for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) { + unsigned base_bit; + uint32_t vid_map = br_vid_bitmap[k]; + uint32_t untagged_map = br_untagged_bitmap[k]; + + base_bit = k * 32; + i = -1; + done = 0; + do { + j = find_next_bit(i, vid_map); + if (j > 0) { + /* first hit of any bit */ + if (begin == UINT16_MAX && end == UINT16_MAX) { + begin = end = j - 1 + base_bit; + untagged = is_bit_set(j - 1, untagged_map); + goto next; + } + + /* this bit is a continuation of prior bits */ + if (j - 2 + base_bit == end && untagged == is_bit_set(j - 1, untagged_map) && (uint16_t)j - 1 + base_bit != pvid && (uint16_t)begin != pvid) { + end++; + goto next; + } + } else + done = 1; + + if (begin != UINT16_MAX) { + cnt++; + if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1) + break; + + br_vlan.flags = 0; + if (untagged) + br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED; + + if (begin == end) { + br_vlan.vid = begin; + + if (begin == pvid) + br_vlan.flags |= BRIDGE_VLAN_INFO_PVID; + + r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); + } else { + br_vlan.vid = begin; + br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN; + + r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); + + br_vlan.vid = end; + br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; + br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END; + + r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m"); + } + + if (done) + break; + } + if (j > 0) { + begin = end = j - 1 + base_bit; + untagged = is_bit_set(j - 1, untagged_map); + } + + next: + i = j; + } while(!done); + } + if (!cnt) + return -EINVAL; + + return cnt; +} + +static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EEXIST) + log_link_error_errno(link, r, "Could not add VLAN to bridge port: %m"); + + return 1; +} + +int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + int r; + uint16_t flags; + sd_netlink *rtnl; + + assert(link); + assert(link->manager); + assert(br_vid_bitmap); + assert(br_untagged_bitmap); + assert(link->network); + + /* pvid might not be in br_vid_bitmap yet */ + if (pvid) + set_bit(pvid, br_vid_bitmap); + + rtnl = link->manager->rtnl; + + /* create new RTM message */ + r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex); + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); + + r = sd_rtnl_message_link_set_family(req, PF_BRIDGE); + if (r < 0) + return log_link_error_errno(link, r, "Could not set message family: %m"); + + r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); + if (r < 0) + return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); + + /* master needs flag self */ + if (!link->network->bridge) { + flags = BRIDGE_FLAGS_SELF; + sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t)); + } + + /* add vlan info */ + r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap); + if (r < 0) + return log_link_error_errno(link, r, "Could not append VLANs: %m"); + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m"); + + /* send message to the kernel */ + r = sd_netlink_call_async(rtnl, req, set_brvlan_handler, link, 0, NULL); + if (r < 0) + return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); + + return 0; +} + +static int parse_vid_range(const char *rvalue, uint16_t *vid, uint16_t *vid_end) { + int r; + char *p; + char *_rvalue = NULL; + uint16_t _vid = UINT16_MAX; + uint16_t _vid_end = UINT16_MAX; + + assert(rvalue); + assert(vid); + assert(vid_end); + + _rvalue = strdupa(rvalue); + p = strchr(_rvalue, '-'); + if (p) { + *p = '\0'; + p++; + r = parse_vlanid(_rvalue, &_vid); + if (r < 0) + return r; + + if (!_vid) + return -ERANGE; + + r = parse_vlanid(p, &_vid_end); + if (r < 0) + return r; + + if (!_vid_end) + return -ERANGE; + } else { + r = parse_vlanid(_rvalue, &_vid); + if (r < 0) + return r; + + if (!_vid) + return -ERANGE; + } + + *vid = _vid; + *vid_end = _vid_end; + return r; +} + +int config_parse_brvlan_vlan(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) { + Network *network = userdata; + int r; + uint16_t vid, vid_end; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_vid_range(rvalue, &vid, &vid_end); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN, ignoring: %s", rvalue); + return 0; + } + + if (UINT16_MAX == vid_end) + set_bit(vid++, network->br_vid_bitmap); + else { + if (vid >= vid_end) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue); + return 0; + } + for (; vid <= vid_end; vid++) + set_bit(vid, network->br_vid_bitmap); + } + return 0; +} + +int config_parse_brvlan_untagged(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) { + Network *network = userdata; + int r; + uint16_t vid, vid_end; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = parse_vid_range(rvalue, &vid, &vid_end); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse VLAN: %s", rvalue); + return 0; + } + + if (UINT16_MAX == vid_end) { + set_bit(vid, network->br_vid_bitmap); + set_bit(vid, network->br_untagged_bitmap); + } else { + if (vid >= vid_end) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue); + return 0; + } + for (; vid <= vid_end; vid++) { + set_bit(vid, network->br_vid_bitmap); + set_bit(vid, network->br_untagged_bitmap); + } + } + return 0; +} diff --git a/src/network/networkd-brvlan.h b/src/network/networkd-brvlan.h new file mode 100644 index 0000000000..6aa6883bfc --- /dev/null +++ b/src/network/networkd-brvlan.h @@ -0,0 +1,29 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2016 BISDN GmbH. All rights reserved. + + 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 . +***/ + +#include + +typedef struct Link Link; + +int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap); + +int config_parse_brvlan_vlan(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_brvlan_untagged(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-link.c b/src/network/networkd-link.c index 5f25873b46..dce5c2be6e 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1114,6 +1114,16 @@ int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u return 1; } +static int link_set_bridge_vlan(Link *link) { + int r = 0; + + r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap); + if (r < 0) + log_link_error_errno(link, r, "Failed to assign VLANs to bridge port: %m"); + + return r; +} + static int link_set_bridge_fdb(Link *link) { FdbEntry *fdb_entry; int r = 0; @@ -1996,6 +2006,12 @@ static int link_joined(Link *link) { log_link_error_errno(link, r, "Could not set bridge message: %m"); } + if (link->network->bridge || NETDEV_KIND_BRIDGE == netdev_kind_from_string(link->kind)) { + r = link_set_bridge_vlan(link); + if (r < 0) + log_link_error_errno(link, r, "Could not set bridge vlan: %m"); + } + return link_enter_set_addresses(link); } diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index d9f5b95cdf..0b0aa58f67 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -4,6 +4,7 @@ #include "networkd.h" #include "networkd-conf.h" #include "network-internal.h" +#include "vlan-util.h" %} struct ConfigPerfItem; %null_strings @@ -112,6 +113,9 @@ Bridge.AllowPortToBeRoot, config_parse_bool, Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood) BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 +BridgeVLAN.PVID, config_parse_vlanid, 0, offsetof(Network, pvid) +BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0 +BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 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_use_dns) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c03c0f0bed..84bdf75b38 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -147,7 +147,8 @@ static int network_load_one(Manager *manager, const char *filename) { "DHCPServer\0" "IPv6AcceptRA\0" "Bridge\0" - "BridgeFDB\0", + "BridgeFDB\0" + "BridgeVLAN\0", config_item_perf_lookup, network_network_gperf_lookup, false, false, true, network); if (r < 0) diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index a49748d1b1..38688cc400 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -28,6 +28,7 @@ #include "resolve-util.h" #include "networkd-address.h" +#include "networkd-brvlan.h" #include "networkd-fdb.h" #include "networkd-lldp-tx.h" #include "networkd-netdev.h" @@ -37,6 +38,9 @@ #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 +#define BRIDGE_VLAN_BITMAP_MAX 4096 +#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32) + typedef enum DCHPClientIdentifier { DHCP_CLIENT_ID_MAC, DHCP_CLIENT_ID_DUID, @@ -146,6 +150,10 @@ struct Network { bool unicast_flood; unsigned cost; + uint16_t pvid; + uint32_t br_vid_bitmap[BRIDGE_VLAN_BITMAP_LEN]; + uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN]; + AddressFamilyBoolean ip_forward; bool ip_masquerade; -- cgit v1.2.3-54-g00ecf From 9c1e04d0fa80c73ef0dd4647c103cdb7edb7f580 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 10 Jun 2016 13:09:06 +0200 Subject: nspawn: introduce --notify-ready=[no|yes] (#3474) This the patch implements a notificaiton mechanism from the init process in the container to systemd-nspawn. The switch --notify-ready=yes configures systemd-nspawn to wait the "READY=1" message from the init process in the container to send its own to systemd. --notify-ready=no is equivalent to the previous behavior before this patch, systemd-nspawn notifies systemd with a "READY=1" message when the container is created. This notificaiton mechanism uses socket file with path relative to the contanier "/run/systemd/nspawn/notify". The default values it --notify-ready=no. It is also possible to configure this mechanism from the .nspawn files using NotifyReady. This parameter takes the same options of the command line switch. Before this patch, systemd-nspawn notifies "ready" after the inner child was created, regardless the status of the service running inside it. Now, with --notify-ready=yes, systemd-nspawn notifies when the service is ready. This is really useful when there are dependencies between different contaniers. Fixes https://github.com/systemd/systemd/issues/1369 Based on the work from https://github.com/systemd/systemd/pull/3022 Testing: Boot a OS inside a container with systemd-nspawn. Note: modify the commands accordingly with your filesystem. 1. Create a filesystem where you can boot an OS. 2. sudo systemd-nspawn -D ${HOME}/distros/fedora-23/ sh 2.1. Create the unit file /etc/systemd/system/sleep.service inside the container (You can use the example below) 2.2. systemdctl enable sleep 2.3 exit 3. sudo systemd-run --service-type=notify --unit=notify-test ${HOME}/systemd/systemd-nspawn --notify-ready=yes -D ${HOME}/distros/fedora-23/ -b 4. In a different shell run "systemctl status notify-test" When using --notify-ready=yes the service status is "activating" for 20 seconds before being set to "active (running)". Instead, using --notify-ready=no the service status is marked "active (running)" quickly, without waiting for the 20 seconds. This patch was also test with --private-users=yes, you can test it just adding it at the end of the command at point 3. ------ sleep.service ------ [Unit] Description=sleep After=network.target [Service] Type=oneshot ExecStart=/bin/sleep 20 [Install] WantedBy=multi-user.target ------------ end ------------ --- man/systemd-nspawn.xml | 13 +++ man/systemd.nspawn.xml | 9 ++ src/nspawn/nspawn-gperf.gperf | 1 + src/nspawn/nspawn-settings.h | 4 +- src/nspawn/nspawn.c | 195 ++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 214 insertions(+), 8 deletions(-) (limited to 'man') diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 0c8c699201..08122795f4 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -980,6 +980,19 @@ effect. + + --notify-ready= + + Configures support for notifications from the container's init process. + --notify-ready= takes a boolean ( and ). + With option systemd-nspawn notifies systemd + with a READY=1 message when the init process is created. + With option systemd-nspawn waits for the + READY=1 message from the init process in the container + before sending its own to systemd. For more details about notifications + see sd_notify3). + + diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 3683412c14..6df4aeb2a9 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -259,6 +259,15 @@ command line switch, and takes the same options. This option is privileged (see above). + + + NotifyReady= + + Configures support for notifications from the container's init process. + This is equivalent to use command line switch, + and takes the same options. See systemd-nspawn1 + for details about the specific options supported. + diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 2b5d452662..3231a48d5a 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -27,6 +27,7 @@ Exec.Personality, config_parse_personality, 0, offsetof(Settings, Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id) Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory) Exec.PrivateUsers, config_parse_private_users, 0, 0 +Exec.NotifyReady, config_parse_bool, 0, offsetof(Settings, notify_ready) Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only) Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode) Files.Bind, config_parse_bind, 0, 0 diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 1c47e37912..231e6d7266 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -56,7 +56,8 @@ typedef enum SettingsMask { SETTING_CUSTOM_MOUNTS = 1 << 11, SETTING_WORKING_DIRECTORY = 1 << 12, SETTING_USERNS = 1 << 13, - _SETTINGS_MASK_ALL = (1 << 14) -1 + SETTING_NOTIFY_READY = 1 << 14, + _SETTINGS_MASK_ALL = (1 << 15) -1 } SettingsMask; typedef struct Settings { @@ -73,6 +74,7 @@ typedef struct Settings { char *working_directory; UserNamespaceMode userns_mode; uid_t uid_shift, uid_range; + bool notify_ready; /* [Image] */ int read_only; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index d1c65e8b0b..ea24de7608 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -104,6 +104,10 @@ * UID range here */ #define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000)) #define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000)) +/* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path + * nspawn_notify_socket_path is relative to the container + * the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */ +#define NSPAWN_NOTIFY_SOCKET_PATH "/run/systemd/nspawn/notify" typedef enum ContainerStatus { CONTAINER_TERMINATED, @@ -187,6 +191,7 @@ static SettingsMask arg_settings_mask = 0; static int arg_settings_trusted = -1; static char **arg_parameters = NULL; static const char *arg_container_service_name = "systemd-nspawn"; +static bool arg_notify_ready = false; static void help(void) { printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" @@ -267,6 +272,8 @@ static void help(void) { " the service unit nspawn is running in\n" " --volatile[=MODE] Run the system in volatile mode\n" " --settings=BOOLEAN Load additional settings from .nspawn file\n" + " --notify-ready=BOOLEAN Receive notifications from the container's init process,\n" + " accepted values: yes and no\n" , program_invocation_short_name); } @@ -367,6 +374,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SETTINGS, ARG_CHDIR, ARG_PRIVATE_USERS_CHOWN, + ARG_NOTIFY_READY, }; static const struct option options[] = { @@ -415,6 +423,7 @@ static int parse_argv(int argc, char *argv[]) { { "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL }, { "settings", required_argument, NULL, ARG_SETTINGS }, { "chdir", required_argument, NULL, ARG_CHDIR }, + { "notify-ready", required_argument, NULL, ARG_NOTIFY_READY }, {} }; @@ -987,6 +996,16 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_WORKING_DIRECTORY; break; + case ARG_NOTIFY_READY: + r = parse_boolean(optarg); + if (r < 0) { + log_error("%s is not a valid notify mode. Valid modes are: yes, no, and ready.", optarg); + return -EINVAL; + } + arg_notify_ready = r; + arg_settings_mask |= SETTING_NOTIFY_READY; + break; + case '?': return -EINVAL; @@ -2529,6 +2548,7 @@ static int inner_child( NULL, /* container_uuid */ NULL, /* LISTEN_FDS */ NULL, /* LISTEN_PID */ + NULL, /* NOTIFY_SOCKET */ NULL }; @@ -2656,6 +2676,8 @@ static int inner_child( (asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0)) return log_oom(); } + if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH) < 0) + return log_oom(); env_use = strv_env_merge(2, envp, arg_setenv); if (!env_use) @@ -2725,6 +2747,37 @@ static int inner_child( return log_error_errno(r, "execv() failed: %m"); } +static int setup_sd_notify_child(void) { + static const int one = 1; + int fd = -1; + union sockaddr_union sa = { + .sa.sa_family = AF_UNIX, + }; + int r; + + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (fd < 0) + return log_error_errno(errno, "Failed to allocate notification socket: %m"); + + (void) mkdir_parents(NSPAWN_NOTIFY_SOCKET_PATH, 0755); + (void) unlink(NSPAWN_NOTIFY_SOCKET_PATH); + + strncpy(sa.un.sun_path, NSPAWN_NOTIFY_SOCKET_PATH, sizeof(sa.un.sun_path)-1); + r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); + if (r < 0) { + safe_close(fd); + return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); + } + + r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); + if (r < 0) { + safe_close(fd); + return log_error_errno(errno, "SO_PASSCRED failed: %m"); + } + + return fd; +} + static int outer_child( Barrier *barrier, const char *directory, @@ -2736,6 +2789,7 @@ static int outer_child( bool secondary, int pid_socket, int uuid_socket, + int notify_socket, int kmsg_socket, int rtnl_socket, int uid_shift_socket, @@ -2744,12 +2798,14 @@ static int outer_child( pid_t pid; ssize_t l; int r; + _cleanup_close_ int fd = -1; assert(barrier); assert(directory); assert(console); assert(pid_socket >= 0); assert(uuid_socket >= 0); + assert(notify_socket >= 0); assert(kmsg_socket >= 0); cg_unified_flush(); @@ -2936,6 +2992,10 @@ static int outer_child( if (r < 0) return log_error_errno(r, "Failed to move root directory: %m"); + fd = setup_sd_notify_child(); + if (fd < 0) + return fd; + pid = raw_clone(SIGCHLD|CLONE_NEWNS| (arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) | (arg_private_network ? CLONE_NEWNET : 0) | @@ -2945,6 +3005,7 @@ static int outer_child( if (pid == 0) { pid_socket = safe_close(pid_socket); uuid_socket = safe_close(uuid_socket); + notify_socket = safe_close(notify_socket); uid_shift_socket = safe_close(uid_shift_socket); /* The inner child has all namespaces that are @@ -2974,8 +3035,13 @@ static int outer_child( return -EIO; } + l = send_one_fd(notify_socket, fd, 0); + if (l < 0) + return log_error_errno(errno, "Failed to send notify fd: %m"); + pid_socket = safe_close(pid_socket); uuid_socket = safe_close(uuid_socket); + notify_socket = safe_close(notify_socket); kmsg_socket = safe_close(kmsg_socket); rtnl_socket = safe_close(rtnl_socket); @@ -3058,6 +3124,96 @@ static int setup_uid_map(pid_t pid) { return 0; } +static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_fdset_free_ FDSet *fds = NULL; + char buf[NOTIFY_BUFFER_MAX+1]; + char *p = NULL; + struct iovec iovec = { + .iov_base = buf, + .iov_len = sizeof(buf)-1, + }; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; + } control = {}; + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + struct ucred *ucred = NULL; + ssize_t n; + pid_t inner_child_pid; + _cleanup_strv_free_ char **tags = NULL; + + assert(userdata); + + inner_child_pid = PTR_TO_PID(userdata); + + if (revents != EPOLLIN) { + log_warning("Got unexpected poll event for notify fd."); + return 0; + } + + n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + return log_warning_errno(errno, "Couldn't read notification socket: %m"); + } + cmsg_close_all(&msghdr); + + CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + + ucred = (struct ucred*) CMSG_DATA(cmsg); + } + } + + if (!ucred || ucred->pid != inner_child_pid) { + log_warning("Received notify message without valid credentials. Ignoring."); + return 0; + } + + if ((size_t) n >= sizeof(buf)) { + log_warning("Received notify message exceeded maximum size. Ignoring."); + return 0; + } + + buf[n] = 0; + tags = strv_split(buf, "\n\r"); + if (!tags) + return log_oom(); + + if (strv_find(tags, "READY=1")) + sd_notifyf(false, "READY=1\n"); + + p = strv_find_startswith(tags, "STATUS="); + if (p) + sd_notifyf(false, "STATUS=Container running: %s", p); + + return 0; +} + +static int setup_sd_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid) { + int r; + sd_event_source *notify_event_source; + + r = sd_event_add_io(event, ¬ify_event_source, fd, EPOLLIN, nspawn_dispatch_notify_fd, inner_child_pid); + if (r < 0) + return log_error_errno(r, "Failed to allocate notify event source: %m"); + + (void) sd_event_source_set_description(notify_event_source, "nspawn-notify"); + + return 0; +} + static int load_settings(void) { _cleanup_(settings_freep) Settings *settings = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -3286,6 +3442,9 @@ static int load_settings(void) { } } + if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0) + arg_notify_ready = settings->notify_ready; + return 0; } @@ -3536,7 +3695,9 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uuid_socket_pair[2] = { -1, -1 }, + notify_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }; + _cleanup_close_ int notify_socket= -1; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; @@ -3587,6 +3748,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, notify_socket_pair) < 0) { + r = log_error_errno(errno, "Failed to create notify socket pair: %m"); + goto finish; + } + if (arg_userns_mode != USER_NAMESPACE_NO) if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) { r = log_error_errno(errno, "Failed to create uid shift socket pair: %m"); @@ -3628,6 +3794,7 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); pid_socket_pair[0] = safe_close(pid_socket_pair[0]); uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]); + notify_socket_pair[0] = safe_close(notify_socket_pair[0]); uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); (void) reset_all_signal_handlers(); @@ -3643,6 +3810,7 @@ int main(int argc, char *argv[]) { secondary, pid_socket_pair[1], uuid_socket_pair[1], + notify_socket_pair[1], kmsg_socket_pair[1], rtnl_socket_pair[1], uid_shift_socket_pair[1], @@ -3661,6 +3829,7 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]); pid_socket_pair[1] = safe_close(pid_socket_pair[1]); uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]); + notify_socket_pair[1] = safe_close(notify_socket_pair[1]); uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); if (arg_userns_mode != USER_NAMESPACE_NO) { @@ -3734,6 +3903,13 @@ int main(int argc, char *argv[]) { goto finish; } + /* We also retrieve the socket used for notifications generated by outer child */ + notify_socket = receive_one_fd(notify_socket_pair[0], 0); + if (notify_socket < 0) { + r = log_error_errno(errno, "Failed to receive notification socket from the outer child: %m"); + goto finish; + } + log_debug("Init process invoked as PID " PID_FMT, pid); if (arg_userns_mode != USER_NAMESPACE_NO) { @@ -3848,6 +4024,16 @@ int main(int argc, char *argv[]) { goto finish; } + r = sd_event_new(&event); + if (r < 0) { + log_error_errno(r, "Failed to get default event source: %m"); + goto finish; + } + + r = setup_sd_notify_parent(event, notify_socket, PID_TO_PTR(pid)); + if (r < 0) + goto finish; + /* Let the child know that we are ready and wait that the child is completely ready now. */ if (!barrier_place_and_sync(&barrier)) { /* #4 */ log_error("Child died too early."); @@ -3860,15 +4046,10 @@ int main(int argc, char *argv[]) { etc_passwd_lock = safe_close(etc_passwd_lock); sd_notifyf(false, - "READY=1\n" "STATUS=Container running.\n" "X_NSPAWN_LEADER_PID=" PID_FMT, pid); - - r = sd_event_new(&event); - if (r < 0) { - log_error_errno(r, "Failed to get default event source: %m"); - goto finish; - } + if (!arg_notify_ready) + sd_notify(false, "READY=1\n"); if (arg_kill_signal > 0) { /* Try to kill the init system on SIGINT or SIGTERM */ -- cgit v1.2.3-54-g00ecf From cf677fe6868f0565dd625cfbc2992a0f2cd3e053 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Fri, 10 Jun 2016 18:19:54 +0200 Subject: core/execute: add the magic character '!' to allow privileged execution (#3493) This patch implements the new magic character '!'. By putting '!' in front of a command, systemd executes it with full privileges ignoring paramters such as User, Group, SupplementaryGroups, CapabilityBoundingSet, AmbientCapabilities, SecureBits, SystemCallFilter, SELinuxContext, AppArmorProfile, SmackProcessLabel, and RestrictAddressFamilies. Fixes partially https://github.com/systemd/systemd/issues/3414 Related to https://github.com/coreos/rkt/issues/2482 Testing: 1. Create a user 'bob' 2. Create the unit file /etc/systemd/system/exec-perm.service (You can use the example below) 3. sudo systemctl start ext-perm.service 4. Verify that the commands starting with '!' were not executed as bob, 4.1 Looking to the output of ls -l /tmp/exec-perm 4.2 Each file contains the result of the id command. ````````````````````````````````````````````````````````````````` [Unit] Description=ext-perm [Service] Type=oneshot TimeoutStartSec=0 User=bob ExecStartPre=!/usr/bin/sh -c "/usr/bin/rm /tmp/exec-perm*" ; /usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start-pre" ExecStart=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start" ; !/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-star-2" ExecStartPost=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-start-post" ExecReload=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-reload" ExecStop=!/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-stop" ExecStopPost=/usr/bin/sh -c "/usr/bin/id > /tmp/exec-perm-stop-post" [Install] WantedBy=multi-user.target] ````````````````````````````````````````````````````````````````` --- man/systemd.exec.xml | 27 +++++++++++++++------------ man/systemd.service.xml | 7 ++++--- src/core/execute.c | 6 +++--- src/core/execute.h | 3 ++- src/core/load-fragment.c | 15 ++++++++++----- 5 files changed, 34 insertions(+), 24 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 4a3dd14c39..1c3256a662 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -146,7 +146,7 @@ Sets the Unix user or group that the processes are executed as, respectively. Takes a single user or group name or ID as argument. If no group is set, the default group - of the user is chosen. + of the user is chosen. These do not affect commands prefixed with !. @@ -161,7 +161,7 @@ this one will have no effect. In any way, this option does not override, but extends the list of supplementary groups configured in the system group database for the - user. + user. This does not affect commands prefixed with !. @@ -795,7 +795,8 @@ process are enforced. This option may appear more than once, in which case the bounding sets are merged. If the empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior settings have no effect. If set to ~ (without any further argument), the bounding set is - reset to the full set of available capabilities, also undoing any previous settings. + reset to the full set of available capabilities, also undoing any previous settings. This does not affect + commands prefixed with !. @@ -824,7 +825,8 @@ as a non-privileged user but still want to give it some capabilities. Note that in this case option keep-caps is automatically added to SecureBits= to retain the - capabilities over the user change. + capabilities over the user change. AmbientCapabilities= does not affect + commands prefixed with !. @@ -840,8 +842,8 @@ . This option may appear more than once, in which case the secure bits are ORed. If the empty string is assigned to this option, - the bits are reset to 0. See - capabilities7 + the bits are reset to 0. This does not affect commands prefixed with !. + See capabilities7 for details. @@ -1097,8 +1099,8 @@ domain transition. However, the policy still needs to authorize the transition. This directive is ignored if SELinux is disabled. If prefixed by -, all errors - will be ignored. See - setexeccon3 + will be ignored. This does not affect commands prefixed with !. + See setexeccon3 for details. @@ -1110,7 +1112,7 @@ Profiles must already be loaded in the kernel, or the unit will fail. This result in a non operation if AppArmor is not enabled. If prefixed by -, all errors will - be ignored. + be ignored. This does not affect commands prefixed with !. @@ -1129,7 +1131,8 @@ The value may be prefixed by -, in which case all errors will be ignored. An empty value may be - specified to unset previous assignments. + specified to unset previous assignments. This does not affect + commands prefixed with !. @@ -1180,7 +1183,7 @@ listed explicitly. This option may be specified more than once, in which case the filter masks are merged. If the empty string is assigned, the filter is reset, all prior assignments will - have no effect. + have no effect. This does not affect commands prefixed with !. If you specify both types of this option (i.e. whitelisting and blacklisting), the first encountered will @@ -1343,7 +1346,7 @@ family should be included in the configured whitelist as it is frequently used for local communication, including for syslog2 - logging. + logging. This does not affect commands prefixed with !. diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 6641dfed4f..6e969abc25 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -295,9 +295,10 @@ If the absolute filename is prefixed with -, an exit code of the command normally considered a failure (i.e. non-zero exit status or abnormal - exit due to signal) is ignored and considered success. If both - - and @ are used, they - can appear in either order. + exit due to signal) is ignored and considered success. + If the absolute path is prefixed with ! then + it is executed with full privileges. -, @, and ! + may be used together and they can appear in any order. If more than one command is specified, the commands are invoked sequentially in the order they appear in the unit diff --git a/src/core/execute.c b/src/core/execute.c index e718c43df9..802f14d575 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1717,7 +1717,7 @@ static int exec_child( umask(context->umask); - if (params->apply_permissions) { + if (params->apply_permissions && !command->privileged) { r = enforce_groups(context, username, gid); if (r < 0) { *exit_status = EXIT_GROUP; @@ -1842,7 +1842,7 @@ static int exec_child( } #ifdef HAVE_SELINUX - if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) { + if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) { r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net); if (r < 0) { *exit_status = EXIT_SELINUX_CONTEXT; @@ -1867,7 +1867,7 @@ static int exec_child( return r; } - if (params->apply_permissions) { + if (params->apply_permissions && !command->privileged) { bool use_address_families = context->address_families_whitelist || !set_isempty(context->address_families); diff --git a/src/core/execute.h b/src/core/execute.h index 464869d226..cd1f7b36f6 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -81,7 +81,8 @@ struct ExecCommand { char **argv; ExecStatus exec_status; LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */ - bool ignore; + bool ignore:1; + bool privileged:1; }; struct ExecRuntime { diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 2d8f6296c8..17c72aed88 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -596,7 +596,7 @@ int config_parse_exec( p = rvalue; do { _cleanup_free_ char *path = NULL, *firstword = NULL; - bool separate_argv0 = false, ignore = false; + bool separate_argv0 = false, ignore = false, privileged = false; _cleanup_free_ ExecCommand *nce = NULL; _cleanup_strv_free_ char **n = NULL; size_t nlen = 0, nbufsize = 0; @@ -610,14 +610,18 @@ int config_parse_exec( return 0; f = firstword; - for (i = 0; i < 2; i++) { - /* We accept an absolute path as first argument, or - * alternatively an absolute prefixed with @ to allow - * overriding of argv[0]. */ + for (i = 0; i < 3; i++) { + /* We accept an absolute path as first argument. + * If it's prefixed with - and the path doesn't exist, + * we ignore it instead of erroring out; + * if it's prefixed with @, we allow overriding of argv[0]; + * and if it's prefixed with !, it will be run with full privileges */ if (*f == '-' && !ignore) ignore = true; else if (*f == '@' && !separate_argv0) separate_argv0 = true; + else if (*f == '!' && !privileged) + privileged = true; else break; f++; @@ -715,6 +719,7 @@ int config_parse_exec( nce->argv = n; nce->path = path; nce->ignore = ignore; + nce->privileged = privileged; exec_command_append_list(e, nce); -- cgit v1.2.3-54-g00ecf From 2c7284a9a966a7790cb260e89428db5bb2020eef Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 20:29:32 +0200 Subject: man: document what SIGUSR1 and SIGUSR2 do to resolved --- man/systemd-resolved.service.xml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'man') diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 829729ca09..485f3e9aee 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -145,6 +145,28 @@ + + Signals + + + + SIGUSR1 + + Upon reception of the SIGUSR1 process signal systemd-resolved will dump the + contents of all DNS resource record caches it maintains into the system logs. + + + + SIGUSR2 + + Upon reception of the SIGUSR2 process signal systemd-resolved will flush all + caches it maintains. Note that it should normally not be necessary to request this explicitly – except for + debugging purposes – as systemd-resolved flushes the caches automatically anyway any time + the host's network configuration changes. + + + + See Also -- cgit v1.2.3-54-g00ecf From ba35662fbdde7b90aed6b34c641b4ff0ea740c68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 20:40:30 +0200 Subject: resolved: also add a way to flush all caches via the bus And expose it in "resolve-tool --flush-caches". --- man/systemd-resolve.xml | 6 ++++++ src/resolve/resolve-tool.c | 36 ++++++++++++++++++++++++++++++++++++ src/resolve/resolved-bus.c | 12 ++++++++++++ src/resolve/resolved-manager.c | 15 +++++++++++---- src/resolve/resolved-manager.h | 2 ++ 5 files changed, 67 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index 4b66f836a2..b917ac20a2 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -288,6 +288,12 @@ Resets the statistics counters shown in to zero. + + + + Flushes all DNS resource record caches the service maintains locally. + + diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 7e145c64c4..bc6dcf04a4 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -66,6 +66,7 @@ static enum { MODE_RESOLVE_TLSA, MODE_STATISTICS, MODE_RESET_STATISTICS, + MODE_FLUSH_CACHES, } arg_mode = MODE_RESOLVE_HOST; static ServiceFamily service_family_from_string(const char *s) { @@ -1037,6 +1038,24 @@ static int reset_statistics(sd_bus *bus) { return 0; } +static int flush_caches(sd_bus *bus) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + r = sd_bus_call_method(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "FlushCaches", + &error, + NULL, + NULL); + if (r < 0) + return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r)); + + return 0; +} + static void help_protocol_types(void) { if (arg_legend) puts("Known protocol types:"); @@ -1097,6 +1116,7 @@ static void help(void) { " --legend=BOOL Print headers and additional info (default: yes)\n" " --statistics Show resolver statistics\n" " --reset-statistics Reset resolver statistics\n" + " --flush-caches Flush all local DNS caches\n" , program_invocation_short_name); } @@ -1114,6 +1134,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, + ARG_FLUSH_CACHES, }; static const struct option options[] = { @@ -1134,6 +1155,7 @@ static int parse_argv(int argc, char *argv[]) { { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, + { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES }, {} }; @@ -1307,6 +1329,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_RESET_STATISTICS; break; + case ARG_FLUSH_CACHES: + arg_mode = MODE_FLUSH_CACHES; + break; + case '?': return -EINVAL; @@ -1473,6 +1499,16 @@ int main(int argc, char **argv) { r = reset_statistics(bus); break; + + case MODE_FLUSH_CACHES: + if (argc > optind) { + log_error("Too many arguments."); + r = -EINVAL; + goto finish; + } + + r = flush_caches(bus); + break; } finish: diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 6d4e5746f7..a72a03cfad 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1535,6 +1535,17 @@ static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_e return sd_bus_reply_method_return(message, "o", p); } +static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + assert(message); + assert(m); + + manager_flush_caches(m); + + return sd_bus_reply_method_return(message, NULL); +} + static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0), @@ -1550,6 +1561,7 @@ static const sd_bus_vtable resolve_vtable[] = { SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0), + SD_BUS_METHOD("FlushCaches", NULL, NULL, bus_method_flush_caches, 0), SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0), SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0), diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 6cf75f9183..a46f13b92f 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -468,16 +468,14 @@ static int manager_sigusr1(sd_event_source *s, const struct signalfd_siginfo *si static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { Manager *m = userdata; - DnsScope *scope; assert(s); assert(si); assert(m); - LIST_FOREACH(scopes, scope, m->dns_scopes) - dns_cache_flush(&scope->cache); - + manager_flush_caches(m); log_info("Flushed all caches."); + return 0; } @@ -1251,3 +1249,12 @@ bool manager_routable(Manager *m, int family) { return false; } + +void manager_flush_caches(Manager *m) { + DnsScope *scope; + + assert(m); + + LIST_FOREACH(scopes, scope, m->dns_scopes) + dns_cache_flush(&scope->cache); +} diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 97f75ace79..ef71202ef9 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -170,3 +170,5 @@ bool manager_dnssec_supported(Manager *m); void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key); bool manager_routable(Manager *m, int family); + +void manager_flush_caches(Manager *m); -- cgit v1.2.3-54-g00ecf From 1f9ac68b5bc671f1f8b0a32084810d39394208a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 10 Jun 2016 17:43:38 +0200 Subject: core: improve seccomp syscall grouping a bit This adds three new seccomp syscall groups: @keyring for kernel keyring access, @cpu-emulation for CPU emulation features, for exampe vm86() for dosemu and suchlike, and @debug for ptrace() and related calls. Also, the @clock group is updated with more syscalls that alter the system clock. capset() is added to @privileged, and pciconfig_iobase() is added to @raw-io. Finally, @obsolete is a cleaned up. A number of syscalls that never existed on Linux and have no number assigned on any architecture are removed, as they only exist in the man pages and other operating sytems, but not in code at all. create_module() is moved from @module to @obsolete, as it is an obsolete system call. mem_getpolicy() is removed from the @obsolete list, as it is not obsolete, but simply a NUMA API. --- man/systemd.exec.xml | 38 ++++++++++++++++++-------------- src/shared/seccomp-util.c | 55 +++++++++++++++++++++++++++++++---------------- 2 files changed, 58 insertions(+), 35 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 1c3256a662..a39e800854 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1218,49 +1218,55 @@ @clock - System calls for changing the system clock (adjtimex(), - settimeofday()) + System calls for changing the system clock (adjtimex2, settimeofday2, and related calls) + + + @cpu-emulation + System calls for CPU emulation functionality (vm862 and related calls) + + + @debug + Debugging, performance monitoring and tracing functionality (ptrace2, perf_event_open2 and related calls) @io-event - Event loop use (poll(), select(), - epoll7, - eventfd()...) + Event loop system calls (poll2, select2, epoll7, eventfd2 and related calls) @ipc - SysV IPC, POSIX Message Queues or other IPC (mq_overview7, - svipc7) + SysV IPC, POSIX Message Queues or other IPC (mq_overview7, svipc7) + + + @keyring + Kernel keyring access (keyctl2 and related calls) @module - Kernel module control (create_module(), init_module()...) + Kernel module control (init_module2, delete_module2 and related calls) @mount - File system mounting and unmounting (chroot(), mount()...) + File system mounting and unmounting (mount2, chroot2, and related calls) @network-io - Socket I/O (including local AF_UNIX): - socket7, - unix7 + Socket I/O (including local AF_UNIX): socket7, unix7 @obsolete - Unusual, obsolete or unimplemented (fattach(), gtty(), vm86()...) + Unusual, obsolete or unimplemented (create_module2, gtty2, …) @privileged - All system calls which need superuser capabilities (capabilities7) + All system calls which need super-user capabilities (capabilities7) @process - Process control, execution, namespaces (execve(), kill(), namespaces7...) + Process control, execution, namespaces (execve2, kill2, namespaces7, … @raw-io - Raw I/O ports (ioperm(), iopl(), pciconfig_read()...) + Raw I/O port access (ioperm2, iopl2, pciconfig_read(), … diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 30d22d2242..8656d112b8 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -95,7 +95,31 @@ const SystemCallFilterSet syscall_filter_sets[] = { .set_name = "@clock", .value = "adjtimex\0" + "clock_adjtime\0" + "clock_settime\0" "settimeofday\0" + "stime\0" + }, { + /* CPU emulation calls */ + .set_name = "@cpu-emulation", + .value = + "modify_ldt\0" + "subpage_prot\0" + "switch_endian\0" + "vm86\0" + "vm86old\0" + }, { + /* Debugging/Performance Monitoring/Tracing */ + .set_name = "@debug", + .value = + "lookup_dcookie\0" + "perf_event_open\0" + "process_vm_readv\0" + "process_vm_writev\0" + "ptrace\0" + "rtas\0" + "s390_runtime_instr\0" + "sys_debug_setcontext\0" }, { /* Default list */ .set_name = "@default", @@ -147,11 +171,17 @@ const SystemCallFilterSet syscall_filter_sets[] = { "shmctl\0" "shmdt\0" "shmget\0" + }, { + /* Keyring */ + .set_name = "@keyring", + .value = + "add_key\0" + "keyctl\0" + "request_key\0" }, { /* Kernel module control */ .set_name = "@module", .value = - "create_module\0" "delete_module\0" "finit_module\0" "init_module\0" @@ -197,40 +227,26 @@ const SystemCallFilterSet syscall_filter_sets[] = { "_sysctl\0" "afs_syscall\0" "break\0" - "fattach\0" - "fdetach\0" + "create_module\0" "ftime\0" "get_kernel_syms\0" - "get_mempolicy\0" - "getmsg\0" "getpmsg\0" "gtty\0" - "isastream\0" "lock\0" - "madvise1\0" - "modify_ldt\0" "mpx\0" - "pciconfig_iobase\0" - "perf_event_open\0" "prof\0" "profil\0" - "putmsg\0" "putpmsg\0" "query_module\0" - "rtas\0" - "s390_runtime_instr\0" "security\0" "sgetmask\0" "ssetmask\0" "stty\0" - "subpage_prot\0" - "switch_endian\0" - "sys_debug_setcontext\0" + "sysfs\0" "tuxcall\0" "ulimit\0" "uselib\0" - "vm86\0" - "vm86old\0" + "ustat\0" "vserver\0" }, { /* Nice grab-bag of all system calls which need superuser capabilities */ @@ -242,6 +258,7 @@ const SystemCallFilterSet syscall_filter_sets[] = { "acct\0" "bdflush\0" "bpf\0" + "capset\0" "chown32\0" "chown\0" "chroot\0" @@ -268,7 +285,6 @@ const SystemCallFilterSet syscall_filter_sets[] = { "setreuid\0" "setuid32\0" "setuid\0" - "stime\0" "swapoff\0" "swapon\0" "sysctl\0" @@ -295,6 +311,7 @@ const SystemCallFilterSet syscall_filter_sets[] = { .value = "ioperm\0" "iopl\0" + "pciconfig_iobase\0" "pciconfig_read\0" "pciconfig_write\0" "s390_pci_mmio_read\0" -- cgit v1.2.3-54-g00ecf From dcd61450026c281c916f12c2affa220e0994ba19 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Mon, 13 Jun 2016 18:28:42 +0400 Subject: core: parse `rd.rescue` and `rd.emergency` as initrd-specific shorthands (#3488) Typing `rd.rescue` is easier than `rd.systemd.unit=rescue.target`. --- man/kernel-command-line.xml | 4 +++- man/systemd.xml | 14 ++++++++------ src/basic/proc-cmdline.c | 18 +++++++++++++++--- src/basic/util.c | 18 +++++++++++------- src/basic/util.h | 1 + src/core/main.c | 2 +- src/test/test-proc-cmdline.c | 11 +++++++++++ 7 files changed, 50 insertions(+), 18 deletions(-) (limited to 'man') diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 9c04849f66..3ecc969c10 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -146,7 +146,9 @@ -b + rd.emergency emergency + rd.rescue rescue single s @@ -158,7 +160,7 @@ 5 Parameters understood by the system and service - manager, as compatibility options. For details, see + manager, as compatibility and convenience options. For details, see systemd1. diff --git a/man/systemd.xml b/man/systemd.xml index b8d91b8943..65f55199e2 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -1024,25 +1024,27 @@ emergency + rd.emergency -b Boot into emergency mode. This is equivalent - to systemd.unit=emergency.target and - provided for compatibility reasons and to be easier to - type. + to systemd.unit=emergency.target or + rd.systemd.unit=emergency.target, respectively, and + provided for compatibility reasons and to be easier to type. rescue + rd.rescue single s S 1 Boot into rescue mode. This is equivalent to - systemd.unit=rescue.target and provided for - compatibility reasons and to be easier to - type. + systemd.unit=rescue.target or + rd.systemd.unit=rescue.target, respectively, and + provided for compatibility reasons and to be easier to type. diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 3505fa9c9a..0430beadaa 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -160,17 +160,29 @@ static const char * const rlmap[] = { "3", SPECIAL_MULTI_USER_TARGET, "4", SPECIAL_MULTI_USER_TARGET, "5", SPECIAL_GRAPHICAL_TARGET, + NULL +}; + +static const char * const rlmap_initrd[] = { + "emergency", SPECIAL_EMERGENCY_TARGET, + "rescue", SPECIAL_RESCUE_TARGET, + NULL }; const char* runlevel_to_target(const char *word) { size_t i; + const char * const *rlmap_ptr = in_initrd() ? rlmap_initrd + : rlmap; if (!word) return NULL; - for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(word, rlmap[i])) - return rlmap[i+1]; + if (in_initrd() && (word = startswith(word, "rd.")) == NULL) + return NULL; + + for (i = 0; rlmap_ptr[i] != NULL; i += 2) + if (streq(word, rlmap_ptr[i])) + return rlmap_ptr[i+1]; return NULL; } diff --git a/src/basic/util.c b/src/basic/util.c index 756c663be4..f2f92fb3b7 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -64,6 +64,7 @@ assert_cc(EAGAIN == EWOULDBLOCK); int saved_argc = 0; char **saved_argv = NULL; +static int saved_in_initrd = -1; size_t page_size(void) { static thread_local size_t pgsz = 0; @@ -454,11 +455,10 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa } bool in_initrd(void) { - static int saved = -1; struct statfs s; - if (saved >= 0) - return saved; + if (saved_in_initrd >= 0) + return saved_in_initrd; /* We make two checks here: * @@ -470,11 +470,15 @@ bool in_initrd(void) { * emptying when transititioning to the main systemd. */ - saved = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); + saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && + statfs("/", &s) >= 0 && + is_temporary_fs(&s); - return saved; + return saved_in_initrd; +} + +void in_initrd_force(bool value) { + saved_in_initrd = value; } /* hey glibc, APIs with callbacks without a user pointer are so useless */ diff --git a/src/basic/util.h b/src/basic/util.h index 1c032c15c9..9e6df19ef1 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -86,6 +86,7 @@ int prot_from_flags(int flags) _const_; int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); bool in_initrd(void); +void in_initrd_force(bool value); void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), diff --git a/src/core/main.c b/src/core/main.c index 93098daa9b..2785a3aa0b 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -409,7 +409,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { if (detect_container() > 0) log_set_target(LOG_TARGET_CONSOLE); - } else if (!in_initrd() && !value) { + } else if (!value) { const char *target; /* SysV compatibility */ diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index a7a8f621a2..80ad5ed98b 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -23,6 +23,7 @@ #include "proc-cmdline.h" #include "special.h" #include "string-util.h" +#include "util.h" static int parse_item(const char *key, const char *value) { assert_se(key); @@ -36,9 +37,19 @@ static void test_parse_proc_cmdline(void) { } static void test_runlevel_to_target(void) { + in_initrd_force(false); assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), NULL)); + + in_initrd_force(true); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), NULL)); + assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET)); } int main(void) { -- cgit v1.2.3-54-g00ecf From 1d7100298c2a696d99f6fbd6ab858762aeb51ac7 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Tue, 14 Jun 2016 22:41:57 +0530 Subject: networkd: Tunnel add support to configure key for VTI/VTI6 (#3532) fixes #3298 --- man/systemd.netdev.xml | 27 ++++++++++++ src/network/networkd-netdev-gperf.gperf | 3 ++ src/network/networkd-netdev-tunnel.c | 75 +++++++++++++++++++++++++++++++++ src/network/networkd-netdev-tunnel.h | 9 ++++ 4 files changed, 114 insertions(+) (limited to 'man') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index cde5d65949..3cc58ca854 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -638,6 +638,33 @@ + + Key= + + The Key= parameter specifies the same key to use in + both directions (InputKey= and OutputKey=). + The Key= is either a number or an IPv4 address-like dotted quad. + It is used as mark-configured SAD/SPD entry as part of the lookup key (both in data + and control path) in ip xfrm (framework used to implement IPsec protocol). + See + ip-xfrm - transform configuration for details. It is only used for VTI/VTI6 + tunnels. + + + + InputKey= + + The InputKey= parameter specifies the key to use for input. + The format is same as Key=. It is only used for VTI/VTI6 tunnels. + + + + OutputKey= + + The OutputKey= parameter specifies the key to use for output. + The format is same as Key=. It is only used for VTI/VTI6 tunnels. + + Mode= diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index a9512cd77b..bf93b0d9fa 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -42,6 +42,9 @@ Tunnel.Local, config_parse_tunnel_address, 0, Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote) Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos) Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl) +Tunnel.Key, config_parse_tunnel_key, 0, offsetof(Tunnel, key) +Tunnel.InputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, ikey) +Tunnel.OutputKey, config_parse_tunnel_key, 0, offsetof(Tunnel, okey) Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc) Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode) Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel) diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 7aaa041ba3..58dec36c9a 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -200,6 +200,33 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl return r; } +static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_message *m) { + Tunnel *t = VTI(netdev); + uint32_t ikey, okey; + int r; + + assert(link); + assert(m); + assert(t); + + if (t->key != 0) + ikey = okey = htobe32(t->key); + else { + ikey = htobe32(t->ikey); + okey = htobe32(t->okey); + } + + r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_IKEY attribute: %m"); + + r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m"); + + return 0; +} + static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { Tunnel *t = VTI(netdev); int r; @@ -214,6 +241,10 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); + r = netdev_vti_fill_message_key(netdev, link, m); + if (r < 0) + return r; + r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); @@ -239,6 +270,10 @@ static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlin if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m"); + r = netdev_vti_fill_message_key(netdev, link, m); + if (r < 0) + return r; + r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m"); @@ -413,6 +448,46 @@ int config_parse_tunnel_address(const char *unit, return 0; } +int config_parse_tunnel_key(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) { + union in_addr_union buffer; + Tunnel *t = userdata; + uint32_t k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = in_addr_from_string(AF_INET, rvalue, &buffer); + if (r < 0) { + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue); + return 0; + } + } else + k = be32toh(buffer.in.s_addr); + + if (streq(lvalue, "Key")) + t->key = k; + else if (streq(lvalue, "InputKey")) + t->ikey = k; + else + t->okey = k; + + return 0; +} + int config_parse_ipv6_flowlabel(const char* unit, const char *filename, unsigned line, diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index 7d31e7b687..32a46bd82f 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -49,6 +49,10 @@ typedef struct Tunnel { unsigned tos; unsigned flags; + uint32_t key; + uint32_t ikey; + uint32_t okey; + union in_addr_union local; union in_addr_union remote; @@ -108,3 +112,8 @@ int config_parse_encap_limit(const char *unit, const char *filename, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_tunnel_key(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); -- cgit v1.2.3-54-g00ecf From 875ae5661a011b757f0eaa468dea6ba91cbe5437 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 19:36:09 +0200 Subject: core: optionally, accept a percentage value for MemoryLimit= and related settings If a percentage is used, it is taken relative to the installed RAM size. This should make it easier to write generic unit files that adapt to the local system. --- man/systemd.resource-control.xml | 36 +++++++++++++++++++----------------- src/core/load-fragment.c | 16 +++++++++++++--- 2 files changed, 32 insertions(+), 20 deletions(-) (limited to 'man') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index d4c8fa7091..0551d75026 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -228,9 +228,11 @@ reclaimed as long as memory can be reclaimed from unprotected units. Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is - parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. This controls the - memory.low control group attribute. For details about this control group attribute, see - cgroup-v2.txt. + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a + percentage value may be specified, which is taken relative to the installed physical memory on the + system. This controls the memory.low control group attribute. For details about this + control group attribute, see cgroup-v2.txt. Implies MemoryAccounting=true. @@ -247,7 +249,9 @@ aggressively in such cases. This is the main mechanism to control memory usage of a unit. Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is - parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a + percentage value may be specified, which is taken relative to the installed physical memory on the + system. If assigned the special value infinity, no memory limit is applied. This controls the memory.high control group attribute. For details about this control group attribute, see cgroup-v2.txt. @@ -268,8 +272,9 @@ last line of defense. Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is - parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the - special value infinity, no memory limit is applied. This controls the + parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a + percentage value may be specified, which is taken relative to the installed physical memory on the system. If + assigned the special value infinity, no memory limit is applied. This controls the memory.max control group attribute. For details about this control group attribute, see cgroup-v2.txt. @@ -284,17 +289,14 @@ MemoryLimit=bytes - Specify the limit on maximum memory usage of the - executed processes. The limit specifies how much process and - kernel memory can be used by tasks in this unit. Takes a - memory size in bytes. If the value is suffixed with K, M, G - or T, the specified memory size is parsed as Kilobytes, - Megabytes, Gigabytes, or Terabytes (with the base 1024), - respectively. If assigned the special value - infinity, no memory limit is applied. This - controls the memory.limit_in_bytes - control group attribute. For details about this control - group attribute, see Specify the limit on maximum memory usage of the executed processes. The limit specifies how much + process and kernel memory can be used by tasks in this unit. Takes a memory size in bytes. If the value is + suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or + Terabytes (with the base 1024), respectively. Alternatively, a percentage value may be specified, which is + taken relative to the installed physical memory on the system. If assigned the special value + infinity, no memory limit is applied. This controls the + memory.limit_in_bytes control group attribute. For details about this control group + attribute, see memory.txt. Implies MemoryAccounting=true. diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index fe60bee789..05852cc7e3 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2812,9 +2812,19 @@ int config_parse_memory_limit( int r; if (!isempty(rvalue) && !streq(rvalue, "infinity")) { - r = parse_size(rvalue, 1024, &bytes); - if (r < 0 || bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + + r = parse_percent(rvalue); + if (r < 0) { + r = parse_size(rvalue, 1024, &bytes); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); + return 0; + } + } else + bytes = (((physical_memory() / page_size()) * (uint64_t) r) / 100) * page_size(); + + if (bytes < 1) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' too small. Ignoring.", rvalue); return 0; } } -- cgit v1.2.3-54-g00ecf From 328583dbc3621271dbdac4a279865ea7243f8ddf Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jun 2016 19:37:42 +0200 Subject: man: minor fixes --- man/systemd.resource-control.xml | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'man') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 0551d75026..7263c0b329 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -92,16 +92,14 @@ Automatic Dependencies - Units with the Slice= setting set get - automatic Requires= and - After= dependencies on the specified slice - unit. + Units with the Slice= setting set automatically acquire Requires= and + After= dependencies on the specified slice unit. Unified and Legacy Control Group Hierarchies - Unified control group hierarchy is the new version of kernel control group interface. Depending on the + The unified control group hierarchy is the new version of kernel control group interface. Depending on the resource type, there are differences in resource control capabilities. Also, because of interface changes, some resource types have a separate set of options on the unified hierarchy. @@ -117,8 +115,8 @@ - MemoryMax replaces MemoryLimit. MemoryLow - and MemoryHigh are effective only on unified hierarchy. + MemoryMax= replaces MemoryLimit=. MemoryLow= + and MemoryHigh= are effective only on unified hierarchy. -- cgit v1.2.3-54-g00ecf From bd8420c5186de99ac6684d47a30743a29a1b4dd6 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 14 Jun 2016 17:11:46 -0400 Subject: man: fix option letter in udevadm control -e -x never worked, so let's just correct the man page. Fixes #3524. --- man/udevadm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'man') diff --git a/man/udevadm.xml b/man/udevadm.xml index 8c1abd2770..1c7921f5bd 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -380,7 +380,7 @@ Modify the internal state of the running udev daemon. - + Signal and wait for systemd-udevd to exit. -- cgit v1.2.3-54-g00ecf From 7bce046bcf076e9cb359f1c78951b879430edb9e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Jun 2016 16:50:45 +0200 Subject: core: set $JOURNAL_STREAM to the dev_t/ino_t of the journal stream of executed services This permits services to detect whether their stdout/stderr is connected to the journal, and if so talk to the journal directly, thus permitting carrying of metadata. As requested by the gtk folks: #2473 --- configure.ac | 1 + man/systemd.exec.xml | 20 +++++++++++++++++++ src/basic/formats-util.h | 16 ++++++++++++++++ src/core/execute.c | 50 +++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 80 insertions(+), 7 deletions(-) (limited to 'man') diff --git a/configure.ac b/configure.ac index ffc6eedcdd..7fd78bfb60 100644 --- a/configure.ac +++ b/configure.ac @@ -249,6 +249,7 @@ AC_CHECK_SIZEOF(uid_t) AC_CHECK_SIZEOF(gid_t) AC_CHECK_SIZEOF(time_t) AC_CHECK_SIZEOF(dev_t) +AC_CHECK_SIZEOF(ino_t) AC_CHECK_SIZEOF(rlim_t,,[ #include #include diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index a39e800854..dbfc7692f7 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1539,6 +1539,26 @@ termcap5. + + + $JOURNAL_STREAM + + If the standard output or standard error output of the executed processes are connected to the + journal (for example, by setting StandardError=journal) $JOURNAL_STREAM + contains the device and inode numbers of the connection file descriptor, formatted in decimal, separated by a + colon (:). This permits invoked processes to safely detect whether their standard output or + standard error output are connected to the journal. The device and inode numbers of the file descriptors should + be compared with the values set in the environment variable to determine whether the process output is still + connected to the journal. Note that it is generally not sufficient to only check whether + $JOURNAL_STREAM is set at all as services might invoke external processes replacing their + standard output or standard error output, without unsetting the environment variable. + + This environment variable is primarily useful to allow services to optionally upgrade their used log + protocol to the native journal protocol (using + sd_journal_print3 and other + functions) if their standard output or standard error output is connected to the journal anyway, thus enabling + delivery of structured metadata along with logged messages. + Additional variables may be configured by the following diff --git a/src/basic/formats-util.h b/src/basic/formats-util.h index 9b4e8e98fa..39a185f59b 100644 --- a/src/basic/formats-util.h +++ b/src/basic/formats-util.h @@ -61,3 +61,19 @@ #else # error Unknown rlim_t size #endif + +#if SIZEOF_DEV_T == 8 +# define DEV_FMT "%" PRIu64 +#elif SIZEOF_DEV_T == 4 +# define DEV_FMT "%" PRIu32 +#else +# error Unknown dev_t size +#endif + +#if SIZEOF_INO_T == 8 +# define INO_FMT "%" PRIu64 +#elif SIZEOF_INO_T == 4 +# define INO_FMT "%" PRIu32 +#else +# error Unknown ino_t size +#endif diff --git a/src/core/execute.c b/src/core/execute.c index b5a5997f15..3c3369373f 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -454,7 +454,10 @@ static int setup_output( int fileno, int socket_fd, const char *ident, - uid_t uid, gid_t gid) { + uid_t uid, + gid_t gid, + dev_t *journal_stream_dev, + ino_t *journal_stream_ino) { ExecOutput o; ExecInput i; @@ -464,6 +467,8 @@ static int setup_output( assert(context); assert(params); assert(ident); + assert(journal_stream_dev); + assert(journal_stream_ino); if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) { @@ -543,6 +548,17 @@ static int setup_output( if (r < 0) { log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr"); r = open_null_as(O_WRONLY, fileno); + } else { + struct stat st; + + /* If we connected this fd to the journal via a stream, patch the device/inode into the passed + * parameters, but only then. This is useful so that we can set $JOURNAL_STREAM that permits + * services to detect whether they are connected to the journal or not. */ + + if (fstat(fileno, &st) >= 0) { + *journal_stream_dev = st.st_dev; + *journal_stream_ino = st.st_ino; + } } return r; @@ -1286,6 +1302,8 @@ static int build_environment( const char *home, const char *username, const char *shell, + dev_t journal_stream_dev, + ino_t journal_stream_ino, char ***ret) { _cleanup_strv_free_ char **our_env = NULL; @@ -1295,7 +1313,7 @@ static int build_environment( assert(c); assert(ret); - our_env = new0(char*, 11); + our_env = new0(char*, 12); if (!our_env) return -ENOMEM; @@ -1367,8 +1385,15 @@ static int build_environment( our_env[n_env++] = x; } + if (journal_stream_dev != 0 && journal_stream_ino != 0) { + if (asprintf(&x, "JOURNAL_STREAM=" DEV_FMT ":" INO_FMT, journal_stream_dev, journal_stream_ino) < 0) + return -ENOMEM; + + our_env[n_env++] = x; + } + our_env[n_env++] = NULL; - assert(n_env <= 11); + assert(n_env <= 12); *ret = our_env; our_env = NULL; @@ -1481,10 +1506,12 @@ static int exec_child( _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; const char *username = NULL, *home = NULL, *shell = NULL, *wd; + dev_t journal_stream_dev = 0; + ino_t journal_stream_ino = 0; + bool needs_mount_namespace; uid_t uid = UID_INVALID; gid_t gid = GID_INVALID; int i, r; - bool needs_mount_namespace; assert(unit); assert(command); @@ -1584,13 +1611,13 @@ static int exec_child( return r; } - r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid); + r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino); if (r < 0) { *exit_status = EXIT_STDOUT; return r; } - r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid); + r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino); if (r < 0) { *exit_status = EXIT_STDERR; return r; @@ -1729,7 +1756,16 @@ static int exec_child( } } - r = build_environment(context, params, n_fds, home, username, shell, &our_env); + r = build_environment( + context, + params, + n_fds, + home, + username, + shell, + journal_stream_dev, + journal_stream_ino, + &our_env); if (r < 0) { *exit_status = EXIT_MEMORY; return r; -- cgit v1.2.3-54-g00ecf From 20897a0d6ea12bbc08f70146cc7ad4540b65a0fa Mon Sep 17 00:00:00 2001 From: Andreas Rammhold Date: Fri, 10 Jun 2016 01:57:51 +0200 Subject: networkd: added support for vrf interfaces (#3316) --- Makefile.am | 2 ++ configure.ac | 1 + man/systemd.netdev.xml | 13 ++++++++ src/basic/missing.h | 4 +++ src/libsystemd/sd-netlink/netlink-types.c | 8 +++++ src/libsystemd/sd-netlink/netlink-types.h | 1 + src/network/networkd-netdev-gperf.gperf | 2 ++ src/network/networkd-netdev-vrf.c | 50 +++++++++++++++++++++++++++++++ src/network/networkd-netdev-vrf.h | 33 ++++++++++++++++++++ src/network/networkd-netdev.c | 4 +++ src/network/networkd-netdev.h | 1 + src/network/networkd.h | 1 + 12 files changed, 120 insertions(+) create mode 100644 src/network/networkd-netdev-vrf.c create mode 100644 src/network/networkd-netdev-vrf.h (limited to 'man') diff --git a/Makefile.am b/Makefile.am index 8960513ffe..50e01af667 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5462,6 +5462,8 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-link.c \ src/network/networkd-netdev.h \ src/network/networkd-netdev.c \ + src/network/networkd-netdev-vrf.h \ + src/network/networkd-netdev-vrf.c \ src/network/networkd-netdev-tunnel.h \ src/network/networkd-netdev-tunnel.c \ src/network/networkd-netdev-veth.h \ diff --git a/configure.ac b/configure.ac index ffc6eedcdd..f4fcc4f113 100644 --- a/configure.ac +++ b/configure.ac @@ -325,6 +325,7 @@ AC_CHECK_TYPES([char16_t, char32_t, key_serial_t], AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, IN6_ADDR_GEN_MODE_STABLE_PRIVACY, + IFLA_VRF_TABLE, IFLA_MACVLAN_FLAGS, IFLA_IPVLAN_MODE, IFLA_VTI_REMOTE, diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 3cc58ca854..2be1efee2f 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -161,6 +161,10 @@ vxlan A virtual extensible LAN (vxlan), for connecting Cloud computing deployments. + + vrf + A Virtual Routing and Forwarding (VRF) interface to create seperate routing and forwarding domains. + @@ -1137,7 +1141,16 @@ Name=dummy-test Kind=dummy MACAddress=12:34:56:78:9a:bc + + /etc/systemd/network/25-vrf.netdev + Create an VRF interface with table 42. + [NetDev] +Name=vrf-test +Kind=vrf +[VRF] +TableId=42 + See Also diff --git a/src/basic/missing.h b/src/basic/missing.h index 53dfa1c801..b1272f8799 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -837,6 +837,10 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BRPORT_PROXYARP 10 #endif +#if !HAVE_DECL_IFLA_VRF_TABLE +#define IFLA_VRF_TABLE 1 +#endif + #if !HAVE_DECL_NDA_IFINDEX #define NDA_UNSPEC 0 #define NDA_DST 1 diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 3a4bac2ced..566a050432 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -278,6 +278,10 @@ static const NLType rtnl_link_info_data_ip6tnl_types[] = { [IFLA_IPTUN_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, }; +static const NLType rtnl_link_info_data_vrf_types[] = { + [IFLA_VRF_TABLE] = { .type = NETLINK_TYPE_U32 }, +}; + /* these strings must match the .kind entries in the kernel */ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_BOND] = "bond", @@ -298,6 +302,7 @@ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_VTI_TUNNEL] = "vti", [NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL] = "vti6", [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = "ip6tnl", + [NL_UNION_LINK_INFO_DATA_VRF] = "vrf", }; DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData); @@ -338,6 +343,9 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = { [NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL] = { .count = ELEMENTSOF(rtnl_link_info_data_ip6tnl_types), .types = rtnl_link_info_data_ip6tnl_types }, + [NL_UNION_LINK_INFO_DATA_VRF] = { .count = ELEMENTSOF(rtnl_link_info_data_vrf_types), + .types = rtnl_link_info_data_vrf_types }, + }; static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = { diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index ecb20bfcdc..7c0e598b26 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -86,6 +86,7 @@ typedef enum NLUnionLinkInfoData { NL_UNION_LINK_INFO_DATA_VTI_TUNNEL, NL_UNION_LINK_INFO_DATA_VTI6_TUNNEL, NL_UNION_LINK_INFO_DATA_IP6TNL_TUNNEL, + NL_UNION_LINK_INFO_DATA_VRF, _NL_UNION_LINK_INFO_DATA_MAX, _NL_UNION_LINK_INFO_DATA_INVALID = -1 } NLUnionLinkInfoData; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index bf93b0d9fa..9d69f61376 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -11,6 +11,7 @@ #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" #include "networkd-netdev-vxlan.h" +#include "networkd-netdev-vrf.h" #include "networkd-netdev.h" #include "vlan-util.h" %} @@ -105,3 +106,4 @@ Bridge.ForwardDelaySec, config_parse_sec, 0, Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier) Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping) Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering) +VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table_id) diff --git a/src/network/networkd-netdev-vrf.c b/src/network/networkd-netdev-vrf.c new file mode 100644 index 0000000000..8bbb0aecb1 --- /dev/null +++ b/src/network/networkd-netdev-vrf.c @@ -0,0 +1,50 @@ +/*** + This file is part of systemd. + + Copyright 2016 Andreas Rammhold + + 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 . +***/ + +#include + +#include "sd-netlink.h" +#include "missing.h" +#include "networkd-netdev-vrf.h" + +static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { + Vrf *v; + int r; + + assert(netdev); + assert(!link); + assert(m); + + v = VRF(netdev); + + assert(v); + + r = sd_netlink_message_append_u32(m, IFLA_VRF_TABLE, v->table_id); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IPLA_VRF_TABLE attribute: %m"); + + return r; +} + +const NetDevVTable vrf_vtable = { + .object_size = sizeof(Vrf), + .sections = "Match\0NetDev\0VRF\0", + .fill_message_create = netdev_vrf_fill_message_create, + .create_type = NETDEV_CREATE_MASTER, +}; diff --git a/src/network/networkd-netdev-vrf.h b/src/network/networkd-netdev-vrf.h new file mode 100644 index 0000000000..3d92a26a4d --- /dev/null +++ b/src/network/networkd-netdev-vrf.h @@ -0,0 +1,33 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Andreas Rammhold + + 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 . +***/ + +typedef struct Vrf Vrf; + +#include "networkd-netdev.h" + +struct Vrf { + NetDev meta; + + uint32_t table_id; +}; + +DEFINE_NETDEV_CAST(VRF, Vrf); +extern const NetDevVTable vrf_vtable; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 851a36290c..b55d76a53c 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -55,6 +55,8 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { [NETDEV_KIND_TUN] = &tun_vtable, [NETDEV_KIND_TAP] = &tap_vtable, [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable, + [NETDEV_KIND_VRF] = &vrf_vtable, + }; static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { @@ -78,6 +80,8 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { [NETDEV_KIND_TUN] = "tun", [NETDEV_KIND_TAP] = "tap", [NETDEV_KIND_IP6TNL] = "ip6tnl", + [NETDEV_KIND_VRF] = "vrf", + }; DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 20244c0309..b92a973b85 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -55,6 +55,7 @@ typedef enum NetDevKind { NETDEV_KIND_DUMMY, NETDEV_KIND_TUN, NETDEV_KIND_TAP, + NETDEV_KIND_VRF, _NETDEV_KIND_MAX, _NETDEV_KIND_INVALID = -1 } NetDevKind; diff --git a/src/network/networkd.h b/src/network/networkd.h index ab512f0d08..c4bd712147 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -41,6 +41,7 @@ #include "networkd-netdev-tuntap.h" #include "networkd-netdev-veth.h" #include "networkd-netdev-vlan.h" +#include "networkd-netdev-vrf.h" #include "networkd-netdev-vxlan.h" #include "networkd-network.h" #include "networkd-util.h" -- cgit v1.2.3-54-g00ecf From 6cb955c6a18d7e122ca24ca4873343ca41feeb50 Mon Sep 17 00:00:00 2001 From: Andreas Rammhold Date: Mon, 13 Jun 2016 01:05:49 +0200 Subject: networkd: vrf: add support for enslaving devices to VRFs --- man/systemd.network.xml | 17 +++++++++++++++++ src/network/networkd-link.c | 23 ++++++++++++++++++++++- src/network/networkd-netdev-vrf.c | 2 +- src/network/networkd-netdev.c | 4 ++-- src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 6 +++++- src/network/networkd-network.h | 1 + 7 files changed, 49 insertions(+), 5 deletions(-) (limited to 'man') diff --git a/man/systemd.network.xml b/man/systemd.network.xml index ea98c821fa..edf227c134 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -578,6 +578,12 @@ The name of the bond to add the link to. + + VRF= + + The name of the VRF to add the link to. + + VLAN= @@ -1276,6 +1282,17 @@ Name=bond1 [Network] DHCP=yes + + + + + /etc/systemd/network/25-vrf.network + Add the bond1 interface to the VRF master interface vrf-test. This will redirect routes generated on this interface to be within the routing table defined during VRF creation. Traffic won't be redirected towards the VRFs routing table unless specific ip-rules are added. + [Match] +Name=bond1 + +[Network] +VRF=vrf-test diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 044f934e5f..1842685180 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1600,7 +1600,7 @@ static int link_up(Link *link) { return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); /* set it free if not enslaved with networkd */ - if (!link->network->bridge && !link->network->bond) { + if (!link->network->bridge && !link->network->bond && !link->network->vrf) { r = sd_netlink_message_append_u32(req, IFLA_MASTER, 0); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_MASTER attribute: %m"); @@ -2055,6 +2055,7 @@ static int link_enter_join_netdev(Link *link) { if (!link->network->bridge && !link->network->bond && + !link->network->vrf && hashmap_isempty(link->network->stacked_netdevs)) return link_joined(link); @@ -2101,6 +2102,26 @@ static int link_enter_join_netdev(Link *link) { link->enslaving++; } + if (link->network->vrf) { + log_struct(LOG_DEBUG, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->vrf), + LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->vrf->ifname), + NULL); + r = netdev_join(link->network->vrf, link, netdev_join_handler); + if (r < 0) { + log_struct_errno(LOG_WARNING, r, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->vrf), + LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->vrf->ifname), + NULL); + link_enter_failed(link); + return r; + } + + link->enslaving++; + } + HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { log_struct(LOG_DEBUG, diff --git a/src/network/networkd-netdev-vrf.c b/src/network/networkd-netdev-vrf.c index 8bbb0aecb1..89bd142e8c 100644 --- a/src/network/networkd-netdev-vrf.c +++ b/src/network/networkd-netdev-vrf.c @@ -44,7 +44,7 @@ static int netdev_vrf_fill_message_create(NetDev *netdev, Link *link, sd_netlink const NetDevVTable vrf_vtable = { .object_size = sizeof(Vrf), - .sections = "Match\0NetDev\0VRF\0", + .sections = "NetDev\0VRF\0", .fill_message_create = netdev_vrf_fill_message_create, .create_type = NETDEV_CREATE_MASTER, }; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index b55d76a53c..b192884fd9 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -202,7 +202,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h assert(netdev->state == NETDEV_STATE_READY); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); assert(link); assert(callback); @@ -285,7 +285,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call assert(netdev); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); if (netdev->state == NETDEV_STATE_READY) { r = netdev_enslave_ready(netdev, link, callback); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 0b0aa58f67..affc0d00e9 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -37,6 +37,7 @@ Network.MACVTAP, config_parse_netdev, Network.IPVLAN, config_parse_netdev, 0, 0 Network.VXLAN, config_parse_netdev, 0, 0 Network.Tunnel, config_parse_tunnel, 0, 0 +Network.VRF, config_parse_netdev, 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) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 84bdf75b38..2b764d4f24 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -244,8 +244,8 @@ void network_free(Network *network) { strv_free(network->bind_carrier); netdev_unref(network->bridge); - netdev_unref(network->bond); + netdev_unref(network->vrf); HASHMAP_FOREACH(netdev, network->stacked_netdevs, i) { hashmap_remove(network->stacked_netdevs, netdev->ifname); @@ -470,6 +470,10 @@ int config_parse_netdev(const char *unit, case NETDEV_KIND_BOND: network->bond = netdev; + break; + case NETDEV_KIND_VRF: + network->vrf = netdev; + break; case NETDEV_KIND_VLAN: case NETDEV_KIND_MACVLAN: diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 38688cc400..08ee939faa 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -104,6 +104,7 @@ struct Network { NetDev *bridge; NetDev *bond; + NetDev *vrf; Hashmap *stacked_netdevs; /* DHCP Client Support */ -- cgit v1.2.3-54-g00ecf From ff74d2058152d0a9ed82346c16ec30b6694cbfa5 Mon Sep 17 00:00:00 2001 From: Lukáš Nykrýn Date: Sun, 19 Jun 2016 19:22:46 +0200 Subject: man: match runlevel symlinks recommendation with our makefile (#3563) In makefile we create symlinks runlevel5.target to graphical.target and runlevel2-4.target to multi-user.target. Let's say the same thing in systemd.special manpage. --- man/systemd.special.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'man') diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 26974ed73f..19ca6d6837 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -497,8 +497,8 @@ These are targets that are called whenever the SysV compatibility code asks for runlevel 2, 3, 4, 5, respectively. It is a good idea to make this an alias for - (i.e. symlink to) multi-user.target - (for runlevel 2) or graphical.target + (i.e. symlink to) graphical.target + (for runlevel 5) or multi-user.target (the others). -- cgit v1.2.3-54-g00ecf From be371fe03937b6b3c45ee58a96622ff1849b14e4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 15 Jun 2016 21:43:36 +0200 Subject: resolve: add "systemd-resolve --status" command The new command shows the per-link and global DNS configuration currently in effect. This is useful to quickly see the DNS settings resolved acquired from networkd and that was pushed into it via the bus APIs. --- man/systemd-resolve.xml | 7 + src/resolve/resolve-tool.c | 522 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 526 insertions(+), 3 deletions(-) (limited to 'man') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index b917ac20a2..b7fbee3154 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -294,8 +294,15 @@ Flushes all DNS resource record caches the service maintains locally. + + + + Shows the global and per-link DNS settings in currently in effect. + + + diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 2cb2e42b23..4e1e916669 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -21,17 +21,21 @@ #include #include "sd-bus.h" +#include "sd-netlink.h" #include "af-list.h" #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "escape.h" -#include "in-addr-util.h" #include "gcrypt-util.h" +#include "in-addr-util.h" +#include "netlink-util.h" +#include "pager.h" #include "parse-util.h" #include "resolved-def.h" #include "resolved-dns-packet.h" +#include "strv.h" #include "terminal-util.h" #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC) @@ -42,6 +46,7 @@ static uint16_t arg_type = 0; static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; +static bool arg_no_pager = false; typedef enum ServiceFamily { SERVICE_FAMILY_TCP, @@ -67,6 +72,7 @@ static enum { MODE_STATISTICS, MODE_RESET_STATISTICS, MODE_FLUSH_CACHES, + MODE_STATUS, } arg_mode = MODE_RESOLVE_HOST; static ServiceFamily service_family_from_string(const char *s) { @@ -1031,6 +1037,472 @@ static int flush_caches(sd_bus *bus) { return 0; } +static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(iay)"); + if (r < 0) + return r; + + for (;;) { + const void *a; + char *pretty; + int family; + size_t sz; + + r = sd_bus_message_enter_container(m, 'r', "iay"); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_read(m, "i", &family); + if (r < 0) + return r; + + r = sd_bus_message_read_array(m, 'y', &a, &sz); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (!IN_SET(family, AF_INET, AF_INET6)) { + log_debug("Unexpected family, ignoring."); + continue; + } + + if (sz != FAMILY_ADDRESS_SIZE(family)) { + log_debug("Address size mismatch, ignoring."); + continue; + } + + r = in_addr_to_string(family, a, &pretty); + if (r < 0) + return r; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(sb)"); + if (r < 0) + return r; + + for (;;) { + const char *domain; + int route_only; + char *pretty; + + r = sd_bus_message_read(m, "(sb)", &domain, &route_only); + if (r < 0) + return r; + if (r == 0) + break; + + if (route_only) + pretty = strappend("~", domain); + else + pretty = strdup(domain); + if (!pretty) + return -ENOMEM; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empty_line) { + + struct link_info { + uint64_t scopes_mask; + char *llmnr; + char *mdns; + char *dnssec; + char **dns; + char **domains; + char **ntas; + int dnssec_supported; + } link_info = {}; + + static const struct bus_properties_map property_map[] = { + { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) }, + { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) }, + { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) }, + { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) }, + { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) }, + { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) }, + { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) }, + {} + }; + + _cleanup_free_ char *ifi = NULL, *p = NULL; + char ifname[IF_NAMESIZE] = ""; + char **i; + int r; + + assert(bus); + assert(ifindex > 0); + assert(empty_line); + + if (!name) { + if (!if_indextoname(ifindex, ifname)) + return log_error_errno(errno, "Failed to resolve interface name for %i: %m", ifindex); + + name = ifname; + } + + if (asprintf(&ifi, "%i", ifindex) < 0) + return log_oom(); + + r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p); + if (r < 0) + return log_oom(); + + r = bus_map_all_properties(bus, + "org.freedesktop.resolve1", + p, + property_map, + &link_info); + if (r < 0) { + log_error_errno(r, "Failed to get link data for %i: %m", ifindex); + goto finish; + } + + pager_open(arg_no_pager, false); + + if (*empty_line) + fputc('\n', stdout); + + printf("%sLink %i (%s)%s\n", + ansi_highlight(), ifindex, name, ansi_normal()); + + if (link_info.scopes_mask == 0) + printf(" Current Scopes: none\n"); + else + printf(" Current Scopes:%s%s%s%s%s\n", + link_info.scopes_mask & SD_RESOLVED_DNS ? " DNS" : "", + link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "", + link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "", + link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "", + link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : ""); + + printf(" LLMNR setting: %s\n" + "MulticastDNS setting: %s\n" + " DNSSEC setting: %s\n" + " DNSSEC supported: %s\n", + strna(link_info.llmnr), + strna(link_info.mdns), + strna(link_info.dnssec), + yes_no(link_info.dnssec_supported)); + + STRV_FOREACH(i, link_info.dns) { + printf(" %s %s\n", + i == link_info.dns ? "DNS Server:" : " ", + *i); + } + + STRV_FOREACH(i, link_info.domains) { + printf(" %s %s\n", + i == link_info.domains ? "DNS Domain:" : " ", + *i); + } + + STRV_FOREACH(i, link_info.ntas) { + printf(" %s %s\n", + i == link_info.ntas ? "DNSSEC NTA:" : " ", + *i); + } + + *empty_line = true; + + r = 0; + +finish: + strv_free(link_info.dns); + strv_free(link_info.domains); + free(link_info.llmnr); + free(link_info.mdns); + free(link_info.dnssec); + strv_free(link_info.ntas); + return r; +} + +static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(iiay)"); + if (r < 0) + return r; + + for (;;) { + const void *a; + char *pretty; + int family, ifindex; + size_t sz; + + r = sd_bus_message_enter_container(m, 'r', "iiay"); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_read(m, "ii", &ifindex, &family); + if (r < 0) + return r; + + r = sd_bus_message_read_array(m, 'y', &a, &sz); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + if (ifindex != 0) /* only show the global ones here */ + continue; + + if (!IN_SET(family, AF_INET, AF_INET6)) { + log_debug("Unexpected family, ignoring."); + continue; + } + + if (sz != FAMILY_ADDRESS_SIZE(family)) { + log_debug("Address size mismatch, ignoring."); + continue; + } + + r = in_addr_to_string(family, a, &pretty); + if (r < 0) + return r; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) { + char ***l = userdata; + int r; + + assert(bus); + assert(member); + assert(m); + assert(l); + + r = sd_bus_message_enter_container(m, 'a', "(isb)"); + if (r < 0) + return r; + + for (;;) { + const char *domain; + int route_only, ifindex; + char *pretty; + + r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only); + if (r < 0) + return r; + if (r == 0) + break; + + if (ifindex != 0) /* only show the global ones here */ + continue; + + if (route_only) + pretty = strappend("~", domain); + else + pretty = strdup(domain); + if (!pretty) + return -ENOMEM; + + r = strv_consume(l, pretty); + if (r < 0) + return r; + } + + r = sd_bus_message_exit_container(m); + if (r < 0) + return r; + + return 0; +} + +static int status_global(sd_bus *bus, bool *empty_line) { + + struct global_info { + char **dns; + char **domains; + char **ntas; + } global_info = {}; + + static const struct bus_properties_map property_map[] = { + { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) }, + { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) }, + { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) }, + {} + }; + + char **i; + int r; + + assert(bus); + assert(empty_line); + + r = bus_map_all_properties(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + property_map, + &global_info); + if (r < 0) { + log_error_errno(r, "Failed to get global data: %m"); + goto finish; + } + + if (strv_isempty(global_info.dns) && strv_isempty(global_info.domains) && strv_isempty(global_info.ntas)) { + r = 0; + goto finish; + } + + pager_open(arg_no_pager, false); + + printf("%sGlobal%s\n", ansi_highlight(), ansi_normal()); + STRV_FOREACH(i, global_info.dns) { + printf(" %s %s\n", + i == global_info.dns ? "DNS Server:" : " ", + *i); + } + + STRV_FOREACH(i, global_info.domains) { + printf(" %s %s\n", + i == global_info.domains ? "DNS Domain:" : " ", + *i); + } + + strv_sort(global_info.ntas); + STRV_FOREACH(i, global_info.ntas) { + printf(" %s %s\n", + i == global_info.ntas ? "DNSSEC NTA:" : " ", + *i); + } + + *empty_line = true; + + r = 0; + +finish: + strv_free(global_info.dns); + strv_free(global_info.domains); + strv_free(global_info.ntas); + + return r; +} + +static int status_all(sd_bus *bus) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + sd_netlink_message *i; + bool empty_line = true; + int r; + + assert(bus); + + r = status_global(bus, &empty_line); + if (r < 0) + return r; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_message_request_dump(req, true); + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_call(rtnl, req, 0, &reply); + if (r < 0) + return log_error_errno(r, "Failed to enumerate links: %m"); + + r = 0; + for (i = reply; i; i = sd_netlink_message_next(i)) { + const char *name; + int ifindex, q; + uint16_t type; + + q = sd_netlink_message_get_type(i, &type); + if (q < 0) + return rtnl_log_parse_error(q); + + if (type != RTM_NEWLINK) + continue; + + q = sd_rtnl_message_link_get_ifindex(i, &ifindex); + if (q < 0) + return rtnl_log_parse_error(q); + + if (ifindex == LOOPBACK_IFINDEX) + continue; + + q = sd_netlink_message_read_string(i, IFLA_IFNAME, &name); + if (q < 0) + return rtnl_log_parse_error(q); + + q = status_ifindex(bus, ifindex, name, &empty_line); + if (q < 0 && r >= 0) + r = q; + } + + return r; +} + static void help_protocol_types(void) { if (arg_legend) puts("Known protocol types:"); @@ -1038,8 +1510,8 @@ static void help_protocol_types(void) { } static void help_dns_types(void) { - int i; const char *t; + int i; if (arg_legend) puts("Known DNS RR types:"); @@ -1051,8 +1523,8 @@ static void help_dns_types(void) { } static void help_dns_classes(void) { - int i; const char *t; + int i; if (arg_legend) puts("Known DNS RR classes:"); @@ -1073,6 +1545,7 @@ static void help(void) { "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n" " -h --help Show this help\n" " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" " -4 Resolve IPv4 addresses\n" " -6 Resolve IPv6 addresses\n" " -i --interface=INTERFACE Look on interface\n" @@ -1091,6 +1564,7 @@ static void help(void) { " --legend=BOOL Print headers and additional info (default: yes)\n" " --statistics Show resolver statistics\n" " --reset-statistics Reset resolver statistics\n" + " --status Show link and server status\n" " --flush-caches Flush all local DNS caches\n" , program_invocation_short_name); } @@ -1109,7 +1583,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_SEARCH, ARG_STATISTICS, ARG_RESET_STATISTICS, + ARG_STATUS, ARG_FLUSH_CACHES, + ARG_NO_PAGER, }; static const struct option options[] = { @@ -1130,7 +1606,9 @@ static int parse_argv(int argc, char *argv[]) { { "search", required_argument, NULL, ARG_SEARCH }, { "statistics", no_argument, NULL, ARG_STATISTICS, }, { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, + { "status", no_argument, NULL, ARG_STATUS }, { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, {} }; @@ -1308,6 +1786,14 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = MODE_FLUSH_CACHES; break; + case ARG_STATUS: + arg_mode = MODE_STATUS; + break; + + case ARG_NO_PAGER: + arg_no_pager = true; + break; + case '?': return -EINVAL; @@ -1484,8 +1970,38 @@ int main(int argc, char **argv) { r = flush_caches(bus); break; + + case MODE_STATUS: + + if (argc > optind) { + char **ifname; + bool empty_line = false; + + r = 0; + STRV_FOREACH(ifname, argv + optind) { + int ifindex, q; + + q = parse_ifindex(argv[optind], &ifindex); + if (q < 0) { + ifindex = if_nametoindex(argv[optind]); + if (ifindex <= 0) { + log_error_errno(errno, "Failed to resolve interface name: %s", argv[optind]); + continue; + } + } + + q = status_ifindex(bus, ifindex, NULL, &empty_line); + if (q < 0 && r >= 0) + r = q; + } + } else + r = status_all(bus); + + break; } finish: + pager_close(); + return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- cgit v1.2.3-54-g00ecf From b541146bf8c34aaaa9efcf58325f18da9253c4ec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Jun 2016 13:19:21 +0200 Subject: man: beef up resolved man page Let's explain the various APIs and various ways to handle /etc/resolv.conf. --- man/systemd-resolved.service.xml | 95 ++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 23 deletions(-) (limited to 'man') diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 485f3e9aee..0df037ba69 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -58,27 +58,45 @@ systemd-resolved is a system service that provides network name resolution to local applications. It implements a caching and validating DNS/DNSSEC stub resolver, as well as an LLMNR resolver and - responder. In addition it maintains the /run/systemd/resolve/resolv.conf file for - compatibility with traditional Linux programs. This file may be symlinked from - /etc/resolv.conf. - - The glibc NSS module - nss-resolve8 is required to - permit glibc's NSS resolver functions to resolve host names via systemd-resolved. - - The DNS servers contacted are determined from the global - settings in /etc/systemd/resolved.conf, the - per-link static settings in /etc/systemd/network/*.network files, - and the per-link dynamic settings received over DHCP. See - resolved.conf5 - and - systemd.network5 - for details. To improve compatibility, - /etc/resolv.conf is read in order to discover - configured system DNS servers, but only if it is not a symlink - to /run/systemd/resolve/resolv.conf (see above). + responder. Local applications may submit network name resolution requests via three interfaces: + + + The native, fully-featured API systemd-resolved exposes on the bus. See the + API Documentation for + details. Usage of this API is generally recommended to clients as it is asynchronous and fully featured (for + example, properly returns DNSSEC validation status and interface scope for addresses as necessary for supporting + link-local networking). + + The glibc + getaddrinfo3 API (as defined + by RFC3493) and its related resolver functions, + including gethostbyname3. This + API is widely supported, including beyond the Linux platform. In its current form it does not expose DNSSEC + validation status information however, and is synchronous only. This API is backed by the glibc Name Service + Switch (nss5). Usage of the + glibc NSS module nss-resolve8 + is required in order to allow glibc's NSS resolver functions to resolve host names via + systemd-resolved. + + Additionally, systemd-resolved provides a local DNS stub listener on IP + address 127.0.0.53 on the local loopback interface. Programs issuing DNS requests directly, bypassing any local + API may be directed to this stub, in order to connect them systemd-resolved. Note however that + it is strongly recommended that local programs use the glibc NSS or bus APIs instead (as described above), as + various network resolution concepts (such as link-local addressing, or LLMNR Unicode domains) cannot be mapped to + the unicast DNS protocol. + - systemd-resolved synthesizes DNS RRs for the following cases: + The DNS servers contacted are determined from the global settings in + /etc/systemd/resolved.conf, the per-link static settings in + /etc/systemd/network/*.network files, the per-link dynamic settings received over DHCP and any + DNS server information made available by other system services. See + resolved.conf5 and + systemd.network5 for details + about systemd's own configuration files for DNS servers. To improve compatibility, + /etc/resolv.conf is read in order to discover configured system DNS servers, but only if it is + not a symlink to /run/systemd/resolve/resolv.conf (see below). + + systemd-resolved synthesizes DNS resource records (RRs) for the following cases: The local, configured hostname is resolved to @@ -137,14 +155,45 @@ per-interface domains are exclusively routed to the matching interfaces. - Note that /run/systemd/resolve/resolv.conf should not be used directly by applications, - but only through a symlink from /etc/resolv.conf. - See the resolved D-Bus API Documentation for information about the APIs systemd-resolved provides. + + <filename>/etc/resolv.conf</filename> + + Three modes of handling /etc/resolv.conf (see + resolv.conf5) are + supported: + + + A static file /usr/lib/systemd/resolv.conf is provided that lists + the 127.0.0.53 DNS stub (see above) as only DNS server. This file may be symlinked from + /etc/resolv.conf in order to connect all local clients that bypass local DNS APIs to + systemd-resolved. This mode of operation is recommended. + + systemd-resolved maintains the + /run/systemd/resolve/resolv.conf file for compatibility with traditional Linux + programs. This file may be symlinked from /etc/resolv.conf and is always kept up-to-date, + containing information about all known DNS servers. Note the file format's limitations: it does not know a + concept of per-interface DNS servers and hence only contains system-wide DNS server definitions. Note that + /run/systemd/resolve/resolv.conf should not be used directly by applications, but only + through a symlink from /etc/resolv.conf. If this mode of operation is used local clients + that bypass any local DNS API will also bypass systemd-resolved and will talk directly to the + known DNS servers. + + Alternatively, /etc/resolv.conf may be managed by other packages, in which + case systemd-resolved will read it for DNS configuration data. In this mode of operation + systemd-resolved is consumer rather than provider of this configuration + file. + + + Note that the selected mode of operation for this file is detected fully automatically, depending on whether + /etc/resolv.conf is a symlink to /run/systemd/resolve/resolv.conf or + lists 127.0.0.53 as DNS server. + + Signals -- cgit v1.2.3-54-g00ecf From e382c49f1dfe172cc14651fd0908da6ebf12ef53 Mon Sep 17 00:00:00 2001 From: mahkoh Date: Tue, 21 Jun 2016 17:52:32 +0200 Subject: man: document some sd-bus functions (#3567) * sd_bus_add_match * sd_bus_get_fd * sd_bus_message_read_basic * sd_bus_process --- Makefile-man.am | 8 +++ man/sd_bus_add_match.xml | 119 ++++++++++++++++++++++++++++++++++++++ man/sd_bus_get_fd.xml | 101 ++++++++++++++++++++++++++++++++ man/sd_bus_message_read_basic.xml | 113 ++++++++++++++++++++++++++++++++++++ man/sd_bus_process.xml | 111 +++++++++++++++++++++++++++++++++++ 5 files changed, 452 insertions(+) create mode 100644 man/sd_bus_add_match.xml create mode 100644 man/sd_bus_get_fd.xml create mode 100644 man/sd_bus_message_read_basic.xml create mode 100644 man/sd_bus_process.xml (limited to 'man') diff --git a/Makefile-man.am b/Makefile-man.am index d5b328d267..cd7583bed7 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -31,11 +31,13 @@ MANPAGES += \ man/sd-id128.3 \ man/sd-journal.3 \ man/sd_booted.3 \ + man/sd_bus_add_match.3 \ man/sd_bus_creds_get_pid.3 \ man/sd_bus_creds_new_from_pid.3 \ man/sd_bus_default.3 \ man/sd_bus_error.3 \ man/sd_bus_error_add_map.3 \ + man/sd_bus_get_fd.3 \ man/sd_bus_message_append.3 \ man/sd_bus_message_append_array.3 \ man/sd_bus_message_append_basic.3 \ @@ -43,9 +45,11 @@ MANPAGES += \ man/sd_bus_message_append_strv.3 \ man/sd_bus_message_get_cookie.3 \ man/sd_bus_message_get_monotonic_usec.3 \ + man/sd_bus_message_read_basic.3 \ man/sd_bus_negotiate_fds.3 \ man/sd_bus_new.3 \ man/sd_bus_path_encode.3 \ + man/sd_bus_process.3 \ man/sd_bus_request_name.3 \ man/sd_event_add_child.3 \ man/sd_event_add_defer.3 \ @@ -2522,11 +2526,13 @@ EXTRA_DIST += \ man/sd-journal.xml \ man/sd-login.xml \ man/sd_booted.xml \ + man/sd_bus_add_match.xml \ man/sd_bus_creds_get_pid.xml \ man/sd_bus_creds_new_from_pid.xml \ man/sd_bus_default.xml \ man/sd_bus_error.xml \ man/sd_bus_error_add_map.xml \ + man/sd_bus_get_fd.xml \ man/sd_bus_message_append.xml \ man/sd_bus_message_append_array.xml \ man/sd_bus_message_append_basic.xml \ @@ -2534,9 +2540,11 @@ EXTRA_DIST += \ man/sd_bus_message_append_strv.xml \ man/sd_bus_message_get_cookie.xml \ man/sd_bus_message_get_monotonic_usec.xml \ + man/sd_bus_message_read_basic.xml \ man/sd_bus_negotiate_fds.xml \ man/sd_bus_new.xml \ man/sd_bus_path_encode.xml \ + man/sd_bus_process.xml \ man/sd_bus_request_name.xml \ man/sd_event_add_child.xml \ man/sd_event_add_defer.xml \ diff --git a/man/sd_bus_add_match.xml b/man/sd_bus_add_match.xml new file mode 100644 index 0000000000..8bcf7164a0 --- /dev/null +++ b/man/sd_bus_add_match.xml @@ -0,0 +1,119 @@ + + + + + + + + + sd_bus_add_match + systemd + + + + Julian + Orth + ju.orth@gmail.com + + + + + + sd_bus_add_match + 3 + + + + sd_bus_add_match + + Add a match rule for message dispatching + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_add_match + sd_bus *bus + sd_bus_slot **slot + const char *match + sd_bus_message_handler_t callback + void *userdata + + + + typedef int (*sd_bus_message_handler_t) + sd_bus_message *m + void *userdata + sd_bus_error *ret_error + + + + + + Description + + + sd_bus_add_match() adds a match rule used to dispatch + incoming messages. The syntax of the rule passed in + match is described in the + D-Bus Specification. + + + + The message m passed to the callback is only + borrowed, that is, the callback should not call + sd_bus_message_unref3 + on it. If the callback wants to hold on to the message beyond the lifetime + of the callback, it needs to call + sd_bus_message_ref3 + to create a new reference. + + + + If an error occurs during the callback invocation, the callback should + return a negative error number. If it wants other callbacks that match the + same rule to be called, it should return 0. Otherwise it should return a + positive integer. + + + + + Return Value + + + On success, sd_bus_add_match() returns 0 or a + positive integer. On failure, it returns a negative errno-style error + code. + + + + + See Also + + + systemd1, + sd-bus3, + + + + diff --git a/man/sd_bus_get_fd.xml b/man/sd_bus_get_fd.xml new file mode 100644 index 0000000000..49162a6e65 --- /dev/null +++ b/man/sd_bus_get_fd.xml @@ -0,0 +1,101 @@ + + + + + + + + + sd_bus_get_fd + systemd + + + + Julian + Orth + ju.orth@gmail.com + + + + + + sd_bus_get_fd + 3 + + + + sd_bus_get_fd + + Get the file descriptor connected to the message bus + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_get_fd + sd_bus *bus + + + + + + Description + + + sd_bus_get_fd() returns the file descriptor used to + communicate with the message bus. This descriptor can be used with + select3, + poll3, + or similar functions to wait for incmming messages. + + + + If the bus was created with the + sd_bus_set_fd3 + function, then the input_fd used in that call is + returned. + + + + + Return Value + + + Returns the file descriptor used for incoming messages from the message + bus. + + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_set_fd3, + + + + diff --git a/man/sd_bus_message_read_basic.xml b/man/sd_bus_message_read_basic.xml new file mode 100644 index 0000000000..6a46403159 --- /dev/null +++ b/man/sd_bus_message_read_basic.xml @@ -0,0 +1,113 @@ + + + + + + + + + sd_bus_message_read_basic + systemd + + + + Julian + Orth + ju.orth@gmail.com + + + + + + sd_bus_message_read_basic + 3 + + + + sd_bus_message_read_basic + + Read a basic type from a message + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_message_read_basic + sd_bus_message *m + char type + void *p + + + + + + Description + + + sd_bus_message_read_basic() reads a basic type from a + message and advances the read position in the message. The set of basic + types and their ascii codes passed in type are + described in the D-Bus + Specification. + + + + If p is not NULL, it should contain a pointer to an + appropriate object. For example, if type is + 'y', the object passed in p + should have type uint8_t *. If type + is 's', the object passed in p + should have type const char **. Note that, if the basic type + is a pointer (e.g., const char * in the case of a string), + the pointer is only borrowed and the contents must be copied if they are + to be used after the end of the messages lifetime. Similarly, during the + lifetime of such a pointer, the message must not be modified. + + + + If there is no object of the specified type at the current position in the + message, an error is returned. + + + + + Return Value + + + On success, sd_bus_message_read_basic() returns 0 or + a positive integer. On failure, it returns a negative errno-style error + code. + + + + + See Also + + + systemd1, + sd-bus3, + + + + diff --git a/man/sd_bus_process.xml b/man/sd_bus_process.xml new file mode 100644 index 0000000000..4b9f52e52f --- /dev/null +++ b/man/sd_bus_process.xml @@ -0,0 +1,111 @@ + + + + + + + + + sd_bus_process + systemd + + + + Julian + Orth + ju.orth@gmail.com + + + + + + sd_bus_process + 3 + + + + sd_bus_process + + Drive the connection + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_process + sd_bus *bus + sd_bus_message **r + + + + + + Description + + + sd_bus_process() drives the connection between the + message bus and the client. That is, it handles connecting, + authentication, and message processing. It should be called in a loop + until no further progress can be made or an error occurs. + + + + Once no further progress can be made, + sd_bus_wait3 + should be called. Alternatively the user can wait for incoming data on + the file descriptor returned by + sd_bus_get_fd3. + + + + sd_bus_process processes at most one incoming + message per call. If the parameter r is not NULL + and the call processed a message, *r is set to this message. + The caller owns a reference to this message and should call + sd_bus_message_unref3 + when the message is no longer needed. If r is not + NULL, progress was made, but no message was processed, *r is + set to NULL. + + + + + Return Value + + + If progress was made, a positive integer is returned. If no progress was + made, 0 is returned. If an error occurs, a negative errno-style error code + is returned. + + + + + See Also + + + systemd1, + sd-bus3, + + + + -- cgit v1.2.3-54-g00ecf From 2787d83c28b7565ea6f80737170514e5e6186917 Mon Sep 17 00:00:00 2001 From: Minkyung Date: Wed, 22 Jun 2016 20:26:05 +0900 Subject: watchdog: Support changing watchdog_usec during runtime (#3492) Add sd_notify() parameter to change watchdog_usec during runtime. Application can change watchdog_usec value by sd_notify like this. Example. sd_notify(0, "WATCHDOG_USEC=20000000"). To reset watchdog_usec as configured value in service file, restart service. Notice. sd_event is not currently supported. If application uses sd_event_set_watchdog, or sd_watchdog_enabled, do not use "WATCHDOG_USEC" option through sd_notify. --- man/sd_notify.xml | 9 ++++++++ src/core/service.c | 56 +++++++++++++++++++++++++++++++++++++++++++++---- src/core/service.h | 2 ++ src/systemd/sd-daemon.h | 5 +++++ 4 files changed, 68 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/sd_notify.xml b/man/sd_notify.xml index bd6cfdcd29..025fbec6c1 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -250,6 +250,15 @@ restrictions, it is ignored. + + WATCHDOG_USEC=... + + Reset watchdog_usec value during runtime. + Notice that this is not available when using sd_event_set_watchdog() + or sd_watchdog_enabled(). + Example : WATCHDOG_USEC=20000000 + + It is recommended to prefix variable names that are not diff --git a/src/core/service.c b/src/core/service.c index 78c33b1530..13de671700 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -200,16 +200,27 @@ static void service_stop_watchdog(Service *s) { s->watchdog_timestamp = DUAL_TIMESTAMP_NULL; } +static usec_t service_get_watchdog_usec(Service *s) { + assert(s); + + if (s->watchdog_override_enable) + return s->watchdog_override_usec; + else + return s->watchdog_usec; +} + static void service_start_watchdog(Service *s) { int r; + usec_t watchdog_usec; assert(s); - if (s->watchdog_usec <= 0) + watchdog_usec = service_get_watchdog_usec(s); + if (watchdog_usec == 0 || watchdog_usec == USEC_INFINITY) return; if (s->watchdog_event_source) { - r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec)); + r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, watchdog_usec)); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m"); return; @@ -221,7 +232,7 @@ static void service_start_watchdog(Service *s) { UNIT(s)->manager->event, &s->watchdog_event_source, CLOCK_MONOTONIC, - usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec), 0, + usec_add(s->watchdog_timestamp.monotonic, watchdog_usec), 0, service_dispatch_watchdog, s); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m"); @@ -246,6 +257,17 @@ static void service_reset_watchdog(Service *s) { service_start_watchdog(s); } +static void service_reset_watchdog_timeout(Service *s, usec_t watchdog_override_usec) { + assert(s); + + s->watchdog_override_enable = true; + s->watchdog_override_usec = watchdog_override_usec; + service_reset_watchdog(s); + + log_unit_debug(UNIT(s), "watchdog_usec="USEC_FMT, s->watchdog_usec); + log_unit_debug(UNIT(s), "watchdog_override_usec="USEC_FMT, s->watchdog_override_usec); +} + static void service_fd_store_unlink(ServiceFDStore *fs) { if (!fs) @@ -1992,6 +2014,9 @@ static int service_start(Unit *u) { s->notify_state = NOTIFY_UNKNOWN; + s->watchdog_override_enable = false; + s->watchdog_override_usec = 0; + service_enter_start_pre(s); return 1; } @@ -2123,6 +2148,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); + if (s->watchdog_override_enable) + unit_serialize_item_format(u, f, "watchdog-override-usec", USEC_FMT, s->watchdog_override_usec); + return 0; } @@ -2317,6 +2345,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, s->stderr_fd = fdset_remove(fds, fd); s->exec_context.stdio_as_fds = true; } + } else if (streq(key, "watchdog-override-usec")) { + usec_t watchdog_override_usec; + if (timestamp_deserialize(value, &watchdog_override_usec) < 0) + log_unit_debug(u, "Failed to parse watchdog_override_usec value: %s", value); + else { + s->watchdog_override_enable = true; + s->watchdog_override_usec = watchdog_override_usec; + } } else log_unit_debug(u, "Unknown serialization key: %s", key); @@ -2895,12 +2931,15 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) { Service *s = SERVICE(userdata); char t[FORMAT_TIMESPAN_MAX]; + usec_t watchdog_usec; assert(s); assert(source == s->watchdog_event_source); + watchdog_usec = service_get_watchdog_usec(s); + log_unit_error(UNIT(s), "Watchdog timeout (limit %s)!", - format_timespan(t, sizeof(t), s->watchdog_usec, 1)); + format_timespan(t, sizeof(t), watchdog_usec, 1)); service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG); @@ -3037,6 +3076,15 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) service_add_fd_store_set(s, fds, name); } + e = strv_find_startswith(tags, "WATCHDOG_USEC="); + if (e) { + usec_t watchdog_override_usec; + if (safe_atou64(e, &watchdog_override_usec) < 0) + log_unit_warning(u, "Failed to parse WATCHDOG_USEC=%s", e); + else + service_reset_watchdog_timeout(s, watchdog_override_usec); + } + /* Notify clients about changed status or main pid */ if (notify_dbus) unit_add_to_dbus_queue(u); diff --git a/src/core/service.h b/src/core/service.h index 4af3d40439..cfef375b03 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -120,6 +120,8 @@ struct Service { dual_timestamp watchdog_timestamp; usec_t watchdog_usec; + usec_t watchdog_override_usec; + bool watchdog_override_enable; sd_event_source *watchdog_event_source; ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX]; diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h index e6787b0a64..740b176903 100644 --- a/src/systemd/sd-daemon.h +++ b/src/systemd/sd-daemon.h @@ -196,6 +196,11 @@ int sd_is_mq(int fd, const char *path); invocation. This variable is only supported with sd_pid_notify_with_fds(). + WATCHDOG_USEC=... + Reset watchdog_usec value during runtime. + To reset watchdog_usec value, start the service again. + Example: "WATCHDOG_USEC=20000000" + Daemons can choose to send additional variables. However, it is recommended to prefix variable names not listed above with X_. -- cgit v1.2.3-54-g00ecf From d1562103fbdf3ab34cbef747390de85bb411d9f8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jun 2016 23:28:12 +0200 Subject: man: document that %f in units always unescapes (#3578) --- man/systemd.unit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'man') diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 341789cd47..85a7b12d76 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1234,7 +1234,7 @@ %f Unescaped filename - This is either the unescaped instance name (if applicable) with / prepended (if applicable), or the prefix name prepended with /. + This is either the unescaped instance name (if applicable) with / prepended (if applicable), or the unescaped prefix name prepended with /. %c -- cgit v1.2.3-54-g00ecf From b09c0bbad831a11e2200a6ebb48908a10ce29305 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 22 Jun 2016 23:30:36 +0200 Subject: nspawn: improve man page (#3577) This change documents the existance of the systemd-nspawn@.service template unit file, which was previously not mentioned at all. Since the unit file uses slightly different default than nspawn invoked from the command line, these defaults are now explicitly documented too. A couple of further additions and changes are made, too. Replaces: #3497 --- man/systemd-nspawn.xml | 155 ++++++++++++++++++++++++++++--------------------- man/systemd.nspawn.xml | 18 +++--- 2 files changed, 99 insertions(+), 74 deletions(-) (limited to 'man') diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 08122795f4..c436f42948 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -67,69 +67,82 @@ Description - systemd-nspawn may be used to run a - command or OS in a light-weight namespace container. In many ways - it is similar to - chroot1, - but more powerful since it fully virtualizes the file system - hierarchy, as well as the process tree, the various IPC subsystems - and the host and domain name. - - systemd-nspawn limits access to various - kernel interfaces in the container to read-only, such as - /sys, /proc/sys or - /sys/fs/selinux. Network interfaces and the - system clock may not be changed from within the container. Device - nodes may not be created. The host system cannot be rebooted and - kernel modules may not be loaded from within the container. - - Note that even though these security precautions are taken - systemd-nspawn is not suitable for fully secure - container setups. Many of the security features may be - circumvented and are hence primarily useful to avoid accidental - changes to the host system from the container. - - In contrast to - chroot1 systemd-nspawn - may be used to boot full Linux-based operating systems in a + systemd-nspawn may be used to run a command or OS in a light-weight namespace + container. In many ways it is similar to chroot1, but more powerful + since it fully virtualizes the file system hierarchy, as well as the process tree, the various IPC subsystems and + the host and domain name. + + Like chroot1 the + systemd-nspawn command may be invoked on any directory tree containing an operating system tree, + using the command line option. By using the option an OS + tree is automatically searched in a couple of locations, most importantly in + /var/lib/machines, the suggested directory to place container images installed on the + system. + + In contrast to chroot1 systemd-nspawn + may be used to boot full Linux-based operating systems in a container. + + systemd-nspawn limits access to various kernel interfaces in the container to read-only, + such as /sys, /proc/sys or /sys/fs/selinux. The + host's network interfaces and the system clock may not be changed from within the container. Device nodes may not + be created. The host system cannot be rebooted and kernel modules may not be loaded from within the container. - Use a tool like - dnf8, - debootstrap8, - or - pacman8 - to set up an OS directory tree suitable as file system hierarchy - for systemd-nspawn containers. - - Note that systemd-nspawn will mount file - systems private to the container to /dev, - /run and similar. These will not be visible - outside of the container, and their contents will be lost when the - container exits. - - Note that running two systemd-nspawn - containers from the same directory tree will not make processes in - them see each other. The PID namespace separation of the two - containers is complete and the containers will share very few - runtime objects except for the underlying file system. Use - machinectl1's - login command to request an additional login - prompt in a running container. - - systemd-nspawn implements the - Container - Interface specification. - - As a safety check systemd-nspawn will - verify the existence of /usr/lib/os-release - or /etc/os-release in the container tree - before starting the container (see - os-release5). - It might be necessary to add this file to the container tree - manually if the OS of the container is too old to contain this + Use a tool like dnf8, debootstrap8, or + pacman8 to + set up an OS directory tree suitable as file system hierarchy for systemd-nspawn containers. See + the Examples section below for details on suitable invocation of these commands. + + As a safety check systemd-nspawn will verify the existence of + /usr/lib/os-release or /etc/os-release in the container tree before + starting the container (see + os-release5). It might be + necessary to add this file to the container tree manually if the OS of the container is too old to contain this file out-of-the-box. + + systemd-nspawn may be invoked directly from the interactive command line or run as system + service in the background. In this mode each container instance runs as its own service instance; a default + template unit file systemd-nspawn@.service is provided to make this easy, taking the container + name as instance identifier. Note that different default options apply when systemd-nspawn is + invoked by the template unit file than interactively on the commnd line. Most importanly the template unit file + makes use of the which is not the default in case systemd-nspawn is + invoked from the interactive command line. Further differences with the defaults are documented dalong with the + various supported options below. + + The machinectl1 tool may + be used to execute a number of operations on containers. In particular it provides easy-to-use commands to run + containers as system services using the systemd-nspawn@.service template unit + file. + + Along with each container a settings file with the .nspawn suffix may exist, containing + additional settings to apply when running the container. See + systemd.nspawn5 for + details. Settings files override the default options used by the systemd-nspawn@.service + template unit file, making it usually unnecessary to alter this template file directly. + + Note that systemd-nspawn will mount file systems private to the container to + /dev, /run and similar. These will not be visible outside of the + container, and their contents will be lost when the container exits. + + Note that running two systemd-nspawn containers from the same directory tree will not make + processes in them see each other. The PID namespace separation of the two containers is complete and the containers + will share very few runtime objects except for the underlying file system. Use + machinectl1's + login or shell commands to request an additional login session in a running + container. + + systemd-nspawn implements the Container Interface + specification. + + While running, containers invoked with systemd-nspawn are registered with the + systemd-machined8 service that + keeps track of running containers, and provides programming interfaces to interact with them. @@ -139,7 +152,7 @@ are used as arguments for the init binary. Otherwise, COMMAND specifies the program to launch in the container, and the remaining arguments are used as - arguments for this program. If is not used and + arguments for this program. If is not used and no arguments are specified, a shell is launched in the container. @@ -310,6 +323,9 @@ + + Note that is the default mode of operation if the + systemd-nspawn@.service template unit file is used. @@ -446,7 +462,10 @@ If the kernel supports the user namespaces feature, equivalent to , otherwise equivalent to - . + . + + Note that is the default if the systemd-nspawn@.service template unit + file is used. @@ -540,6 +559,9 @@ assignment via DHCP. In case systemd-networkd is running on both the host and inside the container, automatic IP communication from the container to the host is thus available, with further connectivity to the external network. + + Note that is the default if the + systemd-nspawn@.service template unit file is used. @@ -705,7 +727,10 @@ Effectively, booting a container once with guest or host will link the journal persistently if further on the default of - auto is used. + auto is used. + + Note that is the default if the + systemd-nspawn@.service template unit file is used. @@ -981,10 +1006,10 @@ - --notify-ready= + Configures support for notifications from the container's init process. - --notify-ready= takes a boolean ( and ). + takes a boolean ( and ). With option systemd-nspawn notifies systemd with a READY=1 message when the init process is created. With option systemd-nspawn waits for the diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 6df4aeb2a9..b1344d6c10 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -146,7 +146,8 @@ specified parameters using Parameters= are passed as additional arguments to the init process. This setting corresponds to the switch on the systemd-nspawn command line. This option may not be combined with - ProcessTwo=yes. + ProcessTwo=yes. This option is the default if the + systemd-nspawn@.service template unit file is used. @@ -257,7 +258,8 @@ Configures support for usernamespacing. This is equivalent to the command line switch, and takes the same options. This option is privileged - (see above). + (see above). This option is the default if the systemd-nspawn@.service template unit file + is used. @@ -367,13 +369,11 @@ VirtualEthernet= - Takes a boolean argument. Configures whether - to create a virtual Ethernet connection - (veth) between host and the container. This - setting implies Private=yes. This setting - corresponds to the command - line switch. This option is privileged (see - above). + Takes a boolean argument. Configures whether to create a virtual Ethernet connection + (veth) between host and the container. This setting implies + Private=yes. This setting corresponds to the command line + switch. This option is privileged (see above). This option is the default if the + systemd-nspawn@.service template unit file is used. -- cgit v1.2.3-54-g00ecf From f4170c671b863a211056972a469abd416086f22c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Jun 2016 01:45:45 +0200 Subject: execute: add a new easy-to-use RestrictRealtime= option to units It takes a boolean value. If true, access to SCHED_RR, SCHED_FIFO and SCHED_DEADLINE is blocked, which my be used to lock up the system. --- man/systemd.exec.xml | 13 +++++ src/core/dbus-execute.c | 5 +- src/core/execute.c | 95 +++++++++++++++++++++++++++++++++-- src/core/execute.h | 4 +- src/core/load-fragment-gperf.gperf.m4 | 2 + 5 files changed, 114 insertions(+), 5 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index dbfc7692f7..ed02666daf 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -1413,6 +1413,19 @@ + + RestrictRealtime= + + Takes a boolean argument. If set, any attempts to enable realtime scheduling in a process of + the unit are refused. This restricts access to realtime task scheduling policies such as + SCHED_FIFO, SCHED_RR or SCHED_DEADLINE. See + sched7 for details about + these scheduling policies. Realtime scheduling policies may be used to monopolize CPU time for longer periods + of time, and may hence be used to lock up or otherwise trigger Denial-of-Service situations on the system. It + is hence recommended to restrict access to realtime scheduling to the few programs that actually require + them. Defaults to off. + + diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 4c88c41127..644b9561b5 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -720,6 +720,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; @@ -1057,7 +1058,7 @@ int bus_exec_context_set_transient_property( } else if (STR_IN_SET(name, "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "PrivateTmp", "PrivateDevices", "PrivateNetwork", - "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute")) { + "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime")) { int b; r = sd_bus_message_read(message, "b", &b); @@ -1083,6 +1084,8 @@ int bus_exec_context_set_transient_property( c->syslog_level_prefix = b; else if (streq(name, "MemoryDenyWriteExecute")) c->memory_deny_write_execute = b; + else if (streq(name, "RestrictRealtime")) + c->restrict_realtime = b; unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b)); } diff --git a/src/core/execute.c b/src/core/execute.c index cf52355fc4..8cb18dbd5b 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1264,6 +1264,76 @@ finish: return r; } +static int apply_restrict_realtime(const ExecContext *c) { + static const int permitted_policies[] = { + SCHED_OTHER, + SCHED_BATCH, + SCHED_IDLE, + }; + + scmp_filter_ctx *seccomp; + unsigned i; + int r, p, max_policy = 0; + + assert(c); + + seccomp = seccomp_init(SCMP_ACT_ALLOW); + if (!seccomp) + return -ENOMEM; + + /* Determine the highest policy constant we want to allow */ + for (i = 0; i < ELEMENTSOF(permitted_policies); i++) + if (permitted_policies[i] > max_policy) + max_policy = permitted_policies[i]; + + /* Go through all policies with lower values than that, and block them -- unless they appear in the + * whitelist. */ + for (p = 0; p < max_policy; p++) { + bool good = false; + + /* Check if this is in the whitelist. */ + for (i = 0; i < ELEMENTSOF(permitted_policies); i++) + if (permitted_policies[i] == p) { + good = true; + break; + } + + if (good) + continue; + + /* Deny this policy */ + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPERM), + SCMP_SYS(sched_setscheduler), + 1, + SCMP_A1(SCMP_CMP_EQ, p)); + if (r < 0) + goto finish; + } + + /* Blacklist all other policies, i.e. the ones with higher values. Note that all comparisons are unsigned here, + * hence no need no check for < 0 values. */ + r = seccomp_rule_add( + seccomp, + SCMP_ACT_ERRNO(EPERM), + SCMP_SYS(sched_setscheduler), + 1, + SCMP_A1(SCMP_CMP_GT, max_policy)); + if (r < 0) + goto finish; + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; + + r = seccomp_load(seccomp); + +finish: + seccomp_release(seccomp); + return r; +} + #endif static void do_idle_pipe_dance(int idle_pipe[4]) { @@ -1962,6 +2032,14 @@ static int exec_child( } } + /* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */ + if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO]) { + if (setrlimit(RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)) < 0) { + *exit_status = EXIT_LIMITS; + return -errno; + } + } + if (!cap_test_all(context->capability_bounding_set)) { r = capability_bounding_set_drop(context->capability_bounding_set, false); if (r < 0) { @@ -2017,7 +2095,7 @@ static int exec_child( } if (context->no_new_privileges || - (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || context->memory_deny_write_execute || use_syscall_filter))) + (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || context->memory_deny_write_execute || context->restrict_realtime || use_syscall_filter))) if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) { *exit_status = EXIT_NO_NEW_PRIVILEGES; return -errno; @@ -2039,6 +2117,15 @@ static int exec_child( return r; } } + + if (context->restrict_realtime) { + r = apply_restrict_realtime(context); + if (r < 0) { + *exit_status = EXIT_SECCOMP; + return r; + } + } + if (use_syscall_filter) { r = apply_seccomp(context); if (r < 0) { @@ -2474,7 +2561,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { "%sProtectHome: %s\n" "%sProtectSystem: %s\n" "%sIgnoreSIGPIPE: %s\n" - "%sMemoryDenyWriteExecute: %s\n", + "%sMemoryDenyWriteExecute: %s\n" + "%sRestrictRealtime: %s\n", prefix, c->umask, prefix, c->working_directory ? c->working_directory : "/", prefix, c->root_directory ? c->root_directory : "/", @@ -2485,7 +2573,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, protect_home_to_string(c->protect_home), prefix, protect_system_to_string(c->protect_system), prefix, yes_no(c->ignore_sigpipe), - prefix, yes_no(c->memory_deny_write_execute)); + prefix, yes_no(c->memory_deny_write_execute), + prefix, yes_no(c->restrict_realtime)); STRV_FOREACH(e, c->environment) fprintf(f, "%sEnvironment: %s\n", prefix, *e); diff --git a/src/core/execute.h b/src/core/execute.h index cd1f7b36f6..210eea0e82 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -193,12 +193,14 @@ struct ExecContext { char **runtime_directory; mode_t runtime_directory_mode; + bool memory_deny_write_execute; + bool restrict_realtime; + bool oom_score_adjust_set:1; bool nice_set:1; bool ioprio_set:1; bool cpu_sched_set:1; bool no_new_privileges_set:1; - bool memory_deny_write_execute; }; #include "cgroup-util.h" diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index eb58586523..fe1006830b 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -56,11 +56,13 @@ m4_ifdef(`HAVE_SECCOMP', $1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs) $1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context) $1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute) +$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime) $1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)', `$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 +$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) $1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) -- cgit v1.2.3-54-g00ecf From ceeddf79b8464469a5307a1030862c7c4fe289e9 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Fri, 24 Jun 2016 07:54:28 +0200 Subject: resolved: add option to disable caching (#3592) In some cases, caching DNS results locally is not desirable, a it makes DNS cache poisoning attacks a tad easier and also allows users on the system to determine whether or not a particular domain got visited by another user. Thus provide a new "Cache" resolved.conf option to disable it. --- NEWS | 8 ++++++++ man/resolved.conf.xml | 17 +++++++++++++++++ src/resolve/resolved-dns-transaction.c | 4 ++++ src/resolve/resolved-gperf.gperf | 1 + src/resolve/resolved-manager.c | 1 + src/resolve/resolved-manager.h | 1 + src/resolve/resolved.conf.in | 1 + 7 files changed, 33 insertions(+) (limited to 'man') diff --git a/NEWS b/NEWS index 7ecb10e216..e4efb476c6 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,14 @@ CHANGES WITH 231: "Options=" with a drop-in, or mount /tmp from /etc/fstab with your desired options. + * systemd-resolved gained a new "Cache=" option in resolved.conf. + Local caching makes DNS poisoning attacks slightly easier and allows + a local user to detect whether any other user on the same machine has + recently visited a given DNS name (privacy). If that is a concern, + you can disable local caching with this option at the cost of slower + DNS resolution (which is particularly expensive with DNSSEC). The + default continues to be "yes" (i. e. caching is enabled). + Contributions from: ... — Somewhere, 2016-XX-XX diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 920ce9e89b..024ad6a9c1 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -202,6 +202,23 @@ + + Cache= + Takes a boolean argument. If "yes" (the default), + resolving a domain name which already got queried earlier will re-use + the previous result as long as that is still valid, and thus does not + need to do an actual network request. + + However, local caching slightly increases the chance of a + successful DNS poisoning attack, and might also be a privacy problem in + some environments: By measuring the time it takes to resolve a + particular network name, a user can determine whether any other user on + the same machine recently visited that name. If either of these is a + concern, you may disable the local caching. Be aware that this comes at + a performance cost, which is very high with DNSSEC. + + + diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 09f60d3e76..06e7145422 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -590,6 +590,10 @@ static void dns_transaction_cache_answer(DnsTransaction *t) { if (!IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR)) return; + /* Caching disabled? */ + if (!t->scope->manager->enable_cache) + return; + /* We never cache if this packet is from the local host, under * the assumption that a locally running DNS server would * cache this anyway, and probably knows better when to flush diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index 82f26215df..2fd56bce26 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -19,3 +19,4 @@ Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0 Resolve.Domains, config_parse_search_domains, 0, 0 Resolve.LLMNR, config_parse_resolve_support, 0, offsetof(Manager, llmnr_support) Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode) +Resolve.Cache, config_parse_bool, 0, offsetof(Manager, enable_cache) diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 30036049da..add463b6a9 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -500,6 +500,7 @@ int manager_new(Manager **ret) { m->llmnr_support = RESOLVE_SUPPORT_YES; m->mdns_support = RESOLVE_SUPPORT_NO; m->dnssec_mode = DEFAULT_DNSSEC_MODE; + m->enable_cache = true; m->read_resolv_conf = true; m->need_builtin_fallbacks = true; m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 114fec7927..deebd8e484 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -46,6 +46,7 @@ struct Manager { ResolveSupport llmnr_support; ResolveSupport mdns_support; DnssecMode dnssec_mode; + bool enable_cache; /* Network */ Hashmap *links; diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index a288588924..3bd8389c88 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -17,3 +17,4 @@ #Domains= #LLMNR=yes #DNSSEC=@DEFAULT_DNSSEC_MODE@ +#Cache=yes -- cgit v1.2.3-54-g00ecf From 39c38ce17c3a15f7b709536a6d7f1f7e093ac450 Mon Sep 17 00:00:00 2001 From: Doug Christman Date: Fri, 24 Jun 2016 02:00:35 -0400 Subject: systemctl: Create new unit files with "edit --force" (#3584) --- TODO | 4 +--- man/systemctl.xml | 6 ++++++ src/systemctl/systemctl.c | 38 +++++++++++++++++++++++--------------- 3 files changed, 30 insertions(+), 18 deletions(-) (limited to 'man') diff --git a/TODO b/TODO index 8de1029b9b..0d18e0734b 100644 --- a/TODO +++ b/TODO @@ -197,9 +197,7 @@ Features: * systemctl: if some operation fails, show log output? -* systemctl edit: -- allow creation of units from scratch -- use equvalent of cat() to insert existing config as a comment, prepended with #. +* systemctl edit: use equvalent of cat() to insert existing config as a comment, prepended with #. Upon editor exit, lines with one # are removed, lines with two # are left with one #, etc. * exponential backoff in timesyncd when we cannot reach a server diff --git a/man/systemctl.xml b/man/systemctl.xml index 914af929c8..742da81cfe 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -481,6 +481,9 @@ When used with enable, overwrite any existing conflicting symlinks. + When used with edit, create all of the + specified units which do not already exist. + When used with halt, poweroff, reboot or kexec, execute the selected operation without shutting down all units. However, all processes will be killed forcibly and all file systems are unmounted or remounted read-only. This is hence a @@ -1303,6 +1306,9 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service If is specified, this will copy the original units instead of creating drop-in files. + If is specified and any units do + not already exist, new unit files will be opened for editing. + If is specified, the changes will be made temporarily in /run and they will be lost on the next reboot. diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 38b5a7e082..0a8e60c195 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2499,7 +2499,7 @@ static int unit_find_paths( r = 1; } - if (r == 0) + if (r == 0 && !arg_force) log_error("No files found for %s.", unit_name); return r; @@ -6070,7 +6070,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t); } else if (r < 0) - return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t); + return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path); *ret_tmp_fn = t; t = NULL; @@ -6114,9 +6114,10 @@ static int get_file_to_edit( return 0; } -static int unit_file_create_dropin( +static int unit_file_create_new( const LookupPaths *paths, const char *unit_name, + const char *suffix, char **ret_new_path, char **ret_tmp_path) { @@ -6127,7 +6128,7 @@ static int unit_file_create_dropin( assert(ret_new_path); assert(ret_tmp_path); - ending = strjoina(unit_name, ".d/override.conf"); + ending = strjoina(unit_name, suffix); r = get_file_to_edit(paths, ending, &tmp_new_path); if (r < 0) return r; @@ -6180,7 +6181,6 @@ static int unit_file_create_copy( r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path); if (r < 0) { - log_error_errno(r, "Failed to create temporary file for \"%s\": %m", tmp_new_path); free(tmp_new_path); return r; } @@ -6291,18 +6291,26 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { r = unit_find_paths(bus, *name, &lp, &path, NULL); if (r < 0) return r; - else if (r == 0) - return -ENOENT; - else if (!path) { - // FIXME: support units with path==NULL (no FragmentPath) - log_error("No fragment exists for %s.", *name); - return -ENOENT; + else if (!arg_force) { + if (r == 0) { + log_error("Run 'systemctl edit --force %s' to create a new unit.", *name); + return -ENOENT; + } else if (!path) { + // FIXME: support units with path==NULL (no FragmentPath) + log_error("No fragment exists for %s.", *name); + return -ENOENT; + } + } + + if (path) { + if (arg_full) + r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path); + else + r = unit_file_create_new(&lp, *name, ".d/override.conf", &new_path, &tmp_path); + } else { + r = unit_file_create_new(&lp, *name, NULL, &new_path, &tmp_path); } - if (arg_full) - r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path); - else - r = unit_file_create_dropin(&lp, *name, &new_path, &tmp_path); if (r < 0) return r; -- cgit v1.2.3-54-g00ecf From cdfe156acdf159341cf7771b019f1aa08a19acac Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 26 Jun 2016 17:35:22 +0200 Subject: man: document what Authenticated: in the systemd-resolve output actually means (#3571) My educated guess is that #3561 was filed due to confusion around the systemd-resolve "Data Authenticated:" output. Let's try to clean up the confusion a bit, and document what it means in the man page. --- man/systemd-resolve.xml | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'man') diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml index b7fbee3154..ca26bb4d49 100644 --- a/man/systemd-resolve.xml +++ b/man/systemd-resolve.xml @@ -114,6 +114,12 @@ and IPv6 addresses. If the parameters specified are formatted as IPv4 or IPv6 operation the reverse operation is done, and a hostname is retrieved for the specified addresses. + The program's output contains information about the protocol used for the look-up and on which network + interface the data was discovered. It also contains information on whether the information could be + authenticated. All data for which local DNSSEC validation succeeds is considered authenticated. Moreover all data + originating from local, trusted sources is also reported authenticated, including resolution of the local host + name, the localhost host name or all data from /etc/hosts. + The switch may be used to specify a DNS resource record type (A, AAAA, SOA, MX, ...) in order to request a specific DNS resource record, instead of the address or reverse address lookups. The special value help may be used to list known values. -- cgit v1.2.3-54-g00ecf From aa4f6cf12c474aa2c6535e4b2c434ea39c9d568c Mon Sep 17 00:00:00 2001 From: Luca Bruno Date: Tue, 28 Jun 2016 20:14:08 +0200 Subject: man: clarify NotifyAccess overriding (#3620) Type=notify has a magic overriding case where a NotifyAccess=none is turned into a NotifyAccess=main for sanity purposes. This makes docs more clear about such behavior: https://github.com/systemd/systemd/blob/2787d83c28b7565ea6f80737170514e5e6186917/src/core/service.c#L650:L651 --- man/systemd.service.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'man') diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 6e969abc25..70f12b2d32 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -202,8 +202,9 @@ notification message has been sent. If this option is used, NotifyAccess= (see below) should be set to open access to the notification socket provided by systemd. If - NotifyAccess= is not set, it will be - implicitly set to . Note that currently + NotifyAccess= is missing or set to + , it will be forcibly set to + . Note that currently Type= will not work if used in combination with PrivateNetwork=. -- cgit v1.2.3-54-g00ecf From 60a3b1e11ab0cef0f1e690a7c7117866113cf540 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Jun 2016 12:25:07 -0700 Subject: sd-event: expose the event loop iteration counter via sd_event_get_iteration() (#3631) This extends the existing event loop iteration counter to 64bit, and exposes it via a new function sd_event_get_iteration(). This is helpful for cases like issue #3612. After all, since we maintain the counter anyway, we might as well expose it. (This also fixes an unrelated issue in the man page for sd_event_wait() where micro and milliseconds got mixed up) --- Makefile-man.am | 5 +++++ man/sd_event_wait.xml | 22 ++++++++++++++++------ src/libsystemd/libsystemd.sym | 5 +++++ src/libsystemd/sd-event/sd-event.c | 14 +++++++++++--- src/systemd/sd-event.h | 1 + 5 files changed, 38 insertions(+), 9 deletions(-) (limited to 'man') diff --git a/Makefile-man.am b/Makefile-man.am index cd7583bed7..8ab733360d 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -338,6 +338,7 @@ MANPAGES_ALIAS += \ man/sd_event_default.3 \ man/sd_event_dispatch.3 \ man/sd_event_get_exit_code.3 \ + man/sd_event_get_iteration.3 \ man/sd_event_get_state.3 \ man/sd_event_get_tid.3 \ man/sd_event_get_watchdog.3 \ @@ -669,6 +670,7 @@ man/sd_event_child_handler_t.3: man/sd_event_add_child.3 man/sd_event_default.3: man/sd_event_new.3 man/sd_event_dispatch.3: man/sd_event_wait.3 man/sd_event_get_exit_code.3: man/sd_event_exit.3 +man/sd_event_get_iteration.3: man/sd_event_wait.3 man/sd_event_get_state.3: man/sd_event_wait.3 man/sd_event_get_tid.3: man/sd_event_new.3 man/sd_event_get_watchdog.3: man/sd_event_set_watchdog.3 @@ -1318,6 +1320,9 @@ man/sd_event_dispatch.html: man/sd_event_wait.html man/sd_event_get_exit_code.html: man/sd_event_exit.html $(html-alias) +man/sd_event_get_iteration.html: man/sd_event_wait.html + $(html-alias) + man/sd_event_get_state.html: man/sd_event_wait.html $(html-alias) diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml index f2aea00e98..26327dc688 100644 --- a/man/sd_event_wait.xml +++ b/man/sd_event_wait.xml @@ -47,6 +47,7 @@ sd_event_prepare sd_event_dispatch sd_event_get_state + sd_event_get_iteration SD_EVENT_INITIAL SD_EVENT_PREPARING SD_EVENT_ARMED @@ -93,6 +94,12 @@ sd_event *event + + int sd_event_get_iteration + sd_event *event + uint64_t *ret + + @@ -140,12 +147,15 @@ determine the state the event loop is currently in. It returns one of the states described below. - All four functions take, as the first argument, the event - loop object event that has been created - with sd_event_new(). The timeout for - sd_event_wait() is specified in - usec in milliseconds. (uint64_t) - -1 may be used to specify an infinite timeout. + sd_event_get_iteration() may be used to determine the current iteration of the event + loop. It returns an unsigned 64bit integer containing a counter that increases monotonically with each iteration of + the event loop, starting with 0. The counter is increased at the time of the + sd_event_prepare() invocation. + + All five functions take, as the first argument, the event loop object event that has + been created with sd_event_new(). The timeout for sd_event_wait() is + specified in usec in microseconds. (uint64_t) -1 may be used to + specify an infinite timeout. diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 0b3a1708dc..542254295c 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -495,3 +495,8 @@ global: sd_journal_open_directory_fd; sd_journal_open_files_fd; } LIBSYSTEMD_229; + +LIBSYSTEMD_231 { +global: + sd_event_get_iteration; +} LIBSYSTEMD_230; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index f364b54b50..9857f8b1fc 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -109,8 +109,8 @@ struct sd_event_source { int64_t priority; unsigned pending_index; unsigned prepare_index; - unsigned pending_iteration; - unsigned prepare_iteration; + uint64_t pending_iteration; + uint64_t prepare_iteration; LIST_FIELDS(sd_event_source, sources); @@ -215,7 +215,7 @@ struct sd_event { pid_t original_pid; - unsigned iteration; + uint64_t iteration; triple_timestamp timestamp; int state; @@ -2874,3 +2874,11 @@ _public_ int sd_event_get_watchdog(sd_event *e) { return e->watchdog; } + +_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + *ret = e->iteration; + return 0; +} diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 531ace1c34..cc26b7df55 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -104,6 +104,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid); int sd_event_get_exit_code(sd_event *e, int *code); int sd_event_set_watchdog(sd_event *e, int b); int sd_event_get_watchdog(sd_event *e); +int sd_event_get_iteration(sd_event *e, uint64_t *ret); sd_event_source* sd_event_source_ref(sd_event_source *s); sd_event_source* sd_event_source_unref(sd_event_source *s); -- cgit v1.2.3-54-g00ecf From 17c22746b176f2e544d33bdaf30b282ce2c88933 Mon Sep 17 00:00:00 2001 From: Lukas Lösche Date: Thu, 30 Jun 2016 21:25:51 +0200 Subject: man: minor typo "has already has happened" (#3635) --- man/journalctl.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'man') diff --git a/man/journalctl.xml b/man/journalctl.xml index 3efe6ef62a..29239c6315 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -824,7 +824,7 @@ flushed from /run/log/journal into /var/log/journal once during system runtime, and this command exits cleanly without executing any - operation if this has already has happened. This command + operation if this has already happened. This command effectively guarantees that all data is flushed to /var/log/journal at the time it returns. -- cgit v1.2.3-54-g00ecf From 32b5236916296044a89532025e9fb5ef7e68ca8a Mon Sep 17 00:00:00 2001 From: Douglas Christman Date: Thu, 30 Jun 2016 20:16:05 -0400 Subject: calendarspec: allow ranges in date and time specifications Resolves #3042 --- TODO | 1 - man/systemd.time.xml | 5 +++- src/basic/calendarspec.c | 64 +++++++++++++++++++++++++++++++------------- src/test/test-calendarspec.c | 5 ++++ 4 files changed, 54 insertions(+), 21 deletions(-) (limited to 'man') diff --git a/TODO b/TODO index 3af3126453..5208bdb818 100644 --- a/TODO +++ b/TODO @@ -565,7 +565,6 @@ Features: o CLOCK_REALTIME makes jumps (TFD_TIMER_CANCEL_ON_SET) o DST changes - Support 2012-02~4 as syntax for specifying the fourth to last day of the month. - - calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1 - Modulate timer frequency based on battery state * add libsystemd-password or so to query passwords during boot using the password agent logic diff --git a/man/systemd.time.xml b/man/systemd.time.xml index ffcac82263..6f9e88406d 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -227,7 +227,8 @@ values separated by commas. Values may also be suffixed with / and a repetition value, which indicates that the value and all values plus multiples of the repetition value - are matched. + are matched. Each component may also contain a range of values + separated by ... The seconds component may contain decimal fractions both in the value and the repetition. All fractions are rounded to 6 @@ -273,6 +274,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 monday *-12-* 17:00 → Mon *-12-* 17:00:00 Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45 12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00 + 12..14:10,20,30 → *-*-* 12,13,14:10,20,30:00 mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45 03-05 08:05:40 → *-03-05 08:05:40 08:05:40 → *-*-* 08:05:40 @@ -281,6 +283,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40 2003-03-05 05:40 → 2003-03-05 05:40:00 05:40:23.4200004/3.1700005 → 05:40:23.420000/3.170001 + 2003-02..04-05 → 2003-02,03,04-05 00:00:00 2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC 2003-03-05 → 2003-03-05 00:00:00 03-05 → *-03-05 00:00:00 diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 6e0bab9b94..54ab909ddf 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -32,6 +32,8 @@ #include "parse-util.h" #include "string-util.h" +/* Longest valid date/time range is 1970..2199 */ +#define MAX_RANGE_LEN 230 #define BITS_WEEKDAYS 127 static void free_chain(CalendarComponent *c) { @@ -448,8 +450,26 @@ static int parse_component_decimal(const char **p, bool usec, unsigned long *res return 0; } +static int const_chain(int value, CalendarComponent **c) { + CalendarComponent *cc = NULL; + + assert(c); + + cc = new0(CalendarComponent, 1); + if (!cc) + return -ENOMEM; + + cc->value = value; + cc->repeat = 0; + cc->next = *c; + + *c = cc; + + return 0; +} + static int prepend_component(const char **p, bool usec, CalendarComponent **c) { - unsigned long value, repeat = 0; + unsigned long i, value, range_end, range_inc, repeat = 0; CalendarComponent *cc; int r; const char *e; @@ -471,6 +491,30 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) { if (repeat == 0) return -ERANGE; + } else if (e[0] == '.' && e[1] == '.') { + e += 2; + r = parse_component_decimal(&e, usec, &range_end); + if (r < 0) + return r; + + if (value >= range_end) + return -EINVAL; + + range_inc = usec ? USEC_PER_SEC : 1; + + /* Don't allow impossibly large ranges... */ + if (range_end - value >= MAX_RANGE_LEN * range_inc) + return -EINVAL; + + /* ...or ranges with only a single element */ + if (range_end - value < range_inc) + return -EINVAL; + + for (i = value; i <= range_end; i += range_inc) { + r = const_chain(i, c); + if (r < 0) + return r; + } } if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':') @@ -495,24 +539,6 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) { return 0; } -static int const_chain(int value, CalendarComponent **c) { - CalendarComponent *cc = NULL; - - assert(c); - - cc = new0(CalendarComponent, 1); - if (!cc) - return -ENOMEM; - - cc->value = value; - cc->repeat = 0; - cc->next = *c; - - *c = cc; - - return 0; -} - static int parse_chain(const char **p, bool usec, CalendarComponent **c) { const char *t; CalendarComponent *cc = NULL; diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 5a8c6cbfb6..cb2538ed7f 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -124,6 +124,10 @@ int main(int argc, char* argv[]) { test_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001"); test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); + test_one("9..11,13:00,30", "*-*-* 09,10,11,13:00,30:00"); + test_one("1..3-1..3 1..3:1..3", "*-01,02,03-01,02,03 01,02,03:01,02,03:00"); + test_one("00:00:1.125..2.125", "*-*-* 00:00:01.125000,02.125000"); + test_one("00:00:1.0..3.8", "*-*-* 00:00:01,02,03"); test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000); test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000); @@ -146,6 +150,7 @@ int main(int argc, char* argv[]) { assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0); assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0); assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0); + assert_se(calendar_spec_from_string("00:00:00.0..00.9", &c) < 0); return 0; } -- cgit v1.2.3-54-g00ecf From e638d0504fa4861896f47c19e22b48c7f8ca3478 Mon Sep 17 00:00:00 2001 From: Douglas Christman Date: Thu, 30 Jun 2016 22:26:07 -0400 Subject: calendarspec: use ".." notation for ranges of weekdays For backwards compatibility, both the new format (Mon..Wed) and the old format (Mon-Wed) are supported. --- man/systemd.time.xml | 10 +++++----- src/basic/calendarspec.c | 24 ++++++++++++++++++------ src/test/test-calendarspec.c | 7 +++++-- 3 files changed, 28 insertions(+), 13 deletions(-) (limited to 'man') diff --git a/man/systemd.time.xml b/man/systemd.time.xml index 6f9e88406d..9f0b2e1120 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -217,8 +217,8 @@ should consist of one or more English language weekday names, either in the abbreviated (Wed) or non-abbreviated (Wednesday) form (case does not matter), separated by commas. Specifying two - weekdays separated by - refers to a range of - continuous weekdays. , and - + weekdays separated by .. refers to a range of + continuous weekdays. , and .. may be combined freely. In the date and time specifications, any component may be @@ -263,12 +263,12 @@ Examples for valid timestamps and their normalized form: - Sat,Thu,Mon-Wed,Sat-Sun → Mon-Thu,Sat,Sun *-*-* 00:00:00 + Sat,Thu,Mon..Wed,Sat..Sun → Mon..Thu,Sat,Sun *-*-* 00:00:00 Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00 Wed *-1 → Wed *-*-01 00:00:00 - Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00 + Wed..Wed,Wed *-1 → Wed *-*-01 00:00:00 Wed, 17:48 → Wed *-*-* 17:48:00 -Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 +Wed..Sat,Tue 12-10-15 1:2:3 → Tue..Sat 2012-10-15 01:02:03 *-*-7 0:0:0 → *-*-07 00:00:00 10-15 → *-10-15 00:00:00 monday *-12-* 17:00 → Mon *-12-* 17:00:00 diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 54ab909ddf..e4cfab364e 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -202,7 +202,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { }; int l, x; - bool need_colon = false; + bool need_comma = false; assert(f); assert(c); @@ -213,10 +213,10 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { if (c->weekdays_bits & (1 << x)) { if (l < 0) { - if (need_colon) + if (need_comma) fputc(',', f); else - need_colon = true; + need_comma = true; fputs(days[x], f); l = x; @@ -225,7 +225,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { } else if (l >= 0) { if (x > l + 1) { - fputc(x > l + 2 ? '-' : ',', f); + fputs(x > l + 2 ? ".." : ",", f); fputs(days[x-1], f); } @@ -234,7 +234,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { } if (l >= 0 && x > l + 1) { - fputc(x > l + 2 ? '-' : ',', f); + fputs(x > l + 2 ? ".." : ",", f); fputs(days[x-1], f); } } @@ -359,6 +359,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { skip = strlen(day_nr[i].name); if ((*p)[skip] != '-' && + (*p)[skip] != '.' && (*p)[skip] != ',' && (*p)[skip] != ' ' && (*p)[skip] != 0) @@ -396,7 +397,18 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { return 0; } - if (**p == '-') { + if (**p == '.') { + if (l >= 0) + return -EINVAL; + + if ((*p)[1] != '.') + return -EINVAL; + + l = day_nr[i].nr; + *p += 1; + + /* Support ranges with "-" for backwards compatibility */ + } else if (**p == '-') { if (l >= 0) return -EINVAL; diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index cb2538ed7f..4a2b93de59 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -91,12 +91,15 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_ int main(int argc, char* argv[]) { CalendarSpec *c; - test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon-Thu,Sat,Sun *-*-* 00:00:00"); + test_one("Sat,Thu,Mon-Wed,Sat-Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00"); + test_one("Sat,Thu,Mon..Wed,Sat..Sun", "Mon..Thu,Sat,Sun *-*-* 00:00:00"); test_one("Mon,Sun 12-*-* 2,1:23", "Mon,Sun 2012-*-* 01,02:23:00"); test_one("Wed *-1", "Wed *-*-01 00:00:00"); test_one("Wed-Wed,Wed *-1", "Wed *-*-01 00:00:00"); + test_one("Wed..Wed,Wed *-1", "Wed *-*-01 00:00:00"); test_one("Wed, 17:48", "Wed *-*-* 17:48:00"); - test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue-Sat 2012-10-15 01:02:03"); + test_one("Wed-Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03"); + test_one("Wed..Sat,Tue 12-10-15 1:2:3", "Tue..Sat 2012-10-15 01:02:03"); test_one("*-*-7 0:0:0", "*-*-07 00:00:00"); test_one("10-15", "*-10-15 00:00:00"); test_one("monday *-12-* 17:00", "Mon *-12-* 17:00:00"); -- cgit v1.2.3-54-g00ecf From 6dd6a9c4930462a847e3f3924d88124ba9cc0522 Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Thu, 12 May 2016 11:23:35 +0200 Subject: treewide: fix typos --- NEWS | 2 +- man/sd_bus_get_fd.xml | 2 +- man/systemd-nspawn.xml | 4 ++-- man/systemd.netdev.xml | 2 +- src/login/logind-core.c | 2 +- src/nspawn/nspawn-network.c | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'man') diff --git a/NEWS b/NEWS index e4efb476c6..7a0d1d573e 100644 --- a/NEWS +++ b/NEWS @@ -851,7 +851,7 @@ CHANGES WITH 227: files controlled by the number of files that shall remain, in addition to the already existing control by size and by date. This is useful as journal interleaving performance - degrades with too many seperate journal files, and allows + degrades with too many separate journal files, and allows putting an effective limit on them. The new setting defaults to 100, but this may be changed by setting SystemMaxFiles= and RuntimeMaxFiles= in journald.conf. Also, the diff --git a/man/sd_bus_get_fd.xml b/man/sd_bus_get_fd.xml index 49162a6e65..9f7019069f 100644 --- a/man/sd_bus_get_fd.xml +++ b/man/sd_bus_get_fd.xml @@ -68,7 +68,7 @@ project='die-net'>select3, poll3, - or similar functions to wait for incmming messages. + or similar functions to wait for incoming messages. diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index c436f42948..cb0468fbf5 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -109,9 +109,9 @@ service in the background. In this mode each container instance runs as its own service instance; a default template unit file systemd-nspawn@.service is provided to make this easy, taking the container name as instance identifier. Note that different default options apply when systemd-nspawn is - invoked by the template unit file than interactively on the commnd line. Most importanly the template unit file + invoked by the template unit file than interactively on the command line. Most importantly the template unit file makes use of the which is not the default in case systemd-nspawn is - invoked from the interactive command line. Further differences with the defaults are documented dalong with the + invoked from the interactive command line. Further differences with the defaults are documented along with the various supported options below. The machinectl1 tool may diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 2be1efee2f..571e9aa946 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -163,7 +163,7 @@ A virtual extensible LAN (vxlan), for connecting Cloud computing deployments. vrf - A Virtual Routing and Forwarding (VRF) interface to create seperate routing and forwarding domains. + A Virtual Routing and Forwarding (VRF) interface to create separate routing and forwarding domains. diff --git a/src/login/logind-core.c b/src/login/logind-core.c index cbf8d757fe..eff5a4a36f 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -496,7 +496,7 @@ static int manager_count_external_displays(Manager *m) { continue; /* Ignore internal displays: the type is encoded in - * the sysfs name, as the second dash seperated item + * the sysfs name, as the second dash separated item * (the first is the card name, the last the connector * number). We implement a whitelist of external * displays here, rather than a whitelist, to ensure diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 8da47a2ca6..428cc04de0 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -350,7 +350,7 @@ int setup_bridge(const char *veth_name, const char *bridge_name, bool create) { if (create) { /* We take a system-wide lock here, so that we can safely check whether there's still a member in the - * bridge before removing it, without risking interferance from other nspawn instances. */ + * bridge before removing it, without risking interference from other nspawn instances. */ r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock); if (r < 0) -- cgit v1.2.3-54-g00ecf From e8644ece7b28c7b8449344d6c647d9b4558d28b1 Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Fri, 24 Jun 2016 15:32:57 +0200 Subject: man: add link to sd_bus_add_match to busctl.xml --- man/busctl.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'man') diff --git a/man/busctl.xml b/man/busctl.xml index b71a174634..052a33097f 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -119,8 +119,10 @@ When showing messages being exchanged, show only the - subset matching MATCH. - + subset matching MATCH. + See + sd_bus_add_match3. + -- cgit v1.2.3-54-g00ecf From 4d89618a4eb048704b37fec37eaa7b4cef66e6e9 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 6 Jul 2016 11:12:03 +0530 Subject: man: networkd bonding remove 802.3ad from transmit hash policy (#3666) The xmit_hash_policy does not have 802.3ad value. Remove this from man. --- man/systemd.netdev.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'man') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 571e9aa946..8f946c97ae 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -808,8 +808,7 @@ layer2, layer3+4, layer2+3, - encap2+3, - 802.3ad, and + encap2+3, and encap3+4. -- cgit v1.2.3-54-g00ecf From d6cdc4cd4b58cfff4b44e1201e54f05b4a38d2d4 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Fri, 8 Jul 2016 23:08:07 +0400 Subject: man: improve wording for calendar spec's repetition values (#3687) --- man/systemd.time.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'man') diff --git a/man/systemd.time.xml b/man/systemd.time.xml index 9f0b2e1120..aae3accb6c 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -226,7 +226,7 @@ match. Alternatively, each component can be specified as a list of values separated by commas. Values may also be suffixed with / and a repetition value, which indicates that - the value and all values plus multiples of the repetition value + the value itself and the value plus all multiples of the repetition value are matched. Each component may also contain a range of values separated by ... -- cgit v1.2.3-54-g00ecf From 61233823aa4b0fe9605e0a7cd77261b3c5bca8e9 Mon Sep 17 00:00:00 2001 From: Torstein Husebø Date: Sun, 10 Jul 2016 14:48:23 +0200 Subject: treewide: fix typos and remove accidental repetition of words --- NEWS | 4 ++-- TODO | 4 ++-- hwdb/70-pointingstick.hwdb | 2 +- man/systemd.offline-updates.xml | 2 +- src/basic/copy.c | 2 +- src/basic/fileio.c | 2 +- src/basic/mount-util.c | 2 +- src/basic/strv.c | 2 +- src/basic/user-util.c | 2 +- src/core/cgroup.c | 2 +- src/core/execute.c | 2 +- src/core/execute.h | 2 +- src/core/killall.c | 2 +- src/core/load-fragment.c | 4 ++-- src/core/machine-id-setup.c | 2 +- src/core/main.c | 2 +- src/core/transaction.c | 4 ++-- src/core/unit.c | 2 +- src/coredump/coredump.c | 2 +- src/journal/journald-server.c | 2 +- src/journal/sd-journal.c | 2 +- src/libsystemd/sd-bus/bus-message.c | 4 ++-- src/libsystemd/sd-device/sd-device.c | 2 +- src/libudev/libudev-device.c | 2 +- src/machine/machined.c | 2 +- src/machine/operation.c | 4 ++-- src/network/networkd-link.c | 2 +- src/nspawn/nspawn-cgroup.c | 2 +- src/nss-myhostname/nss-myhostname.c | 2 +- src/resolve/resolved-dns-answer.c | 2 +- src/resolve/resolved-dns-cache.c | 2 +- src/resolve/resolved-dns-dnssec.c | 2 +- src/resolve/resolved-dns-query.c | 2 +- src/shared/path-lookup.c | 2 +- src/sysusers/sysusers.c | 2 +- src/udev/udev-event.c | 2 +- sysctl.d/50-default.conf | 2 +- tmpfiles.d/systemd-nspawn.conf | 2 +- 38 files changed, 44 insertions(+), 44 deletions(-) (limited to 'man') diff --git a/NEWS b/NEWS index 7a0d1d573e..dcc1d55048 100644 --- a/NEWS +++ b/NEWS @@ -569,7 +569,7 @@ CHANGES WITH 228: the service. * Timer units gained support for a new RemainAfterElapse= - setting which takes a boolean argument. It defaults on on, + setting which takes a boolean argument. It defaults on, exposing behaviour unchanged to previous releases. If set to off, timer units are unloaded after they elapsed if they cannot elapse again. This is particularly useful for @@ -5236,7 +5236,7 @@ CHANGES WITH 192: * We do not mount the "cpuset" controller anymore together with "cpu" and "cpuacct", as "cpuset" groups generally cannot be started if no parameters are assigned to it. "cpuset" hence - broke code that assumed it it could create "cpu" groups and + broke code that assumed it could create "cpu" groups and just start them. * journalctl -f will now subscribe to terminal size changes, diff --git a/TODO b/TODO index 5208bdb818..06659ee50d 100644 --- a/TODO +++ b/TODO @@ -126,7 +126,7 @@ Features: * docs: bring http://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime up to date * mounting and unmounting mount points manually with different source - devices will result in collected collected on all devices used. + devices will result in collected on all devices used. http://lists.freedesktop.org/archives/systemd-devel/2015-April/030225.html * add a job mode that will fail if a transaction would mean stopping @@ -554,7 +554,7 @@ Features: - systemctl enable: fail if target to alias into does not exist? maybe show how many units are enabled afterwards? - systemctl: "Journal has been rotated since unit was started." message is misleading - better error message if you run systemctl without systemd running - - systemctl status output should should include list of triggering units and their status + - systemctl status output should include list of triggering units and their status * unit install: - "systemctl mask" should find all names by which a unit is accessible diff --git a/hwdb/70-pointingstick.hwdb b/hwdb/70-pointingstick.hwdb index 9adcf6d804..ec166ead40 100644 --- a/hwdb/70-pointingstick.hwdb +++ b/hwdb/70-pointingstick.hwdb @@ -69,7 +69,7 @@ # # -# Sort by by brand, model +# Sort by brand, model ######################################### # Dell diff --git a/man/systemd.offline-updates.xml b/man/systemd.offline-updates.xml index 946234ad90..ae53b8552d 100644 --- a/man/systemd.offline-updates.xml +++ b/man/systemd.offline-updates.xml @@ -93,7 +93,7 @@ As the first step, the update script should check if the - /system-update symlink points to the the location used by that update + /system-update symlink points to the location used by that update script. In case it does not exists or points to a different location, the script must exit without error. It is possible for multiple update services to be installed, and for multiple update scripts to be launched in parallel, and only the one that corresponds to the tool diff --git a/src/basic/copy.c b/src/basic/copy.c index c3586728d0..9883f5fa31 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -169,7 +169,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, * so reduce our maximum by the amount we already copied, * but don't go below our copy buffer size, unless we are - * close the the limit of bytes we are allowed to copy. */ + * close the limit of bytes we are allowed to copy. */ m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); } diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 0360a8eab3..47ccfc39d8 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1067,7 +1067,7 @@ int fflush_and_check(FILE *f) { return 0; } -/* This is much like like mkostemp() but is subject to umask(). */ +/* This is much like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern, int flags) { _cleanup_umask_ mode_t u = 0; int fd; diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index ba698959b7..f5b5a70d21 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -104,7 +104,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { * * As last fallback we do traditional fstat() based st_dev * comparisons. This is how things were traditionally done, - * but unionfs breaks breaks this since it exposes file + * but unionfs breaks this since it exposes file * systems with a variety of st_dev reported. Also, btrfs * subvolumes have different st_dev, even though they aren't * real mounts of their own. */ diff --git a/src/basic/strv.c b/src/basic/strv.c index 53298268f4..e0e2d1ebbe 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -876,7 +876,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) { if (n == 0) return 0; - /* Adds the value value n times to l */ + /* Adds the value n times to l */ k = strv_length(*l); diff --git a/src/basic/user-util.c b/src/basic/user-util.c index f65ca3edaa..e9d668ddfc 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -458,7 +458,7 @@ int take_etc_passwd_lock(const char *root) { * * Note that shadow-utils also takes per-database locks in * addition to lckpwdf(). However, we don't given that they - * are redundant as they they invoke lckpwdf() first and keep + * are redundant as they invoke lckpwdf() first and keep * it during everything they do. The per-database locks are * awfully racy, and thus we just won't do them. */ diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 6e36e6b340..2ba1627b85 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1658,7 +1658,7 @@ int manager_setup_cgroup(Manager *m) { /* 3. Install agent */ if (unified) { - /* In the unified hierarchy we can can get + /* In the unified hierarchy we can get * cgroup empty notifications via inotify. */ m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source); diff --git a/src/core/execute.c b/src/core/execute.c index 8c487b371f..f4f5723c35 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2827,7 +2827,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { bool exec_context_maintains_privileges(ExecContext *c) { assert(c); - /* Returns true if the process forked off would run run under + /* Returns true if the process forked off would run under * an unchanged UID or as root. */ if (!c->user) diff --git a/src/core/execute.h b/src/core/execute.h index 210eea0e82..cacf66cf51 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -130,7 +130,7 @@ struct ExecContext { bool ignore_sigpipe; - /* Since resolving these names might might involve socket + /* Since resolving these names might involve socket * connections and we don't want to deadlock ourselves these * names are resolved on execution only and in the child * process. */ diff --git a/src/core/killall.c b/src/core/killall.c index 09378f7085..e1359b72d2 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -80,7 +80,7 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) { get_process_comm(pid, &comm); if (r) - log_notice("Process " PID_FMT " (%s) has been been marked to be excluded from killing. It is " + log_notice("Process " PID_FMT " (%s) has been marked to be excluded from killing. It is " "running from the root file system, and thus likely to block re-mounting of the " "root file system to read-only. Please consider moving it into an initrd file " "system instead.", pid, strna(comm)); diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 8295cf45a6..61b333b506 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3594,7 +3594,7 @@ int config_parse_protect_home( assert(data); /* Our enum shall be a superset of booleans, hence first try - * to parse as as boolean, and then as enum */ + * to parse as boolean, and then as enum */ k = parse_boolean(rvalue); if (k > 0) @@ -3637,7 +3637,7 @@ int config_parse_protect_system( assert(data); /* Our enum shall be a superset of booleans, hence first try - * to parse as as boolean, and then as enum */ + * to parse as boolean, and then as enum */ k = parse_boolean(rvalue); if (k > 0) diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 0145fe2894..ea6b085e4f 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -303,7 +303,7 @@ int machine_id_commit(const char *root) { if (r < 0) return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id); if (r == 0) { - log_debug("%s is is not a mount point. Nothing to do.", etc_machine_id); + log_debug("%s is not a mount point. Nothing to do.", etc_machine_id); return 0; } diff --git a/src/core/main.c b/src/core/main.c index 3d74ef1adf..fc04fb8051 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1444,7 +1444,7 @@ int main(int argc, char *argv[]) { /* * Do a dummy very first call to seal the kernel's time warp magic. * - * Do not call this this from inside the initrd. The initrd might not + * Do not call this from inside the initrd. The initrd might not * carry /etc/adjtime with LOCAL, but the real system could be set up * that way. In such case, we need to delay the time-warp or the sealing * until we reach the real system. diff --git a/src/core/transaction.c b/src/core/transaction.c index e06a48a2f1..af539171fd 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -373,7 +373,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi delete = NULL; for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) { - /* logging for j not k here here to provide consistent narrative */ + /* logging for j not k here to provide consistent narrative */ log_unit_warning(j->unit, "Found dependency on %s/%s", k->unit->id, job_type_to_string(k->type)); @@ -392,7 +392,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi if (delete) { const char *status; - /* logging for j not k here here to provide consistent narrative */ + /* logging for j not k here to provide consistent narrative */ log_unit_warning(j->unit, "Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type)); diff --git a/src/core/unit.c b/src/core/unit.c index 5f06a7dfe7..1479d06606 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -3790,7 +3790,7 @@ bool unit_is_pristine(Unit *u) { /* Check if the unit already exists or is already around, * in a number of different ways. Note that to cater for unit * types such as slice, we are generally fine with units that - * are marked UNIT_LOADED even even though nothing was + * are marked UNIT_LOADED even though nothing was * actually loaded, as those unit types don't require a file * on disk to validly load. */ diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 999de63900..82a54968e7 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -811,7 +811,7 @@ static int process_socket(int fd) { goto finish; } - /* Make sure we we got all data we really need */ + /* Make sure we got all data we really need */ assert(context[CONTEXT_PID]); assert(context[CONTEXT_UID]); assert(context[CONTEXT_GID]); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 8f82d2a838..b1cbda0fff 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1607,7 +1607,7 @@ static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, /* Dispatch one stream notification event */ stdout_stream_send_notify(s->stdout_streams_notify_queue); - /* Leave us enabled if there's still more to to do. */ + /* Leave us enabled if there's still more to do. */ if (s->send_watchdog || s->stdout_streams_notify_queue) return 0; diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 1cea68ad42..75a0ffb49b 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1438,7 +1438,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) if (j->toplevel_fd < 0) d = opendir(path); else - /* Open the specified directory relative to the the toplevel fd. Enforce that the path specified is + /* Open the specified directory relative to the toplevel fd. Enforce that the path specified is * relative, by dropping the initial slash */ d = xopendirat(j->toplevel_fd, skip_slash(path), 0); if (!d) { diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index b8958ec7bb..5cec804e32 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -181,7 +181,7 @@ static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, b if (!np) goto poison; } else { - /* Initially, the header is allocated as part of of + /* Initially, the header is allocated as part of * the sd_bus_message itself, let's replace it by * dynamic data */ @@ -2865,7 +2865,7 @@ static int bus_message_close_header(sd_bus_message *m) { /* The actual user data is finished now, we just complete the variant and struct now (at least on gvariant). Remember - this position, so that during parsing we know where to to + this position, so that during parsing we know where to put the outer container end. */ m->user_body_size = m->body_size; diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index d503232505..0c4ad966bd 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -197,7 +197,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { return -errno; } } else { - /* everything else just just needs to be a directory */ + /* everything else just needs to be a directory */ if (!is_dir(syspath, false)) return -ENODEV; } diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index 814e016800..995bf56586 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -619,7 +619,7 @@ _public_ const char *udev_device_get_syspath(struct udev_device *udev_device) * * Get the kernel device name in /sys. * - * Returns: the name string of the device device + * Returns: the name string of the device **/ _public_ const char *udev_device_get_sysname(struct udev_device *udev_device) { diff --git a/src/machine/machined.c b/src/machine/machined.c index f7ceb5e603..57121945f3 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -303,7 +303,7 @@ void manager_gc(Manager *m, bool drop_not_started) { machine_get_state(machine) != MACHINE_CLOSING) machine_stop(machine); - /* Now, the stop stop probably made this referenced + /* Now, the stop probably made this referenced * again, but if it didn't, then it's time to let it * go entirely. */ if (!machine_check_gc(machine, drop_not_started)) { diff --git a/src/machine/operation.c b/src/machine/operation.c index 8f8321a8b3..2bf93cb493 100644 --- a/src/machine/operation.c +++ b/src/machine/operation.c @@ -30,7 +30,7 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat assert(o); assert(si); - log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i", + log_debug("Operating " PID_FMT " is now complete with code=%s status=%i", o->pid, sigchld_code_to_string(si->si_code), si->si_status); @@ -59,7 +59,7 @@ static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdat } } else { - /* The default default operaton when done is to simply return an error on failure or an empty success + /* The default operation when done is to simply return an error on failure or an empty success * message on success. */ if (r < 0) goto fail; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1842685180..2a9a7bb7c7 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2173,7 +2173,7 @@ static int link_set_ipv6_forward(Link *link) { if (!link_ipv6_forward_enabled(link)) return 0; - /* On Linux, the IPv6 stack does not not know a per-interface + /* On Linux, the IPv6 stack does not know a per-interface * packet forwarding setting: either packet forwarding is on * for all, or off for all. We hence don't bother with a * per-interface setting, but simply propagate the interface diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index f50f1ad6c2..b1580236c9 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -123,7 +123,7 @@ int create_subcgroup(pid_t pid, bool unified_requested) { int unified, r; CGroupMask supported; - /* In the unified hierarchy inner nodes may only only contain + /* In the unified hierarchy inner nodes may only contain * subgroups, but not processes. Hence, if we running in the * unified hierarchy and the container does the same, and we * did not create a scope unit for the container move us and diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 9a6e157e12..11c27575c0 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -96,7 +96,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( return NSS_STATUS_TRYAGAIN; } - /* We respond to our local host name, our our hostname suffixed with a single dot. */ + /* We respond to our local host name, our hostname suffixed with a single dot. */ if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) { *errnop = ENOENT; *h_errnop = HOST_NOT_FOUND; diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 13dcba8421..ab85754bf7 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -702,7 +702,7 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) { if (a->items[i].rr->key->class == DNS_CLASS_IN && ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) || (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local))) - /* Order address records that are are not preferred to the end of the array */ + /* Order address records that are not preferred to the end of the array */ items[end--] = a->items[i]; else /* Order all other records to the beginning of the array */ diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 87f7c21d03..9233fb0ac1 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -691,7 +691,7 @@ int dns_cache_put( return 0; /* See https://tools.ietf.org/html/rfc2308, which say that a - * matching SOA record in the packet is used to to enable + * matching SOA record in the packet is used to enable * negative caching. */ r = dns_answer_find_soa(answer, key, &soa, &flags); if (r < 0) diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index a54aed3a63..d4a267c89f 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -1642,7 +1642,7 @@ static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) { if (r <= 0) return r; - /* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */ + /* If the name we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix); if (r < 0) return r; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index c8af5579f0..53be18efc6 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -520,7 +520,7 @@ int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) { assert(q); assert(auxiliary_for); - /* Ensure that that the query is not auxiliary yet, and + /* Ensure that the query is not auxiliary yet, and * nothing else is auxiliary to it either */ assert(!q->auxiliary_for); assert(!q->auxiliary_queries); diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index ca593b6963..862096ae7b 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -88,7 +88,7 @@ static int user_data_dir(char **ret, const char *suffix) { assert(suffix); /* We don't treat /etc/xdg/systemd here as the spec - * suggests because we assume that that is a link to + * suggests because we assume that is a link to * /etc/systemd/ anyway. */ e = getenv("XDG_DATA_HOME"); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 4377f1b910..787d68a009 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1418,7 +1418,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { } if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) { - log_error("[%s:%u] Unknown command command type '%c'.", fname, line, action[0]); + log_error("[%s:%u] Unknown command type '%c'.", fname, line, action[0]); return -EBADMSG; } diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 8d601c9c2c..54cd741bb1 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -249,7 +249,7 @@ subst: if (event->program_result == NULL) break; - /* get part part of the result string */ + /* get part of the result string */ i = 0; if (attr != NULL) i = strtoul(attr, &rest, 10); diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf index def151bb84..f08f32e849 100644 --- a/sysctl.d/50-default.conf +++ b/sysctl.d/50-default.conf @@ -5,7 +5,7 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. -# See sysctl.d(5) and core(5) for for documentation. +# See sysctl.d(5) and core(5) for documentation. # To override settings in this file, create a local file in /etc # (e.g. /etc/sysctl.d/90-override.conf), and put any assignments diff --git a/tmpfiles.d/systemd-nspawn.conf b/tmpfiles.d/systemd-nspawn.conf index 9fa3878d6b..78bd1c670e 100644 --- a/tmpfiles.d/systemd-nspawn.conf +++ b/tmpfiles.d/systemd-nspawn.conf @@ -10,7 +10,7 @@ Q /var/lib/machines 0700 - - - # Remove old temporary snapshots, but only at boot. Ideally we'd have -# "self-destroying" btrfs snapshots that go away if the last last +# "self-destroying" btrfs snapshots that go away if the last # reference to it does. To mimic a scheme like this at least remove # the old snapshots on fresh boots, where we know they cannot be # referenced anymore. Note that we actually remove all temporary files -- cgit v1.2.3-54-g00ecf From 037a3ded54f72338fc95285d7971b61f695e3c1a Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 12 Jul 2016 11:58:14 +0200 Subject: man: fix indefinite articles (#3694) --- man/crypttab.xml | 2 +- man/machinectl.xml | 4 ++-- man/sd_event_add_time.xml | 4 ++-- man/sd_journal_get_data.xml | 2 +- man/systemd.netdev.xml | 4 ++-- man/systemd.network.xml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'man') diff --git a/man/crypttab.xml b/man/crypttab.xml index 1de834a045..4b8d4aa3d6 100644 --- a/man/crypttab.xml +++ b/man/crypttab.xml @@ -93,7 +93,7 @@ field is not present or the password is set to none or -, the password has to be manually entered during system boot. Otherwise, the field is - interpreted as a absolute path to a file containing the encryption + interpreted as an absolute path to a file containing the encryption password. For swap encryption, /dev/urandom or the hardware device /dev/hw_random can be used as the password file; using /dev/random diff --git a/man/machinectl.xml b/man/machinectl.xml index d3891332e4..597a5cc583 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -333,7 +333,7 @@ Show properties of one or more registered virtual machines or containers or the manager itself. If no argument is specified, properties of the manager will be - shown. If an NAME is specified, properties of this virtual + shown. If a NAME is specified, properties of this virtual machine or container are shown. By default, empty properties are suppressed. Use to show those too. To select specific properties to show, use @@ -575,7 +575,7 @@ Show properties of one or more registered virtual machine or container images, or the manager itself. If no argument is specified, properties of the manager will be - shown. If an NAME is specified, properties of this virtual + shown. If a NAME is specified, properties of this virtual machine or container image are shown. By default, empty properties are suppressed. Use to show those too. To select specific properties to show, use diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml index a2c0d54b56..2c0bd0ba10 100644 --- a/man/sd_event_add_time.xml +++ b/man/sd_event_add_time.xml @@ -213,7 +213,7 @@ in µs. sd_event_source_get_time_accuracy() - retrieves the configured accuracy value of a event source + retrieves the configured accuracy value of an event source created previously with sd_event_add_time(). It takes the event source object and a pointer to a variable to store the accuracy in. The accuracy is specified in µs. @@ -224,7 +224,7 @@ the event source object and accuracy, in µs. sd_event_source_get_time_clock() - retrieves the configured clock of a event source created + retrieves the configured clock of an event source created previously with sd_event_add_time(). It takes the event source object and a pointer to a variable to store the clock identifier in. diff --git a/man/sd_journal_get_data.xml b/man/sd_journal_get_data.xml index 908ee7db16..1321114de0 100644 --- a/man/sd_journal_get_data.xml +++ b/man/sd_journal_get_data.xml @@ -151,7 +151,7 @@ in size — but the library might still return larger data objects. That means applications should not rely exclusively on this setting to limit the size of the data fields returned, but need to - apply a explicit size limit on the returned data as well. This + apply an explicit size limit on the returned data as well. This threshold defaults to 64K by default. To retrieve the complete data fields this threshold should be turned off by setting it to 0, so that the library always returns the complete data objects. diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 8f946c97ae..38aede84cb 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -124,7 +124,7 @@ An IPv4 or IPv6 tunnel over IPv6 ip6gretap - An Level 2 GRE tunnel over IPv6. + A Level 2 GRE tunnel over IPv6. ipip An IPv4 over IPv4 tunnel. @@ -1142,7 +1142,7 @@ MACAddress=12:34:56:78:9a:bc /etc/systemd/network/25-vrf.netdev - Create an VRF interface with table 42. + Create a VRF interface with table 42. [NetDev] Name=vrf-test Kind=vrf diff --git a/man/systemd.network.xml b/man/systemd.network.xml index edf227c134..4541a55490 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -841,7 +841,7 @@ ClientIdentifier= The DHCPv4 client identifier to use. Either mac to use the MAC address of the link - or duid (the default, see below) to use a RFC4361-compliant Client ID. + or duid (the default, see below) to use an RFC4361-compliant Client ID. -- cgit v1.2.3-54-g00ecf From 595bfe7df2999cfb99b274ce510695aed4aba6d5 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Tue, 12 Jul 2016 12:52:11 +0200 Subject: Various fixes for typos found by lintian (#3705) --- NEWS | 4 ++-- man/libudev.xml | 2 +- man/sd_event_add_time.xml | 2 +- man/systemd-socket-activate.xml | 2 +- man/systemd.special.xml | 2 +- man/systemd.timer.xml | 2 +- src/boot/bootctl.c | 2 +- src/core/cgroup.c | 2 +- src/core/unit.c | 4 ++-- src/journal-remote/microhttpd-util.c | 2 +- src/libsystemd-network/lldp-neighbor.c | 2 +- src/libsystemd/sd-login/sd-login.c | 2 +- src/machine/machined-dbus.c | 2 +- src/network/networkd-link.c | 4 ++-- src/nspawn/nspawn.c | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) (limited to 'man') diff --git a/NEWS b/NEWS index dcc1d55048..bdba05eb2a 100644 --- a/NEWS +++ b/NEWS @@ -569,7 +569,7 @@ CHANGES WITH 228: the service. * Timer units gained support for a new RemainAfterElapse= - setting which takes a boolean argument. It defaults on, + setting which takes a boolean argument. It defaults to on, exposing behaviour unchanged to previous releases. If set to off, timer units are unloaded after they elapsed if they cannot elapse again. This is particularly useful for @@ -760,7 +760,7 @@ CHANGES WITH 227: * Support for USB FunctionFS activation has been added. This allows implementation of USB gadget services that are activated as soon as they are requested, so that they don't - have to run continously, similar to classic socket + have to run continuously, similar to classic socket activation. * The "systemctl exit" command now optionally takes an diff --git a/man/libudev.xml b/man/libudev.xml index 7ef978463c..53b68dcc89 100644 --- a/man/libudev.xml +++ b/man/libudev.xml @@ -81,7 +81,7 @@ To introspect a local device on a system, a udev device object can be created via udev_device_new_from_syspath3 - and friends. The device object allows to query current state, + and friends. The device object allows one to query current state, read and write attributes and lookup properties of the device in question. diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml index 2c0bd0ba10..5496b71529 100644 --- a/man/sd_event_add_time.xml +++ b/man/sd_event_add_time.xml @@ -123,7 +123,7 @@ regarding the various types of clocks. The usec parameter specifies the earliest time, in microseconds (µs), relative to the clock's epoch, when the timer shall be triggered. If a time already in the past is specified (including 0), this timer source "fires" immediately and is ready to be - dispatched. If the paramater is specified as UINT64_MAX the timer event will never elapse, + dispatched. If the parameter is specified as UINT64_MAX the timer event will never elapse, which may be used as an alternative to explicitly disabling a timer event source with sd_event_source_set_enabled3. The accuracy parameter specifies an additional accuracy value in µs specifying how much the diff --git a/man/systemd-socket-activate.xml b/man/systemd-socket-activate.xml index 5d7f157c72..2cf3a7d377 100644 --- a/man/systemd-socket-activate.xml +++ b/man/systemd-socket-activate.xml @@ -142,7 +142,7 @@ FileDescriptorName= in socket unit files, and enables use of sd_listen_fds_with_names3. Multiple entries may be specifies using separate options or by separating names with colons - (:) in one option. In case more names are given than descriptors, superflous ones willl be + (:) in one option. In case more names are given than descriptors, superfluous ones willl be ignored. In case less names are given than descriptors, the remaining file descriptors will be unnamed. diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 19ca6d6837..9d79315069 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -473,7 +473,7 @@ systemd-fstab-generator3 and systemd-gpt-auto-generator3 - automatically setup the appropiate dependencies to make this happen. + automatically setup the appropriate dependencies to make this happen. diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 0fa95e97a8..4fe140e4bc 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -76,7 +76,7 @@ Note that in case the unit to activate is already active at the time the timer elapses it is not restarted, but simply left running. There is no concept of spawning new service instances in this case. Due to this, services - with RemainAfterExit= set (which stay around continously even after the service's main process + with RemainAfterExit= set (which stay around continuously even after the service's main process exited) are usually not suitable for activation via repetitive timers, as they will only be activated once, and then stay around forever. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index d0af41498f..0d42948720 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -101,7 +101,7 @@ static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t errno = 0; r = blkid_do_safeprobe(b); if (r == -2) { - log_error("File system \"%s\" is ambigious.", p); + log_error("File system \"%s\" is ambiguous.", p); return -ENODEV; } else if (r == 1) { log_error("File system \"%s\" does not contain a label.", p); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 2ba1627b85..94d1161605 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1136,7 +1136,7 @@ int unit_watch_cgroup(Unit *u) { /* Only applies to the unified hierarchy */ r = cg_unified(); if (r < 0) - return log_unit_error_errno(u, r, "Failed detect wether the unified hierarchy is used: %m"); + return log_unit_error_errno(u, r, "Failed detect whether the unified hierarchy is used: %m"); if (r == 0) return 0; diff --git a/src/core/unit.c b/src/core/unit.c index 1479d06606..fdf7ce3af3 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1683,7 +1683,7 @@ static void unit_check_unneeded(Unit *u) { if (unit_active_or_pending(other)) return; - /* If stopping a unit fails continously we might enter a stop + /* If stopping a unit fails continuously we might enter a stop * loop here, hence stop acting on the service being * unnecessary after a while. */ if (!ratelimit_test(&u->auto_stop_ratelimit)) { @@ -1728,7 +1728,7 @@ static void unit_check_binds_to(Unit *u) { if (!stop) return; - /* If stopping a unit fails continously we might enter a stop + /* If stopping a unit fails continuously we might enter a stop * loop here, hence stop acting on the service being * unnecessary after a while. */ if (!ratelimit_test(&u->auto_stop_ratelimit)) { diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index c65c43186f..2f16b02e9a 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -60,7 +60,7 @@ static int mhd_respond_internal(struct MHD_Connection *connection, if (!response) return MHD_NO; - log_debug("Queing response %u: %s", code, buffer); + log_debug("Queueing response %u: %s", code, buffer); MHD_add_response_header(response, "Content-Type", "text/plain"); r = MHD_queue_response(connection, code, response); MHD_destroy_response(response); diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 88f7e329b0..53e29377b3 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -197,7 +197,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { assert(n); if (n->raw_size < sizeof(struct ether_header)) { - log_lldp("Recieved truncated packet, ignoring."); + log_lldp("Received truncated packet, ignoring."); return -EBADMSG; } diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 9d4f187502..3fcefada3f 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -124,7 +124,7 @@ _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) { /* The internal APIs return the empty string for the root * cgroup, let's return the "/" in the public APIs instead, as - * that's easier and less ambigious for people to grok. */ + * that's easier and less ambiguous for people to grok. */ if (isempty(c)) { free(c); c = strdup("/"); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 52ce83a185..1923e8b971 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -953,7 +953,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err /* Create a temporary file we can dump information about deleted images into. We use a temporary file for this * instead of a pipe or so, since this might grow quit large in theory and we don't want to process this - * continously */ + * continuously */ result_fd = open_tmpfile_unlinkable("/tmp/", O_RDWR|O_CLOEXEC); if (result_fd < 0) return -errno; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2a9a7bb7c7..82f56158be 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2726,7 +2726,7 @@ network_file_fail: r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in); if (r < 0) - return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address); + return log_link_error_errno(link, r, "Falied to set initial DHCPv4 address %s: %m", dhcp4_address); } dhcp4_address_fail: @@ -2744,7 +2744,7 @@ dhcp4_address_fail: r = sd_ipv4ll_set_address(link->ipv4ll, &address.in); if (r < 0) - return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address); + return log_link_error_errno(link, r, "Falied to set initial IPv4LL address %s: %m", ipv4ll_address); } ipv4ll_address_fail: diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 73c56d7310..0bab2557b0 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2873,7 +2873,7 @@ static int outer_child( if (l < 0) return log_error_errno(errno, "Failed to recv UID shift: %m"); if (l != sizeof(arg_uid_shift)) { - log_error("Short read while recieving UID shift."); + log_error("Short read while receiving UID shift."); return -EIO; } } -- cgit v1.2.3-54-g00ecf From f749954d924dc126fd3b8a5539b537ddb1a07f71 Mon Sep 17 00:00:00 2001 From: Michal Soltys Date: Fri, 15 Jul 2016 04:20:45 +0200 Subject: correct information about implicit dependencies (#3730) systemd.special.xml: corrections about implicit dependencies for basic.target, sysinit.target and shutdown.target. systemd.target.xml: corrections about implicit dependencies for target units in general. --- man/systemd.special.xml | 16 +++++++++++----- man/systemd.target.xml | 19 ++++++++++++++----- 2 files changed, 25 insertions(+), 10 deletions(-) (limited to 'man') diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 9d79315069..18ad8f92e5 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -127,9 +127,9 @@ A special target unit covering basic boot-up. - systemd automatically adds dependencies of the types - Requires= and After= - for this target unit to all services (except for those with + systemd automatically adds dependency of the type + After= for this target unit to all + services (except for those with DefaultDependencies=no). Usually, this should pull-in all local mount points plus @@ -509,8 +509,9 @@ system shutdown. Services that shall be terminated on system shutdown - shall add Conflicts= dependencies to this - unit for their service unit, which is implicitly done when + shall add Conflicts= and + Before= dependencies to this unit for + their service unit, which is implicitly done when DefaultDependencies=yes is set (the default). @@ -579,6 +580,11 @@ sysinit.target + systemd automatically adds dependencies of the types + Requires= and After= + for this target unit to all services (except for those with + DefaultDependencies=no). + This target pulls in the services required for system initialization. System services pulled in by this target should declare DefaultDependencies=no and specify diff --git a/man/systemd.target.xml b/man/systemd.target.xml index ab910d75dd..645d8493c1 100644 --- a/man/systemd.target.xml +++ b/man/systemd.target.xml @@ -82,11 +82,20 @@ Automatic Dependencies - Unless DefaultDependencies= in the [Unit] section is set to - , target units will implicitly complement all configured dependencies of type - Wants=, Requires= with dependencies of type After=, unless - an ordering dependency of any kind between the target and the respective other unit is already in place. Note that - this behaviour is disabled if either unit has DefaultDependencies=no. + Unless DefaultDependencies= is set to + in either of releated units or an explicit ordering + dependency is already defined, target units will implicitly complement all + configured dependencies of type Wants= or + Requires= with dependencies of type + After=. Note that Wants= or + Requires= must be defined in the target unit itself - if + you for example define Wants=some.target in + some.service, the implicit ordering will not be added. + + All target units automatically gain Conflicts= + dependency against shutdown.target unless DefaultDependencies= + is set to . + -- cgit v1.2.3-54-g00ecf From e306f2df03d2d5bad1053f1a3afe8a49cd0d87a8 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Sat, 16 Jul 2016 11:09:25 -0400 Subject: man: replace dash with mdash where appropriate --- man/systemd.netdev.xml | 2 +- man/systemd.target.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'man') diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 38aede84cb..a5c6f0fa40 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -651,7 +651,7 @@ It is used as mark-configured SAD/SPD entry as part of the lookup key (both in data and control path) in ip xfrm (framework used to implement IPsec protocol). See - ip-xfrm - transform configuration for details. It is only used for VTI/VTI6 + ip-xfrm — transform configuration for details. It is only used for VTI/VTI6 tunnels. diff --git a/man/systemd.target.xml b/man/systemd.target.xml index 645d8493c1..2e35e54fc4 100644 --- a/man/systemd.target.xml +++ b/man/systemd.target.xml @@ -88,7 +88,7 @@ configured dependencies of type Wants= or Requires= with dependencies of type After=. Note that Wants= or - Requires= must be defined in the target unit itself - if + Requires= must be defined in the target unit itself — if you for example define Wants=some.target in some.service, the implicit ordering will not be added. -- cgit v1.2.3-54-g00ecf From 7fbbf283c8b1cebf29d14acf9ff6587ad525cbc2 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Sat, 16 Jul 2016 18:51:45 +0200 Subject: man: mention system-shutdown hook directory in synopsis (#3741) The distinction between systemd-shutdown the binary vs system-shutdown the hook directory (without the 'd') is not immediately obvious and can be quite confusing if you are looking for a directory which doesn't exist. Therefore explicitly mention the hook directory in the synopsis with a trailing slash to make it clearer which is which. --- man/systemd-halt.service.xml | 1 + 1 file changed, 1 insertion(+) (limited to 'man') diff --git a/man/systemd-halt.service.xml b/man/systemd-halt.service.xml index c94e2a1820..d16e5d628f 100644 --- a/man/systemd-halt.service.xml +++ b/man/systemd-halt.service.xml @@ -57,6 +57,7 @@ systemd-reboot.service systemd-kexec.service /usr/lib/systemd/systemd-shutdown + /usr/lib/systemd/system-shutdown/ -- cgit v1.2.3-54-g00ecf From fc549b96054d52bbde68a4aa773bf4037700d389 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 28 Jun 2016 15:12:01 -0400 Subject: Drop parentheses in two places --- man/systemd-resolved.service.xml | 4 ++-- src/basic/strv.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 0df037ba69..141b06e374 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -68,8 +68,8 @@ link-local networking). The glibc - getaddrinfo3 API (as defined - by RFC3493) and its related resolver functions, + getaddrinfo3 API as defined + by RFC3493 and its related resolver functions, including gethostbyname3. This API is widely supported, including beyond the Linux platform. In its current form it does not expose DNSSEC validation status information however, and is synchronous only. This API is backed by the glibc Name Service diff --git a/src/basic/strv.c b/src/basic/strv.c index e0e2d1ebbe..db315ac10a 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -803,9 +803,8 @@ char **strv_reverse(char **l) { if (n <= 1) return l; - for (i = 0; i < n / 2; i++) { + for (i = 0; i < n / 2; i++) SWAP_TWO(l[i], l[n-1-i]); - } return l; } -- cgit v1.2.3-54-g00ecf From 4c5db93f8a3fe5f332f07af0cf5d17260cb0e861 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Jul 2016 17:10:26 -0700 Subject: man: document that sd_journal_print() strips trailing whitespace --- man/sd_journal_print.xml | 86 ++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 51 deletions(-) (limited to 'man') diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml index 17fdc9c1f2..6fe078d88e 100644 --- a/man/sd_journal_print.xml +++ b/man/sd_journal_print.xml @@ -93,27 +93,20 @@ Description - sd_journal_print() may be used to - submit simple, plain text log entries to the system journal. The - first argument is a priority value. This is followed by a format - string and its parameters, similar to - printf3 - or + sd_journal_print() may be used to submit simple, plain text log entries to the system + journal. The first argument is a priority value. This is followed by a format string and its parameters, similar to + printf3 or syslog3. - The priority value is one of - LOG_EMERG, - LOG_ALERT, - LOG_CRIT, - LOG_ERR, - LOG_WARNING, - LOG_NOTICE, - LOG_INFO, - LOG_DEBUG, as defined in - syslog.h, see - syslog3 - for details. It is recommended to use this call to submit log - messages in the application locale or system locale and in UTF-8 - format, but no such restrictions are enforced. + The priority value is one of LOG_EMERG, LOG_ALERT, + LOG_CRIT, LOG_ERR, LOG_WARNING, + LOG_NOTICE, LOG_INFO, LOG_DEBUG, as defined in + syslog.h, see syslog3 for details. It is + recommended to use this call to submit log messages in the application locale or system locale and in UTF-8 format, + but no such restrictions are enforced. Note that log messages written using this function are generally not + expected to end in a new-line character. However, as all trailing whitespace (including spaces, new-lines, + tabulators and carriage returns) are automatically stripped from the logged string, it is acceptable to specify one + (or more). Leading whitespace (as well as inner whitespace) is left unmodified however. sd_journal_printv() is similar to sd_journal_print() but takes a variable @@ -123,35 +116,26 @@ for more information) instead of the format string. It is otherwise equivalent in behavior. - sd_journal_send() may be used to submit - structured log entries to the system journal. It takes a series of - format strings, each immediately followed by their associated - parameters, terminated by NULL. The strings - passed should be of the format VARIABLE=value. - The variable name must be in uppercase and consist only of - characters, numbers and underscores, and may not begin with an - underscore. (All assignments that do not follow this syntax will - be ignored.) The value can be of any size and format. It is highly - recommended to submit text strings formatted in the UTF-8 - character encoding only, and submit binary fields only when - formatting in UTF-8 strings is not sensible. A number of - well-known fields are defined, see - systemd.journal-fields7 - for details, but additional application defined fields may be - used. A variable may be assigned more than one value per - entry. - - sd_journal_sendv() is similar to - sd_journal_send() but takes an array of - struct iovec (as defined in - uio.h, see - readv3 - for details) instead of the format string. Each structure should - reference one field of the entry to submit. The second argument - specifies the number of structures in the array. - sd_journal_sendv() is particularly useful to - submit binary objects to the journal where that is - necessary. + sd_journal_send() may be used to submit structured log entries to the system journal. It + takes a series of format strings, each immediately followed by their associated parameters, terminated by + NULL. The strings passed should be of the format VARIABLE=value. The + variable name must be in uppercase and consist only of characters, numbers and underscores, and may not begin with + an underscore. (All assignments that do not follow this syntax will be ignored.) The value can be of any size and + format. It is highly recommended to submit text strings formatted in the UTF-8 character encoding only, and submit + binary fields only when formatting in UTF-8 strings is not sensible. A number of well-known fields are defined, see + systemd.journal-fields7 for + details, but additional application defined fields may be used. A variable may be assigned more than one value per + entry. If this function is used, trailing whitespace is automatically removed from each formatted field. + + sd_journal_sendv() is similar to sd_journal_send() but takes an + array of struct iovec (as defined in uio.h, see readv3 for details) + instead of the format string. Each structure should reference one field of the entry to submit. The second argument + specifies the number of structures in the array. sd_journal_sendv() is particularly useful to + submit binary objects to the journal where that is necessary. Note that this function wil not strip trailing + whitespace of the passed fields, but passes the specified data along unmodified. This is different from both + sd_journal_print() and sd_journal_send() described above, which are based + on format strings, and do strip trailing whitespace. sd_journal_perror() is a similar to perror3 @@ -174,8 +158,8 @@ sd_journal_print(LOG_INFO, "Hello World, this is PID %lu!", (unsigned long) getpid()); sd_journal_send("MESSAGE=Hello World, this is PID %lu!", (unsigned long) getpid(), - "PRIORITY=%i", LOG_INFO, - NULL); + "PRIORITY=%i", LOG_INFO, + NULL); Note that these calls implicitly add fields for the source file, function name and code line where invoked. This is -- cgit v1.2.3-54-g00ecf From c4b41707462a74eb7008e8d12a0b4d0a0c09bff4 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Wed, 6 Jul 2016 09:48:58 +0200 Subject: namespace: unify limit behavior on non-directory paths Despite the name, `Read{Write,Only}Directories=` already allows for regular file paths to be masked. This commit adds the same behavior to `InaccessibleDirectories=` and makes it explicit in the doc. This patch introduces `/run/systemd/inaccessible/{reg,dir,chr,blk,fifo,sock}` {dile,device}nodes and mounts on the appropriate one the paths specified in `InacessibleDirectories=`. Based on Luca's patch from https://github.com/systemd/systemd/pull/3327 --- man/systemd.exec.xml | 14 ++++++++------ src/basic/mount-util.c | 18 ++++++++++++++++++ src/basic/mount-util.h | 2 ++ src/core/dbus-execute.c | 12 ++++++------ src/core/mount-setup.c | 14 +++++++++++--- src/core/namespace.c | 31 +++++++++++++++++++++++-------- 6 files changed, 68 insertions(+), 23 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index ed02666daf..e982333434 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -855,24 +855,26 @@ Sets up a new file system namespace for executed processes. These options may be used to limit access a process might have to the main file system hierarchy. Each - setting takes a space-separated list of directory paths relative to + setting takes a space-separated list of paths relative to the host's root directory (i.e. the system running the service manager). - Directories listed in + Note that if entries contain symlinks, they are resolved from the host's root directory as well. + Entries (files or directories) listed in ReadWriteDirectories= are accessible from within the namespace with the same access rights as from - outside. Directories listed in + outside. Entries listed in ReadOnlyDirectories= are accessible for reading only, writing will be refused even if the usual file - access controls would permit this. Directories listed in + access controls would permit this. Entries listed in InaccessibleDirectories= will be made inaccessible for processes inside the namespace, and may not countain any other mountpoints, including those specified by ReadWriteDirectories= or ReadOnlyDirectories=. Note that restricting access with these options does not extend - to submounts of a directory that are created later on. These + to submounts of a directory that are created later on. + Non-directory paths can be specified as well. These options may be specified more than once, in which case all - directories listed will have limited access from within the + paths listed will have limited access from within the namespace. If the empty string is assigned to this option, the specific list is reset, and all prior assignments have no effect. diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 90b7a885a8..63dff3dd5c 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -532,3 +532,21 @@ int repeat_unmount(const char *path, int flags) { done = true; } } + +const char* mode_to_inaccessible_node(mode_t mode) { + switch(mode & S_IFMT) { + case S_IFREG: + return "/run/systemd/inaccessible/reg"; + case S_IFDIR: + return "/run/systemd/inaccessible/dir"; + case S_IFCHR: + return "/run/systemd/inaccessible/chr"; + case S_IFBLK: + return "/run/systemd/inaccessible/blk"; + case S_IFIFO: + return "/run/systemd/inaccessible/fifo"; + case S_IFSOCK: + return "/run/systemd/inaccessible/sock"; + } + return NULL; +} diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index bdb525d6b0..f46989ebb3 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -49,4 +49,6 @@ union file_handle_union { char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; }; +const char* mode_to_inaccessible_node(mode_t mode); + #define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 644b9561b5..4588ecad09 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1346,12 +1346,12 @@ int bus_exec_context_set_transient_property( if (mode != UNIT_CHECK) { _cleanup_free_ char *joined = NULL; - if (streq(name, "ReadWriteDirectories")) - dirs = &c->read_write_dirs; - else if (streq(name, "ReadOnlyDirectories")) - dirs = &c->read_only_dirs; - else /* "InaccessibleDirectories" */ - dirs = &c->inaccessible_dirs; + if (STR_IN_SET(name, "ReadWriteDirectories", "ReadWritePaths")) + dirs = &c->read_write_paths; + else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths")) + dirs = &c->read_only_paths; + else /* "InaccessiblePaths" */ + dirs = &c->inaccessible_paths; if (strv_length(l) == 0) { *dirs = strv_free(*dirs); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index f9c9b4a91f..5d8ab0ec70 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -28,6 +28,7 @@ #include "cgroup-util.h" #include "dev-setup.h" #include "efivars.h" +#include "fs-util.h" #include "label.h" #include "log.h" #include "macro.h" @@ -403,9 +404,16 @@ int mount_setup(bool loaded_policy) { * really needs to stay for good, otherwise software that * copied sd-daemon.c into their sources will misdetect * systemd. */ - mkdir_label("/run/systemd", 0755); - mkdir_label("/run/systemd/system", 0755); - mkdir_label("/run/systemd/inaccessible", 0000); + (void) mkdir_label("/run/systemd", 0755); + (void) mkdir_label("/run/systemd/system", 0755); + (void) mkdir_label("/run/systemd/inaccessible", 0000); + /* Set up inaccessible items */ + (void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0); + (void) mkdir_label("/run/systemd/inaccessible/dir", 0000); + (void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0)); + (void) mknod("/run/systemd/inaccessible/blk", S_IFBLK | 0000, makedev(0, 0)); + (void) mkfifo("/run/systemd/inaccessible/fifo", 0000); + (void) mknod("/run/systemd/inaccessible/sock", S_IFSOCK | 0000, 0); return 0; } diff --git a/src/core/namespace.c b/src/core/namespace.c index 203d122810..e465e825a1 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -278,6 +278,7 @@ static int apply_mount( const char *what; int r; + struct stat target; assert(m); @@ -287,12 +288,22 @@ static int apply_mount( /* First, get rid of everything that is below if there * is anything... Then, overmount it with an - * inaccessible directory. */ + * inaccessible path. */ umount_recursive(m->path, 0); - what = "/run/systemd/inaccessible"; - break; + r = lstat(m->path, &target); + if (r != 0) { + if (m->ignore && errno == ENOENT) + return 0; + return -errno; + } + what = mode_to_inaccessible_node(target.st_mode); + if (what == NULL) { + log_debug("File type not supported. Note that symlinks are not allowed"); + return -ELOOP; + } + break; case READONLY: case READWRITE: /* Nothing to mount here, we just later toggle the @@ -317,12 +328,16 @@ static int apply_mount( assert(what); r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL); - if (r >= 0) + if (r >= 0) { log_debug("Successfully mounted %s to %s", what, m->path); - else if (m->ignore && errno == ENOENT) - return 0; - - return r; + return r; + } + else { + if (m->ignore && errno == ENOENT) + return 0; + log_debug("Failed mounting %s to %s: %s", what, m->path, strerror(errno)); + return -errno; + } } static int make_read_only(BindMount *m) { -- cgit v1.2.3-54-g00ecf From 2a624c36e646e9ef8d204a506b12e7dbd380e111 Mon Sep 17 00:00:00 2001 From: Alessandro Puccetti Date: Thu, 7 Jul 2016 11:17:00 +0200 Subject: doc,core: Read{Write,Only}Paths= and InaccessiblePaths= This patch renames Read{Write,Only}Directories= and InaccessibleDirectories= to Read{Write,Only}Paths= and InaccessiblePaths=, previous names are kept as aliases but they are not advertised in the documentation. Renamed variables: `read_write_dirs` --> `read_write_paths` `read_only_dirs` --> `read_only_paths` `inaccessible_dirs` --> `inaccessible_paths` --- man/systemd.exec.xml | 28 +++++++++++++-------------- shell-completion/bash/systemd-run | 4 ++-- shell-completion/zsh/_systemd-run | 4 ++-- src/core/dbus-execute.c | 13 ++++++++----- src/core/execute.c | 36 +++++++++++++++++------------------ src/core/execute.h | 2 +- src/core/load-fragment-gperf.gperf.m4 | 9 ++++++--- src/core/namespace.c | 18 +++++++++--------- src/core/namespace.h | 6 +++--- src/shared/bus-unit-util.c | 3 ++- 10 files changed, 65 insertions(+), 58 deletions(-) (limited to 'man') diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index e982333434..49fea98a95 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -848,9 +848,9 @@ - ReadWriteDirectories= - ReadOnlyDirectories= - InaccessibleDirectories= + ReadWritePaths= + ReadOnlyPaths= + InaccessiblePaths= Sets up a new file system namespace for executed processes. These options may be used to limit access @@ -858,18 +858,18 @@ setting takes a space-separated list of paths relative to the host's root directory (i.e. the system running the service manager). Note that if entries contain symlinks, they are resolved from the host's root directory as well. - Entries (files or directories) listed in - ReadWriteDirectories= are accessible from + Entries (files or directories) listed in + ReadWritePaths= are accessible from within the namespace with the same access rights as from outside. Entries listed in - ReadOnlyDirectories= are accessible for + ReadOnlyPaths= are accessible for reading only, writing will be refused even if the usual file access controls would permit this. Entries listed in - InaccessibleDirectories= will be made + InaccessiblePaths= will be made inaccessible for processes inside the namespace, and may not countain any other mountpoints, including those specified by - ReadWriteDirectories= or - ReadOnlyDirectories=. + ReadWritePaths= or + ReadOnlyPaths=. Note that restricting access with these options does not extend to submounts of a directory that are created later on. Non-directory paths can be specified as well. These @@ -879,9 +879,9 @@ specific list is reset, and all prior assignments have no effect. Paths in - ReadOnlyDirectories= + ReadOnlyPaths= and - InaccessibleDirectories= + InaccessiblePaths= may be prefixed with -, in which case they will be ignored when they do not @@ -1036,9 +1036,9 @@ PrivateDevices=, ProtectSystem=, ProtectHome=, - ReadOnlyDirectories=, - InaccessibleDirectories= and - ReadWriteDirectories=) require that mount + ReadOnlyPaths=, + InaccessiblePaths= and + ReadWritePaths=) require that mount and unmount propagation from the unit's file system namespace is disabled, and hence downgrade to . diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index 8152b021e7..022331e6a9 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -84,8 +84,8 @@ _systemd_run() { LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= - SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= - ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= + SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWritePaths= + ReadOnlyPaths= InaccessiblePaths= EnvironmentFile= ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment=' COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run index c425085cd8..6362b97766 100644 --- a/shell-completion/zsh/_systemd-run +++ b/shell-completion/zsh/_systemd-run @@ -37,8 +37,8 @@ _arguments \ LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \ PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= \ TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= \ - SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= \ - ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= \ + SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWritePaths= \ + ReadOnlyPaths= InaccessiblePaths= EnvironmentFile= \ ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment= \ ))' \ '--description=[Description for unit]:description' \ diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 4588ecad09..b2ef3db491 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -695,9 +695,12 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1323,8 +1326,8 @@ int bus_exec_context_set_transient_property( return 1; - } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { - + } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", + "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) { _cleanup_strv_free_ char **l = NULL; char ***dirs; char **p; diff --git a/src/core/execute.c b/src/core/execute.c index f4f5723c35..05dc1aaec1 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1507,9 +1507,9 @@ static bool exec_needs_mount_namespace( assert(context); assert(params); - if (!strv_isempty(context->read_write_dirs) || - !strv_isempty(context->read_only_dirs) || - !strv_isempty(context->inaccessible_dirs)) + if (!strv_isempty(context->read_write_paths) || + !strv_isempty(context->read_only_paths) || + !strv_isempty(context->inaccessible_paths)) return true; if (context->mount_flags != 0) @@ -1933,9 +1933,9 @@ static int exec_child( r = setup_namespace( params->apply_chroot ? context->root_directory : NULL, - context->read_write_dirs, - context->read_only_dirs, - context->inaccessible_dirs, + context->read_write_paths, + context->read_only_paths, + context->inaccessible_paths, tmp, var, context->private_devices, @@ -2324,9 +2324,9 @@ void exec_context_done(ExecContext *c) { c->pam_name = mfree(c->pam_name); - c->read_only_dirs = strv_free(c->read_only_dirs); - c->read_write_dirs = strv_free(c->read_write_dirs); - c->inaccessible_dirs = strv_free(c->inaccessible_dirs); + c->read_only_paths = strv_free(c->read_only_paths); + c->read_write_paths = strv_free(c->read_write_paths); + c->inaccessible_paths = strv_free(c->inaccessible_paths); if (c->cpuset) CPU_FREE(c->cpuset); @@ -2732,21 +2732,21 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { if (c->pam_name) fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name); - if (strv_length(c->read_write_dirs) > 0) { - fprintf(f, "%sReadWriteDirs:", prefix); - strv_fprintf(f, c->read_write_dirs); + if (strv_length(c->read_write_paths) > 0) { + fprintf(f, "%sReadWritePaths:", prefix); + strv_fprintf(f, c->read_write_paths); fputs("\n", f); } - if (strv_length(c->read_only_dirs) > 0) { - fprintf(f, "%sReadOnlyDirs:", prefix); - strv_fprintf(f, c->read_only_dirs); + if (strv_length(c->read_only_paths) > 0) { + fprintf(f, "%sReadOnlyPaths:", prefix); + strv_fprintf(f, c->read_only_paths); fputs("\n", f); } - if (strv_length(c->inaccessible_dirs) > 0) { - fprintf(f, "%sInaccessibleDirs:", prefix); - strv_fprintf(f, c->inaccessible_dirs); + if (strv_length(c->inaccessible_paths) > 0) { + fprintf(f, "%sInaccessiblePaths:", prefix); + strv_fprintf(f, c->inaccessible_paths); fputs("\n", f); } diff --git a/src/core/execute.h b/src/core/execute.h index cacf66cf51..73b8a119b0 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -152,7 +152,7 @@ struct ExecContext { bool smack_process_label_ignore; char *smack_process_label; - char **read_write_dirs, **read_only_dirs, **inaccessible_dirs; + char **read_write_paths, **read_only_paths, **inaccessible_paths; unsigned long mount_flags; uint64_t capability_bounding_set; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index fe1006830b..6a5c16a000 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -80,9 +80,12 @@ $1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQ $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) $1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) -$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) -$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs) -$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) +$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths) +$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths) +$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths) +$1.ReadWritePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths) +$1.ReadOnlyPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths) +$1.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths) $1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp) $1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices) diff --git a/src/core/namespace.c b/src/core/namespace.c index e465e825a1..722538caf1 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -362,9 +362,9 @@ static int make_read_only(BindMount *m) { int setup_namespace( const char* root_directory, - char** read_write_dirs, - char** read_only_dirs, - char** inaccessible_dirs, + char** read_write_paths, + char** read_only_paths, + char** inaccessible_paths, const char* tmp_dir, const char* var_tmp_dir, bool private_dev, @@ -383,9 +383,9 @@ int setup_namespace( return -errno; n = !!tmp_dir + !!var_tmp_dir + - strv_length(read_write_dirs) + - strv_length(read_only_dirs) + - strv_length(inaccessible_dirs) + + strv_length(read_write_paths) + + strv_length(read_only_paths) + + strv_length(inaccessible_paths) + private_dev + (protect_home != PROTECT_HOME_NO ? 3 : 0) + (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) + @@ -393,15 +393,15 @@ int setup_namespace( if (n > 0) { m = mounts = (BindMount *) alloca0(n * sizeof(BindMount)); - r = append_mounts(&m, read_write_dirs, READWRITE); + r = append_mounts(&m, read_write_paths, READWRITE); if (r < 0) return r; - r = append_mounts(&m, read_only_dirs, READONLY); + r = append_mounts(&m, read_only_paths, READONLY); if (r < 0) return r; - r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE); + r = append_mounts(&m, inaccessible_paths, INACCESSIBLE); if (r < 0) return r; diff --git a/src/core/namespace.h b/src/core/namespace.h index b54b7b47d6..1aedf5f208 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -40,9 +40,9 @@ typedef enum ProtectSystem { } ProtectSystem; int setup_namespace(const char *chroot, - char **read_write_dirs, - char **read_only_dirs, - char **inaccessible_dirs, + char **read_write_paths, + char **read_only_paths, + char **inaccessible_paths, const char *tmp_dir, const char *var_tmp_dir, bool private_dev, diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 04471e2373..94ffa8af87 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -453,7 +453,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } r = sd_bus_message_append(m, "v", "i", oa); - } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { + } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", + "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) { const char *p; r = sd_bus_message_open_container(m, 'v', "as"); -- cgit v1.2.3-54-g00ecf From 0d23bc57da6a3aeb1e7f92cfd7da2cd831b7c11c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 14:27:05 +0200 Subject: sd-journal: suppress empty lines Let's make sure our logging APIs is in sync with how stdout/stderr logging works. --- man/sd_journal_print.xml | 3 ++- src/journal/journal-send.c | 11 ++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'man') diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml index 6fe078d88e..76542527fc 100644 --- a/man/sd_journal_print.xml +++ b/man/sd_journal_print.xml @@ -106,7 +106,8 @@ but no such restrictions are enforced. Note that log messages written using this function are generally not expected to end in a new-line character. However, as all trailing whitespace (including spaces, new-lines, tabulators and carriage returns) are automatically stripped from the logged string, it is acceptable to specify one - (or more). Leading whitespace (as well as inner whitespace) is left unmodified however. + (or more). Empty lines (after trailing whitespace removal) are suppressed. On non-empty lines, leading whitespace + (as well as inner whitespace) is left unmodified. sd_journal_printv() is similar to sd_journal_print() but takes a variable diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index 1b92585488..440fba67ca 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -110,6 +110,10 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) { /* Strip trailing whitespace, keep prefix whitespace. */ (void) strstrip(buffer); + /* Suppress empty lines */ + if (isempty(buffer+8)) + return 0; + zero(iov); IOVEC_SET_STRING(iov[0], buffer); IOVEC_SET_STRING(iov[1], p); @@ -476,7 +480,12 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); - (void) strstrip(buffer); /* strip trailing whitespace, keep prefixing whitespace */ + /* Strip trailing whitespace, keep prefixing whitespace */ + (void) strstrip(buffer); + + /* Suppress empty lines */ + if (isempty(buffer+8)) + return 0; /* func is initialized from __func__ which is not a macro, but * a static const char[], hence cannot easily be prefixed with -- cgit v1.2.3-54-g00ecf From dfc6109fcd7cd8987ca77326eef25c0deb25abd9 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Tue, 19 Jul 2016 15:24:23 -0400 Subject: man: mention that locale changes might require initramfs to be rebuilt (#3754) https://bugzilla.redhat.com/show_bug.cgi?id=1151651 Also explain what localectl does a bit better: https://bugzilla.redhat.com/show_bug.cgi?id=1357861 --- man/localectl.xml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/localectl.xml b/man/localectl.xml index 7def047f62..8d2becb5d9 100644 --- a/man/localectl.xml +++ b/man/localectl.xml @@ -60,7 +60,10 @@ Description localectl may be used to query and change - the system locale and keyboard layout settings. + the system locale and keyboard layout settings. It communicates with + systemd-localed8 + to modify files such as /etc/locale.conf and + /etc/vconsole.conf. The system locale controls the language settings of system services and of the UI before the user logs in, such as the @@ -72,9 +75,14 @@ such as the display manager, as well as the default for users after login. - Use + Note that the changes performed using this tool might require + the initramfs to be rebuilt to take effect during early system boot. + The initramfs is not rebuilt automatically by localectl. + + + Note that systemd-firstboot1 - to initialize the system locale for mounted (but not booted) + may be used to initialize the system locale for mounted (but not booted) system images. @@ -214,7 +222,8 @@ , systemctl1, systemd-localed.service8, - systemd-firstboot1 + systemd-firstboot1, + mkinitrd8 -- cgit v1.2.3-54-g00ecf From 13317a22e5cf8f7c458616a971e60e84255bc364 Mon Sep 17 00:00:00 2001 From: mulkieran Date: Tue, 19 Jul 2016 23:15:22 -0400 Subject: man: revise entry about specifying a file path (#3739) * Specifying a device node has an effect much larger than a simple shortcut for a field/value match, so the original sentence is no longer a good way to start the paragraph. * Specifying a device node causes matches to be generated for all ancestor devices of the device specified, not just its parents. * Indicates that the path must be absolute, but that it may be a link. * Eliminates a few typos. --- man/journalctl.xml | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'man') diff --git a/man/journalctl.xml b/man/journalctl.xml index 29239c6315..e77621d7b3 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -87,18 +87,26 @@ causes all matches before and after to be combined in a disjunction (i.e. logical OR). - As shortcuts for a few types of field/value matches, file - paths may be specified. If a file path refers to an executable - file, this is equivalent to an _EXE= match - for the canonicalized binary path. Similarly, if a path refers - to a device node then match is added for the kernel name of the - device (_KERNEL_DEVICE=). Also, matches for the - kernel names of all the parent devices are added automatically. - Device node paths are not stable across reboots, therefore match - for the current boot id (_BOOT_ID=) is - always added as well. Note that only the log entries for - the existing device nodes maybe queried by providing path to - the device node. + It is also possible to filter the entries by specifying an + absolute file path as an argument. The file path may be a file or + a symbolic link and the file must exist at the time of the query. If a + file path refers to an executable binary, an _EXE= + match for the canonicalized binary path is added to the query. If a + file path refers to an executable script, a _COMM= + match for the script name is added to the query. If a file path + refers to a device node, _KERNEL_DEVICE= matches for + the kernel name of the device and for each of its ancestor devices is + added to the query. Symbolic links are dereferenced, kernel names are + synthesized, and parent devices are identified from the environment at + the time of the query. In general, a device node is the best proxy for + an actual device, as log entries do not usually contain fields that + identify an actual device. For the resulting log entries to be correct + for the actual device, the relevant parts of the environment at the time + the entry was logged, in particular the actual device corresponding to + the device node, must have been the same as those at the time of the + query. Because device nodes generally change their corresponding devices + across reboots, specifying a device node path causes the resulting + entries to be restricted to those from the current boot. Additional constraints may be added using options , , etc., to -- cgit v1.2.3-54-g00ecf From 891a15cab2d9df187bb55903223bc2a569cf9f5d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 20 Jul 2016 09:17:33 +0200 Subject: man: document a tiny bit better what udev_device_get_is_initialized() actually returns --- man/udev_device_get_syspath.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/udev_device_get_syspath.xml b/man/udev_device_get_syspath.xml index b54749ed56..014f43b21c 100644 --- a/man/udev_device_get_syspath.xml +++ b/man/udev_device_get_syspath.xml @@ -184,10 +184,10 @@ to such a parent device. On failure, NULL is returned. - On success, udev_device_get_is_initialized() - returns either 1 or 0, - depending on whether the passed device is initialized or not. On - failure, a negative error code is returned. + On success, udev_device_get_is_initialized() returns either 1 or + 0, depending on whether the passed device has already been initialized by udev or not. On + failure, a negative error code is returned. Note that devices for which no udev rules are defined are never + reported initialized. -- cgit v1.2.3-54-g00ecf From 00f69504a2c1861d98a027afdebc22c873f09083 Mon Sep 17 00:00:00 2001 From: Alexander Kurtz Date: Thu, 21 Jul 2016 02:29:54 +0200 Subject: bootctl: Always use upper case for "/EFI/BOOT" and "/EFI/BOOT/BOOT*.EFI". If the ESP is not mounted with "iocharset=ascii", but with "iocharset=utf8" (which is for example the default in Debian), the file system becomes case sensitive. This means that a file created as "FooBarBaz" cannot be accessed as "foobarbaz" since those are then considered different files. Moreover, a file created as "FooBar" can then also not be accessed as "foobar", and it also prevents such a file from being created, as both would use the same 8.3 short name "FOOBAR". Even though the UEFI specification [0] does give the canonical spelling for the files mentioned above, not all implementations completely conform to that, so it's possible that those files would already exist, but with a different spelling, causing subtle bugs when scanning or modifying the ESP. While the proper fix would of course be that everybody conformed to the standard, we can work around this problem by just referencing the files by their 8.3 short names, i.e. using upper case. Fixes: #3740 [0] , version 2.6, section 3.5.1.1 --- man/bootctl.xml | 4 ++-- src/boot/bootctl.c | 8 ++++---- test/test-efi-create-disk.sh | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'man') diff --git a/man/bootctl.xml b/man/bootctl.xml index ebd58750d3..6e835c037f 100644 --- a/man/bootctl.xml +++ b/man/bootctl.xml @@ -74,14 +74,14 @@ bootctl update updates all installed versions of systemd-boot, if the current version is newer than the version installed in the EFI system partition. This also includes - the EFI default/fallback loader at /EFI/Boot/boot*.efi. A + the EFI default/fallback loader at /EFI/BOOT/BOOT*.EFI. A systemd-boot entry in the EFI boot variables is created if there is no current entry. The created entry will be added to the end of the boot order list. bootctl install installs systemd-boot into the EFI system partition. A copy of systemd-boot will be stored as - the EFI default/fallback loader at /EFI/Boot/boot*.efi. A systemd-boot + the EFI default/fallback loader at /EFI/BOOT/BOOT*.EFI. A systemd-boot entry in the EFI boot variables is created and added to the top of the boot order list. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 52d79f1c67..7cb2259717 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -288,7 +288,7 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) { else if (r < 0) return r; - r = enumerate_binaries(esp_path, "EFI/Boot", "boot"); + r = enumerate_binaries(esp_path, "EFI/BOOT", "boot"); if (r == 0) log_error("No default/fallback boot loader installed in ESP."); else if (r < 0) @@ -548,7 +548,7 @@ static int mkdir_one(const char *prefix, const char *suffix) { static const char *efi_subdirs[] = { "EFI", "EFI/systemd", - "EFI/Boot", + "EFI/BOOT", "loader", "loader/entries" }; @@ -579,7 +579,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) { char *v; /* Create the EFI default boot loader name (specified for removable devices) */ - v = strjoina(esp_path, "/EFI/Boot/BOOT", name + strlen("systemd-boot")); + v = strjoina(esp_path, "/EFI/BOOT/BOOT", name + strlen("systemd-boot")); strupper(strrchr(v, '/') + 1); k = copy_file(p, v, force); @@ -781,7 +781,7 @@ static int remove_boot_efi(const char *esp_path) { struct dirent *de; int r, c = 0; - p = strjoina(esp_path, "/EFI/Boot"); + p = strjoina(esp_path, "/EFI/BOOT"); d = opendir(p); if (!d) { if (errno == ENOENT) diff --git a/test/test-efi-create-disk.sh b/test/test-efi-create-disk.sh index 56dd09abd7..cd4699dc18 100755 --- a/test/test-efi-create-disk.sh +++ b/test/test-efi-create-disk.sh @@ -11,8 +11,8 @@ mkfs.vfat -F32 ${LOOP}p1 mkdir -p mnt mount ${LOOP}p1 mnt -mkdir -p mnt/EFI/{Boot,systemd} -cp systemd-bootx64.efi mnt/EFI/Boot/bootx64.efi +mkdir -p mnt/EFI/{BOOT,systemd} +cp systemd-bootx64.efi mnt/EFI/BOOT/BOOTX64.efi [ -e /boot/shellx64.efi ] && cp /boot/shellx64.efi mnt/ -- cgit v1.2.3-54-g00ecf From 9ca8d43479dc198e8d6fc86492aa6576f97bbfc2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 21 Jul 2016 20:23:51 +0200 Subject: sd-id128: handle NULL return parameter in sd_id128_from_string() nicer If the return parameter is NULL, simply validate the string, and return no error. --- man/sd_id128_to_string.xml | 12 +++++------- src/libsystemd/sd-id128/sd-id128.c | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'man') diff --git a/man/sd_id128_to_string.xml b/man/sd_id128_to_string.xml index e70c80892e..927d1ad5f2 100644 --- a/man/sd_id128_to_string.xml +++ b/man/sd_id128_to_string.xml @@ -74,13 +74,11 @@ lowercase hexadecimal digits and be terminated by a NUL byte. - sd_id128_from_string() implements the - reverse operation: it takes a 33 character string with 32 - hexadecimal digits (either lowercase or uppercase, terminated by - NUL) and parses them back into a 128-bit ID - returned in ret. Alternatively, this call - can also parse a 37-character string with a 128-bit ID formatted - as RFC UUID. + sd_id128_from_string() implements the reverse operation: it takes a 33 character string + with 32 hexadecimal digits (either lowercase or uppercase, terminated by NUL) and parses them + back into a 128-bit ID returned in ret. Alternatively, this call can also parse a + 37-character string with a 128-bit ID formatted as RFC UUID. If ret is passed as NULL the + function will validate the passed ID string, but not actually return it in parsed form. For more information about the sd_id128_t type see diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 1470e4c01a..9f47d04e61 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -52,7 +52,6 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { bool is_guid = false; assert_return(s, -EINVAL); - assert_return(ret, -EINVAL); for (n = 0, i = 0; n < 16;) { int a, b; @@ -90,7 +89,8 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { if (s[i] != 0) return -EINVAL; - *ret = t; + if (ret) + *ret = t; return 0; } -- cgit v1.2.3-54-g00ecf From 487ddeb8bc1a05816802adb2d5a9dc4416b386fe Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 12:21:21 +0200 Subject: machine-id-setup: add new --print switch If specified we'll simply output the used machine ID. --- man/systemd-machine-id-setup.xml | 6 ++++++ src/machine-id-setup/machine-id-setup-main.c | 30 +++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'man') diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml index bfcd74f436..749987a937 100644 --- a/man/systemd-machine-id-setup.xml +++ b/man/systemd-machine-id-setup.xml @@ -151,6 +151,12 @@ early boot service. + + + + Print the machine ID generated or commited after the operation is complete. + + diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index b0199f181d..cc9b1b38fe 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -29,6 +29,7 @@ static char *arg_root = NULL; static bool arg_commit = false; +static bool arg_print = false; static void help(void) { printf("%s [OPTIONS...]\n\n" @@ -37,6 +38,7 @@ static void help(void) { " --version Show package version\n" " --root=ROOT Filesystem root\n" " --commit Commit transient ID\n" + " --print Print used machine ID\n" , program_invocation_short_name); } @@ -46,6 +48,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION = 0x100, ARG_ROOT, ARG_COMMIT, + ARG_PRINT, }; static const struct option options[] = { @@ -53,6 +56,7 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "root", required_argument, NULL, ARG_ROOT }, { "commit", no_argument, NULL, ARG_COMMIT }, + { "print", no_argument, NULL, ARG_PRINT }, {} }; @@ -82,6 +86,10 @@ static int parse_argv(int argc, char *argv[]) { arg_commit = true; break; + case ARG_PRINT: + arg_print = true; + break; + case '?': return -EINVAL; @@ -98,6 +106,8 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char *argv[]) { + char buf[SD_ID128_STRING_MAX]; + sd_id128_t id; int r; log_parse_environment(); @@ -107,10 +117,24 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - if (arg_commit) + if (arg_commit) { r = machine_id_commit(arg_root); - else - r = machine_id_setup(arg_root, SD_ID128_NULL, NULL); + if (r < 0) + goto finish; + + r = sd_id128_get_machine(&id); + if (r < 0) { + log_error_errno(r, "Failed to read machine ID back: %m"); + goto finish; + } + } else { + r = machine_id_setup(arg_root, SD_ID128_NULL, &id); + if (r < 0) + goto finish; + } + + if (arg_print) + puts(sd_id128_to_string(id, buf)); finish: free(arg_root); -- cgit v1.2.3-54-g00ecf From 83f8e80857090f63cf6a02c54d381dad3c0fad55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 15:58:49 +0200 Subject: core: support percentage specifications on TasksMax= This adds support for a TasksMax=40% syntax for specifying values relative to the system's configured maximum number of processes. This is useful in order to neatly subdivide the available room for tasks within containers. --- man/systemd.resource-control.xml | 15 +++++------ src/basic/util.c | 55 ++++++++++++++++++++++++++++++++++++++++ src/basic/util.h | 3 +++ src/core/dbus-cgroup.c | 22 ++++++++++++++++ src/core/load-fragment.c | 15 ++++++++--- src/shared/bus-unit-util.c | 35 ++++++++++++++----------- src/test/test-util.c | 38 +++++++++++++++++++++++++++ 7 files changed, 156 insertions(+), 27 deletions(-) (limited to 'man') diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 7263c0b329..bf44a68345 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -327,15 +327,12 @@ TasksMax=N - Specify the maximum number of tasks that may be - created in the unit. This ensures that the number of tasks - accounted for the unit (see above) stays below a specific - limit. If assigned the special value - infinity, no tasks limit is applied. This - controls the pids.max control group - attribute. For details about this control group attribute, - see pids.txt. + Specify the maximum number of tasks that may be created in the unit. This ensures that the number of + tasks accounted for the unit (see above) stays below a specific limit. This either takes an absolute number + of tasks or a percentage value that is taken relative to the configured maximum number of tasks on the + system. If assigned the special value infinity, no tasks limit is applied. This controls + the pids.max control group attribute. For details about this control group attribute, see + pids.txt. Implies TasksAccounting=true. The system default for this setting may be controlled with diff --git a/src/basic/util.c b/src/basic/util.c index 09d16697b7..c4b6fc2925 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -832,6 +832,61 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) { return r; } +uint64_t system_tasks_max(void) { + +#if SIZEOF_PID_T == 4 +#define TASKS_MAX ((uint64_t) (INT32_MAX-1)) +#elif SIZEOF_PID_T == 2 +#define TASKS_MAX ((uint64_t) (INT16_MAX-1)) +#else +#error "Unknown pid_t size" +#endif + + _cleanup_free_ char *value = NULL, *root = NULL; + uint64_t a = TASKS_MAX, b = TASKS_MAX; + + /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this + * limit: + * + * a) the maximum value for the pid_t type + * b) the cgroups pids_max attribute for the system + * c) the kernel's configure maximum PID value + * + * And then pick the smallest of the three */ + + if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0) + (void) safe_atou64(value, &a); + + if (cg_get_root_path(&root) >= 0) { + value = mfree(value); + + if (cg_get_attribute("pids", root, "pids.max", &value) >= 0) + (void) safe_atou64(value, &b); + } + + return MIN3(TASKS_MAX, + a <= 0 ? TASKS_MAX : a, + b <= 0 ? TASKS_MAX : b); +} + +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { + uint64_t t, m; + + assert(max > 0); + + /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages + * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */ + + t = system_tasks_max(); + assert(t > 0); + + m = t * v; + if (m / t != v) /* overflow? */ + return UINT64_MAX; + + return m / max; +} + int update_reboot_parameter_and_warn(const char *param) { int r; diff --git a/src/basic/util.h b/src/basic/util.h index db105197e8..8500c3077c 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -186,6 +186,9 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int uint64_t physical_memory(void); uint64_t physical_memory_scale(uint64_t v, uint64_t max); +uint64_t system_tasks_max(void); +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); + int update_reboot_parameter_and_warn(const char *param); int version(void); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 6167ce92cd..b3e2830c11 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -1060,6 +1060,8 @@ int bus_cgroup_set_property( r = sd_bus_message_read(message, "t", &limit); if (r < 0) return r; + if (limit <= 0) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name); if (mode != UNIT_CHECK) { c->tasks_max = limit; @@ -1071,6 +1073,26 @@ int bus_cgroup_set_property( unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit); } + return 1; + } else if (streq(name, "TasksMaxScale")) { + uint64_t limit; + uint32_t raw; + + r = sd_bus_message_read(message, "u", &raw); + if (r < 0) + return r; + + limit = system_tasks_max_scale(raw, UINT32_MAX); + if (limit <= 0 || limit >= UINT64_MAX) + return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name); + + if (mode != UNIT_CHECK) { + c->tasks_max = limit; + unit_invalidate_cgroup(u, CGROUP_MASK_PIDS); + unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%", + (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX))); + } + return 1; } diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 782e420e4c..cd7bf9c707 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2861,9 +2861,18 @@ int config_parse_tasks_max( return 0; } - r = safe_atou64(rvalue, &u); - if (r < 0 || u < 1) { - log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); + r = parse_percent(rvalue); + if (r < 0) { + r = safe_atou64(rvalue, &u); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); + return 0; + } + } else + u = system_tasks_max_scale(r, 100U); + + if (u <= 0 || u >= UINT64_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue); return 0; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 94ffa8af87..e63e9195f1 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -148,6 +148,26 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "sv", field, "t", bytes); goto finish; + } else if (streq(field, "TasksMax")) { + uint64_t t; + + if (isempty(eq) || streq(eq, "infinity")) + t = (uint64_t) -1; + else { + r = parse_percent(eq); + if (r >= 0) { + r = sd_bus_message_append(m, "sv", "TasksMaxScale", "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U)); + goto finish; + } else { + r = safe_atou64(eq, &t); + if (r < 0) + return log_error_errno(r, "Failed to parse maximum tasks specification %s", assignment); + } + + } + + r = sd_bus_message_append(m, "sv", "TasksMax", "t", t); + goto finish; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); @@ -191,21 +211,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "b", r); - } else if (streq(field, "TasksMax")) { - uint64_t n; - - if (isempty(eq) || streq(eq, "infinity")) - n = (uint64_t) -1; - else { - r = safe_atou64(eq, &n); - if (r < 0) { - log_error("Failed to parse maximum tasks specification %s", assignment); - return -EINVAL; - } - } - - r = sd_bus_message_append(m, "v", "t", n); - } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) { uint64_t u; diff --git a/src/test/test-util.c b/src/test/test-util.c index e177612a9f..1b5cba86c1 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -308,7 +308,43 @@ static void test_physical_memory_scale(void) { /* overflow */ assert_se(physical_memory_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); +} + +static void test_system_tasks_max(void) { + uint64_t t; + + t = system_tasks_max(); + assert_se(t > 0); + assert_se(t < UINT64_MAX); + + log_info("Max tasks: %" PRIu64, t); +} + +static void test_system_tasks_max_scale(void) { + uint64_t t; + + t = system_tasks_max(); + + assert_se(system_tasks_max_scale(0, 100) == 0); + assert_se(system_tasks_max_scale(100, 100) == t); + + assert_se(system_tasks_max_scale(0, 1) == 0); + assert_se(system_tasks_max_scale(1, 1) == t); + assert_se(system_tasks_max_scale(2, 1) == 2*t); + + assert_se(system_tasks_max_scale(0, 2) == 0); + assert_se(system_tasks_max_scale(1, 2) == t/2); + assert_se(system_tasks_max_scale(2, 2) == t); + assert_se(system_tasks_max_scale(3, 2) == (3*t)/2); + assert_se(system_tasks_max_scale(4, 2) == t*2); + + assert_se(system_tasks_max_scale(0, UINT32_MAX) == 0); + assert_se(system_tasks_max_scale((UINT32_MAX-1)/2, UINT32_MAX-1) == t/2); + assert_se(system_tasks_max_scale(UINT32_MAX, UINT32_MAX) == t); + + /* overflow */ + assert_se(system_tasks_max_scale(UINT64_MAX/4, UINT64_MAX) == UINT64_MAX); } int main(int argc, char *argv[]) { @@ -327,6 +363,8 @@ int main(int argc, char *argv[]) { test_raw_clone(); test_physical_memory(); test_physical_memory_scale(); + test_system_tasks_max(); + test_system_tasks_max_scale(); return 0; } -- cgit v1.2.3-54-g00ecf From c06eec15d5816236c11e35b35e444f62f37b6ef6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 17:19:58 +0200 Subject: logind: change TasksMax= value for user logins to 33% Let's change from a fixed value of 12288 tasks per user to a relative value of 33%, which with the kernel's default of 32768 translates to 10813. This is a slight decrease of the limit, for no other reason than "33%" sounding like a nice round number that is close enough to 12288 (which would translate to 37.5%). (Well, it also has the nice effect of still leaving a bit of room in the PID space if there are 3 cooperating evil users that try to consume all PIDs... Also, I like my bikesheds blue). Since the new value is taken relative, and machined's TasksMax= setting defaults to 16384, 33% inside of containers is usually equivalent to 5406, which should still be ample space. To summarize: | on the host | in the container old default | 12288 | 12288 new default | 10813 | 5406 --- man/logind.conf.xml | 9 ++++----- src/login/logind-gperf.gperf | 2 +- src/login/logind-user.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ src/login/logind.c | 2 +- src/login/logind.conf.in | 2 +- src/login/logind.h | 1 + 6 files changed, 53 insertions(+), 8 deletions(-) (limited to 'man') diff --git a/man/logind.conf.xml b/man/logind.conf.xml index fe92277a1f..adba5a4131 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -315,12 +315,11 @@ UserTasksMax= - Sets the maximum number of OS tasks each user - may run concurrently. This controls the - TasksMax= setting of the per-user slice - unit, see + Sets the maximum number of OS tasks each user may run concurrently. This controls the + TasksMax= setting of the per-user slice unit, see systemd.resource-control5 - for details. Defaults to 12288 (12K). + for details. Defaults to 33%, which equals 10813 with the kernel's defaults on the host, but might be smaller + in OS containers. diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 6bd08adc05..0b6a5f3cf4 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -36,4 +36,4 @@ Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manag Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc) Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max) Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max) -Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max) +Login.UserTasksMax, config_parse_user_tasks_max,0, offsetof(Manager, user_tasks_max) diff --git a/src/login/logind-user.c b/src/login/logind-user.c index de44d369cf..f7d83909a0 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -870,3 +870,48 @@ int config_parse_tmpfs_size( return 0; } + +int config_parse_user_tasks_max( + 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) { + + uint64_t *m = data; + uint64_t k; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + /* First, try to parse as percentage */ + r = parse_percent(rvalue); + if (r > 0 && r < 100) + k = system_tasks_max_scale(r, 100U); + else { + + /* If the passed argument was not a percentage, or out of range, parse as byte size */ + + r = safe_atou64(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse tasks maximum, ignoring: %s", rvalue); + return 0; + } + } + + if (k <= 0 || k >= UINT64_MAX) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Tasks maximum out of range, ignoring: %s", rvalue); + return 0; + } + + *m = k; + return 0; +} diff --git a/src/login/logind.c b/src/login/logind.c index d01dd110ea..5ce36d28c7 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -62,7 +62,7 @@ static void manager_reset_config(Manager *m) { m->idle_action = HANDLE_IGNORE; m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */ - m->user_tasks_max = 12288; + m->user_tasks_max = system_tasks_max_scale(33U, 100U); /* 33% */ m->sessions_max = 8192; m->inhibitors_max = 8192; diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 32c0844cb6..6f720b7708 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -34,4 +34,4 @@ #RemoveIPC=yes #InhibitorsMax=8192 #SessionsMax=8192 -#UserTasksMax=12288 +#UserTasksMax=33% diff --git a/src/login/logind.h b/src/login/logind.h index 90431eb4b0..086fa1eeb5 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -187,6 +187,7 @@ const struct ConfigPerfItem* logind_gperf_lookup(const char *key, unsigned lengt int manager_set_lid_switch_ignore(Manager *m, usec_t until); int config_parse_tmpfs_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); +int config_parse_user_tasks_max(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 manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret); int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret); -- cgit v1.2.3-54-g00ecf From 79baeeb96d58676853521e10a358e85d83dac7f1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 19 Jul 2016 17:29:00 +0200 Subject: core: change TasksMax= default for system services to 15% As it turns out 512 is max number of tasks per service is hit by too many applications, hence let's bump it a bit, and make it relative to the system's maximum number of PIDs. With this change the new default is 15%. At the kernel's default pids_max value of 32768 this translates to 4915. At machined's default TasksMax= setting of 16384 this translates to 2457. Why 15%? Because it sounds like a round number and is close enough to 4096 which I was going for, i.e. an eight-fold increase over the old 512 Summary: | on the host | in a container old default | 512 | 512 new default | 4915 | 2457 --- man/systemd-system.conf.xml | 9 ++++----- src/core/main.c | 4 +++- src/core/manager.c | 2 +- src/core/system.conf | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'man') diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index 8833e73c72..1bb40fd234 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -325,12 +325,11 @@ DefaultTasksMax= - Configure the default value for the per-unit - TasksMax= setting. See + Configure the default value for the per-unit TasksMax= setting. See systemd.resource-control5 - for details. This setting applies to all unit types that - support resource control settings, with the exception of slice - units. Defaults to 512. + for details. This setting applies to all unit types that support resource control settings, with the exception + of slice units. Defaults to 15%, which equals 4915 with the kernel's defaults on the host, but might be smaller + in OS containers. diff --git a/src/core/main.c b/src/core/main.c index 4c767a3c9d..c59228ad53 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -127,7 +127,7 @@ static bool arg_default_io_accounting = false; static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; static bool arg_default_tasks_accounting = true; -static uint64_t arg_default_tasks_max = UINT64_C(512); +static uint64_t arg_default_tasks_max = UINT64_MAX; static sd_id128_t arg_machine_id = {}; noreturn static void freeze_or_reboot(void) { @@ -1558,6 +1558,8 @@ int main(int argc, char *argv[]) { (void) reset_all_signal_handlers(); (void) ignore_signals(SIGNALS_IGNORE, -1); + arg_default_tasks_max = system_tasks_max_scale(15U, 100U); /* 15% the system PIDs equals 4915 by default. */ + if (parse_config_file() < 0) { error_message = "Failed to parse config file"; goto finish; diff --git a/src/core/manager.c b/src/core/manager.c index a0181e2138..4d84a0b37e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -569,7 +569,7 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) { m->exit_code = _MANAGER_EXIT_CODE_INVALID; m->default_timer_accuracy_usec = USEC_PER_MINUTE; m->default_tasks_accounting = true; - m->default_tasks_max = UINT64_C(512); + m->default_tasks_max = UINT64_MAX; #ifdef ENABLE_EFI if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) diff --git a/src/core/system.conf b/src/core/system.conf index db8b7acd78..c6bb050aac 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -42,7 +42,7 @@ #DefaultBlockIOAccounting=no #DefaultMemoryAccounting=no #DefaultTasksAccounting=yes -#DefaultTasksMax=512 +#DefaultTasksMax=15% #DefaultLimitCPU= #DefaultLimitFSIZE= #DefaultLimitDATA= -- cgit v1.2.3-54-g00ecf From 5bd7342617d2f351136aff349e8fb066035353c8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Jul 2016 20:17:23 +0200 Subject: man: rework resolved.conf's Cache= documentation Let's not mention the supposed security benefit of turning off caching. It is really questionnable, and I#d rather not create the impression that we actually believed turning off caching would be a good idea. Instead, mention that Cache=no is implicit if a DNS server on the local host is used. --- man/resolved.conf.xml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'man') diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 024ad6a9c1..7556c6ff31 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -204,19 +204,13 @@ Cache= - Takes a boolean argument. If "yes" (the default), - resolving a domain name which already got queried earlier will re-use - the previous result as long as that is still valid, and thus does not - need to do an actual network request. - - However, local caching slightly increases the chance of a - successful DNS poisoning attack, and might also be a privacy problem in - some environments: By measuring the time it takes to resolve a - particular network name, a user can determine whether any other user on - the same machine recently visited that name. If either of these is a - concern, you may disable the local caching. Be aware that this comes at - a performance cost, which is very high with DNSSEC. - + Takes a boolean argument. If "yes" (the default), resolving a domain name which already got + queried earlier will return the previous result as long as it is still valid, and thus does not result in a new + network request. Be aware that that turning off caching comes at a performance penalty, which is particularly + high when DNSSEC is used. + + Note that caching is turned off implicitly if the configured DNS server is on a host-local IP address + (such as 127.0.0.1 or ::1), in order to avoid duplicate local caching. -- cgit v1.2.3-54-g00ecf From 3990961df02a255cb75cc80445535d153fc7f165 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 15:10:15 +0200 Subject: man: update systemctl man page for unit file commands, in particular "systemctl enable" Clarify that "systemctl enable" can operate either on unit names or on unit file paths (also, adjust the --help text to clarify this). Say that "systemctl enable" on unit file paths also links the unit into the search path. Many other fixes. This should improve the documentation to avoid further confusion around #3706. --- man/systemctl.xml | 187 +++++++++++++++++++++------------------------- src/systemctl/systemctl.c | 2 +- 2 files changed, 88 insertions(+), 101 deletions(-) (limited to 'man') diff --git a/man/systemctl.xml b/man/systemctl.xml index 742da81cfe..c7b830b7fb 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -973,70 +973,62 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service list-unit-files PATTERN... - List unit files installed in the file system and their enablement state - (as reported by is-enabled). If one or more - PATTERNs are specified, only units whose filename - (just the last component of the path) matches one of them are shown. + List unit files installed on the system, in combination with their enablement state (as reported by + is-enabled). If one or more PATTERNs are specified, only unit + files whose name matches one of them are shown (patterns matching unit file system paths are not + supported). enable NAME... + enable PATH... - Enable one or more unit files or unit file instances, - as specified on the command line. This will create a number - of symlinks as encoded in the [Install] - sections of the unit files. After the symlinks have been - created, the systemd configuration is reloaded (in a way that - is equivalent to daemon-reload) to ensure - the changes are taken into account immediately. Note that - this does not have the effect of also - starting any of the units being enabled. If this - is desired, either should be used - together with this command, or an additional start - command must be invoked for the unit. Also note that, in case of - instance enablement, symlinks named the same as instances - are created in the install location, however they all point to the - same template unit file. - - This command will print the actions executed. This - output may be suppressed by passing . + Enable one or more units or unit instances. This will create a set of symlinks, as encoded in the + [Install] sections of the indicated unit files. After the symlinks have been created, + the system manager configuration is reloaded (in a way equivalent to daemon-reload), in + order to ensure the changes are taken into account immediately. Note that this does + not have the effect of also starting any of the units being enabled. If this is + desired, combine this command with the switch, or invoke start + with appropriate arguments later. Note that in case of unit instance enablement (i.e. enablement of units of + the form foo@bar.service), symlinks named the same as instances are created in the + unit configuration diectory, however they point to the single template unit file they are instantiated + from. + + This command expects either valid unit names (in which case appropriate unit files for these names + are automatically searched in the various unit file directories), or absolute paths to unit files (in which + case these files are read directly). If a specified unit file is located outside of the unit file + directories searched automatically, an additional symlink is created, linking it into the unit + configuration path, thus ensuring it is automatically found when requested by commands such as + start. + + This command will print the file system operations executed. This output may be suppressed by passing + . - Note that this operation creates only the suggested - symlinks for the units. While this command is the - recommended way to manipulate the unit configuration - directory, the administrator is free to make additional - changes manually by placing or removing symlinks in the - directory. This is particularly useful to create - configurations that deviate from the suggested default - installation. In this case, the administrator must make sure - to invoke daemon-reload manually as - necessary to ensure the changes are taken into account. + Note that this operation creates only the symlinks suggested in the [Install] + section of the unit files. While this command is the recommended way to manipulate the unit configuration + directory, the administrator is free to make additional changes manually by placing or removing symlinks + below this directory. This is particularly useful to create configurations that deviate from the suggested + default installation. In this case, the administrator must make sure to invoke + daemon-reload manually as necessary, in order to ensure the changes are taken into + account. - Enabling units should not be confused with starting - (activating) units, as done by the start - command. Enabling and starting units is orthogonal: units - may be enabled without being started and started without - being enabled. Enabling simply hooks the unit into various - suggested places (for example, so that the unit is - automatically started on boot or when a particular kind of - hardware is plugged in). Starting actually spawns the daemon - process (in case of service units), or binds the socket (in - case of socket units), and so on. - - Depending on whether , - , , - or is specified, this enables the unit - for the system, for the calling user only, for only this boot of - the system, or for all future logins of all users, or only this - boot. Note that in the last case, no systemd daemon - configuration is reloaded. - - Using enable on masked units - results in an error. + Enabling units should not be confused with starting (activating) units, as done by the + start command. Enabling and starting units is orthogonal: units may be enabled without + being started and started without being enabled. Enabling simply hooks the unit into various suggested + places (for example, so that the unit is automatically started on boot or when a particular kind of + hardware is plugged in). Starting actually spawns the daemon process (in case of service units), or binds + the socket (in case of socket units), and so on. + + Depending on whether , , , + or is specified, this enables the unit for the system, for the calling user only, + for only this boot of the system, or for all future logins of all users, or only this boot. Note that in + the last case, no systemd daemon configuration is reloaded. + + Using enable on masked units is not supported and results in an error. @@ -1044,28 +1036,31 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service disable NAME... - Disables one or more units. This removes all symlinks - to the specified unit files from the unit configuration - directory, and hence undoes the changes made by - enable. Note however that this removes - all symlinks to the unit files (i.e. including manual - additions), not just those actually created by - enable. This call implicitly reloads the - systemd daemon configuration after completing the disabling - of the units. Note that this command does not implicitly - stop the units that are being disabled. If this is desired, either - should be used together with this command, or - an additional stop command should be executed - afterwards. - - This command will print the actions executed. This - output may be suppressed by passing . + Disables one or more units. This removes all symlinks to the unit files backing the specified units + from the unit configuration directory, and hence undoes any changes made by enable or + link. Note that this removes all symlinks to matching unit files, + including manually created symlinks, and not just those actually created by enable or + link. Note that while disable undoes the effect of + enable, the two commands are otherwise not symmetric, as disable may + remove more symlinks than a prior enable invocation of the same unit created. + + This command expects valid unit names only, it does not accept paths to unit files. + + In addition to the units specified as arguments, all units are disabled that are listed in the + Also= setting contained in the [Install] section of any of the unit + files being operated on. + + This command implicitly reloads the system manager configuration after completing the operation. Note + that this command does not implicitly stop the units that are being disabled. If this is desired, either + combine this command with the switch, or invoke the stop command + with appropriate arguments later. + + This command will print information about the file system operations (symlink removals) + executed. This output may be suppressed by passing . - This command honors , - , and - in a similar way as - enable. + This command honors , , + and in a similar way as enable. @@ -1073,12 +1068,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service reenable NAME... - Reenable one or more unit files, as specified on the - command line. This is a combination of - disable and enable and - is useful to reset the symlinks a unit is enabled with to - the defaults configured in the [Install] - section of the unit file. + Reenable one or more units, as specified on the command line. This is a combination of + disable and enable and is useful to reset the symlinks a unit file is + enabled with to the defaults configured in its [Install] section. This commands expects + a unit uname only, it does not accept paths to unit files. @@ -1209,16 +1202,13 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service mask NAME... - Mask one or more unit files, as specified on the - command line. This will link these units to - /dev/null, making it impossible to - start them. This is a stronger version of - disable, since it prohibits all kinds of - activation of the unit, including enablement and manual - activation. Use this option with care. This honors the - option to only mask temporarily - until the next reboot of the system. The - option can be used to ensure that the units are also stopped. + Mask one or more units, as specified on the command line. This will link these unit files to + /dev/null, making it impossible to start them. This is a stronger version of + disable, since it prohibits all kinds of activation of the unit, including enablement + and manual activation. Use this option with care. This honors the option to only + mask temporarily until the next reboot of the system. The option may be used to + ensure that the units are also stopped. This command expects valid unit names only, it does not accept unit + file paths. @@ -1226,23 +1216,20 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service unmask NAME... - Unmask one or more unit files, as specified on the - command line. This will undo the effect of - mask. + Unmask one or more unit files, as specified on the command line. This will undo the effect of + mask. This command expects valid unit names only, it does not accept unit file + paths. - link FILENAME... + link PATH... - Link a unit file that is not in the unit file search - paths into the unit file search path. This requires an - absolute path to a unit file. The effect of this can be - undone with disable. The effect of this - command is that a unit file is available for - start and other commands although it - is not installed directly in the unit search path. + Link a unit file that is not in the unit file search paths into the unit file search path. This + command expects an absolute path to a unit file. The effect of this may be undone with + disable. The effect of this command is that a unit file is made available for commands + such as start, even though it is not installed directly in the unit search path. diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 5298fcfb9c..bfd770e4df 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -6533,7 +6533,7 @@ static void systemctl_help(void) { " unit is required or wanted\n\n" "Unit File Commands:\n" " list-unit-files [PATTERN...] List installed unit files\n" - " enable NAME... Enable one or more unit files\n" + " enable [NAME...|PATH...] Enable one or more unit files\n" " disable NAME... Disable one or more unit files\n" " reenable NAME... Reenable one or more unit files\n" " preset NAME... Enable/disable one or more unit files\n" -- cgit v1.2.3-54-g00ecf From 5164c3b473fd7c3b72d3e98a4664fa44a18469bb Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Fri, 22 Jul 2016 16:31:55 -0400 Subject: man: make chroot less prominent in discussion of nspawn Not as many people use chroot as before, so make the flow a bit nicer by talking less about chroot. "change to the either" is awkward and unclear. Just remove that part, because all changes are lost, period. --- man/systemd-nspawn.xml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'man') diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index cb0468fbf5..9b623c8353 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -73,11 +73,9 @@ since it fully virtualizes the file system hierarchy, as well as the process tree, the various IPC subsystems and the host and domain name. - Like chroot1 the - systemd-nspawn command may be invoked on any directory tree containing an operating system tree, + systemd-nspawn may be invoked on any directory tree containing an operating system tree, using the command line option. By using the option an OS - tree is automatically searched in a couple of locations, most importantly in + tree is automatically searched for in a couple of locations, most importantly in /var/lib/machines, the suggested directory to place container images installed on the system. @@ -935,8 +933,8 @@ tmpfs instance, and /usr from the OS tree is mounted into it in read-only mode (the system thus starts up with read-only OS - resources, but pristine state and configuration, any changes - to the either are lost on shutdown). When the mode parameter + image, but pristine state and configuration, any changes + are lost on shutdown). When the mode parameter is specified as , the OS tree is mounted read-only, but /var is mounted as a tmpfs instance into it (the system thus -- cgit v1.2.3-54-g00ecf From 93f07c87890a54c956eac38f206161071a968a55 Mon Sep 17 00:00:00 2001 From: Zbigniew Jędrzejewski-Szmek Date: Mon, 25 Jul 2016 10:41:04 -0400 Subject: man: use "search for unit" To "search something", in the meaning of looking for it, is valid, but "search _for_ something" is much more commonly used, especially when the meaning could be confused with "looking _through_ something" (for some other object). (C.f. "the police search a person", "the police search for a person".) Also reword the rest of the paragraph to avoid using "automatically" three times. --- man/systemctl.xml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'man') diff --git a/man/systemctl.xml b/man/systemctl.xml index c7b830b7fb..e7880d24f7 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -996,12 +996,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service unit configuration diectory, however they point to the single template unit file they are instantiated from. - This command expects either valid unit names (in which case appropriate unit files for these names - are automatically searched in the various unit file directories), or absolute paths to unit files (in which - case these files are read directly). If a specified unit file is located outside of the unit file - directories searched automatically, an additional symlink is created, linking it into the unit - configuration path, thus ensuring it is automatically found when requested by commands such as - start. + This command expects either valid unit names (in which case various unit file directories are + automatically searched for unit files with appropriate names), or absolute paths to unit files (in which + case these files are read directly). If a specified unit file is located outside of the usual unit file + directories, an additional symlink is created, linking it into the unit configuration path, thus ensuring + it is found when requested by commands such as start. This command will print the file system operations executed. This output may be suppressed by passing . -- cgit v1.2.3-54-g00ecf From 43eb109aa9b8952dbcbfc0ae564d91c180f5d93a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 16:53:33 +0200 Subject: core: change ExecStart=! syntax to ExecStart=+ (#3797) As suggested by @mbiebl we already use the "!" special char in unit file assignments for negation, hence we should not use it in a different context for privileged execution. Let's use "+" instead. --- NEWS | 2 +- man/systemd.exec.xml | 20 ++++++++++---------- man/systemd.service.xml | 20 ++++++++------------ src/core/load-fragment.c | 2 +- 4 files changed, 20 insertions(+), 24 deletions(-) (limited to 'man') diff --git a/NEWS b/NEWS index 36fb84b26f..0ffe025400 100644 --- a/NEWS +++ b/NEWS @@ -4,7 +4,7 @@ CHANGES WITH 231: * In service units the various ExecXYZ= settings have been extended with an additional special character as first argument of the - assigned value: if the character '!' is used the specified command + assigned value: if the character '+' is used the specified command line it will be run with full privileges, regardless of User=, Group=, CapabilityBoundingSet= and similar options. The effect is similar to the existing PermissionsStartOnly= option, but allows diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 49fea98a95..41ae6e76de 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -146,7 +146,7 @@ Sets the Unix user or group that the processes are executed as, respectively. Takes a single user or group name or ID as argument. If no group is set, the default group - of the user is chosen. These do not affect commands prefixed with !. + of the user is chosen. These do not affect commands prefixed with +. @@ -161,7 +161,7 @@ this one will have no effect. In any way, this option does not override, but extends the list of supplementary groups configured in the system group database for the - user. This does not affect commands prefixed with !. + user. This does not affect commands prefixed with +. @@ -796,7 +796,7 @@ empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior settings have no effect. If set to ~ (without any further argument), the bounding set is reset to the full set of available capabilities, also undoing any previous settings. This does not affect - commands prefixed with !. + commands prefixed with +. @@ -826,7 +826,7 @@ Note that in this case option keep-caps is automatically added to SecureBits= to retain the capabilities over the user change. AmbientCapabilities= does not affect - commands prefixed with !. + commands prefixed with +. @@ -842,7 +842,7 @@ . This option may appear more than once, in which case the secure bits are ORed. If the empty string is assigned to this option, - the bits are reset to 0. This does not affect commands prefixed with !. + the bits are reset to 0. This does not affect commands prefixed with +. See capabilities7 for details. @@ -1101,7 +1101,7 @@ domain transition. However, the policy still needs to authorize the transition. This directive is ignored if SELinux is disabled. If prefixed by -, all errors - will be ignored. This does not affect commands prefixed with !. + will be ignored. This does not affect commands prefixed with +. See setexeccon3 for details. @@ -1114,7 +1114,7 @@ Profiles must already be loaded in the kernel, or the unit will fail. This result in a non operation if AppArmor is not enabled. If prefixed by -, all errors will - be ignored. This does not affect commands prefixed with !. + be ignored. This does not affect commands prefixed with +. @@ -1134,7 +1134,7 @@ The value may be prefixed by -, in which case all errors will be ignored. An empty value may be specified to unset previous assignments. This does not affect - commands prefixed with !. + commands prefixed with +. @@ -1185,7 +1185,7 @@ listed explicitly. This option may be specified more than once, in which case the filter masks are merged. If the empty string is assigned, the filter is reset, all prior assignments will - have no effect. This does not affect commands prefixed with !. + have no effect. This does not affect commands prefixed with +. If you specify both types of this option (i.e. whitelisting and blacklisting), the first encountered will @@ -1354,7 +1354,7 @@ family should be included in the configured whitelist as it is frequently used for local communication, including for syslog2 - logging. This does not affect commands prefixed with !. + logging. This does not affect commands prefixed with +. diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 70f12b2d32..875d368fcf 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -288,18 +288,14 @@ ExecStart= is specified, then the service must have RemainAfterExit=yes set. - For each of the specified commands, the first argument - must be an absolute path to an executable. Optionally, if this - file name is prefixed with @, the second - token will be passed as argv[0] to the - executed process, followed by the further arguments specified. - If the absolute filename is prefixed with - -, an exit code of the command normally - considered a failure (i.e. non-zero exit status or abnormal - exit due to signal) is ignored and considered success. - If the absolute path is prefixed with ! then - it is executed with full privileges. -, @, and ! - may be used together and they can appear in any order. + For each of the specified commands, the first argument must be an absolute path to an + executable. Optionally, if this file name is prefixed with @, the second token will be + passed as argv[0] to the executed process, followed by the further arguments specified. If + the absolute filename is prefixed with -, an exit code of the command normally considered a + failure (i.e. non-zero exit status or abnormal exit due to signal) is ignored and considered success. If the + absolute path is prefixed with + then it is executed with full + privileges. -, @, and + may be used together and they + can appear in any order. If more than one command is specified, the commands are invoked sequentially in the order they appear in the unit diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index ae306de4ae..a36953f766 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -620,7 +620,7 @@ int config_parse_exec( ignore = true; else if (*f == '@' && !separate_argv0) separate_argv0 = true; - else if (*f == '!' && !privileged) + else if (*f == '+' && !privileged) privileged = true; else break; -- cgit v1.2.3-54-g00ecf From 91fe95e158405f2798997d21cb403d624e9b5578 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 20:14:13 +0200 Subject: man: minor man page fix Addressing: https://github.com/systemd/systemd/commit/b541146bf8c34aaaa9efcf58325f18da9253c4ec#commitcomment-17997074 --- man/systemd-resolved.service.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'man') diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 141b06e374..aa1c2365e5 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -80,10 +80,10 @@ Additionally, systemd-resolved provides a local DNS stub listener on IP address 127.0.0.53 on the local loopback interface. Programs issuing DNS requests directly, bypassing any local - API may be directed to this stub, in order to connect them systemd-resolved. Note however that - it is strongly recommended that local programs use the glibc NSS or bus APIs instead (as described above), as - various network resolution concepts (such as link-local addressing, or LLMNR Unicode domains) cannot be mapped to - the unicast DNS protocol. + API may be directed to this stub, in order to connect them to systemd-resolved. Note however + that it is strongly recommended that local programs use the glibc NSS or bus APIs instead (as described above), + as various network resolution concepts (such as link-local addressing, or LLMNR Unicode domains) cannot be mapped + to the unicast DNS protocol. The DNS servers contacted are determined from the global settings in -- cgit v1.2.3-54-g00ecf From 91c8861526816be8e19c52f8ef5339a4eca5573e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Jul 2016 20:56:24 +0200 Subject: man: extend documentation on the SplitMode= setting (#3801) Adressing https://github.com/systemd/systemd/issues/3755#issuecomment-234214273 --- man/journald.conf.xml | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'man') diff --git a/man/journald.conf.xml b/man/journald.conf.xml index 3964cd6bc5..fef4fde898 100644 --- a/man/journald.conf.xml +++ b/man/journald.conf.xml @@ -129,21 +129,22 @@ SplitMode= - Controls whether to split up journal files per - user. One of uid, login - and none. If uid, all - users will get each their own journal files regardless of - whether they possess a login session or not, however system - users will log into the system journal. If - login, actually logged-in users will get - each their own journal files, but users without login session - and system users will log into the system journal. If - none, journal files are not split up by - user and all messages are instead stored in the single system - journal. Note that splitting up journal files by user is only - available for journals stored persistently. If journals are - stored on volatile storage (see above), only a single journal - file for all user IDs is kept. Defaults to + Controls whether to split up journal files per user. Split-up journal files are primarily + useful for access control: on UNIX/Linux access control is managed per file, and the journal daemon will assign + users read access to their journal files. This setting takes one of uid, + login or none. If uid, all regular users will get each + their own journal files regardless of whether their processes possess login sessions or not, however system + users will log into the system journal. If login, actually logged-in users will get each + their own journal files, but users without login session and system users will log into the system + journal. Note that in this mode, user code running outside of any login session will log into the system log + instead of the split-out user logs. Most importantly, this means that information about core dumps of user + processes collected via the + systemd-coredump8 subsystem + will end up in the system logs instead of the user logs, and thus not be accessible to the owning users. If + none, journal files are not split up by user and all messages are instead stored in the + single system journal. In this mode unprivileged users generally do not have access to their own log data. Note + that splitting up journal files by user is only available for journals stored persistently. If journals are + stored on volatile storage (see above), only a single journal file for all user IDs is kept. Defaults to uid. -- cgit v1.2.3-54-g00ecf From ca3b53e532b4af5a1b13c9a997187c2cb7673a36 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:19:20 -0400 Subject: FSDG: man/: Refer to the operating system as GNU/Linux. This is not a blind replacement of "Linux" with "GNU/Linux". In some cases, "Linux" is (correctly) used to refer to just the kernel. In others, it is in a string for which code must also be adjusted; these instances are not included in this commit. --- man/daemon.xml | 4 ++-- man/sd-bus-errors.xml | 2 +- man/sd_bus_error_add_map.xml | 2 +- man/systemd.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'man') diff --git a/man/daemon.xml b/man/daemon.xml index 485c66225e..a649749683 100644 --- a/man/daemon.xml +++ b/man/daemon.xml @@ -168,7 +168,7 @@ New-Style Daemons - Modern services for Linux should be implemented as + Modern services for GNU/Linux should be implemented as new-style daemons. This makes it easier to supervise and control them at runtime and simplifies their implementation. @@ -309,7 +309,7 @@ as detailed in the LSB Linux Standard Base Core Specification. This method of - activation is supported ubiquitously on Linux init systems, both + activation is supported ubiquitously on GNU/Linux init systems, both old-style and new-style systems. Among other issues, SysV init scripts have the disadvantage of involving shell scripts in the boot process. New-style init systems generally employ updated diff --git a/man/sd-bus-errors.xml b/man/sd-bus-errors.xml index 055af7a682..d2b81f4e4a 100644 --- a/man/sd-bus-errors.xml +++ b/man/sd-bus-errors.xml @@ -126,7 +126,7 @@ In addition to this list, in sd-bus, the special error namespace System.Error. is used to map - arbitrary Linux system errors (as defined by errno3) to D-Bus errors and back. For example, the error EUCLEAN is mapped to diff --git a/man/sd_bus_error_add_map.xml b/man/sd_bus_error_add_map.xml index 139bd77d8c..7dc1ef6c90 100644 --- a/man/sd_bus_error_add_map.xml +++ b/man/sd_bus_error_add_map.xml @@ -82,7 +82,7 @@ The sd_bus_error_add_map() call may be used to register additional mappings for converting D-Bus errors - to Linux errno-style errors. The mappings + to GNU/Linux errno-style errors. The mappings defined with this call are consulted by calls such as sd_bus_error_set3 or diff --git a/man/systemd.xml b/man/systemd.xml index 65f55199e2..4f0201fc76 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -61,7 +61,7 @@ Description - systemd is a system and service manager for Linux operating + systemd is a system and service manager for GNU/Linux operating systems. When run as first process on boot (as PID 1), it acts as init system that brings up and maintains userspace services. -- cgit v1.2.3-54-g00ecf From 69a361b7021f508d342cd408b9070b2cbf148dfa Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:23:40 -0400 Subject: FSDG: os-release: Default to PRETTY_NAME "GNU/Linux" instead of "Linux". --- man/kernel-install.xml | 2 +- man/os-release.xml | 2 +- src/analyze/analyze.c | 2 +- src/core/main.c | 4 ++-- src/firstboot/firstboot.c | 2 +- src/kernel-install/90-loaderentry.install | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) (limited to 'man') diff --git a/man/kernel-install.xml b/man/kernel-install.xml index d7e27de758..eb519188a6 100644 --- a/man/kernel-install.xml +++ b/man/kernel-install.xml @@ -106,7 +106,7 @@ PRETTY_NAME parameter specified in /etc/os-release or /usr/lib/os-release (if the former is - missing), or "Linux + missing), or "GNU/Linux KERNEL-VERSION", if unset. If the file initrd is found next to the linux file, the initrd will be added to diff --git a/man/os-release.xml b/man/os-release.xml index 99bbb61004..27d18749dc 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -210,7 +210,7 @@ suitable for presentation to the user. May or may not contain a release code name or OS version of some kind, as suitable. If not set, defaults to - PRETTY_NAME="Linux". Example: + PRETTY_NAME="GNU/Linux". Example: PRETTY_NAME="Fedora 17 (Beefy Miracle)". diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index cbf9354a7a..66830695f3 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -653,7 +653,7 @@ static int analyze_plot(sd_bus *bus) { svg("\n"); svg("%s", pretty_times); svg("%s %s (%s %s %s) %s %s", - isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name, + isempty(host->os_pretty_name) ? "GNU/Linux" : host->os_pretty_name, strempty(host->hostname), strempty(host->kernel_name), strempty(host->kernel_release), diff --git a/src/core/main.c b/src/core/main.c index f2adca7d2b..719bc49475 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1240,11 +1240,11 @@ static int status_welcome(void) { return status_printf(NULL, false, false, "\nWelcome to \x1B[%sm%s\x1B[0m!\n", isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); else return status_printf(NULL, false, false, "\nWelcome to %s!\n", - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); } static int write_container_id(void) { diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index c9e8e54ee3..83a21eaf0e 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -96,7 +96,7 @@ static void print_welcome(void) { log_warning_errno(r, "Failed to read os-release file: %m"); printf("\nWelcome to your new installation of %s!\nPlease configure a few basic system settings:\n\n", - isempty(pretty_name) ? "Linux" : pretty_name); + isempty(pretty_name) ? "GNU/Linux" : pretty_name); press_any_key(); diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index a0bca05c9a..af9f0f9ccd 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -38,7 +38,7 @@ elif [[ -f /usr/lib/os-release ]]; then fi if ! [[ $PRETTY_NAME ]]; then - PRETTY_NAME="Linux $KERNEL_VERSION" + PRETTY_NAME="GNU/Linux $KERNEL_VERSION" fi declare -a BOOT_OPTIONS -- cgit v1.2.3-54-g00ecf From 148d8a99607e4d7d55dc5556640635425a88ff2c Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:24:56 -0400 Subject: FSDG: os-release: Default to NAME "GNU/Linux" instead of "Linux". --- man/os-release.xml | 2 +- src/journal-remote/journal-gatewayd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'man') diff --git a/man/os-release.xml b/man/os-release.xml index 27d18749dc..a88d16b171 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -121,7 +121,7 @@ A string identifying the operating system, without a version component, and suitable for presentation to the user. If not set, defaults to - NAME=Linux. Example: + NAME=GNU/Linux. Example: NAME=Fedora or NAME="Debian GNU/Linux". diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 4ad9184993..e265027a04 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -801,7 +801,7 @@ static int request_handler_machine( SD_ID128_FORMAT_VAL(mid), SD_ID128_FORMAT_VAL(bid), hostname_cleanup(hostname), - os_name ? os_name : "Linux", + os_name ? os_name : "GNU/Linux", v ? v : "bare", usage, cutoff_from, -- cgit v1.2.3-54-g00ecf From 904288f6aa71411de4ba786384f38d9c2adc1bb3 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:28:30 -0400 Subject: FSDG: os-release: Default ID to "gnu-linux" instead of "linux". As far as I can tell, no code in this repository actually uses the ID field, so this is just a man page change. --- man/os-release.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'man') diff --git a/man/os-release.xml b/man/os-release.xml index a88d16b171..caf60f41a3 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -145,7 +145,7 @@ the operating system, excluding any version information and suitable for processing by scripts or usage in generated filenames. If not set, defaults to - ID=linux. Example: + ID=gnu-linux. Example: ID=fedora or ID=debian. -- cgit v1.2.3-54-g00ecf From 10b7e8ea5e1361f866bb4f734d9ca68061855cec Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 25 May 2016 12:32:21 -0400 Subject: FSDG: man/: Use FSDG operating systems as examples. --- man/os-release.xml | 49 +++++++++++++++++++++++++------------------------ man/systemd-nspawn.xml | 37 +++++++++++++------------------------ 2 files changed, 38 insertions(+), 48 deletions(-) (limited to 'man') diff --git a/man/os-release.xml b/man/os-release.xml index caf60f41a3..2811f434c5 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -122,7 +122,7 @@ without a version component, and suitable for presentation to the user. If not set, defaults to NAME=GNU/Linux. Example: - NAME=Fedora or NAME="Debian + NAME=BLAG or NAME="gNewSense GNU/Linux". @@ -133,8 +133,8 @@ version, excluding any OS name information, possibly including a release code name, and suitable for presentation to the user. This field is optional. Example: - VERSION=17 or VERSION="17 (Beefy - Miracle)". + VERSION=210k or VERSION="210k + (Spartakus)". @@ -146,8 +146,8 @@ suitable for processing by scripts or usage in generated filenames. If not set, defaults to ID=gnu-linux. Example: - ID=fedora or - ID=debian. + ID=blag or + ID=gnewsense. @@ -168,9 +168,9 @@ should be listed in order of how closely the local operating system relates to the listed ones, starting with the closest. This field is optional. Example: for an operating system with - ID=centos, an assignment of + ID=blag, an assignment of ID_LIKE="rhel fedora" would be appropriate. - For an operating system with ID=ubuntu, an + For an operating system with ID=gnewsense, an assignment of ID_LIKE=debian is appropriate. @@ -199,8 +199,8 @@ identifying the operating system version, excluding any OS name information or release code name, and suitable for processing by scripts or usage in generated filenames. This - field is optional. Example: VERSION_ID=17 - or VERSION_ID=11.04. + field is optional. Example: VERSION_ID=210k + or VERSION_ID=7.0. @@ -211,8 +211,8 @@ a release code name or OS version of some kind, as suitable. If not set, defaults to PRETTY_NAME="GNU/Linux". Example: - PRETTY_NAME="Fedora 17 (Beefy - Miracle)". + PRETTY_NAME="BLAG 210k + (Spartakus)". @@ -235,7 +235,7 @@ Common Platform Enumeration Specification as proposed by the NIST. This field is optional. Example: - CPE_NAME="cpe:/o:fedoraproject:fedora:17" + CPE_NAME="cpe:/o:blagblagblag:blag:210k" @@ -270,8 +270,8 @@ one URL shall be listed in each setting. If multiple resources need to be referenced, it is recommended to provide an online landing page linking all available resources. Examples: - HOME_URL="https://fedoraproject.org/" and - BUG_REPORT_URL="https://bugzilla.redhat.com/" + HOME_URL="https://www.blagblagblag.org/" and + BUG_REPORT_URL="https://blag.fsf.org/" @@ -346,21 +346,22 @@ recommended to prefix new fields with an OS specific name in order to avoid name clashes. Applications reading this file must ignore unknown fields. Example: - DEBIAN_BTS="debbugs://bugs.debian.org/" + DEBIAN_BTS="debbugs://bugs.gnewsense.org/" Example - NAME=Fedora -VERSION="17 (Beefy Miracle)" -ID=fedora -VERSION_ID=17 -PRETTY_NAME="Fedora 17 (Beefy Miracle)" -ANSI_COLOR="0;34" -CPE_NAME="cpe:/o:fedoraproject:fedora:17" -HOME_URL="https://fedoraproject.org/" -BUG_REPORT_URL="https://bugzilla.redhat.com/" + NAME=Parabola +VERSION="rolling-release" +ID=parabola +ID_LIKE=arch +VERSION_ID=rolling-release +PRETTY_NAME="Parabola GNU/Linux-libre" +ANSI_COLOR="1;35" +CPE_NAME="cpe:/o:parabola:parabola:rolling-release" +HOME_URL="https://www.parabola.nu/" +BUG_REPORT_URL="https://labs.parabola.nu/" diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 9b623c8353..69d2f6ff7d 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -1026,46 +1026,35 @@ Examples - Download a Fedora image and start a shell in it + Build and boot a minimal BLAG distribution in a container - # machinectl pull-raw --verify=no http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz -# systemd-nspawn -M Fedora-Cloud-Base-20141203-21 - - This downloads an image using - machinectl1 - and opens a shell in it. - - - - Build and boot a minimal Fedora distribution in a container - - # dnf -y --releasever=23 --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora --enablerepo=updates install systemd passwd dnf fedora-release vim-minimal + # dnf -y --releasever=210k --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=blag --enablerepo=updates install systemd passwd dnf blag-release vim-minimal # systemd-nspawn -bD /srv/mycontainer - This installs a minimal Fedora distribution into the + This installs a minimal BLAG distribution into the directory /srv/mycontainer/ and then boots an OS in a namespace container in it. - Spawn a shell in a container of a minimal Debian unstable distribution + Spawn a shell in a container of a minimal gNewSense unstable distribution - # debootstrap --arch=amd64 unstable ~/debian-tree/ -# systemd-nspawn -D ~/debian-tree/ + # debootstrap --arch=amd64 unstable ~/gnewsense-tree/ +# systemd-nspawn -D ~/gnewsense-tree/ - This installs a minimal Debian unstable distribution into - the directory ~/debian-tree/ and then + This installs a minimal gNewSense unstable distribution into + the directory ~/gnewsense-tree/ and then spawns a shell in a namespace container in it. - Boot a minimal Arch Linux distribution in a container + Boot a minimal Parabola GNU/Linux-libre distribution in a container - # pacstrap -c -d ~/arch-tree/ base -# systemd-nspawn -bD ~/arch-tree/ + # pacstrap -c -d ~/parabola-tree/ base +# systemd-nspawn -bD ~/parabola-tree/ - This installs a minimal Arch Linux distribution into the - directory ~/arch-tree/ and then boots an OS + This installs a minimal Parabola GNU/Linux-libre distribution into the + directory ~/parabola-tree/ and then boots an OS in a namespace container in it. -- cgit v1.2.3-54-g00ecf