1*40393Sbostic /*- 2*40393Sbostic * compat.c -- 3*40393Sbostic * The routines in this file implement the full-compatibility 4*40393Sbostic * mode of PMake. Most of the special functionality of PMake 5*40393Sbostic * is available in this mode. Things not supported: 6*40393Sbostic * - different shells. 7*40393Sbostic * - friendly variable substitution. 8*40393Sbostic * 9*40393Sbostic * Copyright (c) 1988, 1989 by the Regents of the University of California 10*40393Sbostic * Copyright (c) 1988, 1989 by Adam de Boor 11*40393Sbostic * Copyright (c) 1989 by Berkeley Softworks 12*40393Sbostic * 13*40393Sbostic * Permission to use, copy, modify, and distribute this 14*40393Sbostic * software and its documentation for any non-commercial purpose 15*40393Sbostic * and without fee is hereby granted, provided that the above copyright 16*40393Sbostic * notice appears in all copies. The University of California, 17*40393Sbostic * Berkeley Softworks and Adam de Boor make no representations about 18*40393Sbostic * the suitability of this software for any purpose. It is provided 19*40393Sbostic * "as is" without express or implied warranty. 20*40393Sbostic * 21*40393Sbostic * Interface: 22*40393Sbostic * Compat_Run Initialize things for this module and recreate 23*40393Sbostic * thems as need creatin' 24*40393Sbostic */ 25*40393Sbostic #ifndef lint 26*40393Sbostic static char *rcsid = "$Id: compat.c,v 1.24 89/11/14 13:43:41 adam Exp $ SPRITE (Berkeley)"; 27*40393Sbostic #endif lint 28*40393Sbostic 29*40393Sbostic #include <stdio.h> 30*40393Sbostic #include <sys/types.h> 31*40393Sbostic #include <sys/signal.h> 32*40393Sbostic #include <sys/wait.h> 33*40393Sbostic #include <sys/errno.h> 34*40393Sbostic #include <ctype.h> 35*40393Sbostic #include "make.h" 36*40393Sbostic extern int errno; 37*40393Sbostic 38*40393Sbostic /* 39*40393Sbostic * The following array is used to make a fast determination of which 40*40393Sbostic * characters are interpreted specially by the shell. If a command 41*40393Sbostic * contains any of these characters, it is executed by the shell, not 42*40393Sbostic * directly by us. 43*40393Sbostic */ 44*40393Sbostic 45*40393Sbostic static char meta[256]; 46*40393Sbostic 47*40393Sbostic static GNode *curTarg = NILGNODE; 48*40393Sbostic static GNode *ENDNode; 49*40393Sbostic static int CompatRunCommand(); 50*40393Sbostic 51*40393Sbostic /*- 52*40393Sbostic *----------------------------------------------------------------------- 53*40393Sbostic * CompatInterrupt -- 54*40393Sbostic * Interrupt the creation of the current target and remove it if 55*40393Sbostic * it ain't precious. 56*40393Sbostic * 57*40393Sbostic * Results: 58*40393Sbostic * None. 59*40393Sbostic * 60*40393Sbostic * Side Effects: 61*40393Sbostic * The target is removed and the process exits. If .INTERRUPT exists, 62*40393Sbostic * its commands are run first WITH INTERRUPTS IGNORED.. 63*40393Sbostic * 64*40393Sbostic *----------------------------------------------------------------------- 65*40393Sbostic */ 66*40393Sbostic static int 67*40393Sbostic CompatInterrupt (signo) 68*40393Sbostic int signo; 69*40393Sbostic { 70*40393Sbostic GNode *gn; 71*40393Sbostic 72*40393Sbostic if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) { 73*40393Sbostic char *file = Var_Value (TARGET, curTarg); 74*40393Sbostic 75*40393Sbostic if (unlink (file) == SUCCESS) { 76*40393Sbostic printf ("*** %s removed\n", file); 77*40393Sbostic } 78*40393Sbostic 79*40393Sbostic /* 80*40393Sbostic * Run .INTERRUPT only if hit with interrupt signal 81*40393Sbostic */ 82*40393Sbostic if (signo == SIGINT) { 83*40393Sbostic gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 84*40393Sbostic if (gn != NILGNODE) { 85*40393Sbostic Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 86*40393Sbostic } 87*40393Sbostic } 88*40393Sbostic } 89*40393Sbostic exit (0); 90*40393Sbostic } 91*40393Sbostic 92*40393Sbostic /*- 93*40393Sbostic *----------------------------------------------------------------------- 94*40393Sbostic * CompatRunCommand -- 95*40393Sbostic * Execute the next command for a target. If the command returns an 96*40393Sbostic * error, the node's made field is set to ERROR and creation stops. 97*40393Sbostic * 98*40393Sbostic * Results: 99*40393Sbostic * 0 if the command succeeded, 1 if an error occurred. 100*40393Sbostic * 101*40393Sbostic * Side Effects: 102*40393Sbostic * The node's 'made' field may be set to ERROR. 103*40393Sbostic * 104*40393Sbostic *----------------------------------------------------------------------- 105*40393Sbostic */ 106*40393Sbostic static int 107*40393Sbostic CompatRunCommand (cmd, gn) 108*40393Sbostic char *cmd; /* Command to execute */ 109*40393Sbostic GNode *gn; /* Node from which the command came */ 110*40393Sbostic { 111*40393Sbostic char *cmdStart; /* Start of expanded command */ 112*40393Sbostic register char *cp; 113*40393Sbostic Boolean silent, /* Don't print command */ 114*40393Sbostic errCheck; /* Check errors */ 115*40393Sbostic union wait reason; /* Reason for child's death */ 116*40393Sbostic int status; /* Description of child's death */ 117*40393Sbostic int cpid; /* Child actually found */ 118*40393Sbostic int numWritten; /* Number of bytes written for error message */ 119*40393Sbostic ReturnStatus stat; /* Status of fork */ 120*40393Sbostic LstNode cmdNode; /* Node where current command is located */ 121*40393Sbostic char **av; /* Argument vector for thing to exec */ 122*40393Sbostic int argc; /* Number of arguments in av or 0 if not 123*40393Sbostic * dynamically allocated */ 124*40393Sbostic Boolean local; /* TRUE if command should be executed 125*40393Sbostic * locally */ 126*40393Sbostic 127*40393Sbostic silent = gn->type & OP_SILENT; 128*40393Sbostic errCheck = !(gn->type & OP_IGNORE); 129*40393Sbostic 130*40393Sbostic cmdNode = Lst_Member (gn->commands, (ClientData)cmd); 131*40393Sbostic cmdStart = Var_Subst (cmd, gn, FALSE); 132*40393Sbostic 133*40393Sbostic /* 134*40393Sbostic * Str_BreakString will return an argv with a NULL in av[1], thus causing 135*40393Sbostic * execvp to choke and die horribly. Besides, how can we execute a null 136*40393Sbostic * command? In any case, we warn the user that the command expanded to 137*40393Sbostic * nothing (is this the right thing to do?). 138*40393Sbostic */ 139*40393Sbostic 140*40393Sbostic if (*cmdStart == '\0') { 141*40393Sbostic if (!noWarnings) { 142*40393Sbostic Error("%s expands to empty string", cmd); 143*40393Sbostic } 144*40393Sbostic return(0); 145*40393Sbostic } else { 146*40393Sbostic cmd = cmdStart; 147*40393Sbostic } 148*40393Sbostic Lst_Replace (cmdNode, (ClientData)cmdStart); 149*40393Sbostic 150*40393Sbostic if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 151*40393Sbostic (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart); 152*40393Sbostic return(0); 153*40393Sbostic } else if (strcmp(cmdStart, "...") == 0) { 154*40393Sbostic gn->type |= OP_SAVE_CMDS; 155*40393Sbostic return(0); 156*40393Sbostic } 157*40393Sbostic 158*40393Sbostic while ((*cmd == '@') || (*cmd == '-')) { 159*40393Sbostic if (*cmd == '@') { 160*40393Sbostic silent = TRUE; 161*40393Sbostic } else { 162*40393Sbostic errCheck = FALSE; 163*40393Sbostic } 164*40393Sbostic cmd++; 165*40393Sbostic } 166*40393Sbostic 167*40393Sbostic /* 168*40393Sbostic * Search for meta characters in the command. If there are no meta 169*40393Sbostic * characters, there's no need to execute a shell to execute the 170*40393Sbostic * command. 171*40393Sbostic */ 172*40393Sbostic for (cp = cmd; !meta[*cp]; cp++) { 173*40393Sbostic continue; 174*40393Sbostic } 175*40393Sbostic 176*40393Sbostic /* 177*40393Sbostic * Print the command before echoing if we're not supposed to be quiet for 178*40393Sbostic * this one. We also print the command if -n given. 179*40393Sbostic */ 180*40393Sbostic if (!silent || noExecute) { 181*40393Sbostic printf ("%s\n", cmd); 182*40393Sbostic fflush(stdout); 183*40393Sbostic } 184*40393Sbostic 185*40393Sbostic /* 186*40393Sbostic * If we're not supposed to execute any commands, this is as far as 187*40393Sbostic * we go... 188*40393Sbostic */ 189*40393Sbostic if (noExecute) { 190*40393Sbostic return (0); 191*40393Sbostic } 192*40393Sbostic 193*40393Sbostic if (*cp != '\0') { 194*40393Sbostic /* 195*40393Sbostic * If *cp isn't the null character, we hit a "meta" character and 196*40393Sbostic * need to pass the command off to the shell. We give the shell the 197*40393Sbostic * -e flag as well as -c if it's supposed to exit when it hits an 198*40393Sbostic * error. 199*40393Sbostic */ 200*40393Sbostic static char *shargv[4] = { "/bin/sh" }; 201*40393Sbostic 202*40393Sbostic shargv[1] = (errCheck ? "-ec" : "-c"); 203*40393Sbostic shargv[2] = cmd; 204*40393Sbostic shargv[3] = (char *)NULL; 205*40393Sbostic av = shargv; 206*40393Sbostic argc = 0; 207*40393Sbostic } else { 208*40393Sbostic /* 209*40393Sbostic * No meta-characters, so no need to exec a shell. Break the command 210*40393Sbostic * into words to form an argument vector we can execute. 211*40393Sbostic * Str_BreakString sticks our name in av[0], so we have to 212*40393Sbostic * skip over it... 213*40393Sbostic */ 214*40393Sbostic av = Str_BreakString(cmd, " \t", "\n", &argc); 215*40393Sbostic av += 1; 216*40393Sbostic } 217*40393Sbostic 218*40393Sbostic /* 219*40393Sbostic * If the job has not been marked unexportable, tell the Rmt module we've 220*40393Sbostic * got something for it...local is set TRUE if the job should be run 221*40393Sbostic * locally. 222*40393Sbostic */ 223*40393Sbostic if (!(gn->type & OP_NOEXPORT)) { 224*40393Sbostic local = !Rmt_Begin(av[0], av, gn); 225*40393Sbostic } else { 226*40393Sbostic local = TRUE; 227*40393Sbostic } 228*40393Sbostic 229*40393Sbostic /* 230*40393Sbostic * Fork and execute the single command. If the fork fails, we abort. 231*40393Sbostic */ 232*40393Sbostic cpid = vfork(); 233*40393Sbostic if (cpid < 0) { 234*40393Sbostic Fatal("Could not fork"); 235*40393Sbostic } 236*40393Sbostic if (cpid == 0) { 237*40393Sbostic if (local) { 238*40393Sbostic execvp(av[0], av); 239*40393Sbostic numWritten = write (2, av[0], strlen (av[0])); 240*40393Sbostic numWritten = write (2, ": not found\n", sizeof(": not found")); 241*40393Sbostic } else { 242*40393Sbostic Rmt_Exec(av[0], av, FALSE); 243*40393Sbostic } 244*40393Sbostic exit(1); 245*40393Sbostic } else if (argc != 0) { 246*40393Sbostic /* 247*40393Sbostic * If there's a vector that needs freeing (the command was executed 248*40393Sbostic * directly), do so now, being sure to back up the argument vector 249*40393Sbostic * to where it started... 250*40393Sbostic */ 251*40393Sbostic av -= 1; 252*40393Sbostic Str_FreeVec (argc, av); 253*40393Sbostic } 254*40393Sbostic 255*40393Sbostic /* 256*40393Sbostic * The child is off and running. Now all we can do is wait... 257*40393Sbostic */ 258*40393Sbostic while (1) { 259*40393Sbostic int id; 260*40393Sbostic 261*40393Sbostic if (!local) { 262*40393Sbostic id = Rmt_LastID(cpid); 263*40393Sbostic } 264*40393Sbostic 265*40393Sbostic while ((stat = wait(&reason)) != cpid) { 266*40393Sbostic if (stat == -1 && errno != EINTR) { 267*40393Sbostic break; 268*40393Sbostic } 269*40393Sbostic } 270*40393Sbostic 271*40393Sbostic if (!local) { 272*40393Sbostic Rmt_Done(id); 273*40393Sbostic } 274*40393Sbostic 275*40393Sbostic 276*40393Sbostic if (stat > -1) { 277*40393Sbostic if (WIFSTOPPED(reason)) { 278*40393Sbostic status = reason.w_stopval; /* stopped */ 279*40393Sbostic } else if (WIFEXITED(reason)) { 280*40393Sbostic status = reason.w_retcode; /* exited */ 281*40393Sbostic if (status != 0) { 282*40393Sbostic printf ("*** Error code %d", status); 283*40393Sbostic } 284*40393Sbostic } else { 285*40393Sbostic status = reason.w_termsig; /* signaled */ 286*40393Sbostic printf ("*** Signal %d", status); 287*40393Sbostic } 288*40393Sbostic 289*40393Sbostic 290*40393Sbostic if (!WIFEXITED(reason) || (status != 0)) { 291*40393Sbostic if (errCheck) { 292*40393Sbostic gn->made = ERROR; 293*40393Sbostic if (keepgoing) { 294*40393Sbostic /* 295*40393Sbostic * Abort the current target, but let others 296*40393Sbostic * continue. 297*40393Sbostic */ 298*40393Sbostic printf (" (continuing)\n"); 299*40393Sbostic } 300*40393Sbostic } else { 301*40393Sbostic /* 302*40393Sbostic * Continue executing commands for this target. 303*40393Sbostic * If we return 0, this will happen... 304*40393Sbostic */ 305*40393Sbostic printf (" (ignored)\n"); 306*40393Sbostic status = 0; 307*40393Sbostic } 308*40393Sbostic } 309*40393Sbostic break; 310*40393Sbostic } else { 311*40393Sbostic Fatal ("error in wait: %d", stat); 312*40393Sbostic /*NOTREACHED*/ 313*40393Sbostic } 314*40393Sbostic } 315*40393Sbostic 316*40393Sbostic return (status); 317*40393Sbostic } 318*40393Sbostic 319*40393Sbostic /*- 320*40393Sbostic *----------------------------------------------------------------------- 321*40393Sbostic * CompatMake -- 322*40393Sbostic * Make a target. 323*40393Sbostic * 324*40393Sbostic * Results: 325*40393Sbostic * 0 326*40393Sbostic * 327*40393Sbostic * Side Effects: 328*40393Sbostic * If an error is detected and not being ignored, the process exits. 329*40393Sbostic * 330*40393Sbostic *----------------------------------------------------------------------- 331*40393Sbostic */ 332*40393Sbostic static int 333*40393Sbostic CompatMake (gn, pgn) 334*40393Sbostic GNode *gn; /* The node to make */ 335*40393Sbostic GNode *pgn; /* Parent to abort if necessary */ 336*40393Sbostic { 337*40393Sbostic if (gn->type & OP_USE) { 338*40393Sbostic Make_HandleUse(gn, pgn); 339*40393Sbostic } else if (gn->made == UNMADE) { 340*40393Sbostic /* 341*40393Sbostic * First mark ourselves to be made, then apply whatever transformations 342*40393Sbostic * the suffix module thinks are necessary. Once that's done, we can 343*40393Sbostic * descend and make all our children. If any of them has an error 344*40393Sbostic * but the -k flag was given, our 'make' field will be set FALSE again. 345*40393Sbostic * This is our signal to not attempt to do anything but abort our 346*40393Sbostic * parent as well. 347*40393Sbostic */ 348*40393Sbostic gn->make = TRUE; 349*40393Sbostic gn->made = BEINGMADE; 350*40393Sbostic Suff_FindDeps (gn); 351*40393Sbostic Lst_ForEach (gn->children, CompatMake, (ClientData)gn); 352*40393Sbostic if (!gn->make) { 353*40393Sbostic gn->made = ABORTED; 354*40393Sbostic pgn->make = FALSE; 355*40393Sbostic return (0); 356*40393Sbostic } 357*40393Sbostic 358*40393Sbostic if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 359*40393Sbostic Var_Set (IMPSRC, Var_Value(TARGET, gn), pgn); 360*40393Sbostic } 361*40393Sbostic 362*40393Sbostic /* 363*40393Sbostic * All the children were made ok. Now cmtime contains the modification 364*40393Sbostic * time of the newest child, we need to find out if we exist and when 365*40393Sbostic * we were modified last. The criteria for datedness are defined by the 366*40393Sbostic * Make_OODate function. 367*40393Sbostic */ 368*40393Sbostic if (DEBUG(MAKE)) { 369*40393Sbostic printf("Examining %s...", gn->name); 370*40393Sbostic } 371*40393Sbostic if (! Make_OODate(gn)) { 372*40393Sbostic gn->made = UPTODATE; 373*40393Sbostic if (DEBUG(MAKE)) { 374*40393Sbostic printf("up-to-date.\n"); 375*40393Sbostic } 376*40393Sbostic return (0); 377*40393Sbostic } else if (DEBUG(MAKE)) { 378*40393Sbostic printf("out-of-date.\n"); 379*40393Sbostic } 380*40393Sbostic 381*40393Sbostic /* 382*40393Sbostic * If the user is just seeing if something is out-of-date, exit now 383*40393Sbostic * to tell him/her "yes". 384*40393Sbostic */ 385*40393Sbostic if (queryFlag) { 386*40393Sbostic exit (-1); 387*40393Sbostic } 388*40393Sbostic 389*40393Sbostic /* 390*40393Sbostic * We need to be re-made. We also have to make sure we've got a $? 391*40393Sbostic * variable. To be nice, we also define the $> variable using 392*40393Sbostic * Make_DoAllVar(). 393*40393Sbostic */ 394*40393Sbostic Make_DoAllVar(gn); 395*40393Sbostic 396*40393Sbostic /* 397*40393Sbostic * Alter our type to tell if errors should be ignored or things 398*40393Sbostic * should not be printed so CompatRunCommand knows what to do. 399*40393Sbostic */ 400*40393Sbostic if (Targ_Ignore (gn)) { 401*40393Sbostic gn->type |= OP_IGNORE; 402*40393Sbostic } 403*40393Sbostic if (Targ_Silent (gn)) { 404*40393Sbostic gn->type |= OP_SILENT; 405*40393Sbostic } 406*40393Sbostic 407*40393Sbostic if (Job_CheckCommands (gn, Fatal)) { 408*40393Sbostic /* 409*40393Sbostic * Our commands are ok, but we still have to worry about the -t 410*40393Sbostic * flag... 411*40393Sbostic */ 412*40393Sbostic if (!touchFlag) { 413*40393Sbostic curTarg = gn; 414*40393Sbostic Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn); 415*40393Sbostic curTarg = NILGNODE; 416*40393Sbostic } else { 417*40393Sbostic Job_Touch (gn, gn->type & OP_SILENT); 418*40393Sbostic } 419*40393Sbostic } else { 420*40393Sbostic gn->made = ERROR; 421*40393Sbostic } 422*40393Sbostic 423*40393Sbostic if (gn->made != ERROR) { 424*40393Sbostic /* 425*40393Sbostic * If the node was made successfully, mark it so, update 426*40393Sbostic * its modification time and timestamp all its parents. Note 427*40393Sbostic * that for .ZEROTIME targets, the timestamping isn't done. 428*40393Sbostic * This is to keep its state from affecting that of its parent. 429*40393Sbostic */ 430*40393Sbostic gn->made = MADE; 431*40393Sbostic #ifndef RECHECK 432*40393Sbostic /* 433*40393Sbostic * We can't re-stat the thing, but we can at least take care of 434*40393Sbostic * rules where a target depends on a source that actually creates 435*40393Sbostic * the target, but only if it has changed, e.g. 436*40393Sbostic * 437*40393Sbostic * parse.h : parse.o 438*40393Sbostic * 439*40393Sbostic * parse.o : parse.y 440*40393Sbostic * yacc -d parse.y 441*40393Sbostic * cc -c y.tab.c 442*40393Sbostic * mv y.tab.o parse.o 443*40393Sbostic * cmp -s y.tab.h parse.h || mv y.tab.h parse.h 444*40393Sbostic * 445*40393Sbostic * In this case, if the definitions produced by yacc haven't 446*40393Sbostic * changed from before, parse.h won't have been updated and 447*40393Sbostic * gn->mtime will reflect the current modification time for 448*40393Sbostic * parse.h. This is something of a kludge, I admit, but it's a 449*40393Sbostic * useful one.. 450*40393Sbostic * 451*40393Sbostic * XXX: People like to use a rule like 452*40393Sbostic * 453*40393Sbostic * FRC: 454*40393Sbostic * 455*40393Sbostic * To force things that depend on FRC to be made, so we have to 456*40393Sbostic * check for gn->children being empty as well... 457*40393Sbostic */ 458*40393Sbostic if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) { 459*40393Sbostic gn->mtime = now; 460*40393Sbostic } 461*40393Sbostic #else 462*40393Sbostic /* 463*40393Sbostic * This is what Make does and it's actually a good thing, as it 464*40393Sbostic * allows rules like 465*40393Sbostic * 466*40393Sbostic * cmp -s y.tab.h parse.h || cp y.tab.h parse.h 467*40393Sbostic * 468*40393Sbostic * to function as intended. Unfortunately, thanks to the stateless 469*40393Sbostic * nature of NFS (and the speed of this program), there are times 470*40393Sbostic * when the modification time of a file created on a remote 471*40393Sbostic * machine will not be modified before the stat() implied by 472*40393Sbostic * the Dir_MTime occurs, thus leading us to believe that the file 473*40393Sbostic * is unchanged, wreaking havoc with files that depend on this one. 474*40393Sbostic * 475*40393Sbostic * I have decided it is better to make too much than to make too 476*40393Sbostic * little, so this stuff is commented out unless you're sure it's 477*40393Sbostic * ok. 478*40393Sbostic * -- ardeb 1/12/88 479*40393Sbostic */ 480*40393Sbostic if (noExecute || Dir_MTime(gn) == 0) { 481*40393Sbostic gn->mtime = now; 482*40393Sbostic } 483*40393Sbostic if (DEBUG(MAKE)) { 484*40393Sbostic printf("update time: %s\n", Targ_FmtTime(gn->mtime)); 485*40393Sbostic } 486*40393Sbostic #endif 487*40393Sbostic if (!(gn->type & OP_EXEC)) { 488*40393Sbostic pgn->childMade = TRUE; 489*40393Sbostic Make_TimeStamp(pgn, gn); 490*40393Sbostic } 491*40393Sbostic } else if (keepgoing) { 492*40393Sbostic pgn->make = FALSE; 493*40393Sbostic } else { 494*40393Sbostic printf ("\n\nStop.\n"); 495*40393Sbostic exit (1); 496*40393Sbostic } 497*40393Sbostic } else if (gn->made == ERROR) { 498*40393Sbostic /* 499*40393Sbostic * Already had an error when making this beastie. Tell the parent 500*40393Sbostic * to abort. 501*40393Sbostic */ 502*40393Sbostic pgn->make = FALSE; 503*40393Sbostic } else { 504*40393Sbostic if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 505*40393Sbostic Var_Set (IMPSRC, Var_Value(TARGET, gn), pgn); 506*40393Sbostic } 507*40393Sbostic switch(gn->made) { 508*40393Sbostic case BEINGMADE: 509*40393Sbostic Error("Graph cycles through %s\n", gn->name); 510*40393Sbostic gn->made = ERROR; 511*40393Sbostic pgn->make = FALSE; 512*40393Sbostic break; 513*40393Sbostic case MADE: 514*40393Sbostic if ((gn->type & OP_EXEC) == 0) { 515*40393Sbostic pgn->childMade = TRUE; 516*40393Sbostic Make_TimeStamp(pgn, gn); 517*40393Sbostic } 518*40393Sbostic break; 519*40393Sbostic case UPTODATE: 520*40393Sbostic if ((gn->type & OP_EXEC) == 0) { 521*40393Sbostic Make_TimeStamp(pgn, gn); 522*40393Sbostic } 523*40393Sbostic break; 524*40393Sbostic } 525*40393Sbostic } 526*40393Sbostic 527*40393Sbostic return (0); 528*40393Sbostic } 529*40393Sbostic 530*40393Sbostic /*- 531*40393Sbostic *----------------------------------------------------------------------- 532*40393Sbostic * Compat_Run -- 533*40393Sbostic * Initialize this mode and start making. 534*40393Sbostic * 535*40393Sbostic * Results: 536*40393Sbostic * None. 537*40393Sbostic * 538*40393Sbostic * Side Effects: 539*40393Sbostic * Guess what? 540*40393Sbostic * 541*40393Sbostic *----------------------------------------------------------------------- 542*40393Sbostic */ 543*40393Sbostic void 544*40393Sbostic Compat_Run(targs) 545*40393Sbostic Lst targs; /* List of target nodes to re-create */ 546*40393Sbostic { 547*40393Sbostic char *cp; /* Pointer to string of shell meta-characters */ 548*40393Sbostic GNode *gn; /* Current root target */ 549*40393Sbostic int errors; /* Number of targets not remade due to errors */ 550*40393Sbostic 551*40393Sbostic if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 552*40393Sbostic signal(SIGINT, CompatInterrupt); 553*40393Sbostic } 554*40393Sbostic if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 555*40393Sbostic signal(SIGTERM, CompatInterrupt); 556*40393Sbostic } 557*40393Sbostic if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 558*40393Sbostic signal(SIGHUP, CompatInterrupt); 559*40393Sbostic } 560*40393Sbostic if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 561*40393Sbostic signal(SIGQUIT, CompatInterrupt); 562*40393Sbostic } 563*40393Sbostic 564*40393Sbostic for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { 565*40393Sbostic meta[*cp] = 1; 566*40393Sbostic } 567*40393Sbostic /* 568*40393Sbostic * The null character serves as a sentinel in the string. 569*40393Sbostic */ 570*40393Sbostic meta[0] = 1; 571*40393Sbostic 572*40393Sbostic ENDNode = Targ_FindNode(".END", TARG_CREATE); 573*40393Sbostic /* 574*40393Sbostic * If the user has defined a .BEGIN target, execute the commands attached 575*40393Sbostic * to it. 576*40393Sbostic */ 577*40393Sbostic if (!queryFlag) { 578*40393Sbostic gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 579*40393Sbostic if (gn != NILGNODE) { 580*40393Sbostic Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 581*40393Sbostic } 582*40393Sbostic } 583*40393Sbostic 584*40393Sbostic /* 585*40393Sbostic * For each entry in the list of targets to create, call CompatMake on 586*40393Sbostic * it to create the thing. CompatMake will leave the 'made' field of gn 587*40393Sbostic * in one of several states: 588*40393Sbostic * UPTODATE gn was already up-to-date 589*40393Sbostic * MADE gn was recreated successfully 590*40393Sbostic * ERROR An error occurred while gn was being created 591*40393Sbostic * ABORTED gn was not remade because one of its inferiors 592*40393Sbostic * could not be made due to errors. 593*40393Sbostic */ 594*40393Sbostic errors = 0; 595*40393Sbostic while (!Lst_IsEmpty (targs)) { 596*40393Sbostic gn = (GNode *) Lst_DeQueue (targs); 597*40393Sbostic CompatMake (gn, gn); 598*40393Sbostic 599*40393Sbostic if (gn->made == UPTODATE) { 600*40393Sbostic printf ("`%s' is up to date.\n", gn->name); 601*40393Sbostic } else if (gn->made == ABORTED) { 602*40393Sbostic printf ("`%s' not remade because of errors.\n", gn->name); 603*40393Sbostic errors += 1; 604*40393Sbostic } 605*40393Sbostic } 606*40393Sbostic 607*40393Sbostic /* 608*40393Sbostic * If the user has defined a .END target, run its commands. 609*40393Sbostic */ 610*40393Sbostic if (errors == 0) { 611*40393Sbostic Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn); 612*40393Sbostic } 613*40393Sbostic } 614