]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl.c
sleep: implement suspend/hibernate as first class targets
[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
1753 default:
1754 return -EINVAL;
1755 }
1756
1757 m = dbus_message_new_method_call(
1758 "org.freedesktop.login1",
1759 "/org/freedesktop/login1",
1760 "org.freedesktop.login1.Manager",
1761 method);
1762 if (!m) {
1763 log_error("Could not allocate message.");
1764 r = -ENOMEM;
1765 goto finish;
1766 }
1767
1768 if (!dbus_message_append_args(m,
1769 DBUS_TYPE_BOOLEAN, &interactive,
1770 DBUS_TYPE_INVALID)) {
1771 log_error("Could not append arguments to message.");
1772 r = -ENOMEM;
1773 goto finish;
1774 }
1775
1776 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
1777 if (!reply) {
1778 if (error_is_no_service(&error)) {
1779 log_debug("Failed to issue method call: %s", bus_error_message(&error));
1780 r = -ENOENT;
1781 goto finish;
1782 }
1783
1784 if (dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
1785 log_debug("Failed to issue method call: %s", bus_error_message(&error));
1786 r = -EACCES;
1787 goto finish;
1788 }
1789
1790 log_info("Failed to issue method call: %s", bus_error_message(&error));
1791 r = -EIO;
1792 goto finish;
1793 }
1794
1795 r = 0;
1796
1797finish:
1798 if (m)
1799 dbus_message_unref(m);
1800
1801 if (reply)
1802 dbus_message_unref(reply);
1803
1804 dbus_error_free(&error);
1805
1806 return r;
1807#else
1808 return -ENOSYS;
1809#endif
1810}
1811
729e3769 1812static int start_special(DBusConnection *bus, char **args) {
4c80c73c 1813 enum action a;
983d9c90
LP
1814 int r;
1815
514f4ef5
LP
1816 assert(args);
1817
4c80c73c
KS
1818 a = verb_to_action(args[0]);
1819
c32b90de
LP
1820 if (arg_force >= 2 && geteuid() != 0) {
1821 log_error("Must be root.");
1822 return -EPERM;
1823 }
1824
7e59bfcb
LP
1825 if (arg_force >= 2 &&
1826 (a == ACTION_HALT ||
1827 a == ACTION_POWEROFF ||
1828 a == ACTION_REBOOT))
1829 halt_now(a);
e606bb61 1830
7e59bfcb 1831 if (arg_force >= 1 &&
4c80c73c
KS
1832 (a == ACTION_HALT ||
1833 a == ACTION_POWEROFF ||
1834 a == ACTION_REBOOT ||
1835 a == ACTION_KEXEC ||
1836 a == ACTION_EXIT))
729e3769 1837 return daemon_reload(bus, args);
20b09ca7 1838
7e59bfcb
LP
1839 /* first try logind, to allow authentication with polkit */
1840 if (geteuid() != 0 &&
1841 (a == ACTION_POWEROFF ||
1842 a == ACTION_REBOOT)) {
1843 r = reboot_with_logind(bus, a);
1844 if (r >= 0)
1845 return r;
4c80c73c 1846 }
983d9c90 1847
4c80c73c 1848 r = start_unit(bus, args);
983d9c90 1849 if (r >= 0)
4c80c73c 1850 warn_wall(a);
514f4ef5 1851
983d9c90 1852 return r;
514f4ef5
LP
1853}
1854
729e3769 1855static int check_unit(DBusConnection *bus, char **args) {
0183528f
LP
1856 DBusMessage *m = NULL, *reply = NULL;
1857 const char
1858 *interface = "org.freedesktop.systemd1.Unit",
1859 *property = "ActiveState";
22f4096c 1860 int r = 3; /* According to LSB: "program is not running" */
0183528f 1861 DBusError error;
729e3769 1862 char **name;
0183528f
LP
1863
1864 assert(bus);
1865 assert(args);
1866
1867 dbus_error_init(&error);
1868
729e3769 1869 STRV_FOREACH(name, args+1) {
0183528f
LP
1870 const char *path = NULL;
1871 const char *state;
1872 DBusMessageIter iter, sub;
1873
1874 if (!(m = dbus_message_new_method_call(
1875 "org.freedesktop.systemd1",
1876 "/org/freedesktop/systemd1",
1877 "org.freedesktop.systemd1.Manager",
1878 "GetUnit"))) {
1879 log_error("Could not allocate message.");
1880 r = -ENOMEM;
1881 goto finish;
1882 }
1883
1884 if (!dbus_message_append_args(m,
729e3769 1885 DBUS_TYPE_STRING, name,
0183528f
LP
1886 DBUS_TYPE_INVALID)) {
1887 log_error("Could not append arguments to message.");
1888 r = -ENOMEM;
1889 goto finish;
1890 }
1891
1892 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
1893
1894 /* Hmm, cannot figure out anything about this unit... */
1895 if (!arg_quiet)
1896 puts("unknown");
1897
ed2d7a44 1898 dbus_error_free(&error);
8a0867d6 1899 dbus_message_unref(m);
78e39b43 1900 m = NULL;
0183528f
LP
1901 continue;
1902 }
1903
1904 if (!dbus_message_get_args(reply, &error,
1905 DBUS_TYPE_OBJECT_PATH, &path,
1906 DBUS_TYPE_INVALID)) {
4cf5d675 1907 log_error("Failed to parse reply: %s", bus_error_message(&error));
0183528f
LP
1908 r = -EIO;
1909 goto finish;
1910 }
1911
1912 dbus_message_unref(m);
1913 if (!(m = dbus_message_new_method_call(
1914 "org.freedesktop.systemd1",
1915 path,
1916 "org.freedesktop.DBus.Properties",
1917 "Get"))) {
1918 log_error("Could not allocate message.");
1919 r = -ENOMEM;
1920 goto finish;
1921 }
1922
1923 if (!dbus_message_append_args(m,
1924 DBUS_TYPE_STRING, &interface,
1925 DBUS_TYPE_STRING, &property,
1926 DBUS_TYPE_INVALID)) {
1927 log_error("Could not append arguments to message.");
1928 r = -ENOMEM;
1929 goto finish;
1930 }
1931
1932 dbus_message_unref(reply);
1933 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 1934 log_error("Failed to issue method call: %s", bus_error_message(&error));
0183528f
LP
1935 r = -EIO;
1936 goto finish;
1937 }
1938
1939 if (!dbus_message_iter_init(reply, &iter) ||
1940 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
1941 log_error("Failed to parse reply.");
1942 r = -EIO;
1943 goto finish;
1944 }
1945
1946 dbus_message_iter_recurse(&iter, &sub);
1947
1948 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
1949 log_error("Failed to parse reply.");
1950 r = -EIO;
1951 goto finish;
1952 }
1953
1954 dbus_message_iter_get_basic(&sub, &state);
1955
1956 if (!arg_quiet)
1957 puts(state);
1958
f1e36d67 1959 if (streq(state, "active") || streq(state, "reloading"))
0183528f
LP
1960 r = 0;
1961
1962 dbus_message_unref(m);
1963 dbus_message_unref(reply);
1964 m = reply = NULL;
1965 }
1966
1967finish:
1968 if (m)
1969 dbus_message_unref(m);
1970
1971 if (reply)
1972 dbus_message_unref(reply);
1973
1974 dbus_error_free(&error);
1975
1976 return r;
48220598
LP
1977}
1978
729e3769 1979static int kill_unit(DBusConnection *bus, char **args) {
f8440af5 1980 DBusMessage *m = NULL;
8a0867d6
LP
1981 int r = 0;
1982 DBusError error;
729e3769 1983 char **name;
8a0867d6
LP
1984
1985 assert(bus);
1986 assert(args);
1987
1988 dbus_error_init(&error);
1989
1990 if (!arg_kill_who)
1991 arg_kill_who = "all";
1992
1993 if (!arg_kill_mode)
1994 arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process";
1995
729e3769 1996 STRV_FOREACH(name, args+1) {
f8440af5 1997 DBusMessage *reply;
8a0867d6
LP
1998
1999 if (!(m = dbus_message_new_method_call(
2000 "org.freedesktop.systemd1",
2001 "/org/freedesktop/systemd1",
2002 "org.freedesktop.systemd1.Manager",
2003 "KillUnit"))) {
2004 log_error("Could not allocate message.");
2005 r = -ENOMEM;
2006 goto finish;
2007 }
2008
2009 if (!dbus_message_append_args(m,
729e3769 2010 DBUS_TYPE_STRING, name,
8a0867d6
LP
2011 DBUS_TYPE_STRING, &arg_kill_who,
2012 DBUS_TYPE_STRING, &arg_kill_mode,
2013 DBUS_TYPE_INT32, &arg_signal,
2014 DBUS_TYPE_INVALID)) {
2015 log_error("Could not append arguments to message.");
2016 r = -ENOMEM;
2017 goto finish;
2018 }
2019
2020 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
2021 log_error("Failed to issue method call: %s", bus_error_message(&error));
2022 dbus_error_free(&error);
2023 r = -EIO;
2024 }
2025
2026 dbus_message_unref(m);
2027
2028 if (reply)
2029 dbus_message_unref(reply);
2030 m = reply = NULL;
2031 }
2032
2033finish:
2034 if (m)
2035 dbus_message_unref(m);
2036
8a0867d6
LP
2037 dbus_error_free(&error);
2038
2039 return r;
2040}
2041
582a507f 2042typedef struct ExecStatusInfo {
0129173a
LP
2043 char *name;
2044
582a507f
LP
2045 char *path;
2046 char **argv;
2047
b708e7ce
LP
2048 bool ignore;
2049
582a507f
LP
2050 usec_t start_timestamp;
2051 usec_t exit_timestamp;
2052 pid_t pid;
2053 int code;
2054 int status;
2055
2056 LIST_FIELDS(struct ExecStatusInfo, exec);
2057} ExecStatusInfo;
2058
2059static void exec_status_info_free(ExecStatusInfo *i) {
2060 assert(i);
2061
0129173a 2062 free(i->name);
582a507f
LP
2063 free(i->path);
2064 strv_free(i->argv);
2065 free(i);
2066}
2067
2068static int exec_status_info_deserialize(DBusMessageIter *sub, ExecStatusInfo *i) {
b21a0ef8 2069 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
582a507f
LP
2070 DBusMessageIter sub2, sub3;
2071 const char*path;
2072 unsigned n;
2073 uint32_t pid;
2074 int32_t code, status;
b708e7ce 2075 dbus_bool_t ignore;
582a507f
LP
2076
2077 assert(i);
2078 assert(i);
2079
2080 if (dbus_message_iter_get_arg_type(sub) != DBUS_TYPE_STRUCT)
2081 return -EIO;
2082
2083 dbus_message_iter_recurse(sub, &sub2);
2084
2085 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0)
2086 return -EIO;
2087
2088 if (!(i->path = strdup(path)))
2089 return -ENOMEM;
2090
2091 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_ARRAY ||
2092 dbus_message_iter_get_element_type(&sub2) != DBUS_TYPE_STRING)
2093 return -EIO;
2094
2095 n = 0;
2096 dbus_message_iter_recurse(&sub2, &sub3);
2097 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2098 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2099 dbus_message_iter_next(&sub3);
2100 n++;
2101 }
2102
2103
2104 if (!(i->argv = new0(char*, n+1)))
2105 return -ENOMEM;
2106
2107 n = 0;
2108 dbus_message_iter_recurse(&sub2, &sub3);
2109 while (dbus_message_iter_get_arg_type(&sub3) != DBUS_TYPE_INVALID) {
2110 const char *s;
2111
2112 assert(dbus_message_iter_get_arg_type(&sub3) == DBUS_TYPE_STRING);
2113 dbus_message_iter_get_basic(&sub3, &s);
2114 dbus_message_iter_next(&sub3);
2115
2116 if (!(i->argv[n++] = strdup(s)))
2117 return -ENOMEM;
2118 }
2119
2120 if (!dbus_message_iter_next(&sub2) ||
b708e7ce 2121 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, true) < 0 ||
582a507f 2122 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp, true) < 0 ||
b21a0ef8 2123 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &start_timestamp_monotonic, true) < 0 ||
582a507f 2124 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp, true) < 0 ||
b21a0ef8 2125 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &exit_timestamp_monotonic, true) < 0 ||
582a507f
LP
2126 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT32, &pid, true) < 0 ||
2127 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &code, true) < 0 ||
2128 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_INT32, &status, false) < 0)
2129 return -EIO;
2130
b708e7ce 2131 i->ignore = ignore;
582a507f
LP
2132 i->start_timestamp = (usec_t) start_timestamp;
2133 i->exit_timestamp = (usec_t) exit_timestamp;
2134 i->pid = (pid_t) pid;
2135 i->code = code;
2136 i->status = status;
2137
2138 return 0;
2139}
2140
61cbdc4b
LP
2141typedef struct UnitStatusInfo {
2142 const char *id;
2143 const char *load_state;
2144 const char *active_state;
2145 const char *sub_state;
a4375746 2146 const char *unit_file_state;
61cbdc4b
LP
2147
2148 const char *description;
4a9e2fff 2149 const char *following;
61cbdc4b 2150
c31b4423 2151 const char *path;
61cbdc4b
LP
2152 const char *default_control_group;
2153
9f39404c 2154 const char *load_error;
f42806df 2155 const char *result;
9f39404c 2156
584be568 2157 usec_t inactive_exit_timestamp;
df50185b 2158 usec_t inactive_exit_timestamp_monotonic;
584be568
LP
2159 usec_t active_enter_timestamp;
2160 usec_t active_exit_timestamp;
2161 usec_t inactive_enter_timestamp;
2162
45fb0699
LP
2163 bool need_daemon_reload;
2164
61cbdc4b
LP
2165 /* Service */
2166 pid_t main_pid;
2167 pid_t control_pid;
2168 const char *status_text;
d06dacd0 2169 bool running:1;
07459bb6 2170#ifdef HAVE_SYSV_COMPAT
d06dacd0 2171 bool is_sysv:1;
07459bb6 2172#endif
61cbdc4b
LP
2173
2174 usec_t start_timestamp;
2175 usec_t exit_timestamp;
2176
2177 int exit_code, exit_status;
2178
90bbc946
LP
2179 usec_t condition_timestamp;
2180 bool condition_result;
2181
61cbdc4b
LP
2182 /* Socket */
2183 unsigned n_accepted;
2184 unsigned n_connections;
b8131a87 2185 bool accept;
61cbdc4b
LP
2186
2187 /* Device */
2188 const char *sysfs_path;
2189
2190 /* Mount, Automount */
2191 const char *where;
2192
2193 /* Swap */
2194 const char *what;
582a507f
LP
2195
2196 LIST_HEAD(ExecStatusInfo, exec);
61cbdc4b
LP
2197} UnitStatusInfo;
2198
2199static void print_status_info(UnitStatusInfo *i) {
582a507f 2200 ExecStatusInfo *p;
2ee68f72 2201 const char *on, *off, *ss;
584be568
LP
2202 usec_t timestamp;
2203 char since1[FORMAT_TIMESTAMP_PRETTY_MAX], *s1;
2204 char since2[FORMAT_TIMESTAMP_MAX], *s2;
582a507f 2205
61cbdc4b
LP
2206 assert(i);
2207
2208 /* This shows pretty information about a unit. See
2209 * print_property() for a low-level property printer */
2210
2211 printf("%s", strna(i->id));
2212
2213 if (i->description && !streq_ptr(i->id, i->description))
2214 printf(" - %s", i->description);
2215
2216 printf("\n");
2217
4a9e2fff
LP
2218 if (i->following)
2219 printf("\t Follow: unit currently follows state of %s\n", i->following);
2220
f7b9e331 2221 if (streq_ptr(i->load_state, "error")) {
c1072ea0
LP
2222 on = ansi_highlight_red(true);
2223 off = ansi_highlight_red(false);
c31b4423
LP
2224 } else
2225 on = off = "";
2226
9f39404c
LP
2227 if (i->load_error)
2228 printf("\t Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error);
a4375746
LP
2229 else if (i->path && i->unit_file_state)
2230 printf("\t Loaded: %s%s%s (%s; %s)\n", on, strna(i->load_state), off, i->path, i->unit_file_state);
9f39404c 2231 else if (i->path)
c31b4423 2232 printf("\t Loaded: %s%s%s (%s)\n", on, strna(i->load_state), off, i->path);
61cbdc4b 2233 else
c31b4423 2234 printf("\t Loaded: %s%s%s\n", on, strna(i->load_state), off);
61cbdc4b 2235
2ee68f72
LP
2236 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
2237
fdf20a31 2238 if (streq_ptr(i->active_state, "failed")) {
c1072ea0
LP
2239 on = ansi_highlight_red(true);
2240 off = ansi_highlight_red(false);
2ee68f72
LP
2241 } else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
2242 on = ansi_highlight_green(true);
2243 off = ansi_highlight_green(false);
2244 } else
2245 on = off = "";
2246
2247 if (ss)
584be568 2248 printf("\t Active: %s%s (%s)%s",
2ee68f72
LP
2249 on,
2250 strna(i->active_state),
2251 ss,
2252 off);
2253 else
584be568 2254 printf("\t Active: %s%s%s",
2ee68f72
LP
2255 on,
2256 strna(i->active_state),
2257 off);
61cbdc4b 2258
f42806df
LP
2259 if (!isempty(i->result) && !streq(i->result, "success"))
2260 printf(" (Result: %s)", i->result);
2261
584be568
LP
2262 timestamp = (streq_ptr(i->active_state, "active") ||
2263 streq_ptr(i->active_state, "reloading")) ? i->active_enter_timestamp :
2264 (streq_ptr(i->active_state, "inactive") ||
fdf20a31 2265 streq_ptr(i->active_state, "failed")) ? i->inactive_enter_timestamp :
584be568
LP
2266 streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
2267 i->active_exit_timestamp;
2268
2269 s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
2270 s2 = format_timestamp(since2, sizeof(since2), timestamp);
2271
2272 if (s1)
538da63d 2273 printf(" since %s; %s\n", s2, s1);
584be568 2274 else if (s2)
538da63d 2275 printf(" since %s\n", s2);
584be568
LP
2276 else
2277 printf("\n");
2278
90bbc946
LP
2279 if (!i->condition_result && i->condition_timestamp > 0) {
2280 s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
2281 s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
2282
2283 if (s1)
2284 printf("\t start condition failed at %s; %s\n", s2, s1);
2285 else if (s2)
2286 printf("\t start condition failed at %s\n", s2);
2287 }
2288
61cbdc4b
LP
2289 if (i->sysfs_path)
2290 printf("\t Device: %s\n", i->sysfs_path);
9feeba4b 2291 if (i->where)
61cbdc4b 2292 printf("\t Where: %s\n", i->where);
9feeba4b 2293 if (i->what)
61cbdc4b
LP
2294 printf("\t What: %s\n", i->what);
2295
b8131a87 2296 if (i->accept)
61cbdc4b
LP
2297 printf("\tAccepted: %u; Connected: %u\n", i->n_accepted, i->n_connections);
2298
582a507f
LP
2299 LIST_FOREACH(exec, p, i->exec) {
2300 char *t;
9a57c629 2301 bool good;
582a507f
LP
2302
2303 /* Only show exited processes here */
2304 if (p->code == 0)
2305 continue;
2306
2307 t = strv_join(p->argv, " ");
9a57c629 2308 printf("\t Process: %u %s=%s ", p->pid, p->name, strna(t));
582a507f
LP
2309 free(t);
2310
9a57c629
LP
2311#ifdef HAVE_SYSV_COMPAT
2312 if (i->is_sysv)
2313 good = is_clean_exit_lsb(p->code, p->status);
2314 else
2315#endif
2316 good = is_clean_exit(p->code, p->status);
2317
2318 if (!good) {
c1072ea0
LP
2319 on = ansi_highlight_red(true);
2320 off = ansi_highlight_red(false);
9a57c629
LP
2321 } else
2322 on = off = "";
2323
2324 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
2325
d06dacd0
LP
2326 if (p->code == CLD_EXITED) {
2327 const char *c;
2328
582a507f 2329 printf("status=%i", p->status);
d06dacd0 2330
07459bb6 2331#ifdef HAVE_SYSV_COMPAT
d06dacd0 2332 if ((c = exit_status_to_string(p->status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
07459bb6
FF
2333#else
2334 if ((c = exit_status_to_string(p->status, EXIT_STATUS_SYSTEMD)))
2335#endif
d06dacd0
LP
2336 printf("/%s", c);
2337
2338 } else
582a507f 2339 printf("signal=%s", signal_to_string(p->status));
9a57c629
LP
2340
2341 printf(")%s\n", off);
2342
582a507f
LP
2343 if (i->main_pid == p->pid &&
2344 i->start_timestamp == p->start_timestamp &&
2345 i->exit_timestamp == p->start_timestamp)
2346 /* Let's not show this twice */
2347 i->main_pid = 0;
2348
2349 if (p->pid == i->control_pid)
2350 i->control_pid = 0;
2351 }
2352
61cbdc4b
LP
2353 if (i->main_pid > 0 || i->control_pid > 0) {
2354 printf("\t");
2355
2356 if (i->main_pid > 0) {
f3d41013 2357 printf("Main PID: %u", (unsigned) i->main_pid);
61cbdc4b
LP
2358
2359 if (i->running) {
2360 char *t = NULL;
87d2c1ff 2361 get_process_comm(i->main_pid, &t);
61cbdc4b
LP
2362 if (t) {
2363 printf(" (%s)", t);
2364 free(t);
2365 }
6d4fc029 2366 } else if (i->exit_code > 0) {
61cbdc4b
LP
2367 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
2368
d06dacd0
LP
2369 if (i->exit_code == CLD_EXITED) {
2370 const char *c;
2371
61cbdc4b 2372 printf("status=%i", i->exit_status);
d06dacd0 2373
07459bb6 2374#ifdef HAVE_SYSV_COMPAT
d06dacd0 2375 if ((c = exit_status_to_string(i->exit_status, i->is_sysv ? EXIT_STATUS_LSB : EXIT_STATUS_SYSTEMD)))
07459bb6
FF
2376#else
2377 if ((c = exit_status_to_string(i->exit_status, EXIT_STATUS_SYSTEMD)))
2378#endif
d06dacd0
LP
2379 printf("/%s", c);
2380
2381 } else
582a507f 2382 printf("signal=%s", signal_to_string(i->exit_status));
6d4fc029
LP
2383 printf(")");
2384 }
61cbdc4b
LP
2385 }
2386
2387 if (i->main_pid > 0 && i->control_pid > 0)
2388 printf(";");
2389
2390 if (i->control_pid > 0) {
2391 char *t = NULL;
2392
2393 printf(" Control: %u", (unsigned) i->control_pid);
2394
87d2c1ff 2395 get_process_comm(i->control_pid, &t);
61cbdc4b
LP
2396 if (t) {
2397 printf(" (%s)", t);
2398 free(t);
2399 }
2400 }
2401
2402 printf("\n");
2403 }
2404
17bb7382
LP
2405 if (i->status_text)
2406 printf("\t Status: \"%s\"\n", i->status_text);
2407
c59760ee 2408 if (i->default_control_group) {
ab35fb1b
LP
2409 unsigned c;
2410
61cbdc4b 2411 printf("\t CGroup: %s\n", i->default_control_group);
ab35fb1b 2412
a8f11321 2413 if (arg_transport != TRANSPORT_SSH) {
b69d29ce
LP
2414 unsigned k = 0;
2415 pid_t extra[2];
2416
2417 c = columns();
2418 if (c > 18)
a8f11321
LP
2419 c -= 18;
2420 else
2421 c = 0;
ab35fb1b 2422
b69d29ce
LP
2423 if (i->main_pid > 0)
2424 extra[k++] = i->main_pid;
2425
2426 if (i->control_pid > 0)
2427 extra[k++] = i->control_pid;
2428
2429 show_cgroup_and_extra_by_spec(i->default_control_group, "\t\t ", c, false, arg_all, extra, k);
a8f11321 2430 }
c59760ee 2431 }
45fb0699 2432
6f003b43
LP
2433 if (i->id && arg_transport != TRANSPORT_SSH) {
2434 printf("\n");
34a35ece 2435 show_journal_by_unit(i->id, arg_output, 0, i->inactive_exit_timestamp_monotonic, arg_lines, arg_all, arg_follow);
6f003b43 2436 }
86aa7ba4 2437
45fb0699 2438 if (i->need_daemon_reload)
2cc59dbf 2439 printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %s daemon-reload' recommended.\n",
c1072ea0
LP
2440 ansi_highlight_red(true),
2441 ansi_highlight_red(false),
729e3769 2442 arg_scope == UNIT_FILE_SYSTEM ? "--system" : "--user");
61cbdc4b
LP
2443}
2444
2445static int status_property(const char *name, DBusMessageIter *iter, UnitStatusInfo *i) {
2446
a4c279f8
LP
2447 assert(name);
2448 assert(iter);
2449 assert(i);
2450
61cbdc4b
LP
2451 switch (dbus_message_iter_get_arg_type(iter)) {
2452
2453 case DBUS_TYPE_STRING: {
2454 const char *s;
2455
2456 dbus_message_iter_get_basic(iter, &s);
2457
a4c279f8 2458 if (!isempty(s)) {
61cbdc4b
LP
2459 if (streq(name, "Id"))
2460 i->id = s;
2461 else if (streq(name, "LoadState"))
2462 i->load_state = s;
2463 else if (streq(name, "ActiveState"))
2464 i->active_state = s;
2465 else if (streq(name, "SubState"))
2466 i->sub_state = s;
2467 else if (streq(name, "Description"))
2468 i->description = s;
2469 else if (streq(name, "FragmentPath"))
c31b4423 2470 i->path = s;
07459bb6 2471#ifdef HAVE_SYSV_COMPAT
d06dacd0
LP
2472 else if (streq(name, "SysVPath")) {
2473 i->is_sysv = true;
c31b4423 2474 i->path = s;
07459bb6
FF
2475 }
2476#endif
2477 else if (streq(name, "DefaultControlGroup"))
61cbdc4b
LP
2478 i->default_control_group = s;
2479 else if (streq(name, "StatusText"))
2480 i->status_text = s;
2481 else if (streq(name, "SysFSPath"))
2482 i->sysfs_path = s;
2483 else if (streq(name, "Where"))
2484 i->where = s;
2485 else if (streq(name, "What"))
2486 i->what = s;
4a9e2fff
LP
2487 else if (streq(name, "Following"))
2488 i->following = s;
a4375746
LP
2489 else if (streq(name, "UnitFileState"))
2490 i->unit_file_state = s;
f42806df
LP
2491 else if (streq(name, "Result"))
2492 i->result = s;
61cbdc4b
LP
2493 }
2494
2495 break;
2496 }
2497
b8131a87
LP
2498 case DBUS_TYPE_BOOLEAN: {
2499 dbus_bool_t b;
2500
2501 dbus_message_iter_get_basic(iter, &b);
2502
2503 if (streq(name, "Accept"))
2504 i->accept = b;
45fb0699
LP
2505 else if (streq(name, "NeedDaemonReload"))
2506 i->need_daemon_reload = b;
90bbc946
LP
2507 else if (streq(name, "ConditionResult"))
2508 i->condition_result = b;
b8131a87
LP
2509
2510 break;
2511 }
2512
61cbdc4b
LP
2513 case DBUS_TYPE_UINT32: {
2514 uint32_t u;
2515
2516 dbus_message_iter_get_basic(iter, &u);
2517
2518 if (streq(name, "MainPID")) {
2519 if (u > 0) {
2520 i->main_pid = (pid_t) u;
2521 i->running = true;
2522 }
2523 } else if (streq(name, "ControlPID"))
2524 i->control_pid = (pid_t) u;
2525 else if (streq(name, "ExecMainPID")) {
2526 if (u > 0)
2527 i->main_pid = (pid_t) u;
2528 } else if (streq(name, "NAccepted"))
2529 i->n_accepted = u;
2530 else if (streq(name, "NConnections"))
2531 i->n_connections = u;
2532
2533 break;
2534 }
2535
2536 case DBUS_TYPE_INT32: {
2537 int32_t j;
2538
2539 dbus_message_iter_get_basic(iter, &j);
2540
2541 if (streq(name, "ExecMainCode"))
2542 i->exit_code = (int) j;
2543 else if (streq(name, "ExecMainStatus"))
2544 i->exit_status = (int) j;
2545
2546 break;
2547 }
2548
2549 case DBUS_TYPE_UINT64: {
2550 uint64_t u;
2551
2552 dbus_message_iter_get_basic(iter, &u);
2553
2554 if (streq(name, "ExecMainStartTimestamp"))
2555 i->start_timestamp = (usec_t) u;
2556 else if (streq(name, "ExecMainExitTimestamp"))
2557 i->exit_timestamp = (usec_t) u;
584be568
LP
2558 else if (streq(name, "ActiveEnterTimestamp"))
2559 i->active_enter_timestamp = (usec_t) u;
2560 else if (streq(name, "InactiveEnterTimestamp"))
2561 i->inactive_enter_timestamp = (usec_t) u;
2562 else if (streq(name, "InactiveExitTimestamp"))
2563 i->inactive_exit_timestamp = (usec_t) u;
df50185b
LP
2564 else if (streq(name, "InactiveExitTimestampMonotonic"))
2565 i->inactive_exit_timestamp_monotonic = (usec_t) u;
584be568
LP
2566 else if (streq(name, "ActiveExitTimestamp"))
2567 i->active_exit_timestamp = (usec_t) u;
90bbc946
LP
2568 else if (streq(name, "ConditionTimestamp"))
2569 i->condition_timestamp = (usec_t) u;
61cbdc4b
LP
2570
2571 break;
2572 }
582a507f
LP
2573
2574 case DBUS_TYPE_ARRAY: {
2575
2576 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT &&
2577 startswith(name, "Exec")) {
2578 DBusMessageIter sub;
2579
2580 dbus_message_iter_recurse(iter, &sub);
2581 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2582 ExecStatusInfo *info;
2583 int r;
2584
2585 if (!(info = new0(ExecStatusInfo, 1)))
2586 return -ENOMEM;
2587
0129173a
LP
2588 if (!(info->name = strdup(name))) {
2589 free(info);
2590 return -ENOMEM;
2591 }
2592
582a507f
LP
2593 if ((r = exec_status_info_deserialize(&sub, info)) < 0) {
2594 free(info);
2595 return r;
2596 }
2597
2598 LIST_PREPEND(ExecStatusInfo, exec, i->exec, info);
2599
2600 dbus_message_iter_next(&sub);
2601 }
2602 }
2603
2604 break;
2605 }
9f39404c
LP
2606
2607 case DBUS_TYPE_STRUCT: {
2608
2609 if (streq(name, "LoadError")) {
2610 DBusMessageIter sub;
2611 const char *n, *message;
2612 int r;
2613
2614 dbus_message_iter_recurse(iter, &sub);
2615
2616 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &n, true);
2617 if (r < 0)
2618 return r;
2619
2620 r = bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &message, false);
2621 if (r < 0)
2622 return r;
2623
2624 if (!isempty(message))
2625 i->load_error = message;
2626 }
2627
2628 break;
2629 }
61cbdc4b
LP
2630 }
2631
2632 return 0;
2633}
2634
48220598
LP
2635static int print_property(const char *name, DBusMessageIter *iter) {
2636 assert(name);
2637 assert(iter);
2638
61cbdc4b
LP
2639 /* This is a low-level property printer, see
2640 * print_status_info() for the nicer output */
2641
ea4a240d 2642 if (arg_property && !strv_find(arg_property, name))
48220598
LP
2643 return 0;
2644
2645 switch (dbus_message_iter_get_arg_type(iter)) {
2646
48220598
LP
2647 case DBUS_TYPE_STRUCT: {
2648 DBusMessageIter sub;
2649 dbus_message_iter_recurse(iter, &sub);
2650
ebf57b80 2651 if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_UINT32 && streq(name, "Job")) {
48220598
LP
2652 uint32_t u;
2653
2654 dbus_message_iter_get_basic(&sub, &u);
2655
2656 if (u)
2657 printf("%s=%u\n", name, (unsigned) u);
2658 else if (arg_all)
2659 printf("%s=\n", name);
2660
2661 return 0;
ebf57b80 2662 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "Unit")) {
48220598
LP
2663 const char *s;
2664
2665 dbus_message_iter_get_basic(&sub, &s);
2666
2667 if (arg_all || s[0])
2668 printf("%s=%s\n", name, s);
2669
2670 return 0;
9f39404c
LP
2671 } else if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING && streq(name, "LoadError")) {
2672 const char *a = NULL, *b = NULL;
2673
f786e80d 2674 if (bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &a, true) >= 0)
9f39404c
LP
2675 bus_iter_get_basic_and_next(&sub, DBUS_TYPE_STRING, &b, false);
2676
2677 if (arg_all || !isempty(a) || !isempty(b))
2678 printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
f786e80d
LP
2679
2680 return 0;
48220598
LP
2681 }
2682
2683 break;
2684 }
2685
2686 case DBUS_TYPE_ARRAY:
2687
a4c279f8 2688 if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "EnvironmentFiles")) {
8c7be95e
LP
2689 DBusMessageIter sub, sub2;
2690
2691 dbus_message_iter_recurse(iter, &sub);
2692 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2693 const char *path;
2694 dbus_bool_t ignore;
2695
2696 dbus_message_iter_recurse(&sub, &sub2);
2697
2698 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) >= 0 &&
2699 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_BOOLEAN, &ignore, false) >= 0)
ecdcbc5e 2700 printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
8c7be95e
LP
2701
2702 dbus_message_iter_next(&sub);
2703 }
2704
2705 return 0;
2706
ebf57b80
LP
2707 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Paths")) {
2708 DBusMessageIter sub, sub2;
2709
2710 dbus_message_iter_recurse(iter, &sub);
ebf57b80
LP
2711 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2712 const char *type, *path;
2713
2714 dbus_message_iter_recurse(&sub, &sub2);
2715
2716 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) >= 0 &&
2717 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, false) >= 0)
2718 printf("%s=%s\n", type, path);
2719
2720 dbus_message_iter_next(&sub);
2721 }
2722
707e5e52 2723 return 0;
582a507f 2724
707e5e52
LP
2725 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "Timers")) {
2726 DBusMessageIter sub, sub2;
2727
2728 dbus_message_iter_recurse(iter, &sub);
707e5e52
LP
2729 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2730 const char *base;
2731 uint64_t value, next_elapse;
2732
2733 dbus_message_iter_recurse(&sub, &sub2);
2734
2735 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &base, true) >= 0 &&
2736 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &value, true) >= 0 &&
552e4331
LP
2737 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_UINT64, &next_elapse, false) >= 0) {
2738 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
2739
2740 printf("%s={ value=%s ; next_elapse=%s }\n",
fe68089d 2741 base,
552e4331
LP
2742 format_timespan(timespan1, sizeof(timespan1), value),
2743 format_timespan(timespan2, sizeof(timespan2), next_elapse));
2744 }
fe68089d
LP
2745
2746 dbus_message_iter_next(&sub);
2747 }
2748
2749 return 0;
fe68089d 2750
d8bbda91
LP
2751 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && streq(name, "ControlGroupAttributes")) {
2752 DBusMessageIter sub, sub2;
2753
2754 dbus_message_iter_recurse(iter, &sub);
2755 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
2756 const char *controller, *attr, *value;
2757
2758 dbus_message_iter_recurse(&sub, &sub2);
2759
2760 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &controller, true) >= 0 &&
2761 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &attr, true) >= 0 &&
2762 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &value, false) >= 0) {
2763
2764 printf("ControlGroupAttribute={ controller=%s ; attribute=%s ; value=\"%s\" }\n",
2765 controller,
2766 attr,
2767 value);
2768 }
2769
2770 dbus_message_iter_next(&sub);
2771 }
2772
2773 return 0;
2774
582a507f
LP
2775 } else if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRUCT && startswith(name, "Exec")) {
2776 DBusMessageIter sub;
fe68089d
LP
2777
2778 dbus_message_iter_recurse(iter, &sub);
fe68089d 2779 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRUCT) {
582a507f 2780 ExecStatusInfo info;
fe68089d 2781
582a507f
LP
2782 zero(info);
2783 if (exec_status_info_deserialize(&sub, &info) >= 0) {
fe68089d 2784 char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
582a507f
LP
2785 char *t;
2786
2787 t = strv_join(info.argv, " ");
2788
ecdcbc5e 2789 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
2790 name,
2791 strna(info.path),
2792 strna(t),
b708e7ce 2793 yes_no(info.ignore),
582a507f
LP
2794 strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
2795 strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
2796 (unsigned) info. pid,
2797 sigchld_code_to_string(info.code),
2798 info.status,
2799 info.code == CLD_EXITED ? "" : "/",
2800 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
fe68089d 2801
582a507f 2802 free(t);
fe68089d
LP
2803 }
2804
582a507f
LP
2805 free(info.path);
2806 strv_free(info.argv);
707e5e52
LP
2807
2808 dbus_message_iter_next(&sub);
2809 }
2810
48220598
LP
2811 return 0;
2812 }
2813
2814 break;
2815 }
2816
a4c279f8
LP
2817 if (generic_print_property(name, iter, arg_all) > 0)
2818 return 0;
2819
48220598
LP
2820 if (arg_all)
2821 printf("%s=[unprintable]\n", name);
2822
2823 return 0;
2824}
2825
be8088a2 2826static int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
48220598
LP
2827 DBusMessage *m = NULL, *reply = NULL;
2828 const char *interface = "";
2829 int r;
2830 DBusError error;
2831 DBusMessageIter iter, sub, sub2, sub3;
61cbdc4b 2832 UnitStatusInfo info;
582a507f 2833 ExecStatusInfo *p;
48220598
LP
2834
2835 assert(bus);
2836 assert(path);
61cbdc4b 2837 assert(new_line);
48220598 2838
61cbdc4b 2839 zero(info);
48220598
LP
2840 dbus_error_init(&error);
2841
2842 if (!(m = dbus_message_new_method_call(
2843 "org.freedesktop.systemd1",
2844 path,
2845 "org.freedesktop.DBus.Properties",
2846 "GetAll"))) {
2847 log_error("Could not allocate message.");
2848 r = -ENOMEM;
2849 goto finish;
2850 }
2851
2852 if (!dbus_message_append_args(m,
2853 DBUS_TYPE_STRING, &interface,
2854 DBUS_TYPE_INVALID)) {
2855 log_error("Could not append arguments to message.");
2856 r = -ENOMEM;
2857 goto finish;
2858 }
2859
2860 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 2861 log_error("Failed to issue method call: %s", bus_error_message(&error));
48220598
LP
2862 r = -EIO;
2863 goto finish;
2864 }
2865
2866 if (!dbus_message_iter_init(reply, &iter) ||
2867 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
2868 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
2869 log_error("Failed to parse reply.");
2870 r = -EIO;
2871 goto finish;
2872 }
2873
2874 dbus_message_iter_recurse(&iter, &sub);
2875
61cbdc4b
LP
2876 if (*new_line)
2877 printf("\n");
2878
2879 *new_line = true;
2880
48220598
LP
2881 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
2882 const char *name;
2883
2884 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
2885 log_error("Failed to parse reply.");
2886 r = -EIO;
2887 goto finish;
2888 }
2889
2890 dbus_message_iter_recurse(&sub, &sub2);
0183528f 2891
48220598
LP
2892 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
2893 log_error("Failed to parse reply.");
2894 r = -EIO;
2895 goto finish;
2896 }
2897
2898 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
2899 log_error("Failed to parse reply.");
2900 r = -EIO;
2901 goto finish;
2902 }
2903
2904 dbus_message_iter_recurse(&sub2, &sub3);
2905
61cbdc4b
LP
2906 if (show_properties)
2907 r = print_property(name, &sub3);
2908 else
2909 r = status_property(name, &sub3, &info);
2910
2911 if (r < 0) {
48220598
LP
2912 log_error("Failed to parse reply.");
2913 r = -EIO;
2914 goto finish;
2915 }
2916
2917 dbus_message_iter_next(&sub);
2918 }
2919
f1e36d67
LP
2920 r = 0;
2921
22f4096c
LP
2922 if (!show_properties)
2923 print_status_info(&info);
f1e36d67 2924
22f4096c 2925 if (!streq_ptr(info.active_state, "active") &&
be8088a2
LP
2926 !streq_ptr(info.active_state, "reloading") &&
2927 streq(verb, "status"))
22f4096c
LP
2928 /* According to LSB: "program not running" */
2929 r = 3;
61cbdc4b 2930
582a507f
LP
2931 while ((p = info.exec)) {
2932 LIST_REMOVE(ExecStatusInfo, exec, info.exec, p);
2933 exec_status_info_free(p);
2934 }
2935
48220598
LP
2936finish:
2937 if (m)
2938 dbus_message_unref(m);
2939
2940 if (reply)
2941 dbus_message_unref(reply);
2942
2943 dbus_error_free(&error);
2944
2945 return r;
2946}
2947
729e3769 2948static int show(DBusConnection *bus, char **args) {
48220598 2949 DBusMessage *m = NULL, *reply = NULL;
22f4096c 2950 int r, ret = 0;
48220598 2951 DBusError error;
61cbdc4b 2952 bool show_properties, new_line = false;
729e3769 2953 char **name;
48220598
LP
2954
2955 assert(bus);
2956 assert(args);
2957
2958 dbus_error_init(&error);
2959
61cbdc4b
LP
2960 show_properties = !streq(args[0], "status");
2961
ec14911e 2962 if (show_properties)
1968a360 2963 pager_open_if_enabled();
ec14911e 2964
729e3769 2965 if (show_properties && strv_length(args) <= 1) {
48220598
LP
2966 /* If not argument is specified inspect the manager
2967 * itself */
2968
be8088a2 2969 ret = show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line);
48220598
LP
2970 goto finish;
2971 }
2972
729e3769 2973 STRV_FOREACH(name, args+1) {
48220598
LP
2974 const char *path = NULL;
2975 uint32_t id;
2976
729e3769 2977 if (safe_atou32(*name, &id) < 0) {
598b557b
LP
2978
2979 /* Interpret as unit name */
48220598
LP
2980
2981 if (!(m = dbus_message_new_method_call(
2982 "org.freedesktop.systemd1",
2983 "/org/freedesktop/systemd1",
2984 "org.freedesktop.systemd1.Manager",
e87d1818 2985 "LoadUnit"))) {
48220598 2986 log_error("Could not allocate message.");
22f4096c 2987 ret = -ENOMEM;
48220598
LP
2988 goto finish;
2989 }
2990
2991 if (!dbus_message_append_args(m,
729e3769 2992 DBUS_TYPE_STRING, name,
48220598
LP
2993 DBUS_TYPE_INVALID)) {
2994 log_error("Could not append arguments to message.");
22f4096c 2995 ret = -ENOMEM;
48220598
LP
2996 goto finish;
2997 }
2998
ed2d7a44
LP
2999 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
3000
3001 if (!dbus_error_has_name(&error, DBUS_ERROR_ACCESS_DENIED)) {
4cf5d675 3002 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c 3003 ret = -EIO;
ed2d7a44
LP
3004 goto finish;
3005 }
3006
3007 dbus_error_free(&error);
3008
3009 dbus_message_unref(m);
3010 if (!(m = dbus_message_new_method_call(
3011 "org.freedesktop.systemd1",
3012 "/org/freedesktop/systemd1",
3013 "org.freedesktop.systemd1.Manager",
3014 "GetUnit"))) {
3015 log_error("Could not allocate message.");
22f4096c 3016 ret = -ENOMEM;
ed2d7a44
LP
3017 goto finish;
3018 }
3019
3020 if (!dbus_message_append_args(m,
729e3769 3021 DBUS_TYPE_STRING, name,
ed2d7a44
LP
3022 DBUS_TYPE_INVALID)) {
3023 log_error("Could not append arguments to message.");
22f4096c 3024 ret = -ENOMEM;
ed2d7a44
LP
3025 goto finish;
3026 }
3027
3028 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3029 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c
LP
3030
3031 if (dbus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT))
3032 ret = 4; /* According to LSB: "program or service status is unknown" */
3033 else
3034 ret = -EIO;
ed2d7a44
LP
3035 goto finish;
3036 }
3037 }
3038
598b557b
LP
3039 } else if (show_properties) {
3040
3041 /* Interpret as job id */
48220598
LP
3042
3043 if (!(m = dbus_message_new_method_call(
3044 "org.freedesktop.systemd1",
3045 "/org/freedesktop/systemd1",
3046 "org.freedesktop.systemd1.Manager",
3047 "GetJob"))) {
3048 log_error("Could not allocate message.");
22f4096c 3049 ret = -ENOMEM;
48220598
LP
3050 goto finish;
3051 }
3052
3053 if (!dbus_message_append_args(m,
3054 DBUS_TYPE_UINT32, &id,
3055 DBUS_TYPE_INVALID)) {
3056 log_error("Could not append arguments to message.");
22f4096c 3057 ret = -ENOMEM;
48220598
LP
3058 goto finish;
3059 }
48220598 3060
598b557b 3061 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3062 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c 3063 ret = -EIO;
598b557b
LP
3064 goto finish;
3065 }
3066 } else {
3067
3068 /* Interpret as PID */
3069
3070 if (!(m = dbus_message_new_method_call(
3071 "org.freedesktop.systemd1",
3072 "/org/freedesktop/systemd1",
3073 "org.freedesktop.systemd1.Manager",
3074 "GetUnitByPID"))) {
3075 log_error("Could not allocate message.");
22f4096c 3076 ret = -ENOMEM;
598b557b
LP
3077 goto finish;
3078 }
3079
3080 if (!dbus_message_append_args(m,
3081 DBUS_TYPE_UINT32, &id,
3082 DBUS_TYPE_INVALID)) {
3083 log_error("Could not append arguments to message.");
22f4096c 3084 ret = -ENOMEM;
598b557b
LP
3085 goto finish;
3086 }
3087
ed2d7a44 3088 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3089 log_error("Failed to issue method call: %s", bus_error_message(&error));
22f4096c 3090 ret = -EIO;
ed2d7a44
LP
3091 goto finish;
3092 }
48220598
LP
3093 }
3094
3095 if (!dbus_message_get_args(reply, &error,
3096 DBUS_TYPE_OBJECT_PATH, &path,
3097 DBUS_TYPE_INVALID)) {
4cf5d675 3098 log_error("Failed to parse reply: %s", bus_error_message(&error));
22f4096c 3099 ret = -EIO;
48220598
LP
3100 goto finish;
3101 }
3102
be8088a2 3103 if ((r = show_one(args[0], bus, path, show_properties, &new_line)) != 0)
22f4096c 3104 ret = r;
48220598
LP
3105
3106 dbus_message_unref(m);
3107 dbus_message_unref(reply);
3108 m = reply = NULL;
3109 }
3110
48220598
LP
3111finish:
3112 if (m)
3113 dbus_message_unref(m);
3114
3115 if (reply)
3116 dbus_message_unref(reply);
3117
3118 dbus_error_free(&error);
3119
22f4096c 3120 return ret;
0183528f
LP
3121}
3122
729e3769 3123static int dump(DBusConnection *bus, char **args) {
7e4249b9
LP
3124 DBusMessage *m = NULL, *reply = NULL;
3125 DBusError error;
3126 int r;
3127 const char *text;
3128
3129 dbus_error_init(&error);
3130
1968a360 3131 pager_open_if_enabled();
ec14911e 3132
7e4249b9
LP
3133 if (!(m = dbus_message_new_method_call(
3134 "org.freedesktop.systemd1",
3135 "/org/freedesktop/systemd1",
3136 "org.freedesktop.systemd1.Manager",
3137 "Dump"))) {
3138 log_error("Could not allocate message.");
3139 return -ENOMEM;
3140 }
3141
3142 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3143 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3144 r = -EIO;
3145 goto finish;
3146 }
3147
3148 if (!dbus_message_get_args(reply, &error,
3149 DBUS_TYPE_STRING, &text,
3150 DBUS_TYPE_INVALID)) {
4cf5d675 3151 log_error("Failed to parse reply: %s", bus_error_message(&error));
7e4249b9
LP
3152 r = -EIO;
3153 goto finish;
3154 }
3155
3156 fputs(text, stdout);
3157
3158 r = 0;
3159
3160finish:
3161 if (m)
3162 dbus_message_unref(m);
3163
3164 if (reply)
3165 dbus_message_unref(reply);
3166
3167 dbus_error_free(&error);
3168
3169 return r;
3170}
3171
729e3769 3172static int snapshot(DBusConnection *bus, char **args) {
7e4249b9
LP
3173 DBusMessage *m = NULL, *reply = NULL;
3174 DBusError error;
3175 int r;
3176 const char *name = "", *path, *id;
3177 dbus_bool_t cleanup = FALSE;
3178 DBusMessageIter iter, sub;
3179 const char
3180 *interface = "org.freedesktop.systemd1.Unit",
3181 *property = "Id";
3182
3183 dbus_error_init(&error);
3184
3185 if (!(m = dbus_message_new_method_call(
3186 "org.freedesktop.systemd1",
3187 "/org/freedesktop/systemd1",
3188 "org.freedesktop.systemd1.Manager",
3189 "CreateSnapshot"))) {
3190 log_error("Could not allocate message.");
3191 return -ENOMEM;
3192 }
3193
729e3769 3194 if (strv_length(args) > 1)
7e4249b9
LP
3195 name = args[1];
3196
3197 if (!dbus_message_append_args(m,
3198 DBUS_TYPE_STRING, &name,
3199 DBUS_TYPE_BOOLEAN, &cleanup,
3200 DBUS_TYPE_INVALID)) {
3201 log_error("Could not append arguments to message.");
3202 r = -ENOMEM;
3203 goto finish;
3204 }
3205
3206 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3207 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3208 r = -EIO;
3209 goto finish;
3210 }
3211
3212 if (!dbus_message_get_args(reply, &error,
3213 DBUS_TYPE_OBJECT_PATH, &path,
3214 DBUS_TYPE_INVALID)) {
4cf5d675 3215 log_error("Failed to parse reply: %s", bus_error_message(&error));
7e4249b9
LP
3216 r = -EIO;
3217 goto finish;
3218 }
3219
3220 dbus_message_unref(m);
3221 if (!(m = dbus_message_new_method_call(
3222 "org.freedesktop.systemd1",
3223 path,
3224 "org.freedesktop.DBus.Properties",
3225 "Get"))) {
3226 log_error("Could not allocate message.");
3227 return -ENOMEM;
3228 }
3229
3230 if (!dbus_message_append_args(m,
3231 DBUS_TYPE_STRING, &interface,
3232 DBUS_TYPE_STRING, &property,
3233 DBUS_TYPE_INVALID)) {
3234 log_error("Could not append arguments to message.");
3235 r = -ENOMEM;
3236 goto finish;
3237 }
3238
3239 dbus_message_unref(reply);
3240 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3241 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3242 r = -EIO;
3243 goto finish;
3244 }
3245
3246 if (!dbus_message_iter_init(reply, &iter) ||
3247 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3248 log_error("Failed to parse reply.");
3249 r = -EIO;
3250 goto finish;
3251 }
3252
3253 dbus_message_iter_recurse(&iter, &sub);
3254
3255 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) {
3256 log_error("Failed to parse reply.");
3257 r = -EIO;
3258 goto finish;
3259 }
3260
3261 dbus_message_iter_get_basic(&sub, &id);
0183528f
LP
3262
3263 if (!arg_quiet)
3264 puts(id);
7e4249b9
LP
3265 r = 0;
3266
3267finish:
3268 if (m)
3269 dbus_message_unref(m);
3270
3271 if (reply)
3272 dbus_message_unref(reply);
3273
3274 dbus_error_free(&error);
3275
3276 return r;
3277}
3278
729e3769 3279static int delete_snapshot(DBusConnection *bus, char **args) {
6759e7a7
LP
3280 DBusMessage *m = NULL, *reply = NULL;
3281 int r;
3282 DBusError error;
729e3769 3283 char **name;
6759e7a7
LP
3284
3285 assert(bus);
3286 assert(args);
3287
3288 dbus_error_init(&error);
3289
729e3769 3290 STRV_FOREACH(name, args+1) {
6759e7a7
LP
3291 const char *path = NULL;
3292
3293 if (!(m = dbus_message_new_method_call(
3294 "org.freedesktop.systemd1",
3295 "/org/freedesktop/systemd1",
3296 "org.freedesktop.systemd1.Manager",
3297 "GetUnit"))) {
3298 log_error("Could not allocate message.");
3299 r = -ENOMEM;
3300 goto finish;
3301 }
3302
3303 if (!dbus_message_append_args(m,
729e3769 3304 DBUS_TYPE_STRING, name,
6759e7a7
LP
3305 DBUS_TYPE_INVALID)) {
3306 log_error("Could not append arguments to message.");
3307 r = -ENOMEM;
3308 goto finish;
3309 }
3310
3311 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3312 log_error("Failed to issue method call: %s", bus_error_message(&error));
6759e7a7
LP
3313 r = -EIO;
3314 goto finish;
3315 }
3316
3317 if (!dbus_message_get_args(reply, &error,
3318 DBUS_TYPE_OBJECT_PATH, &path,
3319 DBUS_TYPE_INVALID)) {
4cf5d675 3320 log_error("Failed to parse reply: %s", bus_error_message(&error));
6759e7a7
LP
3321 r = -EIO;
3322 goto finish;
3323 }
3324
3325 dbus_message_unref(m);
3326 if (!(m = dbus_message_new_method_call(
3327 "org.freedesktop.systemd1",
3328 path,
3329 "org.freedesktop.systemd1.Snapshot",
3330 "Remove"))) {
3331 log_error("Could not allocate message.");
3332 r = -ENOMEM;
3333 goto finish;
3334 }
3335
3336 dbus_message_unref(reply);
3337 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3338 log_error("Failed to issue method call: %s", bus_error_message(&error));
6759e7a7
LP
3339 r = -EIO;
3340 goto finish;
3341 }
3342
3343 dbus_message_unref(m);
3344 dbus_message_unref(reply);
3345 m = reply = NULL;
3346 }
3347
3348 r = 0;
3349
3350finish:
3351 if (m)
3352 dbus_message_unref(m);
3353
3354 if (reply)
3355 dbus_message_unref(reply);
3356
3357 dbus_error_free(&error);
3358
3359 return r;
3360}
3361
729e3769 3362static int daemon_reload(DBusConnection *bus, char **args) {
7e4249b9
LP
3363 DBusMessage *m = NULL, *reply = NULL;
3364 DBusError error;
3365 int r;
3366 const char *method;
3367
3368 dbus_error_init(&error);
3369
e4b61340
LP
3370 if (arg_action == ACTION_RELOAD)
3371 method = "Reload";
3372 else if (arg_action == ACTION_REEXEC)
3373 method = "Reexecute";
3374 else {
3375 assert(arg_action == ACTION_SYSTEMCTL);
3376
3377 method =
20b09ca7
LP
3378 streq(args[0], "clear-jobs") ||
3379 streq(args[0], "cancel") ? "ClearJobs" :
3380 streq(args[0], "daemon-reexec") ? "Reexecute" :
3381 streq(args[0], "reset-failed") ? "ResetFailed" :
3382 streq(args[0], "halt") ? "Halt" :
3383 streq(args[0], "poweroff") ? "PowerOff" :
3384 streq(args[0], "reboot") ? "Reboot" :
3385 streq(args[0], "kexec") ? "KExec" :
3386 streq(args[0], "exit") ? "Exit" :
3387 /* "daemon-reload" */ "Reload";
e4b61340 3388 }
7e4249b9
LP
3389
3390 if (!(m = dbus_message_new_method_call(
3391 "org.freedesktop.systemd1",
3392 "/org/freedesktop/systemd1",
3393 "org.freedesktop.systemd1.Manager",
3394 method))) {
3395 log_error("Could not allocate message.");
3396 return -ENOMEM;
3397 }
3398
3399 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
e4b61340
LP
3400
3401 if (arg_action != ACTION_SYSTEMCTL && error_is_no_service(&error)) {
3402 /* There's always a fallback possible for
3403 * legacy actions. */
aabd9b11 3404 r = -EADDRNOTAVAIL;
e4b61340
LP
3405 goto finish;
3406 }
3407
b23de6af
LP
3408 if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
3409 /* On reexecution, we expect a disconnect, not
3410 * a reply */
3411 r = 0;
3412 goto finish;
3413 }
3414
4cf5d675 3415 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3416 r = -EIO;
3417 goto finish;
3418 }
3419
aabd9b11 3420 r = 0;
7e4249b9
LP
3421
3422finish:
3423 if (m)
3424 dbus_message_unref(m);
3425
3426 if (reply)
3427 dbus_message_unref(reply);
3428
3429 dbus_error_free(&error);
3430
3431 return r;
3432}
3433
729e3769 3434static int reset_failed(DBusConnection *bus, char **args) {
f8440af5 3435 DBusMessage *m = NULL;
5632e374
LP
3436 int r;
3437 DBusError error;
729e3769 3438 char **name;
5632e374
LP
3439
3440 assert(bus);
3441 dbus_error_init(&error);
3442
729e3769
LP
3443 if (strv_length(args) <= 1)
3444 return daemon_reload(bus, args);
5632e374 3445
729e3769 3446 STRV_FOREACH(name, args+1) {
f8440af5 3447 DBusMessage *reply;
5632e374
LP
3448
3449 if (!(m = dbus_message_new_method_call(
3450 "org.freedesktop.systemd1",
3451 "/org/freedesktop/systemd1",
3452 "org.freedesktop.systemd1.Manager",
fdf20a31 3453 "ResetFailedUnit"))) {
5632e374
LP
3454 log_error("Could not allocate message.");
3455 r = -ENOMEM;
3456 goto finish;
3457 }
3458
3459 if (!dbus_message_append_args(m,
729e3769 3460 DBUS_TYPE_STRING, name,
5632e374
LP
3461 DBUS_TYPE_INVALID)) {
3462 log_error("Could not append arguments to message.");
3463 r = -ENOMEM;
3464 goto finish;
3465 }
3466
3467 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3468 log_error("Failed to issue method call: %s", bus_error_message(&error));
5632e374
LP
3469 r = -EIO;
3470 goto finish;
3471 }
3472
3473 dbus_message_unref(m);
3474 dbus_message_unref(reply);
3475 m = reply = NULL;
3476 }
3477
3478 r = 0;
3479
3480finish:
3481 if (m)
3482 dbus_message_unref(m);
3483
5632e374
LP
3484 dbus_error_free(&error);
3485
3486 return r;
3487}
3488
729e3769 3489static int show_enviroment(DBusConnection *bus, char **args) {
7e4249b9
LP
3490 DBusMessage *m = NULL, *reply = NULL;
3491 DBusError error;
3492 DBusMessageIter iter, sub, sub2;
3493 int r;
3494 const char
3495 *interface = "org.freedesktop.systemd1.Manager",
3496 *property = "Environment";
3497
3498 dbus_error_init(&error);
3499
1968a360 3500 pager_open_if_enabled();
ec14911e 3501
7e4249b9
LP
3502 if (!(m = dbus_message_new_method_call(
3503 "org.freedesktop.systemd1",
3504 "/org/freedesktop/systemd1",
3505 "org.freedesktop.DBus.Properties",
3506 "Get"))) {
3507 log_error("Could not allocate message.");
3508 return -ENOMEM;
3509 }
3510
3511 if (!dbus_message_append_args(m,
3512 DBUS_TYPE_STRING, &interface,
3513 DBUS_TYPE_STRING, &property,
3514 DBUS_TYPE_INVALID)) {
3515 log_error("Could not append arguments to message.");
3516 r = -ENOMEM;
3517 goto finish;
3518 }
3519
3520 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3521 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3522 r = -EIO;
3523 goto finish;
3524 }
3525
3526 if (!dbus_message_iter_init(reply, &iter) ||
3527 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
3528 log_error("Failed to parse reply.");
3529 r = -EIO;
3530 goto finish;
3531 }
3532
3533 dbus_message_iter_recurse(&iter, &sub);
3534
3535 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY ||
3536 dbus_message_iter_get_element_type(&sub) != DBUS_TYPE_STRING) {
3537 log_error("Failed to parse reply.");
3538 r = -EIO;
3539 goto finish;
3540 }
3541
3542 dbus_message_iter_recurse(&sub, &sub2);
3543
3544 while (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_INVALID) {
3545 const char *text;
3546
3547 if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
3548 log_error("Failed to parse reply.");
3549 r = -EIO;
3550 goto finish;
3551 }
3552
3553 dbus_message_iter_get_basic(&sub2, &text);
3554 printf("%s\n", text);
3555
3556 dbus_message_iter_next(&sub2);
3557 }
3558
3559 r = 0;
3560
3561finish:
3562 if (m)
3563 dbus_message_unref(m);
3564
3565 if (reply)
3566 dbus_message_unref(reply);
3567
3568 dbus_error_free(&error);
3569
3570 return r;
3571}
3572
729e3769 3573static int set_environment(DBusConnection *bus, char **args) {
7e4249b9
LP
3574 DBusMessage *m = NULL, *reply = NULL;
3575 DBusError error;
3576 int r;
3577 const char *method;
3578 DBusMessageIter iter, sub;
729e3769 3579 char **name;
7e4249b9
LP
3580
3581 dbus_error_init(&error);
3582
3583 method = streq(args[0], "set-environment")
3584 ? "SetEnvironment"
3585 : "UnsetEnvironment";
3586
3587 if (!(m = dbus_message_new_method_call(
3588 "org.freedesktop.systemd1",
3589 "/org/freedesktop/systemd1",
3590 "org.freedesktop.systemd1.Manager",
3591 method))) {
3592
3593 log_error("Could not allocate message.");
3594 return -ENOMEM;
3595 }
3596
3597 dbus_message_iter_init_append(m, &iter);
3598
3599 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
3600 log_error("Could not append arguments to message.");
3601 r = -ENOMEM;
3602 goto finish;
3603 }
3604
729e3769
LP
3605 STRV_FOREACH(name, args+1)
3606 if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
7e4249b9
LP
3607 log_error("Could not append arguments to message.");
3608 r = -ENOMEM;
3609 goto finish;
3610 }
3611
3612 if (!dbus_message_iter_close_container(&iter, &sub)) {
3613 log_error("Could not append arguments to message.");
3614 r = -ENOMEM;
3615 goto finish;
3616 }
3617
3618 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
4cf5d675 3619 log_error("Failed to issue method call: %s", bus_error_message(&error));
7e4249b9
LP
3620 r = -EIO;
3621 goto finish;
3622 }
3623
3624 r = 0;
3625
3626finish:
3627 if (m)
3628 dbus_message_unref(m);
3629
3630 if (reply)
3631 dbus_message_unref(reply);
3632
3633 dbus_error_free(&error);
3634
3635 return r;
3636}
3637
729e3769
LP
3638static int enable_sysv_units(char **args) {
3639 int r = 0;
ee5762e3 3640
6fdae8a6 3641#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
3642 const char *verb = args[0];
3643 unsigned f = 1, t = 1;
3644 LookupPaths paths;
ee5762e3 3645
729e3769
LP
3646 if (arg_scope != UNIT_FILE_SYSTEM)
3647 return 0;
ee5762e3 3648
729e3769
LP
3649 if (!streq(verb, "enable") &&
3650 !streq(verb, "disable") &&
3651 !streq(verb, "is-enabled"))
3652 return 0;
ee5762e3 3653
729e3769
LP
3654 /* Processes all SysV units, and reshuffles the array so that
3655 * afterwards only the native units remain */
ee5762e3 3656
729e3769
LP
3657 zero(paths);
3658 r = lookup_paths_init(&paths, MANAGER_SYSTEM, false);
3659 if (r < 0)
3660 return r;
ee5762e3 3661
729e3769 3662 r = 0;
ee5762e3 3663
729e3769
LP
3664 for (f = 1; args[f]; f++) {
3665 const char *name;
3666 char *p;
3667 bool found_native = false, found_sysv;
3668 unsigned c = 1;
3669 const char *argv[6] = { "/sbin/chkconfig", NULL, NULL, NULL, NULL };
3670 char **k, *l, *q = NULL;
3671 int j;
3672 pid_t pid;
3673 siginfo_t status;
ee5762e3 3674
729e3769 3675 name = args[f];
ee5762e3 3676
729e3769
LP
3677 if (!endswith(name, ".service"))
3678 continue;
ee5762e3 3679
729e3769
LP
3680 if (path_is_absolute(name))
3681 continue;
ee5762e3 3682
729e3769
LP
3683 STRV_FOREACH(k, paths.unit_path) {
3684 p = NULL;
ee5762e3 3685
729e3769
LP
3686 if (!isempty(arg_root))
3687 asprintf(&p, "%s/%s/%s", arg_root, *k, name);
3688 else
3689 asprintf(&p, "%s/%s", *k, name);
ee5762e3 3690
729e3769
LP
3691 if (!p) {
3692 log_error("No memory");
3693 r = -ENOMEM;
3694 goto finish;
3695 }
ee5762e3 3696
729e3769
LP
3697 found_native = access(p, F_OK) >= 0;
3698 free(p);
ee5762e3 3699
729e3769
LP
3700 if (found_native)
3701 break;
3702 }
ee5762e3 3703
729e3769
LP
3704 if (found_native)
3705 continue;
ee5762e3 3706
729e3769
LP
3707 p = NULL;
3708 if (!isempty(arg_root))
3709 asprintf(&p, "%s/" SYSTEM_SYSVINIT_PATH "/%s", arg_root, name);
3710 else
3711 asprintf(&p, SYSTEM_SYSVINIT_PATH "/%s", name);
3712 if (!p) {
3713 log_error("No memory");
3714 r = -ENOMEM;
3715 goto finish;
3716 }
ee5762e3 3717
729e3769
LP
3718 p[strlen(p) - sizeof(".service") + 1] = 0;
3719 found_sysv = access(p, F_OK) >= 0;
ee5762e3 3720
729e3769
LP
3721 if (!found_sysv) {
3722 free(p);
3723 continue;
71fad675
LP
3724 }
3725
729e3769
LP
3726 /* Mark this entry, so that we don't try enabling it as native unit */
3727 args[f] = (char*) "";
ee5762e3 3728
729e3769 3729 log_info("%s is not a native service, redirecting to /sbin/chkconfig.", name);
ee5762e3 3730
729e3769
LP
3731 if (!isempty(arg_root))
3732 argv[c++] = q = strappend("--root=", arg_root);
ee5762e3 3733
9eb977db 3734 argv[c++] = path_get_file_name(p);
729e3769
LP
3735 argv[c++] =
3736 streq(verb, "enable") ? "on" :
3737 streq(verb, "disable") ? "off" : "--level=5";
3738 argv[c] = NULL;
ee5762e3 3739
729e3769
LP
3740 l = strv_join((char**)argv, " ");
3741 if (!l) {
3742 log_error("No memory.");
3743 free(q);
3744 free(p);
3745 r = -ENOMEM;
3746 goto finish;
3747 }
ee5762e3 3748
729e3769
LP
3749 log_info("Executing %s", l);
3750 free(l);
ee5762e3 3751
729e3769
LP
3752 pid = fork();
3753 if (pid < 0) {
3754 log_error("Failed to fork: %m");
3755 free(p);
3756 free(q);
3757 r = -errno;
3758 goto finish;
3759 } else if (pid == 0) {
3760 /* Child */
ee5762e3 3761
729e3769
LP
3762 execv(argv[0], (char**) argv);
3763 _exit(EXIT_FAILURE);
3764 }
ee5762e3 3765
729e3769
LP
3766 free(p);
3767 free(q);
ee5762e3 3768
729e3769
LP
3769 j = wait_for_terminate(pid, &status);
3770 if (j < 0) {
3771 log_error("Failed to wait for child: %s", strerror(-r));
3772 r = j;
3773 goto finish;
3774 }
ee5762e3 3775
729e3769
LP
3776 if (status.si_code == CLD_EXITED) {
3777 if (streq(verb, "is-enabled")) {
3778 if (status.si_status == 0) {
3779 if (!arg_quiet)
3780 puts("enabled");
3781 r = 1;
3782 } else {
3783 if (!arg_quiet)
3784 puts("disabled");
3785 }
ee5762e3 3786
729e3769
LP
3787 } else if (status.si_status != 0) {
3788 r = -EINVAL;
3789 goto finish;
3790 }
3791 } else {
3792 r = -EPROTO;
3793 goto finish;
3794 }
ee5762e3
LP
3795 }
3796
729e3769
LP
3797finish:
3798 lookup_paths_free(&paths);
ee5762e3 3799
729e3769
LP
3800 /* Drop all SysV units */
3801 for (f = 1, t = 1; args[f]; f++) {
ee5762e3 3802
729e3769 3803 if (isempty(args[f]))
ee5762e3
LP
3804 continue;
3805
729e3769
LP
3806 args[t++] = args[f];
3807 }
ee5762e3 3808
729e3769 3809 args[t] = NULL;
ee5762e3 3810
729e3769
LP
3811#endif
3812 return r;
3813}
ee5762e3 3814
729e3769
LP
3815static int enable_unit(DBusConnection *bus, char **args) {
3816 const char *verb = args[0];
3817 UnitFileChange *changes = NULL;
3818 unsigned n_changes = 0, i;
3819 int carries_install_info = -1;
3820 DBusMessage *m = NULL, *reply = NULL;
3821 int r;
3822 DBusError error;
ee5762e3 3823
729e3769
LP
3824 r = enable_sysv_units(args);
3825 if (r < 0)
3826 return r;
ee5762e3 3827
ab5919fa
MS
3828 if (!args[1])
3829 return 0;
3830
3831 dbus_error_init(&error);
3832
729e3769
LP
3833 if (!bus || avoid_bus()) {
3834 if (streq(verb, "enable")) {
3835 r = unit_file_enable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3836 carries_install_info = r;
3837 } else if (streq(verb, "disable"))
3838 r = unit_file_disable(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3839 else if (streq(verb, "reenable")) {
3840 r = unit_file_reenable(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3841 carries_install_info = r;
3842 } else if (streq(verb, "link"))
3843 r = unit_file_link(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3844 else if (streq(verb, "preset")) {
3845 r = unit_file_preset(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3846 carries_install_info = r;
3847 } else if (streq(verb, "mask"))
3848 r = unit_file_mask(arg_scope, arg_runtime, arg_root, args+1, arg_force, &changes, &n_changes);
3849 else if (streq(verb, "unmask"))
3850 r = unit_file_unmask(arg_scope, arg_runtime, arg_root, args+1, &changes, &n_changes);
3851 else
3852 assert_not_reached("Unknown verb");
ee5762e3 3853
729e3769
LP
3854 if (r < 0) {
3855 log_error("Operation failed: %s", strerror(-r));
3856 goto finish;
ee5762e3
LP
3857 }
3858
d1f262fa
LP
3859 if (!arg_quiet) {
3860 for (i = 0; i < n_changes; i++) {
3861 if (changes[i].type == UNIT_FILE_SYMLINK)
3862 log_info("ln -s '%s' '%s'", changes[i].source, changes[i].path);
3863 else
3864 log_info("rm '%s'", changes[i].path);
3865 }
ee5762e3
LP
3866 }
3867
729e3769
LP
3868 } else {
3869 const char *method;
3870 bool send_force = true, expect_carries_install_info = false;
3871 dbus_bool_t a, b;
3872 DBusMessageIter iter, sub, sub2;
3873
3874 if (streq(verb, "enable")) {
3875 method = "EnableUnitFiles";
3876 expect_carries_install_info = true;
3877 } else if (streq(verb, "disable")) {
3878 method = "DisableUnitFiles";
3879 send_force = false;
3880 } else if (streq(verb, "reenable")) {
3881 method = "ReenableUnitFiles";
3882 expect_carries_install_info = true;
3883 } else if (streq(verb, "link"))
3884 method = "LinkUnitFiles";
3885 else if (streq(verb, "preset")) {
3886 method = "PresetUnitFiles";
3887 expect_carries_install_info = true;
3888 } else if (streq(verb, "mask"))
3889 method = "MaskUnitFiles";
3890 else if (streq(verb, "unmask")) {
3891 method = "UnmaskUnitFiles";
3892 send_force = false;
3893 } else
3894 assert_not_reached("Unknown verb");
3895
3896 m = dbus_message_new_method_call(
3897 "org.freedesktop.systemd1",
3898 "/org/freedesktop/systemd1",
3899 "org.freedesktop.systemd1.Manager",
3900 method);
3901 if (!m) {
ee5762e3
LP
3902 log_error("Out of memory");
3903 r = -ENOMEM;
3904 goto finish;
3905 }
3906
729e3769 3907 dbus_message_iter_init_append(m, &iter);
ee5762e3 3908
729e3769
LP
3909 r = bus_append_strv_iter(&iter, args+1);
3910 if (r < 0) {
3911 log_error("Failed to append unit files.");
ee5762e3
LP
3912 goto finish;
3913 }
3914
729e3769
LP
3915 a = arg_runtime;
3916 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &a)) {
3917 log_error("Failed to append runtime boolean.");
ee5762e3
LP
3918 r = -ENOMEM;
3919 goto finish;
3920 }
3921
729e3769
LP
3922 if (send_force) {
3923 b = arg_force;
be394c48 3924
729e3769
LP
3925 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b)) {
3926 log_error("Failed to append force boolean.");
3927 r = -ENOMEM;
3928 goto finish;
3929 }
09adcdf7 3930 }
ee5762e3 3931
729e3769
LP
3932 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
3933 if (!reply) {
3934 log_error("Failed to issue method call: %s", bus_error_message(&error));
3935 r = -EIO;
3936 goto finish;
ee5762e3
LP
3937 }
3938
729e3769
LP
3939 if (!dbus_message_iter_init(reply, &iter)) {
3940 log_error("Failed to initialize iterator.");
3941 goto finish;
3942 }
be394c48 3943
729e3769
LP
3944 if (expect_carries_install_info) {
3945 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &b, true);
3946 if (r < 0) {
3947 log_error("Failed to parse reply.");
3948 goto finish;
3949 }
ee5762e3 3950
729e3769 3951 carries_install_info = b;
ee5762e3
LP
3952 }
3953
729e3769
LP
3954 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
3955 dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
3956 log_error("Failed to parse reply.");
3957 r = -EIO;
3958 goto finish;
ee5762e3
LP
3959 }
3960
729e3769
LP
3961 dbus_message_iter_recurse(&iter, &sub);
3962 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
3963 const char *type, *path, *source;
c8b2e52c 3964
729e3769
LP
3965 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
3966 log_error("Failed to parse reply.");
3967 r = -EIO;
3968 goto finish;
c8b2e52c
LP
3969 }
3970
729e3769 3971 dbus_message_iter_recurse(&sub, &sub2);
c8b2e52c 3972
729e3769
LP
3973 if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &type, true) < 0 ||
3974 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &path, true) < 0 ||
3975 bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &source, false) < 0) {
3976 log_error("Failed to parse reply.");
3977 r = -EIO;
3978 goto finish;
c8b2e52c
LP
3979 }
3980
d1f262fa
LP
3981 if (!arg_quiet) {
3982 if (streq(type, "symlink"))
3983 log_info("ln -s '%s' '%s'", source, path);
3984 else
3985 log_info("rm '%s'", path);
3986 }
b77398f7 3987
729e3769
LP
3988 dbus_message_iter_next(&sub);
3989 }
b77398f7 3990
729e3769
LP
3991 /* Try to reload if enabeld */
3992 if (!arg_no_reload)
3993 r = daemon_reload(bus, args);
b647f10d 3994 }
3d3961f2 3995
729e3769
LP
3996 if (carries_install_info == 0)
3997 log_warning("Warning: unit files do not carry install information. No operation executed.");
ee5762e3 3998
729e3769
LP
3999finish:
4000 if (m)
4001 dbus_message_unref(m);
ee5762e3 4002
729e3769
LP
4003 if (reply)
4004 dbus_message_unref(reply);
ee5762e3 4005
729e3769 4006 unit_file_changes_free(changes, n_changes);
ee5762e3 4007
729e3769
LP
4008 dbus_error_free(&error);
4009 return r;
ee5762e3
LP
4010}
4011
729e3769 4012static int unit_is_enabled(DBusConnection *bus, char **args) {
ee5762e3
LP
4013 DBusError error;
4014 int r;
729e3769
LP
4015 DBusMessage *m = NULL, *reply = NULL;
4016 bool enabled;
4017 char **name;
ee5762e3
LP
4018
4019 dbus_error_init(&error);
4020
729e3769
LP
4021 r = enable_sysv_units(args);
4022 if (r < 0)
4023 return r;
ee5762e3 4024
729e3769 4025 enabled = r > 0;
ee5762e3 4026
729e3769 4027 if (!bus || avoid_bus()) {
ee5762e3 4028
729e3769
LP
4029 STRV_FOREACH(name, args+1) {
4030 UnitFileState state;
ee5762e3 4031
729e3769
LP
4032 state = unit_file_get_state(arg_scope, arg_root, *name);
4033 if (state < 0) {
4034 r = state;
4035 goto finish;
4036 }
ee5762e3 4037
729e3769
LP
4038 if (state == UNIT_FILE_ENABLED ||
4039 state == UNIT_FILE_ENABLED_RUNTIME ||
4040 state == UNIT_FILE_STATIC)
4041 enabled = true;
4042
4043 if (!arg_quiet)
4044 puts(unit_file_state_to_string(state));
71fad675 4045 }
ee5762e3 4046
729e3769
LP
4047 } else {
4048 STRV_FOREACH(name, args+1) {
4049 const char *s;
63a723f3 4050
729e3769
LP
4051 m = dbus_message_new_method_call(
4052 "org.freedesktop.systemd1",
4053 "/org/freedesktop/systemd1",
4054 "org.freedesktop.systemd1.Manager",
4055 "GetUnitFileState");
4056 if (!m) {
4057 log_error("Out of memory");
4058 r = -ENOMEM;
4059 goto finish;
4060 }
ee5762e3 4061
729e3769
LP
4062 if (!dbus_message_append_args(m,
4063 DBUS_TYPE_STRING, name,
4064 DBUS_TYPE_INVALID)) {
4065 log_error("Could not append arguments to message.");
4066 r = -ENOMEM;
4067 goto finish;
4068 }
ee5762e3 4069
729e3769
LP
4070 reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
4071 if (!reply) {
4072 log_error("Failed to issue method call: %s", bus_error_message(&error));
4073 r = -EIO;
4074 goto finish;
4075 }
ee5762e3 4076
729e3769
LP
4077 if (!dbus_message_get_args(reply, &error,
4078 DBUS_TYPE_STRING, &s,
4079 DBUS_TYPE_INVALID)) {
4080 log_error("Failed to parse reply: %s", bus_error_message(&error));
4081 r = -EIO;
ee5762e3
LP
4082 goto finish;
4083 }
4084
729e3769
LP
4085 dbus_message_unref(m);
4086 dbus_message_unref(reply);
4087 m = reply = NULL;
ee5762e3 4088
729e3769
LP
4089 if (streq(s, "enabled") ||
4090 streq(s, "enabled-runtime") ||
4091 streq(s, "static"))
4092 enabled = true;
4093
4094 if (!arg_quiet)
4095 puts(s);
560d8f23 4096 }
ee5762e3
LP
4097 }
4098
729e3769 4099 r = enabled ? 0 : 1;
ee5762e3 4100
729e3769
LP
4101finish:
4102 if (m)
4103 dbus_message_unref(m);
ee5762e3 4104
729e3769
LP
4105 if (reply)
4106 dbus_message_unref(reply);
ee5762e3 4107
729e3769 4108 dbus_error_free(&error);
ee5762e3
LP
4109 return r;
4110}
4111
e4b61340 4112static int systemctl_help(void) {
7e4249b9 4113
729e3769
LP
4114 pager_open_if_enabled();
4115
2e33c433 4116 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
729e3769 4117 "Query or send control commands to the systemd manager.\n\n"
8a0867d6
LP
4118 " -h --help Show this help\n"
4119 " --version Show package version\n"
4120 " -t --type=TYPE List only units of a particular type\n"
4121 " -p --property=NAME Show only properties by this name\n"
4122 " -a --all Show all units/properties, including dead/empty ones\n"
30732560 4123 " --failed Show only failed units\n"
8a0867d6
LP
4124 " --full Don't ellipsize unit names on output\n"
4125 " --fail When queueing a new job, fail if conflicting jobs are\n"
4126 " pending\n"
e67c3609
LP
4127 " --ignore-dependencies\n"
4128 " When queueing a new job, ignore all its dependencies\n"
a8f11321
LP
4129 " --kill-who=WHO Who to send signal to\n"
4130 " -s --signal=SIGNAL Which signal to send\n"
aca4c786 4131 " -H --host=[USER@]HOST\n"
a8f11321
LP
4132 " Show information for remote host\n"
4133 " -P --privileged Acquire privileges before execution\n"
8a0867d6
LP
4134 " -q --quiet Suppress output\n"
4135 " --no-block Do not wait until operation finished\n"
8a0867d6 4136 " --no-wall Don't send wall message before halt/power-off/reboot\n"
8a0867d6
LP
4137 " --no-reload When enabling/disabling unit files, don't reload daemon\n"
4138 " configuration\n"
ebed32bf 4139 " --no-legend Do not print a legend (column headers and hints)\n"
69fc152f 4140 " --no-pager Do not pipe output into a pager\n"
501fc174
LP
4141 " --no-ask-password\n"
4142 " Do not ask for system passwords\n"
a8f11321
LP
4143 " --order When generating graph for dot, show only order\n"
4144 " --require When generating graph for dot, show only requirement\n"
4145 " --system Connect to system manager\n"
4146 " --user Connect to user service manager\n"
4147 " --global Enable/disable unit files globally\n"
8a0867d6
LP
4148 " -f --force When enabling unit files, override existing symlinks\n"
4149 " When shutting down, execute action immediately\n"
729e3769 4150 " --root=PATH Enable unit files in the specified root directory\n"
df50185b
LP
4151 " --runtime Enable unit files only temporarily until next reboot\n"
4152 " -n --lines=INTEGER Journal entries to show\n"
4153 " --follow Follow journal\n"
d3f2bdbf
LP
4154 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
4155 " verbose, export, json, cat)\n\n"
34c4b47b 4156 "Unit Commands:\n"
729e3769 4157 " list-units List loaded units\n"
ee5762e3
LP
4158 " start [NAME...] Start (activate) one or more units\n"
4159 " stop [NAME...] Stop (deactivate) one or more units\n"
7e4249b9 4160 " reload [NAME...] Reload one or more units\n"
6f28c033
LP
4161 " restart [NAME...] Start or restart one or more units\n"
4162 " try-restart [NAME...] Restart one or more units if active\n"
4163 " reload-or-restart [NAME...] Reload one or more units is possible,\n"
4164 " otherwise start or restart\n"
4165 " reload-or-try-restart [NAME...] Reload one or more units is possible,\n"
4166 " otherwise restart if active\n"
7e4249b9 4167 " isolate [NAME] Start one unit and stop all others\n"
8a0867d6 4168 " kill [NAME...] Send signal to processes of a unit\n"
ee5762e3 4169 " is-active [NAME...] Check whether units are active\n"
75676b72 4170 " status [NAME...|PID...] Show runtime status of one or more units\n"
6f28c033 4171 " show [NAME...|JOB...] Show properties of one or more\n"
ee5762e3 4172 " units/jobs or the manager\n"
fdf20a31
MM
4173 " reset-failed [NAME...] Reset failed state for all, one, or more\n"
4174 " units\n"
34c4b47b
LP
4175 " load [NAME...] Load one or more units\n\n"
4176 "Unit File Commands:\n"
729e3769 4177 " list-unit-files List installed unit files\n"
ee5762e3
LP
4178 " enable [NAME...] Enable one or more unit files\n"
4179 " disable [NAME...] Disable one or more unit files\n"
729e3769
LP
4180 " reenable [NAME...] Reenable one or more unit files\n"
4181 " preset [NAME...] Enable/disable one or more unit files\n"
4182 " based on preset configuration\n"
4183 " mask [NAME...] Mask one or more units\n"
4184 " unmask [NAME...] Unmask one or more units\n"
4185 " link [PATH...] Link one or more units files into\n"
4186 " the search path\n"
34c4b47b
LP
4187 " is-enabled [NAME...] Check whether unit files are enabled\n\n"
4188 "Job Commands:\n"
48220598 4189 " list-jobs List jobs\n"
34c4b47b
LP
4190 " cancel [JOB...] Cancel all, one, or more jobs\n\n"
4191 "Status Commands:\n"
7e4249b9 4192 " dump Dump server status\n"
34c4b47b
LP
4193 " dot Dump dependency graph for dot(1)\n\n"
4194 "Snapshot Commands:\n"
7e4249b9 4195 " snapshot [NAME] Create a snapshot\n"
34c4b47b
LP
4196 " delete [NAME...] Remove one or more snapshots\n\n"
4197 "Environment Commands:\n"
7e4249b9
LP
4198 " show-environment Dump environment\n"
4199 " set-environment [NAME=VALUE...] Set one or more environment variables\n"
34c4b47b
LP
4200 " unset-environment [NAME...] Unset one or more environment variables\n\n"
4201 "Manager Lifecycle Commands:\n"
4202 " daemon-reload Reload systemd manager configuration\n"
4203 " daemon-reexec Reexecute systemd manager\n\n"
4204 "System Commands:\n"
20b09ca7
LP
4205 " default Enter system default mode\n"
4206 " rescue Enter system rescue mode\n"
4207 " emergency Enter system emergency mode\n"
514f4ef5 4208 " halt Shut down and halt the system\n"
2e33c433 4209 " poweroff Shut down and power-off the system\n"
514f4ef5 4210 " reboot Shut down and reboot the system\n"
20b09ca7 4211 " kexec Shut down and reboot the system with kexec\n"
6edd7d0a
LP
4212 " exit Request user instance exit\n"
4213 " suspend Suspend the system\n"
4214 " hibernate Hibernate the system\n",
5b6319dc 4215 program_invocation_short_name);
7e4249b9
LP
4216
4217 return 0;
4218}
4219
e4b61340
LP
4220static int halt_help(void) {
4221
2e33c433 4222 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4223 "%s the system.\n\n"
4224 " --help Show this help\n"
4225 " --halt Halt the machine\n"
4226 " -p --poweroff Switch off the machine\n"
4227 " --reboot Reboot the machine\n"
2e33c433
LP
4228 " -f --force Force immediate halt/power-off/reboot\n"
4229 " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n"
e4b61340 4230 " -d --no-wtmp Don't write wtmp record\n"
2e33c433
LP
4231 " -n --no-sync Don't sync before halt/power-off/reboot\n"
4232 " --no-wall Don't send wall message before halt/power-off/reboot\n",
e4b61340
LP
4233 program_invocation_short_name,
4234 arg_action == ACTION_REBOOT ? "Reboot" :
4235 arg_action == ACTION_POWEROFF ? "Power off" :
4236 "Halt");
4237
4238 return 0;
4239}
4240
4241static int shutdown_help(void) {
4242
08e4b1c5 4243 printf("%s [OPTIONS...] [TIME] [WALL...]\n\n"
e4b61340
LP
4244 "Shut down the system.\n\n"
4245 " --help Show this help\n"
4246 " -H --halt Halt the machine\n"
4247 " -P --poweroff Power-off the machine\n"
4248 " -r --reboot Reboot the machine\n"
4249 " -h Equivalent to --poweroff, overriden by --halt\n"
2e33c433 4250 " -k Don't halt/power-off/reboot, just send warnings\n"
f6144808 4251 " --no-wall Don't send wall message before halt/power-off/reboot\n"
f6144808 4252 " -c Cancel a pending shutdown\n",
e4b61340
LP
4253 program_invocation_short_name);
4254
4255 return 0;
4256}
4257
4258static int telinit_help(void) {
4259
2e33c433 4260 printf("%s [OPTIONS...] {COMMAND}\n\n"
514f4ef5
LP
4261 "Send control commands to the init daemon.\n\n"
4262 " --help Show this help\n"
2e33c433 4263 " --no-wall Don't send wall message before halt/power-off/reboot\n\n"
e4b61340
LP
4264 "Commands:\n"
4265 " 0 Power-off the machine\n"
4266 " 6 Reboot the machine\n"
514f4ef5
LP
4267 " 2, 3, 4, 5 Start runlevelX.target unit\n"
4268 " 1, s, S Enter rescue mode\n"
4269 " q, Q Reload init daemon configuration\n"
4270 " u, U Reexecute init daemon\n",
e4b61340
LP
4271 program_invocation_short_name);
4272
4273 return 0;
4274}
4275
4276static int runlevel_help(void) {
4277
2e33c433 4278 printf("%s [OPTIONS...]\n\n"
e4b61340
LP
4279 "Prints the previous and current runlevel of the init system.\n\n"
4280 " --help Show this help\n",
4281 program_invocation_short_name);
4282
4283 return 0;
4284}
4285
4286static int systemctl_parse_argv(int argc, char *argv[]) {
7e4249b9
LP
4287
4288 enum {
90d473a1 4289 ARG_FAIL = 0x100,
e67c3609 4290 ARG_IGNORE_DEPENDENCIES,
35df8f27 4291 ARG_VERSION,
af2d49f7 4292 ARG_USER,
7e4249b9 4293 ARG_SYSTEM,
ee5762e3 4294 ARG_GLOBAL,
6e905d93 4295 ARG_NO_BLOCK,
ebed32bf 4296 ARG_NO_LEGEND,
611efaac 4297 ARG_NO_PAGER,
4445a875
LP
4298 ARG_NO_WALL,
4299 ARG_ORDER,
8fe914ec 4300 ARG_REQUIRE,
be394c48 4301 ARG_ROOT,
ee5762e3 4302 ARG_FULL,
ee5762e3 4303 ARG_NO_RELOAD,
8a0867d6 4304 ARG_KILL_MODE,
501fc174 4305 ARG_KILL_WHO,
30732560 4306 ARG_NO_ASK_PASSWORD,
729e3769 4307 ARG_FAILED,
df50185b 4308 ARG_RUNTIME,
568b679f
LP
4309 ARG_FOLLOW,
4310 ARG_FORCE
7e4249b9
LP
4311 };
4312
4313 static const struct option options[] = {
ee5762e3 4314 { "help", no_argument, NULL, 'h' },
35df8f27 4315 { "version", no_argument, NULL, ARG_VERSION },
ee5762e3
LP
4316 { "type", required_argument, NULL, 't' },
4317 { "property", required_argument, NULL, 'p' },
4318 { "all", no_argument, NULL, 'a' },
30732560 4319 { "failed", no_argument, NULL, ARG_FAILED },
ee5762e3
LP
4320 { "full", no_argument, NULL, ARG_FULL },
4321 { "fail", no_argument, NULL, ARG_FAIL },
e67c3609 4322 { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
af2d49f7 4323 { "user", no_argument, NULL, ARG_USER },
ee5762e3
LP
4324 { "system", no_argument, NULL, ARG_SYSTEM },
4325 { "global", no_argument, NULL, ARG_GLOBAL },
4326 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
ebed32bf 4327 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
0736af98 4328 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
ee5762e3
LP
4329 { "no-wall", no_argument, NULL, ARG_NO_WALL },
4330 { "quiet", no_argument, NULL, 'q' },
4331 { "order", no_argument, NULL, ARG_ORDER },
4332 { "require", no_argument, NULL, ARG_REQUIRE },
be394c48 4333 { "root", required_argument, NULL, ARG_ROOT },
568b679f 4334 { "force", no_argument, NULL, ARG_FORCE },
ee5762e3 4335 { "no-reload", no_argument, NULL, ARG_NO_RELOAD },
69fc152f 4336 { "kill-mode", required_argument, NULL, ARG_KILL_MODE }, /* undocumented on purpose */
8a0867d6
LP
4337 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
4338 { "signal", required_argument, NULL, 's' },
501fc174 4339 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
a8f11321
LP
4340 { "host", required_argument, NULL, 'H' },
4341 { "privileged",no_argument, NULL, 'P' },
729e3769 4342 { "runtime", no_argument, NULL, ARG_RUNTIME },
df50185b
LP
4343 { "lines", required_argument, NULL, 'n' },
4344 { "follow", no_argument, NULL, ARG_FOLLOW },
4345 { "output", required_argument, NULL, 'o' },
ee5762e3 4346 { NULL, 0, NULL, 0 }
7e4249b9
LP
4347 };
4348
4349 int c;
4350
e4b61340 4351 assert(argc >= 0);
7e4249b9
LP
4352 assert(argv);
4353
df50185b 4354 while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:Pn:o:", options, NULL)) >= 0) {
7e4249b9
LP
4355
4356 switch (c) {
4357
4358 case 'h':
e4b61340 4359 systemctl_help();
7e4249b9 4360 return 0;
35df8f27
LP
4361
4362 case ARG_VERSION:
4363 puts(PACKAGE_STRING);
7d568925
LP
4364 puts(DISTRIBUTION);
4365 puts(SYSTEMD_FEATURES);
35df8f27 4366 return 0;
7e4249b9
LP
4367
4368 case 't':
4369 arg_type = optarg;
4370 break;
4371
ea4a240d
LP
4372 case 'p': {
4373 char **l;
4374
4375 if (!(l = strv_append(arg_property, optarg)))
4376 return -ENOMEM;
4377
4378 strv_free(arg_property);
4379 arg_property = l;
48220598
LP
4380
4381 /* If the user asked for a particular
4382 * property, show it to him, even if it is
4383 * empty. */
4384 arg_all = true;
4385 break;
ea4a240d 4386 }
48220598 4387
7e4249b9
LP
4388 case 'a':
4389 arg_all = true;
4390 break;
4391
90d473a1 4392 case ARG_FAIL:
e67c3609
LP
4393 arg_job_mode = "fail";
4394 break;
4395
4396 case ARG_IGNORE_DEPENDENCIES:
4397 arg_job_mode = "ignore-dependencies";
7e4249b9
LP
4398 break;
4399
af2d49f7 4400 case ARG_USER:
729e3769 4401 arg_scope = UNIT_FILE_USER;
7e4249b9
LP
4402 break;
4403
4404 case ARG_SYSTEM:
729e3769
LP
4405 arg_scope = UNIT_FILE_SYSTEM;
4406 break;
4407
4408 case ARG_GLOBAL:
4409 arg_scope = UNIT_FILE_GLOBAL;
7e4249b9
LP
4410 break;
4411
6e905d93
LP
4412 case ARG_NO_BLOCK:
4413 arg_no_block = true;
7e4249b9
LP
4414 break;
4415
ebed32bf
MS
4416 case ARG_NO_LEGEND:
4417 arg_no_legend = true;
4418 break;
4419
611efaac
LP
4420 case ARG_NO_PAGER:
4421 arg_no_pager = true;
4422 break;
0736af98 4423
514f4ef5
LP
4424 case ARG_NO_WALL:
4425 arg_no_wall = true;
4426 break;
4427
4445a875
LP
4428 case ARG_ORDER:
4429 arg_dot = DOT_ORDER;
4430 break;
4431
4432 case ARG_REQUIRE:
4433 arg_dot = DOT_REQUIRE;
4434 break;
4435
be394c48
FC
4436 case ARG_ROOT:
4437 arg_root = optarg;
4438 break;
4439
8fe914ec
LP
4440 case ARG_FULL:
4441 arg_full = true;
4442 break;
4443
30732560
LP
4444 case ARG_FAILED:
4445 arg_failed = true;
4446 break;
4447
0183528f
LP
4448 case 'q':
4449 arg_quiet = true;
4450 break;
4451
568b679f
LP
4452 case ARG_FORCE:
4453 arg_force ++;
4454 break;
4455
4456 case ARG_FOLLOW:
4457 arg_follow = true;
4458 break;
4459
b4f27ccc 4460 case 'f':
568b679f 4461 /* -f is short for both --follow and --force! */
e606bb61 4462 arg_force ++;
568b679f 4463 arg_follow = true;
ee5762e3
LP
4464 break;
4465
4466 case ARG_NO_RELOAD:
4467 arg_no_reload = true;
4468 break;
4469
8a0867d6
LP
4470 case ARG_KILL_WHO:
4471 arg_kill_who = optarg;
4472 break;
4473
4474 case ARG_KILL_MODE:
4475 arg_kill_mode = optarg;
4476 break;
4477
4478 case 's':
4479 if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
4480 log_error("Failed to parse signal string %s.", optarg);
4481 return -EINVAL;
4482 }
4483 break;
4484
501fc174
LP
4485 case ARG_NO_ASK_PASSWORD:
4486 arg_ask_password = false;
4487 break;
4488
a8f11321
LP
4489 case 'P':
4490 arg_transport = TRANSPORT_POLKIT;
4491 break;
4492
4493 case 'H':
4494 arg_transport = TRANSPORT_SSH;
4495 arg_host = optarg;
4496 break;
4497
729e3769
LP
4498 case ARG_RUNTIME:
4499 arg_runtime = true;
4500 break;
4501
df50185b
LP
4502 case 'n':
4503 if (safe_atou(optarg, &arg_lines) < 0) {
4504 log_error("Failed to parse lines '%s'", optarg);
4505 return -EINVAL;
4506 }
4507 break;
4508
df50185b
LP
4509 case 'o':
4510 arg_output = output_mode_from_string(optarg);
4511 if (arg_output < 0) {
4512 log_error("Unknown output '%s'.", optarg);
4513 return -EINVAL;
4514 }
4515 break;
4516
7e4249b9
LP
4517 case '?':
4518 return -EINVAL;
4519
4520 default:
4521 log_error("Unknown option code %c", c);
4522 return -EINVAL;
4523 }
4524 }
4525
729e3769 4526 if (arg_transport != TRANSPORT_NORMAL && arg_scope != UNIT_FILE_SYSTEM) {
a8f11321
LP
4527 log_error("Cannot access user instance remotely.");
4528 return -EINVAL;
4529 }
4530
7e4249b9
LP
4531 return 1;
4532}
4533
e4b61340
LP
4534static int halt_parse_argv(int argc, char *argv[]) {
4535
4536 enum {
4537 ARG_HELP = 0x100,
4538 ARG_HALT,
514f4ef5
LP
4539 ARG_REBOOT,
4540 ARG_NO_WALL
e4b61340
LP
4541 };
4542
4543 static const struct option options[] = {
4544 { "help", no_argument, NULL, ARG_HELP },
4545 { "halt", no_argument, NULL, ARG_HALT },
4546 { "poweroff", no_argument, NULL, 'p' },
4547 { "reboot", no_argument, NULL, ARG_REBOOT },
4548 { "force", no_argument, NULL, 'f' },
4549 { "wtmp-only", no_argument, NULL, 'w' },
4550 { "no-wtmp", no_argument, NULL, 'd' },
4551 { "no-sync", no_argument, NULL, 'n' },
514f4ef5 4552 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
4553 { NULL, 0, NULL, 0 }
4554 };
4555
4556 int c, runlevel;
4557
4558 assert(argc >= 0);
4559 assert(argv);
4560
4561 if (utmp_get_runlevel(&runlevel, NULL) >= 0)
4562 if (runlevel == '0' || runlevel == '6')
65491fd8 4563 arg_force = 2;
e4b61340
LP
4564
4565 while ((c = getopt_long(argc, argv, "pfwdnih", options, NULL)) >= 0) {
4566 switch (c) {
4567
4568 case ARG_HELP:
4569 halt_help();
4570 return 0;
4571
4572 case ARG_HALT:
4573 arg_action = ACTION_HALT;
4574 break;
4575
4576 case 'p':
a042efad
MS
4577 if (arg_action != ACTION_REBOOT)
4578 arg_action = ACTION_POWEROFF;
e4b61340
LP
4579 break;
4580
4581 case ARG_REBOOT:
4582 arg_action = ACTION_REBOOT;
4583 break;
4584
4585 case 'f':
65491fd8 4586 arg_force = 2;
e4b61340
LP
4587 break;
4588
4589 case 'w':
4590 arg_dry = true;
4591 break;
4592
4593 case 'd':
4594 arg_no_wtmp = true;
4595 break;
4596
4597 case 'n':
4598 arg_no_sync = true;
4599 break;
4600
514f4ef5
LP
4601 case ARG_NO_WALL:
4602 arg_no_wall = true;
4603 break;
4604
e4b61340
LP
4605 case 'i':
4606 case 'h':
4607 /* Compatibility nops */
4608 break;
4609
4610 case '?':
4611 return -EINVAL;
4612
4613 default:
4614 log_error("Unknown option code %c", c);
4615 return -EINVAL;
4616 }
4617 }
4618
4619 if (optind < argc) {
4620 log_error("Too many arguments.");
4621 return -EINVAL;
4622 }
4623
4624 return 1;
4625}
4626
f6144808
LP
4627static int parse_time_spec(const char *t, usec_t *_u) {
4628 assert(t);
4629 assert(_u);
4630
4631 if (streq(t, "now"))
4632 *_u = 0;
1a639877 4633 else if (!strchr(t, ':')) {
f6144808
LP
4634 uint64_t u;
4635
1a639877 4636 if (safe_atou64(t, &u) < 0)
f6144808
LP
4637 return -EINVAL;
4638
4639 *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
4640 } else {
4641 char *e = NULL;
4642 long hour, minute;
4643 struct tm tm;
4644 time_t s;
4645 usec_t n;
4646
4647 errno = 0;
4648 hour = strtol(t, &e, 10);
4649 if (errno != 0 || *e != ':' || hour < 0 || hour > 23)
4650 return -EINVAL;
4651
4652 minute = strtol(e+1, &e, 10);
4653 if (errno != 0 || *e != 0 || minute < 0 || minute > 59)
4654 return -EINVAL;
4655
4656 n = now(CLOCK_REALTIME);
08e4b1c5
LP
4657 s = (time_t) (n / USEC_PER_SEC);
4658
4659 zero(tm);
f6144808
LP
4660 assert_se(localtime_r(&s, &tm));
4661
4662 tm.tm_hour = (int) hour;
4663 tm.tm_min = (int) minute;
08e4b1c5 4664 tm.tm_sec = 0;
f6144808
LP
4665
4666 assert_se(s = mktime(&tm));
4667
4668 *_u = (usec_t) s * USEC_PER_SEC;
4669
4670 while (*_u <= n)
4671 *_u += USEC_PER_DAY;
4672 }
4673
4674 return 0;
4675}
4676
e4b61340
LP
4677static int shutdown_parse_argv(int argc, char *argv[]) {
4678
4679 enum {
4680 ARG_HELP = 0x100,
514f4ef5 4681 ARG_NO_WALL
e4b61340
LP
4682 };
4683
4684 static const struct option options[] = {
4685 { "help", no_argument, NULL, ARG_HELP },
4686 { "halt", no_argument, NULL, 'H' },
4687 { "poweroff", no_argument, NULL, 'P' },
4688 { "reboot", no_argument, NULL, 'r' },
04ebb595 4689 { "kexec", no_argument, NULL, 'K' }, /* not documented extension */
514f4ef5 4690 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
4691 { NULL, 0, NULL, 0 }
4692 };
4693
f6144808 4694 int c, r;
e4b61340
LP
4695
4696 assert(argc >= 0);
4697 assert(argv);
4698
f6144808 4699 while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0) {
e4b61340
LP
4700 switch (c) {
4701
4702 case ARG_HELP:
4703 shutdown_help();
4704 return 0;
4705
4706 case 'H':
4707 arg_action = ACTION_HALT;
4708 break;
4709
4710 case 'P':
4711 arg_action = ACTION_POWEROFF;
4712 break;
4713
4714 case 'r':
5622dde3
KS
4715 if (kexec_loaded())
4716 arg_action = ACTION_KEXEC;
4717 else
4718 arg_action = ACTION_REBOOT;
e4b61340
LP
4719 break;
4720
04ebb595
LP
4721 case 'K':
4722 arg_action = ACTION_KEXEC;
4723 break;
4724
e4b61340
LP
4725 case 'h':
4726 if (arg_action != ACTION_HALT)
4727 arg_action = ACTION_POWEROFF;
4728 break;
4729
4730 case 'k':
4731 arg_dry = true;
4732 break;
4733
514f4ef5
LP
4734 case ARG_NO_WALL:
4735 arg_no_wall = true;
4736 break;
4737
e4b61340
LP
4738 case 't':
4739 case 'a':
4740 /* Compatibility nops */
4741 break;
4742
f6144808
LP
4743 case 'c':
4744 arg_action = ACTION_CANCEL_SHUTDOWN;
4745 break;
4746
e4b61340
LP
4747 case '?':
4748 return -EINVAL;
4749
4750 default:
4751 log_error("Unknown option code %c", c);
4752 return -EINVAL;
4753 }
4754 }
4755
6b5ad000 4756 if (argc > optind) {
7e59bfcb
LP
4757 r = parse_time_spec(argv[optind], &arg_when);
4758 if (r < 0) {
f6144808
LP
4759 log_error("Failed to parse time specification: %s", argv[optind]);
4760 return r;
4761 }
6b5ad000 4762 } else
08e4b1c5 4763 arg_when = now(CLOCK_REALTIME) + USEC_PER_MINUTE;
442b9094 4764
f6144808 4765 /* We skip the time argument */
e4b61340
LP
4766 if (argc > optind + 1)
4767 arg_wall = argv + optind + 1;
4768
4769 optind = argc;
4770
4771 return 1;
e4b61340
LP
4772}
4773
4774static int telinit_parse_argv(int argc, char *argv[]) {
4775
4776 enum {
4777 ARG_HELP = 0x100,
514f4ef5 4778 ARG_NO_WALL
e4b61340
LP
4779 };
4780
4781 static const struct option options[] = {
4782 { "help", no_argument, NULL, ARG_HELP },
514f4ef5 4783 { "no-wall", no_argument, NULL, ARG_NO_WALL },
e4b61340
LP
4784 { NULL, 0, NULL, 0 }
4785 };
4786
4787 static const struct {
4788 char from;
4789 enum action to;
4790 } table[] = {
4791 { '0', ACTION_POWEROFF },
4792 { '6', ACTION_REBOOT },
ef2f1067 4793 { '1', ACTION_RESCUE },
e4b61340
LP
4794 { '2', ACTION_RUNLEVEL2 },
4795 { '3', ACTION_RUNLEVEL3 },
4796 { '4', ACTION_RUNLEVEL4 },
4797 { '5', ACTION_RUNLEVEL5 },
4798 { 's', ACTION_RESCUE },
4799 { 'S', ACTION_RESCUE },
4800 { 'q', ACTION_RELOAD },
4801 { 'Q', ACTION_RELOAD },
4802 { 'u', ACTION_REEXEC },
4803 { 'U', ACTION_REEXEC }
4804 };
4805
4806 unsigned i;
4807 int c;
4808
4809 assert(argc >= 0);
4810 assert(argv);
4811
4812 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4813 switch (c) {
4814
4815 case ARG_HELP:
4816 telinit_help();
4817 return 0;
4818
514f4ef5
LP
4819 case ARG_NO_WALL:
4820 arg_no_wall = true;
4821 break;
4822
e4b61340
LP
4823 case '?':
4824 return -EINVAL;
4825
4826 default:
4827 log_error("Unknown option code %c", c);
4828 return -EINVAL;
4829 }
4830 }
4831
4832 if (optind >= argc) {
2f02ce40 4833 telinit_help();
e4b61340
LP
4834 return -EINVAL;
4835 }
4836
4837 if (optind + 1 < argc) {
4838 log_error("Too many arguments.");
4839 return -EINVAL;
4840 }
4841
4842 if (strlen(argv[optind]) != 1) {
4843 log_error("Expected single character argument.");
4844 return -EINVAL;
4845 }
4846
4847 for (i = 0; i < ELEMENTSOF(table); i++)
4848 if (table[i].from == argv[optind][0])
4849 break;
4850
4851 if (i >= ELEMENTSOF(table)) {
4852 log_error("Unknown command %s.", argv[optind]);
4853 return -EINVAL;
4854 }
4855
4856 arg_action = table[i].to;
4857
4858 optind ++;
4859
4860 return 1;
4861}
4862
4863static int runlevel_parse_argv(int argc, char *argv[]) {
4864
4865 enum {
4866 ARG_HELP = 0x100,
4867 };
4868
4869 static const struct option options[] = {
4870 { "help", no_argument, NULL, ARG_HELP },
4871 { NULL, 0, NULL, 0 }
4872 };
4873
4874 int c;
4875
4876 assert(argc >= 0);
4877 assert(argv);
4878
4879 while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) {
4880 switch (c) {
4881
4882 case ARG_HELP:
4883 runlevel_help();
4884 return 0;
4885
4886 case '?':
4887 return -EINVAL;
4888
4889 default:
4890 log_error("Unknown option code %c", c);
4891 return -EINVAL;
4892 }
4893 }
4894
4895 if (optind < argc) {
4896 log_error("Too many arguments.");
4897 return -EINVAL;
4898 }
4899
4900 return 1;
4901}
4902
4903static int parse_argv(int argc, char *argv[]) {
4904 assert(argc >= 0);
4905 assert(argv);
4906
4907 if (program_invocation_short_name) {
4908
4909 if (strstr(program_invocation_short_name, "halt")) {
4910 arg_action = ACTION_HALT;
4911 return halt_parse_argv(argc, argv);
4912 } else if (strstr(program_invocation_short_name, "poweroff")) {
4913 arg_action = ACTION_POWEROFF;
4914 return halt_parse_argv(argc, argv);
4915 } else if (strstr(program_invocation_short_name, "reboot")) {
5622dde3
KS
4916 if (kexec_loaded())
4917 arg_action = ACTION_KEXEC;
4918 else
4919 arg_action = ACTION_REBOOT;
e4b61340
LP
4920 return halt_parse_argv(argc, argv);
4921 } else if (strstr(program_invocation_short_name, "shutdown")) {
4922 arg_action = ACTION_POWEROFF;
4923 return shutdown_parse_argv(argc, argv);
4924 } else if (strstr(program_invocation_short_name, "init")) {
d5ca5f11
LP
4925
4926 if (sd_booted() > 0) {
4927 arg_action = ACTION_INVALID;
4928 return telinit_parse_argv(argc, argv);
4929 } else {
4930 /* Hmm, so some other init system is
4931 * running, we need to forward this
4932 * request to it. For now we simply
4933 * guess that it is Upstart. */
4934
4935 execv("/lib/upstart/telinit", argv);
4936
4937 log_error("Couldn't find an alternative telinit implementation to spawn.");
4938 return -EIO;
4939 }
4940
e4b61340
LP
4941 } else if (strstr(program_invocation_short_name, "runlevel")) {
4942 arg_action = ACTION_RUNLEVEL;
4943 return runlevel_parse_argv(argc, argv);
4944 }
4945 }
4946
4947 arg_action = ACTION_SYSTEMCTL;
4948 return systemctl_parse_argv(argc, argv);
4949}
4950
d55ae9e6 4951static int action_to_runlevel(void) {
eb22ac37
LP
4952
4953 static const char table[_ACTION_MAX] = {
4954 [ACTION_HALT] = '0',
4955 [ACTION_POWEROFF] = '0',
4956 [ACTION_REBOOT] = '6',
4957 [ACTION_RUNLEVEL2] = '2',
4958 [ACTION_RUNLEVEL3] = '3',
4959 [ACTION_RUNLEVEL4] = '4',
4960 [ACTION_RUNLEVEL5] = '5',
4961 [ACTION_RESCUE] = '1'
4962 };
4963
d55ae9e6
LP
4964 assert(arg_action < _ACTION_MAX);
4965
4966 return table[arg_action];
4967}
4968
f1c5860b 4969static int talk_upstart(void) {
d55ae9e6
LP
4970 DBusMessage *m = NULL, *reply = NULL;
4971 DBusError error;
4972 int previous, rl, r;
4973 char
4974 env1_buf[] = "RUNLEVEL=X",
4975 env2_buf[] = "PREVLEVEL=X";
4976 char *env1 = env1_buf, *env2 = env2_buf;
4977 const char *emit = "runlevel";
4978 dbus_bool_t b_false = FALSE;
4979 DBusMessageIter iter, sub;
f1c5860b 4980 DBusConnection *bus;
d55ae9e6
LP
4981
4982 dbus_error_init(&error);
4983
4984 if (!(rl = action_to_runlevel()))
4985 return 0;
4986
4987 if (utmp_get_runlevel(&previous, NULL) < 0)
4988 previous = 'N';
4989
b574246b 4990 if (!(bus = dbus_connection_open_private("unix:abstract=/com/ubuntu/upstart", &error))) {
f1c5860b
LP
4991 if (dbus_error_has_name(&error, DBUS_ERROR_NO_SERVER)) {
4992 r = 0;
4993 goto finish;
4994 }
4995
4cf5d675 4996 log_error("Failed to connect to Upstart bus: %s", bus_error_message(&error));
f1c5860b
LP
4997 r = -EIO;
4998 goto finish;
4999 }
5000
5001 if ((r = bus_check_peercred(bus)) < 0) {
5002 log_error("Failed to verify owner of bus.");
5003 goto finish;
5004 }
5005
d55ae9e6
LP
5006 if (!(m = dbus_message_new_method_call(
5007 "com.ubuntu.Upstart",
5008 "/com/ubuntu/Upstart",
5009 "com.ubuntu.Upstart0_6",
5010 "EmitEvent"))) {
5011
5012 log_error("Could not allocate message.");
f1c5860b
LP
5013 r = -ENOMEM;
5014 goto finish;
d55ae9e6
LP
5015 }
5016
5017 dbus_message_iter_init_append(m, &iter);
5018
5019 env1_buf[sizeof(env1_buf)-2] = rl;
5020 env2_buf[sizeof(env2_buf)-2] = previous;
5021
5022 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &emit) ||
5023 !dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub) ||
5024 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env1) ||
5025 !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &env2) ||
5026 !dbus_message_iter_close_container(&iter, &sub) ||
5027 !dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b_false)) {
5028 log_error("Could not append arguments to message.");
5029 r = -ENOMEM;
5030 goto finish;
5031 }
5032
5033 if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
5034
5035 if (error_is_no_service(&error)) {
aabd9b11 5036 r = -EADDRNOTAVAIL;
d55ae9e6
LP
5037 goto finish;
5038 }
5039
4cf5d675 5040 log_error("Failed to issue method call: %s", bus_error_message(&error));
d55ae9e6
LP
5041 r = -EIO;
5042 goto finish;
5043 }
5044
0a55b298 5045 r = 1;
d55ae9e6
LP
5046
5047finish:
5048 if (m)
5049 dbus_message_unref(m);
5050
5051 if (reply)
5052 dbus_message_unref(reply);
5053
b574246b 5054 if (bus) {
5d452f9c 5055 dbus_connection_flush(bus);
b574246b 5056 dbus_connection_close(bus);
f1c5860b 5057 dbus_connection_unref(bus);
b574246b 5058 }
f1c5860b 5059
d55ae9e6
LP
5060 dbus_error_free(&error);
5061
5062 return r;
5063}
5064
5065static int talk_initctl(void) {
eb22ac37
LP
5066 struct init_request request;
5067 int r, fd;
d55ae9e6 5068 char rl;
eb22ac37 5069
d55ae9e6 5070 if (!(rl = action_to_runlevel()))
eb22ac37
LP
5071 return 0;
5072
5073 zero(request);
5074 request.magic = INIT_MAGIC;
5075 request.sleeptime = 0;
5076 request.cmd = INIT_CMD_RUNLVL;
d55ae9e6
LP
5077 request.runlevel = rl;
5078
5079 if ((fd = open(INIT_FIFO, O_WRONLY|O_NDELAY|O_CLOEXEC|O_NOCTTY)) < 0) {
5080
5081 if (errno == ENOENT)
5082 return 0;
eb22ac37 5083
d55ae9e6 5084 log_error("Failed to open "INIT_FIFO": %m");
eb22ac37 5085 return -errno;
d55ae9e6 5086 }
eb22ac37 5087
d55ae9e6 5088 errno = 0;
eb22ac37
LP
5089 r = loop_write(fd, &request, sizeof(request), false) != sizeof(request);
5090 close_nointr_nofail(fd);
5091
d55ae9e6
LP
5092 if (r < 0) {
5093 log_error("Failed to write to "INIT_FIFO": %m");
eb22ac37 5094 return errno ? -errno : -EIO;
d55ae9e6 5095 }
eb22ac37
LP
5096
5097 return 1;
e4b61340
LP
5098}
5099
ee5762e3 5100static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
7e4249b9 5101
7e4249b9
LP
5102 static const struct {
5103 const char* verb;
5104 const enum {
5105 MORE,
5106 LESS,
5107 EQUAL
5108 } argc_cmp;
5109 const int argc;
729e3769 5110 int (* const dispatch)(DBusConnection *bus, char **args);
7e4249b9 5111 } verbs[] = {
ee5762e3 5112 { "list-units", LESS, 1, list_units },
729e3769 5113 { "list-unit-files", EQUAL, 1, list_unit_files },
ee5762e3
LP
5114 { "list-jobs", EQUAL, 1, list_jobs },
5115 { "clear-jobs", EQUAL, 1, daemon_reload },
5116 { "load", MORE, 2, load_unit },
5117 { "cancel", MORE, 2, cancel_job },
5118 { "start", MORE, 2, start_unit },
5119 { "stop", MORE, 2, start_unit },
a76f7be2 5120 { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5121 { "reload", MORE, 2, start_unit },
5122 { "restart", MORE, 2, start_unit },
5123 { "try-restart", MORE, 2, start_unit },
5124 { "reload-or-restart", MORE, 2, start_unit },
5125 { "reload-or-try-restart", MORE, 2, start_unit },
5126 { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
64e5f1b7 5127 { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
ee5762e3
LP
5128 { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
5129 { "isolate", EQUAL, 2, start_unit },
8a0867d6 5130 { "kill", MORE, 2, kill_unit },
ee5762e3
LP
5131 { "is-active", MORE, 2, check_unit },
5132 { "check", MORE, 2, check_unit },
5133 { "show", MORE, 1, show },
5134 { "status", MORE, 2, show },
ee5762e3
LP
5135 { "dump", EQUAL, 1, dump },
5136 { "dot", EQUAL, 1, dot },
5137 { "snapshot", LESS, 2, snapshot },
5138 { "delete", MORE, 2, delete_snapshot },
5139 { "daemon-reload", EQUAL, 1, daemon_reload },
5140 { "daemon-reexec", EQUAL, 1, daemon_reload },
ee5762e3
LP
5141 { "show-environment", EQUAL, 1, show_enviroment },
5142 { "set-environment", MORE, 2, set_environment },
5143 { "unset-environment", MORE, 2, set_environment },
5144 { "halt", EQUAL, 1, start_special },
5145 { "poweroff", EQUAL, 1, start_special },
5146 { "reboot", EQUAL, 1, start_special },
20b09ca7 5147 { "kexec", EQUAL, 1, start_special },
6edd7d0a
LP
5148 { "suspend", EQUAL, 1, start_special },
5149 { "hibernate", EQUAL, 1, start_special },
ee5762e3
LP
5150 { "default", EQUAL, 1, start_special },
5151 { "rescue", EQUAL, 1, start_special },
5152 { "emergency", EQUAL, 1, start_special },
20b09ca7 5153 { "exit", EQUAL, 1, start_special },
fdf20a31 5154 { "reset-failed", MORE, 1, reset_failed },
ee5762e3
LP
5155 { "enable", MORE, 2, enable_unit },
5156 { "disable", MORE, 2, enable_unit },
729e3769
LP
5157 { "is-enabled", MORE, 2, unit_is_enabled },
5158 { "reenable", MORE, 2, enable_unit },
5159 { "preset", MORE, 2, enable_unit },
5160 { "mask", MORE, 2, enable_unit },
5161 { "unmask", MORE, 2, enable_unit },
5162 { "link", MORE, 2, enable_unit }
7e4249b9
LP
5163 };
5164
e4b61340 5165 int left;
7e4249b9 5166 unsigned i;
7e4249b9 5167
e4b61340
LP
5168 assert(argc >= 0);
5169 assert(argv);
ee5762e3 5170 assert(error);
7e4249b9
LP
5171
5172 left = argc - optind;
5173
5174 if (left <= 0)
5175 /* Special rule: no arguments means "list-units" */
5176 i = 0;
5177 else {
0183528f
LP
5178 if (streq(argv[optind], "help")) {
5179 systemctl_help();
5180 return 0;
5181 }
5182
7e4249b9
LP
5183 for (i = 0; i < ELEMENTSOF(verbs); i++)
5184 if (streq(argv[optind], verbs[i].verb))
5185 break;
5186
5187 if (i >= ELEMENTSOF(verbs)) {
5188 log_error("Unknown operation %s", argv[optind]);
e4b61340 5189 return -EINVAL;
7e4249b9
LP
5190 }
5191 }
5192
5193 switch (verbs[i].argc_cmp) {
5194
5195 case EQUAL:
5196 if (left != verbs[i].argc) {
5197 log_error("Invalid number of arguments.");
e4b61340 5198 return -EINVAL;
7e4249b9
LP
5199 }
5200
5201 break;
5202
5203 case MORE:
5204 if (left < verbs[i].argc) {
5205 log_error("Too few arguments.");
e4b61340 5206 return -EINVAL;
7e4249b9
LP
5207 }
5208
5209 break;
5210
5211 case LESS:
5212 if (left > verbs[i].argc) {
5213 log_error("Too many arguments.");
e4b61340 5214 return -EINVAL;
7e4249b9
LP
5215 }
5216
5217 break;
5218
5219 default:
5220 assert_not_reached("Unknown comparison operator.");
5221 }
5222
ee5762e3
LP
5223 /* Require a bus connection for all operations but
5224 * enable/disable */
729e3769
LP
5225 if (!streq(verbs[i].verb, "enable") &&
5226 !streq(verbs[i].verb, "disable") &&
c971700e 5227 !streq(verbs[i].verb, "is-enabled") &&
d380a3bc 5228 !streq(verbs[i].verb, "list-unit-files") &&
729e3769
LP
5229 !streq(verbs[i].verb, "reenable") &&
5230 !streq(verbs[i].verb, "preset") &&
5231 !streq(verbs[i].verb, "mask") &&
5232 !streq(verbs[i].verb, "unmask") &&
5233 !streq(verbs[i].verb, "link")) {
82e23ddd
LP
5234
5235 if (running_in_chroot() > 0) {
5236 log_info("Running in chroot, ignoring request.");
5237 return 0;
5238 }
5239
3beddc78 5240 if (((!streq(verbs[i].verb, "reboot") &&
59ddae9f
LP
5241 !streq(verbs[i].verb, "halt") &&
5242 !streq(verbs[i].verb, "poweroff")) || arg_force <= 0) && !bus) {
f176b5c2
LP
5243 log_error("Failed to get D-Bus connection: %s",
5244 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
8185a509
LP
5245 return -EIO;
5246 }
5247
5248 } else {
5249
729e3769 5250 if (!bus && !avoid_bus()) {
f176b5c2
LP
5251 log_error("Failed to get D-Bus connection: %s",
5252 dbus_error_is_set(error) ? error->message : "No connection to service manager.");
82e23ddd
LP
5253 return -EIO;
5254 }
ee5762e3
LP
5255 }
5256
729e3769 5257 return verbs[i].dispatch(bus, argv + optind);
e4b61340
LP
5258}
5259
52c00215 5260static int send_shutdownd(usec_t t, char mode, bool dry_run, bool warn, const char *message) {
04ebb595 5261 int fd;
f6144808 5262 struct msghdr msghdr;
04ebb595 5263 struct iovec iovec[2];
f6144808 5264 union sockaddr_union sockaddr;
04ebb595
LP
5265 struct sd_shutdown_command c;
5266
5267 fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
5268 if (fd < 0)
5269 return -errno;
f6144808
LP
5270
5271 zero(c);
04ebb595 5272 c.usec = t;
f6144808 5273 c.mode = mode;
52c00215 5274 c.dry_run = dry_run;
9be9828c
LP
5275 c.warn_wall = warn;
5276
f6144808
LP
5277 zero(sockaddr);
5278 sockaddr.sa.sa_family = AF_UNIX;
2b583ce6 5279 strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
f6144808 5280
f6144808
LP
5281 zero(msghdr);
5282 msghdr.msg_name = &sockaddr;
2b583ce6 5283 msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
f6144808 5284
04ebb595
LP
5285 zero(iovec);
5286 iovec[0].iov_base = (char*) &c;
5287 iovec[0].iov_len = offsetof(struct sd_shutdown_command, wall_message);
5288
5289 if (isempty(message))
5290 msghdr.msg_iovlen = 1;
5291 else {
5292 iovec[1].iov_base = (char*) message;
5293 iovec[1].iov_len = strlen(message);
5294 msghdr.msg_iovlen = 2;
5295 }
5296 msghdr.msg_iov = iovec;
f6144808
LP
5297
5298 if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
5299 close_nointr_nofail(fd);
5300 return -errno;
5301 }
5302
5303 close_nointr_nofail(fd);
5304 return 0;
5305}
5306
e4b61340 5307static int reload_with_fallback(DBusConnection *bus) {
e4b61340
LP
5308
5309 if (bus) {
5310 /* First, try systemd via D-Bus. */
d76702a7 5311 if (daemon_reload(bus, NULL) >= 0)
e4b61340
LP
5312 return 0;
5313 }
5314
5315 /* Nothing else worked, so let's try signals */
5316 assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
5317
5318 if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0) {
5319 log_error("kill() failed: %m");
5320 return -errno;
5321 }
5322
5323 return 0;
5324}
5325
5326static int start_with_fallback(DBusConnection *bus) {
e4b61340
LP
5327
5328 if (bus) {
5329 /* First, try systemd via D-Bus. */
729e3769 5330 if (start_unit(bus, NULL) >= 0)
983d9c90 5331 goto done;
e4b61340
LP
5332 }
5333
ec7f7f20
LP
5334 /* Hmm, talking to systemd via D-Bus didn't work. Then
5335 * let's try to talk to Upstart via D-Bus. */
e364ad06 5336 if (talk_upstart() > 0)
ec7f7f20
LP
5337 goto done;
5338
e4b61340
LP
5339 /* Nothing else worked, so let's try
5340 * /dev/initctl */
fbc43921 5341 if (talk_initctl() > 0)
983d9c90 5342 goto done;
d55ae9e6
LP
5343
5344 log_error("Failed to talk to init daemon.");
5345 return -EIO;
983d9c90
LP
5346
5347done:
5348 warn_wall(arg_action);
5349 return 0;
e4b61340
LP
5350}
5351
4c80c73c 5352static void halt_now(enum action a) {
e606bb61
LP
5353
5354 /* Make sure C-A-D is handled by the kernel from this
5355 * point on... */
5356 reboot(RB_ENABLE_CAD);
5357
4c80c73c 5358 switch (a) {
e606bb61
LP
5359
5360 case ACTION_HALT:
5361 log_info("Halting.");
5362 reboot(RB_HALT_SYSTEM);
5363 break;
5364
5365 case ACTION_POWEROFF:
5366 log_info("Powering off.");
5367 reboot(RB_POWER_OFF);
5368 break;
5369
5370 case ACTION_REBOOT:
5371 log_info("Rebooting.");
5372 reboot(RB_AUTOBOOT);
5373 break;
5374
5375 default:
5376 assert_not_reached("Unknown halt action.");
5377 }
5378
5379 assert_not_reached("Uh? This shouldn't happen.");
5380}
5381
e4b61340
LP
5382static int halt_main(DBusConnection *bus) {
5383 int r;
5384
bc8c2f5c 5385 if (geteuid() != 0) {
7e59bfcb
LP
5386 /* Try logind if we are a normal user and no special
5387 * mode applies. Maybe PolicyKit allows us to shutdown
5388 * the machine. */
5389
5390 if (arg_when <= 0 &&
5391 !arg_dry &&
65491fd8 5392 !arg_force &&
7e59bfcb
LP
5393 (arg_action == ACTION_POWEROFF ||
5394 arg_action == ACTION_REBOOT)) {
4c80c73c
KS
5395 r = reboot_with_logind(bus, arg_action);
5396 if (r >= 0)
5397 return r;
5398 }
5399
cc8a7a61 5400 log_error("Must be root.");
bc8c2f5c
LP
5401 return -EPERM;
5402 }
5403
f6144808 5404 if (arg_when > 0) {
9be9828c
LP
5405 char *m;
5406
5407 m = strv_join(arg_wall, " ");
5408 r = send_shutdownd(arg_when,
5409 arg_action == ACTION_HALT ? 'H' :
5410 arg_action == ACTION_POWEROFF ? 'P' :
04ebb595 5411 arg_action == ACTION_KEXEC ? 'K' :
9be9828c 5412 'r',
52c00215 5413 arg_dry,
9be9828c
LP
5414 !arg_no_wall,
5415 m);
5416 free(m);
5417
5418 if (r < 0)
f6144808 5419 log_warning("Failed to talk to shutdownd, proceeding with immediate shutdown: %s", strerror(-r));
08e4b1c5 5420 else {
7e59bfcb
LP
5421 char date[FORMAT_TIMESTAMP_MAX];
5422
08e4b1c5
LP
5423 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
5424 format_timestamp(date, sizeof(date), arg_when));
f6144808 5425 return 0;
08e4b1c5 5426 }
f6144808
LP
5427 }
5428
65491fd8 5429 if (!arg_dry && !arg_force)
e4b61340
LP
5430 return start_with_fallback(bus);
5431
d90e1a30
LP
5432 if (!arg_no_wtmp) {
5433 if (sd_booted() > 0)
5434 log_debug("Not writing utmp record, assuming that systemd-update-utmp is used.");
7e59bfcb
LP
5435 else {
5436 r = utmp_put_shutdown();
5437 if (r < 0)
5438 log_warning("Failed to write utmp record: %s", strerror(-r));
5439 }
d90e1a30 5440 }
e4b61340
LP
5441
5442 if (!arg_no_sync)
5443 sync();
5444
5445 if (arg_dry)
5446 return 0;
5447
e606bb61 5448 halt_now(arg_action);
e4b61340
LP
5449 /* We should never reach this. */
5450 return -ENOSYS;
5451}
5452
5453static int runlevel_main(void) {
5454 int r, runlevel, previous;
5455
729e3769
LP
5456 r = utmp_get_runlevel(&runlevel, &previous);
5457 if (r < 0) {
5458 puts("unknown");
e4b61340
LP
5459 return r;
5460 }
5461
5462 printf("%c %c\n",
5463 previous <= 0 ? 'N' : previous,
5464 runlevel <= 0 ? 'N' : runlevel);
5465
5466 return 0;
5467}
5468
5469int main(int argc, char*argv[]) {
22f4096c 5470 int r, retval = EXIT_FAILURE;
e4b61340
LP
5471 DBusConnection *bus = NULL;
5472 DBusError error;
5473
5474 dbus_error_init(&error);
5475
5476 log_parse_environment();
2396fb04 5477 log_open();
e4b61340 5478
04ebb595
LP
5479 r = parse_argv(argc, argv);
5480 if (r < 0)
e4b61340
LP
5481 goto finish;
5482 else if (r == 0) {
22f4096c 5483 retval = EXIT_SUCCESS;
7e4249b9
LP
5484 goto finish;
5485 }
5486
e4b61340
LP
5487 /* /sbin/runlevel doesn't need to communicate via D-Bus, so
5488 * let's shortcut this */
5489 if (arg_action == ACTION_RUNLEVEL) {
22f4096c
LP
5490 r = runlevel_main();
5491 retval = r < 0 ? EXIT_FAILURE : r;
e4b61340
LP
5492 goto finish;
5493 }
5494
82e23ddd
LP
5495 if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
5496 log_info("Running in chroot, ignoring request.");
5497 retval = 0;
5498 goto finish;
5499 }
5500
729e3769
LP
5501 if (!avoid_bus()) {
5502 if (arg_transport == TRANSPORT_NORMAL)
5503 bus_connect(arg_scope == UNIT_FILE_SYSTEM ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &bus, &private_bus, &error);
5504 else if (arg_transport == TRANSPORT_POLKIT) {
5505 bus_connect_system_polkit(&bus, &error);
5506 private_bus = false;
5507 } else if (arg_transport == TRANSPORT_SSH) {
5508 bus_connect_system_ssh(NULL, arg_host, &bus, &error);
5509 private_bus = false;
5510 } else
5511 assert_not_reached("Uh, invalid transport...");
5512 }
e4b61340
LP
5513
5514 switch (arg_action) {
5515
22f4096c
LP
5516 case ACTION_SYSTEMCTL:
5517 r = systemctl_main(bus, argc, argv, &error);
e4b61340 5518 break;
e4b61340
LP
5519
5520 case ACTION_HALT:
5521 case ACTION_POWEROFF:
5522 case ACTION_REBOOT:
5622dde3 5523 case ACTION_KEXEC:
22f4096c 5524 r = halt_main(bus);
e4b61340
LP
5525 break;
5526
e4b61340
LP
5527 case ACTION_RUNLEVEL2:
5528 case ACTION_RUNLEVEL3:
5529 case ACTION_RUNLEVEL4:
5530 case ACTION_RUNLEVEL5:
5531 case ACTION_RESCUE:
514f4ef5 5532 case ACTION_EMERGENCY:
eb22ac37 5533 case ACTION_DEFAULT:
22f4096c 5534 r = start_with_fallback(bus);
e4b61340 5535 break;
7e4249b9 5536
e4b61340
LP
5537 case ACTION_RELOAD:
5538 case ACTION_REEXEC:
22f4096c 5539 r = reload_with_fallback(bus);
e4b61340
LP
5540 break;
5541
f6144808 5542 case ACTION_CANCEL_SHUTDOWN:
52c00215 5543 r = send_shutdownd(0, 0, false, false, NULL);
f6144808
LP
5544 break;
5545
eb22ac37
LP
5546 case ACTION_INVALID:
5547 case ACTION_RUNLEVEL:
e4b61340
LP
5548 default:
5549 assert_not_reached("Unknown action");
5550 }
7e4249b9 5551
22f4096c
LP
5552 retval = r < 0 ? EXIT_FAILURE : r;
5553
7e4249b9 5554finish:
b574246b 5555 if (bus) {
5d452f9c 5556 dbus_connection_flush(bus);
b574246b 5557 dbus_connection_close(bus);
7e4249b9 5558 dbus_connection_unref(bus);
b574246b 5559 }
7e4249b9 5560
e4b61340
LP
5561 dbus_error_free(&error);
5562
7e4249b9
LP
5563 dbus_shutdown();
5564
ea4a240d
LP
5565 strv_free(arg_property);
5566
1888c907 5567 pager_close();
6bb92a16
LP
5568 ask_password_agent_close();
5569 polkit_agent_close();
1888c907 5570
7e4249b9
LP
5571 return retval;
5572}