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$");
29119482Sobrien
3038465Smsmith#include <stand.h>
3138465Smsmith#include <string.h>
3238465Smsmith#include "bootstrap.h"
33243243Sae#include "disk.h"
3438465Smsmith#include "libi386.h"
35237766Savg#include "../zfs/libzfs.h"
3638465Smsmith
3739673Sdfrstatic int	i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path);
3838465Smsmith
3938465Smsmith/*
4038465Smsmith * Point (dev) at an allocated device specifier for the device matching the
4138465Smsmith * path in (devspec). If it contains an explicit device specification,
4238465Smsmith * use that.  If not, use the default device.
4338465Smsmith */
4438465Smsmithint
4539673Sdfri386_getdev(void **vdev, const char *devspec, const char **path)
4638465Smsmith{
4738465Smsmith    struct i386_devdesc **dev = (struct i386_devdesc **)vdev;
4838465Smsmith    int				rv;
4938465Smsmith
5038465Smsmith    /*
5138465Smsmith     * If it looks like this is just a path and no
5238465Smsmith     * device, go with the current device.
5338465Smsmith     */
5438465Smsmith    if ((devspec == NULL) ||
5538465Smsmith	(devspec[0] == '/') ||
5638465Smsmith	(strchr(devspec, ':') == NULL)) {
5738465Smsmith
5838465Smsmith	if (((rv = i386_parsedev(dev, getenv("currdev"), NULL)) == 0) &&
5938465Smsmith	    (path != NULL))
6038465Smsmith		*path = devspec;
6138465Smsmith	return(rv);
6238465Smsmith    }
6338465Smsmith
6438465Smsmith    /*
6538465Smsmith     * Try to parse the device name off the beginning of the devspec
6638465Smsmith     */
6738465Smsmith    return(i386_parsedev(dev, devspec, path));
6838465Smsmith}
6938465Smsmith
7038465Smsmith/*
7138465Smsmith * Point (dev) at an allocated device specifier matching the string version
7238465Smsmith * at the beginning of (devspec).  Return a pointer to the remaining
7338465Smsmith * text in (path).
7438465Smsmith *
7538465Smsmith * In all cases, the beginning of (devspec) is compared to the names
7638465Smsmith * of known devices in the device switch, and then any following text
7738465Smsmith * is parsed according to the rules applied to the device type.
7838465Smsmith *
7938465Smsmith * For disk-type devices, the syntax is:
8038465Smsmith *
8138465Smsmith * disk<unit>[s<slice>][<partition>]:
8238465Smsmith *
8338465Smsmith */
8438465Smsmithstatic int
8539673Sdfri386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path)
8638465Smsmith{
8738465Smsmith    struct i386_devdesc *idev;
8838465Smsmith    struct devsw	*dv;
89243243Sae    int			i, unit, err;
9039673Sdfr    char		*cp;
9139673Sdfr    const char		*np;
9238465Smsmith
9338465Smsmith    /* minimum length check */
9438465Smsmith    if (strlen(devspec) < 2)
9538465Smsmith	return(EINVAL);
9638465Smsmith
9738465Smsmith    /* look for a device that matches */
9838465Smsmith    for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
9938465Smsmith	if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) {
10038465Smsmith	    dv = devsw[i];
10138465Smsmith	    break;
10238465Smsmith	}
10338465Smsmith    }
10438465Smsmith    if (dv == NULL)
10538465Smsmith	return(ENOENT);
10638465Smsmith    idev = malloc(sizeof(struct i386_devdesc));
10738465Smsmith    err = 0;
10838465Smsmith    np = (devspec + strlen(dv->dv_name));
10938465Smsmith
11038465Smsmith    switch(dv->dv_type) {
11138465Smsmith    case DEVT_NONE:			/* XXX what to do here?  Do we care? */
11238465Smsmith	break;
11338465Smsmith
11438465Smsmith    case DEVT_DISK:
115243243Sae	err = disk_parsedev((struct disk_devdesc *)idev, np, path);
116243243Sae	if (err != 0)
11738465Smsmith	    goto fail;
11838465Smsmith	break;
11986091Sjhb
12086091Sjhb    case DEVT_CD:
12138465Smsmith    case DEVT_NET:
12238465Smsmith	unit = 0;
12386091Sjhb
12438465Smsmith	if (*np && (*np != ':')) {
12538465Smsmith	    unit = strtol(np, &cp, 0);	/* get unit number if present */
12638465Smsmith	    if (cp == np) {
12738465Smsmith		err = EUNIT;
12838465Smsmith		goto fail;
12938465Smsmith	    }
130181282Scperciva	} else {
131181282Scperciva		cp = np;
13238465Smsmith	}
13338465Smsmith	if (*cp && (*cp != ':')) {
13438465Smsmith	    err = EINVAL;
13538465Smsmith	    goto fail;
13638465Smsmith	}
13786091Sjhb
138163897Smarcel	idev->d_unit = unit;
13938465Smsmith	if (path != NULL)
14038465Smsmith	    *path = (*cp == 0) ? cp : cp + 1;
14138465Smsmith	break;
142237766Savg    case DEVT_ZFS:
143237766Savg	err = zfs_parsedev((struct zfs_devdesc *)idev, np, path);
144237766Savg	if (err != 0)
145237766Savg	    goto fail;
146237766Savg	break;
14738465Smsmith    default:
14838465Smsmith	err = EINVAL;
14938465Smsmith	goto fail;
15038465Smsmith    }
15138465Smsmith    idev->d_dev = dv;
15238465Smsmith    idev->d_type = dv->dv_type;
15338465Smsmith    if (dev == NULL) {
15438465Smsmith	free(idev);
15538465Smsmith    } else {
15638465Smsmith	*dev = idev;
15738465Smsmith    }
15838465Smsmith    return(0);
15938465Smsmith
16038465Smsmith fail:
16138465Smsmith    free(idev);
16238465Smsmith    return(err);
16338465Smsmith}
16438465Smsmith
16538465Smsmith
16638465Smsmithchar *
16738465Smsmithi386_fmtdev(void *vdev)
16838465Smsmith{
16938465Smsmith    struct i386_devdesc	*dev = (struct i386_devdesc *)vdev;
17038465Smsmith    static char		buf[128];	/* XXX device length constant? */
171243243Sae
17238465Smsmith    switch(dev->d_type) {
17338465Smsmith    case DEVT_NONE:
17438465Smsmith	strcpy(buf, "(no device)");
17538465Smsmith	break;
17638465Smsmith
17786091Sjhb    case DEVT_CD:
178243243Sae    case DEVT_NET:
179163897Smarcel	sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit);
18086091Sjhb	break;
18186091Sjhb
18238465Smsmith    case DEVT_DISK:
183243243Sae	return (disk_fmtdev(vdev));
18438465Smsmith
185237766Savg    case DEVT_ZFS:
186237766Savg	return(zfs_fmtdev(vdev));
18738465Smsmith    }
18838465Smsmith    return(buf);
18938465Smsmith}
19038465Smsmith
19138465Smsmith
19238465Smsmith/*
19338465Smsmith * Set currdev to suit the value being supplied in (value)
19438465Smsmith */
19538465Smsmithint
196146697Sjhbi386_setcurrdev(struct env_var *ev, int flags, const void *value)
19738465Smsmith{
19838465Smsmith    struct i386_devdesc	*ncurr;
19938465Smsmith    int			rv;
20039662Smsmith
20138465Smsmith    if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0)
20238465Smsmith	return(rv);
20338465Smsmith    free(ncurr);
20438465Smsmith    env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
20538465Smsmith    return(0);
20638465Smsmith}
207