Commit | Line | Data |
---|---|---|
b6b5501c | 1 | #ifndef lint |
f7770429 | 2 | static char *sccsid = "@(#)docmd.c 4.4 (Berkeley) 83/10/12"; |
b6b5501c RC |
3 | #endif |
4 | ||
5 | #include "defs.h" | |
6 | ||
7 | FILE *lfp; /* log file for recording files updated */ | |
8 | ||
9 | /* | |
82572cb6 | 10 | * Process commands for sending files to other machines. |
b6b5501c | 11 | */ |
82572cb6 | 12 | dohcmds(files, hosts, cmds) |
b6b5501c RC |
13 | struct block *files, *hosts, *cmds; |
14 | { | |
15 | register struct block *h, *f, *c; | |
3024eb6f | 16 | register char **cpp; |
82572cb6 | 17 | int n, ddir; |
b6b5501c RC |
18 | |
19 | if (debug) | |
82572cb6 | 20 | printf("dohcmds(%x, %x, %x)\n", files, hosts, cmds); |
b6b5501c | 21 | |
82572cb6 RC |
22 | files = expand(files, 0); |
23 | hosts = expand(hosts, 1); | |
b6b5501c RC |
24 | if (files == NULL) |
25 | fatal("no files to be updated\n"); | |
26 | if (hosts == NULL) | |
27 | fatal("empty list of hosts to be updated\n"); | |
28 | except = cmds; | |
82572cb6 | 29 | ddir = files->b_next != NULL; |
b6b5501c RC |
30 | |
31 | for (h = hosts; h != NULL; h = h->b_next) { | |
82572cb6 RC |
32 | if (!qflag) |
33 | printf("updating host %s\n", h->b_name); | |
b6b5501c | 34 | if (!nflag) { |
82572cb6 RC |
35 | if (!makeconn(h->b_name)) |
36 | continue; | |
b6b5501c RC |
37 | if ((lfp = fopen(tmpfile, "w")) == NULL) { |
38 | fatal("cannot open %s\n", tmpfile); | |
39 | exit(1); | |
40 | } | |
b6b5501c RC |
41 | } |
42 | for (f = files; f != NULL; f = f->b_next) { | |
43 | if (filec) { | |
44 | for (cpp = filev; *cpp; cpp++) | |
45 | if (!strcmp(f->b_name, *cpp)) | |
46 | goto found; | |
82572cb6 RC |
47 | if (!nflag) { |
48 | (void) fclose(lfp); | |
49 | } | |
b6b5501c RC |
50 | continue; |
51 | } | |
52 | found: | |
53 | n = 0; | |
54 | for (c = cmds; c != NULL; c = c->b_next) | |
55 | if (c->b_type == INSTALL) { | |
3024eb6f | 56 | install(f->b_name, c->b_name, ddir, c->b_options); |
b6b5501c RC |
57 | n++; |
58 | } | |
59 | if (n == 0) | |
f7770429 | 60 | install(f->b_name, f->b_name, 0, options); |
b6b5501c RC |
61 | } |
62 | if (!nflag) { | |
82572cb6 RC |
63 | /* signal end of connection */ |
64 | (void) write(rem, "\2\n", 2); | |
b6b5501c | 65 | (void) close(rem); |
82572cb6 | 66 | (void) fclose(lfp); |
b6b5501c RC |
67 | } |
68 | for (c = cmds; c != NULL; c = c->b_next) | |
69 | if (c->b_type == NOTIFY) | |
f7770429 | 70 | notify(tmpfile, h->b_name, c->b_args, 0); |
b6b5501c RC |
71 | } |
72 | if (!nflag) | |
73 | (void) unlink(tmpfile); | |
74 | } | |
75 | ||
76 | /* | |
77 | * Create a connection to the rdist server on the machine rhost. | |
78 | */ | |
79 | makeconn(rhost) | |
80 | char *rhost; | |
81 | { | |
82 | register char *ruser; | |
83 | extern char user[]; | |
84 | ||
f7770429 RC |
85 | (void) sprintf(buf, "/usr/local/rdist -Server%s%s", |
86 | nflag ? " -n" : "", qflag ? " -q" : ""); | |
b6b5501c RC |
87 | |
88 | ruser = rindex(rhost, '.'); | |
89 | if (ruser != NULL) { | |
90 | *ruser++ = '\0'; | |
91 | if (!okname(ruser)) | |
92 | return(0); | |
93 | } else | |
94 | ruser = user; | |
95 | ||
96 | if (debug) { | |
97 | printf("makeconn(%s)\n", rhost); | |
98 | printf("luser = %s, ruser = %s\n", user, ruser); | |
99 | printf("buf = %s\n", buf); | |
100 | } | |
101 | ||
82572cb6 | 102 | fflush(stdout); |
b6b5501c RC |
103 | rem = rcmd(&rhost, IPPORT_CMDSERVER, user, ruser, buf, 0); |
104 | if (rem < 0) | |
105 | return(0); | |
106 | if (response() < 0) | |
107 | return(0); | |
108 | return(1); | |
109 | } | |
110 | ||
111 | /* | |
112 | * Update the file(s) if they are different. | |
82572cb6 RC |
113 | * destdir = 1 if destination should be a directory |
114 | * (i.e., more than one source is being copied to the same destination). | |
b6b5501c | 115 | */ |
f7770429 | 116 | install(src, dest, destdir, opts) |
b6b5501c | 117 | char *src, *dest; |
f7770429 | 118 | int destdir, opts; |
b6b5501c | 119 | { |
3024eb6f RC |
120 | register char *cp; |
121 | ||
82572cb6 RC |
122 | if (exclude(src)) |
123 | return; | |
b6b5501c | 124 | |
3024eb6f | 125 | if (nflag || debug) { |
f7770429 RC |
126 | printf("%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", |
127 | opts & WHOLE ? " -w" : "", | |
128 | opts & YOUNGER ? " -y" : "", src, dest); | |
3024eb6f RC |
129 | if (nflag) |
130 | return; | |
82572cb6 | 131 | } |
b6b5501c RC |
132 | /* |
133 | * Pass the destination file/directory name to remote. | |
134 | */ | |
82572cb6 | 135 | (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest); |
b6b5501c RC |
136 | if (debug) |
137 | printf("buf = %s", buf); | |
138 | (void) write(rem, buf, strlen(buf)); | |
3024eb6f | 139 | |
f7770429 RC |
140 | if (!destdir && (opts & WHOLE)) |
141 | opts |= STRIP; | |
142 | sendf(src, NULL, opts); | |
82572cb6 RC |
143 | } |
144 | ||
145 | struct tstamp { | |
146 | time_t lastmod; | |
147 | FILE *tfp; | |
148 | } ts[NSTAMPS]; | |
149 | ||
150 | int nstamps; | |
151 | ||
3024eb6f RC |
152 | extern char target[], *tp; |
153 | ||
82572cb6 RC |
154 | /* |
155 | * Process commands for comparing files to time stamp files. | |
156 | */ | |
157 | dofcmds(files, stamps, cmds) | |
158 | struct block *files, *stamps, *cmds; | |
159 | { | |
160 | register struct block *b; | |
161 | register struct tstamp *t; | |
162 | register char **cpp; | |
f7770429 RC |
163 | struct timeval tv[2]; |
164 | struct timezone tz; | |
82572cb6 RC |
165 | struct stat stb; |
166 | extern char *tmpinc; | |
82572cb6 RC |
167 | |
168 | if (debug) | |
169 | printf("dofcmds()\n"); | |
170 | ||
171 | files = expand(files, 0); | |
f7770429 | 172 | stamps = expand(stamps, 0); |
82572cb6 RC |
173 | if (files == NULL) |
174 | fatal("no files to be updated\n"); | |
175 | if (stamps == NULL) | |
176 | fatal("empty time stamp file list\n"); | |
177 | except = cmds; | |
178 | ||
179 | t = ts; | |
180 | nstamps = 0; | |
181 | for (b = stamps; b != NULL; b = b->b_next) { | |
182 | if (stat(b->b_name, &stb) < 0) { | |
183 | error("%s: %s\n", b->b_name, sys_errlist[errno]); | |
184 | continue; | |
185 | } | |
186 | if (++nstamps > NSTAMPS) | |
187 | fatal("too many time stamp files in one command\n"); | |
188 | if (debug) | |
189 | printf("%s: %d\n", b->b_name, stb.st_mtime); | |
190 | t->lastmod = stb.st_mtime; | |
f7770429 RC |
191 | (void) gettimeofday(&tv[0], &tz); |
192 | tv[1] = tv[0]; | |
193 | (void) utimes(b->b_name, tv); | |
194 | if (!nflag && !(options & VERIFY)) { | |
82572cb6 RC |
195 | if ((t->tfp = fopen(tmpfile, "w")) == NULL) |
196 | error("%s: %s\n", b->b_name, sys_errlist[errno]); | |
197 | (*tmpinc)++; | |
198 | } else | |
199 | t->tfp = NULL; | |
200 | t++; | |
201 | } | |
f7770429 | 202 | |
82572cb6 RC |
203 | for (b = files; b != NULL; b = b->b_next) { |
204 | if (filec) { | |
205 | for (cpp = filev; *cpp; cpp++) | |
206 | if (!strcmp(b->b_name, *cpp)) | |
207 | goto found; | |
208 | continue; | |
209 | } | |
210 | found: | |
211 | tp = NULL; | |
212 | cmptime(b->b_name); | |
213 | } | |
f7770429 | 214 | |
82572cb6 | 215 | *tmpinc = 'A'; |
f7770429 RC |
216 | for (t = ts; t < &ts[nstamps]; t++) { |
217 | if (t->tfp != NULL) | |
218 | (void) fclose(t->tfp); | |
82572cb6 RC |
219 | for (b = cmds; b != NULL; b = b->b_next) |
220 | if (b->b_type == NOTIFY) | |
f7770429 RC |
221 | notify(tmpfile, NULL, b->b_args, t->lastmod); |
222 | if (!nflag && !(options & VERIFY)) | |
82572cb6 RC |
223 | (void) unlink(tmpfile); |
224 | (*tmpinc)++; | |
225 | } | |
226 | } | |
227 | ||
228 | /* | |
229 | * Compare the mtime of file to the list of time stamps. | |
230 | */ | |
231 | cmptime(name) | |
232 | char *name; | |
233 | { | |
234 | register struct tstamp *t; | |
235 | struct stat stb; | |
236 | ||
237 | if (debug) | |
238 | printf("cmptime(%s)\n", name); | |
239 | ||
240 | if (exclude(name)) | |
241 | return; | |
242 | ||
243 | /* | |
244 | * first time cmptime() is called? | |
245 | */ | |
246 | if (tp == NULL) { | |
247 | exptilde(target, name); | |
248 | tp = name = target; | |
249 | while (*tp) | |
250 | tp++; | |
251 | } | |
252 | if (access(name, 4) < 0 || stat(name, &stb) < 0) { | |
253 | error("%s: %s\n", name, sys_errlist[errno]); | |
254 | return; | |
255 | } | |
256 | ||
257 | switch (stb.st_mode & S_IFMT) { | |
258 | case S_IFREG: | |
259 | break; | |
260 | ||
261 | case S_IFDIR: | |
262 | rcmptime(&stb); | |
263 | return; | |
264 | ||
265 | default: | |
266 | error("%s: not a plain file\n", name); | |
267 | return; | |
268 | } | |
269 | ||
270 | for (t = ts; t < &ts[nstamps]; t++) { | |
f7770429 RC |
271 | if (stb.st_mtime > t->lastmod) |
272 | log(t->tfp, "new: %s\n", name); | |
82572cb6 RC |
273 | } |
274 | } | |
275 | ||
276 | rcmptime(st) | |
277 | struct stat *st; | |
278 | { | |
279 | register DIR *d; | |
280 | register struct direct *dp; | |
281 | register char *cp; | |
282 | char *otp; | |
283 | int len; | |
284 | ||
285 | if (debug) | |
286 | printf("rcmptime(%x)\n", st); | |
287 | ||
288 | if ((d = opendir(target)) == NULL) { | |
289 | error("%s: %s\n", target, sys_errlist[errno]); | |
290 | return; | |
291 | } | |
292 | otp = tp; | |
293 | len = tp - target; | |
294 | while (dp = readdir(d)) { | |
295 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) | |
296 | continue; | |
297 | if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { | |
298 | error("%s/%s: Name too long\n", target, dp->d_name); | |
299 | continue; | |
300 | } | |
301 | tp = otp; | |
302 | *tp++ = '/'; | |
303 | cp = dp->d_name; | |
304 | while (*tp++ = *cp++) | |
305 | ; | |
306 | tp--; | |
307 | cmptime(target); | |
308 | } | |
309 | closedir(d); | |
310 | tp = otp; | |
311 | *tp = '\0'; | |
b6b5501c RC |
312 | } |
313 | ||
314 | /* | |
315 | * Notify the list of people the changes that were made. | |
f7770429 RC |
316 | * rhost == NULL if we are mailing a list of changes compared to at time |
317 | * stamp file. | |
b6b5501c | 318 | */ |
f7770429 | 319 | notify(file, rhost, to, lmod) |
3024eb6f | 320 | char *file, *rhost; |
b6b5501c | 321 | register struct block *to; |
f7770429 | 322 | time_t lmod; |
b6b5501c RC |
323 | { |
324 | register int fd, len; | |
325 | FILE *pf, *popen(); | |
326 | struct stat stb; | |
327 | ||
f7770429 | 328 | if (options & VERIFY) |
b6b5501c RC |
329 | return; |
330 | if (!qflag) { | |
82572cb6 | 331 | printf("notify "); |
3024eb6f RC |
332 | if (rhost) |
333 | printf("@%s ", rhost); | |
b6b5501c RC |
334 | prnames(to); |
335 | } | |
336 | if (nflag) | |
337 | return; | |
338 | ||
82572cb6 RC |
339 | if ((fd = open(file, 0)) < 0) { |
340 | error("%s: %s\n", file, sys_errlist[errno]); | |
341 | return; | |
342 | } | |
343 | if (fstat(fd, &stb) < 0) { | |
344 | error("%s: %s\n", file, sys_errlist[errno]); | |
345 | (void) close(fd); | |
346 | return; | |
347 | } | |
348 | if (stb.st_size == 0) { | |
349 | (void) close(fd); | |
b6b5501c RC |
350 | return; |
351 | } | |
352 | /* | |
353 | * Create a pipe to mailling program. | |
354 | */ | |
355 | pf = popen(MAILCMD, "w"); | |
3024eb6f RC |
356 | if (pf == NULL) { |
357 | error("notify: \"%s\" failed\n", MAILCMD); | |
358 | (void) close(fd); | |
359 | return; | |
360 | } | |
b6b5501c RC |
361 | /* |
362 | * Output the proper header information. | |
363 | */ | |
364 | fprintf(pf, "From: rdist (Remote distribution program)\n"); | |
365 | fprintf(pf, "To:"); | |
f7770429 RC |
366 | if (!any('@', to->b_name) && host != NULL) |
367 | fprintf(pf, " %s@%s", to->b_name, rhost); | |
368 | else | |
369 | fprintf(pf, " %s", to->b_name); | |
370 | to = to->b_next; | |
b6b5501c | 371 | while (to != NULL) { |
3024eb6f | 372 | if (!any('@', to->b_name) && host != NULL) |
f7770429 | 373 | fprintf(pf, ", %s@%s", to->b_name, rhost); |
82572cb6 | 374 | else |
f7770429 | 375 | fprintf(pf, ", %s", to->b_name); |
b6b5501c RC |
376 | to = to->b_next; |
377 | } | |
378 | putc('\n', pf); | |
f7770429 RC |
379 | if (rhost != NULL) |
380 | fprintf(pf, "Subject: files updated by rdist from %s to %s\n", | |
381 | host, rhost); | |
382 | else | |
383 | fprintf(pf, "Subject: files updated after %s\n", ctime(&lmod)); | |
b6b5501c RC |
384 | putc('\n', pf); |
385 | ||
386 | while ((len = read(fd, buf, BUFSIZ)) > 0) | |
387 | (void) fwrite(buf, 1, len, pf); | |
388 | (void) close(fd); | |
389 | (void) pclose(pf); | |
390 | } | |
391 | ||
392 | struct block *except; /* list of files to exclude */ | |
393 | ||
394 | /* | |
395 | * Return true if name is in list. | |
396 | */ | |
397 | exclude(file) | |
398 | char *file; | |
399 | { | |
400 | register struct block *b, *c; | |
401 | ||
402 | for (c = except; c != NULL; c = c->b_next) { | |
403 | if (c->b_type != EXCEPT) | |
404 | continue; | |
405 | for (b = c->b_args; b != NULL; b = b->b_next) | |
406 | if (!strcmp(file, b->b_name)) | |
407 | return(1); | |
408 | } | |
409 | return(0); | |
410 | } | |
411 | ||
412 | okname(name) | |
413 | register char *name; | |
414 | { | |
415 | register char *cp = name; | |
416 | register int c; | |
417 | ||
418 | do { | |
419 | c = *cp; | |
420 | if (c & 0200) | |
421 | goto bad; | |
422 | if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') | |
423 | goto bad; | |
424 | cp++; | |
425 | } while (*cp); | |
426 | return(1); | |
427 | bad: | |
428 | error("invalid user name %s\n", name); | |
429 | return(0); | |
430 | } | |
431 | ||
432 | char * | |
433 | colon(cp) | |
434 | register char *cp; | |
435 | { | |
436 | ||
437 | while (*cp) { | |
438 | if (*cp == ':') | |
439 | return(cp); | |
440 | if (*cp == '/') | |
441 | return(0); | |
442 | cp++; | |
443 | } | |
444 | return(0); | |
445 | } |