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