1 /* $NetBSD: dev.c,v 1.4 1994/10/30 21:48:23 cgd Exp $ */ 2 3 /*- 4 * Copyright (c) 1993 5 * The Regents of the University of California. 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 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/reboot.h> 34 35 #include "stand.h" 36 37 int 38 nodev(void) 39 { 40 return (ENXIO); 41 } 42 43 void 44 nullsys(void) 45 { 46 } 47 48 /* ARGSUSED */ 49 int 50 noioctl(struct open_file *f __unused, u_long cmd __unused, void *data __unused) 51 { 52 return (EINVAL); 53 } 54 55 char * 56 devformat(struct devdesc *d) 57 { 58 static char name[DEV_DEVLEN]; 59 60 if (d->d_dev->dv_fmtdev != NULL) 61 return (d->d_dev->dv_fmtdev(d)); 62 snprintf(name, sizeof(name), "%s%d:", d->d_dev->dv_name, d->d_unit); 63 return (name); 64 } 65 66 /* NB: devspec points to the remainder of the device name after dv_name */ 67 int 68 default_parsedev(struct devdesc **dev, const char *devspec, 69 const char **path) 70 { 71 struct devdesc *idev; 72 int unit, err; 73 char *cp; 74 75 idev = malloc(sizeof(struct devdesc)); 76 if (idev == NULL) 77 return (ENOMEM); 78 79 unit = 0; 80 cp = (char *)devspec; /* strtol interface, alas */ 81 82 if (*devspec != '\0' && *devspec != ':') { 83 errno = 0; 84 unit = strtol(devspec, &cp, 0); 85 if (errno != 0 || cp == devspec) { 86 err = EUNIT; 87 goto fail; 88 } 89 } 90 if (*cp != '\0' && *cp != ':') { 91 err = EINVAL; 92 goto fail; 93 } 94 95 idev->d_unit = unit; 96 if (path != NULL) 97 *path = (*cp == 0) ? cp : cp + 1; 98 *dev = idev; 99 return (0); 100 fail: 101 free(idev); 102 return (err); 103 } 104 105 /* 106 * Helper for URI-syntax devices. NB: like default_parsedev(), devspec is 107 * the remainder after dv_name. Parses "[N]://host[:port][/path]"; EINVAL 108 * if devspec doesn't match that pattern. 109 */ 110 int 111 parse_uri(const char *devspec, int *unitp, char **hostp, int *portp, 112 const char **pathp) 113 { 114 const char *cp, *p; 115 char *end; 116 int unit; 117 118 cp = devspec; 119 unit = 0; 120 if (*cp != '\0' && *cp != ':') { 121 errno = 0; 122 unit = strtol(cp, &end, 0); 123 if (errno != 0 || end == cp) 124 return (EINVAL); 125 cp = end; 126 } 127 if (strncmp(cp, "://", 3) != 0) 128 return (EINVAL); 129 cp += 3; 130 131 p = cp; 132 while (*p != '\0' && *p != '/' && *p != ':') 133 p++; 134 if (p == cp) 135 return (EINVAL); /* empty host */ 136 137 *hostp = malloc(p - cp + 1); 138 if (*hostp == NULL) 139 return (ENOMEM); 140 memcpy(*hostp, cp, p - cp); 141 (*hostp)[p - cp] = '\0'; 142 143 *portp = 0; 144 if (*p == ':') { 145 p++; 146 errno = 0; 147 *portp = strtol(p, &end, 10); 148 if (errno != 0 || end == p) { 149 free(*hostp); 150 *hostp = NULL; 151 return (EINVAL); 152 } 153 p = end; 154 } 155 156 if (*p != '\0' && *p != '/') { 157 free(*hostp); 158 *hostp = NULL; 159 return (EINVAL); 160 } 161 162 *unitp = unit; 163 if (pathp != NULL) 164 *pathp = p; 165 return (0); 166 } 167 168 /* NB: devspec points to the whole device spec, and possible trailing path */ 169 int 170 devparse(struct devdesc **dev, const char *devspec, const char **path) 171 { 172 struct devdesc *idev; 173 struct devsw *dv; 174 int i, err; 175 const char *np; 176 177 /* minimum length check */ 178 if (strlen(devspec) < 2) 179 return (EINVAL); 180 181 /* look for a device that matches */ 182 for (i = 0; devsw[i] != NULL; i++) { 183 dv = devsw[i]; 184 if (dv->dv_match != NULL) { 185 if (dv->dv_match(dv, devspec) != 0) 186 break; 187 } else { 188 if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name))) 189 break; 190 } 191 } 192 if (devsw[i] == NULL) 193 return (ENOENT); 194 idev = NULL; 195 err = 0; 196 if (dv->dv_parsedev) { 197 err = dv->dv_parsedev(&idev, devspec, path); 198 } else { 199 np = devspec + strlen(dv->dv_name); 200 err = default_parsedev(&idev, np, path); 201 } 202 if (err != 0) 203 return (err); 204 205 idev->d_dev = dv; 206 if (dev != NULL) 207 *dev = idev; 208 else 209 free(idev); 210 return (0); 211 } 212 213 int 214 devinit(void) 215 { 216 int err = 0; 217 218 /* 219 * March through the device switch probing for things. 220 */ 221 for (int i = 0; devsw[i] != NULL; i++) { 222 if (devsw[i]->dv_init != NULL) { 223 if ((devsw[i]->dv_init)() != 0) { 224 err++; 225 } 226 } 227 } 228 return (err); 229 } 230 231 void 232 dev_cleanup(void) 233 { 234 int i; 235 236 /* Call cleanup routines */ 237 for (i = 0; devsw[i] != NULL; ++i) 238 if (devsw[i]->dv_cleanup != NULL) 239 (devsw[i]->dv_cleanup)(); 240 } 241