static int copen(int startfd, char *fname, int filemode, int createmode) { struct pathname pn; vnode_t *vp, *sdvp; file_t *fp, *startfp; enum vtype type; int error; int fd, dupfd; vnode_t *startvp; proc_t *p = curproc; if (startfd == AT_FDCWD) { /* * Regular open() */ startvp = NULL; } else { /* * We're here via openat() */ char startchar; if (copyin(fname, &startchar, sizeof (char))) return (set_errno(EFAULT)); /* * if startchar is / then startfd is ignored */ if (startchar == '/') startvp = NULL; else { if ((startfp = getf(startfd)) == NULL) return (set_errno(EBADF)); startvp = startfp->f_vnode; VN_HOLD(startvp); releasef(startfd); } } if (filemode & FXATTR) { /* * Make sure we have a valid request. * We must either have a real fd or AT_FDCWD */ if (startfd != AT_FDCWD && startvp == NULL) { error = EINVAL; goto out; } if (error = pn_get(fname, UIO_USERSPACE, &pn)) { goto out; } if (startfd == AT_FDCWD) { mutex_enter(&p->p_lock); startvp = PTOU(p)->u_cdir; VN_HOLD(startvp); mutex_exit(&p->p_lock); } /* * Verify permission to put attributes on file */ if ((VOP_ACCESS(startvp, VREAD, 0, CRED()) != 0) && (VOP_ACCESS(startvp, VWRITE, 0, CRED()) != 0) && (VOP_ACCESS(startvp, VEXEC, 0, CRED()) != 0)) { error = EACCES; pn_free(&pn); goto out; } if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0) { error = VOP_LOOKUP(startvp, "", &sdvp, &pn, LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED()); } else { error = EINVAL; } pn_free(&pn); if (error != 0) goto out; VN_RELE(startvp); startvp = sdvp; } if ((filemode & (FREAD|FWRITE)) != 0) { if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) filemode &= ~FNDELAY; error = falloc((vnode_t *)NULL, filemode, &fp, &fd); if (error == 0) { #ifdef C2_AUDIT if (audit_active) audit_setfsat_path(1); #endif /* C2_AUDIT */ /* * Last arg is a don't-care term if * !(filemode & FCREAT). */ error = vn_openat(fname, UIO_USERSPACE, filemode, (int)(createmode & MODEMASK), &vp, CRCREAT, u.u_cmask, startvp); if (startvp != NULL) VN_RELE(startvp); if (error == 0) { #ifdef C2_AUDIT if (audit_active) audit_copen(fd, fp, vp); #endif /* C2_AUDIT */ if ((vp->v_flag & VDUP) == 0) { fp->f_vnode = vp; mutex_exit(&fp->f_tlock); /* * We must now fill in the slot * falloc reserved. */ setf(fd, fp); return (fd); } else { /* * Special handling for /dev/fd. * Give up the file pointer * and dup the indicated file descriptor * (in v_rdev). This is ugly, but I've * seen worse. */ unfalloc(fp); dupfd = getminor(vp->v_rdev); type = vp->v_type; mutex_enter(&vp->v_lock); vp->v_flag &= ~VDUP; mutex_exit(&vp->v_lock); VN_RELE(vp); if (type != VCHR) return (set_errno(EINVAL)); if ((fp = getf(dupfd)) == NULL) { setf(fd, NULL); return (set_errno(EBADF)); } mutex_enter(&fp->f_tlock); fp->f_count++; mutex_exit(&fp->f_tlock); setf(fd, fp); releasef(dupfd); } return (fd); } else { setf(fd, NULL); unfalloc(fp); return (set_errno(error)); } } } else { error = EINVAL; } out: if (startvp != NULL) VN_RELE(startvp); return (set_errno(error)); }
/* ARGSUSED */ int ufs_fioio( struct vnode *vp, /* any file on the fs */ struct fioio *fiou, /* fioio struct in userland */ int flag, /* flag from VOP_IOCTL() */ struct cred *cr) /* credentials from ufs_ioctl */ { int error = 0; struct vnode *vpio = NULL; /* vnode for inode open */ struct inode *ipio = NULL; /* inode for inode open */ struct file *fpio = NULL; /* file for inode open */ struct inode *ip; /* inode for file system */ struct fs *fs; /* fs for file system */ STRUCT_DECL(fioio, fio); /* copy of user's fioio struct */ /* * must be privileged */ if (secpolicy_fs_config(cr, vp->v_vfsp) != 0) return (EPERM); STRUCT_INIT(fio, flag & DATAMODEL_MASK); /* * get user's copy of fioio struct */ if (copyin(fiou, STRUCT_BUF(fio), STRUCT_SIZE(fio))) return (EFAULT); ip = VTOI(vp); fs = ip->i_fs; /* * check the inode number against the fs's inode number bounds */ if (STRUCT_FGET(fio, fio_ino) < UFSROOTINO) return (ESRCH); if (STRUCT_FGET(fio, fio_ino) >= fs->fs_ncg * fs->fs_ipg) return (ESRCH); rw_enter(&ip->i_ufsvfs->vfs_dqrwlock, RW_READER); /* * get the inode */ error = ufs_iget(ip->i_vfs, STRUCT_FGET(fio, fio_ino), &ipio, cr); rw_exit(&ip->i_ufsvfs->vfs_dqrwlock); if (error) return (error); /* * check the generation number */ rw_enter(&ipio->i_contents, RW_READER); if (ipio->i_gen != STRUCT_FGET(fio, fio_gen)) { error = ESTALE; rw_exit(&ipio->i_contents); goto errout; } /* * check if the inode is free */ if (ipio->i_mode == 0) { error = ENOENT; rw_exit(&ipio->i_contents); goto errout; } rw_exit(&ipio->i_contents); /* * Adapted from copen: get a file struct * Large Files: We open this file descriptor with FOFFMAX flag * set so that it will be like a large file open. */ if (falloc(NULL, (FREAD|FOFFMAX), &fpio, STRUCT_FADDR(fio, fio_fd))) goto errout; /* * Adapted from vn_open: check access and then open the file */ vpio = ITOV(ipio); if (error = VOP_ACCESS(vpio, VREAD, 0, cr, NULL)) goto errout; if (error = VOP_OPEN(&vpio, FREAD, cr, NULL)) goto errout; /* * Adapted from copen: initialize the file struct */ fpio->f_vnode = vpio; /* * return the fd */ if (copyout(STRUCT_BUF(fio), fiou, STRUCT_SIZE(fio))) { error = EFAULT; goto errout; } setf(STRUCT_FGET(fio, fio_fd), fpio); mutex_exit(&fpio->f_tlock); return (0); errout: /* * free the file struct and fd */ if (fpio) { setf(STRUCT_FGET(fio, fio_fd), NULL); unfalloc(fpio); } /* * release the hold on the inode */ if (ipio) VN_RELE(ITOV(ipio)); return (error); }
/* * pipe(2) system call. * Create a pipe by connecting two streams together. Associate * each end of the pipe with a vnode, a file descriptor and * one of the streams. */ longlong_t pipe() { vnode_t *vp1, *vp2; struct file *fp1, *fp2; int error = 0; int fd1, fd2; rval_t r; /* * Allocate and initialize two vnodes. */ makepipe(&vp1, &vp2); /* * Allocate and initialize two file table entries and two * file pointers. Each file pointer is open for read and * write. */ if (error = falloc(vp1, FWRITE|FREAD, &fp1, &fd1)) { VN_RELE(vp1); VN_RELE(vp2); return ((longlong_t)set_errno(error)); } if (error = falloc(vp2, FWRITE|FREAD, &fp2, &fd2)) goto out2; /* * Create two stream heads and attach to each vnode. */ if (error = fifo_stropen(&vp1, FWRITE|FREAD, fp1->f_cred, 0, 0)) goto out; if (error = fifo_stropen(&vp2, FWRITE|FREAD, fp2->f_cred, 0, 0)) { (void) VOP_CLOSE(vp1, FWRITE|FREAD, 1, (offset_t)0, fp1->f_cred); goto out; } strmate(vp1, vp2); VTOF(vp1)->fn_ino = VTOF(vp2)->fn_ino = fifogetid(); /* * Now fill in the entries that falloc reserved */ mutex_exit(&fp1->f_tlock); mutex_exit(&fp2->f_tlock); setf(fd1, fp1); setf(fd2, fp2); /* * Return the file descriptors to the user. They now * point to two different vnodes which have different * stream heads. */ r.r_val1 = fd1; r.r_val2 = fd2; return (r.r_vals); out: unfalloc(fp2); setf(fd2, NULL); out2: unfalloc(fp1); setf(fd1, NULL); VN_RELE(vp1); VN_RELE(vp2); return ((longlong_t)set_errno(error)); }
int t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr) { int madefp = 0; struct T_info_ack inforeq; int retval; vnode_t *vp; struct strioctl strioc; int error; TIUSER *ntiptr; int rtries = 0; /* * Special case for install: miniroot needs to be able to access files * via NFS as though it were always in the global zone. */ if (nfs_global_client_only != 0) cr = kcred; KTLILOG(2, "t_kopen: fp %x, ", fp); KTLILOG(2, "rdev %x, ", rdev); KTLILOG(2, "flags %x\n", flags); *tiptr = NULL; error = 0; retval = 0; if (fp == NULL) { if (rdev == 0 || rdev == NODEV) { KTLILOG(1, "t_kopen: null device\n", 0); return (EINVAL); } /* * allocate a file pointer, but * no file descripter. */ if ((error = falloc(NULL, flags, &fp, NULL)) != 0) { KTLILOG(1, "t_kopen: falloc: %d\n", error); return (error); } /* Install proper cred in file */ if (cr != fp->f_cred) { crhold(cr); crfree(fp->f_cred); fp->f_cred = cr; } vp = makespecvp(rdev, VCHR); /* * this will call the streams open for us. * Want to retry if error is EAGAIN, the streams open routine * might fail due to temporarely out of memory. */ do { if ((error = VOP_OPEN(&vp, flags, cr)) == EAGAIN) { (void) delay(hz); } } while (error == EAGAIN && ++rtries < 5); if (error) { KTLILOG(1, "t_kopen: VOP_OPEN: %d\n", error); unfalloc(fp); VN_RELE(vp); return (error); } /* * fp is completely initialized so drop the write lock. * I actually don't need any locking on fp in here since * there is no fd pointing at it. However, since I could * call closef if there is an error and closef requires * the fp read locked, I will acquire the read lock here * and make sure I release it before I leave this routine. */ fp->f_vnode = vp; mutex_exit(&fp->f_tlock); madefp = 1; } else { vp = fp->f_vnode; } if (vp->v_stream == NULL) { if (madefp) (void) closef(fp); KTLILOG(1, "t_kopen: not a streams device\n", 0); return (ENOSTR); } /* * allocate a new transport structure */ ntiptr = kmem_alloc(TIUSERSZ, KM_SLEEP); ntiptr->fp = fp; ntiptr->flags = madefp ? MADE_FP : 0; KTLILOG(2, "t_kopen: vp %x, ", vp); KTLILOG(2, "stp %x\n", vp->v_stream); /* * see if TIMOD is already pushed */ error = strioctl(vp, I_FIND, (intptr_t)"timod", 0, K_TO_K, cr, &retval); if (error) { kmem_free(ntiptr, TIUSERSZ); if (madefp) (void) closef(fp); KTLILOG(1, "t_kopen: strioctl(I_FIND, timod): %d\n", error); return (error); } if (retval == 0) { tryagain: error = strioctl(vp, I_PUSH, (intptr_t)"timod", 0, K_TO_K, cr, &retval); if (error) { switch (error) { case ENOSPC: case EAGAIN: case ENOSR: /* * This probably means the master file * should be tuned. */ cmn_err(CE_WARN, "t_kopen: I_PUSH of timod failed, error %d\n", error); (void) delay(hz); error = 0; goto tryagain; default: kmem_free(ntiptr, TIUSERSZ); if (madefp) (void) closef(fp); KTLILOG(1, "t_kopen: I_PUSH (timod): %d", error); return (error); } } } inforeq.PRIM_type = T_INFO_REQ; strioc.ic_cmd = TI_GETINFO; strioc.ic_timout = 0; strioc.ic_dp = (char *)&inforeq; strioc.ic_len = (int)sizeof (struct T_info_req); error = strdoioctl(vp->v_stream, &strioc, FNATIVE, K_TO_K, cr, &retval); if (error) { kmem_free(ntiptr, TIUSERSZ); if (madefp) (void) closef(fp); KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): %d\n", error); return (error); } if (retval) { if ((retval & 0xff) == TSYSERR) error = (retval >> 8) & 0xff; else error = t_tlitosyserr(retval & 0xff); kmem_free(ntiptr, TIUSERSZ); if (madefp) (void) closef(fp); KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): retval: 0x%x\n", retval); return (error); }
static int copen(int startfd, char *fname, int filemode, int createmode) { struct pathname pn; vnode_t *vp, *sdvp; file_t *fp, *startfp; enum vtype type; int error; int fd, dupfd; vnode_t *startvp; proc_t *p = curproc; uio_seg_t seg = UIO_USERSPACE; char *open_filename = fname; uint32_t auditing = AU_AUDITING(); char startchar; if (filemode & (FSEARCH|FEXEC)) { /* * Must be one or the other and neither FREAD nor FWRITE * Must not be any of FAPPEND FCREAT FTRUNC FXATTR FXATTRDIROPEN * XXX: Should these just be silently ignored? */ if ((filemode & (FREAD|FWRITE)) || (filemode & (FSEARCH|FEXEC)) == (FSEARCH|FEXEC) || (filemode & (FAPPEND|FCREAT|FTRUNC|FXATTR|FXATTRDIROPEN))) return (set_errno(EINVAL)); } if (startfd == AT_FDCWD) { /* * Regular open() */ startvp = NULL; } else { /* * We're here via openat() */ if (copyin(fname, &startchar, sizeof (char))) return (set_errno(EFAULT)); /* * if startchar is / then startfd is ignored */ if (startchar == '/') startvp = NULL; else { if ((startfp = getf(startfd)) == NULL) return (set_errno(EBADF)); startvp = startfp->f_vnode; VN_HOLD(startvp); releasef(startfd); } } /* * Handle __openattrdirat() requests */ if (filemode & FXATTRDIROPEN) { if (auditing && startvp != NULL) audit_setfsat_path(1); if (error = lookupnameat(fname, seg, FOLLOW, NULLVPP, &vp, startvp)) return (set_errno(error)); if (startvp != NULL) VN_RELE(startvp); startvp = vp; } /* * Do we need to go into extended attribute space? */ if (filemode & FXATTR) { if (startfd == AT_FDCWD) { if (copyin(fname, &startchar, sizeof (char))) return (set_errno(EFAULT)); /* * If startchar == '/' then no extended attributes * are looked up. */ if (startchar == '/') { startvp = NULL; } else { mutex_enter(&p->p_lock); startvp = PTOU(p)->u_cdir; VN_HOLD(startvp); mutex_exit(&p->p_lock); } } /* * Make sure we have a valid extended attribute request. * We must either have a real fd or AT_FDCWD and a relative * pathname. */ if (startvp == NULL) { goto noxattr; } } if (filemode & (FXATTR|FXATTRDIROPEN)) { vattr_t vattr; if (error = pn_get(fname, UIO_USERSPACE, &pn)) { goto out; } /* * In order to access hidden attribute directory the * user must be able to stat() the file */ vattr.va_mask = AT_ALL; if (error = VOP_GETATTR(startvp, &vattr, 0, CRED(), NULL)) { pn_free(&pn); goto out; } if ((startvp->v_vfsp->vfs_flag & VFS_XATTR) != 0 || vfs_has_feature(startvp->v_vfsp, VFSFT_SYSATTR_VIEWS)) { error = VOP_LOOKUP(startvp, "", &sdvp, &pn, (filemode & FXATTRDIROPEN) ? LOOKUP_XATTR : LOOKUP_XATTR|CREATE_XATTR_DIR, rootvp, CRED(), NULL, NULL, NULL); } else { error = EINVAL; } /* * For __openattrdirat() use "." as filename to open * as part of vn_openat() */ if (error == 0 && (filemode & FXATTRDIROPEN)) { open_filename = "."; seg = UIO_SYSSPACE; } pn_free(&pn); if (error != 0) goto out; VN_RELE(startvp); startvp = sdvp; } noxattr: if ((filemode & (FREAD|FWRITE|FSEARCH|FEXEC|FXATTRDIROPEN)) != 0) { if ((filemode & (FNONBLOCK|FNDELAY)) == (FNONBLOCK|FNDELAY)) filemode &= ~FNDELAY; error = falloc((vnode_t *)NULL, filemode, &fp, &fd); if (error == 0) { if (auditing && startvp != NULL) audit_setfsat_path(1); /* * Last arg is a don't-care term if * !(filemode & FCREAT). */ error = vn_openat(open_filename, seg, filemode, (int)(createmode & MODEMASK), &vp, CRCREAT, PTOU(curproc)->u_cmask, startvp, fd); if (startvp != NULL) VN_RELE(startvp); if (error == 0) { if ((vp->v_flag & VDUP) == 0) { fp->f_vnode = vp; mutex_exit(&fp->f_tlock); /* * We must now fill in the slot * falloc reserved. */ setf(fd, fp); return (fd); } else { /* * Special handling for /dev/fd. * Give up the file pointer * and dup the indicated file descriptor * (in v_rdev). This is ugly, but I've * seen worse. */ unfalloc(fp); dupfd = getminor(vp->v_rdev); type = vp->v_type; mutex_enter(&vp->v_lock); vp->v_flag &= ~VDUP; mutex_exit(&vp->v_lock); VN_RELE(vp); if (type != VCHR) return (set_errno(EINVAL)); if ((fp = getf(dupfd)) == NULL) { setf(fd, NULL); return (set_errno(EBADF)); } mutex_enter(&fp->f_tlock); fp->f_count++; mutex_exit(&fp->f_tlock); setf(fd, fp); releasef(dupfd); } return (fd); } else { setf(fd, NULL); unfalloc(fp); return (set_errno(error)); } } } else { error = EINVAL; } out: if (startvp != NULL) VN_RELE(startvp); return (set_errno(error)); }