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