Annotation of src/usr.bin/make/meta.c, Revision 1.43
1.43 ! christos 1: /* $NetBSD: meta.c,v 1.42 2016/01/17 15:30:23 christos Exp $ */
1.15 sjg 2:
1.1 sjg 3: /*
4: * Implement 'meta' mode.
5: * Adapted from John Birrell's patches to FreeBSD make.
6: * --sjg
7: */
8: /*
9: * Copyright (c) 2009-2010, Juniper Networks, Inc.
10: * Portions Copyright (c) 2009, John Birrell.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: */
1.3 sjg 33: #if defined(USE_META)
1.1 sjg 34:
35: #ifdef HAVE_CONFIG_H
36: # include "config.h"
37: #endif
38: #include <sys/stat.h>
39: #include <sys/ioctl.h>
40: #include <libgen.h>
41: #include <errno.h>
1.2 sjg 42: #if !defined(HAVE_CONFIG_H) || defined(HAVE_ERR_H)
1.1 sjg 43: #include <err.h>
1.2 sjg 44: #endif
1.1 sjg 45:
46: #include "make.h"
47: #include "job.h"
48:
49: #ifdef HAVE_FILEMON_H
50: # include <filemon.h>
51: #endif
52: #if !defined(USE_FILEMON) && defined(FILEMON_SET_FD)
53: # define USE_FILEMON
54: #endif
55:
56: static BuildMon Mybm; /* for compat */
1.32 sjg 57: static Lst metaBailiwick; /* our scope of control */
58: static Lst metaIgnorePaths; /* paths we deliberately ignore */
59:
60: #ifndef MAKE_META_IGNORE_PATHS
61: #define MAKE_META_IGNORE_PATHS ".MAKE.META.IGNORE_PATHS"
62: #endif
1.1 sjg 63:
64: Boolean useMeta = FALSE;
65: static Boolean useFilemon = FALSE;
66: static Boolean writeMeta = FALSE;
67: static Boolean metaEnv = FALSE; /* don't save env unless asked */
68: static Boolean metaVerbose = FALSE;
69: static Boolean metaIgnoreCMDs = FALSE; /* ignore CMDs in .meta files */
1.12 sjg 70: static Boolean metaCurdirOk = FALSE; /* write .meta in .CURDIR Ok? */
1.22 sjg 71: static Boolean metaSilent = FALSE; /* if we have a .meta be SILENT */
1.1 sjg 72:
73: extern Boolean forceJobs;
74: extern Boolean comatMake;
1.25 sjg 75: extern char **environ;
1.1 sjg 76:
77: #define MAKE_META_PREFIX ".MAKE.META.PREFIX"
78:
79: #ifndef N2U
80: # define N2U(n, u) (((n) + ((u) - 1)) / (u))
81: #endif
82: #ifndef ROUNDUP
83: # define ROUNDUP(n, u) (N2U((n), (u)) * (u))
84: #endif
85:
1.2 sjg 86: #if !defined(HAVE_STRSEP)
87: # define strsep(s, d) stresep((s), (d), 0)
88: #endif
89:
1.1 sjg 90: /*
91: * Filemon is a kernel module which snoops certain syscalls.
92: *
93: * C chdir
94: * E exec
95: * F [v]fork
96: * L [sym]link
97: * M rename
98: * R read
99: * W write
100: * S stat
101: *
102: * See meta_oodate below - we mainly care about 'E' and 'R'.
103: *
104: * We can still use meta mode without filemon, but
105: * the benefits are more limited.
106: */
107: #ifdef USE_FILEMON
108: # ifndef _PATH_FILEMON
109: # define _PATH_FILEMON "/dev/filemon"
110: # endif
111:
112: /*
113: * Open the filemon device.
114: */
115: static void
116: filemon_open(BuildMon *pbm)
117: {
118: int retry;
119:
120: pbm->mon_fd = pbm->filemon_fd = -1;
121: if (!useFilemon)
122: return;
123:
124: for (retry = 5; retry >= 0; retry--) {
125: if ((pbm->filemon_fd = open(_PATH_FILEMON, O_RDWR)) >= 0)
126: break;
127: }
128:
129: if (pbm->filemon_fd < 0) {
130: useFilemon = FALSE;
131: warn("Could not open %s", _PATH_FILEMON);
132: return;
133: }
134:
135: /*
136: * We use a file outside of '.'
137: * to avoid a FreeBSD kernel bug where unlink invalidates
138: * cwd causing getcwd to do a lot more work.
139: * We only care about the descriptor.
140: */
141: pbm->mon_fd = mkTempFile("filemon.XXXXXX", NULL);
142: if (ioctl(pbm->filemon_fd, FILEMON_SET_FD, &pbm->mon_fd) < 0) {
143: err(1, "Could not set filemon file descriptor!");
144: }
145: /* we don't need these once we exec */
1.42 christos 146: (void)fcntl(pbm->mon_fd, F_SETFD, FD_CLOEXEC);
147: (void)fcntl(pbm->filemon_fd, F_SETFD, FD_CLOEXEC);
1.1 sjg 148: }
149:
150: /*
151: * Read the build monitor output file and write records to the target's
152: * metadata file.
153: */
154: static void
155: filemon_read(FILE *mfp, int fd)
156: {
157: char buf[BUFSIZ];
1.35 sjg 158: int n;
1.1 sjg 159:
160: /* Check if we're not writing to a meta data file.*/
161: if (mfp == NULL) {
162: if (fd >= 0)
163: close(fd); /* not interested */
164: return;
165: }
166: /* rewind */
1.24 christos 167: (void)lseek(fd, (off_t)0, SEEK_SET);
1.1 sjg 168:
1.36 sjg 169: fprintf(mfp, "\n-- filemon acquired metadata --\n");
1.1 sjg 170:
1.35 sjg 171: while ((n = read(fd, buf, sizeof(buf))) > 0) {
172: fwrite(buf, 1, n, mfp);
1.1 sjg 173: }
174: fflush(mfp);
1.35 sjg 175: close(fd);
1.1 sjg 176: }
177: #endif
178:
1.8 sjg 179: /*
180: * when realpath() fails,
181: * we use this, to clean up ./ and ../
182: */
183: static void
184: eat_dots(char *buf, size_t bufsz, int dots)
185: {
186: char *cp;
187: char *cp2;
188: const char *eat;
189: size_t eatlen;
190:
191: switch (dots) {
192: case 1:
193: eat = "/./";
194: eatlen = 2;
195: break;
196: case 2:
197: eat = "/../";
198: eatlen = 3;
199: break;
200: default:
201: return;
202: }
203:
204: do {
205: cp = strstr(buf, eat);
206: if (cp) {
207: cp2 = cp + eatlen;
208: if (dots == 2 && cp > buf) {
209: do {
210: cp--;
211: } while (cp > buf && *cp != '/');
212: }
213: if (*cp == '/') {
214: strlcpy(cp, cp2, bufsz - (cp - buf));
215: } else {
216: return; /* can't happen? */
217: }
218: }
219: } while (cp);
220: }
221:
1.1 sjg 222: static char *
223: meta_name(struct GNode *gn, char *mname, size_t mnamelen,
224: const char *dname,
225: const char *tname)
226: {
227: char buf[MAXPATHLEN];
228: char cwd[MAXPATHLEN];
229: char *rp;
230: char *cp;
231: char *tp;
232: char *p[4]; /* >= number of possible uses */
233: int i;
234:
235: i = 0;
236: if (!dname)
237: dname = Var_Value(".OBJDIR", gn, &p[i++]);
238: if (!tname)
239: tname = Var_Value(TARGET, gn, &p[i++]);
240:
1.8 sjg 241: if (realpath(dname, cwd))
242: dname = cwd;
243:
1.1 sjg 244: /*
245: * Weed out relative paths from the target file name.
246: * We have to be careful though since if target is a
247: * symlink, the result will be unstable.
248: * So we use realpath() just to get the dirname, and leave the
249: * basename as given to us.
250: */
251: if ((cp = strrchr(tname, '/'))) {
252: if (realpath(tname, buf)) {
253: if ((rp = strrchr(buf, '/'))) {
254: rp++;
255: cp++;
256: if (strcmp(cp, rp) != 0)
257: strlcpy(rp, cp, sizeof(buf) - (rp - buf));
258: }
259: tname = buf;
1.8 sjg 260: } else {
261: /*
262: * We likely have a directory which is about to be made.
263: * We pretend realpath() succeeded, to have a chance
264: * of generating the same meta file name that we will
265: * next time through.
266: */
267: if (tname[0] == '/') {
268: strlcpy(buf, tname, sizeof(buf));
269: } else {
270: snprintf(buf, sizeof(buf), "%s/%s", cwd, tname);
271: }
272: eat_dots(buf, sizeof(buf), 1); /* ./ */
273: eat_dots(buf, sizeof(buf), 2); /* ../ */
274: tname = buf;
1.1 sjg 275: }
276: }
277: /* on some systems dirname may modify its arg */
278: tp = bmake_strdup(tname);
279: if (strcmp(dname, dirname(tp)) == 0)
280: snprintf(mname, mnamelen, "%s.meta", tname);
281: else {
282: snprintf(mname, mnamelen, "%s/%s.meta", dname, tname);
283:
284: /*
285: * Replace path separators in the file name after the
286: * current object directory path.
287: */
288: cp = mname + strlen(dname) + 1;
289:
290: while (*cp != '\0') {
291: if (*cp == '/')
292: *cp = '_';
293: cp++;
294: }
295: }
296: free(tp);
297: for (i--; i >= 0; i--) {
298: if (p[i])
299: free(p[i]);
300: }
301: return (mname);
302: }
303:
304: /*
305: * Return true if running ${.MAKE}
306: * Bypassed if target is flagged .MAKE
307: */
308: static int
309: is_submake(void *cmdp, void *gnp)
310: {
311: static char *p_make = NULL;
312: static int p_len;
313: char *cmd = cmdp;
314: GNode *gn = gnp;
315: char *mp = NULL;
316: char *cp;
317: char *cp2;
318: int rc = 0; /* keep looking */
319:
320: if (!p_make) {
321: p_make = Var_Value(".MAKE", gn, &cp);
322: p_len = strlen(p_make);
323: }
324: cp = strchr(cmd, '$');
325: if ((cp)) {
1.40 sjg 326: mp = Var_Subst(NULL, cmd, gn, FALSE, TRUE);
1.1 sjg 327: cmd = mp;
328: }
329: cp2 = strstr(cmd, p_make);
330: if ((cp2)) {
331: switch (cp2[p_len]) {
332: case '\0':
333: case ' ':
334: case '\t':
335: case '\n':
336: rc = 1;
337: break;
338: }
339: if (cp2 > cmd && rc > 0) {
340: switch (cp2[-1]) {
341: case ' ':
342: case '\t':
343: case '\n':
344: break;
345: default:
346: rc = 0; /* no match */
347: break;
348: }
349: }
350: }
351: if (mp)
352: free(mp);
353: return (rc);
354: }
355:
356: typedef struct meta_file_s {
357: FILE *fp;
358: GNode *gn;
359: } meta_file_t;
360:
361: static int
362: printCMD(void *cmdp, void *mfpp)
363: {
364: meta_file_t *mfp = mfpp;
365: char *cmd = cmdp;
366: char *cp = NULL;
367:
368: if (strchr(cmd, '$')) {
1.40 sjg 369: cmd = cp = Var_Subst(NULL, cmd, mfp->gn, FALSE, TRUE);
1.1 sjg 370: }
371: fprintf(mfp->fp, "CMD %s\n", cmd);
372: if (cp)
373: free(cp);
374: return 0;
375: }
376:
377: /*
378: * Certain node types never get a .meta file
379: */
380: #define SKIP_META_TYPE(_type) do { \
381: if ((gn->type & __CONCAT(OP_, _type))) { \
382: if (DEBUG(META)) { \
383: fprintf(debug_file, "Skipping meta for %s: .%s\n", \
384: gn->name, __STRING(_type)); \
385: } \
386: return (NULL); \
387: } \
388: } while (0)
389:
390: static FILE *
391: meta_create(BuildMon *pbm, GNode *gn)
392: {
393: meta_file_t mf;
394: char buf[MAXPATHLEN];
395: char objdir[MAXPATHLEN];
396: char **ptr;
397: const char *dname;
398: const char *tname;
399: char *fname;
400: const char *cp;
401: char *p[4]; /* >= possible uses */
402: int i;
403: struct stat fs;
404:
405:
406: /* This may be a phony node which we don't want meta data for... */
407: /* Skip .meta for .BEGIN, .END, .ERROR etc as well. */
408: /* Or it may be explicitly flagged as .NOMETA */
409: SKIP_META_TYPE(NOMETA);
410: /* Unless it is explicitly flagged as .META */
411: if (!(gn->type & OP_META)) {
412: SKIP_META_TYPE(PHONY);
413: SKIP_META_TYPE(SPECIAL);
414: SKIP_META_TYPE(MAKE);
415: }
416:
417: mf.fp = NULL;
418:
419: i = 0;
420:
421: dname = Var_Value(".OBJDIR", gn, &p[i++]);
422: tname = Var_Value(TARGET, gn, &p[i++]);
423:
424: /* The object directory may not exist. Check it.. */
425: if (stat(dname, &fs) != 0) {
426: if (DEBUG(META))
427: fprintf(debug_file, "Skipping meta for %s: no .OBJDIR\n",
428: gn->name);
429: goto out;
430: }
431: /* Check if there are no commands to execute. */
432: if (Lst_IsEmpty(gn->commands)) {
433: if (DEBUG(META))
434: fprintf(debug_file, "Skipping meta for %s: no commands\n",
435: gn->name);
436: goto out;
437: }
438:
439: /* make sure these are canonical */
440: if (realpath(dname, objdir))
441: dname = objdir;
442:
443: /* If we aren't in the object directory, don't create a meta file. */
1.12 sjg 444: if (!metaCurdirOk && strcmp(curdir, dname) == 0) {
1.1 sjg 445: if (DEBUG(META))
446: fprintf(debug_file, "Skipping meta for %s: .OBJDIR == .CURDIR\n",
447: gn->name);
448: goto out;
449: }
450: if (!(gn->type & OP_META)) {
451: /* We do not generate .meta files for sub-makes */
452: if (Lst_ForEach(gn->commands, is_submake, gn)) {
453: if (DEBUG(META))
454: fprintf(debug_file, "Skipping meta for %s: .MAKE\n",
455: gn->name);
456: goto out;
457: }
458: }
459:
460: if (metaVerbose) {
461: char *mp;
462:
463: /* Describe the target we are building */
1.40 sjg 464: mp = Var_Subst(NULL, "${" MAKE_META_PREFIX "}", gn, FALSE, TRUE);
1.1 sjg 465: if (*mp)
466: fprintf(stdout, "%s\n", mp);
467: free(mp);
468: }
469: /* Get the basename of the target */
470: if ((cp = strrchr(tname, '/')) == NULL) {
471: cp = tname;
472: } else {
473: cp++;
474: }
475:
476: fflush(stdout);
477:
478: if (strcmp(cp, makeDependfile) == 0)
479: goto out;
480:
481: if (!writeMeta)
482: /* Don't create meta data. */
483: goto out;
484:
485: fname = meta_name(gn, pbm->meta_fname, sizeof(pbm->meta_fname),
486: dname, tname);
487:
1.8 sjg 488: #ifdef DEBUG_META_MODE
489: if (DEBUG(META))
490: fprintf(debug_file, "meta_create: %s\n", fname);
491: #endif
492:
1.1 sjg 493: if ((mf.fp = fopen(fname, "w")) == NULL)
494: err(1, "Could not open meta file '%s'", fname);
495:
496: fprintf(mf.fp, "# Meta data file %s\n", fname);
497:
498: mf.gn = gn;
499:
500: Lst_ForEach(gn->commands, printCMD, &mf);
501:
502: fprintf(mf.fp, "CWD %s\n", getcwd(buf, sizeof(buf)));
503: fprintf(mf.fp, "TARGET %s\n", tname);
504:
505: if (metaEnv) {
506: for (ptr = environ; *ptr != NULL; ptr++)
507: fprintf(mf.fp, "ENV %s\n", *ptr);
508: }
509:
510: fprintf(mf.fp, "-- command output --\n");
511: fflush(mf.fp);
512:
513: Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
514: Var_Append(".MAKE.META.CREATED", fname, VAR_GLOBAL);
1.22 sjg 515:
516: gn->type |= OP_META; /* in case anyone wants to know */
517: if (metaSilent) {
518: gn->type |= OP_SILENT;
519: }
1.1 sjg 520: out:
521: for (i--; i >= 0; i--) {
522: if (p[i])
523: free(p[i]);
524: }
525:
526: return (mf.fp);
527: }
528:
1.12 sjg 529: static Boolean
530: boolValue(char *s)
531: {
532: switch(*s) {
533: case '0':
534: case 'N':
535: case 'n':
536: case 'F':
537: case 'f':
538: return FALSE;
539: }
540: return TRUE;
541: }
1.1 sjg 542:
1.27 sjg 543: /*
544: * Initialization we need before reading makefiles.
545: */
546: void
1.30 sjg 547: meta_init(void)
1.27 sjg 548: {
549: #ifdef USE_FILEMON
550: /* this allows makefiles to test if we have filemon support */
551: Var_Set(".MAKE.PATH_FILEMON", _PATH_FILEMON, VAR_GLOBAL, 0);
552: #endif
553: }
554:
555:
556: /*
557: * Initialization we need after reading makefiles.
558: */
1.1 sjg 559: void
1.27 sjg 560: meta_mode_init(const char *make_mode)
1.1 sjg 561: {
562: static int once = 0;
1.12 sjg 563: char *cp;
1.1 sjg 564:
565: useMeta = TRUE;
566: useFilemon = TRUE;
567: writeMeta = TRUE;
568:
569: if (make_mode) {
570: if (strstr(make_mode, "env"))
571: metaEnv = TRUE;
572: if (strstr(make_mode, "verb"))
573: metaVerbose = TRUE;
574: if (strstr(make_mode, "read"))
575: writeMeta = FALSE;
576: if (strstr(make_mode, "nofilemon"))
577: useFilemon = FALSE;
1.13 sjg 578: if ((cp = strstr(make_mode, "curdirok="))) {
579: metaCurdirOk = boolValue(&cp[9]);
1.12 sjg 580: }
1.22 sjg 581: if ((cp = strstr(make_mode, "silent="))) {
582: metaSilent = boolValue(&cp[7]);
583: }
1.1 sjg 584: if (strstr(make_mode, "ignore-cmd"))
585: metaIgnoreCMDs = TRUE;
586: /* for backwards compatability */
587: Var_Set(".MAKE.META_CREATED", "${.MAKE.META.CREATED}", VAR_GLOBAL, 0);
588: Var_Set(".MAKE.META_FILES", "${.MAKE.META.FILES}", VAR_GLOBAL, 0);
589: }
590: if (metaVerbose && !Var_Exists(MAKE_META_PREFIX, VAR_GLOBAL)) {
591: /*
592: * The default value for MAKE_META_PREFIX
593: * prints the absolute path of the target.
594: * This works be cause :H will generate '.' if there is no /
595: * and :tA will resolve that to cwd.
596: */
597: Var_Set(MAKE_META_PREFIX, "Building ${.TARGET:H:tA}/${.TARGET:T}", VAR_GLOBAL, 0);
598: }
599: if (once)
600: return;
601: once = 1;
602: memset(&Mybm, 0, sizeof(Mybm));
1.17 sjg 603: /*
604: * We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
605: */
606: metaBailiwick = Lst_Init(FALSE);
1.40 sjg 607: cp = Var_Subst(NULL, "${.MAKE.META.BAILIWICK:O:u:tA}", VAR_GLOBAL,
608: FALSE, TRUE);
1.17 sjg 609: if (cp) {
610: str2Lst_Append(metaBailiwick, cp, NULL);
611: }
1.32 sjg 612: /*
613: * We ignore any paths that start with ${.MAKE.META.IGNORE_PATHS}
614: */
615: metaIgnorePaths = Lst_Init(FALSE);
616: Var_Append(MAKE_META_IGNORE_PATHS,
617: "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}", VAR_GLOBAL);
618: cp = Var_Subst(NULL,
1.40 sjg 619: "${" MAKE_META_IGNORE_PATHS ":O:u:tA}", VAR_GLOBAL,
620: FALSE, TRUE);
1.32 sjg 621: if (cp) {
622: str2Lst_Append(metaIgnorePaths, cp, NULL);
623: }
1.1 sjg 624: }
625:
626: /*
627: * In each case below we allow for job==NULL
628: */
629: void
630: meta_job_start(Job *job, GNode *gn)
631: {
632: BuildMon *pbm;
633:
634: if (job != NULL) {
635: pbm = &job->bm;
636: } else {
637: pbm = &Mybm;
638: }
639: pbm->mfp = meta_create(pbm, gn);
640: #ifdef USE_FILEMON_ONCE
641: /* compat mode we open the filemon dev once per command */
642: if (job == NULL)
643: return;
644: #endif
645: #ifdef USE_FILEMON
646: if (pbm->mfp != NULL && useFilemon) {
647: filemon_open(pbm);
648: } else {
649: pbm->mon_fd = pbm->filemon_fd = -1;
650: }
651: #endif
652: }
653:
654: /*
655: * The child calls this before doing anything.
656: * It does not disturb our state.
657: */
658: void
659: meta_job_child(Job *job)
660: {
661: #ifdef USE_FILEMON
662: BuildMon *pbm;
663:
664: if (job != NULL) {
665: pbm = &job->bm;
666: } else {
667: pbm = &Mybm;
668: }
1.37 sjg 669: if (pbm->mfp != NULL) {
670: close(fileno(pbm->mfp));
671: if (useFilemon) {
672: pid_t pid;
673:
674: pid = getpid();
675: if (ioctl(pbm->filemon_fd, FILEMON_SET_PID, &pid) < 0) {
676: err(1, "Could not set filemon pid!");
677: }
1.1 sjg 678: }
679: }
680: #endif
681: }
682:
683: void
684: meta_job_error(Job *job, GNode *gn, int flags, int status)
685: {
686: char cwd[MAXPATHLEN];
687: BuildMon *pbm;
688:
689: if (job != NULL) {
690: pbm = &job->bm;
691: } else {
692: if (!gn)
693: gn = job->node;
694: pbm = &Mybm;
695: }
696: if (pbm->mfp != NULL) {
697: fprintf(pbm->mfp, "*** Error code %d%s\n",
698: status,
699: (flags & JOB_IGNERR) ?
700: "(ignored)" : "");
701: }
702: if (gn) {
703: Var_Set(".ERROR_TARGET", gn->path ? gn->path : gn->name, VAR_GLOBAL, 0);
704: }
705: getcwd(cwd, sizeof(cwd));
706: Var_Set(".ERROR_CWD", cwd, VAR_GLOBAL, 0);
1.6 sjg 707: if (pbm && pbm->meta_fname[0]) {
1.1 sjg 708: Var_Set(".ERROR_META_FILE", pbm->meta_fname, VAR_GLOBAL, 0);
709: }
1.16 sjg 710: meta_job_finish(job);
1.1 sjg 711: }
712:
713: void
714: meta_job_output(Job *job, char *cp, const char *nl)
715: {
716: BuildMon *pbm;
717:
718: if (job != NULL) {
719: pbm = &job->bm;
720: } else {
721: pbm = &Mybm;
722: }
723: if (pbm->mfp != NULL) {
724: if (metaVerbose) {
725: static char *meta_prefix = NULL;
726: static int meta_prefix_len;
727:
728: if (!meta_prefix) {
729: char *cp2;
730:
1.40 sjg 731: meta_prefix = Var_Subst(NULL, "${" MAKE_META_PREFIX "}",
732: VAR_GLOBAL, FALSE, TRUE);
1.1 sjg 733: if ((cp2 = strchr(meta_prefix, '$')))
734: meta_prefix_len = cp2 - meta_prefix;
735: else
736: meta_prefix_len = strlen(meta_prefix);
737: }
738: if (strncmp(cp, meta_prefix, meta_prefix_len) == 0) {
739: cp = strchr(cp+1, '\n');
740: if (!cp++)
741: return;
742: }
743: }
744: fprintf(pbm->mfp, "%s%s", cp, nl);
745: }
746: }
747:
748: void
749: meta_cmd_finish(void *pbmp)
750: {
751: #ifdef USE_FILEMON
752: BuildMon *pbm = pbmp;
753:
754: if (!pbm)
755: pbm = &Mybm;
756:
757: if (pbm->filemon_fd >= 0) {
758: close(pbm->filemon_fd);
759: filemon_read(pbm->mfp, pbm->mon_fd);
760: pbm->filemon_fd = pbm->mon_fd = -1;
761: }
762: #endif
763: }
764:
765: void
766: meta_job_finish(Job *job)
767: {
768: BuildMon *pbm;
769:
770: if (job != NULL) {
771: pbm = &job->bm;
772: } else {
773: pbm = &Mybm;
774: }
775: if (pbm->mfp != NULL) {
776: meta_cmd_finish(pbm);
777: fclose(pbm->mfp);
778: pbm->mfp = NULL;
1.6 sjg 779: pbm->meta_fname[0] = '\0';
1.1 sjg 780: }
781: }
782:
783: /*
784: * Fetch a full line from fp - growing bufp if needed
785: * Return length in bufp.
786: */
787: static int
788: fgetLine(char **bufp, size_t *szp, int o, FILE *fp)
789: {
790: char *buf = *bufp;
791: size_t bufsz = *szp;
792: struct stat fs;
793: int x;
794:
795: if (fgets(&buf[o], bufsz - o, fp) != NULL) {
796: check_newline:
797: x = o + strlen(&buf[o]);
798: if (buf[x - 1] == '\n')
799: return x;
800: /*
801: * We need to grow the buffer.
802: * The meta file can give us a clue.
803: */
804: if (fstat(fileno(fp), &fs) == 0) {
805: size_t newsz;
806: char *p;
807:
808: newsz = ROUNDUP((fs.st_size / 2), BUFSIZ);
809: if (newsz <= bufsz)
810: newsz = ROUNDUP(fs.st_size, BUFSIZ);
811: if (DEBUG(META))
1.19 sjg 812: fprintf(debug_file, "growing buffer %zu -> %zu\n",
813: bufsz, newsz);
1.1 sjg 814: p = bmake_realloc(buf, newsz);
815: if (p) {
816: *bufp = buf = p;
817: *szp = bufsz = newsz;
818: /* fetch the rest */
819: if (!fgets(&buf[x], bufsz - x, fp))
820: return x; /* truncated! */
821: goto check_newline;
822: }
823: }
824: }
825: return 0;
826: }
827:
1.17 sjg 828: static int
829: prefix_match(void *p, void *q)
830: {
831: const char *prefix = p;
832: const char *path = q;
833: size_t n = strlen(prefix);
834:
835: return (0 == strncmp(path, prefix, n));
836: }
837:
838: static int
839: string_match(const void *p, const void *q)
840: {
841: const char *p1 = p;
842: const char *p2 = q;
843:
844: return strcmp(p1, p2);
845: }
846:
847:
1.1 sjg 848: /*
849: * When running with 'meta' functionality, a target can be out-of-date
1.34 snj 850: * if any of the references in its meta data file is more recent.
1.5 sjg 851: * We have to track the latestdir on a per-process basis.
1.1 sjg 852: */
1.38 sjg 853: #define LCWD_VNAME_FMT ".meta.%d.lcwd"
1.5 sjg 854: #define LDIR_VNAME_FMT ".meta.%d.ldir"
855:
1.20 sjg 856: /*
857: * It is possible that a .meta file is corrupted,
858: * if we detect this we want to reproduce it.
859: * Setting oodate TRUE will have that effect.
860: */
861: #define CHECK_VALID_META(p) if (!(p && *p)) { \
862: warnx("%s: %d: malformed", fname, lineno); \
863: oodate = TRUE; \
864: continue; \
865: }
866:
1.33 sjg 867: #define DEQUOTE(p) if (*p == '\'') { \
868: char *ep; \
869: p++; \
870: if ((ep = strchr(p, '\''))) \
871: *ep = '\0'; \
872: }
873:
1.1 sjg 874: Boolean
875: meta_oodate(GNode *gn, Boolean oodate)
876: {
1.5 sjg 877: static char *tmpdir = NULL;
1.11 sjg 878: static char cwd[MAXPATHLEN];
1.38 sjg 879: char lcwd_vname[64];
1.5 sjg 880: char ldir_vname[64];
1.38 sjg 881: char lcwd[MAXPATHLEN];
1.1 sjg 882: char latestdir[MAXPATHLEN];
883: char fname[MAXPATHLEN];
884: char fname1[MAXPATHLEN];
1.5 sjg 885: char fname2[MAXPATHLEN];
1.38 sjg 886: char fname3[MAXPATHLEN];
1.1 sjg 887: char *p;
888: char *cp;
1.33 sjg 889: char *link_src;
890: char *move_target;
1.11 sjg 891: static size_t cwdlen = 0;
1.7 sjg 892: static size_t tmplen = 0;
1.1 sjg 893: FILE *fp;
1.26 sjg 894: Boolean needOODATE = FALSE;
1.17 sjg 895: Lst missingFiles;
896:
1.4 sjg 897: if (oodate)
898: return oodate; /* we're done */
899:
1.17 sjg 900: missingFiles = Lst_Init(FALSE);
901:
1.1 sjg 902: /*
903: * We need to check if the target is out-of-date. This includes
904: * checking if the expanded command has changed. This in turn
905: * requires that all variables are set in the same way that they
906: * would be if the target needs to be re-built.
907: */
908: Make_DoAllVar(gn);
909:
910: meta_name(gn, fname, sizeof(fname), NULL, NULL);
911:
1.8 sjg 912: #ifdef DEBUG_META_MODE
913: if (DEBUG(META))
914: fprintf(debug_file, "meta_oodate: %s\n", fname);
915: #endif
916:
1.1 sjg 917: if ((fp = fopen(fname, "r")) != NULL) {
918: static char *buf = NULL;
919: static size_t bufsz;
920: int lineno = 0;
1.5 sjg 921: int lastpid = 0;
922: int pid;
1.1 sjg 923: int f = 0;
924: int x;
925: LstNode ln;
926: struct stat fs;
927:
928: if (!buf) {
929: bufsz = 8 * BUFSIZ;
930: buf = bmake_malloc(bufsz);
931: }
1.5 sjg 932:
1.11 sjg 933: if (!cwdlen) {
934: if (getcwd(cwd, sizeof(cwd)) == NULL)
935: err(1, "Could not get current working directory");
936: cwdlen = strlen(cwd);
937: }
1.38 sjg 938: strlcpy(lcwd, cwd, sizeof(lcwd));
939: strlcpy(latestdir, cwd, sizeof(latestdir));
1.11 sjg 940:
1.5 sjg 941: if (!tmpdir) {
942: tmpdir = getTmpdir();
943: tmplen = strlen(tmpdir);
944: }
945:
1.1 sjg 946: /* we want to track all the .meta we read */
947: Var_Append(".MAKE.META.FILES", fname, VAR_GLOBAL);
948:
949: ln = Lst_First(gn->commands);
950: while (!oodate && (x = fgetLine(&buf, &bufsz, 0, fp)) > 0) {
951: lineno++;
952: if (buf[x - 1] == '\n')
953: buf[x - 1] = '\0';
1.20 sjg 954: else {
1.1 sjg 955: warnx("%s: %d: line truncated at %u", fname, lineno, x);
1.20 sjg 956: oodate = TRUE;
957: break;
958: }
1.33 sjg 959: link_src = NULL;
960: move_target = NULL;
1.1 sjg 961: /* Find the start of the build monitor section. */
962: if (!f) {
963: if (strncmp(buf, "-- filemon", 10) == 0) {
964: f = 1;
965: continue;
966: }
967: if (strncmp(buf, "# buildmon", 10) == 0) {
968: f = 1;
969: continue;
970: }
971: }
972:
973: /* Delimit the record type. */
974: p = buf;
1.7 sjg 975: #ifdef DEBUG_META_MODE
976: if (DEBUG(META))
977: fprintf(debug_file, "%s: %d: %s\n", fname, lineno, buf);
978: #endif
1.1 sjg 979: strsep(&p, " ");
980: if (f) {
1.5 sjg 981: /*
982: * We are in the 'filemon' output section.
983: * Each record from filemon follows the general form:
984: *
985: * <key> <pid> <data>
986: *
987: * Where:
988: * <key> is a single letter, denoting the syscall.
989: * <pid> is the process that made the syscall.
990: * <data> is the arguments (of interest).
991: */
992: switch(buf[0]) {
993: case '#': /* comment */
994: case 'V': /* version */
995: break;
996: default:
997: /*
998: * We need to track pathnames per-process.
999: *
1000: * Each process run by make, starts off in the 'CWD'
1001: * recorded in the .meta file, if it chdirs ('C')
1002: * elsewhere we need to track that - but only for
1003: * that process. If it forks ('F'), we initialize
1004: * the child to have the same cwd as its parent.
1005: *
1006: * We also need to track the 'latestdir' of
1007: * interest. This is usually the same as cwd, but
1008: * not if a process is reading directories.
1009: *
1010: * Each time we spot a different process ('pid')
1011: * we save the current value of 'latestdir' in a
1012: * variable qualified by 'lastpid', and
1013: * re-initialize 'latestdir' to any pre-saved
1014: * value for the current 'pid' and 'CWD' if none.
1015: */
1.20 sjg 1016: CHECK_VALID_META(p);
1.5 sjg 1017: pid = atoi(p);
1018: if (pid > 0 && pid != lastpid) {
1019: char *ldir;
1020: char *tp;
1021:
1022: if (lastpid > 0) {
1.38 sjg 1023: /* We need to remember these. */
1024: Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
1.5 sjg 1025: Var_Set(ldir_vname, latestdir, VAR_GLOBAL, 0);
1026: }
1.38 sjg 1027: snprintf(lcwd_vname, sizeof(lcwd_vname), LCWD_VNAME_FMT, pid);
1.5 sjg 1028: snprintf(ldir_vname, sizeof(ldir_vname), LDIR_VNAME_FMT, pid);
1029: lastpid = pid;
1030: ldir = Var_Value(ldir_vname, VAR_GLOBAL, &tp);
1031: if (ldir) {
1032: strlcpy(latestdir, ldir, sizeof(latestdir));
1033: if (tp)
1034: free(tp);
1.38 sjg 1035: }
1036: ldir = Var_Value(lcwd_vname, VAR_GLOBAL, &tp);
1037: if (ldir) {
1038: strlcpy(lcwd, ldir, sizeof(lcwd));
1039: if (tp)
1040: free(tp);
1041: }
1.5 sjg 1042: }
1043: /* Skip past the pid. */
1044: if (strsep(&p, " ") == NULL)
1045: continue;
1.7 sjg 1046: #ifdef DEBUG_META_MODE
1047: if (DEBUG(META))
1.38 sjg 1048: fprintf(debug_file, "%s: %d: %d: %c: cwd=%s lcwd=%s ldir=%s\n",
1049: fname, lineno,
1050: pid, buf[0], cwd, lcwd, latestdir);
1.7 sjg 1051: #endif
1.5 sjg 1052: break;
1053: }
1054:
1.20 sjg 1055: CHECK_VALID_META(p);
1056:
1.1 sjg 1057: /* Process according to record type. */
1058: switch (buf[0]) {
1.5 sjg 1059: case 'X': /* eXit */
1.38 sjg 1060: Var_Delete(lcwd_vname, VAR_GLOBAL);
1.5 sjg 1061: Var_Delete(ldir_vname, VAR_GLOBAL);
1062: lastpid = 0; /* no need to save ldir_vname */
1063: break;
1064:
1065: case 'F': /* [v]Fork */
1066: {
1067: char cldir[64];
1068: int child;
1069:
1070: child = atoi(p);
1071: if (child > 0) {
1.38 sjg 1072: snprintf(cldir, sizeof(cldir), LCWD_VNAME_FMT, child);
1073: Var_Set(cldir, lcwd, VAR_GLOBAL, 0);
1.5 sjg 1074: snprintf(cldir, sizeof(cldir), LDIR_VNAME_FMT, child);
1075: Var_Set(cldir, latestdir, VAR_GLOBAL, 0);
1.38 sjg 1076: #ifdef DEBUG_META_MODE
1077: if (DEBUG(META))
1078: fprintf(debug_file, "%s: %d: %d: cwd=%s lcwd=%s ldir=%s\n",
1079: fname, lineno,
1080: child, cwd, lcwd, latestdir);
1081: #endif
1.5 sjg 1082: }
1083: }
1084: break;
1.1 sjg 1085:
1.5 sjg 1086: case 'C': /* Chdir */
1.38 sjg 1087: /* Update lcwd and latest directory. */
1088: strlcpy(latestdir, p, sizeof(latestdir));
1089: strlcpy(lcwd, p, sizeof(lcwd));
1090: Var_Set(lcwd_vname, lcwd, VAR_GLOBAL, 0);
1091: Var_Set(ldir_vname, lcwd, VAR_GLOBAL, 0);
1092: #ifdef DEBUG_META_MODE
1093: if (DEBUG(META))
1094: fprintf(debug_file, "%s: %d: cwd=%s ldir=%s\n", fname, lineno, cwd, lcwd);
1095: #endif
1.1 sjg 1096: break;
1097:
1.17 sjg 1098: case 'M': /* renaMe */
1.33 sjg 1099: /*
1100: * For 'M'oves we want to check
1101: * the src as for 'R'ead
1102: * and the target as for 'W'rite.
1103: */
1104: cp = p; /* save this for a second */
1105: /* now get target */
1106: if (strsep(&p, " ") == NULL)
1107: continue;
1108: CHECK_VALID_META(p);
1109: move_target = p;
1110: p = cp;
1.17 sjg 1111: /* 'L' and 'M' put single quotes around the args */
1.33 sjg 1112: DEQUOTE(p);
1113: DEQUOTE(move_target);
1.17 sjg 1114: /* FALLTHROUGH */
1115: case 'D': /* unlink */
1116: if (*p == '/' && !Lst_IsEmpty(missingFiles)) {
1117: /* remove p from the missingFiles list if present */
1118: if ((ln = Lst_Find(missingFiles, p, string_match)) != NULL) {
1119: char *tp = Lst_Datum(ln);
1120: Lst_Remove(missingFiles, ln);
1121: free(tp);
1.28 sjg 1122: ln = NULL; /* we're done with it */
1.17 sjg 1123: }
1124: }
1.33 sjg 1125: if (buf[0] == 'M') {
1126: /* the target of the mv is a file 'W'ritten */
1127: #ifdef DEBUG_META_MODE
1128: if (DEBUG(META))
1129: fprintf(debug_file, "meta_oodate: M %s -> %s\n",
1130: p, move_target);
1131: #endif
1132: p = move_target;
1133: goto check_write;
1134: }
1.17 sjg 1135: break;
1136: case 'L': /* Link */
1.33 sjg 1137: /*
1138: * For 'L'inks check
1139: * the src as for 'R'ead
1140: * and the target as for 'W'rite.
1141: */
1142: link_src = p;
1143: /* now get target */
1.17 sjg 1144: if (strsep(&p, " ") == NULL)
1145: continue;
1.20 sjg 1146: CHECK_VALID_META(p);
1.17 sjg 1147: /* 'L' and 'M' put single quotes around the args */
1.33 sjg 1148: DEQUOTE(p);
1149: DEQUOTE(link_src);
1150: #ifdef DEBUG_META_MODE
1151: if (DEBUG(META))
1152: fprintf(debug_file, "meta_oodate: L %s -> %s\n",
1153: link_src, p);
1154: #endif
1.17 sjg 1155: /* FALLTHROUGH */
1156: case 'W': /* Write */
1.33 sjg 1157: check_write:
1.17 sjg 1158: /*
1159: * If a file we generated within our bailiwick
1160: * but outside of .OBJDIR is missing,
1161: * we need to do it again.
1162: */
1163: /* ignore non-absolute paths */
1164: if (*p != '/')
1165: break;
1166:
1167: if (Lst_IsEmpty(metaBailiwick))
1168: break;
1169:
1170: /* ignore cwd - normal dependencies handle those */
1171: if (strncmp(p, cwd, cwdlen) == 0)
1172: break;
1173:
1174: if (!Lst_ForEach(metaBailiwick, prefix_match, p))
1175: break;
1176:
1177: /* tmpdir might be within */
1178: if (tmplen > 0 && strncmp(p, tmpdir, tmplen) == 0)
1179: break;
1180:
1181: /* ignore anything containing the string "tmp" */
1182: if ((strstr("tmp", p)))
1183: break;
1184:
1.41 sjg 1185: if ((link_src != NULL && lstat(p, &fs) < 0) ||
1186: (link_src == NULL && stat(p, &fs) < 0)) {
1.17 sjg 1187: Lst_AtEnd(missingFiles, bmake_strdup(p));
1188: }
1189: break;
1.33 sjg 1190: check_link_src:
1191: p = link_src;
1192: link_src = NULL;
1193: #ifdef DEBUG_META_MODE
1194: if (DEBUG(META))
1195: fprintf(debug_file, "meta_oodate: L src %s\n", p);
1196: #endif
1197: /* FALLTHROUGH */
1.5 sjg 1198: case 'R': /* Read */
1199: case 'E': /* Exec */
1.1 sjg 1200: /*
1201: * Check for runtime files that can't
1202: * be part of the dependencies because
1203: * they are _expected_ to change.
1204: */
1.32 sjg 1205: if (*p == '/' &&
1206: Lst_ForEach(metaIgnorePaths, prefix_match, p)) {
1207: #ifdef DEBUG_META_MODE
1208: if (DEBUG(META))
1209: fprintf(debug_file, "meta_oodate: ignoring: %s\n",
1210: p);
1211: #endif
1.31 sjg 1212: break;
1.32 sjg 1213: }
1.31 sjg 1214:
1.1 sjg 1215: /*
1.5 sjg 1216: * The rest of the record is the file name.
1217: * Check if it's not an absolute path.
1.1 sjg 1218: */
1.5 sjg 1219: {
1220: char *sdirs[4];
1221: char **sdp;
1222: int sdx = 0;
1223: int found = 0;
1224:
1225: if (*p == '/') {
1226: sdirs[sdx++] = p; /* done */
1227: } else {
1228: if (strcmp(".", p) == 0)
1229: continue; /* no point */
1230:
1231: /* Check vs latestdir */
1232: snprintf(fname1, sizeof(fname1), "%s/%s", latestdir, p);
1233: sdirs[sdx++] = fname1;
1234:
1.38 sjg 1235: if (strcmp(latestdir, lcwd) != 0) {
1236: /* Check vs lcwd */
1237: snprintf(fname2, sizeof(fname2), "%s/%s", lcwd, p);
1238: sdirs[sdx++] = fname2;
1239: }
1240: if (strcmp(lcwd, cwd) != 0) {
1.5 sjg 1241: /* Check vs cwd */
1.38 sjg 1242: snprintf(fname3, sizeof(fname3), "%s/%s", cwd, p);
1243: sdirs[sdx++] = fname3;
1.5 sjg 1244: }
1245: }
1246: sdirs[sdx++] = NULL;
1.1 sjg 1247:
1.5 sjg 1248: for (sdp = sdirs; *sdp && !found; sdp++) {
1.7 sjg 1249: #ifdef DEBUG_META_MODE
1250: if (DEBUG(META))
1251: fprintf(debug_file, "%s: %d: looking for: %s\n", fname, lineno, *sdp);
1252: #endif
1.5 sjg 1253: if (stat(*sdp, &fs) == 0) {
1254: found = 1;
1255: p = *sdp;
1256: }
1257: }
1258: if (found) {
1.7 sjg 1259: #ifdef DEBUG_META_MODE
1260: if (DEBUG(META))
1261: fprintf(debug_file, "%s: %d: found: %s\n", fname, lineno, p);
1262: #endif
1.5 sjg 1263: if (!S_ISDIR(fs.st_mode) &&
1264: fs.st_mtime > gn->mtime) {
1265: if (DEBUG(META))
1266: fprintf(debug_file, "%s: %d: file '%s' is newer than the target...\n", fname, lineno, p);
1267: oodate = TRUE;
1268: } else if (S_ISDIR(fs.st_mode)) {
1269: /* Update the latest directory. */
1270: realpath(p, latestdir);
1271: }
1272: } else if (errno == ENOENT && *p == '/' &&
1273: strncmp(p, cwd, cwdlen) != 0) {
1274: /*
1275: * A referenced file outside of CWD is missing.
1276: * We cannot catch every eventuality here...
1277: */
1.4 sjg 1278: if (DEBUG(META))
1.5 sjg 1279: fprintf(debug_file, "%s: %d: file '%s' may have moved?...\n", fname, lineno, p);
1.4 sjg 1280: oodate = TRUE;
1281: }
1.1 sjg 1282: }
1.38 sjg 1283: if (buf[0] == 'E') {
1284: /* previous latestdir is no longer relevant */
1285: strlcpy(latestdir, lcwd, sizeof(latestdir));
1286: }
1.1 sjg 1287: break;
1288: default:
1289: break;
1290: }
1.33 sjg 1291: if (!oodate && buf[0] == 'L' && link_src != NULL)
1292: goto check_link_src;
1.5 sjg 1293: } else if (strcmp(buf, "CMD") == 0) {
1.1 sjg 1294: /*
1295: * Compare the current command with the one in the
1296: * meta data file.
1297: */
1298: if (ln == NULL) {
1299: if (DEBUG(META))
1300: fprintf(debug_file, "%s: %d: there were more build commands in the meta data file than there are now...\n", fname, lineno);
1301: oodate = TRUE;
1302: } else {
1303: char *cmd = (char *)Lst_Datum(ln);
1.29 sjg 1304: Boolean hasOODATE = FALSE;
1.1 sjg 1305:
1.29 sjg 1306: if (strstr(cmd, "$?"))
1307: hasOODATE = TRUE;
1308: else if ((cp = strstr(cmd, ".OODATE"))) {
1309: /* check for $[{(].OODATE[:)}] */
1310: if (cp > cmd + 2 && cp[-2] == '$')
1311: hasOODATE = TRUE;
1312: }
1313: if (hasOODATE) {
1314: needOODATE = TRUE;
1315: if (DEBUG(META))
1316: fprintf(debug_file, "%s: %d: cannot compare command using .OODATE\n", fname, lineno);
1.1 sjg 1317: }
1.40 sjg 1318: cmd = Var_Subst(NULL, cmd, gn, TRUE, TRUE);
1.1 sjg 1319:
1320: if ((cp = strchr(cmd, '\n'))) {
1321: int n;
1322:
1323: /*
1324: * This command contains newlines, we need to
1325: * fetch more from the .meta file before we
1326: * attempt a comparison.
1327: */
1328: /* first put the newline back at buf[x - 1] */
1329: buf[x - 1] = '\n';
1330: do {
1331: /* now fetch the next line */
1332: if ((n = fgetLine(&buf, &bufsz, x, fp)) <= 0)
1333: break;
1334: x = n;
1335: lineno++;
1336: if (buf[x - 1] != '\n') {
1337: warnx("%s: %d: line truncated at %u", fname, lineno, x);
1338: break;
1339: }
1340: cp = strchr(++cp, '\n');
1341: } while (cp);
1342: if (buf[x - 1] == '\n')
1343: buf[x - 1] = '\0';
1344: }
1.29 sjg 1345: if (!hasOODATE &&
1.1 sjg 1346: !(gn->type & OP_NOMETA_CMP) &&
1347: strcmp(p, cmd) != 0) {
1348: if (DEBUG(META))
1349: fprintf(debug_file, "%s: %d: a build command has changed\n%s\nvs\n%s\n", fname, lineno, p, cmd);
1350: if (!metaIgnoreCMDs)
1351: oodate = TRUE;
1352: }
1353: free(cmd);
1354: ln = Lst_Succ(ln);
1355: }
1356: } else if (strcmp(buf, "CWD") == 0) {
1.14 sjg 1357: /*
1358: * Check if there are extra commands now
1359: * that weren't in the meta data file.
1360: */
1361: if (!oodate && ln != NULL) {
1362: if (DEBUG(META))
1363: fprintf(debug_file, "%s: %d: there are extra build commands now that weren't in the meta data file\n", fname, lineno);
1364: oodate = TRUE;
1365: }
1.11 sjg 1366: if (strcmp(p, cwd) != 0) {
1.1 sjg 1367: if (DEBUG(META))
1368: fprintf(debug_file, "%s: %d: the current working directory has changed from '%s' to '%s'\n", fname, lineno, p, curdir);
1369: oodate = TRUE;
1370: }
1371: }
1372: }
1373:
1374: fclose(fp);
1.17 sjg 1375: if (!Lst_IsEmpty(missingFiles)) {
1376: if (DEBUG(META))
1377: fprintf(debug_file, "%s: missing files: %s...\n",
1378: fname, (char *)Lst_Datum(Lst_First(missingFiles)));
1379: oodate = TRUE;
1380: Lst_Destroy(missingFiles, (FreeProc *)free);
1381: }
1.21 sjg 1382: } else {
1383: if ((gn->type & OP_META)) {
1384: if (DEBUG(META))
1385: fprintf(debug_file, "%s: required but missing\n", fname);
1386: oodate = TRUE;
1387: }
1.1 sjg 1388: }
1.26 sjg 1389: if (oodate && needOODATE) {
1.4 sjg 1390: /*
1.26 sjg 1391: * Target uses .OODATE which is empty; or we wouldn't be here.
1392: * We have decided it is oodate, so .OODATE needs to be set.
1393: * All we can sanely do is set it to .ALLSRC.
1.4 sjg 1394: */
1395: Var_Delete(OODATE, gn);
1.26 sjg 1396: Var_Set(OODATE, Var_Value(ALLSRC, gn, &cp), gn, 0);
1397: if (cp)
1398: free(cp);
1.4 sjg 1399: }
1.1 sjg 1400: return oodate;
1401: }
1402:
1403: /* support for compat mode */
1404:
1405: static int childPipe[2];
1406:
1407: void
1408: meta_compat_start(void)
1409: {
1410: #ifdef USE_FILEMON_ONCE
1411: /*
1412: * We need to re-open filemon for each cmd.
1413: */
1414: BuildMon *pbm = &Mybm;
1415:
1416: if (pbm->mfp != NULL && useFilemon) {
1417: filemon_open(pbm);
1418: } else {
1419: pbm->mon_fd = pbm->filemon_fd = -1;
1420: }
1421: #endif
1422: if (pipe(childPipe) < 0)
1423: Punt("Cannot create pipe: %s", strerror(errno));
1424: /* Set close-on-exec flag for both */
1.42 christos 1425: (void)fcntl(childPipe[0], F_SETFD, FD_CLOEXEC);
1426: (void)fcntl(childPipe[1], F_SETFD, FD_CLOEXEC);
1.1 sjg 1427: }
1428:
1429: void
1430: meta_compat_child(void)
1431: {
1432: meta_job_child(NULL);
1433: if (dup2(childPipe[1], 1) < 0 ||
1434: dup2(1, 2) < 0) {
1435: execError("dup2", "pipe");
1436: _exit(1);
1437: }
1438: }
1439:
1440: void
1441: meta_compat_parent(void)
1442: {
1443: FILE *fp;
1444: char buf[BUFSIZ];
1445:
1446: close(childPipe[1]); /* child side */
1447: fp = fdopen(childPipe[0], "r");
1448: while (fgets(buf, sizeof(buf), fp)) {
1449: meta_job_output(NULL, buf, "");
1450: printf("%s", buf);
1451: }
1452: fclose(fp);
1453: }
1.3 sjg 1454:
1455: #endif /* USE_META */
CVSweb <webmaster@jp.NetBSD.org>