xref: /plan9/sys/src/cmd/rc/havefork.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 #include "rc.h"
2 #include "getflags.h"
3 #include "exec.h"
4 #include "io.h"
5 #include "fns.h"
6 
7 int havefork = 1;
8 
9 void
10 Xasync(void)
11 {
12 	int null = open("/dev/null", 0);
13 	int pid;
14 	char npid[10];
15 	if(null<0){
16 		Xerror("Can't open /dev/null\n");
17 		return;
18 	}
19 	switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
20 	case -1:
21 		close(null);
22 		Xerror("try again");
23 		break;
24 	case 0:
25 		clearwaitpids();
26 		pushredir(ROPEN, null, 0);
27 		start(runq->code, runq->pc+1, runq->local);
28 		runq->ret = 0;
29 		break;
30 	default:
31 		addwaitpid(pid);
32 		close(null);
33 		runq->pc = runq->code[runq->pc].i;
34 		inttoascii(npid, pid);
35 		setvar("apid", newword(npid, (word *)0));
36 		break;
37 	}
38 }
39 
40 void
41 Xpipe(void)
42 {
43 	struct thread *p = runq;
44 	int pc = p->pc, forkid;
45 	int lfd = p->code[pc++].i;
46 	int rfd = p->code[pc++].i;
47 	int pfd[2];
48 	if(pipe(pfd)<0){
49 		Xerror("can't get pipe");
50 		return;
51 	}
52 	switch(forkid = fork()){
53 	case -1:
54 		Xerror("try again");
55 		break;
56 	case 0:
57 		clearwaitpids();
58 		start(p->code, pc+2, runq->local);
59 		runq->ret = 0;
60 		close(pfd[PRD]);
61 		pushredir(ROPEN, pfd[PWR], lfd);
62 		break;
63 	default:
64 		addwaitpid(forkid);
65 		start(p->code, p->code[pc].i, runq->local);
66 		close(pfd[PWR]);
67 		pushredir(ROPEN, pfd[PRD], rfd);
68 		p->pc = p->code[pc+1].i;
69 		p->pid = forkid;
70 		break;
71 	}
72 }
73 
74 enum { Wordmax = 8192, };
75 
76 /*
77  * Who should wait for the exit from the fork?
78  */
79 void
80 Xbackq(void)
81 {
82 	int c, pid;
83 	int pfd[2];
84 	char wd[Wordmax + 1];
85 	char *s, *ewd = &wd[Wordmax], *stop;
86 	struct io *f;
87 	var *ifs = vlook("ifs");
88 	word *v, *nextv;
89 
90 	stop = ifs->val? ifs->val->word: "";
91 	if(pipe(pfd)<0){
92 		Xerror("can't make pipe");
93 		return;
94 	}
95 	switch(pid = fork()){
96 	case -1:
97 		Xerror("try again");
98 		close(pfd[PRD]);
99 		close(pfd[PWR]);
100 		return;
101 	case 0:
102 		clearwaitpids();
103 		close(pfd[PRD]);
104 		start(runq->code, runq->pc+1, runq->local);
105 		pushredir(ROPEN, pfd[PWR], 1);
106 		return;
107 	default:
108 		addwaitpid(pid);
109 		close(pfd[PWR]);
110 		f = openfd(pfd[PRD]);
111 		s = wd;
112 		v = 0;
113 		while((c = rchr(f))!=EOF){
114 			if(strchr(stop, c) || s==ewd){
115 				if(s!=wd){
116 					*s='\0';
117 					v = newword(wd, v);
118 					s = wd;
119 				}
120 			}
121 			else *s++=c;
122 		}
123 		if(s!=wd){
124 			*s='\0';
125 			v = newword(wd, v);
126 		}
127 		closeio(f);
128 		Waitfor(pid, 0);
129 		/* v points to reversed arglist -- reverse it onto argv */
130 		while(v){
131 			nextv = v->next;
132 			v->next = runq->argv->words;
133 			runq->argv->words = v;
134 			v = nextv;
135 		}
136 		runq->pc = runq->code[runq->pc].i;
137 		return;
138 	}
139 }
140 
141 void
142 Xpipefd(void)
143 {
144 	struct thread *p = runq;
145 	int pc = p->pc, pid;
146 	char name[40];
147 	int pfd[2];
148 	int sidefd, mainfd;
149 	if(pipe(pfd)<0){
150 		Xerror("can't get pipe");
151 		return;
152 	}
153 	if(p->code[pc].i==READ){
154 		sidefd = pfd[PWR];
155 		mainfd = pfd[PRD];
156 	}
157 	else{
158 		sidefd = pfd[PRD];
159 		mainfd = pfd[PWR];
160 	}
161 	switch(pid = fork()){
162 	case -1:
163 		Xerror("try again");
164 		break;
165 	case 0:
166 		clearwaitpids();
167 		start(p->code, pc+2, runq->local);
168 		close(mainfd);
169 		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
170 		runq->ret = 0;
171 		break;
172 	default:
173 		addwaitpid(pid);
174 		close(sidefd);
175 		pushredir(ROPEN, mainfd, mainfd);	/* isn't this a noop? */
176 		strcpy(name, Fdprefix);
177 		inttoascii(name+strlen(name), mainfd);
178 		pushword(name);
179 		p->pc = p->code[pc+1].i;
180 		break;
181 	}
182 }
183 
184 void
185 Xsubshell(void)
186 {
187 	int pid;
188 	switch(pid = fork()){
189 	case -1:
190 		Xerror("try again");
191 		break;
192 	case 0:
193 		clearwaitpids();
194 		start(runq->code, runq->pc+1, runq->local);
195 		runq->ret = 0;
196 		break;
197 	default:
198 		addwaitpid(pid);
199 		Waitfor(pid, 1);
200 		runq->pc = runq->code[runq->pc].i;
201 		break;
202 	}
203 }
204 
205 int
206 execforkexec(void)
207 {
208 	int pid;
209 	int n;
210 	char buf[ERRMAX];
211 
212 	switch(pid = fork()){
213 	case -1:
214 		return -1;
215 	case 0:
216 		clearwaitpids();
217 		pushword("exec");
218 		execexec();
219 		strcpy(buf, "can't exec: ");
220 		n = strlen(buf);
221 		errstr(buf+n, ERRMAX-n);
222 		Exit(buf);
223 	}
224 	addwaitpid(pid);
225 	return pid;
226 }
227