Atomic print and re-print desc on status, flush before reboot

Refactor print() to emit description + final status in a single call to
cprintf(), preventing kernel messages from splitting the two parts.

For two-phase print(-1,...) + print_result() sequences used by, e.g.,
run_interactive, save the last description and re-print it before the
[ OK ] / [FAIL] output so the status is never left stranded on a blank
line when command output or kernel messages have scrolled away the
original description.

Finally, add print_exit() which drains the console output buffer with
tcdrain(2) and resets ANSI SGR attributes + cursor visibility before the
kernel takes back the console on reboot/halt, preventing escape code
leakage into bootloader or early-kernel output.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-04-07 11:36:19 +02:00
parent 50b9e46e19
commit 96f944b816
3 changed files with 66 additions and 6 deletions
+58 -2
View File
@@ -50,6 +50,7 @@
static pstyle_t progress_onoff = PROGRESS_DEFAULT;
static pstyle_t progress_style = PROGRESS_DEFAULT;
static char last_desc[512]; /* saved description for re-print after interruption */
#ifndef HOSTNAME_PATH
#define HOSTNAME_PATH "/etc/hostname"
@@ -336,6 +337,8 @@ void printv(const char *fmt, va_list ap)
len = print_timestamp(buf, sizeof(buf));
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
strlcpy(last_desc, &buf[len], sizeof(last_desc)); /* save for re-print */
if (progress_style == PROGRESS_CLASSIC)
cprintf("\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
else
@@ -344,25 +347,66 @@ void printv(const char *fmt, va_list ap)
void print(int rc, const char *fmt, ...)
{
char buf[ttcols];
size_t len;
if (progress_style == PROGRESS_SILENT)
return;
buf[0] = 0;
len = print_timestamp(buf, sizeof(buf));
if (fmt) {
va_list ap;
va_start(ap, fmt);
printv(fmt, ap);
vsnprintf(&buf[len], sizeof(buf) - len, fmt, ap);
va_end(ap);
strlcpy(last_desc, &buf[len], sizeof(last_desc));
} else if (rc >= 0 && last_desc[0]) {
/*
* No new description, but we have one saved from an earlier
* print(-1, ...) call. Re-print it so the final status is not
* left stranded if command output or a kernel message scrolled
* away the original description line.
*/
strlcpy(&buf[len], last_desc, sizeof(buf) - len);
} else {
buf[0] = 0;
}
if (rc < 0)
if (rc < 0) {
/* Pending state: show description with spinner, no final status yet */
if (!buf[0])
return;
delline();
if (progress_style == PROGRESS_CLASSIC)
cprintf("\r%s ", pad(buf, sizeof(buf), ".", sizeof(buf)));
else
cprintf("\r\e[K%s%s", status(3), buf);
return;
}
/*
* Final status. Emit description + status in a single cprintf() so
* both reach the console in one write(), preventing kernel messages or
* command output from splitting the description from its [ OK ]/[FAIL].
*/
last_desc[0] = 0;
if (buf[0]) {
delline();
if (progress_style == PROGRESS_CLASSIC)
cprintf("\r%s %s\n", pad(buf, sizeof(buf), ".", sizeof(buf)), status(rc));
else
cprintf("\r\e[K%s%s\r%s\n", status(3), buf, status(rc));
} else {
if (progress_style == PROGRESS_CLASSIC)
cprintf("%s\n", status(rc));
else
cprintf("\r%s\n", status(rc));
}
}
void print_desc(char *action, char *desc)
{
@@ -375,6 +419,18 @@ int print_result(int fail)
return fail;
}
/*
* Reset console state and drain the output buffer before kernel takeover.
* Called just before reboot()/halt() to prevent ANSI escape codes from
* leaking into bootloader or early-kernel output.
*/
void print_exit(void)
{
tcdrain(STDERR_FILENO);
dprint(STDERR_FILENO, "\e[0m\e[?25h", 10); /* reset SGR, show cursor */
tcdrain(STDERR_FILENO);
}
void set_hostname(char **hostname)
{
FILE *fp;
+1
View File
@@ -68,6 +68,7 @@ void printv (const char *fmt, va_list ap);
void print (int action, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
void print_desc (char *action, char *desc);
int print_result (int fail);
void print_exit (void);
void set_hostname (char **hostname);
void networking (int updown);
+3
View File
@@ -424,14 +424,17 @@ void do_shutdown(shutop_t op)
}
print(0, "Rebooting ...");
print_exit();
reboot(RB_AUTOBOOT);
} else if (op == SHUT_OFF) {
print(0, "Powering down ...");
print_exit();
reboot(RB_POWER_OFF);
}
/* Also fallback if any of the other two fails */
print(0, "Halting ...");
print_exit();
reboot(RB_HALT_SYSTEM);
}