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