plan9ish.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       plan9ish.c (10617B)
       ---
            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/etc/rcmain");
           31 }
           32 
           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 };
           57 
           58 void
           59 execrfork(void)
           60 {
           61         int arg;
           62         char *s;
           63 
           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");
          100         }
          101         else
          102                 setstatus("");
          103         poplist();
          104 }
          105 
          106 
          107 
          108 #define        SEP        '\1'
          109 char **environp;
          110 struct word *enval(s)
          111 register char *s;
          112 {
          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;
          121 }
          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;
          140                 }
          141         }
          142 }
          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;
          160                 }
          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;
          177                 }
          178 #endif
          179         }
          180         Xreturn();
          181 }
          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;
          191         }
          192         Xpopm();
          193         envp=environp;
          194         start(rdfns, 1, runq->local);
          195 }
          196 extern int mapfd(int);
          197 int Waitfor(int pid, int unused0){
          198         thread *p;
          199         Waitmsg *w;
          200         char errbuf[ERRMAX];
          201 
          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;
          212                 }
          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);
          219                         }
          220                 free(w);
          221         }
          222 
          223         rerrstr(errbuf, sizeof errbuf);
          224         if(strcmp(errbuf, "interrupted")==0) return -1;
          225         return 0;
          226 }
          227 char **mkargv(word *a)
          228 {
          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;
          234 }
          235 /*
          236 void addenv(var *v)
          237 {
          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);
          251                 }
          252         }
          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);
          263                         }
          264                         close(f);
          265                 }
          266         }
          267 }
          268 void updenvlocal(var *v)
          269 {
          270         if(v){
          271                 updenvlocal(v->next);
          272                 addenv(v);
          273         }
          274 }
          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);
          281 }
          282 */
          283 int
          284 cmpenv(const void *a, const void *b)
          285 {
          286         return strcmp(*(char**)a, *(char**)b);
          287 }
          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;
          302                 }
          303                 if(v->fn){
          304                         nvar++;
          305                         nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
          306                 }
          307         }
          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++;
          322                         }
          323                         *p++='\0';
          324                 }
          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';
          342                 }
          343         }
          344         *ep=0;
          345         qsort((char *)env, nvar, sizeof ep[0], cmpenv);
          346         return env;        
          347 }
          348 void Updenv(void){}
          349 void Execute(word *args, word *path)
          350 {
          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++;
          363                         }
          364                         if(nc+strlen(argv[1])<1024){
          365                                 strcat(file, argv[1]);
          366                                 execve(file, argv+1, env);
          367                         }
          368                         else werrstr("command name too long");
          369                 }
          370         }
          371         rerrstr(file, sizeof file);
          372         pfmt(err, "%s: %s\n", argv[1], file);
          373         efree((char *)argv);
          374 }
          375 #define        NDIR        256                /* shoud be a better way */
          376 int Globsize(char *p)
          377 {
          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;
          384                 }
          385                 else
          386                         globlen++;
          387         }
          388         return isglob?globlen:0;
          389 }
          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)
          398 {
          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;
          409                 }
          410                 free(db);
          411                 return f;
          412         }
          413         free(db);
          414         close(f);
          415         return -1;
          416 }
          417 int Readdir(int f, char *p, int onlydirs)
          418 {
          419         int n;
          420         USED(onlydirs);        /* only advisory */
          421 
          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;
          433         }
          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;
          439 }
          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;
          446         }
          447         close(f);
          448 }
          449 int interrupted = 0;
          450 void
          451 notifyf(void *unused0, char *s)
          452 {
          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);
          460                                 }
          461                                 interrupted = 1;
          462                         }
          463                         goto Out;
          464                 }
          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++;
          475         }
          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();
          479         }
          480         noted(NCONT);
          481 }
          482 void Trapinit(void){
          483         notify(notifyf);
          484 }
          485 void Unlink(char *name)
          486 {
          487         remove(name);
          488 }
          489 long Write(int fd, char *buf, long cnt)
          490 {
          491         return write(fd, buf, (long)cnt);
          492 }
          493 long Read(int fd, char *buf, long cnt)
          494 {
          495         int i;
          496 
          497         i = readnb(fd, buf, cnt);
          498         if(ntrap) dotrap();
          499         return i;
          500 }
          501 long Seek(int fd, long cnt, long whence)
          502 {
          503         return seek(fd, cnt, whence);
          504 }
          505 int Executable(char *file)
          506 {
          507         Dir *statbuf;
          508         int ret;
          509 
          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;
          515 }
          516 int Creat(char *file)
          517 {
          518         return create(file, 1, 0666L);
          519 }
          520 int Dup(int a, int b){
          521         return dup(a, b);
          522 }
          523 int Dup1(int a){
          524         return dup(a, -1);
          525 }
          526 void Exit(char *stat)
          527 {
          528         Updenv();
          529         setstatus(stat);
          530         exits(truestatus()?"":getstatus());
          531 }
          532 int Eintr(void){
          533         return interrupted;
          534 }
          535 void Noerror(void){
          536         interrupted=0;
          537 }
          538 int
          539 Isatty(int fd){
          540         return isatty(fd);
          541 }
          542 void Abort(void){
          543         pfmt(err, "aborting\n");
          544         flush(err);
          545         Exit("aborting");
          546 }
          547 void Memcpy(char *a, char *b, long n)
          548 {
          549         memmove(a, b, (long)n);
          550 }
          551 void *Malloc(ulong n){
          552         return malloc(n);
          553 }
          554 
          555 int
          556 exitcode(char *msg)
          557 {
          558         int n;
          559         
          560         n = atoi(msg);
          561         if(n == 0)
          562                 n = 1;
          563         return n;
          564 }
          565 
          566 int *waitpids;
          567 int nwaitpids;
          568 
          569 void
          570 addwaitpid(int pid)
          571 {
          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;
          576 }
          577 
          578 void
          579 delwaitpid(int pid)
          580 {
          581         int r, w;
          582         
          583         for(r=w=0; r<nwaitpids; r++)
          584                 if(waitpids[r] != pid)
          585                         waitpids[w++] = waitpids[r];
          586         nwaitpids = w;
          587 }
          588 
          589 void
          590 clearwaitpids(void)
          591 {
          592         nwaitpids = 0;
          593 }
          594 
          595 int
          596 havewaitpid(int pid)
          597 {
          598         int i;
          599         
          600         for(i=0; i<nwaitpids; i++)
          601                 if(waitpids[i] == pid)
          602                         return 1;
          603         return 0;
          604 }