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