ref: b0a436ba688da0ecc7c224ecfdf94287a01b1107
dir: /kern/sysproc.c/
#include "u.h"
#include <signal.h>
#include "lib.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "proc.h"
#include "user.h"
#include "sys.h"
#include <a.out.h>
#include <sys/mman.h>
#include <setjmp.h>
jmp_buf exec_jmp;
#define pgsize 0x1000
/* Use sizes from arm32 */
#define USTKTOP 0x3FFFFFFFULL
#define USTKSIZE 0x100000
void
devmask(Pgrp *pgrp, int invert, char *devs)
{
int t, w;
char *p;
Rune r;
u64int mask[nelem(pgrp->notallowed)];
if(invert)
memset(mask, 0xFF, sizeof mask);
else
memset(mask, 0, sizeof mask);
w = sizeof mask[0] * 8;
for(p = devs; *p != '\0';){
p += chartorune(&r, p);
t = devno(r);
if(t == -1)
continue;
if(invert)
mask[t/w] &= ~(1<<t%w);
else
mask[t/w] |= 1<<t%w;
}
}
static void
copyname(char *file)
{
char *p;
p = strrchr(file, '/');
if(p == nil)
p = file;
else
p++;
strncpy(up->name, p, NAMEMAX);
if(up->path != nil && decref(up->path) == 0)
free(up->path);
up->path = malloc(sizeof(Ref) + strlen(file)+1);
memset(up->path, 0, sizeof(Ref) + strlen(file)+1);
incref(up->path);
strcpy((char*)(up->path + 1), file);
}
static uvlong
_round(uvlong a, ulong b)
{
uvlong w;
w = (a/b)*b;
if (a!=w)
w += b;
return(w);
}
Fd *
newfid(void)
{
Fd *fd;
fd = mallocz(sizeof(*fd), 1);
incref(&fd->ref);
return fd;
}
Fd *
copyfd(Fd *old)
{
Fd *new;
rlock(&old->rw);
new = newfid();
if(old->nfds > 0) {
new->nfds = old->nfds;
new->fds = mallocz(old->nfds, 1);
memcpy(new->fds, old->fds, old->nfds);
}
runlock(&old->rw);
return new;
}
void
fddecref(Fd *fd)
{
if(decref(&fd->ref) == 0) {
free(fd->fds);
free(fd);
}
}
int
iscexec(Fd *fd, int n)
{
int r;
r = 0;
rlock(&fd->rw);
if(n / 8 < fd->nfds)
r = (fd->fds[n / 8] & (1 << (n % 8))) != 0;
runlock(&fd->rw);
return r;
}
void
setcexec(Fd *fd, int n, int status)
{
int old;
wlock(&fd->rw);
if(n / 8 >= fd->nfds) {
if(status == 0) {
wunlock(&fd->rw);
return;
}
old = fd->nfds;
fd->nfds = (n / 8) + 1;
fd->fds = realloc(fd->fds, fd->nfds);
memset(fd->fds + old, 0, fd->nfds - old);
}
if(status == 0)
fd->fds[n / 8] &= ~(1 << (n % 8));
else
fd->fds[n / 8] |= (1 << (n % 8));
wunlock(&fd->rw);
}
int
procfdprint(Chan *c, int fd, char *s, int ns)
{
return snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %lud %.2ux) %5ld %8lld %s\n",
fd,
&"r w rw"[(c->mode&3)<<1],
devtab[c->type]->dc, c->dev,
c->qid.path, c->qid.vers, c->qid.type,
8102, c->offset, c->path->s);
}
void
fdclear(Fd *fd)
{
int i, j, k;
wlock(&fd->rw);
if(fd->nfds == 0) {
wunlock(&fd->rw);
return;
}
for(i = 0; i < fd->nfds; i++) {
j = fd->fds[i];
for(k = 0; k < 8; k++)
if(j & (1<<k))
close(8 * i + k);
}
free(fd->fds);
fd->nfds = 0;
fd->fds = nil;
wunlock(&fd->rw);
}
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 *vs, int c, ulong n)
{
jmp_buf env;
volatile int ok;
if (vs == NULL)
return NULL;
ok = setjmp(env);
if (ok == 0) {
const unsigned char *s = vs;
const unsigned char *end = s + n;
while (s < end) {
if (*s == (unsigned char)c)
return (void *)(uintptr_t)s;
s++;
}
}
/* fault → ok != 0 */
return NULL;
}
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(;;) {
#ifdef DREGS
dump();
#endif
step();
}
case NDFLT:
exits(msg);
case NCONT:
break;
default:
panic("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;
((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
sp = tos;
#ifdef DTRACE
print("initstack: tos=%.8ux tossz=%.8ux USTKTOP=%.8ux\n", tos, sizeof(Tos), USTKTOP);
#endif
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;
#ifdef DTRACE
print("initstack: argc=%d sp=%.8ux ap=%.8ux\n", argc, sp, ap);
#endif
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;
}
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, *stack;
uvlong txtaddr, txtsz, dataddr, datsz, datoff, bsssz, hdrsz;
Exec hdr;
char buf[2];
int fd;
fd = open(file, OREAD);
if(fd < 0) return -1;
up->arg = strdup(file);
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);
hdrsz = sizeof(Exec);
txtaddr = pgsize + hdrsz;
txtsz = beswal(hdr.text);
dataddr = _round(pgsize+txtsz+hdrsz, pgsize);
datsz = beswal(hdr.data);
datoff = txtsz + hdrsz;
bsssz = beswal(hdr.bss);
copyname(file);
// TODO: Notes.
up->notehandler = up->innote = up->notein = up->noteout = 0;
freesegs();
memset(up->R, 0, sizeof(up->R));
up->CPSR = 0;
text = newseg(txtaddr - hdrsz, txtsz + hdrsz, TSEG);
data = newseg(dataddr, datsz, DSEG);
bss = newseg(dataddr + datsz, bsssz, BSEG);
stack = newseg((USTKTOP & ~7) - USTKSIZE, USTKSIZE, ESEG);
seek(fd, 0, 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");
up->seg[TSEG] = text;
up->seg[DSEG] = data;
up->seg[BSEG] = bss;
up->seg[ESEG] = stack;
memset(bss->data, 0, bss->size);
up->R[15] = beswal(hdr.entry);
close(fd);
fdclear(up->fd);
initstack(argc, argv);
#ifdef DTRACE
print("loadtext: PC=%.8ux, R1=%.8ux, R13=%.8ux\n", up->R[15], up->R[1], up->R[13]);
#endif
resetvfp();
return 0;
}
void
procrun(void *v)
{
USED(v);
for(;;) {
#ifdef DREGS
dump();
#endif
step();
while((up->notein - up->noteout) % NNOTE) {
donote(up->notes[up->noteout % NNOTE], 0);
up->noteout++;
}
}
}
int
sysrfork(int flag)
{
Proc *p;
Fgrp *ofg;
Pgrp *opg;
Rgrp *org;
Egrp *oeg;
char *devs = nil;
int i, n;
/* 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);
closepgrp(opg);
}
if(flag & RFNOMNT)
devmask(up->pgrp, 1, devs);
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.ref = 1;
if(flag & RFENVG)
envcpy(up->egrp, oeg);
closeegrp(oeg);
}
if(flag & RFNOTEG){
qlock(&up->debug);
// TODO: Notegroups
//setnoteid(up, 0); /* can't error() with 0 argument */
qunlock(&up->debug);
}
return 0;
}
p = newproc();
qlock(&up->debug);
qlock(&p->debug);
p->slash = cclone(up->slash);
p->dot = cclone(up->dot);
strecpy(p->text, p->text+sizeof p->text, up->text);
p->kp = 0;
/* TODO: Notes */
//p->nnote = 0;
//p->notify = up->notify;
//p->notified = 0;
//p->notepending = 0;
//p->lastnote = nil;
//if((flag & RFNOTEG) == 0)
// p->noteid = up->noteid;
/* Copy regs over */
for(i = 1; i <= 15; i++)
p->R[i] = up->R[i];
p->R[0] = 0;
p->CPSR = up->CPSR;
p->FPSR = up->FPSR;
//strcpy(&p->args, "");
//p->nargs = 0;
//p->setargs = 0;
qunlock(&p->debug);
qunlock(&up->debug);
if(waserror()){
p->kp = 1;
nexterror();
}
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();
if(flag & (RFFDG|RFCFDG)) {
if(flag & RFFDG)
p->fgrp = dupfgrp(up->fgrp);
else
p->fgrp = dupfgrp(nil);
}
else {
p->fgrp = up->fgrp;
incref(&up->fgrp->ref);
}
/* Process groups */
if(flag & (RFNAMEG|RFCNAMEG)) {
p->pgrp = newpgrp();
if(flag & RFNAMEG)
pgrpcpy(p->pgrp, up->pgrp);
/* inherit notallowed */
memmove(p->pgrp->notallowed, up->pgrp->notallowed, sizeof p->pgrp->notallowed);
} else {
p->pgrp = up->pgrp;
incref(&p->pgrp->ref);
}
if(flag & RFNOMNT)
devmask(p->pgrp, 1, devs);
if(flag & RFREND)
p->rgrp = newrgrp();
else {
incref(&up->rgrp->ref);
p->rgrp = up->rgrp;
}
/* Environment group */
if(flag & (RFENVG|RFCENVG)) {
p->egrp = smalloc(sizeof(Egrp));
p->egrp->ref.ref = 1;
if(flag & RFENVG)
envcpy(p->egrp, up->egrp);
} else {
p->egrp = up->egrp;
incref(&p->egrp->ref);
}
p->fn = procrun;
p->parent = up;
p->arg = 0;
poperror();
if((flag&RFNOWAIT) == 0){
// TODO: Actually use parent + ppid
lock(&up->exl);
up->nchild++;
unlock(&up->exl);
}
osproc(p);
up->child = p;
return p->pid;
}