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