1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2001, 2002 Dima Dorfman. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * DEVFS control. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/queue.h> 35 36 #include <assert.h> 37 #include <err.h> 38 #include <fcntl.h> 39 #include <paths.h> 40 #include <stdio.h> 41 #include <stdint.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "extern.h" 47 48 int mpfd; 49 50 static ctbl_t ctbl_main = { 51 { "rule", rule_main }, 52 { "ruleset", ruleset_main }, 53 { NULL, NULL } 54 }; 55 56 int 57 main(int ac, char **av) 58 { 59 const char *mountpt; 60 struct cmd *c; 61 int 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 */ 95 int 96 atonum(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 */ 111 int 112 eatoi(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 */ 126 uint16_t 127 eatonum(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 */ 143 size_t 144 efgetln(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 171 struct 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 */ 182 void 183 tokenize(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 223 void 224 usage(void) 225 { 226 227 fprintf(stderr, "usage: %s\n%s\n", 228 "\tdevfs [-m mount-point] rule [-s ruleset] ...", 229 "\tdevfs [-m mount-point] ruleset ..."); 230 exit(1); 231 } 232