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