121569Sdist /* 235619Sbostic * Copyright (c) 1983 The Regents of the University of California. 335619Sbostic * All rights reserved. 435619Sbostic * 535619Sbostic * Redistribution and use in source and binary forms are permitted 635619Sbostic * provided that the above copyright notice and this paragraph are 735619Sbostic * duplicated in all such forms and that any documentation, 835619Sbostic * advertising materials, and other materials related to such 935619Sbostic * distribution and use acknowledge that the software was developed 1035619Sbostic * by the University of California, Berkeley. The name of the 1135619Sbostic * University may not be used to endorse or promote products derived 1235619Sbostic * from this software without specific prior written permission. 1335619Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435619Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537038Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621569Sdist */ 1721569Sdist 186440Swnj #ifndef lint 1921569Sdist char copyright[] = 2035619Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2121569Sdist All rights reserved.\n"; 2235619Sbostic #endif /* not lint */ 236440Swnj 2421569Sdist #ifndef lint 25*38100Sbostic static char sccsid[] = "@(#)rcp.c 5.18 (Berkeley) 05/21/89"; 2635619Sbostic #endif /* not lint */ 2721569Sdist 2812989Ssam /* 2912989Ssam * rcp 3012989Ssam */ 316720Smckusick #include <sys/param.h> 3232127Sbostic #include <sys/file.h> 336440Swnj #include <sys/stat.h> 3423101Slepreau #include <sys/time.h> 356440Swnj #include <sys/ioctl.h> 3638098Sbostic #include <sys/dir.h> 3738098Sbostic #include <sys/signal.h> 389199Ssam #include <netinet/in.h> 396440Swnj #include <pwd.h> 4018026Sralph #include <netdb.h> 416440Swnj #include <errno.h> 4238098Sbostic #include <strings.h> 4338098Sbostic #include <stdio.h> 4438098Sbostic #include <ctype.h> 4537037Sbostic #include "pathnames.h" 4612989Ssam 4738098Sbostic #ifdef KERBEROS 4836624Skfall #include <kerberos/krb.h> 4938098Sbostic 5038098Sbostic char krb_realm[REALM_SZ]; 5138098Sbostic int use_kerberos = 1, encrypt = 0; 5238098Sbostic CREDENTIALS cred; 5338098Sbostic Key_schedule schedule; 5436624Skfall #endif 5536624Skfall 5638098Sbostic extern int errno; 5738098Sbostic extern char *sys_errlist[]; 5838098Sbostic struct passwd *pwd; 5938098Sbostic int errs, pflag, port, rem, userid; 6038098Sbostic int iamremote, iamrecursive, targetshouldbedirectory; 616440Swnj 62*38100Sbostic #define CMDNEEDS 20 63*38100Sbostic char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 6438098Sbostic 6538098Sbostic typedef struct _buf { 6621254Smckusick int cnt; 6721254Smckusick char *buf; 6838098Sbostic } BUF; 6921254Smckusick 706440Swnj main(argc, argv) 716440Swnj int argc; 726440Swnj char **argv; 736440Swnj { 7438098Sbostic extern int optind; 7518126Sralph struct servent *sp; 7638099Sbostic int ch, fflag, tflag; 7738098Sbostic char *targ, *colon(); 7838098Sbostic struct passwd *getpwuid(); 7938098Sbostic int lostconn(); 8018026Sralph 8138098Sbostic #ifdef KERBEROS 8236626Skfall sp = getservbyname("kshell", "tcp"); 8338098Sbostic if (sp == NULL) { 8436626Skfall use_kerberos = 0; 8536626Skfall old_warning("kshell service unknown"); 8636626Skfall sp = getservbyname("kshell", "tcp"); 8736626Skfall } 8836626Skfall #else 8918026Sralph sp = getservbyname("shell", "tcp"); 9036626Skfall #endif 9138098Sbostic if (!sp) { 9238098Sbostic (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 9318026Sralph exit(1); 9418026Sralph } 9518126Sralph port = sp->s_port; 9638098Sbostic 9738098Sbostic if (!(pwd = getpwuid(userid = getuid()))) { 9838098Sbostic (void)fprintf(stderr, "rcp: unknown user %d.\n", userid); 996440Swnj exit(1); 1006440Swnj } 10123101Slepreau 10238099Sbostic fflag = tflag = 0; 10338098Sbostic while ((ch = getopt(argc, argv, "dfkprtx")) != EOF) 10438098Sbostic switch(ch) { 10538098Sbostic case 'd': 10638098Sbostic targetshouldbedirectory = 1; 10723101Slepreau break; 10838098Sbostic case 'f': /* "from" */ 10938099Sbostic fflag = 1; 11038099Sbostic break; 11138098Sbostic #ifdef KERBEROS 11238098Sbostic case 'k': 11336624Skfall strncpy(krb_realm, ++argv, REALM_SZ); 11436624Skfall break; 11536624Skfall #endif 11638098Sbostic case 'p': /* preserve access/mod times */ 11738098Sbostic ++pflag; 11823101Slepreau break; 11938098Sbostic case 'r': 12038098Sbostic ++iamrecursive; 12123101Slepreau break; 12238098Sbostic case 't': /* "to" */ 12338099Sbostic tflag = 1; 12438099Sbostic break; 12538098Sbostic #ifdef KERBEROS 12638098Sbostic case 'x': 12738098Sbostic encrypt = 1; 12838098Sbostic des_set_key(cred.session, schedule); 12938098Sbostic break; 13038098Sbostic #endif 13138098Sbostic case '?': 13238098Sbostic default: 13332127Sbostic usage(); 13423101Slepreau } 13538098Sbostic argc -= optind; 13638098Sbostic argv += optind; 13738098Sbostic 13838099Sbostic if (fflag) { 13938099Sbostic iamremote = 1; 14038099Sbostic (void)response(); 14138099Sbostic (void)setuid(userid); 14238099Sbostic source(argc, argv); 14338099Sbostic exit(errs); 14438099Sbostic } 14538099Sbostic 14638099Sbostic if (tflag) { 14738099Sbostic iamremote = 1; 14838099Sbostic (void)setuid(userid); 14938099Sbostic sink(argc, argv); 15038099Sbostic exit(errs); 15138099Sbostic } 15238099Sbostic 15332127Sbostic if (argc < 2) 15432127Sbostic usage(); 1556440Swnj if (argc > 2) 1566440Swnj targetshouldbedirectory = 1; 15738098Sbostic 15832127Sbostic rem = -1; 15938098Sbostic (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 16038098Sbostic pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 16138098Sbostic 16238098Sbostic (void)signal(SIGPIPE, lostconn); 16338098Sbostic 16438098Sbostic if (targ = colon(argv[argc - 1])) 16538098Sbostic toremote(targ, argc, argv); 16638098Sbostic else { 16738098Sbostic tolocal(argc, argv); 16838098Sbostic if (targetshouldbedirectory) 16938098Sbostic verifydir(argv[argc - 1]); 17038098Sbostic } 17138098Sbostic exit(errs); 17238098Sbostic } 17338098Sbostic 17438098Sbostic toremote(targ, argc, argv) 17538098Sbostic char *targ; 17638098Sbostic int argc; 17738098Sbostic char **argv; 17838098Sbostic { 17938098Sbostic int i; 180*38100Sbostic char *bp, *host, *src, *suser, *thost, *tuser; 181*38100Sbostic char *colon(), *malloc(); 18238098Sbostic 18338098Sbostic *targ++ = 0; 18438098Sbostic if (*targ == 0) 18538098Sbostic targ = "."; 18638098Sbostic 187*38100Sbostic if (thost = index(argv[argc - 1], '@')) { 18838098Sbostic *thost++ = 0; 18938098Sbostic tuser = argv[argc - 1]; 19038098Sbostic if (*tuser == '\0') 19124711Sbloom tuser = NULL; 19238098Sbostic else if (!okname(tuser)) 19338098Sbostic exit(1); 19438098Sbostic } else { 19538098Sbostic thost = argv[argc - 1]; 19638098Sbostic tuser = NULL; 19738098Sbostic } 19836624Skfall 19938098Sbostic for (i = 0; i < argc - 1; i++) { 20038098Sbostic src = colon(argv[i]); 20138098Sbostic if (src) { /* remote to remote */ 20238098Sbostic *src++ = 0; 20338098Sbostic if (*src == 0) 20438098Sbostic src = "."; 20538098Sbostic host = index(argv[i], '@'); 206*38100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_RSH) + 207*38100Sbostic strlen(argv[i]) + strlen(src) + 208*38100Sbostic strlen(tuser) + strlen(thost) + 209*38100Sbostic strlen(targ)) + CMDNEEDS + 20))) 210*38100Sbostic nospace(); 21138098Sbostic if (host) { 21238098Sbostic *host++ = 0; 21338098Sbostic suser = argv[i]; 21438098Sbostic if (*suser == '\0') 21538098Sbostic suser = pwd->pw_name; 21638098Sbostic else if (!okname(suser)) 21738098Sbostic continue; 218*38100Sbostic (void)sprintf(bp, 21938098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'", 22038098Sbostic _PATH_RSH, host, suser, cmd, src, 22138098Sbostic tuser ? tuser : "", tuser ? "@" : "", 22238098Sbostic thost, targ); 22338098Sbostic } else 224*38100Sbostic (void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'", 22538098Sbostic _PATH_RSH, argv[i], cmd, src, 22638098Sbostic tuser ? tuser : "", tuser ? "@" : "", 22738098Sbostic thost, targ); 228*38100Sbostic (void)susystem(bp); 229*38100Sbostic (void)free(bp); 23038098Sbostic } else { /* local to remote */ 23138098Sbostic if (rem == -1) { 232*38100Sbostic if (!(bp = malloc((u_int)strlen(targ) + 233*38100Sbostic CMDNEEDS + 20))) 234*38100Sbostic nospace(); 235*38100Sbostic (void)sprintf(bp, "%s -t %s", cmd, targ); 23638098Sbostic host = thost; 23738098Sbostic #ifdef KERBEROS 23838098Sbostic if (use_kerberos) 239*38100Sbostic kerberos(bp, 240*38100Sbostic tuser ? tuser : pwd->pw_name); 24138098Sbostic else 24238098Sbostic #endif 24324711Sbloom rem = rcmd(&host, port, pwd->pw_name, 24424711Sbloom tuser ? tuser : pwd->pw_name, 245*38100Sbostic bp, 0); 24638098Sbostic if (rem < 0) 24738098Sbostic exit(1); 24838098Sbostic if (response() < 0) 24938098Sbostic exit(1); 250*38100Sbostic (void)free(bp); 25138098Sbostic (void)setuid(userid); 2526440Swnj } 25338098Sbostic source(1, argv+i); 2546440Swnj } 25538098Sbostic } 25638098Sbostic } 25738098Sbostic 25838098Sbostic tolocal(argc, argv) 25938098Sbostic int argc; 26038098Sbostic char **argv; 26138098Sbostic { 26238098Sbostic int i; 263*38100Sbostic char *bp, *host, *src, *suser; 264*38100Sbostic char *colon(), *malloc(); 26538098Sbostic 26638098Sbostic for (i = 0; i < argc - 1; i++) { 267*38100Sbostic if (!(src = colon(argv[i]))) { /* local to local */ 268*38100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_CP) + 269*38100Sbostic strlen(argv[i]) + strlen(argv[argc - 1])) + 20))) 270*38100Sbostic nospace(); 271*38100Sbostic (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP, 272*38100Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 273*38100Sbostic argv[i], argv[argc - 1]); 274*38100Sbostic (void)susystem(bp); 275*38100Sbostic (void)free(bp); 276*38100Sbostic continue; 277*38100Sbostic } 278*38100Sbostic *src++ = 0; 279*38100Sbostic if (*src == 0) 280*38100Sbostic src = "."; 281*38100Sbostic host = index(argv[i], '@'); 282*38100Sbostic if (host) { 283*38100Sbostic *host++ = 0; 284*38100Sbostic suser = argv[i]; 285*38100Sbostic if (*suser == '\0') 28638098Sbostic suser = pwd->pw_name; 287*38100Sbostic else if (!okname(suser)) 288*38100Sbostic continue; 289*38100Sbostic } else { 290*38100Sbostic host = argv[i]; 291*38100Sbostic suser = pwd->pw_name; 292*38100Sbostic } 293*38100Sbostic if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20))) 294*38100Sbostic nospace(); 295*38100Sbostic (void)sprintf(bp, "%s -f %s", cmd, src); 29638098Sbostic #ifdef KERBEROS 297*38100Sbostic if (use_kerberos) 298*38100Sbostic kerberos(bp, suser); 299*38100Sbostic else 30038098Sbostic #endif 301*38100Sbostic rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0); 302*38100Sbostic (void)free(bp); 303*38100Sbostic if (rem < 0) 304*38100Sbostic continue; 305*38100Sbostic (void)setreuid(0, userid); 306*38100Sbostic sink(1, argv + argc - 1); 307*38100Sbostic (void)setreuid(userid, 0); 308*38100Sbostic (void)close(rem); 309*38100Sbostic rem = -1; 3106440Swnj } 3116440Swnj } 3126440Swnj 31338098Sbostic #ifdef KERBEROS 314*38100Sbostic kerberos(bp, user) 315*38100Sbostic char *bp, *user; 31638098Sbostic { 31738098Sbostic struct servent *sp; 31838098Sbostic char *host; 31938098Sbostic 32038098Sbostic again: rem = KSUCCESS; 32138098Sbostic if (krb_realm[0] == '\0') 32238098Sbostic rem = krb_get_lrealm(krb_realm, 1); 32338098Sbostic if (rem == KSUCCESS) { 32438098Sbostic if (encrypt) 325*38100Sbostic rem = krcmd_mutual(&host, port, user, bp, 0, 326*38100Sbostic krb_realm, &cred, schedule); 32738098Sbostic else 328*38100Sbostic rem = krcmd(&host, port, user, bp, 0, krb_realm); 32938098Sbostic } else { 33038098Sbostic (void)fprintf(stderr, 33138098Sbostic "rcp: error getting local realm %s\n", krb_err_txt[rem]); 33238098Sbostic exit(1); 33338098Sbostic } 33438098Sbostic if (rem < 0 && errno == ECONNREFUSED) { 33538098Sbostic use_kerberos = 0; 33638098Sbostic old_warning("remote host doesn't support Kerberos"); 33738098Sbostic sp = getservbyname("shell", "tcp"); 33838098Sbostic if (sp == NULL) { 33938098Sbostic (void)fprintf(stderr, 34038098Sbostic "rcp: unknown service shell/tcp\n"); 34138098Sbostic exit(1); 34238098Sbostic } 34338098Sbostic port = sp->s_port; 34438098Sbostic goto again; 34538098Sbostic } 34638098Sbostic } 34738098Sbostic #endif /* KERBEROS */ 34838098Sbostic 3496440Swnj verifydir(cp) 3506440Swnj char *cp; 3516440Swnj { 3526440Swnj struct stat stb; 3536440Swnj 35418126Sralph if (stat(cp, &stb) >= 0) { 35518126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 35618126Sralph return; 35718126Sralph errno = ENOTDIR; 35818126Sralph } 3596440Swnj error("rcp: %s: %s.\n", cp, sys_errlist[errno]); 3606440Swnj exit(1); 3616440Swnj } 3626440Swnj 3636440Swnj char * 3646440Swnj colon(cp) 36538098Sbostic register char *cp; 3666440Swnj { 36738098Sbostic for (; *cp; ++cp) { 3686440Swnj if (*cp == ':') 36938098Sbostic return(cp); 3706440Swnj if (*cp == '/') 37138098Sbostic return(0); 3726440Swnj } 37338098Sbostic return(0); 3746440Swnj } 3756440Swnj 3766440Swnj okname(cp0) 3776440Swnj char *cp0; 3786440Swnj { 3796440Swnj register char *cp = cp0; 3806440Swnj register int c; 3816440Swnj 3826440Swnj do { 3836440Swnj c = *cp; 3846440Swnj if (c & 0200) 3856440Swnj goto bad; 3866440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 3876440Swnj goto bad; 388*38100Sbostic } while (*++cp); 38938098Sbostic return(1); 3906440Swnj bad: 391*38100Sbostic (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0); 39238098Sbostic return(0); 3936440Swnj } 3946440Swnj 39517999Sserge susystem(s) 39617999Sserge char *s; 3976440Swnj { 39817999Sserge int status, pid, w; 39917999Sserge register int (*istat)(), (*qstat)(); 4006440Swnj 40117999Sserge if ((pid = vfork()) == 0) { 40238098Sbostic (void)setuid(userid); 40337037Sbostic execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 40417999Sserge _exit(127); 40517999Sserge } 40617999Sserge istat = signal(SIGINT, SIG_IGN); 40717999Sserge qstat = signal(SIGQUIT, SIG_IGN); 40817999Sserge while ((w = wait(&status)) != pid && w != -1) 40917999Sserge ; 41017999Sserge if (w == -1) 41117999Sserge status = -1; 41238098Sbostic (void)signal(SIGINT, istat); 41338098Sbostic (void)signal(SIGQUIT, qstat); 41438098Sbostic return(status); 4156440Swnj } 4166440Swnj 4176440Swnj source(argc, argv) 4186440Swnj int argc; 4196440Swnj char **argv; 4206440Swnj { 4216440Swnj struct stat stb; 42238098Sbostic static BUF buffer; 42338098Sbostic BUF *bp; 42438098Sbostic off_t i; 42532268Sbostic int x, readerr, f, amt; 42638098Sbostic char *last, *name, buf[BUFSIZ]; 42738098Sbostic BUF *allocbuf(); 4286440Swnj 4296440Swnj for (x = 0; x < argc; x++) { 4306440Swnj name = argv[x]; 43138098Sbostic if ((f = open(name, O_RDONLY, 0)) < 0) { 4326440Swnj error("rcp: %s: %s\n", name, sys_errlist[errno]); 4336440Swnj continue; 4346440Swnj } 4356440Swnj if (fstat(f, &stb) < 0) 4366440Swnj goto notreg; 4376440Swnj switch (stb.st_mode&S_IFMT) { 4386440Swnj 4396440Swnj case S_IFREG: 4406440Swnj break; 4416440Swnj 4426440Swnj case S_IFDIR: 4436440Swnj if (iamrecursive) { 44438098Sbostic (void)close(f); 44523101Slepreau rsource(name, &stb); 4466440Swnj continue; 4476440Swnj } 44838098Sbostic /* FALLTHROUGH */ 4496440Swnj default: 45038098Sbostic notreg: (void)close(f); 4516440Swnj error("rcp: %s: not a plain file\n", name); 4526440Swnj continue; 4536440Swnj } 4546440Swnj last = rindex(name, '/'); 4556440Swnj if (last == 0) 4566440Swnj last = name; 4576440Swnj else 4586440Swnj last++; 45923101Slepreau if (pflag) { 46023101Slepreau /* 46123101Slepreau * Make it compatible with possible future 46223101Slepreau * versions expecting microseconds. 46323101Slepreau */ 464*38100Sbostic (void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime, 465*38100Sbostic stb.st_atime); 46638098Sbostic (void)write(rem, buf, strlen(buf)); 46723101Slepreau if (response() < 0) { 46838098Sbostic (void)close(f); 46923101Slepreau continue; 47023101Slepreau } 47123101Slepreau } 472*38100Sbostic (void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777, 473*38100Sbostic stb.st_size, last); 47438098Sbostic (void)write(rem, buf, strlen(buf)); 4756440Swnj if (response() < 0) { 47638098Sbostic (void)close(f); 4776440Swnj continue; 4786440Swnj } 47935689Sbostic if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { 48038098Sbostic (void)close(f); 48121254Smckusick continue; 48221254Smckusick } 48332268Sbostic readerr = 0; 48421254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 48521254Smckusick amt = bp->cnt; 4866440Swnj if (i + amt > stb.st_size) 4876440Swnj amt = stb.st_size - i; 48832268Sbostic if (readerr == 0 && read(f, bp->buf, amt) != amt) 48932268Sbostic readerr = errno; 49038098Sbostic (void)write(rem, bp->buf, amt); 4916440Swnj } 49238098Sbostic (void)close(f); 49332268Sbostic if (readerr == 0) 49438098Sbostic (void)write(rem, "", 1); 4956440Swnj else 49632268Sbostic error("rcp: %s: %s\n", name, sys_errlist[readerr]); 49738098Sbostic (void)response(); 4986440Swnj } 4996440Swnj } 5006440Swnj 50123101Slepreau rsource(name, statp) 5026440Swnj char *name; 50323101Slepreau struct stat *statp; 5046440Swnj { 50538098Sbostic DIR *d; 5066440Swnj struct direct *dp; 507*38100Sbostic char *last, *vect[1], path[MAXPATHLEN]; 5086440Swnj 50938098Sbostic if (!(d = opendir(name))) { 51018126Sralph error("rcp: %s: %s\n", name, sys_errlist[errno]); 5116440Swnj return; 5126440Swnj } 5136440Swnj last = rindex(name, '/'); 5146440Swnj if (last == 0) 5156440Swnj last = name; 5166440Swnj else 5176440Swnj last++; 51823101Slepreau if (pflag) { 519*38100Sbostic (void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime, 520*38100Sbostic statp->st_atime); 521*38100Sbostic (void)write(rem, path, strlen(path)); 52223101Slepreau if (response() < 0) { 52323101Slepreau closedir(d); 52423101Slepreau return; 52523101Slepreau } 52623101Slepreau } 527*38100Sbostic (void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 528*38100Sbostic (void)write(rem, path, strlen(path)); 5296440Swnj if (response() < 0) { 5306440Swnj closedir(d); 5316440Swnj return; 5326440Swnj } 5336440Swnj while (dp = readdir(d)) { 5346440Swnj if (dp->d_ino == 0) 5356440Swnj continue; 5366440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 5376440Swnj continue; 538*38100Sbostic if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 539*38100Sbostic error("%s/%s: name too long.\n", name, dp->d_name); 5406440Swnj continue; 5416440Swnj } 542*38100Sbostic (void)sprintf(path, "%s/%s", name, dp->d_name); 543*38100Sbostic vect[0] = path; 544*38100Sbostic source(1, vect); 5456440Swnj } 5466440Swnj closedir(d); 54738098Sbostic (void)write(rem, "E\n", 2); 54838098Sbostic (void)response(); 5496440Swnj } 5506440Swnj 5516440Swnj response() 5526440Swnj { 55338098Sbostic register char *cp; 55438098Sbostic char ch, resp, rbuf[BUFSIZ]; 5556440Swnj 55638098Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 5576440Swnj lostconn(); 5586440Swnj 55938098Sbostic cp = rbuf; 56038098Sbostic switch(resp) { 56123101Slepreau case 0: /* ok */ 56238098Sbostic return(0); 5636440Swnj default: 5646440Swnj *cp++ = resp; 56538098Sbostic /* FALLTHROUGH */ 56623101Slepreau case 1: /* error, followed by err msg */ 56723101Slepreau case 2: /* fatal error, "" */ 5686440Swnj do { 56938098Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 5706440Swnj lostconn(); 57138098Sbostic *cp++ = ch; 57238098Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 57338098Sbostic 57438098Sbostic if (!iamremote) 57538098Sbostic (void)write(2, rbuf, cp - rbuf); 57638098Sbostic ++errs; 5776440Swnj if (resp == 1) 57838098Sbostic return(-1); 5796440Swnj exit(1); 5806440Swnj } 5816440Swnj /*NOTREACHED*/ 5826440Swnj } 5836440Swnj 5846440Swnj lostconn() 5856440Swnj { 58638098Sbostic if (!iamremote) 58738098Sbostic (void)fprintf(stderr, "rcp: lost connection\n"); 5886440Swnj exit(1); 5896440Swnj } 5906440Swnj 5916440Swnj sink(argc, argv) 5926440Swnj int argc; 5936440Swnj char **argv; 5946440Swnj { 595*38100Sbostic register char *cp; 59638098Sbostic static BUF buffer; 59721254Smckusick struct stat stb; 59823101Slepreau struct timeval tv[2]; 599*38100Sbostic BUF *bp, *allocbuf(); 600*38100Sbostic off_t i, j; 601*38100Sbostic char ch, *targ, *why; 602*38100Sbostic int amt, count, exists, first, mask, mode; 603*38100Sbostic int ofd, setimes, size, targisdir, wrerr; 604*38100Sbostic char *np, *vect[1], buf[BUFSIZ], *malloc(); 6056440Swnj 606*38100Sbostic #define atime tv[0] 607*38100Sbostic #define mtime tv[1] 608*38100Sbostic #define SCREWUP(str) { why = str; goto screwup; } 609*38100Sbostic 610*38100Sbostic setimes = targisdir = 0; 611*38100Sbostic mask = umask(0); 61223112Slepreau if (!pflag) 61338098Sbostic (void)umask(mask); 61418126Sralph if (argc != 1) { 6156440Swnj error("rcp: ambiguous target\n"); 6166440Swnj exit(1); 6176440Swnj } 6186440Swnj targ = *argv; 6196440Swnj if (targetshouldbedirectory) 6206440Swnj verifydir(targ); 62138098Sbostic (void)write(rem, "", 1); 6226440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 6236440Swnj targisdir = 1; 624*38100Sbostic for (first = 1;; first = 0) { 625*38100Sbostic cp = buf; 6266440Swnj if (read(rem, cp, 1) <= 0) 6276440Swnj return; 6286440Swnj if (*cp++ == '\n') 629*38100Sbostic SCREWUP("unexpected <newline>"); 6306440Swnj do { 631*38100Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 6326440Swnj SCREWUP("lost connection"); 633*38100Sbostic *cp++ = ch; 634*38100Sbostic } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 635*38100Sbostic if (ch == '\n') 636*38100Sbostic *--cp; 6376440Swnj *cp = 0; 638*38100Sbostic 639*38100Sbostic if (buf[0] == '\01' || buf[0] == '\02') { 6406440Swnj if (iamremote == 0) 641*38100Sbostic (void)write(2, buf + 1, strlen(buf + 1)); 642*38100Sbostic if (buf[0] == '\02') 6436440Swnj exit(1); 6446440Swnj errs++; 6456440Swnj continue; 6466440Swnj } 647*38100Sbostic if (buf[0] == 'E') { 64838098Sbostic (void)write(rem, "", 1); 6496440Swnj return; 6506440Swnj } 65123101Slepreau 65223101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 653*38100Sbostic cp = buf; 65423101Slepreau if (*cp == 'T') { 65523101Slepreau setimes++; 65623101Slepreau cp++; 65723101Slepreau getnum(mtime.tv_sec); 65823101Slepreau if (*cp++ != ' ') 65923101Slepreau SCREWUP("mtime.sec not delimited"); 66023101Slepreau getnum(mtime.tv_usec); 66123101Slepreau if (*cp++ != ' ') 66223101Slepreau SCREWUP("mtime.usec not delimited"); 66323101Slepreau getnum(atime.tv_sec); 66423101Slepreau if (*cp++ != ' ') 66523101Slepreau SCREWUP("atime.sec not delimited"); 66623101Slepreau getnum(atime.tv_usec); 66723101Slepreau if (*cp++ != '\0') 66823101Slepreau SCREWUP("atime.usec not delimited"); 66938098Sbostic (void)write(rem, "", 1); 67023101Slepreau continue; 67123101Slepreau } 67214580Sralph if (*cp != 'C' && *cp != 'D') { 67314580Sralph /* 67414580Sralph * Check for the case "rcp remote:foo\* local:bar". 67514580Sralph * In this case, the line "No match." can be returned 67614580Sralph * by the shell before the rcp command on the remote is 67714580Sralph * executed so the ^Aerror_message convention isn't 67814580Sralph * followed. 67914580Sralph */ 68014580Sralph if (first) { 68114580Sralph error("%s\n", cp); 68214580Sralph exit(1); 68314580Sralph } 6846440Swnj SCREWUP("expected control record"); 68514580Sralph } 6866440Swnj mode = 0; 687*38100Sbostic for (++cp; cp < buf + 5; cp++) { 6886440Swnj if (*cp < '0' || *cp > '7') 6896440Swnj SCREWUP("bad mode"); 6906440Swnj mode = (mode << 3) | (*cp - '0'); 6916440Swnj } 6926440Swnj if (*cp++ != ' ') 6936440Swnj SCREWUP("mode not delimited"); 6946440Swnj size = 0; 69523112Slepreau while (isdigit(*cp)) 6966440Swnj size = size * 10 + (*cp++ - '0'); 6976440Swnj if (*cp++ != ' ') 6986440Swnj SCREWUP("size not delimited"); 699*38100Sbostic if (targisdir) { 700*38100Sbostic static char *namebuf; 701*38100Sbostic static int cursize; 702*38100Sbostic int need; 703*38100Sbostic 704*38100Sbostic need = strlen(targ) + strlen(cp) + 250; 705*38100Sbostic if (need > cursize) { 706*38100Sbostic if (!(namebuf = malloc((u_int)need))) 707*38100Sbostic error("out of memory"); 708*38100Sbostic } 709*38100Sbostic (void)sprintf(namebuf, "%s%s%s", targ, 7106440Swnj *targ ? "/" : "", cp); 711*38100Sbostic np = namebuf; 712*38100Sbostic } 7136440Swnj else 714*38100Sbostic np = targ; 715*38100Sbostic exists = stat(np, &stb) == 0; 716*38100Sbostic if (buf[0] == 'D') { 71718126Sralph if (exists) { 7186440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 7196440Swnj errno = ENOTDIR; 7206440Swnj goto bad; 7216440Swnj } 72223112Slepreau if (pflag) 723*38100Sbostic (void)chmod(np, mode); 724*38100Sbostic } else if (mkdir(np, mode) < 0) 7256440Swnj goto bad; 726*38100Sbostic vect[0] = np; 727*38100Sbostic sink(1, vect); 72823101Slepreau if (setimes) { 72923101Slepreau setimes = 0; 730*38100Sbostic if (utimes(np, tv) < 0) 731*38100Sbostic error("rcp: can't set times on %s: %s\n", 732*38100Sbostic np, sys_errlist[errno]); 73323101Slepreau } 7346440Swnj continue; 73518126Sralph } 736*38100Sbostic if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 737*38100Sbostic bad: error("rcp: %s: %s\n", np, sys_errlist[errno]); 7386440Swnj continue; 7396440Swnj } 74023112Slepreau if (exists && pflag) 741*38100Sbostic (void)fchmod(ofd, mode); 74238098Sbostic (void)write(rem, "", 1); 743*38100Sbostic if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) { 744*38100Sbostic (void)close(ofd); 74521254Smckusick continue; 74621254Smckusick } 74721254Smckusick cp = bp->buf; 74821254Smckusick count = 0; 7496440Swnj wrerr = 0; 7506440Swnj for (i = 0; i < size; i += BUFSIZ) { 75121254Smckusick amt = BUFSIZ; 7526440Swnj if (i + amt > size) 7536440Swnj amt = size - i; 75421254Smckusick count += amt; 7556440Swnj do { 75621254Smckusick j = read(rem, cp, amt); 75724711Sbloom if (j <= 0) { 758*38100Sbostic error("rcp: %s", 759*38100Sbostic j ? sys_errlist[errno] : 760*38100Sbostic "dropped connection"); 7616440Swnj exit(1); 76224711Sbloom } 7636440Swnj amt -= j; 7646440Swnj cp += j; 7656440Swnj } while (amt > 0); 76621254Smckusick if (count == bp->cnt) { 76721254Smckusick if (wrerr == 0 && 768*38100Sbostic write(ofd, bp->buf, count) != count) 76921254Smckusick wrerr++; 77021254Smckusick count = 0; 77121254Smckusick cp = bp->buf; 77221254Smckusick } 7736440Swnj } 77421254Smckusick if (count != 0 && wrerr == 0 && 775*38100Sbostic write(ofd, bp->buf, count) != count) 77621254Smckusick wrerr++; 777*38100Sbostic if (ftruncate(ofd, size)) 778*38100Sbostic error("rcp: can't truncate %s: %s\n", np, 779*38100Sbostic sys_errlist[errno]); 780*38100Sbostic (void)close(ofd); 78138098Sbostic (void)response(); 78223101Slepreau if (setimes) { 78323101Slepreau setimes = 0; 784*38100Sbostic if (utimes(np, tv) < 0) 78523101Slepreau error("rcp: can't set times on %s: %s\n", 786*38100Sbostic np, sys_errlist[errno]); 78723101Slepreau } 7886440Swnj if (wrerr) 789*38100Sbostic error("rcp: %s: %s\n", np, sys_errlist[errno]); 7906440Swnj else 79138098Sbostic (void)write(rem, "", 1); 7926440Swnj } 7936440Swnj screwup: 794*38100Sbostic error("rcp: protocol screwup: %s\n", why); 7956440Swnj exit(1); 7966440Swnj } 7976440Swnj 79838098Sbostic BUF * 79921254Smckusick allocbuf(bp, fd, blksize) 80038098Sbostic BUF *bp; 80121254Smckusick int fd, blksize; 80221254Smckusick { 80321254Smckusick struct stat stb; 80421254Smckusick int size; 80538098Sbostic char *malloc(); 80621254Smckusick 80721254Smckusick if (fstat(fd, &stb) < 0) { 80821254Smckusick error("rcp: fstat: %s\n", sys_errlist[errno]); 80938098Sbostic return(0); 81021254Smckusick } 81121254Smckusick size = roundup(stb.st_blksize, blksize); 81221254Smckusick if (size == 0) 81321254Smckusick size = blksize; 81421254Smckusick if (bp->cnt < size) { 81521254Smckusick if (bp->buf != 0) 81621254Smckusick free(bp->buf); 81738098Sbostic bp->buf = (char *)malloc((u_int)size); 818*38100Sbostic if (!bp->buf) { 81921254Smckusick error("rcp: malloc: out of memory\n"); 82038098Sbostic return(0); 82121254Smckusick } 82221254Smckusick } 82321254Smckusick bp->cnt = size; 82438098Sbostic return(bp); 82521254Smckusick } 82621254Smckusick 82738098Sbostic /* VARARGS1 */ 828*38100Sbostic error(fmt, a1, a2, a3) 8296440Swnj char *fmt; 830*38100Sbostic int a1, a2, a3; 8316440Swnj { 83238098Sbostic int len; 83338098Sbostic char buf[BUFSIZ]; 8346440Swnj 83538098Sbostic ++errs; 83638098Sbostic buf[0] = 0x01; 837*38100Sbostic (void)sprintf(buf + 1, fmt, a1, a2, a3); 83838098Sbostic len = strlen(buf); 83938098Sbostic (void)write(rem, buf, len); 84038098Sbostic if (!iamremote) 84138098Sbostic (void)write(2, buf + 1, len - 1); 8426440Swnj } 84332127Sbostic 844*38100Sbostic nospace() 845*38100Sbostic { 846*38100Sbostic (void)fprintf(stderr, "rcp: out of memory.\n"); 847*38100Sbostic exit(1); 848*38100Sbostic } 849*38100Sbostic 850*38100Sbostic #ifdef KERBEROS 851*38100Sbostic old_warning(str) 852*38100Sbostic char *str; 853*38100Sbostic { 854*38100Sbostic (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); 855*38100Sbostic } 856*38100Sbostic #endif 857*38100Sbostic 85832127Sbostic usage() 85932127Sbostic { 86038098Sbostic #ifdef KERBEROS 86138098Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 86238098Sbostic "usage: rcp [-k realm] [-px] f1 f2", 86338098Sbostic "or: rcp [-k realm] [-rpx] f1 ... fn directory"); 86436626Skfall #else 86538098Sbostic (void)fprintf(stderr, 86638098Sbostic "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); 86736626Skfall #endif 86832127Sbostic exit(1); 86932127Sbostic } 870