121569Sdist /* 221569Sdist * Copyright (c) 1983 Regents of the University of California. 321569Sdist * All rights reserved. The Berkeley software License Agreement 421569Sdist * specifies the terms and conditions for redistribution. 521569Sdist */ 621569Sdist 76440Swnj #ifndef lint 821569Sdist char copyright[] = 921569Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\ 1021569Sdist All rights reserved.\n"; 1121569Sdist #endif not lint 126440Swnj 1321569Sdist #ifndef lint 14*23112Slepreau static char sccsid[] = "@(#)rcp.c 5.3 (Berkeley) 06/08/85"; 1521569Sdist #endif not lint 1621569Sdist 1712989Ssam /* 1812989Ssam * rcp 1912989Ssam */ 206720Smckusick #include <sys/param.h> 216440Swnj #include <sys/stat.h> 2223101Slepreau #include <sys/time.h> 236440Swnj #include <sys/ioctl.h> 249199Ssam 259199Ssam #include <netinet/in.h> 269199Ssam 279199Ssam #include <stdio.h> 289199Ssam #include <signal.h> 296440Swnj #include <pwd.h> 306440Swnj #include <ctype.h> 3118026Sralph #include <netdb.h> 326440Swnj #include <errno.h> 3312989Ssam 346440Swnj int rem; 356440Swnj char *colon(), *index(), *rindex(), *malloc(), *strcpy(), *sprintf(); 366440Swnj int errs; 376440Swnj int lostconn(); 386440Swnj int errno; 396440Swnj char *sys_errlist[]; 406440Swnj int iamremote, targetshouldbedirectory; 416440Swnj int iamrecursive; 4223101Slepreau int pflag; 436440Swnj struct passwd *pwd; 446440Swnj struct passwd *getpwuid(); 4518126Sralph int userid; 4618126Sralph int port; 476440Swnj 4821254Smckusick struct buffer { 4921254Smckusick int cnt; 5021254Smckusick char *buf; 5121254Smckusick } *allocbuf(); 5221254Smckusick 536440Swnj /*VARARGS*/ 546440Swnj int error(); 556440Swnj 566440Swnj #define ga() (void) write(rem, "", 1) 576440Swnj 586440Swnj main(argc, argv) 596440Swnj int argc; 606440Swnj char **argv; 616440Swnj { 626440Swnj char *targ, *host, *src; 6318631Sralph #ifndef NAMESERVER 6418631Sralph char *suser, *tuser; 6518631Sralph #else NAMESERVER 6618259Sralph char *suser, *tuser, *thost; 6718631Sralph #endif NAMESERVER 686440Swnj int i; 696440Swnj char buf[BUFSIZ], cmd[16]; 7018126Sralph struct servent *sp; 7118026Sralph 7218026Sralph sp = getservbyname("shell", "tcp"); 7318026Sralph if (sp == NULL) { 7418026Sralph fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 7518026Sralph exit(1); 7618026Sralph } 7718126Sralph port = sp->s_port; 7818126Sralph pwd = getpwuid(userid = getuid()); 796440Swnj if (pwd == 0) { 806440Swnj fprintf(stderr, "who are you?\n"); 816440Swnj exit(1); 826440Swnj } 8323101Slepreau 8423101Slepreau for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) { 8523101Slepreau (*argv)++; 8623101Slepreau while (**argv) switch (*(*argv)++) { 8723101Slepreau 8823101Slepreau case 'r': 8923101Slepreau iamrecursive++; 9023101Slepreau break; 9123101Slepreau 9223101Slepreau case 'p': /* preserve mtimes and atimes */ 9323101Slepreau pflag++; 9423101Slepreau break; 9523101Slepreau 9623101Slepreau /* The rest of these are not for users. */ 9723101Slepreau case 'd': 9823101Slepreau targetshouldbedirectory = 1; 9923101Slepreau break; 10023101Slepreau 10123101Slepreau case 'f': /* "from" */ 10223101Slepreau iamremote = 1; 10323101Slepreau (void) response(); 10423101Slepreau (void) setuid(userid); 10523101Slepreau source(--argc, ++argv); 10623101Slepreau exit(errs); 10723101Slepreau 10823101Slepreau case 't': /* "to" */ 10923101Slepreau iamremote = 1; 11023101Slepreau (void) setuid(userid); 11123101Slepreau sink(--argc, ++argv); 11223101Slepreau exit(errs); 11323101Slepreau 11423101Slepreau default: 11523101Slepreau fprintf(stderr, 116*23112Slepreau "Usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n"); 11723101Slepreau exit(1); 11823101Slepreau } 1196440Swnj } 1206440Swnj rem = -1; 1216440Swnj if (argc > 2) 1226440Swnj targetshouldbedirectory = 1; 12323101Slepreau (void) sprintf(cmd, "rcp%s%s%s", 12423101Slepreau iamrecursive ? " -r" : "", pflag ? " -p" : "", 12523101Slepreau targetshouldbedirectory ? " -d" : ""); 12623101Slepreau (void) signal(SIGPIPE, lostconn); 1276440Swnj targ = colon(argv[argc - 1]); 12823101Slepreau if (targ) { /* ... to remote */ 1296440Swnj *targ++ = 0; 13013542Ssam if (*targ == 0) 13113542Ssam targ = "."; 13218631Sralph #ifndef NAMESERVER 13318631Sralph tuser = rindex(argv[argc - 1], '.'); 13418631Sralph if (tuser) { 13518631Sralph *tuser++ = 0; 13618631Sralph if (!okname(tuser)) 13718631Sralph exit(1); 13818631Sralph } else 13918631Sralph tuser = pwd->pw_name; 14018631Sralph #else NAMESERVER 14118259Sralph thost = index(argv[argc - 1], '@'); 14218259Sralph if (thost) { 14318259Sralph *thost++ = 0; 14418259Sralph tuser = argv[argc - 1]; 14518259Sralph if (*tuser == '\0') 14618259Sralph tuser = pwd->pw_name; 14718259Sralph else if (!okname(tuser)) 1486440Swnj exit(1); 14918259Sralph } else { 15018259Sralph thost = argv[argc - 1]; 1516440Swnj tuser = pwd->pw_name; 15218259Sralph } 15318631Sralph #endif NAMESERVER 1546440Swnj for (i = 0; i < argc - 1; i++) { 1556440Swnj src = colon(argv[i]); 15623101Slepreau if (src) { /* remote to remote */ 1576440Swnj *src++ = 0; 15813542Ssam if (*src == 0) 15913738Ssam src = "."; 16018631Sralph #ifndef NAMESERVER 16118631Sralph suser = rindex(argv[i], '.'); 16218631Sralph if (suser) { 16318631Sralph *suser++ = 0; 16418631Sralph if (!okname(suser)) 16518631Sralph #else NAMESERVER 16618259Sralph host = index(argv[i], '@'); 16718259Sralph if (host) { 16818259Sralph *host++ = 0; 16918259Sralph suser = argv[i]; 17018259Sralph if (*suser == '\0') 17118259Sralph suser = pwd->pw_name; 17218259Sralph else if (!okname(suser)) 17318631Sralph #endif NAMESERVER 1746440Swnj continue; 17518631Sralph #ifndef NAMESERVER 17618631Sralph (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s.%s:%s'", 17718631Sralph argv[i], suser, cmd, src, 17818631Sralph argv[argc - 1], tuser, targ); 17918631Sralph } else 18018631Sralph (void) sprintf(buf, "rsh %s -n %s %s '%s.%s:%s'", 18118631Sralph argv[i], cmd, src, 18218631Sralph argv[argc - 1], tuser, targ); 18318631Sralph #else NAMESERVER 18418259Sralph (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s@%s:%s'", 18518259Sralph host, suser, cmd, src, 18618259Sralph tuser, thost, targ); 1876440Swnj } else 18818259Sralph (void) sprintf(buf, "rsh %s -n %s %s '%s@%s:%s'", 18915898Sralph argv[i], cmd, src, 19018259Sralph tuser, thost, targ); 19118631Sralph #endif NAMESERVER 1926440Swnj (void) susystem(buf); 19323101Slepreau } else { /* local to remote */ 1946440Swnj if (rem == -1) { 1956440Swnj (void) sprintf(buf, "%s -t %s", 1966440Swnj cmd, targ); 19718631Sralph #ifndef NAMESERVER 19818631Sralph host = argv[argc - 1]; 19918631Sralph #else NAMESERVER 20018259Sralph host = thost; 20118631Sralph #endif NAMESERVER 20218126Sralph rem = rcmd(&host, port, pwd->pw_name, tuser, 2036440Swnj buf, 0); 2046440Swnj if (rem < 0) 2056440Swnj exit(1); 2066440Swnj if (response() < 0) 2076440Swnj exit(1); 20818126Sralph (void) setuid(userid); 2096440Swnj } 2106440Swnj source(1, argv+i); 2116440Swnj } 2126440Swnj } 21323101Slepreau } else { /* ... to local */ 2146440Swnj if (targetshouldbedirectory) 2156440Swnj verifydir(argv[argc - 1]); 2166440Swnj for (i = 0; i < argc - 1; i++) { 2176440Swnj src = colon(argv[i]); 21823101Slepreau if (src == 0) { /* local to local */ 21923101Slepreau (void) sprintf(buf, "/bin/cp%s%s %s %s", 2206440Swnj iamrecursive ? " -r" : "", 22123101Slepreau pflag ? " -p" : "", 2226440Swnj argv[i], argv[argc - 1]); 2236440Swnj (void) susystem(buf); 22423101Slepreau } else { /* remote to local */ 2256440Swnj *src++ = 0; 22613542Ssam if (*src == 0) 22713542Ssam src = "."; 22818631Sralph #ifndef NAMESERVER 22918631Sralph suser = rindex(argv[i], '.'); 23018631Sralph if (suser) { 23118631Sralph *suser++ = 0; 23218631Sralph if (!okname(suser)) 23318631Sralph #else NAMESERVER 23418259Sralph host = index(argv[i], '@'); 23518259Sralph if (host) { 23618259Sralph *host++ = 0; 23718259Sralph suser = argv[i]; 23818259Sralph if (*suser == '\0') 23918259Sralph suser = pwd->pw_name; 24018259Sralph else if (!okname(suser)) 24118631Sralph #endif NAMESERVER 2426440Swnj continue; 24318631Sralph #ifndef NAMESERVER 24418631Sralph } else 24518631Sralph #else NAMESERVER 24618259Sralph } else { 24718259Sralph host = argv[i]; 24818631Sralph #endif NAMESERVER 2496440Swnj suser = pwd->pw_name; 25018631Sralph #ifdef NAMESERVER 25118259Sralph } 25218631Sralph #endif NAMESERVER 2536440Swnj (void) sprintf(buf, "%s -f %s", cmd, src); 25418631Sralph #ifndef NAMESERVER 25518631Sralph host = argv[i]; 25618631Sralph #endif NAMESERVER 25718126Sralph rem = rcmd(&host, port, pwd->pw_name, suser, 2586440Swnj buf, 0); 2596440Swnj if (rem < 0) 26018259Sralph continue; 26118126Sralph (void) setreuid(0, userid); 2626440Swnj sink(1, argv+argc-1); 26318126Sralph (void) setreuid(userid, 0); 2646440Swnj (void) close(rem); 2656440Swnj rem = -1; 2666440Swnj } 2676440Swnj } 2686440Swnj } 2696440Swnj exit(errs); 2706440Swnj } 2716440Swnj 2726440Swnj verifydir(cp) 2736440Swnj char *cp; 2746440Swnj { 2756440Swnj struct stat stb; 2766440Swnj 27718126Sralph if (stat(cp, &stb) >= 0) { 27818126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 27918126Sralph return; 28018126Sralph errno = ENOTDIR; 28118126Sralph } 2826440Swnj error("rcp: %s: %s.\n", cp, sys_errlist[errno]); 2836440Swnj exit(1); 2846440Swnj } 2856440Swnj 2866440Swnj char * 2876440Swnj colon(cp) 2886440Swnj char *cp; 2896440Swnj { 2906440Swnj 2916440Swnj while (*cp) { 2926440Swnj if (*cp == ':') 2936440Swnj return (cp); 2946440Swnj if (*cp == '/') 2956440Swnj return (0); 2966440Swnj cp++; 2976440Swnj } 2986440Swnj return (0); 2996440Swnj } 3006440Swnj 3016440Swnj okname(cp0) 3026440Swnj char *cp0; 3036440Swnj { 3046440Swnj register char *cp = cp0; 3056440Swnj register int c; 3066440Swnj 3076440Swnj do { 3086440Swnj c = *cp; 3096440Swnj if (c & 0200) 3106440Swnj goto bad; 3116440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 3126440Swnj goto bad; 3136440Swnj cp++; 3146440Swnj } while (*cp); 3156440Swnj return (1); 3166440Swnj bad: 3176440Swnj fprintf(stderr, "rcp: invalid user name %s\n", cp0); 3186440Swnj return (0); 3196440Swnj } 3206440Swnj 32117999Sserge susystem(s) 32217999Sserge char *s; 3236440Swnj { 32417999Sserge int status, pid, w; 32517999Sserge register int (*istat)(), (*qstat)(); 3266440Swnj 32717999Sserge if ((pid = vfork()) == 0) { 32823101Slepreau (void) setuid(userid); 32917999Sserge execl("/bin/sh", "sh", "-c", s, (char *)0); 33017999Sserge _exit(127); 33117999Sserge } 33217999Sserge istat = signal(SIGINT, SIG_IGN); 33317999Sserge qstat = signal(SIGQUIT, SIG_IGN); 33417999Sserge while ((w = wait(&status)) != pid && w != -1) 33517999Sserge ; 33617999Sserge if (w == -1) 33717999Sserge status = -1; 33823101Slepreau (void) signal(SIGINT, istat); 33923101Slepreau (void) signal(SIGQUIT, qstat); 34017999Sserge return (status); 3416440Swnj } 3426440Swnj 3436440Swnj source(argc, argv) 3446440Swnj int argc; 3456440Swnj char **argv; 3466440Swnj { 3476440Swnj char *last, *name; 3486440Swnj struct stat stb; 34921254Smckusick static struct buffer buffer; 35021254Smckusick struct buffer *bp; 35121254Smckusick int x, sizerr, f, amt; 35221254Smckusick off_t i; 3536440Swnj char buf[BUFSIZ]; 3546440Swnj 3556440Swnj for (x = 0; x < argc; x++) { 3566440Swnj name = argv[x]; 35718126Sralph if ((f = open(name, 0)) < 0) { 3586440Swnj error("rcp: %s: %s\n", name, sys_errlist[errno]); 3596440Swnj continue; 3606440Swnj } 3616440Swnj if (fstat(f, &stb) < 0) 3626440Swnj goto notreg; 3636440Swnj switch (stb.st_mode&S_IFMT) { 3646440Swnj 3656440Swnj case S_IFREG: 3666440Swnj break; 3676440Swnj 3686440Swnj case S_IFDIR: 3696440Swnj if (iamrecursive) { 3706440Swnj (void) close(f); 37123101Slepreau rsource(name, &stb); 3726440Swnj continue; 3736440Swnj } 3746440Swnj /* fall into ... */ 3756440Swnj default: 3766440Swnj notreg: 3776440Swnj (void) close(f); 3786440Swnj error("rcp: %s: not a plain file\n", name); 3796440Swnj continue; 3806440Swnj } 3816440Swnj last = rindex(name, '/'); 3826440Swnj if (last == 0) 3836440Swnj last = name; 3846440Swnj else 3856440Swnj last++; 38623101Slepreau if (pflag) { 38723101Slepreau /* 38823101Slepreau * Make it compatible with possible future 38923101Slepreau * versions expecting microseconds. 39023101Slepreau */ 39123101Slepreau (void) sprintf(buf, "T%ld 0 %ld 0\n", 39223101Slepreau stb.st_mtime, stb.st_atime); 39323101Slepreau (void) write(rem, buf, strlen(buf)); 39423101Slepreau if (response() < 0) { 39523101Slepreau (void) close(f); 39623101Slepreau continue; 39723101Slepreau } 39823101Slepreau } 39923101Slepreau (void) sprintf(buf, "C%04o %ld %s\n", 4006440Swnj stb.st_mode&07777, stb.st_size, last); 4016440Swnj (void) write(rem, buf, strlen(buf)); 4026440Swnj if (response() < 0) { 4036440Swnj (void) close(f); 4046440Swnj continue; 4056440Swnj } 40621254Smckusick if ((bp = allocbuf(&buffer, f, BUFSIZ)) < 0) { 40721254Smckusick (void) close(f); 40821254Smckusick continue; 40921254Smckusick } 4106440Swnj sizerr = 0; 41121254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 41221254Smckusick amt = bp->cnt; 4136440Swnj if (i + amt > stb.st_size) 4146440Swnj amt = stb.st_size - i; 41521254Smckusick if (sizerr == 0 && read(f, bp->buf, amt) != amt) 4166440Swnj sizerr = 1; 41721254Smckusick (void) write(rem, bp->buf, amt); 4186440Swnj } 4196440Swnj (void) close(f); 4206440Swnj if (sizerr == 0) 4216440Swnj ga(); 4226440Swnj else 4236440Swnj error("rcp: %s: file changed size\n", name); 4246440Swnj (void) response(); 4256440Swnj } 4266440Swnj } 4276440Swnj 42813542Ssam #include <sys/dir.h> 4296440Swnj 43023101Slepreau rsource(name, statp) 4316440Swnj char *name; 43223101Slepreau struct stat *statp; 4336440Swnj { 4346440Swnj DIR *d = opendir(name); 4356440Swnj char *last; 4366440Swnj struct direct *dp; 4376440Swnj char buf[BUFSIZ]; 4386440Swnj char *bufv[1]; 4396440Swnj 4406440Swnj if (d == 0) { 44118126Sralph error("rcp: %s: %s\n", name, sys_errlist[errno]); 4426440Swnj return; 4436440Swnj } 4446440Swnj last = rindex(name, '/'); 4456440Swnj if (last == 0) 4466440Swnj last = name; 4476440Swnj else 4486440Swnj last++; 44923101Slepreau if (pflag) { 45023101Slepreau (void) sprintf(buf, "T%ld 0 %ld 0\n", 45123101Slepreau statp->st_mtime, statp->st_atime); 45223101Slepreau (void) write(rem, buf, strlen(buf)); 45323101Slepreau if (response() < 0) { 45423101Slepreau closedir(d); 45523101Slepreau return; 45623101Slepreau } 45723101Slepreau } 45823101Slepreau (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 4596440Swnj (void) write(rem, buf, strlen(buf)); 4606440Swnj if (response() < 0) { 4616440Swnj closedir(d); 4626440Swnj return; 4636440Swnj } 4646440Swnj while (dp = readdir(d)) { 4656440Swnj if (dp->d_ino == 0) 4666440Swnj continue; 4676440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 4686440Swnj continue; 4696440Swnj if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 4706440Swnj error("%s/%s: Name too long.\n", name, dp->d_name); 4716440Swnj continue; 4726440Swnj } 4736440Swnj (void) sprintf(buf, "%s/%s", name, dp->d_name); 4746440Swnj bufv[0] = buf; 4756440Swnj source(1, bufv); 4766440Swnj } 4776440Swnj closedir(d); 4786440Swnj (void) write(rem, "E\n", 2); 4796440Swnj (void) response(); 4806440Swnj } 4816440Swnj 4826440Swnj response() 4836440Swnj { 4846440Swnj char resp, c, rbuf[BUFSIZ], *cp = rbuf; 4856440Swnj 4866440Swnj if (read(rem, &resp, 1) != 1) 4876440Swnj lostconn(); 4886440Swnj switch (resp) { 4896440Swnj 49023101Slepreau case 0: /* ok */ 4916440Swnj return (0); 4926440Swnj 4936440Swnj default: 4946440Swnj *cp++ = resp; 4956440Swnj /* fall into... */ 49623101Slepreau case 1: /* error, followed by err msg */ 49723101Slepreau case 2: /* fatal error, "" */ 4986440Swnj do { 4996440Swnj if (read(rem, &c, 1) != 1) 5006440Swnj lostconn(); 5016440Swnj *cp++ = c; 5026440Swnj } while (cp < &rbuf[BUFSIZ] && c != '\n'); 5036440Swnj if (iamremote == 0) 5046440Swnj (void) write(2, rbuf, cp - rbuf); 5056440Swnj errs++; 5066440Swnj if (resp == 1) 5076440Swnj return (-1); 5086440Swnj exit(1); 5096440Swnj } 5106440Swnj /*NOTREACHED*/ 5116440Swnj } 5126440Swnj 5136440Swnj lostconn() 5146440Swnj { 5156440Swnj 5166440Swnj if (iamremote == 0) 5176440Swnj fprintf(stderr, "rcp: lost connection\n"); 5186440Swnj exit(1); 5196440Swnj } 5206440Swnj 5216440Swnj sink(argc, argv) 5226440Swnj int argc; 5236440Swnj char **argv; 5246440Swnj { 52521254Smckusick off_t i, j; 52621254Smckusick char *targ, *whopp, *cp; 52721254Smckusick int of, mode, wrerr, exists, first, count, amt, size; 52821254Smckusick struct buffer *bp; 52921254Smckusick static struct buffer buffer; 53021254Smckusick struct stat stb; 53121254Smckusick int targisdir = 0; 5326440Swnj int mask = umask(0); 5336440Swnj char *myargv[1]; 53423101Slepreau char cmdbuf[BUFSIZ], nambuf[BUFSIZ]; 53523101Slepreau int setimes = 0; 53623101Slepreau struct timeval tv[2]; 53723101Slepreau #define atime tv[0] 53823101Slepreau #define mtime tv[1] 53921254Smckusick #define SCREWUP(str) { whopp = str; goto screwup; } 5406440Swnj 541*23112Slepreau if (!pflag) 542*23112Slepreau (void) umask(mask); 54318126Sralph if (argc != 1) { 5446440Swnj error("rcp: ambiguous target\n"); 5456440Swnj exit(1); 5466440Swnj } 5476440Swnj targ = *argv; 5486440Swnj if (targetshouldbedirectory) 5496440Swnj verifydir(targ); 5506440Swnj ga(); 5516440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 5526440Swnj targisdir = 1; 55314580Sralph for (first = 1; ; first = 0) { 5546440Swnj cp = cmdbuf; 5556440Swnj if (read(rem, cp, 1) <= 0) 5566440Swnj return; 5576440Swnj if (*cp++ == '\n') 5586440Swnj SCREWUP("unexpected '\\n'"); 5596440Swnj do { 5606440Swnj if (read(rem, cp, 1) != 1) 5616440Swnj SCREWUP("lost connection"); 5626440Swnj } while (*cp++ != '\n'); 5636440Swnj *cp = 0; 5646440Swnj if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') { 5656440Swnj if (iamremote == 0) 56613542Ssam (void) write(2, cmdbuf+1, strlen(cmdbuf+1)); 5676440Swnj if (cmdbuf[0] == '\02') 5686440Swnj exit(1); 5696440Swnj errs++; 5706440Swnj continue; 5716440Swnj } 5726440Swnj *--cp = 0; 5736440Swnj cp = cmdbuf; 5746440Swnj if (*cp == 'E') { 5756440Swnj ga(); 5766440Swnj return; 5776440Swnj } 57823101Slepreau 57923101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 58023101Slepreau if (*cp == 'T') { 58123101Slepreau setimes++; 58223101Slepreau cp++; 58323101Slepreau getnum(mtime.tv_sec); 58423101Slepreau if (*cp++ != ' ') 58523101Slepreau SCREWUP("mtime.sec not delimited"); 58623101Slepreau getnum(mtime.tv_usec); 58723101Slepreau if (*cp++ != ' ') 58823101Slepreau SCREWUP("mtime.usec not delimited"); 58923101Slepreau getnum(atime.tv_sec); 59023101Slepreau if (*cp++ != ' ') 59123101Slepreau SCREWUP("atime.sec not delimited"); 59223101Slepreau getnum(atime.tv_usec); 59323101Slepreau if (*cp++ != '\0') 59423101Slepreau SCREWUP("atime.usec not delimited"); 59523101Slepreau ga(); 59623101Slepreau continue; 59723101Slepreau } 59814580Sralph if (*cp != 'C' && *cp != 'D') { 59914580Sralph /* 60014580Sralph * Check for the case "rcp remote:foo\* local:bar". 60114580Sralph * In this case, the line "No match." can be returned 60214580Sralph * by the shell before the rcp command on the remote is 60314580Sralph * executed so the ^Aerror_message convention isn't 60414580Sralph * followed. 60514580Sralph */ 60614580Sralph if (first) { 60714580Sralph error("%s\n", cp); 60814580Sralph exit(1); 60914580Sralph } 6106440Swnj SCREWUP("expected control record"); 61114580Sralph } 6126440Swnj cp++; 6136440Swnj mode = 0; 6146440Swnj for (; cp < cmdbuf+5; cp++) { 6156440Swnj if (*cp < '0' || *cp > '7') 6166440Swnj SCREWUP("bad mode"); 6176440Swnj mode = (mode << 3) | (*cp - '0'); 6186440Swnj } 6196440Swnj if (*cp++ != ' ') 6206440Swnj SCREWUP("mode not delimited"); 6216440Swnj size = 0; 622*23112Slepreau while (isdigit(*cp)) 6236440Swnj size = size * 10 + (*cp++ - '0'); 6246440Swnj if (*cp++ != ' ') 6256440Swnj SCREWUP("size not delimited"); 6266440Swnj if (targisdir) 6276440Swnj (void) sprintf(nambuf, "%s%s%s", targ, 6286440Swnj *targ ? "/" : "", cp); 6296440Swnj else 6306440Swnj (void) strcpy(nambuf, targ); 6316440Swnj exists = stat(nambuf, &stb) == 0; 63218126Sralph if (cmdbuf[0] == 'D') { 63318126Sralph if (exists) { 6346440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 6356440Swnj errno = ENOTDIR; 6366440Swnj goto bad; 6376440Swnj } 638*23112Slepreau if (pflag) 639*23112Slepreau (void) chmod(nambuf, mode); 64018126Sralph } else if (mkdir(nambuf, mode) < 0) 6416440Swnj goto bad; 6426440Swnj myargv[0] = nambuf; 6436440Swnj sink(1, myargv); 64423101Slepreau if (setimes) { 64523101Slepreau setimes = 0; 64623101Slepreau if (utimes(nambuf, tv) < 0) 64723101Slepreau error("rcp: can't set times on %s: %s\n", 64823101Slepreau nambuf, sys_errlist[errno]); 64923101Slepreau } 6506440Swnj continue; 65118126Sralph } 65218126Sralph if ((of = creat(nambuf, mode)) < 0) { 6536440Swnj bad: 6546440Swnj error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 6556440Swnj continue; 6566440Swnj } 657*23112Slepreau if (exists && pflag) 658*23112Slepreau (void) fchmod(of, mode); 6596440Swnj ga(); 66021254Smckusick if ((bp = allocbuf(&buffer, of, BUFSIZ)) < 0) { 66123101Slepreau (void) close(of); 66221254Smckusick continue; 66321254Smckusick } 66421254Smckusick cp = bp->buf; 66521254Smckusick count = 0; 6666440Swnj wrerr = 0; 6676440Swnj for (i = 0; i < size; i += BUFSIZ) { 66821254Smckusick amt = BUFSIZ; 6696440Swnj if (i + amt > size) 6706440Swnj amt = size - i; 67121254Smckusick count += amt; 6726440Swnj do { 67321254Smckusick j = read(rem, cp, amt); 6746440Swnj if (j <= 0) 6756440Swnj exit(1); 6766440Swnj amt -= j; 6776440Swnj cp += j; 6786440Swnj } while (amt > 0); 67921254Smckusick if (count == bp->cnt) { 68021254Smckusick if (wrerr == 0 && 68121254Smckusick write(of, bp->buf, count) != count) 68221254Smckusick wrerr++; 68321254Smckusick count = 0; 68421254Smckusick cp = bp->buf; 68521254Smckusick } 6866440Swnj } 68721254Smckusick if (count != 0 && wrerr == 0 && 68821254Smckusick write(of, bp->buf, count) != count) 68921254Smckusick wrerr++; 6906440Swnj (void) close(of); 6916440Swnj (void) response(); 69223101Slepreau if (setimes) { 69323101Slepreau setimes = 0; 69423101Slepreau if (utimes(nambuf, tv) < 0) 69523101Slepreau error("rcp: can't set times on %s: %s\n", 69623101Slepreau nambuf, sys_errlist[errno]); 69723101Slepreau } 6986440Swnj if (wrerr) 69923101Slepreau error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 7006440Swnj else 7016440Swnj ga(); 7026440Swnj } 7036440Swnj screwup: 7046440Swnj error("rcp: protocol screwup: %s\n", whopp); 7056440Swnj exit(1); 7066440Swnj } 7076440Swnj 70821254Smckusick struct buffer * 70921254Smckusick allocbuf(bp, fd, blksize) 71021254Smckusick struct buffer *bp; 71121254Smckusick int fd, blksize; 71221254Smckusick { 71321254Smckusick struct stat stb; 71421254Smckusick int size; 71521254Smckusick 71621254Smckusick if (fstat(fd, &stb) < 0) { 71721254Smckusick error("rcp: fstat: %s\n", sys_errlist[errno]); 71821254Smckusick return ((struct buffer *)-1); 71921254Smckusick } 72021254Smckusick size = roundup(stb.st_blksize, blksize); 72121254Smckusick if (size == 0) 72221254Smckusick size = blksize; 72321254Smckusick if (bp->cnt < size) { 72421254Smckusick if (bp->buf != 0) 72521254Smckusick free(bp->buf); 72623101Slepreau bp->buf = (char *)malloc((unsigned) size); 72721254Smckusick if (bp->buf == 0) { 72821254Smckusick error("rcp: malloc: out of memory\n"); 72921254Smckusick return ((struct buffer *)-1); 73021254Smckusick } 73121254Smckusick } 73221254Smckusick bp->cnt = size; 73321254Smckusick return (bp); 73421254Smckusick } 73521254Smckusick 73623101Slepreau /*VARARGS1*/ 7376440Swnj error(fmt, a1, a2, a3, a4, a5) 7386440Swnj char *fmt; 7396440Swnj int a1, a2, a3, a4, a5; 7406440Swnj { 7416440Swnj char buf[BUFSIZ], *cp = buf; 7426440Swnj 7436440Swnj errs++; 7446440Swnj *cp++ = 1; 7456440Swnj (void) sprintf(cp, fmt, a1, a2, a3, a4, a5); 7466440Swnj (void) write(rem, buf, strlen(buf)); 7476440Swnj if (iamremote == 0) 7486440Swnj (void) write(2, buf+1, strlen(buf+1)); 7496440Swnj } 750