Commit | Line | Data |
---|---|---|
2f8aab68 | 1 | #ifndef lint |
82572cb6 | 2 | static char *sccsid = "@(#)server.c 4.2 (Berkeley) 83/09/27"; |
2f8aab68 RC |
3 | #endif |
4 | ||
5 | #include "defs.h" | |
6 | ||
7 | #define ga() (void) write(rem, "", 1) | |
8 | ||
82572cb6 | 9 | char buf[BUFSIZ]; /* general purpose buffer */ |
2f8aab68 RC |
10 | char target[BUFSIZ]; /* target/source directory name */ |
11 | char *tp; /* pointer to end of target name */ | |
12 | int catname; /* cat name to target name */ | |
13 | ||
82572cb6 RC |
14 | static struct passwd *p = NULL; |
15 | static struct group *g = NULL; | |
16 | ||
17 | extern FILE *lfp; /* log file for mailing changes */ | |
18 | ||
2f8aab68 RC |
19 | /* |
20 | * Server routine to read requests and process them. | |
21 | * Commands are: | |
22 | * Tname - Transmit file if out of date | |
23 | * Vname - Verify if file out of date or not | |
24 | * Qname - Query if file exists. Return mtime & size if it does. | |
25 | */ | |
26 | server() | |
27 | { | |
28 | char cmdbuf[BUFSIZ]; | |
29 | register char *cp; | |
30 | register struct block *bp, *last = NULL; | |
31 | register int n; | |
32 | static struct block cmdblk = { EXCEPT }; | |
33 | ||
34 | (void) umask(0); | |
35 | ga(); | |
36 | ||
37 | for (;;) { | |
38 | cp = cmdbuf; | |
39 | if (read(rem, cp, 1) <= 0) | |
40 | return; | |
41 | if (*cp++ == '\n') { | |
42 | error("expected control record\n"); | |
43 | continue; | |
44 | } | |
45 | do { | |
46 | if (read(rem, cp, 1) != 1) | |
47 | lostconn(); | |
82572cb6 | 48 | } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]); |
2f8aab68 RC |
49 | *--cp = '\0'; |
50 | cp = cmdbuf; | |
51 | switch (*cp++) { | |
52 | case 'X': /* add name to list of files to exclude */ | |
53 | if (*cp == '\0') | |
54 | continue; | |
55 | bp = ALLOC(block); | |
56 | if (bp == NULL) | |
57 | fatal("ran out of memory\n"); | |
58 | bp->b_type = NAME; | |
59 | bp->b_next = bp->b_args = NULL; | |
60 | bp->b_name = cp = (char *) malloc(strlen(cp) + 1); | |
61 | if (cp == NULL) | |
62 | fatal("ran out of memory\n"); | |
63 | strcpy(cp, &cmdbuf[1]); | |
64 | if (last == NULL) { | |
65 | except = &cmdblk; | |
66 | cmdblk.b_args = last = bp; | |
67 | } else { | |
68 | last->b_next = bp; | |
69 | last = bp; | |
70 | } | |
71 | continue; | |
72 | ||
73 | case 'T': /* init target file/directory name */ | |
82572cb6 RC |
74 | catname = 1; /* target should be directory */ |
75 | goto dotarget; | |
76 | ||
77 | case 't': /* init target file/directory name */ | |
2f8aab68 | 78 | catname = 0; |
82572cb6 RC |
79 | dotarget: |
80 | exptilde(target, cp); | |
2f8aab68 RC |
81 | tp = target; |
82 | while (*tp) | |
83 | tp++; | |
84 | continue; | |
85 | ||
86 | case 'S': /* Send. Transfer file if out of date. */ | |
87 | tp = NULL; | |
88 | sendf(cp, 0); | |
89 | continue; | |
90 | ||
91 | case 'V': /* Verify. See if file is out of date. */ | |
92 | tp = NULL; | |
93 | sendf(cp, 1); | |
94 | continue; | |
95 | ||
96 | case 'R': /* Receive. Transfer file. */ | |
97 | recvf(cp, 0); | |
98 | continue; | |
99 | ||
100 | case 'D': /* Directory. Transfer file. */ | |
101 | recvf(cp, 1); | |
102 | continue; | |
103 | ||
104 | case 'E': /* End. (of directory) */ | |
105 | *tp = '\0'; | |
82572cb6 | 106 | if (--catname < 0) { |
2f8aab68 RC |
107 | error("too many 'E's\n"); |
108 | continue; | |
109 | } | |
82572cb6 RC |
110 | cp = rindex(target, '/'); |
111 | if (cp == NULL) | |
112 | tp = NULL; | |
113 | else { | |
114 | *cp = '\0'; | |
115 | tp = cp; | |
116 | } | |
2f8aab68 RC |
117 | ga(); |
118 | continue; | |
119 | ||
120 | case 'Q': /* Query. Does file exist? */ | |
121 | query(cp); | |
122 | continue; | |
123 | ||
124 | case 'L': /* Log. save message in log file */ | |
125 | query(cp); | |
126 | continue; | |
127 | ||
82572cb6 RC |
128 | case '\1': |
129 | errs++; | |
130 | continue; | |
131 | ||
132 | case '\2': | |
133 | return; | |
134 | ||
2f8aab68 RC |
135 | default: |
136 | error("unknown command type %s\n", cp); | |
137 | case '\0': | |
138 | continue; | |
139 | } | |
140 | } | |
141 | } | |
142 | ||
143 | /* | |
144 | * Transfer the file or directory 'name'. | |
145 | */ | |
146 | sendf(name, verify) | |
147 | char *name; | |
148 | int verify; | |
149 | { | |
150 | register char *last; | |
2f8aab68 | 151 | struct stat stb; |
82572cb6 | 152 | int sizerr, f, u; |
2f8aab68 RC |
153 | off_t i; |
154 | ||
155 | if (debug) | |
156 | printf("sendf(%s, %d)\n", name, verify); | |
157 | ||
158 | if (exclude(name)) | |
159 | return; | |
160 | ||
82572cb6 RC |
161 | /* |
162 | * first time sendf() is called? | |
163 | */ | |
164 | if (tp == NULL) { | |
165 | exptilde(target, name); | |
166 | tp = name = target; | |
167 | while (*tp) | |
168 | tp++; | |
169 | } | |
2f8aab68 RC |
170 | if (access(name, 4) < 0 || stat(name, &stb) < 0) { |
171 | error("%s: %s\n", name, sys_errlist[errno]); | |
172 | return; | |
173 | } | |
174 | last = rindex(name, '/'); | |
175 | if (last == NULL) | |
176 | last = name; | |
177 | else | |
178 | last++; | |
82572cb6 | 179 | if ((u = update(last, &stb)) == 0) |
2f8aab68 RC |
180 | return; |
181 | ||
82572cb6 RC |
182 | if (p == NULL || p->pw_uid != stb.st_uid) |
183 | if ((p = getpwuid(stb.st_uid)) == NULL) { | |
184 | error("no password entry for uid %d\n", stb.st_uid); | |
185 | return; | |
186 | } | |
187 | if (g == NULL || g->gr_gid != stb.st_gid) | |
188 | if ((g = getgrgid(stb.st_gid)) == NULL) { | |
189 | error("no name for group %d\n", stb.st_gid); | |
190 | return; | |
191 | } | |
2f8aab68 RC |
192 | |
193 | switch (stb.st_mode & S_IFMT) { | |
194 | case S_IFREG: | |
195 | break; | |
196 | ||
197 | case S_IFDIR: | |
198 | rsendf(name, verify, &stb, p->pw_name, g->gr_name); | |
199 | return; | |
200 | ||
201 | default: | |
202 | error("%s: not a plain file\n", name); | |
203 | return; | |
204 | } | |
205 | ||
82572cb6 | 206 | log(lfp, "%s: %s\n", u == 2 ? "updating" : "installing", name); |
2f8aab68 RC |
207 | |
208 | if (verify || vflag) | |
209 | return; | |
210 | ||
82572cb6 RC |
211 | if ((f = open(name, 0)) < 0) { |
212 | error("%s: %s\n", name, sys_errlist[errno]); | |
213 | return; | |
214 | } | |
2f8aab68 RC |
215 | (void) sprintf(buf, "R%04o %D %D %s %s %s\n", stb.st_mode & 07777, |
216 | stb.st_size, stb.st_mtime, p->pw_name, g->gr_name, last); | |
217 | if (debug) | |
218 | printf("buf = %s", buf); | |
219 | (void) write(rem, buf, strlen(buf)); | |
220 | if (response() < 0) { | |
221 | (void) close(f); | |
222 | return; | |
223 | } | |
224 | sizerr = 0; | |
225 | for (i = 0; i < stb.st_size; i += BUFSIZ) { | |
226 | int amt = BUFSIZ; | |
227 | if (i + amt > stb.st_size) | |
228 | amt = stb.st_size - i; | |
229 | if (sizerr == 0 && read(f, buf, amt) != amt) | |
230 | sizerr = 1; | |
231 | (void) write(rem, buf, amt); | |
232 | } | |
233 | (void) close(f); | |
234 | if (sizerr) | |
235 | error("%s: file changed size\n", name); | |
236 | else | |
237 | ga(); | |
238 | (void) response(); | |
239 | } | |
240 | ||
241 | rsendf(name, verify, st, owner, group) | |
242 | char *name; | |
243 | int verify; | |
244 | struct stat *st; | |
245 | char *owner, *group; | |
246 | { | |
247 | DIR *d; | |
248 | struct direct *dp; | |
249 | register char *last; | |
250 | char *otp; | |
82572cb6 | 251 | int len; |
2f8aab68 RC |
252 | |
253 | if (debug) | |
254 | printf("rsendf(%s, %d, %x, %s, %s)\n", name, verify, st, | |
255 | owner, group); | |
256 | ||
257 | if ((d = opendir(name)) == NULL) { | |
258 | error("%s: %s\n", name, sys_errlist[errno]); | |
259 | return; | |
260 | } | |
261 | last = rindex(name, '/'); | |
262 | if (last == NULL) | |
263 | last = name; | |
264 | else | |
265 | last++; | |
266 | (void) sprintf(buf, "D%04o 0 0 %s %s %s\n", st->st_mode & 07777, | |
267 | owner, group, last); | |
268 | if (debug) | |
269 | printf("buf = %s", buf); | |
270 | (void) write(rem, buf, strlen(buf)); | |
271 | if (response() < 0) { | |
272 | closedir(d); | |
273 | return; | |
274 | } | |
2f8aab68 | 275 | otp = tp; |
82572cb6 | 276 | len = tp - target; |
2f8aab68 | 277 | while (dp = readdir(d)) { |
2f8aab68 RC |
278 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) |
279 | continue; | |
82572cb6 | 280 | if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { |
2f8aab68 RC |
281 | error("%s/%s: Name too long\n", name, dp->d_name); |
282 | continue; | |
283 | } | |
284 | tp = otp; | |
285 | *tp++ = '/'; | |
286 | last = dp->d_name; | |
287 | while (*tp++ = *last++) | |
288 | ; | |
289 | tp--; | |
290 | sendf(target, verify); | |
291 | } | |
292 | closedir(d); | |
293 | (void) write(rem, "E\n", 2); | |
294 | (void) response(); | |
295 | tp = otp; | |
296 | *tp = '\0'; | |
297 | } | |
298 | ||
299 | /* | |
300 | * Check to see if file needs to be updated on the remote machine. | |
82572cb6 | 301 | * Returns 0 if no update, 1 if remote doesn't exist, and 2 if out of date. |
2f8aab68 RC |
302 | */ |
303 | update(name, st) | |
304 | char *name; | |
305 | struct stat *st; | |
306 | { | |
307 | register char *cp; | |
308 | register off_t size; | |
309 | register time_t mtime; | |
310 | ||
311 | if (debug) | |
312 | printf("update(%s, %x)\n", name, st); | |
313 | ||
314 | /* | |
315 | * Check to see if the file exists on the remote machine. | |
316 | */ | |
317 | (void) sprintf(buf, "Q%s\n", name); | |
318 | if (debug) | |
319 | printf("buf = %s", buf); | |
320 | (void) write(rem, buf, strlen(buf)); | |
321 | cp = buf; | |
322 | do { | |
323 | if (read(rem, cp, 1) != 1) | |
324 | lostconn(); | |
82572cb6 | 325 | } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); |
2f8aab68 RC |
326 | *--cp = '\0'; |
327 | cp = buf; | |
328 | if (debug) | |
329 | printf("resp = %s\n", cp); | |
330 | ||
331 | switch (*cp++) { | |
332 | case 'Y': | |
333 | break; | |
334 | ||
82572cb6 | 335 | case 'N': /* file doesn't exist so install it */ |
2f8aab68 RC |
336 | return(1); |
337 | ||
338 | case '\1': | |
82572cb6 RC |
339 | errs++; |
340 | if (*cp != '\0') { | |
341 | if (!iamremote) { | |
342 | fflush(stdout); | |
343 | (void) write(2, cp, strlen(cp)); | |
344 | } | |
345 | if (lfp != NULL) | |
346 | (void) fwrite(cp, 1, strlen(cp), lfp); | |
347 | } | |
2f8aab68 RC |
348 | return(0); |
349 | ||
350 | default: | |
351 | error("unexpected response '%c' to query\n", *--cp); | |
352 | return(0); | |
353 | } | |
354 | ||
355 | if (*cp == '\0') { | |
356 | if ((st->st_mode & S_IFMT) == S_IFDIR) | |
82572cb6 RC |
357 | return(2); |
358 | return(1); | |
2f8aab68 RC |
359 | } |
360 | ||
361 | size = 0; | |
362 | while (isdigit(*cp)) | |
363 | size = size * 10 + (*cp++ - '0'); | |
364 | if (*cp++ != ' ') { | |
365 | error("size not delimited\n"); | |
366 | return(0); | |
367 | } | |
368 | mtime = 0; | |
369 | while (isdigit(*cp)) | |
370 | mtime = mtime * 10 + (*cp++ - '0'); | |
371 | if (*cp != '\0') { | |
372 | error("mtime not delimited\n"); | |
373 | return(0); | |
374 | } | |
375 | /* | |
376 | * File needs to be updated? | |
377 | */ | |
378 | if (st->st_mtime == mtime && st->st_size == size || | |
82572cb6 | 379 | yflag && st->st_mtime < mtime) |
2f8aab68 | 380 | return(0); |
82572cb6 | 381 | return(2); |
2f8aab68 RC |
382 | } |
383 | ||
384 | /* | |
385 | * Query. Check to see if file exists. Return one of the following: | |
386 | * N\n - doesn't exist | |
387 | * Ysize mtime\n - exists and its a regular file (size & mtime of file) | |
388 | * Y\n - exists and its a directory | |
389 | * ^Aerror message\n | |
390 | */ | |
391 | query(name) | |
392 | char *name; | |
393 | { | |
394 | struct stat stb; | |
395 | ||
396 | if (catname) | |
397 | (void) sprintf(tp, "/%s", name); | |
398 | if (stat(target, &stb) < 0) { | |
399 | (void) write(rem, "N\n", 2); | |
400 | *tp = '\0'; | |
401 | return; | |
402 | } | |
403 | ||
404 | switch (stb.st_mode & S_IFMT) { | |
405 | case S_IFREG: | |
406 | (void) sprintf(buf, "Y%D %D\n", stb.st_size, stb.st_mtime); | |
407 | (void) write(rem, buf, strlen(buf)); | |
408 | break; | |
409 | ||
410 | case S_IFDIR: | |
411 | (void) write(rem, "Y\n", 2); | |
412 | break; | |
413 | ||
414 | default: | |
415 | error("%s: not a plain file\n", name); | |
416 | break; | |
417 | } | |
418 | *tp = '\0'; | |
419 | } | |
420 | ||
421 | recvf(cmd, isdir) | |
422 | char *cmd; | |
423 | int isdir; | |
424 | { | |
425 | register char *cp; | |
426 | int f, mode, wrerr, exists, olderrno; | |
427 | off_t i, size; | |
428 | time_t mtime; | |
429 | struct stat stb; | |
430 | struct timeval tvp[2]; | |
431 | char *owner, *group, *dir; | |
432 | char new[BUFSIZ]; | |
82572cb6 | 433 | extern char *tmpname; |
2f8aab68 RC |
434 | |
435 | mode = 0; | |
436 | for (cp = cmd; cp < cmd+4; cp++) { | |
437 | if (*cp < '0' || *cp > '7') { | |
438 | error("bad mode\n"); | |
439 | return; | |
440 | } | |
441 | mode = (mode << 3) | (*cp - '0'); | |
442 | } | |
443 | if (*cp++ != ' ') { | |
444 | error("mode not delimited\n"); | |
445 | return; | |
446 | } | |
447 | size = 0; | |
448 | while (isdigit(*cp)) | |
449 | size = size * 10 + (*cp++ - '0'); | |
450 | if (*cp++ != ' ') { | |
451 | error("size not delimited\n"); | |
452 | return; | |
453 | } | |
454 | mtime = 0; | |
455 | while (isdigit(*cp)) | |
456 | mtime = mtime * 10 + (*cp++ - '0'); | |
457 | if (*cp++ != ' ') { | |
458 | error("mtime not delimited\n"); | |
459 | return; | |
460 | } | |
461 | owner = cp; | |
462 | while (*cp && *cp != ' ') | |
463 | cp++; | |
464 | if (*cp != ' ') { | |
465 | error("owner name not delimited\n"); | |
466 | return; | |
467 | } | |
468 | *cp++ = '\0'; | |
469 | group = cp; | |
470 | while (*cp && *cp != ' ') | |
471 | cp++; | |
472 | if (*cp != ' ') { | |
473 | error("group name not delimited\n"); | |
474 | return; | |
475 | } | |
476 | *cp++ = '\0'; | |
477 | ||
82572cb6 | 478 | new[0] = '\0'; |
2f8aab68 RC |
479 | if (isdir) { |
480 | if (catname++) { | |
481 | *tp++ = '/'; | |
482 | while (*tp++ = *cp++) | |
483 | ; | |
484 | tp--; | |
485 | } | |
82572cb6 RC |
486 | if (vflag) { |
487 | ga(); | |
488 | return; | |
489 | } | |
2f8aab68 RC |
490 | if (stat(target, &stb) == 0) { |
491 | if ((stb.st_mode & S_IFMT) != S_IFDIR) { | |
492 | errno = ENOTDIR; | |
493 | goto bad; | |
494 | } | |
495 | } else { | |
496 | /* | |
497 | * Check parent directory for write permission. | |
498 | */ | |
499 | cp = rindex(target, '/'); | |
500 | if (cp == NULL) | |
501 | dir = "."; | |
502 | else if (cp == target) { | |
503 | dir = "/"; | |
504 | cp = NULL; | |
505 | } else { | |
506 | dir = target; | |
507 | *cp = '\0'; | |
508 | } | |
82572cb6 RC |
509 | if (access(dir, 2) < 0) |
510 | goto bad2; | |
2f8aab68 RC |
511 | if (cp != NULL) |
512 | *cp = '/'; | |
2f8aab68 RC |
513 | if (mkdir(target, mode) < 0) |
514 | goto bad; | |
82572cb6 RC |
515 | if (chog(target, owner, group, mode) < 0) |
516 | return; | |
2f8aab68 | 517 | } |
2f8aab68 RC |
518 | ga(); |
519 | return; | |
520 | } | |
521 | ||
522 | if (catname) | |
523 | (void) sprintf(tp, "/%s", cp); | |
524 | if (stat(target, &stb) == 0) { | |
525 | switch (stb.st_mode & S_IFMT) { | |
526 | case S_IFREG: | |
527 | break; | |
528 | ||
529 | case S_IFDIR: | |
530 | if (!catname) { | |
531 | (void) sprintf(tp, "/%s", cp); | |
532 | break; | |
533 | } | |
534 | ||
535 | default: | |
536 | error("%s: not a regular file\n", target); | |
537 | return; | |
538 | } | |
539 | } | |
540 | /* | |
541 | * Check parent directory for write permission. | |
542 | */ | |
543 | cp = rindex(target, '/'); | |
544 | if (cp == NULL) | |
545 | dir = "."; | |
546 | else if (cp == target) { | |
547 | dir = "/"; | |
548 | cp = NULL; | |
549 | } else { | |
550 | dir = target; | |
551 | *cp = '\0'; | |
552 | } | |
82572cb6 RC |
553 | if (access(dir, 2) < 0) { |
554 | bad2: | |
555 | error("%s: %s\n", dir, sys_errlist[errno]); | |
556 | if (cp != NULL) | |
557 | *cp = '/'; | |
558 | return; | |
559 | } | |
560 | (void) sprintf(new, "%s/%s", dir, tmpname); | |
2f8aab68 RC |
561 | if (cp != NULL) |
562 | *cp = '/'; | |
2f8aab68 RC |
563 | if ((f = creat(new, mode)) < 0) |
564 | goto bad1; | |
82572cb6 RC |
565 | if (chog(new, owner, group, mode) < 0) { |
566 | (void) close(f); | |
567 | (void) unlink(new); | |
2f8aab68 | 568 | return; |
82572cb6 | 569 | } |
2f8aab68 RC |
570 | ga(); |
571 | ||
572 | wrerr = 0; | |
573 | for (i = 0; i < size; i += BUFSIZ) { | |
574 | int amt = BUFSIZ; | |
575 | char *cp = buf; | |
576 | ||
577 | if (i + amt > size) | |
578 | amt = size - i; | |
579 | do { | |
580 | int j = read(rem, cp, amt); | |
581 | ||
82572cb6 RC |
582 | if (j <= 0) { |
583 | (void) close(f); | |
584 | (void) unlink(new); | |
2f8aab68 | 585 | cleanup(); |
82572cb6 | 586 | } |
2f8aab68 RC |
587 | amt -= j; |
588 | cp += j; | |
589 | } while (amt > 0); | |
590 | amt = BUFSIZ; | |
591 | if (i + amt > size) | |
592 | amt = size - i; | |
593 | if (wrerr == 0 && write(f, buf, amt) != amt) { | |
594 | olderrno = errno; | |
595 | wrerr++; | |
596 | } | |
597 | } | |
598 | (void) response(); | |
599 | if (wrerr) { | |
600 | error("%s: %s\n", cp, sys_errlist[olderrno]); | |
82572cb6 RC |
601 | (void) close(f); |
602 | (void) unlink(new); | |
2f8aab68 RC |
603 | return; |
604 | } | |
605 | ||
606 | /* | |
607 | * Set last modified time | |
608 | */ | |
609 | (void) fstat(f, &stb); | |
610 | (void) close(f); | |
611 | tvp[0].tv_sec = stb.st_atime; | |
612 | tvp[0].tv_usec = 0; | |
613 | tvp[1].tv_sec = mtime; | |
614 | tvp[1].tv_usec = 0; | |
615 | if (utimes(new, tvp) < 0) { | |
616 | bad1: | |
617 | error("%s: %s\n", new, sys_errlist[errno]); | |
82572cb6 RC |
618 | if (new[0]) |
619 | (void) unlink(new); | |
2f8aab68 RC |
620 | return; |
621 | } | |
622 | ||
623 | if (rename(new, target) < 0) { | |
624 | bad: | |
625 | error("%s: %s\n", target, sys_errlist[errno]); | |
82572cb6 RC |
626 | if (new[0]) |
627 | (void) unlink(new); | |
2f8aab68 RC |
628 | return; |
629 | } | |
630 | ga(); | |
631 | } | |
632 | ||
633 | /* | |
634 | * Change owner and group of file. | |
635 | */ | |
82572cb6 | 636 | chog(file, owner, group, mode) |
2f8aab68 | 637 | char *file, *owner, *group; |
82572cb6 | 638 | int mode; |
2f8aab68 | 639 | { |
82572cb6 RC |
640 | extern int userid, groupid; |
641 | extern char user[]; | |
2f8aab68 RC |
642 | register int i; |
643 | int uid, gid; | |
644 | ||
645 | uid = userid; | |
646 | if (userid == 0) { | |
82572cb6 RC |
647 | if (p == NULL || strcmp(owner, p->pw_name) != 0) { |
648 | if ((p = getpwnam(owner)) == NULL) { | |
649 | if (mode & 04000) { | |
650 | error("%s: unknown login name\n", owner); | |
651 | return(-1); | |
652 | } | |
653 | } else | |
654 | uid = p->pw_uid; | |
655 | } else | |
656 | uid = p->pw_uid; | |
657 | } | |
658 | gid = groupid; | |
659 | if (g == NULL || strcmp(group, g->gr_name) != 0) { | |
660 | if ((g = getgrnam(group)) == NULL) { | |
661 | if (mode & 02000) { | |
662 | error("%s: unknown group\n", group); | |
663 | return(-1); | |
664 | } | |
665 | } else | |
666 | gid = g->gr_gid; | |
667 | } else | |
668 | gid = g->gr_gid; | |
669 | if (userid && groupid != gid) { | |
670 | for (i = 0; g->gr_mem[i] != NULL; i++) | |
2f8aab68 RC |
671 | if (!(strcmp(user, g->gr_mem[i]))) |
672 | goto ok; | |
82572cb6 | 673 | gid = groupid; |
2f8aab68 RC |
674 | } |
675 | ok: | |
676 | if (chown(file, uid, gid) < 0) { | |
677 | error("%s: %s\n", file, sys_errlist[errno]); | |
678 | return(-1); | |
679 | } | |
680 | return(0); | |
681 | } | |
682 | ||
2f8aab68 | 683 | /*VARARGS*/ |
82572cb6 RC |
684 | log(fp, fmt, a1, a2, a3) |
685 | FILE *fp; | |
2f8aab68 RC |
686 | char *fmt; |
687 | int a1, a2, a3; | |
688 | { | |
689 | /* Print changes locally if not quiet mode */ | |
690 | if (!qflag) | |
691 | printf(fmt, a1, a2, a3); | |
692 | ||
693 | /* Save changes (for mailing) if really updating files */ | |
82572cb6 RC |
694 | if (!vflag && fp != NULL) |
695 | fprintf(fp, fmt, a1, a2, a3); | |
2f8aab68 RC |
696 | } |
697 | ||
698 | /*VARARGS*/ | |
699 | error(fmt, a1, a2, a3) | |
700 | char *fmt; | |
701 | int a1, a2, a3; | |
702 | { | |
703 | errs++; | |
704 | strcpy(buf, "\1rdist: "); | |
705 | (void) sprintf(buf+8, fmt, a1, a2, a3); | |
706 | (void) write(rem, buf, strlen(buf)); | |
707 | if (buf[1] != '\0') { | |
82572cb6 RC |
708 | if (!iamremote) { |
709 | fflush(stdout); | |
2f8aab68 | 710 | (void) write(2, buf+1, strlen(buf+1)); |
82572cb6 | 711 | } |
2f8aab68 RC |
712 | if (lfp != NULL) |
713 | (void) fwrite(buf+1, 1, strlen(buf+1), lfp); | |
714 | } | |
715 | } | |
716 | ||
717 | /*VARARGS*/ | |
718 | fatal(fmt, a1, a2,a3) | |
719 | char *fmt; | |
720 | int a1, a2, a3; | |
721 | { | |
722 | errs++; | |
723 | strcpy(buf, "\2rdist: "); | |
724 | (void) sprintf(buf+8, fmt, a1, a2, a3); | |
725 | (void) write(rem, buf, strlen(buf)); | |
726 | if (buf[1] != '\0') { | |
82572cb6 RC |
727 | if (!iamremote) { |
728 | fflush(stdout); | |
2f8aab68 | 729 | (void) write(2, buf+1, strlen(buf+1)); |
82572cb6 | 730 | } |
2f8aab68 RC |
731 | if (lfp != NULL) |
732 | (void) fwrite(buf+1, 1, strlen(buf+1), lfp); | |
733 | } | |
734 | cleanup(); | |
735 | } | |
736 | ||
737 | response() | |
738 | { | |
739 | char resp, c, *cp = buf; | |
740 | ||
741 | if (debug) | |
742 | printf("response()\n"); | |
743 | ||
744 | if (read(rem, &resp, 1) != 1) | |
745 | lostconn(); | |
746 | ||
747 | switch (resp) { | |
748 | case '\0': | |
749 | return(0); | |
750 | ||
751 | default: | |
752 | *cp++ = resp; | |
753 | /* fall into... */ | |
754 | case '\1': | |
755 | case '\2': | |
756 | errs++; | |
757 | do { | |
758 | if (read(rem, cp, 1) != 1) | |
759 | lostconn(); | |
82572cb6 RC |
760 | } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); |
761 | if (buf[0] != '\n') { | |
762 | if (!iamremote) { | |
763 | fflush(stdout); | |
2f8aab68 | 764 | (void) write(2, buf, cp - buf); |
82572cb6 | 765 | } |
2f8aab68 RC |
766 | if (lfp != NULL) |
767 | (void) fwrite(buf, 1, cp - buf, lfp); | |
768 | } | |
769 | if (resp == '\1') | |
770 | return(-1); | |
771 | cleanup(); | |
772 | } | |
773 | /*NOTREACHED*/ | |
774 | } | |
775 | ||
776 | lostconn() | |
777 | { | |
778 | if (!iamremote) | |
779 | fprintf(stderr, "rdist: lost connection\n"); | |
780 | cleanup(); | |
781 | } |