devicename.c revision 294997
1193323Sed/*- 2193323Sed * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3193323Sed * Copyright (c) 2006 Marcel Moolenaar 4193323Sed * All rights reserved. 5193323Sed * 6193323Sed * Redistribution and use in source and binary forms, with or without 7193323Sed * modification, are permitted provided that the following conditions 8193323Sed * are met: 9193323Sed * 1. Redistributions of source code must retain the above copyright 10193323Sed * notice, this list of conditions and the following disclaimer. 11193323Sed * 2. Redistributions in binary form must reproduce the above copyright 12193323Sed * notice, this list of conditions and the following disclaimer in the 13193323Sed * documentation and/or other materials provided with the distribution. 14193323Sed * 15193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24249423Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25249423Sdim * SUCH DAMAGE. 26249423Sdim */ 27249423Sdim 28249423Sdim#include <sys/cdefs.h> 29249423Sdim__FBSDID("$FreeBSD: stable/10/sys/boot/efi/loader/devicename.c 294997 2016-01-28 16:52:02Z smh $"); 30193323Sed 31193323Sed#include <stand.h> 32198090Srdivacky#include <string.h> 33193323Sed#include <sys/disklabel.h> 34198090Srdivacky#include <sys/param.h> 35249423Sdim#include <bootstrap.h> 36249423Sdim 37249423Sdim#include <efi.h> 38193323Sed#include <efilib.h> 39193323Sed 40193323Sed#include "loader_efi.h" 41193323Sed 42193323Sedstatic int efi_parsedev(struct devdesc **, const char *, const char **); 43193323Sed 44193323Sed/* 45218893Sdim * Point (dev) at an allocated device specifier for the device matching the 46193323Sed * path in (devspec). If it contains an explicit device specification, 47193323Sed * use that. If not, use the default device. 48193323Sed */ 49193323Sedint 50193323Sedefi_getdev(void **vdev, const char *devspec, const char **path) 51193323Sed{ 52193323Sed struct devdesc **dev = (struct devdesc **)vdev; 53193323Sed int rv; 54193323Sed 55193323Sed /* 56193323Sed * If it looks like this is just a path and no device, then 57193323Sed * use the current device instead. 58198892Srdivacky */ 59193323Sed if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) { 60193323Sed rv = efi_parsedev(dev, getenv("currdev"), NULL); 61193323Sed if (rv == 0 && path != NULL) 62193323Sed *path = devspec; 63193323Sed return (rv); 64193323Sed } 65193323Sed 66193323Sed /* Parse the device name off the beginning of the devspec. */ 67234353Sdim return (efi_parsedev(dev, devspec, path)); 68234353Sdim} 69234353Sdim 70234353Sdim/* 71234353Sdim * Point (dev) at an allocated device specifier matching the string version 72234353Sdim * at the beginning of (devspec). Return a pointer to the remaining 73234353Sdim * text in (path). 74234353Sdim * 75234353Sdim * In all cases, the beginning of (devspec) is compared to the names 76234353Sdim * of known devices in the device switch, and then any following text 77234353Sdim * is parsed according to the rules applied to the device type. 78234353Sdim * 79234353Sdim * For disk-type devices, the syntax is: 80234353Sdim * 81234353Sdim * fs<unit>: 82234353Sdim */ 83234353Sdimstatic int 84234353Sdimefi_parsedev(struct devdesc **dev, const char *devspec, const char **path) 85193323Sed{ 86193323Sed struct devdesc *idev; 87193323Sed struct devsw *dv; 88193323Sed char *cp; 89193323Sed const char *np; 90193323Sed int i; 91193323Sed 92193323Sed /* minimum length check */ 93193323Sed if (strlen(devspec) < 2) 94193323Sed return (EINVAL); 95193323Sed 96193323Sed /* look for a device that matches */ 97193323Sed for (i = 0; devsw[i] != NULL; i++) { 98193323Sed dv = devsw[i]; 99193323Sed if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name))) 100193323Sed break; 101193323Sed } 102193323Sed if (devsw[i] == NULL) 103193323Sed return (ENOENT); 104234353Sdim 105234353Sdim np = devspec + strlen(dv->dv_name); 106193323Sed 107234353Sdim { 108234353Sdim idev = malloc(sizeof(struct devdesc)); 109193323Sed if (idev == NULL) 110193323Sed return (ENOMEM); 111193323Sed 112193323Sed idev->d_dev = dv; 113193323Sed idev->d_type = dv->dv_type; 114234353Sdim idev->d_unit = -1; 115193323Sed if (*np != '\0' && *np != ':') { 116193323Sed idev->d_unit = strtol(np, &cp, 0); 117193323Sed if (cp == np) { 118193323Sed idev->d_unit = -1; 119193323Sed free(idev); 120193323Sed return (EUNIT); 121193323Sed } 122193323Sed } 123193323Sed } 124193323Sed 125193323Sed if (*cp != '\0' && *cp != ':') { 126193323Sed free(idev); 127193323Sed return (EINVAL); 128193323Sed } 129193323Sed 130193323Sed if (path != NULL) 131193323Sed *path = (*cp == 0) ? cp : cp + 1; 132193323Sed if (dev != NULL) 133193323Sed *dev = idev; 134193323Sed else 135193323Sed free(idev); 136193323Sed return (0); 137193323Sed} 138200581Srdivacky 139200581Srdivackychar * 140193323Sedefi_fmtdev(void *vdev) 141193323Sed{ 142193323Sed struct devdesc *dev = (struct devdesc *)vdev; 143193323Sed static char buf[SPECNAMELEN + 1]; 144193323Sed 145193323Sed switch(dev->d_type) { 146193323Sed case DEVT_NONE: 147193323Sed strcpy(buf, "(no device)"); 148207618Srdivacky break; 149207618Srdivacky 150207618Srdivacky default: 151207618Srdivacky sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); 152207618Srdivacky break; 153207618Srdivacky } 154207618Srdivacky 155207618Srdivacky return (buf); 156193323Sed} 157224145Sdim 158224145Sdim/* 159224145Sdim * Set currdev to suit the value being supplied in (value) 160224145Sdim */ 161193323Sedint 162193323Sedefi_setcurrdev(struct env_var *ev, int flags, const void *value) 163193323Sed{ 164193323Sed struct devdesc *ncurr; 165193323Sed int rv; 166193323Sed 167193323Sed rv = efi_parsedev(&ncurr, value, NULL); 168193323Sed if (rv != 0) 169193323Sed return (rv); 170193323Sed 171193323Sed free(ncurr); 172193323Sed env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL); 173193323Sed return (0); 174193323Sed} 175193323Sed