]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
dbus-unit: always load the unit before handling a message for it
[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
729e3769 2958static int show(DBusConnection *bus, char **args) {
48220598 2959 DBusMessage *m = NULL, *reply = NULL;
22f4096c 2960 int r, ret = 0;
48220598 2961 DBusError error;
61cbdc4b 2962 bool show_properties, new_line = false;
729e3769 2963 char **name;
48220598
LP
2964
2965 assert(bus);
2966 assert(args);
2967
2968 dbus_error_init(&error);
2969
61cbdc4b
LP
2970 show_properties = !streq(args[0], "status");
2971
ec14911e 2972 if (show_properties)
1968a360 2973 pager_open_if_enabled();
ec14911e 2974
729e3769 2975 if (show_properties && strv_length(args) <= 1) {
48220598
LP
2976 /* If not argument is specified inspect the manager
2977 * itself */
2978
be8088a2 2979 ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
48220598
LP
2980 goto finish;
2981 }
2982
729e3769 2983 STRV_FOREACH(name, args+1) {
48220598
LP
2984 const char *path = NULL;
2985 uint32_t id;
2986
729e3769 2987 if (safe_atou32(*name, &id) < 0) {
598b557b
LP
2988
2989 /* Interpret as unit name */
48220598
LP
2990
2991 if (!(m = dbus_message_new_method_call(
2992 "org.freedesktop.systemd1",
2993 "/org/freedesktop/systemd1",
2994 "org.freedesktop.systemd1.Manager",
e87d1818 2995 "LoadUnit"))) {
48220598 2996 log_error("Could not allocate message.");
22f4096c 2997 ret = -ENOMEM;
48220598
LP
2998 goto finish;
2999 }
3000
3001 if (!dbus_message_append_args(m,
729e3769 3002 DBUS_TYPE_STRING, name,
48220598
LP
3003 DBUS_TYPE_INVALID)) {
3004 log_error("Could not append arguments to message.");
22f4096c 3005 ret = -ENOMEM;
48220598
LP
3006 goto finish;
3007 }
3008
ed2d7a44
LP
3009 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3010
3011 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
4cf5d675 3012 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c 3013 ret = -EIO;
ed2d7a44
LP
3014 goto finish;
3015 }
3016
3017 dbus_error_free(&error);
3018
3019 dbus_message_unref(m);
3020 if (!(m = dbus_message_new_method_call(
3021 "org.freedesktop.systemd1",
3022 "/org/freedesktop/systemd1",
3023 "org.freedesktop.systemd1.Manager",
3024 "GetUnit"))) {
3025 log_error("Could not allocate message.");
22f4096c 3026 ret = -ENOMEM;
ed2d7a44
LP
3027 goto finish;
3028 }
3029
3030 if (!dbus_message_append_args(m,
729e3769 3031 DBUS_TYPE_STRING, name,
ed2d7a44
LP
3032 DBUS_TYPE_INVALID)) {
3033 log_error("Could not append arguments to message.");
22f4096c 3034 ret = -ENOMEM;
ed2d7a44
LP
3035 goto finish;
3036 }
3037
3038 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3039 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c
LP
3040
3041 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
3042 ret = 4; /* According to LSB: "program or service status is unknown" */
3043 else
3044 ret = -EIO;
ed2d7a44
LP
3045 goto finish;
3046 }
3047 }
3048
598b557b
LP
3049 } else if (show_properties) {
3050
3051 /* Interpret as job id */
48220598
LP
3052
3053 if (!(m = dbus_message_new_method_call(
3054 "org.freedesktop.systemd1",
3055 "/org/freedesktop/systemd1",
3056 "org.freedesktop.systemd1.Manager",
3057 "GetJob"))) {
3058 log_error("Could not allocate message.");
22f4096c 3059 ret = -ENOMEM;
48220598
LP
3060 goto finish;
3061 }
3062
3063 if (!dbus_message_append_args(m,
3064 DBUS_TYPE_UINT32, &id,
3065 DBUS_TYPE_INVALID)) {
3066 log_error("Could not append arguments to message.");
22f4096c 3067 ret = -ENOMEM;
48220598
LP
3068 goto finish;
3069 }
48220598 3070
598b557b 3071 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3072 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c 3073 ret = -EIO;
598b557b
LP
3074 goto finish;
3075 }
3076 } else {
3077
3078 /* Interpret as PID */
3079
3080 if (!(m = dbus_message_new_method_call(
3081 "org.freedesktop.systemd1",
3082 "/org/freedesktop/systemd1",
3083 "org.freedesktop.systemd1.Manager",
3084 "GetUnitByPID"))) {
3085 log_error("Could not allocate message.");
22f4096c 3086 ret = -ENOMEM;
598b557b
LP
3087 goto finish;
3088 }
3089
3090 if (!dbus_message_append_args(m,
3091 DBUS_TYPE_UINT32, &id,
3092 DBUS_TYPE_INVALID)) {
3093 log_error("Could not append arguments to message.");
22f4096c 3094 ret = -ENOMEM;
598b557b
LP
3095 goto finish;
3096 }
3097
ed2d7a44 3098 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3099 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c 3100 ret = -EIO;
ed2d7a44
LP
3101 goto finish;
3102 }
48220598
LP
3103 }
3104
3105 if (!dbus_message_get_args(reply, &error,
3106 DBUS_TYPE_OBJECT_PATH, &path,
3107 DBUS_TYPE_INVALID)) {
4cf5d675 3108 log_error("Failed to parse reply: %s", bus_error_message(&error));
22f4096c 3109 ret = -EIO;
48220598
LP
3110 goto finish;
3111 }
3112
be8088a2 3113 if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
22f4096c 3114 ret = r;
48220598
LP
3115
3116 dbus_message_unref(m);
3117 dbus_message_unref(reply);
3118 m = reply = NULL;
3119 }
3120
48220598
LP
3121finish:
3122 if (m)
3123 dbus_message_unref(m);
3124
3125 if (reply)
3126 dbus_message_unref(reply);
3127
3128 dbus_error_free(&error);
3129
22f4096c 3130 return ret;
0183528f
LP
3131}
3132
729e3769 3133static int dump(DBusConnection *bus, char **args) {
7e4249b9
LP
3134 DBusMessage *m = NULL, *reply = NULL;
3135 DBusError error;
3136 int r;
3137 const char *text;
3138
3139 dbus_error_init(&error);
3140
1968a360 3141 pager_open_if_enabled();
ec14911e 3142
7e4249b9
LP
3143 if (!(m = dbus_message_new_method_call(
3144 "org.freedesktop.systemd1",
3145 "/org/freedesktop/systemd1",
3146 "org.freedesktop.systemd1.Manager",
3147 "Dump"))) {
3148 log_error("Could not allocate message.");
3149 return -ENOMEM;
3150 }
3151
3152 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3153 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3154 r = -EIO;
3155 goto finish;
3156 }
3157
3158 if (!dbus_message_get_args(reply, &error,
3159 DBUS_TYPE_STRING, &text,
3160 DBUS_TYPE_INVALID)) {
4cf5d675 3161 log_error("Failed to parse reply: %s", bus_error_message(&error));
7e4249b9
LP
3162 r = -EIO;
3163 goto finish;
3164 }
3165
3166 fputs(text, stdout);
3167
3168 r = 0;
3169
3170finish:
3171 if (m)
3172 dbus_message_unref(m);
3173
3174 if (reply)
3175 dbus_message_unref(reply);
3176
3177 dbus_error_free(&error);
3178
3179 return r;
3180}
3181
729e3769 3182static int snapshot(DBusConnection *bus, char **args) {
7e4249b9
LP
3183 DBusMessage *m = NULL, *reply = NULL;
3184 DBusError error;
3185 int r;
3186 const char *name = "", *path, *id;
3187 dbus_bool_t cleanup = FALSE;
3188 DBusMessageIter iter, sub;
3189 const char
3190 *interface = "org.freedesktop.systemd1.Unit",
3191 *property = "Id";
3192
3193 dbus_error_init(&error);
3194
3195 if (!(m = dbus_message_new_method_call(
3196 "org.freedesktop.systemd1",
3197 "/org/freedesktop/systemd1",
3198 "org.freedesktop.systemd1.Manager",
3199 "CreateSnapshot"))) {
3200 log_error("Could not allocate message.");
3201 return -ENOMEM;
3202 }
3203
729e3769 3204 if (strv_length(args) > 1)
7e4249b9
LP
3205 name = args[1];
3206
3207 if (!dbus_message_append_args(m,
3208 DBUS_TYPE_STRING, &name,
3209 DBUS_TYPE_BOOLEAN, &cleanup,
3210 DBUS_TYPE_INVALID)) {
3211 log_error("Could not append arguments to message.");
3212 r = -ENOMEM;
3213 goto finish;
3214 }
3215
3216 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3217 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3218 r = -EIO;
3219 goto finish;
3220 }
3221
3222 if (!dbus_message_get_args(reply, &error,
3223 DBUS_TYPE_OBJECT_PATH, &path,
3224 DBUS_TYPE_INVALID)) {
4cf5d675 3225 log_error("Failed to parse reply: %s", bus_error_message(&error));
7e4249b9
LP
3226 r = -EIO;
3227 goto finish;
3228 }
3229
3230 dbus_message_unref(m);
3231 if (!(m = dbus_message_new_method_call(
3232 "org.freedesktop.systemd1",
3233 path,
3234 "org.freedesktop.DBus.Properties",
3235 "Get"))) {
3236 log_error("Could not allocate message.");
3237 return -ENOMEM;
3238 }
3239
3240 if (!dbus_message_append_args(m,
3241 DBUS_TYPE_STRING, &interface,
3242 DBUS_TYPE_STRING, &property,
3243 DBUS_TYPE_INVALID)) {
3244 log_error("Could not append arguments to message.");
3245 r = -ENOMEM;
3246 goto finish;
3247 }
3248
3249 dbus_message_unref(reply);
3250 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3251 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3252 r = -EIO;
3253 goto finish;
3254 }
3255
3256 if (!dbus_message_iter_init(reply, &iter) ||
3257 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3258 log_error("Failed to parse reply.");
3259 r = -EIO;
3260 goto finish;
3261 }
3262
3263 dbus_message_iter_recurse(&iter, &sub);
3264
3265 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
3266 log_error("Failed to parse reply.");
3267 r = -EIO;
3268 goto finish;
3269 }
3270
3271 dbus_message_iter_get_basic(&sub, &id);
0183528f
LP
3272
3273 if (!arg_quiet)
3274 puts(id);
7e4249b9
LP
3275 r = 0;
3276
3277finish:
3278 if (m)
3279 dbus_message_unref(m);
3280
3281 if (reply)
3282 dbus_message_unref(reply);
3283
3284 dbus_error_free(&error);
3285
3286 return r;
3287}
3288
729e3769 3289static int delete_snapshot(DBusConnection *bus, char **args) {
6759e7a7
LP
3290 DBusMessage *m = NULL, *reply = NULL;
3291 int r;
3292 DBusError error;
729e3769 3293 char **name;
6759e7a7
LP
3294
3295 assert(bus);
3296 assert(args);
3297
3298 dbus_error_init(&error);
3299
729e3769 3300 STRV_FOREACH(name, args+1) {
6759e7a7
LP
3301 const char *path = NULL;
3302
3303 if (!(m = dbus_message_new_method_call(
3304 "org.freedesktop.systemd1",
3305 "/org/freedesktop/systemd1",
3306 "org.freedesktop.systemd1.Manager",
3307 "GetUnit"))) {
3308 log_error("Could not allocate message.");
3309 r = -ENOMEM;
3310 goto finish;
3311 }
3312
3313 if (!dbus_message_append_args(m,
729e3769 3314 DBUS_TYPE_STRING, name,
6759e7a7
LP
3315 DBUS_TYPE_INVALID)) {
3316 log_error("Could not append arguments to message.");
3317 r = -ENOMEM;
3318 goto finish;
3319 }
3320
3321 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3322 log_error("Failed to issue method call: %s", bus_error_message(&error));
6759e7a7
LP
3323 r = -EIO;
3324 goto finish;
3325 }
3326
3327 if (!dbus_message_get_args(reply, &error,
3328 DBUS_TYPE_OBJECT_PATH, &path,
3329 DBUS_TYPE_INVALID)) {
4cf5d675 3330 log_error("Failed to parse reply: %s", bus_error_message(&error));
6759e7a7
LP
3331 r = -EIO;
3332 goto finish;
3333 }
3334
3335 dbus_message_unref(m);
3336 if (!(m = dbus_message_new_method_call(
3337 "org.freedesktop.systemd1",
3338 path,
3339 "org.freedesktop.systemd1.Snapshot",
3340 "Remove"))) {
3341 log_error("Could not allocate message.");
3342 r = -ENOMEM;
3343 goto finish;
3344 }
3345
3346 dbus_message_unref(reply);
3347 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3348 log_error("Failed to issue method call: %s", bus_error_message(&error));
6759e7a7
LP
3349 r = -EIO;
3350 goto finish;
3351 }
3352
3353 dbus_message_unref(m);
3354 dbus_message_unref(reply);
3355 m = reply = NULL;
3356 }
3357
3358 r = 0;
3359
3360finish:
3361 if (m)
3362 dbus_message_unref(m);
3363
3364 if (reply)
3365 dbus_message_unref(reply);
3366
3367 dbus_error_free(&error);
3368
3369 return r;
3370}
3371
729e3769 3372static int daemon_reload(DBusConnection *bus, char **args) {
7e4249b9
LP
3373 DBusMessage *m = NULL, *reply = NULL;
3374 DBusError error;
3375 int r;
3376 const char *method;
3377
3378 dbus_error_init(&error);
3379
e4b61340
LP
3380 if (arg_action == ACTION_RELOAD)
3381 method = "Reload";
3382 else if (arg_action == ACTION_REEXEC)
3383 method = "Reexecute";
3384 else {
3385 assert(arg_action == ACTION_SYSTEMCTL);
3386
3387 method =
20b09ca7
LP
3388 streq(args[0], "clear-jobs") ||
3389 streq(args[0], "cancel") ? "ClearJobs" :
3390 streq(args[0], "daemon-reexec") ? "Reexecute" :
3391 streq(args[0], "reset-failed") ? "ResetFailed" :
3392 streq(args[0], "halt") ? "Halt" :
3393 streq(args[0], "poweroff") ? "PowerOff" :
3394 streq(args[0], "reboot") ? "Reboot" :
3395 streq(args[0], "kexec") ? "KExec" :
3396 streq(args[0], "exit") ? "Exit" :
3397 /* "daemon-reload" */ "Reload";
e4b61340 3398 }
7e4249b9
LP
3399
3400 if (!(m = dbus_message_new_method_call(
3401 "org.freedesktop.systemd1",
3402 "/org/freedesktop/systemd1",
3403 "org.freedesktop.systemd1.Manager",
3404 method))) {
3405 log_error("Could not allocate message.");
3406 return -ENOMEM;
3407 }
3408
3409 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
e4b61340
LP
3410
3411 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3412 /* There's always a fallback possible for
3413 * legacy actions. */
aabd9b11 3414 r = -EADDRNOTAVAIL;
e4b61340
LP
3415 goto finish;
3416 }
3417
b23de6af
LP
3418 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3419 /* On reexecution, we expect a disconnect, not
3420 * a reply */
3421 r = 0;
3422 goto finish;
3423 }
3424
4cf5d675 3425 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3426 r = -EIO;
3427 goto finish;
3428 }
3429
aabd9b11 3430 r = 0;
7e4249b9
LP
3431
3432finish:
3433 if (m)
3434 dbus_message_unref(m);
3435
3436 if (reply)
3437 dbus_message_unref(reply);
3438
3439 dbus_error_free(&error);
3440
3441 return r;
3442}
3443
729e3769 3444static int reset_failed(DBusConnection *bus, char **args) {
f8440af5 3445 DBusMessage *m = NULL;
5632e374
LP
3446 int r;
3447 DBusError error;
729e3769 3448 char **name;
5632e374
LP
3449
3450 assert(bus);
3451 dbus_error_init(&error);
3452
729e3769
LP
3453 if (strv_length(args) <= 1)
3454 return daemon_reload(bus, args);
5632e374 3455
729e3769 3456 STRV_FOREACH(name, args+1) {
f8440af5 3457 DBusMessage *reply;
5632e374
LP
3458
3459 if (!(m = dbus_message_new_method_call(
3460 "org.freedesktop.systemd1",
3461 "/org/freedesktop/systemd1",
3462 "org.freedesktop.systemd1.Manager",
fdf20a31 3463 "ResetFailedUnit"))) {
5632e374
LP
3464 log_error("Could not allocate message.");
3465 r = -ENOMEM;
3466 goto finish;
3467 }
3468
3469 if (!dbus_message_append_args(m,
729e3769 3470 DBUS_TYPE_STRING, name,
5632e374
LP
3471 DBUS_TYPE_INVALID)) {
3472 log_error("Could not append arguments to message.");
3473 r = -ENOMEM;
3474 goto finish;
3475 }
3476
3477 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3478 log_error("Failed to issue method call: %s", bus_error_message(&error));
5632e374
LP
3479 r = -EIO;
3480 goto finish;
3481 }
3482
3483 dbus_message_unref(m);
3484 dbus_message_unref(reply);
3485 m = reply = NULL;
3486 }
3487
3488 r = 0;
3489
3490finish:
3491 if (m)
3492 dbus_message_unref(m);
3493
5632e374
LP
3494 dbus_error_free(&error);
3495
3496 return r;
3497}
3498
729e3769 3499static int show_enviroment(DBusConnection *bus, char **args) {
7e4249b9
LP
3500 DBusMessage *m = NULL, *reply = NULL;
3501 DBusError error;
3502 DBusMessageIter iter, sub, sub2;
3503 int r;
3504 const char
3505 *interface = "org.freedesktop.systemd1.Manager",
3506 *property = "Environment";
3507
3508 dbus_error_init(&error);
3509
1968a360 3510 pager_open_if_enabled();
ec14911e 3511
7e4249b9
LP
3512 if (!(m = dbus_message_new_method_call(
3513 "org.freedesktop.systemd1",
3514 "/org/freedesktop/systemd1",
3515 "org.freedesktop.DBus.Properties",
3516 "Get"))) {
3517 log_error("Could not allocate message.");
3518 return -ENOMEM;
3519 }
3520
3521 if (!dbus_message_append_args(m,
3522 DBUS_TYPE_STRING, &interface,
3523 DBUS_TYPE_STRING, &property,
3524 DBUS_TYPE_INVALID)) {
3525 log_error("Could not append arguments to message.");
3526 r = -ENOMEM;
3527 goto finish;
3528 }
3529
3530 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3531 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3532 r = -EIO;
3533 goto finish;
3534 }
3535
3536 if (!dbus_message_iter_init(reply, &iter) ||
3537 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3538 log_error("Failed to parse reply.");
3539 r = -EIO;
3540 goto finish;
3541 }
3542
3543 dbus_message_iter_recurse(&iter, &sub);
3544
3545 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3546 dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
3547 log_error("Failed to parse reply.");
3548 r = -EIO;
3549 goto finish;
3550 }
3551
3552 dbus_message_iter_recurse(&sub, &sub2);
3553
3554 while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3555 const char *text;
3556
3557 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3558 log_error("Failed to parse reply.");
3559 r = -EIO;
3560 goto finish;
3561 }
3562
3563 dbus_message_iter_get_basic(&sub2, &text);
3564 printf("%s\n", text);
3565
3566 dbus_message_iter_next(&sub2);
3567 }
3568
3569 r = 0;
3570
3571finish:
3572 if (m)
3573 dbus_message_unref(m);
3574
3575 if (reply)
3576 dbus_message_unref(reply);
3577
3578 dbus_error_free(&error);
3579
3580 return r;
3581}
3582
957eb8ca
LP
3583static int switch_root(DBusConnection *bus, char **args) {
3584 DBusMessage *m = NULL, *reply = NULL;
3585 unsigned l;
3586 const char *root, *init;
3587 DBusError error;
3588 int r;
3589
3590 dbus_error_init(&error);
3591
3592 l = strv_length(args);
3593 if (l < 2 || l > 3) {
3594 log_error("Wrong number of arguments.");
3595 return -EINVAL;
3596 }
3597
3598 root = args[1];
3599 init = l >= 3 ? args[2] : "";
3600
3601 m = dbus_message_new_method_call(
3602 "org.freedesktop.systemd1",
3603 "/org/freedesktop/systemd1",
3604 "org.freedesktop.systemd1.Manager",
3605 "SwitchRoot");
3606 if (!m) {
3607 log_error("Could not allocate message.");
3608 return -ENOMEM;
3609 }
3610
3611 if (!dbus_message_append_args(
3612 m,
3613 DBUS_TYPE_STRING, &root,
3614 DBUS_TYPE_STRING, &init,
3615 DBUS_TYPE_INVALID)) {
3616 log_error("Could not append arguments to message.");
3617 r = -ENOMEM;
3618 goto finish;
3619 }
3620
3621 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3622 if (!reply) {
3623 log_error("Failed to issue method call: %s", bus_error_message(&error));
3624 r = -EIO;
3625 goto finish;
3626 }
3627
3628 r = 0;
3629
3630finish:
3631 if (m)
3632 dbus_message_unref(m);
3633
3634 if (reply)
3635 dbus_message_unref(reply);
3636
3637 dbus_error_free(&error);
3638
3639 return r;
3640}
3641
729e3769 3642static int set_environment(DBusConnection *bus, char **args) {
7e4249b9
LP
3643 DBusMessage *m = NULL, *reply = NULL;
3644 DBusError error;
3645 int r;
3646 const char *method;
3647 DBusMessageIter iter, sub;
729e3769 3648 char **name;
7e4249b9
LP
3649
3650 dbus_error_init(&error);
3651
3652 method = streq(args[0], "set-environment")
3653 ? "SetEnvironment"
3654 : "UnsetEnvironment";
3655
3656 if (!(m = dbus_message_new_method_call(
3657 "org.freedesktop.systemd1",
3658 "/org/freedesktop/systemd1",
3659 "org.freedesktop.systemd1.Manager",
3660 method))) {
3661
3662 log_error("Could not allocate message.");
3663 return -ENOMEM;
3664 }
3665
3666 dbus_message_iter_init_append(m, &iter);
3667
3668 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3669 log_error("Could not append arguments to message.");
3670 r = -ENOMEM;
3671 goto finish;
3672 }
3673
729e3769
LP
3674 STRV_FOREACH(name, args+1)
3675 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
7e4249b9
LP
3676 log_error("Could not append arguments to message.");
3677 r = -ENOMEM;
3678 goto finish;
3679 }
3680
3681 if (!dbus_message_iter_close_container(&iter, &sub)) {
3682 log_error("Could not append arguments to message.");
3683 r = -ENOMEM;
3684 goto finish;
3685 }
3686
3687 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3688 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3689 r = -EIO;
3690 goto finish;
3691 }
3692
3693 r = 0;
3694
3695finish:
3696 if (m)
3697 dbus_message_unref(m);
3698
3699 if (reply)
3700 dbus_message_unref(reply);
3701
3702 dbus_error_free(&error);
3703
3704 return r;
3705}
3706
729e3769
LP
3707static int enable_sysv_units(char **args) {
3708 int r = 0;
ee5762e3 3709
6fdae8a6 3710#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
3711 const char *verb = args[0];
3712 unsigned f = 1, t = 1;
3713 LookupPaths paths;
ee5762e3 3714
729e3769
LP
3715 if (arg_scope != UNIT_FILE_SYSTEM)
3716 return 0;
ee5762e3 3717
729e3769
LP
3718 if (!streq(verb, "enable") &&
3719 !streq(verb, "disable") &&
3720 !streq(verb, "is-enabled"))
3721 return 0;
ee5762e3 3722
729e3769
LP
3723 /* Processes all SysV units, and reshuffles the array so that
3724 * afterwards only the native units remain */
ee5762e3 3725
729e3769
LP
3726 zero(paths);
3727 r = lookup_paths_init(&paths, MANAGER_SYSTEM, false);
3728 if (r < 0)
3729 return r;
ee5762e3 3730
729e3769 3731 r = 0;
ee5762e3 3732
729e3769
LP
3733 for (f = 1; args[f]; f++) {
3734 const char *name;
3735 char *p;
3736 bool found_native = false, found_sysv;
3737 unsigned c = 1;
3738 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3739 char **k, *l, *q = NULL;
3740 int j;
3741 pid_t pid;
3742 siginfo_t status;
ee5762e3 3743
729e3769 3744 name = args[f];
ee5762e3 3745
729e3769
LP
3746 if (!endswith(name, ".service"))
3747 continue;
ee5762e3 3748
729e3769
LP
3749 if (path_is_absolute(name))
3750 continue;
ee5762e3 3751
729e3769
LP
3752 STRV_FOREACH(k, paths.unit_path) {
3753 p = NULL;
ee5762e3 3754
729e3769
LP
3755 if (!isempty(arg_root))
3756 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3757 else
3758 asprintf(&p, "%s/%s", *k, name);
ee5762e3 3759
729e3769
LP
3760 if (!p) {
3761 log_error("No memory");
3762 r = -ENOMEM;
3763 goto finish;
3764 }
ee5762e3 3765
729e3769
LP
3766 found_native = access(p, F_OK) >= 0;
3767 free(p);
ee5762e3 3768
729e3769
LP
3769 if (found_native)
3770 break;
3771 }
ee5762e3 3772
729e3769
LP
3773 if (found_native)
3774 continue;
ee5762e3 3775
729e3769
LP
3776 p = NULL;
3777 if (!isempty(arg_root))
3778 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3779 else
3780 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3781 if (!p) {
3782 log_error("No memory");
3783 r = -ENOMEM;
3784 goto finish;
3785 }
ee5762e3 3786
729e3769
LP
3787 p[strlen(p) - sizeof(".service") + 1] = 0;
3788 found_sysv = access(p, F_OK) >= 0;
ee5762e3 3789
729e3769
LP
3790 if (!found_sysv) {
3791 free(p);
3792 continue;
71fad675
LP
3793 }
3794
729e3769
LP
3795 /* Mark this entry, so that we don't try enabling it as native unit */
3796 args[f] = (char*) "";
ee5762e3 3797
729e3769 3798 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 3799
729e3769
LP
3800 if (!isempty(arg_root))
3801 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 3802
9eb977db 3803 argv[c++] = path_get_file_name(p);
729e3769
LP
3804 argv[c++] =
3805 streq(verb, "enable") ? "on" :
3806 streq(verb, "disable") ? "off" : "--level=5";
3807 argv[c] = NULL;
ee5762e3 3808
729e3769
LP
3809 l = strv_join((char**)argv, " ");
3810 if (!l) {
3811 log_error("No memory.");
3812 free(q);
3813 free(p);
3814 r = -ENOMEM;
3815 goto finish;
3816 }
ee5762e3 3817
729e3769
LP
3818 log_info("Executing %s", l);
3819 free(l);
ee5762e3 3820
729e3769
LP
3821 pid = fork();
3822 if (pid < 0) {
3823 log_error("Failed to fork: %m");
3824 free(p);
3825 free(q);
3826 r = -errno;
3827 goto finish;
3828 } else if (pid == 0) {
3829 /* Child */
ee5762e3 3830
729e3769
LP
3831 execv(argv[0], (char**) argv);
3832 _exit(EXIT_FAILURE);
3833 }
ee5762e3 3834
729e3769
LP
3835 free(p);
3836 free(q);
ee5762e3 3837
729e3769
LP
3838 j = wait_for_terminate(pid, &status);
3839 if (j < 0) {
3840 log_error("Failed to wait for child: %s", strerror(-r));
3841 r = j;
3842 goto finish;
3843 }
ee5762e3 3844
729e3769
LP
3845 if (status.si_code == CLD_EXITED) {
3846 if (streq(verb, "is-enabled")) {
3847 if (status.si_status == 0) {
3848 if (!arg_quiet)
3849 puts("enabled");
3850 r = 1;
3851 } else {
3852 if (!arg_quiet)
3853 puts("disabled");
3854 }
ee5762e3 3855
729e3769
LP
3856 } else if (status.si_status != 0) {
3857 r = -EINVAL;
3858 goto finish;
3859 }
3860 } else {
3861 r = -EPROTO;
3862 goto finish;
3863 }
ee5762e3
LP
3864 }
3865
729e3769
LP
3866finish:
3867 lookup_paths_free(&paths);
ee5762e3 3868
729e3769
LP
3869 /* Drop all SysV units */
3870 for (f = 1, t = 1; args[f]; f++) {
ee5762e3 3871
729e3769 3872 if (isempty(args[f]))
ee5762e3
LP
3873 continue;
3874
729e3769
LP
3875 args[t++] = args[f];
3876 }
ee5762e3 3877
729e3769 3878 args[t] = NULL;
ee5762e3 3879
729e3769
LP
3880#endif
3881 return r;
3882}
ee5762e3 3883
729e3769
LP
3884static int enable_unit(DBusConnection *bus, char **args) {
3885 const char *verb = args[0];
3886 UnitFileChange *changes = NULL;
3887 unsigned n_changes = 0, i;
3888 int carries_install_info = -1;
3889 DBusMessage *m = NULL, *reply = NULL;
3890 int r;
3891 DBusError error;
ee5762e3 3892
729e3769
LP
3893 r = enable_sysv_units(args);
3894 if (r < 0)
3895 return r;
ee5762e3 3896
ab5919fa
MS
3897 if (!args[1])
3898 return 0;
3899
3900 dbus_error_init(&error);
3901
729e3769
LP
3902 if (!bus || avoid_bus()) {
3903 if (streq(verb, "enable")) {
3904 r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3905 carries_install_info = r;
3906 } else if (streq(verb, "disable"))
3907 r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3908 else if (streq(verb, "reenable")) {
3909 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3910 carries_install_info = r;
3911 } else if (streq(verb, "link"))
3912 r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3913 else if (streq(verb, "preset")) {
3914 r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3915 carries_install_info = r;
3916 } else if (streq(verb, "mask"))
3917 r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3918 else if (streq(verb, "unmask"))
3919 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3920 else
3921 assert_not_reached("Unknown verb");
ee5762e3 3922
729e3769
LP
3923 if (r < 0) {
3924 log_error("Operation failed: %s", strerror(-r));
3925 goto finish;
ee5762e3
LP
3926 }
3927
d1f262fa
LP
3928 if (!arg_quiet) {
3929 for (i = 0; i < n_changes; i++) {
3930 if (changes[i].type == UNIT_FILE_SYMLINK)
3931 log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3932 else
3933 log_info("rm '%s'", changes[i].path);
3934 }
ee5762e3
LP
3935 }
3936
729e3769
LP
3937 } else {
3938 const char *method;
3939 bool send_force = true, expect_carries_install_info = false;
3940 dbus_bool_t a, b;
3941 DBusMessageIter iter, sub, sub2;
3942
3943 if (streq(verb, "enable")) {
3944 method = "EnableUnitFiles";
3945 expect_carries_install_info = true;
3946 } else if (streq(verb, "disable")) {
3947 method = "DisableUnitFiles";
3948 send_force = false;
3949 } else if (streq(verb, "reenable")) {
3950 method = "ReenableUnitFiles";
3951 expect_carries_install_info = true;
3952 } else if (streq(verb, "link"))
3953 method = "LinkUnitFiles";
3954 else if (streq(verb, "preset")) {
3955 method = "PresetUnitFiles";
3956 expect_carries_install_info = true;
3957 } else if (streq(verb, "mask"))
3958 method = "MaskUnitFiles";
3959 else if (streq(verb, "unmask")) {
3960 method = "UnmaskUnitFiles";
3961 send_force = false;
3962 } else
3963 assert_not_reached("Unknown verb");
3964
3965 m = dbus_message_new_method_call(
3966 "org.freedesktop.systemd1",
3967 "/org/freedesktop/systemd1",
3968 "org.freedesktop.systemd1.Manager",
3969 method);
3970 if (!m) {
ee5762e3
LP
3971 log_error("Out of memory");
3972 r = -ENOMEM;
3973 goto finish;
3974 }
3975
729e3769 3976 dbus_message_iter_init_append(m, &iter);
ee5762e3 3977
729e3769
LP
3978 r = bus_append_strv_iter(&iter, args+1);
3979 if (r < 0) {
3980 log_error("Failed to append unit files.");
ee5762e3
LP
3981 goto finish;
3982 }
3983
729e3769
LP
3984 a = arg_runtime;
3985 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3986 log_error("Failed to append runtime boolean.");
ee5762e3
LP
3987 r = -ENOMEM;
3988 goto finish;
3989 }
3990
729e3769
LP
3991 if (send_force) {
3992 b = arg_force;
be394c48 3993
729e3769
LP
3994 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3995 log_error("Failed to append force boolean.");
3996 r = -ENOMEM;
3997 goto finish;
3998 }
09adcdf7 3999 }
ee5762e3 4000
729e3769
LP
4001 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4002 if (!reply) {
4003 log_error("Failed to issue method call: %s", bus_error_message(&error));
4004 r = -EIO;
4005 goto finish;
ee5762e3
LP
4006 }
4007
729e3769
LP
4008 if (!dbus_message_iter_init(reply, &iter)) {
4009 log_error("Failed to initialize iterator.");
4010 goto finish;
4011 }
be394c48 4012
729e3769
LP
4013 if (expect_carries_install_info) {
4014 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
4015 if (r < 0) {
4016 log_error("Failed to parse reply.");
4017 goto finish;
4018 }
ee5762e3 4019
729e3769 4020 carries_install_info = b;
ee5762e3
LP
4021 }
4022
729e3769
LP
4023 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
4024 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
4025 log_error("Failed to parse reply.");
4026 r = -EIO;
4027 goto finish;
ee5762e3
LP
4028 }
4029
729e3769
LP
4030 dbus_message_iter_recurse(&iter, &sub);
4031 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
4032 const char *type, *path, *source;
c8b2e52c 4033
729e3769
LP
4034 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
4035 log_error("Failed to parse reply.");
4036 r = -EIO;
4037 goto finish;
c8b2e52c
LP
4038 }
4039
729e3769 4040 dbus_message_iter_recurse(&sub, &sub2);
c8b2e52c 4041
729e3769
LP
4042 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
4043 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
4044 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
4045 log_error("Failed to parse reply.");
4046 r = -EIO;
4047 goto finish;
c8b2e52c
LP
4048 }
4049
d1f262fa
LP
4050 if (!arg_quiet) {
4051 if (streq(type, "symlink"))
4052 log_info("ln -s '%s' '%s'", source, path);
4053 else
4054 log_info("rm '%s'", path);
4055 }
b77398f7 4056
729e3769
LP
4057 dbus_message_iter_next(&sub);
4058 }
b77398f7 4059
729e3769
LP
4060 /* Try to reload if enabeld */
4061 if (!arg_no_reload)
4062 r = daemon_reload(bus, args);
b647f10d 4063 }
3d3961f2 4064
729e3769
LP
4065 if (carries_install_info == 0)
4066 log_warning("Warning: unit files do not carry install information. No operation executed.");
ee5762e3 4067
729e3769
LP
4068finish:
4069 if (m)
4070 dbus_message_unref(m);
ee5762e3 4071
729e3769
LP
4072 if (reply)
4073 dbus_message_unref(reply);
ee5762e3 4074
729e3769 4075 unit_file_changes_free(changes, n_changes);
ee5762e3 4076
729e3769
LP
4077 dbus_error_free(&error);
4078 return r;
ee5762e3
LP
4079}
4080
729e3769 4081static int unit_is_enabled(DBusConnection *bus, char **args) {
ee5762e3
LP
4082 DBusError error;
4083 int r;
729e3769
LP
4084 DBusMessage *m = NULL, *reply = NULL;
4085 bool enabled;
4086 char **name;
ee5762e3
LP
4087
4088 dbus_error_init(&error);
4089
729e3769
LP
4090 r = enable_sysv_units(args);
4091 if (r < 0)
4092 return r;
ee5762e3 4093
729e3769 4094 enabled = r > 0;
ee5762e3 4095
729e3769 4096 if (!bus || avoid_bus()) {
ee5762e3 4097
729e3769
LP
4098 STRV_FOREACH(name, args+1) {
4099 UnitFileState state;
ee5762e3 4100
729e3769
LP
4101 state = unit_file_get_state(arg_scope, arg_root, *name);
4102 if (state < 0) {
4103 r = state;
4104 goto finish;
4105 }
ee5762e3 4106
729e3769
LP
4107 if (state == UNIT_FILE_ENABLED ||
4108 state == UNIT_FILE_ENABLED_RUNTIME ||
4109 state == UNIT_FILE_STATIC)
4110 enabled = true;
4111
4112 if (!arg_quiet)
4113 puts(unit_file_state_to_string(state));
71fad675 4114 }
ee5762e3 4115
729e3769
LP
4116 } else {
4117 STRV_FOREACH(name, args+1) {
4118 const char *s;
63a723f3 4119
729e3769
LP
4120 m = dbus_message_new_method_call(
4121 "org.freedesktop.systemd1",
4122 "/org/freedesktop/systemd1",
4123 "org.freedesktop.systemd1.Manager",
4124 "GetUnitFileState");
4125 if (!m) {
4126 log_error("Out of memory");
4127 r = -ENOMEM;
4128 goto finish;
4129 }
ee5762e3 4130
729e3769
LP
4131 if (!dbus_message_append_args(m,
4132 DBUS_TYPE_STRING, name,
4133 DBUS_TYPE_INVALID)) {
4134 log_error("Could not append arguments to message.");
4135 r = -ENOMEM;
4136 goto finish;
4137 }
ee5762e3 4138
729e3769
LP
4139 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4140 if (!reply) {
4141 log_error("Failed to issue method call: %s", bus_error_message(&error));
4142 r = -EIO;
4143 goto finish;
4144 }
ee5762e3 4145
729e3769
LP
4146 if (!dbus_message_get_args(reply, &error,
4147 DBUS_TYPE_STRING, &s,
4148 DBUS_TYPE_INVALID)) {
4149 log_error("Failed to parse reply: %s", bus_error_message(&error));
4150 r = -EIO;
ee5762e3
LP
4151 goto finish;
4152 }
4153
729e3769
LP
4154 dbus_message_unref(m);
4155 dbus_message_unref(reply);
4156 m = reply = NULL;
ee5762e3 4157
729e3769
LP
4158 if (streq(s, "enabled") ||
4159 streq(s, "enabled-runtime") ||
4160 streq(s, "static"))
4161 enabled = true;
4162
4163 if (!arg_quiet)
4164 puts(s);
560d8f23 4165 }
ee5762e3
LP
4166 }
4167
729e3769 4168 r = enabled ? 0 : 1;
ee5762e3 4169
729e3769
LP
4170finish:
4171 if (m)
4172 dbus_message_unref(m);
ee5762e3 4173
729e3769
LP
4174 if (reply)
4175 dbus_message_unref(reply);
ee5762e3 4176
729e3769 4177 dbus_error_free(&error);
ee5762e3
LP
4178 return r;
4179}
4180
e4b61340 4181static int systemctl_help(void) {
7e4249b9 4182
729e3769
LP
4183 pager_open_if_enabled();
4184
2e33c433 4185 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 4186 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
4187 " -h --help Show this help\n"
4188 " --version Show package version\n"
4189 " -t --type=TYPE List only units of a particular type\n"
4190 " -p --property=NAME Show only properties by this name\n"
4191 " -a --all Show all units/properties, including dead/empty ones\n"
30732560 4192 " --failed Show only failed units\n"
8a0867d6
LP
4193 " --full Don't ellipsize unit names on output\n"
4194 " --fail When queueing a new job, fail if conflicting jobs are\n"
4195 " pending\n"
e67c3609
LP
4196 " --ignore-dependencies\n"
4197 " When queueing a new job, ignore all its dependencies\n"
a8f11321
LP
4198 " --kill-who=WHO Who to send signal to\n"
4199 " -s --signal=SIGNAL Which signal to send\n"
aca4c786 4200 " -H --host=[USER@]HOST\n"
a8f11321
LP
4201 " Show information for remote host\n"
4202 " -P --privileged Acquire privileges before execution\n"
8a0867d6
LP
4203 " -q --quiet Suppress output\n"
4204 " --no-block Do not wait until operation finished\n"
8a0867d6 4205 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
4206 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4207 " configuration\n"
ebed32bf 4208 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 4209 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
4210 " --no-ask-password\n"
4211 " Do not ask for system passwords\n"
a8f11321
LP
4212 " --order When generating graph for dot, show only order\n"
4213 " --require When generating graph for dot, show only requirement\n"
4214 " --system Connect to system manager\n"
4215 " --user Connect to user service manager\n"
4216 " --global Enable/disable unit files globally\n"
8a0867d6
LP
4217 " -f --force When enabling unit files, override existing symlinks\n"
4218 " When shutting down, execute action immediately\n"
729e3769 4219 " --root=PATH Enable unit files in the specified root directory\n"
df50185b
LP
4220 " --runtime Enable unit files only temporarily until next reboot\n"
4221 " -n --lines=INTEGER Journal entries to show\n"
4222 " --follow Follow journal\n"
d3f2bdbf
LP
4223 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
4224 " verbose, export, json, cat)\n\n"
34c4b47b 4225 "Unit Commands:\n"
729e3769 4226 " list-units List loaded units\n"
ee5762e3
LP
4227 " start [NAME...] Start (activate) one or more units\n"
4228 " stop [NAME...] Stop (deactivate) one or more units\n"
7e4249b9 4229 " reload [NAME...] Reload one or more units\n"
6f28c033
LP
4230 " restart [NAME...] Start or restart one or more units\n"
4231 " try-restart [NAME...] Restart one or more units if active\n"
4232 " reload-or-restart [NAME...] Reload one or more units is possible,\n"
4233 " otherwise start or restart\n"
4234 " reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4235 " otherwise restart if active\n"
7e4249b9 4236 " isolate [NAME] Start one unit and stop all others\n"
8a0867d6 4237 " kill [NAME...] Send signal to processes of a unit\n"
ee5762e3 4238 " is-active [NAME...] Check whether units are active\n"
75676b72 4239 " status [NAME...|PID...] Show runtime status of one or more units\n"
6f28c033 4240 " show [NAME...|JOB...] Show properties of one or more\n"
ee5762e3 4241 " units/jobs or the manager\n"
fdf20a31
MM
4242 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4243 " units\n"
34c4b47b
LP
4244 " load [NAME...] Load one or more units\n\n"
4245 "Unit File Commands:\n"
729e3769 4246 " list-unit-files List installed unit files\n"
ee5762e3
LP
4247 " enable [NAME...] Enable one or more unit files\n"
4248 " disable [NAME...] Disable one or more unit files\n"
729e3769
LP
4249 " reenable [NAME...] Reenable one or more unit files\n"
4250 " preset [NAME...] Enable/disable one or more unit files\n"
4251 " based on preset configuration\n"
4252 " mask [NAME...] Mask one or more units\n"
4253 " unmask [NAME...] Unmask one or more units\n"
4254 " link [PATH...] Link one or more units files into\n"
4255 " the search path\n"
34c4b47b
LP
4256 " is-enabled [NAME...] Check whether unit files are enabled\n\n"
4257 "Job Commands:\n"
48220598 4258 " list-jobs List jobs\n"
34c4b47b
LP
4259 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
4260 "Status Commands:\n"
7e4249b9 4261 " dump Dump server status\n"
34c4b47b
LP
4262 " dot Dump dependency graph for dot(1)\n\n"
4263 "Snapshot Commands:\n"
7e4249b9 4264 " snapshot [NAME] Create a snapshot\n"
34c4b47b
LP
4265 " delete [NAME...] Remove one or more snapshots\n\n"
4266 "Environment Commands:\n"
7e4249b9
LP
4267 " show-environment Dump environment\n"
4268 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
34c4b47b
LP
4269 " unset-environment [NAME...] Unset one or more environment variables\n\n"
4270 "Manager Lifecycle Commands:\n"
4271 " daemon-reload Reload systemd manager configuration\n"
4272 " daemon-reexec Reexecute systemd manager\n\n"
4273 "System Commands:\n"
20b09ca7
LP
4274 " default Enter system default mode\n"
4275 " rescue Enter system rescue mode\n"
4276 " emergency Enter system emergency mode\n"
514f4ef5 4277 " halt Shut down and halt the system\n"
2e33c433 4278 " poweroff Shut down and power-off the system\n"
514f4ef5 4279 " reboot Shut down and reboot the system\n"
20b09ca7 4280 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a 4281 " exit Request user instance exit\n"
957eb8ca 4282 " switch-root [ROOT] [INIT] Change to a different root file system\n"
6edd7d0a
LP
4283 " suspend Suspend the system\n"
4284 " hibernate Hibernate the system\n",
5b6319dc 4285 program_invocation_short_name);
7e4249b9
LP
4286
4287 return 0;
4288}
4289
e4b61340
LP
4290static int halt_help(void) {
4291
2e33c433 4292 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4293 "%s the system.\n\n"
4294 " --help Show this help\n"
4295 " --halt Halt the machine\n"
4296 " -p --poweroff Switch off the machine\n"
4297 " --reboot Reboot the machine\n"
2e33c433
LP
4298 " -f --force Force immediate halt/power-off/reboot\n"
4299 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 4300 " -d --no-wtmp Don't write wtmp record\n"
2e33c433
LP
4301 " -n --no-sync Don't sync before halt/power-off/reboot\n"
4302 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340
LP
4303 program_invocation_short_name,
4304 arg_action == ACTION_REBOOT ? "Reboot" :
4305 arg_action == ACTION_POWEROFF ? "Power off" :
4306 "Halt");
4307
4308 return 0;
4309}
4310
4311static int shutdown_help(void) {
4312
08e4b1c5 4313 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
4314 "Shut down the system.\n\n"
4315 " --help Show this help\n"
4316 " -H --halt Halt the machine\n"
4317 " -P --poweroff Power-off the machine\n"
4318 " -r --reboot Reboot the machine\n"
4319 " -h Equivalent to --poweroff, overriden by --halt\n"
2e33c433 4320 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 4321 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 4322 " -c Cancel a pending shutdown\n",
e4b61340
LP
4323 program_invocation_short_name);
4324
4325 return 0;
4326}
4327
4328static int telinit_help(void) {
4329
2e33c433 4330 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
4331 "Send control commands to the init daemon.\n\n"
4332 " --help Show this help\n"
2e33c433 4333 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
4334 "Commands:\n"
4335 " 0 Power-off the machine\n"
4336 " 6 Reboot the machine\n"
514f4ef5
LP
4337 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4338 " 1, s, S Enter rescue mode\n"
4339 " q, Q Reload init daemon configuration\n"
4340 " u, U Reexecute init daemon\n",
e4b61340
LP
4341 program_invocation_short_name);
4342
4343 return 0;
4344}
4345
4346static int runlevel_help(void) {
4347
2e33c433 4348 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4349 "Prints the previous and current runlevel of the init system.\n\n"
4350 " --help Show this help\n",
4351 program_invocation_short_name);
4352
4353 return 0;
4354}
4355
4356static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
4357
4358 enum {
90d473a1 4359 ARG_FAIL = 0x100,
e67c3609 4360 ARG_IGNORE_DEPENDENCIES,
35df8f27 4361 ARG_VERSION,
af2d49f7 4362 ARG_USER,
7e4249b9 4363 ARG_SYSTEM,
ee5762e3 4364 ARG_GLOBAL,
6e905d93 4365 ARG_NO_BLOCK,
ebed32bf 4366 ARG_NO_LEGEND,
611efaac 4367 ARG_NO_PAGER,
4445a875
LP
4368 ARG_NO_WALL,
4369 ARG_ORDER,
8fe914ec 4370 ARG_REQUIRE,
be394c48 4371 ARG_ROOT,
ee5762e3 4372 ARG_FULL,
ee5762e3 4373 ARG_NO_RELOAD,
8a0867d6 4374 ARG_KILL_MODE,
501fc174 4375 ARG_KILL_WHO,
30732560 4376 ARG_NO_ASK_PASSWORD,
729e3769 4377 ARG_FAILED,
df50185b 4378 ARG_RUNTIME,
568b679f
LP
4379 ARG_FOLLOW,
4380 ARG_FORCE
7e4249b9
LP
4381 };
4382
4383 static const struct option options[] = {
ee5762e3 4384 { "help", no_argument, NULL, 'h' },
35df8f27 4385 { "version", no_argument, NULL, ARG_VERSION },
ee5762e3
LP
4386 { "type", required_argument, NULL, 't' },
4387 { "property", required_argument, NULL, 'p' },
4388 { "all", no_argument, NULL, 'a' },
30732560 4389 { "failed", no_argument, NULL, ARG_FAILED },
ee5762e3
LP
4390 { "full", no_argument, NULL, ARG_FULL },
4391 { "fail", no_argument, NULL, ARG_FAIL },
e67c3609 4392 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
af2d49f7 4393 { "user", no_argument, NULL, ARG_USER },
ee5762e3
LP
4394 { "system", no_argument, NULL, ARG_SYSTEM },
4395 { "global", no_argument, NULL, ARG_GLOBAL },
4396 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
ebed32bf 4397 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
0736af98 4398 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
ee5762e3
LP
4399 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4400 { "quiet", no_argument, NULL, 'q' },
4401 { "order", no_argument, NULL, ARG_ORDER },
4402 { "require", no_argument, NULL, ARG_REQUIRE },
be394c48 4403 { "root", required_argument, NULL, ARG_ROOT },
568b679f 4404 { "force", no_argument, NULL, ARG_FORCE },
ee5762e3 4405 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
69fc152f 4406 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
8a0867d6
LP
4407 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
4408 { "signal", required_argument, NULL, 's' },
501fc174 4409 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
a8f11321
LP
4410 { "host", required_argument, NULL, 'H' },
4411 { "privileged",no_argument, NULL, 'P' },
729e3769 4412 { "runtime", no_argument, NULL, ARG_RUNTIME },
df50185b
LP
4413 { "lines", required_argument, NULL, 'n' },
4414 { "follow", no_argument, NULL, ARG_FOLLOW },
4415 { "output", required_argument, NULL, 'o' },
ee5762e3 4416 { NULL, 0, NULL, 0 }
7e4249b9
LP
4417 };
4418
4419 int c;
4420
e4b61340 4421 assert(argc >= 0);
7e4249b9
LP
4422 assert(argv);
4423
df50185b 4424 while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
7e4249b9
LP
4425
4426 switch (c) {
4427
4428 case 'h':
e4b61340 4429 systemctl_help();
7e4249b9 4430 return 0;
35df8f27
LP
4431
4432 case ARG_VERSION:
4433 puts(PACKAGE_STRING);
7d568925
LP
4434 puts(DISTRIBUTION);
4435 puts(SYSTEMD_FEATURES);
35df8f27 4436 return 0;
7e4249b9
LP
4437
4438 case 't':
4439 arg_type = optarg;
4440 break;
4441
ea4a240d
LP
4442 case 'p': {
4443 char **l;
4444
4445 if (!(l = strv_append(arg_property, optarg)))
4446 return -ENOMEM;
4447
4448 strv_free(arg_property);
4449 arg_property = l;
48220598
LP
4450
4451 /* If the user asked for a particular
4452 * property, show it to him, even if it is
4453 * empty. */
4454 arg_all = true;
4455 break;
ea4a240d 4456 }
48220598 4457
7e4249b9
LP
4458 case 'a':
4459 arg_all = true;
4460 break;
4461
90d473a1 4462 case ARG_FAIL:
e67c3609
LP
4463 arg_job_mode = "fail";
4464 break;
4465
4466 case ARG_IGNORE_DEPENDENCIES:
4467 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
4468 break;
4469
af2d49f7 4470 case ARG_USER:
729e3769 4471 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
4472 break;
4473
4474 case ARG_SYSTEM:
729e3769
LP
4475 arg_scope = UNIT_FILE_SYSTEM;
4476 break;
4477
4478 case ARG_GLOBAL:
4479 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
4480 break;
4481
6e905d93
LP
4482 case ARG_NO_BLOCK:
4483 arg_no_block = true;
7e4249b9
LP
4484 break;
4485
ebed32bf
MS
4486 case ARG_NO_LEGEND:
4487 arg_no_legend = true;
4488 break;
4489
611efaac
LP
4490 case ARG_NO_PAGER:
4491 arg_no_pager = true;
4492 break;
0736af98 4493
514f4ef5
LP
4494 case ARG_NO_WALL:
4495 arg_no_wall = true;
4496 break;
4497
4445a875
LP
4498 case ARG_ORDER:
4499 arg_dot = DOT_ORDER;
4500 break;
4501
4502 case ARG_REQUIRE:
4503 arg_dot = DOT_REQUIRE;
4504 break;
4505
be394c48
FC
4506 case ARG_ROOT:
4507 arg_root = optarg;
4508 break;
4509
8fe914ec
LP
4510 case ARG_FULL:
4511 arg_full = true;
4512 break;
4513
30732560
LP
4514 case ARG_FAILED:
4515 arg_failed = true;
4516 break;
4517
0183528f
LP
4518 case 'q':
4519 arg_quiet = true;
4520 break;
4521
568b679f
LP
4522 case ARG_FORCE:
4523 arg_force ++;
4524 break;
4525
4526 case ARG_FOLLOW:
4527 arg_follow = true;
4528 break;
4529
b4f27ccc 4530 case 'f':
568b679f 4531 /* -f is short for both --follow and --force! */
e606bb61 4532 arg_force ++;
568b679f 4533 arg_follow = true;
ee5762e3
LP
4534 break;
4535
4536 case ARG_NO_RELOAD:
4537 arg_no_reload = true;
4538 break;
4539
8a0867d6
LP
4540 case ARG_KILL_WHO:
4541 arg_kill_who = optarg;
4542 break;
4543
4544 case ARG_KILL_MODE:
4545 arg_kill_mode = optarg;
4546 break;
4547
4548 case 's':
4549 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4550 log_error("Failed to parse signal string %s.", optarg);
4551 return -EINVAL;
4552 }
4553 break;
4554
501fc174
LP
4555 case ARG_NO_ASK_PASSWORD:
4556 arg_ask_password = false;
4557 break;
4558
a8f11321
LP
4559 case 'P':
4560 arg_transport = TRANSPORT_POLKIT;
4561 break;
4562
4563 case 'H':
4564 arg_transport = TRANSPORT_SSH;
4565 arg_host = optarg;
4566 break;
4567
729e3769
LP
4568 case ARG_RUNTIME:
4569 arg_runtime = true;
4570 break;
4571
df50185b
LP
4572 case 'n':
4573 if (safe_atou(optarg, &arg_lines) < 0) {
4574 log_error("Failed to parse lines '%s'", optarg);
4575 return -EINVAL;
4576 }
4577 break;
4578
df50185b
LP
4579 case 'o':
4580 arg_output = output_mode_from_string(optarg);
4581 if (arg_output < 0) {
4582 log_error("Unknown output '%s'.", optarg);
4583 return -EINVAL;
4584 }
4585 break;
4586
7e4249b9
LP
4587 case '?':
4588 return -EINVAL;
4589
4590 default:
4591 log_error("Unknown option code %c", c);
4592 return -EINVAL;
4593 }
4594 }
4595
729e3769 4596 if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
4597 log_error("Cannot access user instance remotely.");
4598 return -EINVAL;
4599 }
4600
7e4249b9
LP
4601 return 1;
4602}
4603
e4b61340
LP
4604static int halt_parse_argv(int argc, char *argv[]) {
4605
4606 enum {
4607 ARG_HELP = 0x100,
4608 ARG_HALT,
514f4ef5
LP
4609 ARG_REBOOT,
4610 ARG_NO_WALL
e4b61340
LP
4611 };
4612
4613 static const struct option options[] = {
4614 { "help", no_argument, NULL, ARG_HELP },
4615 { "halt", no_argument, NULL, ARG_HALT },
4616 { "poweroff", no_argument, NULL, 'p' },
4617 { "reboot", no_argument, NULL, ARG_REBOOT },
4618 { "force", no_argument, NULL, 'f' },
4619 { "wtmp-only", no_argument, NULL, 'w' },
4620 { "no-wtmp", no_argument, NULL, 'd' },
4621 { "no-sync", no_argument, NULL, 'n' },
514f4ef5 4622 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
4623 { NULL, 0, NULL, 0 }
4624 };
4625
4626 int c, runlevel;
4627
4628 assert(argc >= 0);
4629 assert(argv);
4630
4631 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4632 if (runlevel == '0' || runlevel == '6')
65491fd8 4633 arg_force = 2;
e4b61340
LP
4634
4635 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4636 switch (c) {
4637
4638 case ARG_HELP:
4639 halt_help();
4640 return 0;
4641
4642 case ARG_HALT:
4643 arg_action = ACTION_HALT;
4644 break;
4645
4646 case 'p':
a042efad
MS
4647 if (arg_action != ACTION_REBOOT)
4648 arg_action = ACTION_POWEROFF;
e4b61340
LP
4649 break;
4650
4651 case ARG_REBOOT:
4652 arg_action = ACTION_REBOOT;
4653 break;
4654
4655 case 'f':
65491fd8 4656 arg_force = 2;
e4b61340
LP
4657 break;
4658
4659 case 'w':
4660 arg_dry = true;
4661 break;
4662
4663 case 'd':
4664 arg_no_wtmp = true;
4665 break;
4666
4667 case 'n':
4668 arg_no_sync = true;
4669 break;
4670
514f4ef5
LP
4671 case ARG_NO_WALL:
4672 arg_no_wall = true;
4673 break;
4674
e4b61340
LP
4675 case 'i':
4676 case 'h':
4677 /* Compatibility nops */
4678 break;
4679
4680 case '?':
4681 return -EINVAL;
4682
4683 default:
4684 log_error("Unknown option code %c", c);
4685 return -EINVAL;
4686 }
4687 }
4688
4689 if (optind < argc) {
4690 log_error("Too many arguments.");
4691 return -EINVAL;
4692 }
4693
4694 return 1;
4695}
4696
f6144808
LP
4697static int parse_time_spec(const char *t, usec_t *_u) {
4698 assert(t);
4699 assert(_u);
4700
4701 if (streq(t, "now"))
4702 *_u = 0;
1a639877 4703 else if (!strchr(t, ':')) {
f6144808
LP
4704 uint64_t u;
4705
1a639877 4706 if (safe_atou64(t, &u) < 0)
f6144808
LP
4707 return -EINVAL;
4708
4709 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4710 } else {
4711 char *e = NULL;
4712 long hour, minute;
4713 struct tm tm;
4714 time_t s;
4715 usec_t n;
4716
4717 errno = 0;
4718 hour = strtol(t, &e, 10);
4719 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4720 return -EINVAL;
4721
4722 minute = strtol(e+1, &e, 10);
4723 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4724 return -EINVAL;
4725
4726 n = now(CLOCK_REALTIME);
08e4b1c5
LP
4727 s = (time_t) (n / USEC_PER_SEC);
4728
4729 zero(tm);
f6144808
LP
4730 assert_se(localtime_r(&s, &tm));
4731
4732 tm.tm_hour = (int) hour;
4733 tm.tm_min = (int) minute;
08e4b1c5 4734 tm.tm_sec = 0;
f6144808
LP
4735
4736 assert_se(s = mktime(&tm));
4737
4738 *_u = (usec_t) s * USEC_PER_SEC;
4739
4740 while (*_u <= n)
4741 *_u += USEC_PER_DAY;
4742 }
4743
4744 return 0;
4745}
4746
e4b61340
LP
4747static int shutdown_parse_argv(int argc, char *argv[]) {
4748
4749 enum {
4750 ARG_HELP = 0x100,
514f4ef5 4751 ARG_NO_WALL
e4b61340
LP
4752 };
4753
4754 static const struct option options[] = {
4755 { "help", no_argument, NULL, ARG_HELP },
4756 { "halt", no_argument, NULL, 'H' },
4757 { "poweroff", no_argument, NULL, 'P' },
4758 { "reboot", no_argument, NULL, 'r' },
04ebb595 4759 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 4760 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
4761 { NULL, 0, NULL, 0 }
4762 };
4763
f6144808 4764 int c, r;
e4b61340
LP
4765
4766 assert(argc >= 0);
4767 assert(argv);
4768
f6144808 4769 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
e4b61340
LP
4770 switch (c) {
4771
4772 case ARG_HELP:
4773 shutdown_help();
4774 return 0;
4775
4776 case 'H':
4777 arg_action = ACTION_HALT;
4778 break;
4779
4780 case 'P':
4781 arg_action = ACTION_POWEROFF;
4782 break;
4783
4784 case 'r':
5622dde3
KS
4785 if (kexec_loaded())
4786 arg_action = ACTION_KEXEC;
4787 else
4788 arg_action = ACTION_REBOOT;
e4b61340
LP
4789 break;
4790
04ebb595
LP
4791 case 'K':
4792 arg_action = ACTION_KEXEC;
4793 break;
4794
e4b61340
LP
4795 case 'h':
4796 if (arg_action != ACTION_HALT)
4797 arg_action = ACTION_POWEROFF;
4798 break;
4799
4800 case 'k':
4801 arg_dry = true;
4802 break;
4803
514f4ef5
LP
4804 case ARG_NO_WALL:
4805 arg_no_wall = true;
4806 break;
4807
e4b61340
LP
4808 case 't':
4809 case 'a':
4810 /* Compatibility nops */
4811 break;
4812
f6144808
LP
4813 case 'c':
4814 arg_action = ACTION_CANCEL_SHUTDOWN;
4815 break;
4816
e4b61340
LP
4817 case '?':
4818 return -EINVAL;
4819
4820 default:
4821 log_error("Unknown option code %c", c);
4822 return -EINVAL;
4823 }
4824 }
4825
6b5ad000 4826 if (argc > optind) {
7e59bfcb
LP
4827 r = parse_time_spec(argv[optind], &arg_when);
4828 if (r < 0) {
f6144808
LP
4829 log_error("Failed to parse time specification: %s", argv[optind]);
4830 return r;
4831 }
6b5ad000 4832 } else
08e4b1c5 4833 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 4834
f6144808 4835 /* We skip the time argument */
e4b61340
LP
4836 if (argc > optind + 1)
4837 arg_wall = argv + optind + 1;
4838
4839 optind = argc;
4840
4841 return 1;
e4b61340
LP
4842}
4843
4844static int telinit_parse_argv(int argc, char *argv[]) {
4845
4846 enum {
4847 ARG_HELP = 0x100,
514f4ef5 4848 ARG_NO_WALL
e4b61340
LP
4849 };
4850
4851 static const struct option options[] = {
4852 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 4853 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
4854 { NULL, 0, NULL, 0 }
4855 };
4856
4857 static const struct {
4858 char from;
4859 enum action to;
4860 } table[] = {
4861 { '0', ACTION_POWEROFF },
4862 { '6', ACTION_REBOOT },
ef2f1067 4863 { '1', ACTION_RESCUE },
e4b61340
LP
4864 { '2', ACTION_RUNLEVEL2 },
4865 { '3', ACTION_RUNLEVEL3 },
4866 { '4', ACTION_RUNLEVEL4 },
4867 { '5', ACTION_RUNLEVEL5 },
4868 { 's', ACTION_RESCUE },
4869 { 'S', ACTION_RESCUE },
4870 { 'q', ACTION_RELOAD },
4871 { 'Q', ACTION_RELOAD },
4872 { 'u', ACTION_REEXEC },
4873 { 'U', ACTION_REEXEC }
4874 };
4875
4876 unsigned i;
4877 int c;
4878
4879 assert(argc >= 0);
4880 assert(argv);
4881
4882 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4883 switch (c) {
4884
4885 case ARG_HELP:
4886 telinit_help();
4887 return 0;
4888
514f4ef5
LP
4889 case ARG_NO_WALL:
4890 arg_no_wall = true;
4891 break;
4892
e4b61340
LP
4893 case '?':
4894 return -EINVAL;
4895
4896 default:
4897 log_error("Unknown option code %c", c);
4898 return -EINVAL;
4899 }
4900 }
4901
4902 if (optind >= argc) {
2f02ce40 4903 telinit_help();
e4b61340
LP
4904 return -EINVAL;
4905 }
4906
4907 if (optind + 1 < argc) {
4908 log_error("Too many arguments.");
4909 return -EINVAL;
4910 }
4911
4912 if (strlen(argv[optind]) != 1) {
4913 log_error("Expected single character argument.");
4914 return -EINVAL;
4915 }
4916
4917 for (i = 0; i < ELEMENTSOF(table); i++)
4918 if (table[i].from == argv[optind][0])
4919 break;
4920
4921 if (i >= ELEMENTSOF(table)) {
4922 log_error("Unknown command %s.", argv[optind]);
4923 return -EINVAL;
4924 }
4925
4926 arg_action = table[i].to;
4927
4928 optind ++;
4929
4930 return 1;
4931}
4932
4933static int runlevel_parse_argv(int argc, char *argv[]) {
4934
4935 enum {
4936 ARG_HELP = 0x100,
4937 };
4938
4939 static const struct option options[] = {
4940 { "help", no_argument, NULL, ARG_HELP },
4941 { NULL, 0, NULL, 0 }
4942 };
4943
4944 int c;
4945
4946 assert(argc >= 0);
4947 assert(argv);
4948
4949 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4950 switch (c) {
4951
4952 case ARG_HELP:
4953 runlevel_help();
4954 return 0;
4955
4956 case '?':
4957 return -EINVAL;
4958
4959 default:
4960 log_error("Unknown option code %c", c);
4961 return -EINVAL;
4962 }
4963 }
4964
4965 if (optind < argc) {
4966 log_error("Too many arguments.");
4967 return -EINVAL;
4968 }
4969
4970 return 1;
4971}
4972
4973static int parse_argv(int argc, char *argv[]) {
4974 assert(argc >= 0);
4975 assert(argv);
4976
4977 if (program_invocation_short_name) {
4978
4979 if (strstr(program_invocation_short_name, "halt")) {
4980 arg_action = ACTION_HALT;
4981 return halt_parse_argv(argc, argv);
4982 } else if (strstr(program_invocation_short_name, "poweroff")) {
4983 arg_action = ACTION_POWEROFF;
4984 return halt_parse_argv(argc, argv);
4985 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
4986 if (kexec_loaded())
4987 arg_action = ACTION_KEXEC;
4988 else
4989 arg_action = ACTION_REBOOT;
e4b61340
LP
4990 return halt_parse_argv(argc, argv);
4991 } else if (strstr(program_invocation_short_name, "shutdown")) {
4992 arg_action = ACTION_POWEROFF;
4993 return shutdown_parse_argv(argc, argv);
4994 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
4995
4996 if (sd_booted() > 0) {
4997 arg_action = ACTION_INVALID;
4998 return telinit_parse_argv(argc, argv);
4999 } else {
5000 /* Hmm, so some other init system is
5001 * running, we need to forward this
5002 * request to it. For now we simply
5003 * guess that it is Upstart. */
5004
5005 execv("/lib/upstart/telinit", argv);
5006
5007 log_error("Couldn't find an alternative telinit implementation to spawn.");
5008 return -EIO;
5009 }
5010
e4b61340
LP
5011 } else if (strstr(program_invocation_short_name, "runlevel")) {
5012 arg_action = ACTION_RUNLEVEL;
5013 return runlevel_parse_argv(argc, argv);
5014 }
5015 }
5016
5017 arg_action = ACTION_SYSTEMCTL;
5018 return systemctl_parse_argv(argc, argv);
5019}
5020
d55ae9e6 5021static int action_to_runlevel(void) {
eb22ac37
LP
5022
5023 static const char table[_ACTION_MAX] = {
5024 [ACTION_HALT] = '0',
5025 [ACTION_POWEROFF] = '0',
5026 [ACTION_REBOOT] = '6',
5027 [ACTION_RUNLEVEL2] = '2',
5028 [ACTION_RUNLEVEL3] = '3',
5029 [ACTION_RUNLEVEL4] = '4',
5030 [ACTION_RUNLEVEL5] = '5',
5031 [ACTION_RESCUE] = '1'
5032 };
5033
d55ae9e6
LP
5034 assert(arg_action < _ACTION_MAX);
5035
5036 return table[arg_action];
5037}
5038
f1c5860b 5039static int talk_upstart(void) {
d55ae9e6
LP
5040 DBusMessage *m = NULL, *reply = NULL;
5041 DBusError error;
5042 int previous, rl, r;
5043 char
5044 env1_buf[] = "RUNLEVEL=X",
5045 env2_buf[] = "PREVLEVEL=X";
5046 char *env1 = env1_buf, *env2 = env2_buf;
5047 const char *emit = "runlevel";
5048 dbus_bool_t b_false = FALSE;
5049 DBusMessageIter iter, sub;
f1c5860b 5050 DBusConnection *bus;
d55ae9e6
LP
5051
5052 dbus_error_init(&error);
5053
5054 if (!(rl = action_to_runlevel()))
5055 return 0;
5056
5057 if (utmp_get_runlevel(&previous, NULL) < 0)
5058 previous = 'N';
5059
b574246b 5060 if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
f1c5860b
LP
5061 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
5062 r = 0;
5063 goto finish;
5064 }
5065
4cf5d675 5066 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
f1c5860b
LP
5067 r = -EIO;
5068 goto finish;
5069 }
5070
5071 if ((r = bus_check_peercred(bus)) < 0) {
5072 log_error("Failed to verify owner of bus.");
5073 goto finish;
5074 }
5075
d55ae9e6
LP
5076 if (!(m = dbus_message_new_method_call(
5077 "com.ubuntu.Upstart",
5078 "/com/ubuntu/Upstart",
5079 "com.ubuntu.Upstart0_6",
5080 "EmitEvent"))) {
5081
5082 log_error("Could not allocate message.");
f1c5860b
LP
5083 r = -ENOMEM;
5084 goto finish;
d55ae9e6
LP
5085 }
5086
5087 dbus_message_iter_init_append(m, &iter);
5088
5089 env1_buf[sizeof(env1_buf)-2] = rl;
5090 env2_buf[sizeof(env2_buf)-2] = previous;
5091
5092 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5093 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5094 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5095 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5096 !dbus_message_iter_close_container(&iter, &sub) ||
5097 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5098 log_error("Could not append arguments to message.");
5099 r = -ENOMEM;
5100 goto finish;
5101 }
5102
5103 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5104
5105 if (error_is_no_service(&error)) {
aabd9b11 5106 r = -EADDRNOTAVAIL;
d55ae9e6
LP
5107 goto finish;
5108 }
5109
4cf5d675 5110 log_error("Failed to issue method call: %s", bus_error_message(&error));
d55ae9e6
LP
5111 r = -EIO;
5112 goto finish;
5113 }
5114
0a55b298 5115 r = 1;
d55ae9e6
LP
5116
5117finish:
5118 if (m)
5119 dbus_message_unref(m);
5120
5121 if (reply)
5122 dbus_message_unref(reply);
5123
b574246b 5124 if (bus) {
5d452f9c 5125 dbus_connection_flush(bus);
b574246b 5126 dbus_connection_close(bus);
f1c5860b 5127 dbus_connection_unref(bus);
b574246b 5128 }
f1c5860b 5129
d55ae9e6
LP
5130 dbus_error_free(&error);
5131
5132 return r;
5133}
5134
5135static int talk_initctl(void) {
eb22ac37
LP
5136 struct init_request request;
5137 int r, fd;
d55ae9e6 5138 char rl;
eb22ac37 5139
d55ae9e6 5140 if (!(rl = action_to_runlevel()))
eb22ac37
LP
5141 return 0;
5142
5143 zero(request);
5144 request.magic = INIT_MAGIC;
5145 request.sleeptime = 0;
5146 request.cmd = INIT_CMD_RUNLVL;
d55ae9e6
LP
5147 request.runlevel = rl;
5148
5149 if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5150
5151 if (errno == ENOENT)
5152 return 0;
eb22ac37 5153
d55ae9e6 5154 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 5155 return -errno;
d55ae9e6 5156 }
eb22ac37 5157
d55ae9e6 5158 errno = 0;
eb22ac37
LP
5159 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5160 close_nointr_nofail(fd);
5161
d55ae9e6
LP
5162 if (r < 0) {
5163 log_error("Failed to write to "INIT_FIFO": %m");
eb22ac37 5164 return errno ? -errno : -EIO;
d55ae9e6 5165 }
eb22ac37
LP
5166
5167 return 1;
e4b61340
LP
5168}
5169
ee5762e3 5170static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
7e4249b9 5171
7e4249b9
LP
5172 static const struct {
5173 const char* verb;
5174 const enum {
5175 MORE,
5176 LESS,
5177 EQUAL
5178 } argc_cmp;
5179 const int argc;
729e3769 5180 int (* const dispatch)(DBusConnection *bus, char **args);
7e4249b9 5181 } verbs[] = {
ee5762e3 5182 { "list-units", LESS, 1, list_units },
729e3769 5183 { "list-unit-files", EQUAL, 1, list_unit_files },
ee5762e3
LP
5184 { "list-jobs", EQUAL, 1, list_jobs },
5185 { "clear-jobs", EQUAL, 1, daemon_reload },
5186 { "load", MORE, 2, load_unit },
5187 { "cancel", MORE, 2, cancel_job },
5188 { "start", MORE, 2, start_unit },
5189 { "stop", MORE, 2, start_unit },
a76f7be2 5190 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5191 { "reload", MORE, 2, start_unit },
5192 { "restart", MORE, 2, start_unit },
5193 { "try-restart", MORE, 2, start_unit },
5194 { "reload-or-restart", MORE, 2, start_unit },
5195 { "reload-or-try-restart", MORE, 2, start_unit },
5196 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 5197 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5198 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
5199 { "isolate", EQUAL, 2, start_unit },
8a0867d6 5200 { "kill", MORE, 2, kill_unit },
ee5762e3
LP
5201 { "is-active", MORE, 2, check_unit },
5202 { "check", MORE, 2, check_unit },
5203 { "show", MORE, 1, show },
5204 { "status", MORE, 2, show },
ee5762e3
LP
5205 { "dump", EQUAL, 1, dump },
5206 { "dot", EQUAL, 1, dot },
5207 { "snapshot", LESS, 2, snapshot },
5208 { "delete", MORE, 2, delete_snapshot },
5209 { "daemon-reload", EQUAL, 1, daemon_reload },
5210 { "daemon-reexec", EQUAL, 1, daemon_reload },
ee5762e3
LP
5211 { "show-environment", EQUAL, 1, show_enviroment },
5212 { "set-environment", MORE, 2, set_environment },
5213 { "unset-environment", MORE, 2, set_environment },
5214 { "halt", EQUAL, 1, start_special },
5215 { "poweroff", EQUAL, 1, start_special },
5216 { "reboot", EQUAL, 1, start_special },
20b09ca7 5217 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
5218 { "suspend", EQUAL, 1, start_special },
5219 { "hibernate", EQUAL, 1, start_special },
ee5762e3
LP
5220 { "default", EQUAL, 1, start_special },
5221 { "rescue", EQUAL, 1, start_special },
5222 { "emergency", EQUAL, 1, start_special },
20b09ca7 5223 { "exit", EQUAL, 1, start_special },
fdf20a31 5224 { "reset-failed", MORE, 1, reset_failed },
ee5762e3
LP
5225 { "enable", MORE, 2, enable_unit },
5226 { "disable", MORE, 2, enable_unit },
729e3769
LP
5227 { "is-enabled", MORE, 2, unit_is_enabled },
5228 { "reenable", MORE, 2, enable_unit },
5229 { "preset", MORE, 2, enable_unit },
5230 { "mask", MORE, 2, enable_unit },
5231 { "unmask", MORE, 2, enable_unit },
957eb8ca
LP
5232 { "link", MORE, 2, enable_unit },
5233 { "switch-root", MORE, 2, switch_root },
7e4249b9
LP
5234 };
5235
e4b61340 5236 int left;
7e4249b9 5237 unsigned i;
7e4249b9 5238
e4b61340
LP
5239 assert(argc >= 0);
5240 assert(argv);
ee5762e3 5241 assert(error);
7e4249b9
LP
5242
5243 left = argc - optind;
5244
5245 if (left <= 0)
5246 /* Special rule: no arguments means "list-units" */
5247 i = 0;
5248 else {
0183528f
LP
5249 if (streq(argv[optind], "help")) {
5250 systemctl_help();
5251 return 0;
5252 }
5253
7e4249b9
LP
5254 for (i = 0; i < ELEMENTSOF(verbs); i++)
5255 if (streq(argv[optind], verbs[i].verb))
5256 break;
5257
5258 if (i >= ELEMENTSOF(verbs)) {
5259 log_error("Unknown operation %s", argv[optind]);
e4b61340 5260 return -EINVAL;
7e4249b9
LP
5261 }
5262 }
5263
5264 switch (verbs[i].argc_cmp) {
5265
5266 case EQUAL:
5267 if (left != verbs[i].argc) {
5268 log_error("Invalid number of arguments.");
e4b61340 5269 return -EINVAL;
7e4249b9
LP
5270 }
5271
5272 break;
5273
5274 case MORE:
5275 if (left < verbs[i].argc) {
5276 log_error("Too few arguments.");
e4b61340 5277 return -EINVAL;
7e4249b9
LP
5278 }
5279
5280 break;
5281
5282 case LESS:
5283 if (left > verbs[i].argc) {
5284 log_error("Too many arguments.");
e4b61340 5285 return -EINVAL;
7e4249b9
LP
5286 }
5287
5288 break;
5289
5290 default:
5291 assert_not_reached("Unknown comparison operator.");
5292 }
5293
ee5762e3
LP
5294 /* Require a bus connection for all operations but
5295 * enable/disable */
729e3769
LP
5296 if (!streq(verbs[i].verb, "enable") &&
5297 !streq(verbs[i].verb, "disable") &&
c971700e 5298 !streq(verbs[i].verb, "is-enabled") &&
d380a3bc 5299 !streq(verbs[i].verb, "list-unit-files") &&
729e3769
LP
5300 !streq(verbs[i].verb, "reenable") &&
5301 !streq(verbs[i].verb, "preset") &&
5302 !streq(verbs[i].verb, "mask") &&
5303 !streq(verbs[i].verb, "unmask") &&
5304 !streq(verbs[i].verb, "link")) {
82e23ddd
LP
5305
5306 if (running_in_chroot() > 0) {
5307 log_info("Running in chroot, ignoring request.");
5308 return 0;
5309 }
5310
3beddc78 5311 if (((!streq(verbs[i].verb, "reboot") &&
59ddae9f
LP
5312 !streq(verbs[i].verb, "halt") &&
5313 !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
f176b5c2
LP
5314 log_error("Failed to get D-Bus connection: %s",
5315 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
8185a509
LP
5316 return -EIO;
5317 }
5318
5319 } else {
5320
729e3769 5321 if (!bus && !avoid_bus()) {
f176b5c2
LP
5322 log_error("Failed to get D-Bus connection: %s",
5323 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
82e23ddd
LP
5324 return -EIO;
5325 }
ee5762e3
LP
5326 }
5327
729e3769 5328 return verbs[i].dispatch(bus, argv + optind);
e4b61340
LP
5329}
5330
52c00215 5331static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
04ebb595 5332 int fd;
f6144808 5333 struct msghdr msghdr;
04ebb595 5334 struct iovec iovec[2];
f6144808 5335 union sockaddr_union sockaddr;
04ebb595
LP
5336 struct sd_shutdown_command c;
5337
5338 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5339 if (fd < 0)
5340 return -errno;
f6144808
LP
5341
5342 zero(c);
04ebb595 5343 c.usec = t;
f6144808 5344 c.mode = mode;
52c00215 5345 c.dry_run = dry_run;
9be9828c
LP
5346 c.warn_wall = warn;
5347
f6144808
LP
5348 zero(sockaddr);
5349 sockaddr.sa.sa_family = AF_UNIX;
2b583ce6 5350 strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
f6144808 5351
f6144808
LP
5352 zero(msghdr);
5353 msghdr.msg_name = &sockaddr;
2b583ce6 5354 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
f6144808 5355
04ebb595
LP
5356 zero(iovec);
5357 iovec[0].iov_base = (char*) &c;
5358 iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5359
5360 if (isempty(message))
5361 msghdr.msg_iovlen = 1;
5362 else {
5363 iovec[1].iov_base = (char*) message;
5364 iovec[1].iov_len = strlen(message);
5365 msghdr.msg_iovlen = 2;
5366 }
5367 msghdr.msg_iov = iovec;
f6144808
LP
5368
5369 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5370 close_nointr_nofail(fd);
5371 return -errno;
5372 }
5373
5374 close_nointr_nofail(fd);
5375 return 0;
5376}
5377
e4b61340 5378static int reload_with_fallback(DBusConnection *bus) {
e4b61340
LP
5379
5380 if (bus) {
5381 /* First, try systemd via D-Bus. */
d76702a7 5382 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
5383 return 0;
5384 }
5385
5386 /* Nothing else worked, so let's try signals */
5387 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5388
5389 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5390 log_error("kill() failed: %m");
5391 return -errno;
5392 }
5393
5394 return 0;
5395}
5396
5397static int start_with_fallback(DBusConnection *bus) {
e4b61340
LP
5398
5399 if (bus) {
5400 /* First, try systemd via D-Bus. */
729e3769 5401 if (start_unit(bus, NULL) >= 0)
983d9c90 5402 goto done;
e4b61340
LP
5403 }
5404
ec7f7f20
LP
5405 /* Hmm, talking to systemd via D-Bus didn't work. Then
5406 * let's try to talk to Upstart via D-Bus. */
e364ad06 5407 if (talk_upstart() > 0)
ec7f7f20
LP
5408 goto done;
5409
e4b61340
LP
5410 /* Nothing else worked, so let's try
5411 * /dev/initctl */
fbc43921 5412 if (talk_initctl() > 0)
983d9c90 5413 goto done;
d55ae9e6
LP
5414
5415 log_error("Failed to talk to init daemon.");
5416 return -EIO;
983d9c90
LP
5417
5418done:
5419 warn_wall(arg_action);
5420 return 0;
e4b61340
LP
5421}
5422
4c80c73c 5423static void halt_now(enum action a) {
e606bb61
LP
5424
5425 /* Make sure C-A-D is handled by the kernel from this
5426 * point on... */
5427 reboot(RB_ENABLE_CAD);
5428
4c80c73c 5429 switch (a) {
e606bb61
LP
5430
5431 case ACTION_HALT:
5432 log_info("Halting.");
5433 reboot(RB_HALT_SYSTEM);
5434 break;
5435
5436 case ACTION_POWEROFF:
5437 log_info("Powering off.");
5438 reboot(RB_POWER_OFF);
5439 break;
5440
5441 case ACTION_REBOOT:
5442 log_info("Rebooting.");
5443 reboot(RB_AUTOBOOT);
5444 break;
5445
5446 default:
5447 assert_not_reached("Unknown halt action.");
5448 }
5449
5450 assert_not_reached("Uh? This shouldn't happen.");
5451}
5452
e4b61340
LP
5453static int halt_main(DBusConnection *bus) {
5454 int r;
5455
bc8c2f5c 5456 if (geteuid() != 0) {
7e59bfcb
LP
5457 /* Try logind if we are a normal user and no special
5458 * mode applies. Maybe PolicyKit allows us to shutdown
5459 * the machine. */
5460
5461 if (arg_when <= 0 &&
5462 !arg_dry &&
65491fd8 5463 !arg_force &&
7e59bfcb
LP
5464 (arg_action == ACTION_POWEROFF ||
5465 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
5466 r = reboot_with_logind(bus, arg_action);
5467 if (r >= 0)
5468 return r;
5469 }
5470
cc8a7a61 5471 log_error("Must be root.");
bc8c2f5c
LP
5472 return -EPERM;
5473 }
5474
f6144808 5475 if (arg_when > 0) {
9be9828c
LP
5476 char *m;
5477
5478 m = strv_join(arg_wall, " ");
5479 r = send_shutdownd(arg_when,
5480 arg_action == ACTION_HALT ? 'H' :
5481 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 5482 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 5483 'r',
52c00215 5484 arg_dry,
9be9828c
LP
5485 !arg_no_wall,
5486 m);
5487 free(m);
5488
5489 if (r < 0)
f6144808 5490 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 5491 else {
7e59bfcb
LP
5492 char date[FORMAT_TIMESTAMP_MAX];
5493
08e4b1c5
LP
5494 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5495 format_timestamp(date, sizeof(date), arg_when));
f6144808 5496 return 0;
08e4b1c5 5497 }
f6144808
LP
5498 }
5499
65491fd8 5500 if (!arg_dry && !arg_force)
e4b61340
LP
5501 return start_with_fallback(bus);
5502
d90e1a30
LP
5503 if (!arg_no_wtmp) {
5504 if (sd_booted() > 0)
5505 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
5506 else {
5507 r = utmp_put_shutdown();
5508 if (r < 0)
5509 log_warning("Failed to write utmp record: %s", strerror(-r));
5510 }
d90e1a30 5511 }
e4b61340
LP
5512
5513 if (!arg_no_sync)
5514 sync();
5515
5516 if (arg_dry)
5517 return 0;
5518
e606bb61 5519 halt_now(arg_action);
e4b61340
LP
5520 /* We should never reach this. */
5521 return -ENOSYS;
5522}
5523
5524static int runlevel_main(void) {
5525 int r, runlevel, previous;
5526
729e3769
LP
5527 r = utmp_get_runlevel(&runlevel, &previous);
5528 if (r < 0) {
5529 puts("unknown");
e4b61340
LP
5530 return r;
5531 }
5532
5533 printf("%c %c\n",
5534 previous <= 0 ? 'N' : previous,
5535 runlevel <= 0 ? 'N' : runlevel);
5536
5537 return 0;
5538}
5539
5540int main(int argc, char*argv[]) {
22f4096c 5541 int r, retval = EXIT_FAILURE;
e4b61340
LP
5542 DBusConnection *bus = NULL;
5543 DBusError error;
5544
5545 dbus_error_init(&error);
5546
5547 log_parse_environment();
2396fb04 5548 log_open();
e4b61340 5549
04ebb595
LP
5550 r = parse_argv(argc, argv);
5551 if (r < 0)
e4b61340
LP
5552 goto finish;
5553 else if (r == 0) {
22f4096c 5554 retval = EXIT_SUCCESS;
7e4249b9
LP
5555 goto finish;
5556 }
5557
e4b61340
LP
5558 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5559 * let's shortcut this */
5560 if (arg_action == ACTION_RUNLEVEL) {
22f4096c
LP
5561 r = runlevel_main();
5562 retval = r < 0 ? EXIT_FAILURE : r;
e4b61340
LP
5563 goto finish;
5564 }
5565
82e23ddd
LP
5566 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5567 log_info("Running in chroot, ignoring request.");
5568 retval = 0;
5569 goto finish;
5570 }
5571
729e3769
LP
5572 if (!avoid_bus()) {
5573 if (arg_transport == TRANSPORT_NORMAL)
5574 bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5575 else if (arg_transport == TRANSPORT_POLKIT) {
5576 bus_connect_system_polkit(&bus, &error);
5577 private_bus = false;
5578 } else if (arg_transport == TRANSPORT_SSH) {
5579 bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5580 private_bus = false;
5581 } else
5582 assert_not_reached("Uh, invalid transport...");
5583 }
e4b61340
LP
5584
5585 switch (arg_action) {
5586
22f4096c
LP
5587 case ACTION_SYSTEMCTL:
5588 r = systemctl_main(bus, argc, argv, &error);
e4b61340 5589 break;
e4b61340
LP
5590
5591 case ACTION_HALT:
5592 case ACTION_POWEROFF:
5593 case ACTION_REBOOT:
5622dde3 5594 case ACTION_KEXEC:
22f4096c 5595 r = halt_main(bus);
e4b61340
LP
5596 break;
5597
e4b61340
LP
5598 case ACTION_RUNLEVEL2:
5599 case ACTION_RUNLEVEL3:
5600 case ACTION_RUNLEVEL4:
5601 case ACTION_RUNLEVEL5:
5602 case ACTION_RESCUE:
514f4ef5 5603 case ACTION_EMERGENCY:
eb22ac37 5604 case ACTION_DEFAULT:
22f4096c 5605 r = start_with_fallback(bus);
e4b61340 5606 break;
7e4249b9 5607
e4b61340
LP
5608 case ACTION_RELOAD:
5609 case ACTION_REEXEC:
22f4096c 5610 r = reload_with_fallback(bus);
e4b61340
LP
5611 break;
5612
f6144808 5613 case ACTION_CANCEL_SHUTDOWN:
52c00215 5614 r = send_shutdownd(0, 0, false, false, NULL);
f6144808
LP
5615 break;
5616
eb22ac37
LP
5617 case ACTION_INVALID:
5618 case ACTION_RUNLEVEL:
e4b61340
LP
5619 default:
5620 assert_not_reached("Unknown action");
5621 }
7e4249b9 5622
22f4096c
LP
5623 retval = r < 0 ? EXIT_FAILURE : r;
5624
7e4249b9 5625finish:
b574246b 5626 if (bus) {
5d452f9c 5627 dbus_connection_flush(bus);
b574246b 5628 dbus_connection_close(bus);
7e4249b9 5629 dbus_connection_unref(bus);
b574246b 5630 }
7e4249b9 5631
e4b61340
LP
5632 dbus_error_free(&error);
5633
7e4249b9
LP
5634 dbus_shutdown();
5635
ea4a240d
LP
5636 strv_free(arg_property);
5637
1888c907 5638 pager_close();
6bb92a16
LP
5639 ask_password_agent_close();
5640 polkit_agent_close();
1888c907 5641
7e4249b9
LP
5642 return retval;
5643}