tsrc/cmd: Add a repurposed import(4), called `9import', to the ports. - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit ac3ba726f9b4978829e4ad186b00109262fa2b93
 (DIR) parent 37f8ed2410ad5cbd46eda00a77f8bf4950bcf544
 (HTM) Author: Akshat Kumar <seed@mail.nanosouffle.net>
       Date:   Mon, 24 Sep 2012 10:35:01 -0400
       
       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
       tthat 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:
         M CONTRIBUTORS                        |       1 +
         A man/man4/9import.4                  |      79 +++++++++++++++++++++++++++++++
         A src/cmd/9import.c                   |     239 +++++++++++++++++++++++++++++++
       
       3 files changed, 319 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/CONTRIBUTORS b/CONTRIBUTORS
       t@@ -5,6 +5,7 @@
        
        Abhishek Kulkarni <adkulkar@umail.iu.edu>
        Albert Lee <trisk@acm.jhu.edu>
       +Akshat Kumar <seed@mail.nanosouffle.net>
        André Günther <Andre.G@gmx.de>
        Anthony Martin <ality@pbrane.org>
        Anthony Sorace <a@9srv.net>
 (DIR) diff --git a/man/man4/9import.4 b/man/man4/9import.4
       t@@ -0,0 +1,79 @@
       +.TH 9IMPORT 4
       +.SH NAME
       +9import \- import a name space from a remote system
       +.SH SYNOPSIS
       +.B 9import
       +[
       +.I options
       +]
       +.I system
       +.I file
       +[
       +.I mountpoint
       +]
       +.SH DESCRIPTION
       +The
       +.I 9import
       +tool allows an arbitrary
       +.I file
       +on a remote
       +.I system,
       +with the capability of running the Plan 9
       +.IR exportfs (4)
       +service,
       +to be imported into the local name space.
       +Usually
       +.I file
       +is a directory, so the complete
       +file tree under the directory is made available.
       +.PP
       +A process is started on the
       +remote machine, with authority of the user of
       +.IR 9import ,
       +to perform work for the local machine using the
       +.IR exportfs (4)
       +service.
       +The default port used is TCP 17007.
       +If
       +.I mountpoint
       +is omitted, then
       +.I 9import
       +uses the name of the remote
       +.I file
       +as the local mount point.
       +.PP
       +The options are:
       +.TF "-s namexxx"
       +.PD
       +.TP
       +.B -A
       +Skip the authentication protocol.
       +This is useful for connecting to foreign systems like Inferno.
       +.TP
       +.B -k \fIkeypattern
       +Use
       +.I keypattern
       +to select a key to authenticate to the remote side
       +(see
       +.IR auth (2)).
       +.TP
       +.B -p
       +Push the
       +.IR aan (8)
       +filter onto the connection to protect against
       +temporary network outages.
       +.TP
       +.B -s \fIname
       +Post the connection's mountable file descriptor as
       +.BI /srv/ name\fR.
       +.SH SOURCE
       +.B \*9/src/cmd/9import.c
       +.SH SEE ALSO
       +.IR srv (4),
       +.IR aan (8),
       +.IR listen1 (8),
       +.B cs
       +in
       +.IR ndb (7)
       +.SH BUGS
       +Encryption is not implemented.
 (DIR) diff --git a/src/cmd/9import.c b/src/cmd/9import.c
       t@@ -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];
       +}