Merge branch 'setterm' of git://github.com/kerolasa/lelux-utiliteetit

* 'setterm' of git://github.com/kerolasa/lelux-utiliteetit:
  setterm: add --resize option
This commit is contained in:
Karel Zak 2017-01-04 12:27:27 +01:00
commit 912885d012
2 changed files with 118 additions and 1 deletions

View File

@ -228,6 +228,13 @@ Turns keyboard repeat on or off.
Displays the terminal reset string, which typically resets the terminal to
its power-on state.
.TP
\fB\-\-resize\fP
Reset terminal size by assessing maximum row and column. This is useful
when actual geometry and kernel terminal driver are not in sync. Most
notable use case is with serial consoles, that do not use
.BR ioctl (3)
but just byte streams and breaks.
.TP
\fB\-\-reverse\fP [\fBon\fP|\fBoff\fP]
Turns reverse video mode on or off. Except on a virtual console,
.B \-\-reverse off

View File

@ -75,6 +75,7 @@
# include <linux/tiocl.h>
#endif
#include "all-io.h"
#include "c.h"
#include "closestream.h"
#include "nls.h"
@ -182,7 +183,7 @@ struct setterm_control {
opt_appck_on:1, opt_invsc_on:1, opt_msg_on:1, opt_cl_all:1,
vcterm:1;
/* Option flags. Set when an option is invoked. */
uint64_t opt_term:1, opt_reset:1, opt_initialize:1, opt_cursor:1,
uint64_t opt_term:1, opt_reset:1, opt_resize:1, opt_initialize:1, opt_cursor:1,
opt_linewrap:1, opt_default:1, opt_foreground:1,
opt_background:1, opt_bold:1, opt_blink:1, opt_reverse:1,
opt_underline:1, opt_store:1, opt_clear:1, opt_blank:1,
@ -385,6 +386,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
fputs(USAGE_OPTIONS, out);
fputs(_(" --term <terminal_name> override TERM environment variable\n"), out);
fputs(_(" --reset reset terminal to power-on state\n"), out);
fputs(_(" --resize reset terminal rows and columns\n"), out);
fputs(_(" --initialize display init string, and use default settings\n"), out);
fputs(_(" --default use default terminal settings\n"), out);
fputs(_(" --store save current terminal settings as default\n"), out);
@ -437,6 +439,7 @@ static void parse_option(struct setterm_control *ctl, int ac, char **av)
enum {
OPT_TERM = CHAR_MAX + 1,
OPT_RESET,
OPT_RESIZE,
OPT_INITIALIZE,
OPT_CURSOR,
OPT_REPEAT,
@ -474,6 +477,7 @@ static void parse_option(struct setterm_control *ctl, int ac, char **av)
static const struct option longopts[] = {
{"term", required_argument, NULL, OPT_TERM},
{"reset", no_argument, NULL, OPT_RESET},
{"resize", no_argument, NULL, OPT_RESIZE},
{"initialize", no_argument, NULL, OPT_INITIALIZE},
{"cursor", required_argument, NULL, OPT_CURSOR},
{"repeat", required_argument, NULL, OPT_REPEAT},
@ -527,6 +531,9 @@ static void parse_option(struct setterm_control *ctl, int ac, char **av)
case OPT_RESET:
ctl->opt_reset = set_opt_flag(ctl->opt_reset);
break;
case OPT_RESIZE:
ctl->opt_resize = set_opt_flag(ctl->opt_resize);
break;
case OPT_INITIALIZE:
ctl->opt_initialize = set_opt_flag(ctl->opt_initialize);
break;
@ -815,6 +822,104 @@ static int vc_only(struct setterm_control *ctl, const char *err)
return ctl->vcterm;
}
static void tty_raw(struct termios *saved_attributes, int *saved_fl)
{
struct termios tattr;
fcntl(STDIN_FILENO, F_GETFL, saved_fl);
tcgetattr(STDIN_FILENO, saved_attributes);
fcntl(STDIN_FILENO, 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(STDIN_FILENO, TCSAFLUSH, &tattr);
}
static void tty_restore(struct termios *saved_attributes, int *saved_fl)
{
fcntl(STDIN_FILENO, F_SETFL, *saved_fl);
tcsetattr(STDIN_FILENO, TCSANOW, saved_attributes);
}
static int select_wait(void)
{
struct timeval tv;
fd_set set;
int ret;
FD_ZERO(&set);
FD_SET(STDIN_FILENO, &set);
tv.tv_sec = 10;
tv.tv_usec = 0;
while ((ret = select(1, &set, NULL, NULL, &tv)) < 0) {
if (errno == EINTR)
continue;
err(EXIT_FAILURE, _("select failed"));
}
return ret;
}
static int resizetty(void)
{
/*
* \e7 Save current state (cursor coordinates, attributes,
* character sets pointed at by G0, G1).
* \e[r Set scrolling region; parameters are top and bottom row.
* \e[32766E Move cursor down 32766 (INT16_MAX - 1) rows.
* \e[32766C Move cursor right 32766 columns.
* \e[6n Report cursor position.
* \e8 Restore state most recently saved by \e7.
*/
static const char *getpos = "\e7\e[r\e[32766E\e[32766C\e[6n\e8";
char retstr[32];
int row, col;
size_t pos;
ssize_t rc;
struct winsize ws;
struct termios saved_attributes;
int saved_fl;
if (!isatty(STDIN_FILENO))
errx(EXIT_FAILURE, _("stdin does not refer to a terminal"));
tty_raw(&saved_attributes, &saved_fl);
if (write_all(STDIN_FILENO, getpos, strlen(getpos)) < 0) {
warn(_("write failed"));
tty_restore(&saved_attributes, &saved_fl);
return 1;
}
for (pos = 0; pos < sizeof(retstr) - 1;) {
if (0 == select_wait())
break;
if ((rc =
read(STDIN_FILENO, retstr + pos,
sizeof(retstr) - 1 - pos)) < 0) {
if (errno == EINTR)
continue;
warn(_("read failed"));
tty_restore(&saved_attributes, &saved_fl);
return 1;
}
pos += rc;
if (retstr[pos - 1] == 'R')
break;
}
retstr[pos] = 0;
tty_restore(&saved_attributes, &saved_fl);
rc = sscanf(retstr, "\033[%d;%dR", &row, &col);
if (rc != 2) {
warnx(_("invalid cursor position: %s"), retstr);
return 1;
}
memset(&ws, 0, sizeof(struct winsize));
ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
ws.ws_row = row;
ws.ws_col = col;
ioctl(STDIN_FILENO, TIOCSWINSZ, &ws);
return 0;
}
static void perform_sequence(struct setterm_control *ctl)
{
int result;
@ -823,6 +928,11 @@ static void perform_sequence(struct setterm_control *ctl)
if (ctl->opt_reset)
putp(ti_entry("rs1"));
/* -resize. */
if (ctl->opt_resize)
if (resizetty())
warnx(_("reset failed"));
/* -initialize. */
if (ctl->opt_initialize)
putp(ti_entry("is2"));