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
))
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
);
242 static char *find_optional_arg(char **av
, char *oa
, int *oi
)
249 if (!arg
|| arg
[0] == '-')
256 static int parse_blank(char **av
, char *oa
, int *oi
)
260 arg
= find_optional_arg(av
, oa
, oi
);
262 return BLANKEDSCREEN
;
263 if (!strcmp(arg
, "force"))
265 else if (!strcmp(arg
, "poke"))
266 return UNBLANKSCREEN
;
270 ret
= strtos32_or_err(arg
, _("argument error"));
271 if (ret
< 0 || BLANK_MAX
< ret
)
272 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
277 static int parse_powersave(const char *arg
)
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
;
289 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
292 static int parse_msglevel(const char *arg
)
296 ret
= strtos32_or_err(arg
, _("argument error"));
297 if (ret
< CONSOLE_LEVEL_MIN
|| CONSOLE_LEVEL_MAX
< ret
)
298 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
302 static int parse_snap(char **av
, char *oa
, int *oi
)
307 arg
= find_optional_arg(av
, oa
, oi
);
310 ret
= strtos32_or_err(arg
, _("argument error"));
312 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
316 static void parse_tabs(char **av
, char *oa
, int *oi
, int *tab_array
)
321 tab_array
[i
] = strtos32_or_err(oa
, _("argument error"));
326 errx(EXIT_FAILURE
, _("too many tabs"));
327 if (av
[*oi
][0] == '-')
329 tab_array
[i
] = strtos32_or_err(av
[*oi
], _("argument error"));
336 static int parse_regtabs(char **av
, char *oa
, int *oi
)
341 arg
= find_optional_arg(av
, oa
, oi
);
343 return DEFAULT_TAB_LEN
;
344 ret
= strtos32_or_err(arg
, _("argument error"));
345 if (ret
< 1 || TABS_MAX
< ret
)
346 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
350 static int parse_blength(char **av
, char *oa
, int *oi
)
355 arg
= find_optional_arg(av
, oa
, oi
);
358 ret
= strtos32_or_err(arg
, _("argument error"));
359 if (ret
< 0 || BLENGTH_MAX
< ret
)
360 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
364 static int parse_bfreq(char **av
, char *oa
, int *oi
)
368 arg
= find_optional_arg(av
, oa
, oi
);
371 return strtos32_or_err(arg
, _("argument error"));
374 static void __attribute__((__noreturn__
)) usage(void)
377 fputs(USAGE_HEADER
, out
);
379 _(" %s [options]\n"), program_invocation_short_name
);
381 fputs(USAGE_SEPARATOR
, out
);
382 fputs(_("Set the attributes of a terminal.\n"), out
);
384 fputs(USAGE_OPTIONS
, out
);
385 fputs(_(" --term <terminal_name> override TERM environment variable\n"), out
);
386 fputs(_(" --reset reset terminal to power-on state\n"), out
);
387 fputs(_(" --resize reset terminal rows and columns\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 printf( " --help %s\n", USAGE_OPTSTR_HELP
);
422 printf( " --version %s\n", USAGE_OPTSTR_VERSION
);
424 printf(USAGE_MAN_TAIL("setterm(1)"));
428 static int __attribute__((__pure__
)) set_opt_flag(int opt
)
431 errx(EXIT_FAILURE
, _("duplicate use of an option"));
435 static void parse_option(struct setterm_control
*ctl
, int ac
, char **av
)
439 OPT_TERM
= CHAR_MAX
+ 1,
476 static const struct option longopts
[] = {
477 {"term", required_argument
, NULL
, OPT_TERM
},
478 {"reset", no_argument
, NULL
, OPT_RESET
},
479 {"resize", no_argument
, NULL
, OPT_RESIZE
},
480 {"initialize", no_argument
, NULL
, OPT_INITIALIZE
},
481 {"cursor", required_argument
, NULL
, OPT_CURSOR
},
482 {"repeat", required_argument
, NULL
, OPT_REPEAT
},
483 {"appcursorkeys", required_argument
, NULL
, OPT_APPCURSORKEYS
},
484 {"linewrap", required_argument
, NULL
, OPT_LINEWRAP
},
485 {"default", no_argument
, NULL
, OPT_DEFAULT
},
486 {"foreground", required_argument
, NULL
, OPT_FOREGROUND
},
487 {"background", required_argument
, NULL
, OPT_BACKGROUND
},
488 {"ulcolor", required_argument
, NULL
, OPT_ULCOLOR
},
489 {"hbcolor", required_argument
, NULL
, OPT_HBCOLOR
},
490 {"inversescreen", required_argument
, NULL
, OPT_INVERSESCREEN
},
491 {"bold", required_argument
, NULL
, OPT_BOLD
},
492 {"half-bright", required_argument
, NULL
, OPT_HALF_BRIGHT
},
493 {"blink", required_argument
, NULL
, OPT_BLINK
},
494 {"reverse", required_argument
, NULL
, OPT_REVERSE
},
495 {"underline", required_argument
, NULL
, OPT_UNDERLINE
},
496 {"store", no_argument
, NULL
, OPT_STORE
},
497 {"clear", required_argument
, NULL
, OPT_CLEAR
},
498 {"tabs", optional_argument
, NULL
, OPT_TABS
},
499 {"clrtabs", optional_argument
, NULL
, OPT_CLRTABS
},
500 {"regtabs", optional_argument
, NULL
, OPT_REGTABS
},
501 {"blank", optional_argument
, NULL
, OPT_BLANK
},
502 {"dump", optional_argument
, NULL
, OPT_DUMP
},
503 {"append", required_argument
, NULL
, OPT_APPEND
},
504 {"file", required_argument
, NULL
, OPT_FILE
},
505 {"msg", required_argument
, NULL
, OPT_MSG
},
506 {"msglevel", required_argument
, NULL
, OPT_MSGLEVEL
},
507 {"powersave", required_argument
, NULL
, OPT_POWERSAVE
},
508 {"powerdown", optional_argument
, NULL
, OPT_POWERDOWN
},
509 {"blength", optional_argument
, NULL
, OPT_BLENGTH
},
510 {"bfreq", optional_argument
, NULL
, OPT_BFREQ
},
511 {"version", no_argument
, NULL
, OPT_VERSION
},
512 {"help", no_argument
, NULL
, OPT_HELP
},
515 static const ul_excl_t excl
[] = {
516 { OPT_DEFAULT
, OPT_STORE
},
517 { OPT_TABS
, OPT_CLRTABS
, OPT_REGTABS
},
518 { OPT_MSG
, OPT_MSGLEVEL
},
521 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
523 while ((c
= getopt_long_only(ac
, av
, "", longopts
, NULL
)) != -1) {
524 err_exclusive_options(c
, longopts
, excl
, excl_st
);
527 ctl
->opt_term
= set_opt_flag(ctl
->opt_term
);
528 ctl
->opt_te_terminal_name
= optarg
;
531 ctl
->opt_reset
= set_opt_flag(ctl
->opt_reset
);
534 ctl
->opt_resize
= set_opt_flag(ctl
->opt_resize
);
537 ctl
->opt_initialize
= set_opt_flag(ctl
->opt_initialize
);
540 ctl
->opt_cursor
= set_opt_flag(ctl
->opt_cursor
);
541 ctl
->opt_cu_on
= parse_switch(optarg
, _("argument error"),
545 ctl
->opt_repeat
= set_opt_flag(ctl
->opt_repeat
);
546 ctl
->opt_rep_on
= parse_switch(optarg
, _("argument error"),
549 case OPT_APPCURSORKEYS
:
550 ctl
->opt_appcursorkeys
= set_opt_flag(ctl
->opt_appcursorkeys
);
551 ctl
->opt_appck_on
= parse_switch(optarg
, _("argument error"),
555 ctl
->opt_linewrap
= set_opt_flag(ctl
->opt_linewrap
);
556 ctl
->opt_li_on
= parse_switch(optarg
, _("argument error"),
560 ctl
->opt_default
= set_opt_flag(ctl
->opt_default
);
563 ctl
->opt_foreground
= set_opt_flag(ctl
->opt_foreground
);
564 ctl
->opt_fo_color
= parse_febg_color(optarg
);
567 ctl
->opt_background
= set_opt_flag(ctl
->opt_background
);
568 ctl
->opt_ba_color
= parse_febg_color(optarg
);
571 ctl
->opt_ulcolor
= set_opt_flag(ctl
->opt_ulcolor
);
572 ctl
->opt_ul_color
= parse_ulhb_color(av
, &optind
);
575 ctl
->opt_hbcolor
= set_opt_flag(ctl
->opt_hbcolor
);
576 ctl
->opt_hb_color
= parse_ulhb_color(av
, &optind
);
578 case OPT_INVERSESCREEN
:
579 ctl
->opt_inversescreen
= set_opt_flag(ctl
->opt_inversescreen
);
580 ctl
->opt_invsc_on
= parse_switch(optarg
, _("argument error"),
584 ctl
->opt_bold
= set_opt_flag(ctl
->opt_bold
);
585 ctl
->opt_bo_on
= parse_switch(optarg
, _("argument error"),
588 case OPT_HALF_BRIGHT
:
589 ctl
->opt_halfbright
= set_opt_flag(ctl
->opt_halfbright
);
590 ctl
->opt_hb_on
= parse_switch(optarg
, _("argument error"),
594 ctl
->opt_blink
= set_opt_flag(ctl
->opt_blink
);
595 ctl
->opt_bl_on
= parse_switch(optarg
, _("argument error"),
599 ctl
->opt_reverse
= set_opt_flag(ctl
->opt_reverse
);
600 ctl
->opt_re_on
= parse_switch(optarg
, _("argument error"),
604 ctl
->opt_underline
= set_opt_flag(ctl
->opt_underline
);
605 ctl
->opt_un_on
= parse_switch(optarg
, _("argument error"),
609 ctl
->opt_store
= set_opt_flag(ctl
->opt_store
);
612 ctl
->opt_clear
= set_opt_flag(ctl
->opt_clear
);
613 ctl
->opt_cl_all
= parse_switch(optarg
, _("argument error"),
614 "all", "reset", NULL
);
617 ctl
->opt_tabs
= set_opt_flag(ctl
->opt_tabs
);
618 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
621 ctl
->opt_clrtabs
= set_opt_flag(ctl
->opt_clrtabs
);
622 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
625 ctl
->opt_regtabs
= set_opt_flag(ctl
->opt_regtabs
);
626 ctl
->opt_rt_len
= parse_regtabs(av
, optarg
, &optind
);
629 ctl
->opt_blank
= set_opt_flag(ctl
->opt_blank
);
630 ctl
->opt_bl_min
= parse_blank(av
, optarg
, &optind
);
633 ctl
->opt_snap
= set_opt_flag(ctl
->opt_snap
);
634 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
637 ctl
->opt_append
= set_opt_flag(ctl
->opt_append
);
638 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
641 ctl
->opt_snapfile
= set_opt_flag(ctl
->opt_snapfile
);
642 ctl
->opt_sn_name
= optarg
;
645 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
646 ctl
->opt_msg_on
= parse_switch(optarg
, _("argument error"),
650 ctl
->opt_msglevel
= set_opt_flag(ctl
->opt_msglevel
);
651 ctl
->opt_msglevel_num
= parse_msglevel(optarg
);
652 if (ctl
->opt_msglevel_num
== 0) {
653 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
654 ctl
->opt_msg_on
|= 1;
658 ctl
->opt_powersave
= set_opt_flag(ctl
->opt_powersave
);
659 ctl
->opt_ps_mode
= parse_powersave(optarg
);
662 ctl
->opt_powerdown
= set_opt_flag(ctl
->opt_powerdown
);
663 ctl
->opt_pd_min
= parse_blank(av
, optarg
, &optind
);
666 ctl
->opt_blength
= set_opt_flag(ctl
->opt_blength
);
667 ctl
->opt_blength_l
= parse_blength(av
, optarg
, &optind
);
670 ctl
->opt_bfreq
= set_opt_flag(ctl
->opt_bfreq
);
671 ctl
->opt_bfreq_f
= parse_bfreq(av
, optarg
, &optind
);
674 printf(UTIL_LINUX_VERSION
);
679 errtryhelp(EXIT_FAILURE
);
684 /* Return the specified terminfo string, or an empty string if no such
685 * terminfo capability exists. */
686 static char *ti_entry(const char *name
)
690 if ((buf_ptr
= tigetstr(name
)) == (char *)-1)
695 static void show_tabs(void)
697 int i
, co
= tigetnum("cols");
701 for (i
= 10; i
< co
- 2; i
+= 10)
704 for (i
= 1; i
<= co
; i
++)
705 putchar(i
% 10 + '0');
707 for (i
= 1; i
< co
; i
++)
713 static int open_snapshot_device(struct setterm_control
*ctl
)
718 xasprintf(&ctl
->in_device
, "/dev/vcsa%d", ctl
->opt_sn_num
);
720 xasprintf(&ctl
->in_device
, "/dev/vcsa");
721 fd
= open(ctl
->in_device
, O_RDONLY
);
723 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
727 static void set_blanking(struct setterm_control
*ctl
)
732 if (0 <= ctl
->opt_bl_min
) {
733 printf("\033[9;%d]", ctl
->opt_bl_min
);
736 switch (ctl
->opt_bl_min
) {
738 ioctlarg
= TIOCL_BLANKSCREEN
;
739 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
740 warn(_("cannot force blank"));
743 ioctlarg
= TIOCL_UNBLANKSCREEN
;
744 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
745 warn(_("cannot force unblank"));
748 ioctlarg
= TIOCL_BLANKEDSCREEN
;
749 ret
= ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
);
751 warn(_("cannot get blank status"));
755 default: /* should be impossible to reach */
761 static void screendump(struct setterm_control
*ctl
)
763 unsigned char header
[4];
764 unsigned int rows
, cols
;
769 char *inbuf
, *outbuf
, *p
, *q
;
771 /* open source and destination files */
772 fd
= open_snapshot_device(ctl
);
773 if (!ctl
->opt_sn_name
)
774 ctl
->opt_sn_name
= "screen.dump";
775 out
= fopen(ctl
->opt_sn_name
, ctl
->opt_snap
? "w" : "a");
777 err(EXIT_DUMPFILE
, _("cannot open dump file %s for output"), ctl
->opt_sn_name
);
778 /* determine snapshot size */
779 if (read(fd
, header
, 4) != 4)
780 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
783 if (rows
* cols
== 0)
784 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
785 /* allocate buffers */
786 inbuf
= xmalloc(rows
* cols
* 2);
787 outbuf
= xmalloc(rows
* (cols
+ 1));
789 rc
= read(fd
, inbuf
, rows
* cols
* 2);
790 if (rc
< 0 || (size_t)rc
!= rows
* cols
* 2)
791 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
794 /* copy inbuf to outbuf */
795 for (i
= 0; i
< rows
; i
++) {
796 for (j
= 0; j
< cols
; j
++) {
800 while (j
-- > 0 && q
[-1] == ' ')
804 fwrite(outbuf
, 1, q
- outbuf
, out
);
805 /* clean up allocations */
809 free(ctl
->in_device
);
810 if (close_stream(out
) != 0)
811 errx(EXIT_FAILURE
, _("write error"));
815 /* Some options are applicable when terminal is virtual console. */
816 static int vc_only(struct setterm_control
*ctl
, const char *err
)
818 if (!ctl
->vcterm
&& err
)
819 warnx(_("terminal %s does not support %s"),
820 ctl
->opt_te_terminal_name
, err
);
824 static void tty_raw(struct termios
*saved_attributes
, int *saved_fl
)
826 struct termios tattr
;
828 fcntl(STDIN_FILENO
, F_GETFL
, saved_fl
);
829 tcgetattr(STDIN_FILENO
, saved_attributes
);
830 fcntl(STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
831 memcpy(&tattr
, saved_attributes
, sizeof(struct termios
));
832 tattr
.c_lflag
&= ~(ICANON
| ECHO
);
833 tattr
.c_cc
[VMIN
] = 1;
834 tattr
.c_cc
[VTIME
] = 0;
835 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tattr
);
838 static void tty_restore(struct termios
*saved_attributes
, int *saved_fl
)
840 fcntl(STDIN_FILENO
, F_SETFL
, *saved_fl
);
841 tcsetattr(STDIN_FILENO
, TCSANOW
, saved_attributes
);
844 static int select_wait(void)
851 FD_SET(STDIN_FILENO
, &set
);
854 while ((ret
= select(1, &set
, NULL
, NULL
, &tv
)) < 0) {
857 err(EXIT_FAILURE
, _("select failed"));
862 static int resizetty(void)
865 * \e7 Save current state (cursor coordinates, attributes,
866 * character sets pointed at by G0, G1).
867 * \e[r Set scrolling region; parameters are top and bottom row.
868 * \e[32766E Move cursor down 32766 (INT16_MAX - 1) rows.
869 * \e[32766C Move cursor right 32766 columns.
870 * \e[6n Report cursor position.
871 * \e8 Restore state most recently saved by \e7.
873 static const char *getpos
= "\e7\e[r\e[32766E\e[32766C\e[6n\e8";
879 struct termios saved_attributes
;
882 if (!isatty(STDIN_FILENO
))
883 errx(EXIT_FAILURE
, _("stdin does not refer to a terminal"));
885 tty_raw(&saved_attributes
, &saved_fl
);
886 if (write_all(STDIN_FILENO
, getpos
, strlen(getpos
)) < 0) {
887 warn(_("write failed"));
888 tty_restore(&saved_attributes
, &saved_fl
);
891 for (pos
= 0; pos
< sizeof(retstr
) - 1;) {
892 if (0 == select_wait())
895 read(STDIN_FILENO
, retstr
+ pos
,
896 sizeof(retstr
) - 1 - pos
)) < 0) {
899 warn(_("read failed"));
900 tty_restore(&saved_attributes
, &saved_fl
);
904 if (retstr
[pos
- 1] == 'R')
908 tty_restore(&saved_attributes
, &saved_fl
);
909 rc
= sscanf(retstr
, "\033[%d;%dR", &row
, &col
);
911 warnx(_("invalid cursor position: %s"), retstr
);
914 memset(&ws
, 0, sizeof(struct winsize
));
915 ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
);
918 ioctl(STDIN_FILENO
, TIOCSWINSZ
, &ws
);
922 static void perform_sequence(struct setterm_control
*ctl
)
928 putp(ti_entry("rs1"));
933 warnx(_("reset failed"));
936 if (ctl
->opt_initialize
)
937 putp(ti_entry("is2"));
939 /* -cursor [on|off]. */
940 if (ctl
->opt_cursor
) {
942 putp(ti_entry("cnorm"));
944 putp(ti_entry("civis"));
947 /* -linewrap [on|off]. */
948 if (ctl
->opt_linewrap
)
949 fputs(ctl
->opt_li_on
? "\033[?7h" : "\033[?7l", stdout
);
951 /* -repeat [on|off]. */
952 if (ctl
->opt_repeat
&& vc_only(ctl
, "--repeat"))
953 fputs(ctl
->opt_rep_on
? "\033[?8h" : "\033[?8l", stdout
);
955 /* -appcursorkeys [on|off]. */
956 if (ctl
->opt_appcursorkeys
&& vc_only(ctl
, "--appcursorkeys"))
957 fputs(ctl
->opt_appck_on
? "\033[?1h" : "\033[?1l", stdout
);
959 /* -default. Vc sets default rendition, otherwise clears all
961 if (ctl
->opt_default
) {
962 if (vc_only(ctl
, NULL
))
965 putp(ti_entry("sgr0"));
968 /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
969 if (ctl
->opt_foreground
)
970 printf("\033[3%c%s", '0' + ctl
->opt_fo_color
, "m");
972 /* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
973 if (ctl
->opt_background
)
974 printf("\033[4%c%s", '0' + ctl
->opt_ba_color
, "m");
976 /* -ulcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
977 if (ctl
->opt_ulcolor
&& vc_only(ctl
, "--ulcolor"))
978 printf("\033[1;%d]", ctl
->opt_ul_color
);
980 /* -hbcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
981 if (ctl
->opt_hbcolor
)
982 printf("\033[2;%d]", ctl
->opt_hb_color
);
984 /* -inversescreen [on|off]. */
985 if (ctl
->opt_inversescreen
)
986 fputs(ctl
->opt_invsc_on
? "\033[?5h" : "\033[?5l", stdout
);
988 /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
992 putp(ti_entry("bold"));
994 if (vc_only(ctl
, NULL
))
995 fputs("\033[22m", stdout
);
997 putp(ti_entry("sgr0"));
1001 /* -half-bright [on|off]. Vc behaves as expected, otherwise off
1002 * turns off all attributes. */
1003 if (ctl
->opt_halfbright
) {
1005 putp(ti_entry("dim"));
1007 if (vc_only(ctl
, NULL
))
1008 fputs("\033[22m", stdout
);
1010 putp(ti_entry("sgr0"));
1014 /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
1015 * all attributes. */
1016 if (ctl
->opt_blink
) {
1018 putp(ti_entry("blink"));
1020 if (vc_only(ctl
, NULL
))
1021 fputs("\033[25m", stdout
);
1023 putp(ti_entry("sgr0"));
1027 /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
1028 * off all attributes. */
1029 if (ctl
->opt_reverse
) {
1031 putp(ti_entry("rev"));
1033 if (vc_only(ctl
, NULL
))
1034 fputs("\033[27m", stdout
);
1036 putp(ti_entry("sgr0"));
1040 /* -underline [on|off]. */
1041 if (ctl
->opt_underline
)
1042 putp(ti_entry(ctl
->opt_un_on
? "smul" : "rmul"));
1045 if (ctl
->opt_store
&& vc_only(ctl
, "--store"))
1046 fputs("\033[8]", stdout
);
1048 /* -clear [all|rest]. */
1050 putp(ti_entry(ctl
->opt_cl_all
? "clear" : "ed"));
1053 if (ctl
->opt_tabs
) {
1054 if (ctl
->opt_tb_array
[0] == -1)
1059 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1060 printf("\033[%dG\033H", ctl
->opt_tb_array
[i
]);
1066 if (ctl
->opt_clrtabs
&& vc_only(ctl
, "--clrtabs")) {
1069 if (ctl
->opt_tb_array
[0] == -1)
1070 fputs("\033[3g", stdout
);
1072 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1073 printf("\033[%dG\033[g", ctl
->opt_tb_array
[i
]);
1078 if (ctl
->opt_regtabs
&& vc_only(ctl
, "--regtabs")) {
1081 fputs("\033[3g\r", stdout
);
1082 for (i
= ctl
->opt_rt_len
+ 1; i
<= TABS_MAX
; i
+= ctl
->opt_rt_len
)
1083 printf("\033[%dC\033H", ctl
->opt_rt_len
);
1087 /* -blank [0-60]. */
1088 if (ctl
->opt_blank
&& vc_only(ctl
, "--blank"))
1091 /* -powersave [on|vsync|hsync|powerdown|off] (console) */
1092 if (ctl
->opt_powersave
) {
1094 ioctlarg
[0] = TIOCL_SETVESABLANK
;
1095 ioctlarg
[1] = ctl
->opt_ps_mode
;
1096 if (ioctl(STDIN_FILENO
, TIOCLINUX
, ioctlarg
))
1097 warn(_("cannot (un)set powersave mode"));
1100 /* -powerdown [0-60]. */
1101 if (ctl
->opt_powerdown
)
1102 printf("\033[14;%d]", ctl
->opt_pd_min
);
1104 /* -snap [1-NR_CONS]. */
1105 if (ctl
->opt_snap
|| ctl
->opt_append
)
1108 /* -msg [on|off]. Controls printk's to console. */
1109 if (ctl
->opt_msg
&& vc_only(ctl
, "--msg")) {
1110 if (ctl
->opt_msg_on
)
1111 result
= klogctl(SYSLOG_ACTION_CONSOLE_ON
, NULL
, 0);
1113 result
= klogctl(SYSLOG_ACTION_CONSOLE_OFF
, NULL
, 0);
1116 warn(_("klogctl error"));
1119 /* -msglevel [0-8]. Console printk message level. */
1120 if (ctl
->opt_msglevel_num
&& vc_only(ctl
, "--msglevel")) {
1122 klogctl(SYSLOG_ACTION_CONSOLE_LEVEL
, NULL
,
1123 ctl
->opt_msglevel_num
);
1125 warn(_("klogctl error"));
1128 /* -blength [0-2000] */
1129 if (ctl
->opt_blength
&& vc_only(ctl
, "--blength")) {
1130 printf("\033[11;%d]", ctl
->opt_blength_l
);
1133 /* -bfreq freqnumber */
1134 if (ctl
->opt_bfreq
&& vc_only(ctl
, "--bfreq")) {
1135 printf("\033[10;%d]", ctl
->opt_bfreq_f
);
1139 static void init_terminal(struct setterm_control
*ctl
)
1143 if (!ctl
->opt_te_terminal_name
) {
1144 ctl
->opt_te_terminal_name
= getenv("TERM");
1145 if (ctl
->opt_te_terminal_name
== NULL
)
1146 errx(EXIT_FAILURE
, _("$TERM is not defined."));
1149 /* Find terminfo entry. */
1150 if (setupterm(ctl
->opt_te_terminal_name
, STDOUT_FILENO
, &term_errno
))
1151 switch (term_errno
) {
1153 errx(EXIT_FAILURE
, _("terminfo database cannot be found"));
1155 errx(EXIT_FAILURE
, _("%s: unknown terminal type"), ctl
->opt_te_terminal_name
);
1157 errx(EXIT_FAILURE
, _("terminal is hardcopy"));
1160 /* See if the terminal is a virtual console terminal. */
1161 ctl
->vcterm
= (!strncmp(ctl
->opt_te_terminal_name
, "con", 3) ||
1162 !strncmp(ctl
->opt_te_terminal_name
, "linux", 5));
1166 int main(int argc
, char **argv
)
1168 struct setterm_control ctl
= { NULL
};
1170 setlocale(LC_ALL
, "");
1171 bindtextdomain(PACKAGE
, LOCALEDIR
);
1172 textdomain(PACKAGE
);
1173 atexit(close_stdout
);
1176 warnx(_("bad usage"));
1177 errtryhelp(EXIT_FAILURE
);
1179 parse_option(&ctl
, argc
, argv
);
1180 init_terminal(&ctl
);
1181 perform_sequence(&ctl
);
1183 return EXIT_SUCCESS
;