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