From be994c2640d806eaecaaabf7d79ec7080c42dd3a Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 29 Jun 2023 02:43:17 +0900 Subject: [PATCH] battery-check: several follow-ups Follow-ups for e3d4148d50909119c4e9327e6ad96d3ca7f4661a. - 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... --- man/initrd-battery-check.service.xml | 72 +++++++++++++ man/rules/meson.build | 2 +- man/systemd-battery-check.xml | 63 ----------- src/basic/glyph-util.h | 8 +- src/battery-check/battery-check.c | 129 +++++++++++++---------- test/units/testsuite-74.battery-check.sh | 9 ++ units/initrd-battery-check.service.in | 2 +- 7 files changed, 161 insertions(+), 124 deletions(-) create mode 100644 man/initrd-battery-check.service.xml delete mode 100644 man/systemd-battery-check.xml create mode 100755 test/units/testsuite-74.battery-check.sh diff --git a/man/initrd-battery-check.service.xml b/man/initrd-battery-check.service.xml new file mode 100644 index 0000000000..582b2269fb --- /dev/null +++ b/man/initrd-battery-check.service.xml @@ -0,0 +1,72 @@ + + + + + + + + systemd-battery-check + systemd + + + + initrd-battery-check.service + 8 + + + + initrd-battery-check.service + systemd-battery-check + Check battery level whether there's enough charge, and power off if not. + + + + initrd-battery-check.service + + /usr/lib/systemd/systemd-battery-check + OPTIONS + + + + + Description + + + initrd-battery-check.service 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. + + + systemd-battery-check 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. + + + + + Options + + The following options are understood by systemd-battery-check: + + + + + + + + + Exit status + + + On success (running on AC power or battery capacity greater than 5%), 0 is returned, a non-zero failure + code otherwise. + + + + + See Also + + systemd1 + + + + diff --git a/man/rules/meson.build b/man/rules/meson.build index f924f551eb..e5a36c43d8 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -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'], @@ -887,7 +888,6 @@ manpages = [ ''], ['systemd-ask-password', '1', [], ''], ['systemd-backlight@.service', '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', diff --git a/man/systemd-battery-check.xml b/man/systemd-battery-check.xml deleted file mode 100644 index 58719c795c..0000000000 --- a/man/systemd-battery-check.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - systemd-battery-check - systemd - - - - systemd-battery-check - 1 - - - - systemd-battery-check - Checks battery level to see whether there's enough charge. - - - - - systemd-battery-check - OPTIONS - - - - - Description - - systemd-battery-check 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. - The tool 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. - - - - Options - - The following options are understood: - - - - - - - - - Exit status - - On success (running on AC power or battery capacity greater than 5%), 0 is returned, a non-zero failure code otherwise. - - - - See Also - - systemd1 - - - - diff --git a/src/basic/glyph-util.h b/src/basic/glyph-util.h index 876a5a91e6..e26ef64c18 100644 --- a/src/basic/glyph-util.h +++ b/src/basic/glyph-util.h @@ -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); } diff --git a/src/battery-check/battery-check.c b/src/battery-check/battery-check.c index 14bb870ca4..ca13251ae0 100644 --- a/src/battery-check/battery-check.c +++ b/src/battery-check/battery-check.c @@ -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[]) { @@ -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(); @@ -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) @@ -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); diff --git a/test/units/testsuite-74.battery-check.sh b/test/units/testsuite-74.battery-check.sh new file mode 100755 index 0000000000..ec5a0c86e6 --- /dev/null +++ b/test/units/testsuite-74.battery-check.sh @@ -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 || : diff --git a/units/initrd-battery-check.service.in b/units/initrd-battery-check.service.in index 4b14049746..052586f3c7 100644 --- a/units/initrd-battery-check.service.in +++ b/units/initrd-battery-check.service.in @@ -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 -- 2.25.1