]> git.ipfire.org Git - thirdparty/util-linux.git/blame - term-utils/setterm.c
libfdisk: (dos) add ID related debug messages
[thirdparty/util-linux.git] / term-utils / setterm.c
CommitLineData
6dbe3af9
KZ
1/* setterm.c, set terminal attributes.
2 *
3 * Copyright (C) 1990 Gordon Irlam (gordoni@cs.ua.oz.au). Conditions of use,
4 * modification, and redistribution are contained in the file COPYRIGHT that
5 * forms part of this distribution.
6 *
7 * Adaption to Linux by Peter MacDonald.
8 *
9 * Enhancements by Mika Liljeberg (liljeber@cs.Helsinki.FI)
10 *
fd6b7a7f
KZ
11 * Beep modifications by Christophe Jolif (cjolif@storm.gatelink.fr.net)
12 *
13 * Sanity increases by Cafeine Addict [sic].
14 *
eb63b9b8 15 * Powersave features by todd j. derr <tjd@wordsmith.org>
fd6b7a7f
KZ
16 *
17 * Converted to terminfo by Kars de Jong (jongk@cs.utwente.nl)
6dbe3af9 18 *
b50945d4 19 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c
KZ
20 * - added Native Language Support
21 *
6dbe3af9
KZ
22 * Semantics:
23 *
fd6b7a7f 24 * Setterm writes to standard output a character string that will
871ffd09 25 * invoke the specified terminal capabilities. Where possible
fd6b7a7f
KZ
26 * terminfo is consulted to find the string to use. Some options
27 * however do not correspond to a terminfo capability. In this case if
28 * the terminal type is "con*", or "linux*" the string that invokes
29 * the specified capabilities on the PC Linux virtual console driver
30 * is output. Options that are not implemented by the terminal are
31 * ignored.
6dbe3af9
KZ
32 *
33 * The following options are non-obvious.
34 *
35 * -term can be used to override the TERM environment variable.
36 *
37 * -reset displays the terminal reset string, which typically resets the
38 * terminal to its power on state.
39 *
40 * -initialize displays the terminal initialization string, which typically
41 * sets the terminal's rendering options, and other attributes to the
42 * default values.
43 *
44 * -default sets the terminal's rendering options to the default values.
45 *
46 * -store stores the terminal's current rendering options as the default
fd6b7a7f 47 * values. */
6dbe3af9 48
104ecc7e
SK
49#include <ctype.h>
50#include <errno.h>
51#include <fcntl.h>
45c90b77 52#include <getopt.h>
6dbe3af9 53#include <stdio.h>
22853e4a 54#include <stdlib.h>
6dbe3af9 55#include <string.h>
104ecc7e
SK
56#include <sys/ioctl.h>
57#include <sys/klog.h>
58#include <sys/param.h> /* for MAXPATHLEN */
59#include <sys/time.h>
60#include <termios.h>
61#include <unistd.h>
bfc4331b 62
5c36a0eb 63#ifndef NCURSES_CONST
104ecc7e 64# define NCURSES_CONST const /* define before including term.h */
5c36a0eb 65#endif
48d7b13a 66#ifdef HAVE_NCURSES_H
104ecc7e 67# include <ncurses.h>
b6e899d9 68#elif defined(HAVE_NCURSES_NCURSES_H)
104ecc7e 69# include <ncurses/ncurses.h>
fd6b7a7f 70#endif
bfc4331b
MF
71/* must include after ncurses.h */
72#include <term.h>
48d7b13a 73
5c55d9bf 74#ifdef HAVE_LINUX_TIOCL_H
104ecc7e 75# include <linux/tiocl.h>
5c55d9bf 76#endif
b6e899d9 77
5d795999 78#include "all-io.h"
b6e899d9 79#include "c.h"
cdd2a8c3 80#include "closestream.h"
104ecc7e 81#include "nls.h"
11f69359 82#include "optutils.h"
35b578a0 83#include "strutils.h"
104ecc7e 84#include "xalloc.h"
6dbe3af9 85
fd6b7a7f 86/* Constants. */
6dbe3af9 87
261f1423
SK
88/* Non-standard return values. */
89#define EXIT_DUMPFILE -1
90
6dbe3af9 91/* Colors. */
010f219d
SK
92enum {
93 BLACK = 0,
94 RED,
95 GREEN,
96 YELLOW,
97 BLUE,
98 MAGENTA,
99 CYAN,
100 WHITE,
101 GREY,
102 DEFAULT
103};
6dbe3af9 104
98297e65
KZ
105static const char *colornames[] = {
106 [BLACK] = "black",
107 [RED] = "red",
108 [GREEN] = "green",
109 [YELLOW]= "yellow",
110 [BLUE] = "blue",
111 [MAGENTA]="magenta",
112 [CYAN] = "cyan",
113 [WHITE] = "white",
114 [GREY] = "grey",
115 [DEFAULT] = "default"
116};
117
118#define is_valid_color(x) (x >= 0 && (size_t) x < ARRAY_SIZE(colornames))
119
5c55d9bf 120/* Blank commands */
010f219d
SK
121enum {
122 BLANKSCREEN = -1,
123 UNBLANKSCREEN = -2,
124 BLANKEDSCREEN = -3
125};
5c55d9bf
ST
126
127/* <linux/tiocl.h> fallback */
128#ifndef TIOCL_BLANKSCREEN
010f219d
SK
129enum {
130 TIOCL_UNBLANKSCREEN = 4, /* unblank screen */
131 TIOCL_SETVESABLANK = 10, /* set vesa blanking mode */
132 TIOCL_BLANKSCREEN = 14, /* keep screen blank even if a key is pressed */
133 TIOCL_BLANKEDSCREEN = 15 /* return which vt was blanked */
134};
5c55d9bf
ST
135#endif
136
3393c136
SK
137/* Powersave modes */
138enum {
139 VESA_BLANK_MODE_OFF = 0,
140 VESA_BLANK_MODE_SUSPENDV,
141 VESA_BLANK_MODE_SUSPENDH,
142 VESA_BLANK_MODE_POWERDOWN
143};
144
145/* klogctl() actions */
146enum {
147 SYSLOG_ACTION_CONSOLE_OFF = 6,
148 SYSLOG_ACTION_CONSOLE_ON = 7,
149 SYSLOG_ACTION_CONSOLE_LEVEL = 8
150};
151
152/* Console log levels */
153enum {
91746583 154 CONSOLE_LEVEL_MIN = 0,
3393c136
SK
155 CONSOLE_LEVEL_MAX = 8
156};
157
158/* Various numbers */
159#define DEFAULT_TAB_LEN 8
160#define BLANK_MAX 60
161#define TABS_MAX 160
162#define BLENGTH_MAX 2000
163
341566ff 164/* Command controls. */
d87d20b0
SK
165struct setterm_control {
166 char *opt_te_terminal_name; /* terminal name */
167 int opt_bl_min; /* blank screen */
168 int opt_blength_l; /* bell duration in milliseconds */
169 int opt_bfreq_f; /* bell frequency in Hz */
9e930041 170 int opt_sn_num; /* console number to be snapshot */
d87d20b0 171 char *opt_sn_name; /* path to write snap */
341566ff 172 char *in_device; /* device to snapshot */
9e930041 173 int opt_msglevel_num; /* printk() logging level */
d87d20b0
SK
174 int opt_ps_mode; /* powersave mode */
175 int opt_pd_min; /* powerdown time */
176 int opt_rt_len; /* regular tab length */
177 int opt_tb_array[TABS_MAX + 1]; /* array for tab list */
178 /* colors */
179 int opt_fo_color:4, opt_ba_color:4, opt_ul_color:4, opt_hb_color:4;
180 /* boolean options */
d8c1fc7a
SK
181 unsigned int opt_cu_on:1, opt_li_on:1, opt_bo_on:1, opt_hb_on:1,
182 opt_bl_on:1, opt_re_on:1, opt_un_on:1, opt_rep_on:1,
183 opt_appck_on:1, opt_invsc_on:1, opt_msg_on:1, opt_cl_all:1,
184 vcterm:1;
d87d20b0 185 /* Option flags. Set when an option is invoked. */
5d795999 186 uint64_t opt_term:1, opt_reset:1, opt_resize:1, opt_initialize:1, opt_cursor:1,
d87d20b0
SK
187 opt_linewrap:1, opt_default:1, opt_foreground:1,
188 opt_background:1, opt_bold:1, opt_blink:1, opt_reverse:1,
189 opt_underline:1, opt_store:1, opt_clear:1, opt_blank:1,
190 opt_snap:1, opt_snapfile:1, opt_append:1, opt_ulcolor:1,
191 opt_hbcolor:1, opt_halfbright:1, opt_repeat:1, opt_tabs:1,
192 opt_clrtabs:1, opt_regtabs:1, opt_appcursorkeys:1,
193 opt_inversescreen:1, opt_msg:1, opt_msglevel:1, opt_powersave:1,
194 opt_powerdown:1, opt_blength:1, opt_bfreq:1;
195};
6dbe3af9 196
98297e65
KZ
197static int parse_color(const char *arg)
198{
199 size_t i;
200
201 for (i = 0; i < ARRAY_SIZE(colornames); i++) {
202 if (strcmp(colornames[i], arg) == 0)
203 return i;
204 }
205
206 return -EINVAL;
207}
208
45c90b77
SK
209static int parse_febg_color(const char *arg)
210{
98297e65 211 int color = parse_color(arg);
35b578a0 212
98297e65 213 if (color < 0)
35b578a0 214 color = strtos32_or_err(arg, _("argument error"));
98297e65
KZ
215
216 if (!is_valid_color(color) || color == GREY)
c8a6f83e 217 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
35b578a0 218 return color;
6dbe3af9
KZ
219}
220
ef4d11d5 221static int parse_ulhb_color(char **av, int *oi)
45c90b77
SK
222{
223 char *color_name;
224 int bright = 0;
225 int color = -1;
226
ef4d11d5 227 if (av[*oi] && strcmp(av[*oi - 1], "bright") == 0) {
45c90b77 228 bright = 1;
ef4d11d5
SK
229 color_name = av[*oi];
230 (*oi)++;
45c90b77 231 } else
ef4d11d5 232 color_name = av[*oi - 1];
45c90b77 233
98297e65
KZ
234 color = parse_color(color_name);
235 if (color < 0)
35b578a0 236 color = strtos32_or_err(color_name, _("argument error"));
98297e65 237 if (!is_valid_color(color))
c8a6f83e 238 errx(EXIT_FAILURE, "%s: %s", _("argument error"), color_name);
45c90b77
SK
239 if (bright && (color == BLACK || color == GREY))
240 errx(EXIT_FAILURE, _("argument error: bright %s is not supported"), color_name);
241
242 return color;
6dbe3af9
KZ
243}
244
ef4d11d5 245static char *find_optional_arg(char **av, char *oa, int *oi)
45c90b77
SK
246{
247 char *arg;
ef4d11d5
SK
248 if (oa)
249 return oa;
45c90b77 250 else {
ef4d11d5 251 arg = av[*oi];
45c90b77
SK
252 if (!arg || arg[0] == '-')
253 return NULL;
22853e4a 254 }
ef4d11d5 255 (*oi)++;
45c90b77 256 return arg;
6dbe3af9
KZ
257}
258
ef4d11d5 259static int parse_blank(char **av, char *oa, int *oi)
45c90b77
SK
260{
261 char *arg;
262
ef4d11d5 263 arg = find_optional_arg(av, oa, oi);
45c90b77
SK
264 if (!arg)
265 return BLANKEDSCREEN;
266 if (!strcmp(arg, "force"))
267 return BLANKSCREEN;
268 else if (!strcmp(arg, "poke"))
269 return UNBLANKSCREEN;
270 else {
35b578a0 271 int ret;
45c90b77 272
35b578a0 273 ret = strtos32_or_err(arg, _("argument error"));
45c90b77 274 if (ret < 0 || BLANK_MAX < ret)
c8a6f83e 275 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
45c90b77 276 return ret;
22853e4a 277 }
6dbe3af9
KZ
278}
279
45c90b77
SK
280static int parse_powersave(const char *arg)
281{
282 if (strcmp(arg, "on") == 0)
283 return VESA_BLANK_MODE_SUSPENDV;
284 else if (strcmp(arg, "vsync") == 0)
285 return VESA_BLANK_MODE_SUSPENDV;
286 else if (strcmp(arg, "hsync") == 0)
287 return VESA_BLANK_MODE_SUSPENDH;
288 else if (strcmp(arg, "powerdown") == 0)
289 return VESA_BLANK_MODE_POWERDOWN;
290 else if (strcmp(arg, "off") == 0)
291 return VESA_BLANK_MODE_OFF;
c8a6f83e 292 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
fd6b7a7f
KZ
293}
294
45c90b77
SK
295static int parse_msglevel(const char *arg)
296{
35b578a0 297 int ret;
6dbe3af9 298
35b578a0 299 ret = strtos32_or_err(arg, _("argument error"));
45c90b77 300 if (ret < CONSOLE_LEVEL_MIN || CONSOLE_LEVEL_MAX < ret)
c8a6f83e 301 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
45c90b77 302 return ret;
6dbe3af9
KZ
303}
304
ef4d11d5 305static int parse_snap(char **av, char *oa, int *oi)
45c90b77 306{
35b578a0 307 int ret;
45c90b77
SK
308 char *arg;
309
ef4d11d5 310 arg = find_optional_arg(av, oa, oi);
45c90b77
SK
311 if (!arg)
312 return 0;
35b578a0 313 ret = strtos32_or_err(arg, _("argument error"));
45c90b77 314 if (ret < 1)
c8a6f83e 315 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
45c90b77 316 return ret;
6dbe3af9
KZ
317}
318
ef4d11d5 319static void parse_tabs(char **av, char *oa, int *oi, int *tab_array)
45c90b77
SK
320{
321 int i = 0;
6dbe3af9 322
ef4d11d5
SK
323 if (oa) {
324 tab_array[i] = strtos32_or_err(oa, _("argument error"));
45c90b77 325 i++;
22853e4a 326 }
ef4d11d5 327 while (av[*oi]) {
45c90b77
SK
328 if (TABS_MAX < i)
329 errx(EXIT_FAILURE, _("too many tabs"));
ef4d11d5 330 if (av[*oi][0] == '-')
45c90b77 331 break;
ef4d11d5
SK
332 tab_array[i] = strtos32_or_err(av[*oi], _("argument error"));
333 (*oi)++;
45c90b77 334 i++;
22853e4a 335 }
45c90b77 336 tab_array[i] = -1;
6dbe3af9
KZ
337}
338
ef4d11d5 339static int parse_regtabs(char **av, char *oa, int *oi)
45c90b77
SK
340{
341 int ret;
342 char *arg;
343
ef4d11d5 344 arg = find_optional_arg(av, oa, oi);
45c90b77
SK
345 if (!arg)
346 return DEFAULT_TAB_LEN;
35b578a0 347 ret = strtos32_or_err(arg, _("argument error"));
45c90b77 348 if (ret < 1 || TABS_MAX < ret)
c8a6f83e 349 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
45c90b77 350 return ret;
6dbe3af9
KZ
351}
352
ef4d11d5 353static int parse_blength(char **av, char *oa, int *oi)
45c90b77
SK
354{
355 int ret = -1;
356 char *arg;
357
ef4d11d5 358 arg = find_optional_arg(av, oa, oi);
45c90b77
SK
359 if (!arg)
360 return 0;
35b578a0 361 ret = strtos32_or_err(arg, _("argument error"));
45c90b77 362 if (ret < 0 || BLENGTH_MAX < ret)
c8a6f83e 363 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
45c90b77 364 return ret;
fd6b7a7f
KZ
365}
366
ef4d11d5 367static int parse_bfreq(char **av, char *oa, int *oi)
45c90b77
SK
368{
369 char *arg;
370
ef4d11d5 371 arg = find_optional_arg(av, oa, oi);
45c90b77
SK
372 if (!arg)
373 return 0;
35b578a0 374 return strtos32_or_err(arg, _("argument error"));
fd6b7a7f
KZ
375}
376
253e5e71
SK
377static void __attribute__((__noreturn__)) usage(FILE *out)
378{
253e5e71 379 fputs(USAGE_HEADER, out);
a1e04e8f
KZ
380 fprintf(out,
381 _(" %s [options]\n"), program_invocation_short_name);
451dbcfa
BS
382
383 fputs(USAGE_SEPARATOR, out);
384 fputs(_("Set the attributes of a terminal.\n"), out);
385
253e5e71 386 fputs(USAGE_OPTIONS, out);
5edc8dbc 387 fputs(_(" --term <terminal_name> override TERM environment variable\n"), out);
d276d995 388 fputs(_(" --reset reset terminal to power-on state\n"), out);
5d795999 389 fputs(_(" --resize reset terminal rows and columns\n"), out);
5edc8dbc
SK
390 fputs(_(" --initialize display init string, and use default settings\n"), out);
391 fputs(_(" --default use default terminal settings\n"), out);
392 fputs(_(" --store save current terminal settings as default\n"), out);
393 fputs(_(" --cursor [on|off] display cursor\n"), out);
394 fputs(_(" --repeat [on|off] keyboard repeat\n"), out);
395 fputs(_(" --appcursorkeys [on|off] cursor key application mode\n"), out);
396 fputs(_(" --linewrap [on|off] continue on a new line when a line is full\n"), out);
397 fputs(_(" --inversescreen [on|off] swap colors for the whole screen\n"), out);
d276d995
BS
398 fputs(_(" --foreground default|<color> set foreground color\n"), out);
399 fputs(_(" --background default|<color> set background color\n"), out);
400 fputs(_(" --ulcolor [bright] <color> set underlined text color\n"), out);
401 fputs(_(" --hbcolor [bright] <color> set bold text color\n"), out);
402 fputs(_(" <color>: black blue cyan green grey magenta red white yellow\n"), out);
5edc8dbc
SK
403 fputs(_(" --bold [on|off] bold\n"), out);
404 fputs(_(" --half-bright [on|off] dim\n"), out);
405 fputs(_(" --blink [on|off] blink\n"), out);
406 fputs(_(" --underline [on|off] underline\n"), out);
407 fputs(_(" --reverse [on|off] swap foreground and background colors\n"), out);
408 fputs(_(" --clear [all|rest] clear screen and set cursor position\n"), out);
d276d995
BS
409 fputs(_(" --tabs [<number>...] set these tab stop positions, or show them\n"), out);
410 fputs(_(" --clrtabs [<number>...] clear these tab stop positions, or all\n"), out);
411 fputs(_(" --regtabs [1-160] set a regular tab stop interval\n"), out);
412 fputs(_(" --blank [0-60|force|poke] set time of inactivity before screen blanks\n"), out);
413 fputs(_(" --dump [<number>] write vcsa<number> console dump to file\n"), out);
414 fputs(_(" --append [<number>] append vcsa<number> console dump to file\n"), out);
415 fputs(_(" --file <filename> name of the dump file\n"), out);
416 fputs(_(" --msg [on|off] send kernel messages to console\n"), out);
417 fputs(_(" --msglevel 0-8 kernel console log level\n"), out);
5edc8dbc
SK
418 fputs(_(" --powersave [on|vsync|hsync|powerdown|off]\n"), out);
419 fputs(_(" set vesa powersaving features\n"), out);
420 fputs(_(" --powerdown [0-60] set vesa powerdown interval in minutes\n"), out);
421 fputs(_(" --blength [0-2000] duration of the bell in milliseconds\n"), out);
422 fputs(_(" --bfreq <number> bell frequency in Hertz\n"), out);
d276d995
BS
423 fputs(_(" --version show version information and exit\n"), out);
424 fputs(_(" --help display this help and exit\n"), out);
6a801e1a 425 fprintf(out, USAGE_MAN_TAIL("setterm(1)"));
faa0548d
SK
426 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
427}
6dbe3af9 428
d87d20b0 429static int __attribute__((__pure__)) set_opt_flag(int opt)
45c90b77 430{
d87d20b0 431 if (opt)
45c90b77 432 errx(EXIT_FAILURE, _("duplicate use of an option"));
d87d20b0 433 return 1;
45c90b77 434}
6dbe3af9 435
ef4d11d5 436static void parse_option(struct setterm_control *ctl, int ac, char **av)
45c90b77
SK
437{
438 int c;
439 enum {
440 OPT_TERM = CHAR_MAX + 1,
441 OPT_RESET,
5d795999 442 OPT_RESIZE,
45c90b77
SK
443 OPT_INITIALIZE,
444 OPT_CURSOR,
445 OPT_REPEAT,
446 OPT_APPCURSORKEYS,
447 OPT_LINEWRAP,
448 OPT_DEFAULT,
449 OPT_FOREGROUND,
450 OPT_BACKGROUND,
451 OPT_ULCOLOR,
452 OPT_HBCOLOR,
453 OPT_INVERSESCREEN,
454 OPT_BOLD,
455 OPT_HALF_BRIGHT,
456 OPT_BLINK,
457 OPT_REVERSE,
458 OPT_UNDERLINE,
459 OPT_STORE,
460 OPT_CLEAR,
461 OPT_TABS,
462 OPT_CLRTABS,
463 OPT_REGTABS,
464 OPT_BLANK,
465 OPT_DUMP,
466 OPT_APPEND,
467 OPT_FILE,
468 OPT_MSG,
469 OPT_MSGLEVEL,
470 OPT_POWERSAVE,
471 OPT_POWERDOWN,
472 OPT_BLENGTH,
473 OPT_BFREQ,
474 OPT_VERSION,
475 OPT_HELP
476 };
477 static const struct option longopts[] = {
478 {"term", required_argument, NULL, OPT_TERM},
479 {"reset", no_argument, NULL, OPT_RESET},
5d795999 480 {"resize", no_argument, NULL, OPT_RESIZE},
45c90b77
SK
481 {"initialize", no_argument, NULL, OPT_INITIALIZE},
482 {"cursor", required_argument, NULL, OPT_CURSOR},
483 {"repeat", required_argument, NULL, OPT_REPEAT},
484 {"appcursorkeys", required_argument, NULL, OPT_APPCURSORKEYS},
485 {"linewrap", required_argument, NULL, OPT_LINEWRAP},
486 {"default", no_argument, NULL, OPT_DEFAULT},
487 {"foreground", required_argument, NULL, OPT_FOREGROUND},
488 {"background", required_argument, NULL, OPT_BACKGROUND},
489 {"ulcolor", required_argument, NULL, OPT_ULCOLOR},
45c90b77
SK
490 {"hbcolor", required_argument, NULL, OPT_HBCOLOR},
491 {"inversescreen", required_argument, NULL, OPT_INVERSESCREEN},
492 {"bold", required_argument, NULL, OPT_BOLD},
493 {"half-bright", required_argument, NULL, OPT_HALF_BRIGHT},
494 {"blink", required_argument, NULL, OPT_BLINK},
495 {"reverse", required_argument, NULL, OPT_REVERSE},
496 {"underline", required_argument, NULL, OPT_UNDERLINE},
497 {"store", no_argument, NULL, OPT_STORE},
498 {"clear", required_argument, NULL, OPT_CLEAR},
499 {"tabs", optional_argument, NULL, OPT_TABS},
500 {"clrtabs", optional_argument, NULL, OPT_CLRTABS},
501 {"regtabs", optional_argument, NULL, OPT_REGTABS},
502 {"blank", optional_argument, NULL, OPT_BLANK},
503 {"dump", optional_argument, NULL, OPT_DUMP},
504 {"append", required_argument, NULL, OPT_APPEND},
505 {"file", required_argument, NULL, OPT_FILE},
506 {"msg", required_argument, NULL, OPT_MSG},
507 {"msglevel", required_argument, NULL, OPT_MSGLEVEL},
508 {"powersave", required_argument, NULL, OPT_POWERSAVE},
509 {"powerdown", optional_argument, NULL, OPT_POWERDOWN},
510 {"blength", optional_argument, NULL, OPT_BLENGTH},
511 {"bfreq", optional_argument, NULL, OPT_BFREQ},
512 {"version", no_argument, NULL, OPT_VERSION},
513 {"help", no_argument, NULL, OPT_HELP},
514 {NULL, 0, NULL, 0}
515 };
11f69359
SK
516 static const ul_excl_t excl[] = {
517 { OPT_DEFAULT, OPT_STORE },
518 { OPT_TABS, OPT_CLRTABS, OPT_REGTABS },
519 { OPT_MSG, OPT_MSGLEVEL },
520 { 0 }
521 };
522 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
45c90b77 523
ef4d11d5 524 while ((c = getopt_long_only(ac, av, "", longopts, NULL)) != -1) {
11f69359 525 err_exclusive_options(c, longopts, excl, excl_st);
45c90b77
SK
526 switch (c) {
527 case OPT_TERM:
d87d20b0
SK
528 ctl->opt_term = set_opt_flag(ctl->opt_term);
529 ctl->opt_te_terminal_name = optarg;
45c90b77
SK
530 break;
531 case OPT_RESET:
d87d20b0 532 ctl->opt_reset = set_opt_flag(ctl->opt_reset);
45c90b77 533 break;
5d795999
SK
534 case OPT_RESIZE:
535 ctl->opt_resize = set_opt_flag(ctl->opt_resize);
536 break;
45c90b77 537 case OPT_INITIALIZE:
d87d20b0 538 ctl->opt_initialize = set_opt_flag(ctl->opt_initialize);
45c90b77
SK
539 break;
540 case OPT_CURSOR:
d87d20b0 541 ctl->opt_cursor = set_opt_flag(ctl->opt_cursor);
30b294c4
KZ
542 ctl->opt_cu_on = parse_switch(optarg, _("argument error"),
543 "on", "off", NULL);
45c90b77
SK
544 break;
545 case OPT_REPEAT:
d87d20b0 546 ctl->opt_repeat = set_opt_flag(ctl->opt_repeat);
30b294c4
KZ
547 ctl->opt_rep_on = parse_switch(optarg, _("argument error"),
548 "on", "off", NULL);
45c90b77
SK
549 break;
550 case OPT_APPCURSORKEYS:
d87d20b0 551 ctl->opt_appcursorkeys = set_opt_flag(ctl->opt_appcursorkeys);
30b294c4
KZ
552 ctl->opt_appck_on = parse_switch(optarg, _("argument error"),
553 "on", "off", NULL);
45c90b77
SK
554 break;
555 case OPT_LINEWRAP:
d87d20b0 556 ctl->opt_linewrap = set_opt_flag(ctl->opt_linewrap);
30b294c4
KZ
557 ctl->opt_li_on = parse_switch(optarg, _("argument error"),
558 "on", "off", NULL);
45c90b77
SK
559 break;
560 case OPT_DEFAULT:
d87d20b0 561 ctl->opt_default = set_opt_flag(ctl->opt_default);
45c90b77
SK
562 break;
563 case OPT_FOREGROUND:
d87d20b0
SK
564 ctl->opt_foreground = set_opt_flag(ctl->opt_foreground);
565 ctl->opt_fo_color = parse_febg_color(optarg);
45c90b77
SK
566 break;
567 case OPT_BACKGROUND:
d87d20b0
SK
568 ctl->opt_background = set_opt_flag(ctl->opt_background);
569 ctl->opt_ba_color = parse_febg_color(optarg);
45c90b77
SK
570 break;
571 case OPT_ULCOLOR:
d87d20b0 572 ctl->opt_ulcolor = set_opt_flag(ctl->opt_ulcolor);
ef4d11d5 573 ctl->opt_ul_color = parse_ulhb_color(av, &optind);
45c90b77
SK
574 break;
575 case OPT_HBCOLOR:
d87d20b0 576 ctl->opt_hbcolor = set_opt_flag(ctl->opt_hbcolor);
ef4d11d5 577 ctl->opt_hb_color = parse_ulhb_color(av, &optind);
45c90b77
SK
578 break;
579 case OPT_INVERSESCREEN:
d87d20b0 580 ctl->opt_inversescreen = set_opt_flag(ctl->opt_inversescreen);
30b294c4
KZ
581 ctl->opt_invsc_on = parse_switch(optarg, _("argument error"),
582 "on", "off", NULL);
45c90b77
SK
583 break;
584 case OPT_BOLD:
d87d20b0 585 ctl->opt_bold = set_opt_flag(ctl->opt_bold);
30b294c4
KZ
586 ctl->opt_bo_on = parse_switch(optarg, _("argument error"),
587 "on", "off", NULL);
45c90b77
SK
588 break;
589 case OPT_HALF_BRIGHT:
d87d20b0 590 ctl->opt_halfbright = set_opt_flag(ctl->opt_halfbright);
30b294c4
KZ
591 ctl->opt_hb_on = parse_switch(optarg, _("argument error"),
592 "on", "off", NULL);
45c90b77
SK
593 break;
594 case OPT_BLINK:
d87d20b0 595 ctl->opt_blink = set_opt_flag(ctl->opt_blink);
30b294c4
KZ
596 ctl->opt_bl_on = parse_switch(optarg, _("argument error"),
597 "on", "off", NULL);
45c90b77
SK
598 break;
599 case OPT_REVERSE:
d87d20b0 600 ctl->opt_reverse = set_opt_flag(ctl->opt_reverse);
30b294c4
KZ
601 ctl->opt_re_on = parse_switch(optarg, _("argument error"),
602 "on", "off", NULL);
45c90b77
SK
603 break;
604 case OPT_UNDERLINE:
d87d20b0 605 ctl->opt_underline = set_opt_flag(ctl->opt_underline);
30b294c4
KZ
606 ctl->opt_un_on = parse_switch(optarg, _("argument error"),
607 "on", "off", NULL);
45c90b77
SK
608 break;
609 case OPT_STORE:
d87d20b0 610 ctl->opt_store = set_opt_flag(ctl->opt_store);
45c90b77
SK
611 break;
612 case OPT_CLEAR:
d87d20b0 613 ctl->opt_clear = set_opt_flag(ctl->opt_clear);
30b294c4
KZ
614 ctl->opt_cl_all = parse_switch(optarg, _("argument error"),
615 "all", "reset", NULL);
45c90b77
SK
616 break;
617 case OPT_TABS:
d87d20b0 618 ctl->opt_tabs = set_opt_flag(ctl->opt_tabs);
ef4d11d5 619 parse_tabs(av, optarg, &optind, ctl->opt_tb_array);
45c90b77
SK
620 break;
621 case OPT_CLRTABS:
d87d20b0 622 ctl->opt_clrtabs = set_opt_flag(ctl->opt_clrtabs);
ef4d11d5 623 parse_tabs(av, optarg, &optind, ctl->opt_tb_array);
45c90b77
SK
624 break;
625 case OPT_REGTABS:
d87d20b0 626 ctl->opt_regtabs = set_opt_flag(ctl->opt_regtabs);
ef4d11d5 627 ctl->opt_rt_len = parse_regtabs(av, optarg, &optind);
45c90b77
SK
628 break;
629 case OPT_BLANK:
d87d20b0 630 ctl->opt_blank = set_opt_flag(ctl->opt_blank);
ef4d11d5 631 ctl->opt_bl_min = parse_blank(av, optarg, &optind);
45c90b77
SK
632 break;
633 case OPT_DUMP:
d87d20b0 634 ctl->opt_snap = set_opt_flag(ctl->opt_snap);
ef4d11d5 635 ctl->opt_sn_num = parse_snap(av, optarg, &optind);
45c90b77
SK
636 break;
637 case OPT_APPEND:
d87d20b0 638 ctl->opt_append = set_opt_flag(ctl->opt_append);
ef4d11d5 639 ctl->opt_sn_num = parse_snap(av, optarg, &optind);
45c90b77
SK
640 break;
641 case OPT_FILE:
d87d20b0
SK
642 ctl->opt_snapfile = set_opt_flag(ctl->opt_snapfile);
643 ctl->opt_sn_name = optarg;
45c90b77
SK
644 break;
645 case OPT_MSG:
d87d20b0 646 ctl->opt_msg = set_opt_flag(ctl->opt_msg);
30b294c4
KZ
647 ctl->opt_msg_on = parse_switch(optarg, _("argument error"),
648 "on", "off", NULL);
45c90b77
SK
649 break;
650 case OPT_MSGLEVEL:
d87d20b0
SK
651 ctl->opt_msglevel = set_opt_flag(ctl->opt_msglevel);
652 ctl->opt_msglevel_num = parse_msglevel(optarg);
91746583
SK
653 if (ctl->opt_msglevel_num == 0) {
654 ctl->opt_msg = set_opt_flag(ctl->opt_msg);
655 ctl->opt_msg_on |= 1;
656 }
45c90b77
SK
657 break;
658 case OPT_POWERSAVE:
d87d20b0
SK
659 ctl->opt_powersave = set_opt_flag(ctl->opt_powersave);
660 ctl->opt_ps_mode = parse_powersave(optarg);
45c90b77
SK
661 break;
662 case OPT_POWERDOWN:
d87d20b0 663 ctl->opt_powerdown = set_opt_flag(ctl->opt_powerdown);
ef4d11d5 664 ctl->opt_pd_min = parse_blank(av, optarg, &optind);
45c90b77
SK
665 break;
666 case OPT_BLENGTH:
d87d20b0 667 ctl->opt_blength = set_opt_flag(ctl->opt_blength);
ef4d11d5 668 ctl->opt_blength_l = parse_blength(av, optarg, &optind);
45c90b77
SK
669 break;
670 case OPT_BFREQ:
d87d20b0 671 ctl->opt_bfreq = set_opt_flag(ctl->opt_bfreq);
ef4d11d5 672 ctl->opt_bfreq_f = parse_bfreq(av, optarg, &optind);
45c90b77
SK
673 break;
674 case OPT_VERSION:
675 printf(UTIL_LINUX_VERSION);
676 exit(EXIT_SUCCESS);
677 case OPT_HELP:
678 usage(stdout);
679 default:
677ec86c 680 errtryhelp(EXIT_FAILURE);
45c90b77
SK
681 }
682 }
6dbe3af9
KZ
683}
684
16279cc2
SK
685/* Return the specified terminfo string, or an empty string if no such
686 * terminfo capability exists. */
687static char *ti_entry(const char *name)
688{
22853e4a 689 char *buf_ptr;
6dbe3af9 690
ffc43748
KZ
691 if ((buf_ptr = tigetstr((char *)name)) == (char *)-1)
692 buf_ptr = NULL;
22853e4a 693 return buf_ptr;
6dbe3af9
KZ
694}
695
c591be87
SK
696static void show_tabs(void)
697{
698 int i, co = tigetnum("cols");
699
700 if (co > 0) {
701 printf("\r ");
702 for (i = 10; i < co - 2; i += 10)
703 printf("%-10d", i);
704 putchar('\n');
705 for (i = 1; i <= co; i++)
706 putchar(i % 10 + '0');
707 putchar('\n');
708 for (i = 1; i < co; i++)
709 printf("\tT\b");
710 putchar('\n');
711 }
712}
713
341566ff 714static int open_snapshot_device(struct setterm_control *ctl)
c591be87 715{
c591be87 716 int fd;
c591be87 717
609d4853
SK
718 if (ctl->opt_sn_num)
719 xasprintf(&ctl->in_device, "/dev/vcsa%d", ctl->opt_sn_num);
720 else
721 xasprintf(&ctl->in_device, "/dev/vcsa");
722 fd = open(ctl->in_device, O_RDONLY);
341566ff 723 if (fd < 0)
cda2b5b9 724 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
341566ff
SK
725 return fd;
726}
727
7a20c8a1
SK
728static void set_blanking(struct setterm_control *ctl)
729{
730 char ioctlarg;
731 int ret;
732
733 if (0 <= ctl->opt_bl_min) {
734 printf("\033[9;%d]", ctl->opt_bl_min);
735 return;
736 }
737 switch (ctl->opt_bl_min) {
738 case BLANKSCREEN:
739 ioctlarg = TIOCL_BLANKSCREEN;
740 if (ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg))
741 warn(_("cannot force blank"));
742 break;
743 case UNBLANKSCREEN:
744 ioctlarg = TIOCL_UNBLANKSCREEN;
745 if (ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg))
746 warn(_("cannot force unblank"));
747 break;
748 case BLANKEDSCREEN:
749 ioctlarg = TIOCL_BLANKEDSCREEN;
750 ret = ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg);
751 if (ret < 0)
752 warn(_("cannot get blank status"));
753 else
754 printf("%d\n", ret);
755 break;
756 default: /* should be impossible to reach */
757 abort();
758 }
759 return;
760}
761
341566ff
SK
762static void screendump(struct setterm_control *ctl)
763{
764 unsigned char header[4];
765 unsigned int rows, cols;
766 int fd;
767 FILE *out;
768 size_t i, j;
769 ssize_t rc;
770 char *inbuf, *outbuf, *p, *q;
341566ff
SK
771
772 /* open source and destination files */
773 fd = open_snapshot_device(ctl);
774 if (!ctl->opt_sn_name)
4636f061 775 ctl->opt_sn_name = "screen.dump";
341566ff
SK
776 out = fopen(ctl->opt_sn_name, ctl->opt_snap ? "w" : "a");
777 if (!out)
223939d9 778 err(EXIT_DUMPFILE, _("cannot open dump file %s for output"), ctl->opt_sn_name);
341566ff 779 /* determine snapshot size */
c591be87 780 if (read(fd, header, 4) != 4)
cda2b5b9 781 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
c591be87
SK
782 rows = header[0];
783 cols = header[1];
784 if (rows * cols == 0)
cda2b5b9 785 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
341566ff 786 /* allocate buffers */
c591be87
SK
787 inbuf = xmalloc(rows * cols * 2);
788 outbuf = xmalloc(rows * (cols + 1));
341566ff 789 /* read input */
c591be87
SK
790 rc = read(fd, inbuf, rows * cols * 2);
791 if (rc < 0 || (size_t)rc != rows * cols * 2)
cda2b5b9 792 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
c591be87
SK
793 p = inbuf;
794 q = outbuf;
341566ff 795 /* copy inbuf to outbuf */
c591be87
SK
796 for (i = 0; i < rows; i++) {
797 for (j = 0; j < cols; j++) {
798 *q++ = *p;
799 p += 2;
800 }
801 while (j-- > 0 && q[-1] == ' ')
802 q--;
803 *q++ = '\n';
804 }
341566ff
SK
805 fwrite(outbuf, 1, q - outbuf, out);
806 /* clean up allocations */
c591be87
SK
807 close(fd);
808 free(inbuf);
809 free(outbuf);
609d4853 810 free(ctl->in_device);
341566ff
SK
811 if (close_stream(out) != 0)
812 errx(EXIT_FAILURE, _("write error"));
c591be87 813 return;
c591be87
SK
814}
815
da27df25
SK
816/* Some options are applicable when terminal is virtual console. */
817static int vc_only(struct setterm_control *ctl, const char *err)
818{
74ce680a
SK
819 if (!ctl->vcterm && err)
820 warnx(_("terminal %s does not support %s"),
821 ctl->opt_te_terminal_name, err);
da27df25
SK
822 return ctl->vcterm;
823}
824
5d795999
SK
825static void tty_raw(struct termios *saved_attributes, int *saved_fl)
826{
827 struct termios tattr;
828
829 fcntl(STDIN_FILENO, F_GETFL, saved_fl);
830 tcgetattr(STDIN_FILENO, saved_attributes);
831 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
832 memcpy(&tattr, saved_attributes, sizeof(struct termios));
833 tattr.c_lflag &= ~(ICANON | ECHO);
834 tattr.c_cc[VMIN] = 1;
835 tattr.c_cc[VTIME] = 0;
836 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
837}
838
839static void tty_restore(struct termios *saved_attributes, int *saved_fl)
840{
841 fcntl(STDIN_FILENO, F_SETFL, *saved_fl);
842 tcsetattr(STDIN_FILENO, TCSANOW, saved_attributes);
843}
844
845static int select_wait(void)
846{
847 struct timeval tv;
848 fd_set set;
849 int ret;
850
851 FD_ZERO(&set);
852 FD_SET(STDIN_FILENO, &set);
853 tv.tv_sec = 10;
854 tv.tv_usec = 0;
855 while ((ret = select(1, &set, NULL, NULL, &tv)) < 0) {
856 if (errno == EINTR)
857 continue;
858 err(EXIT_FAILURE, _("select failed"));
859 }
860 return ret;
861}
862
863static int resizetty(void)
864{
865 /*
866 * \e7 Save current state (cursor coordinates, attributes,
867 * character sets pointed at by G0, G1).
868 * \e[r Set scrolling region; parameters are top and bottom row.
869 * \e[32766E Move cursor down 32766 (INT16_MAX - 1) rows.
870 * \e[32766C Move cursor right 32766 columns.
871 * \e[6n Report cursor position.
872 * \e8 Restore state most recently saved by \e7.
873 */
874 static const char *getpos = "\e7\e[r\e[32766E\e[32766C\e[6n\e8";
875 char retstr[32];
876 int row, col;
877 size_t pos;
878 ssize_t rc;
879 struct winsize ws;
880 struct termios saved_attributes;
881 int saved_fl;
882
883 if (!isatty(STDIN_FILENO))
884 errx(EXIT_FAILURE, _("stdin does not refer to a terminal"));
885
886 tty_raw(&saved_attributes, &saved_fl);
887 if (write_all(STDIN_FILENO, getpos, strlen(getpos)) < 0) {
888 warn(_("write failed"));
889 tty_restore(&saved_attributes, &saved_fl);
890 return 1;
891 }
892 for (pos = 0; pos < sizeof(retstr) - 1;) {
893 if (0 == select_wait())
894 break;
895 if ((rc =
896 read(STDIN_FILENO, retstr + pos,
897 sizeof(retstr) - 1 - pos)) < 0) {
898 if (errno == EINTR)
899 continue;
900 warn(_("read failed"));
901 tty_restore(&saved_attributes, &saved_fl);
902 return 1;
903 }
904 pos += rc;
905 if (retstr[pos - 1] == 'R')
906 break;
907 }
908 retstr[pos] = 0;
909 tty_restore(&saved_attributes, &saved_fl);
910 rc = sscanf(retstr, "\033[%d;%dR", &row, &col);
911 if (rc != 2) {
912 warnx(_("invalid cursor position: %s"), retstr);
913 return 1;
914 }
915 memset(&ws, 0, sizeof(struct winsize));
916 ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
917 ws.ws_row = row;
918 ws.ws_col = col;
919 ioctl(STDIN_FILENO, TIOCSWINSZ, &ws);
920 return 0;
921}
922
d87d20b0
SK
923static void perform_sequence(struct setterm_control *ctl)
924{
22853e4a 925 int result;
6dbe3af9 926
22853e4a 927 /* -reset. */
16279cc2 928 if (ctl->opt_reset)
22853e4a 929 putp(ti_entry("rs1"));
6dbe3af9 930
5d795999
SK
931 /* -resize. */
932 if (ctl->opt_resize)
933 if (resizetty())
934 warnx(_("reset failed"));
935
22853e4a 936 /* -initialize. */
16279cc2 937 if (ctl->opt_initialize)
22853e4a 938 putp(ti_entry("is2"));
6dbe3af9 939
22853e4a 940 /* -cursor [on|off]. */
d87d20b0
SK
941 if (ctl->opt_cursor) {
942 if (ctl->opt_cu_on)
22853e4a
KZ
943 putp(ti_entry("cnorm"));
944 else
945 putp(ti_entry("civis"));
946 }
6dbe3af9 947
da27df25 948 /* -linewrap [on|off]. */
78dd23cb 949 if (ctl->opt_linewrap)
d87d20b0 950 fputs(ctl->opt_li_on ? "\033[?7h" : "\033[?7l", stdout);
6dbe3af9 951
da27df25
SK
952 /* -repeat [on|off]. */
953 if (ctl->opt_repeat && vc_only(ctl, "--repeat"))
d87d20b0 954 fputs(ctl->opt_rep_on ? "\033[?8h" : "\033[?8l", stdout);
6dbe3af9 955
da27df25
SK
956 /* -appcursorkeys [on|off]. */
957 if (ctl->opt_appcursorkeys && vc_only(ctl, "--appcursorkeys"))
d87d20b0 958 fputs(ctl->opt_appck_on ? "\033[?1h" : "\033[?1l", stdout);
6dbe3af9 959
22853e4a 960 /* -default. Vc sets default rendition, otherwise clears all
16279cc2 961 * attributes. */
d87d20b0 962 if (ctl->opt_default) {
da27df25 963 if (vc_only(ctl, NULL))
22853e4a 964 printf("\033[0m");
6dbe3af9 965 else
fd6b7a7f 966 putp(ti_entry("sgr0"));
6dbe3af9 967 }
22853e4a 968
da27df25 969 /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
78dd23cb 970 if (ctl->opt_foreground)
d87d20b0 971 printf("\033[3%c%s", '0' + ctl->opt_fo_color, "m");
22853e4a 972
da27df25 973 /* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
78dd23cb 974 if (ctl->opt_background)
d87d20b0 975 printf("\033[4%c%s", '0' + ctl->opt_ba_color, "m");
22853e4a 976
da27df25
SK
977 /* -ulcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
978 if (ctl->opt_ulcolor && vc_only(ctl, "--ulcolor"))
d87d20b0 979 printf("\033[1;%d]", ctl->opt_ul_color);
22853e4a 980
da27df25 981 /* -hbcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
78dd23cb 982 if (ctl->opt_hbcolor)
d87d20b0 983 printf("\033[2;%d]", ctl->opt_hb_color);
22853e4a 984
da27df25 985 /* -inversescreen [on|off]. */
78dd23cb 986 if (ctl->opt_inversescreen)
d87d20b0 987 fputs(ctl->opt_invsc_on ? "\033[?5h" : "\033[?5l", stdout);
22853e4a
KZ
988
989 /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
16279cc2 990 * all attributes. */
d87d20b0
SK
991 if (ctl->opt_bold) {
992 if (ctl->opt_bo_on)
22853e4a
KZ
993 putp(ti_entry("bold"));
994 else {
da27df25 995 if (vc_only(ctl, NULL))
6ed37604 996 fputs("\033[22m", stdout);
22853e4a
KZ
997 else
998 putp(ti_entry("sgr0"));
999 }
1000 }
1001
16279cc2
SK
1002 /* -half-bright [on|off]. Vc behaves as expected, otherwise off
1003 * turns off all attributes. */
d87d20b0
SK
1004 if (ctl->opt_halfbright) {
1005 if (ctl->opt_hb_on)
22853e4a
KZ
1006 putp(ti_entry("dim"));
1007 else {
da27df25 1008 if (vc_only(ctl, NULL))
6ed37604 1009 fputs("\033[22m", stdout);
22853e4a
KZ
1010 else
1011 putp(ti_entry("sgr0"));
1012 }
1013 }
1014
1015 /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
16279cc2 1016 * all attributes. */
d87d20b0
SK
1017 if (ctl->opt_blink) {
1018 if (ctl->opt_bl_on)
22853e4a
KZ
1019 putp(ti_entry("blink"));
1020 else {
da27df25 1021 if (vc_only(ctl, NULL))
6ed37604 1022 fputs("\033[25m", stdout);
22853e4a
KZ
1023 else
1024 putp(ti_entry("sgr0"));
1025 }
1026 }
1027
1028 /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
16279cc2 1029 * off all attributes. */
d87d20b0
SK
1030 if (ctl->opt_reverse) {
1031 if (ctl->opt_re_on)
22853e4a
KZ
1032 putp(ti_entry("rev"));
1033 else {
da27df25 1034 if (vc_only(ctl, NULL))
6ed37604 1035 fputs("\033[27m", stdout);
22853e4a
KZ
1036 else
1037 putp(ti_entry("sgr0"));
1038 }
1039 }
1040
1041 /* -underline [on|off]. */
d87d20b0
SK
1042 if (ctl->opt_underline)
1043 putp(ti_entry(ctl->opt_un_on ? "smul" : "rmul"));
22853e4a 1044
da27df25
SK
1045 /* -store. */
1046 if (ctl->opt_store && vc_only(ctl, "--store"))
6ed37604 1047 fputs("\033[8]", stdout);
22853e4a
KZ
1048
1049 /* -clear [all|rest]. */
d87d20b0
SK
1050 if (ctl->opt_clear)
1051 putp(ti_entry(ctl->opt_cl_all ? "clear" : "ed"));
22853e4a 1052
da27df25 1053 /* -tabs. */
78dd23cb 1054 if (ctl->opt_tabs) {
d87d20b0 1055 if (ctl->opt_tb_array[0] == -1)
22853e4a
KZ
1056 show_tabs();
1057 else {
78dd23cb
SK
1058 int i;
1059
16279cc2 1060 for (i = 0; ctl->opt_tb_array[i] > 0; i++)
d87d20b0 1061 printf("\033[%dG\033H", ctl->opt_tb_array[i]);
22853e4a
KZ
1062 putchar('\r');
1063 }
1064 }
1065
da27df25
SK
1066 /* -clrtabs. */
1067 if (ctl->opt_clrtabs && vc_only(ctl, "--clrtabs")) {
22853e4a
KZ
1068 int i;
1069
d87d20b0 1070 if (ctl->opt_tb_array[0] == -1)
6ed37604 1071 fputs("\033[3g", stdout);
6dbe3af9 1072 else
16279cc2 1073 for (i = 0; ctl->opt_tb_array[i] > 0; i++)
d87d20b0 1074 printf("\033[%dG\033[g", ctl->opt_tb_array[i]);
22853e4a 1075 putchar('\r');
6dbe3af9 1076 }
6dbe3af9 1077
da27df25
SK
1078 /* -regtabs. */
1079 if (ctl->opt_regtabs && vc_only(ctl, "--regtabs")) {
22853e4a
KZ
1080 int i;
1081
6ed37604 1082 fputs("\033[3g\r", stdout);
16279cc2
SK
1083 for (i = ctl->opt_rt_len + 1; i <= TABS_MAX; i += ctl->opt_rt_len)
1084 printf("\033[%dC\033H", ctl->opt_rt_len);
22853e4a
KZ
1085 putchar('\r');
1086 }
1087
1088 /* -blank [0-60]. */
7a20c8a1
SK
1089 if (ctl->opt_blank && vc_only(ctl, "--blank"))
1090 set_blanking(ctl);
5c55d9bf 1091
22853e4a 1092 /* -powersave [on|vsync|hsync|powerdown|off] (console) */
d87d20b0 1093 if (ctl->opt_powersave) {
22853e4a 1094 char ioctlarg[2];
5c55d9bf 1095 ioctlarg[0] = TIOCL_SETVESABLANK;
d87d20b0 1096 ioctlarg[1] = ctl->opt_ps_mode;
16279cc2 1097 if (ioctl(STDIN_FILENO, TIOCLINUX, ioctlarg))
261f1423 1098 warn(_("cannot (un)set powersave mode"));
22853e4a
KZ
1099 }
1100
1101 /* -powerdown [0-60]. */
16279cc2 1102 if (ctl->opt_powerdown)
d87d20b0 1103 printf("\033[14;%d]", ctl->opt_pd_min);
fd6b7a7f 1104
22853e4a 1105 /* -snap [1-NR_CONS]. */
16279cc2 1106 if (ctl->opt_snap || ctl->opt_append)
341566ff 1107 screendump(ctl);
22853e4a 1108
16279cc2 1109 /* -msg [on|off]. Controls printk's to console. */
da27df25 1110 if (ctl->opt_msg && vc_only(ctl, "--msg")) {
d87d20b0 1111 if (ctl->opt_msg_on)
3393c136 1112 result = klogctl(SYSLOG_ACTION_CONSOLE_ON, NULL, 0);
22853e4a 1113 else
3393c136 1114 result = klogctl(SYSLOG_ACTION_CONSOLE_OFF, NULL, 0);
22853e4a
KZ
1115
1116 if (result != 0)
261f1423 1117 warn(_("klogctl error"));
22853e4a
KZ
1118 }
1119
16279cc2 1120 /* -msglevel [0-8]. Console printk message level. */
da27df25 1121 if (ctl->opt_msglevel_num && vc_only(ctl, "--msglevel")) {
16279cc2
SK
1122 result =
1123 klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL,
1124 ctl->opt_msglevel_num);
22853e4a 1125 if (result != 0)
261f1423 1126 warn(_("klogctl error"));
22853e4a
KZ
1127 }
1128
1129 /* -blength [0-2000] */
da27df25 1130 if (ctl->opt_blength && vc_only(ctl, "--blength")) {
d87d20b0 1131 printf("\033[11;%d]", ctl->opt_blength_l);
22853e4a 1132 }
b6e899d9 1133
22853e4a 1134 /* -bfreq freqnumber */
da27df25 1135 if (ctl->opt_bfreq && vc_only(ctl, "--bfreq")) {
d87d20b0 1136 printf("\033[10;%d]", ctl->opt_bfreq_f);
22853e4a 1137 }
6dbe3af9
KZ
1138}
1139
dcc2fe29 1140static void init_terminal(struct setterm_control *ctl)
d87d20b0 1141{
d87d20b0 1142 int term_errno;
6dbe3af9 1143
dcc2fe29
SK
1144 if (!ctl->opt_te_terminal_name) {
1145 ctl->opt_te_terminal_name = getenv("TERM");
1146 if (ctl->opt_te_terminal_name == NULL)
261f1423 1147 errx(EXIT_FAILURE, _("$TERM is not defined."));
6dbe3af9 1148 }
6dbe3af9 1149
22853e4a 1150 /* Find terminfo entry. */
dcc2fe29
SK
1151 if (setupterm(ctl->opt_te_terminal_name, STDOUT_FILENO, &term_errno))
1152 switch (term_errno) {
261f1423
SK
1153 case -1:
1154 errx(EXIT_FAILURE, _("terminfo database cannot be found"));
1155 case 0:
dcc2fe29 1156 errx(EXIT_FAILURE, _("%s: unknown terminal type"), ctl->opt_te_terminal_name);
261f1423
SK
1157 case 1:
1158 errx(EXIT_FAILURE, _("terminal is hardcopy"));
1159 }
6dbe3af9 1160
22853e4a 1161 /* See if the terminal is a virtual console terminal. */
dcc2fe29
SK
1162 ctl->vcterm = (!strncmp(ctl->opt_te_terminal_name, "con", 3) ||
1163 !strncmp(ctl->opt_te_terminal_name, "linux", 5));
1164}
1165
6dbe3af9 1166
dcc2fe29
SK
1167int main(int argc, char **argv)
1168{
87918040 1169 struct setterm_control ctl = { NULL };
dcc2fe29
SK
1170
1171 setlocale(LC_ALL, "");
1172 bindtextdomain(PACKAGE, LOCALEDIR);
1173 textdomain(PACKAGE);
1174 atexit(close_stdout);
1175
1176 if (argc < 2)
1177 usage(stderr);
1178
1179 parse_option(&ctl, argc, argv);
1180 init_terminal(&ctl);
d87d20b0 1181 perform_sequence(&ctl);
6dbe3af9 1182
261f1423 1183 return EXIT_SUCCESS;
6dbe3af9 1184}