chiark / gitweb /
systemctl: make most operations NOPs in a chroot
[elogind.git] / src / systemctl.c
index 63e74d904a93d0cceac7c3ac3d80fd17080b3b70..eab4bf30c4baddef1d4e0a7a406435eca790b95f 100644 (file)
@@ -108,6 +108,12 @@ static enum dot {
         DOT_ORDER,
         DOT_REQUIRE
 } arg_dot = DOT_ALL;
+static enum transport {
+        TRANSPORT_NORMAL,
+        TRANSPORT_SSH,
+        TRANSPORT_POLKIT
+} arg_transport = TRANSPORT_NORMAL;
+static const char *arg_host = NULL;
 
 static bool private_bus = false;
 
@@ -381,7 +387,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
         if (on_tty()) {
                 printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD",
                        active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
-                if (columns() >= 80+12 || arg_full)
+                if (columns() >= 80+12 || arg_full || !arg_no_pager)
                         printf(" %s\n", "DESCRIPTION");
                 else
                         printf("\n");
@@ -434,7 +440,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                         if (u->job_id == 0)
                                 printf(" %-*s", job_len, "");
 
-                        if (arg_full)
+                        if (arg_full || !arg_no_pager)
                                 printf(" %s", u->description);
                         else
                                 printf(" %.*s", columns() - a - b - 1, u->description);
@@ -1414,7 +1420,8 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
 
         if (arg_action == ACTION_SYSTEMCTL) {
                 method =
-                        streq(args[0], "stop")                  ? "StopUnit" :
+                        streq(args[0], "stop") ||
+                        streq(args[0], "condstop")              ? "StopUnit" :
                         streq(args[0], "reload")                ? "ReloadUnit" :
                         streq(args[0], "restart")               ? "RestartUnit" :
 
@@ -1831,6 +1838,9 @@ typedef struct UnitStatusInfo {
 
         int exit_code, exit_status;
 
+        usec_t condition_timestamp;
+        bool condition_result;
+
         /* Socket */
         unsigned n_accepted;
         unsigned n_connections;
@@ -1922,6 +1932,16 @@ static void print_status_info(UnitStatusInfo *i) {
         else
                 printf("\n");
 
+        if (!i->condition_result && i->condition_timestamp > 0) {
+                s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
+                s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
+
+                if (s1)
+                        printf("\t          start condition failed at %s; %s\n", s2, s1);
+                else if (s2)
+                        printf("\t          start condition failed at %s\n", s2);
+        }
+
         if (i->sysfs_path)
                 printf("\t  Device: %s\n", i->sysfs_path);
         if (i->where)
@@ -2048,12 +2068,14 @@ static void print_status_info(UnitStatusInfo *i) {
 
                 printf("\t  CGroup: %s\n", i->default_control_group);
 
-                if ((c = columns()) > 18)
-                        c -= 18;
-                else
-                        c = 0;
+                if (arg_transport != TRANSPORT_SSH) {
+                        if ((c = columns()) > 18)
+                                c -= 18;
+                        else
+                                c = 0;
 
-                show_cgroup_by_path(i->default_control_group, "\t\t  ", c);
+                        show_cgroup_by_path(i->default_control_group, "\t\t  ", c);
+                }
         }
 
         if (i->need_daemon_reload)
@@ -2117,6 +2139,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                         i->accept = b;
                 else if (streq(name, "NeedDaemonReload"))
                         i->need_daemon_reload = b;
+                else if (streq(name, "ConditionResult"))
+                        i->condition_result = b;
 
                 break;
         }
@@ -2174,6 +2198,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
                         i->inactive_exit_timestamp = (usec_t) u;
                 else if (streq(name, "ActiveExitTimestamp"))
                         i->active_exit_timestamp = (usec_t) u;
+                else if (streq(name, "ConditionTimestamp"))
+                        i->condition_timestamp = (usec_t) u;
 
                 break;
         }
@@ -3583,6 +3609,7 @@ static int config_parse_also(
                 unsigned line,
                 const char *section,
                 const char *lvalue,
+                int ltype,
                 const char *rvalue,
                 void *data,
                 void *userdata) {
@@ -3997,11 +4024,11 @@ finish:
 static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo *i, const char *config_path) {
 
         const ConfigItem items[] = {
-                { "Alias",    config_parse_strv, &i->aliases,   "Install" },
-                { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
-                { "Also",     config_parse_also, NULL,          "Install" },
+                { "Alias",    config_parse_strv, 0, &i->aliases,   "Install" },
+                { "WantedBy", config_parse_strv, 0, &i->wanted_by, "Install" },
+                { "Also",     config_parse_also, 0, NULL,          "Install" },
 
-                { NULL, NULL, NULL, NULL }
+                { NULL, NULL, 0, NULL, NULL }
         };
 
         char **p;
@@ -4072,7 +4099,7 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
                                 argv[1] = file_name_from_path(sysv);
                                 argv[2] =
                                         streq(verb, "enable") ? "on" :
-                                        streq(verb, "disable") ? "off" : "--level=3";
+                                        streq(verb, "disable") ? "off" : "--level=5";
 
                                 log_info("Executing %s %s %s", argv[0], argv[1], strempty(argv[2]));
 
@@ -4273,22 +4300,25 @@ static int systemctl_help(void) {
                "                      pending\n"
                "     --ignore-dependencies\n"
                "                      When queueing a new job, ignore all its dependencies\n"
+               "     --kill-mode=MODE How to send signal\n"
+               "     --kill-who=WHO   Who to send signal to\n"
+               "  -s --signal=SIGNAL  Which signal to send\n"
+               "  -H --host=[user@]host\n"
+               "                      Show information for remote host\n"
+               "  -P --privileged     Acquire privileges before execution\n"
                "  -q --quiet          Suppress output\n"
                "     --no-block       Do not wait until operation finished\n"
-               "     --no-pager       Do not pipe output into a pager.\n"
-               "     --system         Connect to system manager\n"
-               "     --user           Connect to user service manager\n"
-               "     --order          When generating graph for dot, show only order\n"
-               "     --require        When generating graph for dot, show only requirement\n"
                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
-               "     --global         Enable/disable unit files globally\n"
                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
                "                      configuration\n"
+               "     --no-pager       Do not pipe output into a pager.\n"
                "     --no-ask-password\n"
                "                      Do not ask for system passwords\n"
-               "     --kill-mode=MODE How to send signal\n"
-               "     --kill-who=WHO   Who to send signal to\n"
-               "  -s --signal=SIGNAL  Which signal to send\n"
+               "     --order          When generating graph for dot, show only order\n"
+               "     --require        When generating graph for dot, show only requirement\n"
+               "     --system         Connect to system manager\n"
+               "     --user           Connect to user service manager\n"
+               "     --global         Enable/disable unit files globally\n"
                "  -f --force          When enabling unit files, override existing symlinks\n"
                "                      When shutting down, execute action immediately\n"
                "     --defaults       When disabling unit files, remove default symlinks only\n\n"
@@ -4455,6 +4485,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
                 { "signal",    required_argument, NULL, 's'           },
                 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
+                { "host",      required_argument, NULL, 'H'           },
+                { "privileged",no_argument,       NULL, 'P'           },
                 { NULL,        0,                 NULL, 0             }
         };
 
@@ -4466,7 +4498,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         /* Only when running as systemctl we ask for passwords */
         arg_ask_password = true;
 
-        while ((c = getopt_long(argc, argv, "ht:p:aqfs:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:P", options, NULL)) >= 0) {
 
                 switch (c) {
 
@@ -4588,6 +4620,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_ask_password = false;
                         break;
 
+                case 'P':
+                        arg_transport = TRANSPORT_POLKIT;
+                        break;
+
+                case 'H':
+                        arg_transport = TRANSPORT_SSH;
+                        arg_host = optarg;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -4597,6 +4638,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 }
         }
 
+        if (arg_transport != TRANSPORT_NORMAL && arg_user) {
+                log_error("Cannot access user instance remotely.");
+                return -EINVAL;
+        }
+
         return 1;
 }
 
@@ -5191,6 +5237,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                 { "cancel",                MORE,  2, cancel_job        },
                 { "start",                 MORE,  2, start_unit        },
                 { "stop",                  MORE,  2, start_unit        },
+                { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
                 { "reload",                MORE,  2, start_unit        },
                 { "restart",               MORE,  2, start_unit        },
                 { "try-restart",           MORE,  2, start_unit        },
@@ -5289,11 +5336,17 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
 
         /* Require a bus connection for all operations but
          * enable/disable */
-        if (!streq(verbs[i].verb, "enable") &&
-            !streq(verbs[i].verb, "disable") &&
-            !bus) {
-                log_error("Failed to get D-Bus connection: %s", error->message);
-                return -EIO;
+        if (!streq(verbs[i].verb, "enable") && !streq(verbs[i].verb, "disable")) {
+
+                if (running_in_chroot() > 0) {
+                        log_info("Running in chroot, ignoring request.");
+                        return 0;
+                }
+
+                if (!bus) {
+                        log_error("Failed to get D-Bus connection: %s", error->message);
+                        return -EIO;
+                }
         }
 
         return verbs[i].dispatch(bus, argv + optind, left);
@@ -5320,7 +5373,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
         zero(sockaddr);
         sockaddr.sa.sa_family = AF_UNIX;
         sockaddr.un.sun_path[0] = 0;
-        strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1);
+        strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
 
         zero(iovec);
         iovec.iov_base = (char*) &c;
@@ -5328,7 +5381,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
 
         zero(msghdr);
         msghdr.msg_name = &sockaddr;
-        msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
+        msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
 
         msghdr.msg_iov = &iovec;
         msghdr.msg_iovlen = 1;
@@ -5605,7 +5658,22 @@ int main(int argc, char*argv[]) {
                 goto finish;
         }
 
-        bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
+        if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
+                log_info("Running in chroot, ignoring request.");
+                retval = 0;
+                goto finish;
+        }
+
+        if (arg_transport == TRANSPORT_NORMAL)
+                bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
+        else if (arg_transport == TRANSPORT_POLKIT) {
+                bus_connect_system_polkit(&bus, &error);
+                private_bus = false;
+        } else if (arg_transport == TRANSPORT_SSH) {
+                bus_connect_system_ssh(NULL, arg_host, &bus, &error);
+                private_bus = false;
+        } else
+                assert_not_reached("Uh, invalid transport...");
 
         switch (arg_action) {