ref: eff99e9be0f63c0cc54146e21af5bd423238c226
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;
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)
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;
}
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);
}
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;
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 & ~7) - sizeof(Tos) * 2;
((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
}
static int
loadscript(Chan *tc, char *file, int argc, char **argv)
{
char buf[513], *p, **q, **nargv;
int rc, nargc, i;
rc = devtab[tc->type]->read(tc, &buf, 512, 0);
if(rc <= 0)
goto invalid;
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 = mallocz(sizeof(char *) * (nargc + argc), 1);
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)
{
Chan *tc;
Segment *text, *data, *bss;
Exec hdr;
char buf[2];
vlong off;
int n;
/* Open the file using namespaced access */
tc = namec(file, Aopen, OEXEC, 0);
if(tc == nil) {
print("cannot open %s: %r", file);
return -1;
}
/* Peek the first two bytes */
devtab[tc->type]->read(tc, &buf, 2, 0);
if(buf[0] =='#' && buf[1] == '!') {
return loadscript(tc, file, argc, argv);
}
n = devtab[tc->type]->read(tc, &hdr, sizeof(Exec), 0);
if(n != sizeof(Exec)) {
print("short read on exec header");
cclose(tc);
return -1;
}
if(beswal(hdr.magic) != E_MAGIC) {
print("bad magic number in exec header: got 0x%lux, want 0x%lux", beswal(hdr.magic), E_MAGIC);
cclose(tc);
return -1;
}
freesegs();
up->CPSR = 0;
/* Create segments: text, data, bss, stack */
text = newseg(beswal(hdr.entry), beswal(hdr.text) + sizeof(Exec), SEGTEXT);
data = newseg(beswal(hdr.entry) + beswal(hdr.text) + sizeof(Exec), beswal(hdr.data), SEGDATA);
bss = newseg(beswal(hdr.entry) + beswal(hdr.text) + sizeof(Exec) + beswal(hdr.data), beswal(hdr.bss), SEGBSS);
newseg((USTKTOP & ~7) - USTKSIZE, USTKSIZE, SEGSTACK);
/* Read text segment (including header) */
off = sizeof(Exec);
n = devtab[tc->type]->read(tc, text->data, beswal(hdr.text) + sizeof(Exec), off);
if(n != beswal(hdr.text) + sizeof(Exec)) {
freesegs();
werrstr("short read on text segment: got %d, want %lud", n, beswal(hdr.text) + sizeof(Exec));
cclose(tc);
return -1;
}
/* Read data segment */
off += beswal(hdr.text);
n = devtab[tc->type]->read(tc, data->data, beswal(hdr.data), off);
if(n != beswal(hdr.data)) {
freesegs();
werrstr("short read on data segment: got %d, want %lud", n, beswal(hdr.data));
cclose(tc);
return -1;
}
memset(bss->data, 0, bss->size);
up->R[15] = beswal(hdr.entry);
initstack(argc, argv);
//if(debug)
print("loadtext: PC=%.8ux, R1=%.8ux, R13=%.8ux\n", up->R[15], up->R[1], up->R[13]);
/* Close the channel */
cclose(tc);
resetvfp();
return 0;
}