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 pushword("exec");
67 execexec();
68 strcpy(buf, "can't exec: ");
69 n = strlen(buf);
70 errstr(buf+n, ERRMAX-n);
71 Exit(buf);
72 default:
73 poplist();
74 /* interrupts don't get us out */
75 while(Waitfor(pid, 1) < 0)
76 ;
77 }
78 }
79 }
80 }
81 struct word nullpath={ "", 0};
82 void doredir(redir *rp)
83 {
84 if(rp){
85 doredir(rp->next);
86 switch(rp->type){
87 case ROPEN:
88 if(rp->from!=rp->to){
89 Dup(rp->from, rp->to);
90 close(rp->from);
91 }
92 break;
93 case RDUP: Dup(rp->from, rp->to); break;
94 case RCLOSE: close(rp->from); break;
95 }
96 }
97 }
98 word *searchpath(char *w){
99 word *path;
100 if(strncmp(w, "/", 1)==0
101 || strncmp(w, "#", 1)==0
102 || strncmp(w, "./", 2)==0
103 || strncmp(w, "../", 3)==0
104 || (path=vlook("path")->val)==0)
105 path=&nullpath;
106 return path;
108 void execexec(void){
109 popword(); /* "exec" */
110 if(runq->argv->words==0){
111 Xerror1("empty argument list");
112 return;
114 doredir(runq->redir);
115 Execute(runq->argv->words, searchpath(runq->argv->words->word));
116 poplist();
118 void execfunc(var *func)
120 word *starval;
121 popword();
122 starval=runq->argv->words;
123 runq->argv->words=0;
124 poplist();
125 start(func->fn, func->pc, (struct var *)0);
126 runq->local=newvar(strdup("*"), runq->local);
127 runq->local->val=starval;
128 runq->local->changed=1;
130 int dochdir(char *word){
131 /* report to /dev/wdir if it exists and we're interactive */
132 static int wdirfd = -2;
133 if(chdir(word)<0) return -1;
134 if(flag['i']!=0){
135 if(wdirfd==-2) /* try only once */
136 wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
137 if(wdirfd>=0)
138 write(wdirfd, word, strlen(word));
140 return 1;
142 void execcd(void){
143 word *a=runq->argv->words;
144 word *cdpath;
145 char dir[512];
146 setstatus("can't cd");
147 cdpath=vlook("cdpath")->val;
148 switch(count(a)){
149 default:
150 pfmt(err, "Usage: cd [directory]\n");
151 break;
152 case 2:
153 if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
154 for(;cdpath;cdpath=cdpath->next){
155 strcpy(dir, cdpath->word);
156 if(dir[0]) strcat(dir, "/");
157 strcat(dir, a->next->word);
158 if(dochdir(dir)>=0){
159 if(strlen(cdpath->word)
160 && strcmp(cdpath->word, ".")!=0)
161 pfmt(err, "%s\n", dir);
162 setstatus("");
163 break;
166 if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
167 break;
168 case 1:
169 a=vlook("home")->val;
170 if(count(a)>=1){
171 if(dochdir(a->word)>=0)
172 setstatus("");
173 else
174 pfmt(err, "Can't cd %s: %r\n", a->word);
176 else
177 pfmt(err, "Can't cd -- $home empty\n");
178 break;
180 poplist();
182 void execexit(void){
183 switch(count(runq->argv->words)){
184 default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
185 case 2: setstatus(runq->argv->words->next->word);
186 case 1: Xexit();
189 void execshift(void){
190 int n;
191 word *a;
192 var *star;
193 switch(count(runq->argv->words)){
194 default:
195 pfmt(err, "Usage: shift [n]\n");
196 setstatus("shift usage");
197 poplist();
198 return;
199 case 2: n=atoi(runq->argv->words->next->word); break;
200 case 1: n=1; break;
202 star=vlook("*");
203 for(;n && star->val;--n){
204 a=star->val->next;
205 efree(star->val->word);
206 efree((char *)star->val);
207 star->val=a;
208 star->changed=1;
210 setstatus("");
211 poplist();
213 int octal(char *s)
215 int n=0;
216 while(*s==' ' || *s=='\t' || *s=='\n') s++;
217 while('0'<=*s && *s<='7') n=n*8+*s++-'0';
218 return n;
220 int mapfd(int fd)
222 redir *rp;
223 for(rp=runq->redir;rp;rp=rp->next){
224 switch(rp->type){
225 case RCLOSE:
226 if(rp->from==fd) fd=-1;
227 break;
228 case RDUP:
229 case ROPEN:
230 if(rp->to==fd) fd=rp->from;
231 break;
234 return fd;
236 union code rdcmds[4];
237 void execcmds(io *f)
239 static int first=1;
240 if(first){
241 rdcmds[0].i=1;
242 rdcmds[1].f=Xrdcmds;
243 rdcmds[2].f=Xreturn;
244 first=0;
246 start(rdcmds, 1, runq->local);
247 runq->cmdfd=f;
248 runq->iflast=0;
250 void execeval(void){
251 char *cmdline, *s, *t;
252 int len=0;
253 word *ap;
254 if(count(runq->argv->words)<=1){
255 Xerror1("Usage: eval cmd ...");
256 return;
258 eflagok=1;
259 for(ap=runq->argv->words->next;ap;ap=ap->next)
260 len+=1+strlen(ap->word);
261 cmdline=emalloc(len);
262 s=cmdline;
263 for(ap=runq->argv->words->next;ap;ap=ap->next){
264 for(t=ap->word;*t;) *s++=*t++;
265 *s++=' ';
267 s[-1]='\n';
268 poplist();
269 execcmds(opencore(cmdline, len));
270 efree(cmdline);
272 union code dotcmds[14];
273 void execdot(void){
274 int iflag=0;
275 int fd;
276 list *av;
277 thread *p=runq;
278 char *zero;
279 static int first=1;
280 char file[512];
281 word *path;
282 if(first){
283 dotcmds[0].i=1;
284 dotcmds[1].f=Xmark;
285 dotcmds[2].f=Xword;
286 dotcmds[3].s="0";
287 dotcmds[4].f=Xlocal;
288 dotcmds[5].f=Xmark;
289 dotcmds[6].f=Xword;
290 dotcmds[7].s="*";
291 dotcmds[8].f=Xlocal;
292 dotcmds[9].f=Xrdcmds;
293 dotcmds[10].f=Xunlocal;
294 dotcmds[11].f=Xunlocal;
295 dotcmds[12].f=Xreturn;
296 first=0;
298 else
299 eflagok=1;
300 popword();
301 if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
302 iflag=1;
303 popword();
305 /* get input file */
306 if(p->argv->words==0){
307 Xerror1("Usage: . [-i] file [arg ...]");
308 return;
310 zero=strdup(p->argv->words->word);
311 popword();
312 fd=-1;
313 for(path=searchpath(zero);path;path=path->next){
314 strcpy(file, path->word);
315 if(file[0]) strcat(file, "/");
316 strcat(file, zero);
317 if((fd=open(file, 0))>=0) break;
318 if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
319 fd=Dup1(0);
320 if(fd>=0) break;
323 if(fd<0){
324 pfmt(err, "%s: ", zero);
325 setstatus("can't open");
326 Xerror(".: can't open");
327 return;
329 /* set up for a new command loop */
330 start(dotcmds, 1, (struct var *)0);
331 pushredir(RCLOSE, fd, 0);
332 runq->cmdfile=zero;
333 runq->cmdfd=openfd(fd);
334 runq->iflag=iflag;
335 runq->iflast=0;
336 /* push $* value */
337 pushlist();
338 runq->argv->words=p->argv->words;
339 /* free caller's copy of $* */
340 av=p->argv;
341 p->argv=av->next;
342 efree((char *)av);
343 /* push $0 value */
344 pushlist();
345 pushword(zero);
346 ndot++;
348 void execflag(void){
349 char *letter, *val;
350 switch(count(runq->argv->words)){
351 case 2:
352 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
353 break;
354 case 3:
355 letter=runq->argv->words->next->word;
356 val=runq->argv->words->next->next->word;
357 if(strlen(letter)==1){
358 if(strcmp(val, "+")==0){
359 flag[(uchar)letter[0]]=flagset;
360 break;
362 if(strcmp(val, "-")==0){
363 flag[(uchar)letter[0]]=0;
364 break;
367 default:
368 Xerror1("Usage: flag [letter] [+-]");
369 return;
371 poplist();
373 void execwhatis(void){ /* mildly wrong -- should fork before writing */
374 word *a, *b, *path;
375 var *v;
376 struct builtin *bp;
377 char file[512];
378 struct io out[1];
379 int found, sep;
380 a=runq->argv->words->next;
381 if(a==0){
382 Xerror1("Usage: whatis name ...");
383 return;
385 setstatus("");
386 out->fd=mapfd(1);
387 out->bufp=out->buf;
388 out->ebuf=&out->buf[NBUF];
389 out->strp=0;
390 for(;a;a=a->next){
391 v=vlook(a->word);
392 if(v->val){
393 pfmt(out, "%s=", a->word);
394 if(v->val->next==0)
395 pfmt(out, "%q\n", v->val->word);
396 else{
397 sep='(';
398 for(b=v->val;b && b->word;b=b->next){
399 pfmt(out, "%c%q", sep, b->word);
400 sep=' ';
402 pfmt(out, ")\n");
404 found=1;
406 else
407 found=0;
408 v=gvlook(a->word);
409 if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
410 else{
411 for(bp=Builtin;bp->name;bp++)
412 if(strcmp(a->word, bp->name)==0){
413 pfmt(out, "builtin %s\n", a->word);
414 break;
416 if(!bp->name){
417 for(path=searchpath(a->word);path;path=path->next){
418 strcpy(file, path->word);
419 if(file[0]) strcat(file, "/");
420 strcat(file, a->word);
421 if(Executable(file)){
422 pfmt(out, "%s\n", file);
423 break;
426 if(!path && !found){
427 pfmt(err, "%s: not found\n", a->word);
428 setstatus("not found");
433 poplist();
434 flush(err);
436 void execwait(void){
437 switch(count(runq->argv->words)){
438 default: Xerror1("Usage: wait [pid]"); return;
439 case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
440 case 1: Waitfor(-1, 0); break;
442 poplist();