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 | * |
29e5014e | 7 | * @(#)kern_proc.c 8.7 (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 { | |
3ef0a118 | 30 | LIST_ENTRY(uidinfo) ui_hash; |
0c06af94 KM |
31 | uid_t ui_uid; |
32 | long ui_proccnt; | |
3ef0a118 KM |
33 | }; |
34 | #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) | |
35 | LIST_HEAD(uihashhead, uidinfo) *uihashtbl; | |
36 | u_long uihash; /* size of hash table - 1 */ | |
0c06af94 KM |
37 | |
38 | /* | |
3ef0a118 | 39 | * Other process lists |
0c06af94 | 40 | */ |
3ef0a118 KM |
41 | struct pidhashhead *pidhashtbl; |
42 | u_long pidhash; | |
43 | struct pgrphashhead *pgrphashtbl; | |
44 | u_long pgrphash; | |
45 | struct proclist allproc; | |
46 | struct proclist zombproc; | |
47 | ||
48 | /* | |
49 | * Initialize global process hashing structures. | |
50 | */ | |
5d263ebe | 51 | void |
3ef0a118 | 52 | procinit() |
0c06af94 KM |
53 | { |
54 | ||
3ef0a118 KM |
55 | LIST_INIT(&allproc); |
56 | LIST_INIT(&zombproc); | |
57 | pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); | |
58 | pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash); | |
0c06af94 KM |
59 | uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash); |
60 | } | |
61 | ||
62 | /* | |
63 | * Change the count associated with number of processes | |
64 | * a given user is using. | |
65 | */ | |
66 | int | |
67 | chgproccnt(uid, diff) | |
68 | uid_t uid; | |
69 | int diff; | |
70 | { | |
3ef0a118 KM |
71 | register struct uidinfo *uip; |
72 | register struct uihashhead *uipp; | |
0c06af94 | 73 | |
3ef0a118 KM |
74 | uipp = UIHASH(uid); |
75 | for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next) | |
0c06af94 KM |
76 | if (uip->ui_uid == uid) |
77 | break; | |
78 | if (uip) { | |
79 | uip->ui_proccnt += diff; | |
80 | if (uip->ui_proccnt > 0) | |
81 | return (uip->ui_proccnt); | |
82 | if (uip->ui_proccnt < 0) | |
83 | panic("chgproccnt: procs < 0"); | |
3ef0a118 | 84 | LIST_REMOVE(uip, ui_hash); |
0c06af94 KM |
85 | FREE(uip, M_PROC); |
86 | return (0); | |
87 | } | |
88 | if (diff <= 0) { | |
89 | if (diff == 0) | |
90 | return(0); | |
91 | panic("chgproccnt: lost user"); | |
92 | } | |
93 | MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); | |
3ef0a118 | 94 | LIST_INSERT_HEAD(uipp, uip, ui_hash); |
0c06af94 KM |
95 | uip->ui_uid = uid; |
96 | uip->ui_proccnt = diff; | |
97 | return (diff); | |
98 | } | |
99 | ||
29dd101b | 100 | /* |
4147b3f6 | 101 | * Is p an inferior of the current process? |
29dd101b | 102 | */ |
4147b3f6 | 103 | inferior(p) |
a2a2a0d6 | 104 | register struct proc *p; |
29dd101b | 105 | { |
2dccc728 | 106 | |
bed84066 MK |
107 | for (; p != curproc; p = p->p_pptr) |
108 | if (p->p_pid == 0) | |
4147b3f6 BJ |
109 | return (0); |
110 | return (1); | |
29dd101b | 111 | } |
a2a2a0d6 | 112 | |
b3ce9b0f MK |
113 | /* |
114 | * Locate a process by number | |
115 | */ | |
a2a2a0d6 BJ |
116 | struct proc * |
117 | pfind(pid) | |
cb84e0ab | 118 | register pid_t pid; |
a2a2a0d6 | 119 | { |
cb84e0ab | 120 | register struct proc *p; |
a2a2a0d6 | 121 | |
3ef0a118 | 122 | for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next) |
a2a2a0d6 BJ |
123 | if (p->p_pid == pid) |
124 | return (p); | |
cb84e0ab | 125 | return (NULL); |
a2a2a0d6 | 126 | } |
1d348849 | 127 | |
8fe87cbb MT |
128 | /* |
129 | * Locate a process group by number | |
130 | */ | |
131 | struct pgrp * | |
132 | pgfind(pgid) | |
133 | register pid_t pgid; | |
134 | { | |
cb84e0ab | 135 | register struct pgrp *pgrp; |
8fe87cbb | 136 | |
3ef0a118 KM |
137 | for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; |
138 | pgrp = pgrp->pg_hash.le_next) | |
8fe87cbb | 139 | if (pgrp->pg_id == pgid) |
b3ce9b0f | 140 | return (pgrp); |
cb84e0ab | 141 | return (NULL); |
8fe87cbb MT |
142 | } |
143 | ||
144 | /* | |
145 | * Move p to a new or existing process group (and session) | |
146 | */ | |
29e5014e | 147 | int |
bed84066 | 148 | enterpgrp(p, pgid, mksess) |
8fe87cbb MT |
149 | register struct proc *p; |
150 | pid_t pgid; | |
4d808bff | 151 | int mksess; |
8fe87cbb MT |
152 | { |
153 | register struct pgrp *pgrp = pgfind(pgid); | |
8fe87cbb | 154 | |
944e89dc | 155 | #ifdef DIAGNOSTIC |
cb84e0ab | 156 | if (pgrp != NULL && mksess) /* firewalls */ |
bed84066 | 157 | panic("enterpgrp: setsid into non-empty pgrp"); |
8fe87cbb | 158 | if (SESS_LEADER(p)) |
bed84066 | 159 | panic("enterpgrp: session leader attempted setpgrp"); |
944e89dc | 160 | #endif |
2e8f8cae | 161 | if (pgrp == NULL) { |
f9e28ab9 MT |
162 | pid_t savepid = p->p_pid; |
163 | struct proc *np; | |
8fe87cbb MT |
164 | /* |
165 | * new process group | |
166 | */ | |
944e89dc | 167 | #ifdef DIAGNOSTIC |
8fe87cbb | 168 | if (p->p_pid != pgid) |
bed84066 | 169 | panic("enterpgrp: new pgrp and pid != pgid"); |
944e89dc | 170 | #endif |
8fe87cbb | 171 | MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, |
3ef0a118 | 172 | M_WAITOK); |
f9e28ab9 MT |
173 | if ((np = pfind(savepid)) == NULL || np != p) |
174 | return (ESRCH); | |
8fe87cbb MT |
175 | if (mksess) { |
176 | register struct session *sess; | |
f3aac35d | 177 | |
8fe87cbb MT |
178 | /* |
179 | * new session | |
180 | */ | |
181 | MALLOC(sess, struct session *, sizeof(struct session), | |
3ef0a118 | 182 | M_SESSION, M_WAITOK); |
8fe87cbb MT |
183 | sess->s_leader = p; |
184 | sess->s_count = 1; | |
944e89dc MT |
185 | sess->s_ttyvp = NULL; |
186 | sess->s_ttyp = NULL; | |
f3aac35d MK |
187 | bcopy(p->p_session->s_login, sess->s_login, |
188 | sizeof(sess->s_login)); | |
cf5ef508 | 189 | p->p_flag &= ~P_CONTROLT; |
8fe87cbb | 190 | pgrp->pg_session = sess; |
944e89dc | 191 | #ifdef DIAGNOSTIC |
bed84066 MK |
192 | if (p != curproc) |
193 | panic("enterpgrp: mksession and p != curproc"); | |
944e89dc | 194 | #endif |
8fe87cbb MT |
195 | } else { |
196 | pgrp->pg_session = p->p_session; | |
197 | pgrp->pg_session->s_count++; | |
198 | } | |
199 | pgrp->pg_id = pgid; | |
3ef0a118 KM |
200 | LIST_INIT(&pgrp->pg_members); |
201 | LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); | |
8fe87cbb | 202 | pgrp->pg_jobc = 0; |
69ed180a | 203 | } else if (pgrp == p->p_pgrp) |
f9e28ab9 | 204 | return (0); |
2dccc728 | 205 | |
8fe87cbb | 206 | /* |
2dccc728 MK |
207 | * Adjust eligibility of affected pgrps to participate in job control. |
208 | * Increment eligibility counts before decrementing, otherwise we | |
209 | * could reach 0 spuriously during the first call. | |
8fe87cbb | 210 | */ |
2dccc728 MK |
211 | fixjobc(p, pgrp, 1); |
212 | fixjobc(p, p->p_pgrp, 0); | |
213 | ||
3ef0a118 KM |
214 | LIST_REMOVE(p, p_pglist); |
215 | if (p->p_pgrp->pg_members.lh_first == 0) | |
2dccc728 | 216 | pgdelete(p->p_pgrp); |
2dccc728 | 217 | p->p_pgrp = pgrp; |
3ef0a118 | 218 | LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); |
f9e28ab9 | 219 | return (0); |
8fe87cbb MT |
220 | } |
221 | ||
222 | /* | |
223 | * remove process from process group | |
224 | */ | |
29e5014e | 225 | int |
bed84066 | 226 | leavepgrp(p) |
8fe87cbb MT |
227 | register struct proc *p; |
228 | { | |
8fe87cbb | 229 | |
3ef0a118 KM |
230 | LIST_REMOVE(p, p_pglist); |
231 | if (p->p_pgrp->pg_members.lh_first == 0) | |
8fe87cbb MT |
232 | pgdelete(p->p_pgrp); |
233 | p->p_pgrp = 0; | |
f9e28ab9 | 234 | return (0); |
8fe87cbb MT |
235 | } |
236 | ||
237 | /* | |
238 | * delete a process group | |
239 | */ | |
5d263ebe | 240 | void |
8fe87cbb MT |
241 | pgdelete(pgrp) |
242 | register struct pgrp *pgrp; | |
243 | { | |
8fe87cbb | 244 | |
944e89dc MT |
245 | if (pgrp->pg_session->s_ttyp != NULL && |
246 | pgrp->pg_session->s_ttyp->t_pgrp == pgrp) | |
247 | pgrp->pg_session->s_ttyp->t_pgrp = NULL; | |
3ef0a118 | 248 | LIST_REMOVE(pgrp, pg_hash); |
8fe87cbb MT |
249 | if (--pgrp->pg_session->s_count == 0) |
250 | FREE(pgrp->pg_session, M_SESSION); | |
251 | FREE(pgrp, M_PGRP); | |
252 | } | |
253 | ||
4d808bff | 254 | static void orphanpg(); |
3fb7685a | 255 | |
69ed180a | 256 | /* |
2dccc728 MK |
257 | * Adjust pgrp jobc counters when specified process changes process group. |
258 | * We count the number of processes in each process group that "qualify" | |
259 | * the group for terminal job control (those with a parent in a different | |
260 | * process group of the same session). If that count reaches zero, the | |
261 | * process group becomes orphaned. Check both the specified process' | |
262 | * process group and that of its children. | |
263 | * entering == 0 => p is leaving specified group. | |
264 | * entering == 1 => p is entering specified group. | |
69ed180a | 265 | */ |
5d263ebe | 266 | void |
2dccc728 | 267 | fixjobc(p, pgrp, entering) |
69ed180a | 268 | register struct proc *p; |
2dccc728 MK |
269 | register struct pgrp *pgrp; |
270 | int entering; | |
69ed180a | 271 | { |
2dccc728 MK |
272 | register struct pgrp *hispgrp; |
273 | register struct session *mysession = pgrp->pg_session; | |
69ed180a | 274 | |
2dccc728 MK |
275 | /* |
276 | * Check p's parent to see whether p qualifies its own process | |
277 | * group; if so, adjust count for p's process group. | |
278 | */ | |
279 | if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && | |
69ed180a | 280 | hispgrp->pg_session == mysession) |
2dccc728 MK |
281 | if (entering) |
282 | pgrp->pg_jobc++; | |
283 | else if (--pgrp->pg_jobc == 0) | |
284 | orphanpg(pgrp); | |
69ed180a | 285 | |
2dccc728 MK |
286 | /* |
287 | * Check this process' children to see whether they qualify | |
288 | * their process groups; if so, adjust counts for children's | |
289 | * process groups. | |
290 | */ | |
3ef0a118 | 291 | for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next) |
2dccc728 | 292 | if ((hispgrp = p->p_pgrp) != pgrp && |
69ed180a MT |
293 | hispgrp->pg_session == mysession && |
294 | p->p_stat != SZOMB) | |
2dccc728 | 295 | if (entering) |
69ed180a | 296 | hispgrp->pg_jobc++; |
2dccc728 MK |
297 | else if (--hispgrp->pg_jobc == 0) |
298 | orphanpg(hispgrp); | |
299 | } | |
69ed180a | 300 | |
2dccc728 MK |
301 | /* |
302 | * A process group has become orphaned; | |
303 | * if there are any stopped processes in the group, | |
304 | * hang-up all process in that group. | |
305 | */ | |
4d808bff | 306 | static void |
2dccc728 MK |
307 | orphanpg(pg) |
308 | struct pgrp *pg; | |
309 | { | |
310 | register struct proc *p; | |
311 | ||
3ef0a118 | 312 | for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { |
2dccc728 | 313 | if (p->p_stat == SSTOP) { |
3ef0a118 KM |
314 | for (p = pg->pg_members.lh_first; p != 0; |
315 | p = p->p_pglist.le_next) { | |
2dccc728 MK |
316 | psignal(p, SIGHUP); |
317 | psignal(p, SIGCONT); | |
69ed180a | 318 | } |
2dccc728 MK |
319 | return; |
320 | } | |
321 | } | |
69ed180a | 322 | } |
2dccc728 | 323 | |
3ef0a118 | 324 | #ifdef DEBUG |
8fe87cbb MT |
325 | pgrpdump() |
326 | { | |
327 | register struct pgrp *pgrp; | |
328 | register struct proc *p; | |
329 | register i; | |
330 | ||
3ef0a118 KM |
331 | for (i = 0; i <= pgrphash; i++) { |
332 | if (pgrp = pgrphashtbl[i].lh_first) { | |
333 | printf("\tindx %d\n", i); | |
334 | for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) { | |
335 | printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n", | |
336 | pgrp, pgrp->pg_id, pgrp->pg_session, | |
337 | pgrp->pg_session->s_count, | |
338 | pgrp->pg_members.lh_first); | |
339 | for (p = pgrp->pg_members.lh_first; p != 0; | |
340 | p = p->p_pglist.le_next) { | |
341 | printf("\t\tpid %d addr %x pgrp %x\n", | |
342 | p->p_pid, p, p->p_pgrp); | |
343 | } | |
344 | } | |
8fe87cbb MT |
345 | } |
346 | } | |
347 | } | |
3ef0a118 | 348 | #endif /* DEBUG */ |