1*83Sbill /* kern_proc.c 3.2 10/14/12 */ 236Sbill 336Sbill #include "../h/param.h" 436Sbill #include "../h/systm.h" 536Sbill #include "../h/map.h" 636Sbill #include "../h/mtpr.h" 736Sbill #include "../h/dir.h" 836Sbill #include "../h/user.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" 1536Sbill #include "../h/pte.h" 1636Sbill #include "../h/vm.h" 1736Sbill #include "../h/text.h" 1836Sbill 1936Sbill /* 2036Sbill * exec system call, with and without environments. 2136Sbill */ 2236Sbill struct execa { 2336Sbill char *fname; 2436Sbill char **argp; 2536Sbill char **envp; 2636Sbill }; 2736Sbill 2836Sbill exec() 2936Sbill { 3036Sbill ((struct execa *)u.u_ap)->envp = NULL; 3136Sbill exece(); 3236Sbill } 3336Sbill 3436Sbill exece() 3536Sbill { 3636Sbill register nc; 3736Sbill register char *cp; 3836Sbill register struct buf *bp; 3936Sbill register struct execa *uap; 4036Sbill int na, ne, ucp, ap, c; 4136Sbill struct inode *ip; 4236Sbill swblk_t bno; 4336Sbill 4436Sbill if ((ip = namei(uchar, 0)) == NULL) 4536Sbill return; 4636Sbill bno = 0; 4736Sbill bp = 0; 4836Sbill if(access(ip, IEXEC)) 4936Sbill goto bad; 5036Sbill if((ip->i_mode & IFMT) != IFREG || 5136Sbill (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { 5236Sbill u.u_error = EACCES; 5336Sbill goto bad; 5436Sbill } 5536Sbill /* 5636Sbill * Collect arguments on "file" in swap space. 5736Sbill */ 5836Sbill na = 0; 5936Sbill ne = 0; 6036Sbill nc = 0; 6136Sbill uap = (struct execa *)u.u_ap; 6236Sbill if ((bno = malloc(swapmap, ctod(clrnd((int) btoc(NCARGS))))) == 0) { 6336Sbill swkill(u.u_procp, "exece"); 6436Sbill goto bad; 6536Sbill } 6636Sbill if (bno % CLSIZE) 6736Sbill panic("execa malloc"); 6836Sbill if (uap->argp) for (;;) { 6936Sbill ap = NULL; 7036Sbill if (uap->argp) { 7136Sbill ap = fuword((caddr_t)uap->argp); 7236Sbill uap->argp++; 7336Sbill } 7436Sbill if (ap==NULL && uap->envp) { 7536Sbill uap->argp = NULL; 7636Sbill if ((ap = fuword((caddr_t)uap->envp)) == NULL) 7736Sbill break; 7836Sbill uap->envp++; 7936Sbill ne++; 8036Sbill } 8136Sbill if (ap==NULL) 8236Sbill break; 8336Sbill na++; 8436Sbill if(ap == -1) 8536Sbill u.u_error = EFAULT; 8636Sbill do { 8736Sbill if (nc >= NCARGS-1) 8836Sbill u.u_error = E2BIG; 8936Sbill if ((c = fubyte((caddr_t)ap++)) < 0) 9036Sbill u.u_error = EFAULT; 91*83Sbill if (u.u_error) { 92*83Sbill if (bp) 93*83Sbill brelse(bp); 94*83Sbill bp = 0; 9536Sbill goto badarg; 96*83Sbill } 9736Sbill if ((nc&BMASK) == 0) { 9836Sbill if (bp) 9936Sbill bdwrite(bp); 10036Sbill bp = getblk(swapdev, (daddr_t)(dbtofsb(swplo+bno)+(nc>>BSHIFT))); 10136Sbill cp = bp->b_un.b_addr; 10236Sbill } 10336Sbill nc++; 10436Sbill *cp++ = c; 10536Sbill } while (c>0); 10636Sbill } 10736Sbill if (bp) 10836Sbill bdwrite(bp); 10936Sbill bp = 0; 11036Sbill nc = (nc + NBPW-1) & ~(NBPW-1); 11136Sbill if (getxfile(ip, nc) || u.u_error) { 11236Sbill badarg: 11336Sbill for (c = 0; c < nc; c += BSIZE) 11436Sbill if (bp = baddr(swapdev, dbtofsb(swplo+bno)+(c>>BSHIFT))) { 11536Sbill bp->b_flags |= B_AGE; /* throw away */ 11636Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 11736Sbill brelse(bp); 11836Sbill bp = 0; 11936Sbill } 12036Sbill goto bad; 12136Sbill } 12236Sbill 12336Sbill /* 12436Sbill * copy back arglist 12536Sbill */ 12636Sbill 12736Sbill ucp = USRSTACK - nc - NBPW; 12836Sbill ap = ucp - na*NBPW - 3*NBPW; 12936Sbill u.u_ar0[SP] = ap; 13036Sbill VOID suword((caddr_t)ap, na-ne); 13136Sbill nc = 0; 13236Sbill for (;;) { 13336Sbill ap += NBPW; 13436Sbill if (na==ne) { 13536Sbill VOID suword((caddr_t)ap, 0); 13636Sbill ap += NBPW; 13736Sbill } 13836Sbill if (--na < 0) 13936Sbill break; 14036Sbill VOID suword((caddr_t)ap, ucp); 14136Sbill do { 14236Sbill if ((nc&BMASK) == 0) { 14336Sbill if (bp) 14436Sbill brelse(bp); 14536Sbill bp = bread(swapdev, (daddr_t)(dbtofsb(swplo+bno)+(nc>>BSHIFT))); 14636Sbill bp->b_flags |= B_AGE; /* throw away */ 14736Sbill bp->b_flags &= ~B_DELWRI; /* cancel io */ 14836Sbill cp = bp->b_un.b_addr; 14936Sbill } 15036Sbill VOID subyte((caddr_t)ucp++, (c = *cp++)); 15136Sbill nc++; 15236Sbill } while(c&0377); 15336Sbill } 15436Sbill VOID suword((caddr_t)ap, 0); 15536Sbill VOID suword((caddr_t)ucp, 0); 15636Sbill setregs(); 15736Sbill bad: 15836Sbill if (bp) 15936Sbill brelse(bp); 16036Sbill if (bno) 16136Sbill mfree(swapmap, ctod(clrnd((int) btoc(NCARGS))), bno); 16236Sbill iput(ip); 16336Sbill } 16436Sbill 16536Sbill /* 16636Sbill * Read in and set up memory for executed file. 16736Sbill * Zero return is normal; 16836Sbill * non-zero means only the text is being replaced 16936Sbill */ 17036Sbill getxfile(ip, nargc) 17136Sbill register struct inode *ip; 17236Sbill { 17336Sbill register sep; 17436Sbill register size_t ts, ds, ss; 17536Sbill register int overlay; 17636Sbill int pagi = 0; 17736Sbill 17836Sbill /* 17936Sbill * read in first few bytes 18036Sbill * of file for segment 18136Sbill * sizes: 18236Sbill * ux_mag = 407/410/411/405 18336Sbill * 407 is plain executable 18436Sbill * 410 is RO text 18536Sbill * 411 is separated ID 18636Sbill * 405 is overlaid text 18736Sbill * 412 is demand paged plain executable (NOT IMPLEMENTED) 18836Sbill * 413 is demand paged RO text 18936Sbill */ 19036Sbill 19136Sbill u.u_base = (caddr_t)&u.u_exdata; 19236Sbill u.u_count = sizeof(u.u_exdata); 19336Sbill u.u_offset = 0; 19436Sbill u.u_segflg = 1; 19536Sbill readi(ip); 19636Sbill u.u_segflg = 0; 19736Sbill if(u.u_error) 19836Sbill goto bad; 19936Sbill if (u.u_count!=0) { 20036Sbill u.u_error = ENOEXEC; 20136Sbill goto bad; 20236Sbill } 20336Sbill sep = 0; 20436Sbill overlay = 0; 20536Sbill switch (u.u_exdata.ux_mag) { 20636Sbill 20736Sbill case 0405: 20836Sbill overlay++; 20936Sbill break; 21036Sbill 21136Sbill case 0412: 21236Sbill u.u_error = ENOEXEC; 21336Sbill goto bad; 21436Sbill 21536Sbill case 0407: 21636Sbill u.u_exdata.ux_dsize += u.u_exdata.ux_tsize; 21736Sbill u.u_exdata.ux_tsize = 0; 21836Sbill break; 21936Sbill 22036Sbill case 0413: 22136Sbill pagi = SPAGI; 22236Sbill /* fall into ... */ 22336Sbill 22436Sbill case 0410: 22536Sbill if (u.u_exdata.ux_tsize == 0) { 22636Sbill u.u_error = ENOEXEC; 22736Sbill goto bad; 22836Sbill } 22936Sbill break; 23036Sbill 23136Sbill case 0411: 23236Sbill u.u_error = ENOEXEC; 23336Sbill goto bad; 23436Sbill 23536Sbill default: 23636Sbill u.u_error = ENOEXEC; 23736Sbill goto bad; 23836Sbill } 23936Sbill if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) { 24036Sbill u.u_error = ETXTBSY; 24136Sbill goto bad; 24236Sbill } 24336Sbill 24436Sbill /* 24536Sbill * find text and data sizes 24636Sbill * try them out for possible 24736Sbill * exceed of max sizes 24836Sbill */ 24936Sbill 25036Sbill ts = clrnd(btoc(u.u_exdata.ux_tsize)); 25136Sbill ds = clrnd(btoc((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize))); 25236Sbill ss = clrnd(SSIZE + btoc(nargc)); 25336Sbill if (overlay) { 25436Sbill if ((u.u_procp->p_flag & SPAGI) || u.u_sep==0 && ctos(ts) != ctos(u.u_tsize) || nargc) { 25536Sbill u.u_error = ENOMEM; 25636Sbill goto bad; 25736Sbill } 25836Sbill ds = u.u_dsize; 25936Sbill ss = u.u_ssize; 26036Sbill sep = u.u_sep; 26136Sbill xfree(); 26236Sbill xalloc(ip, pagi); 26336Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 26436Sbill } else { 26536Sbill if (chksize(ts, ds, ss)) 26636Sbill goto bad; 26736Sbill u.u_cdmap = zdmap; 26836Sbill u.u_csmap = zdmap; 26936Sbill if (swpexpand(ds, ss, &u.u_cdmap, &u.u_csmap) == NULL) 27036Sbill goto bad; 27136Sbill 27236Sbill /* 27336Sbill * At this point, committed to the new image! 27436Sbill * Release virtual memory resources of old process, and 27536Sbill * initialize the virtual memory of the new process. 27636Sbill * If we resulted from vfork(), instead wakeup our 27736Sbill * parent who will set SVFDONE when he has taken back 27836Sbill * our resources. 27936Sbill */ 28036Sbill u.u_prof.pr_scale = 0; 28136Sbill if ((u.u_procp->p_flag & SVFORK) == 0) 28236Sbill vrelvm(); 28336Sbill else { 28436Sbill u.u_procp->p_flag &= ~SVFORK; 28536Sbill u.u_procp->p_flag |= SKEEP; 28636Sbill wakeup((caddr_t)u.u_procp); 28736Sbill while ((u.u_procp->p_flag & SVFDONE) == 0) 28836Sbill sleep((caddr_t)u.u_procp, PZERO - 1); 28936Sbill u.u_procp->p_flag &= ~(SVFDONE|SKEEP); 29036Sbill } 29136Sbill u.u_procp->p_flag &= ~(SPAGI|SANOM|SUANOM); 29236Sbill u.u_procp->p_flag |= pagi; 29336Sbill u.u_dmap = u.u_cdmap; 29436Sbill u.u_smap = u.u_csmap; 29536Sbill vgetvm(ts, ds, ss); 29636Sbill 29736Sbill if (pagi == 0) { 29836Sbill /* 29936Sbill * Read in data segment. 30036Sbill */ 30136Sbill u.u_base = (char *)ctob(ts); 30236Sbill u.u_offset = sizeof(u.u_exdata)+u.u_exdata.ux_tsize; 30336Sbill u.u_count = u.u_exdata.ux_dsize; 30436Sbill readi(ip); 30536Sbill } 30636Sbill xalloc(ip, pagi); 30736Sbill if (pagi && u.u_procp->p_textp) 30836Sbill vinifod((struct fpte *)dptopte(u.u_procp, 0), 30936Sbill PG_FTEXT, u.u_procp->p_textp->x_iptr, 31036Sbill 1 + ts/CLSIZE, (int)btoc(u.u_exdata.ux_dsize)); 31136Sbill 31236Sbill /* THIS SHOULD BE DONE AT A LOWER LEVEL, IF AT ALL */ 31336Sbill mtpr(TBIA,1); 31436Sbill 31536Sbill /* 31636Sbill * set SUID/SGID protections, if no tracing 31736Sbill */ 31836Sbill if ((u.u_procp->p_flag&STRC)==0) { 31936Sbill if(ip->i_mode&ISUID) 32036Sbill if(u.u_uid != 0) { 32136Sbill u.u_uid = ip->i_uid; 32236Sbill u.u_procp->p_uid = ip->i_uid; 32336Sbill } 32436Sbill if(ip->i_mode&ISGID) 32536Sbill u.u_gid = ip->i_gid; 32636Sbill } else 32736Sbill psignal(u.u_procp, SIGTRC); 32836Sbill } 32936Sbill u.u_tsize = ts; 33036Sbill u.u_dsize = ds; 33136Sbill u.u_ssize = ss; 33236Sbill u.u_sep = sep; 33336Sbill bad: 33436Sbill return(overlay); 33536Sbill } 33636Sbill 33736Sbill /* 33836Sbill * Clear registers on exec 33936Sbill */ 34036Sbill setregs() 34136Sbill { 34236Sbill register int *rp; 34336Sbill register i; 34436Sbill 34536Sbill for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++) 34636Sbill if((*rp & 1) == 0) 34736Sbill *rp = 0; 34836Sbill /* 34936Sbill for(rp = &u.u_ar0[0]; rp < &u.u_ar0[16];) 35036Sbill *rp++ = 0; 35136Sbill */ 35236Sbill u.u_ar0[PC] = u.u_exdata.ux_entloc + 2; /* skip over entry mask */ 35336Sbill for(i=0; i<NOFILE; i++) { 35436Sbill if (u.u_pofile[i]&EXCLOSE) { 35536Sbill closef(u.u_ofile[i]); 35636Sbill u.u_ofile[i] = NULL; 35736Sbill } 35836Sbill u.u_pofile[i] &= ~EXCLOSE; 35936Sbill } 36036Sbill /* 36136Sbill * Remember file name for accounting. 36236Sbill */ 36336Sbill u.u_acflag &= ~AFORK; 36436Sbill bcopy((caddr_t)u.u_dbuf, (caddr_t)u.u_comm, DIRSIZ); 36536Sbill } 36636Sbill 36736Sbill /* 36836Sbill * exit system call: 36936Sbill * pass back caller's arg 37036Sbill */ 37136Sbill rexit() 37236Sbill { 37336Sbill register struct a { 37436Sbill int rval; 37536Sbill } *uap; 37636Sbill 37736Sbill uap = (struct a *)u.u_ap; 37836Sbill exit((uap->rval & 0377) << 8); 37936Sbill } 38036Sbill 38136Sbill /* 38236Sbill * Release resources. 38336Sbill * Save u. area for parent to look at. 38436Sbill * Enter zombie state. 38536Sbill * Wake up parent and init processes, 38636Sbill * and dispose of children. 38736Sbill */ 38836Sbill exit(rv) 38936Sbill { 39036Sbill register int i; 39136Sbill register struct proc *p, *q; 39236Sbill register struct file *f; 39336Sbill register int x; 39436Sbill 39536Sbill #ifdef PGINPROF 39636Sbill vmsizmon(); 39736Sbill #endif 39836Sbill p = u.u_procp; 39936Sbill p->p_flag &= ~(STRC|SULOCK); 40036Sbill p->p_flag |= SWEXIT; 40136Sbill p->p_clktim = 0; 40236Sbill rate.v_pgin -= p->p_aveflt; 40336Sbill p->p_aveflt = 0; 40436Sbill for(i=0; i<NSIG; i++) 40536Sbill u.u_signal[i] = 1; 40636Sbill /* 40736Sbill * Release virtual memory. If we resulted from 40836Sbill * a vfork(), instead give the resources back to 40936Sbill * the parent. 41036Sbill */ 41136Sbill if ((p->p_flag & SVFORK) == 0) 41236Sbill vrelvm(); 41336Sbill else { 41436Sbill p->p_flag &= ~SVFORK; 41536Sbill wakeup((caddr_t)p); 41636Sbill while ((p->p_flag & SVFDONE) == 0) 41736Sbill sleep((caddr_t)p, PZERO - 1); 41836Sbill p->p_flag &= ~SVFDONE; 41936Sbill } 42036Sbill for(i=0; i<NOFILE; i++) { 42136Sbill f = u.u_ofile[i]; 42236Sbill u.u_ofile[i] = NULL; 42336Sbill closef(f); 42436Sbill } 42536Sbill plock(u.u_cdir); 42636Sbill iput(u.u_cdir); 42736Sbill if (u.u_rdir) { 42836Sbill plock(u.u_rdir); 42936Sbill iput(u.u_rdir); 43036Sbill } 43136Sbill acct(); 43236Sbill vrelpt(u.u_procp); 43336Sbill vrelu(u.u_procp, 0); 43436Sbill multprog--; 43536Sbill spl7(); /* clock will get mad because of overlaying */ 43636Sbill p->p_stat = SZOMB; 43736Sbill i = PIDHASH(p->p_pid); 43836Sbill x = p - proc; 43936Sbill if (pidhash[i] == x) 44036Sbill pidhash[i] = p->p_idhash; 44136Sbill else { 44236Sbill for (i = pidhash[i]; i != 0; i = proc[i].p_idhash) 44336Sbill if (proc[i].p_idhash == x) { 44436Sbill proc[i].p_idhash = p->p_idhash; 44536Sbill goto done; 44636Sbill } 44736Sbill panic("exit"); 44836Sbill } 44936Sbill done: 45036Sbill ((struct xproc *)p)->xp_xstat = rv; /* overlay */ 45136Sbill ((struct xproc *)p)->xp_vm = u.u_vm; /* overlay */ 45236Sbill vmsadd(&((struct xproc *)p)->xp_vm, &u.u_cvm); 45336Sbill for(q = &proc[0]; q < &proc[NPROC]; q++) 45436Sbill if(q->p_ppid == p->p_pid) { 45536Sbill wakeup((caddr_t)&proc[1]); 45636Sbill q->p_ppid = 1; 45736Sbill if (q->p_stat==SSTOP) 45836Sbill setrun(q); 45936Sbill } 46036Sbill q = pfind(p->p_ppid); 46136Sbill if (q) 46236Sbill wakeup((caddr_t)q); 46336Sbill swtch(); 46436Sbill } 46536Sbill 46636Sbill wait() 46736Sbill { 46836Sbill 46936Sbill wait1((struct vtimes *)0); 47036Sbill } 47136Sbill 47236Sbill /* 47336Sbill * Wait system call. 47436Sbill * Search for a terminated (zombie) child, 47536Sbill * finally lay it to rest, and collect its status. 47636Sbill * Look also for stopped (traced) children, 47736Sbill * and pass back status from them. 47836Sbill */ 47936Sbill wait1(vp) 48036Sbill struct vtimes *vp; 48136Sbill { 48236Sbill register f; 48336Sbill register struct proc *p; 48436Sbill 48536Sbill f = 0; 48636Sbill 48736Sbill loop: 48836Sbill for(p = &proc[0]; p < &proc[NPROC]; p++) 48936Sbill if(p->p_ppid == u.u_procp->p_pid) { 49036Sbill f++; 49136Sbill if(p->p_stat == SZOMB) { 49236Sbill u.u_r.r_val1 = p->p_pid; 49336Sbill u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat; 49436Sbill ((struct xproc *)p)->xp_xstat = 0; 49536Sbill if (vp) 49636Sbill *vp = ((struct xproc *)p)->xp_vm; 49736Sbill vmsadd(&u.u_cvm, &((struct xproc *)p)->xp_vm); 49836Sbill ((struct xproc *)p)->xp_vm = zvms; 49936Sbill p->p_stat = NULL; 50036Sbill p->p_pid = 0; 50136Sbill p->p_ppid = 0; 50236Sbill p->p_sig = 0; 50336Sbill p->p_pgrp = 0; 50436Sbill p->p_flag = 0; 50536Sbill p->p_wchan = 0; 50636Sbill return; 50736Sbill } 50836Sbill if(p->p_stat == SSTOP) { 50936Sbill if((p->p_flag&SWTED) == 0) { 51036Sbill p->p_flag |= SWTED; 51136Sbill u.u_r.r_val1 = p->p_pid; 51236Sbill u.u_r.r_val2 = (fsig(p)<<8) | 0177; 51336Sbill return; 51436Sbill } 51536Sbill continue; 51636Sbill } 51736Sbill } 51836Sbill if(f) { 51936Sbill sleep((caddr_t)u.u_procp, PWAIT); 52036Sbill goto loop; 52136Sbill } 52236Sbill u.u_error = ECHILD; 52336Sbill } 52436Sbill 52536Sbill /* 52636Sbill * fork system call. 52736Sbill */ 52836Sbill fork() 52936Sbill { 53036Sbill 53136Sbill u.u_cdmap = zdmap; 53236Sbill u.u_csmap = zdmap; 53336Sbill if (swpexpand(u.u_dsize, u.u_ssize, &u.u_cdmap, &u.u_csmap) == 0) { 53436Sbill u.u_r.r_val2 = 0; 53536Sbill return; 53636Sbill } 53736Sbill fork1(0); 53836Sbill } 53936Sbill 54036Sbill fork1(isvfork) 54136Sbill { 54236Sbill register struct proc *p1, *p2; 54336Sbill register a; 54436Sbill 54536Sbill a = 0; 54636Sbill p2 = NULL; 54736Sbill for(p1 = &proc[0]; p1 < &proc[NPROC]; p1++) { 54836Sbill if (p1->p_stat==NULL && p2==NULL) 54936Sbill p2 = p1; 55036Sbill else { 55136Sbill if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) 55236Sbill a++; 55336Sbill } 55436Sbill } 55536Sbill /* 55636Sbill * Disallow if 55736Sbill * No processes at all; 55836Sbill * not su and too many procs owned; or 55936Sbill * not su and would take last slot. 56036Sbill */ 56136Sbill if (p2==NULL || (u.u_uid!=0 && (p2==&proc[NPROC-1] || a>MAXUPRC))) { 56236Sbill u.u_error = EAGAIN; 56336Sbill if (!isvfork) { 56436Sbill VOID vsexpand(0, &u.u_cdmap, 1); 56536Sbill VOID vsexpand(0, &u.u_csmap, 1); 56636Sbill } 56736Sbill goto out; 56836Sbill } 56936Sbill p1 = u.u_procp; 57036Sbill if(newproc(isvfork)) { 57136Sbill u.u_r.r_val1 = p1->p_pid; 57236Sbill u.u_r.r_val2 = 1; /* child */ 57336Sbill u.u_start = time; 57436Sbill u.u_acflag = AFORK; 57536Sbill return; 57636Sbill } 57736Sbill u.u_r.r_val1 = p2->p_pid; 57836Sbill 57936Sbill out: 58036Sbill u.u_r.r_val2 = 0; 58136Sbill } 58236Sbill 58336Sbill /* 58436Sbill * break system call. 58536Sbill * -- bad planning: "break" is a dirty word in C. 58636Sbill */ 58736Sbill sbreak() 58836Sbill { 58936Sbill struct a { 59036Sbill char *nsiz; 59136Sbill }; 59236Sbill register int n, d; 59336Sbill 59436Sbill /* 59536Sbill * set n to new data size 59636Sbill * set d to new-old 59736Sbill */ 59836Sbill 59936Sbill n = btoc(((struct a *)u.u_ap)->nsiz); 60036Sbill if (!u.u_sep) 60136Sbill n -= ctos(u.u_tsize) * stoc(1); 60236Sbill if (n < 0) 60336Sbill n = 0; 60436Sbill d = clrnd(n - u.u_dsize); 60536Sbill if (chksize(u.u_tsize, u.u_dsize+d, u.u_ssize)) 60636Sbill return; 60736Sbill if (swpexpand(u.u_dsize+d, u.u_ssize, &u.u_dmap, &u.u_smap)==0) 60836Sbill return; 60936Sbill expand(d, P0BR); 61036Sbill } 611