devicename.c revision 186231
1176348Smarcel/*-
2176348Smarcel * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3176348Smarcel * All rights reserved.
4176348Smarcel *
5176348Smarcel * Redistribution and use in source and binary forms, with or without
6176348Smarcel * modification, are permitted provided that the following conditions
7176348Smarcel * are met:
8176348Smarcel * 1. Redistributions of source code must retain the above copyright
9176348Smarcel *    notice, this list of conditions and the following disclaimer.
10176348Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11176348Smarcel *    notice, this list of conditions and the following disclaimer in the
12176348Smarcel *    documentation and/or other materials provided with the distribution.
13176348Smarcel *
14176348Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15176348Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16176348Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17176348Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18176348Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19176348Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20176348Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21176348Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22176348Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23176348Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24176348Smarcel * SUCH DAMAGE.
25176348Smarcel */
26176348Smarcel
27176348Smarcel#include <sys/cdefs.h>
28176348Smarcel__FBSDID("$FreeBSD: head/sys/boot/uboot/lib/devicename.c 186231 2008-12-17 15:58:07Z raj $");
29176348Smarcel
30177152Sobrien#include <sys/disklabel.h>
31177152Sobrien
32176348Smarcel#include <stand.h>
33176348Smarcel#include <string.h>
34176348Smarcel
35176348Smarcel#include "bootstrap.h"
36176348Smarcel#include "libuboot.h"
37176348Smarcel
38186231Srajstatic int uboot_parsedev(struct uboot_devdesc **dev, const char *devspec,
39186231Sraj    const char **path);
40176348Smarcel
41177152Sobrien/*
42176348Smarcel * Point (dev) at an allocated device specifier for the device matching the
43176348Smarcel * path in (devspec). If it contains an explicit device specification,
44176348Smarcel * use that.  If not, use the default device.
45176348Smarcel */
46176348Smarcelint
47176348Smarceluboot_getdev(void **vdev, const char *devspec, const char **path)
48176348Smarcel{
49177152Sobrien	struct uboot_devdesc **dev = (struct uboot_devdesc **)vdev;
50177152Sobrien	int rv;
51176348Smarcel
52177152Sobrien	/*
53177152Sobrien	 * If it looks like this is just a path and no
54177152Sobrien	 * device, go with the current device.
55177152Sobrien	 */
56177152Sobrien	if ((devspec == NULL) || (devspec[0] == '/') ||
57177152Sobrien	    (strchr(devspec, ':') == NULL)) {
58177152Sobrien
59177152Sobrien		if (((rv = uboot_parsedev(dev, getenv("currdev"), NULL)) == 0)
60177152Sobrien		    && (path != NULL))
61176348Smarcel		*path = devspec;
62177152Sobrien		return(rv);
63177152Sobrien	}
64177152Sobrien
65177152Sobrien	/*
66177152Sobrien	 * Try to parse the device name off the beginning of the devspec.
67177152Sobrien	 */
68185099Sraj	return (uboot_parsedev(dev, devspec, path));
69176348Smarcel}
70176348Smarcel
71176348Smarcel/*
72176348Smarcel * Point (dev) at an allocated device specifier matching the string version
73176348Smarcel * at the beginning of (devspec).  Return a pointer to the remaining
74176348Smarcel * text in (path).
75176348Smarcel *
76176348Smarcel * In all cases, the beginning of (devspec) is compared to the names
77176348Smarcel * of known devices in the device switch, and then any following text
78176348Smarcel * is parsed according to the rules applied to the device type.
79176348Smarcel *
80176348Smarcel * For disk-type devices, the syntax is:
81176348Smarcel *
82185099Sraj * disk<unit>[<partition>]:
83177152Sobrien *
84176348Smarcel */
85176348Smarcelstatic int
86177152Sobrienuboot_parsedev(struct uboot_devdesc **dev, const char *devspec,
87177152Sobrien    const char **path)
88176348Smarcel{
89177152Sobrien	struct uboot_devdesc *idev;
90185099Sraj	struct devsw *dv;
91185099Sraj	char *cp;
92185099Sraj	const char *np;
93185099Sraj	int i, unit, partition, err;
94176348Smarcel
95177152Sobrien	/* minimum length check */
96177152Sobrien	if (strlen(devspec) < 2)
97177152Sobrien		return(EINVAL);
98176348Smarcel
99177152Sobrien	/* look for a device that matches */
100177152Sobrien	for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
101177152Sobrien		if (!strncmp(devspec, devsw[i]->dv_name,
102177152Sobrien		    strlen(devsw[i]->dv_name))) {
103177152Sobrien			dv = devsw[i];
104177152Sobrien			break;
105177152Sobrien		}
106176348Smarcel	}
107177152Sobrien	if (dv == NULL)
108177152Sobrien		return(ENOENT);
109177152Sobrien	idev = malloc(sizeof(struct uboot_devdesc));
110177152Sobrien	err = 0;
111177152Sobrien	np = (devspec + strlen(dv->dv_name));
112176348Smarcel
113177152Sobrien	switch(dv->dv_type) {
114185099Sraj	case DEVT_NONE:
115177152Sobrien		break;
116177152Sobrien
117177152Sobrien	case DEVT_DISK:
118177152Sobrien		unit = -1;
119177152Sobrien		partition = -1;
120177152Sobrien		if (*np && (*np != ':')) {
121177152Sobrien			/* next comes the unit number */
122177152Sobrien			unit = strtol(np, &cp, 10);
123177152Sobrien			if (cp == np) {
124177152Sobrien				err = EUNIT;
125177152Sobrien				goto fail;
126177152Sobrien			}
127177152Sobrien			if (*cp && (*cp != ':')) {
128185099Sraj				/* get partition */
129177152Sobrien				partition = *cp - 'a';
130177152Sobrien				if ((partition < 0) ||
131177152Sobrien				    (partition >= MAXPARTITIONS)) {
132177152Sobrien					err = EPART;
133177152Sobrien					goto fail;
134177152Sobrien				}
135177152Sobrien				cp++;
136177152Sobrien			}
137177152Sobrien		}
138177152Sobrien		if (*cp && (*cp != ':')) {
139177152Sobrien			err = EINVAL;
140185099Sraj			goto fail;
141176348Smarcel		}
142177152Sobrien
143177152Sobrien		idev->d_unit = unit;
144185099Sraj		idev->d_disk.partition = partition;
145185099Sraj		idev->d_disk.data = NULL;
146177152Sobrien		if (path != NULL)
147177152Sobrien			*path = (*cp == 0) ? cp : cp + 1;
148177152Sobrien		break;
149177152Sobrien
150177152Sobrien	case DEVT_NET:
151177152Sobrien		unit = 0;
152177152Sobrien
153177152Sobrien		if (*np && (*np != ':')) {
154177152Sobrien			/* get unit number if present */
155177152Sobrien			unit = strtol(np, &cp, 0);
156177152Sobrien			if (cp == np) {
157177152Sobrien				err = EUNIT;
158177152Sobrien				goto fail;
159177152Sobrien			}
160176348Smarcel		}
161177152Sobrien		if (*cp && (*cp != ':')) {
162177152Sobrien			err = EINVAL;
163177152Sobrien			goto fail;
164177152Sobrien		}
165185099Sraj		idev->d_unit = unit;
166176348Smarcel
167177152Sobrien		if (path != NULL)
168177152Sobrien			*path = (*cp == 0) ? cp : cp + 1;
169177152Sobrien		break;
170176348Smarcel
171177152Sobrien	default:
172177152Sobrien		err = EINVAL;
173176348Smarcel		goto fail;
174176348Smarcel	}
175177152Sobrien	idev->d_dev = dv;
176177152Sobrien	idev->d_type = dv->dv_type;
177177152Sobrien	if (dev == NULL) {
178177152Sobrien		free(idev);
179177152Sobrien	} else {
180177152Sobrien		*dev = idev;
181176348Smarcel	}
182186231Sraj	return (0);
183176348Smarcel
184177152Sobrienfail:
185176348Smarcel	free(idev);
186186231Sraj	return (err);
187176348Smarcel}
188176348Smarcel
189176348Smarcel
190176348Smarcelchar *
191176348Smarceluboot_fmtdev(void *vdev)
192176348Smarcel{
193177152Sobrien	struct uboot_devdesc *dev = (struct uboot_devdesc *)vdev;
194177152Sobrien	char *cp;
195186231Sraj	static char buf[128];
196176348Smarcel
197177152Sobrien	switch(dev->d_type) {
198177152Sobrien	case DEVT_NONE:
199177152Sobrien		strcpy(buf, "(no device)");
200177152Sobrien		break;
201176348Smarcel
202177152Sobrien	case DEVT_DISK:
203177152Sobrien		cp = buf;
204177152Sobrien		cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit);
205177152Sobrien		if (dev->d_kind.disk.partition >= 0)
206177152Sobrien			cp += sprintf(cp, "%c", dev->d_kind.disk.partition +
207177152Sobrien			    'a');
208177152Sobrien		strcat(cp, ":");
209177152Sobrien		break;
210177152Sobrien
211177152Sobrien	case DEVT_NET:
212177152Sobrien		sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
213177152Sobrien		break;
214177152Sobrien	}
215177152Sobrien	return(buf);
216176348Smarcel}
217176348Smarcel
218176348Smarcel/*
219177152Sobrien * Set currdev to suit the value being supplied in (value).
220176348Smarcel */
221176348Smarcelint
222176348Smarceluboot_setcurrdev(struct env_var *ev, int flags, const void *value)
223176348Smarcel{
224186231Sraj	struct uboot_devdesc *ncurr;
225186231Sraj	int rv;
226176348Smarcel
227177152Sobrien	if ((rv = uboot_parsedev(&ncurr, value, NULL)) != 0)
228186231Sraj		return (rv);
229177152Sobrien	free(ncurr);
230177152Sobrien	env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
231186231Sraj	return (0);
232176348Smarcel}
233