date and time created 83/01/21 11:12:40 by dlw
[unix-history] / usr / src / bin / rcp / rcp.c
CommitLineData
b7ff3bb3 1#ifndef lint
94a2d2a7 2static char sccsid[] = "@(#)rcp.c 4.4 82/11/14";
b7ff3bb3
BJ
3#endif
4
ed0072ae 5#include <sys/param.h>
b7ff3bb3
BJ
6#include <sys/stat.h>
7#include <sys/ioctl.h>
94a2d2a7
SL
8
9#include <netinet/in.h>
10
11#include <stdio.h>
12#include <signal.h>
b7ff3bb3
BJ
13#include <pwd.h>
14#include <ctype.h>
15#include <errno.h>
16/*
17 * rcp
18 */
19int rem;
20char *colon(), *index(), *rindex(), *malloc(), *strcpy(), *sprintf();
21int errs;
22int lostconn();
23int iamremote;
24
25int errno;
26char *sys_errlist[];
27int iamremote, targetshouldbedirectory;
28int iamrecursive;
29struct passwd *pwd;
30struct passwd *getpwuid();
31
32/*VARARGS*/
33int error();
34
35#define ga() (void) write(rem, "", 1)
36
37main(argc, argv)
38 int argc;
39 char **argv;
40{
41 char *targ, *host, *src;
42 char *suser, *tuser;
43 int i;
44 char buf[BUFSIZ], cmd[16];
45
46 setpwent();
47 pwd = getpwuid(getuid());
48 endpwent();
49 if (pwd == 0) {
50 fprintf(stderr, "who are you?\n");
51 exit(1);
52 }
53 argc--, argv++;
54 if (argc > 0 && !strcmp(*argv, "-r")) {
55 iamrecursive++;
56 argc--, argv++;
57 }
58 if (argc > 0 && !strcmp(*argv, "-d")) {
59 targetshouldbedirectory = 1;
60 argc--, argv++;
61 }
62 if (argc > 0 && !strcmp(*argv, "-f")) {
63 argc--, argv++; iamremote = 1;
64 (void) response();
65 (void) setuid(getuid());
66 source(argc, argv);
67 exit(errs);
68 }
69 if (argc > 0 && !strcmp(*argv, "-t")) {
70 argc--, argv++; iamremote = 1;
71 (void) setuid(getuid());
72 sink(argc, argv);
73 exit(errs);
74 }
75 rem = -1;
76 if (argc > 2)
77 targetshouldbedirectory = 1;
78 (void) sprintf(cmd, "rcp%s%s",
79 iamrecursive ? " -r" : "", targetshouldbedirectory ? " -d" : "");
80 sigsys(SIGPIPE, lostconn);
81 targ = colon(argv[argc - 1]);
82 if (targ) {
83 *targ++ = 0;
84 tuser = rindex(argv[argc - 1], '.');
85 if (tuser) {
86 *tuser++ = 0;
87 if (!okname(tuser))
88 exit(1);
89 } else
90 tuser = pwd->pw_name;
91 for (i = 0; i < argc - 1; i++) {
92 src = colon(argv[i]);
93 if (src) {
94 *src++ = 0;
95 suser = rindex(argv[i], '.');
96 if (suser) {
97 *suser++ = 0;
98 if (!okname(suser))
99 continue;
5f10dd79 100 (void) sprintf(buf, "rsh %s -L %s %s %s '%s:%s' </dev/null",
b7ff3bb3
BJ
101 argv[i], suser, cmd,
102 src, argv[argc - 1], targ);
103 } else
104 (void) sprintf(buf, "rsh %s %s %s '%s:%s' </dev/null",
105 argv[i], cmd,
106 src, argv[argc - 1], targ);
107 (void) susystem(buf);
108 } else {
109 if (rem == -1) {
110 (void) sprintf(buf, "%s -t %s",
111 cmd, targ);
112 host = argv[argc - 1];
113 rem = rcmd(&host, IPPORT_CMDSERVER,
114 pwd->pw_name, tuser,
115 buf, 0);
116 if (rem < 0)
117 exit(1);
118 if (response() < 0)
119 exit(1);
120 }
121 source(1, argv+i);
122 }
123 }
124 } else {
125 if (targetshouldbedirectory)
126 verifydir(argv[argc - 1]);
127 for (i = 0; i < argc - 1; i++) {
128 src = colon(argv[i]);
129 if (src == 0) {
130 (void) sprintf(buf, "/bin/cp%s %s %s",
131 iamrecursive ? " -r" : "",
132 argv[i], argv[argc - 1]);
133 (void) susystem(buf);
134 } else {
135 *src++ = 0;
136 suser = rindex(argv[i], '.');
137 if (suser) {
138 *suser++ = 0;
139 if (!okname(suser))
140 continue;
141 } else
142 suser = pwd->pw_name;
143 (void) sprintf(buf, "%s -f %s", cmd, src);
144 host = argv[i];
145 rem = rcmd(&host, IPPORT_CMDSERVER,
146 pwd->pw_name, suser,
147 buf, 0);
148 if (rem < 0)
149 exit(1);
150 sink(1, argv+argc-1);
151 (void) close(rem);
152 rem = -1;
153 }
154 }
155 }
156 exit(errs);
157}
158
159verifydir(cp)
160 char *cp;
161{
162 struct stat stb;
163
164 if (stat(cp, &stb) < 0)
165 goto bad;
166 if ((stb.st_mode & S_IFMT) == S_IFDIR)
167 return;
168 errno = ENOTDIR;
169bad:
170 error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
171 exit(1);
172}
173
174char *
175colon(cp)
176 char *cp;
177{
178
179 while (*cp) {
180 if (*cp == ':')
181 return (cp);
182 if (*cp == '/')
183 return (0);
184 cp++;
185 }
186 return (0);
187}
188
189okname(cp0)
190 char *cp0;
191{
192 register char *cp = cp0;
193 register int c;
194
195 do {
196 c = *cp;
197 if (c & 0200)
198 goto bad;
199 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
200 goto bad;
201 cp++;
202 } while (*cp);
203 return (1);
204bad:
205 fprintf(stderr, "rcp: invalid user name %s\n", cp0);
206 return (0);
207}
208
209susystem(buf)
210 char *buf;
211{
212
213 if (fork() == 0) {
214 (void) setuid(getuid());
215 (void) system(buf);
216 _exit(0);
217 } else
218 (void) wait((int *)0);
219}
220
221source(argc, argv)
222 int argc;
223 char **argv;
224{
225 char *last, *name;
226 struct stat stb;
227 char buf[BUFSIZ];
5f10dd79
KM
228 int x, sizerr, f;
229 off_t i;
b7ff3bb3
BJ
230
231 for (x = 0; x < argc; x++) {
232 name = argv[x];
233 if (access(name, 4) < 0 || (f = open(name, 0)) < 0) {
234 error("rcp: %s: %s\n", name, sys_errlist[errno]);
235 continue;
236 }
237 if (fstat(f, &stb) < 0)
238 goto notreg;
239 switch (stb.st_mode&S_IFMT) {
240
241 case S_IFREG:
242 break;
243
244 case S_IFDIR:
245 if (iamrecursive) {
246 (void) close(f);
247 rsource(name, (int)stb.st_mode);
248 continue;
249 }
250 /* fall into ... */
251 default:
252notreg:
253 (void) close(f);
254 error("rcp: %s: not a plain file\n", name);
255 continue;
256 }
257 last = rindex(name, '/');
258 if (last == 0)
259 last = name;
260 else
261 last++;
5f10dd79 262 (void) sprintf(buf, "C%04o %D %s\n",
b7ff3bb3
BJ
263 stb.st_mode&07777, stb.st_size, last);
264 (void) write(rem, buf, strlen(buf));
265 if (response() < 0) {
266 (void) close(f);
267 continue;
268 }
269 sizerr = 0;
270 for (i = 0; i < stb.st_size; i += BUFSIZ) {
271 int amt = BUFSIZ;
272 if (i + amt > stb.st_size)
273 amt = stb.st_size - i;
274 if (sizerr == 0 && read(f, buf, amt) != amt)
275 sizerr = 1;
276 (void) write(rem, buf, amt);
277 }
278 (void) close(f);
279 if (sizerr == 0)
280 ga();
281 else
282 error("rcp: %s: file changed size\n", name);
283 (void) response();
284 }
285}
286
ed0072ae 287#include <dir.h>
b7ff3bb3
BJ
288
289rsource(name, mode)
290 char *name;
291 int mode;
292{
293 DIR *d = opendir(name);
294 char *last;
295 struct direct *dp;
296 char buf[BUFSIZ];
297 char *bufv[1];
298
299 if (d == 0) {
300 error("%s: %s\n", name, sys_errlist[errno]);
301 return;
302 }
303 last = rindex(name, '/');
304 if (last == 0)
305 last = name;
306 else
307 last++;
308 (void) sprintf(buf, "D%04o %d %s\n", mode&07777, 0, last);
309 (void) write(rem, buf, strlen(buf));
310 if (response() < 0) {
311 closedir(d);
312 return;
313 }
314 while (dp = readdir(d)) {
315 if (dp->d_ino == 0)
316 continue;
317 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
318 continue;
319 if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
320 error("%s/%s: Name too long.\n", name, dp->d_name);
321 continue;
322 }
323 (void) sprintf(buf, "%s/%s", name, dp->d_name);
324 bufv[0] = buf;
325 source(1, bufv);
326 }
327 closedir(d);
328 (void) write(rem, "E\n", 2);
329 (void) response();
330}
331
332response()
333{
334 char resp, c, rbuf[BUFSIZ], *cp = rbuf;
335
336 if (read(rem, &resp, 1) != 1)
337 lostconn();
338 switch (resp) {
339
340 case 0:
341 return (0);
342
343 default:
344 *cp++ = resp;
345 /* fall into... */
346 case 1:
347 case 2:
348 do {
349 if (read(rem, &c, 1) != 1)
350 lostconn();
351 *cp++ = c;
352 } while (cp < &rbuf[BUFSIZ] && c != '\n');
353 if (iamremote == 0)
354 (void) write(2, rbuf, cp - rbuf);
355 errs++;
356 if (resp == 1)
357 return (-1);
358 exit(1);
359 }
360 /*NOTREACHED*/
361}
362
363lostconn()
364{
365
366 if (iamremote == 0)
367 fprintf(stderr, "rcp: lost connection\n");
368 exit(1);
369}
370
371sink(argc, argv)
372 int argc;
373 char **argv;
374{
375 char *targ;
376 char cmdbuf[BUFSIZ], nambuf[BUFSIZ], buf[BUFSIZ], *cp;
5f10dd79
KM
377 int of, mode, wrerr, exists;
378 off_t i, size;
b7ff3bb3
BJ
379 char *whopp;
380 struct stat stb; int targisdir = 0;
381#define SCREWUP(str) { whopp = str; goto screwup; }
382 int mask = umask(0);
383 char *myargv[1];
384
385 umask(mask);
386 if (argc > 1) {
387 error("rcp: ambiguous target\n");
388 exit(1);
389 }
390 targ = *argv;
391 if (targetshouldbedirectory)
392 verifydir(targ);
393 ga();
394 if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
395 targisdir = 1;
396 for (;;) {
397 cp = cmdbuf;
398 if (read(rem, cp, 1) <= 0)
399 return;
400 if (*cp++ == '\n')
401 SCREWUP("unexpected '\\n'");
402 do {
403 if (read(rem, cp, 1) != 1)
404 SCREWUP("lost connection");
405 } while (*cp++ != '\n');
406 *cp = 0;
407 if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
408 if (iamremote == 0)
409 (void) write(2, cmdbuf, strlen(cmdbuf));
410 if (cmdbuf[0] == '\02')
411 exit(1);
412 errs++;
413 continue;
414 }
415 *--cp = 0;
416 cp = cmdbuf;
417 if (*cp == 'E') {
418 ga();
419 return;
420 }
421 if (*cp != 'C' && *cp != 'D')
422 SCREWUP("expected control record");
423 cp++;
424 mode = 0;
425 for (; cp < cmdbuf+5; cp++) {
426 if (*cp < '0' || *cp > '7')
427 SCREWUP("bad mode");
428 mode = (mode << 3) | (*cp - '0');
429 }
430 if (*cp++ != ' ')
431 SCREWUP("mode not delimited");
432 size = 0;
433 while (*cp >= '0' && *cp <= '9')
434 size = size * 10 + (*cp++ - '0');
435 if (*cp++ != ' ')
436 SCREWUP("size not delimited");
437 if (targisdir)
438 (void) sprintf(nambuf, "%s%s%s", targ,
439 *targ ? "/" : "", cp);
440 else
441 (void) strcpy(nambuf, targ);
442 exists = stat(nambuf, &stb) == 0;
443 if (exists && access(nambuf, 2) < 0)
444 goto bad2;
445 { char *slash = rindex(nambuf, '/'), *dir;
446 if (slash == 0) {
447 slash = "/";
448 dir = ".";
449 } else {
450 *slash = 0;
451 dir = nambuf;
452 }
453 if (exists == 0 && access(dir, 2) < 0)
454 goto bad;
455 *slash = '/';
456 if (cmdbuf[0] == 'D') {
457 if (stat(nambuf, &stb) == 0) {
458 if ((stb.st_mode&S_IFMT) != S_IFDIR) {
459 errno = ENOTDIR;
460 goto bad;
461 }
462 } else if (mkdir(nambuf, mode) < 0)
463 goto bad;
464 myargv[0] = nambuf;
465 sink(1, myargv);
466 continue;
467 }
468 if ((of = creat(nambuf, mode)) < 0) {
469 bad:
470 *slash = '/';
471 bad2:
472 error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
473 continue;
474 }
475 }
476 if (exists == 0) {
477 (void) stat(nambuf, &stb);
478 (void) chown(nambuf, pwd->pw_uid, stb.st_gid);
479 (void) chmod(nambuf, mode &~ mask);
480 }
481 ga();
482 wrerr = 0;
483 for (i = 0; i < size; i += BUFSIZ) {
484 int amt = BUFSIZ;
485 char *cp = buf;
486
487 if (i + amt > size)
488 amt = size - i;
489 do {
490 int j = read(rem, cp, amt);
491
492 if (j <= 0)
493 exit(1);
494 amt -= j;
495 cp += j;
496 } while (amt > 0);
497 amt = BUFSIZ;
498 if (i + amt > size)
499 amt = size - i;
500 if (wrerr == 0 && write(of, buf, amt) != amt)
501 wrerr++;
502 }
503 (void) close(of);
504 (void) response();
505 if (wrerr)
506 error("rcp: %s: %s\n", cp, sys_errlist[errno]);
507 else
508 ga();
509 }
510screwup:
511 error("rcp: protocol screwup: %s\n", whopp);
512 exit(1);
513}
514
515/*VARARGS*/
516error(fmt, a1, a2, a3, a4, a5)
517 char *fmt;
518 int a1, a2, a3, a4, a5;
519{
520 char buf[BUFSIZ], *cp = buf;
521
522 errs++;
523 *cp++ = 1;
524 (void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
525 (void) write(rem, buf, strlen(buf));
526 if (iamremote == 0)
527 (void) write(2, buf+1, strlen(buf+1));
528}
529
530mkdir(name, mode)
531 char *name;
532 int mode;
533{
534 char *argv[4];
535 int pid, rc;
536
537 argv[0] = "mkdir";
538 argv[1] = name;
539 argv[2] = 0;
540 pid = fork();
541 if (pid < 0) {
542 perror("cp");
543 return (1);
544 }
545 if (pid) {
546 while (wait(&rc) != pid)
547 continue;
548 if (rc == 0)
549 if (chmod(name, mode) < 0) {
550 perror(name);
551 rc = 1;
552 }
553 return (rc);
554 }
555 (void) setuid(getuid());
556 execv("/bin/mkdir", argv);
557 execv("/usr/bin/mkdir", argv);
558 perror("mkdir");
559 _exit(1);
560 /*NOTREACHED*/
561}
5f10dd79 562