static int fd_revoke(struct lwp *l, int fd, register_t *retval) { file_t *fp; vnode_t *vp; int error; if ((fp = fd_getfile(fd)) == NULL) return EBADF; if (fp->f_type != DTYPE_VNODE) { fd_putfile(fd); return EINVAL; } vp = (vnode_t *) fp->f_data; if (vp->v_type != VCHR && vp->v_type != VBLK) { error = EINVAL; goto out; } error = dorevoke(vp, l->l_cred); out: vrele(vp); fd_putfile(fd); return error; }
int svr4_sys_open(struct lwp *l, const struct svr4_sys_open_args *uap, register_t *retval) { int error; struct sys_open_args cup; SCARG(&cup, flags) = svr4_to_bsd_flags(SCARG(uap, flags)); SCARG(&cup, path) = SCARG(uap, path); SCARG(&cup, mode) = SCARG(uap, mode); error = sys_open(l, &cup, retval); if (error) return error; /* XXXAD locking */ if (!(SCARG(&cup, flags) & O_NOCTTY) && SESS_LEADER(l->l_proc) && !(l->l_proc->p_lflag & PL_CONTROLT)) { file_t *fp; fp = fd_getfile(*retval); /* ignore any error, just give it a try */ if (fp != NULL) { if (fp->f_type == DTYPE_VNODE) (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, NULL); fd_putfile(*retval); } } return 0; }
static int fd_truncate(struct lwp *l, int fd, struct flock *flp, register_t *retval) { file_t *fp; off_t start, length; vnode_t *vp; struct vattr vattr; int error; struct sys_ftruncate_args ft; /* * We only support truncating the file. */ if ((fp = fd_getfile(fd)) == NULL) return EBADF; vp = fp->f_data; if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { fd_putfile(fd); return ESPIPE; } if ((error = VOP_GETATTR(vp, &vattr, l->l_cred)) != 0) { fd_putfile(fd); return error; } length = vattr.va_size; switch (flp->l_whence) { case SEEK_CUR: start = fp->f_offset + flp->l_start; break; case SEEK_END: start = flp->l_start + length; break; case SEEK_SET: start = flp->l_start; break; default: fd_putfile(fd); return EINVAL; } if (start + flp->l_len < length) { /* We don't support free'ing in the middle of the file */ fd_putfile(fd); return EINVAL; } SCARG(&ft, fd) = fd; SCARG(&ft, length) = start; error = sys_ftruncate(l, &ft, retval); fd_putfile(fd); return error; }
/* Read requests from comfd and proxy them to /dev/puffs */ static void writethread(void *arg) { struct ptargs *pap = arg; struct file *fp; struct putter_hdr *phdr; register_t rv; char *buf; off_t off; size_t toread; int error; buf = kmem_alloc(BUFSIZE, KM_SLEEP); phdr = (struct putter_hdr *)buf; for (;;) { size_t n; /* * Need to write everything to the "kernel" in one chunk, * so make sure we have it here. */ off = 0; toread = sizeof(struct putter_hdr); do { struct rumpuser_iovec iov; iov.iov_base = buf+off; iov.iov_len = toread; error = rumpuser_iovread(pap->comfd, &iov, 1, RUMPUSER_IOV_NOSEEK, &n); if (error) panic("rumpuser_read %zd %d", n, error); if (n == 0) goto out; off += n; if (off >= sizeof(struct putter_hdr)) toread = phdr->pth_framelen - off; else toread = off - sizeof(struct putter_hdr); } while (toread); off = 0; rv = 0; fp = fd_getfile(pap->fpfd); if (fp == NULL) error = EINVAL; else error = dofilewrite(pap->fpfd, fp, buf, phdr->pth_framelen, &off, 0, &rv); if (error == ENXIO) goto out; KASSERT(rv == phdr->pth_framelen); } out: kthread_exit(0); }
/* ARGSUSED */ int sys_flock(struct lwp *l, const struct sys_flock_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(int) how; } */ int fd, how, error; file_t *fp; vnode_t *vp; struct flock lf; fd = SCARG(uap, fd); how = SCARG(uap, how); error = 0; if ((fp = fd_getfile(fd)) == NULL) { return EBADF; } if (fp->f_type != DTYPE_VNODE) { fd_putfile(fd); return EOPNOTSUPP; } vp = fp->f_vnode; lf.l_whence = SEEK_SET; lf.l_start = 0; lf.l_len = 0; switch (how & ~LOCK_NB) { case LOCK_UN: lf.l_type = F_UNLCK; atomic_and_uint(&fp->f_flag, ~FHASLOCK); error = VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK); fd_putfile(fd); return error; case LOCK_EX: lf.l_type = F_WRLCK; break; case LOCK_SH: lf.l_type = F_RDLCK; break; default: fd_putfile(fd); return EINVAL; } atomic_or_uint(&fp->f_flag, FHASLOCK); if (how & LOCK_NB) { error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK); } else { error = VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT); } fd_putfile(fd); return error; }
/* * Convert a file descriptor to appropriate smb_share pointer */ static struct file* nsmb_getfp(struct filedesc* fdp, int fd, int flag) { struct file* fp; fp = fd_getfile(fdp, fd); if ((fp->f_flag & flag) == 0) return (NULL); return (fp); }
/* * Read requests from /dev/puffs and forward them to comfd * * XXX: the init detection is really sucky, but let's not * waste too much energy for a better one here */ static void readthread(void *arg) { struct ptargs *pap = arg; struct file *fp; register_t rv; char *buf; off_t off; int error, inited; buf = kmem_alloc(BUFSIZE, KM_SLEEP); inited = 0; retry: kpause(NULL, 0, hz/4, NULL); for (;;) { size_t n; off = 0; fp = fd_getfile(pap->fpfd); if (fp == NULL) error = EINVAL; else error = dofileread(pap->fpfd, fp, buf, BUFSIZE, &off, 0, &rv); if (error) { if (error == ENOENT && inited == 0) goto retry; if (error == ENXIO) break; panic("fileread failed: %d", error); } inited = 1; while (rv) { struct rumpuser_iovec iov; iov.iov_base = buf; iov.iov_len = rv; error = rumpuser_iovwrite(pap->comfd, &iov, 1, RUMPUSER_IOV_NOSEEK, &n); if (error) panic("fileread failed: %d", error); if (n == 0) panic("fileread failed: closed"); rv -= n; } } kthread_exit(0); }
/* * Return status information about a file descriptor. * Common function for compat code. */ int do_sys_fstat(int fd, struct stat *sb) { file_t *fp; int error; if ((fp = fd_getfile(fd)) == NULL) { return EBADF; } error = (*fp->f_ops->fo_stat)(fp, sb); fd_putfile(fd); return error; }
/* * Duplicate a file descriptor. */ int sys_dup(struct lwp *l, const struct sys_dup_args *uap, register_t *retval) { /* { syscallarg(int) fd; } */ int error, newfd, oldfd; file_t *fp; oldfd = SCARG(uap, fd); if ((fp = fd_getfile(oldfd)) == NULL) { return EBADF; } error = fd_dup(fp, 0, &newfd, false); fd_putfile(oldfd); *retval = newfd; return error; }
/* * Adjust for a truncated SCM_RIGHTS control message. * This means closing any file descriptors that aren't present * in the returned buffer. * m is the mbuf holding the (already externalized) SCM_RIGHTS message. */ static void free_rights(struct mbuf *m) { struct cmsghdr *cm; int *fdv; unsigned int nfds, i; KASSERT(sizeof(*cm) <= m->m_len); cm = mtod(m, struct cmsghdr *); KASSERT(CMSG_ALIGN(sizeof(*cm)) <= cm->cmsg_len); KASSERT(cm->cmsg_len <= m->m_len); nfds = (cm->cmsg_len - CMSG_ALIGN(sizeof(*cm))) / sizeof(int); fdv = (int *)CMSG_DATA(cm); for (i = 0; i < nfds; i++) if (fd_getfile(fdv[i]) != NULL) (void)fd_close(fdv[i]); }
/* * Return pathconf information about a file descriptor. */ int sys_fpathconf(struct lwp *l, const struct sys_fpathconf_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(int) name; } */ int fd, error; file_t *fp; fd = SCARG(uap, fd); error = 0; if ((fp = fd_getfile(fd)) == NULL) { return (EBADF); } switch (fp->f_type) { case DTYPE_SOCKET: case DTYPE_PIPE: if (SCARG(uap, name) != _PC_PIPE_BUF) error = EINVAL; else *retval = PIPE_BUF; break; case DTYPE_VNODE: error = VOP_PATHCONF(fp->f_vnode, SCARG(uap, name), retval); break; case DTYPE_KQUEUE: error = EINVAL; break; default: error = EOPNOTSUPP; break; } fd_putfile(fd); return (error); }
int ultrix_sys_open(struct lwp *l, const struct ultrix_sys_open_args *uap, register_t *retval) { struct proc *p = l->l_proc; int q, r; int noctty; int ret; struct sys_open_args ap; /* convert open flags into NetBSD flags */ q = SCARG(uap, flags); noctty = q & 0x8000; r = (q & (0x0001 | 0x0002 | 0x0008 | 0x0040 | 0x0200 | 0x0400 | 0x0800)); r |= ((q & (0x0004 | 0x1000 | 0x4000)) ? O_NONBLOCK : 0); r |= ((q & 0x0080) ? O_SHLOCK : 0); r |= ((q & 0x0100) ? O_EXLOCK : 0); r |= ((q & 0x2000) ? O_FSYNC : 0); SCARG(&ap, path) = SCARG(uap, path); SCARG(&ap, flags) = r; SCARG(&ap, mode) = SCARG(uap, mode); ret = sys_open(l, &ap, retval); /* XXXSMP */ if (!ret && !noctty && SESS_LEADER(p) && !(p->p_lflag & PL_CONTROLT)) { file_t *fp; int fd; fd = (int)*retval; fp = fd_getfile(fd); /* ignore any error, just give it a try */ if (fp != NULL) { if (fp->f_type == DTYPE_VNODE) (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, NULL); fd_putfile(fd); } } return ret; }
static int /*ARGSUSED*/ ptmopen(dev_t dev, int flag, int mode, struct lwp *l) { int error; int fd; dev_t ttydev; struct mount *mp; switch(minor(dev)) { case 0: /* /dev/ptmx */ case 2: /* /emul/linux/dev/ptmx */ if ((error = pty_getmp(l, &mp)) != 0) return error; if ((error = pty_alloc_master(l, &fd, &ttydev, mp)) != 0) return error; if (minor(dev) == 2) { /* * Linux ptyfs grants the pty right here. * Handle this case here, instead of writing * a new linux module. */ if ((error = pty_grant_slave(l, ttydev, mp)) != 0) { file_t *fp = fd_getfile(fd); if (fp != NULL) { fd_close(fd); } return error; } } curlwp->l_dupfd = fd; return EMOVEFD; case 1: /* /dev/ptm */ return 0; default: return ENODEV; } }
int sys_paccept(struct lwp *l, const struct sys_paccept_args *uap, register_t *retval) { /* { syscallarg(int) s; syscallarg(struct sockaddr *) name; syscallarg(unsigned int *) anamelen; syscallarg(const sigset_t *) mask; syscallarg(int) flags; } */ int error, fd; struct mbuf *name; sigset_t *mask, amask; if (SCARG(uap, mask) != NULL) { error = copyin(SCARG(uap, mask), &amask, sizeof(amask)); if (error) return error; mask = &amask; } else mask = NULL; error = do_sys_accept(l, SCARG(uap, s), &name, retval, mask, SCARG(uap, flags), FNONBLOCK); if (error != 0) return error; error = copyout_sockname(SCARG(uap, name), SCARG(uap, anamelen), MSG_LENUSRSPACE, name); if (name != NULL) m_free(name); if (error != 0) { fd = (int)*retval; if (fd_getfile(fd) != NULL) (void)fd_close(fd); } return error; }
/* ARGSUSED */ int compat_12_sys_fstat(struct lwp *l, const struct compat_12_sys_fstat_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(struct stat12 *) sb; } */ int fd = SCARG(uap, fd); struct file *fp; struct stat ub; struct stat12 oub; int error; if ((fp = fd_getfile(fd)) == NULL) return (EBADF); error = (*fp->f_ops->fo_stat)(fp, &ub); fd_putfile(fd); if (error == 0) { compat_12_stat_conv(&ub, &oub); error = copyout(&oub, SCARG(uap, sb), sizeof (oub)); } return (error); }
/* * Close a file descriptor. */ int sys_close(struct lwp *l, const struct sys_close_args *uap, register_t *retval) { /* { syscallarg(int) fd; } */ int error; if (fd_getfile(SCARG(uap, fd)) == NULL) { return EBADF; } error = fd_close(SCARG(uap, fd)); if (error == ERESTART) { #ifdef DIAGNOSTIC printf("pid %d: close returned ERESTART\n", (int)l->l_proc->p_pid); #endif error = EINTR; } return error; }
int do_posix_fadvise(int fd, off_t offset, off_t len, int advice) { file_t *fp; vnode_t *vp; off_t endoffset; int error; CTASSERT(POSIX_FADV_NORMAL == UVM_ADV_NORMAL); CTASSERT(POSIX_FADV_RANDOM == UVM_ADV_RANDOM); CTASSERT(POSIX_FADV_SEQUENTIAL == UVM_ADV_SEQUENTIAL); if (len == 0) { endoffset = INT64_MAX; } else if (len > 0 && (INT64_MAX - offset) >= len) { endoffset = offset + len; } else { return EINVAL; } if ((fp = fd_getfile(fd)) == NULL) { return EBADF; } if (fp->f_type != DTYPE_VNODE) { if (fp->f_type == DTYPE_PIPE || fp->f_type == DTYPE_SOCKET) { error = ESPIPE; } else { error = EOPNOTSUPP; } fd_putfile(fd); return error; } switch (advice) { case POSIX_FADV_WILLNEED: case POSIX_FADV_DONTNEED: vp = fp->f_vnode; if (vp->v_type != VREG && vp->v_type != VBLK) { fd_putfile(fd); return 0; } break; } switch (advice) { case POSIX_FADV_NORMAL: case POSIX_FADV_RANDOM: case POSIX_FADV_SEQUENTIAL: /* * We ignore offset and size. Must lock the file to * do this, as f_advice is sub-word sized. */ mutex_enter(&fp->f_lock); fp->f_advice = (u_char)advice; mutex_exit(&fp->f_lock); error = 0; break; case POSIX_FADV_WILLNEED: vp = fp->f_vnode; error = uvm_readahead(&vp->v_uobj, offset, endoffset - offset); break; case POSIX_FADV_DONTNEED: vp = fp->f_vnode; /* * Align the region to page boundaries as VOP_PUTPAGES expects * by shrinking it. We shrink instead of expand because we * do not want to deactivate cache outside of the requested * region. It means that if the specified region is smaller * than PAGE_SIZE, we do nothing. */ if (round_page(offset) < trunc_page(endoffset) && offset <= round_page(offset)) { mutex_enter(vp->v_interlock); error = VOP_PUTPAGES(vp, round_page(offset), trunc_page(endoffset), PGO_DEACTIVATE | PGO_CLEANIT); } else { error = 0; } break; case POSIX_FADV_NOREUSE: /* Not implemented yet. */ error = 0; break; default: error = EINVAL; break; } fd_putfile(fd); return error; }
int linux_ioctl_fdio(struct proc *p, struct linux_sys_ioctl_args *uap, register_t *retval) { struct filedesc *fdp; struct file *fp; int error; int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *); u_long com; struct fd_type fparams; struct linux_floppy_struct lflop; struct linux_floppy_drive_struct ldrive; com = (u_long)SCARG(uap, data); fdp = p->p_fd; if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) return (EBADF); FREF(fp); com = SCARG(uap, com); ioctlf = fp->f_ops->fo_ioctl; retval[0] = error = 0; switch (com) { case LINUX_FDMSGON: case LINUX_FDMSGOFF: case LINUX_FDTWADDLE: case LINUX_FDCLRPRM: /* whatever you say */ break; case LINUX_FDPOLLDRVSTAT: /* * Just fill in some innocent defaults. */ memset(&ldrive, 0, sizeof ldrive); ldrive.fd_ref = 1; ldrive.maxblock = 2; ldrive.maxtrack = ldrive.track = 1; ldrive.flags = LINUX_FD_DISK_WRITABLE; error = copyout(&ldrive, SCARG(uap, data), sizeof ldrive); break; case LINUX_FDGETPRM: error = ioctlf(fp, FD_GTYPE, (caddr_t)&fparams, p); if (error != 0) break; lflop.size = fparams.heads * fparams.sectrac * fparams.tracks; lflop.sect = fparams.sectrac; lflop.head = fparams.heads; lflop.track = fparams.tracks; lflop.stretch = fparams.step == 2 ? 1 : 0; lflop.spec1 = fparams.steprate; lflop.gap = fparams.gap1; lflop.fmt_gap = fparams.gap2; lflop.rate = fparams.rate; error = copyout(&lflop, SCARG(uap, data), sizeof lflop); break; case LINUX_FDSETPRM: /* * Should use FDIOCSETFORMAT here, iff its interface * is extended. */ case LINUX_FDDEFPRM: case LINUX_FDFMTBEG: case LINUX_FDFMTTRK: case LINUX_FDFMTEND: case LINUX_FDSETEMSGTRESH: case LINUX_FDFLUSH: case LINUX_FDSETMAXERRS: case LINUX_FDGETMAXERRS: case LINUX_FDGETDRVTYP: case LINUX_FDSETDRVPRM: case LINUX_FDGETDRVPRM: case LINUX_FDGETDRVSTAT: case LINUX_FDRESET: case LINUX_FDGETFDCSTAT: case LINUX_FDWERRORCLR: case LINUX_FDWERRORGET: case LINUX_FDRAWCMD: case LINUX_FDEJECT: default: error = EINVAL; } FRELE(fp, p); return 0; }
/* * We come here in a last attempt to satisfy a Linux ioctl() call */ int linux_machdepioctl(struct lwp *l, const struct linux_sys_ioctl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(u_long) com; syscallarg(void *) data; } */ struct sys_ioctl_args bia; u_long com; int error, error1; #if (NWSDISPLAY > 0) struct vt_mode lvt; struct kbentry kbe; #endif struct linux_hd_geometry hdg; struct linux_hd_big_geometry hdg_big; struct biosdisk_info *bip; file_t *fp; int fd; struct disklabel label, *labp; struct partinfo partp; int (*ioctlf)(struct file *, u_long, void *); u_long start, biostotal, realtotal; u_char heads, sectors; u_int cylinders; struct ioctl_pt pt; fd = SCARG(uap, fd); SCARG(&bia, fd) = fd; SCARG(&bia, data) = SCARG(uap, data); com = SCARG(uap, com); if ((fp = fd_getfile(fd)) == NULL) return (EBADF); switch (com) { #if (NWSDISPLAY > 0) case LINUX_KDGKBMODE: com = KDGKBMODE; break; case LINUX_KDSKBMODE: com = KDSKBMODE; if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW) SCARG(&bia, data) = (void *)K_RAW; break; case LINUX_KIOCSOUND: SCARG(&bia, data) = (void *)(((unsigned long)SCARG(&bia, data)) & 0xffff); /* fall through */ case LINUX_KDMKTONE: com = KDMKTONE; break; case LINUX_KDSETMODE: com = KDSETMODE; break; case LINUX_KDGETMODE: /* KD_* values are equal to the wscons numbers */ com = WSDISPLAYIO_GMODE; break; case LINUX_KDENABIO: com = KDENABIO; break; case LINUX_KDDISABIO: com = KDDISABIO; break; case LINUX_KDGETLED: com = KDGETLED; break; case LINUX_KDSETLED: com = KDSETLED; break; case LINUX_VT_OPENQRY: com = VT_OPENQRY; break; case LINUX_VT_GETMODE: error = fp->f_ops->fo_ioctl(fp, VT_GETMODE, &lvt); if (error != 0) goto out; lvt.relsig = native_to_linux_signo[lvt.relsig]; lvt.acqsig = native_to_linux_signo[lvt.acqsig]; lvt.frsig = native_to_linux_signo[lvt.frsig]; error = copyout(&lvt, SCARG(uap, data), sizeof (lvt)); goto out; case LINUX_VT_SETMODE: error = copyin(SCARG(uap, data), &lvt, sizeof (lvt)); if (error != 0) goto out; lvt.relsig = linux_to_native_signo[lvt.relsig]; lvt.acqsig = linux_to_native_signo[lvt.acqsig]; lvt.frsig = linux_to_native_signo[lvt.frsig]; error = fp->f_ops->fo_ioctl(fp, VT_SETMODE, &lvt); goto out; case LINUX_VT_DISALLOCATE: /* XXX should use WSDISPLAYIO_DELSCREEN */ error = 0; goto out; case LINUX_VT_RELDISP: com = VT_RELDISP; break; case LINUX_VT_ACTIVATE: com = VT_ACTIVATE; break; case LINUX_VT_WAITACTIVE: com = VT_WAITACTIVE; break; case LINUX_VT_GETSTATE: com = VT_GETSTATE; break; case LINUX_KDGKBTYPE: { static const u_int8_t kb101 = KB_101; /* This is what Linux does. */ error = copyout(&kb101, SCARG(uap, data), 1); goto out; } case LINUX_KDGKBENT: /* * The Linux KDGKBENT ioctl is different from the * SYSV original. So we handle it in machdep code. * XXX We should use keyboard mapping information * from wsdisplay, but this would be expensive. */ if ((error = copyin(SCARG(uap, data), &kbe, sizeof(struct kbentry)))) goto out; if (kbe.kb_table >= sizeof(linux_keytabs) / sizeof(u_short *) || kbe.kb_index >= NR_KEYS) { error = EINVAL; goto out; } kbe.kb_value = linux_keytabs[kbe.kb_table][kbe.kb_index]; error = copyout(&kbe, SCARG(uap, data), sizeof(struct kbentry)); goto out; #endif case LINUX_HDIO_GETGEO: case LINUX_HDIO_GETGEO_BIG: /* * Try to mimic Linux behaviour: return the BIOS geometry * if possible (extending its # of cylinders if it's beyond * the 1023 limit), fall back to the MI geometry (i.e. * the real geometry) if not found, by returning an * error. See common/linux_hdio.c */ bip = fd2biosinfo(curproc, fp); ioctlf = fp->f_ops->fo_ioctl; error = ioctlf(fp, DIOCGDEFLABEL, (void *)&label); error1 = ioctlf(fp, DIOCGPART, (void *)&partp); if (error != 0 && error1 != 0) { error = error1; goto out; } labp = error != 0 ? &label : partp.disklab; start = error1 != 0 ? partp.part->p_offset : 0; if (bip != NULL && bip->bi_head != 0 && bip->bi_sec != 0 && bip->bi_cyl != 0) { heads = bip->bi_head; sectors = bip->bi_sec; cylinders = bip->bi_cyl; biostotal = heads * sectors * cylinders; realtotal = labp->d_ntracks * labp->d_nsectors * labp->d_ncylinders; if (realtotal > biostotal) cylinders = realtotal / (heads * sectors); } else { heads = labp->d_ntracks; cylinders = labp->d_ncylinders; sectors = labp->d_nsectors; } if (com == LINUX_HDIO_GETGEO) { hdg.start = start; hdg.heads = heads; hdg.cylinders = cylinders; hdg.sectors = sectors; error = copyout(&hdg, SCARG(uap, data), sizeof hdg); goto out; } else { hdg_big.start = start; hdg_big.heads = heads; hdg_big.cylinders = cylinders; hdg_big.sectors = sectors; error = copyout(&hdg_big, SCARG(uap, data), sizeof hdg_big); goto out; } default: /* * Unknown to us. If it's on a device, just pass it through * using PTIOCLINUX, the device itself might be able to * make some sense of it. * XXX hack: if the function returns EJUSTRETURN, * it has stuffed a sysctl return value in pt.data. */ ioctlf = fp->f_ops->fo_ioctl; pt.com = SCARG(uap, com); pt.data = SCARG(uap, data); error = ioctlf(fp, PTIOCLINUX, &pt); if (error == EJUSTRETURN) { retval[0] = (register_t)pt.data; error = 0; } if (error == ENOTTY) { DPRINTF(("linux_machdepioctl: invalid ioctl %08lx\n", com)); } goto out; } SCARG(&bia, com) = com; error = sys_ioctl(curlwp, &bia, retval); out: fd_putfile(fd); return error; }
int linux32_ioctl_termios(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(netbsd32_u_long) com; syscallarg(netbsd32_charp) data; } */ file_t *fp; u_long com; struct linux32_termio tmplt; struct linux32_termios tmplts; struct termios tmpbts; int idat; struct netbsd32_ioctl_args ia; int error; char tioclinux; int (*bsdioctl)(file_t *, u_long, void *); if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) return (EBADF); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { fd_putfile(SCARG(uap, fd)); error = EBADF; goto out; } bsdioctl = fp->f_ops->fo_ioctl; com = SCARG(uap, com); retval[0] = 0; switch (com) { case LINUX32_TCGETS: error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); if (error) goto out; bsd_termios_to_linux32_termios(&tmpbts, &tmplts); error = copyout(&tmplts, SCARG_P32(uap, data), sizeof tmplts); goto out; case LINUX32_TCSETS: case LINUX32_TCSETSW: case LINUX32_TCSETSF: /* * First fill in all fields, so that we keep the current * values for fields that Linux doesn't know about. */ error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); if (error) goto out; if ((error = copyin(SCARG_P32(uap, data), &tmplts, sizeof tmplts)) != 0) goto out; linux32_termios_to_bsd_termios(&tmplts, &tmpbts); switch (com) { case LINUX32_TCSETS: com = TIOCSETA; break; case LINUX32_TCSETSW: com = TIOCSETAW; break; case LINUX32_TCSETSF: com = TIOCSETAF; break; } error = (*bsdioctl)(fp, com, &tmpbts); goto out; case LINUX32_TCGETA: error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); if (error) goto out; bsd_termios_to_linux32_termio(&tmpbts, &tmplt); error = copyout(&tmplt, SCARG_P32(uap, data), sizeof tmplt); goto out; case LINUX32_TCSETA: case LINUX32_TCSETAW: case LINUX32_TCSETAF: /* * First fill in all fields, so that we keep the current * values for fields that Linux doesn't know about. */ error = (*bsdioctl)(fp, TIOCGETA, &tmpbts); if (error) goto out; if ((error = copyin(SCARG_P32(uap, data), &tmplt, sizeof tmplt)) != 0) goto out; linux32_termio_to_bsd_termios(&tmplt, &tmpbts); switch (com) { case LINUX32_TCSETA: com = TIOCSETA; break; case LINUX32_TCSETAW: com = TIOCSETAW; break; case LINUX32_TCSETAF: com = TIOCSETAF; break; } error = (*bsdioctl)(fp, com, &tmpbts); goto out; case LINUX32_TCFLSH: switch((u_long)SCARG_P32(uap, data)) { case 0: idat = FREAD; break; case 1: idat = FWRITE; break; case 2: idat = 0; break; default: error = EINVAL; goto out; } error = (*bsdioctl)(fp, TIOCFLUSH, &idat); goto out; case LINUX32_TIOCGETD: error = (*bsdioctl)(fp, TIOCGETD, &idat); if (error) goto out; switch (idat) { case TTYDISC: idat = LINUX_N_TTY; break; case SLIPDISC: idat = LINUX_N_SLIP; break; case PPPDISC: idat = LINUX_N_PPP; break; case STRIPDISC: idat = LINUX_N_STRIP; break; /* * Linux does not have the tablet line discipline. */ case TABLDISC: default: idat = -1; /* XXX What should this be? */ break; } error = copyout(&idat, SCARG_P32(uap, data), sizeof idat); goto out; case LINUX32_TIOCSETD: if ((error = copyin(SCARG_P32(uap, data), &idat, sizeof idat)) != 0) goto out; switch (idat) { case LINUX_N_TTY: idat = TTYDISC; break; case LINUX_N_SLIP: idat = SLIPDISC; break; case LINUX_N_PPP: idat = PPPDISC; break; case LINUX_N_STRIP: idat = STRIPDISC; break; /* * We can't handle the mouse line discipline Linux has. */ case LINUX_N_MOUSE: case LINUX_N_AX25: case LINUX_N_X25: case LINUX_N_6PACK: default: error = EINVAL; goto out; } error = (*bsdioctl)(fp, TIOCSETD, &idat); goto out; case LINUX32_TIOCLINUX: if ((error = copyin(SCARG_P32(uap, data), &tioclinux, sizeof tioclinux)) != 0) goto out; switch (tioclinux) { case LINUX_TIOCLINUX_KERNMSG: /* * XXX needed to not fail for some things. Could * try to use TIOCCONS, but the char argument * specifies the VT #, not an fd. */ error = 0; goto out; case LINUX_TIOCLINUX_COPY: case LINUX_TIOCLINUX_PASTE: case LINUX_TIOCLINUX_UNBLANK: case LINUX_TIOCLINUX_LOADLUT: case LINUX_TIOCLINUX_READSHIFT: case LINUX_TIOCLINUX_READMOUSE: case LINUX_TIOCLINUX_VESABLANK: case LINUX_TIOCLINUX_CURCONS: /* could use VT_GETACTIVE */ error = EINVAL; goto out; } break; case LINUX32_TIOCGWINSZ: SCARG(&ia, com) = TIOCGWINSZ; break; case LINUX32_TIOCSWINSZ: SCARG(&ia, com) = TIOCSWINSZ; break; case LINUX32_TIOCGPGRP: SCARG(&ia, com) = TIOCGPGRP; break; case LINUX32_TIOCSPGRP: SCARG(&ia, com) = TIOCSPGRP; break; case LINUX32_FIONREAD: SCARG(&ia, com) = FIONREAD; break; case LINUX32_FIONBIO: SCARG(&ia, com) = FIONBIO; break; case LINUX32_FIOASYNC: SCARG(&ia, com) = FIOASYNC; break; case LINUX32_TIOCEXCL: SCARG(&ia, com) = TIOCEXCL; break; case LINUX32_TIOCNXCL: SCARG(&ia, com) = TIOCNXCL; break; case LINUX32_TIOCCONS: SCARG(&ia, com) = TIOCCONS; break; case LINUX32_TIOCNOTTY: SCARG(&ia, com) = TIOCNOTTY; break; case LINUX32_TCSBRK: idat = (u_long)SCARG_P32(uap, data); if (idat != 0) SCARG(&ia, com) = TIOCDRAIN; else { if ((error = (*bsdioctl)(fp, TIOCSBRK, NULL)) != 0) goto out; error = tsleep(&idat, PZERO | PCATCH, "linux_tcsbrk", hz / 4); if (error == EINTR || error == ERESTART) { (void)(*bsdioctl)(fp, TIOCCBRK, NULL); error = EINTR; } else error = (*bsdioctl)(fp, TIOCCBRK, NULL); goto out; } break; case LINUX32_TIOCMGET: SCARG(&ia, com) = TIOCMGET; break; case LINUX32_TIOCMSET: SCARG(&ia, com) = TIOCMSET; break; case LINUX32_TIOCMBIC: SCARG(&ia, com) = TIOCMBIC; break; case LINUX32_TIOCMBIS: SCARG(&ia, com) = TIOCMBIS; break; #ifdef LINUX32_TIOCGPTN case LINUX32_TIOCGPTN: #ifndef NO_DEV_PTM { struct ptmget ptm; error = (*bsdioctl)(fp, TIOCPTSNAME, &ptm); if (error != 0) goto out; error = copyout(&ptm.sfd, SCARG_P32(uap, data), sizeof(ptm.sfd)); goto out; } #endif /* NO_DEV_PTM */ #endif /* LINUX32_TIOCGPTN */ default: error = EINVAL; goto out; } SCARG(&ia, fd) = SCARG(uap, fd); SCARG(&ia, data) = SCARG(uap, data); error = netbsd32_ioctl(curlwp, &ia, retval); out: fd_putfile(SCARG(uap, fd)); return error; }
/* ARGSUSED */ int sys_execve(struct proc *p, void *v, register_t *retval) { struct sys_execve_args /* { syscallarg(const char *) path; syscallarg(char *const *) argp; syscallarg(char *const *) envp; } */ *uap = v; int error; struct exec_package pack; struct nameidata nid; struct vattr attr; struct ucred *cred = p->p_ucred; char *argp; char * const *cpp, *dp, *sp; #ifdef KTRACE char *env_start; #endif struct process *pr = p->p_p; long argc, envc; size_t len, sgap; #ifdef MACHINE_STACK_GROWS_UP size_t slen; #endif char *stack; struct ps_strings arginfo; struct vmspace *vm = pr->ps_vmspace; char **tmpfap; extern struct emul emul_native; #if NSYSTRACE > 0 int wassugid = ISSET(pr->ps_flags, PS_SUGID | PS_SUGIDEXEC); size_t pathbuflen; #endif char *pathbuf = NULL; struct vnode *otvp; /* get other threads to stop */ if ((error = single_thread_set(p, SINGLE_UNWIND, 1))) return (error); /* * Cheap solution to complicated problems. * Mark this process as "leave me alone, I'm execing". */ atomic_setbits_int(&pr->ps_flags, PS_INEXEC); #if NSYSTRACE > 0 if (ISSET(p->p_flag, P_SYSTRACE)) { systrace_execve0(p); pathbuf = pool_get(&namei_pool, PR_WAITOK); error = copyinstr(SCARG(uap, path), pathbuf, MAXPATHLEN, &pathbuflen); if (error != 0) goto clrflag; } #endif if (pathbuf != NULL) { NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, p); } else { NDINIT(&nid, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), p); } /* * initialize the fields of the exec package. */ if (pathbuf != NULL) pack.ep_name = pathbuf; else pack.ep_name = (char *)SCARG(uap, path); pack.ep_hdr = malloc(exec_maxhdrsz, M_EXEC, M_WAITOK); pack.ep_hdrlen = exec_maxhdrsz; pack.ep_hdrvalid = 0; pack.ep_ndp = &nid; pack.ep_interp = NULL; pack.ep_emul_arg = NULL; VMCMDSET_INIT(&pack.ep_vmcmds); pack.ep_vap = &attr; pack.ep_emul = &emul_native; pack.ep_flags = 0; /* see if we can run it. */ if ((error = check_exec(p, &pack)) != 0) { goto freehdr; } /* XXX -- THE FOLLOWING SECTION NEEDS MAJOR CLEANUP */ /* allocate an argument buffer */ argp = km_alloc(NCARGS, &kv_exec, &kp_pageable, &kd_waitok); #ifdef DIAGNOSTIC if (argp == NULL) panic("execve: argp == NULL"); #endif dp = argp; argc = 0; /* copy the fake args list, if there's one, freeing it as we go */ if (pack.ep_flags & EXEC_HASARGL) { tmpfap = pack.ep_fa; while (*tmpfap != NULL) { char *cp; cp = *tmpfap; while (*cp) *dp++ = *cp++; *dp++ = '\0'; free(*tmpfap, M_EXEC, 0); tmpfap++; argc++; } free(pack.ep_fa, M_EXEC, 0); pack.ep_flags &= ~EXEC_HASARGL; } /* Now get argv & environment */ if (!(cpp = SCARG(uap, argp))) { error = EFAULT; goto bad; } if (pack.ep_flags & EXEC_SKIPARG) cpp++; while (1) { len = argp + ARG_MAX - dp; if ((error = copyin(cpp, &sp, sizeof(sp))) != 0) goto bad; if (!sp) break; if ((error = copyinstr(sp, dp, len, &len)) != 0) { if (error == ENAMETOOLONG) error = E2BIG; goto bad; } dp += len; cpp++; argc++; } /* must have at least one argument */ if (argc == 0) { error = EINVAL; goto bad; } #ifdef KTRACE if (KTRPOINT(p, KTR_EXECARGS)) ktrexec(p, KTR_EXECARGS, argp, dp - argp); #endif envc = 0; /* environment does not need to be there */ if ((cpp = SCARG(uap, envp)) != NULL ) { #ifdef KTRACE env_start = dp; #endif while (1) { len = argp + ARG_MAX - dp; if ((error = copyin(cpp, &sp, sizeof(sp))) != 0) goto bad; if (!sp) break; if ((error = copyinstr(sp, dp, len, &len)) != 0) { if (error == ENAMETOOLONG) error = E2BIG; goto bad; } dp += len; cpp++; envc++; } #ifdef KTRACE if (KTRPOINT(p, KTR_EXECENV)) ktrexec(p, KTR_EXECENV, env_start, dp - env_start); #endif } dp = (char *)(((long)dp + _STACKALIGNBYTES) & ~_STACKALIGNBYTES); sgap = STACKGAPLEN; /* * If we have enabled random stackgap, the stack itself has already * been moved from a random location, but is still aligned to a page * boundary. Provide the lower bits of random placement now. */ if (stackgap_random != 0) { sgap += arc4random() & PAGE_MASK; sgap = (sgap + _STACKALIGNBYTES) & ~_STACKALIGNBYTES; } /* Now check if args & environ fit into new stack */ len = ((argc + envc + 2 + pack.ep_emul->e_arglen) * sizeof(char *) + sizeof(long) + dp + sgap + sizeof(struct ps_strings)) - argp; len = (len + _STACKALIGNBYTES) &~ _STACKALIGNBYTES; if (len > pack.ep_ssize) { /* in effect, compare to initial limit */ error = ENOMEM; goto bad; } /* adjust "active stack depth" for process VSZ */ pack.ep_ssize = len; /* maybe should go elsewhere, but... */ /* * we're committed: any further errors will kill the process, so * kill the other threads now. */ single_thread_set(p, SINGLE_EXIT, 0); /* * Prepare vmspace for remapping. Note that uvmspace_exec can replace * pr_vmspace! */ uvmspace_exec(p, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS); vm = pr->ps_vmspace; /* Now map address space */ vm->vm_taddr = (char *)trunc_page(pack.ep_taddr); vm->vm_tsize = atop(round_page(pack.ep_taddr + pack.ep_tsize) - trunc_page(pack.ep_taddr)); vm->vm_daddr = (char *)trunc_page(pack.ep_daddr); vm->vm_dsize = atop(round_page(pack.ep_daddr + pack.ep_dsize) - trunc_page(pack.ep_daddr)); vm->vm_dused = 0; vm->vm_ssize = atop(round_page(pack.ep_ssize)); vm->vm_maxsaddr = (char *)pack.ep_maxsaddr; vm->vm_minsaddr = (char *)pack.ep_minsaddr; /* create the new process's VM space by running the vmcmds */ #ifdef DIAGNOSTIC if (pack.ep_vmcmds.evs_used == 0) panic("execve: no vmcmds"); #endif error = exec_process_vmcmds(p, &pack); /* if an error happened, deallocate and punt */ if (error) goto exec_abort; /* old "stackgap" is gone now */ pr->ps_stackgap = 0; #ifdef MACHINE_STACK_GROWS_UP pr->ps_strings = (vaddr_t)vm->vm_maxsaddr + sgap; if (uvm_map_protect(&vm->vm_map, (vaddr_t)vm->vm_maxsaddr, trunc_page(pr->ps_strings), PROT_NONE, TRUE)) goto exec_abort; #else pr->ps_strings = (vaddr_t)vm->vm_minsaddr - sizeof(arginfo) - sgap; if (uvm_map_protect(&vm->vm_map, round_page(pr->ps_strings + sizeof(arginfo)), (vaddr_t)vm->vm_minsaddr, PROT_NONE, TRUE)) goto exec_abort; #endif /* remember information about the process */ arginfo.ps_nargvstr = argc; arginfo.ps_nenvstr = envc; #ifdef MACHINE_STACK_GROWS_UP stack = (char *)vm->vm_maxsaddr + sizeof(arginfo) + sgap; slen = len - sizeof(arginfo) - sgap; #else stack = (char *)(vm->vm_minsaddr - len); #endif /* Now copy argc, args & environ to new stack */ if (!(*pack.ep_emul->e_copyargs)(&pack, &arginfo, stack, argp)) goto exec_abort; /* copy out the process's ps_strings structure */ if (copyout(&arginfo, (char *)pr->ps_strings, sizeof(arginfo))) goto exec_abort; stopprofclock(pr); /* stop profiling */ fdcloseexec(p); /* handle close on exec */ execsigs(p); /* reset caught signals */ TCB_SET(p, NULL); /* reset the TCB address */ pr->ps_kbind_addr = 0; /* reset the kbind bits */ pr->ps_kbind_cookie = 0; /* set command name & other accounting info */ memset(p->p_comm, 0, sizeof(p->p_comm)); len = min(nid.ni_cnd.cn_namelen, MAXCOMLEN); memcpy(p->p_comm, nid.ni_cnd.cn_nameptr, len); pr->ps_acflag &= ~AFORK; /* record proc's vnode, for use by sysctl */ otvp = pr->ps_textvp; vref(pack.ep_vp); pr->ps_textvp = pack.ep_vp; if (otvp) vrele(otvp); atomic_setbits_int(&pr->ps_flags, PS_EXEC); if (pr->ps_flags & PS_PPWAIT) { atomic_clearbits_int(&pr->ps_flags, PS_PPWAIT); atomic_clearbits_int(&pr->ps_pptr->ps_flags, PS_ISPWAIT); wakeup(pr->ps_pptr); } /* * If process does execve() while it has a mismatched real, * effective, or saved uid/gid, we set PS_SUGIDEXEC. */ if (cred->cr_uid != cred->cr_ruid || cred->cr_uid != cred->cr_svuid || cred->cr_gid != cred->cr_rgid || cred->cr_gid != cred->cr_svgid) atomic_setbits_int(&pr->ps_flags, PS_SUGIDEXEC); else atomic_clearbits_int(&pr->ps_flags, PS_SUGIDEXEC); atomic_clearbits_int(&pr->ps_flags, PS_TAMED); tame_dropwpaths(pr); /* * deal with set[ug]id. * MNT_NOEXEC has already been used to disable s[ug]id. */ if ((attr.va_mode & (VSUID | VSGID)) && proc_cansugid(p)) { int i; atomic_setbits_int(&pr->ps_flags, PS_SUGID|PS_SUGIDEXEC); #ifdef KTRACE /* * If process is being ktraced, turn off - unless * root set it. */ if (pr->ps_tracevp && !(pr->ps_traceflag & KTRFAC_ROOT)) ktrcleartrace(pr); #endif p->p_ucred = cred = crcopy(cred); if (attr.va_mode & VSUID) cred->cr_uid = attr.va_uid; if (attr.va_mode & VSGID) cred->cr_gid = attr.va_gid; /* * For set[ug]id processes, a few caveats apply to * stdin, stdout, and stderr. */ error = 0; fdplock(p->p_fd); for (i = 0; i < 3; i++) { struct file *fp = NULL; /* * NOTE - This will never return NULL because of * immature fds. The file descriptor table is not * shared because we're suid. */ fp = fd_getfile(p->p_fd, i); /* * Ensure that stdin, stdout, and stderr are already * allocated. We do not want userland to accidentally * allocate descriptors in this range which has implied * meaning to libc. */ if (fp == NULL) { short flags = FREAD | (i == 0 ? 0 : FWRITE); struct vnode *vp; int indx; if ((error = falloc(p, &fp, &indx)) != 0) break; #ifdef DIAGNOSTIC if (indx != i) panic("sys_execve: falloc indx != i"); #endif if ((error = cdevvp(getnulldev(), &vp)) != 0) { fdremove(p->p_fd, indx); closef(fp, p); break; } if ((error = VOP_OPEN(vp, flags, cred, p)) != 0) { fdremove(p->p_fd, indx); closef(fp, p); vrele(vp); break; } if (flags & FWRITE) vp->v_writecount++; fp->f_flag = flags; fp->f_type = DTYPE_VNODE; fp->f_ops = &vnops; fp->f_data = (caddr_t)vp; FILE_SET_MATURE(fp, p); } } fdpunlock(p->p_fd); if (error) goto exec_abort; } else atomic_clearbits_int(&pr->ps_flags, PS_SUGID); /* * Reset the saved ugids and update the process's copy of the * creds if the creds have been changed */ if (cred->cr_uid != cred->cr_svuid || cred->cr_gid != cred->cr_svgid) { /* make sure we have unshared ucreds */ p->p_ucred = cred = crcopy(cred); cred->cr_svuid = cred->cr_uid; cred->cr_svgid = cred->cr_gid; } if (pr->ps_ucred != cred) { struct ucred *ocred; ocred = pr->ps_ucred; crhold(cred); pr->ps_ucred = cred; crfree(ocred); } if (pr->ps_flags & PS_SUGIDEXEC) { int i, s = splclock(); timeout_del(&pr->ps_realit_to); for (i = 0; i < nitems(pr->ps_timer); i++) { timerclear(&pr->ps_timer[i].it_interval); timerclear(&pr->ps_timer[i].it_value); } splx(s); } /* reset CPU time usage for the thread, but not the process */ timespecclear(&p->p_tu.tu_runtime); p->p_tu.tu_uticks = p->p_tu.tu_sticks = p->p_tu.tu_iticks = 0; km_free(argp, NCARGS, &kv_exec, &kp_pageable); pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf); vn_close(pack.ep_vp, FREAD, cred, p); /* * notify others that we exec'd */ KNOTE(&pr->ps_klist, NOTE_EXEC); /* setup new registers and do misc. setup. */ if (pack.ep_emul->e_fixup != NULL) { if ((*pack.ep_emul->e_fixup)(p, &pack) != 0) goto free_pack_abort; } #ifdef MACHINE_STACK_GROWS_UP (*pack.ep_emul->e_setregs)(p, &pack, (u_long)stack + slen, retval); #else (*pack.ep_emul->e_setregs)(p, &pack, (u_long)stack, retval); #endif /* map the process's signal trampoline code */ if (exec_sigcode_map(pr, pack.ep_emul)) goto free_pack_abort; #ifdef __HAVE_EXEC_MD_MAP /* perform md specific mappings that process might need */ if (exec_md_map(p, &pack)) goto free_pack_abort; #endif if (pr->ps_flags & PS_TRACED) psignal(p, SIGTRAP); free(pack.ep_hdr, M_EXEC, pack.ep_hdrlen); /* * Call emulation specific exec hook. This can setup per-process * p->p_emuldata or do any other per-process stuff an emulation needs. * * If we are executing process of different emulation than the * original forked process, call e_proc_exit() of the old emulation * first, then e_proc_exec() of new emulation. If the emulation is * same, the exec hook code should deallocate any old emulation * resources held previously by this process. */ if (pr->ps_emul && pr->ps_emul->e_proc_exit && pr->ps_emul != pack.ep_emul) (*pr->ps_emul->e_proc_exit)(p); p->p_descfd = 255; if ((pack.ep_flags & EXEC_HASFD) && pack.ep_fd < 255) p->p_descfd = pack.ep_fd; /* * Call exec hook. Emulation code may NOT store reference to anything * from &pack. */ if (pack.ep_emul->e_proc_exec) (*pack.ep_emul->e_proc_exec)(p, &pack); #if defined(KTRACE) && defined(COMPAT_LINUX) /* update ps_emul, but don't ktrace it if native-execing-native */ if (pr->ps_emul != pack.ep_emul || pack.ep_emul != &emul_native) { pr->ps_emul = pack.ep_emul; if (KTRPOINT(p, KTR_EMUL)) ktremul(p); } #else /* update ps_emul, the old value is no longer needed */ pr->ps_emul = pack.ep_emul; #endif atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); single_thread_clear(p, P_SUSPSIG); #if NSYSTRACE > 0 if (ISSET(p->p_flag, P_SYSTRACE) && wassugid && !ISSET(pr->ps_flags, PS_SUGID | PS_SUGIDEXEC)) systrace_execve1(pathbuf, p); #endif if (pathbuf != NULL) pool_put(&namei_pool, pathbuf); return (0); bad: /* free the vmspace-creation commands, and release their references */ kill_vmcmds(&pack.ep_vmcmds); /* kill any opened file descriptor, if necessary */ if (pack.ep_flags & EXEC_HASFD) { pack.ep_flags &= ~EXEC_HASFD; fdplock(p->p_fd); (void) fdrelease(p, pack.ep_fd); fdpunlock(p->p_fd); } if (pack.ep_interp != NULL) pool_put(&namei_pool, pack.ep_interp); if (pack.ep_emul_arg != NULL) free(pack.ep_emul_arg, M_TEMP, pack.ep_emul_argsize); /* close and put the exec'd file */ vn_close(pack.ep_vp, FREAD, cred, p); pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf); km_free(argp, NCARGS, &kv_exec, &kp_pageable); freehdr: free(pack.ep_hdr, M_EXEC, pack.ep_hdrlen); #if NSYSTRACE > 0 clrflag: #endif atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); single_thread_clear(p, P_SUSPSIG); if (pathbuf != NULL) pool_put(&namei_pool, pathbuf); return (error); exec_abort: /* * the old process doesn't exist anymore. exit gracefully. * get rid of the (new) address space we have created, if any, get rid * of our namei data and vnode, and exit noting failure */ uvm_deallocate(&vm->vm_map, VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS - VM_MIN_ADDRESS); if (pack.ep_interp != NULL) pool_put(&namei_pool, pack.ep_interp); if (pack.ep_emul_arg != NULL) free(pack.ep_emul_arg, M_TEMP, pack.ep_emul_argsize); pool_put(&namei_pool, nid.ni_cnd.cn_pnbuf); vn_close(pack.ep_vp, FREAD, cred, p); km_free(argp, NCARGS, &kv_exec, &kp_pageable); free_pack_abort: free(pack.ep_hdr, M_EXEC, pack.ep_hdrlen); if (pathbuf != NULL) pool_put(&namei_pool, pathbuf); exit1(p, W_EXITCODE(0, SIGABRT), EXIT_NORMAL); /* NOTREACHED */ atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); return (0); }
/* * Most ioctl command are just converted to their NetBSD values, * and passed on. The ones that take structure pointers and (flag) * values need some massaging. */ int linux_sys_ioctl(struct lwp *l, const struct linux_sys_ioctl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(u_long) com; syscallarg(void *) data; } */ int error; switch (LINUX_IOCGROUP(SCARG(uap, com))) { case 'M': switch(SCARG(uap, com)) { case LINUX_MEGARAID_CMD: case LINUX_MEGARAID_GET_AEN: { struct sys_ioctl_args ua; u_long com = 0; if (SCARG(uap, com) & IOC_IN) com |= IOC_OUT; if (SCARG(uap, com) & IOC_OUT) com |= IOC_IN; SCARG(&ua, fd) = SCARG(uap, fd); SCARG(&ua, com) = SCARG(uap, com); SCARG(&ua, com) &= ~IOC_DIRMASK; SCARG(&ua, com) |= com; SCARG(&ua, data) = SCARG(uap, data); error = sys_ioctl(l, (const void *)&ua, retval); break; } default: error = oss_ioctl_mixer(l, LINUX_TO_OSS(uap), retval); break; } break; case 'Q': error = oss_ioctl_sequencer(l, LINUX_TO_OSS(uap), retval); break; case 'P': error = oss_ioctl_audio(l, LINUX_TO_OSS(uap), retval); break; case 'V': /* video4linux2 */ case 'd': /* drm */ { struct sys_ioctl_args ua; u_long com = 0; if (SCARG(uap, com) & IOC_IN) com |= IOC_OUT; if (SCARG(uap, com) & IOC_OUT) com |= IOC_IN; SCARG(&ua, fd) = SCARG(uap, fd); SCARG(&ua, com) = SCARG(uap, com); SCARG(&ua, com) &= ~IOC_DIRMASK; SCARG(&ua, com) |= com; SCARG(&ua, data) = SCARG(uap, data); error = sys_ioctl(l, (const void *)&ua, retval); break; } case 'r': /* VFAT ioctls; not yet supported */ error = ENOSYS; break; case 'S': error = linux_ioctl_cdrom(l, uap, retval); break; case 't': case 'f': error = linux_ioctl_termios(l, uap, retval); break; case 'm': error = linux_ioctl_mtio(l, uap, retval); break; case 'T': { #if NSEQUENCER > 0 /* XXX XAX 2x check this. */ /* * Both termios and the MIDI sequencer use 'T' to identify * the ioctl, so we have to differentiate them in another * way. We do it by indexing in the cdevsw with the major * device number and check if that is the sequencer entry. */ bool is_sequencer = false; struct file *fp; struct vnode *vp; struct vattr va; extern const struct cdevsw sequencer_cdevsw; if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) return EBADF; if (fp->f_type == DTYPE_VNODE && (vp = (struct vnode *)fp->f_data) != NULL && vp->v_type == VCHR) { vn_lock(vp, LK_SHARED | LK_RETRY); error = VOP_GETATTR(vp, &va, l->l_cred); VOP_UNLOCK(vp); if (error == 0 && cdevsw_lookup(va.va_rdev) == &sequencer_cdevsw) is_sequencer = true; } if (is_sequencer) { error = oss_ioctl_sequencer(l, (const void *)LINUX_TO_OSS(uap), retval); } else { error = linux_ioctl_termios(l, uap, retval); } fd_putfile(SCARG(uap, fd)); #else error = linux_ioctl_termios(l, uap, retval); #endif } break; case '"': error = linux_ioctl_sg(l, uap, retval); break; case 0x89: error = linux_ioctl_socket(l, uap, retval); break; case 0x03: error = linux_ioctl_hdio(l, uap, retval); break; case 0x02: error = linux_ioctl_fdio(l, uap, retval); break; case 0x12: error = linux_ioctl_blkio(l, uap, retval); break; default: error = linux_machdepioctl(l, uap, retval); break; } if (error == EPASSTHROUGH) { /* * linux returns EINVAL or ENOTTY for not supported ioctls. */ error = EINVAL; } return error; }
/* * We come here in a last attempt to satisfy a Linux ioctl() call */ int linux_machdepioctl(struct proc *p, void *v, register_t *retval) { struct linux_sys_ioctl_args /* { syscallarg(int) fd; syscallarg(u_long) com; syscallarg(caddr_t) data; } */ *uap = v; struct sys_ioctl_args bia; u_long com; int error; #if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL)) struct vt_mode lvt; caddr_t bvtp, sg; #endif struct filedesc *fdp; struct file *fp; int fd; int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *); struct ioctl_pt pt; fd = SCARG(uap, fd); SCARG(&bia, fd) = SCARG(uap, fd); SCARG(&bia, data) = SCARG(uap, data); com = SCARG(uap, com); fdp = p->p_fd; if ((fp = fd_getfile(fdp, fd)) == NULL) return (EBADF); switch (com) { #if (NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL)) case LINUX_KDGKBMODE: com = KDGKBMODE; break; case LINUX_KDSKBMODE: com = KDSKBMODE; if ((unsigned)SCARG(uap, data) == LINUX_K_MEDIUMRAW) SCARG(&bia, data) = (caddr_t)K_RAW; break; case LINUX_KIOCSOUND: SCARG(&bia, data) = (caddr_t)(((unsigned long)SCARG(&bia, data)) & 0xffff); /* FALLTHROUGH */ case LINUX_KDMKTONE: com = KDMKTONE; break; case LINUX_KDSETMODE: com = KDSETMODE; break; case LINUX_KDGETMODE: #if NWSDISPLAY > 0 && defined(WSDISPLAY_COMPAT_USL) com = WSDISPLAYIO_GMODE; #else com = KDGETMODE; #endif break; case LINUX_KDENABIO: com = KDENABIO; break; case LINUX_KDDISABIO: com = KDDISABIO; break; case LINUX_KDGETLED: com = KDGETLED; break; case LINUX_KDSETLED: com = KDSETLED; break; case LINUX_VT_OPENQRY: com = VT_OPENQRY; break; case LINUX_VT_GETMODE: { int sig; SCARG(&bia, com) = VT_GETMODE; if ((error = sys_ioctl(p, &bia, retval))) return error; if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, sizeof (struct vt_mode)))) return error; /* We need to bounds check here in case there is a race with another thread */ if ((error = bsd_to_linux_signal(lvt.relsig, &sig))) return error; lvt.relsig = sig; if ((error = bsd_to_linux_signal(lvt.acqsig, &sig))) return error; lvt.acqsig = sig; if ((error = bsd_to_linux_signal(lvt.frsig, &sig))) return error; lvt.frsig = sig; return copyout((caddr_t)&lvt, SCARG(uap, data), sizeof (struct vt_mode)); } case LINUX_VT_SETMODE: { int sig; com = VT_SETMODE; if ((error = copyin(SCARG(uap, data), (caddr_t)&lvt, sizeof (struct vt_mode)))) return error; if ((error = linux_to_bsd_signal(lvt.relsig, &sig))) return error; lvt.relsig = sig; if ((error = linux_to_bsd_signal(lvt.acqsig, &sig))) return error; lvt.acqsig = sig; if ((error = linux_to_bsd_signal(lvt.frsig, &sig))) return error; lvt.frsig = sig; sg = stackgap_init(p->p_emul); bvtp = stackgap_alloc(&sg, sizeof (struct vt_mode)); if ((error = copyout(&lvt, bvtp, sizeof (struct vt_mode)))) return error; SCARG(&bia, data) = bvtp; break; } case LINUX_VT_DISALLOCATE: /* XXX should use WSDISPLAYIO_DELSCREEN */ return 0; case LINUX_VT_RELDISP: com = VT_RELDISP; break; case LINUX_VT_ACTIVATE: com = VT_ACTIVATE; break; case LINUX_VT_WAITACTIVE: com = VT_WAITACTIVE; break; case LINUX_VT_GETSTATE: com = VT_GETSTATE; break; case LINUX_KDGKBTYPE: { char tmp = KB_101; /* This is what Linux does */ return copyout(&tmp, SCARG(uap, data), sizeof(char)); } #endif default: /* * Unknown to us. If it's on a device, just pass it through * using PTIOCLINUX, the device itself might be able to * make some sense of it. * XXX hack: if the function returns EJUSTRETURN, * it has stuffed a sysctl return value in pt.data. */ FREF(fp); ioctlf = fp->f_ops->fo_ioctl; pt.com = SCARG(uap, com); pt.data = SCARG(uap, data); error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p); FRELE(fp); if (error == EJUSTRETURN) { retval[0] = (register_t)pt.data; error = 0; } if (error == ENOTTY) printf("linux_machdepioctl: invalid ioctl %08lx\n", com); return (error); } SCARG(&bia, com) = com; return sys_ioctl(p, &bia, retval); }
/* * The file control system call. */ int sys_fcntl(struct lwp *l, const struct sys_fcntl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(int) cmd; syscallarg(void *) arg; } */ int fd, i, tmp, error, cmd, newmin; filedesc_t *fdp; file_t *fp; struct flock fl; bool cloexec = false; fd = SCARG(uap, fd); cmd = SCARG(uap, cmd); fdp = l->l_fd; error = 0; switch (cmd) { case F_CLOSEM: if (fd < 0) return EBADF; while ((i = fdp->fd_lastfile) >= fd) { if (fd_getfile(i) == NULL) { /* Another thread has updated. */ continue; } fd_close(i); } return 0; case F_MAXFD: *retval = fdp->fd_lastfile; return 0; case F_SETLKW: case F_SETLK: case F_GETLK: error = copyin(SCARG(uap, arg), &fl, sizeof(fl)); if (error) return error; error = do_fcntl_lock(fd, cmd, &fl); if (cmd == F_GETLK && error == 0) error = copyout(&fl, SCARG(uap, arg), sizeof(fl)); return error; default: /* Handled below */ break; } if ((fp = fd_getfile(fd)) == NULL) return (EBADF); if ((cmd & F_FSCTL)) { error = fcntl_forfs(fd, fp, cmd, SCARG(uap, arg)); fd_putfile(fd); return error; } switch (cmd) { case F_DUPFD_CLOEXEC: cloexec = true; /*FALLTHROUGH*/ case F_DUPFD: newmin = (long)SCARG(uap, arg); if ((u_int)newmin >= l->l_proc->p_rlimit[RLIMIT_NOFILE].rlim_cur || (u_int)newmin >= maxfiles) { fd_putfile(fd); return EINVAL; } error = fd_dup(fp, newmin, &i, cloexec); *retval = i; break; case F_GETFD: *retval = fdp->fd_dt->dt_ff[fd]->ff_exclose; break; case F_SETFD: fd_set_exclose(l, fd, ((long)SCARG(uap, arg) & FD_CLOEXEC) != 0); break; case F_GETNOSIGPIPE: *retval = (fp->f_flag & FNOSIGPIPE) != 0; break; case F_SETNOSIGPIPE: if (SCARG(uap, arg)) atomic_or_uint(&fp->f_flag, FNOSIGPIPE); else atomic_and_uint(&fp->f_flag, ~FNOSIGPIPE); *retval = 0; break; case F_GETFL: *retval = OFLAGS(fp->f_flag); break; case F_SETFL: /* XXX not guaranteed to be atomic. */ tmp = FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS; error = (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &tmp); if (error) break; i = tmp ^ fp->f_flag; if (i & FNONBLOCK) { int flgs = tmp & FNONBLOCK; error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, &flgs); if (error) { (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &fp->f_flag); break; } } if (i & FASYNC) { int flgs = tmp & FASYNC; error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, &flgs); if (error) { if (i & FNONBLOCK) { tmp = fp->f_flag & FNONBLOCK; (void)(*fp->f_ops->fo_ioctl)(fp, FIONBIO, &tmp); } (*fp->f_ops->fo_fcntl)(fp, F_SETFL, &fp->f_flag); break; } } fp->f_flag = (fp->f_flag & ~FCNTLFLAGS) | tmp; break; case F_GETOWN: error = (*fp->f_ops->fo_ioctl)(fp, FIOGETOWN, &tmp); *retval = tmp; break; case F_SETOWN: tmp = (int)(uintptr_t) SCARG(uap, arg); error = (*fp->f_ops->fo_ioctl)(fp, FIOSETOWN, &tmp); break; default: error = EINVAL; } fd_putfile(fd); return (error); }
/* * main ioctl syscall. * * ok, here we are in the biggy. we have to do fix ups depending * on the ioctl command before and afterwards. */ int netbsd32_ioctl(struct lwp *l, const struct netbsd32_ioctl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(netbsd32_u_long) com; syscallarg(netbsd32_voidp) data; } */ struct proc *p = l->l_proc; struct file *fp; struct filedesc *fdp; u_long com; int error = 0; u_int size, size32; void *data, *memp = NULL; void *data32, *memp32 = NULL; unsigned fd; fdfile_t *ff; int tmp; #define STK_PARAMS 128 u_long stkbuf[STK_PARAMS/sizeof(u_long)]; u_long stkbuf32[STK_PARAMS/sizeof(u_long)]; /* * we need to translate some commands (_IOW) before calling sys_ioctl, * some after (_IOR), and some both (_IOWR). */ #if 0 { char *dirs[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!", "INOUT", "VOID|IN|OUT!" }; printf("netbsd32_ioctl(%d, %x, %x): %s group %c base %d len %d\n", SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data), dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)], IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)), IOCPARM_LEN(SCARG(uap, com))); } #endif fdp = p->p_fd; fd = SCARG(uap, fd); if ((fp = fd_getfile(fd)) == NULL) return (EBADF); if ((fp->f_flag & (FREAD | FWRITE)) == 0) { error = EBADF; goto out; } ff = fdp->fd_ofiles[SCARG(uap, fd)]; switch (com = SCARG(uap, com)) { case FIOCLEX: ff->ff_exclose = true; fdp->fd_exclose = true; goto out; case FIONCLEX: ff->ff_exclose = false; goto out; } /* * Interpret high order word to find amount of data to be * copied to/from the user's address space. */ size = 0; size32 = IOCPARM_LEN(com); if (size32 > IOCPARM_MAX) { error = ENOTTY; goto out; } if (size32 > sizeof(stkbuf)) { memp32 = kmem_alloc((size_t)size32, KM_SLEEP); data32 = memp32; } else data32 = (void *)stkbuf32; if (com&IOC_IN) { if (size32) { error = copyin(SCARG_P32(uap, data), data32, size32); if (error) { if (memp32) kmem_free(memp32, (size_t)size32); goto out; } ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data), size32, 0); } else *(void **)data32 = SCARG_P32(uap, data); } else if ((com&IOC_OUT) && size32) /* * Zero the buffer so the user always * gets back something deterministic. */ memset(data32, 0, size32); else if (com&IOC_VOID) *(void **)data32 = SCARG_P32(uap, data); /* * convert various structures, pointers, and other objects that * change size from 32 bit -> 64 bit, for all ioctl commands. */ switch (SCARG(uap, com)) { case FIONBIO: mutex_enter(&fp->f_lock); if ((tmp = *(int *)data32) != 0) fp->f_flag |= FNONBLOCK; else fp->f_flag &= ~FNONBLOCK; mutex_exit(&fp->f_lock); error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (void *)&tmp); break; case FIOASYNC: mutex_enter(&fp->f_lock); if ((tmp = *(int *)data32) != 0) fp->f_flag |= FASYNC; else fp->f_flag &= ~FASYNC; mutex_exit(&fp->f_lock); error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (void *)&tmp); break; case DIOCGPART32: IOCTL_STRUCT_CONV_TO(DIOCGPART, partinfo); #if 0 /* not implemented by anything */ case DIOCRFORMAT32: IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op); case DIOCWFORMAT32: IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op); #endif /* * only a few ifreq syscalls need conversion and those are * all driver specific... XXX */ #if 0 case SIOCGADDRROM3232: IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq); case SIOCGCHIPID32: IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq); case SIOCSIFADDR32: IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq); case OSIOCGIFADDR32: IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq); case SIOCGIFADDR32: IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq); case SIOCSIFDSTADDR32: IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq); case OSIOCGIFDSTADDR32: IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq); case SIOCGIFDSTADDR32: IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq); case OSIOCGIFBRDADDR32: IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq); case SIOCGIFBRDADDR32: IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq); case SIOCSIFBRDADDR32: IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq); case OSIOCGIFNETMASK32: IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq); case SIOCGIFNETMASK32: IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq); case SIOCSIFNETMASK32: IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq); case SIOCGIFMETRIC32: IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq); case SIOCSIFMETRIC32: IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq); case SIOCDIFADDR32: IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq); case SIOCADDMULTI32: IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq); case SIOCDELMULTI32: IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq); case SIOCSIFMEDIA32: IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq); case SIOCSIFMTU32: IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq); case SIOCGIFMTU32: IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq); case BIOCGETIF32: IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq); case BIOCSETIF32: IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq); case SIOCPHASE132: IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq); case SIOCPHASE232: IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq); #endif case OOSIOCGIFCONF32: IOCTL_STRUCT_CONV_TO(OOSIOCGIFCONF, ifconf); case OSIOCGIFCONF32: IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf); case SIOCGIFCONF32: IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf); case SIOCGIFFLAGS32: IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq); case SIOCSIFFLAGS32: IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq); case SIOCGIFMEDIA32: IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq); case SIOCSDRVSPEC32: IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv); case SIOCGETVIFCNT32: IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req); case SIOCGETSGCNT32: IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req); default: #ifdef NETBSD32_MD_IOCTL error = netbsd32_md_ioctl(fp, com, data32, l); #else error = (*fp->f_ops->fo_ioctl)(fp, com, data32); #endif break; } if (error == EPASSTHROUGH) error = ENOTTY; /* * Copy any data to user, size was * already set and checked above. */ if (error == 0 && (com&IOC_OUT) && size32) { error = copyout(data32, SCARG_P32(uap, data), size32); ktrgenio(fd, UIO_READ, SCARG_P32(uap, data), size32, error); } /* if we malloced data, free it here */ if (memp32) kmem_free(memp32, (size_t)size32); if (memp) kmem_free(memp, (size_t)size); out: fd_putfile(fd); return (error); }
int do_fcntl_lock(int fd, int cmd, struct flock *fl) { file_t *fp; vnode_t *vp; proc_t *p; int error, flg; if ((fp = fd_getfile(fd)) == NULL) return EBADF; if (fp->f_type != DTYPE_VNODE) { fd_putfile(fd); return EINVAL; } vp = fp->f_vnode; if (fl->l_whence == SEEK_CUR) fl->l_start += fp->f_offset; flg = F_POSIX; p = curproc; switch (cmd) { case F_SETLKW: flg |= F_WAIT; /* Fall into F_SETLK */ case F_SETLK: switch (fl->l_type) { case F_RDLCK: if ((fp->f_flag & FREAD) == 0) { error = EBADF; break; } if ((p->p_flag & PK_ADVLOCK) == 0) { mutex_enter(p->p_lock); p->p_flag |= PK_ADVLOCK; mutex_exit(p->p_lock); } error = VOP_ADVLOCK(vp, p, F_SETLK, fl, flg); break; case F_WRLCK: if ((fp->f_flag & FWRITE) == 0) { error = EBADF; break; } if ((p->p_flag & PK_ADVLOCK) == 0) { mutex_enter(p->p_lock); p->p_flag |= PK_ADVLOCK; mutex_exit(p->p_lock); } error = VOP_ADVLOCK(vp, p, F_SETLK, fl, flg); break; case F_UNLCK: error = VOP_ADVLOCK(vp, p, F_UNLCK, fl, F_POSIX); break; default: error = EINVAL; break; } break; case F_GETLK: if (fl->l_type != F_RDLCK && fl->l_type != F_WRLCK && fl->l_type != F_UNLCK) { error = EINVAL; break; } error = VOP_ADVLOCK(vp, p, F_GETLK, fl, F_POSIX); break; default: error = EINVAL; break; } fd_putfile(fd); return error; }
int do_sys_accept(struct lwp *l, int sock, struct mbuf **name, register_t *new_sock, const sigset_t *mask, int flags, int clrflags) { file_t *fp, *fp2; struct mbuf *nam; int error, fd; struct socket *so, *so2; short wakeup_state = 0; if ((fp = fd_getfile(sock)) == NULL) return EBADF; if (fp->f_type != DTYPE_SOCKET) { fd_putfile(sock); return ENOTSOCK; } if ((error = fd_allocfile(&fp2, &fd)) != 0) { fd_putfile(sock); return error; } nam = m_get(M_WAIT, MT_SONAME); *new_sock = fd; so = fp->f_socket; solock(so); if (__predict_false(mask)) sigsuspendsetup(l, mask); if (!(so->so_proto->pr_flags & PR_LISTEN)) { error = EOPNOTSUPP; goto bad; } if ((so->so_options & SO_ACCEPTCONN) == 0) { error = EINVAL; goto bad; } if ((so->so_state & SS_NBIO) && so->so_qlen == 0) { error = EWOULDBLOCK; goto bad; } while (so->so_qlen == 0 && so->so_error == 0) { if (so->so_state & SS_CANTRCVMORE) { so->so_error = ECONNABORTED; break; } if (wakeup_state & SS_RESTARTSYS) { error = ERESTART; goto bad; } error = sowait(so, true, 0); if (error) { goto bad; } wakeup_state = so->so_state; } if (so->so_error) { error = so->so_error; so->so_error = 0; goto bad; } /* connection has been removed from the listen queue */ KNOTE(&so->so_rcv.sb_sel.sel_klist, NOTE_SUBMIT); so2 = TAILQ_FIRST(&so->so_q); if (soqremque(so2, 1) == 0) panic("accept"); fp2->f_type = DTYPE_SOCKET; fp2->f_flag = (fp->f_flag & ~clrflags) | ((flags & SOCK_NONBLOCK) ? FNONBLOCK : 0)| ((flags & SOCK_NOSIGPIPE) ? FNOSIGPIPE : 0); fp2->f_ops = &socketops; fp2->f_socket = so2; if (fp2->f_flag & FNONBLOCK) so2->so_state |= SS_NBIO; else so2->so_state &= ~SS_NBIO; error = soaccept(so2, nam); so2->so_cred = kauth_cred_dup(so->so_cred); sounlock(so); if (error) { /* an error occurred, free the file descriptor and mbuf */ m_freem(nam); mutex_enter(&fp2->f_lock); fp2->f_count++; mutex_exit(&fp2->f_lock); closef(fp2); fd_abort(curproc, NULL, fd); } else { fd_set_exclose(l, fd, (flags & SOCK_CLOEXEC) != 0); fd_affix(curproc, fp2, fd); *name = nam; } fd_putfile(sock); if (__predict_false(mask)) sigsuspendteardown(l); return error; bad: sounlock(so); m_freem(nam); fd_putfile(sock); fd_abort(curproc, fp2, fd); if (__predict_false(mask)) sigsuspendteardown(l); return error; }
/* * Most actions in the fcntl() call are straightforward; simply * pass control to the NetBSD system call. A few commands need * conversions after the actual system call has done its work, * because the flag values and lock structure are different. */ int linux_sys_fcntl(struct lwp *l, const struct linux_sys_fcntl_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(int) cmd; syscallarg(void *) arg; } */ struct proc *p = l->l_proc; int fd, cmd, error; u_long val; void *arg; struct sys_fcntl_args fca; file_t *fp; struct vnode *vp; struct vattr va; long pgid; struct pgrp *pgrp; struct tty *tp; fd = SCARG(uap, fd); cmd = SCARG(uap, cmd); arg = SCARG(uap, arg); switch (cmd) { case LINUX_F_DUPFD: cmd = F_DUPFD; break; case LINUX_F_GETFD: cmd = F_GETFD; break; case LINUX_F_SETFD: cmd = F_SETFD; break; case LINUX_F_GETFL: SCARG(&fca, fd) = fd; SCARG(&fca, cmd) = F_GETFL; SCARG(&fca, arg) = arg; if ((error = sys_fcntl(l, &fca, retval))) return error; retval[0] = bsd_to_linux_ioflags(retval[0]); return 0; case LINUX_F_SETFL: { file_t *fp1 = NULL; val = linux_to_bsd_ioflags((unsigned long)SCARG(uap, arg)); /* * Linux seems to have same semantics for sending SIGIO to the * read side of socket, but slightly different semantics * for SIGIO to the write side. Rather than sending the SIGIO * every time it's possible to write (directly) more data, it * only sends SIGIO if last write(2) failed due to insufficient * memory to hold the data. This is compatible enough * with NetBSD semantics to not do anything about the * difference. * * Linux does NOT send SIGIO for pipes. Deal with socketpair * ones and DTYPE_PIPE ones. For these, we don't set * the underlying flags (we don't pass O_ASYNC flag down * to sys_fcntl()), but set the FASYNC flag for file descriptor, * so that F_GETFL would report the ASYNC i/o is on. */ if (val & O_ASYNC) { if (((fp1 = fd_getfile(fd)) == NULL)) return (EBADF); if (((fp1->f_type == DTYPE_SOCKET) && fp1->f_data && ((struct socket *)fp1->f_data)->so_state & SS_ISAPIPE) || (fp1->f_type == DTYPE_PIPE)) val &= ~O_ASYNC; else { /* not a pipe, do not modify anything */ fd_putfile(fd); fp1 = NULL; } } SCARG(&fca, fd) = fd; SCARG(&fca, cmd) = F_SETFL; SCARG(&fca, arg) = (void *) val; error = sys_fcntl(l, &fca, retval); /* Now set the FASYNC flag for pipes */ if (fp1) { if (!error) { mutex_enter(&fp1->f_lock); fp1->f_flag |= FASYNC; mutex_exit(&fp1->f_lock); } fd_putfile(fd); } return (error); } case LINUX_F_GETLK: do_linux_getlk(fd, cmd, arg, linux, flock); case LINUX_F_SETLK: case LINUX_F_SETLKW: do_linux_setlk(fd, cmd, arg, linux, flock, LINUX_F_SETLK); case LINUX_F_SETOWN: case LINUX_F_GETOWN: /* * We need to route fcntl() for tty descriptors around normal * fcntl(), since NetBSD tty TIOC{G,S}PGRP semantics is too * restrictive for Linux F_{G,S}ETOWN. For non-tty descriptors, * this is not a problem. */ if ((fp = fd_getfile(fd)) == NULL) return EBADF; /* Check it's a character device vnode */ if (fp->f_type != DTYPE_VNODE || (vp = (struct vnode *)fp->f_data) == NULL || vp->v_type != VCHR) { fd_putfile(fd); not_tty: /* Not a tty, proceed with common fcntl() */ cmd = cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN; break; } vn_lock(vp, LK_SHARED | LK_RETRY); error = VOP_GETATTR(vp, &va, l->l_cred); VOP_UNLOCK(vp); fd_putfile(fd); if (error) return error; if ((tp = cdev_tty(va.va_rdev)) == NULL) goto not_tty; /* set tty pg_id appropriately */ mutex_enter(proc_lock); if (cmd == LINUX_F_GETOWN) { retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PGID; mutex_exit(proc_lock); return 0; } if ((long)arg <= 0) { pgid = -(long)arg; } else { struct proc *p1 = proc_find((long)arg); if (p1 == NULL) { mutex_exit(proc_lock); return (ESRCH); } pgid = (long)p1->p_pgrp->pg_id; } pgrp = pgrp_find(pgid); if (pgrp == NULL || pgrp->pg_session != p->p_session) { mutex_exit(proc_lock); return EPERM; } tp->t_pgrp = pgrp; mutex_exit(proc_lock); return 0; default: return EOPNOTSUPP; } SCARG(&fca, fd) = fd; SCARG(&fca, cmd) = cmd; SCARG(&fca, arg) = arg; return sys_fcntl(l, &fca, retval); }
int linux_ioctl_hdio(struct proc *p, struct linux_sys_ioctl_args *uap, register_t *retval) { u_long com; int error, error1; caddr_t sg; struct filedesc *fdp; struct file *fp; int (*ioctlf)(struct file *, u_long, caddr_t, struct proc *); struct ataparams *atap, ata; struct atareq req; struct disklabel label, *labp; struct partinfo partp; struct linux_hd_geometry hdg; struct linux_hd_big_geometry hdg_big; fdp = p->p_fd; if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) return (EBADF); FREF(fp); com = SCARG(uap, com); ioctlf = fp->f_ops->fo_ioctl; retval[0] = error = 0; com = SCARG(uap, com); switch (com) { case LINUX_HDIO_OBSOLETE_IDENTITY: case LINUX_HDIO_GET_IDENTITY: sg = stackgap_init(p->p_emul); atap = stackgap_alloc(&sg, DEV_BSIZE); if (atap == NULL) { error = ENOMEM; break; } req.flags = ATACMD_READ; req.command = WDCC_IDENTIFY; req.databuf = (caddr_t)atap; req.datalen = DEV_BSIZE; req.timeout = 1000; error = ioctlf(fp, ATAIOCCOMMAND, (caddr_t)&req, p); if (error != 0) break; if (req.retsts != ATACMD_OK) { error = EIO; break; } error = copyin(atap, &ata, sizeof ata); if (error != 0) break; /* * 142 is the size of the old structure used by Linux, * which doesn't seem to be defined anywhere anymore. */ error = copyout(&ata, SCARG(uap, data), com == LINUX_HDIO_GET_IDENTITY ? sizeof ata : 142); break; case LINUX_HDIO_GETGEO: error = linux_machdepioctl(p, uap, retval); if (error == 0) break; error = ioctlf(fp, DIOCGDINFO, (caddr_t)&label, p); error1 = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p); if (error != 0 && error1 != 0) { error = error1; break; } labp = error != 0 ? &label : partp.disklab; hdg.start = error1 != 0 ? partp.part->p_offset : 0; hdg.heads = labp->d_ntracks; hdg.cylinders = labp->d_ncylinders; hdg.sectors = labp->d_nsectors; error = copyout(&hdg, SCARG(uap, data), sizeof hdg); break; case LINUX_HDIO_GETGEO_BIG: error = linux_machdepioctl(p, uap, retval); if (error == 0) break; case LINUX_HDIO_GETGEO_BIG_RAW: error = ioctlf(fp, DIOCGDINFO, (caddr_t)&label, p); error1 = ioctlf(fp, DIOCGPART, (caddr_t)&partp, p); if (error != 0 && error1 != 0) { error = error1; break; } labp = error != 0 ? &label : partp.disklab; hdg_big.start = error1 != 0 ? partp.part->p_offset : 0; hdg_big.heads = labp->d_ntracks; hdg_big.cylinders = labp->d_ncylinders; hdg_big.sectors = labp->d_nsectors; error = copyout(&hdg_big, SCARG(uap, data), sizeof hdg_big); break; case LINUX_HDIO_GET_UNMASKINTR: case LINUX_HDIO_GET_MULTCOUNT: case LINUX_HDIO_GET_KEEPSETTINGS: case LINUX_HDIO_GET_32BIT: case LINUX_HDIO_GET_NOWERR: case LINUX_HDIO_GET_DMA: case LINUX_HDIO_GET_NICE: case LINUX_HDIO_DRIVE_RESET: case LINUX_HDIO_TRISTATE_HWIF: case LINUX_HDIO_DRIVE_TASK: case LINUX_HDIO_DRIVE_CMD: case LINUX_HDIO_SET_MULTCOUNT: case LINUX_HDIO_SET_UNMASKINTR: case LINUX_HDIO_SET_KEEPSETTINGS: case LINUX_HDIO_SET_32BIT: case LINUX_HDIO_SET_NOWERR: case LINUX_HDIO_SET_DMA: case LINUX_HDIO_SET_PIO_MODE: case LINUX_HDIO_SCAN_HWIF: case LINUX_HDIO_SET_NICE: case LINUX_HDIO_UNREGISTER_HWIF: error = EINVAL; } FRELE(fp); return error; }
int darwin_sys_load_shared_file(struct lwp *l, const struct darwin_sys_load_shared_file_args *uap, register_t *retval) { /* { syscallarg(char *) filename; syscallarg(void *) addr; syscallarg(u_long) len; syscallarg(void **) base; syscallarg(int) count: syscallarg(mach_sf_mapping_t *) mappings; syscallarg(int *) flags; } */ struct file *fp; struct vnode *vp = NULL; vaddr_t base; struct proc *p = l->l_proc; int flags; char *filename; mach_sf_mapping_t *mapp = NULL; size_t maplen; struct sys_open_args open_cup; struct sys_close_args close_cup; register_t fdc; int fd; int i; int error; vaddr_t max_addr, addr; size_t len; vaddr_t uaddr; int need_relocation; struct exec_vmcmd evc; filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyin(SCARG(uap, filename), filename, MAXPATHLEN)) != 0) goto bad1; if ((error = copyin(SCARG(uap, base), &base, sizeof(base))) != 0) goto bad1; if ((error = copyin(SCARG(uap, flags), &flags, sizeof(base))) != 0) goto bad1; #ifdef DEBUG_DARWIN DPRINTF(("darwin_sys_load_shared_file: filename = %p ", SCARG(uap, filename))); DPRINTF(("addr = %p len = 0x%08lx base = %p ", SCARG(uap, addr), SCARG(uap, len), SCARG(uap, base))); DPRINTF(("count = %d mappings = %p flags = %p ", SCARG(uap, count), SCARG(uap, mappings), SCARG(uap, flags))); DPRINTF(("*base = 0x%08lx *flags = %d filename=`%s'\n", base, flags, filename)); #endif SCARG(&open_cup, path) = SCARG(uap, filename); SCARG(&open_cup, flags) = O_RDONLY; SCARG(&open_cup, mode) = 0; if ((error = sys_open(l, &open_cup, &fdc)) != 0) goto bad1; fd = (int)fdc; fp = fd_getfile(fd); if (fp == NULL) { error = EBADF; goto bad1point5; } vp = fp->f_data; vref(vp); if (SCARG(uap, count) < 0 || SCARG(uap, count) > PAGE_SIZE / sizeof(*mapp)) { error = EINVAL; goto bad2; } maplen = SCARG(uap, count) * sizeof(*mapp); mapp = malloc(maplen, M_TEMP, M_WAITOK); if ((error = copyin(SCARG(uap, mappings), mapp, maplen)) != 0) goto bad2; #ifdef DEBUG_DARWIN for (i = 0; i < SCARG(uap, count); i++) { DPRINTF(("mapp[%d].mapping_offset = 0x%08lx\n", i, mapp[i].mapping_offset)); DPRINTF(("mapp[%d].size = 0x%08lx\n", i, (long)mapp[i].size)); DPRINTF(("mapp[%d].file_offset = 0x%08lx\n", i, mapp[i].file_offset)); DPRINTF(("mapp[%d].protection = %d\n", i, mapp[i].protection)); DPRINTF(("mapp[%d].cksum = %ld\n", i, mapp[i].cksum)); } #endif /* Check if we can load at the default addresses */ need_relocation = 0; vm_map_lock(&p->p_vmspace->vm_map); for (i = 0; i < SCARG(uap, count); i++) if ((uvm_map_findspace(&p->p_vmspace->vm_map, base + mapp[i].mapping_offset, mapp[i].size, &uaddr, NULL, 0, 0, UVM_FLAG_FIXED)) == NULL) need_relocation = 1; vm_map_unlock(&p->p_vmspace->vm_map); /* If we cannot, we need a relocation */ if (need_relocation) { DPRINTF(("Relocating\n")); /* Compute the length of the region enclosing all sections */ max_addr = 0; for (i = 0; i < SCARG(uap, count); i++) { addr = (vaddr_t)(mapp[i].mapping_offset + base + mapp[i].size); if (addr > max_addr) max_addr = addr; } len = max_addr - base; DPRINTF(("base = 0x%08lx max_addr = 0x%08lx len = 0x%08x\n", base, max_addr, len)); /* Find some place to map this region */ vm_map_lock(&p->p_vmspace->vm_map); if ((uvm_map_findspace(&p->p_vmspace->vm_map, base, len, &uaddr, NULL, 0, PAGE_SIZE, 0)) == NULL) { DPRINTF(("Impossible to find some space\n")); vm_map_unlock(&p->p_vmspace->vm_map); error = ENOMEM; goto bad2; } vm_map_unlock(&p->p_vmspace->vm_map); /* Update the base address */ base = uaddr; DPRINTF(("New base address: base = 0x%08lx\n", base)); } /* Do the actual mapping */ for (i = 0; i < SCARG(uap, count); i++) { bzero(&evc, sizeof(evc)); evc.ev_addr = base + mapp[i].mapping_offset; evc.ev_len = mapp[i].size; evc.ev_prot = mapp[i].protection & VM_PROT_ALL; evc.ev_flags = 0; if (mapp[i].protection & MACH_VM_PROT_ZF) evc.ev_proc = vmcmd_map_zero; else evc.ev_proc = vmcmd_map_readvn; evc.ev_offset = mapp[i].file_offset; evc.ev_vp = vp; DPRINTF(("map section %d: start = 0x%08lx, len = 0x%08lx\n", i, evc.ev_addr, evc.ev_len)); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); if ((error = (*evc.ev_proc)(l, &evc)) != 0) { VOP_UNLOCK(vp, 0); DPRINTF(("Failed\n")); goto bad2; } VOP_UNLOCK(vp, 0); DPRINTF(("Success\n")); } bad2: if (mapp) free(mapp, M_TEMP); vrele(vp); fd_putfile(fd); bad1point5: SCARG(&close_cup, fd) = fd; if ((error = sys_close(l, &close_cup, retval)) != 0) goto bad1; if ((error = copyout(&base, SCARG(uap, base), sizeof(base))) != 0) goto bad1; if ((error = copyout(&flags, SCARG(uap, flags), sizeof(base))) != 0) goto bad1; bad1: free(filename, M_TEMP); return error; }