xref: /original-bsd/sys/kern/kern_proc.c (revision 333da485)
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)kern_proc.c	8.4 (Berkeley) 01/04/94
8  */
9 
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>
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>
25 
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 
90 /*
91  * Is p an inferior of the current process?
92  */
93 inferior(p)
94 	register struct proc *p;
95 {
96 
97 	for (; p != curproc; p = p->p_pptr)
98 		if (p->p_pid == 0)
99 			return (0);
100 	return (1);
101 }
102 
103 /*
104  * Locate a process by number
105  */
106 struct proc *
107 pfind(pid)
108 	register pid_t pid;
109 {
110 	register struct proc *p;
111 
112 	for (p = pidhash[PIDHASH(pid)]; p != NULL; p = p->p_hash)
113 		if (p->p_pid == pid)
114 			return (p);
115 	return (NULL);
116 }
117 
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;
126 
127 	for (pgrp = pgrphash[PIDHASH(pgid)];
128 	    pgrp != NULL; pgrp = pgrp->pg_hforw)
129 		if (pgrp->pg_id == pgid)
130 			return (pgrp);
131 	return (NULL);
132 }
133 
134 /*
135  * Move p to a new or existing process group (and session)
136  */
137 enterpgrp(p, pgid, mksess)
138 	register struct proc *p;
139 	pid_t pgid;
140 	int mksess;
141 {
142 	register struct pgrp *pgrp = pgfind(pgid);
143 	register struct proc **pp;
144 	int n;
145 
146 #ifdef DIAGNOSTIC
147 	if (pgrp != NULL && mksess)	/* firewalls */
148 		panic("enterpgrp: setsid into non-empty pgrp");
149 	if (SESS_LEADER(p))
150 		panic("enterpgrp: session leader attempted setpgrp");
151 #endif
152 	if (pgrp == NULL) {
153 		pid_t savepid = p->p_pid;
154 		struct proc *np;
155 		/*
156 		 * new process group
157 		 */
158 #ifdef DIAGNOSTIC
159 		if (p->p_pid != pgid)
160 			panic("enterpgrp: new pgrp and pid != pgid");
161 #endif
162 		MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
163 		       M_WAITOK);
164 		if ((np = pfind(savepid)) == NULL || np != p)
165 			return (ESRCH);
166 		if (mksess) {
167 			register struct session *sess;
168 
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;
176 			sess->s_ttyvp = NULL;
177 			sess->s_ttyp = NULL;
178 			bcopy(p->p_session->s_login, sess->s_login,
179 			    sizeof(sess->s_login));
180 			p->p_flag &= ~P_CONTROLT;
181 			pgrp->pg_session = sess;
182 #ifdef DIAGNOSTIC
183 			if (p != curproc)
184 				panic("enterpgrp: mksession and p != curproc");
185 #endif
186 		} else {
187 			pgrp->pg_session = p->p_session;
188 			pgrp->pg_session->s_count++;
189 		}
190 		pgrp->pg_id = pgid;
191 		pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)];
192 		pgrphash[n] = pgrp;
193 		pgrp->pg_jobc = 0;
194 		pgrp->pg_mem = NULL;
195 	} else if (pgrp == p->p_pgrp)
196 		return (0);
197 
198 	/*
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.
202 	 */
203 	fixjobc(p, pgrp, 1);
204 	fixjobc(p, p->p_pgrp, 0);
205 
206 	/*
207 	 * unlink p from old process group
208 	 */
209 	for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) {
210 		if (*pp == p) {
211 			*pp = p->p_pgrpnxt;
212 			break;
213 		}
214 	}
215 #ifdef DIAGNOSTIC
216 	if (pp == NULL)
217 		panic("enterpgrp: can't find p on old pgrp");
218 #endif
219 	/*
220 	 * delete old if empty
221 	 */
222 	if (p->p_pgrp->pg_mem == 0)
223 		pgdelete(p->p_pgrp);
224 	/*
225 	 * link into new one
226 	 */
227 	p->p_pgrp = pgrp;
228 	p->p_pgrpnxt = pgrp->pg_mem;
229 	pgrp->pg_mem = p;
230 	return (0);
231 }
232 
233 /*
234  * remove process from process group
235  */
236 leavepgrp(p)
237 	register struct proc *p;
238 {
239 	register struct proc **pp = &p->p_pgrp->pg_mem;
240 
241 	for (; *pp; pp = &(*pp)->p_pgrpnxt) {
242 		if (*pp == p) {
243 			*pp = p->p_pgrpnxt;
244 			break;
245 		}
246 	}
247 #ifdef DIAGNOSTIC
248 	if (pp == NULL)
249 		panic("leavepgrp: can't find p in pgrp");
250 #endif
251 	if (!p->p_pgrp->pg_mem)
252 		pgdelete(p->p_pgrp);
253 	p->p_pgrp = 0;
254 	return (0);
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 
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;
268 	for (; *pgp; pgp = &(*pgp)->pg_hforw) {
269 		if (*pgp == pgrp) {
270 			*pgp = pgrp->pg_hforw;
271 			break;
272 		}
273 	}
274 #ifdef DIAGNOSTIC
275 	if (pgp == NULL)
276 		panic("pgdelete: can't find pgrp on hash chain");
277 #endif
278 	if (--pgrp->pg_session->s_count == 0)
279 		FREE(pgrp->pg_session, M_SESSION);
280 	FREE(pgrp, M_PGRP);
281 }
282 
283 static void orphanpg();
284 
285 /*
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.
294  */
295 fixjobc(p, pgrp, entering)
296 	register struct proc *p;
297 	register struct pgrp *pgrp;
298 	int entering;
299 {
300 	register struct pgrp *hispgrp;
301 	register struct session *mysession = pgrp->pg_session;
302 
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 &&
308 	    hispgrp->pg_session == mysession)
309 		if (entering)
310 			pgrp->pg_jobc++;
311 		else if (--pgrp->pg_jobc == 0)
312 			orphanpg(pgrp);
313 
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 &&
321 		    hispgrp->pg_session == mysession &&
322 		    p->p_stat != SZOMB)
323 			if (entering)
324 				hispgrp->pg_jobc++;
325 			else if (--hispgrp->pg_jobc == 0)
326 				orphanpg(hispgrp);
327 }
328 
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  */
334 static void
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);
345 			}
346 			return;
347 		}
348 	}
349 }
350 
351 #ifdef debug
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 }
375 #endif /* debug */
376