make -l, -m mutually exclusive, rename -n as -K for consistency with
[unix-history] / usr / src / bin / rcp / rcp.c
CommitLineData
22e155fc 1/*
ebb479fc
KB
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
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
28e380e2 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22e155fc
DF
16 */
17
18#ifndef lint
19char copyright[] =
ebb479fc 20"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
22e155fc 21 All rights reserved.\n";
ebb479fc 22#endif /* not lint */
22e155fc 23
b7ff3bb3 24#ifndef lint
6ebcb998 25static char sccsid[] = "@(#)rcp.c 5.25 (Berkeley) %G%";
ebb479fc 26#endif /* not lint */
b7ff3bb3 27
4ca10280
SL
28/*
29 * rcp
30 */
ed0072ae 31#include <sys/param.h>
5f286db0 32#include <sys/file.h>
b7ff3bb3 33#include <sys/stat.h>
af86e024 34#include <sys/time.h>
b7ff3bb3 35#include <sys/ioctl.h>
35673a6d
KB
36#include <sys/dir.h>
37#include <sys/signal.h>
94a2d2a7 38#include <netinet/in.h>
b7ff3bb3 39#include <pwd.h>
92e58d95 40#include <netdb.h>
b7ff3bb3 41#include <errno.h>
6ebcb998 42#include <string.h>
35673a6d
KB
43#include <stdio.h>
44#include <ctype.h>
e4ba000a 45#include "pathnames.h"
4ca10280 46
35673a6d 47#ifdef KERBEROS
579f51c2 48#include <kerberosIV/krb.h>
5d178979
KF
49char dst_realm_buf[REALM_SZ];
50char *dest_realm = NULL;
51int use_kerberos = 1, encrypt = 0;
52CREDENTIALS cred;
53Key_schedule schedule;
54extern char *krb_realmofhost();
55#define OPTIONS "dfkprtx"
56#else
57#define OPTIONS "dfprt"
2b6b7619
KF
58#endif
59
35673a6d 60extern int errno;
35673a6d 61struct passwd *pwd;
5d178979
KF
62u_short port;
63uid_t userid;
64int errs, rem;
65int pflag, iamremote, iamrecursive, targetshouldbedirectory;
371655cc 66
5d178979 67#define CMDNEEDS 64
d4c44137 68char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
b7ff3bb3 69
35673a6d
KB
70typedef struct _buf {
71 int cnt;
72 char *buf;
73} BUF;
b7ff3bb3
BJ
74
75main(argc, argv)
76 int argc;
77 char **argv;
78{
35673a6d 79 extern int optind;
11bfe9c9 80 struct servent *sp;
f95b553a 81 int ch, fflag, tflag;
35673a6d
KB
82 char *targ, *colon();
83 struct passwd *getpwuid();
84 int lostconn();
92e58d95 85
f95b553a 86 fflag = tflag = 0;
5d178979 87 while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
35673a6d 88 switch(ch) {
5d178979 89 /* user-visible flags */
35673a6d
KB
90 case 'p': /* preserve access/mod times */
91 ++pflag;
af86e024 92 break;
35673a6d
KB
93 case 'r':
94 ++iamrecursive;
af86e024 95 break;
5d178979
KF
96#ifdef KERBEROS
97 case 'k':
98 strncpy(dst_realm_buf, ++argv, REALM_SZ);
99 dest_realm = dst_realm_buf;
f95b553a 100 break;
35673a6d
KB
101 case 'x':
102 encrypt = 1;
5d178979 103 /* des_set_key(cred.session, schedule); */
35673a6d
KB
104 break;
105#endif
5d178979
KF
106 /* rshd-invoked options (server) */
107 case 'd':
108 targetshouldbedirectory = 1;
109 break;
110 case 'f': /* "from" */
111 iamremote = 1;
112 fflag = 1;
113 break;
114 case 't': /* "to" */
115 iamremote = 1;
116 tflag = 1;
117 break;
118
35673a6d
KB
119 case '?':
120 default:
5f286db0 121 usage();
af86e024 122 }
35673a6d
KB
123 argc -= optind;
124 argv += optind;
125
5d178979
KF
126#ifdef KERBEROS
127 sp = getservbyname((encrypt ? "ekshell" : "kshell"), "tcp");
128 if (sp == NULL) {
129 char msgbuf[64];
130 use_kerberos = 0;
131 (void) sprintf(msgbuf, "can't get entry for %s/tcp service",
132 (encrypt ? "ekshell" : "kshell"));
133 old_warning(msgbuf);
134 sp = getservbyname("shell", "tcp");
135 }
136#else
137 sp = getservbyname("shell", "tcp");
138#endif
139 if (sp == NULL) {
140 (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n");
141 exit(1);
142 }
143 port = sp->s_port;
144
145 if (!(pwd = getpwuid(userid = getuid()))) {
146 (void)fprintf(stderr, "rcp: unknown user %d.\n", userid);
147 exit(1);
148 }
149
f95b553a 150 if (fflag) {
5d178979 151 /* follow "protocol", send data */
f95b553a
KB
152 (void)response();
153 (void)setuid(userid);
154 source(argc, argv);
155 exit(errs);
156 }
157
158 if (tflag) {
5d178979 159 /* receive data */
f95b553a
KB
160 (void)setuid(userid);
161 sink(argc, argv);
162 exit(errs);
163 }
164
5f286db0
KB
165 if (argc < 2)
166 usage();
b7ff3bb3
BJ
167 if (argc > 2)
168 targetshouldbedirectory = 1;
35673a6d 169
5f286db0 170 rem = -1;
5d178979
KF
171 /* command to be executed on remote system using "rsh" */
172#ifdef KERBEROS
173 (void)sprintf(cmd, "rcp%s%s%s%s", iamrecursive ? " -r" : "",
174 ((encrypt && use_kerberos) ? " -x" : ""),
175 pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
176#else
35673a6d
KB
177 (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "",
178 pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
5d178979 179#endif
35673a6d
KB
180
181 (void)signal(SIGPIPE, lostconn);
182
183 if (targ = colon(argv[argc - 1]))
5d178979 184 toremote(targ, argc, argv); /* destination is remote host */
35673a6d 185 else {
5d178979 186 tolocal(argc, argv); /* destination is local host */
35673a6d
KB
187 if (targetshouldbedirectory)
188 verifydir(argv[argc - 1]);
189 }
190 exit(errs);
191}
192
193toremote(targ, argc, argv)
194 char *targ;
195 int argc;
196 char **argv;
197{
198 int i;
d4c44137
KB
199 char *bp, *host, *src, *suser, *thost, *tuser;
200 char *colon(), *malloc();
35673a6d
KB
201
202 *targ++ = 0;
203 if (*targ == 0)
204 targ = ".";
205
d4c44137 206 if (thost = index(argv[argc - 1], '@')) {
5d178979 207 /* user@host */
35673a6d
KB
208 *thost++ = 0;
209 tuser = argv[argc - 1];
210 if (*tuser == '\0')
9e9252a8 211 tuser = NULL;
35673a6d
KB
212 else if (!okname(tuser))
213 exit(1);
214 } else {
215 thost = argv[argc - 1];
216 tuser = NULL;
217 }
2b6b7619 218
35673a6d
KB
219 for (i = 0; i < argc - 1; i++) {
220 src = colon(argv[i]);
221 if (src) { /* remote to remote */
222 *src++ = 0;
223 if (*src == 0)
224 src = ".";
225 host = index(argv[i], '@');
d4c44137
KB
226 if (!(bp = malloc((u_int)(strlen(_PATH_RSH) +
227 strlen(argv[i]) + strlen(src) +
ef49bf4f 228 tuser ? strlen(tuser) : 0 + strlen(thost) +
d4c44137
KB
229 strlen(targ)) + CMDNEEDS + 20)))
230 nospace();
35673a6d
KB
231 if (host) {
232 *host++ = 0;
233 suser = argv[i];
234 if (*suser == '\0')
235 suser = pwd->pw_name;
236 else if (!okname(suser))
237 continue;
d4c44137 238 (void)sprintf(bp,
35673a6d
KB
239 "%s %s -l %s -n %s %s '%s%s%s:%s'",
240 _PATH_RSH, host, suser, cmd, src,
241 tuser ? tuser : "", tuser ? "@" : "",
242 thost, targ);
243 } else
d4c44137 244 (void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'",
35673a6d
KB
245 _PATH_RSH, argv[i], cmd, src,
246 tuser ? tuser : "", tuser ? "@" : "",
247 thost, targ);
d4c44137
KB
248 (void)susystem(bp);
249 (void)free(bp);
35673a6d
KB
250 } else { /* local to remote */
251 if (rem == -1) {
d4c44137
KB
252 if (!(bp = malloc((u_int)strlen(targ) +
253 CMDNEEDS + 20)))
254 nospace();
255 (void)sprintf(bp, "%s -t %s", cmd, targ);
35673a6d
KB
256 host = thost;
257#ifdef KERBEROS
258 if (use_kerberos)
5d178979
KF
259 rem = kerberos(&host, bp,
260 pwd->pw_name,
d4c44137 261 tuser ? tuser : pwd->pw_name);
35673a6d
KB
262 else
263#endif
9e9252a8
JB
264 rem = rcmd(&host, port, pwd->pw_name,
265 tuser ? tuser : pwd->pw_name,
d4c44137 266 bp, 0);
35673a6d
KB
267 if (rem < 0)
268 exit(1);
269 if (response() < 0)
270 exit(1);
d4c44137 271 (void)free(bp);
35673a6d 272 (void)setuid(userid);
b7ff3bb3 273 }
35673a6d 274 source(1, argv+i);
b7ff3bb3 275 }
35673a6d
KB
276 }
277}
278
279tolocal(argc, argv)
280 int argc;
281 char **argv;
282{
283 int i;
d4c44137
KB
284 char *bp, *host, *src, *suser;
285 char *colon(), *malloc();
35673a6d
KB
286
287 for (i = 0; i < argc - 1; i++) {
d4c44137
KB
288 if (!(src = colon(argv[i]))) { /* local to local */
289 if (!(bp = malloc((u_int)(strlen(_PATH_CP) +
290 strlen(argv[i]) + strlen(argv[argc - 1])) + 20)))
291 nospace();
292 (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP,
293 iamrecursive ? " -r" : "", pflag ? " -p" : "",
294 argv[i], argv[argc - 1]);
295 (void)susystem(bp);
296 (void)free(bp);
297 continue;
298 }
299 *src++ = 0;
300 if (*src == 0)
301 src = ".";
302 host = index(argv[i], '@');
303 if (host) {
304 *host++ = 0;
305 suser = argv[i];
306 if (*suser == '\0')
35673a6d 307 suser = pwd->pw_name;
d4c44137 308 else if (!okname(suser))
35673a6d 309 continue;
d4c44137
KB
310 } else {
311 host = argv[i];
312 suser = pwd->pw_name;
b7ff3bb3 313 }
d4c44137
KB
314 if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20)))
315 nospace();
316 (void)sprintf(bp, "%s -f %s", cmd, src);
317#ifdef KERBEROS
318 if (use_kerberos)
5d178979 319 rem = kerberos(&host, bp, pwd->pw_name, suser);
d4c44137
KB
320 else
321#endif
322 rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0);
323 (void)free(bp);
324 if (rem < 0)
325 continue;
326 (void)setreuid(0, userid);
327 sink(1, argv + argc - 1);
328 (void)setreuid(userid, 0);
329 (void)close(rem);
330 rem = -1;
b7ff3bb3 331 }
b7ff3bb3
BJ
332}
333
334verifydir(cp)
335 char *cp;
336{
337 struct stat stb;
338
11bfe9c9
RC
339 if (stat(cp, &stb) >= 0) {
340 if ((stb.st_mode & S_IFMT) == S_IFDIR)
341 return;
342 errno = ENOTDIR;
343 }
ef49bf4f 344 error("rcp: %s: %s.\n", cp, strerror(errno));
b7ff3bb3
BJ
345 exit(1);
346}
347
348char *
349colon(cp)
35673a6d 350 register char *cp;
b7ff3bb3 351{
35673a6d 352 for (; *cp; ++cp) {
b7ff3bb3 353 if (*cp == ':')
35673a6d 354 return(cp);
b7ff3bb3 355 if (*cp == '/')
35673a6d 356 return(0);
b7ff3bb3 357 }
35673a6d 358 return(0);
b7ff3bb3
BJ
359}
360
361okname(cp0)
362 char *cp0;
363{
364 register char *cp = cp0;
365 register int c;
366
367 do {
368 c = *cp;
369 if (c & 0200)
370 goto bad;
371 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
372 goto bad;
d4c44137 373 } while (*++cp);
35673a6d 374 return(1);
b7ff3bb3 375bad:
d4c44137 376 (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0);
35673a6d 377 return(0);
b7ff3bb3
BJ
378}
379
48755084
S
380susystem(s)
381 char *s;
b7ff3bb3 382{
48755084 383 int status, pid, w;
5d178979 384 register sig_t istat, qstat;
b7ff3bb3 385
48755084 386 if ((pid = vfork()) == 0) {
35673a6d 387 (void)setuid(userid);
e4ba000a 388 execl(_PATH_BSHELL, "sh", "-c", s, (char *)0);
48755084
S
389 _exit(127);
390 }
391 istat = signal(SIGINT, SIG_IGN);
392 qstat = signal(SIGQUIT, SIG_IGN);
393 while ((w = wait(&status)) != pid && w != -1)
394 ;
395 if (w == -1)
396 status = -1;
35673a6d
KB
397 (void)signal(SIGINT, istat);
398 (void)signal(SIGQUIT, qstat);
399 return(status);
b7ff3bb3
BJ
400}
401
402source(argc, argv)
403 int argc;
404 char **argv;
405{
b7ff3bb3 406 struct stat stb;
35673a6d
KB
407 static BUF buffer;
408 BUF *bp;
5f10dd79 409 off_t i;
35673a6d
KB
410 int x, readerr, f, amt;
411 char *last, *name, buf[BUFSIZ];
412 BUF *allocbuf();
b7ff3bb3
BJ
413
414 for (x = 0; x < argc; x++) {
415 name = argv[x];
35673a6d 416 if ((f = open(name, O_RDONLY, 0)) < 0) {
ef49bf4f 417 error("rcp: %s: %s\n", name, strerror(errno));
b7ff3bb3
BJ
418 continue;
419 }
420 if (fstat(f, &stb) < 0)
421 goto notreg;
422 switch (stb.st_mode&S_IFMT) {
423
424 case S_IFREG:
425 break;
426
427 case S_IFDIR:
428 if (iamrecursive) {
35673a6d 429 (void)close(f);
af86e024 430 rsource(name, &stb);
b7ff3bb3
BJ
431 continue;
432 }
35673a6d 433 /* FALLTHROUGH */
b7ff3bb3 434 default:
35673a6d 435notreg: (void)close(f);
b7ff3bb3
BJ
436 error("rcp: %s: not a plain file\n", name);
437 continue;
438 }
439 last = rindex(name, '/');
440 if (last == 0)
441 last = name;
442 else
443 last++;
af86e024
JL
444 if (pflag) {
445 /*
446 * Make it compatible with possible future
447 * versions expecting microseconds.
448 */
d4c44137
KB
449 (void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime,
450 stb.st_atime);
35673a6d 451 (void)write(rem, buf, strlen(buf));
af86e024 452 if (response() < 0) {
35673a6d 453 (void)close(f);
af86e024
JL
454 continue;
455 }
456 }
d4c44137
KB
457 (void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777,
458 stb.st_size, last);
35673a6d 459 (void)write(rem, buf, strlen(buf));
b7ff3bb3 460 if (response() < 0) {
35673a6d 461 (void)close(f);
b7ff3bb3
BJ
462 continue;
463 }
809ba2d2 464 if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
35673a6d 465 (void)close(f);
371655cc
KM
466 continue;
467 }
f68c1c98 468 readerr = 0;
371655cc
KM
469 for (i = 0; i < stb.st_size; i += bp->cnt) {
470 amt = bp->cnt;
b7ff3bb3
BJ
471 if (i + amt > stb.st_size)
472 amt = stb.st_size - i;
f68c1c98
KB
473 if (readerr == 0 && read(f, bp->buf, amt) != amt)
474 readerr = errno;
35673a6d 475 (void)write(rem, bp->buf, amt);
b7ff3bb3 476 }
35673a6d 477 (void)close(f);
f68c1c98 478 if (readerr == 0)
35673a6d 479 (void)write(rem, "", 1);
b7ff3bb3 480 else
ef49bf4f 481 error("rcp: %s: %s\n", name, strerror(readerr));
35673a6d 482 (void)response();
b7ff3bb3
BJ
483 }
484}
485
af86e024 486rsource(name, statp)
b7ff3bb3 487 char *name;
af86e024 488 struct stat *statp;
b7ff3bb3 489{
35673a6d 490 DIR *d;
b7ff3bb3 491 struct direct *dp;
d4c44137 492 char *last, *vect[1], path[MAXPATHLEN];
b7ff3bb3 493
35673a6d 494 if (!(d = opendir(name))) {
ef49bf4f 495 error("rcp: %s: %s\n", name, strerror(errno));
b7ff3bb3
BJ
496 return;
497 }
498 last = rindex(name, '/');
499 if (last == 0)
500 last = name;
501 else
502 last++;
af86e024 503 if (pflag) {
d4c44137
KB
504 (void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime,
505 statp->st_atime);
506 (void)write(rem, path, strlen(path));
af86e024
JL
507 if (response() < 0) {
508 closedir(d);
509 return;
510 }
511 }
d4c44137
KB
512 (void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
513 (void)write(rem, path, strlen(path));
b7ff3bb3
BJ
514 if (response() < 0) {
515 closedir(d);
516 return;
517 }
518 while (dp = readdir(d)) {
519 if (dp->d_ino == 0)
520 continue;
521 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
522 continue;
d4c44137
KB
523 if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
524 error("%s/%s: name too long.\n", name, dp->d_name);
b7ff3bb3
BJ
525 continue;
526 }
d4c44137
KB
527 (void)sprintf(path, "%s/%s", name, dp->d_name);
528 vect[0] = path;
529 source(1, vect);
b7ff3bb3
BJ
530 }
531 closedir(d);
35673a6d
KB
532 (void)write(rem, "E\n", 2);
533 (void)response();
b7ff3bb3
BJ
534}
535
536response()
537{
35673a6d
KB
538 register char *cp;
539 char ch, resp, rbuf[BUFSIZ];
b7ff3bb3 540
35673a6d 541 if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
b7ff3bb3 542 lostconn();
b7ff3bb3 543
35673a6d
KB
544 cp = rbuf;
545 switch(resp) {
af86e024 546 case 0: /* ok */
35673a6d 547 return(0);
b7ff3bb3
BJ
548 default:
549 *cp++ = resp;
35673a6d 550 /* FALLTHROUGH */
af86e024
JL
551 case 1: /* error, followed by err msg */
552 case 2: /* fatal error, "" */
b7ff3bb3 553 do {
35673a6d 554 if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
b7ff3bb3 555 lostconn();
35673a6d
KB
556 *cp++ = ch;
557 } while (cp < &rbuf[BUFSIZ] && ch != '\n');
558
559 if (!iamremote)
560 (void)write(2, rbuf, cp - rbuf);
561 ++errs;
b7ff3bb3 562 if (resp == 1)
35673a6d 563 return(-1);
b7ff3bb3
BJ
564 exit(1);
565 }
566 /*NOTREACHED*/
567}
568
569lostconn()
570{
35673a6d
KB
571 if (!iamremote)
572 (void)fprintf(stderr, "rcp: lost connection\n");
b7ff3bb3
BJ
573 exit(1);
574}
575
576sink(argc, argv)
577 int argc;
578 char **argv;
579{
d4c44137 580 register char *cp;
35673a6d 581 static BUF buffer;
371655cc 582 struct stat stb;
af86e024 583 struct timeval tv[2];
ef49bf4f 584 enum { YES, NO, DISPLAYED } wrerr;
d4c44137
KB
585 BUF *bp, *allocbuf();
586 off_t i, j;
587 char ch, *targ, *why;
588 int amt, count, exists, first, mask, mode;
ef49bf4f 589 int ofd, setimes, size, targisdir;
d4c44137 590 char *np, *vect[1], buf[BUFSIZ], *malloc();
b7ff3bb3 591
d4c44137
KB
592#define atime tv[0]
593#define mtime tv[1]
594#define SCREWUP(str) { why = str; goto screwup; }
595
596 setimes = targisdir = 0;
597 mask = umask(0);
a4372a41 598 if (!pflag)
35673a6d 599 (void)umask(mask);
11bfe9c9 600 if (argc != 1) {
b7ff3bb3
BJ
601 error("rcp: ambiguous target\n");
602 exit(1);
603 }
604 targ = *argv;
605 if (targetshouldbedirectory)
606 verifydir(targ);
35673a6d 607 (void)write(rem, "", 1);
b7ff3bb3
BJ
608 if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
609 targisdir = 1;
d4c44137
KB
610 for (first = 1;; first = 0) {
611 cp = buf;
b7ff3bb3
BJ
612 if (read(rem, cp, 1) <= 0)
613 return;
614 if (*cp++ == '\n')
d4c44137 615 SCREWUP("unexpected <newline>");
b7ff3bb3 616 do {
d4c44137 617 if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
b7ff3bb3 618 SCREWUP("lost connection");
d4c44137
KB
619 *cp++ = ch;
620 } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
b7ff3bb3 621 *cp = 0;
d4c44137
KB
622
623 if (buf[0] == '\01' || buf[0] == '\02') {
b7ff3bb3 624 if (iamremote == 0)
d4c44137
KB
625 (void)write(2, buf + 1, strlen(buf + 1));
626 if (buf[0] == '\02')
b7ff3bb3
BJ
627 exit(1);
628 errs++;
629 continue;
630 }
d4c44137 631 if (buf[0] == 'E') {
35673a6d 632 (void)write(rem, "", 1);
b7ff3bb3
BJ
633 return;
634 }
af86e024 635
3eafec57 636 if (ch == '\n')
6f6da275 637 *--cp = 0;
3eafec57 638
af86e024 639#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
d4c44137 640 cp = buf;
af86e024
JL
641 if (*cp == 'T') {
642 setimes++;
643 cp++;
644 getnum(mtime.tv_sec);
645 if (*cp++ != ' ')
646 SCREWUP("mtime.sec not delimited");
647 getnum(mtime.tv_usec);
648 if (*cp++ != ' ')
649 SCREWUP("mtime.usec not delimited");
650 getnum(atime.tv_sec);
651 if (*cp++ != ' ')
652 SCREWUP("atime.sec not delimited");
653 getnum(atime.tv_usec);
654 if (*cp++ != '\0')
655 SCREWUP("atime.usec not delimited");
35673a6d 656 (void)write(rem, "", 1);
af86e024
JL
657 continue;
658 }
4550ab9e
RC
659 if (*cp != 'C' && *cp != 'D') {
660 /*
661 * Check for the case "rcp remote:foo\* local:bar".
662 * In this case, the line "No match." can be returned
663 * by the shell before the rcp command on the remote is
664 * executed so the ^Aerror_message convention isn't
665 * followed.
666 */
667 if (first) {
668 error("%s\n", cp);
669 exit(1);
670 }
b7ff3bb3 671 SCREWUP("expected control record");
4550ab9e 672 }
b7ff3bb3 673 mode = 0;
d4c44137 674 for (++cp; cp < buf + 5; cp++) {
b7ff3bb3
BJ
675 if (*cp < '0' || *cp > '7')
676 SCREWUP("bad mode");
677 mode = (mode << 3) | (*cp - '0');
678 }
679 if (*cp++ != ' ')
680 SCREWUP("mode not delimited");
681 size = 0;
a4372a41 682 while (isdigit(*cp))
b7ff3bb3
BJ
683 size = size * 10 + (*cp++ - '0');
684 if (*cp++ != ' ')
685 SCREWUP("size not delimited");
d4c44137
KB
686 if (targisdir) {
687 static char *namebuf;
688 static int cursize;
689 int need;
690
691 need = strlen(targ) + strlen(cp) + 250;
692 if (need > cursize) {
693 if (!(namebuf = malloc((u_int)need)))
3eafec57 694 error("out of memory\n");
d4c44137
KB
695 }
696 (void)sprintf(namebuf, "%s%s%s", targ,
b7ff3bb3 697 *targ ? "/" : "", cp);
d4c44137
KB
698 np = namebuf;
699 }
b7ff3bb3 700 else
d4c44137
KB
701 np = targ;
702 exists = stat(np, &stb) == 0;
703 if (buf[0] == 'D') {
11bfe9c9 704 if (exists) {
b7ff3bb3
BJ
705 if ((stb.st_mode&S_IFMT) != S_IFDIR) {
706 errno = ENOTDIR;
707 goto bad;
708 }
a4372a41 709 if (pflag)
d4c44137
KB
710 (void)chmod(np, mode);
711 } else if (mkdir(np, mode) < 0)
b7ff3bb3 712 goto bad;
d4c44137
KB
713 vect[0] = np;
714 sink(1, vect);
af86e024
JL
715 if (setimes) {
716 setimes = 0;
d4c44137
KB
717 if (utimes(np, tv) < 0)
718 error("rcp: can't set times on %s: %s\n",
ef49bf4f 719 np, strerror(errno));
af86e024 720 }
b7ff3bb3 721 continue;
11bfe9c9 722 }
d4c44137 723 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
ef49bf4f 724bad: error("rcp: %s: %s\n", np, strerror(errno));
b7ff3bb3 725 continue;
b7ff3bb3 726 }
a4372a41 727 if (exists && pflag)
d4c44137 728 (void)fchmod(ofd, mode);
35673a6d 729 (void)write(rem, "", 1);
d4c44137
KB
730 if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) {
731 (void)close(ofd);
371655cc
KM
732 continue;
733 }
734 cp = bp->buf;
735 count = 0;
ef49bf4f 736 wrerr = NO;
b7ff3bb3 737 for (i = 0; i < size; i += BUFSIZ) {
371655cc 738 amt = BUFSIZ;
b7ff3bb3
BJ
739 if (i + amt > size)
740 amt = size - i;
371655cc 741 count += amt;
b7ff3bb3 742 do {
371655cc 743 j = read(rem, cp, amt);
9e9252a8 744 if (j <= 0) {
3eafec57 745 error("rcp: %s\n",
ef49bf4f 746 j ? strerror(errno) :
d4c44137 747 "dropped connection");
b7ff3bb3 748 exit(1);
9e9252a8 749 }
b7ff3bb3
BJ
750 amt -= j;
751 cp += j;
752 } while (amt > 0);
371655cc 753 if (count == bp->cnt) {
ef49bf4f 754 if (wrerr == NO &&
d4c44137 755 write(ofd, bp->buf, count) != count)
ef49bf4f 756 wrerr = YES;
371655cc
KM
757 count = 0;
758 cp = bp->buf;
759 }
b7ff3bb3 760 }
ef49bf4f 761 if (count != 0 && wrerr == NO &&
d4c44137 762 write(ofd, bp->buf, count) != count)
ef49bf4f
KB
763 wrerr = YES;
764 if (ftruncate(ofd, size)) {
d4c44137 765 error("rcp: can't truncate %s: %s\n", np,
ef49bf4f
KB
766 strerror(errno));
767 wrerr = DISPLAYED;
768 }
d4c44137 769 (void)close(ofd);
35673a6d 770 (void)response();
ef49bf4f 771 if (setimes && wrerr == NO) {
af86e024 772 setimes = 0;
ef49bf4f 773 if (utimes(np, tv) < 0) {
af86e024 774 error("rcp: can't set times on %s: %s\n",
ef49bf4f
KB
775 np, strerror(errno));
776 wrerr = DISPLAYED;
777 }
778 }
779 switch(wrerr) {
780 case YES:
781 error("rcp: %s: %s\n", np, strerror(errno));
782 break;
783 case NO:
35673a6d 784 (void)write(rem, "", 1);
ef49bf4f
KB
785 break;
786 case DISPLAYED:
787 break;
788 }
b7ff3bb3
BJ
789 }
790screwup:
d4c44137 791 error("rcp: protocol screwup: %s\n", why);
b7ff3bb3
BJ
792 exit(1);
793}
794
35673a6d 795BUF *
371655cc 796allocbuf(bp, fd, blksize)
35673a6d 797 BUF *bp;
371655cc
KM
798 int fd, blksize;
799{
800 struct stat stb;
801 int size;
35673a6d 802 char *malloc();
371655cc
KM
803
804 if (fstat(fd, &stb) < 0) {
ef49bf4f 805 error("rcp: fstat: %s\n", strerror(errno));
35673a6d 806 return(0);
371655cc
KM
807 }
808 size = roundup(stb.st_blksize, blksize);
809 if (size == 0)
810 size = blksize;
811 if (bp->cnt < size) {
812 if (bp->buf != 0)
813 free(bp->buf);
35673a6d 814 bp->buf = (char *)malloc((u_int)size);
d4c44137 815 if (!bp->buf) {
371655cc 816 error("rcp: malloc: out of memory\n");
35673a6d 817 return(0);
371655cc
KM
818 }
819 }
820 bp->cnt = size;
35673a6d 821 return(bp);
371655cc
KM
822}
823
35673a6d 824/* VARARGS1 */
d4c44137 825error(fmt, a1, a2, a3)
b7ff3bb3 826 char *fmt;
d4c44137 827 int a1, a2, a3;
b7ff3bb3 828{
3eafec57 829 static FILE *fp;
35673a6d
KB
830
831 ++errs;
3eafec57
KB
832 if (!fp && !(fp = fdopen(rem, "w")))
833 return;
834 (void)fprintf(fp, "%c", 0x01);
835 (void)fprintf(fp, fmt, a1, a2, a3);
836 (void)fflush(fp);
35673a6d 837 if (!iamremote)
3eafec57 838 (void)fprintf(stderr, fmt, a1, a2, a3);
b7ff3bb3 839}
5f286db0 840
d4c44137
KB
841nospace()
842{
843 (void)fprintf(stderr, "rcp: out of memory.\n");
844 exit(1);
845}
846
d4c44137 847
5f286db0
KB
848usage()
849{
35673a6d
KB
850#ifdef KERBEROS
851 (void)fprintf(stderr, "%s\n\t%s\n",
852 "usage: rcp [-k realm] [-px] f1 f2",
853 "or: rcp [-k realm] [-rpx] f1 ... fn directory");
a678b549 854#else
35673a6d
KB
855 (void)fprintf(stderr,
856 "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n");
a678b549 857#endif
5f286db0
KB
858 exit(1);
859}
5d178979
KF
860
861#ifdef KERBEROS
862old_warning(str)
863 char *str;
864{
865 (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str);
866}
867
868int
869kerberos(host, bp, locuser, user)
870
871 char **host, *bp, *locuser, *user;
872{
873 struct servent *sp;
874
875again:
876 if (use_kerberos) {
877 rem = KSUCCESS;
878 errno = 0;
879 if (dest_realm == NULL)
880 dest_realm = krb_realmofhost(*host);
881
882 if (encrypt)
883 rem = krcmd_mutual(
884 host, port,
885 user, bp, 0,
886 dest_realm,
887 &cred, schedule);
888 else
889 rem = krcmd(
890 host, port,
891 user, bp, 0, dest_realm);
892
893 if (rem < 0) {
894 use_kerberos = 0;
895 sp = getservbyname("shell", "tcp");
896 if (sp == NULL) {
897 (void)fprintf(stderr,
898 "rcp: unknown service shell/tcp\n");
899 exit(1);
900 }
901 if (errno == ECONNREFUSED)
902 old_warning(
903 "remote host doesn't support Kerberos");
904
905 if (errno == ENOENT)
906 old_warning(
907 "Can't provide Kerberos auth data");
908 port = sp->s_port;
909 goto again;
910 }
911 } else {
912 if (encrypt) {
913 fprintf(stderr,
914 "The -x option requires Kerberos authentication\n");
915 exit(1);
916 }
917 rem = rcmd(host, sp->s_port, locuser, user, bp, 0);
918 }
919 return(rem);
920}
921#endif /* KERBEROS */