1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  *      doname.c
  28  *
  29  *      Figure out which targets are out of date and rebuild them
  30  */
  31 
  32 /*
  33  * Included files
  34  */
  35 #include <avo/avo_alloca.h>               /* alloca() */
  36 #if defined(TEAMWARE_MAKE_CMN)
  37 #include <avo/util.h>             /* avo_get_user(), avo_hostname() */
  38 #endif
  39 
  40 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
  41 #       include <avo/strings.h>   /* AVO_STRDUP() */
  42 #       include <dm/Avo_MToolJobResultMsg.h>
  43 #       include <dm/Avo_MToolJobStartMsg.h>
  44 #       include <dm/Avo_MToolRsrcInfoMsg.h>
  45 #       include <dm/Avo_macro_defs.h> /* AVO_BLOCK_INTERUPTS & AVO_UNBLOCK_INTERUPTS */
  46 #       include <dmthread/Avo_ServerState.h>
  47 #       include <rw/pstream.h>
  48 #       include <rw/xdrstrea.h>
  49 #endif
  50 
  51 #include <fcntl.h>
  52 #include <mk/defs.h>
  53 #include <mksh/i18n.h>            /* get_char_semantics_value() */
  54 #include <mksh/macro.h>           /* getvar(), expand_value() */
  55 #include <mksh/misc.h>            /* getmem() */
  56 #include <poll.h>
  57 
  58 #ifdef PARALLEL
  59 #       include <rx/api.h>
  60 #endif
  61 
  62 #include <signal.h>
  63 
  64 #ifndef HP_UX
  65 #       include <stropts.h>
  66 #endif
  67 
  68 #include <sys/errno.h>
  69 #include <sys/stat.h>
  70 #include <sys/types.h>
  71 #include <sys/utsname.h>  /* uname() */
  72 #include <sys/wait.h>
  73 #include <unistd.h>               /* close() */
  74 
  75 /*
  76  * Defined macros
  77  */
  78 #ifndef PARALLEL
  79 #       define LOCALHOST "localhost"
  80 #endif
  81 
  82 #define MAXRULES 100
  83 
  84 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
  85 #define SEND_MTOOL_MSG(cmds) \
  86         if (send_mtool_msgs) { \
  87                 cmds \
  88         }
  89 #else
  90 #define SEND_MTOOL_MSG(cmds) 
  91 #endif
  92 
  93 // Sleep for .1 seconds between stat()'s
  94 const int       STAT_RETRY_SLEEP_TIME = 100000;
  95 
  96 /*
  97  * typedefs & structs
  98  */
  99 
 100 /*
 101  * Static variables
 102  */
 103 static char     hostName[MAXNAMELEN] = "";
 104 static char     userName[MAXNAMELEN] = "";
 105 
 106 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
 107         static FILE     *mtool_msgs_fp;
 108         static XDR      xdrs;
 109         static int      sent_rsrc_info_msg = 0;
 110 #endif
 111 
 112 static int      second_pass = 0;
 113 
 114 /*
 115  * File table of contents
 116  */
 117 extern  Doname          doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
 118 extern  Doname          doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
 119 static  Boolean         check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
 120 void            dynamic_dependencies(Name target);
 121 static  Doname          run_command(register Property line, Boolean print_machine);
 122 extern  Doname          execute_serial(Property line);
 123 extern  Name            vpath_translation(register Name cmd);
 124 extern  void            check_state(Name temp_file_name);
 125 static  void            read_dependency_file(register Name filename);
 126 static  void            check_read_state_file(void);
 127 static  void            do_assign(register Name line, register Name target);
 128 static  void            build_command_strings(Name target, register Property line);
 129 static  Doname          touch_command(register Property line, register Name target, Doname result);
 130 extern  void            update_target(Property line, Doname result);
 131 static  Doname          sccs_get(register Name target, register Property *command);
 132 extern  void            read_directory_of_file(register Name file);
 133 static  void            add_pattern_conditionals(register Name target);
 134 extern  void            set_locals(register Name target, register Property old_locals);
 135 extern  void            reset_locals(register Name target, register Property old_locals, register Property conditional, register int index);
 136 extern  Boolean         check_auto_dependencies(Name target, int auto_count, Name *automatics);
 137 static  void            delete_query_chain(Chain ch);
 138 
 139 // From read2.cc
 140 extern  Name            normalize_name(register wchar_t *name_string, register int length);
 141 
 142 
 143 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
 144         static void             append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg);
 145         static int              pollResults(char *outFn, char *errFn, char *hostNm);
 146         static void             pollResultsAction(char *outFn, char *errFn);
 147         static void             rxmGetNextResultsBlock(int fd);
 148         static int              us_sleep(unsigned int nusecs);
 149         extern "C" void         Avo_PollResultsAction_Sigusr1Handler(int foo);
 150 #endif
 151 
 152 /*
 153  * DONE.
 154  *
 155  *      doname_check(target, do_get, implicit, automatic)
 156  *
 157  *      Will call doname() and then inspect the return value
 158  *
 159  *      Return value:
 160  *                              Indication if the build failed or not
 161  *
 162  *      Parameters:
 163  *              target          The target to build
 164  *              do_get          Passed thru to doname()
 165  *              implicit        Passed thru to doname()
 166  *              automatic       Are we building a hidden dependency?
 167  *
 168  *      Global variables used:
 169  *              build_failed_seen       Set if -k is on and error occurs
 170  *              continue_after_error    Indicates that -k is on
 171  *              report_dependencies     No error msg if -P is on
 172  */
 173 Doname
 174 doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
 175 {
 176         int first_time = 1;
 177         (void) fflush(stdout);
 178 try_again:
 179         switch (doname(target, do_get, implicit, automatic)) {
 180         case build_ok:
 181                 second_pass = 0;
 182                 return build_ok;
 183         case build_running:
 184                 second_pass = 0;
 185                 return build_running;
 186         case build_failed:
 187                 if (!continue_after_error) {
 188                         fatal(catgets(catd, 1, 13, "Target `%s' not remade because of errors"),
 189                               target->string_mb);
 190                 }
 191                 build_failed_seen = true;
 192                 second_pass = 0;
 193                 return build_failed;
 194         case build_dont_know:
 195                 /*
 196                  * If we can't figure out how to build an automatic
 197                  * (hidden) dependency, we just ignore it.
 198                  * We later declare the target to be out of date just in
 199                  * case something changed.
 200                  * Also, don't complain if just reporting the dependencies
 201                  * and not building anything.
 202                  */
 203                 if (automatic || (report_dependencies_level > 0)) {
 204                         second_pass = 0;
 205                         return build_dont_know;
 206                 }
 207                 if(first_time) {
 208                         first_time = 0;
 209                         second_pass = 1;
 210                         goto try_again;
 211                 }
 212                 second_pass = 0;
 213                 if (continue_after_error && !svr4) {
 214                         warning(catgets(catd, 1, 14, "Don't know how to make target `%s'"),
 215                                 target->string_mb);
 216                         build_failed_seen = true;
 217                         return build_failed;
 218                 }
 219                 fatal(catgets(catd, 1, 15, "Don't know how to make target `%s'"), target->string_mb);
 220                 break;
 221         }
 222 #ifdef lint
 223         return build_failed;
 224 #endif
 225 }
 226 
 227 
 228 void
 229 enter_explicit_rule_from_dynamic_rule(Name target, Name source)
 230 {
 231         Property line, source_line;
 232         Dependency dependency;
 233 
 234         source_line = get_prop(source->prop, line_prop);
 235         line = maybe_append_prop(target, line_prop);
 236         line->body.line.sccs_command = false;
 237         line->body.line.target = target;
 238         if (line->body.line.command_template == NULL) {
 239                 line->body.line.command_template = source_line->body.line.command_template;
 240                 for (dependency = source_line->body.line.dependencies;
 241                      dependency != NULL;
 242                      dependency = dependency->next) {
 243                         enter_dependency(line, dependency->name, false);
 244                 }
 245                 line->body.line.less = target;
 246         }
 247         line->body.line.percent = NULL;
 248 }
 249 
 250 
 251 
 252 Name
 253 find_dyntarget(Name target)
 254 {
 255         Dyntarget               p;
 256         int                     i;
 257         String_rec              string;
 258         wchar_t                 buffer[STRING_BUFFER_LENGTH];
 259         wchar_t                 *pp, * bufend;
 260         wchar_t                 tbuffer[MAXPATHLEN];
 261         Wstring                 wcb(target);
 262 
 263         for (p = dyntarget_list; p != NULL; p = p->next) {
 264                 INIT_STRING_FROM_STACK(string, buffer);
 265                 expand_value(p->name, &string, false);
 266                 i = 0;
 267                 pp = string.buffer.start;
 268                 bufend = pp + STRING_BUFFER_LENGTH;
 269                 while((*pp != nul_char) && (pp < bufend)) {
 270                         if(iswspace(*pp)) {
 271                                 tbuffer[i] = nul_char;
 272                                 if(i > 0) {
 273                                         if (wcb.equal(tbuffer)) {
 274                                                 enter_explicit_rule_from_dynamic_rule(target, p->name);
 275                                                 return(target);
 276                                         }
 277                                 }
 278                                 pp++;
 279                                 i = 0;
 280                                 continue;
 281                         }
 282                         tbuffer[i] = *pp;
 283                         i++;
 284                         pp++;
 285                         if(*pp == nul_char) {
 286                                 tbuffer[i] = nul_char;
 287                                 if(i > 0) {
 288                                         if (wcb.equal(tbuffer)) {
 289                                                 enter_explicit_rule_from_dynamic_rule(target, p->name);
 290                                                 return(target);
 291                                         }
 292                                 }
 293                                 break;
 294                         }
 295                 }
 296         }
 297         return(NULL);
 298 }
 299 
 300 /*
 301  * DONE.
 302  *
 303  *      doname(target, do_get, implicit)
 304  *
 305  *      Chases all files the target depends on and builds any that
 306  *      are out of date. If the target is out of date it is then rebuilt.
 307  *
 308  *      Return value:
 309  *                              Indiates if build failed or nt
 310  *
 311  *      Parameters:
 312  *              target          Target to build
 313  *              do_get          Run sccs get is nessecary
 314  *              implicit        doname is trying to find an implicit rule
 315  *
 316  *      Global variables used:
 317  *              assign_done     True if command line assgnment has happened
 318  *              commands_done   Preserved for the case that we need local value
 319  *              debug_level     Should we trace make's actions?
 320  *              default_rule    The rule for ".DEFAULT", used as last resort
 321  *              empty_name      The Name "", used when looking for single sfx
 322  *              keep_state      Indicates that .KEEP_STATE is on
 323  *              parallel        True if building in parallel
 324  *              recursion_level Used for tracing
 325  *              report_dependencies make -P is on
 326  */
 327 Doname
 328 doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
 329 {
 330         Doname                  result = build_dont_know;
 331         Chain                   out_of_date_list = NULL;
 332 #ifdef TEAMWARE_MAKE_CMN
 333         Chain                   target_group;
 334 #endif
 335         Property                old_locals = NULL;
 336         register Property       line;
 337         Property                command = NULL;
 338         register Dependency     dependency;
 339         Name                    less = NULL;
 340         Name                    true_target = target;
 341         Name                    *automatics = NULL;
 342         register int            auto_count;
 343         Boolean                 rechecking_target = false;
 344         Boolean                 saved_commands_done;
 345         Boolean                 restart = false;
 346         Boolean                 save_parallel = parallel;
 347 #ifdef NSE
 348         Boolean                 save_readdep;
 349 #endif
 350         Boolean                 doing_subtree = false;
 351 
 352         Boolean                 recheck_conditionals = false;
 353 
 354         if (target->state == build_running) {
 355                 return build_running;
 356         }
 357         line = get_prop(target->prop, line_prop);
 358 #ifdef TEAMWARE_MAKE_CMN
 359         if (line != NULL) {
 360                 /*
 361                  * If this target is a member of target group and one of the
 362                  * other members of the group is running, mark this target
 363                  * as running.
 364                  */
 365                 for (target_group = line->body.line.target_group;
 366                      target_group != NULL;
 367                      target_group = target_group->next) {
 368                         if (is_running(target_group->name)) {
 369                                 target->state = build_running;
 370                                 add_pending(target,
 371                                             recursion_level,
 372                                             do_get,
 373                                             implicit,
 374                                             false);
 375                                 return build_running;
 376                         }
 377                 }
 378         }
 379 #ifdef NSE
 380         nse_check_file_backquotes(target->string);
 381 #endif
 382 #endif
 383         /*
 384          * If the target is a constructed one for a "::" target,
 385          * we need to consider that.
 386          */
 387         if (target->has_target_prop) {
 388                 true_target = get_prop(target->prop,
 389                                        target_prop)->body.target.target;
 390                 if (true_target->colon_splits > 0) {
 391                         /* Make sure we have a valid time for :: targets */
 392                         Property        time;
 393 
 394                         time = get_prop(true_target->prop, time_prop);
 395                         if (time != NULL) {
 396                                 true_target->stat.time = time->body.time.time;
 397                         }
 398                 }
 399         }
 400         (void) exists(true_target);
 401         /*
 402          * If the target has been processed, we don't need to do it again,
 403          * unless it depends on conditional macros or a delayed assignment,
 404          * or it has been done when KEEP_STATE is on.
 405          */
 406         if (target->state == build_ok) {
 407                 if((!keep_state || (!target->depends_on_conditional && !assign_done))) {
 408                         return build_ok;
 409                 } else {
 410                         recheck_conditionals = true;
 411                 }
 412         }
 413         if (target->state == build_subtree) {
 414                 /* A dynamic macro subtree is being built */
 415                 target->state = build_dont_know;
 416                 doing_subtree = true;
 417                 if (!target->checking_subtree) {
 418                         /*
 419                          * This target has been started before and therefore
 420                          * not all dependencies have to be built.
 421                          */
 422                         restart = true;
 423                 }
 424         } else if (target->state == build_pending) {
 425                 target->state = build_dont_know;
 426                 restart = true;
 427 /*
 428 #ifdef TEAMWARE_MAKE_CMN
 429         } else if (parallel &&
 430                    keep_state &&
 431                    (target->conditional_cnt > 0)) {
 432             if (!parallel_ok(target, false)) {
 433                 add_subtree(target, recursion_level, do_get, implicit);
 434                 target->state = build_running;
 435                 return build_running;
 436             }
 437 #endif
 438  */
 439         }
 440         /*
 441          * If KEEP_STATE is on, we have to rebuild the target if the
 442          * building of it caused new automatic dependencies to be reported.
 443          * This is where we restart the build.
 444          */
 445         if (line != NULL) {
 446                 line->body.line.percent = NULL;
 447         }
 448 recheck_target:
 449         /* Init all local variables */
 450         result = build_dont_know;
 451         out_of_date_list = NULL;
 452         command = NULL;
 453         less = NULL;
 454         auto_count = 0;
 455         if (!restart && line != NULL) {
 456                 /*
 457                  * If this target has never been built before, mark all
 458                  * of the dependencies as never built.
 459                  */
 460                 for (dependency = line->body.line.dependencies;
 461                      dependency != NULL;
 462                      dependency = dependency->next) {
 463                         dependency->built = false;
 464                 }
 465         }
 466         /* Save the set of automatic depes defined for this target */
 467         if (keep_state &&
 468             (line != NULL) &&
 469             (line->body.line.dependencies != NULL)) {
 470                 Name *p;
 471 
 472                 /*
 473                  * First run thru the dependency list to see how many
 474                  * autos there are.
 475                  */
 476                 for (dependency = line->body.line.dependencies;
 477                      dependency != NULL;
 478                      dependency = dependency->next) {
 479                         if (dependency->automatic && !dependency->stale) {
 480                                 auto_count++;
 481                         }
 482                 }
 483                 /* Create vector to hold the current autos */
 484                 automatics =
 485                   (Name *) alloca((int) (auto_count * sizeof (Name)));
 486                 /* Copy them */
 487                 for (p = automatics, dependency = line->body.line.dependencies;
 488                      dependency != NULL;
 489                      dependency = dependency->next) {
 490                         if (dependency->automatic && !dependency->stale) {
 491                                 *p++ = dependency->name;
 492                         }
 493                 }
 494         }
 495         if (debug_level > 1) {
 496                 (void) printf(NOCATGETS("%*sdoname(%s)\n"),
 497                               recursion_level,
 498                               "",
 499                               target->string_mb);
 500         }
 501         recursion_level++;
 502         /* Avoid infinite loops */
 503         if (target->state == build_in_progress) {
 504                 warning(catgets(catd, 1, 16, "Infinite loop: Target `%s' depends on itself"),
 505                         target->string_mb);
 506                 return build_ok;
 507         }
 508         target->state = build_in_progress;
 509 
 510         /* Activate conditional macros for the target */
 511         if (!target->added_pattern_conditionals) {
 512                 add_pattern_conditionals(target);
 513                 target->added_pattern_conditionals = true;
 514         }
 515         if (target->conditional_cnt > 0) {
 516                 old_locals = (Property) alloca(target->conditional_cnt *
 517                                                sizeof (Property_rec));
 518                 set_locals(target, old_locals);
 519         }
 520 
 521 /*
 522  * after making the call to dynamic_dependecies unconditional we can handle
 523  * target names that are same as file name. In this case $$@ in the 
 524  * dependencies did not mean anything. WIth this change it expands it
 525  * as expected.
 526  */
 527         if (!target->has_depe_list_expanded)
 528         {
 529 #ifdef NSE
 530                 save_readdep = reading_dependencies;
 531                 reading_dependencies= true;
 532 #endif
 533                 dynamic_dependencies(target);
 534 #ifdef NSE
 535                 reading_dependencies= save_readdep;
 536 #endif
 537         }
 538 
 539 /*
 540  *      FIRST SECTION -- GO THROUGH DEPENDENCIES AND COLLECT EXPLICIT
 541  *      COMMANDS TO RUN
 542  */
 543         if ((line = get_prop(target->prop, line_prop)) != NULL) {
 544                 if (check_dependencies(&result,
 545                                        line,
 546                                        do_get,
 547                                        target,
 548                                        true_target,
 549                                        doing_subtree,
 550                                        &out_of_date_list,
 551                                        old_locals,
 552                                        implicit,
 553                                        &command,
 554                                        less,
 555                                        rechecking_target,
 556                                        recheck_conditionals)) {
 557                         return build_running;
 558                 }
 559                 if (line->body.line.query != NULL) {
 560                         delete_query_chain(line->body.line.query);
 561                 }
 562                 line->body.line.query = out_of_date_list;
 563         }
 564 
 565 #ifdef PARALLEL
 566         if (doing_subtree) {
 567                 parallel = false;
 568         }
 569 #endif
 570 
 571 /*
 572  * If the target is a :: type, do not try to find the rule for the target,
 573  * all actions will be taken by separate branches.
 574  * Else, we try to find an implicit rule using various methods,
 575  * we quit as soon as one is found.
 576  *
 577  * [tolik, 12 Sep 2002] Do not try to find implicit rule for the target
 578  * being rechecked - the target is being rechecked means that it already
 579  * has explicit dependencies derived from an implicit rule found
 580  * in previous step.
 581  */
 582         if (target->colon_splits == 0 && !rechecking_target) {
 583                 /* Look for percent matched rule */
 584                 if ((result == build_dont_know) &&
 585                     (command == NULL)) {
 586                         switch (find_percent_rule(
 587                                         target,
 588                                         &command,
 589                                         recheck_conditionals)) {
 590                         case build_failed:
 591                                 result = build_failed;
 592                                 break;
 593 #ifdef TEAMWARE_MAKE_CMN
 594                         case build_running:
 595                                 target->state = build_running;
 596                                 add_pending(target,
 597                                             --recursion_level,
 598                                             do_get,
 599                                             implicit,
 600                                             false);
 601                                 if (target->conditional_cnt > 0) {
 602                                         reset_locals(target,
 603                                                      old_locals,
 604                                                      get_prop(target->prop,
 605                                                              conditional_prop),
 606                                                      0);
 607                                 }
 608                                 return build_running;
 609 #endif
 610                         case build_ok:
 611                                 result = build_ok;
 612                                 break;
 613                         }
 614                 }
 615                 /* Look for double suffix rule */
 616                 if (result == build_dont_know) {
 617                         Property member;
 618 
 619                         if (target->is_member &&
 620                             ((member = get_prop(target->prop, member_prop)) !=
 621                              NULL)) {
 622                                 switch (find_ar_suffix_rule(target,
 623                                                 member->body.
 624                                                 member.member,
 625                                                 &command,
 626                                                 recheck_conditionals)) {
 627                                 case build_failed:
 628                                         result = build_failed;
 629                                         break;
 630 #ifdef TEAMWARE_MAKE_CMN
 631                                 case build_running:
 632                                         target->state = build_running;
 633                                         add_pending(target,
 634                                                     --recursion_level,
 635                                                     do_get,
 636                                                     implicit,
 637                                                     false);
 638                                     if (target->conditional_cnt > 0) {
 639                                             reset_locals(target,
 640                                                          old_locals,
 641                                                          get_prop(target->prop,
 642                                                              conditional_prop),
 643                                                          0);
 644                                     }
 645                                         return build_running;
 646 #endif
 647                                 default:
 648                                         /* ALWAYS bind $% for old style */
 649                                         /* ar rules */
 650                                         if (line == NULL) {
 651                                                 line =
 652                                                   maybe_append_prop(target,
 653                                                                     line_prop);
 654                                         }
 655                                         line->body.line.percent =
 656                                           member->body.member.member;
 657                                         break;
 658                                 }
 659                         } else {
 660                                 switch (find_double_suffix_rule(target,
 661                                                 &command,
 662                                                 recheck_conditionals)) {
 663                                 case build_failed:
 664                                         result = build_failed;
 665                                         break;
 666 #ifdef TEAMWARE_MAKE_CMN
 667                                 case build_running:
 668                                         target->state = build_running;
 669                                         add_pending(target,
 670                                                     --recursion_level,
 671                                                     do_get,
 672                                                     implicit,
 673                                                     false);
 674                                         if (target->conditional_cnt > 0) {
 675                                                 reset_locals(target,
 676                                                              old_locals,
 677                                                              get_prop(target->
 678                                                                       prop,
 679                                                                       conditional_prop),
 680                                                              0);
 681                                         }
 682                                         return build_running;
 683 #endif
 684                                 }
 685                         }
 686                 }
 687                 /* Look for single suffix rule */
 688 
 689 /* /tolik/
 690  * I commented !implicit to fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
 691  * This caused problem with SVR4 tilde rules (infinite recursion). So I made some changes in "implicit.cc"
 692  */
 693 /* /tolik, 06.21.96/
 694  * Regression! See BugId 1255360
 695  * If more than one percent rules are defined for the same target then
 696  * the behaviour of 'make' with my previous fix may be different from one
 697  * of the 'old make'. 
 698  * The global variable second_pass (maybe it should be an argument to doname())
 699  * is intended to avoid this regression. It is set in doname_check().
 700  * First, 'make' will work as it worked before. Only when it is
 701  * going to say "don't know how to make target" it sets second_pass to true and
 702  * run 'doname' again but now trying to use Single Suffix Rules.
 703  */
 704                 if ((result == build_dont_know) && !automatic && (!implicit || second_pass) &&
 705                     ((line == NULL) ||
 706                      ((line->body.line.target != NULL) &&
 707                       !line->body.line.target->has_regular_dependency))) {
 708                         switch (find_suffix_rule(target,
 709                                                  target,
 710                                                  empty_name,
 711                                                  &command,
 712                                                  recheck_conditionals)) {
 713                         case build_failed:
 714                                 result = build_failed;
 715                                 break;
 716 #ifdef TEAMWARE_MAKE_CMN
 717                         case build_running:
 718                                 target->state = build_running;
 719                                 add_pending(target,
 720                                             --recursion_level,
 721                                             do_get,
 722                                             implicit,
 723                                             false);
 724                                 if (target->conditional_cnt > 0) {
 725                                         reset_locals(target,
 726                                                      old_locals,
 727                                                      get_prop(target->prop,
 728                                                              conditional_prop),
 729                                                      0);
 730                                 }
 731                                 return build_running;
 732 #endif
 733                         }
 734                 }
 735                 /* Try to sccs get */
 736                 if ((command == NULL) &&
 737                     (result == build_dont_know) &&
 738                     do_get) {
 739                         result = sccs_get(target, &command);
 740                 }
 741 
 742                 /* Use .DEFAULT rule if it is defined. */
 743                 if ((command == NULL) &&
 744                     (result == build_dont_know) &&
 745                     (true_target->colons == no_colon) &&
 746                     default_rule &&
 747                     !implicit) {
 748                         /* Make sure we have a line prop */
 749                         line = maybe_append_prop(target, line_prop);
 750                         command = line;
 751                         Boolean out_of_date;
 752                         if (true_target->is_member) {
 753                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
 754                                                                         line->body.line.dependency_time);
 755                         } else {
 756                                 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
 757                                                                     line->body.line.dependency_time);
 758                         }
 759                         if (build_unconditional || out_of_date) {
 760                                 line->body.line.is_out_of_date = true;
 761                                 if (debug_level > 0) {
 762                                         (void) printf(catgets(catd, 1, 17, "%*sBuilding %s using .DEFAULT because it is out of date\n"),
 763                                                       recursion_level,
 764                                                       "",
 765                                                       true_target->string_mb);
 766                                 }
 767                         }
 768                         line->body.line.sccs_command = false;
 769                         line->body.line.command_template = default_rule;
 770                         line->body.line.target = true_target;
 771                         line->body.line.star = NULL;
 772                         line->body.line.less = true_target;
 773                         line->body.line.percent = NULL;
 774                 }
 775         }
 776 
 777         /* We say "target up to date" if no cmd were executed for the target */
 778         if (!target->is_double_colon_parent) {
 779                 commands_done = false;
 780         }
 781 
 782         silent = silent_all;
 783         ignore_errors = ignore_errors_all;
 784         if  (posix)
 785         {
 786           if  (!silent)
 787           {
 788             silent = (Boolean) target->silent_mode;
 789           }
 790           if  (!ignore_errors)
 791           {
 792             ignore_errors = (Boolean) target->ignore_error_mode;
 793           }
 794         }
 795 
 796         int doname_dyntarget = 0;
 797 r_command:
 798         /* Run commands if any. */
 799         if ((command != NULL) &&
 800             (command->body.line.command_template != NULL)) {
 801                 if (result != build_failed) {
 802                         result = run_command(command, 
 803                                              (Boolean) ((parallel || save_parallel) && !silent));
 804 #ifdef NSE
 805                         nse_check_no_deps_no_rule(target,
 806                                 get_prop(target->prop, line_prop), command);
 807 #endif
 808                 }
 809                 switch (result) {
 810 #ifdef TEAMWARE_MAKE_CMN
 811                 case build_running:
 812                         add_running(target,
 813                                     true_target,
 814                                     command,
 815                                     --recursion_level,
 816                                     auto_count,
 817                                     automatics,
 818                                     do_get,
 819                                     implicit);
 820                         target->state = build_running;
 821                         if ((line = get_prop(target->prop,
 822                                              line_prop)) != NULL) {
 823                                 if (line->body.line.query != NULL) {
 824                                         delete_query_chain(line->body.line.query);
 825                                 }
 826                                 line->body.line.query = NULL;
 827                         }
 828                         if (target->conditional_cnt > 0) {
 829                                 reset_locals(target,
 830                                              old_locals,
 831                                              get_prop(target->prop,
 832                                                      conditional_prop),
 833                                              0);
 834                         }
 835                         return build_running;
 836                 case build_serial:
 837                         add_serial(target,
 838                                    --recursion_level,
 839                                    do_get,
 840                                    implicit);
 841                         target->state = build_running;
 842                         line = get_prop(target->prop, line_prop);
 843                         if (line != NULL) {
 844                                 if (line->body.line.query != NULL) {
 845                                         delete_query_chain(line->body.line.query);
 846                                 }
 847                                 line->body.line.query = NULL;
 848                         }
 849                         if (target->conditional_cnt > 0) {
 850                                 reset_locals(target,
 851                                              old_locals,
 852                                              get_prop(target->prop,
 853                                                      conditional_prop),
 854                                              0);
 855                         }
 856                         return build_running;
 857 #endif
 858                 case build_ok:
 859                         /* If all went OK set a nice timestamp */
 860                         if (true_target->stat.time == file_doesnt_exist) {
 861                                 true_target->stat.time = file_max_time;
 862                         }
 863                         break;
 864                 }
 865         } else {
 866                 /*
 867                  * If no command was found for the target, and it doesn't
 868                  * exist, and it is mentioned as a target in the makefile,
 869                  * we say it is extremely new and that it is OK.
 870                  */
 871                 if (target->colons != no_colon) {
 872                         if (true_target->stat.time == file_doesnt_exist){
 873                                 true_target->stat.time = file_max_time;
 874                         }
 875                         result = build_ok;
 876                 }
 877                 /*
 878                  * Trying dynamic targets.
 879                  */
 880                 if(!doname_dyntarget) {
 881                         doname_dyntarget = 1;
 882                         Name dtarg = find_dyntarget(target);
 883                         if(dtarg!=NULL) {
 884                                 if (!target->has_depe_list_expanded) {
 885                                         dynamic_dependencies(target);
 886                                 }
 887                                 if ((line = get_prop(target->prop, line_prop)) != NULL) {
 888                                         if (check_dependencies(&result,
 889                                                                line,
 890                                                                do_get,
 891                                                                target,
 892                                                                true_target,
 893                                                                doing_subtree,
 894                                                                &out_of_date_list,
 895                                                                old_locals,
 896                                                                implicit,
 897                                                                &command,
 898                                                                less,
 899                                                                rechecking_target,
 900                                                                recheck_conditionals))
 901                                         {
 902                                                 return build_running;
 903                                         }
 904                                         if (line->body.line.query != NULL) {
 905                                                 delete_query_chain(line->body.line.query);
 906                                         }
 907                                         line->body.line.query = out_of_date_list;
 908                                 }
 909                                 goto r_command;
 910                         }
 911                 }
 912                 /*
 913                  * If the file exists, it is OK that we couldnt figure
 914                  * out how to build it.
 915                  */
 916                 (void) exists(target);
 917                 if ((target->stat.time != file_doesnt_exist) &&
 918                     (result == build_dont_know)) {
 919                         result = build_ok;
 920                 }
 921         }
 922 
 923         /*
 924          * Some of the following is duplicated in the function finish_doname.
 925          * If anything is changed here, check to see if it needs to be
 926          * changed there.
 927          */
 928         if ((line = get_prop(target->prop, line_prop)) != NULL) {
 929                 if (line->body.line.query != NULL) {
 930                         delete_query_chain(line->body.line.query);
 931                 }
 932                 line->body.line.query = NULL;
 933         }
 934         target->state = result;
 935         parallel = save_parallel;
 936         if (target->conditional_cnt > 0) {
 937                 reset_locals(target,
 938                              old_locals,
 939                              get_prop(target->prop, conditional_prop),
 940                              0);
 941         }
 942         recursion_level--;
 943         if (target->is_member) {
 944                 Property member;
 945 
 946                 /* Propagate the timestamp from the member file to the member*/
 947                 if ((target->stat.time != file_max_time) &&
 948                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
 949                     (exists(member->body.member.member) > file_doesnt_exist)) {
 950                         target->stat.time =
 951                           member->body.member.member->stat.time;
 952                 }
 953         }
 954         /*
 955          * Check if we found any new auto dependencies when we
 956          * built the target.
 957          */
 958         if ((result == build_ok) && check_auto_dependencies(target,
 959                                                             auto_count,
 960                                                             automatics)) {
 961                 if (debug_level > 0) {
 962                         (void) printf(catgets(catd, 1, 18, "%*sTarget `%s' acquired new dependencies from build, rechecking all dependencies\n"),
 963                                       recursion_level,
 964                                       "",
 965                                       true_target->string_mb);
 966                 }
 967                 rechecking_target = true;
 968                 saved_commands_done = commands_done;
 969                 goto recheck_target;
 970         }
 971 
 972         if (rechecking_target && !commands_done) {
 973                 commands_done = saved_commands_done;
 974         }
 975 
 976         return result;
 977 }
 978 
 979 /*
 980  * DONE.
 981  *
 982  *      check_dependencies(result, line, do_get,
 983  *                      target, true_target, doing_subtree, out_of_date_tail,
 984  *                      old_locals, implicit, command, less, rechecking_target)
 985  *
 986  *      Return value:
 987  *                              True returned if some dependencies left running
 988  *                              
 989  *      Parameters:
 990  *              result          Pointer to cell we update if build failed
 991  *              line            We get the dependencies from here
 992  *              do_get          Allow use of sccs get in recursive doname()
 993  *              target          The target to chase dependencies for
 994  *              true_target     The real one for :: and lib(member)
 995  *              doing_subtree   True if building a conditional macro subtree
 996  *              out_of_date_tail Used to set the $? list
 997  *              old_locals      Used for resetting the local macros
 998  *              implicit        Called when scanning for implicit rules?
 999  *              command         Place to stuff command
1000  *              less            Set to $< value
1001  *
1002  *      Global variables used:
1003  *              command_changed Set if we suspect .make.state needs rewrite
1004  *              debug_level     Should we trace actions?
1005  *              force           The Name " FORCE", compared against
1006  *              recursion_level Used for tracing
1007  *              rewrite_statefile Set if .make.state needs rewriting
1008  *              wait_name       The Name ".WAIT", compared against
1009  */
1010 static Boolean
1011 #ifdef TEAMWARE_MAKE_CMN
1012 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
1013 #else
1014 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean, Chain *out_of_date_tail, Property, Boolean, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
1015 #endif
1016 {
1017         Boolean                 dependencies_running;
1018         register Dependency     dependency;
1019         Doname                  dep_result;
1020         Boolean                 dependency_changed = false;
1021 
1022         line->body.line.dependency_time = file_doesnt_exist;
1023         if (line->body.line.query != NULL) {
1024                 delete_query_chain(line->body.line.query);
1025         }
1026         line->body.line.query = NULL;
1027         line->body.line.is_out_of_date = false;
1028         dependencies_running = false;
1029         /*
1030          * Run thru all the dependencies and call doname() recursively
1031          * on each of them.
1032          */
1033         for (dependency = line->body.line.dependencies;
1034              dependency != NULL;
1035              dependency = dependency->next) {
1036                 Boolean this_dependency_changed = false;
1037 
1038                 if (!dependency->automatic &&
1039                     (rechecking_target || target->rechecking_target)) {
1040                         /*
1041                          * We only bother with the autos when rechecking
1042                          */
1043                         continue;
1044                 }
1045 
1046                 if (dependency->name == wait_name) {
1047                         /*
1048                          * The special target .WAIT means finish all of
1049                          * the prior dependencies before continuing.
1050                          */
1051                         if (dependencies_running) {
1052                                 break;
1053                         }
1054 #ifdef DISTRIBUTED
1055                 } else if ((!parallel_ok(dependency->name, false)) &&
1056                            (dependencies_running)) {
1057                         /*
1058                          * If we can't execute the current dependency in
1059                          * parallel, hold off the dependency processing
1060                          * to preserve the order of the dependencies.
1061                          */
1062                         break;
1063 #endif
1064                 } else {
1065                         timestruc_t     depe_time = file_doesnt_exist;
1066 
1067 
1068                         if (true_target->is_member) {
1069                                 depe_time = exists(dependency->name);
1070                         }
1071                         if (dependency->built ||
1072                             (dependency->name->state == build_failed)) {
1073                                 dep_result = (Doname) dependency->name->state;
1074                         } else {
1075 #ifdef NSE
1076                                 nse_check_sccs(target->string,
1077                                                dependency->name->string);
1078                                 nse_check_derived_src(target,
1079                                                dependency->name->string,
1080                                                line->body.line.command_template);
1081 #endif
1082                                 dep_result = doname_check(dependency->name,
1083                                                           do_get,
1084                                                           false,
1085                                                           (Boolean) dependency->automatic);
1086                         }
1087                         if (true_target->is_member || dependency->name->is_member) {
1088                                 /* should compare only secs, cause lib members does not have nsec time resolution */
1089                                 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
1090                                         this_dependency_changed =
1091                                           dependency_changed =
1092                                             true;
1093                                 }
1094                         } else {
1095                                 if (depe_time != dependency->name->stat.time) {
1096                                         this_dependency_changed =
1097                                           dependency_changed =
1098                                             true;
1099                                 }
1100                         }
1101                         dependency->built = true;
1102                         switch (dep_result) {
1103                         case build_running:
1104                                 dependencies_running = true;
1105                                 continue;
1106                         case build_failed:
1107                                 *result = build_failed;
1108                                 break;
1109                         case build_dont_know:
1110 /*
1111  * If make can't figure out how to make a dependency, maybe the dependency
1112  * is out of date. In this case, we just declare the target out of date
1113  * and go on. If we really need the dependency, the make'ing of the target
1114  * will fail. This will only happen for automatic (hidden) dependencies.
1115  */
1116                                 if(!recheck_conditionals) {
1117                                         line->body.line.is_out_of_date = true;
1118                                 }
1119                                 /*
1120                                  * Make sure the dependency is not saved
1121                                  * in the state file.
1122                                  */
1123                                 dependency->stale = true;
1124                                 rewrite_statefile =
1125                                   command_changed =
1126                                     true;
1127                                 if (debug_level > 0) {
1128                                         (void) printf(catgets(catd, 1, 19, "Target %s rebuilt because dependency %s does not exist\n"),
1129                                                      true_target->string_mb,
1130                                                      dependency->name->string_mb);
1131                                 }
1132                                 break;
1133                         }
1134                         if (dependency->name->depends_on_conditional) {
1135                                 target->depends_on_conditional = true;
1136                         }
1137                         if (dependency->name == force) {
1138                                 target->stat.time =
1139                                   dependency->name->stat.time;
1140                         }
1141                         /*
1142                          * Propagate new timestamp from "member" to
1143                          * "lib.a(member)".
1144                          */
1145                         (void) exists(dependency->name);
1146 
1147                         /* Collect the timestamp of the youngest dependency */
1148                         line->body.line.dependency_time =
1149                           MAX(dependency->name->stat.time,
1150                               line->body.line.dependency_time);
1151 
1152                         /* Correction: do not consider nanosecs for members */
1153                         if(true_target->is_member || dependency->name->is_member) {
1154                                 line->body.line.dependency_time.tv_nsec = 0;
1155                         }
1156 
1157                         if (debug_level > 1) {
1158                                 (void) printf(catgets(catd, 1, 20, "%*sDate(%s)=%s \n"),
1159                                               recursion_level,
1160                                               "",
1161                                               dependency->name->string_mb,
1162                                               time_to_string(dependency->name->
1163                                                              stat.time));
1164                                 if (dependency->name->stat.time > line->body.line.dependency_time) {
1165                                         (void) printf(catgets(catd, 1, 21, "%*sDate-dependencies(%s) set to %s\n"),
1166                                                       recursion_level,
1167                                                       "",
1168                                                       true_target->string_mb,
1169                                                       time_to_string(line->body.line.
1170                                                                      dependency_time));
1171                                 }
1172                         }
1173 
1174                         /* Build the $? list */
1175                         if (true_target->is_member) {
1176                                 if (this_dependency_changed == true) {
1177                                         true_target->stat.time = dependency->name->stat.time;
1178                                         true_target->stat.time.tv_sec--;
1179                                 } else {
1180                                         /* Dina: 
1181                                          * The next statement is commented
1182                                          * out as a fix for bug #1051032.
1183                                          * if dependency hasn't changed
1184                                          * then there's no need to invalidate
1185                                          * true_target. This statemnt causes
1186                                          * make to take much longer to process
1187                                          * an already-built archive. Soren
1188                                          * said it was a quick fix for some
1189                                          * problem he doesn't remember.
1190                                         true_target->stat.time = file_no_time;
1191                                          */
1192                                         (void) exists(true_target);
1193                                 }
1194                         } else {
1195                                 (void) exists(true_target);
1196                         }
1197                         Boolean out_of_date;
1198                         if (true_target->is_member || dependency->name->is_member) {
1199                                 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1200                                                                         dependency->name->stat.time);
1201                         } else {
1202                                 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1203                                                                     dependency->name->stat.time);
1204                         }
1205                         if ((build_unconditional || out_of_date) &&
1206                             (dependency->name != force) &&
1207                             (dependency->stale == false)) {
1208                                 *out_of_date_tail = ALLOC(Chain);
1209                                 if (dependency->name->is_member &&
1210                                     (get_prop(dependency->name->prop,
1211                                               member_prop) != NULL)) {
1212                                         (*out_of_date_tail)->name =
1213                                           get_prop(dependency->name->prop,
1214                                                    member_prop)->
1215                                                      body.member.member;
1216                                 } else {
1217                                         (*out_of_date_tail)->name =
1218                                           dependency->name;
1219                                 }
1220                                 (*out_of_date_tail)->next = NULL;
1221                                 out_of_date_tail = &(*out_of_date_tail)->next;
1222                                 if (debug_level > 0) {
1223                                         if (dependency->name->stat.time == file_max_time) {
1224                                                 (void) printf(catgets(catd, 1, 22, "%*sBuilding %s because %s does not exist\n"),
1225                                                               recursion_level,
1226                                                               "",
1227                                                               true_target->string_mb,
1228                                                               dependency->name->string_mb);
1229                                         } else {
1230                                                 (void) printf(catgets(catd, 1, 23, "%*sBuilding %s because it is out of date relative to %s\n"),
1231                                                               recursion_level,
1232                                                               "",
1233                                                               true_target->string_mb,
1234                                                               dependency->name->string_mb);
1235                                         }
1236                                 }
1237                         }
1238                         if (dependency->name == force) {
1239                                 force->stat.time =
1240                                   file_max_time;
1241                                 force->state = build_dont_know;
1242                         }
1243                 }
1244         }
1245 #ifdef TEAMWARE_MAKE_CMN
1246         if (dependencies_running) {
1247                 if (doing_subtree) {
1248                         if (target->conditional_cnt > 0) {
1249                                 reset_locals(target,
1250                                              old_locals,
1251                                              get_prop(target->prop,
1252                                                       conditional_prop),
1253                                              0);
1254                         }
1255                         return true;
1256                 } else {
1257                         target->state = build_running;
1258                         add_pending(target,
1259                                     --recursion_level,
1260                                     do_get,
1261                                     implicit,
1262                                     false);
1263                         if (target->conditional_cnt > 0) {
1264                                 reset_locals(target,
1265                                              old_locals,
1266                                              get_prop(target->prop,
1267                                                       conditional_prop),
1268                                              0);
1269                         }
1270                         return true;
1271                 }
1272         }
1273 #endif
1274         /*
1275          * Collect the timestamp of the youngest double colon target
1276          * dependency.
1277          */
1278         if (target->is_double_colon_parent) {
1279                 for (dependency = line->body.line.dependencies;
1280                      dependency != NULL;
1281                      dependency = dependency->next) {
1282                         Property        tmp_line;
1283 
1284                         if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) {
1285                                 if(tmp_line->body.line.dependency_time != file_max_time) {
1286                                         target->stat.time =
1287                                           MAX(tmp_line->body.line.dependency_time,
1288                                               target->stat.time);
1289                                 }
1290                         }
1291                 }
1292         }
1293         if ((true_target->is_member) && (dependency_changed == true)) {
1294                 true_target->stat.time = file_no_time;
1295         }
1296         /*
1297          * After scanning all the dependencies, we check the rule
1298          * if we found one.
1299          */
1300         if (line->body.line.command_template != NULL) {
1301                 if (line->body.line.command_template_redefined) {
1302                         warning(catgets(catd, 1, 24, "Too many rules defined for target %s"),
1303                                 target->string_mb);
1304                 }
1305                 *command = line;
1306                 /* Check if the target is out of date */
1307                 Boolean out_of_date;
1308                 if (true_target->is_member) {
1309                         out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1310                                                                 line->body.line.dependency_time);
1311                 } else {
1312                         out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1313                                                             line->body.line.dependency_time);
1314                 }
1315                 if (build_unconditional || out_of_date){
1316                         if(!recheck_conditionals) {
1317                                 line->body.line.is_out_of_date = true;
1318                         }
1319                 }
1320                 line->body.line.sccs_command = false;
1321                 line->body.line.target = true_target;
1322                 if(gnu_style) {
1323 
1324                         // set $< for explicit rule
1325                         if(line->body.line.dependencies != NULL) {
1326                                 less = line->body.line.dependencies->name;
1327                         }
1328 
1329                         // set $* for explicit rule
1330                         Name                    target_body;
1331                         Name                    tt = true_target;
1332                         Property                member;
1333                         register wchar_t        *target_end;
1334                         register Dependency     suffix;
1335                         register int            suffix_length;
1336                         Wstring                 targ_string;
1337                         Wstring                 suf_string;
1338 
1339                         if (true_target->is_member &&
1340                             ((member = get_prop(target->prop, member_prop)) !=
1341                              NULL)) {
1342                                 tt = member->body.member.member;
1343                         }
1344                         targ_string.init(tt);
1345                         target_end = targ_string.get_string() + tt->hash.length;
1346                         for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
1347                                 suffix_length = suffix->name->hash.length;
1348                                 suf_string.init(suffix->name);
1349                                 if (tt->hash.length < suffix_length) {
1350                                         continue;
1351                                 } else if (!IS_WEQUALN(suf_string.get_string(),
1352                                                 (target_end - suffix_length),
1353                                                 suffix_length)) {
1354                                         continue;
1355                                 }
1356                                 target_body = GETNAME(
1357                                         targ_string.get_string(),
1358                                         (int)(tt->hash.length - suffix_length)
1359                                 );
1360                                 line->body.line.star = target_body;
1361                         }
1362 
1363                         // set result = build_ok so that implicit rules are not used.
1364                         if(*result == build_dont_know) {
1365                                 *result = build_ok;
1366                         }
1367                 }
1368                 if (less != NULL) {
1369                         line->body.line.less = less;
1370                 }
1371         }
1372 
1373         return false;
1374 }
1375 
1376 /*
1377  *      dynamic_dependencies(target)
1378  *
1379  *      Checks if any dependency contains a macro ref
1380  *      If so, it replaces the dependency with the expanded version.
1381  *      Here, "$@" gets translated to target->string. That is
1382  *      the current name on the left of the colon in the
1383  *      makefile.  Thus,
1384  *              xyz:    s.$@.c
1385  *      translates into
1386  *              xyz:    s.xyz.c
1387  *
1388  *      Also, "$(@F)" translates to the same thing without a preceeding
1389  *      directory path (if one exists).
1390  *      Note, to enter "$@" on a dependency line in a makefile
1391  *      "$$@" must be typed. This is because make expands
1392  *      macros in dependency lists upon reading them.
1393  *      dynamic_dependencies() also expands file wildcards.
1394  *      If there are any Shell meta characters in the name,
1395  *      search the directory, and replace the dependency
1396  *      with the set of files the pattern matches
1397  *
1398  *      Parameters:
1399  *              target          Target to sanitize dependencies for
1400  *
1401  *      Global variables used:
1402  *              c_at            The Name "@", used to set macro value
1403  *              debug_level     Should we trace actions?
1404  *              dot             The Name ".", used to read directory
1405  *              recursion_level Used for tracing
1406  */
1407 void
1408 dynamic_dependencies(Name target)
1409 {
1410         wchar_t                 pattern[MAXPATHLEN];
1411         register wchar_t        *p;
1412         Property                line;
1413         register Dependency     dependency;
1414         register Dependency     *remove;
1415         String_rec              string;
1416         wchar_t                 buffer[MAXPATHLEN];
1417         register Boolean        set_at = false;
1418         register wchar_t        *start;
1419         Dependency              new_depe;
1420         register Boolean        reuse_cell;
1421         Dependency              first_member;
1422         Name                    directory;
1423         Name                    lib;
1424         Name                    member;
1425         Property                prop;
1426         Name                    true_target = target;
1427         wchar_t                 *library;
1428 
1429         if ((line = get_prop(target->prop, line_prop)) == NULL) {
1430                 return;
1431         }
1432         /* If the target is constructed from a "::" target we consider that */
1433         if (target->has_target_prop) {
1434                 true_target = get_prop(target->prop,
1435                                        target_prop)->body.target.target;
1436         }
1437         /* Scan all dependencies and process the ones that contain "$" chars */
1438         for (dependency = line->body.line.dependencies;
1439              dependency != NULL;
1440              dependency = dependency->next) {
1441                 if (!dependency->name->dollar) {
1442                         continue;
1443                 }
1444                 target->has_depe_list_expanded = true;
1445 
1446                 /* The make macro $@ is bound to the target name once per */
1447                 /* invocation of dynamic_dependencies() */
1448                 if (!set_at) {
1449                         (void) SETVAR(c_at, true_target, false);
1450                         set_at = true;
1451                 }
1452                 /* Expand this dependency string */
1453                 INIT_STRING_FROM_STACK(string, buffer);
1454                 expand_value(dependency->name, &string, false);
1455                 /* Scan the expanded string. It could contain whitespace */
1456                 /* which mean it expands to several dependencies */
1457                 start = string.buffer.start;
1458                 while (iswspace(*start)) {
1459                         start++;
1460                 }
1461                 /* Remove the cell (later) if the macro was empty */
1462                 if (start[0] == (int) nul_char) {
1463                         dependency->name = NULL;
1464                 }
1465 
1466 /* azv 10/26/95 to fix bug BID_1170218 */
1467                 if ((start[0] == (int) period_char) &&
1468                     (start[1] == (int) slash_char)) {
1469                         start += 2;
1470                 }
1471 /* azv */
1472 
1473                 first_member = NULL;
1474                 /* We use the original dependency cell for the first */
1475                 /* dependency from the expansion */
1476                 reuse_cell = true;
1477                 /* We also have to deal with dependencies that expand to */
1478                 /* lib.a(members) notation */
1479                 for (p = start; *p != (int) nul_char; p++) {
1480                         if ((*p == (int) parenleft_char)) {
1481                                 lib = GETNAME(start, p - start);
1482                                 lib->is_member = true;
1483                                 first_member = dependency;
1484                                 start = p + 1;
1485                                 while (iswspace(*start)) {
1486                                         start++;
1487                                 }
1488                                 break;
1489                         }
1490                 }
1491                 do {
1492                     /* First skip whitespace */
1493                         for (p = start; *p != (int) nul_char; p++) {
1494                                 if ((*p == (int) nul_char) ||
1495                                     iswspace(*p) ||
1496                                     (*p == (int) parenright_char)) {
1497                                         break;
1498                                 }
1499                         }
1500                         /* Enter dependency from expansion */
1501                         if (p != start) {
1502                                 /* Create new dependency cell if */
1503                                 /* this is not the first dependency */
1504                                 /* picked from the expansion */
1505                                 if (!reuse_cell) {
1506                                         new_depe = ALLOC(Dependency);
1507                                         new_depe->next = dependency->next;
1508                                         new_depe->automatic = false;
1509                                         new_depe->stale = false;
1510                                         new_depe->built = false;
1511                                         dependency->next = new_depe;
1512                                         dependency = new_depe;
1513                                 }
1514                                 reuse_cell = false;
1515                                 /* Internalize the dependency name */
1516                                 // tolik. Fix for bug 4110429: inconsistent expansion for macros that
1517                                 // include "//" and "/./"
1518                                 //dependency->name = GETNAME(start, p - start);
1519                                 dependency->name = normalize_name(start, p - start);
1520                                 if ((debug_level > 0) &&
1521                                     (first_member == NULL)) {
1522                                         (void) printf(catgets(catd, 1, 25, "%*sDynamic dependency `%s' for target `%s'\n"),
1523                                                       recursion_level,
1524                                                       "",
1525                                                       dependency->name->string_mb,
1526                                                       true_target->string_mb);
1527                                 }
1528                                 for (start = p; iswspace(*start); start++);
1529                                 p = start;
1530                         }
1531                 } while ((*p != (int) nul_char) &&
1532                          (*p != (int) parenright_char));
1533                 /* If the expansion was of lib.a(members) format we now */
1534                 /* enter the proper member cells */
1535                 if (first_member != NULL) {
1536                         /* Scan the new dependencies and transform them from */
1537                         /* "foo" to "lib.a(foo)" */
1538                         for (; 1; first_member = first_member->next) {
1539                                 /* Build "lib.a(foo)" name */
1540                                 INIT_STRING_FROM_STACK(string, buffer);
1541                                 APPEND_NAME(lib,
1542                                               &string,
1543                                               (int) lib->hash.length);
1544                                 append_char((int) parenleft_char, &string);
1545                                 APPEND_NAME(first_member->name,
1546                                               &string,
1547                                               FIND_LENGTH);
1548                                 append_char((int) parenright_char, &string);
1549                                 member = first_member->name;
1550                                 /* Replace "foo" with "lib.a(foo)" */
1551                                 first_member->name =
1552                                   GETNAME(string.buffer.start, FIND_LENGTH);
1553                                 if (string.free_after_use) {
1554                                         retmem(string.buffer.start);
1555                                 }
1556                                 if (debug_level > 0) {
1557                                         (void) printf(catgets(catd, 1, 26, "%*sDynamic dependency `%s' for target `%s'\n"),
1558                                                       recursion_level,
1559                                                       "",
1560                                                       first_member->name->
1561                                                       string_mb,
1562                                                       true_target->string_mb);
1563                                 }
1564                                 first_member->name->is_member = lib->is_member;
1565                                 /* Add member property to member */
1566                                 prop = maybe_append_prop(first_member->name,
1567                                                          member_prop);
1568                                 prop->body.member.library = lib;
1569                                 prop->body.member.entry = NULL;
1570                                 prop->body.member.member = member;
1571                                 if (first_member == dependency) {
1572                                         break;
1573                                 }
1574                         }
1575                 }
1576         }
1577         Wstring wcb;
1578         /* Then scan all the dependencies again. This time we want to expand */
1579         /* shell file wildcards */
1580         for (remove = &line->body.line.dependencies, dependency = *remove;
1581              dependency != NULL;
1582              dependency = *remove) {
1583                 if (dependency->name == NULL) {
1584                         dependency = *remove = (*remove)->next;
1585                         continue;
1586                 }
1587                 /* If dependency name string contains shell wildcards */
1588                 /* replace the name with the expansion */
1589                 if (dependency->name->wildcard) {
1590 #ifdef NSE
1591                         nse_wildcard(target->string, dependency->name->string);
1592 #endif
1593                         wcb.init(dependency->name);
1594                         if ((start = (wchar_t *) wschr(wcb.get_string(),
1595                                            (int) parenleft_char)) != NULL) {
1596                                 /* lib(*) type pattern */
1597                                 library = buffer;
1598                                 (void) wsncpy(buffer,
1599                                               wcb.get_string(),
1600                                               start - wcb.get_string());
1601                                 buffer[start-wcb.get_string()] =
1602                                   (int) nul_char;
1603                                 (void) wsncpy(pattern,
1604                                               start + 1,
1605 (int) (dependency->name->hash.length-(start-wcb.get_string())-2));
1606                                 pattern[dependency->name->hash.length -
1607                                         (start-wcb.get_string()) - 2] =
1608                                           (int) nul_char;
1609                         } else {
1610                                 library = NULL;
1611                                 (void) wsncpy(pattern,
1612                                               wcb.get_string(),
1613                                               (int) dependency->name->hash.length);
1614                                 pattern[dependency->name->hash.length] =
1615                                   (int) nul_char;
1616                         }
1617                         start = (wchar_t *) wsrchr(pattern, (int) slash_char);
1618                         if (start == NULL) {
1619                                 directory = dot;
1620                                 p = pattern;
1621                         } else {
1622                                 directory = GETNAME(pattern, start-pattern);
1623                                 p = start+1;
1624                         }
1625                         /* The expansion is handled by the read_dir() routine*/
1626                         if (read_dir(directory, p, line, library)) {
1627                                 *remove = (*remove)->next;
1628                         } else {
1629                                 remove = &dependency->next;
1630                         }
1631                 } else {
1632                         remove = &dependency->next;
1633                 }
1634         }
1635 
1636         /* Then unbind $@ */
1637         (void) SETVAR(c_at, (Name) NULL, false);
1638 }
1639 
1640 /*
1641  * DONE.
1642  *
1643  *      run_command(line)
1644  *
1645  *      Takes one Cmd_line and runs the commands from it.
1646  *
1647  *      Return value:
1648  *                              Indicates if the command failed or not
1649  *
1650  *      Parameters:
1651  *              line            The command line to run
1652  *
1653  *      Global variables used:
1654  *              commands_done   Set if we do run command
1655  *              current_line    Set to the line we run a command from
1656  *              current_target  Set to the target we run a command for
1657  *              file_number     Used to form temp file name
1658  *              keep_state      Indicates that .KEEP_STATE is on
1659  *              make_state      The Name ".make.state", used to check timestamp
1660  *              parallel        True if currently building in parallel
1661  *              parallel_process_cnt Count of parallel processes running
1662  *              quest           Indicates that make -q is on
1663  *              rewrite_statefile Set if we do run a command
1664  *              sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value
1665  *              temp_file_directory Used to form temp fie name
1666  *              temp_file_name  Set to the name of the temp file
1667  *              touch           Indicates that make -t is on
1668  */
1669 static Doname
1670 run_command(register Property line, Boolean)
1671 {
1672         register Doname         result = build_ok;
1673         register Boolean        remember_only = false;
1674         register Name           target = line->body.line.target;
1675         wchar_t                 *string;
1676         char                    tmp_file_path[MAXPATHLEN];
1677 
1678         if (!line->body.line.is_out_of_date && target->rechecking_target) {
1679                 target->rechecking_target = false;
1680                 return build_ok;
1681         }
1682 
1683         /*
1684          * Build the command if we know the target is out of date,
1685          * or if we want to check cmd consistency.
1686          */
1687         if (line->body.line.is_out_of_date || keep_state) {
1688                 /* Hack for handling conditional macros in DMake. */
1689                 if (!line->body.line.dont_rebuild_command_used) {
1690                         build_command_strings(target, line);
1691                 }
1692         }
1693         /* Never mind */
1694         if (!line->body.line.is_out_of_date) {
1695                 return build_ok;
1696         }
1697         /* If quest, then exit(1) because the target is out of date */
1698         if (quest) {
1699                 if (posix) {
1700 #ifdef TEAMWARE_MAKE_CMN
1701                         result = execute_parallel(line, true);
1702 #else
1703                         result = execute_serial(line);
1704 #endif
1705                 }
1706                 exit_status = 1;
1707                 exit(1);
1708         }
1709         /* We actually had to do something this time */
1710         rewrite_statefile = commands_done = true;
1711         /*
1712          * If this is an sccs command, we have to do some extra checking
1713          * and possibly complain. If the file can't be gotten because it's
1714          * checked out, we complain and behave as if the command was
1715          * executed eventhough we ignored the command.
1716          */
1717         if (!touch &&
1718             line->body.line.sccs_command &&
1719             (target->stat.time != file_doesnt_exist) &&
1720             ((target->stat.mode & 0222) != 0)) {
1721                 fatal(catgets(catd, 1, 27, "%s is writable so it cannot be sccs gotten"),
1722                       target->string_mb);
1723                 target->has_complained = remember_only = true;
1724         }
1725         /*
1726          * If KEEP_STATE is on, we make sure we have the timestamp for
1727          * .make.state. If .make.state changes during the command run,
1728          * we reread .make.state after the command. We also setup the
1729          * environment variable that asks utilities to report dependencies.
1730          */
1731         if (!touch &&
1732             keep_state &&
1733             !remember_only) {
1734                 (void) exists(make_state);
1735                 if((strlen(temp_file_directory) == 1) && 
1736                         (temp_file_directory[0] == '/')) {
1737                    tmp_file_path[0] = '\0';
1738                 } else {
1739                    strcpy(tmp_file_path, temp_file_directory);
1740                 }
1741                 sprintf(mbs_buffer,
1742                                 NOCATGETS("%s/.make.dependency.%08x.%d.%d"),
1743                                 tmp_file_path,
1744                                 hostid,
1745                                 getpid(),
1746                                 file_number++);
1747                 MBSTOWCS(wcs_buffer, mbs_buffer);
1748                 Boolean fnd;
1749                 temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd);
1750                 temp_file_name->stat.is_file = true;
1751                 int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2;
1752                 wchar_t *to = string = ALLOC_WC(len);
1753                 for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) {
1754                         if (*from == (int) space_char) {
1755                                 *to++ = (int) backslash_char;
1756                         }
1757                         *to++ = *from++;
1758                 }
1759                 *to++ = (int) space_char;
1760                 MBSTOWCS(to, target->string_mb);
1761                 Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd);
1762                 (void) SETVAR(sunpro_dependencies,
1763                               sprodep_name,
1764                               false);
1765                 retmem(string);
1766         } else {
1767                 temp_file_name = NULL;
1768         }
1769 
1770         /*
1771          * In case we are interrupted, we need to know what was going on.
1772          */
1773         current_target = target;
1774         /*
1775          * We also need to be able to save an empty command instead of the
1776          * interrupted one in .make.state.
1777          */
1778         current_line = line;
1779         if (remember_only) {
1780                 /* Empty block!!! */
1781         } else if (touch) {
1782                 result = touch_command(line, target, result);
1783                 if (posix) {
1784 #ifdef TEAMWARE_MAKE_CMN
1785                         result = execute_parallel(line, true);
1786 #else
1787                         result = execute_serial(line);
1788 #endif
1789                 }
1790         } else {
1791                 /*
1792                  * If this is not a touch run, we need to execute the
1793                  * proper command(s) for the target.
1794                  */
1795 #ifdef TEAMWARE_MAKE_CMN
1796                 if (parallel) {
1797                         if (!parallel_ok(target, true)) {
1798                                 /*
1799                                  * We are building in parallel, but
1800                                  * this target must be built in serial.
1801                                  */
1802                                 /*
1803                                  * If nothing else is building,
1804                                  * do this one, else wait.
1805                                  */
1806                                 if (parallel_process_cnt == 0) {
1807 #ifdef TEAMWARE_MAKE_CMN
1808                                         result = execute_parallel(line, true, target->localhost);
1809 #else
1810                                         result = execute_serial(line);
1811 #endif
1812                                 } else {
1813                                         current_target = NULL;
1814                                         current_line = NULL;
1815 /*
1816                                         line->body.line.command_used = NULL;
1817  */
1818                                         line->body.line.dont_rebuild_command_used = true;
1819                                         return build_serial;
1820                                 }
1821                         } else {
1822                                 result = execute_parallel(line, false);
1823                                 switch (result) {
1824                                 case build_running:
1825                                         return build_running;
1826                                 case build_serial:
1827                                         if (parallel_process_cnt == 0) {
1828 #ifdef TEAMWARE_MAKE_CMN
1829                                                 result = execute_parallel(line, true, target->localhost);
1830 #else
1831                                                 result = execute_serial(line);
1832 #endif
1833                                         } else {
1834                                                 current_target = NULL;
1835                                                 current_line = NULL;
1836                                                 target->parallel = false;
1837                                                 line->body.line.command_used =
1838                                                                         NULL;
1839                                                 return build_serial;
1840                                         }
1841                                 }
1842                         }
1843                 } else {
1844 #endif
1845 #ifdef TEAMWARE_MAKE_CMN
1846                         result = execute_parallel(line, true, target->localhost);
1847 #else
1848                         result = execute_serial(line);
1849 #endif
1850 #ifdef TEAMWARE_MAKE_CMN
1851                 }
1852 #endif
1853         }
1854         temp_file_name = NULL;
1855         if (report_dependencies_level == 0){
1856                 update_target(line, result);
1857         }
1858         current_target = NULL;
1859         current_line = NULL;
1860         return result;
1861 }
1862 
1863 /*
1864  *      execute_serial(line)
1865  *
1866  *      Runs thru the command line for the target and
1867  *      executes the rules one by one.
1868  *
1869  *      Return value:
1870  *                              The result of the command build
1871  *
1872  *      Parameters:     
1873  *              line            The command to execute
1874  *
1875  *      Static variables used:
1876  *
1877  *      Global variables used:
1878  *              continue_after_error -k flag
1879  *              do_not_exec_rule -n flag
1880  *              report_dependencies -P flag
1881  *              silent          Don't echo commands before executing
1882  *              temp_file_name  Temp file for auto dependencies
1883  *              vpath_defined   If true, translate path for command
1884  */
1885 Doname
1886 execute_serial(Property line)
1887 {
1888         int                     child_pid = 0;
1889 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
1890         Avo_MToolJobResultMsg   *job_result_msg;
1891         RWCollectable           *xdr_msg;
1892 #endif
1893         Boolean                 printed_serial;
1894         Doname                  result = build_ok;
1895         Cmd_line                rule, cmd_tail, command = NULL;
1896         char                    mbstring[MAXPATHLEN];
1897         int                     filed;
1898         Name                    target = line->body.line.target;
1899 
1900         SEND_MTOOL_MSG(
1901                 if (!sent_rsrc_info_msg) {
1902                         if (userName[0] == '\0') {
1903                                 avo_get_user(userName, NULL);
1904                         }
1905                         if (hostName[0] == '\0') {
1906                                 strcpy(hostName, avo_hostname());
1907                         }
1908                         send_rsrc_info_msg(1, hostName, userName);
1909                         sent_rsrc_info_msg = 1;
1910                 }
1911                 send_job_start_msg(line);
1912                 job_result_msg = new Avo_MToolJobResultMsg();
1913         );
1914 
1915         target->has_recursive_dependency = false;
1916         // We have to create a copy of the rules chain for processing because
1917         // the original one can be destroyed during .make.state file rereading.
1918         for (rule = line->body.line.command_used;
1919              rule != NULL;
1920              rule = rule->next) {
1921                 if (command == NULL) {
1922                         command = cmd_tail = ALLOC(Cmd_line);
1923                 } else {
1924                         cmd_tail->next = ALLOC(Cmd_line);
1925                         cmd_tail = cmd_tail->next;
1926                 }
1927                 *cmd_tail = *rule;
1928         }
1929         if (command) {
1930                 cmd_tail->next = NULL;
1931         }
1932         for (rule = command; rule != NULL; rule = rule->next) {
1933                 if (posix && (touch || quest) && !rule->always_exec) {
1934                         continue;
1935                 }
1936                 if (vpath_defined) {
1937                         rule->command_line =
1938                           vpath_translation(rule->command_line);
1939                 }
1940                 /* Echo command line, maybe. */
1941                 if ((rule->command_line->hash.length > 0) &&
1942                     !silent &&
1943                     (!rule->silent || do_not_exec_rule) &&
1944                     (report_dependencies_level == 0)) {
1945                         (void) printf("%s\n", rule->command_line->string_mb);
1946                         SEND_MTOOL_MSG(
1947                                 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
1948                         );
1949                 }
1950                 if (rule->command_line->hash.length > 0) {
1951                         SEND_MTOOL_MSG(
1952                                 (void) sprintf(mbstring,
1953                                                 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
1954                                                 tmpdir,
1955                                                 getpid(),
1956                                                 file_number++);
1957 
1958                                 int tmp_fd = mkstemp(mbstring);
1959                                 if(tmp_fd) {
1960                                         (void) close(tmp_fd);
1961                                 }
1962 
1963                                 stdout_file = strdup(mbstring);
1964                                 stderr_file = NULL;
1965                                 child_pid = pollResults(stdout_file,
1966                                                         (char *)NULL,
1967                                                         (char *)NULL);
1968                         );
1969                         /* Do assignment if command line prefixed with "=" */
1970                         if (rule->assign) {
1971                                 result = build_ok;
1972                                 do_assign(rule->command_line, target);
1973                         } else if (report_dependencies_level == 0) {
1974                                 /* Execute command line. */
1975 #ifdef DISTRIBUTED
1976                                 setvar_envvar((Avo_DoJobMsg *)NULL);
1977 #else
1978                                 setvar_envvar();
1979 #endif
1980                                 result = dosys(rule->command_line,
1981                                                (Boolean) rule->ignore_error,
1982                                                (Boolean) rule->make_refd,
1983                                                /* ds 98.04.23 bug #4085164. make should always show error messages */
1984                                                false,
1985                                                /* BOOLEAN(rule->silent &&
1986                                                        rule->ignore_error), */
1987                                                (Boolean) rule->always_exec,
1988                                                target,
1989                                                send_mtool_msgs);
1990 #ifdef NSE
1991                                 nse_did_recursion= false;
1992 #endif
1993                                 check_state(temp_file_name);
1994 #ifdef NSE
1995                                 nse_check_cd(line);
1996 #endif
1997                         }
1998                         SEND_MTOOL_MSG(
1999                                 append_job_result_msg(job_result_msg);
2000                                 if (child_pid > 0) {
2001                                         kill(child_pid, SIGUSR1);
2002                                         while (!((waitpid(child_pid, 0, 0) == -1)
2003                                                 && (errno == ECHILD)));
2004                                 }
2005                                 child_pid = 0;
2006                                 (void) unlink(stdout_file);
2007                                 retmem_mb(stdout_file);
2008                                 stdout_file = NULL;
2009                         );
2010                 } else {
2011                         result = build_ok;
2012                 }
2013                 if (result == build_failed) {
2014                         if (silent || rule->silent) {
2015                                 (void) printf(catgets(catd, 1, 242, "The following command caused the error:\n%s\n"),
2016                                               rule->command_line->string_mb);
2017                                 SEND_MTOOL_MSG(
2018                                         job_result_msg->appendOutput(AVO_STRDUP(catgets(catd, 1, 243, "The following command caused the error:")));
2019                                         job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
2020                                 );
2021                         }
2022                         if (!rule->ignore_error && !ignore_errors) {
2023                                 if (!continue_after_error) {
2024                                         SEND_MTOOL_MSG(
2025                                                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2026                                                 xdr_msg = (RWCollectable*)
2027                                                         job_result_msg;
2028                                                 xdr(&xdrs, xdr_msg);
2029                                                 (void) fflush(mtool_msgs_fp);
2030                                                 delete job_result_msg;
2031                                         );
2032                                         fatal(catgets(catd, 1, 244, "Command failed for target `%s'"),
2033                                               target->string_mb);
2034                                 }
2035                                 /*
2036                                  * Make sure a failing command is not
2037                                  * saved in .make.state.
2038                                  */
2039                                 line->body.line.command_used = NULL;
2040                                 break;
2041                         } else {
2042                                 result = build_ok;
2043                         }
2044                 }
2045         }
2046         for (rule = command; rule != NULL; rule = cmd_tail) {
2047                 cmd_tail = rule->next;
2048                 free(rule);
2049         }
2050         command = NULL;
2051         SEND_MTOOL_MSG(
2052                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2053                 xdr_msg = (RWCollectable*) job_result_msg;
2054                 xdr(&xdrs, xdr_msg);
2055                 (void) fflush(mtool_msgs_fp);
2056 
2057                 delete job_result_msg;
2058         );
2059         if (temp_file_name != NULL) {
2060                 free_name(temp_file_name);
2061         }
2062         temp_file_name = NULL;
2063 
2064         Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
2065         if(spro != NULL) {
2066                 Name val = spro->body.macro.value;
2067                 if(val != NULL) {
2068                         free_name(val);
2069                         spro->body.macro.value = NULL;
2070                 }
2071         }
2072         spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
2073         if(spro) {
2074                 char *val = spro->body.env_mem.value;
2075                 if(val != NULL) {
2076                         /* 
2077                          * Do not return memory allocated for SUNPRO_DEPENDENCIES
2078                          * It will be returned in setvar_daemon() in macro.cc 
2079                          */
2080                         //      retmem_mb(val);
2081                         spro->body.env_mem.value = NULL;
2082                 }
2083         }
2084         
2085         return result;
2086 }
2087 
2088 
2089 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2090 
2091 /*
2092  * Create and send an Avo_MToolRsrcInfoMsg.
2093  */
2094 void
2095 send_rsrc_info_msg(int max_jobs, char *hostname, char *username)
2096 {
2097         static int              first = 1;
2098         Avo_MToolRsrcInfoMsg    *msg;
2099         RWSlistCollectables     server_list;
2100         Avo_ServerState         *server_state;
2101         RWCollectable           *xdr_msg;
2102 
2103         if (!first) {
2104                 return;
2105         }
2106         first = 0;
2107 
2108         create_xdrs_ptr();
2109 
2110         server_state = new Avo_ServerState(max_jobs, hostname, username);
2111         server_list.append(server_state);
2112         msg = new Avo_MToolRsrcInfoMsg(&server_list);
2113 
2114         xdr_msg = (RWCollectable *)msg;
2115         xdr(get_xdrs_ptr(), xdr_msg);
2116         (void) fflush(get_mtool_msgs_fp());
2117 
2118         delete server_state;
2119         delete msg;
2120 }
2121 
2122 /*
2123  * Create and send an Avo_MToolJobStartMsg.
2124  */
2125 void
2126 send_job_start_msg(Property line)
2127 {
2128         int                     cmd_options = 0;
2129         Avo_MToolJobStartMsg    *msg;
2130         Cmd_line                rule;
2131         Name                    target = line->body.line.target;
2132         RWCollectable           *xdr_msg;
2133 
2134         if (userName[0] == '\0') {
2135                 avo_get_user(userName, NULL);
2136         }
2137         if (hostName[0] == '\0') {
2138                 strcpy(hostName, avo_hostname());
2139         }
2140 
2141         msg = new Avo_MToolJobStartMsg();
2142         msg->setJobId(++job_msg_id);
2143         msg->setTarget(AVO_STRDUP(target->string_mb));
2144         msg->setHost(AVO_STRDUP(hostName));
2145         msg->setUser(AVO_STRDUP(userName));
2146 
2147         for (rule = line->body.line.command_used;
2148              rule != NULL;
2149              rule = rule->next) {
2150                 if (posix && (touch || quest) && !rule->always_exec) {
2151                         continue;
2152                 }
2153                 if (vpath_defined) {
2154                         rule->command_line =
2155                           vpath_translation(rule->command_line);
2156                 }
2157                 cmd_options = 0;
2158                 if (rule->ignore_error || ignore_errors) {
2159                         cmd_options |= ignore_mask;
2160                 }
2161                 if (rule->silent || silent) {
2162                         cmd_options |= silent_mask;
2163                 }
2164                 if (rule->command_line->meta) {
2165                         cmd_options |= meta_mask;
2166                 }
2167                 if (!touch && (rule->command_line->hash.length > 0)) {
2168                         msg->appendCmd(new Avo_DmakeCommand(rule->command_line->string_mb, cmd_options));
2169                 }
2170         }
2171 
2172         xdr_msg = (RWCollectable*) msg;
2173         xdr(&xdrs, xdr_msg);
2174         (void) fflush(mtool_msgs_fp);
2175 
2176 /* tolik, 08/39/2002.
2177    I commented out this code because it causes using unallocated memory.
2178         delete msg;
2179 */
2180 }
2181 
2182 /*
2183  * Append the stdout/err to Avo_MToolJobResultMsg.
2184  */
2185 static void
2186 append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg)
2187 {
2188         FILE            *fp;
2189         char            line[MAXPATHLEN];
2190         char            stdout_file2[MAXPATHLEN];
2191 
2192         if (stdout_file != NULL) {
2193                 fp = fopen(stdout_file, "r");
2194                 if (fp == NULL) {
2195                         /* Hmmm... what should we do here? */
2196                         warning(catgets(catd, 1, 326, "fopen() of stdout_file failed. Output may be lost"));
2197                         return;
2198                 }
2199                 while (fgets(line, MAXPATHLEN, fp) != NULL) {
2200                         if (line[strlen(line) - 1] == '\n') {
2201                                 line[strlen(line) - 1] = '\0';
2202                         }
2203                         job_result_msg->appendOutput(AVO_STRDUP(line));
2204                 }
2205                 (void) fclose(fp);
2206                 us_sleep(STAT_RETRY_SLEEP_TIME);
2207         } else {
2208                 /* Hmmm... stdout_file shouldn't be NULL */
2209                 warning(catgets(catd, 1, 327, "Internal stdout_file variable shouldn't be NULL. Output may be lost"));
2210         }
2211 }
2212 #endif /* TEAMWARE_MAKE_CMN */
2213 
2214 /*
2215  *      vpath_translation(cmd)
2216  *
2217  *      Translates one command line by
2218  *      checking each word. If the word has an alias it is translated.
2219  *
2220  *      Return value:
2221  *                              The translated command
2222  *
2223  *      Parameters:
2224  *              cmd             Command to translate
2225  *
2226  *      Global variables used:
2227  */
2228 Name
2229 vpath_translation(register Name cmd)
2230 {
2231         wchar_t                 buffer[STRING_BUFFER_LENGTH];
2232         String_rec              new_cmd;
2233         wchar_t                 *p;
2234         wchar_t                 *start;
2235 
2236         if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) {
2237                 return cmd;
2238         }
2239         INIT_STRING_FROM_STACK(new_cmd, buffer);
2240 
2241         Wstring wcb(cmd);
2242         p = wcb.get_string();
2243 
2244         while (*p != (int) nul_char) {
2245                 while (iswspace(*p) && (*p != (int) nul_char)) {
2246                         append_char(*p++, &new_cmd);
2247                 }
2248                 start = p;
2249                 while (!iswspace(*p) && (*p != (int) nul_char)) {
2250                         p++;
2251                 }
2252                 cmd = GETNAME(start, p - start);
2253                 if (cmd->has_vpath_alias_prop) {
2254                         cmd = get_prop(cmd->prop, vpath_alias_prop)->
2255                                                 body.vpath_alias.alias;
2256                         APPEND_NAME(cmd,
2257                                       &new_cmd,
2258                                       (int) cmd->hash.length);
2259                 } else {
2260                         append_string(start, &new_cmd, p - start);
2261                 }
2262         }
2263         cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH);
2264         if (new_cmd.free_after_use) {
2265                 retmem(new_cmd.buffer.start);
2266         }
2267         return cmd;
2268 }
2269 
2270 /*
2271  *      check_state(temp_file_name)
2272  *
2273  *      Reads and checks the state changed by the previously executed command.
2274  *
2275  *      Parameters:
2276  *              temp_file_name  The auto dependency temp file
2277  *
2278  *      Global variables used:
2279  */
2280 void
2281 check_state(Name temp_file_name)
2282 {
2283         if (!keep_state) {
2284                 return;
2285         }
2286 
2287         /*
2288          * Then read the temp file that now might 
2289          * contain dependency reports from utilities 
2290          */
2291         read_dependency_file(temp_file_name);
2292 
2293         /*
2294          * And reread .make.state if it
2295          * changed (the command ran recursive makes) 
2296          */
2297         check_read_state_file();
2298         if (temp_file_name != NULL) {
2299                 (void) unlink(temp_file_name->string_mb);
2300         }
2301 }
2302 
2303 /*
2304  *      read_dependency_file(filename)
2305  *
2306  *      Read the temp file used for reporting dependencies to make
2307  *
2308  *      Parameters:
2309  *              filename        The name of the file with the state info
2310  *
2311  *      Global variables used:
2312  *              makefile_type   The type of makefile being read
2313  *              read_trace_level Debug flag
2314  *              temp_file_number The always increasing number for unique files
2315  *              trace_reader    Debug flag
2316  */
2317 static void
2318 read_dependency_file(register Name filename)
2319 {
2320         register Makefile_type  save_makefile_type;
2321 
2322         if (filename == NULL) {
2323                 return;
2324         }
2325         filename->stat.time = file_no_time;
2326         if (exists(filename) > file_doesnt_exist) {
2327                 save_makefile_type = makefile_type;
2328                 makefile_type = reading_cpp_file;
2329                 if (read_trace_level > 1) {
2330                         trace_reader = true;
2331                 }
2332                 temp_file_number++;
2333                 (void) read_simple_file(filename,
2334                                         false,
2335                                         false,
2336                                         false,
2337                                         false,
2338                                         false,
2339                                         false);
2340                 trace_reader = false;
2341                 makefile_type = save_makefile_type;
2342         }
2343 }
2344 
2345 /*
2346  *      check_read_state_file()
2347  *
2348  *      Check if .make.state has changed
2349  *      If it has we reread it
2350  *
2351  *      Parameters:
2352  *
2353  *      Global variables used:
2354  *              make_state      Make state file name
2355  *              makefile_type   Type of makefile being read
2356  *              read_trace_level Debug flag
2357  *              trace_reader    Debug flag
2358  */
2359 static void
2360 check_read_state_file(void)
2361 {
2362         timestruc_t             previous = make_state->stat.time;
2363         register Makefile_type  save_makefile_type;
2364         register Property       makefile;
2365 
2366         make_state->stat.time = file_no_time;
2367         if ((exists(make_state) == file_doesnt_exist) ||
2368             (make_state->stat.time == previous)) {
2369                 return;
2370         }
2371         save_makefile_type = makefile_type;
2372         makefile_type = rereading_statefile;
2373         /* Make sure we clear the old cached contents of .make.state */
2374         makefile = maybe_append_prop(make_state, makefile_prop);
2375         if (makefile->body.makefile.contents != NULL) {
2376                 retmem(makefile->body.makefile.contents);
2377                 makefile->body.makefile.contents = NULL;
2378         }
2379         if (read_trace_level > 1) {
2380                 trace_reader = true;
2381         }
2382         temp_file_number++;
2383         (void) read_simple_file(make_state,
2384                                 false,
2385                                 false,
2386                                 false,
2387                                 false,
2388                                 false,
2389                                 true);
2390         trace_reader = false;
2391         makefile_type = save_makefile_type;
2392 }
2393 
2394 /*
2395  *      do_assign(line, target)
2396  *
2397  *      Handles runtime assignments for command lines prefixed with "=".
2398  *
2399  *      Parameters:
2400  *              line            The command that contains an assignment
2401  *              target          The Name of the target, used for error reports
2402  *
2403  *      Global variables used:
2404  *              assign_done     Set to indicate doname needs to reprocess
2405  */
2406 static void
2407 do_assign(register Name line, register Name target)
2408 {
2409         Wstring wcb(line);
2410         register wchar_t        *string = wcb.get_string();
2411         register wchar_t        *equal;
2412         register Name           name;
2413         register Boolean        append = false;
2414 
2415         /*
2416          * If any runtime assignments are done, doname() must reprocess all
2417          * targets in the future since the macro values used to build the
2418          * command lines for the targets might have changed.
2419          */
2420         assign_done = true;
2421         /* Skip white space. */
2422         while (iswspace(*string)) {
2423                 string++;
2424         }
2425         equal = string;
2426         /* Find "+=" or "=". */
2427         while (!iswspace(*equal) &&
2428                (*equal != (int) plus_char) &&
2429                (*equal != (int) equal_char)) {
2430                 equal++;
2431         }
2432         /* Internalize macro name. */
2433         name = GETNAME(string, equal - string);
2434         /* Skip over "+=" "=". */
2435         while (!((*equal == (int) nul_char) ||
2436                  (*equal == (int) equal_char) ||
2437                  (*equal == (int) plus_char))) {
2438                 equal++;
2439         }
2440         switch (*equal) {
2441         case nul_char:
2442                 fatal(catgets(catd, 1, 31, "= expected in rule `%s' for target `%s'"),
2443                       line->string_mb,
2444                       target->string_mb);
2445         case plus_char:
2446                 append = true;
2447                 equal++;
2448                 break;
2449         }
2450         equal++;
2451         /* Skip over whitespace in front of value. */
2452         while (iswspace(*equal)) {
2453                 equal++;
2454         }
2455         /* Enter new macro value. */
2456         enter_equal(name,
2457                     GETNAME(equal, wcb.get_string() + line->hash.length - equal),
2458                     append);
2459 }
2460 
2461 /*
2462  *      build_command_strings(target, line)
2463  *
2464  *      Builds the command string to used when
2465  *      building a target. If the string is different from the previous one
2466  *      is_out_of_date is set.
2467  *
2468  *      Parameters:
2469  *              target          Target to build commands for
2470  *              line            Where to stuff result
2471  *
2472  *      Global variables used:
2473  *              c_at            The Name "@", used to set macro value
2474  *              command_changed Set if command is different from old
2475  *              debug_level     Should we trace activities?
2476  *              do_not_exec_rule Always echo when running -n
2477  *              empty_name      The Name "", used for empty rule
2478  *              funny           Semantics of characters
2479  *              ignore_errors   Used to init field for line
2480  *              is_conditional  Set to false befor evaling macro, checked
2481  *                              after expanding macros
2482  *              keep_state      Indicates that .KEEP_STATE is on
2483  *              make_word_mentioned Set by macro eval, inits field for cmd
2484  *              query           The Name "?", used to set macro value
2485  *              query_mentioned Set by macro eval, inits field for cmd
2486  *              recursion_level Used for tracing
2487  *              silent          Used to init field for line
2488  */
2489 static void
2490 build_command_strings(Name target, register Property line)
2491 {
2492         String_rec              command_line;
2493         register Cmd_line       command_template = line->body.line.command_template;
2494         register Cmd_line       *insert = &line->body.line.command_used;
2495         register Cmd_line       used = *insert;
2496         wchar_t                 buffer[STRING_BUFFER_LENGTH];
2497         wchar_t                 *start;
2498         Name                    new_command_line;
2499         register Boolean        new_command_longer = false;
2500         register Boolean        ignore_all_command_dependency = true;
2501         Property                member;
2502         static Name             less_name;
2503         static Name             percent_name;
2504         static Name             star;
2505         Name                    tmp_name;
2506 
2507         if (less_name == NULL) {
2508                 MBSTOWCS(wcs_buffer, "<");
2509                 less_name = GETNAME(wcs_buffer, FIND_LENGTH);
2510                 MBSTOWCS(wcs_buffer, "%");
2511                 percent_name = GETNAME(wcs_buffer, FIND_LENGTH);
2512                 MBSTOWCS(wcs_buffer, "*");
2513                 star = GETNAME(wcs_buffer, FIND_LENGTH);
2514         }
2515 
2516         /* We have to check if a target depends on conditional macros */
2517         /* Targets that do must be reprocessed by doname() each time around */
2518         /* since the macro values used when building the target might have */
2519         /* changed */
2520         conditional_macro_used = false;
2521         /* If we are building a lib.a(member) target $@ should be bound */
2522         /* to lib.a */
2523         if (target->is_member &&
2524             ((member = get_prop(target->prop, member_prop)) != NULL)) {
2525                 target = member->body.member.library;
2526         }
2527         /* If we are building a "::" help target $@ should be bound to */
2528         /* the real target name */
2529         /* A lib.a(member) target is never :: */
2530         if (target->has_target_prop) {
2531                 target = get_prop(target->prop, target_prop)->
2532                   body.target.target;
2533         }
2534         /* Bind the magic macros that make supplies */
2535         tmp_name = target;
2536         if(tmp_name != NULL) {
2537                 if (tmp_name->has_vpath_alias_prop) {
2538                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2539                                         body.vpath_alias.alias;
2540                 }
2541         }
2542         (void) SETVAR(c_at, tmp_name, false);
2543 
2544         tmp_name = line->body.line.star;
2545         if(tmp_name != NULL) {
2546                 if (tmp_name->has_vpath_alias_prop) {
2547                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2548                                         body.vpath_alias.alias;
2549                 }
2550         }
2551         (void) SETVAR(star, tmp_name, false);
2552 
2553         tmp_name = line->body.line.less;
2554         if(tmp_name != NULL) {
2555                 if (tmp_name->has_vpath_alias_prop) {
2556                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2557                                         body.vpath_alias.alias;
2558                 }
2559         }
2560         (void) SETVAR(less_name, tmp_name, false);
2561 
2562         tmp_name = line->body.line.percent;
2563         if(tmp_name != NULL) {
2564                 if (tmp_name->has_vpath_alias_prop) {
2565                         tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2566                                         body.vpath_alias.alias;
2567                 }
2568         }
2569         (void) SETVAR(percent_name, tmp_name, false);
2570 
2571         /* $? is seldom used and it is expensive to build */
2572         /* so we store the list form and build the string on demand */
2573         Chain query_list = NULL;
2574         Chain *query_list_tail = &query_list;
2575 
2576         for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) {
2577                 *query_list_tail = ALLOC(Chain);
2578                 (*query_list_tail)->name = ch->name;
2579                 if ((*query_list_tail)->name->has_vpath_alias_prop) {
2580                         (*query_list_tail)->name =
2581                                 get_prop((*query_list_tail)->name->prop,
2582                                         vpath_alias_prop)->body.vpath_alias.alias;
2583                 }
2584                 (*query_list_tail)->next = NULL;
2585                 query_list_tail = &(*query_list_tail)->next;
2586         }
2587         (void) setvar_daemon(query,
2588                              (Name) query_list,
2589                              false,
2590                              chain_daemon,
2591                              false,
2592                              debug_level);
2593 
2594         /* build $^ */
2595         Chain hat_list = NULL;
2596         Chain *hat_list_tail = &hat_list;
2597 
2598         for (Dependency dependency = line->body.line.dependencies; 
2599                 dependency != NULL;
2600                 dependency = dependency->next) {
2601                 /* skip automatic dependencies */
2602                 if (!dependency->automatic) {
2603                         if ((dependency->name != force) &&
2604                                 (dependency->stale == false)) {
2605                                 *hat_list_tail = ALLOC(Chain);
2606                         
2607                                 if (dependency->name->is_member &&
2608                                         (get_prop(dependency->name->prop, member_prop) != NULL)) {
2609                                         (*hat_list_tail)->name = 
2610                                                         get_prop(dependency->name->prop,
2611                                                                 member_prop)->body.member.member;
2612                                 } else {
2613                                         (*hat_list_tail)->name = dependency->name;
2614                                 }
2615 
2616                                 if((*hat_list_tail)->name != NULL) {
2617                                         if ((*hat_list_tail)->name->has_vpath_alias_prop) {
2618                                                 (*hat_list_tail)->name =
2619                                                         get_prop((*hat_list_tail)->name->prop,
2620                                                                 vpath_alias_prop)->body.vpath_alias.alias;
2621                                         }
2622                                 }
2623 
2624                                 (*hat_list_tail)->next = NULL;
2625                                 hat_list_tail = &(*hat_list_tail)->next;
2626                         }
2627                 }
2628         }
2629         (void) setvar_daemon(hat,
2630                              (Name) hat_list,
2631                              false,
2632                              chain_daemon,
2633                              false,
2634                              debug_level);
2635 
2636 /* We have two command sequences we need to handle */
2637 /* The old one that we probably read from .make.state */
2638 /* and the new one we are building that will replace the old one */
2639 /* Even when KEEP_STATE is not on we build a new command sequence and store */
2640 /* it in the line prop. This command sequence is then executed by */
2641 /* run_command(). If KEEP_STATE is on it is also later written to */
2642 /* .make.state. The routine replaces the old command line by line with the */
2643 /* new one trying to reuse Cmd_lines */
2644 
2645         /* If there is no old command_used we have to start creating */
2646         /* Cmd_lines to keep the new cmd in */
2647         if (used == NULL) {
2648                 new_command_longer = true;
2649                 *insert = used = ALLOC(Cmd_line);
2650                 used->next = NULL;
2651                 used->command_line = NULL;
2652                 insert = &used->next;
2653         }
2654         /* Run thru the template for the new command and build the expanded */
2655         /* new command lines */
2656         for (;
2657              command_template != NULL;
2658              command_template = command_template->next, insert = &used->next, used = *insert) {
2659                 /* If there is no old command_used Cmd_line we need to */
2660                 /* create one and say that cmd consistency failed */
2661                 if (used == NULL) {
2662                         new_command_longer = true;
2663                         *insert = used = ALLOC(Cmd_line);
2664                         used->next = NULL;
2665                         used->command_line = empty_name;
2666                 }
2667                 /* Prepare the Cmd_line for the processing */
2668                 /* The command line prefixes "@-=?" are stripped and that */
2669                 /* information is saved in the Cmd_line */
2670                 used->assign = false;
2671                 used->ignore_error = ignore_errors;
2672                 used->silent = silent;
2673                 used->always_exec = false;
2674                 /* Expand the macros in the command line */
2675                 INIT_STRING_FROM_STACK(command_line, buffer);
2676                 make_word_mentioned =
2677                   query_mentioned =
2678                     false;
2679                 expand_value(command_template->command_line, &command_line, true);
2680                 /* If the macro $(MAKE) is mentioned in the command */
2681                 /* "make -n" runs actually execute the command */
2682                 used->make_refd = make_word_mentioned;
2683                 used->ignore_command_dependency = query_mentioned;
2684                 /* Strip the prefixes */
2685                 start = command_line.buffer.start;
2686                 for (;
2687                      iswspace(*start) ||
2688                      (get_char_semantics_value(*start) & (int) command_prefix_sem);
2689                      start++) {
2690                         switch (*start) {
2691                         case question_char:
2692                                 used->ignore_command_dependency = true;
2693                                 break;
2694                         case exclam_char:
2695                                 used->ignore_command_dependency = false;
2696                                 break;
2697                         case equal_char:
2698                                 used->assign = true;
2699                                 break;
2700                         case hyphen_char:
2701                                 used->ignore_error = true;
2702                                 break;
2703                         case at_char:
2704                                 if (!do_not_exec_rule) {
2705                                         used->silent = true;
2706                                 }
2707                                 break;
2708                         case plus_char:
2709                                 if(posix) {
2710                                   used->always_exec  = true;
2711                                 }
2712                                 break;
2713                         }
2714                 }
2715                 /* If all command lines of the template are prefixed with "?"*/
2716                 /* the VIRTUAL_ROOT is not used for cmd consistency checks */
2717                 if (!used->ignore_command_dependency) {
2718                         ignore_all_command_dependency = false;
2719                 }
2720                 /* Internalize the expanded and stripped command line */
2721                 new_command_line = GETNAME(start, FIND_LENGTH);
2722                 if ((used->command_line == NULL) &&
2723                     (line->body.line.sccs_command)) {
2724                         used->command_line = new_command_line;
2725                         new_command_longer = false;
2726                 }
2727                 /* Compare it with the old one for command consistency */
2728                 if (used->command_line != new_command_line) {
2729                         Name vpath_translated = vpath_translation(new_command_line);
2730                         if (keep_state &&
2731                             !used->ignore_command_dependency && (vpath_translated != used->command_line)) {
2732                                 if (debug_level > 0) {
2733                                         if (used->command_line != NULL
2734                                             && *used->command_line->string_mb !=
2735                                             '\0') {
2736                                                 (void) printf(catgets(catd, 1, 32, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"),
2737                                                               recursion_level,
2738                                                               "",
2739                                                               target->string_mb,
2740                                                               vpath_translated->string_mb,
2741                                                               recursion_level,
2742                                                               "",
2743                                                               used->
2744                                                               command_line->
2745                                                               string_mb);
2746                                         } else {
2747                                                 (void) printf(catgets(catd, 1, 33, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"),
2748                                                               recursion_level,
2749                                                               "",
2750                                                               target->string_mb,
2751                                                               vpath_translated->string_mb,
2752                                                               recursion_level,
2753                                                               "");
2754                                         }
2755                                 }
2756                                 command_changed = true;
2757                                 line->body.line.is_out_of_date = true;
2758                         }
2759                         used->command_line = new_command_line;
2760                 }
2761                 if (command_line.free_after_use) {
2762                         retmem(command_line.buffer.start);
2763                 }
2764         }
2765         /* Check if the old command is longer than the new for */
2766         /* command consistency */
2767         if (used != NULL) {
2768                 *insert = NULL;
2769                 if (keep_state &&
2770                     !ignore_all_command_dependency) {
2771                         if (debug_level > 0) {
2772                                 (void) printf(catgets(catd, 1, 34, "%*sBuilding %s because new command shorter than old\n"),
2773                                               recursion_level,
2774                                               "",
2775                                               target->string_mb);
2776                         }
2777                         command_changed = true;
2778                         line->body.line.is_out_of_date = true;
2779                 }
2780         }
2781         /* Check if the new command is longer than the old command for */
2782         /* command consistency */
2783         if (new_command_longer &&
2784             !ignore_all_command_dependency &&
2785             keep_state) {
2786                 if (debug_level > 0) {
2787                         (void) printf(catgets(catd, 1, 35, "%*sBuilding %s because new command longer than old\n"),
2788                                       recursion_level,
2789                                       "",
2790                                       target->string_mb);
2791                 }
2792                 command_changed = true;
2793                 line->body.line.is_out_of_date = true;
2794         }
2795         /* Unbind the magic macros */
2796         (void) SETVAR(c_at, (Name) NULL, false);
2797         (void) SETVAR(star, (Name) NULL, false);
2798         (void) SETVAR(less_name, (Name) NULL, false);
2799         (void) SETVAR(percent_name, (Name) NULL, false);
2800         (void) SETVAR(query, (Name) NULL, false);
2801         if (query_list != NULL) {
2802                 delete_query_chain(query_list);
2803         }
2804         (void) SETVAR(hat, (Name) NULL, false);
2805         if (hat_list != NULL) {
2806                 delete_query_chain(hat_list);
2807         }
2808 
2809         if (conditional_macro_used) {
2810                 target->conditional_macro_list = cond_macro_list;
2811                 cond_macro_list = NULL;
2812                 target->depends_on_conditional = true;
2813         }
2814 }
2815 
2816 /*
2817  *      touch_command(line, target, result)
2818  *
2819  *      If this is an "make -t" run we do this.
2820  *      We touch all targets in the target group ("foo + fie:") if any.
2821  *
2822  *      Return value:
2823  *                              Indicates if the command failed or not
2824  *
2825  *      Parameters:
2826  *              line            The command line to update
2827  *              target          The target we are touching
2828  *              result          Initial value for the result we return
2829  *
2830  *      Global variables used:
2831  *              do_not_exec_rule Indicates that -n is on
2832  *              silent          Do not echo commands
2833  */
2834 static Doname
2835 touch_command(register Property line, register Name target, Doname result)
2836 {
2837         Name                    name;
2838         register Chain          target_group;
2839         String_rec              touch_string;
2840         wchar_t                 buffer[MAXPATHLEN];
2841         Name                    touch_cmd;
2842         Cmd_line                rule;
2843 
2844 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2845         Avo_MToolJobResultMsg   *job_result_msg;
2846         RWCollectable           *xdr_msg;
2847         int                     child_pid = 0;
2848         wchar_t                 string[MAXPATHLEN];
2849         char                    mbstring[MAXPATHLEN];
2850         int                     filed;
2851 #endif
2852 
2853         SEND_MTOOL_MSG(
2854                 if (!sent_rsrc_info_msg) {
2855                         if (userName[0] == '\0') {
2856                                 avo_get_user(userName, NULL);
2857                         }
2858                         if (hostName[0] == '\0') {
2859                                 strcpy(hostName, avo_hostname());
2860                         }
2861                         send_rsrc_info_msg(1, hostName, userName);
2862                         sent_rsrc_info_msg = 1;
2863                 }
2864                 send_job_start_msg(line);
2865                 job_result_msg = new Avo_MToolJobResultMsg();
2866         );
2867         for (name = target, target_group = NULL; name != NULL;) {
2868                 if (!name->is_member) {
2869                         /*
2870                          * Build a touch command that can be passed
2871                          * to dosys(). If KEEP_STATE is on, "make -t"
2872                          * will save the proper command, not the
2873                          * "touch" in .make.state.
2874                          */
2875                         INIT_STRING_FROM_STACK(touch_string, buffer);
2876                         MBSTOWCS(wcs_buffer, NOCATGETS("touch "));
2877                         append_string(wcs_buffer, &touch_string, FIND_LENGTH);
2878                         touch_cmd = name;
2879                         if (name->has_vpath_alias_prop) {
2880                                 touch_cmd = get_prop(name->prop,
2881                                                  vpath_alias_prop)->
2882                                                    body.vpath_alias.alias;
2883                         }
2884                         APPEND_NAME(touch_cmd,
2885                                       &touch_string,
2886                                       FIND_LENGTH);
2887                         touch_cmd = GETNAME(touch_string.buffer.start,
2888                                             FIND_LENGTH);
2889                         if (touch_string.free_after_use) {
2890                                 retmem(touch_string.buffer.start);
2891                         }
2892                         if (!silent ||
2893                             do_not_exec_rule &&
2894                             (target_group == NULL)) {
2895                                 (void) printf("%s\n", touch_cmd->string_mb);
2896                                 SEND_MTOOL_MSG(
2897                                         job_result_msg->appendOutput(AVO_STRDUP(touch_cmd->string_mb));
2898                                 );
2899                         }
2900                         /* Run the touch command, or simulate it */
2901                         if (!do_not_exec_rule) {
2902 
2903                                 SEND_MTOOL_MSG(
2904                                         (void) sprintf(mbstring,
2905                                                         NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
2906                                                         tmpdir,
2907                                                         getpid(),
2908                                                         file_number++);
2909                                 
2910                                         int tmp_fd = mkstemp(mbstring);
2911                                         if(tmp_fd) {
2912                                                 (void) close(tmp_fd);
2913                                         }
2914 
2915                                         stdout_file = strdup(mbstring);
2916                                         stderr_file = NULL;
2917                                         child_pid = pollResults(stdout_file,
2918                                                                 (char *)NULL,
2919                                                                 (char *)NULL);
2920                                 );
2921 
2922                                 result = dosys(touch_cmd,
2923                                                false,
2924                                                false,
2925                                                false,
2926                                                false,
2927                                                name,
2928                                                send_mtool_msgs);
2929 
2930                                 SEND_MTOOL_MSG(
2931                                         append_job_result_msg(job_result_msg);
2932                                         if (child_pid > 0) {
2933                                                 kill(child_pid, SIGUSR1);
2934                                                 while (!((waitpid(child_pid, 0, 0) == -1)
2935                                                         && (errno == ECHILD)));
2936                                         }
2937                                         child_pid = 0;
2938                                         (void) unlink(stdout_file);
2939                                         retmem_mb(stdout_file);
2940                                         stdout_file = NULL;
2941                                 );
2942 
2943                         } else {
2944                                 result = build_ok;
2945                         }
2946                 } else {
2947                         result = build_ok;
2948                 }
2949                 if (target_group == NULL) {
2950                         target_group = line->body.line.target_group;
2951                 } else {
2952                         target_group = target_group->next;
2953                 }
2954                 if (target_group != NULL) {
2955                         name = target_group->name;
2956                 } else {
2957                         name = NULL;
2958                 }
2959         }
2960         SEND_MTOOL_MSG(
2961                 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2962                 xdr_msg = (RWCollectable*) job_result_msg;
2963                 xdr(&xdrs, xdr_msg);
2964                 (void) fflush(mtool_msgs_fp);
2965                 delete job_result_msg;
2966         );
2967         return result;
2968 }
2969 
2970 /*
2971  *      update_target(line, result)
2972  *
2973  *      updates the status of a target after executing its commands.
2974  *
2975  *      Parameters:
2976  *              line            The command line block to update
2977  *              result          Indicates that build is OK so can update
2978  *
2979  *      Global variables used:
2980  *              do_not_exec_rule Indicates that -n is on
2981  *              touch           Fake the new timestamp if we are just touching
2982  */
2983 void
2984 update_target(Property line, Doname result)
2985 {
2986         Name                    target;
2987         Chain                   target_group;
2988         Property                line2;
2989         timestruc_t             old_stat_time;
2990         Property                member;
2991 
2992         /*
2993          * [tolik] Additional fix for bug 1063790. It was fixed
2994          * for serial make long ago, but DMake dumps core when
2995          * target is a symlink and sccs file is newer then target. 
2996          * In this case, finish_children() calls update_target()
2997          * with line==NULL.
2998          */
2999         if(line == NULL) {
3000                 /* XXX. Should we do anything here? */
3001                 return;
3002         }       
3003 
3004         target = line->body.line.target;
3005 
3006         if ((result == build_ok) && (line->body.line.command_used != NULL)) {
3007                 if (do_not_exec_rule ||
3008                     touch ||
3009                     (target->is_member &&
3010                      (line->body.line.command_template != NULL) &&
3011                      (line->body.line.command_template->command_line->string_mb[0] == 0) &&
3012                      (line->body.line.command_template->next == NULL))) {
3013                         /* If we are simulating execution we need to fake a */
3014                         /* new timestamp for the target we didnt build */
3015                         target->stat.time = file_max_time;
3016                 } else {
3017                         /*
3018                          * If we really built the target we read the new
3019                          * timestamp.
3020                          * Fix for bug #1110906: if .c file is newer than
3021                          * the corresponding .o file which is in an archive
3022                          * file, make will compile the .c file but it won't
3023                          * update the object in the .a file.
3024                          */
3025                         old_stat_time = target->stat.time;
3026                         target->stat.time = file_no_time;
3027                         (void) exists(target);
3028                         if ((target->is_member) &&
3029                             (target->stat.time == old_stat_time)) {
3030                                 member = get_prop(target->prop, member_prop);
3031                                 if (member != NULL) {
3032                                         target->stat.time = member->body.member.library->stat.time;
3033                                         target->stat.time.tv_sec++;
3034                                 }
3035                         }
3036                 }
3037                 /* If the target is part of a group we need to propagate the */
3038                 /* result of the run to all members */
3039                 for (target_group = line->body.line.target_group;
3040                      target_group != NULL;
3041                      target_group = target_group->next) {
3042                         target_group->name->stat.time = target->stat.time;
3043                         line2 = maybe_append_prop(target_group->name,
3044                                                   line_prop);
3045                         line2->body.line.command_used =
3046                           line->body.line.command_used;
3047                         line2->body.line.target = target_group->name;
3048                 }
3049         }
3050         target->has_built = true;
3051 }
3052 
3053 /*
3054  *      sccs_get(target, command)
3055  *
3056  *      Figures out if it possible to sccs get a file
3057  *      and builds the command to do it if it is.
3058  *
3059  *      Return value:
3060  *                              Indicates if sccs get failed or not
3061  *
3062  *      Parameters:
3063  *              target          Target to get
3064  *              command         Where to deposit command to use
3065  *
3066  *      Global variables used:
3067  *              debug_level     Should we trace activities?
3068  *              recursion_level Used for tracing
3069  *              sccs_get_rule   The rule to used for sccs getting
3070  */
3071 static Doname
3072 sccs_get(register Name target, register Property *command)
3073 {
3074         register int            result;
3075         char                    link[MAXPATHLEN];
3076         String_rec              string;
3077         wchar_t                 name[MAXPATHLEN];
3078         register wchar_t        *p;
3079         timestruc_t             sccs_time;
3080         register Property       line;
3081         int                     sym_link_depth = 0;
3082 
3083         /* For sccs, we need to chase symlinks. */
3084         while (target->stat.is_sym_link) {
3085                 if (sym_link_depth++ > 90) {
3086                         fatal(catgets(catd, 1, 95, "Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."),
3087                               target->string_mb);
3088                 }
3089                 /* Read the value of the link. */
3090                 result = readlink_vroot(target->string_mb,
3091                                         link,
3092                                         sizeof(link),
3093                                         NULL,
3094                                         VROOT_DEFAULT);
3095                 if (result == -1) {
3096                         fatal(catgets(catd, 1, 36, "Can't read symbolic link `%s': %s"),
3097                               target->string_mb, errmsg(errno));
3098                 }
3099                 link[result] = 0;
3100                 /* Use the value to build the proper filename. */
3101                 INIT_STRING_FROM_STACK(string, name);
3102 
3103                 Wstring wcb(target);
3104                 if ((link[0] != slash_char) &&
3105                     ((p = (wchar_t *) wsrchr(wcb.get_string(), slash_char)) != NULL)) {
3106                         append_string(wcb.get_string(), &string, p - wcb.get_string() + 1);
3107                 }
3108                 append_string(link, &string, result);
3109                 /* Replace the old name with the translated name. */
3110                 target = normalize_name(string.buffer.start, string.text.p - string.buffer.start);
3111                 (void) exists(target);
3112                 if (string.free_after_use) {
3113                         retmem(string.buffer.start);
3114                 }
3115         }
3116 
3117         /*
3118          * read_dir() also reads the ?/SCCS dir and saves information
3119          * about which files have SCSC/s. files.
3120          */
3121         if (target->stat.has_sccs == DONT_KNOW_SCCS) {
3122                 read_directory_of_file(target);
3123         }
3124         switch (target->stat.has_sccs) {
3125         case DONT_KNOW_SCCS:
3126                 /* We dont know by now there is no SCCS/s.* */
3127                 target->stat.has_sccs = NO_SCCS;
3128         case NO_SCCS:
3129                 /*
3130                  * If there is no SCCS/s.* but the plain file exists,
3131                  * we say things are OK.
3132                  */
3133                 if (target->stat.time > file_doesnt_exist) {
3134                         return build_ok;
3135                 }
3136                 /* If we cant find the plain file, we give up. */
3137                 return build_dont_know;
3138         case HAS_SCCS:
3139                 /*
3140                  * Pay dirt. We now need to figure out if the plain file
3141                  * is out of date relative to the SCCS/s.* file.
3142                  */
3143                 sccs_time = exists(get_prop(target->prop,
3144                                             sccs_prop)->body.sccs.file);
3145                 break;
3146         }
3147 
3148         if ((!target->has_complained &&
3149             (sccs_time != file_doesnt_exist) &&
3150             (sccs_get_rule != NULL))) {
3151                 /* only checking */
3152                 if (command == NULL) {
3153                         return build_ok;
3154                 }
3155                 /*
3156                  * We provide a command line for the target. The line is a
3157                  * "sccs get" command from default.mk.
3158                  */
3159                 line = maybe_append_prop(target, line_prop);
3160                 *command = line;
3161                 if (sccs_time > target->stat.time) {
3162                         /*
3163                          * And only if the plain file is out of date do we
3164                          * request execution of the command.
3165                          */
3166                         line->body.line.is_out_of_date = true;
3167                         if (debug_level > 0) {
3168                                 (void) printf(catgets(catd, 1, 37, "%*sSccs getting %s because s. file is younger than source file\n"),
3169                                               recursion_level,
3170                                               "",
3171                                               target->string_mb);
3172                         }
3173                 }
3174                 line->body.line.sccs_command = true;
3175                 line->body.line.command_template = sccs_get_rule;
3176                 if(!svr4 && (!allrules_read || posix)) {
3177                    if((target->prop) &&
3178                       (target->prop->body.sccs.file) &&
3179                       (target->prop->body.sccs.file->string_mb)) {
3180                       if((strlen(target->prop->body.sccs.file->string_mb) ==
3181                         strlen(target->string_mb) + 2) && 
3182                         (target->prop->body.sccs.file->string_mb[0] == 's') &&
3183                         (target->prop->body.sccs.file->string_mb[1] == '.')) {
3184 
3185                          line->body.line.command_template = get_posix_rule;
3186                       }
3187                    }
3188                 }
3189                 line->body.line.target = target;
3190                 /*
3191                  * Also make sure the rule is build with $* and $<
3192                  * bound properly.
3193                  */
3194                 line->body.line.star = NULL;
3195                 line->body.line.less = NULL;
3196                 line->body.line.percent = NULL;
3197                 return build_ok;
3198         }
3199         return build_dont_know;
3200 }
3201 
3202 /*
3203  *      read_directory_of_file(file)
3204  *
3205  *      Reads the directory the specified file lives in.
3206  *
3207  *      Parameters:
3208  *              file            The file we need to read dir for
3209  *
3210  *      Global variables used:
3211  *              dot             The Name ".", used as the default dir
3212  */
3213 void
3214 read_directory_of_file(register Name file)
3215 {
3216 
3217         Wstring file_string(file);
3218         wchar_t * wcb = file_string.get_string();
3219         wchar_t usr_include_buf[MAXPATHLEN];
3220         wchar_t usr_include_sys_buf[MAXPATHLEN];
3221 
3222         register Name           directory = dot;
3223         register wchar_t        *p = (wchar_t *) wsrchr(wcb,
3224                                                         (int) slash_char);
3225         register int            length = p - wcb;
3226         static Name             usr_include;
3227         static Name             usr_include_sys;
3228 
3229         if (usr_include == NULL) {
3230                 MBSTOWCS(usr_include_buf, NOCATGETS("/usr/include"));
3231                 usr_include = GETNAME(usr_include_buf, FIND_LENGTH);
3232                 MBSTOWCS(usr_include_sys_buf, NOCATGETS("/usr/include/sys"));
3233                 usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH);
3234         }
3235 
3236         /*
3237          * If the filename contains a "/" we have to extract the path
3238          * Else the path defaults to ".".
3239          */
3240         if (p != NULL) {
3241                 /*
3242                  * Check some popular directories first to possibly
3243                  * save time. Compare string length first to gain speed.
3244                  */
3245                 if ((usr_include->hash.length == length) &&
3246                     IS_WEQUALN(usr_include_buf,
3247                                wcb,
3248                                length)) {
3249                         directory = usr_include;
3250                 } else if ((usr_include_sys->hash.length == length) &&
3251                            IS_WEQUALN(usr_include_sys_buf,
3252                                       wcb,
3253                                       length)) {
3254                         directory = usr_include_sys;
3255                 } else {
3256                         directory = GETNAME(wcb, length);
3257                 }
3258         }
3259         (void) read_dir(directory,
3260                         (wchar_t *) NULL,
3261                         (Property) NULL,
3262                         (wchar_t *) NULL);
3263 }
3264 
3265 /*
3266  *      add_pattern_conditionals(target)
3267  *
3268  *      Scan the list of conditionals defined for pattern targets and add any
3269  *      that match this target to its list of conditionals.
3270  *
3271  *      Parameters:
3272  *              target          The target we should add conditionals for
3273  *
3274  *      Global variables used:
3275  *              conditionals    The list of pattern conditionals
3276  */
3277 static void
3278 add_pattern_conditionals(register Name target)
3279 {
3280         register Property       conditional;
3281         Property                new_prop;
3282         Property                *previous;
3283         Name_rec                dummy;
3284         wchar_t                 *pattern;
3285         wchar_t                 *percent;
3286         int                     length;
3287 
3288         Wstring wcb(target);
3289         Wstring wcb1;
3290 
3291         for (conditional = get_prop(conditionals->prop, conditional_prop);
3292              conditional != NULL;
3293              conditional = get_prop(conditional->next, conditional_prop)) {
3294                 wcb1.init(conditional->body.conditional.target);
3295                 pattern = wcb1.get_string();
3296                 if (pattern[1] != 0) {
3297                         percent = (wchar_t *) wschr(pattern, (int) percent_char);
3298                         if (!wcb.equaln(pattern, percent-pattern) ||
3299                             !IS_WEQUAL(wcb.get_string(wcb.length()-wslen(percent+1)), percent+1)) {
3300                                 continue;
3301                         }
3302                 }
3303                 for (previous = &target->prop;
3304                      *previous != NULL;
3305                      previous = &(*previous)->next) {
3306                         if (((*previous)->type == conditional_prop) &&
3307                             ((*previous)->body.conditional.sequence >
3308                              conditional->body.conditional.sequence)) {
3309                                 break;
3310                         }
3311                 }
3312                 if (*previous == NULL) {
3313                         new_prop = append_prop(target, conditional_prop);
3314                 } else {
3315                         dummy.prop = NULL;
3316                         new_prop = append_prop(&dummy, conditional_prop);
3317                         new_prop->next = *previous;
3318                         *previous = new_prop;
3319                 }
3320                 target->conditional_cnt++;
3321                 new_prop->body.conditional = conditional->body.conditional;
3322         }
3323 }
3324 
3325 /*
3326  *      set_locals(target, old_locals)
3327  *
3328  *      Sets any conditional macros for the target.
3329  *      Each target carries a possibly empty set of conditional properties.
3330  *
3331  *      Parameters:
3332  *              target          The target to set conditional macros for
3333  *              old_locals      Space to store old values in
3334  *
3335  *      Global variables used:
3336  *              debug_level     Should we trace activity?
3337  *              is_conditional  We need to preserve this value
3338  *              recursion_level Used for tracing
3339  */
3340 void
3341 set_locals(register Name target, register Property old_locals)
3342 {
3343         register Property       conditional;
3344         register int            i;
3345         register Boolean        saved_conditional_macro_used;
3346         Chain                   cond_name;
3347         Chain                   cond_chain;
3348 
3349 #ifdef DISTRIBUTED
3350         if (target->dont_activate_cond_values) {
3351                 return;
3352         }
3353 #endif
3354 
3355         saved_conditional_macro_used = conditional_macro_used;
3356 
3357         /* Scan the list of conditional properties and apply each one */
3358         for (conditional = get_prop(target->prop, conditional_prop), i = 0;
3359              conditional != NULL;
3360              conditional = get_prop(conditional->next, conditional_prop),
3361              i++) {
3362                 /* Save the old value */
3363                 old_locals[i].body.macro =
3364                   maybe_append_prop(conditional->body.conditional.name,
3365                                     macro_prop)->body.macro;
3366                 if (debug_level > 1) {
3367                         (void) printf(catgets(catd, 1, 38, "%*sActivating conditional value: "),
3368                                       recursion_level,
3369                                       "");
3370                 }
3371                 /* Set the conditional value. Macros are expanded when the */
3372                 /* macro is refd as usual */
3373                 if ((conditional->body.conditional.name != virtual_root) ||
3374                     (conditional->body.conditional.value != virtual_root)) {
3375                         (void) SETVAR(conditional->body.conditional.name,
3376                                       conditional->body.conditional.value,
3377                                       (Boolean) conditional->body.conditional.append);
3378                 }
3379                 cond_name = ALLOC(Chain);
3380                 cond_name->name = conditional->body.conditional.name;
3381         }
3382         /* Put this target on the front of the chain of conditional targets */
3383         cond_chain = ALLOC(Chain);
3384         cond_chain->name = target;
3385         cond_chain->next = conditional_targets;
3386         conditional_targets = cond_chain;
3387         conditional_macro_used = saved_conditional_macro_used;
3388 }
3389 
3390 /*
3391  *      reset_locals(target, old_locals, conditional, index)
3392  *
3393  *      Removes any conditional macros for the target.
3394  *
3395  *      Parameters:
3396  *              target          The target we are retoring values for
3397  *              old_locals      The values to restore
3398  *              conditional     The first conditional block for the target
3399  *              index           into the old_locals vector
3400  *      Global variables used:
3401  *              debug_level     Should we trace activities?
3402  *              recursion_level Used for tracing
3403  */
3404 void
3405 reset_locals(register Name target, register Property old_locals, register Property conditional, register int index)
3406 {
3407         register Property       this_conditional;
3408         Chain                   cond_chain;
3409 
3410 #ifdef DISTRIBUTED
3411         if (target->dont_activate_cond_values) {
3412                 return;
3413         }
3414 #endif
3415 
3416         /* Scan the list of conditional properties and restore the old value */
3417         /* to each one Reverse the order relative to when we assigned macros */
3418         this_conditional = get_prop(conditional->next, conditional_prop);
3419         if (this_conditional != NULL) {
3420                 reset_locals(target, old_locals, this_conditional, index+1);
3421         } else {
3422                 /* Remove conditional target from chain */
3423                 if (conditional_targets == NULL ||
3424                     conditional_targets->name != target) {
3425                         warning(catgets(catd, 1, 39, "Internal error: reset target not at head of condtional_targets chain"));
3426                 } else {
3427                         cond_chain = conditional_targets->next;
3428                         retmem_mb((caddr_t) conditional_targets);
3429                         conditional_targets = cond_chain;
3430                 }
3431         }
3432         get_prop(conditional->body.conditional.name->prop,
3433                  macro_prop)->body.macro = old_locals[index].body.macro;
3434         if (conditional->body.conditional.name == virtual_root) {
3435                 (void) SETVAR(virtual_root, getvar(virtual_root), false);
3436         }
3437         if (debug_level > 1) {
3438                 if (old_locals[index].body.macro.value != NULL) {
3439                         (void) printf(catgets(catd, 1, 40, "%*sdeactivating conditional value: %s= %s\n"),
3440                                       recursion_level,
3441                                       "",
3442                                       conditional->body.conditional.name->
3443                                       string_mb,
3444                                       old_locals[index].body.macro.value->
3445                                       string_mb);
3446                 } else {
3447                         (void) printf(catgets(catd, 1, 41, "%*sdeactivating conditional value: %s =\n"),
3448                                       recursion_level,
3449                                       "",
3450                                       conditional->body.conditional.name->
3451                                       string_mb);
3452                 }
3453         }
3454 }
3455 
3456 /*
3457  *      check_auto_dependencies(target, auto_count, automatics)
3458  *
3459  *      Returns true if the target now has a dependency
3460  *      it didn't previously have (saved on automatics).
3461  *
3462  *      Return value:
3463  *                              true if new dependency found
3464  *
3465  *      Parameters:
3466  *              target          Target we check
3467  *              auto_count      Number of old automatic vars
3468  *              automatics      Saved old automatics
3469  *
3470  *      Global variables used:
3471  *              keep_state      Indicates that .KEEP_STATE is on
3472  */
3473 Boolean
3474 check_auto_dependencies(Name target, int auto_count, Name *automatics)
3475 {
3476         Name            *p;
3477         int             n;
3478         Property        line;
3479         Dependency      dependency;
3480 
3481         if (keep_state) {
3482                 if ((line = get_prop(target->prop, line_prop)) == NULL) {
3483                         return false;
3484                 }
3485                 /* Go thru new list of automatic depes */
3486                 for (dependency = line->body.line.dependencies;
3487                      dependency != NULL;
3488                      dependency = dependency->next) {
3489                         /* And make sure that each one existed before we */
3490                         /* built the target */
3491                         if (dependency->automatic && !dependency->stale) {
3492                                 for (n = auto_count, p = automatics;
3493                                      n > 0;
3494                                      n--) {
3495                                         if (*p++ == dependency->name) {
3496                                                 /* If we can find it on the */
3497                                                 /* saved list of autos we */
3498                                                 /* are OK  */
3499                                                 goto not_new;
3500                                         }
3501                                 }
3502                                 /* But if we scan over the old list */
3503                                 /* of auto. without finding it it is */
3504                                 /* new and we must check it */
3505                                 return true;
3506                         }
3507                 not_new:;
3508                 }
3509                 return false;
3510         } else {
3511                 return false;
3512         }
3513 }
3514 
3515 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
3516 void
3517 create_xdrs_ptr(void)
3518 {
3519         static int      xdrs_init = 0;
3520 
3521         if (!xdrs_init) {
3522                 xdrs_init = 1;
3523                 mtool_msgs_fp = fdopen(mtool_msgs_fd, "a");
3524                 xdrstdio_create(&xdrs,
3525                                 mtool_msgs_fp,
3526                                 XDR_ENCODE);
3527         }
3528 }
3529 
3530 XDR *
3531 get_xdrs_ptr(void)
3532 {
3533         return &xdrs;
3534 }
3535 
3536 FILE *
3537 get_mtool_msgs_fp(void)
3538 {
3539         return mtool_msgs_fp;
3540 }
3541 
3542 int
3543 get_job_msg_id(void)
3544 {
3545         return job_msg_id;
3546 }
3547 
3548 // Continuously poll and show the results of remotely executing a job,
3549 // i.e., output the stdout and stderr files.
3550 
3551 static int
3552 pollResults(char *outFn, char *errFn, char *hostNm)
3553 {
3554         int             child;
3555 
3556         child = fork();
3557         switch (child) {
3558         case -1:
3559                 break;
3560         case 0:
3561                 enable_interrupt((void (*) (int))SIG_DFL);
3562 #ifdef linux
3563                 (void) signal(SIGUSR1, Avo_PollResultsAction_Sigusr1Handler);
3564 #else
3565                 (void) sigset(SIGUSR1, Avo_PollResultsAction_Sigusr1Handler);
3566 #endif
3567                 pollResultsAction(outFn, errFn);
3568 
3569                 exit(0);
3570                 break;
3571         default:
3572                 break;
3573         }
3574         return child;
3575 }
3576 
3577 // This is the PollResultsAction SIGUSR1 handler.
3578 
3579 static bool_t pollResultsActionTimeToFinish = FALSE;
3580 
3581 extern "C" void
3582 Avo_PollResultsAction_Sigusr1Handler(int foo)
3583 {
3584         pollResultsActionTimeToFinish = TRUE;
3585 }
3586 
3587 static void
3588 pollResultsAction(char *outFn, char *errFn)
3589 {
3590         int                     fd;
3591         time_t                  file_time = 0;
3592         long                    file_time_nsec = 0;
3593         struct stat             statbuf;
3594         int                     stat_rc;
3595 
3596         // Keep stat'ing until file exists.
3597         while (((stat_rc = stat(outFn, &statbuf)) != 0) &&
3598                (errno == ENOENT) && 
3599                !pollResultsActionTimeToFinish) {
3600                 us_sleep(STAT_RETRY_SLEEP_TIME);
3601         }
3602         // The previous stat() could be failed due to EINTR
3603         // So one more try is needed
3604         if (stat_rc != 0 && stat(outFn, &statbuf) != 0) {
3605                 // stat() failed
3606                 warning(NOCATGETS("Internal error: stat(\"%s\", ...) failed: %s\n"),
3607                         outFn, strerror(errno));
3608                 exit(1);
3609         }
3610 
3611         if ((fd = open(outFn, O_RDONLY)) < 0
3612                 && (errno != EINTR || (fd = open(outFn, O_RDONLY)) < 0)) {
3613                 // open() failed
3614                 warning(NOCATGETS("Internal error: open(\"%s\", O_RDONLY) failed: %s\n"),
3615                         outFn, strerror(errno));
3616                 exit(1);
3617         }
3618 
3619         while (!pollResultsActionTimeToFinish && stat(outFn, &statbuf) == 0) {
3620 #ifdef linux
3621                 if ((statbuf.st_mtime > file_time)
3622                    ) {
3623                         file_time = statbuf.st_mtime;
3624                         rxmGetNextResultsBlock(fd);
3625                 }
3626 #else
3627                 if ((statbuf.st_mtim.tv_sec > file_time) ||
3628                     ((statbuf.st_mtim.tv_sec == file_time) &&
3629                     (statbuf.st_mtim.tv_nsec > file_time_nsec))
3630                    ) {
3631                         file_time = statbuf.st_mtim.tv_sec;
3632                         file_time_nsec = statbuf.st_mtim.tv_nsec;
3633                         rxmGetNextResultsBlock(fd);
3634                 }
3635 #endif
3636                 us_sleep(STAT_RETRY_SLEEP_TIME);
3637         }
3638         // Check for the rest of output
3639         rxmGetNextResultsBlock(fd);
3640 
3641         (void) close(fd);
3642 }
3643 
3644 static void
3645 rxmGetNextResultsBlock(int fd)
3646 {
3647         size_t                  to_read = 8 * 1024;
3648         ssize_t                 bytes_read;
3649         ssize_t                 bytes_written;
3650         char                    results_buf[8 * 1024];
3651         sigset_t                newset;
3652         sigset_t                oldset;
3653 
3654         // Read some more from the output/results file.
3655         // Hopefully the kernel managed to prefetch the stuff.
3656         bytes_read = read(fd, results_buf, to_read);
3657         while (bytes_read > 0) {
3658                 AVO_BLOCK_INTERUPTS;
3659                 bytes_written = write(1, results_buf, bytes_read);
3660                 AVO_UNBLOCK_INTERUPTS;
3661                 if (bytes_written != bytes_read) {
3662                         // write() failed
3663                         warning(NOCATGETS("Internal error: write(1, ...) failed: %s\n"),
3664                                 strerror(errno));
3665                         exit(1);
3666                 }
3667                 bytes_read = read(fd, results_buf, to_read);
3668         }
3669 }
3670 
3671 // Generic, interruptable microsecond resolution sleep member function.
3672 
3673 static int
3674 us_sleep(unsigned int nusecs)
3675 {
3676         struct pollfd dummy;
3677         int timeout;
3678 
3679         if ((timeout = nusecs/1000) <= 0) {
3680                 timeout = 1;
3681         }
3682         return poll(&dummy, 0, timeout);
3683 }
3684 #endif /* TEAMWARE_MAKE_CMN */
3685 
3686 // Recursively delete each of the Chain struct on the chain.
3687 
3688 static void
3689 delete_query_chain(Chain ch)
3690 {
3691         if (ch == NULL) {
3692                 return;
3693         } else {
3694                 delete_query_chain(ch->next);
3695                 retmem_mb((char *) ch);
3696         }
3697 }
3698 
3699 Doname
3700 target_can_be_built(register Name target) {
3701         Doname          result = build_dont_know;
3702         Name            true_target = target;
3703         Property        line;
3704 
3705         if (target == wait_name) {
3706                 return(build_ok);
3707         }
3708         /*
3709          * If the target is a constructed one for a "::" target,
3710          * we need to consider that.
3711          */
3712         if (target->has_target_prop) {
3713                 true_target = get_prop(target->prop,
3714                                        target_prop)->body.target.target;
3715         }
3716 
3717         (void) exists(true_target);
3718 
3719         if (true_target->state == build_running) {
3720                 return(build_running);
3721         }
3722         if (true_target->stat.time != file_doesnt_exist) {
3723                 result = build_ok;
3724         }
3725 
3726         /* get line property for the target */
3727         line = get_prop(true_target->prop, line_prop);
3728 
3729         /* first check for explicit rule */
3730         if (line != NULL && line->body.line.command_template != NULL) {
3731                 result = build_ok;
3732         }
3733         /* try to find pattern rule */
3734         if (result == build_dont_know) {
3735                 result = find_percent_rule(target, NULL, false);
3736         }
3737         
3738         /* try to find double suffix rule */
3739         if (result == build_dont_know) {
3740                 if (target->is_member) {
3741                         Property member = get_prop(target->prop, member_prop);
3742                         if (member != NULL && member->body.member.member != NULL) {
3743                                 result = find_ar_suffix_rule(target, member->body.member.member, NULL, false);
3744                         } else {
3745                                 result = find_double_suffix_rule(target, NULL, false);
3746                         }
3747                 } else {
3748                         result = find_double_suffix_rule(target, NULL, false);
3749                 }
3750         }
3751         
3752         /* try to find suffix rule */
3753         if ((result == build_dont_know) && second_pass) {
3754                 result = find_suffix_rule(target, target, empty_name, NULL, false);
3755         }
3756         
3757         /* check for sccs */
3758         if (result == build_dont_know) {
3759                 result = sccs_get(target, NULL);
3760         }
3761         
3762         /* try to find dyn target */
3763         if (result == build_dont_know) {
3764                 Name dtarg = find_dyntarget(target);
3765                 if (dtarg != NULL) {
3766                         result = target_can_be_built(dtarg);
3767                 }
3768         }
3769         
3770         /* check whether target was mentioned in makefile */
3771         if (result == build_dont_know) {
3772                 if (target->colons != no_colon) {
3773                         result = build_ok;
3774                 }
3775         }
3776 
3777         /* result */
3778         return result;
3779 }