/* * fixterm * * This program queries the terminal for its dimensions, and updates * the kernel's notion of this tty's dimensions accordingly. Most * modern remote login tools (i.e. ssh) handle this behind the scenes, * but this program can still come in handy if you are using a serial * connection. * * Compile with: gcc -o fixterm fixterm.c * * Written by David Simmons, June 2008 * http://davidsimmons.com/ * * This program is in the public domain. No rights are asserted. * The author assumes no responsibility for any damage caused by the * use or posession of this program. Use at your own risk. * */ #include #include #include #include #include #include #include #define BUFFER_SIZE (32) #define NUM_PARAMS (5) struct termio old_term; /* * set_raw() * * Put the terminal into raw mode, saving the * previous terminal state so we can later restore it. */ void set_raw() { struct termio new_term; if (ioctl(1, TCGETA, &old_term) == -1) { fprintf(stderr, "error: cannot get tty status\n"); exit(10); } memcpy(&new_term, &old_term, sizeof(struct termio)); new_term.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); new_term.c_cc[VMIN] = 0; new_term.c_cc[VTIME] = 0; if (ioctl(1, TCSETA, &new_term) == -1) { fprintf(stderr, "error: cannot put terminal in raw mode\n"); exit(10); } } /* * set_cooked() * * Return the terminal to cooked mode, by restoring the * state we saved in set_raw(). */ void set_cooked() { if (ioctl(1, TCSETA, &old_term) == -1) { fprintf(stderr, "error: cannot return terminal to cooked mode\n"); exit(10); } } /* * set_window_size() * * Set the kernel's notion of this terminal's dimensions. */ void set_window_size(int w, int h) { struct winsize ws; if (ioctl(1, TIOCGWINSZ, &ws) == -1) { fprintf( stderr, "error: cannot query the terminal's current notion of its " "window size\n" ); set_cooked(); exit(10); } ws.ws_col = w; ws.ws_row = h; if (ioctl(1, TIOCSWINSZ, &ws) == -1) { fprintf(stderr, "error: cannot set the window size\n"); set_cooked(); exit(10); } } /* * Exit the program if we get a SIGALRM, * indicating a timeout. */ void handle_alarm(int x) { fprintf( stderr, "error: timeout while waiting for a response from your " "terminal.\n" ); set_cooked(); exit(2); } /* * Clean up if we get a terminating signal * (SIGTERM or SIGINTR) */ void handle_abort(int x) { set_cooked(); exit(3); } /* * debug routines */ void debug_parameters(int count, int *params) { int i; printf("parameters: "); for (i=0; i 20) { goto parse_error; } else { usleep(50000); } continue; } *bp = c; bp++; switch (state) { case 0: if (c == 27) { state = 1; continue; } else { goto parse_error; } break; case 1: if (c == '[') { state = 2; param_start = bp; continue; } else { goto parse_error; } break; case 2: if (c == 't') { state = 3; } if (bp >= (buffer + BUFFER_SIZE - 1)) { goto parse_error; } if (c == ';') { /* process parameter */ if (param_index >= NUM_PARAMS) { goto parse_error; } params[param_index] = atoi(param_start); param_start=bp; param_index++; } break; } if (state == 3) { break; } } *bp = '\0'; /* process last param */ if (param_index >= NUM_PARAMS) { goto parse_error; } params[param_index] = atoi(param_start); param_start=bp; param_index++; /* note width and height */ int width, height; if (param_index == 2) { /* gnome terminal doesn't send the required first parameter "8", grr */ height = params[0]; width = params[1]; } else if ((param_index == 3) && (params[0] == 8)) { /* for xterm and others */ height = params[1]; width = params[2]; } else { /* something unexpected happened */ set_cooked(); fprintf(stderr, "error: received unexpected parameters.\n"); debug_parameters(param_index, params); debug_buffer(buffer, bp); exit(13); } printf("setting terminal to %dx%d\n", width, height); /* apply the received window size to the terminal */ set_window_size(width, height); /* clean up and exit */ set_cooked(); exit(0); parse_error: set_cooked(); if (buffer == bp) { fprintf( stderr, "error: no response received from your terminal.\n" ); } else { fprintf( stderr, "error: cannot parse the response from your terminal.\n" ); debug_buffer(buffer, bp); } exit(1); }