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