121569Sdist /* 2*35619Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*35619Sbostic * All rights reserved. 4*35619Sbostic * 5*35619Sbostic * Redistribution and use in source and binary forms are permitted 6*35619Sbostic * provided that the above copyright notice and this paragraph are 7*35619Sbostic * duplicated in all such forms and that any documentation, 8*35619Sbostic * advertising materials, and other materials related to such 9*35619Sbostic * distribution and use acknowledge that the software was developed 10*35619Sbostic * by the University of California, Berkeley. The name of the 11*35619Sbostic * University may not be used to endorse or promote products derived 12*35619Sbostic * from this software without specific prior written permission. 13*35619Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35619Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35619Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621569Sdist */ 1721569Sdist 186440Swnj #ifndef lint 1921569Sdist char copyright[] = 20*35619Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2121569Sdist All rights reserved.\n"; 22*35619Sbostic #endif /* not lint */ 236440Swnj 2421569Sdist #ifndef lint 25*35619Sbostic static char sccsid[] = "@(#)rcp.c 5.10 (Berkeley) 09/20/88"; 26*35619Sbostic #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> 369199Ssam 379199Ssam #include <netinet/in.h> 389199Ssam 399199Ssam #include <stdio.h> 409199Ssam #include <signal.h> 416440Swnj #include <pwd.h> 426440Swnj #include <ctype.h> 4318026Sralph #include <netdb.h> 446440Swnj #include <errno.h> 4512989Ssam 466440Swnj int rem; 4732419Sbostic char *colon(), *index(), *rindex(), *malloc(), *strcpy(); 486440Swnj int errs; 496440Swnj int lostconn(); 506440Swnj int errno; 516440Swnj char *sys_errlist[]; 526440Swnj int iamremote, targetshouldbedirectory; 536440Swnj int iamrecursive; 5423101Slepreau int pflag; 556440Swnj struct passwd *pwd; 566440Swnj struct passwd *getpwuid(); 5718126Sralph int userid; 5818126Sralph int port; 596440Swnj 6021254Smckusick struct buffer { 6121254Smckusick int cnt; 6221254Smckusick char *buf; 6321254Smckusick } *allocbuf(); 6421254Smckusick 656440Swnj /*VARARGS*/ 666440Swnj int error(); 676440Swnj 686440Swnj #define ga() (void) write(rem, "", 1) 696440Swnj 706440Swnj main(argc, argv) 716440Swnj int argc; 726440Swnj char **argv; 736440Swnj { 746440Swnj char *targ, *host, *src; 7518259Sralph char *suser, *tuser, *thost; 766440Swnj int i; 776440Swnj char buf[BUFSIZ], cmd[16]; 7818126Sralph struct servent *sp; 7918026Sralph 8018026Sralph sp = getservbyname("shell", "tcp"); 8118026Sralph if (sp == NULL) { 8218026Sralph fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 8318026Sralph exit(1); 8418026Sralph } 8518126Sralph port = sp->s_port; 8618126Sralph pwd = getpwuid(userid = getuid()); 876440Swnj if (pwd == 0) { 886440Swnj fprintf(stderr, "who are you?\n"); 896440Swnj exit(1); 906440Swnj } 9123101Slepreau 9223101Slepreau for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) { 9323101Slepreau (*argv)++; 9423101Slepreau while (**argv) switch (*(*argv)++) { 9523101Slepreau 9623101Slepreau case 'r': 9723101Slepreau iamrecursive++; 9823101Slepreau break; 9923101Slepreau 10023101Slepreau case 'p': /* preserve mtimes and atimes */ 10123101Slepreau pflag++; 10223101Slepreau break; 10323101Slepreau 10423101Slepreau /* The rest of these are not for users. */ 10523101Slepreau case 'd': 10623101Slepreau targetshouldbedirectory = 1; 10723101Slepreau break; 10823101Slepreau 10923101Slepreau case 'f': /* "from" */ 11023101Slepreau iamremote = 1; 11123101Slepreau (void) response(); 11223101Slepreau (void) setuid(userid); 11323101Slepreau source(--argc, ++argv); 11423101Slepreau exit(errs); 11523101Slepreau 11623101Slepreau case 't': /* "to" */ 11723101Slepreau iamremote = 1; 11823101Slepreau (void) setuid(userid); 11923101Slepreau sink(--argc, ++argv); 12023101Slepreau exit(errs); 12123101Slepreau 12223101Slepreau default: 12332127Sbostic usage(); 12423101Slepreau } 1256440Swnj } 12632127Sbostic if (argc < 2) 12732127Sbostic usage(); 1286440Swnj if (argc > 2) 1296440Swnj targetshouldbedirectory = 1; 13032127Sbostic rem = -1; 13123101Slepreau (void) sprintf(cmd, "rcp%s%s%s", 13223101Slepreau iamrecursive ? " -r" : "", pflag ? " -p" : "", 13323101Slepreau targetshouldbedirectory ? " -d" : ""); 13423101Slepreau (void) signal(SIGPIPE, lostconn); 1356440Swnj targ = colon(argv[argc - 1]); 13623101Slepreau if (targ) { /* ... to remote */ 1376440Swnj *targ++ = 0; 13813542Ssam if (*targ == 0) 13913542Ssam targ = "."; 14018259Sralph thost = index(argv[argc - 1], '@'); 14118259Sralph if (thost) { 14218259Sralph *thost++ = 0; 14318259Sralph tuser = argv[argc - 1]; 14418259Sralph if (*tuser == '\0') 14524711Sbloom tuser = NULL; 14618259Sralph else if (!okname(tuser)) 1476440Swnj exit(1); 14818259Sralph } else { 14918259Sralph thost = argv[argc - 1]; 15024711Sbloom tuser = NULL; 15118259Sralph } 1526440Swnj for (i = 0; i < argc - 1; i++) { 1536440Swnj src = colon(argv[i]); 15423101Slepreau if (src) { /* remote to remote */ 1556440Swnj *src++ = 0; 15613542Ssam if (*src == 0) 15713738Ssam src = "."; 15818259Sralph host = index(argv[i], '@'); 15918259Sralph if (host) { 16018259Sralph *host++ = 0; 16118259Sralph suser = argv[i]; 16218259Sralph if (*suser == '\0') 16318259Sralph suser = pwd->pw_name; 16418259Sralph else if (!okname(suser)) 1656440Swnj continue; 16631028Sbostic (void) sprintf(buf, "/usr/ucb/rsh %s -l %s -n %s %s '%s%s%s:%s'", 16731945Sbostic host, suser, cmd, src, 16831945Sbostic tuser ? tuser : "", 16924711Sbloom tuser ? "@" : "", 17024711Sbloom thost, targ); 17118631Sralph } else 17231028Sbostic (void) sprintf(buf, "/usr/ucb/rsh %s -n %s %s '%s%s%s:%s'", 17331945Sbostic argv[i], cmd, src, 17431945Sbostic tuser ? tuser : "", 17524711Sbloom tuser ? "@" : "", 17624711Sbloom thost, targ); 1776440Swnj (void) susystem(buf); 17823101Slepreau } else { /* local to remote */ 1796440Swnj if (rem == -1) { 1806440Swnj (void) sprintf(buf, "%s -t %s", 1816440Swnj cmd, targ); 18218259Sralph host = thost; 18324711Sbloom rem = rcmd(&host, port, pwd->pw_name, 18424711Sbloom tuser ? tuser : pwd->pw_name, 1856440Swnj buf, 0); 1866440Swnj if (rem < 0) 1876440Swnj exit(1); 1886440Swnj if (response() < 0) 1896440Swnj exit(1); 19018126Sralph (void) setuid(userid); 1916440Swnj } 1926440Swnj source(1, argv+i); 1936440Swnj } 1946440Swnj } 19523101Slepreau } else { /* ... to local */ 1966440Swnj if (targetshouldbedirectory) 1976440Swnj verifydir(argv[argc - 1]); 1986440Swnj for (i = 0; i < argc - 1; i++) { 1996440Swnj src = colon(argv[i]); 20023101Slepreau if (src == 0) { /* local to local */ 20123101Slepreau (void) sprintf(buf, "/bin/cp%s%s %s %s", 2026440Swnj iamrecursive ? " -r" : "", 20323101Slepreau pflag ? " -p" : "", 2046440Swnj argv[i], argv[argc - 1]); 2056440Swnj (void) susystem(buf); 20623101Slepreau } else { /* remote to local */ 2076440Swnj *src++ = 0; 20813542Ssam if (*src == 0) 20913542Ssam src = "."; 21018259Sralph host = index(argv[i], '@'); 21118259Sralph if (host) { 21218259Sralph *host++ = 0; 21318259Sralph suser = argv[i]; 21418259Sralph if (*suser == '\0') 21518259Sralph suser = pwd->pw_name; 21618259Sralph else if (!okname(suser)) 2176440Swnj continue; 21818259Sralph } else { 21918259Sralph host = argv[i]; 2206440Swnj suser = pwd->pw_name; 22118259Sralph } 2226440Swnj (void) sprintf(buf, "%s -f %s", cmd, src); 22318126Sralph rem = rcmd(&host, port, pwd->pw_name, suser, 2246440Swnj buf, 0); 2256440Swnj if (rem < 0) 22618259Sralph continue; 22718126Sralph (void) setreuid(0, userid); 2286440Swnj sink(1, argv+argc-1); 22918126Sralph (void) setreuid(userid, 0); 2306440Swnj (void) close(rem); 2316440Swnj rem = -1; 2326440Swnj } 2336440Swnj } 2346440Swnj } 2356440Swnj exit(errs); 2366440Swnj } 2376440Swnj 2386440Swnj verifydir(cp) 2396440Swnj char *cp; 2406440Swnj { 2416440Swnj struct stat stb; 2426440Swnj 24318126Sralph if (stat(cp, &stb) >= 0) { 24418126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 24518126Sralph return; 24618126Sralph errno = ENOTDIR; 24718126Sralph } 2486440Swnj error("rcp: %s: %s.\n", cp, sys_errlist[errno]); 2496440Swnj exit(1); 2506440Swnj } 2516440Swnj 2526440Swnj char * 2536440Swnj colon(cp) 2546440Swnj char *cp; 2556440Swnj { 2566440Swnj 2576440Swnj while (*cp) { 2586440Swnj if (*cp == ':') 2596440Swnj return (cp); 2606440Swnj if (*cp == '/') 2616440Swnj return (0); 2626440Swnj cp++; 2636440Swnj } 2646440Swnj return (0); 2656440Swnj } 2666440Swnj 2676440Swnj okname(cp0) 2686440Swnj char *cp0; 2696440Swnj { 2706440Swnj register char *cp = cp0; 2716440Swnj register int c; 2726440Swnj 2736440Swnj do { 2746440Swnj c = *cp; 2756440Swnj if (c & 0200) 2766440Swnj goto bad; 2776440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 2786440Swnj goto bad; 2796440Swnj cp++; 2806440Swnj } while (*cp); 2816440Swnj return (1); 2826440Swnj bad: 2836440Swnj fprintf(stderr, "rcp: invalid user name %s\n", cp0); 2846440Swnj return (0); 2856440Swnj } 2866440Swnj 28717999Sserge susystem(s) 28817999Sserge char *s; 2896440Swnj { 29017999Sserge int status, pid, w; 29117999Sserge register int (*istat)(), (*qstat)(); 2926440Swnj 29317999Sserge if ((pid = vfork()) == 0) { 29423101Slepreau (void) setuid(userid); 29517999Sserge execl("/bin/sh", "sh", "-c", s, (char *)0); 29617999Sserge _exit(127); 29717999Sserge } 29817999Sserge istat = signal(SIGINT, SIG_IGN); 29917999Sserge qstat = signal(SIGQUIT, SIG_IGN); 30017999Sserge while ((w = wait(&status)) != pid && w != -1) 30117999Sserge ; 30217999Sserge if (w == -1) 30317999Sserge status = -1; 30423101Slepreau (void) signal(SIGINT, istat); 30523101Slepreau (void) signal(SIGQUIT, qstat); 30617999Sserge return (status); 3076440Swnj } 3086440Swnj 3096440Swnj source(argc, argv) 3106440Swnj int argc; 3116440Swnj char **argv; 3126440Swnj { 3136440Swnj char *last, *name; 3146440Swnj struct stat stb; 31521254Smckusick static struct buffer buffer; 31621254Smckusick struct buffer *bp; 31732268Sbostic int x, readerr, f, amt; 31821254Smckusick off_t i; 3196440Swnj char buf[BUFSIZ]; 3206440Swnj 3216440Swnj for (x = 0; x < argc; x++) { 3226440Swnj name = argv[x]; 32318126Sralph if ((f = open(name, 0)) < 0) { 3246440Swnj error("rcp: %s: %s\n", name, sys_errlist[errno]); 3256440Swnj continue; 3266440Swnj } 3276440Swnj if (fstat(f, &stb) < 0) 3286440Swnj goto notreg; 3296440Swnj switch (stb.st_mode&S_IFMT) { 3306440Swnj 3316440Swnj case S_IFREG: 3326440Swnj break; 3336440Swnj 3346440Swnj case S_IFDIR: 3356440Swnj if (iamrecursive) { 3366440Swnj (void) close(f); 33723101Slepreau rsource(name, &stb); 3386440Swnj continue; 3396440Swnj } 3406440Swnj /* fall into ... */ 3416440Swnj default: 3426440Swnj notreg: 3436440Swnj (void) close(f); 3446440Swnj error("rcp: %s: not a plain file\n", name); 3456440Swnj continue; 3466440Swnj } 3476440Swnj last = rindex(name, '/'); 3486440Swnj if (last == 0) 3496440Swnj last = name; 3506440Swnj else 3516440Swnj last++; 35223101Slepreau if (pflag) { 35323101Slepreau /* 35423101Slepreau * Make it compatible with possible future 35523101Slepreau * versions expecting microseconds. 35623101Slepreau */ 35723101Slepreau (void) sprintf(buf, "T%ld 0 %ld 0\n", 35823101Slepreau stb.st_mtime, stb.st_atime); 35923101Slepreau (void) write(rem, buf, strlen(buf)); 36023101Slepreau if (response() < 0) { 36123101Slepreau (void) close(f); 36223101Slepreau continue; 36323101Slepreau } 36423101Slepreau } 36523101Slepreau (void) sprintf(buf, "C%04o %ld %s\n", 3666440Swnj stb.st_mode&07777, stb.st_size, last); 3676440Swnj (void) write(rem, buf, strlen(buf)); 3686440Swnj if (response() < 0) { 3696440Swnj (void) close(f); 3706440Swnj continue; 3716440Swnj } 37221254Smckusick if ((bp = allocbuf(&buffer, f, BUFSIZ)) < 0) { 37321254Smckusick (void) close(f); 37421254Smckusick continue; 37521254Smckusick } 37632268Sbostic readerr = 0; 37721254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 37821254Smckusick amt = bp->cnt; 3796440Swnj if (i + amt > stb.st_size) 3806440Swnj amt = stb.st_size - i; 38132268Sbostic if (readerr == 0 && read(f, bp->buf, amt) != amt) 38232268Sbostic readerr = errno; 38321254Smckusick (void) write(rem, bp->buf, amt); 3846440Swnj } 3856440Swnj (void) close(f); 38632268Sbostic if (readerr == 0) 3876440Swnj ga(); 3886440Swnj else 38932268Sbostic error("rcp: %s: %s\n", name, sys_errlist[readerr]); 3906440Swnj (void) response(); 3916440Swnj } 3926440Swnj } 3936440Swnj 39413542Ssam #include <sys/dir.h> 3956440Swnj 39623101Slepreau rsource(name, statp) 3976440Swnj char *name; 39823101Slepreau struct stat *statp; 3996440Swnj { 4006440Swnj DIR *d = opendir(name); 4016440Swnj char *last; 4026440Swnj struct direct *dp; 4036440Swnj char buf[BUFSIZ]; 4046440Swnj char *bufv[1]; 4056440Swnj 4066440Swnj if (d == 0) { 40718126Sralph error("rcp: %s: %s\n", name, sys_errlist[errno]); 4086440Swnj return; 4096440Swnj } 4106440Swnj last = rindex(name, '/'); 4116440Swnj if (last == 0) 4126440Swnj last = name; 4136440Swnj else 4146440Swnj last++; 41523101Slepreau if (pflag) { 41623101Slepreau (void) sprintf(buf, "T%ld 0 %ld 0\n", 41723101Slepreau statp->st_mtime, statp->st_atime); 41823101Slepreau (void) write(rem, buf, strlen(buf)); 41923101Slepreau if (response() < 0) { 42023101Slepreau closedir(d); 42123101Slepreau return; 42223101Slepreau } 42323101Slepreau } 42423101Slepreau (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 4256440Swnj (void) write(rem, buf, strlen(buf)); 4266440Swnj if (response() < 0) { 4276440Swnj closedir(d); 4286440Swnj return; 4296440Swnj } 4306440Swnj while (dp = readdir(d)) { 4316440Swnj if (dp->d_ino == 0) 4326440Swnj continue; 4336440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 4346440Swnj continue; 4356440Swnj if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 4366440Swnj error("%s/%s: Name too long.\n", name, dp->d_name); 4376440Swnj continue; 4386440Swnj } 4396440Swnj (void) sprintf(buf, "%s/%s", name, dp->d_name); 4406440Swnj bufv[0] = buf; 4416440Swnj source(1, bufv); 4426440Swnj } 4436440Swnj closedir(d); 4446440Swnj (void) write(rem, "E\n", 2); 4456440Swnj (void) response(); 4466440Swnj } 4476440Swnj 4486440Swnj response() 4496440Swnj { 4506440Swnj char resp, c, rbuf[BUFSIZ], *cp = rbuf; 4516440Swnj 4526440Swnj if (read(rem, &resp, 1) != 1) 4536440Swnj lostconn(); 4546440Swnj switch (resp) { 4556440Swnj 45623101Slepreau case 0: /* ok */ 4576440Swnj return (0); 4586440Swnj 4596440Swnj default: 4606440Swnj *cp++ = resp; 4616440Swnj /* fall into... */ 46223101Slepreau case 1: /* error, followed by err msg */ 46323101Slepreau case 2: /* fatal error, "" */ 4646440Swnj do { 4656440Swnj if (read(rem, &c, 1) != 1) 4666440Swnj lostconn(); 4676440Swnj *cp++ = c; 4686440Swnj } while (cp < &rbuf[BUFSIZ] && c != '\n'); 4696440Swnj if (iamremote == 0) 4706440Swnj (void) write(2, rbuf, cp - rbuf); 4716440Swnj errs++; 4726440Swnj if (resp == 1) 4736440Swnj return (-1); 4746440Swnj exit(1); 4756440Swnj } 4766440Swnj /*NOTREACHED*/ 4776440Swnj } 4786440Swnj 4796440Swnj lostconn() 4806440Swnj { 4816440Swnj 4826440Swnj if (iamremote == 0) 4836440Swnj fprintf(stderr, "rcp: lost connection\n"); 4846440Swnj exit(1); 4856440Swnj } 4866440Swnj 4876440Swnj sink(argc, argv) 4886440Swnj int argc; 4896440Swnj char **argv; 4906440Swnj { 49121254Smckusick off_t i, j; 49221254Smckusick char *targ, *whopp, *cp; 49321254Smckusick int of, mode, wrerr, exists, first, count, amt, size; 49421254Smckusick struct buffer *bp; 49521254Smckusick static struct buffer buffer; 49621254Smckusick struct stat stb; 49721254Smckusick int targisdir = 0; 4986440Swnj int mask = umask(0); 4996440Swnj char *myargv[1]; 50023101Slepreau char cmdbuf[BUFSIZ], nambuf[BUFSIZ]; 50123101Slepreau int setimes = 0; 50223101Slepreau struct timeval tv[2]; 50323101Slepreau #define atime tv[0] 50423101Slepreau #define mtime tv[1] 50521254Smckusick #define SCREWUP(str) { whopp = str; goto screwup; } 5066440Swnj 50723112Slepreau if (!pflag) 50823112Slepreau (void) umask(mask); 50918126Sralph if (argc != 1) { 5106440Swnj error("rcp: ambiguous target\n"); 5116440Swnj exit(1); 5126440Swnj } 5136440Swnj targ = *argv; 5146440Swnj if (targetshouldbedirectory) 5156440Swnj verifydir(targ); 5166440Swnj ga(); 5176440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 5186440Swnj targisdir = 1; 51914580Sralph for (first = 1; ; first = 0) { 5206440Swnj cp = cmdbuf; 5216440Swnj if (read(rem, cp, 1) <= 0) 5226440Swnj return; 5236440Swnj if (*cp++ == '\n') 5246440Swnj SCREWUP("unexpected '\\n'"); 5256440Swnj do { 5266440Swnj if (read(rem, cp, 1) != 1) 5276440Swnj SCREWUP("lost connection"); 5286440Swnj } while (*cp++ != '\n'); 5296440Swnj *cp = 0; 5306440Swnj if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') { 5316440Swnj if (iamremote == 0) 53213542Ssam (void) write(2, cmdbuf+1, strlen(cmdbuf+1)); 5336440Swnj if (cmdbuf[0] == '\02') 5346440Swnj exit(1); 5356440Swnj errs++; 5366440Swnj continue; 5376440Swnj } 5386440Swnj *--cp = 0; 5396440Swnj cp = cmdbuf; 5406440Swnj if (*cp == 'E') { 5416440Swnj ga(); 5426440Swnj return; 5436440Swnj } 54423101Slepreau 54523101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 54623101Slepreau if (*cp == 'T') { 54723101Slepreau setimes++; 54823101Slepreau cp++; 54923101Slepreau getnum(mtime.tv_sec); 55023101Slepreau if (*cp++ != ' ') 55123101Slepreau SCREWUP("mtime.sec not delimited"); 55223101Slepreau getnum(mtime.tv_usec); 55323101Slepreau if (*cp++ != ' ') 55423101Slepreau SCREWUP("mtime.usec not delimited"); 55523101Slepreau getnum(atime.tv_sec); 55623101Slepreau if (*cp++ != ' ') 55723101Slepreau SCREWUP("atime.sec not delimited"); 55823101Slepreau getnum(atime.tv_usec); 55923101Slepreau if (*cp++ != '\0') 56023101Slepreau SCREWUP("atime.usec not delimited"); 56123101Slepreau ga(); 56223101Slepreau continue; 56323101Slepreau } 56414580Sralph if (*cp != 'C' && *cp != 'D') { 56514580Sralph /* 56614580Sralph * Check for the case "rcp remote:foo\* local:bar". 56714580Sralph * In this case, the line "No match." can be returned 56814580Sralph * by the shell before the rcp command on the remote is 56914580Sralph * executed so the ^Aerror_message convention isn't 57014580Sralph * followed. 57114580Sralph */ 57214580Sralph if (first) { 57314580Sralph error("%s\n", cp); 57414580Sralph exit(1); 57514580Sralph } 5766440Swnj SCREWUP("expected control record"); 57714580Sralph } 5786440Swnj cp++; 5796440Swnj mode = 0; 5806440Swnj for (; cp < cmdbuf+5; cp++) { 5816440Swnj if (*cp < '0' || *cp > '7') 5826440Swnj SCREWUP("bad mode"); 5836440Swnj mode = (mode << 3) | (*cp - '0'); 5846440Swnj } 5856440Swnj if (*cp++ != ' ') 5866440Swnj SCREWUP("mode not delimited"); 5876440Swnj size = 0; 58823112Slepreau while (isdigit(*cp)) 5896440Swnj size = size * 10 + (*cp++ - '0'); 5906440Swnj if (*cp++ != ' ') 5916440Swnj SCREWUP("size not delimited"); 5926440Swnj if (targisdir) 5936440Swnj (void) sprintf(nambuf, "%s%s%s", targ, 5946440Swnj *targ ? "/" : "", cp); 5956440Swnj else 5966440Swnj (void) strcpy(nambuf, targ); 5976440Swnj exists = stat(nambuf, &stb) == 0; 59818126Sralph if (cmdbuf[0] == 'D') { 59918126Sralph if (exists) { 6006440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 6016440Swnj errno = ENOTDIR; 6026440Swnj goto bad; 6036440Swnj } 60423112Slepreau if (pflag) 60523112Slepreau (void) chmod(nambuf, mode); 60618126Sralph } else if (mkdir(nambuf, mode) < 0) 6076440Swnj goto bad; 6086440Swnj myargv[0] = nambuf; 6096440Swnj sink(1, myargv); 61023101Slepreau if (setimes) { 61123101Slepreau setimes = 0; 61223101Slepreau if (utimes(nambuf, tv) < 0) 61323101Slepreau error("rcp: can't set times on %s: %s\n", 61423101Slepreau nambuf, sys_errlist[errno]); 61523101Slepreau } 6166440Swnj continue; 61718126Sralph } 61832127Sbostic if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) { 6196440Swnj bad: 6206440Swnj error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 6216440Swnj continue; 6226440Swnj } 62323112Slepreau if (exists && pflag) 62423112Slepreau (void) fchmod(of, mode); 6256440Swnj ga(); 62621254Smckusick if ((bp = allocbuf(&buffer, of, BUFSIZ)) < 0) { 62723101Slepreau (void) close(of); 62821254Smckusick continue; 62921254Smckusick } 63021254Smckusick cp = bp->buf; 63121254Smckusick count = 0; 6326440Swnj wrerr = 0; 6336440Swnj for (i = 0; i < size; i += BUFSIZ) { 63421254Smckusick amt = BUFSIZ; 6356440Swnj if (i + amt > size) 6366440Swnj amt = size - i; 63721254Smckusick count += amt; 6386440Swnj do { 63921254Smckusick j = read(rem, cp, amt); 64024711Sbloom if (j <= 0) { 64124711Sbloom if (j == 0) 64224711Sbloom error("rcp: dropped connection"); 64324711Sbloom else 64424711Sbloom error("rcp: %s\n", 64524711Sbloom sys_errlist[errno]); 6466440Swnj exit(1); 64724711Sbloom } 6486440Swnj amt -= j; 6496440Swnj cp += j; 6506440Swnj } while (amt > 0); 65121254Smckusick if (count == bp->cnt) { 65221254Smckusick if (wrerr == 0 && 65321254Smckusick write(of, bp->buf, count) != count) 65421254Smckusick wrerr++; 65521254Smckusick count = 0; 65621254Smckusick cp = bp->buf; 65721254Smckusick } 6586440Swnj } 65921254Smckusick if (count != 0 && wrerr == 0 && 66021254Smckusick write(of, bp->buf, count) != count) 66121254Smckusick wrerr++; 66232127Sbostic if (ftruncate(of, size)) 66332127Sbostic error("rcp: can't truncate %s: %s\n", 66432127Sbostic nambuf, sys_errlist[errno]); 6656440Swnj (void) close(of); 6666440Swnj (void) response(); 66723101Slepreau if (setimes) { 66823101Slepreau setimes = 0; 66923101Slepreau if (utimes(nambuf, tv) < 0) 67023101Slepreau error("rcp: can't set times on %s: %s\n", 67123101Slepreau nambuf, sys_errlist[errno]); 67223101Slepreau } 6736440Swnj if (wrerr) 67423101Slepreau error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 6756440Swnj else 6766440Swnj ga(); 6776440Swnj } 6786440Swnj screwup: 6796440Swnj error("rcp: protocol screwup: %s\n", whopp); 6806440Swnj exit(1); 6816440Swnj } 6826440Swnj 68321254Smckusick struct buffer * 68421254Smckusick allocbuf(bp, fd, blksize) 68521254Smckusick struct buffer *bp; 68621254Smckusick int fd, blksize; 68721254Smckusick { 68821254Smckusick struct stat stb; 68921254Smckusick int size; 69021254Smckusick 69121254Smckusick if (fstat(fd, &stb) < 0) { 69221254Smckusick error("rcp: fstat: %s\n", sys_errlist[errno]); 69321254Smckusick return ((struct buffer *)-1); 69421254Smckusick } 69521254Smckusick size = roundup(stb.st_blksize, blksize); 69621254Smckusick if (size == 0) 69721254Smckusick size = blksize; 69821254Smckusick if (bp->cnt < size) { 69921254Smckusick if (bp->buf != 0) 70021254Smckusick free(bp->buf); 70123101Slepreau bp->buf = (char *)malloc((unsigned) size); 70221254Smckusick if (bp->buf == 0) { 70321254Smckusick error("rcp: malloc: out of memory\n"); 70421254Smckusick return ((struct buffer *)-1); 70521254Smckusick } 70621254Smckusick } 70721254Smckusick bp->cnt = size; 70821254Smckusick return (bp); 70921254Smckusick } 71021254Smckusick 71123101Slepreau /*VARARGS1*/ 7126440Swnj error(fmt, a1, a2, a3, a4, a5) 7136440Swnj char *fmt; 7146440Swnj int a1, a2, a3, a4, a5; 7156440Swnj { 7166440Swnj char buf[BUFSIZ], *cp = buf; 7176440Swnj 7186440Swnj errs++; 7196440Swnj *cp++ = 1; 7206440Swnj (void) sprintf(cp, fmt, a1, a2, a3, a4, a5); 7216440Swnj (void) write(rem, buf, strlen(buf)); 7226440Swnj if (iamremote == 0) 7236440Swnj (void) write(2, buf+1, strlen(buf+1)); 7246440Swnj } 72532127Sbostic 72632127Sbostic usage() 72732127Sbostic { 72832127Sbostic fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr); 72932127Sbostic exit(1); 73032127Sbostic } 731