1*71552555SToomas Soome /*
24a5d661aSToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
34a5d661aSToomas Soome * All rights reserved.
44a5d661aSToomas Soome *
54a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without
64a5d661aSToomas Soome * modification, are permitted provided that the following conditions
74a5d661aSToomas Soome * are met:
84a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright
94a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer.
104a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
114a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the
124a5d661aSToomas Soome * documentation and/or other materials provided with the distribution.
134a5d661aSToomas Soome *
144a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154a5d661aSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164a5d661aSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174a5d661aSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184a5d661aSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194a5d661aSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204a5d661aSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224a5d661aSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234a5d661aSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244a5d661aSToomas Soome * SUCH DAMAGE.
254a5d661aSToomas Soome */
264a5d661aSToomas Soome
274a5d661aSToomas Soome #include <sys/cdefs.h>
284a5d661aSToomas Soome
294a5d661aSToomas Soome #include <stand.h>
304a5d661aSToomas Soome #include <string.h>
31*71552555SToomas Soome #include <sys/param.h>
324a5d661aSToomas Soome #include "bootstrap.h"
334a5d661aSToomas Soome #include "disk.h"
344a5d661aSToomas Soome #include "libi386.h"
354a5d661aSToomas Soome #include "../zfs/libzfs.h"
364a5d661aSToomas Soome
37*71552555SToomas Soome static int i386_parsedev(struct i386_devdesc **, const char *, const char **);
384a5d661aSToomas Soome
394a5d661aSToomas Soome /*
40*71552555SToomas Soome * Point dev at an allocated device specifier for the device matching the
41*71552555SToomas Soome * path in devspec. If it contains an explicit device specification,
424a5d661aSToomas Soome * use that. If not, use the default device.
434a5d661aSToomas Soome */
444a5d661aSToomas Soome int
i386_getdev(void ** vdev,const char * devspec,const char ** path)454a5d661aSToomas Soome i386_getdev(void **vdev, const char *devspec, const char **path)
464a5d661aSToomas Soome {
474a5d661aSToomas Soome struct i386_devdesc **dev = (struct i386_devdesc **)vdev;
484a5d661aSToomas Soome int rv;
494a5d661aSToomas Soome
504a5d661aSToomas Soome /*
514a5d661aSToomas Soome * If it looks like this is just a path and no
524a5d661aSToomas Soome * device, go with the current device.
534a5d661aSToomas Soome */
544a5d661aSToomas Soome if ((devspec == NULL) ||
55*71552555SToomas Soome (devspec[0] == '/') || (strchr(devspec, ':') == NULL)) {
564a5d661aSToomas Soome
57*71552555SToomas Soome rv = i386_parsedev(dev, getenv("currdev"), NULL);
58*71552555SToomas Soome if (rv == 0 && path != NULL)
594a5d661aSToomas Soome *path = devspec;
604a5d661aSToomas Soome return (rv);
614a5d661aSToomas Soome }
624a5d661aSToomas Soome
634a5d661aSToomas Soome /*
644a5d661aSToomas Soome * Try to parse the device name off the beginning of the devspec
654a5d661aSToomas Soome */
664a5d661aSToomas Soome return (i386_parsedev(dev, devspec, path));
674a5d661aSToomas Soome }
684a5d661aSToomas Soome
694a5d661aSToomas Soome /*
704a5d661aSToomas Soome * Point (dev) at an allocated device specifier matching the string version
714a5d661aSToomas Soome * at the beginning of (devspec). Return a pointer to the remaining
724a5d661aSToomas Soome * text in (path).
734a5d661aSToomas Soome *
744a5d661aSToomas Soome * In all cases, the beginning of (devspec) is compared to the names
754a5d661aSToomas Soome * of known devices in the device switch, and then any following text
764a5d661aSToomas Soome * is parsed according to the rules applied to the device type.
774a5d661aSToomas Soome *
784a5d661aSToomas Soome * For disk-type devices, the syntax is:
794a5d661aSToomas Soome *
804a5d661aSToomas Soome * disk<unit>[s<slice>][<partition>]:
814a5d661aSToomas Soome *
824a5d661aSToomas Soome */
834a5d661aSToomas Soome static int
i386_parsedev(struct i386_devdesc ** dev,const char * devspec,const char ** path)844a5d661aSToomas Soome i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path)
854a5d661aSToomas Soome {
864a5d661aSToomas Soome struct i386_devdesc *idev;
874a5d661aSToomas Soome struct devsw *dv;
884a5d661aSToomas Soome int i, unit, err;
894a5d661aSToomas Soome char *cp;
904a5d661aSToomas Soome const char *np;
914a5d661aSToomas Soome
924a5d661aSToomas Soome /* minimum length check */
934a5d661aSToomas Soome if (strlen(devspec) < 2)
944a5d661aSToomas Soome return (EINVAL);
954a5d661aSToomas Soome
964a5d661aSToomas Soome /* look for a device that matches */
974a5d661aSToomas Soome for (i = 0, dv = NULL; devsw[i] != NULL; i++) {
984a5d661aSToomas Soome dv = devsw[i];
99*71552555SToomas Soome if (strncmp(devspec, dv->dv_name, strlen(dv->dv_name)) == 0)
1004a5d661aSToomas Soome break;
1014a5d661aSToomas Soome }
102*71552555SToomas Soome if (devsw[i] == NULL)
1034a5d661aSToomas Soome return (ENOENT);
104*71552555SToomas Soome
105*71552555SToomas Soome np = devspec + strlen(dv->dv_name);
106*71552555SToomas Soome idev = NULL;
1074a5d661aSToomas Soome err = 0;
1084a5d661aSToomas Soome
1094a5d661aSToomas Soome switch (dv->dv_type) {
110*71552555SToomas Soome case DEVT_NONE:
1114a5d661aSToomas Soome break;
1124a5d661aSToomas Soome
1134a5d661aSToomas Soome case DEVT_DISK:
114*71552555SToomas Soome idev = malloc(sizeof (struct i386_devdesc));
115*71552555SToomas Soome if (idev == NULL)
116*71552555SToomas Soome return (ENOMEM);
117*71552555SToomas Soome
1184a5d661aSToomas Soome err = disk_parsedev((struct disk_devdesc *)idev, np, path);
1194a5d661aSToomas Soome if (err != 0)
1204a5d661aSToomas Soome goto fail;
1214a5d661aSToomas Soome break;
1224a5d661aSToomas Soome
123*71552555SToomas Soome case DEVT_ZFS:
124*71552555SToomas Soome idev = malloc(sizeof (struct zfs_devdesc));
125*71552555SToomas Soome if (idev == NULL)
126*71552555SToomas Soome return (ENOMEM);
127*71552555SToomas Soome
128*71552555SToomas Soome err = zfs_parsedev((struct zfs_devdesc *)idev, np, path);
129*71552555SToomas Soome if (err != 0)
130*71552555SToomas Soome goto fail;
131*71552555SToomas Soome break;
132*71552555SToomas Soome
133*71552555SToomas Soome default:
134*71552555SToomas Soome idev = malloc(sizeof (struct devdesc));
135*71552555SToomas Soome if (idev == NULL)
136*71552555SToomas Soome return (ENOMEM);
137*71552555SToomas Soome
1384a5d661aSToomas Soome unit = 0;
139*71552555SToomas Soome cp = (char *)np;
1404a5d661aSToomas Soome
1414a5d661aSToomas Soome if (*np && (*np != ':')) {
142*71552555SToomas Soome /* get unit number if present */
143*71552555SToomas Soome unit = strtol(np, &cp, 0);
1444a5d661aSToomas Soome if (cp == np) {
1454a5d661aSToomas Soome err = EUNIT;
1464a5d661aSToomas Soome goto fail;
1474a5d661aSToomas Soome }
1484a5d661aSToomas Soome }
1494a5d661aSToomas Soome if (*cp && (*cp != ':')) {
1504a5d661aSToomas Soome err = EINVAL;
1514a5d661aSToomas Soome goto fail;
1524a5d661aSToomas Soome }
1534a5d661aSToomas Soome
1544a5d661aSToomas Soome idev->d_unit = unit;
1554a5d661aSToomas Soome if (path != NULL)
156*71552555SToomas Soome *path = (*cp == '\0') ? cp : cp + 1;
1574a5d661aSToomas Soome break;
1584a5d661aSToomas Soome }
159*71552555SToomas Soome
1604a5d661aSToomas Soome idev->d_dev = dv;
1614a5d661aSToomas Soome idev->d_type = dv->dv_type;
162*71552555SToomas Soome
163*71552555SToomas Soome if (dev != NULL)
1644a5d661aSToomas Soome *dev = idev;
165*71552555SToomas Soome else
166*71552555SToomas Soome free(idev);
1674a5d661aSToomas Soome return (0);
1684a5d661aSToomas Soome
1694a5d661aSToomas Soome fail:
1704a5d661aSToomas Soome free(idev);
1714a5d661aSToomas Soome return (err);
1724a5d661aSToomas Soome }
1734a5d661aSToomas Soome
1744a5d661aSToomas Soome
1754a5d661aSToomas Soome char *
i386_fmtdev(void * vdev)1764a5d661aSToomas Soome i386_fmtdev(void *vdev)
1774a5d661aSToomas Soome {
1784a5d661aSToomas Soome struct i386_devdesc *dev = (struct i386_devdesc *)vdev;
179*71552555SToomas Soome static char buf[SPECNAMELEN + 1];
1804a5d661aSToomas Soome
1814a5d661aSToomas Soome switch (dev->d_type) {
1824a5d661aSToomas Soome case DEVT_NONE:
183*71552555SToomas Soome strlcpy(buf, "(no device)", sizeof (buf));
1844a5d661aSToomas Soome break;
1854a5d661aSToomas Soome
1864a5d661aSToomas Soome case DEVT_DISK:
1874a5d661aSToomas Soome return (disk_fmtdev(vdev));
1884a5d661aSToomas Soome
1894a5d661aSToomas Soome case DEVT_ZFS:
1904a5d661aSToomas Soome return (zfs_fmtdev(vdev));
191*71552555SToomas Soome
192*71552555SToomas Soome default:
193*71552555SToomas Soome snprintf(buf, sizeof (buf), "%s%d:", dev->d_dev->dv_name,
194*71552555SToomas Soome dev->d_unit);
195*71552555SToomas Soome break;
1964a5d661aSToomas Soome }
1974a5d661aSToomas Soome return (buf);
1984a5d661aSToomas Soome }
1994a5d661aSToomas Soome
2004a5d661aSToomas Soome
2014a5d661aSToomas Soome /*
2024a5d661aSToomas Soome * Set currdev to suit the value being supplied in (value)
2034a5d661aSToomas Soome */
2044a5d661aSToomas Soome int
i386_setcurrdev(struct env_var * ev,int flags,const void * value)2054a5d661aSToomas Soome i386_setcurrdev(struct env_var *ev, int flags, const void *value)
2064a5d661aSToomas Soome {
2074a5d661aSToomas Soome struct i386_devdesc *ncurr;
2084a5d661aSToomas Soome int rv;
2094a5d661aSToomas Soome
2104a5d661aSToomas Soome if ((rv = i386_parsedev(&ncurr, value, NULL)) != 0)
2114a5d661aSToomas Soome return (rv);
212*71552555SToomas Soome
2134a5d661aSToomas Soome free(ncurr);
2144a5d661aSToomas Soome env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
2154a5d661aSToomas Soome return (0);
2164a5d661aSToomas Soome }
217