clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name docmd.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/rdist/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I . -I /usr/src/usr.bin/rdist -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/rdist/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/rdist/docmd.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | #include <ctype.h> |
33 | #include <dirent.h> |
34 | #include <errno.h> |
35 | #include <fcntl.h> |
36 | #include <paths.h> |
37 | #include <stdlib.h> |
38 | #include <string.h> |
39 | #include <unistd.h> |
40 | |
41 | #include "client.h" |
42 | #include "gram.h" |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | struct subcmd *subcmds; |
49 | |
50 | struct namelist *filelist; |
51 | time_t lastmod; |
52 | |
53 | static void closeconn(void); |
54 | static void notify(char *, struct namelist *, time_t); |
55 | static void checkcmd(struct cmd *); |
56 | static void markfailed(struct cmd *, struct cmd *); |
57 | static int remotecmd(char *, char *, char *, char *); |
58 | static int makeconn(char *); |
59 | static void doarrow(struct cmd *, char **); |
60 | static void rcmptime(struct stat *, struct subcmd *, char **); |
61 | static void cmptime(char *, struct subcmd *, char **); |
62 | static void dodcolon(struct cmd *, char **); |
63 | static void docmdhost(struct cmd *, char **); |
64 | static void docmd(struct cmd *, int, char **); |
65 | |
66 | |
67 | |
68 | |
69 | static void |
70 | closeconn(void) |
71 | { |
72 | debugmsg(DM_CALL, "closeconn() called\n"); |
73 | |
74 | if (rem_w >= 0) { |
75 | |
76 | signal(SIGPIPE, SIG_IGN); |
77 | |
78 | (void) sendcmd(C_FERRMSG, NULL); |
79 | (void) close(rem_w); |
80 | (void) close(rem_r); |
81 | rem_w = -1; |
82 | rem_r = -1; |
83 | } |
84 | } |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | |
91 | static void |
92 | notify(char *rhost, struct namelist *to, time_t lmod) |
93 | { |
94 | int fd; |
95 | ssize_t len; |
96 | FILE *pf; |
97 | struct stat stb; |
98 | static char buf[BUFSIZ]; |
99 | char *file, *user; |
100 | |
101 | if (IS_ON(options, DO_VERIFY) || to == NULL) |
102 | return; |
103 | |
104 | if ((file = getnotifyfile()) == NULL) |
105 | return; |
106 | |
107 | if (!IS_ON(options, DO_QUIET)) { |
108 | message(MT_INFO, "notify %s%s %s", |
109 | (rhost) ? "@" : "", |
110 | (rhost) ? rhost : "", getnlstr(to)); |
111 | } |
112 | |
113 | if (nflag) |
114 | return; |
115 | |
116 | debugmsg(DM_MISC, "notify() temp file = '%s'", file); |
117 | |
118 | if ((fd = open(file, O_RDONLY)) == -1) { |
119 | error("%s: open for reading failed: %s", file, SYSERR); |
120 | return; |
121 | } |
122 | if (fstat(fd, &stb) == -1) { |
123 | error("%s: fstat failed: %s", file, SYSERR); |
124 | (void) close(fd); |
125 | return; |
126 | } |
127 | if (stb.st_size == 0) { |
128 | (void) close(fd); |
129 | return; |
130 | } |
131 | |
132 | |
133 | |
134 | |
135 | |
136 | (void) snprintf(buf, sizeof(buf), "IFS=\" \t\"; export IFS; %s -oi -t", |
137 | _PATH_SENDMAIL); |
138 | pf = popen(buf, "w"); |
139 | if (pf == NULL) { |
140 | error("notify: \"%s\" failed\n", _PATH_SENDMAIL); |
141 | (void) unlink(file); |
142 | (void) close(fd); |
143 | return; |
144 | } |
145 | |
146 | |
147 | |
148 | (void) fprintf(pf, "Auto-Submitted: auto-generated\n"); |
149 | (void) fprintf(pf, "From: rdist (Remote distribution program)\n"); |
150 | (void) fprintf(pf, "To:"); |
151 | if (!any('@', to->n_name) && rhost != NULL) |
152 | (void) fprintf(pf, " %s@%s", to->n_name, rhost); |
153 | else |
154 | (void) fprintf(pf, " %s", to->n_name); |
155 | to = to->n_next; |
156 | while (to != NULL) { |
157 | if (!any('@', to->n_name) && rhost != NULL) |
158 | (void) fprintf(pf, ", %s@%s", to->n_name, rhost); |
159 | else |
160 | (void) fprintf(pf, ", %s", to->n_name); |
161 | to = to->n_next; |
162 | } |
163 | (void) putc('\n', pf); |
164 | |
165 | if ((user = getlogin()) == NULL) |
166 | user = locuser; |
167 | |
168 | if (rhost != NULL) |
169 | (void) fprintf(pf, |
170 | "Subject: files updated by %s from %s to %s\n", |
171 | locuser, host, rhost); |
172 | else |
173 | (void) fprintf(pf, "Subject: files updated after %s\n", |
174 | ctime(&lmod)); |
175 | (void) putc('\n', pf); |
176 | (void) putc('\n', pf); |
177 | (void) fprintf(pf, "Options: %s\n\n", getondistoptlist(options)); |
178 | |
179 | while ((len = read(fd, buf, sizeof(buf))) > 0) |
180 | (void) fwrite(buf, 1, len, pf); |
181 | |
182 | (void) pclose(pf); |
183 | (void) close(fd); |
184 | (void) unlink(file); |
185 | } |
186 | |
187 | |
188 | |
189 | |
190 | |
191 | |
192 | |
193 | static void |
194 | checkcmd(struct cmd *cmd) |
195 | { |
196 | int l; |
197 | |
198 | if (!cmd || !(cmd->c_name)) { |
199 | debugmsg(DM_MISC, "checkcmd() NULL cmd parameter"); |
200 | return; |
201 | } |
202 | |
203 | l = strlen(cmd->c_name); |
204 | if (l <= 0) |
205 | return; |
206 | if (cmd->c_name[l-1] == '+') { |
207 | cmd->c_flags |= CMD_NOCHKNFS; |
208 | cmd->c_name[l-1] = CNULL; |
209 | } |
210 | } |
211 | |
212 | |
213 | |
214 | |
215 | |
216 | void |
217 | markassigned(struct cmd *cmd, struct cmd *cmdlist) |
218 | { |
219 | struct cmd *pcmd; |
220 | |
221 | for (pcmd = cmdlist; pcmd; pcmd = pcmd->c_next) { |
222 | checkcmd(pcmd); |
223 | if (pcmd->c_type == cmd->c_type && |
224 | strcmp(pcmd->c_name, cmd->c_name)==0) |
225 | pcmd->c_flags |= CMD_ASSIGNED; |
226 | } |
227 | } |
228 | |
229 | |
230 | |
231 | |
232 | static void |
233 | markfailed(struct cmd *cmd, struct cmd *cmdlist) |
234 | { |
235 | struct cmd *pc; |
236 | |
237 | if (!cmd) { |
238 | debugmsg(DM_MISC, "markfailed() NULL cmd parameter"); |
239 | return; |
240 | } |
241 | |
242 | checkcmd(cmd); |
243 | cmd->c_flags |= CMD_CONNFAILED; |
244 | for (pc = cmdlist; pc; pc = pc->c_next) { |
245 | checkcmd(pc); |
246 | if (pc->c_type == cmd->c_type && |
247 | strcmp(pc->c_name, cmd->c_name)==0) |
248 | pc->c_flags |= CMD_CONNFAILED; |
249 | } |
250 | } |
251 | |
252 | static int |
253 | remotecmd(char *rhost, char *luser, char *ruser, char *cmd) |
254 | { |
255 | int desc; |
256 | |
257 | debugmsg(DM_MISC, "local user = %s remote user = %s\n", luser, ruser); |
258 | debugmsg(DM_MISC, "Remote command = '%s'\n", cmd); |
259 | |
260 | (void) fflush(stdout); |
261 | (void) fflush(stderr); |
262 | (void) signal(SIGALRM, sighandler); |
263 | (void) alarm(RTIMEOUT); |
264 | |
265 | debugmsg(DM_MISC, "Remote shell command = '%s'\n", |
266 | path_remsh ? path_remsh : "default"); |
267 | (void) signal(SIGPIPE, SIG_IGN); |
268 | desc = rcmdsh(&rhost, -1, luser, ruser, cmd, path_remsh); |
269 | if (desc > 0) |
270 | (void) signal(SIGPIPE, sighandler); |
271 | |
272 | (void) alarm(0); |
273 | |
274 | return(desc); |
275 | } |
276 | |
277 | |
278 | |
279 | |
280 | |
281 | static int |
282 | makeconn(char *rhost) |
283 | { |
284 | char *ruser, *cp; |
285 | static char *cur_host = NULL; |
286 | char tuser[BUFSIZ], buf[BUFSIZ]; |
287 | u_char respbuff[BUFSIZ]; |
288 | int n; |
289 | |
290 | debugmsg(DM_CALL, "makeconn(%s)", rhost); |
291 | |
292 | |
293 | |
294 | |
295 | if (cur_host != NULL && rem_w >= 0) { |
296 | if (strcmp(cur_host, rhost) == 0) |
297 | return(1); |
298 | closeconn(); |
299 | } |
300 | |
301 | |
302 | |
303 | |
304 | cur_host = rhost; |
305 | cp = strchr(rhost, '@'); |
306 | |
307 | if (cp != NULL) { |
| 50 | | Assuming 'cp' is not equal to NULL | |
|
| |
308 | char c = *cp; |
309 | |
310 | *cp = CNULL; |
311 | (void) strlcpy((char *)tuser, rhost, sizeof(tuser)); |
| 52 | | Null pointer passed as 2nd argument to string copy function |
|
312 | *cp = c; |
313 | rhost = cp + 1; |
314 | ruser = tuser; |
315 | if (*ruser == CNULL) |
316 | ruser = locuser; |
317 | else if (!okname(ruser)) |
318 | return(0); |
319 | } else |
320 | ruser = locuser; |
321 | |
322 | if (!IS_ON(options, DO_QUIET)) |
323 | message(MT_VERBOSE, "updating host %s", rhost); |
324 | |
325 | (void) snprintf(buf, sizeof(buf), "%.*s -S", |
326 | (int)(sizeof(buf)-5), path_rdistd); |
327 | |
328 | if ((rem_r = rem_w = remotecmd(rhost, locuser, ruser, buf)) < 0) |
329 | return(0); |
330 | |
331 | |
332 | |
333 | |
334 | respbuff[0] = '\0'; |
335 | n = remline(respbuff, sizeof(respbuff), TRUE); |
336 | if (n <= 0 || respbuff[0] != S_VERSION) { |
337 | if (n > 0) |
338 | error("Unexpected input from server: \"%s\".", respbuff); |
339 | else |
340 | error("No input from server."); |
341 | closeconn(); |
342 | return(0); |
343 | } |
344 | |
345 | |
346 | |
347 | |
348 | |
349 | |
350 | |
351 | if (respbuff[1] == CNULL) { |
352 | |
353 | |
354 | |
355 | (void) sendcmd(S_VERSION, "%d", VERSION); |
356 | if (response() < 0) |
357 | return(0); |
358 | } else { |
359 | |
360 | |
361 | |
362 | int proto_version = atoi(&respbuff[1]); |
363 | if (proto_version != VERSION) { |
364 | fatalerr( |
365 | "Server version (%d) is not the same as local version (%d).", |
366 | proto_version, VERSION); |
367 | return(0); |
368 | } |
369 | } |
370 | |
371 | |
372 | |
373 | |
374 | if (host[0]) { |
375 | (void) sendcmd(C_SETCONFIG, "%c%s", SC_HOSTNAME, host); |
376 | if (response() < 0) |
377 | return(0); |
378 | } |
379 | if (min_freespace) { |
380 | (void) sendcmd(C_SETCONFIG, "%c%lld", SC_FREESPACE, |
381 | min_freespace); |
382 | if (response() < 0) |
383 | return(0); |
384 | } |
385 | if (min_freefiles) { |
386 | (void) sendcmd(C_SETCONFIG, "%c%lld", SC_FREEFILES, |
387 | min_freefiles); |
388 | if (response() < 0) |
389 | return(0); |
390 | } |
391 | if (remotemsglist) { |
392 | (void) sendcmd(C_SETCONFIG, "%c%s", SC_LOGGING, remotemsglist); |
393 | if (response() < 0) |
394 | return(0); |
395 | } |
396 | if (strcmp(defowner, "bin") != 0) { |
397 | (void) sendcmd(C_SETCONFIG, "%c%s", SC_DEFOWNER, defowner); |
398 | if (response() < 0) |
399 | return(0); |
400 | } |
401 | if (strcmp(defgroup, "bin") != 0) { |
402 | (void) sendcmd(C_SETCONFIG, "%c%s", SC_DEFGROUP, defgroup); |
403 | if (response() < 0) |
404 | return(0); |
405 | } |
406 | |
407 | return(1); |
408 | } |
409 | |
410 | |
411 | |
412 | |
413 | static void |
414 | doarrow(struct cmd *cmd, char **filev) |
415 | { |
416 | struct namelist *f; |
417 | struct subcmd *sc; |
418 | char **cpp; |
419 | int n, ddir, destdir; |
420 | volatile opt_t opts = options; |
421 | struct namelist *files; |
422 | struct subcmd *sbcmds; |
423 | char *rhost; |
424 | volatile int didupdate = 0; |
425 | |
426 | if (setjmp_ok) { |
| 35 | | Assuming 'setjmp_ok' is 0 | |
|
| |
427 | error("reentrant call to doarrow"); |
428 | abort(); |
429 | } |
430 | |
431 | if (!cmd) { |
| |
432 | debugmsg(DM_MISC, "doarrow() NULL cmd parameter"); |
433 | return; |
434 | } |
435 | |
436 | files = cmd->c_files; |
437 | sbcmds = cmd->c_cmds; |
438 | rhost = cmd->c_name; |
| 38 | | Null pointer value stored to 'rhost' | |
|
439 | |
440 | if (files == NULL) { |
| 39 | | Assuming 'files' is not equal to NULL | |
|
| |
441 | error("No files to be updated on %s for target \"%s\"", |
442 | rhost, cmd->c_label); |
443 | return; |
444 | } |
445 | |
446 | debugmsg(DM_CALL, "doarrow(%p, %s, %p) start", |
447 | files, A(rhost), sbcmds); |
| |
448 | |
449 | if (nflag) |
| |
| |
450 | (void) printf("updating host %s\n", rhost); |
451 | else { |
452 | if (cmd->c_flags & CMD_CONNFAILED) { |
| 44 | | Assuming the condition is false | |
|
| |
453 | debugmsg(DM_MISC, |
454 | "makeconn %s failed before; skipping\n", |
455 | rhost); |
456 | return; |
457 | } |
458 | |
459 | if (setjmp(finish_jmpbuf)) { |
| 46 | | Assuming the condition is false | |
|
| |
460 | setjmp_ok = FALSE; |
461 | debugmsg(DM_MISC, "setjmp to finish_jmpbuf"); |
462 | markfailed(cmd, cmds); |
463 | return; |
464 | } |
465 | setjmp_ok = TRUE; |
466 | |
467 | if (!makeconn(rhost)) { |
| 48 | | Passing null pointer value via 1st parameter 'rhost' | |
|
| |
468 | setjmp_ok = FALSE; |
469 | markfailed(cmd, cmds); |
470 | return; |
471 | } |
472 | } |
473 | |
474 | subcmds = sbcmds; |
475 | filelist = files; |
476 | |
477 | n = 0; |
478 | for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { |
479 | if (sc->sc_type != INSTALL) |
480 | continue; |
481 | n++; |
482 | |
483 | |
484 | |
485 | |
486 | |
487 | |
488 | |
489 | |
490 | |
491 | |
492 | |
493 | |
494 | |
495 | |
496 | ddir = files->n_next != NULL; |
497 | if (!ddir) { |
498 | struct stat s; |
499 | int isadir = 0; |
500 | |
501 | if (lstat(files->n_name, &s) == 0) |
502 | isadir = S_ISDIR(s.st_mode); |
503 | if (!isadir && sc->sc_name && *sc->sc_name) |
504 | ddir = !strcmp(xbasename(sc->sc_name),"."); |
505 | destdir = isadir | ddir; |
506 | } else |
507 | destdir = ddir; |
508 | |
509 | debugmsg(DM_MISC, |
510 | "Debug files->n_next= %p, destdir=%d, ddir=%d", |
511 | files->n_next, destdir, ddir); |
512 | |
513 | if (!sc->sc_name || !*sc->sc_name) { |
514 | destdir = 0; |
515 | ddir = 0; |
516 | } |
517 | |
518 | debugmsg(DM_MISC, |
519 | "Debug sc->sc_name=%p, destdir=%d, ddir=%d", |
520 | sc->sc_name, destdir, ddir); |
521 | |
522 | for (f = files; f != NULL; f = f->n_next) { |
523 | if (filev) { |
524 | for (cpp = filev; *cpp; cpp++) |
525 | if (strcmp(f->n_name, *cpp) == 0) |
526 | goto found; |
527 | continue; |
528 | } |
529 | found: |
530 | if (install(f->n_name, sc->sc_name, ddir, destdir, |
531 | sc->sc_options) > 0) |
532 | ++didupdate; |
533 | opts = sc->sc_options; |
534 | } |
535 | |
536 | } |
537 | |
538 | |
539 | if (!n) { |
540 | for (f = files; f != NULL; f = f->n_next) { |
541 | if (filev) { |
542 | for (cpp = filev; *cpp; cpp++) |
543 | if (strcmp(f->n_name, *cpp) == 0) |
544 | goto found2; |
545 | continue; |
546 | } |
547 | found2: |
548 | |
549 | if (install(f->n_name, NULL, 0, 0, options) > 0) |
550 | ++didupdate; |
551 | } |
552 | } |
553 | |
554 | |
555 | |
556 | |
557 | if (didupdate > 0) { |
558 | runcmdspecial(cmd, opts); |
559 | didupdate = 0; |
560 | } |
561 | |
562 | if (!nflag) |
563 | (void) signal(SIGPIPE, cleanup); |
564 | |
565 | for (sc = sbcmds; sc != NULL; sc = sc->sc_next) |
566 | if (sc->sc_type == NOTIFY) |
567 | notify(rhost, sc->sc_args, (time_t) 0); |
568 | |
569 | if (!nflag) { |
570 | struct linkbuf *nextl, *l; |
571 | |
572 | for (l = ihead; l != NULL; freelinkinfo(l), l = nextl) { |
573 | nextl = l->nextp; |
574 | if (contimedout || IS_ON(opts, DO_IGNLNKS) || |
575 | l->count == 0) |
576 | continue; |
577 | message(MT_WARNING, "%s: Warning: %d %s link%s", |
578 | l->pathname, abs(l->count), |
579 | (l->count > 0) ? "missing" : "extra", |
580 | (l->count == 1) ? "" : "s"); |
581 | } |
582 | ihead = NULL; |
583 | } |
584 | setjmp_ok = FALSE; |
585 | } |
586 | |
587 | int |
588 | okname(char *name) |
589 | { |
590 | char *cp = name; |
591 | int c, isbad; |
592 | |
593 | for (isbad = FALSE; *cp && !isbad; ++cp) { |
594 | c = *cp; |
595 | if (c & 0200) |
596 | isbad = TRUE; |
597 | if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') |
598 | isbad = TRUE; |
599 | } |
600 | |
601 | if (isbad) { |
602 | error("Invalid user name \"%s\"\n", name); |
603 | return(0); |
604 | } |
605 | return(1); |
606 | } |
607 | |
608 | static void |
609 | rcmptime(struct stat *st, struct subcmd *sbcmds, char **env) |
610 | { |
611 | DIR *d; |
612 | struct dirent *dp; |
613 | char *cp; |
614 | char *optarget; |
615 | int len; |
616 | |
617 | debugmsg(DM_CALL, "rcmptime(%p) start", st); |
618 | |
619 | if ((d = opendir((char *) target)) == NULL) { |
620 | error("%s: open directory failed: %s", target, SYSERR); |
621 | return; |
622 | } |
623 | optarget = ptarget; |
624 | len = ptarget - target; |
625 | while ((dp = readdir(d)) != NULL) { |
626 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) |
627 | continue; |
628 | if (len + 1 + (int)strlen(dp->d_name) >= BUFSIZ - 1) { |
629 | error("%s/%s: Name too long\n", target, dp->d_name); |
630 | continue; |
631 | } |
632 | ptarget = optarget; |
633 | *ptarget++ = '/'; |
634 | cp = dp->d_name; |
635 | while ((*ptarget++ = *cp++) != '\0') |
636 | ; |
637 | ptarget--; |
638 | cmptime(target, sbcmds, env); |
639 | } |
640 | (void) closedir((DIR *) d); |
641 | ptarget = optarget; |
642 | *ptarget = '\0'; |
643 | } |
644 | |
645 | |
646 | |
647 | |
648 | static void |
649 | cmptime(char *name, struct subcmd *sbcmds, char **env) |
650 | { |
651 | struct subcmd *sc; |
652 | struct stat stb; |
653 | |
654 | debugmsg(DM_CALL, "cmptime(%s)", name); |
655 | |
656 | if (except(name)) |
657 | return; |
658 | |
659 | if (nflag) { |
660 | (void) printf("comparing dates: %s\n", name); |
661 | return; |
662 | } |
663 | |
664 | |
665 | |
666 | |
667 | if (ptarget == NULL) { |
668 | if (exptilde(target, name, sizeof(target)) == NULL) |
669 | return; |
670 | ptarget = name = target; |
671 | while (*ptarget) |
672 | ptarget++; |
673 | } |
674 | if (access(name, R_OK) == -1 || stat(name, &stb) == -1) { |
675 | error("%s: cannot access file: %s", name, SYSERR); |
676 | return; |
677 | } |
678 | |
679 | if (S_ISDIR(stb.st_mode)) { |
680 | rcmptime(&stb, sbcmds, env); |
681 | return; |
682 | } else if (!S_ISREG(stb.st_mode)) { |
683 | error("%s: not a plain file", name); |
684 | return; |
685 | } |
686 | |
687 | if (stb.st_mtime > lastmod) { |
688 | message(MT_INFO, "%s: file is newer", name); |
689 | for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { |
690 | char buf[BUFSIZ]; |
691 | if (sc->sc_type != SPECIAL) |
692 | continue; |
693 | if (sc->sc_args != NULL && !inlist(sc->sc_args, name)) |
694 | continue; |
695 | (void) snprintf(buf, sizeof(buf), "%s=%s;%s", |
696 | E_LOCFILE, name, sc->sc_name); |
697 | message(MT_CHANGE, "special \"%s\"", buf); |
698 | if (*env) { |
699 | size_t len = strlen(*env) + strlen(name) + 2; |
700 | *env = xrealloc(*env, len); |
701 | (void) strlcat(*env, name, len); |
702 | (void) strlcat(*env, ":", len); |
703 | } |
704 | if (IS_ON(options, DO_VERIFY)) |
705 | continue; |
706 | |
707 | runcommand(buf); |
708 | } |
709 | } |
710 | } |
711 | |
712 | |
713 | |
714 | |
715 | static void |
716 | dodcolon(struct cmd *cmd, char **filev) |
717 | { |
718 | struct subcmd *sc; |
719 | struct namelist *f; |
720 | char *cp, **cpp; |
721 | struct stat stb; |
722 | struct namelist *files = cmd->c_files; |
723 | struct subcmd *sbcmds = cmd->c_cmds; |
724 | char *env, *stamp = cmd->c_name; |
725 | |
726 | debugmsg(DM_CALL, "dodcolon()"); |
727 | |
728 | if (files == NULL) { |
729 | error("No files to be updated for target \"%s\"", |
730 | cmd->c_label); |
731 | return; |
732 | } |
733 | if (stat(stamp, &stb) == -1) { |
734 | error("%s: stat failed: %s", stamp, SYSERR); |
735 | return; |
736 | } |
737 | |
738 | debugmsg(DM_MISC, "%s: mtime %lld\n", stamp, (long long)stb.st_mtime); |
739 | |
740 | env = NULL; |
741 | for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { |
742 | if (sc->sc_type == CMDSPECIAL) { |
743 | env = xmalloc(sizeof(E_FILES) + 3); |
744 | (void) snprintf(env, sizeof(E_FILES) + 3, |
745 | "%s='", E_FILES); |
746 | break; |
747 | } |
748 | } |
749 | |
750 | subcmds = sbcmds; |
751 | filelist = files; |
752 | |
753 | lastmod = stb.st_mtime; |
754 | if (!nflag && !IS_ON(options, DO_VERIFY)) |
755 | |
756 | |
757 | |
758 | (void) setfiletime(stamp, (time_t) 0, (time_t) 0); |
759 | |
760 | for (f = files; f != NULL; f = f->n_next) { |
761 | if (filev) { |
762 | for (cpp = filev; *cpp; cpp++) |
763 | if (strcmp(f->n_name, *cpp) == 0) |
764 | goto found; |
765 | continue; |
766 | } |
767 | found: |
768 | ptarget = NULL; |
769 | cmptime(f->n_name, sbcmds, &env); |
770 | } |
771 | |
772 | for (sc = sbcmds; sc != NULL; sc = sc->sc_next) { |
773 | if (sc->sc_type == NOTIFY) |
774 | notify(NULL, sc->sc_args, (time_t)lastmod); |
775 | else if (sc->sc_type == CMDSPECIAL && env) { |
776 | size_t len = strlen(env); |
777 | if (env[len - 1] == ':') |
778 | env[--len] = CNULL; |
779 | len += 2 + strlen(sc->sc_name) + 1; |
780 | env = xrealloc(env, len); |
781 | (void) strlcat(env, "';", len); |
782 | (void) strlcat(env, sc->sc_name, len); |
783 | message(MT_CHANGE, "cmdspecial \"%s\"", env); |
784 | if (!nflag && IS_OFF(options, DO_VERIFY)) |
785 | runcommand(env); |
786 | (void) free(env); |
787 | env = NULL; |
788 | } |
789 | } |
790 | if (!nflag && !IS_ON(options, DO_VERIFY) && (cp = getnotifyfile())) |
791 | (void) unlink(cp); |
792 | } |
793 | |
794 | |
795 | |
796 | |
797 | int |
798 | except(char *file) |
799 | { |
800 | struct subcmd *sc; |
801 | struct namelist *nl; |
802 | |
803 | debugmsg(DM_CALL, "except(%s)", file); |
804 | |
805 | for (sc = subcmds; sc != NULL; sc = sc->sc_next) { |
806 | if (sc->sc_type == EXCEPT) { |
807 | for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) |
808 | if (strcmp(file, nl->n_name) == 0) |
809 | return(1); |
810 | continue; |
811 | } |
812 | if (sc->sc_type == PATTERN) { |
813 | for (nl = sc->sc_args; nl != NULL; nl = nl->n_next) { |
814 | char ebuf[BUFSIZ]; |
815 | int ecode = 0; |
816 | |
817 | |
818 | if (nl->n_regex == NULL) { |
819 | nl->n_regex = xmalloc(sizeof(regex_t)); |
820 | ecode = regcomp(nl->n_regex, nl->n_name, |
821 | REG_NOSUB); |
822 | } |
823 | if (ecode == 0) { |
824 | ecode = regexec(nl->n_regex, file, 0, |
825 | NULL, 0); |
826 | } |
827 | switch (ecode) { |
828 | case REG_NOMATCH: |
829 | break; |
830 | case 0: |
831 | return(1); |
832 | default: |
833 | regerror(ecode, nl->n_regex, ebuf, |
834 | sizeof(ebuf)); |
835 | error("Regex error \"%s\" for \"%s\".", |
836 | ebuf, nl->n_name); |
837 | return(0); |
838 | } |
839 | } |
840 | } |
841 | } |
842 | return(0); |
843 | } |
844 | |
845 | |
846 | |
847 | |
848 | static void |
849 | docmdhost(struct cmd *cmd, char **filev) |
850 | { |
851 | checkcmd(cmd); |
852 | |
853 | |
854 | |
855 | |
856 | |
857 | if (do_fork && !amchild) { |
| |
858 | pid_t pid; |
859 | |
860 | |
861 | |
862 | |
863 | |
864 | while (activechildren >= maxchildren) |
| 22 | | Assuming 'activechildren' is < 'maxchildren' | |
|
| 23 | | Loop condition is false. Execution continues on line 867 | |
|
865 | waitup(); |
866 | |
867 | pid = spawn(cmd, cmds); |
| 24 | | Value assigned to field 'c_name' | |
|
868 | if (pid == 0) |
| 25 | | Assuming 'pid' is equal to 0 | |
|
| |
869 | |
870 | amchild = 1; |
871 | else |
872 | |
873 | return; |
874 | } |
875 | |
876 | |
877 | |
878 | |
879 | if (cmd->c_flags & CMD_NOCHKNFS) |
| 27 | | Assuming the condition is false | |
|
| |
880 | FLAG_OFF(options, DO_CHKNFS); |
881 | |
882 | if (!nflag) { |
| |
883 | currenthost = (cmd->c_name) ? cmd->c_name : "<unknown>"; |
| |
| 31 | | Assuming field 'c_name' is null | |
|
| |
884 | setproctitle("update %s", currenthost); |
885 | } |
886 | |
887 | switch (cmd->c_type) { |
| 33 | | Control jumps to 'case 1:' at line 888 | |
|
888 | case ARROW: |
889 | doarrow(cmd, filev); |
| |
890 | break; |
891 | case DCOLON: |
892 | dodcolon(cmd, filev); |
893 | break; |
894 | default: |
895 | fatalerr("illegal command type %d", cmd->c_type); |
896 | } |
897 | } |
898 | |
899 | |
900 | |
901 | |
902 | static void |
903 | docmd(struct cmd *cmd, int argc, char **argv) |
904 | { |
905 | struct namelist *f; |
906 | int i; |
907 | |
908 | if (argc) { |
| |
| |
909 | for (i = 0; i < argc; i++) { |
910 | if (cmd->c_label != NULL && |
911 | strcmp(cmd->c_label, argv[i]) == 0) { |
912 | docmdhost(cmd, NULL); |
913 | return; |
914 | } |
915 | for (f = cmd->c_files; f != NULL; f = f->n_next) |
916 | if (strcmp(f->n_name, argv[i]) == 0) { |
917 | docmdhost(cmd, &argv[i]); |
918 | return; |
919 | } |
920 | } |
921 | } else |
922 | docmdhost(cmd, NULL); |
| |
923 | } |
924 | |
925 | |
926 | |
927 | |
928 | |
929 | |
930 | |
931 | |
932 | |
933 | |
934 | |
935 | |
936 | |
937 | |
938 | |
939 | |
940 | |
941 | |
942 | |
943 | |
944 | void |
945 | docmds(struct namelist *hostlist, int argc, char **argv) |
946 | { |
947 | struct cmd *c; |
948 | char *cp; |
949 | int i; |
950 | |
951 | (void) signal(SIGHUP, sighandler); |
952 | (void) signal(SIGINT, sighandler); |
953 | (void) signal(SIGQUIT, sighandler); |
954 | (void) signal(SIGTERM, sighandler); |
955 | |
956 | if (!nflag) |
| 1 | Assuming 'nflag' is not equal to 0 | |
|
| |
957 | setvbuf(stdout, NULL, _IOLBF, 0); |
958 | |
959 | |
960 | |
961 | |
962 | |
963 | for (i = 0; i < argc; i++) { |
| 3 | | Assuming 'i' is >= 'argc' | |
|
| 4 | | Loop condition is false. Execution continues on line 977 | |
|
964 | int found; |
965 | |
966 | for (found = FALSE, c = cmds; c != NULL; c = c->c_next) { |
967 | if (c->c_label && argv[i] && |
968 | strcmp(c->c_label, argv[i]) == 0) { |
969 | found = TRUE; |
970 | break; |
971 | } |
972 | } |
973 | if (!found) |
974 | error("Label \"%s\" is not defined in the distfile.", |
975 | argv[i]); |
976 | } |
977 | if (nerrs) |
| |
| |
978 | return; |
979 | |
980 | |
981 | |
982 | |
983 | for (c = cmds; c != NULL; c = c->c_next) { |
| 7 | | Assuming 'c' is not equal to NULL | |
|
| 8 | | Loop condition is true. Entering loop body | |
|
984 | checkcmd(c); |
985 | if (do_fork) { |
| 9 | | Assuming 'do_fork' is not equal to 0 | |
|
| |
986 | |
987 | |
988 | |
989 | if (amchild) { |
| 11 | | Assuming 'amchild' is 0 | |
|
| |
990 | if (strcmp(c->c_name, currenthost) != 0) |
991 | continue; |
992 | } else if (c->c_flags & CMD_ASSIGNED) { |
| 13 | | Assuming the condition is false | |
|
| |
993 | |
994 | debugmsg(DM_MISC, "prev assigned: %s\n", |
995 | c->c_name); |
996 | continue; |
997 | } |
998 | } |
999 | |
1000 | if (hostlist) { |
| 15 | | Assuming 'hostlist' is null | |
|
| |
1001 | |
1002 | struct namelist *nlptr; |
1003 | |
1004 | for (nlptr = hostlist; nlptr; nlptr = nlptr->n_next) |
1005 | |
1006 | |
1007 | |
1008 | |
1009 | if ((strcmp(c->c_name, nlptr->n_name) == 0) || |
1010 | ((cp = strchr(c->c_name, '@')) && |
1011 | strcmp(++cp, nlptr->n_name) == 0)) |
1012 | docmd(c, argc, argv); |
1013 | continue; |
1014 | } else |
1015 | |
1016 | docmd(c, argc, argv); |
| |
1017 | } |
1018 | |
1019 | if (do_fork) { |
1020 | |
1021 | |
1022 | |
1023 | |
1024 | if (amchild) { |
1025 | if (!IS_ON(options, DO_QUIET)) |
1026 | message(MT_VERBOSE, "updating of %s finished", |
1027 | currenthost); |
1028 | closeconn(); |
1029 | cleanup(0); |
1030 | exit(nerrs); |
1031 | } |
1032 | |
1033 | |
1034 | |
1035 | |
1036 | while (activechildren > 0) { |
1037 | debugmsg(DM_MISC, |
1038 | "Waiting for %d children to finish.\n", |
1039 | activechildren); |
1040 | waitup(); |
1041 | } |
1042 | } else if (!nflag) { |
1043 | |
1044 | |
1045 | |
1046 | closeconn(); |
1047 | cleanup(0); |
1048 | } |
1049 | } |