procfs_ioctl.c revision 170307
187321Sdes/*-
287321Sdes * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
387321Sdes * All rights reserved.
487321Sdes *
587321Sdes * Redistribution and use in source and binary forms, with or without
687321Sdes * modification, are permitted provided that the following conditions
787321Sdes * are met:
887321Sdes * 1. Redistributions of source code must retain the above copyright
987321Sdes *    notice, this list of conditions and the following disclaimer
1087321Sdes *    in this position and unchanged.
1187321Sdes * 2. Redistributions in binary form must reproduce the above copyright
1287321Sdes *    notice, this list of conditions and the following disclaimer in the
1387321Sdes *    documentation and/or other materials provided with the distribution.
1487321Sdes * 3. The name of the author may not be used to endorse or promote products
1587321Sdes *    derived from this software without specific prior written permission.
1687321Sdes *
1787321Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1887321Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1987321Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2087321Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2187321Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2287321Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2387321Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2487321Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2587321Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2687321Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2787321Sdes *
2887321Sdes *      $FreeBSD: head/sys/fs/procfs/procfs_ioctl.c 170307 2007-06-05 00:00:57Z jeff $
2987321Sdes */
3087321Sdes
31147676Speter#include "opt_compat.h"
32147676Speter
3387321Sdes#include <sys/param.h>
3487321Sdes#include <sys/lock.h>
3587321Sdes#include <sys/mutex.h>
3687321Sdes#include <sys/pioctl.h>
37164033Srwatson#include <sys/priv.h>
3887321Sdes#include <sys/proc.h>
3987321Sdes#include <sys/signalvar.h>
4087321Sdes#include <sys/systm.h>
4187321Sdes
4287321Sdes#include <fs/pseudofs/pseudofs.h>
4387321Sdes#include <fs/procfs/procfs.h>
4487321Sdes
45147692Speter#ifdef COMPAT_IA32
46147692Speterstruct procfs_status32 {
47147692Speter	int	state;	/* Running, stopped, something else? */
48147692Speter	int	flags;	/* Any flags */
49147692Speter	unsigned int	events;	/* Events to stop on */
50147692Speter	int	why;	/* What event, if any, proc stopped on */
51147692Speter	unsigned int	val;	/* Any extra data */
52147692Speter};
53147692Speter
54147692Speter#define	PIOCWAIT32	_IOR('p', 4, struct procfs_status32)
55147692Speter#define	PIOCSTATUS32	_IOR('p', 6, struct procfs_status32)
56147692Speter#endif
57147692Speter
5887321Sdes/*
5987321Sdes * Process ioctls
6087321Sdes */
6187321Sdesint
6287321Sdesprocfs_ioctl(PFS_IOCTL_ARGS)
6387321Sdes{
6487321Sdes	struct procfs_status *ps;
65147692Speter#ifdef COMPAT_IA32
66147692Speter	struct procfs_status32 *ps32;
67147692Speter#endif
6887542Sdes	int error, flags, sig;
69162711Sru#ifdef COMPAT_FREEBSD6
70162711Sru	int ival;
71162711Sru#endif
7287321Sdes
73169168Sdes	KASSERT(p != NULL,
74169168Sdes	    ("%s() called without a process", __func__));
75169168Sdes	PROC_LOCK_ASSERT(p, MA_OWNED);
76169168Sdes
7787321Sdes	error = 0;
7887321Sdes	switch (cmd) {
79147676Speter#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
80147676Speter	case _IOC(IOC_IN, 'p', 1, 0):
81147676Speter#endif
82162711Sru#ifdef COMPAT_FREEBSD6
83162711Sru	case _IO('p', 1):
84162711Sru		ival = IOCPARM_IVAL(data);
85162711Sru		data = &ival;
86162711Sru#endif
8787321Sdes	case PIOCBIS:
88162711Sru		p->p_stops |= *(unsigned int *)data;
8987321Sdes		break;
90147676Speter#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
91147676Speter	case _IOC(IOC_IN, 'p', 2, 0):
92147676Speter#endif
93162711Sru#ifdef COMPAT_FREEBSD6
94162711Sru	case _IO('p', 2):
95162711Sru		ival = IOCPARM_IVAL(data);
96162711Sru		data = &ival;
97162711Sru#endif
9887321Sdes	case PIOCBIC:
99162711Sru		p->p_stops &= ~*(unsigned int *)data;
10087321Sdes		break;
101147676Speter#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
102147676Speter	case _IOC(IOC_IN, 'p', 3, 0):
103147676Speter#endif
104162711Sru#ifdef COMPAT_FREEBSD6
105162711Sru	case _IO('p', 3):
106162711Sru		ival = IOCPARM_IVAL(data);
107162711Sru		data = &ival;
108162711Sru#endif
10987321Sdes	case PIOCSFL:
110162711Sru		flags = *(unsigned int *)data;
111164033Srwatson		if (flags & PF_ISUGID) {
112164033Srwatson			/*
113164033Srwatson			 * XXXRW: Is this specific check required here, as
114164033Srwatson			 * p_candebug() should implement it, or other checks
115164033Srwatson			 * are missing.
116164033Srwatson			 */
117166826Srwatson			error = priv_check_cred(td->td_ucred,
118166826Srwatson			    PRIV_DEBUG_SUGID, SUSER_ALLOWJAIL);
119164033Srwatson			if (error)
120164033Srwatson				break;
121164033Srwatson		}
12287542Sdes		p->p_pfsflags = flags;
12387321Sdes		break;
12487321Sdes	case PIOCGFL:
12587542Sdes		*(unsigned int *)data = p->p_pfsflags;
12687321Sdes		break;
12787321Sdes	case PIOCWAIT:
128164356Skib		while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) {
12987321Sdes			/* sleep until p stops */
130169168Sdes			_PHOLD(p);
13187321Sdes			error = msleep(&p->p_stype, &p->p_mtx,
13287321Sdes			    PWAIT|PCATCH, "pioctl", 0);
133169168Sdes			_PRELE(p);
13487321Sdes			if (error != 0)
13587321Sdes				break;
13687321Sdes		}
13787321Sdes		/* fall through to PIOCSTATUS */
13887321Sdes	case PIOCSTATUS:
13987321Sdes		ps = (struct procfs_status *)data;
14087321Sdes		ps->state = (p->p_step == 0);
14187321Sdes		ps->flags = 0; /* nope */
14287321Sdes		ps->events = p->p_stops;
14387321Sdes		ps->why = p->p_step ? p->p_stype : 0;
14487321Sdes		ps->val = p->p_step ? p->p_xstat : 0;
14587321Sdes		break;
146147692Speter#ifdef COMPAT_IA32
147147692Speter	case PIOCWAIT32:
148164356Skib		while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) {
149147692Speter			/* sleep until p stops */
150169168Sdes			_PHOLD(p);
151147692Speter			error = msleep(&p->p_stype, &p->p_mtx,
152147692Speter			    PWAIT|PCATCH, "pioctl", 0);
153169168Sdes			_PRELE(p);
154147692Speter			if (error != 0)
155147692Speter				break;
156147692Speter		}
157147692Speter		/* fall through to PIOCSTATUS32 */
158147692Speter	case PIOCSTATUS32:
159147692Speter		ps32 = (struct procfs_status32 *)data;
160147692Speter		ps32->state = (p->p_step == 0);
161147692Speter		ps32->flags = 0; /* nope */
162147692Speter		ps32->events = p->p_stops;
163147692Speter		ps32->why = p->p_step ? p->p_stype : 0;
164147692Speter		ps32->val = p->p_step ? p->p_xstat : 0;
165147692Speter		break;
166147692Speter#endif
167147676Speter#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
168147676Speter	case _IOC(IOC_IN, 'p', 5, 0):
169147676Speter#endif
170162711Sru#ifdef COMPAT_FREEBSD6
171162711Sru	case _IO('p', 5):
172162711Sru		ival = IOCPARM_IVAL(data);
173162711Sru		data = &ival;
174162711Sru#endif
17587321Sdes	case PIOCCONT:
17687542Sdes		if (p->p_step == 0)
17787321Sdes			break;
178162711Sru		sig = *(unsigned int *)data;
17987542Sdes		if (sig != 0 && !_SIG_VALID(sig)) {
18087321Sdes			error = EINVAL;
18187321Sdes			break;
18287321Sdes		}
18387321Sdes#if 0
18487321Sdes		p->p_step = 0;
18599072Sjulian		if (P_SHOULDSTOP(p)) {
18687321Sdes			p->p_xstat = sig;
187102950Sdavidxu			p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG);
188170307Sjeff			PROC_SLOCK(p);
189103216Sjulian			thread_unsuspend(p);
190170307Sjeff			PROC_SUNLOCK(p);
191113618Sjhb		} else if (sig)
192113618Sjhb			psignal(p, sig);
19387321Sdes#else
19487321Sdes		if (sig)
19587321Sdes			psignal(p, sig);
19687542Sdes		p->p_step = 0;
19787321Sdes		wakeup(&p->p_step);
19887321Sdes#endif
19987321Sdes		break;
20087321Sdes	default:
20187321Sdes		error = (ENOTTY);
20287321Sdes	}
203123247Sdes
20487321Sdes	return (error);
20587321Sdes}
20687321Sdes
20787321Sdes/*
20887321Sdes * Clean up on last close
20987321Sdes */
21087321Sdesint
21187321Sdesprocfs_close(PFS_CLOSE_ARGS)
21287321Sdes{
21387321Sdes	if (p != NULL && (p->p_pfsflags & PF_LINGER) == 0) {
214113618Sjhb		PROC_LOCK_ASSERT(p, MA_OWNED);
21587321Sdes		p->p_pfsflags = 0;
21687321Sdes		p->p_stops = 0;
21787321Sdes		p->p_step = 0;
21887321Sdes		wakeup(&p->p_step);
21987321Sdes	}
22087321Sdes	return (0);
22187321Sdes}
222