diff options
-rw-r--r-- | man/systemctl.xml | 12 | ||||
-rw-r--r-- | src/systemctl/systemctl-start-unit.c | 65 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 31 | ||||
-rw-r--r-- | src/systemctl/systemctl.h | 1 |
4 files changed, 96 insertions, 13 deletions
diff --git a/man/systemctl.xml b/man/systemctl.xml index db4e2b2c65..642a5ecf2d 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -2317,6 +2317,18 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err </varlistentry> <varlistentry> + <term><option>--marked</option></term> + + <listitem><para>Only allowed with <command>reload-or-restart</command>. Enqueues restart jobs for all + units that have the <literal>needs-restart</literal> mark, and reload jobs for units that have the + <literal>needs-reload</literal> mark. When a unit marked for reload does not support reload, restart + will be queued. Those properties can be set using <command>set-property Marks</command>.</para> + + <para>Unless <option>--no-block</option> is used, <command>systemctl</command> will wait for the + queued jobs to finish.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>--read-only</option></term> <listitem><para>When used with <command>bind</command>, creates a read-only bind mount.</para></listitem> diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c index d08e363c9f..c40e807212 100644 --- a/src/systemctl/systemctl-start-unit.c +++ b/src/systemctl/systemctl-start-unit.c @@ -176,6 +176,43 @@ fail: return r; } +static int enqueue_marked_jobs( + sd_bus *bus, + BusWaitForJobs *w) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + log_debug("%s dbus call org.freedesktop.systemd1.Manager EnqueueMarkedJobs()", + arg_dry_run ? "Would execute" : "Executing"); + + if (arg_dry_run) + return 0; + + r = bus_call_method(bus, bus_systemd_mgr, "EnqueueMarkedJobs", &error, &reply, NULL); + if (r < 0) + return log_error_errno(r, "Failed to start jobs: %s", bus_error_message(&error, r)); + + _cleanup_strv_free_ char **paths = NULL; + r = sd_bus_message_read_strv(reply, &paths); + if (r < 0) + return bus_log_parse_error(r); + + if (w) { + char **path; + + STRV_FOREACH(path, paths) { + log_debug("Adding %s to the set", *path); + r = bus_wait_for_jobs_add(w, *path); + if (r < 0) + return log_error_errno(r, "Failed to watch job %s: %m", *path); + } + } + + return 0; +} + const struct action_metadata action_table[_ACTION_MAX] = { [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" }, [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" }, @@ -265,7 +302,7 @@ int start_unit(int argc, char *argv[], void *userdata) { job_type = "start"; mode = "isolate"; suffix = ".target"; - } else { + } else if (!arg_marked) { /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */ method = verb_to_method(argv[0]); job_type = verb_to_job_type(argv[0]); @@ -289,7 +326,7 @@ int start_unit(int argc, char *argv[], void *userdata) { names = strv_new(one_name); if (!names) return log_oom(); - } else { + } else if (!arg_marked) { bool expanded; r = expand_unit_names(bus, strv_skip(argv, 1), suffix, &names, &expanded); @@ -322,19 +359,23 @@ int start_unit(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to allocate unit watch context: %m"); } - STRV_FOREACH(name, names) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + if (arg_marked) + ret = enqueue_marked_jobs(bus, w); - r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu); - if (ret == EXIT_SUCCESS && r < 0) - ret = translate_bus_error_to_exit_status(r, &error); + else + STRV_FOREACH(name, names) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - if (r >= 0 && streq(method, "StopUnit")) { - r = strv_push(&stopped_units, *name); - if (r < 0) - return log_oom(); + r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu); + if (ret == EXIT_SUCCESS && r < 0) + ret = translate_bus_error_to_exit_status(r, &error); + + if (r >= 0 && streq(method, "StopUnit")) { + r = strv_push(&stopped_units, *name); + if (r < 0) + return log_oom(); + } } - } if (!arg_no_block) { const char* extra_args[4]; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 16d0555c7c..315202a64b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -108,6 +108,7 @@ char **arg_clean_what = NULL; TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY; bool arg_read_only = false; bool arg_mkdir = false; +bool arg_marked = false; STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); @@ -295,6 +296,7 @@ static int systemctl_help(void) { " 'us+utc': 'Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC\n" " --read-only Create read-only bind mount\n" " --mkdir Create directory before mounting, if missing\n" + " --marked Restart/reload previously marked units\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -413,6 +415,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_TIMESTAMP_STYLE, ARG_READ_ONLY, ARG_MKDIR, + ARG_MARKED, }; static const struct option options[] = { @@ -471,6 +474,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "timestamp", required_argument, NULL, ARG_TIMESTAMP_STYLE }, { "read-only", no_argument, NULL, ARG_READ_ONLY }, { "mkdir", no_argument, NULL, ARG_MKDIR }, + { "marked", no_argument, NULL, ARG_MARKED }, {} }; @@ -900,6 +904,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_mkdir = true; break; + case ARG_MARKED: + arg_marked = true; + break; + case '.': /* Output an error mimicking getopt, and print a hint afterwards */ log_error("%s: invalid option -- '.'", program_invocation_name); @@ -923,6 +931,27 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--wait may not be combined with --no-block."); + bool do_reload_or_restart = streq_ptr(argv[optind], "reload-or-restart"); + if (arg_marked) { + if (!do_reload_or_restart) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--marked may only be used with 'reload-or-restart'."); + if (optind + 1 < argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No additional arguments allowed with 'reload-or-restart --marked'."); + if (arg_wait) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--marked --wait is not supported."); + if (arg_show_transaction) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--marked --show-transaction is not supported."); + + } else if (do_reload_or_restart) { + if (optind + 1 >= argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "List of units to restart/reload is required."); + } + return 1; } @@ -1004,7 +1033,7 @@ static int systemctl_main(int argc, char *argv[]) { { "reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, - { "reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, + { "reload-or-restart", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "reload-or-try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with old systemctl <= 228 */ { "try-reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "force-reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with SysV */ diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h index 0ebe4580c6..3c5a4023a9 100644 --- a/src/systemctl/systemctl.h +++ b/src/systemctl/systemctl.h @@ -93,5 +93,6 @@ extern char **arg_clean_what; extern TimestampStyle arg_timestamp_style; extern bool arg_read_only; extern bool arg_mkdir; +extern bool arg_marked; int systemctl_dispatch_parse_argv(int argc, char *argv[]); |