commit 3d7e9092a436b707f2160fb869ab68e2a222bc4e from: rsc date: Tue Oct 14 02:35:00 2003 UTC Single-threaded plumber that can run "start" rules. Thanks to Caerwyn Jones. commit - 169aba14a4766b3d15695ef27681d0f1d04f8521 commit + 3d7e9092a436b707f2160fb869ab68e2a222bc4e blob - /dev/null blob + abc56d085b57766e154e8061cdc6fd0f73858317 (mode 644) --- /dev/null +++ include/plumb.h @@ -0,0 +1,48 @@ +#pragma lib "libplumb.a" +#pragma src "/sys/src/libplumb" + +/* + * Message format: + * source application\n + * destination port\n + * working directory\n + * type\n + * attributes\n + * nbytes\n + * n bytes of data + */ + +typedef struct Plumbattr Plumbattr; +typedef struct Plumbmsg Plumbmsg; + +struct Plumbmsg +{ + char *src; + char *dst; + char *wdir; + char *type; + Plumbattr *attr; + int ndata; + char *data; +}; + +struct Plumbattr +{ + char *name; + char *value; + Plumbattr *next; +}; + +int plumbsend(int, Plumbmsg*); +Plumbmsg* plumbrecv(int); +char* plumbpack(Plumbmsg*, int*); +Plumbmsg* plumbunpack(char*, int); +Plumbmsg* plumbunpackpartial(char*, int, int*); +char* plumbpackattr(Plumbattr*); +Plumbattr* plumbunpackattr(char*); +Plumbattr* plumbaddattr(Plumbattr*, Plumbattr*); +Plumbattr* plumbdelattr(Plumbattr*, char*); +void plumbfree(Plumbmsg*); +char* plumblookup(Plumbattr*, char*); +int plumbopen(char*, int); +int eplumb(int, char*); blob - /dev/null blob + df3c8bed7565e93ce43629a55a5cd1166a6e078f (mode 644) --- /dev/null +++ src/cmd/plumb/Makefile @@ -0,0 +1,16 @@ + +CFLAGS=-I../../../include +LDLIBS=-L../../../lib -lplumb -lbio -lregexp9 -lfmt -l9 -lutf +all: plumb plumber + +plumb: plumb.o + cc -o $@ plumb.o $(LDLIBS) + +plumber: match.o rules.o plumber.o + cc -o $@ match.o rules.o plumber.o $(LDLIBS) + +clean: + rm -f *.o + +install: plumb plumber + cp plumb plumber ../../../bin blob - f702a5c514e73a0a8d5fac2e17d0512b07a03c57 blob + 5411bd92a4793484300a147ef031cf9fc5f8ba46 --- src/lib9/Makefile +++ src/lib9/Makefile @@ -7,6 +7,8 @@ OFILES=\ _exits.$O\ argv0.$O\ await.$O\ + cleanname.$O\ + dirstat.$O\ encodefmt.$O\ errstr.$O\ exits.$O\ @@ -16,12 +18,10 @@ OFILES=\ lock.$O\ malloctag.$O\ mallocz.$O\ - netmkaddr.$O\ nrand.$O\ qlock.$O\ readn.$O\ rendez-$(SYSNAME).$O\ - sleep.$O\ strecpy.$O\ sysfatal.$O\ tas-$(OBJTYPE).$O\ blob - /dev/null blob + cfcb4822afed0e47944ab8a7c90b529003a9daed (mode 644) --- /dev/null +++ src/lib9/cleanname.c @@ -0,0 +1,52 @@ +#include +#include + +/* + * 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; +} blob - /dev/null blob + fb9cd0acdc83b7d9cb2ae99e49094eb74c458f98 (mode 644) --- /dev/null +++ src/lib9/dirstat.c @@ -0,0 +1,83 @@ +#include "u.h" +#include "libc.h" +#include +#include +#include +#include + +static void +statconv(Dir *dir, struct stat *s) +{ + struct passwd *p; + struct group *g; + ulong q; + + p = getpwuid(s->st_uid); + if (p) + strncpy(dir->uid, p->pw_name, NAMELEN); + g = getgrgid(s->st_gid); + if (g) + strncpy(dir->gid, g->gr_name, NAMELEN); + q = 0; + if(S_ISDIR(s->st_mode)) + q = CHDIR; + q |= s->st_ino & 0x00FFFFFFUL; + dir->qid.path = q; + dir->qid.vers = s->st_mtime; + dir->mode = (dir->qid.path&CHDIR)|(s->st_mode&0777); + dir->atime = s->st_atime; + dir->mtime = s->st_mtime; + dir->length = s->st_size; + dir->dev = s->st_dev; + dir->type = 'M'; + if(S_ISFIFO(s->st_mode)) + dir->type = '|'; +} + +int +dirfstat(int fd, Dir *d) +{ + struct stat sbuf; + + if(fstat(fd, &sbuf) < 0) + return -1; + statconv(d, &sbuf); + return 0; +} + +static char * +lelem(char *path) +{ + char *pr; + + pr = utfrrune(path, '/'); + if(pr) + pr++; + else + pr = path; + return pr; +} + +int +dirstat(char *f, Dir *d) +{ + struct stat sbuf; + + if(stat(f, &sbuf) < 0) + return -1; + statconv(d, &sbuf); + strncpy(d->name, lelem(f), NAMELEN); + return 0; +} + +int +dirfwstat(int fd, Dir *d) +{ + return -1; +} + +int +dirwstat(char *name, Dir *d) +{ + return -1; +} blob - /dev/null blob + e9d07a6658c8d8e0c914cbecb4c779b97dfc4ce6 (mode 755) --- /dev/null +++ src/libplumb/Makefile @@ -0,0 +1,19 @@ + +LIB=../../lib/libplumb.a +OFILES=\ + mesg.o\ + +HFILES=../../include/plumb.h + +INCLUDES=-I../../include + +CFLAGS += $(INCLUDES) -D_POSIX_SOURCE + +CC=cc + +$(LIB): $(OFILES) + ar r $(LIB) $(OFILES) + +clean: + rm -rf $(TARG) $(OFILES) + blob - /dev/null blob + 36a95d687f882f4cac738da882a22788bde65f01 (mode 755) --- /dev/null +++ src/libplumb/event.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "plumb.h" + +typedef struct EQueue EQueue; + +struct EQueue +{ + int id; + char *buf; + int nbuf; + EQueue *next; +}; + +static EQueue *equeue; +static Lock eqlock; + +static +int +partial(int id, Event *e, uchar *b, int n) +{ + EQueue *eq, *p; + int nmore; + + lock(&eqlock); + for(eq = equeue; eq != nil; eq = eq->next) + if(eq->id == id) + break; + unlock(&eqlock); + if(eq == nil) + return 0; + /* partial message exists for this id */ + eq->buf = realloc(eq->buf, eq->nbuf+n); + if(eq->buf == nil) + drawerror(display, "eplumb: cannot allocate buffer"); + memmove(eq->buf+eq->nbuf, b, n); + eq->nbuf += n; + e->v = plumbunpackpartial((char*)eq->buf, eq->nbuf, &nmore); + if(nmore == 0){ /* no more to read in this message */ + lock(&eqlock); + if(eq == equeue) + equeue = eq->next; + else{ + for(p = equeue; p!=nil && p->next!=eq; p = p->next) + ; + if(p == nil) + drawerror(display, "eplumb: bad event queue"); + p->next = eq->next; + } + unlock(&eqlock); + free(eq->buf); + free(eq); + } + return 1; +} + +static +void +addpartial(int id, char *b, int n) +{ + EQueue *eq; + + eq = malloc(sizeof(EQueue)); + if(eq == nil) + return; + eq->id = id; + eq->nbuf = n; + eq->buf = malloc(n); + if(eq->buf == nil){ + free(eq); + return; + } + memmove(eq->buf, b, n); + lock(&eqlock); + eq->next = equeue; + equeue = eq; + unlock(&eqlock); +} + +static +int +plumbevent(int id, Event *e, uchar *b, int n) +{ + int nmore; + + if(partial(id, e, b, n) == 0){ + /* no partial message already waiting for this id */ + e->v = plumbunpackpartial((char*)b, n, &nmore); + if(nmore > 0) /* incomplete message */ + addpartial(id, (char*)b, n); + } + if(e->v == nil) + return 0; + return id; +} + +int +eplumb(int key, char *port) +{ + int fd; + + fd = plumbopen(port, OREAD|OCEXEC); + if(fd < 0) + return -1; + return estartfn(key, fd, 8192, plumbevent); +} blob - /dev/null blob + 93ab03f68ca7ba83140e658c15736166ddec28c3 (mode 755) --- /dev/null +++ src/libplumb/mesg.c @@ -0,0 +1,403 @@ +#include +#include +#include "plumb.h" + +static char attrbuf[4096]; + +int +plumbopen(char *name, int omode) +{ + int fd, f; + char *s; + char buf[128]; + + if(name[0] == '/') + return open(name, omode); + snprint(buf, sizeof buf, "/mnt/plumb/%s", name); + fd = open(buf, omode); + if(fd >= 0) + return fd; + snprint(buf, sizeof buf, "/mnt/term/mnt/plumb/%s", name); + fd = open(buf, omode); + if(fd >= 0) + return fd; + /* try mounting service */ + s = getenv("plumbsrv"); + if(s == nil) + return -1; + snprint(buf, sizeof buf, "/mnt/plumb/%s", name); + return open(buf, omode); +} + +static int +Strlen(char *s) +{ + if(s == nil) + return 0; + return strlen(s); +} + +static char* +Strcpy(char *s, char *t) +{ + if(t == nil) + return s; + return strcpy(s, t) + strlen(t); +} + +/* quote attribute value, if necessary */ +static char* +quote(char *s) +{ + char *t; + int c; + + if(s == nil){ + attrbuf[0] = '\0'; + return attrbuf; + } + if(strpbrk(s, " '=\t") == nil) + return s; + t = attrbuf; + *t++ = '\''; + while(t < attrbuf+sizeof attrbuf-2){ + c = *s++; + if(c == '\0') + break; + *t++ = c; + if(c == '\'') + *t++ = c; + } + *t++ = '\''; + *t = '\0'; + return attrbuf; +} + +char* +plumbpackattr(Plumbattr *attr) +{ + int n; + Plumbattr *a; + char *s, *t; + + if(attr == nil) + return nil; + n = 0; + for(a=attr; a!=nil; a=a->next) + n += Strlen(a->name) + 1 + Strlen(quote(a->value)) + 1; + s = malloc(n); + if(s == nil) + return nil; + t = s; + *t = '\0'; + for(a=attr; a!=nil; a=a->next){ + if(t != s) + *t++ = ' '; + strcpy(t, a->name); + strcat(t, "="); + strcat(t, quote(a->value)); + t += strlen(t); + } + if(t > s+n) + abort(); + return s; +} + +char* +plumblookup(Plumbattr *attr, char *name) +{ + while(attr){ + if(strcmp(attr->name, name) == 0) + return attr->value; + attr = attr->next; + } + return nil; +} + +char* +plumbpack(Plumbmsg *m, int *np) +{ + int n, ndata; + char *buf, *p, *attr; + + ndata = m->ndata; + if(ndata < 0) + ndata = Strlen(m->data); + attr = plumbpackattr(m->attr); + n = Strlen(m->src)+1 + Strlen(m->dst)+1 + Strlen(m->wdir)+1 + + Strlen(m->type)+1 + Strlen(attr)+1 + 16 + ndata; + buf = malloc(n+1); /* +1 for '\0' */ + if(buf == nil){ + free(attr); + return nil; + } + p = Strcpy(buf, m->src); + *p++ = '\n'; + p = Strcpy(p, m->dst); + *p++ = '\n'; + p = Strcpy(p, m->wdir); + *p++ = '\n'; + p = Strcpy(p, m->type); + *p++ = '\n'; + p = Strcpy(p, attr); + *p++ = '\n'; + p += sprint(p, "%d\n", ndata); + memmove(p, m->data, ndata); + *np = (p-buf)+ndata; + buf[*np] = '\0'; /* null terminate just in case */ + if(*np >= n+1) + abort(); + free(attr); + return buf; +} + +int +plumbsend(int fd, Plumbmsg *m) +{ + char *buf; + int n; + + buf = plumbpack(m, &n); + if(buf == nil) + return -1; + n = write(fd, buf, n); + free(buf); + return n; +} + +static int +plumbline(char **linep, char *buf, int i, int n, int *bad) +{ + int starti; + char *p; + + if(*bad) + return i; + starti = i; + while(isrc); + free(m->dst); + free(m->wdir); + free(m->type); + for(a=m->attr; a!=nil; a=next){ + next = a->next; + free(a->name); + free(a->value); + free(a); + } + free(m->data); + free(m); +} + +Plumbattr* +plumbunpackattr(char *p) +{ + Plumbattr *attr, *prev, *a; + char *q, *v; + int c, quoting; + + attr = prev = nil; + while(*p!='\0' && *p!='\n'){ + while(*p==' ' || *p=='\t') + p++; + if(*p == '\0') + break; + for(q=p; *q!='\0' && *q!='\n' && *q!=' ' && *q!='\t'; q++) + if(*q == '=') + break; + if(*q != '=') + break; /* malformed attribute */ + a = malloc(sizeof(Plumbattr)); + if(a == nil) + break; + a->name = malloc(q-p+1); + if(a->name == nil){ + free(a); + break; + } + memmove(a->name, p, q-p); + a->name[q-p] = '\0'; + /* process quotes in value */ + q++; /* skip '=' */ + v = attrbuf; + quoting = 0; + while(*q!='\0' && *q!='\n'){ + if(v >= attrbuf+sizeof attrbuf) + break; + c = *q++; + if(quoting){ + if(c == '\''){ + if(*q == '\'') + q++; + else{ + quoting = 0; + continue; + } + } + }else{ + if(c==' ' || c=='\t') + break; + if(c == '\''){ + quoting = 1; + continue; + } + } + *v++ = c; + } + a->value = malloc(v-attrbuf+1); + if(a->value == nil){ + free(a->name); + free(a); + break; + } + memmove(a->value, attrbuf, v-attrbuf); + a->value[v-attrbuf] = '\0'; + a->next = nil; + if(prev == nil) + attr = a; + else + prev->next = a; + prev = a; + p = q; + } + return attr; +} + +Plumbattr* +plumbaddattr(Plumbattr *attr, Plumbattr *new) +{ + Plumbattr *l; + + l = attr; + if(l == nil) + return new; + while(l->next != nil) + l = l->next; + l->next = new; + return attr; +} + +Plumbattr* +plumbdelattr(Plumbattr *attr, char *name) +{ + Plumbattr *l, *prev; + + prev = nil; + for(l=attr; l!=nil; l=l->next){ + if(strcmp(name, l->name) == 0) + break; + prev = l; + } + if(l == nil) + return nil; + if(prev) + prev->next = l->next; + else + attr = l->next; + free(l->name); + free(l->value); + free(l); + return attr; +} + +Plumbmsg* +plumbunpackpartial(char *buf, int n, int *morep) +{ + Plumbmsg *m; + int i, bad; + char *ntext, *attr; + + m = malloc(sizeof(Plumbmsg)); + if(m == nil) + return nil; + memset(m, 0, sizeof(Plumbmsg)); + if(morep != nil) + *morep = 0; + bad = 0; + i = plumbline(&m->src, buf, 0, n, &bad); + i = plumbline(&m->dst, buf, i, n, &bad); + i = plumbline(&m->wdir, buf, i, n, &bad); + i = plumbline(&m->type, buf, i, n, &bad); + i = plumbline(&attr, buf, i, n, &bad); + m->attr = plumbunpackattr(attr); + free(attr); + i = plumbline(&ntext, buf, i, n, &bad); + m->ndata = atoi(ntext); + if(m->ndata != n-i){ + bad = 1; + if(morep!=nil && m->ndata>n-i) + *morep = m->ndata - (n-i); + } + free(ntext); + if(!bad){ + m->data = malloc(n-i+1); /* +1 for '\0' */ + if(m->data == nil) + bad = 1; + else{ + memmove(m->data, buf+i, m->ndata); + m->ndata = n-i; + /* null-terminate in case it's text */ + m->data[m->ndata] = '\0'; + } + } + if(bad){ + plumbfree(m); + m = nil; + } + return m; +} + +Plumbmsg* +plumbunpack(char *buf, int n) +{ + return plumbunpackpartial(buf, n, nil); +} + +Plumbmsg* +plumbrecv(int fd) +{ + char *buf; + Plumbmsg *m; + int n, more; + + buf = malloc(8192); + if(buf == nil) + return nil; + n = read(fd, buf, 8192); + m = nil; + if(n > 0){ + m = plumbunpackpartial(buf, n, &more); + if(m==nil && more>0){ + /* we now know how many more bytes to read for complete message */ + buf = realloc(buf, n+more); + if(buf == nil) + return nil; + if(readn(fd, buf+n, more) == more) + m = plumbunpackpartial(buf, n+more, nil); + } + } + free(buf); + return m; +}