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