chiark / gitweb /
cgroup: kill processes, not tasks and other cgroup changes
[elogind.git] / src / systemctl.c
index 76f6b84aa59e2f8589d1808333afde9d85a01db7..799f57d006d3b0b6b0883e7eba18cbcad1418cbe 100644 (file)
 #include "special.h"
 #include "initreq.h"
 #include "strv.h"
+#include "dbus-common.h"
+#include "cgroup-show.h"
+#include "cgroup-util.h"
+#include "list.h"
 
 static const char *arg_type = NULL;
 static const char *arg_property = NULL;
@@ -74,6 +78,8 @@ enum action {
         _ACTION_MAX
 } arg_action = ACTION_SYSTEMCTL;
 
+static bool private_bus = false;
+
 static bool error_is_no_service(DBusError *error) {
 
         assert(error);
@@ -106,57 +112,6 @@ static int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *da
         return 0;
 }
 
-static int bus_check_peercred(DBusConnection *c) {
-        int fd;
-        struct ucred ucred;
-        socklen_t l;
-
-        assert(c);
-
-        assert_se(dbus_connection_get_unix_fd(c, &fd));
-
-        l = sizeof(struct ucred);
-        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0) {
-                log_error("SO_PEERCRED failed: %m");
-                return -errno;
-        }
-
-        if (l != sizeof(struct ucred)) {
-                log_error("SO_PEERCRED returned wrong size.");
-                return -E2BIG;
-        }
-
-        if (ucred.uid != 0)
-                return -EPERM;
-
-        return 1;
-}
-
-static int columns(void) {
-        static int parsed_columns = 0;
-        const char *e;
-
-        if (parsed_columns > 0)
-                return parsed_columns;
-
-        if ((e = getenv("COLUMNS")))
-                parsed_columns = atoi(e);
-
-        if (parsed_columns <= 0) {
-                struct winsize ws;
-                zero(ws);
-
-                if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
-                        parsed_columns = ws.ws_col;
-        }
-
-        if (parsed_columns <= 0)
-                parsed_columns = 80;
-
-        return parsed_columns;
-
-}
-
 static void warn_wall(enum action action) {
         static const char *table[_ACTION_MAX] = {
                 [ACTION_HALT]      = "The system is going down for system halt NOW!",
@@ -262,6 +217,9 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
 
                         int a = 0, b = 0;
 
+                        if (streq(active_state, "maintenance"))
+                                fputs(ANSI_HIGHLIGHT_ON, stdout);
+
                         printf("%-45s %-6s %-12s %-12s%n", id, load_state, active_state, sub_state, &a);
 
                         if (job_id != 0)
@@ -273,9 +231,12 @@ static int list_units(DBusConnection *bus, char **args, unsigned n) {
                                 if (job_id == 0)
                                         printf("                ");
 
-                                printf("%.*s", columns() - a - b - 2, description);
+                                printf(" %.*s", columns() - a - b - 2, description);
                         }
 
+                        if (streq(active_state, "maintenance"))
+                                fputs(ANSI_HIGHLIGHT_OFF, stdout);
+
                         fputs("\n", stdout);
                         k++;
                 }
@@ -546,10 +507,10 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
 
         dbus_error_init(&error);
 
-        /* log_debug("Got D-Bus request: %s.%s() on %s", */
-        /*           dbus_message_get_interface(message), */
-        /*           dbus_message_get_member(message), */
-        /*           dbus_message_get_path(message)); */
+        log_debug("Got D-Bus request: %s.%s() on %s",
+                  dbus_message_get_interface(message),
+                  dbus_message_get_member(message),
+                  dbus_message_get_path(message));
 
         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
                 log_error("Warning! D-Bus connection terminated.");
@@ -586,6 +547,9 @@ static int enable_wait_for_jobs(DBusConnection *bus) {
 
         assert(bus);
 
+        if (private_bus)
+                return 0;
+
         dbus_error_init(&error);
         dbus_bus_add_match(bus,
                            "type='signal',"
@@ -881,6 +845,7 @@ static int check_unit(DBusConnection *bus, char **args, unsigned n) {
                         if (!arg_quiet)
                                 puts("unknown");
 
+                        dbus_error_free(&error);
                         continue;
                 }
 
@@ -959,41 +924,93 @@ finish:
         return r;
 }
 
-static void show_cgroup(const char *name) {
-        char *fn, *pids;
-        int r;
-        char *p;
+typedef struct ExecStatusInfo {
+        char *path;
+        char **argv;
 
-        if (!startswith(name, "name=systemd:"))
-                return;
+        usec_t start_timestamp;
+        usec_t exit_timestamp;
+        pid_t pid;
+        int code;
+        int status;
 
-        if (asprintf(&fn, "/cgroup/systemd/%s/tasks", name + 13) < 0)
-                return;
+        LIST_FIELDS(struct ExecStatusInfo, exec);
+} ExecStatusInfo;
+
+static void exec_status_info_free(ExecStatusInfo *i) {
+        assert(i);
 
-        r = read_one_line_file(fn, &pids);
-        free(fn);
+        free(i->path);
+        strv_free(i->argv);
+        free(i);
+}
 
-        if (r < 0)
-                return;
+static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
+        uint64_t start_timestamp, exit_timestamp;
+        DBusMessageIter sub2, sub3;
+        const char*path;
+        unsigned n;
+        uint32_t pid;
+        int32_t code, status;
 
-        p = pids;
-        while (p[0]) {
-                unsigned long ul;
-                char *t = NULL;
+        assert(i);
+        assert(i);
 
-                p += strspn(p, WHITESPACE);
+        if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
+                return -EIO;
 
-                errno = 0;
-                ul = strtoul(p, &p, 0);
-                if (errno != 0 || ul <= 0)
-                        break;
+        dbus_message_iter_recurse(sub, &sub2);
 
-                get_process_cmdline((pid_t) ul, 60, &t);
-                printf("\t\t%lu %s\n", ul, strna(t));
-                free(t);
+        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
+                return -EIO;
+
+        if (!(i->path = strdup(path)))
+                return -ENOMEM;
+
+        if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
+            dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
+                return -EIO;
+
+        n = 0;
+        dbus_message_iter_recurse(&sub2, &sub3);
+        while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
+                assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
+                dbus_message_iter_next(&sub3);
+                n++;
+        }
+
+
+        if (!(i->argv = new0(char*, n+1)))
+                return -ENOMEM;
+
+        n = 0;
+        dbus_message_iter_recurse(&sub2, &sub3);
+        while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
+                const char *s;
+
+                assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
+                dbus_message_iter_get_basic(&sub3, &s);
+                dbus_message_iter_next(&sub3);
+
+                if (!(i->argv[n++] = strdup(s)))
+                        return -ENOMEM;
         }
 
-        free(pids);
+        if (!dbus_message_iter_next(&sub2) ||
+            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
+            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
+            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
+            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
+            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
+                return -EIO;
+
+        i->start_timestamp = (usec_t) start_timestamp;
+        i->exit_timestamp = (usec_t) exit_timestamp;
+        i->pid = (pid_t) pid;
+        i->code = code;
+        i->status = status;
+
+        return 0;
 }
 
 typedef struct UnitStatusInfo {
@@ -1021,6 +1038,7 @@ typedef struct UnitStatusInfo {
         /* Socket */
         unsigned n_accepted;
         unsigned n_connections;
+        bool accept;
 
         /* Device */
         const char *sysfs_path;
@@ -1030,9 +1048,14 @@ typedef struct UnitStatusInfo {
 
         /* Swap */
         const char *what;
+
+        LIST_HEAD(ExecStatusInfo, exec);
 } UnitStatusInfo;
 
 static void print_status_info(UnitStatusInfo *i) {
+        ExecStatusInfo *p;
+        int r;
+
         assert(i);
 
         /* This shows pretty information about a unit. See
@@ -1052,14 +1075,23 @@ static void print_status_info(UnitStatusInfo *i) {
         else
                 printf("\t  Loaded: %s\n", strna(i->load_state));
 
-        if (streq_ptr(i->active_state, "maintenance"))
-                printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
-                       strna(i->active_state),
-                       strna(i->sub_state));
-        else
-                printf("\t  Active: %s (%s)\n",
-                       strna(i->active_state),
-                       strna(i->sub_state));
+        if (streq_ptr(i->active_state, "maintenance")) {
+                        if (streq_ptr(i->active_state, i->sub_state))
+                                printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s" ANSI_HIGHLIGHT_OFF "\n",
+                                       strna(i->active_state));
+                        else
+                                printf("\t  Active: " ANSI_HIGHLIGHT_ON "%s (%s)" ANSI_HIGHLIGHT_OFF "\n",
+                                       strna(i->active_state),
+                                       strna(i->sub_state));
+        } else {
+                if (streq_ptr(i->active_state, i->sub_state))
+                        printf("\t  Active: %s\n",
+                               strna(i->active_state));
+                else
+                        printf("\t  Active: %s (%s)\n",
+                               strna(i->active_state),
+                               strna(i->sub_state));
+        }
 
         if (i->sysfs_path)
                 printf("\t  Device: %s\n", i->sysfs_path);
@@ -1071,14 +1103,41 @@ static void print_status_info(UnitStatusInfo *i) {
         if (i->status_text)
                 printf("\t  Status: \"%s\"\n", i->status_text);
 
-        if (i->id && endswith(i->id, ".socket"))
+        if (i->accept)
                 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
 
+        LIST_FOREACH(exec, p, i->exec) {
+                char *t;
+
+                /* Only show exited processes here */
+                if (p->code == 0)
+                        continue;
+
+                t = strv_join(p->argv, " ");
+                printf("\t  Exited: %u (%s, code=%s, ", p->pid, strna(t), sigchld_code_to_string(p->code));
+                free(t);
+
+                if (p->code == CLD_EXITED)
+                        printf("status=%i", p->status);
+                else
+                        printf("signal=%s", signal_to_string(p->status));
+                printf(")\n");
+
+                if (i->main_pid == p->pid &&
+                    i->start_timestamp == p->start_timestamp &&
+                    i->exit_timestamp == p->start_timestamp)
+                        /* Let's not show this twice */
+                        i->main_pid = 0;
+
+                if (p->pid == i->control_pid)
+                        i->control_pid = 0;
+        }
+
         if (i->main_pid > 0 || i->control_pid > 0) {
                 printf("\t");
 
                 if (i->main_pid > 0) {
-                        printf(" Process: %u", (unsigned) i->main_pid);
+                        printf("    Main: %u", (unsigned) i->main_pid);
 
                         if (i->running) {
                                 char *t = NULL;
@@ -1093,7 +1152,7 @@ static void print_status_info(UnitStatusInfo *i) {
                                 if (i->exit_code == CLD_EXITED)
                                         printf("status=%i", i->exit_status);
                                 else
-                                        printf("signal=%s", strsignal(i->exit_status));
+                                        printf("signal=%s", signal_to_string(i->exit_status));
                                 printf(")");
                         }
                 }
@@ -1117,8 +1176,19 @@ static void print_status_info(UnitStatusInfo *i) {
         }
 
         if (i->default_control_group) {
+                unsigned c;
+
                 printf("\t  CGroup: %s\n", i->default_control_group);
-                show_cgroup(i->default_control_group);
+
+                if ((c = columns()) > 18)
+                        c -= 18;
+                else
+                        c = 0;
+
+                if ((r = cg_init()) < 0)
+                        log_error("Failed to initialize libcg: %s", strerror(-r));
+                else
+                        show_cgroup_recursive(i->default_control_group, "\t\t  ", c);
         }
 }
 
@@ -1159,6 +1229,17 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                 break;
         }
 
+        case DBUS_TYPE_BOOLEAN: {
+                dbus_bool_t b;
+
+                dbus_message_iter_get_basic(iter, &b);
+
+                if (streq(name, "Accept"))
+                        i->accept = b;
+
+                break;
+        }
+
         case DBUS_TYPE_UINT32: {
                 uint32_t u;
 
@@ -1207,6 +1288,34 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
 
                 break;
         }
+
+        case DBUS_TYPE_ARRAY: {
+
+                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
+                    startswith(name, "Exec")) {
+                        DBusMessageIter sub;
+
+                        dbus_message_iter_recurse(iter, &sub);
+                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
+                                ExecStatusInfo *info;
+                                int r;
+
+                                if (!(info = new0(ExecStatusInfo, 1)))
+                                        return -ENOMEM;
+
+                                if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
+                                        free(info);
+                                        return r;
+                                }
+
+                                LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
+
+                                dbus_message_iter_next(&sub);
+                        }
+                }
+
+                break;
+        }
         }
 
         return 0;
@@ -1320,7 +1429,6 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         bool space = false;
 
                         dbus_message_iter_recurse(iter, &sub);
-
                         if (arg_all ||
                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                                 printf("%s=", name);
@@ -1340,11 +1448,11 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
 
                         return 0;
+
                 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_BYTE) {
                         DBusMessageIter sub;
 
                         dbus_message_iter_recurse(iter, &sub);
-
                         if (arg_all ||
                             dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
                                 printf("%s=", name);
@@ -1363,11 +1471,11 @@ 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, "Paths")) {
                         DBusMessageIter sub, sub2;
 
                         dbus_message_iter_recurse(iter, &sub);
-
                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
                                 const char *type, *path;
 
@@ -1381,11 +1489,11 @@ 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, "Timers")) {
                         DBusMessageIter sub, sub2;
 
                         dbus_message_iter_recurse(iter, &sub);
-
                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
                                 const char *base;
                                 uint64_t value, next_elapse;
@@ -1407,59 +1515,38 @@ static int print_property(const char *name, DBusMessageIter *iter) {
                         }
 
                         return 0;
-                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
 
-                        DBusMessageIter sub, sub2, sub3;
+                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
+                        DBusMessageIter sub;
 
                         dbus_message_iter_recurse(iter, &sub);
-
                         while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
-                                const char *path;
-                                uint64_t start_time, exit_time;
-                                uint32_t pid;
-                                int32_t code, status;
-
-                                dbus_message_iter_recurse(&sub, &sub2);
-
-                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
-                                        continue;
-
-                                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
-                                    dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
-                                        continue;
-
-                                printf("%s={ path=%s ; argv[]=", name, path);
-
-                                dbus_message_iter_recurse(&sub2, &sub3);
-
-                                while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
-                                        const char *s;
-
-                                        assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
-                                        dbus_message_iter_get_basic(&sub3, &s);
-                                        printf("%s ", s);
-                                        dbus_message_iter_next(&sub3);
-                                }
-
-                                if (dbus_message_iter_next(&sub2) &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_time, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_time, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) >= 0 &&
-                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) >= 0) {
+                                ExecStatusInfo info;
 
+                                zero(info);
+                                if (exec_status_info_deserialize(&sub, &info) >= 0) {
                                         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
+                                        char *t;
+
+                                        t = strv_join(info.argv, " ");
+
+                                        printf("%s={ path=%s ; argv[]=%s;  start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
+                                               name,
+                                               strna(info.path),
+                                               strna(t),
+                                               strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
+                                               strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
+                                               (unsigned) info. pid,
+                                               sigchld_code_to_string(info.code),
+                                               info.status,
+                                               info.code == CLD_EXITED ? "" : "/",
+                                               strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
 
-                                        printf("; start=%s ; stop=%s ; pid=%u ; code=%s ; status=%i/%s",
-                                               strna(format_timestamp(timestamp1, sizeof(timestamp1), start_time)),
-                                               strna(format_timestamp(timestamp2, sizeof(timestamp2), exit_time)),
-                                               (unsigned) pid,
-                                               sigchld_code_to_string(code),
-                                               status,
-                                               strempty(code == CLD_EXITED ? NULL : strsignal(status)));
+                                        free(t);
                                 }
 
-                                printf(" }\n");
+                                free(info.path);
+                                strv_free(info.argv);
 
                                 dbus_message_iter_next(&sub);
                         }
@@ -1483,6 +1570,7 @@ static int show_one(DBusConnection *bus, const char *path, bool show_properties,
         DBusError error;
         DBusMessageIter iter, sub, sub2, sub3;
         UnitStatusInfo info;
+        ExecStatusInfo *p;
 
         assert(bus);
         assert(path);
@@ -1572,6 +1660,11 @@ static int show_one(DBusConnection *bus, const char *path, bool show_properties,
         if (!show_properties)
                 print_status_info(&info);
 
+        while ((p = info.exec)) {
+                LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
+                exec_status_info_free(p);
+        }
+
         r = 0;
 
 finish:
@@ -1632,6 +1725,42 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                 goto finish;
                         }
 
+                        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+
+                                if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
+                                        log_error("Failed to issue method call: %s", error.message);
+                                        r = -EIO;
+                                        goto finish;
+                                }
+
+                                dbus_error_free(&error);
+
+                                dbus_message_unref(m);
+                                if (!(m = dbus_message_new_method_call(
+                                                      "org.freedesktop.systemd1",
+                                                      "/org/freedesktop/systemd1",
+                                                      "org.freedesktop.systemd1.Manager",
+                                                      "GetUnit"))) {
+                                        log_error("Could not allocate message.");
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                if (!dbus_message_append_args(m,
+                                                              DBUS_TYPE_STRING, &args[i],
+                                                              DBUS_TYPE_INVALID)) {
+                                        log_error("Could not append arguments to message.");
+                                        r = -ENOMEM;
+                                        goto finish;
+                                }
+
+                                if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                                        log_error("Failed to issue method call: %s", error.message);
+                                        r = -EIO;
+                                        goto finish;
+                                }
+                        }
+
                 } else {
 
                         if (!(m = dbus_message_new_method_call(
@@ -1651,12 +1780,12 @@ static int show(DBusConnection *bus, char **args, unsigned n) {
                                 r = -ENOMEM;
                                 goto finish;
                         }
-                }
 
-                if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
-                        log_error("Failed to issue method call: %s", error.message);
-                        r = -EIO;
-                        goto finish;
+                        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+                                log_error("Failed to issue method call: %s", error.message);
+                                r = -EIO;
+                                goto finish;
+                        }
                 }
 
                 if (!dbus_message_get_args(reply, &error,
@@ -1698,10 +1827,10 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
 
         dbus_error_init(&error);
 
-        /* log_debug("Got D-Bus request: %s.%s() on %s", */
-        /*           dbus_message_get_interface(message), */
-        /*           dbus_message_get_member(message), */
-        /*           dbus_message_get_path(message)); */
+        log_debug("Got D-Bus request: %s.%s() on %s",
+                  dbus_message_get_interface(message),
+                  dbus_message_get_member(message),
+                  dbus_message_get_path(message));
 
         if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
                 log_error("Warning! D-Bus connection terminated.");
@@ -1827,43 +1956,45 @@ static int monitor(DBusConnection *bus, char **args, unsigned n) {
 
         dbus_error_init(&error);
 
-        dbus_bus_add_match(bus,
-                           "type='signal',"
-                           "sender='org.freedesktop.systemd1',"
-                           "interface='org.freedesktop.systemd1.Manager',"
-                           "path='/org/freedesktop/systemd1'",
-                           &error);
+        if (!private_bus) {
+                dbus_bus_add_match(bus,
+                                   "type='signal',"
+                                   "sender='org.freedesktop.systemd1',"
+                                   "interface='org.freedesktop.systemd1.Manager',"
+                                   "path='/org/freedesktop/systemd1'",
+                                   &error);
 
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to add match: %s", error.message);
-                r = -EIO;
-                goto finish;
-        }
+                if (dbus_error_is_set(&error)) {
+                        log_error("Failed to add match: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
 
-        dbus_bus_add_match(bus,
-                           "type='signal',"
-                           "sender='org.freedesktop.systemd1',"
-                           "interface='org.freedesktop.systemd1.Unit',"
-                           "member='Changed'",
-                           &error);
+                dbus_bus_add_match(bus,
+                                   "type='signal',"
+                                   "sender='org.freedesktop.systemd1',"
+                                   "interface='org.freedesktop.systemd1.Unit',"
+                                   "member='Changed'",
+                                   &error);
 
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to add match: %s", error.message);
-                r = -EIO;
-                goto finish;
-        }
+                if (dbus_error_is_set(&error)) {
+                        log_error("Failed to add match: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
 
-        dbus_bus_add_match(bus,
-                           "type='signal',"
-                           "sender='org.freedesktop.systemd1',"
-                           "interface='org.freedesktop.systemd1.Job',"
-                           "member='Changed'",
-                           &error);
+                dbus_bus_add_match(bus,
+                                   "type='signal',"
+                                   "sender='org.freedesktop.systemd1',"
+                                   "interface='org.freedesktop.systemd1.Job',"
+                                   "member='Changed'",
+                                   &error);
 
-        if (dbus_error_is_set(&error)) {
-                log_error("Failed to add match: %s", error.message);
-                r = -EIO;
-                goto finish;
+                if (dbus_error_is_set(&error)) {
+                        log_error("Failed to add match: %s", error.message);
+                        r = -EIO;
+                        goto finish;
+                }
         }
 
         if (!dbus_connection_add_filter(bus, monitor_filter, NULL, NULL)) {
@@ -3072,7 +3203,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[]) {
                 { "reboot",            EQUAL, 1, start_special   },
                 { "default",           EQUAL, 1, start_special   },
                 { "rescue",            EQUAL, 1, start_special   },
-                { "emergency",         EQUAL, 1, start_special   },
+                { "emergency",         EQUAL, 1, start_special   }
         };
 
         int left;
@@ -3184,7 +3315,12 @@ static int start_with_fallback(DBusConnection *bus) {
 static int halt_main(DBusConnection *bus) {
         int r;
 
-        if (!arg_immediate)
+        if (geteuid() != 0) {
+                log_error("Must to be root.");
+                return -EPERM;
+        }
+
+        if (!arg_dry && !arg_immediate)
                 return start_with_fallback(bus);
 
         if (!arg_no_wtmp)
@@ -3264,19 +3400,7 @@ int main(int argc, char*argv[]) {
                 goto finish;
         }
 
-        /* If we are root, then let's not go via the bus */
-        if (geteuid() == 0 && !arg_session) {
-                bus = dbus_connection_open("unix:abstract=/org/freedesktop/systemd1/private", &error);
-
-                if (bus && bus_check_peercred(bus) < 0) {
-                        log_error("Failed to verify owner of bus.");
-                        goto finish;
-                }
-        } else
-                bus = dbus_bus_get(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &error);
-
-        if (bus)
-                dbus_connection_set_exit_on_disconnect(bus, FALSE);
+        bus_connect(arg_session ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
 
         switch (arg_action) {