/* * mp - path - addr in user space of mount point (ie /usr or whatever) * data - addr in user space of mount params including the name of the block * special file to treat as a filesystem. */ int msdosfs_mount(struct mount *mp, const char *path, void *data, struct nameidata *ndp, struct proc *p) { struct vnode *devvp; /* vnode for blk device to mount */ struct msdosfs_args args; /* will hold data from mount request */ /* msdosfs specific mount control block */ struct msdosfsmount *pmp = NULL; size_t size; int error, flags; mode_t accessmode; char *fspec = NULL; error = copyin(data, &args, sizeof(struct msdosfs_args)); if (error) return (error); /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { pmp = VFSTOMSDOSFS(mp); error = 0; if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = vflush(mp, NULLVP, flags); } if (!error && (mp->mnt_flag & MNT_RELOAD)) /* not yet implemented */ error = EOPNOTSUPP; if (error) return (error); if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ if (suser(p, 0) != 0) { devvp = pmp->pm_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) return (error); } pmp->pm_flags &= ~MSDOSFSMNT_RONLY; } if (args.fspec == 0) { #ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ if (args.flags & MSDOSFSMNT_MNTOPT) { pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; } #endif /* * Process export requests. */ return (vfs_export(mp, &pmp->pm_export, &args.export_info)); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ fspec = malloc(MNAMELEN, M_MOUNT, M_WAITOK); error = copyinstr(args.fspec, fspec, MNAMELEN - 1, &size); if (error) goto error; disk_map(fspec, fspec, MNAMELEN, DM_OPENBLCK); NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, p); if ((error = namei(ndp)) != 0) goto error; devvp = ndp->ni_vp; if (devvp->v_type != VBLK) { error = ENOTBLK; goto error_devvp; } if (major(devvp->v_rdev) >= nblkdev) { error = ENXIO; goto error_devvp; } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ if (suser(p, 0) != 0) { accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) goto error_devvp; } if ((mp->mnt_flag & MNT_UPDATE) == 0) error = msdosfs_mountfs(devvp, mp, p, &args); else { if (devvp != pmp->pm_devvp) error = EINVAL; /* XXX needs translation */ else vrele(devvp); } if (error) goto error_devvp; pmp = VFSTOMSDOSFS(mp); pmp->pm_gid = args.gid; pmp->pm_uid = args.uid; pmp->pm_mask = args.mask; pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; else if (!(pmp->pm_flags & (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { struct vnode *rvp; /* * Try to divine whether to support Win'95 long filenames */ if (FAT32(pmp)) pmp->pm_flags |= MSDOSFSMNT_LONGNAME; else { if ((error = msdosfs_root(mp, &rvp)) != 0) { msdosfs_unmount(mp, MNT_FORCE, p); goto error; } pmp->pm_flags |= findwin95(VTODE(rvp)) ? MSDOSFSMNT_LONGNAME : MSDOSFSMNT_SHORTNAME; vput(rvp); } } (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); size = strlcpy(mp->mnt_stat.f_mntfromname, fspec, MNAMELEN - 1); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); bcopy(&args, &mp->mnt_stat.mount_info.msdosfs_args, sizeof(args)); #ifdef MSDOSFS_DEBUG printf("msdosfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap); #endif return (0); error_devvp: vrele(devvp); error: if (fspec) free(fspec, M_MOUNT); return (error); }
/* * VFS Operations. * * mount system call */ int ffs_mount(struct mount *mp, const char *path, void *data, struct nameidata *ndp, struct proc *p) { struct vnode *devvp; struct ufs_args args; struct ufsmount *ump = NULL; struct fs *fs; char fname[MNAMELEN]; char fspec[MNAMELEN]; int error = 0, flags; int ronly; mode_t accessmode; error = copyin(data, &args, sizeof(struct ufs_args)); if (error) return (error); #ifndef FFS_SOFTUPDATES if (mp->mnt_flag & MNT_SOFTDEP) { printf("WARNING: soft updates isn't compiled in\n"); mp->mnt_flag &= ~MNT_SOFTDEP; } #endif /* * Soft updates is incompatible with "async", * so if we are doing softupdates stop the user * from setting the async flag. */ if ((mp->mnt_flag & (MNT_SOFTDEP | MNT_ASYNC)) == (MNT_SOFTDEP | MNT_ASYNC)) { return (EINVAL); } /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_fs; devvp = ump->um_devvp; error = 0; ronly = fs->fs_ronly; if (ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { /* Flush any dirty data */ mp->mnt_flag &= ~MNT_RDONLY; VFS_SYNC(mp, MNT_WAIT, p->p_ucred, p); mp->mnt_flag |= MNT_RDONLY; /* * Get rid of files open for writing. */ flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; if (fs->fs_flags & FS_DOSOFTDEP) { error = softdep_flushfiles(mp, flags, p); mp->mnt_flag &= ~MNT_SOFTDEP; } else error = ffs_flushfiles(mp, flags, p); ronly = 1; } /* * Flush soft dependencies if disabling it via an update * mount. This may leave some items to be processed, * so don't do this yet XXX. */ if ((fs->fs_flags & FS_DOSOFTDEP) && !(mp->mnt_flag & MNT_SOFTDEP) && !(mp->mnt_flag & MNT_RDONLY) && fs->fs_ronly == 0) { #if 0 flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = softdep_flushfiles(mp, flags, p); #elif FFS_SOFTUPDATES mp->mnt_flag |= MNT_SOFTDEP; #endif } /* * When upgrading to a softdep mount, we must first flush * all vnodes. (not done yet -- see above) */ if (!(fs->fs_flags & FS_DOSOFTDEP) && (mp->mnt_flag & MNT_SOFTDEP) && fs->fs_ronly == 0) { #if 0 flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = ffs_flushfiles(mp, flags, p); #else mp->mnt_flag &= ~MNT_SOFTDEP; #endif } if (!error && (mp->mnt_flag & MNT_RELOAD)) error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); if (error) goto error_1; if (ronly && (mp->mnt_flag & MNT_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ if (suser(p, 0)) { vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) goto error_1; } if (fs->fs_clean == 0) { #if 0 /* * It is safe to mount an unclean file system * if it was previously mounted with softdep * but we may lose space and must * sometimes run fsck manually. */ if (fs->fs_flags & FS_DOSOFTDEP) printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); else #endif if (mp->mnt_flag & MNT_FORCE) { printf( "WARNING: %s was not properly unmounted\n", fs->fs_fsmnt); } else { printf( "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", fs->fs_fsmnt); error = EROFS; goto error_1; } } if ((fs->fs_flags & FS_DOSOFTDEP)) { error = softdep_mount(devvp, mp, fs, p->p_ucred); if (error) goto error_1; } fs->fs_contigdirs = malloc((u_long)fs->fs_ncg, M_UFSMNT, M_WAITOK|M_ZERO); ronly = 0; } if (args.fspec == NULL) { /* * Process export requests. */ error = vfs_export(mp, &ump->um_export, &args.export_info); if (error) goto error_1; else goto success; } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ error = copyinstr(args.fspec, fspec, sizeof(fspec), NULL); if (error) goto error_1; if (disk_map(fspec, fname, MNAMELEN, DM_OPENBLCK) == -1) memcpy(fname, fspec, sizeof(fname)); NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p); if ((error = namei(ndp)) != 0) goto error_1; devvp = ndp->ni_vp; if (devvp->v_type != VBLK) { error = ENOTBLK; goto error_2; } if (major(devvp->v_rdev) >= nblkdev) { error = ENXIO; goto error_2; } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ if (suser(p, 0)) { accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); VOP_UNLOCK(devvp, 0, p); if (error) goto error_2; } if (mp->mnt_flag & MNT_UPDATE) { /* * UPDATE * If it's not the same vnode, or at least the same device * then it's not correct. */ if (devvp != ump->um_devvp) { if (devvp->v_rdev == ump->um_devvp->v_rdev) { vrele(devvp); } else { error = EINVAL; /* needs translation */ } } else vrele(devvp); /* * Update device name only on success */ if (!error) { /* * Save "mounted from" info for mount point (NULL pad) */ memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN); strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN); memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN); strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN); } } else { /* * Since this is a new mount, we want the names for * the device and the mount point copied in. If an * error occurs, the mountpoint is discarded by the * upper level code. */ memset(mp->mnt_stat.f_mntonname, 0, MNAMELEN); strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN); memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN); strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN); memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN); strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN); error = ffs_mountfs(devvp, mp, p); } if (error) goto error_2; /* * Initialize FS stat information in mount struct; uses both * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname * * This code is common to root and non-root mounts */ memcpy(&mp->mnt_stat.mount_info.ufs_args, &args, sizeof(args)); VFS_STATFS(mp, &mp->mnt_stat, p); success: if (path && (mp->mnt_flag & MNT_UPDATE)) { /* Update clean flag after changing read-onlyness. */ fs = ump->um_fs; if (ronly != fs->fs_ronly) { fs->fs_ronly = ronly; fs->fs_clean = ronly && (fs->fs_flags & FS_UNCLEAN) == 0 ? 1 : 0; if (ronly) free(fs->fs_contigdirs, M_UFSMNT, 0); } if (!ronly) { if (mp->mnt_flag & MNT_SOFTDEP) fs->fs_flags |= FS_DOSOFTDEP; else fs->fs_flags &= ~FS_DOSOFTDEP; } ffs_sbupdate(ump, MNT_WAIT); } return (0); error_2: /* error with devvp held */ vrele (devvp); error_1: /* no state to back out */ return (error); }
/* * VFS Operations. * * mount system call */ int ext2fs_mount(struct mount *mp, const char *path, void *data, struct nameidata *ndp, struct proc *p) { struct vnode *devvp; struct ufs_args args; struct ufsmount *ump = NULL; struct m_ext2fs *fs; char fname[MNAMELEN]; char fspec[MNAMELEN]; int error, flags; mode_t accessmode; error = copyin(data, &args, sizeof(struct ufs_args)); if (error) return (error); /* * If updating, check whether changing from read-only to * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_e2fs; if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { flags = WRITECLOSE; if (mp->mnt_flag & MNT_FORCE) flags |= FORCECLOSE; error = ext2fs_flushfiles(mp, flags, p); if (error == 0 && ext2fs_cgupdate(ump, MNT_WAIT) == 0 && (fs->e2fs.e2fs_state & E2FS_ERRORS) == 0) { fs->e2fs.e2fs_state = E2FS_ISCLEAN; (void)ext2fs_sbupdate(ump, MNT_WAIT); } if (error) return (error); fs->e2fs_ronly = 1; } if (mp->mnt_flag & MNT_RELOAD) { error = ext2fs_reload(mp, ndp->ni_cnd.cn_cred, p); if (error) return (error); } if (fs->e2fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { /* * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ if (suser(p, 0) != 0) { devvp = ump->um_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, VREAD | VWRITE, p->p_ucred); VOP_UNLOCK(devvp, 0); if (error) return (error); } fs->e2fs_ronly = 0; if (fs->e2fs.e2fs_state == E2FS_ISCLEAN) fs->e2fs.e2fs_state = 0; else fs->e2fs.e2fs_state = E2FS_ERRORS; fs->e2fs_fmod = 1; } if (args.fspec == NULL) { /* * Process export requests. */ return (vfs_export(mp, &ump->um_export, &args.export_info)); } } /* * Not an update, or updating the name: look up the name * and verify that it refers to a sensible block device. */ error = copyinstr(args.fspec, fspec, sizeof(fspec), NULL); if (error) goto error; if (disk_map(fspec, fname, MNAMELEN, DM_OPENBLCK) == -1) memcpy(fname, fspec, sizeof(fname)); NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p); if ((error = namei(ndp)) != 0) goto error; devvp = ndp->ni_vp; if (devvp->v_type != VBLK) { error = ENOTBLK; goto error_devvp; } if (major(devvp->v_rdev) >= nblkdev) { error = ENXIO; goto error_devvp; } /* * If mount by non-root, then verify that user has necessary * permissions on the device. */ if (suser(p, 0) != 0) { accessmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accessmode |= VWRITE; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_ACCESS(devvp, accessmode, p->p_ucred); VOP_UNLOCK(devvp, 0); if (error) goto error_devvp; } if ((mp->mnt_flag & MNT_UPDATE) == 0) error = ext2fs_mountfs(devvp, mp, p); else { if (devvp != ump->um_devvp) error = EINVAL; /* XXX needs translation */ else vrele(devvp); } if (error) goto error_devvp; ump = VFSTOUFS(mp); fs = ump->um_e2fs; memset(fs->e2fs_fsmnt, 0, sizeof(fs->e2fs_fsmnt)); strlcpy(fs->e2fs_fsmnt, path, sizeof(fs->e2fs_fsmnt)); if (fs->e2fs.e2fs_rev > E2FS_REV0) { memset(fs->e2fs.e2fs_fsmnt, 0, sizeof(fs->e2fs.e2fs_fsmnt)); strlcpy(fs->e2fs.e2fs_fsmnt, mp->mnt_stat.f_mntonname, sizeof(fs->e2fs.e2fs_fsmnt)); } memcpy(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt, MNAMELEN); memset(mp->mnt_stat.f_mntfromname, 0, MNAMELEN); strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN); memset(mp->mnt_stat.f_mntfromspec, 0, MNAMELEN); strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN); if (fs->e2fs_fmod != 0) { /* XXX */ fs->e2fs_fmod = 0; if (fs->e2fs.e2fs_state == 0) fs->e2fs.e2fs_wtime = time_second; else printf("%s: file system not clean; please fsck(8)\n", mp->mnt_stat.f_mntfromname); ext2fs_cgupdate(ump, MNT_WAIT); } goto success; error_devvp: /* Error with devvp held. */ vrele(devvp); error: /* Error with no state to backout. */ success: return (error); }
int diskmapioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct dk_diskmap *dm; struct nameidata ndp; struct filedesc *fdp; struct file *fp = NULL; struct vnode *vp = NULL, *ovp; char *devname; int fd, error = EINVAL; if (cmd != DIOCMAP) return EINVAL; /* * Map a request for a disk to the correct device. We should be * supplied with either a diskname or a disklabel UID. */ dm = (struct dk_diskmap *)addr; fd = dm->fd; devname = malloc(PATH_MAX, M_DEVBUF, M_WAITOK); if (copyinstr(dm->device, devname, PATH_MAX, NULL)) goto invalid; if (disk_map(devname, devname, PATH_MAX, dm->flags) == 0) if (copyoutstr(devname, dm->device, PATH_MAX, NULL)) goto invalid; /* Attempt to open actual device. */ fdp = p->p_fd; fdplock(fdp); if ((error = getvnode(fdp, fd, &fp)) != 0) goto bad; ndp.ni_segflg = UIO_SYSSPACE; ndp.ni_dirfd = AT_FDCWD; ndp.ni_dirp = devname; ndp.ni_cnd.cn_proc = p; if ((error = vn_open(&ndp, fp->f_flag, 0)) != 0) goto bad; vp = ndp.ni_vp; /* Close the original vnode. */ ovp = (struct vnode *)fp->f_data; if (fp->f_flag & FWRITE) ovp->v_writecount--; if (ovp->v_writecount == 0) { vn_lock(ovp, LK_EXCLUSIVE | LK_RETRY, p); VOP_CLOSE(ovp, fp->f_flag, p->p_ucred); vput(ovp); } fp->f_type = DTYPE_VNODE; fp->f_ops = &vnops; fp->f_data = (caddr_t)vp; fp->f_offset = 0; fp->f_rxfer = 0; fp->f_wxfer = 0; fp->f_seek = 0; fp->f_rbytes = 0; fp->f_wbytes = 0; VOP_UNLOCK(vp, 0); FRELE(fp, p); fdpunlock(fdp); free(devname, M_DEVBUF, 0); return 0; bad: if (vp) vput(vp); if (fp) FRELE(fp, p); fdpunlock(fdp); invalid: free(devname, M_DEVBUF, 0); return (error); }