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(_(" --cursor [on|off] display cursor\n"), out
);
395 fputs(_(" --repeat [on|off] keyboard repeat\n"), out
);
396 fputs(_(" --appcursorkeys [on|off] cursor key application mode\n"), out
);
397 fputs(_(" --linewrap [on|off] continue on a new line when a line is full\n"), out
);
398 fputs(_(" --inversescreen [on|off] swap colors for the whole screen\n"), out
);
399 fputs(_(" --foreground default|<color> set foreground color\n"), out
);
400 fputs(_(" --background default|<color> set background color\n"), out
);
401 fputs(_(" --ulcolor [bright] <color> set underlined text color\n"), out
);
402 fputs(_(" --hbcolor [bright] <color> set half-bright text color\n"), out
);
403 fputs(_(" <color>: black blue cyan green grey magenta red white yellow\n"), out
);
404 fputs(_(" --bold [on|off] bold\n"), out
);
405 fputs(_(" --half-bright [on|off] dim\n"), out
);
406 fputs(_(" --blink [on|off] blink\n"), out
);
407 fputs(_(" --underline [on|off] underline\n"), out
);
408 fputs(_(" --reverse [on|off] swap foreground and background colors\n"), out
);
409 fputs(_(" --clear [all|rest] clear screen and set cursor position\n"), out
);
410 fputs(_(" --tabs [<number>...] set these tab stop positions, or show them\n"), out
);
411 fputs(_(" --clrtabs [<number>...] clear these tab stop positions, or all\n"), out
);
412 fputs(_(" --regtabs [1-160] set a regular tab stop interval\n"), out
);
413 fputs(_(" --blank [0-60|force|poke] set time of inactivity before screen blanks\n"), out
);
414 fputs(_(" --dump [<number>] write vcsa<number> console dump to file\n"), out
);
415 fputs(_(" --append [<number>] append vcsa<number> console dump to file\n"), out
);
416 fputs(_(" --file <filename> name of the dump file\n"), out
);
417 fputs(_(" --msg [on|off] send kernel messages to console\n"), out
);
418 fputs(_(" --msglevel 0-8 kernel console log level\n"), out
);
419 fputs(_(" --powersave [on|vsync|hsync|powerdown|off]\n"), out
);
420 fputs(_(" set vesa powersaving features\n"), out
);
421 fputs(_(" --powerdown [0-60] set vesa powerdown interval in minutes\n"), out
);
422 fputs(_(" --blength [0-2000] duration of the bell in milliseconds\n"), out
);
423 fputs(_(" --bfreq <number> bell frequency in Hertz\n"), out
);
424 printf( " --help %s\n", USAGE_OPTSTR_HELP
);
425 printf( " --version %s\n", USAGE_OPTSTR_VERSION
);
427 printf(USAGE_MAN_TAIL("setterm(1)"));
431 static int __attribute__((__pure__
)) set_opt_flag(int opt
)
434 errx(EXIT_FAILURE
, _("duplicate use of an option"));
438 static void parse_option(struct setterm_control
*ctl
, int ac
, char **av
)
442 OPT_TERM
= CHAR_MAX
+ 1,
479 static const struct option longopts
[] = {
480 {"term", required_argument
, NULL
, OPT_TERM
},
481 {"reset", no_argument
, NULL
, OPT_RESET
},
482 {"resize", no_argument
, NULL
, OPT_RESIZE
},
483 {"initialize", no_argument
, NULL
, OPT_INITIALIZE
},
484 {"cursor", required_argument
, NULL
, OPT_CURSOR
},
485 {"repeat", required_argument
, NULL
, OPT_REPEAT
},
486 {"appcursorkeys", required_argument
, NULL
, OPT_APPCURSORKEYS
},
487 {"linewrap", required_argument
, NULL
, OPT_LINEWRAP
},
488 {"default", no_argument
, NULL
, OPT_DEFAULT
},
489 {"foreground", required_argument
, NULL
, OPT_FOREGROUND
},
490 {"background", required_argument
, NULL
, OPT_BACKGROUND
},
491 {"ulcolor", required_argument
, NULL
, OPT_ULCOLOR
},
492 {"hbcolor", required_argument
, NULL
, OPT_HBCOLOR
},
493 {"inversescreen", required_argument
, NULL
, OPT_INVERSESCREEN
},
494 {"bold", required_argument
, NULL
, OPT_BOLD
},
495 {"half-bright", required_argument
, NULL
, OPT_HALF_BRIGHT
},
496 {"blink", required_argument
, NULL
, OPT_BLINK
},
497 {"reverse", required_argument
, NULL
, OPT_REVERSE
},
498 {"underline", required_argument
, NULL
, OPT_UNDERLINE
},
499 {"store", no_argument
, NULL
, OPT_STORE
},
500 {"clear", required_argument
, NULL
, OPT_CLEAR
},
501 {"tabs", optional_argument
, NULL
, OPT_TABS
},
502 {"clrtabs", optional_argument
, NULL
, OPT_CLRTABS
},
503 {"regtabs", optional_argument
, NULL
, OPT_REGTABS
},
504 {"blank", optional_argument
, NULL
, OPT_BLANK
},
505 {"dump", optional_argument
, NULL
, OPT_DUMP
},
506 {"append", required_argument
, NULL
, OPT_APPEND
},
507 {"file", required_argument
, NULL
, OPT_FILE
},
508 {"msg", required_argument
, NULL
, OPT_MSG
},
509 {"msglevel", required_argument
, NULL
, OPT_MSGLEVEL
},
510 {"powersave", required_argument
, NULL
, OPT_POWERSAVE
},
511 {"powerdown", optional_argument
, NULL
, OPT_POWERDOWN
},
512 {"blength", optional_argument
, NULL
, OPT_BLENGTH
},
513 {"bfreq", optional_argument
, NULL
, OPT_BFREQ
},
514 {"version", no_argument
, NULL
, OPT_VERSION
},
515 {"help", no_argument
, NULL
, OPT_HELP
},
518 static const ul_excl_t excl
[] = {
519 { OPT_DEFAULT
, OPT_STORE
},
520 { OPT_TABS
, OPT_CLRTABS
, OPT_REGTABS
},
521 { OPT_MSG
, OPT_MSGLEVEL
},
524 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
526 while ((c
= getopt_long_only(ac
, av
, "", longopts
, NULL
)) != -1) {
527 err_exclusive_options(c
, longopts
, excl
, excl_st
);
530 ctl
->opt_term
= set_opt_flag(ctl
->opt_term
);
531 ctl
->opt_te_terminal_name
= optarg
;
534 ctl
->opt_reset
= set_opt_flag(ctl
->opt_reset
);
537 ctl
->opt_resize
= set_opt_flag(ctl
->opt_resize
);
540 ctl
->opt_initialize
= set_opt_flag(ctl
->opt_initialize
);
543 ctl
->opt_cursor
= set_opt_flag(ctl
->opt_cursor
);
544 ctl
->opt_cu_on
= parse_switch(optarg
, _("argument error"),
548 ctl
->opt_repeat
= set_opt_flag(ctl
->opt_repeat
);
549 ctl
->opt_rep_on
= parse_switch(optarg
, _("argument error"),
552 case OPT_APPCURSORKEYS
:
553 ctl
->opt_appcursorkeys
= set_opt_flag(ctl
->opt_appcursorkeys
);
554 ctl
->opt_appck_on
= parse_switch(optarg
, _("argument error"),
558 ctl
->opt_linewrap
= set_opt_flag(ctl
->opt_linewrap
);
559 ctl
->opt_li_on
= parse_switch(optarg
, _("argument error"),
563 ctl
->opt_default
= set_opt_flag(ctl
->opt_default
);
566 ctl
->opt_foreground
= set_opt_flag(ctl
->opt_foreground
);
567 ctl
->opt_fo_color
= parse_febg_color(optarg
);
570 ctl
->opt_background
= set_opt_flag(ctl
->opt_background
);
571 ctl
->opt_ba_color
= parse_febg_color(optarg
);
574 ctl
->opt_ulcolor
= set_opt_flag(ctl
->opt_ulcolor
);
575 ctl
->opt_ul_color
= parse_ulhb_color(av
, &optind
);
578 ctl
->opt_hbcolor
= set_opt_flag(ctl
->opt_hbcolor
);
579 ctl
->opt_hb_color
= parse_ulhb_color(av
, &optind
);
581 case OPT_INVERSESCREEN
:
582 ctl
->opt_inversescreen
= set_opt_flag(ctl
->opt_inversescreen
);
583 ctl
->opt_invsc_on
= parse_switch(optarg
, _("argument error"),
587 ctl
->opt_bold
= set_opt_flag(ctl
->opt_bold
);
588 ctl
->opt_bo_on
= parse_switch(optarg
, _("argument error"),
591 case OPT_HALF_BRIGHT
:
592 ctl
->opt_halfbright
= set_opt_flag(ctl
->opt_halfbright
);
593 ctl
->opt_hb_on
= parse_switch(optarg
, _("argument error"),
597 ctl
->opt_blink
= set_opt_flag(ctl
->opt_blink
);
598 ctl
->opt_bl_on
= parse_switch(optarg
, _("argument error"),
602 ctl
->opt_reverse
= set_opt_flag(ctl
->opt_reverse
);
603 ctl
->opt_re_on
= parse_switch(optarg
, _("argument error"),
607 ctl
->opt_underline
= set_opt_flag(ctl
->opt_underline
);
608 ctl
->opt_un_on
= parse_switch(optarg
, _("argument error"),
612 ctl
->opt_store
= set_opt_flag(ctl
->opt_store
);
615 ctl
->opt_clear
= set_opt_flag(ctl
->opt_clear
);
616 ctl
->opt_cl_all
= parse_switch(optarg
, _("argument error"),
617 "all", "reset", NULL
);
620 ctl
->opt_tabs
= set_opt_flag(ctl
->opt_tabs
);
621 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
624 ctl
->opt_clrtabs
= set_opt_flag(ctl
->opt_clrtabs
);
625 parse_tabs(av
, optarg
, &optind
, ctl
->opt_tb_array
);
628 ctl
->opt_regtabs
= set_opt_flag(ctl
->opt_regtabs
);
629 ctl
->opt_rt_len
= parse_regtabs(av
, optarg
, &optind
);
632 ctl
->opt_blank
= set_opt_flag(ctl
->opt_blank
);
633 ctl
->opt_bl_min
= parse_blank(av
, optarg
, &optind
);
636 ctl
->opt_snap
= set_opt_flag(ctl
->opt_snap
);
637 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
640 ctl
->opt_append
= set_opt_flag(ctl
->opt_append
);
641 ctl
->opt_sn_num
= parse_snap(av
, optarg
, &optind
);
644 ctl
->opt_snapfile
= set_opt_flag(ctl
->opt_snapfile
);
645 ctl
->opt_sn_name
= optarg
;
648 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
649 ctl
->opt_msg_on
= parse_switch(optarg
, _("argument error"),
653 ctl
->opt_msglevel
= set_opt_flag(ctl
->opt_msglevel
);
654 ctl
->opt_msglevel_num
= parse_msglevel(optarg
);
655 if (ctl
->opt_msglevel_num
== 0) {
656 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
657 ctl
->opt_msg_on
|= 1;
661 ctl
->opt_powersave
= set_opt_flag(ctl
->opt_powersave
);
662 ctl
->opt_ps_mode
= parse_powersave(optarg
);
665 ctl
->opt_powerdown
= set_opt_flag(ctl
->opt_powerdown
);
666 ctl
->opt_pd_min
= parse_blank(av
, optarg
, &optind
);
669 ctl
->opt_blength
= set_opt_flag(ctl
->opt_blength
);
670 ctl
->opt_blength_l
= parse_blength(av
, optarg
, &optind
);
673 ctl
->opt_bfreq
= set_opt_flag(ctl
->opt_bfreq
);
674 ctl
->opt_bfreq_f
= parse_bfreq(av
, optarg
, &optind
);
678 print_version(EXIT_SUCCESS
);
682 errtryhelp(EXIT_FAILURE
);
687 /* Return the specified terminfo string, or an empty string if no such
688 * terminfo capability exists. */
689 static char *ti_entry(const char *name
)
693 if ((buf_ptr
= tigetstr(name
)) == (char *)-1)
698 static void show_tabs(void)
700 int i
, co
= tigetnum("cols");
704 for (i
= 10; i
< co
- 2; i
+= 10)
707 for (i
= 1; i
<= co
; i
++)
708 putchar(i
% 10 + '0');
710 for (i
= 1; i
< co
; i
++)
716 static int open_snapshot_device(struct setterm_control
*ctl
)
721 xasprintf(&ctl
->in_device
, "/dev/vcsa%d", ctl
->opt_sn_num
);
723 xasprintf(&ctl
->in_device
, "/dev/vcsa");
724 fd
= open(ctl
->in_device
, O_RDONLY
);
726 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
730 static void set_blanking(struct setterm_control
*ctl
)
735 if (0 <= ctl
->opt_bl_min
) {
736 printf("\033[9;%d]", ctl
->opt_bl_min
);
739 switch (ctl
->opt_bl_min
) {
741 ioctlarg
= TIOCL_BLANKSCREEN
;
742 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
743 warn(_("cannot force blank"));
746 ioctlarg
= TIOCL_UNBLANKSCREEN
;
747 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
748 warn(_("cannot force unblank"));
751 ioctlarg
= TIOCL_BLANKEDSCREEN
;
752 ret
= ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
);
754 warn(_("cannot get blank status"));
758 default: /* should be impossible to reach */
764 static void screendump(struct setterm_control
*ctl
)
766 unsigned char header
[4];
767 unsigned int rows
, cols
;
772 char *inbuf
, *outbuf
, *p
, *q
;
774 /* open source and destination files */
775 fd
= open_snapshot_device(ctl
);
776 if (!ctl
->opt_sn_name
)
777 ctl
->opt_sn_name
= "screen.dump";
778 out
= fopen(ctl
->opt_sn_name
, ctl
->opt_snap
? "w" : "a");
780 err(EXIT_DUMPFILE
, _("cannot open dump file %s for output"), ctl
->opt_sn_name
);
781 /* determine snapshot size */
782 if (read(fd
, header
, 4) != 4)
783 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
786 if (rows
* cols
== 0)
787 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
788 /* allocate buffers */
789 inbuf
= xmalloc(rows
* cols
* 2);
790 outbuf
= xmalloc(rows
* (cols
+ 1));
792 rc
= read(fd
, inbuf
, rows
* cols
* 2);
793 if (rc
< 0 || (size_t)rc
!= rows
* cols
* 2)
794 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
797 /* copy inbuf to outbuf */
798 for (i
= 0; i
< rows
; i
++) {
799 for (j
= 0; j
< cols
; j
++) {
803 while (j
-- > 0 && q
[-1] == ' ')
807 fwrite(outbuf
, 1, q
- outbuf
, out
);
808 /* clean up allocations */
812 free(ctl
->in_device
);
813 if (close_stream(out
) != 0)
814 errx(EXIT_FAILURE
, _("write error"));
818 /* Some options are applicable when terminal is virtual console. */
819 static int vc_only(struct setterm_control
*ctl
, const char *err
)
821 if (!ctl
->vcterm
&& err
)
822 warnx(_("terminal %s does not support %s"),
823 ctl
->opt_te_terminal_name
, err
);
827 static void tty_raw(struct termios
*saved_attributes
, int *saved_fl
)
829 struct termios tattr
;
831 fcntl(STDIN_FILENO
, F_GETFL
, saved_fl
);
832 tcgetattr(STDIN_FILENO
, saved_attributes
);
833 fcntl(STDIN_FILENO
, F_SETFL
, O_NONBLOCK
);
834 memcpy(&tattr
, saved_attributes
, sizeof(struct termios
));
835 tattr
.c_lflag
&= ~(ICANON
| ECHO
);
836 tattr
.c_cc
[VMIN
] = 1;
837 tattr
.c_cc
[VTIME
] = 0;
838 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tattr
);
841 static void tty_restore(struct termios
*saved_attributes
, int *saved_fl
)
843 fcntl(STDIN_FILENO
, F_SETFL
, *saved_fl
);
844 tcsetattr(STDIN_FILENO
, TCSANOW
, saved_attributes
);
847 static int select_wait(void)
854 FD_SET(STDIN_FILENO
, &set
);
857 while ((ret
= select(1, &set
, NULL
, NULL
, &tv
)) < 0) {
860 err(EXIT_FAILURE
, _("select failed"));
865 static int resizetty(void)
868 * \e7 Save current state (cursor coordinates, attributes,
869 * character sets pointed at by G0, G1).
870 * \e[r Set scrolling region; parameters are top and bottom row.
871 * \e[32766E Move cursor down 32766 (INT16_MAX - 1) rows.
872 * \e[32766C Move cursor right 32766 columns.
873 * \e[6n Report cursor position.
874 * \e8 Restore state most recently saved by \e7.
876 static const char *getpos
= "\e7\e[r\e[32766E\e[32766C\e[6n\e8";
882 struct termios saved_attributes
;
885 if (!isatty(STDIN_FILENO
))
886 errx(EXIT_FAILURE
, _("stdin does not refer to a terminal"));
888 tty_raw(&saved_attributes
, &saved_fl
);
889 if (write_all(STDIN_FILENO
, getpos
, strlen(getpos
)) < 0) {
890 warn(_("write failed"));
891 tty_restore(&saved_attributes
, &saved_fl
);
894 for (pos
= 0; pos
< sizeof(retstr
) - 1;) {
895 if (0 == select_wait())
898 read(STDIN_FILENO
, retstr
+ pos
,
899 sizeof(retstr
) - 1 - pos
)) < 0) {
902 warn(_("read failed"));
903 tty_restore(&saved_attributes
, &saved_fl
);
907 if (retstr
[pos
- 1] == 'R')
911 tty_restore(&saved_attributes
, &saved_fl
);
912 rc
= sscanf(retstr
, "\033[%d;%dR", &row
, &col
);
914 warnx(_("invalid cursor position: %s"), retstr
);
917 memset(&ws
, 0, sizeof(struct winsize
));
918 ioctl(STDIN_FILENO
, TIOCGWINSZ
, &ws
);
921 ioctl(STDIN_FILENO
, TIOCSWINSZ
, &ws
);
925 static void perform_sequence(struct setterm_control
*ctl
)
931 putp(ti_entry("rs1"));
936 warnx(_("reset failed"));
939 if (ctl
->opt_initialize
)
940 putp(ti_entry("is2"));
942 /* -cursor [on|off]. */
943 if (ctl
->opt_cursor
) {
945 putp(ti_entry("cnorm"));
947 putp(ti_entry("civis"));
950 /* -linewrap [on|off]. */
951 if (ctl
->opt_linewrap
)
952 fputs(ctl
->opt_li_on
? "\033[?7h" : "\033[?7l", stdout
);
954 /* -repeat [on|off]. */
955 if (ctl
->opt_repeat
&& vc_only(ctl
, "--repeat"))
956 fputs(ctl
->opt_rep_on
? "\033[?8h" : "\033[?8l", stdout
);
958 /* -appcursorkeys [on|off]. */
959 if (ctl
->opt_appcursorkeys
&& vc_only(ctl
, "--appcursorkeys"))
960 fputs(ctl
->opt_appck_on
? "\033[?1h" : "\033[?1l", stdout
);
962 /* -default. Vc sets default rendition, otherwise clears all
964 if (ctl
->opt_default
) {
965 if (vc_only(ctl
, NULL
))
968 putp(ti_entry("sgr0"));
971 /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
972 if (ctl
->opt_foreground
)
973 printf("\033[3%c%s", '0' + ctl
->opt_fo_color
, "m");
975 /* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
976 if (ctl
->opt_background
)
977 printf("\033[4%c%s", '0' + ctl
->opt_ba_color
, "m");
979 /* -ulcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
980 if (ctl
->opt_ulcolor
&& vc_only(ctl
, "--ulcolor"))
981 printf("\033[1;%d]", ctl
->opt_ul_color
);
983 /* -hbcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
984 if (ctl
->opt_hbcolor
)
985 printf("\033[2;%d]", ctl
->opt_hb_color
);
987 /* -inversescreen [on|off]. */
988 if (ctl
->opt_inversescreen
)
989 fputs(ctl
->opt_invsc_on
? "\033[?5h" : "\033[?5l", stdout
);
991 /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
995 putp(ti_entry("bold"));
997 if (vc_only(ctl
, NULL
))
998 fputs("\033[22m", stdout
);
1000 putp(ti_entry("sgr0"));
1004 /* -half-bright [on|off]. Vc behaves as expected, otherwise off
1005 * turns off all attributes. */
1006 if (ctl
->opt_halfbright
) {
1008 putp(ti_entry("dim"));
1010 if (vc_only(ctl
, NULL
))
1011 fputs("\033[22m", stdout
);
1013 putp(ti_entry("sgr0"));
1017 /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
1018 * all attributes. */
1019 if (ctl
->opt_blink
) {
1021 putp(ti_entry("blink"));
1023 if (vc_only(ctl
, NULL
))
1024 fputs("\033[25m", stdout
);
1026 putp(ti_entry("sgr0"));
1030 /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
1031 * off all attributes. */
1032 if (ctl
->opt_reverse
) {
1034 putp(ti_entry("rev"));
1036 if (vc_only(ctl
, NULL
))
1037 fputs("\033[27m", stdout
);
1039 putp(ti_entry("sgr0"));
1043 /* -underline [on|off]. */
1044 if (ctl
->opt_underline
)
1045 putp(ti_entry(ctl
->opt_un_on
? "smul" : "rmul"));
1048 if (ctl
->opt_store
&& vc_only(ctl
, "--store"))
1049 fputs("\033[8]", stdout
);
1051 /* -clear [all|rest]. */
1053 putp(ti_entry(ctl
->opt_cl_all
? "clear" : "ed"));
1056 if (ctl
->opt_tabs
) {
1057 if (ctl
->opt_tb_array
[0] == -1)
1062 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1063 printf("\033[%dG\033H", ctl
->opt_tb_array
[i
]);
1069 if (ctl
->opt_clrtabs
&& vc_only(ctl
, "--clrtabs")) {
1072 if (ctl
->opt_tb_array
[0] == -1)
1073 fputs("\033[3g", stdout
);
1075 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
1076 printf("\033[%dG\033[g", ctl
->opt_tb_array
[i
]);
1081 if (ctl
->opt_regtabs
&& vc_only(ctl
, "--regtabs")) {
1084 fputs("\033[3g\r", stdout
);
1085 for (i
= ctl
->opt_rt_len
+ 1; i
<= TABS_MAX
; i
+= ctl
->opt_rt_len
)
1086 printf("\033[%dC\033H", ctl
->opt_rt_len
);
1090 /* -blank [0-60]. */
1091 if (ctl
->opt_blank
&& vc_only(ctl
, "--blank"))
1094 /* -powersave [on|vsync|hsync|powerdown|off] (console) */
1095 if (ctl
->opt_powersave
) {
1097 ioctlarg
[0] = TIOCL_SETVESABLANK
;
1098 ioctlarg
[1] = ctl
->opt_ps_mode
;
1099 if (ioctl(STDIN_FILENO
, TIOCLINUX
, ioctlarg
))
1100 warn(_("cannot (un)set powersave mode"));
1103 /* -powerdown [0-60]. */
1104 if (ctl
->opt_powerdown
)
1105 printf("\033[14;%d]", ctl
->opt_pd_min
);
1107 /* -snap [1-NR_CONS]. */
1108 if (ctl
->opt_snap
|| ctl
->opt_append
)
1111 /* -msg [on|off]. Controls printk's to console. */
1112 if (ctl
->opt_msg
&& vc_only(ctl
, "--msg")) {
1113 if (ctl
->opt_msg_on
)
1114 result
= klogctl(SYSLOG_ACTION_CONSOLE_ON
, NULL
, 0);
1116 result
= klogctl(SYSLOG_ACTION_CONSOLE_OFF
, NULL
, 0);
1119 warn(_("klogctl error"));
1122 /* -msglevel [0-8]. Console printk message level. */
1123 if (ctl
->opt_msglevel_num
&& vc_only(ctl
, "--msglevel")) {
1125 klogctl(SYSLOG_ACTION_CONSOLE_LEVEL
, NULL
,
1126 ctl
->opt_msglevel_num
);
1128 warn(_("klogctl error"));
1131 /* -blength [0-2000] */
1132 if (ctl
->opt_blength
&& vc_only(ctl
, "--blength")) {
1133 printf("\033[11;%d]", ctl
->opt_blength_l
);
1136 /* -bfreq freqnumber */
1137 if (ctl
->opt_bfreq
&& vc_only(ctl
, "--bfreq")) {
1138 printf("\033[10;%d]", ctl
->opt_bfreq_f
);
1142 static void init_terminal(struct setterm_control
*ctl
)
1146 if (!ctl
->opt_te_terminal_name
) {
1147 ctl
->opt_te_terminal_name
= getenv("TERM");
1148 if (ctl
->opt_te_terminal_name
== NULL
)
1149 errx(EXIT_FAILURE
, _("$TERM is not defined."));
1152 /* Find terminfo entry. */
1153 if (setupterm(ctl
->opt_te_terminal_name
, STDOUT_FILENO
, &term_errno
))
1154 switch (term_errno
) {
1156 errx(EXIT_FAILURE
, _("terminfo database cannot be found"));
1158 errx(EXIT_FAILURE
, _("%s: unknown terminal type"), ctl
->opt_te_terminal_name
);
1160 errx(EXIT_FAILURE
, _("terminal is hardcopy"));
1163 /* See if the terminal is a virtual console terminal. */
1164 ctl
->vcterm
= (!strncmp(ctl
->opt_te_terminal_name
, "con", 3) ||
1165 !strncmp(ctl
->opt_te_terminal_name
, "linux", 5));
1169 int main(int argc
, char **argv
)
1171 struct setterm_control ctl
= { NULL
};
1173 setlocale(LC_ALL
, "");
1174 bindtextdomain(PACKAGE
, LOCALEDIR
);
1175 textdomain(PACKAGE
);
1176 close_stdout_atexit();
1179 warnx(_("bad usage"));
1180 errtryhelp(EXIT_FAILURE
);
1182 parse_option(&ctl
, argc
, argv
);
1183 init_terminal(&ctl
);
1184 perform_sequence(&ctl
);
1186 return EXIT_SUCCESS
;