Blob


1 /*
2 * Plan 9 versions of system-specific functions
3 * By convention, exported routines herein have names beginning with an
4 * upper case letter.
5 */
6 #include "rc.h"
7 #include "exec.h"
8 #include "io.h"
9 #include "fns.h"
10 #include "getflags.h"
11 char *Signame[]={
12 "sigexit", "sighup", "sigint", "sigquit",
13 "sigalrm", "sigkill", "sigfpe", "sigterm",
14 0
15 };
16 char *syssigname[]={
17 "exit", /* can't happen */
18 "hangup",
19 "interrupt",
20 "quit", /* can't happen */
21 "alarm",
22 "kill",
23 "sys: fp: ",
24 "term",
25 0
26 };
27 char*
28 Rcmain(void)
29 {
30 return unsharp("#9/rcmain");
31 }
33 char Fdprefix[]="/dev/fd/";
34 long readnb(int, char *, long);
35 void execfinit(void);
36 void execbind(void);
37 void execmount(void);
38 void execulimit(void);
39 void execumask(void);
40 void execrfork(void);
41 builtin Builtin[]={
42 "cd", execcd,
43 "whatis", execwhatis,
44 "eval", execeval,
45 "exec", execexec, /* but with popword first */
46 "exit", execexit,
47 "shift", execshift,
48 "wait", execwait,
49 ".", execdot,
50 "finit", execfinit,
51 "flag", execflag,
52 "ulimit", execulimit,
53 "umask", execumask,
54 "rfork", execrfork,
55 0
56 };
58 void
59 execrfork(void)
60 {
61 int arg;
62 char *s;
64 switch(count(runq->argv->words)){
65 case 1:
66 arg = RFENVG|RFNOTEG|RFNAMEG;
67 break;
68 case 2:
69 arg = 0;
70 for(s = runq->argv->words->next->word;*s;s++) switch(*s){
71 default:
72 goto Usage;
73 case 'n':
74 arg|=RFNAMEG; break;
75 case 'N':
76 arg|=RFCNAMEG;
77 break;
78 case 'e':
79 /* arg|=RFENVG; */ break;
80 case 'E':
81 arg|=RFCENVG; break;
82 case 's':
83 arg|=RFNOTEG; break;
84 case 'f':
85 arg|=RFFDG; break;
86 case 'F':
87 arg|=RFCFDG; break;
88 }
89 break;
90 default:
91 Usage:
92 pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word);
93 setstatus("rfork usage");
94 poplist();
95 return;
96 }
97 if(rfork(arg)==-1){
98 pfmt(err, "rc: %s failed\n", runq->argv->words->word);
99 setstatus("rfork failed");
101 else
102 setstatus("");
103 poplist();
108 #define SEP '\1'
109 char **environp;
110 struct word *enval(s)
111 register char *s;
113 register char *t, c;
114 register struct word *v;
115 for(t=s;*t && *t!=SEP;t++);
116 c=*t;
117 *t='\0';
118 v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
119 *t=c;
120 return v;
122 void Vinit(void){
123 extern char **environ;
124 register char *s;
125 register char **env=environ;
126 environp=env;
127 for(;*env;env++){
128 for(s=*env;*s && *s!='(' && *s!='=';s++);
129 switch(*s){
130 case '\0':
131 /* pfmt(err, "rc: odd environment %q?\n", *env); */
132 break;
133 case '=':
134 *s='\0';
135 setvar(*env, enval(s+1));
136 *s='=';
137 break;
138 case '(': /* ignore functions for now */
139 break;
143 char **envp;
144 void Xrdfn(void){
145 char *p;
146 register char *s;
147 register int len;
148 for(;*envp;envp++){
149 s = *envp;
150 if(strncmp(s, "fn#", 3) == 0){
151 p = strchr(s, '=');
152 if(p == nil)
153 continue;
154 *p = ' ';
155 s[2] = ' ';
156 len = strlen(s);
157 execcmds(opencore(s, len));
158 s[len] = '\0';
159 return;
161 #if 0
162 for(s=*envp;*s && *s!='(' && *s!='=';s++);
163 switch(*s){
164 case '\0':
165 pfmt(err, "environment %q?\n", *envp);
166 break;
167 case '=': /* ignore variables */
168 break;
169 case '(': /* Bourne again */
170 s=*envp+3;
171 envp++;
172 len=strlen(s);
173 s[len]='\n';
174 execcmds(opencore(s, len+1));
175 s[len]='\0';
176 return;
178 #endif
180 Xreturn();
182 union code rdfns[4];
183 void execfinit(void){
184 static int first=1;
185 if(first){
186 rdfns[0].i=1;
187 rdfns[1].f=Xrdfn;
188 rdfns[2].f=Xjump;
189 rdfns[3].i=1;
190 first=0;
192 Xpopm();
193 envp=environp;
194 start(rdfns, 1, runq->local);
196 extern int mapfd(int);
197 int Waitfor(int pid, int unused0){
198 thread *p;
199 Waitmsg *w;
200 char errbuf[ERRMAX];
202 if(pid >= 0 && !havewaitpid(pid))
203 return 0;
204 while((w = wait()) != nil){
205 delwaitpid(w->pid);
206 if(w->pid==pid){
207 if(strncmp(w->msg, "signal: ", 8) == 0)
208 fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
209 setstatus(w->msg);
210 free(w);
211 return 0;
213 if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0)
214 fprint(2, "%d: %s\n", w->pid, w->msg);
215 for(p=runq->ret;p;p=p->ret)
216 if(p->pid==w->pid){
217 p->pid=-1;
218 strcpy(p->status, w->msg);
220 free(w);
223 rerrstr(errbuf, sizeof errbuf);
224 if(strcmp(errbuf, "interrupted")==0) return -1;
225 return 0;
227 char **mkargv(word *a)
229 char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
230 char **argp=argv+1; /* leave one at front for runcoms */
231 for(;a;a=a->next) *argp++=a->word;
232 *argp=0;
233 return argv;
235 /*
236 void addenv(var *v)
238 char envname[256];
239 word *w;
240 int f;
241 io *fd;
242 if(v->changed){
243 v->changed=0;
244 snprint(envname, sizeof envname, "/env/%s", v->name);
245 if((f=Creat(envname))<0)
246 pfmt(err, "rc: can't open %s: %r\n", envname);
247 else{
248 for(w=v->val;w;w=w->next)
249 write(f, w->word, strlen(w->word)+1L);
250 close(f);
253 if(v->fnchanged){
254 v->fnchanged=0;
255 snprint(envname, sizeof envname, "/env/fn#%s", v->name);
256 if((f=Creat(envname))<0)
257 pfmt(err, "rc: can't open %s: %r\n", envname);
258 else{
259 if(v->fn){
260 fd=openfd(f);
261 pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
262 closeio(fd);
264 close(f);
268 void updenvlocal(var *v)
270 if(v){
271 updenvlocal(v->next);
272 addenv(v);
275 void Updenv(void){
276 var *v, **h;
277 for(h=gvar;h!=&gvar[NVAR];h++)
278 for(v=*h;v;v=v->next)
279 addenv(v);
280 if(runq) updenvlocal(runq->local);
282 */
283 int
284 cmpenv(const void *a, const void *b)
286 return strcmp(*(char**)a, *(char**)b);
288 char **mkenv(){
289 register char **env, **ep, *p, *q;
290 register struct var **h, *v;
291 register struct word *a;
292 register int nvar=0, nchr=0, sep;
293 /*
294 * Slightly kludgy loops look at locals then globals
295 */
296 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
297 if((v==vlook(v->name)) && v->val){
298 nvar++;
299 nchr+=strlen(v->name)+1;
300 for(a=v->val;a;a=a->next)
301 nchr+=strlen(a->word)+1;
303 if(v->fn){
304 nvar++;
305 nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
308 env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
309 ep=env;
310 p=(char *)&env[nvar+1];
311 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
312 if((v==vlook(v->name)) && v->val){
313 *ep++=p;
314 q=v->name;
315 while(*q) *p++=*q++;
316 sep='=';
317 for(a=v->val;a;a=a->next){
318 *p++=sep;
319 sep=SEP;
320 q=a->word;
321 while(*q) *p++=*q++;
323 *p++='\0';
325 if(v->fn){
326 *ep++=p;
327 #if 0
328 *p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
329 *p++='f'; *p++='n'; *p++=' ';
330 q=v->name;
331 while(*q) *p++=*q++;
332 *p++=' ';
333 #endif
334 *p++='f'; *p++='n'; *p++='#';
335 q=v->name;
336 while(*q) *p++=*q++;
337 *p++='=';
338 q=v->fn[v->pc-1].s;
339 while(*q) *p++=*q++;
340 *p++='\n';
341 *p++='\0';
344 *ep=0;
345 qsort((char *)env, nvar, sizeof ep[0], cmpenv);
346 return env;
348 void Updenv(void){}
349 void Execute(word *args, word *path)
351 char **argv=mkargv(args);
352 char **env=mkenv();
353 char file[1024];
354 int nc;
355 Updenv();
356 for(;path;path=path->next){
357 nc=strlen(path->word);
358 if(nc<1024){
359 strcpy(file, path->word);
360 if(file[0]){
361 strcat(file, "/");
362 nc++;
364 if(nc+strlen(argv[1])<1024){
365 strcat(file, argv[1]);
366 execve(file, argv+1, env);
368 else werrstr("command name too long");
371 rerrstr(file, sizeof file);
372 pfmt(err, "%s: %s\n", argv[1], file);
373 efree((char *)argv);
375 #define NDIR 256 /* shoud be a better way */
376 int Globsize(char *p)
378 ulong isglob=0, globlen=NDIR+1;
379 for(;*p;p++){
380 if(*p==GLOB){
381 p++;
382 if(*p!=GLOB) isglob++;
383 globlen+=*p=='*'?NDIR:1;
385 else
386 globlen++;
388 return isglob?globlen:0;
390 #define NFD 50
391 #define NDBUF 32
392 struct{
393 Dir *dbuf;
394 int i;
395 int n;
396 }dir[NFD];
397 int Opendir(char *name)
399 Dir *db;
400 int f;
401 f=open(name, 0);
402 if(f==-1)
403 return f;
404 db = dirfstat(f);
405 if(db!=nil && (db->mode&DMDIR)){
406 if(f<NFD){
407 dir[f].i=0;
408 dir[f].n=0;
410 free(db);
411 return f;
413 free(db);
414 close(f);
415 return -1;
417 int Readdir(int f, char *p, int onlydirs)
419 int n;
420 USED(onlydirs); /* only advisory */
422 if(f<0 || f>=NFD)
423 return 0;
424 if(dir[f].i==dir[f].n){ /* read */
425 free(dir[f].dbuf);
426 dir[f].dbuf=0;
427 n=dirread(f, &dir[f].dbuf);
428 if(n>=0)
429 dir[f].n=n;
430 else
431 dir[f].n=0;
432 dir[f].i=0;
434 if(dir[f].i==dir[f].n)
435 return 0;
436 strcpy(p, dir[f].dbuf[dir[f].i].name);
437 dir[f].i++;
438 return 1;
440 void Closedir(int f){
441 if(f>=0 && f<NFD){
442 free(dir[f].dbuf);
443 dir[f].i=0;
444 dir[f].n=0;
445 dir[f].dbuf=0;
447 close(f);
449 int interrupted = 0;
450 void
451 notifyf(void *unused0, char *s)
453 int i;
454 for(i=0;syssigname[i];i++)
455 if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
456 if(strncmp(s, "sys: ", 5)!=0){
457 if(kidpid && !interrupted){
458 interrupted=1;
459 postnote(PNGROUP, kidpid, s);
461 interrupted = 1;
463 goto Out;
465 if(strcmp(s, "sys: window size change") != 0)
466 if(strcmp(s, "sys: write on closed pipe") != 0)
467 if(strcmp(s, "sys: child") != 0)
468 pfmt(err, "rc: note: %s\n", s);
469 noted(NDFLT);
470 return;
471 Out:
472 if(strcmp(s, "interrupt")!=0 || trap[i]==0){
473 trap[i]++;
474 ntrap++;
476 if(ntrap>=32){ /* rc is probably in a trap loop */
477 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
478 abort();
480 noted(NCONT);
482 void Trapinit(void){
483 notify(notifyf);
485 void Unlink(char *name)
487 remove(name);
489 long Write(int fd, char *buf, long cnt)
491 return write(fd, buf, (long)cnt);
493 long Read(int fd, char *buf, long cnt)
495 int i;
497 i = readnb(fd, buf, cnt);
498 if(ntrap) dotrap();
499 return i;
501 long Seek(int fd, long cnt, long whence)
503 return seek(fd, cnt, whence);
505 int Executable(char *file)
507 Dir *statbuf;
508 int ret;
510 statbuf = dirstat(file);
511 if(statbuf == nil) return 0;
512 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
513 free(statbuf);
514 return ret;
516 int Creat(char *file)
518 return create(file, 1, 0666L);
520 int Dup(int a, int b){
521 return dup(a, b);
523 int Dup1(int a){
524 return dup(a, -1);
526 void Exit(char *stat)
528 Updenv();
529 setstatus(stat);
530 exits(truestatus()?"":getstatus());
532 int Eintr(void){
533 return interrupted;
535 void Noerror(void){
536 interrupted=0;
538 int
539 Isatty(int fd){
540 return isatty(fd);
542 void Abort(void){
543 pfmt(err, "aborting\n");
544 flush(err);
545 Exit("aborting");
547 void Memcpy(char *a, char *b, long n)
549 memmove(a, b, (long)n);
551 void *Malloc(ulong n){
552 return malloc(n);
555 int
556 exitcode(char *msg)
558 int n;
560 n = atoi(msg);
561 if(n == 0)
562 n = 1;
563 return n;
566 int *waitpids;
567 int nwaitpids;
569 void
570 addwaitpid(int pid)
572 waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
573 if(waitpids == 0)
574 panic("Can't realloc %d waitpids", nwaitpids+1);
575 waitpids[nwaitpids++] = pid;
578 void
579 delwaitpid(int pid)
581 int r, w;
583 for(r=w=0; r<nwaitpids; r++)
584 if(waitpids[r] != pid)
585 waitpids[w++] = waitpids[r];
586 nwaitpids = w;
589 void
590 clearwaitpids(void)
592 nwaitpids = 0;
595 int
596 havewaitpid(int pid)
598 int i;
600 for(i=0; i<nwaitpids; i++)
601 if(waitpids[i] == pid)
602 return 1;
603 return 0;