| @@ -1,706 +1,704 @@ | | | @@ -1,706 +1,704 @@ |
1 | /* $NetBSD: compat.c,v 1.173 2020/11/01 17:47:26 rillig Exp $ */ | | 1 | /* $NetBSD: compat.c,v 1.174 2020/11/02 20:50:24 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | | 4 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * 3. Neither the name of the University nor the names of its contributors | | 18 | * 3. Neither the name of the University nor the names of its contributors |
19 | * may be used to endorse or promote products derived from this software | | 19 | * may be used to endorse or promote products derived from this software |
20 | * without specific prior written permission. | | 20 | * without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
32 | * SUCH DAMAGE. | | 32 | * SUCH DAMAGE. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | /* | | 35 | /* |
36 | * Copyright (c) 1988, 1989 by Adam de Boor | | 36 | * Copyright (c) 1988, 1989 by Adam de Boor |
37 | * Copyright (c) 1989 by Berkeley Softworks | | 37 | * Copyright (c) 1989 by Berkeley Softworks |
38 | * All rights reserved. | | 38 | * All rights reserved. |
39 | * | | 39 | * |
40 | * This code is derived from software contributed to Berkeley by | | 40 | * This code is derived from software contributed to Berkeley by |
41 | * Adam de Boor. | | 41 | * Adam de Boor. |
42 | * | | 42 | * |
43 | * Redistribution and use in source and binary forms, with or without | | 43 | * Redistribution and use in source and binary forms, with or without |
44 | * modification, are permitted provided that the following conditions | | 44 | * modification, are permitted provided that the following conditions |
45 | * are met: | | 45 | * are met: |
46 | * 1. Redistributions of source code must retain the above copyright | | 46 | * 1. Redistributions of source code must retain the above copyright |
47 | * notice, this list of conditions and the following disclaimer. | | 47 | * notice, this list of conditions and the following disclaimer. |
48 | * 2. Redistributions in binary form must reproduce the above copyright | | 48 | * 2. Redistributions in binary form must reproduce the above copyright |
49 | * notice, this list of conditions and the following disclaimer in the | | 49 | * notice, this list of conditions and the following disclaimer in the |
50 | * documentation and/or other materials provided with the distribution. | | 50 | * documentation and/or other materials provided with the distribution. |
51 | * 3. All advertising materials mentioning features or use of this software | | 51 | * 3. All advertising materials mentioning features or use of this software |
52 | * must display the following acknowledgement: | | 52 | * must display the following acknowledgement: |
53 | * This product includes software developed by the University of | | 53 | * This product includes software developed by the University of |
54 | * California, Berkeley and its contributors. | | 54 | * California, Berkeley and its contributors. |
55 | * 4. Neither the name of the University nor the names of its contributors | | 55 | * 4. Neither the name of the University nor the names of its contributors |
56 | * may be used to endorse or promote products derived from this software | | 56 | * may be used to endorse or promote products derived from this software |
57 | * without specific prior written permission. | | 57 | * without specific prior written permission. |
58 | * | | 58 | * |
59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 59 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 60 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 61 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 62 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 63 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 64 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 65 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 66 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 67 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 68 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
69 | * SUCH DAMAGE. | | 69 | * SUCH DAMAGE. |
70 | */ | | 70 | */ |
71 | | | 71 | |
72 | /*- | | 72 | /*- |
73 | * compat.c -- | | 73 | * compat.c -- |
74 | * The routines in this file implement the full-compatibility | | 74 | * The routines in this file implement the full-compatibility |
75 | * mode of PMake. Most of the special functionality of PMake | | 75 | * mode of PMake. Most of the special functionality of PMake |
76 | * is available in this mode. Things not supported: | | 76 | * is available in this mode. Things not supported: |
77 | * - different shells. | | 77 | * - different shells. |
78 | * - friendly variable substitution. | | 78 | * - friendly variable substitution. |
79 | * | | 79 | * |
80 | * Interface: | | 80 | * Interface: |
81 | * Compat_Run Initialize things for this module and recreate | | 81 | * Compat_Run Initialize things for this module and recreate |
82 | * thems as need creatin' | | 82 | * thems as need creatin' |
83 | */ | | 83 | */ |
84 | | | 84 | |
85 | #include <sys/types.h> | | 85 | #include <sys/types.h> |
86 | #include <sys/stat.h> | | 86 | #include <sys/stat.h> |
87 | #include <sys/wait.h> | | 87 | #include <sys/wait.h> |
88 | | | 88 | |
89 | #include <errno.h> | | 89 | #include <errno.h> |
90 | #include <signal.h> | | 90 | #include <signal.h> |
91 | | | 91 | |
92 | #include "make.h" | | 92 | #include "make.h" |
93 | #include "dir.h" | | 93 | #include "dir.h" |
94 | #include "job.h" | | 94 | #include "job.h" |
95 | #include "metachar.h" | | 95 | #include "metachar.h" |
96 | #include "pathnames.h" | | 96 | #include "pathnames.h" |
97 | | | 97 | |
98 | /* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */ | | 98 | /* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */ |
99 | MAKE_RCSID("$NetBSD: compat.c,v 1.173 2020/11/01 17:47:26 rillig Exp $"); | | 99 | MAKE_RCSID("$NetBSD: compat.c,v 1.174 2020/11/02 20:50:24 rillig Exp $"); |
100 | | | 100 | |
101 | static GNode *curTarg = NULL; | | 101 | static GNode *curTarg = NULL; |
102 | static pid_t compatChild; | | 102 | static pid_t compatChild; |
103 | static int compatSigno; | | 103 | static int compatSigno; |
104 | | | 104 | |
105 | /* | | 105 | /* |
106 | * CompatDeleteTarget -- delete a failed, interrupted, or otherwise | | 106 | * CompatDeleteTarget -- delete the file of a failed, interrupted, or |
107 | * duffed target if not inhibited by .PRECIOUS. | | 107 | * otherwise duffed target if not inhibited by .PRECIOUS. |
108 | */ | | 108 | */ |
109 | static void | | 109 | static void |
110 | CompatDeleteTarget(GNode *gn) | | 110 | CompatDeleteTarget(GNode *gn) |
111 | { | | 111 | { |
112 | if (gn != NULL && !Targ_Precious(gn)) { | | 112 | if (gn != NULL && !Targ_Precious(gn)) { |
113 | const char *file = GNode_VarTarget(gn); | | 113 | const char *file = GNode_VarTarget(gn); |
114 | | | 114 | |
115 | if (!opts.noExecute && eunlink(file) != -1) { | | 115 | if (!opts.noExecute && eunlink(file) != -1) { |
116 | Error("*** %s removed", file); | | 116 | Error("*** %s removed", file); |
117 | } | | 117 | } |
118 | } | | 118 | } |
119 | } | | 119 | } |
120 | | | 120 | |
121 | /* Interrupt the creation of the current target and remove it if it ain't | | 121 | /* Interrupt the creation of the current target and remove it if it ain't |
122 | * precious. Then exit. | | 122 | * precious. Then exit. |
123 | * | | 123 | * |
124 | * If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED. | | 124 | * If .INTERRUPT exists, its commands are run first WITH INTERRUPTS IGNORED. |
125 | * | | 125 | * |
126 | * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've | | 126 | * XXX: is .PRECIOUS supposed to inhibit .INTERRUPT? I doubt it, but I've |
127 | * left the logic alone for now. - dholland 20160826 | | 127 | * left the logic alone for now. - dholland 20160826 |
128 | */ | | 128 | */ |
129 | static void | | 129 | static void |
130 | CompatInterrupt(int signo) | | 130 | CompatInterrupt(int signo) |
131 | { | | 131 | { |
132 | GNode *gn; | | | |
133 | | | | |
134 | CompatDeleteTarget(curTarg); | | 132 | CompatDeleteTarget(curTarg); |
135 | | | 133 | |
136 | if (curTarg != NULL && !Targ_Precious(curTarg)) { | | 134 | if (curTarg != NULL && !Targ_Precious(curTarg)) { |
137 | /* | | 135 | /* |
138 | * Run .INTERRUPT only if hit with interrupt signal | | 136 | * Run .INTERRUPT only if hit with interrupt signal |
139 | */ | | 137 | */ |
140 | if (signo == SIGINT) { | | 138 | if (signo == SIGINT) { |
141 | gn = Targ_FindNode(".INTERRUPT"); | | 139 | GNode *gn = Targ_FindNode(".INTERRUPT"); |
142 | if (gn != NULL) { | | 140 | if (gn != NULL) { |
143 | Compat_Make(gn, gn); | | 141 | Compat_Make(gn, gn); |
144 | } | | 142 | } |
145 | } | | 143 | } |
146 | } | | 144 | } |
147 | | | 145 | |
148 | if (signo == SIGQUIT) | | 146 | if (signo == SIGQUIT) |
149 | _exit(signo); | | 147 | _exit(signo); |
150 | | | 148 | |
151 | /* | | 149 | /* |
152 | * If there is a child running, pass the signal on. | | 150 | * If there is a child running, pass the signal on. |
153 | * We will exist after it has exited. | | 151 | * We will exist after it has exited. |
154 | */ | | 152 | */ |
155 | compatSigno = signo; | | 153 | compatSigno = signo; |
156 | if (compatChild > 0) { | | 154 | if (compatChild > 0) { |
157 | KILLPG(compatChild, signo); | | 155 | KILLPG(compatChild, signo); |
158 | } else { | | 156 | } else { |
159 | bmake_signal(signo, SIG_DFL); | | 157 | bmake_signal(signo, SIG_DFL); |
160 | kill(myPid, signo); | | 158 | kill(myPid, signo); |
161 | } | | 159 | } |
162 | } | | 160 | } |
163 | | | 161 | |
164 | /* Execute the next command for a target. If the command returns an error, | | 162 | /* Execute the next command for a target. If the command returns an error, |
165 | * the node's made field is set to ERROR and creation stops. | | 163 | * the node's made field is set to ERROR and creation stops. |
166 | * | | 164 | * |
167 | * Input: | | 165 | * Input: |
168 | * cmdp Command to execute | | 166 | * cmdp Command to execute |
169 | * gnp Node from which the command came | | 167 | * gnp Node from which the command came |
170 | * | | 168 | * |
171 | * Results: | | 169 | * Results: |
172 | * 0 if the command succeeded, 1 if an error occurred. | | 170 | * 0 if the command succeeded, 1 if an error occurred. |
173 | */ | | 171 | */ |
174 | int | | 172 | int |
175 | Compat_RunCommand(const char *cmdp, GNode *gn) | | 173 | Compat_RunCommand(const char *cmdp, GNode *gn) |
176 | { | | 174 | { |
177 | char *cmdStart; /* Start of expanded command */ | | 175 | char *cmdStart; /* Start of expanded command */ |
178 | char *bp; | | 176 | char *bp; |
179 | Boolean silent; /* Don't print command */ | | 177 | Boolean silent; /* Don't print command */ |
180 | Boolean doIt; /* Execute even if -n */ | | 178 | Boolean doIt; /* Execute even if -n */ |
181 | volatile Boolean errCheck; /* Check errors */ | | 179 | volatile Boolean errCheck; /* Check errors */ |
182 | int reason; /* Reason for child's death */ | | 180 | int reason; /* Reason for child's death */ |
183 | int status; /* Description of child's death */ | | 181 | int status; /* Description of child's death */ |
184 | pid_t cpid; /* Child actually found */ | | 182 | pid_t cpid; /* Child actually found */ |
185 | pid_t retstat; /* Result of wait */ | | 183 | pid_t retstat; /* Result of wait */ |
186 | StringListNode *cmdNode; /* Node where current command is located */ | | 184 | StringListNode *cmdNode; /* Node where current command is located */ |
187 | const char **volatile av; /* Argument vector for thing to exec */ | | 185 | const char **volatile av; /* Argument vector for thing to exec */ |
188 | char **volatile mav; /* Copy of the argument vector for freeing */ | | 186 | char **volatile mav; /* Copy of the argument vector for freeing */ |
189 | Boolean useShell; /* TRUE if command should be executed | | 187 | Boolean useShell; /* TRUE if command should be executed |
190 | * using a shell */ | | 188 | * using a shell */ |
191 | const char *volatile cmd = cmdp; | | 189 | const char *volatile cmd = cmdp; |
192 | | | 190 | |
193 | silent = (gn->type & OP_SILENT) != 0; | | 191 | silent = (gn->type & OP_SILENT) != 0; |
194 | errCheck = !(gn->type & OP_IGNORE); | | 192 | errCheck = !(gn->type & OP_IGNORE); |
195 | doIt = FALSE; | | 193 | doIt = FALSE; |
196 | | | 194 | |
197 | /* Luckily the commands don't end up in a string pool, otherwise | | 195 | /* Luckily the commands don't end up in a string pool, otherwise |
198 | * this comparison could match too early, in a dependency using "..." | | 196 | * this comparison could match too early, in a dependency using "..." |
199 | * for delayed commands, run in parallel mode, using the same shell | | 197 | * for delayed commands, run in parallel mode, using the same shell |
200 | * command line more than once; see JobPrintCommand. | | 198 | * command line more than once; see JobPrintCommand. |
201 | * TODO: write a unit-test to protect against this potential bug. */ | | 199 | * TODO: write a unit-test to protect against this potential bug. */ |
202 | cmdNode = Lst_FindDatum(gn->commands, cmd); | | 200 | cmdNode = Lst_FindDatum(gn->commands, cmd); |
203 | (void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart); | | 201 | (void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart); |
204 | /* TODO: handle errors */ | | 202 | /* TODO: handle errors */ |
205 | | | 203 | |
206 | if (*cmdStart == '\0') { | | 204 | if (*cmdStart == '\0') { |
207 | free(cmdStart); | | 205 | free(cmdStart); |
208 | return 0; | | 206 | return 0; |
209 | } | | 207 | } |
210 | cmd = cmdStart; | | 208 | cmd = cmdStart; |
211 | LstNode_Set(cmdNode, cmdStart); | | 209 | LstNode_Set(cmdNode, cmdStart); |
212 | | | 210 | |
213 | if (gn->type & OP_SAVE_CMDS) { | | 211 | if (gn->type & OP_SAVE_CMDS) { |
214 | GNode *endNode = Targ_GetEndNode(); | | 212 | GNode *endNode = Targ_GetEndNode(); |
215 | if (gn != endNode) { | | 213 | if (gn != endNode) { |
216 | Lst_Append(endNode->commands, cmdStart); | | 214 | Lst_Append(endNode->commands, cmdStart); |
217 | return 0; | | 215 | return 0; |
218 | } | | 216 | } |
219 | } | | 217 | } |
220 | if (strcmp(cmdStart, "...") == 0) { | | 218 | if (strcmp(cmdStart, "...") == 0) { |
221 | gn->type |= OP_SAVE_CMDS; | | 219 | gn->type |= OP_SAVE_CMDS; |
222 | return 0; | | 220 | return 0; |
223 | } | | 221 | } |
224 | | | 222 | |
225 | while (*cmd == '@' || *cmd == '-' || *cmd == '+') { | | 223 | while (*cmd == '@' || *cmd == '-' || *cmd == '+') { |
226 | switch (*cmd) { | | 224 | switch (*cmd) { |
227 | case '@': | | 225 | case '@': |
228 | silent = !DEBUG(LOUD); | | 226 | silent = !DEBUG(LOUD); |
229 | break; | | 227 | break; |
230 | case '-': | | 228 | case '-': |
231 | errCheck = FALSE; | | 229 | errCheck = FALSE; |
232 | break; | | 230 | break; |
233 | case '+': | | 231 | case '+': |
234 | doIt = TRUE; | | 232 | doIt = TRUE; |
235 | if (!shellName) /* we came here from jobs */ | | 233 | if (!shellName) /* we came here from jobs */ |
236 | Shell_Init(); | | 234 | Shell_Init(); |
237 | break; | | 235 | break; |
238 | } | | 236 | } |
239 | cmd++; | | 237 | cmd++; |
240 | } | | 238 | } |
241 | | | 239 | |
242 | while (ch_isspace(*cmd)) | | 240 | while (ch_isspace(*cmd)) |
243 | cmd++; | | 241 | cmd++; |
244 | | | 242 | |
245 | /* | | 243 | /* |
246 | * If we did not end up with a command, just skip it. | | 244 | * If we did not end up with a command, just skip it. |
247 | */ | | 245 | */ |
248 | if (!*cmd) | | 246 | if (!*cmd) |
249 | return 0; | | 247 | return 0; |
250 | | | 248 | |
251 | #if !defined(MAKE_NATIVE) | | 249 | #if !defined(MAKE_NATIVE) |
252 | /* | | 250 | /* |
253 | * In a non-native build, the host environment might be weird enough | | 251 | * In a non-native build, the host environment might be weird enough |
254 | * that it's necessary to go through a shell to get the correct | | 252 | * that it's necessary to go through a shell to get the correct |
255 | * behaviour. Or perhaps the shell has been replaced with something | | 253 | * behaviour. Or perhaps the shell has been replaced with something |
256 | * that does extra logging, and that should not be bypassed. | | 254 | * that does extra logging, and that should not be bypassed. |
257 | */ | | 255 | */ |
258 | useShell = TRUE; | | 256 | useShell = TRUE; |
259 | #else | | 257 | #else |
260 | /* | | 258 | /* |
261 | * Search for meta characters in the command. If there are no meta | | 259 | * Search for meta characters in the command. If there are no meta |
262 | * characters, there's no need to execute a shell to execute the | | 260 | * characters, there's no need to execute a shell to execute the |
263 | * command. | | 261 | * command. |
264 | * | | 262 | * |
265 | * Additionally variable assignments and empty commands | | 263 | * Additionally variable assignments and empty commands |
266 | * go to the shell. Therefore treat '=' and ':' like shell | | 264 | * go to the shell. Therefore treat '=' and ':' like shell |
267 | * meta characters as documented in make(1). | | 265 | * meta characters as documented in make(1). |
268 | */ | | 266 | */ |
269 | | | 267 | |
270 | useShell = needshell(cmd); | | 268 | useShell = needshell(cmd); |
271 | #endif | | 269 | #endif |
272 | | | 270 | |
273 | /* | | 271 | /* |
274 | * Print the command before echoing if we're not supposed to be quiet for | | 272 | * Print the command before echoing if we're not supposed to be quiet for |
275 | * this one. We also print the command if -n given. | | 273 | * this one. We also print the command if -n given. |
276 | */ | | 274 | */ |
277 | if (!silent || !GNode_ShouldExecute(gn)) { | | 275 | if (!silent || !GNode_ShouldExecute(gn)) { |
278 | printf("%s\n", cmd); | | 276 | printf("%s\n", cmd); |
279 | fflush(stdout); | | 277 | fflush(stdout); |
280 | } | | 278 | } |
281 | | | 279 | |
282 | /* | | 280 | /* |
283 | * If we're not supposed to execute any commands, this is as far as | | 281 | * If we're not supposed to execute any commands, this is as far as |
284 | * we go... | | 282 | * we go... |
285 | */ | | 283 | */ |
286 | if (!doIt && !GNode_ShouldExecute(gn)) { | | 284 | if (!doIt && !GNode_ShouldExecute(gn)) { |
287 | return 0; | | 285 | return 0; |
288 | } | | 286 | } |
289 | DEBUG1(JOB, "Execute: '%s'\n", cmd); | | 287 | DEBUG1(JOB, "Execute: '%s'\n", cmd); |
290 | | | 288 | |
291 | if (useShell) { | | 289 | if (useShell) { |
292 | /* | | 290 | /* |
293 | * We need to pass the command off to the shell, typically | | 291 | * We need to pass the command off to the shell, typically |
294 | * because the command contains a "meta" character. | | 292 | * because the command contains a "meta" character. |
295 | */ | | 293 | */ |
296 | static const char *shargv[5]; | | 294 | static const char *shargv[5]; |
297 | int shargc; | | 295 | int shargc; |
298 | | | 296 | |
299 | shargc = 0; | | 297 | shargc = 0; |
300 | shargv[shargc++] = shellPath; | | 298 | shargv[shargc++] = shellPath; |
301 | /* | | 299 | /* |
302 | * The following work for any of the builtin shell specs. | | 300 | * The following work for any of the builtin shell specs. |
303 | */ | | 301 | */ |
304 | if (errCheck && shellErrFlag) { | | 302 | if (errCheck && shellErrFlag) { |
305 | shargv[shargc++] = shellErrFlag; | | 303 | shargv[shargc++] = shellErrFlag; |
306 | } | | 304 | } |
307 | if (DEBUG(SHELL)) | | 305 | if (DEBUG(SHELL)) |
308 | shargv[shargc++] = "-xc"; | | 306 | shargv[shargc++] = "-xc"; |
309 | else | | 307 | else |
310 | shargv[shargc++] = "-c"; | | 308 | shargv[shargc++] = "-c"; |
311 | shargv[shargc++] = cmd; | | 309 | shargv[shargc++] = cmd; |
312 | shargv[shargc] = NULL; | | 310 | shargv[shargc] = NULL; |
313 | av = shargv; | | 311 | av = shargv; |
314 | bp = NULL; | | 312 | bp = NULL; |
315 | mav = NULL; | | 313 | mav = NULL; |
316 | } else { | | 314 | } else { |
317 | /* | | 315 | /* |
318 | * No meta-characters, so no need to exec a shell. Break the command | | 316 | * No meta-characters, so no need to exec a shell. Break the command |
319 | * into words to form an argument vector we can execute. | | 317 | * into words to form an argument vector we can execute. |
320 | */ | | 318 | */ |
321 | Words words = Str_Words(cmd, FALSE); | | 319 | Words words = Str_Words(cmd, FALSE); |
322 | mav = words.words; | | 320 | mav = words.words; |
323 | bp = words.freeIt; | | 321 | bp = words.freeIt; |
324 | av = (void *)mav; | | 322 | av = (void *)mav; |
325 | } | | 323 | } |
326 | | | 324 | |
327 | #ifdef USE_META | | 325 | #ifdef USE_META |
328 | if (useMeta) { | | 326 | if (useMeta) { |
329 | meta_compat_start(); | | 327 | meta_compat_start(); |
330 | } | | 328 | } |
331 | #endif | | 329 | #endif |
332 | | | 330 | |
333 | /* | | 331 | /* |
334 | * Fork and execute the single command. If the fork fails, we abort. | | 332 | * Fork and execute the single command. If the fork fails, we abort. |
335 | */ | | 333 | */ |
336 | compatChild = cpid = vFork(); | | 334 | compatChild = cpid = vFork(); |
337 | if (cpid < 0) { | | 335 | if (cpid < 0) { |
338 | Fatal("Could not fork"); | | 336 | Fatal("Could not fork"); |
339 | } | | 337 | } |
340 | if (cpid == 0) { | | 338 | if (cpid == 0) { |
341 | Var_ExportVars(); | | 339 | Var_ExportVars(); |
342 | #ifdef USE_META | | 340 | #ifdef USE_META |
343 | if (useMeta) { | | 341 | if (useMeta) { |
344 | meta_compat_child(); | | 342 | meta_compat_child(); |
345 | } | | 343 | } |
346 | #endif | | 344 | #endif |
347 | (void)execvp(av[0], (char *const *)UNCONST(av)); | | 345 | (void)execvp(av[0], (char *const *)UNCONST(av)); |
348 | execDie("exec", av[0]); | | 346 | execDie("exec", av[0]); |
349 | } | | 347 | } |
350 | | | 348 | |
351 | free(mav); | | 349 | free(mav); |
352 | free(bp); | | 350 | free(bp); |
353 | | | 351 | |
354 | /* XXX: Memory management looks suspicious here. */ | | 352 | /* XXX: Memory management looks suspicious here. */ |
355 | /* XXX: Setting a list item to NULL is unexpected. */ | | 353 | /* XXX: Setting a list item to NULL is unexpected. */ |
356 | LstNode_SetNull(cmdNode); | | 354 | LstNode_SetNull(cmdNode); |
357 | | | 355 | |
358 | #ifdef USE_META | | 356 | #ifdef USE_META |
359 | if (useMeta) { | | 357 | if (useMeta) { |
360 | meta_compat_parent(cpid); | | 358 | meta_compat_parent(cpid); |
361 | } | | 359 | } |
362 | #endif | | 360 | #endif |
363 | | | 361 | |
364 | /* | | 362 | /* |
365 | * The child is off and running. Now all we can do is wait... | | 363 | * The child is off and running. Now all we can do is wait... |
366 | */ | | 364 | */ |
367 | while ((retstat = wait(&reason)) != cpid) { | | 365 | while ((retstat = wait(&reason)) != cpid) { |
368 | if (retstat > 0) | | 366 | if (retstat > 0) |
369 | JobReapChild(retstat, reason, FALSE); /* not ours? */ | | 367 | JobReapChild(retstat, reason, FALSE); /* not ours? */ |
370 | if (retstat == -1 && errno != EINTR) { | | 368 | if (retstat == -1 && errno != EINTR) { |
371 | break; | | 369 | break; |
372 | } | | 370 | } |
373 | } | | 371 | } |
374 | | | 372 | |
375 | if (retstat < 0) | | 373 | if (retstat < 0) |
376 | Fatal("error in wait: %d: %s", retstat, strerror(errno)); | | 374 | Fatal("error in wait: %d: %s", retstat, strerror(errno)); |
377 | | | 375 | |
378 | if (WIFSTOPPED(reason)) { | | 376 | if (WIFSTOPPED(reason)) { |
379 | status = WSTOPSIG(reason); /* stopped */ | | 377 | status = WSTOPSIG(reason); /* stopped */ |
380 | } else if (WIFEXITED(reason)) { | | 378 | } else if (WIFEXITED(reason)) { |
381 | status = WEXITSTATUS(reason); /* exited */ | | 379 | status = WEXITSTATUS(reason); /* exited */ |
382 | #if defined(USE_META) && defined(USE_FILEMON_ONCE) | | 380 | #if defined(USE_META) && defined(USE_FILEMON_ONCE) |
383 | if (useMeta) { | | 381 | if (useMeta) { |
384 | meta_cmd_finish(NULL); | | 382 | meta_cmd_finish(NULL); |
385 | } | | 383 | } |
386 | #endif | | 384 | #endif |
387 | if (status != 0) { | | 385 | if (status != 0) { |
388 | if (DEBUG(ERROR)) { | | 386 | if (DEBUG(ERROR)) { |
389 | const char *cp; | | 387 | const char *cp; |
390 | debug_printf("\n*** Failed target: %s\n*** Failed command: ", | | 388 | debug_printf("\n*** Failed target: %s\n*** Failed command: ", |
391 | gn->name); | | 389 | gn->name); |
392 | for (cp = cmd; *cp; ) { | | 390 | for (cp = cmd; *cp; ) { |
393 | if (ch_isspace(*cp)) { | | 391 | if (ch_isspace(*cp)) { |
394 | debug_printf(" "); | | 392 | debug_printf(" "); |
395 | while (ch_isspace(*cp)) | | 393 | while (ch_isspace(*cp)) |
396 | cp++; | | 394 | cp++; |
397 | } else { | | 395 | } else { |
398 | debug_printf("%c", *cp); | | 396 | debug_printf("%c", *cp); |
399 | cp++; | | 397 | cp++; |
400 | } | | 398 | } |
401 | } | | 399 | } |
402 | debug_printf("\n"); | | 400 | debug_printf("\n"); |
403 | } | | 401 | } |
404 | printf("*** Error code %d", status); | | 402 | printf("*** Error code %d", status); |
405 | } | | 403 | } |
406 | } else { | | 404 | } else { |
407 | status = WTERMSIG(reason); /* signaled */ | | 405 | status = WTERMSIG(reason); /* signaled */ |
408 | printf("*** Signal %d", status); | | 406 | printf("*** Signal %d", status); |
409 | } | | 407 | } |
410 | | | 408 | |
411 | | | 409 | |
412 | if (!WIFEXITED(reason) || status != 0) { | | 410 | if (!WIFEXITED(reason) || status != 0) { |
413 | if (errCheck) { | | 411 | if (errCheck) { |
414 | #ifdef USE_META | | 412 | #ifdef USE_META |
415 | if (useMeta) { | | 413 | if (useMeta) { |
416 | meta_job_error(NULL, gn, 0, status); | | 414 | meta_job_error(NULL, gn, 0, status); |
417 | } | | 415 | } |
418 | #endif | | 416 | #endif |
419 | gn->made = ERROR; | | 417 | gn->made = ERROR; |
420 | if (opts.keepgoing) { | | 418 | if (opts.keepgoing) { |
421 | /* Abort the current target, but let others continue. */ | | 419 | /* Abort the current target, but let others continue. */ |
422 | printf(" (continuing)\n"); | | 420 | printf(" (continuing)\n"); |
423 | } else { | | 421 | } else { |
424 | printf("\n"); | | 422 | printf("\n"); |
425 | } | | 423 | } |
426 | if (deleteOnError) | | 424 | if (deleteOnError) |
427 | CompatDeleteTarget(gn); | | 425 | CompatDeleteTarget(gn); |
428 | } else { | | 426 | } else { |
429 | /* | | 427 | /* |
430 | * Continue executing commands for this target. | | 428 | * Continue executing commands for this target. |
431 | * If we return 0, this will happen... | | 429 | * If we return 0, this will happen... |
432 | */ | | 430 | */ |
433 | printf(" (ignored)\n"); | | 431 | printf(" (ignored)\n"); |
434 | status = 0; | | 432 | status = 0; |
435 | } | | 433 | } |
436 | } | | 434 | } |
437 | | | 435 | |
438 | free(cmdStart); | | 436 | free(cmdStart); |
439 | compatChild = 0; | | 437 | compatChild = 0; |
440 | if (compatSigno) { | | 438 | if (compatSigno) { |
441 | bmake_signal(compatSigno, SIG_DFL); | | 439 | bmake_signal(compatSigno, SIG_DFL); |
442 | kill(myPid, compatSigno); | | 440 | kill(myPid, compatSigno); |
443 | } | | 441 | } |
444 | | | 442 | |
445 | return status; | | 443 | return status; |
446 | } | | 444 | } |
447 | | | 445 | |
448 | static void | | 446 | static void |
449 | RunCommands(GNode *gn) | | 447 | RunCommands(GNode *gn) |
450 | { | | 448 | { |
451 | StringListNode *ln; | | 449 | StringListNode *ln; |
452 | for (ln = gn->commands->first; ln != NULL; ln = ln->next) { | | 450 | for (ln = gn->commands->first; ln != NULL; ln = ln->next) { |
453 | const char *cmd = ln->datum; | | 451 | const char *cmd = ln->datum; |
454 | if (Compat_RunCommand(cmd, gn) != 0) | | 452 | if (Compat_RunCommand(cmd, gn) != 0) |
455 | break; | | 453 | break; |
456 | } | | 454 | } |
457 | } | | 455 | } |
458 | | | 456 | |
459 | static void | | 457 | static void |
460 | MakeNodes(GNodeList *gnodes, GNode *pgn) | | 458 | MakeNodes(GNodeList *gnodes, GNode *pgn) |
461 | { | | 459 | { |
462 | GNodeListNode *ln; | | 460 | GNodeListNode *ln; |
463 | for (ln = gnodes->first; ln != NULL; ln = ln->next) { | | 461 | for (ln = gnodes->first; ln != NULL; ln = ln->next) { |
464 | GNode *cohort = ln->datum; | | 462 | GNode *cohort = ln->datum; |
465 | Compat_Make(cohort, pgn); | | 463 | Compat_Make(cohort, pgn); |
466 | } | | 464 | } |
467 | } | | 465 | } |
468 | | | 466 | |
469 | /* Make a target. | | 467 | /* Make a target. |
470 | * | | 468 | * |
471 | * If an error is detected and not being ignored, the process exits. | | 469 | * If an error is detected and not being ignored, the process exits. |
472 | * | | 470 | * |
473 | * Input: | | 471 | * Input: |
474 | * gn The node to make | | 472 | * gn The node to make |
475 | * pgn Parent to abort if necessary | | 473 | * pgn Parent to abort if necessary |
476 | */ | | 474 | */ |
477 | void | | 475 | void |
478 | Compat_Make(GNode *gn, GNode *pgn) | | 476 | Compat_Make(GNode *gn, GNode *pgn) |
479 | { | | 477 | { |
480 | if (!shellName) /* we came here from jobs */ | | 478 | if (!shellName) /* we came here from jobs */ |
481 | Shell_Init(); | | 479 | Shell_Init(); |
482 | if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) { | | 480 | if (gn->made == UNMADE && (gn == pgn || !(pgn->type & OP_MADE))) { |
483 | /* | | 481 | /* |
484 | * First mark ourselves to be made, then apply whatever transformations | | 482 | * First mark ourselves to be made, then apply whatever transformations |
485 | * the suffix module thinks are necessary. Once that's done, we can | | 483 | * the suffix module thinks are necessary. Once that's done, we can |
486 | * descend and make all our children. If any of them has an error | | 484 | * descend and make all our children. If any of them has an error |
487 | * but the -k flag was given, our 'make' field will be set FALSE again. | | 485 | * but the -k flag was given, our 'make' field will be set FALSE again. |
488 | * This is our signal to not attempt to do anything but abort our | | 486 | * This is our signal to not attempt to do anything but abort our |
489 | * parent as well. | | 487 | * parent as well. |
490 | */ | | 488 | */ |
491 | gn->flags |= REMAKE; | | 489 | gn->flags |= REMAKE; |
492 | gn->made = BEINGMADE; | | 490 | gn->made = BEINGMADE; |
493 | if (!(gn->type & OP_MADE)) | | 491 | if (!(gn->type & OP_MADE)) |
494 | Suff_FindDeps(gn); | | 492 | Suff_FindDeps(gn); |
495 | MakeNodes(gn->children, gn); | | 493 | MakeNodes(gn->children, gn); |
496 | if (!(gn->flags & REMAKE)) { | | 494 | if (!(gn->flags & REMAKE)) { |
497 | gn->made = ABORTED; | | 495 | gn->made = ABORTED; |
498 | pgn->flags &= ~(unsigned)REMAKE; | | 496 | pgn->flags &= ~(unsigned)REMAKE; |
499 | goto cohorts; | | 497 | goto cohorts; |
500 | } | | 498 | } |
501 | | | 499 | |
502 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) | | 500 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) |
503 | Var_Set(IMPSRC, GNode_VarTarget(gn), pgn); | | 501 | Var_Set(IMPSRC, GNode_VarTarget(gn), pgn); |
504 | | | 502 | |
505 | /* | | 503 | /* |
506 | * All the children were made ok. Now youngestChild->mtime contains the | | 504 | * All the children were made ok. Now youngestChild->mtime contains the |
507 | * modification time of the newest child, we need to find out if we | | 505 | * modification time of the newest child, we need to find out if we |
508 | * exist and when we were modified last. The criteria for datedness | | 506 | * exist and when we were modified last. The criteria for datedness |
509 | * are defined by the Make_OODate function. | | 507 | * are defined by the Make_OODate function. |
510 | */ | | 508 | */ |
511 | DEBUG1(MAKE, "Examining %s...", gn->name); | | 509 | DEBUG1(MAKE, "Examining %s...", gn->name); |
512 | if (!Make_OODate(gn)) { | | 510 | if (!Make_OODate(gn)) { |
513 | gn->made = UPTODATE; | | 511 | gn->made = UPTODATE; |
514 | DEBUG0(MAKE, "up-to-date.\n"); | | 512 | DEBUG0(MAKE, "up-to-date.\n"); |
515 | goto cohorts; | | 513 | goto cohorts; |
516 | } else | | 514 | } else |
517 | DEBUG0(MAKE, "out-of-date.\n"); | | 515 | DEBUG0(MAKE, "out-of-date.\n"); |
518 | | | 516 | |
519 | /* | | 517 | /* |
520 | * If the user is just seeing if something is out-of-date, exit now | | 518 | * If the user is just seeing if something is out-of-date, exit now |
521 | * to tell him/her "yes". | | 519 | * to tell him/her "yes". |
522 | */ | | 520 | */ |
523 | if (opts.queryFlag) { | | 521 | if (opts.queryFlag) { |
524 | exit(1); | | 522 | exit(1); |
525 | } | | 523 | } |
526 | | | 524 | |
527 | /* | | 525 | /* |
528 | * We need to be re-made. We also have to make sure we've got a $? | | 526 | * We need to be re-made. We also have to make sure we've got a $? |
529 | * variable. To be nice, we also define the $> variable using | | 527 | * variable. To be nice, we also define the $> variable using |
530 | * Make_DoAllVar(). | | 528 | * Make_DoAllVar(). |
531 | */ | | 529 | */ |
532 | Make_DoAllVar(gn); | | 530 | Make_DoAllVar(gn); |
533 | | | 531 | |
534 | /* | | 532 | /* |
535 | * Alter our type to tell if errors should be ignored or things | | 533 | * Alter our type to tell if errors should be ignored or things |
536 | * should not be printed so CompatRunCommand knows what to do. | | 534 | * should not be printed so CompatRunCommand knows what to do. |
537 | */ | | 535 | */ |
538 | if (Targ_Ignore(gn)) | | 536 | if (Targ_Ignore(gn)) |
539 | gn->type |= OP_IGNORE; | | 537 | gn->type |= OP_IGNORE; |
540 | if (Targ_Silent(gn)) | | 538 | if (Targ_Silent(gn)) |
541 | gn->type |= OP_SILENT; | | 539 | gn->type |= OP_SILENT; |
542 | | | 540 | |
543 | if (Job_CheckCommands(gn, Fatal)) { | | 541 | if (Job_CheckCommands(gn, Fatal)) { |
544 | /* | | 542 | /* |
545 | * Our commands are ok, but we still have to worry about the -t | | 543 | * Our commands are ok, but we still have to worry about the -t |
546 | * flag... | | 544 | * flag... |
547 | */ | | 545 | */ |
548 | if (!opts.touchFlag || (gn->type & OP_MAKE)) { | | 546 | if (!opts.touchFlag || (gn->type & OP_MAKE)) { |
549 | curTarg = gn; | | 547 | curTarg = gn; |
550 | #ifdef USE_META | | 548 | #ifdef USE_META |
551 | if (useMeta && GNode_ShouldExecute(gn)) { | | 549 | if (useMeta && GNode_ShouldExecute(gn)) { |
552 | meta_job_start(NULL, gn); | | 550 | meta_job_start(NULL, gn); |
553 | } | | 551 | } |
554 | #endif | | 552 | #endif |
555 | RunCommands(gn); | | 553 | RunCommands(gn); |
556 | curTarg = NULL; | | 554 | curTarg = NULL; |
557 | } else { | | 555 | } else { |
558 | Job_Touch(gn, (gn->type & OP_SILENT) != 0); | | 556 | Job_Touch(gn, (gn->type & OP_SILENT) != 0); |
559 | } | | 557 | } |
560 | } else { | | 558 | } else { |
561 | gn->made = ERROR; | | 559 | gn->made = ERROR; |
562 | } | | 560 | } |
563 | #ifdef USE_META | | 561 | #ifdef USE_META |
564 | if (useMeta && GNode_ShouldExecute(gn)) { | | 562 | if (useMeta && GNode_ShouldExecute(gn)) { |
565 | if (meta_job_finish(NULL) != 0) | | 563 | if (meta_job_finish(NULL) != 0) |
566 | gn->made = ERROR; | | 564 | gn->made = ERROR; |
567 | } | | 565 | } |
568 | #endif | | 566 | #endif |
569 | | | 567 | |
570 | if (gn->made != ERROR) { | | 568 | if (gn->made != ERROR) { |
571 | /* | | 569 | /* |
572 | * If the node was made successfully, mark it so, update | | 570 | * If the node was made successfully, mark it so, update |
573 | * its modification time and timestamp all its parents. Note | | 571 | * its modification time and timestamp all its parents. Note |
574 | * that for .ZEROTIME targets, the timestamping isn't done. | | 572 | * that for .ZEROTIME targets, the timestamping isn't done. |
575 | * This is to keep its state from affecting that of its parent. | | 573 | * This is to keep its state from affecting that of its parent. |
576 | */ | | 574 | */ |
577 | gn->made = MADE; | | 575 | gn->made = MADE; |
578 | pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; | | 576 | pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0; |
579 | if (!(gn->type & OP_EXEC)) { | | 577 | if (!(gn->type & OP_EXEC)) { |
580 | pgn->flags |= CHILDMADE; | | 578 | pgn->flags |= CHILDMADE; |
581 | Make_TimeStamp(pgn, gn); | | 579 | Make_TimeStamp(pgn, gn); |
582 | } | | 580 | } |
583 | } else if (opts.keepgoing) { | | 581 | } else if (opts.keepgoing) { |
584 | pgn->flags &= ~(unsigned)REMAKE; | | 582 | pgn->flags &= ~(unsigned)REMAKE; |
585 | } else { | | 583 | } else { |
586 | PrintOnError(gn, "\nStop."); | | 584 | PrintOnError(gn, "\nStop."); |
587 | exit(1); | | 585 | exit(1); |
588 | } | | 586 | } |
589 | } else if (gn->made == ERROR) { | | 587 | } else if (gn->made == ERROR) { |
590 | /* Already had an error when making this. Tell the parent to abort. */ | | 588 | /* Already had an error when making this. Tell the parent to abort. */ |
591 | pgn->flags &= ~(unsigned)REMAKE; | | 589 | pgn->flags &= ~(unsigned)REMAKE; |
592 | } else { | | 590 | } else { |
593 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { | | 591 | if (Lst_FindDatum(gn->implicitParents, pgn) != NULL) { |
594 | const char *target = GNode_VarTarget(gn); | | 592 | const char *target = GNode_VarTarget(gn); |
595 | Var_Set(IMPSRC, target != NULL ? target : "", pgn); | | 593 | Var_Set(IMPSRC, target != NULL ? target : "", pgn); |
596 | } | | 594 | } |
597 | switch(gn->made) { | | 595 | switch(gn->made) { |
598 | case BEINGMADE: | | 596 | case BEINGMADE: |
599 | Error("Graph cycles through %s", gn->name); | | 597 | Error("Graph cycles through %s", gn->name); |
600 | gn->made = ERROR; | | 598 | gn->made = ERROR; |
601 | pgn->flags &= ~(unsigned)REMAKE; | | 599 | pgn->flags &= ~(unsigned)REMAKE; |
602 | break; | | 600 | break; |
603 | case MADE: | | 601 | case MADE: |
604 | if ((gn->type & OP_EXEC) == 0) { | | 602 | if ((gn->type & OP_EXEC) == 0) { |
605 | pgn->flags |= CHILDMADE; | | 603 | pgn->flags |= CHILDMADE; |
606 | Make_TimeStamp(pgn, gn); | | 604 | Make_TimeStamp(pgn, gn); |
607 | } | | 605 | } |
608 | break; | | 606 | break; |
609 | case UPTODATE: | | 607 | case UPTODATE: |
610 | if ((gn->type & OP_EXEC) == 0) { | | 608 | if ((gn->type & OP_EXEC) == 0) { |
611 | Make_TimeStamp(pgn, gn); | | 609 | Make_TimeStamp(pgn, gn); |
612 | } | | 610 | } |
613 | break; | | 611 | break; |
614 | default: | | 612 | default: |
615 | break; | | 613 | break; |
616 | } | | 614 | } |
617 | } | | 615 | } |
618 | | | 616 | |
619 | cohorts: | | 617 | cohorts: |
620 | MakeNodes(gn->cohorts, pgn); | | 618 | MakeNodes(gn->cohorts, pgn); |
621 | } | | 619 | } |
622 | | | 620 | |
623 | /* Initialize this module and start making. | | 621 | /* Initialize this module and start making. |
624 | * | | 622 | * |
625 | * Input: | | 623 | * Input: |
626 | * targs The target nodes to re-create | | 624 | * targs The target nodes to re-create |
627 | */ | | 625 | */ |
628 | void | | 626 | void |
629 | Compat_Run(GNodeList *targs) | | 627 | Compat_Run(GNodeList *targs) |
630 | { | | 628 | { |
631 | GNode *gn = NULL; /* Current root target */ | | 629 | GNode *gn = NULL; /* Current root target */ |
632 | int errors; /* Number of targets not remade due to errors */ | | 630 | int errors; /* Number of targets not remade due to errors */ |
633 | | | 631 | |
634 | if (!shellName) | | 632 | if (!shellName) |
635 | Shell_Init(); | | 633 | Shell_Init(); |
636 | | | 634 | |
637 | if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) | | 635 | if (bmake_signal(SIGINT, SIG_IGN) != SIG_IGN) |
638 | bmake_signal(SIGINT, CompatInterrupt); | | 636 | bmake_signal(SIGINT, CompatInterrupt); |
639 | if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) | | 637 | if (bmake_signal(SIGTERM, SIG_IGN) != SIG_IGN) |
640 | bmake_signal(SIGTERM, CompatInterrupt); | | 638 | bmake_signal(SIGTERM, CompatInterrupt); |
641 | if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) | | 639 | if (bmake_signal(SIGHUP, SIG_IGN) != SIG_IGN) |
642 | bmake_signal(SIGHUP, CompatInterrupt); | | 640 | bmake_signal(SIGHUP, CompatInterrupt); |
643 | if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) | | 641 | if (bmake_signal(SIGQUIT, SIG_IGN) != SIG_IGN) |
644 | bmake_signal(SIGQUIT, CompatInterrupt); | | 642 | bmake_signal(SIGQUIT, CompatInterrupt); |
645 | | | 643 | |
646 | /* Create the .END node now, to keep the (debug) output of the | | 644 | /* Create the .END node now, to keep the (debug) output of the |
647 | * counter.mk test the same as before 2020-09-23. This implementation | | 645 | * counter.mk test the same as before 2020-09-23. This implementation |
648 | * detail probably doesn't matter though. */ | | 646 | * detail probably doesn't matter though. */ |
649 | (void)Targ_GetEndNode(); | | 647 | (void)Targ_GetEndNode(); |
650 | /* | | 648 | /* |
651 | * If the user has defined a .BEGIN target, execute the commands attached | | 649 | * If the user has defined a .BEGIN target, execute the commands attached |
652 | * to it. | | 650 | * to it. |
653 | */ | | 651 | */ |
654 | if (!opts.queryFlag) { | | 652 | if (!opts.queryFlag) { |
655 | gn = Targ_FindNode(".BEGIN"); | | 653 | gn = Targ_FindNode(".BEGIN"); |
656 | if (gn != NULL) { | | 654 | if (gn != NULL) { |
657 | Compat_Make(gn, gn); | | 655 | Compat_Make(gn, gn); |
658 | if (gn->made == ERROR) { | | 656 | if (gn->made == ERROR) { |
659 | PrintOnError(gn, "\nStop."); | | 657 | PrintOnError(gn, "\nStop."); |
660 | exit(1); | | 658 | exit(1); |
661 | } | | 659 | } |
662 | } | | 660 | } |
663 | } | | 661 | } |
664 | | | 662 | |
665 | /* | | 663 | /* |
666 | * Expand .USE nodes right now, because they can modify the structure | | 664 | * Expand .USE nodes right now, because they can modify the structure |
667 | * of the tree. | | 665 | * of the tree. |
668 | */ | | 666 | */ |
669 | Make_ExpandUse(targs); | | 667 | Make_ExpandUse(targs); |
670 | | | 668 | |
671 | /* | | 669 | /* |
672 | * For each entry in the list of targets to create, call Compat_Make on | | 670 | * For each entry in the list of targets to create, call Compat_Make on |
673 | * it to create the thing. Compat_Make will leave the 'made' field of gn | | 671 | * it to create the thing. Compat_Make will leave the 'made' field of gn |
674 | * in one of several states: | | 672 | * in one of several states: |
675 | * UPTODATE gn was already up-to-date | | 673 | * UPTODATE gn was already up-to-date |
676 | * MADE gn was recreated successfully | | 674 | * MADE gn was recreated successfully |
677 | * ERROR An error occurred while gn was being created | | 675 | * ERROR An error occurred while gn was being created |
678 | * ABORTED gn was not remade because one of its inferiors | | 676 | * ABORTED gn was not remade because one of its inferiors |
679 | * could not be made due to errors. | | 677 | * could not be made due to errors. |
680 | */ | | 678 | */ |
681 | errors = 0; | | 679 | errors = 0; |
682 | while (!Lst_IsEmpty(targs)) { | | 680 | while (!Lst_IsEmpty(targs)) { |
683 | gn = Lst_Dequeue(targs); | | 681 | gn = Lst_Dequeue(targs); |
684 | Compat_Make(gn, gn); | | 682 | Compat_Make(gn, gn); |
685 | | | 683 | |
686 | if (gn->made == UPTODATE) { | | 684 | if (gn->made == UPTODATE) { |
687 | printf("`%s' is up to date.\n", gn->name); | | 685 | printf("`%s' is up to date.\n", gn->name); |
688 | } else if (gn->made == ABORTED) { | | 686 | } else if (gn->made == ABORTED) { |
689 | printf("`%s' not remade because of errors.\n", gn->name); | | 687 | printf("`%s' not remade because of errors.\n", gn->name); |
690 | errors++; | | 688 | errors++; |
691 | } | | 689 | } |
692 | } | | 690 | } |
693 | | | 691 | |
694 | /* | | 692 | /* |
695 | * If the user has defined a .END target, run its commands. | | 693 | * If the user has defined a .END target, run its commands. |
696 | */ | | 694 | */ |
697 | if (errors == 0) { | | 695 | if (errors == 0) { |
698 | GNode *endNode = Targ_GetEndNode(); | | 696 | GNode *endNode = Targ_GetEndNode(); |
699 | Compat_Make(endNode, endNode); | | 697 | Compat_Make(endNode, endNode); |
700 | /* XXX: Did you mean endNode->made instead of gn->made? */ | | 698 | /* XXX: Did you mean endNode->made instead of gn->made? */ |
701 | if (gn->made == ERROR) { | | 699 | if (gn->made == ERROR) { |
702 | PrintOnError(gn, "\nStop."); | | 700 | PrintOnError(gn, "\nStop."); |
703 | exit(1); | | 701 | exit(1); |
704 | } | | 702 | } |
705 | } | | 703 | } |
706 | } | | 704 | } |