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