xref: /plan9-contrib/sys/src/cmd/rc/havefork.c (revision 6891d8578618fb7ccda4a131c122d4d0e6580c4b)
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 		/*
114 		 * this isn't quite right for utf.  stop could have utf
115 		 * in it, and we're processing the input as bytes, not
116 		 * utf encodings of runes.  further, if we run out of
117 		 * room in wd, we can chop in the middle of a utf encoding
118 		 * (not to mention stepping on one of the bytes).
119 		 * presotto's Strings seem like the right data structure here.
120 		 */
121 		while((c = rchr(f))!=EOF){
122 			if(strchr(stop, c) || s==ewd){
123 				if(s!=wd){
124 					*s='\0';
125 					v = newword(wd, v);
126 					s = wd;
127 				}
128 			}
129 			else *s++=c;
130 		}
131 		if(s!=wd){
132 			*s='\0';
133 			v = newword(wd, v);
134 		}
135 		closeio(f);
136 		Waitfor(pid, 0);
137 		/* v points to reversed arglist -- reverse it onto argv */
138 		while(v){
139 			nextv = v->next;
140 			v->next = runq->argv->words;
141 			runq->argv->words = v;
142 			v = nextv;
143 		}
144 		runq->pc = runq->code[runq->pc].i;
145 		return;
146 	}
147 }
148 
149 void
150 Xpipefd(void)
151 {
152 	struct thread *p = runq;
153 	int pc = p->pc, pid;
154 	char name[40];
155 	int pfd[2];
156 	int sidefd, mainfd;
157 	if(pipe(pfd)<0){
158 		Xerror("can't get pipe");
159 		return;
160 	}
161 	if(p->code[pc].i==READ){
162 		sidefd = pfd[PWR];
163 		mainfd = pfd[PRD];
164 	}
165 	else{
166 		sidefd = pfd[PRD];
167 		mainfd = pfd[PWR];
168 	}
169 	switch(pid = fork()){
170 	case -1:
171 		Xerror("try again");
172 		break;
173 	case 0:
174 		clearwaitpids();
175 		start(p->code, pc+2, runq->local);
176 		close(mainfd);
177 		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
178 		runq->ret = 0;
179 		break;
180 	default:
181 		addwaitpid(pid);
182 		close(sidefd);
183 		pushredir(ROPEN, mainfd, mainfd);	/* isn't this a noop? */
184 		strcpy(name, Fdprefix);
185 		inttoascii(name+strlen(name), mainfd);
186 		pushword(name);
187 		p->pc = p->code[pc+1].i;
188 		break;
189 	}
190 }
191 
192 void
193 Xsubshell(void)
194 {
195 	int pid;
196 	switch(pid = fork()){
197 	case -1:
198 		Xerror("try again");
199 		break;
200 	case 0:
201 		clearwaitpids();
202 		start(runq->code, runq->pc+1, runq->local);
203 		runq->ret = 0;
204 		break;
205 	default:
206 		addwaitpid(pid);
207 		Waitfor(pid, 1);
208 		runq->pc = runq->code[runq->pc].i;
209 		break;
210 	}
211 }
212 
213 int
214 execforkexec(void)
215 {
216 	int pid;
217 	int n;
218 	char buf[ERRMAX];
219 
220 	switch(pid = fork()){
221 	case -1:
222 		return -1;
223 	case 0:
224 		clearwaitpids();
225 		pushword("exec");
226 		execexec();
227 		strcpy(buf, "can't exec: ");
228 		n = strlen(buf);
229 		errstr(buf+n, ERRMAX-n);
230 		Exit(buf);
231 	}
232 	addwaitpid(pid);
233 	return pid;
234 }
235