1206376Srpaulo/*-
2206376Srpaulo * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3206376Srpaulo * Copyright (c) 2006 Marcel Moolenaar
4206376Srpaulo * All rights reserved.
5206376Srpaulo *
6206376Srpaulo * Redistribution and use in source and binary forms, with or without
7206376Srpaulo * modification, are permitted provided that the following conditions
8206376Srpaulo * are met:
9206376Srpaulo * 1. Redistributions of source code must retain the above copyright
10206376Srpaulo *    notice, this list of conditions and the following disclaimer.
11206376Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
12206376Srpaulo *    notice, this list of conditions and the following disclaimer in the
13206376Srpaulo *    documentation and/or other materials provided with the distribution.
14206376Srpaulo *
15206376Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16206376Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17206376Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18206376Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19206376Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20206376Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21206376Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22206376Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23206376Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24206376Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25206376Srpaulo * SUCH DAMAGE.
26206376Srpaulo */
27206376Srpaulo
28206376Srpaulo#include <sys/cdefs.h>
29206376Srpaulo__FBSDID("$FreeBSD$");
30206376Srpaulo
31206376Srpaulo#include <stand.h>
32206376Srpaulo#include <string.h>
33206376Srpaulo#include <sys/disklabel.h>
34206376Srpaulo#include "bootstrap.h"
35206376Srpaulo
36206376Srpaulo#include <efi.h>
37206376Srpaulo#include <efilib.h>
38206376Srpaulo
39206376Srpaulostatic int i386_parsedev(struct devdesc **, const char *, const char **);
40206376Srpaulo
41206376Srpaulo/*
42206376Srpaulo * Point (dev) at an allocated device specifier for the device matching the
43206376Srpaulo * path in (devspec). If it contains an explicit device specification,
44206376Srpaulo * use that.  If not, use the default device.
45206376Srpaulo */
46206376Srpauloint
47206376Srpauloi386_getdev(void **vdev, const char *devspec, const char **path)
48206376Srpaulo{
49206376Srpaulo	struct devdesc **dev = (struct devdesc **)vdev;
50206376Srpaulo	int rv;
51206376Srpaulo
52206376Srpaulo	/*
53206376Srpaulo	 * If it looks like this is just a path and no device, then
54206376Srpaulo	 * use the current device instead.
55206376Srpaulo	 */
56206376Srpaulo	if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) {
57206376Srpaulo		rv = i386_parsedev(dev, getenv("currdev"), NULL);
58206376Srpaulo		if (rv == 0 && path != NULL)
59206376Srpaulo			*path = devspec;
60206376Srpaulo		return (rv);
61206376Srpaulo	}
62206376Srpaulo
63206376Srpaulo	/* Parse the device name off the beginning of the devspec. */
64206376Srpaulo	return (i386_parsedev(dev, devspec, path));
65206376Srpaulo}
66206376Srpaulo
67206376Srpaulo/*
68206376Srpaulo * Point (dev) at an allocated device specifier matching the string version
69206376Srpaulo * at the beginning of (devspec).  Return a pointer to the remaining
70206376Srpaulo * text in (path).
71206376Srpaulo *
72206376Srpaulo * In all cases, the beginning of (devspec) is compared to the names
73206376Srpaulo * of known devices in the device switch, and then any following text
74206376Srpaulo * is parsed according to the rules applied to the device type.
75206376Srpaulo *
76206376Srpaulo * For disk-type devices, the syntax is:
77206376Srpaulo *
78206376Srpaulo * fs<unit>:
79206376Srpaulo */
80206376Srpaulostatic int
81206376Srpauloi386_parsedev(struct devdesc **dev, const char *devspec, const char **path)
82206376Srpaulo{
83206376Srpaulo	struct devdesc *idev;
84206376Srpaulo	struct devsw *dv;
85206376Srpaulo	char *cp;
86206376Srpaulo	const char *np;
87206376Srpaulo	int i, err;
88206376Srpaulo
89206376Srpaulo	/* minimum length check */
90206376Srpaulo	if (strlen(devspec) < 2)
91206376Srpaulo		return (EINVAL);
92206376Srpaulo
93206376Srpaulo	/* look for a device that matches */
94206376Srpaulo	for (i = 0; devsw[i] != NULL; i++) {
95206376Srpaulo		dv = devsw[i];
96206376Srpaulo		if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name)))
97206376Srpaulo			break;
98206376Srpaulo	}
99206376Srpaulo	if (devsw[i] == NULL)
100206376Srpaulo		return (ENOENT);
101206376Srpaulo
102206376Srpaulo	idev = malloc(sizeof(struct devdesc));
103206376Srpaulo	if (idev == NULL)
104206376Srpaulo		return (ENOMEM);
105206376Srpaulo
106206376Srpaulo	idev->d_dev = dv;
107206376Srpaulo	idev->d_type = dv->dv_type;
108206376Srpaulo	idev->d_unit = -1;
109206376Srpaulo
110206376Srpaulo	err = 0;
111206376Srpaulo	np = devspec + strlen(dv->dv_name);
112206376Srpaulo	if (*np != '\0' && *np != ':') {
113206376Srpaulo		idev->d_unit = strtol(np, &cp, 0);
114206376Srpaulo		if (cp == np) {
115206376Srpaulo			idev->d_unit = -1;
116206376Srpaulo			free(idev);
117206376Srpaulo			return (EUNIT);
118206376Srpaulo		}
119206376Srpaulo	}
120206376Srpaulo	if (*cp != '\0' && *cp != ':') {
121206376Srpaulo		free(idev);
122206376Srpaulo		return (EINVAL);
123206376Srpaulo	}
124206376Srpaulo
125206376Srpaulo	if (path != NULL)
126206376Srpaulo		*path = (*cp == 0) ? cp : cp + 1;
127206376Srpaulo	if (dev != NULL)
128206376Srpaulo		*dev = idev;
129206376Srpaulo	else
130206376Srpaulo		free(idev);
131206376Srpaulo	return (0);
132206376Srpaulo}
133206376Srpaulo
134206376Srpaulochar *
135206376Srpauloi386_fmtdev(void *vdev)
136206376Srpaulo{
137206376Srpaulo	struct devdesc *dev = (struct devdesc *)vdev;
138206376Srpaulo	static char buf[32];	/* XXX device length constant? */
139206376Srpaulo
140206376Srpaulo	switch(dev->d_type) {
141206376Srpaulo	case DEVT_NONE:
142206376Srpaulo		strcpy(buf, "(no device)");
143206376Srpaulo		break;
144206376Srpaulo
145206376Srpaulo	default:
146206376Srpaulo		sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
147206376Srpaulo		break;
148206376Srpaulo	}
149206376Srpaulo
150206376Srpaulo	return(buf);
151206376Srpaulo}
152206376Srpaulo
153206376Srpaulo/*
154206376Srpaulo * Set currdev to suit the value being supplied in (value)
155206376Srpaulo */
156206376Srpauloint
157206376Srpauloi386_setcurrdev(struct env_var *ev, int flags, const void *value)
158206376Srpaulo{
159206376Srpaulo	struct devdesc *ncurr;
160206376Srpaulo	int rv;
161206376Srpaulo
162206376Srpaulo	rv = i386_parsedev(&ncurr, value, NULL);
163206376Srpaulo	if (rv != 0)
164206376Srpaulo		return(rv);
165206376Srpaulo
166206376Srpaulo	free(ncurr);
167206376Srpaulo	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
168206376Srpaulo	return (0);
169206376Srpaulo}
170