blob: 3577aeeedcb8ed1c7d1470bd43867eaa2cf7ad1d [file] [log] [blame]
/*
* setleds.c - aeb, 940130, 940909, 991008
*
* Call: setleds [-L] [-D] [-F] [{+|-}{num|caps|scroll}]*
* will set or clear the indicated flags on the stdin tty,
* and report the settings before and after.
* In particular, setleds without arguments will only report.
*/
#include <stdio.h>
#include <fcntl.h>
#include <linux/kd.h>
#include <sys/ioctl.h>
#include "nls.h"
#include "version.h"
static void attr_noreturn
usage(void)
{
fprintf(stderr, _(
"Usage:\n"
" setleds [-v] [-L] [-D] [-F] [[+|-][ num | caps | scroll %s]]\n"
"Thus,\n"
" setleds +caps -num\n"
"will set CapsLock, clear NumLock and leave ScrollLock unchanged.\n"
"The settings before and after the change (if any) are reported\n"
"when the -v option is given or when no change is requested.\n"
"Normally, setleds influences the vt flag settings\n"
"(and these are usually reflected in the leds).\n"
"With -L, setleds only sets the leds, and leaves the flags alone.\n"
"With -D, setleds sets both the flags and the default flags, so\n"
"that a subsequent reset will not change the flags.\n"
),
#ifdef __sparc__
"| compose "
#else
""
#endif
);
exit(1);
}
#define onoff(a) ((a) ? _("on ") : _("off"))
/* report the bits, in the order seen on the (my) keyboard */
#define LED_NLOCK 1
#define LED_CMPOSE 2
#define LED_SCRLCK 4
#define LED_CLOCK 8
static void
sunreport(int leds) {
printf("NumLock %s Compose %s ScrollLock %s CapsLock %s\n",
onoff(leds & LED_NLOCK),
onoff(leds & LED_CMPOSE),
onoff(leds & LED_SCRLCK),
onoff(leds & LED_CLOCK));
}
static void
report(int leds) {
printf("NumLock %s CapsLock %s ScrollLock %s\n",
onoff(leds & LED_NUM),
onoff(leds & LED_CAP),
onoff(leds & LED_SCR));
}
struct led {
char *name;
int bit;
int sunbit;
} leds[] = {
{ "scroll", LED_SCR, LED_SCRLCK },
{ "num", LED_NUM, LED_NLOCK },
{ "caps", LED_CAP, LED_CLOCK },
#ifdef __sparc__
{ "compose", 0, LED_CMPOSE }
#endif
};
static void
getleds(char *cur_leds) {
if (ioctl(0, KDGETLED, cur_leds)) {
perror("KDGETLED");
fprintf(stderr,
_("Error reading current led setting. Maybe stdin is not a VT?\n"));
exit(1);
}
}
static int
setleds(char cur_leds) {
if (ioctl(0, KDSETLED, cur_leds)) {
perror("KDSETLED");
return -1;
}
return 0;
}
static void
getflags(char *flags) {
if (ioctl(0, KDGKBLED, flags)) {
perror("KDGKBLED");
fprintf(stderr,
_("Error reading current flags setting. "
"Maybe you are not on the console?\n"));
exit(1);
}
}
static int sunkbdfd = -1;
#ifndef KIOCGLED
#define arg_state attr_unused
#else
#define arg_state
#endif
static void attr_noreturn
sungetleds(arg_state char *cur_leds) {
#ifdef KIOCGLED
if (ioctl(sunkbdfd, KIOCGLED, cur_leds)) {
perror("KIOCGLED");
fprintf(stderr,
_("Error reading current led setting from /dev/kbd.\n"));
exit(1);
}
#else
fprintf(stderr, _("KIOCGLED unavailable?\n"));
exit(1);
#endif
}
#ifndef KIOCSLED
#define arg_state attr_unused
#else
#define arg_state
#endif
static void attr_noreturn
sunsetleds(arg_state char *cur_leds) {
#ifdef KIOCSLED
if (ioctl(sunkbdfd, KIOCSLED, cur_leds)) {
perror("KIOCSLED");
fprintf(stderr,
_("Error reading current led setting from /dev/kbd.\n"));
exit(1);
}
#else
fprintf(stderr, _("KIOCSLED unavailable?\n"));
exit(1);
#endif
}
int
main(int argc, char **argv) {
int optL = 0, optD = 0, optF = 0, verbose = 0;
char oleds, nleds, oflags, nflags, odefflags, ndefflags;
char nval, ndef, sign;
char osunleds = 0, nsunleds, nsunval, nsundef;
char *ap;
struct led *lp;
set_progname(argv[0]);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE_NAME, LOCALEDIR);
textdomain(PACKAGE_NAME);
if (argc == 2 && (!strcmp("-V", argv[1]) || !strcmp("--version", argv[1])))
print_version_and_exit();
#ifdef __sparc__
sunkbdfd = open("/dev/kbd", O_RDONLY);
if (sunkbdfd < 0) {
perror("/dev/kbd");
fprintf(stderr, _("Error opening /dev/kbd.\n"));
/* exit(1); */
}
#endif
getflags(&oflags);
getleds(&oleds);
if (sunkbdfd >= 0)
sungetleds(&osunleds);
while (argc > 1) {
if (!strcmp("-L", argv[1]))
optL = 1;
else if (!strcmp("-D", argv[1]))
optD = 1;
else if (!strcmp("-F", argv[1]))
optF = 1;
else if (!strcmp("-v", argv[1]))
verbose = 1;
else
break;
argc--;
argv++;
}
odefflags = ndefflags = ((oflags >> 4) & 7);
oflags = nflags = (oflags & 7);
if (argc <= 1) {
if (optL) {
nleds = 0xff;
if (setleds(nleds)) {
fprintf(stderr, _("Error resetting ledmode\n"));
exit(1);
}
}
/* If nothing to do, report, even if not verbose */
if (!optD && !optL && !optF)
optD = optL = optF = 1;
if (optD) {
printf(_("Current default flags: "));
report(odefflags);
}
if (optF) {
printf(_("Current flags: "));
report(oflags & 07);
}
if (optL) {
printf(_("Current leds: "));
if (sunkbdfd >= 0)
sunreport(osunleds);
else
report(oleds);
}
exit(0);
}
if (!optL)
optF = 1;
nval = 0;
ndef = 0;
nsunval = 0;
nsundef = 0;
while(--argc) {
ap = *++argv;
sign = 1; /* by default: set */
if(*ap == '+')
ap++;
else if(*ap == '-') {
sign = 0;
ap++;
}
for (lp = leds; (unsigned) (lp-leds) < sizeof(leds)/sizeof(leds[0]); lp++) {
if(!strcmp(ap, lp->name)) {
if(sign) {
nval |= lp->bit;
nsunval |= lp->sunbit;
}
ndef |= lp->bit;
nsundef |= lp->sunbit;
goto nxtarg;
}
}
fprintf(stderr, _("unrecognized argument: _%s_\n\n"), ap);
usage();
nxtarg: ;
}
if (optD) {
ndefflags = (odefflags & ~ndef) | nval;
if (verbose) {
printf(_("Old default flags: "));
report(odefflags);
printf(_("New default flags: "));
report(ndefflags);
}
}
if (optF) {
nflags = ((oflags & ~ndef) | nval);
if (verbose) {
printf(_("Old flags: "));
report(oflags & 07);
printf(_("New flags: "));
report(nflags & 07);
}
}
if (optD || optF) {
if (ioctl(0, KDSKBLED, (ndefflags << 4) | nflags)) {
perror("KDSKBLED");
exit(1);
}
}
if (optL) {
if (sunkbdfd >= 0) {
nsunleds = (osunleds & ~nsundef) | nsunval;
if (verbose) {
printf(_("Old leds: "));
sunreport(osunleds);
printf(_("New leds: "));
sunreport(nsunleds);
}
sunsetleds(&nsunleds);
} else {
nleds = (oleds & ~ndef) | nval;
if (verbose) {
printf(_("Old leds: "));
report(oleds);
printf(_("New leds: "));
report(nleds);
}
if (setleds(nleds))
exit(1);
}
}
exit(0);
}