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*17276525SWarner Losh static int userboot_parsedev(struct devdesc **dev, const char *devspec, 425d5a6216SToomas 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 { 52*17276525SWarner Losh struct devdesc **dev = (struct 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 635d5a6216SToomas Soome rv = userboot_parsedev(dev, getenv("currdev"), NULL); 645d5a6216SToomas 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*17276525SWarner Losh userboot_parsedev(struct devdesc **dev, const char *devspec, 915d5a6216SToomas Soome const char **path) 92ca987d46SWarner Losh { 93*17276525SWarner Losh struct 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++) { 1055d5a6216SToomas Soome if (strncmp(devspec, devsw[i]->dv_name, 1065d5a6216SToomas 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: 122*17276525SWarner Losh free(idev); 123*17276525SWarner Losh err = disk_parsedev(&idev, np, path); 124ca987d46SWarner Losh if (err != 0) 125ca987d46SWarner Losh goto fail; 126ca987d46SWarner Losh break; 127ca987d46SWarner Losh 128ca987d46SWarner Losh case DEVT_CD: 129ca987d46SWarner Losh case DEVT_NET: 130ca987d46SWarner Losh unit = 0; 131ca987d46SWarner Losh 132ca987d46SWarner Losh if (*np && (*np != ':')) { 1335d5a6216SToomas Soome /* get unit number if present */ 1345d5a6216SToomas Soome unit = strtol(np, (char **)&cp, 0); 135ca987d46SWarner Losh if (cp == np) { 136ca987d46SWarner Losh err = EUNIT; 137ca987d46SWarner Losh goto fail; 138ca987d46SWarner Losh } 139ca987d46SWarner Losh } else { 140ca987d46SWarner Losh cp = np; 141ca987d46SWarner Losh } 142ca987d46SWarner Losh if (*cp && (*cp != ':')) { 143ca987d46SWarner Losh err = EINVAL; 144ca987d46SWarner Losh goto fail; 145ca987d46SWarner Losh } 146ca987d46SWarner Losh 147*17276525SWarner Losh idev->d_unit = unit; 148ca987d46SWarner Losh if (path != NULL) 149ca987d46SWarner Losh *path = (*cp == 0) ? cp : cp + 1; 150ca987d46SWarner Losh break; 151ca987d46SWarner Losh 152ca987d46SWarner Losh case DEVT_ZFS: 153ca987d46SWarner Losh #if defined(USERBOOT_ZFS_SUPPORT) 154*17276525SWarner Losh /* XXX assumes sizeof disk_devdesc >= sizeof zfs_devdesc */ 155ca987d46SWarner Losh err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); 156ca987d46SWarner Losh if (err != 0) 157ca987d46SWarner Losh goto fail; 158ca987d46SWarner Losh break; 159ca987d46SWarner Losh #else 160ca987d46SWarner Losh /* FALLTHROUGH */ 161ca987d46SWarner Losh #endif 162ca987d46SWarner Losh 163ca987d46SWarner Losh default: 164ca987d46SWarner Losh err = EINVAL; 165ca987d46SWarner Losh goto fail; 166ca987d46SWarner Losh } 167*17276525SWarner Losh idev->d_dev = dv; 168ca987d46SWarner Losh if (dev == NULL) { 169ca987d46SWarner Losh free(idev); 170ca987d46SWarner Losh } else { 171ca987d46SWarner Losh *dev = idev; 172ca987d46SWarner Losh } 173ca987d46SWarner Losh return (0); 174ca987d46SWarner Losh 175ca987d46SWarner Losh fail: 176ca987d46SWarner Losh free(idev); 177ca987d46SWarner Losh return (err); 178ca987d46SWarner Losh } 179ca987d46SWarner Losh 180ca987d46SWarner Losh 181ca987d46SWarner Losh /* 182ca987d46SWarner Losh * Set currdev to suit the value being supplied in (value) 183ca987d46SWarner Losh */ 184ca987d46SWarner Losh int 185ca987d46SWarner Losh userboot_setcurrdev(struct env_var *ev, int flags, const void *value) 186ca987d46SWarner Losh { 187*17276525SWarner Losh struct devdesc *ncurr; 188ca987d46SWarner Losh int rv; 189ca987d46SWarner Losh 190ca987d46SWarner Losh if ((rv = userboot_parsedev(&ncurr, value, NULL)) != 0) 191ca987d46SWarner Losh return (rv); 192ca987d46SWarner Losh free(ncurr); 193b4cb3fe0SToomas Soome 194b4cb3fe0SToomas Soome return (mount_currdev(ev, flags, value)); 195ca987d46SWarner Losh } 196