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