ref: 8d93ccdbb2a2dee8d2eb1387da1b316fdf84b208
dir: /kern/sysproc.c/
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "user.h"
#include "mem.h"
#include "sys.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 u32int
arg(int n)
{
/* no locking necessary, since we're on the stack */
return *(u32int*) vaddrnol(up->R[13] + 4 + 4 * n, 4);
}
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*
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
/* Load text and data segments into memory */
/* the following code is not for the weak of heart */
void
donote(char *msg, ulong type)
{
int rc;
u32int *ureg, *sp, uregp, msgp;
char *msgb;
print("In donote\n");
if(up->notehandler == 0)
exits(msg);
clrex();
uregp = up->R[13] - 18 * 4;
ureg = vaddrnol(uregp, 18 * 4);
memcpy(ureg, up->R, 15 * 4);
ureg[15] = type;
ureg[16] = up->CPSR;
ureg[17] = up->R[15];
up->R[13] = uregp;
msgp = up->R[13] -= ERRMAX;
msgb = vaddrnol(msgp, ERRMAX);
strncpy(msgb, msg, ERRMAX);
up->R[13] -= 3 * 4;
sp = vaddrnol(up->R[13], 3 * 4);
sp[0] = 0;
sp[2] = msgp;
up->R[0] = uregp;
up->R[15] = up->notehandler;
up->innote = 1;
switch(rc = setjmp(up->notejmp) - 1) {
case -1:
for(;;) {
step();
}
case NDFLT:
exits(msg);
case NCONT:
break;
default:
sysfatal("unhandled noted argument %d", rc);
}
up->innote = 0;
ureg = vaddrnol(uregp, 18 * 4); /* just to be sure */
memcpy(up->R, ureg, 15 * 4);
up->CPSR = ureg[16];
up->R[15] = ureg[17];
}
static void
initstack(int argc, char **argv)
{
ulong tos, sp, ap, size, i, len;
tos = USTKTOP - sizeof(Tos) * 2;
sp = tos;
size = 8;
for(i = 0; i < argc; i++)
size += strlen(argv[i]) + 5;
sp -= size;
sp &= ~7;
up->R[0] = tos;
up->R[1] = USTKTOP - 4;
up->R[13] = sp;
*(ulong *) vaddrnol(sp, 4) = argc;
sp += 4;
ap = sp + (argc + 1) * 4;
for(i = 0; i < argc; i++) {
*(ulong *) vaddrnol(sp, 4) = ap;
sp += 4;
len = strlen(argv[i]) + 1;
memcpy(vaddrnol(ap, len), argv[i], len);
ap += len;
}
*(ulong *) vaddrnol(sp, 4) = 0;
inittos();
}
void
inittos(void)
{
ulong tos;
tos = USTKTOP - sizeof(Tos) * 2;
((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
}
// TODO: fd has to go away here.
static int
loadscript(int fd, char *file, int argc, char **argv)
{
char buf[513], *p, **q, **nargv;
int rc, nargc, i;
seek(fd, 0, 0);
rc = readn(fd, buf, 512);
if(rc <= 0)
goto invalid;
close(fd);
buf[rc] = 0;
p = strchr(buf, '\n');
if(p == nil)
goto invalid;
*p = 0;
while(isspace(*--p))
*p = 0;
nargc = 0;
p = buf + 2;
while(*p) {
while(*p && isspace(*p))
p++;
nargc++;
while(*p && !isspace(*p))
p++;
}
if(nargc == 0)
goto invalid;
nargv = emallocz(sizeof(char *) * (nargc + argc));
q = nargv;
p = buf + 2;
while(*p) {
while(*p && isspace(*p))
p++;
*(p-1) = 0;
*q++ = p;
while(*p && !isspace(*p))
p++;
}
*q++ = file;
for(i = 1; i < argc; i++)
*q++ = argv[i];
rc = loadtext(*nargv, argc + nargc, nargv);
free(nargv);
return rc;
invalid:
werrstr("exec header invalid");
return -1;
}
int
loadtext(char *file, int argc, char **argv)
{
Segment *text, *data, *bss;
char buf[2];
Chan *tc;
int n;
union {
struct {
Exec ex;
uvlong hdr[1];
} ehdr;
char buf[256];
} u;
tc = namec(file, Aopen, OEXEC, 0);
n = devtab[tc->type]->read(tc, u.buf, sizeof(u.buf), 0);
copyname(file);
up->notehandler = up->innote = up->notein = up->noteout = 0;
freesegs();
memset(up->R, 0, sizeof(up->R));
up->CPSR = 0;
// Read instead with beswav(whatever)
//text = newseg(fp.txtaddr - fp.hdrsz, fp.txtsz + fp.hdrsz, SEGTEXT);
//data = newseg(fp.dataddr, fp.datsz, SEGDATA);
//bss = newseg(fp.dataddr + fp.datsz, fp.bsssz, SEGBSS);
//newseg(USTKTOP - STACKSIZE, STACKSIZE, SEGSTACK);
// This also doesn't work, we want to read in the devtab way
//seek(fd, fp.txtoff - fp.hdrsz, 0);
//if(readn(fd, text->data, fp.txtsz + fp.hdrsz) < fp.txtsz + fp.hdrsz)
// sysfatal("%r");
//seek(fd, fp.datoff, 0);
//if(readn(fd, data->data, fp.datsz) < fp.datsz)
// sysfatal("%r");
//memset(bss->data, 0, bss->size);
//up->R[15] = fp.entry;
//if(havesymbols && syminit(fd, &fp) < 0)
// fprint(2, "initializing symbol table: %r\n");
//close(fd);
fdclear(up->fd);
initstack(argc, argv);
resetfpa();
return 0;
}