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