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