~ubuntu-branches/ubuntu/vivid/systemd/vivid

« back to all changes in this revision

Viewing changes to .pc/v204..upstream-fixes_204-8/src/systemctl/systemctl.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2014-04-26 17:29:00 UTC
  • mfrom: (6.1.24 sid)
  • Revision ID: package-import@ubuntu.com-20140426172900-7eqx3dziwfe5w91c
Tags: 204-8ubuntu1
* Merge with Debian unstable. Drop the systemd-services split as we want to
  move to systemd as pid 1 (UbuntuSpec:core-1403-systemd-transition) so that
  we can start experimenting with booting Ubuntu with systemd. This does NOT
  yet change the default, with this upstart will still be used to bring up
  the system. To boot with systemd, add init=/lib/systemd/systemd to the
  grub menu (at boot or in /etc/default/grub GRUB_CMDLINE_LINUX_DEFAULT).

  Remaining Ubuntu specific changes:
  - debian/rules: Don't build the systemd-sysv package for now.
  - debian/udev.templates: Drop debconfiscation of udev, not necessary for
    Ubuntu. Drop debconf pre-dependency.
  - debian/extra/initramfs.top: Drop $ROOTDELAY, we do that in a more
    sensible way with wait-for-root. (Will get applicable to Debian once
    Debian gets wait-for-root in initramfs-tools.)
  - Drop debian/extra/{50-udev-default.rules,60-persistent-storage*.rules,
    75-cd-aliases-generator.rules,80-drivers.rules,80-networking.rules,
    91-permissions.rules}: These are the Debian specific rules, in Ubuntu we
    have always used the upstream ones.
  - Add debian/extra/rules/78-graphics-card.rules: Mark graphics devices as
    PRIMARY_DEVICE_FOR_DISPLAY so that we can wait for those in plymouth.
  - Add debian/extra/rules/73-idrac.rules: On Dell PowerEdge systems, the
    iDRAC7 and later support a USB Virtual NIC for management. Name this
    interface "idrac" to avoid confusion with "real" network interfaces.
  - Add debian/extra/udev.py: Apport hook.
  - debian/extra/udev.startup, debian/rules: Don't install/support
    /etc/udev/links.conf, that's a hack (if you want links, create udev
    rules).
  - Drop debian/source/{git-patches,options}, we use proper patches.
  - debian/rules: We continue to use the old net iface naming schema for the
    time being. Install old udev rule generator in debian/udev.install.
  - debian/rules: Don't install init.d scripts, only the upstart jobs.
  - debian/rules: Add an epoch to libgudev.
  - Drop debian/udev.dirs, not necessary.
  - Drop debian/udev.NEWS, debian/udev.maintscript: Not applicable to
    Ubuntu.
  - debian/udev.{postinst,postrm,preinst,prerm}: Keep our much simpler
    versions (all platforms must support udev, no debconf).
  - debian/rules: Drop doc dir symlinking. It creates havoc with dpkg
    upgrades, and we already have the automatic per-file symlinking.
  - Add debian/extra/rules/40-hyperv-hotadd.rules: Workaround for LP #1233466
  - Various debian/patches/*, see patch headers.

  Applicable to Debian:
  - Add libpam-systemd.systemd-logind.upstart to bring up logind at boot
    when using upstart.
  - debian/control, debian/tests/: Add autopkgtest.
  - debian/extra/initramfs.hook, debian/udev.*{pre,post}inst: Divert udevadm
    to udevadm.upgrade during upgrades while udev is unconfigured.
  - Add debian/extra/60-keyboard.hwdb: Latest upstream keymaps, for easy
    backporting.
  - debian/extra/initramfs.bottom: If LVM is installed, settle udev,
    otherwise we get missing LV symlinks. (LP #1185394)
  - Add debian/extra/README-{etc,lib}-rules.d documentation, install into
    udev.
  - debian/rules: Run tests during package build.
  - debian/udev.udev-finish.upstart: Fix path to tmp-rules,
    debian/extra/rule_generator.functions creates them in /run/udev/.
  - debian/udev-udeb.install: Add 64-btrfs.rules, 75-probe_mtd.rules, and
    80-drivers.rules, they are potentially useful in a d-i environment.
  - debian/extra/rules/75-persistent-net-generator.rules: Add new block of
    Windows Azure ethernet hardware address to ignore persistent naming
    (LP #1274348).
  - debian/extra/udev.startup: Mount devpts with the correct permissions to
    avoid needing pt_chown.
  - debian/libpam-systemd.prerm: Do proper refcounting of the PAM module
    package on prerm, so that we don't drop the module from the PAM config
    when uninstalling a foreign-arch package.  Related to LP #1295521.
  - Run dh_install with --list-missing.

  Upgrade fixes, keep until 16.04 LTS release:
  - debian/control: Conflicts/Replaces/Provides systemd-services.
* debian/tests/timedated: Get along with comments in /etc/timezone,
  cloud-init puts one there.

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 Lesser General Public License as published by
 
10
  the Free Software Foundation; either version 2.1 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
  Lesser General Public License for more details.
 
17
 
 
18
  You should have received a copy of the GNU Lesser General Public License
 
19
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 
20
***/
 
21
 
 
22
#include <sys/reboot.h>
 
23
#include <stdio.h>
 
24
#include <getopt.h>
 
25
#include <locale.h>
 
26
#include <stdbool.h>
 
27
#include <string.h>
 
28
#include <errno.h>
 
29
#include <sys/ioctl.h>
 
30
#include <termios.h>
 
31
#include <unistd.h>
 
32
#include <fcntl.h>
 
33
#include <sys/socket.h>
 
34
#include <sys/stat.h>
 
35
#include <stddef.h>
 
36
#include <sys/prctl.h>
 
37
#include <dbus/dbus.h>
 
38
 
 
39
#include <systemd/sd-daemon.h>
 
40
#include <systemd/sd-shutdown.h>
 
41
#include <systemd/sd-login.h>
 
42
 
 
43
#include "log.h"
 
44
#include "util.h"
 
45
#include "macro.h"
 
46
#include "set.h"
 
47
#include "utmp-wtmp.h"
 
48
#include "special.h"
 
49
#include "initreq.h"
 
50
#include "path-util.h"
 
51
#include "strv.h"
 
52
#include "dbus-common.h"
 
53
#include "cgroup-show.h"
 
54
#include "cgroup-util.h"
 
55
#include "list.h"
 
56
#include "path-lookup.h"
 
57
#include "conf-parser.h"
 
58
#include "exit-status.h"
 
59
#include "bus-errors.h"
 
60
#include "build.h"
 
61
#include "unit-name.h"
 
62
#include "pager.h"
 
63
#include "spawn-ask-password-agent.h"
 
64
#include "spawn-polkit-agent.h"
 
65
#include "install.h"
 
66
#include "logs-show.h"
 
67
#include "path-util.h"
 
68
#include "socket-util.h"
 
69
#include "fileio.h"
 
70
 
 
71
static char **arg_types = NULL;
 
72
static char **arg_load_states = NULL;
 
73
static char **arg_properties = NULL;
 
74
static bool arg_all = false;
 
75
static enum dependency {
 
76
        DEPENDENCY_FORWARD,
 
77
        DEPENDENCY_REVERSE,
 
78
        DEPENDENCY_AFTER,
 
79
        DEPENDENCY_BEFORE,
 
80
} arg_dependency = DEPENDENCY_FORWARD;
 
81
static const char *arg_job_mode = "replace";
 
82
static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
 
83
static bool arg_no_block = false;
 
84
static bool arg_no_legend = false;
 
85
static bool arg_no_pager = false;
 
86
static bool arg_no_wtmp = false;
 
87
static bool arg_no_wall = false;
 
88
static bool arg_no_reload = false;
 
89
static bool arg_show_types = false;
 
90
static bool arg_ignore_inhibitors = false;
 
91
static bool arg_dry = false;
 
92
static bool arg_quiet = false;
 
93
static bool arg_full = false;
 
94
static int arg_force = 0;
 
95
static bool arg_ask_password = true;
 
96
static bool arg_failed = false;
 
97
static bool arg_runtime = false;
 
98
static char **arg_wall = NULL;
 
99
static const char *arg_kill_who = NULL;
 
100
static int arg_signal = SIGTERM;
 
101
static const char *arg_root = NULL;
 
102
static usec_t arg_when = 0;
 
103
static enum action {
 
104
        ACTION_INVALID,
 
105
        ACTION_SYSTEMCTL,
 
106
        ACTION_HALT,
 
107
        ACTION_POWEROFF,
 
108
        ACTION_REBOOT,
 
109
        ACTION_KEXEC,
 
110
        ACTION_EXIT,
 
111
        ACTION_SUSPEND,
 
112
        ACTION_HIBERNATE,
 
113
        ACTION_HYBRID_SLEEP,
 
114
        ACTION_RUNLEVEL2,
 
115
        ACTION_RUNLEVEL3,
 
116
        ACTION_RUNLEVEL4,
 
117
        ACTION_RUNLEVEL5,
 
118
        ACTION_RESCUE,
 
119
        ACTION_EMERGENCY,
 
120
        ACTION_DEFAULT,
 
121
        ACTION_RELOAD,
 
122
        ACTION_REEXEC,
 
123
        ACTION_RUNLEVEL,
 
124
        ACTION_CANCEL_SHUTDOWN,
 
125
        _ACTION_MAX
 
126
} arg_action = ACTION_SYSTEMCTL;
 
127
static enum transport {
 
128
        TRANSPORT_NORMAL,
 
129
        TRANSPORT_SSH,
 
130
        TRANSPORT_POLKIT
 
131
} arg_transport = TRANSPORT_NORMAL;
 
132
static const char *arg_host = NULL;
 
133
static unsigned arg_lines = 10;
 
134
static OutputMode arg_output = OUTPUT_SHORT;
 
135
static bool arg_plain = false;
 
136
 
 
137
static bool private_bus = false;
 
138
 
 
139
static int daemon_reload(DBusConnection *bus, char **args);
 
140
static void halt_now(enum action a);
 
141
 
 
142
static void pager_open_if_enabled(void) {
 
143
 
 
144
        if (arg_no_pager)
 
145
                return;
 
146
 
 
147
        pager_open(false);
 
148
}
 
149
 
 
150
static void ask_password_agent_open_if_enabled(void) {
 
151
 
 
152
        /* Open the password agent as a child process if necessary */
 
153
 
 
154
        if (!arg_ask_password)
 
155
                return;
 
156
 
 
157
        if (arg_scope != UNIT_FILE_SYSTEM)
 
158
                return;
 
159
 
 
160
        ask_password_agent_open();
 
161
}
 
162
 
 
163
#ifdef HAVE_LOGIND
 
164
static void polkit_agent_open_if_enabled(void) {
 
165
 
 
166
        /* Open the polkit agent as a child process if necessary */
 
167
 
 
168
        if (!arg_ask_password)
 
169
                return;
 
170
 
 
171
        if (arg_scope != UNIT_FILE_SYSTEM)
 
172
                return;
 
173
 
 
174
        polkit_agent_open();
 
175
}
 
176
#endif
 
177
 
 
178
static const char *ansi_highlight(bool b) {
 
179
 
 
180
        if (!on_tty())
 
181
                return "";
 
182
 
 
183
        return b ? ANSI_HIGHLIGHT_ON : ANSI_HIGHLIGHT_OFF;
 
184
}
 
185
 
 
186
static const char *ansi_highlight_red(bool b) {
 
187
 
 
188
        if (!on_tty())
 
189
                return "";
 
190
 
 
191
        return b ? ANSI_HIGHLIGHT_RED_ON : ANSI_HIGHLIGHT_OFF;
 
192
}
 
193
 
 
194
static const char *ansi_highlight_green(bool b) {
 
195
 
 
196
        if (!on_tty())
 
197
                return "";
 
198
 
 
199
        return b ? ANSI_HIGHLIGHT_GREEN_ON : ANSI_HIGHLIGHT_OFF;
 
200
}
 
201
 
 
202
static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
 
203
        assert(error);
 
204
 
 
205
        if (!dbus_error_is_set(error))
 
206
                return r;
 
207
 
 
208
        if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
 
209
            dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
 
210
            dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
 
211
            dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
 
212
                return EXIT_NOPERMISSION;
 
213
 
 
214
        if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
 
215
                return EXIT_NOTINSTALLED;
 
216
 
 
217
        if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
 
218
            dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
 
219
                return EXIT_NOTIMPLEMENTED;
 
220
 
 
221
        if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
 
222
                return EXIT_NOTCONFIGURED;
 
223
 
 
224
        if (r != 0)
 
225
                return r;
 
226
 
 
227
        return EXIT_FAILURE;
 
228
}
 
229
 
 
230
static void warn_wall(enum action a) {
 
231
        static const char *table[_ACTION_MAX] = {
 
232
                [ACTION_HALT]            = "The system is going down for system halt NOW!",
 
233
                [ACTION_REBOOT]          = "The system is going down for reboot NOW!",
 
234
                [ACTION_POWEROFF]        = "The system is going down for power-off NOW!",
 
235
                [ACTION_KEXEC]           = "The system is going down for kexec reboot NOW!",
 
236
                [ACTION_RESCUE]          = "The system is going down to rescue mode NOW!",
 
237
                [ACTION_EMERGENCY]       = "The system is going down to emergency mode NOW!",
 
238
                [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
 
239
        };
 
240
 
 
241
        if (arg_no_wall)
 
242
                return;
 
243
 
 
244
        if (arg_wall) {
 
245
                _cleanup_free_ char *p;
 
246
 
 
247
                p = strv_join(arg_wall, " ");
 
248
                if (!p) {
 
249
                        log_oom();
 
250
                        return;
 
251
                }
 
252
 
 
253
                if (*p) {
 
254
                        utmp_wall(p, NULL);
 
255
                        return;
 
256
                }
 
257
        }
 
258
 
 
259
        if (!table[a])
 
260
                return;
 
261
 
 
262
        utmp_wall(table[a], NULL);
 
263
}
 
264
 
 
265
static bool avoid_bus(void) {
 
266
 
 
267
        if (running_in_chroot() > 0)
 
268
                return true;
 
269
 
 
270
        if (sd_booted() <= 0)
 
271
                return true;
 
272
 
 
273
        if (!isempty(arg_root))
 
274
                return true;
 
275
 
 
276
        if (arg_scope == UNIT_FILE_GLOBAL)
 
277
                return true;
 
278
 
 
279
        return false;
 
280
}
 
281
 
 
282
static int compare_unit_info(const void *a, const void *b) {
 
283
        const char *d1, *d2;
 
284
        const struct unit_info *u = a, *v = b;
 
285
 
 
286
        d1 = strrchr(u->id, '.');
 
287
        d2 = strrchr(v->id, '.');
 
288
 
 
289
        if (d1 && d2) {
 
290
                int r;
 
291
 
 
292
                r = strcasecmp(d1, d2);
 
293
                if (r != 0)
 
294
                        return r;
 
295
        }
 
296
 
 
297
        return strcasecmp(u->id, v->id);
 
298
}
 
299
 
 
300
static bool output_show_unit(const struct unit_info *u) {
 
301
        const char *dot;
 
302
 
 
303
        if (arg_failed)
 
304
                return streq(u->active_state, "failed");
 
305
 
 
306
        return (!arg_types || ((dot = strrchr(u->id, '.')) &&
 
307
                               strv_find(arg_types, dot+1))) &&
 
308
                (!arg_load_states || strv_find(arg_load_states, u->load_state)) &&
 
309
                (arg_all || !(streq(u->active_state, "inactive")
 
310
                              || u->following[0]) || u->job_id > 0);
 
311
}
 
312
 
 
313
static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
 
314
        unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
 
315
        const struct unit_info *u;
 
316
        int job_count = 0;
 
317
 
 
318
        max_id_len = sizeof("UNIT")-1;
 
319
        active_len = sizeof("ACTIVE")-1;
 
320
        sub_len = sizeof("SUB")-1;
 
321
        job_len = sizeof("JOB")-1;
 
322
        desc_len = 0;
 
323
 
 
324
        for (u = unit_infos; u < unit_infos + c; u++) {
 
325
                if (!output_show_unit(u))
 
326
                        continue;
 
327
 
 
328
                max_id_len = MAX(max_id_len, strlen(u->id));
 
329
                active_len = MAX(active_len, strlen(u->active_state));
 
330
                sub_len = MAX(sub_len, strlen(u->sub_state));
 
331
                if (u->job_id != 0) {
 
332
                        job_len = MAX(job_len, strlen(u->job_type));
 
333
                        job_count++;
 
334
                }
 
335
        }
 
336
 
 
337
        if (!arg_full) {
 
338
                unsigned basic_len;
 
339
                id_len = MIN(max_id_len, 25u);
 
340
                basic_len = 5 + id_len + 5 + active_len + sub_len;
 
341
                if (job_count)
 
342
                        basic_len += job_len + 1;
 
343
                if (basic_len < (unsigned) columns()) {
 
344
                        unsigned extra_len, incr;
 
345
                        extra_len = columns() - basic_len;
 
346
                        /* Either UNIT already got 25, or is fully satisfied.
 
347
                         * Grant up to 25 to DESC now. */
 
348
                        incr = MIN(extra_len, 25u);
 
349
                        desc_len += incr;
 
350
                        extra_len -= incr;
 
351
                        /* split the remaining space between UNIT and DESC,
 
352
                         * but do not give UNIT more than it needs. */
 
353
                        if (extra_len > 0) {
 
354
                                incr = MIN(extra_len / 2, max_id_len - id_len);
 
355
                                id_len += incr;
 
356
                                desc_len += extra_len - incr;
 
357
                        }
 
358
                }
 
359
        } else
 
360
                id_len = max_id_len;
 
361
 
 
362
        for (u = unit_infos; u < unit_infos + c; u++) {
 
363
                _cleanup_free_ char *e = NULL;
 
364
                const char *on_loaded, *off_loaded, *on = "";
 
365
                const char *on_active, *off_active, *off = "";
 
366
 
 
367
                if (!output_show_unit(u))
 
368
                        continue;
 
369
 
 
370
                if (!n_shown && !arg_no_legend) {
 
371
                        printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
 
372
                               active_len, "ACTIVE", sub_len, "SUB");
 
373
                        if (job_count)
 
374
                                printf("%-*s ", job_len, "JOB");
 
375
                        if (!arg_full && arg_no_pager)
 
376
                                printf("%.*s\n", desc_len, "DESCRIPTION");
 
377
                        else
 
378
                                printf("%s\n", "DESCRIPTION");
 
379
                }
 
380
 
 
381
                n_shown++;
 
382
 
 
383
                if (streq(u->load_state, "error")) {
 
384
                        on_loaded = on = ansi_highlight_red(true);
 
385
                        off_loaded = off = ansi_highlight_red(false);
 
386
                } else
 
387
                        on_loaded = off_loaded = "";
 
388
 
 
389
                if (streq(u->active_state, "failed")) {
 
390
                        on_active = on = ansi_highlight_red(true);
 
391
                        off_active = off = ansi_highlight_red(false);
 
392
                } else
 
393
                        on_active = off_active = "";
 
394
 
 
395
                e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
 
396
 
 
397
                printf("%s%-*s%s %s%-6s%s %s%-*s %-*s%s %-*s",
 
398
                       on, id_len, e ? e : u->id, off,
 
399
                       on_loaded, u->load_state, off_loaded,
 
400
                       on_active, active_len, u->active_state,
 
401
                       sub_len, u->sub_state, off_active,
 
402
                       job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
 
403
                if (!arg_full && arg_no_pager)
 
404
                        printf("%.*s\n", desc_len, u->description);
 
405
                else
 
406
                        printf("%s\n", u->description);
 
407
        }
 
408
 
 
409
        if (!arg_no_legend) {
 
410
                const char *on, *off;
 
411
 
 
412
                if (n_shown) {
 
413
                        printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
 
414
                               "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
 
415
                               "SUB    = The low-level unit activation state, values depend on unit type.\n");
 
416
                        if (job_count)
 
417
                                printf("JOB    = Pending job for the unit.\n");
 
418
                        puts("");
 
419
                        on = ansi_highlight(true);
 
420
                        off = ansi_highlight(false);
 
421
                } else {
 
422
                        on = ansi_highlight_red(true);
 
423
                        off = ansi_highlight_red(false);
 
424
                }
 
425
 
 
426
                if (arg_all)
 
427
                        printf("%s%u loaded units listed.%s\n"
 
428
                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
 
429
                               on, n_shown, off);
 
430
                else
 
431
                        printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
 
432
                               "To show all installed unit files use 'systemctl list-unit-files'.\n",
 
433
                               on, n_shown, off);
 
434
        }
 
435
}
 
436
 
 
437
static int get_unit_list(DBusConnection *bus, DBusMessage **reply,
 
438
                         struct unit_info **unit_infos, unsigned *c) {
 
439
        DBusMessageIter iter, sub;
 
440
        size_t size = 0;
 
441
        int r;
 
442
 
 
443
        assert(bus);
 
444
        assert(unit_infos);
 
445
        assert(c);
 
446
 
 
447
        r = bus_method_call_with_reply(
 
448
                        bus,
 
449
                        "org.freedesktop.systemd1",
 
450
                        "/org/freedesktop/systemd1",
 
451
                        "org.freedesktop.systemd1.Manager",
 
452
                        "ListUnits",
 
453
                        reply,
 
454
                        NULL,
 
455
                        DBUS_TYPE_INVALID);
 
456
        if (r < 0)
 
457
                return r;
 
458
 
 
459
        if (!dbus_message_iter_init(*reply, &iter) ||
 
460
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
461
            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
 
462
                log_error("Failed to parse reply.");
 
463
                return -EIO;
 
464
        }
 
465
 
 
466
        dbus_message_iter_recurse(&iter, &sub);
 
467
 
 
468
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
469
                if (!GREEDY_REALLOC(*unit_infos, size, *c + 1))
 
470
                        return log_oom();
 
471
 
 
472
                bus_parse_unit_info(&sub, *unit_infos + *c);
 
473
                (*c)++;
 
474
 
 
475
                dbus_message_iter_next(&sub);
 
476
        }
 
477
 
 
478
        return 0;
 
479
}
 
480
 
 
481
static int list_units(DBusConnection *bus, char **args) {
 
482
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
483
        _cleanup_free_ struct unit_info *unit_infos = NULL;
 
484
        unsigned c = 0;
 
485
        int r;
 
486
 
 
487
        pager_open_if_enabled();
 
488
 
 
489
        r = get_unit_list(bus, &reply, &unit_infos, &c);
 
490
        if (r < 0)
 
491
                return r;
 
492
 
 
493
        qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
 
494
 
 
495
        output_units_list(unit_infos, c);
 
496
 
 
497
        return 0;
 
498
}
 
499
 
 
500
static int get_triggered_units(DBusConnection *bus, const char* unit_path,
 
501
                               char*** triggered)
 
502
{
 
503
        const char *interface = "org.freedesktop.systemd1.Unit",
 
504
                   *triggers_property = "Triggers";
 
505
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
506
        DBusMessageIter iter, sub;
 
507
        int r;
 
508
 
 
509
        r = bus_method_call_with_reply(bus,
 
510
                                       "org.freedesktop.systemd1",
 
511
                                       unit_path,
 
512
                                       "org.freedesktop.DBus.Properties",
 
513
                                       "Get",
 
514
                                       &reply,
 
515
                                       NULL,
 
516
                                       DBUS_TYPE_STRING, &interface,
 
517
                                       DBUS_TYPE_STRING, &triggers_property,
 
518
                                       DBUS_TYPE_INVALID);
 
519
        if (r < 0)
 
520
                return r;
 
521
 
 
522
        if (!dbus_message_iter_init(reply, &iter) ||
 
523
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
 
524
                log_error("Failed to parse reply.");
 
525
                return -EBADMSG;
 
526
        }
 
527
 
 
528
        dbus_message_iter_recurse(&iter, &sub);
 
529
        dbus_message_iter_recurse(&sub, &iter);
 
530
        sub = iter;
 
531
 
 
532
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
533
                const char *unit;
 
534
 
 
535
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
 
536
                        log_error("Failed to parse reply.");
 
537
                        return -EBADMSG;
 
538
                }
 
539
 
 
540
                dbus_message_iter_get_basic(&sub, &unit);
 
541
                r = strv_extend(triggered, unit);
 
542
                if (r < 0)
 
543
                        return r;
 
544
 
 
545
                dbus_message_iter_next(&sub);
 
546
        }
 
547
 
 
548
        return 0;
 
549
}
 
550
 
 
551
static int get_listening(DBusConnection *bus, const char* unit_path,
 
552
                         char*** listen, unsigned *c)
 
553
{
 
554
        const char *interface = "org.freedesktop.systemd1.Socket",
 
555
                   *listen_property = "Listen";
 
556
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
557
        DBusMessageIter iter, sub;
 
558
        int r;
 
559
 
 
560
        r = bus_method_call_with_reply(bus,
 
561
                                       "org.freedesktop.systemd1",
 
562
                                       unit_path,
 
563
                                       "org.freedesktop.DBus.Properties",
 
564
                                       "Get",
 
565
                                       &reply,
 
566
                                       NULL,
 
567
                                       DBUS_TYPE_STRING, &interface,
 
568
                                       DBUS_TYPE_STRING, &listen_property,
 
569
                                       DBUS_TYPE_INVALID);
 
570
        if (r < 0)
 
571
                return r;
 
572
 
 
573
        if (!dbus_message_iter_init(reply, &iter) ||
 
574
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
 
575
                log_error("Failed to parse reply.");
 
576
                return -EBADMSG;
 
577
        }
 
578
 
 
579
        dbus_message_iter_recurse(&iter, &sub);
 
580
        dbus_message_iter_recurse(&sub, &iter);
 
581
        sub = iter;
 
582
 
 
583
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
584
                DBusMessageIter sub2;
 
585
                const char *type, *path;
 
586
 
 
587
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
 
588
                        log_error("Failed to parse reply.");
 
589
                        return -EBADMSG;
 
590
                }
 
591
 
 
592
                dbus_message_iter_recurse(&sub, &sub2);
 
593
 
 
594
                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
 
595
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
 
596
                        r = strv_extend(listen, type);
 
597
                        if (r < 0)
 
598
                                return r;
 
599
 
 
600
                        r = strv_extend(listen, path);
 
601
                        if (r < 0)
 
602
                                return r;
 
603
 
 
604
                        (*c) ++;
 
605
                }
 
606
 
 
607
                dbus_message_iter_next(&sub);
 
608
        }
 
609
 
 
610
        return 0;
 
611
}
 
612
 
 
613
struct socket_info {
 
614
        const char* id;
 
615
 
 
616
        char* type;
 
617
        char* path;
 
618
 
 
619
        /* Note: triggered is a list here, although it almost certainly
 
620
         * will always be one unit. Nevertheless, dbus API allows for multiple
 
621
         * values, so let's follow that.*/
 
622
        char** triggered;
 
623
 
 
624
        /* The strv above is shared. free is set only in the first one. */
 
625
        bool own_triggered;
 
626
};
 
627
 
 
628
static int socket_info_compare(struct socket_info *a, struct socket_info *b) {
 
629
        int o = strcmp(a->path, b->path);
 
630
        if (o == 0)
 
631
                o = strcmp(a->type, b->type);
 
632
        return o;
 
633
}
 
634
 
 
635
static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
 
636
        struct socket_info *s;
 
637
        unsigned pathlen = sizeof("LISTEN") - 1,
 
638
                typelen = (sizeof("TYPE") - 1) * arg_show_types,
 
639
                socklen = sizeof("UNIT") - 1,
 
640
                servlen = sizeof("ACTIVATES") - 1;
 
641
        const char *on, *off;
 
642
 
 
643
        for (s = socket_infos; s < socket_infos + cs; s++) {
 
644
                char **a;
 
645
                unsigned tmp = 0;
 
646
 
 
647
                socklen = MAX(socklen, strlen(s->id));
 
648
                if (arg_show_types)
 
649
                        typelen = MAX(typelen, strlen(s->type));
 
650
                pathlen = MAX(pathlen, strlen(s->path));
 
651
 
 
652
                STRV_FOREACH(a, s->triggered)
 
653
                        tmp += strlen(*a) + 2*(a != s->triggered);
 
654
                servlen = MAX(servlen, tmp);
 
655
        }
 
656
 
 
657
        if (cs) {
 
658
                printf("%-*s %-*.*s%-*s %s\n",
 
659
                       pathlen, "LISTEN",
 
660
                       typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
 
661
                       socklen, "UNIT",
 
662
                       "ACTIVATES");
 
663
 
 
664
                for (s = socket_infos; s < socket_infos + cs; s++) {
 
665
                        char **a;
 
666
 
 
667
                        if (arg_show_types)
 
668
                                printf("%-*s %-*s %-*s",
 
669
                                       pathlen, s->path, typelen, s->type, socklen, s->id);
 
670
                        else
 
671
                                printf("%-*s %-*s",
 
672
                                       pathlen, s->path, socklen, s->id);
 
673
                        STRV_FOREACH(a, s->triggered)
 
674
                                printf("%s %s",
 
675
                                       a == s->triggered ? "" : ",", *a);
 
676
                        printf("\n");
 
677
                }
 
678
 
 
679
                on = ansi_highlight(true);
 
680
                off = ansi_highlight(false);
 
681
                printf("\n");
 
682
        } else {
 
683
                on = ansi_highlight_red(true);
 
684
                off = ansi_highlight_red(false);
 
685
        }
 
686
 
 
687
        printf("%s%u sockets listed.%s\n", on, cs, off);
 
688
        if (!arg_all)
 
689
                printf("Pass --all to see loaded but inactive sockets, too.\n");
 
690
 
 
691
        return 0;
 
692
}
 
693
 
 
694
static int list_sockets(DBusConnection *bus, char **args) {
 
695
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
696
        _cleanup_free_ struct unit_info *unit_infos = NULL;
 
697
        struct socket_info *socket_infos = NULL;
 
698
        const struct unit_info *u;
 
699
        struct socket_info *s;
 
700
        unsigned cu = 0, cs = 0;
 
701
        size_t size = 0;
 
702
        int r;
 
703
 
 
704
        pager_open_if_enabled();
 
705
 
 
706
        r = get_unit_list(bus, &reply, &unit_infos, &cu);
 
707
        if (r < 0)
 
708
                return r;
 
709
 
 
710
        for (u = unit_infos; u < unit_infos + cu; u++) {
 
711
                const char *dot;
 
712
                _cleanup_strv_free_ char **listen = NULL, **triggered = NULL;
 
713
                unsigned c = 0, i;
 
714
 
 
715
                if (!output_show_unit(u))
 
716
                        continue;
 
717
 
 
718
                if ((dot = strrchr(u->id, '.')) && !streq(dot+1, "socket"))
 
719
                        continue;
 
720
 
 
721
                r = get_triggered_units(bus, u->unit_path, &triggered);
 
722
                if (r < 0)
 
723
                        goto cleanup;
 
724
 
 
725
                r = get_listening(bus, u->unit_path, &listen, &c);
 
726
                if (r < 0)
 
727
                        goto cleanup;
 
728
 
 
729
                if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
 
730
                        r = log_oom();
 
731
                        goto cleanup;
 
732
                }
 
733
 
 
734
                for (i = 0; i < c; i++)
 
735
                        socket_infos[cs + i] = (struct socket_info) {
 
736
                                .id = u->id,
 
737
                                .type = listen[i*2],
 
738
                                .path = listen[i*2 + 1],
 
739
                                .triggered = triggered,
 
740
                                .own_triggered = i==0,
 
741
                        };
 
742
 
 
743
                /* from this point on we will cleanup those socket_infos */
 
744
                cs += c;
 
745
                free(listen);
 
746
                listen = triggered = NULL; /* avoid cleanup */
 
747
        }
 
748
 
 
749
        qsort(socket_infos, cs, sizeof(struct socket_info),
 
750
              (__compar_fn_t) socket_info_compare);
 
751
 
 
752
        output_sockets_list(socket_infos, cs);
 
753
 
 
754
 cleanup:
 
755
        assert(cs == 0 || socket_infos);
 
756
        for (s = socket_infos; s < socket_infos + cs; s++) {
 
757
                free(s->type);
 
758
                free(s->path);
 
759
                if (s->own_triggered)
 
760
                        strv_free(s->triggered);
 
761
        }
 
762
        free(socket_infos);
 
763
 
 
764
        return 0;
 
765
}
 
766
 
 
767
static int compare_unit_file_list(const void *a, const void *b) {
 
768
        const char *d1, *d2;
 
769
        const UnitFileList *u = a, *v = b;
 
770
 
 
771
        d1 = strrchr(u->path, '.');
 
772
        d2 = strrchr(v->path, '.');
 
773
 
 
774
        if (d1 && d2) {
 
775
                int r;
 
776
 
 
777
                r = strcasecmp(d1, d2);
 
778
                if (r != 0)
 
779
                        return r;
 
780
        }
 
781
 
 
782
        return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
 
783
}
 
784
 
 
785
static bool output_show_unit_file(const UnitFileList *u) {
 
786
        const char *dot;
 
787
 
 
788
        return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
 
789
}
 
790
 
 
791
static void output_unit_file_list(const UnitFileList *units, unsigned c) {
 
792
        unsigned max_id_len, id_cols, state_cols, n_shown = 0;
 
793
        const UnitFileList *u;
 
794
 
 
795
        max_id_len = sizeof("UNIT FILE")-1;
 
796
        state_cols = sizeof("STATE")-1;
 
797
        for (u = units; u < units + c; u++) {
 
798
                if (!output_show_unit_file(u))
 
799
                        continue;
 
800
 
 
801
                max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
 
802
                state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
 
803
        }
 
804
 
 
805
        if (!arg_full) {
 
806
                unsigned basic_cols;
 
807
                id_cols = MIN(max_id_len, 25u);
 
808
                basic_cols = 1 + id_cols + state_cols;
 
809
                if (basic_cols < (unsigned) columns())
 
810
                        id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
 
811
        } else
 
812
                id_cols = max_id_len;
 
813
 
 
814
        if (!arg_no_legend)
 
815
                printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
 
816
 
 
817
        for (u = units; u < units + c; u++) {
 
818
                _cleanup_free_ char *e = NULL;
 
819
                const char *on, *off;
 
820
                const char *id;
 
821
 
 
822
                if (!output_show_unit_file(u))
 
823
                        continue;
 
824
 
 
825
                n_shown++;
 
826
 
 
827
                if (u->state == UNIT_FILE_MASKED ||
 
828
                    u->state == UNIT_FILE_MASKED_RUNTIME ||
 
829
                    u->state == UNIT_FILE_DISABLED ||
 
830
                    u->state == UNIT_FILE_INVALID) {
 
831
                        on  = ansi_highlight_red(true);
 
832
                        off = ansi_highlight_red(false);
 
833
                } else if (u->state == UNIT_FILE_ENABLED) {
 
834
                        on  = ansi_highlight_green(true);
 
835
                        off = ansi_highlight_green(false);
 
836
                } else
 
837
                        on = off = "";
 
838
 
 
839
                id = path_get_file_name(u->path);
 
840
 
 
841
                e = arg_full ? NULL : ellipsize(id, id_cols, 33);
 
842
 
 
843
                printf("%-*s %s%-*s%s\n",
 
844
                       id_cols, e ? e : id,
 
845
                       on, state_cols, unit_file_state_to_string(u->state), off);
 
846
        }
 
847
 
 
848
        if (!arg_no_legend)
 
849
                printf("\n%u unit files listed.\n", n_shown);
 
850
}
 
851
 
 
852
static int list_unit_files(DBusConnection *bus, char **args) {
 
853
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
854
        _cleanup_free_ UnitFileList *units = NULL;
 
855
        DBusMessageIter iter, sub, sub2;
 
856
        unsigned c = 0, n_units = 0;
 
857
        int r;
 
858
 
 
859
        pager_open_if_enabled();
 
860
 
 
861
        if (avoid_bus()) {
 
862
                Hashmap *h;
 
863
                UnitFileList *u;
 
864
                Iterator i;
 
865
 
 
866
                h = hashmap_new(string_hash_func, string_compare_func);
 
867
                if (!h)
 
868
                        return log_oom();
 
869
 
 
870
                r = unit_file_get_list(arg_scope, arg_root, h);
 
871
                if (r < 0) {
 
872
                        unit_file_list_free(h);
 
873
                        log_error("Failed to get unit file list: %s", strerror(-r));
 
874
                        return r;
 
875
                }
 
876
 
 
877
                n_units = hashmap_size(h);
 
878
                units = new(UnitFileList, n_units);
 
879
                if (!units) {
 
880
                        unit_file_list_free(h);
 
881
                        return log_oom();
 
882
                }
 
883
 
 
884
                HASHMAP_FOREACH(u, h, i) {
 
885
                        memcpy(units + c++, u, sizeof(UnitFileList));
 
886
                        free(u);
 
887
                }
 
888
 
 
889
                hashmap_free(h);
 
890
        } else {
 
891
                r = bus_method_call_with_reply(
 
892
                                bus,
 
893
                                "org.freedesktop.systemd1",
 
894
                                "/org/freedesktop/systemd1",
 
895
                                "org.freedesktop.systemd1.Manager",
 
896
                                "ListUnitFiles",
 
897
                                &reply,
 
898
                                NULL,
 
899
                                DBUS_TYPE_INVALID);
 
900
                if (r < 0)
 
901
                        return r;
 
902
 
 
903
                if (!dbus_message_iter_init(reply, &iter) ||
 
904
                    dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
905
                    dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
 
906
                        log_error("Failed to parse reply.");
 
907
                        return -EIO;
 
908
                }
 
909
 
 
910
                dbus_message_iter_recurse(&iter, &sub);
 
911
 
 
912
                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
913
                        UnitFileList *u;
 
914
                        const char *state;
 
915
 
 
916
                        assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
 
917
 
 
918
                        if (c >= n_units) {
 
919
                                UnitFileList *w;
 
920
 
 
921
                                n_units = MAX(2*c, 16u);
 
922
                                w = realloc(units, sizeof(struct UnitFileList) * n_units);
 
923
                                if (!w)
 
924
                                        return log_oom();
 
925
 
 
926
                                units = w;
 
927
                        }
 
928
 
 
929
                        u = units + c;
 
930
 
 
931
                        dbus_message_iter_recurse(&sub, &sub2);
 
932
 
 
933
                        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
 
934
                            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
 
935
                                log_error("Failed to parse reply.");
 
936
                                return -EIO;
 
937
                        }
 
938
 
 
939
                        u->state = unit_file_state_from_string(state);
 
940
 
 
941
                        dbus_message_iter_next(&sub);
 
942
                        c++;
 
943
                }
 
944
        }
 
945
 
 
946
        if (c > 0) {
 
947
                qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
 
948
                output_unit_file_list(units, c);
 
949
        }
 
950
 
 
951
        return 0;
 
952
}
 
953
 
 
954
static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
 
955
        int i;
 
956
        _cleanup_free_ char *n = NULL;
 
957
        size_t len = 0;
 
958
        size_t max_len = MAX(columns(),20u);
 
959
 
 
960
        if (!arg_plain) {
 
961
                for (i = level - 1; i >= 0; i--) {
 
962
                        len += 2;
 
963
                        if(len > max_len - 3 && !arg_full) {
 
964
                                printf("%s...\n",max_len % 2 ? "" : " ");
 
965
                                return 0;
 
966
                        }
 
967
                        printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
 
968
                }
 
969
                len += 2;
 
970
                if(len > max_len - 3 && !arg_full) {
 
971
                        printf("%s...\n",max_len % 2 ? "" : " ");
 
972
                        return 0;
 
973
                }
 
974
                printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
 
975
        }
 
976
 
 
977
        if(arg_full){
 
978
                printf("%s\n", name);
 
979
                return 0;
 
980
        }
 
981
 
 
982
        n = ellipsize(name, max_len-len, 100);
 
983
        if(!n)
 
984
                return log_oom();
 
985
 
 
986
        printf("%s\n", n);
 
987
        return 0;
 
988
}
 
989
 
 
990
static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
 
991
        static const char *dependencies[] = {
 
992
                [DEPENDENCY_FORWARD] = "Requires\0"
 
993
                                       "RequiresOverridable\0"
 
994
                                       "Requisite\0"
 
995
                                       "RequisiteOverridable\0"
 
996
                                       "Wants\0",
 
997
                [DEPENDENCY_REVERSE] = "RequiredBy\0"
 
998
                                       "RequiredByOverridable\0"
 
999
                                       "WantedBy\0"
 
1000
                                       "PartOf\0",
 
1001
                [DEPENDENCY_AFTER]   = "After\0",
 
1002
                [DEPENDENCY_BEFORE]  = "Before\0",
 
1003
        };
 
1004
 
 
1005
        _cleanup_free_ char *path;
 
1006
        const char *interface = "org.freedesktop.systemd1.Unit";
 
1007
 
 
1008
        _cleanup_dbus_message_unref_  DBusMessage *reply = NULL;
 
1009
        DBusMessageIter iter, sub, sub2, sub3;
 
1010
 
 
1011
        int r = 0;
 
1012
        char **ret = NULL;
 
1013
 
 
1014
        assert(bus);
 
1015
        assert(name);
 
1016
        assert(deps);
 
1017
 
 
1018
        path = unit_dbus_path_from_name(name);
 
1019
        if (path == NULL) {
 
1020
                r = -EINVAL;
 
1021
                goto finish;
 
1022
        }
 
1023
 
 
1024
        r = bus_method_call_with_reply(
 
1025
                bus,
 
1026
                "org.freedesktop.systemd1",
 
1027
                path,
 
1028
                "org.freedesktop.DBus.Properties",
 
1029
                "GetAll",
 
1030
                &reply,
 
1031
                NULL,
 
1032
                DBUS_TYPE_STRING, &interface,
 
1033
                DBUS_TYPE_INVALID);
 
1034
        if (r < 0)
 
1035
                goto finish;
 
1036
 
 
1037
        if (!dbus_message_iter_init(reply, &iter) ||
 
1038
                dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
1039
                dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
 
1040
                log_error("Failed to parse reply.");
 
1041
                r = -EIO;
 
1042
                goto finish;
 
1043
        }
 
1044
 
 
1045
        dbus_message_iter_recurse(&iter, &sub);
 
1046
 
 
1047
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1048
                const char *prop;
 
1049
 
 
1050
                assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
 
1051
                dbus_message_iter_recurse(&sub, &sub2);
 
1052
 
 
1053
                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
 
1054
                        log_error("Failed to parse reply.");
 
1055
                        r = -EIO;
 
1056
                        goto finish;
 
1057
                }
 
1058
 
 
1059
                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
 
1060
                        log_error("Failed to parse reply.");
 
1061
                        r = -EIO;
 
1062
                        goto finish;
 
1063
                }
 
1064
 
 
1065
                dbus_message_iter_recurse(&sub2, &sub3);
 
1066
                dbus_message_iter_next(&sub);
 
1067
 
 
1068
                assert(arg_dependency < ELEMENTSOF(dependencies));
 
1069
                if (!nulstr_contains(dependencies[arg_dependency], prop))
 
1070
                        continue;
 
1071
 
 
1072
                if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
 
1073
                        if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) {
 
1074
                                DBusMessageIter sub4;
 
1075
                                dbus_message_iter_recurse(&sub3, &sub4);
 
1076
 
 
1077
                                while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
 
1078
                                        const char *s;
 
1079
 
 
1080
                                        assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING);
 
1081
                                        dbus_message_iter_get_basic(&sub4, &s);
 
1082
 
 
1083
                                        r = strv_extend(&ret, s);
 
1084
                                        if (r < 0) {
 
1085
                                                log_oom();
 
1086
                                                goto finish;
 
1087
                                        }
 
1088
 
 
1089
                                        dbus_message_iter_next(&sub4);
 
1090
                                }
 
1091
                        }
 
1092
                }
 
1093
        }
 
1094
finish:
 
1095
        if (r < 0)
 
1096
                strv_free(ret);
 
1097
        else
 
1098
                *deps = ret;
 
1099
        return r;
 
1100
}
 
1101
 
 
1102
static int list_dependencies_compare(const void *_a, const void *_b) {
 
1103
        const char **a = (const char**) _a, **b = (const char**) _b;
 
1104
        if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
 
1105
                return 1;
 
1106
        if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
 
1107
                return -1;
 
1108
        return strcasecmp(*a, *b);
 
1109
}
 
1110
 
 
1111
static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char ***units, unsigned int branches) {
 
1112
        _cleanup_strv_free_ char **deps = NULL, **u;
 
1113
        char **c;
 
1114
        int r = 0;
 
1115
 
 
1116
        u = strv_append(*units, name);
 
1117
        if (!u)
 
1118
                return log_oom();
 
1119
 
 
1120
        r = list_dependencies_get_dependencies(bus, name, &deps);
 
1121
        if (r < 0)
 
1122
                return r;
 
1123
 
 
1124
        qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
 
1125
 
 
1126
        STRV_FOREACH(c, deps) {
 
1127
                if (strv_contains(u, *c)) {
 
1128
                        if (!arg_plain) {
 
1129
                                r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
 
1130
                                if (r < 0)
 
1131
                                        return r;
 
1132
                        }
 
1133
                        continue;
 
1134
                }
 
1135
 
 
1136
                r = list_dependencies_print(*c, level, branches, c[1] == NULL);
 
1137
                if (r < 0)
 
1138
                        return r;
 
1139
 
 
1140
                if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
 
1141
                       r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1));
 
1142
                       if(r < 0)
 
1143
                               return r;
 
1144
                }
 
1145
        }
 
1146
        if (arg_plain) {
 
1147
                strv_free(*units);
 
1148
                *units = u;
 
1149
                u = NULL;
 
1150
        }
 
1151
        return 0;
 
1152
}
 
1153
 
 
1154
static int list_dependencies(DBusConnection *bus, char **args) {
 
1155
        _cleanup_free_ char *unit = NULL;
 
1156
        _cleanup_strv_free_ char **units = NULL;
 
1157
        const char *u;
 
1158
 
 
1159
        assert(bus);
 
1160
 
 
1161
        if (args[1]) {
 
1162
                unit = unit_name_mangle(args[1]);
 
1163
                if (!unit)
 
1164
                        return log_oom();
 
1165
                u = unit;
 
1166
        } else
 
1167
                u = SPECIAL_DEFAULT_TARGET;
 
1168
 
 
1169
        pager_open_if_enabled();
 
1170
 
 
1171
        puts(u);
 
1172
 
 
1173
        return list_dependencies_one(bus, u, 0, &units, 0);
 
1174
}
 
1175
 
 
1176
struct job_info {
 
1177
        uint32_t id;
 
1178
        char *name, *type, *state;
 
1179
};
 
1180
 
 
1181
static void list_jobs_print(struct job_info* jobs, size_t n) {
 
1182
        size_t i;
 
1183
        struct job_info *j;
 
1184
        const char *on, *off;
 
1185
        bool shorten = false;
 
1186
 
 
1187
        assert(n == 0 || jobs);
 
1188
 
 
1189
        if (n == 0) {
 
1190
                on = ansi_highlight_green(true);
 
1191
                off = ansi_highlight_green(false);
 
1192
 
 
1193
                printf("%sNo jobs running.%s\n", on, off);
 
1194
                return;
 
1195
        }
 
1196
 
 
1197
        pager_open_if_enabled();
 
1198
 
 
1199
        {
 
1200
                /* JOB UNIT TYPE STATE */
 
1201
                unsigned l0 = 3, l1 = 4, l2 = 4, l3 = 5;
 
1202
 
 
1203
                for (i = 0, j = jobs; i < n; i++, j++) {
 
1204
                        assert(j->name && j->type && j->state);
 
1205
                        l0 = MAX(l0, DECIMAL_STR_WIDTH(j->id));
 
1206
                        l1 = MAX(l1, strlen(j->name));
 
1207
                        l2 = MAX(l2, strlen(j->type));
 
1208
                        l3 = MAX(l3, strlen(j->state));
 
1209
                }
 
1210
 
 
1211
                if (!arg_full && l0 + 1 + l1 + l2 + 1 + l3 > columns()) {
 
1212
                        l1 = MAX(33u, columns() - l0 - l2 - l3 - 3);
 
1213
                        shorten = true;
 
1214
                }
 
1215
 
 
1216
                if (on_tty())
 
1217
                        printf("%*s %-*s %-*s %-*s\n",
 
1218
                               l0, "JOB",
 
1219
                               l1, "UNIT",
 
1220
                               l2, "TYPE",
 
1221
                               l3, "STATE");
 
1222
 
 
1223
                for (i = 0, j = jobs; i < n; i++, j++) {
 
1224
                        _cleanup_free_ char *e = NULL;
 
1225
 
 
1226
                        if (streq(j->state, "running")) {
 
1227
                                on = ansi_highlight(true);
 
1228
                                off = ansi_highlight(false);
 
1229
                        } else
 
1230
                                on = off = "";
 
1231
 
 
1232
                        e = shorten ? ellipsize(j->name, l1, 33) : NULL;
 
1233
                        printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
 
1234
                               l0, j->id,
 
1235
                               on, l1, e ? e : j->name, off,
 
1236
                               l2, j->type,
 
1237
                               on, l3, j->state, off);
 
1238
                }
 
1239
        }
 
1240
 
 
1241
        on = ansi_highlight(true);
 
1242
        off = ansi_highlight(false);
 
1243
 
 
1244
        if (on_tty())
 
1245
                printf("\n%s%zu jobs listed%s.\n", on, n, off);
 
1246
}
 
1247
 
 
1248
static int list_jobs(DBusConnection *bus, char **args) {
 
1249
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
1250
        DBusMessageIter iter, sub, sub2;
 
1251
        int r;
 
1252
        struct job_info *jobs = NULL;
 
1253
        size_t size = 0, used = 0;
 
1254
 
 
1255
        r = bus_method_call_with_reply(
 
1256
                        bus,
 
1257
                        "org.freedesktop.systemd1",
 
1258
                        "/org/freedesktop/systemd1",
 
1259
                        "org.freedesktop.systemd1.Manager",
 
1260
                        "ListJobs",
 
1261
                        &reply,
 
1262
                        NULL,
 
1263
                        DBUS_TYPE_INVALID);
 
1264
        if (r < 0)
 
1265
                return r;
 
1266
 
 
1267
        if (!dbus_message_iter_init(reply, &iter) ||
 
1268
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
1269
            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
 
1270
                log_error("Failed to parse reply.");
 
1271
                return -EIO;
 
1272
        }
 
1273
 
 
1274
        dbus_message_iter_recurse(&iter, &sub);
 
1275
 
 
1276
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1277
                const char *name, *type, *state, *job_path, *unit_path;
 
1278
                uint32_t id;
 
1279
 
 
1280
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
 
1281
                        log_error("Failed to parse reply.");
 
1282
                        return -EIO;
 
1283
                }
 
1284
 
 
1285
                dbus_message_iter_recurse(&sub, &sub2);
 
1286
 
 
1287
                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
 
1288
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
 
1289
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
 
1290
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
 
1291
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
 
1292
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
 
1293
                        log_error("Failed to parse reply.");
 
1294
                        r = -EIO;
 
1295
                        goto finish;
 
1296
                }
 
1297
 
 
1298
                if (!GREEDY_REALLOC(jobs, size, used + 1)) {
 
1299
                        r = log_oom();
 
1300
                        goto finish;
 
1301
                }
 
1302
 
 
1303
                jobs[used++] = (struct job_info) { id,
 
1304
                                                   strdup(name),
 
1305
                                                   strdup(type),
 
1306
                                                   strdup(state) };
 
1307
                if (!jobs[used-1].name || !jobs[used-1].type || !jobs[used-1].state) {
 
1308
                        r = log_oom();
 
1309
                        goto finish;
 
1310
                }
 
1311
 
 
1312
                dbus_message_iter_next(&sub);
 
1313
        }
 
1314
 
 
1315
        list_jobs_print(jobs, used);
 
1316
 
 
1317
 finish:
 
1318
        while (used--) {
 
1319
                free(jobs[used].name);
 
1320
                free(jobs[used].type);
 
1321
                free(jobs[used].state);
 
1322
        }
 
1323
        free(jobs);
 
1324
 
 
1325
        return 0;
 
1326
}
 
1327
 
 
1328
static int load_unit(DBusConnection *bus, char **args) {
 
1329
        char **name;
 
1330
 
 
1331
        assert(args);
 
1332
 
 
1333
        STRV_FOREACH(name, args+1) {
 
1334
                _cleanup_free_ char *n = NULL;
 
1335
                int r;
 
1336
 
 
1337
                n = unit_name_mangle(*name);
 
1338
                if (!n)
 
1339
                        return log_oom();
 
1340
 
 
1341
                r = bus_method_call_with_reply(
 
1342
                                bus,
 
1343
                                "org.freedesktop.systemd1",
 
1344
                                "/org/freedesktop/systemd1",
 
1345
                                "org.freedesktop.systemd1.Manager",
 
1346
                                "LoadUnit",
 
1347
                                NULL,
 
1348
                                NULL,
 
1349
                                DBUS_TYPE_STRING, &n,
 
1350
                                DBUS_TYPE_INVALID);
 
1351
                if (r < 0)
 
1352
                        return r;
 
1353
        }
 
1354
 
 
1355
        return 0;
 
1356
}
 
1357
 
 
1358
static int cancel_job(DBusConnection *bus, char **args) {
 
1359
        char **name;
 
1360
 
 
1361
        assert(args);
 
1362
 
 
1363
        if (strv_length(args) <= 1)
 
1364
                return daemon_reload(bus, args);
 
1365
 
 
1366
        STRV_FOREACH(name, args+1) {
 
1367
                uint32_t id;
 
1368
                int r;
 
1369
 
 
1370
                r = safe_atou32(*name, &id);
 
1371
                if (r < 0) {
 
1372
                        log_error("Failed to parse job id: %s", strerror(-r));
 
1373
                        return r;
 
1374
                }
 
1375
 
 
1376
                r = bus_method_call_with_reply(
 
1377
                                bus,
 
1378
                                "org.freedesktop.systemd1",
 
1379
                                "/org/freedesktop/systemd1",
 
1380
                                "org.freedesktop.systemd1.Manager",
 
1381
                                "CancelJob",
 
1382
                                NULL,
 
1383
                                NULL,
 
1384
                                DBUS_TYPE_UINT32, &id,
 
1385
                                DBUS_TYPE_INVALID);
 
1386
                if (r < 0)
 
1387
                        return r;
 
1388
        }
 
1389
 
 
1390
        return 0;
 
1391
}
 
1392
 
 
1393
static bool need_daemon_reload(DBusConnection *bus, const char *unit) {
 
1394
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
1395
        dbus_bool_t b = FALSE;
 
1396
        DBusMessageIter iter, sub;
 
1397
        const char
 
1398
                *interface = "org.freedesktop.systemd1.Unit",
 
1399
                *property = "NeedDaemonReload",
 
1400
                *path;
 
1401
        _cleanup_free_ char *n = NULL;
 
1402
        int r;
 
1403
 
 
1404
        /* We ignore all errors here, since this is used to show a warning only */
 
1405
 
 
1406
        n = unit_name_mangle(unit);
 
1407
        if (!n)
 
1408
                return log_oom();
 
1409
 
 
1410
        r = bus_method_call_with_reply(
 
1411
                        bus,
 
1412
                        "org.freedesktop.systemd1",
 
1413
                        "/org/freedesktop/systemd1",
 
1414
                        "org.freedesktop.systemd1.Manager",
 
1415
                        "GetUnit",
 
1416
                        &reply,
 
1417
                        NULL,
 
1418
                        DBUS_TYPE_STRING, &n,
 
1419
                        DBUS_TYPE_INVALID);
 
1420
        if (r < 0)
 
1421
                return r;
 
1422
 
 
1423
        if (!dbus_message_get_args(reply, NULL,
 
1424
                                   DBUS_TYPE_OBJECT_PATH, &path,
 
1425
                                   DBUS_TYPE_INVALID))
 
1426
                return -EIO;
 
1427
 
 
1428
        dbus_message_unref(reply);
 
1429
        reply = NULL;
 
1430
 
 
1431
        r = bus_method_call_with_reply(
 
1432
                        bus,
 
1433
                        "org.freedesktop.systemd1",
 
1434
                        path,
 
1435
                        "org.freedesktop.DBus.Properties",
 
1436
                        "Get",
 
1437
                        &reply,
 
1438
                        NULL,
 
1439
                        DBUS_TYPE_STRING, &interface,
 
1440
                        DBUS_TYPE_STRING, &property,
 
1441
                        DBUS_TYPE_INVALID);
 
1442
        if (r < 0)
 
1443
                return r;
 
1444
 
 
1445
        if (!dbus_message_iter_init(reply, &iter) ||
 
1446
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
 
1447
                return -EIO;
 
1448
 
 
1449
        dbus_message_iter_recurse(&iter, &sub);
 
1450
        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
 
1451
                return -EIO;
 
1452
 
 
1453
        dbus_message_iter_get_basic(&sub, &b);
 
1454
        return b;
 
1455
}
 
1456
 
 
1457
typedef struct WaitData {
 
1458
        Set *set;
 
1459
 
 
1460
        char *name;
 
1461
        char *result;
 
1462
} WaitData;
 
1463
 
 
1464
static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
 
1465
        _cleanup_dbus_error_free_ DBusError error;
 
1466
        WaitData *d = data;
 
1467
 
 
1468
        dbus_error_init(&error);
 
1469
 
 
1470
        assert(connection);
 
1471
        assert(message);
 
1472
        assert(d);
 
1473
 
 
1474
        log_debug("Got D-Bus request: %s.%s() on %s",
 
1475
                  dbus_message_get_interface(message),
 
1476
                  dbus_message_get_member(message),
 
1477
                  dbus_message_get_path(message));
 
1478
 
 
1479
        if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
 
1480
                log_error("Warning! D-Bus connection terminated.");
 
1481
                dbus_connection_close(connection);
 
1482
 
 
1483
        } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
 
1484
                uint32_t id;
 
1485
                const char *path, *result, *unit;
 
1486
 
 
1487
                if (dbus_message_get_args(message, &error,
 
1488
                                          DBUS_TYPE_UINT32, &id,
 
1489
                                          DBUS_TYPE_OBJECT_PATH, &path,
 
1490
                                          DBUS_TYPE_STRING, &unit,
 
1491
                                          DBUS_TYPE_STRING, &result,
 
1492
                                          DBUS_TYPE_INVALID)) {
 
1493
 
 
1494
                        free(set_remove(d->set, (char*) path));
 
1495
 
 
1496
                        if (!isempty(result))
 
1497
                                d->result = strdup(result);
 
1498
 
 
1499
                        if (!isempty(unit))
 
1500
                                d->name = strdup(unit);
 
1501
 
 
1502
                        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
1503
                }
 
1504
#ifndef LEGACY
 
1505
                dbus_error_free(&error);
 
1506
                if (dbus_message_get_args(message, &error,
 
1507
                                          DBUS_TYPE_UINT32, &id,
 
1508
                                          DBUS_TYPE_OBJECT_PATH, &path,
 
1509
                                          DBUS_TYPE_STRING, &result,
 
1510
                                          DBUS_TYPE_INVALID)) {
 
1511
                        /* Compatibility with older systemd versions <
 
1512
                         * 183 during upgrades. This should be dropped
 
1513
                         * one day. */
 
1514
                        free(set_remove(d->set, (char*) path));
 
1515
 
 
1516
                        if (*result)
 
1517
                                d->result = strdup(result);
 
1518
 
 
1519
                        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
1520
                }
 
1521
#endif
 
1522
 
 
1523
                log_error("Failed to parse message: %s", bus_error_message(&error));
 
1524
        }
 
1525
 
 
1526
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
1527
}
 
1528
 
 
1529
static int enable_wait_for_jobs(DBusConnection *bus) {
 
1530
        DBusError error;
 
1531
 
 
1532
        assert(bus);
 
1533
 
 
1534
        if (private_bus)
 
1535
                return 0;
 
1536
 
 
1537
        dbus_error_init(&error);
 
1538
        dbus_bus_add_match(bus,
 
1539
                           "type='signal',"
 
1540
                           "sender='org.freedesktop.systemd1',"
 
1541
                           "interface='org.freedesktop.systemd1.Manager',"
 
1542
                           "member='JobRemoved',"
 
1543
                           "path='/org/freedesktop/systemd1'",
 
1544
                           &error);
 
1545
 
 
1546
        if (dbus_error_is_set(&error)) {
 
1547
                log_error("Failed to add match: %s", bus_error_message(&error));
 
1548
                dbus_error_free(&error);
 
1549
                return -EIO;
 
1550
        }
 
1551
 
 
1552
        /* This is slightly dirty, since we don't undo the match registrations. */
 
1553
        return 0;
 
1554
}
 
1555
 
 
1556
static int wait_for_jobs(DBusConnection *bus, Set *s) {
 
1557
        int r = 0;
 
1558
        WaitData d = { .set = s };
 
1559
 
 
1560
        assert(bus);
 
1561
        assert(s);
 
1562
 
 
1563
        if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
 
1564
                return log_oom();
 
1565
 
 
1566
        while (!set_isempty(s)) {
 
1567
 
 
1568
                if (!dbus_connection_read_write_dispatch(bus, -1)) {
 
1569
                        log_error("Disconnected from bus.");
 
1570
                        return -ECONNREFUSED;
 
1571
                }
 
1572
 
 
1573
                if (!d.result)
 
1574
                        goto free_name;
 
1575
 
 
1576
                if (!arg_quiet) {
 
1577
                        if (streq(d.result, "timeout"))
 
1578
                                log_error("Job for %s timed out.", strna(d.name));
 
1579
                        else if (streq(d.result, "canceled"))
 
1580
                                log_error("Job for %s canceled.", strna(d.name));
 
1581
                        else if (streq(d.result, "dependency"))
 
1582
                                log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
 
1583
                        else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
 
1584
                                log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
 
1585
                }
 
1586
 
 
1587
                if (streq_ptr(d.result, "timeout"))
 
1588
                        r = -ETIME;
 
1589
                else if (streq_ptr(d.result, "canceled"))
 
1590
                        r = -ECANCELED;
 
1591
                else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
 
1592
                        r = -EIO;
 
1593
 
 
1594
                free(d.result);
 
1595
                d.result = NULL;
 
1596
 
 
1597
        free_name:
 
1598
                free(d.name);
 
1599
                d.name = NULL;
 
1600
        }
 
1601
 
 
1602
        dbus_connection_remove_filter(bus, wait_filter, &d);
 
1603
        return r;
 
1604
}
 
1605
 
 
1606
static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
 
1607
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
1608
        _cleanup_free_ char *n = NULL;
 
1609
        DBusMessageIter iter, sub;
 
1610
        const char
 
1611
                *interface = "org.freedesktop.systemd1.Unit",
 
1612
                *property = "ActiveState";
 
1613
        const char *state, *path;
 
1614
        DBusError error;
 
1615
        int r;
 
1616
 
 
1617
        assert(name);
 
1618
 
 
1619
        dbus_error_init(&error);
 
1620
 
 
1621
        n = unit_name_mangle(name);
 
1622
        if (!n)
 
1623
                return log_oom();
 
1624
 
 
1625
        r = bus_method_call_with_reply (
 
1626
                        bus,
 
1627
                        "org.freedesktop.systemd1",
 
1628
                        "/org/freedesktop/systemd1",
 
1629
                        "org.freedesktop.systemd1.Manager",
 
1630
                        "GetUnit",
 
1631
                        &reply,
 
1632
                        &error,
 
1633
                        DBUS_TYPE_STRING, &n,
 
1634
                        DBUS_TYPE_INVALID);
 
1635
        if (r < 0) {
 
1636
                dbus_error_free(&error);
 
1637
 
 
1638
                if (!quiet)
 
1639
                        puts("unknown");
 
1640
                return 0;
 
1641
        }
 
1642
 
 
1643
        if (!dbus_message_get_args(reply, NULL,
 
1644
                                   DBUS_TYPE_OBJECT_PATH, &path,
 
1645
                                   DBUS_TYPE_INVALID)) {
 
1646
                log_error("Failed to parse reply.");
 
1647
                return -EIO;
 
1648
        }
 
1649
 
 
1650
        dbus_message_unref(reply);
 
1651
        reply = NULL;
 
1652
 
 
1653
        r = bus_method_call_with_reply(
 
1654
                        bus,
 
1655
                        "org.freedesktop.systemd1",
 
1656
                        path,
 
1657
                        "org.freedesktop.DBus.Properties",
 
1658
                        "Get",
 
1659
                        &reply,
 
1660
                        NULL,
 
1661
                        DBUS_TYPE_STRING, &interface,
 
1662
                        DBUS_TYPE_STRING, &property,
 
1663
                        DBUS_TYPE_INVALID);
 
1664
        if (r < 0) {
 
1665
                if (!quiet)
 
1666
                        puts("unknown");
 
1667
                return 0;
 
1668
        }
 
1669
 
 
1670
        if (!dbus_message_iter_init(reply, &iter) ||
 
1671
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
 
1672
                log_error("Failed to parse reply.");
 
1673
                return r;
 
1674
        }
 
1675
 
 
1676
        dbus_message_iter_recurse(&iter, &sub);
 
1677
 
 
1678
        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
 
1679
                log_error("Failed to parse reply.");
 
1680
                return r;
 
1681
        }
 
1682
 
 
1683
        dbus_message_iter_get_basic(&sub, &state);
 
1684
 
 
1685
        if (!quiet)
 
1686
                puts(state);
 
1687
 
 
1688
        return strv_find(check_states, state) ? 1 : 0;
 
1689
}
 
1690
 
 
1691
static void check_triggering_units(
 
1692
                DBusConnection *bus,
 
1693
                const char *unit_name) {
 
1694
 
 
1695
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
1696
        DBusMessageIter iter, sub;
 
1697
        const char *interface = "org.freedesktop.systemd1.Unit",
 
1698
                   *load_state_property = "LoadState",
 
1699
                   *triggered_by_property = "TriggeredBy",
 
1700
                   *state;
 
1701
        _cleanup_free_ char *unit_path = NULL, *n = NULL;
 
1702
        bool print_warning_label = true;
 
1703
        int r;
 
1704
 
 
1705
        n = unit_name_mangle(unit_name);
 
1706
        if (!n) {
 
1707
                log_oom();
 
1708
                return;
 
1709
        }
 
1710
 
 
1711
        unit_path = unit_dbus_path_from_name(n);
 
1712
        if (!unit_path) {
 
1713
                log_oom();
 
1714
                return;
 
1715
        }
 
1716
 
 
1717
        r = bus_method_call_with_reply(
 
1718
                        bus,
 
1719
                        "org.freedesktop.systemd1",
 
1720
                        unit_path,
 
1721
                        "org.freedesktop.DBus.Properties",
 
1722
                        "Get",
 
1723
                        &reply,
 
1724
                        NULL,
 
1725
                        DBUS_TYPE_STRING, &interface,
 
1726
                        DBUS_TYPE_STRING, &load_state_property,
 
1727
                        DBUS_TYPE_INVALID);
 
1728
        if (r < 0)
 
1729
                return;
 
1730
 
 
1731
        if (!dbus_message_iter_init(reply, &iter) ||
 
1732
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
 
1733
                log_error("Failed to parse reply.");
 
1734
                return;
 
1735
        }
 
1736
 
 
1737
        dbus_message_iter_recurse(&iter, &sub);
 
1738
 
 
1739
        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
 
1740
            log_error("Failed to parse reply.");
 
1741
            return;
 
1742
        }
 
1743
 
 
1744
        dbus_message_iter_get_basic(&sub, &state);
 
1745
 
 
1746
        if (streq(state, "masked"))
 
1747
            return;
 
1748
 
 
1749
        dbus_message_unref(reply);
 
1750
        reply = NULL;
 
1751
 
 
1752
        r = bus_method_call_with_reply(
 
1753
                        bus,
 
1754
                        "org.freedesktop.systemd1",
 
1755
                        unit_path,
 
1756
                        "org.freedesktop.DBus.Properties",
 
1757
                        "Get",
 
1758
                        &reply,
 
1759
                        NULL,
 
1760
                        DBUS_TYPE_STRING, &interface,
 
1761
                        DBUS_TYPE_STRING, &triggered_by_property,
 
1762
                        DBUS_TYPE_INVALID);
 
1763
        if (r < 0)
 
1764
                return;
 
1765
 
 
1766
        if (!dbus_message_iter_init(reply, &iter) ||
 
1767
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
 
1768
                log_error("Failed to parse reply.");
 
1769
                return;
 
1770
        }
 
1771
 
 
1772
        dbus_message_iter_recurse(&iter, &sub);
 
1773
        dbus_message_iter_recurse(&sub, &iter);
 
1774
        sub = iter;
 
1775
 
 
1776
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
1777
                const char * const check_states[] = {
 
1778
                        "active",
 
1779
                        "reloading",
 
1780
                        NULL
 
1781
                };
 
1782
                const char *service_trigger;
 
1783
 
 
1784
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
 
1785
                        log_error("Failed to parse reply.");
 
1786
                        return;
 
1787
                }
 
1788
 
 
1789
                dbus_message_iter_get_basic(&sub, &service_trigger);
 
1790
 
 
1791
                r = check_one_unit(bus, service_trigger, (char**) check_states, true);
 
1792
                if (r < 0)
 
1793
                        return;
 
1794
                if (r > 0) {
 
1795
                        if (print_warning_label) {
 
1796
                                log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
 
1797
                                print_warning_label = false;
 
1798
                        }
 
1799
 
 
1800
                        log_warning("  %s", service_trigger);
 
1801
                }
 
1802
 
 
1803
                dbus_message_iter_next(&sub);
 
1804
        }
 
1805
}
 
1806
 
 
1807
static int start_unit_one(
 
1808
                DBusConnection *bus,
 
1809
                const char *method,
 
1810
                const char *name,
 
1811
                const char *mode,
 
1812
                DBusError *error,
 
1813
                Set *s) {
 
1814
 
 
1815
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
1816
        _cleanup_free_ char *n;
 
1817
        const char *path;
 
1818
        int r;
 
1819
 
 
1820
        assert(method);
 
1821
        assert(name);
 
1822
        assert(mode);
 
1823
        assert(error);
 
1824
 
 
1825
        n = unit_name_mangle(name);
 
1826
        if (!n)
 
1827
                return log_oom();
 
1828
 
 
1829
        r = bus_method_call_with_reply(
 
1830
                        bus,
 
1831
                        "org.freedesktop.systemd1",
 
1832
                        "/org/freedesktop/systemd1",
 
1833
                        "org.freedesktop.systemd1.Manager",
 
1834
                        method,
 
1835
                        &reply,
 
1836
                        error,
 
1837
                        DBUS_TYPE_STRING, &n,
 
1838
                        DBUS_TYPE_STRING, &mode,
 
1839
                        DBUS_TYPE_INVALID);
 
1840
        if (r) {
 
1841
                if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
 
1842
                        /* There's always a fallback possible for
 
1843
                         * legacy actions. */
 
1844
                        r = -EADDRNOTAVAIL;
 
1845
                else
 
1846
                        log_error("Failed to issue method call: %s", bus_error_message(error));
 
1847
 
 
1848
                return r;
 
1849
        }
 
1850
 
 
1851
        if (!dbus_message_get_args(reply, error,
 
1852
                                   DBUS_TYPE_OBJECT_PATH, &path,
 
1853
                                   DBUS_TYPE_INVALID)) {
 
1854
                log_error("Failed to parse reply: %s", bus_error_message(error));
 
1855
                return -EIO;
 
1856
        }
 
1857
 
 
1858
        if (need_daemon_reload(bus, n))
 
1859
                log_warning("Warning: Unit file of %s changed on disk, 'systemctl %s daemon-reload' recommended.",
 
1860
                            n, arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
 
1861
 
 
1862
        if (s) {
 
1863
                char *p;
 
1864
 
 
1865
                p = strdup(path);
 
1866
                if (!p)
 
1867
                        return log_oom();
 
1868
 
 
1869
                r = set_consume(s, p);
 
1870
                if (r < 0) {
 
1871
                        log_error("Failed to add path to set.");
 
1872
                        return r;
 
1873
                }
 
1874
        }
 
1875
 
 
1876
        return 0;
 
1877
}
 
1878
 
 
1879
static const struct {
 
1880
        const char *target;
 
1881
        const char *verb;
 
1882
        const char *mode;
 
1883
} action_table[_ACTION_MAX] = {
 
1884
        [ACTION_HALT]         = { SPECIAL_HALT_TARGET,         "halt",         "replace-irreversibly" },
 
1885
        [ACTION_POWEROFF]     = { SPECIAL_POWEROFF_TARGET,     "poweroff",     "replace-irreversibly" },
 
1886
        [ACTION_REBOOT]       = { SPECIAL_REBOOT_TARGET,       "reboot",       "replace-irreversibly" },
 
1887
        [ACTION_KEXEC]        = { SPECIAL_KEXEC_TARGET,        "kexec",        "replace-irreversibly" },
 
1888
        [ACTION_RUNLEVEL2]    = { SPECIAL_RUNLEVEL2_TARGET,    NULL,           "isolate" },
 
1889
        [ACTION_RUNLEVEL3]    = { SPECIAL_RUNLEVEL3_TARGET,    NULL,           "isolate" },
 
1890
        [ACTION_RUNLEVEL4]    = { SPECIAL_RUNLEVEL4_TARGET,    NULL,           "isolate" },
 
1891
        [ACTION_RUNLEVEL5]    = { SPECIAL_RUNLEVEL5_TARGET,    NULL,           "isolate" },
 
1892
        [ACTION_RESCUE]       = { SPECIAL_RESCUE_TARGET,       "rescue",       "isolate" },
 
1893
        [ACTION_EMERGENCY]    = { SPECIAL_EMERGENCY_TARGET,    "emergency",    "isolate" },
 
1894
        [ACTION_DEFAULT]      = { SPECIAL_DEFAULT_TARGET,      "default",      "isolate" },
 
1895
        [ACTION_EXIT]         = { SPECIAL_EXIT_TARGET,         "exit",         "replace-irreversibly" },
 
1896
        [ACTION_SUSPEND]      = { SPECIAL_SUSPEND_TARGET,      "suspend",      "replace-irreversibly" },
 
1897
        [ACTION_HIBERNATE]    = { SPECIAL_HIBERNATE_TARGET,    "hibernate",    "replace-irreversibly" },
 
1898
        [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
 
1899
};
 
1900
 
 
1901
static enum action verb_to_action(const char *verb) {
 
1902
        enum action i;
 
1903
 
 
1904
        for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
 
1905
                if (action_table[i].verb && streq(verb, action_table[i].verb))
 
1906
                        return i;
 
1907
        return ACTION_INVALID;
 
1908
}
 
1909
 
 
1910
static int start_unit(DBusConnection *bus, char **args) {
 
1911
 
 
1912
        int r, ret = 0;
 
1913
        const char *method, *mode, *one_name;
 
1914
        _cleanup_set_free_free_ Set *s = NULL;
 
1915
        _cleanup_dbus_error_free_ DBusError error;
 
1916
        char **name;
 
1917
 
 
1918
        dbus_error_init(&error);
 
1919
 
 
1920
        assert(bus);
 
1921
 
 
1922
        ask_password_agent_open_if_enabled();
 
1923
 
 
1924
        if (arg_action == ACTION_SYSTEMCTL) {
 
1925
                enum action action;
 
1926
                method =
 
1927
                        streq(args[0], "stop") ||
 
1928
                        streq(args[0], "condstop")              ? "StopUnit" :
 
1929
                        streq(args[0], "reload")                ? "ReloadUnit" :
 
1930
                        streq(args[0], "restart")               ? "RestartUnit" :
 
1931
 
 
1932
                        streq(args[0], "try-restart")           ||
 
1933
                        streq(args[0], "condrestart")           ? "TryRestartUnit" :
 
1934
 
 
1935
                        streq(args[0], "reload-or-restart")     ? "ReloadOrRestartUnit" :
 
1936
 
 
1937
                        streq(args[0], "reload-or-try-restart") ||
 
1938
                        streq(args[0], "condreload") ||
 
1939
 
 
1940
                        streq(args[0], "force-reload")          ? "ReloadOrTryRestartUnit" :
 
1941
                                                                  "StartUnit";
 
1942
                action = verb_to_action(args[0]);
 
1943
 
 
1944
                mode = streq(args[0], "isolate") ? "isolate" :
 
1945
                       action_table[action].mode ?: arg_job_mode;
 
1946
 
 
1947
                one_name = action_table[action].target;
 
1948
 
 
1949
        } else {
 
1950
                assert(arg_action < ELEMENTSOF(action_table));
 
1951
                assert(action_table[arg_action].target);
 
1952
 
 
1953
                method = "StartUnit";
 
1954
 
 
1955
                mode = action_table[arg_action].mode;
 
1956
                one_name = action_table[arg_action].target;
 
1957
        }
 
1958
 
 
1959
        if (!arg_no_block) {
 
1960
                ret = enable_wait_for_jobs(bus);
 
1961
                if (ret < 0) {
 
1962
                        log_error("Could not watch jobs: %s", strerror(-ret));
 
1963
                        return ret;
 
1964
                }
 
1965
 
 
1966
                s = set_new(string_hash_func, string_compare_func);
 
1967
                if (!s)
 
1968
                        return log_oom();
 
1969
        }
 
1970
 
 
1971
        if (one_name) {
 
1972
                ret = start_unit_one(bus, method, one_name, mode, &error, s);
 
1973
                if (ret < 0)
 
1974
                        ret = translate_bus_error_to_exit_status(ret, &error);
 
1975
        } else {
 
1976
                STRV_FOREACH(name, args+1) {
 
1977
                        r = start_unit_one(bus, method, *name, mode, &error, s);
 
1978
                        if (r < 0) {
 
1979
                                ret = translate_bus_error_to_exit_status(r, &error);
 
1980
                                dbus_error_free(&error);
 
1981
                        }
 
1982
                }
 
1983
        }
 
1984
 
 
1985
        if (!arg_no_block) {
 
1986
                r = wait_for_jobs(bus, s);
 
1987
                if (r < 0)
 
1988
                        return r;
 
1989
 
 
1990
                /* When stopping units, warn if they can still be triggered by
 
1991
                 * another active unit (socket, path, timer) */
 
1992
                if (!arg_quiet && streq(method, "StopUnit")) {
 
1993
                        if (one_name)
 
1994
                                check_triggering_units(bus, one_name);
 
1995
                        else
 
1996
                                STRV_FOREACH(name, args+1)
 
1997
                                        check_triggering_units(bus, *name);
 
1998
                }
 
1999
        }
 
2000
 
 
2001
        return ret;
 
2002
}
 
2003
 
 
2004
/* Ask systemd-logind, which might grant access to unprivileged users
 
2005
 * through PolicyKit */
 
2006
static int reboot_with_logind(DBusConnection *bus, enum action a) {
 
2007
#ifdef HAVE_LOGIND
 
2008
        const char *method;
 
2009
        dbus_bool_t interactive = true;
 
2010
 
 
2011
        if (!bus)
 
2012
                return -EIO;
 
2013
 
 
2014
        polkit_agent_open_if_enabled();
 
2015
 
 
2016
        switch (a) {
 
2017
 
 
2018
        case ACTION_REBOOT:
 
2019
                method = "Reboot";
 
2020
                break;
 
2021
 
 
2022
        case ACTION_POWEROFF:
 
2023
                method = "PowerOff";
 
2024
                break;
 
2025
 
 
2026
        case ACTION_SUSPEND:
 
2027
                method = "Suspend";
 
2028
                break;
 
2029
 
 
2030
        case ACTION_HIBERNATE:
 
2031
                method = "Hibernate";
 
2032
                break;
 
2033
 
 
2034
        case ACTION_HYBRID_SLEEP:
 
2035
                method = "HybridSleep";
 
2036
                break;
 
2037
 
 
2038
        default:
 
2039
                return -EINVAL;
 
2040
        }
 
2041
 
 
2042
        return bus_method_call_with_reply(
 
2043
                        bus,
 
2044
                        "org.freedesktop.login1",
 
2045
                        "/org/freedesktop/login1",
 
2046
                        "org.freedesktop.login1.Manager",
 
2047
                        method,
 
2048
                        NULL,
 
2049
                        NULL,
 
2050
                        DBUS_TYPE_BOOLEAN, &interactive,
 
2051
                        DBUS_TYPE_INVALID);
 
2052
#else
 
2053
        return -ENOSYS;
 
2054
#endif
 
2055
}
 
2056
 
 
2057
static int check_inhibitors(DBusConnection *bus, enum action a) {
 
2058
#ifdef HAVE_LOGIND
 
2059
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
2060
        DBusMessageIter iter, sub, sub2;
 
2061
        int r;
 
2062
        unsigned c = 0;
 
2063
        _cleanup_strv_free_ char **sessions = NULL;
 
2064
        char **s;
 
2065
 
 
2066
        if (!bus)
 
2067
                return 0;
 
2068
 
 
2069
        if (arg_ignore_inhibitors || arg_force > 0)
 
2070
                return 0;
 
2071
 
 
2072
        if (arg_when > 0)
 
2073
                return 0;
 
2074
 
 
2075
        if (geteuid() == 0)
 
2076
                return 0;
 
2077
 
 
2078
        if (!on_tty())
 
2079
                return 0;
 
2080
 
 
2081
        r = bus_method_call_with_reply(
 
2082
                        bus,
 
2083
                        "org.freedesktop.login1",
 
2084
                        "/org/freedesktop/login1",
 
2085
                        "org.freedesktop.login1.Manager",
 
2086
                        "ListInhibitors",
 
2087
                        &reply,
 
2088
                        NULL,
 
2089
                        DBUS_TYPE_INVALID);
 
2090
        if (r < 0)
 
2091
                /* If logind is not around, then there are no inhibitors... */
 
2092
                return 0;
 
2093
 
 
2094
        if (!dbus_message_iter_init(reply, &iter) ||
 
2095
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
2096
            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
 
2097
                log_error("Failed to parse reply.");
 
2098
                return -EIO;
 
2099
        }
 
2100
 
 
2101
        dbus_message_iter_recurse(&iter, &sub);
 
2102
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
2103
                const char *what, *who, *why, *mode;
 
2104
                uint32_t uid, pid;
 
2105
                _cleanup_strv_free_ char **sv = NULL;
 
2106
                _cleanup_free_ char *comm = NULL, *user = NULL;
 
2107
 
 
2108
                if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
 
2109
                        log_error("Failed to parse reply.");
 
2110
                        return -EIO;
 
2111
                }
 
2112
 
 
2113
                dbus_message_iter_recurse(&sub, &sub2);
 
2114
 
 
2115
                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
 
2116
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
 
2117
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
 
2118
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
 
2119
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
 
2120
                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
 
2121
                        log_error("Failed to parse reply.");
 
2122
                        return -EIO;
 
2123
                }
 
2124
 
 
2125
                if (!streq(mode, "block"))
 
2126
                        goto next;
 
2127
 
 
2128
                sv = strv_split(what, ":");
 
2129
                if (!sv)
 
2130
                        return log_oom();
 
2131
 
 
2132
                if (!strv_contains(sv,
 
2133
                                  a == ACTION_HALT ||
 
2134
                                  a == ACTION_POWEROFF ||
 
2135
                                  a == ACTION_REBOOT ||
 
2136
                                  a == ACTION_KEXEC ? "shutdown" : "sleep"))
 
2137
                        goto next;
 
2138
 
 
2139
                get_process_comm(pid, &comm);
 
2140
                user = uid_to_name(uid);
 
2141
                log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
 
2142
                            who, (unsigned long) pid, strna(comm), strna(user), why);
 
2143
                c++;
 
2144
 
 
2145
        next:
 
2146
                dbus_message_iter_next(&sub);
 
2147
        }
 
2148
 
 
2149
        dbus_message_iter_recurse(&iter, &sub);
 
2150
 
 
2151
        /* Check for current sessions */
 
2152
        sd_get_sessions(&sessions);
 
2153
        STRV_FOREACH(s, sessions) {
 
2154
                uid_t uid;
 
2155
                _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
 
2156
 
 
2157
                if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
 
2158
                        continue;
 
2159
 
 
2160
                if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
 
2161
                        continue;
 
2162
 
 
2163
                if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
 
2164
                        continue;
 
2165
 
 
2166
                sd_session_get_tty(*s, &tty);
 
2167
                sd_session_get_seat(*s, &seat);
 
2168
                sd_session_get_service(*s, &service);
 
2169
                user = uid_to_name(uid);
 
2170
 
 
2171
                log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
 
2172
                c++;
 
2173
        }
 
2174
 
 
2175
        if (c <= 0)
 
2176
                return 0;
 
2177
 
 
2178
        log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
 
2179
                  action_table[a].verb);
 
2180
 
 
2181
        return -EPERM;
 
2182
#else
 
2183
        return 0;
 
2184
#endif
 
2185
}
 
2186
 
 
2187
static int start_special(DBusConnection *bus, char **args) {
 
2188
        enum action a;
 
2189
        int r;
 
2190
 
 
2191
        assert(args);
 
2192
 
 
2193
        a = verb_to_action(args[0]);
 
2194
 
 
2195
        r = check_inhibitors(bus, a);
 
2196
        if (r < 0)
 
2197
                return r;
 
2198
 
 
2199
        if (arg_force >= 2 && geteuid() != 0) {
 
2200
                log_error("Must be root.");
 
2201
                return -EPERM;
 
2202
        }
 
2203
 
 
2204
        if (arg_force >= 2 &&
 
2205
            (a == ACTION_HALT ||
 
2206
             a == ACTION_POWEROFF ||
 
2207
             a == ACTION_REBOOT))
 
2208
                halt_now(a);
 
2209
 
 
2210
        if (arg_force >= 1 &&
 
2211
            (a == ACTION_HALT ||
 
2212
             a == ACTION_POWEROFF ||
 
2213
             a == ACTION_REBOOT ||
 
2214
             a == ACTION_KEXEC ||
 
2215
             a == ACTION_EXIT))
 
2216
                return daemon_reload(bus, args);
 
2217
 
 
2218
        /* first try logind, to allow authentication with polkit */
 
2219
        if (geteuid() != 0 &&
 
2220
            (a == ACTION_POWEROFF ||
 
2221
             a == ACTION_REBOOT ||
 
2222
             a == ACTION_SUSPEND ||
 
2223
             a == ACTION_HIBERNATE ||
 
2224
             a == ACTION_HYBRID_SLEEP)) {
 
2225
                r = reboot_with_logind(bus, a);
 
2226
                if (r >= 0)
 
2227
                        return r;
 
2228
        }
 
2229
 
 
2230
        r = start_unit(bus, args);
 
2231
        if (r == EXIT_SUCCESS)
 
2232
                warn_wall(a);
 
2233
 
 
2234
        return r;
 
2235
}
 
2236
 
 
2237
static int check_unit_active(DBusConnection *bus, char **args) {
 
2238
        const char * const check_states[] = {
 
2239
                "active",
 
2240
                "reloading",
 
2241
                NULL
 
2242
        };
 
2243
 
 
2244
        char **name;
 
2245
        int r = 3; /* According to LSB: "program is not running" */
 
2246
 
 
2247
        assert(bus);
 
2248
        assert(args);
 
2249
 
 
2250
        STRV_FOREACH(name, args+1) {
 
2251
                int state;
 
2252
 
 
2253
                state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
 
2254
                if (state < 0)
 
2255
                        return state;
 
2256
                if (state > 0)
 
2257
                        r = 0;
 
2258
        }
 
2259
 
 
2260
        return r;
 
2261
}
 
2262
 
 
2263
static int check_unit_failed(DBusConnection *bus, char **args) {
 
2264
        const char * const check_states[] = {
 
2265
                "failed",
 
2266
                NULL
 
2267
        };
 
2268
 
 
2269
        char **name;
 
2270
        int r = 1;
 
2271
 
 
2272
        assert(bus);
 
2273
        assert(args);
 
2274
 
 
2275
        STRV_FOREACH(name, args+1) {
 
2276
                int state;
 
2277
 
 
2278
                state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
 
2279
                if (state < 0)
 
2280
                        return state;
 
2281
                if (state > 0)
 
2282
                        r = 0;
 
2283
        }
 
2284
 
 
2285
        return r;
 
2286
}
 
2287
 
 
2288
static int kill_unit(DBusConnection *bus, char **args) {
 
2289
        char **name;
 
2290
        int r = 0;
 
2291
 
 
2292
        assert(bus);
 
2293
        assert(args);
 
2294
 
 
2295
        if (!arg_kill_who)
 
2296
                arg_kill_who = "all";
 
2297
 
 
2298
        STRV_FOREACH(name, args+1) {
 
2299
                _cleanup_free_ char *n = NULL;
 
2300
 
 
2301
                n = unit_name_mangle(*name);
 
2302
                if (!n)
 
2303
                        return log_oom();
 
2304
 
 
2305
                r = bus_method_call_with_reply(
 
2306
                                bus,
 
2307
                                "org.freedesktop.systemd1",
 
2308
                                "/org/freedesktop/systemd1",
 
2309
                                "org.freedesktop.systemd1.Manager",
 
2310
                                "KillUnit",
 
2311
                                NULL,
 
2312
                                NULL,
 
2313
                                DBUS_TYPE_STRING, &n,
 
2314
                                DBUS_TYPE_STRING, &arg_kill_who,
 
2315
                                DBUS_TYPE_INT32, &arg_signal,
 
2316
                                DBUS_TYPE_INVALID);
 
2317
                if (r < 0)
 
2318
                        return r;
 
2319
        }
 
2320
        return 0;
 
2321
}
 
2322
 
 
2323
static int set_cgroup(DBusConnection *bus, char **args) {
 
2324
        _cleanup_free_ char *n = NULL;
 
2325
        const char *method, *runtime;
 
2326
        char **argument;
 
2327
        int r;
 
2328
 
 
2329
        assert(bus);
 
2330
        assert(args);
 
2331
 
 
2332
        method =
 
2333
                streq(args[0], "set-cgroup")   ? "SetUnitControlGroup" :
 
2334
                streq(args[0], "unset-cgroup") ? "UnsetUnitControlGroup"
 
2335
                                               : "UnsetUnitControlGroupAttribute";
 
2336
 
 
2337
        runtime = arg_runtime ? "runtime" : "persistent";
 
2338
 
 
2339
        n = unit_name_mangle(args[1]);
 
2340
        if (!n)
 
2341
                return log_oom();
 
2342
 
 
2343
        STRV_FOREACH(argument, args + 2) {
 
2344
 
 
2345
                r = bus_method_call_with_reply(
 
2346
                                bus,
 
2347
                                "org.freedesktop.systemd1",
 
2348
                                "/org/freedesktop/systemd1",
 
2349
                                "org.freedesktop.systemd1.Manager",
 
2350
                                method,
 
2351
                                NULL,
 
2352
                                NULL,
 
2353
                                DBUS_TYPE_STRING, &n,
 
2354
                                DBUS_TYPE_STRING, argument,
 
2355
                                DBUS_TYPE_STRING, &runtime,
 
2356
                                DBUS_TYPE_INVALID);
 
2357
                if (r < 0)
 
2358
                        return r;
 
2359
        }
 
2360
 
 
2361
        return 0;
 
2362
}
 
2363
 
 
2364
static int set_cgroup_attr(DBusConnection *bus, char **args) {
 
2365
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
 
2366
        DBusError error;
 
2367
        DBusMessageIter iter;
 
2368
        _cleanup_free_ char *n = NULL;
 
2369
        const char *runtime;
 
2370
        int r;
 
2371
 
 
2372
        assert(bus);
 
2373
        assert(args);
 
2374
 
 
2375
        dbus_error_init(&error);
 
2376
 
 
2377
        runtime = arg_runtime ? "runtime" : "persistent";
 
2378
 
 
2379
        n = unit_name_mangle(args[1]);
 
2380
        if (!n)
 
2381
                return log_oom();
 
2382
 
 
2383
        m = dbus_message_new_method_call(
 
2384
                        "org.freedesktop.systemd1",
 
2385
                        "/org/freedesktop/systemd1",
 
2386
                        "org.freedesktop.systemd1.Manager",
 
2387
                        "SetUnitControlGroupAttribute");
 
2388
        if (!m)
 
2389
                return log_oom();
 
2390
 
 
2391
        dbus_message_iter_init_append(m, &iter);
 
2392
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &n) ||
 
2393
            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[2]))
 
2394
                return log_oom();
 
2395
 
 
2396
        r = bus_append_strv_iter(&iter, args + 3);
 
2397
        if (r < 0)
 
2398
                return log_oom();
 
2399
 
 
2400
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &runtime))
 
2401
                return log_oom();
 
2402
 
 
2403
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
 
2404
        if (!reply) {
 
2405
                log_error("Failed to issue method call: %s", bus_error_message(&error));
 
2406
                dbus_error_free(&error);
 
2407
                return -EIO;
 
2408
        }
 
2409
 
 
2410
        return 0;
 
2411
}
 
2412
 
 
2413
static int get_cgroup_attr(DBusConnection *bus, char **args) {
 
2414
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
2415
        _cleanup_free_ char *n = NULL;
 
2416
        char **argument;
 
2417
        int r;
 
2418
 
 
2419
        assert(bus);
 
2420
        assert(args);
 
2421
 
 
2422
        n = unit_name_mangle(args[1]);
 
2423
        if (!n)
 
2424
                return log_oom();
 
2425
 
 
2426
        STRV_FOREACH(argument, args + 2) {
 
2427
                _cleanup_strv_free_ char **list = NULL;
 
2428
                DBusMessageIter iter;
 
2429
                char **a;
 
2430
 
 
2431
                r = bus_method_call_with_reply(
 
2432
                                bus,
 
2433
                                "org.freedesktop.systemd1",
 
2434
                                "/org/freedesktop/systemd1",
 
2435
                                "org.freedesktop.systemd1.Manager",
 
2436
                                "GetUnitControlGroupAttribute",
 
2437
                                &reply,
 
2438
                                NULL,
 
2439
                                DBUS_TYPE_STRING, &n,
 
2440
                                DBUS_TYPE_STRING, argument,
 
2441
                                DBUS_TYPE_INVALID);
 
2442
                if (r < 0)
 
2443
                        return r;
 
2444
 
 
2445
                if (!dbus_message_iter_init(reply, &iter)) {
 
2446
                        log_error("Failed to initialize iterator.");
 
2447
                        return -EIO;
 
2448
                }
 
2449
 
 
2450
                r = bus_parse_strv_iter(&iter, &list);
 
2451
                if (r < 0) {
 
2452
                        log_error("Failed to parse value list.");
 
2453
                        return r;
 
2454
                }
 
2455
 
 
2456
                STRV_FOREACH(a, list) {
 
2457
                        if (endswith(*a, "\n"))
 
2458
                                fputs(*a, stdout);
 
2459
                        else
 
2460
                                puts(*a);
 
2461
                }
 
2462
        }
 
2463
 
 
2464
        return 0;
 
2465
}
 
2466
 
 
2467
typedef struct ExecStatusInfo {
 
2468
        char *name;
 
2469
 
 
2470
        char *path;
 
2471
        char **argv;
 
2472
 
 
2473
        bool ignore;
 
2474
 
 
2475
        usec_t start_timestamp;
 
2476
        usec_t exit_timestamp;
 
2477
        pid_t pid;
 
2478
        int code;
 
2479
        int status;
 
2480
 
 
2481
        LIST_FIELDS(struct ExecStatusInfo, exec);
 
2482
} ExecStatusInfo;
 
2483
 
 
2484
static void exec_status_info_free(ExecStatusInfo *i) {
 
2485
        assert(i);
 
2486
 
 
2487
        free(i->name);
 
2488
        free(i->path);
 
2489
        strv_free(i->argv);
 
2490
        free(i);
 
2491
}
 
2492
 
 
2493
static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
 
2494
        uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
 
2495
        DBusMessageIter sub2, sub3;
 
2496
        const char*path;
 
2497
        unsigned n;
 
2498
        uint32_t pid;
 
2499
        int32_t code, status;
 
2500
        dbus_bool_t ignore;
 
2501
 
 
2502
        assert(i);
 
2503
        assert(i);
 
2504
 
 
2505
        if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
 
2506
                return -EIO;
 
2507
 
 
2508
        dbus_message_iter_recurse(sub, &sub2);
 
2509
 
 
2510
        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
 
2511
                return -EIO;
 
2512
 
 
2513
        i->path = strdup(path);
 
2514
        if (!i->path)
 
2515
                return -ENOMEM;
 
2516
 
 
2517
        if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
 
2518
            dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
 
2519
                return -EIO;
 
2520
 
 
2521
        n = 0;
 
2522
        dbus_message_iter_recurse(&sub2, &sub3);
 
2523
        while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
 
2524
                assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
 
2525
                dbus_message_iter_next(&sub3);
 
2526
                n++;
 
2527
        }
 
2528
 
 
2529
        i->argv = new0(char*, n+1);
 
2530
        if (!i->argv)
 
2531
                return -ENOMEM;
 
2532
 
 
2533
        n = 0;
 
2534
        dbus_message_iter_recurse(&sub2, &sub3);
 
2535
        while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
 
2536
                const char *s;
 
2537
 
 
2538
                assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
 
2539
                dbus_message_iter_get_basic(&sub3, &s);
 
2540
                dbus_message_iter_next(&sub3);
 
2541
 
 
2542
                i->argv[n] = strdup(s);
 
2543
                if (!i->argv[n])
 
2544
                        return -ENOMEM;
 
2545
 
 
2546
                n++;
 
2547
        }
 
2548
 
 
2549
        if (!dbus_message_iter_next(&sub2) ||
 
2550
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
 
2551
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
 
2552
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
 
2553
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
 
2554
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
 
2555
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
 
2556
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
 
2557
            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
 
2558
                return -EIO;
 
2559
 
 
2560
        i->ignore = ignore;
 
2561
        i->start_timestamp = (usec_t) start_timestamp;
 
2562
        i->exit_timestamp = (usec_t) exit_timestamp;
 
2563
        i->pid = (pid_t) pid;
 
2564
        i->code = code;
 
2565
        i->status = status;
 
2566
 
 
2567
        return 0;
 
2568
}
 
2569
 
 
2570
typedef struct UnitStatusInfo {
 
2571
        const char *id;
 
2572
        const char *load_state;
 
2573
        const char *active_state;
 
2574
        const char *sub_state;
 
2575
        const char *unit_file_state;
 
2576
 
 
2577
        const char *description;
 
2578
        const char *following;
 
2579
 
 
2580
        char **documentation;
 
2581
 
 
2582
        const char *fragment_path;
 
2583
        const char *source_path;
 
2584
        const char *default_control_group;
 
2585
 
 
2586
        char **dropin_paths;
 
2587
 
 
2588
        const char *load_error;
 
2589
        const char *result;
 
2590
 
 
2591
        usec_t inactive_exit_timestamp;
 
2592
        usec_t inactive_exit_timestamp_monotonic;
 
2593
        usec_t active_enter_timestamp;
 
2594
        usec_t active_exit_timestamp;
 
2595
        usec_t inactive_enter_timestamp;
 
2596
 
 
2597
        bool need_daemon_reload;
 
2598
 
 
2599
        /* Service */
 
2600
        pid_t main_pid;
 
2601
        pid_t control_pid;
 
2602
        const char *status_text;
 
2603
        bool running:1;
 
2604
 
 
2605
        usec_t start_timestamp;
 
2606
        usec_t exit_timestamp;
 
2607
 
 
2608
        int exit_code, exit_status;
 
2609
 
 
2610
        usec_t condition_timestamp;
 
2611
        bool condition_result;
 
2612
 
 
2613
        /* Socket */
 
2614
        unsigned n_accepted;
 
2615
        unsigned n_connections;
 
2616
        bool accept;
 
2617
 
 
2618
        /* Pairs of type, path */
 
2619
        char **listen;
 
2620
 
 
2621
        /* Device */
 
2622
        const char *sysfs_path;
 
2623
 
 
2624
        /* Mount, Automount */
 
2625
        const char *where;
 
2626
 
 
2627
        /* Swap */
 
2628
        const char *what;
 
2629
 
 
2630
        LIST_HEAD(ExecStatusInfo, exec);
 
2631
} UnitStatusInfo;
 
2632
 
 
2633
static void print_status_info(UnitStatusInfo *i) {
 
2634
        ExecStatusInfo *p;
 
2635
        const char *on, *off, *ss;
 
2636
        usec_t timestamp;
 
2637
        char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
 
2638
        char since2[FORMAT_TIMESTAMP_MAX], *s2;
 
2639
        const char *path;
 
2640
        int flags =
 
2641
                arg_all * OUTPUT_SHOW_ALL |
 
2642
                (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
 
2643
                on_tty() * OUTPUT_COLOR |
 
2644
                !arg_quiet * OUTPUT_WARN_CUTOFF |
 
2645
                arg_full * OUTPUT_FULL_WIDTH;
 
2646
        int maxlen = 8; /* a value that'll suffice most of the time */
 
2647
        char **t, **t2;
 
2648
 
 
2649
        assert(i);
 
2650
 
 
2651
        STRV_FOREACH_PAIR(t, t2, i->listen)
 
2652
                maxlen = MAX(maxlen, (int)(sizeof("Listen") - 1 + strlen(*t)));
 
2653
        if (i->accept)
 
2654
                maxlen = MAX(maxlen, (int)sizeof("Accept") - 1);
 
2655
        if (i->main_pid > 0)
 
2656
                maxlen = MAX(maxlen, (int)sizeof("Main PID") - 1);
 
2657
        else if (i->control_pid > 0)
 
2658
                maxlen = MAX(maxlen, (int)sizeof("Control") - 1);
 
2659
 
 
2660
        /* This shows pretty information about a unit. See
 
2661
         * print_property() for a low-level property printer */
 
2662
 
 
2663
        printf("%s", strna(i->id));
 
2664
 
 
2665
        if (i->description && !streq_ptr(i->id, i->description))
 
2666
                printf(" - %s", i->description);
 
2667
 
 
2668
        printf("\n");
 
2669
 
 
2670
        if (i->following)
 
2671
                printf(" %*s: unit currently follows state of %s\n", maxlen, "Follow", i->following);
 
2672
 
 
2673
        if (streq_ptr(i->load_state, "error")) {
 
2674
                on = ansi_highlight_red(true);
 
2675
                off = ansi_highlight_red(false);
 
2676
        } else
 
2677
                on = off = "";
 
2678
 
 
2679
        path = i->source_path ? i->source_path : i->fragment_path;
 
2680
 
 
2681
        if (i->load_error)
 
2682
                printf(" %*s: %s%s%s (Reason: %s)\n",
 
2683
                       maxlen, "Loaded", on, strna(i->load_state), off, i->load_error);
 
2684
        else if (path && i->unit_file_state)
 
2685
                printf(" %*s: %s%s%s (%s; %s)\n",
 
2686
                       maxlen, "Loaded", on, strna(i->load_state), off, path, i->unit_file_state);
 
2687
        else if (path)
 
2688
                printf(" %*s: %s%s%s (%s)\n",
 
2689
                       maxlen, "Loaded", on, strna(i->load_state), off, path);
 
2690
        else
 
2691
                printf(" %*s: %s%s%s\n",
 
2692
                       maxlen, "Loaded", on, strna(i->load_state), off);
 
2693
 
 
2694
        if (!strv_isempty(i->dropin_paths)) {
 
2695
                char ** dropin;
 
2696
                char * dir = NULL;
 
2697
                bool last = false;
 
2698
 
 
2699
                STRV_FOREACH(dropin, i->dropin_paths) {
 
2700
                        if (! dir || last) {
 
2701
                                printf("  %*s ", maxlen, dir ? "" : "Drop-In:");
 
2702
 
 
2703
                                free(dir);
 
2704
 
 
2705
                                if (path_get_parent(*dropin, &dir) < 0) {
 
2706
                                        log_oom();
 
2707
                                        return;
 
2708
                                }
 
2709
 
 
2710
                                printf("%s\n %*s  %s", dir, maxlen, "",
 
2711
                                       draw_special_char(DRAW_TREE_RIGHT));
 
2712
                        }
 
2713
 
 
2714
                        last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
 
2715
 
 
2716
                        printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
 
2717
                }
 
2718
 
 
2719
                free(dir);
 
2720
        }
 
2721
 
 
2722
        ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
 
2723
 
 
2724
        if (streq_ptr(i->active_state, "failed")) {
 
2725
                on = ansi_highlight_red(true);
 
2726
                off = ansi_highlight_red(false);
 
2727
        } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
 
2728
                on = ansi_highlight_green(true);
 
2729
                off = ansi_highlight_green(false);
 
2730
        } else
 
2731
                on = off = "";
 
2732
 
 
2733
        if (ss)
 
2734
                printf(" %*s: %s%s (%s)%s",
 
2735
                       maxlen, "Active",  on, strna(i->active_state), ss, off);
 
2736
        else
 
2737
                printf(" %*s: %s%s%s",
 
2738
                       maxlen, "Active", on, strna(i->active_state), off);
 
2739
 
 
2740
        if (!isempty(i->result) && !streq(i->result, "success"))
 
2741
                printf(" (Result: %s)", i->result);
 
2742
 
 
2743
        timestamp = (streq_ptr(i->active_state, "active")      ||
 
2744
                     streq_ptr(i->active_state, "reloading"))   ? i->active_enter_timestamp :
 
2745
                    (streq_ptr(i->active_state, "inactive")    ||
 
2746
                     streq_ptr(i->active_state, "failed"))      ? i->inactive_enter_timestamp :
 
2747
                    streq_ptr(i->active_state, "activating")    ? i->inactive_exit_timestamp :
 
2748
                                                                  i->active_exit_timestamp;
 
2749
 
 
2750
        s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
 
2751
        s2 = format_timestamp(since2, sizeof(since2), timestamp);
 
2752
 
 
2753
        if (s1)
 
2754
                printf(" since %s; %s\n", s2, s1);
 
2755
        else if (s2)
 
2756
                printf(" since %s\n", s2);
 
2757
        else
 
2758
                printf("\n");
 
2759
 
 
2760
        if (!i->condition_result && i->condition_timestamp > 0) {
 
2761
                s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
 
2762
                s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
 
2763
 
 
2764
                if (s1)
 
2765
                        printf(" %*s start condition failed at %s; %s\n", maxlen, "", s2, s1);
 
2766
                else if (s2)
 
2767
                        printf(" %*s start condition failed at %s\n", maxlen, "", s2);
 
2768
        }
 
2769
 
 
2770
        if (i->sysfs_path)
 
2771
                printf(" %*s: %s\n", maxlen, "Device", i->sysfs_path);
 
2772
        if (i->where)
 
2773
                printf(" %*s: %s\n", maxlen, "Where", i->where);
 
2774
        if (i->what)
 
2775
                printf(" %*s: %s\n", maxlen, "What", i->what);
 
2776
 
 
2777
        STRV_FOREACH(t, i->documentation)
 
2778
                printf(" %*s %s\n", maxlen+1, t == i->documentation ? "Docs:" : "", *t);
 
2779
 
 
2780
        STRV_FOREACH_PAIR(t, t2, i->listen)
 
2781
                printf(" %*s %s (%s)\n", maxlen+1, t == i->listen ? "Listen:" : "", *t2, *t);
 
2782
 
 
2783
        if (i->accept)
 
2784
                printf(" %*s: %u; Connected: %u\n", maxlen, "Accepted", i->n_accepted, i->n_connections);
 
2785
 
 
2786
        LIST_FOREACH(exec, p, i->exec) {
 
2787
                _cleanup_free_ char *argv = NULL;
 
2788
                bool good;
 
2789
 
 
2790
                /* Only show exited processes here */
 
2791
                if (p->code == 0)
 
2792
                        continue;
 
2793
 
 
2794
                argv = strv_join(p->argv, " ");
 
2795
                printf(" %*s: %u %s=%s ", maxlen, "Process", p->pid, p->name, strna(argv));
 
2796
 
 
2797
                good = is_clean_exit_lsb(p->code, p->status, NULL);
 
2798
                if (!good) {
 
2799
                        on = ansi_highlight_red(true);
 
2800
                        off = ansi_highlight_red(false);
 
2801
                } else
 
2802
                        on = off = "";
 
2803
 
 
2804
                printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
 
2805
 
 
2806
                if (p->code == CLD_EXITED) {
 
2807
                        const char *c;
 
2808
 
 
2809
                        printf("status=%i", p->status);
 
2810
 
 
2811
                        c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
 
2812
                        if (c)
 
2813
                                printf("/%s", c);
 
2814
 
 
2815
                } else
 
2816
                        printf("signal=%s", signal_to_string(p->status));
 
2817
 
 
2818
                printf(")%s\n", off);
 
2819
 
 
2820
                if (i->main_pid == p->pid &&
 
2821
                    i->start_timestamp == p->start_timestamp &&
 
2822
                    i->exit_timestamp == p->start_timestamp)
 
2823
                        /* Let's not show this twice */
 
2824
                        i->main_pid = 0;
 
2825
 
 
2826
                if (p->pid == i->control_pid)
 
2827
                        i->control_pid = 0;
 
2828
        }
 
2829
 
 
2830
        if (i->main_pid > 0 || i->control_pid > 0) {
 
2831
                if (i->main_pid > 0) {
 
2832
                        printf(" %*s: %u", maxlen, "Main PID", (unsigned) i->main_pid);
 
2833
 
 
2834
                        if (i->running) {
 
2835
                                _cleanup_free_ char *comm = NULL;
 
2836
                                get_process_comm(i->main_pid, &comm);
 
2837
                                if (comm)
 
2838
                                        printf(" (%s)", comm);
 
2839
                        } else if (i->exit_code > 0) {
 
2840
                                printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
 
2841
 
 
2842
                                if (i->exit_code == CLD_EXITED) {
 
2843
                                        const char *c;
 
2844
 
 
2845
                                        printf("status=%i", i->exit_status);
 
2846
 
 
2847
                                        c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
 
2848
                                        if (c)
 
2849
                                                printf("/%s", c);
 
2850
 
 
2851
                                } else
 
2852
                                        printf("signal=%s", signal_to_string(i->exit_status));
 
2853
                                printf(")");
 
2854
                        }
 
2855
 
 
2856
                        if (i->control_pid > 0)
 
2857
                                printf(";");
 
2858
                }
 
2859
 
 
2860
                if (i->control_pid > 0) {
 
2861
                        _cleanup_free_ char *c = NULL;
 
2862
 
 
2863
                        printf(" %*s: %u", i->main_pid ? 0 : maxlen, "Control", (unsigned) i->control_pid);
 
2864
 
 
2865
                        get_process_comm(i->control_pid, &c);
 
2866
                        if (c)
 
2867
                                printf(" (%s)", c);
 
2868
                }
 
2869
 
 
2870
                printf("\n");
 
2871
        }
 
2872
 
 
2873
        if (i->status_text)
 
2874
                printf(" %*s: \"%s\"\n", maxlen, "Status", i->status_text);
 
2875
 
 
2876
        if (i->default_control_group &&
 
2877
            (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_by_spec(i->default_control_group, false) == 0)) {
 
2878
                unsigned c;
 
2879
 
 
2880
                printf(" %*s: %s\n", maxlen, "CGroup", i->default_control_group);
 
2881
 
 
2882
                if (arg_transport != TRANSPORT_SSH) {
 
2883
                        unsigned k = 0;
 
2884
                        pid_t extra[2];
 
2885
                        char prefix[maxlen + 4];
 
2886
                        memset(prefix, ' ', sizeof(prefix) - 1);
 
2887
                        prefix[sizeof(prefix) - 1] = '\0';
 
2888
 
 
2889
                        c = columns();
 
2890
                        if (c > sizeof(prefix) - 1)
 
2891
                                c -= sizeof(prefix) - 1;
 
2892
                        else
 
2893
                                c = 0;
 
2894
 
 
2895
                        if (i->main_pid > 0)
 
2896
                                extra[k++] = i->main_pid;
 
2897
 
 
2898
                        if (i->control_pid > 0)
 
2899
                                extra[k++] = i->control_pid;
 
2900
 
 
2901
                        show_cgroup_and_extra_by_spec(i->default_control_group, prefix,
 
2902
                                                      c, false, extra, k, flags);
 
2903
                }
 
2904
        }
 
2905
 
 
2906
        if (i->id && arg_transport != TRANSPORT_SSH) {
 
2907
                printf("\n");
 
2908
                show_journal_by_unit(stdout,
 
2909
                                     i->id,
 
2910
                                     arg_output,
 
2911
                                     0,
 
2912
                                     i->inactive_exit_timestamp_monotonic,
 
2913
                                     arg_lines,
 
2914
                                     getuid(),
 
2915
                                     flags,
 
2916
                                     arg_scope == UNIT_FILE_SYSTEM);
 
2917
        }
 
2918
 
 
2919
        if (i->need_daemon_reload)
 
2920
                printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
 
2921
                       ansi_highlight_red(true),
 
2922
                       ansi_highlight_red(false),
 
2923
                       arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
 
2924
}
 
2925
 
 
2926
static void show_unit_help(UnitStatusInfo *i) {
 
2927
        char **p;
 
2928
 
 
2929
        assert(i);
 
2930
 
 
2931
        if (!i->documentation) {
 
2932
                log_info("Documentation for %s not known.", i->id);
 
2933
                return;
 
2934
        }
 
2935
 
 
2936
        STRV_FOREACH(p, i->documentation) {
 
2937
 
 
2938
                if (startswith(*p, "man:")) {
 
2939
                        size_t k;
 
2940
                        char *e = NULL;
 
2941
                        _cleanup_free_ char *page = NULL, *section = NULL;
 
2942
                        const char *args[4] = { "man", NULL, NULL, NULL };
 
2943
                        pid_t pid;
 
2944
 
 
2945
                        k = strlen(*p);
 
2946
 
 
2947
                        if ((*p)[k-1] == ')')
 
2948
                                e = strrchr(*p, '(');
 
2949
 
 
2950
                        if (e) {
 
2951
                                page = strndup((*p) + 4, e - *p - 4);
 
2952
                                section = strndup(e + 1, *p + k - e - 2);
 
2953
                                if (!page || !section) {
 
2954
                                        log_oom();
 
2955
                                        return;
 
2956
                                }
 
2957
 
 
2958
                                args[1] = section;
 
2959
                                args[2] = page;
 
2960
                        } else
 
2961
                                args[1] = *p + 4;
 
2962
 
 
2963
                        pid = fork();
 
2964
                        if (pid < 0) {
 
2965
                                log_error("Failed to fork: %m");
 
2966
                                continue;
 
2967
                        }
 
2968
 
 
2969
                        if (pid == 0) {
 
2970
                                /* Child */
 
2971
                                execvp(args[0], (char**) args);
 
2972
                                log_error("Failed to execute man: %m");
 
2973
                                _exit(EXIT_FAILURE);
 
2974
                        }
 
2975
 
 
2976
                        wait_for_terminate(pid, NULL);
 
2977
                } else
 
2978
                        log_info("Can't show: %s", *p);
 
2979
        }
 
2980
}
 
2981
 
 
2982
static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
 
2983
 
 
2984
        assert(name);
 
2985
        assert(iter);
 
2986
        assert(i);
 
2987
 
 
2988
        switch (dbus_message_iter_get_arg_type(iter)) {
 
2989
 
 
2990
        case DBUS_TYPE_STRING: {
 
2991
                const char *s;
 
2992
 
 
2993
                dbus_message_iter_get_basic(iter, &s);
 
2994
 
 
2995
                if (!isempty(s)) {
 
2996
                        if (streq(name, "Id"))
 
2997
                                i->id = s;
 
2998
                        else if (streq(name, "LoadState"))
 
2999
                                i->load_state = s;
 
3000
                        else if (streq(name, "ActiveState"))
 
3001
                                i->active_state = s;
 
3002
                        else if (streq(name, "SubState"))
 
3003
                                i->sub_state = s;
 
3004
                        else if (streq(name, "Description"))
 
3005
                                i->description = s;
 
3006
                        else if (streq(name, "FragmentPath"))
 
3007
                                i->fragment_path = s;
 
3008
                        else if (streq(name, "SourcePath"))
 
3009
                                i->source_path = s;
 
3010
                        else if (streq(name, "DefaultControlGroup"))
 
3011
                                i->default_control_group = s;
 
3012
                        else if (streq(name, "StatusText"))
 
3013
                                i->status_text = s;
 
3014
                        else if (streq(name, "SysFSPath"))
 
3015
                                i->sysfs_path = s;
 
3016
                        else if (streq(name, "Where"))
 
3017
                                i->where = s;
 
3018
                        else if (streq(name, "What"))
 
3019
                                i->what = s;
 
3020
                        else if (streq(name, "Following"))
 
3021
                                i->following = s;
 
3022
                        else if (streq(name, "UnitFileState"))
 
3023
                                i->unit_file_state = s;
 
3024
                        else if (streq(name, "Result"))
 
3025
                                i->result = s;
 
3026
                }
 
3027
 
 
3028
                break;
 
3029
        }
 
3030
 
 
3031
        case DBUS_TYPE_BOOLEAN: {
 
3032
                dbus_bool_t b;
 
3033
 
 
3034
                dbus_message_iter_get_basic(iter, &b);
 
3035
 
 
3036
                if (streq(name, "Accept"))
 
3037
                        i->accept = b;
 
3038
                else if (streq(name, "NeedDaemonReload"))
 
3039
                        i->need_daemon_reload = b;
 
3040
                else if (streq(name, "ConditionResult"))
 
3041
                        i->condition_result = b;
 
3042
 
 
3043
                break;
 
3044
        }
 
3045
 
 
3046
        case DBUS_TYPE_UINT32: {
 
3047
                uint32_t u;
 
3048
 
 
3049
                dbus_message_iter_get_basic(iter, &u);
 
3050
 
 
3051
                if (streq(name, "MainPID")) {
 
3052
                        if (u > 0) {
 
3053
                                i->main_pid = (pid_t) u;
 
3054
                                i->running = true;
 
3055
                        }
 
3056
                } else if (streq(name, "ControlPID"))
 
3057
                        i->control_pid = (pid_t) u;
 
3058
                else if (streq(name, "ExecMainPID")) {
 
3059
                        if (u > 0)
 
3060
                                i->main_pid = (pid_t) u;
 
3061
                } else if (streq(name, "NAccepted"))
 
3062
                        i->n_accepted = u;
 
3063
                else if (streq(name, "NConnections"))
 
3064
                        i->n_connections = u;
 
3065
 
 
3066
                break;
 
3067
        }
 
3068
 
 
3069
        case DBUS_TYPE_INT32: {
 
3070
                int32_t j;
 
3071
 
 
3072
                dbus_message_iter_get_basic(iter, &j);
 
3073
 
 
3074
                if (streq(name, "ExecMainCode"))
 
3075
                        i->exit_code = (int) j;
 
3076
                else if (streq(name, "ExecMainStatus"))
 
3077
                        i->exit_status = (int) j;
 
3078
 
 
3079
                break;
 
3080
        }
 
3081
 
 
3082
        case DBUS_TYPE_UINT64: {
 
3083
                uint64_t u;
 
3084
 
 
3085
                dbus_message_iter_get_basic(iter, &u);
 
3086
 
 
3087
                if (streq(name, "ExecMainStartTimestamp"))
 
3088
                        i->start_timestamp = (usec_t) u;
 
3089
                else if (streq(name, "ExecMainExitTimestamp"))
 
3090
                        i->exit_timestamp = (usec_t) u;
 
3091
                else if (streq(name, "ActiveEnterTimestamp"))
 
3092
                        i->active_enter_timestamp = (usec_t) u;
 
3093
                else if (streq(name, "InactiveEnterTimestamp"))
 
3094
                        i->inactive_enter_timestamp = (usec_t) u;
 
3095
                else if (streq(name, "InactiveExitTimestamp"))
 
3096
                        i->inactive_exit_timestamp = (usec_t) u;
 
3097
                else if (streq(name, "InactiveExitTimestampMonotonic"))
 
3098
                        i->inactive_exit_timestamp_monotonic = (usec_t) u;
 
3099
                else if (streq(name, "ActiveExitTimestamp"))
 
3100
                        i->active_exit_timestamp = (usec_t) u;
 
3101
                else if (streq(name, "ConditionTimestamp"))
 
3102
                        i->condition_timestamp = (usec_t) u;
 
3103
 
 
3104
                break;
 
3105
        }
 
3106
 
 
3107
        case DBUS_TYPE_ARRAY: {
 
3108
 
 
3109
                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
 
3110
                    startswith(name, "Exec")) {
 
3111
                        DBusMessageIter sub;
 
3112
 
 
3113
                        dbus_message_iter_recurse(iter, &sub);
 
3114
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3115
                                ExecStatusInfo *info;
 
3116
                                int r;
 
3117
 
 
3118
                                if (!(info = new0(ExecStatusInfo, 1)))
 
3119
                                        return -ENOMEM;
 
3120
 
 
3121
                                if (!(info->name = strdup(name))) {
 
3122
                                        free(info);
 
3123
                                        return -ENOMEM;
 
3124
                                }
 
3125
 
 
3126
                                if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
 
3127
                                        free(info);
 
3128
                                        return r;
 
3129
                                }
 
3130
 
 
3131
                                LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
 
3132
 
 
3133
                                dbus_message_iter_next(&sub);
 
3134
                        }
 
3135
 
 
3136
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
 
3137
                        DBusMessageIter sub, sub2;
 
3138
 
 
3139
                        dbus_message_iter_recurse(iter, &sub);
 
3140
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3141
                                const char *type, *path;
 
3142
 
 
3143
                                dbus_message_iter_recurse(&sub, &sub2);
 
3144
 
 
3145
                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
 
3146
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
 
3147
                                        int r;
 
3148
 
 
3149
                                        r = strv_extend(&i->listen, type);
 
3150
                                        if (r < 0)
 
3151
                                                return r;
 
3152
                                        r = strv_extend(&i->listen, path);
 
3153
                                        if (r < 0)
 
3154
                                                return r;
 
3155
                                }
 
3156
 
 
3157
                                dbus_message_iter_next(&sub);
 
3158
                        }
 
3159
 
 
3160
                        return 0;
 
3161
 
 
3162
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING && streq(name, "DropInPaths")) {
 
3163
                        int r = bus_parse_strv_iter(iter, &i->dropin_paths);
 
3164
                        if (r < 0)
 
3165
                                return r;
 
3166
 
 
3167
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
 
3168
                           streq(name, "Documentation")) {
 
3169
 
 
3170
                        DBusMessageIter sub;
 
3171
 
 
3172
                        dbus_message_iter_recurse(iter, &sub);
 
3173
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
 
3174
                                const char *s;
 
3175
                                int r;
 
3176
 
 
3177
                                dbus_message_iter_get_basic(&sub, &s);
 
3178
 
 
3179
                                r = strv_extend(&i->documentation, s);
 
3180
                                if (r < 0)
 
3181
                                        return r;
 
3182
 
 
3183
                                dbus_message_iter_next(&sub);
 
3184
                        }
 
3185
                }
 
3186
 
 
3187
                break;
 
3188
        }
 
3189
 
 
3190
        case DBUS_TYPE_STRUCT: {
 
3191
 
 
3192
                if (streq(name, "LoadError")) {
 
3193
                        DBusMessageIter sub;
 
3194
                        const char *n, *message;
 
3195
                        int r;
 
3196
 
 
3197
                        dbus_message_iter_recurse(iter, &sub);
 
3198
 
 
3199
                        r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
 
3200
                        if (r < 0)
 
3201
                                return r;
 
3202
 
 
3203
                        r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
 
3204
                        if (r < 0)
 
3205
                                return r;
 
3206
 
 
3207
                        if (!isempty(message))
 
3208
                                i->load_error = message;
 
3209
                }
 
3210
 
 
3211
                break;
 
3212
        }
 
3213
        }
 
3214
 
 
3215
        return 0;
 
3216
}
 
3217
 
 
3218
static int print_property(const char *name, DBusMessageIter *iter) {
 
3219
        assert(name);
 
3220
        assert(iter);
 
3221
 
 
3222
        /* This is a low-level property printer, see
 
3223
         * print_status_info() for the nicer output */
 
3224
 
 
3225
        if (arg_properties && !strv_find(arg_properties, name))
 
3226
                return 0;
 
3227
 
 
3228
        switch (dbus_message_iter_get_arg_type(iter)) {
 
3229
 
 
3230
        case DBUS_TYPE_STRUCT: {
 
3231
                DBusMessageIter sub;
 
3232
                dbus_message_iter_recurse(iter, &sub);
 
3233
 
 
3234
                if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
 
3235
                        uint32_t u;
 
3236
 
 
3237
                        dbus_message_iter_get_basic(&sub, &u);
 
3238
 
 
3239
                        if (u)
 
3240
                                printf("%s=%u\n", name, (unsigned) u);
 
3241
                        else if (arg_all)
 
3242
                                printf("%s=\n", name);
 
3243
 
 
3244
                        return 0;
 
3245
                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
 
3246
                        const char *s;
 
3247
 
 
3248
                        dbus_message_iter_get_basic(&sub, &s);
 
3249
 
 
3250
                        if (arg_all || s[0])
 
3251
                                printf("%s=%s\n", name, s);
 
3252
 
 
3253
                        return 0;
 
3254
                } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
 
3255
                        const char *a = NULL, *b = NULL;
 
3256
 
 
3257
                        if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
 
3258
                                bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
 
3259
 
 
3260
                        if (arg_all || !isempty(a) || !isempty(b))
 
3261
                                printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
 
3262
 
 
3263
                        return 0;
 
3264
                }
 
3265
 
 
3266
                break;
 
3267
        }
 
3268
 
 
3269
        case DBUS_TYPE_ARRAY:
 
3270
 
 
3271
                if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
 
3272
                        DBusMessageIter sub, sub2;
 
3273
 
 
3274
                        dbus_message_iter_recurse(iter, &sub);
 
3275
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3276
                                const char *path;
 
3277
                                dbus_bool_t ignore;
 
3278
 
 
3279
                                dbus_message_iter_recurse(&sub, &sub2);
 
3280
 
 
3281
                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
 
3282
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
 
3283
                                        printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
 
3284
 
 
3285
                                dbus_message_iter_next(&sub);
 
3286
                        }
 
3287
 
 
3288
                        return 0;
 
3289
 
 
3290
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
 
3291
                        DBusMessageIter sub, sub2;
 
3292
 
 
3293
                        dbus_message_iter_recurse(iter, &sub);
 
3294
 
 
3295
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3296
                                const char *type, *path;
 
3297
 
 
3298
                                dbus_message_iter_recurse(&sub, &sub2);
 
3299
 
 
3300
                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
 
3301
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
 
3302
                                        printf("%s=%s\n", type, path);
 
3303
 
 
3304
                                dbus_message_iter_next(&sub);
 
3305
                        }
 
3306
 
 
3307
                        return 0;
 
3308
 
 
3309
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
 
3310
                        DBusMessageIter sub, sub2;
 
3311
 
 
3312
                        dbus_message_iter_recurse(iter, &sub);
 
3313
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3314
                                const char *type, *path;
 
3315
 
 
3316
                                dbus_message_iter_recurse(&sub, &sub2);
 
3317
 
 
3318
                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
 
3319
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
 
3320
                                        printf("Listen%s=%s\n", type, path);
 
3321
 
 
3322
                                dbus_message_iter_next(&sub);
 
3323
                        }
 
3324
 
 
3325
                        return 0;
 
3326
 
 
3327
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
 
3328
                        DBusMessageIter sub, sub2;
 
3329
 
 
3330
                        dbus_message_iter_recurse(iter, &sub);
 
3331
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3332
                                const char *base;
 
3333
                                uint64_t value, next_elapse;
 
3334
 
 
3335
                                dbus_message_iter_recurse(&sub, &sub2);
 
3336
 
 
3337
                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
 
3338
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
 
3339
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
 
3340
                                        char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
 
3341
 
 
3342
                                        printf("%s={ value=%s ; next_elapse=%s }\n",
 
3343
                                               base,
 
3344
                                               format_timespan(timespan1, sizeof(timespan1), value, 0),
 
3345
                                               format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
 
3346
                                }
 
3347
 
 
3348
                                dbus_message_iter_next(&sub);
 
3349
                        }
 
3350
 
 
3351
                        return 0;
 
3352
 
 
3353
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
 
3354
                        DBusMessageIter sub, sub2;
 
3355
 
 
3356
                        dbus_message_iter_recurse(iter, &sub);
 
3357
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3358
                                const char *controller, *attr, *value;
 
3359
 
 
3360
                                dbus_message_iter_recurse(&sub, &sub2);
 
3361
 
 
3362
                                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
 
3363
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
 
3364
                                    bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
 
3365
 
 
3366
                                        printf("ControlGroupAttributes={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
 
3367
                                               controller,
 
3368
                                               attr,
 
3369
                                               value);
 
3370
                                }
 
3371
 
 
3372
                                dbus_message_iter_next(&sub);
 
3373
                        }
 
3374
 
 
3375
                        return 0;
 
3376
 
 
3377
                } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
 
3378
                        DBusMessageIter sub;
 
3379
 
 
3380
                        dbus_message_iter_recurse(iter, &sub);
 
3381
                        while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
 
3382
                                ExecStatusInfo info = {};
 
3383
 
 
3384
                                if (exec_status_info_deserialize(&sub, &info) >= 0) {
 
3385
                                        char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
 
3386
                                        _cleanup_free_ char *t;
 
3387
 
 
3388
                                        t = strv_join(info.argv, " ");
 
3389
 
 
3390
                                        printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
 
3391
                                               name,
 
3392
                                               strna(info.path),
 
3393
                                               strna(t),
 
3394
                                               yes_no(info.ignore),
 
3395
                                               strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
 
3396
                                               strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
 
3397
                                               (unsigned) info. pid,
 
3398
                                               sigchld_code_to_string(info.code),
 
3399
                                               info.status,
 
3400
                                               info.code == CLD_EXITED ? "" : "/",
 
3401
                                               strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
 
3402
                                }
 
3403
 
 
3404
                                free(info.path);
 
3405
                                strv_free(info.argv);
 
3406
 
 
3407
                                dbus_message_iter_next(&sub);
 
3408
                        }
 
3409
 
 
3410
                        return 0;
 
3411
                }
 
3412
 
 
3413
                break;
 
3414
        }
 
3415
 
 
3416
        if (generic_print_property(name, iter, arg_all) > 0)
 
3417
                return 0;
 
3418
 
 
3419
        if (arg_all)
 
3420
                printf("%s=[unprintable]\n", name);
 
3421
 
 
3422
        return 0;
 
3423
}
 
3424
 
 
3425
static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
 
3426
        _cleanup_free_ DBusMessage *reply = NULL;
 
3427
        const char *interface = "";
 
3428
        int r;
 
3429
        DBusMessageIter iter, sub, sub2, sub3;
 
3430
        UnitStatusInfo info = {};
 
3431
        ExecStatusInfo *p;
 
3432
 
 
3433
        assert(path);
 
3434
        assert(new_line);
 
3435
 
 
3436
        r = bus_method_call_with_reply(
 
3437
                        bus,
 
3438
                        "org.freedesktop.systemd1",
 
3439
                        path,
 
3440
                        "org.freedesktop.DBus.Properties",
 
3441
                        "GetAll",
 
3442
                        &reply,
 
3443
                        NULL,
 
3444
                        DBUS_TYPE_STRING, &interface,
 
3445
                        DBUS_TYPE_INVALID);
 
3446
        if (r < 0)
 
3447
                return r;
 
3448
 
 
3449
        if (!dbus_message_iter_init(reply, &iter) ||
 
3450
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
3451
            dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)  {
 
3452
                log_error("Failed to parse reply.");
 
3453
                return -EIO;
 
3454
        }
 
3455
 
 
3456
        dbus_message_iter_recurse(&iter, &sub);
 
3457
 
 
3458
        if (*new_line)
 
3459
                printf("\n");
 
3460
 
 
3461
        *new_line = true;
 
3462
 
 
3463
        while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
3464
                const char *name;
 
3465
 
 
3466
                assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
 
3467
                dbus_message_iter_recurse(&sub, &sub2);
 
3468
 
 
3469
                if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
 
3470
                    dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
 
3471
                        log_error("Failed to parse reply.");
 
3472
                        return -EIO;
 
3473
                }
 
3474
 
 
3475
                dbus_message_iter_recurse(&sub2, &sub3);
 
3476
 
 
3477
                if (show_properties)
 
3478
                        r = print_property(name, &sub3);
 
3479
                else
 
3480
                        r = status_property(name, &sub3, &info);
 
3481
                if (r < 0) {
 
3482
                        log_error("Failed to parse reply.");
 
3483
                        return -EIO;
 
3484
                }
 
3485
 
 
3486
                dbus_message_iter_next(&sub);
 
3487
        }
 
3488
 
 
3489
        r = 0;
 
3490
 
 
3491
        if (!show_properties) {
 
3492
                if (streq(verb, "help"))
 
3493
                        show_unit_help(&info);
 
3494
                else
 
3495
                        print_status_info(&info);
 
3496
        }
 
3497
 
 
3498
        strv_free(info.documentation);
 
3499
        strv_free(info.dropin_paths);
 
3500
        strv_free(info.listen);
 
3501
 
 
3502
        if (!streq_ptr(info.active_state, "active") &&
 
3503
            !streq_ptr(info.active_state, "reloading") &&
 
3504
            streq(verb, "status"))
 
3505
                /* According to LSB: "program not running" */
 
3506
                r = 3;
 
3507
 
 
3508
        while ((p = info.exec)) {
 
3509
                LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
 
3510
                exec_status_info_free(p);
 
3511
        }
 
3512
 
 
3513
        return r;
 
3514
}
 
3515
 
 
3516
static int show_one_by_pid(const char *verb, DBusConnection *bus, uint32_t pid, bool *new_line) {
 
3517
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
3518
        const char *path = NULL;
 
3519
        _cleanup_dbus_error_free_ DBusError error;
 
3520
        int r;
 
3521
 
 
3522
        dbus_error_init(&error);
 
3523
 
 
3524
        r = bus_method_call_with_reply(
 
3525
                        bus,
 
3526
                        "org.freedesktop.systemd1",
 
3527
                        "/org/freedesktop/systemd1",
 
3528
                        "org.freedesktop.systemd1.Manager",
 
3529
                        "GetUnitByPID",
 
3530
                        &reply,
 
3531
                        NULL,
 
3532
                        DBUS_TYPE_UINT32, &pid,
 
3533
                        DBUS_TYPE_INVALID);
 
3534
        if (r < 0)
 
3535
                return r;
 
3536
 
 
3537
        if (!dbus_message_get_args(reply, &error,
 
3538
                                   DBUS_TYPE_OBJECT_PATH, &path,
 
3539
                                   DBUS_TYPE_INVALID)) {
 
3540
                log_error("Failed to parse reply: %s", bus_error_message(&error));
 
3541
                return -EIO;
 
3542
        }
 
3543
 
 
3544
        r = show_one(verb, bus, path, false, new_line);
 
3545
        return r;
 
3546
}
 
3547
 
 
3548
static int show_all(const char* verb, DBusConnection *bus, bool show_properties, bool *new_line) {
 
3549
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
3550
        _cleanup_free_ struct unit_info *unit_infos = NULL;
 
3551
        unsigned c = 0;
 
3552
        const struct unit_info *u;
 
3553
        int r;
 
3554
 
 
3555
        r = get_unit_list(bus, &reply, &unit_infos, &c);
 
3556
        if (r < 0)
 
3557
                return r;
 
3558
 
 
3559
        qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
 
3560
 
 
3561
        for (u = unit_infos; u < unit_infos + c; u++) {
 
3562
                _cleanup_free_ char *p = NULL;
 
3563
 
 
3564
                if (!output_show_unit(u))
 
3565
                        continue;
 
3566
 
 
3567
                p = unit_dbus_path_from_name(u->id);
 
3568
                if (!p)
 
3569
                        return log_oom();
 
3570
 
 
3571
                printf("%s -> '%s'\n", u->id, p);
 
3572
 
 
3573
                r = show_one(verb, bus, p, show_properties, new_line);
 
3574
                if (r != 0)
 
3575
                        return r;
 
3576
        }
 
3577
 
 
3578
        return 0;
 
3579
}
 
3580
 
 
3581
static int show(DBusConnection *bus, char **args) {
 
3582
        int r, ret = 0;
 
3583
        bool show_properties, show_status, new_line = false;
 
3584
        char **name;
 
3585
 
 
3586
        assert(bus);
 
3587
        assert(args);
 
3588
 
 
3589
        show_properties = streq(args[0], "show");
 
3590
        show_status = streq(args[0], "status");
 
3591
 
 
3592
        if (show_properties)
 
3593
                pager_open_if_enabled();
 
3594
 
 
3595
        /* If no argument is specified inspect the manager itself */
 
3596
 
 
3597
        if (show_properties && strv_length(args) <= 1)
 
3598
                return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
 
3599
 
 
3600
        if (show_status && strv_length(args) <= 1)
 
3601
                return show_all(args[0], bus, false, &new_line);
 
3602
 
 
3603
        STRV_FOREACH(name, args+1) {
 
3604
                uint32_t id;
 
3605
 
 
3606
                if (safe_atou32(*name, &id) < 0) {
 
3607
                        _cleanup_free_ char *p = NULL, *n = NULL;
 
3608
                        /* Interpret as unit name */
 
3609
 
 
3610
                        n = unit_name_mangle(*name);
 
3611
                        if (!n)
 
3612
                                return log_oom();
 
3613
 
 
3614
                        p = unit_dbus_path_from_name(n);
 
3615
                        if (!p)
 
3616
                                return log_oom();
 
3617
 
 
3618
                        r = show_one(args[0], bus, p, show_properties, &new_line);
 
3619
                        if (r != 0)
 
3620
                                ret = r;
 
3621
 
 
3622
                } else if (show_properties) {
 
3623
                        _cleanup_free_ char *p = NULL;
 
3624
 
 
3625
                        /* Interpret as job id */
 
3626
                        if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
 
3627
                                return log_oom();
 
3628
 
 
3629
                        r = show_one(args[0], bus, p, show_properties, &new_line);
 
3630
                        if (r != 0)
 
3631
                                ret = r;
 
3632
 
 
3633
                } else {
 
3634
                        /* Interpret as PID */
 
3635
                        r = show_one_by_pid(args[0], bus, id, &new_line);
 
3636
                        if (r != 0)
 
3637
                                ret = r;
 
3638
                }
 
3639
        }
 
3640
 
 
3641
        return ret;
 
3642
}
 
3643
 
 
3644
static int dump(DBusConnection *bus, char **args) {
 
3645
        _cleanup_free_ DBusMessage *reply = NULL;
 
3646
        DBusError error;
 
3647
        int r;
 
3648
        const char *text;
 
3649
 
 
3650
        dbus_error_init(&error);
 
3651
 
 
3652
        pager_open_if_enabled();
 
3653
 
 
3654
        r = bus_method_call_with_reply(
 
3655
                        bus,
 
3656
                        "org.freedesktop.systemd1",
 
3657
                        "/org/freedesktop/systemd1",
 
3658
                        "org.freedesktop.systemd1.Manager",
 
3659
                        "Dump",
 
3660
                        &reply,
 
3661
                        NULL,
 
3662
                        DBUS_TYPE_INVALID);
 
3663
        if (r < 0)
 
3664
                return r;
 
3665
 
 
3666
        if (!dbus_message_get_args(reply, &error,
 
3667
                                   DBUS_TYPE_STRING, &text,
 
3668
                                   DBUS_TYPE_INVALID)) {
 
3669
                log_error("Failed to parse reply: %s", bus_error_message(&error));
 
3670
                dbus_error_free(&error);
 
3671
                return  -EIO;
 
3672
        }
 
3673
 
 
3674
        fputs(text, stdout);
 
3675
        return 0;
 
3676
}
 
3677
 
 
3678
static int snapshot(DBusConnection *bus, char **args) {
 
3679
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
3680
        DBusError error;
 
3681
        int r;
 
3682
        dbus_bool_t cleanup = FALSE;
 
3683
        DBusMessageIter iter, sub;
 
3684
        const char
 
3685
                *path, *id,
 
3686
                *interface = "org.freedesktop.systemd1.Unit",
 
3687
                *property = "Id";
 
3688
        _cleanup_free_ char *n = NULL;
 
3689
 
 
3690
        dbus_error_init(&error);
 
3691
 
 
3692
        if (strv_length(args) > 1)
 
3693
                n = snapshot_name_mangle(args[1]);
 
3694
        else
 
3695
                n = strdup("");
 
3696
        if (!n)
 
3697
                return log_oom();
 
3698
 
 
3699
        r = bus_method_call_with_reply (
 
3700
                        bus,
 
3701
                        "org.freedesktop.systemd1",
 
3702
                        "/org/freedesktop/systemd1",
 
3703
                        "org.freedesktop.systemd1.Manager",
 
3704
                        "CreateSnapshot",
 
3705
                        &reply,
 
3706
                        NULL,
 
3707
                        DBUS_TYPE_STRING, &n,
 
3708
                        DBUS_TYPE_BOOLEAN, &cleanup,
 
3709
                        DBUS_TYPE_INVALID);
 
3710
        if (r < 0)
 
3711
                return r;
 
3712
 
 
3713
        if (!dbus_message_get_args(reply, &error,
 
3714
                                   DBUS_TYPE_OBJECT_PATH, &path,
 
3715
                                   DBUS_TYPE_INVALID)) {
 
3716
                log_error("Failed to parse reply: %s", bus_error_message(&error));
 
3717
                dbus_error_free(&error);
 
3718
                return -EIO;
 
3719
        }
 
3720
 
 
3721
        dbus_message_unref(reply);
 
3722
        reply = NULL;
 
3723
 
 
3724
        r = bus_method_call_with_reply (
 
3725
                        bus,
 
3726
                        "org.freedesktop.systemd1",
 
3727
                        path,
 
3728
                        "org.freedesktop.DBus.Properties",
 
3729
                        "Get",
 
3730
                        &reply,
 
3731
                        NULL,
 
3732
                        DBUS_TYPE_STRING, &interface,
 
3733
                        DBUS_TYPE_STRING, &property,
 
3734
                        DBUS_TYPE_INVALID);
 
3735
        if (r < 0)
 
3736
                return r;
 
3737
 
 
3738
        if (!dbus_message_iter_init(reply, &iter) ||
 
3739
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
 
3740
                log_error("Failed to parse reply.");
 
3741
                return -EIO;
 
3742
        }
 
3743
 
 
3744
        dbus_message_iter_recurse(&iter, &sub);
 
3745
 
 
3746
        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)  {
 
3747
                log_error("Failed to parse reply.");
 
3748
                return -EIO;
 
3749
        }
 
3750
 
 
3751
        dbus_message_iter_get_basic(&sub, &id);
 
3752
 
 
3753
        if (!arg_quiet)
 
3754
                puts(id);
 
3755
 
 
3756
        return 0;
 
3757
}
 
3758
 
 
3759
static int delete_snapshot(DBusConnection *bus, char **args) {
 
3760
        char **name;
 
3761
 
 
3762
        assert(args);
 
3763
 
 
3764
        STRV_FOREACH(name, args+1) {
 
3765
                _cleanup_free_ char *n = NULL;
 
3766
                int r;
 
3767
 
 
3768
                n = snapshot_name_mangle(*name);
 
3769
                if (!n)
 
3770
                        return log_oom();
 
3771
 
 
3772
                r = bus_method_call_with_reply(
 
3773
                                bus,
 
3774
                                "org.freedesktop.systemd1",
 
3775
                                "/org/freedesktop/systemd1",
 
3776
                                "org.freedesktop.systemd1.Manager",
 
3777
                                "RemoveSnapshot",
 
3778
                                NULL,
 
3779
                                NULL,
 
3780
                                DBUS_TYPE_STRING, &n,
 
3781
                                DBUS_TYPE_INVALID);
 
3782
                if (r < 0)
 
3783
                        return r;
 
3784
        }
 
3785
 
 
3786
        return 0;
 
3787
}
 
3788
 
 
3789
static int daemon_reload(DBusConnection *bus, char **args) {
 
3790
        int r;
 
3791
        const char *method;
 
3792
        DBusError error;
 
3793
 
 
3794
        if (arg_action == ACTION_RELOAD)
 
3795
                method = "Reload";
 
3796
        else if (arg_action == ACTION_REEXEC)
 
3797
                method = "Reexecute";
 
3798
        else {
 
3799
                assert(arg_action == ACTION_SYSTEMCTL);
 
3800
 
 
3801
                method =
 
3802
                        streq(args[0], "clear-jobs")    ||
 
3803
                        streq(args[0], "cancel")        ? "ClearJobs" :
 
3804
                        streq(args[0], "daemon-reexec") ? "Reexecute" :
 
3805
                        streq(args[0], "reset-failed")  ? "ResetFailed" :
 
3806
                        streq(args[0], "halt")          ? "Halt" :
 
3807
                        streq(args[0], "poweroff")      ? "PowerOff" :
 
3808
                        streq(args[0], "reboot")        ? "Reboot" :
 
3809
                        streq(args[0], "kexec")         ? "KExec" :
 
3810
                        streq(args[0], "exit")          ? "Exit" :
 
3811
                                    /* "daemon-reload" */ "Reload";
 
3812
        }
 
3813
 
 
3814
        r = bus_method_call_with_reply(
 
3815
                        bus,
 
3816
                        "org.freedesktop.systemd1",
 
3817
                        "/org/freedesktop/systemd1",
 
3818
                        "org.freedesktop.systemd1.Manager",
 
3819
                        method,
 
3820
                        NULL,
 
3821
                        &error,
 
3822
                        DBUS_TYPE_INVALID);
 
3823
 
 
3824
        if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
 
3825
                /* There's always a fallback possible for
 
3826
                 * legacy actions. */
 
3827
                r = -EADDRNOTAVAIL;
 
3828
        else if (r == -ETIMEDOUT && streq(method, "Reexecute"))
 
3829
                /* On reexecution, we expect a disconnect, not
 
3830
                 * a reply */
 
3831
                r = 0;
 
3832
        else if (r < 0)
 
3833
                log_error("Failed to issue method call: %s", bus_error_message(&error));
 
3834
 
 
3835
        dbus_error_free(&error);
 
3836
        return r;
 
3837
}
 
3838
 
 
3839
static int reset_failed(DBusConnection *bus, char **args) {
 
3840
        int r = 0;
 
3841
        char **name;
 
3842
 
 
3843
        if (strv_length(args) <= 1)
 
3844
                return daemon_reload(bus, args);
 
3845
 
 
3846
        STRV_FOREACH(name, args+1) {
 
3847
                _cleanup_free_ char *n;
 
3848
 
 
3849
                n = unit_name_mangle(*name);
 
3850
                if (!n)
 
3851
                        return log_oom();
 
3852
 
 
3853
                r = bus_method_call_with_reply(
 
3854
                                bus,
 
3855
                                "org.freedesktop.systemd1",
 
3856
                                "/org/freedesktop/systemd1",
 
3857
                                "org.freedesktop.systemd1.Manager",
 
3858
                                "ResetFailedUnit",
 
3859
                                NULL,
 
3860
                                NULL,
 
3861
                                DBUS_TYPE_STRING, &n,
 
3862
                                DBUS_TYPE_INVALID);
 
3863
                if (r < 0)
 
3864
                        return r;
 
3865
        }
 
3866
 
 
3867
        return 0;
 
3868
}
 
3869
 
 
3870
static int show_enviroment(DBusConnection *bus, char **args) {
 
3871
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
3872
        DBusMessageIter iter, sub, sub2;
 
3873
        int r;
 
3874
        const char
 
3875
                *interface = "org.freedesktop.systemd1.Manager",
 
3876
                *property = "Environment";
 
3877
 
 
3878
        pager_open_if_enabled();
 
3879
 
 
3880
        r = bus_method_call_with_reply(
 
3881
                        bus,
 
3882
                        "org.freedesktop.systemd1",
 
3883
                        "/org/freedesktop/systemd1",
 
3884
                        "org.freedesktop.DBus.Properties",
 
3885
                        "Get",
 
3886
                        &reply,
 
3887
                        NULL,
 
3888
                        DBUS_TYPE_STRING, &interface,
 
3889
                        DBUS_TYPE_STRING, &property,
 
3890
                        DBUS_TYPE_INVALID);
 
3891
        if (r < 0)
 
3892
                return r;
 
3893
 
 
3894
        if (!dbus_message_iter_init(reply, &iter) ||
 
3895
            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
 
3896
                log_error("Failed to parse reply.");
 
3897
                return -EIO;
 
3898
        }
 
3899
 
 
3900
        dbus_message_iter_recurse(&iter, &sub);
 
3901
 
 
3902
        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
 
3903
            dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING)  {
 
3904
                log_error("Failed to parse reply.");
 
3905
                return -EIO;
 
3906
        }
 
3907
 
 
3908
        dbus_message_iter_recurse(&sub, &sub2);
 
3909
 
 
3910
        while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
 
3911
                const char *text;
 
3912
 
 
3913
                if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
 
3914
                        log_error("Failed to parse reply.");
 
3915
                        return -EIO;
 
3916
                }
 
3917
 
 
3918
                dbus_message_iter_get_basic(&sub2, &text);
 
3919
                puts(text);
 
3920
 
 
3921
                dbus_message_iter_next(&sub2);
 
3922
        }
 
3923
 
 
3924
        return 0;
 
3925
}
 
3926
 
 
3927
static int switch_root(DBusConnection *bus, char **args) {
 
3928
        unsigned l;
 
3929
        const char *root;
 
3930
        _cleanup_free_ char *init = NULL;
 
3931
 
 
3932
        l = strv_length(args);
 
3933
        if (l < 2 || l > 3) {
 
3934
                log_error("Wrong number of arguments.");
 
3935
                return -EINVAL;
 
3936
        }
 
3937
 
 
3938
        root = args[1];
 
3939
 
 
3940
        if (l >= 3)
 
3941
                init = strdup(args[2]);
 
3942
        else {
 
3943
                parse_env_file("/proc/cmdline", WHITESPACE,
 
3944
                               "init", &init,
 
3945
                               NULL);
 
3946
 
 
3947
                if (!init)
 
3948
                        init = strdup("");
 
3949
        }
 
3950
        if (!init)
 
3951
                return log_oom();
 
3952
 
 
3953
        log_debug("switching root - root: %s; init: %s", root, init);
 
3954
 
 
3955
        return bus_method_call_with_reply(
 
3956
                        bus,
 
3957
                        "org.freedesktop.systemd1",
 
3958
                        "/org/freedesktop/systemd1",
 
3959
                        "org.freedesktop.systemd1.Manager",
 
3960
                        "SwitchRoot",
 
3961
                        NULL,
 
3962
                        NULL,
 
3963
                        DBUS_TYPE_STRING, &root,
 
3964
                        DBUS_TYPE_STRING, &init,
 
3965
                        DBUS_TYPE_INVALID);
 
3966
}
 
3967
 
 
3968
static int set_environment(DBusConnection *bus, char **args) {
 
3969
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
 
3970
        DBusError error;
 
3971
        const char *method;
 
3972
        DBusMessageIter iter;
 
3973
        int r;
 
3974
 
 
3975
        assert(bus);
 
3976
        assert(args);
 
3977
 
 
3978
        dbus_error_init(&error);
 
3979
 
 
3980
        method = streq(args[0], "set-environment")
 
3981
                ? "SetEnvironment"
 
3982
                : "UnsetEnvironment";
 
3983
 
 
3984
        m = dbus_message_new_method_call(
 
3985
                        "org.freedesktop.systemd1",
 
3986
                        "/org/freedesktop/systemd1",
 
3987
                        "org.freedesktop.systemd1.Manager",
 
3988
                        method);
 
3989
        if (!m)
 
3990
                return log_oom();
 
3991
 
 
3992
        dbus_message_iter_init_append(m, &iter);
 
3993
 
 
3994
        r = bus_append_strv_iter(&iter, args + 1);
 
3995
        if (r < 0)
 
3996
                return log_oom();
 
3997
 
 
3998
        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
 
3999
        if (!reply) {
 
4000
                log_error("Failed to issue method call: %s", bus_error_message(&error));
 
4001
                dbus_error_free(&error);
 
4002
                return -EIO;
 
4003
        }
 
4004
 
 
4005
        return 0;
 
4006
}
 
4007
 
 
4008
static int enable_sysv_units(char **args) {
 
4009
        int r = 0;
 
4010
 
 
4011
#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
 
4012
        const char *verb = args[0];
 
4013
        unsigned f = 1, t = 1;
 
4014
        LookupPaths paths = {};
 
4015
 
 
4016
        if (arg_scope != UNIT_FILE_SYSTEM)
 
4017
                return 0;
 
4018
 
 
4019
        if (!streq(verb, "enable") &&
 
4020
            !streq(verb, "disable") &&
 
4021
            !streq(verb, "is-enabled"))
 
4022
                return 0;
 
4023
 
 
4024
        /* Processes all SysV units, and reshuffles the array so that
 
4025
         * afterwards only the native units remain */
 
4026
 
 
4027
        r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
 
4028
        if (r < 0)
 
4029
                return r;
 
4030
 
 
4031
        r = 0;
 
4032
        for (f = 1; args[f]; f++) {
 
4033
                const char *name;
 
4034
                _cleanup_free_ char *p = NULL, *q = NULL;
 
4035
                bool found_native = false, found_sysv;
 
4036
                unsigned c = 1;
 
4037
                const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
 
4038
                char **k, *l;
 
4039
                int j;
 
4040
                pid_t pid;
 
4041
                siginfo_t status;
 
4042
 
 
4043
                name = args[f];
 
4044
 
 
4045
                if (!endswith(name, ".service"))
 
4046
                        continue;
 
4047
 
 
4048
                if (path_is_absolute(name))
 
4049
                        continue;
 
4050
 
 
4051
                STRV_FOREACH(k, paths.unit_path) {
 
4052
                        if (!isempty(arg_root))
 
4053
                                asprintf(&p, "%s/%s/%s", arg_root, *k, name);
 
4054
                        else
 
4055
                                asprintf(&p, "%s/%s", *k, name);
 
4056
 
 
4057
                        if (!p) {
 
4058
                                r = log_oom();
 
4059
                                goto finish;
 
4060
                        }
 
4061
 
 
4062
                        found_native = access(p, F_OK) >= 0;
 
4063
                        free(p);
 
4064
                        p = NULL;
 
4065
 
 
4066
                        if (found_native)
 
4067
                                break;
 
4068
                }
 
4069
 
 
4070
                if (found_native)
 
4071
                        continue;
 
4072
 
 
4073
                if (!isempty(arg_root))
 
4074
                        asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
 
4075
                else
 
4076
                        asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
 
4077
                if (!p) {
 
4078
                        r = log_oom();
 
4079
                        goto finish;
 
4080
                }
 
4081
 
 
4082
                p[strlen(p) - sizeof(".service") + 1] = 0;
 
4083
                found_sysv = access(p, F_OK) >= 0;
 
4084
 
 
4085
                if (!found_sysv)
 
4086
                        continue;
 
4087
 
 
4088
                /* Mark this entry, so that we don't try enabling it as native unit */
 
4089
                args[f] = (char*) "";
 
4090
 
 
4091
                log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
 
4092
 
 
4093
                if (!isempty(arg_root))
 
4094
                        argv[c++] = q = strappend("--root=", arg_root);
 
4095
 
 
4096
                argv[c++] = path_get_file_name(p);
 
4097
                argv[c++] =
 
4098
                        streq(verb, "enable") ? "on" :
 
4099
                        streq(verb, "disable") ? "off" : "--level=5";
 
4100
                argv[c] = NULL;
 
4101
 
 
4102
                l = strv_join((char**)argv, " ");
 
4103
                if (!l) {
 
4104
                        r = log_oom();
 
4105
                        goto finish;
 
4106
                }
 
4107
 
 
4108
                log_info("Executing %s", l);
 
4109
                free(l);
 
4110
 
 
4111
                pid = fork();
 
4112
                if (pid < 0) {
 
4113
                        log_error("Failed to fork: %m");
 
4114
                        r = -errno;
 
4115
                        goto finish;
 
4116
                } else if (pid == 0) {
 
4117
                        /* Child */
 
4118
 
 
4119
                        execv(argv[0], (char**) argv);
 
4120
                        _exit(EXIT_FAILURE);
 
4121
                }
 
4122
 
 
4123
                j = wait_for_terminate(pid, &status);
 
4124
                if (j < 0) {
 
4125
                        log_error("Failed to wait for child: %s", strerror(-r));
 
4126
                        r = j;
 
4127
                        goto finish;
 
4128
                }
 
4129
 
 
4130
                if (status.si_code == CLD_EXITED) {
 
4131
                        if (streq(verb, "is-enabled")) {
 
4132
                                if (status.si_status == 0) {
 
4133
                                        if (!arg_quiet)
 
4134
                                                puts("enabled");
 
4135
                                        r = 1;
 
4136
                                } else {
 
4137
                                        if (!arg_quiet)
 
4138
                                                puts("disabled");
 
4139
                                }
 
4140
 
 
4141
                        } else if (status.si_status != 0) {
 
4142
                                r = -EINVAL;
 
4143
                                goto finish;
 
4144
                        }
 
4145
                } else {
 
4146
                        r = -EPROTO;
 
4147
                        goto finish;
 
4148
                }
 
4149
        }
 
4150
 
 
4151
finish:
 
4152
        lookup_paths_free(&paths);
 
4153
 
 
4154
        /* Drop all SysV units */
 
4155
        for (f = 1, t = 1; args[f]; f++) {
 
4156
 
 
4157
                if (isempty(args[f]))
 
4158
                        continue;
 
4159
 
 
4160
                args[t++] = args[f];
 
4161
        }
 
4162
 
 
4163
        args[t] = NULL;
 
4164
 
 
4165
#endif
 
4166
        return r;
 
4167
}
 
4168
 
 
4169
static int mangle_names(char **original_names, char ***mangled_names) {
 
4170
        char **i, **l, **name;
 
4171
 
 
4172
        l = new(char*, strv_length(original_names) + 1);
 
4173
        if (!l)
 
4174
                return log_oom();
 
4175
 
 
4176
        i = l;
 
4177
        STRV_FOREACH(name, original_names) {
 
4178
 
 
4179
                /* When enabling units qualified path names are OK,
 
4180
                 * too, hence allow them explicitly. */
 
4181
 
 
4182
                if (is_path(*name))
 
4183
                        *i = strdup(*name);
 
4184
                else
 
4185
                        *i = unit_name_mangle(*name);
 
4186
 
 
4187
                if (!*i) {
 
4188
                        strv_free(l);
 
4189
                        return log_oom();
 
4190
                }
 
4191
 
 
4192
                i++;
 
4193
        }
 
4194
 
 
4195
        *i = NULL;
 
4196
        *mangled_names = l;
 
4197
 
 
4198
        return 0;
 
4199
}
 
4200
 
 
4201
static int enable_unit(DBusConnection *bus, char **args) {
 
4202
        const char *verb = args[0];
 
4203
        UnitFileChange *changes = NULL;
 
4204
        unsigned n_changes = 0, i;
 
4205
        int carries_install_info = -1;
 
4206
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
 
4207
        int r;
 
4208
        _cleanup_dbus_error_free_ DBusError error;
 
4209
        _cleanup_strv_free_ char **mangled_names = NULL;
 
4210
 
 
4211
        dbus_error_init(&error);
 
4212
 
 
4213
        r = enable_sysv_units(args);
 
4214
        if (r < 0)
 
4215
                return r;
 
4216
 
 
4217
        if (!args[1])
 
4218
                return 0;
 
4219
 
 
4220
        if (!bus || avoid_bus()) {
 
4221
                if (streq(verb, "enable")) {
 
4222
                        r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
 
4223
                        carries_install_info = r;
 
4224
                } else if (streq(verb, "disable"))
 
4225
                        r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
 
4226
                else if (streq(verb, "reenable")) {
 
4227
                        r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
 
4228
                        carries_install_info = r;
 
4229
                } else if (streq(verb, "link"))
 
4230
                        r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
 
4231
                else if (streq(verb, "preset")) {
 
4232
                        r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
 
4233
                        carries_install_info = r;
 
4234
                } else if (streq(verb, "mask"))
 
4235
                        r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
 
4236
                else if (streq(verb, "unmask"))
 
4237
                        r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
 
4238
                else
 
4239
                        assert_not_reached("Unknown verb");
 
4240
 
 
4241
                if (r < 0) {
 
4242
                        log_error("Operation failed: %s", strerror(-r));
 
4243
                        goto finish;
 
4244
                }
 
4245
 
 
4246
                if (!arg_quiet) {
 
4247
                        for (i = 0; i < n_changes; i++) {
 
4248
                                if (changes[i].type == UNIT_FILE_SYMLINK)
 
4249
                                        log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
 
4250
                                else
 
4251
                                        log_info("rm '%s'", changes[i].path);
 
4252
                        }
 
4253
                }
 
4254
 
 
4255
                r = 0;
 
4256
        } else {
 
4257
                const char *method;
 
4258
                bool send_force = true, expect_carries_install_info = false;
 
4259
                dbus_bool_t a, b;
 
4260
                DBusMessageIter iter, sub, sub2;
 
4261
 
 
4262
                if (streq(verb, "enable")) {
 
4263
                        method = "EnableUnitFiles";
 
4264
                        expect_carries_install_info = true;
 
4265
                } else if (streq(verb, "disable")) {
 
4266
                        method = "DisableUnitFiles";
 
4267
                        send_force = false;
 
4268
                } else if (streq(verb, "reenable")) {
 
4269
                        method = "ReenableUnitFiles";
 
4270
                        expect_carries_install_info = true;
 
4271
                } else if (streq(verb, "link"))
 
4272
                        method = "LinkUnitFiles";
 
4273
                else if (streq(verb, "preset")) {
 
4274
                        method = "PresetUnitFiles";
 
4275
                        expect_carries_install_info = true;
 
4276
                } else if (streq(verb, "mask"))
 
4277
                        method = "MaskUnitFiles";
 
4278
                else if (streq(verb, "unmask")) {
 
4279
                        method = "UnmaskUnitFiles";
 
4280
                        send_force = false;
 
4281
                } else
 
4282
                        assert_not_reached("Unknown verb");
 
4283
 
 
4284
                m = dbus_message_new_method_call(
 
4285
                                "org.freedesktop.systemd1",
 
4286
                                "/org/freedesktop/systemd1",
 
4287
                                "org.freedesktop.systemd1.Manager",
 
4288
                                method);
 
4289
                if (!m) {
 
4290
                        r = log_oom();
 
4291
                        goto finish;
 
4292
                }
 
4293
 
 
4294
                dbus_message_iter_init_append(m, &iter);
 
4295
 
 
4296
                r = mangle_names(args+1, &mangled_names);
 
4297
                if(r < 0)
 
4298
                        goto finish;
 
4299
 
 
4300
                r = bus_append_strv_iter(&iter, mangled_names);
 
4301
                if (r < 0) {
 
4302
                        log_error("Failed to append unit files.");
 
4303
                        goto finish;
 
4304
                }
 
4305
 
 
4306
                a = arg_runtime;
 
4307
                if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
 
4308
                        log_error("Failed to append runtime boolean.");
 
4309
                        r = -ENOMEM;
 
4310
                        goto finish;
 
4311
                }
 
4312
 
 
4313
                if (send_force) {
 
4314
                        b = arg_force;
 
4315
 
 
4316
                        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
 
4317
                                log_error("Failed to append force boolean.");
 
4318
                                r = -ENOMEM;
 
4319
                                goto finish;
 
4320
                        }
 
4321
                }
 
4322
 
 
4323
                reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
 
4324
                if (!reply) {
 
4325
                        log_error("Failed to issue method call: %s", bus_error_message(&error));
 
4326
                        r = -EIO;
 
4327
                        goto finish;
 
4328
                }
 
4329
 
 
4330
                if (!dbus_message_iter_init(reply, &iter)) {
 
4331
                        log_error("Failed to initialize iterator.");
 
4332
                        goto finish;
 
4333
                }
 
4334
 
 
4335
                if (expect_carries_install_info) {
 
4336
                        r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
 
4337
                        if (r < 0) {
 
4338
                                log_error("Failed to parse reply.");
 
4339
                                goto finish;
 
4340
                        }
 
4341
 
 
4342
                        carries_install_info = b;
 
4343
                }
 
4344
 
 
4345
                if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
 
4346
                    dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)  {
 
4347
                        log_error("Failed to parse reply.");
 
4348
                        r = -EIO;
 
4349
                        goto finish;
 
4350
                }
 
4351
 
 
4352
                dbus_message_iter_recurse(&iter, &sub);
 
4353
                while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
 
4354
                        const char *type, *path, *source;
 
4355
 
 
4356
                        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
 
4357
                                log_error("Failed to parse reply.");
 
4358
                                r = -EIO;
 
4359
                                goto finish;
 
4360
                        }
 
4361
 
 
4362
                        dbus_message_iter_recurse(&sub, &sub2);
 
4363
 
 
4364
                        if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
 
4365
                            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
 
4366
                            bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
 
4367
                                log_error("Failed to parse reply.");
 
4368
                                r = -EIO;
 
4369
                                goto finish;
 
4370
                        }
 
4371
 
 
4372
                        if (!arg_quiet) {
 
4373
                                if (streq(type, "symlink"))
 
4374
                                        log_info("ln -s '%s' '%s'", source, path);
 
4375
                                else
 
4376
                                        log_info("rm '%s'", path);
 
4377
                        }
 
4378
 
 
4379
                        dbus_message_iter_next(&sub);
 
4380
                }
 
4381
 
 
4382
                /* Try to reload if enabeld */
 
4383
                if (!arg_no_reload)
 
4384
                        r = daemon_reload(bus, args);
 
4385
        }
 
4386
 
 
4387
        if (carries_install_info == 0)
 
4388
                log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
 
4389
                            "using systemctl.\n"
 
4390
                            "Possible reasons for having this kind of units are:\n"
 
4391
                            "1) A unit may be statically enabled by being symlinked from another unit's\n"
 
4392
                            "   .wants/ or .requires/ directory.\n"
 
4393
                            "2) A unit's purpose may be to act as a helper for some other unit which has\n"
 
4394
                            "   a requirement dependency on it.\n"
 
4395
                            "3) A unit may be started when needed via activation (socket, path, timer,\n"
 
4396
                            "   D-Bus, udev, scripted systemctl call, ...).\n");
 
4397
 
 
4398
finish:
 
4399
        unit_file_changes_free(changes, n_changes);
 
4400
 
 
4401
        return r;
 
4402
}
 
4403
 
 
4404
static int unit_is_enabled(DBusConnection *bus, char **args) {
 
4405
        _cleanup_dbus_error_free_ DBusError error;
 
4406
        int r;
 
4407
        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
 
4408
        bool enabled;
 
4409
        char **name;
 
4410
        char *n;
 
4411
 
 
4412
        dbus_error_init(&error);
 
4413
 
 
4414
        r = enable_sysv_units(args);
 
4415
        if (r < 0)
 
4416
                return r;
 
4417
 
 
4418
        enabled = r > 0;
 
4419
 
 
4420
        if (!bus || avoid_bus()) {
 
4421
 
 
4422
                STRV_FOREACH(name, args+1) {
 
4423
                        UnitFileState state;
 
4424
 
 
4425
                        n = unit_name_mangle(*name);
 
4426
                        if (!n)
 
4427
                                return log_oom();
 
4428
 
 
4429
                        state = unit_file_get_state(arg_scope, arg_root, n);
 
4430
 
 
4431
                        free(n);
 
4432
 
 
4433
                        if (state < 0)
 
4434
                                return state;
 
4435
 
 
4436
                        if (state == UNIT_FILE_ENABLED ||
 
4437
                            state == UNIT_FILE_ENABLED_RUNTIME ||
 
4438
                            state == UNIT_FILE_STATIC)
 
4439
                                enabled = true;
 
4440
 
 
4441
                        if (!arg_quiet)
 
4442
                                puts(unit_file_state_to_string(state));
 
4443
                }
 
4444
 
 
4445
        } else {
 
4446
                STRV_FOREACH(name, args+1) {
 
4447
                        const char *s;
 
4448
 
 
4449
                        n = unit_name_mangle(*name);
 
4450
                        if (!n)
 
4451
                                return log_oom();
 
4452
 
 
4453
                        r = bus_method_call_with_reply (
 
4454
                                        bus,
 
4455
                                        "org.freedesktop.systemd1",
 
4456
                                        "/org/freedesktop/systemd1",
 
4457
                                        "org.freedesktop.systemd1.Manager",
 
4458
                                        "GetUnitFileState",
 
4459
                                        &reply,
 
4460
                                        NULL,
 
4461
                                        DBUS_TYPE_STRING, &n,
 
4462
                                        DBUS_TYPE_INVALID);
 
4463
 
 
4464
                        free(n);
 
4465
 
 
4466
                        if (r)
 
4467
                                return r;
 
4468
 
 
4469
                        if (!dbus_message_get_args(reply, &error,
 
4470
                                                   DBUS_TYPE_STRING, &s,
 
4471
                                                   DBUS_TYPE_INVALID)) {
 
4472
                                log_error("Failed to parse reply: %s", bus_error_message(&error));
 
4473
                                return -EIO;
 
4474
                        }
 
4475
 
 
4476
                        dbus_message_unref(reply);
 
4477
                        reply = NULL;
 
4478
 
 
4479
                        if (streq(s, "enabled") ||
 
4480
                            streq(s, "enabled-runtime") ||
 
4481
                            streq(s, "static"))
 
4482
                                enabled = true;
 
4483
 
 
4484
                        if (!arg_quiet)
 
4485
                                puts(s);
 
4486
                }
 
4487
        }
 
4488
 
 
4489
        return enabled ? 0 : 1;
 
4490
}
 
4491
 
 
4492
static int systemctl_help(void) {
 
4493
 
 
4494
        pager_open_if_enabled();
 
4495
 
 
4496
        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
 
4497
               "Query or send control commands to the systemd manager.\n\n"
 
4498
               "  -h --help           Show this help\n"
 
4499
               "     --version        Show package version\n"
 
4500
               "  -t --type=TYPE      List only units of a particular type\n"
 
4501
               "  -p --property=NAME  Show only properties by this name\n"
 
4502
               "  -a --all            Show all loaded units/properties, including dead/empty\n"
 
4503
               "                      ones. To list all units installed on the system, use\n"
 
4504
               "                      the 'list-unit-files' command instead.\n"
 
4505
               "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
 
4506
               "     --failed         Show only failed units\n"
 
4507
               "     --full           Don't ellipsize unit names on output\n"
 
4508
               "     --fail           When queueing a new job, fail if conflicting jobs are\n"
 
4509
               "                      pending\n"
 
4510
               "     --irreversible   Create jobs which cannot be implicitly cancelled\n"
 
4511
               "     --show-types     When showing sockets, explicitly show their type\n"
 
4512
               "     --ignore-dependencies\n"
 
4513
               "                      When queueing a new job, ignore all its dependencies\n"
 
4514
               "  -i --ignore-inhibitors\n"
 
4515
               "                      When shutting down or sleeping, ignore inhibitors\n"
 
4516
               "     --kill-who=WHO   Who to send signal to\n"
 
4517
               "  -s --signal=SIGNAL  Which signal to send\n"
 
4518
               "  -H --host=[USER@]HOST\n"
 
4519
               "                      Show information for remote host\n"
 
4520
               "  -P --privileged     Acquire privileges before execution\n"
 
4521
               "  -q --quiet          Suppress output\n"
 
4522
               "     --no-block       Do not wait until operation finished\n"
 
4523
               "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
 
4524
               "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
 
4525
               "                      configuration\n"
 
4526
               "     --no-legend      Do not print a legend (column headers and hints)\n"
 
4527
               "     --no-pager       Do not pipe output into a pager\n"
 
4528
               "     --no-ask-password\n"
 
4529
               "                      Do not ask for system passwords\n"
 
4530
               "     --system         Connect to system manager\n"
 
4531
               "     --user           Connect to user service manager\n"
 
4532
               "     --global         Enable/disable unit files globally\n"
 
4533
               "  -f --force          When enabling unit files, override existing symlinks\n"
 
4534
               "                      When shutting down, execute action immediately\n"
 
4535
               "     --root=PATH      Enable unit files in the specified root directory\n"
 
4536
               "     --runtime        Enable unit files only temporarily until next reboot\n"
 
4537
               "  -n --lines=INTEGER  Journal entries to show\n"
 
4538
               "  -o --output=STRING  Change journal output mode (short, short-monotonic,\n"
 
4539
               "                      verbose, export, json, json-pretty, json-sse, cat)\n\n"
 
4540
               "Unit Commands:\n"
 
4541
               "  list-units                      List loaded units\n"
 
4542
               "  start [NAME...]                 Start (activate) one or more units\n"
 
4543
               "  stop [NAME...]                  Stop (deactivate) one or more units\n"
 
4544
               "  reload [NAME...]                Reload one or more units\n"
 
4545
               "  restart [NAME...]               Start or restart one or more units\n"
 
4546
               "  try-restart [NAME...]           Restart one or more units if active\n"
 
4547
               "  reload-or-restart [NAME...]     Reload one or more units if possible,\n"
 
4548
               "                                  otherwise start or restart\n"
 
4549
               "  reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
 
4550
               "                                  otherwise restart if active\n"
 
4551
               "  isolate [NAME]                  Start one unit and stop all others\n"
 
4552
               "  kill [NAME...]                  Send signal to processes of a unit\n"
 
4553
               "  is-active [NAME...]             Check whether units are active\n"
 
4554
               "  is-failed [NAME...]             Check whether units are failed\n"
 
4555
               "  status [NAME...|PID...]         Show runtime status of one or more units\n"
 
4556
               "  show [NAME...|JOB...]           Show properties of one or more\n"
 
4557
               "                                  units/jobs or the manager\n"
 
4558
               "  help [NAME...|PID...]           Show manual for one or more units\n"
 
4559
               "  reset-failed [NAME...]          Reset failed state for all, one, or more\n"
 
4560
               "                                  units\n"
 
4561
               "  get-cgroup-attr [NAME] [ATTR] ...\n"
 
4562
               "                                  Get control group attrubute\n"
 
4563
               "  set-cgroup-attr [NAME] [ATTR] [VALUE] ...\n"
 
4564
               "                                  Set control group attribute\n"
 
4565
               "  unset-cgroup-attr [NAME] [ATTR...]\n"
 
4566
               "                                  Unset control group attribute\n"
 
4567
               "  set-cgroup [NAME] [CGROUP...]   Add unit to a control group\n"
 
4568
               "  unset-cgroup [NAME] [CGROUP...] Remove unit from a control group\n"
 
4569
               "  load [NAME...]                  Load one or more units\n"
 
4570
               "  list-dependencies [NAME]        Recursively show units which are required\n"
 
4571
               "                                  or wanted by this unit or by which this\n"
 
4572
               "                                  unit is required or wanted\n\n"
 
4573
               "Unit File Commands:\n"
 
4574
               "  list-unit-files                 List installed unit files\n"
 
4575
               "  enable [NAME...]                Enable one or more unit files\n"
 
4576
               "  disable [NAME...]               Disable one or more unit files\n"
 
4577
               "  reenable [NAME...]              Reenable one or more unit files\n"
 
4578
               "  preset [NAME...]                Enable/disable one or more unit files\n"
 
4579
               "                                  based on preset configuration\n"
 
4580
               "  mask [NAME...]                  Mask one or more units\n"
 
4581
               "  unmask [NAME...]                Unmask one or more units\n"
 
4582
               "  link [PATH...]                  Link one or more units files into\n"
 
4583
               "                                  the search path\n"
 
4584
               "  is-enabled [NAME...]            Check whether unit files are enabled\n\n"
 
4585
               "Job Commands:\n"
 
4586
               "  list-jobs                       List jobs\n"
 
4587
               "  cancel [JOB...]                 Cancel all, one, or more jobs\n\n"
 
4588
               "Status Commands:\n"
 
4589
               "  dump                            Dump server status\n"
 
4590
               "Snapshot Commands:\n"
 
4591
               "  snapshot [NAME]                 Create a snapshot\n"
 
4592
               "  delete [NAME...]                Remove one or more snapshots\n\n"
 
4593
               "Environment Commands:\n"
 
4594
               "  show-environment                Dump environment\n"
 
4595
               "  set-environment [NAME=VALUE...] Set one or more environment variables\n"
 
4596
               "  unset-environment [NAME...]     Unset one or more environment variables\n\n"
 
4597
               "Manager Lifecycle Commands:\n"
 
4598
               "  daemon-reload                   Reload systemd manager configuration\n"
 
4599
               "  daemon-reexec                   Reexecute systemd manager\n\n"
 
4600
               "System Commands:\n"
 
4601
               "  default                         Enter system default mode\n"
 
4602
               "  rescue                          Enter system rescue mode\n"
 
4603
               "  emergency                       Enter system emergency mode\n"
 
4604
               "  halt                            Shut down and halt the system\n"
 
4605
               "  poweroff                        Shut down and power-off the system\n"
 
4606
               "  reboot                          Shut down and reboot the system\n"
 
4607
               "  kexec                           Shut down and reboot the system with kexec\n"
 
4608
               "  exit                            Request user instance exit\n"
 
4609
               "  switch-root [ROOT] [INIT]       Change to a different root file system\n"
 
4610
               "  suspend                         Suspend the system\n"
 
4611
               "  hibernate                       Hibernate the system\n"
 
4612
               "  hybrid-sleep                    Hibernate and suspend the system\n",
 
4613
               program_invocation_short_name);
 
4614
 
 
4615
        return 0;
 
4616
}
 
4617
 
 
4618
static int halt_help(void) {
 
4619
 
 
4620
        printf("%s [OPTIONS...]\n\n"
 
4621
               "%s the system.\n\n"
 
4622
               "     --help      Show this help\n"
 
4623
               "     --halt      Halt the machine\n"
 
4624
               "  -p --poweroff  Switch off the machine\n"
 
4625
               "     --reboot    Reboot the machine\n"
 
4626
               "  -f --force     Force immediate halt/power-off/reboot\n"
 
4627
               "  -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
 
4628
               "  -d --no-wtmp   Don't write wtmp record\n"
 
4629
               "     --no-wall   Don't send wall message before halt/power-off/reboot\n",
 
4630
               program_invocation_short_name,
 
4631
               arg_action == ACTION_REBOOT   ? "Reboot" :
 
4632
               arg_action == ACTION_POWEROFF ? "Power off" :
 
4633
                                               "Halt");
 
4634
 
 
4635
        return 0;
 
4636
}
 
4637
 
 
4638
static int shutdown_help(void) {
 
4639
 
 
4640
        printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
 
4641
               "Shut down the system.\n\n"
 
4642
               "     --help      Show this help\n"
 
4643
               "  -H --halt      Halt the machine\n"
 
4644
               "  -P --poweroff  Power-off the machine\n"
 
4645
               "  -r --reboot    Reboot the machine\n"
 
4646
               "  -h             Equivalent to --poweroff, overridden by --halt\n"
 
4647
               "  -k             Don't halt/power-off/reboot, just send warnings\n"
 
4648
               "     --no-wall   Don't send wall message before halt/power-off/reboot\n"
 
4649
               "  -c             Cancel a pending shutdown\n",
 
4650
               program_invocation_short_name);
 
4651
 
 
4652
        return 0;
 
4653
}
 
4654
 
 
4655
static int telinit_help(void) {
 
4656
 
 
4657
        printf("%s [OPTIONS...] {COMMAND}\n\n"
 
4658
               "Send control commands to the init daemon.\n\n"
 
4659
               "     --help      Show this help\n"
 
4660
               "     --no-wall   Don't send wall message before halt/power-off/reboot\n\n"
 
4661
               "Commands:\n"
 
4662
               "  0              Power-off the machine\n"
 
4663
               "  6              Reboot the machine\n"
 
4664
               "  2, 3, 4, 5     Start runlevelX.target unit\n"
 
4665
               "  1, s, S        Enter rescue mode\n"
 
4666
               "  q, Q           Reload init daemon configuration\n"
 
4667
               "  u, U           Reexecute init daemon\n",
 
4668
               program_invocation_short_name);
 
4669
 
 
4670
        return 0;
 
4671
}
 
4672
 
 
4673
static int runlevel_help(void) {
 
4674
 
 
4675
        printf("%s [OPTIONS...]\n\n"
 
4676
               "Prints the previous and current runlevel of the init system.\n\n"
 
4677
               "     --help      Show this help\n",
 
4678
               program_invocation_short_name);
 
4679
 
 
4680
        return 0;
 
4681
}
 
4682
 
 
4683
static int help_types(void) {
 
4684
        int i;
 
4685
        const char *t;
 
4686
 
 
4687
        puts("Available unit types:");
 
4688
        for(i = 0; i < _UNIT_TYPE_MAX; i++) {
 
4689
                t = unit_type_to_string(i);
 
4690
                if (t)
 
4691
                        puts(t);
 
4692
        }
 
4693
 
 
4694
        puts("\nAvailable unit load states: ");
 
4695
        for(i = 0; i < _UNIT_LOAD_STATE_MAX; i++) {
 
4696
                t = unit_load_state_to_string(i);
 
4697
                if (t)
 
4698
                        puts(t);
 
4699
        }
 
4700
 
 
4701
        return 0;
 
4702
}
 
4703
 
 
4704
static int systemctl_parse_argv(int argc, char *argv[]) {
 
4705
 
 
4706
        enum {
 
4707
                ARG_FAIL = 0x100,
 
4708
                ARG_REVERSE,
 
4709
                ARG_AFTER,
 
4710
                ARG_BEFORE,
 
4711
                ARG_SHOW_TYPES,
 
4712
                ARG_IRREVERSIBLE,
 
4713
                ARG_IGNORE_DEPENDENCIES,
 
4714
                ARG_VERSION,
 
4715
                ARG_USER,
 
4716
                ARG_SYSTEM,
 
4717
                ARG_GLOBAL,
 
4718
                ARG_NO_BLOCK,
 
4719
                ARG_NO_LEGEND,
 
4720
                ARG_NO_PAGER,
 
4721
                ARG_NO_WALL,
 
4722
                ARG_ROOT,
 
4723
                ARG_FULL,
 
4724
                ARG_NO_RELOAD,
 
4725
                ARG_KILL_WHO,
 
4726
                ARG_NO_ASK_PASSWORD,
 
4727
                ARG_FAILED,
 
4728
                ARG_RUNTIME,
 
4729
                ARG_FORCE,
 
4730
                ARG_PLAIN
 
4731
        };
 
4732
 
 
4733
        static const struct option options[] = {
 
4734
                { "help",      no_argument,       NULL, 'h'           },
 
4735
                { "version",   no_argument,       NULL, ARG_VERSION   },
 
4736
                { "type",      required_argument, NULL, 't'           },
 
4737
                { "property",  required_argument, NULL, 'p'           },
 
4738
                { "all",       no_argument,       NULL, 'a'           },
 
4739
                { "reverse",   no_argument,       NULL, ARG_REVERSE   },
 
4740
                { "after",     no_argument,       NULL, ARG_AFTER     },
 
4741
                { "before",    no_argument,       NULL, ARG_BEFORE    },
 
4742
                { "show-types", no_argument,      NULL, ARG_SHOW_TYPES },
 
4743
                { "failed",    no_argument,       NULL, ARG_FAILED    },
 
4744
                { "full",      no_argument,       NULL, ARG_FULL      },
 
4745
                { "fail",      no_argument,       NULL, ARG_FAIL      },
 
4746
                { "irreversible", no_argument,    NULL, ARG_IRREVERSIBLE },
 
4747
                { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
 
4748
                { "ignore-inhibitors", no_argument, NULL, 'i'         },
 
4749
                { "user",      no_argument,       NULL, ARG_USER      },
 
4750
                { "system",    no_argument,       NULL, ARG_SYSTEM    },
 
4751
                { "global",    no_argument,       NULL, ARG_GLOBAL    },
 
4752
                { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
 
4753
                { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
 
4754
                { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
 
4755
                { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
 
4756
                { "quiet",     no_argument,       NULL, 'q'           },
 
4757
                { "root",      required_argument, NULL, ARG_ROOT      },
 
4758
                { "force",     no_argument,       NULL, ARG_FORCE     },
 
4759
                { "no-reload", no_argument,       NULL, ARG_NO_RELOAD },
 
4760
                { "kill-who",  required_argument, NULL, ARG_KILL_WHO  },
 
4761
                { "signal",    required_argument, NULL, 's'           },
 
4762
                { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
 
4763
                { "host",      required_argument, NULL, 'H'           },
 
4764
                { "privileged",no_argument,       NULL, 'P'           },
 
4765
                { "runtime",   no_argument,       NULL, ARG_RUNTIME   },
 
4766
                { "lines",     required_argument, NULL, 'n'           },
 
4767
                { "output",    required_argument, NULL, 'o'           },
 
4768
                { "plain",     no_argument,       NULL, ARG_PLAIN     },
 
4769
                { NULL,        0,                 NULL, 0             }
 
4770
        };
 
4771
 
 
4772
        int c;
 
4773
 
 
4774
        assert(argc >= 0);
 
4775
        assert(argv);
 
4776
 
 
4777
        while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:i", options, NULL)) >= 0) {
 
4778
 
 
4779
                switch (c) {
 
4780
 
 
4781
                case 'h':
 
4782
                        systemctl_help();
 
4783
                        return 0;
 
4784
 
 
4785
                case ARG_VERSION:
 
4786
                        puts(PACKAGE_STRING);
 
4787
                        puts(SYSTEMD_FEATURES);
 
4788
                        return 0;
 
4789
 
 
4790
                case 't': {
 
4791
                        char *word, *state;
 
4792
                        size_t size;
 
4793
 
 
4794
                        FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
 
4795
                                _cleanup_free_ char *type;
 
4796
 
 
4797
                                type = strndup(word, size);
 
4798
                                if (!type)
 
4799
                                        return -ENOMEM;
 
4800
 
 
4801
                                if (streq(type, "help")) {
 
4802
                                        help_types();
 
4803
                                        return 0;
 
4804
                                }
 
4805
 
 
4806
                                if (unit_type_from_string(type) >= 0) {
 
4807
                                        if (strv_push(&arg_types, type))
 
4808
                                                return log_oom();
 
4809
                                        type = NULL;
 
4810
                                        continue;
 
4811
                                }
 
4812
 
 
4813
                                if (unit_load_state_from_string(optarg) >= 0) {
 
4814
                                        if (strv_push(&arg_load_states, type))
 
4815
                                                return log_oom();
 
4816
                                        type = NULL;
 
4817
                                        continue;
 
4818
                                }
 
4819
 
 
4820
                                log_error("Unknown unit type or load state '%s'.", type);
 
4821
                                log_info("Use -t help to see a list of allowed values.");
 
4822
                                return -EINVAL;
 
4823
                        }
 
4824
 
 
4825
                        break;
 
4826
                }
 
4827
 
 
4828
                case 'p': {
 
4829
                        /* Make sure that if the empty property list
 
4830
                           was specified, we won't show any properties. */
 
4831
                        if (isempty(optarg) && !arg_properties) {
 
4832
                                arg_properties = strv_new(NULL, NULL);
 
4833
                                if (!arg_properties)
 
4834
                                        return log_oom();
 
4835
                        } else {
 
4836
                                char *word, *state;
 
4837
                                size_t size;
 
4838
 
 
4839
                                FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
 
4840
                                        char *prop;
 
4841
 
 
4842
                                        prop = strndup(word, size);
 
4843
                                        if (!prop)
 
4844
                                                return log_oom();
 
4845
 
 
4846
                                        if (strv_push(&arg_properties, prop)) {
 
4847
                                                free(prop);
 
4848
                                                return log_oom();
 
4849
                                        }
 
4850
                                }
 
4851
                        }
 
4852
 
 
4853
                        /* If the user asked for a particular
 
4854
                         * property, show it to him, even if it is
 
4855
                         * empty. */
 
4856
                        arg_all = true;
 
4857
 
 
4858
                        break;
 
4859
                }
 
4860
 
 
4861
                case 'a':
 
4862
                        arg_all = true;
 
4863
                        break;
 
4864
 
 
4865
                case ARG_REVERSE:
 
4866
                        arg_dependency = DEPENDENCY_REVERSE;
 
4867
                        break;
 
4868
 
 
4869
                case ARG_AFTER:
 
4870
                        arg_dependency = DEPENDENCY_AFTER;
 
4871
                        break;
 
4872
 
 
4873
                case ARG_BEFORE:
 
4874
                        arg_dependency = DEPENDENCY_BEFORE;
 
4875
                        break;
 
4876
 
 
4877
                case ARG_SHOW_TYPES:
 
4878
                        arg_show_types = true;
 
4879
                        break;
 
4880
 
 
4881
                case ARG_FAIL:
 
4882
                        arg_job_mode = "fail";
 
4883
                        break;
 
4884
 
 
4885
                case ARG_IRREVERSIBLE:
 
4886
                        arg_job_mode = "replace-irreversibly";
 
4887
                        break;
 
4888
 
 
4889
                case ARG_IGNORE_DEPENDENCIES:
 
4890
                        arg_job_mode = "ignore-dependencies";
 
4891
                        break;
 
4892
 
 
4893
                case ARG_USER:
 
4894
                        arg_scope = UNIT_FILE_USER;
 
4895
                        break;
 
4896
 
 
4897
                case ARG_SYSTEM:
 
4898
                        arg_scope = UNIT_FILE_SYSTEM;
 
4899
                        break;
 
4900
 
 
4901
                case ARG_GLOBAL:
 
4902
                        arg_scope = UNIT_FILE_GLOBAL;
 
4903
                        break;
 
4904
 
 
4905
                case ARG_NO_BLOCK:
 
4906
                        arg_no_block = true;
 
4907
                        break;
 
4908
 
 
4909
                case ARG_NO_LEGEND:
 
4910
                        arg_no_legend = true;
 
4911
                        break;
 
4912
 
 
4913
                case ARG_NO_PAGER:
 
4914
                        arg_no_pager = true;
 
4915
                        break;
 
4916
 
 
4917
                case ARG_NO_WALL:
 
4918
                        arg_no_wall = true;
 
4919
                        break;
 
4920
 
 
4921
                case ARG_ROOT:
 
4922
                        arg_root = optarg;
 
4923
                        break;
 
4924
 
 
4925
                case ARG_FULL:
 
4926
                        arg_full = true;
 
4927
                        break;
 
4928
 
 
4929
                case ARG_FAILED:
 
4930
                        arg_failed = true;
 
4931
                        break;
 
4932
 
 
4933
                case 'q':
 
4934
                        arg_quiet = true;
 
4935
                        break;
 
4936
 
 
4937
                case ARG_FORCE:
 
4938
                        arg_force ++;
 
4939
                        break;
 
4940
 
 
4941
                case 'f':
 
4942
                        arg_force ++;
 
4943
                        break;
 
4944
 
 
4945
                case ARG_NO_RELOAD:
 
4946
                        arg_no_reload = true;
 
4947
                        break;
 
4948
 
 
4949
                case ARG_KILL_WHO:
 
4950
                        arg_kill_who = optarg;
 
4951
                        break;
 
4952
 
 
4953
                case 's':
 
4954
                        if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
 
4955
                                log_error("Failed to parse signal string %s.", optarg);
 
4956
                                return -EINVAL;
 
4957
                        }
 
4958
                        break;
 
4959
 
 
4960
                case ARG_NO_ASK_PASSWORD:
 
4961
                        arg_ask_password = false;
 
4962
                        break;
 
4963
 
 
4964
                case 'P':
 
4965
                        arg_transport = TRANSPORT_POLKIT;
 
4966
                        break;
 
4967
 
 
4968
                case 'H':
 
4969
                        arg_transport = TRANSPORT_SSH;
 
4970
                        arg_host = optarg;
 
4971
                        break;
 
4972
 
 
4973
                case ARG_RUNTIME:
 
4974
                        arg_runtime = true;
 
4975
                        break;
 
4976
 
 
4977
                case 'n':
 
4978
                        if (safe_atou(optarg, &arg_lines) < 0) {
 
4979
                                log_error("Failed to parse lines '%s'", optarg);
 
4980
                                return -EINVAL;
 
4981
                        }
 
4982
                        break;
 
4983
 
 
4984
                case 'o':
 
4985
                        arg_output = output_mode_from_string(optarg);
 
4986
                        if (arg_output < 0) {
 
4987
                                log_error("Unknown output '%s'.", optarg);
 
4988
                                return -EINVAL;
 
4989
                        }
 
4990
                        break;
 
4991
 
 
4992
                case 'i':
 
4993
                        arg_ignore_inhibitors = true;
 
4994
                        break;
 
4995
 
 
4996
                case ARG_PLAIN:
 
4997
                        arg_plain = true;
 
4998
                        break;
 
4999
 
 
5000
                case '?':
 
5001
                        return -EINVAL;
 
5002
 
 
5003
                default:
 
5004
                        log_error("Unknown option code '%c'.", c);
 
5005
                        return -EINVAL;
 
5006
                }
 
5007
        }
 
5008
 
 
5009
        if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
 
5010
                log_error("Cannot access user instance remotely.");
 
5011
                return -EINVAL;
 
5012
        }
 
5013
 
 
5014
        return 1;
 
5015
}
 
5016
 
 
5017
static int halt_parse_argv(int argc, char *argv[]) {
 
5018
 
 
5019
        enum {
 
5020
                ARG_HELP = 0x100,
 
5021
                ARG_HALT,
 
5022
                ARG_REBOOT,
 
5023
                ARG_NO_WALL
 
5024
        };
 
5025
 
 
5026
        static const struct option options[] = {
 
5027
                { "help",      no_argument,       NULL, ARG_HELP    },
 
5028
                { "halt",      no_argument,       NULL, ARG_HALT    },
 
5029
                { "poweroff",  no_argument,       NULL, 'p'         },
 
5030
                { "reboot",    no_argument,       NULL, ARG_REBOOT  },
 
5031
                { "force",     no_argument,       NULL, 'f'         },
 
5032
                { "wtmp-only", no_argument,       NULL, 'w'         },
 
5033
                { "no-wtmp",   no_argument,       NULL, 'd'         },
 
5034
                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
 
5035
                { NULL,        0,                 NULL, 0           }
 
5036
        };
 
5037
 
 
5038
        int c, runlevel;
 
5039
 
 
5040
        assert(argc >= 0);
 
5041
        assert(argv);
 
5042
 
 
5043
        if (utmp_get_runlevel(&runlevel, NULL) >= 0)
 
5044
                if (runlevel == '0' || runlevel == '6')
 
5045
                        arg_force = 2;
 
5046
 
 
5047
        while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
 
5048
                switch (c) {
 
5049
 
 
5050
                case ARG_HELP:
 
5051
                        halt_help();
 
5052
                        return 0;
 
5053
 
 
5054
                case ARG_HALT:
 
5055
                        arg_action = ACTION_HALT;
 
5056
                        break;
 
5057
 
 
5058
                case 'p':
 
5059
                        if (arg_action != ACTION_REBOOT)
 
5060
                                arg_action = ACTION_POWEROFF;
 
5061
                        break;
 
5062
 
 
5063
                case ARG_REBOOT:
 
5064
                        arg_action = ACTION_REBOOT;
 
5065
                        break;
 
5066
 
 
5067
                case 'f':
 
5068
                        arg_force = 2;
 
5069
                        break;
 
5070
 
 
5071
                case 'w':
 
5072
                        arg_dry = true;
 
5073
                        break;
 
5074
 
 
5075
                case 'd':
 
5076
                        arg_no_wtmp = true;
 
5077
                        break;
 
5078
 
 
5079
                case ARG_NO_WALL:
 
5080
                        arg_no_wall = true;
 
5081
                        break;
 
5082
 
 
5083
                case 'i':
 
5084
                case 'h':
 
5085
                case 'n':
 
5086
                        /* Compatibility nops */
 
5087
                        break;
 
5088
 
 
5089
                case '?':
 
5090
                        return -EINVAL;
 
5091
 
 
5092
                default:
 
5093
                        log_error("Unknown option code '%c'.", c);
 
5094
                        return -EINVAL;
 
5095
                }
 
5096
        }
 
5097
 
 
5098
        if (optind < argc) {
 
5099
                log_error("Too many arguments.");
 
5100
                return -EINVAL;
 
5101
        }
 
5102
 
 
5103
        return 1;
 
5104
}
 
5105
 
 
5106
static int parse_time_spec(const char *t, usec_t *_u) {
 
5107
        assert(t);
 
5108
        assert(_u);
 
5109
 
 
5110
        if (streq(t, "now"))
 
5111
                *_u = 0;
 
5112
        else if (!strchr(t, ':')) {
 
5113
                uint64_t u;
 
5114
 
 
5115
                if (safe_atou64(t, &u) < 0)
 
5116
                        return -EINVAL;
 
5117
 
 
5118
                *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
 
5119
        } else {
 
5120
                char *e = NULL;
 
5121
                long hour, minute;
 
5122
                struct tm tm = {};
 
5123
                time_t s;
 
5124
                usec_t n;
 
5125
 
 
5126
                errno = 0;
 
5127
                hour = strtol(t, &e, 10);
 
5128
                if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
 
5129
                        return -EINVAL;
 
5130
 
 
5131
                minute = strtol(e+1, &e, 10);
 
5132
                if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
 
5133
                        return -EINVAL;
 
5134
 
 
5135
                n = now(CLOCK_REALTIME);
 
5136
                s = (time_t) (n / USEC_PER_SEC);
 
5137
 
 
5138
                assert_se(localtime_r(&s, &tm));
 
5139
 
 
5140
                tm.tm_hour = (int) hour;
 
5141
                tm.tm_min = (int) minute;
 
5142
                tm.tm_sec = 0;
 
5143
 
 
5144
                assert_se(s = mktime(&tm));
 
5145
 
 
5146
                *_u = (usec_t) s * USEC_PER_SEC;
 
5147
 
 
5148
                while (*_u <= n)
 
5149
                        *_u += USEC_PER_DAY;
 
5150
        }
 
5151
 
 
5152
        return 0;
 
5153
}
 
5154
 
 
5155
static int shutdown_parse_argv(int argc, char *argv[]) {
 
5156
 
 
5157
        enum {
 
5158
                ARG_HELP = 0x100,
 
5159
                ARG_NO_WALL
 
5160
        };
 
5161
 
 
5162
        static const struct option options[] = {
 
5163
                { "help",      no_argument,       NULL, ARG_HELP    },
 
5164
                { "halt",      no_argument,       NULL, 'H'         },
 
5165
                { "poweroff",  no_argument,       NULL, 'P'         },
 
5166
                { "reboot",    no_argument,       NULL, 'r'         },
 
5167
                { "kexec",     no_argument,       NULL, 'K'         }, /* not documented extension */
 
5168
                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
 
5169
                { NULL,        0,                 NULL, 0           }
 
5170
        };
 
5171
 
 
5172
        int c, r;
 
5173
 
 
5174
        assert(argc >= 0);
 
5175
        assert(argv);
 
5176
 
 
5177
        while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
 
5178
                switch (c) {
 
5179
 
 
5180
                case ARG_HELP:
 
5181
                        shutdown_help();
 
5182
                        return 0;
 
5183
 
 
5184
                case 'H':
 
5185
                        arg_action = ACTION_HALT;
 
5186
                        break;
 
5187
 
 
5188
                case 'P':
 
5189
                        arg_action = ACTION_POWEROFF;
 
5190
                        break;
 
5191
 
 
5192
                case 'r':
 
5193
                        if (kexec_loaded())
 
5194
                                arg_action = ACTION_KEXEC;
 
5195
                        else
 
5196
                                arg_action = ACTION_REBOOT;
 
5197
                        break;
 
5198
 
 
5199
                case 'K':
 
5200
                        arg_action = ACTION_KEXEC;
 
5201
                        break;
 
5202
 
 
5203
                case 'h':
 
5204
                        if (arg_action != ACTION_HALT)
 
5205
                                arg_action = ACTION_POWEROFF;
 
5206
                        break;
 
5207
 
 
5208
                case 'k':
 
5209
                        arg_dry = true;
 
5210
                        break;
 
5211
 
 
5212
                case ARG_NO_WALL:
 
5213
                        arg_no_wall = true;
 
5214
                        break;
 
5215
 
 
5216
                case 't':
 
5217
                case 'a':
 
5218
                        /* Compatibility nops */
 
5219
                        break;
 
5220
 
 
5221
                case 'c':
 
5222
                        arg_action = ACTION_CANCEL_SHUTDOWN;
 
5223
                        break;
 
5224
 
 
5225
                case '?':
 
5226
                        return -EINVAL;
 
5227
 
 
5228
                default:
 
5229
                        log_error("Unknown option code '%c'.", c);
 
5230
                        return -EINVAL;
 
5231
                }
 
5232
        }
 
5233
 
 
5234
        if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
 
5235
                r = parse_time_spec(argv[optind], &arg_when);
 
5236
                if (r < 0) {
 
5237
                        log_error("Failed to parse time specification: %s", argv[optind]);
 
5238
                        return r;
 
5239
                }
 
5240
        } else
 
5241
                arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
 
5242
 
 
5243
        if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
 
5244
                /* No time argument for shutdown cancel */
 
5245
                arg_wall = argv + optind;
 
5246
        else if (argc > optind + 1)
 
5247
                /* We skip the time argument */
 
5248
                arg_wall = argv + optind + 1;
 
5249
 
 
5250
        optind = argc;
 
5251
 
 
5252
        return 1;
 
5253
}
 
5254
 
 
5255
static int telinit_parse_argv(int argc, char *argv[]) {
 
5256
 
 
5257
        enum {
 
5258
                ARG_HELP = 0x100,
 
5259
                ARG_NO_WALL
 
5260
        };
 
5261
 
 
5262
        static const struct option options[] = {
 
5263
                { "help",      no_argument,       NULL, ARG_HELP    },
 
5264
                { "no-wall",   no_argument,       NULL, ARG_NO_WALL },
 
5265
                { NULL,        0,                 NULL, 0           }
 
5266
        };
 
5267
 
 
5268
        static const struct {
 
5269
                char from;
 
5270
                enum action to;
 
5271
        } table[] = {
 
5272
                { '0', ACTION_POWEROFF },
 
5273
                { '6', ACTION_REBOOT },
 
5274
                { '1', ACTION_RESCUE },
 
5275
                { '2', ACTION_RUNLEVEL2 },
 
5276
                { '3', ACTION_RUNLEVEL3 },
 
5277
                { '4', ACTION_RUNLEVEL4 },
 
5278
                { '5', ACTION_RUNLEVEL5 },
 
5279
                { 's', ACTION_RESCUE },
 
5280
                { 'S', ACTION_RESCUE },
 
5281
                { 'q', ACTION_RELOAD },
 
5282
                { 'Q', ACTION_RELOAD },
 
5283
                { 'u', ACTION_REEXEC },
 
5284
                { 'U', ACTION_REEXEC }
 
5285
        };
 
5286
 
 
5287
        unsigned i;
 
5288
        int c;
 
5289
 
 
5290
        assert(argc >= 0);
 
5291
        assert(argv);
 
5292
 
 
5293
        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
 
5294
                switch (c) {
 
5295
 
 
5296
                case ARG_HELP:
 
5297
                        telinit_help();
 
5298
                        return 0;
 
5299
 
 
5300
                case ARG_NO_WALL:
 
5301
                        arg_no_wall = true;
 
5302
                        break;
 
5303
 
 
5304
                case '?':
 
5305
                        return -EINVAL;
 
5306
 
 
5307
                default:
 
5308
                        log_error("Unknown option code '%c'.", c);
 
5309
                        return -EINVAL;
 
5310
                }
 
5311
        }
 
5312
 
 
5313
        if (optind >= argc) {
 
5314
                telinit_help();
 
5315
                return -EINVAL;
 
5316
        }
 
5317
 
 
5318
        if (optind + 1 < argc) {
 
5319
                log_error("Too many arguments.");
 
5320
                return -EINVAL;
 
5321
        }
 
5322
 
 
5323
        if (strlen(argv[optind]) != 1) {
 
5324
                log_error("Expected single character argument.");
 
5325
                return -EINVAL;
 
5326
        }
 
5327
 
 
5328
        for (i = 0; i < ELEMENTSOF(table); i++)
 
5329
                if (table[i].from == argv[optind][0])
 
5330
                        break;
 
5331
 
 
5332
        if (i >= ELEMENTSOF(table)) {
 
5333
                log_error("Unknown command '%s'.", argv[optind]);
 
5334
                return -EINVAL;
 
5335
        }
 
5336
 
 
5337
        arg_action = table[i].to;
 
5338
 
 
5339
        optind ++;
 
5340
 
 
5341
        return 1;
 
5342
}
 
5343
 
 
5344
static int runlevel_parse_argv(int argc, char *argv[]) {
 
5345
 
 
5346
        enum {
 
5347
                ARG_HELP = 0x100,
 
5348
        };
 
5349
 
 
5350
        static const struct option options[] = {
 
5351
                { "help",      no_argument,       NULL, ARG_HELP    },
 
5352
                { NULL,        0,                 NULL, 0           }
 
5353
        };
 
5354
 
 
5355
        int c;
 
5356
 
 
5357
        assert(argc >= 0);
 
5358
        assert(argv);
 
5359
 
 
5360
        while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
 
5361
                switch (c) {
 
5362
 
 
5363
                case ARG_HELP:
 
5364
                        runlevel_help();
 
5365
                        return 0;
 
5366
 
 
5367
                case '?':
 
5368
                        return -EINVAL;
 
5369
 
 
5370
                default:
 
5371
                        log_error("Unknown option code '%c'.", c);
 
5372
                        return -EINVAL;
 
5373
                }
 
5374
        }
 
5375
 
 
5376
        if (optind < argc) {
 
5377
                log_error("Too many arguments.");
 
5378
                return -EINVAL;
 
5379
        }
 
5380
 
 
5381
        return 1;
 
5382
}
 
5383
 
 
5384
static int parse_argv(int argc, char *argv[]) {
 
5385
        assert(argc >= 0);
 
5386
        assert(argv);
 
5387
 
 
5388
        if (program_invocation_short_name) {
 
5389
 
 
5390
                if (strstr(program_invocation_short_name, "halt")) {
 
5391
                        arg_action = ACTION_HALT;
 
5392
                        return halt_parse_argv(argc, argv);
 
5393
                } else if (strstr(program_invocation_short_name, "poweroff")) {
 
5394
                        arg_action = ACTION_POWEROFF;
 
5395
                        return halt_parse_argv(argc, argv);
 
5396
                } else if (strstr(program_invocation_short_name, "reboot")) {
 
5397
                        if (kexec_loaded())
 
5398
                                arg_action = ACTION_KEXEC;
 
5399
                        else
 
5400
                                arg_action = ACTION_REBOOT;
 
5401
                        return halt_parse_argv(argc, argv);
 
5402
                } else if (strstr(program_invocation_short_name, "shutdown")) {
 
5403
                        arg_action = ACTION_POWEROFF;
 
5404
                        return shutdown_parse_argv(argc, argv);
 
5405
                } else if (strstr(program_invocation_short_name, "init")) {
 
5406
 
 
5407
                        if (sd_booted() > 0) {
 
5408
                                arg_action = ACTION_INVALID;
 
5409
                                return telinit_parse_argv(argc, argv);
 
5410
                        } else {
 
5411
                                /* Hmm, so some other init system is
 
5412
                                 * running, we need to forward this
 
5413
                                 * request to it. For now we simply
 
5414
                                 * guess that it is Upstart. */
 
5415
 
 
5416
                                execv(TELINIT, argv);
 
5417
 
 
5418
                                log_error("Couldn't find an alternative telinit implementation to spawn.");
 
5419
                                return -EIO;
 
5420
                        }
 
5421
 
 
5422
                } else if (strstr(program_invocation_short_name, "runlevel")) {
 
5423
                        arg_action = ACTION_RUNLEVEL;
 
5424
                        return runlevel_parse_argv(argc, argv);
 
5425
                }
 
5426
        }
 
5427
 
 
5428
        arg_action = ACTION_SYSTEMCTL;
 
5429
        return systemctl_parse_argv(argc, argv);
 
5430
}
 
5431
 
 
5432
_pure_ static int action_to_runlevel(void) {
 
5433
 
 
5434
        static const char table[_ACTION_MAX] = {
 
5435
                [ACTION_HALT] =      '0',
 
5436
                [ACTION_POWEROFF] =  '0',
 
5437
                [ACTION_REBOOT] =    '6',
 
5438
                [ACTION_RUNLEVEL2] = '2',
 
5439
                [ACTION_RUNLEVEL3] = '3',
 
5440
                [ACTION_RUNLEVEL4] = '4',
 
5441
                [ACTION_RUNLEVEL5] = '5',
 
5442
                [ACTION_RESCUE] =    '1'
 
5443
        };
 
5444
 
 
5445
        assert(arg_action < _ACTION_MAX);
 
5446
 
 
5447
        return table[arg_action];
 
5448
}
 
5449
 
 
5450
static int talk_upstart(void) {
 
5451
        _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
 
5452
        _cleanup_dbus_error_free_ DBusError error;
 
5453
        int previous, rl, r;
 
5454
        char
 
5455
                env1_buf[] = "RUNLEVEL=X",
 
5456
                env2_buf[] = "PREVLEVEL=X";
 
5457
        char *env1 = env1_buf, *env2 = env2_buf;
 
5458
        const char *emit = "runlevel";
 
5459
        dbus_bool_t b_false = FALSE;
 
5460
        DBusMessageIter iter, sub;
 
5461
        DBusConnection *bus;
 
5462
 
 
5463
        dbus_error_init(&error);
 
5464
 
 
5465
        if (!(rl = action_to_runlevel()))
 
5466
                return 0;
 
5467
 
 
5468
        if (utmp_get_runlevel(&previous, NULL) < 0)
 
5469
                previous = 'N';
 
5470
 
 
5471
        if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
 
5472
                if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
 
5473
                        r = 0;
 
5474
                        goto finish;
 
5475
                }
 
5476
 
 
5477
                log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
 
5478
                r = -EIO;
 
5479
                goto finish;
 
5480
        }
 
5481
 
 
5482
        if ((r = bus_check_peercred(bus)) < 0) {
 
5483
                log_error("Failed to verify owner of bus.");
 
5484
                goto finish;
 
5485
        }
 
5486
 
 
5487
        if (!(m = dbus_message_new_method_call(
 
5488
                              "com.ubuntu.Upstart",
 
5489
                              "/com/ubuntu/Upstart",
 
5490
                              "com.ubuntu.Upstart0_6",
 
5491
                              "EmitEvent"))) {
 
5492
 
 
5493
                log_error("Could not allocate message.");
 
5494
                r = -ENOMEM;
 
5495
                goto finish;
 
5496
        }
 
5497
 
 
5498
        dbus_message_iter_init_append(m, &iter);
 
5499
 
 
5500
        env1_buf[sizeof(env1_buf)-2] = rl;
 
5501
        env2_buf[sizeof(env2_buf)-2] = previous;
 
5502
 
 
5503
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
 
5504
            !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
 
5505
            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
 
5506
            !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
 
5507
            !dbus_message_iter_close_container(&iter, &sub) ||
 
5508
            !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
 
5509
                log_error("Could not append arguments to message.");
 
5510
                r = -ENOMEM;
 
5511
                goto finish;
 
5512
        }
 
5513
 
 
5514
        if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
 
5515
 
 
5516
                if (bus_error_is_no_service(&error)) {
 
5517
                        r = -EADDRNOTAVAIL;
 
5518
                        goto finish;
 
5519
                }
 
5520
 
 
5521
                log_error("Failed to issue method call: %s", bus_error_message(&error));
 
5522
                r = -EIO;
 
5523
                goto finish;
 
5524
        }
 
5525
 
 
5526
        r = 1;
 
5527
 
 
5528
finish:
 
5529
        if (bus) {
 
5530
                dbus_connection_flush(bus);
 
5531
                dbus_connection_close(bus);
 
5532
                dbus_connection_unref(bus);
 
5533
        }
 
5534
 
 
5535
        return r;
 
5536
}
 
5537
 
 
5538
static int talk_initctl(void) {
 
5539
        struct init_request request = {};
 
5540
        int r;
 
5541
        _cleanup_close_ int fd = -1;
 
5542
        char rl;
 
5543
 
 
5544
        rl = action_to_runlevel();
 
5545
        if (!rl)
 
5546
                return 0;
 
5547
 
 
5548
        request.magic = INIT_MAGIC;
 
5549
        request.sleeptime = 0;
 
5550
        request.cmd = INIT_CMD_RUNLVL;
 
5551
        request.runlevel = rl;
 
5552
 
 
5553
        fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
 
5554
        if (fd < 0) {
 
5555
                if (errno == ENOENT)
 
5556
                        return 0;
 
5557
 
 
5558
                log_error("Failed to open "INIT_FIFO": %m");
 
5559
                return -errno;
 
5560
        }
 
5561
 
 
5562
        errno = 0;
 
5563
        r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
 
5564
        if (r) {
 
5565
                log_error("Failed to write to "INIT_FIFO": %m");
 
5566
                return errno > 0 ? -errno : -EIO;
 
5567
        }
 
5568
 
 
5569
        return 1;
 
5570
}
 
5571
 
 
5572
static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
 
5573
 
 
5574
        static const struct {
 
5575
                const char* verb;
 
5576
                const enum {
 
5577
                        MORE,
 
5578
                        LESS,
 
5579
                        EQUAL
 
5580
                } argc_cmp;
 
5581
                const int argc;
 
5582
                int (* const dispatch)(DBusConnection *bus, char **args);
 
5583
        } verbs[] = {
 
5584
                { "list-units",            LESS,  1, list_units        },
 
5585
                { "list-unit-files",       EQUAL, 1, list_unit_files   },
 
5586
                { "list-sockets",          LESS,  1, list_sockets      },
 
5587
                { "list-jobs",             EQUAL, 1, list_jobs         },
 
5588
                { "clear-jobs",            EQUAL, 1, daemon_reload     },
 
5589
                { "load",                  MORE,  2, load_unit         },
 
5590
                { "cancel",                MORE,  2, cancel_job        },
 
5591
                { "start",                 MORE,  2, start_unit        },
 
5592
                { "stop",                  MORE,  2, start_unit        },
 
5593
                { "condstop",              MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
 
5594
                { "reload",                MORE,  2, start_unit        },
 
5595
                { "restart",               MORE,  2, start_unit        },
 
5596
                { "try-restart",           MORE,  2, start_unit        },
 
5597
                { "reload-or-restart",     MORE,  2, start_unit        },
 
5598
                { "reload-or-try-restart", MORE,  2, start_unit        },
 
5599
                { "force-reload",          MORE,  2, start_unit        }, /* For compatibility with SysV */
 
5600
                { "condreload",            MORE,  2, start_unit        }, /* For compatibility with ALTLinux */
 
5601
                { "condrestart",           MORE,  2, start_unit        }, /* For compatibility with RH */
 
5602
                { "isolate",               EQUAL, 2, start_unit        },
 
5603
                { "set-cgroup",            MORE,  3, set_cgroup        },
 
5604
                { "unset-cgroup",          MORE,  3, set_cgroup        },
 
5605
                { "get-cgroup-attr",       MORE,  3, get_cgroup_attr   },
 
5606
                { "set-cgroup-attr",       MORE,  4, set_cgroup_attr   },
 
5607
                { "unset-cgroup-attr",     MORE,  3, set_cgroup        },
 
5608
                { "kill",                  MORE,  2, kill_unit         },
 
5609
                { "is-active",             MORE,  2, check_unit_active },
 
5610
                { "check",                 MORE,  2, check_unit_active },
 
5611
                { "is-failed",             MORE,  2, check_unit_failed },
 
5612
                { "show",                  MORE,  1, show              },
 
5613
                { "status",                MORE,  1, show              },
 
5614
                { "help",                  MORE,  2, show              },
 
5615
                { "dump",                  EQUAL, 1, dump              },
 
5616
                { "snapshot",              LESS,  2, snapshot          },
 
5617
                { "delete",                MORE,  2, delete_snapshot   },
 
5618
                { "daemon-reload",         EQUAL, 1, daemon_reload     },
 
5619
                { "daemon-reexec",         EQUAL, 1, daemon_reload     },
 
5620
                { "show-environment",      EQUAL, 1, show_enviroment   },
 
5621
                { "set-environment",       MORE,  2, set_environment   },
 
5622
                { "unset-environment",     MORE,  2, set_environment   },
 
5623
                { "halt",                  EQUAL, 1, start_special     },
 
5624
                { "poweroff",              EQUAL, 1, start_special     },
 
5625
                { "reboot",                EQUAL, 1, start_special     },
 
5626
                { "kexec",                 EQUAL, 1, start_special     },
 
5627
                { "suspend",               EQUAL, 1, start_special     },
 
5628
                { "hibernate",             EQUAL, 1, start_special     },
 
5629
                { "hybrid-sleep",          EQUAL, 1, start_special     },
 
5630
                { "default",               EQUAL, 1, start_special     },
 
5631
                { "rescue",                EQUAL, 1, start_special     },
 
5632
                { "emergency",             EQUAL, 1, start_special     },
 
5633
                { "exit",                  EQUAL, 1, start_special     },
 
5634
                { "reset-failed",          MORE,  1, reset_failed      },
 
5635
                { "enable",                MORE,  2, enable_unit       },
 
5636
                { "disable",               MORE,  2, enable_unit       },
 
5637
                { "is-enabled",            MORE,  2, unit_is_enabled   },
 
5638
                { "reenable",              MORE,  2, enable_unit       },
 
5639
                { "preset",                MORE,  2, enable_unit       },
 
5640
                { "mask",                  MORE,  2, enable_unit       },
 
5641
                { "unmask",                MORE,  2, enable_unit       },
 
5642
                { "link",                  MORE,  2, enable_unit       },
 
5643
                { "switch-root",           MORE,  2, switch_root       },
 
5644
                { "list-dependencies",     LESS,  2, list_dependencies },
 
5645
        };
 
5646
 
 
5647
        int left;
 
5648
        unsigned i;
 
5649
 
 
5650
        assert(argc >= 0);
 
5651
        assert(argv);
 
5652
        assert(error);
 
5653
 
 
5654
        left = argc - optind;
 
5655
 
 
5656
        if (left <= 0)
 
5657
                /* Special rule: no arguments means "list-units" */
 
5658
                i = 0;
 
5659
        else {
 
5660
                if (streq(argv[optind], "help") && !argv[optind+1]) {
 
5661
                        log_error("This command expects one or more "
 
5662
                                  "unit names. Did you mean --help?");
 
5663
                        return -EINVAL;
 
5664
                }
 
5665
 
 
5666
                for (i = 0; i < ELEMENTSOF(verbs); i++)
 
5667
                        if (streq(argv[optind], verbs[i].verb))
 
5668
                                break;
 
5669
 
 
5670
                if (i >= ELEMENTSOF(verbs)) {
 
5671
                        log_error("Unknown operation '%s'.", argv[optind]);
 
5672
                        return -EINVAL;
 
5673
                }
 
5674
        }
 
5675
 
 
5676
        switch (verbs[i].argc_cmp) {
 
5677
 
 
5678
        case EQUAL:
 
5679
                if (left != verbs[i].argc) {
 
5680
                        log_error("Invalid number of arguments.");
 
5681
                        return -EINVAL;
 
5682
                }
 
5683
 
 
5684
                break;
 
5685
 
 
5686
        case MORE:
 
5687
                if (left < verbs[i].argc) {
 
5688
                        log_error("Too few arguments.");
 
5689
                        return -EINVAL;
 
5690
                }
 
5691
 
 
5692
                break;
 
5693
 
 
5694
        case LESS:
 
5695
                if (left > verbs[i].argc) {
 
5696
                        log_error("Too many arguments.");
 
5697
                        return -EINVAL;
 
5698
                }
 
5699
 
 
5700
                break;
 
5701
 
 
5702
        default:
 
5703
                assert_not_reached("Unknown comparison operator.");
 
5704
        }
 
5705
 
 
5706
        /* Require a bus connection for all operations but
 
5707
         * enable/disable */
 
5708
        if (!streq(verbs[i].verb, "enable") &&
 
5709
            !streq(verbs[i].verb, "disable") &&
 
5710
            !streq(verbs[i].verb, "is-enabled") &&
 
5711
            !streq(verbs[i].verb, "list-unit-files") &&
 
5712
            !streq(verbs[i].verb, "reenable") &&
 
5713
            !streq(verbs[i].verb, "preset") &&
 
5714
            !streq(verbs[i].verb, "mask") &&
 
5715
            !streq(verbs[i].verb, "unmask") &&
 
5716
            !streq(verbs[i].verb, "link")) {
 
5717
 
 
5718
                if (running_in_chroot() > 0) {
 
5719
                        log_info("Running in chroot, ignoring request.");
 
5720
                        return 0;
 
5721
                }
 
5722
 
 
5723
                if (((!streq(verbs[i].verb, "reboot") &&
 
5724
                      !streq(verbs[i].verb, "halt") &&
 
5725
                      !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
 
5726
                        log_error("Failed to get D-Bus connection: %s",
 
5727
                                  dbus_error_is_set(error) ? error->message : "No connection to service manager.");
 
5728
                        return -EIO;
 
5729
                }
 
5730
 
 
5731
        } else {
 
5732
 
 
5733
                if (!bus && !avoid_bus()) {
 
5734
                        log_error("Failed to get D-Bus connection: %s",
 
5735
                                  dbus_error_is_set(error) ? error->message : "No connection to service manager.");
 
5736
                        return -EIO;
 
5737
                }
 
5738
        }
 
5739
 
 
5740
        return verbs[i].dispatch(bus, argv + optind);
 
5741
}
 
5742
 
 
5743
static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
 
5744
        _cleanup_close_ int fd;
 
5745
        struct sd_shutdown_command c = {
 
5746
                .usec = t,
 
5747
                .mode = mode,
 
5748
                .dry_run = dry_run,
 
5749
                .warn_wall = warn,
 
5750
        };
 
5751
        union sockaddr_union sockaddr = {
 
5752
                .un.sun_family = AF_UNIX,
 
5753
                .un.sun_path = "/run/systemd/shutdownd",
 
5754
        };
 
5755
        struct iovec iovec[2] = {
 
5756
                {.iov_base = (char*) &c,
 
5757
                 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
 
5758
                }
 
5759
        };
 
5760
        struct msghdr msghdr = {
 
5761
                .msg_name = &sockaddr,
 
5762
                .msg_namelen = offsetof(struct sockaddr_un, sun_path)
 
5763
                               + sizeof("/run/systemd/shutdownd") - 1,
 
5764
                .msg_iov = iovec,
 
5765
                .msg_iovlen = 1,
 
5766
        };
 
5767
 
 
5768
        fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
 
5769
        if (fd < 0)
 
5770
                return -errno;
 
5771
 
 
5772
        if (!isempty(message)) {
 
5773
                iovec[1].iov_base = (char*) message;
 
5774
                iovec[1].iov_len = strlen(message);
 
5775
                msghdr.msg_iovlen++;
 
5776
        }
 
5777
 
 
5778
        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
 
5779
                return -errno;
 
5780
 
 
5781
        return 0;
 
5782
}
 
5783
 
 
5784
static int reload_with_fallback(DBusConnection *bus) {
 
5785
 
 
5786
        if (bus) {
 
5787
                /* First, try systemd via D-Bus. */
 
5788
                if (daemon_reload(bus, NULL) >= 0)
 
5789
                        return 0;
 
5790
        }
 
5791
 
 
5792
        /* Nothing else worked, so let's try signals */
 
5793
        assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
 
5794
 
 
5795
        if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
 
5796
                log_error("kill() failed: %m");
 
5797
                return -errno;
 
5798
        }
 
5799
 
 
5800
        return 0;
 
5801
}
 
5802
 
 
5803
static int start_with_fallback(DBusConnection *bus) {
 
5804
 
 
5805
        if (bus) {
 
5806
                /* First, try systemd via D-Bus. */
 
5807
                if (start_unit(bus, NULL) >= 0)
 
5808
                        goto done;
 
5809
        }
 
5810
 
 
5811
        /* Hmm, talking to systemd via D-Bus didn't work. Then
 
5812
         * let's try to talk to Upstart via D-Bus. */
 
5813
        if (talk_upstart() > 0)
 
5814
                goto done;
 
5815
 
 
5816
        /* Nothing else worked, so let's try
 
5817
         * /dev/initctl */
 
5818
        if (talk_initctl() > 0)
 
5819
                goto done;
 
5820
 
 
5821
        log_error("Failed to talk to init daemon.");
 
5822
        return -EIO;
 
5823
 
 
5824
done:
 
5825
        warn_wall(arg_action);
 
5826
        return 0;
 
5827
}
 
5828
 
 
5829
static _noreturn_ void halt_now(enum action a) {
 
5830
 
 
5831
       /* Make sure C-A-D is handled by the kernel from this
 
5832
         * point on... */
 
5833
        reboot(RB_ENABLE_CAD);
 
5834
 
 
5835
        switch (a) {
 
5836
 
 
5837
        case ACTION_HALT:
 
5838
                log_info("Halting.");
 
5839
                reboot(RB_HALT_SYSTEM);
 
5840
                break;
 
5841
 
 
5842
        case ACTION_POWEROFF:
 
5843
                log_info("Powering off.");
 
5844
                reboot(RB_POWER_OFF);
 
5845
                break;
 
5846
 
 
5847
        case ACTION_REBOOT:
 
5848
                log_info("Rebooting.");
 
5849
                reboot(RB_AUTOBOOT);
 
5850
                break;
 
5851
 
 
5852
        default:
 
5853
                assert_not_reached("Unknown halt action.");
 
5854
        }
 
5855
 
 
5856
        assert_not_reached("Uh? This shouldn't happen.");
 
5857
}
 
5858
 
 
5859
static int halt_main(DBusConnection *bus) {
 
5860
        int r;
 
5861
 
 
5862
        r = check_inhibitors(bus, arg_action);
 
5863
        if (r < 0)
 
5864
                return r;
 
5865
 
 
5866
        if (geteuid() != 0) {
 
5867
                /* Try logind if we are a normal user and no special
 
5868
                 * mode applies. Maybe PolicyKit allows us to shutdown
 
5869
                 * the machine. */
 
5870
 
 
5871
                if (arg_when <= 0 &&
 
5872
                    !arg_dry &&
 
5873
                    arg_force <= 0 &&
 
5874
                    (arg_action == ACTION_POWEROFF ||
 
5875
                     arg_action == ACTION_REBOOT)) {
 
5876
                        r = reboot_with_logind(bus, arg_action);
 
5877
                        if (r >= 0)
 
5878
                                return r;
 
5879
                }
 
5880
 
 
5881
                log_error("Must be root.");
 
5882
                return -EPERM;
 
5883
        }
 
5884
 
 
5885
        if (arg_when > 0) {
 
5886
                _cleanup_free_ char *m;
 
5887
 
 
5888
                m = strv_join(arg_wall, " ");
 
5889
                r = send_shutdownd(arg_when,
 
5890
                                   arg_action == ACTION_HALT     ? 'H' :
 
5891
                                   arg_action == ACTION_POWEROFF ? 'P' :
 
5892
                                   arg_action == ACTION_KEXEC    ? 'K' :
 
5893
                                                                   'r',
 
5894
                                   arg_dry,
 
5895
                                   !arg_no_wall,
 
5896
                                   m);
 
5897
 
 
5898
                if (r < 0)
 
5899
                        log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
 
5900
                else {
 
5901
                        char date[FORMAT_TIMESTAMP_MAX];
 
5902
 
 
5903
                        log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
 
5904
                                 format_timestamp(date, sizeof(date), arg_when));
 
5905
                        return 0;
 
5906
                }
 
5907
        }
 
5908
 
 
5909
        if (!arg_dry && !arg_force)
 
5910
                return start_with_fallback(bus);
 
5911
 
 
5912
        if (!arg_no_wtmp) {
 
5913
                if (sd_booted() > 0)
 
5914
                        log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
 
5915
                else {
 
5916
                        r = utmp_put_shutdown();
 
5917
                        if (r < 0)
 
5918
                                log_warning("Failed to write utmp record: %s", strerror(-r));
 
5919
                }
 
5920
        }
 
5921
 
 
5922
        if (arg_dry)
 
5923
                return 0;
 
5924
 
 
5925
        halt_now(arg_action);
 
5926
        /* We should never reach this. */
 
5927
        return -ENOSYS;
 
5928
}
 
5929
 
 
5930
static int runlevel_main(void) {
 
5931
        int r, runlevel, previous;
 
5932
 
 
5933
        r = utmp_get_runlevel(&runlevel, &previous);
 
5934
        if (r < 0) {
 
5935
                puts("unknown");
 
5936
                return r;
 
5937
        }
 
5938
 
 
5939
        printf("%c %c\n",
 
5940
               previous <= 0 ? 'N' : previous,
 
5941
               runlevel <= 0 ? 'N' : runlevel);
 
5942
 
 
5943
        return 0;
 
5944
}
 
5945
 
 
5946
int main(int argc, char*argv[]) {
 
5947
        int r, retval = EXIT_FAILURE;
 
5948
        DBusConnection *bus = NULL;
 
5949
        _cleanup_dbus_error_free_ DBusError error;
 
5950
 
 
5951
        dbus_error_init(&error);
 
5952
 
 
5953
        setlocale(LC_ALL, "");
 
5954
        log_parse_environment();
 
5955
        log_open();
 
5956
 
 
5957
        r = parse_argv(argc, argv);
 
5958
        if (r < 0)
 
5959
                goto finish;
 
5960
        else if (r == 0) {
 
5961
                retval = EXIT_SUCCESS;
 
5962
                goto finish;
 
5963
        }
 
5964
 
 
5965
        /* /sbin/runlevel doesn't need to communicate via D-Bus, so
 
5966
         * let's shortcut this */
 
5967
        if (arg_action == ACTION_RUNLEVEL) {
 
5968
                r = runlevel_main();
 
5969
                retval = r < 0 ? EXIT_FAILURE : r;
 
5970
                goto finish;
 
5971
        }
 
5972
 
 
5973
        if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
 
5974
                log_info("Running in chroot, ignoring request.");
 
5975
                retval = 0;
 
5976
                goto finish;
 
5977
        }
 
5978
 
 
5979
        if (!avoid_bus()) {
 
5980
                if (arg_transport == TRANSPORT_NORMAL)
 
5981
                        bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
 
5982
                else if (arg_transport == TRANSPORT_POLKIT) {
 
5983
                        bus_connect_system_polkit(&bus, &error);
 
5984
                        private_bus = false;
 
5985
                } else if (arg_transport == TRANSPORT_SSH) {
 
5986
                        bus_connect_system_ssh(NULL, arg_host, &bus, &error);
 
5987
                        private_bus = false;
 
5988
                } else
 
5989
                        assert_not_reached("Uh, invalid transport...");
 
5990
        }
 
5991
 
 
5992
        switch (arg_action) {
 
5993
 
 
5994
        case ACTION_SYSTEMCTL:
 
5995
                r = systemctl_main(bus, argc, argv, &error);
 
5996
                break;
 
5997
 
 
5998
        case ACTION_HALT:
 
5999
        case ACTION_POWEROFF:
 
6000
        case ACTION_REBOOT:
 
6001
        case ACTION_KEXEC:
 
6002
                r = halt_main(bus);
 
6003
                break;
 
6004
 
 
6005
        case ACTION_RUNLEVEL2:
 
6006
        case ACTION_RUNLEVEL3:
 
6007
        case ACTION_RUNLEVEL4:
 
6008
        case ACTION_RUNLEVEL5:
 
6009
        case ACTION_RESCUE:
 
6010
        case ACTION_EMERGENCY:
 
6011
        case ACTION_DEFAULT:
 
6012
                r = start_with_fallback(bus);
 
6013
                break;
 
6014
 
 
6015
        case ACTION_RELOAD:
 
6016
        case ACTION_REEXEC:
 
6017
                r = reload_with_fallback(bus);
 
6018
                break;
 
6019
 
 
6020
        case ACTION_CANCEL_SHUTDOWN: {
 
6021
                char *m = NULL;
 
6022
 
 
6023
                if (arg_wall) {
 
6024
                        m = strv_join(arg_wall, " ");
 
6025
                        if (!m) {
 
6026
                                retval = EXIT_FAILURE;
 
6027
                                goto finish;
 
6028
                        }
 
6029
                }
 
6030
                r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
 
6031
                if (r < 0)
 
6032
                        log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
 
6033
                free(m);
 
6034
                break;
 
6035
        }
 
6036
 
 
6037
        case ACTION_INVALID:
 
6038
        case ACTION_RUNLEVEL:
 
6039
        default:
 
6040
                assert_not_reached("Unknown action");
 
6041
        }
 
6042
 
 
6043
        retval = r < 0 ? EXIT_FAILURE : r;
 
6044
 
 
6045
finish:
 
6046
        if (bus) {
 
6047
                dbus_connection_flush(bus);
 
6048
                dbus_connection_close(bus);
 
6049
                dbus_connection_unref(bus);
 
6050
        }
 
6051
 
 
6052
        dbus_shutdown();
 
6053
 
 
6054
        strv_free(arg_types);
 
6055
        strv_free(arg_load_states);
 
6056
        strv_free(arg_properties);
 
6057
 
 
6058
        pager_close();
 
6059
        ask_password_agent_close();
 
6060
        polkit_agent_close();
 
6061
 
 
6062
        return retval;
 
6063
}