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