diff options
Diffstat (limited to 'src')
58 files changed, 1269 insertions, 739 deletions
diff --git a/src/basic/log.c b/src/basic/log.c index bd6c96c4f8..2ff70be255 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -967,7 +967,7 @@ int log_set_max_level_from_string(const char *e) { return 0; } -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { /* * The systemd.log_xyz= settings are parsed by all tools, and @@ -1012,7 +1012,7 @@ void log_parse_environment(void) { /* Only try to read the command line in daemons. We assume that anything that has a controlling tty is user stuff. */ - (void) parse_proc_cmdline(parse_proc_cmdline_item); + (void) parse_proc_cmdline(parse_proc_cmdline_item, NULL, true); e = secure_getenv("SYSTEMD_LOG_TARGET"); if (e && log_set_target_from_string(e) < 0) diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 0ef00676ef..2985cc475a 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -162,7 +162,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { fallback_fdinfo: r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); - if (r == -EOPNOTSUPP) + if (IN_SET(r, -EOPNOTSUPP, -EACCES)) goto fallback_fstat; if (r < 0) return r; diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 0430beadaa..8297a222b7 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -42,7 +42,9 @@ int proc_cmdline(char **ret) { return read_one_line_file("/proc/cmdline", ret); } -int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { +int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data), + void *data, + bool strip_prefix) { _cleanup_free_ char *line = NULL; const char *p; int r; @@ -56,7 +58,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { p = line; for (;;) { _cleanup_free_ char *word = NULL; - char *value = NULL; + char *value = NULL, *unprefixed; r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) @@ -66,14 +68,15 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { /* Filter out arguments that are intended only for the * initrd */ - if (!in_initrd() && startswith(word, "rd.")) + unprefixed = startswith(word, "rd."); + if (unprefixed && !in_initrd()) continue; value = strchr(word, '='); if (value) *(value++) = 0; - r = parse_item(word, value); + r = parse_item(strip_prefix && unprefixed ? unprefixed : word, value, data); if (r < 0) return r; } diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h index 452642a2f5..6d6ee95c11 100644 --- a/src/basic/proc-cmdline.h +++ b/src/basic/proc-cmdline.h @@ -20,7 +20,9 @@ ***/ int proc_cmdline(char **ret); -int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value)); +int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data), + void *data, + bool strip_prefix); int get_proc_cmdline_key(const char *parameter, char **value); int shall_restore_state(void); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 12eb55cb7f..d7d3d3c8ce 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -47,6 +47,11 @@ #include "virt.h" #include "watchdog.h" +static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) { + return (runtime ? UNIT_FILE_RUNTIME : 0) | + (force ? UNIT_FILE_FORCE : 0); +} + static int property_get_version( sd_bus *bus, const char *path, @@ -1948,13 +1953,14 @@ static int install_error( static int method_enable_unit_files_generic( sd_bus_message *message, Manager *m, - int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes), + int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), bool carries_install_info, sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; UnitFileChange *changes = NULL; unsigned n_changes = 0; + UnitFileFlags flags; int runtime, force, r; assert(message); @@ -1968,13 +1974,15 @@ static int method_enable_unit_files_generic( if (r < 0) return r; + flags = unit_file_bools_to_flags(runtime, force); + r = bus_verify_manage_unit_files_async(m, message, error); if (r < 0) return r; if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes); + r = call(m->unit_file_scope, flags, NULL, l, &changes, &n_changes); if (r < 0) return install_error(error, r, changes, n_changes); @@ -1993,8 +2001,8 @@ static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bu return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error); } -static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) { - return unit_file_preset(scope, runtime, root_dir, files, UNIT_FILE_PRESET_FULL, force, changes, n_changes); +static int unit_file_preset_without_mode(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes) { + return unit_file_preset(scope, flags, root_dir, files, UNIT_FILE_PRESET_FULL, changes, n_changes); } static int method_preset_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -2013,6 +2021,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use Manager *m = userdata; UnitFilePresetMode mm; int runtime, force, r; + UnitFileFlags flags; const char *mode; assert(message); @@ -2026,6 +2035,8 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use if (r < 0) return r; + flags = unit_file_bools_to_flags(runtime, force); + if (isempty(mode)) mm = UNIT_FILE_PRESET_FULL; else { @@ -2040,7 +2051,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes); + r = unit_file_preset(m->unit_file_scope, flags, NULL, l, mm, &changes, &n_changes); if (r < 0) return install_error(error, r, changes, n_changes); @@ -2050,7 +2061,7 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use static int method_disable_unit_files_generic( sd_bus_message *message, Manager *m, - int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), + int (*call)(UnitFileScope scope, UnitFileFlags flags, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes), sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; @@ -2075,7 +2086,7 @@ static int method_disable_unit_files_generic( if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes); + r = call(m->unit_file_scope, runtime ? UNIT_FILE_RUNTIME : 0, NULL, l, &changes, &n_changes); if (r < 0) return install_error(error, r, changes, n_changes); @@ -2141,7 +2152,7 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes); + r = unit_file_set_default(m->unit_file_scope, force ? UNIT_FILE_FORCE : 0, NULL, name, &changes, &n_changes); if (r < 0) return install_error(error, r, changes, n_changes); @@ -2154,6 +2165,7 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, Manager *m = userdata; UnitFilePresetMode mm; const char *mode; + UnitFileFlags flags; int force, runtime, r; assert(message); @@ -2167,6 +2179,8 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, if (r < 0) return r; + flags = unit_file_bools_to_flags(runtime, force); + if (isempty(mode)) mm = UNIT_FILE_PRESET_FULL; else { @@ -2181,7 +2195,7 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes); + r = unit_file_preset_all(m->unit_file_scope, flags, NULL, mm, &changes, &n_changes); if (r < 0) return install_error(error, r, changes, n_changes); @@ -2196,6 +2210,7 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd int runtime, force, r; char *target, *type; UnitDependency dep; + UnitFileFlags flags; assert(message); assert(m); @@ -2214,17 +2229,62 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd if (r < 0) return r; + flags = unit_file_bools_to_flags(runtime, force); + dep = unit_dependency_from_string(type); if (dep < 0) return -EINVAL; - r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); + r = unit_file_add_dependency(m->unit_file_scope, flags, NULL, l, target, dep, &changes, &n_changes); if (r < 0) return install_error(error, r, changes, n_changes); return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } +static int method_get_unit_file_links(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0, i; + UnitFileFlags flags; + const char *name; + char **p; + int runtime, r; + + r = sd_bus_message_read(message, "sb", &name, &runtime); + if (r < 0) + return r; + + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, SD_BUS_TYPE_ARRAY, "s"); + if (r < 0) + return r; + + p = STRV_MAKE(name); + flags = UNIT_FILE_DRY_RUN | + (runtime ? UNIT_FILE_RUNTIME : 0); + + r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); + if (r < 0) + return log_error_errno(r, "Failed to get file links for %s: %m", name); + + for (i = 0; i < n_changes; i++) + if (changes[i].type == UNIT_FILE_UNLINK) { + r = sd_bus_message_append(reply, "s", changes[i].path); + if (r < 0) + return r; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_VTABLE_START(0), @@ -2370,6 +2430,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetUnitFileLinks", "sb", "as", method_get_unit_file_links, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetExitCode", "y", NULL, method_set_exit_code, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("LookupDynamicUserByName", "s", "u", method_lookup_dynamic_user_by_name, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("LookupDynamicUserByUID", "u", "s", method_lookup_dynamic_user_by_uid, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 3c55e0f7fe..61b83d2d62 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -36,7 +36,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess); -static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction); const sd_bus_vtable bus_service_vtable[] = { SD_BUS_VTABLE_START(0), @@ -50,7 +50,7 @@ const sd_bus_vtable bus_service_vtable[] = { SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST), BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0), - SD_BUS_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("FailureAction", "s", property_get_emergency_action, offsetof(Service, emergency_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST), @@ -79,7 +79,7 @@ const sd_bus_vtable bus_service_vtable[] = { /* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */ SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), - SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_VTABLE_END }; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 245912fc0f..8f34fa1a52 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -37,7 +37,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); -static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction); static int property_get_names( sd_bus *bus, @@ -750,7 +750,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -762,7 +762,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0), diff --git a/src/core/failure-action.c b/src/core/emergency-action.c index ddae46190f..90232bc57a 100644 --- a/src/core/failure-action.c +++ b/src/core/emergency-action.c @@ -23,59 +23,60 @@ #include "bus-error.h" #include "bus-util.h" -#include "failure-action.h" +#include "emergency-action.h" #include "special.h" #include "string-table.h" #include "terminal-util.h" -static void log_and_status(Manager *m, const char *message) { - log_warning("%s", message); +static void log_and_status(Manager *m, const char *message, const char *reason) { + log_warning("%s: %s", message, reason); manager_status_printf(m, STATUS_TYPE_EMERGENCY, ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL, - "%s", message); + "%s: %s", message, reason); } -int failure_action( +int emergency_action( Manager *m, - FailureAction action, - const char *reboot_arg) { + EmergencyAction action, + const char *reboot_arg, + const char *reason) { assert(m); assert(action >= 0); - assert(action < _FAILURE_ACTION_MAX); + assert(action < _EMERGENCY_ACTION_MAX); - if (action == FAILURE_ACTION_NONE) + if (action == EMERGENCY_ACTION_NONE) return -ECANCELED; if (!MANAGER_IS_SYSTEM(m)) { /* Downgrade all options to simply exiting if we run * in user mode */ - log_warning("Exiting as result of failure."); + log_warning("Exiting: %s", reason); m->exit_code = MANAGER_EXIT; return -ECANCELED; } switch (action) { - case FAILURE_ACTION_REBOOT: - log_and_status(m, "Rebooting as result of failure."); + case EMERGENCY_ACTION_REBOOT: + log_and_status(m, "Rebooting", reason); (void) update_reboot_parameter_and_warn(reboot_arg); (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL); break; - case FAILURE_ACTION_REBOOT_FORCE: - log_and_status(m, "Forcibly rebooting as result of failure."); + case EMERGENCY_ACTION_REBOOT_FORCE: + log_and_status(m, "Forcibly rebooting", reason); (void) update_reboot_parameter_and_warn(reboot_arg); m->exit_code = MANAGER_REBOOT; break; - case FAILURE_ACTION_REBOOT_IMMEDIATE: - log_and_status(m, "Rebooting immediately as result of failure."); + case EMERGENCY_ACTION_REBOOT_IMMEDIATE: + log_and_status(m, "Rebooting immediately", reason); sync(); @@ -89,18 +90,18 @@ int failure_action( reboot(RB_AUTOBOOT); break; - case FAILURE_ACTION_POWEROFF: - log_and_status(m, "Powering off as result of failure."); + case EMERGENCY_ACTION_POWEROFF: + log_and_status(m, "Powering off", reason); (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL); break; - case FAILURE_ACTION_POWEROFF_FORCE: - log_and_status(m, "Forcibly powering off as result of failure."); + case EMERGENCY_ACTION_POWEROFF_FORCE: + log_and_status(m, "Forcibly powering off", reason); m->exit_code = MANAGER_POWEROFF; break; - case FAILURE_ACTION_POWEROFF_IMMEDIATE: - log_and_status(m, "Powering off immediately as result of failure."); + case EMERGENCY_ACTION_POWEROFF_IMMEDIATE: + log_and_status(m, "Powering off immediately", reason); sync(); @@ -109,19 +110,19 @@ int failure_action( break; default: - assert_not_reached("Unknown failure action"); + assert_not_reached("Unknown emergency action"); } return -ECANCELED; } -static const char* const failure_action_table[_FAILURE_ACTION_MAX] = { - [FAILURE_ACTION_NONE] = "none", - [FAILURE_ACTION_REBOOT] = "reboot", - [FAILURE_ACTION_REBOOT_FORCE] = "reboot-force", - [FAILURE_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate", - [FAILURE_ACTION_POWEROFF] = "poweroff", - [FAILURE_ACTION_POWEROFF_FORCE] = "poweroff-force", - [FAILURE_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate" +static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = { + [EMERGENCY_ACTION_NONE] = "none", + [EMERGENCY_ACTION_REBOOT] = "reboot", + [EMERGENCY_ACTION_REBOOT_FORCE] = "reboot-force", + [EMERGENCY_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate", + [EMERGENCY_ACTION_POWEROFF] = "poweroff", + [EMERGENCY_ACTION_POWEROFF_FORCE] = "poweroff-force", + [EMERGENCY_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate" }; -DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction); +DEFINE_STRING_TABLE_LOOKUP(emergency_action, EmergencyAction); diff --git a/src/core/failure-action.h b/src/core/emergency-action.h index 1adac4ad5c..8804b59752 100644 --- a/src/core/failure-action.h +++ b/src/core/emergency-action.h @@ -20,22 +20,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -typedef enum FailureAction { - FAILURE_ACTION_NONE, - FAILURE_ACTION_REBOOT, - FAILURE_ACTION_REBOOT_FORCE, - FAILURE_ACTION_REBOOT_IMMEDIATE, - FAILURE_ACTION_POWEROFF, - FAILURE_ACTION_POWEROFF_FORCE, - FAILURE_ACTION_POWEROFF_IMMEDIATE, - _FAILURE_ACTION_MAX, - _FAILURE_ACTION_INVALID = -1 -} FailureAction; +typedef enum EmergencyAction { + EMERGENCY_ACTION_NONE, + EMERGENCY_ACTION_REBOOT, + EMERGENCY_ACTION_REBOOT_FORCE, + EMERGENCY_ACTION_REBOOT_IMMEDIATE, + EMERGENCY_ACTION_POWEROFF, + EMERGENCY_ACTION_POWEROFF_FORCE, + EMERGENCY_ACTION_POWEROFF_IMMEDIATE, + _EMERGENCY_ACTION_MAX, + _EMERGENCY_ACTION_INVALID = -1 +} EmergencyAction; #include "macro.h" #include "manager.h" -int failure_action(Manager *m, FailureAction action, const char *reboot_arg); +int emergency_action(Manager *m, EmergencyAction action, const char *reboot_arg, const char *reason); -const char* failure_action_to_string(FailureAction i) _const_; -FailureAction failure_action_from_string(const char *s) _pure_; +const char* emergency_action_to_string(EmergencyAction i) _const_; +EmergencyAction emergency_action_from_string(const char *s) _pure_; diff --git a/src/core/execute.c b/src/core/execute.c index 1b7b4a928d..5e7d7c25d7 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -730,74 +730,157 @@ static int ask_for_confirmation(char *response, char **argv) { return r; } -static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) { - bool keep_groups = false; +static int get_fixed_user(const ExecContext *c, const char **user, + uid_t *uid, gid_t *gid, + const char **home, const char **shell) { int r; + const char *name; - assert(context); + assert(c); - /* Lookup and set GID and supplementary group list. Here too - * we avoid NSS lookups for gid=0. */ + if (!c->user) + return 0; - if (context->group || username) { - /* First step, initialize groups from /etc/groups */ - if (username && gid != 0) { - if (initgroups(username, gid) < 0) - return -errno; + /* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway + * (i.e. are "/" or "/bin/nologin"). */ - keep_groups = true; - } + name = c->user; + r = get_user_creds_clean(&name, uid, gid, home, shell); + if (r < 0) + return r; - /* Second step, set our gids */ - if (setresgid(gid, gid, gid) < 0) + *user = name; + return 0; +} + +static int get_fixed_group(const ExecContext *c, const char **group, gid_t *gid) { + int r; + const char *name; + + assert(c); + + if (!c->group) + return 0; + + name = c->group; + r = get_group_creds(&name, gid); + if (r < 0) + return r; + + *group = name; + return 0; +} + +static int get_fixed_supplementary_groups(const ExecContext *c, + const char *user, + const char *group, + gid_t gid, + gid_t **supplementary_gids, int *ngids) { + char **i; + int r, k = 0; + int ngroups_max; + bool keep_groups = false; + gid_t *groups = NULL; + _cleanup_free_ gid_t *l_gids = NULL; + + assert(c); + + if (!c->supplementary_groups) + return 0; + + /* + * If SupplementaryGroups= was passed then NGROUPS_MAX has to + * be positive, otherwise fail. + */ + errno = 0; + ngroups_max = (int) sysconf(_SC_NGROUPS_MAX); + if (ngroups_max <= 0) { + if (errno > 0) return -errno; + else + return -EOPNOTSUPP; /* For all other values */ } - if (context->supplementary_groups) { - int ngroups_max, k; - gid_t *gids; - char **i; + /* + * If user is given, then lookup GID and supplementary group list. + * We avoid NSS lookups for gid=0. + */ + if (user && gid_is_valid(gid) && gid != 0) { + /* First step, initialize groups from /etc/groups */ + if (initgroups(user, gid) < 0) + return -errno; - /* Final step, initialize any manually set supplementary groups */ - assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0); + keep_groups = true; + } - if (!(gids = new(gid_t, ngroups_max))) - return -ENOMEM; + l_gids = new(gid_t, ngroups_max); + if (!l_gids) + return -ENOMEM; - if (keep_groups) { - k = getgroups(ngroups_max, gids); - if (k < 0) { - free(gids); - return -errno; - } - } else - k = 0; + if (keep_groups) { + /* + * Lookup the list of groups that the user belongs to, we + * avoid NSS lookups here too for gid=0. + */ + k = ngroups_max; + if (getgrouplist(user, gid, l_gids, &k) < 0) + return -EINVAL; + } else + k = 0; - STRV_FOREACH(i, context->supplementary_groups) { - const char *g; + STRV_FOREACH(i, c->supplementary_groups) { + const char *g; - if (k >= ngroups_max) { - free(gids); - return -E2BIG; - } + if (k >= ngroups_max) + return -E2BIG; - g = *i; - r = get_group_creds(&g, gids+k); - if (r < 0) { - free(gids); - return r; - } + g = *i; + r = get_group_creds(&g, l_gids+k); + if (r < 0) + return r; - k++; - } + k++; + } - r = maybe_setgroups(k, gids); - if (r < 0) { - free(gids); + /* + * Sets ngids to zero to drop all supplementary groups, happens + * when we are under root and SupplementaryGroups= is empty. + */ + if (k == 0) { + *ngids = 0; + return 0; + } + + /* Otherwise get the final list of supplementary groups */ + groups = memdup(l_gids, sizeof(gid_t) * k); + if (!groups) + return -ENOMEM; + + *supplementary_gids = groups; + *ngids = k; + + groups = NULL; + + return 0; +} + +static int enforce_groups(const ExecContext *context, gid_t gid, + gid_t *supplementary_gids, int ngids) { + int r; + + assert(context); + + /* Handle SupplementaryGroups= even if it is empty */ + if (context->supplementary_groups) { + r = maybe_setgroups(ngids, supplementary_gids); + if (r < 0) return r; - } + } - free(gids); + if (gid_is_valid(gid)) { + /* Then set our gids */ + if (setresgid(gid, gid, gid) < 0) + return -errno; } return 0; @@ -806,6 +889,9 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_ static int enforce_user(const ExecContext *context, uid_t uid) { assert(context); + if (!uid_is_valid(uid)) + return 0; + /* Sets (but doesn't look up) the uid and make sure we keep the * capabilities while doing so. */ @@ -1099,18 +1185,19 @@ static void rename_process_from_path(const char *path) { #ifdef HAVE_SECCOMP static bool skip_seccomp_unavailable(const Unit* u, const char* msg) { - if (!is_seccomp_available()) { - log_open(); - log_unit_debug(u, "SECCOMP features not detected in the kernel, skipping %s", msg); - log_close(); - return true; - } - return false; + + if (is_seccomp_available()) + return false; + + log_open(); + log_unit_debug(u, "SECCOMP features not detected in the kernel, skipping %s", msg); + log_close(); + return true; } static int apply_seccomp(const Unit* u, const ExecContext *c) { uint32_t negative_action, action; - scmp_filter_ctx *seccomp; + scmp_filter_ctx seccomp; Iterator i; void *id; int r; @@ -1161,7 +1248,7 @@ finish: } static int apply_address_families(const Unit* u, const ExecContext *c) { - scmp_filter_ctx *seccomp; + scmp_filter_ctx seccomp; Iterator i; int r; @@ -1170,13 +1257,9 @@ static int apply_address_families(const Unit* u, const ExecContext *c) { if (skip_seccomp_unavailable(u, "RestrictAddressFamilies=")) return 0; - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return -ENOMEM; - - r = seccomp_add_secondary_archs(seccomp); + r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW); if (r < 0) - goto finish; + return r; if (c->address_families_whitelist) { int af, first = 0, last = 0; @@ -1273,10 +1356,6 @@ static int apply_address_families(const Unit* u, const ExecContext *c) { } } - r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); - if (r < 0) - goto finish; - r = seccomp_load(seccomp); finish: @@ -1285,7 +1364,7 @@ finish: } static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) { - scmp_filter_ctx *seccomp; + scmp_filter_ctx seccomp; int r; assert(c); @@ -1293,13 +1372,9 @@ static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) if (skip_seccomp_unavailable(u, "MemoryDenyWriteExecute=")) return 0; - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return -ENOMEM; - - r = seccomp_add_secondary_archs(seccomp); + r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW); if (r < 0) - goto finish; + return r; r = seccomp_rule_add( seccomp, @@ -1319,10 +1394,6 @@ static int apply_memory_deny_write_execute(const Unit* u, const ExecContext *c) 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: @@ -1337,7 +1408,7 @@ static int apply_restrict_realtime(const Unit* u, const ExecContext *c) { SCHED_IDLE, }; - scmp_filter_ctx *seccomp; + scmp_filter_ctx seccomp; unsigned i; int r, p, max_policy = 0; @@ -1346,13 +1417,9 @@ static int apply_restrict_realtime(const Unit* u, const ExecContext *c) { if (skip_seccomp_unavailable(u, "RestrictRealtime=")) return 0; - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return -ENOMEM; - - r = seccomp_add_secondary_archs(seccomp); + r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW); if (r < 0) - goto finish; + return r; /* Determine the highest policy constant we want to allow */ for (i = 0; i < ELEMENTSOF(permitted_policies); i++) @@ -1396,10 +1463,6 @@ static int apply_restrict_realtime(const Unit* u, const ExecContext *c) { 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: @@ -1408,7 +1471,7 @@ finish: } static int apply_protect_sysctl(Unit *u, const ExecContext *c) { - scmp_filter_ctx *seccomp; + scmp_filter_ctx seccomp; int r; assert(c); @@ -1419,13 +1482,9 @@ static int apply_protect_sysctl(Unit *u, const ExecContext *c) { if (skip_seccomp_unavailable(u, "ProtectKernelTunables=")) return 0; - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return -ENOMEM; - - r = seccomp_add_secondary_archs(seccomp); + r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW); if (r < 0) - goto finish; + return r; r = seccomp_rule_add( seccomp, @@ -1435,10 +1494,6 @@ static int apply_protect_sysctl(Unit *u, const ExecContext *c) { 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: @@ -1447,56 +1502,17 @@ finish: } static int apply_protect_kernel_modules(Unit *u, const ExecContext *c) { - static const int module_syscalls[] = { - SCMP_SYS(delete_module), - SCMP_SYS(finit_module), - SCMP_SYS(init_module), - }; - - scmp_filter_ctx *seccomp; - unsigned i; - int r; - assert(c); - /* Turn of module syscalls on ProtectKernelModules=yes */ + /* Turn off module syscalls on ProtectKernelModules=yes */ if (skip_seccomp_unavailable(u, "ProtectKernelModules=")) return 0; - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return -ENOMEM; - - r = seccomp_add_secondary_archs(seccomp); - if (r < 0) - goto finish; - - for (i = 0; i < ELEMENTSOF(module_syscalls); i++) { - r = seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(EPERM), - module_syscalls[i], 0); - 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; + return seccomp_load_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_MODULE, SCMP_ACT_ERRNO(EPERM)); } static int apply_private_devices(Unit *u, const ExecContext *c) { - const SystemCallFilterSet *set; - scmp_filter_ctx *seccomp; - const char *sys; - bool syscalls_found = false; - int r; - assert(c); /* If PrivateDevices= is set, also turn off iopl and all @raw-io syscalls. */ @@ -1504,61 +1520,7 @@ static int apply_private_devices(Unit *u, const ExecContext *c) { if (skip_seccomp_unavailable(u, "PrivateDevices=")) return 0; - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return -ENOMEM; - - r = seccomp_add_secondary_archs(seccomp); - if (r < 0) - goto finish; - - for (set = syscall_filter_sets; set->set_name; set++) - if (streq(set->set_name, "@raw-io")) { - syscalls_found = true; - break; - } - - /* We should never fail here */ - if (!syscalls_found) { - r = -EOPNOTSUPP; - goto finish; - } - - NULSTR_FOREACH(sys, set->value) { - int id; - bool add = true; - -#ifndef __NR_s390_pci_mmio_read - if (streq(sys, "s390_pci_mmio_read")) - add = false; -#endif -#ifndef __NR_s390_pci_mmio_write - if (streq(sys, "s390_pci_mmio_write")) - add = false; -#endif - - if (!add) - continue; - - id = seccomp_syscall_resolve_name(sys); - - r = seccomp_rule_add( - seccomp, - SCMP_ACT_ERRNO(EPERM), - id, 0); - 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; + return seccomp_load_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO, SCMP_ACT_ERRNO(EPERM)); } #endif @@ -1804,9 +1766,9 @@ static int setup_private_users(uid_t uid, gid_t gid) { asprintf(&uid_map, "0 0 1\n" /* Map root → root */ UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */ - uid, uid); /* The case where the above is the same */ + uid, uid); else - uid_map = strdup("0 0 1\n"); + uid_map = strdup("0 0 1\n"); /* The case where the above is the same */ if (!uid_map) return -ENOMEM; @@ -2175,13 +2137,15 @@ 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; + _cleanup_free_ gid_t *supplementary_gids = NULL; + const char *username = NULL, *groupname = NULL; + const char *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; + int i, r, ngids = 0; assert(unit); assert(command); @@ -2273,26 +2237,23 @@ static int exec_child( username = dcreds->user->name; } else { - if (context->user) { - username = context->user; - r = get_user_creds_clean(&username, &uid, &gid, &home, &shell); - if (r < 0) { - *exit_status = EXIT_USER; - return r; - } - - /* Note that we don't set $HOME or $SHELL if they are not particularly enlightening anyway - * (i.e. are "/" or "/bin/nologin"). */ + r = get_fixed_user(context, &username, &uid, &gid, &home, &shell); + if (r < 0) { + *exit_status = EXIT_USER; + return r; } - if (context->group) { - const char *g = context->group; + r = get_fixed_group(context, &groupname, &gid); + if (r < 0) { + *exit_status = EXIT_GROUP; + return r; + } - r = get_group_creds(&g, &gid); - if (r < 0) { - *exit_status = EXIT_GROUP; - return r; - } + r = get_fixed_supplementary_groups(context, username, groupname, + gid, &supplementary_gids, &ngids); + if (r < 0) { + *exit_status = EXIT_GROUP; + return r; } } @@ -2558,14 +2519,6 @@ static int exec_child( } } - if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) { - r = enforce_groups(context, username, gid); - if (r < 0) { - *exit_status = EXIT_GROUP; - return r; - } - } - if (context->working_directory_home) wd = home; else if (context->working_directory) @@ -2573,6 +2526,15 @@ static int exec_child( else wd = "/"; + /* Drop group as early as possbile */ + if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) { + r = enforce_groups(context, gid, supplementary_gids, ngids); + if (r < 0) { + *exit_status = EXIT_GROUP; + return r; + } + } + if (params->flags & EXEC_APPLY_CHROOT) { if (!needs_mount_namespace && context->root_directory) if (chroot(context->root_directory) < 0) { diff --git a/src/core/job.c b/src/core/job.c index 7faf2ef686..3ecc8a1a73 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -927,7 +927,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user u = j->unit; job_finish_and_invalidate(j, JOB_TIMEOUT, true, false); - failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg); + emergency_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg, "job timed out"); return 0; } diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 08c88b6b53..af2f9d960b 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -188,13 +188,13 @@ Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate) Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0 Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout) -Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action) +Unit.JobTimeoutAction, config_parse_emergency_action, 0, offsetof(Unit, job_timeout_action) Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval) m4_dnl The following is a legacy alias name for compatibility Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) -Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) +Unit.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action) Unit.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg) Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions) Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions) @@ -251,9 +251,9 @@ Service.WatchdogSec, config_parse_sec, 0, m4_dnl The following three only exist for compatibility, they moved into Unit, see above Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) -Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) +Service.StartLimitAction, config_parse_emergency_action, 0, offsetof(Unit, start_limit_action) Service.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg) -Service.FailureAction, config_parse_failure_action, 0, offsetof(Service, failure_action) +Service.FailureAction, config_parse_emergency_action, 0, offsetof(Service, emergency_action) Service.Type, config_parse_service_type, 0, offsetof(Service, type) Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a69f60097d..118b39c1cf 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -2523,7 +2523,7 @@ int config_parse_unit_condition_null( } DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier"); -DEFINE_CONFIG_PARSE_ENUM(config_parse_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_emergency_action, emergency_action, EmergencyAction, "Failed to parse failure action specifier"); int config_parse_unit_requires_mounts_for( const char *unit, @@ -2618,6 +2618,7 @@ int config_parse_documentation(const char *unit, } #ifdef HAVE_SECCOMP + static int syscall_filter_parse_one( const char *unit, const char *filename, @@ -2628,27 +2629,29 @@ static int syscall_filter_parse_one( bool warn) { int r; - if (*t == '@') { - const SystemCallFilterSet *set; + if (t[0] == '@') { + const SyscallFilterSet *set; + const char *i; - for (set = syscall_filter_sets; set->set_name; set++) - if (streq(set->set_name, t)) { - const char *sys; + set = syscall_filter_set_find(t); + if (!set) { + if (warn) + log_syntax(unit, LOG_WARNING, filename, line, 0, "Don't know system call group, ignoring: %s", t); + return 0; + } - NULSTR_FOREACH(sys, set->value) { - r = syscall_filter_parse_one(unit, filename, line, c, invert, sys, false); - if (r < 0) - return r; - } - break; - } + NULSTR_FOREACH(i, set->value) { + r = syscall_filter_parse_one(unit, filename, line, c, invert, i, false); + if (r < 0) + return r; + } } else { int id; id = seccomp_syscall_resolve_name(t); if (id == __NR_SCMP_ERROR) { if (warn) - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); + log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse system call, ignoring: %s", t); return 0; } @@ -2662,8 +2665,9 @@ static int syscall_filter_parse_one( if (r < 0) return log_oom(); } else - set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); + (void) set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); } + return 0; } @@ -2682,8 +2686,7 @@ int config_parse_syscall_filter( ExecContext *c = data; Unit *u = userdata; bool invert = false; - const char *word, *state; - size_t l; + const char *p; int r; assert(filename); @@ -2722,19 +2725,24 @@ int config_parse_syscall_filter( } } - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *t = NULL; + p = rvalue; + for (;;) { + _cleanup_free_ char *word = NULL; - t = strndup(word, l); - if (!t) + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); + break; + } - r = syscall_filter_parse_one(unit, filename, line, c, invert, t, true); + r = syscall_filter_parse_one(unit, filename, line, c, invert, word, true); if (r < 0) return r; } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); /* Turn on NNP, but only if it wasn't configured explicitly * before, and only if we are in user mode. */ @@ -4315,7 +4323,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_unit_slice, "SLICE" }, { config_parse_documentation, "URL" }, { config_parse_service_timeout, "SECONDS" }, - { config_parse_failure_action, "ACTION" }, + { config_parse_emergency_action, "ACTION" }, { config_parse_set_status, "STATUS" }, { config_parse_service_sockets, "SOCKETS" }, { config_parse_environ, "ENVIRON" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 6d1fe55bcd..c05f205c37 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -75,7 +75,7 @@ int config_parse_unit_condition_string(const char *unit, const char *filename, u int config_parse_unit_condition_null(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_kill_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_notify_access(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_failure_action(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_emergency_action(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_unit_requires_mounts_for(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_syscall_filter(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_syscall_archs(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/core/main.c b/src/core/main.c index cf3c640a73..94602611a7 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -89,6 +89,7 @@ #include "user-util.h" #include "virt.h" #include "watchdog.h" +#include "emergency-action.h" static enum { ACTION_RUN, @@ -131,7 +132,7 @@ static bool arg_default_memory_accounting = false; static bool arg_default_tasks_accounting = true; static uint64_t arg_default_tasks_max = UINT64_MAX; static sd_id128_t arg_machine_id = {}; -static CADBurstAction arg_cad_burst_action = CAD_BURST_ACTION_REBOOT; +static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; noreturn static void freeze_or_reboot(void) { @@ -307,7 +308,7 @@ static int set_machine_id(const char *m) { return 0; } -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; @@ -649,8 +650,6 @@ static int config_parse_join_controllers(const char *unit, return 0; } -static DEFINE_CONFIG_PARSE_ENUM(config_parse_cad_burst_action, cad_burst_action, CADBurstAction, "Failed to parse service restart specifier"); - static int parse_config_file(void) { const ConfigTableItem items[] = { @@ -705,7 +704,7 @@ static int parse_config_file(void) { { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max }, - { "Manager", "CtrlAltDelBurstAction", config_parse_cad_burst_action, 0, &arg_cad_burst_action}, + { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, {} }; @@ -1570,7 +1569,7 @@ int main(int argc, char *argv[]) { } if (arg_system) { - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); } @@ -1778,7 +1777,7 @@ int main(int argc, char *argv[]) { (void) bump_rlimit_nofile(&saved_rlimit_nofile); if (empty_etc) { - r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, false, NULL, 0); + r = unit_file_preset_all(UNIT_FILE_SYSTEM, 0, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, NULL, 0); if (r < 0) log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r, "Failed to populate /etc with preset unit settings, ignoring: %m"); else diff --git a/src/core/manager.c b/src/core/manager.c index 65f163de31..ffccfdcd5e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1911,28 +1911,11 @@ static void manager_handle_ctrl_alt_del(Manager *m) { * 7 times within 2s, we reboot/shutdown immediately, * unless it was disabled in system.conf */ - if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == CAD_BURST_ACTION_IGNORE) + if (ratelimit_test(&m->ctrl_alt_del_ratelimit) || m->cad_burst_action == EMERGENCY_ACTION_NONE) manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY); - else { - switch (m->cad_burst_action) { - - case CAD_BURST_ACTION_REBOOT: - m->exit_code = MANAGER_REBOOT; - break; - - case CAD_BURST_ACTION_POWEROFF: - m->exit_code = MANAGER_POWEROFF; - break; - - default: - assert_not_reached("Unknown action."); - } - - log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.", - cad_burst_action_to_string(m->cad_burst_action)); - status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, performing immediate %s.", - cad_burst_action_to_string(m->cad_burst_action)); - } + else + emergency_action(m, m->cad_burst_action, NULL, + "Ctrl-Alt-Del was pressed more than 7 times within 2s"); } static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { @@ -3590,11 +3573,3 @@ static const char *const manager_state_table[_MANAGER_STATE_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState); - -static const char *const cad_burst_action_table[_CAD_BURST_ACTION_MAX] = { - [CAD_BURST_ACTION_IGNORE] = "ignore", - [CAD_BURST_ACTION_REBOOT] = "reboot-force", - [CAD_BURST_ACTION_POWEROFF] = "poweroff-force", -}; - -DEFINE_STRING_TABLE_LOOKUP(cad_burst_action, CADBurstAction); diff --git a/src/core/manager.h b/src/core/manager.h index 29fe14e10b..35172fdba9 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -62,14 +62,6 @@ typedef enum ManagerExitCode { _MANAGER_EXIT_CODE_INVALID = -1 } ManagerExitCode; -typedef enum CADBurstAction { - CAD_BURST_ACTION_IGNORE, - CAD_BURST_ACTION_REBOOT, - CAD_BURST_ACTION_POWEROFF, - _CAD_BURST_ACTION_MAX, - _CAD_BURST_ACTION_INVALID = -1 -} CADBurstAction; - typedef enum StatusType { STATUS_TYPE_EPHEMERAL, STATUS_TYPE_NORMAL, @@ -315,7 +307,7 @@ struct Manager { /* When the user hits C-A-D more than 7 times per 2s, do something immediately... */ RateLimit ctrl_alt_del_ratelimit; - CADBurstAction cad_burst_action; + EmergencyAction cad_burst_action; const char *unit_log_field; const char *unit_log_format_string; @@ -411,6 +403,3 @@ void manager_deserialize_gid_refs_one(Manager *m, const char *value); const char *manager_state_to_string(ManagerState m) _const_; ManagerState manager_state_from_string(const char *s) _pure_; - -const char *cad_burst_action_to_string(CADBurstAction a) _const_; -CADBurstAction cad_burst_action_from_string(const char *s) _pure_; diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 6caa15b0b8..a61677e645 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -94,6 +94,10 @@ <allow send_destination="org.freedesktop.systemd1" send_interface="org.freedesktop.systemd1.Manager" + send_member="GetUnitFileLinks"/> + + <allow send_destination="org.freedesktop.systemd1" + send_interface="org.freedesktop.systemd1.Manager" send_member="ListJobs"/> <allow send_destination="org.freedesktop.systemd1" diff --git a/src/core/scope.c b/src/core/scope.c index e7583f6d89..af0c43c7da 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -147,6 +147,34 @@ static int scope_verify(Scope *s) { return 0; } +static int scope_load_init_scope(Unit *u) { + assert(u); + + if (!unit_has_name(u, SPECIAL_INIT_SCOPE)) + return 0; + + u->transient = true; + u->no_gc = true; + + /* init.scope is a bit special, as it has to stick around forever. Because of its special semantics we + * synthesize it here, instead of relying on the unit file on disk. */ + + u->default_dependencies = false; + u->ignore_on_isolate = true; + u->refuse_manual_start = true; + u->refuse_manual_stop = true; + + SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14; + + /* Prettify things, if we can. */ + if (!u->description) + u->description = strdup("System and Service Manager"); + if (!u->documentation) + (void) strv_extend(&u->documentation, "man:systemd(1)"); + + return 1; +} + static int scope_load(Unit *u) { Scope *s = SCOPE(u); int r; @@ -158,6 +186,9 @@ static int scope_load(Unit *u) { /* Refuse to load non-transient scope units, but allow them while reloading. */ return -ENOENT; + r = scope_load_init_scope(u); + if (r < 0) + return r; r = unit_load_fragment_and_dropin_optional(u); if (r < 0) return r; @@ -543,25 +574,14 @@ static void scope_enumerate(Manager *m) { r = unit_add_name(u, SPECIAL_INIT_SCOPE); if (r < 0) { unit_free(u); - log_error_errno(r, "Failed to add init.scope name"); + log_error_errno(r, "Failed to add the " SPECIAL_INIT_SCOPE " name: %m"); return; } } u->transient = true; - u->default_dependencies = false; u->no_gc = true; - u->ignore_on_isolate = true; - u->refuse_manual_start = true; - u->refuse_manual_stop = true; SCOPE(u)->deserialized_state = SCOPE_RUNNING; - SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14; - - /* Prettify things, if we can. */ - if (!u->description) - u->description = strdup("System and Service Manager"); - if (!u->documentation) - (void) strv_extend(&u->documentation, "man:systemd(1)"); unit_add_to_load_queue(u); unit_add_to_dbus_queue(u); diff --git a/src/core/service.c b/src/core/service.c index 53c26984ca..ee4f4983fc 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1455,7 +1455,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) if (s->result != SERVICE_SUCCESS) { log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result)); - failure_action(UNIT(s)->manager, s->failure_action, UNIT(s)->reboot_arg); + emergency_action(UNIT(s)->manager, s->emergency_action, UNIT(s)->reboot_arg, "service failed"); } if (allow_restart && service_shall_restart(s)) { diff --git a/src/core/service.h b/src/core/service.h index 888007cc0b..2869144fcb 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -178,7 +178,7 @@ struct Service { char *status_text; int status_errno; - FailureAction failure_action; + EmergencyAction emergency_action; UnitRef accept_socket; diff --git a/src/core/slice.c b/src/core/slice.c index 03fe797f27..0fef29661f 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -130,6 +130,30 @@ static int slice_verify(Slice *s) { return 0; } +static int slice_load_root_slice(Unit *u) { + assert(u); + + if (!unit_has_name(u, SPECIAL_ROOT_SLICE)) + return 0; + + u->no_gc = true; + + /* The root slice is a bit special. For example it is always running and cannot be terminated. Because of its + * special semantics we synthesize it here, instead of relying on the unit file on disk. */ + + u->default_dependencies = false; + u->ignore_on_isolate = true; + u->refuse_manual_start = true; + u->refuse_manual_stop = true; + + if (!u->description) + u->description = strdup("Root Slice"); + if (!u->documentation) + u->documentation = strv_new("man:systemd.special(7)", NULL); + + return 1; +} + static int slice_load(Unit *u) { Slice *s = SLICE(u); int r; @@ -137,6 +161,9 @@ static int slice_load(Unit *u) { assert(s); assert(u->load_state == UNIT_STUB); + r = slice_load_root_slice(u); + if (r < 0) + return r; r = unit_load_fragment_and_dropin_optional(u); if (r < 0) return r; @@ -283,23 +310,14 @@ static void slice_enumerate(Manager *m) { r = unit_add_name(u, SPECIAL_ROOT_SLICE); if (r < 0) { unit_free(u); - log_error_errno(r, "Failed to add -.slice name"); + log_error_errno(r, "Failed to add the "SPECIAL_ROOT_SLICE " name: %m"); return; } } - u->default_dependencies = false; u->no_gc = true; - u->ignore_on_isolate = true; - u->refuse_manual_start = true; - u->refuse_manual_stop = true; SLICE(u)->deserialized_state = SLICE_ACTIVE; - if (!u->description) - u->description = strdup("Root Slice"); - if (!u->documentation) - (void) strv_extend(&u->documentation, "man:systemd.special(7)"); - unit_add_to_load_queue(u); unit_add_to_dbus_queue(u); } diff --git a/src/core/unit.c b/src/core/unit.c index 2fa397bd41..cabb1050a8 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -982,8 +982,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { if (u->job_timeout != USEC_INFINITY) fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0)); - if (u->job_timeout_action != FAILURE_ACTION_NONE) - fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, failure_action_to_string(u->job_timeout_action)); + if (u->job_timeout_action != EMERGENCY_ACTION_NONE) + fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action)); if (u->job_timeout_reboot_arg) fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg); @@ -1490,7 +1490,7 @@ int unit_start_limit_test(Unit *u) { log_unit_warning(u, "Start request repeated too quickly."); u->start_limit_hit = true; - return failure_action(u->manager, u->start_limit_action, u->reboot_arg); + return emergency_action(u->manager, u->start_limit_action, u->reboot_arg, "unit failed"); } /* Errors: diff --git a/src/core/unit.h b/src/core/unit.h index a8dd3e602c..adcdee6db6 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -29,7 +29,7 @@ typedef struct UnitRef UnitRef; typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; #include "condition.h" -#include "failure-action.h" +#include "emergency-action.h" #include "install.h" #include "list.h" #include "unit-name.h" @@ -114,7 +114,7 @@ struct Unit { /* Job timeout and action to take */ usec_t job_timeout; - FailureAction job_timeout_action; + EmergencyAction job_timeout_action; char *job_timeout_reboot_arg; /* References to this */ @@ -178,7 +178,7 @@ struct Unit { /* Put a ratelimit on unit starting */ RateLimit start_limit; - FailureAction start_limit_action; + EmergencyAction start_limit_action; char *reboot_arg; /* Make sure we never enter endless loops with the check unneeded logic, or the BindsTo= logic */ diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index de0a3b6f9c..e2dc4327fe 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -277,12 +277,12 @@ static crypto_device *get_crypto_device(const char *uuid) { return d; } -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; crypto_device *d; _cleanup_free_ char *uuid = NULL, *uuid_value = NULL; - if (STR_IN_SET(key, "luks", "rd.luks") && value) { + if (streq(key, "luks") && value) { r = parse_boolean(value); if (r < 0) @@ -290,7 +290,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_enabled = r; - } else if (STR_IN_SET(key, "luks.crypttab", "rd.luks.crypttab") && value) { + } else if (streq(key, "luks.crypttab") && value) { r = parse_boolean(value); if (r < 0) @@ -298,7 +298,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_read_crypttab = r; - } else if (STR_IN_SET(key, "luks.uuid", "rd.luks.uuid") && value) { + } else if (streq(key, "luks.uuid") && value) { d = get_crypto_device(startswith(value, "luks-") ? value+5 : value); if (!d) @@ -306,7 +306,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { d->create = arg_whitelist = true; - } else if (STR_IN_SET(key, "luks.options", "rd.luks.options") && value) { + } else if (streq(key, "luks.options") && value) { r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value); if (r == 2) { @@ -320,7 +320,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { } else if (free_and_strdup(&arg_default_options, value) < 0) return log_oom(); - } else if (STR_IN_SET(key, "luks.key", "rd.luks.key") && value) { + } else if (streq(key, "luks.key") && value) { r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value); if (r == 2) { @@ -334,7 +334,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { } else if (free_and_strdup(&arg_default_keyfile, value) < 0) return log_oom(); - } else if (STR_IN_SET(key, "luks.name", "rd.luks.name") && value) { + } else if (streq(key, "luks.name") && value) { r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value); if (r == 2) { @@ -478,7 +478,7 @@ int main(int argc, char *argv[]) { if (!arg_disks) goto cleanup; - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true); if (r < 0) { log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); r = EXIT_FAILURE; diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c index 7e80af78e7..7f11ec724d 100644 --- a/src/debug-generator/debug-generator.c +++ b/src/debug-generator/debug-generator.c @@ -33,7 +33,7 @@ static char **arg_mask = NULL; static char **arg_wants = NULL; static bool arg_debug_shell = false; -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; assert(key); @@ -178,7 +178,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index d32e1d923e..be25c6a2b2 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -94,7 +94,7 @@ static void start_target(const char *target, const char *mode) { log_error("Failed to start unit: %s", bus_error_message(&error, r)); } -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; assert(key); @@ -293,7 +293,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 33af553d0d..e77bd71a52 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -590,7 +590,7 @@ static int add_sysroot_usr_mount(void) { "/proc/cmdline"); } -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last @@ -674,7 +674,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 6cc1aad705..a098b27a8e 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -907,7 +907,7 @@ fallback: return 1; } -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; assert(key); @@ -1018,7 +1018,7 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; } - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index d7ee80d58f..17e670604e 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -33,7 +33,7 @@ static const char *arg_dest = "/tmp"; static char *arg_resume_dev = NULL; -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { if (streq(key, "resume") && value) { free(arg_resume_dev); @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) { if (!in_initrd()) return EXIT_SUCCESS; - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 5ea65e2deb..908c7b8eeb 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -71,6 +71,7 @@ #include "string-table.h" #include "string-util.h" #include "user-util.h" +#include "syslog-util.h" #define USER_JOURNALS_MAX 1024 @@ -130,8 +131,6 @@ static void cache_space_invalidate(JournalStorageSpace *space) { } static int cache_space_refresh(Server *s, JournalStorage *storage) { - - _cleanup_closedir_ DIR *d = NULL; JournalStorageSpace *space; JournalMetrics *metrics; uint64_t vfs_used, vfs_avail, avail; @@ -1527,55 +1526,68 @@ static int setup_signals(Server *s) { return 0; } -static int server_parse_proc_cmdline(Server *s) { - _cleanup_free_ char *line = NULL; - const char *p; +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { + Server *s = data; int r; - r = proc_cmdline(&line); - if (r < 0) { - log_warning_errno(r, "Failed to read /proc/cmdline, ignoring: %m"); - return 0; - } - - p = line; - for (;;) { - _cleanup_free_ char *word = NULL; + assert(s); - r = extract_first_word(&p, &word, NULL, 0); + if (streq(key, "systemd.journald.forward_to_syslog")) { + r = value ? parse_boolean(value) : true; if (r < 0) - return log_error_errno(r, "Failed to parse journald syntax \"%s\": %m", line); - - if (r == 0) - break; - - if (startswith(word, "systemd.journald.forward_to_syslog=")) { - r = parse_boolean(word + 35); - if (r < 0) - log_warning("Failed to parse forward to syslog switch %s. Ignoring.", word + 35); - else - s->forward_to_syslog = r; - } else if (startswith(word, "systemd.journald.forward_to_kmsg=")) { - r = parse_boolean(word + 33); - if (r < 0) - log_warning("Failed to parse forward to kmsg switch %s. Ignoring.", word + 33); - else - s->forward_to_kmsg = r; - } else if (startswith(word, "systemd.journald.forward_to_console=")) { - r = parse_boolean(word + 36); - if (r < 0) - log_warning("Failed to parse forward to console switch %s. Ignoring.", word + 36); - else - s->forward_to_console = r; - } else if (startswith(word, "systemd.journald.forward_to_wall=")) { - r = parse_boolean(word + 33); - if (r < 0) - log_warning("Failed to parse forward to wall switch %s. Ignoring.", word + 33); - else - s->forward_to_wall = r; - } else if (startswith(word, "systemd.journald")) - log_warning("Invalid systemd.journald parameter. Ignoring."); - } + log_warning("Failed to parse forward to syslog switch \"%s\". Ignoring.", value); + else + s->forward_to_syslog = r; + } else if (streq(key, "systemd.journald.forward_to_kmsg")) { + r = value ? parse_boolean(value) : true; + if (r < 0) + log_warning("Failed to parse forward to kmsg switch \"%s\". Ignoring.", value); + else + s->forward_to_kmsg = r; + } else if (streq(key, "systemd.journald.forward_to_console")) { + r = value ? parse_boolean(value) : true; + if (r < 0) + log_warning("Failed to parse forward to console switch \"%s\". Ignoring.", value); + else + s->forward_to_console = r; + } else if (streq(key, "systemd.journald.forward_to_wall")) { + r = value ? parse_boolean(value) : true; + if (r < 0) + log_warning("Failed to parse forward to wall switch \"%s\". Ignoring.", value); + else + s->forward_to_wall = r; + } else if (streq(key, "systemd.journald.max_level_console") && value) { + r = log_level_from_string(value); + if (r < 0) + log_warning("Failed to parse max level console value \"%s\". Ignoring.", value); + else + s->max_level_console = r; + } else if (streq(key, "systemd.journald.max_level_store") && value) { + r = log_level_from_string(value); + if (r < 0) + log_warning("Failed to parse max level store value \"%s\". Ignoring.", value); + else + s->max_level_store = r; + } else if (streq(key, "systemd.journald.max_level_syslog") && value) { + r = log_level_from_string(value); + if (r < 0) + log_warning("Failed to parse max level syslog value \"%s\". Ignoring.", value); + else + s->max_level_syslog = r; + } else if (streq(key, "systemd.journald.max_level_kmsg") && value) { + r = log_level_from_string(value); + if (r < 0) + log_warning("Failed to parse max level kmsg value \"%s\". Ignoring.", value); + else + s->max_level_kmsg = r; + } else if (streq(key, "systemd.journald.max_level_wall") && value) { + r = log_level_from_string(value); + if (r < 0) + log_warning("Failed to parse max level wall value \"%s\". Ignoring.", value); + else + s->max_level_wall = r; + } else if (startswith(key, "systemd.journald")) + log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key); /* do not warn about state here, since probably systemd already did */ return 0; @@ -1886,7 +1898,7 @@ int server_init(Server *s) { journal_reset_metrics(&s->runtime_storage.metrics); server_parse_config_file(s); - server_parse_proc_cmdline(s); + parse_proc_cmdline(parse_proc_cmdline_item, s, true); if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) { log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0", diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index f75015d8c3..0901fea8dc 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -59,10 +59,10 @@ static int add_modules(const char *p) { return 0; } -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { int r; - if (STR_IN_SET(key, "modules-load", "rd.modules-load") && value) { + if (streq(key, "modules-load") && value) { r = add_modules(value); if (r < 0) return r; @@ -226,7 +226,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index c2b7970623..b282634e4b 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -57,6 +57,8 @@ static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { unsigned preference; usec_t time_now; int r; + Address *address; + Iterator i; assert(link); assert(rt); @@ -75,6 +77,32 @@ static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { return; } + SET_FOREACH(address, link->addresses, i) { + if (!memcmp(&gateway, &address->in_addr.in6, + sizeof(address->in_addr.in6))) { + char buffer[INET6_ADDRSTRLEN]; + + log_link_debug(link, "No NDisc route added, gateway %s matches local address", + inet_ntop(AF_INET6, + &address->in_addr.in6, + buffer, sizeof(buffer))); + return; + } + } + + SET_FOREACH(address, link->addresses_foreign, i) { + if (!memcmp(&gateway, &address->in_addr.in6, + sizeof(address->in_addr.in6))) { + char buffer[INET6_ADDRSTRLEN]; + + log_link_debug(link, "No NDisc route added, gateway %s matches local address", + inet_ntop(AF_INET6, + &address->in_addr.in6, + buffer, sizeof(buffer))); + 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"); diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index 7913b0088e..46d1669337 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -268,13 +268,13 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin if (b->arp_all_targets != _NETDEV_BOND_ARP_ALL_TARGETS_INVALID) { r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->arp_all_targets); if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_VALIDATE attribute: %m"); + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m"); } if (b->primary_reselect != _NETDEV_BOND_PRIMARY_RESELECT_INVALID) { - r = sd_netlink_message_append_u32(m, IFLA_BOND_ARP_ALL_TARGETS, b->primary_reselect); + r = sd_netlink_message_append_u8(m, IFLA_BOND_PRIMARY_RESELECT, b->primary_reselect); if (r < 0) - return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m"); + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_PRIMARY_RESELECT attribute: %m"); } if (b->resend_igmp <= RESEND_IGMP_MAX) { diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 5587961b9f..bcf8186c33 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -49,7 +49,7 @@ Network.EmitLLDP, config_parse_lldp_emit, Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 -Network.DNS, config_parse_strv, 0, offsetof(Network, dns) +Network.DNS, config_parse_dns, 0, 0 Network.LLMNR, config_parse_resolve_support, 0, offsetof(Network, llmnr) Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns) Network.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Network, dnssec_mode) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 584cb96979..042232fcac 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -979,6 +979,56 @@ int config_parse_dhcp_server_ntp( } } +int config_parse_dns( + 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 *n = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *w = NULL; + union in_addr_union a; + int family; + + r = extract_first_word(&rvalue, &w, WHITESPACE, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); + break; + } + + r = in_addr_from_string_auto(w, &family, &a); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse dns server address, ignoring: %s", w); + continue; + } + + r = strv_consume(&n->dns, w); + if (r < 0) + return log_oom(); + + w = NULL; + } + + return 0; +} + int config_parse_dnssec_negative_trust_anchors( const char *unit, const char *filename, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index ef4b499ab9..42fc82d392 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -220,6 +220,7 @@ int config_parse_netdev(const char *unit, const char *filename, unsigned line, c int config_parse_domains(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_tunnel(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_dhcp(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_dns(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_dhcp_client_identifier(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_ipv6token(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_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 44dc9bfcf4..115de64cf9 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -300,6 +300,59 @@ int mount_sysfs(const char *dest) { MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL); } +static int mkdir_userns(const char *path, mode_t mode, bool in_userns, uid_t uid_shift) { + int r; + + assert(path); + + r = mkdir(path, mode); + if (r < 0 && errno != EEXIST) + return -errno; + + if (!in_userns) { + r = lchown(path, uid_shift, uid_shift); + if (r < 0) + return -errno; + } + + return 0; +} + +static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, bool in_userns, uid_t uid_shift) { + const char *p, *e; + int r; + + assert(path); + + if (prefix && !path_startswith(path, prefix)) + return -ENOTDIR; + + /* create every parent directory in the path, except the last component */ + p = path + strspn(path, "/"); + for (;;) { + char t[strlen(path) + 1]; + + e = p + strcspn(p, "/"); + p = e + strspn(e, "/"); + + /* Is this the last component? If so, then we're done */ + if (*p == 0) + break; + + memcpy(t, path, e - path); + t[e-path] = 0; + + if (prefix && path_startswith(prefix, t)) + continue; + + r = mkdir_userns(t, mode, in_userns, uid_shift); + if (r < 0) + return r; + } + + return mkdir_userns(path, mode, in_userns, uid_shift); +} + int mount_all(const char *dest, bool use_userns, bool in_userns, bool use_netns, @@ -361,7 +414,7 @@ int mount_all(const char *dest, if (mount_table[k].what && r > 0) continue; - r = mkdir_p(where, 0755); + r = mkdir_userns_p(dest, where, 0755, in_userns, uid_shift); if (r < 0 && r != -EEXIST) { if (mount_table[k].fatal) return log_error_errno(r, "Failed to create directory %s: %m", where); diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c index 44a0b397ab..03a397d30c 100644 --- a/src/nspawn/nspawn-seccomp.c +++ b/src/nspawn/nspawn-seccomp.c @@ -135,15 +135,9 @@ int setup_seccomp(uint64_t cap_list_retain) { return 0; } - seccomp = seccomp_init(SCMP_ACT_ALLOW); - if (!seccomp) - return log_oom(); - - r = seccomp_add_secondary_archs(seccomp); - if (r < 0) { - log_error_errno(r, "Failed to add secondary archs to seccomp filter: %m"); - goto finish; - } + r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW); + if (r < 0) + return log_error_errno(r, "Failed to allocate seccomp object: %m"); r = seccomp_add_default_syscall_filter(seccomp, cap_list_retain); if (r < 0) @@ -171,12 +165,6 @@ int setup_seccomp(uint64_t cap_list_retain) { goto finish; } - r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); - if (r < 0) { - log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m"); - goto finish; - } - r = seccomp_load(seccomp); if (r < 0) { log_error_errno(r, "Failed to install seccomp audit filter: %m"); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 2cbe563953..295293858e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2684,6 +2684,10 @@ static int inner_child( } } + r = reset_uid_gid(); + if (r < 0) + return log_error_errno(r, "Couldn't become new root: %m"); + r = mount_all(NULL, arg_userns_mode != USER_NAMESPACE_NO, true, @@ -2726,10 +2730,6 @@ static int inner_child( return r; } - r = reset_uid_gid(); - if (r < 0) - return log_error_errno(r, "Couldn't become new root: %m"); - r = setup_boot_id(NULL); if (r < 0) return r; diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index eea91e3e88..d46a3afe91 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -121,6 +121,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + enum nss_status ret = NSS_STATUS_UNAVAIL; const char *canonical = NULL; size_t l, ms, idx; char *r_name; @@ -167,6 +168,10 @@ enum nss_status _nss_resolve_gethostbyname4_r( if (bus_error_shall_fallback(&error)) goto fallback; + /* Treat all other error conditions as NOTFOUND, and fail. This includes DNSSEC errors and + suchlike. (We don't use UNAVAIL in this case so that the nsswitch.conf configuration can distuingish + such executed but negative replies from complete failure to talk to resolved. */ + ret = NSS_STATUS_NOTFOUND; goto fail; } @@ -279,12 +284,9 @@ fallback: } fail: - /* When we arrive here, resolved runs and has answered (fallback to - * "dns" is handled earlier). So we have a definitive "no" answer and - * should not fall back to subsequent NSS modules via "UNAVAIL". */ *errnop = -r; *h_errnop = NO_RECOVERY; - return NSS_STATUS_NOTFOUND; + return ret; } enum nss_status _nss_resolve_gethostbyname3_r( @@ -300,6 +302,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + enum nss_status ret = NSS_STATUS_UNAVAIL; size_t l, idx, ms, alen; const char *canonical; int c, r, i = 0; @@ -353,6 +356,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( if (bus_error_shall_fallback(&error)) goto fallback; + ret = NSS_STATUS_NOTFOUND; goto fail; } @@ -479,7 +483,7 @@ fallback: fail: *errnop = -r; *h_errnop = NO_RECOVERY; - return NSS_STATUS_NOTFOUND; + return ret; } enum nss_status _nss_resolve_gethostbyaddr2_r( @@ -494,6 +498,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + enum nss_status ret = NSS_STATUS_UNAVAIL; unsigned c = 0, i = 0; size_t ms = 0, idx; const char *n; @@ -560,7 +565,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( if (bus_error_shall_fallback(&error)) goto fallback; - + ret = NSS_STATUS_NOTFOUND; goto fail; } @@ -669,7 +674,7 @@ fallback: fail: *errnop = -r; *h_errnop = NO_RECOVERY; - return NSS_STATUS_NOTFOUND; + return ret; } NSS_GETHOSTBYNAME_FALLBACKS(resolve); diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index 6d8c05f046..2714cde5c7 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -32,7 +32,7 @@ static bool arg_skip = false; static bool arg_force = false; -static int parse_proc_cmdline_item(const char *key, const char *value) { +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { if (streq(key, "quotacheck.mode") && value) { @@ -88,7 +88,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 7282848e35..22c64e8491 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -575,8 +575,7 @@ void dns_server_warn_downgrade(DnsServer *server) { server->warned_downgrade = true; } -bool dns_server_limited_domains(DnsServer *server) -{ +bool dns_server_limited_domains(DnsServer *server) { DnsSearchDomain *domain; bool domain_restricted = false; @@ -589,7 +588,7 @@ bool dns_server_limited_domains(DnsServer *server) if (domain->route_only) { domain_restricted = true; /* ~. means "any domain", thus it is a global server */ - if (streq(DNS_SEARCH_DOMAIN_NAME(domain), ".")) + if (dns_name_is_root(DNS_SEARCH_DOMAIN_NAME(domain))) return false; } diff --git a/src/shared/condition.c b/src/shared/condition.c index f13fa6a9fd..69b4837e1f 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -329,9 +329,9 @@ static int condition_test_needs_update(Condition *c) { uint64_t timestamp; int r; - r = parse_env_file(p, NULL, "TimestampNSec", ×tamp_str, NULL); + r = parse_env_file(p, NULL, "TIMESTAMP_NSEC", ×tamp_str, NULL); if (r < 0) { - log_error_errno(-r, "Failed to parse timestamp file '%s', using mtime: %m", p); + log_error_errno(r, "Failed to parse timestamp file '%s', using mtime: %m", p); return true; } else if (r == 0) { log_debug("No data in timestamp file '%s', using mtime", p); @@ -340,12 +340,11 @@ static int condition_test_needs_update(Condition *c) { r = safe_atou64(timestamp_str, ×tamp); if (r < 0) { - log_error_errno(-r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", - timestamp_str, p); + log_error_errno(r, "Failed to parse timestamp value '%s' in file '%s', using mtime: %m", timestamp_str, p); return true; } - other.st_mtim.tv_nsec = timestamp % NSEC_PER_SEC; + timespec_store(&other.st_mtim, timestamp); } return usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec; diff --git a/src/shared/install.c b/src/shared/install.c index d33a658d0a..96fba6e25b 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -518,6 +518,7 @@ static int remove_marked_symlinks_fd( const char *path, const char *config_path, const LookupPaths *lp, + bool dry_run, bool *restart, UnitFileChange **changes, unsigned *n_changes) { @@ -566,7 +567,7 @@ static int remove_marked_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, dry_run, restart, changes, n_changes); if (q < 0 && r == 0) r = q; @@ -603,14 +604,16 @@ static int remove_marked_symlinks_fd( if (!found) continue; - if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) { - if (r == 0) - r = -errno; - unit_file_changes_add(changes, n_changes, -errno, p, NULL); - continue; - } + if (!dry_run) { + if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) { + if (r == 0) + r = -errno; + unit_file_changes_add(changes, n_changes, -errno, p, NULL); + continue; + } - (void) rmdir_parents(p, config_path); + (void) rmdir_parents(p, config_path); + } unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); @@ -621,7 +624,7 @@ static int remove_marked_symlinks_fd( q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p); if (q < 0) return q; - if (q > 0) + if (q > 0 && !dry_run) *restart = true; } } @@ -633,6 +636,7 @@ static int remove_marked_symlinks( Set *remove_symlinks_to, const char *config_path, const LookupPaths *lp, + bool dry_run, UnitFileChange **changes, unsigned *n_changes) { @@ -659,7 +663,7 @@ static int remove_marked_symlinks( return -errno; /* This takes possession of cfd and closes it */ - q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes); + q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, dry_run, &restart, changes, n_changes); if (r == 0) r = q; } while (restart); @@ -1805,10 +1809,9 @@ static int install_context_mark_for_removal( int unit_file_mask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1824,7 +1827,7 @@ int unit_file_mask( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { _cleanup_free_ char *path = NULL; @@ -1840,7 +1843,7 @@ int unit_file_mask( if (!path) return -ENOMEM; - q = create_symlink(&paths, "/dev/null", path, force, changes, n_changes); + q = create_symlink(&paths, "/dev/null", path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); if (q < 0 && r >= 0) r = q; } @@ -1850,7 +1853,7 @@ int unit_file_mask( int unit_file_unmask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, @@ -1862,6 +1865,7 @@ int unit_file_unmask( size_t n_todo = 0, n_allocated = 0; const char *config_path; char **i; + bool dry_run; int r, q; assert(scope >= 0); @@ -1871,7 +1875,8 @@ int unit_file_unmask( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; + dry_run = !!(flags & UNIT_FILE_DRY_RUN); STRV_FOREACH(i, files) { _cleanup_free_ char *path = NULL; @@ -1908,7 +1913,7 @@ int unit_file_unmask( if (!path) return -ENOMEM; - if (unlink(path) < 0) { + if (!dry_run && unlink(path) < 0) { if (errno != ENOENT) { if (r >= 0) r = -errno; @@ -1926,7 +1931,7 @@ int unit_file_unmask( return q; } - q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, dry_run, changes, n_changes); if (r >= 0) r = q; @@ -1935,10 +1940,9 @@ int unit_file_unmask( int unit_file_link( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1956,7 +1960,7 @@ int unit_file_link( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { _cleanup_free_ char *full = NULL; @@ -2005,7 +2009,7 @@ int unit_file_link( if (!new_path) return -ENOMEM; - q = create_symlink(&paths, *i, new_path, force, changes, n_changes); + q = create_symlink(&paths, *i, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); if (q < 0 && r >= 0) r = q; } @@ -2177,11 +2181,11 @@ int unit_file_revert( return q; } - q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, false, changes, n_changes); if (r >= 0) r = q; - q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes); + q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, false, changes, n_changes); if (r >= 0) r = q; @@ -2190,12 +2194,11 @@ int unit_file_revert( int unit_file_add_dependency( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, const char *target, UnitDependency dep, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2220,7 +2223,7 @@ int unit_file_add_dependency( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info, changes, n_changes); @@ -2260,15 +2263,14 @@ int unit_file_add_dependency( return -ENOMEM; } - return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); + return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); } int unit_file_enable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2286,7 +2288,7 @@ int unit_file_enable( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(f, files) { r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, @@ -2305,12 +2307,12 @@ int unit_file_enable( is useful to determine whether the passed files had any installation data at all. */ - return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes); + return install_context_apply(scope, &c, &paths, config_path, !!(flags & UNIT_FILE_FORCE), SEARCH_LOAD, changes, n_changes); } int unit_file_disable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, @@ -2330,7 +2332,7 @@ int unit_file_disable( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; STRV_FOREACH(i, files) { if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) @@ -2345,15 +2347,14 @@ int unit_file_disable( if (r < 0) return r; - return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes); + return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, !!(flags & UNIT_FILE_DRY_RUN), changes, n_changes); } int unit_file_reenable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2368,19 +2369,19 @@ int unit_file_reenable( n[i] = basename(files[i]); n[i] = NULL; - r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes); + r = unit_file_disable(scope, flags, root_dir, n, changes, n_changes); if (r < 0) return r; /* But the enable command with the full name */ - return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes); + return unit_file_enable(scope, flags, root_dir, files, changes, n_changes); } int unit_file_set_default( UnitFileScope scope, + UnitFileFlags flags, const char *root_dir, const char *name, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2411,7 +2412,7 @@ int unit_file_set_default( return r; new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET); - return create_symlink(&paths, i->path, new_path, force, changes, n_changes); + return create_symlink(&paths, i->path, new_path, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } int unit_file_get_default( @@ -2735,7 +2736,7 @@ static int execute_preset( if (r < 0) return r; - r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes); + r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, false, changes, n_changes); } else r = 0; @@ -2803,11 +2804,10 @@ static int preset_prepare_one( int unit_file_preset( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2826,7 +2826,7 @@ int unit_file_preset( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; r = read_presets(scope, root_dir, &presets); if (r < 0) @@ -2838,15 +2838,14 @@ int unit_file_preset( return r; } - return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } int unit_file_preset_all( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -2865,7 +2864,7 @@ int unit_file_preset_all( if (r < 0) return r; - config_path = runtime ? paths.runtime_config : paths.persistent_config; + config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config; r = read_presets(scope, root_dir, &presets); if (r < 0) @@ -2906,7 +2905,7 @@ int unit_file_preset_all( } } - return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes); + return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } static void unit_file_list_free_one(UnitFileList *f) { diff --git a/src/shared/install.h b/src/shared/install.h index b1f220693b..7a5859e729 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -23,6 +23,7 @@ typedef enum UnitFileScope UnitFileScope; typedef enum UnitFileState UnitFileState; typedef enum UnitFilePresetMode UnitFilePresetMode; typedef enum UnitFileChangeType UnitFileChangeType; +typedef enum UnitFileFlags UnitFileFlags; typedef enum UnitFileType UnitFileType; typedef struct UnitFileChange UnitFileChange; typedef struct UnitFileList UnitFileList; @@ -78,6 +79,12 @@ enum UnitFileChangeType { _UNIT_FILE_CHANGE_INVALID = INT_MIN }; +enum UnitFileFlags { + UNIT_FILE_RUNTIME = 1, + UNIT_FILE_FORCE = 1 << 1, + UNIT_FILE_DRY_RUN = 1 << 2, +}; + /* type can either one of the UnitFileChangeTypes listed above, or a negative error. * If source is specified, it should be the contents of the path symlink. * In case of an error, source should be the existing symlink contents or NULL @@ -144,65 +151,59 @@ bool unit_type_may_template(UnitType type) _const_; int unit_file_enable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_disable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); int unit_file_reenable( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_preset( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_preset_all( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, UnitFilePresetMode mode, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_mask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_unmask( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); int unit_file_link( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_revert( @@ -213,9 +214,9 @@ int unit_file_revert( unsigned *n_changes); int unit_file_set_default( UnitFileScope scope, + UnitFileFlags flags, const char *root_dir, const char *file, - bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_get_default( @@ -224,12 +225,11 @@ int unit_file_get_default( char **name); int unit_file_add_dependency( UnitFileScope scope, - bool runtime, + UnitFileFlags flags, const char *root_dir, char **files, const char *target, UnitDependency dep, - bool force, UnitFileChange **changes, unsigned *n_changes); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 8116c7671f..6252cd16a6 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -26,6 +26,7 @@ #include "macro.h" #include "seccomp-util.h" #include "string-util.h" +#include "util.h" const char* seccomp_arch_to_string(uint32_t c) { @@ -73,7 +74,34 @@ int seccomp_arch_from_string(const char *n, uint32_t *ret) { return 0; } -int seccomp_add_secondary_archs(scmp_filter_ctx *c) { +int seccomp_init_conservative(scmp_filter_ctx *ret, uint32_t default_action) { + scmp_filter_ctx seccomp; + int r; + + /* Much like seccomp_init(), but tries to be a bit more conservative in its defaults: all secondary archs are + * added by default, and NNP is turned off. */ + + seccomp = seccomp_init(default_action); + if (!seccomp) + return -ENOMEM; + + r = seccomp_add_secondary_archs(seccomp); + if (r < 0) + goto finish; + + r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); + if (r < 0) + goto finish; + + *ret = seccomp; + return 0; + +finish: + seccomp_release(seccomp); + return r; +} + +int seccomp_add_secondary_archs(scmp_filter_ctx c) { #if defined(__i386__) || defined(__x86_64__) int r; @@ -110,7 +138,6 @@ int seccomp_add_secondary_archs(scmp_filter_ctx *c) { #endif return 0; - } static bool is_basic_seccomp_available(void) { @@ -132,28 +159,30 @@ bool is_seccomp_available(void) { return cached_enabled; } -const SystemCallFilterSet syscall_filter_sets[] = { - { +const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = { + [SYSCALL_FILTER_SET_CLOCK] = { /* Clock */ - .set_name = "@clock", + .name = "@clock", .value = "adjtimex\0" "clock_adjtime\0" "clock_settime\0" "settimeofday\0" "stime\0" - }, { + }, + [SYSCALL_FILTER_SET_CPU_EMULATION] = { /* CPU emulation calls */ - .set_name = "@cpu-emulation", + .name = "@cpu-emulation", .value = "modify_ldt\0" "subpage_prot\0" "switch_endian\0" "vm86\0" "vm86old\0" - }, { + }, + [SYSCALL_FILTER_SET_DEBUG] = { /* Debugging/Performance Monitoring/Tracing */ - .set_name = "@debug", + .name = "@debug", .value = "lookup_dcookie\0" "perf_event_open\0" @@ -161,11 +190,14 @@ const SystemCallFilterSet syscall_filter_sets[] = { "process_vm_writev\0" "ptrace\0" "rtas\0" +#ifdef __NR_s390_runtime_instr "s390_runtime_instr\0" +#endif "sys_debug_setcontext\0" - }, { + }, + [SYSCALL_FILTER_SET_DEFAULT] = { /* Default list */ - .set_name = "@default", + .name = "@default", .value = "execve\0" "exit\0" @@ -173,9 +205,10 @@ const SystemCallFilterSet syscall_filter_sets[] = { "getrlimit\0" /* make sure processes can query stack size and such */ "rt_sigreturn\0" "sigreturn\0" - }, { + }, + [SYSCALL_FILTER_SET_IO_EVENT] = { /* Event loop use */ - .set_name = "@io-event", + .name = "@io-event", .value = "_newselect\0" "epoll_create1\0" @@ -191,9 +224,10 @@ const SystemCallFilterSet syscall_filter_sets[] = { "ppoll\0" "pselect6\0" "select\0" - }, { + }, + [SYSCALL_FILTER_SET_IPC] = { /* Message queues, SYSV IPC or other IPC: unusual */ - .set_name = "@ipc", + .name = "@ipc", .value = "ipc\0" "mq_getsetattr\0" "mq_notify\0" @@ -215,33 +249,36 @@ const SystemCallFilterSet syscall_filter_sets[] = { "shmctl\0" "shmdt\0" "shmget\0" - }, { + }, + [SYSCALL_FILTER_SET_KEYRING] = { /* Keyring */ - .set_name = "@keyring", + .name = "@keyring", .value = "add_key\0" "keyctl\0" "request_key\0" - }, { + }, + [SYSCALL_FILTER_SET_MODULE] = { /* Kernel module control */ - .set_name = "@module", + .name = "@module", .value = "delete_module\0" "finit_module\0" "init_module\0" - }, { + }, + [SYSCALL_FILTER_SET_MOUNT] = { /* Mounting */ - .set_name = "@mount", + .name = "@mount", .value = "chroot\0" "mount\0" - "oldumount\0" "pivot_root\0" "umount2\0" "umount\0" - }, { + }, + [SYSCALL_FILTER_SET_NETWORK_IO] = { /* Network or Unix socket IO, should not be needed if not network facing */ - .set_name = "@network-io", + .name = "@network-io", .value = "accept4\0" "accept\0" @@ -264,9 +301,10 @@ const SystemCallFilterSet syscall_filter_sets[] = { "socket\0" "socketcall\0" "socketpair\0" - }, { + }, + [SYSCALL_FILTER_SET_OBSOLETE] = { /* Unusual, obsolete or unimplemented, some unknown even to libseccomp */ - .set_name = "@obsolete", + .name = "@obsolete", .value = "_sysctl\0" "afs_syscall\0" @@ -292,9 +330,10 @@ const SystemCallFilterSet syscall_filter_sets[] = { "uselib\0" "ustat\0" "vserver\0" - }, { + }, + [SYSCALL_FILTER_SET_PRIVILEGED] = { /* Nice grab-bag of all system calls which need superuser capabilities */ - .set_name = "@privileged", + .name = "@privileged", .value = "@clock\0" "@module\0" @@ -331,11 +370,12 @@ const SystemCallFilterSet syscall_filter_sets[] = { "setuid\0" "swapoff\0" "swapon\0" - "sysctl\0" + "_sysctl\0" "vhangup\0" - }, { + }, + [SYSCALL_FILTER_SET_PROCESS] = { /* Process control, execution, namespaces */ - .set_name = "@process", + .name = "@process", .value = "arch_prctl\0" "clone\0" @@ -349,19 +389,90 @@ const SystemCallFilterSet syscall_filter_sets[] = { "tkill\0" "unshare\0" "vfork\0" - }, { + }, + [SYSCALL_FILTER_SET_RAW_IO] = { /* Raw I/O ports */ - .set_name = "@raw-io", + .name = "@raw-io", .value = "ioperm\0" "iopl\0" "pciconfig_iobase\0" "pciconfig_read\0" "pciconfig_write\0" +#ifdef __NR_s390_pci_mmio_read "s390_pci_mmio_read\0" +#endif +#ifdef __NR_s390_pci_mmio_write "s390_pci_mmio_write\0" - }, { - .set_name = NULL, - .value = NULL - } +#endif + }, }; + +const SyscallFilterSet *syscall_filter_set_find(const char *name) { + unsigned i; + + if (isempty(name) || name[0] != '@') + return NULL; + + for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) + if (streq(syscall_filter_sets[i].name, name)) + return syscall_filter_sets + i; + + return NULL; +} + +int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action) { + const char *sys; + int r; + + assert(seccomp); + assert(set); + + NULSTR_FOREACH(sys, set->value) { + int id; + + if (sys[0] == '@') { + const SyscallFilterSet *other; + + other = syscall_filter_set_find(sys); + if (!other) + return -EINVAL; + + r = seccomp_add_syscall_filter_set(seccomp, other, action); + } else { + id = seccomp_syscall_resolve_name(sys); + if (id == __NR_SCMP_ERROR) + return -EINVAL; + + r = seccomp_rule_add(seccomp, action, id, 0); + } + if (r < 0) + return r; + } + + return 0; +} + +int seccomp_load_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action) { + scmp_filter_ctx seccomp; + int r; + + assert(set); + + /* The one-stop solution: allocate a seccomp object, add a filter to it, and apply it */ + + r = seccomp_init_conservative(&seccomp, default_action); + if (r < 0) + return r; + + r = seccomp_add_syscall_filter_set(seccomp, set, action); + if (r < 0) + goto finish; + + r = seccomp_load(seccomp); + +finish: + seccomp_release(seccomp); + return r; + +} diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index cca7c17912..8050fc6fbf 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -20,18 +20,45 @@ ***/ #include <seccomp.h> +#include <stdbool.h> #include <stdint.h> 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); +int seccomp_init_conservative(scmp_filter_ctx *ret, uint32_t default_action); + +int seccomp_add_secondary_archs(scmp_filter_ctx c); bool is_seccomp_available(void); -typedef struct SystemCallFilterSet { - const char *set_name; +typedef struct SyscallFilterSet { + const char *name; const char *value; -} SystemCallFilterSet; +} SyscallFilterSet; + +enum { + SYSCALL_FILTER_SET_CLOCK, + SYSCALL_FILTER_SET_CPU_EMULATION, + SYSCALL_FILTER_SET_DEBUG, + SYSCALL_FILTER_SET_DEFAULT, + SYSCALL_FILTER_SET_IO_EVENT, + SYSCALL_FILTER_SET_IPC, + SYSCALL_FILTER_SET_KEYRING, + SYSCALL_FILTER_SET_MODULE, + SYSCALL_FILTER_SET_MOUNT, + SYSCALL_FILTER_SET_NETWORK_IO, + SYSCALL_FILTER_SET_OBSOLETE, + SYSCALL_FILTER_SET_PRIVILEGED, + SYSCALL_FILTER_SET_PROCESS, + SYSCALL_FILTER_SET_RAW_IO, + _SYSCALL_FILTER_SET_MAX +}; + +extern const SyscallFilterSet syscall_filter_sets[]; + +const SyscallFilterSet *syscall_filter_set_find(const char *name); + +int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action); -extern const SystemCallFilterSet syscall_filter_sets[]; +int seccomp_load_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 129706d15f..35d5c11cc7 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -189,6 +189,11 @@ typedef enum BusFocus { static sd_bus *busses[_BUS_FOCUS_MAX] = {}; +static UnitFileFlags args_to_flags(void) { + return (arg_runtime ? UNIT_FILE_RUNTIME : 0) | + (arg_force ? UNIT_FILE_FORCE : 0); +} + static int acquire_bus(BusFocus focus, sd_bus **ret) { int r; @@ -2137,7 +2142,7 @@ static int set_default(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to mangle unit name: %m"); if (install_client_side()) { - r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); + r = unit_file_set_default(arg_scope, UNIT_FILE_FORCE, arg_root, unit, &changes, &n_changes); unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet); if (r > 0) @@ -2716,7 +2721,7 @@ typedef struct { static void wait_context_free(WaitContext *c) { c->match = sd_bus_slot_unref(c->match); c->event = sd_event_unref(c->event); - c->unit_paths = set_free(c->unit_paths); + c->unit_paths = set_free_free(c->unit_paths); } static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) { @@ -2733,31 +2738,37 @@ static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error r = sd_bus_message_skip(m, "s"); if (r < 0) return bus_log_parse_error(r); + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); if (r < 0) return bus_log_parse_error(r); while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) { const char *s; - bool is_failed; r = sd_bus_message_read(m, "s", &s); if (r < 0) return bus_log_parse_error(r); + if (streq(s, "ActiveState")) { + bool is_failed; + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, "s"); if (r < 0) return bus_log_parse_error(r); + r = sd_bus_message_read(m, "s", &s); if (r < 0) return bus_log_parse_error(r); + is_failed = streq(s, "failed"); if (streq(s, "inactive") || is_failed) { log_debug("%s became %s, dropping from --wait tracking", path, s); - set_remove(c->unit_paths, path); - c->any_failed |= is_failed; + free(set_remove(c->unit_paths, path)); + c->any_failed = c->any_failed || is_failed; } else log_debug("ActiveState on %s changed to %s", path, s); + break; /* no need to dissect the rest of the message */ } else { /* other property */ @@ -5955,22 +5966,25 @@ static int enable_unit(int argc, char *argv[], void *userdata) { } if (install_client_side()) { + UnitFileFlags flags; + + flags = args_to_flags(); if (streq(verb, "enable")) { - r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + r = unit_file_enable(arg_scope, flags, arg_root, names, &changes, &n_changes); carries_install_info = r; } else if (streq(verb, "disable")) - r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes); + r = unit_file_disable(arg_scope, flags, arg_root, names, &changes, &n_changes); else if (streq(verb, "reenable")) { - r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + r = unit_file_reenable(arg_scope, flags, arg_root, names, &changes, &n_changes); carries_install_info = r; } else if (streq(verb, "link")) - r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + r = unit_file_link(arg_scope, flags, arg_root, names, &changes, &n_changes); else if (streq(verb, "preset")) { - r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes); + r = unit_file_preset(arg_scope, flags, arg_root, names, arg_preset_mode, &changes, &n_changes); } else if (streq(verb, "mask")) - r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); + r = unit_file_mask(arg_scope, flags, arg_root, names, &changes, &n_changes); else if (streq(verb, "unmask")) - r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes); + r = unit_file_unmask(arg_scope, flags, arg_root, names, &changes, &n_changes); else if (streq(verb, "revert")) r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes); else @@ -6152,7 +6166,7 @@ static int add_dependency(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown verb"); if (install_client_side()) { - r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); + r = unit_file_add_dependency(arg_scope, args_to_flags(), arg_root, names, target, dep, &changes, &n_changes); unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet); if (r > 0) @@ -6214,7 +6228,7 @@ static int preset_all(int argc, char *argv[], void *userdata) { int r; if (install_client_side()) { - r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); + r = unit_file_preset_all(arg_scope, args_to_flags(), arg_root, arg_preset_mode, &changes, &n_changes); unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet); if (r > 0) @@ -6263,6 +6277,63 @@ finish: return r; } +static int show_installation_targets_client_side(const char *name) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0, i; + UnitFileFlags flags; + char **p; + int r; + + p = STRV_MAKE(name); + flags = UNIT_FILE_DRY_RUN | + (arg_runtime ? UNIT_FILE_RUNTIME : 0); + + r = unit_file_disable(UNIT_FILE_SYSTEM, flags, NULL, p, &changes, &n_changes); + if (r < 0) + return log_error_errno(r, "Failed to get file links for %s: %m", name); + + for (i = 0; i < n_changes; i++) + if (changes[i].type == UNIT_FILE_UNLINK) + printf(" %s\n", changes[i].path); + + return 0; +} + +static int show_installation_targets(sd_bus *bus, const char *name) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + const char *link; + int r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "GetUnitFileLinks", + &error, + &reply, + "sb", name, arg_runtime); + if (r < 0) + return log_error_errno(r, "Failed to get unit file links for %s: %s", name, bus_error_message(&error, r)); + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_read(reply, "s", &link)) > 0) + printf(" %s\n", link); + + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + return 0; +} + static int unit_is_enabled(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; @@ -6281,7 +6352,6 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { enabled = r > 0; if (install_client_side()) { - STRV_FOREACH(name, names) { UnitFileState state; @@ -6297,8 +6367,14 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { UNIT_FILE_GENERATED)) enabled = true; - if (!arg_quiet) + if (!arg_quiet) { puts(unit_file_state_to_string(state)); + if (arg_full) { + r = show_installation_targets_client_side(*name); + if (r < 0) + return r; + } + } } r = 0; @@ -6333,8 +6409,14 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated")) enabled = true; - if (!arg_quiet) + if (!arg_quiet) { puts(s); + if (arg_full) { + r = show_installation_targets(bus, *name); + if (r < 0) + return r; + } + } } } diff --git a/src/test/test-execute.c b/src/test/test-execute.c index e8ff02adaf..c369098500 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -70,6 +70,24 @@ static void check(Manager *m, Unit *unit, int status_expected, int code_expected assert_se(service->main_exec_status.code == code_expected); } +static bool is_inaccessible_available(void) { + char *p; + + FOREACH_STRING(p, + "/run/systemd/inaccessible/reg", + "/run/systemd/inaccessible/dir", + "/run/systemd/inaccessible/chr", + "/run/systemd/inaccessible/blk", + "/run/systemd/inaccessible/fifo", + "/run/systemd/inaccessible/sock" + ) { + if (access(p, F_OK) < 0) + return false; + } + + return true; +} + static void test(Manager *m, const char *unit_name, int status_expected, int code_expected) { Unit *unit; @@ -129,6 +147,11 @@ static void test_exec_privatedevices(Manager *m) { log_notice("testing in container, skipping private device tests"); return; } + if (!is_inaccessible_available()) { + log_notice("testing without inaccessible, skipping private device tests"); + return; + } + test(m, "exec-privatedevices-yes.service", 0, CLD_EXITED); test(m, "exec-privatedevices-no.service", 0, CLD_EXITED); } @@ -138,6 +161,11 @@ static void test_exec_privatedevices_capabilities(Manager *m) { log_notice("testing in container, skipping private device tests"); return; } + if (!is_inaccessible_available()) { + log_notice("testing without inaccessible, skipping private device tests"); + return; + } + test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED); test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED); test(m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED); @@ -149,6 +177,10 @@ static void test_exec_protectkernelmodules(Manager *m) { log_notice("testing in container, skipping protectkernelmodules tests"); return; } + if (!is_inaccessible_available()) { + log_notice("testing without inaccessible, skipping protectkernelmodules tests"); + return; + } test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED); test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED); @@ -218,6 +250,15 @@ static void test_exec_group(Manager *m) { log_error_errno(errno, "Skipping test_exec_group, could not find nobody/nfsnobody group: %m"); } +static void test_exec_supplementary_groups(Manager *m) { + test(m, "exec-supplementarygroups.service", 0, CLD_EXITED); + test(m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED); + test(m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED); + test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED); + test(m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED); + test(m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED); +} + static void test_exec_environment(Manager *m) { test(m, "exec-environment.service", 0, CLD_EXITED); test(m, "exec-environment-multiple.service", 0, CLD_EXITED); @@ -390,6 +431,7 @@ int main(int argc, char *argv[]) { test_exec_systemcallerrornumber, test_exec_user, test_exec_group, + test_exec_supplementary_groups, test_exec_environment, test_exec_environmentfile, test_exec_passenvironment, diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 1686054d2a..a98de76b43 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -64,7 +64,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/dev/null")); @@ -80,11 +80,11 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); /* Enabling a masked unit should fail! */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ERFKILL); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ERFKILL); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); @@ -92,7 +92,7 @@ static void test_basic_mask_and_enable(const char *root) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); @@ -107,12 +107,12 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); /* Enabling it again should succeed but be a NOP */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); @@ -126,13 +126,13 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); /* Disabling a disabled unit must suceed but be a NOP */ - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; /* Let's enable this indirectly via a symlink */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); @@ -148,7 +148,7 @@ static void test_basic_mask_and_enable(const char *root) { /* Let's try to reenable */ - assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); @@ -217,7 +217,7 @@ static void test_linked_units(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); /* First, let's link the unit into the search path */ - assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/opt/linked.service")); @@ -229,7 +229,7 @@ static void test_linked_units(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); /* Let's unlink it from the search path again */ - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); @@ -240,7 +240,7 @@ static void test_linked_units(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); /* Now, let's not just link it, but also enable it */ - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); @@ -262,7 +262,7 @@ static void test_linked_units(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); /* And let's unlink it again */ - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); @@ -282,7 +282,7 @@ static void test_linked_units(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service"); @@ -301,7 +301,7 @@ static void test_linked_units(const char *root) { unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(startswith(changes[0].path, root)); @@ -325,7 +325,7 @@ static void test_default(const char *root) { assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); - assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT); + assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT); assert_se(n_changes == 1); assert_se(changes[0].type == -ENOENT); assert_se(streq_ptr(changes[0].path, "idontexist.target")); @@ -334,7 +334,7 @@ static void test_default(const char *root) { assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); - assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0); + assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); @@ -364,7 +364,7 @@ static void test_add_dependency(const char *root) { p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); - assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0); + assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); @@ -401,7 +401,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); @@ -417,7 +417,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); @@ -431,7 +431,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service"); @@ -446,7 +446,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); @@ -462,7 +462,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service"); @@ -507,7 +507,7 @@ static void test_indirect(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); - assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0); + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); @@ -520,7 +520,7 @@ static void test_indirect(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); @@ -560,7 +560,7 @@ static void test_preset_and_list(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); @@ -572,7 +572,7 @@ static void test_preset_and_list(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); @@ -583,7 +583,7 @@ static void test_preset_and_list(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 0); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -591,7 +591,7 @@ static void test_preset_and_list(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes > 0); @@ -716,7 +716,7 @@ static void test_preset_order(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); assert_se(changes[0].type == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service")); @@ -728,7 +728,7 @@ static void test_preset_order(const char *root) { assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); - assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED); diff --git a/src/test/test-install.c b/src/test/test-install.c index 0ac85f040a..fb36aa83ca 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -70,12 +70,12 @@ int main(int argc, char* argv[]) { log_info("/*** enable **/"); - r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** enable2 **/"); - r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -89,7 +89,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -103,10 +103,10 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** mask2 ***/"); - r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -120,10 +120,10 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** unmask2 ***/"); - r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -137,7 +137,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes); + r = unit_file_mask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -151,10 +151,10 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); log_info("/*** disable2 ***/"); - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -168,7 +168,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes); + r = unit_file_unmask(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -182,7 +182,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + r = unit_file_enable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -196,7 +196,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -209,7 +209,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -223,7 +223,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -236,7 +236,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_link(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + r = unit_file_link(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -250,7 +250,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_reenable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, false, &changes, &n_changes); + r = unit_file_reenable(UNIT_FILE_SYSTEM, 0, NULL, (char**) files2, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -264,7 +264,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, 0, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); @@ -276,7 +276,7 @@ int main(int argc, char* argv[]) { changes = NULL; n_changes = 0; - r = unit_file_preset(UNIT_FILE_SYSTEM, false, NULL, (char**) files, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes); + r = unit_file_preset(UNIT_FILE_SYSTEM, 0, NULL, (char**) files, UNIT_FILE_PRESET_FULL, &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c index 80ad5ed98b..4101678f19 100644 --- a/src/test/test-proc-cmdline.c +++ b/src/test/test-proc-cmdline.c @@ -25,15 +25,18 @@ #include "string-util.h" #include "util.h" -static int parse_item(const char *key, const char *value) { +static int obj; + +static int parse_item(const char *key, const char *value, void *data) { assert_se(key); + assert_se(data == &obj); log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); return 0; } static void test_parse_proc_cmdline(void) { - assert_se(parse_proc_cmdline(parse_item) >= 0); + assert_se(parse_proc_cmdline(parse_item, &obj, true) >= 0); } static void test_runlevel_to_target(void) { diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c new file mode 100644 index 0000000000..0060ecdf02 --- /dev/null +++ b/src/test/test-seccomp.c @@ -0,0 +1,103 @@ +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdlib.h> +#include <sys/eventfd.h> +#include <unistd.h> + +#include "fd-util.h" +#include "macro.h" +#include "process-util.h" +#include "seccomp-util.h" + +static void test_seccomp_arch_to_string(void) { + uint32_t a, b; + const char *name; + + a = seccomp_arch_native(); + assert_se(a > 0); + name = seccomp_arch_to_string(a); + assert_se(name); + assert_se(seccomp_arch_from_string(name, &b) >= 0); + assert_se(a == b); +} + +static void test_syscall_filter_set_find(void) { + assert_se(!syscall_filter_set_find(NULL)); + assert_se(!syscall_filter_set_find("")); + assert_se(!syscall_filter_set_find("quux")); + assert_se(!syscall_filter_set_find("@quux")); + + assert_se(syscall_filter_set_find("@clock") == syscall_filter_sets + SYSCALL_FILTER_SET_CLOCK); + assert_se(syscall_filter_set_find("@default") == syscall_filter_sets + SYSCALL_FILTER_SET_DEFAULT); + assert_se(syscall_filter_set_find("@raw-io") == syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO); +} + +static void test_filter_sets(void) { + unsigned i; + int r; + + if (!is_seccomp_available()) + return; + + if (geteuid() != 0) + return; + + for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { + pid_t pid; + + log_info("Testing %s", syscall_filter_sets[i].name); + + pid = fork(); + assert_se(pid >= 0); + + if (pid == 0) { /* Child? */ + int fd; + + if (i == SYSCALL_FILTER_SET_DEFAULT) /* if we look at the default set, whitelist instead of blacklist */ + r = seccomp_load_filter_set(SCMP_ACT_ERRNO(EPERM), syscall_filter_sets + i, SCMP_ACT_ALLOW); + else + r = seccomp_load_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + i, SCMP_ACT_ERRNO(EPERM)); + if (r < 0) + _exit(EXIT_FAILURE); + + /* Test the sycall filter with one random system call */ + fd = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC); + if (IN_SET(i, SYSCALL_FILTER_SET_IO_EVENT, SYSCALL_FILTER_SET_DEFAULT)) + assert_se(fd < 0 && errno == EPERM); + else { + assert_se(fd >= 0); + safe_close(fd); + } + + _exit(EXIT_SUCCESS); + } + + assert_se(wait_for_terminate_and_warn(syscall_filter_sets[i].name, pid, true) == EXIT_SUCCESS); + } +} + +int main(int argc, char *argv[]) { + + test_seccomp_arch_to_string(); + test_syscall_filter_set_find(); + test_filter_sets(); + + return 0; +} diff --git a/src/test/test-tables.c b/src/test/test-tables.c index 0be74921fc..8d4622694e 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -63,7 +63,7 @@ int main(int argc, char **argv) { test_table(device_state, DEVICE_STATE); test_table(exec_input, EXEC_INPUT); test_table(exec_output, EXEC_OUTPUT); - test_table(failure_action, FAILURE_ACTION); + test_table(emergency_action, EMERGENCY_ACTION); test_table(job_mode, JOB_MODE); test_table(job_result, JOB_RESULT); test_table(job_state, JOB_STATE); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 535d317c27..badbab6205 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1362,49 +1362,33 @@ static int listen_fds(int *rctrl, int *rnetlink) { * udev.exec-delay=<number of seconds> delay execution of every executed program * udev.event-timeout=<number of seconds> seconds to wait before terminating an event */ -static int parse_proc_cmdline_item(const char *key, const char *value) { - const char *full_key = key; - int r; +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { + int r = 0; assert(key); if (!value) return 0; - if (startswith(key, "rd.")) - key += strlen("rd."); - - if (startswith(key, "udev.")) - key += strlen("udev."); - else - return 0; - - if (streq(key, "log-priority")) { - int prio; - - prio = util_log_priority(value); - if (prio < 0) - goto invalid; - log_set_max_level(prio); - } else if (streq(key, "children-max")) { + if (streq(key, "udev.log-priority") && value) { + r = util_log_priority(value); + if (r >= 0) + log_set_max_level(r); + } else if (streq(key, "udev.event-timeout") && value) { + r = safe_atou64(value, &arg_event_timeout_usec); + if (r >= 0) { + arg_event_timeout_usec *= USEC_PER_SEC; + arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; + } + } else if (streq(key, "udev.children-max") && value) r = safe_atou(value, &arg_children_max); - if (r < 0) - goto invalid; - } else if (streq(key, "exec-delay")) { + else if (streq(key, "udev.exec-delay") && value) r = safe_atoi(value, &arg_exec_delay); - if (r < 0) - goto invalid; - } else if (streq(key, "event-timeout")) { - r = safe_atou64(value, &arg_event_timeout_usec); - if (r < 0) - goto invalid; - arg_event_timeout_usec *= USEC_PER_SEC; - arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; - } + else if (startswith(key, "udev.")) + log_warning("Unknown udev kernel command line option \"%s\"", key); - return 0; -invalid: - log_warning("invalid %s ignored: %s", full_key, value); + if (r < 0) + log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value); return 0; } @@ -1665,7 +1649,7 @@ int main(int argc, char *argv[]) { if (r <= 0) goto exit; - r = parse_proc_cmdline(parse_proc_cmdline_item); + r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true); if (r < 0) log_warning_errno(r, "failed to parse kernel command line, ignoring: %m"); diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 5cc5abfddf..48c2a3fff4 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -18,6 +18,7 @@ ***/ #include "fd-util.h" +#include "fileio.h" #include "io-util.h" #include "selinux-util.h" #include "util.h" @@ -32,8 +33,8 @@ static int apply_timestamp(const char *path, struct timespec *ts) { *ts, *ts }; - int fd = -1; _cleanup_fclose_ FILE *f = NULL; + int fd = -1; int r; assert(path); @@ -59,18 +60,20 @@ static int apply_timestamp(const char *path, struct timespec *ts) { return log_error_errno(errno, "Failed to create/open timestamp file %s: %m", path); } - f = fdopen(fd, "w"); + f = fdopen(fd, "we"); if (!f) { safe_close(fd); return log_error_errno(errno, "Failed to fdopen() timestamp file %s: %m", path); } (void) fprintf(f, - "%s" - "TimestampNSec=" NSEC_FMT "\n", - MESSAGE, timespec_load_nsec(ts)); + MESSAGE + "TIMESTAMP_NSEC=" NSEC_FMT "\n", + timespec_load_nsec(ts)); - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write timestamp file: %m"); if (futimens(fd, twice) < 0) return log_error_errno(errno, "Failed to update timestamp on %s: %m", path); diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 185b041a1c..a0ab5990fc 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -237,10 +237,10 @@ static void setup_remaining_vcs(int fd, bool utf8) { if (r < 0) log_warning_errno(errno, "KD_FONT_OP_GET failed while trying to get the font metadata: %m"); else { - /* sanitize parameters first */ + /* verify parameter sanity first */ if (cfo.width > 32 || cfo.height > 32 || cfo.charcount > 512) log_warning("Invalid font metadata - width: %u (max 32), height: %u (max 32), count: %u (max 512)", - cfo.width, cfo.height, cfo.charcount); + cfo.width, cfo.height, cfo.charcount); else { /* * Console fonts supported by the kernel are limited in size to 32 x 32 and maximum 512 @@ -270,9 +270,8 @@ static void setup_remaining_vcs(int fd, bool utf8) { } } - if (cfo.op != KD_FONT_OP_SET) { + if (cfo.op != KD_FONT_OP_SET) log_warning("Fonts will not be copied to remaining consoles"); - } for (i = 1; i <= 63; i++) { char ttyname[strlen("/dev/tty") + DECIMAL_STR_MAX(int)]; |