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 /*
  27  *      misc.cc
  28  *
  29  *      This file contains various unclassified routines. Some main groups:
  30  *              getname
  31  *              Memory allocation
  32  *              String handling
  33  *              Property handling
  34  *              Error message handling
  35  *              Make internal state dumping
  36  *              main routine support
  37  */
  38 
  39 /*
  40  * Included files
  41  */
  42 #include <errno.h>
  43 #include <mk/defs.h>
  44 #include <mksh/macro.h>           /* SETVAR() */
  45 #include <mksh/misc.h>            /* enable_interrupt() */
  46 #include <stdarg.h>               /* va_list, va_start(), va_end() */
  47 #include <vroot/report.h> /* SUNPRO_DEPENDENCIES */
  48 
  49 
  50 #ifdef TEAMWARE_MAKE_CMN
  51 #define MAXJOBS_ADJUST_RFE4694000
  52 
  53 #ifdef MAXJOBS_ADJUST_RFE4694000
  54 extern void job_adjust_fini();
  55 #endif /* MAXJOBS_ADJUST_RFE4694000 */
  56 #endif /* TEAMWARE_MAKE_CMN */
  57 
  58 
  59 /*
  60  * Defined macros
  61  */
  62 
  63 /*
  64  * typedefs & structs
  65  */
  66 
  67 /*
  68  * Static variables
  69  */
  70 
  71 /*
  72  * File table of contents
  73  */
  74 static  void            print_rule(register Name target);
  75 static  void            print_target_n_deps(register Name target);
  76 
  77 /*****************************************
  78  *
  79  *      getname
  80  */
  81 
  82 /*****************************************
  83  *
  84  *      Memory allocation
  85  */
  86 
  87 /*
  88  *      free_chain()
  89  *
  90  *      frees a chain of Name_vector's
  91  *
  92  *      Parameters:
  93  *              ptr             Pointer to the first element in the chain
  94  *                              to be freed.
  95  *
  96  *      Global variables used:
  97  */
  98 void 
  99 free_chain(Name_vector ptr)
 100 {
 101         if (ptr != NULL) {
 102                 if (ptr->next != NULL) {
 103                         free_chain(ptr->next);
 104                 }
 105                 free((char *) ptr);
 106         }
 107 }
 108 
 109 /*****************************************
 110  *
 111  *      String manipulation
 112  */
 113 
 114 /*****************************************
 115  *
 116  *      Nameblock property handling
 117  */
 118 
 119 /*****************************************
 120  *
 121  *      Error message handling
 122  */
 123 
 124 /*
 125  *      fatal(format, args...)
 126  *
 127  *      Print a message and die
 128  *
 129  *      Parameters:
 130  *              format          printf type format string
 131  *              args            Arguments to match the format
 132  *
 133  *      Global variables used:
 134  *              fatal_in_progress Indicates if this is a recursive call
 135  *              parallel_process_cnt Do we need to wait for anything?
 136  *              report_pwd      Should we report the current path?
 137  */
 138 /*VARARGS*/
 139 void
 140 fatal(char * message, ...)
 141 {
 142         va_list args;
 143 
 144         va_start(args, message);
 145         (void) fflush(stdout);
 146 #ifdef DISTRIBUTED
 147         (void) fprintf(stderr, catgets(catd, 1, 262, "dmake: Fatal error: "));
 148 #else
 149         (void) fprintf(stderr, catgets(catd, 1, 263, "make: Fatal error: "));
 150 #endif
 151         (void) vfprintf(stderr, message, args);
 152         (void) fprintf(stderr, "\n");
 153         va_end(args);
 154         if (report_pwd) {
 155                 (void) fprintf(stderr,
 156                                catgets(catd, 1, 156, "Current working directory %s\n"),
 157                                get_current_path());
 158         }
 159         (void) fflush(stderr);
 160         if (fatal_in_progress) {
 161                 exit_status = 1;
 162                 exit(1);
 163         }
 164         fatal_in_progress = true;
 165 #ifdef TEAMWARE_MAKE_CMN
 166         /* Let all parallel children finish */
 167         if ((dmake_mode_type == parallel_mode) &&
 168             (parallel_process_cnt > 0)) {
 169                 (void) fprintf(stderr,
 170                                catgets(catd, 1, 157, "Waiting for %d %s to finish\n"),
 171                                parallel_process_cnt,
 172                                parallel_process_cnt == 1 ?
 173                                catgets(catd, 1, 158, "job") : catgets(catd, 1, 159, "jobs"));
 174                 (void) fflush(stderr);
 175         }
 176 
 177         while (parallel_process_cnt > 0) {
 178 #ifdef DISTRIBUTED
 179                 if (dmake_mode_type == distributed_mode) {
 180                         (void) await_dist(false);
 181                 } else {
 182                         await_parallel(true);
 183                 }
 184 #else
 185                 await_parallel(true);
 186 #endif
 187                 finish_children(false);
 188         }
 189 #endif
 190 
 191 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
 192         job_adjust_fini();
 193 #endif
 194 
 195         exit_status = 1;
 196         exit(1);
 197 }
 198 
 199 /*
 200  *      warning(format, args...)
 201  *
 202  *      Print a message and continue.
 203  *
 204  *      Parameters:
 205  *              format          printf type format string
 206  *              args            Arguments to match the format
 207  *
 208  *      Global variables used:
 209  *              report_pwd      Should we report the current path?
 210  */
 211 /*VARARGS*/
 212 void
 213 warning(char * message, ...)
 214 {
 215         va_list args;
 216 
 217         va_start(args, message);
 218         (void) fflush(stdout);
 219 #ifdef DISTRIBUTED
 220         (void) fprintf(stderr, catgets(catd, 1, 264, "dmake: Warning: "));
 221 #else
 222         (void) fprintf(stderr, catgets(catd, 1, 265, "make: Warning: "));
 223 #endif
 224         (void) vfprintf(stderr, message, args);
 225         (void) fprintf(stderr, "\n");
 226         va_end(args);
 227         if (report_pwd) {
 228                 (void) fprintf(stderr,
 229                                catgets(catd, 1, 161, "Current working directory %s\n"),
 230                                get_current_path());
 231         }
 232         (void) fflush(stderr);
 233 }
 234 
 235 /*
 236  *      time_to_string(time)
 237  *
 238  *      Take a numeric time value and produce
 239  *      a proper string representation.
 240  *
 241  *      Return value:
 242  *                              The string representation of the time
 243  *
 244  *      Parameters:
 245  *              time            The time we need to translate
 246  *
 247  *      Global variables used:
 248  */
 249 char *
 250 time_to_string(const timestruc_t &time)
 251 {
 252         struct tm               *tm;
 253         char                    buf[128];
 254 
 255         if (time == file_doesnt_exist) {
 256                 return catgets(catd, 1, 163, "File does not exist");
 257         }
 258         if (time == file_max_time) {
 259                 return catgets(catd, 1, 164, "Younger than any file");
 260         }
 261         tm = localtime(&time.tv_sec);
 262         strftime(buf, sizeof (buf), NOCATGETS("%c %Z"), tm);
 263         buf[127] = (int) nul_char;
 264         return strdup(buf);
 265 }
 266 
 267 /*
 268  *      get_current_path()
 269  *
 270  *      Stuff current_path with the current path if it isnt there already.
 271  *
 272  *      Parameters:
 273  *
 274  *      Global variables used:
 275  */
 276 char *
 277 get_current_path(void)
 278 {
 279         char                    pwd[(MAXPATHLEN * MB_LEN_MAX)];
 280         static char             *current_path;
 281 
 282         if (current_path == NULL) {
 283                 getcwd(pwd, sizeof(pwd));
 284                 if (pwd[0] == (int) nul_char) {
 285                         pwd[0] = (int) slash_char;
 286                         pwd[1] = (int) nul_char;
 287 #ifdef DISTRIBUTED
 288                         current_path = strdup(pwd);
 289                 } else if (IS_EQUALN(pwd, NOCATGETS("/tmp_mnt"), 8)) {
 290                         current_path = strdup(pwd + 8);
 291                 } else {
 292                         current_path = strdup(pwd);
 293                 }
 294 #else
 295                 }
 296                 current_path = strdup(pwd);
 297 #endif
 298         }
 299         return current_path;
 300 }
 301 
 302 /*****************************************
 303  *
 304  *      Make internal state dumping
 305  *
 306  *      This is a set  of routines for dumping the internal make state
 307  *      Used for the -p option
 308  */
 309 
 310 /*
 311  *      dump_make_state()
 312  *
 313  *      Dump make's internal state to stdout
 314  *
 315  *      Parameters:
 316  *
 317  *      Global variables used:
 318  *              svr4                    Was ".SVR4" seen in makefile?
 319  *              svr4_name               The Name ".SVR4", printed
 320  *              posix                   Was ".POSIX" seen in makefile?
 321  *              posix_name              The Name ".POSIX", printed
 322  *              default_rule            Points to the .DEFAULT rule
 323  *              default_rule_name       The Name ".DEFAULT", printed
 324  *              default_target_to_build The first target to print
 325  *              dot_keep_state          The Name ".KEEP_STATE", printed
 326  *              dot_keep_state_file     The Name ".KEEP_STATE_FILE", printed
 327  *              hashtab                 The make hash table for Name blocks
 328  *              ignore_errors           Was ".IGNORE" seen in makefile?
 329  *              ignore_name             The Name ".IGNORE", printed
 330  *              keep_state              Was ".KEEP_STATE" seen in makefile?
 331  *              percent_list            The list of % rules
 332  *              precious                The Name ".PRECIOUS", printed
 333  *              sccs_get_name           The Name ".SCCS_GET", printed
 334  *              sccs_get_posix_name     The Name ".SCCS_GET_POSIX", printed
 335  *              get_name                The Name ".GET", printed
 336  *              get_posix_name          The Name ".GET_POSIX", printed
 337  *              sccs_get_rule           Points to the ".SCCS_GET" rule
 338  *              silent                  Was ".SILENT" seen in makefile?
 339  *              silent_name             The Name ".SILENT", printed
 340  *              suffixes                The suffix list from ".SUFFIXES"
 341  *              suffixes_name           The Name ".SUFFIX", printed
 342  */
 343 void
 344 dump_make_state(void)
 345 {
 346         Name_set::iterator      p, e;
 347         register Property       prop;
 348         register Dependency     dep;
 349         register Cmd_line       rule;
 350         Percent                 percent, percent_depe;
 351 
 352         /* Default target */
 353         if (default_target_to_build != NULL) {
 354                 print_rule(default_target_to_build);
 355         }
 356         (void) printf("\n");
 357 
 358         /* .POSIX */
 359         if (posix) {
 360                 (void) printf("%s:\n", posix_name->string_mb);
 361         }
 362 
 363         /* .DEFAULT */
 364         if (default_rule != NULL) {
 365                 (void) printf("%s:\n", default_rule_name->string_mb);
 366                 for (rule = default_rule; rule != NULL; rule = rule->next) {
 367                         (void) printf("\t%s\n", rule->command_line->string_mb);
 368                 }
 369         }
 370 
 371         /* .IGNORE */
 372         if (ignore_errors) {
 373                 (void) printf("%s:\n", ignore_name->string_mb);
 374         }
 375 
 376         /* .KEEP_STATE: */
 377         if (keep_state) {
 378                 (void) printf("%s:\n\n", dot_keep_state->string_mb);
 379         }
 380 
 381         /* .PRECIOUS */
 382         (void) printf("%s:", precious->string_mb);
 383         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 384                         if ((p->stat.is_precious) || (all_precious)) {
 385                                 (void) printf(" %s", p->string_mb);
 386                         }
 387         }
 388         (void) printf("\n");
 389 
 390         /* .SCCS_GET */
 391         if (sccs_get_rule != NULL) {
 392                 (void) printf("%s:\n", sccs_get_name->string_mb);
 393                 for (rule = sccs_get_rule; rule != NULL; rule = rule->next) {
 394                         (void) printf("\t%s\n", rule->command_line->string_mb);
 395                 }
 396         }
 397 
 398         /* .SILENT */
 399         if (silent) {
 400                 (void) printf("%s:\n", silent_name->string_mb);
 401         }
 402 
 403         /* .SUFFIXES: */
 404         (void) printf("%s:", suffixes_name->string_mb);
 405         for (dep = suffixes; dep != NULL; dep = dep->next) {
 406                 (void) printf(" %s", dep->name->string_mb);
 407                 build_suffix_list(dep->name);
 408         }
 409         (void) printf("\n\n");
 410 
 411         /* % rules */
 412         for (percent = percent_list;
 413              percent != NULL;
 414              percent = percent->next) {
 415                 (void) printf("%s:",
 416                               percent->name->string_mb);
 417                 
 418                 for (percent_depe = percent->dependencies;
 419                      percent_depe != NULL;
 420                      percent_depe = percent_depe->next) {
 421                         (void) printf(" %s", percent_depe->name->string_mb);
 422                 }
 423                 
 424                 (void) printf("\n");
 425 
 426                 for (rule = percent->command_template;
 427                      rule != NULL;
 428                      rule = rule->next) {
 429                         (void) printf("\t%s\n", rule->command_line->string_mb);
 430                 }
 431         }
 432 
 433         /* Suffix rules */
 434         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 435                         Wstring wcb(p);
 436                         if (wcb.get_string()[0] == (int) period_char) {
 437                                 print_rule(p);
 438                         }
 439         }
 440 
 441         /* Macro assignments */
 442         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 443                         if (((prop = get_prop(p->prop, macro_prop)) != NULL) &&
 444                             (prop->body.macro.value != NULL)) {
 445                                 (void) printf("%s", p->string_mb);
 446                                 print_value(prop->body.macro.value,
 447                                             (Daemon) prop->body.macro.daemon);
 448                         }
 449         }
 450         (void) printf("\n");
 451 
 452         /* Conditional macro assignments */
 453         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 454                         for (prop = get_prop(p->prop, conditional_prop);
 455                              prop != NULL;
 456                              prop = get_prop(prop->next, conditional_prop)) {
 457                                 (void) printf("%s := %s",
 458                                               p->string_mb,
 459                                               prop->body.conditional.name->
 460                                               string_mb);
 461                                 if (prop->body.conditional.append) {
 462                                         printf(" +");
 463                                 }
 464                                 else {
 465                                         printf(" ");
 466                                 }
 467                                 print_value(prop->body.conditional.value,
 468                                             no_daemon);
 469                         }
 470         }
 471         (void) printf("\n");
 472 
 473         /* All other dependencies */
 474         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 475                         if (p->colons != no_colon) {
 476                                 print_rule(p);
 477                         }
 478         }
 479         (void) printf("\n");
 480 }
 481 
 482 /*
 483  *      print_rule(target)
 484  *
 485  *      Print the rule for one target
 486  *
 487  *      Parameters:
 488  *              target          Target we print rule for
 489  *
 490  *      Global variables used:
 491  */
 492 static void
 493 print_rule(register Name target)
 494 {
 495         register Cmd_line       rule;
 496         register Property       line;
 497         register Dependency     dependency;
 498 
 499         if (target->dependency_printed ||
 500             ((line = get_prop(target->prop, line_prop)) == NULL) ||
 501             ((line->body.line.command_template == NULL) &&
 502              (line->body.line.dependencies == NULL))) {
 503                 return;
 504         }
 505         target->dependency_printed = true;
 506 
 507         (void) printf("%s:", target->string_mb);
 508 
 509         for (dependency = line->body.line.dependencies;
 510              dependency != NULL;
 511              dependency = dependency->next) {
 512                 (void) printf(" %s", dependency->name->string_mb);
 513         }
 514 
 515         (void) printf("\n");
 516 
 517         for (rule = line->body.line.command_template;
 518              rule != NULL;
 519              rule = rule->next) {
 520                 (void) printf("\t%s\n", rule->command_line->string_mb);
 521         }
 522 }
 523 
 524 void
 525 dump_target_list(void)
 526 {
 527         Name_set::iterator      p, e;
 528         Wstring str;
 529 
 530         for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
 531                         str.init(p);
 532                         wchar_t * wcb = str.get_string();
 533                         if ((p->colons != no_colon) &&
 534                             ((wcb[0] != (int) period_char) ||
 535                              ((wcb[0] == (int) period_char) &&
 536                               (wschr(wcb, (int) slash_char))))) {
 537                                 print_target_n_deps(p);
 538                         }
 539         }
 540 }
 541 
 542 static void
 543 print_target_n_deps(register Name target)
 544 {
 545         register Cmd_line       rule;
 546         register Property       line;
 547         register Dependency     dependency;
 548 
 549         if (target->dependency_printed) {
 550                 return;
 551         }
 552         target->dependency_printed = true;
 553 
 554         (void) printf("%s\n", target->string_mb);
 555 
 556         if ((line = get_prop(target->prop, line_prop)) == NULL) {
 557                 return;
 558         }
 559         for (dependency = line->body.line.dependencies;
 560              dependency != NULL;
 561              dependency = dependency->next) {
 562                 if (!dependency->automatic) {
 563                         print_target_n_deps(dependency->name);
 564                 }
 565         }
 566 }
 567 
 568 /*****************************************
 569  *
 570  *      main() support
 571  */
 572 
 573 /*
 574  *      load_cached_names()
 575  *
 576  *      Load the vector of cached names
 577  *
 578  *      Parameters:
 579  *
 580  *      Global variables used:
 581  *              Many many pointers to Name blocks.
 582  */
 583 void
 584 load_cached_names(void)
 585 {
 586         char            *cp;
 587         Name            dollar;
 588 
 589         /* Load the cached_names struct */
 590         MBSTOWCS(wcs_buffer, NOCATGETS(".BUILT_LAST_MAKE_RUN"));
 591         built_last_make_run = GETNAME(wcs_buffer, FIND_LENGTH);
 592         MBSTOWCS(wcs_buffer, NOCATGETS("@"));
 593         c_at = GETNAME(wcs_buffer, FIND_LENGTH);
 594         MBSTOWCS(wcs_buffer, NOCATGETS(" *conditionals* "));
 595         conditionals = GETNAME(wcs_buffer, FIND_LENGTH);
 596         /*
 597          * A version of make was released with NSE 1.0 that used
 598          * VERSION-1.1 but this version is identical to VERSION-1.0.
 599          * The version mismatch code makes a special case for this
 600          * situation.  If the version number is changed from 1.0
 601          * it should go to 1.2.
 602          */
 603         MBSTOWCS(wcs_buffer, NOCATGETS("VERSION-1.0"));
 604         current_make_version = GETNAME(wcs_buffer, FIND_LENGTH);
 605         MBSTOWCS(wcs_buffer, NOCATGETS(".SVR4"));
 606         svr4_name = GETNAME(wcs_buffer, FIND_LENGTH);
 607         MBSTOWCS(wcs_buffer, NOCATGETS(".POSIX"));
 608         posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 609         MBSTOWCS(wcs_buffer, NOCATGETS(".DEFAULT"));
 610         default_rule_name = GETNAME(wcs_buffer, FIND_LENGTH);
 611 #ifdef NSE
 612         MBSTOWCS(wcs_buffer, NOCATGETS(".DERIVED_SRC"));
 613         derived_src= GETNAME(wcs_buffer, FIND_LENGTH);
 614 #endif
 615         MBSTOWCS(wcs_buffer, NOCATGETS("$"));
 616         dollar = GETNAME(wcs_buffer, FIND_LENGTH);
 617         MBSTOWCS(wcs_buffer, NOCATGETS(".DONE"));
 618         done = GETNAME(wcs_buffer, FIND_LENGTH);
 619         MBSTOWCS(wcs_buffer, NOCATGETS("."));
 620         dot = GETNAME(wcs_buffer, FIND_LENGTH);
 621         MBSTOWCS(wcs_buffer, NOCATGETS(".KEEP_STATE"));
 622         dot_keep_state = GETNAME(wcs_buffer, FIND_LENGTH);
 623         MBSTOWCS(wcs_buffer, NOCATGETS(".KEEP_STATE_FILE"));
 624         dot_keep_state_file = GETNAME(wcs_buffer, FIND_LENGTH);
 625         MBSTOWCS(wcs_buffer, NOCATGETS(""));
 626         empty_name = GETNAME(wcs_buffer, FIND_LENGTH);
 627         MBSTOWCS(wcs_buffer, NOCATGETS(" FORCE"));
 628         force = GETNAME(wcs_buffer, FIND_LENGTH);
 629         MBSTOWCS(wcs_buffer, NOCATGETS("HOST_ARCH"));
 630         host_arch = GETNAME(wcs_buffer, FIND_LENGTH);
 631         MBSTOWCS(wcs_buffer, NOCATGETS("HOST_MACH"));
 632         host_mach = GETNAME(wcs_buffer, FIND_LENGTH);
 633         MBSTOWCS(wcs_buffer, NOCATGETS(".IGNORE"));
 634         ignore_name = GETNAME(wcs_buffer, FIND_LENGTH);
 635         MBSTOWCS(wcs_buffer, NOCATGETS(".INIT"));
 636         init = GETNAME(wcs_buffer, FIND_LENGTH);
 637         MBSTOWCS(wcs_buffer, NOCATGETS(".LOCAL"));
 638         localhost_name = GETNAME(wcs_buffer, FIND_LENGTH);
 639         MBSTOWCS(wcs_buffer, NOCATGETS(".make.state"));
 640         make_state = GETNAME(wcs_buffer, FIND_LENGTH);
 641         MBSTOWCS(wcs_buffer, NOCATGETS("MAKEFLAGS"));
 642         makeflags = GETNAME(wcs_buffer, FIND_LENGTH);
 643         MBSTOWCS(wcs_buffer, NOCATGETS(".MAKE_VERSION"));
 644         make_version = GETNAME(wcs_buffer, FIND_LENGTH);
 645         MBSTOWCS(wcs_buffer, NOCATGETS(".NO_PARALLEL"));
 646         no_parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
 647         MBSTOWCS(wcs_buffer, NOCATGETS(".NOT_AUTO"));
 648         not_auto = GETNAME(wcs_buffer, FIND_LENGTH);
 649         MBSTOWCS(wcs_buffer, NOCATGETS(".PARALLEL"));
 650         parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
 651         MBSTOWCS(wcs_buffer, NOCATGETS("PATH"));
 652         path_name = GETNAME(wcs_buffer, FIND_LENGTH);
 653         MBSTOWCS(wcs_buffer, NOCATGETS("+"));
 654         plus = GETNAME(wcs_buffer, FIND_LENGTH);
 655         MBSTOWCS(wcs_buffer, NOCATGETS(".PRECIOUS"));
 656         precious = GETNAME(wcs_buffer, FIND_LENGTH);
 657         MBSTOWCS(wcs_buffer, NOCATGETS("?"));
 658         query = GETNAME(wcs_buffer, FIND_LENGTH);
 659         MBSTOWCS(wcs_buffer, NOCATGETS("^"));
 660         hat = GETNAME(wcs_buffer, FIND_LENGTH);
 661         MBSTOWCS(wcs_buffer, NOCATGETS(".RECURSIVE"));
 662         recursive_name = GETNAME(wcs_buffer, FIND_LENGTH);
 663         MBSTOWCS(wcs_buffer, NOCATGETS(".SCCS_GET"));
 664         sccs_get_name = GETNAME(wcs_buffer, FIND_LENGTH);
 665         MBSTOWCS(wcs_buffer, NOCATGETS(".SCCS_GET_POSIX"));
 666         sccs_get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 667         MBSTOWCS(wcs_buffer, NOCATGETS(".GET"));
 668         get_name = GETNAME(wcs_buffer, FIND_LENGTH);
 669         MBSTOWCS(wcs_buffer, NOCATGETS(".GET_POSIX"));
 670         get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
 671         MBSTOWCS(wcs_buffer, NOCATGETS("SHELL"));
 672         shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
 673         MBSTOWCS(wcs_buffer, NOCATGETS(".SILENT"));
 674         silent_name = GETNAME(wcs_buffer, FIND_LENGTH);
 675         MBSTOWCS(wcs_buffer, NOCATGETS(".SUFFIXES"));
 676         suffixes_name = GETNAME(wcs_buffer, FIND_LENGTH);
 677         MBSTOWCS(wcs_buffer, SUNPRO_DEPENDENCIES);
 678         sunpro_dependencies = GETNAME(wcs_buffer, FIND_LENGTH);
 679         MBSTOWCS(wcs_buffer, NOCATGETS("TARGET_ARCH"));
 680         target_arch = GETNAME(wcs_buffer, FIND_LENGTH);
 681         MBSTOWCS(wcs_buffer, NOCATGETS("TARGET_MACH"));
 682         target_mach = GETNAME(wcs_buffer, FIND_LENGTH);
 683         MBSTOWCS(wcs_buffer, NOCATGETS("VIRTUAL_ROOT"));
 684         virtual_root = GETNAME(wcs_buffer, FIND_LENGTH);
 685         MBSTOWCS(wcs_buffer, NOCATGETS("VPATH"));
 686         vpath_name = GETNAME(wcs_buffer, FIND_LENGTH);
 687         MBSTOWCS(wcs_buffer, NOCATGETS(".WAIT"));
 688         wait_name = GETNAME(wcs_buffer, FIND_LENGTH);
 689 
 690         wait_name->state = build_ok;
 691 
 692         /* Mark special targets so that the reader treats them properly */
 693         svr4_name->special_reader = svr4_special;
 694         posix_name->special_reader = posix_special;
 695         built_last_make_run->special_reader = built_last_make_run_special;
 696         default_rule_name->special_reader = default_special;
 697 #ifdef NSE
 698         derived_src->special_reader= derived_src_special;
 699 #endif
 700         dot_keep_state->special_reader = keep_state_special;
 701         dot_keep_state_file->special_reader = keep_state_file_special;
 702         ignore_name->special_reader = ignore_special;
 703         make_version->special_reader = make_version_special;
 704         no_parallel_name->special_reader = no_parallel_special;
 705         parallel_name->special_reader = parallel_special;
 706         localhost_name->special_reader = localhost_special;
 707         precious->special_reader = precious_special;
 708         sccs_get_name->special_reader = sccs_get_special;
 709         sccs_get_posix_name->special_reader = sccs_get_posix_special;
 710         get_name->special_reader = get_special;
 711         get_posix_name->special_reader = get_posix_special;
 712         silent_name->special_reader = silent_special;
 713         suffixes_name->special_reader = suffixes_special;
 714 
 715         /* The value of $$ is $ */
 716         (void) SETVAR(dollar, dollar, false);
 717         dollar->dollar = false;
 718 
 719         /* Set the value of $(SHELL) */
 720         if (posix) {
 721           MBSTOWCS(wcs_buffer, NOCATGETS("/usr/xpg4/bin/sh"));
 722         } else {
 723           MBSTOWCS(wcs_buffer, NOCATGETS("/bin/sh"));
 724         }
 725         (void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
 726 
 727         /*
 728          * Use " FORCE" to simulate a FRC dependency for :: type
 729          * targets with no dependencies.
 730          */
 731         (void) append_prop(force, line_prop);
 732         force->stat.time = file_max_time;
 733 
 734         /* Make sure VPATH is defined before current dir is read */
 735         if ((cp = getenv(vpath_name->string_mb)) != NULL) {
 736                 MBSTOWCS(wcs_buffer, cp);
 737                 (void) SETVAR(vpath_name,
 738                               GETNAME(wcs_buffer, FIND_LENGTH),
 739                               false);
 740         }
 741 
 742         /* Check if there is NO PATH variable. If not we construct one. */
 743         if (getenv(path_name->string_mb) == NULL) {
 744                 vroot_path = NULL;
 745                 add_dir_to_path(NOCATGETS("."), &vroot_path, -1);
 746                 add_dir_to_path(NOCATGETS("/bin"), &vroot_path, -1);
 747                 add_dir_to_path(NOCATGETS("/usr/bin"), &vroot_path, -1);
 748         }
 749 }
 750 
 751 /* 
 752  * iterate on list of conditional macros in np, and place them in 
 753  * a String_rec starting with, and separated by the '$' character.
 754  */
 755 void
 756 cond_macros_into_string(Name np, String_rec *buffer)
 757 {
 758         Macro_list      macro_list;
 759 
 760         /* 
 761          * Put the version number at the start of the string
 762          */
 763         MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
 764         append_string(wcs_buffer, buffer, FIND_LENGTH);
 765         /* 
 766          * Add the rest of the conditional macros to the buffer
 767          */
 768         if (np->depends_on_conditional){
 769                 for (macro_list = np->conditional_macro_list; 
 770                      macro_list != NULL; macro_list = macro_list->next){
 771                         append_string(macro_list->macro_name, buffer, 
 772                                 FIND_LENGTH);
 773                         append_char((int) equal_char, buffer);
 774                         append_string(macro_list->value, buffer, FIND_LENGTH);
 775                         append_char((int) dollar_char, buffer);
 776                 }
 777         }
 778 }
 779 /*
 780  *      Copyright (c) 1987-1992 Sun Microsystems, Inc.  All Rights Reserved.
 781  *      Sun considers its source code as an unpublished, proprietary
 782  *      trade secret, and it is available only under strict license
 783  *      provisions.  This copyright notice is placed here only to protect
 784  *      Sun in the event the source is deemed a published work.  Dissassembly,
 785  *      decompilation, or other means of reducing the object code to human
 786  *      readable form is prohibited by the license agreement under which
 787  *      this code is provided to the user or company in possession of this
 788  *      copy.
 789  *      RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the
 790  *      Government is subject to restrictions as set forth in subparagraph
 791  *      (c)(1)(ii) of the Rights in Technical Data and Computer Software
 792  *      clause at DFARS 52.227-7013 and in similar clauses in the FAR and
 793  *      NASA FAR Supplement.
 794  *
 795  * 1.3 91/09/30
 796  */
 797 
 798 
 799 /* Some includes are commented because of the includes at the beginning */
 800 /* #include <signal.h> */
 801 #include <sys/types.h>
 802 #include <sys/stat.h>
 803 #include <sys/param.h>
 804 /* #include <string.h> */
 805 #include <unistd.h>
 806 #include <stdlib.h>
 807 /* #include <stdio.h> */
 808 /* #include <avo/find_dir.h> */
 809 /* #ifndef TEAMWARE_MAKE_CMN
 810 #include <avo/find_dir.h>
 811 #endif */
 812 
 813 /* Routines to find the base directory name from which the various components
 814  * -executables, *crt* libraries etc will be accessed
 815  */
 816 
 817 /* This routine checks to see if a given filename is an executable or not.
 818    Logically similar to the csh statement : if  ( -x $i && ! -d $i )
 819  */
 820 
 821 static int
 822 check_if_exec(char *file)
 823 {
 824         struct stat stb;
 825         if (stat(file, &stb) < 0) {
 826                 return ( -1);
 827         }
 828         if (S_ISDIR(stb.st_mode)) {
 829                 return (-1);
 830         }
 831         if (!(stb.st_mode & S_IEXEC)) {
 832                 return ( -1);
 833         }
 834         return (0);
 835 }
 836 
 837 /* resolve - check for specified file in specified directory
 838  *      sets up dir, following symlinks.
 839  *      returns zero for success, or
 840  *      -1 for error (with errno set properly)
 841  */
 842 static int
 843 resolve (const char *indir,     /* search directory */
 844          const char *cmd,       /* search for name */
 845          char   *dir,   /* directory buffer */
 846          char   **run)  /* resultion name ptr ptr */
 847 {
 848     char               *p;
 849     int                 rv = -1;
 850     int                 sll;
 851     char                symlink[MAXPATHLEN + 1];
 852 
 853     do {
 854         errno = ENAMETOOLONG;
 855         if ((strlen (indir) + strlen (cmd) + 2) > (size_t) MAXPATHLEN)
 856             break;
 857 
 858         sprintf(dir, "%s/%s", indir, cmd);
 859         if (check_if_exec(dir) != 0)  /* check if dir is an executable */
 860         {
 861                 break;          /* Not an executable program */
 862         }
 863 
 864         /* follow symbolic links */
 865         while ((sll = readlink (dir, symlink, MAXPATHLEN)) >= 0) {
 866             symlink[sll] = 0;
 867             if (*symlink == '/')
 868                 strcpy (dir, symlink);
 869             else
 870                 sprintf (strrchr (dir, '/'), "/%s", symlink);
 871         }
 872         if (errno != EINVAL)
 873             break;
 874 
 875         p = strrchr (dir, '/');
 876         *p++ = 0;
 877         if (run)                /* user wants resolution name */
 878             *run = p;
 879         rv = 0;                 /* complete, with success! */
 880 
 881     } while (0);
 882 
 883     return rv;
 884 }
 885 
 886 /* 
 887  *find_run_directory - find executable file in PATH
 888  *
 889  * PARAMETERS:
 890  *      cmd     filename as typed by user (argv[0])
 891  *      cwd     buffer from which is read the working directory
 892  *               if first character is '/' or into which is
 893  *               copied working directory name otherwise
 894  *      dir     buffer into which is copied program's directory
 895  *      pgm     where to return pointer to tail of cmd (may be NULL
 896  *               if not wanted) 
 897  *      run     where to return pointer to tail of final resolved
 898  *               name ( dir/run is the program) (may be NULL
 899  *               if not wanted)
 900  *      path    user's path from environment
 901  *
 902  * Note: run and pgm will agree except when symbolic links have
 903  *      renamed files
 904  *
 905  * RETURNS:
 906  *      returns zero for success,
 907  *      -1 for error (with errno set properly).
 908  *
 909  * EXAMPLE:
 910  *      find_run_directory (argv[0], ".", &charray1, (char **) 0, (char **) 0,
 911  *                          getenv(NOGETTEXT("PATH")));
 912  */
 913 extern int
 914 find_run_directory (char        *cmd,
 915                     char        *cwd,
 916                     char        *dir,
 917                     char        **pgm,
 918                     char        **run,
 919                     char        *path)
 920 {
 921     int                 rv = 0;
 922     char                *f, *s;
 923     int                 i;
 924     char                tmp_path[MAXPATHLEN];
 925 
 926     if (!cmd || !*cmd || !cwd || !dir) {
 927         errno = EINVAL;         /* stupid arguments! */
 928         return -1;
 929     }
 930 
 931     if (*cwd != '/')
 932         if (!(getcwd (cwd, MAXPATHLEN)))
 933             return -1;          /* can not get working directory */
 934 
 935     f = strrchr (cmd, '/');
 936     if (pgm)                    /* user wants program name */
 937         *pgm = f ? f + 1 : cmd;
 938 
 939     /* get program directory */
 940     rv = -1;
 941     if (*cmd == '/')    /* absname given */
 942         rv = resolve ("", cmd + 1, dir, run);
 943     else if (f)         /* relname given */
 944         rv = resolve (cwd, cmd, dir, run);
 945     else {  /* from searchpath */
 946             if (!path || !*path) {      /* if missing or null path */
 947                     tmp_path[0] = '.';  /* assume sanity */
 948                     tmp_path[1] = '\0';
 949             } else {
 950                     strcpy(tmp_path, path);
 951             }
 952         f = tmp_path;
 953         rv = -1;
 954         errno = ENOENT; /* errno gets this if path empty */
 955         while (*f && (rv < 0)) {
 956             s = f;
 957             while (*f && (*f != ':'))
 958                 ++f;
 959             if (*f)
 960                 *f++ = 0;
 961             if (*s == '/')
 962                 rv = resolve (s, cmd, dir, run);
 963             else {
 964                 char                abuf[MAXPATHLEN];
 965 
 966                 sprintf (abuf, "%s/%s", cwd, s);
 967                 rv = resolve (abuf, cmd, dir, run);
 968             }
 969         }
 970     }
 971 
 972     /* Remove any trailing /. */
 973     i = strlen(dir);
 974     if ( dir[i-2] == '/' && dir[i-1] == '.') {
 975             dir[i-2] = '\0';
 976     }
 977 
 978     return rv;
 979 }
 980