devicename.c revision 146697
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 146697 2005-05-27 19:28:04Z jhb $");
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	    }
12338465Smsmith	    if (*cp == 's') {		/* got a slice number */
12438465Smsmith		np = cp + 1;
12538465Smsmith		slice = strtol(np, &cp, 10);
12638465Smsmith		if (cp == np) {
12738465Smsmith		    err = ESLICE;
12838465Smsmith		    goto fail;
12938465Smsmith		}
13038465Smsmith	    }
13138465Smsmith	    if (*cp && (*cp != ':')) {
13238465Smsmith		partition = *cp - 'a';		/* get a partition number */
13338465Smsmith		if ((partition < 0) || (partition >= MAXPARTITIONS)) {
13438465Smsmith		    err = EPART;
13538465Smsmith		    goto fail;
13638465Smsmith		}
13738465Smsmith		cp++;
13838465Smsmith	    }
13938465Smsmith	}
14038465Smsmith	if (*cp && (*cp != ':')) {
14138465Smsmith	    err = EINVAL;
14238465Smsmith	    goto fail;
14338465Smsmith	}
14438465Smsmith
14538465Smsmith	idev->d_kind.biosdisk.unit = unit;
14638465Smsmith	idev->d_kind.biosdisk.slice = slice;
14738465Smsmith	idev->d_kind.biosdisk.partition = partition;
14838465Smsmith	if (path != NULL)
14938465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
15038465Smsmith	break;
15186091Sjhb
15286091Sjhb    case DEVT_CD:
15338465Smsmith    case DEVT_NET:
15438465Smsmith	unit = 0;
15586091Sjhb
15638465Smsmith	if (*np && (*np != ':')) {
15738465Smsmith	    unit = strtol(np, &cp, 0);	/* get unit number if present */
15838465Smsmith	    if (cp == np) {
15938465Smsmith		err = EUNIT;
16038465Smsmith		goto fail;
16138465Smsmith	    }
16238465Smsmith	}
16338465Smsmith	if (*cp && (*cp != ':')) {
16438465Smsmith	    err = EINVAL;
16538465Smsmith	    goto fail;
16638465Smsmith	}
16786091Sjhb
16886091Sjhb	if (dv->dv_type == DEVT_NET)
16986091Sjhb	    idev->d_kind.netif.unit = unit;
17086091Sjhb	else
17186091Sjhb	    idev->d_kind.bioscd.unit = unit;
17238465Smsmith	if (path != NULL)
17338465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
17438465Smsmith	break;
17538465Smsmith
17638465Smsmith    default:
17738465Smsmith	err = EINVAL;
17838465Smsmith	goto fail;
17938465Smsmith    }
18038465Smsmith    idev->d_dev = dv;
18138465Smsmith    idev->d_type = dv->dv_type;
18238465Smsmith    if (dev == NULL) {
18338465Smsmith	free(idev);
18438465Smsmith    } else {
18538465Smsmith	*dev = idev;
18638465Smsmith    }
18738465Smsmith    return(0);
18838465Smsmith
18938465Smsmith fail:
19038465Smsmith    free(idev);
19138465Smsmith    return(err);
19238465Smsmith}
19338465Smsmith
19438465Smsmith
19538465Smsmithchar *
19638465Smsmithi386_fmtdev(void *vdev)
19738465Smsmith{
19838465Smsmith    struct i386_devdesc	*dev = (struct i386_devdesc *)vdev;
19938465Smsmith    static char		buf[128];	/* XXX device length constant? */
20038465Smsmith    char		*cp;
20138465Smsmith
20238465Smsmith    switch(dev->d_type) {
20338465Smsmith    case DEVT_NONE:
20438465Smsmith	strcpy(buf, "(no device)");
20538465Smsmith	break;
20638465Smsmith
20786091Sjhb    case DEVT_CD:
20886091Sjhb	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.bioscd.unit);
20986091Sjhb	break;
21086091Sjhb
21138465Smsmith    case DEVT_DISK:
21238465Smsmith	cp = buf;
21338465Smsmith	cp += sprintf(cp, "%s%d", dev->d_dev->dv_name, dev->d_kind.biosdisk.unit);
21438465Smsmith	if (dev->d_kind.biosdisk.slice > 0)
21538465Smsmith	    cp += sprintf(cp, "s%d", dev->d_kind.biosdisk.slice);
21638465Smsmith	if (dev->d_kind.biosdisk.partition >= 0)
21738465Smsmith	    cp += sprintf(cp, "%c", dev->d_kind.biosdisk.partition + 'a');
21838465Smsmith	strcat(cp, ":");
21938465Smsmith	break;
22038465Smsmith
22138465Smsmith    case DEVT_NET:
22238465Smsmith	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_kind.netif.unit);
22338465Smsmith	break;
22438465Smsmith    }
22538465Smsmith    return(buf);
22638465Smsmith}
22738465Smsmith
22838465Smsmith
22938465Smsmith/*
23038465Smsmith * Set currdev to suit the value being supplied in (value)
23138465Smsmith */
23238465Smsmithint
233146697Sjhbi386_setcurrdev(struct env_var *ev, int flags, const void *value)
23438465Smsmith{
23538465Smsmith    struct i386_devdesc	*ncurr;
23638465Smsmith    int			rv;
23739662Smsmith
23838465Smsmith    if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0)
23938465Smsmith	return(rv);
24038465Smsmith    free(ncurr);
24138465Smsmith    env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
24238465Smsmith    return(0);
24338465Smsmith}
24438465Smsmith
245