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