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