1    	/***********************************************************************
2    	 * pmie.c - performance inference engine
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   	
18   	/*
19   	 * pmie debug flags:
20   	 *	APPL0	- lexical scanning
21   	 *	APPL1	- parse/expression tree construction
22   	 *	APPL2	- expression execution
23   	 */
24   	
25   	#include <ctype.h>
26   	#include <limits.h>
27   	#include "pmapi.h"
28   	#include "impl.h"
29   	#include <sys/stat.h>
30   	
31   	#include "dstruct.h"
32   	#include "stomp.h"
33   	#include "syntax.h"
34   	#include "pragmatics.h"
35   	#include "eval.h"
36   	#include "show.h"
37   	
38   	#if HAVE_TRACE_BACK_STACK
39   	#define MAX_PCS 30	/* max callback procedure depth */
40   	#define MAX_SIZE 48	/* max function name length     */
41   	#include <libexc.h>
42   	#endif
43   	
44   	
45   	/***********************************************************************
46   	 * constants
47   	 ***********************************************************************/
48   	
49   	#define LINE_LENGTH	255		/* max length of command token */
50   	#define PROC_FNAMESIZE  20              /* from proc pmda - proc.h */
51   	#define PMIE_PATHSIZE   (sizeof(PMIE_DIR)+PROC_FNAMESIZE)
52   	
53   	static char *prompt = "pmie> ";
54   	static char *intro  = "Performance Co-Pilot Inference Engine (pmie), "
55   			      "Version %s\n\n%s%s";
56   	char	*clientid;
57   	
58   	static FILE *logfp;
59   	static char logfile[MAXPATHLEN+1];
60   	static char perffile[PMIE_PATHSIZE];	/* /var/tmp/<pid> file name */
61   	
62   	static char menu[] =
63   	"pmie debugger commands\n\n"
64   	"  f [file-name]      - load expressions from given file or stdin\n"
65   	"  l [expr-name]      - list named expression or all expressions\n"
66   	"  r [interval]       - run for given or default interval\n"
67   	"  S time-spec        - set start time for run\n"
68   	"  T time-spec        - set default interval for run command\n"
69   	"  v [expr-name]      - print subexpression used for %h, %i and\n"
70   	"                       %v bindings\n"
71   	"  h or ?             - print this menu of commands\n"
72   	"  q                  - quit\n\n";
73   	
74   	static char usage[] =
75   	    "Usage: %s [options] [filename ...]\n\n"
76   	    "Options:\n"
77   	    "  -A align     align sample times on natural boundaries\n"
78   	    "  -a archive   metrics source is a PCP log archive\n"
79   	    "  -b           one line buffered output stream, stdout on stderr\n"
80   	    "  -C           parse configuration and exit\n"
81   	    "  -c filename  configuration file\n"
82   	    "  -d           interactive debugging mode\n"
83   	    "  -e           force timestamps to be reported when used with -V, -v or -W\n"
84   	    "  -f           run in foreground\n"
85   	    "  -H           do not do a name lookup on the default hostname\n"
86   	    "  -h host      metrics source is PMCD on host\n"
87   	    "  -j stompfile stomp protocol (JMS) file [default %s%cconfig%cpmie%cstomp]\n"
88   	    "  -l logfile   send status and error messages to logfile\n"
89   	    "  -n pmnsfile  use an alternative PMNS\n"
90   	    "  -O offset    initial offset into the time window\n"
91   	    "  -S starttime start of the time window\n"
92   	    "  -T endtime   end of the time window\n"
93   	    "  -t interval  sample interval [default 10 seconds]\n"
94   	    "  -V           verbose mode, annotated expression values printed\n"
95   	    "  -v           verbose mode, expression values printed\n"
96   	    "  -W           verbose mode, satisfying expression values printed\n"
97   	    "  -x           run in domain agent mode (summary PMDA)\n"
98   	    "  -Z timezone  set reporting timezone\n"
99   	    "  -z           set reporting timezone to local time of metrics source\n";
100  	
101  	/***********************************************************************
102  	 * usage message
103  	 ***********************************************************************/
104  	
105  	static void
106  	usageMessage(void)
107  	{
108  	    int sep = __pmPathSeparator();
109  	    fprintf(stderr, usage, pmProgname, pmGetConfig("PCP_VAR_DIR"), sep,sep,sep);
110  	    exit(1);
111  	}
112  	
113  	
114  	/***********************************************************************
115  	 * interactive commands
116  	 ***********************************************************************/
117  	
118  	/* read command input line */
119  	static int
Event noescape: "readLine" does not free or save its pointer parameter "bfr".
120  	readLine(char *bfr, int max)
121  	{
122  	    int		c, i;
123  	
124  	    /* skip blanks */
125  	    do
126  		c = getchar();
127  	    while (isspace(c));
128  	
129  	    /* scan till end of line */
130  	    i = 0;
131  	    while ((c != '\n') && (c != EOF) && (i < max)) {
132  		bfr[i++] = c;
133  		c = getchar();
134  	    }
135  	    bfr[i] = '\0';
136  	    return (c != EOF);
137  	}
138  	
139  	
140  	/* scan interactive command token */
141  	static char *
142  	scanCmd(char **pp)
143  	{
144  	    char	*p = *pp;
145  	
146  	    /* skip blanks */
147  	    while (isspace((int)*p))
148  		p++;
149  	
150  	    /* single char token */
151  	    if (isgraph((int)*p)) {
152  		*pp = p + 1;
153  		return p;
154  	    }
155  	
156  	    return NULL;
157  	}
158  	
159  	
160  	/* scan interactive command argument */
161  	static char *
162  	scanArg(char *p)
163  	{
164  	    char	*q;
165  	
166  	    /* strip leading blanks */
167  	    while (isspace((int)*p))
168  		p++;
169  	    if (*p == '\0')
170  		return NULL;
171  	    q = p;
172  	
173  	    /* strip trailing blanks */
174  	    while (*q != '\0')
175  		q++;
176  	    q--;
177  	    while (isspace((int)*q))
178  		q--;
179  	    *(q + 1) = '\0';
180  	
181  	    /* return result */
182  	    return p;
183  	}
184  	
185  	
186  	/* load rules from given file or stdin */
187  	static void
188  	load(char *fname)
189  	{
190  	    Symbol	s;
191  	    Expr	*d;
192  	    int		sts = 0;
193  	    int		sep = __pmPathSeparator();
194  	    char	config[MAXPATHLEN+1];
195  	
196  	    /* search for configfile on configuration file path */
197  	    if (fname && access(fname, F_OK) != 0) {
198  		sts = oserror();	/* always report the first error */
199  		if (__pmAbsolutePath(fname)) {
200  		    fprintf(stderr, "%s: cannot access config file %s: %s\n", pmProgname, 
201  			    fname, strerror(sts));
202  		    exit(1);
203  		}
204  	#if PCP_DEBUG
205  		else if (pmDebug & DBG_TRACE_APPL0) {
206  		    fprintf(stderr, "load: cannot access config file %s: %s\n", fname, strerror(sts));
207  		}
208  	#endif
209  		snprintf(config, sizeof(config), "%s%c" "config" "%c" "pmie" "%c%s",
210  			pmGetConfig("PCP_VAR_DIR"), sep, sep, sep, fname);
211  		if (access(config, F_OK) != 0) {
212  		    fprintf(stderr, "%s: cannot access config file as either %s or %s: %s\n",
213  			    pmProgname, fname, config, strerror(sts));
214  		    exit(1);
215  		}
216  	#if PCP_DEBUG
217  		else if (pmDebug & DBG_TRACE_APPL0) {
218  		    fprintf(stderr, "load: using standard config file %s\n", config);
219  		}
220  	#endif
221  		fname = config;
222  	    }
223  	#if PCP_DEBUG
224  	    else if (pmDebug & DBG_TRACE_APPL0) {
225  		fprintf(stderr, "load: using config file %s\n",
226  			fname == NULL? "<stdin>":fname);
227  	    }
228  	#endif
229  	
230  	    if (perf->config[0] == '\0') {	/* keep record of first config */
231  		if (fname == NULL)
232  		    strcpy(perf->config, "<stdin>");
233  		else if (realpath(fname, perf->config) == NULL) {
234  		    fprintf(stderr, "%s: failed to resolve realpath for %s: %s\n",
235  			    pmProgname, fname, osstrerror());
236  		    exit(1);
237  		}
238  	    }
239  	
240  	    if (synInit(fname)) {
241  		while ((s = syntax()) != NULL) {
242  		    d = (Expr *) symValue(symDelta);
243  		    pragmatics(s, *(RealTime *)d->smpls[0].ptr);
244  		}
245  	    }
246  	}
247  	
248  	
249  	/* list given expression or all expressions */
250  	static void
251  	list(char *name)
252  	{
253  	    Task	*t;
254  	    Symbol	*r;
255  	    Symbol	s;
256  	    int		i;
257  	
258  	    if (name) {	/* single named rule */
259  		if ( (s = symLookup(&rules, name)) )
260  		    showSyntax(stdout, s);
261  		else
262  		    printf("%s: error - rule \"%s\" not defined\n", pmProgname, name);
263  	    }
264  	    else {	/* all rules */
265  		t = taskq;
266  		while (t) {
267  		    r = t->rules;
268  		    for (i = 0; i < t->nrules; i++) {
269  			showSyntax(stdout, *r);
270  			r++;
271  		    }
272  		    t = t->next;
273  		}
274  	    }
275  	}
276  	
277  	
278  	/* list binding subexpression of given expression or all expressions */
279  	static void
280  	sublist(char *name)
281  	{
282  	    Task	*t;
283  	    Symbol	*r;
284  	    Symbol	s;
285  	    int		i;
286  	
287  	    if (name) {	/* single named rule */
288  		if ( (s = symLookup(&rules, name)) )
289  		    showSubsyntax(stdout, s);
290  		else
291  		    printf("%s: error - rule '%s' not defined\n", pmProgname, name);
292  	    }
293  	    else {	/* all rules */
294  		t = taskq;
295  		while (t) {
296  		    r = t->rules;
297  		    for (i = 0; i < t->nrules; i++) {
298  			showSubsyntax(stdout, *r);
299  			r++;
300  		    }
301  		    t = t->next;
302  		}
303  	    }
304  	}
305  	
306  	
307  	/***********************************************************************
308  	 * manipulate the performance instrumentation data structure
309  	 ***********************************************************************/
310  	
311  	static void
312  	stopmonitor(void)
313  	{
314  	    if (*perffile)
315  		unlink(perffile);
316  	}
317  	
318  	static void
319  	startmonitor(void)
320  	{
321  	    struct hostent	*hep = noDnsFlag ? NULL : gethostbyname(dfltHost);
322  	    void		*ptr;
323  	    int			fd;
324  	    char		zero = '\0';
325  	
326  	    /* try to create the port file directory. OK if it already exists */
327  	    if ( (mkdir2(PMIE_DIR, S_IRWXU | S_IRWXG | S_IRWXO) < 0) &&
328  		 (oserror() != EEXIST) ) {
329  		fprintf(stderr, "%s: error creating stats file dir %s: %s\n",
330  			pmProgname, PMIE_DIR, osstrerror());
331  		exit(1);
332  	    }
333  	
334  	    chmod(PMIE_DIR, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX);
335  	    atexit(stopmonitor);
336  	
337  	    /* create and initialize memory mapped performance data file */
338  	    sprintf(perffile, "%s%c%" FMT_PID, PMIE_DIR, __pmPathSeparator(), getpid());
339  	    unlink(perffile);
340  	    if ((fd = open(perffile, O_RDWR | O_CREAT | O_EXCL | O_TRUNC,
341  				     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
342  		fprintf(stderr, "%s: cannot create stats file %s: %s\n",
343  			pmProgname, perffile, osstrerror());
344  		exit(1);
345  	    }
346  	    /* seek to struct size and write one zero */
347  	    lseek(fd, sizeof(pmiestats_t)-1, SEEK_SET);
348  	    if (write(fd, &zero, 1) != 1) {
349  		fprintf(stderr, "%s: Warning: write failed for stats file %s: %s\n",
350  			pmProgname, perffile, osstrerror());
351  	    }
352  	
353  	    /* map perffile & associate the instrumentation struct with it */
354  	    if ((ptr = __pmMemoryMap(fd, sizeof(pmiestats_t), 1)) == NULL) {
355  		fprintf(stderr, "%s: memory map failed for stats file %s: %s\n",
356  			pmProgname, perffile, osstrerror());
357  		exit(1);
358  	    }
359  	    close(fd);
360  	
361  	    perf = (pmiestats_t *)ptr;
362  	    strcpy(perf->logfile, logfile[0] == '\0'? "<none>" : logfile);
363  	    strcpy(perf->defaultfqdn, hep == NULL? dfltHost : hep->h_name);
364  	    perf->version = 1;
365  	}
366  	
367  	
368  	/***********************************************************************
369  	 * signal handling
370  	 ***********************************************************************/
371  	
372  	static void
373  	sigintproc(int sig)
374  	{
375  	    __pmSetSignalHandler(SIGINT, SIG_IGN);
376  	    __pmSetSignalHandler(SIGTERM, SIG_IGN);
377  	    __pmNotifyErr(LOG_INFO, "%s caught SIGINT or SIGTERM\n", pmProgname);
378  	    exit(1);
379  	}
380  	
381  	static void
382  	sigbye(int sig)
383  	{
384  	    exit(0);
385  	}
386  	
387  	static void
388  	remap_stdout_stderr(void)
389  	{
390  	    int	i, j;
391  	
392  	    fflush(stderr);
393  	    fflush(stdout);
394  	    setlinebuf(stderr);
395  	    setlinebuf(stdout);
396  	    i = fileno(stdout);
397  	    close(i);
398  	    if ((j = dup(fileno(stderr))) != i)
399  		fprintf(stderr, "%s: Warning: failed to link stdout ... "
400  				"dup() returns %d, expected %d (stderr=%d)\n",
401  				pmProgname, j, i, fileno(stderr));
402  	}
403  	
404  	static void
405  	sighupproc(int sig)
406  	{
407  	    FILE *fp;
408  	    int sts;
409  	
410  	    fp = __pmRotateLog(pmProgname, logfile, logfp, &sts);
411  	    if (sts != 0) {
412  		fprintf(stderr, "pmie: PID = %" FMT_PID ", default host = %s\n\n",
413  				getpid(), dfltHost);
414  		remap_stdout_stderr();
415  		logfp = fp;
416  	    } else {
417  		__pmNotifyErr(LOG_ERR, "pmie: log rotation failed\n");
418  	    }
419  	}
420  	
421  	
422  	static void
423  	dotraceback(void)
424  	{
425  	#if HAVE_TRACE_BACK_STACK
426  	    __uint64_t	call_addr[MAX_PCS];
427  	    char	*call_fn[MAX_PCS];
428  	    char	names[MAX_PCS][MAX_SIZE];
429  	    int		res;
430  	    int		i;
431  	
432  	    fprintf(stderr, "\nProcedure call traceback ...\n");
433  	    for (i = 0; i < MAX_PCS; i++)
434  	        call_fn[i] = names[i];
435  	    res = trace_back_stack(MAX_PCS, call_addr, call_fn, MAX_PCS, MAX_SIZE);
436  	    for (i = 1; i < res; i++)
437  	    fprintf(stderr, "  " PRINTF_P_PFX "%p [%s]\n", (void *)call_addr[i], call_fn[i]);
438  	#endif
439  	    return;
440  	}
441  	
442  	static void
443  	sigbadproc(int sig)
444  	{
445  	    __pmNotifyErr(LOG_ERR, "Unexpected signal %d ...\n", sig);
446  	    dotraceback();
447  	    fprintf(stderr, "\nDumping to core ...\n");
448  	    fflush(stderr);
449  	    stopmonitor();
450  	    abort();
451  	}
452  	
453  	
454  	/***********************************************************************
455  	 * command line processing - extract command line arguments & initialize
456  	 ***********************************************************************/
457  	
458  	static void
459  	getargs(int argc, char *argv[])
460  	{
461  	    char		*configfile = NULL;
462  	    char		*commandlog = NULL;
463  	    char		*subopts;
464  	    char		*subopt;
465  	    char		*msg;
466  	    int			checkFlag = 0;
467  	    int			foreground = 0;
468  	    int			err = 0;
469  	    int			sts;
470  	    int			c;
471  	    int			bflag = 0;
472  	    Archive		*a;
473  	    struct timeval	tv, tv1, tv2;
474  	    extern int		showTimeFlag;
475  	    extern int		errs;		/* syntax errors from syntax.c */
476  	
477  	    memset(&tv, 0, sizeof(tv));
478  	    memset(&tv1, 0, sizeof(tv1));
479  	    memset(&tv2, 0, sizeof(tv2));
480  	    dstructInit();
481  	
482  	    while ((c=getopt(argc, argv, "a:A:bc:CdD:efHh:j:l:n:O:S:t:T:vVWXxzZ:?")) != EOF) {
483  	        switch (c) {
484  	
485  		case 'a':			/* archives */
486  		    if (dfltConn && dfltConn != PM_CONTEXT_ARCHIVE) {
487  			fprintf(stderr, "%s: at most one of -a or -h allowed\n",
488  				pmProgname);
489  			err++;
490  			break;
491  		    }
492  		    dfltConn = PM_CONTEXT_ARCHIVE;
493  		    subopts = optarg;
494  		    for ( ; ; ) {
495  			subopt = subopts;
496  			subopts = strchr(subopts, ',');
497  			if (subopts != NULL) {
498  			    *subopts++ = '\0';
499  			}
500  			a = (Archive *) zalloc(sizeof(Archive));
501  			a->fname = subopt;
502  			if (!initArchive(a)) {
503  			    exit(1);
504  			}
505  			if (subopts == NULL) break;
506  		    }
507  		    foreground = 1;
508  		    break;
509  	
510  		case 'A': 			/* sample alignment */
511  		    alignFlag = optarg;
512  		    break;
513  	
514  		case 'b':			/* line buffered, stdout on stderr */
515  		    bflag++;
516  		    break;
517  	
518  		case 'c': 			/* configuration file */
519  		    if (interactive) {
520  			fprintf(stderr, "%s: at most one of -c and -d allowed\n",
521  				pmProgname);
522  			err++;
523  			break;
524  		    }
525  		    configfile = optarg;
526  		    break;
527  	
528  		case 'C': 			/* check config and exit */
529  		    checkFlag = 1;
530  		    break;
531  	
532  		case 'd': 			/* interactive mode */
533  		    if (configfile) {
534  			fprintf(stderr, "%s: at most one of -c and -d allowed\n",
535  				pmProgname);
536  			err++;
537  			break;
538  		    }
539  		    interactive = 1;
540  		    break;
541  	
542  		case 'D':	/* debug flag */
543  		    sts = __pmParseDebug(optarg);
544  		    if (sts < 0) {
545  			fprintf(stderr, "%s: unrecognized debug flag specification "
546  				"(%s)\n", pmProgname, optarg);
547  			err++;
548  		    }
549  		    else
550  			pmDebug |= sts;
551  		    break;
552  	
553  		case 'e':	/* force timestamps */
554  		    showTimeFlag = 1;
555  		    break;
556  	
557  		case 'f':			/* in foreground, not as daemon */
558  		    foreground = 1;
559  		    break;
560  	
561  		case 'H': 			/* no name lookup on exported host */
562  		    noDnsFlag = 1;
563  		    break;
564  	
565  		case 'h': 			/* default host name */
566  		    if (dfltConn) {
567  			fprintf(stderr, "%s: at most one of -a or -h allowed\n",
568  				pmProgname);
569  			err++;
570  			break;
571  		    }
572  		    dfltConn = PM_CONTEXT_HOST;
573  		    dfltHost = optarg;
574  		    break;
575  	
576  	        case 'j':			/* stomp protocol (JMS) config */
577  		    stompfile = optarg;
578  		    break;
579  	
580  		case 'l':			/* alternate log file */
581  		    if (commandlog != NULL) {
582  			fprintf(stderr, "%s: at most one -l option is allowed\n",
583  				pmProgname);
584  			err++;
585  			break;
586  		    }
587  		    commandlog = optarg;
588  		    isdaemon = 1;
589  		    break;
590  	
591  	        case 'n':			/* alternate namespace file */
592  		    pmnsfile = optarg;
593  		    break;
594  	
595  		case 'O':			/* position within time window */
596  		    offsetFlag = optarg;
597  		    break;
598  	
599  		case 'S':			/* start run time */
600  		    startFlag = optarg;
601  		    break;
602  	
603  		case 't':			/* sample interval */
604  		    if (pmParseInterval(optarg, &tv1, &msg) == 0)
605  			dfltDelta = realize(tv1);
606  		    else {
607  			fprintf(stderr, "%s: could not parse -t argument (%s)\n", pmProgname, optarg);
608  			fputs(msg, stderr);
609  			free(msg);
610  			err++;
611  		    }
612  		    break;
613  	
614  		case 'T':			/* evaluation period */
615  		    stopFlag = optarg;
616  		    break;
617  	
618  		case 'v': 			/* print values */
619  		    verbose = 1;
620  		    break;
621  	
622  		case 'V': 			/* print annotated values */
623  		    verbose = 2;
624  		    break;
625  	
626  		case 'W': 			/* print satisfying values */
627  		    verbose = 3;
628  		    break;
629  	
630  		case 'X': 			/* secret applet flag */
631  		    applet = 1;
632  		    verbose = 1;
633  		    setlinebuf(stdout);
634  		    break;
635  	
636  		case 'x': 			/* summary PMDA flag */
637  		    agent = 1;
638  		    verbose = 1;
639  		    isdaemon = 1;
640  		    break;
641  	
642  		case 'z':			/* timezone from host */
643  		    hostZone = 1;
644  		    if (timeZone) {
645  			fprintf(stderr, "%s: only one of -Z and -z allowed\n",
646  				pmProgname);
647  			err++;
648  		    }
649  		    break;
650  	
651  		case 'Z':			/* explicit TZ string */
652  		    timeZone = optarg;
653  		    if (hostZone) {
654  			fprintf(stderr, "%s: only one of -Z and -z allowed\n",
655  				pmProgname);
656  			err++;
657  		    }
658  		    break;
659  	
660  		case '?':
661  	            err++;
662  		}
663  	    }
664  	
665  	    if (configfile && optind != argc) {
666  		fprintf(stderr, "%s: extra filenames cannot be given after using -c\n",
667  			pmProgname);
668  		err++;
669  	    }
670  	    if (bflag && agent) {
671  		fprintf(stderr, "%s: the -b and -x options are incompatible\n",
672  			pmProgname);
673  		err++;
674  	    }
675  	    if (err)
676  	    	usageMessage();
677  	
678  	    if (foreground)
679  		isdaemon = 0;
680  	
681  	    if (archives || interactive)
682  		perf = &instrument;
683  	
684  	    if (isdaemon) {			/* daemon mode */
685  	#if defined(HAVE_TERMIO_SIGNALS)
686  		signal(SIGTTOU, SIG_IGN);
687  		signal(SIGTTIN, SIG_IGN);
688  		signal(SIGTSTP, SIG_IGN);
689  	#endif
690  		__pmSetSignalHandler(SIGINT, sigintproc);
691  		__pmSetSignalHandler(SIGTERM, sigintproc);
692  		__pmSetSignalHandler(SIGBUS, sigbadproc);
693  		__pmSetSignalHandler(SIGSEGV, sigbadproc);
694  	    }
695  	    else {
696  		/* need to catch these so the atexit() processing is done */
697  		__pmSetSignalHandler(SIGINT, sigbye);
698  		__pmSetSignalHandler(SIGTERM, sigbye);
699  	    }
700  	
701  	    if (commandlog != NULL) {
702  		logfp = __pmOpenLog(pmProgname, commandlog, stderr, &sts);
703  		if (realpath(commandlog, logfile) == NULL) {
704  		    fprintf(stderr, "%s: cannot find realpath for log %s: %s\n",
705  			    pmProgname, commandlog, osstrerror());
706  		    exit(1);
707  		}
708  		__pmSetSignalHandler(SIGHUP, (isdaemon && !agent) ? sighupproc : SIG_IGN);
709  	    } else {
710  		__pmSetSignalHandler(SIGHUP, SIG_IGN);
711  	    }
712  	
713  	    /*
714  	     * -b ... force line buffering and stdout onto stderr
715  	     */
716  	    if ((bflag || isdaemon) && !agent)
717  		remap_stdout_stderr();
718  	
719  	    if (dfltConn == 0) {
720  		/* default case, no -a or -h */
721  		dfltConn = PM_CONTEXT_HOST;
722  		dfltHost = localHost;
723  	    }
724  	
725  	    if (!archives && !interactive) {
726  		if (commandlog != NULL)
727  		    fprintf(stderr, "pmie: PID = %" FMT_PID ", default host = %s\n\n", getpid(), dfltHost);
728  		startmonitor();
729  	    }
730  	
731  	    /* default host from leftmost archive on command line */
732  	    if (archives && dfltHost == localHost) {
733  		a = archives;
734  		while (a->next)
735  		    a = a->next;
736  		dfltHost = a->hname;
737  	    }
738  	
739  	    /* initialize time */
740  	    now = archives ? first : getReal() + 1.0;
741  	    zoneInit();
742  	    reflectTime(dfltDelta);
743  	
744  	    /* parse time window - just to check argument syntax */
745  	    unrealize(now, &tv1);
746  	    if (archives)
747  		unrealize(last, &tv2);
748  	    else
749  		tv2.tv_sec = INT_MAX;		/* sizeof(time_t) == sizeof(int) */
750  	    if (pmParseTimeWindow(startFlag, stopFlag, alignFlag, offsetFlag,
751  	                          &tv1, &tv2,
752  	                          &tv, &tv2, &tv1,
753  			          &msg) < 0) {
754  		fputs(msg, stderr);
755  	        exit(1);
756  	    }
757  	    start = realize(tv1);
758  	    stop = realize(tv2);
759  	    runTime = stop - start;
760  	
761  	    /* initialize PMAPI */
762  	    if (pmnsfile != PM_NS_DEFAULT && (sts = pmLoadNameSpace(pmnsfile)) < 0) {
763  		fprintf(stderr, "%s: pmLoadNameSpace failed: %s\n", pmProgname,
764  			pmErrStr(sts));
765  		exit(1);
766  	    }
767  	
768  	    /* when not in secret agent mode, register client id with pmcd */
769  	    if (!agent)
770  		clientid = __pmGetClientId(argc, argv);
771  	
772  	    if (!interactive && optind == argc) {	/* stdin or config file */
773  		load(configfile);
774  	    }
775  	    else {					/* list of 1/more filenames */
776  		while (optind < argc) {
777  		    load(argv[optind]);
778  		    optind++;
779  		}
780  	    }
781  	
782  	#if PCP_DEBUG
783  	    if (pmDebug & DBG_TRACE_APPL1)
784  		dumpRules();
785  	#endif
786  	
787  	    if (checkFlag)
788  		exit(errs == 0 ? 0 : 1);	/* exit 1 for syntax errors ...
789  						 * suggestion from 
790  						 * Kevin Wang <kjw@rightsock.com>
791  						 */
792  	
793  	    if (isdaemon) {			/* daemon mode */
794  		/* Note: we can no longer unilaterally close stdin here, as it
795  		 * can really confuse remap_stdout_stderr() during log rotation!
796  		 */
797  		if (agent)
798  		    close(fileno(stdin));
799  	#ifndef IS_MINGW
800  		setsid();	/* not process group leader, lose controlling tty */
801  	#endif
802  	    }
803  	
804  	    if (stomping)
805  		stompInit();			/* connect to our message server */
806  	
807  	    if (agent)
808  		agentInit();			/* initialize secret agent stuff */
809  	
810  	    /* really parse time window */
811  	    if (!archives) {
812  		now = getReal() + 1.0;
813  		reflectTime(dfltDelta);
814  	    }
815  	    unrealize(now, &tv1);
816  	    if (archives)
817  		unrealize(last, &tv2);
818  	    else
819  		tv2.tv_sec = INT_MAX;
820  	    if (pmParseTimeWindow(startFlag, stopFlag, alignFlag, offsetFlag,
821  			          &tv1, &tv2,
822  	                          &tv, &tv2, &tv1,
823  			          &msg) < 0) {
824  		fputs(msg, stderr);
825  		exit(1);
826  	    }
827  	
828  	    /* set run timing window */
829  	    start = realize(tv1);
830  	    stop = realize(tv2);
831  	    runTime = stop - start;
832  	}
833  	
834  	/***********************************************************************
835  	 * interactive (debugging) mode
836  	 ***********************************************************************/
837  	
838  	static void
839  	interact(void)
840  	{
841  	    int			quit = 0;
Event alloc_fn: Calling allocation function "zalloc". [details]
Event var_assign: Assigning: "line" = storage returned from "zalloc(257UL)".
Also see events: [noescape][leaked_storage]
842  	    char		*line = (char *) zalloc(LINE_LENGTH + 2);
843  	    char		*finger;
844  	    char		*token;
845  	    char		*msg;
846  	    RealTime		rt;
847  	    struct timeval	tv1, tv2;
848  	
849  	    printf(intro, PCP_VERSION, menu, prompt);
850  	    fflush(stdout);
Event noescape: Variable "line" is not freed or pointed-to in function "readLine". [details]
Also see events: [alloc_fn][var_assign][leaked_storage]
At conditional (1): "!quit": Taking true branch.
At conditional (2): "readLine(line, 255)": Taking false branch.
851  	    while (!quit && readLine(line, LINE_LENGTH)) {
852  		finger = line;
853  	
854  		if ( (token = scanCmd(&finger)) ) { 
855  		    switch (*token) {
856  	
857  		    case 'f':
858  			token = scanArg(finger);
859  			load(token);
860  			break;
861  	
862  		    case 'l':
863  			token = scanArg(finger);
864  			list(token);
865  			break;
866  	
867  		    case 'r':
868  			token = scanArg(finger);
869  			if (token) {
870  			    if (pmParseInterval(token, &tv1, &msg) == 0)
871  				runTime = realize(tv1);
872  			    else {
873  				fputs(msg, stderr);
874  				free(msg);
875  				break;
876  			    }
877  			}
878  			if (!archives) {
879  			    invalidate();
880  			    rt = getReal();
881  			    if (now < rt)
882  				now = rt;
883  			    start = now;
884  			}
885  			stop = start + runTime;
886  			run();
887  			break;
888  	
889  		    case 'S':
890  			token = scanArg(finger);
891  			if (token == NULL) {
892  			    fprintf(stderr, "%s: error - argument required\n", pmProgname);
893  			    break;
894  			}
895  			unrealize(start, &tv1);
896  			if (archives)
897  			    unrealize(last, &tv2);
898  			else
899  			    tv2.tv_sec = INT_MAX;
900  			if (__pmParseTime(token, &tv1, &tv2, &tv1, &msg) < 0) {
901  			    fputs(msg, stderr);
902  			    free(msg);
903  			    break;
904  			}
905  			start = realize(tv1);
906  			if (archives)
907  			    invalidate();
908  			break;
909  	
910  		    case 'T':
911  			token = scanArg(finger);
912  			if (token == NULL) {
913  			    fprintf(stderr, "%s: error - argument required\n", pmProgname);
914  			    break;
915  			}
916  			if (pmParseInterval(token, &tv1, &msg) < 0) {
917  			    fputs(msg, stderr);
918  			    free(msg);
919  			    break;
920  			}
921  			runTime = realize(tv1);
922  			break;
923  		    case 'q':
924  			quit = 1;
925  			break;
926  	
927  		    case 'v':
928  			token = scanArg(finger);
929  			sublist(token);
930  			break;
931  	
932  		    case '?':
933  		    default:
934  			printf("%s", menu);
935  		    }
936  		}
937  		if (!quit) {
938  		    printf("%s", prompt);
939  		    fflush(stdout);
940  		}
941  	    }
Event leaked_storage: Variable "line" going out of scope leaks the storage it points to.
Also see events: [alloc_fn][var_assign][noescape]
942  	}
943  	
944  	
945  	/***********************************************************************
946  	 * main
947  	 ***********************************************************************/
948  	
949  	int
950  	main(int argc, char **argv)
951  	{
952  	    __pmSetProgname(argv[0]);
953  	    setlinebuf(stdout);
954  	
955  	    /* PCP_COUNTER_WRAP in environment enables "counter wrap" logic */
956  	    if (getenv("PCP_COUNTER_WRAP") != NULL)
957  		dowrap = 1;
958  	
959  	    getargs(argc, argv);
960  	
961  	    if (interactive)
962  		interact();
963  	    else
964  		run();
965  	    exit(0);
966  	}