/* #define HOWFAR */ /* @(#)sys1.c 1.8 */ #include "sys/param.h" #include "sys/config.h" #include "sys/mmu.h" #include "sys/types.h" #include "sys/sysmacros.h" #include "sys/systm.h" #include "sys/map.h" #include "sys/dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "sys/proc.h" #include "sys/context.h" #include "sys/buf.h" #include "sys/reg.h" #include "sys/file.h" #include "sys/inode.h" #include "sys/seg.h" #include "sys/acct.h" #include "sys/sysinfo.h" #include "sys/var.h" #include "sys/ipc.h" #include "sys/shm.h" #include "sys/scat.h" /* * exec system call, with and without environments. */ struct execa { char *fname; char **argp; char **envp; }; exec() { ((struct execa *)u.u_ap)->envp = NULL; exece(); } #define NCABLK (NCARGS+BSIZE-1)/BSIZE exece() { register unsigned nc; register char *cp; register struct buf *bp; register struct execa *uap; register struct user *up; int na, ne, ucp, ap, c, bno; struct inode *ip; extern struct inode *gethead(); char *namep; extern int (*putchar)(); sysinfo.sysexec++; if ((ip = gethead()) == NULL) return; up = &u; bp = 0; na = 0; nc = 0; ne = 0; uap = (struct execa *)up->u_ap; /* collect arglist */ if ((bno = swapalloc(NCABLK, 0)) == 0) { printf("No swap space for exec args\n"); iput(ip); up->u_error = ENOMEM; return; } if (uap->argp) for (;;) { ap = NULL; if (uap->argp) { ap = fuword((caddr_t)uap->argp); uap->argp++; } if (ap==NULL && uap->envp) { uap->argp = NULL; if ((ap = fuword((caddr_t)uap->envp)) == NULL) break; uap->envp++; ne++; } if (ap==NULL) break; na++; if (ap == -1) up->u_error = EFAULT; do { if (nc >= NCARGS-1) up->u_error = E2BIG; if ((c = fubyte((caddr_t)ap++)) < 0) up->u_error = EFAULT; if (up->u_error) goto bad; if ((nc&BMASK) == 0) { if (bp) bdwrite(bp); bp = getblk(swapdev, (daddr_t)(swplo+bno+(nc>>BSHIFT))); cp = bp->b_un.b_addr; } nc++; *cp++ = c; } while (c>0); } if (bp) bdwrite(bp); bp = 0; nc = (nc + NBPW-1) & ~(NBPW-1); getxfile(ip, (int)(nc + sizeof(char *)*na)); if (up->u_error) { printf("exec error: u_error %d u_dent.d_name ", up->u_error); for (namep = &up->u_dent.d_name[0]; namep && *namep && namep < &up->u_dent.d_name[DIRSIZ]; namep++) (*putchar)(*namep); (*putchar)('\n'); psignal(up->u_procp, SIGKILL); goto bad; } /* copy back arglist */ ucp = v.v_uend - nc - NBPW; ap = ucp - na*NBPW - 3*NBPW; up->u_ar0[SP] = ap; #ifdef HOWFAR printf("Setting new stack pointer to 0x%x\n", ap); #endif (void) suword((caddr_t)ap, na-ne); nc = 0; for (;;) { ap += NBPW; if (na==ne) { ap += NBPW; } if (--na < 0) break; (void) suword((caddr_t)ap, ucp); do { if ((nc&BMASK) == 0) { if (bp) { bp->b_flags |= B_AGE; bp->b_flags &= ~B_DELWRI; brelse(bp); } bp = bread(swapdev, (daddr_t)(swplo+bno+(nc>>BSHIFT))); bp->b_flags |= B_AGE; bp->b_flags &= ~B_DELWRI; cp = bp->b_un.b_addr; } (void) subyte((caddr_t)ucp++, (c = *cp++)); nc++; } while (c&0377); } (void) suword((caddr_t)ap, 0); if ((long)ucp & 1) (void) subyte((caddr_t)ucp++, 0); (void) suword((caddr_t)ucp, 0); setregs(); if (bp) { bp->b_flags |= B_AGE; bp->b_flags &= ~B_DELWRI; brelse(bp); } iput(ip); mfree(swapmap, NCABLK, bno); return; bad: if (bp) brelse(bp); iput(ip); for (nc = 0; nc < NCABLK; nc++) { bp = getblk(swapdev, (daddr_t)(swplo+bno+nc)); bp->b_flags |= B_AGE; bp->b_flags &= ~B_DELWRI; brelse(bp); } mfree(swapmap, NCABLK, bno); } struct inode * gethead() { register struct exdata *ep; register struct inode *ip; register unsigned ds, ts; register struct user *up; struct exdata exdata; struct naout { short magic; short vstamp; long tsize, dsize, bsize, entry, ts, ds; }; struct filhd { unsigned short magic; unsigned short nscns; long timdat, symptr, nsyms; unsigned short opthdr, flags; } ; struct scnhdr { char s_name[8]; long s_paddr, s_vaddr, s_size, s_scnptr, s_relptr, s_lnnoptr; unsigned short s_nreloc, s_nlnno; long s_flags; }; if ((ip = namei(uchar, 0)) == NULL) return(NULL); up = &u; if (access(ip, IEXEC) || (ip->i_mode & IFMT) != IFREG || (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { up->u_error = EACCES; goto bad; } /* * read in first few bytes of file for segment sizes * ux_mag = 407/410/411 * 407 is plain executable * 410 is RO text * 411 is separated ID * 570 Common object * 575 " * set ux_tstart to start of text portion */ ep = &exdata; up->u_base = (caddr_t)ep; up->u_count = sizeof(*ep); up->u_offset = 0; up->u_segflg = 1; readi(ip); #ifdef notdef if (ep->ux_mag == 0570 || ep->ux_mag == 0575) { up->u_base = (caddr_t)ep; up->u_count = sizeof(*ep); up->u_offset = sizeof(struct filhd); up->u_segflg = 1; readi(ip); ep->ux_tstart = sizeof(struct naout) + sizeof(struct filhd) + (3 * sizeof(struct scnhdr)); ep->ux_entloc = ep->ux_ssize; } else { ep->ux_tstart = sizeof(up->u_exdata); } #endif up->u_segflg = 0; if (up->u_count!=0) ep->ux_mag = 0; if (ep->ux_mag == 0407) { ds = btoc((long)ep->ux_tsize + (long)ep->ux_dsize + (long)ep->ux_bsize); ts = 0; ep->ux_dsize += ep->ux_tsize; ep->ux_tsize = 0; } else { ts = btoc(ep->ux_tsize); ds = btoc(ep->ux_dsize+ep->ux_bsize); if ((ip->i_flag&ITEXT)==0 && ip->i_count!=1) { register struct file *fp; for (fp = file; fp < (struct file *)v.ve_file; fp++) if (fp->f_count && fp->f_inode == ip && (fp->f_flag&FWRITE)) { up->u_error = ETXTBSY; goto bad; } } if (ep->ux_mag != 0410) { up->u_error = ENOEXEC; goto bad; } } (void) chksize(ts, ds, (unsigned)(SSIZE+btoc(NCARGS-1))); up->u_exdata = exdata; bad: if (up->u_error) { iput(ip); ip = NULL; } return(ip); } /* * Read in and set up memory for executed file. */ getxfile(ip, nargc) register struct inode *ip; { register struct exdata *ep; register struct user *up; register struct proc *p; register unsigned ts, ds, ss; register i; up = &u; p = up->u_procp; ep = &up->u_exdata; #ifdef HOWFAR printf("getxfile:reading in program\n"); #endif shmexec(); (void) punlock(); xfree(); ts = btoc(ep->ux_tsize); ds = btoc(ep->ux_dsize + ep->ux_bsize); ss = SSIZE + v.v_usize + btoc(nargc); i = v.v_usize+ds+ss; expand(i); (void) estabur((unsigned)0, ds, ss, 0, RO); procclear(p); /* while (--i >= v.v_usize) clearseg((int)(p->p_addr+i)); */ xalloc(ip); up->u_prof.pr_scale = 0; /* * read in data segment */ (void) estabur(ts, ds, (unsigned)0, 0, RO); if (v.v_doffset) up->u_base = (caddr_t)v.v_doffset; else up->u_base = (caddr_t)(v.v_ustart + ctob(stoc(ctos(ts)))); up->u_offset = sizeof(up->u_exdata) + ep->ux_tsize; up->u_count = ep->ux_dsize; readi(ip); if (up->u_count!=0) up->u_error = EFAULT; /* * set SUID/SGID protections, if no tracing */ if ((p->p_flag&STRC)==0) { if (ip->i_mode&ISUID) up->u_uid = ip->i_uid; if (ip->i_mode&ISGID) up->u_gid = ip->i_gid; p->p_suid = up->u_uid; } else psignal(p, SIGTRAP); up->u_tsize = ts; up->u_dsize = ds; up->u_ssize = ss; (void) estabur(ts, ds, ss, 0, RO); } /* * Clear registers on exec */ setregs() { register struct user *up; register char *cp; register int *rp; register i; up = &u; for (rp = &up->u_signal[0]; rp < &up->u_signal[NSIG]; rp++) if ((*rp & 1) == 0) *rp = 0; for (cp = ®loc[0]; cp < ®loc[15]; ) up->u_ar0[*cp++] = 0; up->u_ar0[PC] = up->u_exdata.ux_entloc & ~01; #ifdef HOWFAR printf("New pc = 0x%x\n", up->u_ar0[PC]); #endif for (i=0; iu_pofile[i]&EXCLOSE) && up->u_ofile[i] != NULL) { closef(up->u_ofile[i]); up->u_ofile[i] = NULL; } } /* * Remember file name for accounting. */ up->u_acflag &= ~AFORK; bcopy((caddr_t)up->u_dent.d_name, (caddr_t)up->u_comm, DIRSIZ); } /* * clear the data space for a process */ #ifdef NONSCATLOAD procclear(p) struct proc *p; { register i, a; a = p->p_addr; i = p->p_size; while(--i >= v.v_usize) clearseg(a+i); } #else procclear(p) struct proc *p; { register struct scatter *s; register i, a1; s = scatmap; a1 = p->p_scat; for (i=0; irval & 0377) << 8); } /* * Release resources. * Enter zombie state. * Wake up parent and init processes, * and dispose of children. */ exit(rv) { register struct user *up; register int i; register struct proc *p, *q; #ifdef mc68881 /* MC68881 floating-point coprocessor */ extern short fp881; /* is there an MC68881? */ #endif mc68881 up = &u; p = up->u_procp; p->p_flag &= ~(STRC); p->p_clktim = 0; for (i=0; iu_signal[i] = 1; expand(v.v_usize); (void) estabur((unsigned)0, (unsigned)0, (unsigned)0, 0, RO); if ((p->p_pid == p->p_pgrp) && (up->u_ttyp != NULL) && (*up->u_ttyp == p->p_pgrp)) { *up->u_ttyp = 0; signal(p->p_pgrp, SIGHUP); } p->p_pgrp = 0; for (i=0; iu_ofile[i] != NULL) closef(up->u_ofile[i]); } (void) punlock(); plock(up->u_cdir); iput(up->u_cdir); if (up->u_rdir) { plock(up->u_rdir); iput(up->u_rdir); } #ifdef FLOAT /* sky floating point board */ /* * If this process was using the SKY FFP, restore * the board to a known state. */ if (up->u_fpinuse) savfp(); #endif #ifdef mc68881 /* MC68881 floating-point coprocessor */ /* * If there is an MC68881, save the internal state and user * registers so they'll be available in a core image. * Then reset the coprocessor by restoring it to a null state. */ if (fp881) { fpsave(); fpreset(); } #endif mc68881 /* * call OEM supplied subroutine on process exit */ oemexit(p); xfree(); semexit(); shmexit(); acct(rv); #ifdef NONSCATLOAD mfree(coremap, p->p_size, p->p_addr); #else memfree(p->p_scat); p->p_scat = SCATEND; #endif cxrelse(p->p_context); p->p_stat = SZOMB; ((struct xproc *)p)->xp_xstat = rv; ((struct xproc *)p)->xp_utime = up->u_cutime + up->u_utime; ((struct xproc *)p)->xp_stime = up->u_cstime + up->u_stime; for (q = &proc[1]; q < (struct proc *)v.ve_proc; q++) { if (p->p_pid == q->p_ppid) { q->p_ppid = 1; if (q->p_stat == SZOMB) psignal(&proc[1], SIGCLD); if (q->p_stat == SSTOP) setrun(q); } else if (p->p_ppid == q->p_pid) psignal(q, SIGCLD); if (p->p_pid == q->p_pgrp) q->p_pgrp = 0; } #ifdef NONSCATLOAD resume(proc[0].p_addr, up->u_qsav); #else resume(ixtoc(proc[0].p_scat), up->u_qsav); #endif /* no deposit, no return */ } /* * Wait system call. * Search for a terminated (zombie) child, * finally lay it to rest, and collect its status. * Look also for stopped (traced) children, * and pass back status from them. */ wait() { register struct user *up; register f; register struct proc *p; up = &u; loop: f = 0; for (p = &proc[1]; p < (struct proc *)v.ve_proc; p++) if (p->p_ppid == up->u_procp->p_pid) { f++; if (p->p_stat == SZOMB) { freeproc(p, 1); return; } if (p->p_stat == SSTOP) { if ((p->p_flag&SWTED) == 0) { p->p_flag |= SWTED; up->u_rval1 = p->p_pid; up->u_rval2 = (fsig(p)<<8) | 0177; return; } continue; } } if (f) { (void) sleep((caddr_t)up->u_procp, PWAIT); goto loop; } up->u_error = ECHILD; } /* * Remove zombie children from the process table. */ freeproc(p, flag) register struct proc *p; { register struct user *up; up = &u; if (flag) { register n; n = up->u_procp->p_cpu + p->p_cpu; if (n > 80) n = 80; up->u_procp->p_cpu = n; up->u_rval1 = p->p_pid; up->u_rval2 = ((struct xproc *)p)->xp_xstat; } up->u_cutime += ((struct xproc *)p)->xp_utime; up->u_cstime += ((struct xproc *)p)->xp_stime; p->p_stat = NULL; p->p_pid = 0; p->p_ppid = 0; p->p_sig = 0L; p->p_flag = 0; p->p_wchan = 0; } /* * fork system call. */ fork() { register struct user *up; register a, i; int sz, xsize[NSCATSWAP], xaddr[NSCATSWAP]; up = &u; sysinfo.sysfork++; /* * Disallow if * No processes at all; * not su and too many procs owned; or * not su and would take last slot; or * not su and no space on swap. * Part of check done in newproc(). */ if (up->u_uid && up->u_ruid) { if ((a = malloc(swapmap, ctod(maxmem))) == NULL) { sz = ctod(maxmem); for (i = 0; i < NSCATSWAP; i++) if (sz == 0) { xsize[i] = 0; break; } else { a = MIN(mallocl(swapmap), sz); xsize[i] = a; xaddr[i] = malloc(swapmap, a); sz -= a; } for (i = 0; i < NSCATSWAP; i++) if (xsize[i] == 0) break; else mfree(swapmap, xsize[i], xaddr[i]); if (sz != 0) { printf("Not enough swap space to fork\n"); up->u_error = ENOMEM; goto out; } } else mfree(swapmap, ctod(maxmem), a); } switch( newproc(1) ) { case 1: /* child -- successful newproc */ up->u_rval1 = up->u_procp->p_ppid; up->u_rval2 = 1; /* child */ up->u_start = time; up->u_ticks = lbolt; up->u_mem = v.v_usize + procsize(up->u_procp); up->u_ior = 0; up->u_iow = 0; up->u_ioch = 0; up->u_cstime = 0; up->u_stime = 0; up->u_cutime = 0; up->u_utime = 0; up->u_acflag = AFORK; return; case 0: /* parent -- successful newproc */ /* up->u_rval1 = pid-of-child; */ break; default: /* unsuccessful newproc */ up->u_error = EAGAIN; break; } out: up->u_rval2 = 0; /* parent */ up->u_ar0[PC] += 2; } /* * break system call. * -- bad planning: "break" is a dirty word in C. */ #ifdef NONSCATLOAD sbreak() { register struct user *up; struct a { unsigned nsiz; }; register n, d, a; int i; up = &u; /* * set n to new data size * set d to new-old * set n to new total size */ if (v.v_doffset) n = btoc((int)(((struct a *)up->u_ap)->nsiz)) - btoc(v.v_doffset); else { n = btoc((int)(((struct a *)up->u_ap)->nsiz)) - btoc(v.v_ustart); n -= stoc(ctos(up->u_tsize)); } if (n < 0) n = 0; d = n - up->u_dsize; if (d == 0) return; n += v.v_usize+up->u_ssize; if (chksize(up->u_tsize, up->u_dsize+d, up->u_ssize)) return; up->u_dsize += d; (void) estabur(up->u_tsize, up->u_dsize, up->u_ssize, 0, RO); if (d > 0) goto bigger; a = up->u_procp->p_addr + n - up->u_ssize; i = n; if (d < 0) { n = up->u_ssize; while (n--) { copyseg(a-d, a); a++; } } expand(i); return; bigger: expand(n); a = up->u_procp->p_addr + n; n = up->u_ssize; while (n--) { a--; copyseg(a-d, a); } while (d--) clearseg(--a); } #else sbreak() { register struct scatter *s; register struct user *up; struct a { unsigned nsiz; }; register n, d, a1, a2; int i; short t; up = &u; /* * set n to new data size * set d to new-old * set n to new total size */ n = btoc((int)(((struct a *)up->u_ap)->nsiz)) - btoc(v.v_ustart); n -= stoc(ctos(up->u_tsize)); if (n < 0) n = 0; d = n - up->u_dsize; if (d == 0) return; n += v.v_usize+up->u_ssize; if (chksize(up->u_tsize, up->u_dsize+d, up->u_ssize)) return; s = scatmap; up->u_dsize += d; if (d > 0) goto bigger; nscatfree -= d; /* note: d is negative */ up->u_procp->p_size = n; a1 = up->u_procp->p_scat; n = up->u_dsize + v.v_usize; for (i=1; iu_tsize, up->u_dsize, up->u_ssize, 0, RO); #ifdef OLD a = up->u_procp->p_addr + n - up->u_ssize; i = n; if (d < 0) { n = up->u_ssize; while (n--) { copyseg(a-d, a); a++; } } expand(i); #endif up->u_procp->p_flag &= ~SCONTIG; return; bigger: expand(n); a1 = up->u_procp->p_scat; /* * find last index of original data space */ n = up->u_dsize + v.v_usize - d; if (n == 0) printf("sbreak:original size is zero\n"); for (i=1; iu_ssize !=0 && (int)(up->u_dsize-d) <= 0) printf("sbreak:bigger: unusual condition #1\n"); if (up->u_ssize == 0) { while (d-- > 0) clearseg(ixtoc(a1 = s[a1].sc_index)); if (s[a1].sc_index != SCATEND) printf("sbreak:not at end of list\n"); } else { /* * find end of original stack space */ a2 = a1; for (i=0; iu_ssize; i++) a2 = s[a2].sc_index; t = s[a1].sc_index; s[a1].sc_index = s[a2].sc_index; s[a2].sc_index = SCATEND; while (d-- > 0) clearseg(ixtoc(a1 = s[a1].sc_index)); s[a1].sc_index = t; } (void) estabur(up->u_tsize, up->u_dsize, up->u_ssize, 0, RO); up->u_procp->p_flag &= ~SCONTIG; #ifdef OLD a = up->u_procp->p_addr + n; n = up->u_ssize; while (n--) { a--; copyseg(a-d, a); } while (d--) clearseg(--a); #endif }