Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * Copyright (c) 1982, 1986, 1989, 1991, 1993 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | * @(#)kern_proc.c 8.7 (Berkeley) 2/14/95 | |
34 | * $FreeBSD: src/sys/kern/kern_proc.c,v 1.63.2.9 2003/05/08 07:47:16 kbyanc Exp $ | |
b8acf5a9 | 35 | * $DragonFly: src/sys/kern/kern_proc.c,v 1.7 2003/06/28 02:36:43 dillon Exp $ |
984263bc MD |
36 | */ |
37 | ||
38 | #include <sys/param.h> | |
39 | #include <sys/systm.h> | |
40 | #include <sys/kernel.h> | |
41 | #include <sys/sysctl.h> | |
42 | #include <sys/malloc.h> | |
43 | #include <sys/proc.h> | |
44 | #include <sys/filedesc.h> | |
45 | #include <sys/tty.h> | |
46 | #include <sys/signalvar.h> | |
47 | #include <vm/vm.h> | |
48 | #include <sys/lock.h> | |
49 | #include <vm/pmap.h> | |
50 | #include <vm/vm_map.h> | |
51 | #include <sys/user.h> | |
52 | #include <vm/vm_zone.h> | |
53 | ||
54 | static MALLOC_DEFINE(M_PGRP, "pgrp", "process group header"); | |
55 | MALLOC_DEFINE(M_SESSION, "session", "session header"); | |
56 | static MALLOC_DEFINE(M_PROC, "proc", "Proc structures"); | |
57 | MALLOC_DEFINE(M_SUBPROC, "subproc", "Proc sub-structures"); | |
58 | ||
59 | static int ps_showallprocs = 1; | |
60 | SYSCTL_INT(_kern, OID_AUTO, ps_showallprocs, CTLFLAG_RW, | |
61 | &ps_showallprocs, 0, ""); | |
62 | ||
63 | static void pgdelete __P((struct pgrp *)); | |
64 | ||
65 | static void orphanpg __P((struct pgrp *pg)); | |
66 | ||
67 | /* | |
68 | * Other process lists | |
69 | */ | |
70 | struct pidhashhead *pidhashtbl; | |
71 | u_long pidhash; | |
72 | struct pgrphashhead *pgrphashtbl; | |
73 | u_long pgrphash; | |
74 | struct proclist allproc; | |
75 | struct proclist zombproc; | |
76 | vm_zone_t proc_zone; | |
263e4574 | 77 | vm_zone_t thread_zone; |
984263bc MD |
78 | |
79 | /* | |
80 | * Initialize global process hashing structures. | |
81 | */ | |
82 | void | |
83 | procinit() | |
84 | { | |
85 | ||
86 | LIST_INIT(&allproc); | |
87 | LIST_INIT(&zombproc); | |
88 | pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); | |
89 | pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash); | |
90 | proc_zone = zinit("PROC", sizeof (struct proc), 0, 0, 5); | |
263e4574 | 91 | thread_zone = zinit("THREAD", sizeof (struct thread), 0, 0, 5); |
984263bc MD |
92 | uihashinit(); |
93 | } | |
94 | ||
95 | /* | |
96 | * Is p an inferior of the current process? | |
97 | */ | |
98 | int | |
99 | inferior(p) | |
100 | register struct proc *p; | |
101 | { | |
102 | ||
103 | for (; p != curproc; p = p->p_pptr) | |
104 | if (p->p_pid == 0) | |
105 | return (0); | |
106 | return (1); | |
107 | } | |
108 | ||
109 | /* | |
110 | * Locate a process by number | |
111 | */ | |
112 | struct proc * | |
113 | pfind(pid) | |
114 | register pid_t pid; | |
115 | { | |
116 | register struct proc *p; | |
117 | ||
118 | LIST_FOREACH(p, PIDHASH(pid), p_hash) | |
119 | if (p->p_pid == pid) | |
120 | return (p); | |
121 | return (NULL); | |
122 | } | |
123 | ||
124 | /* | |
125 | * Locate a process group by number | |
126 | */ | |
127 | struct pgrp * | |
128 | pgfind(pgid) | |
129 | register pid_t pgid; | |
130 | { | |
131 | register struct pgrp *pgrp; | |
132 | ||
133 | LIST_FOREACH(pgrp, PGRPHASH(pgid), pg_hash) | |
134 | if (pgrp->pg_id == pgid) | |
135 | return (pgrp); | |
136 | return (NULL); | |
137 | } | |
138 | ||
139 | /* | |
140 | * Move p to a new or existing process group (and session) | |
141 | */ | |
142 | int | |
143 | enterpgrp(p, pgid, mksess) | |
144 | register struct proc *p; | |
145 | pid_t pgid; | |
146 | int mksess; | |
147 | { | |
148 | register struct pgrp *pgrp = pgfind(pgid); | |
149 | ||
150 | KASSERT(pgrp == NULL || !mksess, | |
151 | ("enterpgrp: setsid into non-empty pgrp")); | |
152 | KASSERT(!SESS_LEADER(p), | |
153 | ("enterpgrp: session leader attempted setpgrp")); | |
154 | ||
155 | if (pgrp == NULL) { | |
156 | pid_t savepid = p->p_pid; | |
157 | struct proc *np; | |
158 | /* | |
159 | * new process group | |
160 | */ | |
161 | KASSERT(p->p_pid == pgid, | |
162 | ("enterpgrp: new pgrp and pid != pgid")); | |
163 | if ((np = pfind(savepid)) == NULL || np != p) | |
164 | return (ESRCH); | |
165 | MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, | |
166 | M_WAITOK); | |
167 | if (mksess) { | |
168 | register struct session *sess; | |
169 | ||
170 | /* | |
171 | * new session | |
172 | */ | |
173 | MALLOC(sess, struct session *, sizeof(struct session), | |
174 | M_SESSION, M_WAITOK); | |
175 | sess->s_leader = p; | |
176 | sess->s_sid = p->p_pid; | |
177 | sess->s_count = 1; | |
178 | sess->s_ttyvp = NULL; | |
179 | sess->s_ttyp = NULL; | |
180 | bcopy(p->p_session->s_login, sess->s_login, | |
181 | sizeof(sess->s_login)); | |
182 | p->p_flag &= ~P_CONTROLT; | |
183 | pgrp->pg_session = sess; | |
184 | KASSERT(p == curproc, | |
185 | ("enterpgrp: mksession and p != curproc")); | |
186 | } else { | |
187 | pgrp->pg_session = p->p_session; | |
188 | pgrp->pg_session->s_count++; | |
189 | } | |
190 | pgrp->pg_id = pgid; | |
191 | LIST_INIT(&pgrp->pg_members); | |
192 | LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); | |
193 | pgrp->pg_jobc = 0; | |
194 | SLIST_INIT(&pgrp->pg_sigiolst); | |
195 | } else if (pgrp == p->p_pgrp) | |
196 | return (0); | |
197 | ||
198 | /* | |
199 | * Adjust eligibility of affected pgrps to participate in job control. | |
200 | * Increment eligibility counts before decrementing, otherwise we | |
201 | * could reach 0 spuriously during the first call. | |
202 | */ | |
203 | fixjobc(p, pgrp, 1); | |
204 | fixjobc(p, p->p_pgrp, 0); | |
205 | ||
206 | LIST_REMOVE(p, p_pglist); | |
207 | if (LIST_EMPTY(&p->p_pgrp->pg_members)) | |
208 | pgdelete(p->p_pgrp); | |
209 | p->p_pgrp = pgrp; | |
210 | LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); | |
211 | return (0); | |
212 | } | |
213 | ||
214 | /* | |
215 | * remove process from process group | |
216 | */ | |
217 | int | |
218 | leavepgrp(p) | |
219 | register struct proc *p; | |
220 | { | |
221 | ||
222 | LIST_REMOVE(p, p_pglist); | |
223 | if (LIST_EMPTY(&p->p_pgrp->pg_members)) | |
224 | pgdelete(p->p_pgrp); | |
225 | p->p_pgrp = 0; | |
226 | return (0); | |
227 | } | |
228 | ||
229 | /* | |
230 | * delete a process group | |
231 | */ | |
232 | static void | |
233 | pgdelete(pgrp) | |
234 | register struct pgrp *pgrp; | |
235 | { | |
236 | ||
237 | /* | |
238 | * Reset any sigio structures pointing to us as a result of | |
239 | * F_SETOWN with our pgid. | |
240 | */ | |
241 | funsetownlst(&pgrp->pg_sigiolst); | |
242 | ||
243 | if (pgrp->pg_session->s_ttyp != NULL && | |
244 | pgrp->pg_session->s_ttyp->t_pgrp == pgrp) | |
245 | pgrp->pg_session->s_ttyp->t_pgrp = NULL; | |
246 | LIST_REMOVE(pgrp, pg_hash); | |
247 | if (--pgrp->pg_session->s_count == 0) | |
248 | FREE(pgrp->pg_session, M_SESSION); | |
249 | FREE(pgrp, M_PGRP); | |
250 | } | |
251 | ||
252 | /* | |
253 | * Adjust pgrp jobc counters when specified process changes process group. | |
254 | * We count the number of processes in each process group that "qualify" | |
255 | * the group for terminal job control (those with a parent in a different | |
256 | * process group of the same session). If that count reaches zero, the | |
257 | * process group becomes orphaned. Check both the specified process' | |
258 | * process group and that of its children. | |
259 | * entering == 0 => p is leaving specified group. | |
260 | * entering == 1 => p is entering specified group. | |
261 | */ | |
262 | void | |
263 | fixjobc(p, pgrp, entering) | |
264 | register struct proc *p; | |
265 | register struct pgrp *pgrp; | |
266 | int entering; | |
267 | { | |
268 | register struct pgrp *hispgrp; | |
269 | register struct session *mysession = pgrp->pg_session; | |
270 | ||
271 | /* | |
272 | * Check p's parent to see whether p qualifies its own process | |
273 | * group; if so, adjust count for p's process group. | |
274 | */ | |
275 | if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && | |
276 | hispgrp->pg_session == mysession) { | |
277 | if (entering) | |
278 | pgrp->pg_jobc++; | |
279 | else if (--pgrp->pg_jobc == 0) | |
280 | orphanpg(pgrp); | |
281 | } | |
282 | ||
283 | /* | |
284 | * Check this process' children to see whether they qualify | |
285 | * their process groups; if so, adjust counts for children's | |
286 | * process groups. | |
287 | */ | |
288 | LIST_FOREACH(p, &p->p_children, p_sibling) | |
289 | if ((hispgrp = p->p_pgrp) != pgrp && | |
290 | hispgrp->pg_session == mysession && | |
291 | p->p_stat != SZOMB) { | |
292 | if (entering) | |
293 | hispgrp->pg_jobc++; | |
294 | else if (--hispgrp->pg_jobc == 0) | |
295 | orphanpg(hispgrp); | |
296 | } | |
297 | } | |
298 | ||
299 | /* | |
300 | * A process group has become orphaned; | |
301 | * if there are any stopped processes in the group, | |
302 | * hang-up all process in that group. | |
303 | */ | |
304 | static void | |
305 | orphanpg(pg) | |
306 | struct pgrp *pg; | |
307 | { | |
308 | register struct proc *p; | |
309 | ||
310 | LIST_FOREACH(p, &pg->pg_members, p_pglist) { | |
311 | if (p->p_stat == SSTOP) { | |
312 | LIST_FOREACH(p, &pg->pg_members, p_pglist) { | |
313 | psignal(p, SIGHUP); | |
314 | psignal(p, SIGCONT); | |
315 | } | |
316 | return; | |
317 | } | |
318 | } | |
319 | } | |
320 | ||
321 | #include "opt_ddb.h" | |
322 | #ifdef DDB | |
323 | #include <ddb/ddb.h> | |
324 | ||
325 | DB_SHOW_COMMAND(pgrpdump, pgrpdump) | |
326 | { | |
327 | register struct pgrp *pgrp; | |
328 | register struct proc *p; | |
329 | register int i; | |
330 | ||
331 | for (i = 0; i <= pgrphash; i++) { | |
332 | if (!LIST_EMPTY(&pgrphashtbl[i])) { | |
333 | printf("\tindx %d\n", i); | |
334 | LIST_FOREACH(pgrp, &pgrphashtbl[i], pg_hash) { | |
335 | printf( | |
336 | "\tpgrp %p, pgid %ld, sess %p, sesscnt %d, mem %p\n", | |
337 | (void *)pgrp, (long)pgrp->pg_id, | |
338 | (void *)pgrp->pg_session, | |
339 | pgrp->pg_session->s_count, | |
340 | (void *)LIST_FIRST(&pgrp->pg_members)); | |
341 | LIST_FOREACH(p, &pgrp->pg_members, p_pglist) { | |
342 | printf("\t\tpid %ld addr %p pgrp %p\n", | |
343 | (long)p->p_pid, (void *)p, | |
344 | (void *)p->p_pgrp); | |
345 | } | |
346 | } | |
347 | } | |
348 | } | |
349 | } | |
350 | #endif /* DDB */ | |
351 | ||
352 | /* | |
353 | * Fill in an eproc structure for the specified process. | |
354 | */ | |
355 | void | |
356 | fill_eproc(p, ep) | |
357 | register struct proc *p; | |
358 | register struct eproc *ep; | |
359 | { | |
360 | register struct tty *tp; | |
361 | ||
362 | bzero(ep, sizeof(*ep)); | |
363 | ||
364 | ep->e_paddr = p; | |
6ac7b760 MD |
365 | ep->e_uticks = p->p_thread->td_uticks; |
366 | ep->e_sticks = p->p_thread->td_sticks; | |
367 | ep->e_iticks = p->p_thread->td_iticks; | |
41c20dac MD |
368 | if (p->p_ucred) { |
369 | ep->e_ucred = *p->p_ucred; | |
984263bc MD |
370 | } |
371 | if (p->p_procsig) { | |
372 | ep->e_procsig = *p->p_procsig; | |
373 | } | |
374 | if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) { | |
375 | register struct vmspace *vm = p->p_vmspace; | |
376 | ep->e_vm = *vm; | |
377 | ep->e_vm.vm_rssize = vmspace_resident_count(vm); /*XXX*/ | |
378 | } | |
379 | if ((p->p_flag & P_INMEM) && p->p_stats) | |
380 | ep->e_stats = *p->p_stats; | |
381 | if (p->p_pptr) | |
382 | ep->e_ppid = p->p_pptr->p_pid; | |
383 | if (p->p_pgrp) { | |
384 | ep->e_pgid = p->p_pgrp->pg_id; | |
385 | ep->e_jobc = p->p_pgrp->pg_jobc; | |
386 | ep->e_sess = p->p_pgrp->pg_session; | |
387 | ||
388 | if (ep->e_sess) { | |
389 | bcopy(ep->e_sess->s_login, ep->e_login, sizeof(ep->e_login)); | |
390 | if (ep->e_sess->s_ttyvp) | |
391 | ep->e_flag = EPROC_CTTY; | |
392 | if (p->p_session && SESS_LEADER(p)) | |
393 | ep->e_flag |= EPROC_SLEADER; | |
394 | } | |
395 | } | |
396 | if ((p->p_flag & P_CONTROLT) && | |
397 | (ep->e_sess != NULL) && | |
398 | ((tp = ep->e_sess->s_ttyp) != NULL)) { | |
399 | ep->e_tdev = dev2udev(tp->t_dev); | |
400 | ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID; | |
401 | ep->e_tsess = tp->t_session; | |
402 | } else | |
403 | ep->e_tdev = NOUDEV; | |
404 | if (p->p_wmesg) { | |
405 | strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN); | |
406 | ep->e_wmesg[WMESGLEN] = 0; | |
407 | } | |
408 | } | |
409 | ||
410 | struct proc * | |
411 | zpfind(pid_t pid) | |
412 | { | |
413 | struct proc *p; | |
414 | ||
415 | LIST_FOREACH(p, &zombproc, p_list) | |
416 | if (p->p_pid == pid) | |
417 | return (p); | |
418 | return (NULL); | |
419 | } | |
420 | ||
984263bc MD |
421 | static int |
422 | sysctl_out_proc(struct proc *p, struct sysctl_req *req, int doingzomb) | |
423 | { | |
424 | struct eproc eproc; | |
425 | int error; | |
426 | pid_t pid = p->p_pid; | |
427 | ||
428 | fill_eproc(p, &eproc); | |
429 | error = SYSCTL_OUT(req,(caddr_t)p, sizeof(struct proc)); | |
430 | if (error) | |
431 | return (error); | |
432 | error = SYSCTL_OUT(req,(caddr_t)&eproc, sizeof(eproc)); | |
b8acf5a9 MD |
433 | if (error) |
434 | return (error); | |
435 | error = SYSCTL_OUT(req,(caddr_t)&p->p_thread, sizeof(struct thread)); | |
984263bc MD |
436 | if (error) |
437 | return (error); | |
438 | if (!doingzomb && pid && (pfind(pid) != p)) | |
439 | return EAGAIN; | |
440 | if (doingzomb && zpfind(pid) != p) | |
441 | return EAGAIN; | |
442 | return (0); | |
443 | } | |
444 | ||
445 | static int | |
446 | sysctl_kern_proc(SYSCTL_HANDLER_ARGS) | |
447 | { | |
448 | int *name = (int*) arg1; | |
449 | u_int namelen = arg2; | |
450 | struct proc *p; | |
451 | int doingzomb; | |
452 | int error = 0; | |
41c20dac | 453 | struct ucred *cr1 = curproc->p_ucred; |
984263bc MD |
454 | |
455 | if (oidp->oid_number == KERN_PROC_PID) { | |
456 | if (namelen != 1) | |
457 | return (EINVAL); | |
458 | p = pfind((pid_t)name[0]); | |
459 | if (!p) | |
460 | return (0); | |
41c20dac | 461 | if (!PRISON_CHECK(cr1, p->p_ucred)) |
984263bc MD |
462 | return (0); |
463 | error = sysctl_out_proc(p, req, 0); | |
464 | return (error); | |
465 | } | |
466 | if (oidp->oid_number == KERN_PROC_ALL && !namelen) | |
467 | ; | |
468 | else if (oidp->oid_number != KERN_PROC_ALL && namelen == 1) | |
469 | ; | |
470 | else | |
471 | return (EINVAL); | |
472 | ||
473 | if (!req->oldptr) { | |
474 | /* overestimate by 5 procs */ | |
475 | error = SYSCTL_OUT(req, 0, sizeof (struct kinfo_proc) * 5); | |
476 | if (error) | |
477 | return (error); | |
478 | } | |
479 | for (doingzomb=0 ; doingzomb < 2 ; doingzomb++) { | |
480 | if (!doingzomb) | |
481 | p = LIST_FIRST(&allproc); | |
482 | else | |
483 | p = LIST_FIRST(&zombproc); | |
484 | for (; p != 0; p = LIST_NEXT(p, p_list)) { | |
485 | /* | |
486 | * Show a user only their processes. | |
487 | */ | |
41c20dac | 488 | if ((!ps_showallprocs) && p_trespass(cr1, p->p_ucred)) |
984263bc MD |
489 | continue; |
490 | /* | |
491 | * Skip embryonic processes. | |
492 | */ | |
493 | if (p->p_stat == SIDL) | |
494 | continue; | |
495 | /* | |
496 | * TODO - make more efficient (see notes below). | |
497 | * do by session. | |
498 | */ | |
499 | switch (oidp->oid_number) { | |
500 | ||
501 | case KERN_PROC_PGRP: | |
502 | /* could do this by traversing pgrp */ | |
503 | if (p->p_pgrp == NULL || | |
504 | p->p_pgrp->pg_id != (pid_t)name[0]) | |
505 | continue; | |
506 | break; | |
507 | ||
508 | case KERN_PROC_TTY: | |
509 | if ((p->p_flag & P_CONTROLT) == 0 || | |
510 | p->p_session == NULL || | |
511 | p->p_session->s_ttyp == NULL || | |
512 | dev2udev(p->p_session->s_ttyp->t_dev) != | |
513 | (udev_t)name[0]) | |
514 | continue; | |
515 | break; | |
516 | ||
517 | case KERN_PROC_UID: | |
518 | if (p->p_ucred == NULL || | |
519 | p->p_ucred->cr_uid != (uid_t)name[0]) | |
520 | continue; | |
521 | break; | |
522 | ||
523 | case KERN_PROC_RUID: | |
524 | if (p->p_ucred == NULL || | |
41c20dac | 525 | p->p_ucred->cr_ruid != (uid_t)name[0]) |
984263bc MD |
526 | continue; |
527 | break; | |
528 | } | |
529 | ||
41c20dac | 530 | if (!PRISON_CHECK(cr1, p->p_ucred)) |
984263bc MD |
531 | continue; |
532 | ||
533 | error = sysctl_out_proc(p, req, doingzomb); | |
534 | if (error) | |
535 | return (error); | |
536 | } | |
537 | } | |
538 | return (0); | |
539 | } | |
540 | ||
541 | /* | |
542 | * This sysctl allows a process to retrieve the argument list or process | |
543 | * title for another process without groping around in the address space | |
544 | * of the other process. It also allow a process to set its own "process | |
545 | * title to a string of its own choice. | |
546 | */ | |
547 | static int | |
548 | sysctl_kern_proc_args(SYSCTL_HANDLER_ARGS) | |
549 | { | |
550 | int *name = (int*) arg1; | |
551 | u_int namelen = arg2; | |
552 | struct proc *p; | |
553 | struct pargs *pa; | |
554 | int error = 0; | |
41c20dac | 555 | struct ucred *cr1 = curproc->p_ucred; |
984263bc MD |
556 | |
557 | if (namelen != 1) | |
558 | return (EINVAL); | |
559 | ||
560 | p = pfind((pid_t)name[0]); | |
561 | if (!p) | |
562 | return (0); | |
563 | ||
41c20dac | 564 | if ((!ps_argsopen) && p_trespass(cr1, p->p_ucred)) |
984263bc MD |
565 | return (0); |
566 | ||
567 | if (req->newptr && curproc != p) | |
568 | return (EPERM); | |
569 | ||
570 | if (req->oldptr && p->p_args != NULL) | |
571 | error = SYSCTL_OUT(req, p->p_args->ar_args, p->p_args->ar_length); | |
572 | if (req->newptr == NULL) | |
573 | return (error); | |
574 | ||
575 | if (p->p_args && --p->p_args->ar_ref == 0) | |
576 | FREE(p->p_args, M_PARGS); | |
577 | p->p_args = NULL; | |
578 | ||
579 | if (req->newlen + sizeof(struct pargs) > ps_arg_cache_limit) | |
580 | return (error); | |
581 | ||
582 | MALLOC(pa, struct pargs *, sizeof(struct pargs) + req->newlen, | |
583 | M_PARGS, M_WAITOK); | |
584 | pa->ar_ref = 1; | |
585 | pa->ar_length = req->newlen; | |
586 | error = SYSCTL_IN(req, pa->ar_args, req->newlen); | |
587 | if (!error) | |
588 | p->p_args = pa; | |
589 | else | |
590 | FREE(pa, M_PARGS); | |
591 | return (error); | |
592 | } | |
593 | ||
594 | SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD, 0, "Process table"); | |
595 | ||
596 | SYSCTL_PROC(_kern_proc, KERN_PROC_ALL, all, CTLFLAG_RD|CTLTYPE_STRUCT, | |
597 | 0, 0, sysctl_kern_proc, "S,proc", "Return entire process table"); | |
598 | ||
599 | SYSCTL_NODE(_kern_proc, KERN_PROC_PGRP, pgrp, CTLFLAG_RD, | |
600 | sysctl_kern_proc, "Process table"); | |
601 | ||
602 | SYSCTL_NODE(_kern_proc, KERN_PROC_TTY, tty, CTLFLAG_RD, | |
603 | sysctl_kern_proc, "Process table"); | |
604 | ||
605 | SYSCTL_NODE(_kern_proc, KERN_PROC_UID, uid, CTLFLAG_RD, | |
606 | sysctl_kern_proc, "Process table"); | |
607 | ||
608 | SYSCTL_NODE(_kern_proc, KERN_PROC_RUID, ruid, CTLFLAG_RD, | |
609 | sysctl_kern_proc, "Process table"); | |
610 | ||
611 | SYSCTL_NODE(_kern_proc, KERN_PROC_PID, pid, CTLFLAG_RD, | |
612 | sysctl_kern_proc, "Process table"); | |
613 | ||
614 | SYSCTL_NODE(_kern_proc, KERN_PROC_ARGS, args, CTLFLAG_RW | CTLFLAG_ANYBODY, | |
615 | sysctl_kern_proc_args, "Process argument list"); |