Blob


1 #include <u.h>
2 #include <signal.h>
3 #if defined(PLAN9PORT) && defined(__sun__)
4 # define BSD_COMP /* sigh. for TIOCNOTTY */
5 #endif
6 #include <sys/ioctl.h>
7 #include "rc.h"
8 #include "getflags.h"
9 #include "exec.h"
10 #include "io.h"
11 #include "fns.h"
13 int havefork = 1;
15 void
16 Xasync(void)
17 {
18 int null = open("/dev/null", 0);
19 int tty;
20 int pid;
21 char npid[10];
22 if(null<0){
23 Xerror("Can't open /dev/null\n");
24 return;
25 }
26 switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
27 case -1:
28 close(null);
29 Xerror("try again");
30 break;
31 case 0:
32 clearwaitpids();
33 /*
34 * I don't know what the right thing to do here is,
35 * so this is all experimentally determined.
36 * If we just dup /dev/null onto 0, then running
37 * ssh foo & will reopen /dev/tty, try to read a password,
38 * get a signal, and repeat, in a tight loop, forever.
39 * Arguably this is a bug in ssh (it behaves the same
40 * way under bash as under rc) but I'm fixing it here
41 * anyway. If we dissociate the process from the tty,
42 * then it won't be able to open /dev/tty ever again.
43 * The SIG_IGN on SIGTTOU makes writing the tty
44 * (via fd 1 or 2, for example) succeed even though
45 * our pgrp is not the terminal's controlling pgrp.
46 */
47 if((tty = open("/dev/tty", OREAD)) >= 0){
48 /*
49 * Should make reads of tty fail, writes succeed.
50 */
51 signal(SIGTTIN, SIG_IGN);
52 signal(SIGTTOU, SIG_IGN);
53 ioctl(tty, TIOCNOTTY);
54 close(tty);
55 }
56 if(isatty(0))
57 pushredir(ROPEN, null, 0);
58 else
59 close(null);
60 start(runq->code, runq->pc+1, runq->local);
61 runq->ret = 0;
62 break;
63 default:
64 addwaitpid(pid);
65 close(null);
66 runq->pc = runq->code[runq->pc].i;
67 inttoascii(npid, pid);
68 setvar("apid", newword(npid, (word *)0));
69 break;
70 }
71 }
73 void
74 Xpipe(void)
75 {
76 struct thread *p = runq;
77 int pc = p->pc, forkid;
78 int lfd = p->code[pc++].i;
79 int rfd = p->code[pc++].i;
80 int pfd[2];
81 if(pipe(pfd)<0){
82 Xerror("can't get pipe");
83 return;
84 }
85 switch(forkid = fork()){
86 case -1:
87 Xerror("try again");
88 break;
89 case 0:
90 clearwaitpids();
91 start(p->code, pc+2, runq->local);
92 runq->ret = 0;
93 close(pfd[PRD]);
94 pushredir(ROPEN, pfd[PWR], lfd);
95 break;
96 default:
97 addwaitpid(forkid);
98 start(p->code, p->code[pc].i, runq->local);
99 close(pfd[PWR]);
100 pushredir(ROPEN, pfd[PRD], rfd);
101 p->pc = p->code[pc+1].i;
102 p->pid = forkid;
103 break;
107 /*
108 * Who should wait for the exit from the fork?
109 */
110 void
111 Xbackq(void)
113 struct thread *p = runq;
114 char wd[8193];
115 int c, n;
116 char *s, *ewd=&wd[8192], *stop, *q;
117 struct io *f;
118 var *ifs = vlook("ifs");
119 word *v, *nextv;
120 int pfd[2];
121 int pid;
122 Rune r;
123 stop = ifs->val?ifs->val->word:"";
124 if(pipe(pfd)<0){
125 Xerror("can't make pipe");
126 return;
128 switch(pid = fork()){
129 case -1:
130 Xerror("try again");
131 close(pfd[PRD]);
132 close(pfd[PWR]);
133 return;
134 case 0:
135 clearwaitpids();
136 close(pfd[PRD]);
137 start(runq->code, runq->pc+1, runq->local);
138 pushredir(ROPEN, pfd[PWR], 1);
139 return;
140 default:
141 addwaitpid(pid);
142 close(pfd[PWR]);
143 f = openfd(pfd[PRD]);
144 s = wd;
145 v = 0;
146 while((c = rchr(f))!=EOF){
147 if(s != ewd) {
148 *s++ = c;
149 for(q=stop; *q; q+=n) {
150 n = chartorune(&r, q);
151 if(s-wd >= n && memcmp(s-n, q, n) == 0) {
152 s -= n;
153 goto stop;
156 continue;
158 stop:
159 if(s != wd) {
160 *s = '\0';
161 v = newword(wd, v);
163 s = wd;
165 if(s!=wd){
166 *s='\0';
167 v = newword(wd, v);
169 closeio(f);
170 Waitfor(pid, 0);
171 /* v points to reversed arglist -- reverse it onto argv */
172 while(v){
173 nextv = v->next;
174 v->next = runq->argv->words;
175 runq->argv->words = v;
176 v = nextv;
178 p->pc = p->code[p->pc].i;
179 return;
183 void
184 Xpipefd(void)
186 struct thread *p = runq;
187 int pc = p->pc, pid;
188 char name[40];
189 int pfd[2];
190 struct { int sidefd, mainfd; } fd[2], *r, *w;
192 r = &fd[0];
193 w = &fd[1];
194 switch(p->code[pc].i){
195 case READ:
196 w = nil;
197 break;
198 case WRITE:
199 r = nil;
202 if(r){
203 if(pipe(pfd)<0){
204 Xerror("can't get pipe");
205 return;
207 r->sidefd = pfd[PWR];
208 r->mainfd = pfd[PRD];
210 if(w){
211 if(pipe(pfd)<0){
212 Xerror("can't get pipe");
213 return;
215 w->sidefd = pfd[PRD];
216 w->mainfd = pfd[PWR];
218 switch(pid = fork()){
219 case -1:
220 Xerror("try again");
221 break;
222 case 0:
223 clearwaitpids();
224 start(p->code, pc+2, runq->local);
225 if(r){
226 close(r->mainfd);
227 pushredir(ROPEN, r->sidefd, 1);
229 if(w){
230 close(w->mainfd);
231 pushredir(ROPEN, w->sidefd, 0);
233 runq->ret = 0;
234 break;
235 default:
236 addwaitpid(pid);
237 if(w){
238 close(w->sidefd);
239 pushredir(ROPEN, w->mainfd, w->mainfd); /* so that Xpopredir can close it later */
240 strcpy(name, Fdprefix);
241 inttoascii(name+strlen(name), w->mainfd);
242 pushword(name);
244 if(r){
245 close(r->sidefd);
246 pushredir(ROPEN, r->mainfd, r->mainfd);
247 strcpy(name, Fdprefix);
248 inttoascii(name+strlen(name), r->mainfd);
249 pushword(name);
251 p->pc = p->code[pc+1].i;
252 break;
256 void
257 Xsubshell(void)
259 int pid;
260 switch(pid = fork()){
261 case -1:
262 Xerror("try again");
263 break;
264 case 0:
265 clearwaitpids();
266 start(runq->code, runq->pc+1, runq->local);
267 runq->ret = 0;
268 break;
269 default:
270 addwaitpid(pid);
271 Waitfor(pid, 1);
272 runq->pc = runq->code[runq->pc].i;
273 break;
277 int
278 execforkexec(void)
280 int pid;
281 int n;
282 char buf[ERRMAX];
284 switch(pid = fork()){
285 case -1:
286 return -1;
287 case 0:
288 clearwaitpids();
289 pushword("exec");
290 execexec();
291 strcpy(buf, "can't exec: ");
292 n = strlen(buf);
293 errstr(buf+n, ERRMAX-n);
294 Exit(buf);
296 addwaitpid(pid);
297 return pid;