1100206Sdd/*- 2100799Sdd * Copyright (c) 2001, 2002 Dima Dorfman. 3100206Sdd * All rights reserved. 4100206Sdd * 5100206Sdd * Redistribution and use in source and binary forms, with or without 6100206Sdd * modification, are permitted provided that the following conditions 7100206Sdd * are met: 8100206Sdd * 1. Redistributions of source code must retain the above copyright 9100206Sdd * notice, this list of conditions and the following disclaimer. 10100206Sdd * 2. Redistributions in binary form must reproduce the above copyright 11100206Sdd * notice, this list of conditions and the following disclaimer in the 12100206Sdd * documentation and/or other materials provided with the distribution. 13100206Sdd * 14100206Sdd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15100206Sdd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16100206Sdd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17100206Sdd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18100206Sdd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19100206Sdd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20100206Sdd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21100206Sdd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22100206Sdd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23100206Sdd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24100206Sdd * SUCH DAMAGE. 25100206Sdd */ 26100206Sdd 27100206Sdd/* 28100206Sdd * DEVFS control. 29100206Sdd */ 30100206Sdd 31100206Sdd#include <sys/cdefs.h> 32100206Sdd__FBSDID("$FreeBSD: stable/10/sbin/devfs/devfs.c 315355 2017-03-16 01:59:43Z ngie $"); 33100206Sdd 34100206Sdd#include <sys/param.h> 35100799Sdd#include <sys/queue.h> 36100206Sdd 37100799Sdd#include <assert.h> 38100206Sdd#include <err.h> 39100206Sdd#include <fcntl.h> 40100206Sdd#include <paths.h> 41100206Sdd#include <stdio.h> 42100881Smike#include <stdint.h> 43100206Sdd#include <stdlib.h> 44100206Sdd#include <string.h> 45100206Sdd#include <unistd.h> 46100206Sdd 47100206Sdd#include "extern.h" 48100206Sdd 49100206Sddint mpfd; 50100206Sdd 51100206Sddstatic ctbl_t ctbl_main = { 52100206Sdd { "rule", rule_main }, 53100206Sdd { "ruleset", ruleset_main }, 54100206Sdd { NULL, NULL } 55100206Sdd}; 56100206Sdd 57100206Sddint 58100206Sddmain(int ac, char **av) 59100206Sdd{ 60100206Sdd const char *mountpt; 61100206Sdd struct cmd *c; 62124830Sgrehan int ch; 63100206Sdd 64100206Sdd mountpt = NULL; 65100206Sdd while ((ch = getopt(ac, av, "m:")) != -1) 66100206Sdd switch (ch) { 67100206Sdd case 'm': 68100206Sdd mountpt = optarg; 69100206Sdd break; 70100206Sdd default: 71100206Sdd usage(); 72100206Sdd } 73100206Sdd ac -= optind; 74100206Sdd av += optind; 75100206Sdd if (ac < 1) 76100206Sdd usage(); 77100206Sdd 78100206Sdd if (mountpt == NULL) 79100206Sdd mountpt = _PATH_DEV; 80100206Sdd mpfd = open(mountpt, O_RDONLY); 81100206Sdd if (mpfd == -1) 82100206Sdd err(1, "open: %s", mountpt); 83100206Sdd 84100206Sdd for (c = ctbl_main; c->name != NULL; ++c) 85100206Sdd if (strcmp(c->name, av[0]) == 0) 86100206Sdd exit((*c->handler)(ac, av)); 87100206Sdd errx(1, "unknown command: %s", av[0]); 88100206Sdd} 89100206Sdd 90100206Sdd/* 91100206Sdd * Convert an integer to a "number" (ruleset numbers and rule numbers 92100206Sdd * are 16-bit). If the conversion is successful, num contains the 93100206Sdd * integer representation of s and 1 is returned; otherwise, 0 is 94100206Sdd * returned and num is unchanged. 95100206Sdd */ 96100206Sddint 97100206Sddatonum(const char *s, uint16_t *num) 98100206Sdd{ 99100206Sdd unsigned long ul; 100100206Sdd char *cp; 101100206Sdd 102100206Sdd ul = strtoul(s, &cp, 10); 103100206Sdd if (ul > UINT16_MAX || *cp != '\0') 104100206Sdd return (0); 105100206Sdd *num = (uint16_t)ul; 106100206Sdd return (1); 107100206Sdd} 108100206Sdd 109100206Sdd/* 110100206Sdd * Convert user input in ASCII to an integer. 111100206Sdd */ 112100206Sddint 113100206Sddeatoi(const char *s) 114100206Sdd{ 115100206Sdd char *cp; 116100206Sdd long l; 117100206Sdd 118100206Sdd l = strtol(s, &cp, 10); 119100206Sdd if (l > INT_MAX || *cp != '\0') 120100206Sdd errx(1, "error converting to integer: %s", s); 121100206Sdd return ((int)l); 122100805Sdd} 123100206Sdd 124100206Sdd/* 125100206Sdd * As atonum(), but the result of failure is death. 126100206Sdd */ 127100206Sdduint16_t 128100206Sddeatonum(const char *s) 129100206Sdd{ 130100206Sdd uint16_t num; 131100206Sdd 132100206Sdd if (!atonum(s, &num)) 133100206Sdd errx(1, "error converting to number: %s", s); /* XXX clarify */ 134100206Sdd return (num); 135100805Sdd} 136100206Sdd 137100799Sdd/* 138100799Sdd * Read a line from a /FILE/. If the return value isn't 0, it is the 139100799Sdd * length of the line, a pointer to which exists in /line/. It is the 140100799Sdd * caller's responsibility to free(3) it. If the return value is 0, 141100799Sdd * there was an error or we reached EOF, and /line/ is undefined (so, 142100799Sdd * obviously, the caller shouldn't try to free(3) it). 143100799Sdd */ 144100799Sddsize_t 145100799Sddefgetln(FILE *fp, char **line) 146100799Sdd{ 147100799Sdd size_t rv; 148100799Sdd char *cp; 149100799Sdd 150100799Sdd cp = fgetln(fp, &rv); 151100799Sdd if (cp == NULL) { 152100799Sdd *line = NULL; 153100799Sdd return (rv); 154100799Sdd } 155100799Sdd if (cp[rv - 1] == '\n') { 156100799Sdd cp[rv - 1] = '\0'; 157100799Sdd *line = strdup(cp); 158100799Sdd if (*line == NULL) 159100799Sdd errx(1, "cannot allocate memory"); 160100799Sdd --rv; 161100799Sdd } else { 162100799Sdd *line = malloc(rv + 1); 163100799Sdd if (*line == NULL) 164100799Sdd errx(1, "cannot allocate memory"); 165159605Smaxim memcpy(*line, cp, rv); 166159605Smaxim (*line)[rv] = '\0'; 167100799Sdd } 168100799Sdd assert(rv == strlen(*line)); 169100799Sdd return (rv); 170100799Sdd} 171100799Sdd 172100799Sddstruct ptrstq { 173100799Sdd STAILQ_ENTRY(ptrstq) tq; 174100799Sdd void *ptr; 175100799Sdd}; 176100799Sdd 177100799Sdd/* 178100799Sdd * Create an argument vector from /line/. The caller must free(3) 179100799Sdd * /avp/, and /avp[0]/ when the argument vector is no longer 180100799Sdd * needed unless /acp/ is 0, in which case /avp/ is undefined. 181100799Sdd * /avp/ is NULL-terminated, so it is actually one longer than /acp/. 182100799Sdd */ 183100206Sddvoid 184100799Sddtokenize(const char *line, int *acp, char ***avp) 185100799Sdd{ 186100799Sdd static const char *delims = " \t\n"; 187100799Sdd struct ptrstq *pt; 188100799Sdd STAILQ_HEAD(, ptrstq) plist; 189100799Sdd char **ap, *cp, *wline, *xcp; 190100799Sdd 191100799Sdd line += strspn(line, delims); 192100799Sdd wline = strdup(line); 193100799Sdd if (wline == NULL) 194100799Sdd errx(1, "cannot allocate memory"); 195100799Sdd 196100799Sdd STAILQ_INIT(&plist); 197100799Sdd for (xcp = wline, *acp = 0; 198100799Sdd (cp = strsep(&xcp, delims)) != NULL;) 199100799Sdd if (*cp != '\0') { 200100799Sdd pt = calloc(1, sizeof(*pt)); 201100799Sdd if (pt == NULL) 202100799Sdd errx(1, "cannot allocate memory"); 203100799Sdd pt->ptr = cp; 204100799Sdd STAILQ_INSERT_TAIL(&plist, pt, tq); 205100799Sdd ++*acp; 206100799Sdd } 207100799Sdd if (*acp == 0) 208100799Sdd return; 209100799Sdd assert(STAILQ_FIRST(&plist)->ptr == wline); 210100799Sdd *avp = malloc(sizeof(**avp) * (*acp + 1)); 211100799Sdd if (*avp == NULL) 212100799Sdd errx(1, "cannot allocate memory"); 213100799Sdd for (ap = *avp; !STAILQ_EMPTY(&plist);) { 214100799Sdd pt = STAILQ_FIRST(&plist); 215100799Sdd *ap = pt->ptr; 216100799Sdd ++ap; 217100799Sdd assert(ap <= *avp + (*acp)); 218100799Sdd STAILQ_REMOVE_HEAD(&plist, tq); 219100799Sdd free(pt); 220100799Sdd } 221100799Sdd *ap = NULL; 222100799Sdd} 223100799Sdd 224100799Sddvoid 225100206Sddusage(void) 226100206Sdd{ 227100206Sdd 228315355Sngie fprintf(stderr, "usage: %s\n%s\n", 229315355Sngie "\tdevfs [-m mount-point] [-s ruleset] rule ...", 230315355Sngie "\tdevfs [-m mount-point] ruleset ..."); 231100206Sdd exit(1); 232100206Sdd} 233