2 * Multiplexor for sftp sessions.
3 * Assumes can parse session with sftp> prompts.
4 * Assumes clients are well-behaved and don't hang up the system.
6 * Stupid sftp bug: sftp invokes ssh, which always set O_NONBLOCK
7 * on 0, 1, and 2. Ssh inherits sftp's 2, so we can't use the output pipe
8 * on fd 2, since it will get set O_NONBLOCK, sftp won't notice, and
9 * writes will be lost. So instead we use a separate pipe for errors
10 * and consult it after each command. Assume the pipe buffer is
11 * big enough to hold the error output.
21 #define dprint if(debug)print
29 fprint(2, "usage: sftpcache system\n");
36 static char buf[1000];
40 while((c = Bgetc(bin)) >= 0 && tot<sizeof buf){
44 dprint("OUT %s", buf);
47 if(c == ' ' && tot == 6 && memcmp(buf, "sftp> ", 5) == 0){
49 dprint("OUT %s\n", buf);
54 sysfatal("response too long");
59 readstr(int fd, char *a, int n)
64 if(read(fd, a+i, 1) != 1)
81 while((n = read(sftperr, buf, sizeof buf)) > 0){
85 fprint(2, "OUT errors:\n");
94 bell(void *x, char *msg)
96 if(strcmp(msg, "sys: child") == 0 || strcmp(msg, "sys: write on closed pipe") == 0)
97 sysfatal("sftp exited");
98 if(strcmp(msg, "alarm") == 0)
104 main(int argc, char **argv)
106 char buf[200], cmd[1000], *q, *s;
107 char dir[100], ndir[100];
108 int p[2], px[2], pe[2], pid, ctl, nctl, fd, n;
111 fmtinstall('H', encodefmt);
124 if(pipe(p) < 0 || pipe(px) < 0 || pipe(pe) < 0)
125 sysfatal("pipe: %r");
128 sysfatal("fork: %r");
142 execl("sftp", "sftp", "-b", "/dev/stdin", argv[0], nil);
143 sysfatal("exec sftp: %r");
152 Binit(&bin, px[0], OREAD);
154 fcntl(sftperr, F_SETFL, fcntl(sftperr, F_GETFL, 0)|O_NONBLOCK);
158 while(q && strcmp(q, "sftp> ") != 0);
160 sysfatal("unexpected eof");
162 snprint(buf, sizeof buf, "unix!%s/%s.sftp", getns(), argv[0]);
163 ctl = announce(buf, dir);
165 sysfatal("announce %s: %r", buf);
174 nctl = listen(dir, ndir);
176 sysfatal("listen %s: %r", buf);
177 fd = accept(ctl, ndir);
183 n = readstr(fd, cmd, sizeof cmd);
187 dprint("CMD %s\n", cmd);
188 if(strcmp(cmd, "DONE") == 0){
189 fprint(fd, "DONE\n");
192 fprint(sftpfd, "-%s\n", cmd);
194 if(*q==0 || q[strlen(q)-1] != '\n')
195 sysfatal("unexpected response");
197 if(q[0] != '-' || strcmp(q+1, cmd) != 0)
198 sysfatal("unexpected response");
199 while((q = Brd(&bin)) != nil){
200 if(strcmp(q, "sftp> ") == 0){
205 while(s > q && (s[-1] == ' ' || s[-1] == '\n' || s[-1] == '\t' || s[-1] == '\r'))
208 fprint(fd, "%s\n", q);
211 fprint(fd, "!!! unexpected eof\n");
212 sysfatal("unexpected eof");