1 /** $MirOS: src/usr.bin/make/compat.c,v 1.7 2009/07/25 17:40:38 tg Exp $ */
2 /* $OpenPackages$ */
3 /* $OpenBSD: compat.c,v 1.51 2007/01/04 17:55:35 espie Exp $ */
4 /* $NetBSD: compat.c,v 1.14 1996/11/06 17:59:01 christos Exp $ */
5
6 /*
7 * Copyright (c) 2005, 2009 Thorsten Glaser
8 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
9 * Copyright (c) 1988, 1989 by Adam de Boor
10 * Copyright (c) 1989 by Berkeley Softworks
11 * All rights reserved.
12 *
13 * This code is derived from software contributed to Berkeley by
14 * Adam de Boor.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <limits.h>
47 #include <signal.h>
48 #include <stddef.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include "config.h"
54 #include "defines.h"
55 #include "dir.h"
56 #include "job.h"
57 #include "compat.h"
58 #include "suff.h"
59 #include "var.h"
60 #include "targ.h"
61 #include "error.h"
62 #include "str.h"
63 #include "extern.h"
64 #include "memory.h"
65 #include "gnode.h"
66 #include "make.h"
67 #include "timestamp.h"
68 #include "lst.h"
69 #include "pathnames.h"
70
71 __RCSID("$MirOS: src/usr.bin/make/compat.c,v 1.7 2009/07/25 17:40:38 tg Exp $");
72
73 /* The following array is used to make a fast determination of which
74 * characters are interpreted specially by the shell. If a command
75 * contains any of these characters, it is executed by the shell, not
76 * directly by us. */
77
78 static char meta[256];
79
80 static GNode *ENDNode;
81 static void CompatInterrupt(int);
82 static int CompatRunCommand(LstNode, void *);
83 static void CompatMake(void *, void *);
84 static int shellneed(char **);
85
86 static volatile sig_atomic_t interrupted;
87
88 static void
CompatInterrupt(int signo)89 CompatInterrupt(int signo)
90 {
91 if (interrupted != SIGINT)
92 interrupted = signo;
93 }
94
95 /*-
96 *-----------------------------------------------------------------------
97 * shellneed --
98 *
99 * Results:
100 * Returns 1 if a specified set of arguments
101 * must be executed by the shell,
102 * 0 if it can be run via execve, and -1 if the command can be
103 * handled internally
104 *
105 * Side Effects:
106 * May modify the process umask
107 *-----------------------------------------------------------------------
108 */
109 static int
shellneed(char ** av)110 shellneed(char **av)
111 {
112 const char **p;
113 const char *runsh[] = {
114 ".", ":", "[[", "alias", "bg", "bind", "break", "builtin",
115 "cd", "command", "eval", "exec", "exit", "export", "fc", "fg",
116 "getopts", "jobs", "let", "print", "read", "readonly",
117 "return", "set", "shift", "times", "trap", "typeset",
118 "ulimit", "unalias", "unset", "wait", "whence", NULL
119 };
120
121 /* FIXME most of these ARE actual no-ops */
122 for (p = runsh; *p; p++)
123 if (strcmp(av[0], *p) == 0)
124 return 1;
125
126 if (strcmp(av[0], "umask") == 0) {
127 long umi;
128 char *ep = NULL;
129 mode_t um;
130
131 if (av[1] != NULL) {
132 umi = strtol(av[1], &ep, 8);
133 if (ep == NULL)
134 return 1;
135 um = umi;
136 }
137 else {
138 um = umask(0);
139 printf("%o\n", um);
140 }
141 (void)umask(um);
142 return -1;
143 }
144
145 return 0;
146 }
147
148 /*-
149 *-----------------------------------------------------------------------
150 * CompatRunCommand --
151 * Execute the next command for a target. If the command returns an
152 * error, the node's made field is set to ERROR and creation stops.
153 *
154 * Results:
155 * 0 in case of error, 1 if ok.
156 *
157 * Side Effects:
158 * The node's 'made' field may be set to ERROR.
159 *-----------------------------------------------------------------------
160 */
161 static int
CompatRunCommand(LstNode cmdNode,void * gnp)162 CompatRunCommand(LstNode cmdNode,/* Command to execute */
163 void *gnp) /* Node from which the command came */
164 {
165 char *cmdStart; /* Start of expanded command */
166 char *cp, *bp = NULL;
167 bool silent, /* Don't print command */
168 doExecute; /* Execute the command */
169 volatile bool errCheck; /* Check errors */
170 int reason; /* Reason for child's death */
171 int status; /* Description of child's death */
172 pid_t cpid; /* Child actually found */
173 pid_t statfk; /* Status of fork */
174 char ** volatile av; /* Argument vector for thing to exec */
175 int argc; /* Number of arguments in av or 0 if not
176 * dynamically allocated */
177 bool local; /* true if command should be executed
178 * locally */
179 char *cmd = (char *)Lst_Datum(cmdNode);
180 GNode *gn = (GNode *)gnp;
181 static char *shargv[4] = { (char *)_PATH_MIRBSDKSH };
182
183 silent = gn->type & OP_SILENT;
184 errCheck = !(gn->type & OP_IGNORE);
185 doExecute = !noExecute;
186
187 cmdStart = Var_Subst(cmd, &gn->context, false);
188
189 /* brk_string will return an argv with a NULL in av[0], thus causing
190 * execvp to choke and die horribly. Besides, how can we execute a null
191 * command? In any case, we warn the user that the command expanded to
192 * nothing (is this the right thing to do?). */
193
194 if (*cmdStart == '\0') {
195 free(cmdStart);
196 Error("%s expands to empty string", cmd);
197 return 1;
198 } else
199 cmd = cmdStart;
200 Lst_Replace(cmdNode, cmdStart);
201
202 if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) {
203 Lst_AtEnd(&ENDNode->commands, cmdStart);
204 return 1;
205 } else if (strcmp(cmdStart, "...") == 0) {
206 gn->type |= OP_SAVE_CMDS;
207 return 1;
208 }
209
210 for (;; cmd++) {
211 if (*cmd == '@')
212 silent = DEBUG(LOUD) ? false : true;
213 else if (*cmd == '-')
214 errCheck = false;
215 else if (*cmd == '+')
216 doExecute = true;
217 else
218 break;
219 }
220
221 while (isspace(*cmd))
222 cmd++;
223
224 /* Search for meta characters in the command. If there are no meta
225 * characters, there's no need to execute a shell to execute the
226 * command. */
227 for (cp = cmd; !meta[(unsigned char)*cp]; cp++) {
228 continue;
229 }
230
231 /* Print the command before echoing if we're not supposed to be quiet for
232 * this one. We also print the command if -n given. */
233 if (!silent || noExecute) {
234 printf("%s\n", cmd);
235 fflush(stdout);
236 }
237
238 /* If we're not supposed to execute any commands, this is as far as
239 * we go... */
240 if (!doExecute)
241 return 1;
242
243 if (*cp != '\0') {
244 /* If *cp isn't the null character, we hit a "meta" character and
245 * need to pass the command off to the shell. We give the shell the
246 * -e flag as well as -c if it's supposed to exit when it hits an
247 * error. */
248
249 shargv[1] = (char *)(errCheck ? "-ec" : "-c");
250 shargv[2] = cmd;
251 shargv[3] = NULL;
252 av = shargv;
253 argc = 0;
254 } else {
255 /* No meta-characters, so probably no need to exec a shell.
256 * Break the command into words to form an argument vector
257 * we can execute. */
258 av = brk_string(cmd, &argc, &bp);
259 switch (shellneed(av)) {
260 case -1: /* handled internally */
261 free(bp);
262 free(av);
263 return 1;
264 case 1:
265 shargv[1] = (char *)(errCheck ? "-ec" : "-c");
266 shargv[2] = cmd;
267 shargv[3] = NULL;
268 free(av);
269 free(bp);
270 bp = NULL;
271 av = shargv;
272 argc = 0;
273 break;
274 default: /* nothing needed */
275 break;
276 }
277 }
278
279 local = true;
280
281 /* Fork and execute the single command. If the fork fails, we abort. */
282 cpid = fork();
283 if (cpid == -1)
284 Fatal("Could not fork");
285 if (cpid == 0) {
286 if (local) {
287 execvp(av[0], av);
288 if (errno == ENOENT)
289 fprintf(stderr, "%s: not found\n", av[0]);
290 else
291 perror(av[0]);
292 } else
293 (void)execv(av[0], av);
294 _exit(1);
295 }
296 if (bp) {
297 free(av);
298 free(bp);
299 }
300 free(cmdStart);
301 Lst_Replace(cmdNode, NULL);
302
303 /* The child is off and running. Now all we can do is wait... */
304 while (1) {
305
306 while ((statfk = wait(&reason)) != cpid) {
307 if (statfk == -1 && errno != EINTR)
308 break;
309 }
310
311 if (interrupted)
312 break;
313
314 if (statfk != -1) {
315 if (WIFSTOPPED(reason))
316 status = WSTOPSIG(reason); /* stopped */
317 else if (WIFEXITED(reason)) {
318 status = WEXITSTATUS(reason); /* exited */
319 if (status != 0)
320 printf("*** Error code %d", status);
321 } else {
322 status = WTERMSIG(reason); /* signaled */
323 printf("*** Signal %d", status);
324 }
325
326
327 if (!WIFEXITED(reason) || status != 0) {
328 if (errCheck) {
329 gn->made = ERROR;
330 if (keepgoing)
331 /* Abort the current target, but let others
332 * continue. */
333 printf(" (continuing)\n");
334 } else {
335 /* Continue executing commands for this target.
336 * If we return 0, this will happen... */
337 printf(" (ignored)\n");
338 status = 0;
339 }
340 }
341 return !status;
342 } else
343 Fatal("error in wait: %d", statfk);
344 /*NOTREACHED*/
345 }
346
347 /* This is reached only if interrupted */
348 if (!Targ_Precious(gn)) {
349 char *file = Varq_Value(TARGET_INDEX, gn);
350
351 if (!noExecute && eunlink(file) != -1)
352 Error("*** %s removed\n", file);
353 }
354 if (interrupted == SIGINT) {
355 GNode *i = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);
356 signal(SIGINT, SIG_IGN);
357 signal(SIGTERM, SIG_IGN);
358 signal(SIGHUP, SIG_IGN);
359 signal(SIGQUIT, SIG_IGN);
360 interrupted = 0;
361 if (i != NULL)
362 Lst_ForEachNodeWhile(&i->commands, CompatRunCommand, i);
363 exit(SIGINT);
364 }
365 exit(interrupted);
366 }
367
368 /*-
369 *-----------------------------------------------------------------------
370 * CompatMake --
371 * Make a target.
372 *
373 * Side Effects:
374 * If an error is detected and not being ignored, the process exits.
375 *-----------------------------------------------------------------------
376 */
377 static void
CompatMake(void * gnp,void * pgnp)378 CompatMake(void *gnp, /* The node to make */
379 void *pgnp) /* Parent to abort if necessary */
380 {
381 GNode *gn = (GNode *)gnp;
382 GNode *pgn = (GNode *)pgnp;
383
384 if (pgn->type & OP_MADE) {
385 (void)Dir_MTime(gn);
386 gn->made = UPTODATE;
387 }
388
389 if (gn->type & OP_USE) {
390 Make_HandleUse(gn, pgn);
391 } else if (gn->made == UNMADE) {
392 /* First mark ourselves to be made, then apply whatever transformations
393 * the suffix module thinks are necessary. Once that's done, we can
394 * descend and make all our children. If any of them has an error
395 * but the -k flag was given, our 'make' field will be set false again.
396 * This is our signal to not attempt to do anything but abort our
397 * parent as well. */
398 gn->make = true;
399 gn->made = BEINGMADE;
400 Suff_FindDeps(gn);
401 Lst_ForEach(&gn->children, CompatMake, gn);
402 if (!gn->make) {
403 gn->made = ABORTED;
404 pgn->make = false;
405 return;
406 }
407
408 if (Lst_Member(&gn->iParents, pgn) != NULL) {
409 Varq_Set(IMPSRC_INDEX, Varq_Value(TARGET_INDEX, gn), pgn);
410 }
411
412 /* All the children were made ok. Now cmtime contains the modification
413 * time of the newest child, we need to find out if we exist and when
414 * we were modified last. The criteria for datedness are defined by the
415 * Make_OODate function. */
416 if (DEBUG(MAKE))
417 printf("Examining %s...", gn->name);
418 if (! Make_OODate(gn)) {
419 gn->made = UPTODATE;
420 if (DEBUG(MAKE))
421 printf("up-to-date.\n");
422 return;
423 } else if (DEBUG(MAKE))
424 printf("out-of-date.\n");
425
426 /* If the user is just seeing if something is out-of-date, exit now
427 * to tell him/her "yes". */
428 if (queryFlag)
429 exit(-1);
430
431 /* We need to be re-made. We also have to make sure we've got a $?
432 * variable. To be nice, we also define the $> variable using
433 * Make_DoAllVar(). */
434 Make_DoAllVar(gn);
435
436 /* Alter our type to tell if errors should be ignored or things
437 * should not be printed so CompatRunCommand knows what to do. */
438 if (Targ_Ignore(gn))
439 gn->type |= OP_IGNORE;
440 if (Targ_Silent(gn))
441 gn->type |= OP_SILENT;
442
443 if (Job_CheckCommands(gn, Fatal)) {
444 /* Our commands are ok, but we still have to worry about the -t
445 * flag... */
446 if (!touchFlag)
447 Lst_ForEachNodeWhile(&gn->commands, CompatRunCommand, gn);
448 else
449 Job_Touch(gn, gn->type & OP_SILENT);
450 } else
451 gn->made = ERROR;
452
453 if (gn->made != ERROR) {
454 /* If the node was made successfully, mark it so, update
455 * its modification time and timestamp all its parents. Note
456 * that for .ZEROTIME targets, the timestamping isn't done.
457 * This is to keep its state from affecting that of its parent. */
458 gn->made = MADE;
459 #ifndef RECHECK
460 /* We can't re-stat the thing, but we can at least take care of
461 * rules where a target depends on a source that actually creates
462 * the target, but only if it has changed, e.g.
463 *
464 * parse.h : parse.o
465 *
466 * parse.o : parse.y
467 * yacc -d parse.y
468 * cc -c y.tab.c
469 * mv y.tab.o parse.o
470 * cmp -s y.tab.h parse.h || mv y.tab.h parse.h
471 *
472 * In this case, if the definitions produced by yacc haven't
473 * changed from before, parse.h won't have been updated and
474 * gn->mtime will reflect the current modification time for
475 * parse.h. This is something of a kludge, I admit, but it's a
476 * useful one..
477 *
478 * XXX: People like to use a rule like
479 *
480 * FRC:
481 *
482 * To force things that depend on FRC to be made, so we have to
483 * check for gn->children being empty as well... */
484 if (!Lst_IsEmpty(&gn->commands) || Lst_IsEmpty(&gn->children))
485 gn->mtime = now;
486 #else
487 /* This is what Make does and it's actually a good thing, as it
488 * allows rules like
489 *
490 * cmp -s y.tab.h parse.h || cp y.tab.h parse.h
491 *
492 * to function as intended. Unfortunately, thanks to the stateless
493 * nature of NFS (and the speed of this program), there are times
494 * when the modification time of a file created on a remote
495 * machine will not be modified before the stat() implied by
496 * the Dir_MTime occurs, thus leading us to believe that the file
497 * is unchanged, wreaking havoc with files that depend on this one.
498 *
499 * I have decided it is better to make too much than to make too
500 * little, so this stuff is commented out unless you're sure it's
501 * ok.
502 * -- ardeb 1/12/88
503 */
504 if (noExecute || is_out_of_date(Dir_MTime(gn)))
505 gn->mtime = now;
506 if (is_strictly_before(gn->mtime, gn->cmtime))
507 gn->mtime = gn->cmtime;
508 if (DEBUG(MAKE))
509 printf("update time: %s\n", Targ_FmtTime(gn->mtime));
510 #endif
511 if (!(gn->type & OP_EXEC)) {
512 pgn->childMade = true;
513 Make_TimeStamp(pgn, gn);
514 }
515 } else if (keepgoing)
516 pgn->make = false;
517 else {
518
519 if (gn->lineno)
520 printf("\n\nStop in %s (line %lu of %s).\n",
521 Var_Value(".CURDIR"),
522 (unsigned long)gn->lineno,
523 gn->fname);
524 else
525 printf("\n\nStop in %s.\n", Var_Value(".CURDIR"));
526 exit(1);
527 }
528 } else if (gn->made == ERROR)
529 /* Already had an error when making this beastie. Tell the parent
530 * to abort. */
531 pgn->make = false;
532 else {
533 if (Lst_Member(&gn->iParents, pgn) != NULL) {
534 Varq_Set(IMPSRC_INDEX, Varq_Value(TARGET_INDEX, gn), pgn);
535 }
536 switch (gn->made) {
537 case BEINGMADE:
538 Error("Graph cycles through %s\n", gn->name);
539 gn->made = ERROR;
540 pgn->make = false;
541 break;
542 case MADE:
543 if ((gn->type & OP_EXEC) == 0) {
544 pgn->childMade = true;
545 Make_TimeStamp(pgn, gn);
546 }
547 break;
548 case UPTODATE:
549 if ((gn->type & OP_EXEC) == 0)
550 Make_TimeStamp(pgn, gn);
551 break;
552 default:
553 break;
554 }
555 }
556 }
557
558 void
Compat_Run(Lst targs)559 Compat_Run(Lst targs) /* List of target nodes to re-create */
560 {
561 const char *cp; /* Pointer to string of shell meta-characters */
562 GNode *gn = NULL; /* Current root target */
563 int errors; /* Number of targets not remade due to errors */
564
565 signal(SIGINT, CompatInterrupt);
566 signal(SIGTERM, CompatInterrupt);
567 signal(SIGHUP, CompatInterrupt);
568 signal(SIGQUIT, CompatInterrupt);
569
570 for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++)
571 meta[(unsigned char) *cp] = 1;
572 /* The null character serves as a sentinel in the string. */
573 meta[0] = 1;
574
575 ENDNode = Targ_FindNode(".END", TARG_CREATE);
576 /* If the user has defined a .BEGIN target, execute the commands attached
577 * to it. */
578 if (!queryFlag) {
579 gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);
580 if (gn != NULL) {
581 Lst_ForEachNodeWhile(&gn->commands, CompatRunCommand, gn);
582 if (gn->made == ERROR) {
583 printf("\n\nStop.\n");
584 exit(1);
585 }
586 }
587 }
588
589 /* For each entry in the list of targets to create, call CompatMake on
590 * it to create the thing. CompatMake will leave the 'made' field of gn
591 * in one of several states:
592 * UPTODATE gn was already up-to-date
593 * MADE gn was recreated successfully
594 * ERROR An error occurred while gn was being created
595 * ABORTED gn was not remade because one of its inferiors
596 * could not be made due to errors. */
597 errors = 0;
598 while ((gn = (GNode *)Lst_DeQueue(targs)) != NULL) {
599 CompatMake(gn, gn);
600
601 if (gn->made == UPTODATE)
602 printf("`%s' is up to date.\n", gn->name);
603 else if (gn->made == ABORTED) {
604 printf("`%s' not remade because of errors.\n", gn->name);
605 errors += 1;
606 }
607 }
608
609 /* If the user has defined a .END target, run its commands. */
610 if (errors == 0)
611 Lst_ForEachNodeWhile(&ENDNode->commands, CompatRunCommand, ENDNode);
612 }
613