int procfs_doprocctl(PFS_FILL_ARGS) { int error; struct namemap *nm; if (uio == NULL || uio->uio_rw != UIO_WRITE) return (EOPNOTSUPP); /* * Map signal names into signal generation * or debug control. Unknown commands and/or signals * return EOPNOTSUPP. * * Sending a signal while the process is being debugged * also has the side effect of letting the target continue * to run. There is no way to single-step a signal delivery. */ error = EOPNOTSUPP; sbuf_trim(sb); sbuf_finish(sb); nm = findname(ctlnames, sbuf_data(sb), sbuf_len(sb)); if (nm) { printf("procfs: got a %s command\n", sbuf_data(sb)); error = procfs_control(td, p, nm->nm_val); } else { nm = findname(signames, sbuf_data(sb), sbuf_len(sb)); if (nm) { printf("procfs: got a sig%s\n", sbuf_data(sb)); PROC_LOCK(p); /* This is very broken XXXKSE: */ if (TRACE_WAIT_P(td->td_proc, p)) { p->p_xstat = nm->nm_val; #ifdef FIX_SSTEP /* XXXKSE: */ FIX_SSTEP(FIRST_THREAD_IN_PROC(p)); #endif /* XXXKSE: */ p->p_flag &= ~P_STOPPED_SIG; PROC_SLOCK(p); thread_unsuspend(p); PROC_SUNLOCK(p); } else psignal(p, nm->nm_val); PROC_UNLOCK(p); error = 0; } } return (error); }
static void poll_idle(void) { struct thread *td = curthread; struct rtprio rtp; rtp.prio = RTP_PRIO_MAX; /* lowest priority */ rtp.type = RTP_PRIO_IDLE; PROC_SLOCK(td->td_proc); rtp_to_pri(&rtp, td); PROC_SUNLOCK(td->td_proc); for (;;) { if (poll_in_idle_loop && poll_handlers > 0) { idlepoll_sleeping = 0; ether_poll(poll_each_burst); thread_lock(td); mi_switch(SW_VOL, NULL); thread_unlock(td); } else { idlepoll_sleeping = 1; tsleep(&idlepoll_sleeping, 0, "pollid", hz * 3); } } }
static void racctd(void) { struct thread *td; struct proc *p; struct timeval wallclock; uint64_t runtime; for (;;) { sx_slock(&allproc_lock); FOREACH_PROC_IN_SYSTEM(p) { if (p->p_state != PRS_NORMAL) continue; if (p->p_flag & P_SYSTEM) continue; microuptime(&wallclock); timevalsub(&wallclock, &p->p_stats->p_start); PROC_LOCK(p); PROC_SLOCK(p); FOREACH_THREAD_IN_PROC(p, td) { ruxagg(p, td); thread_lock(td); thread_unlock(td); } runtime = cputick2usec(p->p_rux.rux_runtime); PROC_SUNLOCK(p); #ifdef notyet KASSERT(runtime >= p->p_prev_runtime, ("runtime < p_prev_runtime")); #else if (runtime < p->p_prev_runtime) runtime = p->p_prev_runtime; #endif p->p_prev_runtime = runtime; mtx_lock(&racct_lock); racct_set_locked(p, RACCT_CPU, runtime); racct_set_locked(p, RACCT_WALLCLOCK, wallclock.tv_sec * 1000000 + wallclock.tv_usec); mtx_unlock(&racct_lock); PROC_UNLOCK(p); } sx_sunlock(&allproc_lock); pause("-", hz); }
int procfs_doprocstatus(PFS_FILL_ARGS) { struct session *sess; struct thread *tdfirst; struct tty *tp; struct ucred *cr; const char *wmesg; char *pc; char *sep; int pid, ppid, pgid, sid; int i; pid = p->p_pid; PROC_LOCK(p); ppid = p->p_pptr ? p->p_pptr->p_pid : 0; pgid = p->p_pgrp->pg_id; sess = p->p_pgrp->pg_session; SESS_LOCK(sess); sid = sess->s_leader ? sess->s_leader->p_pid : 0; /* comm pid ppid pgid sid tty ctty,sldr start ut st wmsg euid ruid rgid,egid,groups[1 .. ngroups] */ pc = p->p_comm; do { if (*pc < 33 || *pc > 126 || *pc == '\\') sbuf_printf(sb, "\\%03o", *pc); else sbuf_putc(sb, *pc); } while (*++pc); sbuf_printf(sb, " %d %d %d %d ", pid, ppid, pgid, sid); if ((p->p_flag & P_CONTROLT) && (tp = sess->s_ttyp)) sbuf_printf(sb, "%s ", devtoname(tp->t_dev)); else sbuf_printf(sb, "- "); sep = ""; if (sess->s_ttyvp) { sbuf_printf(sb, "%sctty", sep); sep = ","; } if (SESS_LEADER(p)) { sbuf_printf(sb, "%ssldr", sep); sep = ","; } SESS_UNLOCK(sess); if (*sep != ',') { sbuf_printf(sb, "noflags"); } tdfirst = FIRST_THREAD_IN_PROC(p); thread_lock(tdfirst); if (tdfirst->td_wchan != NULL) { KASSERT(tdfirst->td_wmesg != NULL, ("wchan %p has no wmesg", tdfirst->td_wchan)); wmesg = tdfirst->td_wmesg; } else wmesg = "nochan"; thread_unlock(tdfirst); if (p->p_flag & P_INMEM) { struct timeval start, ut, st; PROC_SLOCK(p); calcru(p, &ut, &st); PROC_SUNLOCK(p); start = p->p_stats->p_start; timevaladd(&start, &boottime); sbuf_printf(sb, " %jd,%ld %jd,%ld %jd,%ld", (intmax_t)start.tv_sec, start.tv_usec, (intmax_t)ut.tv_sec, ut.tv_usec, (intmax_t)st.tv_sec, st.tv_usec); } else sbuf_printf(sb, " -1,-1 -1,-1 -1,-1"); sbuf_printf(sb, " %s", wmesg); cr = p->p_ucred; sbuf_printf(sb, " %lu %lu %lu", (u_long)cr->cr_uid, (u_long)cr->cr_ruid, (u_long)cr->cr_rgid); /* egid (cr->cr_svgid) is equal to cr_ngroups[0] see also getegid(2) in /sys/kern/kern_prot.c */ for (i = 0; i < cr->cr_ngroups; i++) { sbuf_printf(sb, ",%lu", (u_long)cr->cr_groups[i]); } if (jailed(cr)) { mtx_lock(&cr->cr_prison->pr_mtx); sbuf_printf(sb, " %s", prison_name(td->td_ucred->cr_prison, cr->cr_prison)); mtx_unlock(&cr->cr_prison->pr_mtx); } else { sbuf_printf(sb, " -"); } PROC_UNLOCK(p); sbuf_printf(sb, "\n"); return (0); }
static int procfs_control(struct thread *td, struct proc *p, int op) { int error = 0; struct thread *temp; /* * Attach - attaches the target process for debugging * by the calling process. */ if (op == PROCFS_CTL_ATTACH) { sx_xlock(&proctree_lock); PROC_LOCK(p); if ((error = p_candebug(td, p)) != 0) goto out; if (p->p_flag & P_TRACED) { error = EBUSY; goto out; } /* Can't trace yourself! */ if (p->p_pid == td->td_proc->p_pid) { error = EINVAL; goto out; } /* * Go ahead and set the trace flag. * Save the old parent (it's reset in * _DETACH, and also in kern_exit.c:wait4() * Reparent the process so that the tracing * proc gets to see all the action. * Stop the target. */ p->p_flag |= P_TRACED; faultin(p); p->p_xstat = 0; /* XXX ? */ if (p->p_pptr != td->td_proc) { p->p_oppid = p->p_pptr->p_pid; proc_reparent(p, td->td_proc); } psignal(p, SIGSTOP); out: PROC_UNLOCK(p); sx_xunlock(&proctree_lock); return (error); } /* * Authorization check: rely on normal debugging protection, except * allow processes to disengage debugging on a process onto which * they have previously attached, but no longer have permission to * debug. */ PROC_LOCK(p); if (op != PROCFS_CTL_DETACH && ((error = p_candebug(td, p)))) { PROC_UNLOCK(p); return (error); } /* * Target process must be stopped, owned by (td) and * be set up for tracing (P_TRACED flag set). * Allow DETACH to take place at any time for sanity. * Allow WAIT any time, of course. */ switch (op) { case PROCFS_CTL_DETACH: case PROCFS_CTL_WAIT: break; default: if (!TRACE_WAIT_P(td->td_proc, p)) { PROC_UNLOCK(p); return (EBUSY); } } #ifdef FIX_SSTEP /* * do single-step fixup if needed */ FIX_SSTEP(FIRST_THREAD_IN_PROC(p)); #endif /* * Don't deliver any signal by default. * To continue with a signal, just send * the signal name to the ctl file */ p->p_xstat = 0; switch (op) { /* * Detach. Cleans up the target process, reparent it if possible * and set it running once more. */ case PROCFS_CTL_DETACH: /* if not being traced, then this is a painless no-op */ if ((p->p_flag & P_TRACED) == 0) { PROC_UNLOCK(p); return (0); } /* not being traced any more */ p->p_flag &= ~(P_TRACED | P_STOPPED_TRACE); /* remove pending SIGTRAP, else the process will die */ sigqueue_delete_proc(p, SIGTRAP); FOREACH_THREAD_IN_PROC(p, temp) temp->td_dbgflags &= ~TDB_SUSPEND; PROC_UNLOCK(p); /* give process back to original parent */ sx_xlock(&proctree_lock); if (p->p_oppid != p->p_pptr->p_pid) { struct proc *pp; pp = pfind(p->p_oppid); PROC_LOCK(p); if (pp) { PROC_UNLOCK(pp); proc_reparent(p, pp); } } else PROC_LOCK(p); p->p_oppid = 0; p->p_flag &= ~P_WAITED; /* XXX ? */ sx_xunlock(&proctree_lock); wakeup(td->td_proc); /* XXX for CTL_WAIT below ? */ break; /* * Step. Let the target process execute a single instruction. * What does it mean to single step a threaded program? */ case PROCFS_CTL_STEP: error = proc_sstep(FIRST_THREAD_IN_PROC(p)); if (error) { PROC_UNLOCK(p); return (error); } break; /* * Run. Let the target process continue running until a breakpoint * or some other trap. */ case PROCFS_CTL_RUN: p->p_flag &= ~P_STOPPED_SIG; /* this uses SIGSTOP */ break; /* * Wait for the target process to stop. * If the target is not being traced then just wait * to enter */ case PROCFS_CTL_WAIT: if (p->p_flag & P_TRACED) { while (error == 0 && (P_SHOULDSTOP(p)) && (p->p_flag & P_TRACED) && (p->p_pptr == td->td_proc)) error = msleep(p, &p->p_mtx, PWAIT|PCATCH, "procfsx", 0); if (error == 0 && !TRACE_WAIT_P(td->td_proc, p)) error = EBUSY; } else { while (error == 0 && P_SHOULDSTOP(p)) error = msleep(p, &p->p_mtx, PWAIT|PCATCH, "procfs", 0); } PROC_UNLOCK(p); return (error); default: panic("procfs_control"); } PROC_SLOCK(p); thread_unsuspend(p); /* If it can run, let it do so. */ PROC_SUNLOCK(p); PROC_UNLOCK(p); return (0); }
static void do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *td2, struct vmspace *vm2, struct file *fp_procdesc) { struct proc *p1, *pptr; int trypid; struct filedesc *fd; struct filedesc_to_leader *fdtol; struct sigacts *newsigacts; sx_assert(&proctree_lock, SX_SLOCKED); sx_assert(&allproc_lock, SX_XLOCKED); p1 = td->td_proc; trypid = fork_findpid(fr->fr_flags); sx_sunlock(&proctree_lock); p2->p_state = PRS_NEW; /* protect against others */ p2->p_pid = trypid; AUDIT_ARG_PID(p2->p_pid); LIST_INSERT_HEAD(&allproc, p2, p_list); allproc_gen++; LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash); tidhash_add(td2); PROC_LOCK(p2); PROC_LOCK(p1); sx_xunlock(&allproc_lock); bcopy(&p1->p_startcopy, &p2->p_startcopy, __rangeof(struct proc, p_startcopy, p_endcopy)); pargs_hold(p2->p_args); PROC_UNLOCK(p1); bzero(&p2->p_startzero, __rangeof(struct proc, p_startzero, p_endzero)); /* Tell the prison that we exist. */ prison_proc_hold(p2->p_ucred->cr_prison); PROC_UNLOCK(p2); /* * Malloc things while we don't hold any locks. */ if (fr->fr_flags & RFSIGSHARE) newsigacts = NULL; else newsigacts = sigacts_alloc(); /* * Copy filedesc. */ if (fr->fr_flags & RFCFDG) { fd = fdinit(p1->p_fd, false); fdtol = NULL; } else if (fr->fr_flags & RFFDG) { fd = fdcopy(p1->p_fd); fdtol = NULL; } else { fd = fdshare(p1->p_fd); if (p1->p_fdtol == NULL) p1->p_fdtol = filedesc_to_leader_alloc(NULL, NULL, p1->p_leader); if ((fr->fr_flags & RFTHREAD) != 0) { /* * Shared file descriptor table, and shared * process leaders. */ fdtol = p1->p_fdtol; FILEDESC_XLOCK(p1->p_fd); fdtol->fdl_refcount++; FILEDESC_XUNLOCK(p1->p_fd); } else { /* * Shared file descriptor table, and different * process leaders. */ fdtol = filedesc_to_leader_alloc(p1->p_fdtol, p1->p_fd, p2); } } /* * Make a proc table entry for the new process. * Start by zeroing the section of proc that is zero-initialized, * then copy the section that is copied directly from the parent. */ PROC_LOCK(p2); PROC_LOCK(p1); bzero(&td2->td_startzero, __rangeof(struct thread, td_startzero, td_endzero)); bcopy(&td->td_startcopy, &td2->td_startcopy, __rangeof(struct thread, td_startcopy, td_endcopy)); bcopy(&p2->p_comm, &td2->td_name, sizeof(td2->td_name)); td2->td_sigstk = td->td_sigstk; td2->td_flags = TDF_INMEM; td2->td_lend_user_pri = PRI_MAX; #ifdef VIMAGE td2->td_vnet = NULL; td2->td_vnet_lpush = NULL; #endif /* * Allow the scheduler to initialize the child. */ thread_lock(td); sched_fork(td, td2); thread_unlock(td); /* * Duplicate sub-structures as needed. * Increase reference counts on shared objects. */ p2->p_flag = P_INMEM; p2->p_flag2 = p1->p_flag2 & (P2_NOTRACE | P2_NOTRACE_EXEC | P2_TRAPCAP); p2->p_swtick = ticks; if (p1->p_flag & P_PROFIL) startprofclock(p2); /* * Whilst the proc lock is held, copy the VM domain data out * using the VM domain method. */ vm_domain_policy_init(&p2->p_vm_dom_policy); vm_domain_policy_localcopy(&p2->p_vm_dom_policy, &p1->p_vm_dom_policy); if (fr->fr_flags & RFSIGSHARE) { p2->p_sigacts = sigacts_hold(p1->p_sigacts); } else { sigacts_copy(newsigacts, p1->p_sigacts); p2->p_sigacts = newsigacts; } if (fr->fr_flags & RFTSIGZMB) p2->p_sigparent = RFTSIGNUM(fr->fr_flags); else if (fr->fr_flags & RFLINUXTHPN) p2->p_sigparent = SIGUSR1; else p2->p_sigparent = SIGCHLD; p2->p_textvp = p1->p_textvp; p2->p_fd = fd; p2->p_fdtol = fdtol; if (p1->p_flag2 & P2_INHERIT_PROTECTED) { p2->p_flag |= P_PROTECTED; p2->p_flag2 |= P2_INHERIT_PROTECTED; } /* * p_limit is copy-on-write. Bump its refcount. */ lim_fork(p1, p2); thread_cow_get_proc(td2, p2); pstats_fork(p1->p_stats, p2->p_stats); PROC_UNLOCK(p1); PROC_UNLOCK(p2); /* Bump references to the text vnode (for procfs). */ if (p2->p_textvp) vrefact(p2->p_textvp); /* * Set up linkage for kernel based threading. */ if ((fr->fr_flags & RFTHREAD) != 0) { mtx_lock(&ppeers_lock); p2->p_peers = p1->p_peers; p1->p_peers = p2; p2->p_leader = p1->p_leader; mtx_unlock(&ppeers_lock); PROC_LOCK(p1->p_leader); if ((p1->p_leader->p_flag & P_WEXIT) != 0) { PROC_UNLOCK(p1->p_leader); /* * The task leader is exiting, so process p1 is * going to be killed shortly. Since p1 obviously * isn't dead yet, we know that the leader is either * sending SIGKILL's to all the processes in this * task or is sleeping waiting for all the peers to * exit. We let p1 complete the fork, but we need * to go ahead and kill the new process p2 since * the task leader may not get a chance to send * SIGKILL to it. We leave it on the list so that * the task leader will wait for this new process * to commit suicide. */ PROC_LOCK(p2); kern_psignal(p2, SIGKILL); PROC_UNLOCK(p2); } else PROC_UNLOCK(p1->p_leader); } else { p2->p_peers = NULL; p2->p_leader = p2; } sx_xlock(&proctree_lock); PGRP_LOCK(p1->p_pgrp); PROC_LOCK(p2); PROC_LOCK(p1); /* * Preserve some more flags in subprocess. P_PROFIL has already * been preserved. */ p2->p_flag |= p1->p_flag & P_SUGID; td2->td_pflags |= (td->td_pflags & TDP_ALTSTACK) | TDP_FORKING; SESS_LOCK(p1->p_session); if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT) p2->p_flag |= P_CONTROLT; SESS_UNLOCK(p1->p_session); if (fr->fr_flags & RFPPWAIT) p2->p_flag |= P_PPWAIT; p2->p_pgrp = p1->p_pgrp; LIST_INSERT_AFTER(p1, p2, p_pglist); PGRP_UNLOCK(p1->p_pgrp); LIST_INIT(&p2->p_children); LIST_INIT(&p2->p_orphans); callout_init_mtx(&p2->p_itcallout, &p2->p_mtx, 0); /* * If PF_FORK is set, the child process inherits the * procfs ioctl flags from its parent. */ if (p1->p_pfsflags & PF_FORK) { p2->p_stops = p1->p_stops; p2->p_pfsflags = p1->p_pfsflags; } /* * This begins the section where we must prevent the parent * from being swapped. */ _PHOLD(p1); PROC_UNLOCK(p1); /* * Attach the new process to its parent. * * If RFNOWAIT is set, the newly created process becomes a child * of init. This effectively disassociates the child from the * parent. */ if ((fr->fr_flags & RFNOWAIT) != 0) { pptr = p1->p_reaper; p2->p_reaper = pptr; } else { p2->p_reaper = (p1->p_treeflag & P_TREE_REAPER) != 0 ? p1 : p1->p_reaper; pptr = p1; } p2->p_pptr = pptr; LIST_INSERT_HEAD(&pptr->p_children, p2, p_sibling); LIST_INIT(&p2->p_reaplist); LIST_INSERT_HEAD(&p2->p_reaper->p_reaplist, p2, p_reapsibling); if (p2->p_reaper == p1) p2->p_reapsubtree = p2->p_pid; sx_xunlock(&proctree_lock); /* Inform accounting that we have forked. */ p2->p_acflag = AFORK; PROC_UNLOCK(p2); #ifdef KTRACE ktrprocfork(p1, p2); #endif /* * Finish creating the child process. It will return via a different * execution path later. (ie: directly into user mode) */ vm_forkproc(td, p2, td2, vm2, fr->fr_flags); if (fr->fr_flags == (RFFDG | RFPROC)) { VM_CNT_INC(v_forks); VM_CNT_ADD(v_forkpages, p2->p_vmspace->vm_dsize + p2->p_vmspace->vm_ssize); } else if (fr->fr_flags == (RFFDG | RFPROC | RFPPWAIT | RFMEM)) { VM_CNT_INC(v_vforks); VM_CNT_ADD(v_vforkpages, p2->p_vmspace->vm_dsize + p2->p_vmspace->vm_ssize); } else if (p1 == &proc0) { VM_CNT_INC(v_kthreads); VM_CNT_ADD(v_kthreadpages, p2->p_vmspace->vm_dsize + p2->p_vmspace->vm_ssize); } else { VM_CNT_INC(v_rforks); VM_CNT_ADD(v_rforkpages, p2->p_vmspace->vm_dsize + p2->p_vmspace->vm_ssize); } /* * Associate the process descriptor with the process before anything * can happen that might cause that process to need the descriptor. * However, don't do this until after fork(2) can no longer fail. */ if (fr->fr_flags & RFPROCDESC) procdesc_new(p2, fr->fr_pd_flags); /* * Both processes are set up, now check if any loadable modules want * to adjust anything. */ EVENTHANDLER_INVOKE(process_fork, p1, p2, fr->fr_flags); /* * Set the child start time and mark the process as being complete. */ PROC_LOCK(p2); PROC_LOCK(p1); microuptime(&p2->p_stats->p_start); PROC_SLOCK(p2); p2->p_state = PRS_NORMAL; PROC_SUNLOCK(p2); #ifdef KDTRACE_HOOKS /* * Tell the DTrace fasttrap provider about the new process so that any * tracepoints inherited from the parent can be removed. We have to do * this only after p_state is PRS_NORMAL since the fasttrap module will * use pfind() later on. */ if ((fr->fr_flags & RFMEM) == 0 && dtrace_fasttrap_fork) dtrace_fasttrap_fork(p1, p2); #endif /* * Hold the process so that it cannot exit after we make it runnable, * but before we wait for the debugger. */ _PHOLD(p2); if (p1->p_ptevents & PTRACE_FORK) { /* * Arrange for debugger to receive the fork event. * * We can report PL_FLAG_FORKED regardless of * P_FOLLOWFORK settings, but it does not make a sense * for runaway child. */ td->td_dbgflags |= TDB_FORK; td->td_dbg_forked = p2->p_pid; td2->td_dbgflags |= TDB_STOPATFORK; } if (fr->fr_flags & RFPPWAIT) { td->td_pflags |= TDP_RFPPWAIT; td->td_rfppwait_p = p2; td->td_dbgflags |= TDB_VFORK; } PROC_UNLOCK(p2); /* * Now can be swapped. */ _PRELE(p1); PROC_UNLOCK(p1); /* * Tell any interested parties about the new process. */ knote_fork(p1->p_klist, p2->p_pid); SDT_PROBE3(proc, , , create, p2, p1, fr->fr_flags); if (fr->fr_flags & RFPROCDESC) { procdesc_finit(p2->p_procdesc, fp_procdesc); fdrop(fp_procdesc, td); } if ((fr->fr_flags & RFSTOPPED) == 0) { /* * If RFSTOPPED not requested, make child runnable and * add to run queue. */ thread_lock(td2); TD_SET_CAN_RUN(td2); sched_add(td2, SRQ_BORING); thread_unlock(td2); if (fr->fr_pidp != NULL) *fr->fr_pidp = p2->p_pid; } else { *fr->fr_procp = p2; } PROC_LOCK(p2); /* * Wait until debugger is attached to child. */ while (td2->td_proc == p2 && (td2->td_dbgflags & TDB_STOPATFORK) != 0) cv_wait(&p2->p_dbgwait, &p2->p_mtx); _PRELE(p2); racct_proc_fork_done(p2); PROC_UNLOCK(p2); }
/* * Process ioctls */ int procfs_ioctl(PFS_IOCTL_ARGS) { struct procfs_status *ps; #ifdef COMPAT_FREEBSD32 struct procfs_status32 *ps32; #endif int error, flags, sig; #ifdef COMPAT_FREEBSD6 int ival; #endif KASSERT(p != NULL, ("%s() called without a process", __func__)); PROC_LOCK_ASSERT(p, MA_OWNED); error = 0; switch (cmd) { #if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IOC(IOC_IN, 'p', 1, 0): #endif #ifdef COMPAT_FREEBSD6 case _IO('p', 1): ival = IOCPARM_IVAL(data); data = &ival; #endif case PIOCBIS: p->p_stops |= *(unsigned int *)data; break; #if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IOC(IOC_IN, 'p', 2, 0): #endif #ifdef COMPAT_FREEBSD6 case _IO('p', 2): ival = IOCPARM_IVAL(data); data = &ival; #endif case PIOCBIC: p->p_stops &= ~*(unsigned int *)data; break; #if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IOC(IOC_IN, 'p', 3, 0): #endif #ifdef COMPAT_FREEBSD6 case _IO('p', 3): ival = IOCPARM_IVAL(data); data = &ival; #endif case PIOCSFL: flags = *(unsigned int *)data; if (flags & PF_ISUGID) { /* * XXXRW: Is this specific check required here, as * p_candebug() should implement it, or other checks * are missing. */ error = priv_check(td, PRIV_DEBUG_SUGID); if (error) break; } p->p_pfsflags = flags; break; case PIOCGFL: *(unsigned int *)data = p->p_pfsflags; break; case PIOCWAIT: while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) { /* sleep until p stops */ _PHOLD(p); error = msleep(&p->p_stype, &p->p_mtx, PWAIT|PCATCH, "pioctl", 0); _PRELE(p); if (error != 0) break; } /* fall through to PIOCSTATUS */ case PIOCSTATUS: ps = (struct procfs_status *)data; ps->state = (p->p_step == 0); ps->flags = 0; /* nope */ ps->events = p->p_stops; ps->why = p->p_step ? p->p_stype : 0; ps->val = p->p_step ? p->p_xstat : 0; break; #ifdef COMPAT_FREEBSD32 case PIOCWAIT32: while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) { /* sleep until p stops */ _PHOLD(p); error = msleep(&p->p_stype, &p->p_mtx, PWAIT|PCATCH, "pioctl", 0); _PRELE(p); if (error != 0) break; } /* fall through to PIOCSTATUS32 */ case PIOCSTATUS32: ps32 = (struct procfs_status32 *)data; ps32->state = (p->p_step == 0); ps32->flags = 0; /* nope */ ps32->events = p->p_stops; ps32->why = p->p_step ? p->p_stype : 0; ps32->val = p->p_step ? p->p_xstat : 0; break; #endif #if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) case _IOC(IOC_IN, 'p', 5, 0): #endif #ifdef COMPAT_FREEBSD6 case _IO('p', 5): ival = IOCPARM_IVAL(data); data = &ival; #endif case PIOCCONT: if (p->p_step == 0) break; sig = *(unsigned int *)data; if (sig != 0 && !_SIG_VALID(sig)) { error = EINVAL; break; } #if 0 p->p_step = 0; if (P_SHOULDSTOP(p)) { p->p_xstat = sig; p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG); PROC_SLOCK(p); thread_unsuspend(p); PROC_SUNLOCK(p); } else if (sig) kern_psignal(p, sig); #else if (sig) kern_psignal(p, sig); p->p_step = 0; wakeup(&p->p_step); #endif break; default: error = (ENOTTY); } return (error); }