allow downgrade of read-write to read-only (though I cannot imagine
[unix-history] / usr / src / sys / kern / kern_proc.c
CommitLineData
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 */
29struct uidinfo {
30 struct uidinfo *ui_next;
31 struct uidinfo **ui_prev;
32 uid_t ui_uid;
33 long ui_proccnt;
34} **uihashtbl;
35u_long uihash; /* size of hash table - 1 */
36#define UIHASH(uid) ((uid) & uihash)
37
38/*
39 * Allocate a hash table.
40 */
41usrinfoinit()
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 */
51int
52chgproccnt(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 93inferior(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
106struct proc *
107pfind(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 */
121struct pgrp *
122pgfind(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 136enterpgrp(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 211done:
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 228leavepgrp(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
239done:
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 */
248pgdelete(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
262done:
263 if (--pgrp->pg_session->s_count == 0)
264 FREE(pgrp->pg_session, M_SESSION);
265 FREE(pgrp, M_PGRP);
266}
267
4d808bff 268static 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 280fixjobc(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 319static void
2dccc728
MK
320orphanpg(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 */
338pgrpdump()
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 */