xref: /original-bsd/sys/kern/kern_proc.c (revision 95ecee29)
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.3 (Berkeley) 09/23/93
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 	register struct proc *cp;
145 	int n;
146 
147 #ifdef DIAGNOSTIC
148 	if (pgrp != NULL && mksess)	/* firewalls */
149 		panic("enterpgrp: setsid into non-empty pgrp");
150 	if (SESS_LEADER(p))
151 		panic("enterpgrp: session leader attempted setpgrp");
152 #endif
153 	if (pgrp == NULL) {
154 		pid_t savepid = p->p_pid;
155 		struct proc *np;
156 		/*
157 		 * new process group
158 		 */
159 #ifdef DIAGNOSTIC
160 		if (p->p_pid != pgid)
161 			panic("enterpgrp: new pgrp and pid != pgid");
162 #endif
163 		MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
164 		       M_WAITOK);
165 		if ((np = pfind(savepid)) == NULL || np != p)
166 			return (ESRCH);
167 		if (mksess) {
168 			register struct session *sess;
169 
170 			/*
171 			 * new session
172 			 */
173 			MALLOC(sess, struct session *, sizeof(struct session),
174 				M_SESSION, M_WAITOK);
175 			sess->s_leader = p;
176 			sess->s_count = 1;
177 			sess->s_ttyvp = NULL;
178 			sess->s_ttyp = NULL;
179 			bcopy(p->p_session->s_login, sess->s_login,
180 			    sizeof(sess->s_login));
181 			p->p_flag &= ~P_CONTROLT;
182 			pgrp->pg_session = sess;
183 #ifdef DIAGNOSTIC
184 			if (p != curproc)
185 				panic("enterpgrp: mksession and p != curproc");
186 #endif
187 		} else {
188 			pgrp->pg_session = p->p_session;
189 			pgrp->pg_session->s_count++;
190 		}
191 		pgrp->pg_id = pgid;
192 		pgrp->pg_hforw = pgrphash[n = PIDHASH(pgid)];
193 		pgrphash[n] = pgrp;
194 		pgrp->pg_jobc = 0;
195 		pgrp->pg_mem = NULL;
196 	} else if (pgrp == p->p_pgrp)
197 		return (0);
198 
199 	/*
200 	 * Adjust eligibility of affected pgrps to participate in job control.
201 	 * Increment eligibility counts before decrementing, otherwise we
202 	 * could reach 0 spuriously during the first call.
203 	 */
204 	fixjobc(p, pgrp, 1);
205 	fixjobc(p, p->p_pgrp, 0);
206 
207 	/*
208 	 * unlink p from old process group
209 	 */
210 	for (pp = &p->p_pgrp->pg_mem; *pp; pp = &(*pp)->p_pgrpnxt) {
211 		if (*pp == p) {
212 			*pp = p->p_pgrpnxt;
213 			break;
214 		}
215 	}
216 #ifdef DIAGNOSTIC
217 	if (pp == NULL)
218 		panic("enterpgrp: can't find p on old pgrp");
219 #endif
220 	/*
221 	 * delete old if empty
222 	 */
223 	if (p->p_pgrp->pg_mem == 0)
224 		pgdelete(p->p_pgrp);
225 	/*
226 	 * link into new one
227 	 */
228 	p->p_pgrp = pgrp;
229 	p->p_pgrpnxt = pgrp->pg_mem;
230 	pgrp->pg_mem = p;
231 	return (0);
232 }
233 
234 /*
235  * remove process from process group
236  */
237 leavepgrp(p)
238 	register struct proc *p;
239 {
240 	register struct proc **pp = &p->p_pgrp->pg_mem;
241 
242 	for (; *pp; pp = &(*pp)->p_pgrpnxt) {
243 		if (*pp == p) {
244 			*pp = p->p_pgrpnxt;
245 			break;
246 		}
247 	}
248 #ifdef DIAGNOSTIC
249 	if (pp == NULL)
250 		panic("leavepgrp: can't find p in pgrp");
251 #endif
252 	if (!p->p_pgrp->pg_mem)
253 		pgdelete(p->p_pgrp);
254 	p->p_pgrp = 0;
255 	return (0);
256 }
257 
258 /*
259  * delete a process group
260  */
261 pgdelete(pgrp)
262 	register struct pgrp *pgrp;
263 {
264 	register struct pgrp **pgp = &pgrphash[PIDHASH(pgrp->pg_id)];
265 
266 	if (pgrp->pg_session->s_ttyp != NULL &&
267 	    pgrp->pg_session->s_ttyp->t_pgrp == pgrp)
268 		pgrp->pg_session->s_ttyp->t_pgrp = NULL;
269 	for (; *pgp; pgp = &(*pgp)->pg_hforw) {
270 		if (*pgp == pgrp) {
271 			*pgp = pgrp->pg_hforw;
272 			break;
273 		}
274 	}
275 #ifdef DIAGNOSTIC
276 	if (pgp == NULL)
277 		panic("pgdelete: can't find pgrp on hash chain");
278 #endif
279 	if (--pgrp->pg_session->s_count == 0)
280 		FREE(pgrp->pg_session, M_SESSION);
281 	FREE(pgrp, M_PGRP);
282 }
283 
284 static void orphanpg();
285 
286 /*
287  * Adjust pgrp jobc counters when specified process changes process group.
288  * We count the number of processes in each process group that "qualify"
289  * the group for terminal job control (those with a parent in a different
290  * process group of the same session).  If that count reaches zero, the
291  * process group becomes orphaned.  Check both the specified process'
292  * process group and that of its children.
293  * entering == 0 => p is leaving specified group.
294  * entering == 1 => p is entering specified group.
295  */
296 fixjobc(p, pgrp, entering)
297 	register struct proc *p;
298 	register struct pgrp *pgrp;
299 	int entering;
300 {
301 	register struct pgrp *hispgrp;
302 	register struct session *mysession = pgrp->pg_session;
303 
304 	/*
305 	 * Check p's parent to see whether p qualifies its own process
306 	 * group; if so, adjust count for p's process group.
307 	 */
308 	if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
309 	    hispgrp->pg_session == mysession)
310 		if (entering)
311 			pgrp->pg_jobc++;
312 		else if (--pgrp->pg_jobc == 0)
313 			orphanpg(pgrp);
314 
315 	/*
316 	 * Check this process' children to see whether they qualify
317 	 * their process groups; if so, adjust counts for children's
318 	 * process groups.
319 	 */
320 	for (p = p->p_cptr; p; p = p->p_osptr)
321 		if ((hispgrp = p->p_pgrp) != pgrp &&
322 		    hispgrp->pg_session == mysession &&
323 		    p->p_stat != SZOMB)
324 			if (entering)
325 				hispgrp->pg_jobc++;
326 			else if (--hispgrp->pg_jobc == 0)
327 				orphanpg(hispgrp);
328 }
329 
330 /*
331  * A process group has become orphaned;
332  * if there are any stopped processes in the group,
333  * hang-up all process in that group.
334  */
335 static void
336 orphanpg(pg)
337 	struct pgrp *pg;
338 {
339 	register struct proc *p;
340 
341 	for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
342 		if (p->p_stat == SSTOP) {
343 			for (p = pg->pg_mem; p; p = p->p_pgrpnxt) {
344 				psignal(p, SIGHUP);
345 				psignal(p, SIGCONT);
346 			}
347 			return;
348 		}
349 	}
350 }
351 
352 #ifdef debug
353 /* DEBUG */
354 pgrpdump()
355 {
356 	register struct pgrp *pgrp;
357 	register struct proc *p;
358 	register i;
359 
360 	for (i=0; i<PIDHSZ; i++) {
361 		if (pgrphash[i]) {
362 		  printf("\tindx %d\n", i);
363 		  for (pgrp=pgrphash[i]; pgrp; pgrp=pgrp->pg_hforw) {
364 		    printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n",
365 			pgrp, pgrp->pg_id, pgrp->pg_session,
366 			pgrp->pg_session->s_count, pgrp->pg_mem);
367 		    for (p=pgrp->pg_mem; p; p=p->p_pgrpnxt) {
368 			printf("\t\tpid %d addr %x pgrp %x\n",
369 				p->p_pid, p, p->p_pgrp);
370 		    }
371 		  }
372 
373 		}
374 	}
375 }
376 #endif /* debug */
377