summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/main.c2
-rw-r--r--src/login/logind-action.c7
-rw-r--r--src/login/logind-dbus.c56
-rw-r--r--src/shared/sleep-config.c182
-rw-r--r--src/shared/sleep-config.h26
-rw-r--r--src/shared/util.c53
-rw-r--r--src/shared/util.h3
-rw-r--r--src/sleep/sleep.c244
-rw-r--r--src/test/test-sleep.c30
9 files changed, 423 insertions, 180 deletions
diff --git a/src/core/main.c b/src/core/main.c
index 22cec4ed15..7fc06bea05 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -668,7 +668,7 @@ static int parse_config_file(void) {
const char *fn;
int r;
- fn = arg_running_as == SYSTEMD_SYSTEM ? SYSTEM_CONFIG_FILE : USER_CONFIG_FILE;
+ fn = arg_running_as == SYSTEMD_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
f = fopen(fn, "re");
if (!f) {
if (errno == ENOENT)
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index 4091e411b0..c930591023 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -27,6 +27,7 @@
#include "special.h"
#include "dbus-common.h"
#include "logind-action.h"
+#include "sleep-config.h"
int manager_handle_action(
Manager *m,
@@ -74,11 +75,11 @@ int manager_handle_action(
}
if (handle == HANDLE_SUSPEND)
- supported = can_sleep("mem") > 0;
+ supported = can_sleep("suspend") > 0;
else if (handle == HANDLE_HIBERNATE)
- supported = can_sleep("disk") > 0;
+ supported = can_sleep("hibernate") > 0;
else if (handle == HANDLE_HYBRID_SLEEP)
- supported = can_sleep("disk") > 0 && can_sleep_disk("suspend") > 0;
+ supported = can_sleep("hybrid-sleep") > 0;
else if (handle == HANDLE_KEXEC)
supported = access("/sbin/kexec", X_OK) >= 0;
else
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 68e499f52c..4a84b860f1 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -31,6 +31,7 @@
#include "path-util.h"
#include "polkit.h"
#include "special.h"
+#include "sleep-config.h"
#include "systemd/sd-id128.h"
#include "systemd/sd-messages.h"
#include "fileio-label.h"
@@ -1131,8 +1132,7 @@ static int bus_manager_can_shutdown_or_sleep(
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
- const char *sleep_type,
- const char *sleep_disk_type,
+ const char *sleep_verb,
DBusError *error,
DBusMessage **_reply) {
@@ -1153,22 +1153,10 @@ static int bus_manager_can_shutdown_or_sleep(
assert(error);
assert(_reply);
- if (sleep_type) {
- r = can_sleep(sleep_type);
+ if (sleep_verb) {
+ r = can_sleep(sleep_verb);
if (r < 0)
return r;
-
- if (r == 0) {
- result = "na";
- goto finish;
- }
- }
-
- if (sleep_disk_type) {
- r = can_sleep_disk(sleep_disk_type);
- if (r < 0)
- return r;
-
if (r == 0) {
result = "na";
goto finish;
@@ -1313,8 +1301,7 @@ static int bus_manager_do_shutdown_or_sleep(
const char *action,
const char *action_multiple_sessions,
const char *action_ignore_inhibit,
- const char *sleep_type,
- const char *sleep_disk_type,
+ const char *sleep_verb,
DBusError *error,
DBusMessage **_reply) {
@@ -1347,17 +1334,8 @@ static int bus_manager_do_shutdown_or_sleep(
DBUS_TYPE_INVALID))
return -EINVAL;
- if (sleep_type) {
- r = can_sleep(sleep_type);
- if (r < 0)
- return r;
-
- if (r == 0)
- return -ENOTSUP;
- }
-
- if (sleep_disk_type) {
- r = can_sleep_disk(sleep_disk_type);
+ if (sleep_verb) {
+ r = can_sleep(sleep_verb);
if (r < 0)
return r;
@@ -2160,7 +2138,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit",
- NULL, NULL,
+ NULL,
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2172,7 +2150,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit",
- NULL, NULL,
+ NULL,
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2185,7 +2163,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
- "mem", NULL,
+ "suspend",
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2197,7 +2175,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
- "disk", NULL,
+ "hibernate",
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2210,7 +2188,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
- "disk", "suspend",
+ "hybrid-sleep",
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2223,7 +2201,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit",
- NULL, NULL,
+ NULL,
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2234,7 +2212,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit",
- NULL, NULL,
+ NULL,
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2246,7 +2224,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit",
- "mem", NULL,
+ "suspend",
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2258,7 +2236,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
- "disk", NULL,
+ "hibernate",
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
@@ -2270,7 +2248,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
- "disk", "suspend",
+ "hybrid-sleep",
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
new file mode 100644
index 0000000000..73a3acb8be
--- /dev/null
+++ b/src/shared/sleep-config.c
@@ -0,0 +1,182 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+
+#include "conf-parser.h"
+#include "sleep-config.h"
+#include "fileio.h"
+#include "log.h"
+#include "strv.h"
+#include "util.h"
+
+int parse_sleep_config(const char *verb, char ***modes, char ***states) {
+ _cleanup_strv_free_ char
+ **suspend_mode = NULL, **suspend_state = NULL,
+ **hibernate_mode = NULL, **hibernate_state = NULL,
+ **hybrid_mode = NULL, **hybrid_state = NULL;
+
+ const ConfigTableItem items[] = {
+ { "Sleep", "SuspendMode", config_parse_strv, 0, &suspend_mode },
+ { "Sleep", "SuspendState", config_parse_strv, 0, &suspend_state },
+ { "Sleep", "HibernateMode", config_parse_strv, 0, &hibernate_mode },
+ { "Sleep", "HibernateState", config_parse_strv, 0, &hibernate_state },
+ { "Sleep", "HybridSleepMode", config_parse_strv, 0, &hybrid_mode },
+ { "Sleep", "HybridSleepState", config_parse_strv, 0, &hybrid_state },
+ {}};
+
+ int r;
+ FILE _cleanup_fclose_ *f;
+
+ f = fopen(PKGSYSCONFDIR "/sleep.conf", "re");
+ if (!f) {
+ if (errno == ENOENT)
+ return 0;
+
+ log_warning("Failed to open configuration file " PKGSYSCONFDIR "/sleep.conf: %m");
+ return 0;
+ }
+
+ r = config_parse(NULL, PKGSYSCONFDIR "/sleep.conf", f, "Sleep\0",
+ config_item_table_lookup, (void*) items, false, false, NULL);
+ if (r < 0)
+ log_warning("Failed to parse configuration file: %s", strerror(-r));
+
+ if (streq(verb, "suspend")) {
+ /* empty by default */
+ *modes = suspend_mode;
+
+ if (suspend_state)
+ *states = suspend_state;
+ else
+ *states = strv_split_nulstr("mem\0standby\0freeze\0");
+
+ suspend_mode = suspend_state = NULL;
+ } else if (streq(verb, "hibernate")) {
+ if (hibernate_mode)
+ *modes = hibernate_mode;
+ else
+ *modes = strv_split_nulstr("platform\0shutdown\0");
+
+ if (hibernate_state)
+ *states = hibernate_state;
+ else
+ *states = strv_split_nulstr("disk\0");
+
+ hibernate_mode = hibernate_state = NULL;
+ } else if (streq(verb, "hybrid-sleep")) {
+ if (hybrid_mode)
+ *modes = hybrid_mode;
+ else
+ *modes = strv_split_nulstr("suspend\0platform\0shutdown\0");
+
+ if (hybrid_state)
+ *states = hybrid_state;
+ else
+ *states = strv_split_nulstr("disk\0");
+
+ hybrid_mode = hybrid_state = NULL;
+ } else
+ assert_not_reached("what verb");
+
+ if (!modes || !states) {
+ strv_free(*modes);
+ strv_free(*states);
+ return log_oom();
+ }
+
+ return 0;
+}
+
+int can_sleep_state(char **types) {
+ char *w, *state, **type;
+ int r;
+ _cleanup_free_ char *p = NULL;
+
+ if (strv_isempty(types))
+ return true;
+
+ /* If /sys is read-only we cannot sleep */
+ if (access("/sys/power/state", W_OK) < 0)
+ return false;
+
+ r = read_one_line_file("/sys/power/state", &p);
+ if (r < 0)
+ return false;
+
+ STRV_FOREACH(type, types) {
+ size_t l, k;
+
+ k = strlen(*type);
+ FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
+ if (l == k && memcmp(w, *type, l) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+int can_sleep_disk(char **types) {
+ char *w, *state, **type;
+ int r;
+ _cleanup_free_ char *p = NULL;
+
+ if (strv_isempty(types))
+ return true;
+
+ /* If /sys is read-only we cannot sleep */
+ if (access("/sys/power/disk", W_OK) < 0)
+ return false;
+
+ r = read_one_line_file("/sys/power/disk", &p);
+ if (r < 0)
+ return false;
+
+ STRV_FOREACH(type, types) {
+ size_t l, k;
+
+ k = strlen(*type);
+ FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
+ if (l == k && memcmp(w, *type, l) == 0)
+ return true;
+
+ if (l == k + 2 && w[0] == '[' && memcmp(w + 1, *type, l - 2) == 0 && w[l-1] == ']')
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int can_sleep(const char *verb) {
+ _cleanup_strv_free_ char **modes = NULL, **states = NULL;
+ int r;
+
+ assert(streq(verb, "suspend") ||
+ streq(verb, "hibernate") ||
+ streq(verb, "hybrid-sleep"));
+
+ r = parse_sleep_config(verb, &modes, &states);
+ if (r < 0)
+ return false;
+
+ return can_sleep_state(states) && can_sleep_disk(modes);
+}
diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h
new file mode 100644
index 0000000000..51d2dec7b4
--- /dev/null
+++ b/src/shared/sleep-config.h
@@ -0,0 +1,26 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int parse_sleep_config(const char *verb, char ***modes, char ***states);
+
+int can_sleep(const char *verb);
+int can_sleep_disk(char **types);
+int can_sleep_state(char **types);
diff --git a/src/shared/util.c b/src/shared/util.c
index 5d01802ed9..00d3ace616 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -5090,59 +5090,6 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
return r;
}
-int can_sleep(const char *type) {
- char *w, *state;
- size_t l, k;
- int r;
- _cleanup_free_ char *p = NULL;
-
- assert(type);
-
- /* If /sys is read-only we cannot sleep */
- if (access("/sys/power/state", W_OK) < 0)
- return false;
-
- r = read_one_line_file("/sys/power/state", &p);
- if (r < 0)
- return false;
-
- k = strlen(type);
- FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
- if (l == k && memcmp(w, type, l) == 0)
- return true;
-
- return false;
-}
-
-int can_sleep_disk(const char *type) {
- char *w, *state;
- size_t l, k;
- int r;
- _cleanup_free_ char *p = NULL;
-
- assert(type);
-
- /* If /sys is read-only we cannot sleep */
- if (access("/sys/power/state", W_OK) < 0 ||
- access("/sys/power/disk", W_OK) < 0)
- return false;
-
- r = read_one_line_file("/sys/power/disk", &p);
- if (r < 0)
- return false;
-
- k = strlen(type);
- FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
- if (l == k && memcmp(w, type, l) == 0)
- return true;
-
- if (l == k + 2 && w[0] == '[' && memcmp(w + 1, type, l - 2) == 0 && w[l-1] == ']')
- return true;
- }
-
- return false;
-}
-
bool is_valid_documentation_url(const char *url) {
assert(url);
diff --git a/src/shared/util.h b/src/shared/util.h
index 0bcda48b6d..7ef46e8f1e 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -513,9 +513,6 @@ int setrlimit_closest(int resource, const struct rlimit *rlim);
int getenv_for_pid(pid_t pid, const char *field, char **_value);
-int can_sleep(const char *type);
-int can_sleep_disk(const char *type);
-
bool is_valid_documentation_url(const char *url) _pure_;
bool in_initrd(void);
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index f5e78c13c6..a56ab89e54 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -4,6 +4,7 @@
This file is part of systemd.
Copyright 2012 Lennart Poettering
+ Copyright 2013 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -22,107 +23,200 @@
#include <stdio.h>
#include <errno.h>
#include <string.h>
+#include <getopt.h>
-#include "log.h"
-#include "util.h"
#include "systemd/sd-id128.h"
#include "systemd/sd-messages.h"
+#include "log.h"
+#include "util.h"
+#include "strv.h"
#include "fileio.h"
+#include "build.h"
+#include "sleep-config.h"
+
+static char* arg_verb = NULL;
+
+static int write_mode(char **modes) {
+ int r = 0;
+ char **mode;
+
+ STRV_FOREACH(mode, modes) {
+ int k = write_string_file("/sys/power/disk", *mode);
+ if (k == 0)
+ return 0;
+ log_debug("Failed to write '%s' to /sys/power/disk: %s",
+ *mode, strerror(-k));
+ if (r == 0)
+ r = k;
+ }
-int main(int argc, char *argv[]) {
- const char *verb;
- char* arguments[4];
- int r;
- FILE *f;
+ if (r < 0)
+ log_error("Failed to write mode to /sys/power/disk: %s",
+ strerror(-r));
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
+ return r;
+}
- if (argc != 2) {
- log_error("Invalid number of arguments.");
- r = -EINVAL;
- goto finish;
+static int write_state(FILE *f0, char **states) {
+ FILE _cleanup_fclose_ *f = f0;
+ char **state;
+ int r = 0;
+
+ STRV_FOREACH(state, states) {
+ int k;
+
+ k = write_string_to_file(f, *state);
+ if (k == 0)
+ return 0;
+ log_debug("Failed to write '%s' to /sys/power/state: %s",
+ *state, strerror(-k));
+ if (r == 0)
+ r = k;
+
+ fclose(f);
+ f = fopen("/sys/power/state", "we");
+ if (!f) {
+ log_error("Failed to open /sys/power/state: %m");
+ return -errno;
+ }
}
- if (streq(argv[1], "suspend"))
- verb = "mem";
- else if (streq(argv[1], "hibernate") || streq(argv[1], "hybrid-sleep"))
- verb = "disk";
- else {
- log_error("Unknown action '%s'.", argv[1]);
- r = -EINVAL;
- goto finish;
- }
+ return r;
+}
- /* Configure the hibernation mode */
- if (streq(argv[1], "hibernate")) {
- if (write_string_file("/sys/power/disk", "platform") < 0)
- write_string_file("/sys/power/disk", "shutdown");
- } else if (streq(argv[1], "hybrid-sleep")) {
- if (write_string_file("/sys/power/disk", "suspend") < 0)
- if (write_string_file("/sys/power/disk", "platform") < 0)
- write_string_file("/sys/power/disk", "shutdown");
- }
+static int execute(char **modes, char **states) {
+ char* arguments[4];
+ int r;
+ FILE *f;
+ const char* note = strappenda("SLEEP=", arg_verb);
+ /* This file is opened first, so that if we hit an error,
+ * we can abort before modyfing any state. */
f = fopen("/sys/power/state", "we");
if (!f) {
log_error("Failed to open /sys/power/state: %m");
- r = -errno;
- goto finish;
+ return -errno;
}
+ /* Configure the hibernation mode */
+ r = write_mode(modes);
+ if (r < 0)
+ return r;
+
arguments[0] = NULL;
arguments[1] = (char*) "pre";
- arguments[2] = argv[1];
+ arguments[2] = arg_verb;
arguments[3] = NULL;
execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
- if (streq(argv[1], "suspend"))
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SLEEP_START),
- "MESSAGE=Suspending system...",
- "SLEEP=suspend",
- NULL);
- else if (streq(argv[1], "hibernate"))
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SLEEP_START),
- "MESSAGE=Hibernating system...",
- "SLEEP=hibernate",
- NULL);
- else
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SLEEP_START),
- "MESSAGE=Hibernating and suspending system...",
- "SLEEP=hybrid-sleep",
- NULL);
-
- fputs(verb, f);
- fputc('\n', f);
- fflush(f);
-
- r = ferror(f) ? -errno : 0;
-
- if (streq(argv[1], "suspend"))
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
- "MESSAGE=System resumed.",
- "SLEEP=suspend",
- NULL);
- else
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
- "MESSAGE=System thawed.",
- "SLEEP=hibernate",
- NULL);
+ log_struct(LOG_INFO,
+ MESSAGE_ID(SD_MESSAGE_SLEEP_START),
+ "MESSAGE=Suspending system...",
+ note,
+ NULL);
+
+ r = write_state(f, states);
+ if (r < 0)
+ return r;
+
+ log_struct(LOG_INFO,
+ MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
+ "MESSAGE=System resumed.",
+ note,
+ NULL);
arguments[1] = (char*) "post";
execute_directory(SYSTEM_SLEEP_PATH, NULL, arguments);
- fclose(f);
+ return r;
+}
-finish:
+static int help(void) {
+ printf("%s COMMAND\n\n"
+ "Suspend the system, hibernate the system, or both.\n\n"
+ "Commands:\n"
+ " -h --help Show this help and exit\n"
+ " --version Print version string and exit\n"
+ " suspend Suspend the system\n"
+ " hibernate Hibernate the system\n"
+ " hybrid-sleep Both hibernate and suspend the system\n"
+ , program_invocation_short_name
+ );
+
+ return 0;
+}
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+static int parse_argv(int argc, char *argv[]) {
+ enum {
+ ARG_VERSION = 0x100,
+ };
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "+h", options, NULL)) >= 0)
+ switch(c) {
+ case 'h':
+ help();
+ return 0 /* done */;
+
+ case ARG_VERSION:
+ puts(PACKAGE_STRING);
+ puts(SYSTEMD_FEATURES);
+ return 0 /* done */;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ log_error("Unknown option code %c", c);
+ return -EINVAL;
+ }
+
+ if (argc - optind != 1) {
+ log_error("Usage: %s COMMAND",
+ program_invocation_short_name);
+ return -EINVAL;
+ }
+
+ arg_verb = argv[optind];
+ if (!streq(arg_verb, "suspend") &&
+ !streq(arg_verb, "hibernate") &&
+ !streq(arg_verb, "hybrid-sleep")) {
+ log_error("Unknown command '%s'.", arg_verb);
+ return -EINVAL;
+ }
+
+ return 1 /* work to do */;
+}
+
+int main(int argc, char *argv[]) {
+ _cleanup_strv_free_ char **modes = NULL, **states = NULL;
+ int r;
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ goto finish;
+
+ r = parse_sleep_config(arg_verb, &modes, &states);
+ if (r < 0)
+ goto finish;
+
+ r = execute(modes, states);
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c
index 5a98ecda2f..c3cb9c531d 100644
--- a/src/test/test-sleep.c
+++ b/src/test/test-sleep.c
@@ -26,14 +26,32 @@
#include "util.h"
#include "log.h"
+#include "sleep-config.h"
+#include "strv.h"
int main(int argc, char* argv[]) {
- log_info("Can Suspend: %s", yes_no(can_sleep("mem") > 0));
- log_info("Can Hibernate: %s", yes_no(can_sleep("disk") > 0));
- log_info("Can Hibernate+Suspend (Hybrid-Sleep): %s", yes_no(can_sleep_disk("suspend") > 0));
- log_info("Can Hibernate+Reboot: %s", yes_no(can_sleep_disk("reboot") > 0));
- log_info("Can Hibernate+Platform: %s", yes_no(can_sleep_disk("platform") > 0));
- log_info("Can Hibernate+Shutdown: %s", yes_no(can_sleep_disk("shutdown") > 0));
+ _cleanup_strv_free_ char
+ **standby = strv_new("standby", NULL),
+ **mem = strv_new("mem", NULL),
+ **disk = strv_new("disk", NULL),
+ **suspend = strv_new("suspend", NULL),
+ **reboot = strv_new("reboot", NULL),
+ **platform = strv_new("platform", NULL),
+ **shutdown = strv_new("shutdown", NULL),
+ **freez = strv_new("freeze", NULL);
+
+ log_info("Can Standby: %s", yes_no(can_sleep_state(standby) > 0));
+ log_info("Can Suspend: %s", yes_no(can_sleep_state(mem) > 0));
+ log_info("Can Hibernate: %s", yes_no(can_sleep_state(disk) > 0));
+ log_info("Can Hibernate+Suspend (Hybrid-Sleep): %s", yes_no(can_sleep_disk(suspend) > 0));
+ log_info("Can Hibernate+Reboot: %s", yes_no(can_sleep_disk(reboot) > 0));
+ log_info("Can Hibernate+Platform: %s", yes_no(can_sleep_disk(platform) > 0));
+ log_info("Can Hibernate+Shutdown: %s", yes_no(can_sleep_disk(shutdown) > 0));
+ log_info("Can Freeze: %s", yes_no(can_sleep_disk(freez) > 0));
+
+ log_info("Suspend configured and possible: %s", yes_no(can_sleep("suspend") > 0));
+ log_info("Hibernation configured and possible: %s", yes_no(can_sleep("hibernate") > 0));
+ log_info("Hybrid-sleep configured and possible: %s", yes_no(can_sleep("hybrid-sleep") > 0));
return 0;
}