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