devicename.c revision 181282
138465Smsmith/*-
238465Smsmith * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
338465Smsmith * All rights reserved.
438465Smsmith *
538465Smsmith * Redistribution and use in source and binary forms, with or without
638465Smsmith * modification, are permitted provided that the following conditions
738465Smsmith * are met:
838465Smsmith * 1. Redistributions of source code must retain the above copyright
938465Smsmith *    notice, this list of conditions and the following disclaimer.
1038465Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1138465Smsmith *    notice, this list of conditions and the following disclaimer in the
1238465Smsmith *    documentation and/or other materials provided with the distribution.
1338465Smsmith *
1438465Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538465Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638465Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738465Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838465Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938465Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038465Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138465Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238465Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338465Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438465Smsmith * SUCH DAMAGE.
2538465Smsmith */
2638465Smsmith
27119482Sobrien#include <sys/cdefs.h>
28119482Sobrien__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/devicename.c 181282 2008-08-04 07:01:42Z cperciva $");
29119482Sobrien
3038465Smsmith#include <stand.h>
3138465Smsmith#include <string.h>
3238465Smsmith#include <sys/disklabel.h>
3338465Smsmith#include "bootstrap.h"
3438465Smsmith#include "libi386.h"
3538465Smsmith
3639673Sdfrstatic int	i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path);
3738465Smsmith
3838465Smsmith/*
3938465Smsmith * Point (dev) at an allocated device specifier for the device matching the
4038465Smsmith * path in (devspec). If it contains an explicit device specification,
4138465Smsmith * use that.  If not, use the default device.
4238465Smsmith */
4338465Smsmithint
4439673Sdfri386_getdev(void **vdev, const char *devspec, const char **path)
4538465Smsmith{
4638465Smsmith    struct i386_devdesc **dev = (struct i386_devdesc **)vdev;
4738465Smsmith    int				rv;
4838465Smsmith
4938465Smsmith    /*
5038465Smsmith     * If it looks like this is just a path and no
5138465Smsmith     * device, go with the current device.
5238465Smsmith     */
5338465Smsmith    if ((devspec == NULL) ||
5438465Smsmith	(devspec[0] == '/') ||
5538465Smsmith	(strchr(devspec, ':') == NULL)) {
5638465Smsmith
5738465Smsmith	if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
5838465Smsmith	    (path != NULL))
5938465Smsmith		*path = devspec;
6038465Smsmith	return(rv);
6138465Smsmith    }
6238465Smsmith
6338465Smsmith    /*
6438465Smsmith     * Try to parse the device name off the beginning of the devspec
6538465Smsmith     */
6638465Smsmith    return(i386_parsedev(dev, devspec, path));
6738465Smsmith}
6838465Smsmith
6938465Smsmith/*
7038465Smsmith * Point (dev) at an allocated device specifier matching the string version
7138465Smsmith * at the beginning of (devspec).  Return a pointer to the remaining
7238465Smsmith * text in (path).
7338465Smsmith *
7438465Smsmith * In all cases, the beginning of (devspec) is compared to the names
7538465Smsmith * of known devices in the device switch, and then any following text
7638465Smsmith * is parsed according to the rules applied to the device type.
7738465Smsmith *
7838465Smsmith * For disk-type devices, the syntax is:
7938465Smsmith *
8038465Smsmith * disk<unit>[s<slice>][<partition>]:
8138465Smsmith *
8238465Smsmith */
8338465Smsmithstatic int
8439673Sdfri386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path)
8538465Smsmith{
8638465Smsmith    struct i386_devdesc *idev;
8738465Smsmith    struct devsw	*dv;
8838465Smsmith    int			i, unit, slice, partition, err;
8939673Sdfr    char		*cp;
9039673Sdfr    const char		*np;
9138465Smsmith
9238465Smsmith    /* minimum length check */
9338465Smsmith    if (strlen(devspec) < 2)
9438465Smsmith	return(EINVAL);
9538465Smsmith
9638465Smsmith    /* look for a device that matches */
9738465Smsmith    for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
9838465Smsmith	if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) {
9938465Smsmith	    dv = devsw[i];
10038465Smsmith	    break;
10138465Smsmith	}
10238465Smsmith    }
10338465Smsmith    if (dv == NULL)
10438465Smsmith	return(ENOENT);
10538465Smsmith    idev = malloc(sizeof(struct i386_devdesc));
10638465Smsmith    err = 0;
10738465Smsmith    np = (devspec + strlen(dv->dv_name));
10838465Smsmith
10938465Smsmith    switch(dv->dv_type) {
11038465Smsmith    case DEVT_NONE:			/* XXX what to do here?  Do we care? */
11138465Smsmith	break;
11238465Smsmith
11338465Smsmith    case DEVT_DISK:
11438465Smsmith	unit = -1;
11538465Smsmith	slice = -1;
11638465Smsmith	partition = -1;
11738465Smsmith	if (*np && (*np != ':')) {
11838465Smsmith	    unit = strtol(np, &cp, 10);	/* next comes the unit number */
11938465Smsmith	    if (cp == np) {
12038465Smsmith		err = EUNIT;
12138465Smsmith		goto fail;
12238465Smsmith	    }
123172940Sjhb	    if (*cp == 'p') {		/* got a GPT partition */
12438465Smsmith		np = cp + 1;
12538465Smsmith		slice = strtol(np, &cp, 10);
12638465Smsmith		if (cp == np) {
12738465Smsmith		    err = ESLICE;
12838465Smsmith		    goto fail;
12938465Smsmith		}
130172940Sjhb		if (*cp && (*cp != ':')) {
131172940Sjhb		    err = EINVAL;
13238465Smsmith		    goto fail;
13338465Smsmith		}
134172940Sjhb		partition = 0xff;
135172940Sjhb	    } else {
136172940Sjhb		if (*cp == 's') {		/* got a slice number */
137172940Sjhb		    np = cp + 1;
138172940Sjhb		    slice = strtol(np, &cp, 10);
139172940Sjhb		    if (cp == np) {
140172940Sjhb			err = ESLICE;
141172940Sjhb			goto fail;
142172940Sjhb		    }
143172940Sjhb		}
144172940Sjhb		if (*cp && (*cp != ':')) {
145172940Sjhb		    partition = *cp - 'a';	/* got a partition number */
146172940Sjhb		    if ((partition < 0) || (partition >= MAXPARTITIONS)) {
147172940Sjhb			err = EPART;
148172940Sjhb			goto fail;
149172940Sjhb		    }
150172940Sjhb		    cp++;
151172940Sjhb		}
15238465Smsmith	    }
153181282Scperciva	} else {
154181282Scperciva		cp = np;
15538465Smsmith	}
15638465Smsmith	if (*cp && (*cp != ':')) {
15738465Smsmith	    err = EINVAL;
15838465Smsmith	    goto fail;
15938465Smsmith	}
16038465Smsmith
161163897Smarcel	idev->d_unit = unit;
16238465Smsmith	idev->d_kind.biosdisk.slice = slice;
16338465Smsmith	idev->d_kind.biosdisk.partition = partition;
16438465Smsmith	if (path != NULL)
16538465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
16638465Smsmith	break;
16786091Sjhb
16886091Sjhb    case DEVT_CD:
16938465Smsmith    case DEVT_NET:
17038465Smsmith	unit = 0;
17186091Sjhb
17238465Smsmith	if (*np && (*np != ':')) {
17338465Smsmith	    unit = strtol(np, &cp, 0);	/* get unit number if present */
17438465Smsmith	    if (cp == np) {
17538465Smsmith		err = EUNIT;
17638465Smsmith		goto fail;
17738465Smsmith	    }
178181282Scperciva	} else {
179181282Scperciva		cp = np;
18038465Smsmith	}
18138465Smsmith	if (*cp && (*cp != ':')) {
18238465Smsmith	    err = EINVAL;
18338465Smsmith	    goto fail;
18438465Smsmith	}
18586091Sjhb
186163897Smarcel	idev->d_unit = unit;
18738465Smsmith	if (path != NULL)
18838465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
18938465Smsmith	break;
19038465Smsmith
19138465Smsmith    default:
19238465Smsmith	err = EINVAL;
19338465Smsmith	goto fail;
19438465Smsmith    }
19538465Smsmith    idev->d_dev = dv;
19638465Smsmith    idev->d_type = dv->dv_type;
19738465Smsmith    if (dev == NULL) {
19838465Smsmith	free(idev);
19938465Smsmith    } else {
20038465Smsmith	*dev = idev;
20138465Smsmith    }
20238465Smsmith    return(0);
20338465Smsmith
20438465Smsmith fail:
20538465Smsmith    free(idev);
20638465Smsmith    return(err);
20738465Smsmith}
20838465Smsmith
20938465Smsmith
21038465Smsmithchar *
21138465Smsmithi386_fmtdev(void *vdev)
21238465Smsmith{
21338465Smsmith    struct i386_devdesc	*dev = (struct i386_devdesc *)vdev;
21438465Smsmith    static char		buf[128];	/* XXX device length constant? */
21538465Smsmith    char		*cp;
21638465Smsmith
21738465Smsmith    switch(dev->d_type) {
21838465Smsmith    case DEVT_NONE:
21938465Smsmith	strcpy(buf, "(no device)");
22038465Smsmith	break;
22138465Smsmith
22286091Sjhb    case DEVT_CD:
223163897Smarcel	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
22486091Sjhb	break;
22586091Sjhb
22638465Smsmith    case DEVT_DISK:
22738465Smsmith	cp = buf;
228163897Smarcel	cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_unit);
229172940Sjhb	if (dev->d_kind.biosdisk.partition == 0xff) {
230172940Sjhb	    cp += sprintf(cp, "p%d", dev->d_kind.biosdisk.slice);
231172940Sjhb	} else {
232172940Sjhb	    if (dev->d_kind.biosdisk.slice > 0)
233172940Sjhb		cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice);
234172940Sjhb	    if (dev->d_kind.biosdisk.partition >= 0)
235172940Sjhb		cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a');
236172940Sjhb	}
23738465Smsmith	strcat(cp, ":");
23838465Smsmith	break;
23938465Smsmith
24038465Smsmith    case DEVT_NET:
241163897Smarcel	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
24238465Smsmith	break;
24338465Smsmith    }
24438465Smsmith    return(buf);
24538465Smsmith}
24638465Smsmith
24738465Smsmith
24838465Smsmith/*
24938465Smsmith * Set currdev to suit the value being supplied in (value)
25038465Smsmith */
25138465Smsmithint
252146697Sjhbi386_setcurrdev(struct env_var *ev, int flags, const void *value)
25338465Smsmith{
25438465Smsmith    struct i386_devdesc	*ncurr;
25538465Smsmith    int			rv;
25639662Smsmith
25738465Smsmith    if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0)
25838465Smsmith	return(rv);
25938465Smsmith    free(ncurr);
26038465Smsmith    env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
26138465Smsmith    return(0);
26238465Smsmith}
263