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