Plan 9 from Bell Labs’s /usr/web/sources/contrib/cinap_lenrek/old/linuxemu.old/sysproc.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <ureg.h>
#include "linuxsys.h"
#include "linux.h"

SYSCALL(sys_exit)
{
	int n = ARG1;
	char buf[12];

	DPRINT("exit(%d)...\n", n);
	if(n == 0)
		exits(0);	
	sprint(buf, "%d", n);
	exits(buf);

	abort();
}

SYSCALL(sys_exit_group)
{
	int n = ARG1;
	char buf[12];

	DPRINT("exit_group(%d)...\n", n);
	if(n == 0)
		exits(0);
	sprint(buf, "%d", n);
	exits(buf);

	abort();
}

enum {
	CLONE_VM			=0x00000100,
	CLONE_FS			=0x00000200,
	CLONE_FILES			=0x00000400,
	CLONE_SIGHAND		=0x00000800,
	CLONE_PTRACE		=0x00002000,
	CLONE_VFORK			=0x00004000,
	CLONE_PARENT		=0x00008000,
	CLONE_THREAD		=0x00010000,
	CLONE_NEWNS		=0x00020000,
	CLONE_SYSVSEM		=0x00040000,
	CLONE_SETTLS			=0x00080000,
	CLONE_PARENT_SETTID	=0x00100000,
	CLONE_CHILD_CLEARTID=0x00200000,
	CLONE_DETACHED		=0x00400000,
	CLONE_UNTRACED		=0x00800000,
	CLONE_CHILD_SETTID	=0x01000000,
	CLONE_STOPPED		=0x02000000,
};

static void
finishproc(void)
{
	if(threadp->exitsig){
		_kill(threadp->ptid, threadp->exitsig);
	}
	if(threadp->cleartidaddr)
		*threadp->cleartidaddr = 0;
}


int
_kill(int pid, int sig)
{
	int fd;
	char buf[80];
	char *msg;

	DPRINT("kill(%d, %d)... from pid %d\n", pid, sig, threadp->tid);
	if((msg = sigstring(sig)) == nil){
		return -EINVAL;
	}
	snprint(buf, sizeof(buf), "/proc/%d/note", pid);
	if((fd = open(buf, OWRITE)) < 0)
		return -ESRCH;
	write(fd, msg, strlen(msg));
	close(fd);
	return 0;
}

typedef struct Ureg Ureg;
typedef struct Cloneargs Cloneargs;
struct Cloneargs
{
	Ureg		*ureg;
	ulong	cflags;
	ulong	newstack;
	int		*parenttidptr;
	int		*childtidptr;
};

static int
_clone(void *aux)
{
	int r;
	int rflags;
	Cloneargs a, *x;
	Ureg u;

	x = aux;

	DPRINT("_clone: my stack is 0x%p\n", &r);

	memcpy(&a, x, sizeof(a));
	memcpy(&u, x->ureg, sizeof(u));

	rflags = RFREND|RFFDG|RFPROC|RFENVG;
	if(a.cflags & CLONE_FILES)
		rflags &= ~RFFDG;
	if(a.cflags & CLONE_VM){
		rflags |= RFMEM;
		rflags &= ~RFREND;
	}
	if(a.cflags & CLONE_SETTLS){
		fprint(2, "clone(): TLS is not supported!\n");
		abort();
	}
	if((a.cflags & CLONE_VM) && !(a.cflags & CLONE_FILES)){
		fprint(2, "clone(): thread will share memory but not filedescriptors!\n");
		abort(); 
	}

	DPRINT("clone(): do rfork(0x%x)...\n", rflags);

	r = rfork(rflags);

	DPRINT("clone(): rfork(0x%x) -> %d in pid %d\n", rflags, r, getpid());

	if(r < 0){
		r = mkerror();
		fprint(2, "clone(): rfork failed: %r\n");
		return r;
	}

	if(r==0){
		threadp->tid = getpid();
		threadp->exitsig = a.cflags & 0xFF;

		sigclearall(&threadp->ss);
		threadp->ss.level = 0;

		DPRINT("clone(): thread/proc with tid %d starting...", threadp->tid);

		if(!(a.cflags & CLONE_THREAD))
			threadp->tgid = threadp->tid;
		if(!(a.cflags & CLONE_THREAD) || !(a.cflags & CLONE_PARENT))
			threadp->ptid = getppid();

		threadp->cleartidaddr = nil;
		if(a.cflags & CLONE_CHILD_CLEARTID)
			threadp->cleartidaddr = a.childtidptr;

		if(a.cflags & CLONE_CHILD_SETTID){
			assert(a.childtidptr!=nil);
			*a.childtidptr = threadp->tid;
		}

		if(!(a.cflags & CLONE_VM))
			forkallfdtags();

		atexit(finishproc);

		if(a.newstack){
			u.sp = a.newstack;
		}

		/* child returns directly to proc */
		u.pc += 2;
		u.ax = r;
		jumpureg(&u);

		abort();
	} 

	if(a.cflags & CLONE_PARENT_SETTID){
		assert(a.parenttidptr!=nil);
		*a.parenttidptr = r;
	}

	return r;
}

static int
clone(struct Ureg *ureg, ulong cflags, ulong newstack, int *parenttidptr, int *childtidptr)
{
	Cloneargs a;

	DPRINT("clone()...");
	a.ureg = ureg;
	a.cflags = cflags;
	a.newstack = newstack;
	a.parenttidptr = parenttidptr;
	a.childtidptr = childtidptr;

	return do9stack(_clone, &a);
}

SYSCALL(sys_fork)
{
	int r;
	DPRINT("fork()...");
	r = clone(ureg, 0, 0, nil, nil);
	RETURN(r);
}

SYSCALL(sys_clone)
{
	int r;
	ulong cflags;
	ulong newstack;
	int *parenttidptr;
	int *childtidptr;

	cflags = (int)ARG1;
	newstack = (ulong)ARG2;
	parenttidptr = (int*)ARG3;
	childtidptr = (int*)ARG5;

	DPRINT("clone(0x%lux, 0x%lux, 0x%p, ..., 0x%p)...", 
		cflags, newstack, parenttidptr, childtidptr);
	if(!newstack)
		newstack = ureg->sp;
	r = clone(ureg, cflags, newstack, parenttidptr, childtidptr);
	RETURN(r);
}

SYSCALL(sys_set_tid_address)
{
	int r;
	int *tidaddr;
	tidaddr = (int*)ARG1;
	DPRINT("set_tid_address(0x%p)...", tidaddr);
	threadp->cleartidaddr = tidaddr;
	r = threadp->tgid;
	RETURN(r);
}

struct timeval {
	long tv_sec;			/* seconds */
	long	tv_usec;			/* microseconds */
};

struct  rusage {
	struct timeval ru_utime;	/* user time used */
	struct timeval ru_stime;	/* system time used */
	long    ru_maxrss;		/* maximum resident set size */
	long    ru_ixrss;		/* integral shared memory size */
	long    ru_idrss;		/* integral unshared data size */
	long    ru_isrss;			/* integral unshared stack size */
	long    ru_minflt;		/* page reclaims */
	long    ru_majflt;		/* page faults */
	long    ru_nswap;		/* swaps */
	long    ru_inblock;		/* block input operations */
	long    ru_oublock;		/* block output operations */
	long    ru_msgsnd;		/* messages sent */
	long    ru_msgrcv;		/* messages received */
	long    ru_nsignals;		/* signals received */
	long    ru_nvcsw;		/* voluntary context switches */
	long    ru_nivcsw;		/* involuntary " */
};

static int
waitstatus(Waitmsg *w)
{
	int r, t;
	char *bp, *ep;

	r = 0;
	t = 0;
	if(w->msg[0]){
		/* message is 'prog pid:string' */
		bp = w->msg;
		while(*bp){
			if(*bp++ == ':')
				break;
		}
		if(*bp == 0)
			bp = w->msg;
		r = strtol(bp, &ep, 10);
		if(*ep == 0){
			if(r < 0 || r >= 256)
				r = 1;
		}else{
			t = stringsig(bp);
			if(t == 0)
				r = 1;
		}
	}
	return (r<<8) | t;
}

static void
waitresource(struct rusage *ru, Waitmsg *w)
{
	memset(ru, 0, sizeof(*ru));
	ru->ru_utime.tv_sec = w->time[0]/1000;
	ru->ru_utime.tv_usec = (w->time[0]%1000)*1000;
	ru->ru_stime.tv_sec = w->time[1]/1000;
	ru->ru_stime.tv_usec = (w->time[1]%1000)*1000;
}

typedef struct Waited Waited;
struct Waited
{
	Waited	*next;
	Waitmsg	*w;
};

static int
wait4(int wpid, int *status, int options, struct rusage *ru)
{
	static Waited *wl;
	static Lock wllock;
	Waited **i;
	Waitmsg *w;

//	fprint(2, "wait4: %d\n", getpid());
	w = nil;
	lock(&wllock);
	for(i=&wl; *i; i=&((*i)->next)){
		if(wpid <= 0 || (*i)->w->pid == wpid){
			Waited *t;
			t = (*i);
			w = t->w;
			*i = t->next;
			free(t);

			break;
		}
	}
	unlock(&wllock);

	if(w == nil){
		if(options & WNOHANG){
			char pname[50];
			Dir *d;

			snprint(pname, sizeof(pname), "/proc/%d/wait", getpid());
			d = dirstat(pname);
			if(d != nil && d->length == 0){
				free(d);
				return 0;
			}
			free(d);
		}
		for(;;){
			Waited *e;

			w = wait();
			if(w == nil){
				return -1;
			}
			if(wpid <= 0 || w->pid == wpid)
				break;

			e = malloc(sizeof(Waited));
			e->w = w;
			lock(&wllock);
			e->next = wl;
			wl = e;
			unlock(&wllock);
		}
	}

	if(ru != nil)
		waitresource(ru, w);
	if(status != nil)
		*status = waitstatus(w);
	wpid = w->pid;
	free(w);

	return wpid;
}

SYSCALL(sys_wait4)
{
	int pid;
	int *status;
	int opt;
	struct rusage *ru;

	pid = (int)ARG1;
	status = (int*)ARG2;
	opt = (int)ARG3;
	ru = (struct rusage*)ARG4;

	DPRINT("wait4(%d, 0x%p, %d, 0x%p)...", pid, status, opt, ru);
	RETURN(wait4(pid, status, opt, ru));
}

SYSCALL(sys_waitpid)
{
	int pid;
	int *status;
	int opt;

	pid = (int)ARG1;
	status = (int*)ARG2;
	opt = (int)ARG3;

	DPRINT("waitpid(%d, 0x%p, %d)...", pid, status, opt);
	RETURN(wait4(pid, status, opt, nil));
}

static int
_exec(void *aux)
{
	char **eargv;

	eargv = aux;
	mmapexit();
	exec(eargv[0], eargv);
	return mkerror();
}

SYSCALL(sys_execve)
{
	char *name;
	char **argv;
	char **envp;
	char **eargv;
	int i, j;
	Dir *d;

	name = (char*)ARG1;
	argv = (char**)ARG2;
	envp = (char**)ARG3;

	DPRINT("execve(%s, %p, %p)...", name, argv, envp);

	if((d = dirstat(name)) == nil){
		RETURN(mkerror());
	}
	free(d);

	/*
	 * what we do is to cat the emu arg's and the requested
	 * together and exec() it. for example: execve("/bin/ls", ["ls"], ...) 
	 * becomes exec("/bin/linuxemu", ["/bin/linuxemu", "-d", "/bin/ls"]).
	 * then we let the emulator figure out what kind the executable
	 * is.
	 */
	for(j=0; emuargv[j]; j++)
		;
	for(i=0; argv[i]; i++)
		;
	eargv = malloc(sizeof(char*)*(i+j+1));
	for(i=0; emuargv[i]; i++)
		eargv[i] = strdup(emuargv[i]);
	for(i=0; argv[i]; i++)
		eargv[i+j] = strdup(argv[i]);
	eargv[j] = strdup(name);
	eargv[i+j] = nil;
	if(envp)
		writeenv(envp);

	RETURN(do9stack(_exec, eargv));
}

SYSCALL(sys_getpid)
{
	DPRINT("getpid()...");
	RETURN(threadp->pid);
}

SYSCALL(sys_getppid)
{
	DPRINT("getppid()...");
	RETURN(threadp->ptid);
}

SYSCALL(sys_gettid)
{
	DPRINT("gettid()...");
	RETURN(threadp->tid);
}

SYSCALL(sys_getpgrp)
{
	RETURN(threadp->gid);
}

SYSCALL(sys_newgetuid)
{
	RETURN(threadp->uid);
}

SYSCALL(sys_newgetgid)
{
	RETURN(threadp->gid);
}

SYSCALL(sys_newgetegid)
{
	RETURN(threadp->gid);
}

SYSCALL(sys_newgeteuid)
{
	RETURN(threadp->uid);
}



Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].