devicename.c revision 181282
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 */ 2638465Smsmith 27119482Sobrien#include <sys/cdefs.h> 28119482Sobrien__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/devicename.c 181282 2008-08-04 07:01:42Z cperciva $"); 29119482Sobrien 3038465Smsmith#include <stand.h> 3138465Smsmith#include <string.h> 3238465Smsmith#include <sys/disklabel.h> 3338465Smsmith#include "bootstrap.h" 3438465Smsmith#include "libi386.h" 3538465Smsmith 3639673Sdfrstatic int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path); 3738465Smsmith 3838465Smsmith/* 3938465Smsmith * Point (dev) at an allocated device specifier for the device matching the 4038465Smsmith * path in (devspec). If it contains an explicit device specification, 4138465Smsmith * use that. If not, use the default device. 4238465Smsmith */ 4338465Smsmithint 4439673Sdfri386_getdev(void **vdev, const char *devspec, const char **path) 4538465Smsmith{ 4638465Smsmith struct i386_devdesc **dev = (struct i386_devdesc **)vdev; 4738465Smsmith int rv; 4838465Smsmith 4938465Smsmith /* 5038465Smsmith * If it looks like this is just a path and no 5138465Smsmith * device, go with the current device. 5238465Smsmith */ 5338465Smsmith if ((devspec == NULL) || 5438465Smsmith (devspec[0] == '/') || 5538465Smsmith (strchr(devspec, ':') == NULL)) { 5638465Smsmith 5738465Smsmith if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) && 5838465Smsmith (path != NULL)) 5938465Smsmith *path = devspec; 6038465Smsmith return(rv); 6138465Smsmith } 6238465Smsmith 6338465Smsmith /* 6438465Smsmith * Try to parse the device name off the beginning of the devspec 6538465Smsmith */ 6638465Smsmith return(i386_parsedev(dev, devspec, path)); 6738465Smsmith} 6838465Smsmith 6938465Smsmith/* 7038465Smsmith * Point (dev) at an allocated device specifier matching the string version 7138465Smsmith * at the beginning of (devspec). Return a pointer to the remaining 7238465Smsmith * text in (path). 7338465Smsmith * 7438465Smsmith * In all cases, the beginning of (devspec) is compared to the names 7538465Smsmith * of known devices in the device switch, and then any following text 7638465Smsmith * is parsed according to the rules applied to the device type. 7738465Smsmith * 7838465Smsmith * For disk-type devices, the syntax is: 7938465Smsmith * 8038465Smsmith * disk<unit>[s<slice>][<partition>]: 8138465Smsmith * 8238465Smsmith */ 8338465Smsmithstatic int 8439673Sdfri386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) 8538465Smsmith{ 8638465Smsmith struct i386_devdesc *idev; 8738465Smsmith struct devsw *dv; 8838465Smsmith int i, unit, slice, partition, err; 8939673Sdfr char *cp; 9039673Sdfr const char *np; 9138465Smsmith 9238465Smsmith /* minimum length check */ 9338465Smsmith if (strlen(devspec) < 2) 9438465Smsmith return(EINVAL); 9538465Smsmith 9638465Smsmith /* look for a device that matches */ 9738465Smsmith for (i = 0, dv = NULL; devsw[i] != NULL; i++) { 9838465Smsmith if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { 9938465Smsmith dv = devsw[i]; 10038465Smsmith break; 10138465Smsmith } 10238465Smsmith } 10338465Smsmith if (dv == NULL) 10438465Smsmith return(ENOENT); 10538465Smsmith idev = malloc(sizeof(struct i386_devdesc)); 10638465Smsmith err = 0; 10738465Smsmith np = (devspec + strlen(dv->dv_name)); 10838465Smsmith 10938465Smsmith switch(dv->dv_type) { 11038465Smsmith case DEVT_NONE: /* XXX what to do here? Do we care? */ 11138465Smsmith break; 11238465Smsmith 11338465Smsmith case DEVT_DISK: 11438465Smsmith unit = -1; 11538465Smsmith slice = -1; 11638465Smsmith partition = -1; 11738465Smsmith if (*np && (*np != ':')) { 11838465Smsmith unit = strtol(np, &cp, 10); /* next comes the unit number */ 11938465Smsmith if (cp == np) { 12038465Smsmith err = EUNIT; 12138465Smsmith goto fail; 12238465Smsmith } 123172940Sjhb if (*cp == 'p') { /* got a GPT partition */ 12438465Smsmith np = cp + 1; 12538465Smsmith slice = strtol(np, &cp, 10); 12638465Smsmith if (cp == np) { 12738465Smsmith err = ESLICE; 12838465Smsmith goto fail; 12938465Smsmith } 130172940Sjhb if (*cp && (*cp != ':')) { 131172940Sjhb err = EINVAL; 13238465Smsmith goto fail; 13338465Smsmith } 134172940Sjhb partition = 0xff; 135172940Sjhb } else { 136172940Sjhb if (*cp == 's') { /* got a slice number */ 137172940Sjhb np = cp + 1; 138172940Sjhb slice = strtol(np, &cp, 10); 139172940Sjhb if (cp == np) { 140172940Sjhb err = ESLICE; 141172940Sjhb goto fail; 142172940Sjhb } 143172940Sjhb } 144172940Sjhb if (*cp && (*cp != ':')) { 145172940Sjhb partition = *cp - 'a'; /* got a partition number */ 146172940Sjhb if ((partition < 0) || (partition >= MAXPARTITIONS)) { 147172940Sjhb err = EPART; 148172940Sjhb goto fail; 149172940Sjhb } 150172940Sjhb cp++; 151172940Sjhb } 15238465Smsmith } 153181282Scperciva } else { 154181282Scperciva cp = np; 15538465Smsmith } 15638465Smsmith if (*cp && (*cp != ':')) { 15738465Smsmith err = EINVAL; 15838465Smsmith goto fail; 15938465Smsmith } 16038465Smsmith 161163897Smarcel idev->d_unit = unit; 16238465Smsmith idev->d_kind.biosdisk.slice = slice; 16338465Smsmith idev->d_kind.biosdisk.partition = partition; 16438465Smsmith if (path != NULL) 16538465Smsmith *path = (*cp == 0) ? cp : cp + 1; 16638465Smsmith break; 16786091Sjhb 16886091Sjhb case DEVT_CD: 16938465Smsmith case DEVT_NET: 17038465Smsmith unit = 0; 17186091Sjhb 17238465Smsmith if (*np && (*np != ':')) { 17338465Smsmith unit = strtol(np, &cp, 0); /* get unit number if present */ 17438465Smsmith if (cp == np) { 17538465Smsmith err = EUNIT; 17638465Smsmith goto fail; 17738465Smsmith } 178181282Scperciva } else { 179181282Scperciva cp = np; 18038465Smsmith } 18138465Smsmith if (*cp && (*cp != ':')) { 18238465Smsmith err = EINVAL; 18338465Smsmith goto fail; 18438465Smsmith } 18586091Sjhb 186163897Smarcel idev->d_unit = unit; 18738465Smsmith if (path != NULL) 18838465Smsmith *path = (*cp == 0) ? cp : cp + 1; 18938465Smsmith break; 19038465Smsmith 19138465Smsmith default: 19238465Smsmith err = EINVAL; 19338465Smsmith goto fail; 19438465Smsmith } 19538465Smsmith idev->d_dev = dv; 19638465Smsmith idev->d_type = dv->dv_type; 19738465Smsmith if (dev == NULL) { 19838465Smsmith free(idev); 19938465Smsmith } else { 20038465Smsmith *dev = idev; 20138465Smsmith } 20238465Smsmith return(0); 20338465Smsmith 20438465Smsmith fail: 20538465Smsmith free(idev); 20638465Smsmith return(err); 20738465Smsmith} 20838465Smsmith 20938465Smsmith 21038465Smsmithchar * 21138465Smsmithi386_fmtdev(void *vdev) 21238465Smsmith{ 21338465Smsmith struct i386_devdesc *dev = (struct i386_devdesc *)vdev; 21438465Smsmith static char buf[128]; /* XXX device length constant? */ 21538465Smsmith char *cp; 21638465Smsmith 21738465Smsmith switch(dev->d_type) { 21838465Smsmith case DEVT_NONE: 21938465Smsmith strcpy(buf, "(no device)"); 22038465Smsmith break; 22138465Smsmith 22286091Sjhb case DEVT_CD: 223163897Smarcel sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 22486091Sjhb break; 22586091Sjhb 22638465Smsmith case DEVT_DISK: 22738465Smsmith cp = buf; 228163897Smarcel cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit); 229172940Sjhb if (dev->d_kind.biosdisk.partition == 0xff) { 230172940Sjhb cp += sprintf(cp, "p%d", dev->d_kind.biosdisk.slice); 231172940Sjhb } else { 232172940Sjhb if (dev->d_kind.biosdisk.slice > 0) 233172940Sjhb cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice); 234172940Sjhb if (dev->d_kind.biosdisk.partition >= 0) 235172940Sjhb cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a'); 236172940Sjhb } 23738465Smsmith strcat(cp, ":"); 23838465Smsmith break; 23938465Smsmith 24038465Smsmith case DEVT_NET: 241163897Smarcel sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 24238465Smsmith break; 24338465Smsmith } 24438465Smsmith return(buf); 24538465Smsmith} 24638465Smsmith 24738465Smsmith 24838465Smsmith/* 24938465Smsmith * Set currdev to suit the value being supplied in (value) 25038465Smsmith */ 25138465Smsmithint 252146697Sjhbi386_setcurrdev(struct env_var *ev, int flags, const void *value) 25338465Smsmith{ 25438465Smsmith struct i386_devdesc *ncurr; 25538465Smsmith int rv; 25639662Smsmith 25738465Smsmith if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0) 25838465Smsmith return(rv); 25938465Smsmith free(ncurr); 26038465Smsmith env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 26138465Smsmith return(0); 26238465Smsmith} 263