rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 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 | { |
rsc | 8ad5179 | 2004-03-25 23:03:57 +0000 | [diff] [blame] | 30 | return unsharp("#9/rcmain"); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 31 | } |
| 32 | |
rsc | 8ad5179 | 2004-03-25 23:03:57 +0000 | [diff] [blame] | 33 | char Fdprefix[]="/dev/fd/"; |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 34 | void execfinit(void); |
| 35 | void execbind(void); |
| 36 | void execmount(void); |
rsc | 39cff6e | 2004-10-17 05:19:53 +0000 | [diff] [blame] | 37 | void execulimit(void); |
| 38 | void execumask(void); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 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, |
rsc | 39cff6e | 2004-10-17 05:19:53 +0000 | [diff] [blame] | 50 | "ulimit", execulimit, |
| 51 | "umask", execumask, |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 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': |
rsc | c4097c2 | 2004-05-11 17:51:27 +0000 | [diff] [blame] | 77 | // pfmt(err, "rc: odd environment %q?\n", *env); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 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; |
| 106 | } |
| 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; |
| 123 | } |
| 124 | #endif |
| 125 | } |
| 126 | Xreturn(); |
| 127 | } |
| 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; |
| 137 | } |
| 138 | Xpopm(); |
| 139 | envp=environp; |
| 140 | start(rdfns, 1, runq->local); |
| 141 | } |
rsc | f002cc1 | 2004-10-17 05:29:53 +0000 | [diff] [blame] | 142 | extern int mapfd(int); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 143 | int Waitfor(int pid, int unused0){ |
| 144 | thread *p; |
| 145 | Waitmsg *w; |
| 146 | char errbuf[ERRMAX]; |
| 147 | |
| 148 | while((w = wait()) != nil){ |
| 149 | if(w->pid==pid){ |
rsc | f002cc1 | 2004-10-17 05:29:53 +0000 | [diff] [blame] | 150 | if(strncmp(w->msg, "signal: ", 8) == 0) |
| 151 | fprint(mapfd(2), "%d: %s\n", w->pid, w->msg); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 152 | setstatus(w->msg); |
| 153 | free(w); |
| 154 | return 0; |
| 155 | } |
rsc | f002cc1 | 2004-10-17 05:29:53 +0000 | [diff] [blame] | 156 | if(strncmp(w->msg, "signal: ", 8) == 0) |
| 157 | fprint(2, "%d: %s\n", w->pid, w->msg); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 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); |
| 162 | } |
| 163 | free(w); |
| 164 | } |
| 165 | |
| 166 | errstr(errbuf, sizeof errbuf); |
| 167 | if(strcmp(errbuf, "interrupted")==0) return -1; |
| 168 | return 0; |
| 169 | } |
| 170 | char **mkargv(word *a) |
| 171 | { |
| 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; |
| 177 | } |
| 178 | /* |
| 179 | void addenv(var *v) |
| 180 | { |
| 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); |
| 194 | } |
| 195 | } |
| 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); |
| 206 | } |
| 207 | close(f); |
| 208 | } |
| 209 | } |
| 210 | } |
| 211 | void updenvlocal(var *v) |
| 212 | { |
| 213 | if(v){ |
| 214 | updenvlocal(v->next); |
| 215 | addenv(v); |
| 216 | } |
| 217 | } |
| 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); |
| 224 | } |
| 225 | */ |
| 226 | int |
rsc | be22ae2 | 2004-03-26 01:59:35 +0000 | [diff] [blame] | 227 | cmpenv(const void *a, const void *b) |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 228 | { |
rsc | be22ae2 | 2004-03-26 01:59:35 +0000 | [diff] [blame] | 229 | return strcmp(*(char**)a, *(char**)b); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 230 | } |
| 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; |
| 245 | } |
| 246 | if(v->fn){ |
| 247 | nvar++; |
| 248 | nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8; |
| 249 | } |
| 250 | } |
| 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++; |
| 265 | } |
| 266 | *p++='\0'; |
| 267 | } |
| 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'; |
| 285 | } |
| 286 | } |
| 287 | *ep=0; |
| 288 | qsort((char *)env, nvar, sizeof ep[0], cmpenv); |
| 289 | return env; |
| 290 | } |
| 291 | void Updenv(void){} |
| 292 | void Execute(word *args, word *path) |
| 293 | { |
| 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++; |
| 306 | } |
| 307 | if(nc+strlen(argv[1])<1024){ |
| 308 | strcat(file, argv[1]); |
| 309 | execve(file, argv+1, env); |
| 310 | } |
| 311 | else werrstr("command name too long"); |
| 312 | } |
| 313 | } |
| 314 | rerrstr(file, sizeof file); |
| 315 | pfmt(err, "%s: %s\n", argv[1], file); |
| 316 | efree((char *)argv); |
| 317 | } |
| 318 | #define NDIR 256 /* shoud be a better way */ |
| 319 | int Globsize(char *p) |
| 320 | { |
| 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; |
| 327 | } |
| 328 | else |
| 329 | globlen++; |
| 330 | } |
| 331 | return isglob?globlen:0; |
| 332 | } |
| 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) |
| 341 | { |
| 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; |
| 352 | } |
| 353 | free(db); |
| 354 | return f; |
| 355 | } |
| 356 | free(db); |
| 357 | close(f); |
| 358 | return -1; |
| 359 | } |
| 360 | int Readdir(int f, char *p) |
| 361 | { |
| 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; |
| 374 | } |
| 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; |
| 380 | } |
| 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; |
| 387 | } |
| 388 | close(f); |
| 389 | } |
| 390 | int interrupted = 0; |
| 391 | void |
| 392 | notifyf(void *unused0, char *s) |
| 393 | { |
| 394 | int i; |
rsc | 669250d | 2003-12-03 22:50:48 +0000 | [diff] [blame] | 395 | for(i=0;syssigname[i];i++) |
| 396 | if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){ |
rsc | 69ab5d3 | 2004-03-26 17:30:36 +0000 | [diff] [blame] | 397 | if(strncmp(s, "sys: ", 5)!=0){ |
| 398 | if(kidpid && !interrupted){ |
| 399 | interrupted=1; |
| 400 | postnote(PNGROUP, kidpid, s); |
| 401 | } |
| 402 | interrupted = 1; |
| 403 | } |
rsc | 669250d | 2003-12-03 22:50:48 +0000 | [diff] [blame] | 404 | goto Out; |
| 405 | } |
rsc | c6f9206 | 2005-07-14 12:48:02 +0000 | [diff] [blame^] | 406 | if(strcmp(s, "sys: window size change") != 0) |
rsc | 4ee543e | 2005-03-18 19:03:25 +0000 | [diff] [blame] | 407 | if(strcmp(s, "sys: write on closed pipe") != 0) |
rsc | 0b91799 | 2004-03-04 02:36:36 +0000 | [diff] [blame] | 408 | if(strcmp(s, "sys: child") != 0) |
| 409 | pfmt(err, "rc: note: %s\n", s); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 410 | noted(NDFLT); |
| 411 | return; |
| 412 | Out: |
| 413 | if(strcmp(s, "interrupt")!=0 || trap[i]==0){ |
| 414 | trap[i]++; |
| 415 | ntrap++; |
| 416 | } |
| 417 | if(ntrap>=32){ /* rc is probably in a trap loop */ |
| 418 | pfmt(err, "rc: Too many traps (trap %s), aborting\n", s); |
| 419 | abort(); |
| 420 | } |
| 421 | noted(NCONT); |
| 422 | } |
| 423 | void Trapinit(void){ |
| 424 | notify(notifyf); |
| 425 | } |
| 426 | void Unlink(char *name) |
| 427 | { |
| 428 | remove(name); |
| 429 | } |
| 430 | long Write(int fd, char *buf, long cnt) |
| 431 | { |
| 432 | return write(fd, buf, (long)cnt); |
| 433 | } |
| 434 | long Read(int fd, char *buf, long cnt) |
| 435 | { |
rsc | 669250d | 2003-12-03 22:50:48 +0000 | [diff] [blame] | 436 | int i; |
| 437 | |
| 438 | i = read(fd, buf, cnt); |
| 439 | if(ntrap) dotrap(); |
| 440 | return i; |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 441 | } |
| 442 | long Seek(int fd, long cnt, long whence) |
| 443 | { |
| 444 | return seek(fd, cnt, whence); |
| 445 | } |
| 446 | int Executable(char *file) |
| 447 | { |
| 448 | Dir *statbuf; |
| 449 | int ret; |
| 450 | |
| 451 | statbuf = dirstat(file); |
| 452 | if(statbuf == nil) return 0; |
| 453 | ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0); |
| 454 | free(statbuf); |
| 455 | return ret; |
| 456 | } |
| 457 | int Creat(char *file) |
| 458 | { |
| 459 | return create(file, 1, 0666L); |
| 460 | } |
| 461 | int Dup(int a, int b){ |
| 462 | return dup(a, b); |
| 463 | } |
rsc | 134c20c | 2005-02-13 21:38:32 +0000 | [diff] [blame] | 464 | int Dup1(int a){ |
| 465 | return dup(a, -1); |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 466 | } |
| 467 | void Exit(char *stat) |
| 468 | { |
| 469 | Updenv(); |
| 470 | setstatus(stat); |
| 471 | exits(truestatus()?"":getstatus()); |
| 472 | } |
| 473 | int Eintr(void){ |
| 474 | return interrupted; |
| 475 | } |
| 476 | void Noerror(void){ |
| 477 | interrupted=0; |
| 478 | } |
| 479 | int |
rsc | be22ae2 | 2004-03-26 01:59:35 +0000 | [diff] [blame] | 480 | Isatty(int fd){ |
rsc | f08fded | 2003-11-23 18:04:08 +0000 | [diff] [blame] | 481 | return isatty(fd); |
| 482 | } |
| 483 | void Abort(void){ |
| 484 | pfmt(err, "aborting\n"); |
| 485 | flush(err); |
| 486 | Exit("aborting"); |
| 487 | } |
| 488 | void Memcpy(char *a, char *b, long n) |
| 489 | { |
| 490 | memmove(a, b, (long)n); |
| 491 | } |
| 492 | void *Malloc(ulong n){ |
| 493 | return malloc(n); |
| 494 | } |