1*8443Sroot /* kern_proc.c 4.40 82/10/10 */ 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; 2242780Swnj if ((bno = rmalloc(argmap, 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) 3342780Swnj rmfree(argmap, 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, 415912Sbill 1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize)); 41636Sbill 417912Sbill /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 418*8443Sroot #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; 4307865Sroot 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; 52236Sbill 52336Sbill #ifdef PGINPROF 52436Sbill vmsizmon(); 52536Sbill #endif 52636Sbill p = u.u_procp; 52736Sbill p->p_flag &= ~(STRC|SULOCK); 52836Sbill p->p_flag |= SWEXIT; 529188Sbill (void) spl6(); 530188Sbill if ((int)SIG_IGN & 1) 531188Sbill p->p_siga0 = ~0; 532188Sbill else 533188Sbill p->p_siga0 = 0; 534188Sbill if ((int)SIG_IGN & 2) 535188Sbill p->p_siga1 = ~0; 536188Sbill else 537206Sbill p->p_siga1 = 0; 538188Sbill (void) spl0(); 5391399Sbill p->p_cpticks = 0; 5401399Sbill p->p_pctcpu = 0; 5414827Swnj for (i=0; i<NSIG; i++) 542173Sbill u.u_signal[i] = SIG_IGN; 5438151Sroot untimeout(realitexpire, p); 54436Sbill /* 54536Sbill * Release virtual memory. If we resulted from 54636Sbill * a vfork(), instead give the resources back to 54736Sbill * the parent. 54836Sbill */ 54936Sbill if ((p->p_flag & SVFORK) == 0) 55036Sbill vrelvm(); 55136Sbill else { 55236Sbill p->p_flag &= ~SVFORK; 55336Sbill wakeup((caddr_t)p); 55436Sbill while ((p->p_flag & SVFDONE) == 0) 55536Sbill sleep((caddr_t)p, PZERO - 1); 55636Sbill p->p_flag &= ~SVFDONE; 55736Sbill } 5587697Ssam for (i = 0; i < NOFILE; i++) { 5597697Ssam #ifdef notdef 5607697Ssam /* why was this like this? */ 56136Sbill f = u.u_ofile[i]; 56236Sbill u.u_ofile[i] = NULL; 5635581Swnj closef(f, 1); 5647697Ssam #else 5657697Ssam closef(u.u_ofile[i], 1, u.u_pofile[i]); 5667697Ssam u.u_ofile[i] = NULL; 5677697Ssam u.u_pofile[i] = 0; 5687697Ssam #endif 56936Sbill } 5704827Swnj ilock(u.u_cdir); 57136Sbill iput(u.u_cdir); 57236Sbill if (u.u_rdir) { 5734827Swnj ilock(u.u_rdir); 57436Sbill iput(u.u_rdir); 57536Sbill } 5768030Sroot u.u_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 57736Sbill acct(); 5787488Skre #ifdef QUOTA 5797488Skre qclean(); 5807488Skre #endif 58136Sbill vrelpt(u.u_procp); 58236Sbill vrelu(u.u_procp, 0); 5835630Swnj (void) spl5(); /* hack for mem alloc race XXX */ 58436Sbill multprog--; 585931Sbill p->p_stat = SZOMB; 586307Sbill noproc = 1; 58736Sbill i = PIDHASH(p->p_pid); 58836Sbill x = p - proc; 58936Sbill if (pidhash[i] == x) 59036Sbill pidhash[i] = p->p_idhash; 59136Sbill else { 59236Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 59336Sbill if (proc[i].p_idhash == x) { 59436Sbill proc[i].p_idhash = p->p_idhash; 59536Sbill goto done; 59636Sbill } 59736Sbill panic("exit"); 59836Sbill } 5991409Sbill if (p->p_pid == 1) 6001409Sbill panic("init died"); 60136Sbill done: 6028030Sroot p->p_xstat = rv; 6038030Sroot { struct mbuf *m = m_getclr(M_DONTWAIT); p->p_ru = mtod(m, struct rusage *); } 6048030Sroot *p->p_ru = u.u_ru; 6058030Sroot ruadd(p->p_ru, &u.u_cru); 6064827Swnj for (q = proc; q < procNPROC; q++) 6074827Swnj if (q->p_pptr == p) { 6087488Skre if (q->p_osptr) 6097488Skre q->p_osptr->p_ysptr = q->p_ysptr; 6107488Skre if (q->p_ysptr) 6117488Skre q->p_ysptr->p_osptr = q->p_osptr; 6127488Skre if (proc[1].p_cptr) 6137488Skre proc[1].p_cptr->p_ysptr = q; 6147488Skre q->p_osptr = proc[1].p_cptr; 6157488Skre q->p_ysptr = NULL; 6167488Skre proc[1].p_cptr = q; 6177488Skre 618188Sbill q->p_pptr = &proc[1]; 619188Sbill q->p_ppid = 1; 62036Sbill wakeup((caddr_t)&proc[1]); 621188Sbill /* 622212Sbill * Traced processes are killed 623188Sbill * since their existence means someone is screwing up. 624354Sbill * Stopped processes are sent a hangup and a continue. 625212Sbill * This is designed to be ``safe'' for setuid 626212Sbill * processes since they must be willing to tolerate 627212Sbill * hangups anyways. 628188Sbill */ 629212Sbill if (q->p_flag&STRC) { 630188Sbill q->p_flag &= ~STRC; 631188Sbill psignal(q, SIGKILL); 632212Sbill } else if (q->p_stat == SSTOP) { 633212Sbill psignal(q, SIGHUP); 634212Sbill psignal(q, SIGCONT); 635188Sbill } 636215Sbill /* 637215Sbill * Protect this process from future 6385619Swnj * tty signals, clear TSTP/TTIN/TTOU if pending. 639215Sbill */ 6401788Sbill (void) spgrp(q, -1); 64136Sbill } 6426464Swnj psignal(p->p_pptr, SIGCHLD); 643188Sbill wakeup((caddr_t)p->p_pptr); 64436Sbill swtch(); 64536Sbill } 64636Sbill 6478151Sroot #include <vtimes.h> 6488151Sroot 6498099Sroot owait() 65036Sbill { 6518151Sroot struct rusage ru; 6528151Sroot struct vtimes *vtp, avt; 65336Sbill 654188Sbill if ((u.u_ar0[PS] & PSL_ALLCC) != PSL_ALLCC) { 6558030Sroot wait1(0, (struct rusage *)0); 656188Sbill return; 657188Sbill } 6588151Sroot vtp = (struct vtimes *)u.u_ar0[R1]; 6598030Sroot wait1(u.u_ar0[R0], &ru); 660188Sbill if (u.u_error) 661188Sbill return; 6628151Sroot getvtimes(&ru, &avt); 6638151Sroot (void) copyout((caddr_t)&avt, (caddr_t)vtp, sizeof (struct vtimes)); 66436Sbill } 66536Sbill 66636Sbill /* 66736Sbill * Wait system call. 66836Sbill * Search for a terminated (zombie) child, 66936Sbill * finally lay it to rest, and collect its status. 67036Sbill * Look also for stopped (traced) children, 67136Sbill * and pass back status from them. 67236Sbill */ 6738030Sroot wait1(options, ru) 6748030Sroot register int options; 6758030Sroot struct rusage *ru; 67636Sbill { 67736Sbill register f; 6787488Skre register struct proc *p, *q; 67936Sbill 68036Sbill f = 0; 68136Sbill loop: 6824827Swnj for (p = proc; p < procNPROC; p++) 6834827Swnj if (p->p_pptr == u.u_procp) { 68436Sbill f++; 6854827Swnj if (p->p_stat == SZOMB) { 68636Sbill u.u_r.r_val1 = p->p_pid; 6878030Sroot u.u_r.r_val2 = p->p_xstat; 6888030Sroot p->p_xstat = 0; 6898030Sroot if (ru) 6908030Sroot *ru = *p->p_ru; 6918030Sroot ruadd(&u.u_cru, p->p_ru); 6928030Sroot m_free(dtom(p->p_ru)); 6938030Sroot p->p_ru = 0; 69436Sbill p->p_stat = NULL; 69536Sbill p->p_pid = 0; 69636Sbill p->p_ppid = 0; 6977488Skre if (q = p->p_ysptr) 6987488Skre q->p_osptr = p->p_osptr; 6997488Skre if (q = p->p_osptr) 7007488Skre q->p_ysptr = p->p_ysptr; 7017488Skre if ((q = p->p_pptr)->p_cptr == p) 7027488Skre q->p_cptr = p->p_osptr; 703188Sbill p->p_pptr = 0; 7047488Skre p->p_ysptr = 0; 7057488Skre p->p_osptr = 0; 7067488Skre p->p_cptr = 0; 70736Sbill p->p_sig = 0; 708188Sbill p->p_siga0 = 0; 709188Sbill p->p_siga1 = 0; 71036Sbill p->p_pgrp = 0; 71136Sbill p->p_flag = 0; 71236Sbill p->p_wchan = 0; 713188Sbill p->p_cursig = 0; 71436Sbill return; 71536Sbill } 716188Sbill if (p->p_stat == SSTOP && (p->p_flag&SWTED)==0 && 717188Sbill (p->p_flag&STRC || options&WUNTRACED)) { 718188Sbill p->p_flag |= SWTED; 719188Sbill u.u_r.r_val1 = p->p_pid; 720188Sbill u.u_r.r_val2 = (p->p_cursig<<8) | WSTOPPED; 721188Sbill return; 72236Sbill } 72336Sbill } 724188Sbill if (f==0) { 725188Sbill u.u_error = ECHILD; 726188Sbill return; 72736Sbill } 728188Sbill if (options&WNOHANG) { 729188Sbill u.u_r.r_val1 = 0; 730188Sbill return; 731188Sbill } 7328116Sroot if ((u.u_procp->p_flag&SNUSIG) && setjmp(&u.u_qsave)) { 733188Sbill u.u_eosys = RESTARTSYS; 734188Sbill return; 735188Sbill } 736188Sbill sleep((caddr_t)u.u_procp, PWAIT); 737188Sbill goto loop; 73836Sbill } 73936Sbill 74036Sbill /* 74136Sbill * fork system call. 74236Sbill */ 74336Sbill fork() 74436Sbill { 74536Sbill 74636Sbill u.u_cdmap = zdmap; 74736Sbill u.u_csmap = zdmap; 74836Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 74936Sbill u.u_r.r_val2 = 0; 75036Sbill return; 75136Sbill } 75236Sbill fork1(0); 75336Sbill } 75436Sbill 75536Sbill fork1(isvfork) 75636Sbill { 75736Sbill register struct proc *p1, *p2; 7587488Skre #ifndef QUOTA 75936Sbill register a; 76036Sbill 76136Sbill a = 0; 7627488Skre #else 7637488Skre if (u.u_quota != NOQUOT && u.u_quota->q_plim && 7647488Skre u.u_quota->q_cnt >= u.u_quota->q_plim) { 7657488Skre u.u_error = EPROCLIM; 7667488Skre return; 7677488Skre } 7687488Skre #endif 76936Sbill p2 = NULL; 7704827Swnj for (p1 = proc; p1 < procNPROC; p1++) { 7717488Skre #ifdef QUOTA 7727488Skre if (p1->p_stat == NULL) { 7737488Skre p2 = p1; 7747488Skre break; 7757488Skre } 7767488Skre #else 77736Sbill if (p1->p_stat==NULL && p2==NULL) 77836Sbill p2 = p1; 77936Sbill else { 78036Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 78136Sbill a++; 78236Sbill } 7837488Skre #endif 78436Sbill } 78536Sbill /* 78636Sbill * Disallow if 78736Sbill * No processes at all; 78836Sbill * not su and too many procs owned; or 78936Sbill * not su and would take last slot. 79036Sbill */ 7912938Swnj if (p2==NULL) 7922938Swnj tablefull("proc"); 7937488Skre #ifdef QUOTA 7947488Skre if (p2==NULL || (u.u_uid!=0 && p2==procNPROC-1)) { 7957488Skre #else 7962741Swnj if (p2==NULL || (u.u_uid!=0 && (p2==procNPROC-1 || a>MAXUPRC))) { 7977488Skre #endif 79836Sbill u.u_error = EAGAIN; 79936Sbill if (!isvfork) { 800132Sbill (void) vsexpand(0, &u.u_cdmap, 1); 801132Sbill (void) vsexpand(0, &u.u_csmap, 1); 80236Sbill } 80336Sbill goto out; 80436Sbill } 80536Sbill p1 = u.u_procp; 8064827Swnj if (newproc(isvfork)) { 80736Sbill u.u_r.r_val1 = p1->p_pid; 80836Sbill u.u_r.r_val2 = 1; /* child */ 8098030Sroot u.u_start = time.tv_sec; 81036Sbill u.u_acflag = AFORK; 8117488Skre #ifdef QUOTA 8127488Skre u.u_qflags &= ~QUF_LOGIN; 8137488Skre #endif 81436Sbill return; 81536Sbill } 81636Sbill u.u_r.r_val1 = p2->p_pid; 81736Sbill 81836Sbill out: 81936Sbill u.u_r.r_val2 = 0; 82036Sbill } 82136Sbill 8227497Sroot spgrp(top, npgrp) 8237497Sroot register struct proc *top; 8247497Sroot { 8257497Sroot register struct proc *pp, *p; 8267497Sroot int f = 0; 8277497Sroot 8287497Sroot for (p = top; npgrp == -1 || u.u_uid == p->p_uid || 8297497Sroot !u.u_uid || inferior(p); p = pp) { 8307497Sroot if (npgrp == -1) { 8317497Sroot #define bit(a) (1<<(a-1)) 8327497Sroot p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU)); 8337497Sroot } else 8347497Sroot p->p_pgrp = npgrp; 8357497Sroot f++; 8367497Sroot /* 8377497Sroot * Search for children. 8387497Sroot */ 8397497Sroot for (pp = proc; pp < procNPROC; pp++) 8407497Sroot if (pp->p_pptr == p) 8417497Sroot goto cont; 8427497Sroot /* 8437497Sroot * Search for siblings. 8447497Sroot */ 8457497Sroot for (; p != top; p = p->p_pptr) 8467497Sroot for (pp = p + 1; pp < procNPROC; pp++) 8477497Sroot if (pp->p_pptr == p->p_pptr) 8487497Sroot goto cont; 8497497Sroot break; 8507497Sroot cont: 8517497Sroot ; 8527497Sroot } 8537497Sroot return (f); 8547497Sroot } 8557497Sroot 85636Sbill /* 8577497Sroot * Is p an inferior of the current process? 85836Sbill */ 8597497Sroot inferior(p) 8607816Sroot register struct proc *p; 86136Sbill { 86236Sbill 8637497Sroot for (; p != u.u_procp; p = p->p_pptr) 8647497Sroot if (p->p_ppid == 0) 8657497Sroot return (0); 8667497Sroot return (1); 86736Sbill } 8687816Sroot 8697816Sroot struct proc * 8707816Sroot pfind(pid) 8717816Sroot int pid; 8727816Sroot { 8737816Sroot register struct proc *p; 8747816Sroot 8757816Sroot for (p = &proc[pidhash[PIDHASH(pid)]]; p != &proc[0]; p = &proc[p->p_idhash]) 8767816Sroot if (p->p_pid == pid) 8777816Sroot return (p); 8787816Sroot return ((struct proc *)0); 8797816Sroot } 8808099Sroot 8818099Sroot /* 8828099Sroot * Create a new process-- the internal version of 8838099Sroot * sys fork. 8848099Sroot * It returns 1 in the new process, 0 in the old. 8858099Sroot */ 8868099Sroot newproc(isvfork) 8878099Sroot int isvfork; 8888099Sroot { 8898099Sroot register struct proc *p; 8908099Sroot register struct proc *rpp, *rip; 8918099Sroot register int n; 8928099Sroot register struct file *fp; 8938099Sroot 8948099Sroot p = NULL; 8958099Sroot /* 8968099Sroot * First, just locate a slot for a process 8978099Sroot * and copy the useful info from this process into it. 8988099Sroot * The panic "cannot happen" because fork has already 8998099Sroot * checked for the existence of a slot. 9008099Sroot */ 9018099Sroot retry: 9028099Sroot mpid++; 9038099Sroot if (mpid >= 30000) { 9048099Sroot mpid = 0; 9058099Sroot goto retry; 9068099Sroot } 9078099Sroot for (rpp = proc; rpp < procNPROC; rpp++) { 9088099Sroot if (rpp->p_stat == NULL && p==NULL) 9098099Sroot p = rpp; 9108099Sroot if (rpp->p_pid==mpid || rpp->p_pgrp==mpid) 9118099Sroot goto retry; 9128099Sroot } 9138099Sroot if ((rpp = p) == NULL) 9148099Sroot panic("no procs"); 9158099Sroot 9168099Sroot /* 9178099Sroot * Make a proc table entry for the new process. 9188099Sroot */ 9198099Sroot rip = u.u_procp; 9208099Sroot #ifdef QUOTA 9218099Sroot (rpp->p_quota = rip->p_quota)->q_cnt++; 9228099Sroot #endif 9238099Sroot rpp->p_stat = SIDL; 9248099Sroot timerclear(&rpp->p_realtimer.it_value); 9258099Sroot rpp->p_flag = SLOAD | (rip->p_flag & (SPAGI|SNUSIG)); 9268099Sroot if (isvfork) { 9278099Sroot rpp->p_flag |= SVFORK; 9288099Sroot rpp->p_ndx = rip->p_ndx; 9298099Sroot } else 9308099Sroot rpp->p_ndx = rpp - proc; 9318099Sroot rpp->p_uid = rip->p_uid; 9328099Sroot rpp->p_pgrp = rip->p_pgrp; 9338099Sroot rpp->p_nice = rip->p_nice; 9348099Sroot rpp->p_textp = isvfork ? 0 : rip->p_textp; 9358099Sroot rpp->p_pid = mpid; 9368099Sroot rpp->p_ppid = rip->p_pid; 9378099Sroot rpp->p_pptr = rip; 9388099Sroot rpp->p_osptr = rip->p_cptr; 9398099Sroot if (rip->p_cptr) 9408099Sroot rip->p_cptr->p_ysptr = rpp; 9418099Sroot rpp->p_ysptr = NULL; 9428099Sroot rpp->p_cptr = NULL; 9438099Sroot rip->p_cptr = rpp; 9448099Sroot rpp->p_time = 0; 9458099Sroot rpp->p_cpu = 0; 9468099Sroot rpp->p_siga0 = rip->p_siga0; 9478099Sroot rpp->p_siga1 = rip->p_siga1; 9488099Sroot /* take along any pending signals, like stops? */ 9498099Sroot if (isvfork) { 9508099Sroot rpp->p_tsize = rpp->p_dsize = rpp->p_ssize = 0; 9518099Sroot rpp->p_szpt = clrnd(ctopt(UPAGES)); 9528099Sroot forkstat.cntvfork++; 9538099Sroot forkstat.sizvfork += rip->p_dsize + rip->p_ssize; 9548099Sroot } else { 9558099Sroot rpp->p_tsize = rip->p_tsize; 9568099Sroot rpp->p_dsize = rip->p_dsize; 9578099Sroot rpp->p_ssize = rip->p_ssize; 9588099Sroot rpp->p_szpt = rip->p_szpt; 9598099Sroot forkstat.cntfork++; 9608099Sroot forkstat.sizfork += rip->p_dsize + rip->p_ssize; 9618099Sroot } 9628099Sroot rpp->p_rssize = 0; 9638099Sroot rpp->p_maxrss = rip->p_maxrss; 9648099Sroot rpp->p_wchan = 0; 9658099Sroot rpp->p_slptime = 0; 9668099Sroot rpp->p_pctcpu = 0; 9678099Sroot rpp->p_cpticks = 0; 9688099Sroot n = PIDHASH(rpp->p_pid); 9698099Sroot p->p_idhash = pidhash[n]; 9708099Sroot pidhash[n] = rpp - proc; 9718099Sroot multprog++; 9728099Sroot 9738099Sroot /* 9748099Sroot * Increase reference counts on shared objects. 9758099Sroot */ 9768099Sroot for (n = 0; n < NOFILE; n++) { 9778099Sroot fp = u.u_ofile[n]; 9788099Sroot if (fp == NULL) 9798099Sroot continue; 9808099Sroot fp->f_count++; 9818099Sroot if (u.u_pofile[n]&RDLOCK) 9828099Sroot fp->f_inode->i_rdlockc++; 9838099Sroot if (u.u_pofile[n]&WRLOCK) 9848099Sroot fp->f_inode->i_wrlockc++; 9858099Sroot } 9868099Sroot u.u_cdir->i_count++; 9878099Sroot if (u.u_rdir) 9888099Sroot u.u_rdir->i_count++; 9898099Sroot 9908099Sroot /* 9918099Sroot * Partially simulate the environment 9928099Sroot * of the new process so that when it is actually 9938099Sroot * created (by copying) it will look right. 9948099Sroot * This begins the section where we must prevent the parent 9958099Sroot * from being swapped. 9968099Sroot */ 9978099Sroot rip->p_flag |= SKEEP; 9988099Sroot if (procdup(rpp, isvfork)) 9998099Sroot return (1); 10008099Sroot 10018099Sroot /* 10028099Sroot * Make child runnable and add to run queue. 10038099Sroot */ 10048099Sroot (void) spl6(); 10058099Sroot rpp->p_stat = SRUN; 10068099Sroot setrq(rpp); 10078099Sroot (void) spl0(); 10088099Sroot 10098099Sroot /* 10108099Sroot * Cause child to take a non-local goto as soon as it runs. 10118099Sroot * On older systems this was done with SSWAP bit in proc 10128099Sroot * table; on VAX we use u.u_pcb.pcb_sswap so don't need 10138099Sroot * to do rpp->p_flag |= SSWAP. Actually do nothing here. 10148099Sroot */ 10158099Sroot /* rpp->p_flag |= SSWAP; */ 10168099Sroot 10178099Sroot /* 10188099Sroot * Now can be swapped. 10198099Sroot */ 10208099Sroot rip->p_flag &= ~SKEEP; 10218099Sroot 10228099Sroot /* 10238099Sroot * If vfork make chain from parent process to child 10248099Sroot * (where virtal memory is temporarily). Wait for 10258099Sroot * child to finish, steal virtual memory back, 10268099Sroot * and wakeup child to let it die. 10278099Sroot */ 10288099Sroot if (isvfork) { 10298099Sroot u.u_procp->p_xlink = rpp; 10308099Sroot u.u_procp->p_flag |= SNOVM; 10318099Sroot while (rpp->p_flag & SVFORK) 10328099Sroot sleep((caddr_t)rpp, PZERO - 1); 10338099Sroot if ((rpp->p_flag & SLOAD) == 0) 10348099Sroot panic("newproc vfork"); 10358099Sroot uaccess(rpp, Vfmap, &vfutl); 10368099Sroot u.u_procp->p_xlink = 0; 10378099Sroot vpassvm(rpp, u.u_procp, &vfutl, &u, Vfmap); 10388099Sroot u.u_procp->p_flag &= ~SNOVM; 10398099Sroot rpp->p_ndx = rpp - proc; 10408099Sroot rpp->p_flag |= SVFDONE; 10418099Sroot wakeup((caddr_t)rpp); 10428099Sroot } 10438099Sroot 10448099Sroot /* 10458099Sroot * 0 return means parent. 10468099Sroot */ 10478099Sroot return (0); 10488099Sroot } 1049