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