1 /* $NetBSD: kern_proc.c,v 1.23 1998/03/01 02:22:29 fvdl 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.7 (Berkeley) 2/14/95 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, M_WAITOK, &pidhash); 92 pgrphashtbl = hashinit(maxproc / 4, M_PROC, M_WAITOK, &pgrphash); 93 uihashtbl = hashinit(maxproc / 16, M_PROC, M_WAITOK, &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_sid = p->p_pid; 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 int 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