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, (struct var *)0);
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;
325 if(first){
326 dotcmds[0].i = 1;
327 dotcmds[1].f = Xmark;
328 dotcmds[2].f = Xword;
329 dotcmds[3].s="0";
330 dotcmds[4].f = Xlocal;
331 dotcmds[5].f = Xmark;
332 dotcmds[6].f = Xword;
333 dotcmds[7].s="*";
334 dotcmds[8].f = Xlocal;
335 dotcmds[9].f = Xrdcmds;
336 dotcmds[10].f = Xunlocal;
337 dotcmds[11].f = Xunlocal;
338 dotcmds[12].f = Xreturn;
339 first = 0;
341 else
342 eflagok = 1;
343 popword();
344 if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
345 iflag = 1;
346 popword();
348 /* get input file */
349 if(p->argv->words==0){
350 Xerror1("Usage: . [-i] file [arg ...]");
351 return;
353 zero = strdup(p->argv->words->word);
354 popword();
355 fd=-1;
356 for(path = searchpath(zero);path;path = path->next){
357 strcpy(file, path->word);
358 if(file[0])
359 strcat(file, "/");
360 strcat(file, zero);
361 if((fd = open(file, 0))>=0) break;
362 if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
363 fd = Dup1(0);
364 if(fd>=0)
365 break;
368 if(fd<0){
369 pfmt(err, "%s: ", zero);
370 setstatus("can't open");
371 Xerror(".: can't open");
372 return;
374 /* set up for a new command loop */
375 start(dotcmds, 1, (struct var *)0);
376 pushredir(RCLOSE, fd, 0);
377 runq->cmdfile = zero;
378 runq->cmdfd = openfd(fd);
379 runq->iflag = iflag;
380 runq->iflast = 0;
381 /* push $* value */
382 pushlist();
383 runq->argv->words = p->argv->words;
384 /* free caller's copy of $* */
385 av = p->argv;
386 p->argv = av->next;
387 efree((char *)av);
388 /* push $0 value */
389 pushlist();
390 pushword(zero);
391 ndot++;
394 void
395 execflag(void)
397 char *letter, *val;
398 switch(count(runq->argv->words)){
399 case 2:
400 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
401 break;
402 case 3:
403 letter = runq->argv->words->next->word;
404 val = runq->argv->words->next->next->word;
405 if(strlen(letter)==1){
406 if(strcmp(val, "+")==0){
407 flag[(uchar)letter[0]] = flagset;
408 break;
410 if(strcmp(val, "-")==0){
411 flag[(uchar)letter[0]] = 0;
412 break;
415 default:
416 Xerror1("Usage: flag [letter] [+-]");
417 return;
419 poplist();
422 void
423 execwhatis(void){ /* mildly wrong -- should fork before writing */
424 word *a, *b, *path;
425 var *v;
426 struct builtin *bp;
427 char file[512];
428 struct io out[1];
429 int found, sep;
430 a = runq->argv->words->next;
431 if(a==0){
432 Xerror1("Usage: whatis name ...");
433 return;
435 setstatus("");
436 out->fd = mapfd(1);
437 out->bufp = out->buf;
438 out->ebuf = &out->buf[NBUF];
439 out->strp = 0;
440 for(;a;a = a->next){
441 v = vlook(a->word);
442 if(v->val){
443 pfmt(out, "%s=", a->word);
444 if(v->val->next==0)
445 pfmt(out, "%q\n", v->val->word);
446 else{
447 sep='(';
448 for(b = v->val;b && b->word;b = b->next){
449 pfmt(out, "%c%q", sep, b->word);
450 sep=' ';
452 pfmt(out, ")\n");
454 found = 1;
456 else
457 found = 0;
458 v = gvlook(a->word);
459 if(v->fn)
460 pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
461 else{
462 for(bp = Builtin;bp->name;bp++)
463 if(strcmp(a->word, bp->name)==0){
464 pfmt(out, "builtin %s\n", a->word);
465 break;
467 if(!bp->name){
468 for(path = searchpath(a->word);path;path = path->next){
469 strcpy(file, path->word);
470 if(file[0])
471 strcat(file, "/");
472 strcat(file, a->word);
473 if(Executable(file)){
474 pfmt(out, "%s\n", file);
475 break;
478 if(!path && !found){
479 pfmt(err, "%s: not found\n", a->word);
480 setstatus("not found");
485 poplist();
486 flush(err);
489 void
490 execwait(void)
492 switch(count(runq->argv->words)){
493 default:
494 Xerror1("Usage: wait [pid]");
495 return;
496 case 2:
497 Waitfor(atoi(runq->argv->words->next->word), 0);
498 break;
499 case 1:
500 Waitfor(-1, 0);
501 break;
503 poplist();