devfs.c revision 100805
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: head/sbin/devfs/devfs.c 100805 2002-07-28 06:59:40Z dd $"); 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> 42100206Sdd#include <stdlib.h> 43100206Sdd#include <string.h> 44100206Sdd#include <unistd.h> 45100206Sdd 46100206Sdd#include "extern.h" 47100206Sdd 48100206Sddint mpfd; 49100206Sdd 50100206Sddstatic ctbl_t ctbl_main = { 51100206Sdd { "rule", rule_main }, 52100206Sdd { "ruleset", ruleset_main }, 53100206Sdd { NULL, NULL } 54100206Sdd}; 55100206Sdd 56100206Sddint 57100206Sddmain(int ac, char **av) 58100206Sdd{ 59100206Sdd const char *mountpt; 60100206Sdd struct cmd *c; 61100206Sdd char ch; 62100206Sdd 63100206Sdd mountpt = NULL; 64100206Sdd while ((ch = getopt(ac, av, "m:")) != -1) 65100206Sdd switch (ch) { 66100206Sdd case 'm': 67100206Sdd mountpt = optarg; 68100206Sdd break; 69100206Sdd default: 70100206Sdd usage(); 71100206Sdd } 72100206Sdd ac -= optind; 73100206Sdd av += optind; 74100206Sdd if (ac < 1) 75100206Sdd usage(); 76100206Sdd 77100206Sdd if (mountpt == NULL) 78100206Sdd mountpt = _PATH_DEV; 79100206Sdd mpfd = open(mountpt, O_RDONLY); 80100206Sdd if (mpfd == -1) 81100206Sdd err(1, "open: %s", mountpt); 82100206Sdd 83100206Sdd for (c = ctbl_main; c->name != NULL; ++c) 84100206Sdd if (strcmp(c->name, av[0]) == 0) 85100206Sdd exit((*c->handler)(ac, av)); 86100206Sdd errx(1, "unknown command: %s", av[0]); 87100206Sdd} 88100206Sdd 89100206Sdd/* 90100206Sdd * Convert an integer to a "number" (ruleset numbers and rule numbers 91100206Sdd * are 16-bit). If the conversion is successful, num contains the 92100206Sdd * integer representation of s and 1 is returned; otherwise, 0 is 93100206Sdd * returned and num is unchanged. 94100206Sdd */ 95100206Sddint 96100206Sddatonum(const char *s, uint16_t *num) 97100206Sdd{ 98100206Sdd unsigned long ul; 99100206Sdd char *cp; 100100206Sdd 101100206Sdd ul = strtoul(s, &cp, 10); 102100206Sdd if (ul > UINT16_MAX || *cp != '\0') 103100206Sdd return (0); 104100206Sdd *num = (uint16_t)ul; 105100206Sdd return (1); 106100206Sdd} 107100206Sdd 108100206Sdd/* 109100206Sdd * Convert user input in ASCII to an integer. 110100206Sdd */ 111100206Sddint 112100206Sddeatoi(const char *s) 113100206Sdd{ 114100206Sdd char *cp; 115100206Sdd long l; 116100206Sdd 117100206Sdd l = strtol(s, &cp, 10); 118100206Sdd if (l > INT_MAX || *cp != '\0') 119100206Sdd errx(1, "error converting to integer: %s", s); 120100206Sdd return ((int)l); 121100805Sdd} 122100206Sdd 123100206Sdd/* 124100206Sdd * As atonum(), but the result of failure is death. 125100206Sdd */ 126100206Sdduint16_t 127100206Sddeatonum(const char *s) 128100206Sdd{ 129100206Sdd uint16_t num; 130100206Sdd 131100206Sdd if (!atonum(s, &num)) 132100206Sdd errx(1, "error converting to number: %s", s); /* XXX clarify */ 133100206Sdd return (num); 134100805Sdd} 135100206Sdd 136100799Sdd/* 137100799Sdd * Read a line from a /FILE/. If the return value isn't 0, it is the 138100799Sdd * length of the line, a pointer to which exists in /line/. It is the 139100799Sdd * caller's responsibility to free(3) it. If the return value is 0, 140100799Sdd * there was an error or we reached EOF, and /line/ is undefined (so, 141100799Sdd * obviously, the caller shouldn't try to free(3) it). 142100799Sdd */ 143100799Sddsize_t 144100799Sddefgetln(FILE *fp, char **line) 145100799Sdd{ 146100799Sdd size_t rv; 147100799Sdd char *cp; 148100799Sdd 149100799Sdd cp = fgetln(fp, &rv); 150100799Sdd if (cp == NULL) { 151100799Sdd *line = NULL; 152100799Sdd return (rv); 153100799Sdd } 154100799Sdd if (cp[rv - 1] == '\n') { 155100799Sdd cp[rv - 1] = '\0'; 156100799Sdd *line = strdup(cp); 157100799Sdd if (*line == NULL) 158100799Sdd errx(1, "cannot allocate memory"); 159100799Sdd --rv; 160100799Sdd } else { 161100799Sdd *line = malloc(rv + 1); 162100799Sdd if (*line == NULL) 163100799Sdd errx(1, "cannot allocate memory"); 164100799Sdd memcpy(*line, cp, rv); 165100799Sdd *line[rv] = '\0'; 166100799Sdd } 167100799Sdd assert(rv == strlen(*line)); 168100799Sdd return (rv); 169100799Sdd} 170100799Sdd 171100799Sddstruct ptrstq { 172100799Sdd STAILQ_ENTRY(ptrstq) tq; 173100799Sdd void *ptr; 174100799Sdd}; 175100799Sdd 176100799Sdd/* 177100799Sdd * Create an argument vector from /line/. The caller must free(3) 178100799Sdd * /avp/, and /avp[0]/ when the argument vector is no longer 179100799Sdd * needed unless /acp/ is 0, in which case /avp/ is undefined. 180100799Sdd * /avp/ is NULL-terminated, so it is actually one longer than /acp/. 181100799Sdd */ 182100206Sddvoid 183100799Sddtokenize(const char *line, int *acp, char ***avp) 184100799Sdd{ 185100799Sdd static const char *delims = " \t\n"; 186100799Sdd struct ptrstq *pt; 187100799Sdd STAILQ_HEAD(, ptrstq) plist; 188100799Sdd char **ap, *cp, *wline, *xcp; 189100799Sdd 190100799Sdd line += strspn(line, delims); 191100799Sdd wline = strdup(line); 192100799Sdd if (wline == NULL) 193100799Sdd errx(1, "cannot allocate memory"); 194100799Sdd 195100799Sdd STAILQ_INIT(&plist); 196100799Sdd for (xcp = wline, *acp = 0; 197100799Sdd (cp = strsep(&xcp, delims)) != NULL;) 198100799Sdd if (*cp != '\0') { 199100799Sdd pt = calloc(1, sizeof(*pt)); 200100799Sdd if (pt == NULL) 201100799Sdd errx(1, "cannot allocate memory"); 202100799Sdd pt->ptr = cp; 203100799Sdd STAILQ_INSERT_TAIL(&plist, pt, tq); 204100799Sdd ++*acp; 205100799Sdd } 206100799Sdd if (*acp == 0) 207100799Sdd return; 208100799Sdd assert(STAILQ_FIRST(&plist)->ptr == wline); 209100799Sdd *avp = malloc(sizeof(**avp) * (*acp + 1)); 210100799Sdd if (*avp == NULL) 211100799Sdd errx(1, "cannot allocate memory"); 212100799Sdd for (ap = *avp; !STAILQ_EMPTY(&plist);) { 213100799Sdd pt = STAILQ_FIRST(&plist); 214100799Sdd *ap = pt->ptr; 215100799Sdd ++ap; 216100799Sdd assert(ap <= *avp + (*acp)); 217100799Sdd STAILQ_REMOVE_HEAD(&plist, tq); 218100799Sdd free(pt); 219100799Sdd } 220100799Sdd *ap = NULL; 221100799Sdd} 222100799Sdd 223100799Sddvoid 224100206Sddusage(void) 225100206Sdd{ 226100206Sdd 227100206Sdd fprintf(stderr, "usage: devfs rule|ruleset arguments\n"); 228100206Sdd exit(1); 229100206Sdd} 230