2 * Copyright (c) 1983 The Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
21 All rights reserved.\n";
25 static char sccsid[] = "@(#)rcp.c 5.11 (Berkeley) 9/22/88";
31 #include <afs/param.h>
32 #include <sys/param.h>
36 #include <sys/ioctl.h>
38 #include <netinet/in.h>
48 #include <sys/fcntl.h>
52 #if defined(AFS_AIX_ENV)
53 #define vfork() fork()
59 #define SYSERR(x) sys_errlist[x]
60 #define NLfprintf fprintf
67 #endif /* AFS_AIX32_ENV */
70 #include <netinet/in.h>
71 #include <netinet/in_systm.h>
72 #include <netinet/ip.h>
73 #define _PATH_CP "/bin/cp"
74 #define _PATH_RSH "/usr/bin/rsh"
75 #define _PATH_BSHELL "/bin/sh"
79 char *colon(), *index(), *rindex(), *malloc(), *strcpy();
81 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
82 extern char *sys_errlist[];
85 int iamremote, targetshouldbedirectory;
89 struct passwd *getpwuid();
101 #define ga() (void) write(rem, "", 1)
103 #include "AFS_component_version_number.c"
109 char *targ, *host, *src;
110 char *suser, *tuser, *thost;
112 char buf[BUFSIZ], cmd[16];
115 #if defined(AFS_AIX32_ENV) && (defined(NLS) || defined(KJI))
116 setlocale(LC_ALL,"");
118 sp = getservbyname("shell", "tcp");
120 fprintf(stderr, "rcp: shell/tcp: unknown service\n");
124 pwd = getpwuid(userid = getuid());
126 fprintf(stderr, "who are you?\n");
130 for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
132 while (**argv) switch (*(*argv)++) {
138 case 'p': /* preserve mtimes and atimes */
142 /* The rest of these are not for users. */
144 targetshouldbedirectory = 1;
147 case 'f': /* "from" */
150 (void) setuid(userid);
151 source(--argc, ++argv);
156 (void) setuid(userid);
157 sink(--argc, ++argv);
167 targetshouldbedirectory = 1;
169 (void) sprintf(cmd, "rcp%s%s%s",
170 iamrecursive ? " -r" : "", pflag ? " -p" : "",
171 targetshouldbedirectory ? " -d" : "");
172 (void) signal(SIGPIPE, lostconn);
174 targ = colon(argv[argc - 1]);
175 if (targ) { /* ... to remote */
179 thost = index(argv[argc - 1], '@');
182 tuser = argv[argc - 1];
185 else if (!okname(tuser))
188 thost = argv[argc - 1];
191 for (i = 0; i < argc - 1; i++) {
192 char *binpath = "/usr/ucb/rsh";
195 if (stat(binpath, &tstat)) {
197 * Doesn't exist; try another path
199 binpath = "/bin/rsh";
201 src = colon(argv[i]);
202 if (src) { /* remote to remote */
206 host = index(argv[i], '@');
211 suser = pwd->pw_name;
212 else if (!okname(suser))
214 (void) sprintf(buf, "%s %s -l %s -n %s %s '%s%s%s:%s'",
215 binpath, host, suser, cmd, src,
220 (void) sprintf(buf, "%s %s -n %s %s '%s%s%s:%s'",
221 binpath, argv[i], cmd, src,
225 (void) susystem(buf);
226 } else { /* local to remote */
228 (void) sprintf(buf, "%s -t %s",
231 rem = rcmd(&host, port, pwd->pw_name,
232 tuser ? tuser : pwd->pw_name,
237 tos = IPTOS_THROUGHPUT;
238 if (setsockopt(rem, IPPROTO_IP, IP_TOS,
239 (char *)&tos, sizeof(int)) < 0)
240 perror("rcp: setsockopt TOS (ignored)");
244 (void) setuid(userid);
249 } else { /* ... to local */
250 if (targetshouldbedirectory)
251 verifydir(argv[argc - 1]);
252 for (i = 0; i < argc - 1; i++) {
253 src = colon(argv[i]);
254 if (src == 0) { /* local to local */
256 (void) sprintf(buf, "%s%s%s %s %s", _PATH_CP,
258 (void) sprintf(buf, "/bin/cp%s%s %s %s",
260 iamrecursive ? " -r" : "", pflag ? " -p" : "",
261 argv[i], argv[argc - 1]);
262 (void) susystem(buf);
263 } else { /* remote to local */
267 host = index(argv[i], '@');
272 suser = pwd->pw_name;
273 else if (!okname(suser))
277 suser = pwd->pw_name;
279 (void) sprintf(buf, "%s -f %s", cmd, src);
280 rem = rcmd(&host, port, pwd->pw_name, suser,
285 (void) setuid(userid);
286 sink(1, argv+argc-1);
290 tos = IPTOS_THROUGHPUT;
291 if (setsockopt(rem, IPPROTO_IP, IP_TOS,
292 (char *)&tos, sizeof(int)) < 0)
293 perror("rcp: setsockopt TOS (ignored)");
295 (void) setreuid(0, userid);
296 sink(1, argv+argc-1);
297 (void) setreuid(userid, 0);
312 if (stat(cp, &stb) >= 0) {
313 if ((stb.st_mode & S_IFMT) == S_IFDIR)
317 error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
339 register char *cp = cp0;
346 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
352 fprintf(stderr, "rcp: invalid user name %s\n", cp0);
361 register sig_t istat, qstat;
363 register void (*istat)(), (*qstat)();
366 if ((pid = vfork()) == 0) {
367 (void) setuid(userid);
369 execl(_PATH_BSHELL, "sh", "-c", s, (char *)0);
371 execl("/bin/sh", "sh", "-c", s, (char *)0);
375 istat = signal(SIGINT, SIG_IGN);
376 qstat = signal(SIGQUIT, SIG_IGN);
377 while ((w = wait(&status)) != pid && w != -1)
381 (void) signal(SIGINT, istat);
382 (void) signal(SIGQUIT, qstat);
392 static struct buffer buffer;
394 int x, readerr, f, amt;
398 for (x = 0; x < argc; x++) {
400 if ((f = open(name, 0)) < 0) {
401 error("rcp: %s: %s\n", name, sys_errlist[errno]);
404 if (fstat(f, &stb) < 0)
406 switch (stb.st_mode&S_IFMT) {
421 error("rcp: %s: not a plain file\n", name);
424 last = rindex(name, '/');
431 * Make it compatible with possible future
432 * versions expecting microseconds.
434 (void) sprintf(buf, "T%ld 0 %ld 0\n",
435 stb.st_mtime, stb.st_atime);
436 (void) write(rem, buf, strlen(buf));
437 if (response() < 0) {
442 (void) sprintf(buf, "C%04o %ld %s\n",
443 stb.st_mode&07777, stb.st_size, last);
444 (void) write(rem, buf, strlen(buf));
445 if (response() < 0) {
449 if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
454 for (i = 0; i < stb.st_size; i += bp->cnt) {
456 if (i + amt > stb.st_size)
457 amt = stb.st_size - i;
458 if (readerr == 0 && read(f, bp->buf, amt) != amt)
460 (void) write(rem, bp->buf, amt);
466 error("rcp: %s: %s\n", name, sys_errlist[readerr]);
476 DIR *d = opendir(name);
483 error("rcp: %s: %s\n", name, sys_errlist[errno]);
486 last = rindex(name, '/');
492 (void) sprintf(buf, "T%ld 0 %ld 0\n",
493 statp->st_mtime, statp->st_atime);
494 (void) write(rem, buf, strlen(buf));
495 if (response() < 0) {
500 (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
501 (void) write(rem, buf, strlen(buf));
502 if (response() < 0) {
506 while (dp = readdir(d)) {
509 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
511 if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
512 error("%s/%s: Name too long.\n", name, dp->d_name);
515 (void) sprintf(buf, "%s/%s", name, dp->d_name);
520 (void) write(rem, "E\n", 2);
526 char resp, c, rbuf[BUFSIZ], *cp = rbuf;
528 if (read(rem, &resp, 1) != 1)
538 case 1: /* error, followed by err msg */
539 case 2: /* fatal error, "" */
541 if (read(rem, &c, 1) != 1)
544 } while (cp < &rbuf[BUFSIZ] && c != '\n');
546 (void) write(2, rbuf, cp - rbuf);
559 fprintf(stderr, "rcp: lost connection\n");
568 char *targ, *whopp, *cp;
569 int of, mode, wrerr, exists, first, count, amt, size;
571 static struct buffer buffer;
576 char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
578 struct timeval tv[2];
581 #define SCREWUP(str) { whopp = str; goto screwup; }
586 error("rcp: ambiguous target\n");
590 if (targetshouldbedirectory)
593 if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
595 for (first = 1; ; first = 0) {
597 if (read(rem, cp, 1) <= 0)
600 SCREWUP("unexpected '\\n'");
602 if (read(rem, cp, 1) != 1)
603 SCREWUP("lost connection");
604 } while (*cp++ != '\n');
606 if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
608 (void) write(2, cmdbuf+1, strlen(cmdbuf+1));
609 if (cmdbuf[0] == '\02')
621 #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
625 getnum(mtime.tv_sec);
627 SCREWUP("mtime.sec not delimited");
628 getnum(mtime.tv_usec);
630 SCREWUP("mtime.usec not delimited");
631 getnum(atime.tv_sec);
633 SCREWUP("atime.sec not delimited");
634 getnum(atime.tv_usec);
636 SCREWUP("atime.usec not delimited");
640 if (*cp != 'C' && *cp != 'D') {
642 * Check for the case "rcp remote:foo\* local:bar".
643 * In this case, the line "No match." can be returned
644 * by the shell before the rcp command on the remote is
645 * executed so the ^Aerror_message convention isn't
652 SCREWUP("expected control record");
656 for (; cp < cmdbuf+5; cp++) {
657 if (*cp < '0' || *cp > '7')
659 mode = (mode << 3) | (*cp - '0');
662 SCREWUP("mode not delimited");
665 size = size * 10 + (*cp++ - '0');
667 SCREWUP("size not delimited");
669 (void) sprintf(nambuf, "%s%s%s", targ,
670 *targ ? "/" : "", cp);
672 (void) strcpy(nambuf, targ);
673 exists = stat(nambuf, &stb) == 0;
674 if (cmdbuf[0] == 'D') {
676 if ((stb.st_mode&S_IFMT) != S_IFDIR) {
681 (void) chmod(nambuf, mode);
682 } else if (mkdir(nambuf, mode) < 0)
688 if (utimes(nambuf, tv) < 0)
689 error("rcp: can't set times on %s: %s\n",
690 nambuf, sys_errlist[errno]);
694 if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) {
696 error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
700 (void) fchmod(of, mode);
702 if ((bp = allocbuf(&buffer, of, BUFSIZ)) == 0) {
709 for (i = 0; i < size; i += BUFSIZ) {
715 j = read(rem, cp, amt);
718 error("rcp: dropped connection");
727 if (count == bp->cnt) {
729 write(of, bp->buf, count) != count)
735 if (count != 0 && wrerr == 0 &&
736 write(of, bp->buf, count) != count)
738 if (ftruncate(of, size))
739 error("rcp: can't truncate %s: %s\n",
740 nambuf, sys_errlist[errno]);
745 if (utimes(nambuf, tv) < 0)
746 error("rcp: can't set times on %s: %s\n",
747 nambuf, sys_errlist[errno]);
750 error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
755 error("rcp: protocol screwup: %s\n", whopp);
760 allocbuf(bp, fd, blksize)
767 if (fstat(fd, &stb) < 0) {
768 error("rcp: fstat: %s\n", sys_errlist[errno]);
769 return ((struct buffer *)0);
771 #if defined(AIX) || defined(AFS_SUN5_ENV)
774 size = roundup(stb.st_blksize, blksize);
775 #endif /* defined(AIX) */
778 if (bp->cnt < size) {
781 bp->buf = (char *)malloc((unsigned) size);
783 error("rcp: malloc: out of memory\n");
784 return ((struct buffer *)0);
792 error(fmt, a1, a2, a3, a4, a5)
794 #if defined(AFS_64BIT_ENV)
795 char *a1, *a2, *a3, *a4, *a5;
797 int a1, a2, a3, a4, a5;
800 char buf[BUFSIZ], *cp = buf;
804 (void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
805 (void) write(rem, buf, strlen(buf));
807 (void) write(2, buf+1, strlen(buf+1));
812 fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr);