diff --git a/configure.ac b/configure.ac index faa52183..f1373966 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ AC_PROG_MKDIR_P # Configuration. AC_HEADER_STDC -AC_CHECK_HEADERS([fstaby.h termios.h]) +AC_CHECK_HEADERS([fstaby.h termios.h sys/ioctl.h]) AC_CHECK_FUNCS([strstr getopt getfsenty]) # Check for uint[8,16,32]_t diff --git a/src/finit.c b/src/finit.c index 9b270f03..42780ffa 100644 --- a/src/finit.c +++ b/src/finit.c @@ -478,10 +478,6 @@ int main(int argc, char *argv[]) chdir("/"); umask(0); - /* Set up canvas */ - if (!rescue && !debug) - screen_init(); - /* Allow progress, if enabled */ enable_progress(1); @@ -490,8 +486,10 @@ int main(int argc, char *argv[]) */ emergency_shell(); - /* Load plugins early, the first hook is in banner(), so we - * need plugins loaded before calling it. */ + /* + * Load plugins early, the first hook is in banner(), so we + * need plugins loaded before calling it. + */ plugin_init(&loop); /* diff --git a/src/helpers.c b/src/helpers.c index ad1943b9..48c3bcf6 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -121,7 +121,7 @@ static void add_console(char *cons) num_cons++; } -void console_init(void) +static void find_active_consoles(void) { char *cons, *ptr, *tok; char buf[512]; @@ -148,6 +148,12 @@ void console_init(void) } } +void console_init(void) +{ + find_active_consoles(); + screen_init(); +} + ssize_t cprintf(const char *fmt, ...) { const size_t len = strlen(fmt) * 2; diff --git a/src/log.c b/src/log.c index cc603a52..25581024 100644 --- a/src/log.c +++ b/src/log.c @@ -50,9 +50,7 @@ void log_exit(void) * Unless in debug mode at shutdown, Reinitialize screen, * terminal may have been resized at runtime */ - if (debug) - screen_exit(); - else + if (!debug) screen_init(); enable_progress(1); @@ -79,7 +77,6 @@ void log_debug(void) if (debug) { loglevel = LOG_DEBUG; - screen_exit(); } else { loglevel = LOG_NOTICE; screen_init(); diff --git a/src/util.c b/src/util.c index 0679126a..691d6b11 100644 --- a/src/util.c +++ b/src/util.c @@ -28,9 +28,15 @@ #include #include #include +#ifdef HAVE_TERMIOS_H +# include +#endif #include #include #include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif #include /* sysinfo() */ #include /* strlcat() */ #include "util.h" @@ -202,25 +208,66 @@ char *sanitize(char *arg, size_t len) } /* - * Called at boot, and shutdown, to (re)initialize the - * screen size for print() et al. + * Called by initctl, and by finit at boot and shutdown, to + * (re)initialize the screen size for print() et al. */ -void screen_init(void) +int screen_init(void) { - if (!isatty(STDOUT_FILENO)) - return; +#ifdef HAVE_TERMIOS_H + struct pollfd fd = { STDIN_FILENO, POLLIN, 0 }; + struct winsize ws = { 0 }; + struct termios tc, saved; - initscr(&screen_rows, &screen_cols); -} + /* + * Basic TTY init, CLOCaL is important or TIOCWINSZ will block + * until DCD is asserted, and we won't ever get it. + */ + tcgetattr(STDERR_FILENO, &tc); + saved = tc; + tc.c_cflag |= (CLOCAL | CREAD); + tc.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + tcsetattr(STDERR_FILENO, TCSANOW, &tc); -/* - * Called when debug mode is enabled to revert back - * to old-school safe defaults. - */ -void screen_exit(void) -{ - screen_rows = 24; - screen_cols = 80; + /* 1. Try TIOCWINSZ to query window size from kernel */ + if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws)) { + screen_rows = ws.ws_row; + screen_cols = ws.ws_col; + + /* Likely doesn't work in PID 1 after kernel starts us ... */ + if (!ws.ws_row && !ws.ws_col) + goto fallback; + } else if (!isatty(STDOUT_FILENO)) { + /* 2. We may be running under watch(1) */ + screen_cols = atonum(getenv("COLUMNS")); + screen_rows = atonum(getenv("LINES")); + } else { + fallback: + /* 3. ANSI goto + query cursor position trick as fallback */ + fprintf(stderr, "\e7\e[r\e[999;999H\e[6n"); + + if (poll(&fd, 1, 300) > 0) { + int row, col; + + if (scanf("\e[%d;%dR", &row, &col) == 2) { + screen_cols = col; + screen_rows = row; + } + } + + /* Jump back to where we started (\e7) */ + fprintf(stderr, "\e8"); + } + + tcsetattr(STDERR_FILENO, TCSANOW, &saved); + + /* Sanity check */ + if (screen_cols <= 0) + screen_cols = 80; + if (screen_rows <= 0) + screen_rows = 24; +#endif + + return screen_cols; } /** diff --git a/src/util.h b/src/util.h index 84c32379..93db68e0 100644 --- a/src/util.h +++ b/src/util.h @@ -55,9 +55,7 @@ char *uptime (long secs, char *buf, size_t len); char *sanitize (char *arg, size_t len); -void screen_init (void); -void screen_exit (void); -int screen_width (void); +int screen_init (void); static inline char *strterm(char *str, size_t len) {