chiark / gitweb /
systemctl: suggest 'systemctl daemon-reload' without --system
[elogind.git] / src / systemctl / systemctl.c
index b94f7f795858b3c2e395df8019efacf60afc11cd..6a4c2d69002921c5d9965f9ae649f3a6e6225047 100644 (file)
@@ -72,6 +72,12 @@ static char **arg_types = NULL;
 static char **arg_load_states = NULL;
 static char **arg_properties = NULL;
 static bool arg_all = false;
+static enum dependency {
+        DEPENDENCY_FORWARD,
+        DEPENDENCY_REVERSE,
+        DEPENDENCY_AFTER,
+        DEPENDENCY_BEFORE,
+} arg_dependency = DEPENDENCY_FORWARD;
 static const char *arg_job_mode = "replace";
 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
 static bool arg_no_block = false;
@@ -126,6 +132,7 @@ static enum transport {
 static const char *arg_host = NULL;
 static unsigned arg_lines = 10;
 static OutputMode arg_output = OUTPUT_SHORT;
+static bool arg_plain = false;
 
 static bool private_bus = false;
 
@@ -648,11 +655,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;
@@ -671,15 +679,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;
 }
@@ -950,20 +961,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);
@@ -979,12 +992,19 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
 }
 
 static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
-        static const char dependencies[] =
-                "Requires\0"
-                "RequiresOverridable\0"
-                "Requisite\0"
-                "RequisiteOverridable\0"
-                "Wants\0";
+        static const char *dependencies[] = {
+                [DEPENDENCY_FORWARD] = "Requires\0"
+                                       "RequiresOverridable\0"
+                                       "Requisite\0"
+                                       "RequisiteOverridable\0"
+                                       "Wants\0",
+                [DEPENDENCY_REVERSE] = "RequiredBy\0"
+                                       "RequiredByOverridable\0"
+                                       "WantedBy\0"
+                                       "PartOf\0",
+                [DEPENDENCY_AFTER]   = "After\0",
+                [DEPENDENCY_BEFORE]  = "Before\0",
+        };
 
         _cleanup_free_ char *path;
         const char *interface = "org.freedesktop.systemd1.Unit";
@@ -1049,7 +1069,8 @@ static int list_dependencies_get_dependencies(DBusConnection *bus, const char *n
                 dbus_message_iter_recurse(&sub2, &sub3);
                 dbus_message_iter_next(&sub);
 
-                if (!nulstr_contains(dependencies, prop))
+                assert(arg_dependency < ELEMENTSOF(dependencies));
+                if (!nulstr_contains(dependencies[arg_dependency], prop))
                         continue;
 
                 if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
@@ -1091,12 +1112,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();
 
@@ -1108,9 +1129,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;
                 }
 
@@ -1119,17 +1142,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);
@@ -1146,7 +1174,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 {
@@ -1271,8 +1352,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;
                 }
@@ -1833,8 +1913,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;
@@ -2894,10 +2974,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) {
@@ -4194,24 +4274,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");
 
@@ -4255,6 +4341,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");
 
@@ -4270,10 +4358,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.");
@@ -4378,6 +4462,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;
@@ -4479,6 +4608,7 @@ static int systemctl_help(void) {
                "  -a --all            Show all loaded units/properties, including dead/empty\n"
                "                      ones. To list all units installed on the system, use\n"
                "                      the 'list-unit-files' command instead.\n"
+               "     --reverse        Show reverse dependencies with 'list-dependencies'\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"
@@ -4544,7 +4674,8 @@ static int systemctl_help(void) {
                "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
                "  load [NAME...]                  Load one or more units\n"
                "  list-dependencies [NAME]        Recursively show units which are required\n"
-               "                                  or wanted by this unit\n\n"
+               "                                  or wanted by this unit or by which this\n"
+               "                                  unit is required or wanted\n\n"
                "Unit File Commands:\n"
                "  list-unit-files                 List installed unit files\n"
                "  enable [NAME...]                Enable one or more unit files\n"
@@ -4556,6 +4687,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"
@@ -4680,6 +4813,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_FAIL = 0x100,
+                ARG_REVERSE,
+                ARG_AFTER,
+                ARG_BEFORE,
                 ARG_SHOW_TYPES,
                 ARG_IRREVERSIBLE,
                 ARG_IGNORE_DEPENDENCIES,
@@ -4698,7 +4834,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[] = {
@@ -4707,6 +4844,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "type",      required_argument, NULL, 't'           },
                 { "property",  required_argument, NULL, 'p'           },
                 { "all",       no_argument,       NULL, 'a'           },
+                { "reverse",   no_argument,       NULL, ARG_REVERSE   },
+                { "after",     no_argument,       NULL, ARG_AFTER     },
+                { "before",    no_argument,       NULL, ARG_BEFORE    },
                 { "show-types", no_argument,      NULL, ARG_SHOW_TYPES },
                 { "failed",    no_argument,       NULL, ARG_FAILED    },
                 { "full",      no_argument,       NULL, ARG_FULL      },
@@ -4733,6 +4873,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             }
         };
 
@@ -4829,6 +4970,18 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_all = true;
                         break;
 
+                case ARG_REVERSE:
+                        arg_dependency = DEPENDENCY_REVERSE;
+                        break;
+
+                case ARG_AFTER:
+                        arg_dependency = DEPENDENCY_AFTER;
+                        break;
+
+                case ARG_BEFORE:
+                        arg_dependency = DEPENDENCY_BEFORE;
+                        break;
+
                 case ARG_SHOW_TYPES:
                         arg_show_types = true;
                         break;
@@ -4948,6 +5101,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;
 
@@ -5380,7 +5537,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',
@@ -5593,6 +5750,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;
@@ -5664,7 +5824,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.");