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