LCOV - code coverage report
Current view: top level - login - loginctl.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 29 699 4.1 %
Date: 2019-08-22 15:41:25 Functions: 5 34 14.7 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <getopt.h>
       5             : #include <locale.h>
       6             : #include <string.h>
       7             : #include <unistd.h>
       8             : 
       9             : #include "sd-bus.h"
      10             : 
      11             : #include "alloc-util.h"
      12             : #include "bus-error.h"
      13             : #include "bus-unit-procs.h"
      14             : #include "bus-util.h"
      15             : #include "cgroup-show.h"
      16             : #include "cgroup-util.h"
      17             : #include "format-table.h"
      18             : #include "log.h"
      19             : #include "logs-show.h"
      20             : #include "macro.h"
      21             : #include "main-func.h"
      22             : #include "memory-util.h"
      23             : #include "pager.h"
      24             : #include "parse-util.h"
      25             : #include "pretty-print.h"
      26             : #include "process-util.h"
      27             : #include "rlimit-util.h"
      28             : #include "sigbus.h"
      29             : #include "signal-util.h"
      30             : #include "spawn-polkit-agent.h"
      31             : #include "string-table.h"
      32             : #include "strv.h"
      33             : #include "sysfs-show.h"
      34             : #include "terminal-util.h"
      35             : #include "unit-name.h"
      36             : #include "user-util.h"
      37             : #include "verbs.h"
      38             : 
      39             : static char **arg_property = NULL;
      40             : static bool arg_all = false;
      41             : static bool arg_value = false;
      42             : static bool arg_full = false;
      43             : static PagerFlags arg_pager_flags = 0;
      44             : static bool arg_legend = true;
      45             : static const char *arg_kill_who = NULL;
      46             : static int arg_signal = SIGTERM;
      47             : static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
      48             : static char *arg_host = NULL;
      49             : static bool arg_ask_password = true;
      50             : static unsigned arg_lines = 10;
      51             : static OutputMode arg_output = OUTPUT_SHORT;
      52             : 
      53           4 : STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
      54             : 
      55           0 : static OutputFlags get_output_flags(void) {
      56             : 
      57             :         return
      58           0 :                 arg_all * OUTPUT_SHOW_ALL |
      59           0 :                 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
      60           0 :                 colors_enabled() * OUTPUT_COLOR;
      61             : }
      62             : 
      63           0 : static int get_session_path(sd_bus *bus, const char *session_id, sd_bus_error *error, char **path) {
      64           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
      65             :         int r;
      66             :         char *ans;
      67             : 
      68           0 :         r = sd_bus_call_method(
      69             :                         bus,
      70             :                         "org.freedesktop.login1",
      71             :                         "/org/freedesktop/login1",
      72             :                         "org.freedesktop.login1.Manager",
      73             :                         "GetSession",
      74             :                         error, &reply,
      75             :                         "s", session_id);
      76           0 :         if (r < 0)
      77           0 :                 return r;
      78             : 
      79           0 :         r = sd_bus_message_read(reply, "o", &ans);
      80           0 :         if (r < 0)
      81           0 :                 return r;
      82             : 
      83           0 :         ans = strdup(ans);
      84           0 :         if (!ans)
      85           0 :                 return -ENOMEM;
      86             : 
      87           0 :         *path = ans;
      88           0 :         return 0;
      89             : }
      90             : 
      91           0 : static int show_table(Table *table, const char *word) {
      92             :         int r;
      93             : 
      94           0 :         assert(table);
      95           0 :         assert(word);
      96             : 
      97           0 :         if (table_get_rows(table) > 1 || OUTPUT_MODE_IS_JSON(arg_output)) {
      98           0 :                 r = table_set_sort(table, (size_t) 0, (size_t) -1);
      99           0 :                 if (r < 0)
     100           0 :                         return log_error_errno(r, "Failed to sort table: %m");
     101             : 
     102           0 :                 table_set_header(table, arg_legend);
     103             : 
     104           0 :                 if (OUTPUT_MODE_IS_JSON(arg_output))
     105           0 :                         r = table_print_json(table, NULL, output_mode_to_json_format_flags(arg_output) | JSON_FORMAT_COLOR_AUTO);
     106             :                 else
     107           0 :                         r = table_print(table, NULL);
     108           0 :                 if (r < 0)
     109           0 :                         return log_error_errno(r, "Failed to show table: %m");
     110             :         }
     111             : 
     112           0 :         if (arg_legend) {
     113           0 :                 if (table_get_rows(table) > 1)
     114           0 :                         printf("\n%zu %s listed.\n", table_get_rows(table) - 1, word);
     115             :                 else
     116           0 :                         printf("No %s.\n", word);
     117             :         }
     118             : 
     119           0 :         return 0;
     120             : }
     121             : 
     122           0 : static int list_sessions(int argc, char *argv[], void *userdata) {
     123           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     124           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     125           0 :         _cleanup_(table_unrefp) Table *table = NULL;
     126           0 :         sd_bus *bus = userdata;
     127             :         int r;
     128             : 
     129           0 :         assert(bus);
     130           0 :         assert(argv);
     131             : 
     132           0 :         (void) pager_open(arg_pager_flags);
     133             : 
     134           0 :         r = sd_bus_call_method(
     135             :                         bus,
     136             :                         "org.freedesktop.login1",
     137             :                         "/org/freedesktop/login1",
     138             :                         "org.freedesktop.login1.Manager",
     139             :                         "ListSessions",
     140             :                         &error, &reply,
     141             :                         NULL);
     142           0 :         if (r < 0)
     143           0 :                 return log_error_errno(r, "Failed to list sessions: %s", bus_error_message(&error, r));
     144             : 
     145           0 :         r = sd_bus_message_enter_container(reply, 'a', "(susso)");
     146           0 :         if (r < 0)
     147           0 :                 return bus_log_parse_error(r);
     148             : 
     149           0 :         table = table_new("session", "uid", "user", "seat", "tty");
     150           0 :         if (!table)
     151           0 :                 return log_oom();
     152             : 
     153             :         /* Right-align the first two fields (since they are numeric) */
     154           0 :         (void) table_set_align_percent(table, TABLE_HEADER_CELL(0), 100);
     155           0 :         (void) table_set_align_percent(table, TABLE_HEADER_CELL(1), 100);
     156             : 
     157           0 :         for (;;) {
     158           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error_tty = SD_BUS_ERROR_NULL;
     159           0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_tty = NULL;
     160           0 :                 const char *id, *user, *seat, *object, *tty = NULL;
     161             :                 uint32_t uid;
     162             : 
     163           0 :                 r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object);
     164           0 :                 if (r < 0)
     165           0 :                         return bus_log_parse_error(r);
     166           0 :                 if (r == 0)
     167           0 :                         break;
     168             : 
     169           0 :                 r = sd_bus_get_property(
     170             :                                 bus,
     171             :                                 "org.freedesktop.login1",
     172             :                                 object,
     173             :                                 "org.freedesktop.login1.Session",
     174             :                                 "TTY",
     175             :                                 &error_tty,
     176             :                                 &reply_tty,
     177             :                                 "s");
     178           0 :                 if (r < 0)
     179           0 :                         log_warning_errno(r, "Failed to get TTY for session %s: %s", id, bus_error_message(&error_tty, r));
     180             :                 else {
     181           0 :                         r = sd_bus_message_read(reply_tty, "s", &tty);
     182           0 :                         if (r < 0)
     183           0 :                                 return bus_log_parse_error(r);
     184             :                 }
     185             : 
     186           0 :                 r = table_add_many(table,
     187             :                                    TABLE_STRING, id,
     188             :                                    TABLE_UINT32, uid,
     189             :                                    TABLE_STRING, user,
     190             :                                    TABLE_STRING, seat,
     191             :                                    TABLE_STRING, strna(tty));
     192           0 :                 if (r < 0)
     193           0 :                         return log_error_errno(r, "Failed to add row to table: %m");
     194             :         }
     195             : 
     196           0 :         r = sd_bus_message_exit_container(reply);
     197           0 :         if (r < 0)
     198           0 :                 return bus_log_parse_error(r);
     199             : 
     200           0 :         return show_table(table, "sessions");
     201             : }
     202             : 
     203           0 : static int list_users(int argc, char *argv[], void *userdata) {
     204           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     205           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     206           0 :         _cleanup_(table_unrefp) Table *table = NULL;
     207           0 :         sd_bus *bus = userdata;
     208             :         int r;
     209             : 
     210           0 :         assert(bus);
     211           0 :         assert(argv);
     212             : 
     213           0 :         (void) pager_open(arg_pager_flags);
     214             : 
     215           0 :         r = sd_bus_call_method(
     216             :                         bus,
     217             :                         "org.freedesktop.login1",
     218             :                         "/org/freedesktop/login1",
     219             :                         "org.freedesktop.login1.Manager",
     220             :                         "ListUsers",
     221             :                         &error, &reply,
     222             :                         NULL);
     223           0 :         if (r < 0)
     224           0 :                 return log_error_errno(r, "Failed to list users: %s", bus_error_message(&error, r));
     225             : 
     226           0 :         r = sd_bus_message_enter_container(reply, 'a', "(uso)");
     227           0 :         if (r < 0)
     228           0 :                 return bus_log_parse_error(r);
     229             : 
     230           0 :         table = table_new("uid", "user");
     231           0 :         if (!table)
     232           0 :                 return log_oom();
     233             : 
     234           0 :         (void) table_set_align_percent(table, TABLE_HEADER_CELL(0), 100);
     235             : 
     236           0 :         for (;;) {
     237             :                 const char *user;
     238             :                 uint32_t uid;
     239             : 
     240           0 :                 r = sd_bus_message_read(reply, "(uso)", &uid, &user, NULL);
     241           0 :                 if (r < 0)
     242           0 :                         return bus_log_parse_error(r);
     243           0 :                 if (r == 0)
     244           0 :                         break;
     245             : 
     246           0 :                 r = table_add_many(table,
     247             :                                    TABLE_UINT32, uid,
     248             :                                    TABLE_STRING, user);
     249           0 :                 if (r < 0)
     250           0 :                         return log_error_errno(r, "Failed to add row to table: %m");
     251             :         }
     252             : 
     253           0 :         r = sd_bus_message_exit_container(reply);
     254           0 :         if (r < 0)
     255           0 :                 return bus_log_parse_error(r);
     256             : 
     257           0 :         return show_table(table, "users");
     258             : }
     259             : 
     260           0 : static int list_seats(int argc, char *argv[], void *userdata) {
     261           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     262           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     263           0 :         _cleanup_(table_unrefp) Table *table = NULL;
     264           0 :         sd_bus *bus = userdata;
     265             :         int r;
     266             : 
     267           0 :         assert(bus);
     268           0 :         assert(argv);
     269             : 
     270           0 :         (void) pager_open(arg_pager_flags);
     271             : 
     272           0 :         r = sd_bus_call_method(
     273             :                         bus,
     274             :                         "org.freedesktop.login1",
     275             :                         "/org/freedesktop/login1",
     276             :                         "org.freedesktop.login1.Manager",
     277             :                         "ListSeats",
     278             :                         &error, &reply,
     279             :                         NULL);
     280           0 :         if (r < 0)
     281           0 :                 return log_error_errno(r, "Failed to list seats: %s", bus_error_message(&error, r));
     282             : 
     283           0 :         r = sd_bus_message_enter_container(reply, 'a', "(so)");
     284           0 :         if (r < 0)
     285           0 :                 return bus_log_parse_error(r);
     286             : 
     287           0 :         table = table_new("seat");
     288           0 :         if (!table)
     289           0 :                 return log_oom();
     290             : 
     291           0 :         for (;;) {
     292             :                 const char *seat;
     293             : 
     294           0 :                 r = sd_bus_message_read(reply, "(so)", &seat, NULL);
     295           0 :                 if (r < 0)
     296           0 :                         return bus_log_parse_error(r);
     297           0 :                 if (r == 0)
     298           0 :                         break;
     299             : 
     300           0 :                 r = table_add_cell(table, NULL, TABLE_STRING, seat);
     301           0 :                 if (r < 0)
     302           0 :                         return log_error_errno(r, "Failed to add row to table: %m");
     303             :         }
     304             : 
     305           0 :         r = sd_bus_message_exit_container(reply);
     306           0 :         if (r < 0)
     307           0 :                 return bus_log_parse_error(r);
     308             : 
     309           0 :         return show_table(table, "seats");
     310             : }
     311             : 
     312           0 : static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
     313           0 :         _cleanup_free_ char *cgroup = NULL;
     314           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     315             :         unsigned c;
     316             :         int r;
     317             : 
     318           0 :         assert(bus);
     319           0 :         assert(unit);
     320             : 
     321           0 :         r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
     322           0 :         if (r < 0)
     323           0 :                 return r;
     324             : 
     325           0 :         if (isempty(cgroup))
     326           0 :                 return 0;
     327             : 
     328           0 :         c = columns();
     329           0 :         if (c > 18)
     330           0 :                 c -= 18;
     331             :         else
     332           0 :                 c = 0;
     333             : 
     334           0 :         r = unit_show_processes(bus, unit, cgroup, "\t\t  ", c, get_output_flags(), &error);
     335           0 :         if (r == -EBADR) {
     336             : 
     337           0 :                 if (arg_transport == BUS_TRANSPORT_REMOTE)
     338           0 :                         return 0;
     339             : 
     340             :                 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
     341             : 
     342           0 :                 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
     343           0 :                         return 0;
     344             : 
     345           0 :                 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, &leader, leader > 0, get_output_flags());
     346           0 :         } else if (r < 0)
     347           0 :                 return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
     348             : 
     349           0 :         return 0;
     350             : }
     351             : 
     352             : typedef struct SessionStatusInfo {
     353             :         const char *id;
     354             :         uid_t uid;
     355             :         const char *name;
     356             :         struct dual_timestamp timestamp;
     357             :         unsigned vtnr;
     358             :         const char *seat;
     359             :         const char *tty;
     360             :         const char *display;
     361             :         bool remote;
     362             :         const char *remote_host;
     363             :         const char *remote_user;
     364             :         const char *service;
     365             :         pid_t leader;
     366             :         const char *type;
     367             :         const char *class;
     368             :         const char *state;
     369             :         const char *scope;
     370             :         const char *desktop;
     371             : } SessionStatusInfo;
     372             : 
     373             : typedef struct UserStatusInfo {
     374             :         uid_t uid;
     375             :         bool linger;
     376             :         const char *name;
     377             :         struct dual_timestamp timestamp;
     378             :         const char *state;
     379             :         char **sessions;
     380             :         const char *display;
     381             :         const char *slice;
     382             : } UserStatusInfo;
     383             : 
     384             : typedef struct SeatStatusInfo {
     385             :         const char *id;
     386             :         const char *active_session;
     387             :         char **sessions;
     388             : } SeatStatusInfo;
     389             : 
     390           0 : static void user_status_info_clear(UserStatusInfo *info) {
     391           0 :         if (info) {
     392           0 :                 strv_free(info->sessions);
     393           0 :                 zero(*info);
     394             :         }
     395           0 : }
     396             : 
     397           0 : static void seat_status_info_clear(SeatStatusInfo *info) {
     398           0 :         if (info) {
     399           0 :                 strv_free(info->sessions);
     400           0 :                 zero(*info);
     401             :         }
     402           0 : }
     403             : 
     404           0 : static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
     405             :         const char *contents;
     406             :         int r;
     407             : 
     408           0 :         r = sd_bus_message_peek_type(m, NULL, &contents);
     409           0 :         if (r < 0)
     410           0 :                 return r;
     411             : 
     412           0 :         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
     413           0 :         if (r < 0)
     414           0 :                 return r;
     415             : 
     416           0 :         r = sd_bus_message_read_basic(m, contents[0], userdata);
     417           0 :         if (r < 0)
     418           0 :                 return r;
     419             : 
     420           0 :         r = sd_bus_message_skip(m, contents+1);
     421           0 :         if (r < 0)
     422           0 :                 return r;
     423             : 
     424           0 :         r = sd_bus_message_exit_container(m);
     425           0 :         if (r < 0)
     426           0 :                 return r;
     427             : 
     428           0 :         return 0;
     429             : }
     430             : 
     431           0 : static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
     432             :         const char *name;
     433             :         int r;
     434             : 
     435           0 :         assert(bus);
     436           0 :         assert(m);
     437             : 
     438           0 :         r = sd_bus_message_enter_container(m, 'a', "(so)");
     439           0 :         if (r < 0)
     440           0 :                 return r;
     441             : 
     442           0 :         while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
     443           0 :                 r = strv_extend(userdata, name);
     444           0 :                 if (r < 0)
     445           0 :                         return r;
     446             :         }
     447           0 :         if (r < 0)
     448           0 :                 return r;
     449             : 
     450           0 :         return sd_bus_message_exit_container(m);
     451             : }
     452             : 
     453           0 : static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
     454             : 
     455             :         static const struct bus_properties_map map[]  = {
     456             :                 { "Id",                  "s",    NULL,                     offsetof(SessionStatusInfo, id)                  },
     457             :                 { "Name",                "s",    NULL,                     offsetof(SessionStatusInfo, name)                },
     458             :                 { "TTY",                 "s",    NULL,                     offsetof(SessionStatusInfo, tty)                 },
     459             :                 { "Display",             "s",    NULL,                     offsetof(SessionStatusInfo, display)             },
     460             :                 { "RemoteHost",          "s",    NULL,                     offsetof(SessionStatusInfo, remote_host)         },
     461             :                 { "RemoteUser",          "s",    NULL,                     offsetof(SessionStatusInfo, remote_user)         },
     462             :                 { "Service",             "s",    NULL,                     offsetof(SessionStatusInfo, service)             },
     463             :                 { "Desktop",             "s",    NULL,                     offsetof(SessionStatusInfo, desktop)             },
     464             :                 { "Type",                "s",    NULL,                     offsetof(SessionStatusInfo, type)                },
     465             :                 { "Class",               "s",    NULL,                     offsetof(SessionStatusInfo, class)               },
     466             :                 { "Scope",               "s",    NULL,                     offsetof(SessionStatusInfo, scope)               },
     467             :                 { "State",               "s",    NULL,                     offsetof(SessionStatusInfo, state)               },
     468             :                 { "VTNr",                "u",    NULL,                     offsetof(SessionStatusInfo, vtnr)                },
     469             :                 { "Leader",              "u",    NULL,                     offsetof(SessionStatusInfo, leader)              },
     470             :                 { "Remote",              "b",    NULL,                     offsetof(SessionStatusInfo, remote)              },
     471             :                 { "Timestamp",           "t",    NULL,                     offsetof(SessionStatusInfo, timestamp.realtime)  },
     472             :                 { "TimestampMonotonic",  "t",    NULL,                     offsetof(SessionStatusInfo, timestamp.monotonic) },
     473             :                 { "User",                "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid)                 },
     474             :                 { "Seat",                "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat)                },
     475             :                 {}
     476             :         };
     477             : 
     478           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     479           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     480             :         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
     481             :         char since2[FORMAT_TIMESTAMP_MAX];
     482             :         const char *s1, *s2;
     483           0 :         SessionStatusInfo i = {};
     484             :         int r;
     485             : 
     486           0 :         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, BUS_MAP_BOOLEAN_AS_BOOL, &error, &m, &i);
     487           0 :         if (r < 0)
     488           0 :                 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
     489             : 
     490           0 :         if (*new_line)
     491           0 :                 printf("\n");
     492             : 
     493           0 :         *new_line = true;
     494             : 
     495           0 :         printf("%s - ", strna(i.id));
     496             : 
     497           0 :         if (i.name)
     498           0 :                 printf("%s (%"PRIu32")\n", i.name, i.uid);
     499             :         else
     500           0 :                 printf("%"PRIu32"\n", i.uid);
     501             : 
     502           0 :         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
     503           0 :         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
     504             : 
     505           0 :         if (s1)
     506           0 :                 printf("\t   Since: %s; %s\n", s2, s1);
     507           0 :         else if (s2)
     508           0 :                 printf("\t   Since: %s\n", s2);
     509             : 
     510           0 :         if (i.leader > 0) {
     511           0 :                 _cleanup_free_ char *t = NULL;
     512             : 
     513           0 :                 printf("\t  Leader: %"PRIu32, i.leader);
     514             : 
     515           0 :                 get_process_comm(i.leader, &t);
     516           0 :                 if (t)
     517           0 :                         printf(" (%s)", t);
     518             : 
     519           0 :                 printf("\n");
     520             :         }
     521             : 
     522           0 :         if (!isempty(i.seat)) {
     523           0 :                 printf("\t    Seat: %s", i.seat);
     524             : 
     525           0 :                 if (i.vtnr > 0)
     526           0 :                         printf("; vc%u", i.vtnr);
     527             : 
     528           0 :                 printf("\n");
     529             :         }
     530             : 
     531           0 :         if (i.tty)
     532           0 :                 printf("\t     TTY: %s\n", i.tty);
     533           0 :         else if (i.display)
     534           0 :                 printf("\t Display: %s\n", i.display);
     535             : 
     536           0 :         if (i.remote_host && i.remote_user)
     537           0 :                 printf("\t  Remote: %s@%s\n", i.remote_user, i.remote_host);
     538           0 :         else if (i.remote_host)
     539           0 :                 printf("\t  Remote: %s\n", i.remote_host);
     540           0 :         else if (i.remote_user)
     541           0 :                 printf("\t  Remote: user %s\n", i.remote_user);
     542           0 :         else if (i.remote)
     543           0 :                 printf("\t  Remote: Yes\n");
     544             : 
     545           0 :         if (i.service) {
     546           0 :                 printf("\t Service: %s", i.service);
     547             : 
     548           0 :                 if (i.type)
     549           0 :                         printf("; type %s", i.type);
     550             : 
     551           0 :                 if (i.class)
     552           0 :                         printf("; class %s", i.class);
     553             : 
     554           0 :                 printf("\n");
     555           0 :         } else if (i.type) {
     556           0 :                 printf("\t    Type: %s", i.type);
     557             : 
     558           0 :                 if (i.class)
     559           0 :                         printf("; class %s", i.class);
     560             : 
     561           0 :                 printf("\n");
     562           0 :         } else if (i.class)
     563           0 :                 printf("\t   Class: %s\n", i.class);
     564             : 
     565           0 :         if (!isempty(i.desktop))
     566           0 :                 printf("\t Desktop: %s\n", i.desktop);
     567             : 
     568           0 :         if (i.state)
     569           0 :                 printf("\t   State: %s\n", i.state);
     570             : 
     571           0 :         if (i.scope) {
     572           0 :                 printf("\t    Unit: %s\n", i.scope);
     573           0 :                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
     574             : 
     575           0 :                 if (arg_transport == BUS_TRANSPORT_LOCAL) {
     576             : 
     577           0 :                         show_journal_by_unit(
     578             :                                         stdout,
     579             :                                         i.scope,
     580             :                                         arg_output,
     581             :                                         0,
     582             :                                         i.timestamp.monotonic,
     583             :                                         arg_lines,
     584             :                                         0,
     585           0 :                                         get_output_flags() | OUTPUT_BEGIN_NEWLINE,
     586             :                                         SD_JOURNAL_LOCAL_ONLY,
     587             :                                         true,
     588             :                                         NULL);
     589             :                 }
     590             :         }
     591             : 
     592           0 :         return 0;
     593             : }
     594             : 
     595           0 : static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
     596             : 
     597             :         static const struct bus_properties_map map[]  = {
     598             :                 { "Name",               "s",     NULL,                     offsetof(UserStatusInfo, name)                },
     599             :                 { "Linger",             "b",     NULL,                     offsetof(UserStatusInfo, linger)              },
     600             :                 { "Slice",              "s",     NULL,                     offsetof(UserStatusInfo, slice)               },
     601             :                 { "State",              "s",     NULL,                     offsetof(UserStatusInfo, state)               },
     602             :                 { "UID",                "u",     NULL,                     offsetof(UserStatusInfo, uid)                 },
     603             :                 { "Timestamp",          "t",     NULL,                     offsetof(UserStatusInfo, timestamp.realtime)  },
     604             :                 { "TimestampMonotonic", "t",     NULL,                     offsetof(UserStatusInfo, timestamp.monotonic) },
     605             :                 { "Display",            "(so)",  prop_map_first_of_struct, offsetof(UserStatusInfo, display)             },
     606             :                 { "Sessions",           "a(so)", prop_map_sessions_strv,   offsetof(UserStatusInfo, sessions)            },
     607             :                 {}
     608             :         };
     609             : 
     610           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     611           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     612             :         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX];
     613             :         char since2[FORMAT_TIMESTAMP_MAX];
     614             :         const char *s1, *s2;
     615           0 :         _cleanup_(user_status_info_clear) UserStatusInfo i = {};
     616             :         int r;
     617             : 
     618           0 :         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, BUS_MAP_BOOLEAN_AS_BOOL, &error, &m, &i);
     619           0 :         if (r < 0)
     620           0 :                 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
     621             : 
     622           0 :         if (*new_line)
     623           0 :                 printf("\n");
     624             : 
     625           0 :         *new_line = true;
     626             : 
     627           0 :         if (i.name)
     628           0 :                 printf("%s (%"PRIu32")\n", i.name, i.uid);
     629             :         else
     630           0 :                 printf("%"PRIu32"\n", i.uid);
     631             : 
     632           0 :         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
     633           0 :         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
     634             : 
     635           0 :         if (s1)
     636           0 :                 printf("\t   Since: %s; %s\n", s2, s1);
     637           0 :         else if (s2)
     638           0 :                 printf("\t   Since: %s\n", s2);
     639             : 
     640           0 :         if (!isempty(i.state))
     641           0 :                 printf("\t   State: %s\n", i.state);
     642             : 
     643           0 :         if (!strv_isempty(i.sessions)) {
     644             :                 char **l;
     645           0 :                 printf("\tSessions:");
     646             : 
     647           0 :                 STRV_FOREACH(l, i.sessions)
     648           0 :                         printf(" %s%s",
     649           0 :                                streq_ptr(*l, i.display) ? "*" : "",
     650             :                                *l);
     651             : 
     652           0 :                 printf("\n");
     653             :         }
     654             : 
     655           0 :         printf("\t  Linger: %s\n", yes_no(i.linger));
     656             : 
     657           0 :         if (i.slice) {
     658           0 :                 printf("\t    Unit: %s\n", i.slice);
     659           0 :                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
     660             : 
     661           0 :                 show_journal_by_unit(
     662             :                                 stdout,
     663             :                                 i.slice,
     664             :                                 arg_output,
     665             :                                 0,
     666             :                                 i.timestamp.monotonic,
     667             :                                 arg_lines,
     668             :                                 0,
     669           0 :                                 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
     670             :                                 SD_JOURNAL_LOCAL_ONLY,
     671             :                                 true,
     672             :                                 NULL);
     673             :         }
     674             : 
     675           0 :         return 0;
     676             : }
     677             : 
     678           0 : static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
     679             : 
     680             :         static const struct bus_properties_map map[]  = {
     681             :                 { "Id",            "s",     NULL, offsetof(SeatStatusInfo, id) },
     682             :                 { "ActiveSession", "(so)",  prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
     683             :                 { "Sessions",      "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
     684             :                 {}
     685             :         };
     686             : 
     687           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     688           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
     689           0 :         _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
     690             :         int r;
     691             : 
     692           0 :         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, 0, &error, &m, &i);
     693           0 :         if (r < 0)
     694           0 :                 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
     695             : 
     696           0 :         if (*new_line)
     697           0 :                 printf("\n");
     698             : 
     699           0 :         *new_line = true;
     700             : 
     701           0 :         printf("%s\n", strna(i.id));
     702             : 
     703           0 :         if (!strv_isempty(i.sessions)) {
     704             :                 char **l;
     705           0 :                 printf("\tSessions:");
     706             : 
     707           0 :                 STRV_FOREACH(l, i.sessions) {
     708           0 :                         if (streq_ptr(*l, i.active_session))
     709           0 :                                 printf(" *%s", *l);
     710             :                         else
     711           0 :                                 printf(" %s", *l);
     712             :                 }
     713             : 
     714           0 :                 printf("\n");
     715             :         }
     716             : 
     717           0 :         if (arg_transport == BUS_TRANSPORT_LOCAL) {
     718             :                 unsigned c;
     719             : 
     720           0 :                 c = columns();
     721           0 :                 if (c > 21)
     722           0 :                         c -= 21;
     723             :                 else
     724           0 :                         c = 0;
     725             : 
     726           0 :                 printf("\t Devices:\n");
     727             : 
     728           0 :                 show_sysfs(i.id, "\t\t  ", c, get_output_flags());
     729             :         }
     730             : 
     731           0 :         return 0;
     732             : }
     733             : 
     734           0 : static int print_property(const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all) {
     735             :         char type;
     736             :         const char *contents;
     737             :         int r;
     738             : 
     739           0 :         assert(name);
     740           0 :         assert(m);
     741             : 
     742           0 :         r = sd_bus_message_peek_type(m, &type, &contents);
     743           0 :         if (r < 0)
     744           0 :                 return r;
     745             : 
     746           0 :         switch (type) {
     747             : 
     748           0 :         case SD_BUS_TYPE_STRUCT:
     749             : 
     750           0 :                 if (contents[0] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
     751             :                         const char *s;
     752             : 
     753           0 :                         r = sd_bus_message_read(m, "(so)", &s, NULL);
     754           0 :                         if (r < 0)
     755           0 :                                 return bus_log_parse_error(r);
     756             : 
     757           0 :                         if (all || !isempty(s))
     758           0 :                                 bus_print_property_value(name, expected_value, value, s);
     759             : 
     760           0 :                         return 1;
     761             : 
     762           0 :                 } else if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
     763             :                         uint32_t uid;
     764             : 
     765           0 :                         r = sd_bus_message_read(m, "(uo)", &uid, NULL);
     766           0 :                         if (r < 0)
     767           0 :                                 return bus_log_parse_error(r);
     768             : 
     769           0 :                         if (!uid_is_valid(uid))
     770           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     771             :                                                        "Invalid user ID: " UID_FMT,
     772             :                                                        uid);
     773             : 
     774           0 :                         bus_print_property_valuef(name, expected_value, value, UID_FMT, uid);
     775           0 :                         return 1;
     776             :                 }
     777           0 :                 break;
     778             : 
     779           0 :         case SD_BUS_TYPE_ARRAY:
     780             : 
     781           0 :                 if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
     782             :                         const char *s;
     783           0 :                         bool space = false;
     784             : 
     785           0 :                         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
     786           0 :                         if (r < 0)
     787           0 :                                 return bus_log_parse_error(r);
     788             : 
     789           0 :                         if (!value)
     790           0 :                                 printf("%s=", name);
     791             : 
     792           0 :                         while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
     793           0 :                                 printf("%s%s", space ? " " : "", s);
     794           0 :                                 space = true;
     795             :                         }
     796             : 
     797           0 :                         if (space || !value)
     798           0 :                                 printf("\n");
     799             : 
     800           0 :                         if (r < 0)
     801           0 :                                 return bus_log_parse_error(r);
     802             : 
     803           0 :                         r = sd_bus_message_exit_container(m);
     804           0 :                         if (r < 0)
     805           0 :                                 return bus_log_parse_error(r);
     806             : 
     807           0 :                         return 1;
     808             :                 }
     809           0 :                 break;
     810             :         }
     811             : 
     812           0 :         return 0;
     813             : }
     814             : 
     815           0 : static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
     816             :         int r;
     817             : 
     818           0 :         assert(bus);
     819           0 :         assert(path);
     820           0 :         assert(new_line);
     821             : 
     822           0 :         if (*new_line)
     823           0 :                 printf("\n");
     824             : 
     825           0 :         *new_line = true;
     826             : 
     827           0 :         r = bus_print_all_properties(bus, "org.freedesktop.login1", path, print_property, arg_property, arg_value, arg_all, NULL);
     828           0 :         if (r < 0)
     829           0 :                 return bus_log_parse_error(r);
     830             : 
     831           0 :         return 0;
     832             : }
     833             : 
     834           0 : static int show_session(int argc, char *argv[], void *userdata) {
     835           0 :         bool properties, new_line = false;
     836           0 :         sd_bus *bus = userdata;
     837             :         int r, i;
     838           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     839           0 :         _cleanup_free_ char *path = NULL;
     840             : 
     841           0 :         assert(bus);
     842           0 :         assert(argv);
     843             : 
     844           0 :         properties = !strstr(argv[0], "status");
     845             : 
     846           0 :         (void) pager_open(arg_pager_flags);
     847             : 
     848           0 :         if (argc <= 1) {
     849             :                 /* If no argument is specified inspect the manager itself */
     850           0 :                 if (properties)
     851           0 :                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
     852             : 
     853           0 :                 return print_session_status_info(bus, "/org/freedesktop/login1/session/auto", &new_line);
     854             :         }
     855             : 
     856           0 :         for (i = 1; i < argc; i++) {
     857           0 :                 r = get_session_path(bus, argv[i], &error, &path);
     858           0 :                 if (r < 0)
     859           0 :                         return log_error_errno(r, "Failed to get session path: %s", bus_error_message(&error, r));
     860             : 
     861           0 :                 if (properties)
     862           0 :                         r = show_properties(bus, path, &new_line);
     863             :                 else
     864           0 :                         r = print_session_status_info(bus, path, &new_line);
     865             : 
     866           0 :                 if (r < 0)
     867           0 :                         return r;
     868             :         }
     869             : 
     870           0 :         return 0;
     871             : }
     872             : 
     873           0 : static int show_user(int argc, char *argv[], void *userdata) {
     874           0 :         bool properties, new_line = false;
     875           0 :         sd_bus *bus = userdata;
     876             :         int r, i;
     877             : 
     878           0 :         assert(bus);
     879           0 :         assert(argv);
     880             : 
     881           0 :         properties = !strstr(argv[0], "status");
     882             : 
     883           0 :         (void) pager_open(arg_pager_flags);
     884             : 
     885           0 :         if (argc <= 1) {
     886             :                 /* If no argument is specified inspect the manager itself */
     887           0 :                 if (properties)
     888           0 :                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
     889             : 
     890           0 :                 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
     891             :         }
     892             : 
     893           0 :         for (i = 1; i < argc; i++) {
     894           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     895           0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
     896           0 :                 const char *path = NULL;
     897             :                 uid_t uid;
     898             : 
     899           0 :                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
     900           0 :                 if (r < 0)
     901           0 :                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
     902             : 
     903           0 :                 r = sd_bus_call_method(
     904             :                                 bus,
     905             :                                 "org.freedesktop.login1",
     906             :                                 "/org/freedesktop/login1",
     907             :                                 "org.freedesktop.login1.Manager",
     908             :                                 "GetUser",
     909             :                                 &error, &reply,
     910             :                                 "u", (uint32_t) uid);
     911           0 :                 if (r < 0)
     912           0 :                         return log_error_errno(r, "Failed to get user: %s", bus_error_message(&error, r));
     913             : 
     914           0 :                 r = sd_bus_message_read(reply, "o", &path);
     915           0 :                 if (r < 0)
     916           0 :                         return bus_log_parse_error(r);
     917             : 
     918           0 :                 if (properties)
     919           0 :                         r = show_properties(bus, path, &new_line);
     920             :                 else
     921           0 :                         r = print_user_status_info(bus, path, &new_line);
     922             : 
     923           0 :                 if (r < 0)
     924           0 :                         return r;
     925             :         }
     926             : 
     927           0 :         return 0;
     928             : }
     929             : 
     930           0 : static int show_seat(int argc, char *argv[], void *userdata) {
     931           0 :         bool properties, new_line = false;
     932           0 :         sd_bus *bus = userdata;
     933             :         int r, i;
     934             : 
     935           0 :         assert(bus);
     936           0 :         assert(argv);
     937             : 
     938           0 :         properties = !strstr(argv[0], "status");
     939             : 
     940           0 :         (void) pager_open(arg_pager_flags);
     941             : 
     942           0 :         if (argc <= 1) {
     943             :                 /* If no argument is specified inspect the manager itself */
     944           0 :                 if (properties)
     945           0 :                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
     946             : 
     947           0 :                 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/auto", &new_line);
     948             :         }
     949             : 
     950           0 :         for (i = 1; i < argc; i++) {
     951           0 :                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     952           0 :                 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
     953           0 :                 const char *path = NULL;
     954             : 
     955           0 :                 r = sd_bus_call_method(
     956             :                                 bus,
     957             :                                 "org.freedesktop.login1",
     958             :                                 "/org/freedesktop/login1",
     959             :                                 "org.freedesktop.login1.Manager",
     960             :                                 "GetSeat",
     961             :                                 &error, &reply,
     962           0 :                                 "s", argv[i]);
     963           0 :                 if (r < 0)
     964           0 :                         return log_error_errno(r, "Failed to get seat: %s", bus_error_message(&error, r));
     965             : 
     966           0 :                 r = sd_bus_message_read(reply, "o", &path);
     967           0 :                 if (r < 0)
     968           0 :                         return bus_log_parse_error(r);
     969             : 
     970           0 :                 if (properties)
     971           0 :                         r = show_properties(bus, path, &new_line);
     972             :                 else
     973           0 :                         r = print_seat_status_info(bus, path, &new_line);
     974             : 
     975           0 :                 if (r < 0)
     976           0 :                         return r;
     977             :         }
     978             : 
     979           0 :         return 0;
     980             : }
     981             : 
     982           0 : static int activate(int argc, char *argv[], void *userdata) {
     983           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     984           0 :         sd_bus *bus = userdata;
     985             :         char *short_argv[3];
     986             :         int r, i;
     987             : 
     988           0 :         assert(bus);
     989           0 :         assert(argv);
     990             : 
     991           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
     992             : 
     993           0 :         if (argc < 2) {
     994           0 :                 short_argv[0] = argv[0];
     995           0 :                 short_argv[1] = (char*) "";
     996           0 :                 short_argv[2] = NULL;
     997             : 
     998           0 :                 argv = short_argv;
     999           0 :                 argc = 2;
    1000             :         }
    1001             : 
    1002           0 :         for (i = 1; i < argc; i++) {
    1003             : 
    1004           0 :                 r = sd_bus_call_method(
    1005             :                                 bus,
    1006             :                                 "org.freedesktop.login1",
    1007             :                                 "/org/freedesktop/login1",
    1008             :                                 "org.freedesktop.login1.Manager",
    1009           0 :                                 streq(argv[0], "lock-session")      ? "LockSession" :
    1010           0 :                                 streq(argv[0], "unlock-session")    ? "UnlockSession" :
    1011           0 :                                 streq(argv[0], "terminate-session") ? "TerminateSession" :
    1012             :                                                                       "ActivateSession",
    1013             :                                 &error, NULL,
    1014           0 :                                 "s", argv[i]);
    1015           0 :                 if (r < 0)
    1016           0 :                         return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
    1017             :         }
    1018             : 
    1019           0 :         return 0;
    1020             : }
    1021             : 
    1022           0 : static int kill_session(int argc, char *argv[], void *userdata) {
    1023           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1024           0 :         sd_bus *bus = userdata;
    1025             :         int r, i;
    1026             : 
    1027           0 :         assert(bus);
    1028           0 :         assert(argv);
    1029             : 
    1030           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1031             : 
    1032           0 :         if (!arg_kill_who)
    1033           0 :                 arg_kill_who = "all";
    1034             : 
    1035           0 :         for (i = 1; i < argc; i++) {
    1036             : 
    1037           0 :                 r = sd_bus_call_method(
    1038             :                         bus,
    1039             :                         "org.freedesktop.login1",
    1040             :                         "/org/freedesktop/login1",
    1041             :                         "org.freedesktop.login1.Manager",
    1042             :                         "KillSession",
    1043             :                         &error, NULL,
    1044           0 :                         "ssi", argv[i], arg_kill_who, arg_signal);
    1045           0 :                 if (r < 0)
    1046           0 :                         return log_error_errno(r, "Could not kill session: %s", bus_error_message(&error, -r));
    1047             :         }
    1048             : 
    1049           0 :         return 0;
    1050             : }
    1051             : 
    1052           0 : static int enable_linger(int argc, char *argv[], void *userdata) {
    1053           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1054           0 :         sd_bus *bus = userdata;
    1055             :         char* short_argv[3];
    1056             :         bool b;
    1057             :         int r, i;
    1058             : 
    1059           0 :         assert(bus);
    1060           0 :         assert(argv);
    1061             : 
    1062           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1063             : 
    1064           0 :         b = streq(argv[0], "enable-linger");
    1065             : 
    1066           0 :         if (argc < 2) {
    1067             :                 /* No argument? Let's use an empty user name,
    1068             :                  * then logind will use our user. */
    1069             : 
    1070           0 :                 short_argv[0] = argv[0];
    1071           0 :                 short_argv[1] = (char*) "";
    1072           0 :                 short_argv[2] = NULL;
    1073           0 :                 argv = short_argv;
    1074           0 :                 argc = 2;
    1075             :         }
    1076             : 
    1077           0 :         for (i = 1; i < argc; i++) {
    1078             :                 uid_t uid;
    1079             : 
    1080           0 :                 if (isempty(argv[i]))
    1081           0 :                         uid = UID_INVALID;
    1082             :                 else {
    1083           0 :                         r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
    1084           0 :                         if (r < 0)
    1085           0 :                                 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
    1086             :                 }
    1087             : 
    1088           0 :                 r = sd_bus_call_method(
    1089             :                         bus,
    1090             :                         "org.freedesktop.login1",
    1091             :                         "/org/freedesktop/login1",
    1092             :                         "org.freedesktop.login1.Manager",
    1093             :                         "SetUserLinger",
    1094             :                         &error, NULL,
    1095             :                         "ubb", (uint32_t) uid, b, true);
    1096           0 :                 if (r < 0)
    1097           0 :                         return log_error_errno(r, "Could not enable linger: %s", bus_error_message(&error, -r));
    1098             :         }
    1099             : 
    1100           0 :         return 0;
    1101             : }
    1102             : 
    1103           0 : static int terminate_user(int argc, char *argv[], void *userdata) {
    1104           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1105           0 :         sd_bus *bus = userdata;
    1106             :         int r, i;
    1107             : 
    1108           0 :         assert(bus);
    1109           0 :         assert(argv);
    1110             : 
    1111           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1112             : 
    1113           0 :         for (i = 1; i < argc; i++) {
    1114             :                 uid_t uid;
    1115             : 
    1116           0 :                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
    1117           0 :                 if (r < 0)
    1118           0 :                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
    1119             : 
    1120           0 :                 r = sd_bus_call_method(
    1121             :                         bus,
    1122             :                         "org.freedesktop.login1",
    1123             :                         "/org/freedesktop/login1",
    1124             :                         "org.freedesktop.login1.Manager",
    1125             :                         "TerminateUser",
    1126             :                         &error, NULL,
    1127             :                         "u", (uint32_t) uid);
    1128           0 :                 if (r < 0)
    1129           0 :                         return log_error_errno(r, "Could not terminate user: %s", bus_error_message(&error, -r));
    1130             :         }
    1131             : 
    1132           0 :         return 0;
    1133             : }
    1134             : 
    1135           0 : static int kill_user(int argc, char *argv[], void *userdata) {
    1136           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1137           0 :         sd_bus *bus = userdata;
    1138             :         int r, i;
    1139             : 
    1140           0 :         assert(bus);
    1141           0 :         assert(argv);
    1142             : 
    1143           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1144             : 
    1145           0 :         if (!arg_kill_who)
    1146           0 :                 arg_kill_who = "all";
    1147             : 
    1148           0 :         for (i = 1; i < argc; i++) {
    1149             :                 uid_t uid;
    1150             : 
    1151           0 :                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
    1152           0 :                 if (r < 0)
    1153           0 :                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
    1154             : 
    1155           0 :                 r = sd_bus_call_method(
    1156             :                         bus,
    1157             :                         "org.freedesktop.login1",
    1158             :                         "/org/freedesktop/login1",
    1159             :                         "org.freedesktop.login1.Manager",
    1160             :                         "KillUser",
    1161             :                         &error, NULL,
    1162             :                         "ui", (uint32_t) uid, arg_signal);
    1163           0 :                 if (r < 0)
    1164           0 :                         return log_error_errno(r, "Could not kill user: %s", bus_error_message(&error, -r));
    1165             :         }
    1166             : 
    1167           0 :         return 0;
    1168             : }
    1169             : 
    1170           0 : static int attach(int argc, char *argv[], void *userdata) {
    1171           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1172           0 :         sd_bus *bus = userdata;
    1173             :         int r, i;
    1174             : 
    1175           0 :         assert(bus);
    1176           0 :         assert(argv);
    1177             : 
    1178           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1179             : 
    1180           0 :         for (i = 2; i < argc; i++) {
    1181             : 
    1182           0 :                 r = sd_bus_call_method(
    1183             :                         bus,
    1184             :                         "org.freedesktop.login1",
    1185             :                         "/org/freedesktop/login1",
    1186             :                         "org.freedesktop.login1.Manager",
    1187             :                         "AttachDevice",
    1188             :                         &error, NULL,
    1189           0 :                         "ssb", argv[1], argv[i], true);
    1190             : 
    1191           0 :                 if (r < 0)
    1192           0 :                         return log_error_errno(r, "Could not attach device: %s", bus_error_message(&error, -r));
    1193             :         }
    1194             : 
    1195           0 :         return 0;
    1196             : }
    1197             : 
    1198           0 : static int flush_devices(int argc, char *argv[], void *userdata) {
    1199           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1200           0 :         sd_bus *bus = userdata;
    1201             :         int r;
    1202             : 
    1203           0 :         assert(bus);
    1204           0 :         assert(argv);
    1205             : 
    1206           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1207             : 
    1208           0 :         r = sd_bus_call_method(
    1209             :                         bus,
    1210             :                         "org.freedesktop.login1",
    1211             :                         "/org/freedesktop/login1",
    1212             :                         "org.freedesktop.login1.Manager",
    1213             :                         "FlushDevices",
    1214             :                         &error, NULL,
    1215             :                         "b", true);
    1216           0 :         if (r < 0)
    1217           0 :                 return log_error_errno(r, "Could not flush devices: %s", bus_error_message(&error, -r));
    1218             : 
    1219           0 :         return 0;
    1220             : }
    1221             : 
    1222           0 : static int lock_sessions(int argc, char *argv[], void *userdata) {
    1223           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1224           0 :         sd_bus *bus = userdata;
    1225             :         int r;
    1226             : 
    1227           0 :         assert(bus);
    1228           0 :         assert(argv);
    1229             : 
    1230           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1231             : 
    1232           0 :         r = sd_bus_call_method(
    1233             :                         bus,
    1234             :                         "org.freedesktop.login1",
    1235             :                         "/org/freedesktop/login1",
    1236             :                         "org.freedesktop.login1.Manager",
    1237           0 :                         streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
    1238             :                         &error, NULL,
    1239             :                         NULL);
    1240           0 :         if (r < 0)
    1241           0 :                 return log_error_errno(r, "Could not lock sessions: %s", bus_error_message(&error, -r));
    1242             : 
    1243           0 :         return 0;
    1244             : }
    1245             : 
    1246           0 : static int terminate_seat(int argc, char *argv[], void *userdata) {
    1247           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
    1248           0 :         sd_bus *bus = userdata;
    1249             :         int r, i;
    1250             : 
    1251           0 :         assert(bus);
    1252           0 :         assert(argv);
    1253             : 
    1254           0 :         polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
    1255             : 
    1256           0 :         for (i = 1; i < argc; i++) {
    1257             : 
    1258           0 :                 r = sd_bus_call_method(
    1259             :                         bus,
    1260             :                         "org.freedesktop.login1",
    1261             :                         "/org/freedesktop/login1",
    1262             :                         "org.freedesktop.login1.Manager",
    1263             :                         "TerminateSeat",
    1264             :                         &error, NULL,
    1265           0 :                         "s", argv[i]);
    1266           0 :                 if (r < 0)
    1267           0 :                         return log_error_errno(r, "Could not terminate seat: %s", bus_error_message(&error, -r));
    1268             :         }
    1269             : 
    1270           0 :         return 0;
    1271             : }
    1272             : 
    1273           3 : static int help(int argc, char *argv[], void *userdata) {
    1274           3 :         _cleanup_free_ char *link = NULL;
    1275             :         int r;
    1276             : 
    1277           3 :         (void) pager_open(arg_pager_flags);
    1278             : 
    1279           3 :         r = terminal_urlify_man("loginctl", "1", &link);
    1280           3 :         if (r < 0)
    1281           0 :                 return log_oom();
    1282             : 
    1283           3 :         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
    1284             :                "Send control commands to or query the login manager.\n\n"
    1285             :                "  -h --help                Show this help\n"
    1286             :                "     --version             Show package version\n"
    1287             :                "     --no-pager            Do not pipe output into a pager\n"
    1288             :                "     --no-legend           Do not show the headers and footers\n"
    1289             :                "     --no-ask-password     Don't prompt for password\n"
    1290             :                "  -H --host=[USER@]HOST    Operate on remote host\n"
    1291             :                "  -M --machine=CONTAINER   Operate on local container\n"
    1292             :                "  -p --property=NAME       Show only properties by this name\n"
    1293             :                "  -a --all                 Show all properties, including empty ones\n"
    1294             :                "     --value               When showing properties, only print the value\n"
    1295             :                "  -l --full                Do not ellipsize output\n"
    1296             :                "     --kill-who=WHO        Who to send signal to\n"
    1297             :                "  -s --signal=SIGNAL       Which signal to send\n"
    1298             :                "  -n --lines=INTEGER       Number of journal entries to show\n"
    1299             :                "  -o --output=STRING       Change journal output mode (short, short-precise,\n"
    1300             :                "                             short-iso, short-iso-precise, short-full,\n"
    1301             :                "                             short-monotonic, short-unix, verbose, export,\n"
    1302             :                "                             json, json-pretty, json-sse, json-seq, cat,\n"
    1303             :                "                             with-unit)\n"
    1304             :                "Session Commands:\n"
    1305             :                "  list-sessions            List sessions\n"
    1306             :                "  session-status [ID...]   Show session status\n"
    1307             :                "  show-session [ID...]     Show properties of sessions or the manager\n"
    1308             :                "  activate [ID]            Activate a session\n"
    1309             :                "  lock-session [ID...]     Screen lock one or more sessions\n"
    1310             :                "  unlock-session [ID...]   Screen unlock one or more sessions\n"
    1311             :                "  lock-sessions            Screen lock all current sessions\n"
    1312             :                "  unlock-sessions          Screen unlock all current sessions\n"
    1313             :                "  terminate-session ID...  Terminate one or more sessions\n"
    1314             :                "  kill-session ID...       Send signal to processes of a session\n\n"
    1315             :                "User Commands:\n"
    1316             :                "  list-users               List users\n"
    1317             :                "  user-status [USER...]    Show user status\n"
    1318             :                "  show-user [USER...]      Show properties of users or the manager\n"
    1319             :                "  enable-linger [USER...]  Enable linger state of one or more users\n"
    1320             :                "  disable-linger [USER...] Disable linger state of one or more users\n"
    1321             :                "  terminate-user USER...   Terminate all sessions of one or more users\n"
    1322             :                "  kill-user USER...        Send signal to processes of a user\n\n"
    1323             :                "Seat Commands:\n"
    1324             :                "  list-seats               List seats\n"
    1325             :                "  seat-status [NAME...]    Show seat status\n"
    1326             :                "  show-seat [NAME...]      Show properties of seats or the manager\n"
    1327             :                "  attach NAME DEVICE...    Attach one or more devices to a seat\n"
    1328             :                "  flush-devices            Flush all device associations\n"
    1329             :                "  terminate-seat NAME...   Terminate all sessions on one or more seats\n"
    1330             :                "\nSee the %s for details.\n"
    1331             :                , program_invocation_short_name
    1332             :                , link
    1333             :         );
    1334             : 
    1335           3 :         return 0;
    1336             : }
    1337             : 
    1338           4 : static int parse_argv(int argc, char *argv[]) {
    1339             : 
    1340             :         enum {
    1341             :                 ARG_VERSION = 0x100,
    1342             :                 ARG_VALUE,
    1343             :                 ARG_NO_PAGER,
    1344             :                 ARG_NO_LEGEND,
    1345             :                 ARG_KILL_WHO,
    1346             :                 ARG_NO_ASK_PASSWORD,
    1347             :         };
    1348             : 
    1349             :         static const struct option options[] = {
    1350             :                 { "help",            no_argument,       NULL, 'h'                 },
    1351             :                 { "version",         no_argument,       NULL, ARG_VERSION         },
    1352             :                 { "property",        required_argument, NULL, 'p'                 },
    1353             :                 { "all",             no_argument,       NULL, 'a'                 },
    1354             :                 { "value",           no_argument,       NULL, ARG_VALUE           },
    1355             :                 { "full",            no_argument,       NULL, 'l'                 },
    1356             :                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
    1357             :                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
    1358             :                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
    1359             :                 { "signal",          required_argument, NULL, 's'                 },
    1360             :                 { "host",            required_argument, NULL, 'H'                 },
    1361             :                 { "machine",         required_argument, NULL, 'M'                 },
    1362             :                 { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
    1363             :                 { "lines",           required_argument, NULL, 'n'                 },
    1364             :                 { "output",          required_argument, NULL, 'o'                 },
    1365             :                 {}
    1366             :         };
    1367             : 
    1368             :         int c, r;
    1369             : 
    1370           4 :         assert(argc >= 0);
    1371           4 :         assert(argv);
    1372             : 
    1373           4 :         while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
    1374             : 
    1375           4 :                 switch (c) {
    1376             : 
    1377           3 :                 case 'h':
    1378           3 :                         return help(0, NULL, NULL);
    1379             : 
    1380           0 :                 case ARG_VERSION:
    1381           0 :                         return version();
    1382             : 
    1383           0 :                 case 'p': {
    1384           0 :                         r = strv_extend(&arg_property, optarg);
    1385           0 :                         if (r < 0)
    1386           0 :                                 return log_oom();
    1387             : 
    1388             :                         /* If the user asked for a particular
    1389             :                          * property, show it to him, even if it is
    1390             :                          * empty. */
    1391           0 :                         arg_all = true;
    1392           0 :                         break;
    1393             :                 }
    1394             : 
    1395           0 :                 case 'a':
    1396           0 :                         arg_all = true;
    1397           0 :                         break;
    1398             : 
    1399           0 :                 case ARG_VALUE:
    1400           0 :                         arg_value = true;
    1401           0 :                         break;
    1402             : 
    1403           0 :                 case 'l':
    1404           0 :                         arg_full = true;
    1405           0 :                         break;
    1406             : 
    1407           0 :                 case 'n':
    1408           0 :                         if (safe_atou(optarg, &arg_lines) < 0)
    1409           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1410             :                                                        "Failed to parse lines '%s'", optarg);
    1411           0 :                         break;
    1412             : 
    1413           0 :                 case 'o':
    1414           0 :                         if (streq(optarg, "help")) {
    1415           0 :                                 DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX);
    1416           0 :                                 return 0;
    1417             :                         }
    1418             : 
    1419           0 :                         arg_output = output_mode_from_string(optarg);
    1420           0 :                         if (arg_output < 0)
    1421           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1422             :                                                        "Unknown output '%s'.", optarg);
    1423             : 
    1424           0 :                         if (OUTPUT_MODE_IS_JSON(arg_output))
    1425           0 :                                 arg_legend = false;
    1426             : 
    1427           0 :                         break;
    1428             : 
    1429           0 :                 case ARG_NO_PAGER:
    1430           0 :                         arg_pager_flags |= PAGER_DISABLE;
    1431           0 :                         break;
    1432             : 
    1433           0 :                 case ARG_NO_LEGEND:
    1434           0 :                         arg_legend = false;
    1435           0 :                         break;
    1436             : 
    1437           0 :                 case ARG_NO_ASK_PASSWORD:
    1438           0 :                         arg_ask_password = false;
    1439           0 :                         break;
    1440             : 
    1441           0 :                 case ARG_KILL_WHO:
    1442           0 :                         arg_kill_who = optarg;
    1443           0 :                         break;
    1444             : 
    1445           0 :                 case 's':
    1446           0 :                         if (streq(optarg, "help")) {
    1447           0 :                                 DUMP_STRING_TABLE(signal, int, _NSIG);
    1448           0 :                                 return 0;
    1449             :                         }
    1450             : 
    1451           0 :                         arg_signal = signal_from_string(optarg);
    1452           0 :                         if (arg_signal < 0)
    1453           0 :                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
    1454             :                                                        "Failed to parse signal string %s.", optarg);
    1455           0 :                         break;
    1456             : 
    1457           0 :                 case 'H':
    1458           0 :                         arg_transport = BUS_TRANSPORT_REMOTE;
    1459           0 :                         arg_host = optarg;
    1460           0 :                         break;
    1461             : 
    1462           0 :                 case 'M':
    1463           0 :                         arg_transport = BUS_TRANSPORT_MACHINE;
    1464           0 :                         arg_host = optarg;
    1465           0 :                         break;
    1466             : 
    1467           1 :                 case '?':
    1468           1 :                         return -EINVAL;
    1469             : 
    1470           0 :                 default:
    1471           0 :                         assert_not_reached("Unhandled option");
    1472             :                 }
    1473             : 
    1474           0 :         return 1;
    1475             : }
    1476             : 
    1477           0 : static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
    1478             : 
    1479             :         static const Verb verbs[] = {
    1480             :                 { "help",              VERB_ANY, VERB_ANY, 0,            help              },
    1481             :                 { "list-sessions",     VERB_ANY, 1,        VERB_DEFAULT, list_sessions     },
    1482             :                 { "session-status",    VERB_ANY, VERB_ANY, 0,            show_session      },
    1483             :                 { "show-session",      VERB_ANY, VERB_ANY, 0,            show_session      },
    1484             :                 { "activate",          VERB_ANY, 2,        0,            activate          },
    1485             :                 { "lock-session",      VERB_ANY, VERB_ANY, 0,            activate          },
    1486             :                 { "unlock-session",    VERB_ANY, VERB_ANY, 0,            activate          },
    1487             :                 { "lock-sessions",     VERB_ANY, 1,        0,            lock_sessions     },
    1488             :                 { "unlock-sessions",   VERB_ANY, 1,        0,            lock_sessions     },
    1489             :                 { "terminate-session", 2,        VERB_ANY, 0,            activate          },
    1490             :                 { "kill-session",      2,        VERB_ANY, 0,            kill_session      },
    1491             :                 { "list-users",        VERB_ANY, 1,        0,            list_users        },
    1492             :                 { "user-status",       VERB_ANY, VERB_ANY, 0,            show_user         },
    1493             :                 { "show-user",         VERB_ANY, VERB_ANY, 0,            show_user         },
    1494             :                 { "enable-linger",     VERB_ANY, VERB_ANY, 0,            enable_linger     },
    1495             :                 { "disable-linger",    VERB_ANY, VERB_ANY, 0,            enable_linger     },
    1496             :                 { "terminate-user",    2,        VERB_ANY, 0,            terminate_user    },
    1497             :                 { "kill-user",         2,        VERB_ANY, 0,            kill_user         },
    1498             :                 { "list-seats",        VERB_ANY, 1,        0,            list_seats        },
    1499             :                 { "seat-status",       VERB_ANY, VERB_ANY, 0,            show_seat         },
    1500             :                 { "show-seat",         VERB_ANY, VERB_ANY, 0,            show_seat         },
    1501             :                 { "attach",            3,        VERB_ANY, 0,            attach            },
    1502             :                 { "flush-devices",     VERB_ANY, 1,        0,            flush_devices     },
    1503             :                 { "terminate-seat",    2,        VERB_ANY, 0,            terminate_seat    },
    1504             :                 {}
    1505             :         };
    1506             : 
    1507           0 :         return dispatch_verb(argc, argv, verbs, bus);
    1508             : }
    1509             : 
    1510           4 : static int run(int argc, char *argv[]) {
    1511           4 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1512             :         int r;
    1513             : 
    1514           4 :         setlocale(LC_ALL, "");
    1515           4 :         log_show_color(true);
    1516           4 :         log_parse_environment();
    1517           4 :         log_open();
    1518             : 
    1519             :         /* The journal merging logic potentially needs a lot of fds. */
    1520           4 :         (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
    1521             : 
    1522           4 :         sigbus_install();
    1523             : 
    1524           4 :         r = parse_argv(argc, argv);
    1525           4 :         if (r <= 0)
    1526           4 :                 return r;
    1527             : 
    1528           0 :         r = bus_connect_transport(arg_transport, arg_host, false, &bus);
    1529           0 :         if (r < 0)
    1530           0 :                 return log_error_errno(r, "Failed to create bus connection: %m");
    1531             : 
    1532           0 :         (void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
    1533             : 
    1534           0 :         return loginctl_main(argc, argv, bus);
    1535             : }
    1536             : 
    1537           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14