procfs_ioctl.c revision 166826
1317027Sdim/*- 2317027Sdim * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav 3317027Sdim * All rights reserved. 4317027Sdim * 5317027Sdim * Redistribution and use in source and binary forms, with or without 6317027Sdim * modification, are permitted provided that the following conditions 7317027Sdim * are met: 8317027Sdim * 1. Redistributions of source code must retain the above copyright 9317027Sdim * notice, this list of conditions and the following disclaimer 10317027Sdim * in this position and unchanged. 11317027Sdim * 2. Redistributions in binary form must reproduce the above copyright 12317027Sdim * notice, this list of conditions and the following disclaimer in the 13317027Sdim * documentation and/or other materials provided with the distribution. 14317027Sdim * 3. The name of the author may not be used to endorse or promote products 15317027Sdim * derived from this software without specific prior written permission. 16317027Sdim * 17317027Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18317027Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19317027Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20317027Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21317027Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22317027Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23317027Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24317027Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25317027Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26317027Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27317027Sdim * 28317027Sdim * $FreeBSD: head/sys/fs/procfs/procfs_ioctl.c 166826 2007-02-19 13:04:25Z rwatson $ 29317027Sdim */ 30317027Sdim 31317027Sdim#include "opt_compat.h" 32317027Sdim 33317027Sdim#include <sys/param.h> 34317027Sdim#include <sys/lock.h> 35317027Sdim#include <sys/mutex.h> 36317027Sdim#include <sys/pioctl.h> 37317027Sdim#include <sys/priv.h> 38317027Sdim#include <sys/proc.h> 39317027Sdim#include <sys/signalvar.h> 40317027Sdim#include <sys/systm.h> 41317027Sdim 42317027Sdim#include <fs/pseudofs/pseudofs.h> 43317027Sdim#include <fs/procfs/procfs.h> 44317027Sdim 45317027Sdim#ifdef COMPAT_IA32 46317027Sdimstruct procfs_status32 { 47317027Sdim int state; /* Running, stopped, something else? */ 48317027Sdim int flags; /* Any flags */ 49317027Sdim unsigned int events; /* Events to stop on */ 50317027Sdim int why; /* What event, if any, proc stopped on */ 51317027Sdim unsigned int val; /* Any extra data */ 52317027Sdim}; 53317027Sdim 54317027Sdim#define PIOCWAIT32 _IOR('p', 4, struct procfs_status32) 55317027Sdim#define PIOCSTATUS32 _IOR('p', 6, struct procfs_status32) 56317027Sdim#endif 57317027Sdim 58317027Sdim/* 59317027Sdim * Process ioctls 60317027Sdim */ 61317027Sdimint 62317027Sdimprocfs_ioctl(PFS_IOCTL_ARGS) 63317027Sdim{ 64317027Sdim struct procfs_status *ps; 65317027Sdim#ifdef COMPAT_IA32 66317027Sdim struct procfs_status32 *ps32; 67317027Sdim#endif 68317027Sdim int error, flags, sig; 69317027Sdim#ifdef COMPAT_FREEBSD6 70317027Sdim int ival; 71317027Sdim#endif 72317027Sdim 73317027Sdim PROC_LOCK(p); 74317027Sdim error = 0; 75317027Sdim switch (cmd) { 76317027Sdim#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 77317027Sdim case _IOC(IOC_IN, 'p', 1, 0): 78317027Sdim#endif 79317027Sdim#ifdef COMPAT_FREEBSD6 80317027Sdim case _IO('p', 1): 81317027Sdim ival = IOCPARM_IVAL(data); 82317027Sdim data = &ival; 83317027Sdim#endif 84317027Sdim case PIOCBIS: 85317027Sdim p->p_stops |= *(unsigned int *)data; 86317027Sdim break; 87317027Sdim#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 88317027Sdim case _IOC(IOC_IN, 'p', 2, 0): 89317027Sdim#endif 90317027Sdim#ifdef COMPAT_FREEBSD6 91317027Sdim case _IO('p', 2): 92317027Sdim ival = IOCPARM_IVAL(data); 93317027Sdim data = &ival; 94317027Sdim#endif 95317027Sdim case PIOCBIC: 96317027Sdim p->p_stops &= ~*(unsigned int *)data; 97317027Sdim break; 98317027Sdim#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 99317027Sdim case _IOC(IOC_IN, 'p', 3, 0): 100317027Sdim#endif 101317027Sdim#ifdef COMPAT_FREEBSD6 102317027Sdim case _IO('p', 3): 103317027Sdim ival = IOCPARM_IVAL(data); 104317027Sdim data = &ival; 105317027Sdim#endif 106317027Sdim case PIOCSFL: 107317027Sdim flags = *(unsigned int *)data; 108317027Sdim if (flags & PF_ISUGID) { 109317027Sdim /* 110317027Sdim * XXXRW: Is this specific check required here, as 111317027Sdim * p_candebug() should implement it, or other checks 112317027Sdim * are missing. 113317027Sdim */ 114317027Sdim error = priv_check_cred(td->td_ucred, 115317027Sdim PRIV_DEBUG_SUGID, SUSER_ALLOWJAIL); 116317027Sdim if (error) 117317027Sdim break; 118317027Sdim } 119317027Sdim p->p_pfsflags = flags; 120317027Sdim break; 121317027Sdim case PIOCGFL: 122317027Sdim *(unsigned int *)data = p->p_pfsflags; 123317027Sdim break; 124317027Sdim case PIOCWAIT: 125317027Sdim while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) { 126317027Sdim /* sleep until p stops */ 127317027Sdim error = msleep(&p->p_stype, &p->p_mtx, 128317027Sdim PWAIT|PCATCH, "pioctl", 0); 129317027Sdim if (error != 0) 130317027Sdim break; 131317027Sdim } 132317027Sdim /* fall through to PIOCSTATUS */ 133317027Sdim case PIOCSTATUS: 134317027Sdim ps = (struct procfs_status *)data; 135317027Sdim ps->state = (p->p_step == 0); 136317027Sdim ps->flags = 0; /* nope */ 137317027Sdim ps->events = p->p_stops; 138317027Sdim ps->why = p->p_step ? p->p_stype : 0; 139317027Sdim ps->val = p->p_step ? p->p_xstat : 0; 140317027Sdim break; 141317027Sdim#ifdef COMPAT_IA32 142317027Sdim case PIOCWAIT32: 143317027Sdim while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) { 144317027Sdim /* sleep until p stops */ 145317027Sdim error = msleep(&p->p_stype, &p->p_mtx, 146317027Sdim PWAIT|PCATCH, "pioctl", 0); 147317027Sdim if (error != 0) 148317027Sdim break; 149317027Sdim } 150317027Sdim /* fall through to PIOCSTATUS32 */ 151317027Sdim case PIOCSTATUS32: 152317027Sdim ps32 = (struct procfs_status32 *)data; 153317027Sdim ps32->state = (p->p_step == 0); 154317027Sdim ps32->flags = 0; /* nope */ 155317027Sdim ps32->events = p->p_stops; 156317027Sdim ps32->why = p->p_step ? p->p_stype : 0; 157317027Sdim ps32->val = p->p_step ? p->p_xstat : 0; 158317027Sdim break; 159317027Sdim#endif 160317027Sdim#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 161317027Sdim case _IOC(IOC_IN, 'p', 5, 0): 162317027Sdim#endif 163317027Sdim#ifdef COMPAT_FREEBSD6 164317027Sdim case _IO('p', 5): 165317027Sdim ival = IOCPARM_IVAL(data); 166317027Sdim data = &ival; 167317027Sdim#endif 168317027Sdim case PIOCCONT: 169317027Sdim if (p->p_step == 0) 170317027Sdim break; 171317027Sdim sig = *(unsigned int *)data; 172317027Sdim if (sig != 0 && !_SIG_VALID(sig)) { 173317027Sdim error = EINVAL; 174317027Sdim break; 175317027Sdim } 176317027Sdim#if 0 177317027Sdim p->p_step = 0; 178317027Sdim if (P_SHOULDSTOP(p)) { 179317027Sdim p->p_xstat = sig; 180317027Sdim p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG); 181317027Sdim mtx_lock_spin(&sched_lock); 182317027Sdim thread_unsuspend(p); 183317027Sdim mtx_unlock_spin(&sched_lock); 184317027Sdim } else if (sig) 185317027Sdim psignal(p, sig); 186317027Sdim#else 187317027Sdim if (sig) 188317027Sdim psignal(p, sig); 189317027Sdim p->p_step = 0; 190317027Sdim wakeup(&p->p_step); 191317027Sdim#endif 192317027Sdim break; 193317027Sdim default: 194317027Sdim error = (ENOTTY); 195317027Sdim } 196317027Sdim PROC_UNLOCK(p); 197317027Sdim 198317027Sdim return (error); 199317027Sdim} 200317027Sdim 201317027Sdim/* 202317027Sdim * Clean up on last close 203317027Sdim */ 204317027Sdimint 205317027Sdimprocfs_close(PFS_CLOSE_ARGS) 206317027Sdim{ 207317027Sdim if (p != NULL && (p->p_pfsflags & PF_LINGER) == 0) { 208317027Sdim PROC_LOCK_ASSERT(p, MA_OWNED); 209317027Sdim p->p_pfsflags = 0; 210317027Sdim p->p_stops = 0; 211317027Sdim p->p_step = 0; 212317027Sdim wakeup(&p->p_step); 213317027Sdim } 214317027Sdim return (0); 215317027Sdim} 216317027Sdim