Package: util-linux
Version: 2.28.1-1
Severity: wishlist

Hi!
Please advise where to put the attached program.  It fixes the problem when
you connect to a serial console and your terminal size is not exactly 80x24.

If the terminal driver's idea of terminal size doesn't match reality,
there's nastiness that ranges from premature wrapping (horizontally and
vertically) to screen corruption of full-screen programs, having to edit
long commands in bash mostly blindly, etc.  Thus, this program queries the
terminal and stty-s the result.

Alas, this cannot be done unconditionally as the thing attached to the other
side of a serial console isn't always a terminal.  Some might not support
reporting cursor position (I made a timeout of 3 seconds), some expect-likes
might be confused by unknown ANSI codes, some unconditionally blast commands
(the first one would be partially eaten).  Thus, my fix needs to be
requested by the user.


This thingy is way probably way too small for a separate package.

As it fixes a deficiency of getty, it'd be nice to have it next to that.  On
the other hand, one shouldn't thoughtlessly bloat an essential package.

Third option would be patching this into getty, enabled by a command-line
switch.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>

struct termios  saved_attributes;
int             saved_fl;

void tty_raw()
{
    struct termios tattr;

    fcntl(0,F_GETFL,&saved_fl);
    tcgetattr(0, &saved_attributes);

    fcntl(0,F_SETFL,O_NONBLOCK);
    memcpy(&tattr,&saved_attributes,sizeof(struct termios));
    tattr.c_lflag &= ~(ICANON|ECHO);
    tattr.c_cc[VMIN] = 1;
    tattr.c_cc[VTIME] = 0;
    tcsetattr(0, TCSAFLUSH, &tattr);
}

void tty_restore()
{
    fcntl(0,F_SETFL,saved_fl);
    tcsetattr(0, TCSANOW, &saved_attributes);
}

int select_wait()
{
    struct timeval  tv;
    fd_set          se;

    FD_ZERO(&se);
    FD_SET(0,&se);
    tv.tv_sec = 3;
    tv.tv_usec = 0;
    return select(1,&se,NULL,NULL,&tv);
}

int main(int argc, char **argv)
{
    // as a side effect, the scrolling region is set to the entire screen
    static char *teststr = "\e7\e[r\e[999E\e[999C";
    static char *cleanup = "\e8";
    static char *getpos  = "\033[6n";
    char retstr[16];
    int pos,rc,row,col;
    struct winsize ws;

    if (!isatty(0) || !isatty(1))
        exit(2);

    tty_raw();
    write(1,teststr,strlen(teststr));
    write(1,getpos,strlen(getpos));
    for (pos = 0; pos < sizeof(retstr)-1;)
    {
        if (0 == select_wait())
            break;
        if (-1 == (rc = read(0,retstr+pos,sizeof(retstr)-1-pos)))
        {
            perror("read");
            exit(2);
        }
        pos += rc;
        if (retstr[pos-1] == 'R')
            break;
    }
    retstr[pos] = 0;
    write(1,cleanup,strlen(cleanup));
    tty_restore();

    rc = sscanf(retstr,"\033[%d;%dR",&row,&col);
    printf("Terminal size: %dx%d\n", col, row);
    memset(&ws, 0, sizeof(struct winsize));
    ioctl(1,TIOCGWINSZ,&ws);
    ws.ws_row=row;
    ws.ws_col=col;
    ioctl(1,TIOCSWINSZ,&ws);
    exit(0);
}

Reply via email to