diff options
author | Akshat Kumar <seed@mail.nanosouffle.net> | 2012-09-24 10:35:01 -0400 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2012-09-24 10:35:01 -0400 |
commit | ac3ba726f9b4978829e4ad186b00109262fa2b93 (patch) | |
tree | 5e8e17412c3c3827a67cf1f2aa403c083834a143 /src/cmd/9import.c | |
parent | 37f8ed2410ad5cbd46eda00a77f8bf4950bcf544 (diff) | |
download | plan9port-ac3ba726f9b4978829e4ad186b00109262fa2b93.tar.gz plan9port-ac3ba726f9b4978829e4ad186b00109262fa2b93.tar.bz2 plan9port-ac3ba726f9b4978829e4ad186b00109262fa2b93.zip |
src/cmd: Add a repurposed import(4), called `9import', to the ports.
The code is adapted from Plan 9's import(4); this allows us to speak
that protocol. We don't currently support AAN (in the works) or
TLS/SSL.
Thanks to David for help with the man page, testing, and development.
R=0intro, rsc
CC=plan9port.codebot
http://codereview.appspot.com/6458100
Diffstat (limited to 'src/cmd/9import.c')
-rw-r--r-- | src/cmd/9import.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/cmd/9import.c b/src/cmd/9import.c new file mode 100644 index 00000000..c74ffb50 --- /dev/null +++ b/src/cmd/9import.c @@ -0,0 +1,239 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <thread.h> + +enum { + Encnone, + Encssl, + Enctls, +}; + +static char *encprotos[] = { + [Encnone] = "clear", + [Encssl] = "ssl", + [Enctls] = "tls", + nil, +}; + +char *keyspec = ""; +char *filterp; +char *ealgs = "rc4_256 sha1"; +int encproto = Encnone; +AuthInfo *ai; +int debug; +int doauth = 1; +int timedout; + +int connectez(char*, char*); +void sysfatal(char*, ...); +void usage(void); +int filter(int, char *, char *); + +int +catcher(void *v, char *msg) +{ + timedout = 1; + if(strcmp(msg, "alarm") == 0) + return 1; + return 0; +} + +static int +lookup(char *s, char *l[]) +{ + int i; + + for (i = 0; l[i] != 0; i++) + if (strcmp(l[i], s) == 0) + return i; + return -1; +} + +static char* +srvname(char *addr) +{ + int i; + + for(i=0; i<strlen(addr); i++){ + if(addr[i] == '!') + addr[i] = ':'; + } + return addr; +} + +void +threadmain(int argc, char **argv) +{ + char *mntpt, *srvpost, srvfile[64]; + int fd; + + quotefmtinstall(); + srvpost = nil; + ARGBEGIN{ + case 'A': + doauth = 0; + break; + case 'd': + debug++; + break; + case 'E': + if ((encproto = lookup(EARGF(usage()), encprotos)) < 0) + usage(); + break; + case 'e': + ealgs = EARGF(usage()); + if(*ealgs == 0 || strcmp(ealgs, "clear") == 0) + ealgs = nil; + break; + case 'k': + keyspec = EARGF(usage()); + break; + case 'p': + filterp = unsharp("#9/bin/aan"); + break; + case 's': + srvpost = EARGF(usage()); + break; + default: + usage(); + }ARGEND; + + mntpt = 0; /* to shut up compiler */ + switch(argc) { + case 2: + mntpt = argv[1]; + break; + case 3: + mntpt = argv[2]; + break; + default: + usage(); + } + + if(encproto != Encnone) + sysfatal("%s: tls and ssl have not yet been implemented", argv[0]); + + threadnotify(catcher, 1); + alarm(60*1000); + + fd = connectez(argv[0], argv[1]); + + fprint(fd, "impo %s %s\n", filterp? "aan": "nofilter", + encprotos[encproto]); + + if (filterp) + fd = filter(fd, filterp, argv[0]); + + if(srvpost == nil) + srvpost = srvname(argv[0]); + sprint(srvfile, "%s", srvpost); + + if(post9pservice(fd, srvfile, mntpt) < 0) + sysfatal("can't post %s: %r", argv[1]); + alarm(0); + + threadexitsall(0); +} + +/* the name "connect" is special */ +int +connectez(char *system, char *tree) +{ + char buf[ERRMAX], *na; + int fd, n; + char *authp; + + na = netmkaddr(system, "tcp", "exportfs"); + threadsetname("dial %s", na); + if((fd = dial(na, nil, nil, nil)) < 0) + sysfatal("can't dial %s: %r", system); + + if(doauth){ + authp = "p9any"; + threadsetname("auth_proxy auth_getkey proto=%q role=client %s", + authp, keyspec); + ai = auth_proxy(fd, auth_getkey, "proto=%q role=client %s", + authp, keyspec); + if(ai == nil) + sysfatal("%r: %s", system); + } + + threadsetname("writing tree name %s", tree); + n = write(fd, tree, strlen(tree)); + if(n < 0) + sysfatal("can't write tree: %r"); + + strcpy(buf, "can't read tree"); + + threadsetname("awaiting OK for %s", tree); + n = read(fd, buf, sizeof buf - 1); + if(n!=2 || buf[0]!='O' || buf[1]!='K'){ + if (timedout) + sysfatal("timed out connecting to %s", na); + buf[sizeof buf - 1] = '\0'; + sysfatal("bad remote tree: %s", buf); + } + + return fd; +} + +void +usage(void) +{ + fprint(2, "usage: 9import [-A] [-E clear|ssl|tls] " +"[-e 'crypt auth'|clear] [-k keypattern] [-p] [-s srv] host remotefs [mountpoint]\n"); + threadexitsall("usage"); +} + +/* Network on fd1, mount driver on fd0 */ +int +filter(int fd, char *cmd, char *host) +{ + int p[2], len, argc; + char newport[256], buf[256], *s; + char *argv[16], *file, *pbuf; + + if ((len = read(fd, newport, sizeof newport - 1)) < 0) + sysfatal("filter: cannot write port; %r"); + newport[len] = '\0'; + + if ((s = strchr(newport, '!')) == nil) + sysfatal("filter: illegally formatted port %s", newport); + + strecpy(buf, buf+sizeof buf, netmkaddr(host, "tcp", "0")); + pbuf = strrchr(buf, '!'); + strecpy(pbuf, buf+sizeof buf, s); + + if(debug) + fprint(2, "filter: remote port %s\n", newport); + + argc = tokenize(cmd, argv, nelem(argv)-2); + if (argc == 0) + sysfatal("filter: empty command"); + argv[argc++] = "-c"; + argv[argc++] = buf; + argv[argc] = nil; + file = argv[0]; + if (s = strrchr(argv[0], '/')) + argv[0] = s+1; + + if(pipe(p) < 0) + sysfatal("pipe: %r"); + + switch(rfork(RFNOWAIT|RFPROC|RFFDG)) { + case -1: + sysfatal("rfork record module: %r"); + case 0: + dup(p[0], 1); + dup(p[0], 0); + close(p[0]); + close(p[1]); + exec(file, argv); + sysfatal("exec record module: %r"); + default: + close(fd); + close(p[0]); + } + return p[1]; +} |