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