xref: /inferno-os/emu/Plan9/cmd.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include	"dat.h"
2 #include	"fns.h"
3 #include	"error.h"
4 
5 extern	void	vstack(void*);
6 
7 /*
8  * all this is for the benefit of devcmd.
9  * i hope it's grateful.
10  */
11 
12 typedef struct Targ Targ;
13 struct Targ
14 {
15 	int	fd[3];	/* standard input, output and error */
16 	int	wfd;
17 	int*	spin;
18 	char**	args;
19 	char*	dir;
20 	int	pid;
21 	int	nice;
22 };
23 
24 /*
25  * called by vstack once it has moved to
26  * the unshared stack in the new process.
27  */
28 void
29 exectramp(Targ *t)
30 {
31 	int *fd, i, nfd;
32 	char filename[128], err[ERRMAX], status[2*ERRMAX];
33 
34 	t->pid = getpid();
35 	*t->spin = 0;	/* allow parent to proceed: can't just rendezvous: see below */
36 	fd = t->fd;
37 
38 	snprint(filename, sizeof(filename), "#d/%d", t->wfd);
39 	t->wfd = open(filename, OWRITE|OCEXEC);
40 	/* if it failed, we'll manage */
41 
42 	nfd = MAXNFD;	/* TO DO: should read from /fd */
43 	for(i = 0; i < nfd; i++)
44 		if(i != fd[0] && i != fd[1] && i != fd[2] && i != t->wfd)
45 			close(i);
46 
47 	if(fd[0] != 0){
48 		dup(fd[0], 0);
49 		close(fd[0]);
50 	}
51 	if(fd[1] != 1){
52 		dup(fd[1], 1);
53 		close(fd[1]);
54 	}
55 	if(fd[2] != 2){
56 		dup(fd[2], 2);
57 		close(fd[2]);
58 	}
59 
60 	if(t->dir != nil && chdir(t->dir) < 0){
61 		if(t->wfd > 0)
62 			fprint(t->wfd, "chdir: %s: %r", t->dir);
63 		_exits("bad dir");
64 	}
65 	if(t->nice)
66 		oslopri();
67 
68 	exec(t->args[0], t->args);
69 	err[0] = 0;
70 	errstr(err, sizeof(err));
71 	if(t->args[0][0] != '/' && t->args[0][0] != '#' &&
72 	   strncmp(t->args[0], "../", 3) != 0 && strncmp(t->args[0], "./", 2) != 0 &&
73 	   strlen(t->args[0])+5 < sizeof(filename)){
74 		snprint(filename, sizeof(filename), "/bin/%s", t->args[0]);
75 		exec(filename, t->args);
76 		errstr(err, sizeof(err));
77 	}
78 	snprint(status, sizeof(status), "%s: can't exec: %s", t->args[0], err);
79 	if(t->wfd > 0)
80 		write(t->wfd, status, strlen(status));
81 	_exits(status);
82 }
83 
84 void*
85 oscmd(char **args, int nice, char *dir, int *fd)
86 {
87 	Targ *t;
88 	int spin, *spinptr, fd0[2], fd1[2], fd2[2], wfd[2], n;
89 	Dir *d;
90 
91 	up->genbuf[0] = 0;
92 	t = mallocz(sizeof(*t), 1);
93 	if(t == nil)
94 		return nil;
95 	t->args = args;
96 	t->dir = dir;
97 	t->nice = nice;
98 	fd0[0] = fd0[1] = -1;
99 	fd1[0] = fd1[1] = -1;
100 	fd2[0] = fd2[1] = -1;
101 	wfd[0] = wfd[1] = -1;
102 	if(dir != nil){
103 		d = dirstat(dir);
104 		if(d == nil)
105 			goto Error;
106 		free(d);
107 	}
108 	if(pipe(fd0) < 0 || pipe(fd1) < 0 || pipe(fd2) < 0 || pipe(wfd) < 0)
109 		goto Error;
110 
111 	spinptr = &spin;
112 	spin = 1;
113 
114 	t->fd[0] = fd0[0];
115 	t->fd[1] = fd1[1];
116 	t->fd[2] = fd2[1];
117 	t->wfd = wfd[1];
118 	t->spin = spinptr;
119 	switch(rfork(RFPROC|RFMEM|RFREND|RFNOTEG|RFFDG|RFNAMEG|RFENVG)) {
120 	case -1:
121 		goto Error;
122 	case 0:
123 		/* if child returns first from rfork, its call to vstack replaces ... */
124 		vstack(t);
125 		/* ... parent's return address from rfork and parent returns here */
126 	default:
127 		/* if parent returns first from rfork, it comes here */
128 		/* can't call anything: on shared stack until child releases spin in exectramp */
129 		while(*spinptr)
130 			;
131 		break;
132 	}
133 
134 	close(fd0[0]);
135 	close(fd1[1]);
136 	close(fd2[1]);
137 	close(wfd[1]);
138 
139 	n = read(wfd[0], up->genbuf, sizeof(up->genbuf)-1);
140 	close(wfd[0]);
141 	if(n > 0){
142 		close(fd0[1]);
143 		close(fd1[0]);
144 		close(fd2[0]);
145 		up->genbuf[n] = 0;
146 		errstr(up->genbuf, sizeof(up->genbuf));
147 		free(t);
148 		return nil;
149 	}
150 
151 	fd[0] = fd0[1];
152 	fd[1] = fd1[0];
153 	fd[2] = fd2[0];
154 	return t;
155 
156 Error:
157 	errstr(up->genbuf, sizeof(up->genbuf));	/* save the message before close */
158 	close(fd0[0]);
159 	close(fd0[1]);
160 	close(fd1[0]);
161 	close(fd1[1]);
162 	close(fd2[0]);
163 	close(fd2[1]);
164 	close(wfd[0]);
165 	close(wfd[1]);
166 	free(t);
167 	errstr(up->genbuf, sizeof(up->genbuf));
168 	return nil;
169 }
170 
171 int
172 oscmdkill(void *a)
173 {
174 	Targ *t = a;
175 
176 	return postnote(PNGROUP, t->pid, "kill");
177 }
178 
179 int
180 oscmdwait(void*, char *buf, int n)
181 {
182 	return await(buf, n);
183 }
184 
185 void
186 oscmdfree(void *a)
187 {
188 	free(a);
189 }
190