Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
3fb7685a | 2 | * Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California. |
c4ec2128 | 3 | * All rights reserved. |
da7c5cc6 | 4 | * |
dbf0c423 | 5 | * %sccs.include.redist.c% |
c4ec2128 | 6 | * |
0c06af94 | 7 | * @(#)kern_proc.c 7.20 (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) | |
8fe87cbb | 108 | register pid; |
a2a2a0d6 | 109 | { |
b3ce9b0f | 110 | register struct proc *p = pidhash[PIDHASH(pid)]; |
a2a2a0d6 | 111 | |
b3ce9b0f | 112 | for (; p; p = p->p_hash) |
a2a2a0d6 BJ |
113 | if (p->p_pid == pid) |
114 | return (p); | |
115 | return ((struct proc *)0); | |
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 | { | |
125 | register struct pgrp *pgrp = pgrphash[PIDHASH(pgid)]; | |
126 | ||
127 | for (; pgrp; pgrp = pgrp->pg_hforw) | |
128 | if (pgrp->pg_id == pgid) | |
b3ce9b0f | 129 | return (pgrp); |
8fe87cbb MT |
130 | return ((struct pgrp *)0); |
131 | } | |
132 | ||
133 | /* | |
134 | * Move p to a new or existing process group (and session) | |
135 | */ | |
bed84066 | 136 | enterpgrp(p, pgid, mksess) |
8fe87cbb MT |
137 | register struct proc *p; |
138 | pid_t pgid; | |
4d808bff | 139 | int mksess; |
8fe87cbb MT |
140 | { |
141 | register struct pgrp *pgrp = pgfind(pgid); | |
2dccc728 | 142 | register struct proc **pp; |
8fe87cbb | 143 | register struct proc *cp; |
2dccc728 | 144 | int n; |
8fe87cbb | 145 | |
944e89dc | 146 | #ifdef DIAGNOSTIC |
8fe87cbb | 147 | if (pgrp && 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) { |
8fe87cbb MT |
153 | /* |
154 | * new process group | |
155 | */ | |
944e89dc | 156 | #ifdef DIAGNOSTIC |
8fe87cbb | 157 | if (p->p_pid != pgid) |
bed84066 | 158 | panic("enterpgrp: new pgrp and pid != pgid"); |
944e89dc | 159 | #endif |
8fe87cbb MT |
160 | MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, |
161 | M_WAITOK); | |
162 | if (mksess) { | |
163 | register struct session *sess; | |
f3aac35d | 164 | |
8fe87cbb MT |
165 | /* |
166 | * new session | |
167 | */ | |
168 | MALLOC(sess, struct session *, sizeof(struct session), | |
169 | M_SESSION, M_WAITOK); | |
170 | sess->s_leader = p; | |
171 | sess->s_count = 1; | |
944e89dc MT |
172 | sess->s_ttyvp = NULL; |
173 | sess->s_ttyp = NULL; | |
f3aac35d MK |
174 | bcopy(p->p_session->s_login, sess->s_login, |
175 | sizeof(sess->s_login)); | |
944e89dc | 176 | p->p_flag &= ~SCTTY; |
8fe87cbb | 177 | pgrp->pg_session = sess; |
944e89dc | 178 | #ifdef DIAGNOSTIC |
bed84066 MK |
179 | if (p != curproc) |
180 | panic("enterpgrp: mksession and p != curproc"); | |
944e89dc | 181 | #endif |
8fe87cbb MT |
182 | } else { |
183 | pgrp->pg_session = p->p_session; | |
184 | pgrp->pg_session->s_count++; | |
185 | } | |
186 | pgrp->pg_id = pgid; | |
2dccc728 | 187 | pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)]; |
8fe87cbb MT |
188 | pgrphash[n] = pgrp; |
189 | pgrp->pg_jobc = 0; | |
944e89dc | 190 | pgrp->pg_mem = NULL; |
69ed180a MT |
191 | } else if (pgrp == p->p_pgrp) |
192 | return; | |
2dccc728 | 193 | |
8fe87cbb | 194 | /* |
2dccc728 MK |
195 | * Adjust eligibility of affected pgrps to participate in job control. |
196 | * Increment eligibility counts before decrementing, otherwise we | |
197 | * could reach 0 spuriously during the first call. | |
8fe87cbb | 198 | */ |
2dccc728 MK |
199 | fixjobc(p, pgrp, 1); |
200 | fixjobc(p, p->p_pgrp, 0); | |
201 | ||
8fe87cbb MT |
202 | /* |
203 | * unlink p from old process group | |
204 | */ | |
2dccc728 | 205 | for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) |
8fe87cbb MT |
206 | if (*pp == p) { |
207 | *pp = p->p_pgrpnxt; | |
208 | goto done; | |
209 | } | |
bed84066 | 210 | panic("enterpgrp: can't find p on old pgrp"); |
8fe87cbb | 211 | done: |
2dccc728 MK |
212 | /* |
213 | * delete old if empty | |
214 | */ | |
215 | if (p->p_pgrp->pg_mem == 0) | |
216 | pgdelete(p->p_pgrp); | |
8fe87cbb MT |
217 | /* |
218 | * link into new one | |
219 | */ | |
2dccc728 | 220 | p->p_pgrp = pgrp; |
8fe87cbb MT |
221 | p->p_pgrpnxt = pgrp->pg_mem; |
222 | pgrp->pg_mem = p; | |
8fe87cbb MT |
223 | } |
224 | ||
225 | /* | |
226 | * remove process from process group | |
227 | */ | |
bed84066 | 228 | leavepgrp(p) |
8fe87cbb MT |
229 | register struct proc *p; |
230 | { | |
231 | register struct proc **pp = &p->p_pgrp->pg_mem; | |
8fe87cbb MT |
232 | |
233 | for (; *pp; pp = &(*pp)->p_pgrpnxt) | |
234 | if (*pp == p) { | |
235 | *pp = p->p_pgrpnxt; | |
236 | goto done; | |
237 | } | |
bed84066 | 238 | panic("leavepgrp: can't find p in pgrp"); |
8fe87cbb MT |
239 | done: |
240 | if (!p->p_pgrp->pg_mem) | |
241 | pgdelete(p->p_pgrp); | |
242 | p->p_pgrp = 0; | |
243 | } | |
244 | ||
245 | /* | |
246 | * delete a process group | |
247 | */ | |
248 | pgdelete(pgrp) | |
249 | register struct pgrp *pgrp; | |
250 | { | |
251 | register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)]; | |
252 | ||
944e89dc MT |
253 | if (pgrp->pg_session->s_ttyp != NULL && |
254 | pgrp->pg_session->s_ttyp->t_pgrp == pgrp) | |
255 | pgrp->pg_session->s_ttyp->t_pgrp = NULL; | |
8fe87cbb MT |
256 | for (; *pgp; pgp = &(*pgp)->pg_hforw) |
257 | if (*pgp == pgrp) { | |
258 | *pgp = pgrp->pg_hforw; | |
259 | goto done; | |
260 | } | |
2e8f8cae | 261 | panic("pgdelete: can't find pgrp on hash chain"); |
8fe87cbb MT |
262 | done: |
263 | if (--pgrp->pg_session->s_count == 0) | |
264 | FREE(pgrp->pg_session, M_SESSION); | |
265 | FREE(pgrp, M_PGRP); | |
266 | } | |
267 | ||
4d808bff | 268 | static void orphanpg(); |
3fb7685a | 269 | |
69ed180a | 270 | /* |
2dccc728 MK |
271 | * Adjust pgrp jobc counters when specified process changes process group. |
272 | * We count the number of processes in each process group that "qualify" | |
273 | * the group for terminal job control (those with a parent in a different | |
274 | * process group of the same session). If that count reaches zero, the | |
275 | * process group becomes orphaned. Check both the specified process' | |
276 | * process group and that of its children. | |
277 | * entering == 0 => p is leaving specified group. | |
278 | * entering == 1 => p is entering specified group. | |
69ed180a | 279 | */ |
2dccc728 | 280 | fixjobc(p, pgrp, entering) |
69ed180a | 281 | register struct proc *p; |
2dccc728 MK |
282 | register struct pgrp *pgrp; |
283 | int entering; | |
69ed180a | 284 | { |
2dccc728 MK |
285 | register struct pgrp *hispgrp; |
286 | register struct session *mysession = pgrp->pg_session; | |
69ed180a | 287 | |
2dccc728 MK |
288 | /* |
289 | * Check p's parent to see whether p qualifies its own process | |
290 | * group; if so, adjust count for p's process group. | |
291 | */ | |
292 | if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && | |
69ed180a | 293 | hispgrp->pg_session == mysession) |
2dccc728 MK |
294 | if (entering) |
295 | pgrp->pg_jobc++; | |
296 | else if (--pgrp->pg_jobc == 0) | |
297 | orphanpg(pgrp); | |
69ed180a | 298 | |
2dccc728 MK |
299 | /* |
300 | * Check this process' children to see whether they qualify | |
301 | * their process groups; if so, adjust counts for children's | |
302 | * process groups. | |
303 | */ | |
304 | for (p = p->p_cptr; p; p = p->p_osptr) | |
305 | if ((hispgrp = p->p_pgrp) != pgrp && | |
69ed180a MT |
306 | hispgrp->pg_session == mysession && |
307 | p->p_stat != SZOMB) | |
2dccc728 | 308 | if (entering) |
69ed180a | 309 | hispgrp->pg_jobc++; |
2dccc728 MK |
310 | else if (--hispgrp->pg_jobc == 0) |
311 | orphanpg(hispgrp); | |
312 | } | |
69ed180a | 313 | |
2dccc728 MK |
314 | /* |
315 | * A process group has become orphaned; | |
316 | * if there are any stopped processes in the group, | |
317 | * hang-up all process in that group. | |
318 | */ | |
4d808bff | 319 | static void |
2dccc728 MK |
320 | orphanpg(pg) |
321 | struct pgrp *pg; | |
322 | { | |
323 | register struct proc *p; | |
324 | ||
325 | for (p = pg->pg_mem; p; p = p->p_pgrpnxt) { | |
326 | if (p->p_stat == SSTOP) { | |
327 | for (p = pg->pg_mem; p; p = p->p_pgrpnxt) { | |
328 | psignal(p, SIGHUP); | |
329 | psignal(p, SIGCONT); | |
69ed180a | 330 | } |
2dccc728 MK |
331 | return; |
332 | } | |
333 | } | |
69ed180a | 334 | } |
2dccc728 | 335 | |
c4ec2128 | 336 | #ifdef debug |
8fe87cbb MT |
337 | /* DEBUG */ |
338 | pgrpdump() | |
339 | { | |
340 | register struct pgrp *pgrp; | |
341 | register struct proc *p; | |
342 | register i; | |
343 | ||
344 | for (i=0; i<PIDHSZ; i++) { | |
345 | if (pgrphash[i]) { | |
346 | printf("\tindx %d\n", i); | |
347 | for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) { | |
348 | printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n", | |
349 | pgrp, pgrp->pg_id, pgrp->pg_session, | |
350 | pgrp->pg_session->s_count, pgrp->pg_mem); | |
351 | for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) { | |
352 | printf("\t\tpid %d addr %x pgrp %x\n", | |
353 | p->p_pid, p, p->p_pgrp); | |
354 | } | |
355 | } | |
356 | ||
357 | } | |
358 | } | |
359 | } | |
c4ec2128 | 360 | #endif /* debug */ |