* Copyright (c) 1983 The Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
static char sccsid
[] = "@(#)rcp.c 5.15 (Berkeley) %G%";
#include <kerberos/krb.h>
char krb_realm
[REALM_SZ
];
int use_kerberos
= 1, encrypt
= 0;
char *colon(), *index(), *rindex(), *malloc(), *strcpy();
int iamremote
, targetshouldbedirectory
;
struct passwd
*getpwuid();
#define ga() (void) write(rem, "", 1)
char *suser
, *tuser
, *thost
;
char buf
[BUFSIZ
], cmd
[16];
sp
= getservbyname("kshell", "tcp");
old_warning("kshell service unknown");
sp
= getservbyname("kshell", "tcp");
sp
= getservbyname("shell", "tcp");
fprintf(stderr
, "rcp: shell/tcp: unknown service\n");
pwd
= getpwuid(userid
= getuid());
fprintf(stderr
, "who are you?\n");
for (argc
--, argv
++; argc
> 0 && **argv
== '-'; argc
--, argv
++) {
while (**argv
) switch (*(*argv
)++) {
des_set_key(cred
.session
, schedule
);
strncpy(krb_realm
, ++argv
, REALM_SZ
);
case 'p': /* preserve mtimes and atimes */
/* The rest of these are not for users. */
targetshouldbedirectory
= 1;
targetshouldbedirectory
= 1;
(void) sprintf(cmd
, "rcp%s%s%s",
iamrecursive
? " -r" : "", pflag
? " -p" : "",
targetshouldbedirectory
? " -d" : "");
(void) signal(SIGPIPE
, lostconn
);
targ
= colon(argv
[argc
- 1]);
if (targ
) { /* ... to remote */
thost
= index(argv
[argc
- 1], '@');
for (i
= 0; i
< argc
- 1; i
++) {
if (src
) { /* remote to remote */
host
= index(argv
[i
], '@');
(void) sprintf(buf
, "%s %s -l %s -n %s %s '%s%s%s:%s'",
_PATH_RSH
, host
, suser
, cmd
, src
,
(void) sprintf(buf
, "%s %s -n %s %s '%s%s%s:%s'",
_PATH_RSH
, argv
[i
], cmd
, src
,
} else { /* local to remote */
(void) sprintf(buf
, "%s -t %s",
rem
= krb_get_lrealm(krb_realm
,1);
"rcp: error getting local realm %s\n",
if((rem
< 0) && errno
== ECONNREFUSED
) {
old_warning("remote host doesn't support Kerberos");
sp
= getservbyname("shell", "tcp");
fprintf(stderr
, "unknown service shell/tcp\n");
rem
= rcmd(&host
, port
, pwd
->pw_name
,
tuser
? tuser
: pwd
->pw_name
,
rem
= rcmd(&host
, port
, pwd
->pw_name
,
tuser
? tuser
: pwd
->pw_name
,
} else { /* ... to local */
if (targetshouldbedirectory
)
verifydir(argv
[argc
- 1]);
for (i
= 0; i
< argc
- 1; i
++) {
if (src
== 0) { /* local to local */
(void) sprintf(buf
, "%s%s%s %s %s",
_PATH_CP
, iamrecursive
? " -r" : "",
argv
[i
], argv
[argc
- 1]);
} else { /* remote to local */
host
= index(argv
[i
], '@');
(void) sprintf(buf
, "%s -f %s", cmd
, src
);
rem
= krb_get_lrealm(krb_realm
,1);
"rcp: error getting local realm %s\n",
if((rem
< 0) && errno
== ECONNREFUSED
) {
old_warning("remote host doesn't suport Kerberos");
sp
= getservbyname("shell", "tcp");
fprintf(stderr
, "unknown service shell/tcp\n");
rem
= rcmd(&host
, port
, pwd
->pw_name
, suser
,
rem
= rcmd(&host
, port
, pwd
->pw_name
, suser
,
(void) setreuid(0, userid
);
(void) setreuid(userid
, 0);
if (stat(cp
, &stb
) >= 0) {
if ((stb
.st_mode
& S_IFMT
) == S_IFDIR
)
error("rcp: %s: %s.\n", cp
, sys_errlist
[errno
]);
if (!isalpha(c
) && !isdigit(c
) && c
!= '_' && c
!= '-')
fprintf(stderr
, "rcp: invalid user name %s\n", cp0
);
register int (*istat
)(), (*qstat
)();
if ((pid
= vfork()) == 0) {
execl(_PATH_BSHELL
, "sh", "-c", s
, (char *)0);
istat
= signal(SIGINT
, SIG_IGN
);
qstat
= signal(SIGQUIT
, SIG_IGN
);
while ((w
= wait(&status
)) != pid
&& w
!= -1)
(void) signal(SIGINT
, istat
);
(void) signal(SIGQUIT
, qstat
);
static struct buffer buffer
;
for (x
= 0; x
< argc
; x
++) {
if ((f
= open(name
, 0)) < 0) {
error("rcp: %s: %s\n", name
, sys_errlist
[errno
]);
switch (stb
.st_mode
&S_IFMT
) {
error("rcp: %s: not a plain file\n", name
);
last
= rindex(name
, '/');
* Make it compatible with possible future
* versions expecting microseconds.
(void) sprintf(buf
, "T%ld 0 %ld 0\n",
stb
.st_mtime
, stb
.st_atime
);
(void) write(rem
, buf
, strlen(buf
));
(void) sprintf(buf
, "C%04o %ld %s\n",
stb
.st_mode
&07777, stb
.st_size
, last
);
(void) write(rem
, buf
, strlen(buf
));
if ((bp
= allocbuf(&buffer
, f
, BUFSIZ
)) == 0) {
for (i
= 0; i
< stb
.st_size
; i
+= bp
->cnt
) {
if (i
+ amt
> stb
.st_size
)
if (readerr
== 0 && read(f
, bp
->buf
, amt
) != amt
)
(void) write(rem
, bp
->buf
, amt
);
error("rcp: %s: %s\n", name
, sys_errlist
[readerr
]);
error("rcp: %s: %s\n", name
, sys_errlist
[errno
]);
last
= rindex(name
, '/');
(void) sprintf(buf
, "T%ld 0 %ld 0\n",
statp
->st_mtime
, statp
->st_atime
);
(void) write(rem
, buf
, strlen(buf
));
(void) sprintf(buf
, "D%04o %d %s\n", statp
->st_mode
&07777, 0, last
);
(void) write(rem
, buf
, strlen(buf
));
while (dp
= readdir(d
)) {
if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, ".."))
if (strlen(name
) + 1 + strlen(dp
->d_name
) >= BUFSIZ
- 1) {
error("%s/%s: Name too long.\n", name
, dp
->d_name
);
(void) sprintf(buf
, "%s/%s", name
, dp
->d_name
);
(void) write(rem
, "E\n", 2);
char resp
, c
, rbuf
[BUFSIZ
], *cp
= rbuf
;
if (read(rem
, &resp
, 1) != 1)
case 1: /* error, followed by err msg */
case 2: /* fatal error, "" */
if (read(rem
, &c
, 1) != 1)
} while (cp
< &rbuf
[BUFSIZ
] && c
!= '\n');
(void) write(2, rbuf
, cp
- rbuf
);
fprintf(stderr
, "rcp: lost connection\n");
int of
, mode
, wrerr
, exists
, first
, count
, amt
, size
;
static struct buffer buffer
;
char cmdbuf
[BUFSIZ
], nambuf
[BUFSIZ
];
#define SCREWUP(str) { whopp = str; goto screwup; }
error("rcp: ambiguous target\n");
if (targetshouldbedirectory
)
if (stat(targ
, &stb
) == 0 && (stb
.st_mode
& S_IFMT
) == S_IFDIR
)
for (first
= 1; ; first
= 0) {
if (read(rem
, cp
, 1) <= 0)
SCREWUP("unexpected '\\n'");
if (read(rem
, cp
, 1) != 1)
SCREWUP("lost connection");
if (cmdbuf
[0] == '\01' || cmdbuf
[0] == '\02') {
(void) write(2, cmdbuf
+1, strlen(cmdbuf
+1));
#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
SCREWUP("mtime.sec not delimited");
SCREWUP("mtime.usec not delimited");
SCREWUP("atime.sec not delimited");
SCREWUP("atime.usec not delimited");
if (*cp
!= 'C' && *cp
!= 'D') {
* Check for the case "rcp remote:foo\* local:bar".
* In this case, the line "No match." can be returned
* by the shell before the rcp command on the remote is
* executed so the ^Aerror_message convention isn't
SCREWUP("expected control record");
for (; cp
< cmdbuf
+5; cp
++) {
if (*cp
< '0' || *cp
> '7')
mode
= (mode
<< 3) | (*cp
- '0');
SCREWUP("mode not delimited");
size
= size
* 10 + (*cp
++ - '0');
SCREWUP("size not delimited");
(void) sprintf(nambuf
, "%s%s%s", targ
,
(void) strcpy(nambuf
, targ
);
exists
= stat(nambuf
, &stb
) == 0;
if ((stb
.st_mode
&S_IFMT
) != S_IFDIR
) {
(void) chmod(nambuf
, mode
);
} else if (mkdir(nambuf
, mode
) < 0)
if (utimes(nambuf
, tv
) < 0)
error("rcp: can't set times on %s: %s\n",
nambuf
, sys_errlist
[errno
]);
if ((of
= open(nambuf
, O_WRONLY
|O_CREAT
, mode
)) < 0) {
error("rcp: %s: %s\n", nambuf
, sys_errlist
[errno
]);
if ((bp
= allocbuf(&buffer
, of
, BUFSIZ
)) == 0) {
for (i
= 0; i
< size
; i
+= BUFSIZ
) {
error("rcp: dropped connection");
write(of
, bp
->buf
, count
) != count
)
if (count
!= 0 && wrerr
== 0 &&
write(of
, bp
->buf
, count
) != count
)
error("rcp: can't truncate %s: %s\n",
nambuf
, sys_errlist
[errno
]);
if (utimes(nambuf
, tv
) < 0)
error("rcp: can't set times on %s: %s\n",
nambuf
, sys_errlist
[errno
]);
error("rcp: %s: %s\n", nambuf
, sys_errlist
[errno
]);
error("rcp: protocol screwup: %s\n", whopp
);
allocbuf(bp
, fd
, blksize
)
if (fstat(fd
, &stb
) < 0) {
error("rcp: fstat: %s\n", sys_errlist
[errno
]);
return ((struct buffer
*)0);
size
= roundup(stb
.st_blksize
, blksize
);
bp
->buf
= (char *)malloc((unsigned) size
);
error("rcp: malloc: out of memory\n");
return ((struct buffer
*)0);
error(fmt
, a1
, a2
, a3
, a4
, a5
)
char buf
[BUFSIZ
], *cp
= buf
;
(void) sprintf(cp
, fmt
, a1
, a2
, a3
, a4
, a5
);
(void) write(rem
, buf
, strlen(buf
));
(void) write(2, buf
+1, strlen(buf
+1));
fputs("usage: rcp [-k realm] [-x] [-p] f1 f2;\n", stderr
);
fputs(" or: rcp [-k realm] [-x] [-rp] f1 ... fn d2\n", stderr
);
fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr
);
fprintf(stderr
,"Warning: %s, using standard rcp\n", str
);