/* * Attempt to read a disk label from a device * using the indicated strategy routine. * The label must be partly set up before this: * secpercyl, secsize and anything required for a block i/o read * operation in the driver's strategy/start routines * must be filled in before calling us. * * If dos partition table requested, attempt to load it and * find disklabel inside a DOS partition. * * We would like to check if each MBR has a valid DOSMBR_SIGNATURE, but * we cannot because it doesn't always exist. So.. we assume the * MBR is valid. */ int readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, int spoofonly) { bios_diskinfo_t *pdi; struct buf *bp = NULL; dev_t devno; int error; if ((error = initdisklabel(lp))) goto done; /* Look for any BIOS geometry information we should honour. */ devno = chrtoblk(dev); if (devno == NODEV) devno = dev; pdi = bios_getdiskinfo(MAKEBOOTDEV(major(devno), 0, 0, DISKUNIT(devno), RAW_PART)); if (pdi != NULL && pdi->bios_heads > 0 && pdi->bios_sectors > 0) { #ifdef DEBUG printf("Disk GEOM %u/%u/%u -> BIOS GEOM %u/%u/%u\n", lp->d_ntracks, lp->d_nsectors, lp->d_ncylinders, pdi->bios_heads, pdi->bios_sectors, DL_GETDSIZE(lp) / (pdi->bios_heads * pdi->bios_sectors)); #endif lp->d_ntracks = pdi->bios_heads; lp->d_nsectors = pdi->bios_sectors; lp->d_secpercyl = pdi->bios_sectors * pdi->bios_heads; lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_secpercyl; } /* get a buffer and initialize it */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; error = readdoslabel(bp, strat, lp, NULL, spoofonly); if (error == 0) goto done; #if defined(CD9660) error = iso_disklabelspoof(dev, strat, lp); if (error == 0) goto done; #endif #if defined(UDF) error = udf_disklabelspoof(dev, strat, lp); if (error == 0) goto done; #endif done: if (bp) { bp->b_flags |= B_INVAL; brelse(bp); } disk_change = 1; return (error); }
/* * machine dependent system variables. */ int cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen, struct proc *p) { dev_t consdev; dev_t dev; switch (name[0]) { case CPU_CONSDEV: if (namelen != 1) return (ENOTDIR); /* overloaded */ if (cn_tab != NULL) consdev = cn_tab->cn_dev; else consdev = NODEV; return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev, sizeof consdev)); case CPU_CHR2BLK: if (namelen != 2) return (ENOTDIR); /* overloaded */ dev = chrtoblk((dev_t)name[1]); return sysctl_rdstruct(oldp, oldlenp, newp, &dev, sizeof(dev)); case CPU_BIOS: return bios_sysctl(name + 1, namelen - 1, oldp, oldlenp, newp, newlen, p); case CPU_CPUVENDOR: return (sysctl_rdstring(oldp, oldlenp, newp, cpu_vendor)); case CPU_CPUFEATURE: return (sysctl_rdint(oldp, oldlenp, newp, cpu_feature)); case CPU_KBDRESET: if (securelevel > 0) return (sysctl_rdint(oldp, oldlenp, newp, kbd_reset)); else return (sysctl_int(oldp, oldlenp, newp, newlen, &kbd_reset)); case CPU_ALLOWAPERTURE: if (namelen != 1) return (ENOTDIR); /* overloaded */ #ifdef APERTURE if (securelevel > 0) return (sysctl_int_lower(oldp, oldlenp, newp, newlen, &allowaperture)); else return (sysctl_int(oldp, oldlenp, newp, newlen, &allowaperture)); #else return (sysctl_rdint(oldp, oldlenp, newp, 0)); #endif default: return (EOPNOTSUPP); } /* NOTREACHED */ }
/* * return true if a disk */ int isdisk(dev_t dev, int type) { dev_t maj = major(dev); switch (type) { case VCHR: maj = chrtoblk(maj); if (maj == NODEV) { break; } /* FALL THROUGH */ case VBLK: if (bdevsw[maj].d_type == D_DISK) { return (1); } break; } return(0); }
/* * Open a special file. */ int spec_open(void *v) { struct vop_open_args *ap = v; struct proc *p = ap->a_p; struct vnode *vp = ap->a_vp; struct vnode *bvp; dev_t bdev; dev_t dev = (dev_t)vp->v_rdev; int maj = major(dev); int error; /* * Don't allow open if fs is mounted -nodev. */ if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) return (ENXIO); switch (vp->v_type) { case VCHR: if ((u_int)maj >= nchrdev) return (ENXIO); if (ap->a_cred != FSCRED && (ap->a_mode & FWRITE)) { /* * When running in very secure mode, do not allow * opens for writing of any disk character devices. */ if (securelevel >= 2 && cdevsw[maj].d_type == D_DISK) return (EPERM); /* * When running in secure mode, do not allow opens * for writing of /dev/mem, /dev/kmem, or character * devices whose corresponding block devices are * currently mounted. */ if (securelevel >= 1) { if ((bdev = chrtoblk(dev)) != NODEV && vfinddev(bdev, VBLK, &bvp) && bvp->v_usecount > 0 && (error = vfs_mountedon(bvp))) return (error); if (iskmemdev(dev)) return (EPERM); } } if (cdevsw[maj].d_type == D_TTY) vp->v_flag |= VISTTY; if (cdevsw[maj].d_flags & D_CLONE) return (spec_open_clone(ap)); VOP_UNLOCK(vp, 0, p); error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); return (error); case VBLK: if ((u_int)maj >= nblkdev) return (ENXIO); /* * When running in very secure mode, do not allow * opens for writing of any disk block devices. */ if (securelevel >= 2 && ap->a_cred != FSCRED && (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) return (EPERM); /* * Do not allow opens of block devices that are * currently mounted. */ if ((error = vfs_mountedon(vp)) != 0) return (error); return ((*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p)); case VNON: case VLNK: case VDIR: case VREG: case VBAD: case VFIFO: case VSOCK: break; } return (0); }
/* * Open a special file. */ int spec_open(struct vnop_open_args *ap) { struct proc *p = vfs_context_proc(ap->a_context); kauth_cred_t cred = vfs_context_ucred(ap->a_context); struct vnode *vp = ap->a_vp; dev_t bdev, dev = (dev_t)vp->v_rdev; int maj = major(dev); int error; /* * Don't allow open if fs is mounted -nodev. */ if (vp->v_mount && (vp->v_mount->mnt_flag & MNT_NODEV)) return (ENXIO); switch (vp->v_type) { case VCHR: if ((u_int)maj >= (u_int)nchrdev) return (ENXIO); if (cred != FSCRED && (ap->a_mode & FWRITE)) { /* * When running in very secure mode, do not allow * opens for writing of any disk character devices. */ if (securelevel >= 2 && isdisk(dev, VCHR)) return (EPERM); /* * When running in secure mode, do not allow opens * for writing of /dev/mem, /dev/kmem, or character * devices whose corresponding block devices are * currently mounted. */ if (securelevel >= 1) { if ((bdev = chrtoblk(dev)) != NODEV && check_mountedon(bdev, VBLK, &error)) return (error); if (iskmemdev(dev)) return (EPERM); } } if (cdevsw[maj].d_type == D_TTY) { vnode_lock(vp); vp->v_flag |= VISTTY; vnode_unlock(vp); } error = (*cdevsw[maj].d_open)(dev, ap->a_mode, S_IFCHR, p); return (error); case VBLK: if ((u_int)maj >= (u_int)nblkdev) return (ENXIO); /* * When running in very secure mode, do not allow * opens for writing of any disk block devices. */ if (securelevel >= 2 && cred != FSCRED && (ap->a_mode & FWRITE) && bdevsw[maj].d_type == D_DISK) return (EPERM); /* * Do not allow opens of block devices that are * currently mounted. */ if ( (error = vfs_mountedon(vp)) ) return (error); error = (*bdevsw[maj].d_open)(dev, ap->a_mode, S_IFBLK, p); if (!error) { u_int64_t blkcnt; u_int32_t blksize; int setsize = 0; u_int32_t size512 = 512; if (!VNOP_IOCTL(vp, DKIOCGETBLOCKSIZE, (caddr_t)&blksize, 0, ap->a_context)) { /* Switch to 512 byte sectors (temporarily) */ if (!VNOP_IOCTL(vp, DKIOCSETBLOCKSIZE, (caddr_t)&size512, FWRITE, ap->a_context)) { /* Get the number of 512 byte physical blocks. */ if (!VNOP_IOCTL(vp, DKIOCGETBLOCKCOUNT, (caddr_t)&blkcnt, 0, ap->a_context)) { setsize = 1; } } /* If it doesn't set back, we can't recover */ if (VNOP_IOCTL(vp, DKIOCSETBLOCKSIZE, (caddr_t)&blksize, FWRITE, ap->a_context)) error = ENXIO; } vnode_lock(vp); set_blocksize(vp, dev); /* * Cache the size in bytes of the block device for later * use by spec_write(). */ if (setsize) vp->v_specdevsize = blkcnt * (u_int64_t)size512; else vp->v_specdevsize = (u_int64_t)0; /* Default: Can't get */ vnode_unlock(vp); } return(error); default: panic("spec_open type"); } return (0); }