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