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