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 void execfinit(void);
35 void execbind(void);
36 void execmount(void);
37 void execulimit(void);
38 void execumask(void);
39 void execrfork(void);
40 builtin Builtin[]={
41 "cd", execcd,
42 "whatis", execwhatis,
43 "eval", execeval,
44 "exec", execexec, /* but with popword first */
45 "exit", execexit,
46 "shift", execshift,
47 "wait", execwait,
48 ".", execdot,
49 "finit", execfinit,
50 "flag", execflag,
51 "ulimit", execulimit,
52 "umask", execumask,
53 "rfork", execrfork,
54 0
55 };
57 void
58 execrfork(void)
59 {
60 int arg;
61 char *s;
63 switch(count(runq->argv->words)){
64 case 1:
65 arg = RFENVG|RFNOTEG|RFNAMEG;
66 break;
67 case 2:
68 arg = 0;
69 for(s = runq->argv->words->next->word;*s;s++) switch(*s){
70 default:
71 goto Usage;
72 case 'n':
73 arg|=RFNAMEG; break;
74 case 'N':
75 arg|=RFCNAMEG;
76 break;
77 case 'e':
78 /* arg|=RFENVG; */ break;
79 case 'E':
80 arg|=RFCENVG; break;
81 case 's':
82 arg|=RFNOTEG; break;
83 case 'f':
84 arg|=RFFDG; break;
85 case 'F':
86 arg|=RFCFDG; break;
87 }
88 break;
89 default:
90 Usage:
91 pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word);
92 setstatus("rfork usage");
93 poplist();
94 return;
95 }
96 if(rfork(arg)==-1){
97 pfmt(err, "rc: %s failed\n", runq->argv->words->word);
98 setstatus("rfork failed");
99 }
100 else
101 setstatus("");
102 poplist();
107 #define SEP '\1'
108 char **environp;
109 struct word *enval(s)
110 register char *s;
112 register char *t, c;
113 register struct word *v;
114 for(t=s;*t && *t!=SEP;t++);
115 c=*t;
116 *t='\0';
117 v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
118 *t=c;
119 return v;
121 void Vinit(void){
122 extern char **environ;
123 register char *s;
124 register char **env=environ;
125 environp=env;
126 for(;*env;env++){
127 for(s=*env;*s && *s!='(' && *s!='=';s++);
128 switch(*s){
129 case '\0':
130 /* pfmt(err, "rc: odd environment %q?\n", *env); */
131 break;
132 case '=':
133 *s='\0';
134 setvar(*env, enval(s+1));
135 *s='=';
136 break;
137 case '(': /* ignore functions for now */
138 break;
142 char **envp;
143 void Xrdfn(void){
144 char *p;
145 register char *s;
146 register int len;
147 for(;*envp;envp++){
148 s = *envp;
149 if(strncmp(s, "fn#", 3) == 0){
150 p = strchr(s, '=');
151 if(p == nil)
152 continue;
153 *p = ' ';
154 s[2] = ' ';
155 len = strlen(s);
156 execcmds(opencore(s, len));
157 s[len] = '\0';
158 return;
160 #if 0
161 for(s=*envp;*s && *s!='(' && *s!='=';s++);
162 switch(*s){
163 case '\0':
164 pfmt(err, "environment %q?\n", *envp);
165 break;
166 case '=': /* ignore variables */
167 break;
168 case '(': /* Bourne again */
169 s=*envp+3;
170 envp++;
171 len=strlen(s);
172 s[len]='\n';
173 execcmds(opencore(s, len+1));
174 s[len]='\0';
175 return;
177 #endif
179 Xreturn();
181 union code rdfns[4];
182 void execfinit(void){
183 static int first=1;
184 if(first){
185 rdfns[0].i=1;
186 rdfns[1].f=Xrdfn;
187 rdfns[2].f=Xjump;
188 rdfns[3].i=1;
189 first=0;
191 Xpopm();
192 envp=environp;
193 start(rdfns, 1, runq->local);
195 extern int mapfd(int);
196 int Waitfor(int pid, int unused0){
197 thread *p;
198 Waitmsg *w;
199 char errbuf[ERRMAX];
201 while((w = wait()) != nil){
202 if(w->pid==pid){
203 if(strncmp(w->msg, "signal: ", 8) == 0)
204 fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
205 setstatus(w->msg);
206 free(w);
207 return 0;
209 if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0)
210 fprint(2, "%d: %s\n", w->pid, w->msg);
211 for(p=runq->ret;p;p=p->ret)
212 if(p->pid==w->pid){
213 p->pid=-1;
214 strcpy(p->status, w->msg);
216 free(w);
219 errstr(errbuf, sizeof errbuf);
220 if(strcmp(errbuf, "interrupted")==0) return -1;
221 return 0;
223 char **mkargv(word *a)
225 char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
226 char **argp=argv+1; /* leave one at front for runcoms */
227 for(;a;a=a->next) *argp++=a->word;
228 *argp=0;
229 return argv;
231 /*
232 void addenv(var *v)
234 char envname[256];
235 word *w;
236 int f;
237 io *fd;
238 if(v->changed){
239 v->changed=0;
240 snprint(envname, sizeof envname, "/env/%s", v->name);
241 if((f=Creat(envname))<0)
242 pfmt(err, "rc: can't open %s: %r\n", envname);
243 else{
244 for(w=v->val;w;w=w->next)
245 write(f, w->word, strlen(w->word)+1L);
246 close(f);
249 if(v->fnchanged){
250 v->fnchanged=0;
251 snprint(envname, sizeof envname, "/env/fn#%s", v->name);
252 if((f=Creat(envname))<0)
253 pfmt(err, "rc: can't open %s: %r\n", envname);
254 else{
255 if(v->fn){
256 fd=openfd(f);
257 pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
258 closeio(fd);
260 close(f);
264 void updenvlocal(var *v)
266 if(v){
267 updenvlocal(v->next);
268 addenv(v);
271 void Updenv(void){
272 var *v, **h;
273 for(h=gvar;h!=&gvar[NVAR];h++)
274 for(v=*h;v;v=v->next)
275 addenv(v);
276 if(runq) updenvlocal(runq->local);
278 */
279 int
280 cmpenv(const void *a, const void *b)
282 return strcmp(*(char**)a, *(char**)b);
284 char **mkenv(){
285 register char **env, **ep, *p, *q;
286 register struct var **h, *v;
287 register struct word *a;
288 register int nvar=0, nchr=0, sep;
289 /*
290 * Slightly kludgy loops look at locals then globals
291 */
292 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
293 if((v==vlook(v->name)) && v->val){
294 nvar++;
295 nchr+=strlen(v->name)+1;
296 for(a=v->val;a;a=a->next)
297 nchr+=strlen(a->word)+1;
299 if(v->fn){
300 nvar++;
301 nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
304 env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
305 ep=env;
306 p=(char *)&env[nvar+1];
307 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
308 if((v==vlook(v->name)) && v->val){
309 *ep++=p;
310 q=v->name;
311 while(*q) *p++=*q++;
312 sep='=';
313 for(a=v->val;a;a=a->next){
314 *p++=sep;
315 sep=SEP;
316 q=a->word;
317 while(*q) *p++=*q++;
319 *p++='\0';
321 if(v->fn){
322 *ep++=p;
323 #if 0
324 *p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
325 *p++='f'; *p++='n'; *p++=' ';
326 q=v->name;
327 while(*q) *p++=*q++;
328 *p++=' ';
329 #endif
330 *p++='f'; *p++='n'; *p++='#';
331 q=v->name;
332 while(*q) *p++=*q++;
333 *p++='=';
334 q=v->fn[v->pc-1].s;
335 while(*q) *p++=*q++;
336 *p++='\n';
337 *p++='\0';
340 *ep=0;
341 qsort((char *)env, nvar, sizeof ep[0], cmpenv);
342 return env;
344 void Updenv(void){}
345 void Execute(word *args, word *path)
347 char **argv=mkargv(args);
348 char **env=mkenv();
349 char file[1024];
350 int nc;
351 Updenv();
352 for(;path;path=path->next){
353 nc=strlen(path->word);
354 if(nc<1024){
355 strcpy(file, path->word);
356 if(file[0]){
357 strcat(file, "/");
358 nc++;
360 if(nc+strlen(argv[1])<1024){
361 strcat(file, argv[1]);
362 execve(file, argv+1, env);
364 else werrstr("command name too long");
367 rerrstr(file, sizeof file);
368 pfmt(err, "%s: %s\n", argv[1], file);
369 efree((char *)argv);
371 #define NDIR 256 /* shoud be a better way */
372 int Globsize(char *p)
374 ulong isglob=0, globlen=NDIR+1;
375 for(;*p;p++){
376 if(*p==GLOB){
377 p++;
378 if(*p!=GLOB) isglob++;
379 globlen+=*p=='*'?NDIR:1;
381 else
382 globlen++;
384 return isglob?globlen:0;
386 #define NFD 50
387 #define NDBUF 32
388 struct{
389 Dir *dbuf;
390 int i;
391 int n;
392 }dir[NFD];
393 int Opendir(char *name)
395 Dir *db;
396 int f;
397 f=open(name, 0);
398 if(f==-1)
399 return f;
400 db = dirfstat(f);
401 if(db!=nil && (db->mode&DMDIR)){
402 if(f<NFD){
403 dir[f].i=0;
404 dir[f].n=0;
406 free(db);
407 return f;
409 free(db);
410 close(f);
411 return -1;
413 int Readdir(int f, char *p)
415 int n;
416 if(f<0 || f>=NFD)
417 return 0;
418 if(dir[f].i==dir[f].n){ /* read */
419 free(dir[f].dbuf);
420 dir[f].dbuf=0;
421 n=dirread(f, &dir[f].dbuf);
422 if(n>=0)
423 dir[f].n=n;
424 else
425 dir[f].n=0;
426 dir[f].i=0;
428 if(dir[f].i==dir[f].n)
429 return 0;
430 strcpy(p, dir[f].dbuf[dir[f].i].name);
431 dir[f].i++;
432 return 1;
434 void Closedir(int f){
435 if(f>=0 && f<NFD){
436 free(dir[f].dbuf);
437 dir[f].i=0;
438 dir[f].n=0;
439 dir[f].dbuf=0;
441 close(f);
443 int interrupted = 0;
444 void
445 notifyf(void *unused0, char *s)
447 int i;
448 for(i=0;syssigname[i];i++)
449 if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
450 if(strncmp(s, "sys: ", 5)!=0){
451 if(kidpid && !interrupted){
452 interrupted=1;
453 postnote(PNGROUP, kidpid, s);
455 interrupted = 1;
457 goto Out;
459 if(strcmp(s, "sys: window size change") != 0)
460 if(strcmp(s, "sys: write on closed pipe") != 0)
461 if(strcmp(s, "sys: child") != 0)
462 pfmt(err, "rc: note: %s\n", s);
463 noted(NDFLT);
464 return;
465 Out:
466 if(strcmp(s, "interrupt")!=0 || trap[i]==0){
467 trap[i]++;
468 ntrap++;
470 if(ntrap>=32){ /* rc is probably in a trap loop */
471 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
472 abort();
474 noted(NCONT);
476 void Trapinit(void){
477 notify(notifyf);
479 void Unlink(char *name)
481 remove(name);
483 long Write(int fd, char *buf, long cnt)
485 return write(fd, buf, (long)cnt);
487 long Read(int fd, char *buf, long cnt)
489 int i;
491 i = read(fd, buf, cnt);
492 if(ntrap) dotrap();
493 return i;
495 long Seek(int fd, long cnt, long whence)
497 return seek(fd, cnt, whence);
499 int Executable(char *file)
501 Dir *statbuf;
502 int ret;
504 statbuf = dirstat(file);
505 if(statbuf == nil) return 0;
506 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
507 free(statbuf);
508 return ret;
510 int Creat(char *file)
512 return create(file, 1, 0666L);
514 int Dup(int a, int b){
515 return dup(a, b);
517 int Dup1(int a){
518 return dup(a, -1);
520 void Exit(char *stat)
522 Updenv();
523 setstatus(stat);
524 exits(truestatus()?"":getstatus());
526 int Eintr(void){
527 return interrupted;
529 void Noerror(void){
530 interrupted=0;
532 int
533 Isatty(int fd){
534 return isatty(fd);
536 void Abort(void){
537 pfmt(err, "aborting\n");
538 flush(err);
539 Exit("aborting");
541 void Memcpy(char *a, char *b, long n)
543 memmove(a, b, (long)n);
545 void *Malloc(ulong n){
546 return malloc(n);
549 int
550 exitcode(char *msg)
552 int n;
554 n = atoi(msg);
555 if(n == 0)
556 n = 1;
557 return n;