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