2 * Plan 9 versions of system-specific functions
3 * By convention, exported routines herein have names beginning with an
13 Maxenvname = 128, /* undocumented limit */
17 "sigexit", "sighup", "sigint", "sigquit",
18 "sigalrm", "sigkill", "sigfpe", "sigterm",
21 char *syssigname[] = {
22 "exit", /* can't happen */
25 "quit", /* can't happen */
32 char Rcmain[]="/rc/lib/rcmain";
33 char Fdprefix[]="/fd/";
37 void execnewpgrp(void);
42 "exec", execexec, /* but with popword first */
58 switch(count(runq->argv->words)){
60 arg = RFENVG|RFNAMEG|RFNOTEG;
64 for(s = runq->argv->words->next->word;*s;s++) switch(*s){
88 pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word);
89 setstatus("rfork usage");
94 pfmt(err, "rc: %s failed\n", runq->argv->words->word);
95 setstatus("rfork failed");
105 int dir, f, len, i, n, nent;
107 char envname[Maxenvname];
111 dir = open("/env", OREAD);
113 pfmt(err, "rc: can't open /env: %r\n");
118 nent = dirread(dir, &ent);
121 for(i = 0; i<nent; i++){
123 if(len && strncmp(ent[i].name, "fn#", 3)!=0){
124 snprint(envname, sizeof envname, "/env/%s", ent[i].name);
125 if((f = open(envname, 0))>=0){
126 buf = emalloc(len+1);
127 n = readn(f, buf, len);
133 /* Charitably add a 0 at the end if need be */
138 while(s!=buf && s[-1]!='\0') --s;
139 val = newword(s, val);
144 setvar(ent[i].name, val);
145 vlook(ent[i].name)->changed = 0;
162 char envname[Maxenvname];
163 static Dir *ent, *allocent;
169 nent = dirread(envdir, &allocent);
178 if(len && strncmp(e->name, "fn#", 3)==0){
179 snprint(envname, sizeof envname, "/env/%s", e->name);
180 if((f = open(envname, 0))>=0){
195 static int first = 1;
204 envdir = open("/env", 0);
206 pfmt(err, "rc: can't open /env: %r\n");
209 start(rdfns, 1, runq->local);
213 Waitfor(int pid, int)
219 if(pid >= 0 && !havewaitpid(pid))
222 while((w = wait()) != nil){
229 for(p = runq->ret;p;p = p->ret)
232 strcpy(p->status, w->msg);
237 errstr(errbuf, sizeof errbuf);
238 if(strcmp(errbuf, "interrupted")==0) return -1;
245 char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
246 char **argp = argv+1; /* leave one at front for runcoms */
247 for(;a;a = a->next) *argp++=a->word;
255 char envname[Maxenvname];
261 snprint(envname, sizeof envname, "/env/%s", v->name);
262 if((f = Creat(envname))<0)
263 pfmt(err, "rc: can't open %s: %r\n", envname);
265 for(w = v->val;w;w = w->next)
266 write(f, w->word, strlen(w->word)+1L);
272 snprint(envname, sizeof envname, "/env/fn#%s", v->name);
273 if((f = Creat(envname))<0)
274 pfmt(err, "rc: can't open %s: %r\n", envname);
278 pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
290 updenvlocal(v->next);
299 for(h = gvar;h!=&gvar[NVAR];h++)
300 for(v=*h;v;v = v->next)
303 updenvlocal(runq->local);
306 /* not used on plan 9 */
308 ForkExecute(char *file, char **argv, int sin, int sout, int serr)
312 if(access(file, 1) != 0)
314 switch(pid = fork()){
337 Execute(word *args, word *path)
339 char **argv = mkargv(args);
340 char file[1024], errstr[1024];
345 for(;path;path = path->next){
346 nc = strlen(path->word);
347 if(nc < sizeof file - 1){ /* 1 for / */
348 strcpy(file, path->word);
353 if(nc + strlen(argv[1]) < sizeof file){
354 strcat(file, argv[1]);
356 rerrstr(errstr, sizeof errstr);
358 * if file exists and is executable, exec should
359 * have worked, unless it's a directory or an
360 * executable for another architecture. in
361 * particular, if it failed due to lack of
362 * swap/vm (e.g., arg. list too long) or other
363 * allocation failure, stop searching and print
364 * the reason for failure.
366 if (strstr(errstr, " allocat") != nil ||
367 strstr(errstr, " full") != nil)
370 else werrstr("command name too long");
373 pfmt(err, "%s: %s\n", argv[1], errstr);
376 #define NDIR 256 /* shoud be a better way */
381 int isglob = 0, globlen = NDIR+1;
387 globlen+=*p=='*'?NDIR:1;
392 return isglob?globlen:0;
411 if(db!=nil && (db->mode&DMDIR)){
425 trimdirs(Dir *d, int nd)
429 for(r=w=0; r<nd; r++)
436 * onlydirs is advisory -- it means you only
437 * need to return the directories. it's okay to
438 * return files too (e.g., on unix where you can't
439 * tell during the readdir), but that just makes
440 * the globber work harder.
443 Readdir(int f, void *p, int onlydirs)
450 if(dir[f].i==dir[f].n){ /* read */
453 n = dirread(f, &dir[f].dbuf);
456 n = trimdirs(dir[f].dbuf, n);
465 if(dir[f].i == dir[f].n)
467 strcpy(p, dir[f].dbuf[dir[f].i].name);
485 notifyf(void*, char *s)
488 for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
489 if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
492 pfmt(err, "rc: note: %s\n", s);
496 if(strcmp(s, "interrupt")!=0 || trap[i]==0){
500 if(ntrap>=32){ /* rc is probably in a trap loop */
501 pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
520 Write(int fd, void *buf, long cnt)
522 return write(fd, buf, cnt);
526 Read(int fd, void *buf, long cnt)
528 return read(fd, buf, cnt);
532 Seek(int fd, long cnt, long whence)
534 return seek(fd, cnt, whence);
538 Executable(char *file)
543 statbuf = dirstat(file);
546 ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
554 return create(file, 1, 0666L);
574 exits(truestatus()?"":getstatus());
594 if(fd2path(fd, buf, sizeof buf) != 0)
597 /* might be #c/cons during boot - fixed 22 april 2005, remove this later */
598 if(strcmp(buf, "#c/cons") == 0)
601 /* might be /mnt/term/dev/cons */
602 return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
608 pfmt(err, "aborting\n");
614 Memcpy(void *a, void *b, long n)
626 Realloc(void *p, ulong n)
628 return realloc(p, n);
637 waitpids = erealloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
638 waitpids[nwaitpids++] = pid;
646 for(r=w=0; r<nwaitpids; r++)
647 if(waitpids[r] != pid)
648 waitpids[w++] = waitpids[r];
663 for(i=0; i<nwaitpids; i++)
664 if(waitpids[i] == pid)
669 /* avoid loading any floating-point library code */