123371Smckusick /* 263176Sbostic * Copyright (c) 1982, 1986, 1989, 1991, 1993 363176Sbostic * The Regents of the University of California. All rights reserved. 423371Smckusick * 544438Sbostic * %sccs.include.redist.c% 637728Smckusick * 7*68171Scgd * @(#)kern_proc.c 8.6 (Berkeley) 01/09/95 823371Smckusick */ 936Sbill 1051459Sbostic #include <sys/param.h> 1151459Sbostic #include <sys/systm.h> 1251459Sbostic #include <sys/map.h> 1351459Sbostic #include <sys/kernel.h> 1451459Sbostic #include <sys/proc.h> 1551459Sbostic #include <sys/buf.h> 1651459Sbostic #include <sys/acct.h> 1751459Sbostic #include <sys/wait.h> 1851459Sbostic #include <sys/file.h> 1951459Sbostic #include <ufs/ufs/quota.h> 2051459Sbostic #include <sys/uio.h> 2151459Sbostic #include <sys/malloc.h> 2251459Sbostic #include <sys/mbuf.h> 2351459Sbostic #include <sys/ioctl.h> 2451459Sbostic #include <sys/tty.h> 2536Sbill 2617540Skarels /* 2755402Smckusick * Structure associated with user cacheing. 2855402Smckusick */ 2955402Smckusick struct uidinfo { 3067732Smckusick LIST_ENTRY(uidinfo) ui_hash; 3155402Smckusick uid_t ui_uid; 3255402Smckusick long ui_proccnt; 3367732Smckusick }; 3467732Smckusick #define UIHASH(uid) (&uihashtbl[(uid) & uihash]) 3567732Smckusick LIST_HEAD(uihashhead, uidinfo) *uihashtbl; 3667732Smckusick u_long uihash; /* size of hash table - 1 */ 3755402Smckusick 3855402Smckusick /* 3967732Smckusick * Other process lists 4055402Smckusick */ 4167732Smckusick struct pidhashhead *pidhashtbl; 4267732Smckusick u_long pidhash; 4367732Smckusick struct pgrphashhead *pgrphashtbl; 4467732Smckusick u_long pgrphash; 4567732Smckusick struct proclist allproc; 4667732Smckusick struct proclist zombproc; 4767732Smckusick 4867732Smckusick /* 4967732Smckusick * Initialize global process hashing structures. 5067732Smckusick */ 51*68171Scgd void 5267732Smckusick procinit() 5355402Smckusick { 5455402Smckusick 5567732Smckusick LIST_INIT(&allproc); 5667732Smckusick LIST_INIT(&zombproc); 5767732Smckusick pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash); 5867732Smckusick pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash); 5955402Smckusick uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash); 6055402Smckusick } 6155402Smckusick 6255402Smckusick /* 6355402Smckusick * Change the count associated with number of processes 6455402Smckusick * a given user is using. 6555402Smckusick */ 6655402Smckusick int 6755402Smckusick chgproccnt(uid, diff) 6855402Smckusick uid_t uid; 6955402Smckusick int diff; 7055402Smckusick { 7167732Smckusick register struct uidinfo *uip; 7267732Smckusick register struct uihashhead *uipp; 7355402Smckusick 7467732Smckusick uipp = UIHASH(uid); 7567732Smckusick for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next) 7655402Smckusick if (uip->ui_uid == uid) 7755402Smckusick break; 7855402Smckusick if (uip) { 7955402Smckusick uip->ui_proccnt += diff; 8055402Smckusick if (uip->ui_proccnt > 0) 8155402Smckusick return (uip->ui_proccnt); 8255402Smckusick if (uip->ui_proccnt < 0) 8355402Smckusick panic("chgproccnt: procs < 0"); 8467732Smckusick LIST_REMOVE(uip, ui_hash); 8555402Smckusick FREE(uip, M_PROC); 8655402Smckusick return (0); 8755402Smckusick } 8855402Smckusick if (diff <= 0) { 8955402Smckusick if (diff == 0) 9055402Smckusick return(0); 9155402Smckusick panic("chgproccnt: lost user"); 9255402Smckusick } 9355402Smckusick MALLOC(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK); 9467732Smckusick LIST_INSERT_HEAD(uipp, uip, ui_hash); 9555402Smckusick uip->ui_uid = uid; 9655402Smckusick uip->ui_proccnt = diff; 9755402Smckusick return (diff); 9855402Smckusick } 9955402Smckusick 10055402Smckusick /* 1017497Sroot * Is p an inferior of the current process? 10236Sbill */ 1037497Sroot inferior(p) 1047816Sroot register struct proc *p; 10536Sbill { 10645673Skarels 10747542Skarels for (; p != curproc; p = p->p_pptr) 10847542Skarels if (p->p_pid == 0) 1097497Sroot return (0); 1107497Sroot return (1); 11136Sbill } 1127816Sroot 11340709Skarels /* 11440709Skarels * Locate a process by number 11540709Skarels */ 1167816Sroot struct proc * 1177816Sroot pfind(pid) 11864534Sbostic register pid_t pid; 1197816Sroot { 12064534Sbostic register struct proc *p; 1217816Sroot 12267732Smckusick for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next) 1237816Sroot if (p->p_pid == pid) 1247816Sroot return (p); 12564534Sbostic return (NULL); 1267816Sroot } 12716529Skarels 12816529Skarels /* 12935810Smarc * Locate a process group by number 13035810Smarc */ 13135810Smarc struct pgrp * 13235810Smarc pgfind(pgid) 13335810Smarc register pid_t pgid; 13435810Smarc { 13564534Sbostic register struct pgrp *pgrp; 13635810Smarc 13767732Smckusick for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; 13867732Smckusick pgrp = pgrp->pg_hash.le_next) 13935810Smarc if (pgrp->pg_id == pgid) 14040709Skarels return (pgrp); 14164534Sbostic return (NULL); 14235810Smarc } 14335810Smarc 14435810Smarc /* 14535810Smarc * Move p to a new or existing process group (and session) 14635810Smarc */ 14747542Skarels enterpgrp(p, pgid, mksess) 14835810Smarc register struct proc *p; 14935810Smarc pid_t pgid; 15052494Storek int mksess; 15135810Smarc { 15235810Smarc register struct pgrp *pgrp = pgfind(pgid); 15345673Skarels int n; 15435810Smarc 15539562Smarc #ifdef DIAGNOSTIC 15664534Sbostic if (pgrp != NULL && mksess) /* firewalls */ 15747542Skarels panic("enterpgrp: setsid into non-empty pgrp"); 15835810Smarc if (SESS_LEADER(p)) 15947542Skarels panic("enterpgrp: session leader attempted setpgrp"); 16039562Smarc #endif 16137589Smarc if (pgrp == NULL) { 16257055Smarc pid_t savepid = p->p_pid; 16357055Smarc struct proc *np; 16435810Smarc /* 16535810Smarc * new process group 16635810Smarc */ 16739562Smarc #ifdef DIAGNOSTIC 16835810Smarc if (p->p_pid != pgid) 16947542Skarels panic("enterpgrp: new pgrp and pid != pgid"); 17039562Smarc #endif 17135810Smarc MALLOC(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP, 17267732Smckusick M_WAITOK); 17357055Smarc if ((np = pfind(savepid)) == NULL || np != p) 17457055Smarc return (ESRCH); 17535810Smarc if (mksess) { 17635810Smarc register struct session *sess; 17750252Skarels 17835810Smarc /* 17935810Smarc * new session 18035810Smarc */ 18135810Smarc MALLOC(sess, struct session *, sizeof(struct session), 18267732Smckusick M_SESSION, M_WAITOK); 18335810Smarc sess->s_leader = p; 18435810Smarc sess->s_count = 1; 18539562Smarc sess->s_ttyvp = NULL; 18639562Smarc sess->s_ttyp = NULL; 18750252Skarels bcopy(p->p_session->s_login, sess->s_login, 18850252Skarels sizeof(sess->s_login)); 18964589Sbostic p->p_flag &= ~P_CONTROLT; 19035810Smarc pgrp->pg_session = sess; 19139562Smarc #ifdef DIAGNOSTIC 19247542Skarels if (p != curproc) 19347542Skarels panic("enterpgrp: mksession and p != curproc"); 19439562Smarc #endif 19535810Smarc } else { 19635810Smarc pgrp->pg_session = p->p_session; 19735810Smarc pgrp->pg_session->s_count++; 19835810Smarc } 19935810Smarc pgrp->pg_id = pgid; 20067732Smckusick LIST_INIT(&pgrp->pg_members); 20167732Smckusick LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash); 20235810Smarc pgrp->pg_jobc = 0; 20344387Smarc } else if (pgrp == p->p_pgrp) 20457055Smarc return (0); 20545673Skarels 20635810Smarc /* 20745673Skarels * Adjust eligibility of affected pgrps to participate in job control. 20845673Skarels * Increment eligibility counts before decrementing, otherwise we 20945673Skarels * could reach 0 spuriously during the first call. 21035810Smarc */ 21145673Skarels fixjobc(p, pgrp, 1); 21245673Skarels fixjobc(p, p->p_pgrp, 0); 21345673Skarels 21467732Smckusick LIST_REMOVE(p, p_pglist); 21567732Smckusick if (p->p_pgrp->pg_members.lh_first == 0) 21645673Skarels pgdelete(p->p_pgrp); 21745673Skarels p->p_pgrp = pgrp; 21867732Smckusick LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist); 21957055Smarc return (0); 22035810Smarc } 22135810Smarc 22235810Smarc /* 22335810Smarc * remove process from process group 22435810Smarc */ 22547542Skarels leavepgrp(p) 22635810Smarc register struct proc *p; 22735810Smarc { 22835810Smarc 22967732Smckusick LIST_REMOVE(p, p_pglist); 23067732Smckusick if (p->p_pgrp->pg_members.lh_first == 0) 23135810Smarc pgdelete(p->p_pgrp); 23235810Smarc p->p_pgrp = 0; 23357055Smarc return (0); 23435810Smarc } 23535810Smarc 23635810Smarc /* 23735810Smarc * delete a process group 23835810Smarc */ 239*68171Scgd void 24035810Smarc pgdelete(pgrp) 24135810Smarc register struct pgrp *pgrp; 24235810Smarc { 24335810Smarc 24439562Smarc if (pgrp->pg_session->s_ttyp != NULL && 24539562Smarc pgrp->pg_session->s_ttyp->t_pgrp == pgrp) 24639562Smarc pgrp->pg_session->s_ttyp->t_pgrp = NULL; 24767732Smckusick LIST_REMOVE(pgrp, pg_hash); 24835810Smarc if (--pgrp->pg_session->s_count == 0) 24935810Smarc FREE(pgrp->pg_session, M_SESSION); 25035810Smarc FREE(pgrp, M_PGRP); 25135810Smarc } 25235810Smarc 25352494Storek static void orphanpg(); 25448417Skarels 25535810Smarc /* 25645673Skarels * Adjust pgrp jobc counters when specified process changes process group. 25745673Skarels * We count the number of processes in each process group that "qualify" 25845673Skarels * the group for terminal job control (those with a parent in a different 25945673Skarels * process group of the same session). If that count reaches zero, the 26045673Skarels * process group becomes orphaned. Check both the specified process' 26145673Skarels * process group and that of its children. 26245673Skarels * entering == 0 => p is leaving specified group. 26345673Skarels * entering == 1 => p is entering specified group. 26444387Smarc */ 265*68171Scgd void 26645673Skarels fixjobc(p, pgrp, entering) 26744387Smarc register struct proc *p; 26845673Skarels register struct pgrp *pgrp; 26945673Skarels int entering; 27044387Smarc { 27145673Skarels register struct pgrp *hispgrp; 27245673Skarels register struct session *mysession = pgrp->pg_session; 27344387Smarc 27445673Skarels /* 27545673Skarels * Check p's parent to see whether p qualifies its own process 27645673Skarels * group; if so, adjust count for p's process group. 27745673Skarels */ 27845673Skarels if ((hispgrp = p->p_pptr->p_pgrp) != pgrp && 27944387Smarc hispgrp->pg_session == mysession) 28045673Skarels if (entering) 28145673Skarels pgrp->pg_jobc++; 28245673Skarels else if (--pgrp->pg_jobc == 0) 28345673Skarels orphanpg(pgrp); 28444387Smarc 28545673Skarels /* 28645673Skarels * Check this process' children to see whether they qualify 28745673Skarels * their process groups; if so, adjust counts for children's 28845673Skarels * process groups. 28945673Skarels */ 29067732Smckusick for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next) 29145673Skarels if ((hispgrp = p->p_pgrp) != pgrp && 29244387Smarc hispgrp->pg_session == mysession && 29344387Smarc p->p_stat != SZOMB) 29445673Skarels if (entering) 29544387Smarc hispgrp->pg_jobc++; 29645673Skarels else if (--hispgrp->pg_jobc == 0) 29745673Skarels orphanpg(hispgrp); 29845673Skarels } 29944387Smarc 30045673Skarels /* 30145673Skarels * A process group has become orphaned; 30245673Skarels * if there are any stopped processes in the group, 30345673Skarels * hang-up all process in that group. 30445673Skarels */ 30552494Storek static void 30645673Skarels orphanpg(pg) 30745673Skarels struct pgrp *pg; 30845673Skarels { 30945673Skarels register struct proc *p; 31045673Skarels 31167732Smckusick for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) { 31245673Skarels if (p->p_stat == SSTOP) { 31367732Smckusick for (p = pg->pg_members.lh_first; p != 0; 31467732Smckusick p = p->p_pglist.le_next) { 31545673Skarels psignal(p, SIGHUP); 31645673Skarels psignal(p, SIGCONT); 31744387Smarc } 31845673Skarels return; 31945673Skarels } 32045673Skarels } 32144387Smarc } 32245673Skarels 32367732Smckusick #ifdef DEBUG 32435810Smarc pgrpdump() 32535810Smarc { 32635810Smarc register struct pgrp *pgrp; 32735810Smarc register struct proc *p; 32835810Smarc register i; 32935810Smarc 33067732Smckusick for (i = 0; i <= pgrphash; i++) { 33167732Smckusick if (pgrp = pgrphashtbl[i].lh_first) { 33267732Smckusick printf("\tindx %d\n", i); 33367732Smckusick for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) { 33467732Smckusick printf("\tpgrp %x, pgid %d, sess %x, sesscnt %d, mem %x\n", 33567732Smckusick pgrp, pgrp->pg_id, pgrp->pg_session, 33667732Smckusick pgrp->pg_session->s_count, 33767732Smckusick pgrp->pg_members.lh_first); 33867732Smckusick for (p = pgrp->pg_members.lh_first; p != 0; 33967732Smckusick p = p->p_pglist.le_next) { 34067732Smckusick printf("\t\tpid %d addr %x pgrp %x\n", 34167732Smckusick p->p_pid, p, p->p_pgrp); 34267732Smckusick } 34367732Smckusick } 34435810Smarc } 34535810Smarc } 34635810Smarc } 34767732Smckusick #endif /* DEBUG */ 348