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$"); 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 <stdint.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "extern.h" 48 49 int mpfd; 50 51 static ctbl_t ctbl_main = { 52 { "rule", rule_main }, 53 { "ruleset", ruleset_main }, 54 { NULL, NULL } 55 }; 56 57 int 58 main(int ac, char **av) 59 { 60 const char *mountpt; 61 struct cmd *c; 62 int ch; 63 64 mountpt = NULL; 65 while ((ch = getopt(ac, av, "m:")) != -1) 66 switch (ch) { 67 case 'm': 68 mountpt = optarg; 69 break; 70 default: 71 usage(); 72 } 73 ac -= optind; 74 av += optind; 75 if (ac < 1) 76 usage(); 77 78 if (mountpt == NULL) 79 mountpt = _PATH_DEV; 80 mpfd = open(mountpt, O_RDONLY); 81 if (mpfd == -1) 82 err(1, "open: %s", mountpt); 83 84 for (c = ctbl_main; c->name != NULL; ++c) 85 if (strcmp(c->name, av[0]) == 0) 86 exit((*c->handler)(ac, av)); 87 errx(1, "unknown command: %s", av[0]); 88 } 89 90 /* 91 * Convert an integer to a "number" (ruleset numbers and rule numbers 92 * are 16-bit). If the conversion is successful, num contains the 93 * integer representation of s and 1 is returned; otherwise, 0 is 94 * returned and num is unchanged. 95 */ 96 int 97 atonum(const char *s, uint16_t *num) 98 { 99 unsigned long ul; 100 char *cp; 101 102 ul = strtoul(s, &cp, 10); 103 if (ul > UINT16_MAX || *cp != '\0') 104 return (0); 105 *num = (uint16_t)ul; 106 return (1); 107 } 108 109 /* 110 * Convert user input in ASCII to an integer. 111 */ 112 int 113 eatoi(const char *s) 114 { 115 char *cp; 116 long l; 117 118 l = strtol(s, &cp, 10); 119 if (l > INT_MAX || *cp != '\0') 120 errx(1, "error converting to integer: %s", s); 121 return ((int)l); 122 } 123 124 /* 125 * As atonum(), but the result of failure is death. 126 */ 127 uint16_t 128 eatonum(const char *s) 129 { 130 uint16_t num; 131 132 if (!atonum(s, &num)) 133 errx(1, "error converting to number: %s", s); /* XXX clarify */ 134 return (num); 135 } 136 137 /* 138 * Read a line from a /FILE/. If the return value isn't 0, it is the 139 * length of the line, a pointer to which exists in /line/. It is the 140 * caller's responsibility to free(3) it. If the return value is 0, 141 * there was an error or we reached EOF, and /line/ is undefined (so, 142 * obviously, the caller shouldn't try to free(3) it). 143 */ 144 size_t 145 efgetln(FILE *fp, char **line) 146 { 147 size_t rv; 148 char *cp; 149 150 cp = fgetln(fp, &rv); 151 if (cp == NULL) { 152 *line = NULL; 153 return (rv); 154 } 155 if (cp[rv - 1] == '\n') { 156 cp[rv - 1] = '\0'; 157 *line = strdup(cp); 158 if (*line == NULL) 159 errx(1, "cannot allocate memory"); 160 --rv; 161 } else { 162 *line = malloc(rv + 1); 163 if (*line == NULL) 164 errx(1, "cannot allocate memory"); 165 memcpy(*line, cp, rv); 166 (*line)[rv] = '\0'; 167 } 168 assert(rv == strlen(*line)); 169 return (rv); 170 } 171 172 struct ptrstq { 173 STAILQ_ENTRY(ptrstq) tq; 174 void *ptr; 175 }; 176 177 /* 178 * Create an argument vector from /line/. The caller must free(3) 179 * /avp/, and /avp[0]/ when the argument vector is no longer 180 * needed unless /acp/ is 0, in which case /avp/ is undefined. 181 * /avp/ is NULL-terminated, so it is actually one longer than /acp/. 182 */ 183 void 184 tokenize(const char *line, int *acp, char ***avp) 185 { 186 static const char *delims = " \t\n"; 187 struct ptrstq *pt; 188 STAILQ_HEAD(, ptrstq) plist; 189 char **ap, *cp, *wline, *xcp; 190 191 line += strspn(line, delims); 192 wline = strdup(line); 193 if (wline == NULL) 194 errx(1, "cannot allocate memory"); 195 196 STAILQ_INIT(&plist); 197 for (xcp = wline, *acp = 0; 198 (cp = strsep(&xcp, delims)) != NULL;) 199 if (*cp != '\0') { 200 pt = calloc(1, sizeof(*pt)); 201 if (pt == NULL) 202 errx(1, "cannot allocate memory"); 203 pt->ptr = cp; 204 STAILQ_INSERT_TAIL(&plist, pt, tq); 205 ++*acp; 206 } 207 if (*acp == 0) 208 return; 209 assert(STAILQ_FIRST(&plist)->ptr == wline); 210 *avp = malloc(sizeof(**avp) * (*acp + 1)); 211 if (*avp == NULL) 212 errx(1, "cannot allocate memory"); 213 for (ap = *avp; !STAILQ_EMPTY(&plist);) { 214 pt = STAILQ_FIRST(&plist); 215 *ap = pt->ptr; 216 ++ap; 217 assert(ap <= *avp + (*acp)); 218 STAILQ_REMOVE_HEAD(&plist, tq); 219 free(pt); 220 } 221 *ap = NULL; 222 } 223 224 void 225 usage(void) 226 { 227 228 fprintf(stderr, "usage: %s\n%s\n", 229 "\tdevfs [-m mount-point] [-s ruleset] rule ...", 230 "\tdevfs [-m mount-point] ruleset ..."); 231 exit(1); 232 } 233