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