diff options
author | khm <devnull@localhost> | 2017-01-12 16:36:38 -0800 |
---|---|---|
committer | khm <devnull@localhost> | 2017-01-12 16:36:38 -0800 |
commit | dc8c7bf2b73d608ac2483aee303a51a3507b4c5a (patch) | |
tree | f8c69dbf5f36de6f9acea724f2068054b5b8e7a6 /sys/src/cmd/ssh/scp.c | |
parent | cb1555c7d741fa482c339aa9ac8a44753e2ad296 (diff) |
ssh: R.I.P.
Diffstat (limited to 'sys/src/cmd/ssh/scp.c')
-rw-r--r-- | sys/src/cmd/ssh/scp.c | 799 |
1 files changed, 0 insertions, 799 deletions
diff --git a/sys/src/cmd/ssh/scp.c b/sys/src/cmd/ssh/scp.c deleted file mode 100644 index bab66754a..000000000 --- a/sys/src/cmd/ssh/scp.c +++ /dev/null @@ -1,799 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <ctype.h> - -int -isatty(int fd) -{ - char buf[64]; - - buf[0] = '\0'; - fd2path(fd, buf, sizeof buf); - if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0) - return 1; - return 0; -} - -#define OK 0x00 -#define ERROR 0x01 -#define FATAL 0x02 - -char *progname; - -int dflag; -int fflag; -int iflag; -int pflag; -int rflag; -int tflag; -int vflag; - -int remote; - -char *exitflag = nil; - -void scperror(int, char*, ...); -void mustbedir(char*); -void receive(char*); -char *fileaftercolon(char*); -void destislocal(char *cmd, int argc, char *argv[], char *dest); -void destisremote(char *cmd, int argc, char *argv[], char *host, char *dest); -int remotessh(char *host, char *cmd); -void send(char*); -void senddir(char*, int, Dir*); -int getresponse(void); - -char theuser[32]; - -char ssh[] = "/bin/ssh"; - -int remotefd0; -int remotefd1; - -int -runcommand(char *cmd) -{ - Waitmsg *w; - int pid; - char *argv[4]; - - if (cmd == nil) - return -1; - switch(pid = fork()){ - case -1: - return -1; - case 0: - argv[0] = "rc"; - argv[1] = "-c"; - argv[2] = cmd; - argv[3] = nil; - exec("/bin/rc", argv); - exits("exec failed"); - } - for(;;){ - w = wait(); - if(w == nil) - return -1; - if(w->pid == pid) - break; - free(w); - } - if(w->msg[0]){ - free(w); - return -1; - } - free(w); - return 1; -} - -void -vprint(char *fmt, ...) -{ - char buf[1024]; - va_list arg; - static char *name; - - if(vflag == 0) - return; - - va_start(arg, fmt); - vseprint(buf, buf+sizeof(buf), fmt, arg); - va_end(arg); - - if(name == nil){ - name = sysname(); - if(name == nil) - name = "<unknown>"; - } - fprint(2, "%s: %s\n", name, buf); -} - -void -usage(void) -{ - fprint(2, "Usage: scp [-Iidfprtv] source ... destination\n"); - exits("usage"); -} - - -#pragma varargck type "F" int -#pragma varargck type "V" char* -static int flag; - -/* flag: if integer flag, take following char *value */ -int -flagfmt(Fmt *f) -{ - flag = va_arg(f->args, int); - return 0; -} - -/* flag: if previous integer flag, take char *value */ -int -valfmt(Fmt *f) -{ - char *value; - - value = va_arg(f->args, char*); - if(flag) - return fmtprint(f, " %s", value); - return 0; -} - -void -sendokresponse(void) -{ - char ok = OK; - - write(remotefd1, &ok, 1); -} - -void -main(int argc, char *argv[]) -{ - int i, fd; - char cmd[32]; - char *p; - - progname = argv[0]; - fmtinstall('F', flagfmt); - fmtinstall('V', valfmt); - iflag = -1; - - ARGBEGIN { - case 'I': - iflag = 0; - break; - case 'i': - iflag = 1; - break; - case 'd': - dflag++; - break; - case 'f': - fflag++; - remote++; - break; - case 'p': - pflag++; - break; - case 'r': - rflag++; - break; - case 't': - tflag++; - remote++; - break; - case 'v': - vflag++; - break; - default: - scperror(1, "unknown option %c", ARGC()); - } ARGEND - - if(iflag == -1) - iflag = isatty(0); - - remotefd0 = 0; - remotefd1 = 1; - - if(fflag){ - getresponse(); - for(i=0; i<argc; i++) - send(argv[i]); - exits(0); - } - if(tflag){ - if(argc != 1) - usage(); - receive(argv[0]); - exits(0); - } - - if (argc < 2) - usage(); - if (argc > 2) - dflag = 1; - - i = 0; - fd = open("/dev/user", OREAD); - if(fd >= 0){ - i = read(fd, theuser, sizeof theuser - 1); - close(fd); - } - if(i <= 0) - scperror(1, "can't read /dev/user: %r"); - - remotefd0 = -1; - remotefd1 = -1; - - snprint(cmd, sizeof cmd, "scp%F%V%F%V%F%V%F%V", - dflag, "-d", - pflag, "-p", - rflag, "-r", - vflag, "-v"); - - p = fileaftercolon(argv[argc-1]); - if(p != nil) /* send to remote machine. */ - destisremote(cmd, argc-1, argv, argv[argc-1], p); - else{ - if(dflag) - mustbedir(argv[argc-1]); - destislocal(cmd, argc-1, argv, argv[argc-1]); - } - - exits(exitflag); -} - -void -destislocal(char *cmd, int argc, char *argv[], char *dst) -{ - int i; - char *src; - char buf[4096]; - - for(i = 0; i<argc; i++){ - src = fileaftercolon(argv[i]); - if(src == nil){ - /* local file; no network */ - snprint(buf, sizeof buf, "exec cp%F%V%F%V %s %s", - rflag, "-r", - pflag, "-p", - argv[i], dst); - vprint("remotetolocal: %s", buf); - if(runcommand(buf) < 0) - exitflag = "local cp exec"; - }else{ - /* remote file; use network */ - snprint(buf, sizeof buf, "%s -f %s", cmd, src); - if(remotessh(argv[i], buf) < 0) - exitflag = "remote ssh exec"; - else{ - receive(dst); - close(remotefd0); - remotefd0 = -1; - remotefd1 = -1; - } - } - } -} - -void -destisremote(char *cmd, int argc, char *argv[], char *host, char *dest) -{ - int i; - char *src; - char buf[4096]; - - for(i = 0; i < argc; i++){ - vprint("remote destination: send %s to %s:%s", argv[i], host, dest); - /* destination is remote, but source may be local */ - src = fileaftercolon(argv[i]); - if(src != nil){ - /* remote to remote */ - snprint(buf, sizeof buf, "exec %s%F%V%F%V %s %s %s '%s:%s'", - ssh, - iflag, " -i", - vflag, "-v", - argv[i], cmd, src, - host, dest); - vprint("localtoremote: %s", buf); - runcommand(buf); - }else{ - /* local to remote */ - if(remotefd0 == -1){ - snprint(buf, sizeof buf, "%s -t %s", cmd, dest); - if(remotessh(host, buf) < 0) - exits("remotessh"); - if(getresponse() < 0) - exits("bad response"); - } - send(argv[i]); - } - } -} - -void -readhdr(char *p, int n) -{ - int i; - - for(i=0; i<n; i++){ - if(read(remotefd0, &p[i], 1) != 1) - break; - if(p[i] == '\n'){ - p[i] = '\0'; - return; - } - } - /* if at beginning, this is regular EOF */ - if(i == 0) - exits(nil); - scperror(1, "read error on receive header: %r"); -} - -Dir * -receivedir(char *dir, int exists, Dir *d, int settimes, ulong atime, ulong mtime, ulong mode) -{ - Dir nd; - int setmodes; - int fd; - - setmodes = pflag; - if(exists){ - if(!(d->qid.type & QTDIR)) { - scperror(0, "%s: protocol botch: directory requrest for non-directory", dir); - return d; - } - }else{ - /* create it writeable; will fix later */ - setmodes = 1; - fd = create(dir, OREAD, DMDIR|mode|0700); - if (fd < 0){ - scperror(0, "%s: can't create: %r", dir); - return d; - } - d = dirfstat(fd); - close(fd); - if(d == nil){ - scperror(0, "%s: can't stat: %r", dir); - return d; - } - } - receive(dir); - if(settimes || setmodes){ - nulldir(&nd); - if(settimes){ - nd.atime = atime; - nd.mtime = mtime; - d->atime = nd.atime; - d->mtime = nd.mtime; - } - if(setmodes){ - nd.mode = DMDIR | (mode & 0777); - d->mode = nd.mode; - } - if(dirwstat(dir, &nd) < 0){ - scperror(0, "can't wstat %s: %r", dir); - free(d); - return nil; - } - } - return d; -} - -void -receive(char *dest) -{ - int isdir, settimes, mode; - int exists, n, i, fd, m; - int errors; - ulong atime, mtime, size; - char buf[8192], *p; - char name[1024]; - Dir *d; - Dir nd; - - mtime = 0L; - atime = 0L; - settimes = 0; - isdir = 0; - if ((d = dirstat(dest)) && (d->qid.type & QTDIR)) { - isdir = 1; - } - if(dflag && !isdir) - scperror(1, "%s: not a directory: %r", dest); - - sendokresponse(); - - for (;;) { - readhdr(buf, sizeof buf); - - switch(buf[0]){ - case ERROR: - case FATAL: - if(!remote) - fprint(2, "%s\n", buf+1); - exitflag = "bad receive"; - if(buf[0] == FATAL) - exits(exitflag); - continue; - - case 'E': - sendokresponse(); - return; - - case 'T': - settimes = 1; - p = buf + 1; - mtime = strtol(p, &p, 10); - if(*p++ != ' '){ - Badtime: - scperror(1, "bad time format: %s", buf+1); - } - strtol(p, &p, 10); - if(*p++ != ' ') - goto Badtime; - atime = strtol(p, &p, 10); - if(*p++ != ' ') - goto Badtime; - strtol(p, &p, 10); - if(*p++ != 0) - goto Badtime; - - sendokresponse(); - continue; - - case 'D': - case 'C': - p = buf + 1; - mode = strtol(p, &p, 8); - if (*p++ != ' '){ - Badmode: - scperror(1, "bad mode/size format: %s", buf+1); - } - size = strtoll(p, &p, 10); - if(*p++ != ' ') - goto Badmode; - - if(isdir){ - if(dest[0] == '\0') - snprint(name, sizeof name, "%s", p); - else - snprint(name, sizeof name, "%s/%s", dest, p); - }else - snprint(name, sizeof name, "%s", dest); - if(strlen(name) > sizeof name-UTFmax) - scperror(1, "file name too long: %s", dest); - - exists = 1; - free(d); - if((d = dirstat(name)) == nil) - exists = 0; - - if(buf[0] == 'D'){ - vprint("receive directory %s", name); - d = receivedir(name, exists, d, settimes, atime, mtime, mode); - settimes = 0; - continue; - } - - vprint("receive file %s by %s", name, getuser()); - fd = create(name, OWRITE, mode); - if(fd < 0){ - scperror(0, "can't create %s: %r", name); - continue; - } - sendokresponse(); - - /* - * Committed to receive size bytes - */ - errors = 0; - for(i = 0; i < size; i += m){ - n = sizeof buf; - if(n > size - i) - n = size - i; - m = readn(remotefd0, buf, n); - if(m <= 0) - scperror(1, "read error on connection: %r"); - if(errors == 0){ - n = write(fd, buf, m); - if(n != m) - errors = 1; - } - } - - /* if file exists, modes could be wrong */ - if(errors) - scperror(0, "%s: write error: %r", name); - else if(settimes || (exists && (d->mode&0777) != (mode&0777))){ - nulldir(&nd); - if(settimes){ - settimes = 0; - nd.atime = atime; - nd.mtime = mtime; - } - if(exists && (d->mode&0777) != (mode&0777)) - nd.mode = (d->mode & ~0777) | (mode&0777); - if(dirwstat(name, &nd) < 0) - scperror(0, "can't wstat %s: %r", name); - } - free(d); - d = nil; - close(fd); - getresponse(); - if(errors) - exits("write error"); - sendokresponse(); - break; - - default: - scperror(0, "unrecognized header type char %c", buf[0]); - scperror(1, "input line: %s", buf); - } - } -} - -/* - * Lastelem is called when we have a Dir with the final element, but if the file - * has been bound, we want the original name that was used rather than - * the contents of the stat buffer, so do this lexically. - */ -char* -lastelem(char *file) -{ - char *elem; - - elem = strrchr(file, '/'); - if(elem == nil) - return file; - return elem+1; -} - -void -send(char *file) -{ - Dir *d; - ulong i; - int m, n, fd; - char buf[8192]; - - if((fd = open(file, OREAD)) < 0){ - scperror(0, "can't open %s: %r", file); - return; - } - if((d = dirfstat(fd)) == nil){ - scperror(0, "can't fstat %s: %r", file); - goto Return; - } - - if(d->qid.type & QTDIR){ - if(rflag) - senddir(file, fd, d); - else - scperror(0, "%s: is a directory", file); - goto Return; - } - - if(pflag){ - fprint(remotefd1, "T%lud 0 %lud 0\n", d->mtime, d->atime); - if(getresponse() < 0) - goto Return; - } - - fprint(remotefd1, "C%.4luo %lld %s\n", d->mode&0777, d->length, lastelem(file)); - if(getresponse() < 0) - goto Return; - - /* - * We are now committed to send d.length bytes, regardless - */ - for(i=0; i<d->length; i+=m){ - n = sizeof buf; - if(n > d->length - i) - n = d->length - i; - m = readn(fd, buf, n); - if(m <= 0) - break; - write(remotefd1, buf, m); - } - - if(i == d->length) - sendokresponse(); - else{ - /* continue to send gibberish up to d.length */ - for(; i<d->length; i+=n){ - n = sizeof buf; - if(n > d->length - i) - n = d->length - i; - write(remotefd1, buf, n); - } - scperror(0, "%s: %r", file); - } - - getresponse(); - - Return: - free(d); - close(fd); -} - -int -getresponse(void) -{ - uchar first, byte, buf[256]; - int i; - - if (read(remotefd0, &first, 1) != 1) - scperror(1, "lost connection"); - - if(first == 0) - return 0; - - i = 0; - if(first > FATAL){ - fprint(2, "scp: unexpected response character 0x%.2ux\n", first); - buf[i++] = first; - } - - /* read error message up to newline */ - for(;;){ - if(read(remotefd0, &byte, 1) != 1) - scperror(1, "response: dropped connection"); - if(byte == '\n') - break; - if(i < sizeof buf) - buf[i++] = byte; - } - - exitflag = "bad response"; - if(!remote) - fprint(2, "%.*s\n", utfnlen((char*)buf, i), (char*)buf); - - if (first == ERROR) - return -1; - exits(exitflag); - return 0; /* not reached */ -} - -void -senddir(char *name, int fd, Dir *dirp) -{ - Dir *d, *dir; - int n; - char file[256]; - - if(pflag){ - fprint(remotefd1, "T%lud 0 %lud 0\n", dirp->mtime, dirp->atime); - if(getresponse() < 0) - return; - } - - vprint("directory %s mode: D%.4lo %d %.1024s", name, dirp->mode&0777, 0, lastelem(name)); - - fprint(remotefd1, "D%.4lo %d %.1024s\n", dirp->mode&0777, 0, dirp->name); - if(getresponse() < 0) - return; - - n = dirreadall(fd, &dir); - for(d = dir; d < &dir[n]; d++){ - /* shouldn't happen with plan 9, but worth checking anyway */ - if(strcmp(d->name, ".")==0 || strcmp(d->name, "..")==0) - continue; - if(snprint(file, sizeof file, "%s/%s", name, d->name) > sizeof file-UTFmax){ - scperror(0, "%.20s.../%s: name too long; skipping file", file, d->name); - continue; - } - send(file); - } - free(dir); - fprint(remotefd1, "E\n"); - getresponse(); -} - -int -remotessh(char *host, char *cmd) -{ - int i, p[2]; - char *arg[32]; - - vprint("remotessh: %s: %s", host, cmd); - - if(pipe(p) < 0) - scperror(1, "pipe: %r"); - - switch(fork()){ - case -1: - scperror(1, "fork: %r"); - - case 0: - /* child */ - close(p[0]); - dup(p[1], 0); - dup(p[1], 1); - for (i = 3; i < 100; i++) - close(i); - - i = 0; - arg[i++] = ssh; - arg[i++] = "-x"; - arg[i++] = "-a"; - arg[i++] = "-m"; - if(iflag) - arg[i++] = "-i"; - if(vflag) - arg[i++] = "-v"; - arg[i++] = host; - arg[i++] = cmd; - arg[i] = nil; - - exec(ssh, arg); - exits("exec failed"); - - default: - /* parent */ - close(p[1]); - remotefd0 = p[0]; - remotefd1 = p[0]; - } - return 0; -} - -void -scperror(int exit, char *fmt, ...) -{ - char buf[2048]; - va_list arg; - - - va_start(arg, fmt); - vseprint(buf, buf+sizeof(buf), fmt, arg); - va_end(arg); - - fprint(remotefd1, "%cscp: %s\n", ERROR, buf); - - if (!remote) - fprint(2, "scp: %s\n", buf); - exitflag = buf; - if(exit) - exits(exitflag); -} - -char * -fileaftercolon(char *file) -{ - char *c, *s; - - c = utfrune(file, ':'); - if(c == nil) - return nil; - - /* colon must be in middle of name to be a separator */ - if(c == file) - return nil; - - /* does slash occur before colon? */ - s = utfrune(file, '/'); - if(s != nil && s < c) - return nil; - - *c++ = '\0'; - if(*c == '\0') - return "."; - return c; -} - -void -mustbedir(char *file) -{ - Dir *d; - - if((d = dirstat(file)) == nil){ - scperror(1, "%s: %r", file); - return; - } - if(!(d->qid.type & QTDIR)) - scperror(1, "%s: Not a directory", file); - free(d); -} |