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