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