1    	/***********************************************************************
2    	 * dstruct.c - central data structures and associated operations
3    	 ***********************************************************************
4    	 *
5    	 * Copyright (c) 1995-2003 Silicon Graphics, Inc.  All Rights Reserved.
6    	 * 
7    	 * This program is free software; you can redistribute it and/or modify it
8    	 * under the terms of the GNU General Public License as published by the
9    	 * Free Software Foundation; either version 2 of the License, or (at your
10   	 * option) any later version.
11   	 * 
12   	 * This program is distributed in the hope that it will be useful, but
13   	 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14   	 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15   	 * for more details.
16   	 */
17   	#include "pmapi.h"
18   	#include "impl.h"
19   	#include <math.h>
20   	#include <ctype.h>
21   	#include <limits.h>
22   	#ifdef HAVE_SYS_WAIT_H
23   	#include <sys/wait.h>
24   	#endif
25   	#include "dstruct.h"
26   	#include "symbol.h"
27   	#include "pragmatics.h"
28   	#include "fun.h"
29   	#include "eval.h"
30   	#include "show.h"
31   	
32   	#if defined(HAVE_VALUES_H)
33   	#include <values.h>
34   	#endif
35   	#if defined(HAVE_IEEEFP_H)
36   	#include <ieeefp.h>
37   	#endif
38   	#ifndef HAVE_MEMALIGN
39   	#define memalign(a,b) malloc(b)
40   	#endif
41   	
42   	/***********************************************************************
43   	 * constants
44   	 ***********************************************************************/
45   	
46   	char	localHost[MAXHOSTNAMELEN+1];	/* "official" name of localhost */
47   	double	mynan;				/* not-a-number run time initialized */
48   	
49   	
50   	/***********************************************************************
51   	 * user supplied parameters
52   	 ***********************************************************************/
53   	
54   	char		*pmnsfile = PM_NS_DEFAULT;	/* alternate name space */
55   	Archive		*archives;			/* list of open archives */
56   	RealTime	first = -1;			/* archive starting point */
57   	RealTime	last = 0.0;			/* archive end point */
58   	char		*dfltHost;			/* default host */
59   	RealTime	dfltDelta = DELTA_DFLT;		/* default sample interval */
60   	char		*startFlag;			/* start time specified? */
61   	char		*stopFlag;			/* end time specified? */
62   	char		*alignFlag;			/* align time specified? */
63   	char		*offsetFlag;			/* offset time specified? */
64   	RealTime	runTime;			/* run time interval */
65   	int		hostZone;			/* timezone from host? */
66   	char		*timeZone;			/* timezone from command line */
67   	int		verbose;			/* verbosity 0, 1 or 2 */
68   	int		interactive;			/* interactive mode, -d */
69   	int		isdaemon;			/* run as a daemon */
70   	int		agent;				/* secret agent mode? */
71   	int		applet;				/* applet mode? */
72   	int		dowrap;				/* counter wrap? default no */
73   	int		noDnsFlag;			/* do a default name lookup? */
74   	pmiestats_t	*perf;				/* live performance data */
75   	pmiestats_t	instrument;			/* used if no mmap (archive) */
76   	
77   	
78   	/***********************************************************************
79   	 * this is where the action is
80   	 ***********************************************************************/
81   	
82   	Task		*taskq = NULL;		/* evaluator task queue */
83   	Expr		*curr;			/* current executing rule expression */
84   	
85   	SymbolTable	hosts;			/* currently known hosts */
86   	SymbolTable	metrics;		/* currently known metrics */
87   	SymbolTable	rules;			/* currently known rules */
88   	SymbolTable	vars;			/* currently known variables */
89   	
90   	
91   	/***********************************************************************
92   	 * time
93   	 ***********************************************************************/
94   	
95   	RealTime	now;			/* current time */
96   	RealTime	start;			/* start evaluation time */
97   	RealTime	stop;			/* stop evaluation time */
98   	
99   	Symbol		symDelta;		/* current sample interval */
100  	Symbol		symMinute;		/* minutes after the hour 0..59 */
101  	Symbol		symHour;		/* hours since midnight 0..23 */
102  	Symbol		symDay;			/* day of the month 1..31 */
103  	Symbol		symMonth;		/* month of the year 1..12 */
104  	Symbol		symYear;		/* year 1996.. */
105  	Symbol		symWeekday;		/* days since Sunday 0..6 */
106  	
107  	static double	delta;			/* current sample interval */
108  	static double	second;			/* seconds after the minute 0..59 */
109  	static double	minute;			/* minutes after the hour 0..59 */
110  	static double	hour;			/* hours since midnight 0..23 */
111  	static double	day;			/* day of the month 1..31 */
112  	static double	month;			/* month of the year 1..12 */
113  	static double	year;			/* year 1996.. */
114  	static double	weekday;		/* days since Sunday 0..6 */
115  	
116  	/***********************************************************************
117  	 * process creation control
118  	 ***********************************************************************/
119  	int		need_wait;
120  	
121  	
122  	/* return real time */
123  	RealTime
124  	getReal(void)
125  	{
126  	    struct timeval t;
127  	
128  	    __pmtimevalNow(&t);
129  	    return realize(t);
130  	}
131  	
132  	
133  	/* update time variables to reflect current time */
134  	void
135  	reflectTime(RealTime d)
136  	{
137  	    static time_t   then = 0;			/* previous time */
138  	    int		    skip = now - then;
139  	    struct tm	    tm;
140  	
141  	    then = (time_t)now;
142  	
143  	    /* sample interval */
144  	    delta = d;
145  	
146  	    /* try short path for current time */
147  	    if (skip >= 0 && skip < 24 * 60 * 60) {
148  		second += skip;
149  		if (second < 60)
150  		    return;
151  		skip = (int)(second / 60);
152  		second -= (double)(60 * skip);
153  		minute += (double)skip;
154  		if (minute < 60)
155  		    return;
156  		skip = (int)(minute / 60);
157  		minute -= (double)(60 * skip);
158  		hour += (double)skip;
159  		if (hour < 24)
160  		    return;
161  	    }
162  	
163  	    /* long path for current time */
164  	    pmLocaltime(&then, &tm);
165  	    second = (double) tm.tm_sec;
166  	    minute = (double) tm.tm_min;
167  	    hour = (double) tm.tm_hour;
168  	    day = (double) tm.tm_mday;
169  	    month = (double) tm.tm_mon;
170  			    /* tm_year is years since 1900, so this is Y2K safe */
171  	    year = (double) tm.tm_year + 1900;
172  	    weekday = (double) tm.tm_wday;
173  	}
174  	
175  	
176  	/* convert RealTime to timeval */
177  	void
178  	unrealize(RealTime rt, struct timeval *tv)
179  	{
180  	    tv->tv_sec = (time_t)rt;
181  	    tv->tv_usec = (int)(1000000 * (rt - tv->tv_sec));
182  	}
183  	
184  	
185  	/* convert RealTime to timespec */
186  	void
187  	unrealizenano(RealTime rt, struct timespec *ts)
188  	{
189  	    ts->tv_sec = (time_t)rt;
190  	    ts->tv_nsec = (int)(1000000000 * (rt - ts->tv_sec));
191  	}
192  	
193  	#define SLEEP_EVAL	0
194  	#define SLEEP_RETRY	1
195  	
196  	/* sleep until eval or retry RealTime */
197  	void
198  	sleepTight(Task *t, int type)
199  	{
200  	    RealTime	sched;
201  	    RealTime	delay;	/* interval to sleep */
202  	    int		sts;
203  	    RealTime	cur_entry = getReal();
204  	#ifdef HAVE_WAITPID
205  	    pid_t	pid;
206  	
207  	    if (need_wait) {
208  		/* harvest terminated children */
209  		while ((pid = waitpid(-1, &sts, WNOHANG)) > (pid_t)0) {
210  	#if PCP_DEBUG
211  		    if (pmDebug & DBG_TRACE_APPL2) {
212  			fprintf(stderr, "sleepTight: wait: pid=%" FMT_PID " done status=0x%x", pid, sts);
213  			if (WIFEXITED(sts))
214  			    fprintf(stderr, " exit=%d", WEXITSTATUS(sts));
215  			if (WIFSIGNALED(sts))
216  			    fprintf(stderr, " signal=%d", WTERMSIG(sts));
217  			fprintf(stderr, "\n");
218  		    }
219  	#endif
220  		    ;
221  		}
222  		need_wait = 0;
223  	    }
224  	#endif
225  	
226  	    if (!archives) {
227  		struct timespec ts, tleft;
228  		static RealTime	last_sched = -1;
229  		static Task *last_t;
230  		static int last_type;
231  		RealTime cur = getReal();
232  	
233  		sched = type == SLEEP_EVAL ? t->eval : t->retry;
234  	
235  		delay = sched - cur;
236  		if (delay < 0) {
237  		    int		show_detail = 0;
238  		    if (delay <= -1) {
239  			fprintf(stderr, "sleepTight: negative delay (%f). sched=%f, cur=%f\n",
240  				    delay, sched, cur);
241  			show_detail = 1;
242  		    }
243  	#if PCP_DEBUG
244  		    else {
245  			if (pmDebug & DBG_TRACE_APPL2) {
246  			    fprintf(stderr, "sleepTight: small negative delay (%f). sched=%f, cur=%f\n",
247  				    delay, sched, cur);
248  			    show_detail = 1;
249  			}
250  		    }
251  	#endif
252  		    if (show_detail) {
253  			if (last_sched > 0) {
254  			    fprintf(stderr, "Last sleepTight (%s) until: ", last_type == SLEEP_EVAL ? "eval" : "retry");
255  			    showFullTime(stderr, last_sched);
256  			    fputc('\n', stderr);
257  			    fprintf(stderr, "Last ");
258  			    dumpTask(last_t);
259  			}
260  			fprintf(stderr, "This sleepTight() entry: ");
261  			showFullTime(stderr, cur_entry);
262  			fputc('\n', stderr);
263  			fprintf(stderr, "Harvest children done: ");
264  			showFullTime(stderr, cur);
265  			fputc('\n', stderr);
266  			fprintf(stderr, "Want sleepTight (%s) until: ", type == SLEEP_EVAL ? "eval" : "retry");
267  			showFullTime(stderr, sched);
268  			fputc('\n', stderr);
269  			fprintf(stderr, "This ");
270  			dumpTask(t);
271  		    }
272  		}
273  		else {
274  		    unrealizenano(delay, &ts);
275  		    for (;;) {	/* loop to catch early wakeup from nanosleep */
276  			if (ts.tv_sec < 0 || ts.tv_nsec > 999999999) {
277  			    fprintf(stderr, "sleepTight: invalid args: %ld %ld\n",
278  				    ts.tv_sec, ts.tv_nsec);
279  			    break;
280  			}
281  			sts = nanosleep(&ts, &tleft);
282  			if (sts == 0 || (sts < 0 && oserror() != EINTR))
283  			    break;
284  			ts = tleft;
285  		    }
286  		}
287  		last_t = t;
288  		last_type = type;
289  		last_sched = sched;
290  	    }
291  	}
292  	
293  	
294  	/***********************************************************************
295  	 * ring buffer management
296  	 ***********************************************************************/
297  	
298  	void
299  	newRingBfr(Expr *x)
300  	{
301  	    size_t  sz;
302  	    char    *p;
303  	    int     i;
304  	
305  	    sz = ((x->sem == SEM_TRUTH) || (x->sem == SEM_CHAR)) ?
306  		    sizeof(char) * x->tspan :
307  		    sizeof(double) * x->tspan;
308  	    if (x->ring) free(x->ring);
309  	    x->ring = alloc(x->nsmpls * sz);
310  	    p = (char *) x->ring;
311  	    for (i = 0; i < x->nsmpls; i++) {
312  		x->smpls[i].ptr = (void *) p;
313  		p += sz;
314  	    }
315  	}
316  	
317  	
318  	void
319  	newStringBfr(Expr *x, size_t length, char *bfr)
320  	{
321  	    if (x->e_idom != (int)length) {
322  		x->e_idom = (int)length;
323  		x->tspan = (int)length;
324  		x->nvals = (int)length;
325  	    }
326  	    if (x->ring)
327  		free(x->ring);
328  	    x->ring = bfr;
329  	    x->smpls[0].ptr = (void *) bfr;
330  	}
331  	
332  	
333  	/* Rotate ring buffer - safe to call only if x->nsmpls > 1 */
334  	void
335  	rotate(Expr *x)
336  	{
337  	    int     n = x->nsmpls-1;
338  	    Sample *q = &x->smpls[n];
339  	    Sample *p = q - 1;
340  	    void   *t = q->ptr;
341  	    int	    i;
342  	
343  	    for (i = n; i > 0; i--)
344  		*q-- = *p--;
345  	    x->smpls[0].ptr = t;
346  	}
347  	
348  	
349  	/***********************************************************************
350  	 * memory allocation
351  	 ***********************************************************************/
352  	
353  	void *
354  	alloc(size_t size)
355  	{
356  	    void *p;
357  	
358  	    if ((p = malloc(size)) == NULL) {
359  		__pmNoMem("pmie.alloc", size, PM_FATAL_ERR);
360  	    }
361  	    return p;
362  	}
363  	
364  	
365  	void *
366  	zalloc(size_t size)
367  	{
368  	    void *p;
369  	
370  	    if ((p = calloc(1, size)) == NULL) {
371  		__pmNoMem("pmie.zalloc", size, PM_FATAL_ERR);
372  	    }
373  	    return p;
374  	}
375  	
376  	
377  	void *
378  	aalloc(size_t align, size_t size)
379  	{
380  	    void *p;
381  	
382  	    if ((p = memalign(align, size)) == NULL) {
383  		__pmNoMem("pmie.aalloc", size, PM_FATAL_ERR);
384  	    }
385  	    return p;
386  	}
387  	
388  	
389  	void *
390  	ralloc(void *p, size_t size)
391  	{
392  	    void *q;
393  	
394  	    if ((q = realloc(p, size)) == NULL) {
395  		__pmNoMem("pmie.ralloc", size, PM_FATAL_ERR);
396  	    }
397  	    return q;
398  	}
399  	
400  	char *
401  	sdup(char *p)
402  	{
403  	    char *q;
404  	
405  	    if ((q = strdup(p)) == NULL) {
406  		__pmNoMem("pmie.sdup", strlen(p), PM_FATAL_ERR);
407  	    }
408  	    return q;
409  	}
410  	
411  	
412  	Expr *
413  	newExpr(int op, Expr *arg1, Expr *arg2,
414  		int hdom, int idom, int tdom, int nsmpls,
415  		int sem)
416  	{
417  	    Expr *x;
418  	    Expr *arg;
419  	
420  	    x = (Expr *) zalloc(sizeof(Expr) + (nsmpls - 1) * sizeof(Sample));
421  	    x->op = op;
422  	    if (arg1) {
423  		x->arg1 = arg1;
424  		arg1->parent = x;
425  	    }
426  	    if (arg2) {
427  		x->arg2 = arg2;
428  		arg2->parent = x;
429  	    }
430  	    x->hdom = hdom;
431  	    x->e_idom = idom;
432  	    x->tdom = tdom;
433  	    x->nsmpls = nsmpls;
434  	    x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom);
435  	    x->nvals = x->tspan * nsmpls;
436  	    if (arg1) {
437  		arg = primary(arg1, arg2);
438  		x->metrics = arg->metrics;
439  	    }
440  	    x->units = noUnits;
441  	    x->sem = sem;
442  	    return x;
443  	}
444  	
445  	
446  	Profile *
447  	newProfile(Fetch *owner, pmInDom indom)
448  	{
449  	    Profile *p = (Profile *) zalloc(sizeof(Profile));
450  	    p->indom = indom;
451  	    p->fetch = owner;
452  	    return p;
453  	}
454  	
455  	
456  	Fetch *
457  	newFetch(Host *owner)
458  	{
459  	    Fetch *f = (Fetch *) zalloc(sizeof(Fetch));
460  	    f->host = owner;
461  	    return f;
462  	}
463  	
464  	
465  	Host *
466  	newHost(Task *owner, Symbol name)
467  	{
468  	    Host *h = (Host *) zalloc(sizeof(Host));
469  	
470  	    h->name = symCopy(name);
471  	    h->task = owner;
472  	    return h;
473  	}
474  	
475  	
476  	Task *
477  	newTask(RealTime delta, int nth)
478  	{
479  	    Task *t = (Task *) zalloc(sizeof(Task));
480  	    t->nth = nth;
481  	    t->delta = delta;
482  	    return t;
483  	}
484  	
485  	/* translate new metric name to internal pmid for agent mode */
486  	static pmID
487  	agentId(char *name)
488  	{
489  	    int		sts;
490  	    pmID	pmid;
491  	
492  	    if ((sts = pmLookupName(1, &name, &pmid)) < 0) {
493  		fprintf(stderr, "%s: agentId: metric %s not found in namespace: %s\n",
494  			pmProgname, name, pmErrStr(sts));
495  		exit(1);
496  	    }
497  	    return pmid;
498  	}
499  	
500  	
501  	void
502  	newResult(Task *t)
503  	{
504  	    pmResult	 *rslt;
505  	    Symbol	 *sym;
506  	    pmValueSet	 *vset;
507  	    pmValueBlock *vblk;
508  	    int		 i;
509  	    int		 len;
510  	
511  	    /* allocate pmResult */
512  	    rslt = (pmResult *) zalloc(sizeof(pmResult) + (t->nrules - 1) * sizeof(pmValueSet *));
513  	    rslt->numpmid = t->nrules;
514  	
515  	    /* allocate pmValueSet's */
516  	    sym = t->rules;
517  	    for (i = 0; i < t->nrules; i++) {
518  		vset = (pmValueSet *)alloc(sizeof(pmValueSet));
519  		vset->pmid = agentId(symName(*sym));
520  		vset->numval = 0;
521  		vset->valfmt = PM_VAL_DPTR;
522  		vset->vlist[0].inst = PM_IN_NULL;
523  		len = PM_VAL_HDR_SIZE + sizeof(double);
524  		vblk = (pmValueBlock *)zalloc(len);
525  		vblk->vlen = len;
526  		vblk->vtype = PM_TYPE_DOUBLE;
527  		vset->vlist[0].value.pval = vblk;
528  		rslt->vset[i] = vset;
529  		sym++;
530  	    }
531  	
532  	    t->rslt = rslt;
533  	}
534  	
535  	
536  	/***********************************************************************
537  	 * memory deallocation
538  	 *
539  	 * IMPORTANT: These functions free the argument structure plus any
540  	 *            structures it owns below it in the expression tree.
541  	 ***********************************************************************/
542  	
543  	void
544  	freeTask(Task *t)
545  	{
546  	    if ((t->hosts == NULL) && (t->rules == NULL)) {
547  		if (t->next) t->next->prev = t->prev;
548  		if (t->prev) t->prev->next = t->next;
549  		else taskq = t->next;
550  		free(t);
551  	   }
552  	}
553  	
554  	
555  	void
556  	freeHost(Host *h)
557  	{
558  	    if ((h->fetches == NULL) && (h->waits == NULL)) {
559  		if (h->next) h->next->prev = h->prev;
560  		if (h->prev) h->prev->next = h->next;
561  		else {
562  		    h->task->hosts = h->next;
563  		    freeTask(h->task);
564  		}
565  		symFree(h->name);
566  		free(h);
567  	    }
568  	}
569  	
570  	
571  	void
572  	freeFetch(Fetch *f)
573  	{
574  	    if (f->profiles == NULL) {
575  		if (f->next) f->next->prev = f->prev;
576  		if (f->prev) f->prev->next = f->next;
577  		else {
578  		    f->host->fetches = f->next;
579  		    freeHost(f->host);
580  		}
581  		pmDestroyContext(f->handle);
582  		if (f->result) pmFreeResult(f->result);
583  		if (f->pmids) free(f->pmids);
584  		free(f);
585  	    }
586  	}
587  	
588  	
589  	void
590  	FreeProfile(Profile *p)
591  	{
592  	    if (p->metrics == NULL) {
593  		if (p->next) p->next->prev = p->prev;
594  		if (p->prev) p->prev->next = p->next;
595  		else {
596  		    p->fetch->profiles = p->next;
597  		    freeFetch(p->fetch);
598  		}
599  		free(p);
600  	    }
601  	}
602  	
603  	
604  	void
605  	freeMetric(Metric *m)
606  	{
607  	    int		numinst;
608  	
609  	    /* Metric is on fetch list */
610  	    if (m->profile) {
611  		if (m->prev) {
612  		    m->prev->next = m->next;
613  		    if (m->next) m->next->prev = m->prev;
614  		}
615  		else {
616  		    m->host->waits = m->next;
617  		    if (m->next) m->next->prev = NULL;
618  		}
619  		if (m->host) freeHost(m->host);
620  	    }
621  	
622  	    symFree(m->hname);
623  	    numinst =  m->specinst == 0 ? m->m_idom : m->specinst;
624  	    if (numinst > 0 && m->inames) {
625  		int	i;
626  		for (i = 0; i < numinst; i++) {
627  		    if (m->inames[i] != NULL) free(m->inames[i]);
628  		}
629  		free(m->inames);
630  	    }
631  	    if (numinst && m->iids) free(m->iids);
632  	    if (m->vals) free(m->vals);
633  	    free(m);
634  	}
635  	
636  	
637  	void
638  	freeExpr(Expr *x)
639  	{
640  	    Metric	*m;
641  	    int		i;
642  	
643  	    if (x) {
644  		if (x->arg1 && x->arg1->parent == x)
645  		    freeExpr(x->arg1);
646  		if (x->arg2 && x->arg2->parent == x)
647  		    freeExpr(x->arg2);
648  		if (x->metrics && x->op == CND_FETCH) {
649  		    if (x->hdom < 0) {
650  			/*
651  			 * no trips through the loop to call freeMetric(),
652  			 * so free partially allocated structure
653  			 */
654  			free(x->metrics);
655  		    }
656  		    else {
657  			for (m = x->metrics, i = 0; i < x->hdom; m++, i++)
658  			    freeMetric(m);
659  		    }
660  		}
661  		if (x->ring) free(x->ring);
662  		free(x);
663  	    }
664  	}
665  	
666  	
667  	/***********************************************************************
668  	 * comparison functions (for use by qsort)
669  	 ***********************************************************************/
670  	
671  	/* Compare two instance identifiers.
672  	   - This function is passed as an argument to qsort, hence the casts. */
673  	int	/* -1 less, 0 equal, 1 greater */
674  	compid(const void *i1, const void *i2)
675  	{
676  	    if (*(int *)i1 < *(int *)i2) return -1;
677  	    if (*(int *)i1 > *(int *)i2) return 1;
678  	    return 0;
679  	}
680  	
681  	
682  	/* Compare two pmValue's on their inst fields
683  	   - This function is passed as an argument to qsort, hence the casts. */
684  	int	/* -1 less, 0 equal, 1 greater */
685  	compair(const void *pmv1, const void *pmv2)
686  	{
687  	    if (((pmValue *)pmv1)->inst < ((pmValue *)pmv2)->inst) return -1;
688  	    if (((pmValue *)pmv1)->inst > ((pmValue *)pmv2)->inst) return 1;
689  	    return 0;
690  	}
691  	
692  	
693  	/***********************************************************************
694  	 * Expr manipulation
695  	 ***********************************************************************/
696  	
697  	/* Decide primary argument for inheritance of Expr attributes */
698  	Expr *
699  	primary(Expr *arg1, Expr *arg2)
700  	{
701  	    if (arg2 == NULL || arg1->nvals > 1)
702  		return arg1;
703  	    if (arg2->nvals > 1)
704  		return arg2;
705  	    if (arg1->metrics &&
706  		(arg1->hdom != -1 || arg1->e_idom != -1 || arg1->tdom != -1))
707  		return arg1;
708  	    if (arg2->metrics &&
709  		(arg2->hdom != -1 || arg2->e_idom != -1 || arg2->tdom != -1))
710  		return arg2;
711  	    return arg1;
712  	}
713  	
714  	
715  	/* change number of samples allocated in ring buffer */
716  	void
717  	changeSmpls(Expr **p, int nsmpls)
718  	{
719  	    Expr   *x = *p;
720  	    Metric *m;
721  	    int    i;
722  	
723  	    if (nsmpls == x->nsmpls) return;
724  	    *p = x = (Expr *) ralloc(x, sizeof(Expr) + (nsmpls - 1) * sizeof(Sample));
725  	    x->nsmpls = nsmpls;
726  	    x->nvals = x->tspan * nsmpls;
727  	    x->valid = 0;
728  	    if (x->op == CND_FETCH) {
729  		m = x->metrics;
730  		for (i = 0; i < x->hdom; i++) {
731  		    m->expr = x;
732  		    m++;
733  		}
734  	    }
735  	    newRingBfr(x);
736  	}
737  	
738  	
739  	/* propagate instance domain, semantics and units from
740  	   argument expressions to parents */
741  	static void
742  	instExpr(Expr *x)
743  	{
744  	    int	    up = 0;
745  	    Expr    *arg1 = x->arg1;
746  	    Expr    *arg2 = x->arg2;
747  	    Expr    *arg = primary(arg1, arg2);
Event var_decl: Declaring variable "u" without initializer.
Also see events: [uninit_use]
748  	    pmUnits u;
749  	
750  	    /* semantics and units */
At conditional (1): "x->sem == 0": Taking true branch.
751  	    if (x->sem == SEM_UNKNOWN) {
752  	
753  		/* unary expression */
At conditional (2): "arg2 == NULL": Taking false branch.
754  		if (arg2 == NULL) {
755  		    up = 1;
756  		    x->sem = arg1->sem;
757  		    x->units = arg1->units;
758  		}
759  	
760  		/* bianry expression with known args */
At conditional (3): "arg1->sem != 0": Taking true branch.
At conditional (4): "arg2->sem != 0": Taking true branch.
761  		else if ((arg1->sem != SEM_UNKNOWN) &&
762  			 (arg2->sem != SEM_UNKNOWN)) {
763  		    up = 1;
764  		    x->sem = arg->sem;
At conditional (5): "x->op == 7": Taking true branch.
765  		    if (x->op == CND_MUL) {
766  			u.dimSpace = arg1->units.dimSpace + arg2->units.dimSpace;
767  			u.dimTime = arg1->units.dimTime + arg2->units.dimTime;
768  			u.dimCount = arg1->units.dimCount + arg2->units.dimCount;
769  		    }
770  		    else if (x->op == CND_DIV) {
771  			u.dimSpace = arg1->units.dimSpace - arg2->units.dimSpace;
772  			u.dimTime = arg1->units.dimTime - arg2->units.dimTime;
773  			u.dimCount = arg1->units.dimCount - arg2->units.dimCount;
774  		    }
775  		    else
776  			u = arg->units;
Event uninit_use: Using uninitialized value "u": field "u".scaleSpace is uninitialized.
Also see events: [var_decl]
777  		    x->units = u;
778  		}
779  	
780  		/* binary expression with unknown arg */
781  		else
782  		    return;
783  	    }
784  	
785  	    /* instance domain */
786  	    if ((x->e_idom != -1) && (x->e_idom != arg->e_idom)) {
787  		up = 1;
788  		x->e_idom = arg->e_idom;
789  		x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom);
790  		x->nvals = x->tspan * x->nsmpls;
791  		x->valid = 0;
792  		newRingBfr(x);
793  	    }
794  	
795  	    if (up && x->parent)
796  		instExpr(x->parent);
797  	}
798  	
799  	
800  	/* propagate instance domain, semantics and units from given
801  	   fetch expression to its parents */
802  	void
803  	instFetchExpr(Expr *x)
804  	{
805  	    Metric  *m;
806  	    int     ninst;
807  	    int	    up = 0;
808  	    int     i;
809  	
810  	    /* update semantics and units */
811  	    if (x->sem == SEM_UNKNOWN) {
812  		m = x->metrics;
813  		for (i = 0; i < x->hdom; i++) {
814  		    if (m->desc.sem != SEM_UNKNOWN) {
815  			if (m->desc.sem == PM_SEM_COUNTER) {
816  			    x->sem = PM_SEM_INSTANT;
817  			    x->units = canon(m->desc.units);
818  			    x->units.dimTime--;
819  			}
820  			else {
821  			    x->sem = m->desc.sem;
822  			    x->units = canon(m->desc.units);
823  			}
824  			up = 1;
825  			break;
826  		    }
827  		}
828  	    }
829  	
830  	    /*
831  	     * update number of instances ... need to be careful because may be more
832  	     * than one host, and instances may not be fully available ...
833  	     *   m_idom < 0 =>	no idea how many instances there might be (cannot
834  	     *			contact pmcd, unknown metric, can't get indom, ...)
835  	     *   m_idom == 0 =>	no values, but otherwise OK
836  	     *   m_idom > 0 =>	have this many values (and hence instances)
837  	     */
838  	    m = x->metrics;
839  	    ninst = -1;
840  	    for (i = 0; i < x->hdom; i++) {
841  		m->offset = ninst;
842  		if (m->m_idom >= 0) {
843  		    if (ninst == -1)
844  			ninst = m->m_idom;
845  		    else
846  			ninst += m->m_idom;
847  		}
848  		m++;
849  	    }
850  	    if (x->e_idom != ninst) {
851  		x->e_idom = ninst;
852  		x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom);
853  		x->nvals = x->nsmpls * x->tspan;
854  		x->valid = 0;
855  		newRingBfr(x);
856  		up = 1;
857  	    }
858  	    if (up && x->parent)
859  		instExpr(x->parent);
860  	}
861  	
862  	
863  	/***********************************************************************
864  	 * compulsory initialization
865  	 ***********************************************************************/
866  	
867  	void dstructInit(void)
868  	{
869  	    Expr   *x;
870  	    double zero = 0.0;
871  	
872  	    /* not-a-number initialization */
873  	    mynan = zero / zero;
874  	
875  	    /* initialize default host */
876  	    gethostname(localHost, MAXHOSTNAMELEN);
877  	    localHost[MAXHOSTNAMELEN-1] = '\0';
878  	    dfltHost = localHost;
879  	
880  	    /* set up symbol tables */
881  	    symSetTable(&hosts);
882  	    symSetTable(&metrics);
883  	    symSetTable(&rules);
884  	    symSetTable(&vars);
885  	
886  	    /* set yp inter-sample interval (delta) symbol */
887  	    symDelta = symIntern(&vars, "delta");
888  	    x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
889  	    x->smpls[0].ptr = &delta;
890  	    x->valid = 1;
891  	    symValue(symDelta) = x;
892  	
893  	    /* set up time symbols */
894  	    symMinute = symIntern(&vars, "minute");
895  	    x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
896  	    x->smpls[0].ptr = &minute;
897  	    x->valid = 1;
898  	    symValue(symMinute) = x;
899  	    symHour = symIntern(&vars, "hour");
900  	    x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
901  	    x->smpls[0].ptr = &hour;
902  	    x->valid = 1;
903  	    symValue(symHour) = x;
904  	    symDay = symIntern(&vars, "day");
905  	    x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
906  	    x->smpls[0].ptr = &day;
907  	    x->valid = 1;
908  	    symValue(symDay) = x;
909  	    symMonth = symIntern(&vars, "month");
910  	    x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
911  	    x->smpls[0].ptr = &month;
912  	    x->valid = 1;
913  	    symValue(symMonth) = x;
914  	    symYear = symIntern(&vars, "year");
915  	    x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
916  	    x->smpls[0].ptr = &year;
917  	    x->valid = 1;
918  	    symValue(symYear) = x;
919  	    symWeekday = symIntern(&vars, "day_of_week");
920  	    x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
921  	    x->smpls[0].ptr = &weekday;
922  	    x->valid = 1;
923  	    symValue(symWeekday) = x;
924  	}
925  	
926  	
927  	/* get ready to run evaluator */
928  	void
929  	agentInit(void)
930  	{
931  	    Task	*t;
932  	    int		sts;
933  	
934  	    /* Set up local name space for agent */
935  	    /* Only load PMNS if it's default and hence not already loaded */
936  	    if (pmnsfile == PM_NS_DEFAULT && (sts = pmLoadNameSpace(pmnsfile)) < 0) {
937  		fprintf(stderr, "%s: agentInit: cannot load metric namespace: %s\n",
938  			pmProgname, pmErrStr(sts));
939  		exit(1);
940  	    }
941  	
942  	    /* allocate pmResult's and send pmDescs for secret agent mode */
943  	    t = taskq;
944  	    while (t) {
945  		newResult(t);
946  		sendDescs(t);
947  		t = t->next;
948  	    }
949  	}
950  	
951  	/*
952  	 * useful for diagnostics and with dbx
953  	 */
954  	
955  	static struct {
956  	    void	(*addr)(Expr *);
957  	    char	*name;
958  	} fn_map[] = {
959  	    { actAlarm,		"actAlarm" },
960  	    { actAnd,		"actAnd" },
961  	    { actArg,		"actArg" },
962  	    { actFake,		"actFake" },
963  	    { actOr,		"actOr" },
964  	    { actPrint,		"actPrint" },
965  	    { actShell,		"actShell" },
966  	    { actStomp,		"actStomp" },
967  	    { actSyslog,	"actSyslog" },
968  	    { cndAdd_1_1,	"cndAdd_1_1" },
969  	    { cndAdd_1_n,	"cndAdd_1_n" },
970  	    { cndAdd_n_1,	"cndAdd_n_1" },
971  	    { cndAdd_n_n,	"cndAdd_n_n" },
972  	    { cndAll_host,	"cndAll_host" },
973  	    { cndAll_inst,	"cndAll_inst" },
974  	    { cndAll_time,	"cndAll_time" },
975  	    { cndAnd_1_1,	"cndAnd_1_1" },
976  	    { cndAnd_1_n,	"cndAnd_1_n" },
977  	    { cndAnd_n_1,	"cndAnd_n_1" },
978  	    { cndAnd_n_n,	"cndAnd_n_n" },
979  	    { cndAvg_host,	"cndAvg_host" },
980  	    { cndAvg_inst,	"cndAvg_inst" },
981  	    { cndAvg_time,	"cndAvg_time" },
982  	    { cndCount_host,	"cndCount_host" },
983  	    { cndCount_inst,	"cndCount_inst" },
984  	    { cndCount_time,	"cndCount_time" },
985  	    { cndDelay_1,	"cndDelay_1" },
986  	    { cndDelay_n,	"cndDelay_n" },
987  	    { cndDiv_1_1,	"cndDiv_1_1" },
988  	    { cndDiv_1_n,	"cndDiv_1_n" },
989  	    { cndDiv_n_1,	"cndDiv_n_1" },
990  	    { cndDiv_n_n,	"cndDiv_n_n" },
991  	    { cndEq_1_1,	"cndEq_1_1" },
992  	    { cndEq_1_n,	"cndEq_1_n" },
993  	    { cndEq_n_1,	"cndEq_n_1" },
994  	    { cndEq_n_n,	"cndEq_n_n" },
995  	    { cndFall_1,	"cndFall_1" },
996  	    { cndFall_n,	"cndFall_n" },
997  	    { cndFetch_1,	"cndFetch_1" },
998  	    { cndFetch_all,	"cndFetch_all" },
999  	    { cndFetch_n,	"cndFetch_n" },
1000 	    { cndGt_1_1,	"cndGt_1_1" },
1001 	    { cndGt_1_n,	"cndGt_1_n" },
1002 	    { cndGt_n_1,	"cndGt_n_1" },
1003 	    { cndGt_n_n,	"cndGt_n_n" },
1004 	    { cndGte_1_1,	"cndGte_1_1" },
1005 	    { cndGte_1_n,	"cndGte_1_n" },
1006 	    { cndGte_n_1,	"cndGte_n_1" },
1007 	    { cndGte_n_n,	"cndGte_n_n" },
1008 	    { cndLt_1_1,	"cndLt_1_1" },
1009 	    { cndLt_1_n,	"cndLt_1_n" },
1010 	    { cndLt_n_1,	"cndLt_n_1" },
1011 	    { cndLt_n_n,	"cndLt_n_n" },
1012 	    { cndLte_1_1,	"cndLte_1_1" },
1013 	    { cndLte_1_n,	"cndLte_1_n" },
1014 	    { cndLte_n_1,	"cndLte_n_1" },
1015 	    { cndLte_n_n,	"cndLte_n_n" },
1016 	    { cndMax_host,	"cndMax_host" },
1017 	    { cndMax_inst,	"cndMax_inst" },
1018 	    { cndMax_time,	"cndMax_time" },
1019 	    { cndMin_host,	"cndMin_host" },
1020 	    { cndMin_inst,	"cndMin_inst" },
1021 	    { cndMin_time,	"cndMin_time" },
1022 	    { cndMul_1_1,	"cndMul_1_1" },
1023 	    { cndMul_1_n,	"cndMul_1_n" },
1024 	    { cndMul_n_1,	"cndMul_n_1" },
1025 	    { cndMul_n_n,	"cndMul_n_n" },
1026 	    { cndNeg_1,		"cndNeg_1" },
1027 	    { cndNeg_n,		"cndNeg_n" },
1028 	    { cndNeq_1_1,	"cndNeq_1_1" },
1029 	    { cndNeq_1_n,	"cndNeq_1_n" },
1030 	    { cndNeq_n_1,	"cndNeq_n_1" },
1031 	    { cndNeq_n_n,	"cndNeq_n_n" },
1032 	    { cndNot_1,		"cndNot_1" },
1033 	    { cndNot_n,		"cndNot_n" },
1034 	    { cndOr_1_1,	"cndOr_1_1" },
1035 	    { cndOr_1_n,	"cndOr_1_n" },
1036 	    { cndOr_n_1,	"cndOr_n_1" },
1037 	    { cndOr_n_n,	"cndOr_n_n" },
1038 	    { cndPcnt_host,	"cndPcnt_host" },
1039 	    { cndPcnt_inst,	"cndPcnt_inst" },
1040 	    { cndPcnt_time,	"cndPcnt_time" },
1041 	    { cndRate_1,	"cndRate_1" },
1042 	    { cndRate_n,	"cndRate_n" },
1043 	    { cndRise_1,	"cndRise_1" },
1044 	    { cndRise_n,	"cndRise_n" },
1045 	    { cndSome_host,	"cndSome_host" },
1046 	    { cndSome_inst,	"cndSome_inst" },
1047 	    { cndSome_time,	"cndSome_time" },
1048 	    { cndSub_1_1,	"cndSub_1_1" },
1049 	    { cndSub_1_n,	"cndSub_1_n" },
1050 	    { cndSub_n_1,	"cndSub_n_1" },
1051 	    { cndSub_n_n,	"cndSub_n_n" },
1052 	    { cndSum_host,	"cndSum_host" },
1053 	    { cndSum_inst,	"cndSum_inst" },
1054 	    { cndSum_time,	"cndSum_time" },
1055 	    { rule,		"rule" },
1056 	    { NULL,		NULL },
1057 	};
1058 	
1059 	static struct {
1060 	    int			val;
1061 	    char		*name;
1062 	} sem_map[] = {
1063 	    { SEM_UNKNOWN,	"UNKNOWN" },
1064 	    { SEM_NUMVAR,	"NUMVAR" },
1065 	    { SEM_NUMCONST,	"NUMCONST" },
1066 	    { SEM_TRUTH,	"TRUTH" },
1067 	    { SEM_CHAR,		"CHAR" },
1068 	    { SEM_REGEX,	"REGEX" },
1069 	    { PM_SEM_COUNTER,	"COUNTER" },
1070 	    { PM_SEM_INSTANT,	"INSTANT" },
1071 	    { PM_SEM_DISCRETE,	"DISCRETE" },
1072 	    { 0,		NULL },
1073 	};
1074 	
1075 	void
1076 	__dumpExpr(int level, Expr *x)
1077 	{
1078 	    int		i;
1079 	    int		j;
1080 	    int		k;
1081 	
1082 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1083 	    fprintf(stderr, "Expr dump @ " PRINTF_P_PFX "%p\n", x);
1084 	    if (x == NULL) return;
1085 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1086 	    fprintf(stderr, "  op=%d (%s) arg1=" PRINTF_P_PFX "%p arg2=" PRINTF_P_PFX "%p parent=" PRINTF_P_PFX "%p\n",
1087 		x->op, opStrings(x->op), x->arg1, x->arg2, x->parent);
1088 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1089 	    fprintf(stderr, "  eval=");
1090 	    for (j = 0; fn_map[j].addr; j++) {
1091 		if (x->eval == fn_map[j].addr) {
1092 		    fprintf(stderr, "%s", fn_map[j].name);
1093 		    break;
1094 		}
1095 	    }
1096 	    if (fn_map[j].addr == NULL)
1097 		fprintf(stderr, "" PRINTF_P_PFX "%p()", x->eval);
1098 	    fprintf(stderr, " metrics=" PRINTF_P_PFX "%p ring=" PRINTF_P_PFX "%p\n", x->metrics, x->ring);
1099 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1100 	    fprintf(stderr, "  valid=%d cardinality[H,I,T]=[%d,%d,%d] tspan=%d\n",
1101 		x->valid, x->hdom, x->e_idom, x->tdom, x->tspan);
1102 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1103 	    fprintf(stderr, "  nsmpls=%d nvals=%d sem=", x->nsmpls, x->nvals);
1104 	    for (j = 0; sem_map[j].name; j++) {
1105 		if (x->sem == sem_map[j].val) {
1106 		    fprintf(stderr, "%s", sem_map[j].name);
1107 		    break;
1108 		}
1109 	    }
1110 	    if (sem_map[j].name == NULL)
1111 		fprintf(stderr, "%d", x->sem);
1112 	    fprintf(stderr, " units=%s\n", pmUnitsStr(&x->units));
1113 	    if (x->valid > 0) {
1114 		if (x->sem == SEM_TRUTH || x->sem == SEM_CHAR ||
1115 		    x->sem == SEM_NUMVAR || x->sem == SEM_NUMCONST ||
1116 		    x->sem == PM_SEM_COUNTER || x->sem == PM_SEM_INSTANT ||
1117 		    x->sem == PM_SEM_DISCRETE) {
1118 		    for (j = 0; j < x->nsmpls; j++) {
1119 			for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1120 			fprintf(stderr, "  smpls[%d].ptr " PRINTF_P_PFX "%p ", j, x->smpls[j].ptr);
1121 			for (k = 0; k < x->tspan; k++) {
1122 			    if (x->tspan > 1 && x->sem != SEM_CHAR) {
1123 				if (k > 0)
1124 				    fprintf(stderr, ", ");
1125 				fprintf(stderr, "{%d} ", k);
1126 			    }
1127 			    if (x->sem == SEM_TRUTH) {
1128 				char 	c = *((char *)x->smpls[j].ptr+k);
1129 				if ((int)c == TRUE)
1130 				    fprintf(stderr, "true");
1131 				else if ((int)c == FALSE)
1132 				    fprintf(stderr, "false");
1133 				else if ((int)c == DUNNO)
1134 				    fprintf(stderr, "unknown");
1135 				else
1136 				    fprintf(stderr, "bogus (0x%x)", c & 0xff);
1137 			    }
1138 			    else if (x->sem == SEM_CHAR) {
1139 				if (k == 0)
1140 				    fprintf(stderr, "\"%s\"", (char *)x->smpls[j].ptr);
1141 			    }
1142 			    else {
1143 				double	v = *((double *)x->smpls[j].ptr+k);
1144 				if (isnand(v))
1145 				    fputc('?', stderr);
1146 				else
1147 				    fprintf(stderr, "%g", v);
1148 			    }
1149 			}
1150 			fputc('\n', stderr);
1151 		    }
1152 		}
1153 		else if (x->sem == SEM_REGEX) {
1154 		    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1155 		    fprintf(stderr, "  handle=" PRINTF_P_PFX "%p\n", x->ring);
1156 		}
1157 	    }
1158 	}
1159 	
1160 	void
1161 	__dumpMetric(int level, Metric *m)
1162 	{
1163 	    int		i;
1164 	    int		j;
1165 	    int		numinst;
1166 	
1167 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1168 	    fprintf(stderr, "Metric dump @ " PRINTF_P_PFX "%p\n", m);
1169 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1170 	    fprintf(stderr, "expr=" PRINTF_P_PFX "%p profile=" PRINTF_P_PFX "%p host=" PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p\n",
1171 		m->expr, m->profile, m->host, m->next, m->prev);
1172 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1173 	    fprintf(stderr, "metric=%s host=%s conv=%g specinst=%d m_indom=%d\n",
1174 		symName(m->mname), symName(m->hname), m->conv, m->specinst, m->m_idom);
1175 	    if (m->desc.indom != PM_INDOM_NULL) {
1176 		numinst =  m->specinst == 0 ? m->m_idom : m->specinst;
1177 		for (j = 0; j < numinst; j++) {
1178 		    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1179 		    fprintf(stderr, "[%d] iid=", j);
1180 		    if (m->iids[j] == PM_IN_NULL) 
1181 			fprintf(stderr, "?missing");
1182 		    else
1183 			fprintf(stderr, "%d", m->iids[j]);
1184 		    fprintf(stderr, " iname=\"%s\"\n", m->inames[j]);
1185 		}
1186 	    }
1187 	    for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1188 	    fputc('\n', stderr);
1189 	
1190 	#if 0
1191 	    pmDesc          desc;       /* pmAPI metric description */
1192 	    RealTime	    stamp;	/* time stamp for current values */
1193 	    pmValueSet	    *vset;	/* current values */
1194 	    RealTime	    stomp;	/* previous time stamp for rate calculation */
1195 	    double	    *vals;	/* vector of values for rate computation */
1196 	    int		    offset;	/* offset within sample in expr ring buffer */
1197 	... Metric;
1198 	#endif
1199 	
1200 	}
1201 	
1202 	
1203 	void
1204 	__dumpTree(int level, Expr *x)
1205 	{
1206 	    __dumpExpr(level, x);
1207 	    if (x->arg1 != NULL) __dumpTree(level+1, x->arg1);
1208 	    if (x->arg2 != NULL) __dumpTree(level+1, x->arg2);
1209 	}
1210 	
1211 	void
1212 	dumpTree(Expr *x)
1213 	{
1214 	    __dumpTree(0, x);
1215 	}
1216 	
1217 	void
1218 	dumpRules(void)
1219 	{
1220 	    Task	*t;
1221 	    Symbol	*s;
1222 	    int		i;
1223 	
1224 	    for (t = taskq; t != NULL; t = t->next) {
1225 		s = t->rules;
1226 		for (i = 0; i < t->nrules; i++, s++) {
1227 		    fprintf(stderr, "\nRule: %s\n", symName(*s));
1228 		    dumpTree((Expr *)symValue(*s));
1229 		}
1230 	    }
1231 	}
1232 	
1233 	void
1234 	dumpExpr(Expr *x)
1235 	{
1236 	    __dumpExpr(0, x);
1237 	}
1238 	
1239 	void
1240 	dumpMetric(Metric *m)
1241 	{
1242 	    __dumpMetric(0, m);
1243 	}
1244 	
1245 	void
1246 	dumpTask(Task *t)
1247 	{
1248 	    int	i;
1249 	    fprintf(stderr, "Task dump @ " PRINTF_P_PFX "%p\n", t);
1250 	    fprintf(stderr, "  nth=%d delta=%.3f tick=%d next=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p\n", t->nth, t->delta, t->tick, t->next, t->prev);
1251 	    fprintf(stderr, "  eval time: ");
1252 	    showFullTime(stderr, t->eval);
1253 	    fputc('\n', stderr);
1254 	    fprintf(stderr, "  retry time: ");
1255 	    showFullTime(stderr, t->retry);
1256 	    fputc('\n', stderr);
1257 	    if (t->hosts == NULL)
1258 		fprintf(stderr, "  host=<null>\n");
1259 	    else
1260 		fprintf(stderr, "  host=%s (%s)\n", symName(t->hosts->name), t->hosts->down ? "down" : "up");
1261 	    fprintf(stderr, "  rules:\n");
1262 	    for (i = 0; i < t->nrules; i++) {
1263 		fprintf(stderr, "    %s\n", symName(t->rules[i]));
1264 	    }
1265 	}