procfs_ioctl.c revision 169168
1238104Sdes/*- 2238104Sdes * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav 3238104Sdes * All rights reserved. 4238104Sdes * 5238104Sdes * Redistribution and use in source and binary forms, with or without 6238104Sdes * modification, are permitted provided that the following conditions 7238104Sdes * are met: 8238104Sdes * 1. Redistributions of source code must retain the above copyright 9238104Sdes * notice, this list of conditions and the following disclaimer 10238104Sdes * in this position and unchanged. 11238104Sdes * 2. Redistributions in binary form must reproduce the above copyright 12238104Sdes * notice, this list of conditions and the following disclaimer in the 13238104Sdes * documentation and/or other materials provided with the distribution. 14238104Sdes * 3. The name of the author may not be used to endorse or promote products 15238104Sdes * derived from this software without specific prior written permission. 16238104Sdes * 17238104Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18238104Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19238104Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20238104Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21238104Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22238104Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23238104Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24238104Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25238104Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26238104Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27238104Sdes * 28238104Sdes * $FreeBSD: head/sys/fs/procfs/procfs_ioctl.c 169168 2007-05-01 12:59:20Z des $ 29238104Sdes */ 30238104Sdes 31238104Sdes#include "opt_compat.h" 32238104Sdes 33238104Sdes#include <sys/param.h> 34238104Sdes#include <sys/lock.h> 35238104Sdes#include <sys/mutex.h> 36238104Sdes#include <sys/pioctl.h> 37238104Sdes#include <sys/priv.h> 38238104Sdes#include <sys/proc.h> 39238104Sdes#include <sys/signalvar.h> 40238104Sdes#include <sys/systm.h> 41238104Sdes 42238104Sdes#include <fs/pseudofs/pseudofs.h> 43238104Sdes#include <fs/procfs/procfs.h> 44238104Sdes 45238104Sdes#ifdef COMPAT_IA32 46238104Sdesstruct procfs_status32 { 47238104Sdes int state; /* Running, stopped, something else? */ 48238104Sdes int flags; /* Any flags */ 49238104Sdes unsigned int events; /* Events to stop on */ 50238104Sdes int why; /* What event, if any, proc stopped on */ 51238104Sdes unsigned int val; /* Any extra data */ 52238104Sdes}; 53238104Sdes 54238104Sdes#define PIOCWAIT32 _IOR('p', 4, struct procfs_status32) 55238104Sdes#define PIOCSTATUS32 _IOR('p', 6, struct procfs_status32) 56238104Sdes#endif 57238104Sdes 58238104Sdes/* 59238104Sdes * Process ioctls 60238104Sdes */ 61238104Sdesint 62238104Sdesprocfs_ioctl(PFS_IOCTL_ARGS) 63238104Sdes{ 64238104Sdes struct procfs_status *ps; 65238104Sdes#ifdef COMPAT_IA32 66238104Sdes struct procfs_status32 *ps32; 67238104Sdes#endif 68238104Sdes int error, flags, sig; 69238104Sdes#ifdef COMPAT_FREEBSD6 70238104Sdes int ival; 71238104Sdes#endif 72238104Sdes 73238104Sdes KASSERT(p != NULL, 74238104Sdes ("%s() called without a process", __func__)); 75238104Sdes PROC_LOCK_ASSERT(p, MA_OWNED); 76238104Sdes 77238104Sdes error = 0; 78238104Sdes switch (cmd) { 79238104Sdes#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 80238104Sdes case _IOC(IOC_IN, 'p', 1, 0): 81238104Sdes#endif 82238104Sdes#ifdef COMPAT_FREEBSD6 83238104Sdes case _IO('p', 1): 84238104Sdes ival = IOCPARM_IVAL(data); 85238104Sdes data = &ival; 86238104Sdes#endif 87238104Sdes case PIOCBIS: 88238104Sdes p->p_stops |= *(unsigned int *)data; 89238104Sdes break; 90238104Sdes#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 91238104Sdes case _IOC(IOC_IN, 'p', 2, 0): 92238104Sdes#endif 93238104Sdes#ifdef COMPAT_FREEBSD6 94238104Sdes case _IO('p', 2): 95238104Sdes ival = IOCPARM_IVAL(data); 96238104Sdes data = &ival; 97238104Sdes#endif 98238104Sdes case PIOCBIC: 99238104Sdes p->p_stops &= ~*(unsigned int *)data; 100238104Sdes break; 101238104Sdes#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 102238104Sdes case _IOC(IOC_IN, 'p', 3, 0): 103238104Sdes#endif 104238104Sdes#ifdef COMPAT_FREEBSD6 105238104Sdes case _IO('p', 3): 106238104Sdes ival = IOCPARM_IVAL(data); 107238104Sdes data = &ival; 108238104Sdes#endif 109238104Sdes case PIOCSFL: 110238104Sdes flags = *(unsigned int *)data; 111238104Sdes if (flags & PF_ISUGID) { 112238104Sdes /* 113238104Sdes * XXXRW: Is this specific check required here, as 114238104Sdes * p_candebug() should implement it, or other checks 115238104Sdes * are missing. 116238104Sdes */ 117238104Sdes error = priv_check_cred(td->td_ucred, 118238104Sdes PRIV_DEBUG_SUGID, SUSER_ALLOWJAIL); 119238104Sdes if (error) 120238104Sdes break; 121238104Sdes } 122238104Sdes p->p_pfsflags = flags; 123238104Sdes break; 124238104Sdes case PIOCGFL: 125238104Sdes *(unsigned int *)data = p->p_pfsflags; 126238104Sdes break; 127238104Sdes case PIOCWAIT: 128238104Sdes while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) { 129238104Sdes /* sleep until p stops */ 130238104Sdes _PHOLD(p); 131238104Sdes error = msleep(&p->p_stype, &p->p_mtx, 132238104Sdes PWAIT|PCATCH, "pioctl", 0); 133238104Sdes _PRELE(p); 134238104Sdes if (error != 0) 135238104Sdes break; 136238104Sdes } 137238104Sdes /* fall through to PIOCSTATUS */ 138238104Sdes case PIOCSTATUS: 139238104Sdes ps = (struct procfs_status *)data; 140238104Sdes ps->state = (p->p_step == 0); 141269257Sdes ps->flags = 0; /* nope */ 142269257Sdes ps->events = p->p_stops; 143269257Sdes ps->why = p->p_step ? p->p_stype : 0; 144238104Sdes ps->val = p->p_step ? p->p_xstat : 0; 145238104Sdes break; 146238104Sdes#ifdef COMPAT_IA32 147238104Sdes case PIOCWAIT32: 148238104Sdes while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) { 149238104Sdes /* sleep until p stops */ 150238104Sdes _PHOLD(p); 151238104Sdes error = msleep(&p->p_stype, &p->p_mtx, 152238104Sdes PWAIT|PCATCH, "pioctl", 0); 153238104Sdes _PRELE(p); 154238104Sdes if (error != 0) 155238104Sdes break; 156238104Sdes } 157238104Sdes /* fall through to PIOCSTATUS32 */ 158269257Sdes case PIOCSTATUS32: 159269257Sdes ps32 = (struct procfs_status32 *)data; 160269257Sdes ps32->state = (p->p_step == 0); 161269257Sdes ps32->flags = 0; /* nope */ 162269257Sdes ps32->events = p->p_stops; 163269257Sdes ps32->why = p->p_step ? p->p_stype : 0; 164269257Sdes ps32->val = p->p_step ? p->p_xstat : 0; 165238104Sdes break; 166238104Sdes#endif 167238104Sdes#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43) 168238104Sdes case _IOC(IOC_IN, 'p', 5, 0): 169238104Sdes#endif 170238104Sdes#ifdef COMPAT_FREEBSD6 171238104Sdes case _IO('p', 5): 172238104Sdes ival = IOCPARM_IVAL(data); 173238104Sdes data = &ival; 174238104Sdes#endif 175238104Sdes case PIOCCONT: 176238104Sdes if (p->p_step == 0) 177238104Sdes break; 178238104Sdes sig = *(unsigned int *)data; 179238104Sdes if (sig != 0 && !_SIG_VALID(sig)) { 180238104Sdes error = EINVAL; 181238104Sdes break; 182238104Sdes } 183238104Sdes#if 0 184238104Sdes p->p_step = 0; 185238104Sdes if (P_SHOULDSTOP(p)) { 186238104Sdes p->p_xstat = sig; 187238104Sdes p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG); 188238104Sdes mtx_lock_spin(&sched_lock); 189238104Sdes thread_unsuspend(p); 190238104Sdes mtx_unlock_spin(&sched_lock); 191238104Sdes } else if (sig) 192238104Sdes psignal(p, sig); 193238104Sdes#else 194238104Sdes if (sig) 195238104Sdes psignal(p, sig); 196238104Sdes p->p_step = 0; 197238104Sdes wakeup(&p->p_step); 198238104Sdes#endif 199238104Sdes break; 200238104Sdes default: 201238104Sdes error = (ENOTTY); 202238104Sdes } 203238104Sdes 204238104Sdes return (error); 205238104Sdes} 206238104Sdes 207238104Sdes/* 208238104Sdes * Clean up on last close 209238104Sdes */ 210238104Sdesint 211238104Sdesprocfs_close(PFS_CLOSE_ARGS) 212238104Sdes{ 213238104Sdes if (p != NULL && (p->p_pfsflags & PF_LINGER) == 0) { 214238104Sdes PROC_LOCK_ASSERT(p, MA_OWNED); 215238104Sdes p->p_pfsflags = 0; 216238104Sdes p->p_stops = 0; 217238104Sdes p->p_step = 0; 218238104Sdes wakeup(&p->p_step); 219238104Sdes } 220238104Sdes return (0); 221238104Sdes} 222238104Sdes