pwd.h needs types.h
[unix-history] / usr / src / usr.bin / rdist / server.c
CommitLineData
7172eb74
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
0718fb71
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
b36fc510
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
7172eb74
DF
16 */
17
2f8aab68 18#ifndef lint
b36fc510 19static char sccsid[] = "@(#)server.c 5.8 (Berkeley) %G%";
0718fb71 20#endif /* not lint */
2f8aab68
RC
21
22#include "defs.h"
23
d6bccb44
RC
24#define ack() (void) write(rem, "\0\n", 2)
25#define err() (void) write(rem, "\1\n", 2)
2f8aab68 26
a3e6fd64 27struct linkbuf *ihead; /* list of files with more than one link */
82572cb6 28char buf[BUFSIZ]; /* general purpose buffer */
2f8aab68
RC
29char target[BUFSIZ]; /* target/source directory name */
30char *tp; /* pointer to end of target name */
ac288309 31char *Tdest; /* pointer to last T dest*/
2f8aab68 32int catname; /* cat name to target name */
3024eb6f 33char *stp[32]; /* stack of saved tp's for directories */
e8109cf8 34int oumask; /* old umask for creating files */
82572cb6
RC
35
36extern FILE *lfp; /* log file for mailing changes */
37
0fccdfef 38int cleanup();
a3e6fd64 39struct linkbuf *savelink();
0fccdfef 40
2f8aab68
RC
41/*
42 * Server routine to read requests and process them.
43 * Commands are:
44 * Tname - Transmit file if out of date
45 * Vname - Verify if file out of date or not
46 * Qname - Query if file exists. Return mtime & size if it does.
47 */
48server()
49{
50 char cmdbuf[BUFSIZ];
51 register char *cp;
2f8aab68 52
0fccdfef
RC
53 signal(SIGHUP, cleanup);
54 signal(SIGINT, cleanup);
55 signal(SIGQUIT, cleanup);
56 signal(SIGTERM, cleanup);
57 signal(SIGPIPE, cleanup);
58
59 rem = 0;
e8109cf8 60 oumask = umask(0);
6e6d779a
RC
61 (void) sprintf(buf, "V%d\n", VERSION);
62 (void) write(rem, buf, strlen(buf));
2f8aab68
RC
63
64 for (;;) {
65 cp = cmdbuf;
66 if (read(rem, cp, 1) <= 0)
67 return;
68 if (*cp++ == '\n') {
e8109cf8 69 error("server: expected control record\n");
2f8aab68
RC
70 continue;
71 }
72 do {
73 if (read(rem, cp, 1) != 1)
0fccdfef 74 cleanup();
82572cb6 75 } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]);
2f8aab68
RC
76 *--cp = '\0';
77 cp = cmdbuf;
78 switch (*cp++) {
2f8aab68 79 case 'T': /* init target file/directory name */
82572cb6
RC
80 catname = 1; /* target should be directory */
81 goto dotarget;
82
83 case 't': /* init target file/directory name */
2f8aab68 84 catname = 0;
82572cb6 85 dotarget:
e8109cf8
RC
86 if (exptilde(target, cp) == NULL)
87 continue;
2f8aab68
RC
88 tp = target;
89 while (*tp)
90 tp++;
d6bccb44 91 ack();
2f8aab68
RC
92 continue;
93
a3e6fd64
RC
94 case 'R': /* Transfer a regular file. */
95 recvf(cp, S_IFREG);
2f8aab68
RC
96 continue;
97
a3e6fd64
RC
98 case 'D': /* Transfer a directory. */
99 recvf(cp, S_IFDIR);
100 continue;
101
102 case 'K': /* Transfer symbolic link. */
103 recvf(cp, S_IFLNK);
104 continue;
105
106 case 'k': /* Transfer hard link. */
107 hardlink(cp);
2f8aab68
RC
108 continue;
109
110 case 'E': /* End. (of directory) */
111 *tp = '\0';
e8109cf8
RC
112 if (catname <= 0) {
113 error("server: too many 'E's\n");
2f8aab68
RC
114 continue;
115 }
e8109cf8 116 tp = stp[--catname];
3024eb6f 117 *tp = '\0';
d6bccb44 118 ack();
2f8aab68
RC
119 continue;
120
d1dee8e8 121 case 'C': /* Clean. Cleanup a directory */
d6bccb44 122 clean(cp);
e8109cf8
RC
123 continue;
124
125 case 'Q': /* Query. Does the file/directory exist? */
126 query(cp);
127 continue;
128
d6bccb44
RC
129 case 'S': /* Special. Execute commands */
130 dospecial(cp);
131 continue;
132
e8109cf8
RC
133#ifdef notdef
134 /*
135 * These entries are reserved but not currently used.
136 * The intent is to allow remote hosts to have master copies.
137 * Currently, only the host rdist runs on can have masters.
138 */
139 case 'X': /* start a new list of files to exclude */
140 except = bp = NULL;
141 case 'x': /* add name to list of files to exclude */
142 if (*cp == '\0') {
d6bccb44 143 ack();
d1dee8e8
RC
144 continue;
145 }
e8109cf8
RC
146 if (*cp == '~') {
147 if (exptilde(buf, cp) == NULL)
148 continue;
149 cp = buf;
d1dee8e8 150 }
e8109cf8 151 if (bp == NULL)
d6bccb44 152 except = bp = expand(makeblock(NAME, cp), E_VARS);
e8109cf8 153 else
d6bccb44 154 bp->b_next = expand(makeblock(NAME, cp), E_VARS);
e8109cf8
RC
155 while (bp->b_next != NULL)
156 bp = bp->b_next;
d6bccb44 157 ack();
3024eb6f
RC
158 continue;
159
d6bccb44 160 case 'I': /* Install. Transfer file if out of date. */
e8109cf8
RC
161 opts = 0;
162 while (*cp >= '0' && *cp <= '7')
163 opts = (opts << 3) | (*cp++ - '0');
164 if (*cp++ != ' ') {
165 error("server: options not delimited\n");
166 return;
167 }
d6bccb44 168 install(cp, opts);
2f8aab68
RC
169 continue;
170
171 case 'L': /* Log. save message in log file */
3024eb6f 172 log(lfp, cp);
2f8aab68 173 continue;
e8109cf8 174#endif
2f8aab68 175
82572cb6 176 case '\1':
0fccdfef 177 nerrs++;
82572cb6
RC
178 continue;
179
180 case '\2':
181 return;
182
2f8aab68 183 default:
e8109cf8 184 error("server: unknown command '%s'\n", cp);
2f8aab68
RC
185 case '\0':
186 continue;
187 }
188 }
189}
190
191/*
e8109cf8
RC
192 * Update the file(s) if they are different.
193 * destdir = 1 if destination should be a directory
194 * (i.e., more than one source is being copied to the same destination).
2f8aab68 195 */
e8109cf8
RC
196install(src, dest, destdir, opts)
197 char *src, *dest;
198 int destdir, opts;
2f8aab68 199{
e8109cf8 200 char *rname;
ac288309 201 char destcopy[BUFSIZ];
2f8aab68 202
e8109cf8
RC
203 if (dest == NULL) {
204 opts &= ~WHOLE; /* WHOLE mode only useful if renaming */
205 dest = src;
206 }
2f8aab68 207
e8109cf8
RC
208 if (nflag || debug) {
209 printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install",
210 opts & WHOLE ? " -w" : "",
211 opts & YOUNGER ? " -y" : "",
212 opts & COMPARE ? " -b" : "",
d6bccb44 213 opts & REMOVE ? " -R" : "", src, dest);
e8109cf8
RC
214 if (nflag)
215 return;
216 }
217
218 rname = exptilde(target, src);
219 if (rname == NULL)
220 return;
221 tp = target;
222 while (*tp)
223 tp++;
82572cb6 224 /*
e8109cf8 225 * If we are renaming a directory and we want to preserve
d6bccb44 226 * the directory heirarchy (-w), we must strip off the leading
e8109cf8 227 * directory name and preserve the rest.
82572cb6 228 */
e8109cf8 229 if (opts & WHOLE) {
d6bccb44
RC
230 while (*rname == '/')
231 rname++;
232 destdir = 1;
e8109cf8
RC
233 } else {
234 rname = rindex(target, '/');
235 if (rname == NULL)
236 rname = target;
237 else
238 rname++;
82572cb6 239 }
e8109cf8
RC
240 if (debug)
241 printf("target = %s, rname = %s\n", target, rname);
242 /*
243 * Pass the destination file/directory name to remote.
244 */
245 (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest);
246 if (debug)
247 printf("buf = %s", buf);
248 (void) write(rem, buf, strlen(buf));
249 if (response() < 0)
250 return;
251
ac288309
KS
252 if (destdir) {
253 strcpy(destcopy, dest);
254 Tdest = destcopy;
255 }
e8109cf8 256 sendf(rname, opts);
ac288309 257 Tdest = 0;
e8109cf8
RC
258}
259
ac288309
KS
260#define protoname() (pw ? pw->pw_name : user)
261#define protogroup() (gr ? gr->gr_name : group)
e8109cf8
RC
262/*
263 * Transfer the file or directory in target[].
264 * rname is the name of the file on the remote host.
265 */
266sendf(rname, opts)
267 char *rname;
268 int opts;
269{
0fccdfef 270 register struct subcmd *sc;
e8109cf8 271 struct stat stb;
a3e6fd64 272 int sizerr, f, u, len;
e8109cf8 273 off_t i;
a3e6fd64
RC
274 DIR *d;
275 struct direct *dp;
276 char *otp, *cp;
4085f36f 277 extern struct subcmd *subcmds;
ac288309 278 static char user[15], group[15];
e8109cf8
RC
279
280 if (debug)
281 printf("sendf(%s, %x)\n", rname, opts);
282
4085f36f 283 if (except(target))
024fde5b 284 return;
80babee1 285 if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) {
e8109cf8 286 error("%s: %s\n", target, sys_errlist[errno]);
2f8aab68
RC
287 return;
288 }
a3e6fd64
RC
289 if ((u = update(rname, opts, &stb)) == 0) {
290 if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1)
291 (void) savelink(&stb);
2f8aab68 292 return;
a3e6fd64 293 }
2f8aab68 294
e8109cf8
RC
295 if (pw == NULL || pw->pw_uid != stb.st_uid)
296 if ((pw = getpwuid(stb.st_uid)) == NULL) {
a4571018
KS
297 log(lfp, "%s: no password entry for uid %d \n",
298 target, stb.st_uid);
ac288309
KS
299 pw = NULL;
300 sprintf(user, ":%d", stb.st_uid);
82572cb6 301 }
e8109cf8
RC
302 if (gr == NULL || gr->gr_gid != stb.st_gid)
303 if ((gr = getgrgid(stb.st_gid)) == NULL) {
a4571018
KS
304 log(lfp, "%s: no name for group %d\n",
305 target, stb.st_gid);
ac288309
KS
306 gr = NULL;
307 sprintf(group, ":%d", stb.st_gid);
82572cb6 308 }
024fde5b 309 if (u == 1) {
d6bccb44
RC
310 if (opts & VERIFY) {
311 log(lfp, "need to install: %s\n", target);
312 goto dospecial;
313 }
e8109cf8 314 log(lfp, "installing: %s\n", target);
d6bccb44 315 opts &= ~(COMPARE|REMOVE);
024fde5b 316 }
2f8aab68
RC
317
318 switch (stb.st_mode & S_IFMT) {
a3e6fd64
RC
319 case S_IFDIR:
320 if ((d = opendir(target)) == NULL) {
321 error("%s: %s\n", target, sys_errlist[errno]);
322 return;
323 }
324 (void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts,
ac288309 325 stb.st_mode & 07777, protoname(), protogroup(), rname);
a3e6fd64 326 if (debug)
85b60cd9 327 printf("buf = %s", buf);
a3e6fd64
RC
328 (void) write(rem, buf, strlen(buf));
329 if (response() < 0) {
330 closedir(d);
331 return;
332 }
2f8aab68 333
a3e6fd64
RC
334 if (opts & REMOVE)
335 rmchk(opts);
d6bccb44 336
a3e6fd64
RC
337 otp = tp;
338 len = tp - target;
339 while (dp = readdir(d)) {
340 if (!strcmp(dp->d_name, ".") ||
341 !strcmp(dp->d_name, ".."))
342 continue;
343 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
344 error("%s/%s: Name too long\n", target,
345 dp->d_name);
346 continue;
347 }
348 tp = otp;
349 *tp++ = '/';
350 cp = dp->d_name;
351 while (*tp++ = *cp++)
352 ;
353 tp--;
354 sendf(dp->d_name, opts);
355 }
356 closedir(d);
357 (void) write(rem, "E\n", 2);
358 (void) response();
359 tp = otp;
360 *tp = '\0';
2f8aab68
RC
361 return;
362
a3e6fd64
RC
363 case S_IFLNK:
364 if (u != 1)
365 opts |= COMPARE;
ac288309
KS
366 if (stb.st_nlink > 1) {
367 struct linkbuf *lp;
368
369 if ((lp = savelink(&stb)) != NULL) {
370 /* install link */
371 if (*lp->target == 0)
372 (void) sprintf(buf, "k%o %s %s\n", opts,
373 lp->pathname, rname);
374 else
375 (void) sprintf(buf, "k%o %s/%s %s\n", opts,
376 lp->target, lp->pathname, rname);
377 if (debug)
378 printf("buf = %s", buf);
379 (void) write(rem, buf, strlen(buf));
380 (void) response();
381 return;
382 }
383 }
80babee1 384 (void) sprintf(buf, "K%o %o %ld %ld %s %s %s\n", opts,
a3e6fd64 385 stb.st_mode & 07777, stb.st_size, stb.st_mtime,
ac288309 386 protoname(), protogroup(), rname);
a3e6fd64
RC
387 if (debug)
388 printf("buf = %s", buf);
389 (void) write(rem, buf, strlen(buf));
390 if (response() < 0)
391 return;
392 sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size);
393 (void) write(rem, buf, stb.st_size);
394 if (debug)
ba0e5a3a 395 printf("readlink = %.*s\n", (int)stb.st_size, buf);
a3e6fd64
RC
396 goto done;
397
398 case S_IFREG:
399 break;
400
2f8aab68 401 default:
a3e6fd64 402 error("%s: not a file or directory\n", target);
2f8aab68
RC
403 return;
404 }
405
024fde5b 406 if (u == 2) {
d6bccb44
RC
407 if (opts & VERIFY) {
408 log(lfp, "need to update: %s\n", target);
409 goto dospecial;
410 }
e8109cf8 411 log(lfp, "updating: %s\n", target);
024fde5b 412 }
a3e6fd64
RC
413
414 if (stb.st_nlink > 1) {
415 struct linkbuf *lp;
416
417 if ((lp = savelink(&stb)) != NULL) {
418 /* install link */
ac288309 419 if (*lp->target == 0)
a3e6fd64
RC
420 (void) sprintf(buf, "k%o %s %s\n", opts,
421 lp->pathname, rname);
ac288309
KS
422 else
423 (void) sprintf(buf, "k%o %s/%s %s\n", opts,
424 lp->target, lp->pathname, rname);
a3e6fd64
RC
425 if (debug)
426 printf("buf = %s", buf);
427 (void) write(rem, buf, strlen(buf));
428 (void) response();
429 return;
430 }
431 }
2f8aab68 432
e8109cf8
RC
433 if ((f = open(target, 0)) < 0) {
434 error("%s: %s\n", target, sys_errlist[errno]);
82572cb6
RC
435 return;
436 }
80babee1 437 (void) sprintf(buf, "R%o %o %ld %ld %s %s %s\n", opts,
f7770429 438 stb.st_mode & 07777, stb.st_size, stb.st_mtime,
ac288309 439 protoname(), protogroup(), rname);
2f8aab68
RC
440 if (debug)
441 printf("buf = %s", buf);
442 (void) write(rem, buf, strlen(buf));
443 if (response() < 0) {
444 (void) close(f);
445 return;
446 }
447 sizerr = 0;
448 for (i = 0; i < stb.st_size; i += BUFSIZ) {
449 int amt = BUFSIZ;
450 if (i + amt > stb.st_size)
451 amt = stb.st_size - i;
452 if (sizerr == 0 && read(f, buf, amt) != amt)
453 sizerr = 1;
454 (void) write(rem, buf, amt);
455 }
456 (void) close(f);
a3e6fd64 457done:
d6bccb44 458 if (sizerr) {
e8109cf8 459 error("%s: file changed size\n", target);
d6bccb44
RC
460 err();
461 } else
462 ack();
a3e6fd64
RC
463 f = response();
464 if (f < 0 || f == 0 && (opts & COMPARE))
d6bccb44
RC
465 return;
466dospecial:
4085f36f 467 for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
0fccdfef 468 if (sc->sc_type != SPECIAL)
d6bccb44 469 continue;
80babee1 470 if (sc->sc_args != NULL && !inlist(sc->sc_args, target))
d6bccb44 471 continue;
0fccdfef 472 log(lfp, "special \"%s\"\n", sc->sc_name);
d6bccb44
RC
473 if (opts & VERIFY)
474 continue;
80babee1 475 (void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name);
d6bccb44
RC
476 if (debug)
477 printf("buf = %s", buf);
478 (void) write(rem, buf, strlen(buf));
479 while (response() > 0)
480 ;
481 }
2f8aab68
RC
482}
483
a3e6fd64
RC
484struct linkbuf *
485savelink(stp)
486 struct stat *stp;
2f8aab68 487{
a3e6fd64
RC
488 struct linkbuf *lp;
489 int found = 0;
2f8aab68 490
a3e6fd64
RC
491 for (lp = ihead; lp != NULL; lp = lp->nextp)
492 if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) {
493 lp->count--;
494 return(lp);
2f8aab68 495 }
a3e6fd64
RC
496 lp = (struct linkbuf *) malloc(sizeof(*lp));
497 if (lp == NULL)
498 log(lfp, "out of memory, link information lost\n");
499 else {
500 lp->nextp = ihead;
501 ihead = lp;
502 lp->inum = stp->st_ino;
503 lp->devnum = stp->st_dev;
504 lp->count = stp->st_nlink - 1;
505 strcpy(lp->pathname, target);
ac288309
KS
506 if (Tdest)
507 strcpy(lp->target, Tdest);
508 else
509 *lp->target = 0;
2f8aab68 510 }
a3e6fd64 511 return(NULL);
2f8aab68
RC
512}
513
514/*
515 * Check to see if file needs to be updated on the remote machine.
e8109cf8
RC
516 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date
517 * and 3 if comparing binaries to determine if out of date.
2f8aab68 518 */
a3e6fd64 519update(rname, opts, stp)
e8109cf8 520 char *rname;
f7770429 521 int opts;
a3e6fd64 522 struct stat *stp;
2f8aab68 523{
e8109cf8 524 register char *cp, *s;
2f8aab68
RC
525 register off_t size;
526 register time_t mtime;
527
528 if (debug)
a3e6fd64 529 printf("update(%s, %x, %x)\n", rname, opts, stp);
2f8aab68
RC
530
531 /*
532 * Check to see if the file exists on the remote machine.
533 */
e8109cf8 534 (void) sprintf(buf, "Q%s\n", rname);
2f8aab68
RC
535 if (debug)
536 printf("buf = %s", buf);
537 (void) write(rem, buf, strlen(buf));
ac288309 538again:
e8109cf8 539 cp = s = buf;
2f8aab68
RC
540 do {
541 if (read(rem, cp, 1) != 1)
346dad94 542 lostconn();
82572cb6 543 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
2f8aab68 544
e8109cf8 545 switch (*s++) {
2f8aab68
RC
546 case 'Y':
547 break;
548
82572cb6 549 case 'N': /* file doesn't exist so install it */
2f8aab68
RC
550 return(1);
551
552 case '\1':
0fccdfef 553 nerrs++;
e8109cf8 554 if (*s != '\n') {
82572cb6
RC
555 if (!iamremote) {
556 fflush(stdout);
e8109cf8 557 (void) write(2, s, cp - s);
82572cb6
RC
558 }
559 if (lfp != NULL)
e8109cf8 560 (void) fwrite(s, 1, cp - s, lfp);
82572cb6 561 }
2f8aab68
RC
562 return(0);
563
ac288309
KS
564 case '\3':
565 *--cp = '\0';
566 if (lfp != NULL)
567 log(lfp, "update: note: %s\n", s);
568 goto again;
569
2f8aab68 570 default:
85b60cd9 571 *--cp = '\0';
ac288309 572 error("update: unexpected response '%s'\n", s);
2f8aab68
RC
573 return(0);
574 }
575
e8109cf8 576 if (*s == '\n')
3024eb6f 577 return(2);
2f8aab68 578
024fde5b
RC
579 if (opts & COMPARE)
580 return(3);
581
2f8aab68 582 size = 0;
e8109cf8
RC
583 while (isdigit(*s))
584 size = size * 10 + (*s++ - '0');
585 if (*s++ != ' ') {
586 error("update: size not delimited\n");
2f8aab68
RC
587 return(0);
588 }
589 mtime = 0;
e8109cf8
RC
590 while (isdigit(*s))
591 mtime = mtime * 10 + (*s++ - '0');
592 if (*s != '\n') {
593 error("update: mtime not delimited\n");
2f8aab68
RC
594 return(0);
595 }
596 /*
597 * File needs to be updated?
598 */
f7770429 599 if (opts & YOUNGER) {
a3e6fd64 600 if (stp->st_mtime == mtime)
3024eb6f 601 return(0);
a3e6fd64 602 if (stp->st_mtime < mtime) {
e8109cf8 603 log(lfp, "Warning: %s: remote copy is newer\n", target);
3024eb6f
RC
604 return(0);
605 }
a3e6fd64 606 } else if (stp->st_mtime == mtime && stp->st_size == size)
2f8aab68 607 return(0);
82572cb6 608 return(2);
2f8aab68
RC
609}
610
611/*
612 * Query. Check to see if file exists. Return one of the following:
613 * N\n - doesn't exist
614 * Ysize mtime\n - exists and its a regular file (size & mtime of file)
a3e6fd64 615 * Y\n - exists and its a directory or symbolic link
2f8aab68
RC
616 * ^Aerror message\n
617 */
e8109cf8 618query(name)
2f8aab68
RC
619 char *name;
620{
621 struct stat stb;
622
623 if (catname)
624 (void) sprintf(tp, "/%s", name);
3024eb6f 625
a3e6fd64 626 if (lstat(target, &stb) < 0) {
80babee1
RC
627 if (errno == ENOENT)
628 (void) write(rem, "N\n", 2);
629 else
630 error("%s:%s: %s\n", host, target, sys_errlist[errno]);
2f8aab68
RC
631 *tp = '\0';
632 return;
633 }
634
635 switch (stb.st_mode & S_IFMT) {
636 case S_IFREG:
80babee1 637 (void) sprintf(buf, "Y%ld %ld\n", stb.st_size, stb.st_mtime);
2f8aab68
RC
638 (void) write(rem, buf, strlen(buf));
639 break;
640
a3e6fd64 641 case S_IFLNK:
2f8aab68
RC
642 case S_IFDIR:
643 (void) write(rem, "Y\n", 2);
644 break;
645
646 default:
a3e6fd64 647 error("%s: not a file or directory\n", name);
2f8aab68
RC
648 break;
649 }
650 *tp = '\0';
651}
652
a3e6fd64 653recvf(cmd, type)
2f8aab68 654 char *cmd;
a3e6fd64 655 int type;
2f8aab68
RC
656{
657 register char *cp;
6e570eb0 658 int f, mode, opts, wrerr, olderrno;
2f8aab68
RC
659 off_t i, size;
660 time_t mtime;
661 struct stat stb;
662 struct timeval tvp[2];
80babee1 663 char *owner, *group;
2f8aab68 664 char new[BUFSIZ];
82572cb6 665 extern char *tmpname;
2f8aab68 666
f7770429 667 cp = cmd;
024fde5b
RC
668 opts = 0;
669 while (*cp >= '0' && *cp <= '7')
670 opts = (opts << 3) | (*cp++ - '0');
f7770429 671 if (*cp++ != ' ') {
e8109cf8 672 error("recvf: options not delimited\n");
f7770429
RC
673 return;
674 }
2f8aab68 675 mode = 0;
024fde5b 676 while (*cp >= '0' && *cp <= '7')
f7770429 677 mode = (mode << 3) | (*cp++ - '0');
2f8aab68 678 if (*cp++ != ' ') {
e8109cf8 679 error("recvf: mode not delimited\n");
2f8aab68
RC
680 return;
681 }
682 size = 0;
683 while (isdigit(*cp))
684 size = size * 10 + (*cp++ - '0');
685 if (*cp++ != ' ') {
e8109cf8 686 error("recvf: size not delimited\n");
2f8aab68
RC
687 return;
688 }
689 mtime = 0;
690 while (isdigit(*cp))
691 mtime = mtime * 10 + (*cp++ - '0');
692 if (*cp++ != ' ') {
e8109cf8 693 error("recvf: mtime not delimited\n");
2f8aab68
RC
694 return;
695 }
696 owner = cp;
697 while (*cp && *cp != ' ')
698 cp++;
699 if (*cp != ' ') {
e8109cf8 700 error("recvf: owner name not delimited\n");
2f8aab68
RC
701 return;
702 }
703 *cp++ = '\0';
704 group = cp;
705 while (*cp && *cp != ' ')
706 cp++;
707 if (*cp != ' ') {
e8109cf8 708 error("recvf: group name not delimited\n");
2f8aab68
RC
709 return;
710 }
711 *cp++ = '\0';
712
a3e6fd64 713 if (type == S_IFDIR) {
3024eb6f 714 if (catname >= sizeof(stp)) {
a3e6fd64
RC
715 error("%s:%s: too many directory levels\n",
716 host, target);
3024eb6f
RC
717 return;
718 }
719 stp[catname] = tp;
2f8aab68
RC
720 if (catname++) {
721 *tp++ = '/';
722 while (*tp++ = *cp++)
723 ;
724 tp--;
725 }
f7770429 726 if (opts & VERIFY) {
d6bccb44 727 ack();
82572cb6
RC
728 return;
729 }
a3e6fd64 730 if (lstat(target, &stb) == 0) {
d6bccb44 731 if (ISDIR(stb.st_mode)) {
80babee1 732 if ((stb.st_mode & 07777) == mode) {
48568d94
RC
733 ack();
734 return;
735 }
736 buf[0] = '\0';
737 (void) sprintf(buf + 1,
89b53363
JL
738 "%s: Warning: remote mode %o != local mode %o\n",
739 target, stb.st_mode & 07777, mode);
48568d94 740 (void) write(rem, buf, strlen(buf + 1) + 1);
82572cb6 741 return;
d6bccb44 742 }
80babee1
RC
743 errno = ENOTDIR;
744 } else if (errno == ENOENT && (mkdir(target, mode) == 0 ||
745 chkparent(target) == 0 && mkdir(target, mode) == 0)) {
746 if (chog(target, owner, group, mode) == 0)
747 ack();
d6bccb44 748 return;
2f8aab68 749 }
80babee1 750 error("%s:%s: %s\n", host, target, sys_errlist[errno]);
d6bccb44
RC
751 tp = stp[--catname];
752 *tp = '\0';
2f8aab68
RC
753 return;
754 }
755
756 if (catname)
757 (void) sprintf(tp, "/%s", cp);
2f8aab68
RC
758 cp = rindex(target, '/');
759 if (cp == NULL)
80babee1
RC
760 strcpy(new, tmpname);
761 else if (cp == target)
762 (void) sprintf(new, "/%s", tmpname);
763 else {
2f8aab68 764 *cp = '\0';
80babee1 765 (void) sprintf(new, "%s/%s", target, tmpname);
2f8aab68 766 *cp = '/';
80babee1 767 }
a3e6fd64
RC
768
769 if (type == S_IFLNK) {
770 int j;
771
772 ack();
773 cp = buf;
774 for (i = 0; i < size; i += j) {
775 if ((j = read(rem, cp, size - i)) <= 0)
776 cleanup();
777 cp += j;
778 }
779 *cp = '\0';
80babee1
RC
780 if (response() < 0) {
781 err();
782 return;
783 }
d7c49b27
RC
784 if (symlink(buf, new) < 0) {
785 if (errno != ENOENT || chkparent(new) < 0 ||
786 symlink(buf, new) < 0)
787 goto badn;
788 }
a3e6fd64
RC
789 mode &= 0777;
790 if (opts & COMPARE) {
791 char tbuf[BUFSIZ];
792
d7c49b27
RC
793 if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 &&
794 i == size && strncmp(buf, tbuf, size) == 0) {
a3e6fd64
RC
795 (void) unlink(new);
796 ack();
797 return;
798 }
85b60cd9
RC
799 if (opts & VERIFY)
800 goto differ;
a3e6fd64
RC
801 }
802 goto fixup;
803 }
804
80babee1
RC
805 if ((f = creat(new, mode)) < 0) {
806 if (errno != ENOENT || chkparent(new) < 0 ||
807 (f = creat(new, mode)) < 0)
d7c49b27 808 goto badn;
80babee1
RC
809 }
810
d6bccb44 811 ack();
2f8aab68
RC
812 wrerr = 0;
813 for (i = 0; i < size; i += BUFSIZ) {
814 int amt = BUFSIZ;
2f8aab68 815
3024eb6f 816 cp = buf;
2f8aab68
RC
817 if (i + amt > size)
818 amt = size - i;
819 do {
820 int j = read(rem, cp, amt);
821
82572cb6
RC
822 if (j <= 0) {
823 (void) close(f);
824 (void) unlink(new);
2f8aab68 825 cleanup();
82572cb6 826 }
2f8aab68
RC
827 amt -= j;
828 cp += j;
829 } while (amt > 0);
830 amt = BUFSIZ;
831 if (i + amt > size)
832 amt = size - i;
833 if (wrerr == 0 && write(f, buf, amt) != amt) {
834 olderrno = errno;
835 wrerr++;
836 }
837 }
024fde5b 838 (void) close(f);
80babee1
RC
839 if (response() < 0) {
840 err();
841 (void) unlink(new);
842 return;
843 }
2f8aab68 844 if (wrerr) {
6da2b540 845 error("%s:%s: %s\n", host, new, sys_errlist[olderrno]);
82572cb6 846 (void) unlink(new);
2f8aab68
RC
847 return;
848 }
024fde5b
RC
849 if (opts & COMPARE) {
850 FILE *f1, *f2;
851 int c;
852
853 if ((f1 = fopen(target, "r")) == NULL)
80babee1 854 goto badt;
ac288309
KS
855 if ((f2 = fopen(new, "r")) == NULL) {
856 badn:
857 error("%s:%s: %s\n", host, new, sys_errlist[errno]);
858 (void) unlink(new);
859 return;
860 }
024fde5b
RC
861 while ((c = getc(f1)) == getc(f2))
862 if (c == EOF) {
863 (void) fclose(f1);
864 (void) fclose(f2);
865 (void) unlink(new);
d6bccb44 866 ack();
024fde5b
RC
867 return;
868 }
869 (void) fclose(f1);
870 (void) fclose(f2);
871 if (opts & VERIFY) {
a3e6fd64 872 differ:
024fde5b
RC
873 (void) unlink(new);
874 buf[0] = '\0';
80babee1 875 (void) sprintf(buf + 1, "need to update: %s\n",target);
024fde5b
RC
876 (void) write(rem, buf, strlen(buf + 1) + 1);
877 return;
878 }
879 }
2f8aab68
RC
880
881 /*
882 * Set last modified time
883 */
a3e6fd64 884 tvp[0].tv_sec = stb.st_atime; /* old atime from target */
2f8aab68
RC
885 tvp[0].tv_usec = 0;
886 tvp[1].tv_sec = mtime;
887 tvp[1].tv_usec = 0;
3f32107d 888 if (utimes(new, tvp) < 0) {
ac288309 889 note("%s:utimes failed %s: %s\n", host, new, sys_errlist[errno]);
3f32107d
RC
890 }
891 if (chog(new, owner, group, mode) < 0) {
892 (void) unlink(new);
2f8aab68
RC
893 return;
894 }
d7c49b27 895fixup:
2f8aab68 896 if (rename(new, target) < 0) {
80babee1 897badt:
a3e6fd64 898 error("%s:%s: %s\n", host, target, sys_errlist[errno]);
80babee1 899 (void) unlink(new);
2f8aab68
RC
900 return;
901 }
024fde5b
RC
902 if (opts & COMPARE) {
903 buf[0] = '\0';
89b53363 904 (void) sprintf(buf + 1, "updated %s\n", target);
024fde5b
RC
905 (void) write(rem, buf, strlen(buf + 1) + 1);
906 } else
d6bccb44 907 ack();
2f8aab68
RC
908}
909
a3e6fd64
RC
910/*
911 * Creat a hard link to existing file.
912 */
913hardlink(cmd)
914 char *cmd;
915{
916 register char *cp;
917 struct stat stb;
918 char *oldname;
919 int opts, exists = 0;
920
921 cp = cmd;
922 opts = 0;
923 while (*cp >= '0' && *cp <= '7')
924 opts = (opts << 3) | (*cp++ - '0');
925 if (*cp++ != ' ') {
926 error("hardlink: options not delimited\n");
927 return;
928 }
929 oldname = cp;
930 while (*cp && *cp != ' ')
931 cp++;
932 if (*cp != ' ') {
933 error("hardlink: oldname name not delimited\n");
934 return;
935 }
936 *cp++ = '\0';
937
ac288309 938 if (catname) {
a3e6fd64 939 (void) sprintf(tp, "/%s", cp);
ac288309 940 }
a3e6fd64 941 if (lstat(target, &stb) == 0) {
ac288309
KS
942 int mode = stb.st_mode & S_IFMT;
943 if (mode != S_IFREG && mode != S_IFLNK) {
a3e6fd64
RC
944 error("%s:%s: not a regular file\n", host, target);
945 return;
946 }
947 exists = 1;
948 }
ac288309
KS
949 if (chkparent(target) < 0 ) {
950 error("%s:%s: %s (no parent)\n",
951 host, target, sys_errlist[errno]);
952 return;
953 }
954 if (exists && (unlink(target) < 0)) {
955 error("%s:%s: %s (unlink)\n",
956 host, target, sys_errlist[errno]);
957 return;
958 }
959 if (link(oldname, target) < 0) {
960 error("%s:can't link %s to %s\n",
961 host, target, oldname);
a3e6fd64
RC
962 return;
963 }
964 ack();
965}
966
3024eb6f 967/*
80babee1 968 * Check to see if parent directory exists and create one if not.
3024eb6f
RC
969 */
970chkparent(name)
971 char *name;
972{
80babee1
RC
973 register char *cp;
974 struct stat stb;
3024eb6f
RC
975
976 cp = rindex(name, '/');
80babee1 977 if (cp == NULL || cp == name)
3024eb6f 978 return(0);
80babee1
RC
979 *cp = '\0';
980 if (lstat(name, &stb) < 0) {
981 if (errno == ENOENT && chkparent(name) >= 0 &&
982 mkdir(name, 0777 & ~oumask) >= 0) {
3024eb6f 983 *cp = '/';
80babee1
RC
984 return(0);
985 }
986 } else if (ISDIR(stb.st_mode)) {
987 *cp = '/';
3024eb6f
RC
988 return(0);
989 }
80babee1 990 *cp = '/';
3024eb6f
RC
991 return(-1);
992}
993
2f8aab68 994/*
d6bccb44 995 * Change owner, group and mode of file.
2f8aab68 996 */
82572cb6 997chog(file, owner, group, mode)
2f8aab68 998 char *file, *owner, *group;
82572cb6 999 int mode;
2f8aab68 1000{
2f8aab68
RC
1001 register int i;
1002 int uid, gid;
80babee1
RC
1003 extern char user[];
1004 extern int userid;
2f8aab68
RC
1005
1006 uid = userid;
1007 if (userid == 0) {
ac288309
KS
1008 if (*owner == ':') {
1009 uid = atoi(owner + 1);
1010 } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) {
e8109cf8 1011 if ((pw = getpwnam(owner)) == NULL) {
82572cb6 1012 if (mode & 04000) {
ac288309 1013 note("%s:%s: unknown login name, clearing setuid",
a3e6fd64 1014 host, owner);
ac288309
KS
1015 mode &= ~04000;
1016 uid = 0;
82572cb6
RC
1017 }
1018 } else
e8109cf8 1019 uid = pw->pw_uid;
82572cb6 1020 } else
e8109cf8 1021 uid = pw->pw_uid;
ac288309
KS
1022 if (*group == ':') {
1023 gid = atoi(group + 1);
1024 goto ok;
1025 }
d6bccb44
RC
1026 } else if ((mode & 04000) && strcmp(user, owner) != 0)
1027 mode &= ~04000;
80babee1 1028 gid = -1;
e8109cf8 1029 if (gr == NULL || strcmp(group, gr->gr_name) != 0) {
ac288309
KS
1030 if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL))
1031 || ((gr = getgrnam(group)) == NULL)) {
82572cb6 1032 if (mode & 02000) {
ac288309
KS
1033 note("%s:%s: unknown group", host, group);
1034 mode &= ~02000;
82572cb6
RC
1035 }
1036 } else
e8109cf8 1037 gid = gr->gr_gid;
82572cb6 1038 } else
e8109cf8 1039 gid = gr->gr_gid;
80babee1 1040 if (userid && gid >= 0) {
ac288309 1041 if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++)
e8109cf8 1042 if (!(strcmp(user, gr->gr_mem[i])))
2f8aab68 1043 goto ok;
d6bccb44 1044 mode &= ~02000;
80babee1 1045 gid = -1;
2f8aab68
RC
1046 }
1047ok:
80babee1
RC
1048 if (userid)
1049 setreuid(userid, 0);
1050 if (chown(file, uid, gid) < 0 ||
aad0f996 1051 (mode & 07000) && chmod(file, mode) < 0) {
ac288309
KS
1052 note("%s: chown or chmod failed: file %s: %s",
1053 host, file, sys_errlist[errno]);
d6bccb44 1054 }
80babee1
RC
1055 if (userid)
1056 setreuid(0, userid);
2f8aab68
RC
1057 return(0);
1058}
1059
d1dee8e8
RC
1060/*
1061 * Check for files on the machine being updated that are not on the master
1062 * machine and remove them.
1063 */
d6bccb44 1064rmchk(opts)
d1dee8e8
RC
1065 int opts;
1066{
e8109cf8 1067 register char *cp, *s;
d1dee8e8
RC
1068 struct stat stb;
1069
1070 if (debug)
d6bccb44 1071 printf("rmchk()\n");
024fde5b 1072
d1dee8e8
RC
1073 /*
1074 * Tell the remote to clean the files from the last directory sent.
1075 */
d6bccb44 1076 (void) sprintf(buf, "C%o\n", opts & VERIFY);
d1dee8e8
RC
1077 if (debug)
1078 printf("buf = %s", buf);
1079 (void) write(rem, buf, strlen(buf));
1080 if (response() < 0)
1081 return;
d1dee8e8 1082 for (;;) {
e8109cf8 1083 cp = s = buf;
d1dee8e8
RC
1084 do {
1085 if (read(rem, cp, 1) != 1)
346dad94 1086 lostconn();
d1dee8e8
RC
1087 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
1088
e8109cf8 1089 switch (*s++) {
d6bccb44 1090 case 'Q': /* Query if file should be removed */
024fde5b
RC
1091 /*
1092 * Return the following codes to remove query.
d6bccb44
RC
1093 * N\n -- file exists - DON'T remove.
1094 * Y\n -- file doesn't exist - REMOVE.
024fde5b 1095 */
d1dee8e8 1096 *--cp = '\0';
e8109cf8 1097 (void) sprintf(tp, "/%s", s);
d1dee8e8
RC
1098 if (debug)
1099 printf("check %s\n", target);
4085f36f 1100 if (except(target))
d1dee8e8 1101 (void) write(rem, "N\n", 2);
a3e6fd64 1102 else if (lstat(target, &stb) < 0)
d1dee8e8 1103 (void) write(rem, "Y\n", 2);
d6bccb44
RC
1104 else
1105 (void) write(rem, "N\n", 2);
d1dee8e8
RC
1106 break;
1107
1108 case '\0':
1109 *--cp = '\0';
e8109cf8
RC
1110 if (*s != '\0')
1111 log(lfp, "%s\n", s);
d1dee8e8
RC
1112 break;
1113
d6bccb44
RC
1114 case 'E':
1115 *tp = '\0';
1116 ack();
1117 return;
1118
d1dee8e8
RC
1119 case '\1':
1120 case '\2':
0fccdfef 1121 nerrs++;
e8109cf8 1122 if (*s != '\n') {
d1dee8e8
RC
1123 if (!iamremote) {
1124 fflush(stdout);
e8109cf8 1125 (void) write(2, s, cp - s);
d1dee8e8
RC
1126 }
1127 if (lfp != NULL)
e8109cf8 1128 (void) fwrite(s, 1, cp - s, lfp);
d1dee8e8
RC
1129 }
1130 if (buf[0] == '\2')
346dad94 1131 lostconn();
d1dee8e8
RC
1132 break;
1133
1134 default:
d6bccb44
RC
1135 error("rmchk: unexpected response '%s'\n", buf);
1136 err();
d1dee8e8
RC
1137 }
1138 }
1139}
1140
1141/*
d6bccb44 1142 * Check the current directory (initialized by the 'T' command to server())
024fde5b 1143 * for extraneous files and remove them.
d1dee8e8 1144 */
855cc4f4
RC
1145clean(cp)
1146 register char *cp;
d1dee8e8
RC
1147{
1148 DIR *d;
d6bccb44 1149 register struct direct *dp;
d1dee8e8 1150 struct stat stb;
d6bccb44
RC
1151 char *otp;
1152 int len, opts;
d1dee8e8 1153
d6bccb44
RC
1154 opts = 0;
1155 while (*cp >= '0' && *cp <= '7')
1156 opts = (opts << 3) | (*cp++ - '0');
1157 if (*cp != '\0') {
1158 error("clean: options not delimited\n");
1159 return;
d1dee8e8 1160 }
80babee1 1161 if ((d = opendir(target)) == NULL) {
a3e6fd64 1162 error("%s:%s: %s\n", host, target, sys_errlist[errno]);
e8109cf8
RC
1163 return;
1164 }
d6bccb44 1165 ack();
d1dee8e8
RC
1166
1167 otp = tp;
1168 len = tp - target;
1169 while (dp = readdir(d)) {
1170 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
1171 continue;
1172 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
a3e6fd64
RC
1173 error("%s:%s/%s: Name too long\n",
1174 host, target, dp->d_name);
d1dee8e8
RC
1175 continue;
1176 }
1177 tp = otp;
1178 *tp++ = '/';
1179 cp = dp->d_name;;
1180 while (*tp++ = *cp++)
1181 ;
1182 tp--;
a3e6fd64
RC
1183 if (lstat(target, &stb) < 0) {
1184 error("%s:%s: %s\n", host, target, sys_errlist[errno]);
d1dee8e8
RC
1185 continue;
1186 }
d6bccb44 1187 (void) sprintf(buf, "Q%s\n", dp->d_name);
d1dee8e8
RC
1188 (void) write(rem, buf, strlen(buf));
1189 cp = buf;
1190 do {
1191 if (read(rem, cp, 1) != 1)
0fccdfef 1192 cleanup();
d1dee8e8
RC
1193 } while (*cp++ != '\n' && cp < &buf[BUFSIZ]);
1194 *--cp = '\0';
1195 cp = buf;
d6bccb44 1196 if (*cp != 'Y')
d1dee8e8 1197 continue;
e8109cf8
RC
1198 if (opts & VERIFY) {
1199 cp = buf;
1200 *cp++ = '\0';
80babee1 1201 (void) sprintf(cp, "need to remove: %s\n", target);
e8109cf8
RC
1202 (void) write(rem, buf, strlen(cp) + 1);
1203 } else
d1dee8e8
RC
1204 remove(&stb);
1205 }
1206 closedir(d);
d1dee8e8
RC
1207 (void) write(rem, "E\n", 2);
1208 (void) response();
d6bccb44 1209 tp = otp;
e8109cf8 1210 *tp = '\0';
d1dee8e8
RC
1211}
1212
e8109cf8
RC
1213/*
1214 * Remove a file or directory (recursively) and send back an acknowledge
1215 * or an error message.
1216 */
a3e6fd64
RC
1217remove(stp)
1218 struct stat *stp;
d1dee8e8
RC
1219{
1220 DIR *d;
1221 struct direct *dp;
1222 register char *cp;
1223 struct stat stb;
1224 char *otp;
1225 int len;
1226
a3e6fd64 1227 switch (stp->st_mode & S_IFMT) {
d1dee8e8 1228 case S_IFREG:
a3e6fd64 1229 case S_IFLNK:
d1dee8e8
RC
1230 if (unlink(target) < 0)
1231 goto bad;
1232 goto removed;
1233
1234 case S_IFDIR:
1235 break;
1236
1237 default:
a3e6fd64 1238 error("%s:%s: not a plain file\n", host, target);
d1dee8e8
RC
1239 return;
1240 }
1241
80babee1 1242 if ((d = opendir(target)) == NULL)
d1dee8e8
RC
1243 goto bad;
1244
1245 otp = tp;
1246 len = tp - target;
1247 while (dp = readdir(d)) {
1248 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
1249 continue;
1250 if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
a3e6fd64
RC
1251 error("%s:%s/%s: Name too long\n",
1252 host, target, dp->d_name);
d1dee8e8
RC
1253 continue;
1254 }
1255 tp = otp;
1256 *tp++ = '/';
1257 cp = dp->d_name;;
1258 while (*tp++ = *cp++)
1259 ;
1260 tp--;
a3e6fd64
RC
1261 if (lstat(target, &stb) < 0) {
1262 error("%s:%s: %s\n", host, target, sys_errlist[errno]);
d1dee8e8
RC
1263 continue;
1264 }
1265 remove(&stb);
1266 }
1267 closedir(d);
1268 tp = otp;
1269 *tp = '\0';
1270 if (rmdir(target) < 0) {
1271bad:
a3e6fd64 1272 error("%s:%s: %s\n", host, target, sys_errlist[errno]);
d1dee8e8
RC
1273 return;
1274 }
1275removed:
1276 cp = buf;
1277 *cp++ = '\0';
1278 (void) sprintf(cp, "removed %s\n", target);
1279 (void) write(rem, buf, strlen(cp) + 1);
1280}
1281
d6bccb44
RC
1282/*
1283 * Execute a shell command to handle special cases.
1284 */
1285dospecial(cmd)
1286 char *cmd;
1287{
1288 int fd[2], status, pid, i;
1289 register char *cp, *s;
1290 char sbuf[BUFSIZ];
80babee1 1291 extern int userid, groupid;
d6bccb44
RC
1292
1293 if (pipe(fd) < 0) {
1294 error("%s\n", sys_errlist[errno]);
1295 return;
1296 }
1297 if ((pid = fork()) == 0) {
1298 /*
1299 * Return everything the shell commands print.
1300 */
1301 (void) close(0);
1302 (void) close(1);
1303 (void) close(2);
1304 (void) open("/dev/null", 0);
1305 (void) dup(fd[1]);
1306 (void) dup(fd[1]);
1307 (void) close(fd[0]);
1308 (void) close(fd[1]);
80babee1 1309 setgid(groupid);
b5644799 1310 setuid(userid);
d6bccb44
RC
1311 execl("/bin/sh", "sh", "-c", cmd, 0);
1312 _exit(127);
1313 }
1314 (void) close(fd[1]);
1315 s = sbuf;
1316 *s++ = '\0';
1317 while ((i = read(fd[0], buf, sizeof(buf))) > 0) {
1318 cp = buf;
1319 do {
1320 *s++ = *cp++;
1321 if (cp[-1] != '\n') {
1322 if (s < &sbuf[sizeof(sbuf)-1])
1323 continue;
1324 *s++ = '\n';
1325 }
1326 /*
1327 * Throw away blank lines.
1328 */
1329 if (s == &sbuf[2]) {
1330 s--;
1331 continue;
1332 }
1333 (void) write(rem, sbuf, s - sbuf);
1334 s = &sbuf[1];
1335 } while (--i);
1336 }
1337 if (s > &sbuf[1]) {
1338 *s++ = '\n';
1339 (void) write(rem, sbuf, s - sbuf);
1340 }
1341 while ((i = wait(&status)) != pid && i != -1)
1342 ;
1343 if (i == -1)
1344 status = -1;
80babee1 1345 (void) close(fd[0]);
d6bccb44
RC
1346 if (status)
1347 error("shell returned %d\n", status);
1348 else
1349 ack();
1350}
1351
3024eb6f 1352/*VARARGS2*/
82572cb6
RC
1353log(fp, fmt, a1, a2, a3)
1354 FILE *fp;
2f8aab68
RC
1355 char *fmt;
1356 int a1, a2, a3;
1357{
1358 /* Print changes locally if not quiet mode */
1359 if (!qflag)
1360 printf(fmt, a1, a2, a3);
1361
1362 /* Save changes (for mailing) if really updating files */
f7770429 1363 if (!(options & VERIFY) && fp != NULL)
82572cb6 1364 fprintf(fp, fmt, a1, a2, a3);
2f8aab68
RC
1365}
1366
3024eb6f 1367/*VARARGS1*/
2f8aab68
RC
1368error(fmt, a1, a2, a3)
1369 char *fmt;
1370 int a1, a2, a3;
1371{
0fccdfef 1372 nerrs++;
2f8aab68
RC
1373 strcpy(buf, "\1rdist: ");
1374 (void) sprintf(buf+8, fmt, a1, a2, a3);
3024eb6f
RC
1375 if (!iamremote) {
1376 fflush(stdout);
1377 (void) write(2, buf+1, strlen(buf+1));
d6bccb44
RC
1378 } else
1379 (void) write(rem, buf, strlen(buf));
3024eb6f
RC
1380 if (lfp != NULL)
1381 (void) fwrite(buf+1, 1, strlen(buf+1), lfp);
2f8aab68
RC
1382}
1383
3024eb6f 1384/*VARARGS1*/
2f8aab68
RC
1385fatal(fmt, a1, a2,a3)
1386 char *fmt;
1387 int a1, a2, a3;
1388{
0fccdfef 1389 nerrs++;
2f8aab68
RC
1390 strcpy(buf, "\2rdist: ");
1391 (void) sprintf(buf+8, fmt, a1, a2, a3);
3024eb6f
RC
1392 if (!iamremote) {
1393 fflush(stdout);
1394 (void) write(2, buf+1, strlen(buf+1));
d6bccb44
RC
1395 } else
1396 (void) write(rem, buf, strlen(buf));
3024eb6f
RC
1397 if (lfp != NULL)
1398 (void) fwrite(buf+1, 1, strlen(buf+1), lfp);
2f8aab68
RC
1399 cleanup();
1400}
1401
1402response()
1403{
024fde5b 1404 char *cp, *s;
85b60cd9 1405 char resp[BUFSIZ];
2f8aab68
RC
1406
1407 if (debug)
1408 printf("response()\n");
1409
85b60cd9 1410 cp = s = resp;
024fde5b
RC
1411 do {
1412 if (read(rem, cp, 1) != 1)
346dad94 1413 lostconn();
85b60cd9 1414 } while (*cp++ != '\n' && cp < &resp[BUFSIZ]);
2f8aab68 1415
024fde5b 1416 switch (*s++) {
2f8aab68 1417 case '\0':
024fde5b 1418 *--cp = '\0';
d6bccb44 1419 if (*s != '\0') {
024fde5b 1420 log(lfp, "%s\n", s);
d6bccb44
RC
1421 return(1);
1422 }
2f8aab68 1423 return(0);
ac288309
KS
1424 case '\3':
1425 *--cp = '\0';
1426 log(lfp, "Note: %s\n",s);
1427 return(response());
2f8aab68
RC
1428
1429 default:
024fde5b 1430 s--;
2f8aab68
RC
1431 /* fall into... */
1432 case '\1':
1433 case '\2':
0fccdfef 1434 nerrs++;
024fde5b 1435 if (*s != '\n') {
82572cb6
RC
1436 if (!iamremote) {
1437 fflush(stdout);
024fde5b 1438 (void) write(2, s, cp - s);
82572cb6 1439 }
2f8aab68 1440 if (lfp != NULL)
024fde5b 1441 (void) fwrite(s, 1, cp - s, lfp);
2f8aab68 1442 }
85b60cd9 1443 if (resp[0] == '\2')
346dad94 1444 lostconn();
e8109cf8 1445 return(-1);
2f8aab68 1446 }
2f8aab68
RC
1447}
1448
0fccdfef
RC
1449/*
1450 * Remove temporary files and do any cleanup operations before exiting.
1451 */
1452cleanup()
2f8aab68 1453{
0fccdfef
RC
1454 (void) unlink(tmpfile);
1455 exit(1);
2f8aab68 1456}
ac288309
KS
1457
1458note(fmt, a1, a2, a3)
1459{
1460 static char buf[BUFSIZ];
1461 sprintf(buf, fmt, a1, a2, a3);
1462 comment(buf);
1463}
1464
1465comment(s)
1466char *s;
1467{
1468 char c = '\3';
1469 write(rem, &c, 1);
1470 write(rem, s, strlen(s));
1471 c = '\n';
1472 write(rem, &c, 1);
1473}