~ubuntu-branches/debian/jessie/systemd/jessie

« back to all changes in this revision

Viewing changes to src/loginctl.c

  • Committer: Package Import Robot
  • Author(s): Tollef Fog Heen, Tollef Fog Heen, Michael Biebl
  • Date: 2012-04-03 19:59:17 UTC
  • mfrom: (1.1.10) (6.1.3 experimental)
  • Revision ID: package-import@ubuntu.com-20120403195917-l532urrbg4pkreas
Tags: 44-1
[ Tollef Fog Heen ]
* New upstream version.
  - Backport 3492207: journal: PAGE_SIZE is not known on ppc and other
    archs
  - Backport 5a2a2a1: journal: react with immediate rotation to a couple
    of more errors
  - Backport 693ce21: util: never follow symlinks in rm_rf_children()
    Fixes CVE-2012-1174, closes: #664364
* Drop output message from init-functions hook, it's pointless.
* Only rmdir /lib/init/rw if it exists.
* Explicitly order debian-fixup before sysinit.target to prevent a
  possible race condition with the creation of sockets.  Thanks to
  Michael Biebl for debugging this.
* Always restart the initctl socket on upgrades, to mask sysvinit
  removing it.

[ Michael Biebl ]
* Remove workaround for non-interactive sessions from pam config again.
* Create compat /dev/initctl symlink in case we are upgrading from a system
  running a newer version of sysvinit (using /run/initctl) and sysvinit is
  replaced with systemd-sysv during the upgrade. Closes: #663219
* Install new man pages.
* Build-Depend on valac (>= 0.12) instead of valac-0.12. Closes: #663323

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
 
 
3
 
/***
4
 
  This file is part of systemd.
5
 
 
6
 
  Copyright 2010 Lennart Poettering
7
 
 
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.
12
 
 
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.
17
 
 
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/>.
20
 
***/
21
 
 
22
 
#include <dbus/dbus.h>
23
 
#include <unistd.h>
24
 
#include <errno.h>
25
 
#include <string.h>
26
 
#include <getopt.h>
27
 
#include <pwd.h>
28
 
 
29
 
#include "log.h"
30
 
#include "util.h"
31
 
#include "macro.h"
32
 
#include "pager.h"
33
 
#include "dbus-common.h"
34
 
#include "build.h"
35
 
#include "strv.h"
36
 
#include "cgroup-show.h"
37
 
#include "sysfs-show.h"
38
 
 
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 {
45
 
        TRANSPORT_NORMAL,
46
 
        TRANSPORT_SSH,
47
 
        TRANSPORT_POLKIT
48
 
} arg_transport = TRANSPORT_NORMAL;
49
 
static const char *arg_host = NULL;
50
 
 
51
 
static bool on_tty(void) {
52
 
        static int t = -1;
53
 
 
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. */
59
 
 
60
 
        if (_unlikely_(t < 0))
61
 
                t = isatty(STDOUT_FILENO) > 0;
62
 
 
63
 
        return t;
64
 
}
65
 
 
66
 
static void pager_open_if_enabled(void) {
67
 
 
68
 
        /* Cache result before we open the pager */
69
 
        on_tty();
70
 
 
71
 
        if (!arg_no_pager)
72
 
                pager_open();
73
 
}
74
 
 
75
 
static int list_sessions(DBusConnection *bus, char **args, unsigned n) {
76
 
        DBusMessage *m = NULL, *reply = NULL;
77
 
        DBusError error;
78
 
        int r;
79
 
        DBusMessageIter iter, sub, sub2;
80
 
        unsigned k = 0;
81
 
 
82
 
        dbus_error_init(&error);
83
 
 
84
 
        assert(bus);
85
 
 
86
 
        pager_open_if_enabled();
87
 
 
88
 
        m = dbus_message_new_method_call(
89
 
                        "org.freedesktop.login1",
90
 
                        "/org/freedesktop/login1",
91
 
                        "org.freedesktop.login1.Manager",
92
 
                        "ListSessions");
93
 
        if (!m) {
94
 
                log_error("Could not allocate message.");
95
 
                return -ENOMEM;
96
 
        }
97
 
 
98
 
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
99
 
        if (!reply) {
100
 
                log_error("Failed to issue method call: %s", bus_error_message(&error));
101
 
                r = -EIO;
102
 
                goto finish;
103
 
        }
104
 
 
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.");
109
 
                r = -EIO;
110
 
                goto finish;
111
 
        }
112
 
 
113
 
        dbus_message_iter_recurse(&iter, &sub);
114
 
 
115
 
        if (on_tty())
116
 
                printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
117
 
 
118
 
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
119
 
                const char *id, *user, *seat, *object;
120
 
                uint32_t uid;
121
 
 
122
 
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
123
 
                        log_error("Failed to parse reply.");
124
 
                        r = -EIO;
125
 
                        goto finish;
126
 
                }
127
 
 
128
 
                dbus_message_iter_recurse(&sub, &sub2);
129
 
 
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.");
136
 
                        r = -EIO;
137
 
                        goto finish;
138
 
                }
139
 
 
140
 
                printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
141
 
 
142
 
                k++;
143
 
 
144
 
                dbus_message_iter_next(&sub);
145
 
        }
146
 
 
147
 
        if (on_tty())
148
 
                printf("\n%u sessions listed.\n", k);
149
 
 
150
 
        r = 0;
151
 
 
152
 
finish:
153
 
        if (m)
154
 
                dbus_message_unref(m);
155
 
 
156
 
        if (reply)
157
 
                dbus_message_unref(reply);
158
 
 
159
 
        dbus_error_free(&error);
160
 
 
161
 
        return r;
162
 
}
163
 
 
164
 
static int list_users(DBusConnection *bus, char **args, unsigned n) {
165
 
        DBusMessage *m = NULL, *reply = NULL;
166
 
        DBusError error;
167
 
        int r;
168
 
        DBusMessageIter iter, sub, sub2;
169
 
        unsigned k = 0;
170
 
 
171
 
        dbus_error_init(&error);
172
 
 
173
 
        assert(bus);
174
 
 
175
 
        pager_open_if_enabled();
176
 
 
177
 
        m = dbus_message_new_method_call(
178
 
                        "org.freedesktop.login1",
179
 
                        "/org/freedesktop/login1",
180
 
                        "org.freedesktop.login1.Manager",
181
 
                        "ListUsers");
182
 
        if (!m) {
183
 
                log_error("Could not allocate message.");
184
 
                return -ENOMEM;
185
 
        }
186
 
 
187
 
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
188
 
        if (!reply) {
189
 
                log_error("Failed to issue method call: %s", bus_error_message(&error));
190
 
                r = -EIO;
191
 
                goto finish;
192
 
        }
193
 
 
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.");
198
 
                r = -EIO;
199
 
                goto finish;
200
 
        }
201
 
 
202
 
        dbus_message_iter_recurse(&iter, &sub);
203
 
 
204
 
        if (on_tty())
205
 
                printf("%10s %-16s\n", "UID", "USER");
206
 
 
207
 
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
208
 
                const char *user, *object;
209
 
                uint32_t uid;
210
 
 
211
 
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
212
 
                        log_error("Failed to parse reply.");
213
 
                        r = -EIO;
214
 
                        goto finish;
215
 
                }
216
 
 
217
 
                dbus_message_iter_recurse(&sub, &sub2);
218
 
 
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.");
223
 
                        r = -EIO;
224
 
                        goto finish;
225
 
                }
226
 
 
227
 
                printf("%10u %-16s\n", (unsigned) uid, user);
228
 
 
229
 
                k++;
230
 
 
231
 
                dbus_message_iter_next(&sub);
232
 
        }
233
 
 
234
 
        if (on_tty())
235
 
                printf("\n%u users listed.\n", k);
236
 
 
237
 
        r = 0;
238
 
 
239
 
finish:
240
 
        if (m)
241
 
                dbus_message_unref(m);
242
 
 
243
 
        if (reply)
244
 
                dbus_message_unref(reply);
245
 
 
246
 
        dbus_error_free(&error);
247
 
 
248
 
        return r;
249
 
}
250
 
 
251
 
static int list_seats(DBusConnection *bus, char **args, unsigned n) {
252
 
        DBusMessage *m = NULL, *reply = NULL;
253
 
        DBusError error;
254
 
        int r;
255
 
        DBusMessageIter iter, sub, sub2;
256
 
        unsigned k = 0;
257
 
 
258
 
        dbus_error_init(&error);
259
 
 
260
 
        assert(bus);
261
 
 
262
 
        pager_open_if_enabled();
263
 
 
264
 
        m = dbus_message_new_method_call(
265
 
                        "org.freedesktop.login1",
266
 
                        "/org/freedesktop/login1",
267
 
                        "org.freedesktop.login1.Manager",
268
 
                        "ListSeats");
269
 
        if (!m) {
270
 
                log_error("Could not allocate message.");
271
 
                return -ENOMEM;
272
 
        }
273
 
 
274
 
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
275
 
        if (!reply) {
276
 
                log_error("Failed to issue method call: %s", bus_error_message(&error));
277
 
                r = -EIO;
278
 
                goto finish;
279
 
        }
280
 
 
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.");
285
 
                r = -EIO;
286
 
                goto finish;
287
 
        }
288
 
 
289
 
        dbus_message_iter_recurse(&iter, &sub);
290
 
 
291
 
        if (on_tty())
292
 
                printf("%-16s\n", "SEAT");
293
 
 
294
 
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
295
 
                const char *seat, *object;
296
 
 
297
 
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
298
 
                        log_error("Failed to parse reply.");
299
 
                        r = -EIO;
300
 
                        goto finish;
301
 
                }
302
 
 
303
 
                dbus_message_iter_recurse(&sub, &sub2);
304
 
 
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.");
308
 
                        r = -EIO;
309
 
                        goto finish;
310
 
                }
311
 
 
312
 
                printf("%-16s\n", seat);
313
 
 
314
 
                k++;
315
 
 
316
 
                dbus_message_iter_next(&sub);
317
 
        }
318
 
 
319
 
        if (on_tty())
320
 
                printf("\n%u seats listed.\n", k);
321
 
 
322
 
        r = 0;
323
 
 
324
 
finish:
325
 
        if (m)
326
 
                dbus_message_unref(m);
327
 
 
328
 
        if (reply)
329
 
                dbus_message_unref(reply);
330
 
 
331
 
        dbus_error_free(&error);
332
 
 
333
 
        return r;
334
 
}
335
 
 
336
 
typedef struct SessionStatusInfo {
337
 
        const char *id;
338
 
        uid_t uid;
339
 
        const char *name;
340
 
        usec_t timestamp;
341
 
        const char *control_group;
342
 
        int vtnr;
343
 
        const char *seat;
344
 
        const char *tty;
345
 
        const char *display;
346
 
        bool remote;
347
 
        const char *remote_host;
348
 
        const char *remote_user;
349
 
        const char *service;
350
 
        pid_t leader;
351
 
        const char *type;
352
 
        bool active;
353
 
} SessionStatusInfo;
354
 
 
355
 
typedef struct UserStatusInfo {
356
 
        uid_t uid;
357
 
        const char *name;
358
 
        usec_t timestamp;
359
 
        const char *control_group;
360
 
        const char *state;
361
 
        char **sessions;
362
 
        const char *display;
363
 
} UserStatusInfo;
364
 
 
365
 
typedef struct SeatStatusInfo {
366
 
        const char *id;
367
 
        const char *active_session;
368
 
        char **sessions;
369
 
} SeatStatusInfo;
370
 
 
371
 
static void print_session_status_info(SessionStatusInfo *i) {
372
 
        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
373
 
        char since2[FORMAT_TIMESTAMP_MAX], *s2;
374
 
        assert(i);
375
 
 
376
 
        printf("%s - ", strna(i->id));
377
 
 
378
 
        if (i->name)
379
 
                printf("%s (%u)\n", i->name, (unsigned) i->uid);
380
 
        else
381
 
                printf("%u\n", (unsigned) i->uid);
382
 
 
383
 
        s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
384
 
        s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
385
 
 
386
 
        if (s1)
387
 
                printf("\t   Since: %s; %s\n", s2, s1);
388
 
        else if (s2)
389
 
                printf("\t   Since: %s\n", s2);
390
 
 
391
 
        if (i->leader > 0) {
392
 
                char *t = NULL;
393
 
 
394
 
                printf("\t  Leader: %u", (unsigned) i->leader);
395
 
 
396
 
                get_process_name(i->leader, &t);
397
 
                if (t) {
398
 
                        printf(" (%s)", t);
399
 
                        free(t);
400
 
                }
401
 
 
402
 
                printf("\n");
403
 
        }
404
 
 
405
 
        if (i->seat) {
406
 
                printf("\t    Seat: %s", i->seat);
407
 
 
408
 
                if (i->vtnr > 0)
409
 
                        printf("; vc%i", i->vtnr);
410
 
 
411
 
                printf("\n");
412
 
        }
413
 
 
414
 
        if (i->tty)
415
 
                printf("\t     TTY: %s\n", i->tty);
416
 
        else if (i->display)
417
 
                printf("\t Display: %s\n", i->display);
418
 
 
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);
425
 
        else if (i->remote)
426
 
                printf("\t  Remote: Yes\n");
427
 
 
428
 
        if (i->service) {
429
 
                printf("\t Service: %s", i->service);
430
 
 
431
 
                if (i->type)
432
 
                        printf("; type %s", i->type);
433
 
 
434
 
                printf("\n");
435
 
        } else if (i->type)
436
 
                printf("\t    Type: %s\n", i->type);
437
 
 
438
 
        printf("\t  Active: %s\n", yes_no(i->active));
439
 
 
440
 
        if (i->control_group) {
441
 
                unsigned c;
442
 
 
443
 
                printf("\t  CGroup: %s\n", i->control_group);
444
 
 
445
 
                if (arg_transport != TRANSPORT_SSH) {
446
 
                        c = columns();
447
 
                        if (c > 18)
448
 
                                c -= 18;
449
 
                        else
450
 
                                c = 0;
451
 
 
452
 
                        show_cgroup_by_path(i->control_group, "\t\t  ", c);
453
 
                }
454
 
        }
455
 
}
456
 
 
457
 
static void print_user_status_info(UserStatusInfo *i) {
458
 
        char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
459
 
        char since2[FORMAT_TIMESTAMP_MAX], *s2;
460
 
        assert(i);
461
 
 
462
 
        if (i->name)
463
 
                printf("%s (%u)\n", i->name, (unsigned) i->uid);
464
 
        else
465
 
                printf("%u\n", (unsigned) i->uid);
466
 
 
467
 
        s1 = format_timestamp_pretty(since1, sizeof(since1), i->timestamp);
468
 
        s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
469
 
 
470
 
        if (s1)
471
 
                printf("\t   Since: %s; %s\n", s2, s1);
472
 
        else if (s2)
473
 
                printf("\t   Since: %s\n", s2);
474
 
 
475
 
        if (!isempty(i->state))
476
 
                printf("\t   State: %s\n", i->state);
477
 
 
478
 
        if (!strv_isempty(i->sessions)) {
479
 
                char **l;
480
 
                printf("\tSessions:");
481
 
 
482
 
                STRV_FOREACH(l, i->sessions) {
483
 
                        if (streq_ptr(*l, i->display))
484
 
                                printf(" *%s", *l);
485
 
                        else
486
 
                                printf(" %s", *l);
487
 
                }
488
 
 
489
 
                printf("\n");
490
 
        }
491
 
 
492
 
        if (i->control_group) {
493
 
                unsigned c;
494
 
 
495
 
                printf("\t  CGroup: %s\n", i->control_group);
496
 
 
497
 
                if (arg_transport != TRANSPORT_SSH) {
498
 
                        c = columns();
499
 
                        if (c > 18)
500
 
                                c -= 18;
501
 
                        else
502
 
                                c = 0;
503
 
 
504
 
                        show_cgroup_by_path(i->control_group, "\t\t  ", c);
505
 
                }
506
 
        }
507
 
}
508
 
 
509
 
static void print_seat_status_info(SeatStatusInfo *i) {
510
 
        assert(i);
511
 
 
512
 
        printf("%s\n", strna(i->id));
513
 
 
514
 
        if (!strv_isempty(i->sessions)) {
515
 
                char **l;
516
 
                printf("\tSessions:");
517
 
 
518
 
                STRV_FOREACH(l, i->sessions) {
519
 
                        if (streq_ptr(*l, i->active_session))
520
 
                                printf(" *%s", *l);
521
 
                        else
522
 
                                printf(" %s", *l);
523
 
                }
524
 
 
525
 
                printf("\n");
526
 
        }
527
 
 
528
 
        if (arg_transport != TRANSPORT_SSH) {
529
 
                unsigned c;
530
 
 
531
 
                c = columns();
532
 
                if (c > 21)
533
 
                        c -= 21;
534
 
                else
535
 
                        c = 0;
536
 
 
537
 
                printf("\t Devices:\n");
538
 
 
539
 
                show_sysfs(i->id, "\t\t  ", c);
540
 
        }
541
 
}
542
 
 
543
 
static int status_property_session(const char *name, DBusMessageIter *iter, SessionStatusInfo *i) {
544
 
        assert(name);
545
 
        assert(iter);
546
 
        assert(i);
547
 
 
548
 
        switch (dbus_message_iter_get_arg_type(iter)) {
549
 
 
550
 
        case DBUS_TYPE_STRING: {
551
 
                const char *s;
552
 
 
553
 
                dbus_message_iter_get_basic(iter, &s);
554
 
 
555
 
                if (!isempty(s)) {
556
 
                        if (streq(name, "Id"))
557
 
                                i->id = s;
558
 
                        else if (streq(name, "Name"))
559
 
                                i->name = s;
560
 
                        else if (streq(name, "ControlGroupPath"))
561
 
                                i->control_group = s;
562
 
                        else if (streq(name, "TTY"))
563
 
                                i->tty = s;
564
 
                        else if (streq(name, "Display"))
565
 
                                i->display = s;
566
 
                        else if (streq(name, "RemoteHost"))
567
 
                                i->remote_host = s;
568
 
                        else if (streq(name, "RemoteUser"))
569
 
                                i->remote_user = s;
570
 
                        else if (streq(name, "Service"))
571
 
                                i->service = s;
572
 
                        else if (streq(name, "Type"))
573
 
                                i->type = s;
574
 
                }
575
 
                break;
576
 
        }
577
 
 
578
 
        case DBUS_TYPE_UINT32: {
579
 
                uint32_t u;
580
 
 
581
 
                dbus_message_iter_get_basic(iter, &u);
582
 
 
583
 
                if (streq(name, "VTNr"))
584
 
                        i->vtnr = (int) u;
585
 
                else if (streq(name, "Leader"))
586
 
                        i->leader = (pid_t) u;
587
 
 
588
 
                break;
589
 
        }
590
 
 
591
 
        case DBUS_TYPE_BOOLEAN: {
592
 
                dbus_bool_t b;
593
 
 
594
 
                dbus_message_iter_get_basic(iter, &b);
595
 
 
596
 
                if (streq(name, "Remote"))
597
 
                        i->remote = b;
598
 
                else if (streq(name, "Active"))
599
 
                        i->active = b;
600
 
 
601
 
                break;
602
 
        }
603
 
 
604
 
        case DBUS_TYPE_UINT64: {
605
 
                uint64_t u;
606
 
 
607
 
                dbus_message_iter_get_basic(iter, &u);
608
 
 
609
 
                if (streq(name, "Timestamp"))
610
 
                        i->timestamp = (usec_t) u;
611
 
 
612
 
                break;
613
 
        }
614
 
 
615
 
        case DBUS_TYPE_STRUCT: {
616
 
                DBusMessageIter sub;
617
 
 
618
 
                dbus_message_iter_recurse(iter, &sub);
619
 
 
620
 
                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "User")) {
621
 
                        uint32_t u;
622
 
 
623
 
                        dbus_message_iter_get_basic(&sub, &u);
624
 
                        i->uid = (uid_t) u;
625
 
 
626
 
                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Seat")) {
627
 
                        const char *s;
628
 
 
629
 
                        dbus_message_iter_get_basic(&sub, &s);
630
 
 
631
 
                        if (!isempty(s))
632
 
                                i->seat = s;
633
 
                }
634
 
 
635
 
                break;
636
 
        }
637
 
        }
638
 
 
639
 
        return 0;
640
 
}
641
 
 
642
 
static int status_property_user(const char *name, DBusMessageIter *iter, UserStatusInfo *i) {
643
 
        assert(name);
644
 
        assert(iter);
645
 
        assert(i);
646
 
 
647
 
        switch (dbus_message_iter_get_arg_type(iter)) {
648
 
 
649
 
        case DBUS_TYPE_STRING: {
650
 
                const char *s;
651
 
 
652
 
                dbus_message_iter_get_basic(iter, &s);
653
 
 
654
 
                if (!isempty(s)) {
655
 
                        if (streq(name, "Name"))
656
 
                                i->name = s;
657
 
                        else if (streq(name, "ControlGroupPath"))
658
 
                                i->control_group = s;
659
 
                        else if (streq(name, "State"))
660
 
                                i->state = s;
661
 
                }
662
 
                break;
663
 
        }
664
 
 
665
 
        case DBUS_TYPE_UINT32: {
666
 
                uint32_t u;
667
 
 
668
 
                dbus_message_iter_get_basic(iter, &u);
669
 
 
670
 
                if (streq(name, "UID"))
671
 
                        i->uid = (uid_t) u;
672
 
 
673
 
                break;
674
 
        }
675
 
 
676
 
        case DBUS_TYPE_UINT64: {
677
 
                uint64_t u;
678
 
 
679
 
                dbus_message_iter_get_basic(iter, &u);
680
 
 
681
 
                if (streq(name, "Timestamp"))
682
 
                        i->timestamp = (usec_t) u;
683
 
 
684
 
                break;
685
 
        }
686
 
 
687
 
        case DBUS_TYPE_STRUCT: {
688
 
                DBusMessageIter sub;
689
 
 
690
 
                dbus_message_iter_recurse(iter, &sub);
691
 
 
692
 
                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Display")) {
693
 
                        const char *s;
694
 
 
695
 
                        dbus_message_iter_get_basic(&sub, &s);
696
 
 
697
 
                        if (!isempty(s))
698
 
                                i->display = s;
699
 
                }
700
 
 
701
 
                break;
702
 
        }
703
 
 
704
 
        case DBUS_TYPE_ARRAY: {
705
 
 
706
 
                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
707
 
                        DBusMessageIter sub, sub2;
708
 
 
709
 
                        dbus_message_iter_recurse(iter, &sub);
710
 
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
711
 
                                const char *id;
712
 
                                const char *path;
713
 
 
714
 
                                dbus_message_iter_recurse(&sub, &sub2);
715
 
 
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) {
718
 
                                        char **l;
719
 
 
720
 
                                        l = strv_append(i->sessions, id);
721
 
                                        if (!l)
722
 
                                                return -ENOMEM;
723
 
 
724
 
                                        strv_free(i->sessions);
725
 
                                        i->sessions = l;
726
 
                                }
727
 
 
728
 
                                dbus_message_iter_next(&sub);
729
 
                        }
730
 
 
731
 
                        return 0;
732
 
                }
733
 
        }
734
 
        }
735
 
 
736
 
        return 0;
737
 
}
738
 
 
739
 
static int status_property_seat(const char *name, DBusMessageIter *iter, SeatStatusInfo *i) {
740
 
        assert(name);
741
 
        assert(iter);
742
 
        assert(i);
743
 
 
744
 
        switch (dbus_message_iter_get_arg_type(iter)) {
745
 
 
746
 
        case DBUS_TYPE_STRING: {
747
 
                const char *s;
748
 
 
749
 
                dbus_message_iter_get_basic(iter, &s);
750
 
 
751
 
                if (!isempty(s)) {
752
 
                        if (streq(name, "Id"))
753
 
                                i->id = s;
754
 
                }
755
 
                break;
756
 
        }
757
 
 
758
 
        case DBUS_TYPE_STRUCT: {
759
 
                DBusMessageIter sub;
760
 
 
761
 
                dbus_message_iter_recurse(iter, &sub);
762
 
 
763
 
                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "ActiveSession")) {
764
 
                        const char *s;
765
 
 
766
 
                        dbus_message_iter_get_basic(&sub, &s);
767
 
 
768
 
                        if (!isempty(s))
769
 
                                i->active_session = s;
770
 
                }
771
 
 
772
 
                break;
773
 
        }
774
 
 
775
 
        case DBUS_TYPE_ARRAY: {
776
 
 
777
 
                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
778
 
                        DBusMessageIter sub, sub2;
779
 
 
780
 
                        dbus_message_iter_recurse(iter, &sub);
781
 
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
782
 
                                const char *id;
783
 
                                const char *path;
784
 
 
785
 
                                dbus_message_iter_recurse(&sub, &sub2);
786
 
 
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) {
789
 
                                        char **l;
790
 
 
791
 
                                        l = strv_append(i->sessions, id);
792
 
                                        if (!l)
793
 
                                                return -ENOMEM;
794
 
 
795
 
                                        strv_free(i->sessions);
796
 
                                        i->sessions = l;
797
 
                                }
798
 
 
799
 
                                dbus_message_iter_next(&sub);
800
 
                        }
801
 
 
802
 
                        return 0;
803
 
                }
804
 
        }
805
 
        }
806
 
 
807
 
        return 0;
808
 
}
809
 
 
810
 
static int print_property(const char *name, DBusMessageIter *iter) {
811
 
        assert(name);
812
 
        assert(iter);
813
 
 
814
 
        if (arg_property && !strv_find(arg_property, name))
815
 
                return 0;
816
 
 
817
 
        switch (dbus_message_iter_get_arg_type(iter)) {
818
 
 
819
 
        case DBUS_TYPE_STRUCT: {
820
 
                DBusMessageIter sub;
821
 
 
822
 
                dbus_message_iter_recurse(iter, &sub);
823
 
 
824
 
                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING &&
825
 
                    (streq(name, "Display") || streq(name, "ActiveSession"))) {
826
 
                        const char *s;
827
 
 
828
 
                        dbus_message_iter_get_basic(&sub, &s);
829
 
 
830
 
                        if (arg_all || !isempty(s))
831
 
                                printf("%s=%s\n", name, s);
832
 
                        return 0;
833
 
                }
834
 
                break;
835
 
        }
836
 
 
837
 
        case DBUS_TYPE_ARRAY:
838
 
 
839
 
                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Sessions")) {
840
 
                        DBusMessageIter sub, sub2;
841
 
                        bool found = false;
842
 
 
843
 
                        dbus_message_iter_recurse(iter, &sub);
844
 
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
845
 
                                const char *id;
846
 
                                const char *path;
847
 
 
848
 
                                dbus_message_iter_recurse(&sub, &sub2);
849
 
 
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) {
852
 
                                        if (found)
853
 
                                                printf(" %s", id);
854
 
                                        else {
855
 
                                                printf("%s=%s", name, id);
856
 
                                                found = true;
857
 
                                        }
858
 
                                }
859
 
 
860
 
                                dbus_message_iter_next(&sub);
861
 
                        }
862
 
 
863
 
                        if (!found && arg_all)
864
 
                                printf("%s=\n", name);
865
 
                        else if (found)
866
 
                                printf("\n");
867
 
 
868
 
                        return 0;
869
 
                }
870
 
 
871
 
                break;
872
 
        }
873
 
 
874
 
        if (generic_print_property(name, iter, arg_all) > 0)
875
 
                return 0;
876
 
 
877
 
        if (arg_all)
878
 
                printf("%s=[unprintable]\n", name);
879
 
 
880
 
        return 0;
881
 
}
882
 
 
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 = "";
886
 
        int r;
887
 
        DBusError error;
888
 
        DBusMessageIter iter, sub, sub2, sub3;
889
 
        SessionStatusInfo session_info;
890
 
        UserStatusInfo user_info;
891
 
        SeatStatusInfo seat_info;
892
 
 
893
 
        assert(bus);
894
 
        assert(path);
895
 
        assert(new_line);
896
 
 
897
 
        zero(session_info);
898
 
        zero(user_info);
899
 
        zero(seat_info);
900
 
 
901
 
        dbus_error_init(&error);
902
 
 
903
 
        m = dbus_message_new_method_call(
904
 
                        "org.freedesktop.login1",
905
 
                        path,
906
 
                        "org.freedesktop.DBus.Properties",
907
 
                        "GetAll");
908
 
        if (!m) {
909
 
                log_error("Could not allocate message.");
910
 
                r = -ENOMEM;
911
 
                goto finish;
912
 
        }
913
 
 
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.");
918
 
                r = -ENOMEM;
919
 
                goto finish;
920
 
        }
921
 
 
922
 
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
923
 
        if (!reply) {
924
 
                log_error("Failed to issue method call: %s", bus_error_message(&error));
925
 
                r = -EIO;
926
 
                goto finish;
927
 
        }
928
 
 
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.");
933
 
                r = -EIO;
934
 
                goto finish;
935
 
        }
936
 
 
937
 
        dbus_message_iter_recurse(&iter, &sub);
938
 
 
939
 
        if (*new_line)
940
 
                printf("\n");
941
 
 
942
 
        *new_line = true;
943
 
 
944
 
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
945
 
                const char *name;
946
 
 
947
 
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
948
 
                        log_error("Failed to parse reply.");
949
 
                        r = -EIO;
950
 
                        goto finish;
951
 
                }
952
 
 
953
 
                dbus_message_iter_recurse(&sub, &sub2);
954
 
 
955
 
                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
956
 
                        log_error("Failed to parse reply.");
957
 
                        r = -EIO;
958
 
                        goto finish;
959
 
                }
960
 
 
961
 
                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT)  {
962
 
                        log_error("Failed to parse reply.");
963
 
                        r = -EIO;
964
 
                        goto finish;
965
 
                }
966
 
 
967
 
                dbus_message_iter_recurse(&sub2, &sub3);
968
 
 
969
 
                if (show_properties)
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);
975
 
                else
976
 
                        r = status_property_seat(name, &sub3, &seat_info);
977
 
 
978
 
                if (r < 0) {
979
 
                        log_error("Failed to parse reply.");
980
 
                        r = -EIO;
981
 
                        goto finish;
982
 
                }
983
 
 
984
 
                dbus_message_iter_next(&sub);
985
 
        }
986
 
 
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);
992
 
                else
993
 
                        print_seat_status_info(&seat_info);
994
 
        }
995
 
 
996
 
        strv_free(seat_info.sessions);
997
 
        strv_free(user_info.sessions);
998
 
 
999
 
        r = 0;
1000
 
 
1001
 
finish:
1002
 
        if (m)
1003
 
                dbus_message_unref(m);
1004
 
 
1005
 
        if (reply)
1006
 
                dbus_message_unref(reply);
1007
 
 
1008
 
        dbus_error_free(&error);
1009
 
 
1010
 
        return r;
1011
 
}
1012
 
 
1013
 
static int show(DBusConnection *bus, char **args, unsigned n) {
1014
 
        DBusMessage *m = NULL, *reply = NULL;
1015
 
        int r, ret = 0;
1016
 
        DBusError error;
1017
 
        unsigned i;
1018
 
        bool show_properties, new_line = false;
1019
 
 
1020
 
        assert(bus);
1021
 
        assert(args);
1022
 
 
1023
 
        dbus_error_init(&error);
1024
 
 
1025
 
        show_properties = !strstr(args[0], "status");
1026
 
 
1027
 
        if (show_properties)
1028
 
                pager_open_if_enabled();
1029
 
 
1030
 
        if (show_properties && n <= 1) {
1031
 
                /* If not argument is specified inspect the manager
1032
 
                 * itself */
1033
 
 
1034
 
                ret = show_one(args[0], bus, "/org/freedesktop/login1", show_properties, &new_line);
1035
 
                goto finish;
1036
 
        }
1037
 
 
1038
 
        for (i = 1; i < n; i++) {
1039
 
                const char *path = NULL;
1040
 
 
1041
 
                if (strstr(args[0], "session")) {
1042
 
 
1043
 
                        m = dbus_message_new_method_call(
1044
 
                                        "org.freedesktop.login1",
1045
 
                                        "/org/freedesktop/login1",
1046
 
                                        "org.freedesktop.login1.Manager",
1047
 
                                        "GetSession");
1048
 
                        if (!m) {
1049
 
                                log_error("Could not allocate message.");
1050
 
                                ret = -ENOMEM;
1051
 
                                goto finish;
1052
 
                        }
1053
 
 
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.");
1058
 
                                ret = -ENOMEM;
1059
 
                                goto finish;
1060
 
                        }
1061
 
 
1062
 
                } else if (strstr(args[0], "user")) {
1063
 
                        uid_t uid;
1064
 
                        uint32_t u;
1065
 
 
1066
 
                        ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1067
 
                        if (ret < 0) {
1068
 
                                log_error("User %s unknown.", args[i]);
1069
 
                                goto finish;
1070
 
                        }
1071
 
 
1072
 
                        m = dbus_message_new_method_call(
1073
 
                                        "org.freedesktop.login1",
1074
 
                                        "/org/freedesktop/login1",
1075
 
                                        "org.freedesktop.login1.Manager",
1076
 
                                        "GetUser");
1077
 
                        if (!m) {
1078
 
                                log_error("Could not allocate message.");
1079
 
                                ret = -ENOMEM;
1080
 
                                goto finish;
1081
 
                        }
1082
 
 
1083
 
                        u = (uint32_t) uid;
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.");
1088
 
                                ret = -ENOMEM;
1089
 
                                goto finish;
1090
 
                        }
1091
 
                } else {
1092
 
 
1093
 
                        m = dbus_message_new_method_call(
1094
 
                                        "org.freedesktop.login1",
1095
 
                                        "/org/freedesktop/login1",
1096
 
                                        "org.freedesktop.login1.Manager",
1097
 
                                        "GetSeat");
1098
 
                        if (!m) {
1099
 
                                log_error("Could not allocate message.");
1100
 
                                ret = -ENOMEM;
1101
 
                                goto finish;
1102
 
                        }
1103
 
 
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.");
1108
 
                                ret = -ENOMEM;
1109
 
                                goto finish;
1110
 
                        }
1111
 
                }
1112
 
 
1113
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1114
 
                if (!reply) {
1115
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1116
 
                        ret = -EIO;
1117
 
                        goto finish;
1118
 
                }
1119
 
 
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));
1124
 
                        ret = -EIO;
1125
 
                        goto finish;
1126
 
                }
1127
 
 
1128
 
                r = show_one(args[0], bus, path, show_properties, &new_line);
1129
 
                if (r != 0)
1130
 
                        ret = r;
1131
 
 
1132
 
                dbus_message_unref(m);
1133
 
                dbus_message_unref(reply);
1134
 
                m = reply = NULL;
1135
 
        }
1136
 
 
1137
 
finish:
1138
 
        if (m)
1139
 
                dbus_message_unref(m);
1140
 
 
1141
 
        if (reply)
1142
 
                dbus_message_unref(reply);
1143
 
 
1144
 
        dbus_error_free(&error);
1145
 
 
1146
 
        return ret;
1147
 
}
1148
 
 
1149
 
static int activate(DBusConnection *bus, char **args, unsigned n) {
1150
 
        DBusMessage *m = NULL;
1151
 
        int ret = 0;
1152
 
        DBusError error;
1153
 
        unsigned i;
1154
 
 
1155
 
        assert(bus);
1156
 
        assert(args);
1157
 
 
1158
 
        dbus_error_init(&error);
1159
 
 
1160
 
        for (i = 1; i < n; i++) {
1161
 
                DBusMessage *reply;
1162
 
 
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" :
1170
 
                                                                      "ActivateSession");
1171
 
                if (!m) {
1172
 
                        log_error("Could not allocate message.");
1173
 
                        ret = -ENOMEM;
1174
 
                        goto finish;
1175
 
                }
1176
 
 
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.");
1181
 
                        ret = -ENOMEM;
1182
 
                        goto finish;
1183
 
                }
1184
 
 
1185
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1186
 
                if (!reply) {
1187
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1188
 
                        ret = -EIO;
1189
 
                        goto finish;
1190
 
                }
1191
 
 
1192
 
                dbus_message_unref(m);
1193
 
                dbus_message_unref(reply);
1194
 
                m = reply = NULL;
1195
 
        }
1196
 
 
1197
 
finish:
1198
 
        if (m)
1199
 
                dbus_message_unref(m);
1200
 
 
1201
 
        dbus_error_free(&error);
1202
 
 
1203
 
        return ret;
1204
 
}
1205
 
 
1206
 
static int kill_session(DBusConnection *bus, char **args, unsigned n) {
1207
 
        DBusMessage *m = NULL;
1208
 
        int ret = 0;
1209
 
        DBusError error;
1210
 
        unsigned i;
1211
 
 
1212
 
        assert(bus);
1213
 
        assert(args);
1214
 
 
1215
 
        dbus_error_init(&error);
1216
 
 
1217
 
        if (!arg_kill_who)
1218
 
                arg_kill_who = "all";
1219
 
 
1220
 
        for (i = 1; i < n; i++) {
1221
 
                DBusMessage *reply;
1222
 
 
1223
 
                m = dbus_message_new_method_call(
1224
 
                                "org.freedesktop.login1",
1225
 
                                "/org/freedesktop/login1",
1226
 
                                "org.freedesktop.login1.Manager",
1227
 
                                "KillSession");
1228
 
                if (!m) {
1229
 
                        log_error("Could not allocate message.");
1230
 
                        ret = -ENOMEM;
1231
 
                        goto finish;
1232
 
                }
1233
 
 
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.");
1240
 
                        ret = -ENOMEM;
1241
 
                        goto finish;
1242
 
                }
1243
 
 
1244
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1245
 
                if (!reply) {
1246
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1247
 
                        ret = -EIO;
1248
 
                        goto finish;
1249
 
                }
1250
 
 
1251
 
                dbus_message_unref(m);
1252
 
                dbus_message_unref(reply);
1253
 
                m = reply = NULL;
1254
 
        }
1255
 
 
1256
 
finish:
1257
 
        if (m)
1258
 
                dbus_message_unref(m);
1259
 
 
1260
 
        dbus_error_free(&error);
1261
 
 
1262
 
        return ret;
1263
 
}
1264
 
 
1265
 
static int enable_linger(DBusConnection *bus, char **args, unsigned n) {
1266
 
        DBusMessage *m = NULL;
1267
 
        int ret = 0;
1268
 
        DBusError error;
1269
 
        unsigned i;
1270
 
        dbus_bool_t b, interactive = true;
1271
 
 
1272
 
        assert(bus);
1273
 
        assert(args);
1274
 
 
1275
 
        dbus_error_init(&error);
1276
 
 
1277
 
        b = streq(args[0], "enable-linger");
1278
 
 
1279
 
        for (i = 1; i < n; i++) {
1280
 
                DBusMessage *reply;
1281
 
                uint32_t u;
1282
 
                uid_t uid;
1283
 
 
1284
 
                m = dbus_message_new_method_call(
1285
 
                                "org.freedesktop.login1",
1286
 
                                "/org/freedesktop/login1",
1287
 
                                "org.freedesktop.login1.Manager",
1288
 
                                "SetUserLinger");
1289
 
                if (!m) {
1290
 
                        log_error("Could not allocate message.");
1291
 
                        ret = -ENOMEM;
1292
 
                        goto finish;
1293
 
                }
1294
 
 
1295
 
                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1296
 
                if (ret < 0) {
1297
 
                        log_error("Failed to resolve user %s: %s", args[i], strerror(-ret));
1298
 
                        goto finish;
1299
 
                }
1300
 
 
1301
 
                u = (uint32_t) uid;
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.");
1308
 
                        ret = -ENOMEM;
1309
 
                        goto finish;
1310
 
                }
1311
 
 
1312
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1313
 
                if (!reply) {
1314
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1315
 
                        ret = -EIO;
1316
 
                        goto finish;
1317
 
                }
1318
 
 
1319
 
                dbus_message_unref(m);
1320
 
                dbus_message_unref(reply);
1321
 
                m = reply = NULL;
1322
 
        }
1323
 
 
1324
 
        ret = 0;
1325
 
 
1326
 
finish:
1327
 
        if (m)
1328
 
                dbus_message_unref(m);
1329
 
 
1330
 
        dbus_error_free(&error);
1331
 
 
1332
 
        return ret;
1333
 
}
1334
 
 
1335
 
static int terminate_user(DBusConnection *bus, char **args, unsigned n) {
1336
 
        DBusMessage *m = NULL;
1337
 
        int ret = 0;
1338
 
        DBusError error;
1339
 
        unsigned i;
1340
 
 
1341
 
        assert(bus);
1342
 
        assert(args);
1343
 
 
1344
 
        dbus_error_init(&error);
1345
 
 
1346
 
        for (i = 1; i < n; i++) {
1347
 
                uint32_t u;
1348
 
                uid_t uid;
1349
 
                DBusMessage *reply;
1350
 
 
1351
 
                m = dbus_message_new_method_call(
1352
 
                                "org.freedesktop.login1",
1353
 
                                "/org/freedesktop/login1",
1354
 
                                "org.freedesktop.login1.Manager",
1355
 
                                "TerminateUser");
1356
 
                if (!m) {
1357
 
                        log_error("Could not allocate message.");
1358
 
                        ret = -ENOMEM;
1359
 
                        goto finish;
1360
 
                }
1361
 
 
1362
 
                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1363
 
                if (ret < 0) {
1364
 
                        log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
1365
 
                        goto finish;
1366
 
                }
1367
 
 
1368
 
                u = (uint32_t) uid;
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.");
1373
 
                        ret = -ENOMEM;
1374
 
                        goto finish;
1375
 
                }
1376
 
 
1377
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1378
 
                if (!reply) {
1379
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1380
 
                        ret = -EIO;
1381
 
                        goto finish;
1382
 
                }
1383
 
 
1384
 
                dbus_message_unref(m);
1385
 
                dbus_message_unref(reply);
1386
 
                m = reply = NULL;
1387
 
        }
1388
 
 
1389
 
        ret = 0;
1390
 
 
1391
 
finish:
1392
 
        if (m)
1393
 
                dbus_message_unref(m);
1394
 
 
1395
 
        dbus_error_free(&error);
1396
 
 
1397
 
        return ret;
1398
 
}
1399
 
 
1400
 
static int kill_user(DBusConnection *bus, char **args, unsigned n) {
1401
 
        DBusMessage *m = NULL;
1402
 
        int ret = 0;
1403
 
        DBusError error;
1404
 
        unsigned i;
1405
 
 
1406
 
        assert(bus);
1407
 
        assert(args);
1408
 
 
1409
 
        dbus_error_init(&error);
1410
 
 
1411
 
        if (!arg_kill_who)
1412
 
                arg_kill_who = "all";
1413
 
 
1414
 
        for (i = 1; i < n; i++) {
1415
 
                DBusMessage *reply;
1416
 
                uid_t uid;
1417
 
                uint32_t u;
1418
 
 
1419
 
                m = dbus_message_new_method_call(
1420
 
                                "org.freedesktop.login1",
1421
 
                                "/org/freedesktop/login1",
1422
 
                                "org.freedesktop.login1.Manager",
1423
 
                                "KillUser");
1424
 
                if (!m) {
1425
 
                        log_error("Could not allocate message.");
1426
 
                        ret = -ENOMEM;
1427
 
                        goto finish;
1428
 
                }
1429
 
 
1430
 
                ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL);
1431
 
                if (ret < 0) {
1432
 
                        log_error("Failed to look up user %s: %s", args[i], strerror(-ret));
1433
 
                        goto finish;
1434
 
                }
1435
 
 
1436
 
                u = (uint32_t) uid;
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.");
1442
 
                        ret = -ENOMEM;
1443
 
                        goto finish;
1444
 
                }
1445
 
 
1446
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1447
 
                if (!reply) {
1448
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1449
 
                        ret = -EIO;
1450
 
                        goto finish;
1451
 
                }
1452
 
 
1453
 
                dbus_message_unref(m);
1454
 
                dbus_message_unref(reply);
1455
 
                m = reply = NULL;
1456
 
        }
1457
 
 
1458
 
        ret = 0;
1459
 
 
1460
 
finish:
1461
 
        if (m)
1462
 
                dbus_message_unref(m);
1463
 
 
1464
 
        dbus_error_free(&error);
1465
 
 
1466
 
        return ret;
1467
 
}
1468
 
 
1469
 
static int attach(DBusConnection *bus, char **args, unsigned n) {
1470
 
        DBusMessage *m = NULL;
1471
 
        int ret = 0;
1472
 
        DBusError error;
1473
 
        unsigned i;
1474
 
        dbus_bool_t interactive = true;
1475
 
 
1476
 
        assert(bus);
1477
 
        assert(args);
1478
 
 
1479
 
        dbus_error_init(&error);
1480
 
 
1481
 
        for (i = 2; i < n; i++) {
1482
 
                DBusMessage *reply;
1483
 
 
1484
 
                m = dbus_message_new_method_call(
1485
 
                                "org.freedesktop.login1",
1486
 
                                "/org/freedesktop/login1",
1487
 
                                "org.freedesktop.login1.Manager",
1488
 
                                "AttachDevice");
1489
 
                if (!m) {
1490
 
                        log_error("Could not allocate message.");
1491
 
                        ret = -ENOMEM;
1492
 
                        goto finish;
1493
 
                }
1494
 
 
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.");
1501
 
                        ret = -ENOMEM;
1502
 
                        goto finish;
1503
 
                }
1504
 
 
1505
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1506
 
                if (!reply) {
1507
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1508
 
                        ret = -EIO;
1509
 
                        goto finish;
1510
 
                }
1511
 
 
1512
 
                dbus_message_unref(m);
1513
 
                dbus_message_unref(reply);
1514
 
                m = reply = NULL;
1515
 
        }
1516
 
 
1517
 
finish:
1518
 
        if (m)
1519
 
                dbus_message_unref(m);
1520
 
 
1521
 
        dbus_error_free(&error);
1522
 
 
1523
 
        return ret;
1524
 
}
1525
 
 
1526
 
static int flush_devices(DBusConnection *bus, char **args, unsigned n) {
1527
 
        DBusMessage *m = NULL, *reply = NULL;
1528
 
        int ret = 0;
1529
 
        DBusError error;
1530
 
        dbus_bool_t interactive = true;
1531
 
 
1532
 
        assert(bus);
1533
 
        assert(args);
1534
 
 
1535
 
        dbus_error_init(&error);
1536
 
 
1537
 
        m = dbus_message_new_method_call(
1538
 
                        "org.freedesktop.login1",
1539
 
                        "/org/freedesktop/login1",
1540
 
                        "org.freedesktop.login1.Manager",
1541
 
                        "FlushDevices");
1542
 
        if (!m) {
1543
 
                log_error("Could not allocate message.");
1544
 
                ret = -ENOMEM;
1545
 
                goto finish;
1546
 
        }
1547
 
 
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.");
1552
 
                ret = -ENOMEM;
1553
 
                goto finish;
1554
 
        }
1555
 
 
1556
 
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1557
 
        if (!reply) {
1558
 
                log_error("Failed to issue method call: %s", bus_error_message(&error));
1559
 
                ret = -EIO;
1560
 
                goto finish;
1561
 
        }
1562
 
 
1563
 
finish:
1564
 
        if (m)
1565
 
                dbus_message_unref(m);
1566
 
 
1567
 
        if (reply)
1568
 
                dbus_message_unref(reply);
1569
 
 
1570
 
        dbus_error_free(&error);
1571
 
 
1572
 
        return ret;
1573
 
}
1574
 
 
1575
 
static int terminate_seat(DBusConnection *bus, char **args, unsigned n) {
1576
 
        DBusMessage *m = NULL;
1577
 
        int ret = 0;
1578
 
        DBusError error;
1579
 
        unsigned i;
1580
 
 
1581
 
        assert(bus);
1582
 
        assert(args);
1583
 
 
1584
 
        dbus_error_init(&error);
1585
 
 
1586
 
        for (i = 1; i < n; i++) {
1587
 
                DBusMessage *reply;
1588
 
 
1589
 
                m = dbus_message_new_method_call(
1590
 
                                "org.freedesktop.login1",
1591
 
                                "/org/freedesktop/login1",
1592
 
                                "org.freedesktop.login1.Manager",
1593
 
                                "TerminateSeat");
1594
 
                if (!m) {
1595
 
                        log_error("Could not allocate message.");
1596
 
                        ret = -ENOMEM;
1597
 
                        goto finish;
1598
 
                }
1599
 
 
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.");
1604
 
                        ret = -ENOMEM;
1605
 
                        goto finish;
1606
 
                }
1607
 
 
1608
 
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1609
 
                if (!reply) {
1610
 
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
1611
 
                        ret = -EIO;
1612
 
                        goto finish;
1613
 
                }
1614
 
 
1615
 
                dbus_message_unref(m);
1616
 
                dbus_message_unref(reply);
1617
 
                m = reply = NULL;
1618
 
        }
1619
 
 
1620
 
finish:
1621
 
        if (m)
1622
 
                dbus_message_unref(m);
1623
 
 
1624
 
        dbus_error_free(&error);
1625
 
 
1626
 
        return ret;
1627
 
}
1628
 
 
1629
 
static int help(void) {
1630
 
 
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"
1643
 
               "Commands:\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);
1666
 
 
1667
 
        return 0;
1668
 
}
1669
 
 
1670
 
static int parse_argv(int argc, char *argv[]) {
1671
 
 
1672
 
        enum {
1673
 
                ARG_VERSION = 0x100,
1674
 
                ARG_NO_PAGER,
1675
 
                ARG_KILL_WHO
1676
 
        };
1677
 
 
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             }
1689
 
        };
1690
 
 
1691
 
        int c;
1692
 
 
1693
 
        assert(argc >= 0);
1694
 
        assert(argv);
1695
 
 
1696
 
        while ((c = getopt_long(argc, argv, "hp:as:H:P", options, NULL)) >= 0) {
1697
 
 
1698
 
                switch (c) {
1699
 
 
1700
 
                case 'h':
1701
 
                        help();
1702
 
                        return 0;
1703
 
 
1704
 
                case ARG_VERSION:
1705
 
                        puts(PACKAGE_STRING);
1706
 
                        puts(DISTRIBUTION);
1707
 
                        puts(SYSTEMD_FEATURES);
1708
 
                        return 0;
1709
 
 
1710
 
                case 'p': {
1711
 
                        char **l;
1712
 
 
1713
 
                        l = strv_append(arg_property, optarg);
1714
 
                        if (!l)
1715
 
                                return -ENOMEM;
1716
 
 
1717
 
                        strv_free(arg_property);
1718
 
                        arg_property = l;
1719
 
 
1720
 
                        /* If the user asked for a particular
1721
 
                         * property, show it to him, even if it is
1722
 
                         * empty. */
1723
 
                        arg_all = true;
1724
 
                        break;
1725
 
                }
1726
 
 
1727
 
                case 'a':
1728
 
                        arg_all = true;
1729
 
                        break;
1730
 
 
1731
 
                case ARG_NO_PAGER:
1732
 
                        arg_no_pager = true;
1733
 
                        break;
1734
 
 
1735
 
                case ARG_KILL_WHO:
1736
 
                        arg_kill_who = optarg;
1737
 
                        break;
1738
 
 
1739
 
                case 's':
1740
 
                        arg_signal = signal_from_string_try_harder(optarg);
1741
 
                        if (arg_signal < 0) {
1742
 
                                log_error("Failed to parse signal string %s.", optarg);
1743
 
                                return -EINVAL;
1744
 
                        }
1745
 
                        break;
1746
 
 
1747
 
                case 'P':
1748
 
                        arg_transport = TRANSPORT_POLKIT;
1749
 
                        break;
1750
 
 
1751
 
                case 'H':
1752
 
                        arg_transport = TRANSPORT_SSH;
1753
 
                        arg_host = optarg;
1754
 
                        break;
1755
 
 
1756
 
                case '?':
1757
 
                        return -EINVAL;
1758
 
 
1759
 
                default:
1760
 
                        log_error("Unknown option code %c", c);
1761
 
                        return -EINVAL;
1762
 
                }
1763
 
        }
1764
 
 
1765
 
        return 1;
1766
 
}
1767
 
 
1768
 
static int loginctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
1769
 
 
1770
 
        static const struct {
1771
 
                const char* verb;
1772
 
                const enum {
1773
 
                        MORE,
1774
 
                        LESS,
1775
 
                        EQUAL
1776
 
                } argc_cmp;
1777
 
                const int argc;
1778
 
                int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
1779
 
        } verbs[] = {
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   },
1801
 
        };
1802
 
 
1803
 
        int left;
1804
 
        unsigned i;
1805
 
 
1806
 
        assert(argc >= 0);
1807
 
        assert(argv);
1808
 
        assert(error);
1809
 
 
1810
 
        left = argc - optind;
1811
 
 
1812
 
        if (left <= 0)
1813
 
                /* Special rule: no arguments means "list-sessions" */
1814
 
                i = 0;
1815
 
        else {
1816
 
                if (streq(argv[optind], "help")) {
1817
 
                        help();
1818
 
                        return 0;
1819
 
                }
1820
 
 
1821
 
                for (i = 0; i < ELEMENTSOF(verbs); i++)
1822
 
                        if (streq(argv[optind], verbs[i].verb))
1823
 
                                break;
1824
 
 
1825
 
                if (i >= ELEMENTSOF(verbs)) {
1826
 
                        log_error("Unknown operation %s", argv[optind]);
1827
 
                        return -EINVAL;
1828
 
                }
1829
 
        }
1830
 
 
1831
 
        switch (verbs[i].argc_cmp) {
1832
 
 
1833
 
        case EQUAL:
1834
 
                if (left != verbs[i].argc) {
1835
 
                        log_error("Invalid number of arguments.");
1836
 
                        return -EINVAL;
1837
 
                }
1838
 
 
1839
 
                break;
1840
 
 
1841
 
        case MORE:
1842
 
                if (left < verbs[i].argc) {
1843
 
                        log_error("Too few arguments.");
1844
 
                        return -EINVAL;
1845
 
                }
1846
 
 
1847
 
                break;
1848
 
 
1849
 
        case LESS:
1850
 
                if (left > verbs[i].argc) {
1851
 
                        log_error("Too many arguments.");
1852
 
                        return -EINVAL;
1853
 
                }
1854
 
 
1855
 
                break;
1856
 
 
1857
 
        default:
1858
 
                assert_not_reached("Unknown comparison operator.");
1859
 
        }
1860
 
 
1861
 
        if (!bus) {
1862
 
                log_error("Failed to get D-Bus connection: %s", error->message);
1863
 
                return -EIO;
1864
 
        }
1865
 
 
1866
 
        return verbs[i].dispatch(bus, argv + optind, left);
1867
 
}
1868
 
 
1869
 
int main(int argc, char*argv[]) {
1870
 
        int r, retval = EXIT_FAILURE;
1871
 
        DBusConnection *bus = NULL;
1872
 
        DBusError error;
1873
 
 
1874
 
        dbus_error_init(&error);
1875
 
 
1876
 
        log_parse_environment();
1877
 
        log_open();
1878
 
 
1879
 
        r = parse_argv(argc, argv);
1880
 
        if (r < 0)
1881
 
                goto finish;
1882
 
        else if (r == 0) {
1883
 
                retval = EXIT_SUCCESS;
1884
 
                goto finish;
1885
 
        }
1886
 
 
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);
1893
 
        else
1894
 
                assert_not_reached("Uh, invalid transport...");
1895
 
 
1896
 
        r = loginctl_main(bus, argc, argv, &error);
1897
 
        retval = r < 0 ? EXIT_FAILURE : r;
1898
 
 
1899
 
finish:
1900
 
        if (bus) {
1901
 
                dbus_connection_flush(bus);
1902
 
                dbus_connection_close(bus);
1903
 
                dbus_connection_unref(bus);
1904
 
        }
1905
 
 
1906
 
        dbus_error_free(&error);
1907
 
        dbus_shutdown();
1908
 
 
1909
 
        strv_free(arg_property);
1910
 
 
1911
 
        pager_close();
1912
 
 
1913
 
        return retval;
1914
 
}