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