/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2001, 2002 Dima Dorfman.4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728/*29* DEVFS control.30*/3132#include <sys/param.h>33#include <sys/queue.h>3435#include <assert.h>36#include <err.h>37#include <fcntl.h>38#include <paths.h>39#include <stdio.h>40#include <stdint.h>41#include <stdlib.h>42#include <string.h>43#include <unistd.h>4445#include "extern.h"4647int mpfd;4849static ctbl_t ctbl_main = {50{ "rule", rule_main },51{ "ruleset", ruleset_main },52{ NULL, NULL }53};5455int56main(int ac, char **av)57{58const char *mountpt;59struct cmd *c;60int ch;6162mountpt = NULL;63while ((ch = getopt(ac, av, "m:")) != -1)64switch (ch) {65case 'm':66mountpt = optarg;67break;68default:69usage();70}71ac -= optind;72av += optind;73if (ac < 1)74usage();7576if (mountpt == NULL)77mountpt = _PATH_DEV;78mpfd = open(mountpt, O_RDONLY);79if (mpfd == -1)80err(1, "open: %s", mountpt);8182for (c = ctbl_main; c->name != NULL; ++c)83if (strcmp(c->name, av[0]) == 0)84exit((*c->handler)(ac, av));85errx(1, "unknown command: %s", av[0]);86}8788/*89* Convert an integer to a "number" (ruleset numbers and rule numbers90* are 16-bit). If the conversion is successful, num contains the91* integer representation of s and 1 is returned; otherwise, 0 is92* returned and num is unchanged.93*/94int95atonum(const char *s, uint16_t *num)96{97unsigned long ul;98char *cp;99100ul = strtoul(s, &cp, 10);101if (ul > UINT16_MAX || *cp != '\0')102return (0);103*num = (uint16_t)ul;104return (1);105}106107/*108* Convert user input in ASCII to an integer.109*/110int111eatoi(const char *s)112{113char *cp;114long l;115116l = strtol(s, &cp, 10);117if (l > INT_MAX || *cp != '\0')118errx(1, "error converting to integer: %s", s);119return ((int)l);120}121122/*123* As atonum(), but the result of failure is death.124*/125uint16_t126eatonum(const char *s)127{128uint16_t num;129130if (!atonum(s, &num))131errx(1, "error converting to number: %s", s); /* XXX clarify */132return (num);133}134135/*136* Read a line from a /FILE/. If the return value isn't 0, it is the137* length of the line, a pointer to which exists in /line/. It is the138* caller's responsibility to free(3) it. If the return value is 0,139* there was an error or we reached EOF, and /line/ is undefined (so,140* obviously, the caller shouldn't try to free(3) it).141*/142size_t143efgetln(FILE *fp, char **line)144{145size_t rv;146char *cp;147148cp = fgetln(fp, &rv);149if (cp == NULL) {150*line = NULL;151return (rv);152}153if (cp[rv - 1] == '\n') {154cp[rv - 1] = '\0';155*line = strdup(cp);156if (*line == NULL)157errx(1, "cannot allocate memory");158--rv;159} else {160*line = malloc(rv + 1);161if (*line == NULL)162errx(1, "cannot allocate memory");163memcpy(*line, cp, rv);164(*line)[rv] = '\0';165}166assert(rv == strlen(*line));167return (rv);168}169170struct ptrstq {171STAILQ_ENTRY(ptrstq) tq;172void *ptr;173};174175/*176* Create an argument vector from /line/. The caller must free(3)177* /avp/, and /avp[0]/ when the argument vector is no longer178* needed unless /acp/ is 0, in which case /avp/ is undefined.179* /avp/ is NULL-terminated, so it is actually one longer than /acp/.180*/181void182tokenize(const char *line, int *acp, char ***avp)183{184static const char *delims = " \t\n";185struct ptrstq *pt;186STAILQ_HEAD(, ptrstq) plist;187char **ap, *cp, *wline, *xcp;188189line += strspn(line, delims);190wline = strdup(line);191if (wline == NULL)192errx(1, "cannot allocate memory");193194STAILQ_INIT(&plist);195for (xcp = wline, *acp = 0;196(cp = strsep(&xcp, delims)) != NULL;)197if (*cp != '\0') {198pt = calloc(1, sizeof(*pt));199if (pt == NULL)200errx(1, "cannot allocate memory");201pt->ptr = cp;202STAILQ_INSERT_TAIL(&plist, pt, tq);203++*acp;204}205if (*acp == 0)206return;207assert(STAILQ_FIRST(&plist)->ptr == wline);208*avp = malloc(sizeof(**avp) * (*acp + 1));209if (*avp == NULL)210errx(1, "cannot allocate memory");211for (ap = *avp; !STAILQ_EMPTY(&plist);) {212pt = STAILQ_FIRST(&plist);213*ap = pt->ptr;214++ap;215assert(ap <= *avp + (*acp));216STAILQ_REMOVE_HEAD(&plist, tq);217free(pt);218}219*ap = NULL;220}221222void223usage(void)224{225226fprintf(stderr, "usage: %s\n%s\n",227"\tdevfs [-m mount-point] rule [-s ruleset] ...",228"\tdevfs [-m mount-point] ruleset ...");229exit(1);230}231232233