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