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