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 */
64 # define NCURSES_CONST const /* define before including term.h */
68 #elif defined(HAVE_NCURSES_NCURSES_H)
69 # include <ncurses/ncurses.h>
71 /* must include after ncurses.h */
74 #ifdef HAVE_LINUX_TIOCL_H
75 # include <linux/tiocl.h>
79 #include "closestream.h"
87 /* Non-standard return values. */
88 #define EXIT_DUMPFILE -1
104 static const char *colornames
[] = {
114 [DEFAULT
] = "default"
117 #define is_valid_color(x) (x >= 0 && (size_t) x < ARRAY_SIZE(colornames))
126 /* <linux/tiocl.h> fallback */
127 #ifndef TIOCL_BLANKSCREEN
129 TIOCL_UNBLANKSCREEN
= 4, /* unblank screen */
130 TIOCL_SETVESABLANK
= 10, /* set vesa blanking mode */
131 TIOCL_BLANKSCREEN
= 14, /* keep screen blank even if a key is pressed */
132 TIOCL_BLANKEDSCREEN
= 15 /* return which vt was blanked */
136 /* Powersave modes */
138 VESA_BLANK_MODE_OFF
= 0,
139 VESA_BLANK_MODE_SUSPENDV
,
140 VESA_BLANK_MODE_SUSPENDH
,
141 VESA_BLANK_MODE_POWERDOWN
144 /* klogctl() actions */
146 SYSLOG_ACTION_CONSOLE_OFF
= 6,
147 SYSLOG_ACTION_CONSOLE_ON
= 7,
148 SYSLOG_ACTION_CONSOLE_LEVEL
= 8
151 /* Console log levels */
153 CONSOLE_LEVEL_MIN
= 0,
154 CONSOLE_LEVEL_MAX
= 8
157 /* Various numbers */
158 #define DEFAULT_TAB_LEN 8
161 #define BLENGTH_MAX 2000
163 /* Command controls. */
164 struct setterm_control
{
165 char *opt_te_terminal_name
; /* terminal name */
166 int opt_bl_min
; /* blank screen */
167 int opt_blength_l
; /* bell duration in milliseconds */
168 int opt_bfreq_f
; /* bell frequency in Hz */
169 int opt_sn_num
; /* console number to be snapshot */
170 char *opt_sn_name
; /* path to write snap */
171 char *in_device
; /* device to snapshot */
172 int opt_msglevel_num
; /* printk() logging level */
173 int opt_ps_mode
; /* powersave mode */
174 int opt_pd_min
; /* powerdown time */
175 int opt_rt_len
; /* regular tab length */
176 int opt_tb_array
[TABS_MAX
+ 1]; /* array for tab list */
178 int opt_fo_color
:4, opt_ba_color
:4, opt_ul_color
:4, opt_hb_color
:4;
179 /* boolean options */
180 unsigned int opt_cu_on
:1, opt_li_on
:1, opt_bo_on
:1, opt_hb_on
:1,
181 opt_bl_on
:1, opt_re_on
:1, opt_un_on
:1, opt_rep_on
:1,
182 opt_appck_on
:1, opt_invsc_on
:1, opt_msg_on
:1, opt_cl_all
:1,
184 /* Option flags. Set when an option is invoked. */
185 uint64_t opt_term
:1, opt_reset
:1, opt_initialize
:1, opt_cursor
:1,
186 opt_linewrap
:1, opt_default
:1, opt_foreground
:1,
187 opt_background
:1, opt_bold
:1, opt_blink
:1, opt_reverse
:1,
188 opt_underline
:1, opt_store
:1, opt_clear
:1, opt_blank
:1,
189 opt_snap
:1, opt_snapfile
:1, opt_append
:1, opt_ulcolor
:1,
190 opt_hbcolor
:1, opt_halfbright
:1, opt_repeat
:1, opt_tabs
:1,
191 opt_clrtabs
:1, opt_regtabs
:1, opt_appcursorkeys
:1,
192 opt_inversescreen
:1, opt_msg
:1, opt_msglevel
:1, opt_powersave
:1,
193 opt_powerdown
:1, opt_blength
:1, opt_bfreq
:1;
196 static int parse_color(const char *arg
)
200 for (i
= 0; i
< ARRAY_SIZE(colornames
); i
++) {
201 if (strcmp(colornames
[i
], arg
) == 0)
208 static int parse_febg_color(const char *arg
)
210 int color
= parse_color(arg
);
213 color
= strtos32_or_err(arg
, _("argument error"));
215 if (!is_valid_color(color
) || color
== GREY
)
216 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
220 static int parse_ulhb_color(char **argv
, int *optind
)
226 if (argv
[*optind
] && strcmp(argv
[*optind
- 1], "bright") == 0) {
228 color_name
= argv
[*optind
];
231 color_name
= argv
[*optind
- 1];
233 color
= parse_color(color_name
);
235 color
= strtos32_or_err(color_name
, _("argument error"));
236 if (!is_valid_color(color
))
237 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), color_name
);
238 if (bright
&& (color
== BLACK
|| color
== GREY
))
239 errx(EXIT_FAILURE
, _("argument error: bright %s is not supported"), color_name
);
244 static char *find_optional_arg(char **argv
, char *optarg
, int *optind
)
251 if (!arg
|| arg
[0] == '-')
258 static int parse_blank(char **argv
, char *optarg
, int *optind
)
262 arg
= find_optional_arg(argv
, optarg
, optind
);
264 return BLANKEDSCREEN
;
265 if (!strcmp(arg
, "force"))
267 else if (!strcmp(arg
, "poke"))
268 return UNBLANKSCREEN
;
272 ret
= strtos32_or_err(arg
, _("argument error"));
273 if (ret
< 0 || BLANK_MAX
< ret
)
274 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 else if (strcmp(arg
, "vsync") == 0)
284 return VESA_BLANK_MODE_SUSPENDV
;
285 else if (strcmp(arg
, "hsync") == 0)
286 return VESA_BLANK_MODE_SUSPENDH
;
287 else if (strcmp(arg
, "powerdown") == 0)
288 return VESA_BLANK_MODE_POWERDOWN
;
289 else if (strcmp(arg
, "off") == 0)
290 return VESA_BLANK_MODE_OFF
;
291 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
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 **argv
, char *optarg
, int *optind
)
309 arg
= find_optional_arg(argv
, optarg
, optind
);
312 ret
= strtos32_or_err(arg
, _("argument error"));
314 errx(EXIT_FAILURE
, "%s: %s", _("argument error"), arg
);
318 static void parse_tabs(char **argv
, char *optarg
, int *optind
, int *tab_array
)
323 tab_array
[i
] = strtos32_or_err(optarg
, _("argument error"));
326 while (argv
[*optind
]) {
328 errx(EXIT_FAILURE
, _("too many tabs"));
329 if (argv
[*optind
][0] == '-')
331 tab_array
[i
] = strtos32_or_err(argv
[*optind
], _("argument error"));
338 static int parse_regtabs(char **argv
, char *optarg
, int *optind
)
343 arg
= find_optional_arg(argv
, optarg
, optind
);
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 **argv
, char *optarg
, int *optind
)
357 arg
= find_optional_arg(argv
, optarg
, optind
);
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 **argv
, char *optarg
, int *optind
)
370 arg
= find_optional_arg(argv
, optarg
, optind
);
373 return strtos32_or_err(arg
, _("argument error"));
376 static void __attribute__((__noreturn__
)) usage(FILE *out
)
378 fputs(USAGE_HEADER
, out
);
380 _(" %s [options]\n"), program_invocation_short_name
);
382 fputs(USAGE_SEPARATOR
, out
);
383 fputs(_("Set the attributes of a terminal.\n"), out
);
385 fputs(USAGE_OPTIONS
, out
);
386 fputs(_(" --term <terminal_name> override TERM environment variable\n"), out
);
387 fputs(_(" --reset reset terminal to power-on state\n"), out
);
388 fputs(_(" --initialize display init string, and use default settings\n"), out
);
389 fputs(_(" --default use default terminal settings\n"), out
);
390 fputs(_(" --store save current terminal settings as default\n"), out
);
391 fputs(_(" --cursor [on|off] display cursor\n"), out
);
392 fputs(_(" --repeat [on|off] keyboard repeat\n"), out
);
393 fputs(_(" --appcursorkeys [on|off] cursor key application mode\n"), out
);
394 fputs(_(" --linewrap [on|off] continue on a new line when a line is full\n"), out
);
395 fputs(_(" --inversescreen [on|off] swap colors for the whole screen\n"), out
);
396 fputs(_(" --foreground default|<color> set foreground color\n"), out
);
397 fputs(_(" --background default|<color> set background color\n"), out
);
398 fputs(_(" --ulcolor [bright] <color> set underlined text color\n"), out
);
399 fputs(_(" --hbcolor [bright] <color> set bold text color\n"), out
);
400 fputs(_(" <color>: black blue cyan green grey magenta red white yellow\n"), out
);
401 fputs(_(" --bold [on|off] bold\n"), out
);
402 fputs(_(" --half-bright [on|off] dim\n"), out
);
403 fputs(_(" --blink [on|off] blink\n"), out
);
404 fputs(_(" --underline [on|off] underline\n"), out
);
405 fputs(_(" --reverse [on|off] swap foreground and background colors\n"), out
);
406 fputs(_(" --clear [all|rest] clear screen and set cursor position\n"), out
);
407 fputs(_(" --tabs [<number>...] set these tab stop positions, or show them\n"), out
);
408 fputs(_(" --clrtabs [<number>...] clear these tab stop positions, or all\n"), out
);
409 fputs(_(" --regtabs [1-160] set a regular tab stop interval\n"), out
);
410 fputs(_(" --blank [0-60|force|poke] set time of inactivity before screen blanks\n"), out
);
411 fputs(_(" --dump [<number>] write vcsa<number> console dump to file\n"), out
);
412 fputs(_(" --append [<number>] append vcsa<number> console dump to file\n"), out
);
413 fputs(_(" --file <filename> name of the dump file\n"), out
);
414 fputs(_(" --msg [on|off] send kernel messages to console\n"), out
);
415 fputs(_(" --msglevel 0-8 kernel console log level\n"), out
);
416 fputs(_(" --powersave [on|vsync|hsync|powerdown|off]\n"), out
);
417 fputs(_(" set vesa powersaving features\n"), out
);
418 fputs(_(" --powerdown [0-60] set vesa powerdown interval in minutes\n"), out
);
419 fputs(_(" --blength [0-2000] duration of the bell in milliseconds\n"), out
);
420 fputs(_(" --bfreq <number> bell frequency in Hertz\n"), out
);
421 fputs(_(" --version show version information and exit\n"), out
);
422 fputs(_(" --help display this help and exit\n"), out
);
423 fprintf(out
, USAGE_MAN_TAIL("setterm(1)"));
424 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
427 static int __attribute__((__pure__
)) set_opt_flag(int opt
)
430 errx(EXIT_FAILURE
, _("duplicate use of an option"));
434 static void parse_option(struct setterm_control
*ctl
, int argc
, char **argv
)
438 OPT_TERM
= CHAR_MAX
+ 1,
474 static const struct option longopts
[] = {
475 {"term", required_argument
, NULL
, OPT_TERM
},
476 {"reset", no_argument
, NULL
, OPT_RESET
},
477 {"initialize", no_argument
, NULL
, OPT_INITIALIZE
},
478 {"cursor", required_argument
, NULL
, OPT_CURSOR
},
479 {"repeat", required_argument
, NULL
, OPT_REPEAT
},
480 {"appcursorkeys", required_argument
, NULL
, OPT_APPCURSORKEYS
},
481 {"linewrap", required_argument
, NULL
, OPT_LINEWRAP
},
482 {"default", no_argument
, NULL
, OPT_DEFAULT
},
483 {"foreground", required_argument
, NULL
, OPT_FOREGROUND
},
484 {"background", required_argument
, NULL
, OPT_BACKGROUND
},
485 {"ulcolor", required_argument
, NULL
, OPT_ULCOLOR
},
486 {"hbcolor", required_argument
, NULL
, OPT_HBCOLOR
},
487 {"inversescreen", required_argument
, NULL
, OPT_INVERSESCREEN
},
488 {"bold", required_argument
, NULL
, OPT_BOLD
},
489 {"half-bright", required_argument
, NULL
, OPT_HALF_BRIGHT
},
490 {"blink", required_argument
, NULL
, OPT_BLINK
},
491 {"reverse", required_argument
, NULL
, OPT_REVERSE
},
492 {"underline", required_argument
, NULL
, OPT_UNDERLINE
},
493 {"store", no_argument
, NULL
, OPT_STORE
},
494 {"clear", required_argument
, NULL
, OPT_CLEAR
},
495 {"tabs", optional_argument
, NULL
, OPT_TABS
},
496 {"clrtabs", optional_argument
, NULL
, OPT_CLRTABS
},
497 {"regtabs", optional_argument
, NULL
, OPT_REGTABS
},
498 {"blank", optional_argument
, NULL
, OPT_BLANK
},
499 {"dump", optional_argument
, NULL
, OPT_DUMP
},
500 {"append", required_argument
, NULL
, OPT_APPEND
},
501 {"file", required_argument
, NULL
, OPT_FILE
},
502 {"msg", required_argument
, NULL
, OPT_MSG
},
503 {"msglevel", required_argument
, NULL
, OPT_MSGLEVEL
},
504 {"powersave", required_argument
, NULL
, OPT_POWERSAVE
},
505 {"powerdown", optional_argument
, NULL
, OPT_POWERDOWN
},
506 {"blength", optional_argument
, NULL
, OPT_BLENGTH
},
507 {"bfreq", optional_argument
, NULL
, OPT_BFREQ
},
508 {"version", no_argument
, NULL
, OPT_VERSION
},
509 {"help", no_argument
, NULL
, OPT_HELP
},
512 static const ul_excl_t excl
[] = {
513 { OPT_DEFAULT
, OPT_STORE
},
514 { OPT_TABS
, OPT_CLRTABS
, OPT_REGTABS
},
515 { OPT_MSG
, OPT_MSGLEVEL
},
518 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
520 while ((c
= getopt_long_only(argc
, argv
, "", longopts
, NULL
)) != -1) {
521 err_exclusive_options(c
, longopts
, excl
, excl_st
);
524 ctl
->opt_term
= set_opt_flag(ctl
->opt_term
);
525 ctl
->opt_te_terminal_name
= optarg
;
528 ctl
->opt_reset
= set_opt_flag(ctl
->opt_reset
);
531 ctl
->opt_initialize
= set_opt_flag(ctl
->opt_initialize
);
534 ctl
->opt_cursor
= set_opt_flag(ctl
->opt_cursor
);
535 ctl
->opt_cu_on
= parse_switch(optarg
, _("argument error"),
539 ctl
->opt_repeat
= set_opt_flag(ctl
->opt_repeat
);
540 ctl
->opt_rep_on
= parse_switch(optarg
, _("argument error"),
543 case OPT_APPCURSORKEYS
:
544 ctl
->opt_appcursorkeys
= set_opt_flag(ctl
->opt_appcursorkeys
);
545 ctl
->opt_appck_on
= parse_switch(optarg
, _("argument error"),
549 ctl
->opt_linewrap
= set_opt_flag(ctl
->opt_linewrap
);
550 ctl
->opt_li_on
= parse_switch(optarg
, _("argument error"),
554 ctl
->opt_default
= set_opt_flag(ctl
->opt_default
);
557 ctl
->opt_foreground
= set_opt_flag(ctl
->opt_foreground
);
558 ctl
->opt_fo_color
= parse_febg_color(optarg
);
561 ctl
->opt_background
= set_opt_flag(ctl
->opt_background
);
562 ctl
->opt_ba_color
= parse_febg_color(optarg
);
565 ctl
->opt_ulcolor
= set_opt_flag(ctl
->opt_ulcolor
);
566 ctl
->opt_ul_color
= parse_ulhb_color(argv
, &optind
);
569 ctl
->opt_hbcolor
= set_opt_flag(ctl
->opt_hbcolor
);
570 ctl
->opt_hb_color
= parse_ulhb_color(argv
, &optind
);
572 case OPT_INVERSESCREEN
:
573 ctl
->opt_inversescreen
= set_opt_flag(ctl
->opt_inversescreen
);
574 ctl
->opt_invsc_on
= parse_switch(optarg
, _("argument error"),
578 ctl
->opt_bold
= set_opt_flag(ctl
->opt_bold
);
579 ctl
->opt_bo_on
= parse_switch(optarg
, _("argument error"),
582 case OPT_HALF_BRIGHT
:
583 ctl
->opt_halfbright
= set_opt_flag(ctl
->opt_halfbright
);
584 ctl
->opt_hb_on
= parse_switch(optarg
, _("argument error"),
588 ctl
->opt_blink
= set_opt_flag(ctl
->opt_blink
);
589 ctl
->opt_bl_on
= parse_switch(optarg
, _("argument error"),
593 ctl
->opt_reverse
= set_opt_flag(ctl
->opt_reverse
);
594 ctl
->opt_re_on
= parse_switch(optarg
, _("argument error"),
598 ctl
->opt_underline
= set_opt_flag(ctl
->opt_underline
);
599 ctl
->opt_un_on
= parse_switch(optarg
, _("argument error"),
603 ctl
->opt_store
= set_opt_flag(ctl
->opt_store
);
606 ctl
->opt_clear
= set_opt_flag(ctl
->opt_clear
);
607 ctl
->opt_cl_all
= parse_switch(optarg
, _("argument error"),
608 "all", "reset", NULL
);
611 ctl
->opt_tabs
= set_opt_flag(ctl
->opt_tabs
);
612 parse_tabs(argv
, optarg
, &optind
, ctl
->opt_tb_array
);
615 ctl
->opt_clrtabs
= set_opt_flag(ctl
->opt_clrtabs
);
616 parse_tabs(argv
, optarg
, &optind
, ctl
->opt_tb_array
);
619 ctl
->opt_regtabs
= set_opt_flag(ctl
->opt_regtabs
);
620 ctl
->opt_rt_len
= parse_regtabs(argv
, optarg
, &optind
);
623 ctl
->opt_blank
= set_opt_flag(ctl
->opt_blank
);
624 ctl
->opt_bl_min
= parse_blank(argv
, optarg
, &optind
);
627 ctl
->opt_snap
= set_opt_flag(ctl
->opt_snap
);
628 ctl
->opt_sn_num
= parse_snap(argv
, optarg
, &optind
);
631 ctl
->opt_append
= set_opt_flag(ctl
->opt_append
);
632 ctl
->opt_sn_num
= parse_snap(argv
, optarg
, &optind
);
635 ctl
->opt_snapfile
= set_opt_flag(ctl
->opt_snapfile
);
636 ctl
->opt_sn_name
= optarg
;
639 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
640 ctl
->opt_msg_on
= parse_switch(optarg
, _("argument error"),
644 ctl
->opt_msglevel
= set_opt_flag(ctl
->opt_msglevel
);
645 ctl
->opt_msglevel_num
= parse_msglevel(optarg
);
646 if (ctl
->opt_msglevel_num
== 0) {
647 ctl
->opt_msg
= set_opt_flag(ctl
->opt_msg
);
648 ctl
->opt_msg_on
|= 1;
652 ctl
->opt_powersave
= set_opt_flag(ctl
->opt_powersave
);
653 ctl
->opt_ps_mode
= parse_powersave(optarg
);
656 ctl
->opt_powerdown
= set_opt_flag(ctl
->opt_powerdown
);
657 ctl
->opt_pd_min
= parse_blank(argv
, optarg
, &optind
);
660 ctl
->opt_blength
= set_opt_flag(ctl
->opt_blength
);
661 ctl
->opt_blength_l
= parse_blength(argv
, optarg
, &optind
);
664 ctl
->opt_bfreq
= set_opt_flag(ctl
->opt_bfreq
);
665 ctl
->opt_bfreq_f
= parse_bfreq(argv
, optarg
, &optind
);
668 printf(UTIL_LINUX_VERSION
);
678 /* Return the specified terminfo string, or an empty string if no such
679 * terminfo capability exists. */
680 static char *ti_entry(const char *name
)
684 if ((buf_ptr
= tigetstr((char *)name
)) == (char *)-1)
689 static void show_tabs(void)
691 int i
, co
= tigetnum("cols");
695 for (i
= 10; i
< co
- 2; i
+= 10)
698 for (i
= 1; i
<= co
; i
++)
699 putchar(i
% 10 + '0');
701 for (i
= 1; i
< co
; i
++)
707 static int open_snapshot_device(struct setterm_control
*ctl
)
712 xasprintf(&ctl
->in_device
, "/dev/vcsa%d", ctl
->opt_sn_num
);
714 xasprintf(&ctl
->in_device
, "/dev/vcsa");
715 fd
= open(ctl
->in_device
, O_RDONLY
);
717 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
721 static void set_blanking(struct setterm_control
*ctl
)
726 if (0 <= ctl
->opt_bl_min
) {
727 printf("\033[9;%d]", ctl
->opt_bl_min
);
730 switch (ctl
->opt_bl_min
) {
732 ioctlarg
= TIOCL_BLANKSCREEN
;
733 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
734 warn(_("cannot force blank"));
737 ioctlarg
= TIOCL_UNBLANKSCREEN
;
738 if (ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
))
739 warn(_("cannot force unblank"));
742 ioctlarg
= TIOCL_BLANKEDSCREEN
;
743 ret
= ioctl(STDIN_FILENO
, TIOCLINUX
, &ioctlarg
);
745 warn(_("cannot get blank status"));
749 default: /* should be impossible to reach */
755 static void screendump(struct setterm_control
*ctl
)
757 unsigned char header
[4];
758 unsigned int rows
, cols
;
763 char *inbuf
, *outbuf
, *p
, *q
;
765 /* open source and destination files */
766 fd
= open_snapshot_device(ctl
);
767 if (!ctl
->opt_sn_name
)
768 ctl
->opt_sn_name
= "screen.dump";
769 out
= fopen(ctl
->opt_sn_name
, ctl
->opt_snap
? "w" : "a");
771 err(EXIT_DUMPFILE
, _("can not open dump file %s for output"), ctl
->opt_sn_name
);
772 /* determine snapshot size */
773 if (read(fd
, header
, 4) != 4)
774 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
777 if (rows
* cols
== 0)
778 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
779 /* allocate buffers */
780 inbuf
= xmalloc(rows
* cols
* 2);
781 outbuf
= xmalloc(rows
* (cols
+ 1));
783 rc
= read(fd
, inbuf
, rows
* cols
* 2);
784 if (rc
< 0 || (size_t)rc
!= rows
* cols
* 2)
785 err(EXIT_DUMPFILE
, _("cannot read %s"), ctl
->in_device
);
788 /* copy inbuf to outbuf */
789 for (i
= 0; i
< rows
; i
++) {
790 for (j
= 0; j
< cols
; j
++) {
794 while (j
-- > 0 && q
[-1] == ' ')
798 fwrite(outbuf
, 1, q
- outbuf
, out
);
799 /* clean up allocations */
803 free(ctl
->in_device
);
804 if (close_stream(out
) != 0)
805 errx(EXIT_FAILURE
, _("write error"));
809 /* Some options are applicable when terminal is virtual console. */
810 static int vc_only(struct setterm_control
*ctl
, const char *err
)
814 warnx(_("terminal %s does not support %s"),
815 ctl
->opt_te_terminal_name
, err
);
820 static void perform_sequence(struct setterm_control
*ctl
)
826 putp(ti_entry("rs1"));
829 if (ctl
->opt_initialize
)
830 putp(ti_entry("is2"));
832 /* -cursor [on|off]. */
833 if (ctl
->opt_cursor
) {
835 putp(ti_entry("cnorm"));
837 putp(ti_entry("civis"));
840 /* -linewrap [on|off]. */
841 if (ctl
->opt_linewrap
)
842 fputs(ctl
->opt_li_on
? "\033[?7h" : "\033[?7l", stdout
);
844 /* -repeat [on|off]. */
845 if (ctl
->opt_repeat
&& vc_only(ctl
, "--repeat"))
846 fputs(ctl
->opt_rep_on
? "\033[?8h" : "\033[?8l", stdout
);
848 /* -appcursorkeys [on|off]. */
849 if (ctl
->opt_appcursorkeys
&& vc_only(ctl
, "--appcursorkeys"))
850 fputs(ctl
->opt_appck_on
? "\033[?1h" : "\033[?1l", stdout
);
852 /* -default. Vc sets default rendition, otherwise clears all
854 if (ctl
->opt_default
) {
855 if (vc_only(ctl
, NULL
))
858 putp(ti_entry("sgr0"));
861 /* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
862 if (ctl
->opt_foreground
)
863 printf("\033[3%c%s", '0' + ctl
->opt_fo_color
, "m");
865 /* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
866 if (ctl
->opt_background
)
867 printf("\033[4%c%s", '0' + ctl
->opt_ba_color
, "m");
869 /* -ulcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
870 if (ctl
->opt_ulcolor
&& vc_only(ctl
, "--ulcolor"))
871 printf("\033[1;%d]", ctl
->opt_ul_color
);
873 /* -hbcolor black|red|green|yellow|blue|magenta|cyan|white|default. */
874 if (ctl
->opt_hbcolor
)
875 printf("\033[2;%d]", ctl
->opt_hb_color
);
877 /* -inversescreen [on|off]. */
878 if (ctl
->opt_inversescreen
)
879 fputs(ctl
->opt_invsc_on
? "\033[?5h" : "\033[?5l", stdout
);
881 /* -bold [on|off]. Vc behaves as expected, otherwise off turns off
885 putp(ti_entry("bold"));
887 if (vc_only(ctl
, NULL
))
888 fputs("\033[22m", stdout
);
890 putp(ti_entry("sgr0"));
894 /* -half-bright [on|off]. Vc behaves as expected, otherwise off
895 * turns off all attributes. */
896 if (ctl
->opt_halfbright
) {
898 putp(ti_entry("dim"));
900 if (vc_only(ctl
, NULL
))
901 fputs("\033[22m", stdout
);
903 putp(ti_entry("sgr0"));
907 /* -blink [on|off]. Vc behaves as expected, otherwise off turns off
909 if (ctl
->opt_blink
) {
911 putp(ti_entry("blink"));
913 if (vc_only(ctl
, NULL
))
914 fputs("\033[25m", stdout
);
916 putp(ti_entry("sgr0"));
920 /* -reverse [on|off]. Vc behaves as expected, otherwise off turns
921 * off all attributes. */
922 if (ctl
->opt_reverse
) {
924 putp(ti_entry("rev"));
926 if (vc_only(ctl
, NULL
))
927 fputs("\033[27m", stdout
);
929 putp(ti_entry("sgr0"));
933 /* -underline [on|off]. */
934 if (ctl
->opt_underline
)
935 putp(ti_entry(ctl
->opt_un_on
? "smul" : "rmul"));
938 if (ctl
->opt_store
&& vc_only(ctl
, "--store"))
939 fputs("\033[8]", stdout
);
941 /* -clear [all|rest]. */
943 putp(ti_entry(ctl
->opt_cl_all
? "clear" : "ed"));
947 if (ctl
->opt_tb_array
[0] == -1)
952 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
953 printf("\033[%dG\033H", ctl
->opt_tb_array
[i
]);
959 if (ctl
->opt_clrtabs
&& vc_only(ctl
, "--clrtabs")) {
962 if (ctl
->opt_tb_array
[0] == -1)
963 fputs("\033[3g", stdout
);
965 for (i
= 0; ctl
->opt_tb_array
[i
] > 0; i
++)
966 printf("\033[%dG\033[g", ctl
->opt_tb_array
[i
]);
971 if (ctl
->opt_regtabs
&& vc_only(ctl
, "--regtabs")) {
974 fputs("\033[3g\r", stdout
);
975 for (i
= ctl
->opt_rt_len
+ 1; i
<= TABS_MAX
; i
+= ctl
->opt_rt_len
)
976 printf("\033[%dC\033H", ctl
->opt_rt_len
);
981 if (ctl
->opt_blank
&& vc_only(ctl
, "--blank"))
984 /* -powersave [on|vsync|hsync|powerdown|off] (console) */
985 if (ctl
->opt_powersave
) {
987 ioctlarg
[0] = TIOCL_SETVESABLANK
;
988 ioctlarg
[1] = ctl
->opt_ps_mode
;
989 if (ioctl(STDIN_FILENO
, TIOCLINUX
, ioctlarg
))
990 warn(_("cannot (un)set powersave mode"));
993 /* -powerdown [0-60]. */
994 if (ctl
->opt_powerdown
)
995 printf("\033[14;%d]", ctl
->opt_pd_min
);
997 /* -snap [1-NR_CONS]. */
998 if (ctl
->opt_snap
|| ctl
->opt_append
)
1001 /* -msg [on|off]. Controls printk's to console. */
1002 if (ctl
->opt_msg
&& vc_only(ctl
, "--msg")) {
1003 if (ctl
->opt_msg_on
)
1004 result
= klogctl(SYSLOG_ACTION_CONSOLE_ON
, NULL
, 0);
1006 result
= klogctl(SYSLOG_ACTION_CONSOLE_OFF
, NULL
, 0);
1009 warn(_("klogctl error"));
1012 /* -msglevel [0-8]. Console printk message level. */
1013 if (ctl
->opt_msglevel_num
&& vc_only(ctl
, "--msglevel")) {
1015 klogctl(SYSLOG_ACTION_CONSOLE_LEVEL
, NULL
,
1016 ctl
->opt_msglevel_num
);
1018 warn(_("klogctl error"));
1021 /* -blength [0-2000] */
1022 if (ctl
->opt_blength
&& vc_only(ctl
, "--blength")) {
1023 printf("\033[11;%d]", ctl
->opt_blength_l
);
1026 /* -bfreq freqnumber */
1027 if (ctl
->opt_bfreq
&& vc_only(ctl
, "--bfreq")) {
1028 printf("\033[10;%d]", ctl
->opt_bfreq_f
);
1032 static void init_terminal(struct setterm_control
*ctl
)
1036 if (!ctl
->opt_te_terminal_name
) {
1037 ctl
->opt_te_terminal_name
= getenv("TERM");
1038 if (ctl
->opt_te_terminal_name
== NULL
)
1039 errx(EXIT_FAILURE
, _("$TERM is not defined."));
1042 /* Find terminfo entry. */
1043 if (setupterm(ctl
->opt_te_terminal_name
, STDOUT_FILENO
, &term_errno
))
1044 switch (term_errno
) {
1046 errx(EXIT_FAILURE
, _("terminfo database cannot be found"));
1048 errx(EXIT_FAILURE
, _("%s: unknown terminal type"), ctl
->opt_te_terminal_name
);
1050 errx(EXIT_FAILURE
, _("terminal is hardcopy"));
1053 /* See if the terminal is a virtual console terminal. */
1054 ctl
->vcterm
= (!strncmp(ctl
->opt_te_terminal_name
, "con", 3) ||
1055 !strncmp(ctl
->opt_te_terminal_name
, "linux", 5));
1059 int main(int argc
, char **argv
)
1061 struct setterm_control ctl
= { 0 };
1063 setlocale(LC_ALL
, "");
1064 bindtextdomain(PACKAGE
, LOCALEDIR
);
1065 textdomain(PACKAGE
);
1066 atexit(close_stdout
);
1071 parse_option(&ctl
, argc
, argv
);
1072 init_terminal(&ctl
);
1073 perform_sequence(&ctl
);
1075 return EXIT_SUCCESS
;