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