]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
NEWS: add some clarifications
[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
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
7e4249b9
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
7e4249b9 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
7e4249b9
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
e4b61340 22#include <sys/reboot.h>
7e4249b9
LP
23#include <stdio.h>
24#include <getopt.h>
a9cdc94f 25#include <locale.h>
7e4249b9
LP
26#include <stdbool.h>
27#include <string.h>
28#include <errno.h>
29#include <sys/ioctl.h>
30#include <termios.h>
31#include <unistd.h>
eb22ac37 32#include <fcntl.h>
f1c5860b 33#include <sys/socket.h>
ee5762e3 34#include <sys/stat.h>
0e098b15 35#include <stddef.h>
501fc174 36#include <sys/prctl.h>
7e4249b9
LP
37#include <dbus/dbus.h>
38
81527be1 39#include <systemd/sd-daemon.h>
04ebb595 40#include <systemd/sd-shutdown.h>
59164be4 41#include <systemd/sd-login.h>
81527be1 42
7e4249b9
LP
43#include "log.h"
44#include "util.h"
45#include "macro.h"
46#include "set.h"
e4b61340 47#include "utmp-wtmp.h"
514f4ef5 48#include "special.h"
eb22ac37 49#include "initreq.h"
9eb977db 50#include "path-util.h"
e4a9373f 51#include "strv.h"
9a1ac7b9 52#include "dbus-common.h"
ab35fb1b 53#include "cgroup-show.h"
c6c18be3 54#include "cgroup-util.h"
582a507f 55#include "list.h"
ee5762e3
LP
56#include "path-lookup.h"
57#include "conf-parser.h"
d06dacd0 58#include "exit-status.h"
22f4096c 59#include "bus-errors.h"
7d568925 60#include "build.h"
71fad675 61#include "unit-name.h"
1968a360 62#include "pager.h"
6bb92a16
LP
63#include "spawn-ask-password-agent.h"
64#include "spawn-polkit-agent.h"
729e3769 65#include "install.h"
86aa7ba4 66#include "logs-show.h"
9eb977db 67#include "path-util.h"
67445f4e 68#include "socket-util.h"
a5c32cff 69#include "fileio.h"
7e4249b9 70
20b3f379 71static char **arg_types = NULL;
9b9b3d36 72static char **arg_states = NULL;
20b3f379 73static char **arg_properties = NULL;
7e4249b9 74static bool arg_all = false;
afba4199
ZJS
75static enum dependency {
76 DEPENDENCY_FORWARD,
77 DEPENDENCY_REVERSE,
78 DEPENDENCY_AFTER,
79 DEPENDENCY_BEFORE,
80} arg_dependency = DEPENDENCY_FORWARD;
e67c3609 81static const char *arg_job_mode = "replace";
729e3769 82static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
ee5762e3 83static bool arg_no_block = false;
ebed32bf 84static bool arg_no_legend = false;
0736af98 85static bool arg_no_pager = false;
e4b61340 86static bool arg_no_wtmp = false;
514f4ef5 87static bool arg_no_wall = false;
ee5762e3 88static bool arg_no_reload = false;
991f2a39 89static bool arg_show_types = false;
b37844d3 90static bool arg_ignore_inhibitors = false;
e4b61340 91static bool arg_dry = false;
0183528f 92static bool arg_quiet = false;
ee5762e3 93static bool arg_full = false;
e606bb61 94static int arg_force = 0;
6bb92a16 95static bool arg_ask_password = true;
729e3769 96static bool arg_runtime = false;
e4b61340 97static char **arg_wall = NULL;
8a0867d6 98static const char *arg_kill_who = NULL;
8a0867d6 99static int arg_signal = SIGTERM;
69fc152f 100static const char *arg_root = NULL;
f6144808 101static usec_t arg_when = 0;
4445a875 102static enum action {
e4b61340
LP
103 ACTION_INVALID,
104 ACTION_SYSTEMCTL,
105 ACTION_HALT,
106 ACTION_POWEROFF,
107 ACTION_REBOOT,
20b09ca7
LP
108 ACTION_KEXEC,
109 ACTION_EXIT,
6edd7d0a
LP
110 ACTION_SUSPEND,
111 ACTION_HIBERNATE,
6524990f 112 ACTION_HYBRID_SLEEP,
e4b61340
LP
113 ACTION_RUNLEVEL2,
114 ACTION_RUNLEVEL3,
115 ACTION_RUNLEVEL4,
116 ACTION_RUNLEVEL5,
117 ACTION_RESCUE,
514f4ef5
LP
118 ACTION_EMERGENCY,
119 ACTION_DEFAULT,
e4b61340
LP
120 ACTION_RELOAD,
121 ACTION_REEXEC,
122 ACTION_RUNLEVEL,
f6144808 123 ACTION_CANCEL_SHUTDOWN,
e4b61340
LP
124 _ACTION_MAX
125} arg_action = ACTION_SYSTEMCTL;
a8f11321
LP
126static enum transport {
127 TRANSPORT_NORMAL,
128 TRANSPORT_SSH,
129 TRANSPORT_POLKIT
130} arg_transport = TRANSPORT_NORMAL;
7085053a
DW
131static char *arg_host = NULL;
132static char *arg_user = NULL;
df50185b
LP
133static unsigned arg_lines = 10;
134static OutputMode arg_output = OUTPUT_SHORT;
5d0c05e5 135static bool arg_plain = false;
e4b61340 136
f4579ce7
LP
137static bool private_bus = false;
138
729e3769 139static int daemon_reload(DBusConnection *bus, char **args);
4c80c73c 140static void halt_now(enum action a);
1968a360 141
3b0727f5 142static void pager_open_if_enabled(void) {
f8440af5 143
729e3769
LP
144 if (arg_no_pager)
145 return;
3b0727f5 146
1b12a7b5 147 pager_open(false);
729e3769 148}
c0f9c7da 149
6bb92a16 150static void ask_password_agent_open_if_enabled(void) {
501fc174 151
729e3769 152 /* Open the password agent as a child process if necessary */
501fc174
LP
153
154 if (!arg_ask_password)
155 return;
715554e7 156
729e3769 157 if (arg_scope != UNIT_FILE_SYSTEM)
501fc174
LP
158 return;
159
6bb92a16
LP
160 ask_password_agent_open();
161}
162
ba1261bc 163#ifdef HAVE_LOGIND
6bb92a16
LP
164static void polkit_agent_open_if_enabled(void) {
165
166 /* Open the polkit agent as a child process if necessary */
167
168 if (!arg_ask_password)
169 return;
170
171 if (arg_scope != UNIT_FILE_SYSTEM)
172 return;
173
174 polkit_agent_open();
501fc174 175}
ba1261bc 176#endif
501fc174 177
22f4096c
LP
178static int translate_bus_error_to_exit_status(int r, const DBusError *error) {
179 assert(error);
180
181 if (!dbus_error_is_set(error))
182 return r;
183
184 if (dbus_error_has_name(error, DBUS_ERROR_ACCESS_DENIED) ||
185 dbus_error_has_name(error, BUS_ERROR_ONLY_BY_DEPENDENCY) ||
186 dbus_error_has_name(error, BUS_ERROR_NO_ISOLATION) ||
187 dbus_error_has_name(error, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE))
188 return EXIT_NOPERMISSION;
189
190 if (dbus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT))
191 return EXIT_NOTINSTALLED;
192
193 if (dbus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE) ||
194 dbus_error_has_name(error, BUS_ERROR_NOT_SUPPORTED))
195 return EXIT_NOTIMPLEMENTED;
196
197 if (dbus_error_has_name(error, BUS_ERROR_LOAD_FAILED))
198 return EXIT_NOTCONFIGURED;
199
200 if (r != 0)
201 return r;
202
203 return EXIT_FAILURE;
204}
205
4c80c73c 206static void warn_wall(enum action a) {
ef2f1067 207 static const char *table[_ACTION_MAX] = {
dfcc5c33
MS
208 [ACTION_HALT] = "The system is going down for system halt NOW!",
209 [ACTION_REBOOT] = "The system is going down for reboot NOW!",
210 [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
211 [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
212 [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
213 [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
214 [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
ef2f1067
LP
215 };
216
514f4ef5
LP
217 if (arg_no_wall)
218 return;
219
e4a9373f 220 if (arg_wall) {
f84190d8 221 _cleanup_free_ char *p;
e4a9373f 222
7e59bfcb
LP
223 p = strv_join(arg_wall, " ");
224 if (!p) {
f84190d8 225 log_oom();
e4a9373f
LP
226 return;
227 }
228
229 if (*p) {
7af53310 230 utmp_wall(p, NULL);
e4a9373f
LP
231 return;
232 }
e4a9373f
LP
233 }
234
4c80c73c 235 if (!table[a])
ef2f1067
LP
236 return;
237
4c80c73c 238 utmp_wall(table[a], NULL);
ef2f1067
LP
239}
240
729e3769
LP
241static bool avoid_bus(void) {
242
243 if (running_in_chroot() > 0)
244 return true;
245
246 if (sd_booted() <= 0)
247 return true;
248
249 if (!isempty(arg_root))
250 return true;
251
252 if (arg_scope == UNIT_FILE_GLOBAL)
253 return true;
254
255 return false;
256}
257
36c32ba2
LP
258static int compare_unit_info(const void *a, const void *b) {
259 const char *d1, *d2;
260 const struct unit_info *u = a, *v = b;
261
262 d1 = strrchr(u->id, '.');
263 d2 = strrchr(v->id, '.');
264
265 if (d1 && d2) {
266 int r;
267
f84190d8
LP
268 r = strcasecmp(d1, d2);
269 if (r != 0)
36c32ba2
LP
270 return r;
271 }
272
a2a3a5b9 273 return strcasecmp(u->id, v->id);
36c32ba2
LP
274}
275
30732560 276static bool output_show_unit(const struct unit_info *u) {
33330222 277 const char *dot;
b036fc00 278
9b9b3d36
MW
279 if (!strv_isempty(arg_states))
280 return strv_contains(arg_states, u->load_state) || strv_contains(arg_states, u->sub_state) || strv_contains(arg_states, u->active_state);
30732560 281
20b3f379
ZJS
282 return (!arg_types || ((dot = strrchr(u->id, '.')) &&
283 strv_find(arg_types, dot+1))) &&
c147dc42
ZJS
284 (arg_all || !(streq(u->active_state, "inactive")
285 || u->following[0]) || u->job_id > 0);
33330222
ZJS
286}
287
eb68c413 288static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
4deb3b93 289 unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
b036fc00 290 const struct unit_info *u;
ccd41387 291 int job_count = 0;
33330222 292
4deb3b93 293 max_id_len = sizeof("UNIT")-1;
b036fc00
LP
294 active_len = sizeof("ACTIVE")-1;
295 sub_len = sizeof("SUB")-1;
296 job_len = sizeof("JOB")-1;
4deb3b93 297 desc_len = 0;
b036fc00
LP
298
299 for (u = unit_infos; u < unit_infos + c; u++) {
30732560 300 if (!output_show_unit(u))
b036fc00
LP
301 continue;
302
4deb3b93 303 max_id_len = MAX(max_id_len, strlen(u->id));
b036fc00
LP
304 active_len = MAX(active_len, strlen(u->active_state));
305 sub_len = MAX(sub_len, strlen(u->sub_state));
ccd41387 306 if (u->job_id != 0) {
b036fc00 307 job_len = MAX(job_len, strlen(u->job_type));
ccd41387
ZJS
308 job_count++;
309 }
33330222
ZJS
310 }
311
4deb3b93
MS
312 if (!arg_full) {
313 unsigned basic_len;
9607d947 314 id_len = MIN(max_id_len, 25u);
ccd41387
ZJS
315 basic_len = 5 + id_len + 5 + active_len + sub_len;
316 if (job_count)
317 basic_len += job_len + 1;
4deb3b93
MS
318 if (basic_len < (unsigned) columns()) {
319 unsigned extra_len, incr;
320 extra_len = columns() - basic_len;
321 /* Either UNIT already got 25, or is fully satisfied.
322 * Grant up to 25 to DESC now. */
9607d947 323 incr = MIN(extra_len, 25u);
4deb3b93
MS
324 desc_len += incr;
325 extra_len -= incr;
326 /* split the remaining space between UNIT and DESC,
327 * but do not give UNIT more than it needs. */
328 if (extra_len > 0) {
329 incr = MIN(extra_len / 2, max_id_len - id_len);
330 id_len += incr;
331 desc_len += extra_len - incr;
332 }
333 }
334 } else
335 id_len = max_id_len;
336
b036fc00 337 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 338 _cleanup_free_ char *e = NULL;
0ad4e1a8
ZJS
339 const char *on_loaded, *off_loaded, *on = "";
340 const char *on_active, *off_active, *off = "";
b036fc00 341
30732560 342 if (!output_show_unit(u))
b036fc00
LP
343 continue;
344
ad94ad63 345 if (!n_shown && !arg_no_legend) {
ccd41387
ZJS
346 printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
347 active_len, "ACTIVE", sub_len, "SUB");
348 if (job_count)
349 printf("%-*s ", job_len, "JOB");
ad94ad63
ZJS
350 if (!arg_full && arg_no_pager)
351 printf("%.*s\n", desc_len, "DESCRIPTION");
352 else
353 printf("%s\n", "DESCRIPTION");
354 }
355
688c6725
LP
356 n_shown++;
357
2ce982f9
LP
358 if (streq(u->load_state, "error") ||
359 streq(u->load_state, "not-found")) {
0b5a519c
DS
360 on_loaded = on = ansi_highlight_red();
361 off_loaded = off = ansi_highlight_off();
b036fc00
LP
362 } else
363 on_loaded = off_loaded = "";
364
365 if (streq(u->active_state, "failed")) {
0b5a519c
DS
366 on_active = on = ansi_highlight_red();
367 off_active = off = ansi_highlight_off();
b036fc00
LP
368 } else
369 on_active = off_active = "";
eb68c413 370
4deb3b93 371 e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
eb68c413 372
0ad4e1a8
ZJS
373 printf("%s%-*s%s %s%-6s%s %s%-*s %-*s%s %-*s",
374 on, id_len, e ? e : u->id, off,
b036fc00
LP
375 on_loaded, u->load_state, off_loaded,
376 on_active, active_len, u->active_state,
377 sub_len, u->sub_state, off_active,
ccd41387 378 job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
798e258d
MS
379 if (!arg_full && arg_no_pager)
380 printf("%.*s\n", desc_len, u->description);
381 else
382 printf("%s\n", u->description);
eb68c413
ZJS
383 }
384
ebed32bf 385 if (!arg_no_legend) {
57f7ae4f
ZJS
386 const char *on, *off;
387
388 if (n_shown) {
ad94ad63
ZJS
389 printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
390 "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
ccd41387
ZJS
391 "SUB = The low-level unit activation state, values depend on unit type.\n");
392 if (job_count)
393 printf("JOB = Pending job for the unit.\n");
48c2826b 394 puts("");
0b5a519c
DS
395 on = ansi_highlight();
396 off = ansi_highlight_off();
57f7ae4f 397 } else {
0b5a519c
DS
398 on = ansi_highlight_red();
399 off = ansi_highlight_off();
57f7ae4f 400 }
eb68c413
ZJS
401
402 if (arg_all)
48c2826b 403 printf("%s%u loaded units listed.%s\n"
57f7ae4f
ZJS
404 "To show all installed unit files use 'systemctl list-unit-files'.\n",
405 on, n_shown, off);
eb68c413 406 else
48c2826b 407 printf("%s%u loaded units listed.%s Pass --all to see loaded but inactive units, too.\n"
57f7ae4f
ZJS
408 "To show all installed unit files use 'systemctl list-unit-files'.\n",
409 on, n_shown, off);
eb68c413
ZJS
410 }
411}
412
a00963a2
LP
413static int get_unit_list(
414 DBusConnection *bus,
415 DBusMessage **reply,
416 struct unit_info **unit_infos,
417 unsigned *c) {
418
a38694df 419 DBusMessageIter iter, sub;
991f2a39 420 size_t size = 0;
f84190d8 421 int r;
7e4249b9 422
265a7a2a
ZJS
423 assert(bus);
424 assert(unit_infos);
425 assert(c);
ec14911e 426
f84190d8 427 r = bus_method_call_with_reply(
f22f08cd
SP
428 bus,
429 "org.freedesktop.systemd1",
430 "/org/freedesktop/systemd1",
431 "org.freedesktop.systemd1.Manager",
432 "ListUnits",
265a7a2a 433 reply,
f22f08cd
SP
434 NULL,
435 DBUS_TYPE_INVALID);
f84190d8
LP
436 if (r < 0)
437 return r;
7e4249b9 438
265a7a2a 439 if (!dbus_message_iter_init(*reply, &iter) ||
7e4249b9
LP
440 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
441 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
442 log_error("Failed to parse reply.");
f84190d8 443 return -EIO;
7e4249b9
LP
444 }
445
446 dbus_message_iter_recurse(&iter, &sub);
447
7e4249b9 448 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
991f2a39
ZJS
449 if (!GREEDY_REALLOC(*unit_infos, size, *c + 1))
450 return log_oom();
7e4249b9 451
991f2a39
ZJS
452 bus_parse_unit_info(&sub, *unit_infos + *c);
453 (*c)++;
36c32ba2 454
991f2a39
ZJS
455 dbus_message_iter_next(&sub);
456 }
457
458 return 0;
459}
460
461static int list_units(DBusConnection *bus, char **args) {
462 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
463 _cleanup_free_ struct unit_info *unit_infos = NULL;
464 unsigned c = 0;
465 int r;
466
467 pager_open_if_enabled();
468
469 r = get_unit_list(bus, &reply, &unit_infos, &c);
470 if (r < 0)
471 return r;
472
473 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
474
475 output_units_list(unit_infos, c);
476
477 return 0;
478}
479
a00963a2
LP
480static int get_triggered_units(
481 DBusConnection *bus,
482 const char* unit_path,
483 char*** triggered) {
484
991f2a39
ZJS
485 const char *interface = "org.freedesktop.systemd1.Unit",
486 *triggers_property = "Triggers";
7fd1b19b 487 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
991f2a39
ZJS
488 DBusMessageIter iter, sub;
489 int r;
490
491 r = bus_method_call_with_reply(bus,
492 "org.freedesktop.systemd1",
493 unit_path,
494 "org.freedesktop.DBus.Properties",
495 "Get",
496 &reply,
497 NULL,
498 DBUS_TYPE_STRING, &interface,
499 DBUS_TYPE_STRING, &triggers_property,
500 DBUS_TYPE_INVALID);
501 if (r < 0)
502 return r;
503
504 if (!dbus_message_iter_init(reply, &iter) ||
505 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
506 log_error("Failed to parse reply.");
507 return -EBADMSG;
508 }
509
510 dbus_message_iter_recurse(&iter, &sub);
511 dbus_message_iter_recurse(&sub, &iter);
512 sub = iter;
513
514 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
515 const char *unit;
516
517 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
518 log_error("Failed to parse reply.");
519 return -EBADMSG;
520 }
521
522 dbus_message_iter_get_basic(&sub, &unit);
523 r = strv_extend(triggered, unit);
524 if (r < 0)
525 return r;
526
527 dbus_message_iter_next(&sub);
528 }
529
530 return 0;
531}
532
533static int get_listening(DBusConnection *bus, const char* unit_path,
534 char*** listen, unsigned *c)
535{
536 const char *interface = "org.freedesktop.systemd1.Socket",
537 *listen_property = "Listen";
7fd1b19b 538 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
991f2a39
ZJS
539 DBusMessageIter iter, sub;
540 int r;
541
542 r = bus_method_call_with_reply(bus,
543 "org.freedesktop.systemd1",
544 unit_path,
545 "org.freedesktop.DBus.Properties",
546 "Get",
547 &reply,
548 NULL,
549 DBUS_TYPE_STRING, &interface,
550 DBUS_TYPE_STRING, &listen_property,
551 DBUS_TYPE_INVALID);
552 if (r < 0)
553 return r;
554
555 if (!dbus_message_iter_init(reply, &iter) ||
556 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
557 log_error("Failed to parse reply.");
558 return -EBADMSG;
559 }
560
561 dbus_message_iter_recurse(&iter, &sub);
562 dbus_message_iter_recurse(&sub, &iter);
563 sub = iter;
564
565 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
566 DBusMessageIter sub2;
567 const char *type, *path;
36c32ba2 568
991f2a39
ZJS
569 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
570 log_error("Failed to parse reply.");
571 return -EBADMSG;
36c32ba2
LP
572 }
573
991f2a39
ZJS
574 dbus_message_iter_recurse(&sub, &sub2);
575
576 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
577 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
578 r = strv_extend(listen, type);
579 if (r < 0)
580 return r;
36c32ba2 581
991f2a39
ZJS
582 r = strv_extend(listen, path);
583 if (r < 0)
584 return r;
585
586 (*c) ++;
587 }
7e4249b9 588
36c32ba2 589 dbus_message_iter_next(&sub);
36c32ba2
LP
590 }
591
991f2a39
ZJS
592 return 0;
593}
594
595struct socket_info {
596 const char* id;
597
598 char* type;
599 char* path;
600
601 /* Note: triggered is a list here, although it almost certainly
602 * will always be one unit. Nevertheless, dbus API allows for multiple
603 * values, so let's follow that.*/
604 char** triggered;
605
606 /* The strv above is shared. free is set only in the first one. */
607 bool own_triggered;
608};
609
610static int socket_info_compare(struct socket_info *a, struct socket_info *b) {
611 int o = strcmp(a->path, b->path);
612 if (o == 0)
613 o = strcmp(a->type, b->type);
614 return o;
615}
616
617static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
618 struct socket_info *s;
619 unsigned pathlen = sizeof("LISTEN") - 1,
620 typelen = (sizeof("TYPE") - 1) * arg_show_types,
621 socklen = sizeof("UNIT") - 1,
622 servlen = sizeof("ACTIVATES") - 1;
623 const char *on, *off;
624
625 for (s = socket_infos; s < socket_infos + cs; s++) {
626 char **a;
627 unsigned tmp = 0;
628
629 socklen = MAX(socklen, strlen(s->id));
630 if (arg_show_types)
631 typelen = MAX(typelen, strlen(s->type));
632 pathlen = MAX(pathlen, strlen(s->path));
633
634 STRV_FOREACH(a, s->triggered)
635 tmp += strlen(*a) + 2*(a != s->triggered);
636 servlen = MAX(servlen, tmp);
637 }
638
639 if (cs) {
571bfc6c
MM
640 if (!arg_no_legend)
641 printf("%-*s %-*.*s%-*s %s\n",
642 pathlen, "LISTEN",
643 typelen + arg_show_types, typelen + arg_show_types, "TYPE ",
644 socklen, "UNIT",
645 "ACTIVATES");
991f2a39
ZJS
646
647 for (s = socket_infos; s < socket_infos + cs; s++) {
648 char **a;
649
650 if (arg_show_types)
651 printf("%-*s %-*s %-*s",
652 pathlen, s->path, typelen, s->type, socklen, s->id);
653 else
654 printf("%-*s %-*s",
655 pathlen, s->path, socklen, s->id);
656 STRV_FOREACH(a, s->triggered)
657 printf("%s %s",
658 a == s->triggered ? "" : ",", *a);
659 printf("\n");
660 }
661
0b5a519c
DS
662 on = ansi_highlight();
663 off = ansi_highlight_off();
571bfc6c
MM
664 if (!arg_no_legend)
665 printf("\n");
991f2a39 666 } else {
0b5a519c
DS
667 on = ansi_highlight_red();
668 off = ansi_highlight_off();
991f2a39
ZJS
669 }
670
571bfc6c
MM
671 if (!arg_no_legend) {
672 printf("%s%u sockets listed.%s\n", on, cs, off);
673 if (!arg_all)
674 printf("Pass --all to see loaded but inactive sockets, too.\n");
675 }
265a7a2a
ZJS
676
677 return 0;
678}
679
991f2a39 680static int list_sockets(DBusConnection *bus, char **args) {
265a7a2a
ZJS
681 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
682 _cleanup_free_ struct unit_info *unit_infos = NULL;
991f2a39
ZJS
683 struct socket_info *socket_infos = NULL;
684 const struct unit_info *u;
685 struct socket_info *s;
686 unsigned cu = 0, cs = 0;
687 size_t size = 0;
265a7a2a
ZJS
688 int r;
689
690 pager_open_if_enabled();
691
991f2a39 692 r = get_unit_list(bus, &reply, &unit_infos, &cu);
265a7a2a
ZJS
693 if (r < 0)
694 return r;
695
991f2a39
ZJS
696 for (u = unit_infos; u < unit_infos + cu; u++) {
697 const char *dot;
7fd1b19b 698 _cleanup_strv_free_ char **listen = NULL, **triggered = NULL;
991f2a39
ZJS
699 unsigned c = 0, i;
700
701 if (!output_show_unit(u))
702 continue;
703
704 if ((dot = strrchr(u->id, '.')) && !streq(dot+1, "socket"))
705 continue;
706
707 r = get_triggered_units(bus, u->unit_path, &triggered);
708 if (r < 0)
709 goto cleanup;
710
711 r = get_listening(bus, u->unit_path, &listen, &c);
712 if (r < 0)
713 goto cleanup;
714
715 if (!GREEDY_REALLOC(socket_infos, size, cs + c)) {
716 r = log_oom();
717 goto cleanup;
718 }
719
720 for (i = 0; i < c; i++)
721 socket_infos[cs + i] = (struct socket_info) {
722 .id = u->id,
723 .type = listen[i*2],
724 .path = listen[i*2 + 1],
725 .triggered = triggered,
726 .own_triggered = i==0,
727 };
728
729 /* from this point on we will cleanup those socket_infos */
730 cs += c;
731 free(listen);
732 listen = triggered = NULL; /* avoid cleanup */
733 }
734
735 qsort(socket_infos, cs, sizeof(struct socket_info),
736 (__compar_fn_t) socket_info_compare);
737
738 output_sockets_list(socket_infos, cs);
739
740 cleanup:
741 assert(cs == 0 || socket_infos);
742 for (s = socket_infos; s < socket_infos + cs; s++) {
743 free(s->type);
744 free(s->path);
745 if (s->own_triggered)
746 strv_free(s->triggered);
747 }
748 free(socket_infos);
4445a875 749
f84190d8 750 return 0;
4445a875
LP
751}
752
729e3769
LP
753static int compare_unit_file_list(const void *a, const void *b) {
754 const char *d1, *d2;
755 const UnitFileList *u = a, *v = b;
756
757 d1 = strrchr(u->path, '.');
758 d2 = strrchr(v->path, '.');
759
760 if (d1 && d2) {
761 int r;
762
763 r = strcasecmp(d1, d2);
764 if (r != 0)
765 return r;
766 }
767
9eb977db 768 return strcasecmp(path_get_file_name(u->path), path_get_file_name(v->path));
729e3769
LP
769}
770
771static bool output_show_unit_file(const UnitFileList *u) {
772 const char *dot;
773
20b3f379 774 return !arg_types || ((dot = strrchr(u->path, '.')) && strv_find(arg_types, dot+1));
729e3769
LP
775}
776
777static void output_unit_file_list(const UnitFileList *units, unsigned c) {
1c0a113f 778 unsigned max_id_len, id_cols, state_cols, n_shown = 0;
729e3769
LP
779 const UnitFileList *u;
780
1c0a113f
ZJS
781 max_id_len = sizeof("UNIT FILE")-1;
782 state_cols = sizeof("STATE")-1;
783 for (u = units; u < units + c; u++) {
784 if (!output_show_unit_file(u))
785 continue;
786
9eb977db 787 max_id_len = MAX(max_id_len, strlen(path_get_file_name(u->path)));
1c0a113f
ZJS
788 state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
789 }
790
791 if (!arg_full) {
792 unsigned basic_cols;
9607d947 793 id_cols = MIN(max_id_len, 25u);
1c0a113f
ZJS
794 basic_cols = 1 + id_cols + state_cols;
795 if (basic_cols < (unsigned) columns())
796 id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
797 } else
798 id_cols = max_id_len;
799
800 if (!arg_no_legend)
801 printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
729e3769
LP
802
803 for (u = units; u < units + c; u++) {
7fd1b19b 804 _cleanup_free_ char *e = NULL;
729e3769
LP
805 const char *on, *off;
806 const char *id;
807
808 if (!output_show_unit_file(u))
809 continue;
810
811 n_shown++;
812
813 if (u->state == UNIT_FILE_MASKED ||
814 u->state == UNIT_FILE_MASKED_RUNTIME ||
b5b46d59
LP
815 u->state == UNIT_FILE_DISABLED ||
816 u->state == UNIT_FILE_INVALID) {
0b5a519c
DS
817 on = ansi_highlight_red();
818 off = ansi_highlight_off();
729e3769 819 } else if (u->state == UNIT_FILE_ENABLED) {
0b5a519c
DS
820 on = ansi_highlight_green();
821 off = ansi_highlight_off();
729e3769
LP
822 } else
823 on = off = "";
824
9eb977db 825 id = path_get_file_name(u->path);
729e3769 826
1c0a113f 827 e = arg_full ? NULL : ellipsize(id, id_cols, 33);
729e3769 828
1c0a113f
ZJS
829 printf("%-*s %s%-*s%s\n",
830 id_cols, e ? e : id,
831 on, state_cols, unit_file_state_to_string(u->state), off);
729e3769
LP
832 }
833
1c0a113f 834 if (!arg_no_legend)
729e3769
LP
835 printf("\n%u unit files listed.\n", n_shown);
836}
837
838static int list_unit_files(DBusConnection *bus, char **args) {
f84190d8
LP
839 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
840 _cleanup_free_ UnitFileList *units = NULL;
729e3769
LP
841 DBusMessageIter iter, sub, sub2;
842 unsigned c = 0, n_units = 0;
f84190d8 843 int r;
729e3769 844
729e3769
LP
845 pager_open_if_enabled();
846
847 if (avoid_bus()) {
848 Hashmap *h;
849 UnitFileList *u;
850 Iterator i;
851
852 h = hashmap_new(string_hash_func, string_compare_func);
0d0f0c50
SL
853 if (!h)
854 return log_oom();
729e3769
LP
855
856 r = unit_file_get_list(arg_scope, arg_root, h);
857 if (r < 0) {
8ea913b2 858 unit_file_list_free(h);
729e3769
LP
859 log_error("Failed to get unit file list: %s", strerror(-r));
860 return r;
861 }
862
863 n_units = hashmap_size(h);
864 units = new(UnitFileList, n_units);
865 if (!units) {
866 unit_file_list_free(h);
0d0f0c50 867 return log_oom();
729e3769
LP
868 }
869
870 HASHMAP_FOREACH(u, h, i) {
871 memcpy(units + c++, u, sizeof(UnitFileList));
872 free(u);
873 }
874
875 hashmap_free(h);
876 } else {
f84190d8 877 r = bus_method_call_with_reply(
f22f08cd 878 bus,
729e3769
LP
879 "org.freedesktop.systemd1",
880 "/org/freedesktop/systemd1",
881 "org.freedesktop.systemd1.Manager",
f22f08cd
SP
882 "ListUnitFiles",
883 &reply,
884 NULL,
885 DBUS_TYPE_INVALID);
f84190d8
LP
886 if (r < 0)
887 return r;
729e3769
LP
888
889 if (!dbus_message_iter_init(reply, &iter) ||
890 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
891 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
892 log_error("Failed to parse reply.");
f84190d8 893 return -EIO;
729e3769
LP
894 }
895
896 dbus_message_iter_recurse(&iter, &sub);
897
898 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
899 UnitFileList *u;
900 const char *state;
901
ec76596c 902 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT);
729e3769
LP
903
904 if (c >= n_units) {
905 UnitFileList *w;
906
9607d947 907 n_units = MAX(2*c, 16u);
729e3769 908 w = realloc(units, sizeof(struct UnitFileList) * n_units);
f84190d8
LP
909 if (!w)
910 return log_oom();
729e3769
LP
911
912 units = w;
913 }
914
f84190d8 915 u = units + c;
729e3769
LP
916
917 dbus_message_iter_recurse(&sub, &sub2);
918
919 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &u->path, true) < 0 ||
920 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, false) < 0) {
921 log_error("Failed to parse reply.");
f84190d8 922 return -EIO;
729e3769
LP
923 }
924
925 u->state = unit_file_state_from_string(state);
926
927 dbus_message_iter_next(&sub);
928 c++;
929 }
930 }
931
932 if (c > 0) {
933 qsort(units, c, sizeof(UnitFileList), compare_unit_file_list);
934 output_unit_file_list(units, c);
935 }
936
f84190d8 937 return 0;
729e3769
LP
938}
939
55c0b89c
LN
940static int list_dependencies_print(const char *name, int level, unsigned int branches, bool last) {
941 int i;
942 _cleanup_free_ char *n = NULL;
943 size_t len = 0;
9607d947 944 size_t max_len = MAX(columns(),20u);
55c0b89c 945
5d0c05e5
LN
946 if (!arg_plain) {
947 for (i = level - 1; i >= 0; i--) {
948 len += 2;
949 if(len > max_len - 3 && !arg_full) {
950 printf("%s...\n",max_len % 2 ? "" : " ");
951 return 0;
952 }
953 printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERT : DRAW_TREE_SPACE));
954 }
55c0b89c
LN
955 len += 2;
956 if(len > max_len - 3 && !arg_full) {
957 printf("%s...\n",max_len % 2 ? "" : " ");
958 return 0;
959 }
5d0c05e5 960 printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
55c0b89c 961 }
55c0b89c
LN
962
963 if(arg_full){
964 printf("%s\n", name);
965 return 0;
966 }
967
968 n = ellipsize(name, max_len-len, 100);
969 if(!n)
970 return log_oom();
971
972 printf("%s\n", n);
973 return 0;
974}
975
976static int list_dependencies_get_dependencies(DBusConnection *bus, const char *name, char ***deps) {
afba4199
ZJS
977 static const char *dependencies[] = {
978 [DEPENDENCY_FORWARD] = "Requires\0"
979 "RequiresOverridable\0"
980 "Requisite\0"
981 "RequisiteOverridable\0"
982 "Wants\0",
983 [DEPENDENCY_REVERSE] = "RequiredBy\0"
984 "RequiredByOverridable\0"
985 "WantedBy\0"
986 "PartOf\0",
987 [DEPENDENCY_AFTER] = "After\0",
988 [DEPENDENCY_BEFORE] = "Before\0",
989 };
55c0b89c
LN
990
991 _cleanup_free_ char *path;
992 const char *interface = "org.freedesktop.systemd1.Unit";
993
994 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
995 DBusMessageIter iter, sub, sub2, sub3;
996
997 int r = 0;
55c0b89c 998 char **ret = NULL;
55c0b89c
LN
999
1000 assert(bus);
1001 assert(name);
1002 assert(deps);
1003
1004 path = unit_dbus_path_from_name(name);
1005 if (path == NULL) {
1006 r = -EINVAL;
1007 goto finish;
1008 }
1009
1010 r = bus_method_call_with_reply(
1011 bus,
1012 "org.freedesktop.systemd1",
1013 path,
1014 "org.freedesktop.DBus.Properties",
1015 "GetAll",
1016 &reply,
1017 NULL,
1018 DBUS_TYPE_STRING, &interface,
1019 DBUS_TYPE_INVALID);
1020 if (r < 0)
1021 goto finish;
1022
1023 if (!dbus_message_iter_init(reply, &iter) ||
1024 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1025 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
1026 log_error("Failed to parse reply.");
1027 r = -EIO;
1028 goto finish;
1029 }
1030
1031 dbus_message_iter_recurse(&iter, &sub);
1032
1033 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1034 const char *prop;
1035
52a2ab41 1036 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
55c0b89c
LN
1037 dbus_message_iter_recurse(&sub, &sub2);
1038
1039 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &prop, true) < 0) {
1040 log_error("Failed to parse reply.");
1041 r = -EIO;
1042 goto finish;
1043 }
1044
1045 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
1046 log_error("Failed to parse reply.");
1047 r = -EIO;
1048 goto finish;
1049 }
1050
1051 dbus_message_iter_recurse(&sub2, &sub3);
55c0b89c
LN
1052 dbus_message_iter_next(&sub);
1053
afba4199
ZJS
1054 assert(arg_dependency < ELEMENTSOF(dependencies));
1055 if (!nulstr_contains(dependencies[arg_dependency], prop))
55c0b89c
LN
1056 continue;
1057
1058 if (dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_ARRAY) {
1059 if (dbus_message_iter_get_element_type(&sub3) == DBUS_TYPE_STRING) {
1060 DBusMessageIter sub4;
1061 dbus_message_iter_recurse(&sub3, &sub4);
1062
1063 while (dbus_message_iter_get_arg_type(&sub4) != DBUS_TYPE_INVALID) {
1064 const char *s;
1065
1066 assert(dbus_message_iter_get_arg_type(&sub4) == DBUS_TYPE_STRING);
1067 dbus_message_iter_get_basic(&sub4, &s);
540e7dbe
LP
1068
1069 r = strv_extend(&ret, s);
1070 if (r < 0) {
1071 log_oom();
55c0b89c
LN
1072 goto finish;
1073 }
540e7dbe 1074
55c0b89c
LN
1075 dbus_message_iter_next(&sub4);
1076 }
1077 }
1078 }
1079 }
1080finish:
1081 if (r < 0)
d54110d1
LP
1082 strv_free(ret);
1083 else
1084 *deps = ret;
55c0b89c
LN
1085 return r;
1086}
1087
1088static int list_dependencies_compare(const void *_a, const void *_b) {
1089 const char **a = (const char**) _a, **b = (const char**) _b;
1090 if (unit_name_to_type(*a) == UNIT_TARGET && unit_name_to_type(*b) != UNIT_TARGET)
1091 return 1;
1092 if (unit_name_to_type(*a) != UNIT_TARGET && unit_name_to_type(*b) == UNIT_TARGET)
1093 return -1;
1094 return strcasecmp(*a, *b);
1095}
1096
5d0c05e5 1097static int list_dependencies_one(DBusConnection *bus, const char *name, int level, char ***units, unsigned int branches) {
7fd1b19b 1098 _cleanup_strv_free_ char **deps = NULL, **u;
55c0b89c 1099 char **c;
55c0b89c
LN
1100 int r = 0;
1101
5d0c05e5 1102 u = strv_append(*units, name);
cec7eda5 1103 if (!u)
55c0b89c
LN
1104 return log_oom();
1105
1106 r = list_dependencies_get_dependencies(bus, name, &deps);
1107 if (r < 0)
cec7eda5 1108 return r;
55c0b89c
LN
1109
1110 qsort(deps, strv_length(deps), sizeof (char*), list_dependencies_compare);
1111
1112 STRV_FOREACH(c, deps) {
1113 if (strv_contains(u, *c)) {
5d0c05e5
LN
1114 if (!arg_plain) {
1115 r = list_dependencies_print("...", level + 1, (branches << 1) | (c[1] == NULL ? 0 : 1), 1);
1116 if (r < 0)
1117 return r;
1118 }
55c0b89c
LN
1119 continue;
1120 }
1121
1122 r = list_dependencies_print(*c, level, branches, c[1] == NULL);
cec7eda5
ZJS
1123 if (r < 0)
1124 return r;
55c0b89c
LN
1125
1126 if (arg_all || unit_name_to_type(*c) == UNIT_TARGET) {
5d0c05e5 1127 r = list_dependencies_one(bus, *c, level + 1, &u, (branches << 1) | (c[1] == NULL ? 0 : 1));
55c0b89c 1128 if(r < 0)
cec7eda5 1129 return r;
55c0b89c
LN
1130 }
1131 }
5d0c05e5
LN
1132 if (arg_plain) {
1133 strv_free(*units);
1134 *units = u;
1135 u = NULL;
1136 }
cec7eda5 1137 return 0;
55c0b89c
LN
1138}
1139
1140static int list_dependencies(DBusConnection *bus, char **args) {
55c0b89c 1141 _cleanup_free_ char *unit = NULL;
5d0c05e5 1142 _cleanup_strv_free_ char **units = NULL;
e31165b2 1143 const char *u;
55c0b89c
LN
1144
1145 assert(bus);
55c0b89c 1146
e31165b2
LP
1147 if (args[1]) {
1148 unit = unit_name_mangle(args[1]);
1149 if (!unit)
1150 return log_oom();
1151 u = unit;
1152 } else
1153 u = SPECIAL_DEFAULT_TARGET;
55c0b89c
LN
1154
1155 pager_open_if_enabled();
e31165b2
LP
1156
1157 puts(u);
1158
5d0c05e5 1159 return list_dependencies_one(bus, u, 0, &units, 0);
55c0b89c
LN
1160}
1161
99504dd4
VP
1162static int get_default(DBusConnection *bus, char **args) {
1163 char *path = NULL;
66a69314 1164 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
99504dd4
VP
1165 int r;
1166 _cleanup_dbus_error_free_ DBusError error;
1167
1168 dbus_error_init(&error);
1169
1170 if (!bus || avoid_bus()) {
1171 r = unit_file_get_default(arg_scope, arg_root, &path);
1172
1173 if (r < 0) {
1174 log_error("Operation failed: %s", strerror(-r));
1175 goto finish;
1176 }
1177
1178 r = 0;
1179 } else {
1180 r = bus_method_call_with_reply(
1181 bus,
1182 "org.freedesktop.systemd1",
1183 "/org/freedesktop/systemd1",
1184 "org.freedesktop.systemd1.Manager",
1185 "GetDefaultTarget",
1186 &reply,
1187 NULL,
1188 DBUS_TYPE_INVALID);
1189
1190 if (r < 0) {
1191 log_error("Operation failed: %s", strerror(-r));
1192 goto finish;
1193 }
1194
1195 if (!dbus_message_get_args(reply, &error,
1196 DBUS_TYPE_STRING, &path,
1197 DBUS_TYPE_INVALID)) {
1198 log_error("Failed to parse reply: %s", bus_error_message(&error));
1199 dbus_error_free(&error);
1200 return -EIO;
1201 }
1202 }
1203
1204 if (path)
1205 printf("%s\n", path);
1206
1207finish:
1208 if ((!bus || avoid_bus()) && path)
1209 free(path);
1210
1211 return r;
1212
1213}
1214
75add28a
ZJS
1215struct job_info {
1216 uint32_t id;
1217 char *name, *type, *state;
1218};
1219
1220static void list_jobs_print(struct job_info* jobs, size_t n) {
1221 size_t i;
1222 struct job_info *j;
1223 const char *on, *off;
1224 bool shorten = false;
1225
1226 assert(n == 0 || jobs);
1227
1228 if (n == 0) {
0b5a519c
DS
1229 on = ansi_highlight_green();
1230 off = ansi_highlight_off();
75add28a
ZJS
1231
1232 printf("%sNo jobs running.%s\n", on, off);
1233 return;
1234 }
1235
1236 pager_open_if_enabled();
1237
1238 {
1239 /* JOB UNIT TYPE STATE */
1240 unsigned l0 = 3, l1 = 4, l2 = 4, l3 = 5;
1241
1242 for (i = 0, j = jobs; i < n; i++, j++) {
1243 assert(j->name && j->type && j->state);
82da66fb 1244 l0 = MAX(l0, DECIMAL_STR_WIDTH(j->id));
75add28a
ZJS
1245 l1 = MAX(l1, strlen(j->name));
1246 l2 = MAX(l2, strlen(j->type));
1247 l3 = MAX(l3, strlen(j->state));
1248 }
1249
1250 if (!arg_full && l0 + 1 + l1 + l2 + 1 + l3 > columns()) {
1251 l1 = MAX(33u, columns() - l0 - l2 - l3 - 3);
1252 shorten = true;
1253 }
1254
1255 if (on_tty())
1256 printf("%*s %-*s %-*s %-*s\n",
1257 l0, "JOB",
1258 l1, "UNIT",
1259 l2, "TYPE",
1260 l3, "STATE");
1261
1262 for (i = 0, j = jobs; i < n; i++, j++) {
7fd1b19b 1263 _cleanup_free_ char *e = NULL;
75add28a
ZJS
1264
1265 if (streq(j->state, "running")) {
0b5a519c
DS
1266 on = ansi_highlight();
1267 off = ansi_highlight_off();
75add28a
ZJS
1268 } else
1269 on = off = "";
1270
1271 e = shorten ? ellipsize(j->name, l1, 33) : NULL;
1272 printf("%*u %s%-*s%s %-*s %s%-*s%s\n",
1273 l0, j->id,
1274 on, l1, e ? e : j->name, off,
1275 l2, j->type,
1276 on, l3, j->state, off);
1277 }
1278 }
1279
0b5a519c
DS
1280 on = ansi_highlight();
1281 off = ansi_highlight_off();
75add28a
ZJS
1282
1283 if (on_tty())
1284 printf("\n%s%zu jobs listed%s.\n", on, n, off);
1285}
1286
729e3769 1287static int list_jobs(DBusConnection *bus, char **args) {
f84190d8 1288 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
7e4249b9 1289 DBusMessageIter iter, sub, sub2;
f84190d8 1290 int r;
75add28a
ZJS
1291 struct job_info *jobs = NULL;
1292 size_t size = 0, used = 0;
ec14911e 1293
f84190d8 1294 r = bus_method_call_with_reply(
f22f08cd
SP
1295 bus,
1296 "org.freedesktop.systemd1",
1297 "/org/freedesktop/systemd1",
1298 "org.freedesktop.systemd1.Manager",
1299 "ListJobs",
1300 &reply,
1301 NULL,
1302 DBUS_TYPE_INVALID);
f84190d8
LP
1303 if (r < 0)
1304 return r;
7e4249b9
LP
1305
1306 if (!dbus_message_iter_init(reply, &iter) ||
1307 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1308 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1309 log_error("Failed to parse reply.");
f84190d8 1310 return -EIO;
7e4249b9
LP
1311 }
1312
1313 dbus_message_iter_recurse(&iter, &sub);
1314
7e4249b9
LP
1315 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1316 const char *name, *type, *state, *job_path, *unit_path;
1317 uint32_t id;
1318
1319 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1320 log_error("Failed to parse reply.");
f84190d8 1321 return -EIO;
7e4249b9
LP
1322 }
1323
1324 dbus_message_iter_recurse(&sub, &sub2);
1325
1326 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &id, true) < 0 ||
1327 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1328 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
1329 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &state, true) < 0 ||
1330 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &job_path, true) < 0 ||
1331 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &unit_path, false) < 0) {
1332 log_error("Failed to parse reply.");
75add28a
ZJS
1333 r = -EIO;
1334 goto finish;
7e4249b9
LP
1335 }
1336
e9dd0369 1337 if (!GREEDY_REALLOC(jobs, size, used + 1)) {
75add28a
ZJS
1338 r = log_oom();
1339 goto finish;
1340 }
8fe914ec 1341
75add28a
ZJS
1342 jobs[used++] = (struct job_info) { id,
1343 strdup(name),
1344 strdup(type),
1345 strdup(state) };
1346 if (!jobs[used-1].name || !jobs[used-1].type || !jobs[used-1].state) {
1347 r = log_oom();
1348 goto finish;
1349 }
7e4249b9
LP
1350
1351 dbus_message_iter_next(&sub);
1352 }
1353
75add28a
ZJS
1354 list_jobs_print(jobs, used);
1355
1356 finish:
1357 while (used--) {
1358 free(jobs[used].name);
1359 free(jobs[used].type);
1360 free(jobs[used].state);
1361 }
1362 free(jobs);
f73e33d9 1363
f84190d8 1364 return 0;
7e4249b9
LP
1365}
1366
729e3769 1367static int cancel_job(DBusConnection *bus, char **args) {
729e3769 1368 char **name;
7e4249b9 1369
514f4ef5
LP
1370 assert(args);
1371
729e3769
LP
1372 if (strv_length(args) <= 1)
1373 return daemon_reload(bus, args);
ee5762e3 1374
729e3769 1375 STRV_FOREACH(name, args+1) {
5dd9014f
LP
1376 uint32_t id;
1377 int r;
7e4249b9 1378
5dd9014f 1379 r = safe_atou32(*name, &id);
f22f08cd 1380 if (r < 0) {
7e4249b9 1381 log_error("Failed to parse job id: %s", strerror(-r));
5dd9014f 1382 return r;
7e4249b9 1383 }
7e4249b9 1384
5dd9014f 1385 r = bus_method_call_with_reply(
f22f08cd
SP
1386 bus,
1387 "org.freedesktop.systemd1",
1388 "/org/freedesktop/systemd1",
1389 "org.freedesktop.systemd1.Manager",
5dd9014f 1390 "CancelJob",
f22f08cd
SP
1391 NULL,
1392 NULL,
5dd9014f 1393 DBUS_TYPE_UINT32, &id,
f22f08cd 1394 DBUS_TYPE_INVALID);
5dd9014f
LP
1395 if (r < 0)
1396 return r;
7e4249b9
LP
1397 }
1398
5dd9014f 1399 return 0;
7e4249b9
LP
1400}
1401
94c01aeb 1402static int need_daemon_reload(DBusConnection *bus, const char *unit) {
f84190d8 1403 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
94c01aeb 1404 _cleanup_dbus_error_free_ DBusError error;
45fb0699
LP
1405 dbus_bool_t b = FALSE;
1406 DBusMessageIter iter, sub;
1407 const char
1408 *interface = "org.freedesktop.systemd1.Unit",
1409 *property = "NeedDaemonReload",
1410 *path;
f84190d8 1411 _cleanup_free_ char *n = NULL;
f22f08cd 1412 int r;
45fb0699 1413
94c01aeb
LP
1414 dbus_error_init(&error);
1415
45fb0699
LP
1416 /* We ignore all errors here, since this is used to show a warning only */
1417
b0193f1c 1418 n = unit_name_mangle(unit);
69bd386c 1419 if (!n)
f84190d8
LP
1420 return log_oom();
1421
416389f7 1422 r = bus_method_call_with_reply(
f22f08cd
SP
1423 bus,
1424 "org.freedesktop.systemd1",
1425 "/org/freedesktop/systemd1",
1426 "org.freedesktop.systemd1.Manager",
1427 "GetUnit",
1428 &reply,
94c01aeb 1429 &error,
f84190d8 1430 DBUS_TYPE_STRING, &n,
f22f08cd 1431 DBUS_TYPE_INVALID);
f84190d8
LP
1432 if (r < 0)
1433 return r;
45fb0699
LP
1434
1435 if (!dbus_message_get_args(reply, NULL,
1436 DBUS_TYPE_OBJECT_PATH, &path,
1437 DBUS_TYPE_INVALID))
f84190d8 1438 return -EIO;
45fb0699 1439
f22f08cd 1440 dbus_message_unref(reply);
f84190d8
LP
1441 reply = NULL;
1442
1443 r = bus_method_call_with_reply(
f22f08cd 1444 bus,
b0193f1c
LP
1445 "org.freedesktop.systemd1",
1446 path,
1447 "org.freedesktop.DBus.Properties",
f22f08cd
SP
1448 "Get",
1449 &reply,
94c01aeb 1450 &error,
f22f08cd
SP
1451 DBUS_TYPE_STRING, &interface,
1452 DBUS_TYPE_STRING, &property,
1453 DBUS_TYPE_INVALID);
f84190d8
LP
1454 if (r < 0)
1455 return r;
45fb0699
LP
1456
1457 if (!dbus_message_iter_init(reply, &iter) ||
1458 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
f84190d8 1459 return -EIO;
45fb0699
LP
1460
1461 dbus_message_iter_recurse(&iter, &sub);
45fb0699 1462 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
f84190d8 1463 return -EIO;
45fb0699
LP
1464
1465 dbus_message_iter_get_basic(&sub, &b);
45fb0699
LP
1466 return b;
1467}
1468
5e374895
LP
1469typedef struct WaitData {
1470 Set *set;
67f3c402
LP
1471
1472 char *name;
5d44db4a 1473 char *result;
5e374895
LP
1474} WaitData;
1475
7e4249b9 1476static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
7fd1b19b 1477 _cleanup_dbus_error_free_ DBusError error;
5e374895 1478 WaitData *d = data;
7e4249b9 1479
cec7eda5
ZJS
1480 dbus_error_init(&error);
1481
7e4249b9
LP
1482 assert(connection);
1483 assert(message);
5e374895 1484 assert(d);
7e4249b9 1485
54165a39
LP
1486 log_debug("Got D-Bus request: %s.%s() on %s",
1487 dbus_message_get_interface(message),
1488 dbus_message_get_member(message),
1489 dbus_message_get_path(message));
7e4249b9
LP
1490
1491 if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
1492 log_error("Warning! D-Bus connection terminated.");
1493 dbus_connection_close(connection);
1494
1495 } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
1496 uint32_t id;
6e869e18
KS
1497 const char *path, *result, *unit;
1498 char *r;
7e4249b9 1499
5d44db4a
LP
1500 if (dbus_message_get_args(message, &error,
1501 DBUS_TYPE_UINT32, &id,
1502 DBUS_TYPE_OBJECT_PATH, &path,
06dab8e1 1503 DBUS_TYPE_STRING, &unit,
5d44db4a
LP
1504 DBUS_TYPE_STRING, &result,
1505 DBUS_TYPE_INVALID)) {
7e4249b9 1506
c1e784fe
MS
1507 r = set_remove(d->set, (char*) path);
1508 if (!r)
1509 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1510
1511 free(r);
5d44db4a 1512
67f3c402 1513 if (!isempty(result))
5d44db4a
LP
1514 d->result = strdup(result);
1515
67f3c402
LP
1516 if (!isempty(unit))
1517 d->name = strdup(unit);
1518
cec7eda5 1519 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
5d44db4a 1520 }
286ca485 1521#ifndef NOLEGACY
5d44db4a 1522 dbus_error_free(&error);
06dab8e1
LP
1523 if (dbus_message_get_args(message, &error,
1524 DBUS_TYPE_UINT32, &id,
1525 DBUS_TYPE_OBJECT_PATH, &path,
1526 DBUS_TYPE_STRING, &result,
1527 DBUS_TYPE_INVALID)) {
06dab8e1
LP
1528 /* Compatibility with older systemd versions <
1529 * 183 during upgrades. This should be dropped
1530 * one day. */
c1e784fe
MS
1531 r = set_remove(d->set, (char*) path);
1532 if (!r)
1533 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1534
1535 free(r);
5d44db4a 1536
06dab8e1
LP
1537 if (*result)
1538 d->result = strdup(result);
1539
cec7eda5 1540 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
06dab8e1 1541 }
5d44db4a
LP
1542#endif
1543
1544 log_error("Failed to parse message: %s", bus_error_message(&error));
7e4249b9
LP
1545 }
1546
7e4249b9
LP
1547 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1548}
1549
479ef5d3 1550static int enable_wait_for_jobs(DBusConnection *bus) {
7e4249b9 1551 DBusError error;
7e4249b9
LP
1552
1553 assert(bus);
7e4249b9 1554
f4579ce7
LP
1555 if (private_bus)
1556 return 0;
1557
7e4249b9 1558 dbus_error_init(&error);
7e4249b9
LP
1559 dbus_bus_add_match(bus,
1560 "type='signal',"
1561 "sender='org.freedesktop.systemd1',"
1562 "interface='org.freedesktop.systemd1.Manager',"
1563 "member='JobRemoved',"
1564 "path='/org/freedesktop/systemd1'",
1565 &error);
1566
1567 if (dbus_error_is_set(&error)) {
4cf5d675 1568 log_error("Failed to add match: %s", bus_error_message(&error));
a567261a
LP
1569 dbus_error_free(&error);
1570 return -EIO;
7e4249b9
LP
1571 }
1572
479ef5d3 1573 /* This is slightly dirty, since we don't undo the match registrations. */
a567261a 1574 return 0;
7e4249b9
LP
1575}
1576
479ef5d3 1577static int wait_for_jobs(DBusConnection *bus, Set *s) {
67f3c402 1578 int r = 0;
b92bea5d 1579 WaitData d = { .set = s };
479ef5d3
LP
1580
1581 assert(bus);
1582 assert(s);
1583
67f3c402
LP
1584 if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL))
1585 return log_oom();
479ef5d3 1586
67f3c402 1587 while (!set_isempty(s)) {
5e374895 1588
67f3c402
LP
1589 if (!dbus_connection_read_write_dispatch(bus, -1)) {
1590 log_error("Disconnected from bus.");
1591 return -ECONNREFUSED;
1592 }
8e20e31a 1593
d39b034a
ZJS
1594 if (!d.result)
1595 goto free_name;
1596
1597 if (!arg_quiet) {
67f3c402
LP
1598 if (streq(d.result, "timeout"))
1599 log_error("Job for %s timed out.", strna(d.name));
1600 else if (streq(d.result, "canceled"))
1601 log_error("Job for %s canceled.", strna(d.name));
1602 else if (streq(d.result, "dependency"))
95ec8647 1603 log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
67f3c402 1604 else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
95ec8647 1605 log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
67f3c402 1606 }
479ef5d3 1607
67f3c402
LP
1608 if (streq_ptr(d.result, "timeout"))
1609 r = -ETIME;
1610 else if (streq_ptr(d.result, "canceled"))
1611 r = -ECANCELED;
1612 else if (!streq_ptr(d.result, "done") && !streq_ptr(d.result, "skipped"))
1613 r = -EIO;
1614
1615 free(d.result);
1616 d.result = NULL;
1617
d39b034a 1618 free_name:
67f3c402
LP
1619 free(d.name);
1620 d.name = NULL;
1621 }
479ef5d3 1622
d39b034a 1623 dbus_connection_remove_filter(bus, wait_filter, &d);
479ef5d3
LP
1624 return r;
1625}
1626
60f9ba0b
LP
1627static int check_one_unit(DBusConnection *bus, const char *name, char **check_states, bool quiet) {
1628 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
f84190d8 1629 _cleanup_free_ char *n = NULL;
701cdcb9 1630 DBusMessageIter iter, sub;
31be1221
MS
1631 const char
1632 *interface = "org.freedesktop.systemd1.Unit",
1633 *property = "ActiveState";
60f9ba0b 1634 const char *state, *path;
60f9ba0b 1635 DBusError error;
f22f08cd 1636 int r;
701cdcb9 1637
31be1221 1638 assert(name);
701cdcb9 1639
60f9ba0b
LP
1640 dbus_error_init(&error);
1641
f22f08cd 1642 n = unit_name_mangle(name);
60f9ba0b
LP
1643 if (!n)
1644 return log_oom();
1645
f22f08cd
SP
1646 r = bus_method_call_with_reply (
1647 bus,
1648 "org.freedesktop.systemd1",
1649 "/org/freedesktop/systemd1",
1650 "org.freedesktop.systemd1.Manager",
1651 "GetUnit",
1652 &reply,
60f9ba0b
LP
1653 &error,
1654 DBUS_TYPE_STRING, &n,
f22f08cd 1655 DBUS_TYPE_INVALID);
60f9ba0b
LP
1656 if (r < 0) {
1657 dbus_error_free(&error);
1658
1659 if (!quiet)
f22f08cd 1660 puts("unknown");
60f9ba0b 1661 return 0;
f22f08cd 1662 }
e61a3135 1663
f22f08cd 1664 if (!dbus_message_get_args(reply, NULL,
31be1221
MS
1665 DBUS_TYPE_OBJECT_PATH, &path,
1666 DBUS_TYPE_INVALID)) {
f22f08cd 1667 log_error("Failed to parse reply.");
60f9ba0b 1668 return -EIO;
31be1221
MS
1669 }
1670
31be1221 1671 dbus_message_unref(reply);
60f9ba0b
LP
1672 reply = NULL;
1673
1674 r = bus_method_call_with_reply(
f22f08cd
SP
1675 bus,
1676 "org.freedesktop.systemd1",
1677 path,
1678 "org.freedesktop.DBus.Properties",
1679 "Get",
1680 &reply,
1681 NULL,
1682 DBUS_TYPE_STRING, &interface,
1683 DBUS_TYPE_STRING, &property,
1684 DBUS_TYPE_INVALID);
60f9ba0b
LP
1685 if (r < 0) {
1686 if (!quiet)
1687 puts("unknown");
1688 return 0;
1689 }
701cdcb9 1690
31be1221
MS
1691 if (!dbus_message_iter_init(reply, &iter) ||
1692 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1693 log_error("Failed to parse reply.");
60f9ba0b 1694 return r;
31be1221
MS
1695 }
1696
701cdcb9
MS
1697 dbus_message_iter_recurse(&iter, &sub);
1698
31be1221
MS
1699 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1700 log_error("Failed to parse reply.");
60f9ba0b 1701 return r;
701cdcb9 1702 }
31be1221
MS
1703
1704 dbus_message_iter_get_basic(&sub, &state);
1705
1706 if (!quiet)
1707 puts(state);
1708
60f9ba0b 1709 return strv_find(check_states, state) ? 1 : 0;
701cdcb9
MS
1710}
1711
1c291cf3 1712static void check_triggering_units(
701cdcb9 1713 DBusConnection *bus,
701cdcb9
MS
1714 const char *unit_name) {
1715
cad45ba1 1716 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
701cdcb9 1717 DBusMessageIter iter, sub;
31be1221 1718 const char *interface = "org.freedesktop.systemd1.Unit",
d0a5cdb2
JJ
1719 *load_state_property = "LoadState",
1720 *triggered_by_property = "TriggeredBy",
1721 *state;
7fd1b19b 1722 _cleanup_free_ char *unit_path = NULL, *n = NULL;
e61a3135 1723 bool print_warning_label = true;
f22f08cd 1724 int r;
701cdcb9 1725
b0193f1c 1726 n = unit_name_mangle(unit_name);
46eddbb5
ZJS
1727 if (!n) {
1728 log_oom();
1729 return;
1730 }
d3b52baf 1731
46eddbb5 1732 unit_path = unit_dbus_path_from_name(n);
48899192 1733 if (!unit_path) {
46eddbb5 1734 log_oom();
d3b52baf 1735 return;
48899192 1736 }
701cdcb9 1737
d0a5cdb2
JJ
1738 r = bus_method_call_with_reply(
1739 bus,
1740 "org.freedesktop.systemd1",
1741 unit_path,
1742 "org.freedesktop.DBus.Properties",
1743 "Get",
1744 &reply,
1745 NULL,
1746 DBUS_TYPE_STRING, &interface,
1747 DBUS_TYPE_STRING, &load_state_property,
1748 DBUS_TYPE_INVALID);
1749 if (r < 0)
1750 return;
1751
1752 if (!dbus_message_iter_init(reply, &iter) ||
1753 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1754 log_error("Failed to parse reply.");
1755 return;
1756 }
1757
1758 dbus_message_iter_recurse(&iter, &sub);
1759
1760 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1761 log_error("Failed to parse reply.");
1762 return;
1763 }
1764
1765 dbus_message_iter_get_basic(&sub, &state);
1766
1767 if (streq(state, "masked"))
1768 return;
1769
1770 dbus_message_unref(reply);
1771 reply = NULL;
1772
60f9ba0b 1773 r = bus_method_call_with_reply(
f22f08cd
SP
1774 bus,
1775 "org.freedesktop.systemd1",
1776 unit_path,
1777 "org.freedesktop.DBus.Properties",
1778 "Get",
1779 &reply,
1780 NULL,
1781 DBUS_TYPE_STRING, &interface,
1782 DBUS_TYPE_STRING, &triggered_by_property,
1783 DBUS_TYPE_INVALID);
60f9ba0b 1784 if (r < 0)
d3b52baf 1785 return;
701cdcb9
MS
1786
1787 if (!dbus_message_iter_init(reply, &iter) ||
e61a3135 1788 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
f22f08cd 1789 log_error("Failed to parse reply.");
d3b52baf 1790 return;
701cdcb9
MS
1791 }
1792
1793 dbus_message_iter_recurse(&iter, &sub);
1794 dbus_message_iter_recurse(&sub, &iter);
1795 sub = iter;
1796
1797 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
60f9ba0b
LP
1798 const char * const check_states[] = {
1799 "active",
1800 "reloading",
1801 NULL
1802 };
1803 const char *service_trigger;
701cdcb9
MS
1804
1805 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
f22f08cd 1806 log_error("Failed to parse reply.");
d3b52baf 1807 return;
701cdcb9
MS
1808 }
1809
1810 dbus_message_iter_get_basic(&sub, &service_trigger);
1811
60f9ba0b 1812 r = check_one_unit(bus, service_trigger, (char**) check_states, true);
e61a3135 1813 if (r < 0)
d3b52baf 1814 return;
60f9ba0b 1815 if (r > 0) {
701cdcb9 1816 if (print_warning_label) {
1c291cf3 1817 log_warning("Warning: Stopping %s, but it can still be activated by:", unit_name);
e61a3135 1818 print_warning_label = false;
701cdcb9 1819 }
60f9ba0b 1820
1c291cf3 1821 log_warning(" %s", service_trigger);
701cdcb9 1822 }
1c291cf3 1823
222d0348 1824 dbus_message_iter_next(&sub);
701cdcb9 1825 }
701cdcb9
MS
1826}
1827
e4b61340
LP
1828static int start_unit_one(
1829 DBusConnection *bus,
1830 const char *method,
1831 const char *name,
1832 const char *mode,
22f4096c 1833 DBusError *error,
e4b61340 1834 Set *s) {
7e4249b9 1835
cad45ba1 1836 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
f84190d8 1837 _cleanup_free_ char *n;
45fb0699 1838 const char *path;
7e4249b9 1839 int r;
7e4249b9 1840
e4b61340
LP
1841 assert(method);
1842 assert(name);
1843 assert(mode);
22f4096c 1844 assert(error);
7e4249b9 1845
f22f08cd 1846 n = unit_name_mangle(name);
67f3c402
LP
1847 if (!n)
1848 return log_oom();
1849
1850 r = bus_method_call_with_reply(
f22f08cd 1851 bus,
b0193f1c
LP
1852 "org.freedesktop.systemd1",
1853 "/org/freedesktop/systemd1",
1854 "org.freedesktop.systemd1.Manager",
f22f08cd
SP
1855 method,
1856 &reply,
1857 error,
67f3c402 1858 DBUS_TYPE_STRING, &n,
f22f08cd
SP
1859 DBUS_TYPE_STRING, &mode,
1860 DBUS_TYPE_INVALID);
f22f08cd 1861 if (r) {
67f3c402 1862 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
e4b61340
LP
1863 /* There's always a fallback possible for
1864 * legacy actions. */
706900b7 1865 r = -EADDRNOTAVAIL;
c516c8d1
SP
1866 else
1867 log_error("Failed to issue method call: %s", bus_error_message(error));
67f3c402 1868
46eddbb5 1869 return r;
7e4249b9
LP
1870 }
1871
22f4096c 1872 if (!dbus_message_get_args(reply, error,
45fb0699
LP
1873 DBUS_TYPE_OBJECT_PATH, &path,
1874 DBUS_TYPE_INVALID)) {
22f4096c 1875 log_error("Failed to parse reply: %s", bus_error_message(error));
46eddbb5 1876 return -EIO;
45fb0699
LP
1877 }
1878
94c01aeb 1879 if (need_daemon_reload(bus, n) > 0)
1058cbf2
ZJS
1880 log_warning("Warning: Unit file of %s changed on disk, 'systemctl %sdaemon-reload' recommended.",
1881 n, arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
45fb0699 1882
67f3c402 1883 if (s) {
f84190d8
LP
1884 char *p;
1885
67f3c402 1886 p = strdup(path);
46eddbb5
ZJS
1887 if (!p)
1888 return log_oom();
7e4249b9 1889
ef42202a 1890 r = set_consume(s, p);
67f3c402 1891 if (r < 0) {
7e4249b9 1892 log_error("Failed to add path to set.");
46eddbb5 1893 return r;
7e4249b9 1894 }
e4b61340 1895 }
7e4249b9 1896
46eddbb5 1897 return 0;
7e4249b9
LP
1898}
1899
47a0eaa6
MS
1900static const struct {
1901 const char *target;
1902 const char *verb;
1903 const char *mode;
1904} action_table[_ACTION_MAX] = {
1905 [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" },
1906 [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" },
1907 [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" },
1908 [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" },
1909 [ACTION_RUNLEVEL2] = { SPECIAL_RUNLEVEL2_TARGET, NULL, "isolate" },
1910 [ACTION_RUNLEVEL3] = { SPECIAL_RUNLEVEL3_TARGET, NULL, "isolate" },
1911 [ACTION_RUNLEVEL4] = { SPECIAL_RUNLEVEL4_TARGET, NULL, "isolate" },
1912 [ACTION_RUNLEVEL5] = { SPECIAL_RUNLEVEL5_TARGET, NULL, "isolate" },
1913 [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" },
1914 [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" },
1915 [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" },
1916 [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" },
1917 [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" },
1918 [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" },
1919 [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" },
1920};
1921
514f4ef5 1922static enum action verb_to_action(const char *verb) {
47a0eaa6
MS
1923 enum action i;
1924
1925 for (i = ACTION_INVALID; i < _ACTION_MAX; i++)
1926 if (action_table[i].verb && streq(verb, action_table[i].verb))
1927 return i;
1928 return ACTION_INVALID;
514f4ef5
LP
1929}
1930
729e3769 1931static int start_unit(DBusConnection *bus, char **args) {
e4b61340 1932
22f4096c 1933 int r, ret = 0;
514f4ef5 1934 const char *method, *mode, *one_name;
7fd1b19b
HH
1935 _cleanup_set_free_free_ Set *s = NULL;
1936 _cleanup_dbus_error_free_ DBusError error;
729e3769 1937 char **name;
22f4096c
LP
1938
1939 dbus_error_init(&error);
e4b61340 1940
514f4ef5
LP
1941 assert(bus);
1942
6bb92a16 1943 ask_password_agent_open_if_enabled();
501fc174 1944
e4b61340 1945 if (arg_action == ACTION_SYSTEMCTL) {
47a0eaa6 1946 enum action action;
e4b61340 1947 method =
a76f7be2
LP
1948 streq(args[0], "stop") ||
1949 streq(args[0], "condstop") ? "StopUnit" :
6f28c033
LP
1950 streq(args[0], "reload") ? "ReloadUnit" :
1951 streq(args[0], "restart") ? "RestartUnit" :
d68201e9 1952
aa5939a3
MS
1953 streq(args[0], "try-restart") ||
1954 streq(args[0], "condrestart") ? "TryRestartUnit" :
d68201e9 1955
6f28c033 1956 streq(args[0], "reload-or-restart") ? "ReloadOrRestartUnit" :
d68201e9 1957
9d8a57ff 1958 streq(args[0], "reload-or-try-restart") ||
64e5f1b7 1959 streq(args[0], "condreload") ||
d68201e9 1960
aa5939a3 1961 streq(args[0], "force-reload") ? "ReloadOrTryRestartUnit" :
6f28c033 1962 "StartUnit";
47a0eaa6 1963 action = verb_to_action(args[0]);
e4b61340 1964
47a0eaa6
MS
1965 mode = streq(args[0], "isolate") ? "isolate" :
1966 action_table[action].mode ?: arg_job_mode;
e4b61340 1967
47a0eaa6 1968 one_name = action_table[action].target;
e4b61340 1969
e4b61340 1970 } else {
47a0eaa6
MS
1971 assert(arg_action < ELEMENTSOF(action_table));
1972 assert(action_table[arg_action].target);
e4b61340
LP
1973
1974 method = "StartUnit";
514f4ef5 1975
47a0eaa6
MS
1976 mode = action_table[arg_action].mode;
1977 one_name = action_table[arg_action].target;
514f4ef5
LP
1978 }
1979
6e905d93 1980 if (!arg_no_block) {
67f3c402
LP
1981 ret = enable_wait_for_jobs(bus);
1982 if (ret < 0) {
22f4096c 1983 log_error("Could not watch jobs: %s", strerror(-ret));
cec7eda5 1984 return ret;
514f4ef5
LP
1985 }
1986
67f3c402 1987 s = set_new(string_hash_func, string_compare_func);
cec7eda5
ZJS
1988 if (!s)
1989 return log_oom();
e4b61340
LP
1990 }
1991
514f4ef5 1992 if (one_name) {
67f3c402
LP
1993 ret = start_unit_one(bus, method, one_name, mode, &error, s);
1994 if (ret < 0)
1995 ret = translate_bus_error_to_exit_status(ret, &error);
514f4ef5 1996 } else {
67f3c402
LP
1997 STRV_FOREACH(name, args+1) {
1998 r = start_unit_one(bus, method, *name, mode, &error, s);
1999 if (r < 0) {
706900b7 2000 ret = translate_bus_error_to_exit_status(r, &error);
22f4096c
LP
2001 dbus_error_free(&error);
2002 }
67f3c402 2003 }
e4b61340
LP
2004 }
2005
67f3c402
LP
2006 if (!arg_no_block) {
2007 r = wait_for_jobs(bus, s);
cec7eda5
ZJS
2008 if (r < 0)
2009 return r;
49111a70
ZJS
2010
2011 /* When stopping units, warn if they can still be triggered by
2012 * another active unit (socket, path, timer) */
2013 if (!arg_quiet && streq(method, "StopUnit")) {
2014 if (one_name)
2015 check_triggering_units(bus, one_name);
2016 else
2017 STRV_FOREACH(name, args+1)
2018 check_triggering_units(bus, *name);
2019 }
67f3c402 2020 }
514f4ef5 2021
22f4096c 2022 return ret;
e4b61340
LP
2023}
2024
7e59bfcb
LP
2025/* Ask systemd-logind, which might grant access to unprivileged users
2026 * through PolicyKit */
4c80c73c
KS
2027static int reboot_with_logind(DBusConnection *bus, enum action a) {
2028#ifdef HAVE_LOGIND
2029 const char *method;
4c80c73c 2030 dbus_bool_t interactive = true;
4c80c73c 2031
d255133d
LP
2032 if (!bus)
2033 return -EIO;
2034
6bb92a16
LP
2035 polkit_agent_open_if_enabled();
2036
4c80c73c
KS
2037 switch (a) {
2038
2039 case ACTION_REBOOT:
2040 method = "Reboot";
2041 break;
2042
2043 case ACTION_POWEROFF:
2044 method = "PowerOff";
2045 break;
2046
d889a206
LP
2047 case ACTION_SUSPEND:
2048 method = "Suspend";
2049 break;
2050
2051 case ACTION_HIBERNATE:
2052 method = "Hibernate";
2053 break;
2054
6524990f
LP
2055 case ACTION_HYBRID_SLEEP:
2056 method = "HybridSleep";
2057 break;
2058
4c80c73c
KS
2059 default:
2060 return -EINVAL;
2061 }
2062
f84190d8 2063 return bus_method_call_with_reply(
f22f08cd
SP
2064 bus,
2065 "org.freedesktop.login1",
2066 "/org/freedesktop/login1",
2067 "org.freedesktop.login1.Manager",
2068 method,
2069 NULL,
2070 NULL,
2071 DBUS_TYPE_BOOLEAN, &interactive,
2072 DBUS_TYPE_INVALID);
4c80c73c
KS
2073#else
2074 return -ENOSYS;
2075#endif
2076}
2077
b37844d3
LP
2078static int check_inhibitors(DBusConnection *bus, enum action a) {
2079#ifdef HAVE_LOGIND
2080 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
2081 DBusMessageIter iter, sub, sub2;
2082 int r;
2083 unsigned c = 0;
59164be4
LP
2084 _cleanup_strv_free_ char **sessions = NULL;
2085 char **s;
b37844d3 2086
748ebafa
LP
2087 if (!bus)
2088 return 0;
2089
2090 if (arg_ignore_inhibitors || arg_force > 0)
2091 return 0;
2092
2093 if (arg_when > 0)
2094 return 0;
2095
2096 if (geteuid() == 0)
b37844d3
LP
2097 return 0;
2098
2099 if (!on_tty())
2100 return 0;
2101
2102 r = bus_method_call_with_reply(
2103 bus,
2104 "org.freedesktop.login1",
2105 "/org/freedesktop/login1",
2106 "org.freedesktop.login1.Manager",
2107 "ListInhibitors",
2108 &reply,
2109 NULL,
2110 DBUS_TYPE_INVALID);
2111 if (r < 0)
2112 /* If logind is not around, then there are no inhibitors... */
2113 return 0;
2114
2115 if (!dbus_message_iter_init(reply, &iter) ||
2116 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2117 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
2118 log_error("Failed to parse reply.");
2119 return -EIO;
2120 }
2121
2122 dbus_message_iter_recurse(&iter, &sub);
2123 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2124 const char *what, *who, *why, *mode;
2125 uint32_t uid, pid;
2126 _cleanup_strv_free_ char **sv = NULL;
59164be4 2127 _cleanup_free_ char *comm = NULL, *user = NULL;
b37844d3
LP
2128
2129 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
2130 log_error("Failed to parse reply.");
2131 return -EIO;
2132 }
2133
2134 dbus_message_iter_recurse(&sub, &sub2);
2135
2136 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &what, true) < 0 ||
2137 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &who, true) < 0 ||
2138 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &why, true) < 0 ||
2139 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &mode, true) < 0 ||
2140 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &uid, true) < 0 ||
2141 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, false) < 0) {
2142 log_error("Failed to parse reply.");
2143 return -EIO;
2144 }
2145
2146 if (!streq(mode, "block"))
2147 goto next;
2148
2149 sv = strv_split(what, ":");
2150 if (!sv)
2151 return log_oom();
2152
2153 if (!strv_contains(sv,
2154 a == ACTION_HALT ||
2155 a == ACTION_POWEROFF ||
2156 a == ACTION_REBOOT ||
2157 a == ACTION_KEXEC ? "shutdown" : "sleep"))
2158 goto next;
2159
2160 get_process_comm(pid, &comm);
59164be4
LP
2161 user = uid_to_name(uid);
2162 log_warning("Operation inhibited by \"%s\" (PID %lu \"%s\", user %s), reason is \"%s\".",
2163 who, (unsigned long) pid, strna(comm), strna(user), why);
b37844d3
LP
2164 c++;
2165
2166 next:
2167 dbus_message_iter_next(&sub);
2168 }
2169
2170 dbus_message_iter_recurse(&iter, &sub);
2171
59164be4
LP
2172 /* Check for current sessions */
2173 sd_get_sessions(&sessions);
2174 STRV_FOREACH(s, sessions) {
2175 uid_t uid;
2176 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
2177
2178 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
2179 continue;
2180
2181 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
2182 continue;
2183
2184 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
2185 continue;
2186
2187 sd_session_get_tty(*s, &tty);
2188 sd_session_get_seat(*s, &seat);
2189 sd_session_get_service(*s, &service);
2190 user = uid_to_name(uid);
2191
2192 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
2193 c++;
2194 }
2195
b37844d3
LP
2196 if (c <= 0)
2197 return 0;
2198
59164be4 2199 log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'systemctl %s -i'.",
47a0eaa6 2200 action_table[a].verb);
b37844d3
LP
2201
2202 return -EPERM;
2203#else
2204 return 0;
2205#endif
2206}
2207
729e3769 2208static int start_special(DBusConnection *bus, char **args) {
4c80c73c 2209 enum action a;
983d9c90
LP
2210 int r;
2211
514f4ef5
LP
2212 assert(args);
2213
4c80c73c
KS
2214 a = verb_to_action(args[0]);
2215
748ebafa
LP
2216 r = check_inhibitors(bus, a);
2217 if (r < 0)
2218 return r;
2219
c32b90de
LP
2220 if (arg_force >= 2 && geteuid() != 0) {
2221 log_error("Must be root.");
2222 return -EPERM;
2223 }
2224
7e59bfcb
LP
2225 if (arg_force >= 2 &&
2226 (a == ACTION_HALT ||
2227 a == ACTION_POWEROFF ||
2228 a == ACTION_REBOOT))
2229 halt_now(a);
e606bb61 2230
7e59bfcb 2231 if (arg_force >= 1 &&
4c80c73c
KS
2232 (a == ACTION_HALT ||
2233 a == ACTION_POWEROFF ||
2234 a == ACTION_REBOOT ||
2235 a == ACTION_KEXEC ||
2236 a == ACTION_EXIT))
729e3769 2237 return daemon_reload(bus, args);
20b09ca7 2238
7e59bfcb
LP
2239 /* first try logind, to allow authentication with polkit */
2240 if (geteuid() != 0 &&
2241 (a == ACTION_POWEROFF ||
d889a206
LP
2242 a == ACTION_REBOOT ||
2243 a == ACTION_SUSPEND ||
6524990f
LP
2244 a == ACTION_HIBERNATE ||
2245 a == ACTION_HYBRID_SLEEP)) {
7e59bfcb
LP
2246 r = reboot_with_logind(bus, a);
2247 if (r >= 0)
2248 return r;
4c80c73c 2249 }
983d9c90 2250
4c80c73c 2251 r = start_unit(bus, args);
f6bb13ab 2252 if (r == EXIT_SUCCESS)
4c80c73c 2253 warn_wall(a);
514f4ef5 2254
983d9c90 2255 return r;
514f4ef5
LP
2256}
2257
1a0fce45 2258static int check_unit_active(DBusConnection *bus, char **args) {
60f9ba0b
LP
2259 const char * const check_states[] = {
2260 "active",
2261 "reloading",
2262 NULL
2263 };
2264
729e3769 2265 char **name;
31be1221 2266 int r = 3; /* According to LSB: "program is not running" */
0183528f
LP
2267
2268 assert(bus);
2269 assert(args);
2270
729e3769 2271 STRV_FOREACH(name, args+1) {
60f9ba0b
LP
2272 int state;
2273
2274 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
1a0fce45
TA
2275 if (state < 0)
2276 return state;
60f9ba0b 2277 if (state > 0)
1a0fce45
TA
2278 r = 0;
2279 }
2280
2281 return r;
2282}
2283
2284static int check_unit_failed(DBusConnection *bus, char **args) {
60f9ba0b
LP
2285 const char * const check_states[] = {
2286 "failed",
2287 NULL
2288 };
2289
1a0fce45
TA
2290 char **name;
2291 int r = 1;
2292
2293 assert(bus);
2294 assert(args);
2295
2296 STRV_FOREACH(name, args+1) {
60f9ba0b
LP
2297 int state;
2298
2299 state = check_one_unit(bus, *name, (char**) check_states, arg_quiet);
31be1221
MS
2300 if (state < 0)
2301 return state;
60f9ba0b 2302 if (state > 0)
0183528f 2303 r = 0;
0183528f
LP
2304 }
2305
0183528f 2306 return r;
48220598
LP
2307}
2308
729e3769 2309static int kill_unit(DBusConnection *bus, char **args) {
60f9ba0b 2310 char **name;
8a0867d6 2311 int r = 0;
8a0867d6 2312
60f9ba0b 2313 assert(bus);
8a0867d6
LP
2314 assert(args);
2315
8a0867d6
LP
2316 if (!arg_kill_who)
2317 arg_kill_who = "all";
2318
729e3769 2319 STRV_FOREACH(name, args+1) {
60f9ba0b
LP
2320 _cleanup_free_ char *n = NULL;
2321
f22f08cd 2322 n = unit_name_mangle(*name);
f84190d8
LP
2323 if (!n)
2324 return log_oom();
60f9ba0b
LP
2325
2326 r = bus_method_call_with_reply(
f22f08cd 2327 bus,
b0193f1c
LP
2328 "org.freedesktop.systemd1",
2329 "/org/freedesktop/systemd1",
2330 "org.freedesktop.systemd1.Manager",
f22f08cd
SP
2331 "KillUnit",
2332 NULL,
2333 NULL,
f84190d8 2334 DBUS_TYPE_STRING, &n,
f22f08cd
SP
2335 DBUS_TYPE_STRING, &arg_kill_who,
2336 DBUS_TYPE_INT32, &arg_signal,
2337 DBUS_TYPE_INVALID);
60f9ba0b 2338 if (r < 0)
f22f08cd 2339 return r;
8a0867d6 2340 }
f22f08cd 2341 return 0;
8a0867d6
LP
2342}
2343
582a507f 2344typedef struct ExecStatusInfo {
0129173a
LP
2345 char *name;
2346
582a507f
LP
2347 char *path;
2348 char **argv;
2349
b708e7ce
LP
2350 bool ignore;
2351
582a507f
LP
2352 usec_t start_timestamp;
2353 usec_t exit_timestamp;
2354 pid_t pid;
2355 int code;
2356 int status;
2357
2358 LIST_FIELDS(struct ExecStatusInfo, exec);
2359} ExecStatusInfo;
2360
2361static void exec_status_info_free(ExecStatusInfo *i) {
2362 assert(i);
2363
0129173a 2364 free(i->name);
582a507f
LP
2365 free(i->path);
2366 strv_free(i->argv);
2367 free(i);
2368}
2369
2370static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
b21a0ef8 2371 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
582a507f
LP
2372 DBusMessageIter sub2, sub3;
2373 const char*path;
2374 unsigned n;
2375 uint32_t pid;
2376 int32_t code, status;
b708e7ce 2377 dbus_bool_t ignore;
582a507f
LP
2378
2379 assert(i);
2380 assert(i);
2381
2382 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2383 return -EIO;
2384
2385 dbus_message_iter_recurse(sub, &sub2);
2386
2387 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2388 return -EIO;
2389
f84190d8
LP
2390 i->path = strdup(path);
2391 if (!i->path)
582a507f
LP
2392 return -ENOMEM;
2393
2394 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2395 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2396 return -EIO;
2397
2398 n = 0;
2399 dbus_message_iter_recurse(&sub2, &sub3);
2400 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2401 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2402 dbus_message_iter_next(&sub3);
2403 n++;
2404 }
2405
f84190d8
LP
2406 i->argv = new0(char*, n+1);
2407 if (!i->argv)
582a507f
LP
2408 return -ENOMEM;
2409
2410 n = 0;
2411 dbus_message_iter_recurse(&sub2, &sub3);
2412 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2413 const char *s;
2414
2415 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2416 dbus_message_iter_get_basic(&sub3, &s);
2417 dbus_message_iter_next(&sub3);
2418
f84190d8
LP
2419 i->argv[n] = strdup(s);
2420 if (!i->argv[n])
582a507f 2421 return -ENOMEM;
f84190d8
LP
2422
2423 n++;
582a507f
LP
2424 }
2425
2426 if (!dbus_message_iter_next(&sub2) ||
b708e7ce 2427 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
582a507f 2428 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
b21a0ef8 2429 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
582a507f 2430 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
b21a0ef8 2431 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
582a507f
LP
2432 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2433 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2434 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2435 return -EIO;
2436
b708e7ce 2437 i->ignore = ignore;
582a507f
LP
2438 i->start_timestamp = (usec_t) start_timestamp;
2439 i->exit_timestamp = (usec_t) exit_timestamp;
2440 i->pid = (pid_t) pid;
2441 i->code = code;
2442 i->status = status;
2443
2444 return 0;
2445}
2446
61cbdc4b
LP
2447typedef struct UnitStatusInfo {
2448 const char *id;
2449 const char *load_state;
2450 const char *active_state;
2451 const char *sub_state;
a4375746 2452 const char *unit_file_state;
61cbdc4b
LP
2453
2454 const char *description;
4a9e2fff 2455 const char *following;
61cbdc4b 2456
49dbfa7b
LP
2457 char **documentation;
2458
1b64d026
LP
2459 const char *fragment_path;
2460 const char *source_path;
4ad49000 2461 const char *control_group;
61cbdc4b 2462
76d14b87
OS
2463 char **dropin_paths;
2464
9f39404c 2465 const char *load_error;
f42806df 2466 const char *result;
9f39404c 2467
584be568 2468 usec_t inactive_exit_timestamp;
df50185b 2469 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
2470 usec_t active_enter_timestamp;
2471 usec_t active_exit_timestamp;
2472 usec_t inactive_enter_timestamp;
2473
45fb0699
LP
2474 bool need_daemon_reload;
2475
61cbdc4b
LP
2476 /* Service */
2477 pid_t main_pid;
2478 pid_t control_pid;
2479 const char *status_text;
175728c4 2480 const char *pid_file;
d06dacd0 2481 bool running:1;
61cbdc4b
LP
2482
2483 usec_t start_timestamp;
2484 usec_t exit_timestamp;
2485
2486 int exit_code, exit_status;
2487
90bbc946
LP
2488 usec_t condition_timestamp;
2489 bool condition_result;
52990c2e
ZJS
2490 bool failed_condition_trigger;
2491 bool failed_condition_negate;
2492 const char *failed_condition;
2493 const char *failed_condition_param;
90bbc946 2494
61cbdc4b
LP
2495 /* Socket */
2496 unsigned n_accepted;
2497 unsigned n_connections;
b8131a87 2498 bool accept;
61cbdc4b 2499
13160134 2500 /* Pairs of type, path */
67419600
OS
2501 char **listen;
2502
61cbdc4b
LP
2503 /* Device */
2504 const char *sysfs_path;
2505
2506 /* Mount, Automount */
2507 const char *where;
2508
2509 /* Swap */
2510 const char *what;
582a507f
LP
2511
2512 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
2513} UnitStatusInfo;
2514
94e0bd7d
ZJS
2515static void print_status_info(UnitStatusInfo *i,
2516 bool *ellipsized) {
582a507f 2517 ExecStatusInfo *p;
2ee68f72 2518 const char *on, *off, *ss;
584be568 2519 usec_t timestamp;
9185c8e6 2520 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
584be568 2521 char since2[FORMAT_TIMESTAMP_MAX], *s2;
1b64d026 2522 const char *path;
9bdbc2e2
LN
2523 int flags =
2524 arg_all * OUTPUT_SHOW_ALL |
2525 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
2526 on_tty() * OUTPUT_COLOR |
2527 !arg_quiet * OUTPUT_WARN_CUTOFF |
2528 arg_full * OUTPUT_FULL_WIDTH;
13160134 2529 char **t, **t2;
582a507f 2530
61cbdc4b
LP
2531 assert(i);
2532
2533 /* This shows pretty information about a unit. See
2534 * print_property() for a low-level property printer */
2535
2536 printf("%s", strna(i->id));
2537
2538 if (i->description && !streq_ptr(i->id, i->description))
2539 printf(" - %s", i->description);
2540
2541 printf("\n");
2542
4a9e2fff 2543 if (i->following)
856323c9 2544 printf(" Follow: unit currently follows state of %s\n", i->following);
4a9e2fff 2545
f7b9e331 2546 if (streq_ptr(i->load_state, "error")) {
0b5a519c
DS
2547 on = ansi_highlight_red();
2548 off = ansi_highlight_off();
c31b4423
LP
2549 } else
2550 on = off = "";
2551
1b64d026
LP
2552 path = i->source_path ? i->source_path : i->fragment_path;
2553
9f39404c 2554 if (i->load_error)
856323c9
ZJS
2555 printf(" Loaded: %s%s%s (Reason: %s)\n",
2556 on, strna(i->load_state), off, i->load_error);
1b64d026 2557 else if (path && i->unit_file_state)
856323c9
ZJS
2558 printf(" Loaded: %s%s%s (%s; %s)\n",
2559 on, strna(i->load_state), off, path, i->unit_file_state);
1b64d026 2560 else if (path)
856323c9
ZJS
2561 printf(" Loaded: %s%s%s (%s)\n",
2562 on, strna(i->load_state), off, path);
61cbdc4b 2563 else
856323c9
ZJS
2564 printf(" Loaded: %s%s%s\n",
2565 on, strna(i->load_state), off);
61cbdc4b 2566
76d14b87
OS
2567 if (!strv_isempty(i->dropin_paths)) {
2568 char ** dropin;
2569 char * dir = NULL;
2570 bool last = false;
2571
2572 STRV_FOREACH(dropin, i->dropin_paths) {
2573 if (! dir || last) {
856323c9 2574 printf(dir ? " " : " Drop-In: ");
76d14b87
OS
2575
2576 free(dir);
2577
2578 if (path_get_parent(*dropin, &dir) < 0) {
2579 log_oom();
2580 return;
2581 }
2582
856323c9 2583 printf("%s\n %s", dir,
76d14b87
OS
2584 draw_special_char(DRAW_TREE_RIGHT));
2585 }
2586
2587 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
2588
2589 printf("%s%s", path_get_file_name(*dropin), last ? "\n" : ", ");
2590 }
2591
2592 free(dir);
2593 }
2594
2ee68f72
LP
2595 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2596
fdf20a31 2597 if (streq_ptr(i->active_state, "failed")) {
0b5a519c
DS
2598 on = ansi_highlight_red();
2599 off = ansi_highlight_off();
2ee68f72 2600 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
0b5a519c
DS
2601 on = ansi_highlight_green();
2602 off = ansi_highlight_off();
2ee68f72
LP
2603 } else
2604 on = off = "";
2605
2606 if (ss)
856323c9
ZJS
2607 printf(" Active: %s%s (%s)%s",
2608 on, strna(i->active_state), ss, off);
2ee68f72 2609 else
856323c9
ZJS
2610 printf(" Active: %s%s%s",
2611 on, strna(i->active_state), off);
61cbdc4b 2612
f42806df
LP
2613 if (!isempty(i->result) && !streq(i->result, "success"))
2614 printf(" (Result: %s)", i->result);
2615
584be568
LP
2616 timestamp = (streq_ptr(i->active_state, "active") ||
2617 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2618 (streq_ptr(i->active_state, "inactive") ||
fdf20a31 2619 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
584be568
LP
2620 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2621 i->active_exit_timestamp;
2622
bbb8486e 2623 s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
584be568
LP
2624 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2625
2626 if (s1)
538da63d 2627 printf(" since %s; %s\n", s2, s1);
584be568 2628 else if (s2)
538da63d 2629 printf(" since %s\n", s2);
584be568
LP
2630 else
2631 printf("\n");
2632
90bbc946 2633 if (!i->condition_result && i->condition_timestamp > 0) {
bbb8486e 2634 s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
90bbc946
LP
2635 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2636
52990c2e
ZJS
2637 printf(" start condition failed at %s%s%s\n",
2638 s2, s1 ? "; " : "", s1 ? s1 : "");
2639 if (i->failed_condition_trigger)
2640 printf(" none of the trigger conditions were met\n");
2641 else if (i->failed_condition)
2642 printf(" %s=%s%s was not met\n",
2643 i->failed_condition,
2644 i->failed_condition_negate ? "!" : "",
2645 i->failed_condition_param);
90bbc946
LP
2646 }
2647
61cbdc4b 2648 if (i->sysfs_path)
856323c9 2649 printf(" Device: %s\n", i->sysfs_path);
9feeba4b 2650 if (i->where)
856323c9 2651 printf(" Where: %s\n", i->where);
9feeba4b 2652 if (i->what)
856323c9 2653 printf(" What: %s\n", i->what);
49dbfa7b 2654
13160134 2655 STRV_FOREACH(t, i->documentation)
856323c9 2656 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", *t);
49dbfa7b 2657
13160134 2658 STRV_FOREACH_PAIR(t, t2, i->listen)
856323c9 2659 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
67419600 2660
b8131a87 2661 if (i->accept)
856323c9 2662 printf(" Accepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
61cbdc4b 2663
582a507f 2664 LIST_FOREACH(exec, p, i->exec) {
13160134 2665 _cleanup_free_ char *argv = NULL;
9a57c629 2666 bool good;
582a507f
LP
2667
2668 /* Only show exited processes here */
2669 if (p->code == 0)
2670 continue;
2671
13160134 2672 argv = strv_join(p->argv, " ");
856323c9 2673 printf(" Process: %u %s=%s ", p->pid, p->name, strna(argv));
582a507f 2674
96342de6 2675 good = is_clean_exit_lsb(p->code, p->status, NULL);
9a57c629 2676 if (!good) {
0b5a519c
DS
2677 on = ansi_highlight_red();
2678 off = ansi_highlight_off();
9a57c629
LP
2679 } else
2680 on = off = "";
2681
2682 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2683
d06dacd0
LP
2684 if (p->code == CLD_EXITED) {
2685 const char *c;
2686
582a507f 2687 printf("status=%i", p->status);
d06dacd0 2688
1b64d026
LP
2689 c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD);
2690 if (c)
d06dacd0
LP
2691 printf("/%s", c);
2692
2693 } else
582a507f 2694 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
2695
2696 printf(")%s\n", off);
2697
582a507f
LP
2698 if (i->main_pid == p->pid &&
2699 i->start_timestamp == p->start_timestamp &&
2700 i->exit_timestamp == p->start_timestamp)
2701 /* Let's not show this twice */
2702 i->main_pid = 0;
2703
2704 if (p->pid == i->control_pid)
2705 i->control_pid = 0;
2706 }
2707
61cbdc4b 2708 if (i->main_pid > 0 || i->control_pid > 0) {
61cbdc4b 2709 if (i->main_pid > 0) {
856323c9 2710 printf(" Main PID: %u", (unsigned) i->main_pid);
61cbdc4b
LP
2711
2712 if (i->running) {
13160134
ZJS
2713 _cleanup_free_ char *comm = NULL;
2714 get_process_comm(i->main_pid, &comm);
2715 if (comm)
2716 printf(" (%s)", comm);
6d4fc029 2717 } else if (i->exit_code > 0) {
61cbdc4b
LP
2718 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2719
d06dacd0
LP
2720 if (i->exit_code == CLD_EXITED) {
2721 const char *c;
2722
61cbdc4b 2723 printf("status=%i", i->exit_status);
d06dacd0 2724
1b64d026
LP
2725 c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD);
2726 if (c)
d06dacd0
LP
2727 printf("/%s", c);
2728
2729 } else
582a507f 2730 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
2731 printf(")");
2732 }
61cbdc4b 2733
13160134
ZJS
2734 if (i->control_pid > 0)
2735 printf(";");
2736 }
61cbdc4b
LP
2737
2738 if (i->control_pid > 0) {
13160134 2739 _cleanup_free_ char *c = NULL;
61cbdc4b 2740
856323c9 2741 printf(" %8s: %u", i->main_pid ? "" : " Control", (unsigned) i->control_pid);
61cbdc4b 2742
13160134
ZJS
2743 get_process_comm(i->control_pid, &c);
2744 if (c)
2745 printf(" (%s)", c);
61cbdc4b
LP
2746 }
2747
2748 printf("\n");
2749 }
2750
17bb7382 2751 if (i->status_text)
856323c9 2752 printf(" Status: \"%s\"\n", i->status_text);
17bb7382 2753
4ad49000 2754 if (i->control_group &&
042f9f5e 2755 (i->main_pid > 0 || i->control_pid > 0 || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group, false) == 0)) {
ab35fb1b
LP
2756 unsigned c;
2757
4ad49000 2758 printf(" CGroup: %s\n", i->control_group);
ab35fb1b 2759
a8f11321 2760 if (arg_transport != TRANSPORT_SSH) {
b69d29ce
LP
2761 unsigned k = 0;
2762 pid_t extra[2];
856323c9 2763 char prefix[] = " ";
b69d29ce
LP
2764
2765 c = columns();
e8853816
ZJS
2766 if (c > sizeof(prefix) - 1)
2767 c -= sizeof(prefix) - 1;
a8f11321
LP
2768 else
2769 c = 0;
ab35fb1b 2770
b69d29ce
LP
2771 if (i->main_pid > 0)
2772 extra[k++] = i->main_pid;
2773
2774 if (i->control_pid > 0)
2775 extra[k++] = i->control_pid;
2776
a00963a2 2777 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix,
e8853816 2778 c, false, extra, k, flags);
a8f11321 2779 }
c59760ee 2780 }
45fb0699 2781
6f003b43
LP
2782 if (i->id && arg_transport != TRANSPORT_SSH) {
2783 printf("\n");
886a64fe
ZJS
2784 show_journal_by_unit(stdout,
2785 i->id,
2786 arg_output,
2787 0,
2788 i->inactive_exit_timestamp_monotonic,
2789 arg_lines,
2790 getuid(),
2791 flags,
94e0bd7d
ZJS
2792 arg_scope == UNIT_FILE_SYSTEM,
2793 ellipsized);
6f003b43 2794 }
86aa7ba4 2795
45fb0699 2796 if (i->need_daemon_reload)
1058cbf2 2797 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
0b5a519c
DS
2798 ansi_highlight_red(),
2799 ansi_highlight_off(),
1058cbf2 2800 arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
61cbdc4b
LP
2801}
2802
b43f208f 2803static void show_unit_help(UnitStatusInfo *i) {
256425cc
LP
2804 char **p;
2805
2806 assert(i);
2807
2808 if (!i->documentation) {
2809 log_info("Documentation for %s not known.", i->id);
2810 return;
2811 }
2812
2813 STRV_FOREACH(p, i->documentation) {
2814
2815 if (startswith(*p, "man:")) {
2816 size_t k;
2817 char *e = NULL;
7fd1b19b 2818 _cleanup_free_ char *page = NULL, *section = NULL;
256425cc
LP
2819 const char *args[4] = { "man", NULL, NULL, NULL };
2820 pid_t pid;
2821
2822 k = strlen(*p);
2823
2824 if ((*p)[k-1] == ')')
2825 e = strrchr(*p, '(');
2826
2827 if (e) {
2828 page = strndup((*p) + 4, e - *p - 4);
256425cc 2829 section = strndup(e + 1, *p + k - e - 2);
cec7eda5 2830 if (!page || !section) {
0d0f0c50 2831 log_oom();
256425cc
LP
2832 return;
2833 }
2834
2835 args[1] = section;
2836 args[2] = page;
2837 } else
2838 args[1] = *p + 4;
2839
2840 pid = fork();
2841 if (pid < 0) {
2842 log_error("Failed to fork: %m");
256425cc
LP
2843 continue;
2844 }
2845
2846 if (pid == 0) {
2847 /* Child */
2848 execvp(args[0], (char**) args);
2849 log_error("Failed to execute man: %m");
2850 _exit(EXIT_FAILURE);
2851 }
2852
256425cc
LP
2853 wait_for_terminate(pid, NULL);
2854 } else
0315fe37 2855 log_info("Can't show: %s", *p);
256425cc
LP
2856 }
2857}
2858
61cbdc4b
LP
2859static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2860
a4c279f8
LP
2861 assert(name);
2862 assert(iter);
2863 assert(i);
2864
61cbdc4b
LP
2865 switch (dbus_message_iter_get_arg_type(iter)) {
2866
2867 case DBUS_TYPE_STRING: {
2868 const char *s;
2869
2870 dbus_message_iter_get_basic(iter, &s);
2871
a4c279f8 2872 if (!isempty(s)) {
61cbdc4b
LP
2873 if (streq(name, "Id"))
2874 i->id = s;
2875 else if (streq(name, "LoadState"))
2876 i->load_state = s;
2877 else if (streq(name, "ActiveState"))
2878 i->active_state = s;
2879 else if (streq(name, "SubState"))
2880 i->sub_state = s;
2881 else if (streq(name, "Description"))
2882 i->description = s;
2883 else if (streq(name, "FragmentPath"))
1b64d026
LP
2884 i->fragment_path = s;
2885 else if (streq(name, "SourcePath"))
2886 i->source_path = s;
286ca485 2887#ifndef NOLEGACY
a00963a2
LP
2888 else if (streq(name, "DefaultControlGroup")) {
2889 const char *e;
2890 e = startswith(s, SYSTEMD_CGROUP_CONTROLLER ":");
2891 if (e)
2892 i->control_group = e;
2893 }
4ad49000
LP
2894#endif
2895 else if (streq(name, "ControlGroup"))
2896 i->control_group = s;
61cbdc4b
LP
2897 else if (streq(name, "StatusText"))
2898 i->status_text = s;
175728c4
HH
2899 else if (streq(name, "PIDFile"))
2900 i->pid_file = s;
61cbdc4b
LP
2901 else if (streq(name, "SysFSPath"))
2902 i->sysfs_path = s;
2903 else if (streq(name, "Where"))
2904 i->where = s;
2905 else if (streq(name, "What"))
2906 i->what = s;
4a9e2fff
LP
2907 else if (streq(name, "Following"))
2908 i->following = s;
a4375746
LP
2909 else if (streq(name, "UnitFileState"))
2910 i->unit_file_state = s;
f42806df
LP
2911 else if (streq(name, "Result"))
2912 i->result = s;
61cbdc4b
LP
2913 }
2914
2915 break;
2916 }
2917
b8131a87
LP
2918 case DBUS_TYPE_BOOLEAN: {
2919 dbus_bool_t b;
2920
2921 dbus_message_iter_get_basic(iter, &b);
2922
2923 if (streq(name, "Accept"))
2924 i->accept = b;
45fb0699
LP
2925 else if (streq(name, "NeedDaemonReload"))
2926 i->need_daemon_reload = b;
90bbc946
LP
2927 else if (streq(name, "ConditionResult"))
2928 i->condition_result = b;
b8131a87
LP
2929
2930 break;
2931 }
2932
61cbdc4b
LP
2933 case DBUS_TYPE_UINT32: {
2934 uint32_t u;
2935
2936 dbus_message_iter_get_basic(iter, &u);
2937
2938 if (streq(name, "MainPID")) {
2939 if (u > 0) {
2940 i->main_pid = (pid_t) u;
2941 i->running = true;
2942 }
2943 } else if (streq(name, "ControlPID"))
2944 i->control_pid = (pid_t) u;
2945 else if (streq(name, "ExecMainPID")) {
2946 if (u > 0)
2947 i->main_pid = (pid_t) u;
2948 } else if (streq(name, "NAccepted"))
2949 i->n_accepted = u;
2950 else if (streq(name, "NConnections"))
2951 i->n_connections = u;
2952
2953 break;
2954 }
2955
2956 case DBUS_TYPE_INT32: {
2957 int32_t j;
2958
2959 dbus_message_iter_get_basic(iter, &j);
2960
2961 if (streq(name, "ExecMainCode"))
2962 i->exit_code = (int) j;
2963 else if (streq(name, "ExecMainStatus"))
2964 i->exit_status = (int) j;
2965
2966 break;
2967 }
2968
2969 case DBUS_TYPE_UINT64: {
2970 uint64_t u;
2971
2972 dbus_message_iter_get_basic(iter, &u);
2973
2974 if (streq(name, "ExecMainStartTimestamp"))
2975 i->start_timestamp = (usec_t) u;
2976 else if (streq(name, "ExecMainExitTimestamp"))
2977 i->exit_timestamp = (usec_t) u;
584be568
LP
2978 else if (streq(name, "ActiveEnterTimestamp"))
2979 i->active_enter_timestamp = (usec_t) u;
2980 else if (streq(name, "InactiveEnterTimestamp"))
2981 i->inactive_enter_timestamp = (usec_t) u;
2982 else if (streq(name, "InactiveExitTimestamp"))
2983 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
2984 else if (streq(name, "InactiveExitTimestampMonotonic"))
2985 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
2986 else if (streq(name, "ActiveExitTimestamp"))
2987 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
2988 else if (streq(name, "ConditionTimestamp"))
2989 i->condition_timestamp = (usec_t) u;
61cbdc4b
LP
2990
2991 break;
2992 }
582a507f
LP
2993
2994 case DBUS_TYPE_ARRAY: {
2995
2996 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2997 startswith(name, "Exec")) {
2998 DBusMessageIter sub;
2999
3000 dbus_message_iter_recurse(iter, &sub);
3001 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3002 ExecStatusInfo *info;
3003 int r;
3004
52990c2e
ZJS
3005 info = new0(ExecStatusInfo, 1);
3006 if (!info)
582a507f
LP
3007 return -ENOMEM;
3008
52990c2e
ZJS
3009 info->name = strdup(name);
3010 if (!info->name) {
0129173a
LP
3011 free(info);
3012 return -ENOMEM;
3013 }
3014
52990c2e
ZJS
3015 r = exec_status_info_deserialize(&sub, info);
3016 if (r < 0) {
582a507f
LP
3017 free(info);
3018 return r;
3019 }
3020
3021 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
3022
49dbfa7b
LP
3023 dbus_message_iter_next(&sub);
3024 }
67419600 3025
52990c2e
ZJS
3026 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
3027 streq(name, "Listen")) {
67419600
OS
3028 DBusMessageIter sub, sub2;
3029
3030 dbus_message_iter_recurse(iter, &sub);
3031 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3032 const char *type, *path;
3033
3034 dbus_message_iter_recurse(&sub, &sub2);
3035
3036 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3037 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0) {
13160134
ZJS
3038 int r;
3039
3040 r = strv_extend(&i->listen, type);
3041 if (r < 0)
3042 return r;
3043 r = strv_extend(&i->listen, path);
3044 if (r < 0)
3045 return r;
67419600
OS
3046 }
3047
3048 dbus_message_iter_next(&sub);
3049 }
3050
3051 return 0;
3052
52990c2e
ZJS
3053 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
3054 streq(name, "DropInPaths")) {
76d14b87
OS
3055 int r = bus_parse_strv_iter(iter, &i->dropin_paths);
3056 if (r < 0)
3057 return r;
3058
49dbfa7b
LP
3059 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING &&
3060 streq(name, "Documentation")) {
3061
3062 DBusMessageIter sub;
3063
3064 dbus_message_iter_recurse(iter, &sub);
3065 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
3066 const char *s;
13160134 3067 int r;
49dbfa7b
LP
3068
3069 dbus_message_iter_get_basic(&sub, &s);
3070
13160134
ZJS
3071 r = strv_extend(&i->documentation, s);
3072 if (r < 0)
3073 return r;
49dbfa7b 3074
52990c2e
ZJS
3075 dbus_message_iter_next(&sub);
3076 }
3077
3078 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
3079 streq(name, "Conditions")) {
3080 DBusMessageIter sub, sub2;
3081
3082 dbus_message_iter_recurse(iter, &sub);
3083 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3084 const char *cond, *param;
3085 dbus_bool_t trigger, negate;
3086 dbus_int32_t state;
3087
3088 dbus_message_iter_recurse(&sub, &sub2);
3089 log_debug("here");
3090
3091 if(bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &cond, true) >= 0 &&
3092 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &trigger, true) >= 0 &&
3093 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &negate, true) >= 0 &&
3094 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &param, true) >= 0 &&
3095 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &state, false) >= 0) {
3096 log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
3097 if (state < 0 && (!trigger || !i->failed_condition)) {
3098 i->failed_condition = cond;
3099 i->failed_condition_trigger = trigger;
3100 i->failed_condition_negate = negate;
3101 i->failed_condition_param = param;
3102 }
3103 }
3104
582a507f
LP
3105 dbus_message_iter_next(&sub);
3106 }
3107 }
3108
3109 break;
3110 }
9f39404c
LP
3111
3112 case DBUS_TYPE_STRUCT: {
3113
3114 if (streq(name, "LoadError")) {
3115 DBusMessageIter sub;
3116 const char *n, *message;
3117 int r;
3118
3119 dbus_message_iter_recurse(iter, &sub);
3120
3121 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
3122 if (r < 0)
3123 return r;
3124
3125 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
3126 if (r < 0)
3127 return r;
3128
3129 if (!isempty(message))
3130 i->load_error = message;
3131 }
3132
3133 break;
3134 }
61cbdc4b
LP
3135 }
3136
3137 return 0;
3138}
3139
48220598
LP
3140static int print_property(const char *name, DBusMessageIter *iter) {
3141 assert(name);
3142 assert(iter);
3143
61cbdc4b
LP
3144 /* This is a low-level property printer, see
3145 * print_status_info() for the nicer output */
3146
20b3f379 3147 if (arg_properties && !strv_find(arg_properties, name))
48220598
LP
3148 return 0;
3149
3150 switch (dbus_message_iter_get_arg_type(iter)) {
3151
48220598
LP
3152 case DBUS_TYPE_STRUCT: {
3153 DBusMessageIter sub;
3154 dbus_message_iter_recurse(iter, &sub);
3155
ebf57b80 3156 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
3157 uint32_t u;
3158
3159 dbus_message_iter_get_basic(&sub, &u);
3160
3161 if (u)
3162 printf("%s=%u\n", name, (unsigned) u);
3163 else if (arg_all)
3164 printf("%s=\n", name);
3165
3166 return 0;
ebf57b80 3167 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
3168 const char *s;
3169
3170 dbus_message_iter_get_basic(&sub, &s);
3171
3172 if (arg_all || s[0])
3173 printf("%s=%s\n", name, s);
3174
3175 return 0;
9f39404c
LP
3176 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
3177 const char *a = NULL, *b = NULL;
3178
f786e80d 3179 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
9f39404c
LP
3180 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
3181
3182 if (arg_all || !isempty(a) || !isempty(b))
3183 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
f786e80d
LP
3184
3185 return 0;
48220598
LP
3186 }
3187
3188 break;
3189 }
3190
3191 case DBUS_TYPE_ARRAY:
3192
a4c279f8 3193 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
8c7be95e
LP
3194 DBusMessageIter sub, sub2;
3195
3196 dbus_message_iter_recurse(iter, &sub);
3197 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3198 const char *path;
3199 dbus_bool_t ignore;
3200
3201 dbus_message_iter_recurse(&sub, &sub2);
3202
3203 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3204 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
ecdcbc5e 3205 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
8c7be95e
LP
3206
3207 dbus_message_iter_next(&sub);
3208 }
3209
3210 return 0;
3211
ebf57b80
LP
3212 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
3213 DBusMessageIter sub, sub2;
3214
3215 dbus_message_iter_recurse(iter, &sub);
67419600 3216
ebf57b80
LP
3217 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3218 const char *type, *path;
3219
3220 dbus_message_iter_recurse(&sub, &sub2);
3221
3222 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3223 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3224 printf("%s=%s\n", type, path);
3225
3226 dbus_message_iter_next(&sub);
3227 }
3228
707e5e52 3229 return 0;
582a507f 3230
67419600
OS
3231 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Listen")) {
3232 DBusMessageIter sub, sub2;
3233
3234 dbus_message_iter_recurse(iter, &sub);
3235 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3236 const char *type, *path;
3237
3238 dbus_message_iter_recurse(&sub, &sub2);
3239
3240 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
3241 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
3242 printf("Listen%s=%s\n", type, path);
3243
3244 dbus_message_iter_next(&sub);
3245 }
3246
3247 return 0;
3248
707e5e52
LP
3249 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
3250 DBusMessageIter sub, sub2;
3251
3252 dbus_message_iter_recurse(iter, &sub);
707e5e52
LP
3253 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3254 const char *base;
3255 uint64_t value, next_elapse;
3256
3257 dbus_message_iter_recurse(&sub, &sub2);
3258
3259 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
3260 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
552e4331
LP
3261 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
3262 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
3263
3264 printf("%s={ value=%s ; next_elapse=%s }\n",
fe68089d 3265 base,
2fa4092c
LP
3266 format_timespan(timespan1, sizeof(timespan1), value, 0),
3267 format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
552e4331 3268 }
fe68089d
LP
3269
3270 dbus_message_iter_next(&sub);
3271 }
3272
3273 return 0;
fe68089d 3274
582a507f
LP
3275 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
3276 DBusMessageIter sub;
fe68089d
LP
3277
3278 dbus_message_iter_recurse(iter, &sub);
fe68089d 3279 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
b92bea5d 3280 ExecStatusInfo info = {};
fe68089d 3281
582a507f 3282 if (exec_status_info_deserialize(&sub, &info) >= 0) {
fe68089d 3283 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
7fd1b19b 3284 _cleanup_free_ char *t;
582a507f
LP
3285
3286 t = strv_join(info.argv, " ");
3287
ecdcbc5e 3288 printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid=%u ; code=%s ; status=%i%s%s }\n",
582a507f
LP
3289 name,
3290 strna(info.path),
3291 strna(t),
b708e7ce 3292 yes_no(info.ignore),
582a507f
LP
3293 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
3294 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
3295 (unsigned) info. pid,
3296 sigchld_code_to_string(info.code),
3297 info.status,
3298 info.code == CLD_EXITED ? "" : "/",
3299 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d
LP
3300 }
3301
582a507f
LP
3302 free(info.path);
3303 strv_free(info.argv);
707e5e52
LP
3304
3305 dbus_message_iter_next(&sub);
3306 }
3307
48220598 3308 return 0;
4ad49000
LP
3309
3310 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "DeviceAllow")) {
3311 DBusMessageIter sub, sub2;
3312
3313 dbus_message_iter_recurse(iter, &sub);
3314 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3315 const char *path, *rwm;
3316
3317 dbus_message_iter_recurse(&sub, &sub2);
3318
3319 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3320 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &rwm, false) >= 0)
3321 printf("%s=%s %s\n", name, strna(path), strna(rwm));
3322
3323 dbus_message_iter_next(&sub);
3324 }
3325 return 0;
3326
b8ab2dc6
G
3327 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "BlockIODeviceWeight")) {
3328 DBusMessageIter sub, sub2;
3329
3330 dbus_message_iter_recurse(iter, &sub);
3331 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3332 const char *path;
3333 uint64_t weight;
3334
3335 dbus_message_iter_recurse(&sub, &sub2);
3336
3337 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3338 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &weight, false) >= 0)
3339 printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
3340
3341 dbus_message_iter_next(&sub);
3342 }
3343 return 0;
3344
4ad49000
LP
3345 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
3346 DBusMessageIter sub, sub2;
3347
3348 dbus_message_iter_recurse(iter, &sub);
3349 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
3350 const char *path;
3351 uint64_t bandwidth;
3352
3353 dbus_message_iter_recurse(&sub, &sub2);
3354
3355 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
3356 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &bandwidth, false) >= 0)
3357 printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
3358
3359 dbus_message_iter_next(&sub);
3360 }
3361 return 0;
48220598
LP
3362 }
3363
4ad49000 3364
48220598
LP
3365 break;
3366 }
3367
a4c279f8
LP
3368 if (generic_print_property(name, iter, arg_all) > 0)
3369 return 0;
3370
48220598
LP
3371 if (arg_all)
3372 printf("%s=[unprintable]\n", name);
3373
3374 return 0;
3375}
3376
94e0bd7d
ZJS
3377static int show_one(const char *verb,
3378 DBusConnection *bus,
3379 const char *path,
3380 bool show_properties,
3381 bool *new_line,
3382 bool *ellipsized) {
7fd1b19b 3383 _cleanup_free_ DBusMessage *reply = NULL;
48220598
LP
3384 const char *interface = "";
3385 int r;
48220598 3386 DBusMessageIter iter, sub, sub2, sub3;
b92bea5d 3387 UnitStatusInfo info = {};
582a507f 3388 ExecStatusInfo *p;
48220598 3389
48220598 3390 assert(path);
61cbdc4b 3391 assert(new_line);
48220598 3392
f84190d8 3393 r = bus_method_call_with_reply(
f22f08cd
SP
3394 bus,
3395 "org.freedesktop.systemd1",
3396 path,
3397 "org.freedesktop.DBus.Properties",
3398 "GetAll",
3399 &reply,
3400 NULL,
3401 DBUS_TYPE_STRING, &interface,
3402 DBUS_TYPE_INVALID);
f84190d8
LP
3403 if (r < 0)
3404 return r;
48220598
LP
3405
3406 if (!dbus_message_iter_init(reply, &iter) ||
3407 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3408 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
3409 log_error("Failed to parse reply.");
f84190d8 3410 return -EIO;
48220598
LP
3411 }
3412
3413 dbus_message_iter_recurse(&iter, &sub);
3414
61cbdc4b
LP
3415 if (*new_line)
3416 printf("\n");
3417
3418 *new_line = true;
3419
48220598
LP
3420 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3421 const char *name;
3422
f84190d8 3423 assert(dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY);
48220598 3424 dbus_message_iter_recurse(&sub, &sub2);
0183528f 3425
f84190d8
LP
3426 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
3427 dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
48220598 3428 log_error("Failed to parse reply.");
f84190d8 3429 return -EIO;
48220598
LP
3430 }
3431
3432 dbus_message_iter_recurse(&sub2, &sub3);
3433
61cbdc4b
LP
3434 if (show_properties)
3435 r = print_property(name, &sub3);
3436 else
3437 r = status_property(name, &sub3, &info);
61cbdc4b 3438 if (r < 0) {
48220598 3439 log_error("Failed to parse reply.");
f84190d8 3440 return -EIO;
48220598
LP
3441 }
3442
3443 dbus_message_iter_next(&sub);
3444 }
3445
f1e36d67
LP
3446 r = 0;
3447
256425cc 3448 if (!show_properties) {
b43f208f
KS
3449 if (streq(verb, "help"))
3450 show_unit_help(&info);
256425cc 3451 else
94e0bd7d 3452 print_status_info(&info, ellipsized);
256425cc 3453 }
f1e36d67 3454
49dbfa7b 3455 strv_free(info.documentation);
76d14b87 3456 strv_free(info.dropin_paths);
67419600 3457 strv_free(info.listen);
49dbfa7b 3458
22f4096c 3459 if (!streq_ptr(info.active_state, "active") &&
be8088a2 3460 !streq_ptr(info.active_state, "reloading") &&
3b05b8b3 3461 streq(verb, "status")) {
22f4096c 3462 /* According to LSB: "program not running" */
175728c4
HH
3463 /* 0: program is running or service is OK
3464 * 1: program is dead and /var/run pid file exists
3465 * 2: program is dead and /var/lock lock file exists
3466 * 3: program is not running
3467 * 4: program or service status is unknown
3468 */
3b05b8b3 3469 if (info.pid_file && access(info.pid_file, F_OK) == 0)
175728c4
HH
3470 r = 1;
3471 else
3472 r = 3;
e9c1ea9d 3473 }
61cbdc4b 3474
582a507f
LP
3475 while ((p = info.exec)) {
3476 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
3477 exec_status_info_free(p);
3478 }
3479
48220598
LP
3480 return r;
3481}
3482
94e0bd7d
ZJS
3483static int show_one_by_pid(const char *verb,
3484 DBusConnection *bus,
3485 uint32_t pid,
3486 bool *new_line,
3487 bool *ellipsized) {
f84190d8 3488 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
a223b325 3489 const char *path = NULL;
7fd1b19b 3490 _cleanup_dbus_error_free_ DBusError error;
a223b325
MS
3491 int r;
3492
3493 dbus_error_init(&error);
3494
f84190d8 3495 r = bus_method_call_with_reply(
f22f08cd
SP
3496 bus,
3497 "org.freedesktop.systemd1",
3498 "/org/freedesktop/systemd1",
3499 "org.freedesktop.systemd1.Manager",
3500 "GetUnitByPID",
3501 &reply,
3502 NULL,
3503 DBUS_TYPE_UINT32, &pid,
3504 DBUS_TYPE_INVALID);
f84190d8 3505 if (r < 0)
cec7eda5 3506 return r;
a223b325
MS
3507
3508 if (!dbus_message_get_args(reply, &error,
3509 DBUS_TYPE_OBJECT_PATH, &path,
3510 DBUS_TYPE_INVALID)) {
3511 log_error("Failed to parse reply: %s", bus_error_message(&error));
cec7eda5 3512 return -EIO;
a223b325
MS
3513 }
3514
94e0bd7d 3515 r = show_one(verb, bus, path, false, new_line, ellipsized);
a223b325
MS
3516 return r;
3517}
3518
94e0bd7d
ZJS
3519static int show_all(const char* verb,
3520 DBusConnection *bus,
3521 bool show_properties,
3522 bool *new_line,
3523 bool *ellipsized) {
265a7a2a
ZJS
3524 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
3525 _cleanup_free_ struct unit_info *unit_infos = NULL;
3526 unsigned c = 0;
3527 const struct unit_info *u;
3528 int r;
3529
3530 r = get_unit_list(bus, &reply, &unit_infos, &c);
3531 if (r < 0)
3532 return r;
3533
991f2a39
ZJS
3534 qsort(unit_infos, c, sizeof(struct unit_info), compare_unit_info);
3535
265a7a2a 3536 for (u = unit_infos; u < unit_infos + c; u++) {
7fd1b19b 3537 _cleanup_free_ char *p = NULL;
265a7a2a
ZJS
3538
3539 if (!output_show_unit(u))
3540 continue;
3541
3542 p = unit_dbus_path_from_name(u->id);
3543 if (!p)
3544 return log_oom();
3545
3546 printf("%s -> '%s'\n", u->id, p);
3547
94e0bd7d 3548 r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
265a7a2a
ZJS
3549 if (r != 0)
3550 return r;
3551 }
3552
3553 return 0;
3554}
3555
a223b325
MS
3556static int show(DBusConnection *bus, char **args) {
3557 int r, ret = 0;
265a7a2a 3558 bool show_properties, show_status, new_line = false;
729e3769 3559 char **name;
94e0bd7d 3560 bool ellipsized = false;
48220598
LP
3561
3562 assert(bus);
3563 assert(args);
3564
256425cc 3565 show_properties = streq(args[0], "show");
265a7a2a 3566 show_status = streq(args[0], "status");
61cbdc4b 3567
ec14911e 3568 if (show_properties)
1968a360 3569 pager_open_if_enabled();
ec14911e 3570
f84190d8 3571 /* If no argument is specified inspect the manager itself */
48220598 3572
f84190d8 3573 if (show_properties && strv_length(args) <= 1)
94e0bd7d 3574 return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
48220598 3575
265a7a2a 3576 if (show_status && strv_length(args) <= 1)
94e0bd7d
ZJS
3577 ret = show_all(args[0], bus, false, &new_line, &ellipsized);
3578 else
3579 STRV_FOREACH(name, args+1) {
3580 uint32_t id;
48220598 3581
94e0bd7d
ZJS
3582 if (safe_atou32(*name, &id) < 0) {
3583 _cleanup_free_ char *p = NULL, *n = NULL;
3584 /* Interpret as unit name */
48220598 3585
94e0bd7d
ZJS
3586 n = unit_name_mangle(*name);
3587 if (!n)
3588 return log_oom();
f84190d8 3589
94e0bd7d
ZJS
3590 p = unit_dbus_path_from_name(n);
3591 if (!p)
3592 return log_oom();
48220598 3593
94e0bd7d
ZJS
3594 r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
3595 if (r != 0)
3596 ret = r;
ed2d7a44 3597
94e0bd7d
ZJS
3598 } else if (show_properties) {
3599 _cleanup_free_ char *p = NULL;
598b557b 3600
94e0bd7d
ZJS
3601 /* Interpret as job id */
3602 if (asprintf(&p, "/org/freedesktop/systemd1/job/%u", id) < 0)
3603 return log_oom();
48220598 3604
94e0bd7d
ZJS
3605 r = show_one(args[0], bus, p, show_properties, &new_line, &ellipsized);
3606 if (r != 0)
3607 ret = r;
48220598 3608
94e0bd7d
ZJS
3609 } else {
3610 /* Interpret as PID */
3611 r = show_one_by_pid(args[0], bus, id, &new_line, &ellipsized);
3612 if (r != 0)
3613 ret = r;
3614 }
48220598 3615 }
94e0bd7d
ZJS
3616
3617 if (ellipsized && !arg_quiet)
3618 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
48220598 3619
22f4096c 3620 return ret;
0183528f
LP
3621}
3622
8e2af478
LP
3623static int append_assignment(DBusMessageIter *iter, const char *assignment) {
3624 const char *eq;
3625 char *field;
3626 DBusMessageIter sub;
3627 int r;
3628
3629 assert(iter);
3630 assert(assignment);
3631
3632 eq = strchr(assignment, '=');
3633 if (!eq) {
3634 log_error("Not an assignment: %s", assignment);
3635 return -EINVAL;
3636 }
3637
3638 field = strndupa(assignment, eq - assignment);
3639 eq ++;
3640
3641 if (!dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field))
3642 return log_oom();
3643
3644 if (streq(field, "CPUAccounting") ||
3645 streq(field, "MemoryAccounting") ||
3646 streq(field, "BlockIOAccounting")) {
3647 dbus_bool_t b;
3648
3649 r = parse_boolean(eq);
3650 if (r < 0) {
3651 log_error("Failed to parse boolean assignment %s.", assignment);
3652 return -EINVAL;
3653 }
3654
3655 b = r;
3656 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "b", &sub) ||
3657 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &b))
3658 return log_oom();
b42defe3
LP
3659
3660 } else if (streq(field, "MemoryLimit") || streq(field, "MemorySoftLimit")) {
3661 off_t bytes;
3662 uint64_t u;
3663
3664 r = parse_bytes(eq, &bytes);
3665 if (r < 0) {
3666 log_error("Failed to parse bytes specification %s", assignment);
3667 return -EINVAL;
3668 }
3669
3670 u = bytes;
3671 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
3672 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
3673 return log_oom();
3674
3675 } else if (streq(field, "CPUShares") || streq(field, "BlockIOWeight")) {
3676 uint64_t u;
3677
3678 r = safe_atou64(eq, &u);
3679 if (r < 0) {
3680 log_error("Failed to parse %s value %s.", field, eq);
3681 return -EINVAL;
3682 }
3683
3684 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "t", &sub) ||
3685 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT64, &u))
3686 return log_oom();
3687
7041efe9
LP
3688 } else if (streq(field, "DevicePolicy")) {
3689
3690 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "s", &sub) ||
3691 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &eq))
3692 return log_oom();
3693
3694 } else if (streq(field, "DeviceAllow")) {
3695 DBusMessageIter sub2;
3696
3697 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(ss)", &sub) ||
3698 !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(ss)", &sub2))
3699 return log_oom();
3700
3701 if (!isempty(eq)) {
3702 const char *path, *rwm;
3703 DBusMessageIter sub3;
3704 char *e;
3705
3706 e = strchr(eq, ' ');
3707 if (e) {
3708 path = strndupa(eq, e - eq);
3709 rwm = e+1;
3710 } else {
3711 path = eq;
3712 rwm = "";
3713 }
3714
67061256
G
3715 if (!path_startswith(path, "/dev")) {
3716 log_error("%s is not a device file in /dev.", path);
3717 return -EINVAL;
3718 }
3719
7041efe9
LP
3720 if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
3721 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
3722 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &rwm) ||
3723 !dbus_message_iter_close_container(&sub2, &sub3))
3724 return log_oom();
3725 }
3726
3727 if (!dbus_message_iter_close_container(&sub, &sub2))
3728 return log_oom();
3729
67061256
G
3730 } else if (streq(field, "BlockIOReadBandwidth") || streq(field, "BlockIOWriteBandwidth")) {
3731 DBusMessageIter sub2;
3732
3733 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) ||
3734 !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2))
3735 return log_oom();
3736
3737 if (!isempty(eq)) {
3738 const char *path, *bandwidth;
3739 DBusMessageIter sub3;
3740 uint64_t u;
3741 off_t bytes;
3742 char *e;
3743
3744 e = strchr(eq, ' ');
3745 if (e) {
3746 path = strndupa(eq, e - eq);
3747 bandwidth = e+1;
3748 } else {
3749 log_error("Failed to parse %s value %s.", field, eq);
3750 return -EINVAL;
3751 }
3752
3753 if (!path_startswith(path, "/dev")) {
3754 log_error("%s is not a device file in /dev.", path);
3755 return -EINVAL;
3756 }
3757
3758 r = parse_bytes(bandwidth, &bytes);
3759 if (r < 0) {
3760 log_error("Failed to parse byte value %s.", bandwidth);
3761 return -EINVAL;
3762 }
3763
3764 u = (uint64_t) bytes;
3765
3766 if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
3767 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
3768 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) ||
3769 !dbus_message_iter_close_container(&sub2, &sub3))
3770 return log_oom();
3771 }
3772
3773 if (!dbus_message_iter_close_container(&sub, &sub2))
3774 return log_oom();
3775
7239c170
G
3776 } else if (streq(field, "BlockIODeviceWeight")) {
3777 DBusMessageIter sub2;
3778
3779 if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(st)", &sub) ||
3780 !dbus_message_iter_open_container(&sub, DBUS_TYPE_ARRAY, "(st)", &sub2))
3781 return log_oom();
3782
3783 if (!isempty(eq)) {
3784 const char *path, *weight;
3785 DBusMessageIter sub3;
3786 uint64_t u;
3787 char *e;
3788
3789 e = strchr(eq, ' ');
3790 if (e) {
3791 path = strndupa(eq, e - eq);
3792 weight = e+1;
3793 } else {
3794 log_error("Failed to parse %s value %s.", field, eq);
3795 return -EINVAL;
3796 }
3797
3798 if (!path_startswith(path, "/dev")) {
3799 log_error("%s is not a device file in /dev.", path);
3800 return -EINVAL;
3801 }
3802
3803 r = safe_atou64(weight, &u);
3804 if (r < 0) {
3805 log_error("Failed to parse %s value %s.", field, weight);
3806 return -EINVAL;
3807 }
3808 if (!dbus_message_iter_open_container(&sub2, DBUS_TYPE_STRUCT, NULL, &sub3) ||
3809 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, &path) ||
3810 !dbus_message_iter_append_basic(&sub3, DBUS_TYPE_UINT64, &u) ||
3811 !dbus_message_iter_close_container(&sub2, &sub3))
3812 return log_oom();
3813 }
3814
3815 if (!dbus_message_iter_close_container(&sub, &sub2))
3816 return log_oom();
3817
8e2af478
LP
3818 } else {
3819 log_error("Unknown assignment %s.", assignment);
3820 return -EINVAL;
3821 }
3822
3823 if (!dbus_message_iter_close_container(iter, &sub))
3824 return log_oom();
3825
3826 return 0;
3827}
3828
3829static int set_property(DBusConnection *bus, char **args) {
3830
3831 _cleanup_free_ DBusMessage *m = NULL, *reply = NULL;
3832 DBusMessageIter iter, sub;
3833 dbus_bool_t runtime;
3834 DBusError error;
3835 char **i;
3836 int r;
3837
3838 dbus_error_init(&error);
3839
3840 m = dbus_message_new_method_call(
3841 "org.freedesktop.systemd1",
3842 "/org/freedesktop/systemd1",
3843 "org.freedesktop.systemd1.Manager",
3844 "SetUnitProperties");
3845 if (!m)
3846 return log_oom();
3847
3848 dbus_message_iter_init_append(m, &iter);
3849
3850 runtime = arg_runtime;
3851
3852 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &args[1]) ||
3853 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &runtime) ||
3854 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sv)", &sub))
3855 return log_oom();
3856
3857 STRV_FOREACH(i, args + 2) {
3858 DBusMessageIter sub2;
3859
3860 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
3861 return log_oom();
3862
3863 r = append_assignment(&sub2, *i);
3864 if (r < 0)
3865 return r;
3866
3867 if (!dbus_message_iter_close_container(&sub, &sub2))
3868 return log_oom();
3869
3870 }
3871
3872 if (!dbus_message_iter_close_container(&iter, &sub))
3873 return log_oom();
3874
3875 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3876 if (!reply) {
3877 log_error("Failed to issue method call: %s", bus_error_message(&error));
3878 dbus_error_free(&error);
3879 return -EIO;
3880 }
3881
3882 return 0;
3883}
3884
729e3769 3885static int snapshot(DBusConnection *bus, char **args) {
5dd9014f 3886 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
7e4249b9
LP
3887 DBusError error;
3888 int r;
7e4249b9
LP
3889 dbus_bool_t cleanup = FALSE;
3890 DBusMessageIter iter, sub;
3891 const char
1dcf6065 3892 *path, *id,
7e4249b9
LP
3893 *interface = "org.freedesktop.systemd1.Unit",
3894 *property = "Id";
5dd9014f 3895 _cleanup_free_ char *n = NULL;
7e4249b9
LP
3896
3897 dbus_error_init(&error);
3898
1dcf6065 3899 if (strv_length(args) > 1)
a016b922 3900 n = unit_name_mangle_with_suffix(args[1], ".snapshot");
1dcf6065
LP
3901 else
3902 n = strdup("");
3903 if (!n)
3904 return log_oom();
7e4249b9 3905
fb6becb4 3906 r = bus_method_call_with_reply(
f22f08cd
SP
3907 bus,
3908 "org.freedesktop.systemd1",
3909 "/org/freedesktop/systemd1",
3910 "org.freedesktop.systemd1.Manager",
3911 "CreateSnapshot",
3912 &reply,
3913 NULL,
1dcf6065 3914 DBUS_TYPE_STRING, &n,
f22f08cd
SP
3915 DBUS_TYPE_BOOLEAN, &cleanup,
3916 DBUS_TYPE_INVALID);
5dd9014f 3917 if (r < 0)
1dcf6065 3918 return r;
7e4249b9
LP
3919
3920 if (!dbus_message_get_args(reply, &error,
3921 DBUS_TYPE_OBJECT_PATH, &path,
3922 DBUS_TYPE_INVALID)) {
4cf5d675 3923 log_error("Failed to parse reply: %s", bus_error_message(&error));
1dcf6065
LP
3924 dbus_error_free(&error);
3925 return -EIO;
7e4249b9
LP
3926 }
3927
7e4249b9 3928 dbus_message_unref(reply);
5dd9014f
LP
3929 reply = NULL;
3930
f22f08cd
SP
3931 r = bus_method_call_with_reply (
3932 bus,
3933 "org.freedesktop.systemd1",
3934 path,
3935 "org.freedesktop.DBus.Properties",
3936 "Get",
3937 &reply,
3938 NULL,
3939 DBUS_TYPE_STRING, &interface,
3940 DBUS_TYPE_STRING, &property,
3941 DBUS_TYPE_INVALID);
5dd9014f 3942 if (r < 0)
1dcf6065 3943 return r;
7e4249b9
LP
3944
3945 if (!dbus_message_iter_init(reply, &iter) ||
3946 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3947 log_error("Failed to parse reply.");
1dcf6065 3948 return -EIO;
7e4249b9
LP
3949 }
3950
3951 dbus_message_iter_recurse(&iter, &sub);
3952
3953 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
3954 log_error("Failed to parse reply.");
1dcf6065 3955 return -EIO;
7e4249b9
LP
3956 }
3957
3958 dbus_message_iter_get_basic(&sub, &id);
0183528f
LP
3959
3960 if (!arg_quiet)
3961 puts(id);
7e4249b9 3962
1dcf6065 3963 return 0;
7e4249b9
LP
3964}
3965
729e3769 3966static int delete_snapshot(DBusConnection *bus, char **args) {
729e3769 3967 char **name;
6759e7a7 3968
6759e7a7
LP
3969 assert(args);
3970
729e3769 3971 STRV_FOREACH(name, args+1) {
5dd9014f
LP
3972 _cleanup_free_ char *n = NULL;
3973 int r;
6759e7a7 3974
a016b922 3975 n = unit_name_mangle_with_suffix(*name, ".snapshot");
1dcf6065
LP
3976 if (!n)
3977 return log_oom();
3978
5dd9014f 3979 r = bus_method_call_with_reply(
f22f08cd 3980 bus,
b0193f1c
LP
3981 "org.freedesktop.systemd1",
3982 "/org/freedesktop/systemd1",
3983 "org.freedesktop.systemd1.Manager",
5dd9014f 3984 "RemoveSnapshot",
f22f08cd
SP
3985 NULL,
3986 NULL,
1dcf6065 3987 DBUS_TYPE_STRING, &n,
f22f08cd 3988 DBUS_TYPE_INVALID);
5dd9014f
LP
3989 if (r < 0)
3990 return r;
6759e7a7
LP
3991 }
3992
5dd9014f 3993 return 0;
6759e7a7
LP
3994}
3995
729e3769 3996static int daemon_reload(DBusConnection *bus, char **args) {
7e4249b9
LP
3997 int r;
3998 const char *method;
c516c8d1 3999 DBusError error;
7e4249b9 4000
e4b61340
LP
4001 if (arg_action == ACTION_RELOAD)
4002 method = "Reload";
4003 else if (arg_action == ACTION_REEXEC)
4004 method = "Reexecute";
4005 else {
4006 assert(arg_action == ACTION_SYSTEMCTL);
4007
4008 method =
20b09ca7
LP
4009 streq(args[0], "clear-jobs") ||
4010 streq(args[0], "cancel") ? "ClearJobs" :
4011 streq(args[0], "daemon-reexec") ? "Reexecute" :
4012 streq(args[0], "reset-failed") ? "ResetFailed" :
4013 streq(args[0], "halt") ? "Halt" :
4014 streq(args[0], "poweroff") ? "PowerOff" :
4015 streq(args[0], "reboot") ? "Reboot" :
4016 streq(args[0], "kexec") ? "KExec" :
4017 streq(args[0], "exit") ? "Exit" :
4018 /* "daemon-reload" */ "Reload";
e4b61340 4019 }
7e4249b9 4020
1dcf6065 4021 r = bus_method_call_with_reply(
f22f08cd
SP
4022 bus,
4023 "org.freedesktop.systemd1",
4024 "/org/freedesktop/systemd1",
4025 "org.freedesktop.systemd1.Manager",
4026 method,
4027 NULL,
c516c8d1 4028 &error,
f22f08cd
SP
4029 DBUS_TYPE_INVALID);
4030
4031 if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
4032 /* There's always a fallback possible for
4033 * legacy actions. */
4034 r = -EADDRNOTAVAIL;
d0ede8f1
LP
4035 else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
4036 /* On reexecution, we expect a disconnect, not a
4037 * reply */
f22f08cd 4038 r = 0;
1dcf6065 4039 else if (r < 0)
c516c8d1 4040 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9 4041
1dcf6065 4042 dbus_error_free(&error);
7e4249b9
LP
4043 return r;
4044}
4045
729e3769 4046static int reset_failed(DBusConnection *bus, char **args) {
f22f08cd 4047 int r = 0;
f84190d8 4048 char **name;
5632e374 4049
729e3769
LP
4050 if (strv_length(args) <= 1)
4051 return daemon_reload(bus, args);
5632e374 4052
729e3769 4053 STRV_FOREACH(name, args+1) {
f84190d8
LP
4054 _cleanup_free_ char *n;
4055
f22f08cd 4056 n = unit_name_mangle(*name);
f84190d8
LP
4057 if (!n)
4058 return log_oom();
4059
4060 r = bus_method_call_with_reply(
f22f08cd 4061 bus,
b0193f1c
LP
4062 "org.freedesktop.systemd1",
4063 "/org/freedesktop/systemd1",
4064 "org.freedesktop.systemd1.Manager",
f22f08cd
SP
4065 "ResetFailedUnit",
4066 NULL,
4067 NULL,
f84190d8 4068 DBUS_TYPE_STRING, &n,
f22f08cd 4069 DBUS_TYPE_INVALID);
f84190d8
LP
4070 if (r < 0)
4071 return r;
5632e374
LP
4072 }
4073
f84190d8 4074 return 0;
5632e374
LP
4075}
4076
729e3769 4077static int show_enviroment(DBusConnection *bus, char **args) {
f84190d8 4078 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
7e4249b9
LP
4079 DBusMessageIter iter, sub, sub2;
4080 int r;
4081 const char
4082 *interface = "org.freedesktop.systemd1.Manager",
4083 *property = "Environment";
4084
1968a360 4085 pager_open_if_enabled();
ec14911e 4086
f84190d8 4087 r = bus_method_call_with_reply(
f22f08cd
SP
4088 bus,
4089 "org.freedesktop.systemd1",
4090 "/org/freedesktop/systemd1",
4091 "org.freedesktop.DBus.Properties",
4092 "Get",
4093 &reply,
4094 NULL,
4095 DBUS_TYPE_STRING, &interface,
4096 DBUS_TYPE_STRING, &property,
4097 DBUS_TYPE_INVALID);
f84190d8
LP
4098 if (r < 0)
4099 return r;
7e4249b9
LP
4100
4101 if (!dbus_message_iter_init(reply, &iter) ||
4102 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
4103 log_error("Failed to parse reply.");
f84190d8 4104 return -EIO;
7e4249b9
LP
4105 }
4106
4107 dbus_message_iter_recurse(&iter, &sub);
4108
4109 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
4110 dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
4111 log_error("Failed to parse reply.");
f84190d8 4112 return -EIO;
7e4249b9
LP
4113 }
4114
4115 dbus_message_iter_recurse(&sub, &sub2);
4116
4117 while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
4118 const char *text;
4119
4120 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
4121 log_error("Failed to parse reply.");
f84190d8 4122 return -EIO;
7e4249b9
LP
4123 }
4124
4125 dbus_message_iter_get_basic(&sub2, &text);
f84190d8 4126 puts(text);
7e4249b9
LP
4127
4128 dbus_message_iter_next(&sub2);
4129 }
4130
f84190d8 4131 return 0;
7e4249b9
LP
4132}
4133
957eb8ca 4134static int switch_root(DBusConnection *bus, char **args) {
957eb8ca 4135 unsigned l;
13068da8
TG
4136 const char *root;
4137 _cleanup_free_ char *init = NULL;
957eb8ca
LP
4138
4139 l = strv_length(args);
4140 if (l < 2 || l > 3) {
4141 log_error("Wrong number of arguments.");
4142 return -EINVAL;
4143 }
4144
4145 root = args[1];
13068da8
TG
4146
4147 if (l >= 3)
4148 init = strdup(args[2]);
4149 else {
4150 parse_env_file("/proc/cmdline", WHITESPACE,
4151 "init", &init,
4152 NULL);
4153
4154 if (!init)
4155 init = strdup("");
13068da8 4156 }
f84190d8
LP
4157 if (!init)
4158 return log_oom();
13068da8
TG
4159
4160 log_debug("switching root - root: %s; init: %s", root, init);
957eb8ca 4161
f84190d8 4162 return bus_method_call_with_reply(
f22f08cd 4163 bus,
957eb8ca
LP
4164 "org.freedesktop.systemd1",
4165 "/org/freedesktop/systemd1",
4166 "org.freedesktop.systemd1.Manager",
f22f08cd
SP
4167 "SwitchRoot",
4168 NULL,
4169 NULL,
4170 DBUS_TYPE_STRING, &root,
4171 DBUS_TYPE_STRING, &init,
4172 DBUS_TYPE_INVALID);
957eb8ca
LP
4173}
4174
729e3769 4175static int set_environment(DBusConnection *bus, char **args) {
31e767f7 4176 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
7e4249b9 4177 DBusError error;
7e4249b9 4178 const char *method;
31e767f7
LP
4179 DBusMessageIter iter;
4180 int r;
4181
4182 assert(bus);
60f9ba0b 4183 assert(args);
7e4249b9
LP
4184
4185 dbus_error_init(&error);
4186
4187 method = streq(args[0], "set-environment")
4188 ? "SetEnvironment"
4189 : "UnsetEnvironment";
4190
31e767f7
LP
4191 m = dbus_message_new_method_call(
4192 "org.freedesktop.systemd1",
4193 "/org/freedesktop/systemd1",
4194 "org.freedesktop.systemd1.Manager",
4195 method);
4196 if (!m)
4197 return log_oom();
7e4249b9
LP
4198
4199 dbus_message_iter_init_append(m, &iter);
4200
31e767f7
LP
4201 r = bus_append_strv_iter(&iter, args + 1);
4202 if (r < 0)
4203 return log_oom();
7e4249b9 4204
31e767f7
LP
4205 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4206 if (!reply) {
4cf5d675 4207 log_error("Failed to issue method call: %s", bus_error_message(&error));
f84190d8
LP
4208 dbus_error_free(&error);
4209 return -EIO;
7e4249b9
LP
4210 }
4211
f84190d8 4212 return 0;
7e4249b9
LP
4213}
4214
729e3769
LP
4215static int enable_sysv_units(char **args) {
4216 int r = 0;
ee5762e3 4217
77e68fa2 4218#if defined(HAVE_SYSV_COMPAT) && defined(HAVE_CHKCONFIG)
729e3769
LP
4219 const char *verb = args[0];
4220 unsigned f = 1, t = 1;
b92bea5d 4221 LookupPaths paths = {};
ee5762e3 4222
729e3769
LP
4223 if (arg_scope != UNIT_FILE_SYSTEM)
4224 return 0;
ee5762e3 4225
729e3769
LP
4226 if (!streq(verb, "enable") &&
4227 !streq(verb, "disable") &&
4228 !streq(verb, "is-enabled"))
4229 return 0;
ee5762e3 4230
729e3769
LP
4231 /* Processes all SysV units, and reshuffles the array so that
4232 * afterwards only the native units remain */
ee5762e3 4233
67445f4e 4234 r = lookup_paths_init(&paths, SYSTEMD_SYSTEM, false, NULL, NULL, NULL);
729e3769
LP
4235 if (r < 0)
4236 return r;
ee5762e3 4237
729e3769 4238 r = 0;
729e3769
LP
4239 for (f = 1; args[f]; f++) {
4240 const char *name;
7fd1b19b 4241 _cleanup_free_ char *p = NULL, *q = NULL;
729e3769
LP
4242 bool found_native = false, found_sysv;
4243 unsigned c = 1;
4244 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
4b6756a8 4245 char **k, *l;
729e3769
LP
4246 int j;
4247 pid_t pid;
4248 siginfo_t status;
ee5762e3 4249
729e3769 4250 name = args[f];
ee5762e3 4251
729e3769
LP
4252 if (!endswith(name, ".service"))
4253 continue;
ee5762e3 4254
729e3769
LP
4255 if (path_is_absolute(name))
4256 continue;
ee5762e3 4257
729e3769 4258 STRV_FOREACH(k, paths.unit_path) {
729e3769
LP
4259 if (!isempty(arg_root))
4260 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
4261 else
4262 asprintf(&p, "%s/%s", *k, name);
ee5762e3 4263
729e3769 4264 if (!p) {
0d0f0c50 4265 r = log_oom();
729e3769
LP
4266 goto finish;
4267 }
ee5762e3 4268
729e3769
LP
4269 found_native = access(p, F_OK) >= 0;
4270 free(p);
4b6756a8 4271 p = NULL;
ee5762e3 4272
729e3769
LP
4273 if (found_native)
4274 break;
4275 }
ee5762e3 4276
729e3769
LP
4277 if (found_native)
4278 continue;
ee5762e3 4279
729e3769
LP
4280 if (!isempty(arg_root))
4281 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
4282 else
4283 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
4284 if (!p) {
0d0f0c50 4285 r = log_oom();
729e3769
LP
4286 goto finish;
4287 }
ee5762e3 4288
729e3769
LP
4289 p[strlen(p) - sizeof(".service") + 1] = 0;
4290 found_sysv = access(p, F_OK) >= 0;
ee5762e3 4291
4b6756a8 4292 if (!found_sysv)
729e3769 4293 continue;
71fad675 4294
729e3769
LP
4295 /* Mark this entry, so that we don't try enabling it as native unit */
4296 args[f] = (char*) "";
ee5762e3 4297
729e3769 4298 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 4299
729e3769
LP
4300 if (!isempty(arg_root))
4301 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 4302
9eb977db 4303 argv[c++] = path_get_file_name(p);
729e3769
LP
4304 argv[c++] =
4305 streq(verb, "enable") ? "on" :
4306 streq(verb, "disable") ? "off" : "--level=5";
4307 argv[c] = NULL;
ee5762e3 4308
729e3769
LP
4309 l = strv_join((char**)argv, " ");
4310 if (!l) {
0d0f0c50 4311 r = log_oom();
729e3769
LP
4312 goto finish;
4313 }
ee5762e3 4314
729e3769
LP
4315 log_info("Executing %s", l);
4316 free(l);
ee5762e3 4317
729e3769
LP
4318 pid = fork();
4319 if (pid < 0) {
4320 log_error("Failed to fork: %m");
729e3769
LP
4321 r = -errno;
4322 goto finish;
4323 } else if (pid == 0) {
4324 /* Child */
ee5762e3 4325
729e3769
LP
4326 execv(argv[0], (char**) argv);
4327 _exit(EXIT_FAILURE);
4328 }
ee5762e3 4329
729e3769
LP
4330 j = wait_for_terminate(pid, &status);
4331 if (j < 0) {
4332 log_error("Failed to wait for child: %s", strerror(-r));
4333 r = j;
4334 goto finish;
4335 }
ee5762e3 4336
729e3769
LP
4337 if (status.si_code == CLD_EXITED) {
4338 if (streq(verb, "is-enabled")) {
4339 if (status.si_status == 0) {
4340 if (!arg_quiet)
4341 puts("enabled");
4342 r = 1;
4343 } else {
4344 if (!arg_quiet)
4345 puts("disabled");
4346 }
ee5762e3 4347
729e3769
LP
4348 } else if (status.si_status != 0) {
4349 r = -EINVAL;
4350 goto finish;
4351 }
4352 } else {
4353 r = -EPROTO;
4354 goto finish;
4355 }
ee5762e3
LP
4356 }
4357
729e3769
LP
4358finish:
4359 lookup_paths_free(&paths);
ee5762e3 4360
729e3769
LP
4361 /* Drop all SysV units */
4362 for (f = 1, t = 1; args[f]; f++) {
ee5762e3 4363
729e3769 4364 if (isempty(args[f]))
ee5762e3
LP
4365 continue;
4366
729e3769
LP
4367 args[t++] = args[f];
4368 }
ee5762e3 4369
729e3769 4370 args[t] = NULL;
ee5762e3 4371
729e3769
LP
4372#endif
4373 return r;
4374}
ee5762e3 4375
37370d0c 4376static int mangle_names(char **original_names, char ***mangled_names) {
a33fdebb 4377 char **i, **l, **name;
37370d0c 4378
a33fdebb
LP
4379 l = new(char*, strv_length(original_names) + 1);
4380 if (!l)
37370d0c
VP
4381 return log_oom();
4382
a33fdebb 4383 i = l;
37370d0c 4384 STRV_FOREACH(name, original_names) {
44386fc1
LN
4385
4386 /* When enabling units qualified path names are OK,
4387 * too, hence allow them explicitly. */
4388
4389 if (is_path(*name))
4390 *i = strdup(*name);
4391 else
4392 *i = unit_name_mangle(*name);
4393
a33fdebb
LP
4394 if (!*i) {
4395 strv_free(l);
37370d0c 4396 return log_oom();
a33fdebb
LP
4397 }
4398
4399 i++;
37370d0c 4400 }
a33fdebb
LP
4401
4402 *i = NULL;
4403 *mangled_names = l;
37370d0c
VP
4404
4405 return 0;
4406}
4407
729e3769
LP
4408static int enable_unit(DBusConnection *bus, char **args) {
4409 const char *verb = args[0];
4410 UnitFileChange *changes = NULL;
4411 unsigned n_changes = 0, i;
4412 int carries_install_info = -1;
7fd1b19b 4413 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
729e3769 4414 int r;
7fd1b19b
HH
4415 _cleanup_dbus_error_free_ DBusError error;
4416 _cleanup_strv_free_ char **mangled_names = NULL;
cec7eda5
ZJS
4417
4418 dbus_error_init(&error);
ee5762e3 4419
729e3769
LP
4420 r = enable_sysv_units(args);
4421 if (r < 0)
4422 return r;
ee5762e3 4423
ab5919fa
MS
4424 if (!args[1])
4425 return 0;
4426
3a05c0f9
VP
4427 r = mangle_names(args+1, &mangled_names);
4428 if (r < 0)
4429 goto finish;
4430
729e3769
LP
4431 if (!bus || avoid_bus()) {
4432 if (streq(verb, "enable")) {
3a05c0f9 4433 r = unit_file_enable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4434 carries_install_info = r;
4435 } else if (streq(verb, "disable"))
3a05c0f9 4436 r = unit_file_disable(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
729e3769 4437 else if (streq(verb, "reenable")) {
3a05c0f9 4438 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4439 carries_install_info = r;
4440 } else if (streq(verb, "link"))
3a05c0f9 4441 r = unit_file_link(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769 4442 else if (streq(verb, "preset")) {
3a05c0f9 4443 r = unit_file_preset(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769
LP
4444 carries_install_info = r;
4445 } else if (streq(verb, "mask"))
3a05c0f9 4446 r = unit_file_mask(arg_scope, arg_runtime, arg_root, mangled_names, arg_force, &changes, &n_changes);
729e3769 4447 else if (streq(verb, "unmask"))
3a05c0f9 4448 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, mangled_names, &changes, &n_changes);
99504dd4
VP
4449 else if (streq(verb, "set-default"))
4450 r = unit_file_set_default(arg_scope, arg_root, args[1], &changes, &n_changes);
729e3769
LP
4451 else
4452 assert_not_reached("Unknown verb");
ee5762e3 4453
729e3769
LP
4454 if (r < 0) {
4455 log_error("Operation failed: %s", strerror(-r));
4456 goto finish;
ee5762e3
LP
4457 }
4458
d1f262fa
LP
4459 if (!arg_quiet) {
4460 for (i = 0; i < n_changes; i++) {
4461 if (changes[i].type == UNIT_FILE_SYMLINK)
4462 log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
4463 else
4464 log_info("rm '%s'", changes[i].path);
4465 }
ee5762e3
LP
4466 }
4467
df77cdf0 4468 r = 0;
729e3769
LP
4469 } else {
4470 const char *method;
4471 bool send_force = true, expect_carries_install_info = false;
4472 dbus_bool_t a, b;
4473 DBusMessageIter iter, sub, sub2;
4474
4475 if (streq(verb, "enable")) {
4476 method = "EnableUnitFiles";
4477 expect_carries_install_info = true;
4478 } else if (streq(verb, "disable")) {
4479 method = "DisableUnitFiles";
4480 send_force = false;
4481 } else if (streq(verb, "reenable")) {
4482 method = "ReenableUnitFiles";
4483 expect_carries_install_info = true;
4484 } else if (streq(verb, "link"))
4485 method = "LinkUnitFiles";
4486 else if (streq(verb, "preset")) {
4487 method = "PresetUnitFiles";
4488 expect_carries_install_info = true;
4489 } else if (streq(verb, "mask"))
4490 method = "MaskUnitFiles";
4491 else if (streq(verb, "unmask")) {
4492 method = "UnmaskUnitFiles";
4493 send_force = false;
99504dd4
VP
4494 } else if (streq(verb, "set-default")) {
4495 method = "SetDefaultTarget";
729e3769
LP
4496 } else
4497 assert_not_reached("Unknown verb");
4498
4499 m = dbus_message_new_method_call(
4500 "org.freedesktop.systemd1",
4501 "/org/freedesktop/systemd1",
4502 "org.freedesktop.systemd1.Manager",
4503 method);
4504 if (!m) {
0d0f0c50 4505 r = log_oom();
ee5762e3
LP
4506 goto finish;
4507 }
4508
729e3769 4509 dbus_message_iter_init_append(m, &iter);
ee5762e3 4510
37370d0c 4511 r = bus_append_strv_iter(&iter, mangled_names);
729e3769
LP
4512 if (r < 0) {
4513 log_error("Failed to append unit files.");
ee5762e3
LP
4514 goto finish;
4515 }
4516
729e3769
LP
4517 a = arg_runtime;
4518 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
4519 log_error("Failed to append runtime boolean.");
ee5762e3
LP
4520 r = -ENOMEM;
4521 goto finish;
4522 }
4523
729e3769
LP
4524 if (send_force) {
4525 b = arg_force;
be394c48 4526
729e3769
LP
4527 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
4528 log_error("Failed to append force boolean.");
4529 r = -ENOMEM;
4530 goto finish;
4531 }
09adcdf7 4532 }
ee5762e3 4533
729e3769
LP
4534 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4535 if (!reply) {
4536 log_error("Failed to issue method call: %s", bus_error_message(&error));
4537 r = -EIO;
4538 goto finish;
ee5762e3
LP
4539 }
4540
729e3769
LP
4541 if (!dbus_message_iter_init(reply, &iter)) {
4542 log_error("Failed to initialize iterator.");
4543 goto finish;
4544 }
be394c48 4545
729e3769
LP
4546 if (expect_carries_install_info) {
4547 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4548 if (r < 0) {
4549 log_error("Failed to parse reply.");
4550 goto finish;
4551 }
ee5762e3 4552
729e3769 4553 carries_install_info = b;
ee5762e3
LP
4554 }
4555
729e3769
LP
4556 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4557 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
4558 log_error("Failed to parse reply.");
4559 r = -EIO;
4560 goto finish;
ee5762e3
LP
4561 }
4562
729e3769
LP
4563 dbus_message_iter_recurse(&iter, &sub);
4564 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4565 const char *type, *path, *source;
c8b2e52c 4566
729e3769
LP
4567 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4568 log_error("Failed to parse reply.");
4569 r = -EIO;
4570 goto finish;
c8b2e52c
LP
4571 }
4572
729e3769 4573 dbus_message_iter_recurse(&sub, &sub2);
c8b2e52c 4574
729e3769
LP
4575 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4576 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4577 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4578 log_error("Failed to parse reply.");
4579 r = -EIO;
4580 goto finish;
c8b2e52c
LP
4581 }
4582
d1f262fa
LP
4583 if (!arg_quiet) {
4584 if (streq(type, "symlink"))
4585 log_info("ln -s '%s' '%s'", source, path);
4586 else
4587 log_info("rm '%s'", path);
4588 }
b77398f7 4589
729e3769
LP
4590 dbus_message_iter_next(&sub);
4591 }
b77398f7 4592
729e3769 4593 /* Try to reload if enabeld */
d6cb60c7 4594 if (!arg_no_reload)
729e3769 4595 r = daemon_reload(bus, args);
b647f10d 4596 }
3d3961f2 4597
729e3769 4598 if (carries_install_info == 0)
416389f7
LP
4599 log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
4600 "using systemctl.\n"
4601 "Possible reasons for having this kind of units are:\n"
4602 "1) A unit may be statically enabled by being symlinked from another unit's\n"
4603 " .wants/ or .requires/ directory.\n"
4604 "2) A unit's purpose may be to act as a helper for some other unit which has\n"
4605 " a requirement dependency on it.\n"
4606 "3) A unit may be started when needed via activation (socket, path, timer,\n"
4607 " D-Bus, udev, scripted systemctl call, ...).\n");
ee5762e3 4608
729e3769 4609finish:
729e3769 4610 unit_file_changes_free(changes, n_changes);
ee5762e3 4611
729e3769 4612 return r;
ee5762e3
LP
4613}
4614
729e3769 4615static int unit_is_enabled(DBusConnection *bus, char **args) {
7fd1b19b 4616 _cleanup_dbus_error_free_ DBusError error;
ee5762e3 4617 int r;
7fd1b19b 4618 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
729e3769
LP
4619 bool enabled;
4620 char **name;
dec49d88 4621 char *n;
ee5762e3
LP
4622
4623 dbus_error_init(&error);
4624
729e3769
LP
4625 r = enable_sysv_units(args);
4626 if (r < 0)
4627 return r;
ee5762e3 4628
729e3769 4629 enabled = r > 0;
ee5762e3 4630
729e3769 4631 if (!bus || avoid_bus()) {
ee5762e3 4632
729e3769
LP
4633 STRV_FOREACH(name, args+1) {
4634 UnitFileState state;
ee5762e3 4635
dec49d88
LN
4636 n = unit_name_mangle(*name);
4637 if (!n)
4638 return log_oom();
4639
4640 state = unit_file_get_state(arg_scope, arg_root, n);
4641
4642 free(n);
4643
cec7eda5
ZJS
4644 if (state < 0)
4645 return state;
ee5762e3 4646
729e3769
LP
4647 if (state == UNIT_FILE_ENABLED ||
4648 state == UNIT_FILE_ENABLED_RUNTIME ||
4649 state == UNIT_FILE_STATIC)
4650 enabled = true;
4651
4652 if (!arg_quiet)
4653 puts(unit_file_state_to_string(state));
71fad675 4654 }
ee5762e3 4655
729e3769
LP
4656 } else {
4657 STRV_FOREACH(name, args+1) {
4658 const char *s;
63a723f3 4659
dec49d88
LN
4660 n = unit_name_mangle(*name);
4661 if (!n)
4662 return log_oom();
4663
f22f08cd
SP
4664 r = bus_method_call_with_reply (
4665 bus,
729e3769
LP
4666 "org.freedesktop.systemd1",
4667 "/org/freedesktop/systemd1",
4668 "org.freedesktop.systemd1.Manager",
f22f08cd
SP
4669 "GetUnitFileState",
4670 &reply,
4671 NULL,
dec49d88 4672 DBUS_TYPE_STRING, &n,
f22f08cd 4673 DBUS_TYPE_INVALID);
dec49d88
LN
4674
4675 free(n);
4676
f22f08cd 4677 if (r)
cec7eda5 4678 return r;
ee5762e3 4679
729e3769
LP
4680 if (!dbus_message_get_args(reply, &error,
4681 DBUS_TYPE_STRING, &s,
4682 DBUS_TYPE_INVALID)) {
4683 log_error("Failed to parse reply: %s", bus_error_message(&error));
cec7eda5 4684 return -EIO;
ee5762e3
LP
4685 }
4686
729e3769 4687 dbus_message_unref(reply);
f22f08cd 4688 reply = NULL;
ee5762e3 4689
729e3769
LP
4690 if (streq(s, "enabled") ||
4691 streq(s, "enabled-runtime") ||
4692 streq(s, "static"))
4693 enabled = true;
4694
4695 if (!arg_quiet)
4696 puts(s);
560d8f23 4697 }
ee5762e3
LP
4698 }
4699
cec7eda5 4700 return enabled ? 0 : 1;
ee5762e3
LP
4701}
4702
e4b61340 4703static int systemctl_help(void) {
7e4249b9 4704
729e3769
LP
4705 pager_open_if_enabled();
4706
2e33c433 4707 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 4708 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
4709 " -h --help Show this help\n"
4710 " --version Show package version\n"
4711 " -t --type=TYPE List only units of a particular type\n"
a521ae4a 4712 " --state=STATE List only units with particular LOAD or SUB or ACTIVE state\n"
8a0867d6 4713 " -p --property=NAME Show only properties by this name\n"
a5e4972c
LP
4714 " -a --all Show all loaded units/properties, including dead/empty\n"
4715 " ones. To list all units installed on the system, use\n"
4716 " the 'list-unit-files' command instead.\n"
afba4199 4717 " --reverse Show reverse dependencies with 'list-dependencies'\n"
98a6e132 4718 " -l --full Don't ellipsize unit names on output\n"
8a0867d6
LP
4719 " --fail When queueing a new job, fail if conflicting jobs are\n"
4720 " pending\n"
a521ae4a
LP
4721 " --irreversible When queueing a new job, make sure it cannot be implicitly\n"
4722 " cancelled\n"
e67c3609
LP
4723 " --ignore-dependencies\n"
4724 " When queueing a new job, ignore all its dependencies\n"
a521ae4a 4725 " --show-types When showing sockets, explicitly show their type\n"
b37844d3
LP
4726 " -i --ignore-inhibitors\n"
4727 " When shutting down or sleeping, ignore inhibitors\n"
a8f11321
LP
4728 " --kill-who=WHO Who to send signal to\n"
4729 " -s --signal=SIGNAL Which signal to send\n"
aca4c786 4730 " -H --host=[USER@]HOST\n"
a8f11321
LP
4731 " Show information for remote host\n"
4732 " -P --privileged Acquire privileges before execution\n"
8a0867d6
LP
4733 " -q --quiet Suppress output\n"
4734 " --no-block Do not wait until operation finished\n"
8a0867d6 4735 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
4736 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4737 " configuration\n"
ebed32bf 4738 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 4739 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
4740 " --no-ask-password\n"
4741 " Do not ask for system passwords\n"
a8f11321
LP
4742 " --system Connect to system manager\n"
4743 " --user Connect to user service manager\n"
4744 " --global Enable/disable unit files globally\n"
a521ae4a 4745 " --runtime Enable unit files only temporarily until next reboot\n"
8a0867d6
LP
4746 " -f --force When enabling unit files, override existing symlinks\n"
4747 " When shutting down, execute action immediately\n"
729e3769 4748 " --root=PATH Enable unit files in the specified root directory\n"
a521ae4a 4749 " -n --lines=INTEGER Numer of journal entries to show\n"
d3f2bdbf 4750 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
48383c25 4751 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
34c4b47b 4752 "Unit Commands:\n"
729e3769 4753 " list-units List loaded units\n"
3a256a12 4754 " list-sockets List loaded sockets ordered by address\n"
ee5762e3
LP
4755 " start [NAME...] Start (activate) one or more units\n"
4756 " stop [NAME...] Stop (deactivate) one or more units\n"
7e4249b9 4757 " reload [NAME...] Reload one or more units\n"
6f28c033
LP
4758 " restart [NAME...] Start or restart one or more units\n"
4759 " try-restart [NAME...] Restart one or more units if active\n"
d9847b32 4760 " reload-or-restart [NAME...] Reload one or more units if possible,\n"
6f28c033 4761 " otherwise start or restart\n"
d9847b32 4762 " reload-or-try-restart [NAME...] Reload one or more units if possible,\n"
6f28c033 4763 " otherwise restart if active\n"
7e4249b9 4764 " isolate [NAME] Start one unit and stop all others\n"
8a0867d6 4765 " kill [NAME...] Send signal to processes of a unit\n"
ee5762e3 4766 " is-active [NAME...] Check whether units are active\n"
1a0fce45 4767 " is-failed [NAME...] Check whether units are failed\n"
75676b72 4768 " status [NAME...|PID...] Show runtime status of one or more units\n"
6f28c033 4769 " show [NAME...|JOB...] Show properties of one or more\n"
ee5762e3 4770 " units/jobs or the manager\n"
8e2af478
LP
4771 " set-property [NAME] [ASSIGNMENT...]\n"
4772 " Sets one or more properties of a unit\n"
55c0b89c 4773 " help [NAME...|PID...] Show manual for one or more units\n"
fdf20a31
MM
4774 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4775 " units\n"
55c0b89c 4776 " list-dependencies [NAME] Recursively show units which are required\n"
afba4199
ZJS
4777 " or wanted by this unit or by which this\n"
4778 " unit is required or wanted\n\n"
34c4b47b 4779 "Unit File Commands:\n"
729e3769 4780 " list-unit-files List installed unit files\n"
ee5762e3
LP
4781 " enable [NAME...] Enable one or more unit files\n"
4782 " disable [NAME...] Disable one or more unit files\n"
729e3769
LP
4783 " reenable [NAME...] Reenable one or more unit files\n"
4784 " preset [NAME...] Enable/disable one or more unit files\n"
4785 " based on preset configuration\n"
a521ae4a 4786 " is-enabled [NAME...] Check whether unit files are enabled\n\n"
729e3769
LP
4787 " mask [NAME...] Mask one or more units\n"
4788 " unmask [NAME...] Unmask one or more units\n"
4789 " link [PATH...] Link one or more units files into\n"
4790 " the search path\n"
99504dd4 4791 " get-default Get the name of the default target\n"
f535088e 4792 " set-default NAME Set the default target\n\n"
34c4b47b 4793 "Job Commands:\n"
48220598 4794 " list-jobs List jobs\n"
34c4b47b 4795 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
34c4b47b 4796 "Snapshot Commands:\n"
7e4249b9 4797 " snapshot [NAME] Create a snapshot\n"
34c4b47b
LP
4798 " delete [NAME...] Remove one or more snapshots\n\n"
4799 "Environment Commands:\n"
7e4249b9
LP
4800 " show-environment Dump environment\n"
4801 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
a65615ca 4802 " unset-environment [NAME...] Unset one or more environment variables\n\n"
34c4b47b
LP
4803 "Manager Lifecycle Commands:\n"
4804 " daemon-reload Reload systemd manager configuration\n"
4805 " daemon-reexec Reexecute systemd manager\n\n"
4806 "System Commands:\n"
20b09ca7
LP
4807 " default Enter system default mode\n"
4808 " rescue Enter system rescue mode\n"
4809 " emergency Enter system emergency mode\n"
514f4ef5 4810 " halt Shut down and halt the system\n"
2e33c433 4811 " poweroff Shut down and power-off the system\n"
514f4ef5 4812 " reboot Shut down and reboot the system\n"
20b09ca7 4813 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 4814 " exit Request user instance exit\n"
957eb8ca 4815 " switch-root [ROOT] [INIT] Change to a different root file system\n"
6edd7d0a 4816 " suspend Suspend the system\n"
6524990f
LP
4817 " hibernate Hibernate the system\n"
4818 " hybrid-sleep Hibernate and suspend the system\n",
5b6319dc 4819 program_invocation_short_name);
7e4249b9
LP
4820
4821 return 0;
4822}
4823
e4b61340
LP
4824static int halt_help(void) {
4825
2e33c433 4826 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4827 "%s the system.\n\n"
4828 " --help Show this help\n"
4829 " --halt Halt the machine\n"
4830 " -p --poweroff Switch off the machine\n"
4831 " --reboot Reboot the machine\n"
2e33c433
LP
4832 " -f --force Force immediate halt/power-off/reboot\n"
4833 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 4834 " -d --no-wtmp Don't write wtmp record\n"
2e33c433 4835 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340
LP
4836 program_invocation_short_name,
4837 arg_action == ACTION_REBOOT ? "Reboot" :
4838 arg_action == ACTION_POWEROFF ? "Power off" :
4839 "Halt");
4840
4841 return 0;
4842}
4843
4844static int shutdown_help(void) {
4845
08e4b1c5 4846 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
4847 "Shut down the system.\n\n"
4848 " --help Show this help\n"
4849 " -H --halt Halt the machine\n"
4850 " -P --poweroff Power-off the machine\n"
4851 " -r --reboot Reboot the machine\n"
386da858 4852 " -h Equivalent to --poweroff, overridden by --halt\n"
2e33c433 4853 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 4854 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 4855 " -c Cancel a pending shutdown\n",
e4b61340
LP
4856 program_invocation_short_name);
4857
4858 return 0;
4859}
4860
4861static int telinit_help(void) {
4862
2e33c433 4863 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
4864 "Send control commands to the init daemon.\n\n"
4865 " --help Show this help\n"
2e33c433 4866 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
4867 "Commands:\n"
4868 " 0 Power-off the machine\n"
4869 " 6 Reboot the machine\n"
514f4ef5
LP
4870 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4871 " 1, s, S Enter rescue mode\n"
4872 " q, Q Reload init daemon configuration\n"
4873 " u, U Reexecute init daemon\n",
e4b61340
LP
4874 program_invocation_short_name);
4875
4876 return 0;
4877}
4878
4879static int runlevel_help(void) {
4880
2e33c433 4881 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4882 "Prints the previous and current runlevel of the init system.\n\n"
4883 " --help Show this help\n",
4884 program_invocation_short_name);
4885
4886 return 0;
4887}
4888
45c0c61d
ZJS
4889static int help_types(void) {
4890 int i;
830f01f0 4891 const char *t;
45c0c61d
ZJS
4892
4893 puts("Available unit types:");
830f01f0
LP
4894 for(i = 0; i < _UNIT_TYPE_MAX; i++) {
4895 t = unit_type_to_string(i);
4896 if (t)
4897 puts(t);
4898 }
45c0c61d 4899
45c0c61d
ZJS
4900 return 0;
4901}
4902
e4b61340 4903static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
4904
4905 enum {
90d473a1 4906 ARG_FAIL = 0x100,
afba4199
ZJS
4907 ARG_REVERSE,
4908 ARG_AFTER,
4909 ARG_BEFORE,
991f2a39 4910 ARG_SHOW_TYPES,
23ade460 4911 ARG_IRREVERSIBLE,
e67c3609 4912 ARG_IGNORE_DEPENDENCIES,
35df8f27 4913 ARG_VERSION,
af2d49f7 4914 ARG_USER,
7e4249b9 4915 ARG_SYSTEM,
ee5762e3 4916 ARG_GLOBAL,
6e905d93 4917 ARG_NO_BLOCK,
ebed32bf 4918 ARG_NO_LEGEND,
611efaac 4919 ARG_NO_PAGER,
4445a875 4920 ARG_NO_WALL,
be394c48 4921 ARG_ROOT,
ee5762e3 4922 ARG_NO_RELOAD,
501fc174 4923 ARG_KILL_WHO,
30732560 4924 ARG_NO_ASK_PASSWORD,
729e3769 4925 ARG_FAILED,
df50185b 4926 ARG_RUNTIME,
5d0c05e5 4927 ARG_FORCE,
9b9b3d36
MW
4928 ARG_PLAIN,
4929 ARG_STATE
7e4249b9
LP
4930 };
4931
4932 static const struct option options[] = {
9ea9d4cf
LP
4933 { "help", no_argument, NULL, 'h' },
4934 { "version", no_argument, NULL, ARG_VERSION },
4935 { "type", required_argument, NULL, 't' },
4936 { "property", required_argument, NULL, 'p' },
4937 { "all", no_argument, NULL, 'a' },
4938 { "reverse", no_argument, NULL, ARG_REVERSE },
4939 { "after", no_argument, NULL, ARG_AFTER },
4940 { "before", no_argument, NULL, ARG_BEFORE },
4941 { "show-types", no_argument, NULL, ARG_SHOW_TYPES },
4942 { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
4943 { "full", no_argument, NULL, 'l' },
4944 { "fail", no_argument, NULL, ARG_FAIL },
4945 { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE },
4946 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
4947 { "ignore-inhibitors", no_argument, NULL, 'i' },
4948 { "user", no_argument, NULL, ARG_USER },
4949 { "system", no_argument, NULL, ARG_SYSTEM },
4950 { "global", no_argument, NULL, ARG_GLOBAL },
4951 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
4952 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
4953 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
4954 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4955 { "quiet", no_argument, NULL, 'q' },
4956 { "root", required_argument, NULL, ARG_ROOT },
4957 { "force", no_argument, NULL, ARG_FORCE },
4958 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
4959 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
4960 { "signal", required_argument, NULL, 's' },
4961 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
4962 { "host", required_argument, NULL, 'H' },
4963 { "privileged", no_argument, NULL, 'P' },
4964 { "runtime", no_argument, NULL, ARG_RUNTIME },
4965 { "lines", required_argument, NULL, 'n' },
4966 { "output", required_argument, NULL, 'o' },
4967 { "plain", no_argument, NULL, ARG_PLAIN },
4968 { "state", required_argument, NULL, ARG_STATE },
4969 { NULL, 0, NULL, 0 }
7e4249b9
LP
4970 };
4971
4972 int c;
4973
e4b61340 4974 assert(argc >= 0);
7e4249b9
LP
4975 assert(argv);
4976
422fa650 4977 while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:Pn:o:i", options, NULL)) >= 0) {
7e4249b9
LP
4978
4979 switch (c) {
4980
4981 case 'h':
e4b61340 4982 systemctl_help();
7e4249b9 4983 return 0;
35df8f27
LP
4984
4985 case ARG_VERSION:
4986 puts(PACKAGE_STRING);
7d568925 4987 puts(SYSTEMD_FEATURES);
35df8f27 4988 return 0;
7e4249b9 4989
20b3f379
ZJS
4990 case 't': {
4991 char *word, *state;
4992 size_t size;
45c0c61d 4993
20b3f379 4994 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
7fd1b19b 4995 _cleanup_free_ char *type;
20b3f379
ZJS
4996
4997 type = strndup(word, size);
4998 if (!type)
4999 return -ENOMEM;
5000
5001 if (streq(type, "help")) {
5002 help_types();
5003 return 0;
5004 }
5005
5006 if (unit_type_from_string(type) >= 0) {
5007 if (strv_push(&arg_types, type))
5008 return log_oom();
5009 type = NULL;
5010 continue;
5011 }
5012
9b9b3d36
MW
5013 /* It's much nicer to use --state= for
5014 * load states, but let's support this
5015 * in --types= too for compatibility
5016 * with old versions */
20b3f379 5017 if (unit_load_state_from_string(optarg) >= 0) {
9b9b3d36 5018 if (strv_push(&arg_states, type) < 0)
20b3f379
ZJS
5019 return log_oom();
5020 type = NULL;
5021 continue;
5022 }
5023
ab06eef8 5024 log_error("Unknown unit type or load state '%s'.", type);
20b3f379
ZJS
5025 log_info("Use -t help to see a list of allowed values.");
5026 return -EINVAL;
c147dc42 5027 }
20b3f379
ZJS
5028
5029 break;
5030 }
5031
ea4a240d 5032 case 'p': {
033a842c
ZJS
5033 /* Make sure that if the empty property list
5034 was specified, we won't show any properties. */
20b3f379
ZJS
5035 if (isempty(optarg) && !arg_properties) {
5036 arg_properties = strv_new(NULL, NULL);
5037 if (!arg_properties)
5038 return log_oom();
5039 } else {
5040 char *word, *state;
5041 size_t size;
033a842c 5042
20b3f379
ZJS
5043 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5044 char *prop;
033a842c 5045
20b3f379
ZJS
5046 prop = strndup(word, size);
5047 if (!prop)
5048 return log_oom();
ea4a240d 5049
9b9b3d36 5050 if (strv_push(&arg_properties, prop) < 0) {
20b3f379
ZJS
5051 free(prop);
5052 return log_oom();
5053 }
5054 }
033a842c 5055 }
48220598
LP
5056
5057 /* If the user asked for a particular
5058 * property, show it to him, even if it is
5059 * empty. */
5060 arg_all = true;
033a842c 5061
48220598 5062 break;
ea4a240d 5063 }
48220598 5064
7e4249b9
LP
5065 case 'a':
5066 arg_all = true;
5067 break;
5068
afba4199
ZJS
5069 case ARG_REVERSE:
5070 arg_dependency = DEPENDENCY_REVERSE;
5071 break;
5072
5073 case ARG_AFTER:
5074 arg_dependency = DEPENDENCY_AFTER;
5075 break;
5076
5077 case ARG_BEFORE:
5078 arg_dependency = DEPENDENCY_BEFORE;
5079 break;
5080
991f2a39
ZJS
5081 case ARG_SHOW_TYPES:
5082 arg_show_types = true;
5083 break;
5084
90d473a1 5085 case ARG_FAIL:
e67c3609
LP
5086 arg_job_mode = "fail";
5087 break;
5088
23ade460
MS
5089 case ARG_IRREVERSIBLE:
5090 arg_job_mode = "replace-irreversibly";
5091 break;
5092
e67c3609
LP
5093 case ARG_IGNORE_DEPENDENCIES:
5094 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
5095 break;
5096
af2d49f7 5097 case ARG_USER:
729e3769 5098 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
5099 break;
5100
5101 case ARG_SYSTEM:
729e3769
LP
5102 arg_scope = UNIT_FILE_SYSTEM;
5103 break;
5104
5105 case ARG_GLOBAL:
5106 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
5107 break;
5108
6e905d93
LP
5109 case ARG_NO_BLOCK:
5110 arg_no_block = true;
7e4249b9
LP
5111 break;
5112
ebed32bf
MS
5113 case ARG_NO_LEGEND:
5114 arg_no_legend = true;
5115 break;
5116
611efaac
LP
5117 case ARG_NO_PAGER:
5118 arg_no_pager = true;
5119 break;
0736af98 5120
514f4ef5
LP
5121 case ARG_NO_WALL:
5122 arg_no_wall = true;
5123 break;
5124
be394c48
FC
5125 case ARG_ROOT:
5126 arg_root = optarg;
5127 break;
5128
98a6e132 5129 case 'l':
8fe914ec
LP
5130 arg_full = true;
5131 break;
5132
30732560 5133 case ARG_FAILED:
9b9b3d36
MW
5134 if (strv_extend(&arg_states, "failed") < 0)
5135 return log_oom();
5136
30732560
LP
5137 break;
5138
0183528f
LP
5139 case 'q':
5140 arg_quiet = true;
5141 break;
5142
568b679f
LP
5143 case ARG_FORCE:
5144 arg_force ++;
5145 break;
5146
b4f27ccc 5147 case 'f':
e606bb61 5148 arg_force ++;
ee5762e3
LP
5149 break;
5150
5151 case ARG_NO_RELOAD:
5152 arg_no_reload = true;
5153 break;
5154
8a0867d6
LP
5155 case ARG_KILL_WHO:
5156 arg_kill_who = optarg;
5157 break;
5158
8a0867d6
LP
5159 case 's':
5160 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
5161 log_error("Failed to parse signal string %s.", optarg);
5162 return -EINVAL;
5163 }
5164 break;
5165
501fc174
LP
5166 case ARG_NO_ASK_PASSWORD:
5167 arg_ask_password = false;
5168 break;
5169
a8f11321
LP
5170 case 'P':
5171 arg_transport = TRANSPORT_POLKIT;
5172 break;
5173
5174 case 'H':
5175 arg_transport = TRANSPORT_SSH;
7085053a 5176 parse_user_at_host(optarg, &arg_user, &arg_host);
a8f11321
LP
5177 break;
5178
729e3769
LP
5179 case ARG_RUNTIME:
5180 arg_runtime = true;
5181 break;
5182
df50185b
LP
5183 case 'n':
5184 if (safe_atou(optarg, &arg_lines) < 0) {
5185 log_error("Failed to parse lines '%s'", optarg);
5186 return -EINVAL;
5187 }
5188 break;
5189
df50185b
LP
5190 case 'o':
5191 arg_output = output_mode_from_string(optarg);
5192 if (arg_output < 0) {
5193 log_error("Unknown output '%s'.", optarg);
5194 return -EINVAL;
5195 }
5196 break;
5197
b37844d3
LP
5198 case 'i':
5199 arg_ignore_inhibitors = true;
5200 break;
5201
5d0c05e5
LN
5202 case ARG_PLAIN:
5203 arg_plain = true;
5204 break;
5205
9b9b3d36
MW
5206 case ARG_STATE: {
5207 char *word, *state;
5208 size_t size;
5209
5210 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
5211 char *s;
5212
5213 s = strndup(word, size);
5214 if (!s)
5215 return log_oom();
5216
5217 if (strv_push(&arg_states, s) < 0) {
5218 free(s);
5219 return log_oom();
5220 }
5221 }
5222 break;
5223 }
5224
7e4249b9
LP
5225 case '?':
5226 return -EINVAL;
5227
5228 default:
b0193f1c 5229 log_error("Unknown option code '%c'.", c);
7e4249b9
LP
5230 return -EINVAL;
5231 }
5232 }
5233
729e3769 5234 if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
5235 log_error("Cannot access user instance remotely.");
5236 return -EINVAL;
5237 }
5238
7e4249b9
LP
5239 return 1;
5240}
5241
e4b61340
LP
5242static int halt_parse_argv(int argc, char *argv[]) {
5243
5244 enum {
5245 ARG_HELP = 0x100,
5246 ARG_HALT,
514f4ef5
LP
5247 ARG_REBOOT,
5248 ARG_NO_WALL
e4b61340
LP
5249 };
5250
5251 static const struct option options[] = {
5252 { "help", no_argument, NULL, ARG_HELP },
5253 { "halt", no_argument, NULL, ARG_HALT },
5254 { "poweroff", no_argument, NULL, 'p' },
5255 { "reboot", no_argument, NULL, ARG_REBOOT },
5256 { "force", no_argument, NULL, 'f' },
5257 { "wtmp-only", no_argument, NULL, 'w' },
5258 { "no-wtmp", no_argument, NULL, 'd' },
514f4ef5 5259 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
5260 { NULL, 0, NULL, 0 }
5261 };
5262
5263 int c, runlevel;
5264
5265 assert(argc >= 0);
5266 assert(argv);
5267
5268 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
5269 if (runlevel == '0' || runlevel == '6')
65491fd8 5270 arg_force = 2;
e4b61340
LP
5271
5272 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
5273 switch (c) {
5274
5275 case ARG_HELP:
5276 halt_help();
5277 return 0;
5278
5279 case ARG_HALT:
5280 arg_action = ACTION_HALT;
5281 break;
5282
5283 case 'p':
a042efad
MS
5284 if (arg_action != ACTION_REBOOT)
5285 arg_action = ACTION_POWEROFF;
e4b61340
LP
5286 break;
5287
5288 case ARG_REBOOT:
5289 arg_action = ACTION_REBOOT;
5290 break;
5291
5292 case 'f':
65491fd8 5293 arg_force = 2;
e4b61340
LP
5294 break;
5295
5296 case 'w':
5297 arg_dry = true;
5298 break;
5299
5300 case 'd':
5301 arg_no_wtmp = true;
5302 break;
5303
514f4ef5
LP
5304 case ARG_NO_WALL:
5305 arg_no_wall = true;
5306 break;
5307
e4b61340
LP
5308 case 'i':
5309 case 'h':
57371e58 5310 case 'n':
e4b61340
LP
5311 /* Compatibility nops */
5312 break;
5313
5314 case '?':
5315 return -EINVAL;
5316
5317 default:
b0193f1c 5318 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5319 return -EINVAL;
5320 }
5321 }
5322
5323 if (optind < argc) {
5324 log_error("Too many arguments.");
5325 return -EINVAL;
5326 }
5327
5328 return 1;
5329}
5330
f6144808
LP
5331static int parse_time_spec(const char *t, usec_t *_u) {
5332 assert(t);
5333 assert(_u);
5334
5335 if (streq(t, "now"))
5336 *_u = 0;
1a639877 5337 else if (!strchr(t, ':')) {
f6144808
LP
5338 uint64_t u;
5339
1a639877 5340 if (safe_atou64(t, &u) < 0)
f6144808
LP
5341 return -EINVAL;
5342
5343 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
5344 } else {
5345 char *e = NULL;
5346 long hour, minute;
b92bea5d 5347 struct tm tm = {};
f6144808
LP
5348 time_t s;
5349 usec_t n;
5350
5351 errno = 0;
5352 hour = strtol(t, &e, 10);
8333c77e 5353 if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
f6144808
LP
5354 return -EINVAL;
5355
5356 minute = strtol(e+1, &e, 10);
8333c77e 5357 if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
f6144808
LP
5358 return -EINVAL;
5359
5360 n = now(CLOCK_REALTIME);
08e4b1c5
LP
5361 s = (time_t) (n / USEC_PER_SEC);
5362
f6144808
LP
5363 assert_se(localtime_r(&s, &tm));
5364
5365 tm.tm_hour = (int) hour;
5366 tm.tm_min = (int) minute;
08e4b1c5 5367 tm.tm_sec = 0;
f6144808
LP
5368
5369 assert_se(s = mktime(&tm));
5370
5371 *_u = (usec_t) s * USEC_PER_SEC;
5372
5373 while (*_u <= n)
5374 *_u += USEC_PER_DAY;
5375 }
5376
5377 return 0;
5378}
5379
e4b61340
LP
5380static int shutdown_parse_argv(int argc, char *argv[]) {
5381
5382 enum {
5383 ARG_HELP = 0x100,
514f4ef5 5384 ARG_NO_WALL
e4b61340
LP
5385 };
5386
5387 static const struct option options[] = {
5388 { "help", no_argument, NULL, ARG_HELP },
5389 { "halt", no_argument, NULL, 'H' },
5390 { "poweroff", no_argument, NULL, 'P' },
5391 { "reboot", no_argument, NULL, 'r' },
04ebb595 5392 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 5393 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
5394 { NULL, 0, NULL, 0 }
5395 };
5396
f6144808 5397 int c, r;
e4b61340
LP
5398
5399 assert(argc >= 0);
5400 assert(argv);
5401
f6144808 5402 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
e4b61340
LP
5403 switch (c) {
5404
5405 case ARG_HELP:
5406 shutdown_help();
5407 return 0;
5408
5409 case 'H':
5410 arg_action = ACTION_HALT;
5411 break;
5412
5413 case 'P':
5414 arg_action = ACTION_POWEROFF;
5415 break;
5416
5417 case 'r':
5622dde3
KS
5418 if (kexec_loaded())
5419 arg_action = ACTION_KEXEC;
5420 else
5421 arg_action = ACTION_REBOOT;
e4b61340
LP
5422 break;
5423
04ebb595
LP
5424 case 'K':
5425 arg_action = ACTION_KEXEC;
5426 break;
5427
e4b61340
LP
5428 case 'h':
5429 if (arg_action != ACTION_HALT)
5430 arg_action = ACTION_POWEROFF;
5431 break;
5432
5433 case 'k':
5434 arg_dry = true;
5435 break;
5436
514f4ef5
LP
5437 case ARG_NO_WALL:
5438 arg_no_wall = true;
5439 break;
5440
e4b61340
LP
5441 case 't':
5442 case 'a':
5443 /* Compatibility nops */
5444 break;
5445
f6144808
LP
5446 case 'c':
5447 arg_action = ACTION_CANCEL_SHUTDOWN;
5448 break;
5449
e4b61340
LP
5450 case '?':
5451 return -EINVAL;
5452
5453 default:
b0193f1c 5454 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5455 return -EINVAL;
5456 }
5457 }
5458
dfcc5c33 5459 if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
7e59bfcb
LP
5460 r = parse_time_spec(argv[optind], &arg_when);
5461 if (r < 0) {
f6144808
LP
5462 log_error("Failed to parse time specification: %s", argv[optind]);
5463 return r;
5464 }
6b5ad000 5465 } else
08e4b1c5 5466 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 5467
dfcc5c33
MS
5468 if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
5469 /* No time argument for shutdown cancel */
5470 arg_wall = argv + optind;
5471 else if (argc > optind + 1)
5472 /* We skip the time argument */
e4b61340
LP
5473 arg_wall = argv + optind + 1;
5474
5475 optind = argc;
5476
5477 return 1;
e4b61340
LP
5478}
5479
5480static int telinit_parse_argv(int argc, char *argv[]) {
5481
5482 enum {
5483 ARG_HELP = 0x100,
514f4ef5 5484 ARG_NO_WALL
e4b61340
LP
5485 };
5486
5487 static const struct option options[] = {
5488 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 5489 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
5490 { NULL, 0, NULL, 0 }
5491 };
5492
5493 static const struct {
5494 char from;
5495 enum action to;
5496 } table[] = {
5497 { '0', ACTION_POWEROFF },
5498 { '6', ACTION_REBOOT },
ef2f1067 5499 { '1', ACTION_RESCUE },
e4b61340
LP
5500 { '2', ACTION_RUNLEVEL2 },
5501 { '3', ACTION_RUNLEVEL3 },
5502 { '4', ACTION_RUNLEVEL4 },
5503 { '5', ACTION_RUNLEVEL5 },
5504 { 's', ACTION_RESCUE },
5505 { 'S', ACTION_RESCUE },
5506 { 'q', ACTION_RELOAD },
5507 { 'Q', ACTION_RELOAD },
5508 { 'u', ACTION_REEXEC },
5509 { 'U', ACTION_REEXEC }
5510 };
5511
5512 unsigned i;
5513 int c;
5514
5515 assert(argc >= 0);
5516 assert(argv);
5517
5518 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5519 switch (c) {
5520
5521 case ARG_HELP:
5522 telinit_help();
5523 return 0;
5524
514f4ef5
LP
5525 case ARG_NO_WALL:
5526 arg_no_wall = true;
5527 break;
5528
e4b61340
LP
5529 case '?':
5530 return -EINVAL;
5531
5532 default:
b0193f1c 5533 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5534 return -EINVAL;
5535 }
5536 }
5537
5538 if (optind >= argc) {
2f02ce40 5539 telinit_help();
e4b61340
LP
5540 return -EINVAL;
5541 }
5542
5543 if (optind + 1 < argc) {
5544 log_error("Too many arguments.");
5545 return -EINVAL;
5546 }
5547
5548 if (strlen(argv[optind]) != 1) {
5549 log_error("Expected single character argument.");
5550 return -EINVAL;
5551 }
5552
5553 for (i = 0; i < ELEMENTSOF(table); i++)
5554 if (table[i].from == argv[optind][0])
5555 break;
5556
5557 if (i >= ELEMENTSOF(table)) {
b0193f1c 5558 log_error("Unknown command '%s'.", argv[optind]);
e4b61340
LP
5559 return -EINVAL;
5560 }
5561
5562 arg_action = table[i].to;
5563
5564 optind ++;
5565
5566 return 1;
5567}
5568
5569static int runlevel_parse_argv(int argc, char *argv[]) {
5570
5571 enum {
5572 ARG_HELP = 0x100,
5573 };
5574
5575 static const struct option options[] = {
5576 { "help", no_argument, NULL, ARG_HELP },
5577 { NULL, 0, NULL, 0 }
5578 };
5579
5580 int c;
5581
5582 assert(argc >= 0);
5583 assert(argv);
5584
5585 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
5586 switch (c) {
5587
5588 case ARG_HELP:
5589 runlevel_help();
5590 return 0;
5591
5592 case '?':
5593 return -EINVAL;
5594
5595 default:
b0193f1c 5596 log_error("Unknown option code '%c'.", c);
e4b61340
LP
5597 return -EINVAL;
5598 }
5599 }
5600
5601 if (optind < argc) {
5602 log_error("Too many arguments.");
5603 return -EINVAL;
5604 }
5605
5606 return 1;
5607}
5608
5609static int parse_argv(int argc, char *argv[]) {
5610 assert(argc >= 0);
5611 assert(argv);
5612
5613 if (program_invocation_short_name) {
5614
5615 if (strstr(program_invocation_short_name, "halt")) {
5616 arg_action = ACTION_HALT;
5617 return halt_parse_argv(argc, argv);
5618 } else if (strstr(program_invocation_short_name, "poweroff")) {
5619 arg_action = ACTION_POWEROFF;
5620 return halt_parse_argv(argc, argv);
5621 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
5622 if (kexec_loaded())
5623 arg_action = ACTION_KEXEC;
5624 else
5625 arg_action = ACTION_REBOOT;
e4b61340
LP
5626 return halt_parse_argv(argc, argv);
5627 } else if (strstr(program_invocation_short_name, "shutdown")) {
5628 arg_action = ACTION_POWEROFF;
5629 return shutdown_parse_argv(argc, argv);
5630 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
5631
5632 if (sd_booted() > 0) {
5633 arg_action = ACTION_INVALID;
5634 return telinit_parse_argv(argc, argv);
5635 } else {
5636 /* Hmm, so some other init system is
5637 * running, we need to forward this
5638 * request to it. For now we simply
5639 * guess that it is Upstart. */
5640
4ad61fd1 5641 execv(TELINIT, argv);
d5ca5f11
LP
5642
5643 log_error("Couldn't find an alternative telinit implementation to spawn.");
5644 return -EIO;
5645 }
5646
e4b61340
LP
5647 } else if (strstr(program_invocation_short_name, "runlevel")) {
5648 arg_action = ACTION_RUNLEVEL;
5649 return runlevel_parse_argv(argc, argv);
5650 }
5651 }
5652
5653 arg_action = ACTION_SYSTEMCTL;
5654 return systemctl_parse_argv(argc, argv);
5655}
5656
44a6b1b6 5657_pure_ static int action_to_runlevel(void) {
eb22ac37
LP
5658
5659 static const char table[_ACTION_MAX] = {
5660 [ACTION_HALT] = '0',
5661 [ACTION_POWEROFF] = '0',
5662 [ACTION_REBOOT] = '6',
5663 [ACTION_RUNLEVEL2] = '2',
5664 [ACTION_RUNLEVEL3] = '3',
5665 [ACTION_RUNLEVEL4] = '4',
5666 [ACTION_RUNLEVEL5] = '5',
5667 [ACTION_RESCUE] = '1'
5668 };
5669
d55ae9e6
LP
5670 assert(arg_action < _ACTION_MAX);
5671
5672 return table[arg_action];
5673}
5674
f1c5860b 5675static int talk_upstart(void) {
7fd1b19b
HH
5676 _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
5677 _cleanup_dbus_error_free_ DBusError error;
d55ae9e6
LP
5678 int previous, rl, r;
5679 char
5680 env1_buf[] = "RUNLEVEL=X",
5681 env2_buf[] = "PREVLEVEL=X";
5682 char *env1 = env1_buf, *env2 = env2_buf;
5683 const char *emit = "runlevel";
5684 dbus_bool_t b_false = FALSE;
5685 DBusMessageIter iter, sub;
f1c5860b 5686 DBusConnection *bus;
d55ae9e6
LP
5687
5688 dbus_error_init(&error);
5689
5690 if (!(rl = action_to_runlevel()))
5691 return 0;
5692
5693 if (utmp_get_runlevel(&previous, NULL) < 0)
5694 previous = 'N';
5695
b574246b 5696 if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
f1c5860b
LP
5697 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5698 r = 0;
5699 goto finish;
5700 }
5701
4cf5d675 5702 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
f1c5860b
LP
5703 r = -EIO;
5704 goto finish;
5705 }
5706
5707 if ((r = bus_check_peercred(bus)) < 0) {
5708 log_error("Failed to verify owner of bus.");
5709 goto finish;
5710 }
5711
d55ae9e6
LP
5712 if (!(m = dbus_message_new_method_call(
5713 "com.ubuntu.Upstart",
5714 "/com/ubuntu/Upstart",
5715 "com.ubuntu.Upstart0_6",
5716 "EmitEvent"))) {
5717
5718 log_error("Could not allocate message.");
f1c5860b
LP
5719 r = -ENOMEM;
5720 goto finish;
d55ae9e6
LP
5721 }
5722
5723 dbus_message_iter_init_append(m, &iter);
5724
5725 env1_buf[sizeof(env1_buf)-2] = rl;
5726 env2_buf[sizeof(env2_buf)-2] = previous;
5727
5728 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5729 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5730 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5731 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5732 !dbus_message_iter_close_container(&iter, &sub) ||
5733 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5734 log_error("Could not append arguments to message.");
5735 r = -ENOMEM;
5736 goto finish;
5737 }
5738
5739 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5740
c67de56f 5741 if (bus_error_is_no_service(&error)) {
aabd9b11 5742 r = -EADDRNOTAVAIL;
d55ae9e6
LP
5743 goto finish;
5744 }
5745
4cf5d675 5746 log_error("Failed to issue method call: %s", bus_error_message(&error));
d55ae9e6
LP
5747 r = -EIO;
5748 goto finish;
5749 }
5750
0a55b298 5751 r = 1;
d55ae9e6
LP
5752
5753finish:
b574246b 5754 if (bus) {
5d452f9c 5755 dbus_connection_flush(bus);
b574246b 5756 dbus_connection_close(bus);
f1c5860b 5757 dbus_connection_unref(bus);
b574246b 5758 }
f1c5860b 5759
d55ae9e6
LP
5760 return r;
5761}
5762
5763static int talk_initctl(void) {
b92bea5d 5764 struct init_request request = {};
427b47c4 5765 int r;
7fd1b19b 5766 _cleanup_close_ int fd = -1;
d55ae9e6 5767 char rl;
eb22ac37 5768
427b47c4
ZJS
5769 rl = action_to_runlevel();
5770 if (!rl)
eb22ac37
LP
5771 return 0;
5772
eb22ac37
LP
5773 request.magic = INIT_MAGIC;
5774 request.sleeptime = 0;
5775 request.cmd = INIT_CMD_RUNLVL;
d55ae9e6
LP
5776 request.runlevel = rl;
5777
427b47c4
ZJS
5778 fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY);
5779 if (fd < 0) {
d55ae9e6
LP
5780 if (errno == ENOENT)
5781 return 0;
eb22ac37 5782
d55ae9e6 5783 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 5784 return -errno;
d55ae9e6 5785 }
eb22ac37 5786
d55ae9e6 5787 errno = 0;
eb22ac37 5788 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
427b47c4 5789 if (r) {
d55ae9e6 5790 log_error("Failed to write to "INIT_FIFO": %m");
bcb161b0 5791 return errno > 0 ? -errno : -EIO;
d55ae9e6 5792 }
eb22ac37
LP
5793
5794 return 1;
e4b61340
LP
5795}
5796
ee5762e3 5797static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
7e4249b9 5798
7e4249b9
LP
5799 static const struct {
5800 const char* verb;
5801 const enum {
5802 MORE,
5803 LESS,
5804 EQUAL
5805 } argc_cmp;
5806 const int argc;
729e3769 5807 int (* const dispatch)(DBusConnection *bus, char **args);
7e4249b9 5808 } verbs[] = {
ee5762e3 5809 { "list-units", LESS, 1, list_units },
729e3769 5810 { "list-unit-files", EQUAL, 1, list_unit_files },
991f2a39 5811 { "list-sockets", LESS, 1, list_sockets },
ee5762e3
LP
5812 { "list-jobs", EQUAL, 1, list_jobs },
5813 { "clear-jobs", EQUAL, 1, daemon_reload },
ee5762e3
LP
5814 { "cancel", MORE, 2, cancel_job },
5815 { "start", MORE, 2, start_unit },
5816 { "stop", MORE, 2, start_unit },
a76f7be2 5817 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5818 { "reload", MORE, 2, start_unit },
5819 { "restart", MORE, 2, start_unit },
5820 { "try-restart", MORE, 2, start_unit },
5821 { "reload-or-restart", MORE, 2, start_unit },
5822 { "reload-or-try-restart", MORE, 2, start_unit },
5823 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 5824 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5825 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
5826 { "isolate", EQUAL, 2, start_unit },
8a0867d6 5827 { "kill", MORE, 2, kill_unit },
1a0fce45
TA
5828 { "is-active", MORE, 2, check_unit_active },
5829 { "check", MORE, 2, check_unit_active },
5830 { "is-failed", MORE, 2, check_unit_failed },
ee5762e3 5831 { "show", MORE, 1, show },
265a7a2a 5832 { "status", MORE, 1, show },
b43f208f 5833 { "help", MORE, 2, show },
ee5762e3
LP
5834 { "snapshot", LESS, 2, snapshot },
5835 { "delete", MORE, 2, delete_snapshot },
5836 { "daemon-reload", EQUAL, 1, daemon_reload },
5837 { "daemon-reexec", EQUAL, 1, daemon_reload },
ee5762e3
LP
5838 { "show-environment", EQUAL, 1, show_enviroment },
5839 { "set-environment", MORE, 2, set_environment },
5840 { "unset-environment", MORE, 2, set_environment },
5841 { "halt", EQUAL, 1, start_special },
5842 { "poweroff", EQUAL, 1, start_special },
5843 { "reboot", EQUAL, 1, start_special },
20b09ca7 5844 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
5845 { "suspend", EQUAL, 1, start_special },
5846 { "hibernate", EQUAL, 1, start_special },
6524990f 5847 { "hybrid-sleep", EQUAL, 1, start_special },
ee5762e3
LP
5848 { "default", EQUAL, 1, start_special },
5849 { "rescue", EQUAL, 1, start_special },
5850 { "emergency", EQUAL, 1, start_special },
20b09ca7 5851 { "exit", EQUAL, 1, start_special },
fdf20a31 5852 { "reset-failed", MORE, 1, reset_failed },
ee5762e3
LP
5853 { "enable", MORE, 2, enable_unit },
5854 { "disable", MORE, 2, enable_unit },
729e3769
LP
5855 { "is-enabled", MORE, 2, unit_is_enabled },
5856 { "reenable", MORE, 2, enable_unit },
5857 { "preset", MORE, 2, enable_unit },
5858 { "mask", MORE, 2, enable_unit },
5859 { "unmask", MORE, 2, enable_unit },
957eb8ca
LP
5860 { "link", MORE, 2, enable_unit },
5861 { "switch-root", MORE, 2, switch_root },
e31165b2 5862 { "list-dependencies", LESS, 2, list_dependencies },
99504dd4
VP
5863 { "set-default", EQUAL, 2, enable_unit },
5864 { "get-default", LESS, 1, get_default },
8e2af478 5865 { "set-property", MORE, 3, set_property },
7e4249b9
LP
5866 };
5867
e4b61340 5868 int left;
7e4249b9 5869 unsigned i;
7e4249b9 5870
e4b61340
LP
5871 assert(argc >= 0);
5872 assert(argv);
ee5762e3 5873 assert(error);
7e4249b9
LP
5874
5875 left = argc - optind;
5876
5877 if (left <= 0)
5878 /* Special rule: no arguments means "list-units" */
5879 i = 0;
5880 else {
b43f208f
KS
5881 if (streq(argv[optind], "help") && !argv[optind+1]) {
5882 log_error("This command expects one or more "
5883 "unit names. Did you mean --help?");
5884 return -EINVAL;
0183528f
LP
5885 }
5886
7e4249b9
LP
5887 for (i = 0; i < ELEMENTSOF(verbs); i++)
5888 if (streq(argv[optind], verbs[i].verb))
5889 break;
5890
5891 if (i >= ELEMENTSOF(verbs)) {
b0193f1c 5892 log_error("Unknown operation '%s'.", argv[optind]);
e4b61340 5893 return -EINVAL;
7e4249b9
LP
5894 }
5895 }
5896
5897 switch (verbs[i].argc_cmp) {
5898
5899 case EQUAL:
5900 if (left != verbs[i].argc) {
5901 log_error("Invalid number of arguments.");
e4b61340 5902 return -EINVAL;
7e4249b9
LP
5903 }
5904
5905 break;
5906
5907 case MORE:
5908 if (left < verbs[i].argc) {
5909 log_error("Too few arguments.");
e4b61340 5910 return -EINVAL;
7e4249b9
LP
5911 }
5912
5913 break;
5914
5915 case LESS:
5916 if (left > verbs[i].argc) {
5917 log_error("Too many arguments.");
e4b61340 5918 return -EINVAL;
7e4249b9
LP
5919 }
5920
5921 break;
5922
5923 default:
5924 assert_not_reached("Unknown comparison operator.");
5925 }
5926
ee5762e3
LP
5927 /* Require a bus connection for all operations but
5928 * enable/disable */
729e3769
LP
5929 if (!streq(verbs[i].verb, "enable") &&
5930 !streq(verbs[i].verb, "disable") &&
c971700e 5931 !streq(verbs[i].verb, "is-enabled") &&
d380a3bc 5932 !streq(verbs[i].verb, "list-unit-files") &&
729e3769
LP
5933 !streq(verbs[i].verb, "reenable") &&
5934 !streq(verbs[i].verb, "preset") &&
5935 !streq(verbs[i].verb, "mask") &&
5936 !streq(verbs[i].verb, "unmask") &&
99504dd4
VP
5937 !streq(verbs[i].verb, "link") &&
5938 !streq(verbs[i].verb, "set-default") &&
5939 !streq(verbs[i].verb, "get-default")) {
82e23ddd
LP
5940
5941 if (running_in_chroot() > 0) {
5942 log_info("Running in chroot, ignoring request.");
5943 return 0;
5944 }
5945
3beddc78 5946 if (((!streq(verbs[i].verb, "reboot") &&
59ddae9f
LP
5947 !streq(verbs[i].verb, "halt") &&
5948 !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
f176b5c2
LP
5949 log_error("Failed to get D-Bus connection: %s",
5950 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
8185a509
LP
5951 return -EIO;
5952 }
5953
5954 } else {
5955
729e3769 5956 if (!bus && !avoid_bus()) {
f176b5c2
LP
5957 log_error("Failed to get D-Bus connection: %s",
5958 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
82e23ddd
LP
5959 return -EIO;
5960 }
ee5762e3
LP
5961 }
5962
729e3769 5963 return verbs[i].dispatch(bus, argv + optind);
e4b61340
LP
5964}
5965
52c00215 5966static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
7fd1b19b 5967 _cleanup_close_ int fd;
b92bea5d
ZJS
5968 struct sd_shutdown_command c = {
5969 .usec = t,
5970 .mode = mode,
5971 .dry_run = dry_run,
5972 .warn_wall = warn,
5973 };
5974 union sockaddr_union sockaddr = {
5975 .un.sun_family = AF_UNIX,
5976 .un.sun_path = "/run/systemd/shutdownd",
5977 };
5978 struct iovec iovec[2] = {
5979 {.iov_base = (char*) &c,
5980 .iov_len = offsetof(struct sd_shutdown_command, wall_message),
5981 }
5982 };
5983 struct msghdr msghdr = {
5984 .msg_name = &sockaddr,
5985 .msg_namelen = offsetof(struct sockaddr_un, sun_path)
5986 + sizeof("/run/systemd/shutdownd") - 1,
5987 .msg_iov = iovec,
5988 .msg_iovlen = 1,
5989 };
04ebb595
LP
5990
5991 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5992 if (fd < 0)
5993 return -errno;
f6144808 5994
b92bea5d 5995 if (!isempty(message)) {
04ebb595
LP
5996 iovec[1].iov_base = (char*) message;
5997 iovec[1].iov_len = strlen(message);
b92bea5d 5998 msghdr.msg_iovlen++;
04ebb595 5999 }
f6144808 6000
cec7eda5 6001 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
f6144808 6002 return -errno;
f6144808 6003
f6144808
LP
6004 return 0;
6005}
6006
e4b61340 6007static int reload_with_fallback(DBusConnection *bus) {
e4b61340
LP
6008
6009 if (bus) {
6010 /* First, try systemd via D-Bus. */
d76702a7 6011 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
6012 return 0;
6013 }
6014
6015 /* Nothing else worked, so let's try signals */
6016 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
6017
6018 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
6019 log_error("kill() failed: %m");
6020 return -errno;
6021 }
6022
6023 return 0;
6024}
6025
6026static int start_with_fallback(DBusConnection *bus) {
e4b61340
LP
6027
6028 if (bus) {
6029 /* First, try systemd via D-Bus. */
729e3769 6030 if (start_unit(bus, NULL) >= 0)
983d9c90 6031 goto done;
e4b61340
LP
6032 }
6033
ec7f7f20
LP
6034 /* Hmm, talking to systemd via D-Bus didn't work. Then
6035 * let's try to talk to Upstart via D-Bus. */
e364ad06 6036 if (talk_upstart() > 0)
ec7f7f20
LP
6037 goto done;
6038
e4b61340
LP
6039 /* Nothing else worked, so let's try
6040 * /dev/initctl */
fbc43921 6041 if (talk_initctl() > 0)
983d9c90 6042 goto done;
d55ae9e6
LP
6043
6044 log_error("Failed to talk to init daemon.");
6045 return -EIO;
983d9c90
LP
6046
6047done:
6048 warn_wall(arg_action);
6049 return 0;
e4b61340
LP
6050}
6051
d91b8841 6052static _noreturn_ void halt_now(enum action a) {
e606bb61
LP
6053
6054 /* Make sure C-A-D is handled by the kernel from this
6055 * point on... */
6056 reboot(RB_ENABLE_CAD);
6057
4c80c73c 6058 switch (a) {
e606bb61
LP
6059
6060 case ACTION_HALT:
6061 log_info("Halting.");
6062 reboot(RB_HALT_SYSTEM);
6063 break;
6064
6065 case ACTION_POWEROFF:
6066 log_info("Powering off.");
6067 reboot(RB_POWER_OFF);
6068 break;
6069
6070 case ACTION_REBOOT:
6071 log_info("Rebooting.");
6072 reboot(RB_AUTOBOOT);
6073 break;
6074
6075 default:
6076 assert_not_reached("Unknown halt action.");
6077 }
6078
6079 assert_not_reached("Uh? This shouldn't happen.");
6080}
6081
e4b61340
LP
6082static int halt_main(DBusConnection *bus) {
6083 int r;
6084
748ebafa
LP
6085 r = check_inhibitors(bus, arg_action);
6086 if (r < 0)
6087 return r;
b37844d3 6088
bc8c2f5c 6089 if (geteuid() != 0) {
7e59bfcb
LP
6090 /* Try logind if we are a normal user and no special
6091 * mode applies. Maybe PolicyKit allows us to shutdown
6092 * the machine. */
6093
6094 if (arg_when <= 0 &&
6095 !arg_dry &&
b37844d3 6096 arg_force <= 0 &&
7e59bfcb
LP
6097 (arg_action == ACTION_POWEROFF ||
6098 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
6099 r = reboot_with_logind(bus, arg_action);
6100 if (r >= 0)
6101 return r;
6102 }
6103
cc8a7a61 6104 log_error("Must be root.");
bc8c2f5c
LP
6105 return -EPERM;
6106 }
6107
f6144808 6108 if (arg_when > 0) {
7fd1b19b 6109 _cleanup_free_ char *m;
9be9828c
LP
6110
6111 m = strv_join(arg_wall, " ");
6112 r = send_shutdownd(arg_when,
6113 arg_action == ACTION_HALT ? 'H' :
6114 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 6115 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 6116 'r',
52c00215 6117 arg_dry,
9be9828c
LP
6118 !arg_no_wall,
6119 m);
9be9828c
LP
6120
6121 if (r < 0)
f6144808 6122 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 6123 else {
7e59bfcb
LP
6124 char date[FORMAT_TIMESTAMP_MAX];
6125
08e4b1c5
LP
6126 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
6127 format_timestamp(date, sizeof(date), arg_when));
f6144808 6128 return 0;
08e4b1c5 6129 }
f6144808
LP
6130 }
6131
65491fd8 6132 if (!arg_dry && !arg_force)
e4b61340
LP
6133 return start_with_fallback(bus);
6134
d90e1a30
LP
6135 if (!arg_no_wtmp) {
6136 if (sd_booted() > 0)
6137 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
6138 else {
6139 r = utmp_put_shutdown();
6140 if (r < 0)
6141 log_warning("Failed to write utmp record: %s", strerror(-r));
6142 }
d90e1a30 6143 }
e4b61340 6144
e4b61340
LP
6145 if (arg_dry)
6146 return 0;
6147
e606bb61 6148 halt_now(arg_action);
e4b61340
LP
6149 /* We should never reach this. */
6150 return -ENOSYS;
6151}
6152
6153static int runlevel_main(void) {
6154 int r, runlevel, previous;
6155
729e3769
LP
6156 r = utmp_get_runlevel(&runlevel, &previous);
6157 if (r < 0) {
6158 puts("unknown");
e4b61340
LP
6159 return r;
6160 }
6161
6162 printf("%c %c\n",
6163 previous <= 0 ? 'N' : previous,
6164 runlevel <= 0 ? 'N' : runlevel);
6165
6166 return 0;
6167}
6168
6169int main(int argc, char*argv[]) {
22f4096c 6170 int r, retval = EXIT_FAILURE;
e4b61340 6171 DBusConnection *bus = NULL;
7fd1b19b 6172 _cleanup_dbus_error_free_ DBusError error;
e4b61340
LP
6173
6174 dbus_error_init(&error);
6175
a9cdc94f 6176 setlocale(LC_ALL, "");
e4b61340 6177 log_parse_environment();
2396fb04 6178 log_open();
e4b61340 6179
04ebb595
LP
6180 r = parse_argv(argc, argv);
6181 if (r < 0)
e4b61340
LP
6182 goto finish;
6183 else if (r == 0) {
22f4096c 6184 retval = EXIT_SUCCESS;
7e4249b9
LP
6185 goto finish;
6186 }
6187
e4b61340
LP
6188 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
6189 * let's shortcut this */
6190 if (arg_action == ACTION_RUNLEVEL) {
22f4096c
LP
6191 r = runlevel_main();
6192 retval = r < 0 ? EXIT_FAILURE : r;
e4b61340
LP
6193 goto finish;
6194 }
6195
82e23ddd
LP
6196 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
6197 log_info("Running in chroot, ignoring request.");
6198 retval = 0;
6199 goto finish;
6200 }
6201
729e3769
LP
6202 if (!avoid_bus()) {
6203 if (arg_transport == TRANSPORT_NORMAL)
6204 bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
6205 else if (arg_transport == TRANSPORT_POLKIT) {
6206 bus_connect_system_polkit(&bus, &error);
6207 private_bus = false;
6208 } else if (arg_transport == TRANSPORT_SSH) {
7085053a 6209 bus_connect_system_ssh(arg_user, arg_host, &bus, &error);
729e3769
LP
6210 private_bus = false;
6211 } else
6212 assert_not_reached("Uh, invalid transport...");
6213 }
e4b61340
LP
6214
6215 switch (arg_action) {
6216
22f4096c
LP
6217 case ACTION_SYSTEMCTL:
6218 r = systemctl_main(bus, argc, argv, &error);
e4b61340 6219 break;
e4b61340
LP
6220
6221 case ACTION_HALT:
6222 case ACTION_POWEROFF:
6223 case ACTION_REBOOT:
5622dde3 6224 case ACTION_KEXEC:
22f4096c 6225 r = halt_main(bus);
e4b61340
LP
6226 break;
6227
e4b61340
LP
6228 case ACTION_RUNLEVEL2:
6229 case ACTION_RUNLEVEL3:
6230 case ACTION_RUNLEVEL4:
6231 case ACTION_RUNLEVEL5:
6232 case ACTION_RESCUE:
514f4ef5 6233 case ACTION_EMERGENCY:
eb22ac37 6234 case ACTION_DEFAULT:
22f4096c 6235 r = start_with_fallback(bus);
e4b61340 6236 break;
7e4249b9 6237
e4b61340
LP
6238 case ACTION_RELOAD:
6239 case ACTION_REEXEC:
22f4096c 6240 r = reload_with_fallback(bus);
e4b61340
LP
6241 break;
6242
dfcc5c33
MS
6243 case ACTION_CANCEL_SHUTDOWN: {
6244 char *m = NULL;
6245
6246 if (arg_wall) {
6247 m = strv_join(arg_wall, " ");
6248 if (!m) {
6249 retval = EXIT_FAILURE;
6250 goto finish;
6251 }
6252 }
6253 r = send_shutdownd(arg_when, SD_SHUTDOWN_NONE, false, !arg_no_wall, m);
6254 if (r < 0)
6255 log_warning("Failed to talk to shutdownd, shutdown hasn't been cancelled: %s", strerror(-r));
6256 free(m);
f6144808 6257 break;
dfcc5c33 6258 }
f6144808 6259
eb22ac37
LP
6260 case ACTION_INVALID:
6261 case ACTION_RUNLEVEL:
e4b61340
LP
6262 default:
6263 assert_not_reached("Unknown action");
6264 }
7e4249b9 6265
22f4096c
LP
6266 retval = r < 0 ? EXIT_FAILURE : r;
6267
7e4249b9 6268finish:
b574246b 6269 if (bus) {
5d452f9c 6270 dbus_connection_flush(bus);
b574246b 6271 dbus_connection_close(bus);
7e4249b9 6272 dbus_connection_unref(bus);
b574246b 6273 }
7e4249b9
LP
6274
6275 dbus_shutdown();
6276
20b3f379 6277 strv_free(arg_types);
9b9b3d36 6278 strv_free(arg_states);
20b3f379 6279 strv_free(arg_properties);
ea4a240d 6280
1888c907 6281 pager_close();
6bb92a16
LP
6282 ask_password_agent_close();
6283 polkit_agent_close();
1888c907 6284
7e4249b9
LP
6285 return retval;
6286}