new files
This commit is contained in:
parent
72fd2f8819
commit
7c709434ec
9 changed files with 1504 additions and 0 deletions
24
src/cmd/netfiles/COPYING
Normal file
24
src/cmd/netfiles/COPYING
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
Copyright (c) 2005 Russ Cox <rsc@swtch.com>
|
||||
|
||||
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.
|
||||
|
||||
These conditions shall not be whined about.
|
||||
|
||||
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.
|
||||
|
||||
636
src/cmd/netfiles/acme.c
Normal file
636
src/cmd/netfiles/acme.c
Normal file
|
|
@ -0,0 +1,636 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <9pclient.h>
|
||||
#include "acme.h"
|
||||
|
||||
extern int *xxx;
|
||||
static CFsys *acmefs;
|
||||
Win *windows;
|
||||
static Win *last;
|
||||
|
||||
void
|
||||
mountacme(void)
|
||||
{
|
||||
if(acmefs == nil){
|
||||
acmefs = nsmount("acme", nil);
|
||||
if(acmefs == nil)
|
||||
sysfatal("cannot mount acme: %r");
|
||||
}
|
||||
}
|
||||
|
||||
Win*
|
||||
newwin(void)
|
||||
{
|
||||
Win *w;
|
||||
CFid *fid;
|
||||
char buf[100];
|
||||
int id, n;
|
||||
|
||||
mountacme();
|
||||
fid = fsopen(acmefs, "new/ctl", ORDWR);
|
||||
if(fid == nil)
|
||||
sysfatal("open new/ctl: %r");
|
||||
n = fsread(fid, buf, sizeof buf-1);
|
||||
if(n <= 0)
|
||||
sysfatal("read new/ctl: %r");
|
||||
buf[n] = 0;
|
||||
id = atoi(buf);
|
||||
if(id == 0)
|
||||
sysfatal("read new/ctl: malformed message: %s", buf);
|
||||
|
||||
w = emalloc(sizeof *w);
|
||||
w->id = id;
|
||||
w->ctl = fid;
|
||||
w->next = nil;
|
||||
w->prev = last;
|
||||
if(last)
|
||||
last->next = w;
|
||||
else
|
||||
windows = w;
|
||||
last = w;
|
||||
return w;
|
||||
}
|
||||
|
||||
void
|
||||
winclosefiles(Win *w)
|
||||
{
|
||||
if(w->ctl){
|
||||
fsclose(w->ctl);
|
||||
w->ctl = nil;
|
||||
}
|
||||
if(w->body){
|
||||
fsclose(w->body);
|
||||
w->body = nil;
|
||||
}
|
||||
if(w->addr){
|
||||
fsclose(w->addr);
|
||||
w->addr = nil;
|
||||
}
|
||||
if(w->tag){
|
||||
fsclose(w->tag);
|
||||
w->tag = nil;
|
||||
}
|
||||
if(w->event){
|
||||
fsclose(w->event);
|
||||
w->event = nil;
|
||||
}
|
||||
if(w->data){
|
||||
fsclose(w->data);
|
||||
w->data = nil;
|
||||
}
|
||||
if(w->xdata){
|
||||
fsclose(w->xdata);
|
||||
w->xdata = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
winfree(Win *w)
|
||||
{
|
||||
winclosefiles(w);
|
||||
if(w->c){
|
||||
chanfree(w->c);
|
||||
w->c = nil;
|
||||
}
|
||||
if(w->next)
|
||||
w->next->prev = w->prev;
|
||||
else
|
||||
last = w->prev;
|
||||
if(w->prev)
|
||||
w->prev->next = w->next;
|
||||
else
|
||||
windows = w->next;
|
||||
free(w);
|
||||
}
|
||||
|
||||
void
|
||||
windeleteall(void)
|
||||
{
|
||||
Win *w, *next;
|
||||
|
||||
for(w=windows; w; w=next){
|
||||
next = w->next;
|
||||
winctl(w, "delete");
|
||||
}
|
||||
}
|
||||
|
||||
static CFid*
|
||||
wfid(Win *w, char *name)
|
||||
{
|
||||
char buf[100];
|
||||
CFid **fid;
|
||||
|
||||
if(strcmp(name, "ctl") == 0)
|
||||
fid = &w->ctl;
|
||||
else if(strcmp(name, "body") == 0)
|
||||
fid = &w->body;
|
||||
else if(strcmp(name, "addr") == 0)
|
||||
fid = &w->addr;
|
||||
else if(strcmp(name, "tag") == 0)
|
||||
fid = &w->tag;
|
||||
else if(strcmp(name, "event") == 0)
|
||||
fid = &w->event;
|
||||
else if(strcmp(name, "data") == 0)
|
||||
fid = &w->data;
|
||||
else if(strcmp(name, "xdata") == 0)
|
||||
fid = &w->xdata;
|
||||
else{
|
||||
fid = 0;
|
||||
sysfatal("bad window file name %s", name);
|
||||
}
|
||||
|
||||
if(*fid == nil){
|
||||
snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
|
||||
*fid = fsopen(acmefs, buf, ORDWR);
|
||||
if(*fid == nil)
|
||||
sysfatal("open %s: %r", buf);
|
||||
}
|
||||
return *fid;
|
||||
}
|
||||
|
||||
int
|
||||
winopenfd(Win *w, char *name, int mode)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
snprint(buf, sizeof buf, "%d/%s", w->id, name);
|
||||
return fsopenfd(acmefs, buf, mode);
|
||||
}
|
||||
|
||||
int
|
||||
winctl(Win *w, char *fmt, ...)
|
||||
{
|
||||
char *s;
|
||||
va_list arg;
|
||||
CFid *fid;
|
||||
int n;
|
||||
|
||||
va_start(arg, fmt);
|
||||
s = evsmprint(fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
fid = wfid(w, "ctl");
|
||||
n = fspwrite(fid, s, strlen(s), 0);
|
||||
free(s);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
winname(Win *w, char *fmt, ...)
|
||||
{
|
||||
char *s;
|
||||
va_list arg;
|
||||
int n;
|
||||
|
||||
va_start(arg, fmt);
|
||||
s = evsmprint(fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
n = winctl(w, "name %s\n", s);
|
||||
free(s);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
winprint(Win *w, char *name, char *fmt, ...)
|
||||
{
|
||||
char *s;
|
||||
va_list arg;
|
||||
int n;
|
||||
|
||||
va_start(arg, fmt);
|
||||
s = evsmprint(fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
n = fswrite(wfid(w, name), s, strlen(s));
|
||||
free(s);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
winaddr(Win *w, char *fmt, ...)
|
||||
{
|
||||
char *s;
|
||||
va_list arg;
|
||||
int n;
|
||||
|
||||
va_start(arg, fmt);
|
||||
s = evsmprint(fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
n = fswrite(wfid(w, "addr"), s, strlen(s));
|
||||
free(s);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
winreadaddr(Win *w, uint *q1)
|
||||
{
|
||||
char buf[40], *p;
|
||||
uint q0;
|
||||
int n;
|
||||
|
||||
n = fspread(wfid(w, "addr"), buf, sizeof buf-1, 0);
|
||||
if(n <= 0)
|
||||
return -1;
|
||||
buf[n] = 0;
|
||||
q0 = strtoul(buf, &p, 10);
|
||||
if(q1)
|
||||
*q1 = strtoul(p, nil, 10);
|
||||
return q0;
|
||||
}
|
||||
|
||||
int
|
||||
winread(Win *w, char *file, void *a, int n)
|
||||
{
|
||||
return fspread(wfid(w, file), a, n, 0);
|
||||
}
|
||||
|
||||
int
|
||||
winwrite(Win *w, char *file, void *a, int n)
|
||||
{
|
||||
return fswrite(wfid(w, file), a, n);
|
||||
}
|
||||
|
||||
char*
|
||||
fsreadm(CFid *fid)
|
||||
{
|
||||
char *buf;
|
||||
int n, tot, m;
|
||||
|
||||
m = 128;
|
||||
buf = emalloc(m+1);
|
||||
tot = 0;
|
||||
while((n = fspread(fid, buf+tot, m-tot, tot)) > 0){
|
||||
tot += n;
|
||||
if(tot >= m){
|
||||
m += 128;
|
||||
buf = erealloc(buf, m+1);
|
||||
}
|
||||
}
|
||||
if(n < 0){
|
||||
free(buf);
|
||||
return nil;
|
||||
}
|
||||
buf[tot] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
char*
|
||||
winmread(Win *w, char *file)
|
||||
{
|
||||
return fsreadm(wfid(w, file));
|
||||
}
|
||||
|
||||
char*
|
||||
winindex(void)
|
||||
{
|
||||
CFid *fid;
|
||||
char *s;
|
||||
|
||||
mountacme();
|
||||
if((fid = fsopen(acmefs, "index", ORDWR)) == nil)
|
||||
return nil;
|
||||
s = fsreadm(fid);
|
||||
fsclose(fid);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
winseek(Win *w, char *file, int n, int off)
|
||||
{
|
||||
return fsseek(wfid(w, file), n, off);
|
||||
}
|
||||
|
||||
int
|
||||
winwriteevent(Win *w, Event *e)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
snprint(buf, sizeof buf, "%c%c%d %d \n", e->c1, e->c2, e->q0, e->q1);
|
||||
return fswrite(wfid(w, "event"), buf, strlen(buf));
|
||||
}
|
||||
|
||||
int
|
||||
windel(Win *w, int sure)
|
||||
{
|
||||
return winctl(w, sure ? "delete" : "del");
|
||||
}
|
||||
|
||||
int
|
||||
winfd(Win *w, char *name, int mode)
|
||||
{
|
||||
char buf[100];
|
||||
|
||||
snprint(buf, sizeof buf, "acme/%d/%s", w->id, name);
|
||||
return fsopenfd(acmefs, buf, mode);
|
||||
}
|
||||
|
||||
static void
|
||||
error(Win *w, char *msg)
|
||||
{
|
||||
if(msg == nil)
|
||||
longjmp(w->jmp, 1);
|
||||
fprint(2, "%s: win%d: %s\n", argv0, w->id, msg);
|
||||
longjmp(w->jmp, 2);
|
||||
}
|
||||
|
||||
static int
|
||||
getec(Win *w, CFid *efd)
|
||||
{
|
||||
if(w->nbuf <= 0){
|
||||
w->nbuf = fsread(efd, w->buf, sizeof w->buf);
|
||||
if(w->nbuf <= 0)
|
||||
error(w, nil);
|
||||
w->bufp = w->buf;
|
||||
}
|
||||
--w->nbuf;
|
||||
return *w->bufp++;
|
||||
}
|
||||
|
||||
static int
|
||||
geten(Win *w, CFid *efd)
|
||||
{
|
||||
int n, c;
|
||||
|
||||
n = 0;
|
||||
while('0'<=(c=getec(w,efd)) && c<='9')
|
||||
n = n*10+(c-'0');
|
||||
if(c != ' ')
|
||||
error(w, "event number syntax");
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
geter(Win *w, CFid *efd, char *buf, int *nb)
|
||||
{
|
||||
Rune r;
|
||||
int n;
|
||||
|
||||
r = getec(w, efd);
|
||||
buf[0] = r;
|
||||
n = 1;
|
||||
if(r < Runeself)
|
||||
goto Return;
|
||||
while(!fullrune(buf, n))
|
||||
buf[n++] = getec(w, efd);
|
||||
chartorune(&r, buf);
|
||||
Return:
|
||||
*nb = n;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
gete(Win *w, CFid *efd, Event *e)
|
||||
{
|
||||
int i, nb;
|
||||
|
||||
e->c1 = getec(w, efd);
|
||||
e->c2 = getec(w, efd);
|
||||
e->q0 = geten(w, efd);
|
||||
e->q1 = geten(w, efd);
|
||||
e->flag = geten(w, efd);
|
||||
e->nr = geten(w, efd);
|
||||
if(e->nr > EVENTSIZE)
|
||||
error(w, "event string too long");
|
||||
e->nb = 0;
|
||||
for(i=0; i<e->nr; i++){
|
||||
/* e->r[i] = */ geter(w, efd, e->text+e->nb, &nb);
|
||||
e->nb += nb;
|
||||
}
|
||||
/* e->r[e->nr] = 0; */
|
||||
e->text[e->nb] = 0;
|
||||
if(getec(w, efd) != '\n')
|
||||
error(w, "event syntax 2");
|
||||
}
|
||||
|
||||
int
|
||||
winreadevent(Win *w, Event *e)
|
||||
{
|
||||
CFid *efd;
|
||||
int r;
|
||||
|
||||
if((r = setjmp(w->jmp)) != 0){
|
||||
if(r == 1)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
efd = wfid(w, "event");
|
||||
gete(w, efd, e);
|
||||
e->oq0 = e->q0;
|
||||
e->oq1 = e->q1;
|
||||
|
||||
/* expansion */
|
||||
if(e->flag&2){
|
||||
gete(w, efd, &w->e2);
|
||||
if(e->q0==e->q1){
|
||||
w->e2.oq0 = e->q0;
|
||||
w->e2.oq1 = e->q1;
|
||||
w->e2.flag = e->flag;
|
||||
*e = w->e2;
|
||||
}
|
||||
}
|
||||
|
||||
/* chorded argument */
|
||||
if(e->flag&8){
|
||||
gete(w, efd, &w->e3); /* arg */
|
||||
gete(w, efd, &w->e4); /* location */
|
||||
strcpy(e->arg, w->e3.text);
|
||||
strcpy(e->loc, w->e4.text);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
eventfmt(Fmt *fmt)
|
||||
{
|
||||
Event *e;
|
||||
|
||||
e = va_arg(fmt->args, Event*);
|
||||
return fmtprint(fmt, "%c%c %d %d %d %d %q", e->c1, e->c2, e->q0, e->q1, e->flag, e->nr, e->text);
|
||||
}
|
||||
|
||||
void*
|
||||
emalloc(uint n)
|
||||
{
|
||||
void *v;
|
||||
|
||||
v = mallocz(n, 1);
|
||||
if(v == nil)
|
||||
sysfatal("out of memory");
|
||||
return v;
|
||||
}
|
||||
|
||||
void*
|
||||
erealloc(void *v, uint n)
|
||||
{
|
||||
v = realloc(v, n);
|
||||
if(v == nil)
|
||||
sysfatal("out of memory");
|
||||
return v;
|
||||
}
|
||||
|
||||
char*
|
||||
estrdup(char *s)
|
||||
{
|
||||
if(s == nil)
|
||||
return nil;
|
||||
s = strdup(s);
|
||||
if(s == nil)
|
||||
sysfatal("out of memory");
|
||||
return s;
|
||||
}
|
||||
|
||||
char*
|
||||
evsmprint(char *s, va_list v)
|
||||
{
|
||||
s = vsmprint(s, v);
|
||||
if(s == nil)
|
||||
sysfatal("out of memory");
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
pipewinto(Win *w, char *name, int errto, char *cmd, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char *p;
|
||||
int fd[3], pid;
|
||||
|
||||
va_start(arg, cmd);
|
||||
p = evsmprint(cmd, arg);
|
||||
va_end(arg);
|
||||
fd[0] = winfd(w, name, OREAD);
|
||||
fd[1] = dup(errto, -1);
|
||||
fd[2] = dup(errto, -1);
|
||||
pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
|
||||
free(p);
|
||||
return pid;
|
||||
}
|
||||
|
||||
int
|
||||
pipetowin(Win *w, char *name, int errto, char *cmd, ...)
|
||||
{
|
||||
va_list arg;
|
||||
char *p;
|
||||
int fd[3], pid, pfd[2];
|
||||
char buf[1024];
|
||||
int n;
|
||||
|
||||
/*
|
||||
* cannot use winfd here because of buffering caused
|
||||
* by pipe. program might exit before final write to acme
|
||||
* happens. so we might return before the final write.
|
||||
*
|
||||
* to avoid this, we tend the pipe ourselves.
|
||||
*/
|
||||
if(pipe(pfd) < 0)
|
||||
sysfatal("pipe: %r");
|
||||
va_start(arg, cmd);
|
||||
p = evsmprint(cmd, arg);
|
||||
va_end(arg);
|
||||
fd[0] = open("/dev/null", OREAD);
|
||||
fd[1] = pfd[1];
|
||||
if(errto == 0)
|
||||
fd[2] = dup(fd[1], -1);
|
||||
else
|
||||
fd[2] = dup(errto, -1);
|
||||
pid = threadspawnl(fd, "rc", "rc", "-c", p, 0);
|
||||
free(p);
|
||||
while((n = read(pfd[0], buf, sizeof buf)) > 0)
|
||||
winwrite(w, name, buf, n);
|
||||
close(pfd[0]);
|
||||
return pid;
|
||||
}
|
||||
|
||||
char*
|
||||
sysrun(int errto, char *fmt, ...)
|
||||
{
|
||||
static char buf[1024];
|
||||
char *cmd;
|
||||
va_list arg;
|
||||
int n, fd[3], p[2], tot, pid;
|
||||
|
||||
#undef pipe
|
||||
if(pipe(p) < 0)
|
||||
sysfatal("pipe: %r");
|
||||
fd[0] = open("/dev/null", OREAD);
|
||||
fd[1] = p[1];
|
||||
if(errto == 0)
|
||||
fd[2] = dup(fd[1], -1);
|
||||
else
|
||||
fd[2] = dup(errto, -1);
|
||||
|
||||
va_start(arg, fmt);
|
||||
cmd = evsmprint(fmt, arg);
|
||||
va_end(arg);
|
||||
pid = threadspawnl(fd, "rc", "rc", "-c", cmd, 0);
|
||||
|
||||
tot = 0;
|
||||
while((n = read(p[0], buf+tot, sizeof buf-tot)) > 0)
|
||||
tot += n;
|
||||
close(p[0]);
|
||||
twait(pid);
|
||||
if(n < 0)
|
||||
return nil;
|
||||
free(cmd);
|
||||
if(tot == sizeof buf)
|
||||
tot--;
|
||||
buf[tot] = 0;
|
||||
while(tot > 0 && isspace(buf[tot-1]))
|
||||
tot--;
|
||||
buf[tot] = 0;
|
||||
if(tot == 0){
|
||||
werrstr("no output");
|
||||
return nil;
|
||||
}
|
||||
return estrdup(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
eventreader(void *v)
|
||||
{
|
||||
Event e[2];
|
||||
Win *w;
|
||||
int i;
|
||||
|
||||
w = v;
|
||||
i = 0;
|
||||
for(;;){
|
||||
if(winreadevent(w, &e[i]) <= 0)
|
||||
break;
|
||||
sendp(w->c, &e[i]);
|
||||
i = 1-i; /* toggle */
|
||||
}
|
||||
sendp(w->c, nil);
|
||||
threadexits(nil);
|
||||
}
|
||||
|
||||
Channel*
|
||||
wineventchan(Win *w)
|
||||
{
|
||||
if(w->c == nil){
|
||||
w->c = chancreate(sizeof(Event*), 0);
|
||||
threadcreate(eventreader, w, 32*1024);
|
||||
}
|
||||
return w->c;
|
||||
}
|
||||
|
||||
char*
|
||||
wingetname(Win *w)
|
||||
{
|
||||
int n;
|
||||
char *p;
|
||||
|
||||
n = winread(w, "tag", w->name, sizeof w->name-1);
|
||||
if(n <= 0)
|
||||
return nil;
|
||||
w->name[n] = 0;
|
||||
p = strchr(w->name, ' ');
|
||||
if(p)
|
||||
*p = 0;
|
||||
return w->name;
|
||||
}
|
||||
|
||||
82
src/cmd/netfiles/acme.h
Normal file
82
src/cmd/netfiles/acme.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
typedef struct Event Event;
|
||||
typedef struct Win Win;
|
||||
|
||||
#define EVENTSIZE 256
|
||||
struct Event
|
||||
{
|
||||
int c1;
|
||||
int c2;
|
||||
int oq0;
|
||||
int oq1;
|
||||
int q0;
|
||||
int q1;
|
||||
int flag;
|
||||
int nb;
|
||||
int nr;
|
||||
char text[EVENTSIZE*UTFmax+1];
|
||||
char arg[EVENTSIZE*UTFmax+1];
|
||||
char loc[EVENTSIZE*UTFmax+1];
|
||||
};
|
||||
|
||||
struct Win
|
||||
{
|
||||
int id;
|
||||
CFid *ctl;
|
||||
CFid *tag;
|
||||
CFid *body;
|
||||
CFid *addr;
|
||||
CFid *event;
|
||||
CFid *data;
|
||||
CFid *xdata;
|
||||
Channel *c; /* chan(Event) */
|
||||
Win *next;
|
||||
Win *prev;
|
||||
|
||||
/* events */
|
||||
int nbuf;
|
||||
char name[1024];
|
||||
char buf[1024];
|
||||
char *bufp;
|
||||
jmp_buf jmp;
|
||||
Event e2;
|
||||
Event e3;
|
||||
Event e4;
|
||||
};
|
||||
|
||||
Win *newwin(void);
|
||||
|
||||
int eventfmt(Fmt*);
|
||||
int pipewinto(Win *w, char *name, int, char *fmt, ...);
|
||||
int pipetowin(Win *w, char *name, int, char *fmt, ...);
|
||||
char *sysrun(int errto, char*, ...);
|
||||
int winaddr(Win *w, char *fmt, ...);
|
||||
int winctl(Win *w, char *fmt, ...);
|
||||
int windel(Win *w, int sure);
|
||||
int winfd(Win *w, char *name, int);
|
||||
char *winmread(Win *w, char *file);
|
||||
int winname(Win *w, char *fmt, ...);
|
||||
int winprint(Win *w, char *name, char *fmt, ...);
|
||||
int winread(Win *w, char *file, void *a, int n);
|
||||
int winseek(Win *w, char *file, int n, int off);
|
||||
int winreadaddr(Win *w, uint*);
|
||||
int winreadevent(Win *w, Event *e);
|
||||
int winwrite(Win *w, char *file, void *a, int n);
|
||||
int winwriteevent(Win *w, Event *e);
|
||||
int winopenfd(Win *w, char *name, int mode);
|
||||
void windeleteall(void);
|
||||
void winfree(Win *w);
|
||||
void winclosefiles(Win *w);
|
||||
Channel *wineventchan(Win *w);
|
||||
char *winindex(void);
|
||||
void mountacme(void);
|
||||
char *wingetname(Win *w);
|
||||
|
||||
void *erealloc(void*, uint);
|
||||
void *emalloc(uint);
|
||||
char *estrdup(char*);
|
||||
char *evsmprint(char*, va_list);
|
||||
|
||||
int twait(int);
|
||||
void twaitinit(void);
|
||||
|
||||
extern Win *windows;
|
||||
490
src/cmd/netfiles/main.c
Normal file
490
src/cmd/netfiles/main.c
Normal file
|
|
@ -0,0 +1,490 @@
|
|||
/*
|
||||
* Remote file system editing client.
|
||||
* Only talks to acme - external programs do all the hard work.
|
||||
*
|
||||
* If you add a plumbing rule:
|
||||
|
||||
# /n/ paths go to simulator in acme
|
||||
kind is text
|
||||
data matches '[a-zA-Z0-9_\-./]+('$addr')?'
|
||||
data matches '(/n/[a-zA-Z0-9_\-./]+)('$addr')?'
|
||||
plumb to netfileedit
|
||||
plumb client Netfiles
|
||||
|
||||
* then plumbed paths starting with /n/ will find their way here.
|
||||
*
|
||||
* Perhaps on startup should look for windows named /n/ and attach to them?
|
||||
* Or might that be too aggressive?
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <9pclient.h>
|
||||
#include <plumb.h>
|
||||
#include "acme.h"
|
||||
|
||||
char *root = "/n/";
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: Netfiles\n");
|
||||
threadexitsall("usage");
|
||||
}
|
||||
|
||||
extern int chatty9pclient;
|
||||
int debug;
|
||||
#define dprint if(debug)print
|
||||
Win *mkwin(char*);
|
||||
int do3(Win *w, char *arg);
|
||||
|
||||
enum {
|
||||
STACK = 128*1024,
|
||||
};
|
||||
|
||||
enum {
|
||||
Put,
|
||||
Get,
|
||||
Del,
|
||||
Delete,
|
||||
Debug,
|
||||
XXX
|
||||
};
|
||||
|
||||
char *cmds[] = {
|
||||
"Put",
|
||||
"Get",
|
||||
"Del",
|
||||
"Delete",
|
||||
"Debug",
|
||||
nil
|
||||
};
|
||||
|
||||
typedef struct Arg Arg;
|
||||
struct Arg
|
||||
{
|
||||
char *file;
|
||||
char *addr;
|
||||
Channel *c;
|
||||
};
|
||||
|
||||
Arg*
|
||||
arg(char *file, char *addr, Channel *c)
|
||||
{
|
||||
Arg *a;
|
||||
|
||||
a = emalloc(sizeof *a);
|
||||
a->file = estrdup(file);
|
||||
a->addr = estrdup(addr);
|
||||
a->c = c;
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
* return window id of a window named name or name/
|
||||
* assumes name is cleaned.
|
||||
*/
|
||||
int
|
||||
nametowinid(char *name)
|
||||
{
|
||||
char *index, *p, *next;
|
||||
int len, n;
|
||||
|
||||
index = winindex();
|
||||
n = -1;
|
||||
len = strlen(name);
|
||||
for(p=index; p && *p; p=next){
|
||||
if((next = strchr(p, '\n')) != nil)
|
||||
*next = 0;
|
||||
if(strlen(p) <= 5*12)
|
||||
continue;
|
||||
if(memcmp(p+5*12, name, len)!=0)
|
||||
continue;
|
||||
if(p[5*12+len]!=' ' && (p[5*12+len]!='/' || p[5*12+len+1]!=' '))
|
||||
continue;
|
||||
n = atoi(p);
|
||||
break;
|
||||
}
|
||||
free(index);
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* look up window by name
|
||||
*/
|
||||
Win*
|
||||
nametowin(char *name)
|
||||
{
|
||||
int id;
|
||||
Win *w;
|
||||
|
||||
id = nametowinid(name);
|
||||
if(id == -1)
|
||||
return nil;
|
||||
for(w=windows; w; w=w->next)
|
||||
if(w->id == id)
|
||||
return w;
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*
|
||||
* look for s in list
|
||||
*/
|
||||
int
|
||||
lookup(char *s, char **list)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; list[i]; i++)
|
||||
if(strcmp(list[i], s) == 0)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* move to top of file
|
||||
*/
|
||||
void
|
||||
wintop(Win *w)
|
||||
{
|
||||
winaddr(w, "#0");
|
||||
winctl(w, "dot=addr");
|
||||
winctl(w, "show");
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand the click further than acme usually does -- all non-white space is okay.
|
||||
*/
|
||||
char*
|
||||
expandarg(Win *w, Event *e)
|
||||
{
|
||||
if(e->c2 == 'l')
|
||||
return estrdup(e->text);
|
||||
dprint("expand %d %d %d %d\n", e->oq0, e->oq1, e->q0, e->q1);
|
||||
if(e->oq0 == e->oq1 && e->q0 != e->q1)
|
||||
winaddr(w, "#%ud+#1-/[^ \t\\n]*/,#%ud-#1+/[^ \t\\n]*/", e->q0, e->q1);
|
||||
else
|
||||
winaddr(w, "#%ud,#%ud", e->q0, e->q1);
|
||||
return winmread(w, "xdata");
|
||||
}
|
||||
|
||||
/*
|
||||
* handle a plumbing message
|
||||
*/
|
||||
void
|
||||
doplumb(void *vm)
|
||||
{
|
||||
char *addr;
|
||||
Plumbmsg *m;
|
||||
Win *w;
|
||||
|
||||
m = vm;
|
||||
if(m->ndata >= 1024){
|
||||
fprint(2, "insanely long file name (%d bytes) in plumb message (%.32s...)\n",
|
||||
m->ndata, m->data);
|
||||
plumbfree(m);
|
||||
return;
|
||||
}
|
||||
|
||||
addr = plumblookup(m->attr, "addr");
|
||||
w = nametowin(m->data);
|
||||
if(w == nil)
|
||||
w = mkwin(m->data);
|
||||
winaddr(w, "%s", addr);
|
||||
winctl(w, "dot=addr");
|
||||
winctl(w, "show");
|
||||
// windecref(w);
|
||||
plumbfree(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* dispatch messages from the plumber
|
||||
*/
|
||||
void
|
||||
plumbthread(void *v)
|
||||
{
|
||||
CFid *fid;
|
||||
Plumbmsg *m;
|
||||
|
||||
fid = plumbopenfid("netfileedit", OREAD);
|
||||
if(fid == nil){
|
||||
fprint(2, "cannot open plumb/netfileedit: %r\n");
|
||||
return;
|
||||
}
|
||||
while((m = plumbrecvfid(fid)) != nil)
|
||||
threadcreate(doplumb, m, STACK);
|
||||
fsclose(fid);
|
||||
}
|
||||
|
||||
/*
|
||||
* parse /n/system/path
|
||||
*/
|
||||
int
|
||||
parsename(char *name, char **server, char **path)
|
||||
{
|
||||
char *p, *nul;
|
||||
|
||||
cleanname(name);
|
||||
if(strncmp(name, "/n/", 3) != 0 && name[3] == 0)
|
||||
return -1;
|
||||
nul = nil;
|
||||
if((p = strchr(name+3, '/')) == nil)
|
||||
*path = estrdup("/");
|
||||
else{
|
||||
*path = estrdup(p);
|
||||
*p = 0;
|
||||
nul = p;
|
||||
}
|
||||
p = name+3;
|
||||
if(p[0] == 0){
|
||||
free(*path);
|
||||
*server = *path = nil;
|
||||
if(nul)
|
||||
*nul = '/';
|
||||
return -1;
|
||||
}
|
||||
*server = estrdup(p);
|
||||
if(nul)
|
||||
*nul = '/';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* shell out to find the type of a given file
|
||||
*/
|
||||
char*
|
||||
filestat(char *server, char *path)
|
||||
{
|
||||
return sysrun(2, "9 netstat %q %q", server, path);
|
||||
}
|
||||
|
||||
/*
|
||||
* manage a single window
|
||||
*/
|
||||
void
|
||||
filethread(void *v)
|
||||
{
|
||||
char *arg, *name, *p, *server, *path, *type;
|
||||
Arg *a;
|
||||
Channel *c;
|
||||
Event *e;
|
||||
Win *w;
|
||||
|
||||
a = v;
|
||||
threadsetname("file %s", a->file);
|
||||
w = newwin();
|
||||
winname(w, a->file);
|
||||
winprint(w, "tag", "Get Put Look ");
|
||||
c = wineventchan(w);
|
||||
|
||||
goto caseGet;
|
||||
|
||||
while((e=recvp(c)) != nil){
|
||||
if(e->c1!='K')
|
||||
dprint("acme %E\n", e);
|
||||
if(e->c1=='M')
|
||||
switch(e->c2){
|
||||
case 'x':
|
||||
case 'X':
|
||||
switch(lookup(e->text, cmds)){
|
||||
caseGet:
|
||||
case Get:
|
||||
server = nil;
|
||||
path = nil;
|
||||
if(parsename(name=wingetname(w), &server, &path) < 0){
|
||||
fprint(2, "Netfiles: bad name %s\n", name);
|
||||
goto out;
|
||||
}
|
||||
type = filestat(server, path);
|
||||
if(type == nil)
|
||||
type = estrdup("");
|
||||
if(strcmp(type, "file")==0 || strcmp(type, "directory")==0){
|
||||
winaddr(w, ",");
|
||||
winprint(w, "data", "[reading...]");
|
||||
winaddr(w, ",");
|
||||
if(strcmp(type, "file")==0)
|
||||
twait(pipetowin(w, "data", 2, "9 netget %q %q", server, path));
|
||||
else
|
||||
twait(pipetowin(w, "data", 2, "9 netget -d %q %q | winid=%d mc", server, path, w->id));
|
||||
cleanname(name);
|
||||
if(strcmp(type, "directory")==0){
|
||||
p = name+strlen(name);
|
||||
if(p[-1] != '/'){
|
||||
p[0] = '/';
|
||||
p[1] = 0;
|
||||
}
|
||||
}
|
||||
winname(w, name);
|
||||
wintop(w);
|
||||
winctl(w, "clean");
|
||||
if(a && a->addr){
|
||||
winaddr(w, "%s", a->addr);
|
||||
winctl(w, "dot=addr");
|
||||
winctl(w, "show");
|
||||
}
|
||||
}
|
||||
free(type);
|
||||
out:
|
||||
free(server);
|
||||
free(path);
|
||||
if(a){
|
||||
if(a->c){
|
||||
sendp(a->c, w);
|
||||
a->c = nil;
|
||||
}
|
||||
free(a->file);
|
||||
free(a->addr);
|
||||
free(a);
|
||||
a = nil;
|
||||
}
|
||||
break;
|
||||
case Put:
|
||||
server = nil;
|
||||
path = nil;
|
||||
if(parsename(name=wingetname(w), &server, &path) < 0){
|
||||
fprint(2, "Netfiles: bad name %s\n", name);
|
||||
goto out;
|
||||
}
|
||||
if(twait(pipewinto(w, "body", 2, "9 netput %q %q", server, path)) >= 0){
|
||||
cleanname(name);
|
||||
winname(w, name);
|
||||
winctl(w, "clean");
|
||||
}
|
||||
free(server);
|
||||
free(path);
|
||||
break;
|
||||
case Del:
|
||||
winctl(w, "del");
|
||||
break;
|
||||
case Delete:
|
||||
winctl(w, "delete");
|
||||
break;
|
||||
case Debug:
|
||||
debug = !debug;
|
||||
break;
|
||||
default:
|
||||
winwriteevent(w, e);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
arg = expandarg(w, e);
|
||||
if(arg!=nil && do3(w, arg) < 0)
|
||||
winwriteevent(w, e);
|
||||
free(arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
winfree(w);
|
||||
}
|
||||
|
||||
/*
|
||||
* handle a button 3 click
|
||||
*/
|
||||
int
|
||||
do3(Win *w, char *text)
|
||||
{
|
||||
char *addr, *name, *type, *server, *path, *p, *q;
|
||||
static char lastfail[1000];
|
||||
|
||||
if(text[0] == '/')
|
||||
name = estrdup(text);
|
||||
else{
|
||||
p = wingetname(w);
|
||||
q = strrchr(p, '/');
|
||||
*(q+1) = 0;
|
||||
name = emalloc(strlen(p)+1+strlen(text)+1);
|
||||
strcpy(name, p);
|
||||
strcat(name, "/");
|
||||
strcat(name, text);
|
||||
}
|
||||
dprint("do3 %s => %s\n", text, name);
|
||||
if((addr = strchr(name, ':')) != nil)
|
||||
*addr++ = 0;
|
||||
cleanname(name);
|
||||
if(strcmp(name, lastfail) == 0){
|
||||
free(name);
|
||||
return -1;
|
||||
}
|
||||
if(parsename(name, &server, &path) < 0){
|
||||
free(name);
|
||||
return -1;
|
||||
}
|
||||
type = filestat(server, path);
|
||||
free(server);
|
||||
free(path);
|
||||
if(strcmp(type, "file")==0 || strcmp(type, "directory")==0){
|
||||
w = nametowin(name);
|
||||
if(w == nil)
|
||||
w = mkwin(name);
|
||||
winaddr(w, "%s", addr);
|
||||
winctl(w, "dot=addr");
|
||||
winctl(w, "show");
|
||||
free(name);
|
||||
free(type);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* remember last name that didn't exist so that
|
||||
* only the first right-click is slow when searching for text.
|
||||
*/
|
||||
strecpy(lastfail, lastfail+sizeof lastfail, name);
|
||||
free(name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Win*
|
||||
mkwin(char *name)
|
||||
{
|
||||
Arg *a;
|
||||
Channel *c;
|
||||
Win *w;
|
||||
|
||||
c = chancreate(sizeof(void*), 0);
|
||||
a = arg(name, nil, c);
|
||||
threadcreate(filethread, a, STACK);
|
||||
w = recvp(c);
|
||||
chanfree(c);
|
||||
return w;
|
||||
}
|
||||
|
||||
void
|
||||
loopthread(void *v)
|
||||
{
|
||||
QLock lk;
|
||||
|
||||
qlock(&lk);
|
||||
qlock(&lk);
|
||||
}
|
||||
|
||||
void
|
||||
threadmain(int argc, char **argv)
|
||||
{
|
||||
ARGBEGIN{
|
||||
case '9':
|
||||
chatty9pclient = 1;
|
||||
break;
|
||||
case 'D':
|
||||
debug = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
if(argc)
|
||||
usage();
|
||||
|
||||
threadnotify(nil, 0); /* set up correct default handlers */
|
||||
|
||||
fmtinstall('E', eventfmt);
|
||||
doquote = needsrcquote;
|
||||
quotefmtinstall();
|
||||
|
||||
twaitinit();
|
||||
threadcreate(plumbthread, nil, STACK);
|
||||
threadcreate(loopthread, nil, STACK);
|
||||
threadexits(nil);
|
||||
}
|
||||
|
||||
28
src/cmd/netfiles/mkfile
Normal file
28
src/cmd/netfiles/mkfile
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<$PLAN9/src/mkhdr
|
||||
|
||||
TARG=Netfiles
|
||||
|
||||
OFILES=\
|
||||
acme.$O\
|
||||
main.$O\
|
||||
wait.$O\
|
||||
|
||||
HFILES=acme.h
|
||||
|
||||
<$PLAN9/src/mkone
|
||||
|
||||
XTARG=\
|
||||
netget\
|
||||
netput\
|
||||
netstat\
|
||||
|
||||
install:V:
|
||||
for i in $XTARG; do
|
||||
cp $i $BIN
|
||||
done
|
||||
|
||||
push:V:
|
||||
tar cf - mkfile acme.c main.c wait.c acme.h netget netput netstat |
|
||||
gzip >netfiles.tar.gz
|
||||
scp netfiles.tar.gz swtch.com:www/swtch.com
|
||||
|
||||
45
src/cmd/netfiles/netfileget
Executable file
45
src/cmd/netfiles/netfileget
Executable file
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/local/plan9/bin/rc
|
||||
|
||||
f=getfile
|
||||
if(~ $1 -d){
|
||||
f=getdir
|
||||
shift
|
||||
}
|
||||
|
||||
if(! ~ $#* 2){
|
||||
echo 'usage: netget [-d] system path' >[1=2]
|
||||
exit usage
|
||||
}
|
||||
|
||||
ns=`{namespace}
|
||||
if(u test -S $ns/$1)
|
||||
f=$f^9p
|
||||
|
||||
t=/tmp/netget.$pid.$USER
|
||||
fn sigexit { rm -f $t }
|
||||
|
||||
fn getfile {
|
||||
rm -f $t
|
||||
if(! echo get $2 $t | sftp -b - $1 >/dev/null)
|
||||
exit 1
|
||||
cat $t
|
||||
}
|
||||
|
||||
fn getfile9p {
|
||||
if(! 9p read $1/$2)
|
||||
exit 1
|
||||
}
|
||||
|
||||
fn getdir {
|
||||
if(! {echo cd $2; echo ls -l} | sftp -b - $1 | sed '1,2d; s/sftp> //g; /^$/d' >$t)
|
||||
exit 1
|
||||
cat $t | awk '$NF == "." || $NF == ".." { next } {s = $NF; if($0 ~ /^d/) s = s "/"; print s}'
|
||||
}
|
||||
|
||||
fn getdir9p {
|
||||
9p ls -l $1/$2 | awk '{s=$NF; if($0 ~ /^d/) s=s"/"; print s}'
|
||||
}
|
||||
|
||||
$f $1 $2
|
||||
exit 0
|
||||
|
||||
27
src/cmd/netfiles/netfileput
Executable file
27
src/cmd/netfiles/netfileput
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/local/plan9/bin/rc
|
||||
|
||||
if(! ~ $#* 2){
|
||||
echo 'usage: netput system path' >[1=2]
|
||||
exit usage
|
||||
}
|
||||
|
||||
f=putfile
|
||||
ns=`{namespace}
|
||||
if(u test -S $ns/$1)
|
||||
f=$f^9p
|
||||
|
||||
t=/tmp/netget.$pid.$USER
|
||||
fn sigexit { rm -f $t }
|
||||
|
||||
fn putfile{
|
||||
cat >$t
|
||||
if(! echo put $t $2 | sftp -b - $1 >/dev/null)
|
||||
exit 1
|
||||
}
|
||||
fn putfile9p{
|
||||
if(! 9p write $1/$2)
|
||||
exit 1
|
||||
}
|
||||
|
||||
$f $1 $2
|
||||
exit 0
|
||||
52
src/cmd/netfiles/netfilestat
Executable file
52
src/cmd/netfiles/netfilestat
Executable file
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/local/plan9/bin/rc
|
||||
|
||||
if(! ~ $#* 2){
|
||||
echo usage: netisdir system path >[1=2]
|
||||
exit usage
|
||||
}
|
||||
|
||||
f=dostat
|
||||
ns=`{namespace}
|
||||
if(u test -S $ns/$1)
|
||||
f=$f^9p
|
||||
|
||||
t=/tmp/netisdir.$pid.$USER
|
||||
fn sigexit { rm -f $t }
|
||||
|
||||
fn dostat {
|
||||
{
|
||||
echo !echo XXX connected
|
||||
echo cd $2
|
||||
echo !echo XXX directory exists
|
||||
} | sftp -b - $1 >$t >[2=1]
|
||||
if(9 grep -s XXX.directory.exists $t){
|
||||
echo directory
|
||||
exit 0
|
||||
}
|
||||
if(9 grep -s 'is not a directory' $t){
|
||||
echo file
|
||||
exit 0
|
||||
}
|
||||
cat $t | sed 's/sftp> //g; /^$/d; /XXX/d; /^cd /d' >[1=2]
|
||||
if(! 9 grep -s XXX.connected $t){
|
||||
echo connect failed
|
||||
exit 0
|
||||
}
|
||||
echo nonexistent
|
||||
exit 0
|
||||
}
|
||||
|
||||
fn dostat9p {
|
||||
if(! 9p ls -ld $1/$2 >$t >[2]/dev/null){
|
||||
echo nonexistent
|
||||
exit 0
|
||||
}
|
||||
if(9 grep -s '^d' $t){
|
||||
echo directory
|
||||
exit 0
|
||||
}
|
||||
echo file
|
||||
exit 0
|
||||
}
|
||||
|
||||
$f $1 $2
|
||||
120
src/cmd/netfiles/wait.c
Normal file
120
src/cmd/netfiles/wait.c
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <9pclient.h>
|
||||
#include "acme.h"
|
||||
|
||||
extern int debug;
|
||||
|
||||
#define dprint if(debug)print
|
||||
|
||||
typedef struct Waitreq Waitreq;
|
||||
struct Waitreq
|
||||
{
|
||||
int pid;
|
||||
Channel *c;
|
||||
};
|
||||
|
||||
/*
|
||||
* watch the exiting children
|
||||
*/
|
||||
Channel *twaitchan; /* chan(Waitreq) */
|
||||
void
|
||||
waitthread(void *v)
|
||||
{
|
||||
Alt a[3];
|
||||
Waitmsg *w, **wq;
|
||||
Waitreq *rq, r;
|
||||
int i, nrq, nwq;
|
||||
|
||||
threadsetname("waitthread");
|
||||
a[0].c = threadwaitchan();
|
||||
a[0].v = &w;
|
||||
a[0].op = CHANRCV;
|
||||
a[1].c = twaitchan;
|
||||
a[1].v = &r;
|
||||
a[1].op = CHANRCV;
|
||||
a[2].op = CHANEND;
|
||||
|
||||
nrq = 0;
|
||||
nwq = 0;
|
||||
rq = nil;
|
||||
wq = nil;
|
||||
dprint("wait: start\n");
|
||||
for(;;){
|
||||
cont2:;
|
||||
dprint("wait: alt\n");
|
||||
switch(alt(a)){
|
||||
case 0:
|
||||
dprint("wait: pid %d exited\n", w->pid);
|
||||
for(i=0; i<nrq; i++){
|
||||
if(rq[i].pid == w->pid){
|
||||
dprint("wait: match with rq chan %p\n", rq[i].c);
|
||||
sendp(rq[i].c, w);
|
||||
rq[i] = rq[--nrq];
|
||||
goto cont2;
|
||||
}
|
||||
}
|
||||
if(i == nrq){
|
||||
dprint("wait: queueing waitmsg\n");
|
||||
wq = erealloc(wq, (nwq+1)*sizeof(wq[0]));
|
||||
wq[nwq++] = w;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
dprint("wait: req for pid %d chan %p\n", r.pid, r.c);
|
||||
for(i=0; i<nwq; i++){
|
||||
if(w->pid == r.pid){
|
||||
dprint("wait: match with waitmsg\n");
|
||||
sendp(r.c, w);
|
||||
wq[i] = wq[--nwq];
|
||||
goto cont2;
|
||||
}
|
||||
}
|
||||
if(i == nwq){
|
||||
dprint("wait: queueing req\n");
|
||||
rq = erealloc(rq, (nrq+1)*sizeof(rq[0]));
|
||||
rq[nrq] = r;
|
||||
dprint("wait: queueing req pid %d chan %p\n", rq[nrq].pid, rq[nrq].c);
|
||||
nrq++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Waitmsg*
|
||||
twaitfor(int pid)
|
||||
{
|
||||
Waitreq r;
|
||||
Waitmsg *w;
|
||||
|
||||
r.pid = pid;
|
||||
r.c = chancreate(sizeof(Waitmsg*), 1);
|
||||
send(twaitchan, &r);
|
||||
w = recvp(r.c);
|
||||
chanfree(r.c);
|
||||
return w;
|
||||
}
|
||||
|
||||
int
|
||||
twait(int pid)
|
||||
{
|
||||
int x;
|
||||
Waitmsg *w;
|
||||
|
||||
w = twaitfor(pid);
|
||||
x = w->msg[0] != 0 ? -1 : 0;
|
||||
free(w);
|
||||
return x;
|
||||
}
|
||||
|
||||
void
|
||||
twaitinit(void)
|
||||
{
|
||||
threadwaitchan(); /* allocate it before returning */
|
||||
twaitchan = chancreate(sizeof(Waitreq), 10);
|
||||
threadcreate(waitthread, nil, 128*1024);
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue