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 }
19 void
20 Xsimple(void)
21 {
22 word *a;
23 thread *p = runq;
24 var *v;
25 struct builtin *bp;
26 int pid;
27 globlist();
28 a = runq->argv->words;
29 if(a==0){
30 Xerror1("empty argument list");
31 return;
32 }
33 if(flag['x'])
34 pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
35 v = gvlook(a->word);
36 if(v->fn)
37 execfunc(v);
38 else{
39 if(strcmp(a->word, "builtin")==0){
40 if(count(a)==1){
41 pfmt(err, "builtin: empty argument list\n");
42 setstatus("empty arg list");
43 poplist();
44 return;
45 }
46 a = a->next;
47 popword();
48 }
49 for(bp = Builtin;bp->name;bp++)
50 if(strcmp(a->word, bp->name)==0){
51 (*bp->fnc)();
52 return;
53 }
54 if(exitnext()){
55 /* fork and wait is redundant */
56 pushword("exec");
57 execexec();
58 Xexit();
59 }
60 else{
61 flush(err);
62 Updenv(); /* necessary so changes don't go out again */
63 if((pid = execforkexec()) < 0){
64 Xerror("try again");
65 return;
66 }
68 /* interrupts don't get us out */
69 poplist();
70 while(Waitfor(pid, 1) < 0)
71 ;
72 }
73 }
74 }
75 struct word nullpath = { "", 0};
77 void
78 doredir(redir *rp)
79 {
80 if(rp){
81 doredir(rp->next);
82 switch(rp->type){
83 case ROPEN:
84 if(rp->from!=rp->to){
85 Dup(rp->from, rp->to);
86 close(rp->from);
87 }
88 break;
89 case RDUP:
90 Dup(rp->from, rp->to);
91 break;
92 case RCLOSE:
93 close(rp->from);
94 break;
95 }
96 }
97 }
99 word*
100 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;
112 void
113 execexec(void)
115 popword(); /* "exec" */
116 if(runq->argv->words==0){
117 Xerror1("empty argument list");
118 return;
120 doredir(runq->redir);
121 Execute(runq->argv->words, searchpath(runq->argv->words->word));
122 poplist();
125 void
126 execfunc(var *func)
128 word *starval;
129 popword();
130 starval = runq->argv->words;
131 runq->argv->words = 0;
132 poplist();
133 start(func->fn, func->pc, runq->local);
134 runq->local = newvar(strdup("*"), runq->local);
135 runq->local->val = starval;
136 runq->local->changed = 1;
139 int
140 dochdir(char *word)
142 /* report to /dev/wdir if it exists and we're interactive */
143 static int wdirfd = -2;
144 if(chdir(word)<0) return -1;
145 if(flag['i']!=0){
146 if(wdirfd==-2) /* try only once */
147 wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
148 if(wdirfd>=0)
149 write(wdirfd, word, strlen(word));
151 return 1;
154 void
155 execcd(void)
157 word *a = runq->argv->words;
158 word *cdpath;
159 char dir[512];
160 setstatus("can't cd");
161 cdpath = vlook("cdpath")->val;
162 switch(count(a)){
163 default:
164 pfmt(err, "Usage: cd [directory]\n");
165 break;
166 case 2:
167 if(a->next->word[0]=='/' || cdpath==0)
168 cdpath=&nullpath;
169 for(;cdpath;cdpath = cdpath->next){
170 strcpy(dir, cdpath->word);
171 if(dir[0])
172 strcat(dir, "/");
173 strcat(dir, a->next->word);
174 if(dochdir(dir)>=0){
175 if(strlen(cdpath->word)
176 && strcmp(cdpath->word, ".")!=0)
177 pfmt(err, "%s\n", dir);
178 setstatus("");
179 break;
182 if(cdpath==0)
183 pfmt(err, "Can't cd %s: %r\n", a->next->word);
184 break;
185 case 1:
186 a = vlook("home")->val;
187 if(count(a)>=1){
188 if(dochdir(a->word)>=0)
189 setstatus("");
190 else
191 pfmt(err, "Can't cd %s: %r\n", a->word);
193 else
194 pfmt(err, "Can't cd -- $home empty\n");
195 break;
197 poplist();
200 void
201 execexit(void)
203 switch(count(runq->argv->words)){
204 default:
205 pfmt(err, "Usage: exit [status]\nExiting anyway\n");
206 case 2:
207 setstatus(runq->argv->words->next->word);
208 case 1: Xexit();
212 void
213 execshift(void)
215 int n;
216 word *a;
217 var *star;
218 switch(count(runq->argv->words)){
219 default:
220 pfmt(err, "Usage: shift [n]\n");
221 setstatus("shift usage");
222 poplist();
223 return;
224 case 2:
225 n = atoi(runq->argv->words->next->word);
226 break;
227 case 1:
228 n = 1;
229 break;
231 star = vlook("*");
232 for(;n && star->val;--n){
233 a = star->val->next;
234 efree(star->val->word);
235 efree((char *)star->val);
236 star->val = a;
237 star->changed = 1;
239 setstatus("");
240 poplist();
243 int
244 octal(char *s)
246 int n = 0;
247 while(*s==' ' || *s=='\t' || *s=='\n') s++;
248 while('0'<=*s && *s<='7') n = n*8+*s++-'0';
249 return n;
252 int
253 mapfd(int fd)
255 redir *rp;
256 for(rp = runq->redir;rp;rp = rp->next){
257 switch(rp->type){
258 case RCLOSE:
259 if(rp->from==fd)
260 fd=-1;
261 break;
262 case RDUP:
263 case ROPEN:
264 if(rp->to==fd)
265 fd = rp->from;
266 break;
269 return fd;
271 union code rdcmds[4];
273 void
274 execcmds(io *f)
276 static int first = 1;
277 if(first){
278 rdcmds[0].i = 1;
279 rdcmds[1].f = Xrdcmds;
280 rdcmds[2].f = Xreturn;
281 first = 0;
283 start(rdcmds, 1, runq->local);
284 runq->cmdfd = f;
285 runq->iflast = 0;
288 void
289 execeval(void)
291 char *cmdline, *s, *t;
292 int len = 0;
293 word *ap;
294 if(count(runq->argv->words)<=1){
295 Xerror1("Usage: eval cmd ...");
296 return;
298 eflagok = 1;
299 for(ap = runq->argv->words->next;ap;ap = ap->next)
300 len+=1+strlen(ap->word);
301 cmdline = emalloc(len);
302 s = cmdline;
303 for(ap = runq->argv->words->next;ap;ap = ap->next){
304 for(t = ap->word;*t;) *s++=*t++;
305 *s++=' ';
307 s[-1]='\n';
308 poplist();
309 execcmds(opencore(cmdline, len));
310 efree(cmdline);
312 union code dotcmds[14];
314 void
315 execdot(void)
317 int iflag = 0;
318 int fd;
319 list *av;
320 thread *p = runq;
321 char *zero;
322 static int first = 1;
323 char file[512];
324 word *path;
326 if(first){
327 dotcmds[0].i = 1;
328 dotcmds[1].f = Xmark;
329 dotcmds[2].f = Xword;
330 dotcmds[3].s="0";
331 dotcmds[4].f = Xlocal;
332 dotcmds[5].f = Xmark;
333 dotcmds[6].f = Xword;
334 dotcmds[7].s="*";
335 dotcmds[8].f = Xlocal;
336 dotcmds[9].f = Xrdcmds;
337 dotcmds[10].f = Xunlocal;
338 dotcmds[11].f = Xunlocal;
339 dotcmds[12].f = Xreturn;
340 first = 0;
342 else
343 eflagok = 1;
344 popword();
345 if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
346 iflag = 1;
347 popword();
349 /* get input file */
350 if(p->argv->words==0){
351 Xerror1("Usage: . [-i] file [arg ...]");
352 return;
354 zero = strdup(p->argv->words->word);
355 popword();
356 fd=-1;
357 for(path = searchpath(zero);path;path = path->next){
358 strcpy(file, path->word);
359 if(file[0])
360 strcat(file, "/");
361 strcat(file, zero);
362 if((fd = open(file, 0))>=0) break;
363 if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
364 fd = Dup1(0);
365 if(fd>=0)
366 break;
369 if(fd<0){
370 pfmt(err, "%s: ", zero);
371 setstatus("can't open");
372 Xerror(".: can't open");
373 return;
375 /* set up for a new command loop */
376 start(dotcmds, 1, (struct var *)0);
377 pushredir(RCLOSE, fd, 0);
378 runq->cmdfile = zero;
379 runq->cmdfd = openfd(fd);
380 runq->iflag = iflag;
381 runq->iflast = 0;
382 /* push $* value */
383 pushlist();
384 runq->argv->words = p->argv->words;
385 /* free caller's copy of $* */
386 av = p->argv;
387 p->argv = av->next;
388 efree((char *)av);
389 /* push $0 value */
390 pushlist();
391 pushword(zero);
392 ndot++;
395 void
396 execflag(void)
398 char *letter, *val;
399 switch(count(runq->argv->words)){
400 case 2:
401 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
402 break;
403 case 3:
404 letter = runq->argv->words->next->word;
405 val = runq->argv->words->next->next->word;
406 if(strlen(letter)==1){
407 if(strcmp(val, "+")==0){
408 flag[(uchar)letter[0]] = flagset;
409 break;
411 if(strcmp(val, "-")==0){
412 flag[(uchar)letter[0]] = 0;
413 break;
416 default:
417 Xerror1("Usage: flag [letter] [+-]");
418 return;
420 poplist();
423 void
424 execwhatis(void){ /* mildly wrong -- should fork before writing */
425 word *a, *b, *path;
426 var *v;
427 struct builtin *bp;
428 char file[512];
429 struct io out[1];
430 int found, sep;
431 a = runq->argv->words->next;
432 if(a==0){
433 Xerror1("Usage: whatis name ...");
434 return;
436 setstatus("");
437 out->fd = mapfd(1);
438 out->bufp = out->buf;
439 out->ebuf = &out->buf[NBUF];
440 out->strp = 0;
441 for(;a;a = a->next){
442 v = vlook(a->word);
443 if(v->val){
444 pfmt(out, "%s=", a->word);
445 if(v->val->next==0)
446 pfmt(out, "%q\n", v->val->word);
447 else{
448 sep='(';
449 for(b = v->val;b && b->word;b = b->next){
450 pfmt(out, "%c%q", sep, b->word);
451 sep=' ';
453 pfmt(out, ")\n");
455 found = 1;
457 else
458 found = 0;
459 v = gvlook(a->word);
460 if(v->fn)
461 pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
462 else{
463 for(bp = Builtin;bp->name;bp++)
464 if(strcmp(a->word, bp->name)==0){
465 pfmt(out, "builtin %s\n", a->word);
466 break;
468 if(!bp->name){
469 for(path = searchpath(a->word);path;path = path->next){
470 strcpy(file, path->word);
471 if(file[0])
472 strcat(file, "/");
473 strcat(file, a->word);
474 if(Executable(file)){
475 pfmt(out, "%s\n", file);
476 break;
479 if(!path && !found){
480 pfmt(err, "%s: not found\n", a->word);
481 setstatus("not found");
486 poplist();
487 flush(err);
490 void
491 execwait(void)
493 switch(count(runq->argv->words)){
494 default:
495 Xerror1("Usage: wait [pid]");
496 return;
497 case 2:
498 Waitfor(atoi(runq->argv->words->next->word), 0);
499 break;
500 case 1:
501 Waitfor(-1, 0);
502 break;
504 poplist();