1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4
This file is part of systemd.
6
Copyright 2010 Lennart Poettering
8
systemd is free software; you can redistribute it and/or modify it
9
under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
systemd is distributed in the hope that it will be useful, but
14
WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with systemd; If not, see <http://www.gnu.org/licenses/>.
22
#include <dbus/dbus.h>
33
#include "dbus-common.h"
36
#include "cgroup-show.h"
37
#include "sysfs-show.h"
39
static char **arg_property = NULL;
40
static bool arg_all = false;
41
static bool arg_no_pager = false;
42
static const char *arg_kill_who = NULL;
43
static int arg_signal = SIGTERM;
44
static enum transport {
48
} arg_transport = TRANSPORT_NORMAL;
49
static const char *arg_host = NULL;
51
static bool on_tty(void) {
54
/* Note that this is invoked relatively early, before we start
55
* the pager. That means the value we return reflects whether
56
* we originally were started on a tty, not if we currently
57
* are. But this is intended, since we want colour and so on
58
* when run in our own pager. */
60
if (_unlikely_(t < 0))
61
t = isatty(STDOUT_FILENO) > 0;
66
static void pager_open_if_enabled(void) {
68
/* Cache result before we open the pager */
75
static int list_sessions(DBusConnection *bus, char **args, unsigned n) {
76
DBusMessage *m = NULL, *reply = NULL;
79
DBusMessageIter iter, sub, sub2;
82
dbus_error_init(&error);
86
pager_open_if_enabled();
88
m = dbus_message_new_method_call(
89
"org.freedesktop.login1",
90
"/org/freedesktop/login1",
91
"org.freedesktop.login1.Manager",
94
log_error("Could not allocate message.");
98
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
100
log_error("Failed to issue method call: %s", bus_error_message(&error));
105
if (!dbus_message_iter_init(reply, &iter) ||
106
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
107
dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
108
log_error("Failed to parse reply.");
113
dbus_message_iter_recurse(&iter, &sub);
116
printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
118
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
119
const char *id, *user, *seat, *object;
122
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
123
log_error("Failed to parse reply.");
128
dbus_message_iter_recurse(&sub, &sub2);
130
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) < 0 ||
131
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
132
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
133
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
134
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
135
log_error("Failed to parse reply.");
140
printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
144
dbus_message_iter_next(&sub);
148
printf("\n%u sessions listed.\n", k);
154
dbus_message_unref(m);
157
dbus_message_unref(reply);
159
dbus_error_free(&error);
164
static int list_users(DBusConnection *bus, char **args, unsigned n) {
165
DBusMessage *m = NULL, *reply = NULL;
168
DBusMessageIter iter, sub, sub2;
171
dbus_error_init(&error);
175
pager_open_if_enabled();
177
m = dbus_message_new_method_call(
178
"org.freedesktop.login1",
179
"/org/freedesktop/login1",
180
"org.freedesktop.login1.Manager",
183
log_error("Could not allocate message.");
187
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
189
log_error("Failed to issue method call: %s", bus_error_message(&error));
194
if (!dbus_message_iter_init(reply, &iter) ||
195
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
196
dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
197
log_error("Failed to parse reply.");
202
dbus_message_iter_recurse(&iter, &sub);
205
printf("%10s %-16s\n", "UID", "USER");
207
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
208
const char *user, *object;
211
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
212
log_error("Failed to parse reply.");
217
dbus_message_iter_recurse(&sub, &sub2);
219
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
220
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &user, true) < 0 ||
221
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
222
log_error("Failed to parse reply.");
227
printf("%10u %-16s\n", (unsigned) uid, user);
231
dbus_message_iter_next(&sub);
235
printf("\n%u users listed.\n", k);
241
dbus_message_unref(m);
244
dbus_message_unref(reply);
246
dbus_error_free(&error);
251
static int list_seats(DBusConnection *bus, char **args, unsigned n) {
252
DBusMessage *m = NULL, *reply = NULL;
255
DBusMessageIter iter, sub, sub2;
258
dbus_error_init(&error);
262
pager_open_if_enabled();
264
m = dbus_message_new_method_call(
265
"org.freedesktop.login1",
266
"/org/freedesktop/login1",
267
"org.freedesktop.login1.Manager",
270
log_error("Could not allocate message.");
274
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
276
log_error("Failed to issue method call: %s", bus_error_message(&error));
281
if (!dbus_message_iter_init(reply, &iter) ||
282
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
283
dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
284
log_error("Failed to parse reply.");
289
dbus_message_iter_recurse(&iter, &sub);
292
printf("%-16s\n", "SEAT");
294
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
295
const char *seat, *object;
297
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
298
log_error("Failed to parse reply.");
303
dbus_message_iter_recurse(&sub, &sub2);
305
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &seat, true) < 0 ||
306
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
307
log_error("Failed to parse reply.");
312
printf("%-16s\n", seat);
316
dbus_message_iter_next(&sub);
320
printf("\n%u seats listed.\n", k);
326
dbus_message_unref(m);
329
dbus_message_unref(reply);
331
dbus_error_free(&error);
336
typedef struct SessionStatusInfo {
341
const char *control_group;
347
const char *remote_host;
348
const char *remote_user;
355
typedef struct UserStatusInfo {
359
const char *control_group;
365
typedef struct SeatStatusInfo {
367
const char *active_session;
371
static void print_session_status_info(SessionStatusInfo *i) {
372
char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
373
char since2[FORMAT_TIMESTAMP_MAX], *s2;
376
printf("%s - ", strna(i->id));
379
printf("%s (%u)\n", i->name, (unsigned) i->uid);
381
printf("%u\n", (unsigned) i->uid);
383
s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
384
s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
387
printf("\t Since: %s; %s\n", s2, s1);
389
printf("\t Since: %s\n", s2);
394
printf("\t Leader: %u", (unsigned) i->leader);
396
get_process_name(i->leader, &t);
406
printf("\t Seat: %s", i->seat);
409
printf("; vc%i", i->vtnr);
415
printf("\t TTY: %s\n", i->tty);
417
printf("\t Display: %s\n", i->display);
419
if (i->remote_host && i->remote_user)
420
printf("\t Remote: %s@%s\n", i->remote_user, i->remote_host);
421
else if (i->remote_host)
422
printf("\t Remote: %s\n", i->remote_host);
423
else if (i->remote_user)
424
printf("\t Remote: user %s\n", i->remote_user);
426
printf("\t Remote: Yes\n");
429
printf("\t Service: %s", i->service);
432
printf("; type %s", i->type);
436
printf("\t Type: %s\n", i->type);
438
printf("\t Active: %s\n", yes_no(i->active));
440
if (i->control_group) {
443
printf("\t CGroup: %s\n", i->control_group);
445
if (arg_transport != TRANSPORT_SSH) {
452
show_cgroup_by_path(i->control_group, "\t\t ", c);
457
static void print_user_status_info(UserStatusInfo *i) {
458
char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
459
char since2[FORMAT_TIMESTAMP_MAX], *s2;
463
printf("%s (%u)\n", i->name, (unsigned) i->uid);
465
printf("%u\n", (unsigned) i->uid);
467
s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
468
s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
471
printf("\t Since: %s; %s\n", s2, s1);
473
printf("\t Since: %s\n", s2);
475
if (!isempty(i->state))
476
printf("\t State: %s\n", i->state);
478
if (!strv_isempty(i->sessions)) {
480
printf("\tSessions:");
482
STRV_FOREACH(l, i->sessions) {
483
if (streq_ptr(*l, i->display))
492
if (i->control_group) {
495
printf("\t CGroup: %s\n", i->control_group);
497
if (arg_transport != TRANSPORT_SSH) {
504
show_cgroup_by_path(i->control_group, "\t\t ", c);
509
static void print_seat_status_info(SeatStatusInfo *i) {
512
printf("%s\n", strna(i->id));
514
if (!strv_isempty(i->sessions)) {
516
printf("\tSessions:");
518
STRV_FOREACH(l, i->sessions) {
519
if (streq_ptr(*l, i->active_session))
528
if (arg_transport != TRANSPORT_SSH) {
537
printf("\t Devices:\n");
539
show_sysfs(i->id, "\t\t ", c);
543
static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *i) {
548
switch (dbus_message_iter_get_arg_type(iter)) {
550
case DBUS_TYPE_STRING: {
553
dbus_message_iter_get_basic(iter, &s);
556
if (streq(name, "Id"))
558
else if (streq(name, "Name"))
560
else if (streq(name, "ControlGroupPath"))
561
i->control_group = s;
562
else if (streq(name, "TTY"))
564
else if (streq(name, "Display"))
566
else if (streq(name, "RemoteHost"))
568
else if (streq(name, "RemoteUser"))
570
else if (streq(name, "Service"))
572
else if (streq(name, "Type"))
578
case DBUS_TYPE_UINT32: {
581
dbus_message_iter_get_basic(iter, &u);
583
if (streq(name, "VTNr"))
585
else if (streq(name, "Leader"))
586
i->leader = (pid_t) u;
591
case DBUS_TYPE_BOOLEAN: {
594
dbus_message_iter_get_basic(iter, &b);
596
if (streq(name, "Remote"))
598
else if (streq(name, "Active"))
604
case DBUS_TYPE_UINT64: {
607
dbus_message_iter_get_basic(iter, &u);
609
if (streq(name, "Timestamp"))
610
i->timestamp = (usec_t) u;
615
case DBUS_TYPE_STRUCT: {
618
dbus_message_iter_recurse(iter, &sub);
620
if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "User")) {
623
dbus_message_iter_get_basic(&sub, &u);
626
} else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Seat")) {
629
dbus_message_iter_get_basic(&sub, &s);
642
static int status_property_user(const char *name, DBusMessageIter *iter, UserStatusInfo *i) {
647
switch (dbus_message_iter_get_arg_type(iter)) {
649
case DBUS_TYPE_STRING: {
652
dbus_message_iter_get_basic(iter, &s);
655
if (streq(name, "Name"))
657
else if (streq(name, "ControlGroupPath"))
658
i->control_group = s;
659
else if (streq(name, "State"))
665
case DBUS_TYPE_UINT32: {
668
dbus_message_iter_get_basic(iter, &u);
670
if (streq(name, "UID"))
676
case DBUS_TYPE_UINT64: {
679
dbus_message_iter_get_basic(iter, &u);
681
if (streq(name, "Timestamp"))
682
i->timestamp = (usec_t) u;
687
case DBUS_TYPE_STRUCT: {
690
dbus_message_iter_recurse(iter, &sub);
692
if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Display")) {
695
dbus_message_iter_get_basic(&sub, &s);
704
case DBUS_TYPE_ARRAY: {
706
if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
707
DBusMessageIter sub, sub2;
709
dbus_message_iter_recurse(iter, &sub);
710
while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
714
dbus_message_iter_recurse(&sub, &sub2);
716
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
717
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
720
l = strv_append(i->sessions, id);
724
strv_free(i->sessions);
728
dbus_message_iter_next(&sub);
739
static int status_property_seat(const char *name, DBusMessageIter *iter, SeatStatusInfo *i) {
744
switch (dbus_message_iter_get_arg_type(iter)) {
746
case DBUS_TYPE_STRING: {
749
dbus_message_iter_get_basic(iter, &s);
752
if (streq(name, "Id"))
758
case DBUS_TYPE_STRUCT: {
761
dbus_message_iter_recurse(iter, &sub);
763
if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "ActiveSession")) {
766
dbus_message_iter_get_basic(&sub, &s);
769
i->active_session = s;
775
case DBUS_TYPE_ARRAY: {
777
if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
778
DBusMessageIter sub, sub2;
780
dbus_message_iter_recurse(iter, &sub);
781
while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
785
dbus_message_iter_recurse(&sub, &sub2);
787
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
788
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
791
l = strv_append(i->sessions, id);
795
strv_free(i->sessions);
799
dbus_message_iter_next(&sub);
810
static int print_property(const char *name, DBusMessageIter *iter) {
814
if (arg_property && !strv_find(arg_property, name))
817
switch (dbus_message_iter_get_arg_type(iter)) {
819
case DBUS_TYPE_STRUCT: {
822
dbus_message_iter_recurse(iter, &sub);
824
if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING &&
825
(streq(name, "Display") || streq(name, "ActiveSession"))) {
828
dbus_message_iter_get_basic(&sub, &s);
830
if (arg_all || !isempty(s))
831
printf("%s=%s\n", name, s);
837
case DBUS_TYPE_ARRAY:
839
if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
840
DBusMessageIter sub, sub2;
843
dbus_message_iter_recurse(iter, &sub);
844
while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
848
dbus_message_iter_recurse(&sub, &sub2);
850
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &id, true) >= 0 &&
851
bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &path, false) >= 0) {
855
printf("%s=%s", name, id);
860
dbus_message_iter_next(&sub);
863
if (!found && arg_all)
864
printf("%s=\n", name);
874
if (generic_print_property(name, iter, arg_all) > 0)
878
printf("%s=[unprintable]\n", name);
883
static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
884
DBusMessage *m = NULL, *reply = NULL;
885
const char *interface = "";
888
DBusMessageIter iter, sub, sub2, sub3;
889
SessionStatusInfo session_info;
890
UserStatusInfo user_info;
891
SeatStatusInfo seat_info;
901
dbus_error_init(&error);
903
m = dbus_message_new_method_call(
904
"org.freedesktop.login1",
906
"org.freedesktop.DBus.Properties",
909
log_error("Could not allocate message.");
914
if (!dbus_message_append_args(m,
915
DBUS_TYPE_STRING, &interface,
916
DBUS_TYPE_INVALID)) {
917
log_error("Could not append arguments to message.");
922
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
924
log_error("Failed to issue method call: %s", bus_error_message(&error));
929
if (!dbus_message_iter_init(reply, &iter) ||
930
dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
931
dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
932
log_error("Failed to parse reply.");
937
dbus_message_iter_recurse(&iter, &sub);
944
while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
947
if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
948
log_error("Failed to parse reply.");
953
dbus_message_iter_recurse(&sub, &sub2);
955
if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
956
log_error("Failed to parse reply.");
961
if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
962
log_error("Failed to parse reply.");
967
dbus_message_iter_recurse(&sub2, &sub3);
970
r = print_property(name, &sub3);
971
else if (strstr(verb, "session"))
972
r = status_property_session(name, &sub3, &session_info);
973
else if (strstr(verb, "user"))
974
r = status_property_user(name, &sub3, &user_info);
976
r = status_property_seat(name, &sub3, &seat_info);
979
log_error("Failed to parse reply.");
984
dbus_message_iter_next(&sub);
987
if (!show_properties) {
988
if (strstr(verb, "session"))
989
print_session_status_info(&session_info);
990
else if (strstr(verb, "user"))
991
print_user_status_info(&user_info);
993
print_seat_status_info(&seat_info);
996
strv_free(seat_info.sessions);
997
strv_free(user_info.sessions);
1003
dbus_message_unref(m);
1006
dbus_message_unref(reply);
1008
dbus_error_free(&error);
1013
static int show(DBusConnection *bus, char **args, unsigned n) {
1014
DBusMessage *m = NULL, *reply = NULL;
1018
bool show_properties, new_line = false;
1023
dbus_error_init(&error);
1025
show_properties = !strstr(args[0], "status");
1027
if (show_properties)
1028
pager_open_if_enabled();
1030
if (show_properties && n <= 1) {
1031
/* If not argument is specified inspect the manager
1034
ret = show_one(args[0], bus, "/org/freedesktop/login1", show_properties, &new_line);
1038
for (i = 1; i < n; i++) {
1039
const char *path = NULL;
1041
if (strstr(args[0], "session")) {
1043
m = dbus_message_new_method_call(
1044
"org.freedesktop.login1",
1045
"/org/freedesktop/login1",
1046
"org.freedesktop.login1.Manager",
1049
log_error("Could not allocate message.");
1054
if (!dbus_message_append_args(m,
1055
DBUS_TYPE_STRING, &args[i],
1056
DBUS_TYPE_INVALID)) {
1057
log_error("Could not append arguments to message.");
1062
} else if (strstr(args[0], "user")) {
1066
ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1068
log_error("User %s unknown.", args[i]);
1072
m = dbus_message_new_method_call(
1073
"org.freedesktop.login1",
1074
"/org/freedesktop/login1",
1075
"org.freedesktop.login1.Manager",
1078
log_error("Could not allocate message.");
1084
if (!dbus_message_append_args(m,
1085
DBUS_TYPE_UINT32, &u,
1086
DBUS_TYPE_INVALID)) {
1087
log_error("Could not append arguments to message.");
1093
m = dbus_message_new_method_call(
1094
"org.freedesktop.login1",
1095
"/org/freedesktop/login1",
1096
"org.freedesktop.login1.Manager",
1099
log_error("Could not allocate message.");
1104
if (!dbus_message_append_args(m,
1105
DBUS_TYPE_STRING, &args[i],
1106
DBUS_TYPE_INVALID)) {
1107
log_error("Could not append arguments to message.");
1113
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1115
log_error("Failed to issue method call: %s", bus_error_message(&error));
1120
if (!dbus_message_get_args(reply, &error,
1121
DBUS_TYPE_OBJECT_PATH, &path,
1122
DBUS_TYPE_INVALID)) {
1123
log_error("Failed to parse reply: %s", bus_error_message(&error));
1128
r = show_one(args[0], bus, path, show_properties, &new_line);
1132
dbus_message_unref(m);
1133
dbus_message_unref(reply);
1139
dbus_message_unref(m);
1142
dbus_message_unref(reply);
1144
dbus_error_free(&error);
1149
static int activate(DBusConnection *bus, char **args, unsigned n) {
1150
DBusMessage *m = NULL;
1158
dbus_error_init(&error);
1160
for (i = 1; i < n; i++) {
1163
m = dbus_message_new_method_call(
1164
"org.freedesktop.login1",
1165
"/org/freedesktop/login1",
1166
"org.freedesktop.login1.Manager",
1167
streq(args[0], "lock-session") ? "LockSession" :
1168
streq(args[0], "unlock-session") ? "UnlockSession" :
1169
streq(args[0], "terminate-session") ? "TerminateSession" :
1172
log_error("Could not allocate message.");
1177
if (!dbus_message_append_args(m,
1178
DBUS_TYPE_STRING, &args[i],
1179
DBUS_TYPE_INVALID)) {
1180
log_error("Could not append arguments to message.");
1185
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1187
log_error("Failed to issue method call: %s", bus_error_message(&error));
1192
dbus_message_unref(m);
1193
dbus_message_unref(reply);
1199
dbus_message_unref(m);
1201
dbus_error_free(&error);
1206
static int kill_session(DBusConnection *bus, char **args, unsigned n) {
1207
DBusMessage *m = NULL;
1215
dbus_error_init(&error);
1218
arg_kill_who = "all";
1220
for (i = 1; i < n; i++) {
1223
m = dbus_message_new_method_call(
1224
"org.freedesktop.login1",
1225
"/org/freedesktop/login1",
1226
"org.freedesktop.login1.Manager",
1229
log_error("Could not allocate message.");
1234
if (!dbus_message_append_args(m,
1235
DBUS_TYPE_STRING, &args[i],
1236
DBUS_TYPE_STRING, &arg_kill_who,
1237
DBUS_TYPE_INT32, arg_signal,
1238
DBUS_TYPE_INVALID)) {
1239
log_error("Could not append arguments to message.");
1244
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1246
log_error("Failed to issue method call: %s", bus_error_message(&error));
1251
dbus_message_unref(m);
1252
dbus_message_unref(reply);
1258
dbus_message_unref(m);
1260
dbus_error_free(&error);
1265
static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
1266
DBusMessage *m = NULL;
1270
dbus_bool_t b, interactive = true;
1275
dbus_error_init(&error);
1277
b = streq(args[0], "enable-linger");
1279
for (i = 1; i < n; i++) {
1284
m = dbus_message_new_method_call(
1285
"org.freedesktop.login1",
1286
"/org/freedesktop/login1",
1287
"org.freedesktop.login1.Manager",
1290
log_error("Could not allocate message.");
1295
ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1297
log_error("Failed to resolve user %s: %s", args[i], strerror(-ret));
1302
if (!dbus_message_append_args(m,
1303
DBUS_TYPE_UINT32, &u,
1304
DBUS_TYPE_BOOLEAN, &b,
1305
DBUS_TYPE_BOOLEAN, &interactive,
1306
DBUS_TYPE_INVALID)) {
1307
log_error("Could not append arguments to message.");
1312
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1314
log_error("Failed to issue method call: %s", bus_error_message(&error));
1319
dbus_message_unref(m);
1320
dbus_message_unref(reply);
1328
dbus_message_unref(m);
1330
dbus_error_free(&error);
1335
static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
1336
DBusMessage *m = NULL;
1344
dbus_error_init(&error);
1346
for (i = 1; i < n; i++) {
1351
m = dbus_message_new_method_call(
1352
"org.freedesktop.login1",
1353
"/org/freedesktop/login1",
1354
"org.freedesktop.login1.Manager",
1357
log_error("Could not allocate message.");
1362
ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1364
log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
1369
if (!dbus_message_append_args(m,
1370
DBUS_TYPE_UINT32, &u,
1371
DBUS_TYPE_INVALID)) {
1372
log_error("Could not append arguments to message.");
1377
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1379
log_error("Failed to issue method call: %s", bus_error_message(&error));
1384
dbus_message_unref(m);
1385
dbus_message_unref(reply);
1393
dbus_message_unref(m);
1395
dbus_error_free(&error);
1400
static int kill_user(DBusConnection *bus, char **args, unsigned n) {
1401
DBusMessage *m = NULL;
1409
dbus_error_init(&error);
1412
arg_kill_who = "all";
1414
for (i = 1; i < n; i++) {
1419
m = dbus_message_new_method_call(
1420
"org.freedesktop.login1",
1421
"/org/freedesktop/login1",
1422
"org.freedesktop.login1.Manager",
1425
log_error("Could not allocate message.");
1430
ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1432
log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
1437
if (!dbus_message_append_args(m,
1438
DBUS_TYPE_UINT32, &u,
1439
DBUS_TYPE_INT32, arg_signal,
1440
DBUS_TYPE_INVALID)) {
1441
log_error("Could not append arguments to message.");
1446
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1448
log_error("Failed to issue method call: %s", bus_error_message(&error));
1453
dbus_message_unref(m);
1454
dbus_message_unref(reply);
1462
dbus_message_unref(m);
1464
dbus_error_free(&error);
1469
static int attach(DBusConnection *bus, char **args, unsigned n) {
1470
DBusMessage *m = NULL;
1474
dbus_bool_t interactive = true;
1479
dbus_error_init(&error);
1481
for (i = 2; i < n; i++) {
1484
m = dbus_message_new_method_call(
1485
"org.freedesktop.login1",
1486
"/org/freedesktop/login1",
1487
"org.freedesktop.login1.Manager",
1490
log_error("Could not allocate message.");
1495
if (!dbus_message_append_args(m,
1496
DBUS_TYPE_STRING, &args[1],
1497
DBUS_TYPE_STRING, &args[i],
1498
DBUS_TYPE_BOOLEAN, &interactive,
1499
DBUS_TYPE_INVALID)) {
1500
log_error("Could not append arguments to message.");
1505
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1507
log_error("Failed to issue method call: %s", bus_error_message(&error));
1512
dbus_message_unref(m);
1513
dbus_message_unref(reply);
1519
dbus_message_unref(m);
1521
dbus_error_free(&error);
1526
static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
1527
DBusMessage *m = NULL, *reply = NULL;
1530
dbus_bool_t interactive = true;
1535
dbus_error_init(&error);
1537
m = dbus_message_new_method_call(
1538
"org.freedesktop.login1",
1539
"/org/freedesktop/login1",
1540
"org.freedesktop.login1.Manager",
1543
log_error("Could not allocate message.");
1548
if (!dbus_message_append_args(m,
1549
DBUS_TYPE_BOOLEAN, &interactive,
1550
DBUS_TYPE_INVALID)) {
1551
log_error("Could not append arguments to message.");
1556
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1558
log_error("Failed to issue method call: %s", bus_error_message(&error));
1565
dbus_message_unref(m);
1568
dbus_message_unref(reply);
1570
dbus_error_free(&error);
1575
static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
1576
DBusMessage *m = NULL;
1584
dbus_error_init(&error);
1586
for (i = 1; i < n; i++) {
1589
m = dbus_message_new_method_call(
1590
"org.freedesktop.login1",
1591
"/org/freedesktop/login1",
1592
"org.freedesktop.login1.Manager",
1595
log_error("Could not allocate message.");
1600
if (!dbus_message_append_args(m,
1601
DBUS_TYPE_STRING, &args[i],
1602
DBUS_TYPE_INVALID)) {
1603
log_error("Could not append arguments to message.");
1608
reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1610
log_error("Failed to issue method call: %s", bus_error_message(&error));
1615
dbus_message_unref(m);
1616
dbus_message_unref(reply);
1622
dbus_message_unref(m);
1624
dbus_error_free(&error);
1629
static int help(void) {
1631
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1632
"Send control commands to or query the login manager.\n\n"
1633
" -h --help Show this help\n"
1634
" --version Show package version\n"
1635
" -p --property=NAME Show only properties by this name\n"
1636
" -a --all Show all properties, including empty ones\n"
1637
" --kill-who=WHO Who to send signal to\n"
1638
" -s --signal=SIGNAL Which signal to send\n"
1639
" -H --host=[USER@]HOST\n"
1640
" Show information for remote host\n"
1641
" -P --privileged Acquire privileges before execution\n"
1642
" --no-pager Do not pipe output into a pager\n\n"
1644
" list-sessions List sessions\n"
1645
" session-status [ID...] Show session status\n"
1646
" show-session [ID...] Show properties of one or more sessions\n"
1647
" activate [ID] Activate a session\n"
1648
" lock-session [ID...] Screen lock one or more sessions\n"
1649
" unlock-session [ID...] Screen unlock one or more sessions\n"
1650
" terminate-session [ID...] Terminate one or more sessions\n"
1651
" kill-session [ID...] Send signal to processes of a session\n"
1652
" list-users List users\n"
1653
" user-status [USER...] Show user status\n"
1654
" show-user [USER...] Show properties of one or more users\n"
1655
" enable-linger [USER...] Enable linger state of one or more users\n"
1656
" disable-linger [USER...] Disable linger state of one or more users\n"
1657
" terminate-user [USER...] Terminate all sessions of one or more users\n"
1658
" kill-user [USER...] Send signal to processes of a user\n"
1659
" list-seats List seats\n"
1660
" seat-status [NAME...] Show seat status\n"
1661
" show-seat [NAME...] Show properties of one or more seats\n"
1662
" attach [NAME] [DEVICE...] Attach one or more devices to a seat\n"
1663
" flush-devices Flush all device associations\n"
1664
" terminate-seat [NAME...] Terminate all sessions on one or more seats\n",
1665
program_invocation_short_name);
1670
static int parse_argv(int argc, char *argv[]) {
1673
ARG_VERSION = 0x100,
1678
static const struct option options[] = {
1679
{ "help", no_argument, NULL, 'h' },
1680
{ "version", no_argument, NULL, ARG_VERSION },
1681
{ "property", required_argument, NULL, 'p' },
1682
{ "all", no_argument, NULL, 'a' },
1683
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
1684
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
1685
{ "signal", required_argument, NULL, 's' },
1686
{ "host", required_argument, NULL, 'H' },
1687
{ "privileged",no_argument, NULL, 'P' },
1688
{ NULL, 0, NULL, 0 }
1696
while ((c = getopt_long(argc, argv, "hp:as:H:P", options, NULL)) >= 0) {
1705
puts(PACKAGE_STRING);
1707
puts(SYSTEMD_FEATURES);
1713
l = strv_append(arg_property, optarg);
1717
strv_free(arg_property);
1720
/* If the user asked for a particular
1721
* property, show it to him, even if it is
1732
arg_no_pager = true;
1736
arg_kill_who = optarg;
1740
arg_signal = signal_from_string_try_harder(optarg);
1741
if (arg_signal < 0) {
1742
log_error("Failed to parse signal string %s.", optarg);
1748
arg_transport = TRANSPORT_POLKIT;
1752
arg_transport = TRANSPORT_SSH;
1760
log_error("Unknown option code %c", c);
1768
static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
1770
static const struct {
1778
int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
1780
{ "list-sessions", LESS, 1, list_sessions },
1781
{ "session-status", MORE, 2, show },
1782
{ "show-session", MORE, 1, show },
1783
{ "activate", EQUAL, 2, activate },
1784
{ "lock-session", MORE, 2, activate },
1785
{ "unlock-session", MORE, 2, activate },
1786
{ "terminate-session", MORE, 2, activate },
1787
{ "kill-session", MORE, 2, kill_session },
1788
{ "list-users", EQUAL, 1, list_users },
1789
{ "user-status", MORE, 2, show },
1790
{ "show-user", MORE, 1, show },
1791
{ "enable-linger", MORE, 2, enable_linger },
1792
{ "disable-linger", MORE, 2, enable_linger },
1793
{ "terminate-user", MORE, 2, terminate_user },
1794
{ "kill-user", MORE, 2, kill_user },
1795
{ "list-seats", EQUAL, 1, list_seats },
1796
{ "seat-status", MORE, 2, show },
1797
{ "show-seat", MORE, 1, show },
1798
{ "attach", MORE, 3, attach },
1799
{ "flush-devices", EQUAL, 1, flush_devices },
1800
{ "terminate-seat", MORE, 2, terminate_seat },
1810
left = argc - optind;
1813
/* Special rule: no arguments means "list-sessions" */
1816
if (streq(argv[optind], "help")) {
1821
for (i = 0; i < ELEMENTSOF(verbs); i++)
1822
if (streq(argv[optind], verbs[i].verb))
1825
if (i >= ELEMENTSOF(verbs)) {
1826
log_error("Unknown operation %s", argv[optind]);
1831
switch (verbs[i].argc_cmp) {
1834
if (left != verbs[i].argc) {
1835
log_error("Invalid number of arguments.");
1842
if (left < verbs[i].argc) {
1843
log_error("Too few arguments.");
1850
if (left > verbs[i].argc) {
1851
log_error("Too many arguments.");
1858
assert_not_reached("Unknown comparison operator.");
1862
log_error("Failed to get D-Bus connection: %s", error->message);
1866
return verbs[i].dispatch(bus, argv + optind, left);
1869
int main(int argc, char*argv[]) {
1870
int r, retval = EXIT_FAILURE;
1871
DBusConnection *bus = NULL;
1874
dbus_error_init(&error);
1876
log_parse_environment();
1879
r = parse_argv(argc, argv);
1883
retval = EXIT_SUCCESS;
1887
if (arg_transport == TRANSPORT_NORMAL)
1888
bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
1889
else if (arg_transport == TRANSPORT_POLKIT)
1890
bus_connect_system_polkit(&bus, &error);
1891
else if (arg_transport == TRANSPORT_SSH)
1892
bus_connect_system_ssh(NULL, arg_host, &bus, &error);
1894
assert_not_reached("Uh, invalid transport...");
1896
r = loginctl_main(bus, argc, argv, &error);
1897
retval = r < 0 ? EXIT_FAILURE : r;
1901
dbus_connection_flush(bus);
1902
dbus_connection_close(bus);
1903
dbus_connection_unref(bus);
1906
dbus_error_free(&error);
1909
strv_free(arg_property);