]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rc/simple.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / cmd / rc / simple.c
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
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                         }
67
68                         /* interrupts don't get us out */
69                         poplist();
70                         while(Waitfor(pid, 1) < 0)
71                                 ;
72                 }
73         }
74 }
75 struct word nullpath = { "", 0};
76
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 }
98
99 word*
100 searchpath(char *w)
101 {
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;
110 }
111
112 void
113 execexec(void)
114 {
115         popword();      /* "exec" */
116         if(runq->argv->words==0){
117                 Xerror1("empty argument list");
118                 return;
119         }
120         doredir(runq->redir);
121         Execute(runq->argv->words, searchpath(runq->argv->words->word));
122         poplist();
123 }
124
125 void
126 execfunc(var *func)
127 {
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;
137 }
138
139 int
140 dochdir(char *word)
141 {
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));
150         }
151         return 1;
152 }
153
154 void
155 execcd(void)
156 {
157         word *a = runq->argv->words;
158         word *cdpath;
159         char *dir;
160
161         setstatus("can't cd");
162         cdpath = vlook("cdpath")->val;
163         switch(count(a)){
164         default:
165                 pfmt(err, "Usage: cd [directory]\n");
166                 break;
167         case 2:
168                 if(a->next->word[0]=='/' || cdpath==0)
169                         cdpath = &nullpath;
170                 for(; cdpath; cdpath = cdpath->next){
171                         if(cdpath->word[0] != '\0')
172                                 dir = smprint("%s/%s", cdpath->word,
173                                         a->next->word);
174                         else
175                                 dir = strdup(a->next->word);
176
177                         if(dochdir(dir) >= 0){
178                                 if(cdpath->word[0] != '\0' &&
179                                     strcmp(cdpath->word, ".") != 0)
180                                         pfmt(err, "%s\n", dir);
181                                 free(dir);
182                                 setstatus("");
183                                 break;
184                         }
185                         free(dir);
186                 }
187                 if(cdpath==0)
188                         pfmt(err, "Can't cd %s: %r\n", a->next->word);
189                 break;
190         case 1:
191                 a = vlook("home")->val;
192                 if(count(a)>=1){
193                         if(dochdir(a->word)>=0)
194                                 setstatus("");
195                         else
196                                 pfmt(err, "Can't cd %s: %r\n", a->word);
197                 }
198                 else
199                         pfmt(err, "Can't cd -- $home empty\n");
200                 break;
201         }
202         poplist();
203 }
204
205 void
206 execexit(void)
207 {
208         switch(count(runq->argv->words)){
209         default:
210                 pfmt(err, "Usage: exit [status]\nExiting anyway\n");
211         case 2:
212                 setstatus(runq->argv->words->next->word);
213         case 1: Xexit();
214         }
215 }
216
217 void
218 execshift(void)
219 {
220         int n;
221         word *a;
222         var *star;
223         switch(count(runq->argv->words)){
224         default:
225                 pfmt(err, "Usage: shift [n]\n");
226                 setstatus("shift usage");
227                 poplist();
228                 return;
229         case 2:
230                 n = atoi(runq->argv->words->next->word);
231                 break;
232         case 1:
233                 n = 1;
234                 break;
235         }
236         star = vlook("*");
237         for(;n && star->val;--n){
238                 a = star->val->next;
239                 efree(star->val->word);
240                 efree((char *)star->val);
241                 star->val = a;
242                 star->changed = 1;
243         }
244         setstatus("");
245         poplist();
246 }
247
248 int
249 octal(char *s)
250 {
251         int n = 0;
252         while(*s==' ' || *s=='\t' || *s=='\n') s++;
253         while('0'<=*s && *s<='7') n = n*8+*s++-'0';
254         return n;
255 }
256
257 int
258 mapfd(int fd)
259 {
260         redir *rp;
261         for(rp = runq->redir;rp;rp = rp->next){
262                 switch(rp->type){
263                 case RCLOSE:
264                         if(rp->from==fd)
265                                 fd=-1;
266                         break;
267                 case RDUP:
268                 case ROPEN:
269                         if(rp->to==fd)
270                                 fd = rp->from;
271                         break;
272                 }
273         }
274         return fd;
275 }
276 union code rdcmds[4];
277
278 void
279 execcmds(io *f)
280 {
281         static int first = 1;
282         if(first){
283                 rdcmds[0].i = 1;
284                 rdcmds[1].f = Xrdcmds;
285                 rdcmds[2].f = Xreturn;
286                 first = 0;
287         }
288         start(rdcmds, 1, runq->local);
289         runq->cmdfd = f;
290         runq->iflast = 0;
291 }
292
293 void
294 execeval(void)
295 {
296         char *cmdline, *s, *t;
297         int len = 0;
298         word *ap;
299         if(count(runq->argv->words)<=1){
300                 Xerror1("Usage: eval cmd ...");
301                 return;
302         }
303         eflagok = 1;
304         for(ap = runq->argv->words->next;ap;ap = ap->next)
305                 len+=1+strlen(ap->word);
306         cmdline = emalloc(len);
307         s = cmdline;
308         for(ap = runq->argv->words->next;ap;ap = ap->next){
309                 for(t = ap->word;*t;) *s++=*t++;
310                 *s++=' ';
311         }
312         s[-1]='\n';
313         poplist();
314         execcmds(opencore(cmdline, len));
315         efree(cmdline);
316 }
317 union code dotcmds[14];
318
319 void
320 execdot(void)
321 {
322         int iflag = 0;
323         int fd;
324         list *av;
325         thread *p = runq;
326         char *zero, *file;
327         word *path;
328         static int first = 1;
329
330         if(first){
331                 dotcmds[0].i = 1;
332                 dotcmds[1].f = Xmark;
333                 dotcmds[2].f = Xword;
334                 dotcmds[3].s="0";
335                 dotcmds[4].f = Xlocal;
336                 dotcmds[5].f = Xmark;
337                 dotcmds[6].f = Xword;
338                 dotcmds[7].s="*";
339                 dotcmds[8].f = Xlocal;
340                 dotcmds[9].f = Xrdcmds;
341                 dotcmds[10].f = Xunlocal;
342                 dotcmds[11].f = Xunlocal;
343                 dotcmds[12].f = Xreturn;
344                 first = 0;
345         }
346         else
347                 eflagok = 1;
348         popword();
349         if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
350                 iflag = 1;
351                 popword();
352         }
353         /* get input file */
354         if(p->argv->words==0){
355                 Xerror1("Usage: . [-i] file [arg ...]");
356                 return;
357         }
358         zero = strdup(p->argv->words->word);
359         popword();
360         fd = -1;
361         for(path = searchpath(zero); path; path = path->next){
362                 if(path->word[0] != '\0')
363                         file = smprint("%s/%s", path->word, zero);
364                 else
365                         file = strdup(zero);
366
367                 fd = open(file, 0);
368                 free(file);
369                 if(fd >= 0)
370                         break;
371                 if(strcmp(file, "/dev/stdin")==0){      /* for sun & ucb */
372                         fd = Dup1(0);
373                         if(fd>=0)
374                                 break;
375                 }
376         }
377         if(fd<0){
378                 pfmt(err, "%s: ", zero);
379                 setstatus("can't open");
380                 Xerror(".: can't open");
381                 return;
382         }
383         /* set up for a new command loop */
384         start(dotcmds, 1, (struct var *)0);
385         pushredir(RCLOSE, fd, 0);
386         runq->cmdfile = zero;
387         runq->cmdfd = openfd(fd);
388         runq->iflag = iflag;
389         runq->iflast = 0;
390         /* push $* value */
391         pushlist();
392         runq->argv->words = p->argv->words;
393         /* free caller's copy of $* */
394         av = p->argv;
395         p->argv = av->next;
396         efree((char *)av);
397         /* push $0 value */
398         pushlist();
399         pushword(zero);
400         ndot++;
401 }
402
403 void
404 execflag(void)
405 {
406         char *letter, *val;
407         switch(count(runq->argv->words)){
408         case 2:
409                 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
410                 break;
411         case 3:
412                 letter = runq->argv->words->next->word;
413                 val = runq->argv->words->next->next->word;
414                 if(strlen(letter)==1){
415                         if(strcmp(val, "+")==0){
416                                 flag[(uchar)letter[0]] = flagset;
417                                 break;
418                         }
419                         if(strcmp(val, "-")==0){
420                                 flag[(uchar)letter[0]] = 0;
421                                 break;
422                         }
423                 }
424         default:
425                 Xerror1("Usage: flag [letter] [+-]");
426                 return;
427         }
428         poplist();
429 }
430
431 void
432 execwhatis(void){       /* mildly wrong -- should fork before writing */
433         word *a, *b, *path;
434         var *v;
435         struct builtin *bp;
436         char *file;
437         struct io out[1];
438         int found, sep;
439         a = runq->argv->words->next;
440         if(a==0){
441                 Xerror1("Usage: whatis name ...");
442                 return;
443         }
444         setstatus("");
445         out->fd = mapfd(1);
446         out->bufp = out->buf;
447         out->ebuf = &out->buf[NBUF];
448         out->strp = 0;
449         for(;a;a = a->next){
450                 v = vlook(a->word);
451                 if(v->val){
452                         pfmt(out, "%s=", a->word);
453                         if(v->val->next==0)
454                                 pfmt(out, "%q\n", v->val->word);
455                         else{
456                                 sep='(';
457                                 for(b = v->val;b && b->word;b = b->next){
458                                         pfmt(out, "%c%q", sep, b->word);
459                                         sep=' ';
460                                 }
461                                 pfmt(out, ")\n");
462                         }
463                         found = 1;
464                 }
465                 else
466                         found = 0;
467                 v = gvlook(a->word);
468                 if(v->fn)
469                         pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
470                 else{
471                         for(bp = Builtin;bp->name;bp++)
472                                 if(strcmp(a->word, bp->name)==0){
473                                         pfmt(out, "builtin %s\n", a->word);
474                                         break;
475                                 }
476                         if(!bp->name){
477                                 for(path = searchpath(a->word); path;
478                                     path = path->next){
479                                         if(path->word[0] != '\0')
480                                                 file = smprint("%s/%s",
481                                                         path->word, a->word);
482                                         else
483                                                 file = strdup(a->word);
484                                         if(Executable(file)){
485                                                 pfmt(out, "%s\n", file);
486                                                 free(file);
487                                                 break;
488                                         }
489                                         free(file);
490                                 }
491                                 if(!path && !found){
492                                         pfmt(err, "%s: not found\n", a->word);
493                                         setstatus("not found");
494                                 }
495                         }
496                 }
497         }
498         poplist();
499         flush(err);
500 }
501
502 void
503 execwait(void)
504 {
505         switch(count(runq->argv->words)){
506         default:
507                 Xerror1("Usage: wait [pid]");
508                 return;
509         case 2:
510                 Waitfor(atoi(runq->argv->words->next->word), 0);
511                 break;
512         case 1:
513                 Waitfor(-1, 0);
514                 break;
515         }
516         poplist();
517 }