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