X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fsystemctl.c;h=87ecf03410e09973dcc68bed31343ac2824e78ed;hp=94a12ddeb200e1af805e9056e706b371de6cac79;hb=a76f7be2b02416ff430625766619f4443f2141cf;hpb=060ed82ec24d942c5f519e3dae45e9e2bfb227d8 diff --git a/src/systemctl.c b/src/systemctl.c index 94a12ddeb..87ecf0341 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -60,7 +60,7 @@ static const char *arg_type = NULL; static char **arg_property = NULL; static bool arg_all = false; -static bool arg_fail = false; +static const char *arg_job_mode = "replace"; static bool arg_user = false; static bool arg_global = false; static bool arg_immediate = false; @@ -76,6 +76,7 @@ static bool arg_full = false; static bool arg_force = false; static bool arg_defaults = false; static bool arg_ask_password = false; +static bool arg_failed = false; static char **arg_wall = NULL; static const char *arg_kill_who = NULL; static const char *arg_kill_mode = NULL; @@ -107,10 +108,17 @@ static enum dot { DOT_ORDER, DOT_REQUIRE } arg_dot = DOT_ALL; +static enum transport { + TRANSPORT_NORMAL, + TRANSPORT_SSH, + TRANSPORT_POLKIT +} arg_transport = TRANSPORT_NORMAL; +static const char *arg_host = NULL; static bool private_bus = false; static pid_t pager_pid = 0; +static pid_t agent_pid = 0; static int daemon_reload(DBusConnection *bus, char **args, unsigned n); static void pager_open(void); @@ -131,7 +139,10 @@ static bool on_tty(void) { } static void spawn_ask_password_agent(void) { - pid_t parent, child; + pid_t parent; + + if (agent_pid > 0) + return; /* We check STDIN here, not STDOUT, since this is about input, * not output */ @@ -149,18 +160,14 @@ static void spawn_ask_password_agent(void) { /* Spawns a temporary TTY agent, making sure it goes away when * we go away */ - if ((child = fork()) < 0) + if ((agent_pid = fork()) < 0) return; - if (child == 0) { + if (agent_pid == 0) { /* In the child */ - const char * const args[] = { - SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, - "--watch", - NULL - }; int fd; + bool stdout_is_tty, stderr_is_tty; /* Make sure the agent goes away when the parent dies */ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) @@ -174,7 +181,10 @@ static void spawn_ask_password_agent(void) { /* Don't leak fds to the agent */ close_all_fds(NULL, 0); - if (!isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) { + stdout_is_tty = isatty(STDOUT_FILENO); + stderr_is_tty = isatty(STDERR_FILENO); + + if (!stdout_is_tty || !stderr_is_tty) { /* Detach from stdout/stderr. and reopen * /dev/tty for them. This is important to * ensure that when systemctl is started via @@ -187,21 +197,19 @@ static void spawn_ask_password_agent(void) { _exit(EXIT_FAILURE); } - if (!isatty(STDOUT_FILENO)) { - close(STDOUT_FILENO); + if (!stdout_is_tty) dup2(fd, STDOUT_FILENO); - } - if (!isatty(STDERR_FILENO)) { - close(STDERR_FILENO); + if (!stderr_is_tty) dup2(fd, STDERR_FILENO); - } if (fd > 2) close(fd); } - execv(args[0], (char **) args); + execl(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL); + + log_error("Unable to execute agent: %m"); _exit(EXIT_FAILURE); } } @@ -347,9 +355,12 @@ static int compare_unit_info(const void *a, const void *b) { return strcasecmp(u->id, v->id); } -static bool output_show_job(const struct unit_info *u) { +static bool output_show_unit(const struct unit_info *u) { const char *dot; + if (arg_failed) + return streq(u->active_state, "failed"); + return (!arg_type || ((dot = strrchr(u->id, '.')) && streq(dot+1, arg_type))) && (arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0); @@ -364,7 +375,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { job_len = sizeof("JOB")-1; for (u = unit_infos; u < unit_infos + c; u++) { - if (!output_show_job(u)) + if (!output_show_unit(u)) continue; active_len = MAX(active_len, strlen(u->active_state)); @@ -388,7 +399,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) { const char *on_loaded, *off_loaded; const char *on_active, *off_active; - if (!output_show_job(u)) + if (!output_show_unit(u)) continue; n_shown++; @@ -1116,7 +1127,7 @@ finish: typedef struct WaitData { Set *set; - bool failed; + char *result; } WaitData; static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) { @@ -1140,26 +1151,52 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { uint32_t id; - const char *path; + const char *path, *result; dbus_bool_t success = true; - if (!dbus_message_get_args(message, &error, - DBUS_TYPE_UINT32, &id, - DBUS_TYPE_OBJECT_PATH, &path, - DBUS_TYPE_BOOLEAN, &success, - DBUS_TYPE_INVALID)) - log_error("Failed to parse message: %s", bus_error_message(&error)); - else { + if (dbus_message_get_args(message, &error, + DBUS_TYPE_UINT32, &id, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_STRING, &result, + DBUS_TYPE_INVALID)) { char *p; + if ((p = set_remove(d->set, (char*) path))) + free(p); + + if (*result) + d->result = strdup(result); + + goto finish; + } +#ifndef LEGACY + dbus_error_free(&error); + + if (dbus_message_get_args(message, &error, + DBUS_TYPE_UINT32, &id, + DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_BOOLEAN, &success, + DBUS_TYPE_INVALID)) { + char *p; + + /* Compatibility with older systemd versions < + * 19 during upgrades. This should be dropped + * one day */ + if ((p = set_remove(d->set, (char*) path))) free(p); if (!success) - d->failed = true; + d->result = strdup("failed"); + + goto finish; } +#endif + + log_error("Failed to parse message: %s", bus_error_message(&error)); } +finish: dbus_error_free(&error); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1200,7 +1237,6 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) { zero(d); d.set = s; - d.failed = false; if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) { log_error("Failed to add filter."); @@ -1212,10 +1248,27 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) { dbus_connection_read_write_dispatch(bus, -1)) ; - if (!arg_quiet && d.failed) - log_error("Job failed. See system logs and 'systemctl status' for details."); + if (!arg_quiet && d.result) { + if (streq(d.result, "timeout")) + log_error("Job timed out."); + else if (streq(d.result, "canceled")) + log_error("Job canceled."); + else if (streq(d.result, "dependency")) + log_error("A dependency job failed. See system logs for details."); + else if (!streq(d.result, "done") && !streq(d.result, "skipped")) + log_error("Job failed. See system logs and 'systemctl status' for details."); + } + + if (streq_ptr(d.result, "timeout")) + r = -ETIME; + else if (streq_ptr(d.result, "canceled")) + r = -ECANCELED; + else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped")) + r = -EIO; + else + r = 0; - r = d.failed ? -EIO : 0; + free(d.result); finish: /* This is slightly dirty, since we don't undo the filter registration. */ @@ -1367,22 +1420,26 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) { if (arg_action == ACTION_SYSTEMCTL) { method = - streq(args[0], "stop") ? "StopUnit" : + streq(args[0], "stop") || + streq(args[0], "condstop") ? "StopUnit" : streq(args[0], "reload") ? "ReloadUnit" : streq(args[0], "restart") ? "RestartUnit" : + streq(args[0], "try-restart") || streq(args[0], "condrestart") ? "TryRestartUnit" : + streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" : + streq(args[0], "reload-or-try-restart") || + streq(args[0], "condreload") || + streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" : "StartUnit"; mode = (streq(args[0], "isolate") || streq(args[0], "rescue") || - streq(args[0], "emergency")) ? "isolate" : - arg_fail ? "fail" : - "replace"; + streq(args[0], "emergency")) ? "isolate" : arg_job_mode; one_name = table[verb_to_action(args[0])]; @@ -1781,6 +1838,9 @@ typedef struct UnitStatusInfo { int exit_code, exit_status; + usec_t condition_timestamp; + bool condition_result; + /* Socket */ unsigned n_accepted; unsigned n_connections; @@ -1872,6 +1932,16 @@ static void print_status_info(UnitStatusInfo *i) { else printf("\n"); + if (!i->condition_result && i->condition_timestamp > 0) { + s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp); + s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp); + + if (s1) + printf("\t start condition failed at %s; %s\n", s2, s1); + else if (s2) + printf("\t start condition failed at %s\n", s2); + } + if (i->sysfs_path) printf("\t Device: %s\n", i->sysfs_path); if (i->where) @@ -1998,12 +2068,14 @@ static void print_status_info(UnitStatusInfo *i) { printf("\t CGroup: %s\n", i->default_control_group); - if ((c = columns()) > 18) - c -= 18; - else - c = 0; + if (arg_transport != TRANSPORT_SSH) { + if ((c = columns()) > 18) + c -= 18; + else + c = 0; - show_cgroup_by_path(i->default_control_group, "\t\t ", c); + show_cgroup_by_path(i->default_control_group, "\t\t ", c); + } } if (i->need_daemon_reload) @@ -2067,6 +2139,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn i->accept = b; else if (streq(name, "NeedDaemonReload")) i->need_daemon_reload = b; + else if (streq(name, "ConditionResult")) + i->condition_result = b; break; } @@ -2124,6 +2198,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn i->inactive_exit_timestamp = (usec_t) u; else if (streq(name, "ActiveExitTimestamp")) i->active_exit_timestamp = (usec_t) u; + else if (streq(name, "ConditionTimestamp")) + i->condition_timestamp = (usec_t) u; break; } @@ -2324,6 +2400,25 @@ static int print_property(const char *name, DBusMessageIter *iter) { return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) { + DBusMessageIter sub, sub2; + + dbus_message_iter_recurse(iter, &sub); + while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) { + const char *path; + dbus_bool_t ignore; + + dbus_message_iter_recurse(&sub, &sub2); + + if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 && + bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0) + printf("EnvironmentFile=%s (ignore=%s)\n", path, yes_no(ignore)); + + dbus_message_iter_next(&sub); + } + + return 0; + } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) { DBusMessageIter sub, sub2; @@ -2748,11 +2843,12 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") || dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) { uint32_t id; - const char *path; + const char *path, *result; if (!dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &id, DBUS_TYPE_OBJECT_PATH, &path, + DBUS_TYPE_STRING, &result, DBUS_TYPE_INVALID)) log_error("Failed to parse message: %s", bus_error_message(&error)); else if (streq(dbus_message_get_member(message), "JobNew")) @@ -3972,7 +4068,7 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo } if (!f) { -#if defined(TARGET_FEDORA) && defined (HAVE_SYSV_COMPAT) +#if (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)) && defined (HAVE_SYSV_COMPAT) if (endswith(i->name, ".service")) { char *sysv; @@ -4002,7 +4098,7 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo argv[1] = file_name_from_path(sysv); argv[2] = streq(verb, "enable") ? "on" : - streq(verb, "disable") ? "off" : NULL; + streq(verb, "disable") ? "off" : "--level=3"; log_info("Executing %s %s %s", argv[0], argv[1], strempty(argv[2])); @@ -4021,10 +4117,15 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo return r; if (status.si_code == CLD_EXITED) { - if (status.si_status == 0 && (streq(verb, "enable") || streq(verb, "disable"))) + + if (streq(verb, "is-enabled")) + return status.si_status == 0 ? 1 : 0; + + if (status.si_status == 0) n_symlinks ++; return status.si_status == 0 ? 0 : -EINVAL; + } else return -EPROTO; } @@ -4127,6 +4228,8 @@ static int enable_unit(DBusConnection *bus, char **args, unsigned n) { goto finish; } + r = 0; + while ((i = hashmap_first(will_install))) { int q; @@ -4190,25 +4293,31 @@ static int systemctl_help(void) { " -t --type=TYPE List only units of a particular type\n" " -p --property=NAME Show only properties by this name\n" " -a --all Show all units/properties, including dead/empty ones\n" + " --failed Show only failed units\n" " --full Don't ellipsize unit names on output\n" " --fail When queueing a new job, fail if conflicting jobs are\n" " pending\n" + " --ignore-dependencies\n" + " When queueing a new job, ignore all its dependencies\n" + " --kill-mode=MODE How to send signal\n" + " --kill-who=WHO Who to send signal to\n" + " -s --signal=SIGNAL Which signal to send\n" + " -H --host=[user@]host\n" + " Show information for remote host\n" + " -P --privileged Acquire privileges before execution\n" " -q --quiet Suppress output\n" " --no-block Do not wait until operation finished\n" - " --no-pager Do not pipe output into a pager.\n" - " --system Connect to system manager\n" - " --user Connect to user service manager\n" - " --order When generating graph for dot, show only order\n" - " --require When generating graph for dot, show only requirement\n" " --no-wall Don't send wall message before halt/power-off/reboot\n" - " --global Enable/disable unit files globally\n" " --no-reload When enabling/disabling unit files, don't reload daemon\n" " configuration\n" + " --no-pager Do not pipe output into a pager.\n" " --no-ask-password\n" " Do not ask for system passwords\n" - " --kill-mode=MODE How to send signal\n" - " --kill-who=WHO Who to send signal to\n" - " -s --signal=SIGNAL Which signal to send\n" + " --order When generating graph for dot, show only order\n" + " --require When generating graph for dot, show only requirement\n" + " --system Connect to system manager\n" + " --user Connect to user service manager\n" + " --global Enable/disable unit files globally\n" " -f --force When enabling unit files, override existing symlinks\n" " When shutting down, execute action immediately\n" " --defaults When disabling unit files, remove default symlinks only\n\n" @@ -4330,6 +4439,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { enum { ARG_FAIL = 0x100, + ARG_IGNORE_DEPENDENCIES, ARG_VERSION, ARG_USER, ARG_SYSTEM, @@ -4344,7 +4454,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_DEFAULTS, ARG_KILL_MODE, ARG_KILL_WHO, - ARG_NO_ASK_PASSWORD + ARG_NO_ASK_PASSWORD, + ARG_FAILED }; static const struct option options[] = { @@ -4353,8 +4464,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "type", required_argument, NULL, 't' }, { "property", required_argument, NULL, 'p' }, { "all", no_argument, NULL, 'a' }, + { "failed", no_argument, NULL, ARG_FAILED }, { "full", no_argument, NULL, ARG_FULL }, { "fail", no_argument, NULL, ARG_FAIL }, + { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, { "user", no_argument, NULL, ARG_USER }, { "system", no_argument, NULL, ARG_SYSTEM }, { "global", no_argument, NULL, ARG_GLOBAL }, @@ -4371,6 +4484,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "kill-who", required_argument, NULL, ARG_KILL_WHO }, { "signal", required_argument, NULL, 's' }, { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, + { "host", required_argument, NULL, 'H' }, + { "privileged",no_argument, NULL, 'P' }, { NULL, 0, NULL, 0 } }; @@ -4382,7 +4497,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { /* Only when running as systemctl we ask for passwords */ arg_ask_password = true; - while ((c = getopt_long(argc, argv, "ht:p:aqfs:", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:P", options, NULL)) >= 0) { switch (c) { @@ -4421,7 +4536,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_FAIL: - arg_fail = true; + arg_job_mode = "fail"; + break; + + case ARG_IGNORE_DEPENDENCIES: + arg_job_mode = "ignore-dependencies"; break; case ARG_USER: @@ -4456,6 +4575,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_full = true; break; + case ARG_FAILED: + arg_failed = true; + break; + case 'q': arg_quiet = true; break; @@ -4496,6 +4619,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_ask_password = false; break; + case 'P': + arg_transport = TRANSPORT_POLKIT; + break; + + case 'H': + arg_transport = TRANSPORT_SSH; + arg_host = optarg; + break; + case '?': return -EINVAL; @@ -4505,6 +4637,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } } + if (arg_transport != TRANSPORT_NORMAL && arg_user) { + log_error("Cannot access user instance remotely."); + return -EINVAL; + } + return 1; } @@ -4651,6 +4788,18 @@ static int parse_time_spec(const char *t, usec_t *_u) { return 0; } +static bool kexec_loaded(void) { + bool loaded = false; + char *s; + + if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { + if (s[0] == '1') + loaded = true; + free(s); + } + return loaded; +} + static int shutdown_parse_argv(int argc, char *argv[]) { enum { @@ -4688,7 +4837,10 @@ static int shutdown_parse_argv(int argc, char *argv[]) { break; case 'r': - arg_action = ACTION_REBOOT; + if (kexec_loaded()) + arg_action = ACTION_KEXEC; + else + arg_action = ACTION_REBOOT; break; case 'h': @@ -4881,7 +5033,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_POWEROFF; return halt_parse_argv(argc, argv); } else if (strstr(program_invocation_short_name, "reboot")) { - arg_action = ACTION_REBOOT; + if (kexec_loaded()) + arg_action = ACTION_KEXEC; + else + arg_action = ACTION_REBOOT; return halt_parse_argv(argc, argv); } else if (strstr(program_invocation_short_name, "shutdown")) { arg_action = ACTION_POWEROFF; @@ -5081,12 +5236,14 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError { "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 }, @@ -5209,7 +5366,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) { zero(sockaddr); sockaddr.sa.sa_family = AF_UNIX; sockaddr.un.sun_path[0] = 0; - strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1); + strncpy(sockaddr.un.sun_path, "/dev/.run/systemd/shutdownd", sizeof(sockaddr.un.sun_path)); zero(iovec); iovec.iov_base = (char*) &c; @@ -5217,7 +5374,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) { zero(msghdr); msghdr.msg_name = &sockaddr; - msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1; + msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/dev/.run/systemd/shutdownd") - 1; msghdr.msg_iov = &iovec; msghdr.msg_iovlen = 1; @@ -5369,6 +5526,7 @@ static int runlevel_main(void) { static void pager_open(void) { int fd[2]; const char *pager; + pid_t parent_pid; if (pager_pid > 0) return; @@ -5389,6 +5547,8 @@ static void pager_open(void) { return; } + parent_pid = getpid(); + pager_pid = fork(); if (pager_pid < 0) { log_error("Failed to fork pager: %m"); @@ -5404,7 +5564,14 @@ static void pager_open(void) { setenv("LESS", "FRSX", 0); - prctl(PR_SET_PDEATHSIG, SIGTERM); + /* Make sure the pager goes away when the parent dies */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + + /* Check whether our parent died before we were able + * to set the death signal */ + if (getppid() != parent_pid) + _exit(EXIT_SUCCESS); if (pager) { execlp(pager, pager, NULL); @@ -5441,10 +5608,24 @@ static void pager_close(void) { /* Inform pager that we are done */ fclose(stdout); + kill(pager_pid, SIGCONT); wait_for_terminate(pager_pid, &dummy); pager_pid = 0; } +static void agent_close(void) { + siginfo_t dummy; + + if (agent_pid <= 0) + return; + + /* Inform agent that we are done */ + kill(agent_pid, SIGTERM); + kill(agent_pid, SIGCONT); + wait_for_terminate(agent_pid, &dummy); + agent_pid = 0; +} + int main(int argc, char*argv[]) { int r, retval = EXIT_FAILURE; DBusConnection *bus = NULL; @@ -5470,7 +5651,16 @@ int main(int argc, char*argv[]) { goto finish; } - bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error); + if (arg_transport == TRANSPORT_NORMAL) + bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error); + else if (arg_transport == TRANSPORT_POLKIT) { + bus_connect_system_polkit(&bus, &error); + private_bus = false; + } else if (arg_transport == TRANSPORT_SSH) { + bus_connect_system_ssh(NULL, arg_host, &bus, &error); + private_bus = false; + } else + assert_not_reached("Uh, invalid transport..."); switch (arg_action) { @@ -5481,6 +5671,7 @@ int main(int argc, char*argv[]) { case ACTION_HALT: case ACTION_POWEROFF: case ACTION_REBOOT: + case ACTION_KEXEC: r = halt_main(bus); break; @@ -5526,6 +5717,7 @@ finish: strv_free(arg_property); pager_close(); + agent_close(); return retval; }