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