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