]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
CODING_STYLE: document order in which to #include headers
[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
355ff449
MP
5152 /* If we have both a native unit and a SysV script,
5153 * enable/disable them both (below); for is-enabled, prefer the
5154 * native unit */
5155 if (found_native && streq(verb, "is-enabled"))
729e3769 5156 continue;
ee5762e3 5157
0c6ea3a4
ZJS
5158 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5159 if (!p)
60731f32 5160 return log_oom();
ee5762e3 5161
05cae7f3 5162 p[strlen(p) - strlen(".service")] = 0;
729e3769 5163 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5164 if (!found_sysv)
729e3769 5165 continue;
71fad675 5166
355ff449
MP
5167 if (found_native)
5168 log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
5169 else
5170 log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
ee5762e3 5171
729e3769
LP
5172 if (!isempty(arg_root))
5173 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5174
0f0467e6 5175 argv[c++] = verb;
2b6bf07d 5176 argv[c++] = basename(p);
729e3769 5177 argv[c] = NULL;
ee5762e3 5178
729e3769 5179 l = strv_join((char**)argv, " ");
60731f32
ZJS
5180 if (!l)
5181 return log_oom();
ee5762e3 5182
729e3769 5183 log_info("Executing %s", l);
ee5762e3 5184
729e3769 5185 pid = fork();
4a62c710
MS
5186 if (pid < 0)
5187 return log_error_errno(errno, "Failed to fork: %m");
5188 else if (pid == 0) {
729e3769 5189 /* Child */
ee5762e3 5190
729e3769 5191 execv(argv[0], (char**) argv);
0f0467e6 5192 log_error("Failed to execute %s: %m", argv[0]);
729e3769
LP
5193 _exit(EXIT_FAILURE);
5194 }
ee5762e3 5195
729e3769
LP
5196 j = wait_for_terminate(pid, &status);
5197 if (j < 0) {
da927ba9 5198 log_error_errno(r, "Failed to wait for child: %m");
60731f32 5199 return j;
729e3769 5200 }
ee5762e3 5201
729e3769
LP
5202 if (status.si_code == CLD_EXITED) {
5203 if (streq(verb, "is-enabled")) {
5204 if (status.si_status == 0) {
5205 if (!arg_quiet)
5206 puts("enabled");
5207 r = 1;
5208 } else {
5209 if (!arg_quiet)
5210 puts("disabled");
5211 }
ee5762e3 5212
60731f32
ZJS
5213 } else if (status.si_status != 0)
5214 return -EINVAL;
5215 } else
5216 return -EPROTO;
ee5762e3 5217
355ff449
MP
5218 if (found_native)
5219 continue;
5220
a644abed 5221 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
5222 assert(f > 0);
5223 f--;
5224 assert(args[f] == name);
5225 strv_remove(args, name);
729e3769 5226 }
ee5762e3 5227
729e3769
LP
5228#endif
5229 return r;
5230}
ee5762e3 5231
37370d0c 5232static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5233 char **i, **l, **name;
7410616c 5234 int r;
37370d0c 5235
7410616c 5236 l = i = new(char*, strv_length(original_names) + 1);
a33fdebb 5237 if (!l)
37370d0c
VP
5238 return log_oom();
5239
37370d0c 5240 STRV_FOREACH(name, original_names) {
44386fc1
LN
5241
5242 /* When enabling units qualified path names are OK,
5243 * too, hence allow them explicitly. */
5244
7410616c 5245 if (is_path(*name)) {
44386fc1 5246 *i = strdup(*name);
7410616c
LP
5247 if (!*i) {
5248 strv_free(l);
5249 return log_oom();
5250 }
5251 } else {
5252 r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
5253 if (r < 0) {
5254 strv_free(l);
5255 return log_error_errno(r, "Failed to mangle unit name: %m");
5256 }
a33fdebb
LP
5257 }
5258
5259 i++;
37370d0c 5260 }
a33fdebb
LP
5261
5262 *i = NULL;
5263 *mangled_names = l;
37370d0c
VP
5264
5265 return 0;
5266}
5267
f459b602 5268static int enable_unit(sd_bus *bus, char **args) {
e3e0314b 5269 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5270 const char *verb = args[0];
5271 UnitFileChange *changes = NULL;
718db961 5272 unsigned n_changes = 0;
729e3769 5273 int carries_install_info = -1;
729e3769 5274 int r;
ee5762e3 5275
ab5919fa
MS
5276 if (!args[1])
5277 return 0;
5278
e3e0314b 5279 r = mangle_names(args+1, &names);
3a05c0f9 5280 if (r < 0)
cbb13b2a
VP
5281 return r;
5282
e3e0314b 5283 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5284 if (r < 0)
5285 return r;
3a05c0f9 5286
67d66210
LP
5287 /* If the operation was fully executed by the SysV compat,
5288 * let's finish early */
5289 if (strv_isempty(names))
5290 return 0;
5291
729e3769
LP
5292 if (!bus || avoid_bus()) {
5293 if (streq(verb, "enable")) {
e3e0314b 5294 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5295 carries_install_info = r;
5296 } else if (streq(verb, "disable"))
e3e0314b 5297 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5298 else if (streq(verb, "reenable")) {
e3e0314b 5299 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5300 carries_install_info = r;
5301 } else if (streq(verb, "link"))
e3e0314b 5302 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5303 else if (streq(verb, "preset")) {
d309c1c3 5304 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769
LP
5305 carries_install_info = r;
5306 } else if (streq(verb, "mask"))
e3e0314b 5307 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5308 else if (streq(verb, "unmask"))
e3e0314b 5309 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769
LP
5310 else
5311 assert_not_reached("Unknown verb");
ee5762e3 5312
729e3769 5313 if (r < 0) {
da927ba9 5314 log_error_errno(r, "Operation failed: %m");
729e3769 5315 goto finish;
ee5762e3
LP
5316 }
5317
718db961
LP
5318 if (!arg_quiet)
5319 dump_unit_file_changes(changes, n_changes);
ee5762e3 5320
df77cdf0 5321 r = 0;
729e3769 5322 } else {
718db961
LP
5323 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5324 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602 5325 int expect_carries_install_info = false;
d309c1c3 5326 bool send_force = true, send_preset_mode = false;
718db961 5327 const char *method;
729e3769 5328
079dac08
LP
5329 polkit_agent_open_if_enabled();
5330
729e3769
LP
5331 if (streq(verb, "enable")) {
5332 method = "EnableUnitFiles";
5333 expect_carries_install_info = true;
5334 } else if (streq(verb, "disable")) {
5335 method = "DisableUnitFiles";
5336 send_force = false;
5337 } else if (streq(verb, "reenable")) {
5338 method = "ReenableUnitFiles";
5339 expect_carries_install_info = true;
5340 } else if (streq(verb, "link"))
5341 method = "LinkUnitFiles";
5342 else if (streq(verb, "preset")) {
d309c1c3
LP
5343
5344 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5345 method = "PresetUnitFilesWithMode";
5346 send_preset_mode = true;
5347 } else
5348 method = "PresetUnitFiles";
5349
729e3769
LP
5350 expect_carries_install_info = true;
5351 } else if (streq(verb, "mask"))
5352 method = "MaskUnitFiles";
5353 else if (streq(verb, "unmask")) {
5354 method = "UnmaskUnitFiles";
5355 send_force = false;
5356 } else
5357 assert_not_reached("Unknown verb");
5358
f459b602
MAP
5359 r = sd_bus_message_new_method_call(
5360 bus,
151b9b96 5361 &m,
729e3769
LP
5362 "org.freedesktop.systemd1",
5363 "/org/freedesktop/systemd1",
5364 "org.freedesktop.systemd1.Manager",
151b9b96 5365 method);
f459b602
MAP
5366 if (r < 0)
5367 return bus_log_create_error(r);
ee5762e3 5368
e3e0314b 5369 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5370 if (r < 0)
5371 return bus_log_create_error(r);
ee5762e3 5372
d309c1c3
LP
5373 if (send_preset_mode) {
5374 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5375 if (r < 0)
5376 return bus_log_create_error(r);
5377 }
5378
f459b602
MAP
5379 r = sd_bus_message_append(m, "b", arg_runtime);
5380 if (r < 0)
5381 return bus_log_create_error(r);
ee5762e3 5382
729e3769 5383 if (send_force) {
f459b602
MAP
5384 r = sd_bus_message_append(m, "b", arg_force);
5385 if (r < 0)
5386 return bus_log_create_error(r);
ee5762e3
LP
5387 }
5388
c49b30a2 5389 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
5390 if (r < 0) {
5391 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5392 return r;
729e3769 5393 }
be394c48 5394
729e3769 5395 if (expect_carries_install_info) {
f459b602
MAP
5396 r = sd_bus_message_read(reply, "b", &carries_install_info);
5397 if (r < 0)
5398 return bus_log_parse_error(r);
ee5762e3
LP
5399 }
5400
57ab2eab 5401 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
f459b602 5402 if (r < 0)
718db961 5403 return r;
b77398f7 5404
93c941e3 5405 /* Try to reload if enabled */
d6cb60c7 5406 if (!arg_no_reload)
729e3769 5407 r = daemon_reload(bus, args);
f459b602
MAP
5408 else
5409 r = 0;
b647f10d 5410 }
3d3961f2 5411
729e3769 5412 if (carries_install_info == 0)
416389f7
LP
5413 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
5414 "using systemctl.\n"
5415 "Possible reasons for having this kind of units are:\n"
5416 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5417 " .wants/ or .requires/ directory.\n"
5418 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5419 " a requirement dependency on it.\n"
5420 "3) A unit may be started when needed via activation (socket, path, timer,\n"
5421 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 5422
57ab2eab
JS
5423 if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
5424 char *new_args[n_changes + 2];
5425 unsigned i;
5426
5427 new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
5428 for (i = 0; i < n_changes; i++)
5429 new_args[i + 1] = basename(changes[i].path);
5430 new_args[i + 1] = NULL;
5431
5432 r = start_unit(bus, new_args);
5433 }
5434
729e3769 5435finish:
729e3769 5436 unit_file_changes_free(changes, n_changes);
ee5762e3 5437
729e3769 5438 return r;
ee5762e3
LP
5439}
5440
e94937df
LN
5441static int add_dependency(sd_bus *bus, char **args) {
5442 _cleanup_strv_free_ char **names = NULL;
5443 _cleanup_free_ char *target = NULL;
5444 const char *verb = args[0];
5445 UnitDependency dep;
5446 int r = 0;
5447
5448 if (!args[1])
5449 return 0;
5450
7410616c
LP
5451 r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
5452 if (r < 0)
5453 return log_error_errno(r, "Failed to mangle unit name: %m");
e94937df
LN
5454
5455 r = mangle_names(args+2, &names);
5456 if (r < 0)
5457 return r;
5458
5459 if (streq(verb, "add-wants"))
5460 dep = UNIT_WANTS;
5461 else if (streq(verb, "add-requires"))
5462 dep = UNIT_REQUIRES;
5463 else
5464 assert_not_reached("Unknown verb");
5465
5466 if (!bus || avoid_bus()) {
5467 UnitFileChange *changes = NULL;
5468 unsigned n_changes = 0;
5469
5470 r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
5471
f647962d
MS
5472 if (r < 0)
5473 return log_error_errno(r, "Can't add dependency: %m");
e94937df
LN
5474
5475 if (!arg_quiet)
5476 dump_unit_file_changes(changes, n_changes);
5477
5478 unit_file_changes_free(changes, n_changes);
5479
5480 } else {
5481 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5482 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5483
079dac08
LP
5484 polkit_agent_open_if_enabled();
5485
e94937df
LN
5486 r = sd_bus_message_new_method_call(
5487 bus,
5488 &m,
5489 "org.freedesktop.systemd1",
5490 "/org/freedesktop/systemd1",
5491 "org.freedesktop.systemd1.Manager",
5492 "AddDependencyUnitFiles");
5493 if (r < 0)
5494 return bus_log_create_error(r);
5495
342641fb 5496 r = sd_bus_message_append_strv(m, names);
e94937df
LN
5497 if (r < 0)
5498 return bus_log_create_error(r);
5499
342641fb 5500 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
5501 if (r < 0)
5502 return bus_log_create_error(r);
5503
5504 r = sd_bus_call(bus, m, 0, &error, &reply);
5505 if (r < 0) {
5506 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5507 return r;
5508 }
5509
57ab2eab 5510 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
e94937df
LN
5511 if (r < 0)
5512 return r;
5513
5514 if (!arg_no_reload)
5515 r = daemon_reload(bus, args);
5516 else
5517 r = 0;
5518 }
5519
5520 return r;
5521}
5522
d309c1c3
LP
5523static int preset_all(sd_bus *bus, char **args) {
5524 UnitFileChange *changes = NULL;
5525 unsigned n_changes = 0;
5526 int r;
5527
5528 if (!bus || avoid_bus()) {
5529
5530 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
5531 if (r < 0) {
da927ba9 5532 log_error_errno(r, "Operation failed: %m");
d309c1c3
LP
5533 goto finish;
5534 }
5535
5536 if (!arg_quiet)
5537 dump_unit_file_changes(changes, n_changes);
5538
5539 r = 0;
5540
5541 } else {
d309c1c3 5542 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 5543 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
d309c1c3 5544
079dac08
LP
5545 polkit_agent_open_if_enabled();
5546
6e646d22 5547 r = sd_bus_call_method(
d309c1c3
LP
5548 bus,
5549 "org.freedesktop.systemd1",
5550 "/org/freedesktop/systemd1",
5551 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5552 "PresetAllUnitFiles",
5553 &error,
5554 &reply,
d309c1c3
LP
5555 "sbb",
5556 unit_file_preset_mode_to_string(arg_preset_mode),
5557 arg_runtime,
5558 arg_force);
5559 if (r < 0) {
5560 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5561 return r;
5562 }
5563
57ab2eab 5564 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
d309c1c3
LP
5565 if (r < 0)
5566 return r;
5567
5568 if (!arg_no_reload)
5569 r = daemon_reload(bus, args);
5570 else
5571 r = 0;
5572 }
5573
5574finish:
5575 unit_file_changes_free(changes, n_changes);
5576
5577 return r;
5578}
5579
f459b602
MAP
5580static int unit_is_enabled(sd_bus *bus, char **args) {
5581
5582 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 5583 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5584 bool enabled;
5585 char **name;
f459b602 5586 int r;
ee5762e3 5587
e3e0314b 5588 r = mangle_names(args+1, &names);
cbb13b2a
VP
5589 if (r < 0)
5590 return r;
5591
e3e0314b 5592 r = enable_sysv_units(args[0], names);
729e3769
LP
5593 if (r < 0)
5594 return r;
ee5762e3 5595
729e3769 5596 enabled = r > 0;
ee5762e3 5597
729e3769 5598 if (!bus || avoid_bus()) {
ee5762e3 5599
e3e0314b 5600 STRV_FOREACH(name, names) {
729e3769 5601 UnitFileState state;
ee5762e3 5602
cbb13b2a 5603 state = unit_file_get_state(arg_scope, arg_root, *name);
f647962d
MS
5604 if (state < 0)
5605 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
ee5762e3 5606
729e3769
LP
5607 if (state == UNIT_FILE_ENABLED ||
5608 state == UNIT_FILE_ENABLED_RUNTIME ||
aedd4012
JS
5609 state == UNIT_FILE_STATIC ||
5610 state == UNIT_FILE_INDIRECT)
729e3769
LP
5611 enabled = true;
5612
5613 if (!arg_quiet)
5614 puts(unit_file_state_to_string(state));
71fad675 5615 }
ee5762e3 5616
729e3769 5617 } else {
e3e0314b 5618 STRV_FOREACH(name, names) {
f459b602 5619 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 5620 const char *s;
63a723f3 5621
f459b602 5622 r = sd_bus_call_method(
f22f08cd 5623 bus,
729e3769
LP
5624 "org.freedesktop.systemd1",
5625 "/org/freedesktop/systemd1",
5626 "org.freedesktop.systemd1.Manager",
f22f08cd 5627 "GetUnitFileState",
f459b602 5628 &error,
f22f08cd 5629 &reply,
04504f93 5630 "s", *name);
f459b602
MAP
5631 if (r < 0) {
5632 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 5633 return r;
ee5762e3
LP
5634 }
5635
f459b602
MAP
5636 r = sd_bus_message_read(reply, "s", &s);
5637 if (r < 0)
5638 return bus_log_parse_error(r);
ee5762e3 5639
aedd4012 5640 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
729e3769
LP
5641 enabled = true;
5642
5643 if (!arg_quiet)
5644 puts(s);
560d8f23 5645 }
ee5762e3
LP
5646 }
5647
f459b602 5648 return !enabled;
ee5762e3
LP
5649}
5650
99813a19
LP
5651static int is_system_running(sd_bus *bus, char **args) {
5652 _cleanup_free_ char *state = NULL;
5653 int r;
5654
5655 r = sd_bus_get_property_string(
5656 bus,
5657 "org.freedesktop.systemd1",
5658 "/org/freedesktop/systemd1",
5659 "org.freedesktop.systemd1.Manager",
5660 "SystemState",
5661 NULL,
5662 &state);
5663 if (r < 0) {
5664 if (!arg_quiet)
5665 puts("unknown");
5666 return 0;
5667 }
5668
5669 if (!arg_quiet)
5670 puts(state);
5671
5672 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
5673}
5674
7d4fb3b1 5675static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
7d4fb3b1 5676 char *t;
ae6c3cc0 5677 int r;
7d4fb3b1
RC
5678
5679 assert(new_path);
5680 assert(original_path);
5681 assert(ret_tmp_fn);
5682
ae6c3cc0
LP
5683 r = tempfn_random(new_path, &t);
5684 if (r < 0)
029009d4 5685 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
5686
5687 r = mkdir_parents(new_path, 0755);
652212b0 5688 if (r < 0) {
029009d4 5689 log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
652212b0
TA
5690 free(t);
5691 return r;
5692 }
7d4fb3b1 5693
f2068bcc 5694 r = copy_file(original_path, t, 0, 0644, 0);
7d4fb3b1
RC
5695 if (r == -ENOENT) {
5696 r = touch(t);
5697 if (r < 0) {
029009d4 5698 log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
7d4fb3b1
RC
5699 free(t);
5700 return r;
5701 }
5702 } else if (r < 0) {
029009d4 5703 log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
7d4fb3b1
RC
5704 free(t);
5705 return r;
5706 }
5707
5708 *ret_tmp_fn = t;
5709
5710 return 0;
5711}
5712
bc854dc7
ZJS
5713static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
5714 _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
7d4fb3b1
RC
5715
5716 switch (arg_scope) {
5717 case UNIT_FILE_SYSTEM:
bc854dc7
ZJS
5718 path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
5719 if (arg_runtime)
5720 run = path_join(arg_root, "/run/systemd/system/", name);
7d4fb3b1
RC
5721 break;
5722 case UNIT_FILE_GLOBAL:
bc854dc7
ZJS
5723 path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5724 if (arg_runtime)
5725 run = path_join(arg_root, "/run/systemd/user/", name);
7d4fb3b1
RC
5726 break;
5727 case UNIT_FILE_USER:
5728 assert(user_home);
5729 assert(user_runtime);
5730
bc854dc7
ZJS
5731 path = path_join(arg_root, user_home, name);
5732 if (arg_runtime) {
5733 path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5734 if (!path2)
5735 return log_oom();
5736 run = path_join(arg_root, user_runtime, name);
5737 }
7d4fb3b1
RC
5738 break;
5739 default:
5740 assert_not_reached("Invalid scope");
5741 }
bc854dc7 5742 if (!path || (arg_runtime && !run))
7d4fb3b1
RC
5743 return log_oom();
5744
bc854dc7
ZJS
5745 if (arg_runtime) {
5746 if (access(path, F_OK) >= 0)
ff9b60f3 5747 return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
bc854dc7
ZJS
5748 run, path);
5749 if (path2 && access(path2, F_OK) >= 0)
ff9b60f3 5750 return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
bc854dc7
ZJS
5751 run, path2);
5752 *ret_path = run;
5753 run = NULL;
5754 } else {
5755 *ret_path = path;
5756 path = NULL;
5757 }
7d4fb3b1
RC
5758
5759 return 0;
5760}
5761
bc854dc7
ZJS
5762static 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) {
5763 char *tmp_new_path, *ending;
7d4fb3b1
RC
5764 char *tmp_tmp_path;
5765 int r;
5766
5767 assert(unit_name);
5768 assert(ret_new_path);
5769 assert(ret_tmp_path);
5770
63c372cb 5771 ending = strjoina(unit_name, ".d/override.conf");
bc854dc7 5772 r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
5773 if (r < 0)
5774 return r;
5775
5776 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
5777 if (r < 0) {
5778 free(tmp_new_path);
5779 return r;
5780 }
5781
5782 *ret_new_path = tmp_new_path;
5783 *ret_tmp_path = tmp_tmp_path;
5784
5785 return 0;
5786}
5787
1cfa9a4c
LP
5788static int unit_file_create_copy(
5789 const char *unit_name,
5790 const char *fragment_path,
5791 const char *user_home,
5792 const char *user_runtime,
5793 char **ret_new_path,
5794 char **ret_tmp_path) {
5795
7d4fb3b1
RC
5796 char *tmp_new_path;
5797 char *tmp_tmp_path;
5798 int r;
5799
5800 assert(fragment_path);
5801 assert(unit_name);
5802 assert(ret_new_path);
5803 assert(ret_tmp_path);
5804
bc854dc7 5805 r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
5806 if (r < 0)
5807 return r;
5808
5809 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
5810 char response;
5811
029009d4 5812 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
5813 if (r < 0) {
5814 free(tmp_new_path);
5815 return r;
5816 }
5817 if (response != 'y') {
5818 log_warning("%s ignored", unit_name);
5819 free(tmp_new_path);
5820 return -1;
5821 }
5822 }
5823
5824 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
5825 if (r < 0) {
029009d4 5826 log_error_errno(r, "Failed to create temporary file for \"%s\": %m", tmp_new_path);
7d4fb3b1
RC
5827 free(tmp_new_path);
5828 return r;
5829 }
5830
5831 *ret_new_path = tmp_new_path;
5832 *ret_tmp_path = tmp_tmp_path;
5833
5834 return 0;
5835}
5836
5837static int run_editor(char **paths) {
5838 pid_t pid;
5839 int r;
5840
5841 assert(paths);
5842
5843 pid = fork();
5844 if (pid < 0) {
5845 log_error_errno(errno, "Failed to fork: %m");
5846 return -errno;
5847 }
5848
5849 if (pid == 0) {
5850 const char **args;
7d4fb3b1 5851 char *editor;
1cfa9a4c 5852 char **tmp_path, **original_path, *p;
7d4fb3b1
RC
5853 unsigned i = 1;
5854 size_t argc;
5855
5856 argc = strv_length(paths)/2 + 1;
5857 args = newa(const char*, argc + 1);
5858
5859 args[0] = NULL;
5860 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
5861 args[i] = *tmp_path;
5862 i++;
5863 }
5864 args[argc] = NULL;
5865
5866 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
5867 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
5868 * we try to execute well known editors
5869 */
5870 editor = getenv("SYSTEMD_EDITOR");
5871 if (!editor)
5872 editor = getenv("EDITOR");
5873 if (!editor)
5874 editor = getenv("VISUAL");
5875
5876 if (!isempty(editor)) {
5877 args[0] = editor;
5878 execvp(editor, (char* const*) args);
5879 }
5880
1cfa9a4c
LP
5881 FOREACH_STRING(p, "nano", "vim", "vi") {
5882 args[0] = p;
5883 execvp(p, (char* const*) args);
7d4fb3b1
RC
5884 /* We do not fail if the editor doesn't exist
5885 * because we want to try each one of them before
5886 * failing.
5887 */
5888 if (errno != ENOENT) {
5889 log_error("Failed to execute %s: %m", editor);
5890 _exit(EXIT_FAILURE);
5891 }
5892 }
5893
1cfa9a4c 5894 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
5895 _exit(EXIT_FAILURE);
5896 }
5897
5898 r = wait_for_terminate_and_warn("editor", pid, true);
5899 if (r < 0)
5900 return log_error_errno(r, "Failed to wait for child: %m");
5901
5902 return r;
5903}
5904
5905static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
5906 _cleanup_free_ char *user_home = NULL;
5907 _cleanup_free_ char *user_runtime = NULL;
e9e310f8
RC
5908 _cleanup_lookup_paths_free_ LookupPaths lp = {};
5909 bool avoid_bus_cache;
7d4fb3b1
RC
5910 char **name;
5911 int r;
5912
5913 assert(names);
5914 assert(paths);
5915
8df18507 5916 r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
5b013a2f 5917 if (r < 0)
8df18507 5918 return r;
7d4fb3b1 5919
e9e310f8 5920 avoid_bus_cache = !bus || avoid_bus();
7d4fb3b1 5921
e9e310f8
RC
5922 STRV_FOREACH(name, names) {
5923 _cleanup_free_ char *path = NULL;
e9e310f8 5924 char *new_path, *tmp_path;
7d4fb3b1 5925
ad2a0358 5926 r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL);
e9e310f8
RC
5927 if (r < 0)
5928 return r;
b5e6a600
IS
5929 else if (r == 0)
5930 return -ENOENT;
5931 else if (!path) {
ad2a0358 5932 // FIXME: support units with path==NULL (no FragmentPath)
b5e6a600
IS
5933 log_error("No fragment exists for %s.", *name);
5934 return -ENOENT;
5935 }
7d4fb3b1 5936
e9e310f8 5937 if (arg_full)
ad2a0358 5938 r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 5939 else
bc854dc7 5940 r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 5941 if (r < 0)
ad2a0358 5942 return r;
7d4fb3b1 5943
e9e310f8
RC
5944 r = strv_push_pair(paths, new_path, tmp_path);
5945 if (r < 0)
5946 return log_oom();
7d4fb3b1
RC
5947 }
5948
5949 return 0;
5950}
5951
5952static int edit(sd_bus *bus, char **args) {
5953 _cleanup_strv_free_ char **names = NULL;
5954 _cleanup_strv_free_ char **paths = NULL;
5955 char **original, **tmp;
5956 int r;
5957
5958 assert(args);
5959
5960 if (!on_tty()) {
029009d4 5961 log_error("Cannot edit units if not on a tty");
7d4fb3b1
RC
5962 return -EINVAL;
5963 }
5964
5965 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5966 log_error("Cannot remotely edit units");
5967 return -EINVAL;
5968 }
5969
5970 r = expand_names(bus, args + 1, NULL, &names);
5971 if (r < 0)
5972 return log_error_errno(r, "Failed to expand names: %m");
5973
7d4fb3b1
RC
5974 r = find_paths_to_edit(bus, names, &paths);
5975 if (r < 0)
5976 return r;
5977
b5e6a600 5978 if (strv_isempty(paths))
7d4fb3b1 5979 return -ENOENT;
7d4fb3b1
RC
5980
5981 r = run_editor(paths);
5982 if (r < 0)
5983 goto end;
5984
5985 STRV_FOREACH_PAIR(original, tmp, paths) {
5986 /* If the temporary file is empty we ignore it.
5987 * It's useful if the user wants to cancel its modification
5988 */
5989 if (null_or_empty_path(*tmp)) {
029009d4 5990 log_warning("Editing \"%s\" canceled: temporary file is empty", *original);
7d4fb3b1
RC
5991 continue;
5992 }
5993 r = rename(*tmp, *original);
5994 if (r < 0) {
029009d4 5995 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
5996 goto end;
5997 }
5998 }
5999
6000 if (!arg_no_reload && bus && !avoid_bus())
6001 r = daemon_reload(bus, args);
6002
6003end:
6004 STRV_FOREACH_PAIR(original, tmp, paths)
6005 unlink_noerrno(*tmp);
6006
6007 return r;
6008}
6009
601185b4 6010static void systemctl_help(void) {
7e4249b9 6011
729e3769
LP
6012 pager_open_if_enabled();
6013
2e33c433 6014 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 6015 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
6016 " -h --help Show this help\n"
6017 " --version Show package version\n"
f459b602
MAP
6018 " --system Connect to system manager\n"
6019 " --user Connect to user service manager\n"
6020 " -H --host=[USER@]HOST\n"
6021 " Operate on remote host\n"
6022 " -M --machine=CONTAINER\n"
6023 " Operate on local container\n"
3fb90db2
ZJS
6024 " -t --type=TYPE List units of a particular type\n"
6025 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 6026 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
6027 " -a --all Show all loaded units/properties, including dead/empty\n"
6028 " ones. To list all units installed on the system, use\n"
6029 " the 'list-unit-files' command instead.\n"
98a6e132 6030 " -l --full Don't ellipsize unit names on output\n"
1238ee09 6031 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
6032 " --reverse Show reverse dependencies with 'list-dependencies'\n"
6033 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
6034 " queueing a new job\n"
a521ae4a 6035 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
6036 " -i --ignore-inhibitors\n"
6037 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
6038 " --kill-who=WHO Who to send signal to\n"
6039 " -s --signal=SIGNAL Which signal to send\n"
57ab2eab 6040 " --now Start or stop unit in addition to enabling or disabling it\n"
8a0867d6
LP
6041 " -q --quiet Suppress output\n"
6042 " --no-block Do not wait until operation finished\n"
8a0867d6 6043 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 6044 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 6045 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 6046 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
6047 " --no-ask-password\n"
6048 " Do not ask for system passwords\n"
a8f11321 6049 " --global Enable/disable unit files globally\n"
a521ae4a 6050 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
6051 " -f --force When enabling unit files, override existing symlinks\n"
6052 " When shutting down, execute action immediately\n"
3fb90db2 6053 " --preset-mode= Apply only enable, only disable, or all presets\n"
729e3769 6054 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 6055 " -n --lines=INTEGER Number of journal entries to show\n"
86d81e50
RC
6056 " -o --output=STRING Change journal output mode (short, short-iso,\n"
6057 " short-precise, short-monotonic, verbose,\n"
6058 " export, json, json-pretty, json-sse, cat)\n"
5bdf2243 6059 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 6060 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 6061 "Unit Commands:\n"
d8fba7c6
ZJS
6062 " list-units [PATTERN...] List loaded units\n"
6063 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
6064 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
6065 " start NAME... Start (activate) one or more units\n"
6066 " stop NAME... Stop (deactivate) one or more units\n"
6067 " reload NAME... Reload one or more units\n"
6068 " restart NAME... Start or restart one or more units\n"
6069 " try-restart NAME... Restart one or more units if active\n"
6070 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 6071 " otherwise start or restart\n"
4f8f66cb 6072 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 6073 " otherwise restart if active\n"
4f8f66cb
ZJS
6074 " isolate NAME Start one unit and stop all others\n"
6075 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
6076 " is-active PATTERN... Check whether units are active\n"
6077 " is-failed PATTERN... Check whether units are failed\n"
6078 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
6079 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 6080 " units/jobs or the manager\n"
b3ae710c 6081 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 6082 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
6083 " help PATTERN...|PID... Show manual for one or more units\n"
6084 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 6085 " units\n"
55c0b89c 6086 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
6087 " or wanted by this unit or by which this\n"
6088 " unit is required or wanted\n\n"
34c4b47b 6089 "Unit File Commands:\n"
d8fba7c6 6090 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
6091 " enable NAME... Enable one or more unit files\n"
6092 " disable NAME... Disable one or more unit files\n"
6093 " reenable NAME... Reenable one or more unit files\n"
6094 " preset NAME... Enable/disable one or more unit files\n"
729e3769 6095 " based on preset configuration\n"
d309c1c3
LP
6096 " preset-all Enable/disable all unit files based on\n"
6097 " preset configuration\n"
b619ec8f 6098 " is-enabled NAME... Check whether unit files are enabled\n"
4f8f66cb
ZJS
6099 " mask NAME... Mask one or more units\n"
6100 " unmask NAME... Unmask one or more units\n"
6101 " link PATH... Link one or more units files into\n"
729e3769 6102 " the search path\n"
e94937df
LN
6103 " add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
6104 " on specified one or more units\n"
6105 " add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
6106 " on specified one or more units\n"
7d4fb3b1 6107 " edit NAME... Edit one or more unit files\n"
b619ec8f
LP
6108 " get-default Get the name of the default target\n"
6109 " set-default NAME Set the default target\n\n"
0d292f5e
LP
6110 "Machine Commands:\n"
6111 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 6112 "Job Commands:\n"
d8fba7c6 6113 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 6114 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 6115 "Snapshot Commands:\n"
7e4249b9 6116 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 6117 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 6118 "Environment Commands:\n"
7e4249b9 6119 " show-environment Dump environment\n"
4f8f66cb 6120 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a 6121 " unset-environment NAME... Unset one or more environment variables\n"
3fb90db2 6122 " import-environment [NAME...] Import all or some environment variables\n\n"
34c4b47b
LP
6123 "Manager Lifecycle Commands:\n"
6124 " daemon-reload Reload systemd manager configuration\n"
6125 " daemon-reexec Reexecute systemd manager\n\n"
6126 "System Commands:\n"
99813a19 6127 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
6128 " default Enter system default mode\n"
6129 " rescue Enter system rescue mode\n"
6130 " emergency Enter system emergency mode\n"
514f4ef5 6131 " halt Shut down and halt the system\n"
2e33c433 6132 " poweroff Shut down and power-off the system\n"
37185ec8 6133 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 6134 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 6135 " exit Request user instance exit\n"
4f8f66cb 6136 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 6137 " suspend Suspend the system\n"
6524990f
LP
6138 " hibernate Hibernate the system\n"
6139 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 6140 program_invocation_short_name);
7e4249b9
LP
6141}
6142
601185b4 6143static void halt_help(void) {
37185ec8 6144 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
6145 "%s the system.\n\n"
6146 " --help Show this help\n"
6147 " --halt Halt the machine\n"
6148 " -p --poweroff Switch off the machine\n"
6149 " --reboot Reboot the machine\n"
2e33c433
LP
6150 " -f --force Force immediate halt/power-off/reboot\n"
6151 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 6152 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 6153 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 6154 program_invocation_short_name,
37185ec8 6155 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
6156 arg_action == ACTION_REBOOT ? "Reboot" :
6157 arg_action == ACTION_POWEROFF ? "Power off" :
6158 "Halt");
e4b61340
LP
6159}
6160
601185b4 6161static void shutdown_help(void) {
08e4b1c5 6162 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
6163 "Shut down the system.\n\n"
6164 " --help Show this help\n"
6165 " -H --halt Halt the machine\n"
6166 " -P --poweroff Power-off the machine\n"
6167 " -r --reboot Reboot the machine\n"
386da858 6168 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 6169 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 6170 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 6171 " -c Cancel a pending shutdown\n",
e4b61340 6172 program_invocation_short_name);
e4b61340
LP
6173}
6174
601185b4 6175static void telinit_help(void) {
2e33c433 6176 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
6177 "Send control commands to the init daemon.\n\n"
6178 " --help Show this help\n"
2e33c433 6179 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
6180 "Commands:\n"
6181 " 0 Power-off the machine\n"
6182 " 6 Reboot the machine\n"
514f4ef5
LP
6183 " 2, 3, 4, 5 Start runlevelX.target unit\n"
6184 " 1, s, S Enter rescue mode\n"
6185 " q, Q Reload init daemon configuration\n"
6186 " u, U Reexecute init daemon\n",
e4b61340 6187 program_invocation_short_name);
e4b61340
LP
6188}
6189
601185b4 6190static void runlevel_help(void) {
2e33c433 6191 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
6192 "Prints the previous and current runlevel of the init system.\n\n"
6193 " --help Show this help\n",
6194 program_invocation_short_name);
e4b61340
LP
6195}
6196
b93312f5 6197static void help_types(void) {
45c0c61d 6198 int i;
830f01f0 6199 const char *t;
45c0c61d 6200
b93312f5
ZJS
6201 if (!arg_no_legend)
6202 puts("Available unit types:");
f168c273 6203 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
6204 t = unit_type_to_string(i);
6205 if (t)
6206 puts(t);
6207 }
45c0c61d
ZJS
6208}
6209
e4b61340 6210static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
6211
6212 enum {
90d473a1 6213 ARG_FAIL = 0x100,
afba4199
ZJS
6214 ARG_REVERSE,
6215 ARG_AFTER,
6216 ARG_BEFORE,
991f2a39 6217 ARG_SHOW_TYPES,
23ade460 6218 ARG_IRREVERSIBLE,
e67c3609 6219 ARG_IGNORE_DEPENDENCIES,
35df8f27 6220 ARG_VERSION,
af2d49f7 6221 ARG_USER,
7e4249b9 6222 ARG_SYSTEM,
ee5762e3 6223 ARG_GLOBAL,
6e905d93 6224 ARG_NO_BLOCK,
ebed32bf 6225 ARG_NO_LEGEND,
611efaac 6226 ARG_NO_PAGER,
4445a875 6227 ARG_NO_WALL,
be394c48 6228 ARG_ROOT,
ee5762e3 6229 ARG_NO_RELOAD,
501fc174 6230 ARG_KILL_WHO,
30732560 6231 ARG_NO_ASK_PASSWORD,
729e3769 6232 ARG_FAILED,
df50185b 6233 ARG_RUNTIME,
5d0c05e5 6234 ARG_FORCE,
9b9b3d36 6235 ARG_PLAIN,
4dc5b821 6236 ARG_STATE,
d309c1c3
LP
6237 ARG_JOB_MODE,
6238 ARG_PRESET_MODE,
5bdf2243 6239 ARG_FIRMWARE_SETUP,
57ab2eab 6240 ARG_NOW,
7e4249b9
LP
6241 };
6242
6243 static const struct option options[] = {
9ea9d4cf
LP
6244 { "help", no_argument, NULL, 'h' },
6245 { "version", no_argument, NULL, ARG_VERSION },
6246 { "type", required_argument, NULL, 't' },
6247 { "property", required_argument, NULL, 'p' },
6248 { "all", no_argument, NULL, 'a' },
6249 { "reverse", no_argument, NULL, ARG_REVERSE },
6250 { "after", no_argument, NULL, ARG_AFTER },
6251 { "before", no_argument, NULL, ARG_BEFORE },
6252 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
6253 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
6254 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
6255 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
6256 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
6257 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
6258 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
6259 { "ignore-inhibitors", no_argument, NULL, 'i' },
6260 { "user", no_argument, NULL, ARG_USER },
6261 { "system", no_argument, NULL, ARG_SYSTEM },
6262 { "global", no_argument, NULL, ARG_GLOBAL },
6263 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
6264 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
6265 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6266 { "no-wall", no_argument, NULL, ARG_NO_WALL },
6267 { "quiet", no_argument, NULL, 'q' },
6268 { "root", required_argument, NULL, ARG_ROOT },
6269 { "force", no_argument, NULL, ARG_FORCE },
6270 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
6271 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
6272 { "signal", required_argument, NULL, 's' },
6273 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
6274 { "host", required_argument, NULL, 'H' },
f459b602 6275 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
6276 { "runtime", no_argument, NULL, ARG_RUNTIME },
6277 { "lines", required_argument, NULL, 'n' },
6278 { "output", required_argument, NULL, 'o' },
6279 { "plain", no_argument, NULL, ARG_PLAIN },
6280 { "state", required_argument, NULL, ARG_STATE },
1238ee09 6281 { "recursive", no_argument, NULL, 'r' },
d309c1c3 6282 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
5bdf2243 6283 { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
57ab2eab 6284 { "now", no_argument, NULL, ARG_NOW },
eb9da376 6285 {}
7e4249b9
LP
6286 };
6287
6288 int c;
6289
e4b61340 6290 assert(argc >= 0);
7e4249b9
LP
6291 assert(argv);
6292
601185b4 6293 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
6294
6295 switch (c) {
6296
6297 case 'h':
601185b4
ZJS
6298 systemctl_help();
6299 return 0;
35df8f27
LP
6300
6301 case ARG_VERSION:
6302 puts(PACKAGE_STRING);
7d568925 6303 puts(SYSTEMD_FEATURES);
35df8f27 6304 return 0;
7e4249b9 6305
20b3f379 6306 case 't': {
a2a5291b 6307 const char *word, *state;
20b3f379 6308 size_t size;
45c0c61d 6309
20b3f379 6310 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 6311 _cleanup_free_ char *type;
20b3f379
ZJS
6312
6313 type = strndup(word, size);
6314 if (!type)
6315 return -ENOMEM;
6316
6317 if (streq(type, "help")) {
6318 help_types();
6319 return 0;
6320 }
6321
6322 if (unit_type_from_string(type) >= 0) {
6323 if (strv_push(&arg_types, type))
6324 return log_oom();
6325 type = NULL;
6326 continue;
6327 }
6328
9b9b3d36
MW
6329 /* It's much nicer to use --state= for
6330 * load states, but let's support this
6331 * in --types= too for compatibility
6332 * with old versions */
20b3f379 6333 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 6334 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
6335 return log_oom();
6336 type = NULL;
6337 continue;
6338 }
6339
ab06eef8 6340 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
6341 log_info("Use -t help to see a list of allowed values.");
6342 return -EINVAL;
c147dc42 6343 }
20b3f379
ZJS
6344
6345 break;
6346 }
6347
ea4a240d 6348 case 'p': {
033a842c
ZJS
6349 /* Make sure that if the empty property list
6350 was specified, we won't show any properties. */
20b3f379 6351 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 6352 arg_properties = new0(char*, 1);
20b3f379
ZJS
6353 if (!arg_properties)
6354 return log_oom();
6355 } else {
a2a5291b 6356 const char *word, *state;
20b3f379 6357 size_t size;
033a842c 6358
20b3f379
ZJS
6359 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6360 char *prop;
033a842c 6361
20b3f379
ZJS
6362 prop = strndup(word, size);
6363 if (!prop)
6364 return log_oom();
ea4a240d 6365
6e18964d 6366 if (strv_consume(&arg_properties, prop) < 0)
20b3f379 6367 return log_oom();
20b3f379 6368 }
033a842c 6369 }
48220598
LP
6370
6371 /* If the user asked for a particular
6372 * property, show it to him, even if it is
6373 * empty. */
6374 arg_all = true;
033a842c 6375
48220598 6376 break;
ea4a240d 6377 }
48220598 6378
7e4249b9
LP
6379 case 'a':
6380 arg_all = true;
6381 break;
6382
afba4199
ZJS
6383 case ARG_REVERSE:
6384 arg_dependency = DEPENDENCY_REVERSE;
6385 break;
6386
6387 case ARG_AFTER:
6388 arg_dependency = DEPENDENCY_AFTER;
6389 break;
6390
6391 case ARG_BEFORE:
6392 arg_dependency = DEPENDENCY_BEFORE;
6393 break;
6394
991f2a39
ZJS
6395 case ARG_SHOW_TYPES:
6396 arg_show_types = true;
6397 break;
6398
4dc5b821
LP
6399 case ARG_JOB_MODE:
6400 arg_job_mode = optarg;
6401 break;
6402
90d473a1 6403 case ARG_FAIL:
e67c3609
LP
6404 arg_job_mode = "fail";
6405 break;
6406
23ade460
MS
6407 case ARG_IRREVERSIBLE:
6408 arg_job_mode = "replace-irreversibly";
6409 break;
6410
e67c3609
LP
6411 case ARG_IGNORE_DEPENDENCIES:
6412 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
6413 break;
6414
af2d49f7 6415 case ARG_USER:
729e3769 6416 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
6417 break;
6418
6419 case ARG_SYSTEM:
729e3769
LP
6420 arg_scope = UNIT_FILE_SYSTEM;
6421 break;
6422
6423 case ARG_GLOBAL:
6424 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
6425 break;
6426
6e905d93
LP
6427 case ARG_NO_BLOCK:
6428 arg_no_block = true;
7e4249b9
LP
6429 break;
6430
ebed32bf
MS
6431 case ARG_NO_LEGEND:
6432 arg_no_legend = true;
6433 break;
6434
611efaac
LP
6435 case ARG_NO_PAGER:
6436 arg_no_pager = true;
6437 break;
0736af98 6438
514f4ef5
LP
6439 case ARG_NO_WALL:
6440 arg_no_wall = true;
6441 break;
6442
be394c48
FC
6443 case ARG_ROOT:
6444 arg_root = optarg;
6445 break;
6446
98a6e132 6447 case 'l':
8fe914ec
LP
6448 arg_full = true;
6449 break;
6450
30732560 6451 case ARG_FAILED:
9b9b3d36
MW
6452 if (strv_extend(&arg_states, "failed") < 0)
6453 return log_oom();
6454
30732560
LP
6455 break;
6456
0183528f
LP
6457 case 'q':
6458 arg_quiet = true;
6459 break;
6460
568b679f
LP
6461 case ARG_FORCE:
6462 arg_force ++;
6463 break;
6464
b4f27ccc 6465 case 'f':
e606bb61 6466 arg_force ++;
ee5762e3
LP
6467 break;
6468
6469 case ARG_NO_RELOAD:
6470 arg_no_reload = true;
6471 break;
6472
8a0867d6
LP
6473 case ARG_KILL_WHO:
6474 arg_kill_who = optarg;
6475 break;
6476
8a0867d6
LP
6477 case 's':
6478 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
6479 log_error("Failed to parse signal string %s.", optarg);
6480 return -EINVAL;
6481 }
6482 break;
6483
501fc174
LP
6484 case ARG_NO_ASK_PASSWORD:
6485 arg_ask_password = false;
6486 break;
6487
f459b602
MAP
6488 case 'H':
6489 arg_transport = BUS_TRANSPORT_REMOTE;
6490 arg_host = optarg;
a8f11321
LP
6491 break;
6492
f459b602 6493 case 'M':
de33fc62 6494 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 6495 arg_host = optarg;
a8f11321
LP
6496 break;
6497
729e3769
LP
6498 case ARG_RUNTIME:
6499 arg_runtime = true;
6500 break;
6501
df50185b
LP
6502 case 'n':
6503 if (safe_atou(optarg, &arg_lines) < 0) {
6504 log_error("Failed to parse lines '%s'", optarg);
6505 return -EINVAL;
6506 }
6507 break;
6508
df50185b
LP
6509 case 'o':
6510 arg_output = output_mode_from_string(optarg);
6511 if (arg_output < 0) {
6512 log_error("Unknown output '%s'.", optarg);
6513 return -EINVAL;
6514 }
6515 break;
6516
b37844d3
LP
6517 case 'i':
6518 arg_ignore_inhibitors = true;
6519 break;
6520
5d0c05e5
LN
6521 case ARG_PLAIN:
6522 arg_plain = true;
6523 break;
6524
5bdf2243
JJ
6525 case ARG_FIRMWARE_SETUP:
6526 arg_firmware_setup = true;
6527 break;
6528
9b9b3d36 6529 case ARG_STATE: {
a2a5291b 6530 const char *word, *state;
9b9b3d36
MW
6531 size_t size;
6532
6533 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6534 char *s;
6535
6536 s = strndup(word, size);
6537 if (!s)
6538 return log_oom();
6539
6e18964d 6540 if (strv_consume(&arg_states, s) < 0)
9b9b3d36 6541 return log_oom();
9b9b3d36
MW
6542 }
6543 break;
6544 }
6545
1238ee09
LP
6546 case 'r':
6547 if (geteuid() != 0) {
f1721625 6548 log_error("--recursive requires root privileges.");
1238ee09
LP
6549 return -EPERM;
6550 }
6551
6552 arg_recursive = true;
6553 break;
6554
d309c1c3
LP
6555 case ARG_PRESET_MODE:
6556
6557 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
6558 if (arg_preset_mode < 0) {
6559 log_error("Failed to parse preset mode: %s.", optarg);
6560 return -EINVAL;
6561 }
6562
6563 break;
6564
57ab2eab
JS
6565 case ARG_NOW:
6566 arg_now = true;
6567 break;
6568
7e4249b9
LP
6569 case '?':
6570 return -EINVAL;
6571
6572 default:
eb9da376 6573 assert_not_reached("Unhandled option");
7e4249b9 6574 }
7e4249b9 6575
f459b602 6576 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
6577 log_error("Cannot access user instance remotely.");
6578 return -EINVAL;
6579 }
6580
7e4249b9
LP
6581 return 1;
6582}
6583
e4b61340
LP
6584static int halt_parse_argv(int argc, char *argv[]) {
6585
6586 enum {
6587 ARG_HELP = 0x100,
6588 ARG_HALT,
514f4ef5
LP
6589 ARG_REBOOT,
6590 ARG_NO_WALL
e4b61340
LP
6591 };
6592
6593 static const struct option options[] = {
6594 { "help", no_argument, NULL, ARG_HELP },
6595 { "halt", no_argument, NULL, ARG_HALT },
6596 { "poweroff", no_argument, NULL, 'p' },
6597 { "reboot", no_argument, NULL, ARG_REBOOT },
6598 { "force", no_argument, NULL, 'f' },
6599 { "wtmp-only", no_argument, NULL, 'w' },
6600 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 6601 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6602 {}
e4b61340
LP
6603 };
6604
37185ec8 6605 int c, r, runlevel;
e4b61340
LP
6606
6607 assert(argc >= 0);
6608 assert(argv);
6609
6610 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
6611 if (runlevel == '0' || runlevel == '6')
65491fd8 6612 arg_force = 2;
e4b61340 6613
601185b4 6614 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
6615 switch (c) {
6616
6617 case ARG_HELP:
601185b4
ZJS
6618 halt_help();
6619 return 0;
e4b61340
LP
6620
6621 case ARG_HALT:
6622 arg_action = ACTION_HALT;
6623 break;
6624
6625 case 'p':
a042efad
MS
6626 if (arg_action != ACTION_REBOOT)
6627 arg_action = ACTION_POWEROFF;
e4b61340
LP
6628 break;
6629
6630 case ARG_REBOOT:
6631 arg_action = ACTION_REBOOT;
6632 break;
6633
6634 case 'f':
65491fd8 6635 arg_force = 2;
e4b61340
LP
6636 break;
6637
6638 case 'w':
6639 arg_dry = true;
6640 break;
6641
6642 case 'd':
6643 arg_no_wtmp = true;
6644 break;
6645
514f4ef5
LP
6646 case ARG_NO_WALL:
6647 arg_no_wall = true;
6648 break;
6649
e4b61340
LP
6650 case 'i':
6651 case 'h':
57371e58 6652 case 'n':
e4b61340
LP
6653 /* Compatibility nops */
6654 break;
6655
6656 case '?':
6657 return -EINVAL;
6658
6659 default:
eb9da376 6660 assert_not_reached("Unhandled option");
e4b61340 6661 }
e4b61340 6662
c5220a94
MO
6663 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
6664 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
6665 if (r < 0)
37185ec8 6666 return r;
37185ec8 6667 } else if (optind < argc) {
e4b61340
LP
6668 log_error("Too many arguments.");
6669 return -EINVAL;
6670 }
6671
6672 return 1;
6673}
6674
f6144808
LP
6675static int parse_time_spec(const char *t, usec_t *_u) {
6676 assert(t);
6677 assert(_u);
6678
6679 if (streq(t, "now"))
6680 *_u = 0;
1a639877 6681 else if (!strchr(t, ':')) {
f6144808
LP
6682 uint64_t u;
6683
1a639877 6684 if (safe_atou64(t, &u) < 0)
f6144808
LP
6685 return -EINVAL;
6686
6687 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
6688 } else {
6689 char *e = NULL;
6690 long hour, minute;
b92bea5d 6691 struct tm tm = {};
f6144808
LP
6692 time_t s;
6693 usec_t n;
6694
6695 errno = 0;
6696 hour = strtol(t, &e, 10);
8333c77e 6697 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
6698 return -EINVAL;
6699
6700 minute = strtol(e+1, &e, 10);
8333c77e 6701 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
6702 return -EINVAL;
6703
6704 n = now(CLOCK_REALTIME);
08e4b1c5
LP
6705 s = (time_t) (n / USEC_PER_SEC);
6706
f6144808
LP
6707 assert_se(localtime_r(&s, &tm));
6708
6709 tm.tm_hour = (int) hour;
6710 tm.tm_min = (int) minute;
08e4b1c5 6711 tm.tm_sec = 0;
f6144808
LP
6712
6713 assert_se(s = mktime(&tm));
6714
6715 *_u = (usec_t) s * USEC_PER_SEC;
6716
6717 while (*_u <= n)
6718 *_u += USEC_PER_DAY;
6719 }
6720
6721 return 0;
6722}
6723
e4b61340
LP
6724static int shutdown_parse_argv(int argc, char *argv[]) {
6725
6726 enum {
6727 ARG_HELP = 0x100,
514f4ef5 6728 ARG_NO_WALL
e4b61340
LP
6729 };
6730
6731 static const struct option options[] = {
6732 { "help", no_argument, NULL, ARG_HELP },
6733 { "halt", no_argument, NULL, 'H' },
6734 { "poweroff", no_argument, NULL, 'P' },
6735 { "reboot", no_argument, NULL, 'r' },
04ebb595 6736 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 6737 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6738 {}
e4b61340
LP
6739 };
6740
f6144808 6741 int c, r;
e4b61340
LP
6742
6743 assert(argc >= 0);
6744 assert(argv);
6745
75836b9d 6746 while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
e4b61340
LP
6747 switch (c) {
6748
6749 case ARG_HELP:
601185b4
ZJS
6750 shutdown_help();
6751 return 0;
e4b61340
LP
6752
6753 case 'H':
6754 arg_action = ACTION_HALT;
6755 break;
6756
6757 case 'P':
6758 arg_action = ACTION_POWEROFF;
6759 break;
6760
6761 case 'r':
5622dde3
KS
6762 if (kexec_loaded())
6763 arg_action = ACTION_KEXEC;
6764 else
6765 arg_action = ACTION_REBOOT;
e4b61340
LP
6766 break;
6767
04ebb595
LP
6768 case 'K':
6769 arg_action = ACTION_KEXEC;
6770 break;
6771
e4b61340
LP
6772 case 'h':
6773 if (arg_action != ACTION_HALT)
6774 arg_action = ACTION_POWEROFF;
6775 break;
6776
6777 case 'k':
6778 arg_dry = true;
6779 break;
6780
514f4ef5
LP
6781 case ARG_NO_WALL:
6782 arg_no_wall = true;
6783 break;
6784
e4b61340
LP
6785 case 't':
6786 case 'a':
75836b9d
JS
6787 case 'f':
6788 case 'F':
e4b61340
LP
6789 /* Compatibility nops */
6790 break;
6791
f6144808
LP
6792 case 'c':
6793 arg_action = ACTION_CANCEL_SHUTDOWN;
6794 break;
6795
e4b61340
LP
6796 case '?':
6797 return -EINVAL;
6798
6799 default:
eb9da376 6800 assert_not_reached("Unhandled option");
e4b61340 6801 }
e4b61340 6802
dfcc5c33 6803 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
6804 r = parse_time_spec(argv[optind], &arg_when);
6805 if (r < 0) {
f6144808
LP
6806 log_error("Failed to parse time specification: %s", argv[optind]);
6807 return r;
6808 }
6b5ad000 6809 } else
08e4b1c5 6810 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 6811
dfcc5c33
MS
6812 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
6813 /* No time argument for shutdown cancel */
6814 arg_wall = argv + optind;
6815 else if (argc > optind + 1)
6816 /* We skip the time argument */
e4b61340
LP
6817 arg_wall = argv + optind + 1;
6818
6819 optind = argc;
6820
6821 return 1;
e4b61340
LP
6822}
6823
6824static int telinit_parse_argv(int argc, char *argv[]) {
6825
6826 enum {
6827 ARG_HELP = 0x100,
514f4ef5 6828 ARG_NO_WALL
e4b61340
LP
6829 };
6830
6831 static const struct option options[] = {
6832 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 6833 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6834 {}
e4b61340
LP
6835 };
6836
6837 static const struct {
6838 char from;
6839 enum action to;
6840 } table[] = {
6841 { '0', ACTION_POWEROFF },
6842 { '6', ACTION_REBOOT },
ef2f1067 6843 { '1', ACTION_RESCUE },
e4b61340
LP
6844 { '2', ACTION_RUNLEVEL2 },
6845 { '3', ACTION_RUNLEVEL3 },
6846 { '4', ACTION_RUNLEVEL4 },
6847 { '5', ACTION_RUNLEVEL5 },
6848 { 's', ACTION_RESCUE },
6849 { 'S', ACTION_RESCUE },
6850 { 'q', ACTION_RELOAD },
6851 { 'Q', ACTION_RELOAD },
6852 { 'u', ACTION_REEXEC },
6853 { 'U', ACTION_REEXEC }
6854 };
6855
6856 unsigned i;
6857 int c;
6858
6859 assert(argc >= 0);
6860 assert(argv);
6861
601185b4 6862 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6863 switch (c) {
6864
6865 case ARG_HELP:
601185b4
ZJS
6866 telinit_help();
6867 return 0;
e4b61340 6868
514f4ef5
LP
6869 case ARG_NO_WALL:
6870 arg_no_wall = true;
6871 break;
6872
e4b61340
LP
6873 case '?':
6874 return -EINVAL;
6875
6876 default:
eb9da376 6877 assert_not_reached("Unhandled option");
e4b61340 6878 }
e4b61340
LP
6879
6880 if (optind >= argc) {
601185b4
ZJS
6881 log_error("%s: required argument missing.",
6882 program_invocation_short_name);
e4b61340
LP
6883 return -EINVAL;
6884 }
6885
6886 if (optind + 1 < argc) {
6887 log_error("Too many arguments.");
6888 return -EINVAL;
6889 }
6890
6891 if (strlen(argv[optind]) != 1) {
6892 log_error("Expected single character argument.");
6893 return -EINVAL;
6894 }
6895
6896 for (i = 0; i < ELEMENTSOF(table); i++)
6897 if (table[i].from == argv[optind][0])
6898 break;
6899
6900 if (i >= ELEMENTSOF(table)) {
b0193f1c 6901 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
6902 return -EINVAL;
6903 }
6904
6905 arg_action = table[i].to;
6906
6907 optind ++;
6908
6909 return 1;
6910}
6911
6912static int runlevel_parse_argv(int argc, char *argv[]) {
6913
6914 enum {
6915 ARG_HELP = 0x100,
6916 };
6917
6918 static const struct option options[] = {
6919 { "help", no_argument, NULL, ARG_HELP },
eb9da376 6920 {}
e4b61340
LP
6921 };
6922
6923 int c;
6924
6925 assert(argc >= 0);
6926 assert(argv);
6927
601185b4 6928 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6929 switch (c) {
6930
6931 case ARG_HELP:
601185b4
ZJS
6932 runlevel_help();
6933 return 0;
e4b61340
LP
6934
6935 case '?':
6936 return -EINVAL;
6937
6938 default:
eb9da376 6939 assert_not_reached("Unhandled option");
e4b61340 6940 }
e4b61340
LP
6941
6942 if (optind < argc) {
6943 log_error("Too many arguments.");
6944 return -EINVAL;
6945 }
6946
6947 return 1;
6948}
6949
6950static int parse_argv(int argc, char *argv[]) {
6951 assert(argc >= 0);
6952 assert(argv);
6953
6954 if (program_invocation_short_name) {
6955
6956 if (strstr(program_invocation_short_name, "halt")) {
6957 arg_action = ACTION_HALT;
6958 return halt_parse_argv(argc, argv);
6959 } else if (strstr(program_invocation_short_name, "poweroff")) {
6960 arg_action = ACTION_POWEROFF;
6961 return halt_parse_argv(argc, argv);
6962 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
6963 if (kexec_loaded())
6964 arg_action = ACTION_KEXEC;
6965 else
6966 arg_action = ACTION_REBOOT;
e4b61340
LP
6967 return halt_parse_argv(argc, argv);
6968 } else if (strstr(program_invocation_short_name, "shutdown")) {
6969 arg_action = ACTION_POWEROFF;
6970 return shutdown_parse_argv(argc, argv);
6971 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
6972
6973 if (sd_booted() > 0) {
f459b602 6974 arg_action = _ACTION_INVALID;
d5ca5f11
LP
6975 return telinit_parse_argv(argc, argv);
6976 } else {
6977 /* Hmm, so some other init system is
6978 * running, we need to forward this
6979 * request to it. For now we simply
6980 * guess that it is Upstart. */
6981
4ad61fd1 6982 execv(TELINIT, argv);
d5ca5f11
LP
6983
6984 log_error("Couldn't find an alternative telinit implementation to spawn.");
6985 return -EIO;
6986 }
6987
e4b61340
LP
6988 } else if (strstr(program_invocation_short_name, "runlevel")) {
6989 arg_action = ACTION_RUNLEVEL;
6990 return runlevel_parse_argv(argc, argv);
6991 }
6992 }
6993
6994 arg_action = ACTION_SYSTEMCTL;
6995 return systemctl_parse_argv(argc, argv);
6996}
6997
44a6b1b6 6998_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
6999
7000 static const char table[_ACTION_MAX] = {
7001 [ACTION_HALT] = '0',
7002 [ACTION_POWEROFF] = '0',
7003 [ACTION_REBOOT] = '6',
7004 [ACTION_RUNLEVEL2] = '2',
7005 [ACTION_RUNLEVEL3] = '3',
7006 [ACTION_RUNLEVEL4] = '4',
7007 [ACTION_RUNLEVEL5] = '5',
7008 [ACTION_RESCUE] = '1'
7009 };
7010
d55ae9e6
LP
7011 assert(arg_action < _ACTION_MAX);
7012
7013 return table[arg_action];
7014}
7015
d55ae9e6 7016static int talk_initctl(void) {
cbc9fbd1
LP
7017
7018 struct init_request request = {
7019 .magic = INIT_MAGIC,
7020 .sleeptime = 0,
7021 .cmd = INIT_CMD_RUNLVL
7022 };
7023
7fd1b19b 7024 _cleanup_close_ int fd = -1;
d55ae9e6 7025 char rl;
cbc9fbd1 7026 int r;
eb22ac37 7027
427b47c4
ZJS
7028 rl = action_to_runlevel();
7029 if (!rl)
eb22ac37
LP
7030 return 0;
7031
d55ae9e6
LP
7032 request.runlevel = rl;
7033
427b47c4
ZJS
7034 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
7035 if (fd < 0) {
d55ae9e6
LP
7036 if (errno == ENOENT)
7037 return 0;
eb22ac37 7038
56f64d95 7039 log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
eb22ac37 7040 return -errno;
d55ae9e6 7041 }
eb22ac37 7042
553acb7b
ZJS
7043 r = loop_write(fd, &request, sizeof(request), false);
7044 if (r < 0)
7045 return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
eb22ac37
LP
7046
7047 return 1;
e4b61340
LP
7048}
7049
41dd15e4 7050static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 7051
7e4249b9
LP
7052 static const struct {
7053 const char* verb;
7054 const enum {
7055 MORE,
7056 LESS,
7057 EQUAL
7058 } argc_cmp;
7059 const int argc;
f459b602 7060 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
7061 const enum {
7062 NOBUS = 1,
7063 FORCE,
7064 } bus;
7e4249b9 7065 } verbs[] = {
d8fba7c6 7066 { "list-units", MORE, 0, list_units },
d08e75ed 7067 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
7068 { "list-sockets", MORE, 1, list_sockets },
7069 { "list-timers", MORE, 1, list_timers },
7070 { "list-jobs", MORE, 1, list_jobs },
0d292f5e 7071 { "list-machines", MORE, 1, list_machines },
ee5762e3 7072 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
7073 { "cancel", MORE, 2, cancel_job },
7074 { "start", MORE, 2, start_unit },
7075 { "stop", MORE, 2, start_unit },
a76f7be2 7076 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7077 { "reload", MORE, 2, start_unit },
7078 { "restart", MORE, 2, start_unit },
7079 { "try-restart", MORE, 2, start_unit },
7080 { "reload-or-restart", MORE, 2, start_unit },
7081 { "reload-or-try-restart", MORE, 2, start_unit },
7082 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 7083 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7084 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
7085 { "isolate", EQUAL, 2, start_unit },
8a0867d6 7086 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
7087 { "is-active", MORE, 2, check_unit_active },
7088 { "check", MORE, 2, check_unit_active },
7089 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 7090 { "show", MORE, 1, show },
ad2a0358 7091 { "cat", MORE, 2, cat, NOBUS },
265a7a2a 7092 { "status", MORE, 1, show },
b43f208f 7093 { "help", MORE, 2, show },
ee5762e3
LP
7094 { "snapshot", LESS, 2, snapshot },
7095 { "delete", MORE, 2, delete_snapshot },
7096 { "daemon-reload", EQUAL, 1, daemon_reload },
7097 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 7098 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
7099 { "set-environment", MORE, 2, set_environment },
7100 { "unset-environment", MORE, 2, set_environment },
ac3efa8a 7101 { "import-environment", MORE, 1, import_environment},
d08e75ed
ZJS
7102 { "halt", EQUAL, 1, start_special, FORCE },
7103 { "poweroff", EQUAL, 1, start_special, FORCE },
b986229e 7104 { "reboot", MORE, 1, start_special, FORCE },
20b09ca7 7105 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
7106 { "suspend", EQUAL, 1, start_special },
7107 { "hibernate", EQUAL, 1, start_special },
6524990f 7108 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
7109 { "default", EQUAL, 1, start_special },
7110 { "rescue", EQUAL, 1, start_special },
7111 { "emergency", EQUAL, 1, start_special },
20b09ca7 7112 { "exit", EQUAL, 1, start_special },
fdf20a31 7113 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
7114 { "enable", MORE, 2, enable_unit, NOBUS },
7115 { "disable", MORE, 2, enable_unit, NOBUS },
7116 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
7117 { "reenable", MORE, 2, enable_unit, NOBUS },
7118 { "preset", MORE, 2, enable_unit, NOBUS },
d309c1c3 7119 { "preset-all", EQUAL, 1, preset_all, NOBUS },
d08e75ed
ZJS
7120 { "mask", MORE, 2, enable_unit, NOBUS },
7121 { "unmask", MORE, 2, enable_unit, NOBUS },
7122 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 7123 { "switch-root", MORE, 2, switch_root },
e31165b2 7124 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
7125 { "set-default", EQUAL, 2, set_default, NOBUS },
7126 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 7127 { "set-property", MORE, 3, set_property },
99813a19 7128 { "is-system-running", EQUAL, 1, is_system_running },
7d4fb3b1
RC
7129 { "add-wants", MORE, 3, add_dependency, NOBUS },
7130 { "add-requires", MORE, 3, add_dependency, NOBUS },
7131 { "edit", MORE, 2, edit, NOBUS },
d08e75ed
ZJS
7132 {}
7133 }, *verb = verbs;
7e4249b9 7134
e4b61340 7135 int left;
7e4249b9 7136
e4b61340
LP
7137 assert(argc >= 0);
7138 assert(argv);
7e4249b9
LP
7139
7140 left = argc - optind;
7141
d08e75ed
ZJS
7142 /* Special rule: no arguments (left == 0) means "list-units" */
7143 if (left > 0) {
b43f208f
KS
7144 if (streq(argv[optind], "help") && !argv[optind+1]) {
7145 log_error("This command expects one or more "
7146 "unit names. Did you mean --help?");
7147 return -EINVAL;
0183528f
LP
7148 }
7149
d08e75ed
ZJS
7150 for (; verb->verb; verb++)
7151 if (streq(argv[optind], verb->verb))
7152 goto found;
7e4249b9 7153
d08e75ed
ZJS
7154 log_error("Unknown operation '%s'.", argv[optind]);
7155 return -EINVAL;
7e4249b9 7156 }
d08e75ed 7157found:
7e4249b9 7158
d08e75ed 7159 switch (verb->argc_cmp) {
7e4249b9
LP
7160
7161 case EQUAL:
d08e75ed 7162 if (left != verb->argc) {
7e4249b9 7163 log_error("Invalid number of arguments.");
e4b61340 7164 return -EINVAL;
7e4249b9
LP
7165 }
7166
7167 break;
7168
7169 case MORE:
d08e75ed 7170 if (left < verb->argc) {
7e4249b9 7171 log_error("Too few arguments.");
e4b61340 7172 return -EINVAL;
7e4249b9
LP
7173 }
7174
7175 break;
7176
7177 case LESS:
d08e75ed 7178 if (left > verb->argc) {
7e4249b9 7179 log_error("Too many arguments.");
e4b61340 7180 return -EINVAL;
7e4249b9
LP
7181 }
7182
7183 break;
7184
7185 default:
7186 assert_not_reached("Unknown comparison operator.");
7187 }
7188
ee5762e3
LP
7189 /* Require a bus connection for all operations but
7190 * enable/disable */
d08e75ed
ZJS
7191 if (verb->bus == NOBUS) {
7192 if (!bus && !avoid_bus()) {
da927ba9 7193 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
d08e75ed
ZJS
7194 return -EIO;
7195 }
82e23ddd 7196
d08e75ed 7197 } else {
82e23ddd
LP
7198 if (running_in_chroot() > 0) {
7199 log_info("Running in chroot, ignoring request.");
7200 return 0;
7201 }
7202
d08e75ed 7203 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
da927ba9 7204 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
82e23ddd
LP
7205 return -EIO;
7206 }
ee5762e3
LP
7207 }
7208
d08e75ed 7209 return verb->dispatch(bus, argv + optind);
e4b61340
LP
7210}
7211
f459b602 7212static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
7213
7214 if (bus) {
7215 /* First, try systemd via D-Bus. */
d76702a7 7216 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
7217 return 0;
7218 }
7219
7220 /* Nothing else worked, so let's try signals */
7221 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
7222
4a62c710
MS
7223 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
7224 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
7225
7226 return 0;
7227}
7228
f459b602 7229static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
7230
7231 if (bus) {
7232 /* First, try systemd via D-Bus. */
729e3769 7233 if (start_unit(bus, NULL) >= 0)
983d9c90 7234 goto done;
e4b61340
LP
7235 }
7236
7237 /* Nothing else worked, so let's try
7238 * /dev/initctl */
fbc43921 7239 if (talk_initctl() > 0)
983d9c90 7240 goto done;
d55ae9e6
LP
7241
7242 log_error("Failed to talk to init daemon.");
7243 return -EIO;
983d9c90
LP
7244
7245done:
7246 warn_wall(arg_action);
7247 return 0;
e4b61340
LP
7248}
7249
477def80 7250static int halt_now(enum action a) {
e606bb61 7251
4a3ad399
LP
7252 /* The kernel will automaticall flush ATA disks and suchlike
7253 * on reboot(), but the file systems need to be synce'd
7254 * explicitly in advance. */
7255 sync();
7256
7257 /* Make sure C-A-D is handled by the kernel from this point
7258 * on... */
e606bb61
LP
7259 reboot(RB_ENABLE_CAD);
7260
4c80c73c 7261 switch (a) {
e606bb61
LP
7262
7263 case ACTION_HALT:
7264 log_info("Halting.");
7265 reboot(RB_HALT_SYSTEM);
477def80 7266 return -errno;
e606bb61
LP
7267
7268 case ACTION_POWEROFF:
7269 log_info("Powering off.");
7270 reboot(RB_POWER_OFF);
477def80 7271 return -errno;
e606bb61 7272
477def80
LP
7273 case ACTION_REBOOT: {
7274 _cleanup_free_ char *param = NULL;
cbc9fbd1 7275
477def80
LP
7276 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
7277 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
7278 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
7279 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 7280 }
e606bb61 7281
477def80
LP
7282 log_info("Rebooting.");
7283 reboot(RB_AUTOBOOT);
7284 return -errno;
e606bb61
LP
7285 }
7286
477def80
LP
7287 default:
7288 assert_not_reached("Unknown action.");
7289 }
e606bb61
LP
7290}
7291
f459b602 7292static int halt_main(sd_bus *bus) {
e4b61340
LP
7293 int r;
7294
748ebafa
LP
7295 r = check_inhibitors(bus, arg_action);
7296 if (r < 0)
7297 return r;
b37844d3 7298
bc8c2f5c 7299 if (geteuid() != 0) {
7e59bfcb
LP
7300 /* Try logind if we are a normal user and no special
7301 * mode applies. Maybe PolicyKit allows us to shutdown
7302 * the machine. */
7303
7304 if (arg_when <= 0 &&
7305 !arg_dry &&
b37844d3 7306 arg_force <= 0 &&
7e59bfcb
LP
7307 (arg_action == ACTION_POWEROFF ||
7308 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
7309 r = reboot_with_logind(bus, arg_action);
7310 if (r >= 0)
7311 return r;
7312 }
7313
cc8a7a61 7314 log_error("Must be root.");
bc8c2f5c
LP
7315 return -EPERM;
7316 }
7317
f6144808 7318 if (arg_when > 0) {
f0efea23
DM
7319 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7320 _cleanup_bus_close_unref_ sd_bus *b = NULL;
cafbecf3 7321 _cleanup_free_ char *m = NULL;
9be9828c 7322
f0efea23
DM
7323 if (avoid_bus()) {
7324 log_error("Unable to perform operation without bus connection.");
7325 return -ENOSYS;
7326 }
7327
7328 r = sd_bus_open_system(&b);
7329 if (r < 0)
d3a2a053 7330 return log_error_errno(r, "Unable to open system bus: %m");
f0efea23 7331
9be9828c 7332 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
7333 if (!m)
7334 return log_oom();
7335
f0efea23
DM
7336 r = sd_bus_set_property(
7337 b,
7338 "org.freedesktop.login1",
7339 "/org/freedesktop/login1",
7340 "org.freedesktop.login1.Manager",
7341 "WallMessage",
7342 &error,
7343 "s", m);
7344 if (r < 0) {
7345 log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
7346 bus_error_message(&error, r));
7347 sd_bus_error_free(&error);
7348 }
7349
7350 r = sd_bus_set_property(
7351 b,
7352 "org.freedesktop.login1",
7353 "/org/freedesktop/login1",
7354 "org.freedesktop.login1.Manager",
7355 "EnableWallMessages",
7356 &error,
7357 "b", !arg_no_wall);
7358 if (r < 0) {
7359 log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
7360 bus_error_message(&error, r));
7361 sd_bus_error_free(&error);
7362 }
9be9828c 7363
f0efea23
DM
7364 r = sd_bus_call_method(
7365 b,
7366 "org.freedesktop.login1",
7367 "/org/freedesktop/login1",
7368 "org.freedesktop.login1.Manager",
7369 "ScheduleShutdown",
7370 &error,
7371 NULL,
7372 "st",
7373 arg_action == ACTION_HALT ? "halt" :
7374 arg_action == ACTION_POWEROFF ? "poweroff" :
7375 arg_action == ACTION_KEXEC ? "kexec" :
7376 "reboot",
7377 arg_when);
9be9828c 7378 if (r < 0)
f0efea23
DM
7379 log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
7380 bus_error_message(&error, r));
08e4b1c5 7381 else {
7e59bfcb
LP
7382 char date[FORMAT_TIMESTAMP_MAX];
7383
08e4b1c5
LP
7384 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
7385 format_timestamp(date, sizeof(date), arg_when));
f6144808 7386 return 0;
08e4b1c5 7387 }
f6144808
LP
7388 }
7389
65491fd8 7390 if (!arg_dry && !arg_force)
e4b61340
LP
7391 return start_with_fallback(bus);
7392
d90e1a30
LP
7393 if (!arg_no_wtmp) {
7394 if (sd_booted() > 0)
7395 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
7396 else {
7397 r = utmp_put_shutdown();
7398 if (r < 0)
da927ba9 7399 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 7400 }
d90e1a30 7401 }
e4b61340 7402
e4b61340
LP
7403 if (arg_dry)
7404 return 0;
7405
477def80 7406 r = halt_now(arg_action);
da927ba9 7407 log_error_errno(r, "Failed to reboot: %m");
477def80
LP
7408
7409 return r;
e4b61340
LP
7410}
7411
7412static int runlevel_main(void) {
7413 int r, runlevel, previous;
7414
729e3769
LP
7415 r = utmp_get_runlevel(&runlevel, &previous);
7416 if (r < 0) {
7417 puts("unknown");
e4b61340
LP
7418 return r;
7419 }
7420
7421 printf("%c %c\n",
7422 previous <= 0 ? 'N' : previous,
7423 runlevel <= 0 ? 'N' : runlevel);
7424
7425 return 0;
7426}
7427
7428int main(int argc, char*argv[]) {
24996861 7429 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
f459b602 7430 int r;
e4b61340 7431
a9cdc94f 7432 setlocale(LC_ALL, "");
e4b61340 7433 log_parse_environment();
2396fb04 7434 log_open();
e4b61340 7435
184ecaf7
DR
7436 /* Explicitly not on_tty() to avoid setting cached value.
7437 * This becomes relevant for piping output which might be
7438 * ellipsized. */
7439 original_stdout_is_tty = isatty(STDOUT_FILENO);
7440
04ebb595 7441 r = parse_argv(argc, argv);
f459b602 7442 if (r <= 0)
e4b61340 7443 goto finish;
7e4249b9 7444
e4b61340
LP
7445 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
7446 * let's shortcut this */
7447 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 7448 r = runlevel_main();
e4b61340
LP
7449 goto finish;
7450 }
7451
82e23ddd
LP
7452 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
7453 log_info("Running in chroot, ignoring request.");
f459b602 7454 r = 0;
82e23ddd
LP
7455 goto finish;
7456 }
7457
41dd15e4
LP
7458 if (!avoid_bus())
7459 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
7460
6e646d22
LP
7461 if (bus)
7462 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
7463
41dd15e4
LP
7464 /* systemctl_main() will print an error message for the bus
7465 * connection, but only if it needs to */
e4b61340
LP
7466
7467 switch (arg_action) {
7468
22f4096c 7469 case ACTION_SYSTEMCTL:
f459b602 7470 r = systemctl_main(bus, argc, argv, r);
e4b61340 7471 break;
e4b61340
LP
7472
7473 case ACTION_HALT:
7474 case ACTION_POWEROFF:
7475 case ACTION_REBOOT:
5622dde3 7476 case ACTION_KEXEC:
22f4096c 7477 r = halt_main(bus);
e4b61340
LP
7478 break;
7479
e4b61340
LP
7480 case ACTION_RUNLEVEL2:
7481 case ACTION_RUNLEVEL3:
7482 case ACTION_RUNLEVEL4:
7483 case ACTION_RUNLEVEL5:
7484 case ACTION_RESCUE:
514f4ef5 7485 case ACTION_EMERGENCY:
eb22ac37 7486 case ACTION_DEFAULT:
22f4096c 7487 r = start_with_fallback(bus);
e4b61340 7488 break;
7e4249b9 7489
e4b61340
LP
7490 case ACTION_RELOAD:
7491 case ACTION_REEXEC:
22f4096c 7492 r = reload_with_fallback(bus);
e4b61340
LP
7493 break;
7494
dfcc5c33 7495 case ACTION_CANCEL_SHUTDOWN: {
f0efea23
DM
7496 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7497 _cleanup_bus_close_unref_ sd_bus *b = NULL;
f459b602 7498 _cleanup_free_ char *m = NULL;
dfcc5c33 7499
f0efea23
DM
7500 if (avoid_bus()) {
7501 log_error("Unable to perform operation without bus connection.");
7502 return -ENOSYS;
7503 }
7504
7505 r = sd_bus_open_system(&b);
7506 if (r < 0)
d3a2a053 7507 return log_error_errno(r, "Unable to open system bus: %m");
f0efea23 7508
dfcc5c33
MS
7509 if (arg_wall) {
7510 m = strv_join(arg_wall, " ");
7511 if (!m) {
f459b602 7512 r = log_oom();
dfcc5c33
MS
7513 goto finish;
7514 }
7515 }
f459b602 7516
f0efea23
DM
7517 r = sd_bus_set_property(
7518 b,
7519 "org.freedesktop.login1",
7520 "/org/freedesktop/login1",
7521 "org.freedesktop.login1.Manager",
7522 "WallMessage",
7523 &error,
7524 "s", arg_wall);
7525 if (r < 0) {
7526 log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
7527 bus_error_message(&error, r));
7528 sd_bus_error_free(&error);
7529 }
7530
7531 r = sd_bus_set_property(
7532 b,
7533 "org.freedesktop.login1",
7534 "/org/freedesktop/login1",
7535 "org.freedesktop.login1.Manager",
7536 "EnableWallMessages",
7537 &error,
7538 "b", !arg_no_wall);
7539 if (r < 0) {
7540 log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
7541 bus_error_message(&error, r));
7542 sd_bus_error_free(&error);
7543 }
7544
7545 r = sd_bus_call_method(
7546 b,
7547 "org.freedesktop.login1",
7548 "/org/freedesktop/login1",
7549 "org.freedesktop.login1.Manager",
7550 "CancelScheduledShutdown",
7551 &error,
7552 NULL, NULL);
dfcc5c33 7553 if (r < 0)
f0efea23
DM
7554 log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
7555 bus_error_message(&error, r));
f6144808 7556 break;
dfcc5c33 7557 }
f6144808 7558
eb22ac37 7559 case ACTION_RUNLEVEL:
f459b602 7560 case _ACTION_INVALID:
e4b61340
LP
7561 default:
7562 assert_not_reached("Unknown action");
7563 }
7e4249b9
LP
7564
7565finish:
f459b602
MAP
7566 pager_close();
7567 ask_password_agent_close();
7568 polkit_agent_close();
7e4249b9 7569
20b3f379 7570 strv_free(arg_types);
9b9b3d36 7571 strv_free(arg_states);
20b3f379 7572 strv_free(arg_properties);
ea4a240d 7573
f459b602 7574 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 7575}