devicename.c revision 86091
138465Smsmith/*- 238465Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 338465Smsmith * All rights reserved. 438465Smsmith * 538465Smsmith * Redistribution and use in source and binary forms, with or without 638465Smsmith * modification, are permitted provided that the following conditions 738465Smsmith * are met: 838465Smsmith * 1. Redistributions of source code must retain the above copyright 938465Smsmith * notice, this list of conditions and the following disclaimer. 1038465Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1138465Smsmith * notice, this list of conditions and the following disclaimer in the 1238465Smsmith * documentation and/or other materials provided with the distribution. 1338465Smsmith * 1438465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538465Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638465Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738465Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838465Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938465Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2038465Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138465Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238465Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338465Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438465Smsmith * SUCH DAMAGE. 2538465Smsmith * 2650477Speter * $FreeBSD: head/sys/boot/i386/libi386/devicename.c 86091 2001-11-05 18:58:33Z jhb $ 2738465Smsmith */ 2838465Smsmith 2938465Smsmith#include <stand.h> 3038465Smsmith#include <string.h> 3138465Smsmith#include <sys/disklabel.h> 3238465Smsmith#include "bootstrap.h" 3338465Smsmith#include "libi386.h" 3438465Smsmith 3539673Sdfrstatic int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path); 3638465Smsmith 3738465Smsmith/* 3838465Smsmith * Point (dev) at an allocated device specifier for the device matching the 3938465Smsmith * path in (devspec). If it contains an explicit device specification, 4038465Smsmith * use that. If not, use the default device. 4138465Smsmith */ 4238465Smsmithint 4339673Sdfri386_getdev(void **vdev, const char *devspec, const char **path) 4438465Smsmith{ 4538465Smsmith struct i386_devdesc **dev = (struct i386_devdesc **)vdev; 4638465Smsmith int rv; 4738465Smsmith 4838465Smsmith /* 4938465Smsmith * If it looks like this is just a path and no 5038465Smsmith * device, go with the current device. 5138465Smsmith */ 5238465Smsmith if ((devspec == NULL) || 5338465Smsmith (devspec[0] == '/') || 5438465Smsmith (strchr(devspec, ':') == NULL)) { 5538465Smsmith 5638465Smsmith if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) && 5738465Smsmith (path != NULL)) 5838465Smsmith *path = devspec; 5938465Smsmith return(rv); 6038465Smsmith } 6138465Smsmith 6238465Smsmith /* 6338465Smsmith * Try to parse the device name off the beginning of the devspec 6438465Smsmith */ 6538465Smsmith return(i386_parsedev(dev, devspec, path)); 6638465Smsmith} 6738465Smsmith 6838465Smsmith/* 6938465Smsmith * Point (dev) at an allocated device specifier matching the string version 7038465Smsmith * at the beginning of (devspec). Return a pointer to the remaining 7138465Smsmith * text in (path). 7238465Smsmith * 7338465Smsmith * In all cases, the beginning of (devspec) is compared to the names 7438465Smsmith * of known devices in the device switch, and then any following text 7538465Smsmith * is parsed according to the rules applied to the device type. 7638465Smsmith * 7738465Smsmith * For disk-type devices, the syntax is: 7838465Smsmith * 7938465Smsmith * disk<unit>[s<slice>][<partition>]: 8038465Smsmith * 8138465Smsmith */ 8238465Smsmithstatic int 8339673Sdfri386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) 8438465Smsmith{ 8538465Smsmith struct i386_devdesc *idev; 8638465Smsmith struct devsw *dv; 8738465Smsmith int i, unit, slice, partition, err; 8839673Sdfr char *cp; 8939673Sdfr const char *np; 9038465Smsmith 9138465Smsmith /* minimum length check */ 9238465Smsmith if (strlen(devspec) < 2) 9338465Smsmith return(EINVAL); 9438465Smsmith 9538465Smsmith /* look for a device that matches */ 9638465Smsmith for (i = 0, dv = NULL; devsw[i] != NULL; i++) { 9738465Smsmith if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { 9838465Smsmith dv = devsw[i]; 9938465Smsmith break; 10038465Smsmith } 10138465Smsmith } 10238465Smsmith if (dv == NULL) 10338465Smsmith return(ENOENT); 10438465Smsmith idev = malloc(sizeof(struct i386_devdesc)); 10538465Smsmith err = 0; 10638465Smsmith np = (devspec + strlen(dv->dv_name)); 10738465Smsmith 10838465Smsmith switch(dv->dv_type) { 10938465Smsmith case DEVT_NONE: /* XXX what to do here? Do we care? */ 11038465Smsmith break; 11138465Smsmith 11238465Smsmith case DEVT_DISK: 11338465Smsmith unit = -1; 11438465Smsmith slice = -1; 11538465Smsmith partition = -1; 11638465Smsmith if (*np && (*np != ':')) { 11738465Smsmith unit = strtol(np, &cp, 10); /* next comes the unit number */ 11838465Smsmith if (cp == np) { 11938465Smsmith err = EUNIT; 12038465Smsmith goto fail; 12138465Smsmith } 12238465Smsmith if (*cp == 's') { /* got a slice number */ 12338465Smsmith np = cp + 1; 12438465Smsmith slice = strtol(np, &cp, 10); 12538465Smsmith if (cp == np) { 12638465Smsmith err = ESLICE; 12738465Smsmith goto fail; 12838465Smsmith } 12938465Smsmith } 13038465Smsmith if (*cp && (*cp != ':')) { 13138465Smsmith partition = *cp - 'a'; /* get a partition number */ 13238465Smsmith if ((partition < 0) || (partition >= MAXPARTITIONS)) { 13338465Smsmith err = EPART; 13438465Smsmith goto fail; 13538465Smsmith } 13638465Smsmith cp++; 13738465Smsmith } 13838465Smsmith } 13938465Smsmith if (*cp && (*cp != ':')) { 14038465Smsmith err = EINVAL; 14138465Smsmith goto fail; 14238465Smsmith } 14338465Smsmith 14438465Smsmith idev->d_kind.biosdisk.unit = unit; 14538465Smsmith idev->d_kind.biosdisk.slice = slice; 14638465Smsmith idev->d_kind.biosdisk.partition = partition; 14738465Smsmith if (path != NULL) 14838465Smsmith *path = (*cp == 0) ? cp : cp + 1; 14938465Smsmith break; 15086091Sjhb 15186091Sjhb case DEVT_CD: 15238465Smsmith case DEVT_NET: 15338465Smsmith unit = 0; 15486091Sjhb 15538465Smsmith if (*np && (*np != ':')) { 15638465Smsmith unit = strtol(np, &cp, 0); /* get unit number if present */ 15738465Smsmith if (cp == np) { 15838465Smsmith err = EUNIT; 15938465Smsmith goto fail; 16038465Smsmith } 16138465Smsmith } 16238465Smsmith if (*cp && (*cp != ':')) { 16338465Smsmith err = EINVAL; 16438465Smsmith goto fail; 16538465Smsmith } 16686091Sjhb 16786091Sjhb if (dv->dv_type == DEVT_NET) 16886091Sjhb idev->d_kind.netif.unit = unit; 16986091Sjhb else 17086091Sjhb idev->d_kind.bioscd.unit = unit; 17138465Smsmith if (path != NULL) 17238465Smsmith *path = (*cp == 0) ? cp : cp + 1; 17338465Smsmith break; 17438465Smsmith 17538465Smsmith default: 17638465Smsmith err = EINVAL; 17738465Smsmith goto fail; 17838465Smsmith } 17938465Smsmith idev->d_dev = dv; 18038465Smsmith idev->d_type = dv->dv_type; 18138465Smsmith if (dev == NULL) { 18238465Smsmith free(idev); 18338465Smsmith } else { 18438465Smsmith *dev = idev; 18538465Smsmith } 18638465Smsmith return(0); 18738465Smsmith 18838465Smsmith fail: 18938465Smsmith free(idev); 19038465Smsmith return(err); 19138465Smsmith} 19238465Smsmith 19338465Smsmith 19438465Smsmithchar * 19538465Smsmithi386_fmtdev(void *vdev) 19638465Smsmith{ 19738465Smsmith struct i386_devdesc *dev = (struct i386_devdesc *)vdev; 19838465Smsmith static char buf[128]; /* XXX device length constant? */ 19938465Smsmith char *cp; 20038465Smsmith 20138465Smsmith switch(dev->d_type) { 20238465Smsmith case DEVT_NONE: 20338465Smsmith strcpy(buf, "(no device)"); 20438465Smsmith break; 20538465Smsmith 20686091Sjhb case DEVT_CD: 20786091Sjhb sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.bioscd.unit); 20886091Sjhb break; 20986091Sjhb 21038465Smsmith case DEVT_DISK: 21138465Smsmith cp = buf; 21238465Smsmith cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_kind.biosdisk.unit); 21338465Smsmith if (dev->d_kind.biosdisk.slice > 0) 21438465Smsmith cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice); 21538465Smsmith if (dev->d_kind.biosdisk.partition >= 0) 21638465Smsmith cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a'); 21738465Smsmith strcat(cp, ":"); 21838465Smsmith break; 21938465Smsmith 22038465Smsmith case DEVT_NET: 22138465Smsmith sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.netif.unit); 22238465Smsmith break; 22338465Smsmith } 22438465Smsmith return(buf); 22538465Smsmith} 22638465Smsmith 22738465Smsmith 22838465Smsmith/* 22938465Smsmith * Set currdev to suit the value being supplied in (value) 23038465Smsmith */ 23138465Smsmithint 23238465Smsmithi386_setcurrdev(struct env_var *ev, int flags, void *value) 23338465Smsmith{ 23438465Smsmith struct i386_devdesc *ncurr; 23538465Smsmith int rv; 23639662Smsmith 23738465Smsmith if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0) 23838465Smsmith return(rv); 23938465Smsmith free(ncurr); 24038465Smsmith env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 24138465Smsmith return(0); 24238465Smsmith} 24338465Smsmith 244