Blob


1 /*
2 * Maybe `simple' is a misnomer.
3 */
4 #include "rc.h"
5 #include "getflags.h"
6 #include "exec.h"
7 #include "io.h"
8 #include "fns.h"
9 /*
10 * Search through the following code to see if we're just going to exit.
11 */
12 int
13 exitnext(void){
14 union code *c=&runq->code[runq->pc];
15 while(c->f==Xpopredir) c++;
16 return c->f==Xexit;
17 }
18 void Xsimple(void){
19 word *a;
20 thread *p=runq;
21 var *v;
22 struct builtin *bp;
23 int pid, n;
24 char buf[ERRMAX];
25 globlist();
26 a=runq->argv->words;
27 if(a==0){
28 Xerror1("empty argument list");
29 return;
30 }
31 if(flag['x'])
32 pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
33 v=gvlook(a->word);
34 if(v->fn)
35 execfunc(v);
36 else{
37 if(strcmp(a->word, "builtin")==0){
38 if(count(a)==1){
39 pfmt(err, "builtin: empty argument list\n");
40 setstatus("empty arg list");
41 poplist();
42 return;
43 }
44 a=a->next;
45 popword();
46 }
47 for(bp=Builtin;bp->name;bp++)
48 if(strcmp(a->word, bp->name)==0){
49 (*bp->fnc)();
50 return;
51 }
52 if(exitnext()){
53 /* fork and wait is redundant */
54 pushword("exec");
55 execexec();
56 Xexit();
57 }
58 else{
59 flush(err);
60 Updenv(); /* necessary so changes don't go out again */
61 switch(pid=fork()){
62 case -1:
63 Xerror("try again");
64 return;
65 case 0:
66 rfork(RFNOTEG);
67 pushword("exec");
68 execexec();
69 strcpy(buf, "can't exec: ");
70 n = strlen(buf);
71 errstr(buf+n, ERRMAX-n);
72 Exit(buf);
73 default:
74 kidpid = pid;
75 poplist();
76 /* interrupts don't get us out */
77 while(Waitfor(pid, 1) < 0)
78 ;
79 kidpid = 0;
80 }
81 }
82 }
83 }
84 struct word nullpath={ "", 0};
85 void doredir(redir *rp)
86 {
87 if(rp){
88 doredir(rp->next);
89 switch(rp->type){
90 case ROPEN:
91 if(rp->from!=rp->to){
92 Dup(rp->from, rp->to);
93 close(rp->from);
94 }
95 break;
96 case RDUP: Dup(rp->from, rp->to); break;
97 case RCLOSE: close(rp->from); break;
98 }
99 }
101 word *searchpath(char *w){
102 word *path;
103 if(strncmp(w, "/", 1)==0
104 || strncmp(w, "#", 1)==0
105 || strncmp(w, "./", 2)==0
106 || strncmp(w, "../", 3)==0
107 || (path=vlook("path")->val)==0)
108 path=&nullpath;
109 return path;
111 void execexec(void){
112 popword(); /* "exec" */
113 if(runq->argv->words==0){
114 Xerror1("empty argument list");
115 return;
117 doredir(runq->redir);
118 Execute(runq->argv->words, searchpath(runq->argv->words->word));
119 poplist();
121 void execfunc(var *func)
123 word *starval;
124 popword();
125 starval=runq->argv->words;
126 runq->argv->words=0;
127 poplist();
128 start(func->fn, func->pc, (struct var *)0);
129 runq->local=newvar(strdup("*"), runq->local);
130 runq->local->val=starval;
131 runq->local->changed=1;
133 int dochdir(char *word){
134 /* report to /dev/wdir if it exists and we're interactive */
135 static int wdirfd = -2;
136 if(chdir(word)<0) return -1;
137 if(flag['i']!=0){
138 if(wdirfd==-2) /* try only once */
139 wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
140 if(wdirfd>=0)
141 write(wdirfd, word, strlen(word));
143 return 1;
145 void execcd(void){
146 word *a=runq->argv->words;
147 word *cdpath;
148 char dir[512];
149 setstatus("can't cd");
150 cdpath=vlook("cdpath")->val;
151 switch(count(a)){
152 default:
153 pfmt(err, "Usage: cd [directory]\n");
154 break;
155 case 2:
156 if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
157 for(;cdpath;cdpath=cdpath->next){
158 strcpy(dir, cdpath->word);
159 if(dir[0]) strcat(dir, "/");
160 strcat(dir, a->next->word);
161 if(dochdir(dir)>=0){
162 if(strlen(cdpath->word)
163 && strcmp(cdpath->word, ".")!=0)
164 pfmt(err, "%s\n", dir);
165 setstatus("");
166 break;
169 if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
170 break;
171 case 1:
172 a=vlook("home")->val;
173 if(count(a)>=1){
174 if(dochdir(a->word)>=0)
175 setstatus("");
176 else
177 pfmt(err, "Can't cd %s: %r\n", a->word);
179 else
180 pfmt(err, "Can't cd -- $home empty\n");
181 break;
183 poplist();
185 void execexit(void){
186 switch(count(runq->argv->words)){
187 default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
188 case 2: setstatus(runq->argv->words->next->word);
189 case 1: Xexit();
192 void execshift(void){
193 int n;
194 word *a;
195 var *star;
196 switch(count(runq->argv->words)){
197 default:
198 pfmt(err, "Usage: shift [n]\n");
199 setstatus("shift usage");
200 poplist();
201 return;
202 case 2: n=atoi(runq->argv->words->next->word); break;
203 case 1: n=1; break;
205 star=vlook("*");
206 for(;n && star->val;--n){
207 a=star->val->next;
208 efree(star->val->word);
209 efree((char *)star->val);
210 star->val=a;
211 star->changed=1;
213 setstatus("");
214 poplist();
216 int octal(char *s)
218 int n=0;
219 while(*s==' ' || *s=='\t' || *s=='\n') s++;
220 while('0'<=*s && *s<='7') n=n*8+*s++-'0';
221 return n;
223 int mapfd(int fd)
225 redir *rp;
226 for(rp=runq->redir;rp;rp=rp->next){
227 switch(rp->type){
228 case RCLOSE:
229 if(rp->from==fd) fd=-1;
230 break;
231 case RDUP:
232 case ROPEN:
233 if(rp->to==fd) fd=rp->from;
234 break;
237 return fd;
239 union code rdcmds[4];
240 void execcmds(io *f)
242 static int first=1;
243 if(first){
244 rdcmds[0].i=1;
245 rdcmds[1].f=Xrdcmds;
246 rdcmds[2].f=Xreturn;
247 first=0;
249 start(rdcmds, 1, runq->local);
250 runq->cmdfd=f;
251 runq->iflast=0;
253 void execeval(void){
254 char *cmdline, *s, *t;
255 int len=0;
256 word *ap;
257 if(count(runq->argv->words)<=1){
258 Xerror1("Usage: eval cmd ...");
259 return;
261 eflagok=1;
262 for(ap=runq->argv->words->next;ap;ap=ap->next)
263 len+=1+strlen(ap->word);
264 cmdline=emalloc(len);
265 s=cmdline;
266 for(ap=runq->argv->words->next;ap;ap=ap->next){
267 for(t=ap->word;*t;) *s++=*t++;
268 *s++=' ';
270 s[-1]='\n';
271 poplist();
272 execcmds(opencore(cmdline, len));
273 efree(cmdline);
275 union code dotcmds[14];
276 void execdot(void){
277 int iflag=0;
278 int fd;
279 list *av;
280 thread *p=runq;
281 char *zero;
282 static int first=1;
283 char file[512];
284 word *path;
285 if(first){
286 dotcmds[0].i=1;
287 dotcmds[1].f=Xmark;
288 dotcmds[2].f=Xword;
289 dotcmds[3].s="0";
290 dotcmds[4].f=Xlocal;
291 dotcmds[5].f=Xmark;
292 dotcmds[6].f=Xword;
293 dotcmds[7].s="*";
294 dotcmds[8].f=Xlocal;
295 dotcmds[9].f=Xrdcmds;
296 dotcmds[10].f=Xunlocal;
297 dotcmds[11].f=Xunlocal;
298 dotcmds[12].f=Xreturn;
299 first=0;
301 else
302 eflagok=1;
303 popword();
304 if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
305 iflag=1;
306 popword();
308 /* get input file */
309 if(p->argv->words==0){
310 Xerror1("Usage: . [-i] file [arg ...]");
311 return;
313 zero=strdup(p->argv->words->word);
314 popword();
315 fd=-1;
316 for(path=searchpath(zero);path;path=path->next){
317 strcpy(file, path->word);
318 if(file[0]) strcat(file, "/");
319 strcat(file, zero);
320 if((fd=open(file, 0))>=0) break;
321 if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
322 fd=Dup1(0);
323 if(fd>=0) break;
326 if(fd<0){
327 pfmt(err, "%s: ", zero);
328 setstatus("can't open");
329 Xerror(".: can't open");
330 return;
332 /* set up for a new command loop */
333 start(dotcmds, 1, (struct var *)0);
334 pushredir(RCLOSE, fd, 0);
335 runq->cmdfile=zero;
336 runq->cmdfd=openfd(fd);
337 runq->iflag=iflag;
338 runq->iflast=0;
339 /* push $* value */
340 pushlist();
341 runq->argv->words=p->argv->words;
342 /* free caller's copy of $* */
343 av=p->argv;
344 p->argv=av->next;
345 efree((char *)av);
346 /* push $0 value */
347 pushlist();
348 pushword(zero);
349 ndot++;
351 void execflag(void){
352 char *letter, *val;
353 switch(count(runq->argv->words)){
354 case 2:
355 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
356 break;
357 case 3:
358 letter=runq->argv->words->next->word;
359 val=runq->argv->words->next->next->word;
360 if(strlen(letter)==1){
361 if(strcmp(val, "+")==0){
362 flag[(uchar)letter[0]]=flagset;
363 break;
365 if(strcmp(val, "-")==0){
366 flag[(uchar)letter[0]]=0;
367 break;
370 default:
371 Xerror1("Usage: flag [letter] [+-]");
372 return;
374 poplist();
376 void execwhatis(void){ /* mildly wrong -- should fork before writing */
377 word *a, *b, *path;
378 var *v;
379 struct builtin *bp;
380 char file[512];
381 struct io out[1];
382 int found, sep;
383 a=runq->argv->words->next;
384 if(a==0){
385 Xerror1("Usage: whatis name ...");
386 return;
388 setstatus("");
389 out->fd=mapfd(1);
390 out->bufp=out->buf;
391 out->ebuf=&out->buf[NBUF];
392 out->strp=0;
393 for(;a;a=a->next){
394 v=vlook(a->word);
395 if(v->val){
396 pfmt(out, "%s=", a->word);
397 if(v->val->next==0)
398 pfmt(out, "%q\n", v->val->word);
399 else{
400 sep='(';
401 for(b=v->val;b && b->word;b=b->next){
402 pfmt(out, "%c%q", sep, b->word);
403 sep=' ';
405 pfmt(out, ")\n");
407 found=1;
409 else
410 found=0;
411 v=gvlook(a->word);
412 if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
413 else{
414 for(bp=Builtin;bp->name;bp++)
415 if(strcmp(a->word, bp->name)==0){
416 pfmt(out, "builtin %s\n", a->word);
417 break;
419 if(!bp->name){
420 for(path=searchpath(a->word);path;path=path->next){
421 strcpy(file, path->word);
422 if(file[0]) strcat(file, "/");
423 strcat(file, a->word);
424 if(Executable(file)){
425 pfmt(out, "%s\n", file);
426 break;
429 if(!path && !found){
430 pfmt(err, "%s: not found\n", a->word);
431 setstatus("not found");
436 poplist();
437 flush(err);
439 void execwait(void){
440 switch(count(runq->argv->words)){
441 default: Xerror1("Usage: wait [pid]"); return;
442 case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
443 case 1: Waitfor(-1, 0); break;
445 poplist();