Skip to content

Commit a927382

Browse files
authored
Merge pull request #28355 from yuwata/unit-skip-battery-check-by-kernel-command-line
unit: skip battery check when systemd.skip-battery-check specified on boot
2 parents 726f105 + 7cfef4b commit a927382

File tree

6 files changed

+158
-41
lines changed

6 files changed

+158
-41
lines changed

NEWS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,8 @@ CHANGES WITH 254 in spe:
698698
charge level of the system. In case the charge level is very low the
699699
user is notified (graphically via Plymouth – if available – as well
700700
as in text form on the console), and the system is turned off after a
701-
10s delay.
701+
10s delay. The feature can be disabled by passing
702+
systemd.battery-check=0 through the kernel command line.
702703

703704
* The 'passwdqc' library is now supported as an alternative to the
704705
'pwquality' library and it can be selected at build time.

man/systemd-battery-check.service.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,26 @@
6262
</para>
6363
</refsect1>
6464

65+
<refsect1>
66+
<title>Kernel Command Line</title>
67+
68+
<para>The following variables are understood:</para>
69+
70+
<variablelist class='kernel-commandline-options'>
71+
<varlistentry>
72+
<term><varname>systemd.battery-check=<replaceable>BOOL</replaceable></varname></term>
73+
74+
<listitem>
75+
<para>Takes a boolean. If specified with false, <command>systemd-battery-check</command> command
76+
will return immediately with exit status 0 without checking battery capacity and AC power
77+
existence, and the service <filename>systemd-battery-check.service</filename> will succeed. This
78+
may be useful when the command wrongly detects and reports battery capacity percentage or AC power
79+
existence, or when you want to boot the system forcibly.</para>
80+
</listitem>
81+
</varlistentry>
82+
</variablelist>
83+
</refsect1>
84+
6585
<refsect1>
6686
<title>See Also</title>
6787
<para>

src/basic/proc-cmdline.c

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,63 +17,95 @@
1717
#include "strv.h"
1818
#include "virt.h"
1919

20-
int proc_cmdline_filter_pid1_args(
21-
char **argv, /* input, may be reordered by this function. */
22-
char ***ret) {
23-
20+
int proc_cmdline_filter_pid1_args(char **argv, char ***ret) {
2421
enum {
2522
COMMON_GETOPT_ARGS,
2623
SYSTEMD_GETOPT_ARGS,
2724
SHUTDOWN_GETOPT_ARGS,
2825
};
29-
3026
static const struct option options[] = {
3127
COMMON_GETOPT_OPTIONS,
3228
SYSTEMD_GETOPT_OPTIONS,
3329
SHUTDOWN_GETOPT_OPTIONS,
34-
{}
3530
};
31+
static const char *short_options = SYSTEMD_GETOPT_SHORT_OPTIONS;
3632

37-
int saved_optind, saved_opterr, saved_optopt, argc;
38-
char *saved_optarg;
39-
char **filtered;
40-
size_t idx;
33+
_cleanup_strv_free_ char **filtered = NULL;
34+
int state, r;
4135

4236
assert(argv);
4337
assert(ret);
4438

45-
/* Backup global variables. */
46-
saved_optind = optind;
47-
saved_opterr = opterr;
48-
saved_optopt = optopt;
49-
saved_optarg = optarg;
39+
/* Currently, we do not support '-', '+', and ':' at the beginning. */
40+
assert(!IN_SET(short_options[0], '-', '+', ':'));
5041

51-
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
52-
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). Here, we do not use
53-
* the GNU extensions, but might be used previously. Hence, we need to always reset it. */
54-
optind = 0;
42+
/* Filter out all known options. */
43+
state = no_argument;
44+
STRV_FOREACH(p, strv_skip(argv, 1)) {
45+
int prev_state = state;
46+
const char *a = *p;
5547

56-
/* Do not print an error message. */
57-
opterr = 0;
48+
/* Reset the state for the next step. */
49+
state = no_argument;
5850

59-
/* Filter out all known options. */
60-
argc = strv_length(argv);
61-
while (getopt_long(argc, argv, SYSTEMD_GETOPT_SHORT_OPTIONS, options, NULL) >= 0)
62-
;
51+
if (prev_state == required_argument ||
52+
(prev_state == optional_argument && a[0] != '-'))
53+
/* Handled as an argument of the previous option, filtering out the string. */
54+
continue;
6355

64-
idx = optind;
56+
if (a[0] != '-') {
57+
/* Not an option, accepting the string. */
58+
r = strv_extend(&filtered, a);
59+
if (r < 0)
60+
return r;
61+
continue;
62+
}
6563

66-
/* Restore global variables. */
67-
optind = saved_optind;
68-
opterr = saved_opterr;
69-
optopt = saved_optopt;
70-
optarg = saved_optarg;
64+
if (a[1] == '-') {
65+
if (a[2] == '\0') {
66+
/* "--" is specified, accepting remaining strings. */
67+
r = strv_extend_strv(&filtered, strv_skip(p, 1), /* filter_duplicates = */ false);
68+
if (r < 0)
69+
return r;
70+
break;
71+
}
7172

72-
filtered = strv_copy(strv_skip(argv, idx));
73-
if (!filtered)
74-
return -ENOMEM;
73+
/* long option, e.g. --foo */
74+
for (size_t i = 0; i < ELEMENTSOF(options); i++) {
75+
const char *q = startswith(a + 2, options[i].name);
76+
if (!q || !IN_SET(q[0], '=', '\0'))
77+
continue;
78+
79+
/* Found matching option, updating the state if necessary. */
80+
if (q[0] == '\0' && options[i].has_arg == required_argument)
81+
state = required_argument;
82+
83+
break;
84+
}
85+
continue;
86+
}
87+
88+
/* short option(s), e.g. -x or -xyz */
89+
while (a && *++a != '\0')
90+
for (const char *q = short_options; *q != '\0'; q++) {
91+
if (*q != *a)
92+
continue;
93+
94+
/* Found matching short option. */
95+
96+
if (q[1] == ':') {
97+
/* An argument is required or optional, and remaining part
98+
* is handled as argument if exists. */
99+
state = a[1] != '\0' ? no_argument :
100+
q[2] == ':' ? optional_argument : required_argument;
101+
102+
a = NULL; /* Not necessary to parse remaining part. */
103+
}
104+
break;
105+
}
106+
}
75107

76-
*ret = filtered;
108+
*ret = TAKE_PTR(filtered);
77109
return 0;
78110
}
79111

src/battery-check/battery-check.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
#include "io-util.h"
1515
#include "log.h"
1616
#include "main-func.h"
17+
#include "parse-util.h"
1718
#include "pretty-print.h"
19+
#include "proc-cmdline.h"
1820
#include "socket-util.h"
1921
#include "terminal-util.h"
2022
#include "time-util.h"
@@ -24,6 +26,8 @@
2426
#define BATTERY_RESTORED_MESSAGE \
2527
"A.C. power restored, continuing."
2628

29+
static bool arg_doit = true;
30+
2731
static int help(void) {
2832
_cleanup_free_ char *link = NULL;
2933
int r;
@@ -84,6 +88,23 @@ static int plymouth_send_message(const char *mode, const char *message) {
8488
return 0;
8589
}
8690

91+
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
92+
int r;
93+
94+
assert(key);
95+
96+
if (streq(key, "systemd.battery-check")) {
97+
98+
r = value ? parse_boolean(value) : 1;
99+
if (r < 0)
100+
log_warning_errno(r, "Failed to parse %s switch, ignoring: %s", key, value);
101+
else
102+
arg_doit = r;
103+
}
104+
105+
return 0;
106+
}
107+
87108
static int parse_argv(int argc, char * argv[]) {
88109

89110
enum {
@@ -132,10 +153,19 @@ static int run(int argc, char *argv[]) {
132153

133154
log_setup();
134155

156+
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
157+
if (r < 0)
158+
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
159+
135160
r = parse_argv(argc, argv);
136161
if (r <= 0)
137162
return r;
138163

164+
if (!arg_doit) {
165+
log_info("Checking battery status and AC power existence is disabled by the kernel command line, skipping execution.");
166+
return 0;
167+
}
168+
139169
r = battery_is_discharging_and_low();
140170
if (r < 0) {
141171
log_warning_errno(r, "Failed to check battery status, ignoring: %m");

src/test/test-proc-cmdline.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,14 +284,47 @@ TEST(proc_cmdline_filter_pid1_args) {
284284
test_proc_cmdline_filter_pid1_args_one("systemd\0",
285285
STRV_MAKE_EMPTY);
286286

287+
/* short option */
287288
test_proc_cmdline_filter_pid1_args_one("systemd\0"
288-
"hoge\0"
289+
"-a\0" /* unknown option */
290+
"-abc\0" /* unknown options */
291+
"-h\0" /* known option */
292+
"-hDbs\0" /* known options */
293+
"-hsx\0" /* mixed (known and unknown) options */
294+
"-z\0drop1\0" /* option with argument */
295+
"-z\0-z\0accept1\0" /* the second -z is handled as argument */
296+
"-az\0drop2\0" /* options with argument */
297+
"-za\0accept2\0" /* options with argument */
298+
"-z\0--\0-x\0", /* "--" is handled as argument */
299+
STRV_MAKE("accept1", "accept2"));
300+
301+
/* long option */
302+
test_proc_cmdline_filter_pid1_args_one("systemd\0"
303+
"--unknown\0accept1\0" /* unknown option */
304+
"--system\0accept2\0" /* no argument */
305+
"--log-level\0drop1\0" /* required argument (separated with space) */
306+
"--log-level=drop2\0accept3\0" /* required argument (concatenated with '=') */
307+
"--log-level\0--log-level\0accept4\0" /* the second "--log-level" is handled as argument */
308+
"--log-level\0--\0-x\0" /* "--" is handled as argument */
309+
"--log-color\0--log-level\0drop3\0" /* optional argument ("--log-level" is handled as another option) */
310+
"--log-color\0accept5\0" /* optional argument (separated with space) */
311+
"--log-color=drop4\0accept6\0" /* optional argument (concatenated with '=') */
312+
"--log-color\0--\0" /* "--" is _not_ handled as argument, and remaining strings are accepted */
313+
"remaining\0-x\0--foo\0",
314+
STRV_MAKE("accept1", "accept2", "accept3", "accept4", "accept5", "accept6", "remaining", "-x", "--foo"));
315+
316+
/* test for "--" */
317+
test_proc_cmdline_filter_pid1_args_one("systemd\0"
318+
"-a\0"
319+
"--dropped\0"
320+
"--\0" /* remaining strings are accepted */
289321
"-x\0"
290-
"foo\0"
291-
"--aaa\0"
292-
"var\0",
293-
STRV_MAKE("hoge", "foo", "var"));
322+
"-abc\0"
323+
"--hoge\0"
324+
"accepted\0",
325+
STRV_MAKE("-x", "-abc", "--hoge", "accepted"));
294326

327+
/* test for space */
295328
test_proc_cmdline_filter_pid1_args_one("/usr/lib/systemd/systemd\0"
296329
"--switched-root\0"
297330
"--system\0"

units/systemd-battery-check.service.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Description=Check battery level during early boot
1212
Documentation=man:systemd-battery-check.service(8)
1313
ConditionVirtualization=no
1414
ConditionDirectoryNotEmpty=/sys/class/power_supply/
15+
ConditionKernelCommandLine=!systemd.battery-check=0
1516
AssertPathExists=/etc/initrd-release
1617
DefaultDependencies=no
1718
After=plymouth-start.service

0 commit comments

Comments
 (0)