xref: /plan9-contrib/sys/src/cmd/rc/havefork.c (revision 4446a870cd0cc88dde8a2b5b72feb64f4ae5b744)
1 #include "rc.h"
2 #include "exec.h"
3 #include "io.h"
4 #include "fns.h"
5 
6 int havefork = 1;
7 
8 void
Xasync(void)9 Xasync(void)
10 {
11 	int null = open("/dev/null", 0);
12 	int pid;
13 	char npid[10];
14 	if(null<0){
15 		Xerror("Can't open /dev/null\n");
16 		return;
17 	}
18 	switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
19 	case -1:
20 		close(null);
21 		Xerror("try again");
22 		break;
23 	case 0:
24 		clearwaitpids();
25 		pushredir(ROPEN, null, 0);
26 		start(runq->code, runq->pc+1, runq->local);
27 		runq->ret = 0;
28 		break;
29 	default:
30 		addwaitpid(pid);
31 		close(null);
32 		runq->pc = runq->code[runq->pc].i;
33 		inttoascii(npid, pid);
34 		setvar("apid", newword(npid, (word *)0));
35 		break;
36 	}
37 }
38 
39 void
Xpipe(void)40 Xpipe(void)
41 {
42 	struct thread *p = runq;
43 	int pc = p->pc, forkid;
44 	int lfd = p->code[pc++].i;
45 	int rfd = p->code[pc++].i;
46 	int pfd[2];
47 	if(pipe(pfd)<0){
48 		Xerror("can't get pipe");
49 		return;
50 	}
51 	switch(forkid = fork()){
52 	case -1:
53 		Xerror("try again");
54 		break;
55 	case 0:
56 		clearwaitpids();
57 		start(p->code, pc+2, runq->local);
58 		runq->ret = 0;
59 		close(pfd[PRD]);
60 		pushredir(ROPEN, pfd[PWR], lfd);
61 		break;
62 	default:
63 		addwaitpid(forkid);
64 		start(p->code, p->code[pc].i, runq->local);
65 		close(pfd[PWR]);
66 		pushredir(ROPEN, pfd[PRD], rfd);
67 		p->pc = p->code[pc+1].i;
68 		p->pid = forkid;
69 		break;
70 	}
71 }
72 
73 /*
74  * Who should wait for the exit from the fork?
75  */
76 
77 void
Xbackq(void)78 Xbackq(void)
79 {
80 	int n, pid;
81 	int pfd[2];
82 	char *stop;
83 	char utf[UTFmax+1];
84 	io *f, *wd;
85 	word *v, *nextv;
86 	Rune r;
87 
88  	stop = "";
89  	if(runq->argv && runq->argv->words)
90  		stop = runq->argv->words->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 		wd = openstr();
112 		v = nil;
113 		/* rutf requires at least UTFmax+1 bytes in utf */
114 		while((n = rutf(f, utf, &r)) != EOF){
115 			utf[n] = '\0';
116 			if(utfutf(stop, utf) == nil)
117 				pstr(wd, utf);	/* append utf to word */
118 			else
119 				/*
120 				 * utf/r is an ifs rune (e.g., \t, \n), thus
121 				 * ends the current word, if any.
122 				 */
123 				if(*(char *)wd->strp != '\0'){
124 					v = newword((char *)wd->strp, v);
125 					rewind(wd);
126 				}
127 		}
128 		if(*(char *)wd->strp != '\0')
129 			v = newword((char *)wd->strp, v);
130 		closeio(wd);
131 		closeio(f);
132 		Waitfor(pid, 0);
133 		poplist();	/* ditch split in "stop" */
134 		/* v points to reversed arglist -- reverse it onto argv */
135 		while(v){
136 			nextv = v->next;
137 			v->next = runq->argv->words;
138 			runq->argv->words = v;
139 			v = nextv;
140 		}
141 		runq->pc = runq->code[runq->pc].i;
142 		return;
143 	}
144 }
145 
146 void
Xpipefd(void)147 Xpipefd(void)
148 {
149 	struct thread *p = runq;
150 	int pc = p->pc, pid;
151 	char name[40];
152 	int pfd[2];
153 	int sidefd, mainfd;
154 	if(pipe(pfd)<0){
155 		Xerror("can't get pipe");
156 		return;
157 	}
158 	if(p->code[pc].i==READ){
159 		sidefd = pfd[PWR];
160 		mainfd = pfd[PRD];
161 	}
162 	else{
163 		sidefd = pfd[PRD];
164 		mainfd = pfd[PWR];
165 	}
166 	switch(pid = fork()){
167 	case -1:
168 		Xerror("try again");
169 		break;
170 	case 0:
171 		clearwaitpids();
172 		start(p->code, pc+2, runq->local);
173 		close(mainfd);
174 		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
175 		runq->ret = 0;
176 		break;
177 	default:
178 		addwaitpid(pid);
179 		close(sidefd);
180 		pushredir(ROPEN, mainfd, mainfd);
181 		shuffleredir();	/* shuffle redir to bottom of stack for turfredir() */
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