mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
sftp session cache
This commit is contained in:
parent
b1e32ef366
commit
e961291897
1 changed files with 210 additions and 0 deletions
210
src/cmd/sftpcache.c
Normal file
210
src/cmd/sftpcache.c
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue