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