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