devfs.c revision 100805
1/*- 2 * Copyright (c) 2001, 2002 Dima Dorfman. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * DEVFS control. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sbin/devfs/devfs.c 100805 2002-07-28 06:59:40Z dd $"); 33 34#include <sys/param.h> 35#include <sys/queue.h> 36 37#include <assert.h> 38#include <err.h> 39#include <fcntl.h> 40#include <paths.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <unistd.h> 45 46#include "extern.h" 47 48int mpfd; 49 50static ctbl_t ctbl_main = { 51 { "rule", rule_main }, 52 { "ruleset", ruleset_main }, 53 { NULL, NULL } 54}; 55 56int 57main(int ac, char **av) 58{ 59 const char *mountpt; 60 struct cmd *c; 61 char ch; 62 63 mountpt = NULL; 64 while ((ch = getopt(ac, av, "m:")) != -1) 65 switch (ch) { 66 case 'm': 67 mountpt = optarg; 68 break; 69 default: 70 usage(); 71 } 72 ac -= optind; 73 av += optind; 74 if (ac < 1) 75 usage(); 76 77 if (mountpt == NULL) 78 mountpt = _PATH_DEV; 79 mpfd = open(mountpt, O_RDONLY); 80 if (mpfd == -1) 81 err(1, "open: %s", mountpt); 82 83 for (c = ctbl_main; c->name != NULL; ++c) 84 if (strcmp(c->name, av[0]) == 0) 85 exit((*c->handler)(ac, av)); 86 errx(1, "unknown command: %s", av[0]); 87} 88 89/* 90 * Convert an integer to a "number" (ruleset numbers and rule numbers 91 * are 16-bit). If the conversion is successful, num contains the 92 * integer representation of s and 1 is returned; otherwise, 0 is 93 * returned and num is unchanged. 94 */ 95int 96atonum(const char *s, uint16_t *num) 97{ 98 unsigned long ul; 99 char *cp; 100 101 ul = strtoul(s, &cp, 10); 102 if (ul > UINT16_MAX || *cp != '\0') 103 return (0); 104 *num = (uint16_t)ul; 105 return (1); 106} 107 108/* 109 * Convert user input in ASCII to an integer. 110 */ 111int 112eatoi(const char *s) 113{ 114 char *cp; 115 long l; 116 117 l = strtol(s, &cp, 10); 118 if (l > INT_MAX || *cp != '\0') 119 errx(1, "error converting to integer: %s", s); 120 return ((int)l); 121} 122 123/* 124 * As atonum(), but the result of failure is death. 125 */ 126uint16_t 127eatonum(const char *s) 128{ 129 uint16_t num; 130 131 if (!atonum(s, &num)) 132 errx(1, "error converting to number: %s", s); /* XXX clarify */ 133 return (num); 134} 135 136/* 137 * Read a line from a /FILE/. If the return value isn't 0, it is the 138 * length of the line, a pointer to which exists in /line/. It is the 139 * caller's responsibility to free(3) it. If the return value is 0, 140 * there was an error or we reached EOF, and /line/ is undefined (so, 141 * obviously, the caller shouldn't try to free(3) it). 142 */ 143size_t 144efgetln(FILE *fp, char **line) 145{ 146 size_t rv; 147 char *cp; 148 149 cp = fgetln(fp, &rv); 150 if (cp == NULL) { 151 *line = NULL; 152 return (rv); 153 } 154 if (cp[rv - 1] == '\n') { 155 cp[rv - 1] = '\0'; 156 *line = strdup(cp); 157 if (*line == NULL) 158 errx(1, "cannot allocate memory"); 159 --rv; 160 } else { 161 *line = malloc(rv + 1); 162 if (*line == NULL) 163 errx(1, "cannot allocate memory"); 164 memcpy(*line, cp, rv); 165 *line[rv] = '\0'; 166 } 167 assert(rv == strlen(*line)); 168 return (rv); 169} 170 171struct ptrstq { 172 STAILQ_ENTRY(ptrstq) tq; 173 void *ptr; 174}; 175 176/* 177 * Create an argument vector from /line/. The caller must free(3) 178 * /avp/, and /avp[0]/ when the argument vector is no longer 179 * needed unless /acp/ is 0, in which case /avp/ is undefined. 180 * /avp/ is NULL-terminated, so it is actually one longer than /acp/. 181 */ 182void 183tokenize(const char *line, int *acp, char ***avp) 184{ 185 static const char *delims = " \t\n"; 186 struct ptrstq *pt; 187 STAILQ_HEAD(, ptrstq) plist; 188 char **ap, *cp, *wline, *xcp; 189 190 line += strspn(line, delims); 191 wline = strdup(line); 192 if (wline == NULL) 193 errx(1, "cannot allocate memory"); 194 195 STAILQ_INIT(&plist); 196 for (xcp = wline, *acp = 0; 197 (cp = strsep(&xcp, delims)) != NULL;) 198 if (*cp != '\0') { 199 pt = calloc(1, sizeof(*pt)); 200 if (pt == NULL) 201 errx(1, "cannot allocate memory"); 202 pt->ptr = cp; 203 STAILQ_INSERT_TAIL(&plist, pt, tq); 204 ++*acp; 205 } 206 if (*acp == 0) 207 return; 208 assert(STAILQ_FIRST(&plist)->ptr == wline); 209 *avp = malloc(sizeof(**avp) * (*acp + 1)); 210 if (*avp == NULL) 211 errx(1, "cannot allocate memory"); 212 for (ap = *avp; !STAILQ_EMPTY(&plist);) { 213 pt = STAILQ_FIRST(&plist); 214 *ap = pt->ptr; 215 ++ap; 216 assert(ap <= *avp + (*acp)); 217 STAILQ_REMOVE_HEAD(&plist, tq); 218 free(pt); 219 } 220 *ap = NULL; 221} 222 223void 224usage(void) 225{ 226 227 fprintf(stderr, "usage: devfs rule|ruleset arguments\n"); 228 exit(1); 229} 230