1176348Smarcel/*- 2176348Smarcel * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3176348Smarcel * All rights reserved. 4176348Smarcel * 5176348Smarcel * Redistribution and use in source and binary forms, with or without 6176348Smarcel * modification, are permitted provided that the following conditions 7176348Smarcel * are met: 8176348Smarcel * 1. Redistributions of source code must retain the above copyright 9176348Smarcel * notice, this list of conditions and the following disclaimer. 10176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11176348Smarcel * notice, this list of conditions and the following disclaimer in the 12176348Smarcel * documentation and/or other materials provided with the distribution. 13176348Smarcel * 14176348Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15176348Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16176348Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17176348Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18176348Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19176348Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20176348Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21176348Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22176348Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23176348Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24176348Smarcel * SUCH DAMAGE. 25176348Smarcel */ 26176348Smarcel 27176348Smarcel#include <sys/cdefs.h> 28176348Smarcel__FBSDID("$FreeBSD$"); 29176348Smarcel 30176348Smarcel#include <stand.h> 31176348Smarcel#include <string.h> 32176348Smarcel 33176348Smarcel#include "bootstrap.h" 34243243Sae#include "disk.h" 35176348Smarcel#include "libuboot.h" 36176348Smarcel 37186231Srajstatic int uboot_parsedev(struct uboot_devdesc **dev, const char *devspec, 38186231Sraj const char **path); 39176348Smarcel 40177152Sobrien/* 41176348Smarcel * Point (dev) at an allocated device specifier for the device matching the 42176348Smarcel * path in (devspec). If it contains an explicit device specification, 43176348Smarcel * use that. If not, use the default device. 44176348Smarcel */ 45176348Smarcelint 46176348Smarceluboot_getdev(void **vdev, const char *devspec, const char **path) 47176348Smarcel{ 48177152Sobrien struct uboot_devdesc **dev = (struct uboot_devdesc **)vdev; 49177152Sobrien int rv; 50176348Smarcel 51177152Sobrien /* 52177152Sobrien * If it looks like this is just a path and no 53177152Sobrien * device, go with the current device. 54177152Sobrien */ 55177152Sobrien if ((devspec == NULL) || (devspec[0] == '/') || 56177152Sobrien (strchr(devspec, ':') == NULL)) { 57177152Sobrien 58177152Sobrien if (((rv = uboot_parsedev(dev, getenv("currdev"), NULL)) == 0) 59177152Sobrien && (path != NULL)) 60176348Smarcel *path = devspec; 61177152Sobrien return(rv); 62177152Sobrien } 63177152Sobrien 64177152Sobrien /* 65177152Sobrien * Try to parse the device name off the beginning of the devspec. 66177152Sobrien */ 67185099Sraj return (uboot_parsedev(dev, devspec, path)); 68176348Smarcel} 69176348Smarcel 70176348Smarcel/* 71176348Smarcel * Point (dev) at an allocated device specifier matching the string version 72176348Smarcel * at the beginning of (devspec). Return a pointer to the remaining 73176348Smarcel * text in (path). 74176348Smarcel * 75176348Smarcel * In all cases, the beginning of (devspec) is compared to the names 76176348Smarcel * of known devices in the device switch, and then any following text 77176348Smarcel * is parsed according to the rules applied to the device type. 78176348Smarcel * 79176348Smarcel * For disk-type devices, the syntax is: 80176348Smarcel * 81185099Sraj * disk<unit>[<partition>]: 82177152Sobrien * 83176348Smarcel */ 84176348Smarcelstatic int 85177152Sobrienuboot_parsedev(struct uboot_devdesc **dev, const char *devspec, 86177152Sobrien const char **path) 87176348Smarcel{ 88177152Sobrien struct uboot_devdesc *idev; 89185099Sraj struct devsw *dv; 90185099Sraj char *cp; 91185099Sraj const char *np; 92243243Sae int i, unit, err; 93176348Smarcel 94177152Sobrien /* minimum length check */ 95177152Sobrien if (strlen(devspec) < 2) 96177152Sobrien return(EINVAL); 97176348Smarcel 98177152Sobrien /* look for a device that matches */ 99177152Sobrien for (i = 0, dv = NULL; devsw[i] != NULL; i++) { 100177152Sobrien if (!strncmp(devspec, devsw[i]->dv_name, 101177152Sobrien strlen(devsw[i]->dv_name))) { 102177152Sobrien dv = devsw[i]; 103177152Sobrien break; 104177152Sobrien } 105176348Smarcel } 106177152Sobrien if (dv == NULL) 107177152Sobrien return(ENOENT); 108177152Sobrien idev = malloc(sizeof(struct uboot_devdesc)); 109177152Sobrien err = 0; 110177152Sobrien np = (devspec + strlen(dv->dv_name)); 111176348Smarcel 112177152Sobrien switch(dv->dv_type) { 113185099Sraj case DEVT_NONE: 114177152Sobrien break; 115177152Sobrien 116243243Sae#ifdef LOADER_DISK_SUPPORT 117177152Sobrien case DEVT_DISK: 118243243Sae err = disk_parsedev((struct disk_devdesc *)idev, np, path); 119243243Sae if (err != 0) 120185099Sraj goto fail; 121177152Sobrien break; 122243243Sae#endif 123177152Sobrien 124177152Sobrien case DEVT_NET: 125177152Sobrien unit = 0; 126177152Sobrien 127177152Sobrien if (*np && (*np != ':')) { 128177152Sobrien /* get unit number if present */ 129177152Sobrien unit = strtol(np, &cp, 0); 130177152Sobrien if (cp == np) { 131177152Sobrien err = EUNIT; 132177152Sobrien goto fail; 133177152Sobrien } 134176348Smarcel } 135177152Sobrien if (*cp && (*cp != ':')) { 136177152Sobrien err = EINVAL; 137177152Sobrien goto fail; 138177152Sobrien } 139185099Sraj idev->d_unit = unit; 140176348Smarcel 141177152Sobrien if (path != NULL) 142177152Sobrien *path = (*cp == 0) ? cp : cp + 1; 143177152Sobrien break; 144176348Smarcel 145177152Sobrien default: 146177152Sobrien err = EINVAL; 147176348Smarcel goto fail; 148176348Smarcel } 149177152Sobrien idev->d_dev = dv; 150177152Sobrien idev->d_type = dv->dv_type; 151177152Sobrien if (dev == NULL) { 152177152Sobrien free(idev); 153177152Sobrien } else { 154177152Sobrien *dev = idev; 155176348Smarcel } 156186231Sraj return (0); 157176348Smarcel 158177152Sobrienfail: 159176348Smarcel free(idev); 160186231Sraj return (err); 161176348Smarcel} 162176348Smarcel 163176348Smarcel 164176348Smarcelchar * 165176348Smarceluboot_fmtdev(void *vdev) 166176348Smarcel{ 167177152Sobrien struct uboot_devdesc *dev = (struct uboot_devdesc *)vdev; 168186231Sraj static char buf[128]; 169176348Smarcel 170177152Sobrien switch(dev->d_type) { 171177152Sobrien case DEVT_NONE: 172177152Sobrien strcpy(buf, "(no device)"); 173177152Sobrien break; 174176348Smarcel 175177152Sobrien case DEVT_DISK: 176243243Sae#ifdef LOADER_DISK_SUPPORT 177243243Sae return (disk_fmtdev(vdev)); 178243243Sae#endif 179191829Sraj 180177152Sobrien case DEVT_NET: 181177152Sobrien sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 182177152Sobrien break; 183177152Sobrien } 184177152Sobrien return(buf); 185176348Smarcel} 186176348Smarcel 187176348Smarcel/* 188177152Sobrien * Set currdev to suit the value being supplied in (value). 189176348Smarcel */ 190176348Smarcelint 191176348Smarceluboot_setcurrdev(struct env_var *ev, int flags, const void *value) 192176348Smarcel{ 193186231Sraj struct uboot_devdesc *ncurr; 194186231Sraj int rv; 195176348Smarcel 196177152Sobrien if ((rv = uboot_parsedev(&ncurr, value, NULL)) != 0) 197186231Sraj return (rv); 198177152Sobrien free(ncurr); 199177152Sobrien env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 200186231Sraj return (0); 201176348Smarcel} 202