1 From geoff@collyer.net Fri Dec 19 01:21:40 EST 2003
2 Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:21:39 EST 2003
3 Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:21:35 EST 2003
4 Message-ID: <c790d8b1e06b3918ad2c7848a3ae0ec7@collyer.net>
5 subject: rc on unix, part 1
6 From: Geoff Collyer <geoff@collyer.net>
7 Date: Thu, 18 Dec 2003 22:21:33 -0800
8 To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
10 Content-Type: text/plain; charset="US-ASCII"
11 Content-Transfer-Encoding: 7bit
13 I got /sys/src/cmd/rc to compile under APE (in preparation for moving it
14 to Unixes) with the following changed files. I cadged some include files
15 from rsc but had to edit lib9.h slightly. I'll send the include files
16 separately. I can't tell if it works yet, but it does complain about
17 /usr/lib/rcmain being absent when I start it. Oh, and I haven't yet
18 simulated the effect of the OCEXEC bit.
21 # To unbundle, run this file
23 sed 's/^X//' >mkfile <<'!'
48 OFILES=$COMMONOFILES $UNIXOFILES y.tab.$O
63 X ${COMMONOFILES:%.$O=%.c}\
64 X ${UNIXOFILES:%.$O=%.c}\
65 X ${PLAN9OFILES:%.$O=%.c}\
67 X ${TARG:%=/386/bin/%}\
69 CC=pcc -c -B -I../include
75 X cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
78 X rm -f [$OS].out *.[$OS] [xy].tab.? y.debug $TARG
85 X for(test in test/*.test) rc $test >$test.out
88 X pr mkfile $HFILES $FILES $FILES9 $FILESUNIX $YFILES|lp -du
91 sed 's/^X//' >simple.c <<'!'
93 X * Maybe `simple' is a misnomer.
96 X#include "getflags.h"
101 X * Search through the following code to see if we're just going to exit.
104 X union code *c=&runq->code[runq->pc];
105 X while(c->f==Xpopredir) c++;
106 X return c->f==Xexit;
115 X struct builtin *bp;
118 X a = runq->argv->words;
120 X Xerror1("empty argument list");
124 X pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
125 X v = gvlook(a->word);
129 X if(strcmp(a->word, "builtin")==0){
131 X pfmt(err, "builtin: empty argument list\n");
132 X setstatus("empty arg list");
139 X for(bp = Builtin;bp->name;bp++)
140 X if(strcmp(a->word, bp->name)==0){
145 X /* fork and wait is redundant */
152 X Updenv(); /* necessary so changes don't go out again */
153 X if((pid = execforkexec()) < 0){
154 X Xerror("try again");
158 X /* interrupts don't get us out */
160 X while(Waitfor(pid, 1) < 0)
165 struct word nullpath = { "", 0};
174 X if(rp->from!=rp->to){
175 X Dup(rp->from, rp->to);
180 X Dup(rp->from, rp->to);
193 X if(strncmp(w, "/", 1)==0
194 X || strncmp(w, "#", 1)==0
195 X || strncmp(w, "./", 2)==0
196 X || strncmp(w, "../", 3)==0
197 X || (path = vlook("path")->val)==0)
205 X popword(); /* "exec" */
206 X if(runq->argv->words==0){
207 X Xerror1("empty argument list");
210 X doredir(runq->redir);
211 X Execute(runq->argv->words, searchpath(runq->argv->words->word));
220 X starval = runq->argv->words;
221 X runq->argv->words = 0;
223 X start(func->fn, func->pc, (struct var *)0);
224 X runq->local = newvar(strdup("*"), runq->local);
225 X runq->local->val = starval;
226 X runq->local->changed = 1;
232 X /* report to /dev/wdir if it exists and we're interactive */
233 X static int wdirfd = -2;
234 X if(chdir(word)<0) return -1;
236 X if(wdirfd==-2) /* try only once */
237 X /* TODO: arrange close-on-exec on Unix */
238 X wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
240 X write(wdirfd, word, strlen(word));
248 X word *a = runq->argv->words;
251 X setstatus("can't cd");
252 X cdpath = vlook("cdpath")->val;
255 X pfmt(err, "Usage: cd [directory]\n");
258 X if(a->next->word[0]=='/' || cdpath==0)
260 X for(;cdpath;cdpath = cdpath->next){
261 X strcpy(dir, cdpath->word);
264 X strcat(dir, a->next->word);
265 X if(dochdir(dir)>=0){
266 X if(strlen(cdpath->word)
267 X && strcmp(cdpath->word, ".")!=0)
268 X pfmt(err, "%s\n", dir);
274 X pfmt(err, "Can't cd %s: %r\n", a->next->word);
277 X a = vlook("home")->val;
279 X if(dochdir(a->word)>=0)
282 X pfmt(err, "Can't cd %s: %r\n", a->word);
285 X pfmt(err, "Can't cd -- $home empty\n");
294 X switch(count(runq->argv->words)){
296 X pfmt(err, "Usage: exit [status]\nExiting anyway\n");
298 X setstatus(runq->argv->words->next->word);
309 X switch(count(runq->argv->words)){
311 X pfmt(err, "Usage: shift [n]\n");
312 X setstatus("shift usage");
316 X n = atoi(runq->argv->words->next->word);
323 X for(;n && star->val;--n){
324 X a = star->val->next;
325 X efree(star->val->word);
326 X efree((char *)star->val);
338 X while(*s==' ' || *s=='\t' || *s=='\n') s++;
339 X while('0'<=*s && *s<='7') n = n*8+*s++-'0';
347 X for(rp = runq->redir;rp;rp = rp->next){
362 union code rdcmds[4];
367 X static int first = 1;
370 X rdcmds[1].f = Xrdcmds;
371 X rdcmds[2].f = Xreturn;
374 X start(rdcmds, 1, runq->local);
382 X char *cmdline, *s, *t;
385 X if(count(runq->argv->words)<=1){
386 X Xerror1("Usage: eval cmd ...");
390 X for(ap = runq->argv->words->next;ap;ap = ap->next)
391 X len+=1+strlen(ap->word);
392 X cmdline = emalloc(len);
394 X for(ap = runq->argv->words->next;ap;ap = ap->next){
395 X for(t = ap->word;*t;) *s++=*t++;
400 X execcmds(opencore(cmdline, len));
403 union code dotcmds[14];
413 X static int first = 1;
418 X dotcmds[1].f = Xmark;
419 X dotcmds[2].f = Xword;
421 X dotcmds[4].f = Xlocal;
422 X dotcmds[5].f = Xmark;
423 X dotcmds[6].f = Xword;
425 X dotcmds[8].f = Xlocal;
426 X dotcmds[9].f = Xrdcmds;
427 X dotcmds[10].f = Xunlocal;
428 X dotcmds[11].f = Xunlocal;
429 X dotcmds[12].f = Xreturn;
435 X if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
439 X /* get input file */
440 X if(p->argv->words==0){
441 X Xerror1("Usage: . [-i] file [arg ...]");
444 X zero = strdup(p->argv->words->word);
447 X for(path = searchpath(zero);path;path = path->next){
448 X strcpy(file, path->word);
451 X strcat(file, zero);
452 X if((fd = open(file, 0))>=0) break;
453 X if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
460 X pfmt(err, "%s: ", zero);
461 X setstatus("can't open");
462 X Xerror(".: can't open");
465 X /* set up for a new command loop */
466 X start(dotcmds, 1, (struct var *)0);
467 X pushredir(RCLOSE, fd, 0);
468 X runq->cmdfile = zero;
469 X runq->cmdfd = openfd(fd);
470 X runq->iflag = iflag;
472 X /* push $* value */
474 X runq->argv->words = p->argv->words;
475 X /* free caller's copy of $* */
477 X p->argv = av->next;
479 X /* push $0 value */
488 X char *letter, *val;
489 X switch(count(runq->argv->words)){
491 X setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
494 X letter = runq->argv->words->next->word;
495 X val = runq->argv->words->next->next->word;
496 X if(strlen(letter)==1){
497 X if(strcmp(val, "+")==0){
498 X flag[letter[0]] = flagset;
501 X if(strcmp(val, "-")==0){
502 X flag[letter[0]] = 0;
507 X Xerror1("Usage: flag [letter] [+-]");
514 execwhatis(void){ /* mildly wrong -- should fork before writing */
515 X word *a, *b, *path;
517 X struct builtin *bp;
521 X a = runq->argv->words->next;
523 X Xerror1("Usage: whatis name ...");
527 X out->fd = mapfd(1);
528 X out->bufp = out->buf;
529 X out->ebuf = &out->buf[NBUF];
531 X for(;a;a = a->next){
532 X v = vlook(a->word);
534 X pfmt(out, "%s=", a->word);
535 X if(v->val->next==0)
536 X pfmt(out, "%q\n", v->val->word);
539 X for(b = v->val;b && b->word;b = b->next){
540 X pfmt(out, "%c%q", sep, b->word);
549 X v = gvlook(a->word);
551 X pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
553 X for(bp = Builtin;bp->name;bp++)
554 X if(strcmp(a->word, bp->name)==0){
555 X pfmt(out, "builtin %s\n", a->word);
559 X for(path = searchpath(a->word);path;path = path->next){
560 X strcpy(file, path->word);
563 X strcat(file, a->word);
564 X if(Executable(file)){
565 X pfmt(out, "%s\n", file);
569 X if(!path && !found){
570 X pfmt(err, "%s: not found\n", a->word);
571 X setstatus("not found");
583 X switch(count(runq->argv->words)){
585 X Xerror1("Usage: wait [pid]");
588 X Waitfor(atoi(runq->argv->words->next->word), 0);
598 sed 's/^X//' >havefork.c <<'!'
600 X#include "getflags.h"
610 X int null = open("/dev/null", 0);
614 X Xerror("Can't open /dev/null\n");
620 X pid = rfork(RFFDG|RFPROC|RFNOTEG);
625 X Xerror("try again");
628 X pushredir(ROPEN, null, 0);
629 X start(runq->code, runq->pc+1, runq->local);
634 X runq->pc = runq->code[runq->pc].i;
635 X inttoascii(npid, pid);
636 X setvar("apid", newword(npid, (word *)0));
644 X struct thread *p = runq;
645 X int pc = p->pc, forkid;
646 X int lfd = p->code[pc++].i;
647 X int rfd = p->code[pc++].i;
650 X Xerror("can't get pipe");
653 X switch(forkid = fork()){
655 X Xerror("try again");
658 X start(p->code, pc+2, runq->local);
661 X pushredir(ROPEN, pfd[PWR], lfd);
664 X start(p->code, p->code[pc].i, runq->local);
666 X pushredir(ROPEN, pfd[PRD], rfd);
667 X p->pc = p->code[pc+1].i;
674 X * Who should wait for the exit from the fork?
681 X char *s, *ewd=&wd[8192], *stop;
683 X var *ifs = vlook("ifs");
687 X stop = ifs->val?ifs->val->word:"";
689 X Xerror("can't make pipe");
692 X switch(pid = fork()){
694 X Xerror("try again");
700 X start(runq->code, runq->pc+1, runq->local);
701 X pushredir(ROPEN, pfd[PWR], 1);
705 X f = openfd(pfd[PRD]);
708 X while((c = rchr(f))!=EOF){
709 X if(strchr(stop, c) || s==ewd){
712 X v = newword(wd, v);
720 X v = newword(wd, v);
724 X /* v points to reversed arglist -- reverse it onto argv */
727 X v->next = runq->argv->words;
728 X runq->argv->words = v;
731 X runq->pc = runq->code[runq->pc].i;
739 X struct thread *p = runq;
743 X int sidefd, mainfd;
745 X Xerror("can't get pipe");
748 X if(p->code[pc].i==READ){
758 X Xerror("try again");
761 X start(p->code, pc+2, runq->local);
763 X pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
768 X pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
769 X strcpy(name, Fdprefix);
770 X inttoascii(name+strlen(name), mainfd);
772 X p->pc = p->code[pc+1].i;
781 X switch(pid = fork()){
783 X Xerror("try again");
786 X start(runq->code, runq->pc+1, runq->local);
791 X runq->pc = runq->code[runq->pc].i;
803 X switch(pid = fork()){
809 X strcpy(buf, "can't exec: ");
811 X errstr(buf+n, ERRMAX-n);
818 sed 's/^X//' >rc.h <<'!'
820 X * Plan9 is defined for plan 9
821 X * V9 is defined for 9th edition
822 X * Sun is defined for sun-os
823 X * Please don't litter the code with ifdefs. The three below should be enough.
836 X#define _POSIX_SOURCE
837 X#define _BSD_EXTENSION
852 X#define YYMAXDEPTH 500
856 typedef struct tree tree;
857 typedef struct word word;
858 typedef struct io io;
859 typedef union code code;
860 typedef struct var var;
861 typedef struct list list;
862 typedef struct redir redir;
863 typedef struct thread thread;
864 typedef struct builtin builtin;
868 X int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
876 tree *token(char*, int), *klook(char*), *tree1(int, tree*);
877 tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
878 tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
879 tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
880 tree *simplemung(tree*), *heredoc(tree*);
881 void freetree(tree*);
884 X * The first word of any code vector is a reference count.
885 X * Always create a new reference to a code vector by calling codecopy(.).
886 X * Always call codefree(.) when deleting a reference.
904 X char *name; /* ascii name */
905 X word *val; /* value */
907 X code *fn; /* pointer to function's code vector */
909 X int pc; /* pc of start of function */
910 X var *next; /* next on hash or local list */
912 var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
914 var *gvar[NVAR]; /* hash for globals */
915 X#define new(type) ((type *)emalloc(sizeof(type)))
919 X#define NOFILE 128 /* should come from <param.h> */
927 X * Glob character escape in strings:
928 X * In a string, GLOB must be followed by *?[ or GLOB.
929 X * GLOB* matches any string
930 X * GLOB? matches any single character
931 X * GLOB[...] matches anything in the brackets
932 X * GLOBGLOB matches GLOB
934 X#define GLOB ((char)0x01)
936 X * onebyte(c), twobyte(c), threebyte(c)
937 X * Is c the first character of a one- two- or three-byte utf sequence?
939 X#define onebyte(c) ((c&0x80)==0x00)
940 X#define twobyte(c) ((c&0xe0)==0xc0)
941 X#define threebyte(c) ((c&0xf0)==0xe0)
944 int nerror; /* number of errors encountered during compilation */
945 int doprompt; /* is it time for a prompt? */
947 X * Which fds are the reading/writing end of a pipe?
948 X * Unfortunately, this can vary from system to system.
949 X * 9th edition Unix doesn't care, the following defines
954 char Rcmain[], Fdprefix[];
957 X * How many dot commands have we executed?
958 X * Used to ensure that -v flag doesn't print rcmain.
961 char *getstatus(void);
966 sed 's/^X//' >unix.c <<'!'
968 X * Unix versions of system-specific functions
969 X * By convention, exported routines herein have names beginning with an
970 X * upper case letter.
975 X#include "getflags.h"
978 char Rcmain[]="/usr/lib/rcmain";
979 char Fdprefix[]="/dev/fd/";
981 void execfinit(void);
983 struct builtin Builtin[] = {
985 X "whatis", execwhatis,
987 X "exec", execexec, /* but with popword first */
989 X "shift", execshift,
991 X "umask", execumask,
993 X "finit", execfinit,
1006 X for(t = s;*t && *t!=SEP;t++);
1009 X v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
1017 X extern char **environ;
1019 X char **env = environ;
1022 X for(s=*env;*s && *s!='(' && *s!='=';s++);
1025 X pfmt(err, "environment %q?\n", *env);
1029 X setvar(*env, enval(s+1));
1032 X case '(': /* ignore functions for now */
1045 X for(;*envp;envp++){
1046 X for(s=*envp;*s && *s!='(' && *s!='=';s++);
1049 X pfmt(err, "environment %q?\n", *envp);
1051 X case '=': /* ignore variables */
1053 X case '(': /* Bourne again */
1058 X execcmds(opencore(s, len+1));
1066 union code rdfns[4];
1071 X static int first = 1;
1074 X rdfns[1].f = Xrdfn;
1075 X rdfns[2].f = Xjump;
1081 X start(rdfns, 1, runq->local);
1085 cmpenv(const void *aa, const void *ab)
1087 X char **a = aa, **b = ab;
1089 X return strcmp(*a, *b);
1095 X char **env, **ep, *p, *q;
1096 X struct var **h, *v;
1098 X int nvar = 0, nchr = 0, sep;
1101 X * Slightly kludgy loops look at locals then globals.
1102 X * locals no longer exist - geoff
1104 X for(h = gvar-1; h != &gvar[NVAR]; h++)
1105 X for(v = h >= gvar? *h: runq->local; v ;v = v->next){
1106 X if((v==vlook(v->name)) && v->val){
1108 X nchr+=strlen(v->name)+1;
1109 X for(a = v->val;a;a = a->next)
1110 X nchr+=strlen(a->word)+1;
1114 X nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
1117 X env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
1119 X p = (char *)&env[nvar+1];
1120 X for(h = gvar-1; h != &gvar[NVAR]; h++)
1121 X for(v = h >= gvar? *h: runq->local;v;v = v->next){
1122 X if((v==vlook(v->name)) && v->val){
1125 X while(*q) *p++=*q++;
1127 X for(a = v->val;a;a = a->next){
1131 X while(*q) *p++=*q++;
1137 X *p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
1138 X *p++='f'; *p++='n'; *p++=' ';
1140 X while(*q) *p++=*q++;
1142 X q = v->fn[v->pc-1].s;
1143 X while(*q) *p++=*q++;
1148 X qsort((void *)env, nvar, sizeof ep[0], cmpenv);
1153 X/* 1 SIGHUP */ "Hangup",
1155 X/* 3 SIGQUIT */ "Quit",
1156 X/* 4 SIGILL */ "Illegal instruction",
1157 X/* 5 SIGTRAP */ "Trace/BPT trap",
1158 X/* 6 SIGIOT */ "abort",
1159 X/* 7 SIGEMT */ "EMT trap",
1160 X/* 8 SIGFPE */ "Floating exception",
1161 X/* 9 SIGKILL */ "Killed",
1162 X/* 10 SIGBUS */ "Bus error",
1163 X/* 11 SIGSEGV */ "Memory fault",
1164 X/* 12 SIGSYS */ "Bad system call",
1165 X/* 13 SIGPIPE */ 0,
1166 X/* 14 SIGALRM */ "Alarm call",
1167 X/* 15 SIGTERM */ "Terminated",
1168 X/* 16 unused */ "signal 16",
1169 X/* 17 SIGSTOP */ "Process stopped",
1170 X/* 18 unused */ "signal 18",
1171 X/* 19 SIGCONT */ "Process continued",
1172 X/* 20 SIGCHLD */ "Child death",
1176 Waitfor(int pid, int persist)
1181 X char wstatstr[12];
1185 X wpid = wait(&wstat);
1186 X if(errno==EINTR && persist)
1192 X pfmt(err, "trace: ");
1193 X sig = (wstat>>8)&0177;
1195 X if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
1197 X pfmt(err, "%d: ", wpid);
1198 X if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
1199 X pfmt(err, "%s", sigmsg[sig]);
1200 X else if(sig==0177) pfmt(err, "stopped by ptrace");
1201 X else pfmt(err, "signal %d", sig);
1202 X if(wstat&0200)pfmt(err, " -- core dumped");
1205 X wstat = sig?sig+1000:(wstat>>8)&0xFF;
1207 X inttoascii(wstatstr, wstat);
1208 X setstatus(wstatstr);
1212 X for(p = runq->ret;p;p = p->ret)
1215 X inttoascii(p->status, wstat);
1224 register struct word *a;
1226 X char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
1227 X char **argp = argv+1; /* leave one at front for runcoms */
1229 X for(;a;a = a->next)
1241 Execute(struct word *args, struct word *path)
1243 X char *msg="not found";
1247 X char **env = mkenv();
1248 X char **argv = mkargv(args);
1251 X for(;path;path = path->next){
1252 X strcpy(file, path->word);
1254 X strcat(file, "/");
1255 X strcat(file, argv[1]);
1259 X execve(file, argv+1, env);
1262 X pfmt(err, "%s: Bourne again\n", argv[1]);
1264 X argv[1] = strdup(file);
1265 X execve("/bin/sh", argv, env);
1273 X msg="text busy"; goto Bad;
1279 X msg="not enough memory"; goto Bad;
1281 X msg="too big"; goto Bad;
1285 X pfmt(err, "%s: %s\n", argv[1], msg);
1286 X efree((char *)env);
1287 X efree((char *)argv);
1290 X#define NDIR 14 /* should get this from param.h */
1295 X int isglob = 0, globlen = NDIR+1;
1301 X globlen+=*p=='*'?NDIR:1;
1306 X return isglob?globlen:0;
1309 X#include <sys/types.h>
1310 X#include <dirent.h>
1312 X#define NDIRLIST 50
1314 DIR *dirlist[NDIRLIST];
1320 X for(dp = dirlist;dp!=&dirlist[NDIRLIST];dp++)
1322 X *dp = opendir(name);
1323 X return *dp?dp-dirlist:-1;
1329 Readdir(int f, char *p, int /* onlydirs */ )
1331 X struct dirent *dp = readdir(dirlist[f]);
1335 X strcpy(p, dp->d_name);
1342 X closedir(dirlist[f]);
1347 X "sigexit", "sighup", "sigint", "sigquit",
1348 X "sigill", "sigtrap", "sigiot", "sigemt",
1349 X "sigfpe", "sigkill", "sigbus", "sigsegv",
1350 X "sigsys", "sigpipe", "sigalrm", "sigterm",
1351 X "sig16", "sigstop", "sigtstp", "sigcont",
1352 X "sigchld", "sigttin", "sigttou", "sigtint",
1353 X "sigxcpu", "sigxfsz", "sig26", "sig27",
1354 X "sig28", "sig29", "sig30", "sig31",
1361 X signal(sig, gettrap);
1365 X pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
1366 X signal(SIGABRT, (void (*)())0);
1367 X kill(getpid(), SIGABRT);
1377 X if(1 || flag['d']){ /* wrong!!! */
1378 X sig = signal(SIGINT, gettrap);
1380 X signal(SIGINT, SIG_IGN);
1383 X for(i = 1;i<=NSIG;i++) if(i!=SIGCHLD){
1384 X sig = signal(i, gettrap);
1386 X signal(i, SIG_IGN);
1394 X return unlink(name);
1399 X return write(fd, buf, cnt);
1404 X return read(fd, buf, cnt);
1406 Seek(fd, cnt, whence)
1409 X return lseek(fd, cnt, whence);
1414 X return(access(file, 01)==0);
1419 X return creat(file, 0666);
1422 X return dup2(a, b);
1428 X * Wrong: should go through components of a|b|c and return the maximum.
1437 X if(*stat<'0' || '9'<*stat)
1439 X else n = n*10+*stat-'0';
1446 X return errno==EINTR;
1455 X return isatty(fd);
1465 execumask(void) /* wrong -- should fork before writing */
1469 X switch(count(runq->argv->words)){
1471 X pfmt(err, "Usage: umask [umask]\n");
1472 X setstatus("umask usage");
1476 X umask(octal(runq->argv->words->next->word));
1479 X umask(m = umask(0));
1480 X out->fd = mapfd(1);
1481 X out->bufp = out->buf;
1482 X out->ebuf=&out->buf[NBUF];
1484 X pfmt(out, "%o\n", m);
1499 Malloc(unsigned long n)
1501 X return (void *)malloc(n);
1505 errstr(char *buf, int len)
1507 X strncpy(buf, strerror(errno), len);
1511 From geoff@collyer.net Fri Dec 19 01:23:26 EST 2003
1512 Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:23:25 EST 2003
1513 Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:23:22 EST 2003
1514 Message-ID: <0b5ea130198a21a49139759d00d69939@collyer.net>
1515 subject: rc on unix, part 2
1516 From: Geoff Collyer <geoff@collyer.net>
1517 Date: Thu, 18 Dec 2003 22:23:21 -0800
1518 To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
1520 Content-Type: text/plain; charset="US-ASCII"
1521 Content-Transfer-Encoding: 7bit
1523 These are the include files I used to emulate plan 9's include
1524 files on Unix (APE).
1527 # To unbundle, run this file
1530 sed 's/^X//' >include/bio.h <<'!'
1534 X#include <sys/types.h> /* for off_t */
1535 X#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
1537 typedef struct Biobuf Biobuf;
1542 X Bungetsize = 4, /* space for ungetc */
1543 X Bmagic = 0x314159,
1547 X Binactive = 0, /* states */
1557 X int icount; /* neg num of bytes at eob */
1558 X int ocount; /* num of bytes at bob */
1559 X int rdline; /* num of bytes after rdline */
1560 X int runesize; /* num of bytes of last getrune */
1561 X int state; /* r/w/inactive */
1562 X int fid; /* open file */
1563 X int flag; /* magic if malloc'ed */
1564 X off_t offset; /* offset of buffer in file */
1565 X int bsize; /* size of buffer */
1566 X unsigned char* bbuf; /* pointer to beginning of buffer */
1567 X unsigned char* ebuf; /* pointer to end of buffer */
1568 X unsigned char* gbuf; /* pointer to good data in buf */
1569 X unsigned char b[Bungetsize+Bsize];
1573 X ((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
1574 X#define BPUTC(bp,c)\
1575 X ((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
1576 X#define BOFFSET(bp)\
1577 X (((bp)->state==Bractive)?\
1578 X (bp)->offset + (bp)->icount:\
1579 X (((bp)->state==Bwactive)?\
1580 X (bp)->offset + ((bp)->bsize + (bp)->ocount):\
1582 X#define BLINELEN(bp)\
1584 X#define BFILDES(bp)\
1587 int Bbuffered(Biobuf*);
1588 int Bfildes(Biobuf*);
1589 int Bflush(Biobuf*);
1591 int Bgetd(Biobuf*, double*);
1592 int Binit(Biobuf*, int, int);
1593 int Binits(Biobuf*, int, int, unsigned char*, int);
1594 int Blinelen(Biobuf*);
1595 off_t Boffset(Biobuf*);
1596 Biobuf* Bopen(char*, int);
1597 int Bprint(Biobuf*, char*, ...);
1598 int Bputc(Biobuf*, int);
1599 void* Brdline(Biobuf*, int);
1600 long Bread(Biobuf*, void*, long);
1601 off_t Bseek(Biobuf*, off_t, int);
1603 int Bungetc(Biobuf*);
1604 long Bwrite(Biobuf*, void*, long);
1606 long Bgetrune(Biobuf*);
1607 int Bputrune(Biobuf*, long);
1608 int Bungetrune(Biobuf*);
1613 sed 's/^X//' >include/fmt.h <<'!'
1616 X * The authors of this software are Rob Pike and Ken Thompson.
1617 X * Copyright (c) 2002 by Lucent Technologies.
1618 X * Permission to use, copy, modify, and distribute this software for any
1619 X * purpose without fee is hereby granted, provided that this entire notice
1620 X * is included in all copies of any software which is or includes a copy
1621 X * or modification of this software and in all copies of the supporting
1622 X * documentation for such software.
1623 X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
1624 X * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
1625 X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
1626 X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
1632 X#include <stdarg.h>
1638 typedef struct Fmt Fmt;
1640 X unsigned char runes; /* output buffer is runes or chars? */
1641 X void *start; /* of buffer */
1642 X void *to; /* current place in the buffer */
1643 X void *stop; /* end of the buffer; overwritten if flush fails */
1644 X int (*flush)(Fmt *); /* called when to == stop */
1645 X void *farg; /* to make flush a closure */
1646 X int nfmt; /* num chars formatted so far */
1647 X va_list args; /* args passed to dofmt */
1648 X int r; /* % format Rune */
1651 X unsigned long flags;
1656 X FmtLeft = FmtWidth << 1,
1657 X FmtPrec = FmtLeft << 1,
1658 X FmtSharp = FmtPrec << 1,
1659 X FmtSpace = FmtSharp << 1,
1660 X FmtSign = FmtSpace << 1,
1661 X FmtZero = FmtSign << 1,
1662 X FmtUnsigned = FmtZero << 1,
1663 X FmtShort = FmtUnsigned << 1,
1664 X FmtLong = FmtShort << 1,
1665 X FmtVLong = FmtLong << 1,
1666 X FmtComma = FmtVLong << 1,
1667 X FmtByte = FmtComma << 1,
1668 X FmtLDouble = FmtByte << 1,
1670 X FmtFlag = FmtLDouble << 1
1673 extern int print(char*, ...);
1674 extern char* seprint(char*, char*, char*, ...);
1675 extern char* vseprint(char*, char*, char*, va_list);
1676 extern int snprint(char*, int, char*, ...);
1677 extern int vsnprint(char*, int, char*, va_list);
1678 extern char* smprint(char*, ...);
1679 extern char* vsmprint(char*, va_list);
1680 extern int sprint(char*, char*, ...);
1681 extern int fprint(int, char*, ...);
1682 extern int vfprint(int, char*, va_list);
1684 extern int runesprint(Rune*, char*, ...);
1685 extern int runesnprint(Rune*, int, char*, ...);
1686 extern int runevsnprint(Rune*, int, char*, va_list);
1687 extern Rune* runeseprint(Rune*, Rune*, char*, ...);
1688 extern Rune* runevseprint(Rune*, Rune*, char*, va_list);
1689 extern Rune* runesmprint(char*, ...);
1690 extern Rune* runevsmprint(char*, va_list);
1692 extern int fmtfdinit(Fmt*, int, char*, int);
1693 extern int fmtfdflush(Fmt*);
1694 extern int fmtstrinit(Fmt*);
1695 extern char* fmtstrflush(Fmt*);
1697 extern int quotestrfmt(Fmt *f);
1698 extern void quotefmtinstall(void);
1699 extern int (*fmtdoquote)(int);
1702 extern int fmtinstall(int, int (*)(Fmt*));
1703 extern int dofmt(Fmt*, char*);
1704 extern int fmtprint(Fmt*, char*, ...);
1705 extern int fmtvprint(Fmt*, char*, va_list);
1706 extern int fmtrune(Fmt*, int);
1707 extern int fmtstrcpy(Fmt*, char*);
1709 extern double fmtstrtod(const char *, char **);
1710 extern double fmtcharstod(int(*)(void*), void*);
1715 sed 's/^X//' >include/lib9.h <<'!'
1716 X#include <string.h>
1719 X#define nil ((void*)0)
1721 X#define uchar _fmtuchar
1722 X#define ushort _fmtushort
1723 X#define uint _fmtuint
1724 X#define ulong _fmtulong
1725 X#define vlong _fmtvlong
1726 X#define uvlong _fmtuvlong
1728 typedef unsigned char uchar;
1729 typedef unsigned short ushort;
1730 typedef unsigned int uint;
1731 typedef unsigned long ulong;
1733 X#define OREAD O_RDONLY
1734 X#define OWRITE O_WRONLY
1735 X#define ORDWR O_RDWR
1738 echo include/regexp9.h
1739 sed 's/^X//' >include/regexp9.h <<'!'
1742 X#define _REGEXP9H_ 1
1745 typedef struct Resub Resub;
1746 typedef struct Reclass Reclass;
1747 typedef struct Reinst Reinst;
1748 typedef struct Reprog Reprog;
1751 X * Sub expression matches
1767 X * character class, each pair of rune's defines a range
1775 X * Machine instructions
1780 X Reclass *cp; /* class pointer */
1781 X Rune r; /* character */
1782 X int subid; /* sub-expression id for RBRA and LBRA */
1783 X Reinst *right; /* right child of OR */
1785 X union { /* regexp relies on these two being in the same union */
1786 X Reinst *left; /* left child of OR */
1787 X Reinst *next; /* next instruction for CAT & LBRA */
1792 X * Reprogram definition
1795 X Reinst *startinst; /* start pc */
1796 X Reclass class[16]; /* .data */
1797 X Reinst firstinst[5]; /* .text */
1800 extern Reprog *regcomp(char*);
1801 extern Reprog *regcomplit(char*);
1802 extern Reprog *regcompnl(char*);
1803 extern void regerror(char*);
1804 extern int regexec(Reprog*, char*, Resub*, int);
1805 extern void regsub(char*, char*, int, Resub*, int);
1807 extern int rregexec(Reprog*, Rune*, Resub*, int);
1808 extern void rregsub(Rune*, Rune*, Resub*, int);
1813 sed 's/^X//' >include/utf.h <<'!'
1817 typedef unsigned short Rune; /* 16 bits */
1821 X UTFmax = 3, /* maximum bytes per rune */
1822 X Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
1823 X Runeself = 0x80, /* rune and UTF sequences are the same (<) */
1824 X Runeerror = 0x80, /* decoding error in UTF */
1830 extern int runetochar(char*, Rune*);
1831 extern int chartorune(Rune*, char*);
1832 extern int runelen(long);
1833 extern int runenlen(Rune*, int);
1834 extern int fullrune(char*, int);
1835 extern int utflen(char*);
1836 extern int utfnlen(char*, long);
1837 extern char* utfrune(char*, long);
1838 extern char* utfrrune(char*, long);
1839 extern char* utfutf(char*, char*);
1840 extern char* utfecpy(char*, char*, char*);
1842 extern Rune* runestrcat(Rune*, Rune*);
1843 extern Rune* runestrchr(Rune*, Rune);
1844 extern int runestrcmp(Rune*, Rune*);
1845 extern Rune* runestrcpy(Rune*, Rune*);
1846 extern Rune* runestrncpy(Rune*, Rune*, long);
1847 extern Rune* runestrecpy(Rune*, Rune*, Rune*);
1848 extern Rune* runestrdup(Rune*);
1849 extern Rune* runestrncat(Rune*, Rune*, long);
1850 extern int runestrncmp(Rune*, Rune*, long);
1851 extern Rune* runestrrchr(Rune*, Rune);
1852 extern long runestrlen(Rune*);
1853 extern Rune* runestrstr(Rune*, Rune*);
1855 extern Rune tolowerrune(Rune);
1856 extern Rune totitlerune(Rune);
1857 extern Rune toupperrune(Rune);
1858 extern int isalpharune(Rune);
1859 extern int islowerrune(Rune);
1860 extern int isspacerune(Rune);
1861 extern int istitlerune(Rune);
1862 extern int isupperrune(Rune);