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