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 else 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
);
280 static int parse_powersave(const char *arg
)
282 if (strcmp(arg
, "on") == 0)
283 return VESA_BLANK_MODE_SUSPENDV
;
284 else if (strcmp(arg
, "vsync") == 0)
285 return VESA_BLANK_MODE_SUSPENDV
;
286 else if (strcmp(arg
, "hsync") == 0)
287 return VESA_BLANK_MODE_SUSPENDH
;
288 else if (strcmp(arg
, "powerdown") == 0)
289 return VESA_BLANK_MODE_POWERDOWN
;
290 else if (strcmp(arg
, "off") == 0)
291 return VESA_BLANK_MODE_OFF
;
292 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
295 static int parse_msglevel(const char *arg
)
299 ret
= strtos32_or_err(arg
, _("argument error"));
300 if (ret
< CONSOLE_LEVEL_MIN
|| CONSOLE_LEVEL_MAX
< ret
)
301 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
305 static int parse_snap(char **av
, char *oa
, int *oi
)
310 arg
= find_optional_arg(av
, oa
, oi
);
313 ret
= strtos32_or_err(arg
, _("argument error"));
315 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
319 static void parse_tabs(char **av
, char *oa
, int *oi
, int *tab_array
)
324 tab_array
[i
] = strtos32_or_err(oa
, _("argument error"));
329 errx(EXIT_FAILURE
, _("too many tabs"));
330 if (av
[*oi
][0] == '-')
332 tab_array
[i
] = strtos32_or_err(av
[*oi
], _("argument error"));
339 static int parse_regtabs(char **av
, char *oa
, int *oi
)
344 arg
= find_optional_arg(av
, oa
, oi
);
346 return DEFAULT_TAB_LEN
;
347 ret
= strtos32_or_err(arg
, _("argument error"));
348 if (ret
< 1 || TABS_MAX
< ret
)
349 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
353 static int parse_blength(char **av
, char *oa
, int *oi
)
358 arg
= find_optional_arg(av
, oa
, oi
);
361 ret
= strtos32_or_err(arg
, _("argument error"));
362 if (ret
< 0 || BLENGTH_MAX
< ret
)
363 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
367 static int parse_bfreq(char **av
, char *oa
, int *oi
)
371 arg
= find_optional_arg(av
, oa
, oi
);
374 return strtos32_or_err(arg
, _("argument error"));
377 static void __attribute__((__noreturn__
)) usage(void)
380 fputs(USAGE_HEADER
, out
);
382 _(" %s [options]\n"), program_invocation_short_name
);
384 fputs(USAGE_SEPARATOR
, out
);
385 fputs(_("Set the attributes of a terminal.\n"), out
);
387 fputs(USAGE_OPTIONS
, out
);
388 fputs(_(" --term <terminal_name> override TERM environment variable\n"), out
);
389 fputs(_(" --reset reset terminal to power-on state\n"), out
);
390 fputs(_(" --resize reset terminal rows and columns\n"), out
);
391 fputs(_(" --initialize display init string, and use default settings\n"), out
);
392 fputs(_(" --default use default terminal settings\n"), out
);
393 fputs(_(" --store save current terminal settings as default\n"), out
);
394 fputs(USAGE_SEPARATOR
, out
);
396 fputs(_(" --cursor on|off display cursor\n"), out
);
397 fputs(_(" --repeat on|off keyboard repeat\n"), out
);
398 fputs(_(" --appcursorkeys on|off cursor key application mode\n"), out
);
399 fputs(_(" --linewrap on|off continue on a new line when a line is full\n"), out
);
400 fputs(_(" --inversescreen on|off swap colors for the whole screen\n"), out
);
401 fputs(USAGE_SEPARATOR
, out
);
403 fputs(_(" --msg on|off send kernel messages to console\n"), out
);
404 fputs(_(" --msglevel <0-8> kernel console log level\n"), out
);
405 fputs(USAGE_SEPARATOR
, out
);
407 fputs(_(" --foreground default|<color> set foreground color\n"), out
);
408 fputs(_(" --background default|<color> set background color\n"), out
);
409 fputs(_(" --ulcolor [bright] <color> set underlined text color\n"), out
);
410 fputs(_(" --hbcolor [bright] <color> set half-bright text color\n"), out
);
411 fputs(_(" <color>: black blue cyan green grey magenta red white yellow\n"), out
);
412 fputs(USAGE_SEPARATOR
, out
);
414 fputs(_(" --bold on|off bold\n"), out
);
415 fputs(_(" --half-bright on|off dim\n"), out
);
416 fputs(_(" --blink on|off blink\n"), out
);
417 fputs(_(" --underline on|off underline\n"), out
);
418 fputs(_(" --reverse on|off swap foreground and background colors\n"), out
);
419 fputs(USAGE_SEPARATOR
, out
);
421 fputs(_(" --clear[=<all|rest>] clear screen and set cursor position\n"), out
);
422 fputs(_(" --tabs[=<number>...] set these tab stop positions, or show them\n"), out
);
423 fputs(_(" --clrtabs[=<number>...] clear these tab stop positions, or all\n"), out
);
424 fputs(_(" --regtabs[=1-160] set a regular tab stop interval\n"), out
);
425 fputs(_(" --blank[=0-60|force|poke] set time of inactivity before screen blanks\n"), out
);
426 fputs(USAGE_SEPARATOR
, out
);
428 fputs(_(" --dump[=<number>] write vcsa<number> console dump to file\n"), out
);
429 fputs(_(" --append <number> append vcsa<number> console dump to file\n"), out
);
430 fputs(_(" --file <filename> name of the dump file\n"), out
);
431 fputs(USAGE_SEPARATOR
, out
);
433 fputs(_(" --powersave on|vsync|hsync|powerdown|off\n"), out
);
434 fputs(_(" set vesa powersaving features\n"), out
);
435 fputs(_(" --powerdown[=<0-60>] set vesa powerdown interval in minutes\n"), out
);
436 fputs(USAGE_SEPARATOR
, out
);
438 fputs(_(" --blength[=<0-2000>] duration of the bell in milliseconds\n"), out
);
439 fputs(_(" --bfreq[=<number>] bell frequency in Hertz\n"), out
);
441 fputs(USAGE_SEPARATOR
, out
);
442 printf( " --help %s\n", USAGE_OPTSTR_HELP
);
443 printf( " --version %s\n", USAGE_OPTSTR_VERSION
);
445 printf(USAGE_MAN_TAIL("setterm(1)"));
449 static int __attribute__((__pure__
)) set_opt_flag(int opt
)
452 errx(EXIT_FAILURE
, _("duplicate use of an option"));
456 static void parse_option(struct setterm_control
*ctl
, int ac
, char **av
)
460 OPT_TERM
= CHAR_MAX
+ 1,
497 static const struct option longopts
[] = {
498 {"term", required_argument
, NULL
, OPT_TERM
},
499 {"reset", no_argument
, NULL
, OPT_RESET
},
500 {"resize", no_argument
, NULL
, OPT_RESIZE
},
501 {"initialize", no_argument
, NULL
, OPT_INITIALIZE
},
502 {"cursor", required_argument
, NULL
, OPT_CURSOR
},
503 {"repeat", required_argument
, NULL
, OPT_REPEAT
},
504 {"appcursorkeys", required_argument
, NULL
, OPT_APPCURSORKEYS
},
505 {"linewrap", required_argument
, NULL
, OPT_LINEWRAP
},
506 {"default", no_argument
, NULL
, OPT_DEFAULT
},
507 {"foreground", required_argument
, NULL
, OPT_FOREGROUND
},
508 {"background", required_argument
, NULL
, OPT_BACKGROUND
},
509 {"ulcolor", required_argument
, NULL
, OPT_ULCOLOR
},
510 {"hbcolor", required_argument
, NULL
, OPT_HBCOLOR
},
511 {"inversescreen", required_argument
, NULL
, OPT_INVERSESCREEN
},
512 {"bold", required_argument
, NULL
, OPT_BOLD
},
513 {"half-bright", required_argument
, NULL
, OPT_HALF_BRIGHT
},
514 {"blink", required_argument
, NULL
, OPT_BLINK
},
515 {"reverse", required_argument
, NULL
, OPT_REVERSE
},
516 {"underline", required_argument
, NULL
, OPT_UNDERLINE
},
517 {"store", no_argument
, NULL
, OPT_STORE
},
518 {"clear", optional_argument
, NULL
, OPT_CLEAR
},
519 {"tabs", optional_argument
, NULL
, OPT_TABS
},
520 {"clrtabs", optional_argument
, NULL
, OPT_CLRTABS
},
521 {"regtabs", optional_argument
, NULL
, OPT_REGTABS
},
522 {"blank", optional_argument
, NULL
, OPT_BLANK
},
523 {"dump", optional_argument
, NULL
, OPT_DUMP
},
524 {"append", required_argument
, NULL
, OPT_APPEND
},
525 {"file", required_argument
, NULL
, OPT_FILE
},
526 {"msg", required_argument
, NULL
, OPT_MSG
},
527 {"msglevel", required_argument
, NULL
, OPT_MSGLEVEL
},
528 {"powersave", required_argument
, NULL
, OPT_POWERSAVE
},
529 {"powerdown", optional_argument
, NULL
, OPT_POWERDOWN
},
530 {"blength", optional_argument
, NULL
, OPT_BLENGTH
},
531 {"bfreq", optional_argument
, NULL
, OPT_BFREQ
},
532 {"version", no_argument
, NULL
, OPT_VERSION
},
533 {"help", no_argument
, NULL
, OPT_HELP
},
536 static const ul_excl_t excl
[] = {
537 { OPT_DEFAULT
, OPT_STORE
},
538 { OPT_TABS
, OPT_CLRTABS
, OPT_REGTABS
},
539 { OPT_MSG
, OPT_MSGLEVEL
},
542 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
544 while ((c
= getopt_long_only(ac
, av
, "", longopts
, NULL
)) != -1) {
545 err_exclusive_options(c
, longopts
, excl
, excl_st
);
548 ctl
->opt_term
= set_opt_flag(ctl
->opt_term
);
549 ctl
->opt_te_terminal_name
= optarg
;
552 ctl
->opt_reset
= set_opt_flag(ctl
->opt_reset
);
555 ctl
->opt_resize
= set_opt_flag(ctl
->opt_resize
);
558 ctl
->opt_initialize
= set_opt_flag(ctl
->opt_initialize
);
561 ctl
->opt_cursor
= set_opt_flag(ctl
->opt_cursor
);
562 ctl
->opt_cu_on
= parse_switch(optarg
, _("argument error"),
566 ctl
->opt_repeat
= set_opt_flag(ctl
->opt_repeat
);
567 ctl
->opt_rep_on
= parse_switch(optarg
, _("argument error"),
570 case OPT_APPCURSORKEYS
:
571 ctl
->opt_appcursorkeys
= set_opt_flag(ctl
->opt_appcursorkeys
);
572 ctl
->opt_appck_on
= parse_switch(optarg
, _("argument error"),
576 ctl
->opt_linewrap
= set_opt_flag(ctl
->opt_linewrap
);
577 ctl
->opt_li_on
= parse_switch(optarg
, _("argument error"),
581 ctl
->opt_default
= set_opt_flag(ctl
->opt_default
);
584 ctl
->opt_foreground
= set_opt_flag(ctl
->opt_foreground
);
585 ctl
->opt_fo_color
= parse_febg_color(optarg
);
588 ctl
->opt_background
= set_opt_flag(ctl
->opt_background
);
589 ctl
->opt_ba_color
= parse_febg_color(optarg
);
592 ctl
->opt_ulcolor
= set_opt_flag(ctl
->opt_ulcolor
);
593 ctl
->opt_ul_color
= parse_ulhb_color(av
, &optind
);
596 ctl
->opt_hbcolor
= set_opt_flag(ctl
->opt_hbcolor
);
597 ctl
->opt_hb_color
= parse_ulhb_color(av
, &optind
);
599 case OPT_INVERSESCREEN
:
600 ctl
->opt_inversescreen
= set_opt_flag(ctl
->opt_inversescreen
);
601 ctl
->opt_invsc_on
= parse_switch(optarg
, _("argument error"),
605 ctl
->opt_bold
= set_opt_flag(ctl
->opt_bold
);
606 ctl
->opt_bo_on
= parse_switch(optarg
, _("argument error"),
609 case OPT_HALF_BRIGHT
:
610 ctl
->opt_halfbright
= set_opt_flag(ctl
->opt_halfbright
);
611 ctl
->opt_hb_on
= parse_switch(optarg
, _("argument error"),
615 ctl
->opt_blink
= set_opt_flag(ctl
->opt_blink
);
616 ctl
->opt_bl_on
= parse_switch(optarg
, _("argument error"),
620 ctl
->opt_reverse
= set_opt_flag(ctl
->opt_reverse
);
621 ctl
->opt_re_on
= parse_switch(optarg
, _("argument error"),
625 ctl
->opt_underline
= set_opt_flag(ctl
->opt_underline
);
626 ctl
->opt_un_on
= parse_switch(optarg
, _("argument error"),
630 ctl
->opt_store
= set_opt_flag(ctl
->opt_store
);
633 ctl
->opt_clear
= set_opt_flag(ctl
->opt_clear
);
635 ctl
->opt_cl_all
= parse_switch(optarg
, _("argument error"),
636 "all", "rest", NULL
);
641 ctl
->opt_tabs
= set_opt_flag(ctl
->opt_tabs
);
642 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
645 ctl
->opt_clrtabs
= set_opt_flag(ctl
->opt_clrtabs
);
646 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
649 ctl
->opt_regtabs
= set_opt_flag(ctl
->opt_regtabs
);
650 ctl
->opt_rt_len
= parse_regtabs(av
, optarg
, &optind
);
653 ctl
->opt_blank
= set_opt_flag(ctl
->opt_blank
);
654 ctl
->opt_bl_min
= parse_blank(av
, optarg
, &optind
);
657 ctl
->opt_snap
= set_opt_flag(ctl
->opt_snap
);
658 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
661 ctl
->opt_append
= set_opt_flag(ctl
->opt_append
);
662 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
665 ctl
->opt_snapfile
= set_opt_flag(ctl
->opt_snapfile
);
666 ctl
->opt_sn_name
= optarg
;
669 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
670 ctl
->opt_msg_on
= parse_switch(optarg
, _("argument error"),
674 ctl
->opt_msglevel
= set_opt_flag(ctl
->opt_msglevel
);
675 ctl
->opt_msglevel_num
= parse_msglevel(optarg
);
676 if (ctl
->opt_msglevel_num
== 0) {
677 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
678 ctl
->opt_msg_on
|= 1;
682 ctl
->opt_powersave
= set_opt_flag(ctl
->opt_powersave
);
683 ctl
->opt_ps_mode
= parse_powersave(optarg
);
686 ctl
->opt_powerdown
= set_opt_flag(ctl
->opt_powerdown
);
687 ctl
->opt_pd_min
= parse_blank(av
, optarg
, &optind
);
690 ctl
->opt_blength
= set_opt_flag(ctl
->opt_blength
);
691 ctl
->opt_blength_l
= parse_blength(av
, optarg
, &optind
);
694 ctl
->opt_bfreq
= set_opt_flag(ctl
->opt_bfreq
);
695 ctl
->opt_bfreq_f
= parse_bfreq(av
, optarg
, &optind
);
699 print_version(EXIT_SUCCESS
);
703 errtryhelp(EXIT_FAILURE
);
708 /* Return the specified terminfo string, or an empty string if no such
709 * terminfo capability exists. */
710 static char *ti_entry(const char *name
)
714 if ((buf_ptr
= tigetstr(name
)) == (char *)-1)
719 static void show_tabs(void)
721 int i
, co
= tigetnum("cols");
725 for (i
= 10; i
< co
- 2; i
+= 10)
728 for (i
= 1; i
<= co
; i
++)
729 putchar(i
% 10 + '0');
731 for (i
= 1; i
< co
; i
++)
737 static int open_snapshot_device(struct setterm_control
*ctl
)
742 xasprintf(&ctl
->in_device
, "/dev/vcsa%d", ctl
->opt_sn_num
);
744 xasprintf(&ctl
->in_device
, "/dev/vcsa");
745 fd
= open(ctl
->in_device
, O_RDONLY
);
747 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
751 static void set_blanking(struct setterm_control
*ctl
)
756 if (0 <= ctl
->opt_bl_min
) {
757 printf("\033[9;%d]", ctl
->opt_bl_min
);
760 switch (ctl
->opt_bl_min
) {
762 ioctlarg
= TIOCL_BLANKSCREEN
;
763 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
764 warn(_("cannot force blank"));
767 ioctlarg
= TIOCL_UNBLANKSCREEN
;
768 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
769 warn(_("cannot force unblank"));
772 ioctlarg
= TIOCL_BLANKEDSCREEN
;
773 ret
= ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
);
775 warn(_("cannot get blank status"));
779 default: /* should be impossible to reach */
785 static void screendump(struct setterm_control
*ctl
)
787 unsigned char header
[4];
788 unsigned int rows
, cols
;
793 char *inbuf
, *outbuf
, *p
, *q
;
795 /* open source and destination files */
796 fd
= open_snapshot_device(ctl
);
797 if (!ctl
->opt_sn_name
)
798 ctl
->opt_sn_name
= "screen.dump";
799 out
= fopen(ctl
->opt_sn_name
, ctl
->opt_snap
? "w" : "a");
801 err(EXIT_DUMPFILE
, _("cannot open dump file %s for output"), ctl
->opt_sn_name
);
802 /* determine snapshot size */
803 if (read(fd
, header
, 4) != 4)
804 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
807 if (rows
* cols
== 0)
808 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
809 /* allocate buffers */
810 inbuf
= xmalloc(rows
* cols
* 2);
811 outbuf
= xmalloc(rows
* (cols
+ 1));
813 rc
= read(fd
, inbuf
, rows
* cols
* 2);
814 if (rc
< 0 || (size_t)rc
!= rows
* cols
* 2)
815 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
818 /* copy inbuf to outbuf */
819 for (i
= 0; i
< rows
; i
++) {
820 for (j
= 0; j
< cols
; j
++) {
824 while (j
-- > 0 && q
[-1] == ' ')
828 fwrite(outbuf
, 1, q
- outbuf
, out
);
829 /* clean up allocations */
833 free(ctl
->in_device
);
834 if (close_stream(out
) != 0)
835 errx(EXIT_FAILURE
, _("write error"));
839 /* Some options are applicable when terminal is virtual console. */
840 static int vc_only(struct setterm_control
*ctl
, const char *err
)
842 if (!ctl
->vcterm
&& err
)
843 warnx(_("terminal %s does not support %s"),
844 ctl
->opt_te_terminal_name
, err
);
848 static void tty_raw(struct termios
*saved_attributes
, int *saved_fl
)
850 struct termios tattr
;
852 fcntl(STDIN_FILENO
, F_GETFL
, saved_fl
);
853 tcgetattr(STDIN_FILENO
, saved_attributes
);
854 fcntl(STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
855 memcpy(&tattr
, saved_attributes
, sizeof(struct termios
));
856 tattr
.c_lflag
&= ~(ICANON
| ECHO
);
857 tattr
.c_cc
[VMIN
] = 1;
858 tattr
.c_cc
[VTIME
] = 0;
859 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tattr
);
862 static void tty_restore(struct termios
*saved_attributes
, int *saved_fl
)
864 fcntl(STDIN_FILENO
, F_SETFL
, *saved_fl
);
865 tcsetattr(STDIN_FILENO
, TCSANOW
, saved_attributes
);
868 static int select_wait(void)
875 FD_SET(STDIN_FILENO
, &set
);
878 while ((ret
= select(1, &set
, NULL
, NULL
, &tv
)) < 0) {
881 err(EXIT_FAILURE
, _("select failed"));
886 static int resizetty(void)
889 * \e7 Save current state (cursor coordinates, attributes,
890 * character sets pointed at by G0, G1).
891 * \e[r Set scrolling region; parameters are top and bottom row.
892 * \e[32766E Move cursor down 32766 (INT16_MAX - 1) rows.
893 * \e[32766C Move cursor right 32766 columns.
894 * \e[6n Report cursor position.
895 * \e8 Restore state most recently saved by \e7.
897 static const char *getpos
= "\e7\e[r\e[32766E\e[32766C\e[6n\e8";
903 struct termios saved_attributes
;
906 if (!isatty(STDIN_FILENO
))
907 errx(EXIT_FAILURE
, _("stdin does not refer to a terminal"));
909 tty_raw(&saved_attributes
, &saved_fl
);
910 if (write_all(STDIN_FILENO
, getpos
, strlen(getpos
)) < 0) {
911 warn(_("write failed"));
912 tty_restore(&saved_attributes
, &saved_fl
);
915 for (pos
= 0; pos
< sizeof(retstr
) - 1;) {
916 if (0 == select_wait())
919 read(STDIN_FILENO
, retstr
+ pos
,
920 sizeof(retstr
) - 1 - pos
)) < 0) {
923 warn(_("read failed"));
924 tty_restore(&saved_attributes
, &saved_fl
);
928 if (retstr
[pos
- 1] == 'R')
932 tty_restore(&saved_attributes
, &saved_fl
);
933 rc
= sscanf(retstr
, "\033[%d;%dR", &row
, &col
);
935 warnx(_("invalid cursor position: %s"), retstr
);
938 memset(&ws
, 0, sizeof(struct winsize
));
939 ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
);
942 ioctl(STDIN_FILENO
, TIOCSWINSZ
, &ws
);
946 static void perform_sequence(struct setterm_control
*ctl
)
952 putp(ti_entry("rs1"));
957 warnx(_("reset failed"));
960 if (ctl
->opt_initialize
)
961 putp(ti_entry("is2"));
963 /* -cursor [on|off]. */
964 if (ctl
->opt_cursor
) {
966 putp(ti_entry("cnorm"));
968 putp(ti_entry("civis"));
971 /* -linewrap [on|off]. */
972 if (ctl
->opt_linewrap
)
973 fputs(ctl
->opt_li_on
? "\033[?7h" : "\033[?7l", stdout
);
975 /* -repeat [on|off]. */
976 if (ctl
->opt_repeat
&& vc_only(ctl
, "--repeat"))
977 fputs(ctl
->opt_rep_on
? "\033[?8h" : "\033[?8l", stdout
);
979 /* -appcursorkeys [on|off]. */
980 if (ctl
->opt_appcursorkeys
&& vc_only(ctl
, "--appcursorkeys"))
981 fputs(ctl
->opt_appck_on
? "\033[?1h" : "\033[?1l", stdout
);
983 /* -default. Vc sets default rendition, otherwise clears all
985 if (ctl
->opt_default
) {
986 if (vc_only(ctl
, NULL
))
989 putp(ti_entry("sgr0"));
992 /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
993 if (ctl
->opt_foreground
)
994 printf("\033[3%c%s", '0' + ctl
->opt_fo_color
, "m");
996 /* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
997 if (ctl
->opt_background
)
998 printf("\033[4%c%s", '0' + ctl
->opt_ba_color
, "m");
1000 /* -ulcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
1001 if (ctl
->opt_ulcolor
&& vc_only(ctl
, "--ulcolor"))
1002 printf("\033[1;%d]", ctl
->opt_ul_color
);
1004 /* -hbcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
1005 if (ctl
->opt_hbcolor
)
1006 printf("\033[2;%d]", ctl
->opt_hb_color
);
1008 /* -inversescreen [on|off]. */
1009 if (ctl
->opt_inversescreen
)
1010 fputs(ctl
->opt_invsc_on
? "\033[?5h" : "\033[?5l", stdout
);
1012 /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
1013 * all attributes. */
1014 if (ctl
->opt_bold
) {
1016 putp(ti_entry("bold"));
1018 if (vc_only(ctl
, NULL
))
1019 fputs("\033[22m", stdout
);
1021 putp(ti_entry("sgr0"));
1025 /* -half-bright [on|off]. Vc behaves as expected, otherwise off
1026 * turns off all attributes. */
1027 if (ctl
->opt_halfbright
) {
1029 putp(ti_entry("dim"));
1031 if (vc_only(ctl
, NULL
))
1032 fputs("\033[22m", stdout
);
1034 putp(ti_entry("sgr0"));
1038 /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
1039 * all attributes. */
1040 if (ctl
->opt_blink
) {
1042 putp(ti_entry("blink"));
1044 if (vc_only(ctl
, NULL
))
1045 fputs("\033[25m", stdout
);
1047 putp(ti_entry("sgr0"));
1051 /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
1052 * off all attributes. */
1053 if (ctl
->opt_reverse
) {
1055 putp(ti_entry("rev"));
1057 if (vc_only(ctl
, NULL
))
1058 fputs("\033[27m", stdout
);
1060 putp(ti_entry("sgr0"));
1064 /* -underline [on|off]. */
1065 if (ctl
->opt_underline
)
1066 putp(ti_entry(ctl
->opt_un_on
? "smul" : "rmul"));
1069 if (ctl
->opt_store
&& vc_only(ctl
, "--store"))
1070 fputs("\033[8]", stdout
);
1072 /* -clear [all|rest]. */
1074 putp(ti_entry(ctl
->opt_cl_all
? "clear" : "ed"));
1077 if (ctl
->opt_tabs
) {
1078 if (ctl
->opt_tb_array
[0] == -1)
1083 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1084 printf("\033[%dG\033H", ctl
->opt_tb_array
[i
]);
1090 if (ctl
->opt_clrtabs
&& vc_only(ctl
, "--clrtabs")) {
1093 if (ctl
->opt_tb_array
[0] == -1)
1094 fputs("\033[3g", stdout
);
1096 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1097 printf("\033[%dG\033[g", ctl
->opt_tb_array
[i
]);
1102 if (ctl
->opt_regtabs
&& vc_only(ctl
, "--regtabs")) {
1105 fputs("\033[3g\r", stdout
);
1106 for (i
= ctl
->opt_rt_len
+ 1; i
<= TABS_MAX
; i
+= ctl
->opt_rt_len
)
1107 printf("\033[%dC\033H", ctl
->opt_rt_len
);
1111 /* -blank [0-60]. */
1112 if (ctl
->opt_blank
&& vc_only(ctl
, "--blank"))
1115 /* -powersave [on|vsync|hsync|powerdown|off] (console) */
1116 if (ctl
->opt_powersave
) {
1118 ioctlarg
[0] = TIOCL_SETVESABLANK
;
1119 ioctlarg
[1] = ctl
->opt_ps_mode
;
1120 if (ioctl(STDIN_FILENO
, TIOCLINUX
, ioctlarg
))
1121 warn(_("cannot (un)set powersave mode"));
1124 /* -powerdown [0-60]. */
1125 if (ctl
->opt_powerdown
)
1126 printf("\033[14;%d]", ctl
->opt_pd_min
);
1128 /* -snap [1-NR_CONS]. */
1129 if (ctl
->opt_snap
|| ctl
->opt_append
)
1132 /* -msg [on|off]. Controls printk's to console. */
1133 if (ctl
->opt_msg
&& vc_only(ctl
, "--msg")) {
1134 if (ctl
->opt_msg_on
)
1135 result
= klogctl(SYSLOG_ACTION_CONSOLE_ON
, NULL
, 0);
1137 result
= klogctl(SYSLOG_ACTION_CONSOLE_OFF
, NULL
, 0);
1140 warn(_("klogctl error"));
1143 /* -msglevel [0-8]. Console printk message level. */
1144 if (ctl
->opt_msglevel_num
&& vc_only(ctl
, "--msglevel")) {
1146 klogctl(SYSLOG_ACTION_CONSOLE_LEVEL
, NULL
,
1147 ctl
->opt_msglevel_num
);
1149 warn(_("klogctl error"));
1152 /* -blength [0-2000] */
1153 if (ctl
->opt_blength
&& vc_only(ctl
, "--blength")) {
1154 printf("\033[11;%d]", ctl
->opt_blength_l
);
1157 /* -bfreq freqnumber */
1158 if (ctl
->opt_bfreq
&& vc_only(ctl
, "--bfreq")) {
1159 printf("\033[10;%d]", ctl
->opt_bfreq_f
);
1163 static void init_terminal(struct setterm_control
*ctl
)
1167 if (!ctl
->opt_te_terminal_name
) {
1168 ctl
->opt_te_terminal_name
= getenv("TERM");
1169 if (ctl
->opt_te_terminal_name
== NULL
)
1170 errx(EXIT_FAILURE
, _("$TERM is not defined."));
1173 /* Find terminfo entry. */
1174 if (setupterm(ctl
->opt_te_terminal_name
, STDOUT_FILENO
, &term_errno
))
1175 switch (term_errno
) {
1177 errx(EXIT_FAILURE
, _("terminfo database cannot be found"));
1179 errx(EXIT_FAILURE
, _("%s: unknown terminal type"), ctl
->opt_te_terminal_name
);
1181 errx(EXIT_FAILURE
, _("terminal is hardcopy"));
1184 /* See if the terminal is a virtual console terminal. */
1185 ctl
->vcterm
= (!strncmp(ctl
->opt_te_terminal_name
, "con", 3) ||
1186 !strncmp(ctl
->opt_te_terminal_name
, "linux", 5));
1190 int main(int argc
, char **argv
)
1192 struct setterm_control ctl
= { NULL
};
1194 setlocale(LC_ALL
, "");
1195 bindtextdomain(PACKAGE
, LOCALEDIR
);
1196 textdomain(PACKAGE
);
1197 close_stdout_atexit();
1200 warnx(_("bad usage"));
1201 errtryhelp(EXIT_FAILURE
);
1203 parse_option(&ctl
, argc
, argv
);
1204 init_terminal(&ctl
);
1205 perform_sequence(&ctl
);
1207 return EXIT_SUCCESS
;