/* * geli_probe_and_attach() is called from devopen() after it successfully calls * the dv_open() method of a DEVT_DISK device. We taste the partition described * by the disk_devdesc, and if it's geli-encrypted and we can decrypt it, we * create a geli_devdesc and store it into the open_file struct in place of the * underlying provider's disk_devdesc, effectively attaching our code to all IO * processing for the partition. Not quite the elegant stacking provided by * geom in the kernel, but it gets the job done. */ void geli_probe_and_attach(struct open_file *f) { static char gelipw[GELI_PW_MAXLEN]; const char *envpw; struct geli_dev *gdev; struct geli_devdesc *gdesc; struct disk_devdesc *hdesc; uint64_t hmediasize; daddr_t hlastblk; int rc; hdesc = (struct disk_devdesc *)(f->f_devdata); /* Get the last block number for the host provider. */ hdesc->dd.d_dev->dv_ioctl(f, DIOCGMEDIASIZE, &hmediasize); hlastblk = (hmediasize / DEV_BSIZE) - 1; /* Taste the host provider. If it's not geli-encrypted just return. */ gdev = geli_taste(diskdev_read, hdesc, hlastblk, disk_fmtdev(hdesc)); if (gdev == NULL) return; /* * It's geli, try to decrypt it with existing keys, or prompt for a * passphrase if we don't yet have a cached key for it. */ if ((rc = geli_havekey(gdev)) != 0) { envpw = getenv("kern.geom.eli.passphrase"); if (envpw != NULL) { /* Use the cached passphrase */ bcopy(envpw, &gelipw, GELI_PW_MAXLEN); } if ((rc = geli_passphrase(gdev, gelipw)) == 0) { /* Passphrase is good, cache it. */ setenv("kern.geom.eli.passphrase", gelipw, 1); } explicit_bzero(gelipw, sizeof(gelipw)); if (rc != 0) return; } /* * It's geli-encrypted and we can decrypt it. Create a geli_devdesc, * store a reference to the underlying provider's disk_devdesc in it, * then attach it to the openfile struct in place of the host provider. */ if ((gdesc = malloc(sizeof(*gdesc))) == NULL) return; gdesc->ddd.dd.d_dev = &geli_devsw; gdesc->ddd.dd.d_opendata = NULL; gdesc->ddd.dd.d_unit = hdesc->dd.d_unit; gdesc->ddd.d_offset = hdesc->d_offset; gdesc->ddd.d_partition = hdesc->d_partition; gdesc->ddd.d_slice = hdesc->d_slice; gdesc->hdesc = hdesc; gdesc->gdev = gdev; f->f_dev = gdesc->ddd.dd.d_dev; f->f_devdata = gdesc; }
char * userboot_fmtdev(void *vdev) { struct disk_devdesc *dev = (struct disk_devdesc *)vdev; static char buf[128]; /* XXX device length constant? */ switch(dev->d_type) { case DEVT_NONE: strcpy(buf, "(no device)"); break; case DEVT_CD: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; case DEVT_DISK: return (disk_fmtdev(vdev)); case DEVT_NET: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; case DEVT_ZFS: #if defined(USERBOOT_ZFS_SUPPORT) return (zfs_fmtdev(vdev)); #else sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); #endif break; } return(buf); }
char * efi_fmtdev(void *vdev) { struct devdesc *dev = (struct devdesc *)vdev; static char buf[SPECNAMELEN + 1]; switch(dev->d_type) { case DEVT_NONE: strcpy(buf, "(no device)"); break; case DEVT_DISK: return (disk_fmtdev(vdev)); #ifdef EFI_ZFS_BOOT case DEVT_ZFS: return (zfs_fmtdev(dev)); #endif default: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; } return (buf); }
char * uboot_fmtdev(void *vdev) { struct uboot_devdesc *dev = (struct uboot_devdesc *)vdev; static char buf[128]; switch(dev->d_type) { case DEVT_NONE: strcpy(buf, "(no device)"); break; case DEVT_DISK: #ifdef LOADER_DISK_SUPPORT return (disk_fmtdev(vdev)); #endif case DEVT_NET: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; } return(buf); }
char * i386_fmtdev(void *vdev) { struct i386_devdesc *dev = (struct i386_devdesc *)vdev; static char buf[128]; /* XXX device length constant? */ switch(dev->d_type) { case DEVT_NONE: strcpy(buf, "(no device)"); break; case DEVT_CD: case DEVT_NET: sprintf(buf, "%s%d:", dev->d_dev->dv_name, dev->d_unit); break; case DEVT_DISK: return (disk_fmtdev(vdev)); case DEVT_ZFS: return(zfs_fmtdev(vdev)); } return(buf); }