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.6 (Berkeley) 01/09/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 enterpgrp(p, pgid, mksess) 148 register struct proc *p; 149 pid_t pgid; 150 int mksess; 151 { 152 register struct pgrp *pgrp = pgfind(pgid); 153 int n; 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 leavepgrp(p) 226 register struct proc *p; 227 { 228 229 LIST_REMOVE(p, p_pglist); 230 if (p->p_pgrp->pg_members.lh_first == 0) 231 pgdelete(p->p_pgrp); 232 p->p_pgrp = 0; 233 return (0); 234 } 235 236 /* 237 * delete a process group 238 */ 239 void 240 pgdelete(pgrp) 241 register struct pgrp *pgrp; 242 { 243 244 if (pgrp->pg_session->s_ttyp != NULL && 245 pgrp->pg_session->s_ttyp->t_pgrp == pgrp) 246 pgrp->pg_session->s_ttyp->t_pgrp = NULL; 247 LIST_REMOVE(pgrp, pg_hash); 248 if (--pgrp->pg_session->s_count == 0) 249 FREE(pgrp->pg_session, M_SESSION); 250 FREE(pgrp, M_PGRP); 251 } 252 253 static void orphanpg(); 254 255 /* 256 * Adjust pgrp jobc counters when specified process changes process group. 257 * We count the number of processes in each process group that "qualify" 258 * the group for terminal job control (those with a parent in a different 259 * process group of the same session). If that count reaches zero, the 260 * process group becomes orphaned. Check both the specified process' 261 * process group and that of its children. 262 * entering == 0 => p is leaving specified group. 263 * entering == 1 => p is entering specified group. 264 */ 265 void 266 fixjobc(p, pgrp, entering) 267 register struct proc *p; 268 register struct pgrp *pgrp; 269 int entering; 270 { 271 register struct pgrp *hispgrp; 272 register struct session *mysession = pgrp->pg_session; 273 274 /* 275 * Check p's parent to see whether p qualifies its own process 276 * group; if so, adjust count for p's process group. 277 */ 278 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && 279 hispgrp->pg_session == mysession) 280 if (entering) 281 pgrp->pg_jobc++; 282 else if (--pgrp->pg_jobc == 0) 283 orphanpg(pgrp); 284 285 /* 286 * Check this process' children to see whether they qualify 287 * their process groups; if so, adjust counts for children's 288 * process groups. 289 */ 290 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next) 291 if ((hispgrp = p->p_pgrp) != pgrp && 292 hispgrp->pg_session == mysession && 293 p->p_stat != SZOMB) 294 if (entering) 295 hispgrp->pg_jobc++; 296 else if (--hispgrp->pg_jobc == 0) 297 orphanpg(hispgrp); 298 } 299 300 /* 301 * A process group has become orphaned; 302 * if there are any stopped processes in the group, 303 * hang-up all process in that group. 304 */ 305 static void 306 orphanpg(pg) 307 struct pgrp *pg; 308 { 309 register struct proc *p; 310 311 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { 312 if (p->p_stat == SSTOP) { 313 for (p = pg->pg_members.lh_first; p != 0; 314 p = p->p_pglist.le_next) { 315 psignal(p, SIGHUP); 316 psignal(p, SIGCONT); 317 } 318 return; 319 } 320 } 321 } 322 323 #ifdef DEBUG 324 pgrpdump() 325 { 326 register struct pgrp *pgrp; 327 register struct proc *p; 328 register i; 329 330 for (i = 0; i <= pgrphash; i++) { 331 if (pgrp = pgrphashtbl[i].lh_first) { 332 printf("\tindx %d\n", i); 333 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) { 334 printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n", 335 pgrp, pgrp->pg_id, pgrp->pg_session, 336 pgrp->pg_session->s_count, 337 pgrp->pg_members.lh_first); 338 for (p = pgrp->pg_members.lh_first; p != 0; 339 p = p->p_pglist.le_next) { 340 printf("\t\tpid %d addr %x pgrp %x\n", 341 p->p_pid, p, p->p_pgrp); 342 } 343 } 344 } 345 } 346 } 347 #endif /* DEBUG */ 348