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