tsftp session cache - 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 e96129189712a83de71d45cbc852a54c5960d575
 (DIR) parent b1e32ef3661879a140728c4ee32b382d7c71679f
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 21 Mar 2005 07:37:13 +0000
       
       sftp session cache
       
       Diffstat:
         A src/cmd/sftpcache.c                 |     210 +++++++++++++++++++++++++++++++
       
       1 file changed, 210 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/src/cmd/sftpcache.c b/src/cmd/sftpcache.c
       t@@ -0,0 +1,210 @@
       +/*
       + * Multiplexor for sftp sessions.
       + * Assumes can parse session with sftp> prompts.
       + * Assumes clients are well-behaved and don't hang up the system.
       + *
       + * Stupid sftp bug: sftp invokes ssh, which always set O_NONBLOCK
       + * on 0, 1, and 2.  Ssh inherits sftp's 2, so we can't use the output pipe
       + * on fd 2, since it will get set O_NONBLOCK, sftp won't notice, and 
       + * writes will be lost.  So instead we use a separate pipe for errors
       + * and consult it after each command.  Assume the pipe buffer is 
       + * big enough to hold the error output.
       + */
       +#include <u.h>
       +#include <fcntl.h>
       +#include <libc.h>
       +#include <bio.h>
       +
       +#undef pipe
       +
       +int debug;
       +#define dprint if(debug)print
       +int sftpfd;
       +int sftperr;
       +Biobuf bin;
       +
       +void
       +usage(void)
       +{
       +        fprint(2, "usage: sftpcache system\n");
       +        exits("usage");
       +}
       +
       +char*
       +Brd(Biobuf *bin)
       +{
       +        static char buf[1000];
       +        int c, tot;
       +        
       +        tot = 0;
       +        while((c = Bgetc(bin)) >= 0 && tot<sizeof buf){
       +                buf[tot++] = c;
       +                if(c == '\n'){
       +                        buf[tot] = 0;
       +                        dprint("%s", buf);
       +                        return buf;
       +                }
       +                if(c == ' ' && tot == 6 && memcmp(buf, "sftp> ", 5) == 0){
       +                        buf[tot] = 0;
       +                        dprint("%s\n", buf);
       +                        return buf;
       +                }
       +        }
       +        if(tot == sizeof buf)
       +                sysfatal("response too long");
       +        return nil;
       +}
       +
       +int
       +readstr(int fd, char *a, int n)
       +{
       +        int i;
       +        
       +        for(i=0; i<n; i++){
       +                if(read(fd, a+i, 1) != 1)
       +                        return -1;
       +                if(a[i] == '\n'){
       +                        a[i] = 0;
       +                        return i;
       +                }
       +        }
       +        return n;
       +}
       +
       +void
       +doerrors(int fd)
       +{
       +        char buf[100];
       +        int n;
       +        
       +        while((n = read(sftperr, buf, sizeof buf)) > 0){
       +                if(debug)
       +                        write(1, buf, n);
       +                write(fd, buf, n);
       +        }
       +}
       +
       +void
       +bell(void *x, char *msg)
       +{
       +        if(strcmp(msg, "sys: child") == 0 || strcmp(msg, "sys: write on closed pipe") == 0)
       +                sysfatal("sftp exited");
       +        if(strcmp(msg, "alarm") == 0)
       +                noted(NCONT);
       +        noted(NDFLT);
       +}
       +
       +void
       +main(int argc, char **argv)
       +{
       +        char buf[200], cmd[1000], *q, *s;
       +        char dir[100], ndir[100];
       +        int p[2], px[2], pe[2], pid, ctl, nctl, fd, n;
       +        
       +        notify(bell);
       +        fmtinstall('H', encodefmt);
       +
       +        ARGBEGIN{
       +        case 'D':
       +                debug = 1;
       +                break;
       +        default:
       +                usage();
       +        }ARGEND
       +        
       +        if(argc != 1)
       +                usage();
       +        
       +        if(pipe(p) < 0 || pipe(px) < 0 || pipe(pe) < 0)
       +                sysfatal("pipe: %r");
       +        pid = fork();
       +        if(pid < 0)
       +                sysfatal("fork: %r");
       +        if(pid == 0){
       +                close(p[1]);
       +                close(px[0]);
       +                close(pe[0]);
       +                dup(p[0], 0);
       +                dup(px[1], 1);
       +                dup(pe[1], 2);
       +                if(p[0] > 2)
       +                        close(p[0]);
       +                if(px[1] > 2)
       +                        close(px[1]);
       +                if(pe[1] > 2)
       +                        close(pe[1]);
       +                execl("sftp", "sftp", "-b", "/dev/stdin", argv[0], nil);
       +                sysfatal("exec sftp: %r");
       +        }
       +
       +        close(p[0]);
       +        close(px[1]);
       +        close(pe[1]);
       +
       +        sftpfd = p[1];
       +        sftperr = pe[0];
       +        Binit(&bin, px[0], OREAD);
       +
       +        fcntl(sftperr, F_SETFL, fcntl(sftperr, F_GETFL, 0)|O_NONBLOCK);
       +
       +        do
       +                q = Brd(&bin);
       +        while(q && strcmp(q, "sftp> ") != 0);
       +        if(q == nil)
       +                sysfatal("unexpected eof");
       +
       +        snprint(buf, sizeof buf, "unix!%s/%s.sftp", getns(), argv[0]);
       +        ctl = announce(buf, dir);
       +        if(ctl < 0)
       +                sysfatal("announce %s: %r", buf);
       +
       +        pid = fork();
       +        if(pid < 0)
       +                sysfatal("fork");
       +        if(pid != 0)
       +                exits(nil);
       +                
       +        for(;;){
       +                nctl = listen(dir, ndir);
       +                if(nctl < 0)
       +                        sysfatal("listen %s: %r", buf);
       +                fd = accept(ctl, ndir);
       +                close(nctl);
       +                if(fd < 0)
       +                        continue;
       +                for(;;){
       +                //        alarm(1000);
       +                        n = readstr(fd, cmd, sizeof cmd);
       +                //        alarm(0);
       +                        if(n <= 0)
       +                                break;
       +                        dprint("CMD %s\n", cmd);
       +                        if(strcmp(cmd, "DONE") == 0)
       +                                break;
       +                        fprint(sftpfd, "%s\n", cmd);
       +                        q = Brd(&bin);
       +                        if(*q==0 || q[strlen(q)-1] != '\n')
       +                                sysfatal("unexpected response");
       +                        q[strlen(q)-1] = 0;
       +                        if(strcmp(q, cmd) != 0)
       +                                sysfatal("unexpected response");
       +                        while((q = Brd(&bin)) != nil){
       +                                if(strcmp(q, "sftp> ") == 0){
       +                                        doerrors(fd);
       +                                        break;
       +                                }
       +                                s = q+strlen(q);
       +                                while(s > q && (s[-1] == ' ' || s[-1] == '\n' || s[-1] == '\t' || s[-1] == '\r'))
       +                                        s--;
       +                                *s = 0;
       +                                fprint(fd, "%s\n", q);
       +                        }
       +                        if(q == nil){
       +                                fprint(fd, "!!! unexpected eof\n");
       +                                sysfatal("unexpected eof");
       +                        }
       +                }
       +                close(fd);
       +        }
       +}
       +