chiark / gitweb /
Allow for the use of @ in remote host calls
[elogind.git] / src / systemctl / systemctl.c
index 6067781cf19599fafb28e076b7f87aa2dfa927b6..3e4cefec7689d5784ec54b91906a640aff0253e3 100644 (file)
@@ -129,9 +129,11 @@ static enum transport {
         TRANSPORT_SSH,
         TRANSPORT_POLKIT
 } arg_transport = TRANSPORT_NORMAL;
-static const char *arg_host = NULL;
+static char *arg_host = NULL;
+static char *arg_user = NULL;
 static unsigned arg_lines = 10;
 static OutputMode arg_output = OUTPUT_SHORT;
+static bool arg_plain = false;
 
 static bool private_bus = false;
 
@@ -654,11 +656,12 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
         }
 
         if (cs) {
-                printf("%-*s %-*.*s%-*s %s\n",
-                       pathlen, "LISTEN",
-                       typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
-                       socklen, "UNIT",
-                       "ACTIVATES");
+                if (!arg_no_legend)
+                        printf("%-*s %-*.*s%-*s %s\n",
+                               pathlen, "LISTEN",
+                               typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
+                               socklen, "UNIT",
+                               "ACTIVATES");
 
                 for (s = socket_infos; s < socket_infos + cs; s++) {
                         char **a;
@@ -677,15 +680,18 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
 
                 on = ansi_highlight(true);
                 off = ansi_highlight(false);
-                printf("\n");
+                if (!arg_no_legend)
+                        printf("\n");
         } else {
                 on = ansi_highlight_red(true);
                 off = ansi_highlight_red(false);
         }
 
-        printf("%s%u sockets listed.%s\n", on, cs, off);
-        if (!arg_all)
-                printf("Pass --all to see loaded but inactive sockets, too.\n");
+        if (!arg_no_legend) {
+                printf("%s%u sockets listed.%s\n", on, cs, off);
+                if (!arg_all)
+                        printf("Pass --all to see loaded but inactive sockets, too.\n");
+        }
 
         return 0;
 }
@@ -956,20 +962,22 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
         size_t len = 0;
         size_t max_len = MAX(columns(),20u);
 
-        for (i = level - 1; i >= 0; i--) {
+        if (!arg_plain) {
+                for (i = level - 1; i >= 0; i--) {
+                        len += 2;
+                        if(len > max_len - 3 && !arg_full) {
+                                printf("%s...\n",max_len % 2 ? "" : " ");
+                                return 0;
+                        }
+                        printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
+                }
                 len += 2;
                 if(len > max_len - 3 && !arg_full) {
                         printf("%s...\n",max_len % 2 ? "" : " ");
                         return 0;
                 }
-                printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
+                printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
         }
-        len += 2;
-        if(len > max_len - 3 && !arg_full) {
-                printf("%s...\n",max_len % 2 ? "" : " ");
-                return 0;
-        }
-        printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
 
         if(arg_full){
                 printf("%s\n", name);
@@ -1105,12 +1113,12 @@ static int list_dependencies_compare(const void *_a, const void *_b) {
         return strcasecmp(*a, *b);
 }
 
-static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char **units, unsigned int branches) {
+static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char ***units, unsigned int branches) {
         _cleanup_strv_free_ char **deps = NULL, **u;
         char **c;
         int r = 0;
 
-        u = strv_append(units, name);
+        u = strv_append(*units, name);
         if (!u)
                 return log_oom();
 
@@ -1122,9 +1130,11 @@ static int list_dependencies_one(DBusConnection *bus, const char *name, int leve
 
         STRV_FOREACH(c, deps) {
                 if (strv_contains(u, *c)) {
-                        r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
-                        if (r < 0)
-                                return r;
+                        if (!arg_plain) {
+                                r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
+                                if (r < 0)
+                                        return r;
+                        }
                         continue;
                 }
 
@@ -1133,17 +1143,22 @@ static int list_dependencies_one(DBusConnection *bus, const char *name, int leve
                         return r;
 
                 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
-                       r = list_dependencies_one(bus, *c, level + 1, u, (branches << 1) | (c[1] == NULL ? 0 : 1));
+                       r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1));
                        if(r < 0)
                                return r;
                 }
         }
-
+        if (arg_plain) {
+                strv_free(*units);
+                *units = u;
+                u = NULL;
+        }
         return 0;
 }
 
 static int list_dependencies(DBusConnection *bus, char **args) {
         _cleanup_free_ char *unit = NULL;
+        _cleanup_strv_free_ char **units = NULL;
         const char *u;
 
         assert(bus);
@@ -1160,7 +1175,60 @@ static int list_dependencies(DBusConnection *bus, char **args) {
 
         puts(u);
 
-        return list_dependencies_one(bus, u, 0, NULL, 0);
+        return list_dependencies_one(bus, u, 0, &units, 0);
+}
+
+static int get_default(DBusConnection *bus, char **args) {
+        char *path = NULL;
+        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        int r;
+        _cleanup_dbus_error_free_ DBusError error;
+
+        dbus_error_init(&error);
+
+        if (!bus || avoid_bus()) {
+                r = unit_file_get_default(arg_scope, arg_root, &path);
+
+                if (r < 0) {
+                        log_error("Operation failed: %s", strerror(-r));
+                        goto finish;
+                }
+
+                r = 0;
+        } else {
+                r = bus_method_call_with_reply(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "GetDefaultTarget",
+                        &reply,
+                        NULL,
+                        DBUS_TYPE_INVALID);
+
+                if (r < 0) {
+                        log_error("Operation failed: %s", strerror(-r));
+                        goto finish;
+                }
+
+                if (!dbus_message_get_args(reply, &error,
+                                   DBUS_TYPE_STRING, &path,
+                                   DBUS_TYPE_INVALID)) {
+                        log_error("Failed to parse reply: %s", bus_error_message(&error));
+                        dbus_error_free(&error);
+                        return  -EIO;
+                }
+        }
+
+        if (path)
+                printf("%s\n", path);
+
+finish:
+        if ((!bus || avoid_bus()) && path)
+                free(path);
+
+        return r;
+
 }
 
 struct job_info {
@@ -1285,8 +1353,7 @@ static int list_jobs(DBusConnection *bus, char **args) {
                         goto finish;
                 }
 
-                if (!greedy_realloc((void**) &jobs, &size,
-                                    sizeof(struct job_info) * (used + 1))) {
+                if (!GREEDY_REALLOC(jobs, size, used + 1)) {
                         r = log_oom();
                         goto finish;
                 }
@@ -1847,8 +1914,8 @@ static int start_unit_one(
         }
 
         if (need_daemon_reload(bus, n))
-                log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
-                            n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
+                log_warning("Warning: Unit file of %s changed on disk, 'systemctl %sdaemon-reload' recommended.",
+                            n, arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
 
         if (s) {
                 char *p;
@@ -2634,20 +2701,10 @@ static void print_status_info(UnitStatusInfo *i) {
                 on_tty() * OUTPUT_COLOR |
                 !arg_quiet * OUTPUT_WARN_CUTOFF |
                 arg_full * OUTPUT_FULL_WIDTH;
-        int maxlen = 8; /* a value that'll suffice most of the time */
         char **t, **t2;
 
         assert(i);
 
-        STRV_FOREACH_PAIR(t, t2, i->listen)
-                maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
-        if (i->accept)
-                maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
-        if (i->main_pid > 0)
-                maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
-        else if (i->control_pid > 0)
-                maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
-
         /* This shows pretty information about a unit. See
          * print_property() for a low-level property printer */
 
@@ -2659,7 +2716,7 @@ static void print_status_info(UnitStatusInfo *i) {
         printf("\n");
 
         if (i->following)
-                printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
+                printf("   Follow: unit currently follows state of %s\n", i->following);
 
         if (streq_ptr(i->load_state, "error")) {
                 on = ansi_highlight_red(true);
@@ -2670,17 +2727,17 @@ static void print_status_info(UnitStatusInfo *i) {
         path = i->source_path ? i->source_path : i->fragment_path;
 
         if (i->load_error)
-                printf(" %*s: %s%s%s (Reason: %s)\n",
-                       maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
+                printf("   Loaded: %s%s%s (Reason: %s)\n",
+                       on, strna(i->load_state), off, i->load_error);
         else if (path && i->unit_file_state)
-                printf(" %*s: %s%s%s (%s; %s)\n",
-                       maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
+                printf("   Loaded: %s%s%s (%s; %s)\n",
+                       on, strna(i->load_state), off, path, i->unit_file_state);
         else if (path)
-                printf(" %*s: %s%s%s (%s)\n",
-                       maxlen, "Loaded", on, strna(i->load_state), off, path);
+                printf("   Loaded: %s%s%s (%s)\n",
+                       on, strna(i->load_state), off, path);
         else
-                printf(" %*s: %s%s%s\n",
-                       maxlen, "Loaded", on, strna(i->load_state), off);
+                printf("   Loaded: %s%s%s\n",
+                       on, strna(i->load_state), off);
 
         if (!strv_isempty(i->dropin_paths)) {
                 char ** dropin;
@@ -2689,7 +2746,7 @@ static void print_status_info(UnitStatusInfo *i) {
 
                 STRV_FOREACH(dropin, i->dropin_paths) {
                         if (! dir || last) {
-                                printf("  %*s ", maxlen, dir ? "" : "Drop-In:");
+                                printf(dir ? "        " : "  Drop-In: ");
 
                                 free(dir);
 
@@ -2698,7 +2755,7 @@ static void print_status_info(UnitStatusInfo *i) {
                                         return;
                                 }
 
-                                printf("%s\n %*s  %s", dir, maxlen, "",
+                                printf("%s\n           %s", dir,
                                        draw_special_char(DRAW_TREE_RIGHT));
                         }
 
@@ -2722,11 +2779,11 @@ static void print_status_info(UnitStatusInfo *i) {
                 on = off = "";
 
         if (ss)
-                printf(" %*s: %s%s (%s)%s",
-                       maxlen, "Active",  on, strna(i->active_state), ss, off);
+                printf("   Active: %s%s (%s)%s",
+                       on, strna(i->active_state), ss, off);
         else
-                printf(" %*s: %s%s%s",
-                       maxlen, "Active", on, strna(i->active_state), off);
+                printf("   Active: %s%s%s",
+                       on, strna(i->active_state), off);
 
         if (!isempty(i->result) && !streq(i->result, "success"))
                 printf(" (Result: %s)", i->result);
@@ -2753,26 +2810,26 @@ static void print_status_info(UnitStatusInfo *i) {
                 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
 
                 if (s1)
-                        printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
+                        printf("          start condition failed at %s; %s\n", s2, s1);
                 else if (s2)
-                        printf(" %*s start condition failed at %s\n", maxlen, "", s2);
+                        printf("          start condition failed at %s\n", s2);
         }
 
         if (i->sysfs_path)
-                printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
+                printf("   Device: %s\n", i->sysfs_path);
         if (i->where)
-                printf(" %*s: %s\n", maxlen, "Where", i->where);
+                printf("    Where: %s\n", i->where);
         if (i->what)
-                printf(" %*s: %s\n", maxlen, "What", i->what);
+                printf("     What: %s\n", i->what);
 
         STRV_FOREACH(t, i->documentation)
-                printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
+                printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
 
         STRV_FOREACH_PAIR(t, t2, i->listen)
-                printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t);
+                printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
 
         if (i->accept)
-                printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
+                printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
 
         LIST_FOREACH(exec, p, i->exec) {
                 _cleanup_free_ char *argv = NULL;
@@ -2783,7 +2840,7 @@ static void print_status_info(UnitStatusInfo *i) {
                         continue;
 
                 argv = strv_join(p->argv, " ");
-                printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
+                printf("  Process: %u %s=%s ", p->pid, p->name, strna(argv));
 
                 good = is_clean_exit_lsb(p->code, p->status, NULL);
                 if (!good) {
@@ -2820,7 +2877,7 @@ static void print_status_info(UnitStatusInfo *i) {
 
         if (i->main_pid > 0 || i->control_pid > 0) {
                 if (i->main_pid > 0) {
-                        printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
+                        printf(" Main PID: %u", (unsigned) i->main_pid);
 
                         if (i->running) {
                                 _cleanup_free_ char *comm = NULL;
@@ -2851,7 +2908,7 @@ static void print_status_info(UnitStatusInfo *i) {
                 if (i->control_pid > 0) {
                         _cleanup_free_ char *c = NULL;
 
-                        printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
+                        printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid);
 
                         get_process_comm(i->control_pid, &c);
                         if (c)
@@ -2862,20 +2919,18 @@ static void print_status_info(UnitStatusInfo *i) {
         }
 
         if (i->status_text)
-                printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
+                printf("   Status: \"%s\"\n", i->status_text);
 
         if (i->default_control_group &&
             (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
                 unsigned c;
 
-                printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
+                printf("   CGroup: %s\n", i->default_control_group);
 
                 if (arg_transport != TRANSPORT_SSH) {
                         unsigned k = 0;
                         pid_t extra[2];
-                        char prefix[maxlen + 4];
-                        memset(prefix, ' ', sizeof(prefix) - 1);
-                        prefix[sizeof(prefix) - 1] = '\0';
+                        char prefix[] = "           ";
 
                         c = columns();
                         if (c > sizeof(prefix) - 1)
@@ -2908,10 +2963,10 @@ static void print_status_info(UnitStatusInfo *i) {
         }
 
         if (i->need_daemon_reload)
-                printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
+                printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
                        ansi_highlight_red(true),
                        ansi_highlight_red(false),
-                       arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
+                       arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
 }
 
 static void show_unit_help(UnitStatusInfo *i) {
@@ -4208,24 +4263,30 @@ static int enable_unit(DBusConnection *bus, char **args) {
         if (!args[1])
                 return 0;
 
+        r = mangle_names(args+1, &mangled_names);
+        if (r < 0)
+                goto finish;
+
         if (!bus || avoid_bus()) {
                 if (streq(verb, "enable")) {
-                        r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+                        r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
                         carries_install_info = r;
                 } else if (streq(verb, "disable"))
-                        r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
+                        r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
                 else if (streq(verb, "reenable")) {
-                        r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+                        r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
                         carries_install_info = r;
                 } else if (streq(verb, "link"))
-                        r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+                        r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
                 else if (streq(verb, "preset")) {
-                        r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+                        r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
                         carries_install_info = r;
                 } else if (streq(verb, "mask"))
-                        r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
+                        r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
                 else if (streq(verb, "unmask"))
-                        r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
+                        r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
+                else if (streq(verb, "set-default"))
+                        r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
                 else
                         assert_not_reached("Unknown verb");
 
@@ -4269,6 +4330,8 @@ static int enable_unit(DBusConnection *bus, char **args) {
                 else if (streq(verb, "unmask")) {
                         method = "UnmaskUnitFiles";
                         send_force = false;
+                } else if (streq(verb, "set-default")) {
+                        method = "SetDefaultTarget";
                 } else
                         assert_not_reached("Unknown verb");
 
@@ -4284,10 +4347,6 @@ static int enable_unit(DBusConnection *bus, char **args) {
 
                 dbus_message_iter_init_append(m, &iter);
 
-                r = mangle_names(args+1, &mangled_names);
-                if(r < 0)
-                        goto finish;
-
                 r = bus_append_strv_iter(&iter, mangled_names);
                 if (r < 0) {
                         log_error("Failed to append unit files.");
@@ -4392,6 +4451,51 @@ finish:
         return r;
 }
 
+static int set_log_level(DBusConnection *bus, char **args) {
+        _cleanup_dbus_error_free_ DBusError error;
+        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
+        DBusMessageIter iter, sub;
+        const char* property = "LogLevel";
+        const char* interface = "org.freedesktop.systemd1.Manager";
+        const char* value;
+
+        assert(bus);
+        assert(args);
+
+        value = args[1];
+        dbus_error_init(&error);
+
+        m = dbus_message_new_method_call("org.freedesktop.systemd1",
+                                         "/org/freedesktop/systemd1",
+                                         "org.freedesktop.DBus.Properties",
+                                         "Set");
+        if (!m)
+                return log_oom();
+
+        dbus_message_iter_init_append(m, &iter);
+
+        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &interface) ||
+            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property) ||
+            !dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, "s", &sub))
+                return log_oom();
+
+        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &value)) {
+                dbus_message_iter_abandon_container(&iter, &sub);
+                return log_oom();
+        }
+
+        if (!dbus_message_iter_close_container(&iter, &sub))
+                return log_oom();
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(&error));
+                return -EIO;
+        }
+
+        return 0;
+}
+
 static int unit_is_enabled(DBusConnection *bus, char **args) {
         _cleanup_dbus_error_free_ DBusError error;
         int r;
@@ -4530,6 +4634,7 @@ static int systemctl_help(void) {
                "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
                "Unit Commands:\n"
                "  list-units                      List loaded units\n"
+               "  list-sockets                    List loaded sockets ordered by address\n"
                "  start [NAME...]                 Start (activate) one or more units\n"
                "  stop [NAME...]                  Stop (deactivate) one or more units\n"
                "  reload [NAME...]                Reload one or more units\n"
@@ -4572,6 +4677,8 @@ static int systemctl_help(void) {
                "  unmask [NAME...]                Unmask one or more units\n"
                "  link [PATH...]                  Link one or more units files into\n"
                "                                  the search path\n"
+               "  get-default                     Get the name of the default target\n"
+               "  set-default NAME                Set the default target\n"
                "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
                "Job Commands:\n"
                "  list-jobs                       List jobs\n"
@@ -4584,7 +4691,8 @@ static int systemctl_help(void) {
                "Environment Commands:\n"
                "  show-environment                Dump environment\n"
                "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
-               "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
+               "  unset-environment [NAME...]     Unset one or more environment variables\n"
+               "  set-log-level LEVEL             Set logging threshold for systemd\n\n"
                "Manager Lifecycle Commands:\n"
                "  daemon-reload                   Reload systemd manager configuration\n"
                "  daemon-reexec                   Reexecute systemd manager\n\n"
@@ -4717,7 +4825,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_NO_ASK_PASSWORD,
                 ARG_FAILED,
                 ARG_RUNTIME,
-                ARG_FORCE
+                ARG_FORCE,
+                ARG_PLAIN
         };
 
         static const struct option options[] = {
@@ -4755,6 +4864,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
                 { "lines",     required_argument, NULL, 'n'           },
                 { "output",    required_argument, NULL, 'o'           },
+                { "plain",     no_argument,       NULL, ARG_PLAIN     },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -4956,7 +5066,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
                 case 'H':
                         arg_transport = TRANSPORT_SSH;
-                        arg_host = optarg;
+                        parse_user_at_host(optarg, &arg_user, &arg_host);
                         break;
 
                 case ARG_RUNTIME:
@@ -4982,6 +5092,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_ignore_inhibitors = true;
                         break;
 
+                case ARG_PLAIN:
+                        arg_plain = true;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -5414,7 +5528,7 @@ static int parse_argv(int argc, char *argv[]) {
         return systemctl_parse_argv(argc, argv);
 }
 
-static int action_to_runlevel(void) {
+_pure_ static int action_to_runlevel(void) {
 
         static const char table[_ACTION_MAX] = {
                 [ACTION_HALT] =      '0',
@@ -5627,6 +5741,9 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "link",                  MORE,  2, enable_unit       },
                 { "switch-root",           MORE,  2, switch_root       },
                 { "list-dependencies",     LESS,  2, list_dependencies },
+                { "set-default",           EQUAL, 2, enable_unit       },
+                { "get-default",           LESS,  1, get_default       },
+                { "set-log-level",         EQUAL, 2, set_log_level     },
         };
 
         int left;
@@ -5698,7 +5815,9 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
             !streq(verbs[i].verb, "preset") &&
             !streq(verbs[i].verb, "mask") &&
             !streq(verbs[i].verb, "unmask") &&
-            !streq(verbs[i].verb, "link")) {
+            !streq(verbs[i].verb, "link") &&
+            !streq(verbs[i].verb, "set-default") &&
+            !streq(verbs[i].verb, "get-default")) {
 
                 if (running_in_chroot() > 0) {
                         log_info("Running in chroot, ignoring request.");
@@ -5968,7 +6087,7 @@ int main(int argc, char*argv[]) {
                         bus_connect_system_polkit(&bus, &error);
                         private_bus = false;
                 } else if (arg_transport == TRANSPORT_SSH) {
-                        bus_connect_system_ssh(NULL, arg_host, &bus, &error);
+                        bus_connect_system_ssh(arg_user, arg_host, &bus, &error);
                         private_bus = false;
                 } else
                         assert_not_reached("Uh, invalid transport...");