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