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