libsystemd-internal.la \
libsystemd-logs.la \
libsystemd-journal-internal.la \
+ libsystemd-units.la \
libsystemd-shared.la
rootbin_PROGRAMS += \
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--now</option></term>
+
+ <listitem>
+ <para>When used with <command>enable</command>, the units
+ will also be started. When used with <command>disable</command> or
+ <command>mask</command>, the units will also be stopped. The start
+ or stop operation is only carried out when the respective enable or
+ disable operation has been successful.</para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--root=</option></term>
the changes are taken into account immediately. Note that
this does <emphasis>not</emphasis> have the effect of also
starting any of the units being enabled. If this
- is desired, a separate <command>start</command> command must
- be invoked for the unit. Also note that in case of instance
- enablement, symlinks named the same as instances are created in
- the install location, however they all point to the same
- template unit file.</para>
+ is desired, either <option>--now</option> should be used
+ together with this command, or an additional <command>start</command>
+ command must be invoked for the unit. Also note that in case of
+ instance enablement, symlinks named the same as instances
+ are created in the install location, however they all point to the
+ same template unit file.</para>
<para>This command will print the actions executed. This
output may be suppressed by passing <option>--quiet</option>.
<command>enable</command>. This call implicitly reloads the
systemd daemon configuration after completing the disabling
of the units. Note that this command does not implicitly
- stop the units that are being disabled. If this is desired,
- an additional <command>stop</command> command should be
- executed afterwards.</para>
+ stop the units that are being disabled. If this is desired, either
+ <option>--now</option> should be used together with this command, or
+ an additional <command>stop</command> command should be executed
+ afterwards.</para>
<para>This command will print the actions executed. This
output may be suppressed by passing <option>--quiet</option>.
activation of the unit, including enablement and manual
activation. Use this option with care. This honors the
<option>--runtime</option> option to only mask temporarily
- until the next reboot of the system.</para>
+ until the next reboot of the system. The <option>--now</option>
+ option can be used to ensure that the units are also stopped.</para>
</listitem>
</varlistentry>
return bus_wait_for_jobs(d, quiet);
}
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
const char *type, *path, *source;
int r;
else
log_info("Removed symlink %s.", path);
}
+
+ r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
+ if (r < 0)
+ return r;
}
if (r < 0)
return bus_log_parse_error(r);
#include "sd-event.h"
#include "sd-bus.h"
#include "hashmap.h"
+#include "install.h"
#include "time-util.h"
typedef enum BusTransport {
DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet);
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path);
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external);
return bus_log_parse_error(r);
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
return 0;
}
-static int add_file_change(
- UnitFileChange **changes,
- unsigned *n_changes,
- UnitFileChangeType type,
- const char *path,
- const char *source) {
-
- UnitFileChange *c;
- unsigned i;
-
- assert(path);
- assert(!changes == !n_changes);
-
- if (!changes)
- return 0;
-
- c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
- if (!c)
- return -ENOMEM;
-
- *changes = c;
- i = *n_changes;
-
- c[i].type = type;
- c[i].path = strdup(path);
- if (!c[i].path)
- return -ENOMEM;
-
- path_kill_slashes(c[i].path);
-
- if (source) {
- c[i].source = strdup(source);
- if (!c[i].source) {
- free(c[i].path);
- return -ENOMEM;
- }
-
- path_kill_slashes(c[i].path);
- } else
- c[i].source = NULL;
-
- *n_changes = i+1;
- return 0;
-}
-
static int mark_symlink_for_removal(
Set **remove_symlinks_to,
const char *p) {
path_kill_slashes(p);
rmdir_parents(p, config_path);
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
if (!set_get(remove_symlinks_to, p)) {
}
if (symlink("/dev/null", path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
continue;
}
if (force) {
if (symlink_atomic("/dev/null", path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null");
continue;
}
}
q = -errno;
else {
q = mark_symlink_for_removal(&remove_symlinks_to, path);
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
}
}
return -ENOMEM;
if (symlink(*i, path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
continue;
}
if (force) {
if (symlink_atomic(*i, path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i);
continue;
}
}
hashmap_free(h);
}
+int unit_file_changes_add(
+ UnitFileChange **changes,
+ unsigned *n_changes,
+ UnitFileChangeType type,
+ const char *path,
+ const char *source) {
+
+ UnitFileChange *c;
+ unsigned i;
+
+ assert(path);
+ assert(!changes == !n_changes);
+
+ if (!changes)
+ return 0;
+
+ c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
+ if (!c)
+ return -ENOMEM;
+
+ *changes = c;
+ i = *n_changes;
+
+ c[i].type = type;
+ c[i].path = strdup(path);
+ if (!c[i].path)
+ return -ENOMEM;
+
+ path_kill_slashes(c[i].path);
+
+ if (source) {
+ c[i].source = strdup(source);
+ if (!c[i].source) {
+ free(c[i].path);
+ return -ENOMEM;
+ }
+
+ path_kill_slashes(c[i].path);
+ } else
+ c[i].source = NULL;
+
+ *n_changes = i+1;
+ return 0;
+}
+
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
unsigned i;
mkdir_parents_label(new_path, 0755);
if (symlink(old_path, new_path) >= 0) {
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
return 0;
}
if (r < 0)
return r;
- add_file_change(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
- add_file_change(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
return 0;
}
int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
void unit_file_list_free(Hashmap *h);
+int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source);
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_plain = false;
static bool arg_firmware_setup = false;
+static bool arg_now = false;
static bool original_stdout_is_tty;
return r;
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
return bus_log_parse_error(r);
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
if (r < 0)
return r;
"3) A unit may be started when needed via activation (socket, path, timer,\n"
" D-Bus, udev, scripted systemctl call, ...).\n");
+ if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
+ char *new_args[n_changes + 2];
+ unsigned i;
+
+ new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
+ for (i = 0; i < n_changes; i++)
+ new_args[i + 1] = basename(changes[i].path);
+ new_args[i + 1] = NULL;
+
+ r = start_unit(bus, new_args);
+ }
+
finish:
unit_file_changes_free(changes, n_changes);
return r;
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
return r;
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
" When shutting down or sleeping, ignore inhibitors\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
+ " --now Start or stop unit in addition to enabling or disabling it\n"
" -q --quiet Suppress output\n"
" --no-block Do not wait until operation finished\n"
" --no-wall Don't send wall message before halt/power-off/reboot\n"
ARG_JOB_MODE,
ARG_PRESET_MODE,
ARG_FIRMWARE_SETUP,
+ ARG_NOW,
};
static const struct option options[] = {
{ "recursive", no_argument, NULL, 'r' },
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
{ "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
+ { "now", no_argument, NULL, ARG_NOW },
{}
};
break;
+ case ARG_NOW:
+ arg_now = true;
+ break;
+
case '?':
return -EINVAL;