Index: conf/files =================================================================== RCS file: /home/ncvs/src/sys/conf/files,v retrieving revision 1.861 diff -u -p -r1.861 files --- conf/files 15 Jan 2004 10:04:20 -0000 1.861 +++ conf/files 21 Jan 2004 14:03:48 -0000 @@ -1074,6 +1074,7 @@ kern/kern_event.c standard kern/kern_exec.c standard kern/kern_exit.c standard kern/kern_fork.c standard +kern/kern_getsioe.c standard kern/kern_idle.c standard kern/kern_intr.c standard kern/kern_jail.c standard Index: conf/options =================================================================== RCS file: /home/ncvs/src/sys/conf/options,v retrieving revision 1.428 diff -u -p -r1.428 options --- conf/options 7 Dec 2003 04:41:11 -0000 1.428 +++ conf/options 10 Jan 2004 00:30:34 -0000 @@ -98,6 +98,7 @@ GEOM_MIRROR opt_geom.h GEOM_PC98 opt_geom.h GEOM_SUNLABEL opt_geom.h GEOM_VOL opt_geom.h +GETSIOE opt_getsioe.h HW_WDOG KSTACK_PAGES KSTACK_MAX_PAGES Index: kern/kern_getsioe.c =================================================================== RCS file: kern/kern_getsioe.c diff -N kern/kern_getsioe.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ kern/kern_getsioe.c 12 Jan 2004 19:59:02 -0000 @@ -0,0 +1,696 @@ +/*- + * Copyright (c) 2002 Olivier Houchard + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "opt_getsioe.h" + +#ifdef GETSIOE +#include + +#define P_GETSIOEABLE(td, p) ((p->p_state == PRS_NORMAL) && \ + !((p)->p_flag & (P_SYSTEM | P_WEXIT)) && (!((p)->p_flag & P_SUGID) || \ + suser(td) == 0)) +MALLOC_DECLARE(M_FILEDESC); +MALLOC_DECLARE(M_KQUEUE); +MALLOC_DEFINE(M_GETSIOE, "getsioe", "getsioe internal list"); + +struct vn_list { + struct vnode *vn; + struct thread *td; + int revoke; +}; + +static int +redefine_pgrp(struct thread *, struct proc *, struct vn_list *); + +static void +redefine_fd(struct filedesc *, struct thread *, struct filedesc *, + struct filedesc *); + +static int +is_parent(struct proc *cur, struct proc *p) +{ + + while (cur) { + if (cur->p_pid == p->p_pid) + return (1); + cur = cur->p_pptr; + } + return (0); +} + +static int +is_in_glist(pid_t pid, struct proc *p) +{ + int i; + + if (p->p_ngetsioe == 0) + return (0); + for (i = 0; i < p->p_ngetsioe; i++) + if (p->p_pgetsioe[i].pid == pid) + return (1); + return (0); +} + +struct fdp_list { + struct filedesc *fdp; + struct thread *td; +}; + +static int +get_children_nb(struct proc *p) +{ + struct proc *tmp_p; + int res = 0; + + tmp_p = LIST_FIRST(&p->p_children); + while (tmp_p) { + res++; + if (!LIST_EMPTY(&tmp_p->p_children)) + tmp_p = LIST_FIRST(&tmp_p->p_children); + else { + if (LIST_NEXT(tmp_p, p_sibling)) + tmp_p = LIST_NEXT(tmp_p, p_sibling); + else if (tmp_p->p_pptr != p && + LIST_NEXT(tmp_p->p_pptr, p_sibling)) + tmp_p = LIST_NEXT(tmp_p->p_pptr, p_sibling); + else + break; + } + } + return (res); +} + +/* XXX Should belong to kern_descrip.c */ +static void +free_fd(struct filedesc *fdp) +{ + struct file **fpp; + int i; + + FILEDESC_UNLOCK(fdp); + fpp = fdp->fd_ofiles; + for (i = fdp->fd_lastfile; i-- >= 0; fpp++) { + if (*fpp) + (void) closef(*fpp, NULL); + } + if (fdp->fd_nfiles > NDFILE) + FREE(fdp->fd_ofiles, M_FILEDESC); + if (fdp->fd_cdir) + vrele(fdp->fd_cdir); + if (fdp->fd_rdir) + vrele(fdp->fd_rdir); + if (fdp->fd_jdir) + vrele(fdp->fd_jdir); + if (fdp->fd_knlist) + FREE(fdp->fd_knlist, M_KQUEUE); + if (fdp->fd_knhash) + FREE(fdp->fd_knhash, M_KQUEUE); + mtx_destroy(&fdp->fd_mtx); + FREE(fdp, M_FILEDESC); +} + +static void +redefine_all(struct thread *td, int pid) +{ + struct proc *tmp_p, *par, *p; + struct fdp_list *fdp_tab = NULL; + struct vn_list *vn_tab = NULL; + struct filedesc *cur_fdp = NULL, *par_fdp = NULL; + int nb = 0, nb_fdp = 0; + int i; + + sx_slock(&proctree_lock); +do_alloc: + p = pfind(pid); + /* + * Those calls to pfind() are paranoia, p could have exited while + * we didn't hold the proctree_lock. + */ + if (!p || p->p_flag & P_WEXIT) { + sx_sunlock(&proctree_lock); + return; + } + PROC_UNLOCK(p); + nb = get_children_nb(p); + sx_sunlock(&proctree_lock); + fdp_tab = realloc(fdp_tab, (nb + 1) * sizeof(*fdp_tab), M_TEMP, + M_WAITOK | M_ZERO); + vn_tab = realloc(vn_tab, (nb + 1) * sizeof(*vn_tab), M_TEMP, + M_WAITOK | M_ZERO); + sx_slock(&proctree_lock); + if (nb != get_children_nb(p)) + goto do_alloc; + nb = 0; + p = pfind(pid); + if (!p || p->p_flag & P_WEXIT) { + sx_sunlock(&proctree_lock); + return; + } + KNOTE(&p->p_klist, NOTE_GETSIOE); + LIST_REMOVE(p, p_sibling); + LIST_INSERT_HEAD(&td->td_proc->p_children, p, p_sibling); + p->p_pptr = td->td_proc; + PROC_UNLOCK(p); + /* + * XXX We make the process inconditionally enter the new process pgrp + * for now. It would be better to just change the session, but we + * are not ready for that yet. + */ + i = redefine_pgrp(td, p, vn_tab); + if (i) + nb++; + tmp_p = LIST_FIRST(&p->p_children); + while (tmp_p) { + i = redefine_pgrp(td, tmp_p, &vn_tab[nb]); + if (i) + nb++; + if (!LIST_EMPTY(&tmp_p->p_children)) + tmp_p = LIST_FIRST(&tmp_p->p_children); + else { + if (LIST_NEXT(tmp_p, p_sibling)) + tmp_p = LIST_NEXT(tmp_p, p_sibling); + else if (tmp_p->p_pptr != p && + LIST_NEXT(tmp_p->p_pptr, p_sibling)) + tmp_p = LIST_NEXT(tmp_p->p_pptr, p_sibling); + else + break; + } + } + /* + * Bump the reference number of the filedesc so we are sure it won't + * be free. + */ + PROC_LOCK(p); + par = p->p_pptr; + if (p->p_fd && P_GETSIOEABLE(td, p)) { + PROC_UNLOCK(p); + mtx_lock(&fdesc_mtx); + fdp_tab[0].fdp = fdshare(p->p_fd); + mtx_unlock(&fdesc_mtx); + fdp_tab[0].td = FIRST_THREAD_IN_PROC(p); + nb_fdp++; + } else + PROC_UNLOCK(p); + PROC_LOCK(par); + if (!par->p_fd) { + if (nb_fdp == 1) + fdp_tab[0].fdp->fd_refcnt--; + PROC_UNLOCK(par); + goto free_fds; + } + PROC_UNLOCK(par); + PROC_LOCK(td->td_proc); + if (!td->td_proc->p_fd) { + if (nb_fdp == 1) + fdp_tab[0].fdp->fd_refcnt--; + PROC_UNLOCK(td->td_proc); + goto free_fds; + } + PROC_UNLOCK(td->td_proc); + mtx_lock(&fdesc_mtx); + par_fdp = fdshare(par->p_fd); + cur_fdp = fdshare(td->td_proc->p_fd); + mtx_unlock(&fdesc_mtx); + /* + * Check all target process' children to see if they have a + * filedesc array, if so add it to our array. + */ + + tmp_p = LIST_FIRST(&p->p_children); + while (tmp_p) { + PROC_LOCK(tmp_p); + if (P_GETSIOEABLE(td, tmp_p) && tmp_p->p_fd) { + PROC_UNLOCK(tmp_p); + mtx_lock(&fdesc_mtx); + /* Bump the reference of the file descriptor. */ + fdp_tab[nb_fdp].fdp = fdshare(tmp_p->p_fd); + mtx_unlock(&fdesc_mtx); + fdp_tab[nb_fdp++].td = FIRST_THREAD_IN_PROC(tmp_p); + } else + PROC_UNLOCK(tmp_p); + if (!LIST_EMPTY(&tmp_p->p_children)) + tmp_p = LIST_FIRST(&tmp_p->p_children); + else { + if (LIST_NEXT(tmp_p, p_sibling)) + tmp_p = LIST_NEXT(tmp_p, p_sibling); + else if (tmp_p->p_pptr != p && + LIST_NEXT(tmp_p->p_pptr, p_sibling)) + tmp_p = LIST_NEXT(tmp_p->p_pptr, p_sibling); + else + break; + } + } + + sx_sunlock(&proctree_lock); + for (i = 0; i < nb_fdp; i++) { + redefine_fd(fdp_tab[i].fdp, fdp_tab[i].td, cur_fdp, par_fdp); + FILEDESC_LOCK((struct filedesc *)fdp_tab[i].fdp); + if (--fdp_tab[i].fdp->fd_refcnt == 0) + free_fd(fdp_tab[i].fdp); + else + FILEDESC_UNLOCK(fdp_tab[i].fdp); + } + if (par_fdp) { + FILEDESC_LOCK(par_fdp); + if (--par_fdp->fd_refcnt == 0) + free_fd(par_fdp); + else + FILEDESC_UNLOCK(par_fdp); + } + if (cur_fdp) { + FILEDESC_LOCK(cur_fdp); + if (--cur_fdp->fd_refcnt == 0) + free_fd(cur_fdp); + else + FILEDESC_UNLOCK(cur_fdp); + } +free_fds: + free(fdp_tab, M_TEMP); + /* Now revoke the terminals ttyvp */ + for (i = 0; i < nb; i++) { + if (vn_tab[i].revoke) + VOP_REVOKE(vn_tab[i].vn, REVOKEALL); + vrele(vn_tab[i].vn); + } + free(vn_tab, M_TEMP); + +} + +static int +is_a_tty(struct file *fp) +{ + if (fp->f_type == DTYPE_VNODE && (((struct vnode *)fp->f_data)->v_vflag + & VV_ISTTY)) + return (1); + return (0); +} + +static int +redefine_pgrp(struct thread *td, struct proc *to_redef, struct vn_list *vn) +{ + struct thread *ttd; + struct tty *saved_tty = NULL; + int leader; + int ret = 0; + + PROC_LOCK(to_redef); + if (!P_GETSIOEABLE(td, to_redef) || + to_redef->p_pgrp == NULL || to_redef->p_pgrp->pg_session == NULL) { + PROC_UNLOCK(to_redef); + return (0); + } + leader = SESS_LEADER(to_redef); + FOREACH_THREAD_IN_PROC(to_redef, ttd) + ttd->td_flags |= TDF_GETSIOE; + if (to_redef->p_pgrp != td->td_proc->p_pgrp) { + struct pgrp *new_pgrp, *saved_pgrp; + /* Change the process' pgrp */ + saved_pgrp = to_redef->p_pgrp; + PROC_UNLOCK(to_redef); + PROC_LOCK(td->td_proc); + new_pgrp = td->td_proc->p_pgrp; + PROC_UNLOCK(td->td_proc); + PGRP_LOCK(new_pgrp); + PGRP_LOCK(saved_pgrp); + SESS_LOCK(saved_pgrp->pg_session); + saved_tty = saved_pgrp->pg_session->s_ttyp; + if (leader && saved_tty && saved_pgrp->pg_session->s_ttyvp) { + ret = 1; + vn->vn = saved_pgrp->pg_session->s_ttyvp; + vn->td = FIRST_THREAD_IN_PROC(to_redef); + if (saved_tty->t_session == saved_pgrp->pg_session) + vn->revoke = 1; + } + SESS_UNLOCK(saved_pgrp->pg_session); + PROC_LOCK(to_redef); + LIST_REMOVE(to_redef, p_pglist); + to_redef->p_pgrp = new_pgrp; + PROC_UNLOCK(to_redef); + LIST_INSERT_HEAD(&new_pgrp->pg_members, to_redef, p_pglist); + PGRP_UNLOCK(saved_pgrp); + PGRP_UNLOCK(new_pgrp); + if (leader) { + SESS_LOCK(new_pgrp->pg_session); + new_pgrp->pg_session->s_leader = to_redef; + SESS_UNLOCK(new_pgrp->pg_session); + } + fixjobc(to_redef, new_pgrp, 1); + fixjobc(to_redef, saved_pgrp, 0); + if (LIST_EMPTY(&saved_pgrp->pg_members)) + pgdelete(saved_pgrp); + } else + PROC_UNLOCK(to_redef); + if (saved_tty) + ttwakeup(saved_tty); + return (ret); +} + +struct to_close_s { + struct file *file; + struct klist *list; + struct file *new_fp; +}; + +static void +redefine_fd(struct filedesc *oldfdp, struct thread *td, + struct filedesc *cur_fdp, struct filedesc *par_fdp) +{ + int i = 0, j = 0; + int n_close = 0; + struct file *par_std[3], *new_std[3]; + struct to_close_s *to_close = NULL; + char file_flags[3]; + + if (par_fdp) { + FILEDESC_LOCK(par_fdp); + for (i = 0; i < 3 && i <= par_fdp->fd_nfiles; i++) + par_std[i] = par_fdp->fd_ofiles[i]; + FILEDESC_UNLOCK(par_fdp); + } + for (; i < 3; i++) + par_std[i] = NULL; + i = 0; + if (cur_fdp) { + FILEDESC_LOCK(cur_fdp); + for (i = 0; i < 3 && i <= cur_fdp->fd_nfiles ; i++) { + new_std[i] = cur_fdp->fd_ofiles[i]; + file_flags[i] = cur_fdp->fd_ofileflags[i]; + } + FILEDESC_UNLOCK(cur_fdp); + } + + for (; i < 3; i++) { + new_std[i] = NULL; + file_flags[i] = 0; + } + if (oldfdp) { +do_alloc: + i = oldfdp->fd_lastfile; + to_close = realloc(to_close, + (i + 1) * sizeof(struct to_close_s), M_TEMP, + M_WAITOK | M_ZERO); + FILEDESC_LOCK(oldfdp); + if (i != oldfdp->fd_lastfile) { + FILEDESC_UNLOCK(oldfdp); + goto do_alloc; + } + for (i = 0; i <= oldfdp->fd_lastfile ; i++) { + /* + * Copy the calling process stdin/stdout/stderr. + */ + if (oldfdp->fd_ofiles[i] != NULL) + for (j = 0; j < 3; j++) { + if (oldfdp->fd_ofiles[i] == + par_std[j] || + is_a_tty(oldfdp->fd_ofiles[i])) { + + to_close[n_close++]. + file = + oldfdp->fd_ofiles[i]; + if (new_std[i < 3 ? i : j]) + fhold(new_std[i < 3 ? + i : j]); + oldfdp->fd_ofiles[i] = + new_std[i < 3 ? i : j]; + if (i < + oldfdp->fd_knlistsize) { + to_close[n_close - 1] + .list = + &oldfdp-> + fd_knlist[i]; + to_close[n_close - 1]. + new_fp = oldfdp-> + fd_ofiles[i]; + } + if (!oldfdp->fd_ofiles[i]) + if (i < + oldfdp->fd_freefile) + oldfdp-> + fd_freefile + = i; + + break; + } + } + } + while (oldfdp->fd_lastfile > 0 && + oldfdp->fd_ofiles[oldfdp->fd_lastfile] == NULL) + oldfdp->fd_lastfile--; + FILEDESC_UNLOCK(oldfdp); + } + if (to_close) { + for (i = 0; i < n_close; i++) { + if (to_close[i].list != NULL) { + if (to_close[i].new_fp != NULL) { + struct knote *kn; + + kn = SLIST_FIRST(to_close[i].list); + while (kn != NULL) { + if (kn->kn_fop->f_detach) + kn->kn_fop-> + f_detach(kn); + kn->kn_fp = + to_close[i]. + new_fp; + fo_kqfilter(kn->kn_fp, kn); + kn = SLIST_NEXT(kn, + kn_link); + } + } else + knote_remove(td, to_close[i].list); + } + closef(to_close[i].file, td); + } + free(to_close, M_TEMP); + } +} + +/* + * MPSAFE + */ + +int +getsioe(struct thread *td, struct getsioe_args *uap) +{ + struct proc *tmp_proc = NULL, *p = NULL, *cur = NULL, *par = NULL; + struct tty *saved_tty; + int error = 0; + int did_lock = 0; + int wakeup_par = 0; + pid_t pid = uap->pid; + pid_t par_pid = 0; + pid_t pgid; + uint32_t pid_nb = 0; + + if (pid == 0 || pid == 1) { + error = EINVAL; /* trying that on init is not a good idea */ + goto bad; + } + sx_slock(&proctree_lock); + p = pfind(pid); + did_lock = 1; + if (p == NULL) { + error = ESRCH; /* bad pid */ + goto bad; + } + if (!p->p_pgrp) { + error = ESRCH; + goto bad; + } + if (td->td_ucred->cr_uid != p->p_ucred->cr_uid) { + error = suser(td); + if (error) { + error = !p_cansee(td, p) ? error : EINVAL; + goto bad; /* No right to take the process. */ + } + } + /* + * Do not accept system proc. + */ + if (p->p_flag & (P_SYSTEM | P_WEXIT | P_SUGID)) + goto bad; + if (p->p_state != PRS_NORMAL) { + error = EINVAL; + goto bad; + } + cur = td->td_proc; + if (p->p_pptr && p->p_pptr == cur) { /* Nothing to do */ + error = EINVAL; + goto bad; + } + if (is_parent(cur, p)) { + error = EINVAL; /* Doesn't seem to be a good idea. */ + goto bad; + } + + PROC_LOCK(cur); + SESS_LOCK(cur->p_pgrp->pg_session); + saved_tty = cur->p_pgrp->pg_session->s_ttyp; + SESS_UNLOCK(cur->p_pgrp->pg_session); + PROC_UNLOCK(cur); + SESS_LOCK(p->p_pgrp->pg_session); + if (p->p_pgrp->pg_session->s_ttyp != NULL && saved_tty != NULL) + bcopy(&p->p_pgrp->pg_session->s_ttyp->t_termios, + &saved_tty->t_termios, sizeof(struct termios)); + SESS_UNLOCK(p->p_pgrp->pg_session); + + /* Remove p from leader list of peers, if needed. */ + if (p->p_leader && p->p_leader != p) { + mtx_lock(&ppeers_lock); + tmp_proc = p->p_leader; + while (tmp_proc->p_peers != NULL) { + if (tmp_proc->p_peers->p_pid == p->p_pid) { + tmp_proc->p_peers = tmp_proc->p_peers->p_peers; + } + else + tmp_proc = tmp_proc->p_peers; + } + mtx_unlock(&ppeers_lock); + } + + { + struct proc *tmp_proc; + tmp_proc = p->p_pptr; + /* + * Remove the process from the parent list of peers, if needed. + */ + mtx_lock(&ppeers_lock); + while (tmp_proc->p_peers) { + if (tmp_proc->p_peers->p_pid == p->p_pid) + tmp_proc->p_peers = tmp_proc->p_peers->p_peers; + else + tmp_proc = tmp_proc->p_peers; + } + mtx_unlock(&ppeers_lock); + + /* + * Check that the parent doesn't ignore children death and if + * we don't already have the same entry in the list. This can + * happen if a process is getsioed(), if is father doesn't wait + * for him and getsioe() it. This is braindead, but it avoids + * an easy DoS + */ + if (p->p_pptr) { + PROC_LOCK(p->p_pptr); + par_pid = p->p_pptr->p_pid; + mtx_lock(&p->p_pptr->p_sigacts->ps_mtx); + if (!(p->p_pptr->p_sigacts->ps_flag & + (PS_NOCLDWAIT | PS_CLDSIGIGN)) && ! + is_in_glist(p->p_pptr->p_pid, p)) + wakeup_par = 1; + mtx_unlock(&p->p_pptr->p_sigacts->ps_mtx); + PROC_UNLOCK(p->p_pptr); + } + } + pgid = p->p_pgid; + PROC_UNLOCK(p); + + sx_sunlock(&proctree_lock); + + mtx_lock(&Giant); /* + * XXX Use Giant for now to protect us from + * race conditions with fork1() and exit1(). + * Giant is needed for vrele() anyway. + */ + + redefine_all(td, pid); + mtx_unlock(&Giant); + if (wakeup_par) { + /* + * If the old parent should be notified of the fake process + * death, add the getsioed process in the list. + */ + struct getsioed *pidpar = NULL; + + + /* Be paranoid about p->p_pptr */ +do_alloc: + par = pfind(par_pid); + if (par) { + pid_nb = p->p_pptr->p_ngetsioe; + PROC_UNLOCK(par); + pidpar = realloc(pidpar, (pid_nb + 1) * + sizeof(struct getsioed), M_GETSIOE, M_WAITOK); + PROC_LOCK(par); + if (par->p_ngetsioe != pid_nb) { + pid_nb = par->p_ngetsioe; + PROC_UNLOCK(par); + goto do_alloc; + } + if (pid_nb > 0) { + bcopy(par->p_pgetsioe, pidpar, + pid_nb * sizeof(struct getsioed)); + free(par->p_pgetsioe, M_GETSIOE); + } + pidpar[pid_nb].pid = pid; + pidpar[pid_nb].pgid = pgid; + par->p_ngetsioe++; + par->p_pgetsioe = pidpar; + psignal(par, SIGCHLD); + wakeup(par); + PROC_UNLOCK(par); + } else if (pidpar != NULL) + free(pidpar, M_GETSIOE); + } + return (0); +bad: + if (p != NULL) + PROC_UNLOCK(p); + if (did_lock) + sx_sunlock(&proctree_lock); + + return (error); +} + + +#else +int +getsioe(struct thread *td, struct getsioe_args *uap) +{ + return (ENOSYS); +} + +#endif /* GETSIOE */ + Index: kern/syscalls.master =================================================================== RCS file: /home/ncvs/src/sys/kern/syscalls.master,v retrieving revision 1.165 diff -u -p -r1.165 syscalls.master --- kern/syscalls.master 26 Dec 2003 05:58:16 -0000 1.165 +++ kern/syscalls.master 12 Jan 2004 19:46:03 -0000 @@ -628,5 +628,6 @@ int attrnamespace, void *data, size_t nbytes); } 440 MSTD { int kse_switchin(const struct __mcontext *mcp, \ long val, long *loc); } +441 MSTD { int getsioe(pid_t pid, int flags); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: kern/kern_exit.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_exit.c,v retrieving revision 1.218 diff -u -p -r1.218 kern_exit.c --- kern/kern_exit.c 14 Nov 2003 18:49:01 -0000 1.218 +++ kern/kern_exit.c 12 Jan 2004 20:32:03 -0000 @@ -83,6 +83,12 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_ex #include #include +#include "opt_getsioe.h" + +#ifdef GETSIOE +#include +#endif + /* Required to be non-static for SysVR4 emulator */ MALLOC_DEFINE(M_ZOMBIE, "zombie", "zombie proc status"); @@ -134,6 +140,10 @@ exit1(struct thread *td, int rv) * MUST abort all other threads before proceeding past here. */ PROC_LOCK(p); +#ifdef GETSIOE + if (p->p_ngetsioe > 0) + free(p->p_pgetsioe, M_GETSIOE); +#endif /* GETSIOE */ if (p->p_flag & P_SA || p->p_numthreads > 1) { /* * First check if some other thread got here before us.. @@ -577,7 +587,88 @@ wait1(struct thread *td, struct wait_arg mtx_lock(&Giant); loop: nfound = 0; +#ifdef GETSIOE + PROC_LOCK(q); + /* + * Check if there is a getsioed process we should report. + */ + while (nfound < q->p_ngetsioe && + uap->pid != WAIT_ANY && uap->pid != q->p_pgetsioe[nfound].pid && + q->p_pgetsioe[nfound].pgid != -uap->pid) + nfound++; + if (nfound < q->p_ngetsioe) { + struct getsioed *tmp_getsioed = NULL; + struct getsioed currently_getsioed; + int nb = q->p_ngetsioe; + + error = 0; + bcopy(&q->p_pgetsioe[nfound], ¤tly_getsioed, + sizeof(struct getsioed)); + td->td_retval[0] = q->p_pgetsioe[nfound].pid; + if (uap->status) { + status = _WSTOLEN; + error = copyout(&status, uap->status, sizeof(status)); + if (error) { + PROC_UNLOCK(q); + mtx_unlock(&Giant); + return (error); + } + } + PROC_UNLOCK(q); + mtx_unlock(&Giant); + /* + * Remove the getsioed process from our list. + */ +do_alloc: + if (nb > 1) { + /* We already own Giant at this point. */ + tmp_getsioed = malloc((nb - 1) * + sizeof(struct getsioed), M_GETSIOE, M_WAITOK); + PROC_LOCK(q); + if (nb != q->p_ngetsioe) { + free(tmp_getsioed, M_GETSIOE); + nb = q->p_ngetsioe; + PROC_UNLOCK(q); + goto do_alloc; + } + if (nfound >= nb || currently_getsioed.pid != + q->p_pgetsioe[nfound].pid || + currently_getsioed.pgid != + q->p_pgetsioe[nfound].pgid) { + /* Ok list has been modified */ + for (nfound = 0; nfound < nb && + (currently_getsioed.pid != + q->p_pgetsioe[nfound].pid || + currently_getsioed.pgid != + q->p_pgetsioe[nfound].pgid); + nfound++) + ; + if (nfound == nb) { /* Huh ? */ + free(tmp_getsioed, M_GETSIOE); + PROC_UNLOCK(q); + mtx_lock(&Giant); + goto loop; + } + } + if (nfound > 0) + bcopy(q->p_pgetsioe, tmp_getsioed, + nfound * sizeof(struct getsioed)); + if (nfound < nb - 1) + bcopy(&q->p_pgetsioe[nfound + 1], + &tmp_getsioed[nfound], (nb - nfound - 1) * + sizeof(struct getsioed)); + PROC_UNLOCK(q); + } + free(q->p_pgetsioe, M_GETSIOE); + q->p_pgetsioe = tmp_getsioed; + q->p_ngetsioe--; + return (error); + } else + PROC_UNLOCK(q); + nfound = 0; +#endif /* GETSIOE */ sx_xlock(&proctree_lock); + LIST_FOREACH(p, &q->p_children, p_sibling) { PROC_LOCK(p); if (uap->pid != WAIT_ANY && @@ -585,7 +676,7 @@ loop: PROC_UNLOCK(p); continue; } - + /* * This special case handles a kthread spawned by linux_clone * (see linux_misc.c). The linux_wait4 and linux_waitpid Index: kern/kern_proc.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_proc.c,v retrieving revision 1.197 diff -u -p -r1.197 kern_proc.c --- kern/kern_proc.c 16 Oct 2003 08:39:15 -0000 1.197 +++ kern/kern_proc.c 10 Jan 2004 00:17:33 -0000 @@ -77,7 +77,6 @@ MALLOC_DEFINE(M_SUBPROC, "subproc", "Pro static void doenterpgrp(struct proc *, struct pgrp *); static void orphanpg(struct pgrp *pg); static void pgadjustjobc(struct pgrp *pgrp, int entering); -static void pgdelete(struct pgrp *); static void proc_ctor(void *mem, int size, void *arg); static void proc_dtor(void *mem, int size, void *arg); static void proc_init(void *mem, int size); @@ -446,7 +445,7 @@ leavepgrp(p) /* * delete a process group */ -static void +void pgdelete(pgrp) register struct pgrp *pgrp; { Index: kern/kern_descrip.c =================================================================== RCS file: /home/ncvs/src/sys/kern/kern_descrip.c,v retrieving revision 1.223 diff -u -p -r1.223 kern_descrip.c --- kern/kern_descrip.c 17 Jan 2004 00:58:36 -0000 1.223 +++ kern/kern_descrip.c 19 Jan 2004 23:28:12 -0000 @@ -75,7 +75,7 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_de #include #include -static MALLOC_DEFINE(M_FILEDESC, "file desc", "Open file descriptor table"); +MALLOC_DEFINE(M_FILEDESC, "file desc", "Open file descriptor table"); static MALLOC_DEFINE(M_FILEDESC_TO_LEADER, "file desc to leader", "file desc to leader structures"); static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures"); Index: kern/sys_generic.c =================================================================== RCS file: /home/ncvs/src/sys/kern/sys_generic.c,v retrieving revision 1.126 diff -u -p -r1.126 sys_generic.c --- kern/sys_generic.c 9 Nov 2003 09:17:24 -0000 1.126 +++ kern/sys_generic.c 9 Jan 2004 23:42:46 -0000 @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD: src/sys/kern/sys_generic.c,v 1.126 2003/11/09 09:17:24 tanimura Exp $"); #include "opt_ktrace.h" +#include "opt_getsioe.h" #include #include @@ -72,6 +73,8 @@ __FBSDID("$FreeBSD: src/sys/kern/sys_gen #include #include +#include "opt_getsioe.h" + static MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer"); static MALLOC_DEFINE(M_SELECT, "select", "select() buffer"); MALLOC_DEFINE(M_IOV, "iov", "large iov's"); @@ -105,10 +108,18 @@ read(td, uap) struct file *fp; int error; +#ifdef GETSIOE +get_file: +#endif if ((error = fget_read(td, uap->fd, &fp)) == 0) { error = dofileread(td, fp, uap->fd, uap->buf, uap->nbyte, (off_t)-1, 0); fdrop(fp, td); +#ifdef GETSIOE + /* The process woke up from a ttyread; */ + if (error == EGETSIOE) + goto get_file; +#endif } return(error); } @@ -136,6 +147,9 @@ pread(td, uap) struct file *fp; int error; +#ifdef GETSIOE +get_file: +#endif if ((error = fget_read(td, uap->fd, &fp)) != 0) return (error); if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) { @@ -145,6 +159,10 @@ pread(td, uap) uap->offset, FOF_OFFSET); } fdrop(fp, td); +#ifdef GETSIOE + if (error == EGETSIOE) + goto get_file; +#endif return(error); } @@ -196,6 +214,10 @@ dofileread(td, fp, fd, buf, nbyte, offse if (auio.uio_resid != cnt && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; +#ifdef GETSIOE + if (error == EGETSIOE) + return (error); +#endif } cnt -= auio.uio_resid; #ifdef KTRACE @@ -240,8 +262,11 @@ readv(td, uap) struct uio ktruio; #endif - if ((error = fget_read(td, uap->fd, &fp)) != 0) - return (error); +#ifdef GETSIOE +get_file: +#endif + if ((error = fget_read(td, uap->fd, &fp)) != 0) + return (error); needfree = NULL; /* note: can't use iovlen until iovcnt is validated */ iovlen = uap->iovcnt * sizeof (struct iovec); @@ -286,6 +311,17 @@ readv(td, uap) if (auio.uio_resid != cnt && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; +#ifdef GETSIOE + if (error == EGETSIOE) { + if (needfree) + FREE(needfree, M_IOV); +#ifdef KTRACE + FREE(ktriov, M_TEMP); +#endif + fdrop(fp, td); + goto get_file; + } +#endif } cnt -= auio.uio_resid; #ifdef KTRACE @@ -327,14 +363,21 @@ write(td, uap) struct file *fp; int error; +#ifdef GETSIOE +get_file: +#endif if ((error = fget_write(td, uap->fd, &fp)) == 0) { error = dofilewrite(td, fp, uap->fd, uap->buf, uap->nbyte, (off_t)-1, 0); fdrop(fp, td); +#ifdef GETSIOE + if (error == EGETSIOE) + goto get_file; +#endif } else { error = EBADF; /* XXX this can't be right */ } - return(error); + return (error); } /* @@ -360,6 +403,9 @@ pwrite(td, uap) struct file *fp; int error; +#ifdef GETSIOE +get_file: +#endif if ((error = fget_write(td, uap->fd, &fp)) == 0) { if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) { error = ESPIPE; @@ -368,6 +414,10 @@ pwrite(td, uap) uap->nbyte, uap->offset, FOF_OFFSET); } fdrop(fp, td); +#ifdef GETSIOE + if (error == EGETSIOE) + goto get_file; +#endif } else { error = EBADF; /* this can't be right */ } @@ -469,6 +519,9 @@ writev(td, uap) struct uio ktruio; #endif +#ifdef GETSIOE +get_file: +#endif if ((error = fget_write(td, uap->fd, &fp)) != 0) return (EBADF); needfree = NULL; @@ -521,7 +574,18 @@ writev(td, uap) PROC_LOCK(td->td_proc); psignal(td->td_proc, SIGPIPE); PROC_UNLOCK(td->td_proc); + } +#ifdef GETSIOE + else if (error == EGETSIOE) { /* File has changed */ + fdrop(fp, td); + if (needfree) + FREE(needfree, M_IOV); +#ifdef KTRACE + FREE(ktriov, M_TEMP); +#endif + goto get_file; } +#endif } cnt -= auio.uio_resid; #ifdef KTRACE Index: kern/tty.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty.c,v retrieving revision 1.206 diff -u -p -r1.206 tty.c --- kern/tty.c 8 Jan 2004 22:49:23 -0000 1.206 +++ kern/tty.c 9 Jan 2004 23:42:46 -0000 @@ -109,6 +109,12 @@ __FBSDID("$FreeBSD: src/sys/kern/tty.c,v #include #include +#include "opt_getsioe.h" + +#ifdef GETSIOE +#include +#endif + MALLOC_DEFINE(M_TTYS, "ttys", "tty data structures"); long tk_cancc; @@ -824,9 +830,9 @@ ttioctl(struct tty *tp, u_long cmd, void * Policy -- Don't allow FIOSETOWN on someone else's * controlling tty */ - if (tp->t_session != NULL && !isctty(p, tp)) + if (tp->t_session != NULL && !isctty(p, tp)) { return (ENOTTY); - + } error = fsetown(*(int *)data, &tp->t_sigio); if (error) return (error); @@ -1584,6 +1590,19 @@ ttread(struct tty *tp, struct uio *uio, td = curthread; p = td->td_proc; loop: +#ifdef GETSIOE + /* + * Process must have been getsioe() while sleeping. + */ + PROC_LOCK(p); + if (td->td_flags & TDF_GETSIOE && p->p_session->s_ttyp != tp) { + td->td_flags &= ~TDF_GETSIOE; + PROC_UNLOCK(p); + return (EGETSIOE); + } + PROC_UNLOCK(p); +#endif + s = spltty(); lflag = tp->t_lflag; /* @@ -1908,6 +1927,16 @@ ttwrite(struct tty *tp, struct uio *uio, td = curthread; p = td->td_proc; loop: +#ifdef GETSIOE + p = curthread->td_proc; + PROC_LOCK(p); + if (td->td_flags & TDF_GETSIOE && p->p_session->s_ttyp != tp) { + td->td_flags &= ~TDF_GETSIOE; + PROC_UNLOCK(p); + return (EGETSIOE); + } + PROC_UNLOCK(p); +#endif /* GETSIOE */ s = spltty(); if (ISSET(tp->t_state, TS_ZOMBIE)) { splx(s); @@ -2713,7 +2742,7 @@ int ttyread(dev_t dev, struct uio *uio, int flag) { struct tty *tp; - + tp = dev->si_tty; if (tp == NULL) return (ENODEV); Index: kern/tty_pty.c =================================================================== RCS file: /home/ncvs/src/sys/kern/tty_pty.c,v retrieving revision 1.112 diff -u -p -r1.112 tty_pty.c --- kern/tty_pty.c 9 Nov 2003 09:17:24 -0000 1.112 +++ kern/tty_pty.c 9 Jan 2004 23:42:46 -0000 @@ -60,6 +60,12 @@ __FBSDID("$FreeBSD: src/sys/kern/tty_pty #include #include +#include "opt_getsioe.h" + +#ifdef GETSIOE +#include +#endif + static MALLOC_DEFINE(M_PTY, "ptys", "pty data structures"); static void ptsstart(struct tty *tp); @@ -233,6 +239,17 @@ ptsread(dev, uio, flag) int error = 0; again: +#ifdef GETSIOE + PROC_LOCK(p); + if (td->td_flags & TDF_GETSIOE && p->p_session->s_ttyp != tp) { + + td->td_flags &= ~TDF_GETSIOE; + PROC_UNLOCK(p); + return (EGETSIOE); + } + PROC_UNLOCK(p); +#endif /* GETSIOE */ + if (pti->pt_flags & PF_REMOTE) { while (isbackground(p, tp)) { sx_slock(&proctree_lock); @@ -412,6 +429,18 @@ ptcread(dev, uio, flag) * then return the appropriate error instead. */ for (;;) { +#ifdef GETSIOE + struct thread *td = curthread; + struct proc *p = td->td_proc; + PROC_LOCK(p); + if (td->td_flags & TDF_GETSIOE && p->p_session->s_ttyp != tp) { + td->td_flags &= ~TDF_GETSIOE; + PROC_UNLOCK(p); + return (EGETSIOE); + } + PROC_UNLOCK(p); +#endif /* GETSIOE */ + if (tp->t_state&TS_ISOPEN) { if (pti->pt_flags&PF_PKT && pti->pt_send) { error = ureadc((int)pti->pt_send, uio); @@ -543,8 +572,21 @@ ptcwrite(dev, uio, flag) int cnt = 0; struct pt_ioctl *pti = dev->si_drv1; int error = 0; +#ifdef GETSIOE + struct thread *td = curthread; + struct proc *p = td->td_proc; +#endif /* GETSIOE */ again: +#ifdef GETSIOE + PROC_LOCK(p); + if (td->td_flags & TDF_GETSIOE && p->p_session->s_ttyp != tp) { + td->td_flags &= ~TDF_GETSIOE; + PROC_UNLOCK(p); + return (EGETSIOE); + } + PROC_UNLOCK(p); +#endif /* GETSIOE */ if ((tp->t_state&TS_ISOPEN) == 0) goto block; if (pti->pt_flags & PF_REMOTE) { Index: sys/wait.h =================================================================== RCS file: /home/ncvs/src/sys/sys/wait.h,v retrieving revision 1.17 diff -u -p -r1.17 wait.h --- sys/wait.h 5 Jun 2002 02:21:01 -0000 1.17 +++ sys/wait.h 10 Jan 2004 00:25:30 -0000 @@ -57,11 +57,13 @@ #define _WSTATUS(x) (_W_INT(x) & 0177) #define _WSTOPPED 0177 /* _WSTATUS if process is stopped */ +#define _WSTOLEN 0x10000 #define WIFSTOPPED(x) (_WSTATUS(x) == _WSTOPPED) #define WSTOPSIG(x) (_W_INT(x) >> 8) #define WIFSIGNALED(x) (_WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0) #define WTERMSIG(x) (_WSTATUS(x)) #define WIFEXITED(x) (_WSTATUS(x) == 0) +#define WIFSTOLEN(x) (_W_INT(x) == 0100) /* Process was getsioed */ #define WEXITSTATUS(x) (_W_INT(x) >> 8) #define WIFCONTINUED(x) (x == 0x13) /* 0x13 == SIGCONT */ #if __BSD_VISIBLE Index: sys/getsioe.h =================================================================== RCS file: sys/getsioe.h diff -N sys/getsioe.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/getsioe.h 9 Jan 2004 23:57:31 -0000 @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2003 Olivier Houchard + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_GETSIOE_H_ +#define _SYS_GETSIOE_H_ + +#ifdef _KERNEL + +#ifdef MALLOC_DECLARE +MALLOC_DECLARE(M_GETSIOE); +#endif + +struct getsioed { + pid_t pid; + pid_t pgid; +}; +#else + +int getsioe(pid_t, int); + +#endif /* _KERNEL */ + +#define GETSIOE_DETACH 0x0001 + +#endif /* !_SYS_GETSIOE_H_ */ Index: sys/proc.h =================================================================== RCS file: /home/ncvs/src/sys/sys/proc.h,v retrieving revision 1.363 diff -u -p -r1.363 proc.h --- sys/proc.h 3 Jan 2004 02:02:26 -0000 1.363 +++ sys/proc.h 10 Jan 2004 00:19:54 -0000 @@ -356,6 +356,7 @@ struct thread { #define TDF_NEEDSIGCHK 0x020000 /* Thread may need signal delivery. */ #define TDF_SA 0x040000 /* A scheduler activation based thread. */ #define TDF_UMTXWAKEUP 0x080000 /* Libthr thread must not sleep on a umtx. */ +#define TDF_GETSIOE 0x400000 /* Thread got getsioed. */ #define TDF_DEADLKTREAT 0x800000 /* Lock aquisition - deadlock treatment. */ /* "private" flags kept in td_pflags */ @@ -587,6 +588,8 @@ struct proc { void *p_aioinfo; /* (?) ASYNC I/O info. */ struct thread *p_singlethread;/* (c + j) If single threading this is it */ int p_suspcount; /* (c) # threads in suspended mode */ + u_int p_ngetsioe; /* (c) number of children getsioed */ + struct getsioed *p_pgetsioe; /* (c) children getsioed */ /* End area that is zeroed on creation. */ #define p_endzero p_magic @@ -850,6 +853,7 @@ struct pargs *pargs_alloc(int len); void pargs_drop(struct pargs *pa); void pargs_free(struct pargs *pa); void pargs_hold(struct pargs *pa); +void pgdelete(struct pgrp *pgrp); void procinit(void); void threadinit(void); void proc_linkup(struct proc *p, struct ksegrp *kg, Index: sys/event.h =================================================================== RCS file: /home/ncvs/src/sys/sys/event.h,v retrieving revision 1.22 diff -u -p -r1.22 event.h --- sys/event.h 2 Feb 2003 19:39:51 -0000 1.22 +++ sys/event.h 10 Jan 2004 00:24:53 -0000 @@ -98,6 +98,7 @@ struct kevent { #define NOTE_EXIT 0x80000000 /* process exited */ #define NOTE_FORK 0x40000000 /* process forked */ #define NOTE_EXEC 0x20000000 /* process exec'd */ +#define NOTE_GETSIOE 0x10000000 /* process getsioed */ #define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */ #define NOTE_PDATAMASK 0x000fffff /* mask for pid */ Index: sys/errno.h =================================================================== RCS file: /home/ncvs/src/sys/sys/errno.h,v retrieving revision 1.25 diff -u -p -r1.25 errno.h --- sys/errno.h 7 Oct 2002 06:25:23 -0000 1.25 +++ sys/errno.h 10 Jan 2004 00:24:41 -0000 @@ -181,6 +181,7 @@ __END_DECLS #define EJUSTRETURN (-2) /* don't modify regs, just return */ #define ENOIOCTL (-3) /* ioctl not handled by this layer */ #define EDIRIOCTL (-4) /* do direct ioctl in GEOM */ +#define EGETSIOE (-5) /* the file changed */ #endif #endif