1 1.9 maxv /* $NetBSD: devicename.c,v 1.9 2016/08/15 09:00:52 maxv Exp $ */ 2 1.1 cherry 3 1.1 cherry /*- 4 1.1 cherry * Copyright (c) 1998 Michael Smith <msmith (at) freebsd.org> 5 1.1 cherry * All rights reserved. 6 1.1 cherry * 7 1.1 cherry * Redistribution and use in source and binary forms, with or without 8 1.1 cherry * modification, are permitted provided that the following conditions 9 1.1 cherry * are met: 10 1.1 cherry * 1. Redistributions of source code must retain the above copyright 11 1.1 cherry * notice, this list of conditions and the following disclaimer. 12 1.1 cherry * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cherry * notice, this list of conditions and the following disclaimer in the 14 1.1 cherry * documentation and/or other materials provided with the distribution. 15 1.1 cherry * 16 1.1 cherry * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 cherry * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 cherry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 cherry * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 cherry * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 cherry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 cherry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 cherry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 cherry * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 cherry * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 cherry * SUCH DAMAGE. 27 1.1 cherry */ 28 1.1 cherry 29 1.1 cherry #include <sys/cdefs.h> 30 1.1 cherry 31 1.2 cherry /* __FBSDID("$FreeBSD: src/sys/boot/efi/libefi/devicename.c,v 1.3 2004/01/04 23:28:16 obrien Exp $"); */ 32 1.2 cherry 33 1.1 cherry #include <lib/libsa/stand.h> 34 1.4 kiyohara #include <lib/libsa/loadfile.h> 35 1.5 martin #include <lib/libkern/libkern.h> 36 1.1 cherry #include <sys/disklabel.h> 37 1.1 cherry 38 1.1 cherry #include <bootstrap.h> 39 1.1 cherry 40 1.1 cherry #include <efi.h> 41 1.1 cherry #include <efilib.h> 42 1.1 cherry #include "efiboot.h" 43 1.1 cherry 44 1.1 cherry static int efi_parsedev(struct efi_devdesc **dev, const char *devspec, const char **path); 45 1.1 cherry 46 1.1 cherry /* 47 1.1 cherry * Point (dev) at an allocated device specifier for the device matching the 48 1.1 cherry * path in (devspec). If it contains an explicit device specification, 49 1.1 cherry * use that. If not, use the default device. 50 1.1 cherry */ 51 1.1 cherry int 52 1.1 cherry efi_getdev(void **vdev, const char *devspec, const char **path) 53 1.1 cherry { 54 1.1 cherry struct efi_devdesc **dev = (struct efi_devdesc **)vdev; 55 1.1 cherry int rv; 56 1.1 cherry 57 1.1 cherry /* 58 1.1 cherry * If it looks like this is just a path and no 59 1.1 cherry * device, go with the current device. 60 1.1 cherry */ 61 1.1 cherry if ((devspec == NULL) || 62 1.1 cherry (devspec[0] == '/') || 63 1.1 cherry (strchr(devspec, ':') == NULL)) { 64 1.1 cherry 65 1.1 cherry if (((rv = efi_parsedev(dev, getenv("currdev"), NULL)) == 0) && 66 1.1 cherry (path != NULL)) 67 1.1 cherry *path = devspec; 68 1.1 cherry return(rv); 69 1.1 cherry } 70 1.1 cherry 71 1.1 cherry /* 72 1.1 cherry * Try to parse the device name off the beginning of the devspec 73 1.1 cherry */ 74 1.1 cherry return(efi_parsedev(dev, devspec, path)); 75 1.1 cherry } 76 1.1 cherry 77 1.1 cherry /* 78 1.1 cherry * Point (dev) at an allocated device specifier matching the string version 79 1.1 cherry * at the beginning of (devspec). Return a pointer to the remaining 80 1.1 cherry * text in (path). 81 1.1 cherry * 82 1.1 cherry * In all cases, the beginning of (devspec) is compared to the names 83 1.1 cherry * of known devices in the device switch, and then any following text 84 1.1 cherry * is parsed according to the rules applied to the device type. 85 1.1 cherry * 86 1.1 cherry * For disk-type devices, the syntax is: 87 1.1 cherry * 88 1.1 cherry * disk<unit>[s<slice>][<partition>]: 89 1.1 cherry * 90 1.1 cherry */ 91 1.1 cherry static int 92 1.1 cherry efi_parsedev(struct efi_devdesc **dev, const char *devspec, const char **path) 93 1.1 cherry { 94 1.1 cherry struct efi_devdesc *idev; 95 1.1 cherry struct devsw *dv; 96 1.1 cherry int dv_type; 97 1.1 cherry int i, unit, slice, partition, err; 98 1.9 maxv char *cp = NULL; 99 1.1 cherry const char *np; 100 1.1 cherry 101 1.1 cherry /* minimum length check */ 102 1.1 cherry if (strlen(devspec) < 2) 103 1.1 cherry return(EINVAL); 104 1.1 cherry 105 1.1 cherry /* look for a device that matches */ 106 1.1 cherry for (i = 0, dv = NULL; i < ndevs; i++) { 107 1.1 cherry if (!strncmp(devspec, devsw[i].dv_name, strlen(devsw[i].dv_name))) { 108 1.1 cherry dv = &devsw[i]; 109 1.1 cherry break; 110 1.1 cherry } 111 1.1 cherry } 112 1.1 cherry 113 1.1 cherry if (dv == NULL) 114 1.1 cherry return(ENOENT); 115 1.1 cherry idev = alloc(sizeof(struct efi_devdesc)); 116 1.1 cherry err = 0; 117 1.1 cherry np = (devspec + strlen(dv->dv_name)); 118 1.1 cherry 119 1.1 cherry dv_type = DEVT_NONE; 120 1.1 cherry if (!strncmp("disk", dv->dv_name, 4)) dv_type = DEVT_DISK; 121 1.1 cherry if (!strncmp("net", dv->dv_name, 3)) dv_type = DEVT_DISK; 122 1.1 cherry 123 1.1 cherry switch(dv_type) { 124 1.1 cherry case DEVT_NONE: /* XXX what to do here? Do we care? */ 125 1.1 cherry break; 126 1.1 cherry 127 1.1 cherry case DEVT_DISK: 128 1.1 cherry unit = -1; 129 1.1 cherry slice = -1; 130 1.1 cherry partition = -1; 131 1.1 cherry if (*np && (*np != ':')) { 132 1.1 cherry unit = strtol(np, &cp, 10); /* next comes the unit number */ 133 1.1 cherry if (cp == np) { 134 1.1 cherry err = EUNIT; 135 1.1 cherry goto fail; 136 1.1 cherry } 137 1.1 cherry if (*cp == 's') { /* got a slice number */ 138 1.1 cherry np = cp + 1; 139 1.1 cherry slice = strtol(np, &cp, 10); 140 1.1 cherry if (cp == np) { 141 1.3 christos err = EPART; /* XXX : NetBSD calls a FreeBSD SLICE, a Partition! */ 142 1.1 cherry goto fail; 143 1.1 cherry } 144 1.1 cherry } 145 1.1 cherry if (*cp && (*cp != ':')) { 146 1.1 cherry partition = *cp - 'a'; /* get a partition number */ 147 1.1 cherry if ((partition < 0) || (partition >= MAXPARTITIONS)) { 148 1.1 cherry err = EPART; 149 1.1 cherry goto fail; 150 1.1 cherry } 151 1.1 cherry cp++; 152 1.1 cherry } 153 1.1 cherry } 154 1.9 maxv if (cp == NULL) { 155 1.9 maxv err = EINVAL; 156 1.9 maxv goto fail; 157 1.9 maxv } 158 1.1 cherry if (*cp && (*cp != ':')) { 159 1.1 cherry err = EINVAL; 160 1.1 cherry goto fail; 161 1.1 cherry } 162 1.1 cherry 163 1.1 cherry idev->d_kind.efidisk.unit = unit; 164 1.1 cherry idev->d_kind.efidisk.slice = slice; 165 1.1 cherry idev->d_kind.efidisk.partition = partition; 166 1.1 cherry 167 1.1 cherry if (path != NULL) 168 1.1 cherry *path = (*cp == 0) ? cp : cp + 1; 169 1.1 cherry break; 170 1.1 cherry 171 1.1 cherry case DEVT_NET: 172 1.1 cherry unit = 0; 173 1.1 cherry 174 1.1 cherry if (*np && (*np != ':')) { 175 1.1 cherry unit = strtol(np, &cp, 0); /* get unit number if present */ 176 1.1 cherry if (cp == np) { 177 1.1 cherry err = EUNIT; 178 1.1 cherry goto fail; 179 1.1 cherry } 180 1.1 cherry } 181 1.9 maxv if (cp == NULL) { 182 1.9 maxv err = EINVAL; 183 1.9 maxv goto fail; 184 1.9 maxv } 185 1.1 cherry if (*cp && (*cp != ':')) { 186 1.1 cherry err = EINVAL; 187 1.1 cherry goto fail; 188 1.1 cherry } 189 1.1 cherry 190 1.1 cherry idev->d_kind.netif.unit = unit; 191 1.1 cherry if (path != NULL) 192 1.1 cherry *path = (*cp == 0) ? cp : cp + 1; 193 1.1 cherry break; 194 1.1 cherry 195 1.1 cherry default: 196 1.1 cherry err = EINVAL; 197 1.1 cherry goto fail; 198 1.1 cherry } 199 1.1 cherry idev->d_dev = dv; 200 1.1 cherry idev->d_type = dv_type; 201 1.1 cherry if (dev == NULL) { 202 1.1 cherry free(idev); 203 1.1 cherry } else { 204 1.1 cherry *dev = idev; 205 1.1 cherry } 206 1.1 cherry return(0); 207 1.1 cherry 208 1.1 cherry fail: 209 1.1 cherry free(idev); 210 1.1 cherry return(err); 211 1.1 cherry } 212 1.1 cherry 213 1.1 cherry 214 1.1 cherry char * 215 1.1 cherry efi_fmtdev(void *vdev) 216 1.1 cherry { 217 1.1 cherry struct efi_devdesc *dev = (struct efi_devdesc *)vdev; 218 1.1 cherry static char buf[128]; /* XXX device length constant? */ 219 1.7 christos size_t len, buflen = sizeof(buf); 220 1.1 cherry 221 1.1 cherry switch(dev->d_type) { 222 1.1 cherry case DEVT_NONE: 223 1.6 christos strlcpy(buf, "(no device)", sizeof(buf)); 224 1.1 cherry break; 225 1.1 cherry 226 1.1 cherry case DEVT_DISK: 227 1.7 christos len = snprintf(buf, buflen, "%s%d", dev->d_dev->dv_name, dev->d_kind.efidisk.unit); 228 1.7 christos if (len > buflen) 229 1.7 christos len = buflen; 230 1.7 christos if (dev->d_kind.efidisk.slice > 0) { 231 1.7 christos len += snprintf(buf + len, buflen - len, "s%d", dev->d_kind.efidisk.slice); 232 1.7 christos if (len > buflen) 233 1.7 christos len = buflen; 234 1.7 christos } 235 1.7 christos if (dev->d_kind.efidisk.partition >= 0) { 236 1.7 christos len += snprintf(buf + len, buflen - len, "%c", dev->d_kind.efidisk.partition + 'a'); 237 1.7 christos if (len > buflen) 238 1.8 martin len = buflen; 239 1.7 christos } 240 1.6 christos strlcat(buf, ":", sizeof(buf) - len); 241 1.1 cherry break; 242 1.1 cherry 243 1.1 cherry case DEVT_NET: 244 1.7 christos snprintf(buf, buflen, "%s%d:", dev->d_dev->dv_name, dev->d_kind.netif.unit); 245 1.1 cherry break; 246 1.1 cherry } 247 1.1 cherry return(buf); 248 1.1 cherry } 249 1.1 cherry 250 1.1 cherry 251 1.1 cherry /* 252 1.1 cherry * Set currdev to suit the value being supplied in (value) 253 1.1 cherry */ 254 1.1 cherry int 255 1.1 cherry efi_setcurrdev(struct env_var *ev, int flags, void *value) 256 1.1 cherry { 257 1.1 cherry struct efi_devdesc *ncurr; 258 1.1 cherry int rv; 259 1.1 cherry 260 1.1 cherry if ((rv = efi_parsedev(&ncurr, value, NULL)) != 0) 261 1.1 cherry return(rv); 262 1.1 cherry free(ncurr); 263 1.1 cherry env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 264 1.1 cherry return(0); 265 1.1 cherry } 266 1.1 cherry 267