xref: /inferno-os/emu/MacOSX/cmd.c (revision 6e425a9de8c003b5a733621a6b6730ec3cc902b8)
137da2899SCharles.Forsyth #include	<sys/types.h>
237da2899SCharles.Forsyth #include	<signal.h>
337da2899SCharles.Forsyth #include 	<pwd.h>
437da2899SCharles.Forsyth #include	<sys/time.h>
537da2899SCharles.Forsyth #include	<sys/resource.h>
637da2899SCharles.Forsyth #include	<sys/wait.h>
737da2899SCharles.Forsyth #include	<fcntl.h>
837da2899SCharles.Forsyth 
937da2899SCharles.Forsyth #include	"dat.h"
1037da2899SCharles.Forsyth #include	"fns.h"
1137da2899SCharles.Forsyth #include	"error.h"
1237da2899SCharles.Forsyth 
1337da2899SCharles.Forsyth enum
1437da2899SCharles.Forsyth {
1537da2899SCharles.Forsyth 	Debug = 0
1637da2899SCharles.Forsyth };
1737da2899SCharles.Forsyth 
1837da2899SCharles.Forsyth /*
1937da2899SCharles.Forsyth  * os-specific devcmd support.
2037da2899SCharles.Forsyth  * this version should be reasonably portable across Unix systems.
2137da2899SCharles.Forsyth  */
2237da2899SCharles.Forsyth typedef struct Targ Targ;
2337da2899SCharles.Forsyth struct Targ
2437da2899SCharles.Forsyth {
25*6e425a9dSCharles.Forsyth 	int	fd[3];	/* fd[0] is standard input, fd[1] is standard output, fd[2] is standard error */
2637da2899SCharles.Forsyth 	char**	args;
2737da2899SCharles.Forsyth 	char*	dir;
2837da2899SCharles.Forsyth 	int	pid;
2937da2899SCharles.Forsyth 	int	wfd;	/* child writes errors that occur after the fork or on exec */
3037da2899SCharles.Forsyth 	int	uid;
3137da2899SCharles.Forsyth 	int	gid;
3237da2899SCharles.Forsyth };
3337da2899SCharles.Forsyth 
3437da2899SCharles.Forsyth extern int gidnobody;
3537da2899SCharles.Forsyth extern int uidnobody;
3637da2899SCharles.Forsyth 
3737da2899SCharles.Forsyth static int
childproc(Targ * t)3837da2899SCharles.Forsyth childproc(Targ *t)
3937da2899SCharles.Forsyth {
4037da2899SCharles.Forsyth 	int i, nfd;
4137da2899SCharles.Forsyth 
4237da2899SCharles.Forsyth 	if(Debug)
4337da2899SCharles.Forsyth 		print("devcmd: '%s'", t->args[0]);
4437da2899SCharles.Forsyth 
4537da2899SCharles.Forsyth 	nfd = getdtablesize();
4637da2899SCharles.Forsyth 	for(i = 0; i < nfd; i++)
47*6e425a9dSCharles.Forsyth 		if(i != t->fd[0] && i != t->fd[1] && i != t->fd[2] && i != t->wfd)
4837da2899SCharles.Forsyth 			close(i);
4937da2899SCharles.Forsyth 
5037da2899SCharles.Forsyth 	dup2(t->fd[0], 0);
5137da2899SCharles.Forsyth 	dup2(t->fd[1], 1);
52*6e425a9dSCharles.Forsyth 	dup2(t->fd[2], 2);
5337da2899SCharles.Forsyth 	close(t->fd[0]);
5437da2899SCharles.Forsyth 	close(t->fd[1]);
55*6e425a9dSCharles.Forsyth 	close(t->fd[2]);
5637da2899SCharles.Forsyth 
57*6e425a9dSCharles.Forsyth 	/* should have an auth file to do host-specific authorisation? */
5837da2899SCharles.Forsyth 	if(t->gid != -1){
5937da2899SCharles.Forsyth 		if(setgid(t->gid) < 0 && getegid() == 0){
6037da2899SCharles.Forsyth 			fprint(t->wfd, "can't set gid %d: %s", t->gid, strerror(errno));
6137da2899SCharles.Forsyth 			_exit(1);
6237da2899SCharles.Forsyth 		}
6337da2899SCharles.Forsyth 	}
6437da2899SCharles.Forsyth 
6537da2899SCharles.Forsyth 	if(t->uid != -1){
6637da2899SCharles.Forsyth 		if(setuid(t->uid) < 0 && geteuid() == 0){
6737da2899SCharles.Forsyth 			fprint(t->wfd, "can't set uid %d: %s", t->uid, strerror(errno));
6837da2899SCharles.Forsyth 			_exit(1);
6937da2899SCharles.Forsyth 		}
7037da2899SCharles.Forsyth 	}
7137da2899SCharles.Forsyth 
7237da2899SCharles.Forsyth 	if(t->dir != nil && chdir(t->dir) < 0){
7337da2899SCharles.Forsyth 		fprint(t->wfd, "can't chdir to %s: %s", t->dir, strerror(errno));
7437da2899SCharles.Forsyth 		_exit(1);
7537da2899SCharles.Forsyth 	}
7637da2899SCharles.Forsyth 
7737da2899SCharles.Forsyth 	signal(SIGPIPE, SIG_DFL);
7837da2899SCharles.Forsyth 
7937da2899SCharles.Forsyth 	execvp(t->args[0], t->args);
8037da2899SCharles.Forsyth 	if(Debug)
8137da2899SCharles.Forsyth 		print("execvp: %s\n",strerror(errno));
8237da2899SCharles.Forsyth 	fprint(t->wfd, "exec failed: %s", strerror(errno));
8337da2899SCharles.Forsyth 
8437da2899SCharles.Forsyth 	_exit(1);
8537da2899SCharles.Forsyth }
8637da2899SCharles.Forsyth 
8737da2899SCharles.Forsyth void*
oscmd(char ** args,int nice,char * dir,int * fd)88*6e425a9dSCharles.Forsyth oscmd(char **args, int nice, char *dir, int *fd)
8937da2899SCharles.Forsyth {
9037da2899SCharles.Forsyth 	Targ *t;
91*6e425a9dSCharles.Forsyth 	int r, fd0[2], fd1[2], fd2[2], wfd[2], n, pid;
9237da2899SCharles.Forsyth 
9337da2899SCharles.Forsyth 	t = mallocz(sizeof(*t), 1);
9437da2899SCharles.Forsyth 	if(t == nil)
9537da2899SCharles.Forsyth 		return nil;
9637da2899SCharles.Forsyth 
9737da2899SCharles.Forsyth 	fd0[0] = fd0[1] = -1;
9837da2899SCharles.Forsyth 	fd1[0] = fd1[1] = -1;
99*6e425a9dSCharles.Forsyth 	fd2[0] = fd2[1] = -1;
10037da2899SCharles.Forsyth 	wfd[0] = wfd[1] = -1;
101*6e425a9dSCharles.Forsyth 	if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0)
10237da2899SCharles.Forsyth 		goto Error;
10337da2899SCharles.Forsyth 	if(fcntl(wfd[1], F_SETFD, FD_CLOEXEC) < 0)	/* close on exec to give end of file on success */
10437da2899SCharles.Forsyth 		goto Error;
10537da2899SCharles.Forsyth 
10637da2899SCharles.Forsyth 	t->fd[0] = fd0[0];
10737da2899SCharles.Forsyth 	t->fd[1] = fd1[1];
108*6e425a9dSCharles.Forsyth 	t->fd[2] = fd2[1];
10937da2899SCharles.Forsyth 	t->wfd = wfd[1];
11037da2899SCharles.Forsyth 	t->args = args;
11137da2899SCharles.Forsyth 	t->dir = dir;
11237da2899SCharles.Forsyth 	t->gid = up->env->gid;
11337da2899SCharles.Forsyth 	if(t->gid == -1)
11437da2899SCharles.Forsyth 		t->gid = gidnobody;
11537da2899SCharles.Forsyth 	t->uid = up->env->uid;
11637da2899SCharles.Forsyth 	if(t->uid == -1)
11737da2899SCharles.Forsyth 		t->uid = uidnobody;
11837da2899SCharles.Forsyth 
11937da2899SCharles.Forsyth 	signal(SIGCHLD, SIG_DFL);
12037da2899SCharles.Forsyth 	switch(pid = fork()) {
12137da2899SCharles.Forsyth 	case -1:
12237da2899SCharles.Forsyth 		goto Error;
12337da2899SCharles.Forsyth 	case 0:
12437da2899SCharles.Forsyth 		setpgid(0, getpid());
12537da2899SCharles.Forsyth 		if(nice)
12637da2899SCharles.Forsyth 			oslopri();
12737da2899SCharles.Forsyth 		childproc(t);
12837da2899SCharles.Forsyth 		_exit(1);
12937da2899SCharles.Forsyth 	default:
13037da2899SCharles.Forsyth 		t->pid = pid;
13137da2899SCharles.Forsyth 		if(Debug)
13237da2899SCharles.Forsyth 			print("cmd pid %d\n", t->pid);
13337da2899SCharles.Forsyth 		break;
13437da2899SCharles.Forsyth 	}
13537da2899SCharles.Forsyth 
13637da2899SCharles.Forsyth 	close(fd0[0]);
13737da2899SCharles.Forsyth 	close(fd1[1]);
138*6e425a9dSCharles.Forsyth 	close(fd2[1]);
13937da2899SCharles.Forsyth 	close(wfd[1]);
14037da2899SCharles.Forsyth 
14137da2899SCharles.Forsyth 	n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1);
14237da2899SCharles.Forsyth 	close(wfd[0]);
14337da2899SCharles.Forsyth 	if(n > 0){
14437da2899SCharles.Forsyth 		close(fd0[1]);
14537da2899SCharles.Forsyth 		close(fd1[0]);
146*6e425a9dSCharles.Forsyth 		close(fd2[0]);
14737da2899SCharles.Forsyth 		free(t);
14837da2899SCharles.Forsyth 		up->genbuf[n] = 0;
14937da2899SCharles.Forsyth 		if(Debug)
15037da2899SCharles.Forsyth 			print("oscmd: bad exec: %q\n", up->genbuf);
15137da2899SCharles.Forsyth 		error(up->genbuf);
15237da2899SCharles.Forsyth 		return nil;
15337da2899SCharles.Forsyth 	}
15437da2899SCharles.Forsyth 
155*6e425a9dSCharles.Forsyth 	fd[0] = fd0[1];
156*6e425a9dSCharles.Forsyth 	fd[1] = fd1[0];
157*6e425a9dSCharles.Forsyth 	fd[2] = fd2[0];
15837da2899SCharles.Forsyth 	return t;
15937da2899SCharles.Forsyth 
16037da2899SCharles.Forsyth Error:
16137da2899SCharles.Forsyth 	r = errno;
16237da2899SCharles.Forsyth 	if(Debug)
16337da2899SCharles.Forsyth 		print("oscmd: %q\n",strerror(r));
16437da2899SCharles.Forsyth 	close(fd0[0]);
16537da2899SCharles.Forsyth 	close(fd0[1]);
16637da2899SCharles.Forsyth 	close(fd1[0]);
16737da2899SCharles.Forsyth 	close(fd1[1]);
168*6e425a9dSCharles.Forsyth 	close(fd2[0]);
169*6e425a9dSCharles.Forsyth 	close(fd2[1]);
17037da2899SCharles.Forsyth 	close(wfd[0]);
17137da2899SCharles.Forsyth 	close(wfd[1]);
17237da2899SCharles.Forsyth 	error(strerror(r));
17337da2899SCharles.Forsyth 	return nil;
17437da2899SCharles.Forsyth }
17537da2899SCharles.Forsyth 
17637da2899SCharles.Forsyth int
oscmdkill(void * a)17737da2899SCharles.Forsyth oscmdkill(void *a)
17837da2899SCharles.Forsyth {
17937da2899SCharles.Forsyth 	Targ *t = a;
18037da2899SCharles.Forsyth 
18137da2899SCharles.Forsyth 	if(Debug)
18237da2899SCharles.Forsyth 		print("kill: %d\n", t->pid);
18337da2899SCharles.Forsyth 	return kill(-t->pid, SIGTERM);
18437da2899SCharles.Forsyth }
18537da2899SCharles.Forsyth 
18637da2899SCharles.Forsyth int
oscmdwait(void * a,char * buf,int n)18737da2899SCharles.Forsyth oscmdwait(void *a, char *buf, int n)
18837da2899SCharles.Forsyth {
18937da2899SCharles.Forsyth 	Targ *t = a;
19037da2899SCharles.Forsyth 	int s;
19137da2899SCharles.Forsyth 
19237da2899SCharles.Forsyth 	if(waitpid(t->pid, &s, 0) == -1){
19337da2899SCharles.Forsyth 		if(Debug)
19437da2899SCharles.Forsyth 			print("wait error: %d [in %d] %q\n", t->pid, getpid(), strerror(errno));
19537da2899SCharles.Forsyth 		return -1;
19637da2899SCharles.Forsyth 	}
19737da2899SCharles.Forsyth 	if(WIFEXITED(s)){
19837da2899SCharles.Forsyth 		if(WEXITSTATUS(s) == 0)
19937da2899SCharles.Forsyth 			return snprint(buf, n, "%d 0 0 0 ''", t->pid);
20037da2899SCharles.Forsyth 		return snprint(buf, n, "%d 0 0 0 'exit: %d'", t->pid, WEXITSTATUS(s));
20137da2899SCharles.Forsyth 	}
20237da2899SCharles.Forsyth 	if(WIFSIGNALED(s)){
20337da2899SCharles.Forsyth 		if(WTERMSIG(s) == SIGTERM || WTERMSIG(s) == SIGKILL)
20437da2899SCharles.Forsyth 			return snprint(buf, n, "%d 0 0 0 killed", t->pid);
20537da2899SCharles.Forsyth 		return snprint(buf, n, "%d 0 0 0 'signal: %d'", t->pid, WTERMSIG(s));
20637da2899SCharles.Forsyth 	}
20737da2899SCharles.Forsyth 	return snprint(buf, n, "%d 0 0 0 'odd status: 0x%x'", t->pid, s);
20837da2899SCharles.Forsyth }
20937da2899SCharles.Forsyth 
21037da2899SCharles.Forsyth void
oscmdfree(void * a)21137da2899SCharles.Forsyth oscmdfree(void *a)
21237da2899SCharles.Forsyth {
21337da2899SCharles.Forsyth 	free(a);
21437da2899SCharles.Forsyth }
215