src/sbin/wsconsctl/wsconsctl.c

335 lines
8.0 KiB
C

/* $OpenBSD: wsconsctl.c,v 1.32 2019/06/28 13:32:46 deraadt Exp $ */
/* $NetBSD: wsconsctl.c,v 1.2 1998/12/29 22:40:20 hannken Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Juergen Hannken-Illjes.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <fcntl.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "wsconsctl.h"
extern const char *__progname; /* from crt0.o */
extern struct field keyboard_field_tab[];
extern struct field mouse_field_tab[];
extern struct field display_field_tab[];
void usage(void);
struct vartypesw {
const char *name;
struct field *field_tab;
void (*init)(int,int);
void (*getval)(int);
int (*putval)(int);
char * (*nextdev)(int);
} typesw[] = {
{ "keyboard", keyboard_field_tab, NULL,
keyboard_get_values, keyboard_put_values, keyboard_next_device },
{ "mouse", mouse_field_tab, mouse_init,
mouse_get_values, mouse_put_values, mouse_next_device },
{ "display", display_field_tab, NULL,
display_get_values, display_put_values, display_next_device },
{ NULL }
};
struct vartypesw *tab_by_name(const char *, int *);
void
usage(void)
{
fprintf(stderr,
"usage: %s [-an]\n"
" %s [-n] [-f file] name ...\n"
" %s [-n] [-f file] name=value ...\n",
__progname, __progname, __progname);
exit(1);
}
int
main(int argc, char *argv[])
{
int i, ch, error = 0, aflag = 0, do_merge, putval, devidx, devfd;
struct vartypesw *sw = NULL;
char *getsep = "=", *setsep = " -> ", *p;
char *wdev = NULL;
char *device;
struct field *f;
char devname[20];
while ((ch = getopt(argc, argv, "af:nw")) != -1) {
switch(ch) {
case 'a':
aflag = 1;
break;
case 'f':
wdev = optarg;
break;
case 'n':
getsep = setsep = NULL;
break;
case 'w':
/* compat */
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc > 0 && aflag != 0)
errx(1, "excess arguments after -a");
if (argc == 0)
aflag = 1;
if (aflag != 0) {
for (sw = typesw; sw->name; sw++) {
for (devidx = 0;; devidx++) {
device = (*sw->nextdev)(devidx);
if (!device ||
((devfd = open(device, O_WRONLY)) == -1 &&
(devfd = open(device, O_RDONLY)) == -1)) {
if (!device || errno != ENXIO) {
if (device && errno != ENOENT) {
warn("%s", device);
error = 1;
}
break;
} else
continue;
}
if (devidx == 0)
snprintf(devname, sizeof(devname),
"%s", sw->name);
else
snprintf(devname, sizeof(devname),
"%s%d", sw->name, devidx);
if (sw->init != NULL)
(*sw->init)(devfd, devidx);
for (f = sw->field_tab; f->name; f++)
if (!(f->flags &
(FLG_NOAUTO|FLG_WRONLY)))
f->flags |= FLG_GET;
(*sw->getval)(devfd);
for (f = sw->field_tab; f->name; f++)
if (f->flags & FLG_DEAD)
continue;
else if (f->flags & FLG_NOAUTO)
warnx("Use explicit arg to "
"view %s.%s.",
devname, f->name);
else if (f->flags & FLG_GET)
pr_field(devname, f, getsep);
}
}
} else if (argc > 0) {
for (i = 0; i < argc; i++) {
sw = tab_by_name(argv[i], &devidx);
if (!sw)
continue;
if (!wdev)
device = (*sw->nextdev)(devidx);
else
device = wdev;
if (!device ||
((devfd = open(device, O_WRONLY)) == -1 &&
(devfd = open(device, O_RDONLY)) == -1)) {
if (!device) {
const char *c = strchr(argv[i], '.');
int k;
if (!c)
c = strchr(argv[i], '\0');
k = c - argv[i];
warnx("%*.*s: no such variable",
k, k, argv[i]);
} else
warn("%s", device);
error = 1;
continue;
}
if (devidx == 0)
snprintf(devname, sizeof(devname),
"%s", sw->name);
else
snprintf(devname, sizeof(devname),
"%s%d", sw->name, devidx);
if (sw->init != NULL)
(*sw->init)(devfd, devidx);
p = strchr(argv[i], '=');
if (p == NULL) {
if (!strchr(argv[i], '.')) {
for (f = sw->field_tab; f->name; f++)
if (!(f->flags &
(FLG_NOAUTO|FLG_WRONLY)))
f->flags |= FLG_GET;
(*sw->getval)(devfd);
for (f = sw->field_tab; f->name; f++)
if (f->flags & FLG_DEAD)
continue;
else if (f->flags & FLG_NOAUTO)
warnx("Use explicit "
"arg to view "
"%s.%s.",
devname, f->name);
else if (f->flags & FLG_GET)
pr_field(devname, f,
getsep);
continue;
}
f = field_by_name(sw->field_tab, argv[i]);
if (f->flags & FLG_DEAD)
continue;
if ((f->flags & FLG_WRONLY)) {
warnx("%s: write only", argv[i]);
continue;
}
f->flags |= FLG_GET;
(*sw->getval)(devfd);
if (f->flags & FLG_DEAD)
continue;
pr_field(devname, f, getsep);
} else {
if (!strchr(argv[i], '.') ||
(strchr(argv[i], '.') > p)) {
warnx("%s: illegal variable name",
argv[i]);
continue;
}
if (p > argv[i] &&
(*(p - 1) == '+' || *(p - 1) == '-')) {
do_merge = *(p - 1);
*(p - 1) = '\0';
} else
do_merge = 0;
*p++ = '\0';
f = field_by_name(sw->field_tab, argv[i]);
if (f->flags & FLG_DEAD)
continue;
if (f->flags & FLG_RDONLY) {
warnx("%s: read only", argv[i]);
continue;
}
if (do_merge || f->flags & FLG_INIT) {
if (!(f->flags & FLG_MODIFY))
errx(1, "%s: can only be set",
argv[i]);
f->flags |= FLG_GET;
(*sw->getval)(devfd);
f->flags &= ~FLG_GET;
}
rd_field(f, p, do_merge);
f->flags |= FLG_SET;
putval = (*sw->putval)(devfd);
f->flags &= ~FLG_SET;
if (putval != 0 ||
f->flags & (FLG_DEAD|FLG_NOAUTO))
continue;
if (f->flags & FLG_WRONLY) {
pr_field(devname, f, setsep);
} else {
if (!(f->flags & FLG_NORDBACK)) {
f->flags |= FLG_GET;
(*sw->getval)(devfd);
}
if (f->flags & FLG_DEAD)
continue;
pr_field(devname, f, setsep);
}
}
close(devfd);
}
} else
usage();
exit(error);
}
struct vartypesw *
tab_by_name(const char *var, int *idx)
{
struct vartypesw *sw;
const char *p = strchr(var, '.');
char *c;
int i;
for (sw = typesw; sw->name; sw++)
if (!strncmp(sw->name, var, strlen(sw->name)))
break;
if (!p)
p = strchr(var, '\0');
if (!sw->name) {
i = p - var;
warnx("%*.*s: no such variable", i, i, var);
return (NULL);
}
if ((p - var) > strlen(sw->name)) {
c = (char *)var;
c = c + strlen(sw->name);
i = 0;
while (c < p) {
if (*c >= '0' && *c <= '9')
i = i * 10 + *c - '0';
else
i = -1;
c++;
}
if (i < 0 || i > 32) {
i = p - var;
warnx("%*.*s: no such variable", i, i, var);
return (NULL);
}
} else
i = 0;
*idx = i;
return (sw);
}