battery-check: several follow-ups

Follow-ups for e3d4148d50.

- 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...
This commit is contained in:
Yu Watanabe
2023-06-29 15:41:00 +09:00
parent d625f717db
commit be994c2640
7 changed files with 166 additions and 129 deletions
+2 -6
View File
@@ -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);
}
+81 -58
View File
@@ -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;
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');
assert(mode);
assert(message);
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;
log_emergency("%s " BATTERY_LOW_MESSAGE, special_glyph(SPECIAL_GLYPH_LOW_BATTERY));
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));
if (asprintf(&plymouth_message, "%s " BATTERY_LOW_MESSAGE,
special_glyph_full(SPECIAL_GLYPH_LOW_BATTERY, /* force_utf = */ true)) < 0)
return log_oom();
(void) plymouth_send_message("shutdown", plymouth_message);
usleep_safe(10 * USEC_PER_SEC);
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) {
_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();
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();
log_emergency("%s", message);
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);
battery_check_send_plymouth_message(plymouth_message, "shutdown");
sleep(10);
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");
if (asprintf(&ac_message, "A.C. power restored, continuing") < 0)
return log_oom();
log_info("%s",ac_message);
dprintf(fd, "%s\n", ac_message);
battery_check_send_plymouth_message(ac_message, "boot-up");
log_emergency("Battery level critically low, powering off.");
return r;
}
return r;
log_info(BATTERY_RESTORED_MESSAGE);
if (fd >= 0)
dprintf(fd, BATTERY_RESTORED_MESSAGE "\n");
(void) plymouth_send_message("boot-up", BATTERY_RESTORED_MESSAGE);
return 0;
}
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);