ref: dd193a6e22c0911760aa56bbf0df06b4b75772ca
dir: /kern/sysproc.c/
#include "u.h"
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "proc.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
#undef read
jmp_buf exec_jmp;
#define pgsize 0x1000
static void
nop(int x)
{
USED(x);
}
static u32int
arg(int n)
{
USED(n);
/* no locking necessary, since we're on the stack */
return *(u32int*) vaddrnol(up->R[13] + 4 + 4 * n, 4);
}
static uvlong
_round(uvlong a, ulong b)
{
uvlong w;
w = (a/b)*b;
if (a!=w)
w += b;
return(w);
}
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)
print("%d\n", pid);
else
print("x %r\n");
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;
}
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);
}
void
addnote(char *msg)
{
int new;
new = up->notein + 1;
if((new - up->noteout) % NNOTE == 0)
return;
strncpy(up->notes[up->notein % NNOTE], msg, ERRMAX - 1);
up->notein = new;
}
void
donote(char *msg, ulong type)
{
int rc;
u32int *ureg, *sp, uregp, msgp;
char *msgb;
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 & ~7) - sizeof(Tos) * 2;
sp = tos;
if(debug)
print("initstack: tos=%.8ux tossz=%.8ux USTKTOP=%.8ux\n", tos, sizeof(Tos), USTKTOP);
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;
if(debug)
print("initstack: argc=%d sp=%.8ux ap=%.8ux\n", argc, sp, ap);
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 & ~7) - sizeof(Tos) * 2;
((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
}
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 = malloc(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;
uvlong txtaddr, txtsz, txtoff, dataddr, datsz, datoff, bsssz, hdrsz;
Exec hdr;
char buf[2];
int fd;
fd = open(file, OREAD);
if(fd < 0) return -1;
if(pread(fd, buf, 2, 0) == 2 && buf[0] == '#' && buf[1] == '!')
return loadscript(fd, file, argc, argv);
seek(fd, 0, 0);
if(pread(fd, &hdr, sizeof(Exec), 0) != sizeof(Exec))
panic("Short read on header\n");
if(beswal(hdr.magic) != E_MAGIC)
panic("bad magic number in exec header: got 0x%lux, want 0x%lux", beswal(hdr.magic), E_MAGIC);
freesegs();
up->CPSR = 0;
hdrsz = sizeof(Exec);
txtaddr = pgsize + hdrsz;
txtsz = beswal(hdr.text);
txtoff = sizeof(Exec);
dataddr = _round(pgsize+txtsz+hdrsz, pgsize);
datsz = beswal(hdr.data);
datoff = txtsz + hdrsz;
bsssz = beswal(hdr.bss);
/* Create segments: text, data, bss, stack */
text = newseg(txtaddr - hdrsz, txtsz + hdrsz, SEGTEXT);
data = newseg(dataddr, datsz, SEGDATA);
bss = newseg(dataddr + datsz, bsssz, SEGBSS);
newseg((USTKTOP & ~7) - USTKSIZE, USTKSIZE, SEGSTACK);
seek(fd, txtoff - hdrsz, 0);
if(readn(fd, text->data, txtsz + hdrsz) < txtsz + hdrsz)
panic("%r");
seek(fd, datoff, 0);
if(readn(fd, data->data, datsz) < datsz)
panic("%r");
memset(bss->data, 0, bss->size);
up->R[15] = beswal(hdr.entry);
close(fd);
initstack(argc, argv);
if(debug)
print("loadtext: PC=%.8ux, R1=%.8ux, R13=%.8ux\n", up->R[15], up->R[1], up->R[13]);
resetvfp();
return 0;
}