minimal plan9port to cross-build Jehanne

This commit is contained in:
Giacomo Tesio 2021-12-22 10:35:45 +01:00
commit c43269a19e
245 changed files with 26213 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.o

View File

@ -0,0 +1,21 @@
Copyright © 2021 Plan 9 Foundation
Portions Copyright © 2005 Russ Cox, MIT
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

27
README.txt Normal file
View File

@ -0,0 +1,27 @@
A minimal plan9port fork designed just to cross-build Jehanne
=============================================================
The sole goal of these tools is to cross-build Jehanne in a way
that can be more easily ported to Jehanne itself.
Tools available
---------------
- lib
- lib9: stripped down lib9 from plan9port
uses $JEHANNE/hacking instead of $PLAN9 to not mess with
more useful plan9port installation
- bio: plan9port libbio
- yaccpar and yaccpars (parts of "yacc runtime")
- cmd
- yacc (9yacc in $JEHANNE/hacking/bin)
- rc
Commands will be installed in $JEHANNE/hacking/bin
Libraries will be installed in $JEHANNE/hacking/lib
WARNING
-------
Do not use these tools for anything else.

12
build.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/sh -e
TARGET=$JEHANNE/hacking/bin/
TRAMPOLINE=$JEHANNE/hacking/src/trampoline
(cd $TRAMPOLINE/lib/lib9/ && ./lib9.sh.build)
(cd $TRAMPOLINE/lib/bio/ && ./libbio.sh.build)
(cd $TRAMPOLINE/cmd/ && \
cc yacc.c -DPLAN9PORT -I$TRAMPOLINE/include -L$JEHANNE/hacking/lib -O0 -lbio -l9 -o $TARGET/9yacc)
(cp lib/yacc* $TARGET/../lib)
(cd $TRAMPOLINE/cmd/rc/ && ./rc.sh.build)

496
cmd/rc/code.c Normal file
View File

@ -0,0 +1,496 @@
#include "rc.h"
#include "io.h"
#include "exec.h"
#include "fns.h"
#include "getflags.h"
#define c0 t->child[0]
#define c1 t->child[1]
#define c2 t->child[2]
int codep, ncode;
#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
void stuffdot(int);
char *fnstr(tree*);
void outcode(tree*, int);
void codeswitch(tree*, int);
int iscase(tree*);
code *codecopy(code*);
void codefree(code*);
int
morecode(void)
{
ncode+=100;
codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
if(codebuf==0)
panic("Can't realloc %d bytes in morecode!",
ncode*sizeof codebuf[0]);
memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]);
return 0;
}
void
stuffdot(int a)
{
if(a<0 || codep<=a)
panic("Bad address %d in stuffdot", a);
codebuf[a].i = codep;
}
int
compile(tree *t)
{
if(flag['D']) {
struct io *s;
s = openstr();
pfmt(s, "compile: %u\n", t);
write(2, s->strp, strlen(s->strp));
closeio(s);
if(eflagok) // made it out of rcmain - stop executing commands, just print them
t = nil;
}
ncode = 100;
codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
codep = 0;
emiti(0); /* reference count */
outcode(t, flag['e']?1:0);
if(nerror){
efree((char *)codebuf);
return 0;
}
readhere();
emitf(Xreturn);
emitf(0);
return 1;
}
void
cleanhere(char *f)
{
emitf(Xdelhere);
emits(strdup(f));
}
char*
fnstr(tree *t)
{
io *f = openstr();
char *v;
extern char nl;
char svnl = nl;
nl=';';
pfmt(f, "%t", t);
nl = svnl;
v = f->strp;
f->strp = 0;
closeio(f);
return v;
}
void
outcode(tree *t, int eflag)
{
int p, q;
tree *tt;
if(t==0)
return;
if(t->type!=NOT && t->type!=';')
runq->iflast = 0;
switch(t->type){
default:
pfmt(err, "bad type %d in outcode\n", t->type);
break;
case '$':
emitf(Xmark);
outcode(c0, eflag);
emitf(Xdol);
break;
case '"':
emitf(Xmark);
outcode(c0, eflag);
emitf(Xqdol);
break;
case SUB:
emitf(Xmark);
outcode(c0, eflag);
emitf(Xmark);
outcode(c1, eflag);
emitf(Xsub);
break;
case '&':
emitf(Xasync);
if(havefork){
p = emiti(0);
outcode(c0, eflag);
emitf(Xexit);
stuffdot(p);
} else
emits(fnstr(c0));
break;
case ';':
outcode(c0, eflag);
outcode(c1, eflag);
break;
case '^':
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
outcode(c0, eflag);
emitf(Xconc);
break;
case '`':
emitf(Xbackq);
if(havefork){
p = emiti(0);
outcode(c0, 0);
emitf(Xexit);
stuffdot(p);
} else
emits(fnstr(c0));
break;
case ANDAND:
outcode(c0, 0);
emitf(Xtrue);
p = emiti(0);
outcode(c1, eflag);
stuffdot(p);
break;
case ARGLIST:
outcode(c1, eflag);
outcode(c0, eflag);
break;
case BANG:
outcode(c0, eflag);
emitf(Xbang);
break;
case PCMD:
case BRACE:
outcode(c0, eflag);
break;
case COUNT:
emitf(Xmark);
outcode(c0, eflag);
emitf(Xcount);
break;
case FN:
emitf(Xmark);
outcode(c0, eflag);
if(c1){
emitf(Xfn);
p = emiti(0);
emits(fnstr(c1));
outcode(c1, eflag);
emitf(Xunlocal); /* get rid of $* */
emitf(Xreturn);
stuffdot(p);
}
else
emitf(Xdelfn);
break;
case IF:
outcode(c0, 0);
emitf(Xif);
p = emiti(0);
outcode(c1, eflag);
emitf(Xwastrue);
stuffdot(p);
break;
case NOT:
if(!runq->iflast)
yyerror("`if not' does not follow `if(...)'");
emitf(Xifnot);
p = emiti(0);
outcode(c0, eflag);
stuffdot(p);
break;
case OROR:
outcode(c0, 0);
emitf(Xfalse);
p = emiti(0);
outcode(c1, eflag);
stuffdot(p);
break;
case PAREN:
outcode(c0, eflag);
break;
case SIMPLE:
emitf(Xmark);
outcode(c0, eflag);
emitf(Xsimple);
if(eflag)
emitf(Xeflag);
break;
case SUBSHELL:
emitf(Xsubshell);
if(havefork){
p = emiti(0);
outcode(c0, eflag);
emitf(Xexit);
stuffdot(p);
} else
emits(fnstr(c0));
if(eflag)
emitf(Xeflag);
break;
case SWITCH:
codeswitch(t, eflag);
break;
case TWIDDLE:
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
outcode(c0, eflag);
emitf(Xmatch);
if(eflag)
emitf(Xeflag);
break;
case WHILE:
q = codep;
outcode(c0, 0);
if(q==codep)
emitf(Xsettrue); /* empty condition == while(true) */
emitf(Xtrue);
p = emiti(0);
outcode(c1, eflag);
emitf(Xjump);
emiti(q);
stuffdot(p);
break;
case WORDS:
outcode(c1, eflag);
outcode(c0, eflag);
break;
case FOR:
emitf(Xmark);
if(c1){
outcode(c1, eflag);
emitf(Xglob);
}
else{
emitf(Xmark);
emitf(Xword);
emits(strdup("*"));
emitf(Xdol);
}
emitf(Xmark); /* dummy value for Xlocal */
emitf(Xmark);
outcode(c0, eflag);
emitf(Xlocal);
p = emitf(Xfor);
q = emiti(0);
outcode(c2, eflag);
emitf(Xjump);
emiti(p);
stuffdot(q);
emitf(Xunlocal);
break;
case WORD:
emitf(Xword);
emits(strdup(t->str));
break;
case DUP:
if(t->rtype==DUPFD){
emitf(Xdup);
emiti(t->fd0);
emiti(t->fd1);
}
else{
emitf(Xclose);
emiti(t->fd0);
}
outcode(c1, eflag);
emitf(Xpopredir);
break;
case PIPEFD:
emitf(Xpipefd);
emiti(t->rtype);
if(havefork){
p = emiti(0);
outcode(c0, eflag);
emitf(Xexit);
stuffdot(p);
} else {
emits(fnstr(c0));
}
break;
case REDIR:
emitf(Xmark);
outcode(c0, eflag);
emitf(Xglob);
switch(t->rtype){
case APPEND:
emitf(Xappend);
break;
case WRITE:
emitf(Xwrite);
break;
case READ:
case HERE:
emitf(Xread);
break;
case RDWR:
emitf(Xrdwr);
break;
}
emiti(t->fd0);
outcode(c1, eflag);
emitf(Xpopredir);
break;
case '=':
tt = t;
for(;t && t->type=='=';t = c2);
if(t){
for(t = tt;t->type=='=';t = c2){
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
outcode(c0, eflag);
emitf(Xlocal);
}
outcode(t, eflag);
for(t = tt; t->type=='='; t = c2)
emitf(Xunlocal);
}
else{
for(t = tt;t;t = c2){
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
outcode(c0, eflag);
emitf(Xassign);
}
}
t = tt; /* so tests below will work */
break;
case PIPE:
emitf(Xpipe);
emiti(t->fd0);
emiti(t->fd1);
if(havefork){
p = emiti(0);
q = emiti(0);
outcode(c0, eflag);
emitf(Xexit);
stuffdot(p);
} else {
emits(fnstr(c0));
q = emiti(0);
}
outcode(c1, eflag);
emitf(Xreturn);
stuffdot(q);
emitf(Xpipewait);
break;
}
if(t->type!=NOT && t->type!=';')
runq->iflast = t->type==IF;
else if(c0) runq->iflast = c0->type==IF;
}
/*
* switch code looks like this:
* Xmark
* (get switch value)
* Xjump 1f
* out: Xjump leave
* 1: Xmark
* (get case values)
* Xcase 1f
* (commands)
* Xjump out
* 1: Xmark
* (get case values)
* Xcase 1f
* (commands)
* Xjump out
* 1:
* leave:
* Xpopm
*/
void
codeswitch(tree *t, int eflag)
{
int leave; /* patch jump address to leave switch */
int out; /* jump here to leave switch */
int nextcase; /* patch jump address to next case */
tree *tt;
if(c1->child[0]==nil
|| c1->child[0]->type!=';'
|| !iscase(c1->child[0]->child[0])){
yyerror("case missing in switch");
return;
}
emitf(Xmark);
outcode(c0, eflag);
emitf(Xjump);
nextcase = emiti(0);
out = emitf(Xjump);
leave = emiti(0);
stuffdot(nextcase);
t = c1->child[0];
while(t->type==';'){
tt = c1;
emitf(Xmark);
for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
emitf(Xcase);
nextcase = emiti(0);
t = tt;
for(;;){
if(t->type==';'){
if(iscase(c0)) break;
outcode(c0, eflag);
t = c1;
}
else{
if(!iscase(t)) outcode(t, eflag);
break;
}
}
emitf(Xjump);
emiti(out);
stuffdot(nextcase);
}
stuffdot(leave);
emitf(Xpopm);
}
int
iscase(tree *t)
{
if(t->type!=SIMPLE)
return 0;
do t = c0; while(t->type==ARGLIST);
return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
}
code*
codecopy(code *cp)
{
cp[0].i++;
return cp;
}
void
codefree(code *cp)
{
code *p;
if(--cp[0].i!=0)
return;
for(p = cp+1;p->f;p++){
if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
|| p->f==Xrdwr
|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
|| p->f==Xfor || p->f==Xjump
|| p->f==Xsubshell || p->f==Xtrue) p++;
else if(p->f==Xdup || p->f==Xpipefd) p+=2;
else if(p->f==Xpipe) p+=4;
else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
else if(p->f==Xfn){
efree(p[2].s);
p+=2;
}
}
efree((char *)cp);
}

1001
cmd/rc/exec.c Normal file

File diff suppressed because it is too large Load Diff

76
cmd/rc/exec.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Definitions used in the interpreter
*/
extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void);
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void);
extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
extern void Xrdwr(void);
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void);
extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
extern void Xerror(char*);
extern void Xerror1(char*);
/*
* word lists are in correct order,
* i.e. word0->word1->word2->word3->0
*/
struct word{
char *word;
word *next;
};
struct list{
word *words;
list *next;
};
word *newword(char *, word *), *copywords(word *, word *);
struct redir{
char type; /* what to do */
short from, to; /* what to do it to */
struct redir *next; /* what else to do (reverse order) */
};
#define NSTATUS ERRMAX /* length of status (from plan 9) */
/*
* redir types
*/
#define ROPEN 1 /* dup2(from, to); close(from); */
#define RDUP 2 /* dup2(from, to); */
#define RCLOSE 3 /* close(from); */
struct thread{
union code *code; /* code for this thread */
int pc; /* code[pc] is the next instruction */
struct list *argv; /* argument stack */
struct redir *redir; /* redirection stack */
struct redir *startredir; /* redir inheritance point */
struct var *local; /* list of local variables */
char *cmdfile; /* file name in Xrdcmd */
struct io *cmdfd; /* file descriptor for Xrdcmd */
int iflast; /* static `if not' checking */
int eof; /* is cmdfd at eof? */
int iflag; /* interactive? */
int lineno; /* linenumber */
int pid; /* process for Xpipewait to wait for */
char status[NSTATUS]; /* status for Xpipewait */
tree *treenodes; /* tree nodes created by this process */
thread *ret; /* who continues when this finishes */
};
thread *runq;
code *codecopy(code*);
code *codebuf; /* compiler output */
int ntrap; /* number of outstanding traps */
int trap[NSIG]; /* number of outstanding traps per type */
struct builtin{
char *name;
void (*fnc)(void);
};
extern struct builtin Builtin[];
int eflagok; /* kludge flag so that -e doesn't exit in startup */
extern int havefork;
void execcd(void), execwhatis(void), execeval(void), execexec(void);
int execforkexec(void);
void execexit(void), execshift(void);
void execwait(void), execumask(void), execdot(void), execflag(void);
void execfunc(var*), execcmds(io *);

162
cmd/rc/fmtquote.c Normal file
View File

@ -0,0 +1,162 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <u.h>
#include <libc.h>
#include "fmt.h"
#include "fmtdef.h"
extern int (*doquote)(int);
/*
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
* How many runes? How much of the input will be consumed?
* The parameter q is filled in by _quotesetup.
* The string may be UTF or Runes (s or r).
* Return count does not include NUL.
* Terminate the scan at the first of:
* NUL in input
* count exceeded in input
* count exceeded on output
* *ninp is set to number of input bytes accepted.
* nin may be <0 initially, to avoid checking input by count.
*/
void
__quotesetup(char *s, int nin, int nout, Quoteinfo *q, int sharp)
{
int c;
q->quoted = 0;
q->nbytesout = 0;
q->nrunesout = 0;
q->nbytesin = 0;
q->nrunesin = 0;
if(sharp || nin==0 || *s=='\0'){
if(nout < 2)
return;
q->quoted = 1;
q->nbytesout = 2;
q->nrunesout = 2;
}
for(; nin!=0; nin-=1){
c = *s;
if(c == '\0')
break;
if(q->nrunesout+1 > nout)
break;
if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
if(!q->quoted){
if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
break;
q->nrunesout += 2; /* include quotes */
q->nbytesout += 2; /* include quotes */
q->quoted = 1;
}
if(c == '\'') {
q->nbytesout++;
q->nrunesout++; /* quotes reproduce as two characters */
}
}
/* advance input */
s++;
q->nbytesin++;
q->nrunesin++;
/* advance output */
q->nbytesout++;
q->nrunesout++;
}
}
static int
qstrfmt(char *sin, Quoteinfo *q, Fmt *f)
{
int r;
char *t, *s, *m, *me;
ulong fl;
int nc, w;
m = sin;
me = m + q->nbytesin;
w = f->width;
fl = f->flags;
if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
return -1;
t = f->to;
s = f->stop;
FMTCHAR(f, t, s, '\'');
for(nc = q->nrunesin; nc > 0; nc--){
r = *(uchar*)m++;
FMTCHAR(f, t, s, r);
if(r == '\'')
FMTCHAR(f, t, s, r);
}
FMTCHAR(f, t, s, '\'');
f->nfmt += t - (char *)f->to;
f->to = t;
if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
return -1;
return 0;
}
int
__quotestrfmt(int runesin, Fmt *f)
{
int outlen;
char *s;
Quoteinfo q;
f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
s = va_arg(f->args, char *);
if(!s)
return __fmtcpy(f, "<nil>", 5, 5);
if(f->flush)
outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
else
outlen = (char*)f->stop - (char*)f->to;
__quotesetup(s, -1, outlen, &q, f->flags&FmtSharp);
if(!q.quoted)
return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
return qstrfmt(s, &q, f);
}
int
quotestrfmt(Fmt *f)
{
return __quotestrfmt(0, f);
}
void
quotefmtinstall(void)
{
fmtinstall('q', quotestrfmt);
}
int
__needsquotes(char *s, int *quotelenp)
{
Quoteinfo q;
__quotesetup(s, -1, 0x7FFFFFFF, &q, 0);
*quotelenp = q.nbytesout;
return q.quoted;
}

68
cmd/rc/fns.h Normal file
View File

@ -0,0 +1,68 @@
void Abort(void);
void Closedir(int);
int Creat(char*);
int Dup(int, int);
int Dup1(int);
int Eintr(void);
int Executable(char*);
void Execute(word*, word*);
void Exit(char*);
int ForkExecute(char*, char**, int, int, int);
int Globsize(char*);
int Isatty(int);
void Memcpy(char*, char*, long);
void Noerror(void);
int Opendir(char*);
long Read(int, char*, long);
int Readdir(int, char*, int);
long Seek(int, long, long);
void Trapinit(void);
void Unlink(char*);
void Updenv(void);
void Vinit(void);
int Waitfor(int, int);
long Write(int, char*, long);
void addwaitpid(int);
int advance(void);
int back(int);
void cleanhere(char*);
void codefree(code*);
int compile(tree*);
char * list2str(word*);
int count(word*);
void deglob(char*);
void delwaitpid(int);
void dotrap(void);
void freenodes(void);
void freewords(word*);
void globlist(void);
int havewaitpid(int);
int idchr(int);
void inttoascii(char*, long);
void kinit(void);
int mapfd(int);
int match(char*, char*, int);
int matchfn(char*, char*);
char** mkargv(word*);
void clearwaitpids(void);
void panic(char*, int);
void pathinit(void);
void poplist(void);
void popword(void);
void pprompt(void);
void pushlist(void);
void pushredir(int, int, int);
void pushword(char*);
void readhere(void);
word* searchpath(char*);
void setstatus(char*);
void setvar(char*, word*);
void skipnl(void);
void start(code*, int, var*);
int truestatus(void);
void usage(char*);
int wordchr(int);
void yyerror(char*);
int yylex(void);
int yyparse(void);
int parse(void);

244
cmd/rc/getflags.c Normal file
View File

@ -0,0 +1,244 @@
/*% cyntax -DTEST % && cc -DTEST -go # %
*/
#include "rc.h"
#include "getflags.h"
#include "fns.h"
char *flagset[] = {"<flag>"};
char **flag[NFLAG];
char cmdline[NCMDLINE+1];
char *cmdname;
static char *flagarg="";
static void reverse(char**, char**);
static int scanflag(int, char*);
static void errn(char*, int);
static void errs(char*);
static void errc(int);
static int reason;
#define RESET 1
#define FEWARGS 2
#define FLAGSYN 3
#define BADFLAG 4
static int badflag;
int
getflags(int argc, char *argv[], char *flags, int stop)
{
char *s, *t;
int i, j, c, count;
flagarg = flags;
if(cmdname==0)
cmdname = argv[0];
s = cmdline;
for(i = 0;i!=argc;i++){
for(t = argv[i];*t;t++)
if(s!=&cmdline[NCMDLINE])
*s++=*t;
if(i!=argc-1 && s!=&cmdline[NCMDLINE])
*s++=' ';
}
*s='\0';
i = 1;
while(i!=argc){
if(argv[i][0]!='-' || argv[i][1]=='\0'){
if(stop)
return argc;
i++;
continue;
}
s = argv[i]+1;
while(*s){
c=*s++;
count = scanflag(c, flags);
if(count==-1)
return -1;
if(flag[c]){ reason = RESET; badflag = c; return -1; }
if(count==0){
flag[c] = flagset;
if(*s=='\0'){
for(j = i+1;j<=argc;j++)
argv[j-1] = argv[j];
--argc;
}
}
else{
if(*s=='\0'){
for(j = i+1;j<=argc;j++)
argv[j-1] = argv[j];
--argc;
s = argv[i];
}
if(argc-i<count){
reason = FEWARGS;
badflag = c;
return -1;
}
reverse(argv+i, argv+argc);
reverse(argv+i, argv+argc-count);
reverse(argv+argc-count+1, argv+argc);
argc-=count;
flag[c] = argv+argc+1;
flag[c][0] = s;
s="";
}
}
}
return argc;
}
static void
reverse(char **p, char **q)
{
char *t;
for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
}
static int
scanflag(int c, char *f)
{
int fc, count;
if(0<=c && c<NFLAG)
while(*f){
if(*f==' '){
f++;
continue;
}
fc=*f++;
if(*f==':'){
f++;
if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; }
count = 0;
while('0'<=*f && *f<='9') count = count*10+*f++-'0';
}
else
count = 0;
if(*f=='['){
do{
f++;
if(*f=='\0'){ reason = FLAGSYN; return -1; }
}while(*f!=']');
f++;
}
if(c==fc)
return count;
}
reason = BADFLAG;
badflag = c;
return -1;
}
void
usage(char *tail)
{
char *s, *t, c;
int count, nflag = 0;
switch(reason){
case RESET:
errs("Flag -");
errc(badflag);
errs(": set twice\n");
break;
case FEWARGS:
errs("Flag -");
errc(badflag);
errs(": too few arguments\n");
break;
case FLAGSYN:
errs("Bad argument to getflags!\n");
break;
case BADFLAG:
errs("Illegal flag -");
errc(badflag);
errc('\n');
break;
}
errs("Usage: ");
errs(cmdname);
for(s = flagarg;*s;){
c=*s;
if(*s++==' ')
continue;
if(*s==':'){
s++;
count = 0;
while('0'<=*s && *s<='9') count = count*10+*s++-'0';
}
else count = 0;
if(count==0){
if(nflag==0)
errs(" [-");
nflag++;
errc(c);
}
if(*s=='['){
s++;
while(*s!=']' && *s!='\0') s++;
if(*s==']')
s++;
}
}
if(nflag)
errs("]");
for(s = flagarg;*s;){
c=*s;
if(*s++==' ')
continue;
if(*s==':'){
s++;
count = 0;
while('0'<=*s && *s<='9') count = count*10+*s++-'0';
}
else count = 0;
if(count!=0){
errs(" [-");
errc(c);
if(*s=='['){
s++;
t = s;
while(*s!=']' && *s!='\0') s++;
errs(" ");
errn(t, s-t);
if(*s==']')
s++;
}
else
while(count--) errs(" arg");
errs("]");
}
else if(*s=='['){
s++;
while(*s!=']' && *s!='\0') s++;
if(*s==']')
s++;
}
}
if(tail){
errs(" ");
errs(tail);
}
errs("\n");
Exit("bad flags");
}
static void
errn(char *s, int count)
{
while(count){ errc(*s++); --count; }
}
static void
errs(char *s)
{
while(*s) errc(*s++);
}
#define NBUF 80
static char buf[NBUF], *bufp = buf;
static void
errc(int c)
{
*bufp++=c;
if(bufp==&buf[NBUF] || c=='\n'){
Write(2, buf, bufp-buf);
bufp = buf;
}
}

7
cmd/rc/getflags.h Normal file
View File

@ -0,0 +1,7 @@
#define NFLAG 128
#define NCMDLINE 512
extern char **flag[NFLAG];
extern char cmdline[NCMDLINE+1];
extern char *cmdname;
extern char *flagset[];
int getflags(int, char*[], char*, int);

267
cmd/rc/glob.c Normal file
View File

@ -0,0 +1,267 @@
#include "rc.h"
#include "exec.h"
#include "fns.h"
char *globname;
struct word *globv;
/*
* delete all the GLOB marks from s, in place
*/
void
deglob(char *s)
{
char *t = s;
do{
if(*t==GLOB)
t++;
*s++=*t;
}while(*t++);
}
int
globcmp(const void *s, const void *t)
{
return strcmp(*(char**)s, *(char**)t);
}
void
globsort(word *left, word *right)
{
char **list;
word *a;
int n = 0;
for(a = left;a!=right;a = a->next) n++;
list = (char **)emalloc(n*sizeof(char *));
for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
qsort((void *)list, n, sizeof(void *), globcmp);
for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
efree((char *)list);
}
/*
* Push names prefixed by globname and suffixed by a match of p onto the astack.
* namep points to the end of the prefix in globname.
*/
void
globdir(char *p, char *namep)
{
char *t, *newp;
int f;
/* scan the pattern looking for a component with a metacharacter in it */
if(*p=='\0'){
globv = newword(globname, globv);
return;
}
t = namep;
newp = p;
while(*newp){
if(*newp==GLOB)
break;
*t=*newp++;
if(*t++=='/'){
namep = t;
p = newp;
}
}
/* If we ran out of pattern, append the name if accessible */
if(*newp=='\0'){
*t='\0';
if(access(globname, 0)==0)
globv = newword(globname, globv);
return;
}
/* read the directory and recur for any entry that matches */
*namep='\0';
if((f = Opendir(globname[0]?globname:"."))<0) return;
while(*newp!='/' && *newp!='\0') newp++;
while(Readdir(f, namep, *newp=='/')){
if(matchfn(namep, p)){
for(t = namep;*t;t++);
globdir(newp, t);
}
}
Closedir(f);
}
/*
* Push all file names matched by p on the current thread's stack.
* If there are no matches, the list consists of p.
*/
void
glob(char *p)
{
word *svglobv = globv;
int globlen = Globsize(p);
if(!globlen){
deglob(p);
globv = newword(p, globv);
return;
}
globname = emalloc(globlen);
globname[0]='\0';
globdir(p, globname);
efree(globname);
if(svglobv==globv){
deglob(p);
globv = newword(p, globv);
}
else
globsort(globv, svglobv);
}
/*
* Do p and q point at equal utf codes
*/
int
equtf(char *p, char *q)
{
if(*p!=*q)
return 0;
if(twobyte(*p)) return p[1]==q[1];
if(threebyte(*p)){
if(p[1]!=q[1])
return 0;
if(p[1]=='\0')
return 1; /* broken code at end of string! */
return p[2]==q[2];
}
if(fourbyte(*p)){
if(p[1]!=q[1])
return 0;
if(p[1]=='\0')
return 1;
if(p[2]!=q[2])
return 0;
if(p[2]=='\0')
return 1;
return p[3]==q[3];
}
return 1;
}
/*
* Return a pointer to the next utf code in the string,
* not jumping past nuls in broken utf codes!
*/
char*
nextutf(char *p)
{
if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
if(fourbyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p[3]=='\0'?p+3:p+4;
return p+1;
}
/*
* Convert the utf code at *p to a unicode value
*/
int
unicode(char *p)
{
int u=*p&0xff;
if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
if(fourbyte(u)) return (u<<18)|((p[1]&0x3f)<<12)|((p[2]&0x3f)<<6)|(p[3]&0x3f);
return u;
}
/*
* Does the string s match the pattern p
* . and .. are only matched by patterns starting with .
* * matches any sequence of characters
* ? matches any single character
* [...] matches the enclosed list of characters
*/
int
matchfn(char *s, char *p)
{
if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
return 0;
return match(s, p, '/');
}
int
match(char *s, char *p, int stop)
{
int compl, hit, lo, hi, t, c;
for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){
if(*p!=GLOB){
if(!equtf(p, s)) return 0;
}
else switch(*++p){
case GLOB:
if(*s!=GLOB)
return 0;
break;
case '*':
for(;;){
if(match(s, nextutf(p), stop)) return 1;
if(!*s)
break;
s = nextutf(s);
}
return 0;
case '?':
if(*s=='\0')
return 0;
break;
case '[':
if(*s=='\0')
return 0;
c = unicode(s);
p++;
compl=*p=='~';
if(compl)
p++;
hit = 0;
while(*p!=']'){
if(*p=='\0')
return 0; /* syntax error */
lo = unicode(p);
p = nextutf(p);
if(*p!='-')
hi = lo;
else{
p++;
if(*p=='\0')
return 0; /* syntax error */
hi = unicode(p);
p = nextutf(p);
if(hi<lo){ t = lo; lo = hi; hi = t; }
}
if(lo<=c && c<=hi)
hit = 1;
}
if(compl)
hit=!hit;
if(!hit)
return 0;
break;
}
}
return *s=='\0';
}
void
globlist1(word *gl)
{
if(gl){
globlist1(gl->next);
glob(gl->word);
}
}
void
globlist(void)
{
word *a;
globv = 0;
globlist1(runq->argv->words);
poplist();
pushlist();
if(globv){
for(a = globv;a->next;a = a->next);
a->next = runq->argv->words;
runq->argv->words = globv;
}
}

298
cmd/rc/havefork.c Normal file
View File

@ -0,0 +1,298 @@
#include <u.h>
#include <signal.h>
#if defined(PLAN9PORT) && defined(__sun__)
# define BSD_COMP /* sigh. for TIOCNOTTY */
#endif
#include <sys/ioctl.h>
#include "rc.h"
#include "getflags.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
int havefork = 1;
void
Xasync(void)
{
int null = open("/dev/null", 0);
int tty;
int pid;
char npid[10];
if(null<0){
Xerror("Can't open /dev/null\n");
return;
}
switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){
case -1:
close(null);
Xerror("try again");
break;
case 0:
clearwaitpids();
/*
* I don't know what the right thing to do here is,
* so this is all experimentally determined.
* If we just dup /dev/null onto 0, then running
* ssh foo & will reopen /dev/tty, try to read a password,
* get a signal, and repeat, in a tight loop, forever.
* Arguably this is a bug in ssh (it behaves the same
* way under bash as under rc) but I'm fixing it here
* anyway. If we dissociate the process from the tty,
* then it won't be able to open /dev/tty ever again.
* The SIG_IGN on SIGTTOU makes writing the tty
* (via fd 1 or 2, for example) succeed even though
* our pgrp is not the terminal's controlling pgrp.
*/
if((tty = open("/dev/tty", OREAD)) >= 0){
/*
* Should make reads of tty fail, writes succeed.
*/
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
ioctl(tty, TIOCNOTTY);
close(tty);
}
if(isatty(0))
pushredir(ROPEN, null, 0);
else
close(null);
start(runq->code, runq->pc+1, runq->local);
runq->ret = 0;
break;
default:
addwaitpid(pid);
close(null);
runq->pc = runq->code[runq->pc].i;
inttoascii(npid, pid);
setvar("apid", newword(npid, (word *)0));
break;
}
}
void
Xpipe(void)
{
struct thread *p = runq;
int pc = p->pc, forkid;
int lfd = p->code[pc++].i;
int rfd = p->code[pc++].i;
int pfd[2];
if(pipe(pfd)<0){
Xerror("can't get pipe");
return;
}
switch(forkid = fork()){
case -1:
Xerror("try again");
break;
case 0:
clearwaitpids();
start(p->code, pc+2, runq->local);
runq->ret = 0;
close(pfd[PRD]);
pushredir(ROPEN, pfd[PWR], lfd);
break;
default:
addwaitpid(forkid);
start(p->code, p->code[pc].i, runq->local);
close(pfd[PWR]);
pushredir(ROPEN, pfd[PRD], rfd);
p->pc = p->code[pc+1].i;
p->pid = forkid;
break;
}
}
/*
* Who should wait for the exit from the fork?
*/
void
Xbackq(void)
{
struct thread *p = runq;
char wd[8193];
int c, n;
char *s, *ewd=&wd[8192], *stop, *q;
struct io *f;
var *ifs = vlook("ifs");
word *v, *nextv;
int pfd[2];
int pid;
Rune r;
stop = ifs->val?ifs->val->word:"";
if(pipe(pfd)<0){
Xerror("can't make pipe");
return;
}
switch(pid = fork()){
case -1:
Xerror("try again");
close(pfd[PRD]);
close(pfd[PWR]);
return;
case 0:
clearwaitpids();
close(pfd[PRD]);
start(runq->code, runq->pc+1, runq->local);
pushredir(ROPEN, pfd[PWR], 1);
return;
default:
addwaitpid(pid);
close(pfd[PWR]);
f = openfd(pfd[PRD]);
s = wd;
v = 0;
while((c = rchr(f))!=EOF){
if(s != ewd) {
*s++ = c;
for(q=stop; *q; q+=n) {
n = chartorune(&r, q);
if(s-wd >= n && memcmp(s-n, q, n) == 0) {
s -= n;
goto stop;
}
}
continue;
}
stop:
if(s != wd) {
*s = '\0';
v = newword(wd, v);
}
s = wd;
}
if(s!=wd){
*s='\0';
v = newword(wd, v);
}
closeio(f);
Waitfor(pid, 0);
/* v points to reversed arglist -- reverse it onto argv */
while(v){
nextv = v->next;
v->next = runq->argv->words;
runq->argv->words = v;
v = nextv;
}
p->pc = p->code[p->pc].i;
return;
}
}
void
Xpipefd(void)
{
struct thread *p = runq;
int pc = p->pc, pid;
char name[40];
int pfd[2];
struct { int sidefd, mainfd; } fd[2], *r, *w;
r = &fd[0];
w = &fd[1];
switch(p->code[pc].i){
case READ:
w = nil;
break;
case WRITE:
r = nil;
}
if(r){
if(pipe(pfd)<0){
Xerror("can't get pipe");
return;
}
r->sidefd = pfd[PWR];
r->mainfd = pfd[PRD];
}
if(w){
if(pipe(pfd)<0){
Xerror("can't get pipe");
return;
}
w->sidefd = pfd[PRD];
w->mainfd = pfd[PWR];
}
switch(pid = fork()){
case -1:
Xerror("try again");
break;
case 0:
clearwaitpids();
start(p->code, pc+2, runq->local);
if(r){
close(r->mainfd);
pushredir(ROPEN, r->sidefd, 1);
}
if(w){
close(w->mainfd);
pushredir(ROPEN, w->sidefd, 0);
}
runq->ret = 0;
break;
default:
addwaitpid(pid);
if(w){
close(w->sidefd);
pushredir(ROPEN, w->mainfd, w->mainfd); /* so that Xpopredir can close it later */
strcpy(name, Fdprefix);
inttoascii(name+strlen(name), w->mainfd);
pushword(name);
}
if(r){
close(r->sidefd);
pushredir(ROPEN, r->mainfd, r->mainfd);
strcpy(name, Fdprefix);
inttoascii(name+strlen(name), r->mainfd);
pushword(name);
}
p->pc = p->code[pc+1].i;
break;
}
}
void
Xsubshell(void)
{
int pid;
switch(pid = fork()){
case -1:
Xerror("try again");
break;
case 0:
clearwaitpids();
start(runq->code, runq->pc+1, runq->local);
runq->ret = 0;
break;
default:
addwaitpid(pid);
Waitfor(pid, 1);
runq->pc = runq->code[runq->pc].i;
break;
}
}
int
execforkexec(void)
{
int pid;
int n;
char buf[ERRMAX];
switch(pid = fork()){
case -1:
return -1;
case 0:
clearwaitpids();
pushword("exec");
execexec();
strcpy(buf, "can't exec: ");
n = strlen(buf);
errstr(buf+n, ERRMAX-n);
Exit(buf);
}
addwaitpid(pid);
return pid;
}

211
cmd/rc/haventfork.c Normal file
View File

@ -0,0 +1,211 @@
#include "rc.h"
#include "getflags.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
int havefork = 0;
static char **
rcargv(char *s)
{
int argc;
char **argv;
word *p;
p = vlook("*")->val;
argv = malloc((count(p)+6)*sizeof(char*));
argc = 0;
argv[argc++] = argv0;
if(flag['e'])
argv[argc++] = "-Se";
else
argv[argc++] = "-S";
argv[argc++] = "-c";
argv[argc++] = s;
for(p = vlook("*")->val; p; p = p->next)
argv[argc++] = p->word;
argv[argc] = 0;
return argv;
}
void
Xasync(void)
{
uint pid;
char buf[20], **argv;
Updenv();
argv = rcargv(runq->code[runq->pc].s);
pid = ForkExecute(argv0, argv, -1, 1, 2);
free(argv);
if(pid == 0) {
Xerror("proc failed");
return;
}
runq->pc++;
sprint(buf, "%d", pid);
setvar("apid", newword(buf, (word *)0));
}
void
Xbackq(void)
{
char wd[8193], **argv;
int c;
char *s, *ewd=&wd[8192], *stop;
struct io *f;
var *ifs = vlook("ifs");
word *v, *nextv;
int pfd[2];
int pid;
stop = ifs->val?ifs->val->word:"";
if(pipe(pfd)<0){
Xerror("can't make pipe");
return;
}
Updenv();
argv = rcargv(runq->code[runq->pc].s);
pid = ForkExecute(argv0, argv, -1, pfd[1], 2);
free(argv);
close(pfd[1]);
if(pid == 0) {
Xerror("proc failed");
close(pfd[0]);
return;
}
f = openfd(pfd[0]);
s = wd;
v = 0;
while((c=rchr(f))!=EOF){
if(strchr(stop, c) || s==ewd){
if(s!=wd){
*s='\0';
v=newword(wd, v);
s=wd;
}
}
else *s++=c;
}
if(s!=wd){
*s='\0';
v=newword(wd, v);
}
closeio(f);
Waitfor(pid, 1);
/* v points to reversed arglist -- reverse it onto argv */
while(v){
nextv=v->next;
v->next=runq->argv->words;
runq->argv->words=v;
v=nextv;
}
runq->pc++;
}
void
Xpipe(void)
{
thread *p=runq;
int pc=p->pc, pid;
int rfd=p->code[pc+1].i;
int pfd[2];
char **argv;
if(pipe(pfd)<0){
Xerror1("can't get pipe");
return;
}
Updenv();
argv = rcargv(runq->code[pc+2].s);
pid = ForkExecute(argv0, argv, 0, pfd[1], 2);
free(argv);
close(pfd[1]);
if(pid == 0) {
Xerror("proc failed");
close(pfd[0]);
return;
}
start(p->code, pc+4, runq->local);
pushredir(ROPEN, pfd[0], rfd);
p->pc=p->code[pc+3].i;
p->pid=pid;
}
void
Xpipefd(void)
{
Abort();
}
void
Xsubshell(void)
{
char **argv;
int pid;
Updenv();
argv = rcargv(runq->code[runq->pc].s);
pid = ForkExecute(argv0, argv, -1, 1, 2);
free(argv);
if(pid < 0) {
Xerror("proc failed");
return;
}
Waitfor(pid, 1);
runq->pc++;
}
/*
* start a process running the cmd on the stack and return its pid.
*/
int
execforkexec(void)
{
char **argv;
char file[1024];
int nc;
word *path;
int pid;
if(runq->argv->words==0)
return -1;
argv = mkargv(runq->argv->words);
for(path = searchpath(runq->argv->words->word);path;path = path->next){
nc = strlen(path->word);
if(nc<sizeof(file)){
strcpy(file, path->word);
if(file[0]){
strcat(file, "/");
nc++;
}
if(nc+strlen(argv[1])<sizeof(file)){
strcat(file, argv[1]);
pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2));
if(pid >= 0){
free(argv);
return pid;
}
}
}
}
free(argv);
return -1;
}

150
cmd/rc/here.c Normal file
View File

@ -0,0 +1,150 @@
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
struct here *here, **ehere;
int ser = 0;
char tmp[]="/tmp/here0000.0000";
char hex[]="0123456789abcdef";
void psubst(io*, char*);
void pstrs(io*, word*);
void
hexnum(char *p, int n)
{
*p++=hex[(n>>12)&0xF];
*p++=hex[(n>>8)&0xF];
*p++=hex[(n>>4)&0xF];
*p = hex[n&0xF];
}
tree*
heredoc(tree *tag)
{
struct here *h = new(struct here);
if(tag->type!=WORD)
yyerror("Bad here tag");
h->next = 0;
if(here)
*ehere = h;
else
here = h;
ehere=&h->next;
h->tag = tag;
hexnum(&tmp[9], getpid());
hexnum(&tmp[14], ser++);
h->name = strdup(tmp);
return token(tmp, WORD);
}
/*
* bug: lines longer than NLINE get split -- this can cause spurious
* missubstitution, or a misrecognized EOF marker.
*/
#define NLINE 4096
void
readhere(void)
{
struct here *h, *nexth;
io *f;
char *s, *tag;
int c, subst;
char line[NLINE+1];
for(h = here;h;h = nexth){
subst=!h->tag->quoted;
tag = h->tag->str;
c = Creat(h->name);
if(c<0)
yyerror("can't create here document");
f = openfd(c);
s = line;
pprompt();
while((c = rchr(runq->cmdfd))!=EOF){
if(c=='\n' || s==&line[NLINE]){
*s='\0';
if(tag && strcmp(line, tag)==0) break;
if(subst)
psubst(f, line);
else pstr(f, line);
s = line;
if(c=='\n'){
pprompt();
pchr(f, c);
}
else *s++=c;
}
else *s++=c;
}
flush(f);
closeio(f);
cleanhere(h->name);
nexth = h->next;
efree((char *)h);
}
here = 0;
doprompt = 1;
}
void
psubst(io *f, char *s)
{
char *t, *u;
int savec, n;
word *star;
while(*s){
if(*s!='$'){
if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
pchr(f, *s++);
if(*s=='\0')
break;
}
else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
pchr(f, *s++);
if(*s=='\0')
break;
pchr(f, *s++);
if(*s=='\0')
break;
}
pchr(f, *s++);
}
else{
t=++s;
if(*t=='$')
pchr(f, *t++);
else{
while(*t && idchr(*t)) t++;
savec=*t;
*t='\0';
n = 0;
for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0';
if(n && *u=='\0'){
star = vlook("*")->val;
if(star && 1<=n && n<=count(star)){
while(--n) star = star->next;
pstr(f, star->word);
}
}
else
pstrs(f, vlook(s)->val);
*t = savec;
if(savec=='^')
t++;
}
s = t;
}
}
}
void
pstrs(io *f, word *a)
{
if(a){
while(a->next && a->next->word){
pstr(f, a->word);
pchr(f, ' ');
a = a->next;
}
pstr(f, a->word);
}
}

273
cmd/rc/io.c Normal file
View File

@ -0,0 +1,273 @@
#include <limits.h>
#include <errno.h>
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
int pfmtnest = 0;
void
pfmt(io *f, char *fmt, ...)
{
va_list ap;
char err[ERRMAX];
va_start(ap, fmt);
pfmtnest++;
for(;*fmt;fmt++)
if(*fmt!='%')
pchr(f, *fmt);
else switch(*++fmt){
case '\0':
va_end(ap);
return;
case 'c':
pchr(f, va_arg(ap, int));
break;
case 'd':
pdec(f, va_arg(ap, int));
break;
case 'o':
poct(f, va_arg(ap, unsigned));
break;
case 'p':
pptr(f, va_arg(ap, void*));
break;
case 'Q':
pquo(f, va_arg(ap, char *));
break;
case 'q':
pwrd(f, va_arg(ap, char *));
break;
case 'r':
rerrstr(err, sizeof err); pstr(f, err);
break;
case 's':
pstr(f, va_arg(ap, char *));
break;
case 't':
pcmd(f, va_arg(ap, tree *));
break;
case 'u':
pcmdu(f, va_arg(ap, tree *));
break;
case 'v':
pval(f, va_arg(ap, struct word *));
break;
default:
pchr(f, *fmt);
break;
}
va_end(ap);
if(--pfmtnest==0)
flush(f);
}
void
pchr(io *b, int c)
{
if(b->bufp==b->ebuf)
fullbuf(b, c);
else *b->bufp++=c;
}
int
rchr(io *b)
{
if(b->bufp==b->ebuf)
return emptybuf(b);
return *b->bufp++ & 0xFF;
}
void
pquo(io *f, char *s)
{
pchr(f, '\'');
for(;*s;s++)
if(*s=='\'')
pfmt(f, "''");
else pchr(f, *s);
pchr(f, '\'');
}
void
pwrd(io *f, char *s)
{
char *t;
for(t = s;*t;t++) if(!wordchr(*t)) break;
if(t==s || *t)
pquo(f, s);
else pstr(f, s);
}
void
pptr(io *f, void *v)
{
int n;
uintptr p;
p = (uintptr)v;
if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
}
void
pstr(io *f, char *s)
{
if(s==0)
s="(null)";
while(*s) pchr(f, *s++);
}
void
pdec(io *f, int n)
{
if(n<0){
if(n!=INT_MIN){
pchr(f, '-');
pdec(f, -n);
return;
}
/* n is two's complement minimum integer */
n = -(INT_MIN+1);
pchr(f, '-');
pdec(f, n/10);
pchr(f, n%10+'1');
return;
}
if(n>9)
pdec(f, n/10);
pchr(f, n%10+'0');
}
void
poct(io *f, unsigned n)
{
if(n>7)
poct(f, n>>3);
pchr(f, (n&7)+'0');
}
void
pval(io *f, word *a)
{
if(a){
while(a->next && a->next->word){
pwrd(f, a->word);
pchr(f, ' ');
a = a->next;
}
pwrd(f, a->word);
}
}
int
fullbuf(io *f, int c)
{
flush(f);
return *f->bufp++=c;
}
void
flush(io *f)
{
int n;
char *s;
if(f->strp){
n = f->ebuf-f->strp;
f->strp = realloc(f->strp, n+101);
if(f->strp==0)
panic("Can't realloc %d bytes in flush!", n+101);
f->bufp = f->strp+n;
f->ebuf = f->bufp+100;
for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
}
else{
n = f->bufp-f->buf;
if(n && Write(f->fd, f->buf, n) < 0){
Write(3, "Write error\n", 12);
if(ntrap)
dotrap();
}
f->bufp = f->buf;
f->ebuf = f->buf+NBUF;
}
}
io*
openfd(int fd)
{
io *f = new(struct io);
f->fd = fd;
f->bufp = f->ebuf = f->buf;
f->strp = 0;
return f;
}
io*
openstr(void)
{
io *f = new(struct io);
char *s;
f->fd=-1;
f->bufp = f->strp = emalloc(101);
f->ebuf = f->bufp+100;
for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
return f;
}
/*
* Open a corebuffer to read. EOF occurs after reading len
* characters from buf.
*/
io*
opencore(char *s, int len)
{
io *f = new(struct io);
char *buf = emalloc(len);
f->fd= -1 /*open("/dev/null", 0)*/;
f->bufp = f->strp = buf;
f->ebuf = buf+len;
Memcpy(buf, s, len);
return f;
}
void
iorewind(io *io)
{
if(io->fd==-1)
io->bufp = io->strp;
else{
io->bufp = io->ebuf = io->buf;
Seek(io->fd, 0L, 0);
}
}
void
closeio(io *io)
{
if(io->fd>=0)
close(io->fd);
if(io->strp)
efree(io->strp);
efree((char *)io);
}
int
emptybuf(io *f)
{
int n;
if(f->fd==-1)
return EOF;
Loop:
errno = 0;
n = Read(f->fd, f->buf, NBUF);
if(n < 0 && errno == EINTR)
goto Loop;
if(n <= 0)
return EOF;
f->bufp = f->buf;
f->ebuf = f->buf+n;
return *f->bufp++&0xff;
}

31
cmd/rc/io.h Normal file
View File

@ -0,0 +1,31 @@
/*
* on Mac OS X, err is something else,
* and assigning to it causes a bus error.
* what a crappy linker.
*/
#define err rc_err
#define EOF (-1)
#define NBUF 512
struct io{
int fd;
char *bufp, *ebuf, *strp, buf[NBUF];
};
io *err;
io *openfd(int), *openstr(void), *opencore(char *, int);
int emptybuf(io*);
void pchr(io*, int);
int rchr(io*);
void closeio(io*);
void flush(io*);
int fullbuf(io*, int);
void pdec(io*, int);
void poct(io*, unsigned);
void pptr(io*, void*);
void pquo(io*, char*);
void pwrd(io*, char*);
void pstr(io*, char*);
void pcmd(io*, tree*);
void pcmdu(io*, tree*);
void pval(io*, word*);
void pfnc(io*, thread*);
void pfmt(io*, char*, ...);

396
cmd/rc/lex.c Normal file
View File

@ -0,0 +1,396 @@
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "getflags.h"
#include "fns.h"
int getnext(void);
int
wordchr(int c)
{
return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
}
int
idchr(int c)
{
/*
* Formerly:
* return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
* || c=='_' || c=='*';
*/
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
}
int future = EOF;
int doprompt = 1;
int inquote;
int incomm;
/*
* Look ahead in the input stream
*/
int
nextc(void)
{
if(future==EOF)
future = getnext();
return future;
}
/*
* Consume the lookahead character.
*/
int
advance(void)
{
int c = nextc();
lastc = future;
future = EOF;
return c;
}
/*
* read a character from the input stream
*/
int
getnext(void)
{
int c;
static int peekc = EOF;
if(peekc!=EOF){
c = peekc;
peekc = EOF;
return c;
}
if(runq->eof)
return EOF;
if(doprompt)
pprompt();
c = rchr(runq->cmdfd);
if(!inquote && c=='\\'){
c = rchr(runq->cmdfd);
if(c=='\n' && !incomm){ /* don't continue a comment */
doprompt = 1;
c=' ';
}
else{
peekc = c;
c='\\';
}
}
doprompt = doprompt || c=='\n' || c==EOF;
if(c==EOF)
runq->eof++;
else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
return c;
}
void
pprompt(void)
{
var *prompt;
if(runq->iflag){
pstr(err, promptstr);
flush(err);
prompt = vlook("prompt");
if(prompt->val && prompt->val->next)
promptstr = prompt->val->next->word;
else
promptstr="\t";
}
runq->lineno++;
doprompt = 0;
}
int
skipwhite(void)
{
int c, skipped;
skipped = 0;
for(;;){
c = nextc();
/* Why did this used to be if(!inquote && c=='#') ?? */
if(c=='#'){
incomm = 1;
skipped = 1;
for(;;){
c = nextc();
if(c=='\n' || c==EOF) {
incomm = 0;
break;
}
advance();
}
}
if(c==' ' || c=='\t') {
skipped = 1;
advance();
}
else
return skipped;
}
}
void
skipnl(void)
{
int c;
for(;;){
skipwhite();
c = nextc();
if(c!='\n')
return;
advance();
}
}
int
nextis(int c)
{
if(nextc()==c){
advance();
return 1;
}
return 0;
}
char*
addtok(char *p, int val)
{
if(p==0)
return 0;
if(p==&tok[NTOK-1]){
*p = 0;
yyerror("token buffer too short");
return 0;
}
*p++=val;
return p;
}
char*
addutf(char *p, int c)
{
p = addtok(p, c);
if(twobyte(c)) /* 2-byte escape */
return addtok(p, advance());
if(threebyte(c)){ /* 3-byte escape */
p = addtok(p, advance());
return addtok(p, advance());
}
if(fourbyte(c)){ /* 4-byte escape */
p = addtok(p, advance());
p = addtok(p, advance());
return addtok(p, advance());
}
return p;
}
int lastdol; /* was the last token read '$' or '$#' or '"'? */
int lastword; /* was the last token read a word or compound word terminator? */
int
yylex(void)
{
int c, d = nextc();
char *w = tok;
tree *t;
yylval.tree = 0;
/*
* Embarassing sneakiness: if the last token read was a quoted or unquoted
* WORD then we alter the meaning of what follows. If the next character
* is `(', we return SUB (a subscript paren) and consume the `('. Otherwise,
* if the next character is the first character of a simple or compound word,
* we insert a `^' before it.
*/
if(lastword && flag['Y']){
lastword = 0;
if(d=='('){
advance();
strcpy(tok, "(");
return SUB;
}
if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
strcpy(tok, "^");
return '^';
}
}
inquote = 0;
if(skipwhite() && !flag['Y'])
return ' ';
switch(c = advance()){
case EOF:
lastdol = 0;
strcpy(tok, "EOF");
return EOF;
case '$':
lastdol = 1;
if(nextis('#')){
strcpy(tok, "$#");
return COUNT;
}
if(nextis('"')){
strcpy(tok, "$\"");
return '"';
}
strcpy(tok, "$");
return '$';
case '&':
lastdol = 0;
if(nextis('&')){
if(flag['Y'])
skipnl();
strcpy(tok, "&&");
return ANDAND;
}
strcpy(tok, "&");
return '&';
case '|':
lastdol = 0;
if(nextis(c)){
if(flag['Y'])
skipnl();
strcpy(tok, "||");
return OROR;
}
case '<':
case '>':
lastdol = 0;
/*
* funny redirection tokens:
* redir: arrow | arrow '[' fd ']'
* arrow: '<' | '<<' | '>' | '>>' | '|'
* fd: digit | digit '=' | digit '=' digit
* digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
* some possibilities are nonsensical and get a message.
*/
*w++=c;
t = newtree();
switch(c){
case '|':
t->type = PIPE;
t->fd0 = 1;
t->fd1 = 0;
break;
case '>':
t->type = REDIR;
if(nextis(c)){
t->rtype = APPEND;
*w++=c;
}
else t->rtype = WRITE;
t->fd0 = 1;
break;
case '<':
t->type = REDIR;
if(nextis(c)){
t->rtype = HERE;
*w++=c;
} else if (nextis('>')){
t->rtype = RDWR;
*w++=c;
} else t->rtype = READ;
t->fd0 = 0;
break;
}
if(nextis('[')){
*w++='[';
c = advance();
*w++=c;
if(c<'0' || '9'<c){
RedirErr:
*w = 0;
yyerror(t->type==PIPE?"pipe syntax"
:"redirection syntax");
return EOF;
}
t->fd0 = 0;
do{
t->fd0 = t->fd0*10+c-'0';
*w++=c;
c = advance();
}while('0'<=c && c<='9');
if(c=='='){
*w++='=';
if(t->type==REDIR)
t->type = DUP;
c = advance();
if('0'<=c && c<='9'){
t->rtype = DUPFD;
t->fd1 = t->fd0;
t->fd0 = 0;
do{
t->fd0 = t->fd0*10+c-'0';
*w++=c;
c = advance();
}while('0'<=c && c<='9');
}
else{
if(t->type==PIPE)
goto RedirErr;
t->rtype = CLOSE;
}
}
if(c!=']'
|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
goto RedirErr;
*w++=']';
}
*w='\0';
yylval.tree = t;
if(t->type==PIPE && flag['Y'])
skipnl();
if(t->type==REDIR) {
skipwhite();
if(nextc() == '{')
t->type = REDIRW;
}
return t->type;
case '\'':
lastdol = 0;
lastword = 1;
inquote = 1;
for(;;){
c = advance();
if(c==EOF)
break;
if(c=='\''){
if(nextc()!='\'')
break;
advance();
}
w = addutf(w, c);
}
if(w!=0)
*w='\0';
t = token(tok, WORD);
t->quoted = 1;
yylval.tree = t;
return t->type;
}
if(!wordchr(c)){
lastdol = 0;
tok[0] = c;
tok[1]='\0';
return c;
}
for(;;){
/* next line should have (char)c==GLOB, but ken's compiler is broken */
if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
w = addtok(w, GLOB);
w = addutf(w, c);
c = nextc();
if(lastdol?!idchr(c):!wordchr(c)) break;
advance();
}
lastword = 1;
lastdol = 0;
if(w!=0)
*w='\0';
t = klook(tok);
if(t->type!=WORD)
lastword = 0;
t->quoted = 0;
yylval.tree = t;
return t->type;
}

38
cmd/rc/mkfile Normal file
View File

@ -0,0 +1,38 @@
<$PLAN9/src/mkhdr
TARG=rc
OFILES=\
code.$O\
exec.$O\
getflags.$O\
glob.$O\
here.$O\
io.$O\
lex.$O\
parse.$O\
pcmd.$O\
pfnc.$O\
simple.$O\
subr.$O\
trap.$O\
tree.$O\
unixcrap.$O\
var.$O\
y.tab.$O\
plan9ish.$O\
havefork.$O\
HFILES=\
rc.h\
x.tab.h\
io.h\
exec.h\
fns.h\
YFILES=syn.y
<$PLAN9/src/mkone
x.tab.h: y.tab.h
cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h

552
cmd/rc/parse.c Normal file
View File

@ -0,0 +1,552 @@
#include "rc.h"
#include "io.h"
#include "fns.h"
static tree* body(int tok, int *ptok);
static tree* brace(int tok);
static tree* cmd(int tok, int *ptok);
static tree* cmd2(int tok, int *ptok);
static tree* cmd3(int tok, int *ptok);
static tree* cmds(int tok, int *ptok, int nlok);
static tree* epilog(int tok, int *ptok);
static int iswordtok(int tok);
static tree* line(int tok, int *ptok);
static tree* paren(int tok);
static tree* yyredir(int tok, int *ptok);
static tree* yyword(int tok, int *ptok, int eqok);
static tree* word1(int tok, int *ptok);
static tree* words(int tok, int *ptok);
static jmp_buf yyjmp;
static int
dropnl(int tok)
{
while(tok == ' ' || tok == '\n')
tok = yylex();
return tok;
}
static int
dropsp(int tok)
{
while(tok == ' ')
tok = yylex();
return tok;
}
static void
syntax(int tok)
{
USED(tok);
yyerror("syntax error");
longjmp(yyjmp, 1);
}
int
parse(void)
{
tree *t;
int tok;
if(setjmp(yyjmp))
return 1;
// rc: { return 1;}
// | line '\n' {return !compile($1);}
tok = dropsp(yylex());
if(tok == EOF)
return 1;
t = line(tok, &tok);
if(tok != '\n')
yyerror("missing newline at end of line");
yylval.tree = t;
return !compile(t);
}
static tree*
line(int tok, int *ptok)
{
return cmds(tok, ptok, 0);
}
static tree*
body(int tok, int *ptok)
{
return cmds(tok, ptok, 1);
}
static tree*
cmds(int tok, int *ptok, int nlok)
{
tree *t, **last, *t2;
// line: cmd
// | cmdsa line {$$=tree2(';', $1, $2);}
// cmdsa: cmd ';'
// | cmd '&' {$$=tree1('&', $1);}
// body: cmd
// | cmdsan body {$$=tree2(';', $1, $2);}
// cmdsan: cmdsa
// | cmd '\n'
t = nil;
last = nil;
for(;;) {
t2 = cmd(tok, &tok);
if(tok == '&')
t2 = tree1('&', t2);
if(t2 != nil) {
// slot into list t
if(last == nil) {
t = t2;
last = &t;
} else {
*last = tree2(';', *last, t2);
last = &(*last)->child[1];
}
}
if(tok != ';' && tok != '&' && (!nlok || tok != '\n'))
break;
tok = yylex();
}
*ptok = tok;
return t;
}
static tree*
brace(int tok)
{
tree *t;
// brace: '{' body '}' {$$=tree1(BRACE, $2);}
tok = dropsp(tok);
if(tok != '{')
syntax(tok);
t = body(yylex(), &tok);
if(tok != '}')
syntax(tok);
return tree1(BRACE, t);
}
static tree*
paren(int tok)
{
tree *t;
// paren: '(' body ')' {$$=tree1(PCMD, $2);}
tok = dropsp(tok);
if(tok != '(')
syntax(tok);
t = body(yylex(), &tok);
if(tok != ')')
syntax(tok);
return tree1(PCMD, t);
}
static tree*
epilog(int tok, int *ptok)
{
tree *t, *r;
// epilog: {$$=0;}
// | redir epilog {$$=mung2($1, $1->child[0], $2);}
if(tok != REDIR && tok != DUP) {
*ptok = tok;
return nil;
}
r = yyredir(tok, &tok);
t = epilog(tok, &tok);
*ptok = tok;
return mung2(r, r->child[0], t);
}
static tree*
yyredir(int tok, int *ptok)
{
tree *r, *w;
// redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
// | DUP
switch(tok) {
default:
syntax(tok);
case DUP:
r = yylval.tree;
*ptok = dropsp(yylex());
break;
case REDIR:
r = yylval.tree;
w = yyword(yylex(), &tok, 1);
*ptok = dropsp(tok);
r = mung1(r, r->rtype==HERE?heredoc(w):w);
break;
}
return r;
}
static tree*
cmd(int tok, int *ptok)
{
int op;
tree *t1, *t2;
// | cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);}
// | cmd OROR cmd {$$=tree2(OROR, $1, $3);}
tok = dropsp(tok);
t1 = cmd2(tok, &tok);
while(tok == ANDAND || tok == OROR) {
op = tok;
t2 = cmd2(dropnl(yylex()), &tok);
t1 = tree2(op, t1, t2);
}
*ptok = tok;
return t1;
}
static tree*
cmd2(int tok, int *ptok)
{
tree *t1, *t2, *t3;
// | cmd PIPE cmd {$$=mung2($2, $1, $3);}
t1 = cmd3(tok, &tok);
while(tok == PIPE) {
t2 = yylval.tree;
t3 = cmd3(dropnl(yylex()), &tok);
t1 = mung2(t2, t1, t3);
}
*ptok = tok;
return t1;
}
static tree*
cmd3(int tok, int *ptok)
{
tree *t1, *t2, *t3, *t4;
tok = dropsp(tok);
switch(tok) {
case ';':
case '&':
case '\n':
*ptok = tok;
return nil;
case IF:
// | IF paren {skipnl();} cmd {$$=mung2($1, $2, $4);}
// | IF NOT {skipnl();} cmd {$$=mung1($2, $4);}
t1 = yylval.tree;
tok = dropsp(yylex());
if(tok == NOT) {
t1 = yylval.tree;
t2 = cmd(dropnl(yylex()), ptok);
return mung1(t1, t2);
}
t2 = paren(tok);
t3 = cmd(dropnl(yylex()), ptok);
return mung2(t1, t2, t3);
case FOR:
// | FOR '(' word IN words ')' {skipnl();} cmd
// {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
// | FOR '(' word ')' {skipnl();} cmd
// {$$=mung3($1, $3, (tree *)0, $6);}
t1 = yylval.tree;
tok = dropsp(yylex());
if(tok != '(')
syntax(tok);
t2 = yyword(yylex(), &tok, 1);
switch(tok) {
default:
syntax(tok);
case ')':
t3 = nil;
break;
case IN:
t3 = words(yylex(), &tok);
if(t3 == nil)
t3 = tree1(PAREN, nil);
if(tok != ')')
syntax(tok);
break;
}
t4 = cmd(dropnl(yylex()), ptok);
return mung3(t1, t2, t3, t4);
case WHILE:
// | WHILE paren {skipnl();} cmd
// {$$=mung2($1, $2, $4);}
t1 = yylval.tree;
t2 = paren(yylex());
t3 = cmd(dropnl(yylex()), ptok);
return mung2(t1, t2, t3);
case SWITCH:
// | SWITCH word {skipnl();} brace
// {$$=tree2(SWITCH, $2, $4);}
t1 = yyword(yylex(), &tok, 1);
tok = dropnl(tok); // doesn't work in yacc grammar but works here!
t2 = brace(tok);
*ptok = dropsp(yylex());
return tree2(SWITCH, t1, t2);
// Note: cmd: a && for(x) y && b is a && {for (x) {y && b}}.
return cmd(tok, ptok);
case FN:
// | FN words brace {$$=tree2(FN, $2, $3);}
// | FN words {$$=tree1(FN, $2);}
t1 = words(yylex(), &tok);
if(tok != '{') {
*ptok = tok;
return tree1(FN, t1);
}
t2 = brace(tok);
*ptok = dropsp(yylex());
return tree2(FN, t1, t2);
case TWIDDLE:
// | TWIDDLE word words {$$=mung2($1, $2, $3);}
t1 = yylval.tree;
t2 = yyword(yylex(), &tok, 1);
t3 = words(tok, ptok);
return mung2(t1, t2, t3);
case BANG:
case SUBSHELL:
// | BANG cmd {$$=mung1($1, $2);}
// | SUBSHELL cmd {$$=mung1($1, $2);}
// Note: cmd2: ! x | y is !{x | y} not {!x} | y.
t1 = yylval.tree;
return mung1(t1, cmd2(yylex(), ptok));
case REDIR:
case DUP:
// | redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);}
// Note: cmd2: {>x echo a | tr a-z A-Z} writes A to x.
t1 = yyredir(tok, &tok);
t2 = cmd2(tok, ptok);
return mung2(t1, t1->child[0], t2);
case '{':
// | brace epilog {$$=epimung($1, $2);}
t1 = brace(tok);
tok = dropsp(yylex());
t2 = epilog(tok, ptok);
return epimung(t1, t2);
}
if(!iswordtok(tok)) {
*ptok = tok;
return nil;
}
// cmd: ...
// | simple {$$=simplemung($1);}
// | assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);}
// assign: first '=' word {$$=tree2('=', $1, $3);}
// Note: first is same as word except for disallowing all the leading keywords,
// but all those keywords have been picked off in the switch above.
// Except NOT, but disallowing that in yacc was likely a mistake anyway:
// there's no ambiguity in not=1 or not x y z.
t1 = yyword(tok, &tok, 0);
if(tok == '=') {
// assignment
// Note: cmd2: {x=1 true | echo $x} echoes 1.
t1 = tree2('=', t1, yyword(yylex(), &tok, 1));
t2 = cmd2(tok, ptok);
return mung3(t1, t1->child[0], t1->child[1], t2);
}
// simple: first
// | simple word {$$=tree2(ARGLIST, $1, $2);}
// | simple redir {$$=tree2(ARGLIST, $1, $2);}
for(;;) {
if(tok == REDIR || tok == DUP) {
t1 = tree2(ARGLIST, t1, yyredir(tok, &tok));
} else if(iswordtok(tok)) {
t1 = tree2(ARGLIST, t1, yyword(tok, &tok, 1));
} else {
break;
}
}
*ptok = tok;
return simplemung(t1);
}
static tree*
words(int tok, int *ptok)
{
tree *t;
// words: {$$=(tree*)0;}
// | words word {$$=tree2(WORDS, $1, $2);}
t = nil;
tok = dropsp(tok);
while(iswordtok(tok))
t = tree2(WORDS, t, yyword(tok, &tok, 1));
*ptok = tok;
return t;
}
static tree*
yyword(int tok, int *ptok, int eqok)
{
tree *t;
// word: keyword {lastword=1; $1->type=WORD;}
// | comword
// | word '^' word {$$=tree2('^', $1, $3);}
// comword: '$' word {$$=tree1('$', $2);}
// | '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
// | '"' word {$$=tree1('"', $2);}
// | COUNT word {$$=tree1(COUNT, $2);}
// | WORD
// | '`' brace {$$=tree1('`', $2);}
// | '(' words ')' {$$=tree1(PAREN, $2);}
// | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;}
// keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
//
// factored into:
//
// word: word1
// | word '^' word1
//
// word1: keyword | comword
t = word1(tok, &tok);
if(tok == '=' && !eqok)
goto out;
for(;;) {
if(iswordtok(tok)) {
// No free carats around parens.
if(t->type == PAREN || tok == '(')
syntax(tok);
t = tree2('^', t, word1(tok, &tok));
continue;
}
tok = dropsp(tok);
if(tok == '^') {
t = tree2('^', t, word1(yylex(), &tok));
continue;
}
break;
}
out:
*ptok = dropsp(tok);
return t;
}
static tree*
word1(int tok, int *ptok)
{
tree *w, *sub, *t;
tok = dropsp(tok);
switch(tok) {
default:
syntax(tok);
case WORD:
case FOR:
case IN:
case WHILE:
case IF:
case NOT:
case TWIDDLE:
case BANG:
case SUBSHELL:
case SWITCH:
case FN:
// | WORD
// keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
t = yylval.tree;
t->type = WORD;
*ptok = yylex();
return t;
case '=':
*ptok = yylex();
return token("=", WORD);
case '$':
// comword: '$' word1 {$$=tree1('$', $2);}
// | '$' word1 SUB words ')' {$$=tree2(SUB, $2, $4);}
w = word1(yylex(), &tok);
if(tok == '(') {
sub = words(yylex(), &tok);
if(tok != ')')
syntax(tok);
*ptok = yylex();
return tree2(SUB, w, sub);
}
*ptok = tok;
return tree1('$', w);
case '"':
// | '"' word1 {$$=tree1('"', $2);}
return tree1('"', word1(yylex(), ptok));
case COUNT:
// | COUNT word1 {$$=tree1(COUNT, $2);}
return tree1(COUNT, word1(yylex(), ptok));
case '`':
// | '`' brace {$$=tree1('`', $2);}
t = tree1('`', brace(yylex()));
*ptok = yylex();
return t;
case '(':
// | '(' words ')' {$$=tree1(PAREN, $2);}
t = tree1(PAREN, words(yylex(), &tok));
if(tok != ')')
syntax(tok);
*ptok = yylex();
return t;
case REDIRW:
// | REDIRW brace {$$=mung1($1, $2); $$->type=PIPEFD;}
t = yylval.tree;
t = mung1(t, brace(yylex()));
t->type = PIPEFD;
*ptok = yylex();
return t;
}
}
static int
iswordtok(int tok)
{
switch(tok) {
case FOR:
case IN:
case WHILE:
case IF:
case NOT:
case TWIDDLE:
case BANG:
case SUBSHELL:
case SWITCH:
case FN:
case '$':
case '"':
case COUNT:
case WORD:
case '`':
case '(':
case REDIRW:
case '=':
return 1;
}
return 0;
}

265
cmd/rc/pcmd.c Normal file
View File

@ -0,0 +1,265 @@
#include "rc.h"
#include "io.h"
#include "fns.h"
char nl='\n'; /* change to semicolon for bourne-proofing */
#define c0 t->child[0]
#define c1 t->child[1]
#define c2 t->child[2]
void
pdeglob(io *f, char *s)
{
while(*s){
if(*s==GLOB)
s++;
pchr(f, *s++);
}
}
void
pcmd(io *f, tree *t)
{
if(t==0)
return;
switch(t->type){
default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2);
break;
case '$': pfmt(f, "$%t", c0);
break;
case '"': pfmt(f, "$\"%t", c0);
break;
case '&': pfmt(f, "%t&", c0);
break;
case '^': pfmt(f, "%t^%t", c0, c1);
break;
case '`': pfmt(f, "`%t", c0);
break;
case ANDAND: pfmt(f, "%t && %t", c0, c1);
break;
case BANG: pfmt(f, "! %t", c0);
break;
case BRACE: pfmt(f, "{%t}", c0);
break;
case COUNT: pfmt(f, "$#%t", c0);
break;
case FN: pfmt(f, "fn %t %t", c0, c1);
break;
case IF: pfmt(f, "if%t%t", c0, c1);
break;
case NOT: pfmt(f, "if not %t", c0);
break;
case OROR: pfmt(f, "%t || %t", c0, c1);
break;
case PCMD:
case PAREN: pfmt(f, "(%t)", c0);
break;
case SUB: pfmt(f, "$%t(%t)", c0, c1);
break;
case SIMPLE: pfmt(f, "%t", c0);
break;
case SUBSHELL: pfmt(f, "@ %t", c0);
break;
case SWITCH: pfmt(f, "switch %t %t", c0, c1);
break;
case TWIDDLE: pfmt(f, "~ %t %t", c0, c1);
break;
case WHILE: pfmt(f, "while %t%t", c0, c1);
break;
case ARGLIST:
if(c0==0)
pfmt(f, "%t", c1);
else if(c1==0)
pfmt(f, "%t", c0);
else
pfmt(f, "%t %t", c0, c1);
break;
case ';':
if(c0){
if(c1)
pfmt(f, "%t%c%t", c0, nl, c1);
else pfmt(f, "%t", c0);
}
else pfmt(f, "%t", c1);
break;
case WORDS:
if(c0)
pfmt(f, "%t ", c0);
pfmt(f, "%t", c1);
break;
case FOR:
pfmt(f, "for(%t", c0);
if(c1)
pfmt(f, " in %t", c1);
pfmt(f, ")%t", c2);
break;
case WORD:
if(t->quoted)
pfmt(f, "%Q", t->str);
else pdeglob(f, t->str);
break;
case DUP:
if(t->rtype==DUPFD)
pfmt(f, ">[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */
else
pfmt(f, ">[%d=]", t->fd0);
pfmt(f, "%t", c1);
break;
case PIPEFD:
case REDIR:
switch(t->rtype){
case HERE:
pchr(f, '<');
case READ:
case RDWR:
pchr(f, '<');
if(t->rtype==RDWR)
pchr(f, '>');
if(t->fd0!=0)
pfmt(f, "[%d]", t->fd0);
break;
case APPEND:
pchr(f, '>');
case WRITE:
pchr(f, '>');
if(t->fd0!=1)
pfmt(f, "[%d]", t->fd0);
break;
}
pfmt(f, "%t", c0);
if(c1)
pfmt(f, " %t", c1);
break;
case '=':
pfmt(f, "%t=%t", c0, c1);
if(c2)
pfmt(f, " %t", c2);
break;
case PIPE:
pfmt(f, "%t|", c0);
if(t->fd1==0){
if(t->fd0!=1)
pfmt(f, "[%d]", t->fd0);
}
else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
pfmt(f, "%t", c1);
break;
}
}
void
pcmdu(io *f, tree *t) /* unambiguous */
{
if(t==0) {
pfmt(f, "<nil>");
return;
}
switch(t->type){
default: pfmt(f, "(bad %d %p %p %p)", t->type, c0, c1, c2);
break;
case '$': pfmt(f, "($ %u)", c0);
break;
case '"': pfmt(f, "($\" %u)", c0);
break;
case '&': pfmt(f, "(& %u)", c0);
break;
case '^': pfmt(f, "(^ %u %u)", c0, c1);
break;
case '`': pfmt(f, "(` %u)", c0);
break;
case ANDAND: pfmt(f, "(&& %u %u)", c0, c1);
break;
case BANG: pfmt(f, "(! %u)", c0);
break;
case BRACE: pfmt(f, "(brace %u)", c0);
break;
case COUNT: pfmt(f, "($# %u)", c0);
break;
case FN: pfmt(f, "(fn %u %u)", c0, c1);
break;
case IF: pfmt(f, "(if %u %u)", c0, c1);
break;
case NOT: pfmt(f, "(if not %u)", c0);
break;
case OROR: pfmt(f, "(|| %u %u)", c0, c1);
break;
case PCMD:
case PAREN: pfmt(f, "(paren %u)", c0);
break;
case SUB: pfmt(f, "($sub %u %u)", c0, c1);
break;
case SIMPLE: pfmt(f, "(simple %u)", c0);
break;
case SUBSHELL: pfmt(f, "(@ %u)", c0);
break;
case SWITCH: pfmt(f, "(switch %u %u)", c0, c1);
break;
case TWIDDLE: pfmt(f, "(~ %u %u)", c0, c1);
break;
case WHILE: pfmt(f, "(while %u %u)", c0, c1);
break;
case ARGLIST:
pfmt(f, "(arglist %u %u)", c0, c1);
break;
case ';':
pfmt(f, "(; %u %u)", c0, c1);
break;
case WORDS:
pfmt(f, "(words %u %u)", c0, c1);
break;
case FOR:
pfmt(f, "(for %u %u %u)", c0, c1, c2);
break;
case WORD:
if(t->quoted)
pfmt(f, "%Q", t->str);
else pdeglob(f, t->str);
break;
case DUP:
if(t->rtype==DUPFD)
pfmt(f, "(>[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */
else
pfmt(f, "(>[%d=]", t->fd0); /*)*/
pfmt(f, " %u)", c1);
break;
case PIPEFD:
case REDIR:
pfmt(f, "(");
switch(t->rtype){
case HERE:
pchr(f, '<');
case READ:
case RDWR:
pchr(f, '<');
if(t->rtype==RDWR)
pchr(f, '>');
if(t->fd0!=0)
pfmt(f, "[%d]", t->fd0);
break;
case APPEND:
pchr(f, '>');
case WRITE:
pchr(f, '>');
if(t->fd0!=1)
pfmt(f, "[%d]", t->fd0);
break;
}
if(t->rtype == HERE)
pfmt(f, "HERE %u)", c1);
else
pfmt(f, "%u %u)", c0, c1);
break;
case '=':
pfmt(f, "(%u=%u %u)", c0, c1, c2);
break;
case PIPE:
pfmt(f, "(|");
if(t->fd1==0){
if(t->fd0!=1)
pfmt(f, "[%d]", t->fd0);
}
else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
pfmt(f, " %u %u", c0, c1);
break;
}
}

71
cmd/rc/pfnc.c Normal file
View File

@ -0,0 +1,71 @@
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
struct{
void (*f)(void);
char *name;
}fname[] = {
Xappend, "Xappend",
Xasync, "Xasync",
Xbang, "Xbang",
Xclose, "Xclose",
Xdup, "Xdup",
Xeflag, "Xeflag",
Xexit, "Xexit",
Xfalse, "Xfalse",
Xifnot, "Xifnot",
Xjump, "Xjump",
Xmark, "Xmark",
Xpopm, "Xpopm",
Xrdwr, "Xrdwr",
Xread, "Xread",
Xreturn, "Xreturn",
Xtrue, "Xtrue",
Xif, "Xif",
Xwastrue, "Xwastrue",
Xword, "Xword",
Xwrite, "Xwrite",
Xmatch, "Xmatch",
Xcase, "Xcase",
Xconc, "Xconc",
Xassign, "Xassign",
Xdol, "Xdol",
Xcount, "Xcount",
Xlocal, "Xlocal",
Xunlocal, "Xunlocal",
Xfn, "Xfn",
Xdelfn, "Xdelfn",
Xpipe, "Xpipe",
Xpipewait, "Xpipewait",
Xrdcmds, "Xrdcmds",
(void (*)(void))Xerror, "Xerror",
Xbackq, "Xbackq",
Xpipefd, "Xpipefd",
Xsubshell, "Xsubshell",
Xdelhere, "Xdelhere",
Xfor, "Xfor",
Xglob, "Xglob",
Xrdfn, "Xrdfn",
Xsimple, "Xsimple",
Xrdfn, "Xrdfn",
Xqdol, "Xqdol",
0};
void
pfnc(io *fd, thread *t)
{
int i;
void (*fn)(void) = t->code[t->pc].f;
list *a;
pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
pstr(fd, fname[i].name);
break;
}
if(!fname[i].f)
pfmt(fd, "%p", fn);
for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words);
pchr(fd, '\n');
flush(fd);
}

604
cmd/rc/plan9ish.c Normal file
View File

@ -0,0 +1,604 @@
/*
* 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){
dir[f].i=0;
dir[f].n=0;
}
free(db);
return f;
}
free(db);
close(f);
return -1;
}
int Readdir(int f, char *p, int onlydirs)
{
int n;
USED(onlydirs); /* only advisory */
if(f<0 || 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<NFD){
free(dir[f].dbuf);
dir[f].i=0;
dir[f].n=0;
dir[f].dbuf=0;
}
close(f);
}
int interrupted = 0;
void
notifyf(void *unused0, char *s)
{
int i;
for(i=0;syssigname[i];i++)
if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
if(strncmp(s, "sys: ", 5)!=0){
if(kidpid && !interrupted){
interrupted=1;
postnote(PNGROUP, kidpid, s);
}
interrupted = 1;
}
goto Out;
}
if(strcmp(s, "sys: window size change") != 0)
if(strcmp(s, "sys: write on closed pipe") != 0)
if(strcmp(s, "sys: child") != 0)
pfmt(err, "rc: note: %s\n", s);
noted(NDFLT);
return;
Out:
if(strcmp(s, "interrupt")!=0 || trap[i]==0){
trap[i]++;
ntrap++;
}
if(ntrap>=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<nwaitpids; r++)
if(waitpids[r] != pid)
waitpids[w++] = waitpids[r];
nwaitpids = w;
}
void
clearwaitpids(void)
{
nwaitpids = 0;
}
int
havewaitpid(int pid)
{
int i;
for(i=0; i<nwaitpids; i++)
if(waitpids[i] == pid)
return 1;
return 0;
}

153
cmd/rc/rc.h Normal file
View File

@ -0,0 +1,153 @@
/*
* Plan9 is defined for plan 9
* V9 is defined for 9th edition
* Sun is defined for sun-os
* Please don't litter the code with ifdefs. The three below (and one in
* getflags) should be enough.
*/
#define Plan9
#ifdef Plan9
#include <u.h>
#include <libc.h>
#undef NSIG
#undef SIGINT
#undef SIGQUIT
#define NSIG 32
#define SIGINT 2
#define SIGQUIT 3
#endif
#ifdef V9
#include <signal.h>
#include <libc.h>
#endif
#ifdef Sun
#include <signal.h>
#endif
#define YYMAXDEPTH 500
#ifndef PAREN
#ifndef YYMAJOR
#include "x.tab.h"
#endif
#endif
#undef pipe /* so that /dev/fd works */
#define searchpath rcsearchpath /* avoid new libc function */
/* some systems define a global "var", "thread" */
#undef var
#define var rcvar
#undef thread
#define thread rcthread
typedef struct tree tree;
typedef struct word word;
typedef struct io io;
typedef union code code;
typedef struct var var;
typedef struct list list;
typedef struct redir redir;
typedef struct thread thread;
typedef struct builtin builtin;
struct tree{
int type;
int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
char *str;
int quoted;
int iskw;
tree *child[3];
tree *next;
};
tree *newtree(void);
tree *token(char*, int), *klook(char*), *tree1(int, tree*);
tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
tree *simplemung(tree*), *heredoc(tree*);
void freetree(tree*);
tree *cmdtree;
/*
* The first word of any code vector is a reference count.
* Always create a new reference to a code vector by calling codecopy(.).
* Always call codefree(.) when deleting a reference.
*/
union code{
void (*f)(void);
int i;
char *s;
};
char *promptstr;
#define NTOK 8192
char tok[NTOK];
#define APPEND 1
#define WRITE 2
#define READ 3
#define HERE 4
#define DUPFD 5
#define CLOSE 6
#define RDWR 7
struct var{
char *name; /* ascii name */
word *val; /* value */
int changed;
code *fn; /* pointer to function's code vector */
int fnchanged;
int pc; /* pc of start of function */
var *next; /* next on hash or local list */
void (*changefn)(var*);
};
var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
#define NVAR 521
var *gvar[NVAR]; /* hash for globals */
#define new(type) ((type *)emalloc(sizeof(type)))
char *emalloc(long);
void *Malloc(ulong);
void efree(char*);
#define NOFILE 128 /* should come from <param.h> */
struct here{
tree *tag;
char *name;
struct here *next;
};
int mypid;
/*
* Glob character escape in strings:
* In a string, GLOB must be followed by *?[ or GLOB.
* GLOB* matches any string
* GLOB? matches any single character
* GLOB[...] matches anything in the brackets
* GLOBGLOB matches GLOB
*/
#define GLOB ((char)0x01)
/*
* onebyte(c), twobyte(c), threebyte(c)
* Is c the first character of a one- two- or three-byte utf sequence?
*/
#define onebyte(c) ((c&0x80)==0x00)
#define twobyte(c) ((c&0xe0)==0xc0)
#define threebyte(c) ((c&0xf0)==0xe0)
#define fourbyte(c) ((c&0xf8)==0xf0)
char **argp;
char **args;
int nerror; /* number of errors encountered during compilation */
extern int doprompt; /* is it time for a prompt? */
/*
* Which fds are the reading/writing end of a pipe?
* Unfortunately, this can vary from system to system.
* 9th edition Unix doesn't care, the following defines
* work on plan 9.
*/
#define PRD 0
#define PWR 1
extern char *Rcmain(), Fdprefix[];
#define register
/*
* How many dot commands have we executed?
* Used to ensure that -v flag doesn't print rcmain.
*/
int ndot;
char *getstatus(void);
int lastc;
int lastword;
int kidpid;

80
cmd/rc/rc.sh.build Executable file
View File

@ -0,0 +1,80 @@
#!/bin/sh
mkdir -p $JEHANNE/hacking/bin/
TARGET=rc #$JEHANNE/hacking/bin/rc
git clean -xdf .
9yacc -d syn.y
cp y.tab.h x.tab.h
cc -c \
-DPLAN9PORT \
-I$JEHANNE/hacking/src/trampoline/include \
-O2 \
-c \
-Wall \
-Wno-parentheses \
-Wno-missing-braces \
-Wno-switch \
-Wno-comment \
-Wno-sign-compare \
-Wno-unknown-pragmas \
-Wno-misleading-indentation \
-Wno-stringop-truncation \
-Wno-stringop-overflow \
-Wno-format-truncation \
-fno-omit-frame-pointer \
-fsigned-char \
-fcommon \
-ggdb \
code.c \
exec.c \
getflags.c \
glob.c \
havefork.c \
here.c \
io.c \
plan9ish.c \
unixcrap.c \
lex.c \
parse.c \
pcmd.c \
pfnc.c \
simple.c \
subr.c \
trap.c \
tree.c \
var.c \
y.tab.c
gcc -pie -o $TARGET \
code.o \
exec.o \
getflags.o \
glob.o \
here.o \
io.o \
lex.o \
parse.o \
pcmd.o \
pfnc.o \
simple.o \
subr.o \
trap.o \
tree.o \
unixcrap.o \
var.o \
y.tab.o \
plan9ish.o \
havefork.o \
-L$JEHANNE/hacking/lib -lutil -lresolv -lpthread -l9 -lm \
-lutil \
-lresolv \
-lpthread \
-lc
#git clean -xdf .

505
cmd/rc/simple.c Normal file
View File

@ -0,0 +1,505 @@
/*
* Maybe `simple' is a misnomer.
*/
#include "rc.h"
#include "getflags.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
/*
* Search through the following code to see if we're just going to exit.
*/
int
exitnext(void){
union code *c=&runq->code[runq->pc];
while(c->f==Xpopredir) c++;
return c->f==Xexit;
}
void
Xsimple(void)
{
word *a;
thread *p = runq;
var *v;
struct builtin *bp;
int pid;
globlist();
a = runq->argv->words;
if(a==0){
Xerror1("empty argument list");
return;
}
if(flag['x'])
pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
v = gvlook(a->word);
if(v->fn)
execfunc(v);
else{
if(strcmp(a->word, "builtin")==0){
if(count(a)==1){
pfmt(err, "builtin: empty argument list\n");
setstatus("empty arg list");
poplist();
return;
}
a = a->next;
popword();
}
for(bp = Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){
(*bp->fnc)();
return;
}
if(exitnext()){
/* fork and wait is redundant */
pushword("exec");
execexec();
Xexit();
}
else{
flush(err);
Updenv(); /* necessary so changes don't go out again */
if((pid = execforkexec()) < 0){
Xerror("try again");
return;
}
/* interrupts don't get us out */
poplist();
while(Waitfor(pid, 1) < 0)
;
}
}
}
struct word nullpath = { "", 0};
void
doredir(redir *rp)
{
if(rp){
doredir(rp->next);
switch(rp->type){
case ROPEN:
if(rp->from!=rp->to){
Dup(rp->from, rp->to);
close(rp->from);
}
break;
case RDUP:
Dup(rp->from, rp->to);
break;
case RCLOSE:
close(rp->from);
break;
}
}
}
word*
searchpath(char *w)
{
word *path;
if(strncmp(w, "/", 1)==0
/* || strncmp(w, "#", 1)==0 */
|| strncmp(w, "./", 2)==0
|| strncmp(w, "../", 3)==0
|| (path = vlook("path")->val)==0)
path=&nullpath;
return path;
}
void
execexec(void)
{
popword(); /* "exec" */
if(runq->argv->words==0){
Xerror1("empty argument list");
return;
}
doredir(runq->redir);
Execute(runq->argv->words, searchpath(runq->argv->words->word));
poplist();
}
void
execfunc(var *func)
{
word *starval;
popword();
starval = runq->argv->words;
runq->argv->words = 0;
poplist();
start(func->fn, func->pc, runq->local);
runq->local = newvar(strdup("*"), runq->local);
runq->local->val = starval;
runq->local->changed = 1;
}
int
dochdir(char *word)
{
/* report to /dev/wdir if it exists and we're interactive */
static int wdirfd = -2;
if(chdir(word)<0) return -1;
if(flag['i']!=0){
if(wdirfd==-2) /* try only once */
wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
if(wdirfd>=0)
write(wdirfd, word, strlen(word));
}
return 1;
}
void
execcd(void)
{
word *a = runq->argv->words;
word *cdpath;
char dir[512];
setstatus("can't cd");
cdpath = vlook("cdpath")->val;
switch(count(a)){
default:
pfmt(err, "Usage: cd [directory]\n");
break;
case 2:
if(a->next->word[0]=='/' || cdpath==0)
cdpath=&nullpath;
for(;cdpath;cdpath = cdpath->next){
strcpy(dir, cdpath->word);
if(dir[0])
strcat(dir, "/");
strcat(dir, a->next->word);
if(dochdir(dir)>=0){
if(strlen(cdpath->word)
&& strcmp(cdpath->word, ".")!=0)
pfmt(err, "%s\n", dir);
setstatus("");
break;
}
}
if(cdpath==0)
pfmt(err, "Can't cd %s: %r\n", a->next->word);
break;
case 1:
a = vlook("home")->val;
if(count(a)>=1){
if(dochdir(a->word)>=0)
setstatus("");
else
pfmt(err, "Can't cd %s: %r\n", a->word);
}
else
pfmt(err, "Can't cd -- $home empty\n");
break;
}
poplist();
}
void
execexit(void)
{
switch(count(runq->argv->words)){
default:
pfmt(err, "Usage: exit [status]\nExiting anyway\n");
case 2:
setstatus(runq->argv->words->next->word);
case 1: Xexit();
}
}
void
execshift(void)
{
int n;
word *a;
var *star;
switch(count(runq->argv->words)){
default:
pfmt(err, "Usage: shift [n]\n");
setstatus("shift usage");
poplist();
return;
case 2:
n = atoi(runq->argv->words->next->word);
break;
case 1:
n = 1;
break;
}
star = vlook("*");
for(;n && star->val;--n){
a = star->val->next;
efree(star->val->word);
efree((char *)star->val);
star->val = a;
star->changed = 1;
}
setstatus("");
poplist();
}
int
octal(char *s)
{
int n = 0;
while(*s==' ' || *s=='\t' || *s=='\n') s++;
while('0'<=*s && *s<='7') n = n*8+*s++-'0';
return n;
}
int
mapfd(int fd)
{
redir *rp;
for(rp = runq->redir;rp;rp = rp->next){
switch(rp->type){
case RCLOSE:
if(rp->from==fd)
fd=-1;
break;
case RDUP:
case ROPEN:
if(rp->to==fd)
fd = rp->from;
break;
}
}
return fd;
}
union code rdcmds[4];
void
execcmds(io *f)
{
static int first = 1;
if(first){
rdcmds[0].i = 1;
rdcmds[1].f = Xrdcmds;
rdcmds[2].f = Xreturn;
first = 0;
}
start(rdcmds, 1, runq->local);
runq->cmdfd = f;
runq->iflast = 0;
}
void
execeval(void)
{
char *cmdline, *s, *t;
int len = 0;
word *ap;
if(count(runq->argv->words)<=1){
Xerror1("Usage: eval cmd ...");
return;
}
eflagok = 1;
for(ap = runq->argv->words->next;ap;ap = ap->next)
len+=1+strlen(ap->word);
cmdline = emalloc(len);
s = cmdline;
for(ap = runq->argv->words->next;ap;ap = ap->next){
for(t = ap->word;*t;) *s++=*t++;
*s++=' ';
}
s[-1]='\n';
poplist();
execcmds(opencore(cmdline, len));
efree(cmdline);
}
union code dotcmds[14];
void
execdot(void)
{
int iflag = 0;
int fd;
list *av;
thread *p = runq;
char *zero;
static int first = 1;
char file[512];
word *path;
if(first){
dotcmds[0].i = 1;
dotcmds[1].f = Xmark;
dotcmds[2].f = Xword;
dotcmds[3].s="0";
dotcmds[4].f = Xlocal;
dotcmds[5].f = Xmark;
dotcmds[6].f = Xword;
dotcmds[7].s="*";
dotcmds[8].f = Xlocal;
dotcmds[9].f = Xrdcmds;
dotcmds[10].f = Xunlocal;
dotcmds[11].f = Xunlocal;
dotcmds[12].f = Xreturn;
first = 0;
}
else
eflagok = 1;
popword();
if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
iflag = 1;
popword();
}
/* get input file */
if(p->argv->words==0){
Xerror1("Usage: . [-i] file [arg ...]");
return;
}
zero = strdup(p->argv->words->word);
popword();
fd=-1;
for(path = searchpath(zero);path;path = path->next){
strcpy(file, path->word);
if(file[0])
strcat(file, "/");
strcat(file, zero);
if((fd = open(file, 0))>=0) break;
if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
fd = Dup1(0);
if(fd>=0)
break;
}
}
if(fd<0){
pfmt(err, "%s: ", zero);
setstatus("can't open");
Xerror(".: can't open");
return;
}
/* set up for a new command loop */
start(dotcmds, 1, (struct var *)0);
pushredir(RCLOSE, fd, 0);
runq->cmdfile = zero;
runq->cmdfd = openfd(fd);
runq->iflag = iflag;
runq->iflast = 0;
/* push $* value */
pushlist();
runq->argv->words = p->argv->words;
/* free caller's copy of $* */
av = p->argv;
p->argv = av->next;
efree((char *)av);
/* push $0 value */
pushlist();
pushword(zero);
ndot++;
}
void
execflag(void)
{
char *letter, *val;
switch(count(runq->argv->words)){
case 2:
setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
break;
case 3:
letter = runq->argv->words->next->word;
val = runq->argv->words->next->next->word;
if(strlen(letter)==1){
if(strcmp(val, "+")==0){
flag[(uchar)letter[0]] = flagset;
break;
}
if(strcmp(val, "-")==0){
flag[(uchar)letter[0]] = 0;
break;
}
}
default:
Xerror1("Usage: flag [letter] [+-]");
return;
}
poplist();
}
void
execwhatis(void){ /* mildly wrong -- should fork before writing */
word *a, *b, *path;
var *v;
struct builtin *bp;
char file[512];
struct io out[1];
int found, sep;
a = runq->argv->words->next;
if(a==0){
Xerror1("Usage: whatis name ...");
return;
}
setstatus("");
out->fd = mapfd(1);
out->bufp = out->buf;
out->ebuf = &out->buf[NBUF];
out->strp = 0;
for(;a;a = a->next){
v = vlook(a->word);
if(v->val){
pfmt(out, "%s=", a->word);
if(v->val->next==0)
pfmt(out, "%q\n", v->val->word);
else{
sep='(';
for(b = v->val;b && b->word;b = b->next){
pfmt(out, "%c%q", sep, b->word);
sep=' ';
}
pfmt(out, ")\n");
}
found = 1;
}
else
found = 0;
v = gvlook(a->word);
if(v->fn)
pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
else{
for(bp = Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){
pfmt(out, "builtin %s\n", a->word);
break;
}
if(!bp->name){
for(path = searchpath(a->word);path;path = path->next){
strcpy(file, path->word);
if(file[0])
strcat(file, "/");
strcat(file, a->word);
if(Executable(file)){
pfmt(out, "%s\n", file);
break;
}
}
if(!path && !found){
pfmt(err, "%s: not found\n", a->word);
setstatus("not found");
}
}
}
}
poplist();
flush(err);
}
void
execwait(void)
{
switch(count(runq->argv->words)){
default:
Xerror1("Usage: wait [pid]");
return;
case 2:
Waitfor(atoi(runq->argv->words->next->word), 0);
break;
case 1:
Waitfor(-1, 0);
break;
}
poplist();
}

77
cmd/rc/subr.c Normal file
View File

@ -0,0 +1,77 @@
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
char*
emalloc(long n)
{
char *p = (char *)Malloc(n);
if(p==0)
panic("Can't malloc %d bytes", n);
/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/
memset(p, 0, n);
return p;
}
void
efree(char *p)
{
/* pfmt(err, "free %p\n", p); flush(err); /**/
if(p)
free(p);
else pfmt(err, "free 0\n");
}
extern int lastword, lastdol;
void
yyerror(char *m)
{
pfmt(err, "rc: ");
if(runq->cmdfile && !runq->iflag)
pfmt(err, "%s:%d: ", runq->cmdfile, runq->lineno);
else if(runq->cmdfile)
pfmt(err, "%s: ", runq->cmdfile);
else if(!runq->iflag)
pfmt(err, "line %d: ", runq->lineno);
if(tok[0] && tok[0]!='\n')
pfmt(err, "token %q: ", tok);
pfmt(err, "%s\n", m);
flush(err);
lastword = 0;
lastdol = 0;
while(lastc!='\n' && lastc!=EOF) advance();
nerror++;
setvar("status", newword(m, (word *)0));
}
char *bp;
static void
iacvt(int n)
{
if(n<0){
*bp++='-';
n=-n; /* doesn't work for n==-inf */
}
if(n/10)
iacvt(n/10);
*bp++=n%10+'0';
}
void
inttoascii(char *s, long n)
{
bp = s;
iacvt(n);
*bp='\0';
}
void
panic(char *s, int n)
{
pfmt(err, "rc: ");
pfmt(err, s, n);
pchr(err, '\n');
flush(err);
Abort();
}

91
cmd/rc/syn.y Normal file
View File

@ -0,0 +1,91 @@
%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN
%term WORD REDIR REDIRW DUP PIPE SUB
%term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
/* operator priorities -- lowest first */
%left IF WHILE FOR SWITCH ')' NOT
%left ANDAND OROR
%left BANG SUBSHELL
%left PIPE
%left '^'
%right '$' COUNT '"'
%left SUB
%{
#include "rc.h"
#include "fns.h"
%}
%union{
struct tree *tree;
};
%type<tree> line paren brace body cmdsa cmdsan assign epilog redir
%type<tree> cmd simple first word comword keyword words
%type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN
%type<tree> WORD REDIR REDIRW DUP PIPE
%%
rc: { return 1;}
| line '\n' {return !compile($1);}
line: cmd
| cmdsa line {$$=tree2(';', $1, $2);}
body: cmd
| cmdsan body {$$=tree2(';', $1, $2);}
cmdsa: cmd ';'
| cmd '&' {$$=tree1('&', $1);}
cmdsan: cmdsa
| cmd '\n'
brace: '{' body '}' {$$=tree1(BRACE, $2);}
paren: '(' body ')' {$$=tree1(PCMD, $2);}
assign: first '=' word {$$=tree2('=', $1, $3);}
epilog: {$$=0;}
| redir epilog {$$=mung2($1, $1->child[0], $2);}
redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
| DUP
cmd: {$$=0;}
| brace epilog {$$=epimung($1, $2);}
| IF paren {skipnl();} cmd
{$$=mung2($1, $2, $4);}
| IF NOT {skipnl();} cmd {$$=mung1($2, $4);}
| FOR '(' word IN words ')' {skipnl();} cmd
/*
* if ``words'' is nil, we need a tree element to distinguish between
* for(i in ) and for(i), the former being a loop over the empty set
* and the latter being the implicit argument loop. so if $5 is nil
* (the empty set), we represent it as "()". don't parenthesize non-nil
* functions, to avoid growing parentheses every time we reread the
* definition.
*/
{$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
| FOR '(' word ')' {skipnl();} cmd
{$$=mung3($1, $3, (struct tree *)0, $6);}
| WHILE paren {skipnl();} cmd
{$$=mung2($1, $2, $4);}
| SWITCH word {skipnl();} brace
{$$=tree2(SWITCH, $2, $4);}
| simple {$$=simplemung($1);}
| TWIDDLE word words {$$=mung2($1, $2, $3);}
| cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);}
| cmd OROR cmd {$$=tree2(OROR, $1, $3);}
| cmd PIPE cmd {$$=mung2($2, $1, $3);}
| redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);}
| assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);}
| BANG cmd {$$=mung1($1, $2);}
| SUBSHELL cmd {$$=mung1($1, $2);}
| FN words brace {$$=tree2(FN, $2, $3);}
| FN words {$$=tree1(FN, $2);}
simple: first
| simple word {$$=tree2(ARGLIST, $1, $2);}
| simple redir {$$=tree2(ARGLIST, $1, $2);}
first: comword
| first '^' word {$$=tree2('^', $1, $3);}
word: keyword {lastword=1; $1->type=WORD;}
| comword
| word '^' word {$$=tree2('^', $1, $3);}
comword: '$' word {$$=tree1('$', $2);}
| '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
| '"' word {$$=tree1('"', $2);}
| COUNT word {$$=tree1(COUNT, $2);}
| WORD
| '`' brace {$$=tree1('`', $2);}
| '(' words ')' {$$=tree1(PAREN, $2);}
| REDIRW brace {$$=mung1($1, $2); $$->type=PIPEFD;}
keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
words: {$$=(struct tree*)0;}
| words word {$$=tree2(WORDS, $1, $2);}

37
cmd/rc/trap.c Normal file
View File

@ -0,0 +1,37 @@
#include "rc.h"
#include "exec.h"
#include "fns.h"
#include "io.h"
extern char *Signame[];
void
dotrap(void)
{
int i;
struct var *trapreq;
struct word *starval;
starval = vlook("*")->val;
while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){
--trap[i];
--ntrap;
if(getpid()!=mypid) Exit(getstatus());
trapreq = vlook(Signame[i]);
if(trapreq->fn){
start(trapreq->fn, trapreq->pc, (struct var *)0);
runq->local = newvar(strdup("*"), runq->local);
runq->local->val = copywords(starval, (struct word *)0);
runq->local->changed = 1;
runq->redir = runq->startredir = 0;
}
else if(i==SIGINT || i==SIGQUIT){
/*
* run the stack down until we uncover the
* command reading loop. Xreturn will exit
* if there is none (i.e. if this is not
* an interactive rc.)
*/
while(!runq->iflag) Xreturn();
}
else Exit(getstatus());
}
}

146
cmd/rc/tree.c Normal file
View File

@ -0,0 +1,146 @@
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
tree *treenodes;
/*
* create and clear a new tree node, and add it
* to the node list.
*/
tree*
newtree(void)
{
tree *t = new(tree);
t->iskw = 0;
t->str = 0;
t->child[0] = t->child[1] = t->child[2] = 0;
t->next = treenodes;
treenodes = t;
return t;
}
void
freenodes(void)
{
tree *t, *u;
for(t = treenodes;t;t = u){
u = t->next;
if(t->str)
efree(t->str);
efree((char *)t);
}
treenodes = 0;
}
tree*
tree1(int type, tree *c0)
{
return tree3(type, c0, (tree *)0, (tree *)0);
}
tree*
tree2(int type, tree *c0, tree *c1)
{
return tree3(type, c0, c1, (tree *)0);
}
tree*
tree3(int type, tree *c0, tree *c1, tree *c2)
{
tree *t;
if(type==';'){
if(c0==0)
return c1;
if(c1==0)
return c0;
}
t = newtree();
t->type = type;
t->child[0] = c0;
t->child[1] = c1;
t->child[2] = c2;
return t;
}
tree*
mung1(tree *t, tree *c0)
{
t->child[0] = c0;
return t;
}
tree*
mung2(tree *t, tree *c0, tree *c1)
{
t->child[0] = c0;
t->child[1] = c1;
return t;
}
tree*
mung3(tree *t, tree *c0, tree *c1, tree *c2)
{
t->child[0] = c0;
t->child[1] = c1;
t->child[2] = c2;
return t;
}
tree*
epimung(tree *comp, tree *epi)
{
tree *p;
if(epi==0)
return comp;
for(p = epi;p->child[1];p = p->child[1]);
p->child[1] = comp;
return epi;
}
/*
* Add a SIMPLE node at the root of t and percolate all the redirections
* up to the root.
*/
tree*
simplemung(tree *t)
{
tree *u;
struct io *s;
t = tree1(SIMPLE, t);
s = openstr();
pfmt(s, "%t", t);
t->str = strdup(s->strp);
closeio(s);
for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){
if(u->child[1]->type==DUP
|| u->child[1]->type==REDIR){
u->child[1]->child[1] = t;
t = u->child[1];
u->child[1] = 0;
}
}
return t;
}
tree*
token(char *str, int type)
{
tree *t = newtree();
t->type = type;
t->str = strdup(str);
return t;
}
void
freetree(tree *p)
{
if(p==0)
return;
freetree(p->child[0]);
freetree(p->child[1]);
freetree(p->child[2]);
if(p->str)
efree(p->str);
efree((char *)p);
}

242
cmd/rc/unixcrap.c Normal file
View File

@ -0,0 +1,242 @@
#include <u.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <errno.h>
#include <fcntl.h>
#include <libc.h>
#include "rc.h"
#include "exec.h"
#include "io.h"
#include "fns.h"
#include "getflags.h"
extern char **mkargv(word*);
extern int mapfd(int);
static char *eargs = "cdflmnstuv";
static int rlx[] = {
RLIMIT_CORE,
RLIMIT_DATA,
RLIMIT_FSIZE,
#ifdef RLIMIT_MEMLOCK
RLIMIT_MEMLOCK,
#else
0,
#endif
#ifdef RLIMIT_RSS
RLIMIT_RSS,
#else
0,
#endif
RLIMIT_NOFILE,
RLIMIT_STACK,
RLIMIT_CPU,
#ifdef RLIMIT_NPROC
RLIMIT_NPROC,
#else
0,
#endif
#ifdef RLIMIT_RSS
RLIMIT_RSS,
#else
0,
#endif
};
static void
eusage(void)
{
fprint(mapfd(2), "usage: ulimit [-SHa%s [limit]]\n", eargs);
}
#define Notset -4
#define Unlimited -3
#define Hard -2
#define Soft -1
void
execulimit(void)
{
rlim_t n;
int fd, argc, sethard, setsoft, limit;
int flag[256];
char **argv, **oargv, *p;
char *argv0;
struct rlimit rl;
argv0 = nil;
setstatus("");
oargv = mkargv(runq->argv->words);
argv = oargv+1;
for(argc=0; argv[argc]; argc++)
;
memset(flag, 0, sizeof flag);
ARGBEGIN{
default:
if(strchr(eargs, ARGC()) == nil){
eusage();
return;
}
case 'S':
case 'H':
case 'a':
flag[ARGC()] = 1;
break;
}ARGEND
if(argc > 1){
eusage();
goto out;
}
fd = mapfd(1);
sethard = 1;
setsoft = 1;
if(flag['S'] && flag['H'])
;
else if(flag['S'])
sethard = 0;
else if(flag['H'])
setsoft = 0;
limit = Notset;
if(argc>0){
if(strcmp(argv[0], "unlimited") == 0)
limit = Unlimited;
else if(strcmp(argv[0], "hard") == 0)
limit = Hard;
else if(strcmp(argv[0], "soft") == 0)
limit = Soft;
else if((limit = strtol(argv[0], &p, 0)) < 0 || *p != 0){
eusage();
goto out;
}
}
if(flag['a']){
for(p=eargs; *p; p++){
getrlimit(rlx[p-eargs], &rl);
n = flag['H'] ? rl.rlim_max : rl.rlim_cur;
if(n == RLIM_INFINITY)
fprint(fd, "ulimit -%c unlimited\n", *p);
else
fprint(fd, "ulimit -%c %llud\n", *p, (uvlong)n);
}
goto out;
}
for(p=eargs; *p; p++){
if(flag[(uchar)*p]){
n = 0;
getrlimit(rlx[p-eargs], &rl);
switch(limit){
case Notset:
n = flag['H'] ? rl.rlim_max : rl.rlim_cur;
if(n == RLIM_INFINITY)
fprint(fd, "ulimit -%c unlimited\n", *p);
else
fprint(fd, "ulimit -%c %llud\n", *p, (uvlong)n);
break;
case Hard:
n = rl.rlim_max;
goto set;
case Soft:
n = rl.rlim_cur;
goto set;
case Unlimited:
n = RLIM_INFINITY;
goto set;
default:
n = limit;
set:
if(setsoft)
rl.rlim_cur = n;
if(sethard)
rl.rlim_max = n;
if(setrlimit(rlx[p-eargs], &rl) < 0)
fprint(mapfd(2), "setrlimit: %r\n");
}
}
}
out:
free(oargv);
poplist();
flush(err);
}
void
execumask(void)
{
int n, argc;
char **argv, **oargv, *p;
char *argv0;
argv0 = nil;
setstatus("");
oargv = mkargv(runq->argv->words);
argv = oargv+1;
for(argc=0; argv[argc]; argc++)
;
ARGBEGIN{
default:
usage:
fprint(mapfd(2), "usage: umask [mode]\n");
goto out;
}ARGEND
if(argc > 1)
goto usage;
if(argc == 1){
n = strtol(argv[0], &p, 8);
if(*p != 0 || p == argv[0])
goto usage;
umask(n);
goto out;
}
n = umask(0);
umask(n);
if(n < 0){
fprint(mapfd(2), "umask: %r\n");
goto out;
}
fprint(mapfd(1), "umask %03o\n", n);
out:
free(oargv);
poplist();
flush(err);
}
/*
* Cope with non-blocking read.
*/
long
readnb(int fd, char *buf, long cnt)
{
int n, didreset;
int flgs;
didreset = 0;
again:
n = read(fd, buf, cnt);
if(n == -1)
if(errno == EAGAIN){
if(!didreset){
if((flgs = fcntl(fd, F_GETFL, 0)) == -1)
return -1;
flgs &= ~O_NONBLOCK;
if(fcntl(fd, F_SETFL, flgs) == -1)
return -1;
didreset = 1;
}
goto again;
}
return n;
}

173
cmd/rc/var.c Normal file
View File

@ -0,0 +1,173 @@
#include "rc.h"
#include "exec.h"
#include "fns.h"
int
hash(char *s, int n)
{
int h = 0, i = 1;
while(*s) h+=*s++*i++;
h%=n;
return h<0?h+n:h;
}
#define NKW 30
struct kw{
char *name;
int type;
struct kw *next;
}*kw[NKW];
void
kenter(int type, char *name)
{
int h = hash(name, NKW);
struct kw *p = new(struct kw);
p->type = type;
p->name = name;
p->next = kw[h];
kw[h] = p;
}
void
kinit(void)
{
kenter(FOR, "for");
kenter(IN, "in");
kenter(WHILE, "while");
kenter(IF, "if");
kenter(NOT, "not");
kenter(TWIDDLE, "~");
kenter(BANG, "!");
kenter(SUBSHELL, "@");
kenter(SWITCH, "switch");
kenter(FN, "fn");
}
tree*
klook(char *name)
{
struct kw *p;
tree *t = token(name, WORD);
for(p = kw[hash(name, NKW)];p;p = p->next)
if(strcmp(p->name, name)==0){
t->type = p->type;
t->iskw = 1;
break;
}
return t;
}
var*
gvlook(char *name)
{
int h = hash(name, NVAR);
var *v;
for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
return gvar[h] = newvar(strdup(name), gvar[h]);
}
var*
vlook(char *name)
{
var *v;
if(runq)
for(v = runq->local;v;v = v->next)
if(strcmp(v->name, name)==0) return v;
return gvlook(name);
}
void
_setvar(char *name, word *val, int callfn)
{
struct var *v = vlook(name);
freewords(v->val);
v->val=val;
v->changed=1;
if(callfn && v->changefn)
v->changefn(v);
}
void
setvar(char *name, word *val)
{
_setvar(name, val, 1);
}
void
bigpath(var *v)
{
/* convert $PATH to $path */
char *p, *q;
word **l, *w;
if(v->val == nil){
_setvar("path", nil, 0);
return;
}
p = v->val->word;
w = nil;
l = &w;
/*
* Doesn't handle escaped colon nonsense.
*/
if(p[0] == 0)
p = nil;
while(p){
q = strchr(p, ':');
if(q)
*q = 0;
*l = newword(p[0] ? p : ".", nil);
l = &(*l)->next;
if(q){
*q = ':';
p = q+1;
}else
p = nil;
}
_setvar("path", w, 0);
}
char*
list2strcolon(word *words)
{
char *value, *s, *t;
int len = 0;
word *ap;
for(ap = words;ap;ap = ap->next)
len+=1+strlen(ap->word);
value = emalloc(len+1);
s = value;
for(ap = words;ap;ap = ap->next){
for(t = ap->word;*t;) *s++=*t++;
*s++=':';
}
if(s==value)
*s='\0';
else s[-1]='\0';
return value;
}
void
littlepath(var *v)
{
/* convert $path to $PATH */
char *p;
word *w;
p = list2strcolon(v->val);
w = new(word);
w->word = p;
w->next = nil;
_setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */
}
void
pathinit(void)
{
var *v;
v = gvlook("path");
v->changefn = littlepath;
v = gvlook("PATH");
v->changefn = bigpath;
bigpath(v);
}

2993
cmd/yacc.c Normal file

File diff suppressed because it is too large Load Diff

91
include/bio.h Normal file
View File

@ -0,0 +1,91 @@
#ifndef _BIO_H_
#define _BIO_H_ 1
#if defined(__cplusplus)
extern "C" {
#endif
#ifdef AUTOLIB
AUTOLIB(bio)
#endif
#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
typedef struct Biobuf Biobuf;
enum
{
Bsize = 8*1024,
Bungetsize = 4, /* space for ungetc */
Bmagic = 0x314159,
Beof = -1,
Bbad = -2,
Binactive = 0, /* states */
Bractive,
Bwactive,
Bracteof,
Bend
};
struct Biobuf
{
int icount; /* neg num of bytes at eob */
int ocount; /* num of bytes at bob */
int rdline; /* num of bytes after rdline */
int runesize; /* num of bytes of last getrune */
int state; /* r/w/inactive */
int fid; /* open file */
int flag; /* magic if malloc'ed */
long long offset; /* offset of buffer in file */
int bsize; /* size of buffer */
unsigned char* bbuf; /* pointer to beginning of buffer */
unsigned char* ebuf; /* pointer to end of buffer */
unsigned char* gbuf; /* pointer to good data in buf */
unsigned char b[Bungetsize+Bsize];
};
#define BGETC(bp)\
((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
#define BPUTC(bp,c)\
((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
#define BOFFSET(bp)\
(((bp)->state==Bractive)?\
(bp)->offset + (bp)->icount:\
(((bp)->state==Bwactive)?\
(bp)->offset + ((bp)->bsize + (bp)->ocount):\
-1))
#define BLINELEN(bp)\
(bp)->rdline
#define BFILDES(bp)\
(bp)->fid
int Bbuffered(Biobuf*);
Biobuf* Bfdopen(int, int);
int Bfildes(Biobuf*);
int Bflush(Biobuf*);
int Bgetc(Biobuf*);
int Bgetd(Biobuf*, double*);
long Bgetrune(Biobuf*);
int Binit(Biobuf*, int, int);
int Binits(Biobuf*, int, int, unsigned char*, int);
int Blinelen(Biobuf*);
long long Boffset(Biobuf*);
Biobuf* Bopen(char*, int);
int Bprint(Biobuf*, char*, ...);
int Bputc(Biobuf*, int);
int Bputrune(Biobuf*, long);
void* Brdline(Biobuf*, int);
char* Brdstr(Biobuf*, int, int);
long Bread(Biobuf*, void*, long);
long long Bseek(Biobuf*, long long, int);
int Bterm(Biobuf*);
int Bungetc(Biobuf*);
int Bungetrune(Biobuf*);
long Bwrite(Biobuf*, void*, long);
int Bvprint(Biobuf*, char*, va_list);
#if defined(__cplusplus)
}
#endif
#endif

116
include/fmt.h Normal file
View File

@ -0,0 +1,116 @@
#ifndef _FMT_H_
#define _FMT_H_ 1
#if defined(__cplusplus)
extern "C" {
#endif
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
#include <stdarg.h>
#include <utf.h>
typedef struct Fmt Fmt;
struct Fmt{
unsigned char runes; /* output buffer is runes or chars? */
void *start; /* of buffer */
void *to; /* current place in the buffer */
void *stop; /* end of the buffer; overwritten if flush fails */
int (*flush)(Fmt *); /* called when to == stop */
void *farg; /* to make flush a closure */
int nfmt; /* num chars formatted so far */
va_list args; /* args passed to dofmt */
Rune r; /* % format Rune */
int width;
int prec;
unsigned long flags;
char *decimal; /* decimal point; cannot be "" */
/* For %'d */
char *thousands; /* separator for thousands */
/*
* Each char is an integer indicating #digits before next separator. Values:
* \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
* \x00: repeat previous indefinitely
* \x**: count that many
*/
char *grouping; /* descriptor of separator placement */
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtApost = FmtSign << 1,
FmtZero = FmtApost << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtByte = FmtComma << 1,
FmtLDouble = FmtByte << 1,
FmtFlag = FmtLDouble << 1
};
extern int (*fmtdoquote)(int);
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
int dofmt(Fmt *f, char *fmt);
int dorfmt(Fmt *f, const Rune *fmt);
double fmtcharstod(int(*f)(void*), void *vp);
int fmtfdflush(Fmt *f);
int fmtfdinit(Fmt *f, int fd, char *buf, int size);
int fmtinstall(int c, int (*f)(Fmt*));
int fmtnullinit(Fmt*);
void fmtlocaleinit(Fmt*, char*, char*, char*);
int fmtprint(Fmt *f, char *fmt, ...);
int fmtrune(Fmt *f, int r);
int fmtrunestrcpy(Fmt *f, Rune *s);
int fmtstrcpy(Fmt *f, char *s);
char* fmtstrflush(Fmt *f);
int fmtstrinit(Fmt *f);
double fmtstrtod(const char *as, char **aas);
int fmtvprint(Fmt *f, char *fmt, va_list args);
int fprint(int fd, char *fmt, ...);
int print(char *fmt, ...);
void quotefmtinstall(void);
int quoterunestrfmt(Fmt *f);
int quotestrfmt(Fmt *f);
Rune* runefmtstrflush(Fmt *f);
int runefmtstrinit(Fmt *f);
Rune* runeseprint(Rune *buf, Rune *e, char *fmt, ...);
Rune* runesmprint(char *fmt, ...);
int runesnprint(Rune *buf, int len, char *fmt, ...);
int runesprint(Rune *buf, char *fmt, ...);
Rune* runevseprint(Rune *buf, Rune *e, char *fmt, va_list args);
Rune* runevsmprint(char *fmt, va_list args);
int runevsnprint(Rune *buf, int len, char *fmt, va_list args);
char* seprint(char *buf, char *e, char *fmt, ...);
char* smprint(char *fmt, ...);
int snprint(char *buf, int len, char *fmt, ...);
int sprint(char *buf, char *fmt, ...);
int vfprint(int fd, char *fmt, va_list args);
char* vseprint(char *buf, char *e, char *fmt, va_list args);
char* vsmprint(char *fmt, va_list args);
int vsnprint(char *buf, int len, char *fmt, va_list args);
#if defined(__cplusplus)
}
#endif
#endif

2
include/lib9.h Normal file
View File

@ -0,0 +1,2 @@
#include <u.h>
#include <libc.h>

950
include/libc.h Normal file
View File

@ -0,0 +1,950 @@
// This file originated as Plan 9's /sys/include/libc.h.
// The plan9port-specific changes may be distributed
// using the license in ../src/lib9/LICENSE.
/*
* Lib9 is miscellany from the Plan 9 C library that doesn't
* fit into libutf or into libfmt, but is still missing from traditional
* Unix C libraries.
*/
#ifndef _LIBC_H_
#define _LIBC_H_ 1
#if defined(__cplusplus)
extern "C" {
#endif
#include <utf.h>
#include <fmt.h>
/*
* Begin usual libc.h
*/
#ifndef nil
#define nil ((void*)0)
#endif
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#ifndef offsetof
#define offsetof(s, m) (ulong)(&(((s*)0)->m))
#endif
/*
* mem routines (provided by system <string.h>)
*
extern void* memccpy(void*, void*, int, ulong);
extern void* memset(void*, int, ulong);
extern int memcmp(void*, void*, ulong);
extern void* memcpy(void*, void*, ulong);
extern void* memmove(void*, void*, ulong);
extern void* memchr(void*, int, ulong);
*/
/*
* string routines (provided by system <string.h>)
*
extern char* strcat(char*, char*);
extern char* strchr(char*, int);
extern int strcmp(char*, char*);
extern char* strcpy(char*, char*);
*/
extern char* strecpy(char*, char*, char*);
extern char* p9strdup(char*);
/*
extern char* strncat(char*, char*, long);
extern char* strncpy(char*, char*, long);
extern int strncmp(char*, char*, long);
extern char* strpbrk(char*, char*);
extern char* strrchr(char*, int);
extern char* strtok(char*, char*);
extern long strlen(char*);
extern long strspn(char*, char*);
extern long strcspn(char*, char*);
extern char* strstr(char*, char*);
*/
extern int cistrncmp(char*, char*, int);
extern int cistrcmp(char*, char*);
extern char* cistrstr(char*, char*);
extern int tokenize(char*, char**, int);
/*
enum
{
UTFmax = 4,
Runesync = 0x80,
Runeself = 0x80,
Runeerror = 0xFFFD,
Runemax = 0x10FFFF,
};
*/
/*
* rune routines (provided by <utf.h>
*
extern int runetochar(char*, Rune*);
extern int chartorune(Rune*, char*);
extern int runelen(long);
extern int runenlen(Rune*, int);
extern int fullrune(char*, int);
extern int utflen(char*);
extern int utfnlen(char*, long);
extern char* utfrune(char*, long);
extern char* utfrrune(char*, long);
extern char* utfutf(char*, char*);
extern char* utfecpy(char*, char*, char*);
extern Rune* runestrcat(Rune*, Rune*);
extern Rune* runestrchr(Rune*, Rune);
extern int runestrcmp(Rune*, Rune*);
extern Rune* runestrcpy(Rune*, Rune*);
extern Rune* runestrncpy(Rune*, Rune*, long);
extern Rune* runestrecpy(Rune*, Rune*, Rune*);
extern Rune* runestrdup(Rune*);
extern Rune* runestrncat(Rune*, Rune*, long);
extern int runestrncmp(Rune*, Rune*, long);
extern Rune* runestrrchr(Rune*, Rune);
extern long runestrlen(Rune*);
extern Rune* runestrstr(Rune*, Rune*);
extern Rune tolowerrune(Rune);
extern Rune totitlerune(Rune);
extern Rune toupperrune(Rune);
extern int isalpharune(Rune);
extern int islowerrune(Rune);
extern int isspacerune(Rune);
extern int istitlerune(Rune);
extern int isupperrune(Rune);
*/
/*
* malloc (provied by system <stdlib.h>)
*
extern void* malloc(ulong);
*/
extern void* p9malloc(ulong);
extern void* mallocz(ulong, int);
extern void p9free(void*);
extern void* p9calloc(ulong, ulong);
extern void* p9realloc(void*, ulong);
extern void setmalloctag(void*, ulong);
extern void setrealloctag(void*, ulong);
extern ulong getmalloctag(void*);
extern ulong getrealloctag(void*);
/*
extern void* malloctopoolblock(void*);
*/
#ifndef NOPLAN9DEFINES
#define malloc p9malloc
#define realloc p9realloc
#define calloc p9calloc
#define free p9free
#undef strdup
#define strdup p9strdup
#endif
/*
* print routines (provided by <fmt.h>)
*
typedef struct Fmt Fmt;
struct Fmt{
uchar runes;
void *start;
void *to;
void *stop;
int (*flush)(Fmt *);
void *farg;
int nfmt;
va_list args;
int r;
int width;
int prec;
ulong flags;
};
enum{
FmtWidth = 1,
FmtLeft = FmtWidth << 1,
FmtPrec = FmtLeft << 1,
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
FmtZero = FmtSign << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
FmtVLong = FmtLong << 1,
FmtComma = FmtVLong << 1,
FmtByte = FmtComma << 1,
FmtFlag = FmtByte << 1
};
extern int print(char*, ...);
extern char* seprint(char*, char*, char*, ...);
extern char* vseprint(char*, char*, char*, va_list);
extern int snprint(char*, int, char*, ...);
extern int vsnprint(char*, int, char*, va_list);
extern char* smprint(char*, ...);
extern char* vsmprint(char*, va_list);
extern int sprint(char*, char*, ...);
extern int fprint(int, char*, ...);
extern int vfprint(int, char*, va_list);
extern int runesprint(Rune*, char*, ...);
extern int runesnprint(Rune*, int, char*, ...);
extern int runevsnprint(Rune*, int, char*, va_list);
extern Rune* runeseprint(Rune*, Rune*, char*, ...);
extern Rune* runevseprint(Rune*, Rune*, char*, va_list);
extern Rune* runesmprint(char*, ...);
extern Rune* runevsmprint(char*, va_list);
extern int fmtfdinit(Fmt*, int, char*, int);
extern int fmtfdflush(Fmt*);
extern int fmtstrinit(Fmt*);
extern char* fmtstrflush(Fmt*);
extern int runefmtstrinit(Fmt*);
extern Rune* runefmtstrflush(Fmt*);
extern int fmtinstall(int, int (*)(Fmt*));
extern int dofmt(Fmt*, char*);
extern int dorfmt(Fmt*, Rune*);
extern int fmtprint(Fmt*, char*, ...);
extern int fmtvprint(Fmt*, char*, va_list);
extern int fmtrune(Fmt*, int);
extern int fmtstrcpy(Fmt*, char*);
extern int fmtrunestrcpy(Fmt*, Rune*);
*/
/*
* error string for %r
* supplied on per os basis, not part of fmt library
*
* (provided by lib9, but declared in fmt.h)
*
extern int errfmt(Fmt *f);
*/
/*
* quoted strings
*/
extern char *unquotestrdup(char*);
extern Rune *unquoterunestrdup(Rune*);
extern char *quotestrdup(char*);
extern Rune *quoterunestrdup(Rune*);
/*
* in fmt.h
*
extern void quotefmtinstall(void);
extern int quotestrfmt(Fmt*);
extern int quoterunestrfmt(Fmt*);
*/
#ifndef NOPLAN9DEFINES
#define doquote fmtdoquote
#endif
extern int needsrcquote(int);
/*
* random number
*/
extern void p9srand(long);
extern int p9rand(void);
extern int p9nrand(int);
extern long p9lrand(void);
extern long p9lnrand(long);
extern double p9frand(void);
extern ulong truerand(void); /* uses /dev/random */
extern ulong ntruerand(ulong); /* uses /dev/random */
#ifndef NOPLAN9DEFINES
#define srand p9srand
#define rand p9rand
#define nrand p9nrand
#define lrand p9lrand
#define lnrand p9lnrand
#define frand p9frand
#endif
/*
* math
*/
extern ulong getfcr(void);
extern void setfsr(ulong);
extern ulong getfsr(void);
extern void setfcr(ulong);
extern double NaN(void);
extern double Inf(int);
extern int isNaN(double);
extern int isInf(double, int);
extern ulong umuldiv(ulong, ulong, ulong);
extern long muldiv(long, long, long);
/*
* provided by math.h
*
extern double pow(double, double);
extern double atan2(double, double);
extern double fabs(double);
extern double atan(double);
extern double log(double);
extern double log10(double);
extern double exp(double);
extern double floor(double);
extern double ceil(double);
extern double hypot(double, double);
extern double sin(double);
extern double cos(double);
extern double tan(double);
extern double asin(double);
extern double acos(double);
extern double sinh(double);
extern double cosh(double);
extern double tanh(double);
extern double sqrt(double);
extern double fmod(double, double);
#define HUGE 3.4028234e38
#define PIO2 1.570796326794896619231e0
#define PI (PIO2+PIO2)
*/
#define PI M_PI
#define PIO2 M_PI_2
/*
* Time-of-day
*/
typedef
struct Tm
{
int sec;
int min;
int hour;
int mday;
int mon;
int year;
int wday;
int yday;
char zone[4];
int tzoff;
} Tm;
extern Tm* p9gmtime(long);
extern Tm* p9localtime(long);
extern char* p9asctime(Tm*);
extern char* p9ctime(long);
extern double p9cputime(void);
extern long p9times(long*);
extern long p9tm2sec(Tm*);
extern vlong p9nsec(void);
#ifndef NOPLAN9DEFINES
#define gmtime p9gmtime
#define localtime p9localtime
#define asctime p9asctime
#define ctime p9ctime
#define cputime p9cputime
#define times p9times
#define tm2sec p9tm2sec
#define nsec p9nsec
#endif
/*
* one-of-a-kind
*/
enum
{
PNPROC = 1,
PNGROUP = 2
};
/* extern int abs(int); <stdlib.h> */
extern int p9atexit(void(*)(void));
extern void p9atexitdont(void(*)(void));
extern int atnotify(int(*)(void*, char*), int);
/*
* <stdlib.h>
extern double atof(char*); <stdlib.h>
*/
extern int p9atoi(char*);
extern long p9atol(char*);
extern vlong p9atoll(char*);
extern double fmtcharstod(int(*)(void*), void*);
extern char* cleanname(char*);
extern int p9decrypt(void*, void*, int);
extern int p9encrypt(void*, void*, int);
extern int netcrypt(void*, void*);
extern int dec64(uchar*, int, char*, int);
extern int enc64(char*, int, uchar*, int);
extern int dec32(uchar*, int, char*, int);
extern int enc32(char*, int, uchar*, int);
extern int dec16(uchar*, int, char*, int);
extern int enc16(char*, int, uchar*, int);
extern int encodefmt(Fmt*);
extern int dirmodefmt(Fmt*);
extern int exitcode(char*);
extern void exits(char*);
extern double p9frexp(double, int*);
extern ulong getcallerpc(void*);
#if defined(__GNUC__) || defined(__clang__) || defined(__IBMC__)
#define getcallerpc(x) ((ulong)__builtin_return_address(0))
#endif
extern char* p9getenv(char*);
extern int p9putenv(char*, char*);
extern int getfields(char*, char**, int, int, char*);
extern int gettokens(char *, char **, int, char *);
extern char* getuser(void);
extern char* p9getwd(char*, int);
extern int iounit(int);
/* extern long labs(long); <math.h> */
/* extern double ldexp(double, int); <math.h> */
extern void p9longjmp(p9jmp_buf, int);
extern char* mktemp(char*);
extern int opentemp(char*, int);
/* extern double modf(double, double*); <math.h> */
extern void p9notejmp(void*, p9jmp_buf, int);
extern void perror(const char*);
extern int postnote(int, int, char *);
extern double p9pow10(int);
/* extern int putenv(char*, char*); <stdlib.h. */
/* extern void qsort(void*, long, long, int (*)(void*, void*)); <stdlib.h> */
extern char* searchpath(char*);
/* extern int p9setjmp(p9jmp_buf); */
#define p9setjmp(b) sigsetjmp((void*)(b), 1)
/*
* <stdlib.h>
extern long strtol(char*, char**, int);
extern ulong strtoul(char*, char**, int);
extern vlong strtoll(char*, char**, int);
extern uvlong strtoull(char*, char**, int);
*/
extern void sysfatal(char*, ...);
extern void p9syslog(int, char*, char*, ...);
extern long p9time(long*);
/* extern int tolower(int); <ctype.h> */
/* extern int toupper(int); <ctype.h> */
extern void needstack(int);
extern char* readcons(char*, char*, int);
extern void (*_pin)(void);
extern void (*_unpin)(void);
#ifndef NOPLAN9DEFINES
#define atexit p9atexit
#define atexitdont p9atexitdont
#define atoi p9atoi
#define atol p9atol
#define atoll p9atoll
#define encrypt p9encrypt
#define decrypt p9decrypt
#undef frexp
#define frexp p9frexp
#define getenv p9getenv
#define getwd p9getwd
#define longjmp p9longjmp
#undef setjmp
#define setjmp p9setjmp
#define putenv p9putenv
#define notejmp p9notejmp
#define jmp_buf p9jmp_buf
#define time p9time
#define pow10 p9pow10
#define strtod fmtstrtod
#define charstod fmtcharstod
#define syslog p9syslog
#endif
/*
* just enough information so that libc can be
* properly locked without dragging in all of libthread
*/
typedef struct _Thread _Thread;
typedef struct _Threadlist _Threadlist;
struct _Threadlist
{
_Thread *head;
_Thread *tail;
};
extern _Thread *(*threadnow)(void);
/*
* synchronization
*/
typedef struct Lock Lock;
struct Lock
{
int init;
pthread_mutex_t mutex;
int held;
};
extern void lock(Lock*);
extern void unlock(Lock*);
extern int canlock(Lock*);
extern int (*_lock)(Lock*, int, ulong);
extern void (*_unlock)(Lock*, ulong);
typedef struct QLock QLock;
struct QLock
{
Lock l;
_Thread *owner;
_Threadlist waiting;
};
extern void qlock(QLock*);
extern void qunlock(QLock*);
extern int canqlock(QLock*);
extern int (*_qlock)(QLock*, int, ulong); /* do not use */
extern void (*_qunlock)(QLock*, ulong);
typedef struct Rendez Rendez;
struct Rendez
{
QLock *l;
_Threadlist waiting;
};
extern void rsleep(Rendez*); /* unlocks r->l, sleeps, locks r->l again */
extern int rwakeup(Rendez*);
extern int rwakeupall(Rendez*);
extern void (*_rsleep)(Rendez*, ulong); /* do not use */
extern int (*_rwakeup)(Rendez*, int, ulong);
typedef struct RWLock RWLock;
struct RWLock
{
Lock l;
int readers;
_Thread *writer;
_Threadlist rwaiting;
_Threadlist wwaiting;
};
extern void rlock(RWLock*);
extern void runlock(RWLock*);
extern int canrlock(RWLock*);
extern void wlock(RWLock*);
extern void wunlock(RWLock*);
extern int canwlock(RWLock*);
extern int (*_rlock)(RWLock*, int, ulong); /* do not use */
extern int (*_wlock)(RWLock*, int, ulong);
extern void (*_runlock)(RWLock*, ulong);
extern void (*_wunlock)(RWLock*, ulong);
/*
* per-process private data
*/
extern void** privalloc(void);
extern void privfree(void**);
/*
* network dialing
*/
#define NETPATHLEN 40
extern int p9accept(int, char*);
extern int p9announce(char*, char*);
extern int p9dial(char*, char*, char*, int*);
extern int p9dialparse(char *ds, char **net, char **unixa, void *ip, int *port);
extern void p9setnetmtpt(char*, int, char*);
extern int p9listen(char*, char*);
extern char* p9netmkaddr(char*, char*, char*);
extern int p9reject(int, char*, char*);
#ifndef NOPLAN9DEFINES
#define accept p9accept
#define announce p9announce
#define dial p9dial
#define setnetmtpt p9setnetmtpt
#define listen p9listen
#define netmkaddr p9netmkaddr
#define reject p9reject
#endif
/*
* encryption
*/
extern int pushssl(int, char*, char*, char*, int*);
extern int pushtls(int, char*, char*, int, char*, char*);
/*
* network services
*/
typedef struct NetConnInfo NetConnInfo;
struct NetConnInfo
{
char *dir; /* connection directory */
char *root; /* network root */
char *spec; /* binding spec */
char *lsys; /* local system */
char *lserv; /* local service */
char *rsys; /* remote system */
char *rserv; /* remote service */
char *laddr;
char *raddr;
};
extern NetConnInfo* getnetconninfo(char*, int);
extern void freenetconninfo(NetConnInfo*);
/*
* system calls
*
*/
#define STATMAX 65535U /* max length of machine-independent stat structure */
#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */
#define ERRMAX 128 /* max length of error string */
#define MORDER 0x0003 /* mask for bits defining order of mounting */
#define MREPL 0x0000 /* mount replaces object */
#define MBEFORE 0x0001 /* mount goes before others in union directory */
#define MAFTER 0x0002 /* mount goes after others in union directory */
#define MCREATE 0x0004 /* permit creation in mounted directory */
#define MCACHE 0x0010 /* cache some data */
#define MMASK 0x0017 /* all bits on */
#define OREAD 0 /* open for read */
#define OWRITE 1 /* write */
#define ORDWR 2 /* read and write */
#define OEXEC 3 /* execute, == read but check execute permission */
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
#define OCEXEC 32 /* or'ed in, close on exec */
#define ORCLOSE 64 /* or'ed in, remove on close */
#define ODIRECT 128 /* or'ed in, direct access */
#define ONONBLOCK 256 /* or'ed in, non-blocking call */
#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
#define OLOCK 0x2000 /* or'ed in, lock after opening */
#define OAPPEND 0x4000 /* or'ed in, append only */
#define AEXIST 0 /* accessible: exists */
#define AEXEC 1 /* execute access */
#define AWRITE 2 /* write access */
#define AREAD 4 /* read access */
/* Segattch */
#define SG_RONLY 0040 /* read only */
#define SG_CEXEC 0100 /* detach on exec */
#define NCONT 0 /* continue after note */
#define NDFLT 1 /* terminate after note */
#define NSAVE 2 /* clear note but hold state */
#define NRSTR 3 /* restore saved state */
/* bits in Qid.type */
#define QTDIR 0x80 /* type bit for directories */
#define QTAPPEND 0x40 /* type bit for append only files */
#define QTEXCL 0x20 /* type bit for exclusive use files */
#define QTMOUNT 0x10 /* type bit for mounted channel */
#define QTAUTH 0x08 /* type bit for authentication file */
#define QTTMP 0x04 /* type bit for non-backed-up file */
#define QTSYMLINK 0x02 /* type bit for symbolic link */
#define QTFILE 0x00 /* type bits for plain file */
/* bits in Dir.mode */
#define DMDIR 0x80000000 /* mode bit for directories */
#define DMAPPEND 0x40000000 /* mode bit for append only files */
#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
#define DMAUTH 0x08000000 /* mode bit for authentication file */
#define DMTMP 0x04000000 /* mode bit for non-backed-up file */
#define DMSYMLINK 0x02000000 /* mode bit for symbolic link (Unix, 9P2000.u) */
#define DMDEVICE 0x00800000 /* mode bit for device file (Unix, 9P2000.u) */
#define DMNAMEDPIPE 0x00200000 /* mode bit for named pipe (Unix, 9P2000.u) */
#define DMSOCKET 0x00100000 /* mode bit for socket (Unix, 9P2000.u) */
#define DMSETUID 0x00080000 /* mode bit for setuid (Unix, 9P2000.u) */
#define DMSETGID 0x00040000 /* mode bit for setgid (Unix, 9P2000.u) */
#define DMREAD 0x4 /* mode bit for read permission */
#define DMWRITE 0x2 /* mode bit for write permission */
#define DMEXEC 0x1 /* mode bit for execute permission */
#ifdef RFMEM /* FreeBSD, OpenBSD */
#undef RFFDG
#undef RFNOTEG
#undef RFPROC
#undef RFMEM
#undef RFNOWAIT
#undef RFCFDG
#undef RFNAMEG
#undef RFENVG
#undef RFCENVG
#undef RFCFDG
#undef RFCNAMEG
#endif
enum
{
RFNAMEG = (1<<0),
RFENVG = (1<<1),
RFFDG = (1<<2),
RFNOTEG = (1<<3),
RFPROC = (1<<4),
RFMEM = (1<<5),
RFNOWAIT = (1<<6),
RFCNAMEG = (1<<10),
RFCENVG = (1<<11),
RFCFDG = (1<<12)
/* RFREND = (1<<13), */
/* RFNOMNT = (1<<14) */
};
typedef
struct Qid
{
uvlong path;
ulong vers;
uchar type;
} Qid;
typedef
struct Dir {
/* system-modified data */
ushort type; /* server type */
uint dev; /* server subtype */
/* file data */
Qid qid; /* unique id from server */
ulong mode; /* permissions */
ulong atime; /* last read time */
ulong mtime; /* last write time */
vlong length; /* file length */
char *name; /* last element of path */
char *uid; /* owner name */
char *gid; /* group name */
char *muid; /* last modifier name */
/* 9P2000.u extensions */
uint uidnum; /* numeric uid */
uint gidnum; /* numeric gid */
uint muidnum; /* numeric muid */
char *ext; /* extended info */
} Dir;
/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
typedef
struct Waitmsg
{
int pid; /* of loved one */
ulong time[3]; /* of loved one & descendants */
char *msg;
} Waitmsg;
typedef
struct IOchunk
{
void *addr;
ulong len;
} IOchunk;
extern void _exits(char*);
extern void abort(void);
/* extern int access(char*, int); */
extern long p9alarm(ulong);
extern int await(char*, int);
extern int awaitfor(int, char*, int);
extern int awaitnohang(char*, int);
/* extern int bind(char*, char*, int); give up */
/* extern int brk(void*); <unistd.h> */
extern int p9chdir(char*);
extern int p9close(int);
extern int p9create(char*, int, ulong);
extern int p9dup(int, int);
extern int errstr(char*, uint);
extern int p9exec(char*, char*[]);
extern int p9execl(char*, ...);
/* extern int p9fork(void); */
extern int p9rfork(int);
/* not implemented
extern int fauth(int, char*);
extern int fstat(int, uchar*, int);
extern int fwstat(int, uchar*, int);
extern int fversion(int, int, char*, int);
extern int mount(int, int, char*, int, char*);
extern int unmount(char*, char*);
*/
extern int noted(int);
extern int notify(void(*)(void*, char*));
extern int noteenable(char*);
extern int notedisable(char*);
extern int notifyon(char*);
extern int notifyoff(char*);
extern int p9open(char*, int);
extern int fd2path(int, char*, int);
extern int p9pipe(int*);
/*
* use defs from <unistd.h>
extern long pread(int, void*, long, vlong);
extern long preadv(int, IOchunk*, int, vlong);
extern long pwrite(int, void*, long, vlong);
extern long pwritev(int, IOchunk*, int, vlong);
extern long read(int, void*, long);
*/
extern long readn(int, void*, long);
/* extern long readv(int, IOchunk*, int); <unistd.h> */
extern int remove(const char*);
/* extern void* sbrk(ulong); <unistd.h> */
/* extern long oseek(int, long, int); */
extern vlong p9seek(int, vlong, int);
/* give up
extern long segattach(int, char*, void*, ulong);
extern int segbrk(void*, void*);
extern int segdetach(void*);
extern int segflush(void*, ulong);
extern int segfree(void*, ulong);
*/
extern int p9sleep(long);
/* extern int stat(char*, uchar*, int); give up */
extern Waitmsg* p9wait(void);
extern Waitmsg* p9waitfor(int);
extern Waitmsg* waitnohang(void);
extern int p9waitpid(void);
/* <unistd.h>
extern long write(int, void*, long);
extern long writev(int, IOchunk*, int);
*/
extern long p9write(int, void*, long);
/* extern int wstat(char*, uchar*, int); give up */
extern ulong rendezvous(ulong, ulong);
#ifndef NOPLAN9DEFINES
#define alarm p9alarm
#define dup p9dup
#define exec p9exec
#define execl p9execl
#define seek p9seek
#define sleep p9sleep
#define wait p9wait
#define waitpid p9waitpid
/* #define fork p9fork */
#define rfork p9rfork
/* #define access p9access */
#define create p9create
#undef open
#define open p9open
#undef close
#define close p9close
#define pipe p9pipe
#define waitfor p9waitfor
#define write p9write
#endif
extern Dir* dirstat(char*);
extern Dir* dirfstat(int);
extern int dirwstat(char*, Dir*);
extern int dirfwstat(int, Dir*);
extern long dirread(int, Dir**);
extern void nulldir(Dir*);
extern long dirreadall(int, Dir**);
/* extern int getpid(void); <unistd.h> */
/* extern int getppid(void); */
extern void rerrstr(char*, uint);
extern char* sysname(void);
extern void werrstr(char*, ...);
extern char* getns(void);
extern char* get9root(void);
extern char* unsharp(char*);
extern int sendfd(int, int);
extern int recvfd(int);
extern int post9pservice(int, char*, char*);
extern int chattyfuse;
/* external names that we don't want to step on */
#ifndef NOPLAN9DEFINES
#define main p9main
#endif
#ifdef VARARGCK
#pragma varargck type "lld" vlong
#pragma varargck type "llx" vlong
#pragma varargck type "lld" uvlong
#pragma varargck type "llx" uvlong
#pragma varargck type "ld" long
#pragma varargck type "lx" long
#pragma varargck type "ld" ulong
#pragma varargck type "lx" ulong
#pragma varargck type "d" int
#pragma varargck type "x" int
#pragma varargck type "c" int
#pragma varargck type "C" int
#pragma varargck type "d" uint
#pragma varargck type "x" uint
#pragma varargck type "c" uint
#pragma varargck type "C" uint
#pragma varargck type "f" double
#pragma varargck type "e" double
#pragma varargck type "g" double
#pragma varargck type "lf" long double
#pragma varargck type "le" long double
#pragma varargck type "lg" long double
#pragma varargck type "s" char*
#pragma varargck type "q" char*
#pragma varargck type "S" Rune*
#pragma varargck type "Q" Rune*
#pragma varargck type "r" void
#pragma varargck type "%" void
#pragma varargck type "n" int*
#pragma varargck type "p" void*
#pragma varargck type "<" void*
#pragma varargck type "[" void*
#pragma varargck type "H" void*
#pragma varargck type "lH" void*
#pragma varargck flag ' '
#pragma varargck flag '#'
#pragma varargck flag '+'
#pragma varargck flag ','
#pragma varargck flag '-'
#pragma varargck flag 'u'
#pragma varargck argpos fmtprint 2
#pragma varargck argpos fprint 2
#pragma varargck argpos print 1
#pragma varargck argpos runeseprint 3
#pragma varargck argpos runesmprint 1
#pragma varargck argpos runesnprint 3
#pragma varargck argpos runesprint 2
#pragma varargck argpos seprint 3
#pragma varargck argpos smprint 1
#pragma varargck argpos snprint 3
#pragma varargck argpos sprint 2
#pragma varargck argpos sysfatal 1
#pragma varargck argpos p9syslog 3
#pragma varargck argpos werrstr 1
#endif
/* compiler directives on plan 9 */
#define SET(x) ((x)=0)
#define USED(x) if(x){}else{}
#ifdef __GNUC__
# if __GNUC__ >= 3
# undef USED
# define USED(x) ((void)(x))
# endif
#endif
/* command line */
extern char *argv0;
extern void __fixargv0(void);
#define ARGBEGIN for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
argv[0] && argv[0][0]=='-' && argv[0][1];\
argc--, argv++) {\
char *_args, *_argt;\
Rune _argc;\
_args = &argv[0][1];\
if(_args[0]=='-' && _args[1]==0){\
argc--; argv++; break;\
}\
_argc = 0;\
while(*_args && (_args += chartorune(&_argc, _args)))\
switch(_argc)
#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
#define ARGF() (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
#define EARGF(x) (_argt=_args, _args="",\
(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
#define ARGC() _argc
#if defined(__cplusplus)
}
#endif
#endif /* _LIB9_H_ */

195
include/u.h Normal file
View File

@ -0,0 +1,195 @@
// See ../src/lib9/LICENSE
#ifndef _U_H_
#define _U_H_ 1
#if defined(__cplusplus)
extern "C" {
#endif
#define HAS_SYS_TERMIOS 1
#define __BSD_VISIBLE 1 /* FreeBSD 5.x */
#if defined(__sun__)
# define __EXTENSIONS__ 1 /* SunOS */
# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__)
/* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
# else
/* What's left? */
# define __MAKECONTEXT_V2_SOURCE 1
# endif
#endif
#define _BSD_SOURCE 1
#define _NETBSD_SOURCE 1 /* NetBSD */
#define _SVID_SOURCE 1
#define _DEFAULT_SOURCE 1
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__AIX__)
# define _XOPEN_SOURCE 1000
# define _XOPEN_SOURCE_EXTENDED 1
#endif
#if defined(__FreeBSD__)
# include <sys/cdefs.h>
/* for strtoll */
# undef __ISO_C_VISIBLE
# define __ISO_C_VISIBLE 1999
# undef __LONG_LONG_SUPPORTED
# define __LONG_LONG_SUPPORTED
#endif
#if defined(__AIX__)
# define _ALL_SOURCE
# undef HAS_SYS_TERMIOS
#endif
#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS 64
#include <inttypes.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <assert.h>
#include <setjmp.h>
#include <stddef.h>
#include <math.h>
#include <ctype.h> /* for tolower */
/*
* OS-specific crap
*/
#define _NEEDUCHAR 1
#define _NEEDUSHORT 1
#define _NEEDUINT 1
#define _NEEDULONG 1
typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
#if defined(__linux__)
# include <sys/types.h>
# include <pthread.h>
# if defined(__USE_MISC)
# undef _NEEDUSHORT
# undef _NEEDUINT
# undef _NEEDULONG
# endif
#elif defined(__sun__)
# include <sys/types.h>
# include <pthread.h>
# undef _NEEDUSHORT
# undef _NEEDUINT
# undef _NEEDULONG
# define nil 0 /* no cast to void* */
#elif defined(__FreeBSD__)
# include <sys/types.h>
# include <osreldate.h>
# include <pthread.h>
# if !defined(_POSIX_SOURCE)
# undef _NEEDUSHORT
# undef _NEEDUINT
# endif
#elif defined(__APPLE__)
# include <sys/types.h>
# include <pthread.h>
# if __GNUC__ < 4
# undef _NEEDUSHORT
# undef _NEEDUINT
# endif
# undef _ANSI_SOURCE
# undef _POSIX_C_SOURCE
# undef _XOPEN_SOURCE
# if !defined(NSIG)
# define NSIG 32
# endif
# define _NEEDLL 1
#elif defined(__NetBSD__)
# include <sched.h>
# include <sys/types.h>
# include <pthread.h>
# undef _NEEDUSHORT
# undef _NEEDUINT
# undef _NEEDULONG
#elif defined(__OpenBSD__)
# include <sys/types.h>
# include <pthread.h>
# undef _NEEDUSHORT
# undef _NEEDUINT
# undef _NEEDULONG
#else
/* No idea what system this is -- try some defaults */
# include <pthread.h>
#endif
#ifndef O_DIRECT
#define O_DIRECT 0
#endif
typedef signed char schar;
#ifdef _NEEDUCHAR
typedef unsigned char uchar;
#endif
#ifdef _NEEDUSHORT
typedef unsigned short ushort;
#endif
#ifdef _NEEDUINT
typedef unsigned int uint;
#endif
#ifdef _NEEDULONG
typedef unsigned long ulong;
#endif
typedef unsigned long long uvlong;
typedef long long vlong;
typedef uvlong u64int;
typedef vlong s64int;
typedef uint8_t u8int;
typedef int8_t s8int;
typedef uint16_t u16int;
typedef int16_t s16int;
typedef uintptr_t uintptr;
typedef intptr_t intptr;
typedef uint u32int;
typedef int s32int;
typedef u32int uint32;
typedef s32int int32;
typedef u16int uint16;
typedef s16int int16;
typedef u64int uint64;
typedef s64int int64;
typedef u8int uint8;
typedef s8int int8;
#undef _NEEDUCHAR
#undef _NEEDUSHORT
#undef _NEEDUINT
#undef _NEEDULONG
/*
* Funny-named symbols to tip off 9l to autolink.
*/
#define AUTOLIB(x) static int __p9l_autolib_ ## x = 1;
#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
/*
* Gcc is too smart for its own good.
*/
#if defined(__GNUC__)
# undef strcmp /* causes way too many warnings */
# if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__))
# undef AUTOLIB
# define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
# undef AUTOFRAMEWORK
# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak));
# else
# undef AUTOLIB
# define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused));
# undef AUTOFRAMEWORK
# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused));
# endif
#endif
#if defined(__cplusplus)
}
#endif
#endif

54
include/utf.h Normal file
View File

@ -0,0 +1,54 @@
#ifndef _UTF_H_
#define _UTF_H_ 1
#if defined(__cplusplus)
extern "C" {
#endif
typedef unsigned int Rune; /* 32 bits */
enum
{
UTFmax = 4, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
Runeerror = 0xFFFD, /* decoding error in UTF */
Runemax = 0x10FFFF /* maximum rune value */
};
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
int chartorune(Rune *rune, char *str);
int fullrune(char *str, int n);
int isalpharune(Rune c);
int islowerrune(Rune c);
int isspacerune(Rune c);
int istitlerune(Rune c);
int isupperrune(Rune c);
int runelen(long c);
int runenlen(Rune *r, int nrune);
Rune* runestrcat(Rune *s1, Rune *s2);
Rune* runestrchr(Rune *s, Rune c);
int runestrcmp(Rune *s1, Rune *s2);
Rune* runestrcpy(Rune *s1, Rune *s2);
Rune* runestrdup(Rune *s) ;
Rune* runestrecpy(Rune *s1, Rune *es1, Rune *s2);
long runestrlen(Rune *s);
Rune* runestrncat(Rune *s1, Rune *s2, long n);
int runestrncmp(Rune *s1, Rune *s2, long n);
Rune* runestrncpy(Rune *s1, Rune *s2, long n);
Rune* runestrrchr(Rune *s, Rune c);
Rune* runestrstr(Rune *s1, Rune *s2);
int runetochar(char *str, Rune *rune);
Rune tolowerrune(Rune c);
Rune totitlerune(Rune c);
Rune toupperrune(Rune c);
char* utfecpy(char *to, char *e, char *from);
int utflen(char *s);
int utfnlen(char *s, long m);
char* utfrrune(char *s, long c);
char* utfrune(char *s, long c);
char* utfutf(char *s1, char *s2);
#if defined(__cplusplus)
}
#endif
#endif

12
lib/bio/_lib9.h Normal file
View File

@ -0,0 +1,12 @@
#include <fmt.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define OREAD O_RDONLY
#define OWRITE O_WRONLY
#include <utf.h>
#define nil ((void*)0)

20
lib/bio/bbuffered.c Normal file
View File

@ -0,0 +1,20 @@
#include "lib9.h"
#include <bio.h>
int
Bbuffered(Biobuf *bp)
{
switch(bp->state) {
case Bracteof:
case Bractive:
return -bp->icount;
case Bwactive:
return bp->bsize + bp->ocount;
case Binactive:
return 0;
}
fprint(2, "Bbuffered: unknown state %d\n", bp->state);
return 0;
}

46
lib/bio/bcat.c Normal file
View File

@ -0,0 +1,46 @@
#include <fmt.h>
#include "bio.h"
Biobuf bout;
void
bcat(Biobuf *b, char *name)
{
char buf[1000];
int n;
while((n = Bread(b, buf, sizeof buf)) > 0){
if(Bwrite(&bout, buf, n) < 0)
fprint(2, "writing during %s: %r\n", name);
}
if(n < 0)
fprint(2, "reading %s: %r\n", name);
}
int
main(int argc, char **argv)
{
int i;
Biobuf b, *bp;
Fmt fmt;
Binit(&bout, 1, O_WRONLY);
Bfmtinit(&fmt, &bout);
fmtprint(&fmt, "hello, world\n");
Bfmtflush(&fmt);
if(argc == 1){
Binit(&b, 0, O_RDONLY);
bcat(&b, "<stdin>");
}else{
for(i=1; i<argc; i++){
if((bp = Bopen(argv[i], O_RDONLY)) == 0){
fprint(2, "Bopen %s: %r\n", argv[i]);
continue;
}
bcat(bp, argv[i]);
Bterm(bp);
}
}
exit(0);
}

9
lib/bio/bfildes.c Normal file
View File

@ -0,0 +1,9 @@
#include "lib9.h"
#include <bio.h>
int
Bfildes(Biobuf *bp)
{
return bp->fid;
}

33
lib/bio/bflush.c Normal file
View File

@ -0,0 +1,33 @@
#include "lib9.h"
#include <bio.h>
int
Bflush(Biobuf *bp)
{
int n, c;
switch(bp->state) {
case Bwactive:
n = bp->bsize+bp->ocount;
if(n == 0)
return 0;
c = write(bp->fid, bp->bbuf, n);
if(n == c) {
bp->offset += n;
bp->ocount = -bp->bsize;
return 0;
}
bp->state = Binactive;
bp->ocount = 0;
break;
case Bracteof:
bp->state = Bractive;
case Bractive:
bp->icount = 0;
bp->gbuf = bp->ebuf;
return 0;
}
return Beof;
}

53
lib/bio/bgetc.c Normal file
View File

@ -0,0 +1,53 @@
#include "lib9.h"
#include <bio.h>
int
Bgetc(Biobuf *bp)
{
int i;
loop:
i = bp->icount;
if(i != 0) {
bp->icount = i+1;
return bp->ebuf[i];
}
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
return Beof;
}
/*
* get next buffer, try to keep Bungetsize
* characters pre-catenated from the previous
* buffer to allow that many ungets.
*/
memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
i = read(bp->fid, bp->bbuf, bp->bsize);
bp->gbuf = bp->bbuf;
if(i <= 0) {
bp->state = Bracteof;
if(i < 0)
bp->state = Binactive;
return Beof;
}
if(i < bp->bsize) {
memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
bp->gbuf = bp->ebuf-i;
}
bp->icount = -i;
bp->offset += i;
goto loop;
}
int
Bungetc(Biobuf *bp)
{
if(bp->state == Bracteof)
bp->state = Bractive;
if(bp->state != Bractive)
return Beof;
bp->icount--;
return 1;
}

36
lib/bio/bgetd.c Normal file
View File

@ -0,0 +1,36 @@
#include "lib9.h"
#include <bio.h>
struct bgetd
{
Biobuf* b;
int eof;
};
static int
Bgetdf(void *vp)
{
int c;
struct bgetd *bg = vp;
c = Bgetc(bg->b);
if(c == Beof)
bg->eof = 1;
return c;
}
int
Bgetd(Biobuf *bp, double *dp)
{
double d;
struct bgetd b;
b.b = bp;
b.eof = 0;
d = fmtcharstod(Bgetdf, &b);
if(b.eof)
return -1;
Bungetc(bp);
*dp = d;
return 1;
}

47
lib/bio/bgetrune.c Normal file
View File

@ -0,0 +1,47 @@
#include "lib9.h"
#include <bio.h>
#include <utf.h>
long
Bgetrune(Biobuf *bp)
{
int c, i;
Rune rune;
char str[UTFmax];
c = Bgetc(bp);
if(c < Runeself) { /* one char */
bp->runesize = 1;
return c;
}
str[0] = c;
for(i=1;;) {
c = Bgetc(bp);
if(c < 0)
return c;
str[i++] = c;
if(fullrune(str, i)) {
bp->runesize = chartorune(&rune, str);
while(i > bp->runesize) {
Bungetc(bp);
i--;
}
return rune;
}
}
}
int
Bungetrune(Biobuf *bp)
{
if(bp->state == Bracteof)
bp->state = Bractive;
if(bp->state != Bractive)
return Beof;
bp->icount -= bp->runesize;
bp->runesize = 0;
return 1;
}

155
lib/bio/binit.c Normal file
View File

@ -0,0 +1,155 @@
#include "lib9.h"
#include <bio.h>
enum
{
MAXBUFS = 20
};
static Biobuf* wbufs[MAXBUFS];
static int atexitflag;
static
void
batexit(void)
{
Biobuf *bp;
int i;
for(i=0; i<MAXBUFS; i++) {
bp = wbufs[i];
if(bp != 0) {
wbufs[i] = 0;
Bflush(bp);
}
}
}
static
void
deinstall(Biobuf *bp)
{
int i;
for(i=0; i<MAXBUFS; i++)
if(wbufs[i] == bp)
wbufs[i] = 0;
}
static
void
install(Biobuf *bp)
{
int i;
deinstall(bp);
for(i=0; i<MAXBUFS; i++)
if(wbufs[i] == 0) {
wbufs[i] = bp;
break;
}
if(atexitflag == 0) {
atexitflag = 1;
atexit(batexit);
}
}
int
Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
{
p += Bungetsize; /* make room for Bungets */
size -= Bungetsize;
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return Beof;
case OREAD:
bp->state = Bractive;
bp->ocount = 0;
break;
case OWRITE:
install(bp);
bp->state = Bwactive;
bp->ocount = -size;
break;
}
bp->bbuf = p;
bp->ebuf = p+size;
bp->bsize = size;
bp->icount = 0;
bp->gbuf = bp->ebuf;
bp->fid = f;
bp->flag = 0;
bp->rdline = 0;
bp->offset = 0;
bp->runesize = 0;
return 0;
}
int
Binit(Biobuf *bp, int f, int mode)
{
return Binits(bp, f, mode, bp->b, sizeof(bp->b));
}
Biobuf*
Bfdopen(int f, int mode)
{
Biobuf *bp;
bp = malloc(sizeof(Biobuf));
if(bp == 0)
return 0;
Binits(bp, f, mode, bp->b, sizeof(bp->b));
bp->flag = Bmagic;
return bp;
}
Biobuf*
Bopen(char *name, int mode)
{
Biobuf *bp;
int f;
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
default:
fprint(2, "Bopen: unknown mode %d\n", mode);
return 0;
case OREAD:
f = open(name, mode);
if(f < 0)
return 0;
break;
case OWRITE:
f = create(name, mode, 0666);
if(f < 0)
return 0;
}
bp = Bfdopen(f, mode);
if(bp == 0)
close(f);
return bp;
}
int
Bterm(Biobuf *bp)
{
int ret;
deinstall(bp);
ret = Bflush(bp);
if(bp->flag == Bmagic) {
bp->flag = 0;
if(close(bp->fid) < 0)
ret = -1;
free(bp);
}
return ret;
}

25
lib/bio/boffset.c Normal file
View File

@ -0,0 +1,25 @@
#include "lib9.h"
#include <bio.h>
vlong
Boffset(Biobuf *bp)
{
vlong n;
switch(bp->state) {
default:
fprint(2, "Boffset: unknown state %d\n", bp->state);
n = Beof;
break;
case Bracteof:
case Bractive:
n = bp->offset + bp->icount;
break;
case Bwactive:
n = bp->offset + (bp->bsize + bp->ocount);
break;
}
return n;
}

14
lib/bio/bprint.c Normal file
View File

@ -0,0 +1,14 @@
#include "lib9.h"
#include <bio.h>
int
Bprint(Biobuf *bp, char *fmt, ...)
{
int n;
va_list arg;
va_start(arg, fmt);
n = Bvprint(bp, fmt, arg);
va_end(arg);
return n;
}

20
lib/bio/bputc.c Normal file
View File

@ -0,0 +1,20 @@
#include "lib9.h"
#include <bio.h>
int
Bputc(Biobuf *bp, int c)
{
int i;
for(;;) {
i = bp->ocount;
if(i) {
bp->ebuf[i++] = c;
bp->ocount = i;
return 0;
}
if(Bflush(bp) == Beof)
break;
}
return Beof;
}

23
lib/bio/bputrune.c Normal file
View File

@ -0,0 +1,23 @@
#include "lib9.h"
#include <bio.h>
#include <utf.h>
int
Bputrune(Biobuf *bp, long c)
{
Rune rune;
char str[UTFmax];
int n;
rune = c;
if(rune < Runeself) {
Bputc(bp, rune);
return 1;
}
n = runetochar(str, &rune);
if(n == 0)
return Bbad;
if(Bwrite(bp, str, n) != n)
return Beof;
return n;
}

94
lib/bio/brdline.c Normal file
View File

@ -0,0 +1,94 @@
#include "lib9.h"
#include <bio.h>
void*
Brdline(Biobuf *bp, int delim)
{
char *ip, *ep;
int i, j;
i = -bp->icount;
if(i == 0) {
/*
* eof or other error
*/
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
bp->rdline = 0;
bp->gbuf = bp->ebuf;
return 0;
}
}
/*
* first try in remainder of buffer (gbuf doesn't change)
*/
ip = (char*)bp->ebuf - i;
ep = memchr(ip, delim, i);
if(ep) {
j = (ep - ip) + 1;
bp->rdline = j;
bp->icount += j;
return ip;
}
/*
* copy data to beginning of buffer
*/
if(i < bp->bsize)
memmove(bp->bbuf, ip, i);
bp->gbuf = bp->bbuf;
/*
* append to buffer looking for the delim
*/
ip = (char*)bp->bbuf + i;
while(i < bp->bsize) {
j = read(bp->fid, ip, bp->bsize-i);
if(j <= 0) {
/*
* end of file with no delim
*/
memmove(bp->ebuf-i, bp->bbuf, i);
bp->rdline = i;
bp->icount = -i;
bp->gbuf = bp->ebuf-i;
return 0;
}
bp->offset += j;
i += j;
ep = memchr(ip, delim, j);
if(ep) {
/*
* found in new piece
* copy back up and reset everything
*/
ip = (char*)bp->ebuf - i;
if(i < bp->bsize){
memmove(ip, bp->bbuf, i);
bp->gbuf = (unsigned char*)ip;
}
j = (ep - (char*)bp->bbuf) + 1;
bp->rdline = j;
bp->icount = j - i;
return ip;
}
ip += j;
}
/*
* full buffer without finding
*/
bp->rdline = bp->bsize;
bp->icount = -bp->bsize;
bp->gbuf = bp->bbuf;
return 0;
}
int
Blinelen(Biobuf *bp)
{
return bp->rdline;
}

111
lib/bio/brdstr.c Normal file
View File

@ -0,0 +1,111 @@
#include "lib9.h"
#include <bio.h>
static char*
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
{
int n;
n = *np;
p = realloc(p, n+ndata+1);
if(p){
memmove(p+n, data, ndata);
n += ndata;
if(n>0 && nulldelim && p[n-1]==delim)
p[--n] = '\0';
else
p[n] = '\0';
*np = n;
}
return p;
}
char*
Brdstr(Biobuf *bp, int delim, int nulldelim)
{
char *ip, *ep, *p;
int i, j;
i = -bp->icount;
bp->rdline = 0;
if(i == 0) {
/*
* eof or other error
*/
if(bp->state != Bractive) {
if(bp->state == Bracteof)
bp->state = Bractive;
bp->gbuf = bp->ebuf;
return nil;
}
}
/*
* first try in remainder of buffer (gbuf doesn't change)
*/
ip = (char*)bp->ebuf - i;
ep = memchr(ip, delim, i);
if(ep) {
j = (ep - ip) + 1;
bp->icount += j;
return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
}
/*
* copy data to beginning of buffer
*/
if(i < bp->bsize)
memmove(bp->bbuf, ip, i);
bp->gbuf = bp->bbuf;
/*
* append to buffer looking for the delim
*/
p = nil;
for(;;){
ip = (char*)bp->bbuf + i;
while(i < bp->bsize) {
j = read(bp->fid, ip, bp->bsize-i);
if(j <= 0 && i == 0)
return p;
if(j <= 0 && i > 0){
/*
* end of file but no delim. pretend we got a delim
* by making the delim \0 and smashing it with nulldelim.
*/
j = 1;
ep = ip;
delim = '\0';
nulldelim = 1;
*ep = delim; /* there will be room for this */
}else{
bp->offset += j;
ep = memchr(ip, delim, j);
}
i += j;
if(ep) {
/*
* found in new piece
* copy back up and reset everything
*/
ip = (char*)bp->ebuf - i;
if(i < bp->bsize){
memmove(ip, bp->bbuf, i);
bp->gbuf = (unsigned char*)ip;
}
j = (ep - (char*)bp->bbuf) + 1;
bp->icount = j - i;
return badd(p, &bp->rdline, ip, j, delim, nulldelim);
}
ip += j;
}
/*
* full buffer without finding; add to user string and continue
*/
p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
i = 0;
bp->icount = 0;
bp->gbuf = bp->ebuf;
}
}

45
lib/bio/bread.c Normal file
View File

@ -0,0 +1,45 @@
#include "lib9.h"
#include <bio.h>
long
Bread(Biobuf *bp, void *ap, long count)
{
long c;
unsigned char *p;
int i, n, ic;
p = ap;
c = count;
ic = bp->icount;
while(c > 0) {
n = -ic;
if(n > c)
n = c;
if(n == 0) {
if(bp->state != Bractive)
break;
i = read(bp->fid, bp->bbuf, bp->bsize);
if(i <= 0) {
bp->state = Bracteof;
if(i < 0)
bp->state = Binactive;
break;
}
bp->gbuf = bp->bbuf;
bp->offset += i;
if(i < bp->bsize) {
memmove(bp->ebuf-i, bp->bbuf, i);
bp->gbuf = bp->ebuf-i;
}
ic = -i;
continue;
}
memmove(p, bp->ebuf+ic, n);
c -= n;
ic += n;
p += n;
}
bp->icount = ic;
return count-c;
}

60
lib/bio/bseek.c Normal file
View File

@ -0,0 +1,60 @@
#include "lib9.h"
#include <bio.h>
long long
Bseek(Biobuf *bp, long long offset, int base)
{
vlong n, d;
int bufsz;
switch(bp->state) {
default:
fprint(2, "Bseek: unknown state %d\n", bp->state);
return Beof;
case Bracteof:
bp->state = Bractive;
bp->icount = 0;
bp->gbuf = bp->ebuf;
case Bractive:
n = offset;
if(base == 1) {
n += Boffset(bp);
base = 0;
}
/*
* try to seek within buffer
*/
if(base == 0) {
d = n - Boffset(bp);
bufsz = bp->ebuf - bp->gbuf;
if(-bufsz <= d && d <= bufsz){
bp->icount += d;
if(d >= 0) {
if(bp->icount <= 0)
return n;
} else {
if(bp->ebuf - bp->gbuf >= -bp->icount)
return n;
}
}
}
/*
* reset the buffer
*/
n = lseek(bp->fid, n, base);
bp->icount = 0;
bp->gbuf = bp->ebuf;
break;
case Bwactive:
Bflush(bp);
n = seek(bp->fid, offset, base);
break;
}
bp->offset = n;
return n;
}

38
lib/bio/bvprint.c Normal file
View File

@ -0,0 +1,38 @@
#include "lib9.h"
#include <bio.h>
static int
fmtBflush(Fmt *f)
{
Biobuf *bp;
bp = f->farg;
bp->ocount = (char*)f->to - (char*)f->stop;
if(Bflush(bp) < 0)
return 0;
f->stop = bp->ebuf;
f->to = (char*)f->stop + bp->ocount;
f->start = f->to;
return 1;
}
int
Bvprint(Biobuf *bp, char *fmt, va_list arg)
{
int n;
Fmt f;
f.runes = 0;
f.stop = bp->ebuf;
f.start = (char*)f.stop + bp->ocount;
f.to = f.start;
f.flush = fmtBflush;
f.farg = bp;
f.nfmt = 0;
fmtlocaleinit(&f, nil, nil, nil);
n = fmtvprint(&f, fmt, arg);
bp->ocount = (char*)f.to - (char*)f.stop;
if(n == 0)
n = f.nfmt;
return n;
}

38
lib/bio/bwrite.c Normal file
View File

@ -0,0 +1,38 @@
#include "lib9.h"
#include <bio.h>
long
Bwrite(Biobuf *bp, void *ap, long count)
{
long c;
unsigned char *p;
int i, n, oc;
p = ap;
c = count;
oc = bp->ocount;
while(c > 0) {
n = -oc;
if(n > c)
n = c;
if(n == 0) {
if(bp->state != Bwactive)
return Beof;
i = write(bp->fid, bp->bbuf, bp->bsize);
if(i != bp->bsize) {
bp->state = Binactive;
return Beof;
}
bp->offset += i;
oc = -bp->bsize;
continue;
}
memmove(bp->ebuf+oc, p, n);
oc += n;
c -= n;
p += n;
}
bp->ocount = oc;
return count-c;
}

25
lib/bio/lib9.std.h Normal file
View File

@ -0,0 +1,25 @@
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE
#include <utf.h>
#include <fmt.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define OREAD O_RDONLY
#define OWRITE O_WRONLY
#define OCEXEC 0
#define ORCLOSE 0
#define OTRUNC 0
#define nil ((void*)0)
typedef long long vlong;
typedef unsigned long long uvlong;
#define seek(fd, offset, whence) lseek(fd, offset, whence)
#define create(name, mode, perm) creat(name, perm)

47
lib/bio/libbio.sh.build Executable file
View File

@ -0,0 +1,47 @@
#!/bin/sh
git clean -xdf .
cc \
-I ../../include\
-DPLAN9PORT \
-O0 \
-c \
-g -ggdb \
-Wall \
-Wno-parentheses \
-Wno-missing-braces \
-Wno-switch \
-Wno-comment \
-Wno-sign-compare \
-Wno-unknown-pragmas \
-Wno-misleading-indentation \
-Wno-stringop-truncation \
-Wno-stringop-overflow \
-Wno-format-truncation \
-fno-omit-frame-pointer \
-fsigned-char \
-fcommon \
bbuffered.c\
bfildes.c\
bflush.c\
bgetc.c\
bgetrune.c\
bgetd.c\
binit.c\
boffset.c\
bprint.c\
bputc.c\
bputrune.c\
brdline.c\
brdstr.c\
bread.c\
bseek.c\
bvprint.c\
bwrite.c
mkdir -p $JEHANNE/hacking/lib/
ar rcs $JEHANNE/hacking/lib/libbio.a *.o
git clean -xdf .

31
lib/bio/mkfile Normal file
View File

@ -0,0 +1,31 @@
<$PLAN9/src/mkhdr
LIB=libbio.a
OFILES=\
bbuffered.$O\
bfildes.$O\
bflush.$O\
bgetc.$O\
bgetrune.$O\
bgetd.$O\
binit.$O\
boffset.$O\
bprint.$O\
bputc.$O\
bputrune.$O\
brdline.$O\
brdstr.$O\
bread.$O\
bseek.$O\
bvprint.$O\
bwrite.$O\
HFILES=\
$PLAN9/include/bio.h\
<$PLAN9/src/mksyslib
bcat: bcat.$O $PLAN9/lib/$LIB
$LD -o bcat bcat.$O -lbio -l9

18
lib/bio/portdate Normal file
View File

@ -0,0 +1,18 @@
bbuffered.c 2004/1225
bcat.c 2004/1225
bfildes.c 2004/1225
bflush.c 2004/1225
bfmt.c 2004/1225
bgetc.c 2004/1225
bgetd.c 2004/1225
bgetrune.c 2004/1225
binit.c 2004/1225
boffset.c 2004/1225
bprint.c 2004/1225
bputc.c 2004/1225
bputrune.c 2004/1225
brdline.c 2004/1225
brdstr.c 2004/1225
bread.c 2004/1225
bseek.c 2004/1225
bwrite.c 2004/1225

92
lib/lib9/LICENSE Normal file
View File

@ -0,0 +1,92 @@
The files listed below were written from scrach for plan9port
and do not derive from the Plan 9 from Bell Labs distribution.
They are made available under an MIT-style license, using the
same terms as the main distribution.
../../include/u.h
non-Plan 9 code in ../../include/libc.h
_exits.c
_p9dialparse.c
_p9dir.c
_p9translate.c
announce.c
argv0.c
atoi.c
atol.c
atoll.c
await.c
create.c
debugmalloc.c
dial.c
dirfstat.c
dirfwstat.c
dirstat.c
dirwstat.c
dup.c
errstr.c
exec.c
execl.c
exitcode.c
fmtlock2.c
fork.c
get9root.c
getcallerpc-386.c
getcallerpc-arm.c
getcallerpc-power.c
getcallerpc-sun4u.s
getcallerpc-x86_64.c
getenv.c
getnetconn.c
getns.c
getuser.c
getwd.c
jmp.c
lock.c
main.c
malloc.c
malloctag.c
mallocz.c
nan.c
needstack.c
notify.c
open.c
opentemp.c
pin.c
pipe.c
post9p.c
postnote.c
priv.c
qlock.c
readcons.c
rfork.c
searchpath.c
seek.c
sendfd.c
sleep.c
strdup.c
sysfatal.c
sysname.c
time.c
truerand.c
udp.c
unsharp.c
Copyright 2001-2007 Russ Cox. All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

10
lib/lib9/_exits.c Normal file
View File

@ -0,0 +1,10 @@
#include <u.h>
#include <libc.h>
void
_exits(char *s)
{
if(s == 0 || *s == 0)
_exit(0);
_exit(exitcode(s));
}

185
lib/lib9/_p9dialparse.c Normal file
View File

@ -0,0 +1,185 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/un.h>
#include <netinet/in.h>
static char *nets[] = { "tcp", "udp", nil };
#define CLASS(p) ((*(uchar*)(p))>>6)
static struct {
char *net;
char *service;
int port;
} porttbl[] = {
"tcp", "9fs", 564,
"tcp", "whoami", 565,
"tcp", "guard", 566,
"tcp", "ticket", 567,
"tcp", "exportfs", 17007,
"tcp", "rexexec", 17009,
"tcp", "ncpu", 17010,
"tcp", "cpu", 17013,
"tcp", "venti", 17034,
"tcp", "wiki", 17035,
"tcp", "secstore", 5356,
"udp", "dns", 53,
"tcp", "dns", 53,
};
static int
setport(struct sockaddr_storage *ss, int port)
{
switch(ss->ss_family){
case AF_INET:
((struct sockaddr_in*)ss)->sin_port = htons(port);
break;
case AF_INET6:
((struct sockaddr_in6*)ss)->sin6_port = htons(port);
break;
default:
errstr("unknown protocol family %d", ss->ss_family);
return -1;
}
return 0;
}
int
p9dialparse(char *addr, char **pnet, char **punix, void *phost, int *pport)
{
char *net, *host, *port, *e;
int i;
struct servent *se;
struct hostent *he;
struct sockaddr_storage *ss;
struct addrinfo *result;
ss = phost;
memset(ss, 0, sizeof *ss);
*punix = nil;
net = addr;
if((host = strchr(net, '!')) == nil){
werrstr("malformed address");
return -1;
}
*host++ = 0;
if((port = strchr(host, '!')) == nil){
if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){
Unix:
if(strlen(host)+1 > sizeof ((struct sockaddr_un*)ss)->sun_path){
werrstr("unix socket name too long");
return -1;
}
*punix = host;
*pnet = "unix";
ss->ss_family = AF_UNIX;
strcpy(((struct sockaddr_un*)ss)->sun_path, host);
*pport = 0;
return 0;
}
werrstr("malformed address");
return -1;
}
*port++ = 0;
if(*host == 0){
werrstr("malformed address (empty host)");
return -1;
}
if(*port == 0){
werrstr("malformed address (empty port)");
return -1;
}
if(strcmp(net, "unix") == 0)
goto Unix;
if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0 && strcmp(net, "net") != 0){
werrstr("bad network %s!%s!%s", net, host, port);
return -1;
}
/* translate host */
if(strcmp(host, "*") == 0){
ss->ss_family = AF_INET6;
((struct sockaddr_in6*)ss)->sin6_addr = in6addr_any;
}else if((he = gethostbyname(host)) != nil && he->h_addr_list[0] != nil){
ss->ss_family = he->h_addrtype;
switch(ss->ss_family){
case AF_INET:
((struct sockaddr_in*)ss)->sin_addr = *(struct in_addr*) *(he->h_addr_list);
break;
case AF_INET6:
((struct sockaddr_in6*)ss)->sin6_addr = *(struct in6_addr*) *(he->h_addr_list);
break;
default:
errstr("unknown protocol family %d", ss->ss_family);
return -1;
}
}else if(getaddrinfo(host, NULL, NULL, &result) == 0) {
switch (result->ai_family) {
case AF_INET:
memmove((struct sockaddr_in*)ss, result->ai_addr, result->ai_addrlen);
break;
case AF_INET6:
memmove((struct sockaddr_in6*)ss, result->ai_addr, result->ai_addrlen);
break;
default:
errstr("unknown protocol family %d", ss->ss_family);
return -1;
}
}else{
werrstr("unknown host %s", host);
return -1;
}
/* translate network and port; should return list rather than first */
if(strcmp(net, "net") == 0){
for(i=0; nets[i]; i++){
if((se = getservbyname(port, nets[i])) != nil){
*pnet = nets[i];
*pport = ntohs(se->s_port);
return setport(ss, *pport);
}
}
}
for(i=0; i<nelem(porttbl); i++){
if(strcmp(net, "net") == 0 || strcmp(porttbl[i].net, net) == 0)
if(strcmp(porttbl[i].service, port) == 0){
*pnet = porttbl[i].net;
*pport = porttbl[i].port;
return setport(ss, *pport);
}
}
if(strcmp(net, "net") == 0){
werrstr("unknown service net!*!%s", port);
return -1;
}
if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){
werrstr("unknown network %s", net);
return -1;
}
*pnet = net;
i = strtol(port, &e, 0);
if(*e == 0){
*pport = i;
return setport(ss, *pport);
}
if((se = getservbyname(port, net)) != nil){
*pport = ntohs(se->s_port);
return setport(ss, *pport);
}
werrstr("unknown service %s!*!%s", net, port);
return -1;
}

242
lib/lib9/_p9dir.c Normal file
View File

@ -0,0 +1,242 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#if defined(__APPLE__)
#define _HAVESTGEN
#include <sys/disk.h>
static vlong
disksize(int fd, struct stat *st)
{
u64int bc;
u32int bs;
bs = 0;
bc = 0;
ioctl(fd, DKIOCGETBLOCKSIZE, &bs);
ioctl(fd, DKIOCGETBLOCKCOUNT, &bc);
if(bs >0 && bc > 0)
return bc*bs;
return 0;
}
#elif defined(__FreeBSD__)
#define _HAVESTGEN
#include <sys/disk.h>
#include <sys/disklabel.h>
#include <sys/ioctl.h>
static vlong
disksize(int fd, struct stat *st)
{
off_t mediasize;
if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
return mediasize;
return 0;
}
#elif defined(__OpenBSD__)
#define _HAVESTGEN
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/dkio.h>
static vlong
disksize(int fd, struct stat *st)
{
struct disklabel lab;
int n;
if(!S_ISCHR(st->st_mode))
return 0;
if(ioctl(fd, DIOCGDINFO, &lab) < 0)
return 0;
n = minor(st->st_rdev)&7;
if(n >= lab.d_npartitions)
return 0;
return (vlong)lab.d_partitions[n].p_size * lab.d_secsize;
}
#elif defined(__linux__)
#include <linux/hdreg.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#undef major
#define major(dev) ((int)(((dev) >> 8) & 0xff))
static vlong
disksize(int fd, struct stat *st)
{
u64int u64;
long l;
struct hd_geometry geo;
memset(&geo, 0, sizeof geo);
l = 0;
u64 = 0;
#ifdef BLKGETSIZE64
if(ioctl(fd, BLKGETSIZE64, &u64) >= 0)
return u64;
#endif
if(ioctl(fd, BLKGETSIZE, &l) >= 0)
return l*512;
if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
return 0;
}
#else
static vlong
disksize(int fd, struct stat *st)
{
return 0;
}
#endif
int _p9usepwlibrary = 1;
/*
* Caching the last group and passwd looked up is
* a significant win (stupidly enough) on most systems.
* It's not safe for threaded programs, but neither is using
* getpwnam in the first place, so I'm not too worried.
*/
int
_p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
{
char *s;
char tmp[20];
static struct group *g;
static struct passwd *p;
static int gid, uid;
int sz, fd;
fd = -1;
USED(fd);
sz = 0;
if(d)
memset(d, 0, sizeof *d);
/* name */
s = strrchr(name, '/');
if(s)
s++;
if(!s || !*s)
s = name;
if(*s == '/')
s++;
if(*s == 0)
s = "/";
if(d){
if(*str + strlen(s)+1 > estr)
d->name = "oops";
else{
strcpy(*str, s);
d->name = *str;
*str += strlen(*str)+1;
}
}
sz += strlen(s)+1;
/* user */
if(p && st->st_uid == uid && p->pw_uid == uid)
;
else if(_p9usepwlibrary){
p = getpwuid(st->st_uid);
uid = st->st_uid;
}
if(p == nil || st->st_uid != uid || p->pw_uid != uid){
snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
s = tmp;
}else
s = p->pw_name;
sz += strlen(s)+1;
if(d){
if(*str+strlen(s)+1 > estr)
d->uid = "oops";
else{
strcpy(*str, s);
d->uid = *str;
*str += strlen(*str)+1;
}
}
/* group */
if(g && st->st_gid == gid && g->gr_gid == gid)
;
else if(_p9usepwlibrary){
g = getgrgid(st->st_gid);
gid = st->st_gid;
}
if(g == nil || st->st_gid != gid || g->gr_gid != gid){
snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
s = tmp;
}else
s = g->gr_name;
sz += strlen(s)+1;
if(d){
if(*str + strlen(s)+1 > estr)
d->gid = "oops";
else{
strcpy(*str, s);
d->gid = *str;
*str += strlen(*str)+1;
}
}
if(d){
d->type = 'M';
d->muid = "";
d->qid.path = st->st_ino;
/*
* do not include st->st_dev in path, because
* automounters give the same file system different
* st_dev values for successive mounts, causing
* spurious write warnings in acme and sam.
d->qid.path |= (uvlong)st->st_dev<<32;
*/
#ifdef _HAVESTGEN
d->qid.vers = st->st_gen;
#endif
if(d->qid.vers == 0)
d->qid.vers = st->st_mtime + st->st_ctime;
d->mode = st->st_mode&0777;
d->atime = st->st_atime;
d->mtime = st->st_mtime;
d->length = st->st_size;
if(S_ISLNK(lst->st_mode)){ /* yes, lst not st */
d->mode |= DMSYMLINK;
d->length = lst->st_size;
}
else if(S_ISDIR(st->st_mode)){
d->length = 0;
d->mode |= DMDIR;
d->qid.type = QTDIR;
}
else if(S_ISFIFO(st->st_mode))
d->mode |= DMNAMEDPIPE;
else if(S_ISSOCK(st->st_mode))
d->mode |= DMSOCKET;
else if(S_ISBLK(st->st_mode)){
d->mode |= DMDEVICE;
d->qid.path = ('b'<<16)|st->st_rdev;
}
else if(S_ISCHR(st->st_mode)){
d->mode |= DMDEVICE;
d->qid.path = ('c'<<16)|st->st_rdev;
}
/* fetch real size for disks */
if(S_ISBLK(lst->st_mode)){
if((fd = open(name, O_RDONLY)) >= 0){
d->length = disksize(fd, st);
close(fd);
}
}
}
return sz;
}

155
lib/lib9/announce.c Normal file
View File

@ -0,0 +1,155 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <errno.h>
#undef sun
#define sun sockun
int
_p9netfd(char *dir)
{
int fd;
if(strncmp(dir, "/dev/fd/", 8) != 0)
return -1;
fd = strtol(dir+8, &dir, 0);
if(*dir != 0)
return -1;
return fd;
}
static void
putfd(char *dir, int fd)
{
snprint(dir, NETPATHLEN, "/dev/fd/%d", fd);
}
#undef unix
#define unix sockunix
static int
addrlen(struct sockaddr_storage *ss)
{
switch(ss->ss_family){
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_UNIX:
return sizeof(struct sockaddr_un);
}
return 0;
}
int
p9announce(char *addr, char *dir)
{
int proto;
char *buf, *unix;
char *net;
int port, s;
int n;
socklen_t sn;
struct sockaddr_storage ss;
buf = strdup(addr);
if(buf == nil)
return -1;
if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){
free(buf);
return -1;
}
if(strcmp(net, "tcp") == 0)
proto = SOCK_STREAM;
else if(strcmp(net, "udp") == 0)
proto = SOCK_DGRAM;
else if(strcmp(net, "unix") == 0)
goto Unix;
else{
werrstr("can only handle tcp, udp, and unix: not %s", net);
free(buf);
return -1;
}
free(buf);
if((s = socket(ss.ss_family, proto, 0)) < 0)
return -1;
sn = sizeof n;
if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
&& n == SOCK_STREAM){
n = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
}
if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
close(s);
return -1;
}
if(proto == SOCK_STREAM){
listen(s, 8);
putfd(dir, s);
}
return s;
Unix:
if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0)
return -1;
if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
if(errno == EADDRINUSE
&& connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0
&& errno == ECONNREFUSED){
/* dead socket, so remove it */
remove(unix);
close(s);
if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0)
return -1;
if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) >= 0)
goto Success;
}
close(s);
return -1;
}
Success:
listen(s, 8);
putfd(dir, s);
return s;
}
int
p9listen(char *dir, char *newdir)
{
int fd, one;
if((fd = _p9netfd(dir)) < 0){
werrstr("bad 'directory' in listen: %s", dir);
return -1;
}
if((fd = accept(fd, nil, nil)) < 0)
return -1;
one = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
putfd(newdir, fd);
return fd;
}
int
p9accept(int cfd, char *dir)
{
int fd;
if((fd = _p9netfd(dir)) < 0){
werrstr("bad 'directory' in accept");
return -1;
}
/* need to dup because the listen fd will be closed */
return dup(fd);
}

9
lib/lib9/argv0.c Normal file
View File

@ -0,0 +1,9 @@
#include <lib9.h>
char *argv0;
/*
* Mac OS can't deal with files that only declare data.
* ARGBEGIN mentions this function so that this file gets pulled in.
*/
void __fixargv0(void) { }

56
lib/lib9/atexit.c Normal file
View File

@ -0,0 +1,56 @@
#include <u.h>
#include <libc.h>
#define NEXIT 33
static Lock onexlock;
static struct
{
void (*f)(void);
int pid;
}onex[NEXIT];
int
atexit(void (*f)(void))
{
int i;
lock(&onexlock);
for(i=0; i<NEXIT; i++)
if(onex[i].f == 0) {
onex[i].pid = getpid();
onex[i].f = f;
unlock(&onexlock);
return 1;
}
unlock(&onexlock);
return 0;
}
void
atexitdont(void (*f)(void))
{
int i, pid;
pid = getpid();
for(i=0; i<NEXIT; i++)
if(onex[i].f == f && onex[i].pid == pid)
onex[i].f = 0;
}
void
exits(char *s)
{
int i, pid;
void (*f)(void);
pid = getpid();
for(i = NEXIT-1; i >= 0; i--)
if((f = onex[i].f) && pid == onex[i].pid) {
onex[i].f = 0;
(*f)();
}
if(s == 0 || *s == 0)
exit(0);
exit(exitcode(s));
}

58
lib/lib9/atnotify.c Normal file
View File

@ -0,0 +1,58 @@
#include <u.h>
#include <libc.h>
#define NFN 33
static int (*onnot[NFN])(void*, char*);
static Lock onnotlock;
static
void
notifier(void *v, char *s)
{
int i;
for(i=0; i<NFN; i++)
if(onnot[i] && ((*onnot[i])(v, s))){
noted(NCONT);
return;
}
noted(NDFLT);
}
int
atnotify(int (*f)(void*, char*), int in)
{
int i, n, ret;
static int init;
if(!init){
notify(notifier);
init = 1; /* assign = */
}
ret = 0;
lock(&onnotlock);
if(in){
for(i=0; i<NFN; i++)
if(onnot[i] == 0) {
onnot[i] = f;
ret = 1;
break;
}
}else{
n = 0;
for(i=0; i<NFN; i++)
if(onnot[i]){
if(ret==0 && onnot[i]==f){
onnot[i] = 0;
ret = 1;
}else
n++;
}
if(n == 0){
init = 0;
notify(0);
}
}
unlock(&onnotlock);
return ret;
}

8
lib/lib9/atoi.c Normal file
View File

@ -0,0 +1,8 @@
#include <u.h>
#include <libc.h>
int
atoi(char *s)
{
return strtol(s, 0, 0);
}

8
lib/lib9/atol.c Normal file
View File

@ -0,0 +1,8 @@
#include <u.h>
#include <libc.h>
long
atol(char *s)
{
return strtol(s, 0, 0);
}

8
lib/lib9/atoll.c Normal file
View File

@ -0,0 +1,8 @@
#include <u.h>
#include <libc.h>
vlong
atoll(char *s)
{
return strtoll(s, 0, 0);
}

136
lib/lib9/await.c Normal file
View File

@ -0,0 +1,136 @@
#define NOPLAN9DEFINES
#include <u.h>
#include <libc.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifndef WCOREDUMP /* not on Mac OS X Tiger */
#define WCOREDUMP(status) 0
#endif
static struct {
int sig;
char *str;
} tab[] = {
SIGHUP, "hangup",
SIGINT, "interrupt",
SIGQUIT, "quit",
SIGILL, "sys: illegal instruction",
SIGTRAP, "sys: breakpoint",
SIGABRT, "sys: abort",
#ifdef SIGEMT
SIGEMT, "sys: emulate instruction executed",
#endif
SIGFPE, "sys: fp: trap",
SIGKILL, "sys: kill",
SIGBUS, "sys: bus error",
SIGSEGV, "sys: segmentation violation",
SIGALRM, "alarm",
SIGTERM, "kill",
SIGURG, "sys: urgent condition on socket",
SIGSTOP, "sys: stop",
SIGTSTP, "sys: tstp",
SIGCONT, "sys: cont",
SIGCHLD, "sys: child",
SIGTTIN, "sys: ttin",
SIGTTOU, "sys: ttou",
#ifdef SIGIO /* not on Mac OS X Tiger */
SIGIO, "sys: i/o possible on fd",
#endif
SIGXCPU, "sys: cpu time limit exceeded",
SIGXFSZ, "sys: file size limit exceeded",
SIGVTALRM, "sys: virtual time alarm",
SIGPROF, "sys: profiling timer alarm",
#ifdef SIGWINCH /* not on Mac OS X Tiger */
SIGWINCH, "sys: window size change",
#endif
#ifdef SIGINFO
SIGINFO, "sys: status request",
#endif
SIGUSR1, "sys: usr1",
SIGUSR2, "sys: usr2",
SIGPIPE, "sys: write on closed pipe",
};
char*
_p9sigstr(int sig, char *tmp)
{
int i;
for(i=0; i<nelem(tab); i++)
if(tab[i].sig == sig)
return tab[i].str;
if(tmp == nil)
return nil;
sprint(tmp, "sys: signal %d", sig);
return tmp;
}
int
_p9strsig(char *s)
{
int i;
for(i=0; i<nelem(tab); i++)
if(strcmp(s, tab[i].str) == 0)
return tab[i].sig;
return 0;
}
static int
_await(int pid4, char *str, int n, int opt)
{
int pid, status, cd;
struct rusage ru;
char buf[128], tmp[64];
uint64_t u, s;
for(;;){
/* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
if(pid4 == -1)
pid = wait3(&status, opt, &ru);
else
pid = wait4(pid4, &status, opt, &ru);
if(pid <= 0)
return -1;
u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
if(WIFEXITED(status)){
status = WEXITSTATUS(status);
if(status)
snprint(buf, sizeof buf, "%d %lud %lud %lud %d", pid, u, s, u+s, status);
else
snprint(buf, sizeof buf, "%d %lud %lud %lud ''", pid, u, s, u+s, status);
strecpy(str, str+n, buf);
return strlen(str);
}
if(WIFSIGNALED(status)){
cd = WCOREDUMP(status);
snprint(buf, sizeof buf, "%d %lud %lud %lud 'signal: %s%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp), cd ? " (core dumped)" : "");
strecpy(str, str+n, buf);
return strlen(str);
}
}
}
int
await(char *str, int n)
{
return _await(-1, str, n, 0);
}
int
awaitnohang(char *str, int n)
{
return _await(-1, str, n, WNOHANG);
}
int
awaitfor(int pid, char *str, int n)
{
return _await(pid, str, n, 0);
}

26
lib/lib9/cistrcmp.c Normal file
View File

@ -0,0 +1,26 @@
#include <u.h>
#include <libc.h>
int
cistrcmp(char *s1, char *s2)
{
int c1, c2;
while(*s1){
c1 = *(uchar*)s1++;
c2 = *(uchar*)s2++;
if(c1 == c2)
continue;
if(c1 >= 'A' && c1 <= 'Z')
c1 -= 'A' - 'a';
if(c2 >= 'A' && c2 <= 'Z')
c2 -= 'A' - 'a';
if(c1 != c2)
return c1 - c2;
}
return -*s2;
}

28
lib/lib9/cistrncmp.c Normal file
View File

@ -0,0 +1,28 @@
#include <u.h>
#include <libc.h>
int
cistrncmp(char *s1, char *s2, int n)
{
int c1, c2;
while(*s1 && n-- > 0){
c1 = *(uchar*)s1++;
c2 = *(uchar*)s2++;
if(c1 == c2)
continue;
if(c1 >= 'A' && c1 <= 'Z')
c1 -= 'A' - 'a';
if(c2 >= 'A' && c2 <= 'Z')
c2 -= 'A' - 'a';
if(c1 != c2)
return c1 - c2;
}
if(n <= 0)
return 0;
return -*s2;
}

23
lib/lib9/cistrstr.c Normal file
View File

@ -0,0 +1,23 @@
#include <u.h>
#include <libc.h>
char*
cistrstr(char *s, char *sub)
{
int c, csub, n;
csub = *sub;
if(csub == '\0')
return s;
if(csub >= 'A' && csub <= 'Z')
csub -= 'A' - 'a';
sub++;
n = strlen(sub);
for(; c = *s; s++){
if(c >= 'A' && c <= 'Z')
c -= 'A' - 'a';
if(c == csub && cistrncmp(s+1, sub, n) == 0)
return s;
}
return nil;
}

52
lib/lib9/cleanname.c Normal file
View File

@ -0,0 +1,52 @@
#include <u.h>
#include <libc.h>
/*
* In place, rewrite name to compress multiple /, eliminate ., and process ..
*/
#define SEP(x) ((x)=='/' || (x) == 0)
char*
cleanname(char *name)
{
char *p, *q, *dotdot;
int rooted;
rooted = name[0] == '/';
/*
* invariants:
* p points at beginning of path element we're considering.
* q points just past the last path element we wrote (no slash).
* dotdot points just past the point where .. cannot backtrack
* any further (no slash).
*/
p = q = dotdot = name+rooted;
while(*p) {
if(p[0] == '/') /* null element */
p++;
else if(p[0] == '.' && SEP(p[1]))
p += 1; /* don't count the separator in case it is nul */
else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
p += 2;
if(q > dotdot) { /* can backtrack */
while(--q > dotdot && *q != '/')
;
} else if(!rooted) { /* /.. is / but ./../ is .. */
if(q != name)
*q++ = '/';
*q++ = '.';
*q++ = '.';
dotdot = q;
}
} else { /* real path element */
if(q != name+rooted)
*q++ = '/';
while((*q = *p) != '/' && *q != 0)
p++, q++;
}
}
if(q == name) /* empty string is really ``.'' */
*q++ = '.';
*q = '\0';
return name;
}

101
lib/lib9/convD2M.c Normal file
View File

@ -0,0 +1,101 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
uint
sizeD2M(Dir *d)
{
char *sv[5];
int i, ns, nstr, fixlen;
sv[0] = d->name;
sv[1] = d->uid;
sv[2] = d->gid;
sv[3] = d->muid;
fixlen = STATFIXLEN;
nstr = 4;
ns = 0;
for(i = 0; i < nstr; i++)
if(sv[i])
ns += strlen(sv[i]);
return fixlen + ns;
}
uint
convD2M(Dir *d, uchar *buf, uint nbuf)
{
uchar *p, *ebuf;
char *sv[5];
int i, ns, nsv[5], ss, nstr, fixlen;
if(nbuf < BIT16SZ)
return 0;
p = buf;
ebuf = buf + nbuf;
sv[0] = d->name;
sv[1] = d->uid;
sv[2] = d->gid;
sv[3] = d->muid;
fixlen = STATFIXLEN;
nstr = 4;
ns = 0;
for(i = 0; i < nstr; i++){
if(sv[i])
nsv[i] = strlen(sv[i]);
else
nsv[i] = 0;
ns += nsv[i];
}
ss = fixlen + ns;
/* set size befor erroring, so user can know how much is needed */
/* note that length excludes count field itself */
PBIT16(p, ss-BIT16SZ);
p += BIT16SZ;
if(ss > nbuf)
return BIT16SZ;
PBIT16(p, d->type);
p += BIT16SZ;
PBIT32(p, d->dev);
p += BIT32SZ;
PBIT8(p, d->qid.type);
p += BIT8SZ;
PBIT32(p, d->qid.vers);
p += BIT32SZ;
PBIT64(p, d->qid.path);
p += BIT64SZ;
PBIT32(p, d->mode);
p += BIT32SZ;
PBIT32(p, d->atime);
p += BIT32SZ;
PBIT32(p, d->mtime);
p += BIT32SZ;
PBIT64(p, d->length);
p += BIT64SZ;
for(i = 0; i < nstr; i++){
ns = nsv[i];
if(p + ns + BIT16SZ > ebuf)
return 0;
PBIT16(p, ns);
p += BIT16SZ;
if(ns)
memmove(p, sv[i], ns);
p += ns;
}
if(ss != p - buf)
return 0;
return p - buf;
}

98
lib/lib9/convM2D.c Normal file
View File

@ -0,0 +1,98 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
int
statcheck(uchar *buf, uint nbuf)
{
uchar *ebuf;
int i, nstr;
ebuf = buf + nbuf;
if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
return -1;
buf += STATFIXLEN - 4 * BIT16SZ;
nstr = 4;
for(i = 0; i < nstr; i++){
if(buf + BIT16SZ > ebuf)
return -1;
buf += BIT16SZ + GBIT16(buf);
}
if(buf != ebuf)
return -1;
return 0;
}
static char nullstring[] = "";
uint
convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
{
uchar *p, *ebuf;
char *sv[5];
int i, ns, nstr;
if(nbuf < STATFIXLEN)
return 0;
p = buf;
ebuf = buf + nbuf;
p += BIT16SZ; /* ignore size */
d->type = GBIT16(p);
p += BIT16SZ;
d->dev = GBIT32(p);
p += BIT32SZ;
d->qid.type = GBIT8(p);
p += BIT8SZ;
d->qid.vers = GBIT32(p);
p += BIT32SZ;
d->qid.path = GBIT64(p);
p += BIT64SZ;
d->mode = GBIT32(p);
p += BIT32SZ;
d->atime = GBIT32(p);
p += BIT32SZ;
d->mtime = GBIT32(p);
p += BIT32SZ;
d->length = GBIT64(p);
p += BIT64SZ;
nstr = 4;
for(i = 0; i < nstr; i++){
if(p + BIT16SZ > ebuf)
return 0;
ns = GBIT16(p);
p += BIT16SZ;
if(p + ns > ebuf)
return 0;
if(strs){
sv[i] = strs;
memmove(strs, p, ns);
strs += ns;
*strs++ = '\0';
}
p += ns;
}
if(strs){
d->name = sv[0];
d->uid = sv[1];
d->gid = sv[2];
d->muid = sv[3];
d->ext = nullstring;
}else{
d->name = nullstring;
d->uid = nullstring;
d->gid = nullstring;
d->muid = nullstring;
d->ext = nullstring;
}
return p - buf;
}

326
lib/lib9/convM2S.c Normal file
View File

@ -0,0 +1,326 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
static
uchar*
gstring(uchar *p, uchar *ep, char **s)
{
uint n;
if(p+BIT16SZ > ep)
return nil;
n = GBIT16(p);
p += BIT16SZ - 1;
if(p+n+1 > ep)
return nil;
/* move it down, on top of count, to make room for '\0' */
memmove(p, p + 1, n);
p[n] = '\0';
*s = (char*)p;
p += n+1;
return p;
}
static
uchar*
gqid(uchar *p, uchar *ep, Qid *q)
{
if(p+QIDSZ > ep)
return nil;
q->type = GBIT8(p);
p += BIT8SZ;
q->vers = GBIT32(p);
p += BIT32SZ;
q->path = GBIT64(p);
p += BIT64SZ;
return p;
}
/*
* no syntactic checks.
* three causes for error:
* 1. message size field is incorrect
* 2. input buffer too short for its own data (counts too long, etc.)
* 3. too many names or qids
* gqid() and gstring() return nil if they would reach beyond buffer.
* main switch statement checks range and also can fall through
* to test at end of routine.
*/
uint
convM2S(uchar *ap, uint nap, Fcall *f)
{
uchar *p, *ep;
uint i, size;
p = ap;
ep = p + nap;
if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
return 0;
size = GBIT32(p);
p += BIT32SZ;
if(size < BIT32SZ+BIT8SZ+BIT16SZ)
return 0;
f->type = GBIT8(p);
p += BIT8SZ;
f->tag = GBIT16(p);
p += BIT16SZ;
switch(f->type)
{
default:
return 0;
case Tversion:
if(p+BIT32SZ > ep)
return 0;
f->msize = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->version);
break;
case Tflush:
if(p+BIT16SZ > ep)
return 0;
f->oldtag = GBIT16(p);
p += BIT16SZ;
break;
case Tauth:
if(p+BIT32SZ > ep)
return 0;
f->afid = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->uname);
if(p == nil)
break;
p = gstring(p, ep, &f->aname);
if(p == nil)
break;
f->uidnum = NOUID;
break;
case Tattach:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
if(p+BIT32SZ > ep)
return 0;
f->afid = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->uname);
if(p == nil)
break;
p = gstring(p, ep, &f->aname);
if(p == nil)
break;
f->uidnum = NOUID;
break;
case Twalk:
if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->newfid = GBIT32(p);
p += BIT32SZ;
f->nwname = GBIT16(p);
p += BIT16SZ;
if(f->nwname > MAXWELEM)
return 0;
for(i=0; i<f->nwname; i++){
p = gstring(p, ep, &f->wname[i]);
if(p == nil)
break;
}
break;
case Topen:
case Topenfd:
if(p+BIT32SZ+BIT8SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->mode = GBIT8(p);
p += BIT8SZ;
break;
case Tcreate:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->name);
if(p == nil)
break;
if(p+BIT32SZ+BIT8SZ > ep)
return 0;
f->perm = GBIT32(p);
p += BIT32SZ;
f->mode = GBIT8(p);
p += BIT8SZ;
break;
case Tread:
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->offset = GBIT64(p);
p += BIT64SZ;
f->count = GBIT32(p);
p += BIT32SZ;
break;
case Twrite:
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->offset = GBIT64(p);
p += BIT64SZ;
f->count = GBIT32(p);
p += BIT32SZ;
if(p+f->count > ep)
return 0;
f->data = (char*)p;
p += f->count;
break;
case Tclunk:
case Tremove:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
break;
case Tstat:
if(p+BIT32SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
break;
case Twstat:
if(p+BIT32SZ+BIT16SZ > ep)
return 0;
f->fid = GBIT32(p);
p += BIT32SZ;
f->nstat = GBIT16(p);
p += BIT16SZ;
if(p+f->nstat > ep)
return 0;
f->stat = p;
p += f->nstat;
break;
/*
*/
case Rversion:
if(p+BIT32SZ > ep)
return 0;
f->msize = GBIT32(p);
p += BIT32SZ;
p = gstring(p, ep, &f->version);
break;
case Rerror:
p = gstring(p, ep, &f->ename);
f->errornum = 0;
break;
case Rflush:
break;
case Rauth:
p = gqid(p, ep, &f->aqid);
if(p == nil)
break;
break;
case Rattach:
p = gqid(p, ep, &f->qid);
if(p == nil)
break;
break;
case Rwalk:
if(p+BIT16SZ > ep)
return 0;
f->nwqid = GBIT16(p);
p += BIT16SZ;
if(f->nwqid > MAXWELEM)
return 0;
for(i=0; i<f->nwqid; i++){
p = gqid(p, ep, &f->wqid[i]);
if(p == nil)
break;
}
break;
case Ropen:
case Ropenfd:
case Rcreate:
p = gqid(p, ep, &f->qid);
if(p == nil)
break;
if(p+BIT32SZ > ep)
return 0;
f->iounit = GBIT32(p);
p += BIT32SZ;
if(f->type == Ropenfd){
if(p+BIT32SZ > ep)
return 0;
f->unixfd = GBIT32(p);
p += BIT32SZ;
}
break;
case Rread:
if(p+BIT32SZ > ep)
return 0;
f->count = GBIT32(p);
p += BIT32SZ;
if(p+f->count > ep)
return 0;
f->data = (char*)p;
p += f->count;
break;
case Rwrite:
if(p+BIT32SZ > ep)
return 0;
f->count = GBIT32(p);
p += BIT32SZ;
break;
case Rclunk:
case Rremove:
break;
case Rstat:
if(p+BIT16SZ > ep)
return 0;
f->nstat = GBIT16(p);
p += BIT16SZ;
if(p+f->nstat > ep)
return 0;
f->stat = p;
p += f->nstat;
break;
case Rwstat:
break;
}
if(p==nil || p>ep)
return 0;
if(ap+size == p)
return size;
return 0;
}

399
lib/lib9/convS2M.c Normal file
View File

@ -0,0 +1,399 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
static
uchar*
pstring(uchar *p, char *s)
{
uint n;
if(s == nil){
PBIT16(p, 0);
p += BIT16SZ;
return p;
}
n = strlen(s);
PBIT16(p, n);
p += BIT16SZ;
memmove(p, s, n);
p += n;
return p;
}
static
uchar*
pqid(uchar *p, Qid *q)
{
PBIT8(p, q->type);
p += BIT8SZ;
PBIT32(p, q->vers);
p += BIT32SZ;
PBIT64(p, q->path);
p += BIT64SZ;
return p;
}
static
uint
stringsz(char *s)
{
if(s == nil)
return BIT16SZ;
return BIT16SZ+strlen(s);
}
uint
sizeS2M(Fcall *f)
{
uint n;
int i;
n = 0;
n += BIT32SZ; /* size */
n += BIT8SZ; /* type */
n += BIT16SZ; /* tag */
switch(f->type)
{
default:
return 0;
case Tversion:
n += BIT32SZ;
n += stringsz(f->version);
break;
case Tflush:
n += BIT16SZ;
break;
case Tauth:
n += BIT32SZ;
n += stringsz(f->uname);
n += stringsz(f->aname);
break;
case Tattach:
n += BIT32SZ;
n += BIT32SZ;
n += stringsz(f->uname);
n += stringsz(f->aname);
break;
case Twalk:
n += BIT32SZ;
n += BIT32SZ;
n += BIT16SZ;
for(i=0; i<f->nwname; i++)
n += stringsz(f->wname[i]);
break;
case Topen:
case Topenfd:
n += BIT32SZ;
n += BIT8SZ;
break;
case Tcreate:
n += BIT32SZ;
n += stringsz(f->name);
n += BIT32SZ;
n += BIT8SZ;
break;
case Tread:
n += BIT32SZ;
n += BIT64SZ;
n += BIT32SZ;
break;
case Twrite:
n += BIT32SZ;
n += BIT64SZ;
n += BIT32SZ;
n += f->count;
break;
case Tclunk:
case Tremove:
n += BIT32SZ;
break;
case Tstat:
n += BIT32SZ;
break;
case Twstat:
n += BIT32SZ;
n += BIT16SZ;
n += f->nstat;
break;
/*
*/
case Rversion:
n += BIT32SZ;
n += stringsz(f->version);
break;
case Rerror:
n += stringsz(f->ename);
break;
case Rflush:
break;
case Rauth:
n += QIDSZ;
break;
case Rattach:
n += QIDSZ;
break;
case Rwalk:
n += BIT16SZ;
n += f->nwqid*QIDSZ;
break;
case Ropen:
case Rcreate:
n += QIDSZ;
n += BIT32SZ;
break;
case Ropenfd:
n += QIDSZ;
n += BIT32SZ;
n += BIT32SZ;
break;
case Rread:
n += BIT32SZ;
n += f->count;
break;
case Rwrite:
n += BIT32SZ;
break;
case Rclunk:
break;
case Rremove:
break;
case Rstat:
n += BIT16SZ;
n += f->nstat;
break;
case Rwstat:
break;
}
return n;
}
uint
convS2M(Fcall *f, uchar *ap, uint nap)
{
uchar *p;
uint i, size;
size = sizeS2M(f);
if(size == 0)
return 0;
if(size > nap)
return 0;
p = (uchar*)ap;
PBIT32(p, size);
p += BIT32SZ;
PBIT8(p, f->type);
p += BIT8SZ;
PBIT16(p, f->tag);
p += BIT16SZ;
switch(f->type)
{
default:
return 0;
case Tversion:
PBIT32(p, f->msize);
p += BIT32SZ;
p = pstring(p, f->version);
break;
case Tflush:
PBIT16(p, f->oldtag);
p += BIT16SZ;
break;
case Tauth:
PBIT32(p, f->afid);
p += BIT32SZ;
p = pstring(p, f->uname);
p = pstring(p, f->aname);
break;
case Tattach:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT32(p, f->afid);
p += BIT32SZ;
p = pstring(p, f->uname);
p = pstring(p, f->aname);
break;
case Twalk:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT32(p, f->newfid);
p += BIT32SZ;
PBIT16(p, f->nwname);
p += BIT16SZ;
if(f->nwname > MAXWELEM)
return 0;
for(i=0; i<f->nwname; i++)
p = pstring(p, f->wname[i]);
break;
case Topen:
case Topenfd:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT8(p, f->mode);
p += BIT8SZ;
break;
case Tcreate:
PBIT32(p, f->fid);
p += BIT32SZ;
p = pstring(p, f->name);
PBIT32(p, f->perm);
p += BIT32SZ;
PBIT8(p, f->mode);
p += BIT8SZ;
break;
case Tread:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT64(p, f->offset);
p += BIT64SZ;
PBIT32(p, f->count);
p += BIT32SZ;
break;
case Twrite:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT64(p, f->offset);
p += BIT64SZ;
PBIT32(p, f->count);
p += BIT32SZ;
memmove(p, f->data, f->count);
p += f->count;
break;
case Tclunk:
case Tremove:
PBIT32(p, f->fid);
p += BIT32SZ;
break;
case Tstat:
PBIT32(p, f->fid);
p += BIT32SZ;
break;
case Twstat:
PBIT32(p, f->fid);
p += BIT32SZ;
PBIT16(p, f->nstat);
p += BIT16SZ;
memmove(p, f->stat, f->nstat);
p += f->nstat;
break;
/*
*/
case Rversion:
PBIT32(p, f->msize);
p += BIT32SZ;
p = pstring(p, f->version);
break;
case Rerror:
p = pstring(p, f->ename);
break;
case Rflush:
break;
case Rauth:
p = pqid(p, &f->aqid);
break;
case Rattach:
p = pqid(p, &f->qid);
break;
case Rwalk:
PBIT16(p, f->nwqid);
p += BIT16SZ;
if(f->nwqid > MAXWELEM)
return 0;
for(i=0; i<f->nwqid; i++)
p = pqid(p, &f->wqid[i]);
break;
case Ropen:
case Rcreate:
case Ropenfd:
p = pqid(p, &f->qid);
PBIT32(p, f->iounit);
p += BIT32SZ;
if(f->type == Ropenfd){
PBIT32(p, f->unixfd);
p += BIT32SZ;
}
break;
case Rread:
PBIT32(p, f->count);
p += BIT32SZ;
memmove(p, f->data, f->count);
p += f->count;
break;
case Rwrite:
PBIT32(p, f->count);
p += BIT32SZ;
break;
case Rclunk:
break;
case Rremove:
break;
case Rstat:
PBIT16(p, f->nstat);
p += BIT16SZ;
memmove(p, f->stat, f->nstat);
p += f->nstat;
break;
case Rwstat:
break;
}
if(size != p-ap)
return 0;
return size;
}

68
lib/lib9/crypt.c Normal file
View File

@ -0,0 +1,68 @@
/*
* Data Encryption Standard
* D.P.Mitchell 83/06/08.
*
* block_cipher(key, block, decrypting)
*
* these routines use the non-standard 7 byte format
* for DES keys.
*/
#include <u.h>
#include <libc.h>
#include <auth.h>
#include <libsec.h>
/*
* destructively encrypt the buffer, which
* must be at least 8 characters long.
*/
int
encrypt(void *key, void *vbuf, int n)
{
ulong ekey[32];
uchar *buf;
int i, r;
if(n < 8)
return 0;
key_setup(key, ekey);
buf = vbuf;
n--;
r = n % 7;
n /= 7;
for(i = 0; i < n; i++){
block_cipher(ekey, buf, 0);
buf += 7;
}
if(r)
block_cipher(ekey, buf - 7 + r, 0);
return 1;
}
/*
* destructively decrypt the buffer, which
* must be at least 8 characters long.
*/
int
decrypt(void *key, void *vbuf, int n)
{
ulong ekey[128];
uchar *buf;
int i, r;
if(n < 8)
return 0;
key_setup(key, ekey);
buf = vbuf;
n--;
r = n % 7;
n /= 7;
buf += n * 7;
if(r)
block_cipher(ekey, buf - 7 + r, 1);
for(i = 0; i < n; i++){
buf -= 7;
block_cipher(ekey, buf, 1);
}
return 1;
}

180
lib/lib9/ctime.c Normal file
View File

@ -0,0 +1,180 @@
/*
* This routine converts time as follows.
* The epoch is 0000 Jan 1 1970 GMT.
* The argument time is in seconds since then.
* The localtime(t) entry returns a pointer to an array
* containing
*
* seconds (0-59)
* minutes (0-59)
* hours (0-23)
* day of month (1-31)
* month (0-11)
* year-1970
* weekday (0-6, Sun is 0)
* day of the year
* daylight savings flag
*
* The routine gets the daylight savings time from the environment.
*
* asctime(tvec))
* where tvec is produced by localtime
* returns a ptr to a character string
* that has the ascii time in the form
*
* \\
* Thu Jan 01 00:00:00 GMT 1970n0
* 012345678901234567890123456789
* 0 1 2
*
* ctime(t) just calls localtime, then asctime.
*/
#include <u.h>
#include <libc.h>
#include "zoneinfo.h"
static char dmsize[12] =
{
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
#define dysize ctimedysize
static int dysize(int);
static void ct_numb(char*, int);
char*
ctime(long t)
{
return asctime(localtime(t));
}
Tm*
localtime(long tim)
{
Tinfo ti;
Tm *ct;
if (zonelookuptinfo(&ti, tim)!=-1) {
ct = gmtime(tim+ti.tzoff);
strncpy(ct->zone, ti.zone, sizeof ct->zone - 1);
ct->zone[sizeof ct->zone-1] = 0;
ct->tzoff = ti.tzoff;
return ct;
}
return gmtime(tim);
}
Tm*
gmtime(long tim)
{
int d0, d1;
long hms, day;
static Tm xtime;
/*
* break initial number into days
*/
hms = tim % 86400L;
day = tim / 86400L;
if(hms < 0) {
hms += 86400L;
day -= 1;
}
/*
* generate hours:minutes:seconds
*/
xtime.sec = hms % 60;
d1 = hms / 60;
xtime.min = d1 % 60;
d1 /= 60;
xtime.hour = d1;
/*
* day is the day number.
* generate day of the week.
* The addend is 4 mod 7 (1/1/1970 was Thursday)
*/
xtime.wday = (day + 7340036L) % 7;
/*
* year number
*/
if(day >= 0)
for(d1 = 1970; day >= dysize(d1); d1++)
day -= dysize(d1);
else
for (d1 = 1970; day < 0; d1--)
day += dysize(d1-1);
xtime.year = d1-1900;
xtime.yday = d0 = day;
/*
* generate month
*/
if(dysize(d1) == 366)
dmsize[1] = 29;
for(d1 = 0; d0 >= dmsize[d1]; d1++)
d0 -= dmsize[d1];
dmsize[1] = 28;
xtime.mday = d0 + 1;
xtime.mon = d1;
strcpy(xtime.zone, "GMT");
return &xtime;
}
char*
asctime(Tm *t)
{
const char *ncp;
static char cbuf[30];
strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
cbuf[0] = *ncp++;
cbuf[1] = *ncp++;
cbuf[2] = *ncp;
ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
cbuf[4] = *ncp++;
cbuf[5] = *ncp++;
cbuf[6] = *ncp;
ct_numb(cbuf+8, t->mday);
ct_numb(cbuf+11, t->hour+100);
ct_numb(cbuf+14, t->min+100);
ct_numb(cbuf+17, t->sec+100);
ncp = t->zone;
cbuf[20] = *ncp++;
cbuf[21] = *ncp++;
cbuf[22] = *ncp;
if(t->year >= 100) {
cbuf[24] = '2';
cbuf[25] = '0';
}
ct_numb(cbuf+26, t->year+100);
return cbuf;
}
static
int
dysize(int y)
{
if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
return 366;
return 365;
}
static
void
ct_numb(char *cp, int n)
{
cp[0] = ' ';
if(n >= 10)
cp[0] = (n/10)%10 + '0';
cp[1] = n%10 + '0';
}

157
lib/lib9/debugmalloc.c Normal file
View File

@ -0,0 +1,157 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
/*
* The Unix libc routines cannot be trusted to do their own locking.
* Sad but apparently true.
*/
static int mallocpid;
/*
* The Unix mallocs don't do nearly enough error checking
* for my tastes. We'll waste another 24 bytes per guy so that
* we can. This is severely antisocial, since now free and p9free
* are not interchangeable.
*/
int debugmalloc;
#define Overhead (debugmalloc ? (6*sizeof(ulong)) : 0)
#define MallocMagic 0xA110C09
#define ReallocMagic 0xB110C09
#define CallocMagic 0xC110C09
#define FreeMagic 0xF533F533
#define CheckMagic 0
#define END "\x7F\x2E\x55\x23"
static void
whoops(void *v)
{
fprint(2, "bad malloc block %p\n", v);
abort();
}
static void*
mark(void *v, ulong pc, ulong n, ulong magic)
{
ulong *u;
char *p;
if(!debugmalloc)
return v;
if(v == nil)
return nil;
if(magic == FreeMagic || magic == CheckMagic){
u = (ulong*)((char*)v-4*sizeof(ulong));
if(u[0] != MallocMagic && u[0] != ReallocMagic && u[0] != CallocMagic)
whoops(v);
n = u[1];
p = (char*)v+n;
if(memcmp(p, END, 4) != 0)
whoops(v);
if(magic != CheckMagic){
u[0] = FreeMagic;
u[1] = u[2] = u[3] = pc;
if(n > 16){
u[4] = u[5] = u[6] = u[7] = pc;
memset((char*)v+16, 0xFB, n-16);
}
}
return u;
}else{
u = v;
u[0] = magic;
u[1] = n;
u[2] = 0;
u[3] = 0;
if(magic == ReallocMagic)
u[3] = pc;
else
u[2] = pc;
p = (char*)(u+4)+n;
memmove(p, END, 4);
return u+4;
}
}
void
setmalloctag(void *v, ulong t)
{
ulong *u;
if(!debugmalloc)
return;
if(v == nil)
return;
u = mark(v, 0, 0, 0);
u[2] = t;
}
void
setrealloctag(void *v, ulong t)
{
ulong *u;
if(!debugmalloc)
return;
if(v == nil)
return;
u = mark(v, 0, 0, 0);
u[3] = t;
}
void*
p9malloc(ulong n)
{
void *v;
if(n == 0)
n++;
/*fprint(2, "%s %d malloc\n", argv0, getpid()); */
mallocpid = getpid();
v = malloc(n+Overhead);
v = mark(v, getcallerpc(&n), n, MallocMagic);
/*fprint(2, "%s %d donemalloc\n", argv0, getpid()); */
return v;
}
void
p9free(void *v)
{
if(v == nil)
return;
/*fprint(2, "%s %d free\n", argv0, getpid()); */
mallocpid = getpid();
v = mark(v, getcallerpc(&v), 0, FreeMagic);
free(v);
/*fprint(2, "%s %d donefree\n", argv0, getpid()); */
}
void*
p9calloc(ulong a, ulong b)
{
void *v;
/*fprint(2, "%s %d calloc\n", argv0, getpid()); */
mallocpid = getpid();
v = calloc(a*b+Overhead, 1);
v = mark(v, getcallerpc(&a), a*b, CallocMagic);
/*fprint(2, "%s %d donecalloc\n", argv0, getpid()); */
return v;
}
void*
p9realloc(void *v, ulong n)
{
/*fprint(2, "%s %d realloc\n", argv0, getpid()); */
mallocpid = getpid();
v = mark(v, getcallerpc(&v), 0, CheckMagic);
v = realloc(v, n+Overhead);
v = mark(v, getcallerpc(&v), n, ReallocMagic);
/*fprint(2, "%s %d donerealloc\n", argv0, getpid()); */
return v;
}

159
lib/lib9/dial.c Normal file
View File

@ -0,0 +1,159 @@
#include <u.h>
#include <libc.h>
#undef accept
#undef announce
#undef dial
#undef setnetmtpt
#undef hangup
#undef listen
#undef netmkaddr
#undef reject
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <netdb.h>
#undef unix
#define unix xunix
static int
isany(struct sockaddr_storage *ss)
{
switch(ss->ss_family){
case AF_INET:
return (((struct sockaddr_in*)ss)->sin_addr.s_addr == INADDR_ANY);
case AF_INET6:
return (memcmp(((struct sockaddr_in6*)ss)->sin6_addr.s6_addr,
in6addr_any.s6_addr, sizeof (struct in6_addr)) == 0);
}
return 0;
}
static int
addrlen(struct sockaddr_storage *ss)
{
switch(ss->ss_family){
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_UNIX:
return sizeof(struct sockaddr_un);
}
return 0;
}
int
p9dial(char *addr, char *local, char *dummy2, int *dummy3)
{
char *buf;
char *net, *unix;
int port;
int proto;
socklen_t sn;
int n;
struct sockaddr_storage ss, ssl;
int s;
if(dummy2 || dummy3){
werrstr("cannot handle extra arguments in dial");
return -1;
}
buf = strdup(addr);
if(buf == nil)
return -1;
if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){
free(buf);
return -1;
}
if(strcmp(net, "unix") != 0 && isany(&ss)){
werrstr("invalid dial address 0.0.0.0 (aka *)");
free(buf);
return -1;
}
if(strcmp(net, "tcp") == 0)
proto = SOCK_STREAM;
else if(strcmp(net, "udp") == 0)
proto = SOCK_DGRAM;
else if(strcmp(net, "unix") == 0)
goto Unix;
else{
werrstr("can only handle tcp, udp, and unix: not %s", net);
free(buf);
return -1;
}
free(buf);
if((s = socket(ss.ss_family, proto, 0)) < 0)
return -1;
if(local){
buf = strdup(local);
if(buf == nil){
close(s);
return -1;
}
if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){
badlocal:
free(buf);
close(s);
return -1;
}
if(unix){
werrstr("bad local address %s for dial %s", local, addr);
goto badlocal;
}
sn = sizeof n;
if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
&& n == SOCK_STREAM){
n = 1;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
}
if(bind(s, (struct sockaddr*)&ssl, addrlen(&ssl)) < 0)
goto badlocal;
free(buf);
}
n = 1;
setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n);
if(!isany(&ss)){
if(connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
close(s);
return -1;
}
}
if(proto == SOCK_STREAM){
int one = 1;
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
}
return s;
Unix:
if(local){
werrstr("local address not supported on unix network");
free(buf);
return -1;
}
/* Allow regular files in addition to Unix sockets. */
if((s = open(unix, ORDWR)) >= 0){
free(buf);
return s;
}
free(buf);
if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0){
werrstr("socket: %r");
return -1;
}
if(connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
werrstr("connect %s: %r", ((struct sockaddr_un*)&ss)->sun_path);
close(s);
return -1;
}
return s;
}

28
lib/lib9/dirfstat.c Normal file
View File

@ -0,0 +1,28 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include <sys/stat.h>
extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
Dir*
dirfstat(int fd)
{
struct stat st;
int nstr;
Dir *d;
char *str, tmp[100];
if(fstat(fd, &st) < 0)
return nil;
snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
d = mallocz(sizeof(Dir)+nstr, 1);
if(d == nil)
return nil;
str = (char*)&d[1];
_p9dir(&st, &st, tmp, d, &str, str+nstr);
return d;
}

56
lib/lib9/dirfwstat.c Normal file
View File

@ -0,0 +1,56 @@
#define NOPLAN9DEFINES
#include <u.h>
#include <libc.h>
#include <sys/time.h>
#include <sys/stat.h>
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
/* do nothing -- futimes exists and is fine */
#elif defined(__SunOS5_9__)
/* use futimesat */
static int
futimes(int fd, struct timeval *tv)
{
return futimesat(fd, 0, tv);
}
#else
/* provide dummy */
/* rename just in case -- linux provides an unusable one */
#undef futimes
#define futimes myfutimes
static int
futimes(int fd, struct timeval *tv)
{
werrstr("futimes not available");
return -1;
}
#endif
int
dirfwstat(int fd, Dir *dir)
{
int ret;
struct timeval tv[2];
ret = 0;
if(~dir->mode != 0){
if(fchmod(fd, dir->mode) < 0)
ret = -1;
}
if(~dir->mtime != 0){
tv[0].tv_sec = dir->mtime;
tv[0].tv_usec = 0;
tv[1].tv_sec = dir->mtime;
tv[1].tv_usec = 0;
if(futimes(fd, tv) < 0)
ret = -1;
}
if(~dir->length != 0){
if(ftruncate(fd, dir->length) < 0)
ret = -1;
}
return ret;
}

62
lib/lib9/dirmodefmt.c Normal file
View File

@ -0,0 +1,62 @@
#include <u.h>
#include <libc.h>
static char *modes[] =
{
"---",
"--x",
"-w-",
"-wx",
"r--",
"r-x",
"rw-",
"rwx",
};
static void
rwx(long m, char *s)
{
strncpy(s, modes[m], 3);
}
int
dirmodefmt(Fmt *f)
{
static char buf[16];
ulong m;
m = va_arg(f->args, ulong);
if(m & DMDIR)
buf[0]='d';
else if(m & DMAPPEND)
buf[0]='a';
else if(m & DMAUTH)
buf[0]='A';
else if(m & DMDEVICE)
buf[0] = 'D';
else if(m & DMSOCKET)
buf[0] = 'S';
else if(m & DMNAMEDPIPE)
buf[0] = 'P';
else
buf[0]='-';
/*
* It's a little weird to have DMSYMLINK conflict with DMEXCL
* here, but since you can have symlinks to any of the above
* things, this is a better display. Especially since we don't do
* DMEXCL on any of the supported systems.
*/
if(m & DMEXCL)
buf[1]='l';
else if(m & DMSYMLINK)
buf[1] = 'L';
else
buf[1]='-';
rwx((m>>6)&7, buf+2);
rwx((m>>3)&7, buf+5);
rwx((m>>0)&7, buf+8);
buf[11] = 0;
return fmtstrcpy(f, buf);
}

31
lib/lib9/dirstat.c Normal file
View File

@ -0,0 +1,31 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include <sys/stat.h>
extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
Dir*
dirstat(char *file)
{
struct stat lst;
struct stat st;
int nstr;
Dir *d;
char *str;
if(lstat(file, &lst) < 0)
return nil;
st = lst;
if((lst.st_mode&S_IFMT) == S_IFLNK)
stat(file, &st);
nstr = _p9dir(&lst, &st, file, nil, nil, nil);
d = mallocz(sizeof(Dir)+nstr, 1);
if(d == nil)
return nil;
str = (char*)&d[1];
_p9dir(&lst, &st, file, d, &str, str+nstr);
return d;
}

31
lib/lib9/dirwstat.c Normal file
View File

@ -0,0 +1,31 @@
#include <u.h>
#define NOPLAN9DEFINES
#include <libc.h>
#include <sys/time.h>
#include <utime.h>
#include <sys/stat.h>
int
dirwstat(char *file, Dir *dir)
{
int ret;
struct utimbuf ub;
/* BUG handle more */
ret = 0;
if(~dir->mode != 0){
if(chmod(file, dir->mode) < 0)
ret = -1;
}
if(~dir->mtime != 0){
ub.actime = dir->mtime;
ub.modtime = dir->mtime;
if(utime(file, &ub) < 0)
ret = -1;
}
if(~dir->length != 0){
if(truncate(file, dir->length) < 0)
ret = -1;
}
return ret;
}

12
lib/lib9/dup.c Normal file
View File

@ -0,0 +1,12 @@
#include <u.h>
#include <libc.h>
#undef dup
int
p9dup(int old, int new)
{
if(new == -1)
return dup(old);
return dup2(old, new);
}

76
lib/lib9/encodefmt.c Normal file
View File

@ -0,0 +1,76 @@
#include <lib9.h>
int
encodefmt(Fmt *f)
{
char *out;
char *buf, *p;
int len;
int ilen;
int rv;
uchar *b;
char obuf[64]; /* rsc optimization */
b = va_arg(f->args, uchar*);
if(b == 0)
return fmtstrcpy(f, "<nil>");
ilen = f->prec;
f->prec = 0;
if(!(f->flags&FmtPrec) || ilen < 0)
goto error;
f->flags &= ~FmtPrec;
switch(f->r){
case '<':
len = (8*ilen+4)/5 + 3;
break;
case '[':
len = (8*ilen+5)/6 + 4;
break;
case 'H':
len = 2*ilen + 1;
break;
default:
goto error;
}
if(len > sizeof(obuf)){
buf = malloc(len);
if(buf == nil)
goto error;
} else
buf = obuf;
/* convert */
out = buf;
switch(f->r){
case '<':
rv = enc32(out, len, b, ilen);
break;
case '[':
rv = enc64(out, len, b, ilen);
break;
case 'H':
rv = enc16(out, len, b, ilen);
if(rv >= 0 && (f->flags & FmtLong))
for(p = buf; *p; p++)
*p = tolower((uchar)*p);
break;
default:
rv = -1;
break;
}
if(rv < 0)
goto error;
fmtstrcpy(f, buf);
if(buf != obuf)
free(buf);
return 0;
error:
return fmtstrcpy(f, "<encodefmt>");
}

80
lib/lib9/errstr.c Normal file
View File

@ -0,0 +1,80 @@
/*
* We assume there's only one error buffer for the whole system.
* If you use ffork, you need to provide a _syserrstr. Since most
* people will use libthread (which provides a _syserrstr), this is
* okay.
*/
#include <u.h>
#include <errno.h>
#include <string.h>
#include <libc.h>
enum
{
EPLAN9 = 0x19283745
};
char *(*_syserrstr)(void);
static char xsyserr[ERRMAX];
static char*
getsyserr(void)
{
char *s;
s = nil;
if(_syserrstr)
s = (*_syserrstr)();
if(s == nil)
s = xsyserr;
return s;
}
int
errstr(char *err, uint n)
{
char tmp[ERRMAX];
char *syserr;
strecpy(tmp, tmp+ERRMAX, err);
rerrstr(err, n);
syserr = getsyserr();
strecpy(syserr, syserr+ERRMAX, tmp);
errno = EPLAN9;
return 0;
}
void
rerrstr(char *err, uint n)
{
char *syserr;
syserr = getsyserr();
if(errno == EINTR)
strcpy(syserr, "interrupted");
else if(errno != EPLAN9)
strcpy(syserr, strerror(errno));
strecpy(err, err+n, syserr);
}
/* replaces __errfmt in libfmt */
int
__errfmt(Fmt *f)
{
if(errno == EPLAN9)
return fmtstrcpy(f, getsyserr());
return fmtstrcpy(f, strerror(errno));
}
void
werrstr(char *fmt, ...)
{
va_list arg;
char buf[ERRMAX];
va_start(arg, fmt);
vseprint(buf, buf+ERRMAX, fmt, arg);
va_end(arg);
errstr(buf, ERRMAX);
}

9
lib/lib9/exec.c Normal file
View File

@ -0,0 +1,9 @@
#include <u.h>
#include <libc.h>
int
exec(char *prog, char *argv[])
{
/* to mimic plan 9 should be just exec, but execvp is a better fit for unix */
return execvp(prog, argv);
}

28
lib/lib9/execl.c Normal file
View File

@ -0,0 +1,28 @@
#include <u.h>
#include <libc.h>
int
execl(char *prog, ...)
{
int i;
va_list arg;
char **argv;
va_start(arg, prog);
for(i=0; va_arg(arg, char*) != nil; i++)
;
va_end(arg);
argv = malloc((i+1)*sizeof(char*));
if(argv == nil)
return -1;
va_start(arg, prog);
for(i=0; (argv[i] = va_arg(arg, char*)) != nil; i++)
;
va_end(arg);
exec(prog, argv);
free(argv);
return -1;
}

8
lib/lib9/exitcode.c Normal file
View File

@ -0,0 +1,8 @@
#include <u.h>
#include <libc.h>
int
exitcode(char *s)
{
return 1;
}

253
lib/lib9/fcallfmt.c Normal file
View File

@ -0,0 +1,253 @@
#include <u.h>
#include <libc.h>
#include <fcall.h>
static uint dumpsome(char*, char*, char*, long);
static void fdirconv(char*, char*, Dir*);
static char *qidtype(char*, uchar);
#define QIDFMT "(%.16llux %lud %s)"
int
fcallfmt(Fmt *fmt)
{
Fcall *f;
int fid, type, tag, i;
char buf[512], tmp[200];
char *p, *e;
Dir *d;
Qid *q;
e = buf+sizeof(buf);
f = va_arg(fmt->args, Fcall*);
type = f->type;
fid = f->fid;
tag = f->tag;
switch(type){
case Tversion: /* 100 */
seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
break;
case Rversion:
seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
break;
case Tauth: /* 102 */
seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
f->afid, f->uname, f->aname);
break;
case Rauth:
seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
break;
case Tattach: /* 104 */
seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
fid, f->afid, f->uname, f->aname);
break;
case Rattach:
seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
break;
case Rerror: /* 107; 106 (Terror) illegal */
seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
break;
case Tflush: /* 108 */
seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
break;
case Rflush:
seprint(buf, e, "Rflush tag %ud", tag);
break;
case Twalk: /* 110 */
p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
if(f->nwname <= MAXWELEM)
for(i=0; i<f->nwname; i++)
p = seprint(p, e, "%d:%s ", i, f->wname[i]);
break;
case Rwalk:
p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
if(f->nwqid <= MAXWELEM)
for(i=0; i<f->nwqid; i++){
q = &f->wqid[i];
p = seprint(p, e, "%d:" QIDFMT " ", i,
q->path, q->vers, qidtype(tmp, q->type));
}
break;
case Topen: /* 112 */
seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
break;
case Ropen:
seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud", tag,
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
break;
case Topenfd: /* 98 */
seprint(buf, e, "Topenfd tag %ud fid %ud mode %d", tag, fid, f->mode);
break;
case Ropenfd:
seprint(buf, e, "Ropenfd tag %ud qid " QIDFMT " iounit %ud unixfd %d", tag,
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit, f->unixfd);
break;
case Tcreate: /* 114 */
seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode);
break;
case Rcreate:
seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
break;
case Tread: /* 116 */
seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
tag, fid, f->offset, f->count);
break;
case Rread:
p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
dumpsome(p, e, f->data, f->count);
break;
case Twrite: /* 118 */
p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
tag, fid, f->offset, f->count);
dumpsome(p, e, f->data, f->count);
break;
case Rwrite:
seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
break;
case Tclunk: /* 120 */
seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
break;
case Rclunk:
seprint(buf, e, "Rclunk tag %ud", tag);
break;
case Tremove: /* 122 */
seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
break;
case Rremove:
seprint(buf, e, "Rremove tag %ud", tag);
break;
case Tstat: /* 124 */
seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
break;
case Rstat:
p = seprint(buf, e, "Rstat tag %ud ", tag);
if(f->stat == nil || f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
convM2D(f->stat, f->nstat, d, (char*)(d+1));
seprint(p, e, " stat ");
fdirconv(p+6, e, d);
}
break;
case Twstat: /* 126 */
p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
if(f->stat == nil || f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
convM2D(f->stat, f->nstat, d, (char*)(d+1));
seprint(p, e, " stat ");
fdirconv(p+6, e, d);
}
break;
case Rwstat:
seprint(buf, e, "Rwstat tag %ud", tag);
break;
default:
seprint(buf, e, "unknown type %d", type);
}
return fmtstrcpy(fmt, buf);
}
static char*
qidtype(char *s, uchar t)
{
char *p;
p = s;
if(t & QTDIR)
*p++ = 'd';
if(t & QTAPPEND)
*p++ = 'a';
if(t & QTEXCL)
*p++ = 'l';
if(t & QTAUTH)
*p++ = 'A';
*p = '\0';
return s;
}
int
dirfmt(Fmt *fmt)
{
char buf[160];
fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
return fmtstrcpy(fmt, buf);
}
static void
fdirconv(char *buf, char *e, Dir *d)
{
char tmp[16];
seprint(buf, e, "'%s' '%s' '%s' '%s' "
"q " QIDFMT " m %#luo "
"at %ld mt %ld l %lld "
"t %d d %d",
d->name, d->uid, d->gid, d->muid,
d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
d->atime, d->mtime, d->length,
d->type, d->dev);
}
/*
* dump out count (or DUMPL, if count is bigger) bytes from
* buf to ans, as a string if they are all printable,
* else as a series of hex bytes
*/
#define DUMPL 64
static uint
dumpsome(char *ans, char *e, char *buf, long count)
{
int i, printable;
char *p;
if(buf == nil){
seprint(ans, e, "<no data>");
return strlen(ans);
}
printable = 1;
if(count > DUMPL)
count = DUMPL;
for(i=0; i<count && printable; i++)
if((buf[i]!=0 && buf[i]<32) || (uchar)buf[i]>127)
printable = 0;
p = ans;
*p++ = '\'';
if(printable){
if(2*count > e-p-2)
count = (e-p-2)/2;
for(i=0; i<count; i++){
if(buf[i] == 0){
*p++ = '\\';
*p++ = '0';
}else if(buf[i] == '\t'){
*p++ = '\\';
*p++ = 't';
}else if(buf[i] == '\n'){
*p++ = '\\';
*p++ = 'n';
}else
*p++ = buf[i];
}
}else{
if(2*count > e-p-2)
count = (e-p-2)/2;
for(i=0; i<count; i++){
if(i>0 && i%4==0)
*p++ = ' ';
sprint(p, "%2.2ux", (uchar)buf[i]);
p += 2;
}
}
*p++ = '\'';
*p = 0;
assert(p < e);
return p - ans;
}

22
lib/lib9/fmt/LICENSE Normal file
View File

@ -0,0 +1,22 @@
/*
* The authors of this software are Rob Pike and Ken Thompson,
* with contributions from Mike Burrows and Sean Dorward.
*
* Copyright (c) 2002-2006 by Lucent Technologies.
* Portions Copyright (c) 2004 Google Inc.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
* NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
* THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
This is a Unix port of the Plan 9 formatted I/O package.
Please send comments about the packaging to Russ Cox <rsc@swtch.com>.

19
lib/lib9/fmt/README Normal file
View File

@ -0,0 +1,19 @@
/*
* The authors of this software are Rob Pike and Ken Thompson.
* Copyright (c) 2002 by Lucent Technologies.
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
This is a Unix port of the Plan 9 formatted I/O package.
Please send comments about the packaging
to Russ Cox <rsc@post.harvard.edu>.

Some files were not shown because too many files have changed in this diff Show More