5050
5151static pstyle_t progress_onoff = PROGRESS_DEFAULT ;
5252static pstyle_t progress_style = PROGRESS_DEFAULT ;
53+ static char last_desc [512 ]; /* saved description for re-print after interruption */
5354
5455#ifndef HOSTNAME_PATH
5556#define HOSTNAME_PATH "/etc/hostname"
@@ -336,6 +337,8 @@ void printv(const char *fmt, va_list ap)
336337 len = print_timestamp (buf , sizeof (buf ));
337338 vsnprintf (& buf [len ], sizeof (buf ) - len , fmt , ap );
338339
340+ strlcpy (last_desc , & buf [len ], sizeof (last_desc )); /* save for re-print */
341+
339342 if (progress_style == PROGRESS_CLASSIC )
340343 cprintf ("\r%s " , pad (buf , sizeof (buf ), "." , sizeof (buf )));
341344 else
@@ -344,24 +347,65 @@ void printv(const char *fmt, va_list ap)
344347
345348void print (int rc , const char * fmt , ...)
346349{
350+ char buf [ttcols ];
351+ size_t len ;
352+
347353 if (progress_style == PROGRESS_SILENT )
348354 return ;
349355
356+ buf [0 ] = 0 ;
357+ len = print_timestamp (buf , sizeof (buf ));
358+
350359 if (fmt ) {
351360 va_list ap ;
352361
353362 va_start (ap , fmt );
354- printv ( fmt , ap );
363+ vsnprintf ( & buf [ len ], sizeof ( buf ) - len , fmt , ap );
355364 va_end (ap );
365+ strlcpy (last_desc , & buf [len ], sizeof (last_desc ));
366+ } else if (rc >= 0 && last_desc [0 ]) {
367+ /*
368+ * No new description, but we have one saved from an earlier
369+ * print(-1, ...) call. Re-print it so the final status is not
370+ * left stranded if command output or a kernel message scrolled
371+ * away the original description line.
372+ */
373+ strlcpy (& buf [len ], last_desc , sizeof (buf ) - len );
374+ } else {
375+ buf [0 ] = 0 ;
356376 }
357377
358- if (rc < 0 )
378+ if (rc < 0 ) {
379+ /* Pending state: show description with spinner, no final status yet */
380+ if (!buf [0 ])
381+ return ;
382+ delline ();
383+ if (progress_style == PROGRESS_CLASSIC )
384+ cprintf ("\r%s " , pad (buf , sizeof (buf ), "." , sizeof (buf )));
385+ else
386+ cprintf ("\r\e[K%s%s" , status (3 ), buf );
359387 return ;
388+ }
360389
361- if (progress_style == PROGRESS_CLASSIC )
362- cprintf ("%s\n" , status (rc ));
363- else
364- cprintf ("\r%s\n" , status (rc ));
390+ /*
391+ * Final status. Emit description + status in a single cprintf() so
392+ * both reach the console in one write(), preventing kernel messages or
393+ * command output from splitting the description from its [ OK ]/[FAIL].
394+ */
395+ last_desc [0 ] = 0 ;
396+
397+ if (buf [0 ]) {
398+ delline ();
399+ if (progress_style == PROGRESS_CLASSIC )
400+ cprintf ("\r%s %s\n" , pad (buf , sizeof (buf ), "." , sizeof (buf )), status (rc ));
401+ else
402+ cprintf ("\r\e[K%s%s\r%s\n" , status (3 ), buf , status (rc ));
403+ } else {
404+ if (progress_style == PROGRESS_CLASSIC )
405+ cprintf ("%s\n" , status (rc ));
406+ else
407+ cprintf ("\r%s\n" , status (rc ));
408+ }
365409}
366410
367411void print_desc (char * action , char * desc )
@@ -375,6 +419,18 @@ int print_result(int fail)
375419 return fail ;
376420}
377421
422+ /*
423+ * Reset console state and drain the output buffer before kernel takeover.
424+ * Called just before reboot()/halt() to prevent ANSI escape codes from
425+ * leaking into bootloader or early-kernel output.
426+ */
427+ void print_exit (void )
428+ {
429+ tcdrain (STDERR_FILENO );
430+ dprint (STDERR_FILENO , "\e[0m\e[?25h" , 10 ); /* reset SGR, show cursor */
431+ tcdrain (STDERR_FILENO );
432+ }
433+
378434void set_hostname (char * * hostname )
379435{
380436 FILE * fp ;
0 commit comments