chiark / gitweb /
gpt-auto-generator: rename root device node symlink to /dev/gpt-auto-root
[elogind.git] / src / systemctl / systemctl.c
index b9d9b3aa961e8ace832a607d5a842a655f0c6aac..17ad7f0462c3e0ec4c0a05154f07b7d4155a4143 100644 (file)
@@ -58,7 +58,6 @@
 #include "path-lookup.h"
 #include "conf-parser.h"
 #include "exit-status.h"
-#include "bus-errors.h"
 #include "build.h"
 #include "unit-name.h"
 #include "pager.h"
@@ -909,6 +908,31 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
         return 0;
 }
 
+static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
+        usec_t next_elapse;
+
+        assert(nw);
+        assert(next);
+
+        if (next->monotonic != (usec_t) -1 && next->monotonic > 0) {
+                usec_t converted;
+
+                if (next->monotonic > nw->monotonic)
+                        converted = nw->realtime + (next->monotonic - nw->monotonic);
+                else
+                        converted = nw->realtime - (nw->monotonic - next->monotonic);
+
+                if (next->realtime != (usec_t) -1 && next->realtime > 0)
+                        next_elapse = MIN(converted, next->realtime);
+                else
+                        next_elapse = converted;
+
+        } else
+                next_elapse = next->realtime;
+
+        return next_elapse;
+}
+
 static int list_timers(sd_bus *bus, char **args) {
 
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
@@ -931,7 +955,7 @@ static int list_timers(sd_bus *bus, char **args) {
 
         for (u = unit_infos; u < unit_infos + n; u++) {
                 _cleanup_strv_free_ char **triggered = NULL;
-                dual_timestamp next;
+                dual_timestamp next = {};
                 usec_t m;
 
                 if (!endswith(u->id, ".timer"))
@@ -945,26 +969,13 @@ static int list_timers(sd_bus *bus, char **args) {
                 if (r < 0)
                         goto cleanup;
 
-                if (next.monotonic != (usec_t) -1 && next.monotonic > 0) {
-                        usec_t converted;
-
-                        if (next.monotonic > nw.monotonic)
-                                converted = nw.realtime + (next.monotonic - nw.monotonic);
-                        else
-                                converted = nw.realtime - (nw.monotonic - next.monotonic);
-
-                        if (next.realtime != (usec_t) -1 && next.realtime > 0)
-                                m = MIN(converted, next.realtime);
-                        else
-                                m = converted;
-                } else
-                        m = next.realtime;
-
                 if (!GREEDY_REALLOC(timer_infos, size, c+1)) {
                         r = log_oom();
                         goto cleanup;
                 }
 
+                m = calc_next_elapse(&nw, &next);
+
                 timer_infos[c++] = (struct timer_info) {
                         .id = u->id,
                         .next_elapse = m,
@@ -2156,13 +2167,11 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
                         return log_oom();
 
                 if (string_is_glob(t))
-                        r = strv_push(&globs, t);
+                        r = strv_consume(&globs, t);
                 else
-                        r = strv_push(&mangled, t);
-                if (r < 0) {
-                        free(t);
+                        r = strv_consume(&mangled, t);
+                if (r < 0)
                         return log_oom();
-                }
         }
 
         /* Query the manager only if any of the names are a glob, since
@@ -2512,14 +2521,16 @@ static int start_special(sd_bus *bus, char **args) {
 static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
         _cleanup_strv_free_ char **names = NULL;
         char **name;
-        int r = code;
+        int r;
 
         assert(bus);
         assert(args);
 
         r = expand_names(bus, args, NULL, &names);
-        if (r < 0)
+        if (r < 0) {
                 log_error("Failed to expand names: %s", strerror(-r));
+                return r;
+        }
 
         STRV_FOREACH(name, names) {
                 int state;
@@ -2527,8 +2538,8 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch
                 state = check_one_unit(bus, *name, good_states, arg_quiet);
                 if (state < 0)
                         return state;
-                if (state > 0)
-                        r = 0;
+                if (state == 0)
+                        r = code;
         }
 
         return r;
@@ -3405,6 +3416,48 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
                         if (arg_all || !isempty(a) || !isempty(b))
                                 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
 
+                        return 0;
+                } else if (streq_ptr(name, "SystemCallFilter")) {
+                        _cleanup_strv_free_ char **l = NULL;
+                        int whitelist;
+
+                        r = sd_bus_message_enter_container(m, 'r', "bas");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read(m, "b", &whitelist);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read_strv(m, &l);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (arg_all || whitelist || !strv_isempty(l)) {
+                                bool first = true;
+                                char **i;
+
+                                fputs(name, stdout);
+                                fputc('=', stdout);
+
+                                if (!whitelist)
+                                        fputc('~', stdout);
+
+                                STRV_FOREACH(i, l) {
+                                        if (first)
+                                                first = false;
+                                        else
+                                                fputc(' ', stdout);
+
+                                        fputs(*i, stdout);
+                                }
+                                fputc('\n', stdout);
+                        }
+
                         return 0;
                 }
 
@@ -3703,8 +3756,8 @@ static int show_one(
             streq(verb, "status")) {
                 /* According to LSB: "program not running" */
                 /* 0: program is running or service is OK
-                 * 1: program is dead and /var/run pid file exists
-                 * 2: program is dead and /var/lock lock file exists
+                 * 1: program is dead and /run PID file exists
+                 * 2: program is dead and /run/lock lock file exists
                  * 3: program is not running
                  * 4: program or service status is unknown
                  */
@@ -3966,163 +4019,6 @@ static int show(sd_bus *bus, char **args) {
         return ret;
 }
 
-static int append_assignment(sd_bus_message *m, const char *assignment) {
-        const char *eq;
-        char *field;
-        int r;
-
-        assert(m);
-        assert(assignment);
-
-        eq = strchr(assignment, '=');
-        if (!eq) {
-                log_error("Not an assignment: %s", assignment);
-                return -EINVAL;
-        }
-
-        field = strndupa(assignment, eq - assignment);
-        eq ++;
-
-        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        if (streq(field, "CPUAccounting") ||
-            streq(field, "MemoryAccounting") ||
-            streq(field, "BlockIOAccounting")) {
-
-                r = parse_boolean(eq);
-                if (r < 0) {
-                        log_error("Failed to parse boolean assignment %s.", assignment);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "b", r);
-
-        } else if (streq(field, "MemoryLimit")) {
-                off_t bytes;
-
-                r = parse_bytes(eq, &bytes);
-                if (r < 0) {
-                        log_error("Failed to parse bytes specification %s", assignment);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
-
-        } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
-                uint64_t u;
-
-                r = safe_atou64(eq, &u);
-                if (r < 0) {
-                        log_error("Failed to parse %s value %s.", field, eq);
-                        return -EINVAL;
-                }
-
-                r = sd_bus_message_append(m, "v", "t", u);
-
-        } else if (streq(field, "DevicePolicy"))
-                r = sd_bus_message_append(m, "v", "s", eq);
-
-        else if (streq(field, "DeviceAllow")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(ss)", 0);
-                else {
-                        const char *path, *rwm;
-                        char *e;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                rwm = e+1;
-                        } else {
-                                path = eq;
-                                rwm = "";
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
-                }
-
-        } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(st)", 0);
-                else {
-                        const char *path, *bandwidth;
-                        off_t bytes;
-                        char *e;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                bandwidth = e+1;
-                        } else {
-                                log_error("Failed to parse %s value %s.", field, eq);
-                                return -EINVAL;
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = parse_bytes(bandwidth, &bytes);
-                        if (r < 0) {
-                                log_error("Failed to parse byte value %s.", bandwidth);
-                                return -EINVAL;
-                        }
-
-                        r = sd_bus_message_append(m, "v", "a(st)", 1, path, (uint64_t) bytes);
-                }
-
-        } else if (streq(field, "BlockIODeviceWeight")) {
-
-                if (isempty(eq))
-                        r = sd_bus_message_append(m, "v", "a(st)", 0);
-                else {
-                        const char *path, *weight;
-                        uint64_t u;
-                        char *e;
-
-                        e = strchr(eq, ' ');
-                        if (e) {
-                                path = strndupa(eq, e - eq);
-                                weight = e+1;
-                        } else {
-                                log_error("Failed to parse %s value %s.", field, eq);
-                                return -EINVAL;
-                        }
-
-                        if (!path_startswith(path, "/dev")) {
-                                log_error("%s is not a device file in /dev.", path);
-                                return -EINVAL;
-                        }
-
-                        r = safe_atou64(weight, &u);
-                        if (r < 0) {
-                                log_error("Failed to parse %s value %s.", field, weight);
-                                return -EINVAL;
-                        }
-                        r = sd_bus_message_append(m, "v", "a(st)", path, u);
-                }
-
-        } else {
-                log_error("Unknown assignment %s.", assignment);
-                return -EINVAL;
-        }
-
-        if (r < 0)
-                return bus_log_create_error(r);
-
-        return 0;
-}
-
 static int set_property(sd_bus *bus, char **args) {
         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4132,11 +4028,11 @@ static int set_property(sd_bus *bus, char **args) {
 
         r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
                         "org.freedesktop.systemd1.Manager",
-                        "SetUnitProperties",
-                        &m);
+                        "SetUnitProperties");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -4157,7 +4053,7 @@ static int set_property(sd_bus *bus, char **args) {
                 if (r < 0)
                         return bus_log_create_error(r);
 
-                r = append_assignment(m, *i);
+                r = bus_append_unit_property_assignment(m, *i);
                 if (r < 0)
                         return r;
 
@@ -4386,8 +4282,8 @@ static int show_environment(sd_bus *bus, char **args) {
 
 static int switch_root(sd_bus *bus, char **args) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *init = NULL;
-        const char *root;
+        _cleanup_free_ char *cmdline_init = NULL;
+        const char *root, *init;
         unsigned l;
         int r;
 
@@ -4400,20 +4296,33 @@ static int switch_root(sd_bus *bus, char **args) {
         root = args[1];
 
         if (l >= 3)
-                init = strdup(args[2]);
+                init = args[2];
         else {
-                parse_env_file("/proc/cmdline", WHITESPACE,
-                               "init", &init,
-                               NULL);
+                r = parse_env_file("/proc/cmdline", WHITESPACE,
+                                   "init", &cmdline_init,
+                                   NULL);
+                if (r < 0)
+                        log_debug("Failed to parse /proc/cmdline: %s", strerror(-r));
 
-                if (!init)
-                        init = strdup("");
+                init = cmdline_init;
         }
 
-        if (!init)
-                return log_oom();
+        if (isempty(init))
+                init = NULL;
 
-        log_debug("switching root - root: %s; init: %s", root, init);
+        if (init) {
+                const char *root_systemd_path = NULL, *root_init_path = NULL;
+
+                root_systemd_path = strappenda(root, "/" SYSTEMD_BINARY_PATH);
+                root_init_path = strappenda3(root, "/", init);
+
+                /* If the passed init is actually the same as the
+                 * systemd binary, then let's suppress it. */
+                if (files_same(root_init_path, root_systemd_path) > 0)
+                        init = NULL;
+        }
+
+        log_debug("Switching root - root: %s; init: %s", root, strna(init));
 
         r = sd_bus_call_method(
                         bus,
@@ -4447,11 +4356,11 @@ static int set_environment(sd_bus *bus, char **args) {
 
         r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
                         "org.freedesktop.systemd1.Manager",
-                        method,
-                        &m);
+                        method);
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -4478,11 +4387,11 @@ static int import_environment(sd_bus *bus, char **args) {
 
         r = sd_bus_message_new_method_call(
                         bus,
+                        &m,
                         "org.freedesktop.systemd1",
                         "/org/freedesktop/systemd1",
                         "org.freedesktop.systemd1.Manager",
-                        "SetEnvironment",
-                        &m);
+                        "SetEnvironment");
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -4740,6 +4649,11 @@ static int enable_unit(sd_bus *bus, char **args) {
         if (r < 0)
                 return r;
 
+        /* If the operation was fully executed by the SysV compat,
+         * let's finish early */
+        if (strv_isempty(names))
+                return 0;
+
         if (!bus || avoid_bus()) {
                 if (streq(verb, "enable")) {
                         r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
@@ -4801,11 +4715,11 @@ static int enable_unit(sd_bus *bus, char **args) {
 
                 r = sd_bus_message_new_method_call(
                                 bus,
+                                &m,
                                 "org.freedesktop.systemd1",
                                 "/org/freedesktop/systemd1",
                                 "org.freedesktop.systemd1.Manager",
-                                method,
-                                &m);
+                                method);
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -5286,10 +5200,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                         if (!prop)
                                                 return log_oom();
 
-                                        if (strv_push(&arg_properties, prop) < 0) {
-                                                free(prop);
+                                        if (strv_consume(&arg_properties, prop) < 0)
                                                 return log_oom();
-                                        }
                                 }
                         }
 
@@ -5458,10 +5370,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 if (!s)
                                         return log_oom();
 
-                                if (strv_push(&arg_states, s) < 0) {
-                                        free(s);
+                                if (strv_consume(&arg_states, s) < 0)
                                         return log_oom();
-                                }
                         }
                         break;
                 }
@@ -5831,7 +5741,6 @@ static int runlevel_parse_argv(int argc, char *argv[]) {
 
                 case ARG_HELP:
                         return runlevel_help();
-                        return 0;
 
                 case '?':
                         return -EINVAL;