1206376Srpaulo/*- 2206376Srpaulo * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3206376Srpaulo * Copyright (c) 2006 Marcel Moolenaar 4206376Srpaulo * All rights reserved. 5206376Srpaulo * 6206376Srpaulo * Redistribution and use in source and binary forms, with or without 7206376Srpaulo * modification, are permitted provided that the following conditions 8206376Srpaulo * are met: 9206376Srpaulo * 1. Redistributions of source code must retain the above copyright 10206376Srpaulo * notice, this list of conditions and the following disclaimer. 11206376Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 12206376Srpaulo * notice, this list of conditions and the following disclaimer in the 13206376Srpaulo * documentation and/or other materials provided with the distribution. 14206376Srpaulo * 15206376Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16206376Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17206376Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18206376Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19206376Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20206376Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21206376Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22206376Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23206376Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24206376Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25206376Srpaulo * SUCH DAMAGE. 26206376Srpaulo */ 27206376Srpaulo 28206376Srpaulo#include <sys/cdefs.h> 29206376Srpaulo__FBSDID("$FreeBSD$"); 30206376Srpaulo 31206376Srpaulo#include <stand.h> 32206376Srpaulo#include <string.h> 33206376Srpaulo#include <sys/disklabel.h> 34206376Srpaulo#include "bootstrap.h" 35206376Srpaulo 36206376Srpaulo#include <efi.h> 37206376Srpaulo#include <efilib.h> 38206376Srpaulo 39206376Srpaulostatic int i386_parsedev(struct devdesc **, const char *, const char **); 40206376Srpaulo 41206376Srpaulo/* 42206376Srpaulo * Point (dev) at an allocated device specifier for the device matching the 43206376Srpaulo * path in (devspec). If it contains an explicit device specification, 44206376Srpaulo * use that. If not, use the default device. 45206376Srpaulo */ 46206376Srpauloint 47206376Srpauloi386_getdev(void **vdev, const char *devspec, const char **path) 48206376Srpaulo{ 49206376Srpaulo struct devdesc **dev = (struct devdesc **)vdev; 50206376Srpaulo int rv; 51206376Srpaulo 52206376Srpaulo /* 53206376Srpaulo * If it looks like this is just a path and no device, then 54206376Srpaulo * use the current device instead. 55206376Srpaulo */ 56206376Srpaulo if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) { 57206376Srpaulo rv = i386_parsedev(dev, getenv("currdev"), NULL); 58206376Srpaulo if (rv == 0 && path != NULL) 59206376Srpaulo *path = devspec; 60206376Srpaulo return (rv); 61206376Srpaulo } 62206376Srpaulo 63206376Srpaulo /* Parse the device name off the beginning of the devspec. */ 64206376Srpaulo return (i386_parsedev(dev, devspec, path)); 65206376Srpaulo} 66206376Srpaulo 67206376Srpaulo/* 68206376Srpaulo * Point (dev) at an allocated device specifier matching the string version 69206376Srpaulo * at the beginning of (devspec). Return a pointer to the remaining 70206376Srpaulo * text in (path). 71206376Srpaulo * 72206376Srpaulo * In all cases, the beginning of (devspec) is compared to the names 73206376Srpaulo * of known devices in the device switch, and then any following text 74206376Srpaulo * is parsed according to the rules applied to the device type. 75206376Srpaulo * 76206376Srpaulo * For disk-type devices, the syntax is: 77206376Srpaulo * 78206376Srpaulo * fs<unit>: 79206376Srpaulo */ 80206376Srpaulostatic int 81206376Srpauloi386_parsedev(struct devdesc **dev, const char *devspec, const char **path) 82206376Srpaulo{ 83206376Srpaulo struct devdesc *idev; 84206376Srpaulo struct devsw *dv; 85206376Srpaulo char *cp; 86206376Srpaulo const char *np; 87206376Srpaulo int i, err; 88206376Srpaulo 89206376Srpaulo /* minimum length check */ 90206376Srpaulo if (strlen(devspec) < 2) 91206376Srpaulo return (EINVAL); 92206376Srpaulo 93206376Srpaulo /* look for a device that matches */ 94206376Srpaulo for (i = 0; devsw[i] != NULL; i++) { 95206376Srpaulo dv = devsw[i]; 96206376Srpaulo if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name))) 97206376Srpaulo break; 98206376Srpaulo } 99206376Srpaulo if (devsw[i] == NULL) 100206376Srpaulo return (ENOENT); 101206376Srpaulo 102206376Srpaulo idev = malloc(sizeof(struct devdesc)); 103206376Srpaulo if (idev == NULL) 104206376Srpaulo return (ENOMEM); 105206376Srpaulo 106206376Srpaulo idev->d_dev = dv; 107206376Srpaulo idev->d_type = dv->dv_type; 108206376Srpaulo idev->d_unit = -1; 109206376Srpaulo 110206376Srpaulo err = 0; 111206376Srpaulo np = devspec + strlen(dv->dv_name); 112206376Srpaulo if (*np != '\0' && *np != ':') { 113206376Srpaulo idev->d_unit = strtol(np, &cp, 0); 114206376Srpaulo if (cp == np) { 115206376Srpaulo idev->d_unit = -1; 116206376Srpaulo free(idev); 117206376Srpaulo return (EUNIT); 118206376Srpaulo } 119206376Srpaulo } 120206376Srpaulo if (*cp != '\0' && *cp != ':') { 121206376Srpaulo free(idev); 122206376Srpaulo return (EINVAL); 123206376Srpaulo } 124206376Srpaulo 125206376Srpaulo if (path != NULL) 126206376Srpaulo *path = (*cp == 0) ? cp : cp + 1; 127206376Srpaulo if (dev != NULL) 128206376Srpaulo *dev = idev; 129206376Srpaulo else 130206376Srpaulo free(idev); 131206376Srpaulo return (0); 132206376Srpaulo} 133206376Srpaulo 134206376Srpaulochar * 135206376Srpauloi386_fmtdev(void *vdev) 136206376Srpaulo{ 137206376Srpaulo struct devdesc *dev = (struct devdesc *)vdev; 138206376Srpaulo static char buf[32]; /* XXX device length constant? */ 139206376Srpaulo 140206376Srpaulo switch(dev->d_type) { 141206376Srpaulo case DEVT_NONE: 142206376Srpaulo strcpy(buf, "(no device)"); 143206376Srpaulo break; 144206376Srpaulo 145206376Srpaulo default: 146206376Srpaulo sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 147206376Srpaulo break; 148206376Srpaulo } 149206376Srpaulo 150206376Srpaulo return(buf); 151206376Srpaulo} 152206376Srpaulo 153206376Srpaulo/* 154206376Srpaulo * Set currdev to suit the value being supplied in (value) 155206376Srpaulo */ 156206376Srpauloint 157206376Srpauloi386_setcurrdev(struct env_var *ev, int flags, const void *value) 158206376Srpaulo{ 159206376Srpaulo struct devdesc *ncurr; 160206376Srpaulo int rv; 161206376Srpaulo 162206376Srpaulo rv = i386_parsedev(&ncurr, value, NULL); 163206376Srpaulo if (rv != 0) 164206376Srpaulo return(rv); 165206376Srpaulo 166206376Srpaulo free(ncurr); 167206376Srpaulo env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 168206376Srpaulo return (0); 169206376Srpaulo} 170