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";
14 static char sccsid
[] = "@(#)rcp.c 1.1 87/12/21 SMI"; /* from UCB 5.3 6/8/85"*/
33 #include <sys/types.h>
43 #include <net/gen/netdb.h>
44 #include <net/netlib.h>
47 #define PROTO(func, args) func args
49 #define PROTO(func, args) func ()
52 PROTO (int main
, (int argc
, char *argv
[]));
53 PROTO (void lostconn
, (int sig
));
54 PROTO (void error
, (char *fmt
, ...) );
55 PROTO (int response
, (void) );
56 PROTO (void source
, (int argc
, char *argv
[]) );
57 PROTO (void sink
, (int argc
, char *argv
[]) );
58 PROTO (void usage
, (void) );
59 PROTO (char *colon
, (char *cp
) );
60 PROTO (int okname
, (char *cp0
) );
61 PROTO (int susystem
, (char *s
) );
62 PROTO (void verifydir
, (char *cp
) );
63 PROTO (void rsource
, (char *name
, struct stat
*statp
) );
64 PROTO (struct buffer
*allocbuf
, (struct buffer
*bp
, int fd
, int blksize
) );
71 int iamremote
, targetshouldbedirectory
;
73 int myuid
; /* uid of invoker */
85 #define ga() (void) write(rem, "", 1)
91 char *targ
, *host
, *src
;
94 #else /* NAMESERVER */
95 char *suser
, *tuser
, *thost
;
96 #endif /* NAMESERVER */
98 char buf
[BUFSIZ
], cmd
[16];
101 sp
= getservbyname("shell", "tcp");
103 fprintf(stderr
, "rcp: shell/tcp: unknown service\n");
107 pwd
= getpwuid(userid
= getuid());
109 fprintf(stderr
, "who are you?\n");
115 * This is a kludge to allow seteuid to user before touching
116 * files and seteuid root before doing rcmd so we can open
120 if (setruid(0) < 0) {
121 perror("setruid root");
127 for (argc
--, argv
++; argc
> 0 && **argv
== '-'; argc
--, argv
++) {
129 while (**argv
) switch (*(*argv
)++) {
135 case 'p': /* preserve mtimes and atimes */
139 /* The rest of these are not for users. */
141 targetshouldbedirectory
= 1;
144 case 'f': /* "from" */
147 source(--argc
, ++argv
);
152 sink(--argc
, ++argv
);
172 targetshouldbedirectory
= 1;
173 (void) sprintf(cmd
, "rcp%s%s%s",
174 iamrecursive
? " -r" : "", pflag
? " -p" : "",
175 targetshouldbedirectory
? " -d" : "");
176 (void) signal(SIGPIPE
, lostconn
);
177 targ
= colon(argv
[argc
- 1]);
178 if (targ
) { /* ... to remote */
183 tuser
= strrchr(argv
[argc
- 1], '.');
189 tuser
= pwd
->pw_name
;
190 #else /* NAMESERVER */
191 thost
= strchr(argv
[argc
- 1], '@');
194 tuser
= argv
[argc
- 1];
196 tuser
= pwd
->pw_name
;
197 else if (!okname(tuser
))
200 thost
= argv
[argc
- 1];
201 tuser
= pwd
->pw_name
;
203 #endif /* NAMESERVER */
204 for (i
= 0; i
< argc
- 1; i
++) {
205 src
= colon(argv
[i
]);
206 if (src
) { /* remote to remote */
211 suser
= strrchr(argv
[i
], '.');
215 #else /* NAMESERVER */
216 host
= strchr(argv
[i
], '@');
221 suser
= pwd
->pw_name
;
222 else if (!okname(suser
))
223 #endif /* NAMESERVER */
226 (void) sprintf(buf
, "rsh %s -l %s -n %s %s '%s.%s:%s'",
227 argv
[i
], suser
, cmd
, src
,
228 argv
[argc
- 1], tuser
, targ
);
230 (void) sprintf(buf
, "rsh %s -n %s %s '%s.%s:%s'",
232 argv
[argc
- 1], tuser
, targ
);
233 #else /* NAMESERVER */
234 (void) sprintf(buf
, "rsh %s -l %s -n %s %s '%s@%s:%s'",
235 host
, suser
, cmd
, src
,
238 (void) sprintf(buf
, "rsh %s -n %s %s '%s@%s:%s'",
241 #endif /* NAMESERVER */
242 (void) susystem(buf
);
243 } else { /* local to remote */
245 (void) sprintf(buf
, "%s -t %s",
248 host
= argv
[argc
- 1];
249 #else /* NAMESERVER */
251 #endif /* NAMESERVER */
253 if (seteuid(0) < 0) {
254 perror("seteuid root");
258 rem
= rcmd(&host
, port
, pwd
->pw_name
,
271 } else { /* ... to local */
272 if (targetshouldbedirectory
)
273 verifydir(argv
[argc
- 1]);
274 for (i
= 0; i
< argc
- 1; i
++) {
275 src
= colon(argv
[i
]);
276 if (src
== 0) { /* local to local */
277 (void) sprintf(buf
, "cp%s%s %s %s",
278 iamrecursive
? " -r" : "",
280 argv
[i
], argv
[argc
- 1]);
281 (void) susystem(buf
);
282 } else { /* remote to local */
287 suser
= strrchr(argv
[i
], '.');
291 #else /* NAMESERVER */
292 host
= strchr(argv
[i
], '@');
297 suser
= pwd
->pw_name
;
298 else if (!okname(suser
))
299 #endif /* NAMESERVER */
303 #else /* NAMESERVER */
306 #endif /* NAMESERVER */
307 suser
= pwd
->pw_name
;
310 #endif /* NAMESERVER */
311 (void) sprintf(buf
, "%s -f %s", cmd
, src
);
314 #endif /* NAMESERVER */
316 if (seteuid(0) < 0) {
317 perror("seteuid root");
321 rem
= rcmd(&host
, port
, pwd
->pw_name
, suser
,
330 sink(1, argv
+argc
-1);
345 if (stat(cp
, &stb
) >= 0) {
346 if ((stb
.st_mode
& S_IFMT
) == S_IFDIR
)
350 error("rcp: %s: %s.\n", cp
, strerror(errno
));
374 register char *cp
= cp0
;
381 if (!isalpha(c
) && !isdigit(c
) && c
!= '_' && c
!= '-')
387 fprintf(stderr
, "rcp: invalid user name %s\n", cp0
);
396 register void PROTO ((*istat
), (int) ), PROTO ((*qstat
), (int) );
398 if ((pid
= vfork()) == 0) {
400 (void) setruid(myuid
);
402 execl("/bin/sh", "sh", "-c", s
, (char *)0);
405 istat
= signal(SIGINT
, SIG_IGN
);
406 qstat
= signal(SIGQUIT
, SIG_IGN
);
407 while ((w
= wait(&status
)) != pid
&& w
!= -1)
411 (void) signal(SIGINT
, istat
);
412 (void) signal(SIGQUIT
, qstat
);
423 static struct buffer buffer
;
425 int x
, sizerr
, f
, amt
;
429 for (x
= 0; x
< argc
; x
++) {
431 if ((f
= open(name
, 0)) < 0) {
432 error("rcp: %s: %s\n", name
, strerror(errno
));
435 if (fstat(f
, &stb
) < 0)
437 switch (stb
.st_mode
&S_IFMT
) {
452 error("rcp: %s: not a plain file\n", name
);
455 last
= strrchr(name
, '/');
462 * Make it compatible with possible future
463 * versions expecting microseconds.
465 (void) sprintf(buf
, "T%ld 0 %ld 0\n",
466 stb
.st_mtime
, stb
.st_atime
);
467 (void) write(rem
, buf
, strlen(buf
));
468 if (response() < 0) {
473 (void) sprintf(buf
, "C%04o %ld %s\n",
474 stb
.st_mode
&07777, stb
.st_size
, last
);
475 (void) write(rem
, buf
, strlen(buf
));
476 if (response() < 0) {
480 if ((bp
= allocbuf(&buffer
, f
, BUFSIZ
)) == 0) {
485 for (i
= 0; i
< stb
.st_size
; i
+= bp
->cnt
) {
487 if (i
+ amt
> stb
.st_size
)
488 amt
= stb
.st_size
- i
;
489 if (sizerr
== 0 && read(f
, bp
->buf
, amt
) != amt
)
491 (void) write(rem
, bp
->buf
, amt
);
497 error("rcp: %s: file changed size\n", name
);
508 DIR *d
= opendir(name
);
515 error("rcp: %s: %s\n", name
, strerror(errno
));
518 last
= strrchr(name
, '/');
524 (void) sprintf(buf
, "T%ld 0 %ld 0\n",
525 statp
->st_mtime
, statp
->st_atime
);
526 (void) write(rem
, buf
, strlen(buf
));
527 if (response() < 0) {
532 (void) sprintf(buf
, "D%04o %d %s\n", statp
->st_mode
&07777, 0, last
);
533 (void) write(rem
, buf
, strlen(buf
));
534 if (response() < 0) {
538 while (dp
= readdir(d
)) {
541 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
543 if (strlen(name
) + 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
544 error("%s/%s: Name too long.\n", name
, dp
->d_name
);
547 (void) sprintf(buf
, "%s/%s", name
, dp
->d_name
);
552 (void) write(rem
, "E\n", 2);
559 char resp
, c
, rbuf
[BUFSIZ
], *cp
= rbuf
;
561 if (read(rem
, &resp
, 1) != 1)
571 case 1: /* error, followed by err msg */
572 case 2: /* fatal error, "" */
574 if (read(rem
, &c
, 1) != 1)
577 } while (cp
< &rbuf
[BUFSIZ
] && c
!= '\n');
579 (void) write(2, rbuf
, cp
- rbuf
);
594 fprintf(stderr
, "rcp: lost connection\n");
604 char *targ
, *whopp
, *cp
;
605 int of
, mode
, wrerr
, exists
, first
, count
, amt
;
607 static struct buffer buffer
;
612 char cmdbuf
[BUFSIZ
], nambuf
[BUFSIZ
];
614 struct utimbuf utimbuf
;
615 #define atime utimbuf.actime
616 #define mtime utimbuf.modtime
618 #define SCREWUP(str) { whopp = str; goto screwup; }
621 seteuid(pwd
->pw_uid
);
626 error("rcp: ambiguous target\n");
630 if (targetshouldbedirectory
)
633 if (stat(targ
, &stb
) == 0 && (stb
.st_mode
& S_IFMT
) == S_IFDIR
)
635 for (first
= 1; ; first
= 0) {
637 if (read(rem
, cp
, 1) <= 0)
640 SCREWUP("unexpected '\\n'");
642 if (read(rem
, cp
, 1) != 1)
643 SCREWUP("lost connection");
644 } while (*cp
++ != '\n');
646 if (cmdbuf
[0] == '\01' || cmdbuf
[0] == '\02') {
648 (void) write(2, cmdbuf
+1, strlen(cmdbuf
+1));
649 if (cmdbuf
[0] == '\02')
661 #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
667 SCREWUP("mtime.sec not delimited");
670 SCREWUP("mtime.usec not delimited");
673 SCREWUP("atime.sec not delimited");
676 SCREWUP("atime.usec not delimited");
680 if (*cp
!= 'C' && *cp
!= 'D') {
682 * Check for the case "rcp remote:foo\* local:bar".
683 * In this case, the line "No match." can be returned
684 * by the shell before the rcp command on the remote is
685 * executed so the ^Aerror_message convention isn't
692 SCREWUP("expected control record");
696 for (; cp
< cmdbuf
+5; cp
++) {
697 if (*cp
< '0' || *cp
> '7')
699 mode
= (mode
<< 3) | (*cp
- '0');
702 SCREWUP("mode not delimited");
705 size
= size
* 10 + (*cp
++ - '0');
707 SCREWUP("size not delimited");
709 (void) sprintf(nambuf
, "%s%s%s", targ
,
710 *targ
? "/" : "", cp
);
712 (void) strcpy(nambuf
, targ
);
713 exists
= stat(nambuf
, &stb
) == 0;
714 if (cmdbuf
[0] == 'D') {
716 if ((stb
.st_mode
&S_IFMT
) != S_IFDIR
) {
721 (void) chmod(nambuf
, mode
);
722 } else if (mkdir(nambuf
, mode
) < 0)
728 if (utime(nambuf
, &utimbuf
) < 0)
729 error("rcp: can't set times on %s: %s\n",
730 nambuf
, strerror(errno
));
734 if ((of
= creat(nambuf
, mode
)) < 0) {
736 error("rcp: %s: %s\n", nambuf
, strerror(errno
));
740 (void) chmod(nambuf
, mode
);
742 if ((bp
= allocbuf(&buffer
, of
, BUFSIZ
)) == 0) {
749 for (i
= 0; i
< size
; i
+= BUFSIZ
) {
755 j
= read(rem
, cp
, amt
);
761 if (count
== bp
->cnt
) {
763 write(of
, bp
->buf
, count
) != count
)
769 if (count
!= 0 && wrerr
== 0 &&
770 write(of
, bp
->buf
, count
) != count
)
776 if (utime(nambuf
, &utimbuf
) < 0)
777 error("rcp: can't set times on %s: %s\n",
778 nambuf
, strerror(errno
));
781 error("rcp: %s: %s\n", nambuf
, strerror(errno
));
786 error("rcp: protocol screwup: %s\n", whopp
);
791 allocbuf(bp
, fd
, blksize
)
798 if (fstat(fd
, &stb
) < 0) {
799 error("rcp: fstat: %s\n", strerror(errno
));
800 return ((struct buffer
*)0);
804 size
= roundup(stb
.st_blksize
, blksize
);
808 if (bp
->cnt
< size
) {
811 bp
->buf
= (char *)malloc((unsigned) size
);
813 error("rcp: malloc: out of memory\n");
814 return ((struct buffer
*)0);
824 error (char *fmt
, ...)
830 char buf
[BUFSIZ
], *cp
= buf
;
837 (void) vsprintf(cp
, fmt
, ap
);
839 (void) write(rem
, buf
, strlen(buf
));
841 (void) write(2, buf
+1, strlen(buf
+1));
847 fprintf(stderr
, "Usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n");