2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
15 static char sccsid
[] = "@(#)rcp.c 1.1 87/12/21 SMI"; /* from UCB 5.3 6/8/85"*/
34 #include <sys/types.h>
45 #include <net/netlib.h>
48 #define PROTO(func, args) func args
50 #define PROTO(func, args) func ()
53 PROTO (int main
, (int argc
, char *argv
[]));
54 PROTO (void lostconn
, (int sig
));
55 PROTO (void error
, (char *fmt
, ...) );
56 PROTO (int response
, (void) );
57 PROTO (void source
, (int argc
, char *argv
[]) );
58 PROTO (void sink
, (int argc
, char *argv
[]) );
59 PROTO (void usage
, (void) );
60 PROTO (char *colon
, (char *cp
) );
61 PROTO (int okname
, (char *cp0
) );
62 PROTO (int susystem
, (char *s
) );
63 PROTO (void verifydir
, (char *cp
) );
64 PROTO (void rsource
, (char *name
, struct stat
*statp
) );
65 PROTO (struct buffer
*allocbuf
, (struct buffer
*bp
, int fd
, int blksize
) );
72 int iamremote
, targetshouldbedirectory
;
74 int myuid
; /* uid of invoker */
86 #define ga() (void) write(rem, "", 1)
92 char *targ
, *host
, *src
;
95 #else /* NAMESERVER */
96 char *suser
, *tuser
, *thost
;
97 #endif /* NAMESERVER */
99 char buf
[BUFSIZ
], cmd
[16];
102 sp
= getservbyname("shell", "tcp");
104 fprintf(stderr
, "rcp: shell/tcp: unknown service\n");
108 pwd
= getpwuid(userid
= getuid());
110 fprintf(stderr
, "who are you?\n");
116 * This is a kludge to allow seteuid to user before touching
117 * files and seteuid root before doing rcmd so we can open
121 if (setruid(0) < 0) {
122 perror("setruid root");
128 for (argc
--, argv
++; argc
> 0 && **argv
== '-'; argc
--, argv
++) {
130 while (**argv
) switch (*(*argv
)++) {
136 case 'p': /* preserve mtimes and atimes */
140 /* The rest of these are not for users. */
142 targetshouldbedirectory
= 1;
145 case 'f': /* "from" */
148 source(--argc
, ++argv
);
153 sink(--argc
, ++argv
);
173 targetshouldbedirectory
= 1;
174 (void) sprintf(cmd
, "rcp%s%s%s",
175 iamrecursive
? " -r" : "", pflag
? " -p" : "",
176 targetshouldbedirectory
? " -d" : "");
177 (void) signal(SIGPIPE
, lostconn
);
178 targ
= colon(argv
[argc
- 1]);
179 if (targ
) { /* ... to remote */
184 tuser
= strrchr(argv
[argc
- 1], '.');
190 tuser
= pwd
->pw_name
;
191 #else /* NAMESERVER */
192 thost
= strchr(argv
[argc
- 1], '@');
195 tuser
= argv
[argc
- 1];
197 tuser
= pwd
->pw_name
;
198 else if (!okname(tuser
))
201 thost
= argv
[argc
- 1];
202 tuser
= pwd
->pw_name
;
204 #endif /* NAMESERVER */
205 for (i
= 0; i
< argc
- 1; i
++) {
206 src
= colon(argv
[i
]);
207 if (src
) { /* remote to remote */
212 suser
= strrchr(argv
[i
], '.');
216 #else /* NAMESERVER */
217 host
= strchr(argv
[i
], '@');
222 suser
= pwd
->pw_name
;
223 else if (!okname(suser
))
224 #endif /* NAMESERVER */
227 (void) sprintf(buf
, "rsh %s -l %s -n %s %s '%s.%s:%s'",
228 argv
[i
], suser
, cmd
, src
,
229 argv
[argc
- 1], tuser
, targ
);
231 (void) sprintf(buf
, "rsh %s -n %s %s '%s.%s:%s'",
233 argv
[argc
- 1], tuser
, targ
);
234 #else /* NAMESERVER */
235 (void) sprintf(buf
, "rsh %s -l %s -n %s %s '%s@%s:%s'",
236 host
, suser
, cmd
, src
,
239 (void) sprintf(buf
, "rsh %s -n %s %s '%s@%s:%s'",
242 #endif /* NAMESERVER */
243 (void) susystem(buf
);
244 } else { /* local to remote */
246 (void) sprintf(buf
, "%s -t %s",
249 host
= argv
[argc
- 1];
250 #else /* NAMESERVER */
252 #endif /* NAMESERVER */
254 if (seteuid(0) < 0) {
255 perror("seteuid root");
259 rem
= rcmd(&host
, port
, pwd
->pw_name
,
272 } else { /* ... to local */
273 if (targetshouldbedirectory
)
274 verifydir(argv
[argc
- 1]);
275 for (i
= 0; i
< argc
- 1; i
++) {
276 src
= colon(argv
[i
]);
277 if (src
== 0) { /* local to local */
278 (void) sprintf(buf
, "cp%s%s %s %s",
279 iamrecursive
? " -r" : "",
281 argv
[i
], argv
[argc
- 1]);
282 (void) susystem(buf
);
283 } else { /* remote to local */
288 suser
= strrchr(argv
[i
], '.');
292 #else /* NAMESERVER */
293 host
= strchr(argv
[i
], '@');
298 suser
= pwd
->pw_name
;
299 else if (!okname(suser
))
300 #endif /* NAMESERVER */
304 #else /* NAMESERVER */
307 #endif /* NAMESERVER */
308 suser
= pwd
->pw_name
;
311 #endif /* NAMESERVER */
312 (void) sprintf(buf
, "%s -f %s", cmd
, src
);
315 #endif /* NAMESERVER */
317 if (seteuid(0) < 0) {
318 perror("seteuid root");
322 rem
= rcmd(&host
, port
, pwd
->pw_name
, suser
,
331 sink(1, argv
+argc
-1);
346 if (stat(cp
, &stb
) >= 0) {
347 if ((stb
.st_mode
& S_IFMT
) == S_IFDIR
)
351 error("rcp: %s: %s.\n", cp
, strerror(errno
));
375 register char *cp
= cp0
;
382 if (!isalpha(c
) && !isdigit(c
) && c
!= '_' && c
!= '-')
388 fprintf(stderr
, "rcp: invalid user name %s\n", cp0
);
397 register void PROTO ((*istat
), (int) ), PROTO ((*qstat
), (int) );
399 if ((pid
= vfork()) == 0) {
401 (void) setruid(myuid
);
403 execl("/bin/sh", "sh", "-c", s
, (char *)0);
406 istat
= signal(SIGINT
, SIG_IGN
);
407 qstat
= signal(SIGQUIT
, SIG_IGN
);
408 while ((w
= wait(&status
)) != pid
&& w
!= -1)
412 (void) signal(SIGINT
, istat
);
413 (void) signal(SIGQUIT
, qstat
);
424 static struct buffer buffer
;
426 int x
, sizerr
, f
, amt
;
430 for (x
= 0; x
< argc
; x
++) {
432 if ((f
= open(name
, 0)) < 0) {
433 error("rcp: %s: %s\n", name
, strerror(errno
));
436 if (fstat(f
, &stb
) < 0)
438 switch (stb
.st_mode
&S_IFMT
) {
453 error("rcp: %s: not a plain file\n", name
);
456 last
= strrchr(name
, '/');
463 * Make it compatible with possible future
464 * versions expecting microseconds.
466 (void) sprintf(buf
, "T%d 0 %d 0\n",
467 stb
.st_mtime
, stb
.st_atime
);
468 (void) write(rem
, buf
, strlen(buf
));
469 if (response() < 0) {
474 (void) sprintf(buf
, "C%04o %lld %s\n",
475 stb
.st_mode
&07777, stb
.st_size
, last
);
476 (void) write(rem
, buf
, strlen(buf
));
477 if (response() < 0) {
481 if ((bp
= allocbuf(&buffer
, f
, BUFSIZ
)) == 0) {
486 for (i
= 0; i
< stb
.st_size
; i
+= bp
->cnt
) {
488 if (i
+ amt
> stb
.st_size
)
489 amt
= stb
.st_size
- i
;
490 if (sizerr
== 0 && read(f
, bp
->buf
, amt
) != amt
)
492 (void) write(rem
, bp
->buf
, amt
);
498 error("rcp: %s: file changed size\n", name
);
509 DIR *d
= opendir(name
);
516 error("rcp: %s: %s\n", name
, strerror(errno
));
519 last
= strrchr(name
, '/');
525 (void) sprintf(buf
, "T%d 0 %d 0\n",
526 statp
->st_mtime
, statp
->st_atime
);
527 (void) write(rem
, buf
, strlen(buf
));
528 if (response() < 0) {
533 (void) sprintf(buf
, "D%04o %d %s\n", statp
->st_mode
&07777, 0, last
);
534 (void) write(rem
, buf
, strlen(buf
));
535 if (response() < 0) {
539 while ((dp
= readdir(d
))) {
542 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
544 if (strlen(name
) + 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
545 error("%s/%s: Name too long.\n", name
, dp
->d_name
);
548 (void) sprintf(buf
, "%s/%s", name
, dp
->d_name
);
553 (void) write(rem
, "E\n", 2);
560 char resp
, c
, rbuf
[BUFSIZ
], *cp
= rbuf
;
562 if (read(rem
, &resp
, 1) != 1)
572 case 1: /* error, followed by err msg */
573 case 2: /* fatal error, "" */
575 if (read(rem
, &c
, 1) != 1)
578 } while (cp
< &rbuf
[BUFSIZ
] && c
!= '\n');
580 (void) write(2, rbuf
, cp
- rbuf
);
595 fprintf(stderr
, "rcp: lost connection\n");
605 char *targ
, *whopp
, *cp
;
606 int of
, mode
, wrerr
, exists
, first
, count
, amt
;
608 static struct buffer buffer
;
613 char cmdbuf
[BUFSIZ
], nambuf
[BUFSIZ
];
615 struct utimbuf utimbuf
;
616 #define atime utimbuf.actime
617 #define mtime utimbuf.modtime
619 #define SCREWUP(str) { whopp = str; goto screwup; }
622 seteuid(pwd
->pw_uid
);
627 error("rcp: ambiguous target\n");
631 if (targetshouldbedirectory
)
634 if (stat(targ
, &stb
) == 0 && (stb
.st_mode
& S_IFMT
) == S_IFDIR
)
636 for (first
= 1; ; first
= 0) {
638 if (read(rem
, cp
, 1) <= 0)
641 SCREWUP("unexpected '\\n'");
643 if (read(rem
, cp
, 1) != 1)
644 SCREWUP("lost connection");
645 } while (*cp
++ != '\n');
647 if (cmdbuf
[0] == '\01' || cmdbuf
[0] == '\02') {
649 (void) write(2, cmdbuf
+1, strlen(cmdbuf
+1));
650 if (cmdbuf
[0] == '\02')
662 #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
668 SCREWUP("mtime.sec not delimited");
671 SCREWUP("mtime.usec not delimited");
674 SCREWUP("atime.sec not delimited");
677 SCREWUP("atime.usec not delimited");
681 if (*cp
!= 'C' && *cp
!= 'D') {
683 * Check for the case "rcp remote:foo\* local:bar".
684 * In this case, the line "No match." can be returned
685 * by the shell before the rcp command on the remote is
686 * executed so the ^Aerror_message convention isn't
693 SCREWUP("expected control record");
697 for (; cp
< cmdbuf
+5; cp
++) {
698 if (*cp
< '0' || *cp
> '7')
700 mode
= (mode
<< 3) | (*cp
- '0');
703 SCREWUP("mode not delimited");
706 size
= size
* 10 + (*cp
++ - '0');
708 SCREWUP("size not delimited");
710 (void) sprintf(nambuf
, "%s%s%s", targ
,
711 *targ
? "/" : "", cp
);
713 (void) strcpy(nambuf
, targ
);
714 exists
= stat(nambuf
, &stb
) == 0;
715 if (cmdbuf
[0] == 'D') {
717 if ((stb
.st_mode
&S_IFMT
) != S_IFDIR
) {
722 (void) chmod(nambuf
, mode
);
723 } else if (mkdir(nambuf
, mode
) < 0)
729 if (utime(nambuf
, &utimbuf
) < 0)
730 error("rcp: can't set times on %s: %s\n",
731 nambuf
, strerror(errno
));
735 if ((of
= creat(nambuf
, mode
)) < 0) {
737 error("rcp: %s: %s\n", nambuf
, strerror(errno
));
741 (void) chmod(nambuf
, mode
);
743 if ((bp
= allocbuf(&buffer
, of
, BUFSIZ
)) == 0) {
750 for (i
= 0; i
< size
; i
+= BUFSIZ
) {
756 j
= read(rem
, cp
, amt
);
762 if (count
== bp
->cnt
) {
764 write(of
, bp
->buf
, count
) != count
)
770 if (count
!= 0 && wrerr
== 0 &&
771 write(of
, bp
->buf
, count
) != count
)
777 if (utime(nambuf
, &utimbuf
) < 0)
778 error("rcp: can't set times on %s: %s\n",
779 nambuf
, strerror(errno
));
782 error("rcp: %s: %s\n", nambuf
, strerror(errno
));
787 error("rcp: protocol screwup: %s\n", whopp
);
792 allocbuf(bp
, fd
, blksize
)
799 if (fstat(fd
, &stb
) < 0) {
800 error("rcp: fstat: %s\n", strerror(errno
));
801 return ((struct buffer
*)0);
805 size
= roundup(stb
.st_blksize
, blksize
);
809 if (bp
->cnt
< size
) {
812 bp
->buf
= (char *)malloc((unsigned) size
);
814 error("rcp: malloc: out of memory\n");
815 return ((struct buffer
*)0);
825 error (char *fmt
, ...)
831 char buf
[BUFSIZ
], *cp
= buf
;
838 (void) vsprintf(cp
, fmt
, ap
);
840 (void) write(rem
, buf
, strlen(buf
));
842 (void) write(2, buf
+1, strlen(buf
+1));
848 fprintf(stderr
, "Usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n");