1 /* $NetBSD: kern_proc.c,v 1.19 1997/05/21 19:56:50 gwr Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1989, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/map.h> 41 #include <sys/kernel.h> 42 #include <sys/proc.h> 43 #include <sys/buf.h> 44 #include <sys/acct.h> 45 #include <sys/wait.h> 46 #include <sys/file.h> 47 #include <ufs/ufs/quota.h> 48 #include <sys/uio.h> 49 #include <sys/malloc.h> 50 #include <sys/mbuf.h> 51 #include <sys/ioctl.h> 52 #include <sys/tty.h> 53 #include <sys/signalvar.h> 54 55 /* 56 * Structure associated with user cacheing. 57 */ 58 struct uidinfo { 59 LIST_ENTRY(uidinfo) ui_hash; 60 uid_t ui_uid; 61 long ui_proccnt; 62 }; 63 #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) 64 LIST_HEAD(uihashhead, uidinfo) *uihashtbl; 65 u_long uihash; /* size of hash table - 1 */ 66 67 /* 68 * Other process lists 69 */ 70 struct pidhashhead *pidhashtbl; 71 u_long pidhash; 72 struct pgrphashhead *pgrphashtbl; 73 u_long pgrphash; 74 struct proclist allproc; 75 struct proclist zombproc; 76 77 static void orphanpg __P((struct pgrp *)); 78 #ifdef DEBUG 79 void pgrpdump __P((void)); 80 #endif 81 82 /* 83 * Initialize global process hashing structures. 84 */ 85 void 86 procinit() 87 { 88 89 LIST_INIT(&allproc); 90 LIST_INIT(&zombproc); 91 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); 92 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash); 93 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash); 94 } 95 96 /* 97 * Change the count associated with number of processes 98 * a given user is using. 99 */ 100 int 101 chgproccnt(uid, diff) 102 uid_t uid; 103 int diff; 104 { 105 register struct uidinfo *uip; 106 register struct uihashhead *uipp; 107 108 uipp = UIHASH(uid); 109 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next) 110 if (uip->ui_uid == uid) 111 break; 112 if (uip) { 113 uip->ui_proccnt += diff; 114 if (uip->ui_proccnt > 0) 115 return (uip->ui_proccnt); 116 if (uip->ui_proccnt < 0) 117 panic("chgproccnt: procs < 0"); 118 LIST_REMOVE(uip, ui_hash); 119 FREE(uip, M_PROC); 120 return (0); 121 } 122 if (diff <= 0) { 123 if (diff == 0) 124 return(0); 125 panic("chgproccnt: lost user"); 126 } 127 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); 128 LIST_INSERT_HEAD(uipp, uip, ui_hash); 129 uip->ui_uid = uid; 130 uip->ui_proccnt = diff; 131 return (diff); 132 } 133 134 /* 135 * Is p an inferior of the current process? 136 */ 137 int 138 inferior(p) 139 register struct proc *p; 140 { 141 142 for (; p != curproc; p = p->p_pptr) 143 if (p->p_pid == 0) 144 return (0); 145 return (1); 146 } 147 148 /* 149 * Locate a process by number 150 */ 151 struct proc * 152 pfind(pid) 153 register pid_t pid; 154 { 155 register struct proc *p; 156 157 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next) 158 if (p->p_pid == pid) 159 return (p); 160 return (NULL); 161 } 162 163 /* 164 * Locate a process group by number 165 */ 166 struct pgrp * 167 pgfind(pgid) 168 register pid_t pgid; 169 { 170 register struct pgrp *pgrp; 171 172 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next) 173 if (pgrp->pg_id == pgid) 174 return (pgrp); 175 return (NULL); 176 } 177 178 /* 179 * Move p to a new or existing process group (and session) 180 */ 181 int 182 enterpgrp(p, pgid, mksess) 183 register struct proc *p; 184 pid_t pgid; 185 int mksess; 186 { 187 register struct pgrp *pgrp = pgfind(pgid); 188 189 #ifdef DIAGNOSTIC 190 if (pgrp != NULL && mksess) /* firewalls */ 191 panic("enterpgrp: setsid into non-empty pgrp"); 192 if (SESS_LEADER(p)) 193 panic("enterpgrp: session leader attempted setpgrp"); 194 #endif 195 if (pgrp == NULL) { 196 pid_t savepid = p->p_pid; 197 struct proc *np; 198 /* 199 * new process group 200 */ 201 #ifdef DIAGNOSTIC 202 if (p->p_pid != pgid) 203 panic("enterpgrp: new pgrp and pid != pgid"); 204 #endif 205 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, 206 M_WAITOK); 207 if ((np = pfind(savepid)) == NULL || np != p) 208 return (ESRCH); 209 if (mksess) { 210 register struct session *sess; 211 212 /* 213 * new session 214 */ 215 MALLOC(sess, struct session *, sizeof(struct session), 216 M_SESSION, M_WAITOK); 217 sess->s_leader = p; 218 sess->s_count = 1; 219 sess->s_ttyvp = NULL; 220 sess->s_ttyp = NULL; 221 bcopy(p->p_session->s_login, sess->s_login, 222 sizeof(sess->s_login)); 223 p->p_flag &= ~P_CONTROLT; 224 pgrp->pg_session = sess; 225 #ifdef DIAGNOSTIC 226 if (p != curproc) 227 panic("enterpgrp: mksession and p != curproc"); 228 #endif 229 } else { 230 pgrp->pg_session = p->p_session; 231 pgrp->pg_session->s_count++; 232 } 233 pgrp->pg_id = pgid; 234 LIST_INIT(&pgrp->pg_members); 235 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); 236 pgrp->pg_jobc = 0; 237 } else if (pgrp == p->p_pgrp) 238 return (0); 239 240 /* 241 * Adjust eligibility of affected pgrps to participate in job control. 242 * Increment eligibility counts before decrementing, otherwise we 243 * could reach 0 spuriously during the first call. 244 */ 245 fixjobc(p, pgrp, 1); 246 fixjobc(p, p->p_pgrp, 0); 247 248 LIST_REMOVE(p, p_pglist); 249 if (p->p_pgrp->pg_members.lh_first == 0) 250 pgdelete(p->p_pgrp); 251 p->p_pgrp = pgrp; 252 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); 253 return (0); 254 } 255 256 /* 257 * remove process from process group 258 */ 259 int 260 leavepgrp(p) 261 register struct proc *p; 262 { 263 264 LIST_REMOVE(p, p_pglist); 265 if (p->p_pgrp->pg_members.lh_first == 0) 266 pgdelete(p->p_pgrp); 267 p->p_pgrp = 0; 268 return (0); 269 } 270 271 /* 272 * delete a process group 273 */ 274 void 275 pgdelete(pgrp) 276 register struct pgrp *pgrp; 277 { 278 279 if (pgrp->pg_session->s_ttyp != NULL && 280 pgrp->pg_session->s_ttyp->t_pgrp == pgrp) 281 pgrp->pg_session->s_ttyp->t_pgrp = NULL; 282 LIST_REMOVE(pgrp, pg_hash); 283 if (--pgrp->pg_session->s_count == 0) 284 FREE(pgrp->pg_session, M_SESSION); 285 FREE(pgrp, M_PGRP); 286 } 287 288 /* 289 * Adjust pgrp jobc counters when specified process changes process group. 290 * We count the number of processes in each process group that "qualify" 291 * the group for terminal job control (those with a parent in a different 292 * process group of the same session). If that count reaches zero, the 293 * process group becomes orphaned. Check both the specified process' 294 * process group and that of its children. 295 * entering == 0 => p is leaving specified group. 296 * entering == 1 => p is entering specified group. 297 */ 298 void 299 fixjobc(p, pgrp, entering) 300 register struct proc *p; 301 register struct pgrp *pgrp; 302 int entering; 303 { 304 register struct pgrp *hispgrp; 305 register struct session *mysession = pgrp->pg_session; 306 307 /* 308 * Check p's parent to see whether p qualifies its own process 309 * group; if so, adjust count for p's process group. 310 */ 311 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && 312 hispgrp->pg_session == mysession) 313 if (entering) 314 pgrp->pg_jobc++; 315 else if (--pgrp->pg_jobc == 0) 316 orphanpg(pgrp); 317 318 /* 319 * Check this process' children to see whether they qualify 320 * their process groups; if so, adjust counts for children's 321 * process groups. 322 */ 323 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next) 324 if ((hispgrp = p->p_pgrp) != pgrp && 325 hispgrp->pg_session == mysession && 326 p->p_stat != SZOMB) 327 if (entering) 328 hispgrp->pg_jobc++; 329 else if (--hispgrp->pg_jobc == 0) 330 orphanpg(hispgrp); 331 } 332 333 /* 334 * A process group has become orphaned; 335 * if there are any stopped processes in the group, 336 * hang-up all process in that group. 337 */ 338 static void 339 orphanpg(pg) 340 struct pgrp *pg; 341 { 342 register struct proc *p; 343 344 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { 345 if (p->p_stat == SSTOP) { 346 for (p = pg->pg_members.lh_first; p != 0; 347 p = p->p_pglist.le_next) { 348 psignal(p, SIGHUP); 349 psignal(p, SIGCONT); 350 } 351 return; 352 } 353 } 354 } 355 356 #ifdef DEBUG 357 void 358 pgrpdump() 359 { 360 register struct pgrp *pgrp; 361 register struct proc *p; 362 register i; 363 364 for (i = 0; i <= pgrphash; i++) { 365 if ((pgrp = pgrphashtbl[i].lh_first) != NULL) { 366 printf("\tindx %d\n", i); 367 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) { 368 printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n", 369 pgrp, pgrp->pg_id, pgrp->pg_session, 370 pgrp->pg_session->s_count, 371 pgrp->pg_members.lh_first); 372 for (p = pgrp->pg_members.lh_first; p != 0; 373 p = p->p_pglist.le_next) { 374 printf("\t\tpid %d addr %p pgrp %p\n", 375 p->p_pid, p, p->p_pgrp); 376 } 377 } 378 } 379 } 380 } 381 #endif /* DEBUG */ 382