1    	/*
2    	 * Indom 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 indomspec_t
24   	 */
25   	indomspec_t *
26   	start_indom(pmInDom indom)
27   	{
28   	    indomspec_t	*ip;
29   	    int		i;
30   	
31   	    for (ip = indom_root; ip != NULL; ip = ip->i_next) {
32   		if (indom == ip->old_indom)
33   		    break;
34   	    }
35   	    if (ip == NULL) {
36   		int	numinst;
37   		int	*instlist;
38   		char	**namelist;
39   	
40   		numinst = pmGetInDomArchive(indom, &instlist, &namelist);
41   		if (numinst < 0) {
42   		    if (wflag) {
43   			snprintf(mess, sizeof(mess), "Instance domain %s: %s", pmInDomStr(indom), pmErrStr(numinst));
44   			yywarn(mess);
45   		    }
46   		    return NULL;
47   		}
48   	
49   		ip = (indomspec_t *)malloc(sizeof(indomspec_t));
50   		if (ip == NULL) {
51   		    fprintf(stderr, "indomspec malloc(%d) failed: %s\n", (int)sizeof(indomspec_t), strerror(errno));
52   		    abandon();
53   		}
54   		ip->i_next = indom_root;
55   		indom_root = ip;
56   		ip->flags = (int *)malloc(numinst*sizeof(int));
57   		if (ip->flags == NULL) {
58   		    fprintf(stderr, "indomspec flags malloc(%d) failed: %s\n", numinst*(int)sizeof(int), strerror(errno));
59   		    abandon();
60   		}
61   		for (i = 0; i < numinst; i++)
62   		    ip->flags[i] = 0;
63   		ip->old_indom = indom;
64   		ip->new_indom = indom;
65   		ip->numinst = numinst;
66   		ip->old_inst = instlist;
67   		ip->new_inst = (int *)malloc(numinst*sizeof(int));
68   		if (ip->new_inst == NULL) {
69   		    fprintf(stderr, "new_inst malloc(%d) failed: %s\n", numinst*(int)sizeof(int), strerror(errno));
70   		    abandon();
71   		}
72   		ip->old_iname = namelist;
73   		ip->new_iname = (char **)malloc(numinst*sizeof(char *));
74   		if (ip->new_iname == NULL) {
75   		    fprintf(stderr, "new_iname malloc(%d) failed: %s\n", numinst*(int)sizeof(char *), strerror(errno));
76   		    abandon();
77   		}
78   	    }
79   	
80   	    return ip;
81   	}
82   	
83   	int
84   	change_inst_by_name(pmInDom indom, char *old, char *new)
85   	{
86   	    int		i;
87   	    indomspec_t	*ip;
88   	
89   	    for (ip = indom_root; ip != NULL; ip = ip->i_next) {
90   		if (indom == ip->old_indom)
91   		    break;
92   	    }
93   	    assert(ip != NULL);
94   	
95   	    for (i = 0; i < ip->numinst; i++) {
96   		if (inst_name_eq(ip->old_iname[i], old) > 0) {
97   		    if ((new == NULL && ip->flags[i]) ||
98   		        (ip->flags[i] & (INST_CHANGE_INAME|INST_DELETE))) {
99   			snprintf(mess, sizeof(mess), "Duplicate or conflicting clauses for instance [%d] \"%s\" of indom %s",
100  			    ip->old_inst[i], ip->old_iname[i], pmInDomStr(indom));
101  			return -1;
102  		    }
103  		    break;
104  		}
105  	    }
106  	    if (i == ip->numinst) {
107  		if (wflag) {
108  		    snprintf(mess, sizeof(mess), "Unknown instance \"%s\" in iname clause for indom %s", old, pmInDomStr(indom));
109  		    yywarn(mess);
110  		}
111  		return 0;
112  	    }
113  	
114  	    if (new == NULL) {
115  		ip->flags[i] |= INST_DELETE;
116  		ip->new_iname[i] = NULL;
117  		return 0;
118  	    }
119  	
120  	    if (strcmp(ip->old_iname[i], new) == 0) {
121  		/* no change ... */
122  		if (wflag) {
123  		    snprintf(mess, sizeof(mess), "Instance domain %s: Instance: \"%s\": No change", pmInDomStr(indom), ip->old_iname[i]);
124  		    yywarn(mess);
125  		}
126  	    }
127  	    else {
128  		ip->flags[i] |= INST_CHANGE_INAME;
129  		ip->new_iname[i] = new;
130  	    }
131  	
132  	    return 0;
133  	}
134  	
135  	int
136  	change_inst_by_inst(pmInDom indom, int old, int new)
137  	{
138  	    int		i;
139  	    indomspec_t	*ip;
140  	
141  	    for (ip = indom_root; ip != NULL; ip = ip->i_next) {
142  		if (indom == ip->old_indom)
143  		    break;
144  	    }
145  	    assert(ip != NULL);
146  	
147  	    for (i = 0; i < ip->numinst; i++) {
148  		if (ip->old_inst[i] == old) {
149  		    if ((new == PM_IN_NULL && ip->flags[i]) ||
150  		        (ip->flags[i] & (INST_CHANGE_INST|INST_DELETE))) {
151  			snprintf(mess, sizeof(mess), "Duplicate or conflicting clauses for instance [%d] \"%s\" of indom %s",
152  			    ip->old_inst[i], ip->old_iname[i], pmInDomStr(indom));
153  			return -1;
154  		    }
155  		    break;
156  		}
157  	    }
158  	    if (i == ip->numinst) {
159  		if (wflag) {
160  		    snprintf(mess, sizeof(mess), "Unknown instance %d in inst clause for indom %s", old, pmInDomStr(indom));
161  		    yywarn(mess);
162  		}
163  		return 0;
164  	    }
165  	
166  	    if (new == PM_IN_NULL) {
167  		ip->flags[i] |= INST_DELETE;
168  		ip->new_inst[i] = PM_IN_NULL;
169  		return 0;
170  	    }
171  	    
172  	    if (ip->old_inst[i] == new) {
173  		/* no change ... */
174  		if (wflag) {
175  		    snprintf(mess, sizeof(mess), "Instance domain %s: Instance: %d: No change", pmInDomStr(indom), ip->old_inst[i]);
176  		    yywarn(mess);
177  		}
178  	    }
179  	    else {
180  		ip->new_inst[i] = new;
181  		ip->flags[i] |= INST_CHANGE_INST;
182  	    }
183  	
184  	    return 0;
185  	}
186  	
187  	typedef struct {
188  	    __pmLogHdr	hdr;
189  	    __pmTimeval	stamp;
190  	    pmInDom	indom;
191  	    int		numinst;
192  	    char	other[1];
193  	} indom_t;
194  	
195  	/*
196  	 * reverse the logic of __pmLogPutInDom()
197  	 */
198  	static void
199  	_pmUnpackInDom(__pmPDU *pdubuf, pmInDom *indom, __pmTimeval *tp, int *numinst, int **instlist, char ***inamelist)
200  	{
201  	    indom_t	*idp;
202  	    int		i;
203  	    int		*ip;
204  	    char	*strbuf;
205  	
206  	    idp = (indom_t *)pdubuf;
207  	
208  	    tp->tv_sec = ntohl(idp->stamp.tv_sec);
209  	    tp->tv_usec = ntohl(idp->stamp.tv_usec);
210  	    *indom = __ntohpmInDom(idp->indom);
211  	    *numinst = ntohl(idp->numinst);
212  	    *instlist = (int *)malloc(*numinst * sizeof(int));
213  	    if (*instlist == NULL) {
214  		fprintf(stderr, "_pmUnpackInDom instlist malloc(%d) failed: %s\n", (int)(*numinst * sizeof(int)), strerror(errno));
215  		abandon();
216  	    }
217  	    ip = (int *)idp->other;
218  	    for (i = 0; i < *numinst; i++)
219  		(*instlist)[i] = ntohl(*ip++);
220  	    *inamelist = (char **)malloc(*numinst * sizeof(char *));
221  	    if (*inamelist == NULL) {
Event suspicious_sizeof: Passing argument "strerror(*__errno_location())" of type "char *" and argument "*numinst * sizeof (char *) /*8*/" to function "fprintf" is suspicious.
222  		fprintf(stderr, "_pmUnpackInDom inamelist malloc(%d) failed: %s\n", (int)(*numinst * sizeof(char *)), strerror(errno));
223  		abandon();
224  	    }
225  	    /*
226  	     * ip[i] is stridx[i], which is offset into strbuf[]
227  	     */
228  	    strbuf = (char *)&ip[*numinst];
229  	    for (i = 0; i < *numinst; i++) {
230  		(*inamelist)[i] = &strbuf[ntohl(ip[i])];
231  	    }
232  	}
233  	
234  	/*
235  	 * Note:
236  	 * 	We unpack the indom metadata record _again_ (was already done when
237  	 * 	the input archive was opened), but the data structure behind
238  	 * 	__pmLogCtl has differences for 32-bit and 64-bit pointers and
239  	 * 	modifying it as part of the rewrite could make badness break
240  	 * 	out later.  It is safer to do it again, populate local copies
241  	 * 	of instlist[] and inamelist[], dink with 'em and then toss them
242  	 * 	away.
243  	 */
244  	void
245  	do_indom(void)
246  	{
247  	    long	out_offset;
248  	    pmInDom	indom;
249  	    __pmTimeval	stamp;
250  	    int		numinst;
251  	    int		*instlist;
252  	    char	**inamelist;
253  	    indomspec_t	*ip;
254  	    int		sts;
255  	    int		i;
256  	    int		j;
257  	    int		need_alloc = 0;
258  	
259  	    out_offset = ftell(outarch.logctl.l_mdfp);
260  	    _pmUnpackInDom(inarch.metarec, &indom, &stamp, &numinst, &instlist, &inamelist);
261  	
262  	    /*
263  	     * global time stamp adjustment (if any has already been done in the
264  	     * PDU buffer, so this is reflected in the unpacked value of stamp.
265  	     */
266  	    for (ip = indom_root; ip != NULL; ip = ip->i_next) {
267  		if (ip->old_indom != indom)
268  		    continue;
269  		if (ip->new_indom != ip->old_indom)
270  		    indom = ip->new_indom;
271  		for (i = 0; i < ip->numinst; i++) {
272  		    for (j = 0; j < numinst; j++) {
273  			if (ip->old_inst[i] == instlist[j])
274  			    break;
275  		    }
276  		    if (j == numinst)
277  			continue;
278  		    if (ip->flags[i] & INST_DELETE) {
279  	#if PCP_DEBUG
280  			if (pmDebug & DBG_TRACE_APPL1)
281  			    fprintf(stderr, "Delete: instance %s (%d) for indom %s\n", ip->old_iname[i], ip->old_inst[i], pmInDomStr(ip->old_indom));
282  	#endif
283  			j++;
284  			while (j < numinst) {
285  			    instlist[j-1] = instlist[j];
286  			    inamelist[j-1] = inamelist[j];
287  			    j++;
288  			}
289  			need_alloc = 1;
290  			numinst--;
291  		    }
292  		    else {
293  			if (ip->flags[i] & INST_CHANGE_INST)
294  			    instlist[j] = ip->new_inst[i];
295  			if (ip->flags[i] & INST_CHANGE_INAME) {
296  			    inamelist[j] = ip->new_iname[i];
297  			    need_alloc = 1;
298  			}
299  	#if PCP_DEBUG
300  			if ((ip->flags[i] & (INST_CHANGE_INST | INST_CHANGE_INAME)) && (pmDebug & DBG_TRACE_APPL1)) {
301  			    if ((ip->flags[i] & (INST_CHANGE_INST | INST_CHANGE_INAME)) == (INST_CHANGE_INST | INST_CHANGE_INAME))
302  				fprintf(stderr, "Rewrite: instance %s (%d) -> %s (%d) for indom %s\n", ip->old_iname[i], ip->old_inst[i], ip->new_iname[i], ip->new_inst[i], pmInDomStr(ip->old_indom));
303  			    else if ((ip->flags[i] & (INST_CHANGE_INST | INST_CHANGE_INAME)) == INST_CHANGE_INST)
304  				fprintf(stderr, "Rewrite: instance %s (%d) -> %s (%d) for indom %s\n", ip->old_iname[i], ip->old_inst[i], ip->old_iname[i], ip->new_inst[i], pmInDomStr(ip->old_indom));
305  			    else
306  				fprintf(stderr, "Rewrite: instance %s (%d) -> %s (%d) for indom %s\n", ip->old_iname[i], ip->old_inst[i], ip->new_iname[i], ip->old_inst[i], pmInDomStr(ip->old_indom));
307  			}
308  	#endif
309  		    }
310  		}
311  	    }
312  	
313  	    if (need_alloc) {
314  		/*
315  		 * __pmLogPutInDom assumes the elements of inamelist[] point into
316  		 * of a contiguous allocation starting at inamelist[0] ... if we've
317  		 * changed an instance name or moved instance names about, then we
318  		 * need to reallocate the strings for inamelist[]
319  		 */
320  		int	need = 0;
321  		char	*new;
322  		char	*p;
323  	
324  		for (j = 0; j < numinst; j++)
325  		    need += strlen(inamelist[j]) + 1;
326  		new = (char *)malloc(need);
327  		if (new == NULL) {
328  		    fprintf(stderr, "inamelist[] malloc(%d) failed: %s\n", need, strerror(errno));
329  		    abandon();
330  		}
331  		p = new;
332  		for (j = 0; j < numinst; j++) {
333  		    strcpy(p, inamelist[j]);
334  		    inamelist[j] = p;
335  		    p += strlen(p) + 1;
336  		}
337  	    }
338  	
339  	    if ((sts = __pmLogPutInDom(&outarch.logctl, indom, &stamp, numinst, instlist, inamelist)) < 0) {
340  		fprintf(stderr, "%s: Error: __pmLogPutInDom: %s: %s\n",
341  				pmProgname, pmInDomStr(indom), pmErrStr(sts));
342  		abandon();
343  	    }
344  	#if PCP_DEBUG
345  	    if (pmDebug & DBG_TRACE_APPL0) {
346  		fprintf(stderr, "Metadata: write InDom %s @ offset=%ld\n", pmInDomStr(indom), out_offset);
347  	    }
348  	#endif
349  	
350  	    free(instlist);
351  	    if (need_alloc)
352  		free(inamelist[0]);
353  	    free(inamelist);
354  	}