177943Sdfr/*-
277943Sdfr * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3164010Smarcel * Copyright (c) 2006 Marcel Moolenaar
477943Sdfr * All rights reserved.
577943Sdfr *
677943Sdfr * Redistribution and use in source and binary forms, with or without
777943Sdfr * modification, are permitted provided that the following conditions
877943Sdfr * are met:
977943Sdfr * 1. Redistributions of source code must retain the above copyright
1077943Sdfr *    notice, this list of conditions and the following disclaimer.
1177943Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1277943Sdfr *    notice, this list of conditions and the following disclaimer in the
1377943Sdfr *    documentation and/or other materials provided with the distribution.
1477943Sdfr *
1577943Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1677943Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1777943Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1877943Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1977943Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2077943Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2177943Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2277943Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2377943Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2477943Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2577943Sdfr * SUCH DAMAGE.
2677943Sdfr */
2777943Sdfr
28124140Sobrien#include <sys/cdefs.h>
29124140Sobrien__FBSDID("$FreeBSD$");
30124140Sobrien
3177943Sdfr#include <stand.h>
3277943Sdfr#include <string.h>
3377943Sdfr#include <sys/disklabel.h>
3477943Sdfr#include "bootstrap.h"
3577943Sdfr
3677943Sdfr#include <efi.h>
3777943Sdfr#include <efilib.h>
3877943Sdfr
39164010Smarcelstatic int ia64_parsedev(struct devdesc **, const char *, const char **);
4077943Sdfr
4177943Sdfr/*
4277943Sdfr * Point (dev) at an allocated device specifier for the device matching the
4377943Sdfr * path in (devspec). If it contains an explicit device specification,
4477943Sdfr * use that.  If not, use the default device.
4577943Sdfr */
4677943Sdfrint
47164010Smarcelia64_getdev(void **vdev, const char *devspec, const char **path)
4877943Sdfr{
49164010Smarcel	struct devdesc **dev = (struct devdesc **)vdev;
50164010Smarcel	int rv;
51164010Smarcel
5283190Sdfr	/*
53164010Smarcel	 * If it looks like this is just a path and no device, then
54164010Smarcel	 * use the current device instead.
5583190Sdfr	 */
56164010Smarcel	if (devspec == NULL || *devspec == '/' || !strchr(devspec, ':')) {
57164010Smarcel		rv = ia64_parsedev(dev, getenv("currdev"), NULL);
58164010Smarcel		if (rv == 0 && path != NULL)
5983190Sdfr			*path = devspec;
60164010Smarcel		return (rv);
6183190Sdfr	}
62164010Smarcel
63164010Smarcel	/* Parse the device name off the beginning of the devspec. */
64164010Smarcel	return (ia64_parsedev(dev, devspec, path));
6577943Sdfr}
6677943Sdfr
6777943Sdfr/*
6877943Sdfr * Point (dev) at an allocated device specifier matching the string version
6977943Sdfr * at the beginning of (devspec).  Return a pointer to the remaining
7077943Sdfr * text in (path).
7177943Sdfr *
7277943Sdfr * In all cases, the beginning of (devspec) is compared to the names
7377943Sdfr * of known devices in the device switch, and then any following text
7477943Sdfr * is parsed according to the rules applied to the device type.
7577943Sdfr *
7677943Sdfr * For disk-type devices, the syntax is:
7777943Sdfr *
78164010Smarcel * fs<unit>:
7977943Sdfr */
8077943Sdfrstatic int
81164010Smarcelia64_parsedev(struct devdesc **dev, const char *devspec, const char **path)
8277943Sdfr{
83164010Smarcel	struct devdesc *idev;
84164010Smarcel	struct devsw *dv;
85164010Smarcel	char *cp;
86164010Smarcel	const char *np;
87164010Smarcel	int i, err;
8877943Sdfr
8983190Sdfr	/* minimum length check */
9083190Sdfr	if (strlen(devspec) < 2)
91164010Smarcel		return (EINVAL);
9277943Sdfr
9383190Sdfr	/* look for a device that matches */
94164010Smarcel	for (i = 0; devsw[i] != NULL; i++) {
95164010Smarcel		dv = devsw[i];
96164010Smarcel		if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name)))
9783190Sdfr			break;
9877943Sdfr	}
99164010Smarcel	if (devsw[i] == NULL)
100164010Smarcel		return (ENOENT);
10177943Sdfr
102164010Smarcel	idev = malloc(sizeof(struct devdesc));
103164010Smarcel	if (idev == NULL)
104164010Smarcel		return (ENOMEM);
10577943Sdfr
106164010Smarcel	idev->d_dev = dv;
107164010Smarcel	idev->d_type = dv->dv_type;
108164010Smarcel	idev->d_unit = -1;
10977943Sdfr
110164010Smarcel	err = 0;
111164010Smarcel	np = devspec + strlen(dv->dv_name);
112164010Smarcel	if (*np != '\0' && *np != ':') {
113164010Smarcel		idev->d_unit = strtol(np, &cp, 0);
114164010Smarcel		if (cp == np) {
115164010Smarcel			idev->d_unit = -1;
116164010Smarcel			free(idev);
117164010Smarcel			return (EUNIT);
11883190Sdfr		}
11977943Sdfr	}
120164010Smarcel	if (*cp != '\0' && *cp != ':') {
12183190Sdfr		free(idev);
122164010Smarcel		return (EINVAL);
12377943Sdfr	}
12477943Sdfr
125164010Smarcel	if (path != NULL)
126164010Smarcel		*path = (*cp == 0) ? cp : cp + 1;
127164010Smarcel	if (dev != NULL)
128164010Smarcel		*dev = idev;
129164010Smarcel	else
130164010Smarcel		free(idev);
131164010Smarcel	return (0);
13277943Sdfr}
13377943Sdfr
13477943Sdfrchar *
135164010Smarcelia64_fmtdev(void *vdev)
13677943Sdfr{
137164010Smarcel	struct devdesc *dev = (struct devdesc *)vdev;
138164010Smarcel	static char buf[32];	/* XXX device length constant? */
139164010Smarcel
14083190Sdfr	switch(dev->d_type) {
14183190Sdfr	case DEVT_NONE:
14283190Sdfr		strcpy(buf, "(no device)");
14383190Sdfr		break;
14477943Sdfr
145164010Smarcel	default:
146163897Smarcel		sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
14783190Sdfr		break;
14883190Sdfr	}
149164010Smarcel
15083190Sdfr	return(buf);
15177943Sdfr}
15277943Sdfr
15377943Sdfr/*
15477943Sdfr * Set currdev to suit the value being supplied in (value)
15577943Sdfr */
15677943Sdfrint
157164010Smarcelia64_setcurrdev(struct env_var *ev, int flags, const void *value)
15877943Sdfr{
159164010Smarcel	struct devdesc *ncurr;
160164010Smarcel	int rv;
161164010Smarcel
162164010Smarcel	rv = ia64_parsedev(&ncurr, value, NULL);
163164010Smarcel	if (rv != 0)
16483190Sdfr		return(rv);
165164010Smarcel
16683190Sdfr	free(ncurr);
16783190Sdfr	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
168164010Smarcel	return (0);
16977943Sdfr}
170