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