#include <9pm/u.h>
#include <9pm/libc.h>
#include "dat.h"
#include "fns.h"
int shargs(char*, int, char**);
long
sysr1(ulong *arg)
{
return 0;
}
long
sysrfork(ulong *arg)
{
Proc *p;
Fgrp *ofg;
Pgrp *opg;
Rgrp *org;
Egrp *oeg;
ulong pid, flag;
flag = arg[0];
/* 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);
/* inherit noattach */
up->pgrp->noattach = opg->noattach;
closepgrp(opg);
}
if(flag & RFNOMNT)
up->pgrp->noattach = 1;
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)
up->noteid = incref(¬eidalloc);
return 0;
}
p = newproc();
p->nerrlab = 0;
p->slash = up->slash;
p->dot = up->dot;
incref(&p->dot->ref);
memmove(p->note, up->note, sizeof(p->note));
p->privatemem = up->privatemem;
p->nnote = up->nnote;
p->notified = 0;
p->lastnote = up->lastnote;
p->notify = up->notify;
p->ureg = up->ureg;
p->dbgreg = 0;
memset(&p->sleep, 0, sizeof p->sleep);
/* File descriptors */
if(flag & (RFFDG|RFCFDG)) {
if(flag & RFFDG)
p->fgrp = dupfgrp(up->fgrp);
else
p->fgrp = dupfgrp(nil);
}
else {
p->fgrp = up->fgrp;
incref(&p->fgrp->ref);
}
/* Process groups */
if(flag & (RFNAMEG|RFCNAMEG)) {
p->pgrp = newpgrp();
if(flag & RFNAMEG)
pgrpcpy(p->pgrp, up->pgrp);
/* inherit noattach */
p->pgrp->noattach = up->pgrp->noattach;
}
else {
p->pgrp = up->pgrp;
incref(&p->pgrp->ref);
}
if(flag & RFNOMNT)
up->pgrp->noattach = 1;
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->hang = up->hang;
p->procmode = up->procmode;
/* Craft a return frame which will cause the child to pop out of
* the scheduler in user mode with the return register zero
forkchild(p, up->dbgreg);
*/
p->parent = up;
p->parentpid = up->pid;
if(flag&RFNOWAIT)
p->parentpid = 0;
else {
lock(&up->exl);
up->nchild++;
unlock(&up->exl);
}
if((flag&RFNOTEG) == 0)
p->noteid = up->noteid;
p->fpstate = up->fpstate;
pid = p->pid;
memset(p->time, 0, sizeof(p->time));
p->time[TReal] = machp0->ticks;
kstrdup(&p->text, up->text);
kstrdup(&p->user, up->user);
p->priority = up->priority;
p->basepri = up->basepri;
p->fixedpri = up->fixedpri;
p->state = Nascent;
/*
ready(p);
sched();
*/
return pid;
}
static long
readn(Chan *c, char *buf, int nbuf)
{
int m, n;
m = 0;
while(m < nbuf){
n = devtab[cc->type]->read(c, buf+m, nbuf-m, m);
if(n <= 0)
break;
m += n;
}
return m;
}
enum
{
Line = 256,
};
char*
sstrdup(char *s)
{
char *t;
t = smalloc(strlen(s)+1);
strcpy(t, s);
return t;
}
long
sysexec(ulong *arg)
{
int m;
char *indir, *prog, **args;
char *buf;
Chan *volatile tc;
prog = (char*)arg[0];
args = (char**)arg[1];
indir = nil;
Again:
tc = namec(prog, Aopen, AEXEC, 0);
buf = smalloc(Line);
if(waserror()){
if(indir
free(buf);
cclose(tc);
nexterror();
}
m = readn(tc, buf, Line);
if(m < 2)
error(Ebadexec);
if(buf[0]=='#' && buf[1]=='!'){
if(indir)
error(Ebadexec);
buf[Line-1] = '\0';
p = strchr(buf, '\n');
if(p==nil)
error(Ebadexec);
*p = '\0';
indir = sstrdup(prog);
prog = buf;
cclose(tc);
poperror();
goto Again;
}
long
sysexec(ulong *arg)
{
ulong t, d, b;
int i;
Chan *tc;
char **argv, **argp;
char *a, *charp, *args, *file;
char **progarg *elem, progelem[64];
ulong ssize, spage, nargs, nbytes, n, bssend;
int indir;
Exec exec;
char line[128];
Fgrp *f;
Image *img;
ulong magic, text, entry, data, bss;
buf = smalloc(2048);
if(waserror()){
free(buf);
nexterror();
}
file = (char*)arg[0];
indir = 0;
elem = nil;
if(waserror()){
free(elem);
nexterror();
}
for(;;){
tc = namec(file, Aopen, OEXEC, 0);
if(waserror()){
cclose(tc);
nexterror();
}
if(!indir)
kstrdup(&elem, up->genbuf);
m = 0;
while(m < 2048){
n = devtab[tc->type]->read(tc, buf+m, 2048-m, m);
if(n <= 0)
break;
m += n;
}
if(m < 2)
error(Ebadexec);
if(isbinary(buf, m))
break;
/*
* Process #! /bin/sh args ...
*/
if(indir || line[0]!='#' || line[1]!='!')
error(Ebadexec);
n = shargs(line, n, &progarg);
if(n == 0)
error(Ebadexec);
indir = 1;
/*
* First arg becomes complete file name
*/
progarg[n++] = file;
progarg[n] = 0;
arg[1] += sizeof(char*);
file = progarg[0];
if(strlen(elem) >= sizeof progelem)
error(Ebadexec);
strcpy(progelem, elem);
progarg[0] = progelem;
poperror();
cclose(tc);
}
/*
* Args: pass 1: count
*/
nbytes = BY2WD; /* hole for profiling clock at top of stack */
nargs = 0;
if(indir){
argp = progarg;
while(*argp){
a = *argp++;
nbytes += strlen(a) + 1;
nargs++;
}
}
evenaddr(arg[1]);
argp = (char**)arg[1];
validaddr((ulong)argp, BY2WD, 0);
while(*argp){
a = *argp++;
if(((ulong)argp&(BY2PG-1)) < BY2WD)
validaddr((ulong)argp, BY2WD, 0);
validaddr((ulong)a, 1, 0);
nbytes += (vmemchr(a, 0, 0x7FFFFFFF) - a) + 1;
nargs++;
}
ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
/*
* 8-byte align SP for those (e.g. sparc) that need it.
* execregs() will subtract another 4 bytes for argc.
*/
if((ssize+4) & 7)
ssize += 4;
spage = (ssize+(BY2PG-1)) >> PGSHIFT;
/*
* Build the stack segment, putting it in kernel virtual for the moment
*/
if(spage > TSTKSIZ)
error(Enovmem);
qlock(&up->seglock);
if(waserror()){
qunlock(&up->seglock);
nexterror();
}
up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);
/*
* Args: pass 2: assemble; the pages will be faulted in
*/
argv = (char**)(TSTKTOP - ssize);
charp = (char*)(TSTKTOP - nbytes);
args = charp;
if(indir)
argp = progarg;
else
argp = (char**)arg[1];
for(i=0; i<nargs; i++){
if(indir && *argp==0) {
indir = 0;
argp = (char**)arg[1];
}
*argv++ = charp + (USTKTOP-TSTKTOP);
n = strlen(*argp) + 1;
memmove(charp, *argp++, n);
charp += n;
}
free(up->text);
up->text = elem;
elem = nil; /* so waserror() won't free elem */
USED(elem);
/* copy args; easiest from new process's stack */
n = charp - args;
if(n > 128) /* don't waste too much space on huge arg lists */
n = 128;
a = up->args;
up->args = nil;
free(a);
up->args = smalloc(n);
memmove(up->args, args, n);
if(n>0 && up->args[n-1]!='\0'){
/* make sure last arg is NUL-terminated */
/* put NUL at UTF-8 character boundary */
for(i=n-1; i>0; --i)
if(fullrune(up->args+i, n-i))
break;
up->args[i] = 0;
n = i+1;
}
up->nargs = n;
/*
* Committed.
* Free old memory.
* Special segments are maintained across exec
*/
for(i = SSEG; i <= BSEG; i++) {
putseg(up->seg[i]);
/* prevent a second free if we have an error */
up->seg[i] = 0;
}
for(i = BSEG+1; i < NSEG; i++) {
s = up->seg[i];
if(s != 0 && (s->type&SG_CEXEC)) {
putseg(s);
up->seg[i] = 0;
}
}
/*
* Close on exec
*/
f = up->fgrp;
for(i=0; i<=f->maxfd; i++)
fdclose(i, CCEXEC);
/* Text. Shared. Attaches to cache image if possible */
/* attachimage returns a locked cache image */
img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
ts = img->s;
up->seg[TSEG] = ts;
ts->flushme = 1;
ts->fstart = 0;
ts->flen = sizeof(Exec)+text;
unlock(img);
/* Data. Shared. */
s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
up->seg[DSEG] = s;
/* Attached by hand */
incref(img);
s->image = img;
s->fstart = ts->fstart+ts->flen;
s->flen = data;
/* BSS. Zero fill on demand */
up->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);
/*
* Move the stack
*/
s = up->seg[ESEG];
up->seg[ESEG] = 0;
up->seg[SSEG] = s;
qunlock(&up->seglock);
poperror(); /* seglock */
poperror(); /* elem */
s->base = USTKTOP-USTKSIZE;
s->top = USTKTOP;
relocateseg(s, USTKTOP-TSTKTOP);
/*
* '/' processes are higher priority (hack to make /ip more responsive).
*/
if(devtab[tc->type]->dc == L'/')
up->basepri = PriRoot;
up->priority = up->basepri;
poperror();
cclose(tc);
/*
* At this point, the mmu contains info about the old address
* space and needs to be flushed
*/
flushmmu();
qlock(&up->debug);
up->nnote = 0;
up->notify = 0;
up->notified = 0;
up->privatemem = 0;
procsetup(up);
qunlock(&up->debug);
if(up->hang)
up->procctl = Proc_stopme;
return execregs(entry, ssize, nargs);
}
int
shargs(char *s, int n, char **ap)
{
int i;
s += 2;
n -= 2; /* skip #! */
for(i=0; s[i]!='\n'; i++)
if(i == n-1)
return 0;
s[i] = 0;
*ap = 0;
i = 0;
for(;;) {
while(*s==' ' || *s=='\t')
s++;
if(*s == 0)
break;
i++;
*ap++ = s;
*ap = 0;
while(*s && *s!=' ' && *s!='\t')
s++;
if(*s == 0)
break;
else
*s++ = 0;
}
return i;
}
int
return0(void *arg)
{
USED(arg);
return 0;
}
long
syssleep(ulong *arg)
{
int n;
n = arg[0];
if(n <= 0) {
up->priority = 0;
sched();
return 0;
}
if(n < TK2MS(1))
n = TK2MS(1);
rendtsleep(&up->sleep, return0, 0, n);
return 0;
}
long
sysalarm(ulong *arg)
{
return procalarm(arg[0]);
}
long
sysexits(ulong *arg)
{
char *status;
char *inval = "invalid exit string";
char buf[ERRMAX];
status = (char*)arg[0];
if(status){
memmove(buf, status, ERRMAX);
buf[ERRMAX-1] = 0;
status = buf;
}
pexit(status, 1);
return 0; /* not reached */
}
long
sysawait(ulong *arg)
{
int i;
int pid;
Waitmsg w;
ulong n;
n = arg[1];
pid = pwait(&w);
if(pid < 0)
return -1;
i = snprint((char*)arg[0], n, "%d %lud %lud %lud %q",
w.pid,
w.time[TUser], w.time[TSys], w.time[TReal],
w.msg);
return i;
}
long
sysdeath(ulong *arg)
{
USED(arg);
pprint("deprecated system call\n");
pexit("Suicide", 0);
return 0; /* not reached */
}
void
werrstr(char *fmt, ...)
{
va_list va;
if(up == nil)
return;
va_start(va, fmt);
doprint(up->syserrstr, up->syserrstr+ERRMAX, fmt, va);
va_end(va);
}
static long
generrstr(char *buf, uint nbuf)
{
char tmp[ERRMAX];
if(nbuf > sizeof tmp)
nbuf = sizeof tmp;
memmove(tmp, buf, nbuf);
/* make sure it's NUL-terminated */
tmp[nbuf-1] = '\0';
memmove(buf, up->syserrstr, nbuf);
buf[nbuf-1] = '\0';
memmove(up->syserrstr, tmp, nbuf);
return 0;
}
long
syserrstr(ulong *arg)
{
return generrstr((char*)arg[0], arg[1]);
}
long
sysnoted(ulong *arg)
{
if(arg[0]!=NRSTR && !up->notified)
error(Egreg);
return 0;
}
/* For binary compatibility */
long
syssetbss(ulong *arg)
{
up->bss = arg[0];
return 0;
}
long
sysrendezvous(ulong *arg)
{
ulong tag;
ulong val;
Proc *p, **l;
tag = arg[0];
l = &REND(up->rgrp, tag);
up->rendval = ~0UL;
print("rendezvous grp %p tag %lux up %p\n", up->rgrp, tag, up);
lock(&up->rgrp->ref.lk);
for(p = *l; p; p = p->rendhash) {
if(p->rendtag == tag) {
print("%p found %p; waking\n", up, p);
*l = p->rendhash;
val = p->rendval;
p->rendval = arg[1];
while(p->mach != 0)
;
ready(p);
unlock(&up->rgrp->ref.lk);
return val;
}
l = &p->rendhash;
}
/* Going to sleep here */
up->rendtag = tag;
up->rendval = arg[1];
up->rendhash = *l;
*l = up;
up->state = Rendezvous;
unlock(&up->rgrp->ref.lk);
print("%p sleep\n", up);
sched();
print("%p awake\n", up);
return up->rendval;
}
syntax highlighted by Code2HTML, v. 0.9.1