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