#include <sys/reboot.h>
#include <stdio.h>
#include <getopt.h>
+#include <locale.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
ACTION_EXIT,
ACTION_SUSPEND,
ACTION_HIBERNATE,
+ ACTION_HYBRID_SLEEP,
ACTION_RUNLEVEL2,
ACTION_RUNLEVEL3,
ACTION_RUNLEVEL4,
TRANSPORT_POLKIT
} arg_transport = TRANSPORT_NORMAL;
static const char *arg_host = NULL;
-static bool arg_follow = false;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static int daemon_reload(DBusConnection *bus, char **args);
static void halt_now(enum action a);
-static bool on_tty(void) {
- static int t = -1;
-
- /* 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 colour and so on
- * when run in our own pager. */
-
- if (_unlikely_(t < 0))
- t = isatty(STDOUT_FILENO) > 0;
-
- return t;
-}
-
static void pager_open_if_enabled(void) {
- /* Cache result before we open the pager */
- on_tty();
-
if (arg_no_pager)
return;
static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
const struct unit_info *u;
+ int job_count = 0;
max_id_len = sizeof("UNIT")-1;
active_len = sizeof("ACTIVE")-1;
max_id_len = MAX(max_id_len, strlen(u->id));
active_len = MAX(active_len, strlen(u->active_state));
sub_len = MAX(sub_len, strlen(u->sub_state));
- if (u->job_id != 0)
+ if (u->job_id != 0) {
job_len = MAX(job_len, strlen(u->job_type));
+ job_count++;
+ }
}
if (!arg_full) {
unsigned basic_len;
id_len = MIN(max_id_len, 25);
- basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
+ basic_len = 5 + id_len + 5 + active_len + sub_len;
+ if (job_count)
+ basic_len += job_len + 1;
if (basic_len < (unsigned) columns()) {
unsigned extra_len, incr;
extra_len = columns() - basic_len;
continue;
if (!n_shown && !arg_no_legend) {
- printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
- active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
+ printf("%-*s %-6s %-*s %-*s ", id_len, "UNIT", "LOAD",
+ active_len, "ACTIVE", sub_len, "SUB");
+ if (job_count)
+ printf("%-*s ", job_len, "JOB");
if (!arg_full && arg_no_pager)
printf("%.*s\n", desc_len, "DESCRIPTION");
else
e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
- printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
+ printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s",
id_len, e ? e : u->id,
on_loaded, u->load_state, off_loaded,
on_active, active_len, u->active_state,
sub_len, u->sub_state, off_active,
- job_len, u->job_id ? u->job_type : "");
+ job_count ? job_len + 1 : 0, u->job_id ? u->job_type : "");
if (!arg_full && arg_no_pager)
printf("%.*s\n", desc_len, u->description);
else
if (n_shown) {
printf("\nLOAD = Reflects whether the unit definition was properly loaded.\n"
"ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
- "SUB = The low-level unit activation state, values depend on unit type.\n"
- "JOB = Pending job for the unit.\n\n");
+ "SUB = The low-level unit activation state, values depend on unit type.\n");
+ if (job_count)
+ printf("JOB = Pending job for the unit.\n");
+ puts("");
on = ansi_highlight(true);
off = ansi_highlight(false);
} else {
else if (streq(d.result, "canceled"))
log_error("Job for %s canceled.", strna(d.name));
else if (streq(d.result, "dependency"))
- log_error("A dependency job for %s failed. See 'journalctl' for details.", strna(d.name));
+ log_error("A dependency job for %s failed. See 'journalctl -xn' for details.", strna(d.name));
else if (!streq(d.result, "done") && !streq(d.result, "skipped"))
- log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl' for details.", strna(d.name), strna(d.name));
+ log_error("Job for %s failed. See 'systemctl status %s' and 'journalctl -xn' for details.", strna(d.name), strna(d.name));
}
if (streq_ptr(d.result, "timeout"))
return ACTION_SUSPEND;
else if (streq(verb, "hibernate"))
return ACTION_HIBERNATE;
+ else if (streq(verb, "hybrid-sleep"))
+ return ACTION_HYBRID_SLEEP;
else
return ACTION_INVALID;
}
[ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
[ACTION_EXIT] = SPECIAL_EXIT_TARGET,
[ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
- [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET
+ [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
+ [ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
};
int r, ret = 0;
method = "Hibernate";
break;
+ case ACTION_HYBRID_SLEEP:
+ method = "HybridSleep";
+ break;
+
default:
return -EINVAL;
}
(a == ACTION_POWEROFF ||
a == ACTION_REBOOT ||
a == ACTION_SUSPEND ||
- a == ACTION_HIBERNATE)) {
+ a == ACTION_HIBERNATE ||
+ a == ACTION_HYBRID_SLEEP)) {
r = reboot_with_logind(bus, a);
if (r >= 0)
return r;
streq_ptr(i->active_state, "activating") ? i->inactive_exit_timestamp :
i->active_exit_timestamp;
- s1 = format_timestamp_pretty(since1, sizeof(since1), timestamp);
+ s1 = format_timestamp_relative(since1, sizeof(since1), timestamp);
s2 = format_timestamp(since2, sizeof(since2), timestamp);
if (s1)
printf("\n");
if (!i->condition_result && i->condition_timestamp > 0) {
- s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
+ s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
if (s1)
if (i->id && arg_transport != TRANSPORT_SSH) {
int flags =
arg_all * OUTPUT_SHOW_ALL |
- arg_follow * OUTPUT_FOLLOW |
- !arg_quiet * OUTPUT_WARN_CUTOFF |
- on_tty() * OUTPUT_COLOR;
+ (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
+ on_tty() * OUTPUT_COLOR |
+ !arg_quiet * OUTPUT_WARN_CUTOFF;
printf("\n");
show_journal_by_unit(stdout,
}
static int set_environment(DBusConnection *bus, char **args) {
- DBusMessage *m = NULL, *reply = NULL;
+ _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
DBusError error;
- int r;
const char *method;
- DBusMessageIter iter, sub;
- char **name;
+ DBusMessageIter iter;
+ int r;
+
+ assert(bus);
dbus_error_init(&error);
? "SetEnvironment"
: "UnsetEnvironment";
- if (!(m = dbus_message_new_method_call(
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- method))) {
-
- log_error("Could not allocate message.");
- return -ENOMEM;
- }
+ m = dbus_message_new_method_call(
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method);
+ if (!m)
+ return log_oom();
dbus_message_iter_init_append(m, &iter);
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "s", &sub)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- STRV_FOREACH(name, args+1)
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, name)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
-
- if (!dbus_message_iter_close_container(&iter, &sub)) {
- log_error("Could not append arguments to message.");
- r = -ENOMEM;
- goto finish;
- }
+ r = bus_append_strv_iter(&iter, args + 1);
+ if (r < 0)
+ return log_oom();
- if (!(reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
+ reply = dbus_connection_send_with_reply_and_block(bus, m, -1, &error);
+ if (!reply) {
log_error("Failed to issue method call: %s", bus_error_message(&error));
r = -EIO;
goto finish;
r = 0;
finish:
- if (m)
- dbus_message_unref(m);
-
- if (reply)
- dbus_message_unref(reply);
-
dbus_error_free(&error);
-
return r;
}
}
}
+ r = 0;
} else {
const char *method;
bool send_force = true, expect_carries_install_info = false;
" --root=PATH Enable unit files in the specified root directory\n"
" --runtime Enable unit files only temporarily until next reboot\n"
" -n --lines=INTEGER Journal entries to show\n"
- " --follow Follow journal\n"
" -o --output=STRING Change journal output mode (short, short-monotonic,\n"
" verbose, export, json, json-pretty, json-sse, cat)\n\n"
"Unit Commands:\n"
" exit Request user instance exit\n"
" switch-root [ROOT] [INIT] Change to a different root file system\n"
" suspend Suspend the system\n"
- " hibernate Hibernate the system\n",
+ " hibernate Hibernate the system\n"
+ " hybrid-sleep Hibernate and suspend the system\n",
program_invocation_short_name);
return 0;
return 0;
}
+static int help_types(void) {
+ int i;
+
+ puts("Available unit types:");
+ for(i = UNIT_SERVICE; i < _UNIT_TYPE_MAX; i++)
+ if (unit_type_table[i])
+ puts(unit_type_table[i]);
+
+ puts("\nAvailable unit load states: ");
+ for(i = UNIT_STUB; i < _UNIT_LOAD_STATE_MAX; i++)
+ if (unit_type_table[i])
+ puts(unit_load_state_table[i]);
+
+ return 0;
+}
+
static int systemctl_parse_argv(int argc, char *argv[]) {
enum {
ARG_NO_ASK_PASSWORD,
ARG_FAILED,
ARG_RUNTIME,
- ARG_FOLLOW,
ARG_FORCE
};
{ "privileged",no_argument, NULL, 'P' },
{ "runtime", no_argument, NULL, ARG_RUNTIME },
{ "lines", required_argument, NULL, 'n' },
- { "follow", no_argument, NULL, ARG_FOLLOW },
{ "output", required_argument, NULL, 'o' },
{ NULL, 0, NULL, 0 }
};
return 0;
case 't':
+ if (streq(optarg, "help")) {
+ help_types();
+ return 0;
+ }
+
if (unit_type_from_string(optarg) >= 0) {
arg_type = optarg;
break;
}
log_error("Unkown unit type or load state '%s'.",
optarg);
+ log_info("Use -t help to see a list of allowed values.");
return -EINVAL;
case 'p': {
char **l;
arg_force ++;
break;
- case ARG_FOLLOW:
- arg_follow = true;
- break;
-
case 'f':
- /* -f is short for both --follow and --force! */
arg_force ++;
- arg_follow = true;
break;
case ARG_NO_RELOAD:
{ "kexec", EQUAL, 1, start_special },
{ "suspend", EQUAL, 1, start_special },
{ "hibernate", EQUAL, 1, start_special },
+ { "hybrid-sleep", EQUAL, 1, start_special },
{ "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special },
dbus_error_init(&error);
+ setlocale(LC_ALL, "");
log_parse_environment();
log_open();