1ca987d46SWarner Losh /*- 2ca987d46SWarner Losh * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3ca987d46SWarner Losh * All rights reserved. 4ca987d46SWarner Losh * 5ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 6ca987d46SWarner Losh * modification, are permitted provided that the following conditions 7ca987d46SWarner Losh * are met: 8ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 9ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 10ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 12ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 13ca987d46SWarner Losh * 14ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ca987d46SWarner Losh * SUCH DAMAGE. 25ca987d46SWarner Losh */ 26ca987d46SWarner Losh 27ca987d46SWarner Losh #include <sys/cdefs.h> 28ca987d46SWarner Losh __FBSDID("$FreeBSD$"); 29ca987d46SWarner Losh 30ca987d46SWarner Losh #include <stand.h> 31ca987d46SWarner Losh #include <string.h> 32ca987d46SWarner Losh 33ca987d46SWarner Losh #include "bootstrap.h" 34ca987d46SWarner Losh #include "disk.h" 35ca987d46SWarner Losh #include "libuserboot.h" 36ca987d46SWarner Losh 37ca987d46SWarner Losh #if defined(USERBOOT_ZFS_SUPPORT) 38007b82d7SWarner Losh #include "libzfs.h" 39ca987d46SWarner Losh #endif 40ca987d46SWarner Losh 41*5d5a6216SToomas Soome static int userboot_parsedev(struct disk_devdesc **dev, const char *devspec, 42*5d5a6216SToomas Soome const char **path); 43ca987d46SWarner Losh 44ca987d46SWarner Losh /* 45ca987d46SWarner Losh * Point (dev) at an allocated device specifier for the device matching the 46ca987d46SWarner Losh * path in (devspec). If it contains an explicit device specification, 47ca987d46SWarner Losh * use that. If not, use the default device. 48ca987d46SWarner Losh */ 49ca987d46SWarner Losh int 50ca987d46SWarner Losh userboot_getdev(void **vdev, const char *devspec, const char **path) 51ca987d46SWarner Losh { 52ca987d46SWarner Losh struct disk_devdesc **dev = (struct disk_devdesc **)vdev; 53ca987d46SWarner Losh int rv; 54ca987d46SWarner Losh 55ca987d46SWarner Losh /* 56ca987d46SWarner Losh * If it looks like this is just a path and no 57ca987d46SWarner Losh * device, go with the current device. 58ca987d46SWarner Losh */ 59ca987d46SWarner Losh if ((devspec == NULL) || 60ca987d46SWarner Losh (devspec[0] == '/') || 61ca987d46SWarner Losh (strchr(devspec, ':') == NULL)) { 62ca987d46SWarner Losh 63*5d5a6216SToomas Soome rv = userboot_parsedev(dev, getenv("currdev"), NULL); 64*5d5a6216SToomas Soome if (rv == 0 && path != NULL) 65ca987d46SWarner Losh *path = devspec; 66ca987d46SWarner Losh return (rv); 67ca987d46SWarner Losh } 68ca987d46SWarner Losh 69ca987d46SWarner Losh /* 70ca987d46SWarner Losh * Try to parse the device name off the beginning of the devspec 71ca987d46SWarner Losh */ 72ca987d46SWarner Losh return (userboot_parsedev(dev, devspec, path)); 73ca987d46SWarner Losh } 74ca987d46SWarner Losh 75ca987d46SWarner Losh /* 76ca987d46SWarner Losh * Point (dev) at an allocated device specifier matching the string version 77ca987d46SWarner Losh * at the beginning of (devspec). Return a pointer to the remaining 78ca987d46SWarner Losh * text in (path). 79ca987d46SWarner Losh * 80ca987d46SWarner Losh * In all cases, the beginning of (devspec) is compared to the names 81ca987d46SWarner Losh * of known devices in the device switch, and then any following text 82ca987d46SWarner Losh * is parsed according to the rules applied to the device type. 83ca987d46SWarner Losh * 84ca987d46SWarner Losh * For disk-type devices, the syntax is: 85ca987d46SWarner Losh * 86ca987d46SWarner Losh * disk<unit>[s<slice>][<partition>]: 87ca987d46SWarner Losh * 88ca987d46SWarner Losh */ 89ca987d46SWarner Losh static int 90*5d5a6216SToomas Soome userboot_parsedev(struct disk_devdesc **dev, const char *devspec, 91*5d5a6216SToomas Soome const char **path) 92ca987d46SWarner Losh { 93ca987d46SWarner Losh struct disk_devdesc *idev; 94ca987d46SWarner Losh struct devsw *dv; 95ca987d46SWarner Losh int i, unit, err; 96ca987d46SWarner Losh const char *cp; 97ca987d46SWarner Losh const char *np; 98ca987d46SWarner Losh 99ca987d46SWarner Losh /* minimum length check */ 100ca987d46SWarner Losh if (strlen(devspec) < 2) 101ca987d46SWarner Losh return (EINVAL); 102ca987d46SWarner Losh 103ca987d46SWarner Losh /* look for a device that matches */ 104ca987d46SWarner Losh for (i = 0, dv = NULL; devsw[i] != NULL; i++) { 105*5d5a6216SToomas Soome if (strncmp(devspec, devsw[i]->dv_name, 106*5d5a6216SToomas Soome strlen(devsw[i]->dv_name)) == 0) { 107ca987d46SWarner Losh dv = devsw[i]; 108ca987d46SWarner Losh break; 109ca987d46SWarner Losh } 110ca987d46SWarner Losh } 111ca987d46SWarner Losh if (dv == NULL) 112ca987d46SWarner Losh return (ENOENT); 113ca987d46SWarner Losh idev = malloc(sizeof(struct disk_devdesc)); 114ca987d46SWarner Losh err = 0; 115ca987d46SWarner Losh np = (devspec + strlen(dv->dv_name)); 116ca987d46SWarner Losh 117ca987d46SWarner Losh switch (dv->dv_type) { 118ca987d46SWarner Losh case DEVT_NONE: /* XXX what to do here? Do we care? */ 119ca987d46SWarner Losh break; 120ca987d46SWarner Losh 121ca987d46SWarner Losh case DEVT_DISK: 122ca987d46SWarner Losh err = disk_parsedev(idev, np, path); 123ca987d46SWarner Losh if (err != 0) 124ca987d46SWarner Losh goto fail; 125ca987d46SWarner Losh break; 126ca987d46SWarner Losh 127ca987d46SWarner Losh case DEVT_CD: 128ca987d46SWarner Losh case DEVT_NET: 129ca987d46SWarner Losh unit = 0; 130ca987d46SWarner Losh 131ca987d46SWarner Losh if (*np && (*np != ':')) { 132*5d5a6216SToomas Soome /* get unit number if present */ 133*5d5a6216SToomas Soome unit = strtol(np, (char **)&cp, 0); 134ca987d46SWarner Losh if (cp == np) { 135ca987d46SWarner Losh err = EUNIT; 136ca987d46SWarner Losh goto fail; 137ca987d46SWarner Losh } 138ca987d46SWarner Losh } else { 139ca987d46SWarner Losh cp = np; 140ca987d46SWarner Losh } 141ca987d46SWarner Losh if (*cp && (*cp != ':')) { 142ca987d46SWarner Losh err = EINVAL; 143ca987d46SWarner Losh goto fail; 144ca987d46SWarner Losh } 145ca987d46SWarner Losh 146de04d704SWarner Losh idev->dd.d_unit = unit; 147ca987d46SWarner Losh if (path != NULL) 148ca987d46SWarner Losh *path = (*cp == 0) ? cp : cp + 1; 149ca987d46SWarner Losh break; 150ca987d46SWarner Losh 151ca987d46SWarner Losh case DEVT_ZFS: 152ca987d46SWarner Losh #if defined(USERBOOT_ZFS_SUPPORT) 153ca987d46SWarner Losh err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); 154ca987d46SWarner Losh if (err != 0) 155ca987d46SWarner Losh goto fail; 156ca987d46SWarner Losh break; 157ca987d46SWarner Losh #else 158ca987d46SWarner Losh /* FALLTHROUGH */ 159ca987d46SWarner Losh #endif 160ca987d46SWarner Losh 161ca987d46SWarner Losh default: 162ca987d46SWarner Losh err = EINVAL; 163ca987d46SWarner Losh goto fail; 164ca987d46SWarner Losh } 165de04d704SWarner Losh idev->dd.d_dev = dv; 166ca987d46SWarner Losh if (dev == NULL) { 167ca987d46SWarner Losh free(idev); 168ca987d46SWarner Losh } else { 169ca987d46SWarner Losh *dev = idev; 170ca987d46SWarner Losh } 171ca987d46SWarner Losh return (0); 172ca987d46SWarner Losh 173ca987d46SWarner Losh fail: 174ca987d46SWarner Losh free(idev); 175ca987d46SWarner Losh return (err); 176ca987d46SWarner Losh } 177ca987d46SWarner Losh 178ca987d46SWarner Losh 179ca987d46SWarner Losh char * 180ca987d46SWarner Losh userboot_fmtdev(void *vdev) 181ca987d46SWarner Losh { 1823dfe152dSWarner Losh struct devdesc *dev = (struct devdesc *)vdev; 183ca987d46SWarner Losh static char buf[128]; /* XXX device length constant? */ 184ca987d46SWarner Losh 1853dfe152dSWarner Losh switch(dev->d_dev->dv_type) { 186ca987d46SWarner Losh case DEVT_NONE: 187ca987d46SWarner Losh strcpy(buf, "(no device)"); 188ca987d46SWarner Losh break; 189ca987d46SWarner Losh 190ca987d46SWarner Losh case DEVT_CD: 1913dfe152dSWarner Losh sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 192ca987d46SWarner Losh break; 193ca987d46SWarner Losh 194ca987d46SWarner Losh case DEVT_DISK: 195ca987d46SWarner Losh return (disk_fmtdev(vdev)); 196ca987d46SWarner Losh 197ca987d46SWarner Losh case DEVT_NET: 1983dfe152dSWarner Losh sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 199ca987d46SWarner Losh break; 200ca987d46SWarner Losh 201ca987d46SWarner Losh case DEVT_ZFS: 202ca987d46SWarner Losh #if defined(USERBOOT_ZFS_SUPPORT) 203ca987d46SWarner Losh return (zfs_fmtdev(vdev)); 204ca987d46SWarner Losh #else 2053dfe152dSWarner Losh sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 206ca987d46SWarner Losh #endif 207ca987d46SWarner Losh break; 208ca987d46SWarner Losh } 209ca987d46SWarner Losh return (buf); 210ca987d46SWarner Losh } 211ca987d46SWarner Losh 212ca987d46SWarner Losh 213ca987d46SWarner Losh /* 214ca987d46SWarner Losh * Set currdev to suit the value being supplied in (value) 215ca987d46SWarner Losh */ 216ca987d46SWarner Losh int 217ca987d46SWarner Losh userboot_setcurrdev(struct env_var *ev, int flags, const void *value) 218ca987d46SWarner Losh { 219ca987d46SWarner Losh struct disk_devdesc *ncurr; 220ca987d46SWarner Losh int rv; 221ca987d46SWarner Losh 222ca987d46SWarner Losh if ((rv = userboot_parsedev(&ncurr, value, NULL)) != 0) 223ca987d46SWarner Losh return (rv); 224ca987d46SWarner Losh free(ncurr); 225ca987d46SWarner Losh env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 226ca987d46SWarner Losh return (0); 227ca987d46SWarner Losh } 228