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