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