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