rminnichmerge57758a716 years agoHistory
1109 lines · 23.2 KB · C
RawDownload
#include	"u.h"#include	"tos.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" #include	"../port/edf.h"#include	<a.out.h> voidsysr1(Ar0* ar0, va_list list){	USED(list); 	ar0->i = 0;} voidsysrfork(Ar0* ar0, va_list list){	Proc *p;	int flag, i, n, pid;	Fgrp *ofg;	Pgrp *opg;	Rgrp *org;	Egrp *oeg;	Mach *wm; 	/*	 * int rfork(int);	 */	flag = va_arg(list, int); 	/* 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 = 1;			if(flag & RFENVG)				envcpy(up->egrp, oeg);			closeegrp(oeg);		}		if(flag & RFNOTEG)			up->noteid = incref(&noteidalloc); 		ar0->i = 0;		return;	} 	p = newproc(); 	p->trace = up->trace;	p->scallnr = up->scallnr;	memmove(p->arg, up->arg, sizeof(up->arg));	p->nerrlab = 0;	p->slash = up->slash;	p->dot = up->dot;	incref(p->dot); 	memmove(p->note, up->note, sizeof(p->note));	p->privatemem = up->privatemem;	p->noswap = up->noswap;	p->nnote = up->nnote;	p->notified = 0;	p->lastnote = up->lastnote;	p->notify = up->notify;	p->ureg = up->ureg;	p->dbgreg = 0; 	/* Make a new set of memory segments */	n = flag & RFMEM;	qlock(&p->seglock);	if(waserror()){		qunlock(&p->seglock);		nexterror();	}	for(i = 0; i < NSEG; i++)		if(up->seg[i])			p->seg[i] = dupseg(up->seg, i, n);	qunlock(&p->seglock);	poperror(); 	/* 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);	} 	/* 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);	}	if(flag & RFNOMNT)		up->pgrp->noattach = 1; 	if(flag & RFREND)		p->rgrp = newrgrp();	else {		incref(up->rgrp);		p->rgrp = up->rgrp;	} 	/* Environment group */	if(flag & (RFENVG|RFCENVG)) {		p->egrp = smalloc(sizeof(Egrp));		p->egrp->ref = 1;		if(flag & RFENVG)			envcpy(p->egrp, up->egrp);	}	else {		p->egrp = up->egrp;		incref(p->egrp);	}	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	 */	sysrforkchild(p, up); 	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; 	pid = p->pid;	memset(p->time, 0, sizeof(p->time));	p->time[TReal] = MACHP(0)->ticks; 	kstrdup(&p->text, up->text);	kstrdup(&p->user, up->user);	/*	 *  since the bss/data segments are now shareable,	 *  any mmu info about this process is now stale	 *  (i.e. has bad properties) and has to be discarded.	 */	mmuflush();	p->basepri = up->basepri;	p->priority = up->basepri;	p->fixedpri = up->fixedpri;	p->mp = up->mp;	wm = up->wired;	if(wm)		procwired(p, wm->machno);	ready(p);	sched(); 	ar0->i = pid;} static uvlongvl2be(uvlong v){	uchar *p; 	p = (uchar*)&v;	return ((uvlong)((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3])<<32)	      |((uvlong)(p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7]);} static ulongl2be(long l){	uchar *cp; 	cp = (uchar*)&l;	return (cp[0]<<24) | (cp[1]<<16) | (cp[2]<<8) | cp[3];} typedef struct {	Exec;	uvlong hdr[1];} Hdr; voidsysexec(Ar0* ar0, va_list list){	Hdr hdr;	Fgrp *f;	Tos *tos;	Chan *chan;	Image *img;	Segment *s;	int argc, i, n;	char *a, **argv, *elem, *file, *p;	char line[sizeof(Exec)], *progarg[sizeof(Exec)/2+1];	long hdrsz, magic, textsz, datasz, bsssz;	uintptr textlim, datalim, bsslim, entry, stack; 	/*	 * void* exec(char* name, char* argv[]);	 */ 	/*	 * Open the file, remembering the final element and the full name.	 */	file = nil;	elem = nil;	chan = nil;	if(waserror()){		if(file)			free(file);		if(elem)			free(elem);		if(chan)			cclose(chan);		nexterror();	} 	p = va_arg(list, char*);	p = validaddr(p, 1, 0);	file = validnamedup(p, 1);	chan = namec(file, Aopen, OEXEC, 0);	kstrdup(&elem, up->genbuf); 	/*	 * Read the header.	 * If it's a #!, fill in progarg[] with info then read a new header	 * from the file indicated by the #!.	 * The #! line must be less than sizeof(Exec) in size,	 * including the terminating \n.	 */	hdrsz = chan->dev->read(chan, &hdr, sizeof(Hdr), 0);	if(hdrsz < 2)		error(Ebadexec);	p = (char*)&hdr;	argc = 0;	if(p[0] == '#' && p[1] == '!'){		p = memccpy(line, (char*)&hdr, '\n', MIN(sizeof(Exec), hdrsz));		if(p == nil)			error(Ebadexec);		*(p-1) = '\0';		argc = tokenize(line+2, progarg, nelem(progarg));		if(argc == 0)			error(Ebadexec); 		/* The original file becomes an extra arg after #! line */		progarg[argc++] = file; 		/*		 * Take the #! $0 as a file to open, and replace		 * $0 with the original path's name.		 */		p = progarg[0];		progarg[0] = elem;		cclose(chan);		chan = nil;	/* in case namec errors out */		USED(chan);		chan = namec(p, Aopen, OEXEC, 0);		hdrsz = chan->dev->read(chan, &hdr, sizeof(Hdr), 0);		if(hdrsz < 2)			error(Ebadexec);	} 	/*	 * #! has had its chance, now we need a real binary.	 */	magic = l2be(hdr.magic);	if(hdrsz != sizeof(Hdr) || magic != AOUT_MAGIC)		error(Ebadexec);	if(magic & HDR_MAGIC){		entry = vl2be(hdr.hdr[0]);		hdrsz = sizeof(Hdr);	}	else{		entry = l2be(hdr.entry);		hdrsz = sizeof(Exec);	} 	textsz = l2be(hdr.text);	datasz = l2be(hdr.data);	bsssz = l2be(hdr.bss); 	textlim = UTROUND(UTZERO+hdrsz+textsz);	datalim = PGROUND(textlim+datasz);	bsslim = PGROUND(textlim+datasz+bsssz); 	/*	 * Check the binary header for consistency,	 * e.g. the entry point is within the text segment and	 * the segments don't overlap each other.	 */	if(entry < UTZERO+hdrsz || entry >= UTZERO+hdrsz+textsz)		error(Ebadexec); 	if(textsz >= textlim || datasz > datalim || bsssz > bsslim	|| textlim >= USTKTOP || datalim >= USTKTOP || bsslim >= USTKTOP	|| datalim < textlim || bsslim < datalim)		error(Ebadexec); 	/*	 * The new stack is created in ESEG, temporarily mapped elsewhere.	 * The stack contains, in descending address order:	 *	a structure containing housekeeping and profiling data (Tos);	 *	argument strings;	 *	array of vectors to the argument strings with a terminating	 *	nil (argv).	 * When the exec is committed, this temporary stack in ESEG will	 * become SSEG.	 * The architecture-dependent code which jumps to the new image	 * will also push a count of the argument array onto the stack (argc).	 */	qlock(&up->seglock);	if(waserror()){		if(up->seg[ESEG] != nil){			putseg(up->seg[ESEG]);			up->seg[ESEG] = nil;		}		qunlock(&up->seglock);		nexterror();	}	up->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG); 	/*	 * Stack is a pointer into the temporary stack	 * segment, and will move as items are pushed.	 */	stack = TSTKTOP-sizeof(Tos); 	/*	 * First, the top-of-stack structure.	 */	tos = (Tos*)stack;	tos->cyclefreq = m->cyclefreq;	cycles((uvlong*)&tos->pcycles);	tos->pcycles = -tos->pcycles;	tos->kcycles = tos->pcycles;	tos->clock = 0; 	/*	 * Next push any arguments found from a #! header.	 */	for(i = 0; i < argc; i++){		n = strlen(progarg[i])+1;		stack -= n;		memmove(UINT2PTR(stack), progarg[i], n);	} 	/*	 * Copy the strings pointed to by the syscall argument argv into	 * the temporary stack segment, being careful to check both argv and	 * the strings it points to are valid.	 */	argv = va_arg(list, char**);	evenaddr(PTR2UINT(argv));	for(i = 0;; i++, argv++){		a = *(char**)validaddr(argv, sizeof(char**), 0);		if(a == nil)			break;		a = validaddr(a, 1, 0);		n = ((char*)vmemchr(a, 0, 0x7fffffff) - a) + 1; 		/*		 * This futzing is so argv[0] gets validated even		 * though it will be thrown away if this is a shell		 * script.		 */		if(argc > 0 && i == 0)			continue; 		/*		 * Before copying the string into the temporary stack,		 * which might involve a demand-page, check the string		 * will not overflow the bottom of the stack.		 */		stack -= n;		if(stack < TSTKTOP-USTKSIZE)			error(Enovmem);		p = UINT2PTR(stack);		memmove(p, a, n);		p[n-1] = 0;		argc++;	}	if(argc < 1)		error(Ebadexec); 	/*	 * Before pushing the argument pointers onto the temporary stack,	 * which might involve a demand-page, check there is room for the	 * terminating nil pointer, plus pointers, plus some slop for however	 * argc might be passed on the stack by sysexecregs (give a page	 * of slop, it is an overestimate, but why not).	 * Sysexecstack does any architecture-dependent stack alignment.	 * Keep a copy of the start of the argument strings before alignment	 * so up->args can be created later.	 * Although the argument vectors are being pushed onto the stack in	 * the temporary segment, the values must be adjusted to reflect	 * the segment address after it replaces the current SSEG.	 */	a = p = UINT2PTR(stack);	stack = sysexecstack(stack, argc);	if(stack-(argc+1)*sizeof(char**)-BY2PG < TSTKTOP-USTKSIZE)		error(Ebadexec); 	argv = (char**)stack;	*--argv = nil;	for(i = 0; i < argc; i++){		*--argv = p + (USTKTOP-TSTKTOP);		p += strlen(p) + 1;	} 	/*	 * Make a good faith copy of the args in up->args using the strings	 * in the temporary stack segment. The length must be > 0 as it	 * includes the \0 on the last argument and argc was checked earlier	 * to be > 0. After the memmove, compensate for any UTF character	 * boundary before placing the terminating \0.	 */	n = p - a;	if(n <= 0)		error(Egreg);	if(n > 128)		n = 128; 	p = smalloc(n);	if(waserror()){		free(p);		nexterror();	} 	memmove(p, a, n);	while(n > 0 && (p[n-1] & 0xc0) == 0x80)		n--;	p[n-1] = '\0'; 	/*	 * All the argument processing is now done, ready to commit.	 */	free(up->text);	up->text = elem;	elem = nil;	free(up->args);	up->args = p;	up->nargs = n;	poperror();				/* p (up->args) */ 	/*	 * Close on exec	 */	f = up->fgrp;	for(i=0; i<=f->maxfd; i++)		fdclose(i, CCEXEC);

Lines 1–500 of 1109.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t