]> git.ipfire.org Git - thirdparty/util-linux.git/blob - term-utils/setterm.c
misc: Fix various typos
[thirdparty/util-linux.git] / term-utils / setterm.c
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 *
11 * Beep modifications by Christophe Jolif (cjolif@storm.gatelink.fr.net)
12 *
13 * Sanity increases by Cafeine Addict [sic].
14 *
15 * Powersave features by todd j. derr <tjd@wordsmith.org>
16 *
17 * Converted to terminfo by Kars de Jong (jongk@cs.utwente.nl)
18 *
19 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
20 * - added Native Language Support
21 *
22 * Semantics:
23 *
24 * Setterm writes to standard output a character string that will
25 * invoke the specified terminal capabilities. Where possible
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.
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
47 * values. */
48
49 #include <ctype.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <getopt.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
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>
62
63 #ifndef NCURSES_CONST
64 # define NCURSES_CONST const /* define before including term.h */
65 #endif
66 #ifdef HAVE_NCURSES_H
67 # include <ncurses.h>
68 #elif defined(HAVE_NCURSES_NCURSES_H)
69 # include <ncurses/ncurses.h>
70 #endif
71 /* must include after ncurses.h */
72 #include <term.h>
73
74 #ifdef HAVE_LINUX_TIOCL_H
75 # include <linux/tiocl.h>
76 #endif
77
78 #include "c.h"
79 #include "closestream.h"
80 #include "nls.h"
81 #include "optutils.h"
82 #include "strutils.h"
83 #include "xalloc.h"
84
85 /* Constants. */
86
87 /* Non-standard return values. */
88 #define EXIT_DUMPFILE -1
89
90 /* Colors. */
91 enum {
92 BLACK = 0,
93 RED,
94 GREEN,
95 YELLOW,
96 BLUE,
97 MAGENTA,
98 CYAN,
99 WHITE,
100 GREY,
101 DEFAULT
102 };
103
104 static const char *colornames[] = {
105 [BLACK] = "black",
106 [RED] = "red",
107 [GREEN] = "green",
108 [YELLOW]= "yellow",
109 [BLUE] = "blue",
110 [MAGENTA]="magenta",
111 [CYAN] = "cyan",
112 [WHITE] = "white",
113 [GREY] = "grey",
114 [DEFAULT] = "default"
115 };
116
117 #define is_valid_color(x) (x >= 0 && (size_t) x < ARRAY_SIZE(colornames))
118
119 /* Blank commands */
120 enum {
121 BLANKSCREEN = -1,
122 UNBLANKSCREEN = -2,
123 BLANKEDSCREEN = -3
124 };
125
126 /* <linux/tiocl.h> fallback */
127 #ifndef TIOCL_BLANKSCREEN
128 enum {
129 TIOCL_UNBLANKSCREEN = 4, /* unblank screen */
130 TIOCL_SETVESABLANK = 10, /* set vesa blanking mode */
131 TIOCL_BLANKSCREEN = 14, /* keep screen blank even if a key is pressed */
132 TIOCL_BLANKEDSCREEN = 15 /* return which vt was blanked */
133 };
134 #endif
135
136 /* Powersave modes */
137 enum {
138 VESA_BLANK_MODE_OFF = 0,
139 VESA_BLANK_MODE_SUSPENDV,
140 VESA_BLANK_MODE_SUSPENDH,
141 VESA_BLANK_MODE_POWERDOWN
142 };
143
144 /* klogctl() actions */
145 enum {
146 SYSLOG_ACTION_CONSOLE_OFF = 6,
147 SYSLOG_ACTION_CONSOLE_ON = 7,
148 SYSLOG_ACTION_CONSOLE_LEVEL = 8
149 };
150
151 /* Console log levels */
152 enum {
153 CONSOLE_LEVEL_MIN = 0,
154 CONSOLE_LEVEL_MAX = 8
155 };
156
157 /* Various numbers */
158 #define DEFAULT_TAB_LEN 8
159 #define BLANK_MAX 60
160 #define TABS_MAX 160
161 #define BLENGTH_MAX 2000
162
163 /* Command controls. */
164 struct setterm_control {
165 char *opt_te_terminal_name; /* terminal name */
166 int opt_bl_min; /* blank screen */
167 int opt_blength_l; /* bell duration in milliseconds */
168 int opt_bfreq_f; /* bell frequency in Hz */
169 int opt_sn_num; /* console number to be snapshot */
170 char *opt_sn_name; /* path to write snap */
171 char *in_device; /* device to snapshot */
172 int opt_msglevel_num; /* printk() logging level */
173 int opt_ps_mode; /* powersave mode */
174 int opt_pd_min; /* powerdown time */
175 int opt_rt_len; /* regular tab length */
176 int opt_tb_array[TABS_MAX + 1]; /* array for tab list */
177 /* colors */
178 int opt_fo_color:4, opt_ba_color:4, opt_ul_color:4, opt_hb_color:4;
179 /* boolean options */
180 unsigned int opt_cu_on:1, opt_li_on:1, opt_bo_on:1, opt_hb_on:1,
181 opt_bl_on:1, opt_re_on:1, opt_un_on:1, opt_rep_on:1,
182 opt_appck_on:1, opt_invsc_on:1, opt_msg_on:1, opt_cl_all:1,
183 vcterm:1;
184 /* Option flags. Set when an option is invoked. */
185 uint64_t opt_term:1, opt_reset:1, opt_initialize:1, opt_cursor:1,
186 opt_linewrap:1, opt_default:1, opt_foreground:1,
187 opt_background:1, opt_bold:1, opt_blink:1, opt_reverse:1,
188 opt_underline:1, opt_store:1, opt_clear:1, opt_blank:1,
189 opt_snap:1, opt_snapfile:1, opt_append:1, opt_ulcolor:1,
190 opt_hbcolor:1, opt_halfbright:1, opt_repeat:1, opt_tabs:1,
191 opt_clrtabs:1, opt_regtabs:1, opt_appcursorkeys:1,
192 opt_inversescreen:1, opt_msg:1, opt_msglevel:1, opt_powersave:1,
193 opt_powerdown:1, opt_blength:1, opt_bfreq:1;
194 };
195
196 static int parse_color(const char *arg)
197 {
198 size_t i;
199
200 for (i = 0; i < ARRAY_SIZE(colornames); i++) {
201 if (strcmp(colornames[i], arg) == 0)
202 return i;
203 }
204
205 return -EINVAL;
206 }
207
208 static int parse_febg_color(const char *arg)
209 {
210 int color = parse_color(arg);
211
212 if (color < 0)
213 color = strtos32_or_err(arg, _("argument error"));
214
215 if (!is_valid_color(color) || color == GREY)
216 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
217 return color;
218 }
219
220 static int parse_ulhb_color(char **argv, int *optind)
221 {
222 char *color_name;
223 int bright = 0;
224 int color = -1;
225
226 if (argv[*optind] && strcmp(argv[*optind - 1], "bright") == 0) {
227 bright = 1;
228 color_name = argv[*optind];
229 (*optind)++;
230 } else
231 color_name = argv[*optind - 1];
232
233 color = parse_color(color_name);
234 if (color < 0)
235 color = strtos32_or_err(color_name, _("argument error"));
236 if (!is_valid_color(color))
237 errx(EXIT_FAILURE, "%s: %s", _("argument error"), color_name);
238 if (bright && (color == BLACK || color == GREY))
239 errx(EXIT_FAILURE, _("argument error: bright %s is not supported"), color_name);
240
241 return color;
242 }
243
244 static char *find_optional_arg(char **argv, char *optarg, int *optind)
245 {
246 char *arg;
247 if (optarg)
248 return optarg;
249 else {
250 arg = argv[*optind];
251 if (!arg || arg[0] == '-')
252 return NULL;
253 }
254 (*optind)++;
255 return arg;
256 }
257
258 static int parse_blank(char **argv, char *optarg, int *optind)
259 {
260 char *arg;
261
262 arg = find_optional_arg(argv, optarg, optind);
263 if (!arg)
264 return BLANKEDSCREEN;
265 if (!strcmp(arg, "force"))
266 return BLANKSCREEN;
267 else if (!strcmp(arg, "poke"))
268 return UNBLANKSCREEN;
269 else {
270 int ret;
271
272 ret = strtos32_or_err(arg, _("argument error"));
273 if (ret < 0 || BLANK_MAX < ret)
274 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
275 return ret;
276 }
277 }
278
279 static int parse_powersave(const char *arg)
280 {
281 if (strcmp(arg, "on") == 0)
282 return VESA_BLANK_MODE_SUSPENDV;
283 else if (strcmp(arg, "vsync") == 0)
284 return VESA_BLANK_MODE_SUSPENDV;
285 else if (strcmp(arg, "hsync") == 0)
286 return VESA_BLANK_MODE_SUSPENDH;
287 else if (strcmp(arg, "powerdown") == 0)
288 return VESA_BLANK_MODE_POWERDOWN;
289 else if (strcmp(arg, "off") == 0)
290 return VESA_BLANK_MODE_OFF;
291 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
292 }
293
294 static int parse_msglevel(const char *arg)
295 {
296 int ret;
297
298 ret = strtos32_or_err(arg, _("argument error"));
299 if (ret < CONSOLE_LEVEL_MIN || CONSOLE_LEVEL_MAX < ret)
300 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
301 return ret;
302 }
303
304 static int parse_snap(char **argv, char *optarg, int *optind)
305 {
306 int ret;
307 char *arg;
308
309 arg = find_optional_arg(argv, optarg, optind);
310 if (!arg)
311 return 0;
312 ret = strtos32_or_err(arg, _("argument error"));
313 if (ret < 1)
314 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
315 return ret;
316 }
317
318 static void parse_tabs(char **argv, char *optarg, int *optind, int *tab_array)
319 {
320 int i = 0;
321
322 if (optarg) {
323 tab_array[i] = strtos32_or_err(optarg, _("argument error"));
324 i++;
325 }
326 while (argv[*optind]) {
327 if (TABS_MAX < i)
328 errx(EXIT_FAILURE, _("too many tabs"));
329 if (argv[*optind][0] == '-')
330 break;
331 tab_array[i] = strtos32_or_err(argv[*optind], _("argument error"));
332 (*optind)++;
333 i++;
334 }
335 tab_array[i] = -1;
336 }
337
338 static int parse_regtabs(char **argv, char *optarg, int *optind)
339 {
340 int ret;
341 char *arg;
342
343 arg = find_optional_arg(argv, optarg, optind);
344 if (!arg)
345 return DEFAULT_TAB_LEN;
346 ret = strtos32_or_err(arg, _("argument error"));
347 if (ret < 1 || TABS_MAX < ret)
348 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
349 return ret;
350 }
351
352 static int parse_blength(char **argv, char *optarg, int *optind)
353 {
354 int ret = -1;
355 char *arg;
356
357 arg = find_optional_arg(argv, optarg, optind);
358 if (!arg)
359 return 0;
360 ret = strtos32_or_err(arg, _("argument error"));
361 if (ret < 0 || BLENGTH_MAX < ret)
362 errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
363 return ret;
364 }
365
366 static int parse_bfreq(char **argv, char *optarg, int *optind)
367 {
368 char *arg;
369
370 arg = find_optional_arg(argv, optarg, optind);
371 if (!arg)
372 return 0;
373 return strtos32_or_err(arg, _("argument error"));
374 }
375
376 static void __attribute__((__noreturn__)) usage(FILE *out)
377 {
378 fputs(USAGE_HEADER, out);
379 fprintf(out,
380 _(" %s [options]\n"), program_invocation_short_name);
381
382 fputs(USAGE_SEPARATOR, out);
383 fputs(_("Set the attributes of a terminal.\n"), out);
384
385 fputs(USAGE_OPTIONS, out);
386 fputs(_(" --term <terminal_name> override TERM environment variable\n"), out);
387 fputs(_(" --reset reset terminal to power-on state\n"), out);
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);
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);
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);
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);
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);
421 fputs(_(" --version show version information and exit\n"), out);
422 fputs(_(" --help display this help and exit\n"), out);
423 fprintf(out, USAGE_MAN_TAIL("setterm(1)"));
424 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
425 }
426
427 static int __attribute__((__pure__)) set_opt_flag(int opt)
428 {
429 if (opt)
430 errx(EXIT_FAILURE, _("duplicate use of an option"));
431 return 1;
432 }
433
434 static void parse_option(struct setterm_control *ctl, int argc, char **argv)
435 {
436 int c;
437 enum {
438 OPT_TERM = CHAR_MAX + 1,
439 OPT_RESET,
440 OPT_INITIALIZE,
441 OPT_CURSOR,
442 OPT_REPEAT,
443 OPT_APPCURSORKEYS,
444 OPT_LINEWRAP,
445 OPT_DEFAULT,
446 OPT_FOREGROUND,
447 OPT_BACKGROUND,
448 OPT_ULCOLOR,
449 OPT_HBCOLOR,
450 OPT_INVERSESCREEN,
451 OPT_BOLD,
452 OPT_HALF_BRIGHT,
453 OPT_BLINK,
454 OPT_REVERSE,
455 OPT_UNDERLINE,
456 OPT_STORE,
457 OPT_CLEAR,
458 OPT_TABS,
459 OPT_CLRTABS,
460 OPT_REGTABS,
461 OPT_BLANK,
462 OPT_DUMP,
463 OPT_APPEND,
464 OPT_FILE,
465 OPT_MSG,
466 OPT_MSGLEVEL,
467 OPT_POWERSAVE,
468 OPT_POWERDOWN,
469 OPT_BLENGTH,
470 OPT_BFREQ,
471 OPT_VERSION,
472 OPT_HELP
473 };
474 static const struct option longopts[] = {
475 {"term", required_argument, NULL, OPT_TERM},
476 {"reset", no_argument, NULL, OPT_RESET},
477 {"initialize", no_argument, NULL, OPT_INITIALIZE},
478 {"cursor", required_argument, NULL, OPT_CURSOR},
479 {"repeat", required_argument, NULL, OPT_REPEAT},
480 {"appcursorkeys", required_argument, NULL, OPT_APPCURSORKEYS},
481 {"linewrap", required_argument, NULL, OPT_LINEWRAP},
482 {"default", no_argument, NULL, OPT_DEFAULT},
483 {"foreground", required_argument, NULL, OPT_FOREGROUND},
484 {"background", required_argument, NULL, OPT_BACKGROUND},
485 {"ulcolor", required_argument, NULL, OPT_ULCOLOR},
486 {"hbcolor", required_argument, NULL, OPT_HBCOLOR},
487 {"inversescreen", required_argument, NULL, OPT_INVERSESCREEN},
488 {"bold", required_argument, NULL, OPT_BOLD},
489 {"half-bright", required_argument, NULL, OPT_HALF_BRIGHT},
490 {"blink", required_argument, NULL, OPT_BLINK},
491 {"reverse", required_argument, NULL, OPT_REVERSE},
492 {"underline", required_argument, NULL, OPT_UNDERLINE},
493 {"store", no_argument, NULL, OPT_STORE},
494 {"clear", required_argument, NULL, OPT_CLEAR},
495 {"tabs", optional_argument, NULL, OPT_TABS},
496 {"clrtabs", optional_argument, NULL, OPT_CLRTABS},
497 {"regtabs", optional_argument, NULL, OPT_REGTABS},
498 {"blank", optional_argument, NULL, OPT_BLANK},
499 {"dump", optional_argument, NULL, OPT_DUMP},
500 {"append", required_argument, NULL, OPT_APPEND},
501 {"file", required_argument, NULL, OPT_FILE},
502 {"msg", required_argument, NULL, OPT_MSG},
503 {"msglevel", required_argument, NULL, OPT_MSGLEVEL},
504 {"powersave", required_argument, NULL, OPT_POWERSAVE},
505 {"powerdown", optional_argument, NULL, OPT_POWERDOWN},
506 {"blength", optional_argument, NULL, OPT_BLENGTH},
507 {"bfreq", optional_argument, NULL, OPT_BFREQ},
508 {"version", no_argument, NULL, OPT_VERSION},
509 {"help", no_argument, NULL, OPT_HELP},
510 {NULL, 0, NULL, 0}
511 };
512 static const ul_excl_t excl[] = {
513 { OPT_DEFAULT, OPT_STORE },
514 { OPT_TABS, OPT_CLRTABS, OPT_REGTABS },
515 { OPT_MSG, OPT_MSGLEVEL },
516 { 0 }
517 };
518 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
519
520 while ((c = getopt_long_only(argc, argv, "", longopts, NULL)) != -1) {
521 err_exclusive_options(c, longopts, excl, excl_st);
522 switch (c) {
523 case OPT_TERM:
524 ctl->opt_term = set_opt_flag(ctl->opt_term);
525 ctl->opt_te_terminal_name = optarg;
526 break;
527 case OPT_RESET:
528 ctl->opt_reset = set_opt_flag(ctl->opt_reset);
529 break;
530 case OPT_INITIALIZE:
531 ctl->opt_initialize = set_opt_flag(ctl->opt_initialize);
532 break;
533 case OPT_CURSOR:
534 ctl->opt_cursor = set_opt_flag(ctl->opt_cursor);
535 ctl->opt_cu_on = parse_switch(optarg, _("argument error"),
536 "on", "off", NULL);
537 break;
538 case OPT_REPEAT:
539 ctl->opt_repeat = set_opt_flag(ctl->opt_repeat);
540 ctl->opt_rep_on = parse_switch(optarg, _("argument error"),
541 "on", "off", NULL);
542 break;
543 case OPT_APPCURSORKEYS:
544 ctl->opt_appcursorkeys = set_opt_flag(ctl->opt_appcursorkeys);
545 ctl->opt_appck_on = parse_switch(optarg, _("argument error"),
546 "on", "off", NULL);
547 break;
548 case OPT_LINEWRAP:
549 ctl->opt_linewrap = set_opt_flag(ctl->opt_linewrap);
550 ctl->opt_li_on = parse_switch(optarg, _("argument error"),
551 "on", "off", NULL);
552 break;
553 case OPT_DEFAULT:
554 ctl->opt_default = set_opt_flag(ctl->opt_default);
555 break;
556 case OPT_FOREGROUND:
557 ctl->opt_foreground = set_opt_flag(ctl->opt_foreground);
558 ctl->opt_fo_color = parse_febg_color(optarg);
559 break;
560 case OPT_BACKGROUND:
561 ctl->opt_background = set_opt_flag(ctl->opt_background);
562 ctl->opt_ba_color = parse_febg_color(optarg);
563 break;
564 case OPT_ULCOLOR:
565 ctl->opt_ulcolor = set_opt_flag(ctl->opt_ulcolor);
566 ctl->opt_ul_color = parse_ulhb_color(argv, &optind);
567 break;
568 case OPT_HBCOLOR:
569 ctl->opt_hbcolor = set_opt_flag(ctl->opt_hbcolor);
570 ctl->opt_hb_color = parse_ulhb_color(argv, &optind);
571 break;
572 case OPT_INVERSESCREEN:
573 ctl->opt_inversescreen = set_opt_flag(ctl->opt_inversescreen);
574 ctl->opt_invsc_on = parse_switch(optarg, _("argument error"),
575 "on", "off", NULL);
576 break;
577 case OPT_BOLD:
578 ctl->opt_bold = set_opt_flag(ctl->opt_bold);
579 ctl->opt_bo_on = parse_switch(optarg, _("argument error"),
580 "on", "off", NULL);
581 break;
582 case OPT_HALF_BRIGHT:
583 ctl->opt_halfbright = set_opt_flag(ctl->opt_halfbright);
584 ctl->opt_hb_on = parse_switch(optarg, _("argument error"),
585 "on", "off", NULL);
586 break;
587 case OPT_BLINK:
588 ctl->opt_blink = set_opt_flag(ctl->opt_blink);
589 ctl->opt_bl_on = parse_switch(optarg, _("argument error"),
590 "on", "off", NULL);
591 break;
592 case OPT_REVERSE:
593 ctl->opt_reverse = set_opt_flag(ctl->opt_reverse);
594 ctl->opt_re_on = parse_switch(optarg, _("argument error"),
595 "on", "off", NULL);
596 break;
597 case OPT_UNDERLINE:
598 ctl->opt_underline = set_opt_flag(ctl->opt_underline);
599 ctl->opt_un_on = parse_switch(optarg, _("argument error"),
600 "on", "off", NULL);
601 break;
602 case OPT_STORE:
603 ctl->opt_store = set_opt_flag(ctl->opt_store);
604 break;
605 case OPT_CLEAR:
606 ctl->opt_clear = set_opt_flag(ctl->opt_clear);
607 ctl->opt_cl_all = parse_switch(optarg, _("argument error"),
608 "all", "reset", NULL);
609 break;
610 case OPT_TABS:
611 ctl->opt_tabs = set_opt_flag(ctl->opt_tabs);
612 parse_tabs(argv, optarg, &optind, ctl->opt_tb_array);
613 break;
614 case OPT_CLRTABS:
615 ctl->opt_clrtabs = set_opt_flag(ctl->opt_clrtabs);
616 parse_tabs(argv, optarg, &optind, ctl->opt_tb_array);
617 break;
618 case OPT_REGTABS:
619 ctl->opt_regtabs = set_opt_flag(ctl->opt_regtabs);
620 ctl->opt_rt_len = parse_regtabs(argv, optarg, &optind);
621 break;
622 case OPT_BLANK:
623 ctl->opt_blank = set_opt_flag(ctl->opt_blank);
624 ctl->opt_bl_min = parse_blank(argv, optarg, &optind);
625 break;
626 case OPT_DUMP:
627 ctl->opt_snap = set_opt_flag(ctl->opt_snap);
628 ctl->opt_sn_num = parse_snap(argv, optarg, &optind);
629 break;
630 case OPT_APPEND:
631 ctl->opt_append = set_opt_flag(ctl->opt_append);
632 ctl->opt_sn_num = parse_snap(argv, optarg, &optind);
633 break;
634 case OPT_FILE:
635 ctl->opt_snapfile = set_opt_flag(ctl->opt_snapfile);
636 ctl->opt_sn_name = optarg;
637 break;
638 case OPT_MSG:
639 ctl->opt_msg = set_opt_flag(ctl->opt_msg);
640 ctl->opt_msg_on = parse_switch(optarg, _("argument error"),
641 "on", "off", NULL);
642 break;
643 case OPT_MSGLEVEL:
644 ctl->opt_msglevel = set_opt_flag(ctl->opt_msglevel);
645 ctl->opt_msglevel_num = parse_msglevel(optarg);
646 if (ctl->opt_msglevel_num == 0) {
647 ctl->opt_msg = set_opt_flag(ctl->opt_msg);
648 ctl->opt_msg_on |= 1;
649 }
650 break;
651 case OPT_POWERSAVE:
652 ctl->opt_powersave = set_opt_flag(ctl->opt_powersave);
653 ctl->opt_ps_mode = parse_powersave(optarg);
654 break;
655 case OPT_POWERDOWN:
656 ctl->opt_powerdown = set_opt_flag(ctl->opt_powerdown);
657 ctl->opt_pd_min = parse_blank(argv, optarg, &optind);
658 break;
659 case OPT_BLENGTH:
660 ctl->opt_blength = set_opt_flag(ctl->opt_blength);
661 ctl->opt_blength_l = parse_blength(argv, optarg, &optind);
662 break;
663 case OPT_BFREQ:
664 ctl->opt_bfreq = set_opt_flag(ctl->opt_bfreq);
665 ctl->opt_bfreq_f = parse_bfreq(argv, optarg, &optind);
666 break;
667 case OPT_VERSION:
668 printf(UTIL_LINUX_VERSION);
669 exit(EXIT_SUCCESS);
670 case OPT_HELP:
671 usage(stdout);
672 default:
673 usage(stderr);
674 }
675 }
676 }
677
678 /* Return the specified terminfo string, or an empty string if no such
679 * terminfo capability exists. */
680 static char *ti_entry(const char *name)
681 {
682 char *buf_ptr;
683
684 if ((buf_ptr = tigetstr((char *)name)) == (char *)-1)
685 buf_ptr = NULL;
686 return buf_ptr;
687 }
688
689 static void show_tabs(void)
690 {
691 int i, co = tigetnum("cols");
692
693 if (co > 0) {
694 printf("\r ");
695 for (i = 10; i < co - 2; i += 10)
696 printf("%-10d", i);
697 putchar('\n');
698 for (i = 1; i <= co; i++)
699 putchar(i % 10 + '0');
700 putchar('\n');
701 for (i = 1; i < co; i++)
702 printf("\tT\b");
703 putchar('\n');
704 }
705 }
706
707 static int open_snapshot_device(struct setterm_control *ctl)
708 {
709 int fd;
710
711 if (ctl->opt_sn_num)
712 xasprintf(&ctl->in_device, "/dev/vcsa%d", ctl->opt_sn_num);
713 else
714 xasprintf(&ctl->in_device, "/dev/vcsa");
715 fd = open(ctl->in_device, O_RDONLY);
716 if (fd < 0)
717 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
718 return fd;
719 }
720
721 static void set_blanking(struct setterm_control *ctl)
722 {
723 char ioctlarg;
724 int ret;
725
726 if (0 <= ctl->opt_bl_min) {
727 printf("\033[9;%d]", ctl->opt_bl_min);
728 return;
729 }
730 switch (ctl->opt_bl_min) {
731 case BLANKSCREEN:
732 ioctlarg = TIOCL_BLANKSCREEN;
733 if (ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg))
734 warn(_("cannot force blank"));
735 break;
736 case UNBLANKSCREEN:
737 ioctlarg = TIOCL_UNBLANKSCREEN;
738 if (ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg))
739 warn(_("cannot force unblank"));
740 break;
741 case BLANKEDSCREEN:
742 ioctlarg = TIOCL_BLANKEDSCREEN;
743 ret = ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg);
744 if (ret < 0)
745 warn(_("cannot get blank status"));
746 else
747 printf("%d\n", ret);
748 break;
749 default: /* should be impossible to reach */
750 abort();
751 }
752 return;
753 }
754
755 static void screendump(struct setterm_control *ctl)
756 {
757 unsigned char header[4];
758 unsigned int rows, cols;
759 int fd;
760 FILE *out;
761 size_t i, j;
762 ssize_t rc;
763 char *inbuf, *outbuf, *p, *q;
764
765 /* open source and destination files */
766 fd = open_snapshot_device(ctl);
767 if (!ctl->opt_sn_name)
768 ctl->opt_sn_name = "screen.dump";
769 out = fopen(ctl->opt_sn_name, ctl->opt_snap ? "w" : "a");
770 if (!out)
771 err(EXIT_DUMPFILE, _("can not open dump file %s for output"), ctl->opt_sn_name);
772 /* determine snapshot size */
773 if (read(fd, header, 4) != 4)
774 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
775 rows = header[0];
776 cols = header[1];
777 if (rows * cols == 0)
778 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
779 /* allocate buffers */
780 inbuf = xmalloc(rows * cols * 2);
781 outbuf = xmalloc(rows * (cols + 1));
782 /* read input */
783 rc = read(fd, inbuf, rows * cols * 2);
784 if (rc < 0 || (size_t)rc != rows * cols * 2)
785 err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
786 p = inbuf;
787 q = outbuf;
788 /* copy inbuf to outbuf */
789 for (i = 0; i < rows; i++) {
790 for (j = 0; j < cols; j++) {
791 *q++ = *p;
792 p += 2;
793 }
794 while (j-- > 0 && q[-1] == ' ')
795 q--;
796 *q++ = '\n';
797 }
798 fwrite(outbuf, 1, q - outbuf, out);
799 /* clean up allocations */
800 close(fd);
801 free(inbuf);
802 free(outbuf);
803 free(ctl->in_device);
804 if (close_stream(out) != 0)
805 errx(EXIT_FAILURE, _("write error"));
806 return;
807 }
808
809 /* Some options are applicable when terminal is virtual console. */
810 static int vc_only(struct setterm_control *ctl, const char *err)
811 {
812 if (!ctl->vcterm) {
813 if (err)
814 warnx(_("terminal %s does not support %s"),
815 ctl->opt_te_terminal_name, err);
816 }
817 return ctl->vcterm;
818 }
819
820 static void perform_sequence(struct setterm_control *ctl)
821 {
822 int result;
823
824 /* -reset. */
825 if (ctl->opt_reset)
826 putp(ti_entry("rs1"));
827
828 /* -initialize. */
829 if (ctl->opt_initialize)
830 putp(ti_entry("is2"));
831
832 /* -cursor [on|off]. */
833 if (ctl->opt_cursor) {
834 if (ctl->opt_cu_on)
835 putp(ti_entry("cnorm"));
836 else
837 putp(ti_entry("civis"));
838 }
839
840 /* -linewrap [on|off]. */
841 if (ctl->opt_linewrap)
842 fputs(ctl->opt_li_on ? "\033[?7h" : "\033[?7l", stdout);
843
844 /* -repeat [on|off]. */
845 if (ctl->opt_repeat && vc_only(ctl, "--repeat"))
846 fputs(ctl->opt_rep_on ? "\033[?8h" : "\033[?8l", stdout);
847
848 /* -appcursorkeys [on|off]. */
849 if (ctl->opt_appcursorkeys && vc_only(ctl, "--appcursorkeys"))
850 fputs(ctl->opt_appck_on ? "\033[?1h" : "\033[?1l", stdout);
851
852 /* -default. Vc sets default rendition, otherwise clears all
853 * attributes. */
854 if (ctl->opt_default) {
855 if (vc_only(ctl, NULL))
856 printf("\033[0m");
857 else
858 putp(ti_entry("sgr0"));
859 }
860
861 /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
862 if (ctl->opt_foreground)
863 printf("\033[3%c%s", '0' + ctl->opt_fo_color, "m");
864
865 /* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
866 if (ctl->opt_background)
867 printf("\033[4%c%s", '0' + ctl->opt_ba_color, "m");
868
869 /* -ulcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
870 if (ctl->opt_ulcolor && vc_only(ctl, "--ulcolor"))
871 printf("\033[1;%d]", ctl->opt_ul_color);
872
873 /* -hbcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
874 if (ctl->opt_hbcolor)
875 printf("\033[2;%d]", ctl->opt_hb_color);
876
877 /* -inversescreen [on|off]. */
878 if (ctl->opt_inversescreen)
879 fputs(ctl->opt_invsc_on ? "\033[?5h" : "\033[?5l", stdout);
880
881 /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
882 * all attributes. */
883 if (ctl->opt_bold) {
884 if (ctl->opt_bo_on)
885 putp(ti_entry("bold"));
886 else {
887 if (vc_only(ctl, NULL))
888 fputs("\033[22m", stdout);
889 else
890 putp(ti_entry("sgr0"));
891 }
892 }
893
894 /* -half-bright [on|off]. Vc behaves as expected, otherwise off
895 * turns off all attributes. */
896 if (ctl->opt_halfbright) {
897 if (ctl->opt_hb_on)
898 putp(ti_entry("dim"));
899 else {
900 if (vc_only(ctl, NULL))
901 fputs("\033[22m", stdout);
902 else
903 putp(ti_entry("sgr0"));
904 }
905 }
906
907 /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
908 * all attributes. */
909 if (ctl->opt_blink) {
910 if (ctl->opt_bl_on)
911 putp(ti_entry("blink"));
912 else {
913 if (vc_only(ctl, NULL))
914 fputs("\033[25m", stdout);
915 else
916 putp(ti_entry("sgr0"));
917 }
918 }
919
920 /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
921 * off all attributes. */
922 if (ctl->opt_reverse) {
923 if (ctl->opt_re_on)
924 putp(ti_entry("rev"));
925 else {
926 if (vc_only(ctl, NULL))
927 fputs("\033[27m", stdout);
928 else
929 putp(ti_entry("sgr0"));
930 }
931 }
932
933 /* -underline [on|off]. */
934 if (ctl->opt_underline)
935 putp(ti_entry(ctl->opt_un_on ? "smul" : "rmul"));
936
937 /* -store. */
938 if (ctl->opt_store && vc_only(ctl, "--store"))
939 fputs("\033[8]", stdout);
940
941 /* -clear [all|rest]. */
942 if (ctl->opt_clear)
943 putp(ti_entry(ctl->opt_cl_all ? "clear" : "ed"));
944
945 /* -tabs. */
946 if (ctl->opt_tabs) {
947 if (ctl->opt_tb_array[0] == -1)
948 show_tabs();
949 else {
950 int i;
951
952 for (i = 0; ctl->opt_tb_array[i] > 0; i++)
953 printf("\033[%dG\033H", ctl->opt_tb_array[i]);
954 putchar('\r');
955 }
956 }
957
958 /* -clrtabs. */
959 if (ctl->opt_clrtabs && vc_only(ctl, "--clrtabs")) {
960 int i;
961
962 if (ctl->opt_tb_array[0] == -1)
963 fputs("\033[3g", stdout);
964 else
965 for (i = 0; ctl->opt_tb_array[i] > 0; i++)
966 printf("\033[%dG\033[g", ctl->opt_tb_array[i]);
967 putchar('\r');
968 }
969
970 /* -regtabs. */
971 if (ctl->opt_regtabs && vc_only(ctl, "--regtabs")) {
972 int i;
973
974 fputs("\033[3g\r", stdout);
975 for (i = ctl->opt_rt_len + 1; i <= TABS_MAX; i += ctl->opt_rt_len)
976 printf("\033[%dC\033H", ctl->opt_rt_len);
977 putchar('\r');
978 }
979
980 /* -blank [0-60]. */
981 if (ctl->opt_blank && vc_only(ctl, "--blank"))
982 set_blanking(ctl);
983
984 /* -powersave [on|vsync|hsync|powerdown|off] (console) */
985 if (ctl->opt_powersave) {
986 char ioctlarg[2];
987 ioctlarg[0] = TIOCL_SETVESABLANK;
988 ioctlarg[1] = ctl->opt_ps_mode;
989 if (ioctl(STDIN_FILENO, TIOCLINUX, ioctlarg))
990 warn(_("cannot (un)set powersave mode"));
991 }
992
993 /* -powerdown [0-60]. */
994 if (ctl->opt_powerdown)
995 printf("\033[14;%d]", ctl->opt_pd_min);
996
997 /* -snap [1-NR_CONS]. */
998 if (ctl->opt_snap || ctl->opt_append)
999 screendump(ctl);
1000
1001 /* -msg [on|off]. Controls printk's to console. */
1002 if (ctl->opt_msg && vc_only(ctl, "--msg")) {
1003 if (ctl->opt_msg_on)
1004 result = klogctl(SYSLOG_ACTION_CONSOLE_ON, NULL, 0);
1005 else
1006 result = klogctl(SYSLOG_ACTION_CONSOLE_OFF, NULL, 0);
1007
1008 if (result != 0)
1009 warn(_("klogctl error"));
1010 }
1011
1012 /* -msglevel [0-8]. Console printk message level. */
1013 if (ctl->opt_msglevel_num && vc_only(ctl, "--msglevel")) {
1014 result =
1015 klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL,
1016 ctl->opt_msglevel_num);
1017 if (result != 0)
1018 warn(_("klogctl error"));
1019 }
1020
1021 /* -blength [0-2000] */
1022 if (ctl->opt_blength && vc_only(ctl, "--blength")) {
1023 printf("\033[11;%d]", ctl->opt_blength_l);
1024 }
1025
1026 /* -bfreq freqnumber */
1027 if (ctl->opt_bfreq && vc_only(ctl, "--bfreq")) {
1028 printf("\033[10;%d]", ctl->opt_bfreq_f);
1029 }
1030 }
1031
1032 static void init_terminal(struct setterm_control *ctl)
1033 {
1034 int term_errno;
1035
1036 if (!ctl->opt_te_terminal_name) {
1037 ctl->opt_te_terminal_name = getenv("TERM");
1038 if (ctl->opt_te_terminal_name == NULL)
1039 errx(EXIT_FAILURE, _("$TERM is not defined."));
1040 }
1041
1042 /* Find terminfo entry. */
1043 if (setupterm(ctl->opt_te_terminal_name, STDOUT_FILENO, &term_errno))
1044 switch (term_errno) {
1045 case -1:
1046 errx(EXIT_FAILURE, _("terminfo database cannot be found"));
1047 case 0:
1048 errx(EXIT_FAILURE, _("%s: unknown terminal type"), ctl->opt_te_terminal_name);
1049 case 1:
1050 errx(EXIT_FAILURE, _("terminal is hardcopy"));
1051 }
1052
1053 /* See if the terminal is a virtual console terminal. */
1054 ctl->vcterm = (!strncmp(ctl->opt_te_terminal_name, "con", 3) ||
1055 !strncmp(ctl->opt_te_terminal_name, "linux", 5));
1056 }
1057
1058
1059 int main(int argc, char **argv)
1060 {
1061 struct setterm_control ctl = { 0 };
1062
1063 setlocale(LC_ALL, "");
1064 bindtextdomain(PACKAGE, LOCALEDIR);
1065 textdomain(PACKAGE);
1066 atexit(close_stdout);
1067
1068 if (argc < 2)
1069 usage(stderr);
1070
1071 parse_option(&ctl, argc, argv);
1072 init_terminal(&ctl);
1073 perform_sequence(&ctl);
1074
1075 return EXIT_SUCCESS;
1076 }