xref: /illumos-gate/usr/src/cmd/make/bin/doname.cc (revision e7afc443)
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 2006 Sun Microsystems, Inc. All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright (c) 2016 by Delphix. All rights reserved.
26  * Copyright 2019 RackTop Systems.
27  */
28 
29 /*
30  *	doname.c
31  *
32  *	Figure out which targets are out of date and rebuild them
33  */
34 
35 /*
36  * Included files
37  */
38 #include <alloca.h>		/* alloca() */
39 #include <fcntl.h>
40 #include <mk/defs.h>
41 #include <mksh/i18n.h>		/* get_char_semantics_value() */
42 #include <mksh/macro.h>		/* getvar(), expand_value() */
43 #include <mksh/misc.h>		/* getmem() */
44 #include <poll.h>
45 #include <libintl.h>
46 #include <signal.h>
47 #include <stropts.h>
48 #include <sys/errno.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <sys/utsname.h>	/* uname() */
52 #include <sys/wait.h>
53 #include <unistd.h>		/* close() */
54 
55 /*
56  * Defined macros
57  */
58 #	define LOCALHOST "localhost"
59 
60 #define MAXRULES 100
61 
62 // Sleep for .1 seconds between stat()'s
63 const int	STAT_RETRY_SLEEP_TIME = 100000;
64 
65 /*
66  * typedefs & structs
67  */
68 
69 /*
70  * Static variables
71  */
72 static char	hostName[MAXNAMELEN] = "";
73 static char	userName[MAXNAMELEN] = "";
74 
75 
76 static int	second_pass = 0;
77 
78 /*
79  * File table of contents
80  */
81 extern	Doname		doname_check(Name target, Boolean do_get, Boolean implicit, Boolean automatic);
82 extern	Doname		doname(Name target, Boolean do_get, Boolean implicit, Boolean automatic);
83 static	Boolean		check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
84 void		dynamic_dependencies(Name target);
85 static	Doname		run_command(Property line, Boolean print_machine);
86 extern	Doname		execute_serial(Property line);
87 extern	Name		vpath_translation(Name cmd);
88 extern	void		check_state(Name temp_file_name);
89 static	void		read_dependency_file(Name filename);
90 static	void		check_read_state_file(void);
91 static	void		do_assign(Name line, Name target);
92 static	void		build_command_strings(Name target, Property line);
93 static	Doname		touch_command(Property line, Name target, Doname result);
94 extern	void		update_target(Property line, Doname result);
95 static	Doname		sccs_get(Name target, Property *command);
96 extern	void		read_directory_of_file(Name file);
97 static	void		add_pattern_conditionals(Name target);
98 extern	void		set_locals(Name target, Property old_locals);
99 extern	void		reset_locals(Name target, Property old_locals, Property conditional, int index);
100 extern	Boolean		check_auto_dependencies(Name target, int auto_count, Name *automatics);
101 static	void		delete_query_chain(Chain ch);
102 
103 // From read2.cc
104 extern	Name		normalize_name(wchar_t *name_string, int length);
105 
106 
107 
108 /*
109  * DONE.
110  *
111  *	doname_check(target, do_get, implicit, automatic)
112  *
113  *	Will call doname() and then inspect the return value
114  *
115  *	Return value:
116  *				Indication if the build failed or not
117  *
118  *	Parameters:
119  *		target		The target to build
120  *		do_get		Passed thru to doname()
121  *		implicit	Passed thru to doname()
122  *		automatic	Are we building a hidden dependency?
123  *
124  *	Global variables used:
125  *		build_failed_seen	Set if -k is on and error occurs
126  *		continue_after_error	Indicates that -k is on
127  *		report_dependencies	No error msg if -P is on
128  */
129 Doname
doname_check(Name target,Boolean do_get,Boolean implicit,Boolean automatic)130 doname_check(Name target, Boolean do_get, Boolean implicit, Boolean automatic)
131 {
132 	int first_time = 1;
133 	Doname rv = build_failed;
134 
135 	(void) fflush(stdout);
136 try_again:
137 	switch (doname(target, do_get, implicit, automatic)) {
138 	case build_ok:
139 		second_pass = 0;
140 		rv = build_ok;
141 		break;
142 	case build_running:
143 		second_pass = 0;
144 		rv = build_running;
145 		break;
146 	case build_failed:
147 		if (!continue_after_error) {
148 			fatal(
149 			    gettext("Target `%s' not remade because of errors"),
150 			    target->string_mb);
151 		}
152 		build_failed_seen = true;
153 		second_pass = 0;
154 		rv = build_failed;
155 		break;
156 	case build_dont_know:
157 		/*
158 		 * If we can't figure out how to build an automatic
159 		 * (hidden) dependency, we just ignore it.
160 		 * We later declare the target to be out of date just in
161 		 * case something changed.
162 		 * Also, don't complain if just reporting the dependencies
163 		 * and not building anything.
164 		 */
165 		if (automatic || (report_dependencies_level > 0)) {
166 			second_pass = 0;
167 			rv = build_dont_know;
168 			break;
169 		}
170 		if(first_time) {
171 			first_time = 0;
172 			second_pass = 1;
173 			goto try_again;
174 		}
175 		second_pass = 0;
176 		if (continue_after_error && !svr4) {
177 			warning(gettext("Don't know how to make target `%s'"),
178 				target->string_mb);
179 			build_failed_seen = true;
180 			rv = build_failed;
181 			break;
182 		}
183 		fatal(gettext("Don't know how to make target `%s'"),
184 		    target->string_mb);
185 		break;
186 	}
187 	return (rv);
188 }
189 
190 
191 void
enter_explicit_rule_from_dynamic_rule(Name target,Name source)192 enter_explicit_rule_from_dynamic_rule(Name target, Name source)
193 {
194 	Property line, source_line;
195 	Dependency dependency;
196 
197 	source_line = get_prop(source->prop, line_prop);
198 	line = maybe_append_prop(target, line_prop);
199 	line->body.line.sccs_command = false;
200 	line->body.line.target = target;
201 	if (line->body.line.command_template == NULL) {
202 		line->body.line.command_template = source_line->body.line.command_template;
203 		for (dependency = source_line->body.line.dependencies;
204 		     dependency != NULL;
205 		     dependency = dependency->next) {
206 			enter_dependency(line, dependency->name, false);
207 		}
208 		line->body.line.less = target;
209 	}
210 	line->body.line.percent = NULL;
211 }
212 
213 
214 
215 Name
find_dyntarget(Name target)216 find_dyntarget(Name target)
217 {
218 	Dyntarget		p;
219 	int			i;
220 	String_rec		string;
221 	wchar_t			buffer[STRING_BUFFER_LENGTH];
222 	wchar_t			*pp, * bufend;
223 	wchar_t			tbuffer[MAXPATHLEN];
224 	Wstring			wcb(target);
225 
226 	for (p = dyntarget_list; p != NULL; p = p->next) {
227 		INIT_STRING_FROM_STACK(string, buffer);
228 		expand_value(p->name, &string, false);
229 		i = 0;
230 		pp = string.buffer.start;
231 		bufend = pp + STRING_BUFFER_LENGTH;
232 		while((*pp != nul_char) && (pp < bufend)) {
233 			if(iswspace(*pp)) {
234 				tbuffer[i] = nul_char;
235 				if(i > 0) {
236 					if (wcb.equal(tbuffer)) {
237 						enter_explicit_rule_from_dynamic_rule(target, p->name);
238 						return(target);
239 					}
240 				}
241 				pp++;
242 				i = 0;
243 				continue;
244 			}
245 			tbuffer[i] = *pp;
246 			i++;
247 			pp++;
248 			if(*pp == nul_char) {
249 				tbuffer[i] = nul_char;
250 				if(i > 0) {
251 					if (wcb.equal(tbuffer)) {
252 						enter_explicit_rule_from_dynamic_rule(target, p->name);
253 						return(target);
254 					}
255 				}
256 				break;
257 			}
258 		}
259 	}
260 	return(NULL);
261 }
262 
263 /*
264  * DONE.
265  *
266  *	doname(target, do_get, implicit)
267  *
268  *	Chases all files the target depends on and builds any that
269  *	are out of date. If the target is out of date it is then rebuilt.
270  *
271  *	Return value:
272  *				Indiates if build failed or nt
273  *
274  *	Parameters:
275  *		target		Target to build
276  *		do_get		Run sccs get is nessecary
277  *		implicit	doname is trying to find an implicit rule
278  *
279  *	Global variables used:
280  *		assign_done	True if command line assgnment has happened
281  *		commands_done	Preserved for the case that we need local value
282  *		debug_level	Should we trace make's actions?
283  *		default_rule	The rule for ".DEFAULT", used as last resort
284  *		empty_name	The Name "", used when looking for single sfx
285  *		keep_state	Indicates that .KEEP_STATE is on
286  *		parallel	True if building in parallel
287  *		recursion_level	Used for tracing
288  *		report_dependencies make -P is on
289  */
290 Doname
doname(Name target,Boolean do_get,Boolean implicit,Boolean automatic)291 doname(Name target, Boolean do_get, Boolean implicit, Boolean automatic)
292 {
293 	Doname			result = build_dont_know;
294 	Chain			out_of_date_list = NULL;
295 	Chain			target_group;
296 	Property		old_locals = NULL;
297 	Property	line;
298 	Property		command = NULL;
299 	Dependency	dependency;
300 	Name			less = NULL;
301 	Name			true_target = target;
302 	Name			*automatics = NULL;
303 	int		auto_count;
304 	Boolean			rechecking_target = false;
305 	Boolean			saved_commands_done;
306 	Boolean			restart = false;
307 	Boolean			save_parallel = parallel;
308 	Boolean			doing_subtree = false;
309 
310 	Boolean			recheck_conditionals = false;
311 
312 	if (target->state == build_running) {
313 		return build_running;
314 	}
315 	line = get_prop(target->prop, line_prop);
316 	if (line != NULL) {
317 		/*
318 		 * If this target is a member of target group and one of the
319 		 * other members of the group is running, mark this target
320 		 * as running.
321 		 */
322 		for (target_group = line->body.line.target_group;
323 		     target_group != NULL;
324 		     target_group = target_group->next) {
325 			if (is_running(target_group->name)) {
326 				target->state = build_running;
327 				add_pending(target,
328 					    recursion_level,
329 					    do_get,
330 					    implicit,
331 					    false);
332 				return build_running;
333 			}
334 		}
335 	}
336 	/*
337 	 * If the target is a constructed one for a "::" target,
338 	 * we need to consider that.
339 	 */
340 	if (target->has_target_prop) {
341 		true_target = get_prop(target->prop,
342 				       target_prop)->body.target.target;
343 		if (true_target->colon_splits > 0) {
344 			/* Make sure we have a valid time for :: targets */
345 			Property        time;
346 
347 			time = get_prop(true_target->prop, time_prop);
348 			if (time != NULL) {
349 				true_target->stat.time = time->body.time.time;
350 			}
351 		}
352 	}
353 	(void) exists(true_target);
354 	/*
355 	 * If the target has been processed, we don't need to do it again,
356 	 * unless it depends on conditional macros or a delayed assignment,
357 	 * or it has been done when KEEP_STATE is on.
358 	 */
359 	if (target->state == build_ok) {
360 		if((!keep_state || (!target->depends_on_conditional && !assign_done))) {
361 			return build_ok;
362 		} else {
363 			recheck_conditionals = true;
364 		}
365 	}
366 	if (target->state == build_subtree) {
367 		/* A dynamic macro subtree is being built */
368 		target->state = build_dont_know;
369 		doing_subtree = true;
370 		if (!target->checking_subtree) {
371 			/*
372 			 * This target has been started before and therefore
373 			 * not all dependencies have to be built.
374 			 */
375 			restart = true;
376 		}
377 	} else if (target->state == build_pending) {
378 		target->state = build_dont_know;
379 		restart = true;
380 /*
381 	} else if (parallel &&
382 		   keep_state &&
383 		   (target->conditional_cnt > 0)) {
384 	    if (!parallel_ok(target, false)) {
385 		add_subtree(target, recursion_level, do_get, implicit);
386 		target->state = build_running;
387 		return build_running;
388 	    }
389  */
390 	}
391 	/*
392 	 * If KEEP_STATE is on, we have to rebuild the target if the
393 	 * building of it caused new automatic dependencies to be reported.
394 	 * This is where we restart the build.
395 	 */
396 	if (line != NULL) {
397 		line->body.line.percent = NULL;
398 	}
399 recheck_target:
400 	/* Init all local variables */
401 	result = build_dont_know;
402 	out_of_date_list = NULL;
403 	command = NULL;
404 	less = NULL;
405 	auto_count = 0;
406 	if (!restart && line != NULL) {
407 		/*
408 		 * If this target has never been built before, mark all
409 		 * of the dependencies as never built.
410 		 */
411 		for (dependency = line->body.line.dependencies;
412 		     dependency != NULL;
413 		     dependency = dependency->next) {
414 			dependency->built = false;
415 		}
416 	}
417 	/* Save the set of automatic depes defined for this target */
418 	if (keep_state &&
419 	    (line != NULL) &&
420 	    (line->body.line.dependencies != NULL)) {
421 		Name *p;
422 
423 		/*
424 		 * First run thru the dependency list to see how many
425 		 * autos there are.
426 		 */
427 		for (dependency = line->body.line.dependencies;
428 		     dependency != NULL;
429 		     dependency = dependency->next) {
430 			if (dependency->automatic && !dependency->stale) {
431 				auto_count++;
432 			}
433 		}
434 		/* Create vector to hold the current autos */
435 		automatics =
436 		  (Name *) alloca((int) (auto_count * sizeof (Name)));
437 		/* Copy them */
438 		for (p = automatics, dependency = line->body.line.dependencies;
439 		     dependency != NULL;
440 		     dependency = dependency->next) {
441 			if (dependency->automatic && !dependency->stale) {
442 				*p++ = dependency->name;
443 			}
444 		}
445 	}
446 	if (debug_level > 1) {
447 		(void) printf("%*sdoname(%s)\n",
448 			      recursion_level,
449 			      "",
450 			      target->string_mb);
451 	}
452 	recursion_level++;
453 	/* Avoid infinite loops */
454 	if (target->state == build_in_progress) {
455 		warning(gettext("Infinite loop: Target `%s' depends on itself"),
456 			target->string_mb);
457 		return build_ok;
458 	}
459 	target->state = build_in_progress;
460 
461 	/* Activate conditional macros for the target */
462 	if (!target->added_pattern_conditionals) {
463 		add_pattern_conditionals(target);
464 		target->added_pattern_conditionals = true;
465 	}
466 	if (target->conditional_cnt > 0) {
467 		old_locals = (Property) alloca(target->conditional_cnt *
468 					       sizeof (Property_rec));
469 		set_locals(target, old_locals);
470 	}
471 
472 /*
473  * after making the call to dynamic_dependecies unconditional we can handle
474  * target names that are same as file name. In this case $$@ in the
475  * dependencies did not mean anything. WIth this change it expands it
476  * as expected.
477  */
478 	if (!target->has_depe_list_expanded)
479 	{
480 		dynamic_dependencies(target);
481 	}
482 
483 /*
484  *	FIRST SECTION -- GO THROUGH DEPENDENCIES AND COLLECT EXPLICIT
485  *	COMMANDS TO RUN
486  */
487 	if ((line = get_prop(target->prop, line_prop)) != NULL) {
488 		if (check_dependencies(&result,
489 				       line,
490 				       do_get,
491 				       target,
492 				       true_target,
493 				       doing_subtree,
494 				       &out_of_date_list,
495 				       old_locals,
496 				       implicit,
497 				       &command,
498 				       less,
499 				       rechecking_target,
500 				       recheck_conditionals)) {
501 			return build_running;
502 		}
503 		if (line->body.line.query != NULL) {
504 			delete_query_chain(line->body.line.query);
505 		}
506 		line->body.line.query = out_of_date_list;
507 	}
508 
509 
510 /*
511  * If the target is a :: type, do not try to find the rule for the target,
512  * all actions will be taken by separate branches.
513  * Else, we try to find an implicit rule using various methods,
514  * we quit as soon as one is found.
515  *
516  * [tolik, 12 Sep 2002] Do not try to find implicit rule for the target
517  * being rechecked - the target is being rechecked means that it already
518  * has explicit dependencies derived from an implicit rule found
519  * in previous step.
520  */
521 	if (target->colon_splits == 0 && !rechecking_target) {
522 		/* Look for percent matched rule */
523 		if ((result == build_dont_know) &&
524 		    (command == NULL)) {
525 			switch (find_percent_rule(
526 					target,
527 					&command,
528 					recheck_conditionals)) {
529 			case build_failed:
530 				result = build_failed;
531 				break;
532 			case build_running:
533 				target->state = build_running;
534 				add_pending(target,
535 					    --recursion_level,
536 					    do_get,
537 					    implicit,
538 					    false);
539 				if (target->conditional_cnt > 0) {
540 					reset_locals(target,
541 						     old_locals,
542 						     get_prop(target->prop,
543 							     conditional_prop),
544 						     0);
545 				}
546 				return build_running;
547 			case build_ok:
548 				result = build_ok;
549 				break;
550 			}
551 		}
552 		/* Look for double suffix rule */
553 		if (result == build_dont_know) {
554 			Property member;
555 
556 			if (target->is_member &&
557 			    ((member = get_prop(target->prop, member_prop)) !=
558 			     NULL)) {
559 			        switch (find_ar_suffix_rule(target,
560 						member->body.
561 						member.member,
562 						&command,
563 						recheck_conditionals)) {
564 				case build_failed:
565 					result = build_failed;
566 					break;
567 				case build_running:
568 					target->state = build_running;
569 					add_pending(target,
570 						    --recursion_level,
571 						    do_get,
572 						    implicit,
573 						    false);
574 				    if (target->conditional_cnt > 0) {
575 					    reset_locals(target,
576 							 old_locals,
577 							 get_prop(target->prop,
578 							     conditional_prop),
579 							 0);
580 				    }
581 					return build_running;
582 				default:
583 					/* ALWAYS bind $% for old style */
584 					/* ar rules */
585 					if (line == NULL) {
586 						line =
587 						  maybe_append_prop(target,
588 								    line_prop);
589 					}
590 					line->body.line.percent =
591 					  member->body.member.member;
592 					break;
593 				}
594 			} else {
595 				switch (find_double_suffix_rule(target,
596 						&command,
597 						recheck_conditionals)) {
598 				case build_failed:
599 					result = build_failed;
600 					break;
601 				case build_running:
602 					target->state = build_running;
603 					add_pending(target,
604 						    --recursion_level,
605 						    do_get,
606 						    implicit,
607 						    false);
608 					if (target->conditional_cnt > 0) {
609 						reset_locals(target,
610 							     old_locals,
611 							     get_prop(target->
612 								      prop,
613 								      conditional_prop),
614 							     0);
615 					}
616 					return build_running;
617 				}
618 			}
619 		}
620 		/* Look for single suffix rule */
621 
622 /* /tolik/
623  * I commented !implicit to fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
624  * This caused problem with SVR4 tilde rules (infinite recursion). So I made some changes in "implicit.cc"
625  */
626 /* /tolik, 06.21.96/
627  * Regression! See BugId 1255360
628  * If more than one percent rules are defined for the same target then
629  * the behaviour of 'make' with my previous fix may be different from one
630  * of the 'old make'.
631  * The global variable second_pass (maybe it should be an argument to doname())
632  * is intended to avoid this regression. It is set in doname_check().
633  * First, 'make' will work as it worked before. Only when it is
634  * going to say "don't know how to make target" it sets second_pass to true and
635  * run 'doname' again but now trying to use Single Suffix Rules.
636  */
637 		if ((result == build_dont_know) && !automatic && (!implicit || second_pass) &&
638 		    ((line == NULL) ||
639 		     ((line->body.line.target != NULL) &&
640 		      !line->body.line.target->has_regular_dependency))) {
641 			switch (find_suffix_rule(target,
642 						 target,
643 						 empty_name,
644 						 &command,
645 						 recheck_conditionals)) {
646 			case build_failed:
647 				result = build_failed;
648 				break;
649 			case build_running:
650 				target->state = build_running;
651 				add_pending(target,
652 					    --recursion_level,
653 					    do_get,
654 					    implicit,
655 					    false);
656 				if (target->conditional_cnt > 0) {
657 					reset_locals(target,
658 						     old_locals,
659 						     get_prop(target->prop,
660 							     conditional_prop),
661 						     0);
662 				}
663 				return build_running;
664 			}
665 		}
666 		/* Try to sccs get */
667 		if ((command == NULL) &&
668 		    (result == build_dont_know) &&
669 		    do_get) {
670 			result = sccs_get(target, &command);
671 		}
672 
673 		/* Use .DEFAULT rule if it is defined. */
674 		if ((command == NULL) &&
675 		    (result == build_dont_know) &&
676 		    (true_target->colons == no_colon) &&
677 		    default_rule &&
678 		    !implicit) {
679 			/* Make sure we have a line prop */
680 			line = maybe_append_prop(target, line_prop);
681 			command = line;
682 			Boolean out_of_date;
683 			if (true_target->is_member) {
684 				out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
685 									line->body.line.dependency_time);
686 			} else {
687 				out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
688 								    line->body.line.dependency_time);
689 			}
690 			if (build_unconditional || out_of_date) {
691 				line->body.line.is_out_of_date = true;
692 				if (debug_level > 0) {
693 					(void) printf(gettext("%*sBuilding %s using .DEFAULT because it is out of date\n"),
694 						      recursion_level,
695 						      "",
696 						      true_target->string_mb);
697 				}
698 			}
699 			line->body.line.sccs_command = false;
700 			line->body.line.command_template = default_rule;
701 			line->body.line.target = true_target;
702 			line->body.line.star = NULL;
703 			line->body.line.less = true_target;
704 			line->body.line.percent = NULL;
705 		}
706 	}
707 
708 	/* We say "target up to date" if no cmd were executed for the target */
709 	if (!target->is_double_colon_parent) {
710 		commands_done = false;
711 	}
712 
713 	silent = silent_all;
714 	ignore_errors = ignore_errors_all;
715 	if  (posix)
716 	{
717 	  if  (!silent)
718 	  {
719             silent = (Boolean) target->silent_mode;
720 	  }
721 	  if  (!ignore_errors)
722 	  {
723             ignore_errors = (Boolean) target->ignore_error_mode;
724 	  }
725 	}
726 
727 	int doname_dyntarget = 0;
728 r_command:
729 	/* Run commands if any. */
730 	if ((command != NULL) &&
731 	    (command->body.line.command_template != NULL)) {
732 		if (result != build_failed) {
733 			result = run_command(command,
734 					     (Boolean) ((parallel || save_parallel) && !silent));
735 		}
736 		switch (result) {
737 		case build_running:
738 			add_running(target,
739 				    true_target,
740 				    command,
741 				    --recursion_level,
742 				    auto_count,
743 				    automatics,
744 				    do_get,
745 				    implicit);
746 			target->state = build_running;
747 			if ((line = get_prop(target->prop,
748 					     line_prop)) != NULL) {
749 				if (line->body.line.query != NULL) {
750 					delete_query_chain(line->body.line.query);
751 				}
752 				line->body.line.query = NULL;
753 			}
754 			if (target->conditional_cnt > 0) {
755 				reset_locals(target,
756 					     old_locals,
757 					     get_prop(target->prop,
758 						     conditional_prop),
759 					     0);
760 			}
761 			return build_running;
762 		case build_serial:
763 			add_serial(target,
764 				   --recursion_level,
765 				   do_get,
766 				   implicit);
767 			target->state = build_running;
768 			line = get_prop(target->prop, line_prop);
769 			if (line != NULL) {
770 				if (line->body.line.query != NULL) {
771 					delete_query_chain(line->body.line.query);
772 				}
773 				line->body.line.query = NULL;
774 			}
775 			if (target->conditional_cnt > 0) {
776 				reset_locals(target,
777 					     old_locals,
778 					     get_prop(target->prop,
779 						     conditional_prop),
780 					     0);
781 			}
782 			return build_running;
783 		case build_ok:
784 			/* If all went OK set a nice timestamp */
785 			if (true_target->stat.time == file_doesnt_exist) {
786 				true_target->stat.time = file_max_time;
787 			}
788 			break;
789 		}
790 	} else {
791 		/*
792 		 * If no command was found for the target, and it doesn't
793 		 * exist, and it is mentioned as a target in the makefile,
794 		 * we say it is extremely new and that it is OK.
795 		 */
796 		if (target->colons != no_colon) {
797 			if (true_target->stat.time == file_doesnt_exist){
798 				true_target->stat.time = file_max_time;
799 			}
800 			result = build_ok;
801 		}
802 		/*
803 		 * Trying dynamic targets.
804 		 */
805 		if(!doname_dyntarget) {
806 			doname_dyntarget = 1;
807 			Name dtarg = find_dyntarget(target);
808 			if(dtarg!=NULL) {
809 				if (!target->has_depe_list_expanded) {
810 					dynamic_dependencies(target);
811 				}
812 				if ((line = get_prop(target->prop, line_prop)) != NULL) {
813 					if (check_dependencies(&result,
814 					                       line,
815 					                       do_get,
816 					                       target,
817 					                       true_target,
818 					                       doing_subtree,
819 					                       &out_of_date_list,
820 					                       old_locals,
821 					                       implicit,
822 					                       &command,
823 					                       less,
824 					                       rechecking_target,
825 					                       recheck_conditionals))
826 					{
827 						return build_running;
828 					}
829 					if (line->body.line.query != NULL) {
830 						delete_query_chain(line->body.line.query);
831 					}
832 					line->body.line.query = out_of_date_list;
833 				}
834 				goto r_command;
835 			}
836 		}
837 		/*
838 		 * If the file exists, it is OK that we couldnt figure
839 		 * out how to build it.
840 		 */
841 		(void) exists(target);
842 		if ((target->stat.time != file_doesnt_exist) &&
843 		    (result == build_dont_know)) {
844 			result = build_ok;
845 		}
846 	}
847 
848 	/*
849 	 * Some of the following is duplicated in the function finish_doname.
850 	 * If anything is changed here, check to see if it needs to be
851 	 * changed there.
852 	 */
853 	if ((line = get_prop(target->prop, line_prop)) != NULL) {
854 		if (line->body.line.query != NULL) {
855 			delete_query_chain(line->body.line.query);
856 		}
857 		line->body.line.query = NULL;
858 	}
859 	target->state = result;
860 	parallel = save_parallel;
861 	if (target->conditional_cnt > 0) {
862 		reset_locals(target,
863 			     old_locals,
864 			     get_prop(target->prop, conditional_prop),
865 			     0);
866 	}
867 	recursion_level--;
868 	if (target->is_member) {
869 		Property member;
870 
871 		/* Propagate the timestamp from the member file to the member*/
872 		if ((target->stat.time != file_max_time) &&
873 		    ((member = get_prop(target->prop, member_prop)) != NULL) &&
874 		    (exists(member->body.member.member) > file_doesnt_exist)) {
875 			target->stat.time =
876 			  member->body.member.member->stat.time;
877 		}
878 	}
879 	/*
880 	 * Check if we found any new auto dependencies when we
881 	 * built the target.
882 	 */
883 	if ((result == build_ok) && check_auto_dependencies(target,
884 							    auto_count,
885 							    automatics)) {
886 		if (debug_level > 0) {
887 			(void) printf(gettext("%*sTarget `%s' acquired new dependencies from build, rechecking all dependencies\n"),
888 				      recursion_level,
889 				      "",
890 				      true_target->string_mb);
891 		}
892 		rechecking_target = true;
893 		saved_commands_done = commands_done;
894 		goto recheck_target;
895 	}
896 
897 	if (rechecking_target && !commands_done) {
898 		commands_done = saved_commands_done;
899 	}
900 
901 	return result;
902 }
903 
904 /*
905  * DONE.
906  *
907  *	check_dependencies(result, line, do_get,
908  *			target, true_target, doing_subtree, out_of_date_tail,
909  *			old_locals, implicit, command, less, rechecking_target)
910  *
911  *	Return value:
912  *				True returned if some dependencies left running
913  *
914  *	Parameters:
915  *		result		Pointer to cell we update if build failed
916  *		line		We get the dependencies from here
917  *		do_get		Allow use of sccs get in recursive doname()
918  *		target		The target to chase dependencies for
919  *		true_target	The real one for :: and lib(member)
920  *		doing_subtree	True if building a conditional macro subtree
921  *		out_of_date_tail Used to set the $? list
922  *		old_locals	Used for resetting the local macros
923  *		implicit	Called when scanning for implicit rules?
924  *		command		Place to stuff command
925  *		less		Set to $< value
926  *
927  *	Global variables used:
928  *		command_changed	Set if we suspect .make.state needs rewrite
929  *		debug_level	Should we trace actions?
930  *		force		The Name " FORCE", compared against
931  *		recursion_level	Used for tracing
932  *		rewrite_statefile Set if .make.state needs rewriting
933  *		wait_name	The Name ".WAIT", compared against
934  */
935 static Boolean
check_dependencies(Doname * result,Property line,Boolean do_get,Name target,Name true_target,Boolean doing_subtree,Chain * out_of_date_tail,Property old_locals,Boolean implicit,Property * command,Name less,Boolean rechecking_target,Boolean recheck_conditionals)936 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
937 {
938 	Boolean			dependencies_running;
939 	Dependency	dependency;
940 	Doname			dep_result;
941 	Boolean			dependency_changed = false;
942 
943 	line->body.line.dependency_time = file_doesnt_exist;
944 	if (line->body.line.query != NULL) {
945 		delete_query_chain(line->body.line.query);
946 	}
947 	line->body.line.query = NULL;
948 	line->body.line.is_out_of_date = false;
949 	dependencies_running = false;
950 	/*
951 	 * Run thru all the dependencies and call doname() recursively
952 	 * on each of them.
953 	 */
954 	for (dependency = line->body.line.dependencies;
955 	     dependency != NULL;
956 	     dependency = dependency->next) {
957 		Boolean this_dependency_changed = false;
958 
959 		if (!dependency->automatic &&
960 		    (rechecking_target || target->rechecking_target)) {
961 			/*
962 			 * We only bother with the autos when rechecking
963 			 */
964 			continue;
965 		}
966 
967 		if (dependency->name == wait_name) {
968 			/*
969 			 * The special target .WAIT means finish all of
970 			 * the prior dependencies before continuing.
971 			 */
972 			if (dependencies_running) {
973 				break;
974 			}
975 		} else if ((!parallel_ok(dependency->name, false)) &&
976 			   (dependencies_running)) {
977 			/*
978 			 * If we can't execute the current dependency in
979 			 * parallel, hold off the dependency processing
980 			 * to preserve the order of the dependencies.
981 			 */
982 			break;
983 		} else {
984 			timestruc_t	depe_time = file_doesnt_exist;
985 
986 
987 			if (true_target->is_member) {
988 				depe_time = exists(dependency->name);
989 			}
990 			if (dependency->built ||
991 			    (dependency->name->state == build_failed)) {
992 				dep_result = (Doname) dependency->name->state;
993 			} else {
994 				dep_result = doname_check(dependency->name,
995 							  do_get,
996 							  false,
997 							  (Boolean) dependency->automatic);
998 			}
999 			if (true_target->is_member || dependency->name->is_member) {
1000 				/* should compare only secs, cause lib members does not have nsec time resolution */
1001 				if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
1002 					this_dependency_changed =
1003 					  dependency_changed =
1004 					    true;
1005 				}
1006 			} else {
1007 				if (depe_time != dependency->name->stat.time) {
1008 					this_dependency_changed =
1009 					  dependency_changed =
1010 					    true;
1011 				}
1012 			}
1013 			dependency->built = true;
1014 			switch (dep_result) {
1015 			case build_running:
1016 				dependencies_running = true;
1017 				continue;
1018 			case build_failed:
1019 				*result = build_failed;
1020 				break;
1021 			case build_dont_know:
1022 /*
1023  * If make can't figure out how to make a dependency, maybe the dependency
1024  * is out of date. In this case, we just declare the target out of date
1025  * and go on. If we really need the dependency, the make'ing of the target
1026  * will fail. This will only happen for automatic (hidden) dependencies.
1027  */
1028 				if(!recheck_conditionals) {
1029 					line->body.line.is_out_of_date = true;
1030 				}
1031 				/*
1032 				 * Make sure the dependency is not saved
1033 				 * in the state file.
1034 				 */
1035 				dependency->stale = true;
1036 				rewrite_statefile =
1037 				  command_changed =
1038 				    true;
1039 				if (debug_level > 0) {
1040 					(void) printf(gettext("Target %s rebuilt because dependency %s does not exist\n"),
1041 						     true_target->string_mb,
1042 						     dependency->name->string_mb);
1043 				}
1044 				break;
1045 			}
1046 			if (dependency->name->depends_on_conditional) {
1047 				target->depends_on_conditional = true;
1048 			}
1049 			if (dependency->name == force) {
1050 				target->stat.time =
1051 				  dependency->name->stat.time;
1052 			}
1053 			/*
1054 			 * Propagate new timestamp from "member" to
1055 			 * "lib.a(member)".
1056 			 */
1057 			(void) exists(dependency->name);
1058 
1059 			/* Collect the timestamp of the youngest dependency */
1060 			line->body.line.dependency_time =
1061 			  MAX(dependency->name->stat.time,
1062 			      line->body.line.dependency_time);
1063 
1064 			/* Correction: do not consider nanosecs for members */
1065 			if(true_target->is_member || dependency->name->is_member) {
1066 				line->body.line.dependency_time.tv_nsec = 0;
1067 			}
1068 
1069 			if (debug_level > 1) {
1070 				(void) printf(gettext("%*sDate(%s)=%s \n"),
1071 					      recursion_level,
1072 					      "",
1073 					      dependency->name->string_mb,
1074 					      time_to_string(dependency->name->
1075 							     stat.time));
1076 				if (dependency->name->stat.time > line->body.line.dependency_time) {
1077 					(void) printf(gettext("%*sDate-dependencies(%s) set to %s\n"),
1078 						      recursion_level,
1079 						      "",
1080 						      true_target->string_mb,
1081 						      time_to_string(line->body.line.
1082 								     dependency_time));
1083 				}
1084 			}
1085 
1086 			/* Build the $? list */
1087 			if (true_target->is_member) {
1088 				if (this_dependency_changed == true) {
1089 					true_target->stat.time = dependency->name->stat.time;
1090 					true_target->stat.time.tv_sec--;
1091 				} else {
1092 					/* Dina:
1093 					 * The next statement is commented
1094 					 * out as a fix for bug #1051032.
1095 					 * if dependency hasn't changed
1096 					 * then there's no need to invalidate
1097 					 * true_target. This statemnt causes
1098 					 * make to take much longer to process
1099 					 * an already-built archive. Soren
1100 					 * said it was a quick fix for some
1101 					 * problem he doesn't remember.
1102 					true_target->stat.time = file_no_time;
1103 					 */
1104 					(void) exists(true_target);
1105 				}
1106 			} else {
1107 				(void) exists(true_target);
1108 			}
1109 			Boolean out_of_date;
1110 			if (true_target->is_member || dependency->name->is_member) {
1111 				out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1112 							                dependency->name->stat.time);
1113 			} else {
1114 				out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1115 							            dependency->name->stat.time);
1116 			}
1117 			if ((build_unconditional || out_of_date) &&
1118 			    (dependency->name != force) &&
1119 			    (dependency->stale == false)) {
1120 				*out_of_date_tail = ALLOC(Chain);
1121 				if (dependency->name->is_member &&
1122 				    (get_prop(dependency->name->prop,
1123 					      member_prop) != NULL)) {
1124 					(*out_of_date_tail)->name =
1125 					  get_prop(dependency->name->prop,
1126 						   member_prop)->
1127 						     body.member.member;
1128 				} else {
1129 					(*out_of_date_tail)->name =
1130 					  dependency->name;
1131 				}
1132 				(*out_of_date_tail)->next = NULL;
1133 				out_of_date_tail = &(*out_of_date_tail)->next;
1134 				if (debug_level > 0) {
1135 					if (dependency->name->stat.time == file_max_time) {
1136 						(void) printf(gettext("%*sBuilding %s because %s does not exist\n"),
1137 							      recursion_level,
1138 							      "",
1139 							      true_target->string_mb,
1140 							      dependency->name->string_mb);
1141 					} else {
1142 						(void) printf(gettext("%*sBuilding %s because it is out of date relative to %s\n"),
1143 							      recursion_level,
1144 							      "",
1145 							      true_target->string_mb,
1146 							      dependency->name->string_mb);
1147 					}
1148 				}
1149 			}
1150 			if (dependency->name == force) {
1151 				force->stat.time =
1152 				  file_max_time;
1153 				force->state = build_dont_know;
1154 			}
1155 		}
1156 	}
1157 	if (dependencies_running) {
1158 		if (doing_subtree) {
1159 			if (target->conditional_cnt > 0) {
1160 				reset_locals(target,
1161 					     old_locals,
1162 					     get_prop(target->prop,
1163 						      conditional_prop),
1164 					     0);
1165 			}
1166 			return true;
1167 		} else {
1168 			target->state = build_running;
1169 			add_pending(target,
1170 				    --recursion_level,
1171 				    do_get,
1172 				    implicit,
1173 				    false);
1174 			if (target->conditional_cnt > 0) {
1175 				reset_locals(target,
1176 					     old_locals,
1177 					     get_prop(target->prop,
1178 						      conditional_prop),
1179 					     0);
1180 			}
1181 			return true;
1182 		}
1183 	}
1184 	/*
1185 	 * Collect the timestamp of the youngest double colon target
1186 	 * dependency.
1187 	 */
1188 	if (target->is_double_colon_parent) {
1189 		for (dependency = line->body.line.dependencies;
1190 		     dependency != NULL;
1191 		     dependency = dependency->next) {
1192 			Property        tmp_line;
1193 
1194 			if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) {
1195 				if(tmp_line->body.line.dependency_time != file_max_time) {
1196 					target->stat.time =
1197 					  MAX(tmp_line->body.line.dependency_time,
1198 					      target->stat.time);
1199 				}
1200 			}
1201 		}
1202 	}
1203 	if ((true_target->is_member) && (dependency_changed == true)) {
1204 		true_target->stat.time = file_no_time;
1205 	}
1206 	/*
1207 	 * After scanning all the dependencies, we check the rule
1208 	 * if we found one.
1209 	 */
1210 	if (line->body.line.command_template != NULL) {
1211 		if (line->body.line.command_template_redefined) {
1212 			warning(gettext("Too many rules defined for target %s"),
1213 				target->string_mb);
1214 		}
1215 		*command = line;
1216 		/* Check if the target is out of date */
1217 		Boolean out_of_date;
1218 		if (true_target->is_member) {
1219 			out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1220 				                                line->body.line.dependency_time);
1221 		} else {
1222 			out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1223 				                            line->body.line.dependency_time);
1224 		}
1225 		if (build_unconditional || out_of_date){
1226 			if(!recheck_conditionals) {
1227 				line->body.line.is_out_of_date = true;
1228 			}
1229 		}
1230 		line->body.line.sccs_command = false;
1231 		line->body.line.target = true_target;
1232 		if(gnu_style) {
1233 
1234 			// set $< for explicit rule
1235 			if(line->body.line.dependencies != NULL) {
1236 				less = line->body.line.dependencies->name;
1237 			}
1238 
1239 			// set $* for explicit rule
1240 			Name			target_body;
1241 			Name			tt = true_target;
1242 			Property		member;
1243 			wchar_t	*target_end;
1244 			Dependency	suffix;
1245 			int		suffix_length;
1246 			Wstring			targ_string;
1247 			Wstring			suf_string;
1248 
1249 			if (true_target->is_member &&
1250 			    ((member = get_prop(target->prop, member_prop)) !=
1251 			     NULL)) {
1252 				tt = member->body.member.member;
1253 			}
1254 			targ_string.init(tt);
1255 			target_end = targ_string.get_string() + tt->hash.length;
1256 			for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
1257 				suffix_length = suffix->name->hash.length;
1258 				suf_string.init(suffix->name);
1259 				if (tt->hash.length < suffix_length) {
1260 					continue;
1261 				} else if (!IS_WEQUALN(suf_string.get_string(),
1262 						(target_end - suffix_length),
1263 						suffix_length)) {
1264 					continue;
1265 				}
1266 				target_body = GETNAME(
1267 					targ_string.get_string(),
1268 					(int)(tt->hash.length - suffix_length)
1269 				);
1270 				line->body.line.star = target_body;
1271 			}
1272 
1273 			// set result = build_ok so that implicit rules are not used.
1274 			if(*result == build_dont_know) {
1275 				*result = build_ok;
1276 			}
1277 		}
1278 		if (less != NULL) {
1279 			line->body.line.less = less;
1280 		}
1281 	}
1282 
1283 	return false;
1284 }
1285 
1286 /*
1287  *	dynamic_dependencies(target)
1288  *
1289  *	Checks if any dependency contains a macro ref
1290  *	If so, it replaces the dependency with the expanded version.
1291  *	Here, "$@" gets translated to target->string. That is
1292  *	the current name on the left of the colon in the
1293  *	makefile.  Thus,
1294  *		xyz:	s.$@.c
1295  *	translates into
1296  *		xyz:	s.xyz.c
1297  *
1298  *	Also, "$(@F)" translates to the same thing without a preceeding
1299  *	directory path (if one exists).
1300  *	Note, to enter "$@" on a dependency line in a makefile
1301  *	"$$@" must be typed. This is because make expands
1302  *	macros in dependency lists upon reading them.
1303  *	dynamic_dependencies() also expands file wildcards.
1304  *	If there are any Shell meta characters in the name,
1305  *	search the directory, and replace the dependency
1306  *	with the set of files the pattern matches
1307  *
1308  *	Parameters:
1309  *		target		Target to sanitize dependencies for
1310  *
1311  *	Global variables used:
1312  *		c_at		The Name "@", used to set macro value
1313  *		debug_level	Should we trace actions?
1314  *		dot		The Name ".", used to read directory
1315  *		recursion_level	Used for tracing
1316  */
1317 void
dynamic_dependencies(Name target)1318 dynamic_dependencies(Name target)
1319 {
1320 	wchar_t			pattern[MAXPATHLEN];
1321 	wchar_t	*p;
1322 	Property		line;
1323 	Dependency	dependency;
1324 	Dependency	*remove;
1325 	String_rec		string;
1326 	wchar_t			buffer[MAXPATHLEN];
1327 	Boolean	set_at = false;
1328 	wchar_t	*start;
1329 	Dependency		new_depe;
1330 	Boolean	reuse_cell;
1331 	Dependency		first_member;
1332 	Name			directory;
1333 	Name			lib;
1334 	Name			member;
1335 	Property		prop;
1336 	Name			true_target = target;
1337 	wchar_t			*library;
1338 
1339 	if ((line = get_prop(target->prop, line_prop)) == NULL) {
1340 		return;
1341 	}
1342 	/* If the target is constructed from a "::" target we consider that */
1343 	if (target->has_target_prop) {
1344 		true_target = get_prop(target->prop,
1345 				       target_prop)->body.target.target;
1346 	}
1347 	/* Scan all dependencies and process the ones that contain "$" chars */
1348 	for (dependency = line->body.line.dependencies;
1349 	     dependency != NULL;
1350 	     dependency = dependency->next) {
1351 		if (!dependency->name->dollar) {
1352 			continue;
1353 		}
1354 		target->has_depe_list_expanded = true;
1355 
1356 		/* The make macro $@ is bound to the target name once per */
1357 		/* invocation of dynamic_dependencies() */
1358 		if (!set_at) {
1359 			(void) SETVAR(c_at, true_target, false);
1360 			set_at = true;
1361 		}
1362 		/* Expand this dependency string */
1363 		INIT_STRING_FROM_STACK(string, buffer);
1364 		expand_value(dependency->name, &string, false);
1365 		/* Scan the expanded string. It could contain whitespace */
1366 		/* which mean it expands to several dependencies */
1367 		start = string.buffer.start;
1368 		while (iswspace(*start)) {
1369 			start++;
1370 		}
1371 		/* Remove the cell (later) if the macro was empty */
1372 		if (start[0] == (int) nul_char) {
1373 			dependency->name = NULL;
1374 		}
1375 
1376 /* azv 10/26/95 to fix bug BID_1170218 */
1377 		if ((start[0] == (int) period_char) &&
1378 		    (start[1] == (int) slash_char)) {
1379 			start += 2;
1380 		}
1381 /* azv */
1382 
1383 		first_member = NULL;
1384 		/* We use the original dependency cell for the first */
1385 		/* dependency from the expansion */
1386 		reuse_cell = true;
1387 		/* We also have to deal with dependencies that expand to */
1388 		/* lib.a(members) notation */
1389 		for (p = start; *p != (int) nul_char; p++) {
1390 			if ((*p == (int) parenleft_char)) {
1391 				lib = GETNAME(start, p - start);
1392 				lib->is_member = true;
1393 				first_member = dependency;
1394 				start = p + 1;
1395 				while (iswspace(*start)) {
1396 					start++;
1397 				}
1398 				break;
1399 			}
1400 		}
1401 		do {
1402 		    /* First skip whitespace */
1403 			for (p = start; *p != (int) nul_char; p++) {
1404 				if ((*p == (int) nul_char) ||
1405 				    iswspace(*p) ||
1406 				    (*p == (int) parenright_char)) {
1407 					break;
1408 				}
1409 			}
1410 			/* Enter dependency from expansion */
1411 			if (p != start) {
1412 				/* Create new dependency cell if */
1413 				/* this is not the first dependency */
1414 				/* picked from the expansion */
1415 				if (!reuse_cell) {
1416 					new_depe = ALLOC(Dependency);
1417 					new_depe->next = dependency->next;
1418 					new_depe->automatic = false;
1419 					new_depe->stale = false;
1420 					new_depe->built = false;
1421 					dependency->next = new_depe;
1422 					dependency = new_depe;
1423 				}
1424 				reuse_cell = false;
1425 				/* Internalize the dependency name */
1426 				// tolik. Fix for bug 4110429: inconsistent expansion for macros that
1427 				// include "//" and "/./"
1428 				//dependency->name = GETNAME(start, p - start);
1429 				dependency->name = normalize_name(start, p - start);
1430 				if ((debug_level > 0) &&
1431 				    (first_member == NULL)) {
1432 					(void) printf(gettext("%*sDynamic dependency `%s' for target `%s'\n"),
1433 						      recursion_level,
1434 						      "",
1435 						      dependency->name->string_mb,
1436 						      true_target->string_mb);
1437 				}
1438 				for (start = p; iswspace(*start); start++);
1439 				p = start;
1440 			}
1441 		} while ((*p != (int) nul_char) &&
1442 			 (*p != (int) parenright_char));
1443 		/* If the expansion was of lib.a(members) format we now */
1444 		/* enter the proper member cells */
1445 		if (first_member != NULL) {
1446 			/* Scan the new dependencies and transform them from */
1447 			/* "foo" to "lib.a(foo)" */
1448 			for (; 1; first_member = first_member->next) {
1449 				/* Build "lib.a(foo)" name */
1450 				INIT_STRING_FROM_STACK(string, buffer);
1451 				APPEND_NAME(lib,
1452 					      &string,
1453 					      (int) lib->hash.length);
1454 				append_char((int) parenleft_char, &string);
1455 				APPEND_NAME(first_member->name,
1456 					      &string,
1457 					      FIND_LENGTH);
1458 				append_char((int) parenright_char, &string);
1459 				member = first_member->name;
1460 				/* Replace "foo" with "lib.a(foo)" */
1461 				first_member->name =
1462 				  GETNAME(string.buffer.start, FIND_LENGTH);
1463 				if (string.free_after_use) {
1464 					retmem(string.buffer.start);
1465 				}
1466 				if (debug_level > 0) {
1467 					(void) printf(gettext("%*sDynamic dependency `%s' for target `%s'\n"),
1468 						      recursion_level,
1469 						      "",
1470 						      first_member->name->
1471 						      string_mb,
1472 						      true_target->string_mb);
1473 				}
1474 				first_member->name->is_member = lib->is_member;
1475 				/* Add member property to member */
1476 				prop = maybe_append_prop(first_member->name,
1477 							 member_prop);
1478 				prop->body.member.library = lib;
1479 				prop->body.member.entry = NULL;
1480 				prop->body.member.member = member;
1481 				if (first_member == dependency) {
1482 					break;
1483 				}
1484 			}
1485 		}
1486 	}
1487 	Wstring wcb;
1488 	/* Then scan all the dependencies again. This time we want to expand */
1489 	/* shell file wildcards */
1490 	for (remove = &line->body.line.dependencies, dependency = *remove;
1491 	     dependency != NULL;
1492 	     dependency = *remove) {
1493 		if (dependency->name == NULL) {
1494 			dependency = *remove = (*remove)->next;
1495 			continue;
1496 		}
1497 		/* If dependency name string contains shell wildcards */
1498 		/* replace the name with the expansion */
1499 		if (dependency->name->wildcard) {
1500 			wcb.init(dependency->name);
1501 			if ((start = (wchar_t *) wcschr(wcb.get_string(),
1502 					   (int) parenleft_char)) != NULL) {
1503 				/* lib(*) type pattern */
1504 				library = buffer;
1505 				(void) wcsncpy(buffer,
1506 					      wcb.get_string(),
1507 					      start - wcb.get_string());
1508 				buffer[start-wcb.get_string()] =
1509 				  (int) nul_char;
1510 				(void) wcsncpy(pattern,
1511 					      start + 1,
1512 (int) (dependency->name->hash.length-(start-wcb.get_string())-2));
1513 				pattern[dependency->name->hash.length -
1514 					(start-wcb.get_string()) - 2] =
1515 					  (int) nul_char;
1516 			} else {
1517 				library = NULL;
1518 				(void) wcsncpy(pattern,
1519 					      wcb.get_string(),
1520 					      (int) dependency->name->hash.length);
1521 				pattern[dependency->name->hash.length] =
1522 				  (int) nul_char;
1523 			}
1524 			start = (wchar_t *) wcsrchr(pattern, (int) slash_char);
1525 			if (start == NULL) {
1526 				directory = dot;
1527 				p = pattern;
1528 			} else {
1529 				directory = GETNAME(pattern, start-pattern);
1530 				p = start+1;
1531 			}
1532 			/* The expansion is handled by the read_dir() routine*/
1533 			if (read_dir(directory, p, line, library)) {
1534 				*remove = (*remove)->next;
1535 			} else {
1536 				remove = &dependency->next;
1537 			}
1538 		} else {
1539 			remove = &dependency->next;
1540 		}
1541         }
1542 
1543 	/* Then unbind $@ */
1544 	(void) SETVAR(c_at, (Name) NULL, false);
1545 }
1546 
1547 /*
1548  * DONE.
1549  *
1550  *	run_command(line)
1551  *
1552  *	Takes one Cmd_line and runs the commands from it.
1553  *
1554  *	Return value:
1555  *				Indicates if the command failed or not
1556  *
1557  *	Parameters:
1558  *		line		The command line to run
1559  *
1560  *	Global variables used:
1561  *		commands_done	Set if we do run command
1562  *		current_line	Set to the line we run a command from
1563  *		current_target	Set to the target we run a command for
1564  *		file_number	Used to form temp file name
1565  *		keep_state	Indicates that .KEEP_STATE is on
1566  *		make_state	The Name ".make.state", used to check timestamp
1567  *		parallel	True if currently building in parallel
1568  *		parallel_process_cnt Count of parallel processes running
1569  *		quest		Indicates that make -q is on
1570  *		rewrite_statefile Set if we do run a command
1571  *		sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value
1572  *		temp_file_directory Used to form temp fie name
1573  *		temp_file_name	Set to the name of the temp file
1574  *		touch		Indicates that make -t is on
1575  */
1576 static Doname
run_command(Property line,Boolean)1577 run_command(Property line, Boolean)
1578 {
1579 	Doname		result = build_ok;
1580 	Boolean	remember_only = false;
1581 	Name		target = line->body.line.target;
1582 	wchar_t			*string;
1583 	char			tmp_file_path[MAXPATHLEN];
1584 
1585 	if (!line->body.line.is_out_of_date && target->rechecking_target) {
1586 		target->rechecking_target = false;
1587 		return build_ok;
1588 	}
1589 
1590 	/*
1591 	 * Build the command if we know the target is out of date,
1592 	 * or if we want to check cmd consistency.
1593 	 */
1594 	if (line->body.line.is_out_of_date || keep_state) {
1595 		/* Hack for handling conditional macros in DMake. */
1596 		if (!line->body.line.dont_rebuild_command_used) {
1597 			build_command_strings(target, line);
1598 		}
1599 	}
1600 	/* Never mind */
1601 	if (!line->body.line.is_out_of_date) {
1602 		return build_ok;
1603 	}
1604 	/* If quest, then exit(1) because the target is out of date */
1605 	if (quest) {
1606 		if (posix) {
1607 			result = execute_parallel(line, true);
1608 		}
1609 		exit_status = 1;
1610 		exit(1);
1611 	}
1612 	/* We actually had to do something this time */
1613 	rewrite_statefile = commands_done = true;
1614 	/*
1615 	 * If this is an sccs command, we have to do some extra checking
1616 	 * and possibly complain. If the file can't be gotten because it's
1617 	 * checked out, we complain and behave as if the command was
1618 	 * executed eventhough we ignored the command.
1619 	 */
1620 	if (!touch &&
1621 	    line->body.line.sccs_command &&
1622 	    (target->stat.time != file_doesnt_exist) &&
1623 	    ((target->stat.mode & 0222) != 0)) {
1624 		fatal(gettext("%s is writable so it cannot be sccs gotten"),
1625 		      target->string_mb);
1626 		target->has_complained = remember_only = true;
1627 	}
1628 	/*
1629 	 * If KEEP_STATE is on, we make sure we have the timestamp for
1630 	 * .make.state. If .make.state changes during the command run,
1631 	 * we reread .make.state after the command. We also setup the
1632 	 * environment variable that asks utilities to report dependencies.
1633 	 */
1634 	if (!touch &&
1635 	    keep_state &&
1636 	    !remember_only) {
1637 		(void) exists(make_state);
1638 		if((strlen(temp_file_directory) == 1) &&
1639 			(temp_file_directory[0] == '/')) {
1640 		   tmp_file_path[0] = '\0';
1641 		} else {
1642 		   strcpy(tmp_file_path, temp_file_directory);
1643 		}
1644 		sprintf(mbs_buffer,
1645 				"%s/.make.dependency.%08x.%d.%d",
1646 			        tmp_file_path,
1647 			        hostid,
1648 			        getpid(),
1649 			        file_number++);
1650 		MBSTOWCS(wcs_buffer, mbs_buffer);
1651 		Boolean fnd;
1652 		temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd);
1653 		temp_file_name->stat.is_file = true;
1654 		int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2;
1655 		wchar_t *to = string = ALLOC_WC(len);
1656 		for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) {
1657 			if (*from == (int) space_char) {
1658 				*to++ = (int) backslash_char;
1659 			}
1660 			*to++ = *from++;
1661 		}
1662 		*to++ = (int) space_char;
1663 		MBSTOWCS(to, target->string_mb);
1664 		Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd);
1665 		(void) SETVAR(sunpro_dependencies,
1666 			      sprodep_name,
1667 			      false);
1668 		retmem(string);
1669 	} else {
1670 		temp_file_name = NULL;
1671 	}
1672 
1673 	/*
1674 	 * In case we are interrupted, we need to know what was going on.
1675 	 */
1676 	current_target = target;
1677 	/*
1678 	 * We also need to be able to save an empty command instead of the
1679 	 * interrupted one in .make.state.
1680 	 */
1681 	current_line = line;
1682 	if (remember_only) {
1683 		/* Empty block!!! */
1684 	} else if (touch) {
1685 		result = touch_command(line, target, result);
1686 		if (posix) {
1687 			result = execute_parallel(line, true);
1688 		}
1689 	} else {
1690 		/*
1691 		 * If this is not a touch run, we need to execute the
1692 		 * proper command(s) for the target.
1693 		 */
1694 		if (parallel) {
1695 			if (!parallel_ok(target, true)) {
1696 				/*
1697 				 * We are building in parallel, but
1698 				 * this target must be built in serial.
1699 				 */
1700 				/*
1701 				 * If nothing else is building,
1702 				 * do this one, else wait.
1703 				 */
1704 				if (parallel_process_cnt == 0) {
1705 					result = execute_parallel(line, true, target->localhost);
1706 				} else {
1707 					current_target = NULL;
1708 					current_line = NULL;
1709 /*
1710 					line->body.line.command_used = NULL;
1711  */
1712 					line->body.line.dont_rebuild_command_used = true;
1713 					return build_serial;
1714 				}
1715 			} else {
1716 				result = execute_parallel(line, false);
1717 				switch (result) {
1718 				case build_running:
1719 					return build_running;
1720 				case build_serial:
1721 					if (parallel_process_cnt == 0) {
1722 						result = execute_parallel(line, true, target->localhost);
1723 					} else {
1724 						current_target = NULL;
1725 						current_line = NULL;
1726 						target->parallel = false;
1727 						line->body.line.command_used =
1728 						    NULL;
1729 						return build_serial;
1730 					}
1731 				}
1732 			}
1733 		} else {
1734 			result = execute_parallel(line, true, target->localhost);
1735 		}
1736 	}
1737 	temp_file_name = NULL;
1738 	if (report_dependencies_level == 0){
1739 		update_target(line, result);
1740 	}
1741 	current_target = NULL;
1742 	current_line = NULL;
1743 	return result;
1744 }
1745 
1746 /*
1747  *	execute_serial(line)
1748  *
1749  *	Runs thru the command line for the target and
1750  *	executes the rules one by one.
1751  *
1752  *	Return value:
1753  *				The result of the command build
1754  *
1755  *	Parameters:
1756  *		line		The command to execute
1757  *
1758  *	Static variables used:
1759  *
1760  *	Global variables used:
1761  *		continue_after_error -k flag
1762  *		do_not_exec_rule -n flag
1763  *		report_dependencies -P flag
1764  *		silent		Don't echo commands before executing
1765  *		temp_file_name	Temp file for auto dependencies
1766  *		vpath_defined	If true, translate path for command
1767  */
1768 Doname
execute_serial(Property line)1769 execute_serial(Property line)
1770 {
1771 	int			child_pid = 0;
1772 	Boolean			printed_serial;
1773 	Doname			result = build_ok;
1774 	Cmd_line		rule, cmd_tail, command = NULL;
1775 	char			mbstring[MAXPATHLEN];
1776 	int			filed;
1777 	Name			target = line->body.line.target;
1778 
1779 	target->has_recursive_dependency = false;
1780 	// We have to create a copy of the rules chain for processing because
1781 	// the original one can be destroyed during .make.state file rereading.
1782 	for (rule = line->body.line.command_used;
1783 	     rule != NULL;
1784 	     rule = rule->next) {
1785 		if (command == NULL) {
1786 			command = cmd_tail = ALLOC(Cmd_line);
1787 		} else {
1788 			cmd_tail->next = ALLOC(Cmd_line);
1789 			cmd_tail = cmd_tail->next;
1790 		}
1791 		*cmd_tail = *rule;
1792 	}
1793 	if (command) {
1794 		cmd_tail->next = NULL;
1795 	}
1796 	for (rule = command; rule != NULL; rule = rule->next) {
1797 		if (posix && (touch || quest) && !rule->always_exec) {
1798 			continue;
1799 		}
1800 		if (vpath_defined) {
1801 			rule->command_line =
1802 			  vpath_translation(rule->command_line);
1803 		}
1804 		/* Echo command line, maybe. */
1805 		if ((rule->command_line->hash.length > 0) &&
1806 		    !silent &&
1807 		    (!rule->silent || do_not_exec_rule) &&
1808 		    (report_dependencies_level == 0)) {
1809 			(void) printf("%s\n", rule->command_line->string_mb);
1810 		}
1811 		if (rule->command_line->hash.length > 0) {
1812 			/* Do assignment if command line prefixed with "=" */
1813 			if (rule->assign) {
1814 				result = build_ok;
1815 				do_assign(rule->command_line, target);
1816 			} else if (report_dependencies_level == 0) {
1817 				/* Execute command line. */
1818 				setvar_envvar();
1819 				result = dosys(rule->command_line,
1820 				               (Boolean) rule->ignore_error,
1821 				               (Boolean) rule->make_refd,
1822 				               /* ds 98.04.23 bug #4085164. make should always show error messages */
1823 				               false,
1824 				               /* BOOLEAN(rule->silent &&
1825 				                       rule->ignore_error), */
1826 				               (Boolean) rule->always_exec,
1827 				               target);
1828 				check_state(temp_file_name);
1829 			}
1830 		} else {
1831 			result = build_ok;
1832 		}
1833 		if (result == build_failed) {
1834 			if (silent || rule->silent) {
1835 				(void) printf(gettext("The following command caused the error:\n%s\n"),
1836 				              rule->command_line->string_mb);
1837 			}
1838 			if (!rule->ignore_error && !ignore_errors) {
1839 				if (!continue_after_error) {
1840 					fatal(gettext("Command failed for target `%s'"),
1841 					      target->string_mb);
1842 				}
1843 				/*
1844 				 * Make sure a failing command is not
1845 				 * saved in .make.state.
1846 				 */
1847 				line->body.line.command_used = NULL;
1848 				break;
1849 			} else {
1850 				result = build_ok;
1851 			}
1852 		}
1853 	}
1854 	for (rule = command; rule != NULL; rule = cmd_tail) {
1855 		cmd_tail = rule->next;
1856 		free(rule);
1857 	}
1858 	command = NULL;
1859 	if (temp_file_name != NULL) {
1860 		free_name(temp_file_name);
1861 	}
1862         temp_file_name = NULL;
1863 
1864 	Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
1865 	if(spro != NULL) {
1866 		Name val = spro->body.macro.value;
1867 		if(val != NULL) {
1868 			free_name(val);
1869 			spro->body.macro.value = NULL;
1870 		}
1871 	}
1872 	spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
1873 	if(spro) {
1874 		char *val = spro->body.env_mem.value;
1875 		if(val != NULL) {
1876 			/*
1877 			 * Do not return memory allocated for SUNPRO_DEPENDENCIES
1878 			 * It will be returned in setvar_daemon() in macro.cc
1879 			 */
1880 			//	retmem_mb(val);
1881 			spro->body.env_mem.value = NULL;
1882 		}
1883 	}
1884 
1885         return result;
1886 }
1887 
1888 
1889 
1890 /*
1891  *	vpath_translation(cmd)
1892  *
1893  *	Translates one command line by
1894  *	checking each word. If the word has an alias it is translated.
1895  *
1896  *	Return value:
1897  *				The translated command
1898  *
1899  *	Parameters:
1900  *		cmd		Command to translate
1901  *
1902  *	Global variables used:
1903  */
1904 Name
vpath_translation(Name cmd)1905 vpath_translation(Name cmd)
1906 {
1907 	wchar_t			buffer[STRING_BUFFER_LENGTH];
1908 	String_rec		new_cmd;
1909 	wchar_t			*p;
1910 	wchar_t			*start;
1911 
1912 	if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) {
1913 		return cmd;
1914 	}
1915 	INIT_STRING_FROM_STACK(new_cmd, buffer);
1916 
1917 	Wstring wcb(cmd);
1918 	p = wcb.get_string();
1919 
1920 	while (*p != (int) nul_char) {
1921 		while (iswspace(*p) && (*p != (int) nul_char)) {
1922 			append_char(*p++, &new_cmd);
1923 		}
1924 		start = p;
1925 		while (!iswspace(*p) && (*p != (int) nul_char)) {
1926 			p++;
1927 		}
1928 		cmd = GETNAME(start, p - start);
1929 		if (cmd->has_vpath_alias_prop) {
1930 			cmd = get_prop(cmd->prop, vpath_alias_prop)->
1931 						body.vpath_alias.alias;
1932 			APPEND_NAME(cmd,
1933 				      &new_cmd,
1934 				      (int) cmd->hash.length);
1935 		} else {
1936 			append_string(start, &new_cmd, p - start);
1937 		}
1938 	}
1939 	cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH);
1940 	if (new_cmd.free_after_use) {
1941 		retmem(new_cmd.buffer.start);
1942 	}
1943 	return cmd;
1944 }
1945 
1946 /*
1947  *	check_state(temp_file_name)
1948  *
1949  *	Reads and checks the state changed by the previously executed command.
1950  *
1951  *	Parameters:
1952  *		temp_file_name	The auto dependency temp file
1953  *
1954  *	Global variables used:
1955  */
1956 void
check_state(Name temp_file_name)1957 check_state(Name temp_file_name)
1958 {
1959 	if (!keep_state) {
1960 		return;
1961 	}
1962 
1963 	/*
1964 	 * Then read the temp file that now might
1965 	 * contain dependency reports from utilities
1966 	 */
1967 	read_dependency_file(temp_file_name);
1968 
1969 	/*
1970 	 * And reread .make.state if it
1971 	 * changed (the command ran recursive makes)
1972 	 */
1973 	check_read_state_file();
1974 	if (temp_file_name != NULL) {
1975 		(void) unlink(temp_file_name->string_mb);
1976 	}
1977 }
1978 
1979 /*
1980  *	read_dependency_file(filename)
1981  *
1982  *	Read the temp file used for reporting dependencies to make
1983  *
1984  *	Parameters:
1985  *		filename	The name of the file with the state info
1986  *
1987  *	Global variables used:
1988  *		makefile_type	The type of makefile being read
1989  *		read_trace_level Debug flag
1990  *		temp_file_number The always increasing number for unique files
1991  *		trace_reader	Debug flag
1992  */
1993 static void
read_dependency_file(Name filename)1994 read_dependency_file(Name filename)
1995 {
1996 	Makefile_type	save_makefile_type;
1997 
1998 	if (filename == NULL) {
1999 		return;
2000 	}
2001 	filename->stat.time = file_no_time;
2002 	if (exists(filename) > file_doesnt_exist) {
2003 		save_makefile_type = makefile_type;
2004 		makefile_type = reading_cpp_file;
2005 		if (read_trace_level > 1) {
2006 			trace_reader = true;
2007 		}
2008 		temp_file_number++;
2009 		(void) read_simple_file(filename,
2010 					false,
2011 					false,
2012 					false,
2013 					false,
2014 					false,
2015 					false);
2016 		trace_reader = false;
2017 		makefile_type = save_makefile_type;
2018 	}
2019 }
2020 
2021 /*
2022  *	check_read_state_file()
2023  *
2024  *	Check if .make.state has changed
2025  *	If it has we reread it
2026  *
2027  *	Parameters:
2028  *
2029  *	Global variables used:
2030  *		make_state	Make state file name
2031  *		makefile_type	Type of makefile being read
2032  *		read_trace_level Debug flag
2033  *		trace_reader	Debug flag
2034  */
2035 static void
check_read_state_file(void)2036 check_read_state_file(void)
2037 {
2038 	timestruc_t		previous = make_state->stat.time;
2039 	Makefile_type	save_makefile_type;
2040 	Property	makefile;
2041 
2042 	make_state->stat.time = file_no_time;
2043 	if ((exists(make_state) == file_doesnt_exist) ||
2044 	    (make_state->stat.time == previous)) {
2045 		return;
2046 	}
2047 	save_makefile_type = makefile_type;
2048 	makefile_type = rereading_statefile;
2049 	/* Make sure we clear the old cached contents of .make.state */
2050 	makefile = maybe_append_prop(make_state, makefile_prop);
2051 	if (makefile->body.makefile.contents != NULL) {
2052 		retmem(makefile->body.makefile.contents);
2053 		makefile->body.makefile.contents = NULL;
2054 	}
2055 	if (read_trace_level > 1) {
2056 		trace_reader = true;
2057 	}
2058 	temp_file_number++;
2059 	(void) read_simple_file(make_state,
2060 				false,
2061 				false,
2062 				false,
2063 				false,
2064 				false,
2065 				true);
2066 	trace_reader = false;
2067 	makefile_type = save_makefile_type;
2068 }
2069 
2070 /*
2071  *	do_assign(line, target)
2072  *
2073  *	Handles runtime assignments for command lines prefixed with "=".
2074  *
2075  *	Parameters:
2076  *		line		The command that contains an assignment
2077  *		target		The Name of the target, used for error reports
2078  *
2079  *	Global variables used:
2080  *		assign_done	Set to indicate doname needs to reprocess
2081  */
2082 static void
do_assign(Name line,Name target)2083 do_assign(Name line, Name target)
2084 {
2085 	Wstring wcb(line);
2086 	wchar_t	*string = wcb.get_string();
2087 	wchar_t	*equal;
2088 	Name		name;
2089 	Boolean	append = false;
2090 
2091 	/*
2092 	 * If any runtime assignments are done, doname() must reprocess all
2093 	 * targets in the future since the macro values used to build the
2094 	 * command lines for the targets might have changed.
2095 	 */
2096 	assign_done = true;
2097 	/* Skip white space. */
2098 	while (iswspace(*string)) {
2099 		string++;
2100 	}
2101 	equal = string;
2102 	/* Find "+=" or "=". */
2103 	while (!iswspace(*equal) &&
2104 	       (*equal != (int) plus_char) &&
2105 	       (*equal != (int) equal_char)) {
2106 		equal++;
2107 	}
2108 	/* Internalize macro name. */
2109 	name = GETNAME(string, equal - string);
2110 	/* Skip over "+=" "=". */
2111 	while (!((*equal == (int) nul_char) ||
2112 		 (*equal == (int) equal_char) ||
2113 		 (*equal == (int) plus_char))) {
2114 		equal++;
2115 	}
2116 	switch (*equal) {
2117 	case nul_char:
2118 		fatal(gettext("= expected in rule `%s' for target `%s'"),
2119 		      line->string_mb,
2120 		      target->string_mb);
2121 	case plus_char:
2122 		append = true;
2123 		equal++;
2124 		break;
2125 	}
2126 	equal++;
2127 	/* Skip over whitespace in front of value. */
2128 	while (iswspace(*equal)) {
2129 		equal++;
2130 	}
2131 	/* Enter new macro value. */
2132 	enter_equal(name,
2133 		    GETNAME(equal, wcb.get_string() + line->hash.length - equal),
2134 		    append);
2135 }
2136 
2137 /*
2138  *	build_command_strings(target, line)
2139  *
2140  *	Builds the command string to used when
2141  *	building a target. If the string is different from the previous one
2142  *	is_out_of_date is set.
2143  *
2144  *	Parameters:
2145  *		target		Target to build commands for
2146  *		line		Where to stuff result
2147  *
2148  *	Global variables used:
2149  *		c_at		The Name "@", used to set macro value
2150  *		command_changed	Set if command is different from old
2151  *		debug_level	Should we trace activities?
2152  *		do_not_exec_rule Always echo when running -n
2153  *		empty_name	The Name "", used for empty rule
2154  *		funny		Semantics of characters
2155  *		ignore_errors	Used to init field for line
2156  *		is_conditional	Set to false befor evaling macro, checked
2157  *				after expanding macros
2158  *		keep_state	Indicates that .KEEP_STATE is on
2159  *		make_word_mentioned Set by macro eval, inits field for cmd
2160  *		query		The Name "?", used to set macro value
2161  *		query_mentioned	Set by macro eval, inits field for cmd
2162  *		recursion_level	Used for tracing
2163  *		silent		Used to init field for line
2164  */
2165 static void
build_command_strings(Name target,Property line)2166 build_command_strings(Name target, Property line)
2167 {
2168 	String_rec		command_line;
2169 	Cmd_line	command_template = line->body.line.command_template;
2170 	Cmd_line	*insert = &line->body.line.command_used;
2171 	Cmd_line	used = *insert;
2172 	wchar_t			buffer[STRING_BUFFER_LENGTH];
2173 	wchar_t			*start;
2174 	Name			new_command_line;
2175 	Boolean	new_command_longer = false;
2176 	Boolean	ignore_all_command_dependency = true;
2177 	Property		member;
2178 	static Name		less_name;
2179 	static Name		percent_name;
2180 	static Name		star;
2181 	Name			tmp_name;
2182 
2183 	if (less_name == NULL) {
2184 		MBSTOWCS(wcs_buffer, "<");
2185 		less_name = GETNAME(wcs_buffer, FIND_LENGTH);
2186 		MBSTOWCS(wcs_buffer, "%");
2187 		percent_name = GETNAME(wcs_buffer, FIND_LENGTH);
2188 		MBSTOWCS(wcs_buffer, "*");
2189 		star = GETNAME(wcs_buffer, FIND_LENGTH);
2190 	}
2191 
2192 	/* We have to check if a target depends on conditional macros */
2193 	/* Targets that do must be reprocessed by doname() each time around */
2194 	/* since the macro values used when building the target might have */
2195 	/* changed */
2196 	conditional_macro_used = false;
2197 	/* If we are building a lib.a(member) target $@ should be bound */
2198 	/* to lib.a */
2199 	if (target->is_member &&
2200 	    ((member = get_prop(target->prop, member_prop)) != NULL)) {
2201 		target = member->body.member.library;
2202 	}
2203 	/* If we are building a "::" help target $@ should be bound to */
2204 	/* the real target name */
2205 	/* A lib.a(member) target is never :: */
2206 	if (target->has_target_prop) {
2207 		target = get_prop(target->prop, target_prop)->
2208 		  body.target.target;
2209 	}
2210 	/* Bind the magic macros that make supplies */
2211 	tmp_name = target;
2212 	if(tmp_name != NULL) {
2213 		if (tmp_name->has_vpath_alias_prop) {
2214 			tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2215 					body.vpath_alias.alias;
2216 		}
2217 	}
2218 	(void) SETVAR(c_at, tmp_name, false);
2219 
2220 	tmp_name = line->body.line.star;
2221 	if(tmp_name != NULL) {
2222 		if (tmp_name->has_vpath_alias_prop) {
2223 			tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2224 					body.vpath_alias.alias;
2225 		}
2226 	}
2227 	(void) SETVAR(star, tmp_name, false);
2228 
2229 	tmp_name = line->body.line.less;
2230 	if(tmp_name != NULL) {
2231 		if (tmp_name->has_vpath_alias_prop) {
2232 			tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2233 					body.vpath_alias.alias;
2234 		}
2235 	}
2236 	(void) SETVAR(less_name, tmp_name, false);
2237 
2238 	tmp_name = line->body.line.percent;
2239 	if(tmp_name != NULL) {
2240 		if (tmp_name->has_vpath_alias_prop) {
2241 			tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2242 					body.vpath_alias.alias;
2243 		}
2244 	}
2245 	(void) SETVAR(percent_name, tmp_name, false);
2246 
2247 	/* $? is seldom used and it is expensive to build */
2248 	/* so we store the list form and build the string on demand */
2249 	Chain query_list = NULL;
2250 	Chain *query_list_tail = &query_list;
2251 
2252 	for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) {
2253 		*query_list_tail = ALLOC(Chain);
2254 		(*query_list_tail)->name = ch->name;
2255 		if ((*query_list_tail)->name->has_vpath_alias_prop) {
2256 			(*query_list_tail)->name =
2257 				get_prop((*query_list_tail)->name->prop,
2258 					vpath_alias_prop)->body.vpath_alias.alias;
2259 		}
2260 		(*query_list_tail)->next = NULL;
2261 		query_list_tail = &(*query_list_tail)->next;
2262 	}
2263 	(void) setvar_daemon(query,
2264 			     (Name) query_list,
2265 			     false,
2266 			     chain_daemon,
2267                              false,
2268                              debug_level);
2269 
2270 	/* build $^ */
2271 	Chain hat_list = NULL;
2272 	Chain *hat_list_tail = &hat_list;
2273 
2274 	for (Dependency dependency = line->body.line.dependencies;
2275 		dependency != NULL;
2276 		dependency = dependency->next) {
2277 		/* skip automatic dependencies */
2278 		if (!dependency->automatic) {
2279 			if ((dependency->name != force) &&
2280 				(dependency->stale == false)) {
2281 				*hat_list_tail = ALLOC(Chain);
2282 
2283 				if (dependency->name->is_member &&
2284 					(get_prop(dependency->name->prop, member_prop) != NULL)) {
2285 					(*hat_list_tail)->name =
2286 							get_prop(dependency->name->prop,
2287 								member_prop)->body.member.member;
2288 				} else {
2289 					(*hat_list_tail)->name = dependency->name;
2290 				}
2291 
2292 				if((*hat_list_tail)->name != NULL) {
2293 					if ((*hat_list_tail)->name->has_vpath_alias_prop) {
2294 						(*hat_list_tail)->name =
2295 							get_prop((*hat_list_tail)->name->prop,
2296 								vpath_alias_prop)->body.vpath_alias.alias;
2297 					}
2298 				}
2299 
2300 				(*hat_list_tail)->next = NULL;
2301 				hat_list_tail = &(*hat_list_tail)->next;
2302 			}
2303 		}
2304 	}
2305 	(void) setvar_daemon(hat,
2306 			     (Name) hat_list,
2307 			     false,
2308 			     chain_daemon,
2309                              false,
2310                              debug_level);
2311 
2312 /* We have two command sequences we need to handle */
2313 /* The old one that we probably read from .make.state */
2314 /* and the new one we are building that will replace the old one */
2315 /* Even when KEEP_STATE is not on we build a new command sequence and store */
2316 /* it in the line prop. This command sequence is then executed by */
2317 /* run_command(). If KEEP_STATE is on it is also later written to */
2318 /* .make.state. The routine replaces the old command line by line with the */
2319 /* new one trying to reuse Cmd_lines */
2320 
2321 	/* If there is no old command_used we have to start creating */
2322 	/* Cmd_lines to keep the new cmd in */
2323 	if (used == NULL) {
2324 		new_command_longer = true;
2325 		*insert = used = ALLOC(Cmd_line);
2326 		used->next = NULL;
2327 		used->command_line = NULL;
2328 		insert = &used->next;
2329 	}
2330 	/* Run thru the template for the new command and build the expanded */
2331 	/* new command lines */
2332 	for (;
2333 	     command_template != NULL;
2334 	     command_template = command_template->next, insert = &used->next, used = *insert) {
2335 		/* If there is no old command_used Cmd_line we need to */
2336 		/* create one and say that cmd consistency failed */
2337 		if (used == NULL) {
2338 			new_command_longer = true;
2339 			*insert = used = ALLOC(Cmd_line);
2340 			used->next = NULL;
2341 			used->command_line = empty_name;
2342 		}
2343 		/* Prepare the Cmd_line for the processing */
2344 		/* The command line prefixes "@-=?" are stripped and that */
2345 		/* information is saved in the Cmd_line */
2346 		used->assign = false;
2347 		used->ignore_error = ignore_errors;
2348 		used->silent = silent;
2349 		used->always_exec = false;
2350 		/* Expand the macros in the command line */
2351 		INIT_STRING_FROM_STACK(command_line, buffer);
2352 		make_word_mentioned =
2353 		  query_mentioned =
2354 		    false;
2355 		expand_value(command_template->command_line, &command_line, true);
2356 		/* If the macro $(MAKE) is mentioned in the command */
2357 		/* "make -n" runs actually execute the command */
2358 		used->make_refd = make_word_mentioned;
2359 		used->ignore_command_dependency = query_mentioned;
2360 		/* Strip the prefixes */
2361 		start = command_line.buffer.start;
2362 		for (;
2363 		     iswspace(*start) ||
2364 		     (get_char_semantics_value(*start) & (int) command_prefix_sem);
2365 		     start++) {
2366 			switch (*start) {
2367 			case question_char:
2368 				used->ignore_command_dependency = true;
2369 				break;
2370 			case exclam_char:
2371 				used->ignore_command_dependency = false;
2372 				break;
2373 			case equal_char:
2374 				used->assign = true;
2375 				break;
2376 			case hyphen_char:
2377 				used->ignore_error = true;
2378 				break;
2379 			case at_char:
2380 				if (!do_not_exec_rule) {
2381 					used->silent = true;
2382 				}
2383 				break;
2384 			case plus_char:
2385 				if(posix) {
2386 				  used->always_exec  = true;
2387 				}
2388 				break;
2389 			}
2390 		}
2391 		/* If all command lines of the template are prefixed with "?"*/
2392 		/* the VIRTUAL_ROOT is not used for cmd consistency checks */
2393 		if (!used->ignore_command_dependency) {
2394 			ignore_all_command_dependency = false;
2395 		}
2396 		/* Internalize the expanded and stripped command line */
2397 		new_command_line = GETNAME(start, FIND_LENGTH);
2398 		if ((used->command_line == NULL) &&
2399 		    (line->body.line.sccs_command)) {
2400 			used->command_line = new_command_line;
2401 			new_command_longer = false;
2402 		}
2403 		/* Compare it with the old one for command consistency */
2404 		if (used->command_line != new_command_line) {
2405 			Name vpath_translated = vpath_translation(new_command_line);
2406 			if (keep_state &&
2407 			    !used->ignore_command_dependency && (vpath_translated != used->command_line)) {
2408 				if (debug_level > 0) {
2409 					if (used->command_line != NULL
2410 					    && *used->command_line->string_mb !=
2411 					    '\0') {
2412 						(void) printf(gettext("%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"),
2413 							      recursion_level,
2414 							      "",
2415 							      target->string_mb,
2416 							      vpath_translated->string_mb,
2417 							      recursion_level,
2418 							      "",
2419 							      used->
2420 							      command_line->
2421 							      string_mb);
2422 					} else {
2423 						(void) printf(gettext("%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"),
2424 							      recursion_level,
2425 							      "",
2426 							      target->string_mb,
2427 							      vpath_translated->string_mb,
2428 							      recursion_level,
2429 							      "");
2430 					}
2431 				}
2432 				command_changed = true;
2433                                 line->body.line.is_out_of_date = true;
2434 			}
2435 			used->command_line = new_command_line;
2436 		}
2437 		if (command_line.free_after_use) {
2438 			retmem(command_line.buffer.start);
2439 		}
2440 	}
2441 	/* Check if the old command is longer than the new for */
2442 	/* command consistency */
2443 	if (used != NULL) {
2444 		*insert = NULL;
2445 		if (keep_state &&
2446 		    !ignore_all_command_dependency) {
2447 			if (debug_level > 0) {
2448 				(void) printf(gettext("%*sBuilding %s because new command shorter than old\n"),
2449 					      recursion_level,
2450 					      "",
2451 					      target->string_mb);
2452 			}
2453 			command_changed = true;
2454                         line->body.line.is_out_of_date = true;
2455 		}
2456 	}
2457 	/* Check if the new command is longer than the old command for */
2458 	/* command consistency */
2459 	if (new_command_longer &&
2460 	    !ignore_all_command_dependency &&
2461 	    keep_state) {
2462 		if (debug_level > 0) {
2463 			(void) printf(gettext("%*sBuilding %s because new command longer than old\n"),
2464 				      recursion_level,
2465 				      "",
2466 				      target->string_mb);
2467 		}
2468 		command_changed = true;
2469                 line->body.line.is_out_of_date = true;
2470 	}
2471 	/* Unbind the magic macros */
2472 	(void) SETVAR(c_at, (Name) NULL, false);
2473 	(void) SETVAR(star, (Name) NULL, false);
2474 	(void) SETVAR(less_name, (Name) NULL, false);
2475 	(void) SETVAR(percent_name, (Name) NULL, false);
2476 	(void) SETVAR(query, (Name) NULL, false);
2477         if (query_list != NULL) {
2478 		delete_query_chain(query_list);
2479         }
2480 	(void) SETVAR(hat, (Name) NULL, false);
2481         if (hat_list != NULL) {
2482 		delete_query_chain(hat_list);
2483         }
2484 
2485 	if (conditional_macro_used) {
2486 		target->conditional_macro_list = cond_macro_list;
2487 		cond_macro_list = NULL;
2488 		target->depends_on_conditional = true;
2489 	}
2490 }
2491 
2492 /*
2493  *	touch_command(line, target, result)
2494  *
2495  *	If this is an "make -t" run we do this.
2496  *	We touch all targets in the target group ("foo + fie:") if any.
2497  *
2498  *	Return value:
2499  *				Indicates if the command failed or not
2500  *
2501  *	Parameters:
2502  *		line		The command line to update
2503  *		target		The target we are touching
2504  *		result		Initial value for the result we return
2505  *
2506  *	Global variables used:
2507  *		do_not_exec_rule Indicates that -n is on
2508  *		silent		Do not echo commands
2509  */
2510 static Doname
touch_command(Property line,Name target,Doname result)2511 touch_command(Property line, Name target, Doname result)
2512 {
2513 	Name			name;
2514 	Chain		target_group;
2515 	String_rec		touch_string;
2516 	wchar_t			buffer[MAXPATHLEN];
2517 	Name			touch_cmd;
2518 	Cmd_line		rule;
2519 
2520 	for (name = target, target_group = NULL; name != NULL;) {
2521 		if (!name->is_member) {
2522 			/*
2523 			 * Build a touch command that can be passed
2524 			 * to dosys(). If KEEP_STATE is on, "make -t"
2525 			 * will save the proper command, not the
2526 			 * "touch" in .make.state.
2527 			 */
2528 			INIT_STRING_FROM_STACK(touch_string, buffer);
2529 			MBSTOWCS(wcs_buffer, "touch ");
2530 			append_string(wcs_buffer, &touch_string, FIND_LENGTH);
2531 			touch_cmd = name;
2532 			if (name->has_vpath_alias_prop) {
2533 				touch_cmd = get_prop(name->prop,
2534 						 vpath_alias_prop)->
2535 						   body.vpath_alias.alias;
2536 			}
2537 			APPEND_NAME(touch_cmd,
2538 				      &touch_string,
2539 				      FIND_LENGTH);
2540 			touch_cmd = GETNAME(touch_string.buffer.start,
2541 					    FIND_LENGTH);
2542 			if (touch_string.free_after_use) {
2543 				retmem(touch_string.buffer.start);
2544 			}
2545 			if (!silent ||
2546 			    do_not_exec_rule &&
2547 			    (target_group == NULL)) {
2548 				(void) printf("%s\n", touch_cmd->string_mb);
2549 			}
2550 			/* Run the touch command, or simulate it */
2551 			if (!do_not_exec_rule) {
2552 				result = dosys(touch_cmd,
2553 					       false,
2554 					       false,
2555 					       false,
2556 					       false,
2557 					       name);
2558 			} else {
2559 				result = build_ok;
2560 			}
2561 		} else {
2562 			result = build_ok;
2563 		}
2564 		if (target_group == NULL) {
2565 			target_group = line->body.line.target_group;
2566 		} else {
2567 			target_group = target_group->next;
2568 		}
2569 		if (target_group != NULL) {
2570 			name = target_group->name;
2571 		} else {
2572 			name = NULL;
2573 		}
2574 	}
2575 	return result;
2576 }
2577 
2578 /*
2579  *	update_target(line, result)
2580  *
2581  *	updates the status of a target after executing its commands.
2582  *
2583  *	Parameters:
2584  *		line		The command line block to update
2585  *		result		Indicates that build is OK so can update
2586  *
2587  *	Global variables used:
2588  *		do_not_exec_rule Indicates that -n is on
2589  *		touch		Fake the new timestamp if we are just touching
2590  */
2591 void
update_target(Property line,Doname result)2592 update_target(Property line, Doname result)
2593 {
2594 	Name			target;
2595 	Chain			target_group;
2596 	Property		line2;
2597 	timestruc_t		old_stat_time;
2598 	Property		member;
2599 
2600 	/*
2601 	 * [tolik] Additional fix for bug 1063790. It was fixed
2602 	 * for serial make long ago, but DMake dumps core when
2603 	 * target is a symlink and sccs file is newer then target.
2604 	 * In this case, finish_children() calls update_target()
2605 	 * with line==NULL.
2606 	 */
2607 	if(line == NULL) {
2608 		/* XXX. Should we do anything here? */
2609 		return;
2610 	}
2611 
2612 	target = line->body.line.target;
2613 
2614 	if ((result == build_ok) && (line->body.line.command_used != NULL)) {
2615 		if (do_not_exec_rule ||
2616 		    touch ||
2617 		    (target->is_member &&
2618 		     (line->body.line.command_template != NULL) &&
2619 		     (line->body.line.command_template->command_line->string_mb[0] == 0) &&
2620 		     (line->body.line.command_template->next == NULL))) {
2621 			/* If we are simulating execution we need to fake a */
2622 			/* new timestamp for the target we didnt build */
2623 			target->stat.time = file_max_time;
2624 		} else {
2625 			/*
2626 			 * If we really built the target we read the new
2627 			 * timestamp.
2628 			 * Fix for bug #1110906: if .c file is newer than
2629 			 * the corresponding .o file which is in an archive
2630 			 * file, make will compile the .c file but it won't
2631 			 * update the object in the .a file.
2632 			 */
2633 			old_stat_time = target->stat.time;
2634 			target->stat.time = file_no_time;
2635 			(void) exists(target);
2636 			if ((target->is_member) &&
2637 			    (target->stat.time == old_stat_time)) {
2638 				member = get_prop(target->prop, member_prop);
2639 				if (member != NULL) {
2640 					target->stat.time = member->body.member.library->stat.time;
2641 					target->stat.time.tv_sec++;
2642 				}
2643 			}
2644 		}
2645 		/* If the target is part of a group we need to propagate the */
2646 		/* result of the run to all members */
2647 		for (target_group = line->body.line.target_group;
2648 		     target_group != NULL;
2649 		     target_group = target_group->next) {
2650 			target_group->name->stat.time = target->stat.time;
2651 			line2 = maybe_append_prop(target_group->name,
2652 						  line_prop);
2653 			line2->body.line.command_used =
2654 			  line->body.line.command_used;
2655 			line2->body.line.target = target_group->name;
2656 		}
2657 	}
2658 	target->has_built = true;
2659 }
2660 
2661 /*
2662  *	sccs_get(target, command)
2663  *
2664  *	Figures out if it possible to sccs get a file
2665  *	and builds the command to do it if it is.
2666  *
2667  *	Return value:
2668  *				Indicates if sccs get failed or not
2669  *
2670  *	Parameters:
2671  *		target		Target to get
2672  *		command		Where to deposit command to use
2673  *
2674  *	Global variables used:
2675  *		debug_level	Should we trace activities?
2676  *		recursion_level	Used for tracing
2677  *		sccs_get_rule	The rule to used for sccs getting
2678  */
2679 static Doname
sccs_get(Name target,Property * command)2680 sccs_get(Name target, Property *command)
2681 {
2682 	int		result;
2683 	char			link[MAXPATHLEN];
2684 	String_rec		string;
2685 	wchar_t			name[MAXPATHLEN];
2686 	wchar_t	*p;
2687 	timestruc_t		sccs_time;
2688 	Property	line;
2689 	int			sym_link_depth = 0;
2690 
2691 	/* For sccs, we need to chase symlinks. */
2692         while (target->stat.is_sym_link) {
2693 		if (sym_link_depth++ > 90) {
2694 			fatal(gettext("Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."),
2695 			      target->string_mb);
2696 		}
2697                 /* Read the value of the link. */
2698                 result = readlink_vroot(target->string_mb,
2699 					link,
2700 					sizeof(link),
2701 					NULL,
2702 					VROOT_DEFAULT);
2703                 if (result == -1) {
2704                         fatal(gettext("Can't read symbolic link `%s': %s"),
2705                               target->string_mb, errmsg(errno));
2706 		}
2707 		link[result] = 0;
2708                 /* Use the value to build the proper filename. */
2709                 INIT_STRING_FROM_STACK(string, name);
2710 
2711 		Wstring wcb(target);
2712                 if ((link[0] != slash_char) &&
2713                     ((p = (wchar_t *) wcsrchr(wcb.get_string(), slash_char)) != NULL)) {
2714                         append_string(wcb.get_string(), &string, p - wcb.get_string() + 1);
2715 		}
2716                 append_string(link, &string, result);
2717                 /* Replace the old name with the translated name. */
2718 		target = normalize_name(string.buffer.start, string.text.p - string.buffer.start);
2719                 (void) exists(target);
2720                 if (string.free_after_use) {
2721                         retmem(string.buffer.start);
2722 		}
2723         }
2724 
2725 	/*
2726 	 * read_dir() also reads the ?/SCCS dir and saves information
2727 	 * about which files have SCSC/s. files.
2728 	 */
2729 	if (target->stat.has_sccs == DONT_KNOW_SCCS) {
2730 		read_directory_of_file(target);
2731 	}
2732 	switch (target->stat.has_sccs) {
2733 	case DONT_KNOW_SCCS:
2734 		/* We dont know by now there is no SCCS/s.* */
2735 		target->stat.has_sccs = NO_SCCS;
2736 		/* FALLTHROUGH */
2737 	case NO_SCCS:
2738 		/*
2739 		 * If there is no SCCS/s.* but the plain file exists,
2740 		 * we say things are OK.
2741 		 */
2742 		if (target->stat.time > file_doesnt_exist) {
2743 			return build_ok;
2744 		}
2745 		/* If we cant find the plain file, we give up. */
2746 		return build_dont_know;
2747 	case HAS_SCCS:
2748 		/*
2749 		 * Pay dirt. We now need to figure out if the plain file
2750 		 * is out of date relative to the SCCS/s.* file.
2751 		 */
2752 		sccs_time = exists(get_prop(target->prop,
2753 					    sccs_prop)->body.sccs.file);
2754 		break;
2755 	}
2756 
2757 	if ((!target->has_complained &&
2758 	    (sccs_time != file_doesnt_exist) &&
2759 	    (sccs_get_rule != NULL))) {
2760 		/* only checking */
2761 		if (command == NULL) {
2762 			return build_ok;
2763 		}
2764 		/*
2765 		 * We provide a command line for the target. The line is a
2766 		 * "sccs get" command from default.mk.
2767 		 */
2768 		line = maybe_append_prop(target, line_prop);
2769 		*command = line;
2770 		if (sccs_time > target->stat.time) {
2771 			/*
2772 			 * And only if the plain file is out of date do we
2773 			 * request execution of the command.
2774 			 */
2775 			line->body.line.is_out_of_date = true;
2776 			if (debug_level > 0) {
2777 				(void) printf(gettext("%*sSccs getting %s because s. file is younger than source file\n"),
2778 					      recursion_level,
2779 					      "",
2780 					      target->string_mb);
2781 			}
2782 		}
2783 		line->body.line.sccs_command = true;
2784 		line->body.line.command_template = sccs_get_rule;
2785 		if(!svr4 && (!allrules_read || posix)) {
2786 		   if((target->prop) &&
2787 		      (target->prop->body.sccs.file) &&
2788 		      (target->prop->body.sccs.file->string_mb)) {
2789 		      if((strlen(target->prop->body.sccs.file->string_mb) ==
2790 			strlen(target->string_mb) + 2) &&
2791 		        (target->prop->body.sccs.file->string_mb[0] == 's') &&
2792 		        (target->prop->body.sccs.file->string_mb[1] == '.')) {
2793 
2794 		         line->body.line.command_template = get_posix_rule;
2795 		      }
2796 		   }
2797 		}
2798 		line->body.line.target = target;
2799 		/*
2800 		 * Also make sure the rule is build with $* and $<
2801 		 * bound properly.
2802 		 */
2803 		line->body.line.star = NULL;
2804 		line->body.line.less = NULL;
2805 		line->body.line.percent = NULL;
2806 		return build_ok;
2807 	}
2808 	return build_dont_know;
2809 }
2810 
2811 /*
2812  *	read_directory_of_file(file)
2813  *
2814  *	Reads the directory the specified file lives in.
2815  *
2816  *	Parameters:
2817  *		file		The file we need to read dir for
2818  *
2819  *	Global variables used:
2820  *		dot		The Name ".", used as the default dir
2821  */
2822 void
read_directory_of_file(Name file)2823 read_directory_of_file(Name file)
2824 {
2825 
2826 	Wstring file_string(file);
2827 	wchar_t * wcb = file_string.get_string();
2828 	wchar_t usr_include_buf[MAXPATHLEN];
2829 	wchar_t usr_include_sys_buf[MAXPATHLEN];
2830 
2831 	Name		directory = dot;
2832 	wchar_t	*p = (wchar_t *) wcsrchr(wcb,
2833 							(int) slash_char);
2834 	int		length = p - wcb;
2835 	static Name		usr_include;
2836 	static Name		usr_include_sys;
2837 
2838 	if (usr_include == NULL) {
2839 		MBSTOWCS(usr_include_buf, "/usr/include");
2840 		usr_include = GETNAME(usr_include_buf, FIND_LENGTH);
2841 		MBSTOWCS(usr_include_sys_buf, "/usr/include/sys");
2842 		usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH);
2843 	}
2844 
2845 	/*
2846 	 * If the filename contains a "/" we have to extract the path
2847 	 * Else the path defaults to ".".
2848 	 */
2849 	if (p != NULL) {
2850 		/*
2851 		 * Check some popular directories first to possibly
2852 		 * save time. Compare string length first to gain speed.
2853 		 */
2854 		if ((usr_include->hash.length == length) &&
2855 		    IS_WEQUALN(usr_include_buf,
2856 			       wcb,
2857 			       length)) {
2858 			directory = usr_include;
2859 		} else if ((usr_include_sys->hash.length == length) &&
2860 		           IS_WEQUALN(usr_include_sys_buf,
2861 		                      wcb,
2862 		                      length)) {
2863 			directory = usr_include_sys;
2864 		} else {
2865 			directory = GETNAME(wcb, length);
2866 		}
2867 	}
2868 	(void) read_dir(directory,
2869 			(wchar_t *) NULL,
2870 			(Property) NULL,
2871 			(wchar_t *) NULL);
2872 }
2873 
2874 /*
2875  *	add_pattern_conditionals(target)
2876  *
2877  *	Scan the list of conditionals defined for pattern targets and add any
2878  *	that match this target to its list of conditionals.
2879  *
2880  *	Parameters:
2881  *		target		The target we should add conditionals for
2882  *
2883  *	Global variables used:
2884  *		conditionals	The list of pattern conditionals
2885  */
2886 static void
add_pattern_conditionals(Name target)2887 add_pattern_conditionals(Name target)
2888 {
2889 	Property	conditional;
2890 	Property		new_prop;
2891 	Property		*previous;
2892 	Name_rec		dummy;
2893 	wchar_t			*pattern;
2894 	wchar_t			*percent;
2895 	int			length;
2896 
2897 	Wstring wcb(target);
2898 	Wstring wcb1;
2899 
2900 	for (conditional = get_prop(conditionals->prop, conditional_prop);
2901 	     conditional != NULL;
2902 	     conditional = get_prop(conditional->next, conditional_prop)) {
2903 		wcb1.init(conditional->body.conditional.target);
2904 		pattern = wcb1.get_string();
2905 		if (pattern[1] != 0) {
2906 			percent = (wchar_t *) wcschr(pattern, (int) percent_char);
2907 			/* Check for possible buffer under-read */
2908 			if ((length = wcb.length()-wcslen(percent+1)) <= 0) {
2909 				continue;
2910 			}
2911 			if (!wcb.equaln(pattern, percent-pattern) ||
2912 			    !IS_WEQUAL(wcb.get_string(length), percent+1)) {
2913 				continue;
2914 			}
2915 		}
2916 		for (previous = &target->prop;
2917 		     *previous != NULL;
2918 		     previous = &(*previous)->next) {
2919 			if (((*previous)->type == conditional_prop) &&
2920 			    ((*previous)->body.conditional.sequence >
2921 			     conditional->body.conditional.sequence)) {
2922 				break;
2923 			}
2924 		}
2925 		if (*previous == NULL) {
2926 			new_prop = append_prop(target, conditional_prop);
2927 		} else {
2928 			dummy.prop = NULL;
2929 			new_prop = append_prop(&dummy, conditional_prop);
2930 			new_prop->next = *previous;
2931 			*previous = new_prop;
2932 		}
2933 		target->conditional_cnt++;
2934 		new_prop->body.conditional = conditional->body.conditional;
2935 	}
2936 }
2937 
2938 /*
2939  *	set_locals(target, old_locals)
2940  *
2941  *	Sets any conditional macros for the target.
2942  *	Each target carries a possibly empty set of conditional properties.
2943  *
2944  *	Parameters:
2945  *		target		The target to set conditional macros for
2946  *		old_locals	Space to store old values in
2947  *
2948  *	Global variables used:
2949  *		debug_level	Should we trace activity?
2950  *		is_conditional	We need to preserve this value
2951  *		recursion_level	Used for tracing
2952  */
2953 void
set_locals(Name target,Property old_locals)2954 set_locals(Name target, Property old_locals)
2955 {
2956 	Property	conditional;
2957 	int		i;
2958 	Boolean	saved_conditional_macro_used;
2959 	Chain			cond_name;
2960 	Chain			cond_chain;
2961 
2962 	if (target->dont_activate_cond_values) {
2963 		return;
2964 	}
2965 
2966 	saved_conditional_macro_used = conditional_macro_used;
2967 
2968 	/* Scan the list of conditional properties and apply each one */
2969 	for (conditional = get_prop(target->prop, conditional_prop), i = 0;
2970 	     conditional != NULL;
2971 	     conditional = get_prop(conditional->next, conditional_prop),
2972 	     i++) {
2973 		/* Save the old value */
2974 		old_locals[i].body.macro =
2975 		  maybe_append_prop(conditional->body.conditional.name,
2976 				    macro_prop)->body.macro;
2977 		if (debug_level > 1) {
2978 			(void) printf(gettext("%*sActivating conditional value: "),
2979 				      recursion_level,
2980 				      "");
2981 		}
2982 		/* Set the conditional value. Macros are expanded when the */
2983 		/* macro is refd as usual */
2984 		if ((conditional->body.conditional.name != virtual_root) ||
2985 		    (conditional->body.conditional.value != virtual_root)) {
2986 			(void) SETVAR(conditional->body.conditional.name,
2987 				      conditional->body.conditional.value,
2988 				      (Boolean) conditional->body.conditional.append);
2989 		}
2990 		cond_name = ALLOC(Chain);
2991 		cond_name->name = conditional->body.conditional.name;
2992 	}
2993 	/* Put this target on the front of the chain of conditional targets */
2994 	cond_chain = ALLOC(Chain);
2995 	cond_chain->name = target;
2996 	cond_chain->next = conditional_targets;
2997 	conditional_targets = cond_chain;
2998 	conditional_macro_used = saved_conditional_macro_used;
2999 }
3000 
3001 /*
3002  *	reset_locals(target, old_locals, conditional, index)
3003  *
3004  *	Removes any conditional macros for the target.
3005  *
3006  *	Parameters:
3007  *		target		The target we are retoring values for
3008  *		old_locals	The values to restore
3009  *		conditional	The first conditional block for the target
3010  *		index		into the old_locals vector
3011  *	Global variables used:
3012  *		debug_level	Should we trace activities?
3013  *		recursion_level	Used for tracing
3014  */
3015 void
reset_locals(Name target,Property old_locals,Property conditional,int index)3016 reset_locals(Name target, Property old_locals, Property conditional, int index)
3017 {
3018 	Property	this_conditional;
3019 	Chain			cond_chain;
3020 
3021 	if (target->dont_activate_cond_values) {
3022 		return;
3023 	}
3024 
3025 	/* Scan the list of conditional properties and restore the old value */
3026 	/* to each one Reverse the order relative to when we assigned macros */
3027 	this_conditional = get_prop(conditional->next, conditional_prop);
3028 	if (this_conditional != NULL) {
3029 		reset_locals(target, old_locals, this_conditional, index+1);
3030 	} else {
3031 		/* Remove conditional target from chain */
3032 		if (conditional_targets == NULL ||
3033 		    conditional_targets->name != target) {
3034 			warning(gettext("Internal error: reset target not at head of condtional_targets chain"));
3035 		} else {
3036 			cond_chain = conditional_targets->next;
3037 			retmem_mb((caddr_t) conditional_targets);
3038 			conditional_targets = cond_chain;
3039 		}
3040 	}
3041 	get_prop(conditional->body.conditional.name->prop,
3042 		 macro_prop)->body.macro = old_locals[index].body.macro;
3043 	if (conditional->body.conditional.name == virtual_root) {
3044 		(void) SETVAR(virtual_root, getvar(virtual_root), false);
3045 	}
3046 	if (debug_level > 1) {
3047 		if (old_locals[index].body.macro.value != NULL) {
3048 			(void) printf(gettext("%*sdeactivating conditional value: %s= %s\n"),
3049 				      recursion_level,
3050 				      "",
3051 				      conditional->body.conditional.name->
3052 				      string_mb,
3053 				      old_locals[index].body.macro.value->
3054 				      string_mb);
3055 		} else {
3056 			(void) printf(gettext("%*sdeactivating conditional value: %s =\n"),
3057 				      recursion_level,
3058 				      "",
3059 				      conditional->body.conditional.name->
3060 				      string_mb);
3061 		}
3062 	}
3063 }
3064 
3065 /*
3066  *	check_auto_dependencies(target, auto_count, automatics)
3067  *
3068  *	Returns true if the target now has a dependency
3069  *	it didn't previously have (saved on automatics).
3070  *
3071  *	Return value:
3072  *				true if new dependency found
3073  *
3074  *	Parameters:
3075  *		target		Target we check
3076  *		auto_count	Number of old automatic vars
3077  *		automatics	Saved old automatics
3078  *
3079  *	Global variables used:
3080  *		keep_state	Indicates that .KEEP_STATE is on
3081  */
3082 Boolean
check_auto_dependencies(Name target,int auto_count,Name * automatics)3083 check_auto_dependencies(Name target, int auto_count, Name *automatics)
3084 {
3085 	Name		*p;
3086 	int		n;
3087 	Property	line;
3088 	Dependency	dependency;
3089 
3090 	if (keep_state) {
3091 		if ((line = get_prop(target->prop, line_prop)) == NULL) {
3092 			return false;
3093 		}
3094 		/* Go thru new list of automatic depes */
3095 		for (dependency = line->body.line.dependencies;
3096 		     dependency != NULL;
3097 		     dependency = dependency->next) {
3098 			/* And make sure that each one existed before we */
3099 			/* built the target */
3100 			if (dependency->automatic && !dependency->stale) {
3101 				for (n = auto_count, p = automatics;
3102 				     n > 0;
3103 				     n--) {
3104 					if (*p++ == dependency->name) {
3105 						/* If we can find it on the */
3106 						/* saved list of autos we */
3107 						/* are OK  */
3108 						goto not_new;
3109 					}
3110 				}
3111 				/* But if we scan over the old list */
3112 				/* of auto. without finding it it is */
3113 				/* new and we must check it */
3114 				return true;
3115 			}
3116 		not_new:;
3117 		}
3118 		return false;
3119 	} else {
3120 		return false;
3121 	}
3122 }
3123 
3124 
3125 // Recursively delete each of the Chain struct on the chain.
3126 
3127 static void
delete_query_chain(Chain ch)3128 delete_query_chain(Chain ch)
3129 {
3130 	if (ch == NULL) {
3131 		return;
3132 	} else {
3133 		delete_query_chain(ch->next);
3134 		retmem_mb((char *) ch);
3135 	}
3136 }
3137 
3138 Doname
target_can_be_built(Name target)3139 target_can_be_built(Name target) {
3140 	Doname		result = build_dont_know;
3141 	Name		true_target = target;
3142 	Property	line;
3143 
3144 	if (target == wait_name) {
3145 		return(build_ok);
3146 	}
3147 	/*
3148 	 * If the target is a constructed one for a "::" target,
3149 	 * we need to consider that.
3150 	 */
3151 	if (target->has_target_prop) {
3152 		true_target = get_prop(target->prop,
3153 				       target_prop)->body.target.target;
3154 	}
3155 
3156 	(void) exists(true_target);
3157 
3158 	if (true_target->state == build_running) {
3159 		return(build_running);
3160 	}
3161 	if (true_target->stat.time != file_doesnt_exist) {
3162 		result = build_ok;
3163 	}
3164 
3165 	/* get line property for the target */
3166 	line = get_prop(true_target->prop, line_prop);
3167 
3168 	/* first check for explicit rule */
3169 	if (line != NULL && line->body.line.command_template != NULL) {
3170 		result = build_ok;
3171 	}
3172 	/* try to find pattern rule */
3173 	if (result == build_dont_know) {
3174 		result = find_percent_rule(target, NULL, false);
3175 	}
3176 
3177 	/* try to find double suffix rule */
3178 	if (result == build_dont_know) {
3179 		if (target->is_member) {
3180 			Property member = get_prop(target->prop, member_prop);
3181 			if (member != NULL && member->body.member.member != NULL) {
3182 				result = find_ar_suffix_rule(target, member->body.member.member, NULL, false);
3183 			} else {
3184 				result = find_double_suffix_rule(target, NULL, false);
3185 			}
3186 		} else {
3187 			result = find_double_suffix_rule(target, NULL, false);
3188 		}
3189 	}
3190 
3191 	/* try to find suffix rule */
3192 	if ((result == build_dont_know) && second_pass) {
3193 		result = find_suffix_rule(target, target, empty_name, NULL, false);
3194 	}
3195 
3196 	/* check for sccs */
3197 	if (result == build_dont_know) {
3198 		result = sccs_get(target, NULL);
3199 	}
3200 
3201 	/* try to find dyn target */
3202 	if (result == build_dont_know) {
3203 		Name dtarg = find_dyntarget(target);
3204 		if (dtarg != NULL) {
3205 			result = target_can_be_built(dtarg);
3206 		}
3207 	}
3208 
3209 	/* check whether target was mentioned in makefile */
3210 	if (result == build_dont_know) {
3211 		if (target->colons != no_colon) {
3212 			result = build_ok;
3213 		}
3214 	}
3215 
3216 	/* result */
3217 	return result;
3218 }
3219