#include "u.h"#include "tos.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h"#include "edf.h" #include <a.out.h> extern void checkpages(void);extern void checkpagerefs(void); uintptrsysr1(va_list){ if(!iseve()) error(Eperm); checkpagerefs(); return 0;} static voidabortion(void*){ pexit("fork aborted", 1);} uintptrsysrfork(va_list list){ Proc *p; int n, i; Fgrp *ofg; Pgrp *opg; Rgrp *org; Egrp *oeg; ulong pid, flag; Mach *wm; flag = va_arg(list, ulong); /* Check flags before we commit */ if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) error(Ebadarg); if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) error(Ebadarg); if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) error(Ebadarg); if((flag&RFPROC) == 0) { if(flag & (RFMEM|RFNOWAIT)) error(Ebadarg); if(flag & (RFFDG|RFCFDG)) { ofg = up->fgrp; if(flag & RFFDG) up->fgrp = dupfgrp(ofg); else up->fgrp = dupfgrp(nil); closefgrp(ofg); } if(flag & (RFNAMEG|RFCNAMEG)) { opg = up->pgrp; up->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(up->pgrp, opg); /* inherit noattach */ up->pgrp->noattach = opg->noattach; closepgrp(opg); } if(flag & RFNOMNT) up->pgrp->noattach = 1; if(flag & RFREND) { org = up->rgrp; up->rgrp = newrgrp(); closergrp(org); } if(flag & (RFENVG|RFCENVG)) { oeg = up->egrp; up->egrp = smalloc(sizeof(Egrp)); up->egrp->ref = 1; if(flag & RFENVG) envcpy(up->egrp, oeg); closeegrp(oeg); } if(flag & RFNOTEG) up->noteid = pidalloc(0); return 0; } p = newproc(); p->scallnr = up->scallnr; p->s = up->s; p->nerrlab = 0; p->slash = up->slash; p->dot = up->dot; incref(p->dot); memmove(p->note, up->note, sizeof(p->note)); p->privatemem = up->privatemem; p->noswap = up->noswap; p->nnote = up->nnote; p->notified = 0; p->lastnote = up->lastnote; p->notify = up->notify; p->ureg = up->ureg; p->dbgreg = 0; /* Abort the child process on error */ if(waserror()){ p->kp = 1; kprocchild(p, abortion, 0); ready(p); nexterror(); } /* Make a new set of memory segments */ n = flag & RFMEM; qlock(&p->seglock); if(waserror()){ qunlock(&p->seglock); nexterror(); } for(i = 0; i < NSEG; i++) if(up->seg[i] != nil) p->seg[i] = dupseg(up->seg, i, n); qunlock(&p->seglock); poperror(); /* File descriptors */ if(flag & (RFFDG|RFCFDG)) { if(flag & RFFDG) p->fgrp = dupfgrp(up->fgrp); else p->fgrp = dupfgrp(nil); } else { p->fgrp = up->fgrp; incref(p->fgrp); } /* Process groups */ if(flag & (RFNAMEG|RFCNAMEG)) { p->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(p->pgrp, up->pgrp); /* inherit noattach */ p->pgrp->noattach = up->pgrp->noattach; } else { p->pgrp = up->pgrp; incref(p->pgrp); } if(flag & RFNOMNT) p->pgrp->noattach = 1; if(flag & RFREND) p->rgrp = newrgrp(); else { incref(up->rgrp); p->rgrp = up->rgrp; } /* Environment group */ if(flag & (RFENVG|RFCENVG)) { p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; if(flag & RFENVG) envcpy(p->egrp, up->egrp); } else { p->egrp = up->egrp; incref(p->egrp); } p->hang = up->hang; p->procmode = up->procmode; if(up->procctl == Proc_tracesyscall) p->procctl = Proc_tracesyscall; poperror(); /* abortion */ /* Craft a return frame which will cause the child to pop out of * the scheduler in user mode with the return register zero */ forkchild(p, up->dbgreg); p->parent = up; if((flag&RFNOWAIT) == 0){ p->parentpid = up->pid; lock(&up->exl); up->nchild++; unlock(&up->exl); } if((flag&RFNOTEG) == 0) p->noteid = up->noteid; pid = p->pid; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; kstrdup(&p->text, up->text); kstrdup(&p->user, up->user); procfork(p); /* * since the bss/data segments are now shareable, * any mmu info about this process is now stale * (i.e. has bad properties) and has to be discarded. */ flushmmu(); p->basepri = up->basepri; p->priority = up->basepri; p->fixedpri = up->fixedpri; p->mp = up->mp; wm = up->wired; if(wm) procwired(p, wm->machno); ready(p); sched(); return pid;} static intshargs(char *s, int n, char **ap){ int i; s += 2; n -= 2; /* skip #! */ for(i=0;; i++){ if(i >= n) return 0; if(s[i]=='\n') break; } s[i] = 0; i = 0; for(;;) { while(*s==' ' || *s=='\t') s++; if(*s == 0) break; ap[i++] = s++; while(*s && *s!=' ' && *s!='\t') s++; if(*s == 0) break; *s++ = 0; } ap[i] = nil; return i;} static ulongl2be(long l){ uchar *cp; cp = (uchar*)&l; return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];} uintptrsysexec(va_list list){ Segment *s, *ts; int i; Chan *tc; char **argv, **argp, **argp0; char *a, *e, *charp, *args, *file, *file0; char *progarg[sizeof(Exec)/2+1], *elem, progelem[64]; ulong magic, ssize, nargs, nbytes, n; uintptr t, d, b, entry, bssend, text, data, bss, tstk, align; int indir; Exec exec; char line[sizeof(Exec)]; Fgrp *f; Image *img; Tos *tos; args = elem = nil; file0 = va_arg(list, char*); validaddr((uintptr)file0, 1, 0); argp0 = va_arg(list, char**); evenaddr((uintptr)argp0); validaddr((uintptr)argp0, 2*BY2WD, 0); if(*argp0 == nil) error(Ebadarg); file0 = validnamedup(file0, 1); if(waserror()){ free(file0); free(elem); free(args); /* Disaster after commit */ if(up->seg[SSEG] == nil) pexit(up->errstr, 1); s = up->seg[ESEG]; if(s != nil){ putseg(s); up->seg[ESEG] = nil; } nexterror(); } align = BY2PG; indir = 0; file = file0; for(;;){ tc = namec(file, Aopen, OEXEC, 0); if(waserror()){ cclose(tc); nexterror(); } if(!indir) kstrdup(&elem, up->genbuf); n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n <= 2) error(Ebadexec); magic = l2be(exec.magic); if(n == sizeof(Exec) && (magic == AOUT_MAGIC)){ entry = l2be(exec.entry); text = l2be(exec.text); if(magic & HDR_MAGIC) text += 8; switch(magic){ case S_MAGIC: /* 2MB segment alignment for amd64 */ align = 0x200000; break; case V_MAGIC: /* 16K segment alignment for mips */ align = 0x4000; break; } if(text >= (USTKTOP-USTKSIZE)-(UTZERO+sizeof(Exec)) || entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text) error(Ebadexec); break; /* for binary */ } /* * Process #! /bin/sh args ... */ memmove(line, &exec, n); if(indir || line[0]!='#' || line[1]!='!') error(Ebadexec); n = shargs(line, n, progarg); if(n < 1) error(Ebadexec); indir = 1; /* * First arg becomes complete file name */ progarg[n++] = file; progarg[n] = nil; argp0++; file = progarg[0]; if(strlen(elem) >= sizeof progelem) error(Ebadexec); strcpy(progelem, elem); progarg[0] = progelem; poperror(); cclose(tc); } data = l2be(exec.data); bss = l2be(exec.bss); align--; t = (UTZERO+sizeof(Exec)+text+align) & ~align; align = BY2PG-1; d = (t + data + align) & ~align; bssend = t + data + bss; b = (bssend + align) & ~align; if(t >= (USTKTOP-USTKSIZE) || d >= (USTKTOP-USTKSIZE) || b >= (USTKTOP-USTKSIZE)) error(Ebadexec); /* * Args: pass 1: count */ nbytes = sizeof(Tos); /* hole for profiling clock at top of stack (and more) */ nargs = 0; if(indir){ argp = progarg; while(*argp != nil){ a = *argp++; nbytes += strlen(a) + 1; nargs++; } } argp = argp0; while(*argp != nil){ a = *argp++; if(((uintptr)argp&(BY2PG-1)) < BY2WD) validaddr((uintptr)argp, BY2WD, 0); validaddr((uintptr)a, 1, 0); e = vmemchr(a, 0, USTKSIZE); if(e == nil) error(Ebadarg); nbytes += (e - a) + 1; if(nbytes >= USTKSIZE) error(Enovmem); nargs++; } ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); /* * 8-byte align SP for those (e.g. sparc) that need it. * execregs() will subtract another 4 bytes for argc. */ if(BY2WD == 4 && (ssize+4) & 7) ssize += 4; if(PGROUND(ssize) >= USTKSIZE) error(Enovmem); /* * Build the stack segment, putting it in kernel virtual for the moment */ qlock(&up->seglock); if(waserror()){ qunlock(&up->seglock); nexterror(); } s = up->seg[SSEG]; do { tstk = s->base; if(tstk <= USTKSIZE) error(Enovmem); } while((s = isoverlap(tstk-USTKSIZE, USTKSIZE)) != nil); up->seg[ESEG] = newseg(SG_STACK, tstk-USTKSIZE, USTKSIZE/BY2PG); /* * Args: pass 2: assemble; the pages will be faulted in */ tos = (Tos*)(tstk - sizeof(Tos)); tos->cyclefreq = m->cyclefreq; tos->kcycles = 0; tos->pcycles = 0; tos->clock = 0; argv = (char**)(tstk - ssize); charp = (char*)(tstk - nbytes); if(indir) argp = progarg; else argp = argp0; for(i=0; i<nargs; i++){ if(indir && *argp==nil) { indir = 0; argp = argp0; } *argv++ = charp + (USTKTOP-tstk); a = *argp++; if(indir) e = strchr(a, 0); else { validaddr((uintptr)a, 1, 0); e = vmemchr(a, 0, (char*)tstk - charp); if(e == nil) error(Ebadarg); } n = (e - a) + 1; memmove(charp, a, n); charp += n; } /* copy args; easiest from new process's stack */ a = (char*)(tstk - nbytes); n = charp - a; if(n > 128) /* don't waste too much space on huge arg lists */ n = 128; args = smalloc(n); memmove(args, a, n); if(n>0 && args[n-1]!='\0'){ /* make sure last arg is NUL-terminated */ /* put NUL at UTF-8 character boundary */ for(i=n-1; i>0; --i) if(fullrune(args+i, n-i)) break; args[i] = 0; n = i+1; } /* * Committed. * Free old memory. * Special segments are maintained across exec */ for(i = SSEG; i <= BSEG; i++) { putseg(up->seg[i]); /* prevent a second free if we have an error */ up->seg[i] = nil; } for(i = ESEG+1; i < NSEG; i++) { s = up->seg[i]; if(s != nil && (s->type&SG_CEXEC) != 0) {Lines 1–500 of 1245. Load more
#include "u.h" #include "tos.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "edf.h" #include <a.out.h> extern void checkpages(void); extern void checkpagerefs(void); uintptr sysr1(va_list) { if(!iseve()) error(Eperm); checkpagerefs(); return 0; } static void abortion(void*) { pexit("fork aborted", 1); } uintptr sysrfork(va_list list) { Proc *p; int n, i; Fgrp *ofg; Pgrp *opg; Rgrp *org; Egrp *oeg; ulong pid, flag; Mach *wm; flag = va_arg(list, ulong); /* Check flags before we commit */ if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) error(Ebadarg); if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) error(Ebadarg); if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) error(Ebadarg); if((flag&RFPROC) == 0) { if(flag & (RFMEM|RFNOWAIT)) error(Ebadarg); if(flag & (RFFDG|RFCFDG)) { ofg = up->fgrp; if(flag & RFFDG) up->fgrp = dupfgrp(ofg); else up->fgrp = dupfgrp(nil); closefgrp(ofg); } if(flag & (RFNAMEG|RFCNAMEG)) { opg = up->pgrp; up->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(up->pgrp, opg); /* inherit noattach */ up->pgrp->noattach = opg->noattach; closepgrp(opg); } if(flag & RFNOMNT) up->pgrp->noattach = 1; if(flag & RFREND) { org = up->rgrp; up->rgrp = newrgrp(); closergrp(org); } if(flag & (RFENVG|RFCENVG)) { oeg = up->egrp; up->egrp = smalloc(sizeof(Egrp)); up->egrp->ref = 1; if(flag & RFENVG) envcpy(up->egrp, oeg); closeegrp(oeg); } if(flag & RFNOTEG) up->noteid = pidalloc(0); return 0; } p = newproc(); p->scallnr = up->scallnr; p->s = up->s; p->nerrlab = 0; p->slash = up->slash; p->dot = up->dot; incref(p->dot); memmove(p->note, up->note, sizeof(p->note)); p->privatemem = up->privatemem; p->noswap = up->noswap; p->nnote = up->nnote; p->notified = 0; p->lastnote = up->lastnote; p->notify = up->notify; p->ureg = up->ureg; p->dbgreg = 0; /* Abort the child process on error */ if(waserror()){ p->kp = 1; kprocchild(p, abortion, 0); ready(p); nexterror(); } /* Make a new set of memory segments */ n = flag & RFMEM; qlock(&p->seglock); if(waserror()){ qunlock(&p->seglock); nexterror(); } for(i = 0; i < NSEG; i++) if(up->seg[i] != nil) p->seg[i] = dupseg(up->seg, i, n); qunlock(&p->seglock); poperror(); /* File descriptors */ if(flag & (RFFDG|RFCFDG)) { if(flag & RFFDG) p->fgrp = dupfgrp(up->fgrp); else p->fgrp = dupfgrp(nil); } else { p->fgrp = up->fgrp; incref(p->fgrp); } /* Process groups */ if(flag & (RFNAMEG|RFCNAMEG)) { p->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(p->pgrp, up->pgrp); /* inherit noattach */ p->pgrp->noattach = up->pgrp->noattach; } else { p->pgrp = up->pgrp; incref(p->pgrp); } if(flag & RFNOMNT) p->pgrp->noattach = 1; if(flag & RFREND) p->rgrp = newrgrp(); else { incref(up->rgrp); p->rgrp = up->rgrp; } /* Environment group */ if(flag & (RFENVG|RFCENVG)) { p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; if(flag & RFENVG) envcpy(p->egrp, up->egrp); } else { p->egrp = up->egrp; incref(p->egrp); } p->hang = up->hang; p->procmode = up->procmode; if(up->procctl == Proc_tracesyscall) p->procctl = Proc_tracesyscall; poperror(); /* abortion */ /* Craft a return frame which will cause the child to pop out of * the scheduler in user mode with the return register zero */ forkchild(p, up->dbgreg); p->parent = up; if((flag&RFNOWAIT) == 0){ p->parentpid = up->pid; lock(&up->exl); up->nchild++; unlock(&up->exl); } if((flag&RFNOTEG) == 0) p->noteid = up->noteid; pid = p->pid; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; kstrdup(&p->text, up->text); kstrdup(&p->user, up->user); procfork(p); /* * since the bss/data segments are now shareable, * any mmu info about this process is now stale * (i.e. has bad properties) and has to be discarded. */ flushmmu(); p->basepri = up->basepri; p->priority = up->basepri; p->fixedpri = up->fixedpri; p->mp = up->mp; wm = up->wired; if(wm) procwired(p, wm->machno); ready(p); sched(); return pid; } static int shargs(char *s, int n, char **ap) { int i; s += 2; n -= 2; /* skip #! */ for(i=0;; i++){ if(i >= n) return 0; if(s[i]=='\n') break; } s[i] = 0; i = 0; for(;;) { while(*s==' ' || *s=='\t') s++; if(*s == 0) break; ap[i++] = s++; while(*s && *s!=' ' && *s!='\t') s++; if(*s == 0) break; *s++ = 0; } ap[i] = nil; return i; } static ulong l2be(long l) { uchar *cp; cp = (uchar*)&l; return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3]; } uintptr sysexec(va_list list) { Segment *s, *ts; int i; Chan *tc; char **argv, **argp, **argp0; char *a, *e, *charp, *args, *file, *file0; char *progarg[sizeof(Exec)/2+1], *elem, progelem[64]; ulong magic, ssize, nargs, nbytes, n; uintptr t, d, b, entry, bssend, text, data, bss, tstk, align; int indir; Exec exec; char line[sizeof(Exec)]; Fgrp *f; Image *img; Tos *tos; args = elem = nil; file0 = va_arg(list, char*); validaddr((uintptr)file0, 1, 0); argp0 = va_arg(list, char**); evenaddr((uintptr)argp0); validaddr((uintptr)argp0, 2*BY2WD, 0); if(*argp0 == nil) error(Ebadarg); file0 = validnamedup(file0, 1); if(waserror()){ free(file0); free(elem); free(args); /* Disaster after commit */ if(up->seg[SSEG] == nil) pexit(up->errstr, 1); s = up->seg[ESEG]; if(s != nil){ putseg(s); up->seg[ESEG] = nil; } nexterror(); } align = BY2PG; indir = 0; file = file0; for(;;){ tc = namec(file, Aopen, OEXEC, 0); if(waserror()){ cclose(tc); nexterror(); } if(!indir) kstrdup(&elem, up->genbuf); n = devtab[tc->type]->read(tc, &exec, sizeof(Exec), 0); if(n <= 2) error(Ebadexec); magic = l2be(exec.magic); if(n == sizeof(Exec) && (magic == AOUT_MAGIC)){ entry = l2be(exec.entry); text = l2be(exec.text); if(magic & HDR_MAGIC) text += 8; switch(magic){ case S_MAGIC: /* 2MB segment alignment for amd64 */ align = 0x200000; break; case V_MAGIC: /* 16K segment alignment for mips */ align = 0x4000; break; } if(text >= (USTKTOP-USTKSIZE)-(UTZERO+sizeof(Exec)) || entry < UTZERO+sizeof(Exec) || entry >= UTZERO+sizeof(Exec)+text) error(Ebadexec); break; /* for binary */ } /* * Process #! /bin/sh args ... */ memmove(line, &exec, n); if(indir || line[0]!='#' || line[1]!='!') error(Ebadexec); n = shargs(line, n, progarg); if(n < 1) error(Ebadexec); indir = 1; /* * First arg becomes complete file name */ progarg[n++] = file; progarg[n] = nil; argp0++; file = progarg[0]; if(strlen(elem) >= sizeof progelem) error(Ebadexec); strcpy(progelem, elem); progarg[0] = progelem; poperror(); cclose(tc); } data = l2be(exec.data); bss = l2be(exec.bss); align--; t = (UTZERO+sizeof(Exec)+text+align) & ~align; align = BY2PG-1; d = (t + data + align) & ~align; bssend = t + data + bss; b = (bssend + align) & ~align; if(t >= (USTKTOP-USTKSIZE) || d >= (USTKTOP-USTKSIZE) || b >= (USTKTOP-USTKSIZE)) error(Ebadexec); /* * Args: pass 1: count */ nbytes = sizeof(Tos); /* hole for profiling clock at top of stack (and more) */ nargs = 0; if(indir){ argp = progarg; while(*argp != nil){ a = *argp++; nbytes += strlen(a) + 1; nargs++; } } argp = argp0; while(*argp != nil){ a = *argp++; if(((uintptr)argp&(BY2PG-1)) < BY2WD) validaddr((uintptr)argp, BY2WD, 0); validaddr((uintptr)a, 1, 0); e = vmemchr(a, 0, USTKSIZE); if(e == nil) error(Ebadarg); nbytes += (e - a) + 1; if(nbytes >= USTKSIZE) error(Enovmem); nargs++; } ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1)); /* * 8-byte align SP for those (e.g. sparc) that need it. * execregs() will subtract another 4 bytes for argc. */ if(BY2WD == 4 && (ssize+4) & 7) ssize += 4; if(PGROUND(ssize) >= USTKSIZE) error(Enovmem); /* * Build the stack segment, putting it in kernel virtual for the moment */ qlock(&up->seglock); if(waserror()){ qunlock(&up->seglock); nexterror(); } s = up->seg[SSEG]; do { tstk = s->base; if(tstk <= USTKSIZE) error(Enovmem); } while((s = isoverlap(tstk-USTKSIZE, USTKSIZE)) != nil); up->seg[ESEG] = newseg(SG_STACK, tstk-USTKSIZE, USTKSIZE/BY2PG); /* * Args: pass 2: assemble; the pages will be faulted in */ tos = (Tos*)(tstk - sizeof(Tos)); tos->cyclefreq = m->cyclefreq; tos->kcycles = 0; tos->pcycles = 0; tos->clock = 0; argv = (char**)(tstk - ssize); charp = (char*)(tstk - nbytes); if(indir) argp = progarg; else argp = argp0; for(i=0; i<nargs; i++){ if(indir && *argp==nil) { indir = 0; argp = argp0; } *argv++ = charp + (USTKTOP-tstk); a = *argp++; if(indir) e = strchr(a, 0); else { validaddr((uintptr)a, 1, 0); e = vmemchr(a, 0, (char*)tstk - charp); if(e == nil) error(Ebadarg); } n = (e - a) + 1; memmove(charp, a, n); charp += n; } /* copy args; easiest from new process's stack */ a = (char*)(tstk - nbytes); n = charp - a; if(n > 128) /* don't waste too much space on huge arg lists */ n = 128; args = smalloc(n); memmove(args, a, n); if(n>0 && args[n-1]!='\0'){ /* make sure last arg is NUL-terminated */ /* put NUL at UTF-8 character boundary */ for(i=n-1; i>0; --i) if(fullrune(args+i, n-i)) break; args[i] = 0; n = i+1; } /* * Committed. * Free old memory. * Special segments are maintained across exec */ for(i = SSEG; i <= BSEG; i++) { putseg(up->seg[i]); /* prevent a second free if we have an error */ up->seg[i] = nil; } for(i = ESEG+1; i < NSEG; i++) { s = up->seg[i]; if(s != nil && (s->type&SG_CEXEC) != 0) {