summaryrefslogtreecommitdiff
path: root/src/systemctl/systemctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemctl/systemctl.c')
-rw-r--r--src/systemctl/systemctl.c1810
1 files changed, 959 insertions, 851 deletions
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 34e4751b94..70871cf3e6 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -37,7 +37,7 @@
#include "sd-daemon.h"
#include "sd-login.h"
-#include "build.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-message.h"
@@ -49,31 +49,42 @@
#include "efivars.h"
#include "env-util.h"
#include "exit-status.h"
+#include "fd-util.h"
#include "fileio.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
#include "hostname-util.h"
#include "initreq.h"
#include "install.h"
+#include "io-util.h"
#include "list.h"
+#include "locale-util.h"
#include "log.h"
#include "logs-show.h"
#include "macro.h"
#include "mkdir.h"
#include "pager.h"
+#include "parse-util.h"
#include "path-lookup.h"
#include "path-util.h"
#include "process-util.h"
+#include "rlimit-util.h"
#include "set.h"
#include "signal-util.h"
#include "socket-util.h"
#include "spawn-ask-password-agent.h"
#include "spawn-polkit-agent.h"
#include "special.h"
+#include "stat-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "unit-name.h"
+#include "user-util.h"
#include "util.h"
#include "utmp-wtmp.h"
+#include "verbs.h"
+#include "virt.h"
static char **arg_types = NULL;
static char **arg_states = NULL;
@@ -107,7 +118,7 @@ static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
static char **arg_wall = NULL;
static const char *arg_kill_who = NULL;
static int arg_signal = SIGTERM;
-static const char *arg_root = NULL;
+static char *arg_root = NULL;
static usec_t arg_when = 0;
static enum action {
_ACTION_INVALID,
@@ -134,23 +145,61 @@ static enum action {
_ACTION_MAX
} arg_action = ACTION_SYSTEMCTL;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static char *arg_host = NULL;
+static const char *arg_host = NULL;
static unsigned arg_lines = 10;
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;
-
-static int daemon_reload(sd_bus *bus, char **args);
+static int daemon_reload(int argc, char *argv[], void* userdata);
static int halt_now(enum action a);
static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
-static char** strv_skip_first(char **strv) {
- if (strv_length(strv) > 0)
- return strv + 1;
- return NULL;
+static bool original_stdout_is_tty;
+
+typedef enum BusFocus {
+ BUS_FULL, /* The full bus indicated via --system or --user */
+ BUS_MANAGER, /* The manager itself, possibly directly, possibly via the bus */
+ _BUS_FOCUS_MAX
+} BusFocus;
+
+static sd_bus *busses[_BUS_FOCUS_MAX] = {};
+
+static int acquire_bus(BusFocus focus, sd_bus **ret) {
+ int r;
+
+ assert(focus < _BUS_FOCUS_MAX);
+ assert(ret);
+
+ /* We only go directly to the manager, if we are using a local transport */
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ focus = BUS_FULL;
+
+ if (!busses[focus]) {
+ bool user;
+
+ user = arg_scope != UNIT_FILE_SYSTEM;
+
+ if (focus == BUS_MANAGER)
+ r = bus_connect_transport_systemd(arg_transport, arg_host, user, &busses[focus]);
+ else
+ r = bus_connect_transport(arg_transport, arg_host, user, &busses[focus]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to bus: %m");
+
+ (void) sd_bus_set_allow_interactive_authorization(busses[focus], arg_ask_password);
+ }
+
+ *ret = busses[focus];
+ return 0;
+}
+
+static void release_busses(void) {
+ BusFocus w;
+
+ for (w = 0; w < _BUS_FOCUS_MAX; w++)
+ busses[w] = sd_bus_flush_close_unref(busses[w]);
}
static void pager_open_if_enabled(void) {
@@ -230,42 +279,10 @@ static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error)
return EXIT_FAILURE;
}
-static void warn_wall(enum action a) {
- static const char *table[_ACTION_MAX] = {
- [ACTION_HALT] = "The system is going down for system halt NOW!",
- [ACTION_REBOOT] = "The system is going down for reboot NOW!",
- [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
- [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
- [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
- [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
- [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
- };
-
- if (arg_no_wall)
- return;
-
- if (arg_wall) {
- _cleanup_free_ char *p;
+static bool install_client_side(void) {
- p = strv_join(arg_wall, " ");
- if (!p) {
- log_oom();
- return;
- }
-
- if (*p) {
- utmp_wall(p, NULL, NULL, NULL, NULL);
- return;
- }
- }
-
- if (!table[a])
- return;
-
- utmp_wall(table[a], NULL, NULL, NULL, NULL);
-}
-
-static bool avoid_bus(void) {
+ /* Decides when to execute enable/disable/... operations
+ * client-side rather than server-side. */
if (running_in_chroot() > 0)
return true;
@@ -279,6 +296,10 @@ static bool avoid_bus(void) {
if (arg_scope == UNIT_FILE_GLOBAL)
return true;
+ /* Unsupported environment variable, mostly for debugging purposes */
+ if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0)
+ return true;
+
return false;
}
@@ -652,15 +673,20 @@ static int get_unit_list_recursive(
return c;
}
-static int list_units(sd_bus *bus, char **args) {
+static int list_units(int argc, char *argv[], void *userdata) {
_cleanup_free_ UnitInfo *unit_infos = NULL;
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
+ sd_bus *bus;
int r;
pager_open_if_enabled();
- r = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (r < 0)
return r;
@@ -676,6 +702,10 @@ static int get_triggered_units(
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ assert(bus);
+ assert(path);
+ assert(ret);
+
r = sd_bus_get_property_strv(
bus,
"org.freedesktop.systemd1",
@@ -684,9 +714,8 @@ static int get_triggered_units(
"Triggers",
&error,
ret);
-
if (r < 0)
- log_error("Failed to determine triggers: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to determine triggers: %s", bus_error_message(&error, r));
return 0;
}
@@ -710,10 +739,8 @@ static int get_listening(
&error,
&reply,
"a(ss)");
- if (r < 0) {
- log_error("Failed to get list of listening sockets: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get list of listening sockets: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
if (r < 0)
@@ -853,7 +880,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
return 0;
}
-static int list_sockets(sd_bus *bus, char **args) {
+static int list_sockets(int argc, char *argv[], void *userdata) {
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
_cleanup_free_ UnitInfo *unit_infos = NULL;
@@ -863,10 +890,15 @@ static int list_sockets(sd_bus *bus, char **args) {
unsigned cs = 0;
size_t size = 0;
int r = 0, n;
+ sd_bus *bus;
pager_open_if_enabled();
- n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -947,10 +979,8 @@ static int get_next_elapse(
&error,
't',
&t.monotonic);
- if (r < 0) {
- log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r));
r = sd_bus_get_property_trivial(
bus,
@@ -961,10 +991,8 @@ static int get_next_elapse(
&error,
't',
&t.realtime);
- if (r < 0) {
- log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r));
*next = t;
return 0;
@@ -991,10 +1019,8 @@ static int get_last_trigger(
&error,
't',
last);
- if (r < 0) {
- log_error("Failed to get last trigger time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get last trigger time: %s", bus_error_message(&error, r));
return 0;
}
@@ -1160,7 +1186,7 @@ static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
return next_elapse;
}
-static int list_timers(sd_bus *bus, char **args) {
+static int list_timers(int argc, char *argv[], void *userdata) {
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
_cleanup_free_ struct timer_info *timer_infos = NULL;
@@ -1170,11 +1196,16 @@ static int list_timers(sd_bus *bus, char **args) {
size_t size = 0;
int n, c = 0;
dual_timestamp nw;
+ sd_bus *bus;
int r = 0;
pager_open_if_enabled();
- n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -1326,7 +1357,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
printf("\n%u unit files listed.\n", c);
}
-static int list_unit_files(sd_bus *bus, char **args) {
+static int list_unit_files(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ UnitFileList *units = NULL;
UnitFileList *unit;
@@ -1338,7 +1369,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
pager_open_if_enabled();
- if (avoid_bus()) {
+ if (install_client_side()) {
Hashmap *h;
UnitFileList *u;
Iterator i;
@@ -1351,8 +1382,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
r = unit_file_get_list(arg_scope, arg_root, h);
if (r < 0) {
unit_file_list_free(h);
- log_error_errno(r, "Failed to get unit file list: %m");
- return r;
+ return log_error_errno(r, "Failed to get unit file list: %m");
}
n_units = hashmap_size(h);
@@ -1364,7 +1394,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
}
HASHMAP_FOREACH(u, h, i) {
- if (!output_show_unit_file(u, strv_skip_first(args)))
+ if (!output_show_unit_file(u, strv_skip(argv, 1)))
continue;
units[c++] = *u;
@@ -1375,6 +1405,11 @@ static int list_unit_files(sd_bus *bus, char **args) {
hashmap_free(h);
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = sd_bus_call_method(
bus,
@@ -1385,10 +1420,8 @@ static int list_unit_files(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to list unit files: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
if (r < 0)
@@ -1404,7 +1437,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
unit_file_state_from_string(state)
};
- if (output_show_unit_file(&units[c], strv_skip_first(args)))
+ if (output_show_unit_file(&units[c], strv_skip(argv, 1)))
c ++;
}
@@ -1419,7 +1452,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
output_unit_file_list(units, c);
- if (avoid_bus()) {
+ if (install_client_side()) {
for (unit = units; unit < units + c; unit++)
free(unit->path);
}
@@ -1511,10 +1544,8 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
&error,
&reply,
"s", "org.freedesktop.systemd1.Unit");
- if (r < 0) {
- log_error("Failed to get properties of %s: %s", name, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
if (r < 0)
@@ -1638,16 +1669,15 @@ static int list_dependencies_one(
return 0;
}
-static int list_dependencies(sd_bus *bus, char **args) {
+static int list_dependencies(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **units = NULL;
_cleanup_free_ char *unit = NULL;
const char *u;
+ sd_bus *bus;
int r;
- assert(bus);
-
- if (args[1]) {
- r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &unit);
+ if (argv[1]) {
+ r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
@@ -1657,6 +1687,10 @@ static int list_dependencies(sd_bus *bus, char **args) {
pager_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
puts(u);
return list_dependencies_one(bus, u, 0, &units, 0);
@@ -1872,12 +1906,11 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
printf("\n%u machines listed.\n", n);
}
-static int list_machines(sd_bus *bus, char **args) {
+static int list_machines(int argc, char *argv[], void *userdata) {
struct machine_info *machine_infos = NULL;
+ sd_bus *bus;
int r;
- assert(bus);
-
if (geteuid() != 0) {
log_error("Must be root.");
return -EPERM;
@@ -1885,7 +1918,11 @@ static int list_machines(sd_bus *bus, char **args) {
pager_open_if_enabled();
- r = get_machine_list(bus, &machine_infos, strv_skip_first(args));
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1));
if (r < 0)
return r;
@@ -1896,13 +1933,13 @@ static int list_machines(sd_bus *bus, char **args) {
return 0;
}
-static int get_default(sd_bus *bus, char **args) {
+static int get_default(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *_path = NULL;
const char *path;
int r;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
r = unit_file_get_default(arg_scope, arg_root, &_path);
if (r < 0)
return log_error_errno(r, "Failed to get default target: %m");
@@ -1910,6 +1947,11 @@ static int get_default(sd_bus *bus, char **args) {
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = sd_bus_call_method(
bus,
@@ -1920,10 +1962,8 @@ static int get_default(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to get default target: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &path);
if (r < 0)
@@ -1949,17 +1989,21 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha
}
}
-static int set_default(sd_bus *bus, char **args) {
+static int set_default(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *unit = NULL;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
int r;
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &unit);
+ assert(argc >= 2);
+ assert(argv);
+
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+
r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
if (r < 0)
return log_error_errno(r, "Failed to set default target: %m");
@@ -1967,13 +2011,19 @@ static int set_default(sd_bus *bus, char **args) {
if (!arg_quiet)
dump_unit_file_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
r = 0;
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -1983,10 +2033,8 @@ static int set_default(sd_bus *bus, char **args) {
&error,
&reply,
"sb", unit, 1);
- if (r < 0) {
- log_error("Failed to set default target: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
@@ -1994,13 +2042,11 @@ static int set_default(sd_bus *bus, char **args) {
/* Try to reload if enabled */
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
- unit_file_changes_free(changes, n_changes);
-
return r;
}
@@ -2085,17 +2131,24 @@ static bool output_show_job(struct job_info *job, char **patterns) {
return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
}
-static int list_jobs(sd_bus *bus, char **args) {
+static int list_jobs(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *name, *type, *state, *job_path, *unit_path;
_cleanup_free_ struct job_info *jobs = NULL;
size_t size = 0;
unsigned c = 0;
+ sd_bus *bus;
uint32_t id;
int r;
bool skipped = false;
+ pager_open_if_enabled();
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -2105,10 +2158,8 @@ static int list_jobs(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to list jobs: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
if (r < 0)
@@ -2117,7 +2168,7 @@ static int list_jobs(sd_bus *bus, char **args) {
while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
struct job_info job = { id, name, type, state };
- if (!output_show_job(&job, strv_skip_first(args))) {
+ if (!output_show_job(&job, strv_skip(argv, 1))) {
skipped = true;
continue;
}
@@ -2138,18 +2189,21 @@ static int list_jobs(sd_bus *bus, char **args) {
return r;
}
-static int cancel_job(sd_bus *bus, char **args) {
+static int cancel_job(int argc, char *argv[], void *userdata) {
+ sd_bus *bus;
char **name;
int r = 0;
- assert(args);
-
- if (strv_length(args) <= 1)
- return daemon_reload(bus, args);
+ if (argc <= 1)
+ return daemon_reload(argc, argv, userdata);
polkit_agent_open_if_enabled();
- STRV_FOREACH(name, args+1) {
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(name, strv_skip(argv, 1)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
uint32_t id;
int q;
@@ -2168,7 +2222,7 @@ static int cancel_job(sd_bus *bus, char **args) {
NULL,
"u", id);
if (q < 0) {
- log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -2253,7 +2307,6 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
static int unit_find_paths(
sd_bus *bus,
const char *unit_name,
- bool avoid_bus_cache,
LookupPaths *lp,
char **fragment_path,
char ***dropin_paths) {
@@ -2274,7 +2327,7 @@ static int unit_find_paths(
assert(fragment_path);
assert(lp);
- if (!avoid_bus_cache && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
+ if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL;
_cleanup_free_ char *unit = NULL;
@@ -2471,10 +2524,8 @@ static int check_triggering_units(
"LoadState",
&error,
&state);
- if (r < 0) {
- log_error("Failed to get load state of %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r));
if (streq(state, "masked"))
return 0;
@@ -2487,10 +2538,8 @@ static int check_triggering_units(
"TriggeredBy",
&error,
&triggered_by);
- if (r < 0) {
- log_error("Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
STRV_FOREACH(i, triggered_by) {
r = check_one_unit(bus, *i, "active\0reloading\0", true);
@@ -2586,8 +2635,7 @@ static int start_unit_one(
verb = method_to_verb(method);
- log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
- return r;
+ return log_error_errno(r, "Failed to %s %s: %s", verb, name, bus_error_message(error, r));
}
r = sd_bus_message_read(reply, "o", &path);
@@ -2608,11 +2656,13 @@ static int start_unit_one(
}
static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
-
_cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
char **name;
int r, i;
+ assert(bus);
+ assert(ret);
+
STRV_FOREACH(name, names) {
char *t;
@@ -2637,9 +2687,6 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ UnitInfo *unit_infos = NULL;
- if (!bus)
- return log_error_errno(EOPNOTSUPP, "Unit name globbing without bus is not implemented.");
-
r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
if (r < 0)
return r;
@@ -2687,24 +2734,28 @@ static enum action verb_to_action(const char *verb) {
return _ACTION_INVALID;
}
-static int start_unit(sd_bus *bus, char **args) {
+static int start_unit(int argc, char *argv[], void *userdata) {
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
const char *method, *mode, *one_name, *suffix = NULL;
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r = 0;
- assert(bus);
-
ask_password_agent_open_if_enabled();
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (arg_action == ACTION_SYSTEMCTL) {
enum action action;
- method = verb_to_method(args[0]);
- action = verb_to_action(args[0]);
- if (streq(args[0], "isolate")) {
+ method = verb_to_method(argv[0]);
+ action = verb_to_action(argv[0]);
+
+ if (streq(argv[0], "isolate")) {
mode = "isolate";
suffix = ".target";
} else
@@ -2724,9 +2775,9 @@ static int start_unit(sd_bus *bus, char **args) {
if (one_name)
names = strv_new(one_name, NULL);
else {
- r = expand_names(bus, args + 1, suffix, &names);
+ r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
}
if (!arg_no_block) {
@@ -2761,18 +2812,55 @@ static int start_unit(sd_bus *bus, char **args) {
return r;
}
+static int logind_set_wall_message(void) {
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ _cleanup_free_ char *m = NULL;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ m = strv_join(arg_wall, " ");
+ if (!m)
+ return log_oom();
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetWallMessage",
+ &error,
+ NULL,
+ "sb",
+ m,
+ !arg_no_wall);
+
+ if (r < 0)
+ return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
+
+#endif
+ return 0;
+}
+
/* Ask systemd-logind, which might grant access to unprivileged users
* through PolicyKit */
-static int reboot_with_logind(sd_bus *bus, enum action a) {
+static int logind_reboot(enum action a) {
#ifdef HAVE_LOGIND
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *method, *description;
+ sd_bus *bus;
int r;
- if (!bus)
- return -EIO;
-
polkit_agent_open_if_enabled();
+ (void) logind_set_wall_message();
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
switch (a) {
@@ -2805,33 +2893,6 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
return -EINVAL;
}
- if (!strv_isempty(arg_wall)) {
- _cleanup_free_ char *m;
-
- m = strv_join(arg_wall, " ");
- if (!m)
- return log_oom();
-
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
- }
-
-
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -2842,27 +2903,25 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
NULL,
"b", arg_ask_password);
if (r < 0)
- log_error("Failed to %s via logind: %s", description, bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
- return r;
+ return 0;
#else
return -ENOSYS;
#endif
}
-static int check_inhibitors(sd_bus *bus, enum action a) {
+static int logind_check_inhibitors(enum action a) {
#ifdef HAVE_LOGIND
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_strv_free_ char **sessions = NULL;
const char *what, *who, *why, *mode;
uint32_t uid, pid;
+ sd_bus *bus;
unsigned c = 0;
char **s;
int r;
- if (!bus)
- return 0;
-
if (arg_ignore_inhibitors || arg_force > 0)
return 0;
@@ -2875,6 +2934,10 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
if (!on_tty())
return 0;
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -2964,10 +3027,36 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
#endif
}
-static int prepare_firmware_setup(sd_bus *bus) {
+static int logind_prepare_firmware_setup(void) {
#ifdef HAVE_LOGIND
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetRebootToFirmwareSetup",
+ &error,
+ NULL,
+ "b", true);
+ if (r < 0)
+ return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
+
+ return 0;
+#else
+ log_error("Cannot remotely indicate to EFI to boot into setup mode.");
+ return -ENOSYS;
#endif
+}
+
+static int prepare_firmware_setup(void) {
int r;
if (!arg_firmware_setup)
@@ -2982,38 +3071,42 @@ static int prepare_firmware_setup(sd_bus *bus) {
return r;
}
-#ifdef HAVE_LOGIND
+ return logind_prepare_firmware_setup();
+}
+
+static int set_exit_code(uint8_t code) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetRebootToFirmwareSetup",
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SetExitCode",
&error,
NULL,
- "b", true);
- if (r < 0) {
- log_error("Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
- return r;
- }
+ "y", code);
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
return 0;
-#else
- log_error("Cannot remotely indicate to EFI to boot into setup mode.");
- return -EINVAL;
-#endif
}
-static int start_special(sd_bus *bus, char **args) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+static int start_special(int argc, char *argv[], void *userdata) {
enum action a;
int r;
- assert(args);
+ assert(argv);
- a = verb_to_action(args[0]);
+ a = verb_to_action(argv[0]);
- r = check_inhibitors(bus, a);
+ r = logind_check_inhibitors(a);
if (r < 0)
return r;
@@ -3022,39 +3115,29 @@ static int start_special(sd_bus *bus, char **args) {
return -EPERM;
}
- r = prepare_firmware_setup(bus);
+ r = prepare_firmware_setup();
if (r < 0)
return r;
- if (a == ACTION_REBOOT && args[1]) {
- r = update_reboot_param_file(args[1]);
+ if (a == ACTION_REBOOT && argc > 1) {
+ r = update_reboot_param_file(argv[1]);
if (r < 0)
return r;
- } else if (a == ACTION_EXIT && strv_length(args) > 1) {
- /* If the exit code is not given on the command line, don't
- * reset it to zero: just keep it as it might have been set
- * previously. */
- uint8_t code = 0;
- r = safe_atou8(args[1], &code);
- if (r < 0) {
- log_error("Invalid exit code.");
- return -EINVAL;
- }
+ } else if (a == ACTION_EXIT && argc > 1) {
+ uint8_t code;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SetExitCode",
- &error,
- NULL,
- "y", code);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ /* If the exit code is not given on the command line,
+ * don't reset it to zero: just keep it as it might
+ * have been set previously. */
+
+ r = safe_atou8(argv[1], &code);
+ if (r < 0)
+ return log_error_errno(r, "Invalid exit code.");
+
+ r = set_exit_code(code);
+ if (r < 0)
return r;
- }
}
if (arg_force >= 2 &&
@@ -3071,39 +3154,37 @@ static int start_special(sd_bus *bus, char **args) {
ACTION_REBOOT,
ACTION_KEXEC,
ACTION_EXIT))
- return daemon_reload(bus, args);
+ return daemon_reload(argc, argv, userdata);
- /* first try logind, to allow authentication with polkit */
- if (geteuid() != 0 &&
- IN_SET(a,
+ /* First try logind, to allow authentication with polkit */
+ if (IN_SET(a,
ACTION_POWEROFF,
ACTION_REBOOT,
ACTION_SUSPEND,
ACTION_HIBERNATE,
ACTION_HYBRID_SLEEP)) {
- r = reboot_with_logind(bus, a);
+ r = logind_reboot(a);
if (r >= 0)
return r;
if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
/* requested operation is not supported or already in progress */
return r;
- /* on all other errors, try low-level operation */
- }
- r = start_unit(bus, args);
- if (r == EXIT_SUCCESS)
- warn_wall(a);
+ /* On all other errors, try low-level operation */
+ }
- return r;
+ return start_unit(argc, argv, userdata);
}
-static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
+static int check_unit_generic(int code, const char *good_states, char **args) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r;
- assert(bus);
- assert(args);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = expand_names(bus, args, NULL, &names);
if (r < 0)
@@ -3122,25 +3203,27 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch
return r;
}
-static int check_unit_active(sd_bus *bus, char **args) {
+static int check_unit_active(int argc, char *argv[], void *userdata) {
/* According to LSB: 3, "program is not running" */
- return check_unit_generic(bus, 3, "active\0reloading\0", args + 1);
+ return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1));
}
-static int check_unit_failed(sd_bus *bus, char **args) {
- return check_unit_generic(bus, 1, "failed\0", args + 1);
+static int check_unit_failed(int argc, char *argv[], void *userdata) {
+ return check_unit_generic(1, "failed\0", strv_skip(argv, 1));
}
-static int kill_unit(sd_bus *bus, char **args) {
+static int kill_unit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
char *kill_who = NULL, **name;
+ sd_bus *bus;
int r, q;
- assert(bus);
- assert(args);
-
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (!arg_kill_who)
arg_kill_who = "all";
@@ -3148,9 +3231,9 @@ static int kill_unit(sd_bus *bus, char **args) {
if (streq(arg_job_mode, "fail"))
kill_who = strjoina(arg_kill_who, "-fail", NULL);
- r = expand_names(bus, args + 1, NULL, &names);
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -3165,7 +3248,7 @@ static int kill_unit(sd_bus *bus, char **args) {
NULL,
"ssi", *names, kill_who ? kill_who : arg_kill_who, arg_signal);
if (q < 0) {
- log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -3407,7 +3490,8 @@ static void print_status_info(
dir = mfree(dir);
- if (path_get_parent(*dropin, &dir) < 0) {
+ dir = dirname_malloc(*dropin);
+ if (!dir) {
log_oom();
return;
}
@@ -3456,7 +3540,7 @@ static void print_status_info(
printf("Condition: start %scondition failed%s at %s%s%s\n",
ansi_highlight_yellow(), ansi_normal(),
- s2, s1 ? "; " : "", s1 ? s1 : "");
+ s2, s1 ? "; " : "", strempty(s1));
if (i->failed_condition_trigger)
printf(" none of the trigger conditions were met\n");
else if (i->failed_condition)
@@ -3472,7 +3556,7 @@ static void print_status_info(
printf(" Assert: start %sassertion failed%s at %s%s%s\n",
ansi_highlight_red(), ansi_normal(),
- s2, s1 ? "; " : "", s1 ? s1 : "");
+ s2, s1 ? "; " : "", strempty(s1));
if (i->failed_assert_trigger)
printf(" none of the trigger assertions were met\n");
else if (i->failed_assert)
@@ -3861,13 +3945,13 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
info->name = strdup(name);
if (!info->name)
- log_oom();
+ return log_oom();
LIST_PREPEND(exec, i->exec, info);
info = new0(ExecStatusInfo, 1);
if (!info)
- log_oom();
+ return log_oom();
}
if (r < 0)
@@ -4439,10 +4523,8 @@ static int get_unit_dbus_path_by_pid(
&error,
&reply,
"u", pid);
- if (r < 0) {
- log_error("Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
r = sd_bus_message_read(reply, "o", &u);
if (r < 0)
@@ -4551,16 +4633,22 @@ static int show_system_status(sd_bus *bus) {
return 0;
}
-static int show(sd_bus *bus, char **args) {
- bool show_properties, show_status, new_line = false;
+static int show(int argc, char *argv[], void *userdata) {
+ bool show_properties, show_status, show_help, new_line = false;
bool ellipsized = false;
int r, ret = 0;
+ sd_bus *bus;
- assert(bus);
- assert(args);
+ assert(argv);
- show_properties = streq(args[0], "show");
- show_status = streq(args[0], "status");
+ show_properties = streq(argv[0], "show");
+ show_status = streq(argv[0], "status");
+ show_help = streq(argv[0], "help");
+
+ if (show_help && argc <= 1) {
+ log_error("This command expects one or more unit names. Did you mean --help?");
+ return -EINVAL;
+ }
if (show_properties)
pager_open_if_enabled();
@@ -4571,24 +4659,27 @@ static int show(sd_bus *bus, char **args) {
* be split up into many files. */
setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
- /* If no argument is specified inspect the manager itself */
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
- if (show_properties && strv_length(args) <= 1)
- return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
+ /* If no argument is specified inspect the manager itself */
+ if (show_properties && argc <= 1)
+ return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
- if (show_status && strv_length(args) <= 1) {
+ if (show_status && argc <= 1) {
pager_open_if_enabled();
show_system_status(bus);
new_line = true;
if (arg_all)
- ret = show_all(args[0], bus, false, &new_line, &ellipsized);
+ ret = show_all(argv[0], bus, false, &new_line, &ellipsized);
} else {
_cleanup_free_ char **patterns = NULL;
char **name;
- STRV_FOREACH(name, args + 1) {
+ STRV_FOREACH(name, strv_skip(argv, 1)) {
_cleanup_free_ char *unit = NULL;
uint32_t id;
@@ -4611,8 +4702,7 @@ static int show(sd_bus *bus, char **args) {
}
}
- r = show_one(args[0], bus, unit, show_properties,
- &new_line, &ellipsized);
+ r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4624,7 +4714,7 @@ static int show(sd_bus *bus, char **args) {
r = expand_names(bus, patterns, NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_free_ char *unit;
@@ -4633,8 +4723,7 @@ static int show(sd_bus *bus, char **args) {
if (!unit)
return log_oom();
- r = show_one(args[0], bus, unit, show_properties,
- &new_line, &ellipsized);
+ r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4694,19 +4783,18 @@ static int cat_file(const char *filename, bool newline) {
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
}
-static int cat(sd_bus *bus, char **args) {
+static int cat(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
char **name;
- bool first = true, avoid_bus_cache;
+ sd_bus *bus;
+ bool first = true;
int r;
- assert(args);
-
if (arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Cannot remotely cat units");
+ log_error("Cannot remotely cat units.");
return -EINVAL;
}
@@ -4714,11 +4802,13 @@ static int cat(sd_bus *bus, char **args) {
if (r < 0)
return r;
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
- return log_error_errno(r, "Failed to expand names: %m");
+ return r;
- avoid_bus_cache = !bus || avoid_bus();
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
pager_open_if_enabled();
@@ -4727,7 +4817,7 @@ static int cat(sd_bus *bus, char **args) {
_cleanup_strv_free_ char **dropin_paths = NULL;
char **path;
- r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &fragment_path, &dropin_paths);
+ r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
if (r < 0)
return r;
else if (r == 0)
@@ -4754,15 +4844,20 @@ static int cat(sd_bus *bus, char **args) {
return 0;
}
-static int set_property(sd_bus *bus, char **args) {
+static int set_property(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *n = NULL;
+ sd_bus *bus;
char **i;
int r;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -4773,7 +4868,7 @@ static int set_property(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n);
+ r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
@@ -4785,7 +4880,7 @@ static int set_property(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- STRV_FOREACH(i, args + 2) {
+ STRV_FOREACH(i, strv_skip(argv, 2)) {
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
if (r < 0)
return bus_log_create_error(r);
@@ -4804,25 +4899,24 @@ static int set_property(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
return 0;
}
-static int snapshot(sd_bus *bus, char **args) {
+static int snapshot(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *n = NULL, *id = NULL;
const char *path;
+ sd_bus *bus;
int r;
polkit_agent_open_if_enabled();
- if (strv_length(args) > 1) {
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
+ if (argc > 1) {
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
} else {
@@ -4831,6 +4925,10 @@ static int snapshot(sd_bus *bus, char **args) {
return log_oom();
}
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -4840,10 +4938,8 @@ static int snapshot(sd_bus *bus, char **args) {
&error,
&reply,
"sb", n, false);
- if (r < 0) {
- log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create snapshot: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
@@ -4857,10 +4953,8 @@ static int snapshot(sd_bus *bus, char **args) {
"Id",
&error,
&id);
- if (r < 0) {
- log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get ID of snapshot: %s", bus_error_message(&error, r));
if (!arg_quiet)
puts(id);
@@ -4868,18 +4962,21 @@ static int snapshot(sd_bus *bus, char **args) {
return 0;
}
-static int delete_snapshot(sd_bus *bus, char **args) {
+static int delete_snapshot(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r;
- assert(args);
-
polkit_agent_open_if_enabled();
- r = expand_names(bus, args + 1, ".snapshot", &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), ".snapshot", &names);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4895,7 +4992,7 @@ static int delete_snapshot(sd_bus *bus, char **args) {
NULL,
"s", *name);
if (q < 0) {
- log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -4904,13 +5001,18 @@ static int delete_snapshot(sd_bus *bus, char **args) {
return r;
}
-static int daemon_reload(sd_bus *bus, char **args) {
+static int daemon_reload(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *method;
+ sd_bus *bus;
int r;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (arg_action == ACTION_RELOAD)
method = "Reload";
else if (arg_action == ACTION_REEXEC)
@@ -4919,15 +5021,15 @@ static int daemon_reload(sd_bus *bus, char **args) {
assert(arg_action == ACTION_SYSTEMCTL);
method =
- streq(args[0], "clear-jobs") ||
- streq(args[0], "cancel") ? "ClearJobs" :
- streq(args[0], "daemon-reexec") ? "Reexecute" :
- streq(args[0], "reset-failed") ? "ResetFailed" :
- streq(args[0], "halt") ? "Halt" :
- streq(args[0], "poweroff") ? "PowerOff" :
- streq(args[0], "reboot") ? "Reboot" :
- streq(args[0], "kexec") ? "KExec" :
- streq(args[0], "exit") ? "Exit" :
+ streq(argv[0], "clear-jobs") ||
+ streq(argv[0], "cancel") ? "ClearJobs" :
+ streq(argv[0], "daemon-reexec") ? "Reexecute" :
+ streq(argv[0], "reset-failed") ? "ResetFailed" :
+ streq(argv[0], "halt") ? "Halt" :
+ streq(argv[0], "poweroff") ? "PowerOff" :
+ streq(argv[0], "reboot") ? "Reboot" :
+ streq(argv[0], "kexec") ? "KExec" :
+ streq(argv[0], "exit") ? "Exit" :
/* "daemon-reload" */ "Reload";
}
@@ -4949,24 +5051,29 @@ static int daemon_reload(sd_bus *bus, char **args) {
* reply */
r = 0;
else if (r < 0)
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
return r < 0 ? r : 0;
}
-static int reset_failed(sd_bus *bus, char **args) {
+static int reset_failed(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r, q;
- if (strv_length(args) <= 1)
- return daemon_reload(bus, args);
+ if (argc <= 1)
+ return daemon_reload(argc, argv, userdata);
polkit_agent_open_if_enabled();
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4981,7 +5088,7 @@ static int reset_failed(sd_bus *bus, char **args) {
NULL,
"s", *name);
if (q < 0) {
- log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -4990,14 +5097,19 @@ static int reset_failed(sd_bus *bus, char **args) {
return r;
}
-static int show_environment(sd_bus *bus, char **args) {
+static int show_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *text;
+ sd_bus *bus;
int r;
pager_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
@@ -5007,10 +5119,8 @@ static int show_environment(sd_bus *bus, char **args) {
&error,
&reply,
"as");
- if (r < 0) {
- log_error("Failed to get environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
if (r < 0)
@@ -5028,23 +5138,27 @@ static int show_environment(sd_bus *bus, char **args) {
return 0;
}
-static int switch_root(sd_bus *bus, char **args) {
+static int switch_root(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *cmdline_init = NULL;
const char *root, *init;
- unsigned l;
+ sd_bus *bus;
int r;
- l = strv_length(args);
- if (l < 2 || l > 3) {
+ if (arg_transport != BUS_TRANSPORT_LOCAL) {
+ log_error("Cannot switch root remotely.");
+ return -EINVAL;
+ }
+
+ if (argc < 2 || argc > 3) {
log_error("Wrong number of arguments.");
return -EINVAL;
}
- root = args[1];
+ root = argv[1];
- if (l >= 3)
- init = args[2];
+ if (argc >= 3)
+ init = argv[2];
else {
r = parse_env_file("/proc/cmdline", WHITESPACE,
"init", &cmdline_init,
@@ -5070,6 +5184,10 @@ static int switch_root(sd_bus *bus, char **args) {
init = NULL;
}
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
log_debug("Switching root - root: %s; init: %s", root, strna(init));
r = sd_bus_call_method(
@@ -5081,26 +5199,29 @@ static int switch_root(sd_bus *bus, char **args) {
&error,
NULL,
"ss", root, init);
- if (r < 0) {
- log_error("Failed to switch root: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
return 0;
}
-static int set_environment(sd_bus *bus, char **args) {
+static int set_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
const char *method;
+ sd_bus *bus;
int r;
- assert(bus);
- assert(args);
+ assert(argc > 1);
+ assert(argv);
polkit_agent_open_if_enabled();
- method = streq(args[0], "set-environment")
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ method = streq(argv[0], "set-environment")
? "SetEnvironment"
: "UnsetEnvironment";
@@ -5114,29 +5235,29 @@ static int set_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_strv(m, args + 1);
+ r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to set environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
return 0;
}
-static int import_environment(sd_bus *bus, char **args) {
+static int import_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ sd_bus *bus;
int r;
- assert(bus);
- assert(args);
-
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5147,7 +5268,7 @@ static int import_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- if (strv_isempty(args + 1))
+ if (argc < 2)
r = sd_bus_message_append_strv(m, environ);
else {
char **a, **b;
@@ -5156,7 +5277,7 @@ static int import_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- STRV_FOREACH(a, args + 1) {
+ STRV_FOREACH(a, strv_skip(argv, 1)) {
if (!env_name_is_valid(*a)) {
log_error("Not a valid environment variable name: %s", *a);
@@ -5184,10 +5305,8 @@ static int import_environment(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to import environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
return 0;
}
@@ -5202,6 +5321,9 @@ static int enable_sysv_units(const char *verb, char **args) {
if (arg_scope != UNIT_FILE_SYSTEM)
return 0;
+ if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
+ return 0;
+
if (!STR_IN_SET(verb,
"enable",
"disable",
@@ -5290,13 +5412,13 @@ static int enable_sysv_units(const char *verb, char **args) {
(void) reset_signal_mask();
execv(argv[0], (char**) argv);
- log_error("Failed to execute %s: %m", argv[0]);
+ log_error_errno(r, "Failed to execute %s: %m", argv[0]);
_exit(EXIT_FAILURE);
}
j = wait_for_terminate(pid, &status);
if (j < 0) {
- log_error_errno(r, "Failed to wait for child: %m");
+ log_error_errno(j, "Failed to wait for child: %m");
return j;
}
@@ -5366,18 +5488,18 @@ static int mangle_names(char **original_names, char ***mangled_names) {
return 0;
}
-static int enable_unit(sd_bus *bus, char **args) {
+static int enable_unit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
- const char *verb = args[0];
+ const char *verb = argv[0];
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int carries_install_info = -1;
int r;
- if (!args[1])
+ if (!argv[1])
return 0;
- r = mangle_names(args+1, &names);
+ r = mangle_names(strv_skip(argv, 1), &names);
if (r < 0)
return r;
@@ -5390,7 +5512,7 @@ static int enable_unit(sd_bus *bus, char **args) {
if (strv_isempty(names))
return 0;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
if (streq(verb, "enable")) {
r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
carries_install_info = r;
@@ -5426,9 +5548,14 @@ static int enable_unit(sd_bus *bus, char **args) {
int expect_carries_install_info = false;
bool send_force = true, send_preset_mode = false;
const char *method;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (streq(verb, "enable")) {
method = "EnableUnitFiles";
expect_carries_install_info = true;
@@ -5488,10 +5615,8 @@ static int enable_unit(sd_bus *bus, char **args) {
}
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
if (expect_carries_install_info) {
r = sd_bus_message_read(reply, "b", &carries_install_info);
@@ -5505,7 +5630,7 @@ static int enable_unit(sd_bus *bus, char **args) {
/* Try to reload if enabled */
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5521,16 +5646,21 @@ static int enable_unit(sd_bus *bus, char **args) {
"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")) {
+ if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
char *new_args[n_changes + 2];
+ sd_bus *bus;
unsigned i;
- new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "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);
+ r = start_unit(strv_length(new_args), new_args, userdata);
}
finish:
@@ -5539,21 +5669,21 @@ finish:
return r;
}
-static int add_dependency(sd_bus *bus, char **args) {
+static int add_dependency(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
_cleanup_free_ char *target = NULL;
- const char *verb = args[0];
+ const char *verb = argv[0];
UnitDependency dep;
int r = 0;
- if (!args[1])
+ if (!argv[1])
return 0;
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- r = mangle_names(args+2, &names);
+ r = mangle_names(strv_skip(argv, 2), &names);
if (r < 0)
return r;
@@ -5564,7 +5694,7 @@ static int add_dependency(sd_bus *bus, char **args) {
else
assert_not_reached("Unknown verb");
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
@@ -5581,9 +5711,14 @@ static int add_dependency(sd_bus *bus, char **args) {
} else {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5603,17 +5738,15 @@ static int add_dependency(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5621,12 +5754,12 @@ static int add_dependency(sd_bus *bus, char **args) {
return r;
}
-static int preset_all(sd_bus *bus, char **args) {
+static int preset_all(int argc, char *argv[], void *userdata) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int r;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
if (r < 0) {
@@ -5642,9 +5775,14 @@ static int preset_all(sd_bus *bus, char **args) {
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -5657,17 +5795,15 @@ static int preset_all(sd_bus *bus, char **args) {
unit_file_preset_mode_to_string(arg_preset_mode),
arg_runtime,
arg_force);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5678,25 +5814,24 @@ finish:
return r;
}
-static int unit_is_enabled(sd_bus *bus, char **args) {
+static int unit_is_enabled(int argc, char *argv[], void *userdata) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **names = NULL;
bool enabled;
char **name;
int r;
- r = mangle_names(args+1, &names);
+ r = mangle_names(strv_skip(argv, 1), &names);
if (r < 0)
return r;
- r = enable_sysv_units(args[0], names);
+ r = enable_sysv_units(argv[0], names);
if (r < 0)
return r;
enabled = r > 0;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
STRV_FOREACH(name, names) {
UnitFileState state;
@@ -5717,6 +5852,13 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
}
} else {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
STRV_FOREACH(name, names) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *s;
@@ -5730,10 +5872,8 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
&error,
&reply,
"s", *name);
- if (r < 0) {
- log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &s);
if (r < 0)
@@ -5750,10 +5890,21 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
return !enabled;
}
-static int is_system_running(sd_bus *bus, char **args) {
+static int is_system_running(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *state = NULL;
+ sd_bus *bus;
int r;
+ if (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted()) {
+ if (!arg_quiet)
+ puts("offline");
+ return EXIT_FAILURE;
+ }
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
@@ -5775,7 +5926,7 @@ static int is_system_running(sd_bus *bus, char **args) {
}
static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
- char *t;
+ _cleanup_free_ char *t = NULL;
int r;
assert(new_path);
@@ -5787,27 +5938,21 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
r = mkdir_parents(new_path, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
- free(t);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
r = copy_file(original_path, t, 0, 0644, 0);
if (r == -ENOENT) {
+
r = touch(t);
- if (r < 0) {
- log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
- free(t);
- return r;
- }
- } else if (r < 0) {
- log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
- free(t);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
+
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
*ret_tmp_fn = t;
+ t = NULL;
return 0;
}
@@ -5815,6 +5960,9 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
_cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
+ assert(name);
+ assert(ret_path);
+
switch (arg_scope) {
case UNIT_FILE_SYSTEM:
path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
@@ -5845,12 +5993,16 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
return log_oom();
if (arg_runtime) {
- if (access(path, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
- run, path);
- if (path2 && access(path2, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
- run, path2);
+ if (access(path, F_OK) >= 0) {
+ log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
+ return -EEXIST;
+ }
+
+ if (path2 && access(path2, F_OK) >= 0) {
+ log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2);
+ return -EEXIST;
+ }
+
*ret_path = run;
run = NULL;
} else {
@@ -5862,8 +6014,7 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
}
static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
- char *tmp_new_path, *ending;
- char *tmp_tmp_path;
+ char *tmp_new_path, *tmp_tmp_path, *ending;
int r;
assert(unit_name);
@@ -5895,8 +6046,7 @@ static int unit_file_create_copy(
char **ret_new_path,
char **ret_tmp_path) {
- char *tmp_new_path;
- char *tmp_tmp_path;
+ char *tmp_new_path, *tmp_tmp_path;
int r;
assert(fragment_path);
@@ -5943,10 +6093,8 @@ static int run_editor(char **paths) {
assert(paths);
pid = fork();
- if (pid < 0) {
- log_error_errno(errno, "Failed to fork: %m");
- return -errno;
- }
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
if (pid == 0) {
const char **args;
@@ -6004,7 +6152,7 @@ static int run_editor(char **paths) {
* failing.
*/
if (errno != ENOENT) {
- log_error("Failed to execute %s: %m", editor);
+ log_error_errno(errno, "Failed to execute %s: %m", editor);
_exit(EXIT_FAILURE);
}
}
@@ -6017,14 +6165,13 @@ static int run_editor(char **paths) {
if (r < 0)
return log_error_errno(r, "Failed to wait for child: %m");
- return r;
+ return 0;
}
static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
- bool avoid_bus_cache;
char **name;
int r;
@@ -6035,13 +6182,11 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
if (r < 0)
return r;
- avoid_bus_cache = !bus || avoid_bus();
-
STRV_FOREACH(name, names) {
_cleanup_free_ char *path = NULL;
char *new_path, *tmp_path;
- r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL);
+ r = unit_find_paths(bus, *name, &lp, &path, NULL);
if (r < 0)
return r;
else if (r == 0)
@@ -6067,25 +6212,28 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
return 0;
}
-static int edit(sd_bus *bus, char **args) {
+static int edit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
_cleanup_strv_free_ char **paths = NULL;
char **original, **tmp;
+ sd_bus *bus;
int r;
- assert(args);
-
if (!on_tty()) {
- log_error("Cannot edit units if not on a tty");
+ log_error("Cannot edit units if not on a tty.");
return -EINVAL;
}
if (arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Cannot remotely edit units");
+ log_error("Cannot edit units remotely.");
return -EINVAL;
}
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
@@ -6101,13 +6249,14 @@ static int edit(sd_bus *bus, char **args) {
goto end;
STRV_FOREACH_PAIR(original, tmp, paths) {
- /* If the temporary file is empty we ignore it.
- * It's useful if the user wants to cancel its modification
+ /* If the temporary file is empty we ignore it. It's
+ * useful if the user wants to cancel its modification
*/
if (null_or_empty_path(*tmp)) {
- log_warning("Editing \"%s\" canceled: temporary file is empty", *original);
+ log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
continue;
}
+
r = rename(*tmp, *original);
if (r < 0) {
r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
@@ -6115,12 +6264,14 @@ static int edit(sd_bus *bus, char **args) {
}
}
- if (!arg_no_reload && bus && !avoid_bus())
- r = daemon_reload(bus, args);
+ r = 0;
+
+ if (!arg_no_reload && !install_client_side())
+ r = daemon_reload(argc, argv, userdata);
end:
STRV_FOREACH_PAIR(original, tmp, paths)
- unlink_noerrno(*tmp);
+ (void) unlink(*tmp);
return r;
}
@@ -6314,15 +6465,90 @@ static void runlevel_help(void) {
static void help_types(void) {
int i;
- const char *t;
if (!arg_no_legend)
puts("Available unit types:");
- for (i = 0; i < _UNIT_TYPE_MAX; i++) {
- t = unit_type_to_string(i);
- if (t)
- puts(t);
- }
+ for (i = 0; i < _UNIT_TYPE_MAX; i++)
+ puts(unit_type_to_string(i));
+}
+
+static void help_states(void) {
+ int i;
+
+ if (!arg_no_legend)
+ puts("Available unit load states:");
+ for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
+ puts(unit_load_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable unit active states:");
+ for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
+ puts(unit_active_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable automount unit substates:");
+ for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
+ puts(automount_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable busname unit substates:");
+ for (i = 0; i < _BUSNAME_STATE_MAX; i++)
+ puts(busname_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable device unit substates:");
+ for (i = 0; i < _DEVICE_STATE_MAX; i++)
+ puts(device_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable mount unit substates:");
+ for (i = 0; i < _MOUNT_STATE_MAX; i++)
+ puts(mount_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable path unit substates:");
+ for (i = 0; i < _PATH_STATE_MAX; i++)
+ puts(path_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable scope unit substates:");
+ for (i = 0; i < _SCOPE_STATE_MAX; i++)
+ puts(scope_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable service unit substates:");
+ for (i = 0; i < _SERVICE_STATE_MAX; i++)
+ puts(service_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable slice unit substates:");
+ for (i = 0; i < _SLICE_STATE_MAX; i++)
+ puts(slice_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable snapshot unit substates:");
+ for (i = 0; i < _SNAPSHOT_STATE_MAX; i++)
+ puts(snapshot_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable socket unit substates:");
+ for (i = 0; i < _SOCKET_STATE_MAX; i++)
+ puts(socket_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable swap unit substates:");
+ for (i = 0; i < _SWAP_STATE_MAX; i++)
+ puts(swap_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable target unit substates:");
+ for (i = 0; i < _TARGET_STATE_MAX; i++)
+ puts(target_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable timer unit substates:");
+ for (i = 0; i < _TIMER_STATE_MAX; i++)
+ puts(timer_state_to_string(i));
}
static int systemctl_parse_argv(int argc, char *argv[]) {
@@ -6405,7 +6631,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{}
};
- int c;
+ const char *p;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -6422,20 +6649,22 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 't': {
- const char *word, *state;
- size_t size;
+ if (isempty(optarg))
+ return log_error_errno(r, "--type requires arguments.");
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- _cleanup_free_ char *type;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *type = NULL;
- type = strndup(word, size);
- if (!type)
- return -ENOMEM;
+ r = extract_first_word(&p, &type, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse type: %s", optarg);
+
+ if (r == 0)
+ break;
if (streq(type, "help")) {
help_types();
@@ -6443,7 +6672,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
}
if (unit_type_from_string(type) >= 0) {
- if (strv_push(&arg_types, type))
+ if (strv_push(&arg_types, type) < 0)
return log_oom();
type = NULL;
continue;
@@ -6453,7 +6682,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
* load states, but let's support this
* in --types= too for compatibility
* with old versions */
- if (unit_load_state_from_string(optarg) >= 0) {
+ if (unit_load_state_from_string(type) >= 0) {
if (strv_push(&arg_states, type) < 0)
return log_oom();
type = NULL;
@@ -6476,18 +6705,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
if (!arg_properties)
return log_oom();
} else {
- const char *word, *state;
- size_t size;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *prop = NULL;
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- char *prop;
+ r = extract_first_word(&p, &prop, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse property: %s", optarg);
- prop = strndup(word, size);
- if (!prop)
- return log_oom();
+ if (r == 0)
+ break;
- if (strv_consume(&arg_properties, prop) < 0)
+ if (strv_push(&arg_properties, prop) < 0)
return log_oom();
+
+ prop = NULL;
}
}
@@ -6564,7 +6796,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_ROOT:
- arg_root = optarg;
+ r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ if (r < 0)
+ return r;
break;
case 'l':
@@ -6598,7 +6832,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case 's':
- if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
+ arg_signal = signal_from_string_try_harder(optarg);
+ if (arg_signal < 0) {
log_error("Failed to parse signal string %s.", optarg);
return -EINVAL;
}
@@ -6650,18 +6885,29 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_STATE: {
- const char *word, *state;
- size_t size;
+ if (isempty(optarg))
+ return log_error_errno(r, "--signal requires arguments.");
- FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- char *s;
+ p = optarg;
+ for(;;) {
+ _cleanup_free_ char *s = NULL;
- s = strndup(word, size);
- if (!s)
- return log_oom();
+ r = extract_first_word(&p, &s, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse signal: %s", optarg);
+
+ if (r == 0)
+ break;
+
+ if (streq(s, "help")) {
+ help_states();
+ return 0;
+ }
- if (strv_consume(&arg_states, s) < 0)
+ if (strv_push(&arg_states, s) < 0)
return log_oom();
+
+ s = NULL;
}
break;
}
@@ -6800,7 +7046,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
return 1;
}
-static int parse_time_spec(const char *t, usec_t *_u) {
+static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
assert(t);
assert(_u);
@@ -6866,12 +7112,13 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
{}
};
+ char **wall = NULL;
int c, r;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0)
switch (c) {
case ARG_HELP:
@@ -6929,7 +7176,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
}
if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
- r = parse_time_spec(argv[optind], &arg_when);
+ r = parse_shutdown_time_spec(argv[optind], &arg_when);
if (r < 0) {
log_error("Failed to parse time specification: %s", argv[optind]);
return r;
@@ -6939,10 +7186,16 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
/* No time argument for shutdown cancel */
- arg_wall = argv + optind;
+ wall = argv + optind;
else if (argc > optind + 1)
/* We skip the time argument */
- arg_wall = argv + optind + 1;
+ wall = argv + optind + 1;
+
+ if (wall) {
+ arg_wall = strv_copy(wall);
+ if (!arg_wall)
+ return log_oom();
+ }
optind = argc;
@@ -7006,8 +7259,7 @@ static int telinit_parse_argv(int argc, char *argv[]) {
}
if (optind >= argc) {
- log_error("%s: required argument missing.",
- program_invocation_short_name);
+ log_error("%s: required argument missing.", program_invocation_short_name);
return -EINVAL;
}
@@ -7142,7 +7394,7 @@ _pure_ static int action_to_runlevel(void) {
}
static int talk_initctl(void) {
-
+#ifdef HAVE_SYSV_COMPAT
struct init_request request = {
.magic = INIT_MAGIC,
.sleeptime = 0,
@@ -7164,8 +7416,7 @@ static int talk_initctl(void) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
}
r = loop_write(fd, &request, sizeof(request), false);
@@ -7173,177 +7424,91 @@ static int talk_initctl(void) {
return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
return 1;
+#else
+ return 0;
+#endif
}
-static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
-
- static const struct {
- const char* verb;
- const enum {
- MORE,
- LESS,
- EQUAL
- } argc_cmp;
- const int argc;
- int (* const dispatch)(sd_bus *bus, char **args);
- const enum {
- NOBUS = 1,
- FORCE,
- } bus;
- } verbs[] = {
- { "list-units", MORE, 0, list_units },
- { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
- { "list-sockets", MORE, 1, list_sockets },
- { "list-timers", MORE, 1, list_timers },
- { "list-jobs", MORE, 1, list_jobs },
- { "list-machines", MORE, 1, list_machines },
- { "clear-jobs", EQUAL, 1, daemon_reload },
- { "cancel", MORE, 2, cancel_job },
- { "start", MORE, 2, start_unit },
- { "stop", MORE, 2, start_unit },
- { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
- { "reload", MORE, 2, start_unit },
- { "restart", MORE, 2, start_unit },
- { "try-restart", MORE, 2, start_unit },
- { "reload-or-restart", MORE, 2, start_unit },
- { "reload-or-try-restart", MORE, 2, start_unit },
- { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
- { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
- { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
- { "isolate", EQUAL, 2, start_unit },
- { "kill", MORE, 2, kill_unit },
- { "is-active", MORE, 2, check_unit_active },
- { "check", MORE, 2, check_unit_active },
- { "is-failed", MORE, 2, check_unit_failed },
- { "show", MORE, 1, show },
- { "cat", MORE, 2, cat, NOBUS },
- { "status", MORE, 1, show },
- { "help", MORE, 2, show },
- { "snapshot", LESS, 2, snapshot },
- { "delete", MORE, 2, delete_snapshot },
- { "daemon-reload", EQUAL, 1, daemon_reload },
- { "daemon-reexec", EQUAL, 1, daemon_reload },
- { "show-environment", EQUAL, 1, show_environment },
- { "set-environment", MORE, 2, set_environment },
- { "unset-environment", MORE, 2, set_environment },
- { "import-environment", MORE, 1, import_environment},
- { "halt", EQUAL, 1, start_special, FORCE },
- { "poweroff", EQUAL, 1, start_special, FORCE },
- { "reboot", MORE, 1, start_special, FORCE },
- { "kexec", EQUAL, 1, start_special },
- { "suspend", EQUAL, 1, start_special },
- { "hibernate", EQUAL, 1, start_special },
- { "hybrid-sleep", EQUAL, 1, start_special },
- { "default", EQUAL, 1, start_special },
- { "rescue", EQUAL, 1, start_special },
- { "emergency", EQUAL, 1, start_special },
- { "exit", LESS, 2, start_special },
- { "reset-failed", MORE, 1, reset_failed },
- { "enable", MORE, 2, enable_unit, NOBUS },
- { "disable", MORE, 2, enable_unit, NOBUS },
- { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
- { "reenable", MORE, 2, enable_unit, NOBUS },
- { "preset", MORE, 2, enable_unit, NOBUS },
- { "preset-all", EQUAL, 1, preset_all, NOBUS },
- { "mask", MORE, 2, enable_unit, NOBUS },
- { "unmask", MORE, 2, enable_unit, NOBUS },
- { "link", MORE, 2, enable_unit, NOBUS },
- { "switch-root", MORE, 2, switch_root },
- { "list-dependencies", LESS, 2, list_dependencies },
- { "set-default", EQUAL, 2, set_default, NOBUS },
- { "get-default", EQUAL, 1, get_default, NOBUS },
- { "set-property", MORE, 3, set_property },
- { "is-system-running", EQUAL, 1, is_system_running },
- { "add-wants", MORE, 3, add_dependency, NOBUS },
- { "add-requires", MORE, 3, add_dependency, NOBUS },
- { "edit", MORE, 2, edit, NOBUS },
+static int systemctl_main(int argc, char *argv[]) {
+
+ static const Verb verbs[] = {
+ { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units },
+ { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
+ { "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets },
+ { "list-timers", VERB_ANY, VERB_ANY, 0, list_timers },
+ { "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs },
+ { "list-machines", VERB_ANY, VERB_ANY, 0, list_machines },
+ { "clear-jobs", VERB_ANY, 1, 0, daemon_reload },
+ { "cancel", 2, VERB_ANY, 0, cancel_job },
+ { "start", 2, VERB_ANY, 0, start_unit },
+ { "stop", 2, VERB_ANY, 0, start_unit },
+ { "condstop", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
+ { "reload", 2, VERB_ANY, 0, start_unit },
+ { "restart", 2, VERB_ANY, 0, start_unit },
+ { "try-restart", 2, VERB_ANY, 0, start_unit },
+ { "reload-or-restart", 2, VERB_ANY, 0, start_unit },
+ { "reload-or-try-restart", 2, VERB_ANY, 0, start_unit },
+ { "force-reload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with SysV */
+ { "condreload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
+ { "condrestart", 2, VERB_ANY, 0, start_unit }, /* For compatibility with RH */
+ { "isolate", 2, 2, 0, start_unit },
+ { "kill", 2, VERB_ANY, 0, kill_unit },
+ { "is-active", 2, VERB_ANY, 0, check_unit_active },
+ { "check", 2, VERB_ANY, 0, check_unit_active },
+ { "is-failed", 2, VERB_ANY, 0, check_unit_failed },
+ { "show", VERB_ANY, VERB_ANY, 0, show },
+ { "cat", 2, VERB_ANY, 0, cat },
+ { "status", VERB_ANY, VERB_ANY, 0, show },
+ { "help", VERB_ANY, VERB_ANY, 0, show },
+ { "snapshot", VERB_ANY, 2, 0, snapshot },
+ { "delete", 2, VERB_ANY, 0, delete_snapshot },
+ { "daemon-reload", VERB_ANY, 1, 0, daemon_reload },
+ { "daemon-reexec", VERB_ANY, 1, 0, daemon_reload },
+ { "show-environment", VERB_ANY, 1, 0, show_environment },
+ { "set-environment", 2, VERB_ANY, 0, set_environment },
+ { "unset-environment", 2, VERB_ANY, 0, set_environment },
+ { "import-environment", VERB_ANY, VERB_ANY, 0, import_environment},
+ { "halt", VERB_ANY, 1, 0, start_special },
+ { "poweroff", VERB_ANY, 1, 0, start_special },
+ { "reboot", VERB_ANY, 2, 0, start_special },
+ { "kexec", VERB_ANY, 1, 0, start_special },
+ { "suspend", VERB_ANY, 1, 0, start_special },
+ { "hibernate", VERB_ANY, 1, 0, start_special },
+ { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
+ { "default", VERB_ANY, 1, 0, start_special },
+ { "rescue", VERB_ANY, 1, 0, start_special },
+ { "emergency", VERB_ANY, 1, 0, start_special },
+ { "exit", VERB_ANY, 2, 0, start_special },
+ { "reset-failed", VERB_ANY, VERB_ANY, 0, reset_failed },
+ { "enable", 2, VERB_ANY, 0, enable_unit },
+ { "disable", 2, VERB_ANY, 0, enable_unit },
+ { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
+ { "reenable", 2, VERB_ANY, 0, enable_unit },
+ { "preset", 2, VERB_ANY, 0, enable_unit },
+ { "preset-all", VERB_ANY, 1, 0, preset_all },
+ { "mask", 2, VERB_ANY, 0, enable_unit },
+ { "unmask", 2, VERB_ANY, 0, enable_unit },
+ { "link", 2, VERB_ANY, 0, enable_unit },
+ { "switch-root", 2, VERB_ANY, 0, switch_root },
+ { "list-dependencies", VERB_ANY, 2, 0, list_dependencies },
+ { "set-default", 2, 2, 0, set_default },
+ { "get-default", VERB_ANY, 1, 0, get_default, },
+ { "set-property", 3, VERB_ANY, 0, set_property },
+ { "is-system-running", VERB_ANY, 1, 0, is_system_running },
+ { "add-wants", 3, VERB_ANY, 0, add_dependency },
+ { "add-requires", 3, VERB_ANY, 0, add_dependency },
+ { "edit", 2, VERB_ANY, 0, edit },
{}
- }, *verb = verbs;
-
- int left;
-
- assert(argc >= 0);
- assert(argv);
-
- left = argc - optind;
-
- /* Special rule: no arguments (left == 0) means "list-units" */
- if (left > 0) {
- if (streq(argv[optind], "help") && !argv[optind+1]) {
- log_error("This command expects one or more "
- "unit names. Did you mean --help?");
- return -EINVAL;
- }
-
- for (; verb->verb; verb++)
- if (streq(argv[optind], verb->verb))
- goto found;
-
- log_error("Unknown operation '%s'.", argv[optind]);
- return -EINVAL;
- }
-found:
-
- switch (verb->argc_cmp) {
-
- case EQUAL:
- if (left != verb->argc) {
- log_error("Invalid number of arguments.");
- return -EINVAL;
- }
-
- break;
-
- case MORE:
- if (left < verb->argc) {
- log_error("Too few arguments.");
- return -EINVAL;
- }
-
- break;
-
- case LESS:
- if (left > verb->argc) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
-
- break;
-
- default:
- assert_not_reached("Unknown comparison operator.");
- }
-
- /* Require a bus connection for all operations but
- * enable/disable */
- if (verb->bus == NOBUS) {
- if (!bus && !avoid_bus()) {
- log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
- return -EIO;
- }
-
- } else {
- if (running_in_chroot() > 0) {
- log_info("Running in chroot, ignoring request.");
- return 0;
- }
-
- if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
- log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
- return -EIO;
- }
- }
+ };
- return verb->dispatch(bus, argv + optind);
+ return dispatch_verb(argc, argv, verbs, NULL);
}
-static int reload_with_fallback(sd_bus *bus) {
+static int reload_with_fallback(void) {
- if (bus) {
- /* First, try systemd via D-Bus. */
- if (daemon_reload(bus, NULL) >= 0)
- return 0;
- }
+ /* First, try systemd via D-Bus. */
+ if (daemon_reload(0, NULL, NULL) >= 0)
+ return 0;
/* Nothing else worked, so let's try signals */
assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
@@ -7354,25 +7519,19 @@ static int reload_with_fallback(sd_bus *bus) {
return 0;
}
-static int start_with_fallback(sd_bus *bus) {
+static int start_with_fallback(void) {
- if (bus) {
- /* First, try systemd via D-Bus. */
- if (start_unit(bus, NULL) >= 0)
- goto done;
- }
+ /* First, try systemd via D-Bus. */
+ if (start_unit(0, NULL, NULL) >= 0)
+ return 0;
/* Nothing else worked, so let's try
* /dev/initctl */
if (talk_initctl() > 0)
- goto done;
+ return 0;
log_error("Failed to talk to init daemon.");
return -EIO;
-
-done:
- warn_wall(arg_action);
- return 0;
}
static int halt_now(enum action a) {
@@ -7380,22 +7539,22 @@ static int halt_now(enum action a) {
/* The kernel will automaticall flush ATA disks and suchlike
* on reboot(), but the file systems need to be synce'd
* explicitly in advance. */
- sync();
+ (void) sync();
/* Make sure C-A-D is handled by the kernel from this point
* on... */
- reboot(RB_ENABLE_CAD);
+ (void) reboot(RB_ENABLE_CAD);
switch (a) {
case ACTION_HALT:
log_info("Halting.");
- reboot(RB_HALT_SYSTEM);
+ (void) reboot(RB_HALT_SYSTEM);
return -errno;
case ACTION_POWEROFF:
log_info("Powering off.");
- reboot(RB_POWER_OFF);
+ (void) reboot(RB_POWER_OFF);
return -errno;
case ACTION_KEXEC:
@@ -7404,12 +7563,11 @@ static int halt_now(enum action a) {
if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
log_info("Rebooting with argument '%s'.", param);
- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, param);
+ (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
}
log_info("Rebooting.");
- reboot(RB_AUTOBOOT);
+ (void) reboot(RB_AUTOBOOT);
return -errno;
}
@@ -7418,17 +7576,77 @@ static int halt_now(enum action a) {
}
}
-static int halt_main(sd_bus *bus) {
+static int logind_schedule_shutdown(void) {
+
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ char date[FORMAT_TIMESTAMP_MAX];
+ const char *action;
+ sd_bus *bus;
int r;
- r = check_inhibitors(bus, arg_action);
+ (void) logind_set_wall_message();
+
+ r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
+ switch (arg_action) {
+ case ACTION_HALT:
+ action = "halt";
+ break;
+ case ACTION_POWEROFF:
+ action = "poweroff";
+ break;
+ case ACTION_KEXEC:
+ action = "kexec";
+ break;
+ case ACTION_EXIT:
+ action = "exit";
+ break;
+ case ACTION_REBOOT:
+ default:
+ action = "reboot";
+ break;
+ }
+
+ if (arg_dry)
+ action = strjoina("dry-", action);
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "ScheduleShutdown",
+ &error,
+ NULL,
+ "st",
+ action,
+ arg_when);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
+
+ log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
+ return 0;
+#else
+ log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
+ return -ENOSYS;
+#endif
+}
+
+static int halt_main(void) {
+ int r;
+
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
+
+ if (arg_when > 0)
+ return logind_schedule_shutdown();
+
if (geteuid() != 0) {
- if (arg_when > 0 ||
- arg_dry ||
- arg_force > 0) {
+ if (arg_dry || arg_force > 0) {
log_error("Must be root.");
return -EPERM;
}
@@ -7436,101 +7654,21 @@ static int halt_main(sd_bus *bus) {
/* Try logind if we are a normal user and no special
* mode applies. Maybe PolicyKit allows us to shutdown
* the machine. */
- if (IN_SET(arg_action,
- ACTION_POWEROFF,
- ACTION_REBOOT)) {
- r = reboot_with_logind(bus, arg_action);
+ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
+ r = logind_reboot(arg_action);
if (r >= 0)
return r;
if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
- /* requested operation is not supported or already in progress */
+ /* requested operation is not
+ * supported on the local system or
+ * already in progress */
return r;
/* on all other errors, try low-level operation */
}
}
- if (arg_when > 0) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
- _cleanup_free_ char *m = NULL;
- const char *action;
-
- assert(geteuid() == 0);
-
- if (avoid_bus()) {
- log_error("Unable to perform operation without bus connection.");
- return -ENOSYS;
- }
-
- r = sd_bus_open_system(&b);
- if (r < 0)
- return log_error_errno(r, "Unable to open system bus: %m");
-
- m = strv_join(arg_wall, " ");
- if (!m)
- return log_oom();
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
-
- switch (arg_action) {
- case ACTION_HALT:
- action = "halt";
- break;
- case ACTION_POWEROFF:
- action = "poweroff";
- break;
- case ACTION_KEXEC:
- action = "kexec";
- break;
- default:
- action = "reboot";
- break;
- }
-
- if (arg_dry)
- action = strjoina("dry-", action);
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ScheduleShutdown",
- &error,
- NULL,
- "st",
- action,
- arg_when);
- if (r < 0)
- log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
- bus_error_message(&error, r));
- else {
- char date[FORMAT_TIMESTAMP_MAX];
-
- log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
- format_timestamp(date, sizeof(date), arg_when));
- return 0;
- }
- }
-
if (!arg_dry && !arg_force)
- return start_with_fallback(bus);
+ return start_with_fallback();
assert(geteuid() == 0);
@@ -7548,9 +7686,7 @@ static int halt_main(sd_bus *bus) {
return 0;
r = halt_now(arg_action);
- log_error_errno(r, "Failed to reboot: %m");
-
- return r;
+ return log_error_errno(r, "Failed to reboot: %m");
}
static int runlevel_main(void) {
@@ -7569,8 +7705,37 @@ static int runlevel_main(void) {
return 0;
}
+static int logind_cancel_shutdown(void) {
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ (void) logind_set_wall_message();
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CancelScheduledShutdown",
+ &error,
+ NULL, NULL);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
+
+ return 0;
+#else
+ log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
+ return -ENOSYS;
+#endif
+}
+
int main(int argc, char*argv[]) {
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
@@ -7586,39 +7751,26 @@ int main(int argc, char*argv[]) {
if (r <= 0)
goto finish;
- /* /sbin/runlevel doesn't need to communicate via D-Bus, so
- * let's shortcut this */
- if (arg_action == ACTION_RUNLEVEL) {
- r = runlevel_main();
- goto finish;
- }
-
if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
log_info("Running in chroot, ignoring request.");
r = 0;
goto finish;
}
- if (!avoid_bus())
- r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
-
- if (bus)
- sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
-
/* systemctl_main() will print an error message for the bus
* connection, but only if it needs to */
switch (arg_action) {
case ACTION_SYSTEMCTL:
- r = systemctl_main(bus, argc, argv, r);
+ r = systemctl_main(argc, argv);
break;
case ACTION_HALT:
case ACTION_POWEROFF:
case ACTION_REBOOT:
case ACTION_KEXEC:
- r = halt_main(bus);
+ r = halt_main();
break;
case ACTION_RUNLEVEL2:
@@ -7628,69 +7780,22 @@ int main(int argc, char*argv[]) {
case ACTION_RESCUE:
case ACTION_EMERGENCY:
case ACTION_DEFAULT:
- r = start_with_fallback(bus);
+ r = start_with_fallback();
break;
case ACTION_RELOAD:
case ACTION_REEXEC:
- r = reload_with_fallback(bus);
+ r = reload_with_fallback();
break;
- case ACTION_CANCEL_SHUTDOWN: {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
- _cleanup_free_ char *m = NULL;
-
- if (avoid_bus()) {
- log_error("Unable to perform operation without bus connection.");
- return -ENOSYS;
- }
-
- r = sd_bus_open_system(&b);
- if (r < 0)
- return log_error_errno(r, "Unable to open system bus: %m");
-
- if (arg_wall) {
- m = strv_join(arg_wall, " ");
- if (!m) {
- r = log_oom();
- goto finish;
- }
- }
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "CancelScheduledShutdown",
- &error,
- NULL, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
- bus_error_message(&error, r));
+ case ACTION_CANCEL_SHUTDOWN:
+ r = logind_cancel_shutdown();
break;
- }
case ACTION_RUNLEVEL:
+ r = runlevel_main();
+ break;
+
case _ACTION_INVALID:
default:
assert_not_reached("Unknown action");
@@ -7705,7 +7810,10 @@ finish:
strv_free(arg_states);
strv_free(arg_properties);
- sd_bus_default_flush_close();
+ strv_free(arg_wall);
+ free(arg_root);
+
+ release_busses();
return r < 0 ? EXIT_FAILURE : r;
}