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