chiark / gitweb /
machinectl: given that machinectl invokes a number of polkit enabled methods, start...
[elogind.git] / src / machine / machinectl.c
index c80114cde831b84f22aa2194c2983ea46c77fb50..2c29f1495eb3d47f7a23001099fc3c7e1afba14d 100644 (file)
 #include "util.h"
 #include "macro.h"
 #include "pager.h"
+#include "spawn-polkit-agent.h"
 #include "bus-util.h"
 #include "bus-error.h"
 #include "build.h"
 #include "strv.h"
 #include "unit-name.h"
 #include "cgroup-show.h"
+#include "logs-show.h"
 #include "cgroup-util.h"
 #include "ptyfwd.h"
 #include "event-util.h"
@@ -64,6 +66,9 @@ static char *arg_host = NULL;
 static bool arg_read_only = false;
 static bool arg_mkdir = false;
 static bool arg_quiet = false;
+static bool arg_ask_password = true;
+static unsigned arg_lines = 10;
+static OutputMode arg_output = OUTPUT_SHORT;
 
 static void pager_open_if_enabled(void) {
 
@@ -74,6 +79,28 @@ static void pager_open_if_enabled(void) {
         pager_open(false);
 }
 
+static void polkit_agent_open_if_enabled(void) {
+
+        /* Open the polkit agent as a child process if necessary */
+
+        if (!arg_ask_password)
+                return;
+
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return;
+
+        polkit_agent_open();
+}
+
+static OutputFlags get_output_flags(void) {
+        return
+                arg_all * OUTPUT_SHOW_ALL |
+                arg_full * OUTPUT_FULL_WIDTH |
+                (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
+                on_tty() * OUTPUT_COLOR |
+                !arg_quiet * OUTPUT_WARN_CUTOFF;
+}
+
 typedef struct MachineInfo {
         const char *name;
         const char *class;
@@ -305,7 +332,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_free_ char *path = NULL;
         const char *cgroup;
-        int r, output_flags;
+        int r;
         unsigned c;
 
         assert(bus);
@@ -342,17 +369,13 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
         if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
                 return 0;
 
-        output_flags =
-                arg_all * OUTPUT_SHOW_ALL |
-                arg_full * OUTPUT_FULL_WIDTH;
-
         c = columns();
         if (c > 18)
                 c -= 18;
         else
                 c = 0;
 
-        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, output_flags);
+        show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, get_output_flags());
         return 0;
 }
 
@@ -467,7 +490,7 @@ typedef struct MachineStatusInfo {
         char *unit;
         char *root_directory;
         pid_t leader;
-        usec_t timestamp;
+        struct dual_timestamp timestamp;
         int *netif;
         unsigned n_netif;
 } MachineStatusInfo;
@@ -487,8 +510,8 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
         else
                 putchar('\n');
 
-        s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
-        s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
+        s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
+        s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
 
         if (s1)
                 printf("\t   Since: %s; %s\n", s2, s1);
@@ -552,6 +575,22 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
         if (i->unit) {
                 printf("\t    Unit: %s\n", i->unit);
                 show_unit_cgroup(bus, i->unit, i->leader);
+
+                if (arg_transport == BUS_TRANSPORT_LOCAL) {
+
+                        show_journal_by_unit(
+                                        stdout,
+                                        i->unit,
+                                        arg_output,
+                                        0,
+                                        i->timestamp.monotonic,
+                                        arg_lines,
+                                        0,
+                                        get_output_flags() | OUTPUT_BEGIN_NEWLINE,
+                                        SD_JOURNAL_LOCAL_ONLY,
+                                        true,
+                                        NULL);
+                }
         }
 }
 
@@ -579,15 +618,16 @@ static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
 static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
 
         static const struct bus_properties_map map[]  = {
-                { "Name",              "s",  NULL,          offsetof(MachineStatusInfo, name) },
-                { "Class",             "s",  NULL,          offsetof(MachineStatusInfo, class) },
-                { "Service",           "s",  NULL,          offsetof(MachineStatusInfo, service) },
-                { "Unit",              "s",  NULL,          offsetof(MachineStatusInfo, unit) },
-                { "RootDirectory",     "s",  NULL,          offsetof(MachineStatusInfo, root_directory) },
-                { "Leader",            "u",  NULL,          offsetof(MachineStatusInfo, leader) },
-                { "Timestamp",         "t",  NULL,          offsetof(MachineStatusInfo, timestamp) },
-                { "Id",                "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
-                { "NetworkInterfaces", "ai", map_netif,     0 },
+                { "Name",               "s",  NULL,          offsetof(MachineStatusInfo, name)                },
+                { "Class",              "s",  NULL,          offsetof(MachineStatusInfo, class)               },
+                { "Service",            "s",  NULL,          offsetof(MachineStatusInfo, service)             },
+                { "Unit",               "s",  NULL,          offsetof(MachineStatusInfo, unit)                },
+                { "RootDirectory",      "s",  NULL,          offsetof(MachineStatusInfo, root_directory)      },
+                { "Leader",             "u",  NULL,          offsetof(MachineStatusInfo, leader)              },
+                { "Timestamp",          "t",  NULL,          offsetof(MachineStatusInfo, timestamp.realtime)  },
+                { "TimestampMonotonic", "t",  NULL,          offsetof(MachineStatusInfo, timestamp.monotonic) },
+                { "Id",                 "ay", bus_map_id128, offsetof(MachineStatusInfo, id)                  },
+                { "NetworkInterfaces",  "ai", map_netif,     0                                                },
                 {}
         };
 
@@ -886,6 +926,8 @@ static int kill_machine(int argc, char *argv[], void *userdata) {
 
         assert(bus);
 
+        polkit_agent_open_if_enabled();
+
         if (!arg_kill_who)
                 arg_kill_who = "all";
 
@@ -931,6 +973,8 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
 
         assert(bus);
 
+        polkit_agent_open_if_enabled();
+
         for (i = 1; i < argc; i++) {
                 int r;
 
@@ -1320,6 +1364,8 @@ static int login_machine(int argc, char *argv[], void *userdata) {
                 return -ENOTSUP;
         }
 
+        polkit_agent_open_if_enabled();
+
         r = sd_event_default(&event);
         if (r < 0)
                 return log_error_errno(r, "Failed to get event loop: %m");
@@ -1350,7 +1396,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = sd_bus_message_set_allow_interactive_authorization(m, true);
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1409,6 +1455,8 @@ static int remove_image(int argc, char *argv[], void *userdata) {
 
         assert(bus);
 
+        polkit_agent_open_if_enabled();
+
         for (i = 1; i < argc; i++) {
                 r = sd_bus_call_method(
                                 bus,
@@ -1433,6 +1481,8 @@ static int rename_image(int argc, char *argv[], void *userdata) {
         sd_bus *bus = userdata;
         int r;
 
+        polkit_agent_open_if_enabled();
+
         r = sd_bus_call_method(
                         bus,
                         "org.freedesktop.machine1",
@@ -1455,6 +1505,8 @@ static int clone_image(int argc, char *argv[], void *userdata) {
         sd_bus *bus = userdata;
         int r;
 
+        polkit_agent_open_if_enabled();
+
         r = sd_bus_call_method(
                         bus,
                         "org.freedesktop.machine1",
@@ -1485,6 +1537,8 @@ static int read_only_image(int argc, char *argv[], void *userdata) {
                 }
         }
 
+        polkit_agent_open_if_enabled();
+
         r = sd_bus_call_method(
                         bus,
                         "org.freedesktop.machine1",
@@ -1510,6 +1564,8 @@ static int start_machine(int argc, char *argv[], void *userdata) {
 
         assert(bus);
 
+        polkit_agent_open_if_enabled();
+
         r = bus_wait_for_jobs_new(bus, &w);
         if (r < 0)
                 return log_oom();
@@ -1542,7 +1598,7 @@ static int start_machine(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return bus_log_create_error(r);
 
-                r = sd_bus_message_set_allow_interactive_authorization(m, true);
+                r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
                 if (r < 0)
                         return bus_log_create_error(r);
 
@@ -1582,6 +1638,8 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
 
         assert(bus);
 
+        polkit_agent_open_if_enabled();
+
         method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
 
         r = sd_bus_message_new_method_call(
@@ -1594,7 +1652,7 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = sd_bus_message_set_allow_interactive_authorization(m, true);
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1662,7 +1720,7 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        r = sd_bus_message_set_allow_interactive_authorization(m, true);
+        r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
         if (r < 0)
                 return bus_log_create_error(r);
 
@@ -1684,6 +1742,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --version                Show package version\n"
                "     --no-pager               Do not pipe output into a pager\n"
                "     --no-legend              Do not show the headers and footers\n"
+               "     --no-ask-password        Do not ask for system passwords\n"
                "  -H --host=[USER@]HOST       Operate on remote host\n"
                "  -M --machine=CONTAINER      Operate on local container\n"
                "  -p --property=NAME          Show only properties by this name\n"
@@ -1693,7 +1752,11 @@ static int help(int argc, char *argv[], void *userdata) {
                "     --kill-who=WHO           Who to send signal to\n"
                "  -s --signal=SIGNAL          Which signal to send\n"
                "     --read-only              Create read-only bind mount\n"
-               "     --mkdir                  Create directory before bind mounting, if missing\n\n"
+               "     --mkdir                  Create directory before bind mounting, if missing\n"
+               "  -n --lines=INTEGER          Number of journal entries to show\n"
+               "  -o --output=STRING          Change journal output mode (short,\n"
+               "                              short-monotonic, verbose, export, json,\n"
+               "                              json-pretty, json-sse, cat)\n\n"
                "Machine Commands:\n"
                "  list                        List running VMs and containers\n"
                "  status NAME...              Show VM/container details\n"
@@ -1731,6 +1794,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_KILL_WHO,
                 ARG_READ_ONLY,
                 ARG_MKDIR,
+                ARG_NO_ASK_PASSWORD,
         };
 
         static const struct option options[] = {
@@ -1748,6 +1812,9 @@ static int parse_argv(int argc, char *argv[]) {
                 { "read-only",       no_argument,       NULL, ARG_READ_ONLY       },
                 { "mkdir",           no_argument,       NULL, ARG_MKDIR           },
                 { "quiet",           no_argument,       NULL, 'q'                 },
+                { "lines",           required_argument, NULL, 'n'                 },
+                { "output",          required_argument, NULL, 'o'                 },
+                { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
                 {}
         };
 
@@ -1756,7 +1823,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hp:als:H:M:q", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -1787,6 +1854,21 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_full = true;
                         break;
 
+                case 'n':
+                        if (safe_atou(optarg, &arg_lines) < 0) {
+                                log_error("Failed to parse lines '%s'", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
+                case 'o':
+                        arg_output = output_mode_from_string(optarg);
+                        if (arg_output < 0) {
+                                log_error("Unknown output '%s'.", optarg);
+                                return -EINVAL;
+                        }
+                        break;
+
                 case ARG_NO_PAGER:
                         arg_no_pager = true;
                         break;
@@ -1807,6 +1889,10 @@ static int parse_argv(int argc, char *argv[]) {
                         }
                         break;
 
+                case ARG_NO_ASK_PASSWORD:
+                        arg_ask_password = false;
+                        break;
+
                 case 'H':
                         arg_transport = BUS_TRANSPORT_REMOTE;
                         arg_host = optarg;
@@ -1892,6 +1978,7 @@ int main(int argc, char*argv[]) {
 
 finish:
         pager_close();
+        polkit_agent_close();
 
         strv_free(arg_property);