/* Copyright ©2007 Kris Maglione * See LICENSE file for license details. */ #define IXP_NO_P9_ #define IXP_P9_STRUCTS #include #include #include #include #include #include #include #include static IxpClient *client; static void usage(void) { fprint(1, "usage: %s [-a
] {create | read | ls [-ld] | remove | rm | write} \n" " %s [-a
] xwrite \n" " %s -v\n", argv0, argv0, argv0); exit(1); } static int errfmt(Fmt *f) { return fmtstrcpy(f, ixp_errbuf()); } /* Utility Functions */ static void write_data(IxpCFid *fid, char *name) { void *buf; int len; buf = emalloc(fid->iounit);; do { len = read(0, buf, fid->iounit); if(len > 0 && ixp_write(fid, buf, len) != len) fatal("cannot write file '%s': %r\n", name); } while(len > 0); free(buf); } static int comp_stat(const void *s1, const void *s2) { Stat *st1, *st2; st1 = (Stat*)s1; st2 = (Stat*)s2; return strcmp(st1->name, st2->name); } static void setrwx(long m, char *s) { static char *modes[] = { "---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx", }; strncpy(s, modes[m], 3); } static char * modestr(uint mode) { static char buf[16]; buf[0]='-'; if(mode & P9_DMDIR) buf[0]='d'; buf[1]='-'; setrwx((mode >> 6) & 7, &buf[2]); setrwx((mode >> 3) & 7, &buf[5]); setrwx((mode >> 0) & 7, &buf[8]); buf[11] = 0; return buf; } static char * timestr(uint val) { static char buf[32]; ctime_r((time_t*)&val, buf); buf[strlen(buf) - 1] = '\0'; return buf; } static void print_stat(Stat *s, int lflag) { if(lflag) print("%s %s %s %5llud %s %s\n", modestr(s->mode), s->uid, s->gid, s->length, timestr(s->mtime), s->name); else { if((s->mode&P9_DMDIR) && strcmp(s->name, "/")) print("%s/\n", s->name); else print("%s\n", s->name); } } /* Service Functions */ static int xwrite(int argc, char *argv[]) { IxpCFid *fid; char *file; ARGBEGIN{ default: usage(); }ARGEND; file = EARGF(usage()); fid = ixp_open(client, file, P9_OWRITE); if(fid == nil) fatal("Can't open file '%s': %r\n", file); write_data(fid, file); ixp_close(fid); return 0; } static int xawrite(int argc, char *argv[]) { IxpCFid *fid; char *file, *buf, *arg; int nbuf, mbuf, len; ARGBEGIN{ default: usage(); }ARGEND; file = EARGF(usage()); fid = ixp_open(client, file, P9_OWRITE); if(fid == nil) fatal("Can't open file '%s': %r\n", file); nbuf = 0; mbuf = 128; buf = emalloc(mbuf); while(argc) { arg = ARGF(); len = strlen(arg); if(nbuf + len + 1 > mbuf) { mbuf <<= 1; buf = erealloc(buf, mbuf); } memcpy(buf+nbuf, arg, len); nbuf += len; if(argc) buf[nbuf++] = ' '; } if(ixp_write(fid, buf, nbuf) == -1) fatal("cannot write file '%s': %r\n", file); ixp_close(fid); free(buf); return 0; } static int xcreate(int argc, char *argv[]) { IxpCFid *fid; char *file; ARGBEGIN{ default: usage(); }ARGEND; file = EARGF(usage()); fid = ixp_create(client, file, 0777, P9_OWRITE); if(fid == nil) fatal("Can't create file '%s': %r\n", file); if((fid->qid.type&P9_DMDIR) == 0) write_data(fid, file); ixp_close(fid); return 0; } static int xremove(int argc, char *argv[]) { char *file; int n; ARGBEGIN{ default: usage(); }ARGEND; file = EARGF(usage()); do { if(ixp_remove(client, file) == 0) { fprint(2, "%s: Can't remove file '%s': %r\n", argv0, file); n++; } }while((file = ARGF())); return 0; } static int xread(int argc, char *argv[]) { IxpCFid *fid; char *file, *buf; int count; ARGBEGIN{ default: usage(); }ARGEND; if(argc == 0) usage(); file = EARGF(usage()); do { fid = ixp_open(client, file, P9_OREAD); if(fid == nil) fatal("Can't open file '%s': %r\n", file); buf = emalloc(fid->iounit); while((count = ixp_read(fid, buf, fid->iounit)) > 0) write(1, buf, count); ixp_close(fid); if(count == -1) fprint(2, "%s: cannot read file/directory '%s': %r\n", argv0, file); }while((file = ARGF())); return 0; } static int xls(int argc, char *argv[]) { IxpMsg m; Stat *stat; IxpCFid *fid; char *file; uchar *buf; int lflag, dflag, count, nstat, mstat, i; lflag = dflag = 0; ARGBEGIN{ case 'l': lflag++; break; case 'd': dflag++; break; default: usage(); }ARGEND; file = EARGF(usage()); stat = ixp_stat(client, file); if(stat == nil) fatal("cannot stat file '%s': %r\n", file); if(dflag || (stat->mode&P9_DMDIR) == 0) { print_stat(stat, lflag); ixp_freestat(stat); return 0; } ixp_freestat(stat); fid = ixp_open(client, file, P9_OREAD); if(fid == nil) fatal("Can't open file '%s': %r\n", file); nstat = 0; mstat = 16; stat = emalloc(sizeof(*stat) * mstat); buf = emalloc(fid->iounit); while((count = ixp_read(fid, buf, fid->iounit)) > 0) { m = ixp_message(buf, count, MsgUnpack); while(m.pos < m.end) { if(nstat == mstat) { mstat <<= 1; stat = erealloc(stat, sizeof(*stat) * mstat); } ixp_pstat(&m, &stat[nstat++]); } } ixp_close(fid); qsort(stat, nstat, sizeof(*stat), comp_stat); for(i = 0; i < nstat; i++) { print_stat(&stat[i], lflag); ixp_freestat(&stat[i]); } free(stat); if(count == -1) fatal("cannot read directory '%s': %r\n", file); return 0; } typedef struct exectab exectab; struct exectab { char *cmd; int (*fn)(int, char**); } etab[] = { {"write", xwrite}, {"xwrite", xawrite}, {"read", xread}, {"cat", xread}, {"create", xcreate}, {"remove", xremove}, {"rm", xremove}, {"ls", xls}, {0, 0} }; int main(int argc, char *argv[]) { char *address; exectab *tab; int ret; fmtinstall('r', errfmt); address = getenv("WMII_ADDRESS"); ARGBEGIN{ case 'v': print("%s-" VERSION ", ©2007 Kris Maglione\n", argv0); exit(0); case 'a': address = EARGF(usage()); break; default: usage(); }ARGEND; if(!address) fatal("$WMII_ADDRESS not set\n"); client = ixp_mount(address); if(client == nil) fatal("can't mount: %r\n"); for(tab = etab; tab->cmd; tab++) if(strcmp(*argv, tab->cmd) == 0) break; if(tab->cmd == 0) usage(); ret = tab->fn(argc, argv); ixp_unmount(client); return ret; }