]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rc/simple.c
ip/ipconfig: use ewrite() to enable routing command for sendra
[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         var *v;
24         struct builtin *bp;
25         int pid;
26
27         a = globlist(runq->argv->words);
28         if(a==0){
29                 Xerror1("empty argument list");
30                 return;
31         }
32         if(flag['x'])
33                 pfmt(err, "%v\n", a); /* wrong, should do redirs */
34         v = gvlook(a->word);
35         if(v->fn)
36                 execfunc(v);
37         else{
38                 if(strcmp(a->word, "builtin")==0){
39                         if(count(a)==1){
40                                 pfmt(err, "builtin: empty argument list\n");
41                                 setstatus("empty arg list");
42                                 poplist();
43                                 return;
44                         }
45                         a = a->next;
46                         popword();
47                 }
48                 for(bp = Builtin;bp->name;bp++)
49                         if(strcmp(a->word, bp->name)==0){
50                                 (*bp->fnc)();
51                                 return;
52                         }
53                 if(exitnext()){
54                         /* fork and wait is redundant */
55                         pushword("exec");
56                         execexec();
57                 }
58                 else{
59                         flush(err);
60                         Updenv();       /* necessary so changes don't go out again */
61                         if((pid = execforkexec()) < 0){
62                                 Xerror("try again");
63                                 return;
64                         }
65
66                         /* interrupts don't get us out */
67                         poplist();
68                         while(Waitfor(pid, 1) < 0)
69                                 ;
70                 }
71         }
72 }
73
74 void
75 doredir(redir *rp)
76 {
77         if(rp){
78                 doredir(rp->next);
79                 switch(rp->type){
80                 case ROPEN:
81                         if(rp->from!=rp->to){
82                                 Dup(rp->from, rp->to);
83                                 close(rp->from);
84                         }
85                         break;
86                 case RDUP:
87                         Dup(rp->from, rp->to);
88                         break;
89                 case RCLOSE:
90                         close(rp->from);
91                         break;
92                 }
93         }
94 }
95
96 word*
97 searchpath(char *w, char *v)
98 {
99         static struct word nullpath = { "", 0 };
100         word *path;
101
102         if(w[0] && w[0] != '/' && w[0] != '#' &&
103           (w[0] != '.' || (w[1] && w[1] != '/' && (w[1] != '.' || w[2] && w[2] != '/')))){
104                 path = vlook(v)->val;
105                 if(path)
106                         return path;
107         }
108         return &nullpath;
109 }
110
111 void
112 execexec(void)
113 {
114         popword();      /* "exec" */
115         if(runq->argv->words==0){
116                 Xerror1("empty argument list");
117                 return;
118         }
119         doredir(runq->redir);
120         Execute(runq->argv->words, searchpath(runq->argv->words->word, "path"));
121         poplist();
122         Xexit();
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("*", 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         if(chdir(word)<0)
144                 return -1;
145         newwdir = 1;
146         return 1;
147 }
148
149 void
150 execcd(void)
151 {
152         word *a = runq->argv->words;
153         word *cdpath;
154         char *dir;
155
156         setstatus("can't cd");
157         switch(count(a)){
158         default:
159                 pfmt(err, "Usage: cd [directory]\n");
160                 break;
161         case 2:
162                 a = a->next;
163                 for(cdpath = searchpath(a->word, "cdpath"); cdpath; cdpath = cdpath->next){
164                         if(cdpath->word[0] != '\0')
165                                 dir = smprint("%s/%s", cdpath->word, a->word);
166                         else
167                                 dir = estrdup(a->word);
168                         if(dochdir(dir) >= 0){
169                                 if(cdpath->word[0] != '\0' && strcmp(cdpath->word, ".") != 0)
170                                         pfmt(err, "%s\n", dir);
171                                 free(dir);
172                                 setstatus("");
173                                 break;
174                         }
175                         free(dir);
176                 }
177                 if(cdpath==0)
178                         pfmt(err, "Can't cd %s: %r\n", a->word);
179                 break;
180         case 1:
181                 a = vlook("home")->val;
182                 if(count(a)>=1){
183                         if(dochdir(a->word)>=0)
184                                 setstatus("");
185                         else
186                                 pfmt(err, "Can't cd %s: %r\n", a->word);
187                 }
188                 else
189                         pfmt(err, "Can't cd -- $home empty\n");
190                 break;
191         }
192         poplist();
193 }
194
195 void
196 execexit(void)
197 {
198         switch(count(runq->argv->words)){
199         default:
200                 pfmt(err, "Usage: exit [status]\nExiting anyway\n");
201         case 2:
202                 setstatus(runq->argv->words->next->word);
203         case 1: Xexit();
204         }
205 }
206
207 void
208 execshift(void)
209 {
210         int n;
211         word *a;
212         var *star;
213         switch(count(runq->argv->words)){
214         default:
215                 pfmt(err, "Usage: shift [n]\n");
216                 setstatus("shift usage");
217                 poplist();
218                 return;
219         case 2:
220                 n = atoi(runq->argv->words->next->word);
221                 break;
222         case 1:
223                 n = 1;
224                 break;
225         }
226         star = vlook("*");
227         for(;n>0 && star->val;--n){
228                 a = star->val->next;
229                 free(star->val->word);
230                 free(star->val);
231                 star->val = a;
232                 star->changed = 1;
233         }
234         setstatus("");
235         poplist();
236 }
237
238 int
239 mapfd(int fd)
240 {
241         redir *rp;
242         for(rp = runq->redir;rp;rp = rp->next){
243                 switch(rp->type){
244                 case RCLOSE:
245                         if(rp->from==fd)
246                                 fd=-1;
247                         break;
248                 case RDUP:
249                 case ROPEN:
250                         if(rp->to==fd)
251                                 fd = rp->from;
252                         break;
253                 }
254         }
255         return fd;
256 }
257 union code rdcmds[4];
258
259 void
260 execcmds(io *f)
261 {
262         static int first = 1;
263         if(first){
264                 rdcmds[0].i = 1;
265                 rdcmds[1].f = Xrdcmds;
266                 rdcmds[2].f = Xreturn;
267                 first = 0;
268         }
269         start(rdcmds, 1, runq->local);
270         runq->cmdfd = f;
271         runq->iflast = 0;
272 }
273
274 void
275 execeval(void)
276 {
277         char *cmdline;
278         int len;
279         if(count(runq->argv->words)<=1){
280                 Xerror1("Usage: eval cmd ...");
281                 return;
282         }
283         eflagok = 1;
284         cmdline = list2str(runq->argv->words->next);
285         len = strlen(cmdline);
286         cmdline[len] = '\n';
287         poplist();
288         execcmds(opencore(cmdline, len+1));
289         free(cmdline);
290 }
291 union code dotcmds[14];
292
293 void
294 execdot(void)
295 {
296         int iflag = 0;
297         int fd;
298         list *av;
299         thread *p = runq;
300         char *zero, *file;
301         word *path;
302         static int first = 1;
303
304         if(first){
305                 dotcmds[0].i = 1;
306                 dotcmds[1].f = Xmark;
307                 dotcmds[2].f = Xword;
308                 dotcmds[3].s="0";
309                 dotcmds[4].f = Xlocal;
310                 dotcmds[5].f = Xmark;
311                 dotcmds[6].f = Xword;
312                 dotcmds[7].s="*";
313                 dotcmds[8].f = Xlocal;
314                 dotcmds[9].f = Xrdcmds;
315                 dotcmds[10].f = Xunlocal;
316                 dotcmds[11].f = Xunlocal;
317                 dotcmds[12].f = Xreturn;
318                 first = 0;
319         }
320         else
321                 eflagok = 1;
322         popword();
323         if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
324                 iflag = 1;
325                 popword();
326         }
327         /* get input file */
328         if(p->argv->words==0){
329                 Xerror1("Usage: . [-i] file [arg ...]");
330                 return;
331         }
332         zero = estrdup(p->argv->words->word);
333         popword();
334         fd = -1;
335         for(path = searchpath(zero, "path"); path; path = path->next){
336                 if(path->word[0] != '\0')
337                         file = smprint("%s/%s", path->word, zero);
338                 else
339                         file = estrdup(zero);
340
341                 fd = open(file, 0);
342                 free(file);
343                 if(fd >= 0)
344                         break;
345                 if(strcmp(file, "/dev/stdin")==0){      /* for sun & ucb */
346                         fd = Dup1(0);
347                         if(fd>=0)
348                                 break;
349                 }
350         }
351         if(fd<0){
352                 pfmt(err, "%s: ", zero);
353                 setstatus("can't open");
354                 Xerror(".: can't open");
355                 return;
356         }
357         /* set up for a new command loop */
358         start(dotcmds, 1, (struct var *)0);
359         pushredir(RCLOSE, fd, 0);
360         runq->cmdfile = zero;
361         runq->cmdfd = openfd(fd);
362         runq->iflag = iflag;
363         runq->iflast = 0;
364         /* push $* value */
365         pushlist();
366         runq->argv->words = p->argv->words;
367         /* free caller's copy of $* */
368         av = p->argv;
369         p->argv = av->next;
370         free(av);
371         /* push $0 value */
372         pushlist();
373         pushword(zero);
374         ndot++;
375 }
376
377 void
378 execflag(void)
379 {
380         char *letter, *val;
381         switch(count(runq->argv->words)){
382         case 2:
383                 setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
384                 break;
385         case 3:
386                 letter = runq->argv->words->next->word;
387                 val = runq->argv->words->next->next->word;
388                 if(strlen(letter)==1){
389                         if(strcmp(val, "+")==0){
390                                 flag[(uchar)letter[0]] = flagset;
391                                 break;
392                         }
393                         if(strcmp(val, "-")==0){
394                                 flag[(uchar)letter[0]] = 0;
395                                 break;
396                         }
397                 }
398         default:
399                 Xerror1("Usage: flag [letter] [+-]");
400                 return;
401         }
402         poplist();
403 }
404
405 void
406 execwhatis(void){       /* mildly wrong -- should fork before writing */
407         word *a, *b, *path;
408         var *v;
409         struct builtin *bp;
410         char *file;
411         struct io out[1];
412         int found, sep;
413         a = runq->argv->words->next;
414         if(a==0){
415                 Xerror1("Usage: whatis name ...");
416                 return;
417         }
418         setstatus("");
419         out->fd = mapfd(1);
420         out->bufp = out->buf;
421         out->ebuf = &out->buf[NBUF];
422         out->strp = 0;
423         for(;a;a = a->next){
424                 v = vlook(a->word);
425                 if(v->val){
426                         pfmt(out, "%s=", a->word);
427                         if(v->val->next==0)
428                                 pfmt(out, "%q\n", v->val->word);
429                         else{
430                                 sep='(';
431                                 for(b = v->val;b && b->word;b = b->next){
432                                         pfmt(out, "%c%q", sep, b->word);
433                                         sep=' ';
434                                 }
435                                 pfmt(out, ")\n");
436                         }
437                         found = 1;
438                 }
439                 else
440                         found = 0;
441                 v = gvlook(a->word);
442                 if(v->fn)
443                         pfmt(out, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
444                 else{
445                         for(bp = Builtin;bp->name;bp++)
446                                 if(strcmp(a->word, bp->name)==0){
447                                         pfmt(out, "builtin %s\n", a->word);
448                                         break;
449                                 }
450                         if(!bp->name){
451                                 for(path = searchpath(a->word, "path"); path;
452                                     path = path->next){
453                                         if(path->word[0] != '\0')
454                                                 file = smprint("%s/%s",
455                                                         path->word, a->word);
456                                         else
457                                                 file = estrdup(a->word);
458                                         if(Executable(file)){
459                                                 pfmt(out, "%s\n", file);
460                                                 free(file);
461                                                 break;
462                                         }
463                                         free(file);
464                                 }
465                                 if(!path && !found){
466                                         pfmt(err, "%s: not found\n", a->word);
467                                         setstatus("not found");
468                                 }
469                         }
470                 }
471         }
472         poplist();
473         flush(err);
474 }
475
476 void
477 execwait(void)
478 {
479         switch(count(runq->argv->words)){
480         default:
481                 Xerror1("Usage: wait [pid]");
482                 return;
483         case 2:
484                 Waitfor(atoi(runq->argv->words->next->word), 0);
485                 break;
486         case 1:
487                 Waitfor(-1, 0);
488                 break;
489         }
490         poplist();
491 }