1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1984-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * Glenn Fowler
23  * AT&T Research
24  *
25  * make state variable routines
26  * this file and the is*() macros specify the state variable name format
27  *
28  *	(<var>)		the state of <var>
29  *	(<var>)<rule>	the state of <var> qualified by <rule>
30  *	()<rule>	the state of <rule>
31  *
32  * NOTE: update VERSION in compile.c if the format changes
33  */
34 
35 #include "make.h"
36 #include "options.h"
37 
38 /*
39  * return a pointer to the rule <s1><s2><s3>
40  * force causes the rule to be created
41  * force<0 canon's name first
42  */
43 
44 Rule_t*
catrule(register char * s1,register char * s2,register char * s3,int force)45 catrule(register char* s1, register char* s2, register char* s3, int force)
46 {
47 	Rule_t*		r;
48 
49 	sfputr(internal.nam, s1, *s2++);
50 	if (*s2)
51 		sfputr(internal.nam, s2, s3 ? *s3++ : -1);
52 	if (s3 && *s3)
53 		sfputr(internal.nam, s3, -1);
54 	s1 = sfstruse(internal.nam);
55 	if (!(r = getrule(s1)) && force)
56 	{
57 		if (force < 0)
58 		{
59 			pathcanon(s1, 0, 0);
60 			if (r = getrule(s1))
61 				return r;
62 		}
63 		r = makerule(NiL);
64 	}
65 	return r;
66 }
67 
68 /*
69  * return the state file name
70  * assumes the main makefile has already been read
71  */
72 
73 char*
statefile(void)74 statefile(void)
75 {
76 	char*		dir;
77 	Sfio_t*		sp;
78 	Stat_t		st;
79 
80 	if (!state.statefile && state.makefile)
81 	{
82 		sp = sfstropen();
83 		dir = DELETE;
84 		if (!state.writestate || streq(state.writestate, "-") || !stat(state.writestate, &st) && S_ISDIR(st.st_mode) && (dir = state.writestate))
85 			edit(sp, state.makefile, dir, KEEP, external.state);
86 		else
87 			expand(sp, state.writestate);
88 		state.statefile = strdup(sfstruse(sp));
89 		sfstrclose(sp);
90 	}
91 	return state.statefile;
92 }
93 
94 /*
95  * reconcile s with state view from r
96  *
97  * NOTE: requires state.maxview>0 && 0<=view<=state.maxview
98  */
99 
100 static Rule_t*
stateview(int op,char * name,register Rule_t * s,register Rule_t * r,int view,int accept,Rule_t ** pv)101 stateview(int op, char* name, register Rule_t* s, register Rule_t* r, int view, int accept, Rule_t** pv)
102 {
103 	register Rule_t*	v;
104 	register List_t*	p;
105 	Sfio_t*			fp;
106 
107 	if (pv)
108 		*pv = 0;
109 	if (state.compile < COMPILED)
110 	{
111 #if DEBUG
112 		if (state.test & 0x00000200)
113 			error(2, "STATEVIEW %d %s state file load delayed until after makefile read", view, name);
114 #endif
115 		return 0;
116 	}
117 	if (!(state.view[view].flags & BIND_LOADED))
118 	{
119 		if (view < state.readstate)
120 		{
121 			char*	file;
122 			Sfio_t*	tmp;
123 			long	n;
124 
125 			tmp = sfstropen();
126 			if (name && !s)
127 			{
128 				sfputr(tmp, name, 0);
129 				n = sfstrtell(tmp);
130 			}
131 			else
132 				n = 0;
133 			edit(tmp, statefile(), state.view[view].path, KEEP, KEEP);
134 			sfputc(tmp, 0);
135 			file = sfstrseek(tmp, n, SEEK_SET);
136 			if (fp = sfopen(NiL, file, "br"))
137 			{
138 				/*
139 				 * NOTE: this load should not be a problem for
140 				 *	 internal rule pointers since all
141 				 *	 non-state rules in state files
142 				 *	 are just references
143 				 */
144 
145 				state.stateview = view;
146 				message((-2, "loading state view %d file %s", view, file));
147 				if (load(fp, file, 0, 0) > 0)
148 					state.view[view].flags |= BIND_EXISTS;
149 				else if (state.corrupt && *state.corrupt == 'a' && !(state.view[0].flags & BIND_EXISTS))
150 					state.accept = 1;
151 				state.stateview = -1;
152 				sfclose(fp);
153 			}
154 			if (n)
155 				strcpy(name, sfstrbase(tmp));
156 			sfstrclose(tmp);
157 		}
158 		state.view[view].flags |= BIND_LOADED;
159 	}
160 	if (name)
161 	{
162 		viewname(name, view);
163 		v = getrule(name);
164 		unviewname(name);
165 #if DEBUG
166 		if (state.test & 0x00000200)
167 			error(2, "STATEVIEW %s [%s] test %d [%s] -> %s [%s]", name, s ? timestr(s->time) : "no rule", view, timestr(r->time), v ? v->name : null, v ? timestr(v->time) : "no rule");
168 #endif
169 		if (v)
170 		{
171 			if (pv)
172 				*pv = v;
173 			if (s && (op == RULE && (s->event >= v->event && s->event || !v->time && (v->property & P_force)) || op == PREREQS && s->time >= v->time))
174 				return s;
175 			if (v->time == r->time || accept || r->view == view || (r->property & (P_state|P_use|P_virtual)) || state.believe && view >= (state.believe - 1))
176 			{
177 				if (r->property & P_state)
178 				{
179 					if (r->property & P_statevar)
180 					{
181 						if (r->statedata && (!v->statedata && *r->statedata || v->statedata && !streq(r->statedata, v->statedata) || r->time > v->time))
182 							return 0;
183 						s = r;
184 						s->statedata = v->statedata;
185 						if (v->property & P_parameter)
186 							s->property |= P_parameter;
187 					}
188 				}
189 				else
190 				{
191 					if (r->property & P_use)
192 					{
193 						if (r->action && (!v->action || !streq(r->action, v->action)) || !r->action && v->action)
194 							return 0;
195 						r->time = v->time;
196 					}
197 					if (!s)
198 						s = makerule(name);
199 				}
200 				s->time = v->time;
201 				s->attribute = v->attribute;
202 				s->event = v->event;
203 				s->action = v->action;
204 				if (v->property & P_force)
205 					s->property |= P_force;
206 				else
207 					s->property &= ~P_force;
208 				if (v->dynamic & D_built)
209 					s->dynamic |= D_built;
210 				else
211 					s->dynamic &= ~D_built;
212 				if (v->dynamic & D_lowres)
213 					s->dynamic |= D_lowres;
214 				else
215 					s->dynamic &= ~D_lowres;
216 				s->prereqs = listcopy(v->prereqs);
217 				s->scan = v->scan;
218 				for (p = s->prereqs; p; p = p->next)
219 				{
220 					v = p->rule;
221 					if (v->dynamic & D_lower)
222 					{
223 						unviewname(v->name);
224 						p->rule = makerule(v->name);
225 						viewname(v->name, v->view);
226 					}
227 				}
228 #if DEBUG
229 				if (state.test & 0x00000200)
230 				{
231 					error(2, "STATEVIEW %s accept %d", s->name, view);
232 					if (state.test & 0x00000400)
233 						dumprule(sfstderr, s);
234 				}
235 #endif
236 			}
237 		}
238 	}
239 	return s;
240 }
241 
242 /*
243  * return a pointer to the state rule of var qualified by r
244  * force>0 causes the state rule to be created
245  * force<0 prevents a state bind
246  */
247 
248 Rule_t*
staterule(int op,register Rule_t * r,char * var,int force)249 staterule(int op, register Rule_t* r, char* var, int force)
250 {
251 	register Rule_t*	s;
252 	register int		i;
253 	char*			rul;
254 	char*			nam;
255 	Rule_t*			v;
256 	int			j;
257 	int			k;
258 	int			m;
259 	int			nobind = force < 0;
260 	Flags_t*		b;
261 
262 	switch (op)
263 	{
264 	case PREREQS:
265 		rul = var;
266 		var = "+";
267 		if (!r)
268 		{
269 			if (nobind)
270 			{
271 				sfprintf(internal.nam, "(%s)%s", var, rul);
272 				r = getrule(sfstruse(internal.nam));
273 			}
274 			return r;
275 		}
276 		break;
277 	case RULE:
278 		rul = var;
279 		var = null;
280 		if (!r)
281 		{
282 			if (nobind)
283 			{
284 				sfprintf(internal.nam, "(%s)%s", var, rul);
285 				return getrule(sfstruse(internal.nam));
286 			}
287 			r = makerule(var);
288 			nobind = 1;
289 		}
290 		break;
291 	case VAR:
292 		if (!r)
293 		{
294 			sfprintf(internal.nam, "(%s)", var);
295 			if (!(r = getrule(sfstruse(internal.nam))))
296 			{
297 				if (!force)
298 					return 0;
299 				r = makerule(sfstrbase(internal.nam));
300 			}
301 		}
302 		if (nobind)
303 			return r;
304 		break;
305 #if DEBUG
306 	default:
307 		error(PANIC, "invalid op=%d to staterule()", op);
308 		break;
309 #endif
310 	}
311  again:
312 	if (r->property & P_statevar)
313 	{
314 		if (op == PREREQS)
315 			return 0;
316 		op = RULE;
317 		nam = r->name;
318 		s = r;
319 	}
320 	else if (r->property & P_state)
321 		return 0;
322 	else
323 	{
324 		if ((r->dynamic & (D_member|D_membertoo)) && (rul = strrchr(r->name, '/')))
325 			rul++;
326 		else
327 			rul = unbound(r);
328 		sfprintf(internal.nam, "(%s)%s", var, rul);
329 		nam = sfstruse(internal.nam);
330 		if (s = getrule(nam))
331 			nam = s->name;
332 	}
333 	if (state.maxview && state.readstate && state.makefile && !nobind)
334 	{
335 		b = &r->checked[op];
336 		k = 0;
337 		if (!tstbit(*b, i = (r->property & (P_statevar|P_use|P_virtual)) && state.targetview > 0 ? state.targetview : r->view) && (!s || !s->time || (r->property & P_statevar) || !(k = statetimeq(r, s))))
338 		{
339 			if (!(r->property & (P_statevar|P_use|P_virtual)) && !(r->dynamic & D_bound) && !(r->mark & M_bind) && (s && s->time || !s && state.compile >= COMPILED))
340 			{
341 				/*
342 				 * M_bind guards staterule() recursion
343 				 */
344 
345 				s = r;
346 				s->mark |= M_bind;
347 				r = bind(r);
348 				s->mark &= ~M_bind;
349 				goto again;
350 			}
351 			if ((r->property & P_statevar) && r->time == OLDTIME)
352 			{
353 				for (i = 0; i <= state.maxview; i++)
354 				{
355 					setbit(*b, i);
356 					setbit(r->checked[CONSISTENT], i);
357 				}
358 			}
359 			else
360 			{
361 				if (!(r->property & (P_statevar|P_use|P_virtual)) || state.targetview < 0)
362 				{
363 					m = 1;
364 					j = 0;
365 					if (!(k = r->view) && !(state.view[0].flags & BIND_EXISTS))
366 						k = state.maxview;
367 				}
368 				else
369 				{
370 					m = 0;
371 					j = k = state.targetview;
372 				}
373 #if DEBUG
374 				if (state.test & 0x00000200)
375 					error(2, "STATERULE %s search %d..%d targetview=%d", nam, j, k, state.targetview);
376 #endif
377 				for (i = j; i <= k; i++)
378 				{
379 					setbit(*b, i);
380 					if (i || !(r->property & P_statevar))
381 					{
382 						s = stateview(op, nam, s, r, i, i == k, &v);
383 						if (v)
384 						{
385 							if (m)
386 							{
387 								m = i;
388 								while (++m <= k)
389 									setbit(*b, m);
390 							}
391 							if (op != PREREQS || state.accept)
392 								do setbit(r->checked[CONSISTENT], i); while (--i > j);
393 							break;
394 						}
395 					}
396 					if (state.accept)
397 						setbit(r->checked[CONSISTENT], i);
398 					if (!i)
399 					{
400 						if (op != PREREQS)
401 							setbit(r->checked[CONSISTENT], i);
402 						k = state.maxview;
403 					}
404 				}
405 			}
406 		}
407 		else if (k)
408 			setbit(*b, i);
409 	}
410 	if (!s && force > 0)
411 		s = makerule(nam);
412 	if (s && op == RULE)
413 	{
414 		r->attribute |= s->attribute & internal.retain->attribute;
415 		r->property |= s->property & (P_dontcare|P_terminal);
416 	}
417 	return s;
418 }
419 
420 /*
421  * return a non-state rule pointer corresponding to the staterule r
422  * force causes the non-state rule to be created
423  */
424 
425 Rule_t*
rulestate(register Rule_t * r,int force)426 rulestate(register Rule_t* r, int force)
427 {
428 	register char*		s;
429 
430 	if (r->property & P_staterule)
431 	{
432 		s = r->name;
433 		while (*s && *s++ != ')');
434 		if (!(r = getrule(s)) && force)
435 			r = makerule(s);
436 	}
437 	return r;
438 }
439 
440 /*
441  * return a variable pointer corresponding to the state variable r
442  * force causes the variable to be created
443  */
444 
445 Var_t*
varstate(register Rule_t * r,int force)446 varstate(register Rule_t* r, int force)
447 {
448 	register char*		s;
449 	register char*		t;
450 	register Var_t*		v;
451 
452 	s = r->name;
453 	if (r->property & P_state)
454 	{
455 		if (r->property & P_statevar)
456 		{
457 			s++;
458 			*(t = s + strlen(s) - 1) = 0;
459 		}
460 		else
461 			return 0;
462 	}
463 	else
464 		t = 0;
465 	if (!(v = getvar(s)) && force)
466 		v = setvar(s, null, force < 0 ? V_retain : 0);
467 	if (t)
468 		*t = ')';
469 	return v;
470 }
471 
472 /*
473  * return the auxiliary variable pointer for s
474  * force causes the variable to be created
475  */
476 
477 Var_t*
auxiliary(char * s,int force)478 auxiliary(char* s, int force)
479 {
480 	Var_t*		v;
481 
482 	sfprintf(internal.nam, "(&)%s", s);
483 	if (!(v = getvar(sfstruse(internal.nam))) && force)
484 		v = setvar(sfstrbase(internal.nam), null, 0);
485 	return v;
486 }
487 
488 /*
489  * force r->scan == (*(unsigned char*)h) or all files to be re-scanned
490  */
491 
492 int
forcescan(const char * s,char * v,void * h)493 forcescan(const char* s, char* v, void* h)
494 {
495 	register Rule_t*	r = (Rule_t*)v;
496 	register int		n = h ? *((unsigned char*)h) : r->scan;
497 
498 	NoP(s);
499 	if ((r->property & P_staterule) && r->scan == n && !(r->dynamic & D_scanned))
500 		r->property |= P_force;
501 	return 0;
502 }
503 
504 /*
505  * report state file lock fatal error
506  */
507 
508 static void
badlock(char * file,int view,Time_t date)509 badlock(char* file, int view, Time_t date)
510 {
511 	long	d;
512 
513 	/*
514 	 * probably a bad lock if too old
515 	 */
516 
517 	d = state.regress ? 0 : (CURSECS - tmxsec(date));
518 	if (d > 24 * 60 * 60)
519 		error(1, "%s is probably an invalid lock file", file);
520 	else if (d > 0)
521 		error(1, "another make has been running on %s in %s for the past %s", state.makefile, state.view[view].path, fmtelapsed(d, 1));
522 	else
523 		error(1, "another make is running on %s in %s", state.makefile, state.view[view].path);
524 	error(3, "use -%c to override", OPT(OPT_ignorelock));
525 }
526 
527 /*
528  * get|release exclusive (advisory) access to state file
529  *
530  * this is a general solution that should work on all systems
531  * the following problems need to be addressed
532  *
533  *	o  flock() or lockf() need to work for distributed
534  *	   as well as local file systems
535  *
536  *	o  the file system clock may be different than the
537  *	   local system clock
538  *
539  *	o  creating a specific lock file opens the door for
540  *	   lock files laying around after program and system
541  *	   crashes -- placing the pid of the locking process
542  *	   as file data may not work on distributed process
543  *	   systems
544  */
545 
546 #define LOCKTIME(p,m)	((m)?tmxgetmtime(p):tmxgetctime(p))
547 
548 void
lockstate(int set)549 lockstate(int set)
550 {
551 	register int		fd;
552 	register char*		file;
553 	Time_t			t;
554 	Stat_t			st;
555 
556 	static char*		lockfile;
557 	static Time_t		locktime;
558 	static int		lockmtime;
559 
560 	if (set)
561 	{
562 		if (!state.exec || state.virtualdot || !state.writestate)
563 			return;
564 		edit(internal.nam, statefile(), KEEP, KEEP, external.lock);
565 		file = strdup(sfstruse(internal.nam));
566 		if (!state.ignorelock)
567 		{
568 			int	uid = geteuid();
569 
570 			for (fd = 1; fd <= state.maxview; fd++)
571 			{
572 				edit(internal.nam, file, state.view[fd].path, KEEP, KEEP);
573 				if (!stat(sfstruse(internal.nam), &st) && st.st_uid != uid)
574 					badlock(sfstrbase(internal.nam), fd, LOCKTIME(&st, lockmtime));
575 			}
576 		}
577 		locktime = 0;
578 		for (;;)
579 		{
580 			lockfile = file;
581 			if ((fd = open(file, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY|O_cloexec, 0)) >= 0)
582 				break;
583 			lockfile = 0;
584 			if (stat(file, &st) < 0)
585 				error(3, "cannot create lock file %s", file);
586 			if (!state.ignorelock)
587 				badlock(file, 0, LOCKTIME(&st, lockmtime));
588 			if (remove(file) < 0)
589 				error(3, "cannot remove lock file %s", file);
590 		}
591 
592 		/*
593 		 * fstat() here would be best but some systems
594 		 * like cygwin which shall remain nameless
595 		 * return different time values after the close()
596 		 */
597 
598 		close(fd);
599 		if (stat(file, &st) < 0)
600 			error(3, "cannot stat lock file %s", file);
601 		lockmtime = tmxgetatime(&st) < tmxgetmtime(&st) || tmxgetctime(&st) < tmxgetmtime(&st);
602 		locktime = LOCKTIME(&st, lockmtime);
603 	}
604 	else if (lockfile)
605 	{
606 		if (locktime)
607 		{
608 			if (stat(lockfile, &st) < 0 || (t = LOCKTIME(&st, lockmtime)) != locktime && t != tmxsns(tmxsec(locktime), 0))
609 			{
610 				if (state.writestate)
611 					error(1, "the state file lock on %s has been overridden", state.makefile);
612 			}
613 			else if (remove(lockfile) < 0)
614 				error(1, "cannot remove lock file %s", lockfile);
615 		}
616 		else
617 			remove(lockfile);
618 		free(lockfile);
619 		lockfile = 0;
620 	}
621 }
622 
623 /*
624  * read state from a previous make
625  */
626 
627 void
readstate(void)628 readstate(void)
629 {
630 	register Sfio_t*	fp;
631 	char*			file;
632 
633 	if (state.makefile)
634 	{
635 		lockstate(1);
636 		if (state.readstate && (fp = sfopen(NiL, file = statefile(), "br")))
637 		{
638 			state.stateview = 0;
639 			message((-2, "loading state file %s", file));
640 			makerule(file)->dynamic |= D_built;
641 			if (load(fp, file, 0, 10) > 0)
642 				state.view[0].flags |= BIND_EXISTS;
643 			else if (!state.corrupt)
644 				error(3, "use -%c%c to accept current state or -%c to remake", OPT(OPT_accept), OPT(OPT_readstate), OPT(OPT_readstate));
645 			else if (*state.corrupt == 'a')
646 				state.accept = 1;
647 			state.stateview = -1;
648 			sfclose(fp);
649 		}
650 	}
651 	state.view[0].flags |= BIND_LOADED;
652 }
653 
654 /*
655  * update the superimposed code
656  */
657 
658 static void
code(register const char * s)659 code(register const char* s)
660 {
661 	debug((-6, "enter candidate state variable %s", s));
662 	settype(*s++, C_VARPOS1);
663 	if (*s)
664 	{
665 	 settype(*s++, C_VARPOS2);
666 	 if (*s)
667 	 {
668 	  settype(*s++, C_VARPOS3);
669 	  if (*s)
670 	  {
671 	   settype(*s++, C_VARPOS4);
672 	   if (*s)
673 	   {
674 	    settype(*s++, C_VARPOS5);
675 	    if (*s)
676 	    {
677 	     settype(*s++, C_VARPOS6);
678 	     if (*s)
679 	     {
680 	      settype(*s++, C_VARPOS7);
681 	      if (*s) settype(*s, C_VARPOS8);
682 	     }
683 	    }
684 	   }
685 	  }
686 	 }
687 	}
688 }
689 
690 /*
691  * bind() and scan() r->parameter file prerequisites
692  * this catches all implicit state variables before the
693  * parent files are scanned
694  */
695 
696 static int
checkparam(const char * s,char * v,void * h)697 checkparam(const char* s, char* v, void* h)
698 {
699 	register Rule_t*	r = (Rule_t*)v;
700 	register List_t*	p;
701 	register char*		t;
702 	Time_t			tm;
703 
704 	NoP(s);
705 	NoP(h);
706 	if ((r->property & (P_attribute|P_parameter|P_state)) == P_parameter)
707 	{
708 		r->property |= P_ignore;
709 		maketop(r, 0L, NiL);
710 		for (p = scan(r, &tm); p; p = p->next)
711 			if (((r = p->rule)->property & (P_parameter|P_statevar)) == (P_parameter|P_statevar))
712 			{
713 				r->dynamic |= D_scanned;
714 				if (t = strchr(r->name, ')'))
715 				{
716 					*t = 0;
717 					code(r->name + 1);
718 					*t = ')';
719 				}
720 			}
721 	}
722 	return 0;
723 }
724 
725 /*
726  * check implicit state variable vars
727  */
728 
729 static int
checkvar1(register const char * s,char * u,void * h)730 checkvar1(register const char* s, char* u, void* h)
731 {
732 	register Var_t*		v = (Var_t*)u;
733 	register Rule_t*	r;
734 
735 	NoP(h);
736 	if (v->property & V_scan)
737 	{
738 		state.fullscan = 1;
739 		r = staterule(VAR, NiL, (char*)s, 1);
740 		if (!r->scan)
741 		{
742 			debug((-5, "%s and %s force re-scan", v->name, r->name));
743 			r->scan = SCAN_STATE;
744 			state.forcescan = 1;
745 		}
746 		code(s);
747 	}
748 	return 0;
749 }
750 
751 /*
752  * check implicit state variable rules
753  */
754 
755 static int
checkvar2(const char * s,char * u,void * h)756 checkvar2(const char* s, char* u, void* h)
757 {
758 	register Rule_t*	r = (Rule_t*)u;
759 	Var_t*			v;
760 
761 	NoP(s);
762 	NoP(h);
763 	if ((r->property & P_statevar) && r->scan && !r->view && (!(v = varstate(r, 0)) || !(v->property & V_scan)) && (!(r->property & P_parameter) || !(r->dynamic & D_scanned)))
764 	{
765 		debug((-5, "%s forces re-scan", r->name));
766 		r->scan = 0;
767 		state.forcescan = 1;
768 	}
769 	return 0;
770 }
771 
772 /*
773  * freeze the parameter files and candidate state variables
774  */
775 
776 void
candidates(void)777 candidates(void)
778 {
779 	int	view;
780 
781 	if (state.scan)
782 	{
783 		message((-2, "freeze candidate state variables and parameter files"));
784 		hashwalk(table.rule, 0, checkparam, NiL);
785 		hashwalk(table.var, 0, checkvar1, NiL);
786 		hashwalk(table.rule, 0, checkvar2, NiL);
787 		if (state.forcescan)
788 		{
789 			for (view = 1; view <= state.maxview; view++)
790 				stateview(0, NiL, NiL, NiL, view, 0, NiL);
791 			hashwalk(table.rule, 0, forcescan, NiL);
792 		}
793 	}
794 }
795 
796 /*
797  * save state for the next make
798  */
799 
800 void
savestate(void)801 savestate(void)
802 {
803 	char*	file;
804 
805 	if (state.makefile && state.user && state.compile == COMPILED)
806 	{
807 		if (state.writestate)
808 		{
809 			if (state.finish)
810 				state.compile = SAVED;
811 			if (state.exec && state.savestate)
812 			{
813 				file = statefile();
814 				message((-2, "saving state in %s", file));
815 				state.stateview = 0;
816 				compile(file, NiL);
817 				state.stateview = -1;
818 				state.savestate = 0;
819 			}
820 		}
821 		if (state.finish)
822 			lockstate(0);
823 	}
824 }
825 
826 /*
827  * bind statevar r to a variable
828  */
829 
830 Rule_t*
bindstate(register Rule_t * r,register char * val)831 bindstate(register Rule_t* r, register char* val)
832 {
833 	Rule_t*		s;
834 	Time_t		t;
835 
836 #if DEBUG
837 	if (!(r->property & P_state))
838 		error(PANIC, "bindstate(%s) called for non-state rule", r->name);
839 #endif
840 	if (state.maxview && (r->property & P_statevar) && (s = staterule(VAR, r, NiL, 0)))
841 		r = s;
842 	if ((r->dynamic & D_bound) && !val)
843 		return r;
844 	if (r->property & P_statevar)
845 	{
846 		register Var_t*		v;
847 		char*			e;
848 		Sfio_t*			tmp = 0;
849 
850 		/*
851 		 * determine the current state variable value
852 		 */
853 
854 		if (val)
855 			r->property |= P_virtual;
856 		else if (r->property & P_virtual)
857 			val = null;
858 		else if (v = varstate(r, 0))
859 		{
860 			tmp = sfstropen();
861 			r->dynamic |= D_bound;
862 			expand(tmp, getval(v->name, VAL_PRIMARY));
863 			r->dynamic &= ~D_bound;
864 			val = sfstruse(tmp);
865 		}
866 		else if ((r->property & P_parameter) && r->statedata)
867 			val = r->statedata;
868 		else if (*(r->name + 1) == '-')
869 		{
870 			*(e = r->name + strlen(r->name) - 1) = 0;
871 			val = getval(r->name + 1, 0);
872 			*e = ')';
873 		}
874 		else
875 			val = null;
876 		if (!r->time && state.maxview && (state.view[0].flags & BIND_LOADED))
877 		{
878 			/*
879 			 * see if some other view has an initial value
880 			 */
881 
882 			r->statedata = strdup(val);
883 			staterule(RULE, r, NiL, 0);
884 		}
885 
886 		/*
887 		 * check if the state variable value changed
888 		 * the previous value, if defined, has already
889 		 * been placed in r->statedata by readstate()
890 		 */
891 
892 		message((-2, "checking state variable %s value `%s'", r->name, r->statedata ? r->statedata : null));
893 		if (!r->time || r->statedata && !streq(r->statedata, val) || !r->statedata && *val)
894 		{
895 			/*
896 			 * state variable changed
897 			 */
898 
899 			if (!r->view && !(r->property & P_accept))
900 			{
901 				if (r->time)
902 					reason((1, "state variable %s changed to `%s' from `%s'", r->name, val, r->statedata));
903 				else
904 					reason((1, "state variable %s initialized to `%s'", r->name, val));
905 			}
906 			state.savestate = 1;
907 			if (r->statedata != val)
908 				r->statedata = strdup(val);
909 			if (r->time == (t = CURTIME))
910 				t++;
911 			r->time = t;
912 		}
913 		if ((r->property & P_accept) || state.accept)
914 			r->time = OLDTIME;
915 		if (tmp)
916 			sfstrclose(tmp);
917 	}
918 	bindattribute(r);
919 	return r;
920 }
921 
922 /*
923  * check and stat built target r
924  * otherwise check for motion from . to dir of r
925  *
926  * NOTE: this needs clarification
927  */
928 
929 static int
checkcurrent(register Rule_t * r,Stat_t * st)930 checkcurrent(register Rule_t* r, Stat_t* st)
931 {
932 	register int	n;
933 	register char*	s;
934 	long		pos;
935 
936 	if (r->uname && !(n = rstat(r->uname, st, 1)))
937 		oldname(r);
938 	else if ((n = rstat(r->name, st, 1)) && (state.exec || state.mam.out && !state.mam.port))
939 	{
940 		rebind(r, -1);
941 		n = rstat(r->name, st, 1);
942 	}
943 	if (!n && !(r->dynamic & D_entries) && S_ISREG(st->st_mode))
944 		r->dynamic |= D_regular;
945 	if (!(r->dynamic & D_triggered))
946 		return n;
947 	edit(internal.nam, r->name, KEEP, DELETE, DELETE);
948 	if (!(pos = sfstrtell(internal.nam)))
949 		return n;
950 	sfputc(internal.nam, 0);
951 	sfputr(internal.nam, r->name, 0);
952 	s = sfstrseek(internal.nam, pos + 1, SEEK_SET);
953 	pathcanon(s, 0, 0);
954 	if (!streq(r->name, s))
955 	{
956 		if (!r->uname)
957 			r->uname = r->name;
958 		r->name = strdup(s);
959 	}
960 	s = sfstrseek(internal.nam, 0, SEEK_SET);
961 #if DEBUG
962 	if (state.test & 0x00000100)
963 		error(2, "statetime(%s): dir=%s n=%d time=[%s]", r->name, s, n, timestr(n ? NOTIME : tmxgetmtime(st)));
964 #endif
965 	newfile(r, s, n ? NOTIME : tmxgetmtime(st));
966 	return n;
967 }
968 
969 /*
970  * update internal time of r after its action has completed
971  * sync>0 syncs the state rule prereqs and action
972  * sync<0 resolves r but does not update state
973  */
974 
975 Time_t
statetime(register Rule_t * r,int sync)976 statetime(register Rule_t* r, int sync)
977 {
978 	register Rule_t*	s;
979 	int			a;
980 	int			n;
981 	int			skip = 0;
982 	int			zerostate = 0;
983 	Time_t			t;
984 	Time_t			q;
985 	Rule_t*			x;
986 	Stat_t			st;
987 	Stat_t			ln;
988 
989 	if (r->property & P_state)
990 	{
991 		if ((r->dynamic & D_triggered) && state.exec)
992 			r->time = ((r->property & P_statevar) && r->status == FAILED) ? (Time_t)0 : CURTIME;
993 		return r->time;
994 	}
995 	s = 0;
996 	if (state.interrupt && r->status != EXISTS)
997 		zerostate = 1;
998 	else if (r->status == FAILED)
999 	{
1000 		r->time = 0;
1001 		tmxsetmtime(&st, r->time);
1002 		if ((state.test & 0x00040000) && (s = staterule(RULE, r, NiL, 0)))
1003 		{
1004 			r->time = s->time;
1005 			if (r->property & (P_metarule|P_state))
1006 				r->event = s->event;
1007 			state.savestate = 1;
1008 			skip = 1;
1009 		}
1010 	}
1011 	else if (r->property & P_virtual)
1012 	{
1013 		r->time = CURTIME;
1014 		tmxsetmtime(&st, r->time);
1015 	}
1016 	else if (checkcurrent(r, &st))
1017 	{
1018 		if (r->property & P_dontcare)
1019 			t = 0;
1020 		else
1021 		{
1022 			t = CURTIME;
1023 			zerostate = 1;
1024 		}
1025 		tmxsetmtime(&st, t);
1026 	}
1027 	else if (sync < 0)
1028 		return r->time;
1029 	else if ((s = staterule(RULE, r, NiL, 1)) && s->time == tmxgetmtime(&st))
1030 	{
1031 		if (state.exec && !state.touch)
1032 		{
1033 			/*
1034 			 * this alternate event time prevents the action from
1035 			 * triggering next time if nothing else changes
1036 			 */
1037 
1038 			x = staterule(PREREQS, r, NiL, 1);
1039 			x->dynamic &= ~D_lowres;
1040 			x->time = r->time;
1041 			r->time = s->event;
1042 			if (r->dynamic & D_triggered)
1043 				r->dynamic |= D_same;
1044 		}
1045 		state.savestate = 1;
1046 	}
1047 	else if ((r->dynamic & D_triggered) && state.exec)
1048 	{
1049 		static int	localsync;
1050 		static int	localtest;
1051 		static Time_t	localskew;
1052 
1053 		/*
1054 		 * r is built since its time changed after its action triggered
1055 		 */
1056 
1057 		s->dynamic |= D_built;
1058 		if (x = staterule(PREREQS, r, NiL, 0))
1059 			x->property |= P_force;
1060 
1061 		/*
1062 		 * check for file system and local system time consistency
1063 		 * directories, archives and multi hard link files not sync'd
1064 		 */
1065 
1066 		if (st.st_nlink <= 1 && !S_ISDIR(st.st_mode) && !(r->property & P_archive))
1067 		{
1068 
1069 #if DEBUG
1070 			if (state.test & 0x00000100)
1071 				error(2, "%s: r[%s] s[%s] f[%s]", r->name, timestr(r->time), timestr(s->time), timestr(tmxgetmtime(&st)));
1072 #endif
1073 			if (!localsync && !state.override && r->time && r->time != OLDTIME && !(r->property & P_force) && tmxgetmtime(&st) == tmxgetctime(&st))
1074 			{
1075 				if (((n = (tmxsec(r->time) - (unsigned long)st.st_mtime - 1)) >= 0 || (n = (CURSECS - (unsigned long)st.st_mtime + 2)) <= 0) && (lstat(r->name, &ln) || !S_ISLNK(ln.st_mode)))
1076 				{
1077 					/*
1078 					 * warn if difference not tolerable
1079 					 */
1080 
1081 					a = (n > 0) ? n : -n;
1082 					if (a > 1)
1083 						error(state.regress ? -1 : 1, "%s file system time %s local time by at least %s", r->name, n > 0 ? "lags" : "leads", fmtelapsed(a, 1));
1084 					localsync = a > state.tolerance ? 1 : -1;
1085 				}
1086 			}
1087 			if (localsync > 0)
1088 			{
1089 				/*
1090 				 * NOTE: time stamp syncs work on the assumption that
1091 				 *	 all source files have an mtime that is older
1092 				 *	 than CURTIME -- this isn't too bad since
1093 				 *	 only built files are sync'd; also note that
1094 				 *	 nsec is set to 0 to avoid resolution mismatches
1095 				 */
1096 
1097 				for (;;)
1098 				{
1099 					t = tmxsns(CURSECS + tmxsec(localskew), 0);
1100 					if (tmxtouch(r->name, TMX_NOTIME, t, TMX_NOTIME, 0))
1101 					{
1102 						error(ERROR_SYSTEM|1, "%s not sync'd to local time", r->name);
1103 						break;
1104 					}
1105 					if (localtest)
1106 					{
1107 						tmxsetmtime(&st, t);
1108 						break;
1109 					}
1110 
1111 					/*
1112 					 * some systems try to fix up the local
1113 					 * remote skew in the utime() call
1114 					 * >> this never works <<
1115 					 * members of the club include
1116 					 *	darwin.ppc
1117 					 *	netbsd.i386
1118 					 */
1119 
1120 					if (stat(r->name, &st))
1121 					{
1122 						error(ERROR_SYSTEM|1, "%s not found", r->name);
1123 						break;
1124 					}
1125 					localtest = 1;
1126 					q = tmxgetmtime(&st);
1127 					if (tmxsec(q) == tmxsec(t))
1128 						break;
1129 					localskew = tmxsns(tmxsec(q)-tmxsec(t),0);
1130 					error(state.regress ? -1 : 1, "the utime(2) or utimes(2) system call is botched for the filesystem containing %s (the current time is adjusted by %lu seconds) -- the state may be out of sync", r->name, tmxsec(localskew));
1131 
1132 					/*
1133 					 * the botch may only be for times near "now"
1134 					 * localskew=1s handles this
1135 					 */
1136 
1137 					if (localskew > tmxsns(1,0))
1138 					{
1139 						t = CURTIME + tmxsns(1,0);
1140 						t = tmxsns(tmxsec(t),0);
1141 						if (!tmxtouch(r->name, TMX_NOTIME, t, TMX_NOTIME, 0) && !stat(r->name, &st) && tmxgetmtime(&st) == t)
1142 							localskew = tmxsns(1,0);
1143 					}
1144 				}
1145 			}
1146 		}
1147 	}
1148 	if (!s)
1149 		s = staterule(RULE, r, NiL, 1);
1150 	if (sync)
1151 	{
1152 		s->dynamic |= D_built;
1153 		s->attribute = r->attribute;
1154 		s->action = r->action;
1155 		if (s->prereqs != r->prereqs)
1156 		{
1157 			if ((r->property & (P_joint|P_target)) != (P_joint|P_target))
1158 				freelist(s->prereqs);
1159 			s->prereqs = r->prereqs;
1160 		}
1161 		state.savestate = 1;
1162 	}
1163 	if (!skip && (s->time != ((r->property & P_virtual) ? r->time : tmxgetmtime(&st)) || zerostate && s->time))
1164 	{
1165 		s->dynamic &= ~D_lowres;
1166 		s->time = zerostate ? 0 : (r->property & P_virtual) ? r->time : tmxgetmtime(&st);
1167 		s->event = CURTIME;
1168 		state.savestate = 1;
1169 	}
1170 	return s->time;
1171 }
1172 
1173 /*
1174  * return 1 if rule r time matches state s time modulo
1175  * tolerance and low resolution time state
1176  */
1177 
1178 int
statetimeq(Rule_t * r,Rule_t * s)1179 statetimeq(Rule_t* r, Rule_t* s)
1180 {
1181 	long		d;
1182 
1183 	static int	warned;
1184 
1185 	if (r->time == s->time)
1186 		return 1;
1187 	if (state.tolerance || (s->dynamic & D_lowres))
1188 	{
1189 		if (!(d = tmxsec(r->time) - tmxsec(s->time)) && (s->dynamic & D_lowres))
1190 		{
1191 			s->dynamic &= ~D_lowres;
1192 			s->time = r->time;
1193 			state.savestate = 1;
1194 			return 1;
1195 		}
1196 		if (d >= -state.tolerance && d <= state.tolerance)
1197 			return 1;
1198 	}
1199 	else if (r->time < s->time && !(r->property & P_state) && tmxsec(r->time) == tmxsec(s->time) && !tmxnsec(r->time))
1200 	{
1201 		if (!warned)
1202 		{
1203 			warned = 1;
1204 			if (state.warn)
1205 				error(1, "file timestamp subsecond truncation");
1206 		}
1207 		return 1;
1208 	}
1209 	return 0;
1210 }
1211