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