Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
c34daa85 KB |
2 | * Copyright (c) 1982, 1986, 1989, 1991, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
da7c5cc6 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
c4ec2128 | 6 | * |
1f3d196a | 7 | * @(#)kern_proc.c 8.4 (Berkeley) %G% |
da7c5cc6 | 8 | */ |
961945a8 | 9 | |
4f6e87b7 KB |
10 | #include <sys/param.h> |
11 | #include <sys/systm.h> | |
12 | #include <sys/map.h> | |
13 | #include <sys/kernel.h> | |
14 | #include <sys/proc.h> | |
15 | #include <sys/buf.h> | |
4f6e87b7 KB |
16 | #include <sys/acct.h> |
17 | #include <sys/wait.h> | |
18 | #include <sys/file.h> | |
19 | #include <ufs/ufs/quota.h> | |
20 | #include <sys/uio.h> | |
21 | #include <sys/malloc.h> | |
22 | #include <sys/mbuf.h> | |
23 | #include <sys/ioctl.h> | |
24 | #include <sys/tty.h> | |
a1bce776 | 25 | |
0c06af94 KM |
26 | /* |
27 | * Structure associated with user cacheing. | |
28 | */ | |
29 | struct uidinfo { | |
30 | struct uidinfo *ui_next; | |
31 | struct uidinfo **ui_prev; | |
32 | uid_t ui_uid; | |
33 | long ui_proccnt; | |
34 | } **uihashtbl; | |
35 | u_long uihash; /* size of hash table - 1 */ | |
36 | #define UIHASH(uid) ((uid) & uihash) | |
37 | ||
38 | /* | |
39 | * Allocate a hash table. | |
40 | */ | |
41 | usrinfoinit() | |
42 | { | |
43 | ||
44 | uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash); | |
45 | } | |
46 | ||
47 | /* | |
48 | * Change the count associated with number of processes | |
49 | * a given user is using. | |
50 | */ | |
51 | int | |
52 | chgproccnt(uid, diff) | |
53 | uid_t uid; | |
54 | int diff; | |
55 | { | |
56 | register struct uidinfo **uipp, *uip, *uiq; | |
57 | ||
58 | uipp = &uihashtbl[UIHASH(uid)]; | |
59 | for (uip = *uipp; uip; uip = uip->ui_next) | |
60 | if (uip->ui_uid == uid) | |
61 | break; | |
62 | if (uip) { | |
63 | uip->ui_proccnt += diff; | |
64 | if (uip->ui_proccnt > 0) | |
65 | return (uip->ui_proccnt); | |
66 | if (uip->ui_proccnt < 0) | |
67 | panic("chgproccnt: procs < 0"); | |
68 | if (uiq = uip->ui_next) | |
69 | uiq->ui_prev = uip->ui_prev; | |
70 | *uip->ui_prev = uiq; | |
71 | FREE(uip, M_PROC); | |
72 | return (0); | |
73 | } | |
74 | if (diff <= 0) { | |
75 | if (diff == 0) | |
76 | return(0); | |
77 | panic("chgproccnt: lost user"); | |
78 | } | |
79 | MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); | |
80 | if (uiq = *uipp) | |
81 | uiq->ui_prev = &uip->ui_next; | |
82 | uip->ui_next = uiq; | |
83 | uip->ui_prev = uipp; | |
84 | *uipp = uip; | |
85 | uip->ui_uid = uid; | |
86 | uip->ui_proccnt = diff; | |
87 | return (diff); | |
88 | } | |
89 | ||
29dd101b | 90 | /* |
4147b3f6 | 91 | * Is p an inferior of the current process? |
29dd101b | 92 | */ |
4147b3f6 | 93 | inferior(p) |
a2a2a0d6 | 94 | register struct proc *p; |
29dd101b | 95 | { |
2dccc728 | 96 | |
bed84066 MK |
97 | for (; p != curproc; p = p->p_pptr) |
98 | if (p->p_pid == 0) | |
4147b3f6 BJ |
99 | return (0); |
100 | return (1); | |
29dd101b | 101 | } |
a2a2a0d6 | 102 | |
b3ce9b0f MK |
103 | /* |
104 | * Locate a process by number | |
105 | */ | |
a2a2a0d6 BJ |
106 | struct proc * |
107 | pfind(pid) | |
cb84e0ab | 108 | register pid_t pid; |
a2a2a0d6 | 109 | { |
cb84e0ab | 110 | register struct proc *p; |
a2a2a0d6 | 111 | |
cb84e0ab | 112 | for (p = pidhash[PIDHASH(pid)]; p != NULL; p = p->p_hash) |
a2a2a0d6 BJ |
113 | if (p->p_pid == pid) |
114 | return (p); | |
cb84e0ab | 115 | return (NULL); |
a2a2a0d6 | 116 | } |
1d348849 | 117 | |
8fe87cbb MT |
118 | /* |
119 | * Locate a process group by number | |
120 | */ | |
121 | struct pgrp * | |
122 | pgfind(pgid) | |
123 | register pid_t pgid; | |
124 | { | |
cb84e0ab | 125 | register struct pgrp *pgrp; |
8fe87cbb | 126 | |
cb84e0ab KB |
127 | for (pgrp = pgrphash[PIDHASH(pgid)]; |
128 | pgrp != NULL; pgrp = pgrp->pg_hforw) | |
8fe87cbb | 129 | if (pgrp->pg_id == pgid) |
b3ce9b0f | 130 | return (pgrp); |
cb84e0ab | 131 | return (NULL); |
8fe87cbb MT |
132 | } |
133 | ||
134 | /* | |
135 | * Move p to a new or existing process group (and session) | |
136 | */ | |
bed84066 | 137 | enterpgrp(p, pgid, mksess) |
8fe87cbb MT |
138 | register struct proc *p; |
139 | pid_t pgid; | |
4d808bff | 140 | int mksess; |
8fe87cbb MT |
141 | { |
142 | register struct pgrp *pgrp = pgfind(pgid); | |
2dccc728 | 143 | register struct proc **pp; |
2dccc728 | 144 | int n; |
8fe87cbb | 145 | |
944e89dc | 146 | #ifdef DIAGNOSTIC |
cb84e0ab | 147 | if (pgrp != NULL && mksess) /* firewalls */ |
bed84066 | 148 | panic("enterpgrp: setsid into non-empty pgrp"); |
8fe87cbb | 149 | if (SESS_LEADER(p)) |
bed84066 | 150 | panic("enterpgrp: session leader attempted setpgrp"); |
944e89dc | 151 | #endif |
2e8f8cae | 152 | if (pgrp == NULL) { |
f9e28ab9 MT |
153 | pid_t savepid = p->p_pid; |
154 | struct proc *np; | |
8fe87cbb MT |
155 | /* |
156 | * new process group | |
157 | */ | |
944e89dc | 158 | #ifdef DIAGNOSTIC |
8fe87cbb | 159 | if (p->p_pid != pgid) |
bed84066 | 160 | panic("enterpgrp: new pgrp and pid != pgid"); |
944e89dc | 161 | #endif |
8fe87cbb MT |
162 | MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, |
163 | M_WAITOK); | |
f9e28ab9 MT |
164 | if ((np = pfind(savepid)) == NULL || np != p) |
165 | return (ESRCH); | |
8fe87cbb MT |
166 | if (mksess) { |
167 | register struct session *sess; | |
f3aac35d | 168 | |
8fe87cbb MT |
169 | /* |
170 | * new session | |
171 | */ | |
172 | MALLOC(sess, struct session *, sizeof(struct session), | |
173 | M_SESSION, M_WAITOK); | |
174 | sess->s_leader = p; | |
175 | sess->s_count = 1; | |
944e89dc MT |
176 | sess->s_ttyvp = NULL; |
177 | sess->s_ttyp = NULL; | |
f3aac35d MK |
178 | bcopy(p->p_session->s_login, sess->s_login, |
179 | sizeof(sess->s_login)); | |
cf5ef508 | 180 | p->p_flag &= ~P_CONTROLT; |
8fe87cbb | 181 | pgrp->pg_session = sess; |
944e89dc | 182 | #ifdef DIAGNOSTIC |
bed84066 MK |
183 | if (p != curproc) |
184 | panic("enterpgrp: mksession and p != curproc"); | |
944e89dc | 185 | #endif |
8fe87cbb MT |
186 | } else { |
187 | pgrp->pg_session = p->p_session; | |
188 | pgrp->pg_session->s_count++; | |
189 | } | |
190 | pgrp->pg_id = pgid; | |
2dccc728 | 191 | pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)]; |
8fe87cbb MT |
192 | pgrphash[n] = pgrp; |
193 | pgrp->pg_jobc = 0; | |
944e89dc | 194 | pgrp->pg_mem = NULL; |
69ed180a | 195 | } else if (pgrp == p->p_pgrp) |
f9e28ab9 | 196 | return (0); |
2dccc728 | 197 | |
8fe87cbb | 198 | /* |
2dccc728 MK |
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. | |
8fe87cbb | 202 | */ |
2dccc728 MK |
203 | fixjobc(p, pgrp, 1); |
204 | fixjobc(p, p->p_pgrp, 0); | |
205 | ||
8fe87cbb MT |
206 | /* |
207 | * unlink p from old process group | |
208 | */ | |
f9e28ab9 | 209 | for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) { |
8fe87cbb MT |
210 | if (*pp == p) { |
211 | *pp = p->p_pgrpnxt; | |
f9e28ab9 | 212 | break; |
8fe87cbb | 213 | } |
f9e28ab9 MT |
214 | } |
215 | #ifdef DIAGNOSTIC | |
216 | if (pp == NULL) | |
217 | panic("enterpgrp: can't find p on old pgrp"); | |
218 | #endif | |
2dccc728 MK |
219 | /* |
220 | * delete old if empty | |
221 | */ | |
222 | if (p->p_pgrp->pg_mem == 0) | |
223 | pgdelete(p->p_pgrp); | |
8fe87cbb MT |
224 | /* |
225 | * link into new one | |
226 | */ | |
2dccc728 | 227 | p->p_pgrp = pgrp; |
8fe87cbb MT |
228 | p->p_pgrpnxt = pgrp->pg_mem; |
229 | pgrp->pg_mem = p; | |
f9e28ab9 | 230 | return (0); |
8fe87cbb MT |
231 | } |
232 | ||
233 | /* | |
234 | * remove process from process group | |
235 | */ | |
bed84066 | 236 | leavepgrp(p) |
8fe87cbb MT |
237 | register struct proc *p; |
238 | { | |
239 | register struct proc **pp = &p->p_pgrp->pg_mem; | |
8fe87cbb | 240 | |
f9e28ab9 | 241 | for (; *pp; pp = &(*pp)->p_pgrpnxt) { |
8fe87cbb MT |
242 | if (*pp == p) { |
243 | *pp = p->p_pgrpnxt; | |
f9e28ab9 | 244 | break; |
8fe87cbb | 245 | } |
f9e28ab9 MT |
246 | } |
247 | #ifdef DIAGNOSTIC | |
248 | if (pp == NULL) | |
249 | panic("leavepgrp: can't find p in pgrp"); | |
250 | #endif | |
8fe87cbb MT |
251 | if (!p->p_pgrp->pg_mem) |
252 | pgdelete(p->p_pgrp); | |
253 | p->p_pgrp = 0; | |
f9e28ab9 | 254 | return (0); |
8fe87cbb MT |
255 | } |
256 | ||
257 | /* | |
258 | * delete a process group | |
259 | */ | |
260 | pgdelete(pgrp) | |
261 | register struct pgrp *pgrp; | |
262 | { | |
263 | register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)]; | |
264 | ||
944e89dc MT |
265 | if (pgrp->pg_session->s_ttyp != NULL && |
266 | pgrp->pg_session->s_ttyp->t_pgrp == pgrp) | |
267 | pgrp->pg_session->s_ttyp->t_pgrp = NULL; | |
f9e28ab9 | 268 | for (; *pgp; pgp = &(*pgp)->pg_hforw) { |
8fe87cbb MT |
269 | if (*pgp == pgrp) { |
270 | *pgp = pgrp->pg_hforw; | |
f9e28ab9 | 271 | break; |
8fe87cbb | 272 | } |
f9e28ab9 MT |
273 | } |
274 | #ifdef DIAGNOSTIC | |
275 | if (pgp == NULL) | |
276 | panic("pgdelete: can't find pgrp on hash chain"); | |
277 | #endif | |
8fe87cbb MT |
278 | if (--pgrp->pg_session->s_count == 0) |
279 | FREE(pgrp->pg_session, M_SESSION); | |
280 | FREE(pgrp, M_PGRP); | |
281 | } | |
282 | ||
4d808bff | 283 | static void orphanpg(); |
3fb7685a | 284 | |
69ed180a | 285 | /* |
2dccc728 MK |
286 | * Adjust pgrp jobc counters when specified process changes process group. |
287 | * We count the number of processes in each process group that "qualify" | |
288 | * the group for terminal job control (those with a parent in a different | |
289 | * process group of the same session). If that count reaches zero, the | |
290 | * process group becomes orphaned. Check both the specified process' | |
291 | * process group and that of its children. | |
292 | * entering == 0 => p is leaving specified group. | |
293 | * entering == 1 => p is entering specified group. | |
69ed180a | 294 | */ |
2dccc728 | 295 | fixjobc(p, pgrp, entering) |
69ed180a | 296 | register struct proc *p; |
2dccc728 MK |
297 | register struct pgrp *pgrp; |
298 | int entering; | |
69ed180a | 299 | { |
2dccc728 MK |
300 | register struct pgrp *hispgrp; |
301 | register struct session *mysession = pgrp->pg_session; | |
69ed180a | 302 | |
2dccc728 MK |
303 | /* |
304 | * Check p's parent to see whether p qualifies its own process | |
305 | * group; if so, adjust count for p's process group. | |
306 | */ | |
307 | if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && | |
69ed180a | 308 | hispgrp->pg_session == mysession) |
2dccc728 MK |
309 | if (entering) |
310 | pgrp->pg_jobc++; | |
311 | else if (--pgrp->pg_jobc == 0) | |
312 | orphanpg(pgrp); | |
69ed180a | 313 | |
2dccc728 MK |
314 | /* |
315 | * Check this process' children to see whether they qualify | |
316 | * their process groups; if so, adjust counts for children's | |
317 | * process groups. | |
318 | */ | |
319 | for (p = p->p_cptr; p; p = p->p_osptr) | |
320 | if ((hispgrp = p->p_pgrp) != pgrp && | |
69ed180a MT |
321 | hispgrp->pg_session == mysession && |
322 | p->p_stat != SZOMB) | |
2dccc728 | 323 | if (entering) |
69ed180a | 324 | hispgrp->pg_jobc++; |
2dccc728 MK |
325 | else if (--hispgrp->pg_jobc == 0) |
326 | orphanpg(hispgrp); | |
327 | } | |
69ed180a | 328 | |
2dccc728 MK |
329 | /* |
330 | * A process group has become orphaned; | |
331 | * if there are any stopped processes in the group, | |
332 | * hang-up all process in that group. | |
333 | */ | |
4d808bff | 334 | static void |
2dccc728 MK |
335 | orphanpg(pg) |
336 | struct pgrp *pg; | |
337 | { | |
338 | register struct proc *p; | |
339 | ||
340 | for (p = pg->pg_mem; p; p = p->p_pgrpnxt) { | |
341 | if (p->p_stat == SSTOP) { | |
342 | for (p = pg->pg_mem; p; p = p->p_pgrpnxt) { | |
343 | psignal(p, SIGHUP); | |
344 | psignal(p, SIGCONT); | |
69ed180a | 345 | } |
2dccc728 MK |
346 | return; |
347 | } | |
348 | } | |
69ed180a | 349 | } |
2dccc728 | 350 | |
c4ec2128 | 351 | #ifdef debug |
8fe87cbb MT |
352 | /* DEBUG */ |
353 | pgrpdump() | |
354 | { | |
355 | register struct pgrp *pgrp; | |
356 | register struct proc *p; | |
357 | register i; | |
358 | ||
359 | for (i=0; i<PIDHSZ; i++) { | |
360 | if (pgrphash[i]) { | |
361 | printf("\tindx %d\n", i); | |
362 | for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) { | |
363 | printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n", | |
364 | pgrp, pgrp->pg_id, pgrp->pg_session, | |
365 | pgrp->pg_session->s_count, pgrp->pg_mem); | |
366 | for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) { | |
367 | printf("\t\tpid %d addr %x pgrp %x\n", | |
368 | p->p_pid, p, p->p_pgrp); | |
369 | } | |
370 | } | |
371 | ||
372 | } | |
373 | } | |
374 | } | |
c4ec2128 | 375 | #endif /* debug */ |