]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
man: update mx record example (#4257)
[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))
a6405ca2 2723 log_error("See %s logs and 'systemctl%s status%s %s' for details.",
0b8505b7
RC
2724 arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
2725 arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
a6405ca2 2726 name[0] == '-' ? " --" : "",
0b8505b7 2727 name);
ee87525c
FB
2728
2729 return r;
7e4249b9
LP
2730 }
2731
f459b602
MAP
2732 r = sd_bus_message_read(reply, "o", &path);
2733 if (r < 0)
2734 return bus_log_parse_error(r);
45fb0699 2735
e3e0314b 2736 if (need_daemon_reload(bus, name) > 0)
3f36991e 2737 warn_unit_file_changed(name);
45fb0699 2738
ebd011d9
LP
2739 if (w) {
2740 log_debug("Adding %s to the set", path);
2741 r = bus_wait_for_jobs_add(w, path);
cbc9fbd1
LP
2742 if (r < 0)
2743 return log_oom();
e4b61340 2744 }
7e4249b9 2745
46eddbb5 2746 return 0;
7e4249b9
LP
2747}
2748
e3e0314b 2749static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
e3e0314b
ZJS
2750 _cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
2751 char **name;
7410616c 2752 int r, i;
e3e0314b 2753
4fbd7192
LP
2754 assert(bus);
2755 assert(ret);
2756
e3e0314b
ZJS
2757 STRV_FOREACH(name, names) {
2758 char *t;
2759
e80733be 2760 if (suffix)
7410616c 2761 r = unit_name_mangle_with_suffix(*name, UNIT_NAME_GLOB, suffix, &t);
e80733be 2762 else
7410616c
LP
2763 r = unit_name_mangle(*name, UNIT_NAME_GLOB, &t);
2764 if (r < 0)
2765 return log_error_errno(r, "Failed to mangle name: %m");
e3e0314b
ZJS
2766
2767 if (string_is_glob(t))
6e18964d 2768 r = strv_consume(&globs, t);
e3e0314b 2769 else
6e18964d
ZJS
2770 r = strv_consume(&mangled, t);
2771 if (r < 0)
e3e0314b 2772 return log_oom();
e3e0314b
ZJS
2773 }
2774
2775 /* Query the manager only if any of the names are a glob, since
2776 * this is fairly expensive */
2777 if (!strv_isempty(globs)) {
4afd3348 2778 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
e3e0314b 2779 _cleanup_free_ UnitInfo *unit_infos = NULL;
1b53f64b 2780 size_t allocated, n;
e3e0314b 2781
1238ee09 2782 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
e3e0314b
ZJS
2783 if (r < 0)
2784 return r;
2785
1b53f64b
LP
2786 n = strv_length(mangled);
2787 allocated = n + 1;
2788
2789 for (i = 0; i < r; i++) {
2790 if (!GREEDY_REALLOC(mangled, allocated, n+2))
2791 return log_oom();
2792
2793 mangled[n] = strdup(unit_infos[i].id);
2794 if (!mangled[n])
e3e0314b 2795 return log_oom();
1b53f64b
LP
2796
2797 mangled[++n] = NULL;
2798 }
e3e0314b
ZJS
2799 }
2800
2801 *ret = mangled;
2802 mangled = NULL; /* do not free */
1238ee09 2803
e3e0314b
ZJS
2804 return 0;
2805}
2806
47a0eaa6
MS
2807static const struct {
2808 const char *target;
2809 const char *verb;
2810 const char *mode;
2811} action_table[_ACTION_MAX] = {
2812 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
2813 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
2814 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
2815 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
d5d8429a
LP
2816 [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
2817 [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
2818 [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" },
2819 [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" },
47a0eaa6
MS
2820 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
2821 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
2822 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
2823 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
2824 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
2825 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
2826 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
2827};
2828
514f4ef5 2829static enum action verb_to_action(const char *verb) {
47a0eaa6
MS
2830 enum action i;
2831
f459b602
MAP
2832 for (i = _ACTION_INVALID; i < _ACTION_MAX; i++)
2833 if (streq_ptr(action_table[i].verb, verb))
47a0eaa6 2834 return i;
514f4ef5 2835
f459b602
MAP
2836 return _ACTION_INVALID;
2837}
e4b61340 2838
e449de87 2839static int start_unit(int argc, char *argv[], void *userdata) {
ebd011d9 2840 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
08073121 2841 const char *method, *mode, *one_name, *suffix = NULL;
ebd011d9 2842 _cleanup_strv_free_ char **names = NULL;
4fbd7192 2843 sd_bus *bus;
729e3769 2844 char **name;
b6520546 2845 int r = 0;
e4b61340 2846
4fbd7192
LP
2847 r = acquire_bus(BUS_MANAGER, &bus);
2848 if (r < 0)
2849 return r;
2850
d2ad7e1b
ZJS
2851 ask_password_agent_open_if_enabled();
2852 polkit_agent_open_if_enabled();
2853
e4b61340 2854 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 2855 enum action action;
e4b61340 2856
e449de87
LP
2857 method = verb_to_method(argv[0]);
2858 action = verb_to_action(argv[0]);
2859
2860 if (streq(argv[0], "isolate")) {
08073121
LP
2861 mode = "isolate";
2862 suffix = ".target";
2863 } else
2864 mode = action_table[action].mode ?: arg_job_mode;
e4b61340 2865
e3e0314b 2866 one_name = action_table[action].target;
e4b61340 2867 } else {
47a0eaa6
MS
2868 assert(arg_action < ELEMENTSOF(action_table));
2869 assert(action_table[arg_action].target);
e4b61340
LP
2870
2871 method = "StartUnit";
514f4ef5 2872
47a0eaa6 2873 mode = action_table[arg_action].mode;
e3e0314b 2874 one_name = action_table[arg_action].target;
514f4ef5
LP
2875 }
2876
e3e0314b
ZJS
2877 if (one_name)
2878 names = strv_new(one_name, NULL);
2879 else {
e449de87 2880 r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
e3e0314b 2881 if (r < 0)
691395d8 2882 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b 2883 }
b6520546 2884
6e905d93 2885 if (!arg_no_block) {
ebd011d9 2886 r = bus_wait_for_jobs_new(bus, &w);
f647962d
MS
2887 if (r < 0)
2888 return log_error_errno(r, "Could not watch jobs: %m");
e4b61340
LP
2889 }
2890
b6520546 2891 STRV_FOREACH(name, names) {
4afd3348 2892 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
b6520546 2893 int q;
f459b602 2894
ebd011d9 2895 q = start_unit_one(bus, method, *name, mode, &error, w);
e3e0314b 2896 if (r >= 0 && q < 0)
b6520546 2897 r = translate_bus_error_to_exit_status(q, &error);
e4b61340
LP
2898 }
2899
67f3c402 2900 if (!arg_no_block) {
c11bda1e
ZJS
2901 int q, arg_count = 0;
2902 const char* extra_args[4] = {};
4524439e 2903
4524439e
ZJS
2904 if (arg_scope != UNIT_FILE_SYSTEM)
2905 extra_args[arg_count++] = "--user";
2906
2907 assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
2908 if (arg_transport == BUS_TRANSPORT_REMOTE) {
2909 extra_args[arg_count++] = "-H";
2910 extra_args[arg_count++] = arg_host;
2911 } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
2912 extra_args[arg_count++] = "-M";
2913 extra_args[arg_count++] = arg_host;
2914 }
f459b602 2915
4524439e 2916 q = bus_wait_for_jobs(w, arg_quiet, extra_args);
f459b602
MAP
2917 if (q < 0)
2918 return q;
49111a70
ZJS
2919
2920 /* When stopping units, warn if they can still be triggered by
2921 * another active unit (socket, path, timer) */
b6520546
ZJS
2922 if (!arg_quiet && streq(method, "StopUnit"))
2923 STRV_FOREACH(name, names)
2924 check_triggering_units(bus, *name);
67f3c402 2925 }
514f4ef5 2926
f459b602 2927 return r;
e4b61340
LP
2928}
2929
4fbd7192 2930static int logind_set_wall_message(void) {
f2d11d35 2931#ifdef HAVE_LOGIND
4afd3348 2932 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 2933 sd_bus *bus;
f2d11d35
LP
2934 _cleanup_free_ char *m = NULL;
2935 int r;
2936
4fbd7192
LP
2937 r = acquire_bus(BUS_FULL, &bus);
2938 if (r < 0)
2939 return r;
f2d11d35
LP
2940
2941 m = strv_join(arg_wall, " ");
2942 if (!m)
2943 return log_oom();
2944
2945 r = sd_bus_call_method(
2946 bus,
2947 "org.freedesktop.login1",
2948 "/org/freedesktop/login1",
2949 "org.freedesktop.login1.Manager",
2950 "SetWallMessage",
2951 &error,
2952 NULL,
2953 "sb",
2954 m,
2955 !arg_no_wall);
2956
2957 if (r < 0)
2958 return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
2959
2960#endif
2961 return 0;
2962}
2963
7e59bfcb
LP
2964/* Ask systemd-logind, which might grant access to unprivileged users
2965 * through PolicyKit */
4fbd7192 2966static int logind_reboot(enum action a) {
4c80c73c 2967#ifdef HAVE_LOGIND
4afd3348 2968 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
58158dc7 2969 const char *method, *description;
4fbd7192 2970 sd_bus *bus;
f459b602 2971 int r;
4c80c73c 2972
4fbd7192
LP
2973 r = acquire_bus(BUS_FULL, &bus);
2974 if (r < 0)
2975 return r;
f2d11d35 2976
4c80c73c
KS
2977 switch (a) {
2978
2979 case ACTION_REBOOT:
2980 method = "Reboot";
58158dc7 2981 description = "reboot system";
4c80c73c
KS
2982 break;
2983
2984 case ACTION_POWEROFF:
2985 method = "PowerOff";
58158dc7 2986 description = "power off system";
4c80c73c
KS
2987 break;
2988
d889a206
LP
2989 case ACTION_SUSPEND:
2990 method = "Suspend";
58158dc7 2991 description = "suspend system";
d889a206
LP
2992 break;
2993
2994 case ACTION_HIBERNATE:
2995 method = "Hibernate";
58158dc7 2996 description = "hibernate system";
d889a206
LP
2997 break;
2998
6524990f
LP
2999 case ACTION_HYBRID_SLEEP:
3000 method = "HybridSleep";
58158dc7 3001 description = "put system into hybrid sleep";
6524990f
LP
3002 break;
3003
4c80c73c
KS
3004 default:
3005 return -EINVAL;
3006 }
3007
d2ad7e1b
ZJS
3008 polkit_agent_open_if_enabled();
3009 (void) logind_set_wall_message();
3010
f459b602 3011 r = sd_bus_call_method(
f22f08cd
SP
3012 bus,
3013 "org.freedesktop.login1",
3014 "/org/freedesktop/login1",
3015 "org.freedesktop.login1.Manager",
3016 method,
f459b602 3017 &error,
f22f08cd 3018 NULL,
342641fb 3019 "b", arg_ask_password);
f459b602 3020 if (r < 0)
691395d8 3021 return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
f459b602 3022
691395d8 3023 return 0;
4c80c73c
KS
3024#else
3025 return -ENOSYS;
3026#endif
3027}
3028
4fbd7192 3029static int logind_check_inhibitors(enum action a) {
b37844d3 3030#ifdef HAVE_LOGIND
4afd3348 3031 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
59164be4 3032 _cleanup_strv_free_ char **sessions = NULL;
f459b602
MAP
3033 const char *what, *who, *why, *mode;
3034 uint32_t uid, pid;
4fbd7192 3035 sd_bus *bus;
f459b602 3036 unsigned c = 0;
59164be4 3037 char **s;
f459b602 3038 int r;
b37844d3 3039
748ebafa
LP
3040 if (arg_ignore_inhibitors || arg_force > 0)
3041 return 0;
3042
3043 if (arg_when > 0)
3044 return 0;
3045
3046 if (geteuid() == 0)
b37844d3
LP
3047 return 0;
3048
3049 if (!on_tty())
3050 return 0;
e08ab379
LP
3051
3052 if (arg_transport != BUS_TRANSPORT_LOCAL)
3053 return 0;
b37844d3 3054
4fbd7192
LP
3055 r = acquire_bus(BUS_FULL, &bus);
3056 if (r < 0)
3057 return r;
3058
f459b602 3059 r = sd_bus_call_method(
b37844d3
LP
3060 bus,
3061 "org.freedesktop.login1",
3062 "/org/freedesktop/login1",
3063 "org.freedesktop.login1.Manager",
3064 "ListInhibitors",
b37844d3 3065 NULL,
f459b602
MAP
3066 &reply,
3067 NULL);
b37844d3
LP
3068 if (r < 0)
3069 /* If logind is not around, then there are no inhibitors... */
3070 return 0;
3071
4aa2beac 3072 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
f459b602
MAP
3073 if (r < 0)
3074 return bus_log_parse_error(r);
b37844d3 3075
4aa2beac 3076 while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
59164be4 3077 _cleanup_free_ char *comm = NULL, *user = NULL;
f459b602 3078 _cleanup_strv_free_ char **sv = NULL;
b37844d3
LP
3079
3080 if (!streq(mode, "block"))
f459b602 3081 continue;
b37844d3
LP
3082
3083 sv = strv_split(what, ":");
3084 if (!sv)
3085 return log_oom();
3086
d028e018
ZJS
3087 if ((pid_t) pid < 0)
3088 return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
3089
b37844d3 3090 if (!strv_contains(sv,
4c315c2c
IS
3091 IN_SET(a,
3092 ACTION_HALT,
3093 ACTION_POWEROFF,
3094 ACTION_REBOOT,
3095 ACTION_KEXEC) ? "shutdown" : "sleep"))
f459b602 3096 continue;
b37844d3
LP
3097
3098 get_process_comm(pid, &comm);
59164be4 3099 user = uid_to_name(uid);
f459b602 3100
de0671ee 3101 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
d028e018 3102 who, (pid_t) pid, strna(comm), strna(user), why);
b37844d3 3103
f459b602 3104 c++;
b37844d3 3105 }
f459b602
MAP
3106 if (r < 0)
3107 return bus_log_parse_error(r);
b37844d3 3108
f459b602
MAP
3109 r = sd_bus_message_exit_container(reply);
3110 if (r < 0)
3111 return bus_log_parse_error(r);
b37844d3 3112
59164be4
LP
3113 /* Check for current sessions */
3114 sd_get_sessions(&sessions);
3115 STRV_FOREACH(s, sessions) {
59164be4
LP
3116 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
3117
3118 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
3119 continue;
3120
3121 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
3122 continue;
3123
72240b52 3124 if (sd_session_get_type(*s, &type) < 0 || !STR_IN_SET(type, "x11", "tty"))
59164be4
LP
3125 continue;
3126
3127 sd_session_get_tty(*s, &tty);
3128 sd_session_get_seat(*s, &seat);
3129 sd_session_get_service(*s, &service);
3130 user = uid_to_name(uid);
3131
3132 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
3133 c++;
3134 }
3135
b37844d3
LP
3136 if (c <= 0)
3137 return 0;
3138
59164be4 3139 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 3140 action_table[a].verb);
b37844d3
LP
3141
3142 return -EPERM;
3143#else
3144 return 0;
3145#endif
3146}
3147
4fbd7192 3148static int logind_prepare_firmware_setup(void) {
a4921cf4 3149#ifdef HAVE_LOGIND
4afd3348 3150 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 3151 sd_bus *bus;
a4921cf4
JJ
3152 int r;
3153
4fbd7192
LP
3154 r = acquire_bus(BUS_FULL, &bus);
3155 if (r < 0)
3156 return r;
a4921cf4 3157
a4921cf4
JJ
3158 r = sd_bus_call_method(
3159 bus,
3160 "org.freedesktop.login1",
3161 "/org/freedesktop/login1",
3162 "org.freedesktop.login1.Manager",
3163 "SetRebootToFirmwareSetup",
3164 &error,
3165 NULL,
3166 "b", true);
4fbd7192
LP
3167 if (r < 0)
3168 return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
a4921cf4
JJ
3169
3170 return 0;
3171#else
3172 log_error("Cannot remotely indicate to EFI to boot into setup mode.");
4fbd7192 3173 return -ENOSYS;
a4921cf4
JJ
3174#endif
3175}
3176
4fbd7192
LP
3177static int prepare_firmware_setup(void) {
3178 int r;
3179
3180 if (!arg_firmware_setup)
3181 return 0;
3182
3183 if (arg_transport == BUS_TRANSPORT_LOCAL) {
3184
3185 r = efi_set_reboot_to_firmware(true);
3186 if (r < 0)
3187 log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
3188 else
3189 return r;
3190 }
3191
3192 return logind_prepare_firmware_setup();
3193}
3194
57ab9006 3195static int set_exit_code(uint8_t code) {
4afd3348 3196 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
57ab9006
LP
3197 sd_bus *bus;
3198 int r;
3199
3200 r = acquire_bus(BUS_MANAGER, &bus);
3201 if (r < 0)
3202 return r;
3203
3204 r = sd_bus_call_method(
3205 bus,
3206 "org.freedesktop.systemd1",
3207 "/org/freedesktop/systemd1",
3208 "org.freedesktop.systemd1.Manager",
3209 "SetExitCode",
3210 &error,
3211 NULL,
3212 "y", code);
3213 if (r < 0)
af3d8113 3214 return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
57ab9006
LP
3215
3216 return 0;
3217}
3218
e449de87 3219static int start_special(int argc, char *argv[], void *userdata) {
4c80c73c 3220 enum action a;
983d9c90
LP
3221 int r;
3222
e449de87 3223 assert(argv);
514f4ef5 3224
e449de87 3225 a = verb_to_action(argv[0]);
4c80c73c 3226
4fbd7192 3227 r = logind_check_inhibitors(a);
748ebafa
LP
3228 if (r < 0)
3229 return r;
3230
c32b90de
LP
3231 if (arg_force >= 2 && geteuid() != 0) {
3232 log_error("Must be root.");
3233 return -EPERM;
3234 }
3235
4fbd7192 3236 r = prepare_firmware_setup();
a4921cf4
JJ
3237 if (r < 0)
3238 return r;
5bdf2243 3239
e449de87 3240 if (a == ACTION_REBOOT && argc > 1) {
27c06cb5 3241 r = update_reboot_parameter_and_warn(argv[1]);
b986229e
SW
3242 if (r < 0)
3243 return r;
57ab9006 3244
e449de87 3245 } else if (a == ACTION_EXIT && argc > 1) {
7bbb5359 3246 uint8_t code;
287419c1 3247
57ab9006
LP
3248 /* If the exit code is not given on the command line,
3249 * don't reset it to zero: just keep it as it might
3250 * have been set previously. */
287419c1 3251
e449de87 3252 r = safe_atou8(argv[1], &code);
4fbd7192 3253 if (r < 0)
57ab9006 3254 return log_error_errno(r, "Invalid exit code.");
4fbd7192 3255
57ab9006 3256 r = set_exit_code(code);
691395d8 3257 if (r < 0)
57ab9006 3258 return r;
b986229e
SW
3259 }
3260
7e59bfcb 3261 if (arg_force >= 2 &&
4c315c2c
IS
3262 IN_SET(a,
3263 ACTION_HALT,
3264 ACTION_POWEROFF,
3265 ACTION_REBOOT))
477def80 3266 return halt_now(a);
e606bb61 3267
7e59bfcb 3268 if (arg_force >= 1 &&
4c315c2c
IS
3269 IN_SET(a,
3270 ACTION_HALT,
3271 ACTION_POWEROFF,
3272 ACTION_REBOOT,
3273 ACTION_KEXEC,
3274 ACTION_EXIT))
2853b60a 3275 return trivial_method(argc, argv, userdata);
20b09ca7 3276
7089051f
LP
3277 /* First try logind, to allow authentication with polkit */
3278 if (IN_SET(a,
4c315c2c
IS
3279 ACTION_POWEROFF,
3280 ACTION_REBOOT,
3281 ACTION_SUSPEND,
3282 ACTION_HIBERNATE,
3283 ACTION_HYBRID_SLEEP)) {
4fbd7192 3284 r = logind_reboot(a);
a9085ea3 3285 if (r >= 0)
7e59bfcb 3286 return r;
a9085ea3
IS
3287 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
3288 /* requested operation is not supported or already in progress */
3289 return r;
7089051f
LP
3290
3291 /* On all other errors, try low-level operation */
4c80c73c 3292 }
983d9c90 3293
e449de87 3294 return start_unit(argc, argv, userdata);
514f4ef5
LP
3295}
3296
988b3b17
ZJS
3297static int start_system_special(int argc, char *argv[], void *userdata) {
3298 /* Like start_special above, but raises an error when running in user mode */
3299
3300 if (arg_scope != UNIT_FILE_SYSTEM) {
3301 log_error("Bad action for %s mode.",
3302 arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
3303 return -EINVAL;
3304 }
3305
3306 return start_special(argc, argv, userdata);
3307}
3308
fa0d5878 3309static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
e3e0314b 3310 _cleanup_strv_free_ char **names = NULL;
fa0d5878 3311 UnitActiveState active_state;
4fbd7192 3312 sd_bus *bus;
729e3769 3313 char **name;
fa0d5878 3314 int r, i;
d60f6ad0 3315 bool found = false;
0183528f 3316
4fbd7192
LP
3317 r = acquire_bus(BUS_MANAGER, &bus);
3318 if (r < 0)
3319 return r;
3320
e3e0314b 3321 r = expand_names(bus, args, NULL, &names);
f647962d
MS
3322 if (r < 0)
3323 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
3324
3325 STRV_FOREACH(name, names) {
fa0d5878
BR
3326 r = get_state_one_unit(bus, *name, &active_state);
3327 if (r < 0)
3328 return r;
3329
3330 if (!arg_quiet)
3331 puts(unit_active_state_to_string(active_state));
60f9ba0b 3332
fa0d5878
BR
3333 for (i = 0; i < nb_states; ++i)
3334 if (good_states[i] == active_state)
3335 found = true;
1a0fce45
TA
3336 }
3337
d60f6ad0
LN
3338 /* use the given return code for the case that we won't find
3339 * any unit which matches the list */
3340 return found ? 0 : code;
1a0fce45
TA
3341}
3342
e449de87 3343static int check_unit_active(int argc, char *argv[], void *userdata) {
fa0d5878 3344 const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING };
e3e0314b 3345 /* According to LSB: 3, "program is not running" */
b613907e 3346 return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
e3e0314b 3347}
0183528f 3348
e449de87 3349static int check_unit_failed(int argc, char *argv[], void *userdata) {
fa0d5878 3350 const UnitActiveState states[] = { UNIT_FAILED };
b613907e 3351 return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
48220598
LP
3352}
3353
e449de87 3354static int kill_unit(int argc, char *argv[], void *userdata) {
e3e0314b 3355 _cleanup_strv_free_ char **names = NULL;
ac5e3a50 3356 char *kill_who = NULL, **name;
4fbd7192 3357 sd_bus *bus;
e3e0314b 3358 int r, q;
8a0867d6 3359
4fbd7192
LP
3360 r = acquire_bus(BUS_MANAGER, &bus);
3361 if (r < 0)
3362 return r;
3363
d2ad7e1b
ZJS
3364 polkit_agent_open_if_enabled();
3365
8a0867d6
LP
3366 if (!arg_kill_who)
3367 arg_kill_who = "all";
3368
ac5e3a50
JS
3369 /* --fail was specified */
3370 if (streq(arg_job_mode, "fail"))
81d62103 3371 kill_who = strjoina(arg_kill_who, "-fail");
ac5e3a50 3372
e449de87 3373 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 3374 if (r < 0)
691395d8 3375 return log_error_errno(r, "Failed to expand names: %m");
60f9ba0b 3376
e3e0314b 3377 STRV_FOREACH(name, names) {
4afd3348 3378 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 3379
6e646d22 3380 q = sd_bus_call_method(
f22f08cd 3381 bus,
b0193f1c
LP
3382 "org.freedesktop.systemd1",
3383 "/org/freedesktop/systemd1",
3384 "org.freedesktop.systemd1.Manager",
6e646d22
LP
3385 "KillUnit",
3386 &error,
3387 NULL,
169d7fb6 3388 "ssi", *name, kill_who ? kill_who : arg_kill_who, arg_signal);
e3e0314b 3389 if (q < 0) {
169d7fb6 3390 log_error_errno(q, "Failed to kill unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
3391 if (r == 0)
3392 r = q;
f459b602 3393 }
8a0867d6 3394 }
f459b602 3395
e3e0314b 3396 return r;
8a0867d6
LP
3397}
3398
582a507f 3399typedef struct ExecStatusInfo {
0129173a
LP
3400 char *name;
3401
582a507f
LP
3402 char *path;
3403 char **argv;
3404
b708e7ce
LP
3405 bool ignore;
3406
582a507f
LP
3407 usec_t start_timestamp;
3408 usec_t exit_timestamp;
3409 pid_t pid;
3410 int code;
3411 int status;
3412
3413 LIST_FIELDS(struct ExecStatusInfo, exec);
3414} ExecStatusInfo;
3415
3416static void exec_status_info_free(ExecStatusInfo *i) {
3417 assert(i);
3418
0129173a 3419 free(i->name);
582a507f
LP
3420 free(i->path);
3421 strv_free(i->argv);
3422 free(i);
3423}
3424
f459b602 3425static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
b21a0ef8 3426 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
f459b602 3427 const char *path;
582a507f
LP
3428 uint32_t pid;
3429 int32_t code, status;
f459b602 3430 int ignore, r;
582a507f 3431
f459b602 3432 assert(m);
582a507f 3433 assert(i);
582a507f 3434
f459b602
MAP
3435 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, "sasbttttuii");
3436 if (r < 0)
3437 return bus_log_parse_error(r);
3438 else if (r == 0)
3439 return 0;
582a507f 3440
f459b602
MAP
3441 r = sd_bus_message_read(m, "s", &path);
3442 if (r < 0)
3443 return bus_log_parse_error(r);
582a507f 3444
f84190d8
LP
3445 i->path = strdup(path);
3446 if (!i->path)
f459b602 3447 return log_oom();
582a507f 3448
f459b602
MAP
3449 r = sd_bus_message_read_strv(m, &i->argv);
3450 if (r < 0)
3451 return bus_log_parse_error(r);
3452
3453 r = sd_bus_message_read(m,
3454 "bttttuii",
3455 &ignore,
3456 &start_timestamp, &start_timestamp_monotonic,
3457 &exit_timestamp, &exit_timestamp_monotonic,
3458 &pid,
3459 &code, &status);
3460 if (r < 0)
3461 return bus_log_parse_error(r);
582a507f 3462
b708e7ce 3463 i->ignore = ignore;
582a507f
LP
3464 i->start_timestamp = (usec_t) start_timestamp;
3465 i->exit_timestamp = (usec_t) exit_timestamp;
3466 i->pid = (pid_t) pid;
3467 i->code = code;
3468 i->status = status;
3469
f459b602
MAP
3470 r = sd_bus_message_exit_container(m);
3471 if (r < 0)
3472 return bus_log_parse_error(r);
3473
3474 return 1;
582a507f
LP
3475}
3476
d5db7fe6
WC
3477typedef struct UnitCondition {
3478 char *name;
b1ed76ae 3479 char *param;
d5db7fe6
WC
3480 bool trigger;
3481 bool negate;
d5db7fe6
WC
3482 int tristate;
3483
b1ed76ae 3484 LIST_FIELDS(struct UnitCondition, conditions);
d5db7fe6
WC
3485} UnitCondition;
3486
3487static void unit_condition_free(UnitCondition *c) {
9bb71940
ZJS
3488 if (!c)
3489 return;
d5db7fe6
WC
3490
3491 free(c->name);
3492 free(c->param);
3493 free(c);
3494}
3495
9bb71940
ZJS
3496DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
3497
61cbdc4b
LP
3498typedef struct UnitStatusInfo {
3499 const char *id;
3500 const char *load_state;
3501 const char *active_state;
3502 const char *sub_state;
a4375746 3503 const char *unit_file_state;
d2dc52db 3504 const char *unit_file_preset;
61cbdc4b
LP
3505
3506 const char *description;
4a9e2fff 3507 const char *following;
61cbdc4b 3508
49dbfa7b
LP
3509 char **documentation;
3510
1b64d026
LP
3511 const char *fragment_path;
3512 const char *source_path;
4ad49000 3513 const char *control_group;
61cbdc4b 3514
76d14b87
OS
3515 char **dropin_paths;
3516
9f39404c 3517 const char *load_error;
f42806df 3518 const char *result;
9f39404c 3519
584be568 3520 usec_t inactive_exit_timestamp;
df50185b 3521 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
3522 usec_t active_enter_timestamp;
3523 usec_t active_exit_timestamp;
3524 usec_t inactive_enter_timestamp;
3525
45fb0699 3526 bool need_daemon_reload;
055ef36b 3527 bool transient;
45fb0699 3528
61cbdc4b
LP
3529 /* Service */
3530 pid_t main_pid;
3531 pid_t control_pid;
3532 const char *status_text;
175728c4 3533 const char *pid_file;
d06dacd0 3534 bool running:1;
b4af5a80 3535 int status_errno;
61cbdc4b
LP
3536
3537 usec_t start_timestamp;
3538 usec_t exit_timestamp;
3539
3540 int exit_code, exit_status;
3541
90bbc946
LP
3542 usec_t condition_timestamp;
3543 bool condition_result;
b1ed76ae 3544 LIST_HEAD(UnitCondition, conditions);
59fccdc5
LP
3545
3546 usec_t assert_timestamp;
3547 bool assert_result;
3548 bool failed_assert_trigger;
3549 bool failed_assert_negate;
3550 const char *failed_assert;
3551 const char *failed_assert_parameter;
90bbc946 3552
61cbdc4b
LP
3553 /* Socket */
3554 unsigned n_accepted;
3555 unsigned n_connections;
b8131a87 3556 bool accept;
61cbdc4b 3557
13160134 3558 /* Pairs of type, path */
67419600
OS
3559 char **listen;
3560
61cbdc4b
LP
3561 /* Device */
3562 const char *sysfs_path;
3563
3564 /* Mount, Automount */
3565 const char *where;
3566
3567 /* Swap */
3568 const char *what;
582a507f 3569
934277fe
LP
3570 /* CGroup */
3571 uint64_t memory_current;
da4d897e
TH
3572 uint64_t memory_low;
3573 uint64_t memory_high;
3574 uint64_t memory_max;
96e131ea 3575 uint64_t memory_swap_max;
934277fe 3576 uint64_t memory_limit;
5ad096b3 3577 uint64_t cpu_usage_nsec;
03a7b521
LP
3578 uint64_t tasks_current;
3579 uint64_t tasks_max;
934277fe 3580
582a507f 3581 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
3582} UnitStatusInfo;
3583
a7335518
ZJS
3584static void unit_status_info_free(UnitStatusInfo *info) {
3585 ExecStatusInfo *p;
3586 UnitCondition *c;
3587
3588 strv_free(info->documentation);
3589 strv_free(info->dropin_paths);
3590 strv_free(info->listen);
3591
3592 while ((c = info->conditions)) {
3593 LIST_REMOVE(conditions, info->conditions, c);
3594 unit_condition_free(c);
3595 }
3596
3597 while ((p = info->exec)) {
3598 LIST_REMOVE(exec, info->exec, p);
3599 exec_status_info_free(p);
3600 }
3601}
3602
f459b602 3603static void print_status_info(
291d565a 3604 sd_bus *bus,
f459b602
MAP
3605 UnitStatusInfo *i,
3606 bool *ellipsized) {
3607
582a507f 3608 ExecStatusInfo *p;
b0d14c69 3609 const char *active_on, *active_off, *on, *off, *ss;
584be568 3610 usec_t timestamp;
9185c8e6 3611 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 3612 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 3613 const char *path;
13160134 3614 char **t, **t2;
291d565a 3615 int r;
582a507f 3616
61cbdc4b
LP
3617 assert(i);
3618
3619 /* This shows pretty information about a unit. See
3620 * print_property() for a low-level property printer */
3621
b0d14c69
LP
3622 if (streq_ptr(i->active_state, "failed")) {
3623 active_on = ansi_highlight_red();
1fc464f6 3624 active_off = ansi_normal();
1cf03a4f 3625 } else if (STRPTR_IN_SET(i->active_state, "active", "reloading")) {
b0d14c69 3626 active_on = ansi_highlight_green();
1fc464f6 3627 active_off = ansi_normal();
b0d14c69
LP
3628 } else
3629 active_on = active_off = "";
3630
323b7dc9 3631 printf("%s%s%s %s", active_on, special_glyph(BLACK_CIRCLE), active_off, strna(i->id));
61cbdc4b
LP
3632
3633 if (i->description && !streq_ptr(i->id, i->description))
3634 printf(" - %s", i->description);
3635
3636 printf("\n");
3637
4a9e2fff 3638 if (i->following)
856323c9 3639 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 3640
f7b9e331 3641 if (streq_ptr(i->load_state, "error")) {
0b5a519c 3642 on = ansi_highlight_red();
1fc464f6 3643 off = ansi_normal();
c31b4423
LP
3644 } else
3645 on = off = "";
3646
1b64d026
LP
3647 path = i->source_path ? i->source_path : i->fragment_path;
3648
055ef36b 3649 if (i->load_error != 0)
856323c9
ZJS
3650 printf(" Loaded: %s%s%s (Reason: %s)\n",
3651 on, strna(i->load_state), off, i->load_error);
d2dc52db
LP
3652 else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset))
3653 printf(" Loaded: %s%s%s (%s; %s; vendor preset: %s)\n",
3654 on, strna(i->load_state), off, path, i->unit_file_state, i->unit_file_preset);
3655 else if (path && !isempty(i->unit_file_state))
856323c9
ZJS
3656 printf(" Loaded: %s%s%s (%s; %s)\n",
3657 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 3658 else if (path)
856323c9
ZJS
3659 printf(" Loaded: %s%s%s (%s)\n",
3660 on, strna(i->load_state), off, path);
61cbdc4b 3661 else
856323c9
ZJS
3662 printf(" Loaded: %s%s%s\n",
3663 on, strna(i->load_state), off);
61cbdc4b 3664
055ef36b
LP
3665 if (i->transient)
3666 printf("Transient: yes\n");
3667
76d14b87 3668 if (!strv_isempty(i->dropin_paths)) {
f459b602 3669 _cleanup_free_ char *dir = NULL;
76d14b87 3670 bool last = false;
f459b602 3671 char ** dropin;
76d14b87
OS
3672
3673 STRV_FOREACH(dropin, i->dropin_paths) {
3674 if (! dir || last) {
856323c9 3675 printf(dir ? " " : " Drop-In: ");
76d14b87 3676
97b11eed 3677 dir = mfree(dir);
76d14b87 3678
5f311f8c
LP
3679 dir = dirname_malloc(*dropin);
3680 if (!dir) {
76d14b87
OS
3681 log_oom();
3682 return;
3683 }
3684
856323c9 3685 printf("%s\n %s", dir,
323b7dc9 3686 special_glyph(TREE_RIGHT));
76d14b87
OS
3687 }
3688
3689 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
3690
2b6bf07d 3691 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 3692 }
76d14b87
OS
3693 }
3694
2ee68f72 3695 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 3696 if (ss)
856323c9 3697 printf(" Active: %s%s (%s)%s",
b0d14c69 3698 active_on, strna(i->active_state), ss, active_off);
2ee68f72 3699 else
856323c9 3700 printf(" Active: %s%s%s",
b0d14c69 3701 active_on, strna(i->active_state), active_off);
61cbdc4b 3702
f42806df
LP
3703 if (!isempty(i->result) && !streq(i->result, "success"))
3704 printf(" (Result: %s)", i->result);
3705
1cf03a4f
ZJS
3706 timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
3707 STRPTR_IN_SET(i->active_state, "inactive", "failed") ? i->inactive_enter_timestamp :
3708 STRPTR_IN_SET(i->active_state, "activating") ? i->inactive_exit_timestamp :
3709 i->active_exit_timestamp;
584be568 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
96e131ea
WC
3886 if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX ||
3887 i->memory_max != CGROUP_LIMIT_MAX || i->memory_swap_max != CGROUP_LIMIT_MAX ||
da4d897e
TH
3888 i->memory_limit != CGROUP_LIMIT_MAX) {
3889 const char *prefix = "";
3890
3891 printf(" (");
3892 if (i->memory_low > 0) {
3893 printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low));
3894 prefix = " ";
3895 }
3896 if (i->memory_high != CGROUP_LIMIT_MAX) {
3897 printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
3898 prefix = " ";
3899 }
3900 if (i->memory_max != CGROUP_LIMIT_MAX) {
3901 printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
3902 prefix = " ";
3903 }
96e131ea
WC
3904 if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
3905 printf("%sswap max: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_swap_max));
3906 prefix = " ";
3907 }
da4d897e
TH
3908 if (i->memory_limit != CGROUP_LIMIT_MAX) {
3909 printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
3910 prefix = " ";
3911 }
3912 printf(")");
3913 }
3914 printf("\n");
934277fe
LP
3915 }
3916
5ad096b3
LP
3917 if (i->cpu_usage_nsec != (uint64_t) -1) {
3918 char buf[FORMAT_TIMESPAN_MAX];
3919 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
3920 }
3921
51e22f88 3922 if (i->control_group) {
291d565a
LP
3923 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3924 static const char prefix[] = " ";
ab35fb1b
LP
3925 unsigned c;
3926
51e22f88
LP
3927 printf(" CGroup: %s\n", i->control_group);
3928
291d565a
LP
3929 c = columns();
3930 if (c > sizeof(prefix) - 1)
3931 c -= sizeof(prefix) - 1;
3932 else
3933 c = 0;
ab35fb1b 3934
291d565a
LP
3935 r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
3936 if (r == -EBADR) {
b69d29ce
LP
3937 unsigned k = 0;
3938 pid_t extra[2];
3939
291d565a 3940 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
ab35fb1b 3941
b69d29ce
LP
3942 if (i->main_pid > 0)
3943 extra[k++] = i->main_pid;
3944
3945 if (i->control_pid > 0)
3946 extra[k++] = i->control_pid;
3947
0ff308c8 3948 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
291d565a
LP
3949 } else if (r < 0)
3950 log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r));
c59760ee 3951 }
45fb0699 3952
ece174c5 3953 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
3c756001
LP
3954 show_journal_by_unit(
3955 stdout,
3956 i->id,
3957 arg_output,
3958 0,
3959 i->inactive_exit_timestamp_monotonic,
3960 arg_lines,
3961 getuid(),
3962 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
3963 SD_JOURNAL_LOCAL_ONLY,
3964 arg_scope == UNIT_FILE_SYSTEM,
3965 ellipsized);
86aa7ba4 3966
45fb0699 3967 if (i->need_daemon_reload)
3f36991e 3968 warn_unit_file_changed(i->id);
61cbdc4b
LP
3969}
3970
b43f208f 3971static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
3972 char **p;
3973
3974 assert(i);
3975
3976 if (!i->documentation) {
3977 log_info("Documentation for %s not known.", i->id);
3978 return;
3979 }
3980
78002a67
ZJS
3981 STRV_FOREACH(p, i->documentation)
3982 if (startswith(*p, "man:"))
3983 show_man_page(*p + 4, false);
3984 else
0315fe37 3985 log_info("Can't show: %s", *p);
256425cc
LP
3986}
3987
f459b602
MAP
3988static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
3989 int r;
61cbdc4b 3990
a4c279f8 3991 assert(name);
f459b602 3992 assert(m);
a4c279f8
LP
3993 assert(i);
3994
f459b602 3995 switch (contents[0]) {
61cbdc4b 3996
f459b602 3997 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
3998 const char *s;
3999
f459b602
MAP
4000 r = sd_bus_message_read(m, "s", &s);
4001 if (r < 0)
4002 return bus_log_parse_error(r);
61cbdc4b 4003
37a0d5bf 4004 if (!isempty(s)) {
61cbdc4b
LP
4005 if (streq(name, "Id"))
4006 i->id = s;
4007 else if (streq(name, "LoadState"))
4008 i->load_state = s;
4009 else if (streq(name, "ActiveState"))
4010 i->active_state = s;
4011 else if (streq(name, "SubState"))
4012 i->sub_state = s;
4013 else if (streq(name, "Description"))
4014 i->description = s;
4015 else if (streq(name, "FragmentPath"))
1b64d026
LP
4016 i->fragment_path = s;
4017 else if (streq(name, "SourcePath"))
4018 i->source_path = s;
286ca485 4019#ifndef NOLEGACY
a00963a2
LP
4020 else if (streq(name, "DefaultControlGroup")) {
4021 const char *e;
4022 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
4023 if (e)
4024 i->control_group = e;
4025 }
4ad49000 4026#endif
37a0d5bf
LP
4027 else if (streq(name, "ControlGroup"))
4028 i->control_group = s;
61cbdc4b
LP
4029 else if (streq(name, "StatusText"))
4030 i->status_text = s;
175728c4
HH
4031 else if (streq(name, "PIDFile"))
4032 i->pid_file = s;
61cbdc4b
LP
4033 else if (streq(name, "SysFSPath"))
4034 i->sysfs_path = s;
4035 else if (streq(name, "Where"))
4036 i->where = s;
4037 else if (streq(name, "What"))
4038 i->what = s;
4a9e2fff
LP
4039 else if (streq(name, "Following"))
4040 i->following = s;
a4375746
LP
4041 else if (streq(name, "UnitFileState"))
4042 i->unit_file_state = s;
d2dc52db
LP
4043 else if (streq(name, "UnitFilePreset"))
4044 i->unit_file_preset = s;
f42806df
LP
4045 else if (streq(name, "Result"))
4046 i->result = s;
61cbdc4b
LP
4047 }
4048
4049 break;
4050 }
4051
f459b602
MAP
4052 case SD_BUS_TYPE_BOOLEAN: {
4053 int b;
b8131a87 4054
f459b602
MAP
4055 r = sd_bus_message_read(m, "b", &b);
4056 if (r < 0)
4057 return bus_log_parse_error(r);
b8131a87
LP
4058
4059 if (streq(name, "Accept"))
4060 i->accept = b;
45fb0699
LP
4061 else if (streq(name, "NeedDaemonReload"))
4062 i->need_daemon_reload = b;
90bbc946
LP
4063 else if (streq(name, "ConditionResult"))
4064 i->condition_result = b;
59fccdc5
LP
4065 else if (streq(name, "AssertResult"))
4066 i->assert_result = b;
055ef36b
LP
4067 else if (streq(name, "Transient"))
4068 i->transient = b;
b8131a87
LP
4069
4070 break;
4071 }
4072
f459b602 4073 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
4074 uint32_t u;
4075
f459b602
MAP
4076 r = sd_bus_message_read(m, "u", &u);
4077 if (r < 0)
4078 return bus_log_parse_error(r);
61cbdc4b
LP
4079
4080 if (streq(name, "MainPID")) {
4081 if (u > 0) {
4082 i->main_pid = (pid_t) u;
4083 i->running = true;
4084 }
4085 } else if (streq(name, "ControlPID"))
4086 i->control_pid = (pid_t) u;
4087 else if (streq(name, "ExecMainPID")) {
4088 if (u > 0)
4089 i->main_pid = (pid_t) u;
4090 } else if (streq(name, "NAccepted"))
4091 i->n_accepted = u;
4092 else if (streq(name, "NConnections"))
4093 i->n_connections = u;
4094
4095 break;
4096 }
4097
f459b602 4098 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
4099 int32_t j;
4100
f459b602
MAP
4101 r = sd_bus_message_read(m, "i", &j);
4102 if (r < 0)
4103 return bus_log_parse_error(r);
61cbdc4b
LP
4104
4105 if (streq(name, "ExecMainCode"))
4106 i->exit_code = (int) j;
4107 else if (streq(name, "ExecMainStatus"))
4108 i->exit_status = (int) j;
b4af5a80
LP
4109 else if (streq(name, "StatusErrno"))
4110 i->status_errno = (int) j;
61cbdc4b
LP
4111
4112 break;
4113 }
4114
f459b602 4115 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
4116 uint64_t u;
4117
f459b602
MAP
4118 r = sd_bus_message_read(m, "t", &u);
4119 if (r < 0)
4120 return bus_log_parse_error(r);
61cbdc4b
LP
4121
4122 if (streq(name, "ExecMainStartTimestamp"))
4123 i->start_timestamp = (usec_t) u;
4124 else if (streq(name, "ExecMainExitTimestamp"))
4125 i->exit_timestamp = (usec_t) u;
584be568
LP
4126 else if (streq(name, "ActiveEnterTimestamp"))
4127 i->active_enter_timestamp = (usec_t) u;
4128 else if (streq(name, "InactiveEnterTimestamp"))
4129 i->inactive_enter_timestamp = (usec_t) u;
4130 else if (streq(name, "InactiveExitTimestamp"))
4131 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
4132 else if (streq(name, "InactiveExitTimestampMonotonic"))
4133 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
4134 else if (streq(name, "ActiveExitTimestamp"))
4135 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
4136 else if (streq(name, "ConditionTimestamp"))
4137 i->condition_timestamp = (usec_t) u;
59fccdc5
LP
4138 else if (streq(name, "AssertTimestamp"))
4139 i->assert_timestamp = (usec_t) u;
934277fe
LP
4140 else if (streq(name, "MemoryCurrent"))
4141 i->memory_current = u;
da4d897e
TH
4142 else if (streq(name, "MemoryLow"))
4143 i->memory_low = u;
4144 else if (streq(name, "MemoryHigh"))
4145 i->memory_high = u;
4146 else if (streq(name, "MemoryMax"))
4147 i->memory_max = u;
96e131ea
WC
4148 else if (streq(name, "MemorySwapMax"))
4149 i->memory_swap_max = u;
934277fe
LP
4150 else if (streq(name, "MemoryLimit"))
4151 i->memory_limit = u;
03a7b521
LP
4152 else if (streq(name, "TasksCurrent"))
4153 i->tasks_current = u;
4154 else if (streq(name, "TasksMax"))
4155 i->tasks_max = u;
5ad096b3
LP
4156 else if (streq(name, "CPUUsageNSec"))
4157 i->cpu_usage_nsec = u;
61cbdc4b
LP
4158
4159 break;
4160 }
582a507f 4161
f459b602 4162 case SD_BUS_TYPE_ARRAY:
582a507f 4163
f459b602
MAP
4164 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4165 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 4166
f459b602
MAP
4167 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4168 if (r < 0)
4169 return bus_log_parse_error(r);
582a507f 4170
f459b602
MAP
4171 info = new0(ExecStatusInfo, 1);
4172 if (!info)
4173 return log_oom();
582a507f 4174
f459b602 4175 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 4176
f459b602
MAP
4177 info->name = strdup(name);
4178 if (!info->name)
691395d8 4179 return log_oom();
582a507f 4180
71fda00f 4181 LIST_PREPEND(exec, i->exec, info);
582a507f 4182
f459b602
MAP
4183 info = new0(ExecStatusInfo, 1);
4184 if (!info)
691395d8 4185 return log_oom();
49dbfa7b 4186 }
67419600 4187
f459b602
MAP
4188 if (r < 0)
4189 return bus_log_parse_error(r);
67419600 4190
f459b602
MAP
4191 r = sd_bus_message_exit_container(m);
4192 if (r < 0)
4193 return bus_log_parse_error(r);
67419600 4194
f459b602 4195 return 0;
67419600 4196
f459b602
MAP
4197 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4198 const char *type, *path;
13160134 4199
f459b602
MAP
4200 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4201 if (r < 0)
4202 return bus_log_parse_error(r);
67419600 4203
f459b602 4204 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 4205
f459b602
MAP
4206 r = strv_extend(&i->listen, type);
4207 if (r < 0)
4208 return r;
67419600 4209
f459b602
MAP
4210 r = strv_extend(&i->listen, path);
4211 if (r < 0)
4212 return r;
4213 }
76d14b87 4214 if (r < 0)
f459b602 4215 return bus_log_parse_error(r);
76d14b87 4216
f459b602
MAP
4217 r = sd_bus_message_exit_container(m);
4218 if (r < 0)
4219 return bus_log_parse_error(r);
49dbfa7b 4220
f459b602 4221 return 0;
49dbfa7b 4222
f459b602 4223 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 4224
f459b602
MAP
4225 r = sd_bus_message_read_strv(m, &i->dropin_paths);
4226 if (r < 0)
4227 return bus_log_parse_error(r);
49dbfa7b 4228
f459b602 4229 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 4230
f459b602
MAP
4231 r = sd_bus_message_read_strv(m, &i->documentation);
4232 if (r < 0)
4233 return bus_log_parse_error(r);
52990c2e 4234
f459b602
MAP
4235 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
4236 const char *cond, *param;
4237 int trigger, negate;
4238 int32_t state;
52990c2e 4239
f459b602
MAP
4240 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4241 if (r < 0)
4242 return bus_log_parse_error(r);
4243
4244 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
9bb71940 4245 _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
d5db7fe6 4246
b1ed76ae 4247 log_debug("%s trigger=%d negate=%d %s →%d", cond, trigger, negate, param, state);
d5db7fe6
WC
4248
4249 c = new0(UnitCondition, 1);
4250 if (!c)
4251 return log_oom();
4252
4253 c->name = strdup(cond);
d5db7fe6 4254 c->param = strdup(param);
9bb71940 4255 if (!c->name || !c->param)
d5db7fe6 4256 return log_oom();
d5db7fe6
WC
4257
4258 c->trigger = trigger;
4259 c->negate = negate;
4260 c->tristate = state;
4261
b1ed76ae 4262 LIST_PREPEND(conditions, i->conditions, c);
9bb71940 4263 c = NULL;
59fccdc5
LP
4264 }
4265 if (r < 0)
4266 return bus_log_parse_error(r);
4267
4268 r = sd_bus_message_exit_container(m);
4269 if (r < 0)
4270 return bus_log_parse_error(r);
4271
4272 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) {
4273 const char *cond, *param;
4274 int trigger, negate;
4275 int32_t state;
4276
4277 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
4278 if (r < 0)
4279 return bus_log_parse_error(r);
4280
4281 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
4282 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
4283 if (state < 0 && (!trigger || !i->failed_assert)) {
4284 i->failed_assert = cond;
4285 i->failed_assert_trigger = trigger;
4286 i->failed_assert_negate = negate;
4287 i->failed_assert_parameter = param;
f459b602 4288 }
582a507f 4289 }
f459b602
MAP
4290 if (r < 0)
4291 return bus_log_parse_error(r);
4292
4293 r = sd_bus_message_exit_container(m);
4294 if (r < 0)
4295 return bus_log_parse_error(r);
4296
4297 } else
4298 goto skip;
582a507f
LP
4299
4300 break;
9f39404c 4301
f459b602 4302 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
4303
4304 if (streq(name, "LoadError")) {
9f39404c 4305 const char *n, *message;
9f39404c 4306
f459b602 4307 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 4308 if (r < 0)
f459b602 4309 return bus_log_parse_error(r);
9f39404c
LP
4310
4311 if (!isempty(message))
4312 i->load_error = message;
f459b602
MAP
4313 } else
4314 goto skip;
9f39404c
LP
4315
4316 break;
f459b602
MAP
4317
4318 default:
4319 goto skip;
9f39404c 4320 }
f459b602
MAP
4321
4322 return 0;
4323
4324skip:
4325 r = sd_bus_message_skip(m, contents);
4326 if (r < 0)
4327 return bus_log_parse_error(r);
61cbdc4b
LP
4328
4329 return 0;
4330}
4331
4f9a9105
ZJS
4332#define print_prop(name, fmt, ...) \
4333 do { \
4334 if (arg_value) \
4335 printf(fmt "\n", __VA_ARGS__); \
4336 else \
4337 printf("%s=" fmt "\n", name, __VA_ARGS__); \
4338 } while(0)
4339
f459b602
MAP
4340static int print_property(const char *name, sd_bus_message *m, const char *contents) {
4341 int r;
4342
48220598 4343 assert(name);
f459b602 4344 assert(m);
48220598 4345
61cbdc4b
LP
4346 /* This is a low-level property printer, see
4347 * print_status_info() for the nicer output */
4348
852c1b4d
ZJS
4349 if (arg_properties && !strv_find(arg_properties, name)) {
4350 /* skip what we didn't read */
4351 r = sd_bus_message_skip(m, contents);
4352 return r;
4353 }
48220598 4354
f459b602 4355 switch (contents[0]) {
48220598 4356
f459b602 4357 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 4358
f459b602 4359 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
4360 uint32_t u;
4361
f459b602
MAP
4362 r = sd_bus_message_read(m, "(uo)", &u, NULL);
4363 if (r < 0)
4364 return bus_log_parse_error(r);
48220598 4365
f459b602 4366 if (u > 0)
4f9a9105 4367 print_prop(name, "%"PRIu32, u);
48220598 4368 else if (arg_all)
4f9a9105 4369 print_prop(name, "%s", "");
48220598
LP
4370
4371 return 0;
f459b602
MAP
4372
4373 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
4374 const char *s;
4375
f459b602
MAP
4376 r = sd_bus_message_read(m, "(so)", &s, NULL);
4377 if (r < 0)
4378 return bus_log_parse_error(r);
48220598 4379
f459b602 4380 if (arg_all || !isempty(s))
4f9a9105 4381 print_prop(name, "%s", s);
48220598
LP
4382
4383 return 0;
f459b602
MAP
4384
4385 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
4386 const char *a = NULL, *b = NULL;
4387
f459b602
MAP
4388 r = sd_bus_message_read(m, "(ss)", &a, &b);
4389 if (r < 0)
4390 return bus_log_parse_error(r);
9f39404c
LP
4391
4392 if (arg_all || !isempty(a) || !isempty(b))
4f9a9105 4393 print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
f786e80d 4394
57183d11
LP
4395 return 0;
4396 } else if (streq_ptr(name, "SystemCallFilter")) {
4397 _cleanup_strv_free_ char **l = NULL;
4398 int whitelist;
4399
4400 r = sd_bus_message_enter_container(m, 'r', "bas");
4401 if (r < 0)
4402 return bus_log_parse_error(r);
4403
4404 r = sd_bus_message_read(m, "b", &whitelist);
4405 if (r < 0)
4406 return bus_log_parse_error(r);
4407
4408 r = sd_bus_message_read_strv(m, &l);
4409 if (r < 0)
4410 return bus_log_parse_error(r);
4411
4412 r = sd_bus_message_exit_container(m);
4413 if (r < 0)
4414 return bus_log_parse_error(r);
4415
4416 if (arg_all || whitelist || !strv_isempty(l)) {
4417 bool first = true;
4418 char **i;
4419
4f9a9105
ZJS
4420 if (!arg_value) {
4421 fputs(name, stdout);
4422 fputc('=', stdout);
4423 }
57183d11
LP
4424
4425 if (!whitelist)
4426 fputc('~', stdout);
4427
4428 STRV_FOREACH(i, l) {
4429 if (first)
4430 first = false;
4431 else
4432 fputc(' ', stdout);
4433
4434 fputs(*i, stdout);
4435 }
4436 fputc('\n', stdout);
4437 }
4438
f786e80d 4439 return 0;
48220598
LP
4440 }
4441
4442 break;
48220598 4443
f459b602 4444 case SD_BUS_TYPE_ARRAY:
48220598 4445
f459b602
MAP
4446 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
4447 const char *path;
4448 int ignore;
8c7be95e 4449
f459b602
MAP
4450 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
4451 if (r < 0)
4452 return bus_log_parse_error(r);
8c7be95e 4453
f459b602 4454 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
a1abf5ea 4455 print_prop("EnvironmentFile", "%s (ignore_errors=%s)", path, yes_no(ignore));
8c7be95e 4456
f459b602
MAP
4457 if (r < 0)
4458 return bus_log_parse_error(r);
8c7be95e 4459
f459b602
MAP
4460 r = sd_bus_message_exit_container(m);
4461 if (r < 0)
4462 return bus_log_parse_error(r);
8c7be95e
LP
4463
4464 return 0;
4465
f459b602
MAP
4466 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
4467 const char *type, *path;
67419600 4468
f459b602
MAP
4469 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4470 if (r < 0)
4471 return bus_log_parse_error(r);
ebf57b80 4472
f459b602 4473 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4f9a9105 4474 print_prop(type, "%s", path);
f459b602
MAP
4475 if (r < 0)
4476 return bus_log_parse_error(r);
ebf57b80 4477
f459b602
MAP
4478 r = sd_bus_message_exit_container(m);
4479 if (r < 0)
4480 return bus_log_parse_error(r);
ebf57b80 4481
707e5e52 4482 return 0;
582a507f 4483
f459b602
MAP
4484 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4485 const char *type, *path;
67419600 4486
f459b602
MAP
4487 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4488 if (r < 0)
4489 return bus_log_parse_error(r);
67419600 4490
f459b602 4491 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4f9a9105
ZJS
4492 if (arg_value)
4493 puts(path);
4494 else
4495 printf("Listen%s=%s\n", type, path);
f459b602
MAP
4496 if (r < 0)
4497 return bus_log_parse_error(r);
67419600 4498
f459b602
MAP
4499 r = sd_bus_message_exit_container(m);
4500 if (r < 0)
4501 return bus_log_parse_error(r);
67419600
OS
4502
4503 return 0;
4504
f459b602
MAP
4505 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) {
4506 const char *base;
4507 uint64_t value, next_elapse;
707e5e52 4508
f459b602
MAP
4509 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
4510 if (r < 0)
4511 return bus_log_parse_error(r);
552e4331 4512
f459b602
MAP
4513 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
4514 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4515
4f9a9105
ZJS
4516 print_prop(base, "{ value=%s ; next_elapse=%s }",
4517 format_timespan(timespan1, sizeof(timespan1), value, 0),
4518 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4519 }
f459b602
MAP
4520 if (r < 0)
4521 return bus_log_parse_error(r);
4522
4523 r = sd_bus_message_exit_container(m);
4524 if (r < 0)
4525 return bus_log_parse_error(r);
fe68089d
LP
4526
4527 return 0;
fe68089d 4528
f459b602
MAP
4529 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4530 ExecStatusInfo info = {};
4531
4532 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4533 if (r < 0)
4534 return bus_log_parse_error(r);
4535
4536 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4537 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4538 _cleanup_free_ char *tt;
4539
4540 tt = strv_join(info.argv, " ");
4541
4f9a9105
ZJS
4542 print_prop(name,
4543 "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
4544 strna(info.path),
4545 strna(tt),
4546 yes_no(info.ignore),
4547 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4548 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
4549 info.pid,
4550 sigchld_code_to_string(info.code),
4551 info.status,
4552 info.code == CLD_EXITED ? "" : "/",
4553 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4554
582a507f
LP
4555 free(info.path);
4556 strv_free(info.argv);
f459b602 4557 zero(info);
707e5e52
LP
4558 }
4559
f459b602
MAP
4560 r = sd_bus_message_exit_container(m);
4561 if (r < 0)
4562 return bus_log_parse_error(r);
4563
48220598 4564 return 0;
4ad49000 4565
f459b602
MAP
4566 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
4567 const char *path, *rwm;
4ad49000 4568
f459b602
MAP
4569 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4570 if (r < 0)
4571 return bus_log_parse_error(r);
4ad49000 4572
f459b602 4573 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4f9a9105 4574 print_prop(name, "%s %s", strna(path), strna(rwm));
f459b602
MAP
4575 if (r < 0)
4576 return bus_log_parse_error(r);
4ad49000 4577
f459b602
MAP
4578 r = sd_bus_message_exit_container(m);
4579 if (r < 0)
4580 return bus_log_parse_error(r);
4ad49000 4581
4ad49000
LP
4582 return 0;
4583
72240b52
ZJS
4584 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN &&
4585 STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
f459b602
MAP
4586 const char *path;
4587 uint64_t weight;
b8ab2dc6 4588
f459b602
MAP
4589 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4590 if (r < 0)
4591 return bus_log_parse_error(r);
b8ab2dc6 4592
f459b602 4593 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4f9a9105 4594 print_prop(name, "%s %"PRIu64, strna(path), weight);
f459b602
MAP
4595 if (r < 0)
4596 return bus_log_parse_error(r);
b8ab2dc6 4597
f459b602
MAP
4598 r = sd_bus_message_exit_container(m);
4599 if (r < 0)
4600 return bus_log_parse_error(r);
b8ab2dc6 4601
b8ab2dc6
G
4602 return 0;
4603
72240b52
ZJS
4604 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN &&
4605 (cgroup_io_limit_type_from_string(name) >= 0 ||
4606 STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
f459b602
MAP
4607 const char *path;
4608 uint64_t bandwidth;
4ad49000 4609
f459b602
MAP
4610 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4611 if (r < 0)
4612 return bus_log_parse_error(r);
4ad49000 4613
f459b602 4614 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4f9a9105 4615 print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
f459b602
MAP
4616 if (r < 0)
4617 return bus_log_parse_error(r);
4ad49000 4618
f459b602
MAP
4619 r = sd_bus_message_exit_container(m);
4620 if (r < 0)
4621 return bus_log_parse_error(r);
4ad49000 4622
4ad49000 4623 return 0;
48220598
LP
4624 }
4625
4626 break;
4627 }
4628
4f9a9105 4629 r = bus_print_property(name, m, arg_value, arg_all);
f459b602
MAP
4630 if (r < 0)
4631 return bus_log_parse_error(r);
4632
4633 if (r == 0) {
4634 r = sd_bus_message_skip(m, contents);
4635 if (r < 0)
4636 return bus_log_parse_error(r);
a4c279f8 4637
f459b602
MAP
4638 if (arg_all)
4639 printf("%s=[unprintable]\n", name);
4640 }
48220598
LP
4641
4642 return 0;
4643}
4644
f459b602
MAP
4645static int show_one(
4646 const char *verb,
4647 sd_bus *bus,
4648 const char *path,
3dced37b 4649 const char *unit,
f459b602
MAP
4650 bool show_properties,
4651 bool *new_line,
4652 bool *ellipsized) {
4653
3dced37b 4654 static const struct bus_properties_map property_map[] = {
662bea67
ZJS
4655 { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
4656 { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state) },
3dced37b
LP
4657 {}
4658 };
4659
4afd3348
LP
4660 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4661 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3dced37b 4662 _cleanup_set_free_ Set *found_properties = NULL;
a7335518 4663 _cleanup_(unit_status_info_free) UnitStatusInfo info = {
934277fe 4664 .memory_current = (uint64_t) -1,
da4d897e
TH
4665 .memory_high = CGROUP_LIMIT_MAX,
4666 .memory_max = CGROUP_LIMIT_MAX,
96e131ea 4667 .memory_swap_max = CGROUP_LIMIT_MAX,
934277fe 4668 .memory_limit = (uint64_t) -1,
5ad096b3 4669 .cpu_usage_nsec = (uint64_t) -1,
03a7b521
LP
4670 .tasks_current = (uint64_t) -1,
4671 .tasks_max = (uint64_t) -1,
934277fe 4672 };
f459b602 4673 int r;
48220598 4674
48220598 4675 assert(path);
61cbdc4b 4676 assert(new_line);
48220598 4677
e3e0314b
ZJS
4678 log_debug("Showing one %s", path);
4679
f459b602 4680 r = sd_bus_call_method(
f22f08cd
SP
4681 bus,
4682 "org.freedesktop.systemd1",
4683 path,
4684 "org.freedesktop.DBus.Properties",
4685 "GetAll",
f459b602 4686 &error,
f22f08cd 4687 &reply,
f459b602 4688 "s", "");
4c3e8e39
LP
4689 if (r < 0)
4690 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
48220598 4691
3dced37b
LP
4692 if (unit) {
4693 r = bus_message_map_all_properties(reply, property_map, &info);
4694 if (r < 0)
4695 return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
e33a06a1 4696
3dced37b 4697 if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
bd5b9f0a
ZJS
4698 log_full(streq(verb, "status") ? LOG_ERR : LOG_DEBUG,
4699 "Unit %s could not be found.", unit);
e33a06a1 4700
3dced37b
LP
4701 if (streq(verb, "status"))
4702 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
4703
bd5b9f0a
ZJS
4704 if (!streq(verb, "show"))
4705 return -ENOENT;
3dced37b
LP
4706 }
4707
4708 r = sd_bus_message_rewind(reply, true);
4709 if (r < 0)
4710 return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
4711 }
e33a06a1 4712
f459b602
MAP
4713 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
4714 if (r < 0)
4715 return bus_log_parse_error(r);
48220598 4716
61cbdc4b
LP
4717 if (*new_line)
4718 printf("\n");
4719
4720 *new_line = true;
4721
f459b602
MAP
4722 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
4723 const char *name, *contents;
0183528f 4724
f459b602
MAP
4725 r = sd_bus_message_read(reply, "s", &name);
4726 if (r < 0)
4727 return bus_log_parse_error(r);
48220598 4728
f459b602
MAP
4729 r = sd_bus_message_peek_type(reply, NULL, &contents);
4730 if (r < 0)
4731 return bus_log_parse_error(r);
4732
4733 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
4734 if (r < 0)
4735 return bus_log_parse_error(r);
48220598 4736
3dced37b
LP
4737 if (show_properties) {
4738 r = set_ensure_allocated(&found_properties, &string_hash_ops);
4739 if (r < 0)
4740 return log_oom();
4741
4742 r = set_put(found_properties, name);
4743 if (r < 0 && r != EEXIST)
4744 return log_oom();
4745
f459b602 4746 r = print_property(name, reply, contents);
3dced37b 4747 } else
f459b602
MAP
4748 r = status_property(name, reply, &info, contents);
4749 if (r < 0)
4750 return r;
48220598 4751
f459b602
MAP
4752 r = sd_bus_message_exit_container(reply);
4753 if (r < 0)
4754 return bus_log_parse_error(r);
4755
4756 r = sd_bus_message_exit_container(reply);
4757 if (r < 0)
4758 return bus_log_parse_error(r);
48220598 4759 }
f459b602
MAP
4760 if (r < 0)
4761 return bus_log_parse_error(r);
4762
4763 r = sd_bus_message_exit_container(reply);
4764 if (r < 0)
4765 return bus_log_parse_error(r);
48220598 4766
f1e36d67 4767 r = 0;
3dced37b
LP
4768 if (show_properties) {
4769 char **pp;
bd5b9f0a 4770 int not_found_level = streq(verb, "show") ? LOG_DEBUG : LOG_WARNING;
3dced37b 4771
a7335518 4772 STRV_FOREACH(pp, arg_properties)
3dced37b 4773 if (!set_contains(found_properties, *pp)) {
bd5b9f0a 4774 log_full(not_found_level, "Property %s does not exist.", *pp);
3dced37b
LP
4775 r = -ENXIO;
4776 }
a7335518 4777
3dced37b
LP
4778 } else if (streq(verb, "help"))
4779 show_unit_help(&info);
4780 else if (streq(verb, "status")) {
4781 print_status_info(bus, &info, ellipsized);
4782
7f5da8bd 4783 if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
3dced37b 4784 r = EXIT_PROGRAM_NOT_RUNNING;
256425cc 4785 else
3dced37b 4786 r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
256425cc 4787 }
f1e36d67 4788
48220598
LP
4789 return r;
4790}
4791
f74294c1 4792static int get_unit_dbus_path_by_pid(
f459b602
MAP
4793 sd_bus *bus,
4794 uint32_t pid,
f74294c1 4795 char **unit) {
f459b602 4796
4afd3348
LP
4797 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4798 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
373d32c9 4799 char *u;
a223b325
MS
4800 int r;
4801
f459b602 4802 r = sd_bus_call_method(
f22f08cd
SP
4803 bus,
4804 "org.freedesktop.systemd1",
4805 "/org/freedesktop/systemd1",
4806 "org.freedesktop.systemd1.Manager",
4807 "GetUnitByPID",
f459b602 4808 &error,
f22f08cd 4809 &reply,
f459b602 4810 "u", pid);
691395d8
LP
4811 if (r < 0)
4812 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
a223b325 4813
373d32c9 4814 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
4815 if (r < 0)
4816 return bus_log_parse_error(r);
4817
373d32c9
LP
4818 u = strdup(u);
4819 if (!u)
4820 return log_oom();
4821
4822 *unit = u;
f74294c1 4823 return 0;
a223b325
MS
4824}
4825
f459b602
MAP
4826static int show_all(
4827 const char* verb,
4828 sd_bus *bus,
4829 bool show_properties,
4830 bool *new_line,
4831 bool *ellipsized) {
4832
4afd3348 4833 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602
MAP
4834 _cleanup_free_ UnitInfo *unit_infos = NULL;
4835 const UnitInfo *u;
4836 unsigned c;
5bb75bc7 4837 int r, ret = 0;
265a7a2a 4838
1238ee09 4839 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
4840 if (r < 0)
4841 return r;
4842
ea4b98e6 4843 pager_open(arg_no_pager, false);
dbed408b 4844
f459b602
MAP
4845 c = (unsigned) r;
4846
4847 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 4848
265a7a2a 4849 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 4850 _cleanup_free_ char *p = NULL;
265a7a2a 4851
265a7a2a
ZJS
4852 p = unit_dbus_path_from_name(u->id);
4853 if (!p)
4854 return log_oom();
4855
3dced37b 4856 r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized);
3df538da 4857 if (r < 0)
265a7a2a 4858 return r;
5bb75bc7
ZJS
4859 else if (r > 0 && ret == 0)
4860 ret = r;
265a7a2a
ZJS
4861 }
4862
5bb75bc7 4863 return ret;
265a7a2a
ZJS
4864}
4865
8fcf784d
LP
4866static int show_system_status(sd_bus *bus) {
4867 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
4868 _cleanup_free_ char *hn = NULL;
e7e55dbd 4869 _cleanup_(machine_info_clear) struct machine_info mi = {};
8fcf784d
LP
4870 const char *on, *off;
4871 int r;
4872
4873 hn = gethostname_malloc();
4874 if (!hn)
4875 return log_oom();
4876
4877 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
f647962d
MS
4878 if (r < 0)
4879 return log_error_errno(r, "Failed to read server status: %m");
8fcf784d 4880
8fcf784d
LP
4881 if (streq_ptr(mi.state, "degraded")) {
4882 on = ansi_highlight_red();
1fc464f6 4883 off = ansi_normal();
8fcf784d
LP
4884 } else if (!streq_ptr(mi.state, "running")) {
4885 on = ansi_highlight_yellow();
1fc464f6 4886 off = ansi_normal();
8fcf784d
LP
4887 } else
4888 on = off = "";
4889
323b7dc9 4890 printf("%s%s%s %s\n", on, special_glyph(BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 4891
8fcf784d
LP
4892 printf(" State: %s%s%s\n",
4893 on, strna(mi.state), off);
4894
c6ba5b80
MP
4895 printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs);
4896 printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
8fcf784d
LP
4897
4898 printf(" Since: %s; %s\n",
4899 format_timestamp(since2, sizeof(since2), mi.timestamp),
4900 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
4901
4902 printf(" CGroup: %s\n", mi.control_group ?: "/");
4c315c2c
IS
4903 if (IN_SET(arg_transport,
4904 BUS_TRANSPORT_LOCAL,
4905 BUS_TRANSPORT_MACHINE)) {
8fcf784d
LP
4906 static const char prefix[] = " ";
4907 unsigned c;
4908
4909 c = columns();
4910 if (c > sizeof(prefix) - 1)
4911 c -= sizeof(prefix) - 1;
4912 else
4913 c = 0;
4914
0ff308c8 4915 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
8fcf784d
LP
4916 }
4917
8fcf784d
LP
4918 return 0;
4919}
4920
e449de87
LP
4921static int show(int argc, char *argv[], void *userdata) {
4922 bool show_properties, show_status, show_help, new_line = false;
94e0bd7d 4923 bool ellipsized = false;
e3e0314b 4924 int r, ret = 0;
4fbd7192 4925 sd_bus *bus;
48220598 4926
e449de87 4927 assert(argv);
48220598 4928
e449de87
LP
4929 show_properties = streq(argv[0], "show");
4930 show_status = streq(argv[0], "status");
4931 show_help = streq(argv[0], "help");
4932
4933 if (show_help && argc <= 1) {
4934 log_error("This command expects one or more unit names. Did you mean --help?");
4935 return -EINVAL;
4936 }
61cbdc4b 4937
d2ad7e1b
ZJS
4938 r = acquire_bus(BUS_MANAGER, &bus);
4939 if (r < 0)
4940 return r;
4941
ea4b98e6 4942 pager_open(arg_no_pager, false);
ec14911e 4943
40acc203
ZJS
4944 if (show_status)
4945 /* Increase max number of open files to 16K if we can, we
4946 * might needs this when browsing journal files, which might
4947 * be split up into many files. */
4948 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
4949
4fbd7192 4950 /* If no argument is specified inspect the manager itself */
e449de87 4951 if (show_properties && argc <= 1)
3dced37b 4952 return show_one(argv[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized);
48220598 4953
e449de87 4954 if (show_status && argc <= 1) {
8fcf784d 4955
8fcf784d
LP
4956 show_system_status(bus);
4957 new_line = true;
4958
4959 if (arg_all)
e449de87 4960 ret = show_all(argv[0], bus, false, &new_line, &ellipsized);
8fcf784d 4961 } else {
e3e0314b
ZJS
4962 _cleanup_free_ char **patterns = NULL;
4963 char **name;
4964
e449de87 4965 STRV_FOREACH(name, strv_skip(argv, 1)) {
3dced37b 4966 _cleanup_free_ char *path = NULL, *unit = NULL;
94e0bd7d 4967 uint32_t id;
48220598 4968
94e0bd7d 4969 if (safe_atou32(*name, &id) < 0) {
e3e0314b 4970 if (strv_push(&patterns, *name) < 0)
94e0bd7d 4971 return log_oom();
48220598 4972
e3e0314b 4973 continue;
94e0bd7d 4974 } else if (show_properties) {
94e0bd7d 4975 /* Interpret as job id */
3dced37b 4976 if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 4977 return log_oom();
48220598 4978
94e0bd7d
ZJS
4979 } else {
4980 /* Interpret as PID */
3dced37b 4981 r = get_unit_dbus_path_by_pid(bus, id, &path);
373d32c9 4982 if (r < 0) {
94e0bd7d 4983 ret = r;
373d32c9
LP
4984 continue;
4985 }
3dced37b
LP
4986
4987 r = unit_name_from_dbus_path(path, &unit);
4988 if (r < 0)
4989 return log_oom();
94e0bd7d 4990 }
f74294c1 4991
3dced37b 4992 r = show_one(argv[0], bus, path, unit, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
4993 if (r < 0)
4994 return r;
4995 else if (r > 0 && ret == 0)
4996 ret = r;
48220598 4997 }
94e0bd7d 4998
e3e0314b
ZJS
4999 if (!strv_isempty(patterns)) {
5000 _cleanup_strv_free_ char **names = NULL;
5001
5002 r = expand_names(bus, patterns, NULL, &names);
5003 if (r < 0)
691395d8 5004 return log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
5005
5006 STRV_FOREACH(name, names) {
3dced37b 5007 _cleanup_free_ char *path;
e3e0314b 5008
3dced37b
LP
5009 path = unit_dbus_path_from_name(*name);
5010 if (!path)
e3e0314b
ZJS
5011 return log_oom();
5012
3dced37b 5013 r = show_one(argv[0], bus, path, *name, show_properties, &new_line, &ellipsized);
5bb75bc7
ZJS
5014 if (r < 0)
5015 return r;
3dced37b 5016 if (r > 0 && ret == 0)
5bb75bc7 5017 ret = r;
e3e0314b
ZJS
5018 }
5019 }
5020 }
5021
94e0bd7d
ZJS
5022 if (ellipsized && !arg_quiet)
5023 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 5024
22f4096c 5025 return ret;
0183528f
LP
5026}
5027
8527b07b
ZJS
5028static int cat_file(const char *filename, bool newline) {
5029 _cleanup_close_ int fd;
5030
5031 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
5032 if (fd < 0)
5033 return -errno;
5034
5035 printf("%s%s# %s%s\n",
5036 newline ? "\n" : "",
5037 ansi_highlight_blue(),
5038 filename,
1fc464f6 5039 ansi_normal());
8527b07b
ZJS
5040 fflush(stdout);
5041
59f448cf 5042 return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
8527b07b
ZJS
5043}
5044
e449de87 5045static int cat(int argc, char *argv[], void *userdata) {
ad2a0358 5046 _cleanup_lookup_paths_free_ LookupPaths lp = {};
15ef1144
LP
5047 _cleanup_strv_free_ char **names = NULL;
5048 char **name;
4fbd7192
LP
5049 sd_bus *bus;
5050 bool first = true;
25586912 5051 int r;
15ef1144 5052
3e7eed84 5053 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 5054 log_error("Cannot remotely cat units.");
3e495a66
ZJS
5055 return -EINVAL;
5056 }
5057
4943d143 5058 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
ad2a0358 5059 if (r < 0)
c51932be 5060 return log_error_errno(r, "Failed to determine unit paths: %m");
ad2a0358 5061
4fbd7192 5062 r = acquire_bus(BUS_MANAGER, &bus);
15ef1144 5063 if (r < 0)
4fbd7192 5064 return r;
15ef1144 5065
e449de87 5066 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
4fbd7192
LP
5067 if (r < 0)
5068 return log_error_errno(r, "Failed to expand names: %m");
ad2a0358 5069
ea4b98e6 5070 pager_open(arg_no_pager, false);
15ef1144
LP
5071
5072 STRV_FOREACH(name, names) {
ad2a0358 5073 _cleanup_free_ char *fragment_path = NULL;
15ef1144 5074 _cleanup_strv_free_ char **dropin_paths = NULL;
15ef1144
LP
5075 char **path;
5076
4fbd7192 5077 r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
ad2a0358
ZJS
5078 if (r < 0)
5079 return r;
b5e6a600
IS
5080 else if (r == 0)
5081 return -ENOENT;
15ef1144
LP
5082
5083 if (first)
5084 first = false;
5085 else
5086 puts("");
5087
ad2a0358 5088 if (fragment_path) {
8527b07b
ZJS
5089 r = cat_file(fragment_path, false);
5090 if (r < 0)
5091 return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
15ef1144
LP
5092 }
5093
5094 STRV_FOREACH(path, dropin_paths) {
8527b07b
ZJS
5095 r = cat_file(*path, path == dropin_paths);
5096 if (r < 0)
5097 return log_warning_errno(r, "Failed to cat %s: %m", *path);
15ef1144
LP
5098 }
5099 }
5100
25586912 5101 return 0;
15ef1144
LP
5102}
5103
e449de87 5104static int set_property(int argc, char *argv[], void *userdata) {
4afd3348
LP
5105 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
5106 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 5107 _cleanup_free_ char *n = NULL;
4fbd7192 5108 sd_bus *bus;
8e2af478
LP
5109 int r;
5110
4fbd7192
LP
5111 r = acquire_bus(BUS_MANAGER, &bus);
5112 if (r < 0)
5113 return r;
5114
d2ad7e1b
ZJS
5115 polkit_agent_open_if_enabled();
5116
f459b602
MAP
5117 r = sd_bus_message_new_method_call(
5118 bus,
151b9b96 5119 &m,
8e2af478
LP
5120 "org.freedesktop.systemd1",
5121 "/org/freedesktop/systemd1",
5122 "org.freedesktop.systemd1.Manager",
151b9b96 5123 "SetUnitProperties");
f459b602
MAP
5124 if (r < 0)
5125 return bus_log_create_error(r);
8e2af478 5126
e449de87 5127 r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n);
7410616c
LP
5128 if (r < 0)
5129 return log_error_errno(r, "Failed to mangle unit name: %m");
68372da6 5130
f459b602
MAP
5131 r = sd_bus_message_append(m, "sb", n, arg_runtime);
5132 if (r < 0)
5133 return bus_log_create_error(r);
8e2af478 5134
f459b602
MAP
5135 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
5136 if (r < 0)
5137 return bus_log_create_error(r);
8e2af478 5138
8673cf13
LP
5139 r = bus_append_unit_property_assignment_many(m, strv_skip(argv, 2));
5140 if (r < 0)
5141 return r;
8e2af478 5142
f459b602
MAP
5143 r = sd_bus_message_close_container(m);
5144 if (r < 0)
5145 return bus_log_create_error(r);
8e2af478 5146
c49b30a2 5147 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5148 if (r < 0)
5149 return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
8e2af478
LP
5150
5151 return 0;
5152}
5153
e449de87 5154static int daemon_reload(int argc, char *argv[], void *userdata) {
4afd3348 5155 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2853b60a 5156 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5157 const char *method;
4fbd7192 5158 sd_bus *bus;
f459b602 5159 int r;
7e4249b9 5160
4fbd7192
LP
5161 r = acquire_bus(BUS_MANAGER, &bus);
5162 if (r < 0)
5163 return r;
5164
d2ad7e1b
ZJS
5165 polkit_agent_open_if_enabled();
5166
2853b60a
LP
5167 switch (arg_action) {
5168
5169 case ACTION_RELOAD:
e4b61340 5170 method = "Reload";
2853b60a
LP
5171 break;
5172
5173 case ACTION_REEXEC:
e4b61340 5174 method = "Reexecute";
2853b60a
LP
5175 break;
5176
5177 case ACTION_SYSTEMCTL:
5178 method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
5179 /* "daemon-reload" */ "Reload";
5180 break;
e4b61340 5181
2853b60a
LP
5182 default:
5183 assert_not_reached("Unexpected action");
e4b61340 5184 }
7e4249b9 5185
2853b60a
LP
5186 r = sd_bus_message_new_method_call(
5187 bus,
5188 &m,
5189 "org.freedesktop.systemd1",
5190 "/org/freedesktop/systemd1",
5191 "org.freedesktop.systemd1.Manager",
5192 method);
5193 if (r < 0)
5194 return bus_log_create_error(r);
5195
5196 /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
5197 * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
5198 * their timeout, and for everything else there's the same time budget in place. */
5199
5200 r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
5201
5202 /* On reexecution, we expect a disconnect, not a reply */
5203 if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
5204 r = 0;
5205
5206 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5207 return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
5208
5209 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5210 * old ways of doing things, hence don't log any error in that case here. */
5211
5212 return r < 0 ? r : 0;
5213}
5214
5215static int trivial_method(int argc, char *argv[], void *userdata) {
5216 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5217 const char *method;
5218 sd_bus *bus;
5219 int r;
5220
2853b60a
LP
5221 r = acquire_bus(BUS_MANAGER, &bus);
5222 if (r < 0)
5223 return r;
5224
d2ad7e1b
ZJS
5225 polkit_agent_open_if_enabled();
5226
2853b60a
LP
5227 method =
5228 streq(argv[0], "clear-jobs") ||
5229 streq(argv[0], "cancel") ? "ClearJobs" :
5230 streq(argv[0], "reset-failed") ? "ResetFailed" :
5231 streq(argv[0], "halt") ? "Halt" :
5232 streq(argv[0], "reboot") ? "Reboot" :
5233 streq(argv[0], "kexec") ? "KExec" :
5234 streq(argv[0], "exit") ? "Exit" :
5235 /* poweroff */ "PowerOff";
5236
6e646d22 5237 r = sd_bus_call_method(
f22f08cd
SP
5238 bus,
5239 "org.freedesktop.systemd1",
5240 "/org/freedesktop/systemd1",
5241 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5242 method,
5243 &error,
5244 NULL,
5245 NULL);
2853b60a
LP
5246 if (r < 0 && arg_action == ACTION_SYSTEMCTL)
5247 return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
5248
5249 /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
5250 * old ways of doing things, hence don't log any error in that case here. */
7e4249b9 5251
0a9776c2 5252 return r < 0 ? r : 0;
7e4249b9
LP
5253}
5254
e449de87 5255static int reset_failed(int argc, char *argv[], void *userdata) {
e3e0314b 5256 _cleanup_strv_free_ char **names = NULL;
4fbd7192 5257 sd_bus *bus;
f84190d8 5258 char **name;
e3e0314b 5259 int r, q;
5632e374 5260
e449de87 5261 if (argc <= 1)
2853b60a 5262 return trivial_method(argc, argv, userdata);
5632e374 5263
4fbd7192
LP
5264 r = acquire_bus(BUS_MANAGER, &bus);
5265 if (r < 0)
5266 return r;
5267
d2ad7e1b
ZJS
5268 polkit_agent_open_if_enabled();
5269
e449de87 5270 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
e3e0314b 5271 if (r < 0)
691395d8 5272 return log_error_errno(r, "Failed to expand names: %m");
f84190d8 5273
e3e0314b 5274 STRV_FOREACH(name, names) {
4afd3348 5275 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 5276
6e646d22 5277 q = sd_bus_call_method(
f22f08cd 5278 bus,
b0193f1c
LP
5279 "org.freedesktop.systemd1",
5280 "/org/freedesktop/systemd1",
5281 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5282 "ResetFailedUnit",
5283 &error,
5284 NULL,
5285 "s", *name);
e3e0314b 5286 if (q < 0) {
691395d8 5287 log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
5288 if (r == 0)
5289 r = q;
f459b602 5290 }
5632e374
LP
5291 }
5292
e3e0314b 5293 return r;
5632e374
LP
5294}
5295
e449de87 5296static int show_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5297 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5298 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
f459b602 5299 const char *text;
4fbd7192 5300 sd_bus *bus;
7e4249b9 5301 int r;
7e4249b9 5302
4fbd7192
LP
5303 r = acquire_bus(BUS_MANAGER, &bus);
5304 if (r < 0)
5305 return r;
5306
d2ad7e1b
ZJS
5307 pager_open(arg_no_pager, false);
5308
f459b602 5309 r = sd_bus_get_property(
f22f08cd
SP
5310 bus,
5311 "org.freedesktop.systemd1",
5312 "/org/freedesktop/systemd1",
f459b602
MAP
5313 "org.freedesktop.systemd1.Manager",
5314 "Environment",
5315 &error,
f22f08cd 5316 &reply,
f459b602 5317 "as");
691395d8
LP
5318 if (r < 0)
5319 return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
7e4249b9 5320
f459b602
MAP
5321 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
5322 if (r < 0)
5323 return bus_log_parse_error(r);
7e4249b9 5324
f459b602 5325 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 5326 puts(text);
f459b602
MAP
5327 if (r < 0)
5328 return bus_log_parse_error(r);
7e4249b9 5329
f459b602
MAP
5330 r = sd_bus_message_exit_container(reply);
5331 if (r < 0)
5332 return bus_log_parse_error(r);
7e4249b9 5333
f84190d8 5334 return 0;
7e4249b9
LP
5335}
5336
e449de87 5337static int switch_root(int argc, char *argv[], void *userdata) {
4afd3348 5338 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
5339 _cleanup_free_ char *cmdline_init = NULL;
5340 const char *root, *init;
4fbd7192 5341 sd_bus *bus;
f459b602 5342 int r;
957eb8ca 5343
4fbd7192
LP
5344 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5345 log_error("Cannot switch root remotely.");
5346 return -EINVAL;
5347 }
5348
e449de87 5349 if (argc < 2 || argc > 3) {
957eb8ca
LP
5350 log_error("Wrong number of arguments.");
5351 return -EINVAL;
5352 }
5353
e449de87 5354 root = argv[1];
13068da8 5355
e449de87
LP
5356 if (argc >= 3)
5357 init = argv[2];
13068da8 5358 else {
f39d4a08
HH
5359 r = parse_env_file("/proc/cmdline", WHITESPACE,
5360 "init", &cmdline_init,
5361 NULL);
5362 if (r < 0)
da927ba9 5363 log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
13068da8 5364
f39d4a08 5365 init = cmdline_init;
13068da8 5366 }
f459b602 5367
3c6f7c34 5368 init = empty_to_null(init);
f39d4a08
HH
5369 if (init) {
5370 const char *root_systemd_path = NULL, *root_init_path = NULL;
5371
63c372cb
LP
5372 root_systemd_path = strjoina(root, "/" SYSTEMD_BINARY_PATH);
5373 root_init_path = strjoina(root, "/", init);
f39d4a08
HH
5374
5375 /* If the passed init is actually the same as the
5376 * systemd binary, then let's suppress it. */
5377 if (files_same(root_init_path, root_systemd_path) > 0)
5378 init = NULL;
5379 }
13068da8 5380
4fbd7192
LP
5381 r = acquire_bus(BUS_MANAGER, &bus);
5382 if (r < 0)
5383 return r;
5384
f39d4a08 5385 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 5386
f459b602 5387 r = sd_bus_call_method(
f22f08cd 5388 bus,
957eb8ca
LP
5389 "org.freedesktop.systemd1",
5390 "/org/freedesktop/systemd1",
5391 "org.freedesktop.systemd1.Manager",
f22f08cd 5392 "SwitchRoot",
f459b602 5393 &error,
f22f08cd 5394 NULL,
f459b602 5395 "ss", root, init);
691395d8
LP
5396 if (r < 0)
5397 return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
f459b602
MAP
5398
5399 return 0;
957eb8ca
LP
5400}
5401
e449de87 5402static int set_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5403 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5404 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
7e4249b9 5405 const char *method;
4fbd7192 5406 sd_bus *bus;
31e767f7
LP
5407 int r;
5408
e449de87
LP
5409 assert(argc > 1);
5410 assert(argv);
7e4249b9 5411
4fbd7192
LP
5412 r = acquire_bus(BUS_MANAGER, &bus);
5413 if (r < 0)
5414 return r;
5415
d2ad7e1b
ZJS
5416 polkit_agent_open_if_enabled();
5417
e449de87 5418 method = streq(argv[0], "set-environment")
7e4249b9
LP
5419 ? "SetEnvironment"
5420 : "UnsetEnvironment";
5421
f459b602
MAP
5422 r = sd_bus_message_new_method_call(
5423 bus,
151b9b96 5424 &m,
31e767f7
LP
5425 "org.freedesktop.systemd1",
5426 "/org/freedesktop/systemd1",
5427 "org.freedesktop.systemd1.Manager",
151b9b96 5428 method);
f459b602
MAP
5429 if (r < 0)
5430 return bus_log_create_error(r);
7e4249b9 5431
e449de87 5432 r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
31e767f7 5433 if (r < 0)
f459b602 5434 return bus_log_create_error(r);
7e4249b9 5435
c49b30a2 5436 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5437 if (r < 0)
5438 return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
7e4249b9 5439
f84190d8 5440 return 0;
7e4249b9
LP
5441}
5442
e449de87 5443static int import_environment(int argc, char *argv[], void *userdata) {
4afd3348
LP
5444 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5445 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
4fbd7192 5446 sd_bus *bus;
ac3efa8a
LP
5447 int r;
5448
4fbd7192
LP
5449 r = acquire_bus(BUS_MANAGER, &bus);
5450 if (r < 0)
5451 return r;
5452
d2ad7e1b
ZJS
5453 polkit_agent_open_if_enabled();
5454
ac3efa8a
LP
5455 r = sd_bus_message_new_method_call(
5456 bus,
151b9b96 5457 &m,
ac3efa8a
LP
5458 "org.freedesktop.systemd1",
5459 "/org/freedesktop/systemd1",
5460 "org.freedesktop.systemd1.Manager",
151b9b96 5461 "SetEnvironment");
ac3efa8a
LP
5462 if (r < 0)
5463 return bus_log_create_error(r);
5464
e449de87 5465 if (argc < 2)
ac3efa8a
LP
5466 r = sd_bus_message_append_strv(m, environ);
5467 else {
5468 char **a, **b;
5469
5470 r = sd_bus_message_open_container(m, 'a', "s");
5471 if (r < 0)
5472 return bus_log_create_error(r);
5473
e449de87 5474 STRV_FOREACH(a, strv_skip(argv, 1)) {
ac3efa8a
LP
5475
5476 if (!env_name_is_valid(*a)) {
5477 log_error("Not a valid environment variable name: %s", *a);
5478 return -EINVAL;
5479 }
5480
5481 STRV_FOREACH(b, environ) {
5482 const char *eq;
5483
5484 eq = startswith(*b, *a);
5485 if (eq && *eq == '=') {
5486
5487 r = sd_bus_message_append(m, "s", *b);
5488 if (r < 0)
5489 return bus_log_create_error(r);
5490
5491 break;
5492 }
5493 }
5494 }
5495
5496 r = sd_bus_message_close_container(m);
5497 }
5498 if (r < 0)
5499 return bus_log_create_error(r);
5500
5501 r = sd_bus_call(bus, m, 0, &error, NULL);
691395d8
LP
5502 if (r < 0)
5503 return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
ac3efa8a
LP
5504
5505 return 0;
5506}
5507
cbb13b2a 5508static int enable_sysv_units(const char *verb, char **args) {
729e3769 5509 int r = 0;
ee5762e3 5510
0f0467e6 5511#if defined(HAVE_SYSV_COMPAT)
fb15be83 5512 _cleanup_lookup_paths_free_ LookupPaths paths = {};
e735decc
LP
5513 unsigned f = 0;
5514
5515 /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
ee5762e3 5516
729e3769
LP
5517 if (arg_scope != UNIT_FILE_SYSTEM)
5518 return 0;
ee5762e3 5519
b41b9d2a
LP
5520 if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0)
5521 return 0;
5522
4c315c2c
IS
5523 if (!STR_IN_SET(verb,
5524 "enable",
5525 "disable",
5526 "is-enabled"))
729e3769 5527 return 0;
ee5762e3 5528
4943d143 5529 r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
729e3769
LP
5530 if (r < 0)
5531 return r;
ee5762e3 5532
729e3769 5533 r = 0;
a644abed 5534 while (args[f]) {
e735decc
LP
5535
5536 const char *argv[] = {
5537 ROOTLIBEXECDIR "/systemd-sysv-install",
5538 NULL,
5539 NULL,
5540 NULL,
5541 NULL,
5542 };
5543
05cae7f3 5544 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769 5545 bool found_native = false, found_sysv;
e735decc
LP
5546 siginfo_t status;
5547 const char *name;
729e3769 5548 unsigned c = 1;
729e3769 5549 pid_t pid;
e735decc 5550 int j;
ee5762e3 5551
a644abed 5552 name = args[f++];
ee5762e3 5553
729e3769
LP
5554 if (!endswith(name, ".service"))
5555 continue;
ee5762e3 5556
729e3769
LP
5557 if (path_is_absolute(name))
5558 continue;
ee5762e3 5559
e735decc 5560 j = unit_file_exists(arg_scope, &paths, name);
76ec966f 5561 if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
e735decc 5562 return log_error_errno(j, "Failed to lookup unit file state: %m");
3c6d8e57 5563 found_native = j != 0;
ee5762e3 5564
e735decc
LP
5565 /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
5566 * prefer the native unit */
355ff449 5567 if (found_native && streq(verb, "is-enabled"))
729e3769 5568 continue;
ee5762e3 5569
0c6ea3a4
ZJS
5570 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5571 if (!p)
60731f32 5572 return log_oom();
ee5762e3 5573
05cae7f3 5574 p[strlen(p) - strlen(".service")] = 0;
729e3769 5575 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5576 if (!found_sysv)
729e3769 5577 continue;
71fad675 5578
689e4e6a
CR
5579 if (!arg_quiet) {
5580 if (found_native)
5581 log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
5582 else
5583 log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
5584 }
ee5762e3 5585
729e3769
LP
5586 if (!isempty(arg_root))
5587 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5588
0f0467e6 5589 argv[c++] = verb;
2b6bf07d 5590 argv[c++] = basename(p);
729e3769 5591 argv[c] = NULL;
ee5762e3 5592
729e3769 5593 l = strv_join((char**)argv, " ");
60731f32
ZJS
5594 if (!l)
5595 return log_oom();
ee5762e3 5596
e735decc 5597 log_info("Executing: %s", l);
ee5762e3 5598
729e3769 5599 pid = fork();
4a62c710
MS
5600 if (pid < 0)
5601 return log_error_errno(errno, "Failed to fork: %m");
5602 else if (pid == 0) {
729e3769 5603 /* Child */
ee5762e3 5604
ce30c8dc
LP
5605 (void) reset_all_signal_handlers();
5606 (void) reset_signal_mask();
5607
729e3769 5608 execv(argv[0], (char**) argv);
cc7cb0ca 5609 log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
729e3769
LP
5610 _exit(EXIT_FAILURE);
5611 }
ee5762e3 5612
729e3769 5613 j = wait_for_terminate(pid, &status);
d710aaf7
ZJS
5614 if (j < 0)
5615 return log_error_errno(j, "Failed to wait for child: %m");
ee5762e3 5616
729e3769
LP
5617 if (status.si_code == CLD_EXITED) {
5618 if (streq(verb, "is-enabled")) {
5619 if (status.si_status == 0) {
5620 if (!arg_quiet)
5621 puts("enabled");
5622 r = 1;
5623 } else {
5624 if (!arg_quiet)
5625 puts("disabled");
5626 }
ee5762e3 5627
60731f32 5628 } else if (status.si_status != 0)
c61b443d
LP
5629 return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
5630 } else {
5631 log_error("Unexpected waitid() result.");
60731f32 5632 return -EPROTO;
c61b443d 5633 }
ee5762e3 5634
355ff449
MP
5635 if (found_native)
5636 continue;
5637
a644abed 5638 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
5639 assert(f > 0);
5640 f--;
5641 assert(args[f] == name);
5642 strv_remove(args, name);
729e3769 5643 }
ee5762e3 5644
729e3769
LP
5645#endif
5646 return r;
5647}
ee5762e3 5648
37370d0c 5649static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5650 char **i, **l, **name;
7410616c 5651 int r;
37370d0c 5652
7410616c 5653 l = i = new(char*, strv_length(original_names) + 1);
a33fdebb 5654 if (!l)
37370d0c
VP
5655 return log_oom();
5656
37370d0c 5657 STRV_FOREACH(name, original_names) {
44386fc1
LN
5658
5659 /* When enabling units qualified path names are OK,
5660 * too, hence allow them explicitly. */
5661
7410616c 5662 if (is_path(*name)) {
44386fc1 5663 *i = strdup(*name);
7410616c
LP
5664 if (!*i) {
5665 strv_free(l);
5666 return log_oom();
5667 }
5668 } else {
5669 r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
5670 if (r < 0) {
5671 strv_free(l);
5672 return log_error_errno(r, "Failed to mangle unit name: %m");
5673 }
a33fdebb
LP
5674 }
5675
5676 i++;
37370d0c 5677 }
a33fdebb
LP
5678
5679 *i = NULL;
5680 *mangled_names = l;
37370d0c
VP
5681
5682 return 0;
5683}
5684
1d3c86c0
MS
5685static int normalize_names(char **names, bool warn_if_path) {
5686 char **u;
5687 bool was_path = false;
5688
5689 STRV_FOREACH(u, names) {
5690 int r;
5691
5692 if (!is_path(*u))
5693 continue;
5694
5695 r = free_and_strdup(u, basename(*u));
5696 if (r < 0)
5697 return log_error_errno(r, "Failed to normalize unit file path: %m");
5698
5699 was_path = true;
5700 }
5701
5702 if (warn_if_path && was_path)
5703 log_warning("Warning: Can't execute disable on the unit file path. Proceeding with the unit name.");
5704
5705 return 0;
5706}
5707
d6568222 5708static int unit_exists(const char *unit) {
ba19c6e1 5709 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
d6568222
SS
5710 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
5711 _cleanup_free_ char *path = NULL;
5712 static const struct bus_properties_map property_map[] = {
662bea67
ZJS
5713 { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
5714 { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state)},
d6568222
SS
5715 {},
5716 };
5717 UnitStatusInfo info = {};
5718 sd_bus *bus;
5719 int r;
5720
5721 path = unit_dbus_path_from_name(unit);
5722 if (!path)
5723 return log_oom();
5724
5725 r = acquire_bus(BUS_MANAGER, &bus);
5726 if (r < 0)
5727 return r;
5728
5729 r = sd_bus_call_method(
5730 bus,
5731 "org.freedesktop.systemd1",
5732 path,
5733 "org.freedesktop.DBus.Properties",
5734 "GetAll",
5735 &error,
5736 &reply,
5737 "s", "");
5738 if (r < 0)
5739 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
5740
5741 r = bus_message_map_all_properties(reply, property_map, &info);
5742 if (r < 0)
5743 return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
5744
5745 return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
5746}
5747
e449de87 5748static int enable_unit(int argc, char *argv[], void *userdata) {
e3e0314b 5749 _cleanup_strv_free_ char **names = NULL;
e449de87 5750 const char *verb = argv[0];
729e3769 5751 UnitFileChange *changes = NULL;
718db961 5752 unsigned n_changes = 0;
729e3769 5753 int carries_install_info = -1;
35b132e8 5754 bool ignore_carries_install_info = arg_quiet;
729e3769 5755 int r;
ee5762e3 5756
e449de87 5757 if (!argv[1])
ab5919fa
MS
5758 return 0;
5759
e449de87 5760 r = mangle_names(strv_skip(argv, 1), &names);
3a05c0f9 5761 if (r < 0)
cbb13b2a
VP
5762 return r;
5763
e3e0314b 5764 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5765 if (r < 0)
5766 return r;
3a05c0f9 5767
c61b443d 5768 /* If the operation was fully executed by the SysV compat, let's finish early */
823e5fab
FB
5769 if (strv_isempty(names)) {
5770 if (arg_no_reload || install_client_side())
5771 return 0;
5772 return daemon_reload(argc, argv, userdata);
5773 }
67d66210 5774
1d3c86c0
MS
5775 if (streq(verb, "disable")) {
5776 r = normalize_names(names, true);
5777 if (r < 0)
5778 return r;
5779 }
5780
4fbd7192 5781 if (install_client_side()) {
729e3769 5782 if (streq(verb, "enable")) {
e3e0314b 5783 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5784 carries_install_info = r;
5785 } else if (streq(verb, "disable"))
e3e0314b 5786 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5787 else if (streq(verb, "reenable")) {
e3e0314b 5788 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5789 carries_install_info = r;
5790 } else if (streq(verb, "link"))
e3e0314b 5791 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5792 else if (streq(verb, "preset")) {
d309c1c3 5793 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769 5794 } else if (streq(verb, "mask"))
e3e0314b 5795 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5796 else if (streq(verb, "unmask"))
e3e0314b 5797 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
344ca755
LP
5798 else if (streq(verb, "revert"))
5799 r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
729e3769
LP
5800 else
5801 assert_not_reached("Unknown verb");
ee5762e3 5802
af3d8113 5803 unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
d073dea0 5804 if (r < 0)
85b78539 5805 goto finish;
df77cdf0 5806 r = 0;
729e3769 5807 } else {
4afd3348
LP
5808 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
5809 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
39207373 5810 bool expect_carries_install_info = false;
344ca755 5811 bool send_runtime = true, send_force = true, send_preset_mode = false;
718db961 5812 const char *method;
4fbd7192 5813 sd_bus *bus;
729e3769 5814
d6568222
SS
5815 if (STR_IN_SET(verb, "mask", "unmask")) {
5816 r = unit_exists(*names);
5817 if (r < 0)
5818 return r;
5819 if (r == 0)
5820 log_notice("Unit %s does not exist, proceeding anyway.", *names);
5821 }
5822
4fbd7192
LP
5823 r = acquire_bus(BUS_MANAGER, &bus);
5824 if (r < 0)
5825 return r;
5826
d2ad7e1b
ZJS
5827 polkit_agent_open_if_enabled();
5828
729e3769
LP
5829 if (streq(verb, "enable")) {
5830 method = "EnableUnitFiles";
5831 expect_carries_install_info = true;
5832 } else if (streq(verb, "disable")) {
5833 method = "DisableUnitFiles";
5834 send_force = false;
5835 } else if (streq(verb, "reenable")) {
5836 method = "ReenableUnitFiles";
5837 expect_carries_install_info = true;
5838 } else if (streq(verb, "link"))
5839 method = "LinkUnitFiles";
5840 else if (streq(verb, "preset")) {
d309c1c3
LP
5841
5842 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5843 method = "PresetUnitFilesWithMode";
5844 send_preset_mode = true;
5845 } else
5846 method = "PresetUnitFiles";
5847
729e3769 5848 expect_carries_install_info = true;
39207373 5849 ignore_carries_install_info = true;
729e3769
LP
5850 } else if (streq(verb, "mask"))
5851 method = "MaskUnitFiles";
5852 else if (streq(verb, "unmask")) {
5853 method = "UnmaskUnitFiles";
5854 send_force = false;
344ca755
LP
5855 } else if (streq(verb, "revert")) {
5856 method = "RevertUnitFiles";
5857 send_runtime = send_force = false;
729e3769
LP
5858 } else
5859 assert_not_reached("Unknown verb");
5860
f459b602
MAP
5861 r = sd_bus_message_new_method_call(
5862 bus,
151b9b96 5863 &m,
729e3769
LP
5864 "org.freedesktop.systemd1",
5865 "/org/freedesktop/systemd1",
5866 "org.freedesktop.systemd1.Manager",
151b9b96 5867 method);
f459b602
MAP
5868 if (r < 0)
5869 return bus_log_create_error(r);
ee5762e3 5870
e3e0314b 5871 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5872 if (r < 0)
5873 return bus_log_create_error(r);
ee5762e3 5874
d309c1c3
LP
5875 if (send_preset_mode) {
5876 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5877 if (r < 0)
5878 return bus_log_create_error(r);
5879 }
5880
344ca755
LP
5881 if (send_runtime) {
5882 r = sd_bus_message_append(m, "b", arg_runtime);
5883 if (r < 0)
5884 return bus_log_create_error(r);
5885 }
ee5762e3 5886
729e3769 5887 if (send_force) {
f459b602
MAP
5888 r = sd_bus_message_append(m, "b", arg_force);
5889 if (r < 0)
5890 return bus_log_create_error(r);
ee5762e3
LP
5891 }
5892
c49b30a2 5893 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 5894 if (r < 0)
af3d8113 5895 return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
be394c48 5896
729e3769 5897 if (expect_carries_install_info) {
f459b602
MAP
5898 r = sd_bus_message_read(reply, "b", &carries_install_info);
5899 if (r < 0)
5900 return bus_log_parse_error(r);
ee5762e3
LP
5901 }
5902
57ab2eab 5903 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
f459b602 5904 if (r < 0)
85b78539 5905 goto finish;
b77398f7 5906
93c941e3 5907 /* Try to reload if enabled */
d6cb60c7 5908 if (!arg_no_reload)
e449de87 5909 r = daemon_reload(argc, argv, userdata);
f459b602
MAP
5910 else
5911 r = 0;
b647f10d 5912 }
3d3961f2 5913
39207373 5914 if (carries_install_info == 0 && !ignore_carries_install_info)
fe4aede9
ZJS
5915 log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
5916 "settings in the [Install] section, and DefaultInstance for template units).\n"
5917 "This means they are not meant to be enabled using systemctl.\n"
416389f7
LP
5918 "Possible reasons for having this kind of units are:\n"
5919 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5920 " .wants/ or .requires/ directory.\n"
5921 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5922 " a requirement dependency on it.\n"
5923 "3) A unit may be started when needed via activation (socket, path, timer,\n"
fe4aede9
ZJS
5924 " D-Bus, udev, scripted systemctl call, ...).\n"
5925 "4) In case of template units, the unit is meant to be enabled with some\n"
5926 " instance name specified.");
ee5762e3 5927
e449de87 5928 if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
57ab2eab 5929 char *new_args[n_changes + 2];
4fbd7192 5930 sd_bus *bus;
57ab2eab
JS
5931 unsigned i;
5932
4fbd7192
LP
5933 r = acquire_bus(BUS_MANAGER, &bus);
5934 if (r < 0)
d073dea0 5935 goto finish;
4fbd7192 5936
e449de87 5937 new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
57ab2eab
JS
5938 for (i = 0; i < n_changes; i++)
5939 new_args[i + 1] = basename(changes[i].path);
5940 new_args[i + 1] = NULL;
5941
e449de87 5942 r = start_unit(strv_length(new_args), new_args, userdata);
57ab2eab
JS
5943 }
5944
729e3769 5945finish:
729e3769 5946 unit_file_changes_free(changes, n_changes);
ee5762e3 5947
729e3769 5948 return r;
ee5762e3
LP
5949}
5950
e449de87 5951static int add_dependency(int argc, char *argv[], void *userdata) {
e94937df
LN
5952 _cleanup_strv_free_ char **names = NULL;
5953 _cleanup_free_ char *target = NULL;
e449de87 5954 const char *verb = argv[0];
acc0269c
CH
5955 UnitFileChange *changes = NULL;
5956 unsigned n_changes = 0;
e94937df
LN
5957 UnitDependency dep;
5958 int r = 0;
5959
e449de87 5960 if (!argv[1])
e94937df
LN
5961 return 0;
5962
e449de87 5963 r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target);
7410616c
LP
5964 if (r < 0)
5965 return log_error_errno(r, "Failed to mangle unit name: %m");
e94937df 5966
e449de87 5967 r = mangle_names(strv_skip(argv, 2), &names);
e94937df
LN
5968 if (r < 0)
5969 return r;
5970
5971 if (streq(verb, "add-wants"))
5972 dep = UNIT_WANTS;
5973 else if (streq(verb, "add-requires"))
5974 dep = UNIT_REQUIRES;
5975 else
5976 assert_not_reached("Unknown verb");
5977
4fbd7192 5978 if (install_client_side()) {
e94937df 5979 r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
af3d8113 5980 unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
5f056378
CH
5981
5982 if (r > 0)
5983 r = 0;
e94937df 5984 } else {
4afd3348
LP
5985 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
5986 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 5987 sd_bus *bus;
e94937df 5988
4fbd7192
LP
5989 r = acquire_bus(BUS_MANAGER, &bus);
5990 if (r < 0)
5991 return r;
5992
d2ad7e1b
ZJS
5993 polkit_agent_open_if_enabled();
5994
e94937df
LN
5995 r = sd_bus_message_new_method_call(
5996 bus,
5997 &m,
5998 "org.freedesktop.systemd1",
5999 "/org/freedesktop/systemd1",
6000 "org.freedesktop.systemd1.Manager",
6001 "AddDependencyUnitFiles");
6002 if (r < 0)
6003 return bus_log_create_error(r);
6004
342641fb 6005 r = sd_bus_message_append_strv(m, names);
e94937df
LN
6006 if (r < 0)
6007 return bus_log_create_error(r);
6008
342641fb 6009 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
6010 if (r < 0)
6011 return bus_log_create_error(r);
6012
6013 r = sd_bus_call(bus, m, 0, &error, &reply);
691395d8 6014 if (r < 0)
af3d8113 6015 return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
e94937df 6016
acc0269c 6017 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
e94937df 6018 if (r < 0)
acc0269c 6019 goto finish;
e94937df 6020
acc0269c
CH
6021 if (arg_no_reload) {
6022 r = 0;
6023 goto finish;
6024 }
6025
6026 r = daemon_reload(argc, argv, userdata);
e94937df 6027 }
acc0269c
CH
6028
6029finish:
6030 unit_file_changes_free(changes, n_changes);
6031
6032 return r;
e94937df
LN
6033}
6034
e449de87 6035static int preset_all(int argc, char *argv[], void *userdata) {
acc0269c
CH
6036 UnitFileChange *changes = NULL;
6037 unsigned n_changes = 0;
d309c1c3
LP
6038 int r;
6039
4fbd7192 6040 if (install_client_side()) {
d309c1c3 6041 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
af3d8113 6042 unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
5f056378
CH
6043
6044 if (r > 0)
6045 r = 0;
d309c1c3 6046 } else {
4afd3348
LP
6047 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
6048 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
4fbd7192 6049 sd_bus *bus;
d309c1c3 6050
4fbd7192
LP
6051 r = acquire_bus(BUS_MANAGER, &bus);
6052 if (r < 0)
6053 return r;
6054
d2ad7e1b
ZJS
6055 polkit_agent_open_if_enabled();
6056
6e646d22 6057 r = sd_bus_call_method(
d309c1c3
LP
6058 bus,
6059 "org.freedesktop.systemd1",
6060 "/org/freedesktop/systemd1",
6061 "org.freedesktop.systemd1.Manager",
6e646d22
LP
6062 "PresetAllUnitFiles",
6063 &error,
6064 &reply,
d309c1c3
LP
6065 "sbb",
6066 unit_file_preset_mode_to_string(arg_preset_mode),
6067 arg_runtime,
6068 arg_force);
691395d8 6069 if (r < 0)
af3d8113 6070 return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
d309c1c3 6071
acc0269c 6072 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
d309c1c3 6073 if (r < 0)
acc0269c 6074 goto finish;
d309c1c3 6075
acc0269c
CH
6076 if (arg_no_reload) {
6077 r = 0;
6078 goto finish;
6079 }
6080
6081 r = daemon_reload(argc, argv, userdata);
d309c1c3 6082 }
acc0269c
CH
6083
6084finish:
6085 unit_file_changes_free(changes, n_changes);
6086
6087 return r;
d309c1c3
LP
6088}
6089
e449de87 6090static int unit_is_enabled(int argc, char *argv[], void *userdata) {
f459b602 6091
e3e0314b 6092 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
6093 bool enabled;
6094 char **name;
f459b602 6095 int r;
ee5762e3 6096
e449de87 6097 r = mangle_names(strv_skip(argv, 1), &names);
cbb13b2a
VP
6098 if (r < 0)
6099 return r;
6100
e449de87 6101 r = enable_sysv_units(argv[0], names);
729e3769
LP
6102 if (r < 0)
6103 return r;
ee5762e3 6104
729e3769 6105 enabled = r > 0;
ee5762e3 6106
4fbd7192 6107 if (install_client_side()) {
ee5762e3 6108
e3e0314b 6109 STRV_FOREACH(name, names) {
729e3769 6110 UnitFileState state;
ee5762e3 6111
0ec0deaa
LP
6112 r = unit_file_get_state(arg_scope, arg_root, *name, &state);
6113 if (r < 0)
f647962d 6114 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
ee5762e3 6115
4c315c2c
IS
6116 if (IN_SET(state,
6117 UNIT_FILE_ENABLED,
6118 UNIT_FILE_ENABLED_RUNTIME,
6119 UNIT_FILE_STATIC,
f4139308
LP
6120 UNIT_FILE_INDIRECT,
6121 UNIT_FILE_GENERATED))
729e3769
LP
6122 enabled = true;
6123
6124 if (!arg_quiet)
6125 puts(unit_file_state_to_string(state));
71fad675 6126 }
ee5762e3 6127
5f056378 6128 r = 0;
729e3769 6129 } else {
4afd3348 6130 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192
LP
6131 sd_bus *bus;
6132
6133 r = acquire_bus(BUS_MANAGER, &bus);
6134 if (r < 0)
6135 return r;
6136
e3e0314b 6137 STRV_FOREACH(name, names) {
4afd3348 6138 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
729e3769 6139 const char *s;
63a723f3 6140
f459b602 6141 r = sd_bus_call_method(
f22f08cd 6142 bus,
729e3769
LP
6143 "org.freedesktop.systemd1",
6144 "/org/freedesktop/systemd1",
6145 "org.freedesktop.systemd1.Manager",
f22f08cd 6146 "GetUnitFileState",
f459b602 6147 &error,
f22f08cd 6148 &reply,
04504f93 6149 "s", *name);
691395d8
LP
6150 if (r < 0)
6151 return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
ee5762e3 6152
f459b602
MAP
6153 r = sd_bus_message_read(reply, "s", &s);
6154 if (r < 0)
6155 return bus_log_parse_error(r);
ee5762e3 6156
f4139308 6157 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
729e3769
LP
6158 enabled = true;
6159
6160 if (!arg_quiet)
6161 puts(s);
560d8f23 6162 }
ee5762e3
LP
6163 }
6164
f4139308 6165 return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
ee5762e3
LP
6166}
6167
e449de87 6168static int is_system_running(int argc, char *argv[], void *userdata) {
99813a19 6169 _cleanup_free_ char *state = NULL;
4fbd7192 6170 sd_bus *bus;
99813a19
LP
6171 int r;
6172
040524b4 6173 if (running_in_chroot() > 0 || (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted())) {
94f099d8
LP
6174 if (!arg_quiet)
6175 puts("offline");
6176 return EXIT_FAILURE;
6177 }
6178
4fbd7192
LP
6179 r = acquire_bus(BUS_MANAGER, &bus);
6180 if (r < 0)
6181 return r;
6182
99813a19
LP
6183 r = sd_bus_get_property_string(
6184 bus,
6185 "org.freedesktop.systemd1",
6186 "/org/freedesktop/systemd1",
6187 "org.freedesktop.systemd1.Manager",
6188 "SystemState",
6189 NULL,
6190 &state);
6191 if (r < 0) {
6192 if (!arg_quiet)
6193 puts("unknown");
6194 return 0;
6195 }
6196
6197 if (!arg_quiet)
6198 puts(state);
6199
6200 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
6201}
6202
7d4fb3b1 6203static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
45519fd6 6204 _cleanup_free_ char *t = NULL;
ae6c3cc0 6205 int r;
7d4fb3b1
RC
6206
6207 assert(new_path);
6208 assert(original_path);
6209 assert(ret_tmp_fn);
6210
14bcf25c 6211 r = tempfn_random(new_path, NULL, &t);
ae6c3cc0 6212 if (r < 0)
029009d4 6213 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
6214
6215 r = mkdir_parents(new_path, 0755);
45519fd6 6216 if (r < 0)
691395d8 6217 return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
7d4fb3b1 6218
f2068bcc 6219 r = copy_file(original_path, t, 0, 0644, 0);
7d4fb3b1 6220 if (r == -ENOENT) {
45519fd6 6221
7d4fb3b1 6222 r = touch(t);
45519fd6
LP
6223 if (r < 0)
6224 return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
6225
6226 } else if (r < 0)
39c38ce1 6227 return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path);
7d4fb3b1
RC
6228
6229 *ret_tmp_fn = t;
45519fd6 6230 t = NULL;
7d4fb3b1
RC
6231
6232 return 0;
6233}
6234
c51932be
LP
6235static int get_file_to_edit(
6236 const LookupPaths *paths,
6237 const char *name,
6238 char **ret_path) {
6239
6240 _cleanup_free_ char *path = NULL, *run = NULL;
7d4fb3b1 6241
45519fd6
LP
6242 assert(name);
6243 assert(ret_path);
6244
c51932be
LP
6245 path = strjoin(paths->persistent_config, "/", name, NULL);
6246 if (!path)
7d4fb3b1
RC
6247 return log_oom();
6248
c51932be 6249 if (arg_runtime) {
79d4ace1 6250 run = strjoin(paths->runtime_config, "/", name, NULL);
c51932be
LP
6251 if (!run)
6252 return log_oom();
6253 }
6254
bc854dc7 6255 if (arg_runtime) {
691395d8
LP
6256 if (access(path, F_OK) >= 0) {
6257 log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
6258 return -EEXIST;
6259 }
6260
bc854dc7
ZJS
6261 *ret_path = run;
6262 run = NULL;
6263 } else {
6264 *ret_path = path;
6265 path = NULL;
6266 }
7d4fb3b1
RC
6267
6268 return 0;
6269}
6270
39c38ce1 6271static int unit_file_create_new(
c51932be
LP
6272 const LookupPaths *paths,
6273 const char *unit_name,
39c38ce1 6274 const char *suffix,
c51932be
LP
6275 char **ret_new_path,
6276 char **ret_tmp_path) {
6277
45519fd6 6278 char *tmp_new_path, *tmp_tmp_path, *ending;
7d4fb3b1
RC
6279 int r;
6280
6281 assert(unit_name);
6282 assert(ret_new_path);
6283 assert(ret_tmp_path);
6284
39c38ce1 6285 ending = strjoina(unit_name, suffix);
c51932be 6286 r = get_file_to_edit(paths, ending, &tmp_new_path);
7d4fb3b1
RC
6287 if (r < 0)
6288 return r;
6289
6290 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
6291 if (r < 0) {
6292 free(tmp_new_path);
6293 return r;
6294 }
6295
6296 *ret_new_path = tmp_new_path;
6297 *ret_tmp_path = tmp_tmp_path;
6298
6299 return 0;
6300}
6301
1cfa9a4c 6302static int unit_file_create_copy(
c51932be 6303 const LookupPaths *paths,
1cfa9a4c
LP
6304 const char *unit_name,
6305 const char *fragment_path,
1cfa9a4c
LP
6306 char **ret_new_path,
6307 char **ret_tmp_path) {
6308
45519fd6 6309 char *tmp_new_path, *tmp_tmp_path;
7d4fb3b1
RC
6310 int r;
6311
6312 assert(fragment_path);
6313 assert(unit_name);
6314 assert(ret_new_path);
6315 assert(ret_tmp_path);
6316
c51932be 6317 r = get_file_to_edit(paths, unit_name, &tmp_new_path);
7d4fb3b1
RC
6318 if (r < 0)
6319 return r;
6320
6321 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
6322 char response;
6323
029009d4 6324 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
6325 if (r < 0) {
6326 free(tmp_new_path);
6327 return r;
6328 }
6329 if (response != 'y') {
6330 log_warning("%s ignored", unit_name);
6331 free(tmp_new_path);
dbf43a1b 6332 return -EKEYREJECTED;
7d4fb3b1
RC
6333 }
6334 }
6335
6336 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
6337 if (r < 0) {
7d4fb3b1
RC
6338 free(tmp_new_path);
6339 return r;
6340 }
6341
6342 *ret_new_path = tmp_new_path;
6343 *ret_tmp_path = tmp_tmp_path;
6344
6345 return 0;
6346}
6347
6348static int run_editor(char **paths) {
6349 pid_t pid;
6350 int r;
6351
6352 assert(paths);
6353
6354 pid = fork();
691395d8
LP
6355 if (pid < 0)
6356 return log_error_errno(errno, "Failed to fork: %m");
7d4fb3b1
RC
6357
6358 if (pid == 0) {
6359 const char **args;
9ef5d8f2 6360 char *editor, **editor_args = NULL;
1cfa9a4c 6361 char **tmp_path, **original_path, *p;
9ef5d8f2 6362 unsigned n_editor_args = 0, i = 1;
7d4fb3b1
RC
6363 size_t argc;
6364
ce30c8dc
LP
6365 (void) reset_all_signal_handlers();
6366 (void) reset_signal_mask();
6367
7d4fb3b1 6368 argc = strv_length(paths)/2 + 1;
7d4fb3b1
RC
6369
6370 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
6371 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
6372 * we try to execute well known editors
6373 */
6374 editor = getenv("SYSTEMD_EDITOR");
6375 if (!editor)
6376 editor = getenv("EDITOR");
6377 if (!editor)
6378 editor = getenv("VISUAL");
6379
6380 if (!isempty(editor)) {
9ef5d8f2
JS
6381 editor_args = strv_split(editor, WHITESPACE);
6382 if (!editor_args) {
6383 (void) log_oom();
6384 _exit(EXIT_FAILURE);
6385 }
6386 n_editor_args = strv_length(editor_args);
6387 argc += n_editor_args - 1;
6388 }
6389 args = newa(const char*, argc + 1);
6390
6391 if (n_editor_args > 0) {
6392 args[0] = editor_args[0];
6393 for (; i < n_editor_args; i++)
6394 args[i] = editor_args[i];
6395 }
6396
6397 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
6398 args[i] = *tmp_path;
6399 i++;
7d4fb3b1 6400 }
9ef5d8f2
JS
6401 args[i] = NULL;
6402
6403 if (n_editor_args > 0)
6404 execvp(args[0], (char* const*) args);
7d4fb3b1 6405
9391a1c3 6406 FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
1cfa9a4c
LP
6407 args[0] = p;
6408 execvp(p, (char* const*) args);
7d4fb3b1
RC
6409 /* We do not fail if the editor doesn't exist
6410 * because we want to try each one of them before
6411 * failing.
6412 */
6413 if (errno != ENOENT) {
691395d8 6414 log_error_errno(errno, "Failed to execute %s: %m", editor);
7d4fb3b1
RC
6415 _exit(EXIT_FAILURE);
6416 }
6417 }
6418
1cfa9a4c 6419 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
6420 _exit(EXIT_FAILURE);
6421 }
6422
6423 r = wait_for_terminate_and_warn("editor", pid, true);
6424 if (r < 0)
6425 return log_error_errno(r, "Failed to wait for child: %m");
6426
45519fd6 6427 return 0;
7d4fb3b1
RC
6428}
6429
6430static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
e9e310f8 6431 _cleanup_lookup_paths_free_ LookupPaths lp = {};
7d4fb3b1
RC
6432 char **name;
6433 int r;
6434
6435 assert(names);
6436 assert(paths);
6437
4943d143 6438 r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
5b013a2f 6439 if (r < 0)
8df18507 6440 return r;
7d4fb3b1 6441
e9e310f8 6442 STRV_FOREACH(name, names) {
78df0edc 6443 _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL;
7d4fb3b1 6444
4fbd7192 6445 r = unit_find_paths(bus, *name, &lp, &path, NULL);
e9e310f8
RC
6446 if (r < 0)
6447 return r;
39c38ce1
DC
6448 else if (!arg_force) {
6449 if (r == 0) {
6450 log_error("Run 'systemctl edit --force %s' to create a new unit.", *name);
6451 return -ENOENT;
6452 } else if (!path) {
6453 // FIXME: support units with path==NULL (no FragmentPath)
6454 log_error("No fragment exists for %s.", *name);
6455 return -ENOENT;
6456 }
6457 }
6458
6459 if (path) {
6460 if (arg_full)
6461 r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path);
6462 else
6463 r = unit_file_create_new(&lp, *name, ".d/override.conf", &new_path, &tmp_path);
dbf43a1b 6464 } else
39c38ce1 6465 r = unit_file_create_new(&lp, *name, NULL, &new_path, &tmp_path);
e9e310f8 6466 if (r < 0)
ad2a0358 6467 return r;
7d4fb3b1 6468
e9e310f8
RC
6469 r = strv_push_pair(paths, new_path, tmp_path);
6470 if (r < 0)
6471 return log_oom();
78df0edc 6472 new_path = tmp_path = NULL;
7d4fb3b1
RC
6473 }
6474
6475 return 0;
6476}
6477
e449de87 6478static int edit(int argc, char *argv[], void *userdata) {
7d4fb3b1
RC
6479 _cleanup_strv_free_ char **names = NULL;
6480 _cleanup_strv_free_ char **paths = NULL;
6481 char **original, **tmp;
4fbd7192 6482 sd_bus *bus;
7d4fb3b1
RC
6483 int r;
6484
7d4fb3b1 6485 if (!on_tty()) {
4fbd7192 6486 log_error("Cannot edit units if not on a tty.");
7d4fb3b1
RC
6487 return -EINVAL;
6488 }
6489
6490 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4fbd7192 6491 log_error("Cannot edit units remotely.");
7d4fb3b1
RC
6492 return -EINVAL;
6493 }
6494
4fbd7192
LP
6495 r = acquire_bus(BUS_MANAGER, &bus);
6496 if (r < 0)
6497 return r;
6498
e449de87 6499 r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
7d4fb3b1
RC
6500 if (r < 0)
6501 return log_error_errno(r, "Failed to expand names: %m");
6502
7d4fb3b1
RC
6503 r = find_paths_to_edit(bus, names, &paths);
6504 if (r < 0)
6505 return r;
6506
b5e6a600 6507 if (strv_isempty(paths))
7d4fb3b1 6508 return -ENOENT;
7d4fb3b1
RC
6509
6510 r = run_editor(paths);
6511 if (r < 0)
6512 goto end;
6513
6514 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6
LP
6515 /* If the temporary file is empty we ignore it. It's
6516 * useful if the user wants to cancel its modification
7d4fb3b1
RC
6517 */
6518 if (null_or_empty_path(*tmp)) {
45519fd6 6519 log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
7d4fb3b1
RC
6520 continue;
6521 }
45519fd6 6522
7d4fb3b1
RC
6523 r = rename(*tmp, *original);
6524 if (r < 0) {
029009d4 6525 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
6526 goto end;
6527 }
6528 }
6529
45519fd6
LP
6530 r = 0;
6531
6532 if (!arg_no_reload && !install_client_side())
e449de87 6533 r = daemon_reload(argc, argv, userdata);
7d4fb3b1
RC
6534
6535end:
5f18271e 6536 STRV_FOREACH_PAIR(original, tmp, paths) {
45519fd6 6537 (void) unlink(*tmp);
7d4fb3b1 6538
5f18271e
RC
6539 /* Removing empty dropin dirs */
6540 if (!arg_full) {
043717f9
RC
6541 _cleanup_free_ char *dir;
6542
6543 dir = dirname_malloc(*original);
6544 if (!dir)
6545 return log_oom();
6546
5f18271e
RC
6547 /* no need to check if the dir is empty, rmdir
6548 * does nothing if it is not the case.
6549 */
6550 (void) rmdir(dir);
6551 }
6552 }
6553
7d4fb3b1
RC
6554 return r;
6555}
6556
601185b4 6557static void systemctl_help(void) {
7e4249b9 6558
ea4b98e6 6559 pager_open(arg_no_pager, false);
729e3769 6560
2e33c433 6561 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 6562 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
6563 " -h --help Show this help\n"
6564 " --version Show package version\n"
f459b602
MAP
6565 " --system Connect to system manager\n"
6566 " --user Connect to user service manager\n"
6567 " -H --host=[USER@]HOST\n"
6568 " Operate on remote host\n"
6569 " -M --machine=CONTAINER\n"
6570 " Operate on local container\n"
3fb90db2
ZJS
6571 " -t --type=TYPE List units of a particular type\n"
6572 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 6573 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
6574 " -a --all Show all loaded units/properties, including dead/empty\n"
6575 " ones. To list all units installed on the system, use\n"
6576 " the 'list-unit-files' command instead.\n"
98a6e132 6577 " -l --full Don't ellipsize unit names on output\n"
1238ee09 6578 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
6579 " --reverse Show reverse dependencies with 'list-dependencies'\n"
6580 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
6581 " queueing a new job\n"
a521ae4a 6582 " --show-types When showing sockets, explicitly show their type\n"
4f9a9105 6583 " --value When showing properties, only print the value\n"
b37844d3
LP
6584 " -i --ignore-inhibitors\n"
6585 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
6586 " --kill-who=WHO Who to send signal to\n"
6587 " -s --signal=SIGNAL Which signal to send\n"
57ab2eab 6588 " --now Start or stop unit in addition to enabling or disabling it\n"
8a0867d6
LP
6589 " -q --quiet Suppress output\n"
6590 " --no-block Do not wait until operation finished\n"
8a0867d6 6591 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 6592 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 6593 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 6594 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
6595 " --no-ask-password\n"
6596 " Do not ask for system passwords\n"
a8f11321 6597 " --global Enable/disable unit files globally\n"
a521ae4a 6598 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
6599 " -f --force When enabling unit files, override existing symlinks\n"
6600 " When shutting down, execute action immediately\n"
3fb90db2 6601 " --preset-mode= Apply only enable, only disable, or all presets\n"
729e3769 6602 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 6603 " -n --lines=INTEGER Number of journal entries to show\n"
584c6e70
ZJS
6604 " -o --output=STRING Change journal output mode (short, short-precise,\n"
6605 " short-iso, short-full, short-monotonic, short-unix,\n"
6606 " verbose, export, json, json-pretty, json-sse, cat)\n"
5bdf2243 6607 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 6608 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 6609 "Unit Commands:\n"
d8fba7c6
ZJS
6610 " list-units [PATTERN...] List loaded units\n"
6611 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
6612 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
6613 " start NAME... Start (activate) one or more units\n"
6614 " stop NAME... Stop (deactivate) one or more units\n"
6615 " reload NAME... Reload one or more units\n"
6616 " restart NAME... Start or restart one or more units\n"
6617 " try-restart NAME... Restart one or more units if active\n"
6618 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 6619 " otherwise start or restart\n"
aabf5d42
LP
6620 " try-reload-or-restart NAME... If active, reload one or more units,\n"
6621 " if supported, otherwise restart\n"
4f8f66cb
ZJS
6622 " isolate NAME Start one unit and stop all others\n"
6623 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
6624 " is-active PATTERN... Check whether units are active\n"
6625 " is-failed PATTERN... Check whether units are failed\n"
6626 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
6627 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 6628 " units/jobs or the manager\n"
b3ae710c 6629 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 6630 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
6631 " help PATTERN...|PID... Show manual for one or more units\n"
6632 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 6633 " units\n"
55c0b89c 6634 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
6635 " or wanted by this unit or by which this\n"
6636 " unit is required or wanted\n\n"
34c4b47b 6637 "Unit File Commands:\n"
d8fba7c6 6638 " list-unit-files [PATTERN...] List installed unit files\n"
3990961d 6639 " enable [NAME...|PATH...] Enable one or more unit files\n"
4f8f66cb
ZJS
6640 " disable NAME... Disable one or more unit files\n"
6641 " reenable NAME... Reenable one or more unit files\n"
6642 " preset NAME... Enable/disable one or more unit files\n"
729e3769 6643 " based on preset configuration\n"
d309c1c3
LP
6644 " preset-all Enable/disable all unit files based on\n"
6645 " preset configuration\n"
b619ec8f 6646 " is-enabled NAME... Check whether unit files are enabled\n"
4f8f66cb
ZJS
6647 " mask NAME... Mask one or more units\n"
6648 " unmask NAME... Unmask one or more units\n"
6649 " link PATH... Link one or more units files into\n"
729e3769 6650 " the search path\n"
344ca755
LP
6651 " revert NAME... Revert one or more unit files to vendor\n"
6652 " version\n"
e94937df
LN
6653 " add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
6654 " on specified one or more units\n"
6655 " add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
6656 " on specified one or more units\n"
7d4fb3b1 6657 " edit NAME... Edit one or more unit files\n"
b619ec8f
LP
6658 " get-default Get the name of the default target\n"
6659 " set-default NAME Set the default target\n\n"
0d292f5e
LP
6660 "Machine Commands:\n"
6661 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 6662 "Job Commands:\n"
d8fba7c6 6663 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 6664 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 6665 "Environment Commands:\n"
7e4249b9 6666 " show-environment Dump environment\n"
4f8f66cb 6667 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a 6668 " unset-environment NAME... Unset one or more environment variables\n"
3fb90db2 6669 " import-environment [NAME...] Import all or some environment variables\n\n"
34c4b47b
LP
6670 "Manager Lifecycle Commands:\n"
6671 " daemon-reload Reload systemd manager configuration\n"
6672 " daemon-reexec Reexecute systemd manager\n\n"
6673 "System Commands:\n"
99813a19 6674 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
6675 " default Enter system default mode\n"
6676 " rescue Enter system rescue mode\n"
6677 " emergency Enter system emergency mode\n"
514f4ef5 6678 " halt Shut down and halt the system\n"
2e33c433 6679 " poweroff Shut down and power-off the system\n"
37185ec8 6680 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 6681 " kexec Shut down and reboot the system with kexec\n"
287419c1 6682 " exit [EXIT_CODE] Request user instance or container exit\n"
4f8f66cb 6683 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 6684 " suspend Suspend the system\n"
6524990f
LP
6685 " hibernate Hibernate the system\n"
6686 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 6687 program_invocation_short_name);
7e4249b9
LP
6688}
6689
601185b4 6690static void halt_help(void) {
37185ec8 6691 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
6692 "%s the system.\n\n"
6693 " --help Show this help\n"
6694 " --halt Halt the machine\n"
6695 " -p --poweroff Switch off the machine\n"
6696 " --reboot Reboot the machine\n"
2e33c433
LP
6697 " -f --force Force immediate halt/power-off/reboot\n"
6698 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 6699 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 6700 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 6701 program_invocation_short_name,
37185ec8 6702 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
6703 arg_action == ACTION_REBOOT ? "Reboot" :
6704 arg_action == ACTION_POWEROFF ? "Power off" :
6705 "Halt");
e4b61340
LP
6706}
6707
601185b4 6708static void shutdown_help(void) {
08e4b1c5 6709 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
6710 "Shut down the system.\n\n"
6711 " --help Show this help\n"
6712 " -H --halt Halt the machine\n"
6713 " -P --poweroff Power-off the machine\n"
6714 " -r --reboot Reboot the machine\n"
386da858 6715 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 6716 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 6717 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 6718 " -c Cancel a pending shutdown\n",
e4b61340 6719 program_invocation_short_name);
e4b61340
LP
6720}
6721
601185b4 6722static void telinit_help(void) {
2e33c433 6723 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
6724 "Send control commands to the init daemon.\n\n"
6725 " --help Show this help\n"
2e33c433 6726 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
6727 "Commands:\n"
6728 " 0 Power-off the machine\n"
6729 " 6 Reboot the machine\n"
514f4ef5
LP
6730 " 2, 3, 4, 5 Start runlevelX.target unit\n"
6731 " 1, s, S Enter rescue mode\n"
6732 " q, Q Reload init daemon configuration\n"
6733 " u, U Reexecute init daemon\n",
e4b61340 6734 program_invocation_short_name);
e4b61340
LP
6735}
6736
601185b4 6737static void runlevel_help(void) {
2e33c433 6738 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
6739 "Prints the previous and current runlevel of the init system.\n\n"
6740 " --help Show this help\n",
6741 program_invocation_short_name);
e4b61340
LP
6742}
6743
b93312f5 6744static void help_types(void) {
45c0c61d
ZJS
6745 int i;
6746
b93312f5
ZJS
6747 if (!arg_no_legend)
6748 puts("Available unit types:");
e16972e6
ZJS
6749 for (i = 0; i < _UNIT_TYPE_MAX; i++)
6750 puts(unit_type_to_string(i));
6751}
6752
6753static void help_states(void) {
6754 int i;
6755
6756 if (!arg_no_legend)
6757 puts("Available unit load states:");
6758 for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
6759 puts(unit_load_state_to_string(i));
6760
6761 if (!arg_no_legend)
6762 puts("\nAvailable unit active states:");
6763 for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
6764 puts(unit_active_state_to_string(i));
7e55de3b
ZJS
6765
6766 if (!arg_no_legend)
6767 puts("\nAvailable automount unit substates:");
6768 for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
6769 puts(automount_state_to_string(i));
6770
6771 if (!arg_no_legend)
6772 puts("\nAvailable busname unit substates:");
6773 for (i = 0; i < _BUSNAME_STATE_MAX; i++)
6774 puts(busname_state_to_string(i));
6775
6776 if (!arg_no_legend)
6777 puts("\nAvailable device unit substates:");
6778 for (i = 0; i < _DEVICE_STATE_MAX; i++)
6779 puts(device_state_to_string(i));
6780
6781 if (!arg_no_legend)
6782 puts("\nAvailable mount unit substates:");
6783 for (i = 0; i < _MOUNT_STATE_MAX; i++)
6784 puts(mount_state_to_string(i));
6785
6786 if (!arg_no_legend)
6787 puts("\nAvailable path unit substates:");
6788 for (i = 0; i < _PATH_STATE_MAX; i++)
6789 puts(path_state_to_string(i));
6790
6791 if (!arg_no_legend)
6792 puts("\nAvailable scope unit substates:");
6793 for (i = 0; i < _SCOPE_STATE_MAX; i++)
6794 puts(scope_state_to_string(i));
6795
6796 if (!arg_no_legend)
6797 puts("\nAvailable service unit substates:");
6798 for (i = 0; i < _SERVICE_STATE_MAX; i++)
6799 puts(service_state_to_string(i));
6800
6801 if (!arg_no_legend)
6802 puts("\nAvailable slice unit substates:");
6803 for (i = 0; i < _SLICE_STATE_MAX; i++)
6804 puts(slice_state_to_string(i));
6805
7e55de3b
ZJS
6806 if (!arg_no_legend)
6807 puts("\nAvailable socket unit substates:");
6808 for (i = 0; i < _SOCKET_STATE_MAX; i++)
6809 puts(socket_state_to_string(i));
6810
6811 if (!arg_no_legend)
6812 puts("\nAvailable swap unit substates:");
6813 for (i = 0; i < _SWAP_STATE_MAX; i++)
6814 puts(swap_state_to_string(i));
6815
6816 if (!arg_no_legend)
6817 puts("\nAvailable target unit substates:");
6818 for (i = 0; i < _TARGET_STATE_MAX; i++)
6819 puts(target_state_to_string(i));
6820
6821 if (!arg_no_legend)
6822 puts("\nAvailable timer unit substates:");
6823 for (i = 0; i < _TIMER_STATE_MAX; i++)
6824 puts(timer_state_to_string(i));
45c0c61d
ZJS
6825}
6826
e4b61340 6827static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
6828
6829 enum {
90d473a1 6830 ARG_FAIL = 0x100,
afba4199
ZJS
6831 ARG_REVERSE,
6832 ARG_AFTER,
6833 ARG_BEFORE,
991f2a39 6834 ARG_SHOW_TYPES,
23ade460 6835 ARG_IRREVERSIBLE,
e67c3609 6836 ARG_IGNORE_DEPENDENCIES,
4f9a9105 6837 ARG_VALUE,
35df8f27 6838 ARG_VERSION,
af2d49f7 6839 ARG_USER,
7e4249b9 6840 ARG_SYSTEM,
ee5762e3 6841 ARG_GLOBAL,
6e905d93 6842 ARG_NO_BLOCK,
ebed32bf 6843 ARG_NO_LEGEND,
611efaac 6844 ARG_NO_PAGER,
4445a875 6845 ARG_NO_WALL,
be394c48 6846 ARG_ROOT,
ee5762e3 6847 ARG_NO_RELOAD,
501fc174 6848 ARG_KILL_WHO,
30732560 6849 ARG_NO_ASK_PASSWORD,
729e3769 6850 ARG_FAILED,
df50185b 6851 ARG_RUNTIME,
5d0c05e5 6852 ARG_FORCE,
9b9b3d36 6853 ARG_PLAIN,
4dc5b821 6854 ARG_STATE,
d309c1c3
LP
6855 ARG_JOB_MODE,
6856 ARG_PRESET_MODE,
5bdf2243 6857 ARG_FIRMWARE_SETUP,
57ab2eab 6858 ARG_NOW,
9ef15026 6859 ARG_MESSAGE,
7e4249b9
LP
6860 };
6861
6862 static const struct option options[] = {
9ea9d4cf
LP
6863 { "help", no_argument, NULL, 'h' },
6864 { "version", no_argument, NULL, ARG_VERSION },
6865 { "type", required_argument, NULL, 't' },
6866 { "property", required_argument, NULL, 'p' },
6867 { "all", no_argument, NULL, 'a' },
6868 { "reverse", no_argument, NULL, ARG_REVERSE },
6869 { "after", no_argument, NULL, ARG_AFTER },
6870 { "before", no_argument, NULL, ARG_BEFORE },
6871 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
6872 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
6873 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
6874 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
6875 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
6876 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
6877 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf 6878 { "ignore-inhibitors", no_argument, NULL, 'i' },
4f9a9105 6879 { "value", no_argument, NULL, ARG_VALUE },
9ea9d4cf
LP
6880 { "user", no_argument, NULL, ARG_USER },
6881 { "system", no_argument, NULL, ARG_SYSTEM },
6882 { "global", no_argument, NULL, ARG_GLOBAL },
6883 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
6884 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
6885 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6886 { "no-wall", no_argument, NULL, ARG_NO_WALL },
6887 { "quiet", no_argument, NULL, 'q' },
6888 { "root", required_argument, NULL, ARG_ROOT },
6889 { "force", no_argument, NULL, ARG_FORCE },
6890 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
6891 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
6892 { "signal", required_argument, NULL, 's' },
6893 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
6894 { "host", required_argument, NULL, 'H' },
f459b602 6895 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
6896 { "runtime", no_argument, NULL, ARG_RUNTIME },
6897 { "lines", required_argument, NULL, 'n' },
6898 { "output", required_argument, NULL, 'o' },
6899 { "plain", no_argument, NULL, ARG_PLAIN },
6900 { "state", required_argument, NULL, ARG_STATE },
1238ee09 6901 { "recursive", no_argument, NULL, 'r' },
d309c1c3 6902 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
5bdf2243 6903 { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
57ab2eab 6904 { "now", no_argument, NULL, ARG_NOW },
9ef15026 6905 { "message", required_argument, NULL, ARG_MESSAGE },
eb9da376 6906 {}
7e4249b9
LP
6907 };
6908
5ab22f33 6909 const char *p;
0f03c2a4 6910 int c, r;
7e4249b9 6911
e4b61340 6912 assert(argc >= 0);
7e4249b9
LP
6913 assert(argv);
6914
16f017fa
IS
6915 /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
6916 arg_ask_password = true;
6917
601185b4 6918 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
6919
6920 switch (c) {
6921
6922 case 'h':
601185b4
ZJS
6923 systemctl_help();
6924 return 0;
35df8f27
LP
6925
6926 case ARG_VERSION:
3f6fd1ba 6927 return version();
7e4249b9 6928
20b3f379 6929 case 't': {
bf409580
TA
6930 if (isempty(optarg)) {
6931 log_error("--type requires arguments.");
6932 return -EINVAL;
6933 }
45c0c61d 6934
5ab22f33 6935 p = optarg;
9ed794a3 6936 for (;;) {
5ab22f33 6937 _cleanup_free_ char *type = NULL;
20b3f379 6938
5ab22f33
SS
6939 r = extract_first_word(&p, &type, ",", 0);
6940 if (r < 0)
6941 return log_error_errno(r, "Failed to parse type: %s", optarg);
6942
6943 if (r == 0)
6944 break;
20b3f379
ZJS
6945
6946 if (streq(type, "help")) {
6947 help_types();
6948 return 0;
6949 }
6950
6951 if (unit_type_from_string(type) >= 0) {
7e9d36e0 6952 if (strv_push(&arg_types, type) < 0)
20b3f379
ZJS
6953 return log_oom();
6954 type = NULL;
6955 continue;
6956 }
6957
9b9b3d36
MW
6958 /* It's much nicer to use --state= for
6959 * load states, but let's support this
6960 * in --types= too for compatibility
6961 * with old versions */
7e9d36e0 6962 if (unit_load_state_from_string(type) >= 0) {
9b9b3d36 6963 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
6964 return log_oom();
6965 type = NULL;
6966 continue;
6967 }
6968
ab06eef8 6969 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
6970 log_info("Use -t help to see a list of allowed values.");
6971 return -EINVAL;
c147dc42 6972 }
20b3f379
ZJS
6973
6974 break;
6975 }
6976
ea4a240d 6977 case 'p': {
033a842c
ZJS
6978 /* Make sure that if the empty property list
6979 was specified, we won't show any properties. */
20b3f379 6980 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 6981 arg_properties = new0(char*, 1);
20b3f379
ZJS
6982 if (!arg_properties)
6983 return log_oom();
6984 } else {
5ab22f33 6985 p = optarg;
9ed794a3 6986 for (;;) {
5ab22f33 6987 _cleanup_free_ char *prop = NULL;
033a842c 6988
5ab22f33
SS
6989 r = extract_first_word(&p, &prop, ",", 0);
6990 if (r < 0)
6991 return log_error_errno(r, "Failed to parse property: %s", optarg);
033a842c 6992
5ab22f33
SS
6993 if (r == 0)
6994 break;
ea4a240d 6995
5ab22f33 6996 if (strv_push(&arg_properties, prop) < 0)
20b3f379 6997 return log_oom();
5ab22f33
SS
6998
6999 prop = NULL;
20b3f379 7000 }
033a842c 7001 }
48220598
LP
7002
7003 /* If the user asked for a particular
7004 * property, show it to him, even if it is
7005 * empty. */
7006 arg_all = true;
033a842c 7007
48220598 7008 break;
ea4a240d 7009 }
48220598 7010
7e4249b9
LP
7011 case 'a':
7012 arg_all = true;
7013 break;
7014
afba4199
ZJS
7015 case ARG_REVERSE:
7016 arg_dependency = DEPENDENCY_REVERSE;
7017 break;
7018
7019 case ARG_AFTER:
7020 arg_dependency = DEPENDENCY_AFTER;
7021 break;
7022
7023 case ARG_BEFORE:
7024 arg_dependency = DEPENDENCY_BEFORE;
7025 break;
7026
991f2a39
ZJS
7027 case ARG_SHOW_TYPES:
7028 arg_show_types = true;
7029 break;
7030
4f9a9105
ZJS
7031 case ARG_VALUE:
7032 arg_value = true;
7033 break;
7034
4dc5b821
LP
7035 case ARG_JOB_MODE:
7036 arg_job_mode = optarg;
7037 break;
7038
90d473a1 7039 case ARG_FAIL:
e67c3609
LP
7040 arg_job_mode = "fail";
7041 break;
7042
23ade460
MS
7043 case ARG_IRREVERSIBLE:
7044 arg_job_mode = "replace-irreversibly";
7045 break;
7046
e67c3609
LP
7047 case ARG_IGNORE_DEPENDENCIES:
7048 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
7049 break;
7050
af2d49f7 7051 case ARG_USER:
729e3769 7052 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
7053 break;
7054
7055 case ARG_SYSTEM:
729e3769
LP
7056 arg_scope = UNIT_FILE_SYSTEM;
7057 break;
7058
7059 case ARG_GLOBAL:
7060 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
7061 break;
7062
6e905d93
LP
7063 case ARG_NO_BLOCK:
7064 arg_no_block = true;
7e4249b9
LP
7065 break;
7066
ebed32bf
MS
7067 case ARG_NO_LEGEND:
7068 arg_no_legend = true;
7069 break;
7070
611efaac
LP
7071 case ARG_NO_PAGER:
7072 arg_no_pager = true;
7073 break;
0736af98 7074
514f4ef5
LP
7075 case ARG_NO_WALL:
7076 arg_no_wall = true;
7077 break;
7078
be394c48 7079 case ARG_ROOT:
bac75eb3 7080 r = parse_path_argument_and_warn(optarg, false, &arg_root);
0f03c2a4
LP
7081 if (r < 0)
7082 return r;
be394c48
FC
7083 break;
7084
98a6e132 7085 case 'l':
8fe914ec
LP
7086 arg_full = true;
7087 break;
7088
30732560 7089 case ARG_FAILED:
9b9b3d36
MW
7090 if (strv_extend(&arg_states, "failed") < 0)
7091 return log_oom();
7092
30732560
LP
7093 break;
7094
0183528f
LP
7095 case 'q':
7096 arg_quiet = true;
7097 break;
7098
568b679f 7099 case ARG_FORCE:
313cefa1 7100 arg_force++;
568b679f
LP
7101 break;
7102
b4f27ccc 7103 case 'f':
313cefa1 7104 arg_force++;
ee5762e3
LP
7105 break;
7106
7107 case ARG_NO_RELOAD:
7108 arg_no_reload = true;
7109 break;
7110
8a0867d6
LP
7111 case ARG_KILL_WHO:
7112 arg_kill_who = optarg;
7113 break;
7114
8a0867d6 7115 case 's':
691395d8
LP
7116 arg_signal = signal_from_string_try_harder(optarg);
7117 if (arg_signal < 0) {
8a0867d6
LP
7118 log_error("Failed to parse signal string %s.", optarg);
7119 return -EINVAL;
7120 }
7121 break;
7122
501fc174
LP
7123 case ARG_NO_ASK_PASSWORD:
7124 arg_ask_password = false;
7125 break;
7126
f459b602
MAP
7127 case 'H':
7128 arg_transport = BUS_TRANSPORT_REMOTE;
7129 arg_host = optarg;
a8f11321
LP
7130 break;
7131
f459b602 7132 case 'M':
de33fc62 7133 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 7134 arg_host = optarg;
a8f11321
LP
7135 break;
7136
729e3769
LP
7137 case ARG_RUNTIME:
7138 arg_runtime = true;
7139 break;
7140
df50185b
LP
7141 case 'n':
7142 if (safe_atou(optarg, &arg_lines) < 0) {
7143 log_error("Failed to parse lines '%s'", optarg);
7144 return -EINVAL;
7145 }
7146 break;
7147
df50185b
LP
7148 case 'o':
7149 arg_output = output_mode_from_string(optarg);
7150 if (arg_output < 0) {
7151 log_error("Unknown output '%s'.", optarg);
7152 return -EINVAL;
7153 }
7154 break;
7155
b37844d3
LP
7156 case 'i':
7157 arg_ignore_inhibitors = true;
7158 break;
7159
5d0c05e5
LN
7160 case ARG_PLAIN:
7161 arg_plain = true;
7162 break;
7163
5bdf2243
JJ
7164 case ARG_FIRMWARE_SETUP:
7165 arg_firmware_setup = true;
7166 break;
7167
9b9b3d36 7168 case ARG_STATE: {
bf409580
TA
7169 if (isempty(optarg)) {
7170 log_error("--signal requires arguments.");
7171 return -EINVAL;
7172 }
9b9b3d36 7173
5ab22f33 7174 p = optarg;
9ed794a3 7175 for (;;) {
bc6c18fe 7176 _cleanup_free_ char *s = NULL;
9b9b3d36 7177
5ab22f33
SS
7178 r = extract_first_word(&p, &s, ",", 0);
7179 if (r < 0)
7180 return log_error_errno(r, "Failed to parse signal: %s", optarg);
7181
7182 if (r == 0)
7183 break;
9b9b3d36 7184
e16972e6
ZJS
7185 if (streq(s, "help")) {
7186 help_states();
7187 return 0;
7188 }
7189
7e9d36e0 7190 if (strv_push(&arg_states, s) < 0)
9b9b3d36 7191 return log_oom();
7e9d36e0
LP
7192
7193 s = NULL;
9b9b3d36
MW
7194 }
7195 break;
7196 }
7197
1238ee09
LP
7198 case 'r':
7199 if (geteuid() != 0) {
f1721625 7200 log_error("--recursive requires root privileges.");
1238ee09
LP
7201 return -EPERM;
7202 }
7203
7204 arg_recursive = true;
7205 break;
7206
d309c1c3
LP
7207 case ARG_PRESET_MODE:
7208
7209 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
7210 if (arg_preset_mode < 0) {
7211 log_error("Failed to parse preset mode: %s.", optarg);
7212 return -EINVAL;
7213 }
7214
7215 break;
7216
57ab2eab
JS
7217 case ARG_NOW:
7218 arg_now = true;
7219 break;
7220
9ef15026
JS
7221 case ARG_MESSAGE:
7222 if (strv_extend(&arg_wall, optarg) < 0)
7223 return log_oom();
7224 break;
7225
7e4249b9
LP
7226 case '?':
7227 return -EINVAL;
7228
7229 default:
eb9da376 7230 assert_not_reached("Unhandled option");
7e4249b9 7231 }
7e4249b9 7232
f459b602 7233 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
7234 log_error("Cannot access user instance remotely.");
7235 return -EINVAL;
7236 }
7237
7e4249b9
LP
7238 return 1;
7239}
7240
e4b61340
LP
7241static int halt_parse_argv(int argc, char *argv[]) {
7242
7243 enum {
7244 ARG_HELP = 0x100,
7245 ARG_HALT,
514f4ef5
LP
7246 ARG_REBOOT,
7247 ARG_NO_WALL
e4b61340
LP
7248 };
7249
7250 static const struct option options[] = {
7251 { "help", no_argument, NULL, ARG_HELP },
7252 { "halt", no_argument, NULL, ARG_HALT },
7253 { "poweroff", no_argument, NULL, 'p' },
7254 { "reboot", no_argument, NULL, ARG_REBOOT },
7255 { "force", no_argument, NULL, 'f' },
7256 { "wtmp-only", no_argument, NULL, 'w' },
7257 { "no-wtmp", no_argument, NULL, 'd' },
f3f054f0 7258 { "no-sync", no_argument, NULL, 'n' },
514f4ef5 7259 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7260 {}
e4b61340
LP
7261 };
7262
37185ec8 7263 int c, r, runlevel;
e4b61340
LP
7264
7265 assert(argc >= 0);
7266 assert(argv);
7267
7268 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
7269 if (runlevel == '0' || runlevel == '6')
65491fd8 7270 arg_force = 2;
e4b61340 7271
601185b4 7272 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
7273 switch (c) {
7274
7275 case ARG_HELP:
601185b4
ZJS
7276 halt_help();
7277 return 0;
e4b61340
LP
7278
7279 case ARG_HALT:
7280 arg_action = ACTION_HALT;
7281 break;
7282
7283 case 'p':
a042efad
MS
7284 if (arg_action != ACTION_REBOOT)
7285 arg_action = ACTION_POWEROFF;
e4b61340
LP
7286 break;
7287
7288 case ARG_REBOOT:
7289 arg_action = ACTION_REBOOT;
7290 break;
7291
7292 case 'f':
65491fd8 7293 arg_force = 2;
e4b61340
LP
7294 break;
7295
7296 case 'w':
7297 arg_dry = true;
7298 break;
7299
7300 case 'd':
7301 arg_no_wtmp = true;
7302 break;
7303
f3f054f0
TB
7304 case 'n':
7305 arg_no_sync = true;
7306 break;
7307
514f4ef5
LP
7308 case ARG_NO_WALL:
7309 arg_no_wall = true;
7310 break;
7311
e4b61340
LP
7312 case 'i':
7313 case 'h':
7314 /* Compatibility nops */
7315 break;
7316
7317 case '?':
7318 return -EINVAL;
7319
7320 default:
eb9da376 7321 assert_not_reached("Unhandled option");
e4b61340 7322 }
e4b61340 7323
c5220a94 7324 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
27c06cb5 7325 r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
c5220a94 7326 if (r < 0)
37185ec8 7327 return r;
37185ec8 7328 } else if (optind < argc) {
e4b61340
LP
7329 log_error("Too many arguments.");
7330 return -EINVAL;
7331 }
7332
7333 return 1;
7334}
7335
2cc7b0a2 7336static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
f6144808
LP
7337 assert(t);
7338 assert(_u);
7339
7340 if (streq(t, "now"))
7341 *_u = 0;
1a639877 7342 else if (!strchr(t, ':')) {
f6144808
LP
7343 uint64_t u;
7344
1a639877 7345 if (safe_atou64(t, &u) < 0)
f6144808
LP
7346 return -EINVAL;
7347
7348 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
7349 } else {
7350 char *e = NULL;
7351 long hour, minute;
b92bea5d 7352 struct tm tm = {};
f6144808
LP
7353 time_t s;
7354 usec_t n;
7355
7356 errno = 0;
7357 hour = strtol(t, &e, 10);
8333c77e 7358 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
7359 return -EINVAL;
7360
7361 minute = strtol(e+1, &e, 10);
8333c77e 7362 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
7363 return -EINVAL;
7364
7365 n = now(CLOCK_REALTIME);
08e4b1c5
LP
7366 s = (time_t) (n / USEC_PER_SEC);
7367
f6144808
LP
7368 assert_se(localtime_r(&s, &tm));
7369
7370 tm.tm_hour = (int) hour;
7371 tm.tm_min = (int) minute;
08e4b1c5 7372 tm.tm_sec = 0;
f6144808
LP
7373
7374 assert_se(s = mktime(&tm));
7375
7376 *_u = (usec_t) s * USEC_PER_SEC;
7377
7378 while (*_u <= n)
7379 *_u += USEC_PER_DAY;
7380 }
7381
7382 return 0;
7383}
7384
e4b61340
LP
7385static int shutdown_parse_argv(int argc, char *argv[]) {
7386
7387 enum {
7388 ARG_HELP = 0x100,
514f4ef5 7389 ARG_NO_WALL
e4b61340
LP
7390 };
7391
7392 static const struct option options[] = {
7393 { "help", no_argument, NULL, ARG_HELP },
7394 { "halt", no_argument, NULL, 'H' },
7395 { "poweroff", no_argument, NULL, 'P' },
7396 { "reboot", no_argument, NULL, 'r' },
04ebb595 7397 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 7398 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7399 {}
e4b61340
LP
7400 };
7401
172d7abf 7402 char **wall = NULL;
f6144808 7403 int c, r;
e4b61340
LP
7404
7405 assert(argc >= 0);
7406 assert(argv);
7407
a4420f7b 7408 while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0)
e4b61340
LP
7409 switch (c) {
7410
7411 case ARG_HELP:
601185b4
ZJS
7412 shutdown_help();
7413 return 0;
e4b61340
LP
7414
7415 case 'H':
7416 arg_action = ACTION_HALT;
7417 break;
7418
7419 case 'P':
7420 arg_action = ACTION_POWEROFF;
7421 break;
7422
7423 case 'r':
5622dde3
KS
7424 if (kexec_loaded())
7425 arg_action = ACTION_KEXEC;
7426 else
7427 arg_action = ACTION_REBOOT;
e4b61340
LP
7428 break;
7429
04ebb595
LP
7430 case 'K':
7431 arg_action = ACTION_KEXEC;
7432 break;
7433
e4b61340
LP
7434 case 'h':
7435 if (arg_action != ACTION_HALT)
7436 arg_action = ACTION_POWEROFF;
7437 break;
7438
7439 case 'k':
7440 arg_dry = true;
7441 break;
7442
514f4ef5
LP
7443 case ARG_NO_WALL:
7444 arg_no_wall = true;
7445 break;
7446
e4b61340
LP
7447 case 't':
7448 case 'a':
75836b9d
JS
7449 case 'f':
7450 case 'F':
e4b61340
LP
7451 /* Compatibility nops */
7452 break;
7453
f6144808
LP
7454 case 'c':
7455 arg_action = ACTION_CANCEL_SHUTDOWN;
7456 break;
7457
e4b61340
LP
7458 case '?':
7459 return -EINVAL;
7460
7461 default:
eb9da376 7462 assert_not_reached("Unhandled option");
e4b61340 7463 }
e4b61340 7464
dfcc5c33 7465 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
2cc7b0a2 7466 r = parse_shutdown_time_spec(argv[optind], &arg_when);
7e59bfcb 7467 if (r < 0) {
f6144808
LP
7468 log_error("Failed to parse time specification: %s", argv[optind]);
7469 return r;
7470 }
6b5ad000 7471 } else
08e4b1c5 7472 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 7473
dfcc5c33
MS
7474 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
7475 /* No time argument for shutdown cancel */
172d7abf 7476 wall = argv + optind;
dfcc5c33
MS
7477 else if (argc > optind + 1)
7478 /* We skip the time argument */
172d7abf
LP
7479 wall = argv + optind + 1;
7480
7481 if (wall) {
7482 arg_wall = strv_copy(wall);
7483 if (!arg_wall)
7484 return log_oom();
7485 }
e4b61340
LP
7486
7487 optind = argc;
7488
7489 return 1;
e4b61340
LP
7490}
7491
7492static int telinit_parse_argv(int argc, char *argv[]) {
7493
7494 enum {
7495 ARG_HELP = 0x100,
514f4ef5 7496 ARG_NO_WALL
e4b61340
LP
7497 };
7498
7499 static const struct option options[] = {
7500 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 7501 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 7502 {}
e4b61340
LP
7503 };
7504
7505 static const struct {
7506 char from;
7507 enum action to;
7508 } table[] = {
7509 { '0', ACTION_POWEROFF },
7510 { '6', ACTION_REBOOT },
ef2f1067 7511 { '1', ACTION_RESCUE },
e4b61340
LP
7512 { '2', ACTION_RUNLEVEL2 },
7513 { '3', ACTION_RUNLEVEL3 },
7514 { '4', ACTION_RUNLEVEL4 },
7515 { '5', ACTION_RUNLEVEL5 },
7516 { 's', ACTION_RESCUE },
7517 { 'S', ACTION_RESCUE },
7518 { 'q', ACTION_RELOAD },
7519 { 'Q', ACTION_RELOAD },
7520 { 'u', ACTION_REEXEC },
7521 { 'U', ACTION_REEXEC }
7522 };
7523
7524 unsigned i;
7525 int c;
7526
7527 assert(argc >= 0);
7528 assert(argv);
7529
601185b4 7530 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7531 switch (c) {
7532
7533 case ARG_HELP:
601185b4
ZJS
7534 telinit_help();
7535 return 0;
e4b61340 7536
514f4ef5
LP
7537 case ARG_NO_WALL:
7538 arg_no_wall = true;
7539 break;
7540
e4b61340
LP
7541 case '?':
7542 return -EINVAL;
7543
7544 default:
eb9da376 7545 assert_not_reached("Unhandled option");
e4b61340 7546 }
e4b61340
LP
7547
7548 if (optind >= argc) {
691395d8 7549 log_error("%s: required argument missing.", program_invocation_short_name);
e4b61340
LP
7550 return -EINVAL;
7551 }
7552
7553 if (optind + 1 < argc) {
7554 log_error("Too many arguments.");
7555 return -EINVAL;
7556 }
7557
7558 if (strlen(argv[optind]) != 1) {
7559 log_error("Expected single character argument.");
7560 return -EINVAL;
7561 }
7562
7563 for (i = 0; i < ELEMENTSOF(table); i++)
7564 if (table[i].from == argv[optind][0])
7565 break;
7566
7567 if (i >= ELEMENTSOF(table)) {
b0193f1c 7568 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
7569 return -EINVAL;
7570 }
7571
7572 arg_action = table[i].to;
7573
313cefa1 7574 optind++;
e4b61340
LP
7575
7576 return 1;
7577}
7578
7579static int runlevel_parse_argv(int argc, char *argv[]) {
7580
7581 enum {
7582 ARG_HELP = 0x100,
7583 };
7584
7585 static const struct option options[] = {
7586 { "help", no_argument, NULL, ARG_HELP },
eb9da376 7587 {}
e4b61340
LP
7588 };
7589
7590 int c;
7591
7592 assert(argc >= 0);
7593 assert(argv);
7594
601185b4 7595 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
7596 switch (c) {
7597
7598 case ARG_HELP:
601185b4
ZJS
7599 runlevel_help();
7600 return 0;
e4b61340
LP
7601
7602 case '?':
7603 return -EINVAL;
7604
7605 default:
eb9da376 7606 assert_not_reached("Unhandled option");
e4b61340 7607 }
e4b61340
LP
7608
7609 if (optind < argc) {
7610 log_error("Too many arguments.");
7611 return -EINVAL;
7612 }
7613
7614 return 1;
7615}
7616
7617static int parse_argv(int argc, char *argv[]) {
7618 assert(argc >= 0);
7619 assert(argv);
7620
7621 if (program_invocation_short_name) {
7622
7623 if (strstr(program_invocation_short_name, "halt")) {
7624 arg_action = ACTION_HALT;
7625 return halt_parse_argv(argc, argv);
7626 } else if (strstr(program_invocation_short_name, "poweroff")) {
7627 arg_action = ACTION_POWEROFF;
7628 return halt_parse_argv(argc, argv);
7629 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
7630 if (kexec_loaded())
7631 arg_action = ACTION_KEXEC;
7632 else
7633 arg_action = ACTION_REBOOT;
e4b61340
LP
7634 return halt_parse_argv(argc, argv);
7635 } else if (strstr(program_invocation_short_name, "shutdown")) {
7636 arg_action = ACTION_POWEROFF;
7637 return shutdown_parse_argv(argc, argv);
7638 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
7639
7640 if (sd_booted() > 0) {
f459b602 7641 arg_action = _ACTION_INVALID;
d5ca5f11
LP
7642 return telinit_parse_argv(argc, argv);
7643 } else {
7644 /* Hmm, so some other init system is
7645 * running, we need to forward this
7646 * request to it. For now we simply
7647 * guess that it is Upstart. */
7648
4ad61fd1 7649 execv(TELINIT, argv);
d5ca5f11
LP
7650
7651 log_error("Couldn't find an alternative telinit implementation to spawn.");
7652 return -EIO;
7653 }
7654
e4b61340
LP
7655 } else if (strstr(program_invocation_short_name, "runlevel")) {
7656 arg_action = ACTION_RUNLEVEL;
7657 return runlevel_parse_argv(argc, argv);
7658 }
7659 }
7660
7661 arg_action = ACTION_SYSTEMCTL;
7662 return systemctl_parse_argv(argc, argv);
7663}
7664
d2e79673 7665#ifdef HAVE_SYSV_COMPAT
44a6b1b6 7666_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
7667
7668 static const char table[_ACTION_MAX] = {
7669 [ACTION_HALT] = '0',
7670 [ACTION_POWEROFF] = '0',
7671 [ACTION_REBOOT] = '6',
7672 [ACTION_RUNLEVEL2] = '2',
7673 [ACTION_RUNLEVEL3] = '3',
7674 [ACTION_RUNLEVEL4] = '4',
7675 [ACTION_RUNLEVEL5] = '5',
7676 [ACTION_RESCUE] = '1'
7677 };
7678
d55ae9e6
LP
7679 assert(arg_action < _ACTION_MAX);
7680
7681 return table[arg_action];
7682}
d2e79673 7683#endif
d55ae9e6 7684
d55ae9e6 7685static int talk_initctl(void) {
eca830be 7686#ifdef HAVE_SYSV_COMPAT
cbc9fbd1
LP
7687 struct init_request request = {
7688 .magic = INIT_MAGIC,
7689 .sleeptime = 0,
7690 .cmd = INIT_CMD_RUNLVL
7691 };
7692
7fd1b19b 7693 _cleanup_close_ int fd = -1;
d55ae9e6 7694 char rl;
cbc9fbd1 7695 int r;
eb22ac37 7696
427b47c4
ZJS
7697 rl = action_to_runlevel();
7698 if (!rl)
eb22ac37
LP
7699 return 0;
7700
d55ae9e6
LP
7701 request.runlevel = rl;
7702
427b47c4
ZJS
7703 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
7704 if (fd < 0) {
d55ae9e6
LP
7705 if (errno == ENOENT)
7706 return 0;
eb22ac37 7707
eca830be 7708 return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
d55ae9e6 7709 }
eb22ac37 7710
553acb7b
ZJS
7711 r = loop_write(fd, &request, sizeof(request), false);
7712 if (r < 0)
7713 return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
eb22ac37
LP
7714
7715 return 1;
eca830be
LP
7716#else
7717 return 0;
7718#endif
e4b61340
LP
7719}
7720
e449de87
LP
7721static int systemctl_main(int argc, char *argv[]) {
7722
7723 static const Verb verbs[] = {
1e726cc9 7724 { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_NOCHROOT, list_units },
988b3b17
ZJS
7725 { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
7726 { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets },
7727 { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers },
7728 { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs },
7729 { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines },
7730 { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, trivial_method },
7731 { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job },
7732 { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
7733 { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
7734 { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
7735 { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
7736 { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
7737 { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
7738 { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
7739 { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */
7740 { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
7741 { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */
7742 { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
7743 { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */
7744 { "isolate", 2, 2, VERB_NOCHROOT, start_unit },
7745 { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit },
7746 { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
7747 { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
7748 { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed },
7749 { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
7750 { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat },
7751 { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
7752 { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
7753 { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
7754 { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
7755 { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment },
7756 { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
7757 { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
7758 { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment },
7759 { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7760 { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7761 { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_system_special },
7762 { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7763 { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7764 { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7765 { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7766 { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special },
7767 { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7768 { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
7769 { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special },
7770 { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed },
7771 { "enable", 2, VERB_ANY, 0, enable_unit },
7772 { "disable", 2, VERB_ANY, 0, enable_unit },
7773 { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
7774 { "reenable", 2, VERB_ANY, 0, enable_unit },
7775 { "preset", 2, VERB_ANY, 0, enable_unit },
7776 { "preset-all", VERB_ANY, 1, 0, preset_all },
7777 { "mask", 2, VERB_ANY, 0, enable_unit },
7778 { "unmask", 2, VERB_ANY, 0, enable_unit },
7779 { "link", 2, VERB_ANY, 0, enable_unit },
7780 { "revert", 2, VERB_ANY, 0, enable_unit },
7781 { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
7782 { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
7783 { "set-default", 2, 2, 0, set_default },
7784 { "get-default", VERB_ANY, 1, 0, get_default },
7785 { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property },
7786 { "is-system-running", VERB_ANY, 1, 0, is_system_running },
7787 { "add-wants", 3, VERB_ANY, 0, add_dependency },
7788 { "add-requires", 3, VERB_ANY, 0, add_dependency },
7789 { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit },
d08e75ed 7790 {}
e449de87 7791 };
7e4249b9 7792
e449de87 7793 return dispatch_verb(argc, argv, verbs, NULL);
e4b61340
LP
7794}
7795
4fbd7192 7796static int reload_with_fallback(void) {
e4b61340 7797
4fbd7192 7798 /* First, try systemd via D-Bus. */
e449de87 7799 if (daemon_reload(0, NULL, NULL) >= 0)
4fbd7192 7800 return 0;
e4b61340
LP
7801
7802 /* Nothing else worked, so let's try signals */
2853b60a 7803 assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
e4b61340 7804
4a62c710
MS
7805 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
7806 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
7807
7808 return 0;
7809}
7810
4fbd7192 7811static int start_with_fallback(void) {
e4b61340 7812
4fbd7192 7813 /* First, try systemd via D-Bus. */
e449de87 7814 if (start_unit(0, NULL, NULL) >= 0)
4fbd7192 7815 return 0;
e4b61340 7816
2853b60a 7817 /* Nothing else worked, so let's try /dev/initctl */
fbc43921 7818 if (talk_initctl() > 0)
48ec22bc 7819 return 0;
d55ae9e6
LP
7820
7821 log_error("Failed to talk to init daemon.");
7822 return -EIO;
e4b61340
LP
7823}
7824
477def80 7825static int halt_now(enum action a) {
27c06cb5 7826 int r;
e606bb61 7827
4a3ad399
LP
7828 /* The kernel will automaticall flush ATA disks and suchlike
7829 * on reboot(), but the file systems need to be synce'd
7830 * explicitly in advance. */
f3f054f0
TB
7831 if (!arg_no_sync)
7832 (void) sync();
4a3ad399
LP
7833
7834 /* Make sure C-A-D is handled by the kernel from this point
7835 * on... */
19578bb2 7836 (void) reboot(RB_ENABLE_CAD);
e606bb61 7837
4c80c73c 7838 switch (a) {
e606bb61
LP
7839
7840 case ACTION_HALT:
7841 log_info("Halting.");
19578bb2 7842 (void) reboot(RB_HALT_SYSTEM);
477def80 7843 return -errno;
e606bb61
LP
7844
7845 case ACTION_POWEROFF:
7846 log_info("Powering off.");
19578bb2 7847 (void) reboot(RB_POWER_OFF);
477def80 7848 return -errno;
e606bb61 7849
98d52feb 7850 case ACTION_KEXEC:
477def80
LP
7851 case ACTION_REBOOT: {
7852 _cleanup_free_ char *param = NULL;
cbc9fbd1 7853
27c06cb5
LP
7854 r = read_one_line_file("/run/systemd/reboot-param", &param);
7855 if (r < 0)
7856 log_warning_errno(r, "Failed to read reboot parameter file: %m");
7857
7858 if (!isempty(param)) {
477def80 7859 log_info("Rebooting with argument '%s'.", param);
19578bb2 7860 (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
27c06cb5 7861 log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
37185ec8 7862 }
e606bb61 7863
477def80 7864 log_info("Rebooting.");
19578bb2 7865 (void) reboot(RB_AUTOBOOT);
477def80 7866 return -errno;
e606bb61
LP
7867 }
7868
477def80
LP
7869 default:
7870 assert_not_reached("Unknown action.");
7871 }
e606bb61
LP
7872}
7873
56a730fa
LP
7874static int logind_schedule_shutdown(void) {
7875
7876#ifdef HAVE_LOGIND
4afd3348 7877 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
56a730fa
LP
7878 char date[FORMAT_TIMESTAMP_MAX];
7879 const char *action;
4fbd7192 7880 sd_bus *bus;
56a730fa
LP
7881 int r;
7882
4fbd7192 7883 r = acquire_bus(BUS_FULL, &bus);
56a730fa 7884 if (r < 0)
4fbd7192 7885 return r;
56a730fa
LP
7886
7887 switch (arg_action) {
7888 case ACTION_HALT:
7889 action = "halt";
7890 break;
7891 case ACTION_POWEROFF:
7892 action = "poweroff";
7893 break;
7894 case ACTION_KEXEC:
7895 action = "kexec";
7896 break;
a4420f7b
LP
7897 case ACTION_EXIT:
7898 action = "exit";
7899 break;
7900 case ACTION_REBOOT:
56a730fa
LP
7901 default:
7902 action = "reboot";
7903 break;
7904 }
7905
7906 if (arg_dry)
7907 action = strjoina("dry-", action);
7908
d2ad7e1b
ZJS
7909 (void) logind_set_wall_message();
7910
56a730fa 7911 r = sd_bus_call_method(
4fbd7192 7912 bus,
56a730fa
LP
7913 "org.freedesktop.login1",
7914 "/org/freedesktop/login1",
7915 "org.freedesktop.login1.Manager",
7916 "ScheduleShutdown",
7917 &error,
7918 NULL,
7919 "st",
7920 action,
7921 arg_when);
7922 if (r < 0)
7923 return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
7924
7925 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
7926 return 0;
7927#else
7928 log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
7929 return -ENOSYS;
7930#endif
7931}
7932
4fbd7192 7933static int halt_main(void) {
e4b61340
LP
7934 int r;
7935
4fbd7192 7936 r = logind_check_inhibitors(arg_action);
748ebafa
LP
7937 if (r < 0)
7938 return r;
b37844d3 7939
7f96539d
LP
7940 if (arg_when > 0)
7941 return logind_schedule_shutdown();
7942
bc8c2f5c 7943 if (geteuid() != 0) {
7f96539d 7944 if (arg_dry || arg_force > 0) {
2ac3930f
IS
7945 log_error("Must be root.");
7946 return -EPERM;
7947 }
7948
7e59bfcb
LP
7949 /* Try logind if we are a normal user and no special
7950 * mode applies. Maybe PolicyKit allows us to shutdown
7951 * the machine. */
7f96539d 7952 if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
4fbd7192 7953 r = logind_reboot(arg_action);
4c80c73c
KS
7954 if (r >= 0)
7955 return r;
a9085ea3 7956 if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
7f96539d
LP
7957 /* requested operation is not
7958 * supported on the local system or
7959 * already in progress */
a9085ea3
IS
7960 return r;
7961 /* on all other errors, try low-level operation */
4c80c73c 7962 }
bc8c2f5c
LP
7963 }
7964
65491fd8 7965 if (!arg_dry && !arg_force)
4fbd7192 7966 return start_with_fallback();
e4b61340 7967
2ac3930f
IS
7968 assert(geteuid() == 0);
7969
d90e1a30
LP
7970 if (!arg_no_wtmp) {
7971 if (sd_booted() > 0)
7972 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
7973 else {
7974 r = utmp_put_shutdown();
7975 if (r < 0)
da927ba9 7976 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 7977 }
d90e1a30 7978 }
e4b61340 7979
e4b61340
LP
7980 if (arg_dry)
7981 return 0;
7982
477def80 7983 r = halt_now(arg_action);
691395d8 7984 return log_error_errno(r, "Failed to reboot: %m");
e4b61340
LP
7985}
7986
7987static int runlevel_main(void) {
7988 int r, runlevel, previous;
7989
729e3769
LP
7990 r = utmp_get_runlevel(&runlevel, &previous);
7991 if (r < 0) {
7992 puts("unknown");
e4b61340
LP
7993 return r;
7994 }
7995
7996 printf("%c %c\n",
7997 previous <= 0 ? 'N' : previous,
7998 runlevel <= 0 ? 'N' : runlevel);
7999
8000 return 0;
8001}
8002
2cf05793
LP
8003static int logind_cancel_shutdown(void) {
8004#ifdef HAVE_LOGIND
4afd3348 8005 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
4fbd7192 8006 sd_bus *bus;
949d9ce9
LP
8007 int r;
8008
4fbd7192 8009 r = acquire_bus(BUS_FULL, &bus);
949d9ce9 8010 if (r < 0)
4fbd7192 8011 return r;
949d9ce9 8012
4fbd7192 8013 (void) logind_set_wall_message();
949d9ce9
LP
8014
8015 r = sd_bus_call_method(
4fbd7192 8016 bus,
949d9ce9
LP
8017 "org.freedesktop.login1",
8018 "/org/freedesktop/login1",
8019 "org.freedesktop.login1.Manager",
8020 "CancelScheduledShutdown",
8021 &error,
8022 NULL, NULL);
8023 if (r < 0)
8024 return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
8025
8026 return 0;
2cf05793
LP
8027#else
8028 log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
8029 return -ENOSYS;
8030#endif
949d9ce9
LP
8031}
8032
e4b61340 8033int main(int argc, char*argv[]) {
f459b602 8034 int r;
e4b61340 8035
a9cdc94f 8036 setlocale(LC_ALL, "");
e4b61340 8037 log_parse_environment();
2396fb04 8038 log_open();
592705f2 8039 sigbus_install();
e4b61340 8040
184ecaf7
DR
8041 /* Explicitly not on_tty() to avoid setting cached value.
8042 * This becomes relevant for piping output which might be
8043 * ellipsized. */
8044 original_stdout_is_tty = isatty(STDOUT_FILENO);
8045
04ebb595 8046 r = parse_argv(argc, argv);
f459b602 8047 if (r <= 0)
e4b61340 8048 goto finish;
7e4249b9 8049
040524b4 8050 if (arg_action != ACTION_SYSTEMCTL && running_in_chroot() > 0) {
82e23ddd 8051 log_info("Running in chroot, ignoring request.");
f459b602 8052 r = 0;
82e23ddd
LP
8053 goto finish;
8054 }
8055
41dd15e4
LP
8056 /* systemctl_main() will print an error message for the bus
8057 * connection, but only if it needs to */
e4b61340
LP
8058
8059 switch (arg_action) {
8060
22f4096c 8061 case ACTION_SYSTEMCTL:
e449de87 8062 r = systemctl_main(argc, argv);
e4b61340 8063 break;
e4b61340
LP
8064
8065 case ACTION_HALT:
8066 case ACTION_POWEROFF:
8067 case ACTION_REBOOT:
5622dde3 8068 case ACTION_KEXEC:
4fbd7192 8069 r = halt_main();
e4b61340
LP
8070 break;
8071
e4b61340
LP
8072 case ACTION_RUNLEVEL2:
8073 case ACTION_RUNLEVEL3:
8074 case ACTION_RUNLEVEL4:
8075 case ACTION_RUNLEVEL5:
8076 case ACTION_RESCUE:
514f4ef5 8077 case ACTION_EMERGENCY:
eb22ac37 8078 case ACTION_DEFAULT:
4fbd7192 8079 r = start_with_fallback();
e4b61340 8080 break;
7e4249b9 8081
e4b61340
LP
8082 case ACTION_RELOAD:
8083 case ACTION_REEXEC:
4fbd7192 8084 r = reload_with_fallback();
e4b61340
LP
8085 break;
8086
949d9ce9 8087 case ACTION_CANCEL_SHUTDOWN:
2cf05793 8088 r = logind_cancel_shutdown();
f6144808
LP
8089 break;
8090
eb22ac37 8091 case ACTION_RUNLEVEL:
4f16c1f4
LP
8092 r = runlevel_main();
8093 break;
8094
f459b602 8095 case _ACTION_INVALID:
e4b61340
LP
8096 default:
8097 assert_not_reached("Unknown action");
8098 }
7e4249b9
LP
8099
8100finish:
cf647b69
LP
8101 release_busses();
8102
f459b602
MAP
8103 pager_close();
8104 ask_password_agent_close();
8105 polkit_agent_close();
7e4249b9 8106
20b3f379 8107 strv_free(arg_types);
9b9b3d36 8108 strv_free(arg_states);
20b3f379 8109 strv_free(arg_properties);
ea4a240d 8110
172d7abf 8111 strv_free(arg_wall);
0f03c2a4 8112 free(arg_root);
172d7abf 8113
404f08d3 8114 /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */
9eb4a501 8115 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 8116}