/* * Plan 9 versions of system-specific functions * By convention, exported routines herein have names beginning with an * upper case letter. */ #include "rc.h" #include "exec.h" #include "io.h" #include "fns.h" #include "getflags.h" char *Signame[]={ "sigexit", "sighup", "sigint", "sigquit", "sigalrm", "sigkill", "sigfpe", "sigterm", 0 }; char *syssigname[]={ "exit", /* can't happen */ "hangup", "interrupt", "quit", /* can't happen */ "alarm", "kill", "sys: fp: ", "term", 0 }; char* Rcmain(void) { return unsharp("#9/rcmain"); } char Fdprefix[]="/dev/fd/"; long readnb(int, char *, long); void execfinit(void); void execbind(void); void execmount(void); void execulimit(void); void execumask(void); void execrfork(void); builtin Builtin[]={ "cd", execcd, "whatis", execwhatis, "eval", execeval, "exec", execexec, /* but with popword first */ "exit", execexit, "shift", execshift, "wait", execwait, ".", execdot, "finit", execfinit, "flag", execflag, "ulimit", execulimit, "umask", execumask, "rfork", execrfork, 0 }; void execrfork(void) { int arg; char *s; switch(count(runq->argv->words)){ case 1: arg = RFENVG|RFNOTEG|RFNAMEG; break; case 2: arg = 0; for(s = runq->argv->words->next->word;*s;s++) switch(*s){ default: goto Usage; case 'n': arg|=RFNAMEG; break; case 'N': arg|=RFCNAMEG; break; case 'e': /* arg|=RFENVG; */ break; case 'E': arg|=RFCENVG; break; case 's': arg|=RFNOTEG; break; case 'f': arg|=RFFDG; break; case 'F': arg|=RFCFDG; break; } break; default: Usage: pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word); setstatus("rfork usage"); poplist(); return; } if(rfork(arg)==-1){ pfmt(err, "rc: %s failed\n", runq->argv->words->word); setstatus("rfork failed"); } else setstatus(""); poplist(); } #define SEP '\1' char **environp; struct word *enval(s) register char *s; { register char *t, c; register struct word *v; for(t=s;*t && *t!=SEP;t++); c=*t; *t='\0'; v=newword(s, c=='\0'?(struct word *)0:enval(t+1)); *t=c; return v; } void Vinit(void){ extern char **environ; register char *s; register char **env=environ; environp=env; for(;*env;env++){ for(s=*env;*s && *s!='(' && *s!='=';s++); switch(*s){ case '\0': /* pfmt(err, "rc: odd environment %q?\n", *env); */ break; case '=': *s='\0'; setvar(*env, enval(s+1)); *s='='; break; case '(': /* ignore functions for now */ break; } } } char **envp; void Xrdfn(void){ char *p; register char *s; register int len; for(;*envp;envp++){ s = *envp; if(strncmp(s, "fn#", 3) == 0){ p = strchr(s, '='); if(p == nil) continue; *p = ' '; s[2] = ' '; len = strlen(s); execcmds(opencore(s, len)); s[len] = '\0'; return; } #if 0 for(s=*envp;*s && *s!='(' && *s!='=';s++); switch(*s){ case '\0': pfmt(err, "environment %q?\n", *envp); break; case '=': /* ignore variables */ break; case '(': /* Bourne again */ s=*envp+3; envp++; len=strlen(s); s[len]='\n'; execcmds(opencore(s, len+1)); s[len]='\0'; return; } #endif } Xreturn(); } union code rdfns[4]; void execfinit(void){ static int first=1; if(first){ rdfns[0].i=1; rdfns[1].f=Xrdfn; rdfns[2].f=Xjump; rdfns[3].i=1; first=0; } Xpopm(); envp=environp; start(rdfns, 1, runq->local); } extern int mapfd(int); int Waitfor(int pid, int unused0){ thread *p; Waitmsg *w; char errbuf[ERRMAX]; if(pid >= 0 && !havewaitpid(pid)) return 0; while((w = wait()) != nil){ delwaitpid(w->pid); if(w->pid==pid){ if(strncmp(w->msg, "signal: ", 8) == 0) fprint(mapfd(2), "%d: %s\n", w->pid, w->msg); setstatus(w->msg); free(w); return 0; } if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0) fprint(2, "%d: %s\n", w->pid, w->msg); for(p=runq->ret;p;p=p->ret) if(p->pid==w->pid){ p->pid=-1; strcpy(p->status, w->msg); } free(w); } rerrstr(errbuf, sizeof errbuf); if(strcmp(errbuf, "interrupted")==0) return -1; return 0; } char **mkargv(word *a) { char **argv=(char **)emalloc((count(a)+2)*sizeof(char *)); char **argp=argv+1; /* leave one at front for runcoms */ for(;a;a=a->next) *argp++=a->word; *argp=0; return argv; } /* void addenv(var *v) { char envname[256]; word *w; int f; io *fd; if(v->changed){ v->changed=0; snprint(envname, sizeof envname, "/env/%s", v->name); if((f=Creat(envname))<0) pfmt(err, "rc: can't open %s: %r\n", envname); else{ for(w=v->val;w;w=w->next) write(f, w->word, strlen(w->word)+1L); close(f); } } if(v->fnchanged){ v->fnchanged=0; snprint(envname, sizeof envname, "/env/fn#%s", v->name); if((f=Creat(envname))<0) pfmt(err, "rc: can't open %s: %r\n", envname); else{ if(v->fn){ fd=openfd(f); pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s); closeio(fd); } close(f); } } } void updenvlocal(var *v) { if(v){ updenvlocal(v->next); addenv(v); } } void Updenv(void){ var *v, **h; for(h=gvar;h!=&gvar[NVAR];h++) for(v=*h;v;v=v->next) addenv(v); if(runq) updenvlocal(runq->local); } */ int cmpenv(const void *a, const void *b) { return strcmp(*(char**)a, *(char**)b); } char **mkenv(){ register char **env, **ep, *p, *q; register struct var **h, *v; register struct word *a; register int nvar=0, nchr=0, sep; /* * Slightly kludgy loops look at locals then globals */ for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){ if((v==vlook(v->name)) && v->val){ nvar++; nchr+=strlen(v->name)+1; for(a=v->val;a;a=a->next) nchr+=strlen(a->word)+1; } if(v->fn){ nvar++; nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8; } } env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr); ep=env; p=(char *)&env[nvar+1]; for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){ if((v==vlook(v->name)) && v->val){ *ep++=p; q=v->name; while(*q) *p++=*q++; sep='='; for(a=v->val;a;a=a->next){ *p++=sep; sep=SEP; q=a->word; while(*q) *p++=*q++; } *p++='\0'; } if(v->fn){ *ep++=p; #if 0 *p++='#'; *p++='('; *p++=')'; /* to fool Bourne */ *p++='f'; *p++='n'; *p++=' '; q=v->name; while(*q) *p++=*q++; *p++=' '; #endif *p++='f'; *p++='n'; *p++='#'; q=v->name; while(*q) *p++=*q++; *p++='='; q=v->fn[v->pc-1].s; while(*q) *p++=*q++; *p++='\n'; *p++='\0'; } } *ep=0; qsort((char *)env, nvar, sizeof ep[0], cmpenv); return env; } void Updenv(void){} void Execute(word *args, word *path) { char **argv=mkargv(args); char **env=mkenv(); char file[1024]; int nc; Updenv(); for(;path;path=path->next){ nc=strlen(path->word); if(nc<1024){ strcpy(file, path->word); if(file[0]){ strcat(file, "/"); nc++; } if(nc+strlen(argv[1])<1024){ strcat(file, argv[1]); execve(file, argv+1, env); } else werrstr("command name too long"); } } rerrstr(file, sizeof file); pfmt(err, "%s: %s\n", argv[1], file); efree((char *)argv); } #define NDIR 256 /* shoud be a better way */ int Globsize(char *p) { ulong isglob=0, globlen=NDIR+1; for(;*p;p++){ if(*p==GLOB){ p++; if(*p!=GLOB) isglob++; globlen+=*p=='*'?NDIR:1; } else globlen++; } return isglob?globlen:0; } #define NFD 50 #define NDBUF 32 struct{ Dir *dbuf; int i; int n; }dir[NFD]; int Opendir(char *name) { Dir *db; int f; f=open(name, 0); if(f==-1) return f; db = dirfstat(f); if(db!=nil && (db->mode&DMDIR)){ if(f=NFD) return 0; if(dir[f].i==dir[f].n){ /* read */ free(dir[f].dbuf); dir[f].dbuf=0; n=dirread(f, &dir[f].dbuf); if(n>=0) dir[f].n=n; else dir[f].n=0; dir[f].i=0; } if(dir[f].i==dir[f].n) return 0; strcpy(p, dir[f].dbuf[dir[f].i].name); dir[f].i++; return 1; } void Closedir(int f){ if(f>=0 && f=32){ /* rc is probably in a trap loop */ pfmt(err, "rc: Too many traps (trap %s), aborting\n", s); abort(); } noted(NCONT); } void Trapinit(void){ notify(notifyf); } void Unlink(char *name) { remove(name); } long Write(int fd, char *buf, long cnt) { return write(fd, buf, (long)cnt); } long Read(int fd, char *buf, long cnt) { int i; i = readnb(fd, buf, cnt); if(ntrap) dotrap(); return i; } long Seek(int fd, long cnt, long whence) { return seek(fd, cnt, whence); } int Executable(char *file) { Dir *statbuf; int ret; statbuf = dirstat(file); if(statbuf == nil) return 0; ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0); free(statbuf); return ret; } int Creat(char *file) { return create(file, 1, 0666L); } int Dup(int a, int b){ return dup(a, b); } int Dup1(int a){ return dup(a, -1); } void Exit(char *stat) { Updenv(); setstatus(stat); exits(truestatus()?"":getstatus()); } int Eintr(void){ return interrupted; } void Noerror(void){ interrupted=0; } int Isatty(int fd){ return isatty(fd); } void Abort(void){ pfmt(err, "aborting\n"); flush(err); Exit("aborting"); } void Memcpy(char *a, char *b, long n) { memmove(a, b, (long)n); } void *Malloc(ulong n){ return malloc(n); } int exitcode(char *msg) { int n; n = atoi(msg); if(n == 0) n = 1; return n; } int *waitpids; int nwaitpids; void addwaitpid(int pid) { waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]); if(waitpids == 0) panic("Can't realloc %d waitpids", nwaitpids+1); waitpids[nwaitpids++] = pid; } void delwaitpid(int pid) { int r, w; for(r=w=0; r