shithub: drawcpu

ref: fed44bd6dee3c21a0b5ac0c11c13b4271e20f6f3
dir: /kern/sysproc.c/

View raw version
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "user.h"
#include "mem.h"
#include <a.out.h>
#include <signal.h>
#include <sys/mman.h>
#include <setjmp.h>

#undef rfork

jmp_buf exec_jmp;

static void
nop(int x)
{
    USED(x);
}

static void
sigsegv(int sig)
{
    print("Segfault: %d: %r\n", sig);
    longjmp(exec_jmp, 2);
}

static void
sigquit(int sig)
{
    print("Sigquittin': %r\n");
    longjmp(exec_jmp, 1);
}

static void
sigbus(int sig)
{
    print("Bussin': %r\n");
    longjmp(exec_jmp, 2);
}

static void
sigsys(int sig)
{
    print("We here!!! sig %d\n", sig);
}

int
sysrfork(int flags)
{
    int pid, status;
    int p[2];
    int n;
    char buf[128], *q;
    extern char **environ;
    struct sigaction oldchld;

    memset(&oldchld, 0, sizeof oldchld);

    if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
        flags &= ~(RFPROC|RFFDG|RFENVG);
        n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
        if(n){
            werrstr("unknown flags %08ux in rfork", n);
            return -1;
        }
        if(flags&RFNOWAIT){
            sigaction(SIGCHLD, nil, &oldchld);
            signal(SIGCHLD, nop);
            if(pipe(p) < 0)
                return -1;
        }
        pid = fork();
        if(pid == -1)
            return -1;
        if(flags&RFNOWAIT){
            flags &= ~RFNOWAIT;
            if(pid){
                close(p[1]);
                status = 0;
                if(wait4(pid, &status, 0, 0) < 0){
                    werrstr("pipe dance - wait4 - %r");
                    close(p[0]);
                    return -1;
                }
                n = readn(p[0], buf, sizeof buf-1);
                close(p[0]);
                if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
                    if(!WIFEXITED(status))
                        werrstr("pipe dance - !exited 0x%ux", status);
                    else if(WEXITSTATUS(status) != 0)
                        werrstr("pipe dance - non-zero status 0x%ux", status);
                    else if(n < 0)
                        werrstr("pipe dance - pipe read error - %r");
                    else if(n == 0)
                        werrstr("pipe dance - pipe read eof");
                    else
                        werrstr("pipe dance - unknown failure");
                    return -1;
                }
                buf[n] = 0;
                if(buf[0] == 'x'){
                    werrstr("%s", buf+2);
                    return -1;
                }
                pid = strtol(buf, &q, 0);
            }else{
                signal(SIGCHLD, SIG_IGN);
                close(p[0]);
                pid = fork();
                if(pid){
                    if(pid > 0)
                        fprint(p[1], "%d", pid);
                    else
                        fprint(p[1], "x %r");
                    close(p[1]);
                    _exit(0);
                }else{
                    close(p[1]);
                }
            }
            sigaction(SIGCHLD, &oldchld, nil);
        }
        if(pid != 0)
            return pid;
        if(flags&RFCENVG)
            if(environ)
                *environ = nil;
    }
    if(flags&RFPROC){
        werrstr("cannot use rfork for shared memory -- use libthread");
        return -1;
    }
    if(flags&RFNAMEG){
        flags &= ~RFNAMEG;
    }
    if(flags&RFNOTEG){
        setpgid(0, getpid());
        flags &= ~RFNOTEG;
    }
    if(flags&RFNOWAIT){
        werrstr("cannot use RFNOWAIT without RFPROC");
        return -1;
    }
    if(flags){
        werrstr("unknown flags %08ux in rfork", flags);
        return -1;
    }
    return 0;
}

static int
shargs(char *s, int n, char **ap, int nap)
{
    char *p;
    int i;

    if(n <= 2 || s[0] != '#' || s[1] != '!')
        return -1;
    s += 2;
    n -= 2;
    if((p = memchr(s, '\n', n)) == nil)
        return 0;
    *p = 0;
    i = tokenize(s, ap, nap-1);
    ap[i] = nil;
    return i;
}

ulong
beswal(ulong l)
{
    uchar *p;
    p = (uchar*)&l;
    return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}

uvlong
beswav(uvlong v)
{
    uchar *p;
    p = (uchar*)&v;
    return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
           | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
           | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
           | (uvlong)p[7];
}

void
evenaddr(uintptr addr)
{
    if(addr & 3){
        postnote(up, 1, "sys: odd address", NDebug);
        error(Ebadarg);
    }
}

void*
vmemchr(void *s, int c, ulong n)
{
    uintptr a;
    ulong m, i;
    void *t;

    i = n;
    a = (uintptr)s;
    for(;;){
        m = BY2PG - (a & (BY2PG-1));
        if(i <= m)
            break;
        t = memchr((void*)a, c, m);
        if(t != nil)
            return t;
        a += m;
        i -= m;
        if(a < KZERO)
            validaddr(a, 1, 0);
    }
    return memchr((void*)a, c, i);
}

#undef read
int
sysexec(int argc, char **argv)
{
    union {
        struct {
            Exec ex;
            uvlong hdr[1];
        } ehdr;
        char buf[256];
    } u;
    void (*_main)(int, char*[]);
    char line[256];
    char *progarg[32+1];
    char *file, *elem;
    void *base;
    Chan *tc;
    ulong magic;
    uintptr t, b, entry, text, data, bss, align;
    int n, indir;

    elem = nil;
    align = BY2PG-1;
    indir = 0;
    file = argv[0];

    for(;;){
        tc = namec(file, Aopen, OEXEC, 0);
        if(waserror()){
            cclose(tc);
            nexterror();
        }
        if(!indir)
            kstrdup(&elem, up->genbuf);
        n = devtab[tc->type]->read(tc, u.buf, sizeof(u.buf), 0);
        if (n >= sizeof(Exec)){
            magic = beswal(u.ehdr.ex.magic);
            if(magic & AOUT_MAGIC) {
				if(magic & HDR_MAGIC){
                    if(n < sizeof(u.ehdr))
                        error(Ebadexec);
                    entry = beswav(u.ehdr.hdr[0]);
                    text = UTZERO+sizeof(u.ehdr);
                } else {
                    entry = beswal(u.ehdr.ex.entry);
                    text = UTZERO+sizeof(u.ehdr);
                }
                if(entry < text)
                    error(Ebadexec);
                text += beswal(u.ehdr.ex.text);
                if(text <= entry || text >= (USTKTOP-USTKSIZE))
					error(Ebadexec);
                switch(magic){
                case S_MAGIC:
                    align = 0x1fffff;
                    break;
                case P_MAGIC:
                case V_MAGIC:
                    align = 0x3fff;
                    break;
                case R_MAGIC:
                    align = 0xffff;
                    break;
                }
                break;
            }
        }
        if(indir++)
            error(Ebadexec);

        memmove(line, u.buf, sizeof(u.buf));
        n = shargs(line, n, progarg, nelem(progarg));
        if(n < 1)
            error(Ebadexec);
        progarg[n++] = file;
        progarg[n] = nil;
        file = progarg[0];
        progarg[0] = elem;
        poperror();
        cclose(tc);
    }

    text -= UTZERO;
    entry -= UTZERO;
	data = beswal(u.ehdr.ex.data);
	bss = beswal(u.ehdr.ex.bss);

    /* Set up text, data, and bss. OS dependent. */
    base = osbuildmem(tc, text, data, bss, sizeof(u.ehdr), align);
    b = ((uintptr)base + align) & ~align;

    /* Handle alignment, BSS setup, and memory protection. OS dependent. */
    osprepmem(base, b, text, data, bss);

    poperror();
    cclose(tc);

    /* Meaningful signals to us */
    signal(SIGSEGV, sigsegv);
    signal(SIGQUIT, sigquit);
    signal(SIGINT, sigquit);
    signal(SIGSYS, sigsys);
    signal(SIGBUS, sigbus);

    switch(setjmp(exec_jmp)) {
    case 0:
        print("Base %p, Aligned base %p, Entry offset %lx, Text %lx\n", base, (void*)b, entry, text);

        _main = (void (*)(int, char*[]))(b+entry);
        _main(argc, argv);

        longjmp(exec_jmp, 1);
        break;
    case 1:
        osclrmem((uintptr)b, text+data+bss);
        break;
    case 2:
        //error("Signal: %r");
        return -1;
    }

    return 0;
}