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