1    	/*
2    	 * Metric metadata support for pmlogrewrite
3    	 *
4    	 * Copyright (c) 2011 Ken McDonell.  All Rights Reserved.
5    	 * 
6    	 * This program is free software; you can redistribute it and/or modify it
7    	 * under the terms of the GNU General Public License as published by the
8    	 * Free Software Foundation; either version 2 of the License, or (at your
9    	 * option) any later version.
10   	 * 
11   	 * This program is distributed in the hope that it will be useful, but
12   	 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   	 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   	 * for more details.
15   	 */
16   	
17   	#include "pmapi.h"
18   	#include "impl.h"
19   	#include "logger.h"
20   	#include <assert.h>
21   	
22   	/*
23   	 * Find or create a new metricspec_t
24   	 */
25   	metricspec_t *
26   	start_metric(pmID pmid)
27   	{
28   	    metricspec_t	*mp;
29   	    int			sts;
30   	
31   	#if PCP_DEBUG
32   	    if ((pmDebug & (DBG_TRACE_APPL0 | DBG_TRACE_APPL1)) == (DBG_TRACE_APPL0 | DBG_TRACE_APPL1))
33   		fprintf(stderr, "start_metric(%s)", pmIDStr(pmid));
34   	#endif
35   	
36   	    for (mp = metric_root; mp != NULL; mp = mp->m_next) {
37   		if (pmid == mp->old_desc.pmid) {
38   	#if PCP_DEBUG
39   		    if ((pmDebug & (DBG_TRACE_APPL0 | DBG_TRACE_APPL1)) == (DBG_TRACE_APPL0 | DBG_TRACE_APPL1))
40   			fprintf(stderr, " -> %s\n", mp->old_name);
41   	#endif
42   		    break;
43   		}
44   	    }
45   	    if (mp == NULL) {
46   		char	*name;
47   		pmDesc	desc;
48   	
49   		sts = pmNameID(pmid, &name);
50   		if (sts < 0) {
51   		    if (wflag) {
52   			snprintf(mess, sizeof(mess), "Metric %s pmNameID: %s", pmIDStr(pmid), pmErrStr(sts));
53   			yywarn(mess);
54   		    }
55   		    return NULL;
56   		}
57   		sts = pmLookupDesc(pmid, &desc);
58   		if (sts < 0) {
59   		    if (wflag) {
60   			snprintf(mess, sizeof(mess), "Metric %s: pmLookupDesc: %s", mp->old_name, pmErrStr(sts));
61   			yywarn(mess);
62   		    }
63   		    return NULL;
64   		}
65   	
66   		mp = (metricspec_t *)malloc(sizeof(metricspec_t));
67   		if (mp == NULL) {
68   		    fprintf(stderr, "metricspec malloc(%d) failed: %s\n", (int)sizeof(metricspec_t), strerror(errno));
69   		    abandon();
70   		}
71   		mp->m_next = metric_root;
72   		metric_root = mp;
73   		mp->output = OUTPUT_ALL;
74   		mp->one_inst = 0;
75   		mp->one_name = NULL;
76   		mp->old_name = name;
77   		mp->old_desc = desc;
78   		mp->new_desc = mp->old_desc;
79   		mp->flags = 0;
80   		mp->ip = NULL;
81   	#if PCP_DEBUG
82   		if ((pmDebug & (DBG_TRACE_APPL0 | DBG_TRACE_APPL1)) == (DBG_TRACE_APPL0 | DBG_TRACE_APPL1))
83   		    fprintf(stderr, " -> %s [new entry]\n", mp->old_name);
84   	#endif
85   	    }
86   	
87   	    return mp;
88   	}
89   	
90   	typedef struct {
91   	    __pmLogHdr	hdr;
92   	    pmDesc	desc;
93   	    int		numnames;
94   	    char	strbuf[1];
95   	} desc_t;
96   	
97   	/*
98   	 * reverse the logic of __pmLogPutDesc()
99   	 */
100  	static void
101  	_pmUnpackDesc(__pmPDU *pdubuf, pmDesc *desc, int *numnames, char ***names)
102  	{
103  	    desc_t	*pp;
104  	    int		i;
105  	    char	*p;
106  	    int		slen;
107  	
108  	    pp = (desc_t *)pdubuf;
109  	    desc->type = ntohl(pp->desc.type);
110  	    desc->sem = ntohl(pp->desc.sem);
111  	    desc->indom = __ntohpmInDom(pp->desc.indom);
112  	    desc->units = __ntohpmUnits(pp->desc.units);
113  	    desc->pmid = __ntohpmID(pp->desc.pmid);
114  	    *numnames = ntohl(pp->numnames);
115  	    *names = (char **)malloc(*numnames * sizeof(names[1]));
116  	    if (names == NULL) {
Event suspicious_sizeof: Passing argument "strerror(*__errno_location())" of type "char **" and argument "*numnames * sizeof (names[1]) /*8*/" to function "fprintf" is suspicious. Did you intend to use "sizeof(*names[1])" instead of "sizeof (names[1])" ? In this particular case sizeof(char **) happens to be equal to sizeof(char *), but this is not a portable assumption.
117  		fprintf(stderr, "_pmUnpackDesc malloc(%d) failed: %s\n", (int)(*numnames * sizeof(names[1])), strerror(errno));
118  		abandon();
119  	    }
120  	
121  	    p = pp->strbuf;
122  	    for (i = 0; i < *numnames; i++) {
123  		memcpy(&slen, p, LENSIZE);
124  		slen = ntohl(slen);
125  		p += LENSIZE;
126  		(*names)[i] = malloc(slen+1);
127  		if ((*names)[i] == NULL) {
128  		    fprintf(stderr, "_pmUnpackDesc malloc(%d) failed: %s\n", slen+1, strerror(errno));
129  		    abandon();
130  		}
131  		strncpy((*names)[i], p, slen);
132  		(*names)[i][slen] = '\0';
133  		p += slen;
134  	    }
135  	
136  	    return;
137  	}
138  	
139  	/*
140  	 * rewrite pmDesc from metadata, returns
141  	 * -1	delete this pmDesc
142  	 *  0	no change
143  	 *  1	changed
144  	 */
145  	void
146  	do_desc(void)
147  	{
148  	    metricspec_t	*mp;
149  	    pmDesc		desc;
150  	    int			i;
151  	    int			sts;
152  	    int			numnames;
153  	    char		**names;
154  	    long		out_offset;
155  	
156  	    out_offset = ftell(outarch.logctl.l_mdfp);
157  	    _pmUnpackDesc(inarch.metarec, &desc, &numnames, &names);
158  	
159  	    for (mp = metric_root; mp != NULL; mp = mp->m_next) {
160  		if (desc.pmid != mp->old_desc.pmid || mp->flags == 0)
161  		    continue;
162  		if (mp->flags & METRIC_DELETE) {
163  	#if PCP_DEBUG
164  		    if (pmDebug & DBG_TRACE_APPL1)
165  			fprintf(stderr, "Delete: pmDesc for %s\n", pmIDStr(desc.pmid));
166  	#endif
167  		    goto done;
168  		}
169  	#if PCP_DEBUG
170  		if (pmDebug & DBG_TRACE_APPL1)
171  		    fprintf(stderr, "Rewrite: pmDesc for %s\n", pmIDStr(desc.pmid));
172  	#endif
173  		if (mp->flags & METRIC_CHANGE_PMID)
174  		    desc.pmid = mp->new_desc.pmid;
175  		if (mp->flags & METRIC_CHANGE_NAME) {
176  		    for (i = 0; i < numnames; i++) {
177  			if (strcmp(names[i], mp->old_name) == 0) {
178  			    free(names[i]);
179  			    names[i] = strdup(mp->new_name);
180  			    if (names[i] == NULL) {
181  				fprintf(stderr, "do_desc strdup(%s) failed: %s\n", mp->new_name, strerror(errno));
182  				abandon();
183  			    }
184  			}
185  			break;
186  		    }
187  		    if (i == numnames) {
188  			fprintf(stderr, "%s: Botch: old name %s not found in list of %d names for pmid %s ...",
189  				pmProgname, mp->old_name, numnames, pmIDStr(mp->old_desc.pmid));
190  			for (i = 0; i < numnames; i++) {
191  			    if (i > 0) fputc(',', stderr);
192  			    fprintf(stderr, " %s", names[i]);
193  			}
194  			fputc('\n', stderr);
195  			abandon();
196  		    }
197  		}
198  		if (mp->flags & METRIC_CHANGE_TYPE)
199  		    desc.type = mp->new_desc.type;
200  		if (mp->flags & METRIC_CHANGE_INDOM)
201  		    desc.indom = mp->new_desc.indom;
202  		if (mp->flags & METRIC_CHANGE_SEM)
203  		    desc.sem = mp->new_desc.sem;
204  		if (mp->flags & METRIC_CHANGE_UNITS)
205  		    desc.units = mp->new_desc.units;	/* struct assignment */
206  		break;
207  	    }
208  	    if ((sts = __pmLogPutDesc(&outarch.logctl, &desc, numnames, names)) < 0) {
209  		fprintf(stderr, "%s: Error: __pmLogPutDesc: %s (%s): %s\n",
210  			pmProgname, names[0], pmIDStr(desc.pmid), pmErrStr(sts));
211  		abandon();
212  	    }
213  	#if PCP_DEBUG
214  	    if (pmDebug & DBG_TRACE_APPL0)
215  		fprintf(stderr, "Metadata: write PMID %s @ offset=%ld\n", pmIDStr(desc.pmid), out_offset);
216  	#endif
217  	
218  	done:
219  	    for (i = 0; i < numnames; i++)
220  		free(names[i]);
221  	    free(names);
222  	    return;
223  	}