/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <ctype.h> intisatty(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; intruncommand(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;} voidvprint(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);} voidusage(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 */intflagfmt(Fmt *f){ flag = va_arg(f->args, int); return 0;} /* flag: if previous integer flag, take char *value */intvalfmt(Fmt *f){ char *value; value = va_arg(f->args, char*); if(flag) return fmtprint(f, " %s", value); return 0;} voidsendokresponse(void){ char ok = OK; write(remotefd1, &ok, 1);} voidmain(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);} voiddestislocal(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; } } }} voiddestisremote(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]); } }} voidreadhdr(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;} voidreceive(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 */Lines 1–500 of 808. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 */