blob: c413af42dd9c06940897d480d5a7a1f8f3d028cc [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include <venti.h>
#include <sunrpc.h>
#include <nfs3.h>
#include <diskfs.h>
uchar *buf;
uint bufsize;
Nfs3Handle cwd, root;
Biobuf bin, bout;
char pwd[1000];
Fsys *fsys;
SunAuthUnix *auth;
VtConn *z;
VtCache *c;
Disk *disk;
char *cmdhelp(int, char**);
char *cmdcd(int, char**);
char *cmdpwd(int, char**);
char *cmdls(int, char**);
char *cmdget(int, char**);
char *cmdblock(int, char**);
char *cmddisk(int, char**);
typedef struct Cmd Cmd;
struct Cmd
{
char *s;
char *(*fn)(int, char**);
char *help;
};
Cmd cmdtab[] =
{
"cd", cmdcd, "cd dir - change directory",
"ls", cmdls, "ls [-d] path... - list file",
"get", cmdget, "get path [lpath] - copy file to local directory",
"pwd", cmdpwd, "pwd - print working directory",
"help", cmdhelp, "help - print usage summaries",
"block", cmdblock, "block path offset - print disk offset of path's byte offset",
"disk", cmddisk, "disk offset count - dump disk contents"
};
char*
ebuf(void)
{
static char buf[ERRMAX];
rerrstr(buf, sizeof buf);
return buf;
}
static char*
estrdup(char *s)
{
char *t;
t = emalloc(strlen(s)+1);
strcpy(t, s);
return t;
}
char*
walk(char *path, Nfs3Handle *ph)
{
char *p, *q;
Nfs3Handle h;
Nfs3Status ok;
path = estrdup(path); /* writable */
if(path[0] == '/')
h = root;
else
h = cwd;
for(p=path; *p; p=q){
q = strchr(p, '/');
if(q == nil)
q = p+strlen(p);
else
*q++ = 0;
if(*p == 0)
continue;
if((ok = fsyslookup(fsys, auth, &h, p, &h)) != Nfs3Ok){
nfs3errstr(ok);
free(path);
return ebuf();
}
}
*ph = h;
free(path);
return nil;
}
char*
cmdhelp(int argc, char **argv)
{
int i;
for(i=0; i<nelem(cmdtab); i++)
print("%s\n", cmdtab[i].help);
return nil;
}
char*
cmdcd(int argc, char **argv)
{
char *err;
Nfs3Attr attr;
Nfs3Status ok;
Nfs3Handle h;
if(argc != 2)
return "usage: cd dir";
if((err = walk(argv[1], &h)) != nil)
return err;
if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){
nfs3errstr(ok);
fprint(2, "%s: %r\n", argv[1]);
return nil;
}
if(attr.type != Nfs3FileDir)
return "not a directory";
if(argv[1][0] == '/')
pwd[0] = 0;
strcat(pwd, "/");
strcat(pwd, argv[1]);
cleanname(pwd);
cwd = h;
print("%s\n", pwd);
return nil;
}
char*
cmdpwd(int argc, char **argv)
{
if(argc != 1)
return "usage: pwd";
print("%s\n", pwd);
return nil;
}
/*
* XXX maybe make a list of these in memory and then print them nicer
*/
void
ls(char *dir, char *elem, Nfs3Attr *attr)
{
char c;
c = ' '; /* use attr->type */
Bprint(&bout, "%s%s%s", dir ? dir : "", dir && elem ? "/" : "", elem ? elem : "");
Bprint(&bout, " %c%luo %1d %4d %4d", c, attr->mode, attr->nlink, attr->uid, attr->gid);
Bprint(&bout, " %11,lld %11,lld %4d.%4d %#11,llux %#11,llux",
attr->size, attr->used, attr->major, attr->minor, attr->fsid, attr->fileid);
Bprint(&bout, "\n");
}
void
lsdir(char *dir, Nfs3Handle *h)
{
uchar *data, *p, *ep;
Nfs3Attr attr;
Nfs3Entry e;
Nfs3Handle eh;
u32int count;
u1int eof;
Nfs3Status ok;
u64int cookie;
cookie = 0;
for(;;){
ok = fsysreaddir(fsys, auth, h, 8192, cookie, &data, &count, &eof);
if(ok != Nfs3Ok){
nfs3errstr(ok);
fprint(2, "ls %s: %r\n", dir);
return;
}
fprint(2, "got %d\n", count);
p = data;
ep = data+count;
while(p<ep){
if(nfs3entryunpack(p, ep, &p, &e) < 0){
fprint(2, "%s: unpacking directory: %r\n", dir);
break;
}
cookie = e.cookie;
if((ok = fsyslookup(fsys, auth, h, e.name, &eh)) != Nfs3Ok){
nfs3errstr(ok);
fprint(2, "%s/%s: %r\n", dir, e.name);
continue;
}
if((ok = fsysgetattr(fsys, auth, &eh, &attr)) != Nfs3Ok){
nfs3errstr(ok);
fprint(2, "%s/%s: %r\n", dir, e.name);
continue;
}
ls(dir, e.name, &attr);
}
free(data);
if(eof)
break;
}
}
char*
cmdls(int argc, char **argv)
{
int i;
int dflag;
char *e;
Nfs3Handle h;
Nfs3Attr attr;
Nfs3Status ok;
dflag = 0;
ARGBEGIN{
case 'd':
dflag = 1;
break;
default:
return "usage: ls [-d] [path...]";
}ARGEND
if(argc == 0){
lsdir(nil, &cwd);
Bflush(&bout);
return nil;
}
for(i=0; i<argc; i++){
if((e = walk(argv[i], &h)) != nil){
fprint(2, "%s: %s\n", argv[i], e);
continue;
}
if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){
nfs3errstr(ok);
fprint(2, "%s: %r\n", argv[i]);
continue;
}
if(attr.type != Nfs3FileDir || dflag)
ls(argv[i], nil, &attr);
else
lsdir(argv[i], &h);
Bflush(&bout);
}
return nil;
}
char*
cmdget(int argc, char **argv)
{
uchar eof;
u32int n;
int dflag, fd;
char *e, *local;
uchar *buf;
Nfs3Handle h;
Nfs3Attr attr;
Nfs3Status ok;
vlong o;
dflag = 0;
ARGBEGIN{
default:
usage:
return "usage: get path [lpath]]";
}ARGEND
if(argc != 1 && argc != 2)
goto usage;
if((e = walk(argv[0], &h)) != nil){
fprint(2, "%s: %s\n", argv[0], e);
return nil;
}
if((ok = fsysgetattr(fsys, auth, &h, &attr)) != Nfs3Ok){
nfs3errstr(ok);
fprint(2, "%s: %r\n", argv[0]);
return nil;
}
local = argv[0];
if(argc == 2)
local = argv[1];
if((fd = create(local, OWRITE, 0666)) < 0){
fprint(2, "create %s: %r\n", local);
return nil;
}
eof = 0;
for(o=0; o<attr.size && !eof; o+=n){
if((ok = fsysreadfile(fsys, nil, &h, fsys->blocksize, o, &buf, &n, &eof)) != Nfs3Ok){
nfs3errstr(ok);
fprint(2, "reading %s: %r\n", argv[0]);
close(fd);
return nil;
}
if(write(fd, buf, n) != n){
fprint(2, "writing %s: %r\n", local);
close(fd);
free(buf);
return nil;
}
free(buf);
}
close(fd);
fprint(2, "copied %,lld bytes\n", o);
return nil;
}
char*
cmdblock(int argc, char **argv)
{
char *e;
Nfs3Handle h;
u64int bno;
ARGBEGIN{
default:
return "usage: block path offset";
}ARGEND
if(argc != 2)
return "usage: block path offset";
if((e = walk(argv[0], &h)) != nil){
fprint(2, "%s: %s\n", argv[0], e);
return nil;
}
if((bno = fsys->fileblock(fsys, &h, strtoll(argv[1], 0, 0))) == 0){
fprint(2, "%s: %r\n", argv[0]);
return nil;
}
print("%#llux\n", bno);
return nil;
}
char*
cmddisk(int argc, char **argv)
{
Block *b;
int delta, count, i;
u64int offset;
uchar *p;
ARGBEGIN{
default:
return "usage: disk offset count";
}ARGEND
if(argc != 2)
return "usage: disk offset count";
offset = strtoull(argv[0], 0, 0);
count = atoi(argv[1]);
delta = offset%fsys->blocksize;
b = diskread(disk, fsys->blocksize, offset-delta);
if(b == nil){
fprint(2, "diskread: %r\n");
return nil;
}
p = b->data + delta;
for(i=0; i<count; i++){
Bprint(&bout, "%2.2ux ", p[i]);
if(i%16 == 15)
Bprint(&bout, "\n");
else if(i%8 == 7)
Bprint(&bout, " - ");
}
if(i%16 != 0)
Bprint(&bout, "\n");
Bflush(&bout);
blockput(b);
return nil;
}
void
usage(void)
{
fprint(2, "usage: vftp score\n");
threadexitsall("usage");
}
extern int allowall;
void
threadmain(int argc, char **argv)
{
char *err, *f[10], *p;
int i, nf;
uchar score[VtScoreSize];
Nfs3Status ok;
allowall = 1;
ARGBEGIN{
case 'V':
chattyventi++;
break;
default:
usage();
}ARGEND
if(argc != 1)
usage();
fmtinstall('F', vtfcallfmt);
fmtinstall('H', encodefmt);
fmtinstall('V', vtscorefmt);
if(access(argv[0], AEXIST) >= 0 || strchr(argv[0], '/')){
if((disk = diskopenfile(argv[0])) == nil)
sysfatal("diskopen: %r");
if((disk = diskcache(disk, 32768, 16)) == nil)
sysfatal("diskcache: %r");
}else{
if(vtparsescore(argv[0], nil, score) < 0)
sysfatal("bad score '%s'", argv[0]);
if((z = vtdial(nil)) == nil)
sysfatal("vtdial: %r");
if(vtconnect(z) < 0)
sysfatal("vtconnect: %r");
if((c = vtcachealloc(z, 32768, 32)) == nil)
sysfatal("vtcache: %r");
if((disk = diskopenventi(c, score)) == nil)
sysfatal("diskopenventi: %r");
}
if((fsys = fsysopen(disk)) == nil)
sysfatal("fsysopen: %r");
fprint(2, "block size %d\n", fsys->blocksize);
buf = emalloc(fsys->blocksize);
if((ok = fsysroot(fsys, &root)) != Nfs3Ok){
nfs3errstr(ok);
sysfatal("accessing root: %r");
}
cwd = root;
Binit(&bin, 0, OREAD);
Binit(&bout, 1, OWRITE);
while(fprint(2, "vftp> "), (p = Brdstr(&bin, '\n', 1)) != nil){
if(p[0] == '#')
continue;
nf = tokenize(p, f, nelem(f));
if(nf == 0)
continue;
for(i=0; i<nelem(cmdtab); i++){
if(strcmp(f[0], cmdtab[i].s) == 0){
if((err = cmdtab[i].fn(nf, f)) != nil)
fprint(2, "%s\n", err);
break;
}
}
if(i == nelem(cmdtab))
fprint(2, "unknown command '%s'\n", f[0]);
}
threadexitsall(nil);
}