static const char *arg_type = NULL;
static char **arg_property = NULL;
static bool arg_all = false;
-static bool arg_fail = false;
+static const char *arg_job_mode = "replace";
static bool arg_user = false;
static bool arg_global = false;
static bool arg_immediate = false;
static bool arg_force = false;
static bool arg_defaults = false;
static bool arg_ask_password = false;
+static bool arg_failed = false;
static char **arg_wall = NULL;
static const char *arg_kill_who = NULL;
static const char *arg_kill_mode = NULL;
/* Note that this is invoked relatively early, before we start
* the pager. That means the value we return reflects whether
* we originally were started on a tty, not if we currently
- * are. But this is intended, since we want color, and so on
+ * are. But this is intended, since we want colour and so on
* when run in our own pager. */
if (_unlikely_(t < 0))
};
int fd;
+ bool stdout_is_tty, stderr_is_tty;
/* Make sure the agent goes away when the parent dies */
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
/* Don't leak fds to the agent */
close_all_fds(NULL, 0);
- /* Detach from stdin/stdout/stderr. and reopen
- * /dev/tty for them. This is important to ensure that
- * when systemctl is started via popen() or a similar
- * call that expects to read EOF we actually do
- * generate EOF and not delay this indefinitely by
- * because we keep an unused copy of stdin around. */
- if ((fd = open("/dev/tty", O_RDWR)) < 0) {
- log_error("Failed to open /dev/tty: %m");
- _exit(EXIT_FAILURE);
- }
+ stdout_is_tty = isatty(STDOUT_FILENO);
+ stderr_is_tty = isatty(STDERR_FILENO);
+
+ if (!stdout_is_tty || !stderr_is_tty) {
+ /* Detach from stdout/stderr. and reopen
+ * /dev/tty for them. This is important to
+ * ensure that when systemctl is started via
+ * popen() or a similar call that expects to
+ * read EOF we actually do generate EOF and
+ * not delay this indefinitely by because we
+ * keep an unused copy of stdin around. */
+ if ((fd = open("/dev/tty", O_WRONLY)) < 0) {
+ log_error("Failed to open /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
+ if (!stdout_is_tty)
+ dup2(fd, STDOUT_FILENO);
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
+ if (!stderr_is_tty)
+ dup2(fd, STDERR_FILENO);
- if (fd > 2)
- close(fd);
+ if (fd > 2)
+ close(fd);
+ }
execv(args[0], (char **) args);
_exit(EXIT_FAILURE);
return strcasecmp(u->id, v->id);
}
-static bool output_show_job(const struct unit_info *u) {
+static bool output_show_unit(const struct unit_info *u) {
const char *dot;
+ if (arg_failed)
+ return streq(u->active_state, "failed");
+
return (!arg_type || ((dot = strrchr(u->id, '.')) &&
streq(dot+1, arg_type))) &&
(arg_all || !(streq(u->active_state, "inactive") || u->following[0]) || u->job_id > 0);
job_len = sizeof("JOB")-1;
for (u = unit_infos; u < unit_infos + c; u++) {
- if (!output_show_job(u))
+ if (!output_show_unit(u))
continue;
active_len = MAX(active_len, strlen(u->active_state));
const char *on_loaded, *off_loaded;
const char *on_active, *off_active;
- if (!output_show_job(u))
+ if (!output_show_unit(u))
continue;
n_shown++;
mode =
(streq(args[0], "isolate") ||
streq(args[0], "rescue") ||
- streq(args[0], "emergency")) ? "isolate" :
- arg_fail ? "fail" :
- "replace";
+ streq(args[0], "emergency")) ? "isolate" : arg_job_mode;
one_name = table[verb_to_action(args[0])];
" -t --type=TYPE List only units of a particular type\n"
" -p --property=NAME Show only properties by this name\n"
" -a --all Show all units/properties, including dead/empty ones\n"
+ " --failed Show only failed units\n"
" --full Don't ellipsize unit names on output\n"
" --fail When queueing a new job, fail if conflicting jobs are\n"
" pending\n"
+ " --ignore-dependencies\n"
+ " When queueing a new job, ignore all its dependencies\n"
" -q --quiet Suppress output\n"
" --no-block Do not wait until operation finished\n"
" --no-pager Do not pipe output into a pager.\n"
enum {
ARG_FAIL = 0x100,
+ ARG_IGNORE_DEPENDENCIES,
ARG_VERSION,
ARG_USER,
ARG_SYSTEM,
ARG_DEFAULTS,
ARG_KILL_MODE,
ARG_KILL_WHO,
- ARG_NO_ASK_PASSWORD
+ ARG_NO_ASK_PASSWORD,
+ ARG_FAILED
};
static const struct option options[] = {
{ "type", required_argument, NULL, 't' },
{ "property", required_argument, NULL, 'p' },
{ "all", no_argument, NULL, 'a' },
+ { "failed", no_argument, NULL, ARG_FAILED },
{ "full", no_argument, NULL, ARG_FULL },
{ "fail", no_argument, NULL, ARG_FAIL },
+ { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
{ "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "global", no_argument, NULL, ARG_GLOBAL },
break;
case ARG_FAIL:
- arg_fail = true;
+ arg_job_mode = "fail";
+ break;
+
+ case ARG_IGNORE_DEPENDENCIES:
+ arg_job_mode = "ignore-dependencies";
break;
case ARG_USER:
arg_full = true;
break;
+ case ARG_FAILED:
+ arg_failed = true;
+ break;
+
case 'q':
arg_quiet = true;
break;
return 0;
}
+static bool kexec_loaded(void) {
+ bool loaded = false;
+ char *s;
+
+ if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
+ if (s[0] == '1')
+ loaded = true;
+ free(s);
+ }
+ return loaded;
+}
+
static int shutdown_parse_argv(int argc, char *argv[]) {
enum {
break;
case 'r':
- arg_action = ACTION_REBOOT;
+ if (kexec_loaded())
+ arg_action = ACTION_KEXEC;
+ else
+ arg_action = ACTION_REBOOT;
break;
case 'h':
arg_action = ACTION_POWEROFF;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "reboot")) {
- arg_action = ACTION_REBOOT;
+ if (kexec_loaded())
+ arg_action = ACTION_KEXEC;
+ else
+ arg_action = ACTION_REBOOT;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "shutdown")) {
arg_action = ACTION_POWEROFF;
case ACTION_HALT:
case ACTION_POWEROFF:
case ACTION_REBOOT:
+ case ACTION_KEXEC:
r = halt_main(bus);
break;