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