187321Sdes/*-
2230132Suqs * 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$
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
45205014Snwhitehorn#ifdef COMPAT_FREEBSD32
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;
65205014Snwhitehorn#ifdef COMPAT_FREEBSD32
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			 */
117170587Srwatson			error = priv_check(td, PRIV_DEBUG_SUGID);
118164033Srwatson			if (error)
119164033Srwatson				break;
120164033Srwatson		}
12187542Sdes		p->p_pfsflags = flags;
12287321Sdes		break;
12387321Sdes	case PIOCGFL:
12487542Sdes		*(unsigned int *)data = p->p_pfsflags;
12587321Sdes		break;
12687321Sdes	case PIOCWAIT:
127164356Skib		while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) {
12887321Sdes			/* sleep until p stops */
129169168Sdes			_PHOLD(p);
13087321Sdes			error = msleep(&p->p_stype, &p->p_mtx,
13187321Sdes			    PWAIT|PCATCH, "pioctl", 0);
132169168Sdes			_PRELE(p);
13387321Sdes			if (error != 0)
13487321Sdes				break;
13587321Sdes		}
13687321Sdes		/* fall through to PIOCSTATUS */
13787321Sdes	case PIOCSTATUS:
13887321Sdes		ps = (struct procfs_status *)data;
13987321Sdes		ps->state = (p->p_step == 0);
14087321Sdes		ps->flags = 0; /* nope */
14187321Sdes		ps->events = p->p_stops;
14287321Sdes		ps->why = p->p_step ? p->p_stype : 0;
14387321Sdes		ps->val = p->p_step ? p->p_xstat : 0;
14487321Sdes		break;
145205014Snwhitehorn#ifdef COMPAT_FREEBSD32
146147692Speter	case PIOCWAIT32:
147164356Skib		while (p->p_step == 0 && (p->p_flag & P_WEXIT) == 0) {
148147692Speter			/* sleep until p stops */
149169168Sdes			_PHOLD(p);
150147692Speter			error = msleep(&p->p_stype, &p->p_mtx,
151147692Speter			    PWAIT|PCATCH, "pioctl", 0);
152169168Sdes			_PRELE(p);
153147692Speter			if (error != 0)
154147692Speter				break;
155147692Speter		}
156147692Speter		/* fall through to PIOCSTATUS32 */
157147692Speter	case PIOCSTATUS32:
158147692Speter		ps32 = (struct procfs_status32 *)data;
159147692Speter		ps32->state = (p->p_step == 0);
160147692Speter		ps32->flags = 0; /* nope */
161147692Speter		ps32->events = p->p_stops;
162147692Speter		ps32->why = p->p_step ? p->p_stype : 0;
163147692Speter		ps32->val = p->p_step ? p->p_xstat : 0;
164147692Speter		break;
165147692Speter#endif
166147676Speter#if defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4) || defined(COMPAT_43)
167147676Speter	case _IOC(IOC_IN, 'p', 5, 0):
168147676Speter#endif
169162711Sru#ifdef COMPAT_FREEBSD6
170162711Sru	case _IO('p', 5):
171162711Sru		ival = IOCPARM_IVAL(data);
172162711Sru		data = &ival;
173162711Sru#endif
17487321Sdes	case PIOCCONT:
17587542Sdes		if (p->p_step == 0)
17687321Sdes			break;
177162711Sru		sig = *(unsigned int *)data;
17887542Sdes		if (sig != 0 && !_SIG_VALID(sig)) {
17987321Sdes			error = EINVAL;
18087321Sdes			break;
18187321Sdes		}
18287321Sdes#if 0
18387321Sdes		p->p_step = 0;
18499072Sjulian		if (P_SHOULDSTOP(p)) {
18587321Sdes			p->p_xstat = sig;
186102950Sdavidxu			p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG);
187170307Sjeff			PROC_SLOCK(p);
188103216Sjulian			thread_unsuspend(p);
189170307Sjeff			PROC_SUNLOCK(p);
190113618Sjhb		} else if (sig)
191225617Skmacy			kern_psignal(p, sig);
19287321Sdes#else
19387321Sdes		if (sig)
194225617Skmacy			kern_psignal(p, sig);
19587542Sdes		p->p_step = 0;
19687321Sdes		wakeup(&p->p_step);
19787321Sdes#endif
19887321Sdes		break;
19987321Sdes	default:
20087321Sdes		error = (ENOTTY);
20187321Sdes	}
202123247Sdes
20387321Sdes	return (error);
20487321Sdes}
20587321Sdes
20687321Sdes/*
20787321Sdes * Clean up on last close
20887321Sdes */
20987321Sdesint
21087321Sdesprocfs_close(PFS_CLOSE_ARGS)
21187321Sdes{
21287321Sdes	if (p != NULL && (p->p_pfsflags & PF_LINGER) == 0) {
213113618Sjhb		PROC_LOCK_ASSERT(p, MA_OWNED);
21487321Sdes		p->p_pfsflags = 0;
21587321Sdes		p->p_stops = 0;
21687321Sdes		p->p_step = 0;
21787321Sdes		wakeup(&p->p_step);
21887321Sdes	}
21987321Sdes	return (0);
22087321Sdes}
221