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