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;
116 char *s, *ewd=&wd[8192], *stop;
117 struct io *f;
118 var *ifs = vlook("ifs");
119 word *v, *nextv;
120 int pfd[2];
121 int pid;
122 stop = ifs->val?ifs->val->word:"";
123 if(pipe(pfd)<0){
124 Xerror("can't make pipe");
125 return;
127 switch(pid = fork()){
128 case -1:
129 Xerror("try again");
130 close(pfd[PRD]);
131 close(pfd[PWR]);
132 return;
133 case 0:
134 clearwaitpids();
135 close(pfd[PRD]);
136 start(runq->code, runq->pc+1, runq->local);
137 pushredir(ROPEN, pfd[PWR], 1);
138 return;
139 default:
140 addwaitpid(pid);
141 close(pfd[PWR]);
142 f = openfd(pfd[PRD]);
143 s = wd;
144 v = 0;
145 while((c = rchr(f))!=EOF){
146 if(strchr(stop, c) || s==ewd){
147 if(s!=wd){
148 *s='\0';
149 v = newword(wd, v);
150 s = wd;
153 else *s++=c;
155 if(s!=wd){
156 *s='\0';
157 v = newword(wd, v);
159 closeio(f);
160 Waitfor(pid, 0);
161 /* v points to reversed arglist -- reverse it onto argv */
162 while(v){
163 nextv = v->next;
164 v->next = runq->argv->words;
165 runq->argv->words = v;
166 v = nextv;
168 p->pc = p->code[p->pc].i;
169 return;
173 void
174 Xpipefd(void)
176 struct thread *p = runq;
177 int pc = p->pc, pid;
178 char name[40];
179 int pfd[2];
180 struct { int sidefd, mainfd; } fd[2], *r, *w;
182 r = &fd[0];
183 w = &fd[1];
184 switch(p->code[pc].i){
185 case READ:
186 w = nil;
187 break;
188 case WRITE:
189 r = nil;
192 if(r){
193 if(pipe(pfd)<0){
194 Xerror("can't get pipe");
195 return;
197 r->sidefd = pfd[PWR];
198 r->mainfd = pfd[PRD];
200 if(w){
201 if(pipe(pfd)<0){
202 Xerror("can't get pipe");
203 return;
205 w->sidefd = pfd[PRD];
206 w->mainfd = pfd[PWR];
208 switch(pid = fork()){
209 case -1:
210 Xerror("try again");
211 break;
212 case 0:
213 clearwaitpids();
214 start(p->code, pc+2, runq->local);
215 if(r){
216 close(r->mainfd);
217 pushredir(ROPEN, r->sidefd, 1);
219 if(w){
220 close(w->mainfd);
221 pushredir(ROPEN, w->sidefd, 0);
223 runq->ret = 0;
224 break;
225 default:
226 addwaitpid(pid);
227 if(w){
228 close(w->sidefd);
229 pushredir(ROPEN, w->mainfd, w->mainfd); /* so that Xpopredir can close it later */
230 strcpy(name, Fdprefix);
231 inttoascii(name+strlen(name), w->mainfd);
232 pushword(name);
234 if(r){
235 close(r->sidefd);
236 pushredir(ROPEN, r->mainfd, r->mainfd);
237 strcpy(name, Fdprefix);
238 inttoascii(name+strlen(name), r->mainfd);
239 pushword(name);
241 p->pc = p->code[pc+1].i;
242 break;
246 void
247 Xsubshell(void)
249 int pid;
250 switch(pid = fork()){
251 case -1:
252 Xerror("try again");
253 break;
254 case 0:
255 clearwaitpids();
256 start(runq->code, runq->pc+1, runq->local);
257 runq->ret = 0;
258 break;
259 default:
260 addwaitpid(pid);
261 Waitfor(pid, 1);
262 runq->pc = runq->code[runq->pc].i;
263 break;
267 int
268 execforkexec(void)
270 int pid;
271 int n;
272 char buf[ERRMAX];
274 switch(pid = fork()){
275 case -1:
276 return -1;
277 case 0:
278 clearwaitpids();
279 pushword("exec");
280 execexec();
281 strcpy(buf, "can't exec: ");
282 n = strlen(buf);
283 errstr(buf+n, ERRMAX-n);
284 Exit(buf);
286 addwaitpid(pid);
287 return pid;