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