1*8827Sroot /* kern_proc.c 4.45 82/10/23 */ 236Sbill 336Sbill #include "../h/param.h" 436Sbill #include "../h/systm.h" 536Sbill #include "../h/map.h" 636Sbill #include "../h/dir.h" 736Sbill #include "../h/user.h" 88030Sroot #include "../h/kernel.h" 936Sbill #include "../h/proc.h" 1036Sbill #include "../h/buf.h" 1136Sbill #include "../h/reg.h" 1236Sbill #include "../h/inode.h" 1336Sbill #include "../h/seg.h" 1436Sbill #include "../h/acct.h" 15215Sbill #include "/usr/include/wait.h" 1636Sbill #include "../h/pte.h" 1736Sbill #include "../h/vm.h" 1836Sbill #include "../h/text.h" 19188Sbill #include "../h/psl.h" 20890Sbill #include "../h/file.h" 217488Skre #include "../h/quota.h" 227497Sroot #include "../h/descrip.h" 237713Sroot #include "../h/uio.h" 248030Sroot #include "../h/mbuf.h" 2536Sbill 268030Sroot gethostid() 278030Sroot { 288030Sroot 298099Sroot u.u_r.r_val1 = hostid; 308030Sroot } 318030Sroot 328030Sroot sethostid() 338030Sroot { 348099Sroot struct a { 358099Sroot int hostid; 368099Sroot } *uap = (struct a *)u.u_ap; 378030Sroot 388099Sroot if (suser()) 398099Sroot hostid = uap->hostid; 408030Sroot } 418030Sroot 428099Sroot gethostname() 438099Sroot { 448099Sroot register struct a { 458099Sroot char *hostname; 468099Sroot int len; 478099Sroot } *uap = (struct a *)u.u_ap; 488099Sroot register u_int len; 498099Sroot 508099Sroot len = uap->len; 518099Sroot if (len > hostnamelen) 528099Sroot len = hostnamelen; 538099Sroot if (copyout((caddr_t)hostname, (caddr_t)uap->hostname, len)) 548099Sroot u.u_error = EFAULT; 558099Sroot } 568099Sroot 578099Sroot sethostname() 588099Sroot { 598099Sroot register struct a { 608099Sroot char *hostname; 618099Sroot u_int len; 628099Sroot } *uap = (struct a *)u.u_ap; 638099Sroot 648099Sroot if (!suser()) 658099Sroot return; 668099Sroot if (uap->len > sizeof (hostname) - 1) { 678099Sroot u.u_error = EINVAL; 688099Sroot return; 698099Sroot } 708099Sroot hostnamelen = uap->len; 718099Sroot if (copyin((caddr_t)uap->hostname, hostname, uap->len)) 728099Sroot u.u_error = EFAULT; 738099Sroot hostname[hostnamelen] = 0; 748099Sroot } 758099Sroot 7636Sbill /* 7736Sbill * exec system call, with and without environments. 7836Sbill */ 7936Sbill struct execa { 8036Sbill char *fname; 8136Sbill char **argp; 8236Sbill char **envp; 8336Sbill }; 8436Sbill 858030Sroot execv() 8636Sbill { 8736Sbill ((struct execa *)u.u_ap)->envp = NULL; 888030Sroot execve(); 8936Sbill } 9036Sbill 918030Sroot execve() 9236Sbill { 9336Sbill register nc; 9436Sbill register char *cp; 9536Sbill register struct buf *bp; 9636Sbill register struct execa *uap; 9736Sbill int na, ne, ucp, ap, c; 982301Skre int indir, uid, gid; 992301Skre char *sharg; 10036Sbill struct inode *ip; 10136Sbill swblk_t bno; 1026568Smckusic char cfname[MAXNAMLEN + 1]; 1032301Skre char cfarg[SHSIZE]; 1047748Sroot int resid; 10536Sbill 1065991Swnj if ((ip = namei(uchar, 0, 1)) == NULL) 10736Sbill return; 10836Sbill bno = 0; 10936Sbill bp = 0; 1102301Skre indir = 0; 1112301Skre uid = u.u_uid; 1122301Skre gid = u.u_gid; 1132301Skre if (ip->i_mode & ISUID) 1142301Skre uid = ip->i_uid; 1152301Skre if (ip->i_mode & ISGID) 1162301Skre gid = ip->i_gid; 1172301Skre 1182301Skre again: 1194827Swnj if (access(ip, IEXEC)) 12036Sbill goto bad; 1214827Swnj if ((u.u_procp->p_flag&STRC) && access(ip, IREAD)) 1222330Swnj goto bad; 1234827Swnj if ((ip->i_mode & IFMT) != IFREG || 12436Sbill (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { 12536Sbill u.u_error = EACCES; 12636Sbill goto bad; 12736Sbill } 1282301Skre 12936Sbill /* 1302301Skre * Read in first few bytes of file for segment sizes, ux_mag: 1312301Skre * 407 = plain executable 1322301Skre * 410 = RO text 1332301Skre * 413 = demand paged RO text 1342301Skre * Also an ASCII line beginning with #! is 1352301Skre * the file name of a ``shell'' and arguments may be prepended 1362301Skre * to the argument list if given here. 1372301Skre * 1382301Skre * SHELL NAMES ARE LIMITED IN LENGTH. 1392301Skre * 1402301Skre * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM 1412301Skre * THE ASCII LINE. 1422301Skre */ 1437816Sroot u.u_error = rdwri(UIO_READ, ip, (caddr_t)&u.u_exdata, sizeof (u.u_exdata), 1447748Sroot 0, 1, &resid); 1454827Swnj if (u.u_error) 1462301Skre goto bad; 1477748Sroot u.u_count = resid; 1487816Sroot #ifndef lint 1494982Swnj if (u.u_count > sizeof(u.u_exdata) - sizeof(u.u_exdata.Ux_A) && 1504982Swnj u.u_exdata.ux_shell[0] != '#') { 1512301Skre u.u_error = ENOEXEC; 1522301Skre goto bad; 1532301Skre } 1547816Sroot #endif 1552301Skre switch (u.u_exdata.ux_mag) { 1562301Skre 1572301Skre case 0407: 1582301Skre u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; 1592301Skre u.u_exdata.ux_tsize = 0; 1602301Skre break; 1612301Skre 1622301Skre case 0413: 1632301Skre case 0410: 1642301Skre if (u.u_exdata.ux_tsize == 0) { 1652301Skre u.u_error = ENOEXEC; 1662301Skre goto bad; 1672301Skre } 1682301Skre break; 1692301Skre 1702301Skre default: 1712301Skre if (u.u_exdata.ux_shell[0] != '#' || 1722301Skre u.u_exdata.ux_shell[1] != '!' || 1732301Skre indir) { 1742301Skre u.u_error = ENOEXEC; 1752301Skre goto bad; 1762301Skre } 1772301Skre cp = &u.u_exdata.ux_shell[2]; /* skip "#!" */ 1782301Skre while (cp < &u.u_exdata.ux_shell[SHSIZE]) { 1792301Skre if (*cp == '\t') 1802301Skre *cp = ' '; 1812301Skre else if (*cp == '\n') { 1822301Skre *cp = '\0'; 1832301Skre break; 1842301Skre } 1852301Skre cp++; 1862301Skre } 1872301Skre if (*cp != '\0') { 1882301Skre u.u_error = ENOEXEC; 1892301Skre goto bad; 1902301Skre } 1912301Skre cp = &u.u_exdata.ux_shell[2]; 1922301Skre while (*cp == ' ') 1932301Skre cp++; 1942301Skre u.u_dirp = cp; 1952301Skre while (*cp && *cp != ' ') 1962301Skre cp++; 1972301Skre sharg = NULL; 1982301Skre if (*cp) { 1992301Skre *cp++ = '\0'; 2002301Skre while (*cp == ' ') 2012301Skre cp++; 2022301Skre if (*cp) { 2032301Skre bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); 2042301Skre sharg = cfarg; 2052301Skre } 2062301Skre } 2076568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)cfname, 2087816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 2092301Skre indir = 1; 2102301Skre iput(ip); 2115991Swnj ip = namei(schar, 0, 1); 2122301Skre if (ip == NULL) 2132301Skre return; 2142301Skre goto again; 2152301Skre } 2162301Skre 2172301Skre /* 21836Sbill * Collect arguments on "file" in swap space. 21936Sbill */ 22036Sbill na = 0; 22136Sbill ne = 0; 22236Sbill nc = 0; 22336Sbill uap = (struct execa *)u.u_ap; 2248665S if ((bno = rmalloc(argmap, (long)ctod(clrnd((int)btoc(NCARGS))))) == 0) { 22536Sbill swkill(u.u_procp, "exece"); 22636Sbill goto bad; 22736Sbill } 22836Sbill if (bno % CLSIZE) 2292780Swnj panic("execa rmalloc"); 23036Sbill if (uap->argp) for (;;) { 23136Sbill ap = NULL; 2323621Sroot if (indir && (na == 1 || na == 2 && sharg)) 2332301Skre ap = (int)uap->fname; 2342301Skre else if (uap->argp) { 23536Sbill ap = fuword((caddr_t)uap->argp); 23636Sbill uap->argp++; 23736Sbill } 23836Sbill if (ap==NULL && uap->envp) { 23936Sbill uap->argp = NULL; 24036Sbill if ((ap = fuword((caddr_t)uap->envp)) == NULL) 24136Sbill break; 24236Sbill uap->envp++; 24336Sbill ne++; 24436Sbill } 2456568Smckusic if (ap == NULL) 24636Sbill break; 24736Sbill na++; 2484827Swnj if (ap == -1) 24936Sbill u.u_error = EFAULT; 25036Sbill do { 25136Sbill if (nc >= NCARGS-1) 25236Sbill u.u_error = E2BIG; 2532301Skre if (indir && na == 2 && sharg != NULL) 2542301Skre c = *sharg++ & 0377; 2552301Skre else if ((c = fubyte((caddr_t)ap++)) < 0) 25636Sbill u.u_error = EFAULT; 25783Sbill if (u.u_error) { 25883Sbill if (bp) 25983Sbill brelse(bp); 26083Sbill bp = 0; 26136Sbill goto badarg; 26283Sbill } 2636568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 26436Sbill if (bp) 26536Sbill bdwrite(bp); 2666568Smckusic bp = getblk(argdev, bno + nc / NBPG, 2676568Smckusic CLSIZE*NBPG); 26836Sbill cp = bp->b_un.b_addr; 26936Sbill } 27036Sbill nc++; 27136Sbill *cp++ = c; 2726568Smckusic } while (c > 0); 27336Sbill } 27436Sbill if (bp) 27536Sbill bdwrite(bp); 27636Sbill bp = 0; 27736Sbill nc = (nc + NBPW-1) & ~(NBPW-1); 2786568Smckusic if (indir) { 2796568Smckusic u.u_dent.d_namlen = strlen(cfname); 2806568Smckusic bcopy((caddr_t)cfname, (caddr_t)u.u_dent.d_name, 2817816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 2826568Smckusic } 2832301Skre getxfile(ip, nc + (na+4)*NBPW, uid, gid); 284912Sbill if (u.u_error) { 28536Sbill badarg: 2866568Smckusic for (c = 0; c < nc; c += CLSIZE*NBPG) 2876568Smckusic if (bp = baddr(argdev, bno + c / NBPG, CLSIZE*NBPG)) { 28836Sbill bp->b_flags |= B_AGE; /* throw away */ 28936Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 29036Sbill brelse(bp); 29136Sbill bp = 0; 29236Sbill } 29336Sbill goto bad; 29436Sbill } 29536Sbill 29636Sbill /* 29736Sbill * copy back arglist 29836Sbill */ 29936Sbill ucp = USRSTACK - nc - NBPW; 30036Sbill ap = ucp - na*NBPW - 3*NBPW; 30136Sbill u.u_ar0[SP] = ap; 302132Sbill (void) suword((caddr_t)ap, na-ne); 30336Sbill nc = 0; 30436Sbill for (;;) { 30536Sbill ap += NBPW; 30636Sbill if (na==ne) { 307132Sbill (void) suword((caddr_t)ap, 0); 30836Sbill ap += NBPW; 30936Sbill } 31036Sbill if (--na < 0) 31136Sbill break; 312132Sbill (void) suword((caddr_t)ap, ucp); 31336Sbill do { 3146568Smckusic if (nc % (CLSIZE*NBPG) == 0) { 31536Sbill if (bp) 31636Sbill brelse(bp); 3176568Smckusic bp = bread(argdev, bno + nc / NBPG, 3186568Smckusic CLSIZE*NBPG); 31936Sbill bp->b_flags |= B_AGE; /* throw away */ 32036Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 32136Sbill cp = bp->b_un.b_addr; 32236Sbill } 323132Sbill (void) subyte((caddr_t)ucp++, (c = *cp++)); 32436Sbill nc++; 32536Sbill } while(c&0377); 32636Sbill } 327132Sbill (void) suword((caddr_t)ap, 0); 328132Sbill (void) suword((caddr_t)ucp, 0); 32936Sbill setregs(); 33036Sbill bad: 33136Sbill if (bp) 33236Sbill brelse(bp); 33336Sbill if (bno) 3348816Sroot rmfree(argmap, (long)ctod(clrnd((int) btoc(NCARGS))), bno); 33536Sbill iput(ip); 33636Sbill } 33736Sbill 33836Sbill /* 33936Sbill * Read in and set up memory for executed file. 34036Sbill */ 3412301Skre getxfile(ip, nargc, uid, gid) 34236Sbill register struct inode *ip; 34336Sbill { 34436Sbill register size_t ts, ds, ss; 3452301Skre int pagi; 34636Sbill 3472301Skre if (u.u_exdata.ux_mag == 0413) 34836Sbill pagi = SPAGI; 3492301Skre else 3502301Skre pagi = 0; 3514827Swnj if (u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && 3524827Swnj ip->i_count!=1) { 353890Sbill register struct file *fp; 354890Sbill 3554827Swnj for (fp = file; fp < fileNFILE; fp++) { 3567497Sroot if (fp->f_type == DTYPE_FILE && 3577497Sroot fp->f_inode == ip && (fp->f_flag&FWRITE)) { 358890Sbill u.u_error = ETXTBSY; 359890Sbill goto bad; 360890Sbill } 3614827Swnj } 36236Sbill } 36336Sbill 36436Sbill /* 3654827Swnj * Compute text and data sizes and make sure not too large. 36636Sbill */ 36736Sbill ts = clrnd(btoc(u.u_exdata.ux_tsize)); 36836Sbill ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize))); 36936Sbill ss = clrnd(SSIZE + btoc(nargc)); 370912Sbill if (chksize(ts, ds, ss)) 371912Sbill goto bad; 3724827Swnj 3734827Swnj /* 3744827Swnj * Make sure enough space to start process. 3754827Swnj */ 376912Sbill u.u_cdmap = zdmap; 377912Sbill u.u_csmap = zdmap; 378912Sbill if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 379912Sbill goto bad; 38036Sbill 381912Sbill /* 382912Sbill * At this point, committed to the new image! 383912Sbill * Release virtual memory resources of old process, and 384912Sbill * initialize the virtual memory of the new process. 385912Sbill * If we resulted from vfork(), instead wakeup our 386912Sbill * parent who will set SVFDONE when he has taken back 387912Sbill * our resources. 388912Sbill */ 389912Sbill if ((u.u_procp->p_flag & SVFORK) == 0) 390912Sbill vrelvm(); 391912Sbill else { 392912Sbill u.u_procp->p_flag &= ~SVFORK; 393912Sbill u.u_procp->p_flag |= SKEEP; 394912Sbill wakeup((caddr_t)u.u_procp); 395912Sbill while ((u.u_procp->p_flag & SVFDONE) == 0) 396912Sbill sleep((caddr_t)u.u_procp, PZERO - 1); 397912Sbill u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 398912Sbill } 3993592Swnj u.u_procp->p_flag &= ~(SPAGI|SSEQL|SUANOM|SNUSIG); 400912Sbill u.u_procp->p_flag |= pagi; 401912Sbill u.u_dmap = u.u_cdmap; 402912Sbill u.u_smap = u.u_csmap; 403912Sbill vgetvm(ts, ds, ss); 404912Sbill 4057748Sroot if (pagi == 0) 4067816Sroot u.u_error = 4077816Sroot rdwri(UIO_READ, ip, 4087816Sroot (char*)ctob(ts), (int)u.u_exdata.ux_dsize, 4097816Sroot (int)(sizeof(u.u_exdata)+u.u_exdata.ux_tsize), 4107816Sroot 0, (int *)0); 411912Sbill xalloc(ip, pagi); 412912Sbill if (pagi && u.u_procp->p_textp) 413912Sbill vinifod((struct fpte *)dptopte(u.u_procp, 0), 414912Sbill PG_FTEXT, u.u_procp->p_textp->x_iptr, 4158665S (long)(1 + ts/CLSIZE), (int)btoc(u.u_exdata.ux_dsize)); 41636Sbill 417912Sbill /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 4188443Sroot #include "../vax/mtpr.h" /* XXX */ 419912Sbill mtpr(TBIA, 0); 42036Sbill 4217530Sroot if (u.u_error) 4227530Sroot swkill(u.u_procp, "i/o error mapping pages"); 423912Sbill /* 424912Sbill * set SUID/SGID protections, if no tracing 425912Sbill */ 426912Sbill if ((u.u_procp->p_flag&STRC)==0) { 4274827Swnj u.u_uid = uid; 4284827Swnj u.u_procp->p_uid = uid; 4292301Skre u.u_gid = gid; 4308665S (void) entergroup(gid); 431912Sbill } else 432912Sbill psignal(u.u_procp, SIGTRAP); 43336Sbill u.u_tsize = ts; 43436Sbill u.u_dsize = ds; 43536Sbill u.u_ssize = ss; 43636Sbill bad: 437912Sbill return; 43836Sbill } 43936Sbill 44036Sbill /* 44136Sbill * Clear registers on exec 44236Sbill */ 44336Sbill setregs() 44436Sbill { 445173Sbill register int (**rp)(); 44636Sbill register i; 447188Sbill long sigmask; 44836Sbill 4496464Swnj for (rp = &u.u_signal[1], sigmask = 1L; rp < &u.u_signal[NSIG]; 450188Sbill sigmask <<= 1, rp++) { 451188Sbill switch (*rp) { 452188Sbill 453188Sbill case SIG_IGN: 454188Sbill case SIG_DFL: 455188Sbill case SIG_HOLD: 456188Sbill continue; 457188Sbill 458188Sbill default: 459188Sbill /* 460206Sbill * Normal or deferring catch; revert to default. 461188Sbill */ 462206Sbill (void) spl6(); 463206Sbill *rp = SIG_DFL; 464188Sbill if ((int)*rp & 1) 465188Sbill u.u_procp->p_siga0 |= sigmask; 466188Sbill else 4676327Swnj u.u_procp->p_siga0 &= ~sigmask; 468188Sbill if ((int)*rp & 2) 469188Sbill u.u_procp->p_siga1 |= sigmask; 470188Sbill else 471188Sbill u.u_procp->p_siga1 &= ~sigmask; 472206Sbill (void) spl0(); 473188Sbill continue; 474188Sbill } 475188Sbill } 47636Sbill /* 4774827Swnj for (rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 47836Sbill *rp++ = 0; 47936Sbill */ 48036Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 4814827Swnj for (i=0; i<NOFILE; i++) { 48236Sbill if (u.u_pofile[i]&EXCLOSE) { 4837697Ssam closef(u.u_ofile[i], 1, u.u_pofile[i]); 48436Sbill u.u_ofile[i] = NULL; 4857697Ssam u.u_pofile[i] = 0; 48636Sbill } 48736Sbill } 4884827Swnj 48936Sbill /* 49036Sbill * Remember file name for accounting. 49136Sbill */ 49236Sbill u.u_acflag &= ~AFORK; 4936568Smckusic bcopy((caddr_t)u.u_dent.d_name, (caddr_t)u.u_comm, 4947816Sroot (unsigned)(u.u_dent.d_namlen + 1)); 49536Sbill } 49636Sbill 49736Sbill /* 4984827Swnj * Exit system call: pass back caller's arg 49936Sbill */ 50036Sbill rexit() 50136Sbill { 50236Sbill register struct a { 50336Sbill int rval; 50436Sbill } *uap; 50536Sbill 50636Sbill uap = (struct a *)u.u_ap; 50736Sbill exit((uap->rval & 0377) << 8); 50836Sbill } 50936Sbill 51036Sbill /* 51136Sbill * Release resources. 51236Sbill * Save u. area for parent to look at. 51336Sbill * Enter zombie state. 51436Sbill * Wake up parent and init processes, 51536Sbill * and dispose of children. 51636Sbill */ 51736Sbill exit(rv) 51836Sbill { 51936Sbill register int i; 52036Sbill register struct proc *p, *q; 52136Sbill register int x; 522*8827Sroot struct mbuf *m = m_getclr(M_WAIT); 52336Sbill 52436Sbill #ifdef PGINPROF 52536Sbill vmsizmon(); 52636Sbill #endif 52736Sbill p = u.u_procp; 52836Sbill p->p_flag &= ~(STRC|SULOCK); 52936Sbill p->p_flag |= SWEXIT; 530188Sbill (void) spl6(); 531188Sbill if ((int)SIG_IGN & 1) 532188Sbill p->p_siga0 = ~0; 533188Sbill else 534188Sbill p->p_siga0 = 0; 535188Sbill if ((int)SIG_IGN & 2) 536188Sbill p->p_siga1 = ~0; 537188Sbill else 538206Sbill p->p_siga1 = 0; 539188Sbill (void) spl0(); 5401399Sbill p->p_cpticks = 0; 5411399Sbill p->p_pctcpu = 0; 5424827Swnj for (i=0; i<NSIG; i++) 543173Sbill u.u_signal[i] = SIG_IGN; 5448623Sroot untimeout(realitexpire, (caddr_t)p); 54536Sbill /* 54636Sbill * Release virtual memory. If we resulted from 54736Sbill * a vfork(), instead give the resources back to 54836Sbill * the parent. 54936Sbill */ 55036Sbill if ((p->p_flag & SVFORK) == 0) 55136Sbill vrelvm(); 55236Sbill else { 55336Sbill p->p_flag &= ~SVFORK; 55436Sbill wakeup((caddr_t)p); 55536Sbill while ((p->p_flag & SVFDONE) == 0) 55636Sbill sleep((caddr_t)p, PZERO - 1); 55736Sbill p->p_flag &= ~SVFDONE; 55836Sbill } 5597697Ssam for (i = 0; i < NOFILE; i++) { 5607697Ssam #ifdef notdef 5617697Ssam /* why was this like this? */ 56236Sbill f = u.u_ofile[i]; 56336Sbill u.u_ofile[i] = NULL; 5645581Swnj closef(f, 1); 5657697Ssam #else 5667697Ssam closef(u.u_ofile[i], 1, u.u_pofile[i]); 5677697Ssam u.u_ofile[i] = NULL; 5687697Ssam u.u_pofile[i] = 0; 5697697Ssam #endif 57036Sbill } 5714827Swnj ilock(u.u_cdir); 57236Sbill iput(u.u_cdir); 57336Sbill if (u.u_rdir) { 5744827Swnj ilock(u.u_rdir); 57536Sbill iput(u.u_rdir); 57636Sbill } 5778030Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 57836Sbill acct(); 5797488Skre #ifdef QUOTA 5807488Skre qclean(); 5817488Skre #endif 58236Sbill vrelpt(u.u_procp); 58336Sbill vrelu(u.u_procp, 0); 5845630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 58536Sbill multprog--; 586931Sbill p->p_stat = SZOMB; 587307Sbill noproc = 1; 58836Sbill i = PIDHASH(p->p_pid); 58936Sbill x = p - proc; 59036Sbill if (pidhash[i] == x) 59136Sbill pidhash[i] = p->p_idhash; 59236Sbill else { 59336Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 59436Sbill if (proc[i].p_idhash == x) { 59536Sbill proc[i].p_idhash = p->p_idhash; 59636Sbill goto done; 59736Sbill } 59836Sbill panic("exit"); 59936Sbill } 6001409Sbill if (p->p_pid == 1) 6011409Sbill panic("init died"); 60236Sbill done: 6038030Sroot p->p_xstat = rv; 604*8827Sroot p->p_ru = mtod(m, struct rusage *); 6058030Sroot *p->p_ru = u.u_ru; 6068030Sroot ruadd(p->p_ru, &u.u_cru); 6074827Swnj for (q = proc; q < procNPROC; q++) 6084827Swnj if (q->p_pptr == p) { 6097488Skre if (q->p_osptr) 6107488Skre q->p_osptr->p_ysptr = q->p_ysptr; 6117488Skre if (q->p_ysptr) 6127488Skre q->p_ysptr->p_osptr = q->p_osptr; 6137488Skre if (proc[1].p_cptr) 6147488Skre proc[1].p_cptr->p_ysptr = q; 6157488Skre q->p_osptr = proc[1].p_cptr; 6167488Skre q->p_ysptr = NULL; 6177488Skre proc[1].p_cptr = q; 6187488Skre 619188Sbill q->p_pptr = &proc[1]; 620188Sbill q->p_ppid = 1; 62136Sbill wakeup((caddr_t)&proc[1]); 622188Sbill /* 623212Sbill * Traced processes are killed 624188Sbill * since their existence means someone is screwing up. 625354Sbill * Stopped processes are sent a hangup and a continue. 626212Sbill * This is designed to be ``safe'' for setuid 627212Sbill * processes since they must be willing to tolerate 628212Sbill * hangups anyways. 629188Sbill */ 630212Sbill if (q->p_flag&STRC) { 631188Sbill q->p_flag &= ~STRC; 632188Sbill psignal(q, SIGKILL); 633212Sbill } else if (q->p_stat == SSTOP) { 634212Sbill psignal(q, SIGHUP); 635212Sbill psignal(q, SIGCONT); 636188Sbill } 637215Sbill /* 638215Sbill * Protect this process from future 6395619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 640215Sbill */ 6411788Sbill (void) spgrp(q, -1); 64236Sbill } 6436464Swnj psignal(p->p_pptr, SIGCHLD); 644188Sbill wakeup((caddr_t)p->p_pptr); 64536Sbill swtch(); 64636Sbill } 64736Sbill 6488151Sroot #include <vtimes.h> 6498151Sroot 6508099Sroot owait() 65136Sbill { 6528151Sroot struct rusage ru; 6538151Sroot struct vtimes *vtp, avt; 65436Sbill 655188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 6568030Sroot wait1(0, (struct rusage *)0); 657188Sbill return; 658188Sbill } 6598151Sroot vtp = (struct vtimes *)u.u_ar0[R1]; 6608030Sroot wait1(u.u_ar0[R0], &ru); 661188Sbill if (u.u_error) 662188Sbill return; 6638151Sroot getvtimes(&ru, &avt); 6648151Sroot (void) copyout((caddr_t)&avt, (caddr_t)vtp, sizeof (struct vtimes)); 66536Sbill } 66636Sbill 66736Sbill /* 66836Sbill * Wait system call. 66936Sbill * Search for a terminated (zombie) child, 67036Sbill * finally lay it to rest, and collect its status. 67136Sbill * Look also for stopped (traced) children, 67236Sbill * and pass back status from them. 67336Sbill */ 6748030Sroot wait1(options, ru) 6758030Sroot register int options; 6768030Sroot struct rusage *ru; 67736Sbill { 67836Sbill register f; 6797488Skre register struct proc *p, *q; 68036Sbill 68136Sbill f = 0; 68236Sbill loop: 6834827Swnj for (p = proc; p < procNPROC; p++) 6844827Swnj if (p->p_pptr == u.u_procp) { 68536Sbill f++; 6864827Swnj if (p->p_stat == SZOMB) { 68736Sbill u.u_r.r_val1 = p->p_pid; 6888030Sroot u.u_r.r_val2 = p->p_xstat; 6898030Sroot p->p_xstat = 0; 6908030Sroot if (ru) 6918030Sroot *ru = *p->p_ru; 6928030Sroot ruadd(&u.u_cru, p->p_ru); 6938665S (void) m_free(dtom(p->p_ru)); 6948030Sroot p->p_ru = 0; 69536Sbill p->p_stat = NULL; 69636Sbill p->p_pid = 0; 69736Sbill p->p_ppid = 0; 6987488Skre if (q = p->p_ysptr) 6997488Skre q->p_osptr = p->p_osptr; 7007488Skre if (q = p->p_osptr) 7017488Skre q->p_ysptr = p->p_ysptr; 7027488Skre if ((q = p->p_pptr)->p_cptr == p) 7037488Skre q->p_cptr = p->p_osptr; 704188Sbill p->p_pptr = 0; 7057488Skre p->p_ysptr = 0; 7067488Skre p->p_osptr = 0; 7077488Skre p->p_cptr = 0; 70836Sbill p->p_sig = 0; 709188Sbill p->p_siga0 = 0; 710188Sbill p->p_siga1 = 0; 71136Sbill p->p_pgrp = 0; 71236Sbill p->p_flag = 0; 71336Sbill p->p_wchan = 0; 714188Sbill p->p_cursig = 0; 71536Sbill return; 71636Sbill } 717188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 718188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 719188Sbill p->p_flag |= SWTED; 720188Sbill u.u_r.r_val1 = p->p_pid; 721188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 722188Sbill return; 72336Sbill } 72436Sbill } 725188Sbill if (f==0) { 726188Sbill u.u_error = ECHILD; 727188Sbill return; 72836Sbill } 729188Sbill if (options&WNOHANG) { 730188Sbill u.u_r.r_val1 = 0; 731188Sbill return; 732188Sbill } 7338116Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 734188Sbill u.u_eosys = RESTARTSYS; 735188Sbill return; 736188Sbill } 737188Sbill sleep((caddr_t)u.u_procp, PWAIT); 738188Sbill goto loop; 73936Sbill } 74036Sbill 74136Sbill /* 74236Sbill * fork system call. 74336Sbill */ 74436Sbill fork() 74536Sbill { 74636Sbill 74736Sbill u.u_cdmap = zdmap; 74836Sbill u.u_csmap = zdmap; 74936Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 75036Sbill u.u_r.r_val2 = 0; 75136Sbill return; 75236Sbill } 75336Sbill fork1(0); 75436Sbill } 75536Sbill 75636Sbill fork1(isvfork) 75736Sbill { 75836Sbill register struct proc *p1, *p2; 7597488Skre #ifndef QUOTA 76036Sbill register a; 76136Sbill 76236Sbill a = 0; 7637488Skre #else 7647488Skre if (u.u_quota != NOQUOT && u.u_quota->q_plim && 7657488Skre u.u_quota->q_cnt >= u.u_quota->q_plim) { 7667488Skre u.u_error = EPROCLIM; 7677488Skre return; 7687488Skre } 7697488Skre #endif 77036Sbill p2 = NULL; 7714827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 7727488Skre #ifdef QUOTA 7737488Skre if (p1->p_stat == NULL) { 7747488Skre p2 = p1; 7757488Skre break; 7767488Skre } 7777488Skre #else 77836Sbill if (p1->p_stat==NULL && p2==NULL) 77936Sbill p2 = p1; 78036Sbill else { 78136Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 78236Sbill a++; 78336Sbill } 7847488Skre #endif 78536Sbill } 78636Sbill /* 78736Sbill * Disallow if 78836Sbill * No processes at all; 78936Sbill * not su and too many procs owned; or 79036Sbill * not su and would take last slot. 79136Sbill */ 7922938Swnj if (p2==NULL) 7932938Swnj tablefull("proc"); 7947488Skre #ifdef QUOTA 7957488Skre if (p2==NULL || (u.u_uid!=0 && p2==procNPROC-1)) { 7967488Skre #else 7972741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 7987488Skre #endif 79936Sbill u.u_error = EAGAIN; 80036Sbill if (!isvfork) { 801132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 802132Sbill (void) vsexpand(0, &u.u_csmap, 1); 80336Sbill } 80436Sbill goto out; 80536Sbill } 80636Sbill p1 = u.u_procp; 8074827Swnj if (newproc(isvfork)) { 80836Sbill u.u_r.r_val1 = p1->p_pid; 80936Sbill u.u_r.r_val2 = 1; /* child */ 8108030Sroot u.u_start = time.tv_sec; 81136Sbill u.u_acflag = AFORK; 8127488Skre #ifdef QUOTA 8137488Skre u.u_qflags &= ~QUF_LOGIN; 8147488Skre #endif 81536Sbill return; 81636Sbill } 81736Sbill u.u_r.r_val1 = p2->p_pid; 81836Sbill 81936Sbill out: 82036Sbill u.u_r.r_val2 = 0; 82136Sbill } 82236Sbill 8237497Sroot spgrp(top, npgrp) 8247497Sroot register struct proc *top; 8257497Sroot { 8267497Sroot register struct proc *pp, *p; 8277497Sroot int f = 0; 8287497Sroot 8297497Sroot for (p = top; npgrp == -1 || u.u_uid == p->p_uid || 8307497Sroot !u.u_uid || inferior(p); p = pp) { 8317497Sroot if (npgrp == -1) { 8327497Sroot #define bit(a) (1<<(a-1)) 8337497Sroot p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU)); 8347497Sroot } else 8357497Sroot p->p_pgrp = npgrp; 8367497Sroot f++; 8377497Sroot /* 8387497Sroot * Search for children. 8397497Sroot */ 8407497Sroot for (pp = proc; pp < procNPROC; pp++) 8417497Sroot if (pp->p_pptr == p) 8427497Sroot goto cont; 8437497Sroot /* 8447497Sroot * Search for siblings. 8457497Sroot */ 8467497Sroot for (; p != top; p = p->p_pptr) 8477497Sroot for (pp = p + 1; pp < procNPROC; pp++) 8487497Sroot if (pp->p_pptr == p->p_pptr) 8497497Sroot goto cont; 8507497Sroot break; 8517497Sroot cont: 8527497Sroot ; 8537497Sroot } 8547497Sroot return (f); 8557497Sroot } 8567497Sroot 85736Sbill /* 8587497Sroot * Is p an inferior of the current process? 85936Sbill */ 8607497Sroot inferior(p) 8617816Sroot register struct proc *p; 86236Sbill { 86336Sbill 8647497Sroot for (; p != u.u_procp; p = p->p_pptr) 8657497Sroot if (p->p_ppid == 0) 8667497Sroot return (0); 8677497Sroot return (1); 86836Sbill } 8697816Sroot 8707816Sroot struct proc * 8717816Sroot pfind(pid) 8727816Sroot int pid; 8737816Sroot { 8747816Sroot register struct proc *p; 8757816Sroot 8767816Sroot for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash]) 8777816Sroot if (p->p_pid == pid) 8787816Sroot return (p); 8797816Sroot return ((struct proc *)0); 8807816Sroot } 8818099Sroot 8828099Sroot /* 8838099Sroot * Create a new process-- the internal version of 8848099Sroot * sys fork. 8858099Sroot * It returns 1 in the new process, 0 in the old. 8868099Sroot */ 8878099Sroot newproc(isvfork) 8888099Sroot int isvfork; 8898099Sroot { 8908099Sroot register struct proc *p; 8918099Sroot register struct proc *rpp, *rip; 8928099Sroot register int n; 8938099Sroot register struct file *fp; 8948099Sroot 8958099Sroot p = NULL; 8968099Sroot /* 8978099Sroot * First, just locate a slot for a process 8988099Sroot * and copy the useful info from this process into it. 8998099Sroot * The panic "cannot happen" because fork has already 9008099Sroot * checked for the existence of a slot. 9018099Sroot */ 9028099Sroot retry: 9038099Sroot mpid++; 9048099Sroot if (mpid >= 30000) { 9058099Sroot mpid = 0; 9068099Sroot goto retry; 9078099Sroot } 9088099Sroot for (rpp = proc; rpp < procNPROC; rpp++) { 9098099Sroot if (rpp->p_stat == NULL && p==NULL) 9108099Sroot p = rpp; 9118099Sroot if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 9128099Sroot goto retry; 9138099Sroot } 9148099Sroot if ((rpp = p) == NULL) 9158099Sroot panic("no procs"); 9168099Sroot 9178099Sroot /* 9188099Sroot * Make a proc table entry for the new process. 9198099Sroot */ 9208099Sroot rip = u.u_procp; 9218099Sroot #ifdef QUOTA 9228099Sroot (rpp->p_quota = rip->p_quota)->q_cnt++; 9238099Sroot #endif 9248099Sroot rpp->p_stat = SIDL; 9258099Sroot timerclear(&rpp->p_realtimer.it_value); 9268099Sroot rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 9278099Sroot if (isvfork) { 9288099Sroot rpp->p_flag |= SVFORK; 9298099Sroot rpp->p_ndx = rip->p_ndx; 9308099Sroot } else 9318099Sroot rpp->p_ndx = rpp - proc; 9328099Sroot rpp->p_uid = rip->p_uid; 9338099Sroot rpp->p_pgrp = rip->p_pgrp; 9348099Sroot rpp->p_nice = rip->p_nice; 9358099Sroot rpp->p_textp = isvfork ? 0 : rip->p_textp; 9368099Sroot rpp->p_pid = mpid; 9378099Sroot rpp->p_ppid = rip->p_pid; 9388099Sroot rpp->p_pptr = rip; 9398099Sroot rpp->p_osptr = rip->p_cptr; 9408099Sroot if (rip->p_cptr) 9418099Sroot rip->p_cptr->p_ysptr = rpp; 9428099Sroot rpp->p_ysptr = NULL; 9438099Sroot rpp->p_cptr = NULL; 9448099Sroot rip->p_cptr = rpp; 9458099Sroot rpp->p_time = 0; 9468099Sroot rpp->p_cpu = 0; 9478099Sroot rpp->p_siga0 = rip->p_siga0; 9488099Sroot rpp->p_siga1 = rip->p_siga1; 9498099Sroot /* take along any pending signals, like stops? */ 9508099Sroot if (isvfork) { 9518099Sroot rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 9528099Sroot rpp->p_szpt = clrnd(ctopt(UPAGES)); 9538099Sroot forkstat.cntvfork++; 9548099Sroot forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 9558099Sroot } else { 9568099Sroot rpp->p_tsize = rip->p_tsize; 9578099Sroot rpp->p_dsize = rip->p_dsize; 9588099Sroot rpp->p_ssize = rip->p_ssize; 9598099Sroot rpp->p_szpt = rip->p_szpt; 9608099Sroot forkstat.cntfork++; 9618099Sroot forkstat.sizfork += rip->p_dsize + rip->p_ssize; 9628099Sroot } 9638099Sroot rpp->p_rssize = 0; 9648099Sroot rpp->p_maxrss = rip->p_maxrss; 9658099Sroot rpp->p_wchan = 0; 9668099Sroot rpp->p_slptime = 0; 9678099Sroot rpp->p_pctcpu = 0; 9688099Sroot rpp->p_cpticks = 0; 9698099Sroot n = PIDHASH(rpp->p_pid); 9708099Sroot p->p_idhash = pidhash[n]; 9718099Sroot pidhash[n] = rpp - proc; 9728099Sroot multprog++; 9738099Sroot 9748099Sroot /* 9758099Sroot * Increase reference counts on shared objects. 9768099Sroot */ 9778099Sroot for (n = 0; n < NOFILE; n++) { 9788099Sroot fp = u.u_ofile[n]; 9798099Sroot if (fp == NULL) 9808099Sroot continue; 9818099Sroot fp->f_count++; 9828099Sroot if (u.u_pofile[n]&RDLOCK) 9838099Sroot fp->f_inode->i_rdlockc++; 9848099Sroot if (u.u_pofile[n]&WRLOCK) 9858099Sroot fp->f_inode->i_wrlockc++; 9868099Sroot } 9878099Sroot u.u_cdir->i_count++; 9888099Sroot if (u.u_rdir) 9898099Sroot u.u_rdir->i_count++; 9908099Sroot 9918099Sroot /* 9928099Sroot * Partially simulate the environment 9938099Sroot * of the new process so that when it is actually 9948099Sroot * created (by copying) it will look right. 9958099Sroot * This begins the section where we must prevent the parent 9968099Sroot * from being swapped. 9978099Sroot */ 9988099Sroot rip->p_flag |= SKEEP; 9998099Sroot if (procdup(rpp, isvfork)) 10008099Sroot return (1); 10018099Sroot 10028099Sroot /* 10038099Sroot * Make child runnable and add to run queue. 10048099Sroot */ 10058099Sroot (void) spl6(); 10068099Sroot rpp->p_stat = SRUN; 10078099Sroot setrq(rpp); 10088099Sroot (void) spl0(); 10098099Sroot 10108099Sroot /* 10118099Sroot * Cause child to take a non-local goto as soon as it runs. 10128099Sroot * On older systems this was done with SSWAP bit in proc 10138099Sroot * table; on VAX we use u.u_pcb.pcb_sswap so don't need 10148099Sroot * to do rpp->p_flag |= SSWAP. Actually do nothing here. 10158099Sroot */ 10168099Sroot /* rpp->p_flag |= SSWAP; */ 10178099Sroot 10188099Sroot /* 10198099Sroot * Now can be swapped. 10208099Sroot */ 10218099Sroot rip->p_flag &= ~SKEEP; 10228099Sroot 10238099Sroot /* 10248099Sroot * If vfork make chain from parent process to child 10258099Sroot * (where virtal memory is temporarily). Wait for 10268099Sroot * child to finish, steal virtual memory back, 10278099Sroot * and wakeup child to let it die. 10288099Sroot */ 10298099Sroot if (isvfork) { 10308099Sroot u.u_procp->p_xlink = rpp; 10318099Sroot u.u_procp->p_flag |= SNOVM; 10328099Sroot while (rpp->p_flag & SVFORK) 10338099Sroot sleep((caddr_t)rpp, PZERO - 1); 10348099Sroot if ((rpp->p_flag & SLOAD) == 0) 10358099Sroot panic("newproc vfork"); 10368099Sroot uaccess(rpp, Vfmap, &vfutl); 10378099Sroot u.u_procp->p_xlink = 0; 10388099Sroot vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 10398099Sroot u.u_procp->p_flag &= ~SNOVM; 10408099Sroot rpp->p_ndx = rpp - proc; 10418099Sroot rpp->p_flag |= SVFDONE; 10428099Sroot wakeup((caddr_t)rpp); 10438099Sroot } 10448099Sroot 10458099Sroot /* 10468099Sroot * 0 return means parent. 10478099Sroot */ 10488099Sroot return (0); 10498099Sroot } 1050