1 /* $NetBSD: kern_proc.c,v 1.12 1995/03/19 23:44:49 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 #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 /* 78 * Initialize global process hashing structures. 79 */ 80 void 81 procinit() 82 { 83 84 LIST_INIT(&allproc); 85 LIST_INIT(&zombproc); 86 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); 87 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash); 88 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash); 89 } 90 91 /* 92 * Change the count associated with number of processes 93 * a given user is using. 94 */ 95 int 96 chgproccnt(uid, diff) 97 uid_t uid; 98 int diff; 99 { 100 register struct uidinfo *uip; 101 register struct uihashhead *uipp; 102 103 uipp = UIHASH(uid); 104 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next) 105 if (uip->ui_uid == uid) 106 break; 107 if (uip) { 108 uip->ui_proccnt += diff; 109 if (uip->ui_proccnt > 0) 110 return (uip->ui_proccnt); 111 if (uip->ui_proccnt < 0) 112 panic("chgproccnt: procs < 0"); 113 LIST_REMOVE(uip, ui_hash); 114 FREE(uip, M_PROC); 115 return (0); 116 } 117 if (diff <= 0) { 118 if (diff == 0) 119 return(0); 120 panic("chgproccnt: lost user"); 121 } 122 MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); 123 LIST_INSERT_HEAD(uipp, uip, ui_hash); 124 uip->ui_uid = uid; 125 uip->ui_proccnt = diff; 126 return (diff); 127 } 128 129 /* 130 * Is p an inferior of the current process? 131 */ 132 int 133 inferior(p) 134 register struct proc *p; 135 { 136 137 for (; p != curproc; p = p->p_pptr) 138 if (p->p_pid == 0) 139 return (0); 140 return (1); 141 } 142 143 /* 144 * Locate a process by number 145 */ 146 struct proc * 147 pfind(pid) 148 register pid_t pid; 149 { 150 register struct proc *p; 151 152 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next) 153 if (p->p_pid == pid) 154 return (p); 155 return (NULL); 156 } 157 158 /* 159 * Locate a process group by number 160 */ 161 struct pgrp * 162 pgfind(pgid) 163 register pid_t pgid; 164 { 165 register struct pgrp *pgrp; 166 167 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next) 168 if (pgrp->pg_id == pgid) 169 return (pgrp); 170 return (NULL); 171 } 172 173 /* 174 * Move p to a new or existing process group (and session) 175 */ 176 int 177 enterpgrp(p, pgid, mksess) 178 register struct proc *p; 179 pid_t pgid; 180 int mksess; 181 { 182 register struct pgrp *pgrp = pgfind(pgid); 183 184 #ifdef DIAGNOSTIC 185 if (pgrp != NULL && mksess) /* firewalls */ 186 panic("enterpgrp: setsid into non-empty pgrp"); 187 if (SESS_LEADER(p)) 188 panic("enterpgrp: session leader attempted setpgrp"); 189 #endif 190 if (pgrp == NULL) { 191 pid_t savepid = p->p_pid; 192 struct proc *np; 193 /* 194 * new process group 195 */ 196 #ifdef DIAGNOSTIC 197 if (p->p_pid != pgid) 198 panic("enterpgrp: new pgrp and pid != pgid"); 199 #endif 200 MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, 201 M_WAITOK); 202 if ((np = pfind(savepid)) == NULL || np != p) 203 return (ESRCH); 204 if (mksess) { 205 register struct session *sess; 206 207 /* 208 * new session 209 */ 210 MALLOC(sess, struct session *, sizeof(struct session), 211 M_SESSION, M_WAITOK); 212 sess->s_leader = p; 213 sess->s_count = 1; 214 sess->s_ttyvp = NULL; 215 sess->s_ttyp = NULL; 216 bcopy(p->p_session->s_login, sess->s_login, 217 sizeof(sess->s_login)); 218 p->p_flag &= ~P_CONTROLT; 219 pgrp->pg_session = sess; 220 #ifdef DIAGNOSTIC 221 if (p != curproc) 222 panic("enterpgrp: mksession and p != curproc"); 223 #endif 224 } else { 225 pgrp->pg_session = p->p_session; 226 pgrp->pg_session->s_count++; 227 } 228 pgrp->pg_id = pgid; 229 LIST_INIT(&pgrp->pg_members); 230 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); 231 pgrp->pg_jobc = 0; 232 } else if (pgrp == p->p_pgrp) 233 return (0); 234 235 /* 236 * Adjust eligibility of affected pgrps to participate in job control. 237 * Increment eligibility counts before decrementing, otherwise we 238 * could reach 0 spuriously during the first call. 239 */ 240 fixjobc(p, pgrp, 1); 241 fixjobc(p, p->p_pgrp, 0); 242 243 LIST_REMOVE(p, p_pglist); 244 if (p->p_pgrp->pg_members.lh_first == 0) 245 pgdelete(p->p_pgrp); 246 p->p_pgrp = pgrp; 247 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); 248 return (0); 249 } 250 251 /* 252 * remove process from process group 253 */ 254 int 255 leavepgrp(p) 256 register struct proc *p; 257 { 258 259 LIST_REMOVE(p, p_pglist); 260 if (p->p_pgrp->pg_members.lh_first == 0) 261 pgdelete(p->p_pgrp); 262 p->p_pgrp = 0; 263 return (0); 264 } 265 266 /* 267 * delete a process group 268 */ 269 void 270 pgdelete(pgrp) 271 register struct pgrp *pgrp; 272 { 273 274 if (pgrp->pg_session->s_ttyp != NULL && 275 pgrp->pg_session->s_ttyp->t_pgrp == pgrp) 276 pgrp->pg_session->s_ttyp->t_pgrp = NULL; 277 LIST_REMOVE(pgrp, pg_hash); 278 if (--pgrp->pg_session->s_count == 0) 279 FREE(pgrp->pg_session, M_SESSION); 280 FREE(pgrp, M_PGRP); 281 } 282 283 static void orphanpg(); 284 285 /* 286 * Adjust pgrp jobc counters when specified process changes process group. 287 * We count the number of processes in each process group that "qualify" 288 * the group for terminal job control (those with a parent in a different 289 * process group of the same session). If that count reaches zero, the 290 * process group becomes orphaned. Check both the specified process' 291 * process group and that of its children. 292 * entering == 0 => p is leaving specified group. 293 * entering == 1 => p is entering specified group. 294 */ 295 void 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_children.lh_first; p != 0; p = p->p_sibling.le_next) 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_members.lh_first; p != 0; p = p->p_pglist.le_next) { 342 if (p->p_stat == SSTOP) { 343 for (p = pg->pg_members.lh_first; p != 0; 344 p = p->p_pglist.le_next) { 345 psignal(p, SIGHUP); 346 psignal(p, SIGCONT); 347 } 348 return; 349 } 350 } 351 } 352 353 #ifdef DEBUG 354 pgrpdump() 355 { 356 register struct pgrp *pgrp; 357 register struct proc *p; 358 register i; 359 360 for (i = 0; i <= pgrphash; i++) { 361 if (pgrp = pgrphashtbl[i].lh_first) { 362 printf("\tindx %d\n", i); 363 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) { 364 printf("\tpgrp %p, pgid %d, sess %p, sesscnt %d, mem %p\n", 365 pgrp, pgrp->pg_id, pgrp->pg_session, 366 pgrp->pg_session->s_count, 367 pgrp->pg_members.lh_first); 368 for (p = pgrp->pg_members.lh_first; p != 0; 369 p = p->p_pglist.le_next) { 370 printf("\t\tpid %d addr %p pgrp %p\n", 371 p->p_pid, p, p->p_pgrp); 372 } 373 } 374 } 375 } 376 } 377 #endif /* DEBUG */ 378