/* * Point (dev) at an allocated device specifier matching the string version * at the beginning of (devspec). Return a pointer to the remaining * text in (path). * * In all cases, the beginning of (devspec) is compared to the names * of known devices in the device switch, and then any following text * is parsed according to the rules applied to the device type. * * For disk-type devices, the syntax is: * * disk<unit>[s<slice>][<partition>]: * */ static int i386_parsedev(struct i386_devdesc **dev, const char *devspec, const char **path) { struct i386_devdesc *idev; struct devsw *dv; int i, unit, err; char *cp; const char *np; /* minimum length check */ if (strlen(devspec) < 2) return(EINVAL); /* look for a device that matches */ for (i = 0, dv = NULL; devsw[i] != NULL; i++) { if (!strncmp(devspec, devsw[i]->dv_name, strlen(devsw[i]->dv_name))) { dv = devsw[i]; break; } } if (dv == NULL) return(ENOENT); idev = malloc(sizeof(struct i386_devdesc)); err = 0; np = (devspec + strlen(dv->dv_name)); switch(dv->dv_type) { case DEVT_NONE: /* XXX what to do here? Do we care? */ break; case DEVT_DISK: err = disk_parsedev((struct disk_devdesc *)idev, np, path); if (err != 0) goto fail; break; case DEVT_CD: case DEVT_NET: unit = 0; if (*np && (*np != ':')) { unit = strtol(np, &cp, 0); /* get unit number if present */ if (cp == np) { err = EUNIT; goto fail; } } else { cp = (char *)np; } if (*cp && (*cp != ':')) { err = EINVAL; goto fail; } idev->d_unit = unit; if (path != NULL) *path = (*cp == 0) ? cp : cp + 1; break; case DEVT_ZFS: err = zfs_parsedev((struct zfs_devdesc *)idev, np, path); if (err != 0) goto fail; break; default: err = EINVAL; goto fail; } idev->d_dev = dv; idev->d_type = dv->dv_type; if (dev == NULL) { free(idev); } else { *dev = idev; } return(0); fail: free(idev); return(err); }
/* * Point (dev) at an allocated device specifier matching the string version * at the beginning of (devspec). Return a pointer to the remaining * text in (path). * * In all cases, the beginning of (devspec) is compared to the names * of known devices in the device switch, and then any following text * is parsed according to the rules applied to the device type. * * For disk-type devices, the syntax is: * * fs<unit>: */ static int efi_parsedev(struct devdesc **dev, const char *devspec, const char **path) { struct devdesc *idev; struct devsw *dv; int i, unit, err; char *cp; const char *np; /* minimum length check */ if (strlen(devspec) < 2) return (EINVAL); /* look for a device that matches */ for (i = 0; devsw[i] != NULL; i++) { dv = devsw[i]; if (!strncmp(devspec, dv->dv_name, strlen(dv->dv_name))) break; } if (devsw[i] == NULL) return (ENOENT); np = devspec + strlen(dv->dv_name); idev = NULL; err = 0; switch (dv->dv_type) { case DEVT_NONE: break; case DEVT_DISK: idev = malloc(sizeof(struct disk_devdesc)); if (idev == NULL) return (ENOMEM); err = disk_parsedev((struct disk_devdesc *)idev, np, path); if (err != 0) goto fail; break; #ifdef EFI_ZFS_BOOT case DEVT_ZFS: idev = malloc(sizeof(struct zfs_devdesc)); if (idev == NULL) return (ENOMEM); err = zfs_parsedev((struct zfs_devdesc*)idev, np, path); if (err != 0) goto fail; break; #endif default: idev = malloc(sizeof(struct devdesc)); if (idev == NULL) return (ENOMEM); unit = 0; cp = (char *)np; if (*np != '\0' && *np != ':') { errno = 0; unit = strtol(np, &cp, 0); if (errno != 0 || cp == np) { err = EUNIT; goto fail; } } if (*cp != '\0' && *cp != ':') { err = EINVAL; goto fail; } idev->d_unit = unit; if (path != NULL) *path = (*cp == 0) ? cp : cp + 1; break; } idev->d_dev = dv; idev->d_type = dv->dv_type; if (dev != NULL) *dev = idev; else free(idev); return (0); fail: free(idev); return (err); }