9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | 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 }