devicename.c revision 86091
155714Skris/*- 255714Skris * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 355714Skris * All rights reserved. 455714Skris * 555714Skris * Redistribution and use in source and binary forms, with or without 655714Skris * modification, are permitted provided that the following conditions 755714Skris * are met: 855714Skris * 1. Redistributions of source code must retain the above copyright 955714Skris * notice, this list of conditions and the following disclaimer. 1055714Skris * 2. Redistributions in binary form must reproduce the above copyright 1155714Skris * notice, this list of conditions and the following disclaimer in the 1255714Skris * documentation and/or other materials provided with the distribution. 1355714Skris * 1455714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1568651Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1668651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1755714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1855714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1955714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2055714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2155714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2255714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2355714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2468651Skris * SUCH DAMAGE. 2568651Skris * 2655714Skris * $FreeBSD: head/sys/boot/i386/libi386/devicename.c 86091 2001-11-05 18:58:33Z jhb $ 2755714Skris */ 2855714Skris 2955714Skris#include <stand.h> 3055714Skris#include <string.h> 3155714Skris#include <sys/disklabel.h> 3255714Skris#include "bootstrap.h" 3355714Skris#include "libi386.h" 3455714Skris 3555714Skrisstatic int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path); 3655714Skris 3755714Skris/* 3855714Skris * Point (dev) at an allocated device specifier for the device matching the 3955714Skris * path in (devspec). If it contains an explicit device specification, 4055714Skris * use that. If not, use the default device. 4155714Skris */ 42160814Ssimonint 4355714Skrisi386_getdev(void **vdev, const char *devspec, const char **path) 4455714Skris{ 4555714Skris struct i386_devdesc **dev = (struct i386_devdesc **)vdev; 4655714Skris int rv; 4755714Skris 4855714Skris /* 4955714Skris * If it looks like this is just a path and no 5055714Skris * device, go with the current device. 5155714Skris */ 5255714Skris if ((devspec == NULL) || 5355714Skris (devspec[0] == '/') || 5455714Skris (strchr(devspec, ':') == NULL)) { 5555714Skris 5655714Skris if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) && 5755714Skris (path != NULL)) 5855714Skris *path = devspec; 5955714Skris return(rv); 6055714Skris } 6155714Skris 6255714Skris /* 6355714Skris * Try to parse the device name off the beginning of the devspec 6455714Skris */ 6555714Skris return(i386_parsedev(dev, devspec, path)); 6655714Skris} 6755714Skris 6855714Skris/* 6955714Skris * Point (dev) at an allocated device specifier matching the string version 7055714Skris * at the beginning of (devspec). Return a pointer to the remaining 7155714Skris * text in (path). 7255714Skris * 7355714Skris * In all cases, the beginning of (devspec) is compared to the names 7455714Skris * of known devices in the device switch, and then any following text 75160814Ssimon * is parsed according to the rules applied to the device type. 7655714Skris * 7755714Skris * For disk-type devices, the syntax is: 7855714Skris * 7955714Skris * disk<unit>[s<slice>][<partition>]: 8055714Skris * 81160814Ssimon */ 8255714Skrisstatic int 8355714Skrisi386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) 8455714Skris{ 8555714Skris struct i386_devdesc *idev; 8655714Skris struct devsw *dv; 8755714Skris int i, unit, slice, partition, err; 8855714Skris char *cp; 8955714Skris const char *np; 9055714Skris 9155714Skris /* minimum length check */ 9255714Skris if (strlen(devspec) < 2) 9355714Skris return(EINVAL); 9455714Skris 9555714Skris /* look for a device that matches */ 9655714Skris for (i = 0, dv = NULL; devsw[i] != NULL; i++) { 9755714Skris if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { 9855714Skris dv = devsw[i]; 9955714Skris break; 10055714Skris } 10155714Skris } 10255714Skris if (dv == NULL) 10355714Skris return(ENOENT); 10455714Skris idev = malloc(sizeof(struct i386_devdesc)); 105 err = 0; 106 np = (devspec + strlen(dv->dv_name)); 107 108 switch(dv->dv_type) { 109 case DEVT_NONE: /* XXX what to do here? Do we care? */ 110 break; 111 112 case DEVT_DISK: 113 unit = -1; 114 slice = -1; 115 partition = -1; 116 if (*np && (*np != ':')) { 117 unit = strtol(np, &cp, 10); /* next comes the unit number */ 118 if (cp == np) { 119 err = EUNIT; 120 goto fail; 121 } 122 if (*cp == 's') { /* got a slice number */ 123 np = cp + 1; 124 slice = strtol(np, &cp, 10); 125 if (cp == np) { 126 err = ESLICE; 127 goto fail; 128 } 129 } 130 if (*cp && (*cp != ':')) { 131 partition = *cp - 'a'; /* get a partition number */ 132 if ((partition < 0) || (partition >= MAXPARTITIONS)) { 133 err = EPART; 134 goto fail; 135 } 136 cp++; 137 } 138 } 139 if (*cp && (*cp != ':')) { 140 err = EINVAL; 141 goto fail; 142 } 143 144 idev->d_kind.biosdisk.unit = unit; 145 idev->d_kind.biosdisk.slice = slice; 146 idev->d_kind.biosdisk.partition = partition; 147 if (path != NULL) 148 *path = (*cp == 0) ? cp : cp + 1; 149 break; 150 151 case DEVT_CD: 152 case DEVT_NET: 153 unit = 0; 154 155 if (*np && (*np != ':')) { 156 unit = strtol(np, &cp, 0); /* get unit number if present */ 157 if (cp == np) { 158 err = EUNIT; 159 goto fail; 160 } 161 } 162 if (*cp && (*cp != ':')) { 163 err = EINVAL; 164 goto fail; 165 } 166 167 if (dv->dv_type == DEVT_NET) 168 idev->d_kind.netif.unit = unit; 169 else 170 idev->d_kind.bioscd.unit = unit; 171 if (path != NULL) 172 *path = (*cp == 0) ? cp : cp + 1; 173 break; 174 175 default: 176 err = EINVAL; 177 goto fail; 178 } 179 idev->d_dev = dv; 180 idev->d_type = dv->dv_type; 181 if (dev == NULL) { 182 free(idev); 183 } else { 184 *dev = idev; 185 } 186 return(0); 187 188 fail: 189 free(idev); 190 return(err); 191} 192 193 194char * 195i386_fmtdev(void *vdev) 196{ 197 struct i386_devdesc *dev = (struct i386_devdesc *)vdev; 198 static char buf[128]; /* XXX device length constant? */ 199 char *cp; 200 201 switch(dev->d_type) { 202 case DEVT_NONE: 203 strcpy(buf, "(no device)"); 204 break; 205 206 case DEVT_CD: 207 sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.bioscd.unit); 208 break; 209 210 case DEVT_DISK: 211 cp = buf; 212 cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_kind.biosdisk.unit); 213 if (dev->d_kind.biosdisk.slice > 0) 214 cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice); 215 if (dev->d_kind.biosdisk.partition >= 0) 216 cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a'); 217 strcat(cp, ":"); 218 break; 219 220 case DEVT_NET: 221 sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.netif.unit); 222 break; 223 } 224 return(buf); 225} 226 227 228/* 229 * Set currdev to suit the value being supplied in (value) 230 */ 231int 232i386_setcurrdev(struct env_var *ev, int flags, void *value) 233{ 234 struct i386_devdesc *ncurr; 235 int rv; 236 237 if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0) 238 return(rv); 239 free(ncurr); 240 env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 241 return(0); 242} 243 244