Skip to content

Commit

Permalink
battery-check: several follow-ups
Browse files Browse the repository at this point in the history
Follow-ups for e3d4148.

- add reference to initrd-battery-check.service in man page, and move
  its section from 1 to 8,
- add link to man page in help message,
- introduce ERRNO_IS_NO_PLYMOUTH(),
- propagate error in battery_check_send_plymouth_message(),
- rename battery_check_send_plymouth_message() -> plymouth_send_message(),
- return earlier when the first battery level check passed to reduce
  indentation,
- fix potential use of invalid fd on battery restored,
- do not use emoji for /dev/console,
- add simple test (mostly for coverity),

etc, etc...
  • Loading branch information
yuwata committed Jun 29, 2023
1 parent d625f71 commit be994c2
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 124 deletions.
72 changes: 72 additions & 0 deletions man/initrd-battery-check.service.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->

<refentry id="initrd-battery-check.service" xmlns:xi="http://www.w3.org/2001/XInclude">

<refentryinfo>
<title>systemd-battery-check</title>
<productname>systemd</productname>
</refentryinfo>

<refmeta>
<refentrytitle>initrd-battery-check.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>

<refnamediv>
<refname>initrd-battery-check.service</refname>
<refname>systemd-battery-check</refname>
<refpurpose>Check battery level whether there's enough charge, and power off if not.</refpurpose>
</refnamediv>

<refsynopsisdiv>
<para><filename>initrd-battery-check.service</filename></para>
<cmdsynopsis>
<command>/usr/lib/systemd/systemd-battery-check</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
</cmdsynopsis>
</refsynopsisdiv>

<refsect1>
<title>Description</title>

<para>
<filename>initrd-battery-check.service</filename> is used to check the battery level during the early
boot stage to determine whether there's sufficient battery power to carry on with the booting process.
</para>
<para>
<command>systemd-battery-check</command> returns success if the device is connected to an AC power
source or if the battery charge is greater than 5%. It returns failure otherwise.
</para>
</refsect1>

<refsect1>
<title>Options</title>

<para>The following options are understood by <command>systemd-battery-check</command>:</para>

<variablelist>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>

<refsect1>
<title>Exit status</title>

<para>
On success (running on AC power or battery capacity greater than 5%), 0 is returned, a non-zero failure
code otherwise.
</para>
</refsect1>

<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>

</refentry>
2 changes: 1 addition & 1 deletion man/rules/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ manpages = [
['hostname', '5', [], ''],
['hostnamectl', '1', [], 'ENABLE_HOSTNAMED'],
['hwdb', '7', [], 'ENABLE_HWDB'],
['initrd-battery-check.service', '8', ['systemd-battery-check'], ''],
['integritytab', '5', [], 'HAVE_LIBCRYPTSETUP'],
['iocost.conf', '5', [], ''],
['journal-remote.conf', '5', ['journal-remote.conf.d'], 'HAVE_MICROHTTPD'],
Expand Down Expand Up @@ -887,7 +888,6 @@ manpages = [
''],
['systemd-ask-password', '1', [], ''],
['[email protected]', '8', ['systemd-backlight'], 'ENABLE_BACKLIGHT'],
['systemd-battery-check', '1', [], ''],
['systemd-binfmt.service', '8', ['systemd-binfmt'], 'ENABLE_BINFMT'],
['systemd-bless-boot-generator', '8', [], 'ENABLE_BOOTLOADER'],
['systemd-bless-boot.service',
Expand Down
63 changes: 0 additions & 63 deletions man/systemd-battery-check.xml

This file was deleted.

8 changes: 2 additions & 6 deletions src/basic/glyph-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,14 @@ typedef enum SpecialGlyph {
_SPECIAL_GLYPH_INVALID = -EINVAL,
} SpecialGlyph;

const char *special_glyph_full(SpecialGlyph code, bool force_utf) _const_;

bool emoji_enabled(void);

const char *special_glyph_full(SpecialGlyph code, bool force_utf) _const_;

static inline const char *special_glyph(SpecialGlyph code) {
return special_glyph_full(code, false);
}

static inline const char *special_glyph_force_utf(SpecialGlyph code) {
return special_glyph_full(code, true);
}

static inline const char *special_glyph_check_mark(bool b) {
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
}
Expand Down
129 changes: 76 additions & 53 deletions src/battery-check/battery-check.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,47 +14,74 @@
#include "io-util.h"
#include "log.h"
#include "main-func.h"
#include "pretty-print.h"
#include "socket-util.h"
#include "terminal-util.h"
#include "time-util.h"

#define BATTERY_LOW_MESSAGE \
"Battery level critically low. Please connect your charger or the system will power off in 10 seconds."
#define BATTERY_RESTORED_MESSAGE \
"A.C. power restored, continuing."

static int help(void) {
_cleanup_free_ char *link = NULL;
int r;

r = terminal_urlify_man("systemd-battery-check", "8", &link);
if (r < 0)
return log_oom();

static void help(void) {
printf("%s\n\n"
"Checks battery level to see whether there's enough charge.\n\n"
"%sCheck battery level to see whether there's enough charge.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n",
program_invocation_short_name);
" --version Show package version\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);

return 0;
}

static void battery_check_send_plymouth_message(char *message, const char *mode) {
assert(message);
assert(mode);
static bool ERRNO_IS_NO_PLYMOUTH(int r) {
return IN_SET(abs(r), EAGAIN, ENOENT) || ERRNO_IS_DISCONNECT(r);
}

int r;
static int plymouth_send_message(const char *mode, const char *message) {
static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_close_ int fd = -EBADF;
_cleanup_free_ char *plymouth_message = NULL;
_cleanup_close_ int fd = -EBADF;
int c, r;

assert(mode);
assert(message);

int c = asprintf(&plymouth_message,
"C\x02%c%s%c"
"M\x02%c%s%c",
(int) strlen(mode) + 1, mode, '\x00',
(int) strlen(message) + 1, message, '\x00');
c = asprintf(&plymouth_message,
"C\x02%c%s%c"
"M\x02%c%s%c",
(int) strlen(mode) + 1, mode, '\x00',
(int) strlen(message) + 1, message, '\x00');
if (c < 0)
return (void) log_oom();
return log_oom();

/* We set SOCK_NONBLOCK here so that we rather drop the
* message than wait for plymouth */
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
return (void) log_warning_errno(errno, "socket() failed: %m");
return log_warning_errno(errno, "socket() failed: %m");

if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return (void) log_full_errno(IN_SET(errno, EAGAIN, ENOENT) || ERRNO_IS_DISCONNECT(errno) ? LOG_DEBUG : LOG_WARNING, errno, "Connection to plymouth failed: %m");
return log_full_errno(ERRNO_IS_NO_PLYMOUTH(errno) ? LOG_DEBUG : LOG_WARNING, errno,
"Failed to connect to plymouth: %m");

r = loop_write(fd, plymouth_message, c, /* do_poll = */ false);
if (r < 0)
return (void) log_full_errno(IN_SET(r, -EAGAIN, -ENOENT) || ERRNO_IS_DISCONNECT(r) ?
LOG_DEBUG : LOG_WARNING, r, "Failed to write to plymouth, ignoring: %m");
return log_full_errno(ERRNO_IS_NO_PLYMOUTH(r) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to write to plymouth: %m");

return 0;
}

static int parse_argv(int argc, char * argv[]) {
Expand All @@ -79,8 +106,7 @@ static int parse_argv(int argc, char * argv[]) {
switch (c) {

case 'h':
help();
return 0;
return help();

case ARG_VERSION:
return version();
Expand All @@ -100,10 +126,11 @@ static int parse_argv(int argc, char * argv[]) {
}

static int run(int argc, char *argv[]) {
_cleanup_free_ char *plymouth_message = NULL;
_cleanup_close_ int fd = -EBADF;
int r;

log_parse_environment();
log_open();
log_setup();

r = parse_argv(argc, argv);
if (r <= 0)
Expand All @@ -114,44 +141,40 @@ static int run(int argc, char *argv[]) {
log_warning_errno(r, "Failed to check battery status, ignoring: %m");
return 0;
}
if (r == 0)
return 0;

if (r > 0) {
_cleanup_close_ int fd = -EBADF;
_cleanup_free_ char *message = NULL, *plymouth_message = NULL, *ac_message = NULL;

if (asprintf(&message, "%s Battery level critically low. Please connect your charger or the system will power off in 10 seconds.", special_glyph(SPECIAL_GLYPH_LOW_BATTERY)) < 0)
return log_oom();
log_emergency("%s " BATTERY_LOW_MESSAGE, special_glyph(SPECIAL_GLYPH_LOW_BATTERY));

if (asprintf(&plymouth_message, "%s Battery level critically low. Please connect your charger or the system will power off in 10 seconds.", special_glyph_force_utf(SPECIAL_GLYPH_LOW_BATTERY)) < 0)
return log_oom();
fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
log_warning_errno(fd, "Failed to open console, ignoring: %m");
else
dprintf(fd, ANSI_HIGHLIGHT_RED "%s " BATTERY_LOW_MESSAGE ANSI_NORMAL "\n",
special_glyph_full(SPECIAL_GLYPH_LOW_BATTERY, /* force_utf = */ false));

log_emergency("%s", message);
if (asprintf(&plymouth_message, "%s " BATTERY_LOW_MESSAGE,
special_glyph_full(SPECIAL_GLYPH_LOW_BATTERY, /* force_utf = */ true)) < 0)
return log_oom();

fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
log_warning_errno(fd, "Failed to open console, ignoring: %m");
else
dprintf(fd, ANSI_HIGHLIGHT_RED "%s" ANSI_NORMAL "\n", message);
(void) plymouth_send_message("shutdown", plymouth_message);

battery_check_send_plymouth_message(plymouth_message, "shutdown");
sleep(10);
usleep_safe(10 * USEC_PER_SEC);

r = battery_is_discharging_and_low();
if (r > 0) {
log_emergency("Battery level critically low, powering off.");
return r;
}
if (r < 0)
return log_warning_errno(r, "Failed to check battery status, ignoring: %m");
r = battery_is_discharging_and_low();
if (r < 0)
return log_warning_errno(r, "Failed to check battery status, assuming not charged yet, powering off: %m");
if (r > 0) {
log_emergency("Battery level critically low, powering off.");
return r;
}

if (asprintf(&ac_message, "A.C. power restored, continuing") < 0)
return log_oom();
log_info(BATTERY_RESTORED_MESSAGE);
if (fd >= 0)
dprintf(fd, BATTERY_RESTORED_MESSAGE "\n");
(void) plymouth_send_message("boot-up", BATTERY_RESTORED_MESSAGE);

log_info("%s",ac_message);
dprintf(fd, "%s\n", ac_message);
battery_check_send_plymouth_message(ac_message, "boot-up");
}
return r;
return 0;
}

DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
9 changes: 9 additions & 0 deletions test/units/testsuite-74.battery-check.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: LGPL-2.1-or-later
set -eux
set -o pipefail

systemd-battery-check --help
systemd-battery-check --version

systemd-battery-check || :
2 changes: 1 addition & 1 deletion units/initrd-battery-check.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

[Unit]
Description=Check battery level during early boot
Documentation=man:systemd-battery-check(1)
Documentation=man:initrd-battery-check.service(8)
DefaultDependencies=no
AssertPathExists=/etc/initrd-release
Before=local-fs-pre.target
Expand Down

0 comments on commit be994c2

Please sign in to comment.