merge in netbsd changes.
[unix-history] / usr / src / sys / miscfs / procfs / procfs_ctl.c
CommitLineData
d597ca48 1/*
d597ca48 2 * Copyright (c) 1993 Jan-Simon Pendry
1611db1e
KB
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
d597ca48
JSP
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Jan-Simon Pendry.
8 *
9 * %sccs.include.redist.c%
10 *
679a7c6b 11 * @(#)procfs_ctl.c 8.4 (Berkeley) %G%
d597ca48
JSP
12 *
13 * From:
14 * $Id: procfs_ctl.c,v 3.2 1993/12/15 09:40:17 jsp Exp $
15 */
16
17#include <sys/param.h>
18#include <sys/systm.h>
19#include <sys/time.h>
20#include <sys/kernel.h>
21#include <sys/proc.h>
22#include <sys/vnode.h>
23#include <sys/ioctl.h>
24#include <sys/tty.h>
25#include <sys/resource.h>
26#include <sys/resourcevar.h>
679a7c6b 27#include <sys/ptrace.h>
d597ca48
JSP
28#include <miscfs/procfs/procfs.h>
29
679a7c6b
JSP
30#ifndef FIX_SSTEP
31#define FIX_SSTEP(p)
32#endif
33
34
d597ca48
JSP
35/*
36 * True iff process (p) is in trace wait state
37 * relative to process (curp)
38 */
39#define TRACE_WAIT_P(curp, p) \
40 ((p)->p_stat == SSTOP && \
41 (p)->p_pptr == (curp) && \
42 ((p)->p_flag & P_TRACED))
43
d597ca48
JSP
44#define PROCFS_CTL_ATTACH 1
45#define PROCFS_CTL_DETACH 2
46#define PROCFS_CTL_STEP 3
47#define PROCFS_CTL_RUN 4
48#define PROCFS_CTL_WAIT 5
49
50static vfs_namemap_t ctlnames[] = {
51 /* special /proc commands */
52 { "attach", PROCFS_CTL_ATTACH },
53 { "detach", PROCFS_CTL_DETACH },
54 { "step", PROCFS_CTL_STEP },
55 { "run", PROCFS_CTL_RUN },
56 { "wait", PROCFS_CTL_WAIT },
57 { 0 },
58};
59
60static vfs_namemap_t signames[] = {
61 /* regular signal names */
62 { "hup", SIGHUP }, { "int", SIGINT },
63 { "quit", SIGQUIT }, { "ill", SIGILL },
64 { "trap", SIGTRAP }, { "abrt", SIGABRT },
65 { "iot", SIGIOT }, { "emt", SIGEMT },
66 { "fpe", SIGFPE }, { "kill", SIGKILL },
67 { "bus", SIGBUS }, { "segv", SIGSEGV },
68 { "sys", SIGSYS }, { "pipe", SIGPIPE },
69 { "alrm", SIGALRM }, { "term", SIGTERM },
70 { "urg", SIGURG }, { "stop", SIGSTOP },
71 { "tstp", SIGTSTP }, { "cont", SIGCONT },
72 { "chld", SIGCHLD }, { "ttin", SIGTTIN },
73 { "ttou", SIGTTOU }, { "io", SIGIO },
74 { "xcpu", SIGXCPU }, { "xfsz", SIGXFSZ },
75 { "vtalrm", SIGVTALRM }, { "prof", SIGPROF },
76 { "winch", SIGWINCH }, { "info", SIGINFO },
77 { "usr1", SIGUSR1 }, { "usr2", SIGUSR2 },
78 { 0 },
79};
80
81static int
82procfs_control(curp, p, op)
83 struct proc *curp;
84 struct proc *p;
85 int op;
86{
87 int error;
88
89 /*
90 * Attach - attaches the target process for debugging
91 * by the calling process.
92 */
93 if (op == PROCFS_CTL_ATTACH) {
94 /* check whether already being traced */
95 if (p->p_flag & P_TRACED)
96 return (EBUSY);
97
98 /* can't trace yourself! */
99 if (p->p_pid == curp->p_pid)
100 return (EINVAL);
101
102 /*
103 * Go ahead and set the trace flag.
104 * Save the old parent (it's reset in
105 * _DETACH, and also in kern_exit.c:wait4()
106 * Reparent the process so that the tracing
107 * proc gets to see all the action.
108 * Stop the target.
109 */
110 p->p_flag |= P_TRACED;
111 p->p_xstat = 0; /* XXX ? */
112 if (p->p_pptr != curp) {
113 p->p_oppid = p->p_pptr->p_pid;
114 proc_reparent(p, curp);
115 }
116 psignal(p, SIGSTOP);
117 return (0);
118 }
119
120 /*
121 * Target process must be stopped, owned by (curp) and
122 * be set up for tracing (P_TRACED flag set).
123 * Allow DETACH to take place at any time for sanity.
124 * Allow WAIT any time, of course.
125 */
126 switch (op) {
127 case PROCFS_CTL_DETACH:
128 case PROCFS_CTL_WAIT:
129 break;
130
131 default:
132 if (!TRACE_WAIT_P(curp, p))
133 return (EBUSY);
134 }
135
136 /*
137 * do single-step fixup if needed
138 */
139 FIX_SSTEP(p);
140
141 /*
142 * Don't deliver any signal by default.
143 * To continue with a signal, just send
144 * the signal name to the ctl file
145 */
146 p->p_xstat = 0;
147
148 switch (op) {
149 /*
150 * Detach. Cleans up the target process, reparent it if possible
151 * and set it running once more.
152 */
153 case PROCFS_CTL_DETACH:
154 /* if not being traced, then this is a painless no-op */
155 if ((p->p_flag & P_TRACED) == 0)
156 return (0);
157
158 /* not being traced any more */
159 p->p_flag &= ~P_TRACED;
160
161 /* give process back to original parent */
162 if (p->p_oppid != p->p_pptr->p_pid) {
163 struct proc *pp;
164
165 pp = pfind(p->p_oppid);
166 if (pp)
167 proc_reparent(p, pp);
168 }
169
170 p->p_oppid = 0;
171 p->p_flag &= ~P_WAITED; /* XXX ? */
172 wakeup((caddr_t) curp); /* XXX for CTL_WAIT below ? */
173
174 break;
175
176 /*
177 * Step. Let the target process execute a single instruction.
178 */
179 case PROCFS_CTL_STEP:
679a7c6b
JSP
180 if (error = procfs_sstep(p, 1))
181 return (error);
d597ca48
JSP
182 break;
183
184 /*
185 * Run. Let the target process continue running until a breakpoint
186 * or some other trap.
187 */
188 case PROCFS_CTL_RUN:
189 break;
190
191 /*
192 * Wait for the target process to stop.
193 * If the target is not being traced then just wait
194 * to enter
195 */
196 case PROCFS_CTL_WAIT:
197 error = 0;
198 if (p->p_flag & P_TRACED) {
199 while (error == 0 &&
200 (p->p_stat != SSTOP) &&
201 (p->p_flag & P_TRACED) &&
202 (p->p_pptr == curp)) {
203 error = tsleep((caddr_t) p,
204 PWAIT|PCATCH, "procfsx", 0);
205 }
206 if (error == 0 && !TRACE_WAIT_P(curp, p))
207 error = EBUSY;
208 } else {
209 while (error == 0 && p->p_stat != SSTOP) {
210 error = tsleep((caddr_t) p,
211 PWAIT|PCATCH, "procfs", 0);
212 }
213 }
214 return (error);
215
216 default:
217 panic("procfs_control");
218 }
219
220 if (p->p_stat == SSTOP)
221 setrunnable(p);
222 return (0);
223}
224
225int
226procfs_doctl(curp, p, pfs, uio)
227 struct proc *curp;
228 struct pfsnode *pfs;
229 struct uio *uio;
230 struct proc *p;
231{
d597ca48
JSP
232 int xlen;
233 int error;
d597ca48 234 char msg[PROCFS_CTLLEN+1];
d597ca48
JSP
235 vfs_namemap_t *nm;
236
237 if (uio->uio_rw != UIO_WRITE)
238 return (EOPNOTSUPP);
239
240 xlen = PROCFS_CTLLEN;
241 error = vfs_getuserstr(uio, msg, &xlen);
242 if (error)
243 return (error);
244
245 /*
246 * Map signal names into signal generation
247 * or debug control. Unknown commands and/or signals
248 * return EOPNOTSUPP.
249 *
250 * Sending a signal while the process is being debugged
251 * also has the side effect of letting the target continue
252 * to run. There is no way to single-step a signal delivery.
253 */
254 error = EOPNOTSUPP;
255
256 nm = vfs_findname(ctlnames, msg, xlen);
257 if (nm) {
258 error = procfs_control(curp, p, nm->nm_val);
259 } else {
260 nm = vfs_findname(signames, msg, xlen);
261 if (nm) {
262 if (TRACE_WAIT_P(curp, p)) {
263 p->p_xstat = nm->nm_val;
264 FIX_SSTEP(p);
265 setrunnable(p);
266 } else {
267 psignal(p, nm->nm_val);
268 }
269 error = 0;
270 }
271 }
272
273 return (error);
274}