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 builtin Builtin[]={
40 "cd", execcd,
41 "whatis", execwhatis,
42 "eval", execeval,
43 "exec", execexec, /* but with popword first */
44 "exit", execexit,
45 "shift", execshift,
46 "wait", execwait,
47 ".", execdot,
48 "finit", execfinit,
49 "flag", execflag,
50 "ulimit", execulimit,
51 "umask", execumask,
52 0
53 };
54 #define SEP '\1'
55 char **environp;
56 struct word *enval(s)
57 register char *s;
58 {
59 register char *t, c;
60 register struct word *v;
61 for(t=s;*t && *t!=SEP;t++);
62 c=*t;
63 *t='\0';
64 v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
65 *t=c;
66 return v;
67 }
68 void Vinit(void){
69 extern char **environ;
70 register char *s;
71 register char **env=environ;
72 environp=env;
73 for(;*env;env++){
74 for(s=*env;*s && *s!='(' && *s!='=';s++);
75 switch(*s){
76 case '\0':
77 // pfmt(err, "rc: odd environment %q?\n", *env);
78 break;
79 case '=':
80 *s='\0';
81 setvar(*env, enval(s+1));
82 *s='=';
83 break;
84 case '(': /* ignore functions for now */
85 break;
86 }
87 }
88 }
89 char **envp;
90 void Xrdfn(void){
91 char *p;
92 register char *s;
93 register int len;
94 for(;*envp;envp++){
95 s = *envp;
96 if(strncmp(s, "fn#", 3) == 0){
97 p = strchr(s, '=');
98 if(p == nil)
99 continue;
100 *p = ' ';
101 s[2] = ' ';
102 len = strlen(s);
103 execcmds(opencore(s, len));
104 s[len] = '\0';
105 return;
107 #if 0
108 for(s=*envp;*s && *s!='(' && *s!='=';s++);
109 switch(*s){
110 case '\0':
111 pfmt(err, "environment %q?\n", *envp);
112 break;
113 case '=': /* ignore variables */
114 break;
115 case '(': /* Bourne again */
116 s=*envp+3;
117 envp++;
118 len=strlen(s);
119 s[len]='\n';
120 execcmds(opencore(s, len+1));
121 s[len]='\0';
122 return;
124 #endif
126 Xreturn();
128 union code rdfns[4];
129 void execfinit(void){
130 static int first=1;
131 if(first){
132 rdfns[0].i=1;
133 rdfns[1].f=Xrdfn;
134 rdfns[2].f=Xjump;
135 rdfns[3].i=1;
136 first=0;
138 Xpopm();
139 envp=environp;
140 start(rdfns, 1, runq->local);
142 extern int mapfd(int);
143 int Waitfor(int pid, int unused0){
144 thread *p;
145 Waitmsg *w;
146 char errbuf[ERRMAX];
148 while((w = wait()) != nil){
149 if(w->pid==pid){
150 if(strncmp(w->msg, "signal: ", 8) == 0)
151 fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
152 setstatus(w->msg);
153 free(w);
154 return 0;
156 if(strncmp(w->msg, "signal: ", 8) == 0)
157 fprint(2, "%d: %s\n", w->pid, w->msg);
158 for(p=runq->ret;p;p=p->ret)
159 if(p->pid==w->pid){
160 p->pid=-1;
161 strcpy(p->status, w->msg);
163 free(w);
166 errstr(errbuf, sizeof errbuf);
167 if(strcmp(errbuf, "interrupted")==0) return -1;
168 return 0;
170 char **mkargv(word *a)
172 char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
173 char **argp=argv+1; /* leave one at front for runcoms */
174 for(;a;a=a->next) *argp++=a->word;
175 *argp=0;
176 return argv;
178 /*
179 void addenv(var *v)
181 char envname[256];
182 word *w;
183 int f;
184 io *fd;
185 if(v->changed){
186 v->changed=0;
187 snprint(envname, sizeof envname, "/env/%s", v->name);
188 if((f=Creat(envname))<0)
189 pfmt(err, "rc: can't open %s: %r\n", envname);
190 else{
191 for(w=v->val;w;w=w->next)
192 write(f, w->word, strlen(w->word)+1L);
193 close(f);
196 if(v->fnchanged){
197 v->fnchanged=0;
198 snprint(envname, sizeof envname, "/env/fn#%s", v->name);
199 if((f=Creat(envname))<0)
200 pfmt(err, "rc: can't open %s: %r\n", envname);
201 else{
202 if(v->fn){
203 fd=openfd(f);
204 pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
205 closeio(fd);
207 close(f);
211 void updenvlocal(var *v)
213 if(v){
214 updenvlocal(v->next);
215 addenv(v);
218 void Updenv(void){
219 var *v, **h;
220 for(h=gvar;h!=&gvar[NVAR];h++)
221 for(v=*h;v;v=v->next)
222 addenv(v);
223 if(runq) updenvlocal(runq->local);
225 */
226 int
227 cmpenv(const void *a, const void *b)
229 return strcmp(*(char**)a, *(char**)b);
231 char **mkenv(){
232 register char **env, **ep, *p, *q;
233 register struct var **h, *v;
234 register struct word *a;
235 register int nvar=0, nchr=0, sep;
236 /*
237 * Slightly kludgy loops look at locals then globals
238 */
239 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
240 if((v==vlook(v->name)) && v->val){
241 nvar++;
242 nchr+=strlen(v->name)+1;
243 for(a=v->val;a;a=a->next)
244 nchr+=strlen(a->word)+1;
246 if(v->fn){
247 nvar++;
248 nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
251 env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
252 ep=env;
253 p=(char *)&env[nvar+1];
254 for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
255 if((v==vlook(v->name)) && v->val){
256 *ep++=p;
257 q=v->name;
258 while(*q) *p++=*q++;
259 sep='=';
260 for(a=v->val;a;a=a->next){
261 *p++=sep;
262 sep=SEP;
263 q=a->word;
264 while(*q) *p++=*q++;
266 *p++='\0';
268 if(v->fn){
269 *ep++=p;
270 #if 0
271 *p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
272 *p++='f'; *p++='n'; *p++=' ';
273 q=v->name;
274 while(*q) *p++=*q++;
275 *p++=' ';
276 #endif
277 *p++='f'; *p++='n'; *p++='#';
278 q=v->name;
279 while(*q) *p++=*q++;
280 *p++='=';
281 q=v->fn[v->pc-1].s;
282 while(*q) *p++=*q++;
283 *p++='\n';
284 *p++='\0';
287 *ep=0;
288 qsort((char *)env, nvar, sizeof ep[0], cmpenv);
289 return env;
291 void Updenv(void){}
292 void Execute(word *args, word *path)
294 char **argv=mkargv(args);
295 char **env=mkenv();
296 char file[1024];
297 int nc;
298 Updenv();
299 for(;path;path=path->next){
300 nc=strlen(path->word);
301 if(nc<1024){
302 strcpy(file, path->word);
303 if(file[0]){
304 strcat(file, "/");
305 nc++;
307 if(nc+strlen(argv[1])<1024){
308 strcat(file, argv[1]);
309 execve(file, argv+1, env);
311 else werrstr("command name too long");
314 rerrstr(file, sizeof file);
315 pfmt(err, "%s: %s\n", argv[1], file);
316 efree((char *)argv);
318 #define NDIR 256 /* shoud be a better way */
319 int Globsize(char *p)
321 ulong isglob=0, globlen=NDIR+1;
322 for(;*p;p++){
323 if(*p==GLOB){
324 p++;
325 if(*p!=GLOB) isglob++;
326 globlen+=*p=='*'?NDIR:1;
328 else
329 globlen++;
331 return isglob?globlen:0;
333 #define NFD 50
334 #define NDBUF 32
335 struct{
336 Dir *dbuf;
337 int i;
338 int n;
339 }dir[NFD];
340 int Opendir(char *name)
342 Dir *db;
343 int f;
344 f=open(name, 0);
345 if(f==-1)
346 return f;
347 db = dirfstat(f);
348 if(db!=nil && (db->mode&DMDIR)){
349 if(f<NFD){
350 dir[f].i=0;
351 dir[f].n=0;
353 free(db);
354 return f;
356 free(db);
357 close(f);
358 return -1;
360 int Readdir(int f, char *p)
362 int n;
363 if(f<0 || f>=NFD)
364 return 0;
365 if(dir[f].i==dir[f].n){ /* read */
366 free(dir[f].dbuf);
367 dir[f].dbuf=0;
368 n=dirread(f, &dir[f].dbuf);
369 if(n>=0)
370 dir[f].n=n;
371 else
372 dir[f].n=0;
373 dir[f].i=0;
375 if(dir[f].i==dir[f].n)
376 return 0;
377 strcpy(p, dir[f].dbuf[dir[f].i].name);
378 dir[f].i++;
379 return 1;
381 void Closedir(int f){
382 if(f>=0 && f<NFD){
383 free(dir[f].dbuf);
384 dir[f].i=0;
385 dir[f].n=0;
386 dir[f].dbuf=0;
388 close(f);
390 int interrupted = 0;
391 void
392 notifyf(void *unused0, char *s)
394 int i;
395 for(i=0;syssigname[i];i++)
396 if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
397 if(strncmp(s, "sys: ", 5)!=0){
398 if(kidpid && !interrupted){
399 interrupted=1;
400 postnote(PNGROUP, kidpid, s);
402 interrupted = 1;
404 goto Out;
406 if(strcmp(s, "sys: write on closed pipe") != 0)
407 if(strcmp(s, "sys: child") != 0)
408 pfmt(err, "rc: note: %s\n", s);
409 noted(NDFLT);
410 return;
411 Out:
412 if(strcmp(s, "interrupt")!=0 || trap[i]==0){
413 trap[i]++;
414 ntrap++;
416 if(ntrap>=32){ /* rc is probably in a trap loop */
417 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
418 abort();
420 noted(NCONT);
422 void Trapinit(void){
423 notify(notifyf);
425 void Unlink(char *name)
427 remove(name);
429 long Write(int fd, char *buf, long cnt)
431 return write(fd, buf, (long)cnt);
433 long Read(int fd, char *buf, long cnt)
435 int i;
437 i = read(fd, buf, cnt);
438 if(ntrap) dotrap();
439 return i;
441 long Seek(int fd, long cnt, long whence)
443 return seek(fd, cnt, whence);
445 int Executable(char *file)
447 Dir *statbuf;
448 int ret;
450 statbuf = dirstat(file);
451 if(statbuf == nil) return 0;
452 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
453 free(statbuf);
454 return ret;
456 int Creat(char *file)
458 return create(file, 1, 0666L);
460 int Dup(int a, int b){
461 return dup(a, b);
463 int Dup1(int a){
464 return dup(a, -1);
466 void Exit(char *stat)
468 Updenv();
469 setstatus(stat);
470 exits(truestatus()?"":getstatus());
472 int Eintr(void){
473 return interrupted;
475 void Noerror(void){
476 interrupted=0;
478 int
479 Isatty(int fd){
480 return isatty(fd);
482 void Abort(void){
483 pfmt(err, "aborting\n");
484 flush(err);
485 Exit("aborting");
487 void Memcpy(char *a, char *b, long n)
489 memmove(a, b, (long)n);
491 void *Malloc(ulong n){
492 return malloc(n);