]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
Merge pull request #929 from kaysievers/gpt
[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 3329
97b11eed 3330 dir = mfree(dir);
76d14b87
OS
3331
3332 if (path_get_parent(*dropin, &dir) < 0) {
3333 log_oom();
3334 return;
3335 }
3336
856323c9 3337 printf("%s\n %s", dir,
76d14b87
OS
3338 draw_special_char(DRAW_TREE_RIGHT));
3339 }
3340
3341 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
3342
2b6bf07d 3343 printf("%s%s", basename(*dropin), last ? "\n" : ", ");
76d14b87 3344 }
76d14b87
OS
3345 }
3346
2ee68f72 3347 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2ee68f72 3348 if (ss)
856323c9 3349 printf(" Active: %s%s (%s)%s",
b0d14c69 3350 active_on, strna(i->active_state), ss, active_off);
2ee68f72 3351 else
856323c9 3352 printf(" Active: %s%s%s",
b0d14c69 3353 active_on, strna(i->active_state), active_off);
61cbdc4b 3354
f42806df
LP
3355 if (!isempty(i->result) && !streq(i->result, "success"))
3356 printf(" (Result: %s)", i->result);
3357
584be568
LP
3358 timestamp = (streq_ptr(i->active_state, "active") ||
3359 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
3360 (streq_ptr(i->active_state, "inactive") ||
fdf20a31 3361 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
584be568
LP
3362 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
3363 i->active_exit_timestamp;
3364
bbb8486e 3365 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
3366 s2 = format_timestamp(since2, sizeof(since2), timestamp);
3367
3368 if (s1)
538da63d 3369 printf(" since %s; %s\n", s2, s1);
584be568 3370 else if (s2)
538da63d 3371 printf(" since %s\n", s2);
584be568
LP
3372 else
3373 printf("\n");
3374
90bbc946 3375 if (!i->condition_result && i->condition_timestamp > 0) {
bbb8486e 3376 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
3377 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
3378
59fccdc5
LP
3379 printf("Condition: start %scondition failed%s at %s%s%s\n",
3380 ansi_highlight_yellow(), ansi_highlight_off(),
52990c2e
ZJS
3381 s2, s1 ? "; " : "", s1 ? s1 : "");
3382 if (i->failed_condition_trigger)
3383 printf(" none of the trigger conditions were met\n");
3384 else if (i->failed_condition)
3385 printf(" %s=%s%s was not met\n",
3386 i->failed_condition,
3387 i->failed_condition_negate ? "!" : "",
59fccdc5
LP
3388 i->failed_condition_parameter);
3389 }
3390
3391 if (!i->assert_result && i->assert_timestamp > 0) {
3392 s1 = format_timestamp_relative(since1, sizeof(since1), i->assert_timestamp);
3393 s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
3394
3395 printf(" Assert: start %sassertion failed%s at %s%s%s\n",
3396 ansi_highlight_red(), ansi_highlight_off(),
3397 s2, s1 ? "; " : "", s1 ? s1 : "");
3398 if (i->failed_assert_trigger)
3399 printf(" none of the trigger assertions were met\n");
3400 else if (i->failed_assert)
3401 printf(" %s=%s%s was not met\n",
3402 i->failed_assert,
3403 i->failed_assert_negate ? "!" : "",
3404 i->failed_assert_parameter);
90bbc946
LP
3405 }
3406
61cbdc4b 3407 if (i->sysfs_path)
856323c9 3408 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 3409 if (i->where)
856323c9 3410 printf(" Where: %s\n", i->where);
9feeba4b 3411 if (i->what)
856323c9 3412 printf(" What: %s\n", i->what);
49dbfa7b 3413
13160134 3414 STRV_FOREACH(t, i->documentation)
856323c9 3415 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 3416
13160134 3417 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 3418 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 3419
b8131a87 3420 if (i->accept)
856323c9 3421 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 3422
582a507f 3423 LIST_FOREACH(exec, p, i->exec) {
13160134 3424 _cleanup_free_ char *argv = NULL;
9a57c629 3425 bool good;
582a507f
LP
3426
3427 /* Only show exited processes here */
3428 if (p->code == 0)
3429 continue;
3430
13160134 3431 argv = strv_join(p->argv, " ");
1fa2f38f 3432 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
582a507f 3433
96342de6 3434 good = is_clean_exit_lsb(p->code, p->status, NULL);
9a57c629 3435 if (!good) {
0b5a519c
DS
3436 on = ansi_highlight_red();
3437 off = ansi_highlight_off();
9a57c629
LP
3438 } else
3439 on = off = "";
3440
3441 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
3442
d06dacd0
LP
3443 if (p->code == CLD_EXITED) {
3444 const char *c;
3445
582a507f 3446 printf("status=%i", p->status);
d06dacd0 3447
1b64d026
LP
3448 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
3449 if (c)
d06dacd0
LP
3450 printf("/%s", c);
3451
3452 } else
582a507f 3453 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
3454
3455 printf(")%s\n", off);
3456
582a507f
LP
3457 if (i->main_pid == p->pid &&
3458 i->start_timestamp == p->start_timestamp &&
3459 i->exit_timestamp == p->start_timestamp)
3460 /* Let's not show this twice */
3461 i->main_pid = 0;
3462
3463 if (p->pid == i->control_pid)
3464 i->control_pid = 0;
3465 }
3466
61cbdc4b 3467 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 3468 if (i->main_pid > 0) {
8c06592f 3469 printf(" Main PID: "PID_FMT, i->main_pid);
61cbdc4b
LP
3470
3471 if (i->running) {
13160134
ZJS
3472 _cleanup_free_ char *comm = NULL;
3473 get_process_comm(i->main_pid, &comm);
3474 if (comm)
3475 printf(" (%s)", comm);
6d4fc029 3476 } else if (i->exit_code > 0) {
61cbdc4b
LP
3477 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
3478
d06dacd0
LP
3479 if (i->exit_code == CLD_EXITED) {
3480 const char *c;
3481
61cbdc4b 3482 printf("status=%i", i->exit_status);
d06dacd0 3483
1b64d026
LP
3484 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
3485 if (c)
d06dacd0
LP
3486 printf("/%s", c);
3487
3488 } else
582a507f 3489 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
3490 printf(")");
3491 }
61cbdc4b 3492
13160134
ZJS
3493 if (i->control_pid > 0)
3494 printf(";");
3495 }
61cbdc4b
LP
3496
3497 if (i->control_pid > 0) {
13160134 3498 _cleanup_free_ char *c = NULL;
61cbdc4b 3499
8c06592f 3500 printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid);
61cbdc4b 3501
13160134
ZJS
3502 get_process_comm(i->control_pid, &c);
3503 if (c)
3504 printf(" (%s)", c);
61cbdc4b
LP
3505 }
3506
3507 printf("\n");
3508 }
3509
17bb7382 3510 if (i->status_text)
856323c9 3511 printf(" Status: \"%s\"\n", i->status_text);
b4af5a80
LP
3512 if (i->status_errno > 0)
3513 printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
17bb7382 3514
934277fe
LP
3515 if (i->memory_current != (uint64_t) -1) {
3516 char buf[FORMAT_BYTES_MAX];
3517
3518 printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
3519
3520 if (i->memory_limit != (uint64_t) -1)
3521 printf(" (limit: %s)\n", format_bytes(buf, sizeof(buf), i->memory_limit));
3522 else
3523 printf("\n");
3524 }
3525
5ad096b3
LP
3526 if (i->cpu_usage_nsec != (uint64_t) -1) {
3527 char buf[FORMAT_TIMESPAN_MAX];
3528 printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
3529 }
3530
4ad49000 3531 if (i->control_group &&
8fcf784d 3532 (i->main_pid > 0 || i->control_pid > 0 ||
de33fc62 3533 ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0))) {
ab35fb1b
LP
3534 unsigned c;
3535
4ad49000 3536 printf(" CGroup: %s\n", i->control_group);
ab35fb1b 3537
de33fc62 3538 if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
b69d29ce
LP
3539 unsigned k = 0;
3540 pid_t extra[2];
8fcf784d 3541 static const char prefix[] = " ";
b69d29ce
LP
3542
3543 c = columns();
e8853816
ZJS
3544 if (c > sizeof(prefix) - 1)
3545 c -= sizeof(prefix) - 1;
a8f11321
LP
3546 else
3547 c = 0;
ab35fb1b 3548
b69d29ce
LP
3549 if (i->main_pid > 0)
3550 extra[k++] = i->main_pid;
3551
3552 if (i->control_pid > 0)
3553 extra[k++] = i->control_pid;
3554
3c756001 3555 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags());
a8f11321 3556 }
c59760ee 3557 }
45fb0699 3558
f459b602 3559 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL) {
3c756001
LP
3560 show_journal_by_unit(
3561 stdout,
3562 i->id,
3563 arg_output,
3564 0,
3565 i->inactive_exit_timestamp_monotonic,
3566 arg_lines,
3567 getuid(),
3568 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
3569 SD_JOURNAL_LOCAL_ONLY,
3570 arg_scope == UNIT_FILE_SYSTEM,
3571 ellipsized);
6f003b43 3572 }
86aa7ba4 3573
45fb0699 3574 if (i->need_daemon_reload)
3f36991e 3575 warn_unit_file_changed(i->id);
61cbdc4b
LP
3576}
3577
b43f208f 3578static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
3579 char **p;
3580
3581 assert(i);
3582
3583 if (!i->documentation) {
3584 log_info("Documentation for %s not known.", i->id);
3585 return;
3586 }
3587
78002a67
ZJS
3588 STRV_FOREACH(p, i->documentation)
3589 if (startswith(*p, "man:"))
3590 show_man_page(*p + 4, false);
3591 else
0315fe37 3592 log_info("Can't show: %s", *p);
256425cc
LP
3593}
3594
f459b602
MAP
3595static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *i, const char *contents) {
3596 int r;
61cbdc4b 3597
a4c279f8 3598 assert(name);
f459b602 3599 assert(m);
a4c279f8
LP
3600 assert(i);
3601
f459b602 3602 switch (contents[0]) {
61cbdc4b 3603
f459b602 3604 case SD_BUS_TYPE_STRING: {
61cbdc4b
LP
3605 const char *s;
3606
f459b602
MAP
3607 r = sd_bus_message_read(m, "s", &s);
3608 if (r < 0)
3609 return bus_log_parse_error(r);
61cbdc4b 3610
a4c279f8 3611 if (!isempty(s)) {
61cbdc4b
LP
3612 if (streq(name, "Id"))
3613 i->id = s;
3614 else if (streq(name, "LoadState"))
3615 i->load_state = s;
3616 else if (streq(name, "ActiveState"))
3617 i->active_state = s;
3618 else if (streq(name, "SubState"))
3619 i->sub_state = s;
3620 else if (streq(name, "Description"))
3621 i->description = s;
3622 else if (streq(name, "FragmentPath"))
1b64d026
LP
3623 i->fragment_path = s;
3624 else if (streq(name, "SourcePath"))
3625 i->source_path = s;
286ca485 3626#ifndef NOLEGACY
a00963a2
LP
3627 else if (streq(name, "DefaultControlGroup")) {
3628 const char *e;
3629 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
3630 if (e)
3631 i->control_group = e;
3632 }
4ad49000
LP
3633#endif
3634 else if (streq(name, "ControlGroup"))
3635 i->control_group = s;
61cbdc4b
LP
3636 else if (streq(name, "StatusText"))
3637 i->status_text = s;
175728c4
HH
3638 else if (streq(name, "PIDFile"))
3639 i->pid_file = s;
61cbdc4b
LP
3640 else if (streq(name, "SysFSPath"))
3641 i->sysfs_path = s;
3642 else if (streq(name, "Where"))
3643 i->where = s;
3644 else if (streq(name, "What"))
3645 i->what = s;
4a9e2fff
LP
3646 else if (streq(name, "Following"))
3647 i->following = s;
a4375746
LP
3648 else if (streq(name, "UnitFileState"))
3649 i->unit_file_state = s;
d2dc52db
LP
3650 else if (streq(name, "UnitFilePreset"))
3651 i->unit_file_preset = s;
f42806df
LP
3652 else if (streq(name, "Result"))
3653 i->result = s;
61cbdc4b
LP
3654 }
3655
3656 break;
3657 }
3658
f459b602
MAP
3659 case SD_BUS_TYPE_BOOLEAN: {
3660 int b;
b8131a87 3661
f459b602
MAP
3662 r = sd_bus_message_read(m, "b", &b);
3663 if (r < 0)
3664 return bus_log_parse_error(r);
b8131a87
LP
3665
3666 if (streq(name, "Accept"))
3667 i->accept = b;
45fb0699
LP
3668 else if (streq(name, "NeedDaemonReload"))
3669 i->need_daemon_reload = b;
90bbc946
LP
3670 else if (streq(name, "ConditionResult"))
3671 i->condition_result = b;
59fccdc5
LP
3672 else if (streq(name, "AssertResult"))
3673 i->assert_result = b;
b8131a87
LP
3674
3675 break;
3676 }
3677
f459b602 3678 case SD_BUS_TYPE_UINT32: {
61cbdc4b
LP
3679 uint32_t u;
3680
f459b602
MAP
3681 r = sd_bus_message_read(m, "u", &u);
3682 if (r < 0)
3683 return bus_log_parse_error(r);
61cbdc4b
LP
3684
3685 if (streq(name, "MainPID")) {
3686 if (u > 0) {
3687 i->main_pid = (pid_t) u;
3688 i->running = true;
3689 }
3690 } else if (streq(name, "ControlPID"))
3691 i->control_pid = (pid_t) u;
3692 else if (streq(name, "ExecMainPID")) {
3693 if (u > 0)
3694 i->main_pid = (pid_t) u;
3695 } else if (streq(name, "NAccepted"))
3696 i->n_accepted = u;
3697 else if (streq(name, "NConnections"))
3698 i->n_connections = u;
3699
3700 break;
3701 }
3702
f459b602 3703 case SD_BUS_TYPE_INT32: {
61cbdc4b
LP
3704 int32_t j;
3705
f459b602
MAP
3706 r = sd_bus_message_read(m, "i", &j);
3707 if (r < 0)
3708 return bus_log_parse_error(r);
61cbdc4b
LP
3709
3710 if (streq(name, "ExecMainCode"))
3711 i->exit_code = (int) j;
3712 else if (streq(name, "ExecMainStatus"))
3713 i->exit_status = (int) j;
b4af5a80
LP
3714 else if (streq(name, "StatusErrno"))
3715 i->status_errno = (int) j;
61cbdc4b
LP
3716
3717 break;
3718 }
3719
f459b602 3720 case SD_BUS_TYPE_UINT64: {
61cbdc4b
LP
3721 uint64_t u;
3722
f459b602
MAP
3723 r = sd_bus_message_read(m, "t", &u);
3724 if (r < 0)
3725 return bus_log_parse_error(r);
61cbdc4b
LP
3726
3727 if (streq(name, "ExecMainStartTimestamp"))
3728 i->start_timestamp = (usec_t) u;
3729 else if (streq(name, "ExecMainExitTimestamp"))
3730 i->exit_timestamp = (usec_t) u;
584be568
LP
3731 else if (streq(name, "ActiveEnterTimestamp"))
3732 i->active_enter_timestamp = (usec_t) u;
3733 else if (streq(name, "InactiveEnterTimestamp"))
3734 i->inactive_enter_timestamp = (usec_t) u;
3735 else if (streq(name, "InactiveExitTimestamp"))
3736 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
3737 else if (streq(name, "InactiveExitTimestampMonotonic"))
3738 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
3739 else if (streq(name, "ActiveExitTimestamp"))
3740 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
3741 else if (streq(name, "ConditionTimestamp"))
3742 i->condition_timestamp = (usec_t) u;
59fccdc5
LP
3743 else if (streq(name, "AssertTimestamp"))
3744 i->assert_timestamp = (usec_t) u;
934277fe
LP
3745 else if (streq(name, "MemoryCurrent"))
3746 i->memory_current = u;
3747 else if (streq(name, "MemoryLimit"))
3748 i->memory_limit = u;
5ad096b3
LP
3749 else if (streq(name, "CPUUsageNSec"))
3750 i->cpu_usage_nsec = u;
61cbdc4b
LP
3751
3752 break;
3753 }
582a507f 3754
f459b602 3755 case SD_BUS_TYPE_ARRAY:
582a507f 3756
f459b602
MAP
3757 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
3758 _cleanup_free_ ExecStatusInfo *info = NULL;
582a507f 3759
f459b602
MAP
3760 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
3761 if (r < 0)
3762 return bus_log_parse_error(r);
582a507f 3763
f459b602
MAP
3764 info = new0(ExecStatusInfo, 1);
3765 if (!info)
3766 return log_oom();
582a507f 3767
f459b602 3768 while ((r = exec_status_info_deserialize(m, info)) > 0) {
0129173a 3769
f459b602
MAP
3770 info->name = strdup(name);
3771 if (!info->name)
3772 log_oom();
582a507f 3773
71fda00f 3774 LIST_PREPEND(exec, i->exec, info);
582a507f 3775
f459b602
MAP
3776 info = new0(ExecStatusInfo, 1);
3777 if (!info)
3778 log_oom();
49dbfa7b 3779 }
67419600 3780
f459b602
MAP
3781 if (r < 0)
3782 return bus_log_parse_error(r);
67419600 3783
f459b602
MAP
3784 r = sd_bus_message_exit_container(m);
3785 if (r < 0)
3786 return bus_log_parse_error(r);
67419600 3787
f459b602 3788 return 0;
67419600 3789
f459b602
MAP
3790 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
3791 const char *type, *path;
13160134 3792
f459b602
MAP
3793 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
3794 if (r < 0)
3795 return bus_log_parse_error(r);
67419600 3796
f459b602 3797 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
67419600 3798
f459b602
MAP
3799 r = strv_extend(&i->listen, type);
3800 if (r < 0)
3801 return r;
67419600 3802
f459b602
MAP
3803 r = strv_extend(&i->listen, path);
3804 if (r < 0)
3805 return r;
3806 }
76d14b87 3807 if (r < 0)
f459b602 3808 return bus_log_parse_error(r);
76d14b87 3809
f459b602
MAP
3810 r = sd_bus_message_exit_container(m);
3811 if (r < 0)
3812 return bus_log_parse_error(r);
49dbfa7b 3813
f459b602 3814 return 0;
49dbfa7b 3815
f459b602 3816 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "DropInPaths")) {
49dbfa7b 3817
f459b602
MAP
3818 r = sd_bus_message_read_strv(m, &i->dropin_paths);
3819 if (r < 0)
3820 return bus_log_parse_error(r);
49dbfa7b 3821
f459b602 3822 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Documentation")) {
49dbfa7b 3823
f459b602
MAP
3824 r = sd_bus_message_read_strv(m, &i->documentation);
3825 if (r < 0)
3826 return bus_log_parse_error(r);
52990c2e 3827
f459b602
MAP
3828 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Conditions")) {
3829 const char *cond, *param;
3830 int trigger, negate;
3831 int32_t state;
52990c2e 3832
f459b602
MAP
3833 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
3834 if (r < 0)
3835 return bus_log_parse_error(r);
3836
3837 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
3838 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3839 if (state < 0 && (!trigger || !i->failed_condition)) {
3840 i->failed_condition = cond;
3841 i->failed_condition_trigger = trigger;
3842 i->failed_condition_negate = negate;
59fccdc5
LP
3843 i->failed_condition_parameter = param;
3844 }
3845 }
3846 if (r < 0)
3847 return bus_log_parse_error(r);
3848
3849 r = sd_bus_message_exit_container(m);
3850 if (r < 0)
3851 return bus_log_parse_error(r);
3852
3853 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Asserts")) {
3854 const char *cond, *param;
3855 int trigger, negate;
3856 int32_t state;
3857
3858 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
3859 if (r < 0)
3860 return bus_log_parse_error(r);
3861
3862 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
3863 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3864 if (state < 0 && (!trigger || !i->failed_assert)) {
3865 i->failed_assert = cond;
3866 i->failed_assert_trigger = trigger;
3867 i->failed_assert_negate = negate;
3868 i->failed_assert_parameter = param;
f459b602 3869 }
582a507f 3870 }
f459b602
MAP
3871 if (r < 0)
3872 return bus_log_parse_error(r);
3873
3874 r = sd_bus_message_exit_container(m);
3875 if (r < 0)
3876 return bus_log_parse_error(r);
3877
3878 } else
3879 goto skip;
582a507f
LP
3880
3881 break;
9f39404c 3882
f459b602 3883 case SD_BUS_TYPE_STRUCT_BEGIN:
9f39404c
LP
3884
3885 if (streq(name, "LoadError")) {
9f39404c 3886 const char *n, *message;
9f39404c 3887
f459b602 3888 r = sd_bus_message_read(m, "(ss)", &n, &message);
9f39404c 3889 if (r < 0)
f459b602 3890 return bus_log_parse_error(r);
9f39404c
LP
3891
3892 if (!isempty(message))
3893 i->load_error = message;
f459b602
MAP
3894 } else
3895 goto skip;
9f39404c
LP
3896
3897 break;
f459b602
MAP
3898
3899 default:
3900 goto skip;
9f39404c 3901 }
f459b602
MAP
3902
3903 return 0;
3904
3905skip:
3906 r = sd_bus_message_skip(m, contents);
3907 if (r < 0)
3908 return bus_log_parse_error(r);
61cbdc4b
LP
3909
3910 return 0;
3911}
3912
f459b602
MAP
3913static int print_property(const char *name, sd_bus_message *m, const char *contents) {
3914 int r;
3915
48220598 3916 assert(name);
f459b602 3917 assert(m);
48220598 3918
61cbdc4b
LP
3919 /* This is a low-level property printer, see
3920 * print_status_info() for the nicer output */
3921
852c1b4d
ZJS
3922 if (arg_properties && !strv_find(arg_properties, name)) {
3923 /* skip what we didn't read */
3924 r = sd_bus_message_skip(m, contents);
3925 return r;
3926 }
48220598 3927
f459b602 3928 switch (contents[0]) {
48220598 3929
f459b602 3930 case SD_BUS_TYPE_STRUCT_BEGIN:
48220598 3931
f459b602 3932 if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
3933 uint32_t u;
3934
f459b602
MAP
3935 r = sd_bus_message_read(m, "(uo)", &u, NULL);
3936 if (r < 0)
3937 return bus_log_parse_error(r);
48220598 3938
f459b602 3939 if (u > 0)
8c06592f 3940 printf("%s=%"PRIu32"\n", name, u);
48220598
LP
3941 else if (arg_all)
3942 printf("%s=\n", name);
3943
3944 return 0;
f459b602
MAP
3945
3946 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
3947 const char *s;
3948
f459b602
MAP
3949 r = sd_bus_message_read(m, "(so)", &s, NULL);
3950 if (r < 0)
3951 return bus_log_parse_error(r);
48220598 3952
f459b602 3953 if (arg_all || !isempty(s))
48220598
LP
3954 printf("%s=%s\n", name, s);
3955
3956 return 0;
f459b602
MAP
3957
3958 } else if (contents[1] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
9f39404c
LP
3959 const char *a = NULL, *b = NULL;
3960
f459b602
MAP
3961 r = sd_bus_message_read(m, "(ss)", &a, &b);
3962 if (r < 0)
3963 return bus_log_parse_error(r);
9f39404c
LP
3964
3965 if (arg_all || !isempty(a) || !isempty(b))
3966 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
f786e80d 3967
57183d11
LP
3968 return 0;
3969 } else if (streq_ptr(name, "SystemCallFilter")) {
3970 _cleanup_strv_free_ char **l = NULL;
3971 int whitelist;
3972
3973 r = sd_bus_message_enter_container(m, 'r', "bas");
3974 if (r < 0)
3975 return bus_log_parse_error(r);
3976
3977 r = sd_bus_message_read(m, "b", &whitelist);
3978 if (r < 0)
3979 return bus_log_parse_error(r);
3980
3981 r = sd_bus_message_read_strv(m, &l);
3982 if (r < 0)
3983 return bus_log_parse_error(r);
3984
3985 r = sd_bus_message_exit_container(m);
3986 if (r < 0)
3987 return bus_log_parse_error(r);
3988
3989 if (arg_all || whitelist || !strv_isempty(l)) {
3990 bool first = true;
3991 char **i;
3992
3993 fputs(name, stdout);
3994 fputc('=', stdout);
3995
3996 if (!whitelist)
3997 fputc('~', stdout);
3998
3999 STRV_FOREACH(i, l) {
4000 if (first)
4001 first = false;
4002 else
4003 fputc(' ', stdout);
4004
4005 fputs(*i, stdout);
4006 }
4007 fputc('\n', stdout);
4008 }
4009
f786e80d 4010 return 0;
48220598
LP
4011 }
4012
4013 break;
48220598 4014
f459b602 4015 case SD_BUS_TYPE_ARRAY:
48220598 4016
f459b602
MAP
4017 if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
4018 const char *path;
4019 int ignore;
8c7be95e 4020
f459b602
MAP
4021 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
4022 if (r < 0)
4023 return bus_log_parse_error(r);
8c7be95e 4024
f459b602
MAP
4025 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
4026 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
8c7be95e 4027
f459b602
MAP
4028 if (r < 0)
4029 return bus_log_parse_error(r);
8c7be95e 4030
f459b602
MAP
4031 r = sd_bus_message_exit_container(m);
4032 if (r < 0)
4033 return bus_log_parse_error(r);
8c7be95e
LP
4034
4035 return 0;
4036
f459b602
MAP
4037 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
4038 const char *type, *path;
67419600 4039
f459b602
MAP
4040 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4041 if (r < 0)
4042 return bus_log_parse_error(r);
ebf57b80 4043
f459b602
MAP
4044 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4045 printf("%s=%s\n", type, path);
4046 if (r < 0)
4047 return bus_log_parse_error(r);
ebf57b80 4048
f459b602
MAP
4049 r = sd_bus_message_exit_container(m);
4050 if (r < 0)
4051 return bus_log_parse_error(r);
ebf57b80 4052
707e5e52 4053 return 0;
582a507f 4054
f459b602
MAP
4055 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
4056 const char *type, *path;
67419600 4057
f459b602
MAP
4058 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4059 if (r < 0)
4060 return bus_log_parse_error(r);
67419600 4061
f459b602
MAP
4062 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
4063 printf("Listen%s=%s\n", type, path);
4064 if (r < 0)
4065 return bus_log_parse_error(r);
67419600 4066
f459b602
MAP
4067 r = sd_bus_message_exit_container(m);
4068 if (r < 0)
4069 return bus_log_parse_error(r);
67419600
OS
4070
4071 return 0;
4072
f459b602
MAP
4073 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Timers")) {
4074 const char *base;
4075 uint64_t value, next_elapse;
707e5e52 4076
f459b602
MAP
4077 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
4078 if (r < 0)
4079 return bus_log_parse_error(r);
552e4331 4080
f459b602
MAP
4081 while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
4082 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
fe68089d 4083
f459b602
MAP
4084 printf("%s={ value=%s ; next_elapse=%s }\n",
4085 base,
4086 format_timespan(timespan1, sizeof(timespan1), value, 0),
4087 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
fe68089d 4088 }
f459b602
MAP
4089 if (r < 0)
4090 return bus_log_parse_error(r);
4091
4092 r = sd_bus_message_exit_container(m);
4093 if (r < 0)
4094 return bus_log_parse_error(r);
fe68089d
LP
4095
4096 return 0;
fe68089d 4097
f459b602
MAP
4098 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
4099 ExecStatusInfo info = {};
4100
4101 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sasbttttuii)");
4102 if (r < 0)
4103 return bus_log_parse_error(r);
4104
4105 while ((r = exec_status_info_deserialize(m, &info)) > 0) {
4106 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
4107 _cleanup_free_ char *tt;
4108
4109 tt = strv_join(info.argv, " ");
4110
8c06592f 4111 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
4112 name,
4113 strna(info.path),
4114 strna(tt),
4115 yes_no(info.ignore),
4116 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
4117 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
8c06592f 4118 info.pid,
f459b602
MAP
4119 sigchld_code_to_string(info.code),
4120 info.status,
4121 info.code == CLD_EXITED ? "" : "/",
4122 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 4123
582a507f
LP
4124 free(info.path);
4125 strv_free(info.argv);
f459b602 4126 zero(info);
707e5e52
LP
4127 }
4128
f459b602
MAP
4129 r = sd_bus_message_exit_container(m);
4130 if (r < 0)
4131 return bus_log_parse_error(r);
4132
48220598 4133 return 0;
4ad49000 4134
f459b602
MAP
4135 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
4136 const char *path, *rwm;
4ad49000 4137
f459b602
MAP
4138 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
4139 if (r < 0)
4140 return bus_log_parse_error(r);
4ad49000 4141
f459b602
MAP
4142 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
4143 printf("%s=%s %s\n", name, strna(path), strna(rwm));
4144 if (r < 0)
4145 return bus_log_parse_error(r);
4ad49000 4146
f459b602
MAP
4147 r = sd_bus_message_exit_container(m);
4148 if (r < 0)
4149 return bus_log_parse_error(r);
4ad49000 4150
4ad49000
LP
4151 return 0;
4152
f459b602
MAP
4153 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) {
4154 const char *path;
4155 uint64_t weight;
b8ab2dc6 4156
f459b602
MAP
4157 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4158 if (r < 0)
4159 return bus_log_parse_error(r);
b8ab2dc6 4160
f459b602
MAP
4161 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
4162 printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
4163 if (r < 0)
4164 return bus_log_parse_error(r);
b8ab2dc6 4165
f459b602
MAP
4166 r = sd_bus_message_exit_container(m);
4167 if (r < 0)
4168 return bus_log_parse_error(r);
b8ab2dc6 4169
b8ab2dc6
G
4170 return 0;
4171
f459b602
MAP
4172 } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
4173 const char *path;
4174 uint64_t bandwidth;
4ad49000 4175
f459b602
MAP
4176 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
4177 if (r < 0)
4178 return bus_log_parse_error(r);
4ad49000 4179
f459b602
MAP
4180 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
4181 printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
4182 if (r < 0)
4183 return bus_log_parse_error(r);
4ad49000 4184
f459b602
MAP
4185 r = sd_bus_message_exit_container(m);
4186 if (r < 0)
4187 return bus_log_parse_error(r);
4ad49000 4188
4ad49000 4189 return 0;
48220598
LP
4190 }
4191
4192 break;
4193 }
4194
f459b602
MAP
4195 r = bus_print_property(name, m, arg_all);
4196 if (r < 0)
4197 return bus_log_parse_error(r);
4198
4199 if (r == 0) {
4200 r = sd_bus_message_skip(m, contents);
4201 if (r < 0)
4202 return bus_log_parse_error(r);
a4c279f8 4203
f459b602
MAP
4204 if (arg_all)
4205 printf("%s=[unprintable]\n", name);
4206 }
48220598
LP
4207
4208 return 0;
4209}
4210
f459b602
MAP
4211static int show_one(
4212 const char *verb,
4213 sd_bus *bus,
4214 const char *path,
4215 bool show_properties,
4216 bool *new_line,
4217 bool *ellipsized) {
4218
4219 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4220 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
934277fe
LP
4221 UnitStatusInfo info = {
4222 .memory_current = (uint64_t) -1,
4223 .memory_limit = (uint64_t) -1,
5ad096b3 4224 .cpu_usage_nsec = (uint64_t) -1,
934277fe 4225 };
582a507f 4226 ExecStatusInfo *p;
f459b602 4227 int r;
48220598 4228
48220598 4229 assert(path);
61cbdc4b 4230 assert(new_line);
48220598 4231
e3e0314b
ZJS
4232 log_debug("Showing one %s", path);
4233
f459b602 4234 r = sd_bus_call_method(
f22f08cd
SP
4235 bus,
4236 "org.freedesktop.systemd1",
4237 path,
4238 "org.freedesktop.DBus.Properties",
4239 "GetAll",
f459b602 4240 &error,
f22f08cd 4241 &reply,
f459b602
MAP
4242 "s", "");
4243 if (r < 0) {
4244 log_error("Failed to get properties: %s", bus_error_message(&error, r));
f84190d8 4245 return r;
48220598
LP
4246 }
4247
f459b602
MAP
4248 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
4249 if (r < 0)
4250 return bus_log_parse_error(r);
48220598 4251
61cbdc4b
LP
4252 if (*new_line)
4253 printf("\n");
4254
4255 *new_line = true;
4256
f459b602
MAP
4257 while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
4258 const char *name, *contents;
0183528f 4259
f459b602
MAP
4260 r = sd_bus_message_read(reply, "s", &name);
4261 if (r < 0)
4262 return bus_log_parse_error(r);
48220598 4263
f459b602
MAP
4264 r = sd_bus_message_peek_type(reply, NULL, &contents);
4265 if (r < 0)
4266 return bus_log_parse_error(r);
4267
4268 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
4269 if (r < 0)
4270 return bus_log_parse_error(r);
48220598 4271
61cbdc4b 4272 if (show_properties)
f459b602 4273 r = print_property(name, reply, contents);
61cbdc4b 4274 else
f459b602
MAP
4275 r = status_property(name, reply, &info, contents);
4276 if (r < 0)
4277 return r;
48220598 4278
f459b602
MAP
4279 r = sd_bus_message_exit_container(reply);
4280 if (r < 0)
4281 return bus_log_parse_error(r);
4282
4283 r = sd_bus_message_exit_container(reply);
4284 if (r < 0)
4285 return bus_log_parse_error(r);
48220598 4286 }
f459b602
MAP
4287 if (r < 0)
4288 return bus_log_parse_error(r);
4289
4290 r = sd_bus_message_exit_container(reply);
4291 if (r < 0)
4292 return bus_log_parse_error(r);
48220598 4293
f1e36d67
LP
4294 r = 0;
4295
256425cc 4296 if (!show_properties) {
b43f208f
KS
4297 if (streq(verb, "help"))
4298 show_unit_help(&info);
256425cc 4299 else
94e0bd7d 4300 print_status_info(&info, ellipsized);
256425cc 4301 }
f1e36d67 4302
49dbfa7b 4303 strv_free(info.documentation);
76d14b87 4304 strv_free(info.dropin_paths);
67419600 4305 strv_free(info.listen);
49dbfa7b 4306
22f4096c 4307 if (!streq_ptr(info.active_state, "active") &&
be8088a2 4308 !streq_ptr(info.active_state, "reloading") &&
3b05b8b3 4309 streq(verb, "status")) {
22f4096c 4310 /* According to LSB: "program not running" */
175728c4 4311 /* 0: program is running or service is OK
41a55c46
ZJS
4312 * 1: program is dead and /run PID file exists
4313 * 2: program is dead and /run/lock lock file exists
175728c4
HH
4314 * 3: program is not running
4315 * 4: program or service status is unknown
4316 */
3b05b8b3 4317 if (info.pid_file && access(info.pid_file, F_OK) == 0)
175728c4
HH
4318 r = 1;
4319 else
4320 r = 3;
e9c1ea9d 4321 }
61cbdc4b 4322
582a507f 4323 while ((p = info.exec)) {
71fda00f 4324 LIST_REMOVE(exec, info.exec, p);
582a507f
LP
4325 exec_status_info_free(p);
4326 }
4327
48220598
LP
4328 return r;
4329}
4330
f74294c1 4331static int get_unit_dbus_path_by_pid(
f459b602
MAP
4332 sd_bus *bus,
4333 uint32_t pid,
f74294c1 4334 char **unit) {
f459b602
MAP
4335
4336 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4337 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
373d32c9 4338 char *u;
a223b325
MS
4339 int r;
4340
f459b602 4341 r = sd_bus_call_method(
f22f08cd
SP
4342 bus,
4343 "org.freedesktop.systemd1",
4344 "/org/freedesktop/systemd1",
4345 "org.freedesktop.systemd1.Manager",
4346 "GetUnitByPID",
f459b602 4347 &error,
f22f08cd 4348 &reply,
f459b602
MAP
4349 "u", pid);
4350 if (r < 0) {
1fa2f38f 4351 log_error("Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
cec7eda5 4352 return r;
a223b325
MS
4353 }
4354
373d32c9 4355 r = sd_bus_message_read(reply, "o", &u);
f459b602
MAP
4356 if (r < 0)
4357 return bus_log_parse_error(r);
4358
373d32c9
LP
4359 u = strdup(u);
4360 if (!u)
4361 return log_oom();
4362
4363 *unit = u;
f74294c1 4364 return 0;
a223b325
MS
4365}
4366
f459b602
MAP
4367static int show_all(
4368 const char* verb,
4369 sd_bus *bus,
4370 bool show_properties,
4371 bool *new_line,
4372 bool *ellipsized) {
4373
f459b602
MAP
4374 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4375 _cleanup_free_ UnitInfo *unit_infos = NULL;
4376 const UnitInfo *u;
4377 unsigned c;
5bb75bc7 4378 int r, ret = 0;
265a7a2a 4379
1238ee09 4380 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
265a7a2a
ZJS
4381 if (r < 0)
4382 return r;
4383
dbed408b
LP
4384 pager_open_if_enabled();
4385
f459b602
MAP
4386 c = (unsigned) r;
4387
4388 qsort_safe(unit_infos, c, sizeof(UnitInfo), compare_unit_info);
991f2a39 4389
265a7a2a 4390 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 4391 _cleanup_free_ char *p = NULL;
265a7a2a 4392
265a7a2a
ZJS
4393 p = unit_dbus_path_from_name(u->id);
4394 if (!p)
4395 return log_oom();
4396
94e0bd7d 4397 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
3df538da 4398 if (r < 0)
265a7a2a 4399 return r;
5bb75bc7
ZJS
4400 else if (r > 0 && ret == 0)
4401 ret = r;
265a7a2a
ZJS
4402 }
4403
5bb75bc7 4404 return ret;
265a7a2a
ZJS
4405}
4406
8fcf784d
LP
4407static int show_system_status(sd_bus *bus) {
4408 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], since2[FORMAT_TIMESTAMP_MAX];
4409 _cleanup_free_ char *hn = NULL;
e7e55dbd 4410 _cleanup_(machine_info_clear) struct machine_info mi = {};
8fcf784d
LP
4411 const char *on, *off;
4412 int r;
4413
4414 hn = gethostname_malloc();
4415 if (!hn)
4416 return log_oom();
4417
4418 r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", machine_info_property_map, &mi);
f647962d
MS
4419 if (r < 0)
4420 return log_error_errno(r, "Failed to read server status: %m");
8fcf784d 4421
8fcf784d
LP
4422 if (streq_ptr(mi.state, "degraded")) {
4423 on = ansi_highlight_red();
4424 off = ansi_highlight_off();
4425 } else if (!streq_ptr(mi.state, "running")) {
4426 on = ansi_highlight_yellow();
4427 off = ansi_highlight_off();
4428 } else
4429 on = off = "";
4430
6b01f1d3 4431 printf("%s%s%s %s\n", on, draw_special_char(DRAW_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
b0d14c69 4432
8fcf784d
LP
4433 printf(" State: %s%s%s\n",
4434 on, strna(mi.state), off);
4435
4436 printf(" Jobs: %u queued\n", mi.n_jobs);
4437 printf(" Failed: %u units\n", mi.n_failed_units);
4438
4439 printf(" Since: %s; %s\n",
4440 format_timestamp(since2, sizeof(since2), mi.timestamp),
4441 format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
4442
4443 printf(" CGroup: %s\n", mi.control_group ?: "/");
de33fc62 4444 if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
8fcf784d
LP
4445 static const char prefix[] = " ";
4446 unsigned c;
4447
4448 c = columns();
4449 if (c > sizeof(prefix) - 1)
4450 c -= sizeof(prefix) - 1;
4451 else
4452 c = 0;
4453
3c756001 4454 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
8fcf784d
LP
4455 }
4456
8fcf784d
LP
4457 return 0;
4458}
4459
f459b602 4460static int show(sd_bus *bus, char **args) {
265a7a2a 4461 bool show_properties, show_status, new_line = false;
94e0bd7d 4462 bool ellipsized = false;
e3e0314b 4463 int r, ret = 0;
48220598
LP
4464
4465 assert(bus);
4466 assert(args);
4467
256425cc 4468 show_properties = streq(args[0], "show");
265a7a2a 4469 show_status = streq(args[0], "status");
61cbdc4b 4470
ec14911e 4471 if (show_properties)
1968a360 4472 pager_open_if_enabled();
ec14911e 4473
40acc203
ZJS
4474 if (show_status)
4475 /* Increase max number of open files to 16K if we can, we
4476 * might needs this when browsing journal files, which might
4477 * be split up into many files. */
4478 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
4479
f84190d8 4480 /* If no argument is specified inspect the manager itself */
48220598 4481
f84190d8 4482 if (show_properties && strv_length(args) <= 1)
94e0bd7d 4483 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
48220598 4484
8fcf784d
LP
4485 if (show_status && strv_length(args) <= 1) {
4486
c3441de0 4487 pager_open_if_enabled();
8fcf784d
LP
4488 show_system_status(bus);
4489 new_line = true;
4490
4491 if (arg_all)
4492 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
4493 } else {
e3e0314b
ZJS
4494 _cleanup_free_ char **patterns = NULL;
4495 char **name;
4496
4497 STRV_FOREACH(name, args + 1) {
f74294c1 4498 _cleanup_free_ char *unit = NULL;
94e0bd7d 4499 uint32_t id;
48220598 4500
94e0bd7d 4501 if (safe_atou32(*name, &id) < 0) {
e3e0314b 4502 if (strv_push(&patterns, *name) < 0)
94e0bd7d 4503 return log_oom();
48220598 4504
e3e0314b 4505 continue;
94e0bd7d 4506 } else if (show_properties) {
94e0bd7d 4507 /* Interpret as job id */
f74294c1 4508 if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
94e0bd7d 4509 return log_oom();
48220598 4510
94e0bd7d
ZJS
4511 } else {
4512 /* Interpret as PID */
f74294c1 4513 r = get_unit_dbus_path_by_pid(bus, id, &unit);
373d32c9 4514 if (r < 0) {
94e0bd7d 4515 ret = r;
373d32c9
LP
4516 continue;
4517 }
94e0bd7d 4518 }
f74294c1 4519
5bb75bc7
ZJS
4520 r = show_one(args[0], bus, unit, show_properties,
4521 &new_line, &ellipsized);
4522 if (r < 0)
4523 return r;
4524 else if (r > 0 && ret == 0)
4525 ret = r;
48220598 4526 }
94e0bd7d 4527
e3e0314b
ZJS
4528 if (!strv_isempty(patterns)) {
4529 _cleanup_strv_free_ char **names = NULL;
4530
4531 r = expand_names(bus, patterns, NULL, &names);
4532 if (r < 0)
da927ba9 4533 log_error_errno(r, "Failed to expand names: %m");
e3e0314b
ZJS
4534
4535 STRV_FOREACH(name, names) {
4536 _cleanup_free_ char *unit;
4537
4538 unit = unit_dbus_path_from_name(*name);
4539 if (!unit)
4540 return log_oom();
4541
5bb75bc7
ZJS
4542 r = show_one(args[0], bus, unit, show_properties,
4543 &new_line, &ellipsized);
4544 if (r < 0)
4545 return r;
4546 else if (r > 0 && ret == 0)
4547 ret = r;
e3e0314b
ZJS
4548 }
4549 }
4550 }
4551
94e0bd7d
ZJS
4552 if (ellipsized && !arg_quiet)
4553 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 4554
22f4096c 4555 return ret;
0183528f
LP
4556}
4557
8df18507
ZJS
4558static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) {
4559 int r;
4560
4561 assert(user_home);
4562 assert(user_runtime);
4563 assert(lp);
4564
4565 if (arg_scope == UNIT_FILE_USER) {
4566 r = user_config_home(user_home);
4567 if (r < 0)
4568 return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
4569 else if (r == 0)
4570 return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set.");
4571
4572 r = user_runtime_dir(user_runtime);
4573 if (r < 0)
4574 return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
4575 else if (r == 0)
4576 return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set.");
4577 }
4578
60d27f19 4579 r = lookup_paths_init_from_scope(lp, arg_scope, arg_root);
8df18507 4580 if (r < 0)
029009d4 4581 return log_error_errno(r, "Failed to query unit lookup paths: %m");
8df18507
ZJS
4582
4583 return 0;
4584}
4585
8527b07b
ZJS
4586static int cat_file(const char *filename, bool newline) {
4587 _cleanup_close_ int fd;
4588
4589 fd = open(filename, O_RDONLY|O_CLOEXEC|O_NOCTTY);
4590 if (fd < 0)
4591 return -errno;
4592
4593 printf("%s%s# %s%s\n",
4594 newline ? "\n" : "",
4595 ansi_highlight_blue(),
4596 filename,
4597 ansi_highlight_off());
4598 fflush(stdout);
4599
4600 return copy_bytes(fd, STDOUT_FILENO, (off_t) -1, false);
4601}
4602
15ef1144 4603static int cat(sd_bus *bus, char **args) {
ad2a0358
ZJS
4604 _cleanup_free_ char *user_home = NULL;
4605 _cleanup_free_ char *user_runtime = NULL;
4606 _cleanup_lookup_paths_free_ LookupPaths lp = {};
15ef1144
LP
4607 _cleanup_strv_free_ char **names = NULL;
4608 char **name;
ad2a0358 4609 bool first = true, avoid_bus_cache;
25586912 4610 int r;
15ef1144 4611
15ef1144
LP
4612 assert(args);
4613
3e7eed84
IS
4614 if (arg_transport != BUS_TRANSPORT_LOCAL) {
4615 log_error("Cannot remotely cat units");
3e495a66
ZJS
4616 return -EINVAL;
4617 }
4618
ad2a0358
ZJS
4619 r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
4620 if (r < 0)
4621 return r;
4622
15ef1144
LP
4623 r = expand_names(bus, args + 1, NULL, &names);
4624 if (r < 0)
3e7eed84 4625 return log_error_errno(r, "Failed to expand names: %m");
15ef1144 4626
ad2a0358
ZJS
4627 avoid_bus_cache = !bus || avoid_bus();
4628
15ef1144
LP
4629 pager_open_if_enabled();
4630
4631 STRV_FOREACH(name, names) {
ad2a0358 4632 _cleanup_free_ char *fragment_path = NULL;
15ef1144 4633 _cleanup_strv_free_ char **dropin_paths = NULL;
15ef1144
LP
4634 char **path;
4635
ad2a0358
ZJS
4636 r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &fragment_path, &dropin_paths);
4637 if (r < 0)
4638 return r;
b5e6a600
IS
4639 else if (r == 0)
4640 return -ENOENT;
15ef1144
LP
4641
4642 if (first)
4643 first = false;
4644 else
4645 puts("");
4646
ad2a0358 4647 if (fragment_path) {
8527b07b
ZJS
4648 r = cat_file(fragment_path, false);
4649 if (r < 0)
4650 return log_warning_errno(r, "Failed to cat %s: %m", fragment_path);
15ef1144
LP
4651 }
4652
4653 STRV_FOREACH(path, dropin_paths) {
8527b07b
ZJS
4654 r = cat_file(*path, path == dropin_paths);
4655 if (r < 0)
4656 return log_warning_errno(r, "Failed to cat %s: %m", *path);
15ef1144
LP
4657 }
4658 }
4659
25586912 4660 return 0;
15ef1144
LP
4661}
4662
f459b602
MAP
4663static int set_property(sd_bus *bus, char **args) {
4664 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
4665 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
68372da6 4666 _cleanup_free_ char *n = NULL;
8e2af478
LP
4667 char **i;
4668 int r;
4669
079dac08
LP
4670 polkit_agent_open_if_enabled();
4671
f459b602
MAP
4672 r = sd_bus_message_new_method_call(
4673 bus,
151b9b96 4674 &m,
8e2af478
LP
4675 "org.freedesktop.systemd1",
4676 "/org/freedesktop/systemd1",
4677 "org.freedesktop.systemd1.Manager",
151b9b96 4678 "SetUnitProperties");
f459b602
MAP
4679 if (r < 0)
4680 return bus_log_create_error(r);
8e2af478 4681
7410616c
LP
4682 r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n);
4683 if (r < 0)
4684 return log_error_errno(r, "Failed to mangle unit name: %m");
68372da6 4685
f459b602
MAP
4686 r = sd_bus_message_append(m, "sb", n, arg_runtime);
4687 if (r < 0)
4688 return bus_log_create_error(r);
8e2af478 4689
f459b602
MAP
4690 r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, "(sv)");
4691 if (r < 0)
4692 return bus_log_create_error(r);
8e2af478 4693
f459b602
MAP
4694 STRV_FOREACH(i, args + 2) {
4695 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4696 if (r < 0)
4697 return bus_log_create_error(r);
8e2af478 4698
df31a6c0 4699 r = bus_append_unit_property_assignment(m, *i);
8e2af478
LP
4700 if (r < 0)
4701 return r;
4702
f459b602
MAP
4703 r = sd_bus_message_close_container(m);
4704 if (r < 0)
4705 return bus_log_create_error(r);
8e2af478
LP
4706 }
4707
f459b602
MAP
4708 r = sd_bus_message_close_container(m);
4709 if (r < 0)
4710 return bus_log_create_error(r);
8e2af478 4711
c49b30a2 4712 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
4713 if (r < 0) {
4714 log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
4715 return r;
8e2af478
LP
4716 }
4717
4718 return 0;
4719}
4720
f459b602
MAP
4721static int snapshot(sd_bus *bus, char **args) {
4722 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 4723 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
f459b602
MAP
4724 _cleanup_free_ char *n = NULL, *id = NULL;
4725 const char *path;
7e4249b9 4726 int r;
7e4249b9 4727
079dac08
LP
4728 polkit_agent_open_if_enabled();
4729
7410616c
LP
4730 if (strv_length(args) > 1) {
4731 r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
4732 if (r < 0)
4733 return log_error_errno(r, "Failed to generate unit name: %m");
4734 } else {
1dcf6065 4735 n = strdup("");
7410616c
LP
4736 if (!n)
4737 return log_oom();
4738 }
7e4249b9 4739
6e646d22 4740 r = sd_bus_call_method(
f22f08cd
SP
4741 bus,
4742 "org.freedesktop.systemd1",
4743 "/org/freedesktop/systemd1",
4744 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4745 "CreateSnapshot",
4746 &error,
4747 &reply,
4748 "sb", n, false);
f459b602
MAP
4749 if (r < 0) {
4750 log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
1dcf6065 4751 return r;
7e4249b9
LP
4752 }
4753
f459b602
MAP
4754 r = sd_bus_message_read(reply, "o", &path);
4755 if (r < 0)
4756 return bus_log_parse_error(r);
5dd9014f 4757
f459b602 4758 r = sd_bus_get_property_string(
f22f08cd
SP
4759 bus,
4760 "org.freedesktop.systemd1",
4761 path,
f459b602
MAP
4762 "org.freedesktop.systemd1.Unit",
4763 "Id",
4764 &error,
4765 &id);
4766 if (r < 0) {
4767 log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
1dcf6065 4768 return r;
7e4249b9
LP
4769 }
4770
0183528f
LP
4771 if (!arg_quiet)
4772 puts(id);
7e4249b9 4773
1dcf6065 4774 return 0;
7e4249b9
LP
4775}
4776
f459b602 4777static int delete_snapshot(sd_bus *bus, char **args) {
e3e0314b 4778 _cleanup_strv_free_ char **names = NULL;
729e3769 4779 char **name;
342641fb 4780 int r;
6759e7a7 4781
6759e7a7
LP
4782 assert(args);
4783
079dac08
LP
4784 polkit_agent_open_if_enabled();
4785
e3e0314b
ZJS
4786 r = expand_names(bus, args + 1, ".snapshot", &names);
4787 if (r < 0)
da927ba9 4788 log_error_errno(r, "Failed to expand names: %m");
1dcf6065 4789
e3e0314b 4790 STRV_FOREACH(name, names) {
6e646d22 4791 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb
LP
4792 int q;
4793
6e646d22 4794 q = sd_bus_call_method(
f22f08cd 4795 bus,
b0193f1c
LP
4796 "org.freedesktop.systemd1",
4797 "/org/freedesktop/systemd1",
4798 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4799 "RemoveSnapshot",
4800 &error,
4801 NULL,
4802 "s", *name);
e3e0314b 4803 if (q < 0) {
342641fb 4804 log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
4805 if (r == 0)
4806 r = q;
f459b602 4807 }
6759e7a7
LP
4808 }
4809
e3e0314b 4810 return r;
6759e7a7
LP
4811}
4812
f459b602
MAP
4813static int daemon_reload(sd_bus *bus, char **args) {
4814 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7e4249b9 4815 const char *method;
f459b602 4816 int r;
7e4249b9 4817
079dac08
LP
4818 polkit_agent_open_if_enabled();
4819
e4b61340
LP
4820 if (arg_action == ACTION_RELOAD)
4821 method = "Reload";
4822 else if (arg_action == ACTION_REEXEC)
4823 method = "Reexecute";
4824 else {
4825 assert(arg_action == ACTION_SYSTEMCTL);
4826
4827 method =
20b09ca7
LP
4828 streq(args[0], "clear-jobs") ||
4829 streq(args[0], "cancel") ? "ClearJobs" :
4830 streq(args[0], "daemon-reexec") ? "Reexecute" :
4831 streq(args[0], "reset-failed") ? "ResetFailed" :
4832 streq(args[0], "halt") ? "Halt" :
4833 streq(args[0], "poweroff") ? "PowerOff" :
4834 streq(args[0], "reboot") ? "Reboot" :
4835 streq(args[0], "kexec") ? "KExec" :
4836 streq(args[0], "exit") ? "Exit" :
4837 /* "daemon-reload" */ "Reload";
e4b61340 4838 }
7e4249b9 4839
6e646d22 4840 r = sd_bus_call_method(
f22f08cd
SP
4841 bus,
4842 "org.freedesktop.systemd1",
4843 "/org/freedesktop/systemd1",
4844 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4845 method,
4846 &error,
4847 NULL,
4848 NULL);
f22f08cd
SP
4849 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4850 /* There's always a fallback possible for
4851 * legacy actions. */
4852 r = -EADDRNOTAVAIL;
d0ede8f1
LP
4853 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4854 /* On reexecution, we expect a disconnect, not a
4855 * reply */
f22f08cd 4856 r = 0;
1dcf6065 4857 else if (r < 0)
f459b602 4858 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
7e4249b9 4859
0a9776c2 4860 return r < 0 ? r : 0;
7e4249b9
LP
4861}
4862
f459b602 4863static int reset_failed(sd_bus *bus, char **args) {
e3e0314b 4864 _cleanup_strv_free_ char **names = NULL;
f84190d8 4865 char **name;
e3e0314b 4866 int r, q;
5632e374 4867
729e3769
LP
4868 if (strv_length(args) <= 1)
4869 return daemon_reload(bus, args);
5632e374 4870
079dac08
LP
4871 polkit_agent_open_if_enabled();
4872
e3e0314b
ZJS
4873 r = expand_names(bus, args + 1, NULL, &names);
4874 if (r < 0)
da927ba9 4875 log_error_errno(r, "Failed to expand names: %m");
f84190d8 4876
e3e0314b 4877 STRV_FOREACH(name, names) {
6e646d22 4878 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
342641fb 4879
6e646d22 4880 q = sd_bus_call_method(
f22f08cd 4881 bus,
b0193f1c
LP
4882 "org.freedesktop.systemd1",
4883 "/org/freedesktop/systemd1",
4884 "org.freedesktop.systemd1.Manager",
6e646d22
LP
4885 "ResetFailedUnit",
4886 &error,
4887 NULL,
4888 "s", *name);
e3e0314b 4889 if (q < 0) {
342641fb 4890 log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
e3e0314b
ZJS
4891 if (r == 0)
4892 r = q;
f459b602 4893 }
5632e374
LP
4894 }
4895
e3e0314b 4896 return r;
5632e374
LP
4897}
4898
f459b602
MAP
4899static int show_environment(sd_bus *bus, char **args) {
4900 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4901 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
4902 const char *text;
7e4249b9 4903 int r;
7e4249b9 4904
1968a360 4905 pager_open_if_enabled();
ec14911e 4906
f459b602 4907 r = sd_bus_get_property(
f22f08cd
SP
4908 bus,
4909 "org.freedesktop.systemd1",
4910 "/org/freedesktop/systemd1",
f459b602
MAP
4911 "org.freedesktop.systemd1.Manager",
4912 "Environment",
4913 &error,
f22f08cd 4914 &reply,
f459b602
MAP
4915 "as");
4916 if (r < 0) {
4917 log_error("Failed to get environment: %s", bus_error_message(&error, r));
f84190d8 4918 return r;
7e4249b9
LP
4919 }
4920
f459b602
MAP
4921 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
4922 if (r < 0)
4923 return bus_log_parse_error(r);
7e4249b9 4924
f459b602 4925 while ((r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &text)) > 0)
f84190d8 4926 puts(text);
f459b602
MAP
4927 if (r < 0)
4928 return bus_log_parse_error(r);
7e4249b9 4929
f459b602
MAP
4930 r = sd_bus_message_exit_container(reply);
4931 if (r < 0)
4932 return bus_log_parse_error(r);
7e4249b9 4933
f84190d8 4934 return 0;
7e4249b9
LP
4935}
4936
f459b602
MAP
4937static int switch_root(sd_bus *bus, char **args) {
4938 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f39d4a08
HH
4939 _cleanup_free_ char *cmdline_init = NULL;
4940 const char *root, *init;
f459b602
MAP
4941 unsigned l;
4942 int r;
957eb8ca
LP
4943
4944 l = strv_length(args);
4945 if (l < 2 || l > 3) {
4946 log_error("Wrong number of arguments.");
4947 return -EINVAL;
4948 }
4949
4950 root = args[1];
13068da8
TG
4951
4952 if (l >= 3)
f39d4a08 4953 init = args[2];
13068da8 4954 else {
f39d4a08
HH
4955 r = parse_env_file("/proc/cmdline", WHITESPACE,
4956 "init", &cmdline_init,
4957 NULL);
4958 if (r < 0)
da927ba9 4959 log_debug_errno(r, "Failed to parse /proc/cmdline: %m");
13068da8 4960
f39d4a08 4961 init = cmdline_init;
13068da8 4962 }
f459b602 4963
f39d4a08
HH
4964 if (isempty(init))
4965 init = NULL;
4966
4967 if (init) {
4968 const char *root_systemd_path = NULL, *root_init_path = NULL;
4969
63c372cb
LP
4970 root_systemd_path = strjoina(root, "/" SYSTEMD_BINARY_PATH);
4971 root_init_path = strjoina(root, "/", init);
f39d4a08
HH
4972
4973 /* If the passed init is actually the same as the
4974 * systemd binary, then let's suppress it. */
4975 if (files_same(root_init_path, root_systemd_path) > 0)
4976 init = NULL;
4977 }
13068da8 4978
f39d4a08 4979 log_debug("Switching root - root: %s; init: %s", root, strna(init));
957eb8ca 4980
f459b602 4981 r = sd_bus_call_method(
f22f08cd 4982 bus,
957eb8ca
LP
4983 "org.freedesktop.systemd1",
4984 "/org/freedesktop/systemd1",
4985 "org.freedesktop.systemd1.Manager",
f22f08cd 4986 "SwitchRoot",
f459b602 4987 &error,
f22f08cd 4988 NULL,
f459b602
MAP
4989 "ss", root, init);
4990 if (r < 0) {
4991 log_error("Failed to switch root: %s", bus_error_message(&error, r));
4992 return r;
4993 }
4994
4995 return 0;
957eb8ca
LP
4996}
4997
f459b602
MAP
4998static int set_environment(sd_bus *bus, char **args) {
4999 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5000 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
7e4249b9 5001 const char *method;
31e767f7
LP
5002 int r;
5003
5004 assert(bus);
60f9ba0b 5005 assert(args);
7e4249b9 5006
6e646d22
LP
5007 polkit_agent_open_if_enabled();
5008
7e4249b9
LP
5009 method = streq(args[0], "set-environment")
5010 ? "SetEnvironment"
5011 : "UnsetEnvironment";
5012
f459b602
MAP
5013 r = sd_bus_message_new_method_call(
5014 bus,
151b9b96 5015 &m,
31e767f7
LP
5016 "org.freedesktop.systemd1",
5017 "/org/freedesktop/systemd1",
5018 "org.freedesktop.systemd1.Manager",
151b9b96 5019 method);
f459b602
MAP
5020 if (r < 0)
5021 return bus_log_create_error(r);
7e4249b9 5022
f459b602 5023 r = sd_bus_message_append_strv(m, args + 1);
31e767f7 5024 if (r < 0)
f459b602 5025 return bus_log_create_error(r);
7e4249b9 5026
c49b30a2 5027 r = sd_bus_call(bus, m, 0, &error, NULL);
f459b602
MAP
5028 if (r < 0) {
5029 log_error("Failed to set environment: %s", bus_error_message(&error, r));
5030 return r;
7e4249b9
LP
5031 }
5032
f84190d8 5033 return 0;
7e4249b9
LP
5034}
5035
ac3efa8a
LP
5036static int import_environment(sd_bus *bus, char **args) {
5037 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5038 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
5039 int r;
5040
5041 assert(bus);
5042 assert(args);
5043
6e646d22
LP
5044 polkit_agent_open_if_enabled();
5045
ac3efa8a
LP
5046 r = sd_bus_message_new_method_call(
5047 bus,
151b9b96 5048 &m,
ac3efa8a
LP
5049 "org.freedesktop.systemd1",
5050 "/org/freedesktop/systemd1",
5051 "org.freedesktop.systemd1.Manager",
151b9b96 5052 "SetEnvironment");
ac3efa8a
LP
5053 if (r < 0)
5054 return bus_log_create_error(r);
5055
5056 if (strv_isempty(args + 1))
5057 r = sd_bus_message_append_strv(m, environ);
5058 else {
5059 char **a, **b;
5060
5061 r = sd_bus_message_open_container(m, 'a', "s");
5062 if (r < 0)
5063 return bus_log_create_error(r);
5064
5065 STRV_FOREACH(a, args + 1) {
5066
5067 if (!env_name_is_valid(*a)) {
5068 log_error("Not a valid environment variable name: %s", *a);
5069 return -EINVAL;
5070 }
5071
5072 STRV_FOREACH(b, environ) {
5073 const char *eq;
5074
5075 eq = startswith(*b, *a);
5076 if (eq && *eq == '=') {
5077
5078 r = sd_bus_message_append(m, "s", *b);
5079 if (r < 0)
5080 return bus_log_create_error(r);
5081
5082 break;
5083 }
5084 }
5085 }
5086
5087 r = sd_bus_message_close_container(m);
5088 }
5089 if (r < 0)
5090 return bus_log_create_error(r);
5091
5092 r = sd_bus_call(bus, m, 0, &error, NULL);
5093 if (r < 0) {
5094 log_error("Failed to import environment: %s", bus_error_message(&error, r));
5095 return r;
5096 }
5097
5098 return 0;
5099}
5100
cbb13b2a 5101static int enable_sysv_units(const char *verb, char **args) {
729e3769 5102 int r = 0;
ee5762e3 5103
0f0467e6 5104#if defined(HAVE_SYSV_COMPAT)
a644abed 5105 unsigned f = 0;
fb15be83 5106 _cleanup_lookup_paths_free_ LookupPaths paths = {};
ee5762e3 5107
729e3769
LP
5108 if (arg_scope != UNIT_FILE_SYSTEM)
5109 return 0;
ee5762e3 5110
729e3769
LP
5111 if (!streq(verb, "enable") &&
5112 !streq(verb, "disable") &&
5113 !streq(verb, "is-enabled"))
5114 return 0;
ee5762e3 5115
729e3769
LP
5116 /* Processes all SysV units, and reshuffles the array so that
5117 * afterwards only the native units remain */
ee5762e3 5118
b2c23da8 5119 r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL);
729e3769
LP
5120 if (r < 0)
5121 return r;
ee5762e3 5122
729e3769 5123 r = 0;
a644abed 5124 while (args[f]) {
729e3769 5125 const char *name;
05cae7f3 5126 _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
729e3769
LP
5127 bool found_native = false, found_sysv;
5128 unsigned c = 1;
0f0467e6 5129 const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL };
05cae7f3 5130 char **k;
729e3769
LP
5131 int j;
5132 pid_t pid;
5133 siginfo_t status;
ee5762e3 5134
a644abed 5135 name = args[f++];
ee5762e3 5136
729e3769
LP
5137 if (!endswith(name, ".service"))
5138 continue;
ee5762e3 5139
729e3769
LP
5140 if (path_is_absolute(name))
5141 continue;
ee5762e3 5142
729e3769 5143 STRV_FOREACH(k, paths.unit_path) {
05cae7f3
ZJS
5144 _cleanup_free_ char *path = NULL;
5145
0c6ea3a4
ZJS
5146 path = path_join(arg_root, *k, name);
5147 if (!path)
60731f32 5148 return log_oom();
ee5762e3 5149
4723e4b2 5150 found_native = access(path, F_OK) >= 0;
729e3769
LP
5151 if (found_native)
5152 break;
5153 }
ee5762e3 5154
355ff449
MP
5155 /* If we have both a native unit and a SysV script,
5156 * enable/disable them both (below); for is-enabled, prefer the
5157 * native unit */
5158 if (found_native && streq(verb, "is-enabled"))
729e3769 5159 continue;
ee5762e3 5160
0c6ea3a4
ZJS
5161 p = path_join(arg_root, SYSTEM_SYSVINIT_PATH, name);
5162 if (!p)
60731f32 5163 return log_oom();
ee5762e3 5164
05cae7f3 5165 p[strlen(p) - strlen(".service")] = 0;
729e3769 5166 found_sysv = access(p, F_OK) >= 0;
4b6756a8 5167 if (!found_sysv)
729e3769 5168 continue;
71fad675 5169
355ff449
MP
5170 if (found_native)
5171 log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
5172 else
5173 log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
ee5762e3 5174
729e3769
LP
5175 if (!isempty(arg_root))
5176 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 5177
0f0467e6 5178 argv[c++] = verb;
2b6bf07d 5179 argv[c++] = basename(p);
729e3769 5180 argv[c] = NULL;
ee5762e3 5181
729e3769 5182 l = strv_join((char**)argv, " ");
60731f32
ZJS
5183 if (!l)
5184 return log_oom();
ee5762e3 5185
729e3769 5186 log_info("Executing %s", l);
ee5762e3 5187
729e3769 5188 pid = fork();
4a62c710
MS
5189 if (pid < 0)
5190 return log_error_errno(errno, "Failed to fork: %m");
5191 else if (pid == 0) {
729e3769 5192 /* Child */
ee5762e3 5193
ce30c8dc
LP
5194 (void) reset_all_signal_handlers();
5195 (void) reset_signal_mask();
5196
729e3769 5197 execv(argv[0], (char**) argv);
0f0467e6 5198 log_error("Failed to execute %s: %m", argv[0]);
729e3769
LP
5199 _exit(EXIT_FAILURE);
5200 }
ee5762e3 5201
729e3769
LP
5202 j = wait_for_terminate(pid, &status);
5203 if (j < 0) {
da927ba9 5204 log_error_errno(r, "Failed to wait for child: %m");
60731f32 5205 return j;
729e3769 5206 }
ee5762e3 5207
729e3769
LP
5208 if (status.si_code == CLD_EXITED) {
5209 if (streq(verb, "is-enabled")) {
5210 if (status.si_status == 0) {
5211 if (!arg_quiet)
5212 puts("enabled");
5213 r = 1;
5214 } else {
5215 if (!arg_quiet)
5216 puts("disabled");
5217 }
ee5762e3 5218
60731f32
ZJS
5219 } else if (status.si_status != 0)
5220 return -EINVAL;
5221 } else
5222 return -EPROTO;
ee5762e3 5223
355ff449
MP
5224 if (found_native)
5225 continue;
5226
a644abed 5227 /* Remove this entry, so that we don't try enabling it as native unit */
aba84331
LP
5228 assert(f > 0);
5229 f--;
5230 assert(args[f] == name);
5231 strv_remove(args, name);
729e3769 5232 }
ee5762e3 5233
729e3769
LP
5234#endif
5235 return r;
5236}
ee5762e3 5237
37370d0c 5238static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 5239 char **i, **l, **name;
7410616c 5240 int r;
37370d0c 5241
7410616c 5242 l = i = new(char*, strv_length(original_names) + 1);
a33fdebb 5243 if (!l)
37370d0c
VP
5244 return log_oom();
5245
37370d0c 5246 STRV_FOREACH(name, original_names) {
44386fc1
LN
5247
5248 /* When enabling units qualified path names are OK,
5249 * too, hence allow them explicitly. */
5250
7410616c 5251 if (is_path(*name)) {
44386fc1 5252 *i = strdup(*name);
7410616c
LP
5253 if (!*i) {
5254 strv_free(l);
5255 return log_oom();
5256 }
5257 } else {
5258 r = unit_name_mangle(*name, UNIT_NAME_NOGLOB, i);
5259 if (r < 0) {
5260 strv_free(l);
5261 return log_error_errno(r, "Failed to mangle unit name: %m");
5262 }
a33fdebb
LP
5263 }
5264
5265 i++;
37370d0c 5266 }
a33fdebb
LP
5267
5268 *i = NULL;
5269 *mangled_names = l;
37370d0c
VP
5270
5271 return 0;
5272}
5273
f459b602 5274static int enable_unit(sd_bus *bus, char **args) {
e3e0314b 5275 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5276 const char *verb = args[0];
5277 UnitFileChange *changes = NULL;
718db961 5278 unsigned n_changes = 0;
729e3769 5279 int carries_install_info = -1;
729e3769 5280 int r;
ee5762e3 5281
ab5919fa
MS
5282 if (!args[1])
5283 return 0;
5284
e3e0314b 5285 r = mangle_names(args+1, &names);
3a05c0f9 5286 if (r < 0)
cbb13b2a
VP
5287 return r;
5288
e3e0314b 5289 r = enable_sysv_units(verb, names);
cbb13b2a
VP
5290 if (r < 0)
5291 return r;
3a05c0f9 5292
67d66210
LP
5293 /* If the operation was fully executed by the SysV compat,
5294 * let's finish early */
5295 if (strv_isempty(names))
5296 return 0;
5297
729e3769
LP
5298 if (!bus || avoid_bus()) {
5299 if (streq(verb, "enable")) {
e3e0314b 5300 r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5301 carries_install_info = r;
5302 } else if (streq(verb, "disable"))
e3e0314b 5303 r = unit_file_disable(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769 5304 else if (streq(verb, "reenable")) {
e3e0314b 5305 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769
LP
5306 carries_install_info = r;
5307 } else if (streq(verb, "link"))
e3e0314b 5308 r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5309 else if (streq(verb, "preset")) {
d309c1c3 5310 r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
729e3769
LP
5311 carries_install_info = r;
5312 } else if (streq(verb, "mask"))
e3e0314b 5313 r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
729e3769 5314 else if (streq(verb, "unmask"))
e3e0314b 5315 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
729e3769
LP
5316 else
5317 assert_not_reached("Unknown verb");
ee5762e3 5318
729e3769 5319 if (r < 0) {
da927ba9 5320 log_error_errno(r, "Operation failed: %m");
729e3769 5321 goto finish;
ee5762e3
LP
5322 }
5323
718db961
LP
5324 if (!arg_quiet)
5325 dump_unit_file_changes(changes, n_changes);
ee5762e3 5326
df77cdf0 5327 r = 0;
729e3769 5328 } else {
718db961
LP
5329 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5330 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
f459b602 5331 int expect_carries_install_info = false;
d309c1c3 5332 bool send_force = true, send_preset_mode = false;
718db961 5333 const char *method;
729e3769 5334
079dac08
LP
5335 polkit_agent_open_if_enabled();
5336
729e3769
LP
5337 if (streq(verb, "enable")) {
5338 method = "EnableUnitFiles";
5339 expect_carries_install_info = true;
5340 } else if (streq(verb, "disable")) {
5341 method = "DisableUnitFiles";
5342 send_force = false;
5343 } else if (streq(verb, "reenable")) {
5344 method = "ReenableUnitFiles";
5345 expect_carries_install_info = true;
5346 } else if (streq(verb, "link"))
5347 method = "LinkUnitFiles";
5348 else if (streq(verb, "preset")) {
d309c1c3
LP
5349
5350 if (arg_preset_mode != UNIT_FILE_PRESET_FULL) {
5351 method = "PresetUnitFilesWithMode";
5352 send_preset_mode = true;
5353 } else
5354 method = "PresetUnitFiles";
5355
729e3769
LP
5356 expect_carries_install_info = true;
5357 } else if (streq(verb, "mask"))
5358 method = "MaskUnitFiles";
5359 else if (streq(verb, "unmask")) {
5360 method = "UnmaskUnitFiles";
5361 send_force = false;
5362 } else
5363 assert_not_reached("Unknown verb");
5364
f459b602
MAP
5365 r = sd_bus_message_new_method_call(
5366 bus,
151b9b96 5367 &m,
729e3769
LP
5368 "org.freedesktop.systemd1",
5369 "/org/freedesktop/systemd1",
5370 "org.freedesktop.systemd1.Manager",
151b9b96 5371 method);
f459b602
MAP
5372 if (r < 0)
5373 return bus_log_create_error(r);
ee5762e3 5374
e3e0314b 5375 r = sd_bus_message_append_strv(m, names);
f459b602
MAP
5376 if (r < 0)
5377 return bus_log_create_error(r);
ee5762e3 5378
d309c1c3
LP
5379 if (send_preset_mode) {
5380 r = sd_bus_message_append(m, "s", unit_file_preset_mode_to_string(arg_preset_mode));
5381 if (r < 0)
5382 return bus_log_create_error(r);
5383 }
5384
f459b602
MAP
5385 r = sd_bus_message_append(m, "b", arg_runtime);
5386 if (r < 0)
5387 return bus_log_create_error(r);
ee5762e3 5388
729e3769 5389 if (send_force) {
f459b602
MAP
5390 r = sd_bus_message_append(m, "b", arg_force);
5391 if (r < 0)
5392 return bus_log_create_error(r);
ee5762e3
LP
5393 }
5394
c49b30a2 5395 r = sd_bus_call(bus, m, 0, &error, &reply);
f459b602
MAP
5396 if (r < 0) {
5397 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5398 return r;
729e3769 5399 }
be394c48 5400
729e3769 5401 if (expect_carries_install_info) {
f459b602
MAP
5402 r = sd_bus_message_read(reply, "b", &carries_install_info);
5403 if (r < 0)
5404 return bus_log_parse_error(r);
ee5762e3
LP
5405 }
5406
57ab2eab 5407 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
f459b602 5408 if (r < 0)
718db961 5409 return r;
b77398f7 5410
93c941e3 5411 /* Try to reload if enabled */
d6cb60c7 5412 if (!arg_no_reload)
729e3769 5413 r = daemon_reload(bus, args);
f459b602
MAP
5414 else
5415 r = 0;
b647f10d 5416 }
3d3961f2 5417
729e3769 5418 if (carries_install_info == 0)
416389f7
LP
5419 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
5420 "using systemctl.\n"
5421 "Possible reasons for having this kind of units are:\n"
5422 "1) A unit may be statically enabled by being symlinked from another unit's\n"
5423 " .wants/ or .requires/ directory.\n"
5424 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
5425 " a requirement dependency on it.\n"
5426 "3) A unit may be started when needed via activation (socket, path, timer,\n"
5427 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 5428
57ab2eab
JS
5429 if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
5430 char *new_args[n_changes + 2];
5431 unsigned i;
5432
5433 new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
5434 for (i = 0; i < n_changes; i++)
5435 new_args[i + 1] = basename(changes[i].path);
5436 new_args[i + 1] = NULL;
5437
5438 r = start_unit(bus, new_args);
5439 }
5440
729e3769 5441finish:
729e3769 5442 unit_file_changes_free(changes, n_changes);
ee5762e3 5443
729e3769 5444 return r;
ee5762e3
LP
5445}
5446
e94937df
LN
5447static int add_dependency(sd_bus *bus, char **args) {
5448 _cleanup_strv_free_ char **names = NULL;
5449 _cleanup_free_ char *target = NULL;
5450 const char *verb = args[0];
5451 UnitDependency dep;
5452 int r = 0;
5453
5454 if (!args[1])
5455 return 0;
5456
7410616c
LP
5457 r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
5458 if (r < 0)
5459 return log_error_errno(r, "Failed to mangle unit name: %m");
e94937df
LN
5460
5461 r = mangle_names(args+2, &names);
5462 if (r < 0)
5463 return r;
5464
5465 if (streq(verb, "add-wants"))
5466 dep = UNIT_WANTS;
5467 else if (streq(verb, "add-requires"))
5468 dep = UNIT_REQUIRES;
5469 else
5470 assert_not_reached("Unknown verb");
5471
5472 if (!bus || avoid_bus()) {
5473 UnitFileChange *changes = NULL;
5474 unsigned n_changes = 0;
5475
5476 r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
5477
f647962d
MS
5478 if (r < 0)
5479 return log_error_errno(r, "Can't add dependency: %m");
e94937df
LN
5480
5481 if (!arg_quiet)
5482 dump_unit_file_changes(changes, n_changes);
5483
5484 unit_file_changes_free(changes, n_changes);
5485
5486 } else {
5487 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
5488 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
5489
079dac08
LP
5490 polkit_agent_open_if_enabled();
5491
e94937df
LN
5492 r = sd_bus_message_new_method_call(
5493 bus,
5494 &m,
5495 "org.freedesktop.systemd1",
5496 "/org/freedesktop/systemd1",
5497 "org.freedesktop.systemd1.Manager",
5498 "AddDependencyUnitFiles");
5499 if (r < 0)
5500 return bus_log_create_error(r);
5501
342641fb 5502 r = sd_bus_message_append_strv(m, names);
e94937df
LN
5503 if (r < 0)
5504 return bus_log_create_error(r);
5505
342641fb 5506 r = sd_bus_message_append(m, "ssbb", target, unit_dependency_to_string(dep), arg_runtime, arg_force);
e94937df
LN
5507 if (r < 0)
5508 return bus_log_create_error(r);
5509
5510 r = sd_bus_call(bus, m, 0, &error, &reply);
5511 if (r < 0) {
5512 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5513 return r;
5514 }
5515
57ab2eab 5516 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
e94937df
LN
5517 if (r < 0)
5518 return r;
5519
5520 if (!arg_no_reload)
5521 r = daemon_reload(bus, args);
5522 else
5523 r = 0;
5524 }
5525
5526 return r;
5527}
5528
d309c1c3
LP
5529static int preset_all(sd_bus *bus, char **args) {
5530 UnitFileChange *changes = NULL;
5531 unsigned n_changes = 0;
5532 int r;
5533
5534 if (!bus || avoid_bus()) {
5535
5536 r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
5537 if (r < 0) {
da927ba9 5538 log_error_errno(r, "Operation failed: %m");
d309c1c3
LP
5539 goto finish;
5540 }
5541
5542 if (!arg_quiet)
5543 dump_unit_file_changes(changes, n_changes);
5544
5545 r = 0;
5546
5547 } else {
d309c1c3 5548 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6e646d22 5549 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
d309c1c3 5550
079dac08
LP
5551 polkit_agent_open_if_enabled();
5552
6e646d22 5553 r = sd_bus_call_method(
d309c1c3
LP
5554 bus,
5555 "org.freedesktop.systemd1",
5556 "/org/freedesktop/systemd1",
5557 "org.freedesktop.systemd1.Manager",
6e646d22
LP
5558 "PresetAllUnitFiles",
5559 &error,
5560 &reply,
d309c1c3
LP
5561 "sbb",
5562 unit_file_preset_mode_to_string(arg_preset_mode),
5563 arg_runtime,
5564 arg_force);
5565 if (r < 0) {
5566 log_error("Failed to execute operation: %s", bus_error_message(&error, r));
5567 return r;
5568 }
5569
57ab2eab 5570 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
d309c1c3
LP
5571 if (r < 0)
5572 return r;
5573
5574 if (!arg_no_reload)
5575 r = daemon_reload(bus, args);
5576 else
5577 r = 0;
5578 }
5579
5580finish:
5581 unit_file_changes_free(changes, n_changes);
5582
5583 return r;
5584}
5585
f459b602
MAP
5586static int unit_is_enabled(sd_bus *bus, char **args) {
5587
5588 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
e3e0314b 5589 _cleanup_strv_free_ char **names = NULL;
729e3769
LP
5590 bool enabled;
5591 char **name;
f459b602 5592 int r;
ee5762e3 5593
e3e0314b 5594 r = mangle_names(args+1, &names);
cbb13b2a
VP
5595 if (r < 0)
5596 return r;
5597
e3e0314b 5598 r = enable_sysv_units(args[0], names);
729e3769
LP
5599 if (r < 0)
5600 return r;
ee5762e3 5601
729e3769 5602 enabled = r > 0;
ee5762e3 5603
729e3769 5604 if (!bus || avoid_bus()) {
ee5762e3 5605
e3e0314b 5606 STRV_FOREACH(name, names) {
729e3769 5607 UnitFileState state;
ee5762e3 5608
cbb13b2a 5609 state = unit_file_get_state(arg_scope, arg_root, *name);
f647962d
MS
5610 if (state < 0)
5611 return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
ee5762e3 5612
729e3769
LP
5613 if (state == UNIT_FILE_ENABLED ||
5614 state == UNIT_FILE_ENABLED_RUNTIME ||
aedd4012
JS
5615 state == UNIT_FILE_STATIC ||
5616 state == UNIT_FILE_INDIRECT)
729e3769
LP
5617 enabled = true;
5618
5619 if (!arg_quiet)
5620 puts(unit_file_state_to_string(state));
71fad675 5621 }
ee5762e3 5622
729e3769 5623 } else {
e3e0314b 5624 STRV_FOREACH(name, names) {
f459b602 5625 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729e3769 5626 const char *s;
63a723f3 5627
f459b602 5628 r = sd_bus_call_method(
f22f08cd 5629 bus,
729e3769
LP
5630 "org.freedesktop.systemd1",
5631 "/org/freedesktop/systemd1",
5632 "org.freedesktop.systemd1.Manager",
f22f08cd 5633 "GetUnitFileState",
f459b602 5634 &error,
f22f08cd 5635 &reply,
04504f93 5636 "s", *name);
f459b602
MAP
5637 if (r < 0) {
5638 log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
cec7eda5 5639 return r;
ee5762e3
LP
5640 }
5641
f459b602
MAP
5642 r = sd_bus_message_read(reply, "s", &s);
5643 if (r < 0)
5644 return bus_log_parse_error(r);
ee5762e3 5645
aedd4012 5646 if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
729e3769
LP
5647 enabled = true;
5648
5649 if (!arg_quiet)
5650 puts(s);
560d8f23 5651 }
ee5762e3
LP
5652 }
5653
f459b602 5654 return !enabled;
ee5762e3
LP
5655}
5656
99813a19
LP
5657static int is_system_running(sd_bus *bus, char **args) {
5658 _cleanup_free_ char *state = NULL;
5659 int r;
5660
5661 r = sd_bus_get_property_string(
5662 bus,
5663 "org.freedesktop.systemd1",
5664 "/org/freedesktop/systemd1",
5665 "org.freedesktop.systemd1.Manager",
5666 "SystemState",
5667 NULL,
5668 &state);
5669 if (r < 0) {
5670 if (!arg_quiet)
5671 puts("unknown");
5672 return 0;
5673 }
5674
5675 if (!arg_quiet)
5676 puts(state);
5677
5678 return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
5679}
5680
7d4fb3b1 5681static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
7d4fb3b1 5682 char *t;
ae6c3cc0 5683 int r;
7d4fb3b1
RC
5684
5685 assert(new_path);
5686 assert(original_path);
5687 assert(ret_tmp_fn);
5688
14bcf25c 5689 r = tempfn_random(new_path, NULL, &t);
ae6c3cc0 5690 if (r < 0)
029009d4 5691 return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
7d4fb3b1
RC
5692
5693 r = mkdir_parents(new_path, 0755);
652212b0 5694 if (r < 0) {
029009d4 5695 log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
652212b0
TA
5696 free(t);
5697 return r;
5698 }
7d4fb3b1 5699
f2068bcc 5700 r = copy_file(original_path, t, 0, 0644, 0);
7d4fb3b1
RC
5701 if (r == -ENOENT) {
5702 r = touch(t);
5703 if (r < 0) {
029009d4 5704 log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
7d4fb3b1
RC
5705 free(t);
5706 return r;
5707 }
5708 } else if (r < 0) {
029009d4 5709 log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
7d4fb3b1
RC
5710 free(t);
5711 return r;
5712 }
5713
5714 *ret_tmp_fn = t;
5715
5716 return 0;
5717}
5718
bc854dc7
ZJS
5719static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
5720 _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
7d4fb3b1
RC
5721
5722 switch (arg_scope) {
5723 case UNIT_FILE_SYSTEM:
bc854dc7
ZJS
5724 path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
5725 if (arg_runtime)
5726 run = path_join(arg_root, "/run/systemd/system/", name);
7d4fb3b1
RC
5727 break;
5728 case UNIT_FILE_GLOBAL:
bc854dc7
ZJS
5729 path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5730 if (arg_runtime)
5731 run = path_join(arg_root, "/run/systemd/user/", name);
7d4fb3b1
RC
5732 break;
5733 case UNIT_FILE_USER:
5734 assert(user_home);
5735 assert(user_runtime);
5736
bc854dc7
ZJS
5737 path = path_join(arg_root, user_home, name);
5738 if (arg_runtime) {
5739 path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
5740 if (!path2)
5741 return log_oom();
5742 run = path_join(arg_root, user_runtime, name);
5743 }
7d4fb3b1
RC
5744 break;
5745 default:
5746 assert_not_reached("Invalid scope");
5747 }
bc854dc7 5748 if (!path || (arg_runtime && !run))
7d4fb3b1
RC
5749 return log_oom();
5750
bc854dc7
ZJS
5751 if (arg_runtime) {
5752 if (access(path, F_OK) >= 0)
ff9b60f3 5753 return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
bc854dc7
ZJS
5754 run, path);
5755 if (path2 && access(path2, F_OK) >= 0)
ff9b60f3 5756 return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
bc854dc7
ZJS
5757 run, path2);
5758 *ret_path = run;
5759 run = NULL;
5760 } else {
5761 *ret_path = path;
5762 path = NULL;
5763 }
7d4fb3b1
RC
5764
5765 return 0;
5766}
5767
bc854dc7
ZJS
5768static 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) {
5769 char *tmp_new_path, *ending;
7d4fb3b1
RC
5770 char *tmp_tmp_path;
5771 int r;
5772
5773 assert(unit_name);
5774 assert(ret_new_path);
5775 assert(ret_tmp_path);
5776
63c372cb 5777 ending = strjoina(unit_name, ".d/override.conf");
bc854dc7 5778 r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
5779 if (r < 0)
5780 return r;
5781
5782 r = create_edit_temp_file(tmp_new_path, tmp_new_path, &tmp_tmp_path);
5783 if (r < 0) {
5784 free(tmp_new_path);
5785 return r;
5786 }
5787
5788 *ret_new_path = tmp_new_path;
5789 *ret_tmp_path = tmp_tmp_path;
5790
5791 return 0;
5792}
5793
1cfa9a4c
LP
5794static int unit_file_create_copy(
5795 const char *unit_name,
5796 const char *fragment_path,
5797 const char *user_home,
5798 const char *user_runtime,
5799 char **ret_new_path,
5800 char **ret_tmp_path) {
5801
7d4fb3b1
RC
5802 char *tmp_new_path;
5803 char *tmp_tmp_path;
5804 int r;
5805
5806 assert(fragment_path);
5807 assert(unit_name);
5808 assert(ret_new_path);
5809 assert(ret_tmp_path);
5810
bc854dc7 5811 r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
7d4fb3b1
RC
5812 if (r < 0)
5813 return r;
5814
5815 if (!path_equal(fragment_path, tmp_new_path) && access(tmp_new_path, F_OK) == 0) {
5816 char response;
5817
029009d4 5818 r = ask_char(&response, "yn", "\"%s\" already exists. Overwrite with \"%s\"? [(y)es, (n)o] ", tmp_new_path, fragment_path);
7d4fb3b1
RC
5819 if (r < 0) {
5820 free(tmp_new_path);
5821 return r;
5822 }
5823 if (response != 'y') {
5824 log_warning("%s ignored", unit_name);
5825 free(tmp_new_path);
5826 return -1;
5827 }
5828 }
5829
5830 r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
5831 if (r < 0) {
029009d4 5832 log_error_errno(r, "Failed to create temporary file for \"%s\": %m", tmp_new_path);
7d4fb3b1
RC
5833 free(tmp_new_path);
5834 return r;
5835 }
5836
5837 *ret_new_path = tmp_new_path;
5838 *ret_tmp_path = tmp_tmp_path;
5839
5840 return 0;
5841}
5842
5843static int run_editor(char **paths) {
5844 pid_t pid;
5845 int r;
5846
5847 assert(paths);
5848
5849 pid = fork();
5850 if (pid < 0) {
5851 log_error_errno(errno, "Failed to fork: %m");
5852 return -errno;
5853 }
5854
5855 if (pid == 0) {
5856 const char **args;
9ef5d8f2 5857 char *editor, **editor_args = NULL;
1cfa9a4c 5858 char **tmp_path, **original_path, *p;
9ef5d8f2 5859 unsigned n_editor_args = 0, i = 1;
7d4fb3b1
RC
5860 size_t argc;
5861
ce30c8dc
LP
5862 (void) reset_all_signal_handlers();
5863 (void) reset_signal_mask();
5864
7d4fb3b1 5865 argc = strv_length(paths)/2 + 1;
7d4fb3b1
RC
5866
5867 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
5868 * If neither SYSTEMD_EDITOR nor EDITOR nor VISUAL are present,
5869 * we try to execute well known editors
5870 */
5871 editor = getenv("SYSTEMD_EDITOR");
5872 if (!editor)
5873 editor = getenv("EDITOR");
5874 if (!editor)
5875 editor = getenv("VISUAL");
5876
5877 if (!isempty(editor)) {
9ef5d8f2
JS
5878 editor_args = strv_split(editor, WHITESPACE);
5879 if (!editor_args) {
5880 (void) log_oom();
5881 _exit(EXIT_FAILURE);
5882 }
5883 n_editor_args = strv_length(editor_args);
5884 argc += n_editor_args - 1;
5885 }
5886 args = newa(const char*, argc + 1);
5887
5888 if (n_editor_args > 0) {
5889 args[0] = editor_args[0];
5890 for (; i < n_editor_args; i++)
5891 args[i] = editor_args[i];
5892 }
5893
5894 STRV_FOREACH_PAIR(original_path, tmp_path, paths) {
5895 args[i] = *tmp_path;
5896 i++;
7d4fb3b1 5897 }
9ef5d8f2
JS
5898 args[i] = NULL;
5899
5900 if (n_editor_args > 0)
5901 execvp(args[0], (char* const*) args);
7d4fb3b1 5902
9391a1c3 5903 FOREACH_STRING(p, "editor", "nano", "vim", "vi") {
1cfa9a4c
LP
5904 args[0] = p;
5905 execvp(p, (char* const*) args);
7d4fb3b1
RC
5906 /* We do not fail if the editor doesn't exist
5907 * because we want to try each one of them before
5908 * failing.
5909 */
5910 if (errno != ENOENT) {
5911 log_error("Failed to execute %s: %m", editor);
5912 _exit(EXIT_FAILURE);
5913 }
5914 }
5915
1cfa9a4c 5916 log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR, $EDITOR or $VISUAL.");
7d4fb3b1
RC
5917 _exit(EXIT_FAILURE);
5918 }
5919
5920 r = wait_for_terminate_and_warn("editor", pid, true);
5921 if (r < 0)
5922 return log_error_errno(r, "Failed to wait for child: %m");
5923
5924 return r;
5925}
5926
5927static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
5928 _cleanup_free_ char *user_home = NULL;
5929 _cleanup_free_ char *user_runtime = NULL;
e9e310f8
RC
5930 _cleanup_lookup_paths_free_ LookupPaths lp = {};
5931 bool avoid_bus_cache;
7d4fb3b1
RC
5932 char **name;
5933 int r;
5934
5935 assert(names);
5936 assert(paths);
5937
8df18507 5938 r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
5b013a2f 5939 if (r < 0)
8df18507 5940 return r;
7d4fb3b1 5941
e9e310f8 5942 avoid_bus_cache = !bus || avoid_bus();
7d4fb3b1 5943
e9e310f8
RC
5944 STRV_FOREACH(name, names) {
5945 _cleanup_free_ char *path = NULL;
e9e310f8 5946 char *new_path, *tmp_path;
7d4fb3b1 5947
ad2a0358 5948 r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL);
e9e310f8
RC
5949 if (r < 0)
5950 return r;
b5e6a600
IS
5951 else if (r == 0)
5952 return -ENOENT;
5953 else if (!path) {
ad2a0358 5954 // FIXME: support units with path==NULL (no FragmentPath)
b5e6a600
IS
5955 log_error("No fragment exists for %s.", *name);
5956 return -ENOENT;
5957 }
7d4fb3b1 5958
e9e310f8 5959 if (arg_full)
ad2a0358 5960 r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 5961 else
bc854dc7 5962 r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
e9e310f8 5963 if (r < 0)
ad2a0358 5964 return r;
7d4fb3b1 5965
e9e310f8
RC
5966 r = strv_push_pair(paths, new_path, tmp_path);
5967 if (r < 0)
5968 return log_oom();
7d4fb3b1
RC
5969 }
5970
5971 return 0;
5972}
5973
5974static int edit(sd_bus *bus, char **args) {
5975 _cleanup_strv_free_ char **names = NULL;
5976 _cleanup_strv_free_ char **paths = NULL;
5977 char **original, **tmp;
5978 int r;
5979
5980 assert(args);
5981
5982 if (!on_tty()) {
029009d4 5983 log_error("Cannot edit units if not on a tty");
7d4fb3b1
RC
5984 return -EINVAL;
5985 }
5986
5987 if (arg_transport != BUS_TRANSPORT_LOCAL) {
5988 log_error("Cannot remotely edit units");
5989 return -EINVAL;
5990 }
5991
5992 r = expand_names(bus, args + 1, NULL, &names);
5993 if (r < 0)
5994 return log_error_errno(r, "Failed to expand names: %m");
5995
7d4fb3b1
RC
5996 r = find_paths_to_edit(bus, names, &paths);
5997 if (r < 0)
5998 return r;
5999
b5e6a600 6000 if (strv_isempty(paths))
7d4fb3b1 6001 return -ENOENT;
7d4fb3b1
RC
6002
6003 r = run_editor(paths);
6004 if (r < 0)
6005 goto end;
6006
6007 STRV_FOREACH_PAIR(original, tmp, paths) {
6008 /* If the temporary file is empty we ignore it.
6009 * It's useful if the user wants to cancel its modification
6010 */
6011 if (null_or_empty_path(*tmp)) {
029009d4 6012 log_warning("Editing \"%s\" canceled: temporary file is empty", *original);
7d4fb3b1
RC
6013 continue;
6014 }
6015 r = rename(*tmp, *original);
6016 if (r < 0) {
029009d4 6017 r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
7d4fb3b1
RC
6018 goto end;
6019 }
6020 }
6021
6022 if (!arg_no_reload && bus && !avoid_bus())
6023 r = daemon_reload(bus, args);
6024
6025end:
6026 STRV_FOREACH_PAIR(original, tmp, paths)
6027 unlink_noerrno(*tmp);
6028
6029 return r;
6030}
6031
601185b4 6032static void systemctl_help(void) {
7e4249b9 6033
729e3769
LP
6034 pager_open_if_enabled();
6035
2e33c433 6036 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 6037 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
6038 " -h --help Show this help\n"
6039 " --version Show package version\n"
f459b602
MAP
6040 " --system Connect to system manager\n"
6041 " --user Connect to user service manager\n"
6042 " -H --host=[USER@]HOST\n"
6043 " Operate on remote host\n"
6044 " -M --machine=CONTAINER\n"
6045 " Operate on local container\n"
3fb90db2
ZJS
6046 " -t --type=TYPE List units of a particular type\n"
6047 " --state=STATE List units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 6048 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
6049 " -a --all Show all loaded units/properties, including dead/empty\n"
6050 " ones. To list all units installed on the system, use\n"
6051 " the 'list-unit-files' command instead.\n"
98a6e132 6052 " -l --full Don't ellipsize unit names on output\n"
1238ee09 6053 " -r --recursive Show unit list of host and local containers\n"
4dc5b821
LP
6054 " --reverse Show reverse dependencies with 'list-dependencies'\n"
6055 " --job-mode=MODE Specify how to deal with already queued jobs, when\n"
6056 " queueing a new job\n"
a521ae4a 6057 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
6058 " -i --ignore-inhibitors\n"
6059 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
6060 " --kill-who=WHO Who to send signal to\n"
6061 " -s --signal=SIGNAL Which signal to send\n"
57ab2eab 6062 " --now Start or stop unit in addition to enabling or disabling it\n"
8a0867d6
LP
6063 " -q --quiet Suppress output\n"
6064 " --no-block Do not wait until operation finished\n"
8a0867d6 6065 " --no-wall Don't send wall message before halt/power-off/reboot\n"
3fb90db2 6066 " --no-reload Don't reload daemon after en-/dis-abling unit files\n"
ebed32bf 6067 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 6068 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
6069 " --no-ask-password\n"
6070 " Do not ask for system passwords\n"
a8f11321 6071 " --global Enable/disable unit files globally\n"
a521ae4a 6072 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
6073 " -f --force When enabling unit files, override existing symlinks\n"
6074 " When shutting down, execute action immediately\n"
3fb90db2 6075 " --preset-mode= Apply only enable, only disable, or all presets\n"
729e3769 6076 " --root=PATH Enable unit files in the specified root directory\n"
76fdc966 6077 " -n --lines=INTEGER Number of journal entries to show\n"
86d81e50
RC
6078 " -o --output=STRING Change journal output mode (short, short-iso,\n"
6079 " short-precise, short-monotonic, verbose,\n"
6080 " export, json, json-pretty, json-sse, cat)\n"
5bdf2243 6081 " --firmware-setup Tell the firmware to show the setup menu on next boot\n"
815ebc54 6082 " --plain Print unit dependencies as a list instead of a tree\n\n"
34c4b47b 6083 "Unit Commands:\n"
d8fba7c6
ZJS
6084 " list-units [PATTERN...] List loaded units\n"
6085 " list-sockets [PATTERN...] List loaded sockets ordered by address\n"
6086 " list-timers [PATTERN...] List loaded timers ordered by next elapse\n"
4f8f66cb
ZJS
6087 " start NAME... Start (activate) one or more units\n"
6088 " stop NAME... Stop (deactivate) one or more units\n"
6089 " reload NAME... Reload one or more units\n"
6090 " restart NAME... Start or restart one or more units\n"
6091 " try-restart NAME... Restart one or more units if active\n"
6092 " reload-or-restart NAME... Reload one or more units if possible,\n"
6f28c033 6093 " otherwise start or restart\n"
4f8f66cb 6094 " reload-or-try-restart NAME... Reload one or more units if possible,\n"
6f28c033 6095 " otherwise restart if active\n"
4f8f66cb
ZJS
6096 " isolate NAME Start one unit and stop all others\n"
6097 " kill NAME... Send signal to processes of a unit\n"
b3ae710c
ZJS
6098 " is-active PATTERN... Check whether units are active\n"
6099 " is-failed PATTERN... Check whether units are failed\n"
6100 " status [PATTERN...|PID...] Show runtime status of one or more units\n"
6101 " show [PATTERN...|JOB...] Show properties of one or more\n"
ee5762e3 6102 " units/jobs or the manager\n"
b3ae710c 6103 " cat PATTERN... Show files and drop-ins of one or more units\n"
4f8f66cb 6104 " set-property NAME ASSIGNMENT... Sets one or more properties of a unit\n"
b3ae710c
ZJS
6105 " help PATTERN...|PID... Show manual for one or more units\n"
6106 " reset-failed [PATTERN...] Reset failed state for all, one, or more\n"
fdf20a31 6107 " units\n"
55c0b89c 6108 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
6109 " or wanted by this unit or by which this\n"
6110 " unit is required or wanted\n\n"
34c4b47b 6111 "Unit File Commands:\n"
d8fba7c6 6112 " list-unit-files [PATTERN...] List installed unit files\n"
4f8f66cb
ZJS
6113 " enable NAME... Enable one or more unit files\n"
6114 " disable NAME... Disable one or more unit files\n"
6115 " reenable NAME... Reenable one or more unit files\n"
6116 " preset NAME... Enable/disable one or more unit files\n"
729e3769 6117 " based on preset configuration\n"
d309c1c3
LP
6118 " preset-all Enable/disable all unit files based on\n"
6119 " preset configuration\n"
b619ec8f 6120 " is-enabled NAME... Check whether unit files are enabled\n"
4f8f66cb
ZJS
6121 " mask NAME... Mask one or more units\n"
6122 " unmask NAME... Unmask one or more units\n"
6123 " link PATH... Link one or more units files into\n"
729e3769 6124 " the search path\n"
e94937df
LN
6125 " add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
6126 " on specified one or more units\n"
6127 " add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
6128 " on specified one or more units\n"
7d4fb3b1 6129 " edit NAME... Edit one or more unit files\n"
b619ec8f
LP
6130 " get-default Get the name of the default target\n"
6131 " set-default NAME Set the default target\n\n"
0d292f5e
LP
6132 "Machine Commands:\n"
6133 " list-machines [PATTERN...] List local containers and host\n\n"
34c4b47b 6134 "Job Commands:\n"
d8fba7c6 6135 " list-jobs [PATTERN...] List jobs\n"
34c4b47b 6136 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 6137 "Snapshot Commands:\n"
7e4249b9 6138 " snapshot [NAME] Create a snapshot\n"
4f8f66cb 6139 " delete NAME... Remove one or more snapshots\n\n"
34c4b47b 6140 "Environment Commands:\n"
7e4249b9 6141 " show-environment Dump environment\n"
4f8f66cb 6142 " set-environment NAME=VALUE... Set one or more environment variables\n"
ac3efa8a 6143 " unset-environment NAME... Unset one or more environment variables\n"
3fb90db2 6144 " import-environment [NAME...] Import all or some environment variables\n\n"
34c4b47b
LP
6145 "Manager Lifecycle Commands:\n"
6146 " daemon-reload Reload systemd manager configuration\n"
6147 " daemon-reexec Reexecute systemd manager\n\n"
6148 "System Commands:\n"
99813a19 6149 " is-system-running Check whether system is fully running\n"
20b09ca7
LP
6150 " default Enter system default mode\n"
6151 " rescue Enter system rescue mode\n"
6152 " emergency Enter system emergency mode\n"
514f4ef5 6153 " halt Shut down and halt the system\n"
2e33c433 6154 " poweroff Shut down and power-off the system\n"
37185ec8 6155 " reboot [ARG] Shut down and reboot the system\n"
20b09ca7 6156 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 6157 " exit Request user instance exit\n"
4f8f66cb 6158 " switch-root ROOT [INIT] Change to a different root file system\n"
6edd7d0a 6159 " suspend Suspend the system\n"
6524990f
LP
6160 " hibernate Hibernate the system\n"
6161 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 6162 program_invocation_short_name);
7e4249b9
LP
6163}
6164
601185b4 6165static void halt_help(void) {
37185ec8 6166 printf("%s [OPTIONS...]%s\n\n"
e4b61340
LP
6167 "%s the system.\n\n"
6168 " --help Show this help\n"
6169 " --halt Halt the machine\n"
6170 " -p --poweroff Switch off the machine\n"
6171 " --reboot Reboot the machine\n"
2e33c433
LP
6172 " -f --force Force immediate halt/power-off/reboot\n"
6173 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 6174 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 6175 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340 6176 program_invocation_short_name,
37185ec8 6177 arg_action == ACTION_REBOOT ? " [ARG]" : "",
e4b61340
LP
6178 arg_action == ACTION_REBOOT ? "Reboot" :
6179 arg_action == ACTION_POWEROFF ? "Power off" :
6180 "Halt");
e4b61340
LP
6181}
6182
601185b4 6183static void shutdown_help(void) {
08e4b1c5 6184 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
6185 "Shut down the system.\n\n"
6186 " --help Show this help\n"
6187 " -H --halt Halt the machine\n"
6188 " -P --poweroff Power-off the machine\n"
6189 " -r --reboot Reboot the machine\n"
386da858 6190 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 6191 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 6192 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 6193 " -c Cancel a pending shutdown\n",
e4b61340 6194 program_invocation_short_name);
e4b61340
LP
6195}
6196
601185b4 6197static void telinit_help(void) {
2e33c433 6198 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
6199 "Send control commands to the init daemon.\n\n"
6200 " --help Show this help\n"
2e33c433 6201 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
6202 "Commands:\n"
6203 " 0 Power-off the machine\n"
6204 " 6 Reboot the machine\n"
514f4ef5
LP
6205 " 2, 3, 4, 5 Start runlevelX.target unit\n"
6206 " 1, s, S Enter rescue mode\n"
6207 " q, Q Reload init daemon configuration\n"
6208 " u, U Reexecute init daemon\n",
e4b61340 6209 program_invocation_short_name);
e4b61340
LP
6210}
6211
601185b4 6212static void runlevel_help(void) {
2e33c433 6213 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
6214 "Prints the previous and current runlevel of the init system.\n\n"
6215 " --help Show this help\n",
6216 program_invocation_short_name);
e4b61340
LP
6217}
6218
b93312f5 6219static void help_types(void) {
45c0c61d 6220 int i;
830f01f0 6221 const char *t;
45c0c61d 6222
b93312f5
ZJS
6223 if (!arg_no_legend)
6224 puts("Available unit types:");
f168c273 6225 for (i = 0; i < _UNIT_TYPE_MAX; i++) {
830f01f0
LP
6226 t = unit_type_to_string(i);
6227 if (t)
6228 puts(t);
6229 }
45c0c61d
ZJS
6230}
6231
e4b61340 6232static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
6233
6234 enum {
90d473a1 6235 ARG_FAIL = 0x100,
afba4199
ZJS
6236 ARG_REVERSE,
6237 ARG_AFTER,
6238 ARG_BEFORE,
991f2a39 6239 ARG_SHOW_TYPES,
23ade460 6240 ARG_IRREVERSIBLE,
e67c3609 6241 ARG_IGNORE_DEPENDENCIES,
35df8f27 6242 ARG_VERSION,
af2d49f7 6243 ARG_USER,
7e4249b9 6244 ARG_SYSTEM,
ee5762e3 6245 ARG_GLOBAL,
6e905d93 6246 ARG_NO_BLOCK,
ebed32bf 6247 ARG_NO_LEGEND,
611efaac 6248 ARG_NO_PAGER,
4445a875 6249 ARG_NO_WALL,
be394c48 6250 ARG_ROOT,
ee5762e3 6251 ARG_NO_RELOAD,
501fc174 6252 ARG_KILL_WHO,
30732560 6253 ARG_NO_ASK_PASSWORD,
729e3769 6254 ARG_FAILED,
df50185b 6255 ARG_RUNTIME,
5d0c05e5 6256 ARG_FORCE,
9b9b3d36 6257 ARG_PLAIN,
4dc5b821 6258 ARG_STATE,
d309c1c3
LP
6259 ARG_JOB_MODE,
6260 ARG_PRESET_MODE,
5bdf2243 6261 ARG_FIRMWARE_SETUP,
57ab2eab 6262 ARG_NOW,
7e4249b9
LP
6263 };
6264
6265 static const struct option options[] = {
9ea9d4cf
LP
6266 { "help", no_argument, NULL, 'h' },
6267 { "version", no_argument, NULL, ARG_VERSION },
6268 { "type", required_argument, NULL, 't' },
6269 { "property", required_argument, NULL, 'p' },
6270 { "all", no_argument, NULL, 'a' },
6271 { "reverse", no_argument, NULL, ARG_REVERSE },
6272 { "after", no_argument, NULL, ARG_AFTER },
6273 { "before", no_argument, NULL, ARG_BEFORE },
6274 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
6275 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
6276 { "full", no_argument, NULL, 'l' },
4dc5b821
LP
6277 { "job-mode", required_argument, NULL, ARG_JOB_MODE },
6278 { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
6279 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
6280 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
9ea9d4cf
LP
6281 { "ignore-inhibitors", no_argument, NULL, 'i' },
6282 { "user", no_argument, NULL, ARG_USER },
6283 { "system", no_argument, NULL, ARG_SYSTEM },
6284 { "global", no_argument, NULL, ARG_GLOBAL },
6285 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
6286 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
6287 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
6288 { "no-wall", no_argument, NULL, ARG_NO_WALL },
6289 { "quiet", no_argument, NULL, 'q' },
6290 { "root", required_argument, NULL, ARG_ROOT },
6291 { "force", no_argument, NULL, ARG_FORCE },
6292 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
6293 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
6294 { "signal", required_argument, NULL, 's' },
6295 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
6296 { "host", required_argument, NULL, 'H' },
f459b602 6297 { "machine", required_argument, NULL, 'M' },
9ea9d4cf
LP
6298 { "runtime", no_argument, NULL, ARG_RUNTIME },
6299 { "lines", required_argument, NULL, 'n' },
6300 { "output", required_argument, NULL, 'o' },
6301 { "plain", no_argument, NULL, ARG_PLAIN },
6302 { "state", required_argument, NULL, ARG_STATE },
1238ee09 6303 { "recursive", no_argument, NULL, 'r' },
d309c1c3 6304 { "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
5bdf2243 6305 { "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
57ab2eab 6306 { "now", no_argument, NULL, ARG_NOW },
eb9da376 6307 {}
7e4249b9
LP
6308 };
6309
6310 int c;
6311
e4b61340 6312 assert(argc >= 0);
7e4249b9
LP
6313 assert(argv);
6314
601185b4 6315 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
7e4249b9
LP
6316
6317 switch (c) {
6318
6319 case 'h':
601185b4
ZJS
6320 systemctl_help();
6321 return 0;
35df8f27
LP
6322
6323 case ARG_VERSION:
6324 puts(PACKAGE_STRING);
7d568925 6325 puts(SYSTEMD_FEATURES);
35df8f27 6326 return 0;
7e4249b9 6327
20b3f379 6328 case 't': {
a2a5291b 6329 const char *word, *state;
20b3f379 6330 size_t size;
45c0c61d 6331
20b3f379 6332 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 6333 _cleanup_free_ char *type;
20b3f379
ZJS
6334
6335 type = strndup(word, size);
6336 if (!type)
6337 return -ENOMEM;
6338
6339 if (streq(type, "help")) {
6340 help_types();
6341 return 0;
6342 }
6343
6344 if (unit_type_from_string(type) >= 0) {
6345 if (strv_push(&arg_types, type))
6346 return log_oom();
6347 type = NULL;
6348 continue;
6349 }
6350
9b9b3d36
MW
6351 /* It's much nicer to use --state= for
6352 * load states, but let's support this
6353 * in --types= too for compatibility
6354 * with old versions */
20b3f379 6355 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 6356 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
6357 return log_oom();
6358 type = NULL;
6359 continue;
6360 }
6361
ab06eef8 6362 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
6363 log_info("Use -t help to see a list of allowed values.");
6364 return -EINVAL;
c147dc42 6365 }
20b3f379
ZJS
6366
6367 break;
6368 }
6369
ea4a240d 6370 case 'p': {
033a842c
ZJS
6371 /* Make sure that if the empty property list
6372 was specified, we won't show any properties. */
20b3f379 6373 if (isempty(optarg) && !arg_properties) {
cbc9fbd1 6374 arg_properties = new0(char*, 1);
20b3f379
ZJS
6375 if (!arg_properties)
6376 return log_oom();
6377 } else {
a2a5291b 6378 const char *word, *state;
20b3f379 6379 size_t size;
033a842c 6380
20b3f379
ZJS
6381 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6382 char *prop;
033a842c 6383
20b3f379
ZJS
6384 prop = strndup(word, size);
6385 if (!prop)
6386 return log_oom();
ea4a240d 6387
6e18964d 6388 if (strv_consume(&arg_properties, prop) < 0)
20b3f379 6389 return log_oom();
20b3f379 6390 }
033a842c 6391 }
48220598
LP
6392
6393 /* If the user asked for a particular
6394 * property, show it to him, even if it is
6395 * empty. */
6396 arg_all = true;
033a842c 6397
48220598 6398 break;
ea4a240d 6399 }
48220598 6400
7e4249b9
LP
6401 case 'a':
6402 arg_all = true;
6403 break;
6404
afba4199
ZJS
6405 case ARG_REVERSE:
6406 arg_dependency = DEPENDENCY_REVERSE;
6407 break;
6408
6409 case ARG_AFTER:
6410 arg_dependency = DEPENDENCY_AFTER;
6411 break;
6412
6413 case ARG_BEFORE:
6414 arg_dependency = DEPENDENCY_BEFORE;
6415 break;
6416
991f2a39
ZJS
6417 case ARG_SHOW_TYPES:
6418 arg_show_types = true;
6419 break;
6420
4dc5b821
LP
6421 case ARG_JOB_MODE:
6422 arg_job_mode = optarg;
6423 break;
6424
90d473a1 6425 case ARG_FAIL:
e67c3609
LP
6426 arg_job_mode = "fail";
6427 break;
6428
23ade460
MS
6429 case ARG_IRREVERSIBLE:
6430 arg_job_mode = "replace-irreversibly";
6431 break;
6432
e67c3609
LP
6433 case ARG_IGNORE_DEPENDENCIES:
6434 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
6435 break;
6436
af2d49f7 6437 case ARG_USER:
729e3769 6438 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
6439 break;
6440
6441 case ARG_SYSTEM:
729e3769
LP
6442 arg_scope = UNIT_FILE_SYSTEM;
6443 break;
6444
6445 case ARG_GLOBAL:
6446 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
6447 break;
6448
6e905d93
LP
6449 case ARG_NO_BLOCK:
6450 arg_no_block = true;
7e4249b9
LP
6451 break;
6452
ebed32bf
MS
6453 case ARG_NO_LEGEND:
6454 arg_no_legend = true;
6455 break;
6456
611efaac
LP
6457 case ARG_NO_PAGER:
6458 arg_no_pager = true;
6459 break;
0736af98 6460
514f4ef5
LP
6461 case ARG_NO_WALL:
6462 arg_no_wall = true;
6463 break;
6464
be394c48
FC
6465 case ARG_ROOT:
6466 arg_root = optarg;
6467 break;
6468
98a6e132 6469 case 'l':
8fe914ec
LP
6470 arg_full = true;
6471 break;
6472
30732560 6473 case ARG_FAILED:
9b9b3d36
MW
6474 if (strv_extend(&arg_states, "failed") < 0)
6475 return log_oom();
6476
30732560
LP
6477 break;
6478
0183528f
LP
6479 case 'q':
6480 arg_quiet = true;
6481 break;
6482
568b679f
LP
6483 case ARG_FORCE:
6484 arg_force ++;
6485 break;
6486
b4f27ccc 6487 case 'f':
e606bb61 6488 arg_force ++;
ee5762e3
LP
6489 break;
6490
6491 case ARG_NO_RELOAD:
6492 arg_no_reload = true;
6493 break;
6494
8a0867d6
LP
6495 case ARG_KILL_WHO:
6496 arg_kill_who = optarg;
6497 break;
6498
8a0867d6
LP
6499 case 's':
6500 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
6501 log_error("Failed to parse signal string %s.", optarg);
6502 return -EINVAL;
6503 }
6504 break;
6505
501fc174
LP
6506 case ARG_NO_ASK_PASSWORD:
6507 arg_ask_password = false;
6508 break;
6509
f459b602
MAP
6510 case 'H':
6511 arg_transport = BUS_TRANSPORT_REMOTE;
6512 arg_host = optarg;
a8f11321
LP
6513 break;
6514
f459b602 6515 case 'M':
de33fc62 6516 arg_transport = BUS_TRANSPORT_MACHINE;
f459b602 6517 arg_host = optarg;
a8f11321
LP
6518 break;
6519
729e3769
LP
6520 case ARG_RUNTIME:
6521 arg_runtime = true;
6522 break;
6523
df50185b
LP
6524 case 'n':
6525 if (safe_atou(optarg, &arg_lines) < 0) {
6526 log_error("Failed to parse lines '%s'", optarg);
6527 return -EINVAL;
6528 }
6529 break;
6530
df50185b
LP
6531 case 'o':
6532 arg_output = output_mode_from_string(optarg);
6533 if (arg_output < 0) {
6534 log_error("Unknown output '%s'.", optarg);
6535 return -EINVAL;
6536 }
6537 break;
6538
b37844d3
LP
6539 case 'i':
6540 arg_ignore_inhibitors = true;
6541 break;
6542
5d0c05e5
LN
6543 case ARG_PLAIN:
6544 arg_plain = true;
6545 break;
6546
5bdf2243
JJ
6547 case ARG_FIRMWARE_SETUP:
6548 arg_firmware_setup = true;
6549 break;
6550
9b9b3d36 6551 case ARG_STATE: {
a2a5291b 6552 const char *word, *state;
9b9b3d36
MW
6553 size_t size;
6554
6555 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
6556 char *s;
6557
6558 s = strndup(word, size);
6559 if (!s)
6560 return log_oom();
6561
6e18964d 6562 if (strv_consume(&arg_states, s) < 0)
9b9b3d36 6563 return log_oom();
9b9b3d36
MW
6564 }
6565 break;
6566 }
6567
1238ee09
LP
6568 case 'r':
6569 if (geteuid() != 0) {
f1721625 6570 log_error("--recursive requires root privileges.");
1238ee09
LP
6571 return -EPERM;
6572 }
6573
6574 arg_recursive = true;
6575 break;
6576
d309c1c3
LP
6577 case ARG_PRESET_MODE:
6578
6579 arg_preset_mode = unit_file_preset_mode_from_string(optarg);
6580 if (arg_preset_mode < 0) {
6581 log_error("Failed to parse preset mode: %s.", optarg);
6582 return -EINVAL;
6583 }
6584
6585 break;
6586
57ab2eab
JS
6587 case ARG_NOW:
6588 arg_now = true;
6589 break;
6590
7e4249b9
LP
6591 case '?':
6592 return -EINVAL;
6593
6594 default:
eb9da376 6595 assert_not_reached("Unhandled option");
7e4249b9 6596 }
7e4249b9 6597
f459b602 6598 if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
6599 log_error("Cannot access user instance remotely.");
6600 return -EINVAL;
6601 }
6602
7e4249b9
LP
6603 return 1;
6604}
6605
e4b61340
LP
6606static int halt_parse_argv(int argc, char *argv[]) {
6607
6608 enum {
6609 ARG_HELP = 0x100,
6610 ARG_HALT,
514f4ef5
LP
6611 ARG_REBOOT,
6612 ARG_NO_WALL
e4b61340
LP
6613 };
6614
6615 static const struct option options[] = {
6616 { "help", no_argument, NULL, ARG_HELP },
6617 { "halt", no_argument, NULL, ARG_HALT },
6618 { "poweroff", no_argument, NULL, 'p' },
6619 { "reboot", no_argument, NULL, ARG_REBOOT },
6620 { "force", no_argument, NULL, 'f' },
6621 { "wtmp-only", no_argument, NULL, 'w' },
6622 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 6623 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6624 {}
e4b61340
LP
6625 };
6626
37185ec8 6627 int c, r, runlevel;
e4b61340
LP
6628
6629 assert(argc >= 0);
6630 assert(argv);
6631
6632 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
6633 if (runlevel == '0' || runlevel == '6')
65491fd8 6634 arg_force = 2;
e4b61340 6635
601185b4 6636 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0)
e4b61340
LP
6637 switch (c) {
6638
6639 case ARG_HELP:
601185b4
ZJS
6640 halt_help();
6641 return 0;
e4b61340
LP
6642
6643 case ARG_HALT:
6644 arg_action = ACTION_HALT;
6645 break;
6646
6647 case 'p':
a042efad
MS
6648 if (arg_action != ACTION_REBOOT)
6649 arg_action = ACTION_POWEROFF;
e4b61340
LP
6650 break;
6651
6652 case ARG_REBOOT:
6653 arg_action = ACTION_REBOOT;
6654 break;
6655
6656 case 'f':
65491fd8 6657 arg_force = 2;
e4b61340
LP
6658 break;
6659
6660 case 'w':
6661 arg_dry = true;
6662 break;
6663
6664 case 'd':
6665 arg_no_wtmp = true;
6666 break;
6667
514f4ef5
LP
6668 case ARG_NO_WALL:
6669 arg_no_wall = true;
6670 break;
6671
e4b61340
LP
6672 case 'i':
6673 case 'h':
57371e58 6674 case 'n':
e4b61340
LP
6675 /* Compatibility nops */
6676 break;
6677
6678 case '?':
6679 return -EINVAL;
6680
6681 default:
eb9da376 6682 assert_not_reached("Unhandled option");
e4b61340 6683 }
e4b61340 6684
c5220a94
MO
6685 if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
6686 r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
6687 if (r < 0)
37185ec8 6688 return r;
37185ec8 6689 } else if (optind < argc) {
e4b61340
LP
6690 log_error("Too many arguments.");
6691 return -EINVAL;
6692 }
6693
6694 return 1;
6695}
6696
f6144808
LP
6697static int parse_time_spec(const char *t, usec_t *_u) {
6698 assert(t);
6699 assert(_u);
6700
6701 if (streq(t, "now"))
6702 *_u = 0;
1a639877 6703 else if (!strchr(t, ':')) {
f6144808
LP
6704 uint64_t u;
6705
1a639877 6706 if (safe_atou64(t, &u) < 0)
f6144808
LP
6707 return -EINVAL;
6708
6709 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
6710 } else {
6711 char *e = NULL;
6712 long hour, minute;
b92bea5d 6713 struct tm tm = {};
f6144808
LP
6714 time_t s;
6715 usec_t n;
6716
6717 errno = 0;
6718 hour = strtol(t, &e, 10);
8333c77e 6719 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
6720 return -EINVAL;
6721
6722 minute = strtol(e+1, &e, 10);
8333c77e 6723 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
6724 return -EINVAL;
6725
6726 n = now(CLOCK_REALTIME);
08e4b1c5
LP
6727 s = (time_t) (n / USEC_PER_SEC);
6728
f6144808
LP
6729 assert_se(localtime_r(&s, &tm));
6730
6731 tm.tm_hour = (int) hour;
6732 tm.tm_min = (int) minute;
08e4b1c5 6733 tm.tm_sec = 0;
f6144808
LP
6734
6735 assert_se(s = mktime(&tm));
6736
6737 *_u = (usec_t) s * USEC_PER_SEC;
6738
6739 while (*_u <= n)
6740 *_u += USEC_PER_DAY;
6741 }
6742
6743 return 0;
6744}
6745
e4b61340
LP
6746static int shutdown_parse_argv(int argc, char *argv[]) {
6747
6748 enum {
6749 ARG_HELP = 0x100,
514f4ef5 6750 ARG_NO_WALL
e4b61340
LP
6751 };
6752
6753 static const struct option options[] = {
6754 { "help", no_argument, NULL, ARG_HELP },
6755 { "halt", no_argument, NULL, 'H' },
6756 { "poweroff", no_argument, NULL, 'P' },
6757 { "reboot", no_argument, NULL, 'r' },
04ebb595 6758 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 6759 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6760 {}
e4b61340
LP
6761 };
6762
f6144808 6763 int c, r;
e4b61340
LP
6764
6765 assert(argc >= 0);
6766 assert(argv);
6767
75836b9d 6768 while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
e4b61340
LP
6769 switch (c) {
6770
6771 case ARG_HELP:
601185b4
ZJS
6772 shutdown_help();
6773 return 0;
e4b61340
LP
6774
6775 case 'H':
6776 arg_action = ACTION_HALT;
6777 break;
6778
6779 case 'P':
6780 arg_action = ACTION_POWEROFF;
6781 break;
6782
6783 case 'r':
5622dde3
KS
6784 if (kexec_loaded())
6785 arg_action = ACTION_KEXEC;
6786 else
6787 arg_action = ACTION_REBOOT;
e4b61340
LP
6788 break;
6789
04ebb595
LP
6790 case 'K':
6791 arg_action = ACTION_KEXEC;
6792 break;
6793
e4b61340
LP
6794 case 'h':
6795 if (arg_action != ACTION_HALT)
6796 arg_action = ACTION_POWEROFF;
6797 break;
6798
6799 case 'k':
6800 arg_dry = true;
6801 break;
6802
514f4ef5
LP
6803 case ARG_NO_WALL:
6804 arg_no_wall = true;
6805 break;
6806
e4b61340
LP
6807 case 't':
6808 case 'a':
75836b9d
JS
6809 case 'f':
6810 case 'F':
e4b61340
LP
6811 /* Compatibility nops */
6812 break;
6813
f6144808
LP
6814 case 'c':
6815 arg_action = ACTION_CANCEL_SHUTDOWN;
6816 break;
6817
e4b61340
LP
6818 case '?':
6819 return -EINVAL;
6820
6821 default:
eb9da376 6822 assert_not_reached("Unhandled option");
e4b61340 6823 }
e4b61340 6824
dfcc5c33 6825 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
6826 r = parse_time_spec(argv[optind], &arg_when);
6827 if (r < 0) {
f6144808
LP
6828 log_error("Failed to parse time specification: %s", argv[optind]);
6829 return r;
6830 }
6b5ad000 6831 } else
08e4b1c5 6832 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 6833
dfcc5c33
MS
6834 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
6835 /* No time argument for shutdown cancel */
6836 arg_wall = argv + optind;
6837 else if (argc > optind + 1)
6838 /* We skip the time argument */
e4b61340
LP
6839 arg_wall = argv + optind + 1;
6840
6841 optind = argc;
6842
6843 return 1;
e4b61340
LP
6844}
6845
6846static int telinit_parse_argv(int argc, char *argv[]) {
6847
6848 enum {
6849 ARG_HELP = 0x100,
514f4ef5 6850 ARG_NO_WALL
e4b61340
LP
6851 };
6852
6853 static const struct option options[] = {
6854 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 6855 { "no-wall", no_argument, NULL, ARG_NO_WALL },
eb9da376 6856 {}
e4b61340
LP
6857 };
6858
6859 static const struct {
6860 char from;
6861 enum action to;
6862 } table[] = {
6863 { '0', ACTION_POWEROFF },
6864 { '6', ACTION_REBOOT },
ef2f1067 6865 { '1', ACTION_RESCUE },
e4b61340
LP
6866 { '2', ACTION_RUNLEVEL2 },
6867 { '3', ACTION_RUNLEVEL3 },
6868 { '4', ACTION_RUNLEVEL4 },
6869 { '5', ACTION_RUNLEVEL5 },
6870 { 's', ACTION_RESCUE },
6871 { 'S', ACTION_RESCUE },
6872 { 'q', ACTION_RELOAD },
6873 { 'Q', ACTION_RELOAD },
6874 { 'u', ACTION_REEXEC },
6875 { 'U', ACTION_REEXEC }
6876 };
6877
6878 unsigned i;
6879 int c;
6880
6881 assert(argc >= 0);
6882 assert(argv);
6883
601185b4 6884 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6885 switch (c) {
6886
6887 case ARG_HELP:
601185b4
ZJS
6888 telinit_help();
6889 return 0;
e4b61340 6890
514f4ef5
LP
6891 case ARG_NO_WALL:
6892 arg_no_wall = true;
6893 break;
6894
e4b61340
LP
6895 case '?':
6896 return -EINVAL;
6897
6898 default:
eb9da376 6899 assert_not_reached("Unhandled option");
e4b61340 6900 }
e4b61340
LP
6901
6902 if (optind >= argc) {
601185b4
ZJS
6903 log_error("%s: required argument missing.",
6904 program_invocation_short_name);
e4b61340
LP
6905 return -EINVAL;
6906 }
6907
6908 if (optind + 1 < argc) {
6909 log_error("Too many arguments.");
6910 return -EINVAL;
6911 }
6912
6913 if (strlen(argv[optind]) != 1) {
6914 log_error("Expected single character argument.");
6915 return -EINVAL;
6916 }
6917
6918 for (i = 0; i < ELEMENTSOF(table); i++)
6919 if (table[i].from == argv[optind][0])
6920 break;
6921
6922 if (i >= ELEMENTSOF(table)) {
b0193f1c 6923 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
6924 return -EINVAL;
6925 }
6926
6927 arg_action = table[i].to;
6928
6929 optind ++;
6930
6931 return 1;
6932}
6933
6934static int runlevel_parse_argv(int argc, char *argv[]) {
6935
6936 enum {
6937 ARG_HELP = 0x100,
6938 };
6939
6940 static const struct option options[] = {
6941 { "help", no_argument, NULL, ARG_HELP },
eb9da376 6942 {}
e4b61340
LP
6943 };
6944
6945 int c;
6946
6947 assert(argc >= 0);
6948 assert(argv);
6949
601185b4 6950 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
e4b61340
LP
6951 switch (c) {
6952
6953 case ARG_HELP:
601185b4
ZJS
6954 runlevel_help();
6955 return 0;
e4b61340
LP
6956
6957 case '?':
6958 return -EINVAL;
6959
6960 default:
eb9da376 6961 assert_not_reached("Unhandled option");
e4b61340 6962 }
e4b61340
LP
6963
6964 if (optind < argc) {
6965 log_error("Too many arguments.");
6966 return -EINVAL;
6967 }
6968
6969 return 1;
6970}
6971
6972static int parse_argv(int argc, char *argv[]) {
6973 assert(argc >= 0);
6974 assert(argv);
6975
6976 if (program_invocation_short_name) {
6977
6978 if (strstr(program_invocation_short_name, "halt")) {
6979 arg_action = ACTION_HALT;
6980 return halt_parse_argv(argc, argv);
6981 } else if (strstr(program_invocation_short_name, "poweroff")) {
6982 arg_action = ACTION_POWEROFF;
6983 return halt_parse_argv(argc, argv);
6984 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
6985 if (kexec_loaded())
6986 arg_action = ACTION_KEXEC;
6987 else
6988 arg_action = ACTION_REBOOT;
e4b61340
LP
6989 return halt_parse_argv(argc, argv);
6990 } else if (strstr(program_invocation_short_name, "shutdown")) {
6991 arg_action = ACTION_POWEROFF;
6992 return shutdown_parse_argv(argc, argv);
6993 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
6994
6995 if (sd_booted() > 0) {
f459b602 6996 arg_action = _ACTION_INVALID;
d5ca5f11
LP
6997 return telinit_parse_argv(argc, argv);
6998 } else {
6999 /* Hmm, so some other init system is
7000 * running, we need to forward this
7001 * request to it. For now we simply
7002 * guess that it is Upstart. */
7003
4ad61fd1 7004 execv(TELINIT, argv);
d5ca5f11
LP
7005
7006 log_error("Couldn't find an alternative telinit implementation to spawn.");
7007 return -EIO;
7008 }
7009
e4b61340
LP
7010 } else if (strstr(program_invocation_short_name, "runlevel")) {
7011 arg_action = ACTION_RUNLEVEL;
7012 return runlevel_parse_argv(argc, argv);
7013 }
7014 }
7015
7016 arg_action = ACTION_SYSTEMCTL;
7017 return systemctl_parse_argv(argc, argv);
7018}
7019
44a6b1b6 7020_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
7021
7022 static const char table[_ACTION_MAX] = {
7023 [ACTION_HALT] = '0',
7024 [ACTION_POWEROFF] = '0',
7025 [ACTION_REBOOT] = '6',
7026 [ACTION_RUNLEVEL2] = '2',
7027 [ACTION_RUNLEVEL3] = '3',
7028 [ACTION_RUNLEVEL4] = '4',
7029 [ACTION_RUNLEVEL5] = '5',
7030 [ACTION_RESCUE] = '1'
7031 };
7032
d55ae9e6
LP
7033 assert(arg_action < _ACTION_MAX);
7034
7035 return table[arg_action];
7036}
7037
d55ae9e6 7038static int talk_initctl(void) {
cbc9fbd1
LP
7039
7040 struct init_request request = {
7041 .magic = INIT_MAGIC,
7042 .sleeptime = 0,
7043 .cmd = INIT_CMD_RUNLVL
7044 };
7045
7fd1b19b 7046 _cleanup_close_ int fd = -1;
d55ae9e6 7047 char rl;
cbc9fbd1 7048 int r;
eb22ac37 7049
427b47c4
ZJS
7050 rl = action_to_runlevel();
7051 if (!rl)
eb22ac37
LP
7052 return 0;
7053
d55ae9e6
LP
7054 request.runlevel = rl;
7055
427b47c4
ZJS
7056 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
7057 if (fd < 0) {
d55ae9e6
LP
7058 if (errno == ENOENT)
7059 return 0;
eb22ac37 7060
56f64d95 7061 log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
eb22ac37 7062 return -errno;
d55ae9e6 7063 }
eb22ac37 7064
553acb7b
ZJS
7065 r = loop_write(fd, &request, sizeof(request), false);
7066 if (r < 0)
7067 return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
eb22ac37
LP
7068
7069 return 1;
e4b61340
LP
7070}
7071
41dd15e4 7072static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
7e4249b9 7073
7e4249b9
LP
7074 static const struct {
7075 const char* verb;
7076 const enum {
7077 MORE,
7078 LESS,
7079 EQUAL
7080 } argc_cmp;
7081 const int argc;
f459b602 7082 int (* const dispatch)(sd_bus *bus, char **args);
d08e75ed
ZJS
7083 const enum {
7084 NOBUS = 1,
7085 FORCE,
7086 } bus;
7e4249b9 7087 } verbs[] = {
d8fba7c6 7088 { "list-units", MORE, 0, list_units },
d08e75ed 7089 { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
d8fba7c6
ZJS
7090 { "list-sockets", MORE, 1, list_sockets },
7091 { "list-timers", MORE, 1, list_timers },
7092 { "list-jobs", MORE, 1, list_jobs },
0d292f5e 7093 { "list-machines", MORE, 1, list_machines },
ee5762e3 7094 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
7095 { "cancel", MORE, 2, cancel_job },
7096 { "start", MORE, 2, start_unit },
7097 { "stop", MORE, 2, start_unit },
a76f7be2 7098 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7099 { "reload", MORE, 2, start_unit },
7100 { "restart", MORE, 2, start_unit },
7101 { "try-restart", MORE, 2, start_unit },
7102 { "reload-or-restart", MORE, 2, start_unit },
7103 { "reload-or-try-restart", MORE, 2, start_unit },
7104 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 7105 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
7106 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
7107 { "isolate", EQUAL, 2, start_unit },
8a0867d6 7108 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
7109 { "is-active", MORE, 2, check_unit_active },
7110 { "check", MORE, 2, check_unit_active },
7111 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 7112 { "show", MORE, 1, show },
ad2a0358 7113 { "cat", MORE, 2, cat, NOBUS },
265a7a2a 7114 { "status", MORE, 1, show },
b43f208f 7115 { "help", MORE, 2, show },
ee5762e3
LP
7116 { "snapshot", LESS, 2, snapshot },
7117 { "delete", MORE, 2, delete_snapshot },
7118 { "daemon-reload", EQUAL, 1, daemon_reload },
7119 { "daemon-reexec", EQUAL, 1, daemon_reload },
f459b602 7120 { "show-environment", EQUAL, 1, show_environment },
ee5762e3
LP
7121 { "set-environment", MORE, 2, set_environment },
7122 { "unset-environment", MORE, 2, set_environment },
ac3efa8a 7123 { "import-environment", MORE, 1, import_environment},
d08e75ed
ZJS
7124 { "halt", EQUAL, 1, start_special, FORCE },
7125 { "poweroff", EQUAL, 1, start_special, FORCE },
b986229e 7126 { "reboot", MORE, 1, start_special, FORCE },
20b09ca7 7127 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
7128 { "suspend", EQUAL, 1, start_special },
7129 { "hibernate", EQUAL, 1, start_special },
6524990f 7130 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
7131 { "default", EQUAL, 1, start_special },
7132 { "rescue", EQUAL, 1, start_special },
7133 { "emergency", EQUAL, 1, start_special },
20b09ca7 7134 { "exit", EQUAL, 1, start_special },
fdf20a31 7135 { "reset-failed", MORE, 1, reset_failed },
d08e75ed
ZJS
7136 { "enable", MORE, 2, enable_unit, NOBUS },
7137 { "disable", MORE, 2, enable_unit, NOBUS },
7138 { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
7139 { "reenable", MORE, 2, enable_unit, NOBUS },
7140 { "preset", MORE, 2, enable_unit, NOBUS },
d309c1c3 7141 { "preset-all", EQUAL, 1, preset_all, NOBUS },
d08e75ed
ZJS
7142 { "mask", MORE, 2, enable_unit, NOBUS },
7143 { "unmask", MORE, 2, enable_unit, NOBUS },
7144 { "link", MORE, 2, enable_unit, NOBUS },
957eb8ca 7145 { "switch-root", MORE, 2, switch_root },
e31165b2 7146 { "list-dependencies", LESS, 2, list_dependencies },
d08e75ed
ZJS
7147 { "set-default", EQUAL, 2, set_default, NOBUS },
7148 { "get-default", EQUAL, 1, get_default, NOBUS },
8e2af478 7149 { "set-property", MORE, 3, set_property },
99813a19 7150 { "is-system-running", EQUAL, 1, is_system_running },
7d4fb3b1
RC
7151 { "add-wants", MORE, 3, add_dependency, NOBUS },
7152 { "add-requires", MORE, 3, add_dependency, NOBUS },
7153 { "edit", MORE, 2, edit, NOBUS },
d08e75ed
ZJS
7154 {}
7155 }, *verb = verbs;
7e4249b9 7156
e4b61340 7157 int left;
7e4249b9 7158
e4b61340
LP
7159 assert(argc >= 0);
7160 assert(argv);
7e4249b9
LP
7161
7162 left = argc - optind;
7163
d08e75ed
ZJS
7164 /* Special rule: no arguments (left == 0) means "list-units" */
7165 if (left > 0) {
b43f208f
KS
7166 if (streq(argv[optind], "help") && !argv[optind+1]) {
7167 log_error("This command expects one or more "
7168 "unit names. Did you mean --help?");
7169 return -EINVAL;
0183528f
LP
7170 }
7171
d08e75ed
ZJS
7172 for (; verb->verb; verb++)
7173 if (streq(argv[optind], verb->verb))
7174 goto found;
7e4249b9 7175
d08e75ed
ZJS
7176 log_error("Unknown operation '%s'.", argv[optind]);
7177 return -EINVAL;
7e4249b9 7178 }
d08e75ed 7179found:
7e4249b9 7180
d08e75ed 7181 switch (verb->argc_cmp) {
7e4249b9
LP
7182
7183 case EQUAL:
d08e75ed 7184 if (left != verb->argc) {
7e4249b9 7185 log_error("Invalid number of arguments.");
e4b61340 7186 return -EINVAL;
7e4249b9
LP
7187 }
7188
7189 break;
7190
7191 case MORE:
d08e75ed 7192 if (left < verb->argc) {
7e4249b9 7193 log_error("Too few arguments.");
e4b61340 7194 return -EINVAL;
7e4249b9
LP
7195 }
7196
7197 break;
7198
7199 case LESS:
d08e75ed 7200 if (left > verb->argc) {
7e4249b9 7201 log_error("Too many arguments.");
e4b61340 7202 return -EINVAL;
7e4249b9
LP
7203 }
7204
7205 break;
7206
7207 default:
7208 assert_not_reached("Unknown comparison operator.");
7209 }
7210
ee5762e3
LP
7211 /* Require a bus connection for all operations but
7212 * enable/disable */
d08e75ed
ZJS
7213 if (verb->bus == NOBUS) {
7214 if (!bus && !avoid_bus()) {
da927ba9 7215 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
d08e75ed
ZJS
7216 return -EIO;
7217 }
82e23ddd 7218
d08e75ed 7219 } else {
82e23ddd
LP
7220 if (running_in_chroot() > 0) {
7221 log_info("Running in chroot, ignoring request.");
7222 return 0;
7223 }
7224
d08e75ed 7225 if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
da927ba9 7226 log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
82e23ddd
LP
7227 return -EIO;
7228 }
ee5762e3
LP
7229 }
7230
d08e75ed 7231 return verb->dispatch(bus, argv + optind);
e4b61340
LP
7232}
7233
f459b602 7234static int reload_with_fallback(sd_bus *bus) {
e4b61340
LP
7235
7236 if (bus) {
7237 /* First, try systemd via D-Bus. */
d76702a7 7238 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
7239 return 0;
7240 }
7241
7242 /* Nothing else worked, so let's try signals */
7243 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
7244
4a62c710
MS
7245 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
7246 return log_error_errno(errno, "kill() failed: %m");
e4b61340
LP
7247
7248 return 0;
7249}
7250
f459b602 7251static int start_with_fallback(sd_bus *bus) {
e4b61340
LP
7252
7253 if (bus) {
7254 /* First, try systemd via D-Bus. */
729e3769 7255 if (start_unit(bus, NULL) >= 0)
983d9c90 7256 goto done;
e4b61340
LP
7257 }
7258
7259 /* Nothing else worked, so let's try
7260 * /dev/initctl */
fbc43921 7261 if (talk_initctl() > 0)
983d9c90 7262 goto done;
d55ae9e6
LP
7263
7264 log_error("Failed to talk to init daemon.");
7265 return -EIO;
983d9c90
LP
7266
7267done:
7268 warn_wall(arg_action);
7269 return 0;
e4b61340
LP
7270}
7271
477def80 7272static int halt_now(enum action a) {
e606bb61 7273
4a3ad399
LP
7274 /* The kernel will automaticall flush ATA disks and suchlike
7275 * on reboot(), but the file systems need to be synce'd
7276 * explicitly in advance. */
7277 sync();
7278
7279 /* Make sure C-A-D is handled by the kernel from this point
7280 * on... */
e606bb61
LP
7281 reboot(RB_ENABLE_CAD);
7282
4c80c73c 7283 switch (a) {
e606bb61
LP
7284
7285 case ACTION_HALT:
7286 log_info("Halting.");
7287 reboot(RB_HALT_SYSTEM);
477def80 7288 return -errno;
e606bb61
LP
7289
7290 case ACTION_POWEROFF:
7291 log_info("Powering off.");
7292 reboot(RB_POWER_OFF);
477def80 7293 return -errno;
e606bb61 7294
477def80
LP
7295 case ACTION_REBOOT: {
7296 _cleanup_free_ char *param = NULL;
cbc9fbd1 7297
477def80
LP
7298 if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
7299 log_info("Rebooting with argument '%s'.", param);
37185ec8
WC
7300 syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
7301 LINUX_REBOOT_CMD_RESTART2, param);
37185ec8 7302 }
e606bb61 7303
477def80
LP
7304 log_info("Rebooting.");
7305 reboot(RB_AUTOBOOT);
7306 return -errno;
e606bb61
LP
7307 }
7308
477def80
LP
7309 default:
7310 assert_not_reached("Unknown action.");
7311 }
e606bb61
LP
7312}
7313
f459b602 7314static int halt_main(sd_bus *bus) {
e4b61340
LP
7315 int r;
7316
748ebafa
LP
7317 r = check_inhibitors(bus, arg_action);
7318 if (r < 0)
7319 return r;
b37844d3 7320
bc8c2f5c 7321 if (geteuid() != 0) {
7e59bfcb
LP
7322 /* Try logind if we are a normal user and no special
7323 * mode applies. Maybe PolicyKit allows us to shutdown
7324 * the machine. */
7325
7326 if (arg_when <= 0 &&
7327 !arg_dry &&
b37844d3 7328 arg_force <= 0 &&
7e59bfcb
LP
7329 (arg_action == ACTION_POWEROFF ||
7330 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
7331 r = reboot_with_logind(bus, arg_action);
7332 if (r >= 0)
7333 return r;
7334 }
7335
cc8a7a61 7336 log_error("Must be root.");
bc8c2f5c
LP
7337 return -EPERM;
7338 }
7339
f6144808 7340 if (arg_when > 0) {
f0efea23 7341 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
03976f7b 7342 _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
cafbecf3 7343 _cleanup_free_ char *m = NULL;
9be9828c 7344
f0efea23
DM
7345 if (avoid_bus()) {
7346 log_error("Unable to perform operation without bus connection.");
7347 return -ENOSYS;
7348 }
7349
7350 r = sd_bus_open_system(&b);
7351 if (r < 0)
d3a2a053 7352 return log_error_errno(r, "Unable to open system bus: %m");
f0efea23 7353
9be9828c 7354 m = strv_join(arg_wall, " ");
cbc9fbd1
LP
7355 if (!m)
7356 return log_oom();
7357
f0efea23
DM
7358 r = sd_bus_set_property(
7359 b,
7360 "org.freedesktop.login1",
7361 "/org/freedesktop/login1",
7362 "org.freedesktop.login1.Manager",
7363 "WallMessage",
7364 &error,
7365 "s", m);
7366 if (r < 0) {
7367 log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
7368 bus_error_message(&error, r));
7369 sd_bus_error_free(&error);
7370 }
7371
7372 r = sd_bus_set_property(
7373 b,
7374 "org.freedesktop.login1",
7375 "/org/freedesktop/login1",
7376 "org.freedesktop.login1.Manager",
7377 "EnableWallMessages",
7378 &error,
7379 "b", !arg_no_wall);
7380 if (r < 0) {
7381 log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
7382 bus_error_message(&error, r));
7383 sd_bus_error_free(&error);
7384 }
9be9828c 7385
f0efea23
DM
7386 r = sd_bus_call_method(
7387 b,
7388 "org.freedesktop.login1",
7389 "/org/freedesktop/login1",
7390 "org.freedesktop.login1.Manager",
7391 "ScheduleShutdown",
7392 &error,
7393 NULL,
7394 "st",
7395 arg_action == ACTION_HALT ? "halt" :
7396 arg_action == ACTION_POWEROFF ? "poweroff" :
7397 arg_action == ACTION_KEXEC ? "kexec" :
7398 "reboot",
7399 arg_when);
9be9828c 7400 if (r < 0)
f0efea23
DM
7401 log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
7402 bus_error_message(&error, r));
08e4b1c5 7403 else {
7e59bfcb
LP
7404 char date[FORMAT_TIMESTAMP_MAX];
7405
08e4b1c5
LP
7406 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
7407 format_timestamp(date, sizeof(date), arg_when));
f6144808 7408 return 0;
08e4b1c5 7409 }
f6144808
LP
7410 }
7411
65491fd8 7412 if (!arg_dry && !arg_force)
e4b61340
LP
7413 return start_with_fallback(bus);
7414
d90e1a30
LP
7415 if (!arg_no_wtmp) {
7416 if (sd_booted() > 0)
7417 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
7418 else {
7419 r = utmp_put_shutdown();
7420 if (r < 0)
da927ba9 7421 log_warning_errno(r, "Failed to write utmp record: %m");
7e59bfcb 7422 }
d90e1a30 7423 }
e4b61340 7424
e4b61340
LP
7425 if (arg_dry)
7426 return 0;
7427
477def80 7428 r = halt_now(arg_action);
da927ba9 7429 log_error_errno(r, "Failed to reboot: %m");
477def80
LP
7430
7431 return r;
e4b61340
LP
7432}
7433
7434static int runlevel_main(void) {
7435 int r, runlevel, previous;
7436
729e3769
LP
7437 r = utmp_get_runlevel(&runlevel, &previous);
7438 if (r < 0) {
7439 puts("unknown");
e4b61340
LP
7440 return r;
7441 }
7442
7443 printf("%c %c\n",
7444 previous <= 0 ? 'N' : previous,
7445 runlevel <= 0 ? 'N' : runlevel);
7446
7447 return 0;
7448}
7449
7450int main(int argc, char*argv[]) {
03976f7b 7451 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
f459b602 7452 int r;
e4b61340 7453
a9cdc94f 7454 setlocale(LC_ALL, "");
e4b61340 7455 log_parse_environment();
2396fb04 7456 log_open();
e4b61340 7457
184ecaf7
DR
7458 /* Explicitly not on_tty() to avoid setting cached value.
7459 * This becomes relevant for piping output which might be
7460 * ellipsized. */
7461 original_stdout_is_tty = isatty(STDOUT_FILENO);
7462
04ebb595 7463 r = parse_argv(argc, argv);
f459b602 7464 if (r <= 0)
e4b61340 7465 goto finish;
7e4249b9 7466
e4b61340
LP
7467 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
7468 * let's shortcut this */
7469 if (arg_action == ACTION_RUNLEVEL) {
22f4096c 7470 r = runlevel_main();
e4b61340
LP
7471 goto finish;
7472 }
7473
82e23ddd
LP
7474 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
7475 log_info("Running in chroot, ignoring request.");
f459b602 7476 r = 0;
82e23ddd
LP
7477 goto finish;
7478 }
7479
41dd15e4
LP
7480 if (!avoid_bus())
7481 r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
7482
6e646d22
LP
7483 if (bus)
7484 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
7485
41dd15e4
LP
7486 /* systemctl_main() will print an error message for the bus
7487 * connection, but only if it needs to */
e4b61340
LP
7488
7489 switch (arg_action) {
7490
22f4096c 7491 case ACTION_SYSTEMCTL:
f459b602 7492 r = systemctl_main(bus, argc, argv, r);
e4b61340 7493 break;
e4b61340
LP
7494
7495 case ACTION_HALT:
7496 case ACTION_POWEROFF:
7497 case ACTION_REBOOT:
5622dde3 7498 case ACTION_KEXEC:
22f4096c 7499 r = halt_main(bus);
e4b61340
LP
7500 break;
7501
e4b61340
LP
7502 case ACTION_RUNLEVEL2:
7503 case ACTION_RUNLEVEL3:
7504 case ACTION_RUNLEVEL4:
7505 case ACTION_RUNLEVEL5:
7506 case ACTION_RESCUE:
514f4ef5 7507 case ACTION_EMERGENCY:
eb22ac37 7508 case ACTION_DEFAULT:
22f4096c 7509 r = start_with_fallback(bus);
e4b61340 7510 break;
7e4249b9 7511
e4b61340
LP
7512 case ACTION_RELOAD:
7513 case ACTION_REEXEC:
22f4096c 7514 r = reload_with_fallback(bus);
e4b61340
LP
7515 break;
7516
dfcc5c33 7517 case ACTION_CANCEL_SHUTDOWN: {
f0efea23 7518 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
03976f7b 7519 _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
f459b602 7520 _cleanup_free_ char *m = NULL;
dfcc5c33 7521
f0efea23
DM
7522 if (avoid_bus()) {
7523 log_error("Unable to perform operation without bus connection.");
7524 return -ENOSYS;
7525 }
7526
7527 r = sd_bus_open_system(&b);
7528 if (r < 0)
d3a2a053 7529 return log_error_errno(r, "Unable to open system bus: %m");
f0efea23 7530
dfcc5c33
MS
7531 if (arg_wall) {
7532 m = strv_join(arg_wall, " ");
7533 if (!m) {
f459b602 7534 r = log_oom();
dfcc5c33
MS
7535 goto finish;
7536 }
7537 }
f459b602 7538
f0efea23
DM
7539 r = sd_bus_set_property(
7540 b,
7541 "org.freedesktop.login1",
7542 "/org/freedesktop/login1",
7543 "org.freedesktop.login1.Manager",
7544 "WallMessage",
7545 &error,
7546 "s", arg_wall);
7547 if (r < 0) {
7548 log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
7549 bus_error_message(&error, r));
7550 sd_bus_error_free(&error);
7551 }
7552
7553 r = sd_bus_set_property(
7554 b,
7555 "org.freedesktop.login1",
7556 "/org/freedesktop/login1",
7557 "org.freedesktop.login1.Manager",
7558 "EnableWallMessages",
7559 &error,
7560 "b", !arg_no_wall);
7561 if (r < 0) {
7562 log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
7563 bus_error_message(&error, r));
7564 sd_bus_error_free(&error);
7565 }
7566
7567 r = sd_bus_call_method(
7568 b,
7569 "org.freedesktop.login1",
7570 "/org/freedesktop/login1",
7571 "org.freedesktop.login1.Manager",
7572 "CancelScheduledShutdown",
7573 &error,
7574 NULL, NULL);
dfcc5c33 7575 if (r < 0)
f0efea23
DM
7576 log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
7577 bus_error_message(&error, r));
f6144808 7578 break;
dfcc5c33 7579 }
f6144808 7580
eb22ac37 7581 case ACTION_RUNLEVEL:
f459b602 7582 case _ACTION_INVALID:
e4b61340
LP
7583 default:
7584 assert_not_reached("Unknown action");
7585 }
7e4249b9
LP
7586
7587finish:
f459b602
MAP
7588 pager_close();
7589 ask_password_agent_close();
7590 polkit_agent_close();
7e4249b9 7591
20b3f379 7592 strv_free(arg_types);
9b9b3d36 7593 strv_free(arg_states);
20b3f379 7594 strv_free(arg_properties);
ea4a240d 7595
f459b602 7596 return r < 0 ? EXIT_FAILURE : r;
7e4249b9 7597}