1 /* setterm.c, set terminal attributes.
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.
7 * Adaption to Linux by Peter MacDonald.
9 * Enhancements by Mika Liljeberg (liljeber@cs.Helsinki.FI)
11 * Beep modifications by Christophe Jolif (cjolif@storm.gatelink.fr.net)
13 * Sanity increases by Cafeine Addict [sic].
15 * Powersave features by todd j. derr <tjd@wordsmith.org>
17 * Converted to terminfo by Kars de Jong (jongk@cs.utwente.nl)
19 * 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL>
20 * - added Native Language Support
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
33 * The following options are non-obvious.
35 * -term can be used to override the TERM environment variable.
37 * -reset displays the terminal reset string, which typically resets the
38 * terminal to its power on state.
40 * -initialize displays the terminal initialization string, which typically
41 * sets the terminal's rendering options, and other attributes to the
44 * -default sets the terminal's rendering options to the default values.
46 * -store stores the terminal's current rendering options as the default
56 #include <sys/ioctl.h>
58 #include <sys/param.h> /* for MAXPATHLEN */
63 #if defined(HAVE_NCURSESW_TERM_H)
64 # include <ncursesw/term.h>
65 #elif defined(HAVE_NCURSES_TERM_H)
66 # include <ncurses/term.h>
67 #elif defined(HAVE_TERM_H)
71 #ifdef HAVE_LINUX_TIOCL_H
72 # include <linux/tiocl.h>
77 #include "closestream.h"
85 /* Non-standard return values. */
86 #define EXIT_DUMPFILE -1
102 static const char *colornames
[] = {
112 [DEFAULT
] = "default"
115 #define is_valid_color(x) (x >= 0 && (size_t) x < ARRAY_SIZE(colornames))
124 /* <linux/tiocl.h> fallback */
125 #ifndef TIOCL_BLANKSCREEN
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 */
134 /* Powersave modes */
136 VESA_BLANK_MODE_OFF
= 0,
137 VESA_BLANK_MODE_SUSPENDV
,
138 VESA_BLANK_MODE_SUSPENDH
,
139 VESA_BLANK_MODE_POWERDOWN
142 /* klogctl() actions */
144 SYSLOG_ACTION_CONSOLE_OFF
= 6,
145 SYSLOG_ACTION_CONSOLE_ON
= 7,
146 SYSLOG_ACTION_CONSOLE_LEVEL
= 8
149 /* Console log levels */
151 CONSOLE_LEVEL_MIN
= 0,
152 CONSOLE_LEVEL_MAX
= 8
155 /* Various numbers */
156 #define DEFAULT_TAB_LEN 8
159 #define BLENGTH_MAX 2000
161 /* Command controls. */
162 struct 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 */
167 int opt_sn_num
; /* console number to be snapshot */
168 char *opt_sn_name
; /* path to write snap */
169 char *in_device
; /* device to snapshot */
170 int opt_msglevel_num
; /* printk() logging level */
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 */
176 unsigned int opt_fo_color
:4, opt_ba_color
:4, opt_ul_color
:4, opt_hb_color
:4;
177 /* boolean options */
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,
182 /* Option flags. Set when an option is invoked. */
183 uint64_t opt_term
:1, opt_reset
:1, opt_resize
:1, opt_initialize
:1, opt_cursor
:1,
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;
194 static int parse_color(const char *arg
)
198 for (i
= 0; i
< ARRAY_SIZE(colornames
); i
++) {
199 if (strcmp(colornames
[i
], arg
) == 0)
206 static int parse_febg_color(const char *arg
)
208 int color
= parse_color(arg
);
211 color
= strtos32_or_err(arg
, _("argument error"));
213 if (!is_valid_color(color
) || color
== GREY
)
214 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
218 static int parse_ulhb_color(char **av
, int *oi
)
224 if (av
[*oi
] && strcmp(av
[*oi
- 1], "bright") == 0) {
226 color_name
= av
[*oi
];
229 color_name
= av
[*oi
- 1];
231 color
= parse_color(color_name
);
233 color
= strtos32_or_err(color_name
, _("argument error"));
234 if (!is_valid_color(color
) || color
== DEFAULT
)
235 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), color_name
);
236 if (bright
&& (color
== BLACK
|| color
== GREY
))
237 errx(EXIT_FAILURE
, _("argument error: bright %s is not supported"), color_name
);
245 static char *find_optional_arg(char **av
, char *oa
, int *oi
)
252 if (!arg
|| arg
[0] == '-')
259 static int parse_blank(char **av
, char *oa
, int *oi
)
263 arg
= find_optional_arg(av
, oa
, oi
);
265 return BLANKEDSCREEN
;
266 if (!strcmp(arg
, "force"))
268 if (!strcmp(arg
, "poke"))
269 return UNBLANKSCREEN
;
273 ret
= strtos32_or_err(arg
, _("argument error"));
274 if (ret
< 0 || BLANK_MAX
< ret
)
275 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
279 static int parse_powersave(const char *arg
)
281 if (strcmp(arg
, "on") == 0)
282 return VESA_BLANK_MODE_SUSPENDV
;
283 if (strcmp(arg
, "vsync") == 0)
284 return VESA_BLANK_MODE_SUSPENDV
;
285 if (strcmp(arg
, "hsync") == 0)
286 return VESA_BLANK_MODE_SUSPENDH
;
287 if (strcmp(arg
, "powerdown") == 0)
288 return VESA_BLANK_MODE_POWERDOWN
;
289 if (strcmp(arg
, "off") == 0)
290 return VESA_BLANK_MODE_OFF
;
291 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
294 static int parse_msglevel(const char *arg
)
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
);
304 static int parse_snap(char **av
, char *oa
, int *oi
)
309 arg
= find_optional_arg(av
, oa
, oi
);
312 ret
= strtos32_or_err(arg
, _("argument error"));
314 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
318 static void parse_tabs(char **av
, char *oa
, int *oi
, int *tab_array
)
323 tab_array
[i
] = strtos32_or_err(oa
, _("argument error"));
328 errx(EXIT_FAILURE
, _("too many tabs"));
329 if (av
[*oi
][0] == '-')
331 tab_array
[i
] = strtos32_or_err(av
[*oi
], _("argument error"));
338 static int parse_regtabs(char **av
, char *oa
, int *oi
)
343 arg
= find_optional_arg(av
, oa
, oi
);
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
);
352 static int parse_blength(char **av
, char *oa
, int *oi
)
357 arg
= find_optional_arg(av
, oa
, oi
);
360 ret
= strtos32_or_err(arg
, _("argument error"));
361 if (ret
< 0 || BLENGTH_MAX
< ret
)
362 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
366 static int parse_bfreq(char **av
, char *oa
, int *oi
)
370 arg
= find_optional_arg(av
, oa
, oi
);
373 return strtos32_or_err(arg
, _("argument error"));
376 static void __attribute__((__noreturn__
)) usage(void)
379 fputs(USAGE_HEADER
, out
);
381 _(" %s [options]\n"), program_invocation_short_name
);
383 fputs(USAGE_SEPARATOR
, out
);
384 fputs(_("Set the attributes of a terminal.\n"), out
);
386 fputs(USAGE_OPTIONS
, out
);
387 fputs(_(" --term <terminal_name> override TERM environment variable\n"), out
);
388 fputs(_(" --reset reset terminal to power-on state\n"), out
);
389 fputs(_(" --resize reset terminal rows and columns\n"), out
);
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(USAGE_SEPARATOR
, out
);
395 fputs(_(" --cursor on|off display cursor\n"), out
);
396 fputs(_(" --repeat on|off keyboard repeat\n"), out
);
397 fputs(_(" --appcursorkeys on|off cursor key application mode\n"), out
);
398 fputs(_(" --linewrap on|off continue on a new line when a line is full\n"), out
);
399 fputs(_(" --inversescreen on|off swap colors for the whole screen\n"), out
);
400 fputs(USAGE_SEPARATOR
, out
);
402 fputs(_(" --msg on|off send kernel messages to console\n"), out
);
403 fputs(_(" --msglevel <0-8> kernel console log level\n"), out
);
404 fputs(USAGE_SEPARATOR
, out
);
406 fputs(_(" --foreground default|<color> set foreground color\n"), out
);
407 fputs(_(" --background default|<color> set background color\n"), out
);
408 fputs(_(" --ulcolor [bright] <color> set underlined text color\n"), out
);
409 fputs(_(" --hbcolor [bright] <color> set half-bright text color\n"), out
);
410 fputs(_(" <color>: black blue cyan green grey magenta red white yellow\n"), out
);
411 fputs(USAGE_SEPARATOR
, out
);
413 fputs(_(" --bold on|off bold\n"), out
);
414 fputs(_(" --half-bright on|off dim\n"), out
);
415 fputs(_(" --blink on|off blink\n"), out
);
416 fputs(_(" --underline on|off underline\n"), out
);
417 fputs(_(" --reverse on|off swap foreground and background colors\n"), out
);
418 fputs(USAGE_SEPARATOR
, out
);
420 fputs(_(" --clear[=<all|rest>] clear screen and set cursor position\n"), out
);
421 fputs(_(" --tabs[=<number>...] set these tab stop positions, or show them\n"), out
);
422 fputs(_(" --clrtabs[=<number>...] clear these tab stop positions, or all\n"), out
);
423 fputs(_(" --regtabs[=1-160] set a regular tab stop interval\n"), out
);
424 fputs(_(" --blank[=0-60|force|poke] set time of inactivity before screen blanks\n"), out
);
425 fputs(USAGE_SEPARATOR
, out
);
427 fputs(_(" --dump[=<number>] write vcsa<number> console dump to file\n"), out
);
428 fputs(_(" --append <number> append vcsa<number> console dump to file\n"), out
);
429 fputs(_(" --file <filename> name of the dump file\n"), out
);
430 fputs(USAGE_SEPARATOR
, out
);
432 fputs(_(" --powersave on|vsync|hsync|powerdown|off\n"), out
);
433 fputs(_(" set vesa powersaving features\n"), out
);
434 fputs(_(" --powerdown[=<0-60>] set vesa powerdown interval in minutes\n"), out
);
435 fputs(USAGE_SEPARATOR
, out
);
437 fputs(_(" --blength[=<0-2000>] duration of the bell in milliseconds\n"), out
);
438 fputs(_(" --bfreq[=<number>] bell frequency in Hertz\n"), out
);
440 fputs(USAGE_SEPARATOR
, out
);
441 fprintf(out
, " --help %s\n", USAGE_OPTSTR_HELP
);
442 fprintf(out
, " --version %s\n", USAGE_OPTSTR_VERSION
);
444 fprintf(out
, USAGE_MAN_TAIL("setterm(1)"));
448 static int __attribute__((__pure__
)) set_opt_flag(int opt
)
451 errx(EXIT_FAILURE
, _("duplicate use of an option"));
455 static void parse_option(struct setterm_control
*ctl
, int ac
, char **av
)
459 OPT_TERM
= CHAR_MAX
+ 1,
496 static const struct option longopts
[] = {
497 {"term", required_argument
, NULL
, OPT_TERM
},
498 {"reset", no_argument
, NULL
, OPT_RESET
},
499 {"resize", no_argument
, NULL
, OPT_RESIZE
},
500 {"initialize", no_argument
, NULL
, OPT_INITIALIZE
},
501 {"cursor", required_argument
, NULL
, OPT_CURSOR
},
502 {"repeat", required_argument
, NULL
, OPT_REPEAT
},
503 {"appcursorkeys", required_argument
, NULL
, OPT_APPCURSORKEYS
},
504 {"linewrap", required_argument
, NULL
, OPT_LINEWRAP
},
505 {"default", no_argument
, NULL
, OPT_DEFAULT
},
506 {"foreground", required_argument
, NULL
, OPT_FOREGROUND
},
507 {"background", required_argument
, NULL
, OPT_BACKGROUND
},
508 {"ulcolor", required_argument
, NULL
, OPT_ULCOLOR
},
509 {"hbcolor", required_argument
, NULL
, OPT_HBCOLOR
},
510 {"inversescreen", required_argument
, NULL
, OPT_INVERSESCREEN
},
511 {"bold", required_argument
, NULL
, OPT_BOLD
},
512 {"half-bright", required_argument
, NULL
, OPT_HALF_BRIGHT
},
513 {"blink", required_argument
, NULL
, OPT_BLINK
},
514 {"reverse", required_argument
, NULL
, OPT_REVERSE
},
515 {"underline", required_argument
, NULL
, OPT_UNDERLINE
},
516 {"store", no_argument
, NULL
, OPT_STORE
},
517 {"clear", optional_argument
, NULL
, OPT_CLEAR
},
518 {"tabs", optional_argument
, NULL
, OPT_TABS
},
519 {"clrtabs", optional_argument
, NULL
, OPT_CLRTABS
},
520 {"regtabs", optional_argument
, NULL
, OPT_REGTABS
},
521 {"blank", optional_argument
, NULL
, OPT_BLANK
},
522 {"dump", optional_argument
, NULL
, OPT_DUMP
},
523 {"append", required_argument
, NULL
, OPT_APPEND
},
524 {"file", required_argument
, NULL
, OPT_FILE
},
525 {"msg", required_argument
, NULL
, OPT_MSG
},
526 {"msglevel", required_argument
, NULL
, OPT_MSGLEVEL
},
527 {"powersave", required_argument
, NULL
, OPT_POWERSAVE
},
528 {"powerdown", optional_argument
, NULL
, OPT_POWERDOWN
},
529 {"blength", optional_argument
, NULL
, OPT_BLENGTH
},
530 {"bfreq", optional_argument
, NULL
, OPT_BFREQ
},
531 {"version", no_argument
, NULL
, OPT_VERSION
},
532 {"help", no_argument
, NULL
, OPT_HELP
},
535 static const ul_excl_t excl
[] = {
536 { OPT_DEFAULT
, OPT_STORE
},
537 { OPT_TABS
, OPT_CLRTABS
, OPT_REGTABS
},
538 { OPT_MSG
, OPT_MSGLEVEL
},
541 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
543 while ((c
= getopt_long_only(ac
, av
, "", longopts
, NULL
)) != -1) {
544 err_exclusive_options(c
, longopts
, excl
, excl_st
);
547 ctl
->opt_term
= set_opt_flag(ctl
->opt_term
);
548 ctl
->opt_te_terminal_name
= optarg
;
551 ctl
->opt_reset
= set_opt_flag(ctl
->opt_reset
);
554 ctl
->opt_resize
= set_opt_flag(ctl
->opt_resize
);
557 ctl
->opt_initialize
= set_opt_flag(ctl
->opt_initialize
);
560 ctl
->opt_cursor
= set_opt_flag(ctl
->opt_cursor
);
561 ctl
->opt_cu_on
= parse_switch(optarg
, _("argument error"),
565 ctl
->opt_repeat
= set_opt_flag(ctl
->opt_repeat
);
566 ctl
->opt_rep_on
= parse_switch(optarg
, _("argument error"),
569 case OPT_APPCURSORKEYS
:
570 ctl
->opt_appcursorkeys
= set_opt_flag(ctl
->opt_appcursorkeys
);
571 ctl
->opt_appck_on
= parse_switch(optarg
, _("argument error"),
575 ctl
->opt_linewrap
= set_opt_flag(ctl
->opt_linewrap
);
576 ctl
->opt_li_on
= parse_switch(optarg
, _("argument error"),
580 ctl
->opt_default
= set_opt_flag(ctl
->opt_default
);
583 ctl
->opt_foreground
= set_opt_flag(ctl
->opt_foreground
);
584 ctl
->opt_fo_color
= parse_febg_color(optarg
);
587 ctl
->opt_background
= set_opt_flag(ctl
->opt_background
);
588 ctl
->opt_ba_color
= parse_febg_color(optarg
);
591 ctl
->opt_ulcolor
= set_opt_flag(ctl
->opt_ulcolor
);
592 ctl
->opt_ul_color
= parse_ulhb_color(av
, &optind
);
595 ctl
->opt_hbcolor
= set_opt_flag(ctl
->opt_hbcolor
);
596 ctl
->opt_hb_color
= parse_ulhb_color(av
, &optind
);
598 case OPT_INVERSESCREEN
:
599 ctl
->opt_inversescreen
= set_opt_flag(ctl
->opt_inversescreen
);
600 ctl
->opt_invsc_on
= parse_switch(optarg
, _("argument error"),
604 ctl
->opt_bold
= set_opt_flag(ctl
->opt_bold
);
605 ctl
->opt_bo_on
= parse_switch(optarg
, _("argument error"),
608 case OPT_HALF_BRIGHT
:
609 ctl
->opt_halfbright
= set_opt_flag(ctl
->opt_halfbright
);
610 ctl
->opt_hb_on
= parse_switch(optarg
, _("argument error"),
614 ctl
->opt_blink
= set_opt_flag(ctl
->opt_blink
);
615 ctl
->opt_bl_on
= parse_switch(optarg
, _("argument error"),
619 ctl
->opt_reverse
= set_opt_flag(ctl
->opt_reverse
);
620 ctl
->opt_re_on
= parse_switch(optarg
, _("argument error"),
624 ctl
->opt_underline
= set_opt_flag(ctl
->opt_underline
);
625 ctl
->opt_un_on
= parse_switch(optarg
, _("argument error"),
629 ctl
->opt_store
= set_opt_flag(ctl
->opt_store
);
632 ctl
->opt_clear
= set_opt_flag(ctl
->opt_clear
);
634 ctl
->opt_cl_all
= parse_switch(optarg
, _("argument error"),
635 "all", "rest", NULL
);
640 ctl
->opt_tabs
= set_opt_flag(ctl
->opt_tabs
);
641 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
644 ctl
->opt_clrtabs
= set_opt_flag(ctl
->opt_clrtabs
);
645 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
648 ctl
->opt_regtabs
= set_opt_flag(ctl
->opt_regtabs
);
649 ctl
->opt_rt_len
= parse_regtabs(av
, optarg
, &optind
);
652 ctl
->opt_blank
= set_opt_flag(ctl
->opt_blank
);
653 ctl
->opt_bl_min
= parse_blank(av
, optarg
, &optind
);
656 ctl
->opt_snap
= set_opt_flag(ctl
->opt_snap
);
657 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
660 ctl
->opt_append
= set_opt_flag(ctl
->opt_append
);
661 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
664 ctl
->opt_snapfile
= set_opt_flag(ctl
->opt_snapfile
);
665 ctl
->opt_sn_name
= optarg
;
668 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
669 ctl
->opt_msg_on
= parse_switch(optarg
, _("argument error"),
673 ctl
->opt_msglevel
= set_opt_flag(ctl
->opt_msglevel
);
674 ctl
->opt_msglevel_num
= parse_msglevel(optarg
);
675 if (ctl
->opt_msglevel_num
== 0) {
676 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
677 ctl
->opt_msg_on
|= 1;
681 ctl
->opt_powersave
= set_opt_flag(ctl
->opt_powersave
);
682 ctl
->opt_ps_mode
= parse_powersave(optarg
);
685 ctl
->opt_powerdown
= set_opt_flag(ctl
->opt_powerdown
);
686 ctl
->opt_pd_min
= parse_blank(av
, optarg
, &optind
);
689 ctl
->opt_blength
= set_opt_flag(ctl
->opt_blength
);
690 ctl
->opt_blength_l
= parse_blength(av
, optarg
, &optind
);
693 ctl
->opt_bfreq
= set_opt_flag(ctl
->opt_bfreq
);
694 ctl
->opt_bfreq_f
= parse_bfreq(av
, optarg
, &optind
);
698 print_version(EXIT_SUCCESS
);
702 errtryhelp(EXIT_FAILURE
);
707 /* Return the specified terminfo string, or an empty string if no such
708 * terminfo capability exists. */
709 static char *ti_entry(const char *name
)
713 if ((buf_ptr
= tigetstr(name
)) == (char *)-1)
718 static void show_tabs(void)
720 int i
, co
= tigetnum("cols");
724 for (i
= 10; i
< co
- 2; i
+= 10)
727 for (i
= 1; i
<= co
; i
++)
728 putchar(i
% 10 + '0');
730 for (i
= 1; i
< co
; i
++)
736 static int open_snapshot_device(struct setterm_control
*ctl
)
741 xasprintf(&ctl
->in_device
, "/dev/vcsa%d", ctl
->opt_sn_num
);
743 xasprintf(&ctl
->in_device
, "/dev/vcsa");
744 fd
= open(ctl
->in_device
, O_RDONLY
);
746 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
750 static void set_blanking(struct setterm_control
*ctl
)
755 if (0 <= ctl
->opt_bl_min
) {
756 printf("\033[9;%d]", ctl
->opt_bl_min
);
759 switch (ctl
->opt_bl_min
) {
761 ioctlarg
= TIOCL_BLANKSCREEN
;
762 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
763 warn(_("cannot force blank"));
766 ioctlarg
= TIOCL_UNBLANKSCREEN
;
767 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
768 warn(_("cannot force unblank"));
771 ioctlarg
= TIOCL_BLANKEDSCREEN
;
772 ret
= ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
);
774 warn(_("cannot get blank status"));
778 default: /* should be impossible to reach */
783 static void screendump(struct setterm_control
*ctl
)
785 unsigned char header
[4];
786 unsigned int rows
, cols
;
791 char *inbuf
, *outbuf
, *p
, *q
;
793 /* open source and destination files */
794 fd
= open_snapshot_device(ctl
);
795 if (!ctl
->opt_sn_name
)
796 ctl
->opt_sn_name
= "screen.dump";
797 out
= fopen(ctl
->opt_sn_name
, ctl
->opt_snap
? "w" : "a");
799 err(EXIT_DUMPFILE
, _("cannot open dump file %s for output"), ctl
->opt_sn_name
);
800 /* determine snapshot size */
801 if (read(fd
, header
, 4) != 4)
802 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
805 if (rows
* cols
== 0)
806 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
807 /* allocate buffers */
808 inbuf
= xmalloc(rows
* cols
* 2);
809 outbuf
= xmalloc(rows
* (cols
+ 1));
811 rc
= read(fd
, inbuf
, rows
* cols
* 2);
812 if (rc
< 0 || (size_t)rc
!= rows
* cols
* 2)
813 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
816 /* copy inbuf to outbuf */
817 for (i
= 0; i
< rows
; i
++) {
818 for (j
= 0; j
< cols
; j
++) {
822 while (j
-- > 0 && q
[-1] == ' ')
826 fwrite(outbuf
, 1, q
- outbuf
, out
);
827 /* clean up allocations */
831 free(ctl
->in_device
);
832 if (close_stream(out
) != 0)
833 errx(EXIT_FAILURE
, _("write error"));
836 /* Some options are applicable when terminal is virtual console. */
837 static int vc_only(struct setterm_control
*ctl
, const char *err
)
839 if (!ctl
->vcterm
&& err
)
840 warnx(_("terminal %s does not support %s"),
841 ctl
->opt_te_terminal_name
, err
);
845 static void tty_raw(struct termios
*saved_attributes
, int *saved_fl
)
847 struct termios tattr
;
849 fcntl(STDIN_FILENO
, F_GETFL
, saved_fl
);
850 tcgetattr(STDIN_FILENO
, saved_attributes
);
851 fcntl(STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
852 memcpy(&tattr
, saved_attributes
, sizeof(struct termios
));
853 tattr
.c_lflag
&= ~(ICANON
| ECHO
);
854 tattr
.c_cc
[VMIN
] = 1;
855 tattr
.c_cc
[VTIME
] = 0;
856 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tattr
);
859 static void tty_restore(struct termios
*saved_attributes
, int *saved_fl
)
861 fcntl(STDIN_FILENO
, F_SETFL
, *saved_fl
);
862 tcsetattr(STDIN_FILENO
, TCSANOW
, saved_attributes
);
865 static int select_wait(void)
872 FD_SET(STDIN_FILENO
, &set
);
875 while ((ret
= select(1, &set
, NULL
, NULL
, &tv
)) < 0) {
878 err(EXIT_FAILURE
, _("select failed"));
883 static int resizetty(void)
886 * \e7 Save current state (cursor coordinates, attributes,
887 * character sets pointed at by G0, G1).
888 * \e[r Set scrolling region; parameters are top and bottom row.
889 * \e[32766E Move cursor down 32766 (INT16_MAX - 1) rows.
890 * \e[32766C Move cursor right 32766 columns.
891 * \e[6n Report cursor position.
892 * \e8 Restore state most recently saved by \e7.
894 static const char *getpos
= "\e7\e[r\e[32766E\e[32766C\e[6n\e8";
900 struct termios saved_attributes
;
903 if (!isatty(STDIN_FILENO
))
904 errx(EXIT_FAILURE
, _("stdin does not refer to a terminal"));
906 tty_raw(&saved_attributes
, &saved_fl
);
907 if (write_all(STDIN_FILENO
, getpos
, strlen(getpos
)) < 0) {
908 warn(_("write failed"));
909 tty_restore(&saved_attributes
, &saved_fl
);
912 for (pos
= 0; pos
< sizeof(retstr
) - 1;) {
913 if (0 == select_wait())
916 read(STDIN_FILENO
, retstr
+ pos
,
917 sizeof(retstr
) - 1 - pos
)) < 0) {
920 warn(_("read failed"));
921 tty_restore(&saved_attributes
, &saved_fl
);
925 if (retstr
[pos
- 1] == 'R')
929 tty_restore(&saved_attributes
, &saved_fl
);
930 rc
= sscanf(retstr
, "\033[%d;%dR", &row
, &col
);
932 warnx(_("invalid cursor position: %s"), retstr
);
935 memset(&ws
, 0, sizeof(struct winsize
));
936 ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
);
939 ioctl(STDIN_FILENO
, TIOCSWINSZ
, &ws
);
943 static void perform_sequence(struct setterm_control
*ctl
)
949 putp(ti_entry("rs1"));
954 warnx(_("reset failed"));
957 if (ctl
->opt_initialize
)
958 putp(ti_entry("is2"));
960 /* -cursor [on|off]. */
961 if (ctl
->opt_cursor
) {
963 putp(ti_entry("cnorm"));
965 putp(ti_entry("civis"));
968 /* -linewrap [on|off]. */
969 if (ctl
->opt_linewrap
)
970 fputs(ctl
->opt_li_on
? "\033[?7h" : "\033[?7l", stdout
);
972 /* -repeat [on|off]. */
973 if (ctl
->opt_repeat
&& vc_only(ctl
, "--repeat"))
974 fputs(ctl
->opt_rep_on
? "\033[?8h" : "\033[?8l", stdout
);
976 /* -appcursorkeys [on|off]. */
977 if (ctl
->opt_appcursorkeys
&& vc_only(ctl
, "--appcursorkeys"))
978 fputs(ctl
->opt_appck_on
? "\033[?1h" : "\033[?1l", stdout
);
980 /* -default. Vc sets default rendition, otherwise clears all
982 if (ctl
->opt_default
) {
983 if (vc_only(ctl
, NULL
))
986 putp(ti_entry("sgr0"));
989 /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
990 if (ctl
->opt_foreground
)
991 printf("\033[3%c%s", '0' + ctl
->opt_fo_color
, "m");
993 /* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
994 if (ctl
->opt_background
)
995 printf("\033[4%c%s", '0' + ctl
->opt_ba_color
, "m");
997 /* -ulcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
998 if (ctl
->opt_ulcolor
&& vc_only(ctl
, "--ulcolor"))
999 printf("\033[1;%d]", ctl
->opt_ul_color
);
1001 /* -hbcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
1002 if (ctl
->opt_hbcolor
)
1003 printf("\033[2;%d]", ctl
->opt_hb_color
);
1005 /* -inversescreen [on|off]. */
1006 if (ctl
->opt_inversescreen
)
1007 fputs(ctl
->opt_invsc_on
? "\033[?5h" : "\033[?5l", stdout
);
1009 /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
1010 * all attributes. */
1011 if (ctl
->opt_bold
) {
1013 putp(ti_entry("bold"));
1015 if (vc_only(ctl
, NULL
))
1016 fputs("\033[22m", stdout
);
1018 putp(ti_entry("sgr0"));
1022 /* -half-bright [on|off]. Vc behaves as expected, otherwise off
1023 * turns off all attributes. */
1024 if (ctl
->opt_halfbright
) {
1026 putp(ti_entry("dim"));
1028 if (vc_only(ctl
, NULL
))
1029 fputs("\033[22m", stdout
);
1031 putp(ti_entry("sgr0"));
1035 /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
1036 * all attributes. */
1037 if (ctl
->opt_blink
) {
1039 putp(ti_entry("blink"));
1041 if (vc_only(ctl
, NULL
))
1042 fputs("\033[25m", stdout
);
1044 putp(ti_entry("sgr0"));
1048 /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
1049 * off all attributes. */
1050 if (ctl
->opt_reverse
) {
1052 putp(ti_entry("rev"));
1054 if (vc_only(ctl
, NULL
))
1055 fputs("\033[27m", stdout
);
1057 putp(ti_entry("sgr0"));
1061 /* -underline [on|off]. */
1062 if (ctl
->opt_underline
)
1063 putp(ti_entry(ctl
->opt_un_on
? "smul" : "rmul"));
1066 if (ctl
->opt_store
&& vc_only(ctl
, "--store"))
1067 fputs("\033[8]", stdout
);
1069 /* -clear [all|rest]. */
1071 putp(ti_entry(ctl
->opt_cl_all
? "clear" : "ed"));
1074 if (ctl
->opt_tabs
) {
1075 if (ctl
->opt_tb_array
[0] == -1)
1080 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1081 printf("\033[%dG\033H", ctl
->opt_tb_array
[i
]);
1087 if (ctl
->opt_clrtabs
&& vc_only(ctl
, "--clrtabs")) {
1090 if (ctl
->opt_tb_array
[0] == -1)
1091 fputs("\033[3g", stdout
);
1093 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1094 printf("\033[%dG\033[g", ctl
->opt_tb_array
[i
]);
1099 if (ctl
->opt_regtabs
&& vc_only(ctl
, "--regtabs")) {
1102 fputs("\033[3g\r", stdout
);
1103 for (i
= ctl
->opt_rt_len
+ 1; i
<= TABS_MAX
; i
+= ctl
->opt_rt_len
)
1104 printf("\033[%dC\033H", ctl
->opt_rt_len
);
1108 /* -blank [0-60]. */
1109 if (ctl
->opt_blank
&& vc_only(ctl
, "--blank"))
1112 /* -powersave [on|vsync|hsync|powerdown|off] (console) */
1113 if (ctl
->opt_powersave
) {
1115 ioctlarg
[0] = TIOCL_SETVESABLANK
;
1116 ioctlarg
[1] = ctl
->opt_ps_mode
;
1117 if (ioctl(STDIN_FILENO
, TIOCLINUX
, ioctlarg
))
1118 warn(_("cannot (un)set powersave mode"));
1121 /* -powerdown [0-60]. */
1122 if (ctl
->opt_powerdown
)
1123 printf("\033[14;%d]", ctl
->opt_pd_min
);
1125 /* -snap [1-NR_CONS]. */
1126 if (ctl
->opt_snap
|| ctl
->opt_append
)
1129 /* -msg [on|off]. Controls printk's to console. */
1130 if (ctl
->opt_msg
&& vc_only(ctl
, "--msg")) {
1131 if (ctl
->opt_msg_on
)
1132 result
= klogctl(SYSLOG_ACTION_CONSOLE_ON
, NULL
, 0);
1134 result
= klogctl(SYSLOG_ACTION_CONSOLE_OFF
, NULL
, 0);
1137 warn(_("klogctl error"));
1140 /* -msglevel [0-8]. Console printk message level. */
1141 if (ctl
->opt_msglevel_num
&& vc_only(ctl
, "--msglevel")) {
1143 klogctl(SYSLOG_ACTION_CONSOLE_LEVEL
, NULL
,
1144 ctl
->opt_msglevel_num
);
1146 warn(_("klogctl error"));
1149 /* -blength [0-2000] */
1150 if (ctl
->opt_blength
&& vc_only(ctl
, "--blength")) {
1151 printf("\033[11;%d]", ctl
->opt_blength_l
);
1154 /* -bfreq freqnumber */
1155 if (ctl
->opt_bfreq
&& vc_only(ctl
, "--bfreq")) {
1156 printf("\033[10;%d]", ctl
->opt_bfreq_f
);
1160 static void init_terminal(struct setterm_control
*ctl
)
1164 if (!ctl
->opt_te_terminal_name
) {
1165 ctl
->opt_te_terminal_name
= getenv("TERM");
1166 if (ctl
->opt_te_terminal_name
== NULL
)
1167 errx(EXIT_FAILURE
, _("$TERM is not defined."));
1170 /* Find terminfo entry. */
1171 if (setupterm(ctl
->opt_te_terminal_name
, STDOUT_FILENO
, &term_errno
))
1172 switch (term_errno
) {
1174 errx(EXIT_FAILURE
, _("terminfo database cannot be found"));
1176 errx(EXIT_FAILURE
, _("%s: unknown terminal type"), ctl
->opt_te_terminal_name
);
1178 errx(EXIT_FAILURE
, _("terminal is hardcopy"));
1181 /* See if the terminal is a virtual console terminal. */
1182 ctl
->vcterm
= (!strncmp(ctl
->opt_te_terminal_name
, "con", 3) ||
1183 !strncmp(ctl
->opt_te_terminal_name
, "linux", 5));
1187 int main(int argc
, char **argv
)
1189 struct setterm_control ctl
= { NULL
};
1191 setlocale(LC_ALL
, "");
1192 bindtextdomain(PACKAGE
, LOCALEDIR
);
1193 textdomain(PACKAGE
);
1194 close_stdout_atexit();
1197 warnx(_("bad usage"));
1198 errtryhelp(EXIT_FAILURE
);
1200 parse_option(&ctl
, argc
, argv
);
1201 init_terminal(&ctl
);
1202 perform_sequence(&ctl
);
1204 return EXIT_SUCCESS
;