Print this page
make: translate using gettext, rather than the unmaintainable catgets


  29  *
  30  *      Deal with the parallel processing
  31  */
  32 
  33 /*
  34  * Included files
  35  */
  36 #include <errno.h>                /* errno */
  37 #include <fcntl.h>
  38 #include <mk/defs.h>
  39 #include <mksh/dosys.h>           /* redirect_io() */
  40 #include <mksh/macro.h>           /* expand_value() */
  41 #include <mksh/misc.h>            /* getmem() */
  42 #include <sys/signal.h>
  43 #include <sys/stat.h>
  44 #include <sys/types.h>
  45 #include <sys/utsname.h>
  46 #include <sys/wait.h>
  47 #include <unistd.h>
  48 #include <netdb.h>

  49 
  50 
  51 
  52 /*
  53  * Defined macros
  54  */
  55 #define MAXRULES                100
  56 
  57 /*
  58  * This const should be in avo_dms/include/AvoDmakeCommand.h
  59  */
  60 const int local_host_mask = 0x20;
  61 
  62 
  63 /*
  64  * typedefs & structs
  65  */
  66 
  67 
  68 /*


 114         int                     cmd_options = 0;
 115         char                    *commands[MAXRULES + 5];
 116         char                    *cp;
 117         Name                    dmake_name;
 118         Name                    dmake_value;
 119         int                     ignore;
 120         Name                    make_machines_name;
 121         char                    **p;
 122         Property                prop;
 123         Doname                  result = build_ok;
 124         Cmd_line                rule;
 125         Boolean                 silent_flag;
 126         Name                    target = line->body.line.target;
 127         Boolean                 wrote_state_file = false;
 128 
 129         if ((pmake_max_jobs == 0) &&
 130             (dmake_mode_type == parallel_mode)) {
 131                 if (local_host[0] == '\0') {
 132                         (void) gethostname(local_host, MAXNAMELEN);
 133                 }
 134                 MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_MAX_JOBS"));
 135                 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 136                 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 137                     ((dmake_value = prop->body.macro.value) != NULL)) {
 138                         pmake_max_jobs = atoi(dmake_value->string_mb);
 139                         if (pmake_max_jobs <= 0) {
 140                                 warning(catgets(catd, 1, 308, "DMAKE_MAX_JOBS cannot be less than or equal to zero."));
 141                                 warning(catgets(catd, 1, 309, "setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
 142                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 143                         }
 144                 } else {
 145                         /*
 146                          * For backwards compatibility w/ PMake 1.x, when
 147                          * DMake 2.x is being run in parallel mode, DMake
 148                          * should parse the PMake startup file
 149                          * $(HOME)/.make.machines to get the pmake_max_jobs.
 150                          */
 151                         MBSTOWCS(wcs_buffer, NOCATGETS("PMAKE_MACHINESFILE"));
 152                         dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 153                         if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 154                             ((dmake_value = prop->body.macro.value) != NULL)) {
 155                                 make_machines_name = dmake_value;
 156                         } else {
 157                                 make_machines_name = NULL;
 158                         }
 159                         if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
 160                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 161                         }
 162                 }
 163         }
 164 
 165         if ((dmake_mode_type == serial_mode) ||
 166             ((dmake_mode_type == parallel_mode) && (waitflg))) {
 167                 return (execute_serial(line));
 168         }
 169 
 170         {
 171                 p = commands;


 305  *      ftok(), shmget(), shmat(), shmdt(), shmctl()
 306  *      sem_init(), sem_trywait(), sem_post(), sem_destroy()
 307  *      creat(), close(), unlink()
 308  *      getenv(), putenv()
 309  *
 310  *  Static variables:
 311  *      m2_file         - tmp file name to create ipc key for shared memory
 312  *      m2_shm_id       - shared memory id
 313  *      m2_shm_sem      - shared memory semaphore
 314  */
 315 
 316 static char     m2_file[MAXPATHLEN];
 317 static int      m2_shm_id = -1;
 318 static sem_t*   m2_shm_sem = 0;
 319 
 320 static int
 321 m2_init() {
 322         char    *var;
 323         key_t   key;
 324 
 325         if ((var = getenv(NOCATGETS("__DMAKE_M2_FILE__"))) == 0) {
 326                 /* compose tmp file name */
 327                 sprintf(m2_file, NOCATGETS("%s/dmake.m2.%d.XXXXXX"), tmpdir, getpid());
 328 
 329                 /* create tmp file */
 330                 int fd = mkstemp(m2_file);
 331                 if (fd < 0) {
 332                         return -1;
 333                 } else {
 334                         close(fd);
 335                 }
 336         } else {
 337                 /* using existing semaphore */
 338                 strcpy(m2_file, var);
 339         }
 340 
 341         /* combine IPC key */
 342         if ((key = ftok(m2_file, 38)) == (key_t) -1) {
 343                 return -1;
 344         }
 345 
 346         /* create shared memory */
 347         if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {


 349         }
 350 
 351         /* attach shared memory */
 352         if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
 353                 return -1;
 354         }
 355 
 356         /* root process */
 357         if (var == 0) {
 358                 /* initialize semaphore */
 359                 if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
 360                         return -1;
 361                 }
 362 
 363                 /* alloc memory for env variable */
 364                 if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
 365                         return -1;
 366                 }
 367 
 368                 /* put key to env */
 369                 sprintf(var, NOCATGETS("__DMAKE_M2_FILE__=%s"), m2_file);
 370                 if (putenv(var)) {
 371                         return -1;
 372                 }
 373         }
 374         return 0;
 375 }
 376 
 377 static void
 378 m2_fini() {
 379         if (m2_shm_id >= 0) {
 380                 struct shmid_ds stat;
 381 
 382                 /* determine the number of attached processes */
 383                 if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
 384                         if (stat.shm_nattch <= 1) {
 385                                 /* destroy semaphore */
 386                                 if (m2_shm_sem != 0) {
 387                                         (void) sem_destroy(m2_shm_sem);
 388                                 }
 389 


 464  *
 465  *  Description:
 466  *      Prints warning message, cleans up job adjust data, and disables job adjustment
 467  *
 468  *  Environment:
 469  *      DMAKE_ADJUST_MAX_JOBS
 470  *
 471  *  External functions:
 472  *      putenv()
 473  *
 474  *  Static variables:
 475  *      job_adjust_mode Current job adjust mode
 476  */
 477 static void
 478 job_adjust_error() {
 479         if (job_adjust_mode != ADJUST_NONE) {
 480                 /* cleanup internals */
 481                 job_adjust_fini();
 482 
 483                 /* warning message for the user */
 484                 warning(catgets(catd, 1, 339, "Encountered max jobs auto adjustment error - disabling auto adjustment."));
 485 
 486                 /* switch off job adjustment for the children */
 487                 putenv(strdup(NOCATGETS("DMAKE_ADJUST_MAX_JOBS=NO")));
 488 
 489                 /* and for this dmake */
 490                 job_adjust_mode = ADJUST_NONE;
 491         }
 492 }
 493 
 494 /*
 495  *  void job_adjust_init()
 496  *
 497  *  Description:
 498  *      Parses DMAKE_ADJUST_MAX_JOBS env variable
 499  *      and performs appropriate initializations.
 500  *
 501  *  Environment:
 502  *      DMAKE_ADJUST_MAX_JOBS
 503  *        DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment
 504  *        DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode
 505  *        other                         - M1 adjust mode
 506  *
 507  *  External functions:
 508  *      getenv()
 509  *
 510  *  Static variables:
 511  *      job_adjust_mode Current job adjust mode
 512  */
 513 static void
 514 job_adjust_init() {
 515         if (job_adjust_mode == ADJUST_UNKNOWN) {
 516                 /* default mode */
 517                 job_adjust_mode = ADJUST_M1;
 518 
 519                 /* determine adjust mode */
 520                 if (char *var = getenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS"))) {
 521                         if (strcasecmp(var, NOCATGETS("NO")) == 0) {
 522                                 job_adjust_mode = ADJUST_NONE;
 523                         } else if (strcasecmp(var, NOCATGETS("M2")) == 0) {
 524                                 job_adjust_mode = ADJUST_M2;
 525                         }
 526                 }
 527 
 528                 /* M2 specific initialization */
 529                 if (job_adjust_mode == ADJUST_M2) {
 530                         if (m2_init()) {
 531                                 job_adjust_error();
 532                         }
 533                 }
 534         }
 535 }
 536 
 537 #endif /* MAXJOBS_ADJUST_RFE4694000 */
 538 
 539 /*
 540  *      distribute_process(char **commands, Property line)
 541  *
 542  *      Parameters:
 543  *              commands        argv vector of commands to execute


 604                                 finish_children(true);
 605                         }
 606                 }
 607                 break;
 608         default:
 609                 while (parallel_process_cnt >= pmake_max_jobs) {
 610                         await_parallel(false);
 611                         finish_children(true);
 612                 }
 613         }
 614 #endif /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
 615         setvar_envvar();
 616         /*
 617          * Tell the user what DMake is doing.
 618          */
 619         if (!silent && output_mode != txt2_mode) {
 620                 /*
 621                  * Print local_host --> x job(s).
 622                  */
 623                 (void) fprintf(stdout,
 624                                catgets(catd, 1, 325, "%s --> %d %s\n"),
 625                                local_host,
 626                                parallel_process_cnt + 1,
 627                                (parallel_process_cnt == 0) ? catgets(catd, 1, 124, "job") : catgets(catd, 1, 125, "jobs"));
 628 
 629                 /* Print command line(s). */
 630                 tmp_index = 0;
 631                 while (commands[tmp_index] != NULL) {
 632                     /* No @ char. */
 633                     /* XXX - need to add [2] when + prefix is added */
 634                     if ((commands[tmp_index][0] != (int) at_char) &&
 635                         (commands[tmp_index][1] != (int) at_char)) {
 636                         tmp_index_str_ptr = commands[tmp_index];
 637                         if (*tmp_index_str_ptr == (int) hyphen_char) {
 638                                 tmp_index_str_ptr++;
 639                         }
 640                         (void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
 641                     }
 642                     tmp_index++;
 643                 }
 644                 (void) fflush(stdout);
 645         }
 646 
 647         (void) sprintf(mbstring,
 648                         NOCATGETS("%s/dmake.stdout.%d.%d.XXXXXX"),
 649                         tmpdir,
 650                         getpid(),
 651                         file_number++);
 652 
 653         mktemp(mbstring);
 654 
 655         stdout_file = strdup(mbstring);
 656         stderr_file = NULL;
 657 
 658         if (!out_err_same) {
 659                 (void) sprintf(mbstring,
 660                                 NOCATGETS("%s/dmake.stderr.%d.%d.XXXXXX"),
 661                                 tmpdir,
 662                                 getpid(),
 663                                 file_number++);
 664 
 665                 mktemp(mbstring);
 666 
 667                 stderr_file = strdup(mbstring);
 668         }
 669 
 670         process_running = run_rule_commands(local_host, commands);
 671 
 672         return build_running;
 673 }
 674 
 675 /*
 676  *      doname_parallel(target, do_get, implicit)
 677  *
 678  *      Processes the given target and finishes up any parallel
 679  *      processes left running.
 680  *


 917                                                        rp->implicit);
 918                                         quiescent = false;
 919                                         delete_running_struct(rp);
 920                                         goto start_loop_3;
 921                                 } else {
 922                                         subtree_target = rp_prev;
 923                                         rp_prev = &rp->next;
 924                                 }
 925                         } else {
 926                                 rp_prev = &rp->next;
 927                         }
 928                 }
 929         }
 930         /*
 931          * If still nothing found to build, we either have a deadlock
 932          * or a subtree with a dependency conflict with something waiting
 933          * to build.
 934          */
 935         if (quiescent) {
 936                 if (subtree_target == NULL) {
 937                         fatal(catgets(catd, 1, 126, "Internal error: deadlock detected in process_next"));
 938                 } else {
 939                         rp = *subtree_target;
 940                         if (debug_level > 0) {
 941                                 warning(catgets(catd, 1, 127, "Conditional macro conflict encountered for %s between %s and %s"),
 942                                         subtree_conflict2->string_mb,
 943                                         rp->target->string_mb,
 944                                         subtree_conflict->string_mb);
 945                         }
 946                         *subtree_target = (*subtree_target)->next;
 947                         if (rp->next == NULL) {
 948                                 running_tail = subtree_target;
 949                         }
 950                         recursion_level = rp->recursion_level;
 951                         doname_subtree(rp->target, rp->do_get, rp->implicit);
 952                         delete_running_struct(rp);
 953                 }
 954         }
 955 }
 956 
 957 /*
 958  *      set_conditionals(cnt, targets)
 959  *
 960  *      Sets the conditional macros for the targets given in the array of
 961  *      targets.  The old macro values are returned in an array of


1127                 if (!nohang) {
1128                         (void) alarm(0);
1129                 }
1130                 if (pid <= 0) {
1131                         if (waiterr == EINTR) {
1132                                 if (waitflg) {
1133                                         continue;
1134                                 } else {
1135                                         return;
1136                                 }
1137                         } else {
1138                                 return;
1139                         }
1140                 }
1141                 for (rp = running_list;
1142                      (rp != NULL) && (rp->pid != pid);
1143                      rp = rp->next) {
1144                         ;
1145                 }
1146                 if (rp == NULL) {
1147                         fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list"));
1148                 } else {
1149                         rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
1150                 }
1151                 nohang = true;
1152                 parallel_process_cnt--;
1153 
1154 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
1155                 if (job_adjust_mode == ADJUST_M2) {
1156                         if (m2_release_job()) {
1157                                 job_adjust_error();
1158                         }
1159                 }
1160 #endif
1161         }
1162 }
1163 
1164 /*
1165  *      finish_children(docheck)
1166  *
1167  *      Finishes the processing for all targets which were running


1201                  * Read the auto dependency stuff, handle a failed build,
1202                  * update the target, then finish the doname process for
1203                  * that target.
1204                  */
1205                 if (rp->state == build_ok || rp->state == build_failed) {
1206                         *rp_prev = rp->next;
1207                         if (rp->next == NULL) {
1208                                 running_tail = rp_prev;
1209                         }
1210                         if ((line2 = rp->command) == NULL) {
1211                                 line2 = get_prop(rp->target->prop, line_prop);
1212                         }
1213 
1214 
1215                         /*
1216                          * Check if there were any job output
1217                          * from the parallel build.
1218                          */
1219                         if (rp->stdout_file != NULL) {
1220                                 if (stat(rp->stdout_file, &out_buf) < 0) {
1221                                         fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1222                                             rp->stdout_file,
1223                                             errmsg(errno));
1224                                 }
1225 
1226                                 if ((line2 != NULL) &&
1227                                     (out_buf.st_size > 0)) {
1228                                         cmds_length = 0;
1229                                         for (rule = line2->body.line.command_used,
1230                                                  silent_flag = silent;
1231                                              rule != NULL;
1232                                              rule = rule->next) {
1233                                                 cmds_length += rule->command_line->hash.length + 1;
1234                                                 silent_flag = BOOLEAN(silent_flag || rule->silent);
1235                                         }
1236                                         if (out_buf.st_size != cmds_length || silent_flag ||
1237                                             output_mode == txt2_mode) {
1238                                                 dump_out_file(rp->stdout_file, false);
1239                                         }
1240                                 }
1241                                 (void) unlink(rp->stdout_file);
1242                                 retmem_mb(rp->stdout_file);
1243                                 rp->stdout_file = NULL;
1244                         }
1245 
1246                         if (!out_err_same && (rp->stderr_file != NULL)) {
1247                                 if (stat(rp->stderr_file, &out_buf) < 0) {
1248                                         fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1249                                             rp->stderr_file,
1250                                             errmsg(errno));
1251                                 }
1252                                 if ((line2 != NULL) &&
1253                                     (out_buf.st_size > 0)) {
1254                                         dump_out_file(rp->stderr_file, true);
1255                                 }
1256                                 (void) unlink(rp->stderr_file);
1257                                 retmem_mb(rp->stderr_file);
1258                                 rp->stderr_file = NULL;
1259                         }
1260                         
1261                         check_state(rp->temp_file);
1262                         if (rp->temp_file != NULL) {
1263                                 free_name(rp->temp_file);
1264                         }
1265                         rp->temp_file = NULL;
1266                         if (rp->state == build_failed) {
1267                                 line = get_prop(rp->target->prop, line_prop);
1268                                 if (line != NULL) {
1269                                         line->body.line.command_used = NULL;
1270                                 }
1271                                 if (continue_after_error ||
1272                                     fatal_in_progress ||
1273                                     !docheck) {
1274                                         warning(catgets(catd, 1, 256, "Command failed for target `%s'"),
1275                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1276                                         build_failed_seen = true;
1277                                 } else {
1278                                         /*
1279                                          * XXX??? - DMake needs to exit(),
1280                                          * but shouldn't call fatal().
1281                                          */
1282 #ifdef PRINT_EXIT_STATUS
1283                                         warning(NOCATGETS("I'm in finish_children. rp->state == build_failed."));
1284 #endif
1285 
1286                                         fatal(catgets(catd, 1, 258, "Command failed for target `%s'"),
1287                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1288                                 }
1289                         }
1290                         if (!docheck) {
1291                                 delete_running_struct(rp);
1292                                 rp = *rp_prev;
1293                                 if (rp == NULL) {
1294                                         break;
1295                                 } else {
1296                                         goto bypass_for_loop_inc_4;
1297                                 }
1298                         }
1299                         update_target(get_prop(rp->target->prop, line_prop),
1300                                       rp->state);
1301                         finish_doname(rp);
1302                         delete_running_struct(rp);
1303                         rp = *rp_prev;
1304                         if (rp == NULL) {
1305                                 break;
1306                         } else {


1314 
1315 /*
1316  *      dump_out_file(filename, err)
1317  *
1318  *      Write the contents of the file to stdout, then unlink the file.
1319  *
1320  *      Parameters:
1321  *              filename        Name of temp file containing output
1322  *
1323  *      Global variables used:
1324  */
1325 static void
1326 dump_out_file(char *filename, Boolean err)
1327 {
1328         int             chars_read;
1329         char            copybuf[BUFSIZ];
1330         int             fd;
1331         int             out_fd = (err ? 2 : 1);
1332 
1333         if ((fd = open(filename, O_RDONLY)) < 0) {
1334                 fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"),
1335                       filename,
1336                       errmsg(errno));
1337         }
1338         if (!silent && output_mode != txt2_mode) {
1339                 (void) fprintf(err ? stderr : stdout,
1340                                err ?
1341                                 catgets(catd, 1, 338, "%s --> Job errors\n") :
1342                                 catgets(catd, 1, 259, "%s --> Job output\n"),
1343                                local_host);
1344                 (void) fflush(err ? stderr : stdout);
1345         }
1346         for (chars_read = read(fd, copybuf, BUFSIZ);
1347              chars_read > 0;
1348              chars_read = read(fd, copybuf, BUFSIZ)) {
1349                 /*
1350                  * Read buffers from the source file until end or error.
1351                  */
1352                 if (write(out_fd, copybuf, chars_read) < 0) {
1353                         fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"),
1354                               filename,
1355                               errmsg(errno));
1356                 }
1357         }
1358         (void) close(fd);
1359         (void) unlink(filename);
1360 }
1361 
1362 /*
1363  *      finish_doname(rp)
1364  *
1365  *      Completes the processing for a target which was left running.
1366  *
1367  *      Parameters:
1368  *              rp              Running list entry for target
1369  *
1370  *      Global variables used:
1371  *              debug_level     Debug flag
1372  *              recursion_level Indentation for debug output
1373  */
1374 static void
1375 finish_doname(Running rp)
1376 {
1377         int             auto_count = rp->auto_count;
1378         Name            *automatics = rp->automatics;
1379         Doname          result = rp->state;
1380         Name            target = rp->target;
1381         Name            true_target = rp->true_target;
1382         Property        *conditionals;
1383 
1384         recursion_level = rp->recursion_level;
1385         if (result == build_ok) {
1386                 if (true_target == NULL) {
1387                         (void) printf(NOCATGETS("Target = %s\n"), target->string_mb);
1388                         (void) printf(NOCATGETS(" State = %d\n"), result);
1389                         fatal(NOCATGETS("Internal error: NULL true_target in finish_doname"));
1390                 }
1391                 /* If all went OK, set a nice timestamp */
1392                 if (true_target->stat.time == file_doesnt_exist) {
1393                         true_target->stat.time = file_max_time;
1394                 }
1395         }
1396         target->state = result;
1397         if (target->is_member) {
1398                 Property member;
1399 
1400                 /* Propagate the timestamp from the member file to the member */
1401                 if ((target->stat.time != file_max_time) &&
1402                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
1403                     (exists(member->body.member.member) > file_doesnt_exist)) {
1404                         target->stat.time =
1405 /*
1406                           exists(member->body.member.member);
1407  */
1408                           member->body.member.member->stat.time;
1409                 }
1410         }
1411         /*
1412          * Check if we found any new auto dependencies when we
1413          * built the target.
1414          */
1415         if ((result == build_ok) && check_auto_dependencies(target,
1416                                                             auto_count,
1417                                                             automatics)) {
1418                 if (debug_level > 0) {
1419                         (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
1420                                       recursion_level,
1421                                       "",
1422                                       true_target->string_mb);
1423                 }
1424                 target->rechecking_target = true;
1425                 target->state = build_running;
1426 
1427                 /* [tolik, Tue Mar 25 1997]
1428                  * Fix for bug 4038824:
1429                  *       command line options set by conditional macros get dropped
1430                  * rp->conditional_cnt and rp->conditional_targets must be copied
1431                  * to new 'rp' during add_pending(). Set_conditionals() stores
1432                  * rp->conditional_targets to the global variable 'conditional_targets'
1433                  * Add_pending() will use this variable to set up 'rp'.
1434                  */
1435                 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
1436                 add_pending(target,
1437                             recursion_level,
1438                             rp->do_get,
1439                             rp->implicit,


1767 
1768 /*
1769  * This function replaces the makesh binary.
1770  */
1771  
1772 
1773 static pid_t
1774 run_rule_commands(char *host, char **commands)
1775 {
1776         Boolean         always_exec;
1777         Name            command;
1778         Boolean         ignore;
1779         int             length;
1780         Doname          result;
1781         Boolean         silent_flag;
1782         wchar_t         *tmp_wcs_buffer;
1783 
1784         childPid = fork();
1785         switch (childPid) {
1786         case -1:        /* Error */
1787                 fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"),
1788                       errmsg(errno));
1789                 break;
1790         case 0:         /* Child */
1791                 /* To control the processed targets list is not the child's business */
1792                 running_list = NULL;
1793                 if(out_err_same) {
1794                         redirect_io(stdout_file, (char*)NULL);
1795                 } else {
1796                         redirect_io(stdout_file, stderr_file);
1797                 }
1798                 for (commands = commands;
1799                      (*commands != (char *)NULL);
1800                      commands++) {
1801                         silent_flag = silent;
1802                         ignore = false;
1803                         always_exec = false;
1804                         while ((**commands == (int) at_char) ||
1805                                (**commands == (int) hyphen_char) ||
1806                                (**commands == (int) plus_char)) {
1807                                 if (**commands == (int) at_char) {


1820                                 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
1821                                 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
1822                                 retmem(tmp_wcs_buffer);
1823                         } else {
1824                                 MBSTOWCS(wcs_buffer, *commands);
1825                                 command = GETNAME(wcs_buffer, FIND_LENGTH);
1826                         }
1827                         if ((command->hash.length > 0) &&
1828                             !silent_flag) {
1829                                 (void) printf("%s\n", command->string_mb);
1830                         }
1831                         result = dosys(command,
1832                                        ignore,
1833                                        false,
1834                                        false, /* bugs #4085164 & #4990057 */
1835                                        /* BOOLEAN(silent_flag && ignore), */
1836                                        always_exec, 
1837                                        (Name) NULL);
1838                         if (result == build_failed) {
1839                                 if (silent_flag) {
1840                                         (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb);
1841                                 }
1842                                 if (!ignore) {
1843                                         _exit(1);
1844                                 }
1845                         }
1846                 }
1847                 _exit(0);
1848                 break;
1849         default:
1850                 break;
1851         }
1852         return childPid;
1853 }
1854 
1855 static void
1856 maybe_reread_make_state(void)
1857 {
1858         /* Copying dosys()... */
1859         if (report_dependencies_level == 0) {
1860                 make_state->stat.time = file_no_time;




  29  *
  30  *      Deal with the parallel processing
  31  */
  32 
  33 /*
  34  * Included files
  35  */
  36 #include <errno.h>                /* errno */
  37 #include <fcntl.h>
  38 #include <mk/defs.h>
  39 #include <mksh/dosys.h>           /* redirect_io() */
  40 #include <mksh/macro.h>           /* expand_value() */
  41 #include <mksh/misc.h>            /* getmem() */
  42 #include <sys/signal.h>
  43 #include <sys/stat.h>
  44 #include <sys/types.h>
  45 #include <sys/utsname.h>
  46 #include <sys/wait.h>
  47 #include <unistd.h>
  48 #include <netdb.h>
  49 #include <libintl.h>
  50 
  51 
  52 
  53 /*
  54  * Defined macros
  55  */
  56 #define MAXRULES                100
  57 
  58 /*
  59  * This const should be in avo_dms/include/AvoDmakeCommand.h
  60  */
  61 const int local_host_mask = 0x20;
  62 
  63 
  64 /*
  65  * typedefs & structs
  66  */
  67 
  68 
  69 /*


 115         int                     cmd_options = 0;
 116         char                    *commands[MAXRULES + 5];
 117         char                    *cp;
 118         Name                    dmake_name;
 119         Name                    dmake_value;
 120         int                     ignore;
 121         Name                    make_machines_name;
 122         char                    **p;
 123         Property                prop;
 124         Doname                  result = build_ok;
 125         Cmd_line                rule;
 126         Boolean                 silent_flag;
 127         Name                    target = line->body.line.target;
 128         Boolean                 wrote_state_file = false;
 129 
 130         if ((pmake_max_jobs == 0) &&
 131             (dmake_mode_type == parallel_mode)) {
 132                 if (local_host[0] == '\0') {
 133                         (void) gethostname(local_host, MAXNAMELEN);
 134                 }
 135                 MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
 136                 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 137                 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 138                     ((dmake_value = prop->body.macro.value) != NULL)) {
 139                         pmake_max_jobs = atoi(dmake_value->string_mb);
 140                         if (pmake_max_jobs <= 0) {
 141                                 warning(gettext("DMAKE_MAX_JOBS cannot be less than or equal to zero."));
 142                                 warning(gettext("setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
 143                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 144                         }
 145                 } else {
 146                         /*
 147                          * For backwards compatibility w/ PMake 1.x, when
 148                          * DMake 2.x is being run in parallel mode, DMake
 149                          * should parse the PMake startup file
 150                          * $(HOME)/.make.machines to get the pmake_max_jobs.
 151                          */
 152                         MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
 153                         dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
 154                         if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
 155                             ((dmake_value = prop->body.macro.value) != NULL)) {
 156                                 make_machines_name = dmake_value;
 157                         } else {
 158                                 make_machines_name = NULL;
 159                         }
 160                         if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
 161                                 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
 162                         }
 163                 }
 164         }
 165 
 166         if ((dmake_mode_type == serial_mode) ||
 167             ((dmake_mode_type == parallel_mode) && (waitflg))) {
 168                 return (execute_serial(line));
 169         }
 170 
 171         {
 172                 p = commands;


 306  *      ftok(), shmget(), shmat(), shmdt(), shmctl()
 307  *      sem_init(), sem_trywait(), sem_post(), sem_destroy()
 308  *      creat(), close(), unlink()
 309  *      getenv(), putenv()
 310  *
 311  *  Static variables:
 312  *      m2_file         - tmp file name to create ipc key for shared memory
 313  *      m2_shm_id       - shared memory id
 314  *      m2_shm_sem      - shared memory semaphore
 315  */
 316 
 317 static char     m2_file[MAXPATHLEN];
 318 static int      m2_shm_id = -1;
 319 static sem_t*   m2_shm_sem = 0;
 320 
 321 static int
 322 m2_init() {
 323         char    *var;
 324         key_t   key;
 325 
 326         if ((var = getenv("__DMAKE_M2_FILE__")) == 0) {
 327                 /* compose tmp file name */
 328                 sprintf(m2_file, "%s/dmake.m2.%d.XXXXXX", tmpdir, getpid());
 329 
 330                 /* create tmp file */
 331                 int fd = mkstemp(m2_file);
 332                 if (fd < 0) {
 333                         return -1;
 334                 } else {
 335                         close(fd);
 336                 }
 337         } else {
 338                 /* using existing semaphore */
 339                 strcpy(m2_file, var);
 340         }
 341 
 342         /* combine IPC key */
 343         if ((key = ftok(m2_file, 38)) == (key_t) -1) {
 344                 return -1;
 345         }
 346 
 347         /* create shared memory */
 348         if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {


 350         }
 351 
 352         /* attach shared memory */
 353         if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
 354                 return -1;
 355         }
 356 
 357         /* root process */
 358         if (var == 0) {
 359                 /* initialize semaphore */
 360                 if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
 361                         return -1;
 362                 }
 363 
 364                 /* alloc memory for env variable */
 365                 if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
 366                         return -1;
 367                 }
 368 
 369                 /* put key to env */
 370                 sprintf(var, "__DMAKE_M2_FILE__=%s", m2_file);
 371                 if (putenv(var)) {
 372                         return -1;
 373                 }
 374         }
 375         return 0;
 376 }
 377 
 378 static void
 379 m2_fini() {
 380         if (m2_shm_id >= 0) {
 381                 struct shmid_ds stat;
 382 
 383                 /* determine the number of attached processes */
 384                 if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
 385                         if (stat.shm_nattch <= 1) {
 386                                 /* destroy semaphore */
 387                                 if (m2_shm_sem != 0) {
 388                                         (void) sem_destroy(m2_shm_sem);
 389                                 }
 390 


 465  *
 466  *  Description:
 467  *      Prints warning message, cleans up job adjust data, and disables job adjustment
 468  *
 469  *  Environment:
 470  *      DMAKE_ADJUST_MAX_JOBS
 471  *
 472  *  External functions:
 473  *      putenv()
 474  *
 475  *  Static variables:
 476  *      job_adjust_mode Current job adjust mode
 477  */
 478 static void
 479 job_adjust_error() {
 480         if (job_adjust_mode != ADJUST_NONE) {
 481                 /* cleanup internals */
 482                 job_adjust_fini();
 483 
 484                 /* warning message for the user */
 485                 warning(gettext("Encountered max jobs auto adjustment error - disabling auto adjustment."));
 486 
 487                 /* switch off job adjustment for the children */
 488                 putenv(strdup("DMAKE_ADJUST_MAX_JOBS=NO"));
 489 
 490                 /* and for this dmake */
 491                 job_adjust_mode = ADJUST_NONE;
 492         }
 493 }
 494 
 495 /*
 496  *  void job_adjust_init()
 497  *
 498  *  Description:
 499  *      Parses DMAKE_ADJUST_MAX_JOBS env variable
 500  *      and performs appropriate initializations.
 501  *
 502  *  Environment:
 503  *      DMAKE_ADJUST_MAX_JOBS
 504  *        DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment
 505  *        DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode
 506  *        other                         - M1 adjust mode
 507  *
 508  *  External functions:
 509  *      getenv()
 510  *
 511  *  Static variables:
 512  *      job_adjust_mode Current job adjust mode
 513  */
 514 static void
 515 job_adjust_init() {
 516         if (job_adjust_mode == ADJUST_UNKNOWN) {
 517                 /* default mode */
 518                 job_adjust_mode = ADJUST_M1;
 519 
 520                 /* determine adjust mode */
 521                 if (char *var = getenv("DMAKE_ADJUST_MAX_JOBS")) {
 522                         if (strcasecmp(var, "NO") == 0) {
 523                                 job_adjust_mode = ADJUST_NONE;
 524                         } else if (strcasecmp(var, "M2") == 0) {
 525                                 job_adjust_mode = ADJUST_M2;
 526                         }
 527                 }
 528 
 529                 /* M2 specific initialization */
 530                 if (job_adjust_mode == ADJUST_M2) {
 531                         if (m2_init()) {
 532                                 job_adjust_error();
 533                         }
 534                 }
 535         }
 536 }
 537 
 538 #endif /* MAXJOBS_ADJUST_RFE4694000 */
 539 
 540 /*
 541  *      distribute_process(char **commands, Property line)
 542  *
 543  *      Parameters:
 544  *              commands        argv vector of commands to execute


 605                                 finish_children(true);
 606                         }
 607                 }
 608                 break;
 609         default:
 610                 while (parallel_process_cnt >= pmake_max_jobs) {
 611                         await_parallel(false);
 612                         finish_children(true);
 613                 }
 614         }
 615 #endif /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
 616         setvar_envvar();
 617         /*
 618          * Tell the user what DMake is doing.
 619          */
 620         if (!silent && output_mode != txt2_mode) {
 621                 /*
 622                  * Print local_host --> x job(s).
 623                  */
 624                 (void) fprintf(stdout,
 625                                gettext("%s --> %d %s\n"),
 626                                local_host,
 627                                parallel_process_cnt + 1,
 628                                (parallel_process_cnt == 0) ? gettext("job") : gettext("jobs"));
 629 
 630                 /* Print command line(s). */
 631                 tmp_index = 0;
 632                 while (commands[tmp_index] != NULL) {
 633                     /* No @ char. */
 634                     /* XXX - need to add [2] when + prefix is added */
 635                     if ((commands[tmp_index][0] != (int) at_char) &&
 636                         (commands[tmp_index][1] != (int) at_char)) {
 637                         tmp_index_str_ptr = commands[tmp_index];
 638                         if (*tmp_index_str_ptr == (int) hyphen_char) {
 639                                 tmp_index_str_ptr++;
 640                         }
 641                         (void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
 642                     }
 643                     tmp_index++;
 644                 }
 645                 (void) fflush(stdout);
 646         }
 647 
 648         (void) sprintf(mbstring,
 649                         "%s/dmake.stdout.%d.%d.XXXXXX",
 650                         tmpdir,
 651                         getpid(),
 652                         file_number++);
 653 
 654         mktemp(mbstring);
 655 
 656         stdout_file = strdup(mbstring);
 657         stderr_file = NULL;
 658 
 659         if (!out_err_same) {
 660                 (void) sprintf(mbstring,
 661                                 "%s/dmake.stderr.%d.%d.XXXXXX",
 662                                 tmpdir,
 663                                 getpid(),
 664                                 file_number++);
 665 
 666                 mktemp(mbstring);
 667 
 668                 stderr_file = strdup(mbstring);
 669         }
 670 
 671         process_running = run_rule_commands(local_host, commands);
 672 
 673         return build_running;
 674 }
 675 
 676 /*
 677  *      doname_parallel(target, do_get, implicit)
 678  *
 679  *      Processes the given target and finishes up any parallel
 680  *      processes left running.
 681  *


 918                                                        rp->implicit);
 919                                         quiescent = false;
 920                                         delete_running_struct(rp);
 921                                         goto start_loop_3;
 922                                 } else {
 923                                         subtree_target = rp_prev;
 924                                         rp_prev = &rp->next;
 925                                 }
 926                         } else {
 927                                 rp_prev = &rp->next;
 928                         }
 929                 }
 930         }
 931         /*
 932          * If still nothing found to build, we either have a deadlock
 933          * or a subtree with a dependency conflict with something waiting
 934          * to build.
 935          */
 936         if (quiescent) {
 937                 if (subtree_target == NULL) {
 938                         fatal(gettext("Internal error: deadlock detected in process_next"));
 939                 } else {
 940                         rp = *subtree_target;
 941                         if (debug_level > 0) {
 942                                 warning(gettext("Conditional macro conflict encountered for %s between %s and %s"),
 943                                         subtree_conflict2->string_mb,
 944                                         rp->target->string_mb,
 945                                         subtree_conflict->string_mb);
 946                         }
 947                         *subtree_target = (*subtree_target)->next;
 948                         if (rp->next == NULL) {
 949                                 running_tail = subtree_target;
 950                         }
 951                         recursion_level = rp->recursion_level;
 952                         doname_subtree(rp->target, rp->do_get, rp->implicit);
 953                         delete_running_struct(rp);
 954                 }
 955         }
 956 }
 957 
 958 /*
 959  *      set_conditionals(cnt, targets)
 960  *
 961  *      Sets the conditional macros for the targets given in the array of
 962  *      targets.  The old macro values are returned in an array of


1128                 if (!nohang) {
1129                         (void) alarm(0);
1130                 }
1131                 if (pid <= 0) {
1132                         if (waiterr == EINTR) {
1133                                 if (waitflg) {
1134                                         continue;
1135                                 } else {
1136                                         return;
1137                                 }
1138                         } else {
1139                                 return;
1140                         }
1141                 }
1142                 for (rp = running_list;
1143                      (rp != NULL) && (rp->pid != pid);
1144                      rp = rp->next) {
1145                         ;
1146                 }
1147                 if (rp == NULL) {
1148                         fatal(gettext("Internal error: returned child pid not in running_list"));
1149                 } else {
1150                         rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
1151                 }
1152                 nohang = true;
1153                 parallel_process_cnt--;
1154 
1155 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
1156                 if (job_adjust_mode == ADJUST_M2) {
1157                         if (m2_release_job()) {
1158                                 job_adjust_error();
1159                         }
1160                 }
1161 #endif
1162         }
1163 }
1164 
1165 /*
1166  *      finish_children(docheck)
1167  *
1168  *      Finishes the processing for all targets which were running


1202                  * Read the auto dependency stuff, handle a failed build,
1203                  * update the target, then finish the doname process for
1204                  * that target.
1205                  */
1206                 if (rp->state == build_ok || rp->state == build_failed) {
1207                         *rp_prev = rp->next;
1208                         if (rp->next == NULL) {
1209                                 running_tail = rp_prev;
1210                         }
1211                         if ((line2 = rp->command) == NULL) {
1212                                 line2 = get_prop(rp->target->prop, line_prop);
1213                         }
1214 
1215 
1216                         /*
1217                          * Check if there were any job output
1218                          * from the parallel build.
1219                          */
1220                         if (rp->stdout_file != NULL) {
1221                                 if (stat(rp->stdout_file, &out_buf) < 0) {
1222                                         fatal(gettext("stat of %s failed: %s"),
1223                                             rp->stdout_file,
1224                                             errmsg(errno));
1225                                 }
1226 
1227                                 if ((line2 != NULL) &&
1228                                     (out_buf.st_size > 0)) {
1229                                         cmds_length = 0;
1230                                         for (rule = line2->body.line.command_used,
1231                                                  silent_flag = silent;
1232                                              rule != NULL;
1233                                              rule = rule->next) {
1234                                                 cmds_length += rule->command_line->hash.length + 1;
1235                                                 silent_flag = BOOLEAN(silent_flag || rule->silent);
1236                                         }
1237                                         if (out_buf.st_size != cmds_length || silent_flag ||
1238                                             output_mode == txt2_mode) {
1239                                                 dump_out_file(rp->stdout_file, false);
1240                                         }
1241                                 }
1242                                 (void) unlink(rp->stdout_file);
1243                                 retmem_mb(rp->stdout_file);
1244                                 rp->stdout_file = NULL;
1245                         }
1246 
1247                         if (!out_err_same && (rp->stderr_file != NULL)) {
1248                                 if (stat(rp->stderr_file, &out_buf) < 0) {
1249                                         fatal(gettext("stat of %s failed: %s"),
1250                                             rp->stderr_file,
1251                                             errmsg(errno));
1252                                 }
1253                                 if ((line2 != NULL) &&
1254                                     (out_buf.st_size > 0)) {
1255                                         dump_out_file(rp->stderr_file, true);
1256                                 }
1257                                 (void) unlink(rp->stderr_file);
1258                                 retmem_mb(rp->stderr_file);
1259                                 rp->stderr_file = NULL;
1260                         }
1261                         
1262                         check_state(rp->temp_file);
1263                         if (rp->temp_file != NULL) {
1264                                 free_name(rp->temp_file);
1265                         }
1266                         rp->temp_file = NULL;
1267                         if (rp->state == build_failed) {
1268                                 line = get_prop(rp->target->prop, line_prop);
1269                                 if (line != NULL) {
1270                                         line->body.line.command_used = NULL;
1271                                 }
1272                                 if (continue_after_error ||
1273                                     fatal_in_progress ||
1274                                     !docheck) {
1275                                         warning(gettext("Command failed for target `%s'"),
1276                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1277                                         build_failed_seen = true;
1278                                 } else {
1279                                         /*
1280                                          * XXX??? - DMake needs to exit(),
1281                                          * but shouldn't call fatal().
1282                                          */
1283 #ifdef PRINT_EXIT_STATUS
1284                                         warning("I'm in finish_children. rp->state == build_failed.");
1285 #endif
1286 
1287                                         fatal(gettext("Command failed for target `%s'"),
1288                                                 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1289                                 }
1290                         }
1291                         if (!docheck) {
1292                                 delete_running_struct(rp);
1293                                 rp = *rp_prev;
1294                                 if (rp == NULL) {
1295                                         break;
1296                                 } else {
1297                                         goto bypass_for_loop_inc_4;
1298                                 }
1299                         }
1300                         update_target(get_prop(rp->target->prop, line_prop),
1301                                       rp->state);
1302                         finish_doname(rp);
1303                         delete_running_struct(rp);
1304                         rp = *rp_prev;
1305                         if (rp == NULL) {
1306                                 break;
1307                         } else {


1315 
1316 /*
1317  *      dump_out_file(filename, err)
1318  *
1319  *      Write the contents of the file to stdout, then unlink the file.
1320  *
1321  *      Parameters:
1322  *              filename        Name of temp file containing output
1323  *
1324  *      Global variables used:
1325  */
1326 static void
1327 dump_out_file(char *filename, Boolean err)
1328 {
1329         int             chars_read;
1330         char            copybuf[BUFSIZ];
1331         int             fd;
1332         int             out_fd = (err ? 2 : 1);
1333 
1334         if ((fd = open(filename, O_RDONLY)) < 0) {
1335                 fatal(gettext("open failed for output file %s: %s"),
1336                       filename,
1337                       errmsg(errno));
1338         }
1339         if (!silent && output_mode != txt2_mode) {
1340                 (void) fprintf(err ? stderr : stdout,
1341                                err ?
1342                                 gettext("%s --> Job errors\n") :
1343                                 gettext("%s --> Job output\n"),
1344                                local_host);
1345                 (void) fflush(err ? stderr : stdout);
1346         }
1347         for (chars_read = read(fd, copybuf, BUFSIZ);
1348              chars_read > 0;
1349              chars_read = read(fd, copybuf, BUFSIZ)) {
1350                 /*
1351                  * Read buffers from the source file until end or error.
1352                  */
1353                 if (write(out_fd, copybuf, chars_read) < 0) {
1354                         fatal(gettext("write failed for output file %s: %s"),
1355                               filename,
1356                               errmsg(errno));
1357                 }
1358         }
1359         (void) close(fd);
1360         (void) unlink(filename);
1361 }
1362 
1363 /*
1364  *      finish_doname(rp)
1365  *
1366  *      Completes the processing for a target which was left running.
1367  *
1368  *      Parameters:
1369  *              rp              Running list entry for target
1370  *
1371  *      Global variables used:
1372  *              debug_level     Debug flag
1373  *              recursion_level Indentation for debug output
1374  */
1375 static void
1376 finish_doname(Running rp)
1377 {
1378         int             auto_count = rp->auto_count;
1379         Name            *automatics = rp->automatics;
1380         Doname          result = rp->state;
1381         Name            target = rp->target;
1382         Name            true_target = rp->true_target;
1383         Property        *conditionals;
1384 
1385         recursion_level = rp->recursion_level;
1386         if (result == build_ok) {
1387                 if (true_target == NULL) {
1388                         (void) printf("Target = %s\n", target->string_mb);
1389                         (void) printf(" State = %d\n", result);
1390                         fatal("Internal error: NULL true_target in finish_doname");
1391                 }
1392                 /* If all went OK, set a nice timestamp */
1393                 if (true_target->stat.time == file_doesnt_exist) {
1394                         true_target->stat.time = file_max_time;
1395                 }
1396         }
1397         target->state = result;
1398         if (target->is_member) {
1399                 Property member;
1400 
1401                 /* Propagate the timestamp from the member file to the member */
1402                 if ((target->stat.time != file_max_time) &&
1403                     ((member = get_prop(target->prop, member_prop)) != NULL) &&
1404                     (exists(member->body.member.member) > file_doesnt_exist)) {
1405                         target->stat.time =
1406 /*
1407                           exists(member->body.member.member);
1408  */
1409                           member->body.member.member->stat.time;
1410                 }
1411         }
1412         /*
1413          * Check if we found any new auto dependencies when we
1414          * built the target.
1415          */
1416         if ((result == build_ok) && check_auto_dependencies(target,
1417                                                             auto_count,
1418                                                             automatics)) {
1419                 if (debug_level > 0) {
1420                         (void) printf(gettext("%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
1421                                       recursion_level,
1422                                       "",
1423                                       true_target->string_mb);
1424                 }
1425                 target->rechecking_target = true;
1426                 target->state = build_running;
1427 
1428                 /* [tolik, Tue Mar 25 1997]
1429                  * Fix for bug 4038824:
1430                  *       command line options set by conditional macros get dropped
1431                  * rp->conditional_cnt and rp->conditional_targets must be copied
1432                  * to new 'rp' during add_pending(). Set_conditionals() stores
1433                  * rp->conditional_targets to the global variable 'conditional_targets'
1434                  * Add_pending() will use this variable to set up 'rp'.
1435                  */
1436                 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
1437                 add_pending(target,
1438                             recursion_level,
1439                             rp->do_get,
1440                             rp->implicit,


1768 
1769 /*
1770  * This function replaces the makesh binary.
1771  */
1772  
1773 
1774 static pid_t
1775 run_rule_commands(char *host, char **commands)
1776 {
1777         Boolean         always_exec;
1778         Name            command;
1779         Boolean         ignore;
1780         int             length;
1781         Doname          result;
1782         Boolean         silent_flag;
1783         wchar_t         *tmp_wcs_buffer;
1784 
1785         childPid = fork();
1786         switch (childPid) {
1787         case -1:        /* Error */
1788                 fatal(gettext("Could not fork child process for dmake job: %s"),
1789                       errmsg(errno));
1790                 break;
1791         case 0:         /* Child */
1792                 /* To control the processed targets list is not the child's business */
1793                 running_list = NULL;
1794                 if(out_err_same) {
1795                         redirect_io(stdout_file, (char*)NULL);
1796                 } else {
1797                         redirect_io(stdout_file, stderr_file);
1798                 }
1799                 for (commands = commands;
1800                      (*commands != (char *)NULL);
1801                      commands++) {
1802                         silent_flag = silent;
1803                         ignore = false;
1804                         always_exec = false;
1805                         while ((**commands == (int) at_char) ||
1806                                (**commands == (int) hyphen_char) ||
1807                                (**commands == (int) plus_char)) {
1808                                 if (**commands == (int) at_char) {


1821                                 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
1822                                 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
1823                                 retmem(tmp_wcs_buffer);
1824                         } else {
1825                                 MBSTOWCS(wcs_buffer, *commands);
1826                                 command = GETNAME(wcs_buffer, FIND_LENGTH);
1827                         }
1828                         if ((command->hash.length > 0) &&
1829                             !silent_flag) {
1830                                 (void) printf("%s\n", command->string_mb);
1831                         }
1832                         result = dosys(command,
1833                                        ignore,
1834                                        false,
1835                                        false, /* bugs #4085164 & #4990057 */
1836                                        /* BOOLEAN(silent_flag && ignore), */
1837                                        always_exec, 
1838                                        (Name) NULL);
1839                         if (result == build_failed) {
1840                                 if (silent_flag) {
1841                                         (void) printf(gettext("The following command caused the error:\n%s\n"), command->string_mb);
1842                                 }
1843                                 if (!ignore) {
1844                                         _exit(1);
1845                                 }
1846                         }
1847                 }
1848                 _exit(0);
1849                 break;
1850         default:
1851                 break;
1852         }
1853         return childPid;
1854 }
1855 
1856 static void
1857 maybe_reread_make_state(void)
1858 {
1859         /* Copying dosys()... */
1860         if (report_dependencies_level == 0) {
1861                 make_state->stat.time = file_no_time;