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 2005 Sun Microsystems, Inc. All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #ifdef TEAMWARE_MAKE_CMN
  27 
  28 /*
  29  *      parallel.cc
  30  *
  31  *      Deal with the parallel processing
  32  */
  33 
  34 /*
  35  * Included files
  36  */
  37 #ifdef DISTRIBUTED
  38 #include <avo/strings.h>  /* AVO_STRDUP() */
  39 #include <dm/Avo_DoJobMsg.h>
  40 #include <dm/Avo_MToolJobResultMsg.h>
  41 #endif
  42 #include <errno.h>                /* errno */
  43 #include <fcntl.h>
  44 #include <avo/util.h>             /* avo_get_user(), avo_hostname() */
  45 #include <mk/defs.h>
  46 #include <mksh/dosys.h>           /* redirect_io() */
  47 #include <mksh/macro.h>           /* expand_value() */
  48 #include <mksh/misc.h>            /* getmem() */
  49 #include <sys/signal.h>
  50 #include <sys/stat.h>
  51 #include <sys/types.h>
  52 #include <sys/utsname.h>
  53 #include <sys/wait.h>
  54 #include <unistd.h>
  55 
  56 #ifdef SGE_SUPPORT
  57 #include <dmthread/Avo_PathNames.h>
  58 #endif
  59 
  60 
  61 /*
  62  * Defined macros
  63  */
  64 #define MAXRULES                100
  65 
  66 /*
  67  * This const should be in avo_dms/include/AvoDmakeCommand.h
  68  */
  69 const int local_host_mask = 0x20;
  70 
  71 
  72 /*
  73  * typedefs & structs
  74  */
  75 
  76 
  77 /*
  78  * Static variables
  79  */
  80 #ifdef TEAMWARE_MAKE_CMN
  81 static  Boolean         just_did_subtree = false;
  82 static  char            local_host[MAXNAMELEN] = "";
  83 static  char            user_name[MAXNAMELEN] = "";
  84 #endif
  85 static  int             pmake_max_jobs = 0;
  86 static  pid_t           process_running = -1;
  87 static  Running         *running_tail = &running_list;
  88 static  Name            subtree_conflict;
  89 static  Name            subtree_conflict2;
  90 
  91 
  92 /*
  93  * File table of contents
  94  */
  95 #ifdef DISTRIBUTED
  96 static  void            append_dmake_cmd(Avo_DoJobMsg *dmake_job_msg, char *orig_cmd_line, int cmd_options);
  97 static  void            append_job_result_msg(Avo_MToolJobResultMsg *msg, char *outFn, char *errFn);
  98 static  void            send_job_result_msg(Running rp);
  99 #endif
 100 static  void            delete_running_struct(Running rp);
 101 static  Boolean         dependency_conflict(Name target);
 102 static  Doname          distribute_process(char **commands, Property line);
 103 static  void            doname_subtree(Name target, Boolean do_get, Boolean implicit);
 104 static  void            dump_out_file(char *filename, Boolean err);
 105 static  void            finish_doname(Running rp);
 106 static  void            maybe_reread_make_state(void);
 107 static  void            process_next(void);
 108 static  void            reset_conditionals(int cnt, Name *targets, Property *locals);
 109 static  pid_t           run_rule_commands(char *host, char **commands);
 110 static  Property        *set_conditionals(int cnt, Name *targets);
 111 static  void            store_conditionals(Running rp);
 112 
 113 
 114 /*
 115  *      execute_parallel(line, waitflg)
 116  *
 117  *      DMake 2.x:
 118  *      parallel mode: spawns a parallel process to execute the command group.
 119  *      distributed mode: sends the command group down the pipe to rxm.
 120  *
 121  *      Return value:
 122  *                              The result of the execution
 123  *
 124  *      Parameters:
 125  *              line            The command group to execute
 126  */
 127 Doname
 128 execute_parallel(Property line, Boolean waitflg, Boolean local)
 129 {
 130         int                     argcnt;
 131         int                     cmd_options = 0;
 132         char                    *commands[MAXRULES + 5];
 133         char                    *cp;
 134 #ifdef DISTRIBUTED
 135         Avo_DoJobMsg            *dmake_job_msg = NULL;
 136 #endif
 137         Name                    dmake_name;
 138         Name                    dmake_value;
 139         int                     ignore;
 140         Name                    make_machines_name;
 141         char                    **p;
 142         Property                prop;
 143         Doname                  result = build_ok;
 144         Cmd_line                rule;
 145         Boolean                 silent_flag;
 146         Name                    target = line->body.line.target;
 147         Boolean                 wrote_state_file = false;
 148 
 149         if ((pmake_max_jobs == 0) &&
 150             (dmake_mode_type == parallel_mode)) {
 151                 if (user_name[0] == '\0') {
 152                         avo_get_user(user_name, NULL);
 153                 }
 154                 if (local_host[0] == '\0') {
 155                         strcpy(local_host, avo_hostname());
 156                 }
 157                 MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_MAX_JOBS"));
 158                 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 159                 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 160                     ((dmake_value = prop->body.macro.value) != NULL)) {
 161                         pmake_max_jobs = atoi(dmake_value->string_mb);
 162                         if (pmake_max_jobs <= 0) {
 163                                 warning(catgets(catd, 1, 308, "DMAKE_MAX_JOBS cannot be less than or equal to zero."));
 164                                 warning(catgets(catd, 1, 309, "setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
 165                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 166                         }
 167                 } else {
 168                         /*
 169                          * For backwards compatibility w/ PMake 1.x, when
 170                          * DMake 2.x is being run in parallel mode, DMake
 171                          * should parse the PMake startup file
 172                          * $(HOME)/.make.machines to get the pmake_max_jobs.
 173                          */
 174                         MBSTOWCS(wcs_buffer, NOCATGETS("PMAKE_MACHINESFILE"));
 175                         dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 176                         if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 177                             ((dmake_value = prop->body.macro.value) != NULL)) {
 178                                 make_machines_name = dmake_value;
 179                         } else {
 180                                 make_machines_name = NULL;
 181                         }
 182                         if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
 183                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 184                         }
 185                 }
 186 #ifdef DISTRIBUTED
 187                 if (send_mtool_msgs) {
 188                         send_rsrc_info_msg(pmake_max_jobs, local_host, user_name);
 189                 }
 190 #endif
 191         }
 192 
 193         if ((dmake_mode_type == serial_mode) ||
 194             ((dmake_mode_type == parallel_mode) && (waitflg))) {
 195                 return (execute_serial(line));
 196         }
 197 
 198 #ifdef DISTRIBUTED
 199         if (dmake_mode_type == distributed_mode) {
 200                 if(local) {
 201 //                      return (execute_serial(line));
 202                         waitflg = true;
 203                 }
 204                 dmake_job_msg = new Avo_DoJobMsg();
 205                 dmake_job_msg->setJobId(++job_msg_id);
 206                 dmake_job_msg->setTarget(target->string_mb);
 207                 dmake_job_msg->setImmediateOutput(0);
 208                 called_make = false;
 209         } else
 210 #endif
 211         {
 212                 p = commands;
 213         }
 214 
 215         argcnt = 0;
 216         for (rule = line->body.line.command_used;
 217              rule != NULL;
 218              rule = rule->next) {
 219                 if (posix && (touch || quest) && !rule->always_exec) {
 220                         continue;
 221                 }
 222                 if (vpath_defined) {
 223                         rule->command_line =
 224                           vpath_translation(rule->command_line);
 225                 }
 226                 if (dmake_mode_type == distributed_mode) {
 227                         cmd_options = 0;
 228                         if(local) {
 229                                 cmd_options |= local_host_mask;
 230                         }
 231                 } else {
 232                         silent_flag = false;
 233                         ignore = 0;
 234                 }
 235                 if (rule->command_line->hash.length > 0) {
 236                         if (++argcnt == MAXRULES) {
 237                                 if (dmake_mode_type == distributed_mode) {
 238                                         /* XXX - tell rxm to execute on local host. */
 239                                         /* I WAS HERE!!! */
 240                                 } else {
 241                                         /* Too many rules, run serially instead. */
 242                                         return build_serial;
 243                                 }
 244                         }
 245 #ifdef DISTRIBUTED
 246                         if (dmake_mode_type == distributed_mode) {
 247                                 /*
 248                                  * XXX - set assign_mask to tell rxm
 249                                  * to do the following.
 250                                  */
 251 /* From execute_serial():
 252                                 if (rule->assign) {
 253                                         result = build_ok;
 254                                         do_assign(rule->command_line, target);
 255  */
 256                                 if (0) {
 257                                 } else if (report_dependencies_level == 0) {
 258                                         if (rule->ignore_error) {
 259                                                 cmd_options |= ignore_mask;
 260                                         }
 261                                         if (rule->silent) {
 262                                                 cmd_options |= silent_mask;
 263                                         }
 264                                         if (rule->command_line->meta) {
 265                                                 cmd_options |= meta_mask;
 266                                         }
 267                                         if (rule->make_refd) {
 268                                                 cmd_options |= make_refd_mask;
 269                                         }
 270                                         if (do_not_exec_rule) {
 271                                                 cmd_options |= do_not_exec_mask;
 272                                         }
 273                                         append_dmake_cmd(dmake_job_msg,
 274                                                          rule->command_line->string_mb,
 275                                                          cmd_options);
 276                                         /* Copying dosys()... */
 277                                         if (rule->make_refd) {
 278                                                 if (waitflg) {
 279                                                         dmake_job_msg->setImmediateOutput(1);
 280                                                 }
 281                                                 called_make = true;
 282                                                 if (command_changed &&
 283                                                     !wrote_state_file) {
 284                                                         write_state_file(0, false);
 285                                                         wrote_state_file = true;
 286                                                 }
 287                                         }
 288                                 }
 289                         } else
 290 #endif
 291                         {
 292                                 if (rule->silent && !silent) {
 293                                         silent_flag = true;
 294                                 }
 295                                 if (rule->ignore_error) {
 296                                         ignore++;
 297                                 }
 298                                 /* XXX - need to add support for + prefix */
 299                                 if (silent_flag || ignore) {
 300                                         *p = getmem((silent_flag ? 1 : 0) +
 301                                                     ignore +
 302                                                     (strlen(rule->
 303                                                            command_line->
 304                                                            string_mb)) +
 305                                                     1);
 306                                         cp = *p++;
 307                                         if (silent_flag) {
 308                                                 *cp++ = (int) at_char;
 309                                         }
 310                                         if (ignore) {
 311                                                 *cp++ = (int) hyphen_char;
 312                                         }
 313                                         (void) strcpy(cp, rule->command_line->string_mb);
 314                                 } else {
 315                                         *p++ = rule->command_line->string_mb;
 316                                 }
 317                         }
 318                 }
 319         }
 320         if ((argcnt == 0) ||
 321             (report_dependencies_level > 0)) {
 322 #ifdef DISTRIBUTED
 323                 if (dmake_job_msg) {
 324                         delete dmake_job_msg;
 325                 }
 326 #endif
 327                 return build_ok;
 328         }
 329 #ifdef DISTRIBUTED
 330         if (dmake_mode_type == distributed_mode) {
 331                 // Send  a DoJob message to the rxm process.
 332                 distribute_rxm(dmake_job_msg);
 333 
 334                 // Wait for an acknowledgement.
 335                 Avo_AcknowledgeMsg *ackMsg = getAcknowledgeMsg();
 336                 if (ackMsg) {
 337                         delete ackMsg;
 338                 }
 339 
 340                 if (waitflg) {
 341                         // Wait for, and process a job result.
 342                         result = await_dist(waitflg);
 343                         if (called_make) {
 344                                 maybe_reread_make_state();
 345                         }
 346                         check_state(temp_file_name);
 347                         if (result == build_failed) {
 348                                 if (!continue_after_error) {
 349 
 350 #ifdef PRINT_EXIT_STATUS
 351                                         warning(NOCATGETS("I'm in execute_parallel. await_dist() returned build_failed"));
 352 #endif
 353 
 354                                         fatal(catgets(catd, 1, 252, "Command failed for target `%s'"),
 355                                               target->string_mb);
 356                                 }
 357                                 /*
 358                                  * Make sure a failing command is not
 359                                  * saved in .make.state.
 360                                  */
 361                                 line->body.line.command_used = NULL;
 362                         }
 363                         if (temp_file_name != NULL) {
 364                                 free_name(temp_file_name);
 365                         }
 366                         temp_file_name = NULL;
 367                         Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
 368                         if(spro != NULL) {
 369                                 Name val = spro->body.macro.value;
 370                                 if(val != NULL) {
 371                                         free_name(val);
 372                                         spro->body.macro.value = NULL;
 373                                 }
 374                         }
 375                         spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
 376                         if(spro) {
 377                                 char *val = spro->body.env_mem.value;
 378                                 if(val != NULL) {
 379                                         retmem_mb(val);
 380                                         spro->body.env_mem.value = NULL;
 381                                 }
 382                         }
 383                         return result;
 384                 } else {
 385                         parallel_process_cnt++;
 386                         return build_running;
 387                 }
 388         } else
 389 #endif
 390         {
 391                 *p = NULL;
 392 
 393                 Doname res = distribute_process(commands, line);
 394                 if (res == build_running) {
 395                         parallel_process_cnt++;
 396                 }
 397 
 398                 /*
 399                  * Return only those memory that were specially allocated
 400                  * for part of commands.
 401                  */
 402                 for (int i = 0; commands[i] != NULL; i++) {
 403                         if ((commands[i][0] == (int) at_char) ||
 404                             (commands[i][0] == (int) hyphen_char)) {
 405                                 retmem_mb(commands[i]);
 406                         }
 407                 }
 408                 return res;
 409         }
 410 }
 411 
 412 #ifdef DISTRIBUTED
 413 /*
 414  *      append_dmake_cmd()
 415  *
 416  *      Replaces all escaped newline's (\<cr>)
 417  *        in the original command line with space's,
 418  *        then append the new command line to the DoJobMsg object.
 419  */
 420 static void
 421 append_dmake_cmd(Avo_DoJobMsg *dmake_job_msg,
 422                  char *orig_cmd_line,
 423                  int cmd_options)
 424 {
 425 /*
 426         Avo_DmakeCommand        *tmp_dmake_command;
 427 
 428         tmp_dmake_command = new Avo_DmakeCommand(orig_cmd_line, cmd_options);
 429         dmake_job_msg->appendCmd(tmp_dmake_command);
 430         delete tmp_dmake_command;
 431  */
 432         dmake_job_msg->appendCmd(new Avo_DmakeCommand(orig_cmd_line, cmd_options));
 433 }
 434 #endif
 435 
 436 #ifdef TEAMWARE_MAKE_CMN
 437 #define MAXJOBS_ADJUST_RFE4694000
 438 
 439 #ifdef MAXJOBS_ADJUST_RFE4694000
 440 
 441 #include <unistd.h>       /* sysconf(_SC_NPROCESSORS_ONLN) */
 442 #include <sys/ipc.h>              /* ftok() */
 443 #include <sys/shm.h>              /* shmget(), shmat(), shmdt(), shmctl() */
 444 #include <semaphore.h>            /* sem_init(), sem_trywait(), sem_post(), sem_destroy() */
 445 #if defined(linux)
 446 #define LOADAVG_1MIN    0
 447 #else
 448 #include <sys/loadavg.h>  /* getloadavg() */
 449 #endif /* linux */
 450 
 451 /*
 452  *      adjust_pmake_max_jobs (int pmake_max_jobs)
 453  *
 454  *      Parameters:
 455  *              pmake_max_jobs  - max jobs limit set by user
 456  *
 457  *      External functions used:
 458  *              sysconf()
 459  *              getloadavg()
 460  */
 461 static int
 462 adjust_pmake_max_jobs (int pmake_max_jobs)
 463 {
 464         static int      ncpu = 0;
 465         double          loadavg[3];
 466         int             adjustment;
 467         int             adjusted_max_jobs;
 468 
 469         if (ncpu <= 0) {
 470                 if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) {
 471                         ncpu = 1;
 472                 }
 473         }
 474         if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs);
 475         adjustment = ((int)loadavg[LOADAVG_1MIN]);
 476         if (adjustment < 2) return(pmake_max_jobs);
 477         if (ncpu > 1) {
 478                 adjustment = adjustment / ncpu;
 479         }
 480         adjusted_max_jobs = pmake_max_jobs - adjustment;
 481         if (adjusted_max_jobs < 1) adjusted_max_jobs = 1;
 482         return(adjusted_max_jobs);
 483 }
 484 
 485 /*
 486  *  M2 adjust mode data and functions
 487  *
 488  *  m2_init()           - initializes M2 shared semaphore
 489  *  m2_acquire_job()    - decrements M2 semaphore counter
 490  *  m2_release_job()    - increments M2 semaphore counter
 491  *  m2_fini()           - destroys M2 semaphore and shared memory*
 492  *
 493  *  Environment variables:
 494  *      __DMAKE_M2_FILE__
 495  *
 496  *  External functions:
 497  *      ftok(), shmget(), shmat(), shmdt(), shmctl()
 498  *      sem_init(), sem_trywait(), sem_post(), sem_destroy()
 499  *      creat(), close(), unlink()
 500  *      getenv(), putenv()
 501  *
 502  *  Static variables:
 503  *      m2_file         - tmp file name to create ipc key for shared memory
 504  *      m2_shm_id       - shared memory id
 505  *      m2_shm_sem      - shared memory semaphore
 506  */
 507 
 508 static char     m2_file[MAXPATHLEN];
 509 static int      m2_shm_id = -1;
 510 static sem_t*   m2_shm_sem = 0;
 511 
 512 static int
 513 m2_init() {
 514         char    *var;
 515         key_t   key;
 516 
 517         if ((var = getenv(NOCATGETS("__DMAKE_M2_FILE__"))) == 0) {
 518                 /* compose tmp file name */
 519                 sprintf(m2_file, NOCATGETS("%s/dmake.m2.%d.XXXXXX"), tmpdir, getpid());
 520 
 521                 /* create tmp file */
 522                 int fd = mkstemp(m2_file);
 523                 if (fd < 0) {
 524                         return -1;
 525                 } else {
 526                         close(fd);
 527                 }
 528         } else {
 529                 /* using existing semaphore */
 530                 strcpy(m2_file, var);
 531         }
 532 
 533         /* combine IPC key */
 534         if ((key = ftok(m2_file, 38)) == (key_t) -1) {
 535                 return -1;
 536         }
 537 
 538         /* create shared memory */
 539         if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {
 540                 return -1;
 541         }
 542 
 543         /* attach shared memory */
 544         if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
 545                 return -1;
 546         }
 547 
 548         /* root process */
 549         if (var == 0) {
 550                 /* initialize semaphore */
 551                 if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
 552                         return -1;
 553                 }
 554 
 555                 /* alloc memory for env variable */
 556                 if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
 557                         return -1;
 558                 }
 559 
 560                 /* put key to env */
 561                 sprintf(var, NOCATGETS("__DMAKE_M2_FILE__=%s"), m2_file);
 562                 if (putenv(var)) {
 563                         return -1;
 564                 }
 565         }
 566         return 0;
 567 }
 568 
 569 static void
 570 m2_fini() {
 571         if (m2_shm_id >= 0) {
 572                 struct shmid_ds stat;
 573 
 574                 /* determine the number of attached processes */
 575                 if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
 576                         if (stat.shm_nattch <= 1) {
 577                                 /* destroy semaphore */
 578                                 if (m2_shm_sem != 0) {
 579                                         (void) sem_destroy(m2_shm_sem);
 580                                 }
 581 
 582                                 /* destroy shared memory */
 583                                 (void) shmctl(m2_shm_id, IPC_RMID, &stat);
 584 
 585                                 /* remove tmp file created for the key */
 586                                 (void) unlink(m2_file);
 587                         } else {
 588                                 /* detach shared memory */
 589                                 if (m2_shm_sem != 0) {
 590                                         (void) shmdt((char*) m2_shm_sem);
 591                                 }
 592                         }
 593                 }
 594 
 595                 m2_shm_id = -1;
 596                 m2_shm_sem = 0;
 597         }
 598 }
 599 
 600 static int
 601 m2_acquire_job() {
 602         if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
 603                 if (sem_trywait(m2_shm_sem) == 0) {
 604                         return 1;
 605                 }
 606                 if (errno == EAGAIN) {
 607                         return 0;
 608                 }
 609         }
 610         return -1;
 611 }
 612 
 613 static int
 614 m2_release_job() {
 615         if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
 616                 if (sem_post(m2_shm_sem) == 0) {
 617                         return 0;
 618                 }
 619         }
 620         return -1;
 621 }
 622 
 623 /*
 624  *  job adjust mode
 625  *
 626  *  Possible values:
 627  *    ADJUST_M1         - adjustment by system load (default)
 628  *    ADJUST_M2         - fixed limit of jobs for the group of nested dmakes
 629  *    ADJUST_NONE       - no adjustment - fixed limit of jobs for the current dmake
 630  */
 631 static enum {
 632         ADJUST_UNKNOWN,
 633         ADJUST_M1,
 634         ADJUST_M2,
 635         ADJUST_NONE
 636 } job_adjust_mode = ADJUST_UNKNOWN;
 637 
 638 /*
 639  *  void job_adjust_fini()
 640  *
 641  *  Description:
 642  *      Cleans up job adjust data.
 643  *
 644  *  Static variables:
 645  *      job_adjust_mode Current job adjust mode
 646  */
 647 void
 648 job_adjust_fini() {
 649         if (job_adjust_mode == ADJUST_M2) {
 650                 m2_fini();
 651         }
 652 }
 653 
 654 /*
 655  *  void job_adjust_error()
 656  *
 657  *  Description:
 658  *      Prints warning message, cleans up job adjust data, and disables job adjustment
 659  *
 660  *  Environment:
 661  *      DMAKE_ADJUST_MAX_JOBS
 662  *
 663  *  External functions:
 664  *      putenv()
 665  *
 666  *  Static variables:
 667  *      job_adjust_mode Current job adjust mode
 668  */
 669 static void
 670 job_adjust_error() {
 671         if (job_adjust_mode != ADJUST_NONE) {
 672                 /* cleanup internals */
 673                 job_adjust_fini();
 674 
 675                 /* warning message for the user */
 676                 warning(catgets(catd, 1, 339, "Encountered max jobs auto adjustment error - disabling auto adjustment."));
 677 
 678                 /* switch off job adjustment for the children */
 679                 putenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS=NO"));
 680 
 681                 /* and for this dmake */
 682                 job_adjust_mode = ADJUST_NONE;
 683         }
 684 }
 685 
 686 /*
 687  *  void job_adjust_init()
 688  *
 689  *  Description:
 690  *      Parses DMAKE_ADJUST_MAX_JOBS env variable
 691  *      and performs appropriate initializations.
 692  *
 693  *  Environment:
 694  *      DMAKE_ADJUST_MAX_JOBS
 695  *        DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment
 696  *        DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode
 697  *        other                         - M1 adjust mode
 698  *
 699  *  External functions:
 700  *      getenv()
 701  *
 702  *  Static variables:
 703  *      job_adjust_mode Current job adjust mode
 704  */
 705 static void
 706 job_adjust_init() {
 707         if (job_adjust_mode == ADJUST_UNKNOWN) {
 708                 /* default mode */
 709                 job_adjust_mode = ADJUST_M1;
 710 
 711                 /* determine adjust mode */
 712                 if (char *var = getenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS"))) {
 713                         if (strcasecmp(var, NOCATGETS("NO")) == 0) {
 714                                 job_adjust_mode = ADJUST_NONE;
 715                         } else if (strcasecmp(var, NOCATGETS("M2")) == 0) {
 716                                 job_adjust_mode = ADJUST_M2;
 717                         }
 718                 }
 719 
 720                 /* M2 specific initialization */
 721                 if (job_adjust_mode == ADJUST_M2) {
 722                         if (m2_init()) {
 723                                 job_adjust_error();
 724                         }
 725                 }
 726         }
 727 }
 728 
 729 #endif /* MAXJOBS_ADJUST_RFE4694000 */
 730 #endif /* TEAMWARE_MAKE_CMN */
 731 
 732 /*
 733  *      distribute_process(char **commands, Property line)
 734  *
 735  *      Parameters:
 736  *              commands        argv vector of commands to execute
 737  *
 738  *      Return value:
 739  *                              The result of the execution
 740  *
 741  *      Static variables used:
 742  *              process_running Set to the pid of the process set running
 743  * #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
 744  *              job_adjust_mode Current job adjust mode
 745  * #endif
 746  */
 747 static Doname
 748 distribute_process(char **commands, Property line)
 749 {
 750         static unsigned file_number = 0;
 751         wchar_t         string[MAXPATHLEN];
 752         char            mbstring[MAXPATHLEN];
 753         int             filed;
 754         int             res;
 755         int             tmp_index;
 756         char            *tmp_index_str_ptr;
 757 
 758 #if !defined (TEAMWARE_MAKE_CMN) || !defined (MAXJOBS_ADJUST_RFE4694000)
 759         while (parallel_process_cnt >= pmake_max_jobs) {
 760                 await_parallel(false);
 761                 finish_children(true);
 762         }
 763 #else /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
 764         /* initialize adjust mode, if not initialized */
 765         if (job_adjust_mode == ADJUST_UNKNOWN) {
 766                 job_adjust_init();
 767         }
 768 
 769         /* actions depend on adjust mode */
 770         switch (job_adjust_mode) {
 771         case ADJUST_M1:
 772                 while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) {
 773                         await_parallel(false);
 774                         finish_children(true);
 775                 }
 776                 break;
 777         case ADJUST_M2:
 778                 if ((res = m2_acquire_job()) == 0) {
 779                         if (parallel_process_cnt > 0) {
 780                                 await_parallel(false);
 781                                 finish_children(true);
 782 
 783                                 if ((res = m2_acquire_job()) == 0) {
 784                                         return build_serial;
 785                                 }
 786                         } else {
 787                                 return build_serial;
 788                         }
 789                 }
 790                 if (res < 0) {
 791                         /* job adjustment error */
 792                         job_adjust_error();
 793 
 794                         /* no adjustment */
 795                         while (parallel_process_cnt >= pmake_max_jobs) {
 796                                 await_parallel(false);
 797                                 finish_children(true);
 798                         }
 799                 }
 800                 break;
 801         default:
 802                 while (parallel_process_cnt >= pmake_max_jobs) {
 803                         await_parallel(false);
 804                         finish_children(true);
 805                 }
 806         }
 807 #endif /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
 808 #ifdef DISTRIBUTED
 809         if (send_mtool_msgs) {
 810                 send_job_start_msg(line);
 811         }
 812 #endif
 813 #ifdef DISTRIBUTED
 814         setvar_envvar((Avo_DoJobMsg *)NULL);
 815 #else
 816         setvar_envvar();
 817 #endif
 818         /*
 819          * Tell the user what DMake is doing.
 820          */
 821         if (!silent && output_mode != txt2_mode) {
 822                 /*
 823                  * Print local_host --> x job(s).
 824                  */
 825                 (void) fprintf(stdout,
 826                                catgets(catd, 1, 325, "%s --> %d %s\n"),
 827                                local_host,
 828                                parallel_process_cnt + 1,
 829                                (parallel_process_cnt == 0) ? catgets(catd, 1, 124, "job") : catgets(catd, 1, 125, "jobs"));
 830 
 831                 /* Print command line(s). */
 832                 tmp_index = 0;
 833                 while (commands[tmp_index] != NULL) {
 834                     /* No @ char. */
 835                     /* XXX - need to add [2] when + prefix is added */
 836                     if ((commands[tmp_index][0] != (int) at_char) &&
 837                         (commands[tmp_index][1] != (int) at_char)) {
 838                         tmp_index_str_ptr = commands[tmp_index];
 839                         if (*tmp_index_str_ptr == (int) hyphen_char) {
 840                                 tmp_index_str_ptr++;
 841                         }
 842                         (void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
 843                     }
 844                     tmp_index++;
 845                 }
 846                 (void) fflush(stdout);
 847         }
 848 
 849         (void) sprintf(mbstring,
 850                         NOCATGETS("%s/dmake.stdout.%d.%d.XXXXXX"),
 851                         tmpdir,
 852                         getpid(),
 853                         file_number++);
 854 
 855         mktemp(mbstring);
 856 
 857         stdout_file = strdup(mbstring);
 858         stderr_file = NULL;
 859 #if defined (TEAMWARE_MAKE_CMN) && defined(REDIRECT_ERR)
 860         if (!out_err_same) {
 861                 (void) sprintf(mbstring,
 862                                 NOCATGETS("%s/dmake.stderr.%d.%d.XXXXXX"),
 863                                 tmpdir,
 864                                 getpid(),
 865                                 file_number++);
 866 
 867                 mktemp(mbstring);
 868 
 869                 stderr_file = strdup(mbstring);
 870         }
 871 #endif
 872 
 873 #ifdef SGE_SUPPORT
 874         if (grid) {
 875                 static char *dir4gridscripts = NULL;
 876                 static char *hostName = NULL;
 877                 if (dir4gridscripts == NULL) {
 878                         Name            dmakeOdir_name, dmakeOdir_value;
 879                         Property        prop;
 880                         MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_ODIR"));
 881                         dmakeOdir_name = GETNAME(wcs_buffer, FIND_LENGTH);
 882                         if (((prop = get_prop(dmakeOdir_name->prop, macro_prop)) != NULL) &&
 883                             ((dmakeOdir_value = prop->body.macro.value) != NULL)) {
 884                                 dir4gridscripts = dmakeOdir_value->string_mb;
 885                         }
 886                         dir4gridscripts = Avo_PathNames::pathname_output_directory(dir4gridscripts);
 887                         hostName = Avo_PathNames::pathname_local_host();
 888                 }
 889                 (void) sprintf(script_file,
 890                                 NOCATGETS("%s/dmake.script.%s.%d.%d.XXXXXX"),
 891                                 dir4gridscripts,
 892                                 hostName,
 893                                 getpid(),
 894                                 file_number++);
 895         }
 896 #endif /* SGE_SUPPORT */
 897         process_running = run_rule_commands(local_host, commands);
 898 
 899         return build_running;
 900 }
 901 
 902 /*
 903  *      doname_parallel(target, do_get, implicit)
 904  *
 905  *      Processes the given target and finishes up any parallel
 906  *      processes left running.
 907  *
 908  *      Return value:
 909  *                              Result of target build
 910  *
 911  *      Parameters:
 912  *              target          Target to build
 913  *              do_get          True if sccs get to be done
 914  *              implicit        True if this is an implicit target
 915  */
 916 Doname
 917 doname_parallel(Name target, Boolean do_get, Boolean implicit)
 918 {
 919         Doname          result;
 920 
 921         result = doname_check(target, do_get, implicit, false);
 922         if (result == build_ok || result == build_failed) {
 923                 return result;
 924         }
 925         finish_running();
 926         return (Doname) target->state;
 927 }
 928 
 929 /*
 930  *      doname_subtree(target, do_get, implicit)
 931  *
 932  *      Completely computes an object and its dependents for a
 933  *      serial subtree build.
 934  *
 935  *      Parameters:
 936  *              target          Target to build
 937  *              do_get          True if sccs get to be done
 938  *              implicit        True if this is an implicit target
 939  *
 940  *      Static variables used:
 941  *              running_tail    Tail of the list of running processes
 942  *
 943  *      Global variables used:
 944  *              running_list    The list of running processes
 945  */
 946 static void
 947 doname_subtree(Name target, Boolean do_get, Boolean implicit)
 948 {
 949         Running         save_running_list;
 950         Running         *save_running_tail;
 951 
 952         save_running_list = running_list;
 953         save_running_tail = running_tail;
 954         running_list = NULL;
 955         running_tail = &running_list;
 956         target->state = build_subtree;
 957         target->checking_subtree = true;
 958         while(doname_check(target, do_get, implicit, false) == build_running) {
 959                 target->checking_subtree = false;
 960                 finish_running();
 961                 target->state = build_subtree;
 962         }
 963         target->checking_subtree = false;
 964         running_list = save_running_list;
 965         running_tail = save_running_tail;
 966 }
 967 
 968 /*
 969  *      finish_running()
 970  *
 971  *      Keeps processing until the running_list is emptied out.
 972  *
 973  *      Parameters:
 974  *
 975  *      Global variables used:
 976  *              running_list    The list of running processes
 977  */
 978 void
 979 finish_running(void)
 980 {
 981         while (running_list != NULL) {
 982 #ifdef DISTRIBUTED
 983                 if (dmake_mode_type == distributed_mode) {
 984                         if ((just_did_subtree) ||
 985                             (parallel_process_cnt == 0)) {
 986                                 just_did_subtree = false;
 987                         } else {
 988                                 (void) await_dist(false);
 989                                 finish_children(true);
 990                         }
 991                 } else
 992 #endif
 993                 {
 994                         await_parallel(false);
 995                         finish_children(true);
 996                 }
 997                 if (running_list != NULL) {
 998                         process_next();
 999                 }
1000         }
1001 }
1002 
1003 /*
1004  *      process_next()
1005  *
1006  *      Searches the running list for any targets which can start processing.
1007  *      This can be a pending target, a serial target, or a subtree target.
1008  *
1009  *      Parameters:
1010  *
1011  *      Static variables used:
1012  *              running_tail            The end of the list of running procs
1013  *              subtree_conflict        A target which conflicts with a subtree
1014  *              subtree_conflict2       The other target which conflicts
1015  *
1016  *      Global variables used:
1017  *              commands_done           True if commands executed
1018  *              debug_level             Controls debug output
1019  *              parallel_process_cnt    Number of parallel process running
1020  *              recursion_level         Indentation for debug output
1021  *              running_list            List of running processes
1022  */
1023 static void
1024 process_next(void)
1025 {
1026         Running         rp;
1027         Running         *rp_prev;
1028         Property        line;
1029         Chain           target_group;
1030         Dependency      dep;
1031         Boolean         quiescent = true;
1032         Running         *subtree_target;
1033         Boolean         saved_commands_done;
1034         Property        *conditionals;
1035 
1036         subtree_target = NULL;
1037         subtree_conflict = NULL;
1038         subtree_conflict2 = NULL;
1039         /*
1040          * If nothing currently running, build a serial target, if any.
1041          */
1042 start_loop_1:
1043         for (rp_prev = &running_list, rp = running_list;
1044              rp != NULL && parallel_process_cnt == 0;
1045              rp = rp->next) {
1046                 if (rp->state == build_serial) {
1047                         *rp_prev = rp->next;
1048                         if (rp->next == NULL) {
1049                                 running_tail = rp_prev;
1050                         }
1051                         recursion_level = rp->recursion_level;
1052                         rp->target->state = build_pending;
1053                         (void) doname_check(rp->target,
1054                                             rp->do_get,
1055                                             rp->implicit,
1056                                             false);
1057                         quiescent = false;
1058                         delete_running_struct(rp);
1059                         goto start_loop_1;
1060                 } else {
1061                         rp_prev = &rp->next;
1062                 }
1063         }
1064         /*
1065          * Find a target to build.  The target must be pending, have all
1066          * its dependencies built, and not be in a target group with a target
1067          * currently building.
1068          */
1069 start_loop_2:
1070         for (rp_prev = &running_list, rp = running_list;
1071              rp != NULL;
1072              rp = rp->next) {
1073                 if (!(rp->state == build_pending ||
1074                       rp->state == build_subtree)) {
1075                         quiescent = false;
1076                         rp_prev = &rp->next;
1077                 } else if (rp->state == build_pending) {
1078                         line = get_prop(rp->target->prop, line_prop);
1079                         for (dep = line->body.line.dependencies;
1080                              dep != NULL;
1081                              dep = dep->next) {
1082                                 if (dep->name->state == build_running ||
1083                                     dep->name->state == build_pending ||
1084                                     dep->name->state == build_serial) {
1085                                         break;
1086                                 }
1087                         }
1088                         if (dep == NULL) {
1089                                 for (target_group = line->body.line.target_group;
1090                                      target_group != NULL;
1091                                      target_group = target_group->next) {
1092                                         if (is_running(target_group->name)) {
1093                                                 break;
1094                                         }
1095                                 }
1096                                 if (target_group == NULL) {
1097                                         *rp_prev = rp->next;
1098                                         if (rp->next == NULL) {
1099                                                 running_tail = rp_prev;
1100                                         }
1101                                         recursion_level = rp->recursion_level;
1102                                         rp->target->state = rp->redo ?
1103                                           build_dont_know : build_pending;
1104                                         saved_commands_done = commands_done;
1105                                         conditionals =
1106                                                 set_conditionals
1107                                                     (rp->conditional_cnt,
1108                                                      rp->conditional_targets);
1109                                         rp->target->dont_activate_cond_values = true;
1110                                         if ((doname_check(rp->target,
1111                                                           rp->do_get,
1112                                                           rp->implicit,
1113                                                           rp->target->has_target_prop ? true : false) !=
1114                                              build_running) &&
1115                                             !commands_done) {
1116                                                 commands_done =
1117                                                   saved_commands_done;
1118                                         }
1119                                         rp->target->dont_activate_cond_values = false;
1120                                         reset_conditionals
1121                                                 (rp->conditional_cnt,
1122                                                  rp->conditional_targets,
1123                                                  conditionals);
1124                                         quiescent = false;
1125                                         delete_running_struct(rp);
1126                                         goto start_loop_2;
1127                                 } else {
1128                                         rp_prev = &rp->next;
1129                                 }
1130                         } else {
1131                                 rp_prev = &rp->next;
1132                         }
1133                 } else {
1134                         rp_prev = &rp->next;
1135                 }
1136         }
1137         /*
1138          * If nothing has been found to build and there exists a subtree
1139          * target with no dependency conflicts, build it.
1140          */
1141         if (quiescent) {
1142 start_loop_3:
1143                 for (rp_prev = &running_list, rp = running_list;
1144                      rp != NULL;
1145                      rp = rp->next) {
1146                         if (rp->state == build_subtree) {
1147                                 if (!dependency_conflict(rp->target)) {
1148                                         *rp_prev = rp->next;
1149                                         if (rp->next == NULL) {
1150                                                 running_tail = rp_prev;
1151                                         }
1152                                         recursion_level = rp->recursion_level;
1153                                         doname_subtree(rp->target,
1154                                                        rp->do_get,
1155                                                        rp->implicit);
1156 #ifdef DISTRIBUTED
1157                                         just_did_subtree = true;
1158 #endif
1159                                         quiescent = false;
1160                                         delete_running_struct(rp);
1161                                         goto start_loop_3;
1162                                 } else {
1163                                         subtree_target = rp_prev;
1164                                         rp_prev = &rp->next;
1165                                 }
1166                         } else {
1167                                 rp_prev = &rp->next;
1168                         }
1169                 }
1170         }
1171         /*
1172          * If still nothing found to build, we either have a deadlock
1173          * or a subtree with a dependency conflict with something waiting
1174          * to build.
1175          */
1176         if (quiescent) {
1177                 if (subtree_target == NULL) {
1178                         fatal(catgets(catd, 1, 126, "Internal error: deadlock detected in process_next"));
1179                 } else {
1180                         rp = *subtree_target;
1181                         if (debug_level > 0) {
1182                                 warning(catgets(catd, 1, 127, "Conditional macro conflict encountered for %s between %s and %s"),
1183                                         subtree_conflict2->string_mb,
1184                                         rp->target->string_mb,
1185                                         subtree_conflict->string_mb);
1186                         }
1187                         *subtree_target = (*subtree_target)->next;
1188                         if (rp->next == NULL) {
1189                                 running_tail = subtree_target;
1190                         }
1191                         recursion_level = rp->recursion_level;
1192                         doname_subtree(rp->target, rp->do_get, rp->implicit);
1193 #ifdef DISTRIBUTED
1194                         just_did_subtree = true;
1195 #endif
1196                         delete_running_struct(rp);
1197                 }
1198         }
1199 }
1200 
1201 /*
1202  *      set_conditionals(cnt, targets)
1203  *
1204  *      Sets the conditional macros for the targets given in the array of
1205  *      targets.  The old macro values are returned in an array of
1206  *      Properties for later resetting.
1207  *
1208  *      Return value:
1209  *                                      Array of conditional macro settings
1210  *
1211  *      Parameters:
1212  *              cnt                     Number of targets
1213  *              targets                 Array of targets
1214  */
1215 static Property *
1216 set_conditionals(int cnt, Name *targets)
1217 {
1218         Property        *locals, *lp;
1219         Name            *tp;
1220 
1221         locals = (Property *) getmem(cnt * sizeof(Property));
1222         for (lp = locals, tp = targets;
1223              cnt > 0;
1224              cnt--, lp++, tp++) {
1225                 *lp = (Property) getmem((*tp)->conditional_cnt *
1226                                         sizeof(struct _Property));
1227                 set_locals(*tp, *lp);
1228         }
1229         return locals;
1230 }
1231 
1232 /*
1233  *      reset_conditionals(cnt, targets, locals)
1234  *
1235  *      Resets the conditional macros as saved in the given array of
1236  *      Properties.  The resets are done in reverse order.  Afterwards the
1237  *      data structures are freed.
1238  *
1239  *      Parameters:
1240  *              cnt                     Number of targets
1241  *              targets                 Array of targets
1242  *              locals                  Array of dependency macro settings
1243  */
1244 static void
1245 reset_conditionals(int cnt, Name *targets, Property *locals)
1246 {
1247         Name            *tp;
1248         Property        *lp;
1249 
1250         for (tp = targets + (cnt - 1), lp = locals + (cnt - 1);
1251              cnt > 0;
1252              cnt--, tp--, lp--) {
1253                 reset_locals(*tp,
1254                              *lp,
1255                              get_prop((*tp)->prop, conditional_prop),
1256                              0);
1257                 retmem_mb((caddr_t) *lp);
1258         }
1259         retmem_mb((caddr_t) locals);
1260 }
1261 
1262 /*
1263  *      dependency_conflict(target)
1264  *
1265  *      Returns true if there is an intersection between
1266  *      the subtree of the target and any dependents of the pending targets.
1267  *
1268  *      Return value:
1269  *                                      True if conflict found
1270  *
1271  *      Parameters:
1272  *              target                  Subtree target to check
1273  *
1274  *      Static variables used:
1275  *              subtree_conflict        Target conflict found
1276  *              subtree_conflict2       Second conflict found
1277  *
1278  *      Global variables used:
1279  *              running_list            List of running processes
1280  *              wait_name               .WAIT, not a real dependency
1281  */
1282 static Boolean
1283 dependency_conflict(Name target)
1284 {
1285         Property        line;
1286         Property        pending_line;
1287         Dependency      dp;
1288         Dependency      pending_dp;
1289         Running         rp;
1290 
1291         /* Return if we are already checking this target */
1292         if (target->checking_subtree) {
1293                 return false;
1294         }
1295         target->checking_subtree = true;
1296         line = get_prop(target->prop, line_prop);
1297         if (line == NULL) {
1298                 target->checking_subtree = false;
1299                 return false;
1300         }
1301         /* Check each dependency of the target for conflicts */
1302         for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
1303                 /* Ignore .WAIT dependency */
1304                 if (dp->name == wait_name) {
1305                         continue;
1306                 }
1307                 /*
1308                  * For each pending target, look for a dependency which
1309                  * is the same as a dependency of the subtree target.  Since
1310                  * we can't build the subtree until all pending targets have
1311                  * finished which depend on the same dependency, this is
1312                  * a conflict.
1313                  */
1314                 for (rp = running_list; rp != NULL; rp = rp->next) {
1315                         if (rp->state == build_pending) {
1316                                 pending_line = get_prop(rp->target->prop,
1317                                                         line_prop);
1318                                 if (pending_line == NULL) {
1319                                         continue;
1320                                 }
1321                                 for(pending_dp = pending_line->
1322                                                         body.line.dependencies;
1323                                     pending_dp != NULL;
1324                                     pending_dp = pending_dp->next) {
1325                                         if (dp->name == pending_dp->name) {
1326                                                 target->checking_subtree
1327                                                                 = false;
1328                                                 subtree_conflict = rp->target;
1329                                                 subtree_conflict2 = dp->name;
1330                                                 return true;
1331                                         }
1332                                 }
1333                         }
1334                 }
1335                 if (dependency_conflict(dp->name)) {
1336                         target->checking_subtree = false;
1337                         return true;
1338                 }
1339         }
1340         target->checking_subtree = false;
1341         return false;
1342 }
1343 
1344 /*
1345  *      await_parallel(waitflg)
1346  *
1347  *      Waits for parallel children to exit and finishes their processing.
1348  *      If waitflg is false, the function returns after update_delay.
1349  *
1350  *      Parameters:
1351  *              waitflg         dwight
1352  */
1353 void
1354 await_parallel(Boolean waitflg)
1355 {
1356 #ifdef _CHECK_UPDATE_H
1357         static int number_of_unknown_children = 0;
1358 #endif /* _CHECK_UPDATE_H */
1359         Boolean         nohang;
1360         pid_t           pid;
1361         int             status;
1362         Running         rp;
1363         int             waiterr;
1364 
1365         nohang = false;
1366         for ( ; ; ) {
1367                 if (!nohang) {
1368                         (void) alarm((int) update_delay);
1369                 }
1370                 pid = waitpid((pid_t)-1,
1371                               &status,
1372                               nohang ? WNOHANG : 0);
1373                 waiterr = errno;
1374                 if (!nohang) {
1375                         (void) alarm(0);
1376                 }
1377                 if (pid <= 0) {
1378                         if (waiterr == EINTR) {
1379                                 if (waitflg) {
1380                                         continue;
1381                                 } else {
1382                                         return;
1383                                 }
1384                         } else {
1385                                 return;
1386                         }
1387                 }
1388                 for (rp = running_list;
1389                      (rp != NULL) && (rp->pid != pid);
1390                      rp = rp->next) {
1391                         ;
1392                 }
1393                 if (rp == NULL) {
1394 #ifdef _CHECK_UPDATE_H
1395                         /* Ignore first child - it is check_update */
1396                         if (number_of_unknown_children <= 0) {
1397                                 number_of_unknown_children = 1;
1398                                 return;
1399                         }
1400 #endif /* _CHECK_UPDATE_H */
1401                         if (send_mtool_msgs) {
1402                                 continue;
1403                         } else {
1404                                 fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list"));
1405                         }
1406                 } else {
1407                         rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
1408                 }
1409                 nohang = true;
1410                 parallel_process_cnt--;
1411 
1412 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
1413                 if (job_adjust_mode == ADJUST_M2) {
1414                         if (m2_release_job()) {
1415                                 job_adjust_error();
1416                         }
1417                 }
1418 #endif
1419         }
1420 }
1421 
1422 /*
1423  *      finish_children(docheck)
1424  *
1425  *      Finishes the processing for all targets which were running
1426  *      and have now completed.
1427  *
1428  *      Parameters:
1429  *              docheck         Completely check the finished target
1430  *
1431  *      Static variables used:
1432  *              running_tail    The tail of the running list
1433  *
1434  *      Global variables used:
1435  *              continue_after_error  -k flag
1436  *              fatal_in_progress  True if we are finishing up after fatal err
1437  *              running_list    List of running processes
1438  */
1439 void
1440 finish_children(Boolean docheck)
1441 {
1442         int             cmds_length;
1443         Property        line;
1444         Property        line2;
1445         struct stat     out_buf;
1446         Running         rp;
1447         Running         *rp_prev;
1448         Cmd_line        rule;
1449         Boolean         silent_flag;
1450 
1451         for (rp_prev = &running_list, rp = running_list;
1452              rp != NULL;
1453              rp = rp->next) {
1454 bypass_for_loop_inc_4:
1455                 /*
1456                  * If the state is ok or failed, then this target has
1457                  * finished building.
1458                  * In parallel_mode, output the accumulated stdout/stderr.
1459                  * Read the auto dependency stuff, handle a failed build,
1460                  * update the target, then finish the doname process for
1461                  * that target.
1462                  */
1463                 if (rp->state == build_ok || rp->state == build_failed) {
1464                         *rp_prev = rp->next;
1465                         if (rp->next == NULL) {
1466                                 running_tail = rp_prev;
1467                         }
1468                         if ((line2 = rp->command) == NULL) {
1469                                 line2 = get_prop(rp->target->prop, line_prop);
1470                         }
1471                         if (dmake_mode_type == distributed_mode) {
1472                                 if (rp->make_refd) {
1473                                         maybe_reread_make_state();
1474                                 }
1475                         } else {
1476                                 /*
1477                                  * Send an Avo_MToolJobResultMsg to maketool.
1478                                  */
1479 #ifdef DISTRIBUTED
1480                                 if (send_mtool_msgs) {
1481                                         send_job_result_msg(rp);
1482                                 }
1483 #endif
1484                                 /*
1485                                  * Check if there were any job output
1486                                  * from the parallel build.
1487                                  */
1488                                 if (rp->stdout_file != NULL) {
1489                                         if (stat(rp->stdout_file, &out_buf) < 0) {
1490                                                 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1491                                                       rp->stdout_file,
1492                                                       errmsg(errno));
1493                                         }
1494                                         if ((line2 != NULL) &&
1495                                             (out_buf.st_size > 0)) {
1496                                                 cmds_length = 0;
1497                                                 for (rule = line2->body.line.command_used,
1498                                                      silent_flag = silent;
1499                                                      rule != NULL;
1500                                                      rule = rule->next) {
1501                                                         cmds_length += rule->command_line->hash.length + 1;
1502                                                         silent_flag = BOOLEAN(silent_flag || rule->silent);
1503                                                 }
1504                                                 if (out_buf.st_size != cmds_length || silent_flag ||
1505                                                     output_mode == txt2_mode) {
1506                                                         dump_out_file(rp->stdout_file, false);
1507                                                 }
1508                                         }
1509                                         (void) unlink(rp->stdout_file);
1510                                         retmem_mb(rp->stdout_file);
1511                                         rp->stdout_file = NULL;
1512                                 }
1513 #if defined(REDIRECT_ERR)
1514                                 if (!out_err_same && (rp->stderr_file != NULL)) {
1515                                         if (stat(rp->stderr_file, &out_buf) < 0) {
1516                                                 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1517                                                       rp->stderr_file,
1518                                                       errmsg(errno));
1519                                         }
1520                                         if ((line2 != NULL) &&
1521                                             (out_buf.st_size > 0)) {
1522                                                 dump_out_file(rp->stderr_file, true);
1523                                         }
1524                                         (void) unlink(rp->stderr_file);
1525                                         retmem_mb(rp->stderr_file);
1526                                         rp->stderr_file = NULL;
1527                                 }
1528 #endif
1529                         }
1530                         check_state(rp->temp_file);
1531                         if (rp->temp_file != NULL) {
1532                                 free_name(rp->temp_file);
1533                         }
1534                         rp->temp_file = NULL;
1535                         if (rp->state == build_failed) {
1536                                 line = get_prop(rp->target->prop, line_prop);
1537                                 if (line != NULL) {
1538                                         line->body.line.command_used = NULL;
1539                                 }
1540                                 if (continue_after_error ||
1541                                     fatal_in_progress ||
1542                                     !docheck) {
1543                                         warning(catgets(catd, 1, 256, "Command failed for target `%s'"),
1544                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1545                                         build_failed_seen = true;
1546                                 } else {
1547                                         /*
1548                                          * XXX??? - DMake needs to exit(),
1549                                          * but shouldn't call fatal().
1550                                          */
1551 #ifdef PRINT_EXIT_STATUS
1552                                         warning(NOCATGETS("I'm in finish_children. rp->state == build_failed."));
1553 #endif
1554 
1555                                         fatal(catgets(catd, 1, 258, "Command failed for target `%s'"),
1556                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1557                                 }
1558                         }
1559                         if (!docheck) {
1560                                 delete_running_struct(rp);
1561                                 rp = *rp_prev;
1562                                 if (rp == NULL) {
1563                                         break;
1564                                 } else {
1565                                         goto bypass_for_loop_inc_4;
1566                                 }
1567                         }
1568                         update_target(get_prop(rp->target->prop, line_prop),
1569                                       rp->state);
1570                         finish_doname(rp);
1571                         delete_running_struct(rp);
1572                         rp = *rp_prev;
1573                         if (rp == NULL) {
1574                                 break;
1575                         } else {
1576                                 goto bypass_for_loop_inc_4;
1577                         }
1578                 } else {
1579                         rp_prev = &rp->next;
1580                 }
1581         }
1582 }
1583 
1584 /*
1585  *      dump_out_file(filename, err)
1586  *
1587  *      Write the contents of the file to stdout, then unlink the file.
1588  *
1589  *      Parameters:
1590  *              filename        Name of temp file containing output
1591  *
1592  *      Global variables used:
1593  */
1594 static void
1595 dump_out_file(char *filename, Boolean err)
1596 {
1597         int             chars_read;
1598         char            copybuf[BUFSIZ];
1599         int             fd;
1600         int             out_fd = (err ? 2 : 1);
1601 
1602         if ((fd = open(filename, O_RDONLY)) < 0) {
1603                 fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"),
1604                       filename,
1605                       errmsg(errno));
1606         }
1607         if (!silent && output_mode != txt2_mode) {
1608                 (void) fprintf(err ? stderr : stdout,
1609                                err ?
1610                                 catgets(catd, 1, 338, "%s --> Job errors\n") :
1611                                 catgets(catd, 1, 259, "%s --> Job output\n"),
1612                                local_host);
1613                 (void) fflush(err ? stderr : stdout);
1614         }
1615         for (chars_read = read(fd, copybuf, BUFSIZ);
1616              chars_read > 0;
1617              chars_read = read(fd, copybuf, BUFSIZ)) {
1618                 /*
1619                  * Read buffers from the source file until end or error.
1620                  */
1621                 if (write(out_fd, copybuf, chars_read) < 0) {
1622                         fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"),
1623                               filename,
1624                               errmsg(errno));
1625                 }
1626         }
1627         (void) close(fd);
1628         (void) unlink(filename);
1629 }
1630 
1631 /*
1632  *      finish_doname(rp)
1633  *
1634  *      Completes the processing for a target which was left running.
1635  *
1636  *      Parameters:
1637  *              rp              Running list entry for target
1638  *
1639  *      Global variables used:
1640  *              debug_level     Debug flag
1641  *              recursion_level Indentation for debug output
1642  */
1643 static void
1644 finish_doname(Running rp)
1645 {
1646         int             auto_count = rp->auto_count;
1647         Name            *automatics = rp->automatics;
1648         Doname          result = rp->state;
1649         Name            target = rp->target;
1650         Name            true_target = rp->true_target;
1651         Property        *conditionals;
1652 
1653         recursion_level = rp->recursion_level;
1654         if (result == build_ok) {
1655                 if (true_target == NULL) {
1656                         (void) printf(NOCATGETS("Target = %s\n"), target->string_mb);
1657                         (void) printf(NOCATGETS(" State = %d\n"), result);
1658                         fatal(NOCATGETS("Internal error: NULL true_target in finish_doname"));
1659                 }
1660                 /* If all went OK, set a nice timestamp */
1661                 if (true_target->stat.time == file_doesnt_exist) {
1662                         true_target->stat.time = file_max_time;
1663                 }
1664         }
1665         target->state = result;
1666         if (target->is_member) {
1667                 Property member;
1668 
1669                 /* Propagate the timestamp from the member file to the member */
1670                 if ((target->stat.time != file_max_time) &&
1671                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
1672                     (exists(member->body.member.member) > file_doesnt_exist)) {
1673                         target->stat.time =
1674 /*
1675                           exists(member->body.member.member);
1676  */
1677                           member->body.member.member->stat.time;
1678                 }
1679         }
1680         /*
1681          * Check if we found any new auto dependencies when we
1682          * built the target.
1683          */
1684         if ((result == build_ok) && check_auto_dependencies(target,
1685                                                             auto_count,
1686                                                             automatics)) {
1687                 if (debug_level > 0) {
1688                         (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
1689                                       recursion_level,
1690                                       "",
1691                                       true_target->string_mb);
1692                 }
1693                 target->rechecking_target = true;
1694                 target->state = build_running;
1695 
1696                 /* [tolik, Tue Mar 25 1997]
1697                  * Fix for bug 4038824:
1698                  *       command line options set by conditional macros get dropped
1699                  * rp->conditional_cnt and rp->conditional_targets must be copied
1700                  * to new 'rp' during add_pending(). Set_conditionals() stores
1701                  * rp->conditional_targets to the global variable 'conditional_targets'
1702                  * Add_pending() will use this variable to set up 'rp'.
1703                  */
1704                 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
1705                 add_pending(target,
1706                             recursion_level,
1707                             rp->do_get,
1708                             rp->implicit,
1709                             true);
1710                 reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals);
1711         }
1712 }
1713 
1714 /*
1715  *      new_running_struct()
1716  *
1717  *      Constructor for Running struct. Creates a structure and initializes
1718  *      its fields.
1719  *
1720  */
1721 static Running new_running_struct()
1722 {
1723         Running         rp;
1724 
1725         rp = ALLOC(Running);
1726         rp->target = NULL;
1727         rp->true_target = NULL;
1728         rp->command = NULL;
1729         rp->sprodep_value = NULL;
1730         rp->sprodep_env = NULL;
1731         rp->auto_count = 0;
1732         rp->automatics = NULL;
1733         rp->pid = -1;
1734         rp->job_msg_id = -1;
1735         rp->stdout_file = NULL;
1736         rp->stderr_file = NULL;
1737         rp->temp_file = NULL;
1738         rp->next = NULL;
1739         return rp;
1740 }
1741 
1742 /*
1743  *      add_running(target, true_target, command, recursion_level, auto_count,
1744  *                                      automatics, do_get, implicit)
1745  *
1746  *      Adds a record on the running list for this target, which
1747  *      was just spawned and is running.
1748  *
1749  *      Parameters:
1750  *              target          Target being built
1751  *              true_target     True target for target
1752  *              command         Running command.
1753  *              recursion_level Debug indentation level
1754  *              auto_count      Count of automatic dependencies
1755  *              automatics      List of automatic dependencies
1756  *              do_get          Sccs get flag
1757  *              implicit        Implicit flag
1758  *
1759  *      Static variables used:
1760  *              running_tail    Tail of running list
1761  *              process_running PID of process
1762  *
1763  *      Global variables used:
1764  *              current_line    Current line for target
1765  *              current_target  Current target being built
1766  *              stderr_file     Temporary file for stdout
1767  *              stdout_file     Temporary file for stdout
1768  *              temp_file_name  Temporary file for auto dependencies
1769  */
1770 void
1771 add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit)
1772 {
1773         Running         rp;
1774         Name            *p;
1775 
1776         rp = new_running_struct();
1777         rp->state = build_running;
1778         rp->target = target;
1779         rp->true_target = true_target;
1780         rp->command = command;
1781         Property spro_val = get_prop(sunpro_dependencies->prop, macro_prop);
1782         if(spro_val) {
1783                 rp->sprodep_value = spro_val->body.macro.value;
1784                 spro_val->body.macro.value = NULL;
1785                 spro_val = get_prop(sunpro_dependencies->prop, env_mem_prop);
1786                 if(spro_val) {
1787                         rp->sprodep_env = spro_val->body.env_mem.value;
1788                         spro_val->body.env_mem.value = NULL;
1789                 }
1790         }
1791         rp->recursion_level = recursion_level;
1792         rp->do_get = do_get;
1793         rp->implicit = implicit;
1794         rp->auto_count = auto_count;
1795         if (auto_count > 0) {
1796                 rp->automatics = (Name *) getmem(auto_count * sizeof (Name));
1797                 for (p = rp->automatics; auto_count > 0; auto_count--) {
1798                         *p++ = *automatics++;
1799                 }
1800         } else {
1801                 rp->automatics = NULL;
1802         }
1803 #ifdef DISTRIBUTED
1804         if (dmake_mode_type == distributed_mode) {
1805                 rp->make_refd = called_make;
1806                 called_make = false;
1807         } else
1808 #endif
1809         {
1810                 rp->pid = process_running;
1811                 process_running = -1;
1812                 childPid = -1;
1813         }
1814         rp->job_msg_id = job_msg_id;
1815         rp->stdout_file = stdout_file;
1816         rp->stderr_file = stderr_file;
1817         rp->temp_file = temp_file_name;
1818         rp->redo = false;
1819         rp->next = NULL;
1820         store_conditionals(rp);
1821         stdout_file = NULL;
1822         stderr_file = NULL;
1823         temp_file_name = NULL;
1824         current_target = NULL;
1825         current_line = NULL;
1826         *running_tail = rp;
1827         running_tail = &rp->next;
1828 }
1829 
1830 /*
1831  *      add_pending(target, recursion_level, do_get, implicit, redo)
1832  *
1833  *      Adds a record on the running list for a pending target
1834  *      (waiting for its dependents to finish running).
1835  *
1836  *      Parameters:
1837  *              target          Target being built
1838  *              recursion_level Debug indentation level
1839  *              do_get          Sccs get flag
1840  *              implicit        Implicit flag
1841  *              redo            True if this target is being redone
1842  *
1843  *      Static variables used:
1844  *              running_tail    Tail of running list
1845  */
1846 void
1847 add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo)
1848 {
1849         Running         rp;
1850         rp = new_running_struct();
1851         rp->state = build_pending;
1852         rp->target = target;
1853         rp->recursion_level = recursion_level;
1854         rp->do_get = do_get;
1855         rp->implicit = implicit;
1856         rp->redo = redo;
1857         store_conditionals(rp);
1858         *running_tail = rp;
1859         running_tail = &rp->next;
1860 }
1861 
1862 /*
1863  *      add_serial(target, recursion_level, do_get, implicit)
1864  *
1865  *      Adds a record on the running list for a target which must be
1866  *      executed in serial after others have finished.
1867  *
1868  *      Parameters:
1869  *              target          Target being built
1870  *              recursion_level Debug indentation level
1871  *              do_get          Sccs get flag
1872  *              implicit        Implicit flag
1873  *
1874  *      Static variables used:
1875  *              running_tail    Tail of running list
1876  */
1877 void
1878 add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1879 {
1880         Running         rp;
1881 
1882         rp = new_running_struct();
1883         rp->target = target;
1884         rp->recursion_level = recursion_level;
1885         rp->do_get = do_get;
1886         rp->implicit = implicit;
1887         rp->state = build_serial;
1888         rp->redo = false;
1889         store_conditionals(rp);
1890         *running_tail = rp;
1891         running_tail = &rp->next;
1892 }
1893 
1894 /*
1895  *      add_subtree(target, recursion_level, do_get, implicit)
1896  *
1897  *      Adds a record on the running list for a target which must be
1898  *      executed in isolation after others have finished.
1899  *
1900  *      Parameters:
1901  *              target          Target being built
1902  *              recursion_level Debug indentation level
1903  *              do_get          Sccs get flag
1904  *              implicit        Implicit flag
1905  *
1906  *      Static variables used:
1907  *              running_tail    Tail of running list
1908  */
1909 void
1910 add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1911 {
1912         Running         rp;
1913 
1914         rp = new_running_struct();
1915         rp->target = target;
1916         rp->recursion_level = recursion_level;
1917         rp->do_get = do_get;
1918         rp->implicit = implicit;
1919         rp->state = build_subtree;
1920         rp->redo = false;
1921         store_conditionals(rp);
1922         *running_tail = rp;
1923         running_tail = &rp->next;
1924 }
1925 
1926 /*
1927  *      store_conditionals(rp)
1928  *
1929  *      Creates an array of the currently active targets with conditional
1930  *      macros (found in the chain conditional_targets) and puts that
1931  *      array in the Running struct.
1932  *
1933  *      Parameters:
1934  *              rp              Running struct for storing chain
1935  *
1936  *      Global variables used:
1937  *              conditional_targets  Chain of current dynamic conditionals
1938  */
1939 static void
1940 store_conditionals(Running rp)
1941 {
1942         int             cnt;
1943         Chain           cond_name;
1944 
1945         if (conditional_targets == NULL) {
1946                 rp->conditional_cnt = 0;
1947                 rp->conditional_targets = NULL;
1948                 return;
1949         }
1950         cnt = 0;
1951         for (cond_name = conditional_targets;
1952              cond_name != NULL;
1953              cond_name = cond_name->next) {
1954                 cnt++;
1955         }
1956         rp->conditional_cnt = cnt;
1957         rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name));
1958         for (cond_name = conditional_targets;
1959              cond_name != NULL;
1960              cond_name = cond_name->next) {
1961                 rp->conditional_targets[--cnt] = cond_name->name;
1962         }
1963 }
1964 
1965 /*
1966  *      parallel_ok(target, line_prop_must_exists)
1967  *
1968  *      Returns true if the target can be run in parallel
1969  *
1970  *      Return value:
1971  *                              True if can run in parallel
1972  *
1973  *      Parameters:
1974  *              target          Target being tested
1975  *
1976  *      Global variables used:
1977  *              all_parallel    True if all targets default to parallel
1978  *              only_parallel   True if no targets default to parallel
1979  */
1980 Boolean
1981 parallel_ok(Name target, Boolean line_prop_must_exists)
1982 {
1983         Boolean         assign;
1984         Boolean         make_refd;
1985         Property        line;
1986         Cmd_line        rule;
1987 
1988         assign = make_refd = false;
1989         if (((line = get_prop(target->prop, line_prop)) == NULL) &&
1990             line_prop_must_exists) {
1991                 return false;
1992         }
1993         if (line != NULL) {
1994                 for (rule = line->body.line.command_used;
1995                      rule != NULL;
1996                      rule = rule->next) {
1997                         if (rule->assign) {
1998                                 assign = true;
1999                         } else if (rule->make_refd) {
2000                                 make_refd = true;
2001                         }
2002                 }
2003         }
2004         if (assign) {
2005                 return false;
2006         } else if (target->parallel) {
2007                 return true;
2008         } else if (target->no_parallel) {
2009                 return false;
2010         } else if (all_parallel) {
2011                 return true;
2012         } else if (only_parallel) {
2013                 return false;
2014         } else if (make_refd) {
2015                 return false;
2016         } else {
2017                 return true;
2018         }
2019 }
2020 
2021 /*
2022  *      is_running(target)
2023  *
2024  *      Returns true if the target is running.
2025  *
2026  *      Return value:
2027  *                              True if target is running
2028  *
2029  *      Parameters:
2030  *              target          Target to check
2031  *
2032  *      Global variables used:
2033  *              running_list    List of running processes
2034  */
2035 Boolean
2036 is_running(Name target)
2037 {
2038         Running         rp;
2039 
2040         if (target->state != build_running) {
2041                 return false;
2042         }
2043         for (rp = running_list;
2044              rp != NULL && target != rp->target;
2045              rp = rp->next);
2046         if (rp == NULL) {
2047                 return false;
2048         } else {
2049                 return (rp->state == build_running) ? true : false;
2050         }
2051 }
2052 
2053 /*
2054  * This function replaces the makesh binary.
2055  */
2056  
2057 #ifdef SGE_SUPPORT
2058 #define DO_CHECK(f)     if (f <= 0) { \
2059                                 fprintf(stderr, \
2060                                         catgets(catd, 1, 347, "Could not write to file: %s: %s\n"), \
2061                                                 script_file, errmsg(errno)); \
2062                                 _exit(1); \
2063                         }
2064 #endif /* SGE_SUPPORT */
2065 
2066 static pid_t
2067 run_rule_commands(char *host, char **commands)
2068 {
2069         Boolean         always_exec;
2070         Name            command;
2071         Boolean         ignore;
2072         int             length;
2073         Doname          result;
2074         Boolean         silent_flag;
2075 #ifdef SGE_SUPPORT
2076         wchar_t         *wcmd, *tmp_wcs_buffer = NULL;
2077         char            *cmd, *tmp_mbs_buffer = NULL;
2078         FILE            *scrfp;
2079         Name            shell = getvar(shell_name);
2080 #else
2081         wchar_t         *tmp_wcs_buffer;
2082 #endif /* SGE_SUPPORT */
2083 
2084         childPid = fork();
2085         switch (childPid) {
2086         case -1:        /* Error */
2087                 fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"),
2088                       errmsg(errno));
2089                 break;
2090         case 0:         /* Child */
2091                 /* To control the processed targets list is not the child's business */
2092                 running_list = NULL;
2093 #if defined(REDIRECT_ERR)
2094                 if(out_err_same) {
2095                         redirect_io(stdout_file, (char*)NULL);
2096                 } else {
2097                         redirect_io(stdout_file, stderr_file);
2098                 }
2099 #else
2100                 redirect_io(stdout_file, (char*)NULL);
2101 #endif
2102 #ifdef SGE_SUPPORT
2103                 if (grid) {
2104                         int fdes = mkstemp(script_file);
2105                         if ((fdes < 0) || (scrfp = fdopen(fdes, "w")) == NULL) {
2106                                 fprintf(stderr,
2107                                         catgets(catd, 1, 341, "Could not create file: %s: %s\n"),
2108                                         script_file, errmsg(errno));
2109                                 _exit(1);
2110                         }
2111                         if (IS_EQUAL(shell->string_mb, "")) {
2112                                 shell = shell_name;
2113                         }
2114                 }
2115 #endif /* SGE_SUPPORT */
2116                 for (commands = commands;
2117                      (*commands != (char *)NULL);
2118                      commands++) {
2119                         silent_flag = silent;
2120                         ignore = false;
2121                         always_exec = false;
2122                         while ((**commands == (int) at_char) ||
2123                                (**commands == (int) hyphen_char) ||
2124                                (**commands == (int) plus_char)) {
2125                                 if (**commands == (int) at_char) {
2126                                         silent_flag = true;
2127                                 }
2128                                 if (**commands == (int) hyphen_char) {
2129                                         ignore = true;
2130                                 }
2131                                 if (**commands == (int) plus_char) {
2132                                         always_exec = true;
2133                                 }
2134                                 (*commands)++;
2135                         }
2136 #ifdef SGE_SUPPORT
2137                         if (grid) {
2138                                 if ((length = strlen(*commands)) >= MAXPATHLEN / 2) {
2139                                         wcmd = tmp_wcs_buffer = ALLOC_WC(length * 2 + 1);
2140                                         (void) mbstowcs(tmp_wcs_buffer, *commands, length * 2 + 1);
2141                                 } else {
2142                                         MBSTOWCS(wcs_buffer, *commands);
2143                                         wcmd = wcs_buffer;
2144                                         cmd = mbs_buffer;
2145                                 }
2146                                 wchar_t *from = wcmd + wslen(wcmd);
2147                                 wchar_t *to = from + (from - wcmd);
2148                                 *to = (int) nul_char;
2149                                 while (from > wcmd) {
2150                                         *--to = *--from;
2151                                         if (*from == (int) newline_char) { // newline symbols are already quoted
2152                                                 *--to = *--from;
2153                                         } else if (wschr(char_semantics_char, *from)) {
2154                                                 *--to = (int) backslash_char;
2155                                         }
2156                                 }
2157                                 if (length >= MAXPATHLEN*MB_LEN_MAX/2) { // sizeof(mbs_buffer) / 2
2158                                         cmd = tmp_mbs_buffer = getmem((length * MB_LEN_MAX * 2) + 1);
2159                                         (void) wcstombs(tmp_mbs_buffer, to, (length * MB_LEN_MAX * 2) + 1);
2160                                 } else {
2161                                         WCSTOMBS(mbs_buffer, to);
2162                                         cmd = mbs_buffer;
2163                                 }
2164                                 char *mbst, *mbend;
2165                                 if ((length > 0) &&
2166                                     !silent_flag) {
2167                                         for (mbst = cmd; (mbend = strstr(mbst, "\\\n")) != NULL; mbst = mbend + 2) {
2168                                                 *mbend = '\0';
2169                                                 DO_CHECK(fprintf(scrfp, NOCATGETS("/usr/bin/printf '%%s\\n' %s\\\\\n"), mbst));
2170                                                 *mbend = '\\';
2171                                         }
2172                                         DO_CHECK(fprintf(scrfp, NOCATGETS("/usr/bin/printf '%%s\\n' %s\n"), mbst));
2173                                 }
2174                                 if (!do_not_exec_rule ||
2175                                     !working_on_targets ||
2176                                     always_exec) {
2177 #if defined(linux)
2178                                         if (0 != strcmp(shell->string_mb, (char*)NOCATGETS("/bin/sh"))) {
2179                                                 DO_CHECK(fprintf(scrfp, NOCATGETS("%s -c %s\n"), shell->string_mb, cmd));
2180                                         } else
2181 #endif
2182                                         DO_CHECK(fprintf(scrfp, NOCATGETS("%s -ce %s\n"), shell->string_mb, cmd));
2183                                         DO_CHECK(fputs(NOCATGETS("__DMAKECMDEXITSTAT=$?\nif [ ${__DMAKECMDEXITSTAT} -ne 0 ]; then\n"), scrfp));
2184                                         if (ignore) {
2185                                                 DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s ${__DMAKECMDEXITSTAT} %s\n"),
2186                                                         catgets(catd, 1, 343, "\"*** Error code"),
2187                                                         catgets(catd, 1, 344, "(ignored)\"")));
2188                                         } else {
2189                                                 DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s ${__DMAKECMDEXITSTAT}\n"),
2190                                                         catgets(catd, 1, 342, "\"*** Error code\"")));
2191                                         }
2192                                         if (silent_flag) {
2193                                                 DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s\n"),
2194                                                         catgets(catd, 1, 345, "The following command caused the error:")));
2195                                                 for (mbst = cmd; (mbend = strstr(mbst, "\\\n")) != NULL; mbst = mbend + 2) {
2196                                                         *mbend = '\0';
2197                                                         DO_CHECK(fprintf(scrfp, NOCATGETS("\t/usr/bin/printf '%%s\\n' %s\\\\\n"), mbst));
2198                                                         *mbend = '\\';
2199                                                 }
2200                                                 DO_CHECK(fprintf(scrfp, NOCATGETS("\t/usr/bin/printf '%%s\\n' %s\n"), mbst));
2201                                         }
2202                                         if (!ignore) {
2203                                                 DO_CHECK(fputs(NOCATGETS("\texit ${__DMAKECMDEXITSTAT}\n"), scrfp));
2204                                         }
2205                                         DO_CHECK(fputs(NOCATGETS("fi\n"), scrfp));
2206                                 }
2207                                 if (tmp_wcs_buffer) {
2208                                         retmem_mb(tmp_mbs_buffer);
2209                                         tmp_mbs_buffer = NULL;
2210                                 }
2211                                 if (tmp_wcs_buffer) {
2212                                         retmem(tmp_wcs_buffer);
2213                                         tmp_wcs_buffer = NULL;
2214                                 }
2215                                 continue;
2216                         }
2217 #endif /* SGE_SUPPORT */
2218                         if ((length = strlen(*commands)) >= MAXPATHLEN) {
2219                                 tmp_wcs_buffer = ALLOC_WC(length + 1);
2220                                 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
2221                                 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
2222                                 retmem(tmp_wcs_buffer);
2223                         } else {
2224                                 MBSTOWCS(wcs_buffer, *commands);
2225                                 command = GETNAME(wcs_buffer, FIND_LENGTH);
2226                         }
2227                         if ((command->hash.length > 0) &&
2228                             !silent_flag) {
2229                                 (void) printf("%s\n", command->string_mb);
2230                         }
2231                         result = dosys(command,
2232                                        ignore,
2233                                        false,
2234                                        false, /* bugs #4085164 & #4990057 */
2235                                        /* BOOLEAN(silent_flag && ignore), */
2236                                        always_exec, 
2237                                        (Name) NULL,
2238                                        false);
2239                         if (result == build_failed) {
2240                                 if (silent_flag) {
2241                                         (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb);
2242                                 }
2243                                 if (!ignore) {
2244                                         _exit(1);
2245                                 }
2246                         }
2247                 }
2248 #ifndef SGE_SUPPORT
2249                 _exit(0);
2250 #else
2251                 if (!grid) {
2252                         _exit(0);
2253                 }
2254                 DO_CHECK(fputs(NOCATGETS("exit 0\n"), scrfp));
2255                 if (fclose(scrfp) != 0) {
2256                         fprintf(stderr,
2257                                 catgets(catd, 1, 346, "Could not close file: %s: %s\n"),
2258                                 script_file, errmsg(errno));
2259                         _exit(1);
2260                 }
2261                 {
2262 
2263 #define DEFAULT_QRSH_TRIES_NUMBER       1
2264 #define DEFAULT_QRSH_TIMEOUT            0
2265 
2266                 static char     *sge_env_var = NULL;
2267                 static int      qrsh_tries_number = DEFAULT_QRSH_TRIES_NUMBER;
2268                 static int      qrsh_timeout = DEFAULT_QRSH_TIMEOUT;
2269 #define SGE_DEBUG
2270 #ifdef SGE_DEBUG
2271                 static  Boolean do_not_remove = false;
2272 #endif /* SGE_DEBUG */
2273                 if (sge_env_var == NULL) {
2274                         sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_TRIES"));
2275                         if (sge_env_var != NULL) {
2276                                 qrsh_tries_number = atoi(sge_env_var);
2277                                 if (qrsh_tries_number < 1 || qrsh_tries_number > 9) {
2278                                         qrsh_tries_number = DEFAULT_QRSH_TRIES_NUMBER;
2279                                 }
2280                         }
2281                         sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_TIMEOUT"));
2282                         if (sge_env_var != NULL) {
2283                                 qrsh_timeout = atoi(sge_env_var);
2284                                 if (qrsh_timeout <= 0) {
2285                                         qrsh_timeout = DEFAULT_QRSH_TIMEOUT;
2286                                 }
2287                         } else {
2288                                 sge_env_var = "";
2289                         }
2290 #ifdef SGE_DEBUG
2291                         sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_DEBUG"));
2292                         if (sge_env_var == NULL) {
2293                                 sge_env_var = "";
2294                         }
2295                         if (strstr(sge_env_var, NOCATGETS("noqrsh")) != NULL)
2296                                 qrsh_tries_number = 0;
2297                         if (strstr(sge_env_var, NOCATGETS("donotremove")) != NULL)
2298                                 do_not_remove = true;
2299 #endif /* SGE_DEBUG */
2300                 }
2301                 for (int i = qrsh_tries_number; ; i--)
2302                 if ((childPid = fork()) < 0) {
2303                         fatal(catgets(catd, 1, 348, "Could not fork child process for qrsh job: %s"),
2304                                 errmsg(errno));
2305                         _exit(1);
2306                 } else if (childPid == 0) {
2307                         enable_interrupt((void (*) (int))SIG_DFL);
2308                         if (i > 0) {
2309                                 static char qrsh_cmd[50+MAXPATHLEN] = NOCATGETS("qrsh -cwd -V -noshell -nostdin /bin/sh ");
2310                                 static char *fname_ptr = NULL;
2311                                 static char *argv[] = { NOCATGETS("sh"),
2312                                                         NOCATGETS("-fce"),
2313                                                         qrsh_cmd,
2314                                                         NULL};
2315                                 if (fname_ptr == NULL) {
2316                                         fname_ptr = qrsh_cmd + strlen(qrsh_cmd);
2317                                 }
2318                                 strcpy(fname_ptr, script_file);
2319                                 (void) execve(NOCATGETS("/bin/sh"), argv, environ);
2320                         } else {
2321                                 static char *argv[] = { NOCATGETS("sh"),
2322                                                         script_file,
2323                                                         NULL};
2324                                 (void) execve(NOCATGETS("/bin/sh"), argv, environ);
2325                         }
2326                         fprintf(stderr,
2327                                 catgets(catd, 1, 349, "Could not load `qrsh': %s\n"),
2328                                 errmsg(errno));
2329                         _exit(1);
2330                 } else {
2331 #if defined (HP_UX) || defined (linux) || defined (SUN5_0)
2332                         int             status;
2333 #else
2334                         union wait      status;
2335 #endif
2336                         pid_t pid;
2337                         while ((pid = wait(&status)) != childPid) {
2338                                 if (pid == -1) {
2339                                         fprintf(stderr,
2340                                                 catgets(catd, 1, 350, "wait() failed: %s\n"),
2341                                                 errmsg(errno));
2342                                         _exit(1);
2343                                 }
2344                         }
2345                         if (status != 0 && i > 0) {
2346                                 if (i > 1) {
2347                                         sleep(qrsh_timeout);
2348                                 }
2349                                 continue;
2350                         }
2351 #ifdef SGE_DEBUG
2352                         if (do_not_remove) {
2353                                 if (status) {
2354                                         fprintf(stderr,
2355                                                 NOCATGETS("SGE script failed: %s\n"),
2356                                                 script_file);
2357                                 }
2358                                 _exit(status ? 1 : 0);
2359                         }
2360 #endif /* SGE_DEBUG */
2361                         (void) unlink(script_file);
2362                         _exit(status ? 1 : 0);
2363                 }
2364                 }
2365 #endif /* SGE_SUPPORT */
2366                 break;
2367         default:
2368                 break;
2369         }
2370         return childPid;
2371 }
2372 
2373 static void
2374 maybe_reread_make_state(void)
2375 {
2376         /* Copying dosys()... */
2377         if (report_dependencies_level == 0) {
2378                 make_state->stat.time = file_no_time;
2379                 (void) exists(make_state);
2380                 if (make_state_before == make_state->stat.time) {
2381                         return;
2382                 }
2383                 makefile_type = reading_statefile;
2384                 if (read_trace_level > 1) {
2385                         trace_reader = true;
2386                 }
2387                 temp_file_number++;
2388                 (void) read_simple_file(make_state,
2389                                         false,
2390                                         false,
2391                                         false,
2392                                         false,
2393                                         false,
2394                                         true);
2395                 trace_reader = false;
2396         }
2397 }
2398 
2399 #ifdef DISTRIBUTED
2400 /*
2401  * Create and send an Avo_MToolJobResultMsg.
2402  */
2403 static void
2404 send_job_result_msg(Running rp)
2405 {
2406         Avo_MToolJobResultMsg   *msg;
2407         RWCollectable           *xdr_msg;
2408 
2409         msg = new Avo_MToolJobResultMsg();
2410         msg->setResult(rp->job_msg_id,
2411                        (rp->state == build_ok) ? 0 : 1,
2412                        DONE);
2413         append_job_result_msg(msg,
2414                                 rp->stdout_file,
2415                                 rp->stderr_file);
2416 
2417         xdr_msg = (RWCollectable *)msg;
2418         xdr(get_xdrs_ptr(), xdr_msg);
2419         (void) fflush(get_mtool_msgs_fp());
2420 
2421         delete msg;
2422 }
2423 
2424 /*
2425  * Append the stdout/err to Avo_MToolJobResultMsg.
2426  */
2427 static void
2428 append_job_result_msg(Avo_MToolJobResultMsg *msg, char *outFn, char *errFn)
2429 {
2430         FILE            *fp;
2431         char            line[MAXPATHLEN];
2432 
2433         fp = fopen(outFn, "r");
2434         if (fp == NULL) {
2435                 /* Hmmm... what should we do here? */
2436                 return;
2437         }
2438         while (fgets(line, MAXPATHLEN, fp) != NULL) {
2439                 if (line[strlen(line) - 1] == '\n') {
2440                         line[strlen(line) - 1] = '\0';
2441                 }
2442                 msg->appendOutput(AVO_STRDUP(line));
2443         }
2444         (void) fclose(fp);
2445 }
2446 #endif
2447 
2448 static void
2449 delete_running_struct(Running rp)
2450 {
2451         if ((rp->conditional_cnt > 0) &&
2452             (rp->conditional_targets != NULL)) {
2453                 retmem_mb((char *) rp->conditional_targets);
2454         }
2455 /**/
2456         if ((rp->auto_count > 0) &&
2457             (rp->automatics != NULL)) {
2458                 retmem_mb((char *) rp->automatics);
2459         }
2460 /**/
2461         if(rp->sprodep_value) {
2462                 free_name(rp->sprodep_value);
2463         }
2464         if(rp->sprodep_env) {
2465                 retmem_mb(rp->sprodep_env);
2466         }
2467         retmem_mb((char *) rp);
2468 
2469 }
2470 
2471 #endif
2472