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