pass lint. notice that definitions in llib-lc have changed for
[unix-history] / usr / src / bin / rcp / rcp.c
CommitLineData
b7ff3bb3 1#ifndef lint
ed0072ae 2static char sccsid[] = "@(#)rcp.c 4.3 82/05/09";
b7ff3bb3
BJ
3#endif
4
5#include <stdio.h>
6#include <signal.h>
ed0072ae 7#include <sys/param.h>
b7ff3bb3
BJ
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;
5f10dd79 98 (void) sprintf(buf, "rsh %s -L %s %s %s '%s:%s' </dev/null",
b7ff3bb3
BJ
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];
5f10dd79
KM
226 int x, sizerr, f;
227 off_t i;
b7ff3bb3
BJ
228
229 for (x = 0; x < argc; x++) {
230 name = argv[x];
231 if (access(name, 4) < 0 || (f = open(name, 0)) < 0) {
232 error("rcp: %s: %s\n", name, sys_errlist[errno]);
233 continue;
234 }
235 if (fstat(f, &stb) < 0)
236 goto notreg;
237 switch (stb.st_mode&S_IFMT) {
238
239 case S_IFREG:
240 break;
241
242 case S_IFDIR:
243 if (iamrecursive) {
244 (void) close(f);
245 rsource(name, (int)stb.st_mode);
246 continue;
247 }
248 /* fall into ... */
249 default:
250notreg:
251 (void) close(f);
252 error("rcp: %s: not a plain file\n", name);
253 continue;
254 }
255 last = rindex(name, '/');
256 if (last == 0)
257 last = name;
258 else
259 last++;
5f10dd79 260 (void) sprintf(buf, "C%04o %D %s\n",
b7ff3bb3
BJ
261 stb.st_mode&07777, stb.st_size, last);
262 (void) write(rem, buf, strlen(buf));
263 if (response() < 0) {
264 (void) close(f);
265 continue;
266 }
267 sizerr = 0;
268 for (i = 0; i < stb.st_size; i += BUFSIZ) {
269 int amt = BUFSIZ;
270 if (i + amt > stb.st_size)
271 amt = stb.st_size - i;
272 if (sizerr == 0 && read(f, buf, amt) != amt)
273 sizerr = 1;
274 (void) write(rem, buf, amt);
275 }
276 (void) close(f);
277 if (sizerr == 0)
278 ga();
279 else
280 error("rcp: %s: file changed size\n", name);
281 (void) response();
282 }
283}
284
ed0072ae 285#include <dir.h>
b7ff3bb3
BJ
286
287rsource(name, mode)
288 char *name;
289 int mode;
290{
291 DIR *d = opendir(name);
292 char *last;
293 struct direct *dp;
294 char buf[BUFSIZ];
295 char *bufv[1];
296
297 if (d == 0) {
298 error("%s: %s\n", name, sys_errlist[errno]);
299 return;
300 }
301 last = rindex(name, '/');
302 if (last == 0)
303 last = name;
304 else
305 last++;
306 (void) sprintf(buf, "D%04o %d %s\n", mode&07777, 0, last);
307 (void) write(rem, buf, strlen(buf));
308 if (response() < 0) {
309 closedir(d);
310 return;
311 }
312 while (dp = readdir(d)) {
313 if (dp->d_ino == 0)
314 continue;
315 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
316 continue;
317 if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
318 error("%s/%s: Name too long.\n", name, dp->d_name);
319 continue;
320 }
321 (void) sprintf(buf, "%s/%s", name, dp->d_name);
322 bufv[0] = buf;
323 source(1, bufv);
324 }
325 closedir(d);
326 (void) write(rem, "E\n", 2);
327 (void) response();
328}
329
330response()
331{
332 char resp, c, rbuf[BUFSIZ], *cp = rbuf;
333
334 if (read(rem, &resp, 1) != 1)
335 lostconn();
336 switch (resp) {
337
338 case 0:
339 return (0);
340
341 default:
342 *cp++ = resp;
343 /* fall into... */
344 case 1:
345 case 2:
346 do {
347 if (read(rem, &c, 1) != 1)
348 lostconn();
349 *cp++ = c;
350 } while (cp < &rbuf[BUFSIZ] && c != '\n');
351 if (iamremote == 0)
352 (void) write(2, rbuf, cp - rbuf);
353 errs++;
354 if (resp == 1)
355 return (-1);
356 exit(1);
357 }
358 /*NOTREACHED*/
359}
360
361lostconn()
362{
363
364 if (iamremote == 0)
365 fprintf(stderr, "rcp: lost connection\n");
366 exit(1);
367}
368
369sink(argc, argv)
370 int argc;
371 char **argv;
372{
373 char *targ;
374 char cmdbuf[BUFSIZ], nambuf[BUFSIZ], buf[BUFSIZ], *cp;
5f10dd79
KM
375 int of, mode, wrerr, exists;
376 off_t i, size;
b7ff3bb3
BJ
377 char *whopp;
378 struct stat stb; int targisdir = 0;
379#define SCREWUP(str) { whopp = str; goto screwup; }
380 int mask = umask(0);
381 char *myargv[1];
382
383 umask(mask);
384 if (argc > 1) {
385 error("rcp: ambiguous target\n");
386 exit(1);
387 }
388 targ = *argv;
389 if (targetshouldbedirectory)
390 verifydir(targ);
391 ga();
392 if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
393 targisdir = 1;
394 for (;;) {
395 cp = cmdbuf;
396 if (read(rem, cp, 1) <= 0)
397 return;
398 if (*cp++ == '\n')
399 SCREWUP("unexpected '\\n'");
400 do {
401 if (read(rem, cp, 1) != 1)
402 SCREWUP("lost connection");
403 } while (*cp++ != '\n');
404 *cp = 0;
405 if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
406 if (iamremote == 0)
407 (void) write(2, cmdbuf, strlen(cmdbuf));
408 if (cmdbuf[0] == '\02')
409 exit(1);
410 errs++;
411 continue;
412 }
413 *--cp = 0;
414 cp = cmdbuf;
415 if (*cp == 'E') {
416 ga();
417 return;
418 }
419 if (*cp != 'C' && *cp != 'D')
420 SCREWUP("expected control record");
421 cp++;
422 mode = 0;
423 for (; cp < cmdbuf+5; cp++) {
424 if (*cp < '0' || *cp > '7')
425 SCREWUP("bad mode");
426 mode = (mode << 3) | (*cp - '0');
427 }
428 if (*cp++ != ' ')
429 SCREWUP("mode not delimited");
430 size = 0;
431 while (*cp >= '0' && *cp <= '9')
432 size = size * 10 + (*cp++ - '0');
433 if (*cp++ != ' ')
434 SCREWUP("size not delimited");
435 if (targisdir)
436 (void) sprintf(nambuf, "%s%s%s", targ,
437 *targ ? "/" : "", cp);
438 else
439 (void) strcpy(nambuf, targ);
440 exists = stat(nambuf, &stb) == 0;
441 if (exists && access(nambuf, 2) < 0)
442 goto bad2;
443 { char *slash = rindex(nambuf, '/'), *dir;
444 if (slash == 0) {
445 slash = "/";
446 dir = ".";
447 } else {
448 *slash = 0;
449 dir = nambuf;
450 }
451 if (exists == 0 && access(dir, 2) < 0)
452 goto bad;
453 *slash = '/';
454 if (cmdbuf[0] == 'D') {
455 if (stat(nambuf, &stb) == 0) {
456 if ((stb.st_mode&S_IFMT) != S_IFDIR) {
457 errno = ENOTDIR;
458 goto bad;
459 }
460 } else if (mkdir(nambuf, mode) < 0)
461 goto bad;
462 myargv[0] = nambuf;
463 sink(1, myargv);
464 continue;
465 }
466 if ((of = creat(nambuf, mode)) < 0) {
467 bad:
468 *slash = '/';
469 bad2:
470 error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
471 continue;
472 }
473 }
474 if (exists == 0) {
475 (void) stat(nambuf, &stb);
476 (void) chown(nambuf, pwd->pw_uid, stb.st_gid);
477 (void) chmod(nambuf, mode &~ mask);
478 }
479 ga();
480 wrerr = 0;
481 for (i = 0; i < size; i += BUFSIZ) {
482 int amt = BUFSIZ;
483 char *cp = buf;
484
485 if (i + amt > size)
486 amt = size - i;
487 do {
488 int j = read(rem, cp, amt);
489
490 if (j <= 0)
491 exit(1);
492 amt -= j;
493 cp += j;
494 } while (amt > 0);
495 amt = BUFSIZ;
496 if (i + amt > size)
497 amt = size - i;
498 if (wrerr == 0 && write(of, buf, amt) != amt)
499 wrerr++;
500 }
501 (void) close(of);
502 (void) response();
503 if (wrerr)
504 error("rcp: %s: %s\n", cp, sys_errlist[errno]);
505 else
506 ga();
507 }
508screwup:
509 error("rcp: protocol screwup: %s\n", whopp);
510 exit(1);
511}
512
513/*VARARGS*/
514error(fmt, a1, a2, a3, a4, a5)
515 char *fmt;
516 int a1, a2, a3, a4, a5;
517{
518 char buf[BUFSIZ], *cp = buf;
519
520 errs++;
521 *cp++ = 1;
522 (void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
523 (void) write(rem, buf, strlen(buf));
524 if (iamremote == 0)
525 (void) write(2, buf+1, strlen(buf+1));
526}
527
528mkdir(name, mode)
529 char *name;
530 int mode;
531{
532 char *argv[4];
533 int pid, rc;
534
535 argv[0] = "mkdir";
536 argv[1] = name;
537 argv[2] = 0;
538 pid = fork();
539 if (pid < 0) {
540 perror("cp");
541 return (1);
542 }
543 if (pid) {
544 while (wait(&rc) != pid)
545 continue;
546 if (rc == 0)
547 if (chmod(name, mode) < 0) {
548 perror(name);
549 rc = 1;
550 }
551 return (rc);
552 }
553 (void) setuid(getuid());
554 execv("/bin/mkdir", argv);
555 execv("/usr/bin/mkdir", argv);
556 perror("mkdir");
557 _exit(1);
558 /*NOTREACHED*/
559}
5f10dd79 560