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