2012-05-05 02:06:58 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2012 Lennart Poettering
|
2013-05-04 18:31:28 +02:00
|
|
|
Copyright 2013 Zbigniew Jędrzejewski-Szmek
|
2012-05-05 02:06:58 +02:00
|
|
|
|
|
|
|
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 <errno.h>
|
2013-05-04 18:31:28 +02:00
|
|
|
#include <getopt.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <stdio.h>
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2014-03-06 02:19:06 +01:00
|
|
|
#include "sd-messages.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
|
|
|
|
#include "def.h"
|
2017-01-22 18:35:08 +01:00
|
|
|
#include "exec-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2013-02-14 12:26:13 +01:00
|
|
|
#include "fileio.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "log.h"
|
2013-05-04 18:31:28 +02:00
|
|
|
#include "sleep-config.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "strv.h"
|
|
|
|
#include "util.h"
|
2013-05-04 18:31:28 +02:00
|
|
|
|
|
|
|
static char* arg_verb = NULL;
|
|
|
|
|
|
|
|
static int write_mode(char **modes) {
|
|
|
|
int r = 0;
|
|
|
|
char **mode;
|
|
|
|
|
|
|
|
STRV_FOREACH(mode, modes) {
|
2014-03-06 02:19:06 +01:00
|
|
|
int k;
|
|
|
|
|
2015-07-07 01:19:25 +02:00
|
|
|
k = write_string_file("/sys/power/disk", *mode, 0);
|
2013-05-04 18:31:28 +02:00
|
|
|
if (k == 0)
|
|
|
|
return 0;
|
2014-03-06 02:19:06 +01:00
|
|
|
|
2014-11-28 17:09:20 +01:00
|
|
|
log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m",
|
|
|
|
*mode);
|
2013-05-04 18:31:28 +02:00
|
|
|
if (r == 0)
|
|
|
|
r = k;
|
|
|
|
}
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
if (r < 0)
|
2014-11-28 17:09:20 +01:00
|
|
|
log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
return r;
|
|
|
|
}
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-12-15 22:25:04 +01:00
|
|
|
static int write_state(FILE **f, char **states) {
|
2013-05-04 18:31:28 +02:00
|
|
|
char **state;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
STRV_FOREACH(state, states) {
|
|
|
|
int k;
|
|
|
|
|
2015-07-06 23:31:44 +02:00
|
|
|
k = write_string_stream(*f, *state, true);
|
2013-05-04 18:31:28 +02:00
|
|
|
if (k == 0)
|
|
|
|
return 0;
|
2014-11-28 17:09:20 +01:00
|
|
|
log_debug_errno(k, "Failed to write '%s' to /sys/power/state: %m",
|
|
|
|
*state);
|
2013-05-04 18:31:28 +02:00
|
|
|
if (r == 0)
|
|
|
|
r = k;
|
|
|
|
|
2013-12-15 22:25:04 +01:00
|
|
|
fclose(*f);
|
|
|
|
*f = fopen("/sys/power/state", "we");
|
2014-11-28 19:57:32 +01:00
|
|
|
if (!*f)
|
|
|
|
return log_error_errno(errno, "Failed to open /sys/power/state: %m");
|
2012-05-05 02:06:58 +02:00
|
|
|
}
|
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
return r;
|
|
|
|
}
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
static int execute(char **modes, char **states) {
|
2014-11-28 02:05:14 +01:00
|
|
|
|
|
|
|
char *arguments[] = {
|
|
|
|
NULL,
|
|
|
|
(char*) "pre",
|
|
|
|
arg_verb,
|
|
|
|
NULL
|
|
|
|
};
|
Implement masking and overriding of generators
Sometimes it is necessary to stop a generator from running. Either
because of a bug, or for testing, or some other reason. The only way
to do that would be to rename or chmod the generator binary, which is
inconvenient and does not survive upgrades. Allow masking and
overriding generators similarly to units and other configuration
files.
For the systemd instance, masking would be more common, rather than
overriding generators. For the user instances, it may also be useful
for users to have generators in $XDG_CONFIG_HOME to augment or
override system-wide generators.
Directories are searched according to the usual scheme (/usr/lib,
/usr/local/lib, /run, /etc), and files with the same name in higher
priority directories override files with the same name in lower
priority directories. Empty files and links to /dev/null mask a given
name.
https://bugs.freedesktop.org/show_bug.cgi?id=87230
2015-01-09 02:47:25 +01:00
|
|
|
static const char* const dirs[] = {SYSTEM_SLEEP_PATH, NULL};
|
2014-11-28 02:05:14 +01:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
int r;
|
2013-12-15 22:25:04 +01:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
2012-10-28 00:49:04 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
/* This file is opened first, so that if we hit an error,
|
2014-01-07 17:51:41 +01:00
|
|
|
* we can abort before modifying any state. */
|
2012-05-05 02:06:58 +02:00
|
|
|
f = fopen("/sys/power/state", "we");
|
2014-11-28 19:57:32 +01:00
|
|
|
if (!f)
|
|
|
|
return log_error_errno(errno, "Failed to open /sys/power/state: %m");
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
/* Configure the hibernation mode */
|
|
|
|
r = write_mode(modes);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2017-01-22 21:22:37 +01:00
|
|
|
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
|
2014-11-28 02:05:14 +01:00
|
|
|
LOG_MESSAGE("Suspending system..."),
|
|
|
|
"SLEEP=%s", arg_verb,
|
2013-05-04 18:31:28 +02:00
|
|
|
NULL);
|
|
|
|
|
2013-12-15 22:25:04 +01:00
|
|
|
r = write_state(&f, states);
|
2013-05-04 18:31:28 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
log_struct(LOG_INFO,
|
tree-wide: add SD_ID128_MAKE_STR, remove LOG_MESSAGE_ID
Embedding sd_id128_t's in constant strings was rather cumbersome. We had
SD_ID128_CONST_STR which returned a const char[], but it had two problems:
- it wasn't possible to statically concatanate this array with a normal string
- gcc wasn't really able to optimize this, and generated code to perform the
"conversion" at runtime.
Because of this, even our own code in coredumpctl wasn't using
SD_ID128_CONST_STR.
Add a new macro to generate a constant string: SD_ID128_MAKE_STR.
It is not as elegant as SD_ID128_CONST_STR, because it requires a repetition
of the numbers, but in practice it is more convenient to use, and allows gcc
to generate smarter code:
$ size .libs/systemd{,-logind,-journald}{.old,}
text data bss dec hex filename
1265204 149564 4808 1419576 15a938 .libs/systemd.old
1260268 149564 4808 1414640 1595f0 .libs/systemd
246805 13852 209 260866 3fb02 .libs/systemd-logind.old
240973 13852 209 255034 3e43a .libs/systemd-logind
146839 4984 34 151857 25131 .libs/systemd-journald.old
146391 4984 34 151409 24f71 .libs/systemd-journald
It is also much easier to check if a certain binary uses a certain MESSAGE_ID:
$ strings .libs/systemd.old|grep MESSAGE_ID
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
MESSAGE_ID=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x
$ strings .libs/systemd|grep MESSAGE_ID
MESSAGE_ID=c7a787079b354eaaa9e77b371893cd27
MESSAGE_ID=b07a249cd024414a82dd00cd181378ff
MESSAGE_ID=641257651c1b4ec9a8624d7a40a9e1e7
MESSAGE_ID=de5b426a63be47a7b6ac3eaac82e2f6f
MESSAGE_ID=d34d037fff1847e6ae669a370e694725
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
MESSAGE_ID=1dee0369c7fc4736b7099b38ecb46ee7
MESSAGE_ID=39f53479d3a045ac8e11786248231fbf
MESSAGE_ID=be02cf6855d2428ba40df7e9d022f03d
MESSAGE_ID=7b05ebc668384222baa8881179cfda54
MESSAGE_ID=9d1aaa27d60140bd96365438aad20286
2016-11-06 18:48:23 +01:00
|
|
|
"MESSAGE_ID=" SD_MESSAGE_SLEEP_STOP_STR,
|
2014-12-09 03:58:20 +01:00
|
|
|
LOG_MESSAGE("System resumed."),
|
2014-11-28 02:05:14 +01:00
|
|
|
"SLEEP=%s", arg_verb,
|
2013-05-04 18:31:28 +02:00
|
|
|
NULL);
|
2012-05-30 15:04:39 +02:00
|
|
|
|
2012-05-05 02:06:58 +02:00
|
|
|
arguments[1] = (char*) "post";
|
2017-01-22 21:22:37 +01:00
|
|
|
execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments);
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
return r;
|
|
|
|
}
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2014-08-02 17:12:21 +02:00
|
|
|
static void help(void) {
|
2013-05-04 18:31:28 +02:00
|
|
|
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"
|
2014-08-02 17:12:21 +02:00
|
|
|
, program_invocation_short_name);
|
2013-05-04 18:31:28 +02:00
|
|
|
}
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
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 },
|
2013-11-06 18:28:39 +01:00
|
|
|
{}
|
2013-05-04 18:31:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
assert(argv);
|
|
|
|
|
2014-08-02 17:12:21 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
2013-05-04 18:31:28 +02:00
|
|
|
switch(c) {
|
|
|
|
case 'h':
|
2014-08-02 17:12:21 +02:00
|
|
|
help();
|
|
|
|
return 0; /* done */
|
2013-05-04 18:31:28 +02:00
|
|
|
|
|
|
|
case ARG_VERSION:
|
2015-09-23 03:01:06 +02:00
|
|
|
return version();
|
2013-05-04 18:31:28 +02:00
|
|
|
|
|
|
|
case '?':
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
default:
|
2013-11-06 18:28:39 +01:00
|
|
|
assert_not_reached("Unhandled option");
|
2013-05-04 18:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (argc - optind != 1) {
|
|
|
|
log_error("Usage: %s COMMAND",
|
|
|
|
program_invocation_short_name);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_verb = argv[optind];
|
2012-05-05 02:06:58 +02:00
|
|
|
|
2013-05-04 18:31:28 +02:00
|
|
|
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;
|
2012-05-05 02:06:58 +02:00
|
|
|
}
|