sleep.c revision c33b329709ebe2755181980a050d02ec7c81ed87
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering/***
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering This file is part of systemd.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Copyright 2012 Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Copyright 2013 Zbigniew Jędrzejewski-Szmek
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering (at your option) any later version.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering systemd is distributed in the hope that it will be useful, but
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering Lesser General Public License for more details.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering***/
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <stdio.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <errno.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <string.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include <getopt.h>
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "sd-id128.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "sd-messages.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "log.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "util.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "strv.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "fileio.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "build.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "sleep-config.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering#include "def.h"
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poetteringstatic char* arg_verb = NULL;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poetteringstatic int write_mode(char **modes) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering int r = 0;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering char **mode;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering STRV_FOREACH(mode, modes) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering int k;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering k = write_string_file("/sys/power/disk", *mode);
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (k == 0)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering return 0;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering *mode);
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (r == 0)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering r = k;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering }
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering if (r < 0)
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
718db96199eb307751264e4163555662c9a389faLennart Poettering return r;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering}
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poetteringstatic int write_state(FILE **f, char **states) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering char **state;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering int r = 0;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering STRV_FOREACH(state, states) {
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering int k;
6c12b52e19640747e96f89d85422941a23dc6b29Lennart Poettering
k = write_string_stream(*f, *state);
if (k == 0)
return 0;
log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
*state);
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;
}
}
return r;
}
static int execute(char **modes, char **states) {
char *arguments[] = {
NULL,
(char*) "pre",
arg_verb,
NULL
};
int r;
_cleanup_fclose_ FILE *f = NULL;
/* This file is opened first, so that if we hit an error,
* we can abort before modifying any state. */
f = fopen("/sys/power/state", "we");
if (!f) {
log_error("Failed to open /sys/power/state: %m");
return -errno;
}
/* Configure the hibernation mode */
r = write_mode(modes);
if (r < 0)
return r;
execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_START),
LOG_MESSAGE("Suspending system..."),
"SLEEP=%s", arg_verb,
NULL);
r = write_state(&f, states);
if (r < 0)
return r;
log_struct(LOG_INFO,
LOG_MESSAGE_ID(SD_MESSAGE_SLEEP_STOP),
LOG_MESSAGE("MESSAGE=System resumed."),
"SLEEP=%s", arg_verb,
NULL);
arguments[1] = (char*) "post";
execute_directory(SYSTEM_SLEEP_PATH, NULL, DEFAULT_TIMEOUT_USEC, arguments);
return r;
}
static void 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);
}
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 },
{}
};
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:
assert_not_reached("Unhandled option");
}
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;
}