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