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