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