FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_proc.c
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.22.2.2 1999/09/05 08:15:00 peter Exp $
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/sysctl.h>
41 #include <sys/proc.h>
42 #include <sys/buf.h>
43 #include <sys/acct.h>
44 #include <sys/wait.h>
45 #include <sys/file.h>
46 #include <ufs/ufs/quota.h>
47 #include <sys/uio.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/ioctl.h>
51 #include <sys/tty.h>
52 #include <sys/signalvar.h>
53 #include <vm/vm.h>
54 #include <vm/vm_param.h>
55 #include <vm/vm_prot.h>
56 #include <vm/lock.h>
57 #include <vm/pmap.h>
58 #include <vm/vm_map.h>
59 #include <sys/user.h>
60
61 struct prochd qs[NQS]; /* as good a place as any... */
62 struct prochd rtqs[NQS]; /* Space for REALTIME queues too */
63 struct prochd idqs[NQS]; /* Space for IDLE queues too */
64
65 static void pgdelete __P((struct pgrp *));
66
67 /*
68 * Structure associated with user cacheing.
69 */
70 struct uidinfo {
71 LIST_ENTRY(uidinfo) ui_hash;
72 uid_t ui_uid;
73 long ui_proccnt;
74 };
75 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
76 LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
77 static u_long uihash; /* size of hash table - 1 */
78
79 static void orphanpg __P((struct pgrp *pg));
80
81 /*
82 * Other process lists
83 */
84 struct pidhashhead *pidhashtbl;
85 u_long pidhash;
86 struct pgrphashhead *pgrphashtbl;
87 u_long pgrphash;
88 struct proclist allproc;
89 struct proclist zombproc;
90
91 /*
92 * Initialize global process hashing structures.
93 */
94 void
95 procinit()
96 {
97
98 LIST_INIT(&allproc);
99 LIST_INIT(&zombproc);
100 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
101 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
102 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
103 }
104
105 /*
106 * Change the count associated with number of processes
107 * a given user is using.
108 */
109 int
110 chgproccnt(uid, diff)
111 uid_t uid;
112 int diff;
113 {
114 register struct uidinfo *uip;
115 register struct uihashhead *uipp;
116
117 uipp = UIHASH(uid);
118 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
119 if (uip->ui_uid == uid)
120 break;
121 if (uip) {
122 uip->ui_proccnt += diff;
123 if (uip->ui_proccnt > 0)
124 return (uip->ui_proccnt);
125 if (uip->ui_proccnt < 0)
126 panic("chgproccnt: procs < 0");
127 LIST_REMOVE(uip, ui_hash);
128 FREE(uip, M_PROC);
129 return (0);
130 }
131 if (diff <= 0) {
132 if (diff == 0)
133 return(0);
134 panic("chgproccnt: lost user");
135 }
136 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
137 LIST_INSERT_HEAD(uipp, uip, ui_hash);
138 uip->ui_uid = uid;
139 uip->ui_proccnt = diff;
140 return (diff);
141 }
142
143 /*
144 * Is p an inferior of the current process?
145 */
146 int
147 inferior(p)
148 register struct proc *p;
149 {
150
151 for (; p != curproc; p = p->p_pptr)
152 if (p->p_pid == 0)
153 return (0);
154 return (1);
155 }
156
157 /*
158 * Locate a process by number
159 */
160 struct proc *
161 pfind(pid)
162 register pid_t pid;
163 {
164 register struct proc *p;
165
166 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
167 if (p->p_pid == pid)
168 return (p);
169 return (NULL);
170 }
171
172 /*
173 * Locate a process group by number
174 */
175 struct pgrp *
176 pgfind(pgid)
177 register pid_t pgid;
178 {
179 register struct pgrp *pgrp;
180
181 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0;
182 pgrp = pgrp->pg_hash.le_next)
183 if (pgrp->pg_id == pgid)
184 return (pgrp);
185 return (NULL);
186 }
187
188 /*
189 * Move p to a new or existing process group (and session)
190 */
191 int
192 enterpgrp(p, pgid, mksess)
193 register struct proc *p;
194 pid_t pgid;
195 int mksess;
196 {
197 register struct pgrp *pgrp = pgfind(pgid);
198
199 #ifdef DIAGNOSTIC
200 if (pgrp != NULL && mksess) /* firewalls */
201 panic("enterpgrp: setsid into non-empty pgrp");
202 if (SESS_LEADER(p))
203 panic("enterpgrp: session leader attempted setpgrp");
204 #endif
205 if (pgrp == NULL) {
206 pid_t savepid = p->p_pid;
207 struct proc *np;
208 /*
209 * new process group
210 */
211 #ifdef DIAGNOSTIC
212 if (p->p_pid != pgid)
213 panic("enterpgrp: new pgrp and pid != pgid");
214 #endif
215 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
216 M_WAITOK);
217 if ((np = pfind(savepid)) == NULL || np != p)
218 return (ESRCH);
219 if (mksess) {
220 register struct session *sess;
221
222 /*
223 * new session
224 */
225 MALLOC(sess, struct session *, sizeof(struct session),
226 M_SESSION, M_WAITOK);
227 sess->s_leader = p;
228 sess->s_count = 1;
229 sess->s_ttyvp = NULL;
230 sess->s_ttyp = NULL;
231 bcopy(p->p_session->s_login, sess->s_login,
232 sizeof(sess->s_login));
233 p->p_flag &= ~P_CONTROLT;
234 pgrp->pg_session = sess;
235 #ifdef DIAGNOSTIC
236 if (p != curproc)
237 panic("enterpgrp: mksession and p != curproc");
238 #endif
239 } else {
240 pgrp->pg_session = p->p_session;
241 pgrp->pg_session->s_count++;
242 }
243 pgrp->pg_id = pgid;
244 LIST_INIT(&pgrp->pg_members);
245 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
246 pgrp->pg_jobc = 0;
247 } else if (pgrp == p->p_pgrp)
248 return (0);
249
250 /*
251 * Adjust eligibility of affected pgrps to participate in job control.
252 * Increment eligibility counts before decrementing, otherwise we
253 * could reach 0 spuriously during the first call.
254 */
255 fixjobc(p, pgrp, 1);
256 fixjobc(p, p->p_pgrp, 0);
257
258 LIST_REMOVE(p, p_pglist);
259 if (p->p_pgrp->pg_members.lh_first == 0)
260 pgdelete(p->p_pgrp);
261 p->p_pgrp = pgrp;
262 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
263 return (0);
264 }
265
266 /*
267 * remove process from process group
268 */
269 int
270 leavepgrp(p)
271 register struct proc *p;
272 {
273
274 LIST_REMOVE(p, p_pglist);
275 if (p->p_pgrp->pg_members.lh_first == 0)
276 pgdelete(p->p_pgrp);
277 p->p_pgrp = 0;
278 return (0);
279 }
280
281 /*
282 * delete a process group
283 */
284 static void
285 pgdelete(pgrp)
286 register struct pgrp *pgrp;
287 {
288
289 if (pgrp->pg_session->s_ttyp != NULL &&
290 pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
291 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
292 LIST_REMOVE(pgrp, pg_hash);
293 if (--pgrp->pg_session->s_count == 0)
294 FREE(pgrp->pg_session, M_SESSION);
295 FREE(pgrp, M_PGRP);
296 }
297
298 /*
299 * Adjust pgrp jobc counters when specified process changes process group.
300 * We count the number of processes in each process group that "qualify"
301 * the group for terminal job control (those with a parent in a different
302 * process group of the same session). If that count reaches zero, the
303 * process group becomes orphaned. Check both the specified process'
304 * process group and that of its children.
305 * entering == 0 => p is leaving specified group.
306 * entering == 1 => p is entering specified group.
307 */
308 void
309 fixjobc(p, pgrp, entering)
310 register struct proc *p;
311 register struct pgrp *pgrp;
312 int entering;
313 {
314 register struct pgrp *hispgrp;
315 register struct session *mysession = pgrp->pg_session;
316
317 /*
318 * Check p's parent to see whether p qualifies its own process
319 * group; if so, adjust count for p's process group.
320 */
321 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
322 hispgrp->pg_session == mysession)
323 if (entering)
324 pgrp->pg_jobc++;
325 else if (--pgrp->pg_jobc == 0)
326 orphanpg(pgrp);
327
328 /*
329 * Check this process' children to see whether they qualify
330 * their process groups; if so, adjust counts for children's
331 * process groups.
332 */
333 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
334 if ((hispgrp = p->p_pgrp) != pgrp &&
335 hispgrp->pg_session == mysession &&
336 p->p_stat != SZOMB)
337 if (entering)
338 hispgrp->pg_jobc++;
339 else if (--hispgrp->pg_jobc == 0)
340 orphanpg(hispgrp);
341 }
342
343 /*
344 * A process group has become orphaned;
345 * if there are any stopped processes in the group,
346 * hang-up all process in that group.
347 */
348 static void
349 orphanpg(pg)
350 struct pgrp *pg;
351 {
352 register struct proc *p;
353
354 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
355 if (p->p_stat == SSTOP) {
356 for (p = pg->pg_members.lh_first; p != 0;
357 p = p->p_pglist.le_next) {
358 psignal(p, SIGHUP);
359 psignal(p, SIGCONT);
360 }
361 return;
362 }
363 }
364 }
365
366 #include "opt_ddb.h"
367 #ifdef DDB
368 #include <ddb/ddb.h>
369
370 DB_SHOW_COMMAND(pgrpdump, pgrpdump)
371 {
372 register struct pgrp *pgrp;
373 register struct proc *p;
374 register i;
375
376 for (i = 0; i <= pgrphash; i++) {
377 if (pgrp = pgrphashtbl[i].lh_first) {
378 printf("\tindx %d\n", i);
379 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
380 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
381 pgrp, pgrp->pg_id, pgrp->pg_session,
382 pgrp->pg_session->s_count,
383 pgrp->pg_members.lh_first);
384 for (p = pgrp->pg_members.lh_first; p != 0;
385 p = p->p_pglist.le_next) {
386 printf("\t\tpid %d addr %x pgrp %x\n",
387 p->p_pid, p, p->p_pgrp);
388 }
389 }
390 }
391 }
392 }
393 #endif /* DDB */
394
395 /*
396 * Fill in an eproc structure for the specified process.
397 */
398 void
399 fill_eproc(p, ep)
400 register struct proc *p;
401 register struct eproc *ep;
402 {
403 register struct tty *tp;
404
405 bzero(ep, sizeof(*ep));
406
407 ep->e_paddr = p;
408 if (p->p_cred) {
409 ep->e_pcred = *p->p_cred;
410 if (p->p_ucred)
411 ep->e_ucred = *p->p_ucred;
412 }
413 if (p->p_stat != SIDL && p->p_stat != SZOMB && p->p_vmspace != NULL) {
414 register struct vmspace *vm = p->p_vmspace;
415
416 #ifdef pmap_resident_count
417 ep->e_vm.vm_rssize = pmap_resident_count(&vm->vm_pmap); /*XXX*/
418 #else
419 ep->e_vm.vm_rssize = vm->vm_rssize;
420 #endif
421 ep->e_vm.vm_tsize = vm->vm_tsize;
422 ep->e_vm.vm_dsize = vm->vm_dsize;
423 ep->e_vm.vm_ssize = vm->vm_ssize;
424 ep->e_vm.vm_taddr = vm->vm_taddr;
425 ep->e_vm.vm_daddr = vm->vm_daddr;
426 ep->e_vm.vm_minsaddr = vm->vm_minsaddr;
427 ep->e_vm.vm_maxsaddr = vm->vm_maxsaddr;
428 #ifndef sparc
429 ep->e_vm.vm_pmap = vm->vm_pmap;
430 #endif
431 }
432 if (p->p_pptr)
433 ep->e_ppid = p->p_pptr->p_pid;
434 if (p->p_pgrp) {
435 ep->e_pgid = p->p_pgrp->pg_id;
436 ep->e_jobc = p->p_pgrp->pg_jobc;
437 ep->e_sess = p->p_pgrp->pg_session;
438
439 if (ep->e_sess) {
440 bcopy(ep->e_sess->s_login, ep->e_login, sizeof(ep->e_login));
441 if (ep->e_sess->s_ttyvp)
442 ep->e_flag = EPROC_CTTY;
443 if (p->p_session && SESS_LEADER(p))
444 ep->e_flag |= EPROC_SLEADER;
445 }
446 }
447 if ((p->p_flag & P_CONTROLT) &&
448 (ep->e_sess != NULL) &&
449 ((tp = ep->e_sess->s_ttyp) != NULL)) {
450 ep->e_tdev = tp->t_dev;
451 ep->e_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
452 ep->e_tsess = tp->t_session;
453 } else
454 ep->e_tdev = NODEV;
455 if (p->p_wmesg) {
456 strncpy(ep->e_wmesg, p->p_wmesg, WMESGLEN);
457 ep->e_wmesg[WMESGLEN] = 0;
458 }
459 }
460
461 static struct proc *
462 zpfind(pid_t pid)
463 {
464 struct proc *p;
465
466 for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next)
467 if (p->p_pid == pid)
468 return (p);
469 return (NULL);
470 }
471
472
473 static int
474 sysctl_out_proc(struct proc *p, struct sysctl_req *req, int doingzomb)
475 {
476 struct eproc eproc;
477 int error;
478 pid_t pid = p->p_pid;
479
480 fill_eproc(p, &eproc);
481 error = SYSCTL_OUT(req,(caddr_t)p, sizeof(struct proc));
482 if (error)
483 return (error);
484 error = SYSCTL_OUT(req,(caddr_t)&eproc, sizeof(eproc));
485 if (error)
486 return (error);
487 if (!doingzomb && pid && (pfind(pid) != p))
488 return EAGAIN;
489 if (doingzomb && zpfind(pid) != p)
490 return EAGAIN;
491 return (0);
492 }
493
494 static int
495 sysctl_kern_proc SYSCTL_HANDLER_ARGS
496 {
497 int *name = (int*) arg1;
498 u_int namelen = arg2;
499 struct proc *p;
500 int doingzomb;
501 int error = 0;
502
503 if (oidp->oid_number == KERN_PROC_PID) {
504 if (namelen != 1)
505 return (EINVAL);
506 p = pfind((pid_t)name[0]);
507 if (!p)
508 return (0);
509 error = sysctl_out_proc(p, req, 0);
510 return (error);
511 }
512 if (oidp->oid_number == KERN_PROC_ALL && !namelen)
513 ;
514 else if (oidp->oid_number != KERN_PROC_ALL && namelen == 1)
515 ;
516 else
517 return (EINVAL);
518
519 if (!req->oldptr) {
520 /* overestimate by 5 procs */
521 error = SYSCTL_OUT(req, 0, sizeof (struct kinfo_proc) * 5);
522 if (error)
523 return (error);
524 }
525 for (doingzomb=0 ; doingzomb < 2 ; doingzomb++) {
526 if (!doingzomb)
527 p = allproc.lh_first;
528 else
529 p = zombproc.lh_first;
530 for (; p != 0; p = p->p_list.le_next) {
531 /*
532 * Skip embryonic processes.
533 */
534 if (p->p_stat == SIDL)
535 continue;
536 /*
537 * TODO - make more efficient (see notes below).
538 * do by session.
539 */
540 switch (oidp->oid_number) {
541
542 case KERN_PROC_PGRP:
543 /* could do this by traversing pgrp */
544 if (p->p_pgrp == NULL ||
545 p->p_pgrp->pg_id != (pid_t)name[0])
546 continue;
547 break;
548
549 case KERN_PROC_TTY:
550 if ((p->p_flag & P_CONTROLT) == 0 ||
551 p->p_session == NULL ||
552 p->p_session->s_ttyp == NULL ||
553 p->p_session->s_ttyp->t_dev != (dev_t)name[0])
554 continue;
555 break;
556
557 case KERN_PROC_UID:
558 if (p->p_ucred == NULL ||
559 p->p_ucred->cr_uid != (uid_t)name[0])
560 continue;
561 break;
562
563 case KERN_PROC_RUID:
564 if (p->p_ucred == NULL ||
565 p->p_cred->p_ruid != (uid_t)name[0])
566 continue;
567 break;
568 }
569
570 error = sysctl_out_proc(p, req, doingzomb);
571 if (error)
572 return (error);
573 }
574 }
575 return (0);
576 }
577
578
579 SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD, 0, "Process table");
580
581 SYSCTL_PROC(_kern_proc, KERN_PROC_ALL, all, CTLFLAG_RD|CTLTYPE_STRUCT,
582 0, 0, sysctl_kern_proc, "S,proc", "");
583
584 SYSCTL_NODE(_kern_proc, KERN_PROC_PGRP, pgrp, CTLFLAG_RD,
585 sysctl_kern_proc, "Process table");
586
587 SYSCTL_NODE(_kern_proc, KERN_PROC_TTY, tty, CTLFLAG_RD,
588 sysctl_kern_proc, "Process table");
589
590 SYSCTL_NODE(_kern_proc, KERN_PROC_UID, uid, CTLFLAG_RD,
591 sysctl_kern_proc, "Process table");
592
593 SYSCTL_NODE(_kern_proc, KERN_PROC_RUID, ruid, CTLFLAG_RD,
594 sysctl_kern_proc, "Process table");
595
596 SYSCTL_NODE(_kern_proc, KERN_PROC_PID, pid, CTLFLAG_RD,
597 sysctl_kern_proc, "Process table");
Cache object: c1abb3ce77ffeec50f3a3ecf54c2db9d
|