[BACK]Return to wsconsctl.c CVS log [TXT][DIR] Up to [local] / src / sbin / wsconsctl

File: [local] / src / sbin / wsconsctl / wsconsctl.c (download)

Revision 1.32, Fri Jun 28 13:32:46 2019 UTC (4 years, 11 months ago) by deraadt
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, OPENBSD_7_2_BASE, OPENBSD_7_2, OPENBSD_7_1_BASE, OPENBSD_7_1, OPENBSD_7_0_BASE, OPENBSD_7_0, OPENBSD_6_9_BASE, OPENBSD_6_9, OPENBSD_6_8_BASE, OPENBSD_6_8, OPENBSD_6_7_BASE, OPENBSD_6_7, OPENBSD_6_6_BASE, OPENBSD_6_6, HEAD
Changes since 1.31: +5 -5 lines

When system calls indicate an error they return -1, not some arbitrary
value < 0.  errno is only updated in this case.  Change all (most?)
callers of syscalls to follow this better, and let's see if this strictness
helps us in the future.

/*	$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);
}