(root)/
util-linux-2.39/
term-utils/
setterm.c
       1  /* setterm.c, set terminal attributes.
       2   *
       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.
       6   *
       7   * Adaption to Linux by Peter MacDonald.
       8   *
       9   * Enhancements by Mika Liljeberg (liljeber@cs.Helsinki.FI)
      10   *
      11   * Beep modifications by Christophe Jolif (cjolif@storm.gatelink.fr.net)
      12   *
      13   * Sanity increases by Cafeine Addict [sic].
      14   *
      15   * Powersave features by todd j. derr <tjd@wordsmith.org>
      16   *
      17   * Converted to terminfo by Kars de Jong (jongk@cs.utwente.nl)
      18   *
      19   * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
      20   * - added Native Language Support
      21   *
      22   * Semantics:
      23   *
      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
      31   * ignored.
      32   *
      33   * The following options are non-obvious.
      34   *
      35   *   -term can be used to override the TERM environment variable.
      36   *
      37   *   -reset displays the terminal reset string, which typically resets the
      38   *      terminal to its power on state.
      39   *
      40   *   -initialize displays the terminal initialization string, which typically
      41   *      sets the terminal's rendering options, and other attributes to the
      42   *      default values.
      43   *
      44   *   -default sets the terminal's rendering options to the default values.
      45   *
      46   *   -store stores the terminal's current rendering options as the default
      47   *      values.  */
      48  
      49  #include <ctype.h>
      50  #include <errno.h>
      51  #include <fcntl.h>
      52  #include <getopt.h>
      53  #include <stdio.h>
      54  #include <stdlib.h>
      55  #include <string.h>
      56  #include <sys/ioctl.h>
      57  #include <sys/klog.h>
      58  #include <sys/param.h>		/* for MAXPATHLEN */
      59  #include <sys/time.h>
      60  #include <termios.h>
      61  #include <unistd.h>
      62  
      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)
      68  # include <term.h>
      69  #endif
      70  
      71  #ifdef HAVE_LINUX_TIOCL_H
      72  # include <linux/tiocl.h>
      73  #endif
      74  
      75  #include "all-io.h"
      76  #include "c.h"
      77  #include "closestream.h"
      78  #include "nls.h"
      79  #include "optutils.h"
      80  #include "strutils.h"
      81  #include "xalloc.h"
      82  
      83  /* Constants. */
      84  
      85  /* Non-standard return values. */
      86  #define EXIT_DUMPFILE	-1
      87  
      88  /* Colors. */
      89  enum {
      90  	BLACK = 0,
      91  	RED,
      92  	GREEN,
      93  	YELLOW,
      94  	BLUE,
      95  	MAGENTA,
      96  	CYAN,
      97  	WHITE,
      98  	GREY,
      99  	DEFAULT
     100  };
     101  
     102  static const char *colornames[] = {
     103  	[BLACK] = "black",
     104  	[RED]	= "red",
     105  	[GREEN]	= "green",
     106  	[YELLOW]= "yellow",
     107  	[BLUE]	= "blue",
     108  	[MAGENTA]="magenta",
     109  	[CYAN]	= "cyan",
     110  	[WHITE]	= "white",
     111  	[GREY]	= "grey",
     112  	[DEFAULT] = "default"
     113  };
     114  
     115  #define is_valid_color(x)	(x >= 0 && (size_t) x < ARRAY_SIZE(colornames))
     116  
     117  /* Blank commands */
     118  enum {
     119  	BLANKSCREEN	= -1,
     120  	UNBLANKSCREEN	= -2,
     121  	BLANKEDSCREEN	= -3
     122  };
     123  
     124  /* <linux/tiocl.h> fallback */
     125  #ifndef TIOCL_BLANKSCREEN
     126  enum {
     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 */
     131  };
     132  #endif
     133  
     134  /* Powersave modes */
     135  enum {
     136  	VESA_BLANK_MODE_OFF = 0,
     137  	VESA_BLANK_MODE_SUSPENDV,
     138  	VESA_BLANK_MODE_SUSPENDH,
     139  	VESA_BLANK_MODE_POWERDOWN
     140  };
     141  
     142  /* klogctl() actions */
     143  enum {
     144  	SYSLOG_ACTION_CONSOLE_OFF	= 6,
     145  	SYSLOG_ACTION_CONSOLE_ON	= 7,
     146  	SYSLOG_ACTION_CONSOLE_LEVEL	= 8
     147  };
     148  
     149  /* Console log levels */
     150  enum {
     151  	CONSOLE_LEVEL_MIN = 0,
     152  	CONSOLE_LEVEL_MAX = 8
     153  };
     154  
     155  /* Various numbers  */
     156  #define DEFAULT_TAB_LEN	8
     157  #define	BLANK_MAX	60
     158  #define	TABS_MAX	160
     159  #define BLENGTH_MAX	2000
     160  
     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 */
     175  	/* colors */
     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,
     181  	    vcterm: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;
     192  };
     193  
     194  static int parse_color(const char *arg)
     195  {
     196  	size_t i;
     197  
     198  	for (i = 0; i < ARRAY_SIZE(colornames); i++) {
     199  		if (strcmp(colornames[i], arg) == 0)
     200  			return i;
     201  	}
     202  
     203  	return -EINVAL;
     204  }
     205  
     206  static int parse_febg_color(const char *arg)
     207  {
     208  	int color = parse_color(arg);
     209  
     210  	if (color < 0)
     211  		color = strtos32_or_err(arg, _("argument error"));
     212  
     213  	if (!is_valid_color(color) || color == GREY)
     214  		errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
     215  	return color;
     216  }
     217  
     218  static int parse_ulhb_color(char **av, int *oi)
     219  {
     220  	char *color_name;
     221  	int bright = 0;
     222  	int color = -1;
     223  
     224  	if (av[*oi] && strcmp(av[*oi - 1], "bright") == 0) {
     225  		bright = 1;
     226  		color_name = av[*oi];
     227  		(*oi)++;
     228  	} else
     229  		color_name = av[*oi - 1];
     230  
     231  	color = parse_color(color_name);
     232  	if (color < 0)
     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);
     238  
     239  	if (bright)
     240  		color |= 8;
     241  
     242  	return color;
     243  }
     244  
     245  static char *find_optional_arg(char **av, char *oa, int *oi)
     246  {
     247  	char *arg;
     248  	if (oa)
     249  		return oa;
     250  
     251  	arg = av[*oi];
     252  	if (!arg || arg[0] == '-')
     253  		return NULL;
     254  
     255  	(*oi)++;
     256  	return arg;
     257  }
     258  
     259  static int parse_blank(char **av, char *oa, int *oi)
     260  {
     261  	char *arg;
     262  
     263  	arg = find_optional_arg(av, oa, oi);
     264  	if (!arg)
     265  		return BLANKEDSCREEN;
     266  	if (!strcmp(arg, "force"))
     267  		return BLANKSCREEN;
     268  	if (!strcmp(arg, "poke"))
     269  		return UNBLANKSCREEN;
     270  
     271  	int ret;
     272  
     273  	ret = strtos32_or_err(arg, _("argument error"));
     274  	if (ret < 0 || BLANK_MAX < ret)
     275  		errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
     276  	return ret;
     277  }
     278  
     279  static int parse_powersave(const char *arg)
     280  {
     281  	if (strcmp(arg, "on") == 0)
     282  		return VESA_BLANK_MODE_SUSPENDV;
     283  	if (strcmp(arg, "vsync") == 0)
     284  		return VESA_BLANK_MODE_SUSPENDV;
     285  	if (strcmp(arg, "hsync") == 0)
     286  		return VESA_BLANK_MODE_SUSPENDH;
     287  	if (strcmp(arg, "powerdown") == 0)
     288  		return VESA_BLANK_MODE_POWERDOWN;
     289  	if (strcmp(arg, "off") == 0)
     290  		return VESA_BLANK_MODE_OFF;
     291  	errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
     292  }
     293  
     294  static int parse_msglevel(const char *arg)
     295  {
     296  	int ret;
     297  
     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);
     301  	return ret;
     302  }
     303  
     304  static int parse_snap(char **av, char *oa, int *oi)
     305  {
     306  	int ret;
     307  	char *arg;
     308  
     309  	arg = find_optional_arg(av, oa, oi);
     310  	if (!arg)
     311  		return 0;
     312  	ret = strtos32_or_err(arg, _("argument error"));
     313  	if (ret < 1)
     314  		errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
     315  	return ret;
     316  }
     317  
     318  static void parse_tabs(char **av, char *oa, int *oi, int *tab_array)
     319  {
     320  	int i = 0;
     321  
     322  	if (oa) {
     323  		tab_array[i] = strtos32_or_err(oa, _("argument error"));
     324  		i++;
     325  	}
     326  	while (av[*oi]) {
     327  		if (TABS_MAX < i)
     328  			errx(EXIT_FAILURE, _("too many tabs"));
     329  		if (av[*oi][0] == '-')
     330  			break;
     331  		tab_array[i] = strtos32_or_err(av[*oi], _("argument error"));
     332  		(*oi)++;
     333  		i++;
     334  	}
     335  	tab_array[i] = -1;
     336  }
     337  
     338  static int parse_regtabs(char **av, char *oa, int *oi)
     339  {
     340  	int ret;
     341  	char *arg;
     342  
     343  	arg = find_optional_arg(av, oa, oi);
     344  	if (!arg)
     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);
     349  	return ret;
     350  }
     351  
     352  static int parse_blength(char **av, char *oa, int *oi)
     353  {
     354  	int ret = -1;
     355  	char *arg;
     356  
     357  	arg = find_optional_arg(av, oa, oi);
     358  	if (!arg)
     359  		return 0;
     360  	ret = strtos32_or_err(arg, _("argument error"));
     361  	if (ret < 0 || BLENGTH_MAX < ret)
     362  		errx(EXIT_FAILURE, "%s: %s", _("argument error"), arg);
     363  	return ret;
     364  }
     365  
     366  static int parse_bfreq(char **av, char *oa, int *oi)
     367  {
     368  	char *arg;
     369  
     370  	arg = find_optional_arg(av, oa, oi);
     371  	if (!arg)
     372  		return 0;
     373  	return strtos32_or_err(arg, _("argument error"));
     374  }
     375  
     376  static void __attribute__((__noreturn__)) usage(void)
     377  {
     378  	FILE *out = stdout;
     379  	fputs(USAGE_HEADER, out);
     380  	fprintf(out,
     381  	      _(" %s [options]\n"), program_invocation_short_name);
     382  
     383  	fputs(USAGE_SEPARATOR, out);
     384  	fputs(_("Set the attributes of a terminal.\n"), out);
     385  
     386  	fputs(USAGE_OPTIONS, out);
     387  	fputs(_(" --term <terminal_name>        override TERM environment variable\n"), out);
     388  	fputs(_(" --reset                       reset terminal to power-on state\n"), out);
     389  	fputs(_(" --resize                      reset terminal rows and columns\n"), out);
     390  	fputs(_(" --initialize                  display init string, and use default settings\n"), out);
     391  	fputs(_(" --default                     use default terminal settings\n"), out);
     392  	fputs(_(" --store                       save current terminal settings as default\n"), out);
     393  	fputs(USAGE_SEPARATOR, out);
     394  
     395  	fputs(_(" --cursor on|off               display cursor\n"), out);
     396  	fputs(_(" --repeat on|off               keyboard repeat\n"), out);
     397  	fputs(_(" --appcursorkeys on|off        cursor key application mode\n"), out);
     398  	fputs(_(" --linewrap on|off             continue on a new line when a line is full\n"), out);
     399  	fputs(_(" --inversescreen on|off        swap colors for the whole screen\n"), out);
     400  	fputs(USAGE_SEPARATOR, out);
     401  
     402  	fputs(_(" --msg on|off                  send kernel messages to console\n"), out);
     403  	fputs(_(" --msglevel <0-8>              kernel console log level\n"), out);
     404  	fputs(USAGE_SEPARATOR, out);
     405  
     406  	fputs(_(" --foreground default|<color>  set foreground color\n"), out);
     407  	fputs(_(" --background default|<color>  set background color\n"), out);
     408  	fputs(_(" --ulcolor [bright] <color>    set underlined text color\n"), out);
     409  	fputs(_(" --hbcolor [bright] <color>    set half-bright text color\n"), out);
     410  	fputs(_("        <color>: black blue cyan green grey magenta red white yellow\n"), out);
     411  	fputs(USAGE_SEPARATOR, out);
     412  
     413  	fputs(_(" --bold on|off                 bold\n"), out);
     414  	fputs(_(" --half-bright on|off          dim\n"), out);
     415  	fputs(_(" --blink on|off                blink\n"), out);
     416  	fputs(_(" --underline on|off            underline\n"), out);
     417  	fputs(_(" --reverse  on|off             swap foreground and background colors\n"), out);
     418  	fputs(USAGE_SEPARATOR, out);
     419  
     420  	fputs(_(" --clear[=<all|rest>]          clear screen and set cursor position\n"), out);
     421  	fputs(_(" --tabs[=<number>...]          set these tab stop positions, or show them\n"), out);
     422  	fputs(_(" --clrtabs[=<number>...]       clear these tab stop positions, or all\n"), out);
     423  	fputs(_(" --regtabs[=1-160]             set a regular tab stop interval\n"), out);
     424  	fputs(_(" --blank[=0-60|force|poke]     set time of inactivity before screen blanks\n"), out);
     425  	fputs(USAGE_SEPARATOR, out);
     426  
     427  	fputs(_(" --dump[=<number>]             write vcsa<number> console dump to file\n"), out);
     428  	fputs(_(" --append <number>             append vcsa<number> console dump to file\n"), out);
     429  	fputs(_(" --file <filename>             name of the dump file\n"), out);
     430  	fputs(USAGE_SEPARATOR, out);
     431  
     432  	fputs(_(" --powersave on|vsync|hsync|powerdown|off\n"), out);
     433  	fputs(_("                               set vesa powersaving features\n"), out);
     434  	fputs(_(" --powerdown[=<0-60>]          set vesa powerdown interval in minutes\n"), out);
     435  	fputs(USAGE_SEPARATOR, out);
     436  
     437  	fputs(_(" --blength[=<0-2000>]          duration of the bell in milliseconds\n"), out);
     438  	fputs(_(" --bfreq[=<number>]            bell frequency in Hertz\n"), out);
     439  
     440  	fputs(USAGE_SEPARATOR, out);
     441  	printf( " --help                        %s\n", USAGE_OPTSTR_HELP);
     442  	printf( " --version                     %s\n", USAGE_OPTSTR_VERSION);
     443  
     444  	printf(USAGE_MAN_TAIL("setterm(1)"));
     445  	exit(EXIT_SUCCESS);
     446  }
     447  
     448  static int __attribute__((__pure__)) set_opt_flag(int opt)
     449  {
     450  	if (opt)
     451  		errx(EXIT_FAILURE, _("duplicate use of an option"));
     452  	return 1;
     453  }
     454  
     455  static void parse_option(struct setterm_control *ctl, int ac, char **av)
     456  {
     457  	int c;
     458  	enum {
     459  		OPT_TERM = CHAR_MAX + 1,
     460  		OPT_RESET,
     461  		OPT_RESIZE,
     462  		OPT_INITIALIZE,
     463  		OPT_CURSOR,
     464  		OPT_REPEAT,
     465  		OPT_APPCURSORKEYS,
     466  		OPT_LINEWRAP,
     467  		OPT_DEFAULT,
     468  		OPT_FOREGROUND,
     469  		OPT_BACKGROUND,
     470  		OPT_ULCOLOR,
     471  		OPT_HBCOLOR,
     472  		OPT_INVERSESCREEN,
     473  		OPT_BOLD,
     474  		OPT_HALF_BRIGHT,
     475  		OPT_BLINK,
     476  		OPT_REVERSE,
     477  		OPT_UNDERLINE,
     478  		OPT_STORE,
     479  		OPT_CLEAR,
     480  		OPT_TABS,
     481  		OPT_CLRTABS,
     482  		OPT_REGTABS,
     483  		OPT_BLANK,
     484  		OPT_DUMP,
     485  		OPT_APPEND,
     486  		OPT_FILE,
     487  		OPT_MSG,
     488  		OPT_MSGLEVEL,
     489  		OPT_POWERSAVE,
     490  		OPT_POWERDOWN,
     491  		OPT_BLENGTH,
     492  		OPT_BFREQ,
     493  		OPT_VERSION,
     494  		OPT_HELP
     495  	};
     496  	static const struct option longopts[] = {
     497  		{"term", required_argument, NULL, OPT_TERM},
     498  		{"reset", no_argument, NULL, OPT_RESET},
     499  		{"resize", no_argument, NULL, OPT_RESIZE},
     500  		{"initialize", no_argument, NULL, OPT_INITIALIZE},
     501  		{"cursor", required_argument, NULL, OPT_CURSOR},
     502  		{"repeat", required_argument, NULL, OPT_REPEAT},
     503  		{"appcursorkeys", required_argument, NULL, OPT_APPCURSORKEYS},
     504  		{"linewrap", required_argument, NULL, OPT_LINEWRAP},
     505  		{"default", no_argument, NULL, OPT_DEFAULT},
     506  		{"foreground", required_argument, NULL, OPT_FOREGROUND},
     507  		{"background", required_argument, NULL, OPT_BACKGROUND},
     508  		{"ulcolor", required_argument, NULL, OPT_ULCOLOR},
     509  		{"hbcolor", required_argument, NULL, OPT_HBCOLOR},
     510  		{"inversescreen", required_argument, NULL, OPT_INVERSESCREEN},
     511  		{"bold", required_argument, NULL, OPT_BOLD},
     512  		{"half-bright", required_argument, NULL, OPT_HALF_BRIGHT},
     513  		{"blink", required_argument, NULL, OPT_BLINK},
     514  		{"reverse", required_argument, NULL, OPT_REVERSE},
     515  		{"underline", required_argument, NULL, OPT_UNDERLINE},
     516  		{"store", no_argument, NULL, OPT_STORE},
     517  		{"clear", optional_argument, NULL, OPT_CLEAR},
     518  		{"tabs", optional_argument, NULL, OPT_TABS},
     519  		{"clrtabs", optional_argument, NULL, OPT_CLRTABS},
     520  		{"regtabs", optional_argument, NULL, OPT_REGTABS},
     521  		{"blank", optional_argument, NULL, OPT_BLANK},
     522  		{"dump", optional_argument, NULL, OPT_DUMP},
     523  		{"append", required_argument, NULL, OPT_APPEND},
     524  		{"file", required_argument, NULL, OPT_FILE},
     525  		{"msg", required_argument, NULL, OPT_MSG},
     526  		{"msglevel", required_argument, NULL, OPT_MSGLEVEL},
     527  		{"powersave", required_argument, NULL, OPT_POWERSAVE},
     528  		{"powerdown", optional_argument, NULL, OPT_POWERDOWN},
     529  		{"blength", optional_argument, NULL, OPT_BLENGTH},
     530  		{"bfreq", optional_argument, NULL, OPT_BFREQ},
     531  		{"version", no_argument, NULL, OPT_VERSION},
     532  		{"help", no_argument, NULL, OPT_HELP},
     533  		{NULL, 0, NULL, 0}
     534  	};
     535  	static const ul_excl_t excl[] = {
     536  		{ OPT_DEFAULT, OPT_STORE },
     537  		{ OPT_TABS, OPT_CLRTABS, OPT_REGTABS },
     538  		{ OPT_MSG, OPT_MSGLEVEL },
     539  		{ 0 }
     540  	};
     541  	int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
     542  
     543  	while ((c = getopt_long_only(ac, av, "", longopts, NULL)) != -1) {
     544  		err_exclusive_options(c, longopts, excl, excl_st);
     545  		switch (c) {
     546  		case OPT_TERM:
     547  			ctl->opt_term = set_opt_flag(ctl->opt_term);
     548  			ctl->opt_te_terminal_name = optarg;
     549  			break;
     550  		case OPT_RESET:
     551  			ctl->opt_reset = set_opt_flag(ctl->opt_reset);
     552  			break;
     553  		case OPT_RESIZE:
     554  			ctl->opt_resize = set_opt_flag(ctl->opt_resize);
     555  			break;
     556  		case OPT_INITIALIZE:
     557  			ctl->opt_initialize = set_opt_flag(ctl->opt_initialize);
     558  			break;
     559  		case OPT_CURSOR:
     560  			ctl->opt_cursor = set_opt_flag(ctl->opt_cursor);
     561  			ctl->opt_cu_on = parse_switch(optarg, _("argument error"),
     562  						"on", "off", NULL);
     563  			break;
     564  		case OPT_REPEAT:
     565  			ctl->opt_repeat = set_opt_flag(ctl->opt_repeat);
     566  			ctl->opt_rep_on = parse_switch(optarg, _("argument error"),
     567  						"on", "off", NULL);
     568  			break;
     569  		case OPT_APPCURSORKEYS:
     570  			ctl->opt_appcursorkeys = set_opt_flag(ctl->opt_appcursorkeys);
     571  			ctl->opt_appck_on = parse_switch(optarg, _("argument error"),
     572  						"on", "off", NULL);
     573  			break;
     574  		case OPT_LINEWRAP:
     575  			ctl->opt_linewrap = set_opt_flag(ctl->opt_linewrap);
     576  			ctl->opt_li_on = parse_switch(optarg, _("argument error"),
     577  						"on", "off", NULL);
     578  			break;
     579  		case OPT_DEFAULT:
     580  			ctl->opt_default = set_opt_flag(ctl->opt_default);
     581  			break;
     582  		case OPT_FOREGROUND:
     583  			ctl->opt_foreground = set_opt_flag(ctl->opt_foreground);
     584  			ctl->opt_fo_color = parse_febg_color(optarg);
     585  			break;
     586  		case OPT_BACKGROUND:
     587  			ctl->opt_background = set_opt_flag(ctl->opt_background);
     588  			ctl->opt_ba_color = parse_febg_color(optarg);
     589  			break;
     590  		case OPT_ULCOLOR:
     591  			ctl->opt_ulcolor = set_opt_flag(ctl->opt_ulcolor);
     592  			ctl->opt_ul_color = parse_ulhb_color(av, &optind);
     593  			break;
     594  		case OPT_HBCOLOR:
     595  			ctl->opt_hbcolor = set_opt_flag(ctl->opt_hbcolor);
     596  			ctl->opt_hb_color = parse_ulhb_color(av, &optind);
     597  			break;
     598  		case OPT_INVERSESCREEN:
     599  			ctl->opt_inversescreen = set_opt_flag(ctl->opt_inversescreen);
     600  			ctl->opt_invsc_on = parse_switch(optarg, _("argument error"),
     601  						"on", "off", NULL);
     602  			break;
     603  		case OPT_BOLD:
     604  			ctl->opt_bold = set_opt_flag(ctl->opt_bold);
     605  			ctl->opt_bo_on = parse_switch(optarg, _("argument error"),
     606  						"on", "off", NULL);
     607  			break;
     608  		case OPT_HALF_BRIGHT:
     609  			ctl->opt_halfbright = set_opt_flag(ctl->opt_halfbright);
     610  			ctl->opt_hb_on = parse_switch(optarg, _("argument error"),
     611  						"on", "off", NULL);
     612  			break;
     613  		case OPT_BLINK:
     614  			ctl->opt_blink = set_opt_flag(ctl->opt_blink);
     615  			ctl->opt_bl_on = parse_switch(optarg, _("argument error"),
     616  						"on", "off", NULL);
     617  			break;
     618  		case OPT_REVERSE:
     619  			ctl->opt_reverse = set_opt_flag(ctl->opt_reverse);
     620  			ctl->opt_re_on = parse_switch(optarg, _("argument error"),
     621  						"on", "off", NULL);
     622  			break;
     623  		case OPT_UNDERLINE:
     624  			ctl->opt_underline = set_opt_flag(ctl->opt_underline);
     625  			ctl->opt_un_on = parse_switch(optarg, _("argument error"),
     626  						"on", "off", NULL);
     627  			break;
     628  		case OPT_STORE:
     629  			ctl->opt_store = set_opt_flag(ctl->opt_store);
     630  			break;
     631  		case OPT_CLEAR:
     632  			ctl->opt_clear = set_opt_flag(ctl->opt_clear);
     633  			if (optarg)
     634  				ctl->opt_cl_all = parse_switch(optarg, _("argument error"),
     635  						"all", "rest", NULL);
     636  			else
     637  				ctl->opt_cl_all = 1;
     638  			break;
     639  		case OPT_TABS:
     640  			ctl->opt_tabs = set_opt_flag(ctl->opt_tabs);
     641  			parse_tabs(av, optarg, &optind, ctl->opt_tb_array);
     642  			break;
     643  		case OPT_CLRTABS:
     644  			ctl->opt_clrtabs = set_opt_flag(ctl->opt_clrtabs);
     645  			parse_tabs(av, optarg, &optind, ctl->opt_tb_array);
     646  			break;
     647  		case OPT_REGTABS:
     648  			ctl->opt_regtabs = set_opt_flag(ctl->opt_regtabs);
     649  			ctl->opt_rt_len = parse_regtabs(av, optarg, &optind);
     650  			break;
     651  		case OPT_BLANK:
     652  			ctl->opt_blank = set_opt_flag(ctl->opt_blank);
     653  			ctl->opt_bl_min = parse_blank(av, optarg, &optind);
     654  			break;
     655  		case OPT_DUMP:
     656  			ctl->opt_snap = set_opt_flag(ctl->opt_snap);
     657  			ctl->opt_sn_num = parse_snap(av, optarg, &optind);
     658  			break;
     659  		case OPT_APPEND:
     660  			ctl->opt_append = set_opt_flag(ctl->opt_append);
     661  			ctl->opt_sn_num = parse_snap(av, optarg, &optind);
     662  			break;
     663  		case OPT_FILE:
     664  			ctl->opt_snapfile = set_opt_flag(ctl->opt_snapfile);
     665  			ctl->opt_sn_name = optarg;
     666  			break;
     667  		case OPT_MSG:
     668  			ctl->opt_msg = set_opt_flag(ctl->opt_msg);
     669  			ctl->opt_msg_on = parse_switch(optarg, _("argument error"),
     670  						"on", "off", NULL);
     671  			break;
     672  		case OPT_MSGLEVEL:
     673  			ctl->opt_msglevel = set_opt_flag(ctl->opt_msglevel);
     674  			ctl->opt_msglevel_num = parse_msglevel(optarg);
     675  			if (ctl->opt_msglevel_num == 0) {
     676  				ctl->opt_msg = set_opt_flag(ctl->opt_msg);
     677  				ctl->opt_msg_on |= 1;
     678  			}
     679  			break;
     680  		case OPT_POWERSAVE:
     681  			ctl->opt_powersave = set_opt_flag(ctl->opt_powersave);
     682  			ctl->opt_ps_mode = parse_powersave(optarg);
     683  			break;
     684  		case OPT_POWERDOWN:
     685  			ctl->opt_powerdown = set_opt_flag(ctl->opt_powerdown);
     686  			ctl->opt_pd_min = parse_blank(av, optarg, &optind);
     687  			break;
     688  		case OPT_BLENGTH:
     689  			ctl->opt_blength = set_opt_flag(ctl->opt_blength);
     690  			ctl->opt_blength_l = parse_blength(av, optarg, &optind);
     691  			break;
     692  		case OPT_BFREQ:
     693  			ctl->opt_bfreq = set_opt_flag(ctl->opt_bfreq);
     694  			ctl->opt_bfreq_f = parse_bfreq(av, optarg, &optind);
     695  			break;
     696  
     697  		case OPT_VERSION:
     698  			print_version(EXIT_SUCCESS);
     699  		case OPT_HELP:
     700  			usage();
     701  		default:
     702  			errtryhelp(EXIT_FAILURE);
     703  		}
     704  	}
     705  }
     706  
     707  /* Return the specified terminfo string, or an empty string if no such
     708   * terminfo capability exists.  */
     709  static char *ti_entry(const char *name)
     710  {
     711  	char *buf_ptr;
     712  
     713  	if ((buf_ptr = tigetstr(name)) == (char *)-1)
     714  		buf_ptr = NULL;
     715  	return buf_ptr;
     716  }
     717  
     718  static void show_tabs(void)
     719  {
     720  	int i, co = tigetnum("cols");
     721  
     722  	if (co > 0) {
     723  		printf("\r         ");
     724  		for (i = 10; i < co - 2; i += 10)
     725  			printf("%-10d", i);
     726  		putchar('\n');
     727  		for (i = 1; i <= co; i++)
     728  			putchar(i % 10 + '0');
     729  		putchar('\n');
     730  		for (i = 1; i < co; i++)
     731  			printf("\tT\b");
     732  		putchar('\n');
     733  	}
     734  }
     735  
     736  static int open_snapshot_device(struct setterm_control *ctl)
     737  {
     738  	int fd;
     739  
     740  	if (ctl->opt_sn_num)
     741  		xasprintf(&ctl->in_device, "/dev/vcsa%d", ctl->opt_sn_num);
     742  	else
     743  		xasprintf(&ctl->in_device, "/dev/vcsa");
     744  	fd = open(ctl->in_device, O_RDONLY);
     745  	if (fd < 0)
     746  		err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
     747  	return fd;
     748  }
     749  
     750  static void set_blanking(struct setterm_control *ctl)
     751  {
     752  	char ioctlarg;
     753  	int ret;
     754  
     755  	if (0 <= ctl->opt_bl_min) {
     756  		printf("\033[9;%d]", ctl->opt_bl_min);
     757  		return;
     758  	}
     759  	switch (ctl->opt_bl_min) {
     760  	case BLANKSCREEN:
     761  		ioctlarg = TIOCL_BLANKSCREEN;
     762  		if (ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg))
     763  			warn(_("cannot force blank"));
     764  		break;
     765  	case UNBLANKSCREEN:
     766  		ioctlarg = TIOCL_UNBLANKSCREEN;
     767  		if (ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg))
     768  			warn(_("cannot force unblank"));
     769  		break;
     770  	case BLANKEDSCREEN:
     771  		ioctlarg = TIOCL_BLANKEDSCREEN;
     772  		ret = ioctl(STDIN_FILENO, TIOCLINUX, &ioctlarg);
     773  		if (ret < 0)
     774  			warn(_("cannot get blank status"));
     775  		else
     776  			printf("%d\n", ret);
     777  		break;
     778  	default:		/* should be impossible to reach */
     779  		abort();
     780  	}
     781  }
     782  
     783  static void screendump(struct setterm_control *ctl)
     784  {
     785  	unsigned char header[4];
     786  	unsigned int rows, cols;
     787  	int fd;
     788  	FILE *out;
     789  	size_t i, j;
     790  	ssize_t rc;
     791  	char *inbuf, *outbuf, *p, *q;
     792  
     793  	/* open source and destination files */
     794  	fd = open_snapshot_device(ctl);
     795  	if (!ctl->opt_sn_name)
     796  		ctl->opt_sn_name = "screen.dump";
     797  	out = fopen(ctl->opt_sn_name, ctl->opt_snap ? "w" : "a");
     798  	if (!out)
     799  		err(EXIT_DUMPFILE, _("cannot open dump file %s for output"), ctl->opt_sn_name);
     800  	/* determine snapshot size */
     801  	if (read(fd, header, 4) != 4)
     802  		err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
     803  	rows = header[0];
     804  	cols = header[1];
     805  	if (rows * cols == 0)
     806  		err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
     807  	/* allocate buffers */
     808  	inbuf = xmalloc(rows * cols * 2);
     809  	outbuf = xmalloc(rows * (cols + 1));
     810  	/* read input */
     811  	rc = read(fd, inbuf, rows * cols * 2);
     812  	if (rc < 0 || (size_t)rc != rows * cols * 2)
     813  		err(EXIT_DUMPFILE, _("cannot read %s"), ctl->in_device);
     814  	p = inbuf;
     815  	q = outbuf;
     816  	/* copy inbuf to outbuf */
     817  	for (i = 0; i < rows; i++) {
     818  		for (j = 0; j < cols; j++) {
     819  			*q++ = *p;
     820  			p += 2;
     821  		}
     822  		while (j-- > 0 && q[-1] == ' ')
     823  			q--;
     824  		*q++ = '\n';
     825  	}
     826  	fwrite(outbuf, 1, q - outbuf, out);
     827  	/* clean up allocations */
     828  	close(fd);
     829  	free(inbuf);
     830  	free(outbuf);
     831  	free(ctl->in_device);
     832  	if (close_stream(out) != 0)
     833  		errx(EXIT_FAILURE, _("write error"));
     834  }
     835  
     836  /* Some options are applicable when terminal is virtual console. */
     837  static int vc_only(struct setterm_control *ctl, const char *err)
     838  {
     839  	if (!ctl->vcterm && err)
     840  		warnx(_("terminal %s does not support %s"),
     841  		      ctl->opt_te_terminal_name, err);
     842  	return ctl->vcterm;
     843  }
     844  
     845  static void tty_raw(struct termios *saved_attributes, int *saved_fl)
     846  {
     847  	struct termios tattr;
     848  
     849  	fcntl(STDIN_FILENO, F_GETFL, saved_fl);
     850  	tcgetattr(STDIN_FILENO, saved_attributes);
     851  	fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
     852  	memcpy(&tattr, saved_attributes, sizeof(struct termios));
     853  	tattr.c_lflag &= ~(ICANON | ECHO);
     854  	tattr.c_cc[VMIN] = 1;
     855  	tattr.c_cc[VTIME] = 0;
     856  	tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
     857  }
     858  
     859  static void tty_restore(struct termios *saved_attributes, int *saved_fl)
     860  {
     861  	fcntl(STDIN_FILENO, F_SETFL, *saved_fl);
     862  	tcsetattr(STDIN_FILENO, TCSANOW, saved_attributes);
     863  }
     864  
     865  static int select_wait(void)
     866  {
     867  	struct timeval tv;
     868  	fd_set set;
     869  	int ret;
     870  
     871  	FD_ZERO(&set);
     872  	FD_SET(STDIN_FILENO, &set);
     873  	tv.tv_sec = 10;
     874  	tv.tv_usec = 0;
     875  	while ((ret = select(1, &set, NULL, NULL, &tv)) < 0) {
     876  		if (errno == EINTR)
     877  			continue;
     878  		err(EXIT_FAILURE, _("select failed"));
     879  	}
     880  	return ret;
     881  }
     882  
     883  static int resizetty(void)
     884  {
     885  	/*
     886  	 * \e7        Save current state (cursor coordinates, attributes,
     887  	 *                character sets pointed at by G0, G1).
     888  	 * \e[r       Set scrolling region; parameters are top and bottom row.
     889  	 * \e[32766E  Move cursor down 32766 (INT16_MAX - 1) rows.
     890  	 * \e[32766C  Move cursor right 32766 columns.
     891  	 * \e[6n      Report cursor position.
     892  	 * \e8        Restore state most recently saved by \e7.
     893  	 */
     894  	static const char *getpos = "\e7\e[r\e[32766E\e[32766C\e[6n\e8";
     895  	char retstr[32];
     896  	int row, col;
     897  	size_t pos;
     898  	ssize_t rc;
     899  	struct winsize ws;
     900  	struct termios saved_attributes;
     901  	int saved_fl;
     902  
     903  	if (!isatty(STDIN_FILENO))
     904  		errx(EXIT_FAILURE, _("stdin does not refer to a terminal"));
     905  
     906  	tty_raw(&saved_attributes, &saved_fl);
     907  	if (write_all(STDIN_FILENO, getpos, strlen(getpos)) < 0) {
     908  		warn(_("write failed"));
     909  		tty_restore(&saved_attributes, &saved_fl);
     910  		return 1;
     911  	}
     912  	for (pos = 0; pos < sizeof(retstr) - 1;) {
     913  		if (0 == select_wait())
     914  			break;
     915  		if ((rc =
     916  		     read(STDIN_FILENO, retstr + pos,
     917  			  sizeof(retstr) - 1 - pos)) < 0) {
     918  			if (errno == EINTR)
     919  				continue;
     920  			warn(_("read failed"));
     921  			tty_restore(&saved_attributes, &saved_fl);
     922  			return 1;
     923  		}
     924  		pos += rc;
     925  		if (retstr[pos - 1] == 'R')
     926  			break;
     927  	}
     928  	retstr[pos] = 0;
     929  	tty_restore(&saved_attributes, &saved_fl);
     930  	rc = sscanf(retstr, "\033[%d;%dR", &row, &col);
     931  	if (rc != 2) {
     932  		warnx(_("invalid cursor position: %s"), retstr);
     933  		return 1;
     934  	}
     935  	memset(&ws, 0, sizeof(struct winsize));
     936  	ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
     937  	ws.ws_row = row;
     938  	ws.ws_col = col;
     939  	ioctl(STDIN_FILENO, TIOCSWINSZ, &ws);
     940  	return 0;
     941  }
     942  
     943  static void perform_sequence(struct setterm_control *ctl)
     944  {
     945  	int result;
     946  
     947  	/* -reset. */
     948  	if (ctl->opt_reset)
     949  		putp(ti_entry("rs1"));
     950  
     951  	/* -resize. */
     952  	if (ctl->opt_resize)
     953  		if (resizetty())
     954  			warnx(_("reset failed"));
     955  
     956  	/* -initialize. */
     957  	if (ctl->opt_initialize)
     958  		putp(ti_entry("is2"));
     959  
     960  	/* -cursor [on|off]. */
     961  	if (ctl->opt_cursor) {
     962  		if (ctl->opt_cu_on)
     963  			putp(ti_entry("cnorm"));
     964  		else
     965  			putp(ti_entry("civis"));
     966  	}
     967  
     968  	/* -linewrap [on|off]. */
     969  	if (ctl->opt_linewrap)
     970  		fputs(ctl->opt_li_on ? "\033[?7h" : "\033[?7l", stdout);
     971  
     972  	/* -repeat [on|off]. */
     973  	if (ctl->opt_repeat && vc_only(ctl, "--repeat"))
     974  		fputs(ctl->opt_rep_on ? "\033[?8h" : "\033[?8l", stdout);
     975  
     976  	/* -appcursorkeys [on|off]. */
     977  	if (ctl->opt_appcursorkeys && vc_only(ctl, "--appcursorkeys"))
     978  		fputs(ctl->opt_appck_on ? "\033[?1h" : "\033[?1l", stdout);
     979  
     980  	/* -default.  Vc sets default rendition, otherwise clears all
     981  	 * attributes. */
     982  	if (ctl->opt_default) {
     983  		if (vc_only(ctl, NULL))
     984  			printf("\033[0m");
     985  		else
     986  			putp(ti_entry("sgr0"));
     987  	}
     988  
     989  	/* -foreground black|red|green|yellow|blue|magenta|cyan|white|default. */
     990  	if (ctl->opt_foreground)
     991  		printf("\033[3%c%s", '0' + ctl->opt_fo_color, "m");
     992  
     993  	/* -background black|red|green|yellow|blue|magenta|cyan|white|default. */
     994  	if (ctl->opt_background)
     995  		printf("\033[4%c%s", '0' + ctl->opt_ba_color, "m");
     996  
     997  	/* -ulcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
     998  	if (ctl->opt_ulcolor && vc_only(ctl, "--ulcolor"))
     999  		printf("\033[1;%d]", ctl->opt_ul_color);
    1000  
    1001  	/* -hbcolor [bright] black|red|green|yellow|blue|magenta|cyan|white. */
    1002  	if (ctl->opt_hbcolor)
    1003  		printf("\033[2;%d]", ctl->opt_hb_color);
    1004  
    1005  	/* -inversescreen [on|off]. */
    1006  	if (ctl->opt_inversescreen)
    1007  		fputs(ctl->opt_invsc_on ? "\033[?5h" : "\033[?5l", stdout);
    1008  
    1009  	/* -bold [on|off].  Vc behaves as expected, otherwise off turns off
    1010  	 * all attributes. */
    1011  	if (ctl->opt_bold) {
    1012  		if (ctl->opt_bo_on)
    1013  			putp(ti_entry("bold"));
    1014  		else {
    1015  			if (vc_only(ctl, NULL))
    1016  				fputs("\033[22m", stdout);
    1017  			else
    1018  				putp(ti_entry("sgr0"));
    1019  		}
    1020  	}
    1021  
    1022  	/* -half-bright [on|off].  Vc behaves as expected, otherwise off
    1023  	 * turns off all attributes.  */
    1024  	if (ctl->opt_halfbright) {
    1025  		if (ctl->opt_hb_on)
    1026  			putp(ti_entry("dim"));
    1027  		else {
    1028  			if (vc_only(ctl, NULL))
    1029  				fputs("\033[22m", stdout);
    1030  			else
    1031  				putp(ti_entry("sgr0"));
    1032  		}
    1033  	}
    1034  
    1035  	/* -blink [on|off].  Vc behaves as expected, otherwise off turns off
    1036  	 * all attributes. */
    1037  	if (ctl->opt_blink) {
    1038  		if (ctl->opt_bl_on)
    1039  			putp(ti_entry("blink"));
    1040  		else {
    1041  			if (vc_only(ctl, NULL))
    1042  				fputs("\033[25m", stdout);
    1043  			else
    1044  				putp(ti_entry("sgr0"));
    1045  		}
    1046  	}
    1047  
    1048  	/* -reverse [on|off].  Vc behaves as expected, otherwise off turns
    1049  	 * off all attributes. */
    1050  	if (ctl->opt_reverse) {
    1051  		if (ctl->opt_re_on)
    1052  			putp(ti_entry("rev"));
    1053  		else {
    1054  			if (vc_only(ctl, NULL))
    1055  				fputs("\033[27m", stdout);
    1056  			else
    1057  				putp(ti_entry("sgr0"));
    1058  		}
    1059  	}
    1060  
    1061  	/* -underline [on|off]. */
    1062  	if (ctl->opt_underline)
    1063  		putp(ti_entry(ctl->opt_un_on ? "smul" : "rmul"));
    1064  
    1065  	/* -store. */
    1066  	if (ctl->opt_store && vc_only(ctl, "--store"))
    1067  		fputs("\033[8]", stdout);
    1068  
    1069  	/* -clear [all|rest]. */
    1070  	if (ctl->opt_clear)
    1071  		putp(ti_entry(ctl->opt_cl_all ? "clear" : "ed"));
    1072  
    1073  	/* -tabs. */
    1074  	if (ctl->opt_tabs) {
    1075  		if (ctl->opt_tb_array[0] == -1)
    1076  			show_tabs();
    1077  		else {
    1078  			int i;
    1079  
    1080  			for (i = 0; ctl->opt_tb_array[i] > 0; i++)
    1081  				printf("\033[%dG\033H", ctl->opt_tb_array[i]);
    1082  			putchar('\r');
    1083  		}
    1084  	}
    1085  
    1086  	/* -clrtabs. */
    1087  	if (ctl->opt_clrtabs && vc_only(ctl, "--clrtabs")) {
    1088  		int i;
    1089  
    1090  		if (ctl->opt_tb_array[0] == -1)
    1091  			fputs("\033[3g", stdout);
    1092  		else
    1093  			for (i = 0; ctl->opt_tb_array[i] > 0; i++)
    1094  				printf("\033[%dG\033[g", ctl->opt_tb_array[i]);
    1095  		putchar('\r');
    1096  	}
    1097  
    1098  	/* -regtabs. */
    1099  	if (ctl->opt_regtabs && vc_only(ctl, "--regtabs")) {
    1100  		int i;
    1101  
    1102  		fputs("\033[3g\r", stdout);
    1103  		for (i = ctl->opt_rt_len + 1; i <= TABS_MAX; i += ctl->opt_rt_len)
    1104  			printf("\033[%dC\033H", ctl->opt_rt_len);
    1105  		putchar('\r');
    1106  	}
    1107  
    1108  	/* -blank [0-60]. */
    1109  	if (ctl->opt_blank && vc_only(ctl, "--blank"))
    1110  		set_blanking(ctl);
    1111  
    1112  	/* -powersave [on|vsync|hsync|powerdown|off] (console) */
    1113  	if (ctl->opt_powersave) {
    1114  		char ioctlarg[2];
    1115  		ioctlarg[0] = TIOCL_SETVESABLANK;
    1116  		ioctlarg[1] = ctl->opt_ps_mode;
    1117  		if (ioctl(STDIN_FILENO, TIOCLINUX, ioctlarg))
    1118  			warn(_("cannot (un)set powersave mode"));
    1119  	}
    1120  
    1121  	/* -powerdown [0-60]. */
    1122  	if (ctl->opt_powerdown)
    1123  		printf("\033[14;%d]", ctl->opt_pd_min);
    1124  
    1125  	/* -snap [1-NR_CONS]. */
    1126  	if (ctl->opt_snap || ctl->opt_append)
    1127  		screendump(ctl);
    1128  
    1129  	/* -msg [on|off].  Controls printk's to console. */
    1130  	if (ctl->opt_msg && vc_only(ctl, "--msg")) {
    1131  		if (ctl->opt_msg_on)
    1132  			result = klogctl(SYSLOG_ACTION_CONSOLE_ON, NULL, 0);
    1133  		else
    1134  			result = klogctl(SYSLOG_ACTION_CONSOLE_OFF, NULL, 0);
    1135  
    1136  		if (result != 0)
    1137  			warn(_("klogctl error"));
    1138  	}
    1139  
    1140  	/* -msglevel [0-8].  Console printk message level. */
    1141  	if (ctl->opt_msglevel_num && vc_only(ctl, "--msglevel")) {
    1142  		result =
    1143  		    klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL,
    1144  			    ctl->opt_msglevel_num);
    1145  		if (result != 0)
    1146  			warn(_("klogctl error"));
    1147  	}
    1148  
    1149  	/* -blength [0-2000] */
    1150  	if (ctl->opt_blength && vc_only(ctl, "--blength")) {
    1151  		printf("\033[11;%d]", ctl->opt_blength_l);
    1152  	}
    1153  
    1154  	/* -bfreq freqnumber */
    1155  	if (ctl->opt_bfreq && vc_only(ctl, "--bfreq")) {
    1156  		printf("\033[10;%d]", ctl->opt_bfreq_f);
    1157  	}
    1158  }
    1159  
    1160  static void init_terminal(struct setterm_control *ctl)
    1161  {
    1162  	int term_errno;
    1163  
    1164  	if (!ctl->opt_te_terminal_name) {
    1165  		ctl->opt_te_terminal_name = getenv("TERM");
    1166  		if (ctl->opt_te_terminal_name == NULL)
    1167  			errx(EXIT_FAILURE, _("$TERM is not defined."));
    1168  	}
    1169  
    1170  	/* Find terminfo entry. */
    1171  	if (setupterm(ctl->opt_te_terminal_name, STDOUT_FILENO, &term_errno))
    1172  		switch (term_errno) {
    1173  		case -1:
    1174  			errx(EXIT_FAILURE, _("terminfo database cannot be found"));
    1175  		case 0:
    1176  			errx(EXIT_FAILURE, _("%s: unknown terminal type"), ctl->opt_te_terminal_name);
    1177  		case 1:
    1178  			errx(EXIT_FAILURE, _("terminal is hardcopy"));
    1179  		}
    1180  
    1181  	/* See if the terminal is a virtual console terminal. */
    1182  	ctl->vcterm = (!strncmp(ctl->opt_te_terminal_name, "con", 3) ||
    1183  		       !strncmp(ctl->opt_te_terminal_name, "linux", 5));
    1184  }
    1185  
    1186  
    1187  int main(int argc, char **argv)
    1188  {
    1189  	struct setterm_control ctl = { NULL };
    1190  
    1191  	setlocale(LC_ALL, "");
    1192  	bindtextdomain(PACKAGE, LOCALEDIR);
    1193  	textdomain(PACKAGE);
    1194  	close_stdout_atexit();
    1195  
    1196  	if (argc < 2) {
    1197  		warnx(_("bad usage"));
    1198  		errtryhelp(EXIT_FAILURE);
    1199  	}
    1200  	parse_option(&ctl, argc, argv);
    1201  	init_terminal(&ctl);
    1202  	perform_sequence(&ctl);
    1203  
    1204  	return EXIT_SUCCESS;
    1205  }