devicename.c revision 86091
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 *
2650477Speter * $FreeBSD: head/sys/boot/i386/libi386/devicename.c 86091 2001-11-05 18:58:33Z jhb $
2738465Smsmith */
2838465Smsmith
2938465Smsmith#include <stand.h>
3038465Smsmith#include <string.h>
3138465Smsmith#include <sys/disklabel.h>
3238465Smsmith#include "bootstrap.h"
3338465Smsmith#include "libi386.h"
3438465Smsmith
3539673Sdfrstatic int	i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path);
3638465Smsmith
3738465Smsmith/*
3838465Smsmith * Point (dev) at an allocated device specifier for the device matching the
3938465Smsmith * path in (devspec). If it contains an explicit device specification,
4038465Smsmith * use that.  If not, use the default device.
4138465Smsmith */
4238465Smsmithint
4339673Sdfri386_getdev(void **vdev, const char *devspec, const char **path)
4438465Smsmith{
4538465Smsmith    struct i386_devdesc **dev = (struct i386_devdesc **)vdev;
4638465Smsmith    int				rv;
4738465Smsmith
4838465Smsmith    /*
4938465Smsmith     * If it looks like this is just a path and no
5038465Smsmith     * device, go with the current device.
5138465Smsmith     */
5238465Smsmith    if ((devspec == NULL) ||
5338465Smsmith	(devspec[0] == '/') ||
5438465Smsmith	(strchr(devspec, ':') == NULL)) {
5538465Smsmith
5638465Smsmith	if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
5738465Smsmith	    (path != NULL))
5838465Smsmith		*path = devspec;
5938465Smsmith	return(rv);
6038465Smsmith    }
6138465Smsmith
6238465Smsmith    /*
6338465Smsmith     * Try to parse the device name off the beginning of the devspec
6438465Smsmith     */
6538465Smsmith    return(i386_parsedev(dev, devspec, path));
6638465Smsmith}
6738465Smsmith
6838465Smsmith/*
6938465Smsmith * Point (dev) at an allocated device specifier matching the string version
7038465Smsmith * at the beginning of (devspec).  Return a pointer to the remaining
7138465Smsmith * text in (path).
7238465Smsmith *
7338465Smsmith * In all cases, the beginning of (devspec) is compared to the names
7438465Smsmith * of known devices in the device switch, and then any following text
7538465Smsmith * is parsed according to the rules applied to the device type.
7638465Smsmith *
7738465Smsmith * For disk-type devices, the syntax is:
7838465Smsmith *
7938465Smsmith * disk<unit>[s<slice>][<partition>]:
8038465Smsmith *
8138465Smsmith */
8238465Smsmithstatic int
8339673Sdfri386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path)
8438465Smsmith{
8538465Smsmith    struct i386_devdesc *idev;
8638465Smsmith    struct devsw	*dv;
8738465Smsmith    int			i, unit, slice, partition, err;
8839673Sdfr    char		*cp;
8939673Sdfr    const char		*np;
9038465Smsmith
9138465Smsmith    /* minimum length check */
9238465Smsmith    if (strlen(devspec) < 2)
9338465Smsmith	return(EINVAL);
9438465Smsmith
9538465Smsmith    /* look for a device that matches */
9638465Smsmith    for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
9738465Smsmith	if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) {
9838465Smsmith	    dv = devsw[i];
9938465Smsmith	    break;
10038465Smsmith	}
10138465Smsmith    }
10238465Smsmith    if (dv == NULL)
10338465Smsmith	return(ENOENT);
10438465Smsmith    idev = malloc(sizeof(struct i386_devdesc));
10538465Smsmith    err = 0;
10638465Smsmith    np = (devspec + strlen(dv->dv_name));
10738465Smsmith
10838465Smsmith    switch(dv->dv_type) {
10938465Smsmith    case DEVT_NONE:			/* XXX what to do here?  Do we care? */
11038465Smsmith	break;
11138465Smsmith
11238465Smsmith    case DEVT_DISK:
11338465Smsmith	unit = -1;
11438465Smsmith	slice = -1;
11538465Smsmith	partition = -1;
11638465Smsmith	if (*np && (*np != ':')) {
11738465Smsmith	    unit = strtol(np, &cp, 10);	/* next comes the unit number */
11838465Smsmith	    if (cp == np) {
11938465Smsmith		err = EUNIT;
12038465Smsmith		goto fail;
12138465Smsmith	    }
12238465Smsmith	    if (*cp == 's') {		/* got a slice number */
12338465Smsmith		np = cp + 1;
12438465Smsmith		slice = strtol(np, &cp, 10);
12538465Smsmith		if (cp == np) {
12638465Smsmith		    err = ESLICE;
12738465Smsmith		    goto fail;
12838465Smsmith		}
12938465Smsmith	    }
13038465Smsmith	    if (*cp && (*cp != ':')) {
13138465Smsmith		partition = *cp - 'a';		/* get a partition number */
13238465Smsmith		if ((partition < 0) || (partition >= MAXPARTITIONS)) {
13338465Smsmith		    err = EPART;
13438465Smsmith		    goto fail;
13538465Smsmith		}
13638465Smsmith		cp++;
13738465Smsmith	    }
13838465Smsmith	}
13938465Smsmith	if (*cp && (*cp != ':')) {
14038465Smsmith	    err = EINVAL;
14138465Smsmith	    goto fail;
14238465Smsmith	}
14338465Smsmith
14438465Smsmith	idev->d_kind.biosdisk.unit = unit;
14538465Smsmith	idev->d_kind.biosdisk.slice = slice;
14638465Smsmith	idev->d_kind.biosdisk.partition = partition;
14738465Smsmith	if (path != NULL)
14838465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
14938465Smsmith	break;
15086091Sjhb
15186091Sjhb    case DEVT_CD:
15238465Smsmith    case DEVT_NET:
15338465Smsmith	unit = 0;
15486091Sjhb
15538465Smsmith	if (*np && (*np != ':')) {
15638465Smsmith	    unit = strtol(np, &cp, 0);	/* get unit number if present */
15738465Smsmith	    if (cp == np) {
15838465Smsmith		err = EUNIT;
15938465Smsmith		goto fail;
16038465Smsmith	    }
16138465Smsmith	}
16238465Smsmith	if (*cp && (*cp != ':')) {
16338465Smsmith	    err = EINVAL;
16438465Smsmith	    goto fail;
16538465Smsmith	}
16686091Sjhb
16786091Sjhb	if (dv->dv_type == DEVT_NET)
16886091Sjhb	    idev->d_kind.netif.unit = unit;
16986091Sjhb	else
17086091Sjhb	    idev->d_kind.bioscd.unit = unit;
17138465Smsmith	if (path != NULL)
17238465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
17338465Smsmith	break;
17438465Smsmith
17538465Smsmith    default:
17638465Smsmith	err = EINVAL;
17738465Smsmith	goto fail;
17838465Smsmith    }
17938465Smsmith    idev->d_dev = dv;
18038465Smsmith    idev->d_type = dv->dv_type;
18138465Smsmith    if (dev == NULL) {
18238465Smsmith	free(idev);
18338465Smsmith    } else {
18438465Smsmith	*dev = idev;
18538465Smsmith    }
18638465Smsmith    return(0);
18738465Smsmith
18838465Smsmith fail:
18938465Smsmith    free(idev);
19038465Smsmith    return(err);
19138465Smsmith}
19238465Smsmith
19338465Smsmith
19438465Smsmithchar *
19538465Smsmithi386_fmtdev(void *vdev)
19638465Smsmith{
19738465Smsmith    struct i386_devdesc	*dev = (struct i386_devdesc *)vdev;
19838465Smsmith    static char		buf[128];	/* XXX device length constant? */
19938465Smsmith    char		*cp;
20038465Smsmith
20138465Smsmith    switch(dev->d_type) {
20238465Smsmith    case DEVT_NONE:
20338465Smsmith	strcpy(buf, "(no device)");
20438465Smsmith	break;
20538465Smsmith
20686091Sjhb    case DEVT_CD:
20786091Sjhb	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.bioscd.unit);
20886091Sjhb	break;
20986091Sjhb
21038465Smsmith    case DEVT_DISK:
21138465Smsmith	cp = buf;
21238465Smsmith	cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_kind.biosdisk.unit);
21338465Smsmith	if (dev->d_kind.biosdisk.slice > 0)
21438465Smsmith	    cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice);
21538465Smsmith	if (dev->d_kind.biosdisk.partition >= 0)
21638465Smsmith	    cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a');
21738465Smsmith	strcat(cp, ":");
21838465Smsmith	break;
21938465Smsmith
22038465Smsmith    case DEVT_NET:
22138465Smsmith	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.netif.unit);
22238465Smsmith	break;
22338465Smsmith    }
22438465Smsmith    return(buf);
22538465Smsmith}
22638465Smsmith
22738465Smsmith
22838465Smsmith/*
22938465Smsmith * Set currdev to suit the value being supplied in (value)
23038465Smsmith */
23138465Smsmithint
23238465Smsmithi386_setcurrdev(struct env_var *ev, int flags, void *value)
23338465Smsmith{
23438465Smsmith    struct i386_devdesc	*ncurr;
23538465Smsmith    int			rv;
23639662Smsmith
23738465Smsmith    if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0)
23838465Smsmith	return(rv);
23938465Smsmith    free(ncurr);
24038465Smsmith    env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
24138465Smsmith    return(0);
24238465Smsmith}
24338465Smsmith
244