Exemplo n.º 1
0
int
pmdaFetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda)
{
    int			i;		/* over pmidlist[] */
    int			j;		/* over metatab and vset->vlist[] */
    int			sts;
    int			need;
    int			inst;
    int			numval;
    pmValueSet		*vset;
    pmDesc		*dp;
    pmdaMetric          metaBuf;
    pmdaMetric		*metap;
    pmAtomValue		atom;
    int			type;
    e_ext_t		*extp = (e_ext_t *)pmda->e_ext;

    if (extp->dispatch->version.any.ext != pmda)
	fprintf(stderr, "Botch: pmdaFetch: PMDA domain=%d pmda=%p extp=%p backpointer=%p pmda-via-backpointer %p NOT EQUAL to pmda\n",
	    pmda->e_domain, pmda, extp, extp->dispatch, extp->dispatch->version.any.ext);

    if (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_5)
	__pmdaSetContext(pmda->e_context);

    if (numpmid > extp->maxnpmids) {
	if (extp->res != NULL)
	    free(extp->res);
	/* (numpmid - 1) because there's room for one valueSet in a pmResult */
	need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *);
	if ((extp->res = (pmResult *) malloc(need)) == NULL)
	    return -oserror();
	extp->maxnpmids = numpmid;
    }

    extp->res->timestamp.tv_sec = 0;
    extp->res->timestamp.tv_usec = 0;
    extp->res->numpmid = numpmid;

    /* Look up the pmDesc for the incoming pmids in our pmdaMetrics tables,
       if present.  Fall back to .desc callback if not found (for highly
       dynamic pmdas). */
    for (i = 0; i < numpmid; i++) {
        dp = NULL;

	if (pmda->e_flags & PMDA_EXT_FLAG_HASHED)
	    metap = __pmdaHashedSearch(pmidlist[i], &extp->hashpmids);
	else if (pmda->e_direct)
	    metap = __pmdaDirectSearch(pmidlist[i], pmda);
	else
	    metap = __pmdaLinearSearch(pmidlist[i], pmda);

	if (metap != NULL)
	    dp = &(metap->m_desc);
        else {
            /* possibly a highly dynamic metric with null metrictab[] */
            if (extp->dispatch->version.any.desc != NULL) {
                /* may need a temporary pmdaMetric for passing to e_fetchCallBack */
                sts = (*(extp->dispatch->version.any.desc))(pmidlist[i], &metaBuf.m_desc, pmda);
                if (sts >= 0) {
                    metaBuf.m_user = NULL;
                    metap = &metaBuf;
                    dp = &metaBuf.m_desc;
                }
            }
        }

	if (dp != NULL) {
	    if (dp->indom != PM_INDOM_NULL) {
		/* count instances in the profile */
		numval = 0;
		/* count instances in indom */
		__pmdaStartInst(dp->indom, pmda);
		while (__pmdaNextInst(&inst, pmda)) {
		    numval++;
		}
	    }
	    else {
		/* singular instance domains */
		numval = 1;
	    }
	}
	else {
	    /* dynamic name metrics may often vanish, avoid log spam */
	    if (extp->dispatch->comm.pmda_interface < PMDA_INTERFACE_4) {
		char	strbuf[20];
		__pmNotifyErr(LOG_ERR,
			"pmdaFetch: Requested metric %s is not defined",
			 pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)));
	    }
	    numval = PM_ERR_PMID;
	}


	/* Must use individual malloc()s because of pmFreeResult() */
	if (numval >= 1)
	    extp->res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) +
					    (numval - 1)*sizeof(pmValue));
	else
	    extp->res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) -
					    sizeof(pmValue));
	if (vset == NULL) {
	    sts = -oserror();
	    goto error;
	}
	vset->pmid = pmidlist[i];
	vset->numval = numval;
	vset->valfmt = PM_VAL_INSITU;
	if (vset->numval <= 0)
	    continue;

	if (dp->indom == PM_INDOM_NULL)
	    inst = PM_IN_NULL;
	else {
	    __pmdaStartInst(dp->indom, pmda);
	    __pmdaNextInst(&inst, pmda);
	}
	type = dp->type;
	j = 0;
	do {
	    if (j == numval) {
		/* more instances than expected! */
		numval++;
		extp->res->vset[i] = vset = (pmValueSet *)realloc(vset,
			    sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue));
		if (vset == NULL) {
		    sts = -oserror();
		    goto error;
		}
	    }
	    vset->vlist[j].inst = inst;

	    if ((sts = (*(pmda->e_fetchCallBack))(metap, inst, &atom)) < 0) {
		char	strbuf[20];

		pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf));
		if (sts == PM_ERR_PMID) {
		    __pmNotifyErr(LOG_ERR, 
		        "pmdaFetch: PMID %s not handled by fetch callback\n",
				strbuf);
		}
		else if (sts == PM_ERR_INST) {
#ifdef PCP_DEBUG
		    if (pmDebug & DBG_TRACE_LIBPMDA) {
			__pmNotifyErr(LOG_ERR,
			    "pmdaFetch: Instance %d of PMID %s not handled by fetch callback\n",
				    inst, strbuf);
		    }
#endif
		}
		else if (sts == PM_ERR_APPVERSION ||
			 sts == PM_ERR_PERMISSION ||
			 sts == PM_ERR_AGAIN ||
			 sts == PM_ERR_NYI) {
#ifdef PCP_DEBUG
		    if (pmDebug & DBG_TRACE_LIBPMDA) {
			__pmNotifyErr(LOG_ERR,
			     "pmdaFetch: Unavailable metric PMID %s[%d]\n",
				    strbuf, inst);
		    }
#endif
		}
		else {
		    __pmNotifyErr(LOG_ERR,
			"pmdaFetch: Fetch callback error from metric PMID %s[%d]: %s\n",
				strbuf, inst, pmErrStr(sts));
		}
	    }
	    else {
		/*
		 * PMDA_INTERFACE_2
		 *	>= 0 => OK
		 * PMDA_INTERFACE_3 or PMDA_INTERFACE_4
		 *	== 0 => no values
		 *	> 0  => OK
		 * PMDA_INTERFACE_5 or later
		 *	== 0 (PMDA_FETCH_NOVALUES) => no values
		 *	== 1 (PMDA_FETCH_STATIC) or > 2 => OK
		 *	== 2 (PMDA_FETCH_DYNAMIC) => OK and free(atom.vp)
		 *	     after __pmStuffValue() called
		 */
		if (extp->dispatch->comm.pmda_interface == PMDA_INTERFACE_2 ||
		    (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_3 && sts > 0)) {
		    int		lsts;

		    if ((lsts = __pmStuffValue(&atom, &vset->vlist[j], type)) == PM_ERR_TYPE) {
			char	strbuf[20];
			char	st2buf[20];
			__pmNotifyErr(LOG_ERR, 
				     "pmdaFetch: Descriptor type (%s) for metric %s is bad",
				     pmTypeStr_r(type, strbuf, sizeof(strbuf)),
				     pmIDStr_r(dp->pmid, st2buf, sizeof(st2buf)));
		    }
		    else if (lsts >= 0) {
			vset->valfmt = lsts;
			j++;
		    }
		    if (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_5 && sts == PMDA_FETCH_DYNAMIC) {
			if (type == PM_TYPE_STRING)
			    free(atom.cp);
			else if (type == PM_TYPE_AGGREGATE)
			    free(atom.vbp);
			else {
			    char	strbuf[20];
			    char	st2buf[20];
			    __pmNotifyErr(LOG_WARNING,
					  "pmdaFetch: Attempt to free value for metric %s of wrong type %s\n",
					  pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)),
					  pmTypeStr_r(type, st2buf, sizeof(st2buf)));
			}
		    }
		    if (lsts < 0)
			sts = lsts;
		}
	    }
	} while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, pmda));

	if (j == 0)
	    vset->numval = sts;
	else
	    vset->numval = j;

    }
    *resp = extp->res;
    return 0;

error:

    if (i) {
	extp->res->numpmid = i;
	__pmFreeResultValues(extp->res);
    }
    return sts;
}
Exemplo n.º 2
0
Arquivo: dso.c Projeto: linwukang/pcp
void
dodso(int pdu)
{
    int			sts = 0;		/* initialize to pander to gcc */
    int			length;
    pmDesc		desc;
    pmDesc		*desc_list = NULL;
    pmResult		*result;
    __pmInResult	*inresult;
    int			i;
    int			j;
    char		*buffer;
    struct timeval	start;
    struct timeval	end;
    char		name[32];
    char		**namelist;
    int			*statuslist;
    pmID		pmid;

    if (timer != 0)
        __pmtimevalNow(&start);

    switch (pdu) {

    case PDU_DESC_REQ:
        printf("PMID: %s\n", pmIDStr(param.pmid));
        if ((sts = dodso_desc(param.pmid, &desc)) >= 0)
            __pmPrintDesc(stdout, &desc);
        else
            printf("Error: DSO desc() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_FETCH:
        printf("PMID(s):");
        for (i = 0; i < param.numpmid; i++)
            printf(" %s", pmIDStr(param.pmidlist[i]));
        putchar('\n');

        if (get_desc) {
            desc_list = (pmDesc *)malloc(param.numpmid * sizeof(pmDesc));
            if (desc_list == NULL) {
                printf("Error: DSO fetch() failed: %s\n", pmErrStr(ENOMEM));
                return;
            }
            for (i = 0; i < param.numpmid; i++) {
                if ((sts = dodso_desc(param.pmidlist[i], &desc_list[i])) < 0) {
                    printf("Error: DSO desc() failed: %s\n", pmErrStr(sts));
                    free(desc_list);
                    return;
                }
            }
        }
        sts = 0;
        if (profile_changed) {
#ifdef PCP_DEBUG
            if (pmDebug & DBG_TRACE_PDU)
                fprintf(stderr, "DSO profile()\n");
#endif
            sts = dispatch.version.any.profile(profile, dispatch.version.any.ext);
            if (sts < 0)
                printf("Error: DSO profile() failed: %s\n", pmErrStr(sts));
            else
                profile_changed = 0;
        }
        if (sts >= 0) {
#ifdef PCP_DEBUG
            if (pmDebug & DBG_TRACE_PDU)
                fprintf(stderr, "DSO fetch()\n");
#endif
            sts = dispatch.version.any.fetch(param.numpmid, param.pmidlist,
                                             &result, dispatch.version.any.ext);
            if (sts >= 0) {
                if (desc_list)
                    _dbDumpResult(stdout, result, desc_list);
                else
                    __pmDumpResult(stdout, result);
                /*
                 * DSO PMDA will manage the pmResult skelton, but
                 * we need to free the pmValueSets and values here
                 */
                __pmFreeResultValues(result);
            }
            else {
                printf("Error: DSO fetch() failed: %s\n", pmErrStr(sts));
            }
        }
        if (desc_list)
            free(desc_list);
        break;

    case PDU_INSTANCE_REQ:
        printf("pmInDom: %s\n", pmInDomStr(param.indom));
#ifdef PCP_DEBUG
        if (pmDebug & DBG_TRACE_PDU)
            fprintf(stderr, "DSO instance()\n");
#endif

        sts = dispatch.version.any.instance(param.indom, param.number,
                                            param.name, &inresult,
                                            dispatch.version.any.ext);
        if (sts >= 0)
            printindom(stdout, inresult);
        else
            printf("Error: DSO instance() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_RESULT:

        printf("PMID: %s\n", pmIDStr(param.pmid));
        printf("Getting description...\n");
        desc_list = &desc;
        if ((sts = dodso_desc(param.pmid, desc_list)) < 0) {
            printf("Error: DSO desc() failed: %s\n", pmErrStr(sts));
            return;
        }

        if (profile_changed) {
            printf("Sending Profile...\n");
            sts = dispatch.version.any.profile(profile, dispatch.version.any.ext);
            if (sts < 0) {
                printf("Error: DSO profile() failed: %s\n", pmErrStr(sts));
                return;
            }
            else
                profile_changed = 0;
        }

        printf("Getting Result Structure...\n");
        sts = dispatch.version.any.fetch(1, &(desc.pmid), &result,
                                         dispatch.version.any.ext);
        if (sts < 0) {
            printf("Error: DSO fetch() failed: %s\n", pmErrStr(sts));
            return;
        }

#ifdef PCP_DEBUG
        else if (pmDebug & DBG_TRACE_FETCH)
            _dbDumpResult(stdout, result, desc_list);
#endif

        sts = fillResult(result, desc.type);
        if (sts < 0) {
            pmFreeResult(result);
            return;
        }

        sts = dispatch.version.any.store(result, dispatch.version.any.ext);
        if (sts < 0)
            printf("Error: DSO store() failed: %s\n", pmErrStr(sts));

        break;

    case PDU_TEXT_REQ:
        if (param.number == PM_TEXT_PMID) {
            printf("PMID: %s\n", pmIDStr(param.pmid));
            i = param.pmid;
        }
        else {
            printf("pmInDom: %s\n", pmInDomStr(param.indom));
            i = param.indom;
        }

        for (j = 0; j < 2; j++) {

            if (j == 0)
                param.number |= PM_TEXT_ONELINE;
            else {
                param.number &= ~PM_TEXT_ONELINE;
                param.number |= PM_TEXT_HELP;
            }

            sts = dispatch.version.any.text(i, param.number, &buffer, dispatch.version.any.ext);
            if (sts >= 0) {
                if (j == 0) {
                    if (*buffer != '\0')
                        printf("[%s]\n", buffer);
                    else
                        printf("[<no one line help text specified>]\n");
                }
                else if (*buffer != '\0')
                    printf("%s\n", buffer);
                else
                    printf("<no help text specified>\n");
            }
            else
                printf("Error: DSO text() failed: %s\n", pmErrStr(sts));
        }
        break;

    case PDU_PMNS_IDS:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("PMID: %s\n", pmIDStr(param.pmid));
        sts = dispatch.version.four.name(param.pmid, &namelist, dispatch.version.four.ext);
        if (sts > 0) {
            for (i = 0; i < sts; i++) {
                printf("   %s\n", namelist[i]);
            }
            free(namelist);
        }
        else if (sts == 0)
            printf("Warning: DSO name() returns 0\n");
        else
            printf("Error: DSO name() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_PMNS_NAMES:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("Metric: %s\n", param.name);
        sts = dispatch.version.four.pmid(param.name, &pmid, dispatch.version.four.ext);
        if (sts >= 0)
            printf("   %s\n", pmIDStr(pmid));
        else
            printf("Error: DSO pmid() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_PMNS_CHILD:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("Metric: %s\n", param.name);
        sts = dispatch.version.four.children(param.name, 0, &namelist, &statuslist, dispatch.version.four.ext);
        if (sts > 0) {
            for (i = 0; i < sts; i++) {
                printf("   %8.8s %s\n", statuslist[i] == 1 ? "non-leaf" : "leaf", namelist[i]);
            }
            free(namelist);
            free(statuslist);
        }
        else if (sts == 0)
            printf("Warning: DSO children() returns 0\n");
        else
            printf("Error: DSO children() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_PMNS_TRAVERSE:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("Metric: %s\n", param.name);
        sts = dispatch.version.four.children(param.name, 1, &namelist, &statuslist, dispatch.version.four.ext);
        if (sts > 0) {
            for (i = 0; i < sts; i++) {
                printf("   %8.8s %s\n", statuslist[i] == 1 ? "non-leaf" : "leaf", namelist[i]);
            }
            free(namelist);
            free(statuslist);
        }
        else if (sts == 0)
            printf("Warning: DSO children() returns 0\n");
        else
            printf("Error: DSO children() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_AUTH:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_6) {
            printf("Error: PMDA Interface %d does not support authentication\n", dispatch.comm.pmda_interface);
            break;
        }
        j = param.number;			/* attribute key */
        buffer = param.name;		/* attribute value */
        if (buffer)
            length = strlen(buffer) + 1;	/* length of value */
        else
            length = 0;
        i = 0;				/* client ID */

        __pmAttrKeyStr_r(j, name, sizeof(name)-1);
        name[sizeof(name)-1] = '\0';

        printf("Attribute: %s=%s\n", name, buffer ? buffer : "''");
        sts = dispatch.version.six.attribute(i, j, buffer, length, dispatch.version.six.ext);
        if (sts >= 0)
            printf("Success\n");
        else
            printf("Error: DSO attribute() failed: %s\n", pmErrStr(sts));
        break;

    default:
        printf("Error: DSO PDU (%s) botch!\n", __pmPDUTypeStr(pdu));
        break;
    }

    if (sts >= 0 && timer != 0) {
        __pmtimevalNow(&end);
        printf("Timer: %f seconds\n", __pmtimevalSub(&end, &start));
    }
}
Exemplo n.º 3
0
int
DoFetch(ClientInfo *cip, __pmPDU* pb)
{
    int			i, j;
    int 		sts;
    int			ctxnum;
    __pmTimeval		when;
    int			nPmids;
    pmID		*pmidList;
    static pmResult	*endResult = NULL;
    static int		maxnpmids = 0;	/* sizes endResult */
    DomPmidList		*dList;		/* NOTE: NOT indexed by agent index */
    static int		nDoms = 0;
    static pmResult	**results = NULL;
    static int		*resIndex = NULL;
    __pmFdSet		waitFds;
    __pmFdSet		readyFds;
    int			nWait;
    int			maxFd;
    struct timeval	timeout;

    if (nAgents > nDoms) {
	if (results != NULL)
	    free(results);
	if (resIndex != NULL)
	    free(resIndex);
	results = (pmResult **)malloc((nAgents + 1) * sizeof (pmResult *));
	resIndex = (int *)malloc((nAgents + 1) * sizeof(int));
	if (results == NULL || resIndex == NULL) {
	    __pmNoMem("DoFetch.results", (nAgents + 1) * sizeof (pmResult *) + (nAgents + 1) * sizeof(int), PM_FATAL_ERR);
	}
	nDoms = nAgents;
    }
    memset(results, 0, (nAgents + 1) * sizeof(results[0]));

    sts = __pmDecodeFetch(pb, &ctxnum, &when, &nPmids, &pmidList);
    if (sts < 0)
	return sts;

    /* Check that a profile has been received from the specified context */
    if (ctxnum < 0 || ctxnum >= cip->szProfile ||
	cip->profile[ctxnum] == NULL) {
	__pmUnpinPDUBuf(pb);
	if (ctxnum < 0 || ctxnum >= cip->szProfile)
	    __pmNotifyErr(LOG_ERR, "DoFetch: bad ctxnum=%d\n", ctxnum);
	else
	    __pmNotifyErr(LOG_ERR, "DoFetch: no profile for ctxnum=%d\n", ctxnum);
	return PM_ERR_NOPROFILE;
    }

    if (nPmids > maxnpmids) {
	int		need;
	if (endResult != NULL)
	    free(endResult);
	need = (int)sizeof(pmResult) + (nPmids - 1) * (int)sizeof(pmValueSet *);
	if ((endResult = (pmResult *)malloc(need)) == NULL) {
	    __pmNoMem("DoFetch.endResult", need, PM_FATAL_ERR);
	}
	maxnpmids = nPmids;
    }

    dList = SplitPmidList(nPmids, pmidList);

    /* For each domain in the split pmidList, dispatch the per-domain subset
     * of pmIDs to the appropriate agent.  For DSO agents, the pmResult will
     * come back immediately.  If a request cannot be sent to an agent, a
     * suitable pmResult (containing metric not available values) will be
     * returned.
     */
    __pmFD_ZERO(&waitFds);
    nWait = 0;
    maxFd = -1;
    for (i = 0; dList[i].domain != -1; i++) {
	j = mapdom[dList[i].domain];
	results[j] = SendFetch(&dList[i], &agent[j], cip, ctxnum);
	if (results[j] == NULL) { /* Wait for agent's response */
	    int fd = agent[j].outFd;
	    agent[j].status.busy = 1;
	    __pmFD_SET(fd, &waitFds);
	    if (fd > maxFd)
		maxFd = fd;
	    nWait++;
	}
    }
    /* Construct pmResult for bad-pmID list */
    if (dList[i].listSize != 0)
	results[nAgents] = MakeBadResult(dList[i].listSize, dList[i].list, PM_ERR_NOAGENT);

    /* Wait for results to roll in from agents */
    while (nWait > 0) {
        __pmFD_COPY(&readyFds, &waitFds);
	if (nWait > 1) {
	    timeout.tv_sec = _pmcd_timeout;
	    timeout.tv_usec = 0;

            retry:
	    setoserror(0);
	    sts = __pmSelectRead(maxFd+1, &readyFds, &timeout);

	    if (sts == 0) {
		__pmNotifyErr(LOG_INFO, "DoFetch: select timeout");

		/* Timeout, terminate agents with undelivered results */
		for (i = 0; i < nAgents; i++) {
		    if (agent[i].status.busy) {
			/* Find entry in dList for this agent */
			for (j = 0; dList[j].domain != -1; j++)
			    if (dList[j].domain == agent[i].pmDomainId)
				break;
			results[i] = MakeBadResult(dList[j].listSize,
						   dList[j].list,
						   PM_ERR_NOAGENT);
			pmcd_trace(TR_RECV_TIMEOUT, agent[i].outFd, PDU_RESULT, 0);
			CleanupAgent(&agent[i], AT_COMM, agent[i].inFd);
		    }
		}
		break;
	    }
	    else if (sts < 0) {
		if (neterror() == EINTR)
		    goto retry;
		/* this is not expected to happen! */
		__pmNotifyErr(LOG_ERR, "DoFetch: fatal select failure: %s\n",
			netstrerror());
		Shutdown();
		exit(1);
	    }
	}

	/* Read results from agents that have them ready */
	for (i = 0; i < nAgents; i++) {
	    AgentInfo	*ap = &agent[i];
	    int		pinpdu;
	    if (!ap->status.busy || !__pmFD_ISSET(ap->outFd, &readyFds))
		continue;
	    ap->status.busy = 0;
	    __pmFD_CLR(ap->outFd, &waitFds);
	    nWait--;
	    pinpdu = sts = __pmGetPDU(ap->outFd, ANY_SIZE, _pmcd_timeout, &pb);
	    if (sts > 0)
		pmcd_trace(TR_RECV_PDU, ap->outFd, sts, (int)((__psint_t)pb & 0xffffffff));
	    if (sts == PDU_RESULT) {
		if ((sts = __pmDecodeResult(pb, &results[i])) >= 0)
		    if (results[i]->numpmid != aFreq[i]) {
			pmFreeResult(results[i]);
			sts = PM_ERR_IPC;
#ifdef PCP_DEBUG
			if (pmDebug & DBG_TRACE_APPL0)
			    __pmNotifyErr(LOG_ERR, "DoFetch: \"%s\" agent given %d pmIDs, returned %d\n",
					 ap->pmDomainLabel, aFreq[i], results[i]->numpmid);
#endif
		    }
	    }
	    else {
		if (sts == PDU_ERROR) {
		    int s;
		    if ((s = __pmDecodeError(pb, &sts)) < 0)
			sts = s;
		    else if (sts >= 0)
			sts = PM_ERR_GENERIC;
		    pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_RESULT, sts);
		}
		else if (sts >= 0) {
		    pmcd_trace(TR_WRONG_PDU, ap->outFd, PDU_RESULT, sts);
		    sts = PM_ERR_IPC;
		}
	    }
	    if (pinpdu > 0)
		__pmUnpinPDUBuf(pb);

	    if (sts < 0) {
		/* Find entry in dList for this agent */
		for (j = 0; dList[j].domain != -1; j++)
		    if (dList[j].domain == agent[i].pmDomainId)
			break;
		results[i] = MakeBadResult(dList[j].listSize,
					   dList[j].list, sts);

		if (sts == PM_ERR_PMDANOTREADY) {
		    /* the agent is indicating it can't handle PDUs for now */
		    int k;
		    extern int CheckError(AgentInfo *ap, int sts);

		    for (k = 0; k < dList[j].listSize; k++)
			results[i]->vset[k]->numval = PM_ERR_AGAIN;
		    sts = CheckError(&agent[i], sts);
		}

#ifdef PCP_DEBUG
		if (pmDebug & DBG_TRACE_APPL0) {
		    fprintf(stderr, "RESULT error from \"%s\" agent : %s\n",
			    ap->pmDomainLabel, pmErrStr(sts));
		}
#endif
		if (sts == PM_ERR_IPC || sts == PM_ERR_TIMEOUT)
		    CleanupAgent(ap, AT_COMM, ap->outFd);
	    }
	}
    }

    endResult->numpmid = nPmids;
    __pmtimevalNow(&endResult->timestamp);
    /* The order of the pmIDs in the per-domain results is the same as in the
     * original request, but on a per-domain basis.  resIndex is an array of
     * indices (one per agent) of the next metric to be retrieved from each
     * per-domain result's vset.
     */
    memset(resIndex, 0, (nAgents + 1) * sizeof(resIndex[0]));

    for (i = 0; i < nPmids; i++) {
	j = mapdom[((__pmID_int *)&pmidList[i])->domain];
	endResult->vset[i] = results[j]->vset[resIndex[j]++];
    }
    pmcd_trace(TR_XMIT_PDU, cip->fd, PDU_RESULT, endResult->numpmid);

    sts = 0;
    if (cip->status.changes) {
	/* notify client of PMCD state change */
	sts = __pmSendError(cip->fd, FROM_ANON, (int)cip->status.changes);
	if (sts > 0)
	    sts = 0;
	cip->status.changes = 0;
    }
    if (sts == 0)
	sts = __pmSendResult(cip->fd, FROM_ANON, endResult);

    if (sts < 0) {
	pmcd_trace(TR_XMIT_ERR, cip->fd, PDU_RESULT, sts);
	CleanupClient(cip, sts);
    }

    /*
     * pmFreeResult() all the accumulated results.
     */
    for (i = 0; dList[i].domain != -1; i++) {
	j = mapdom[dList[i].domain];
	if (agent[j].ipcType == AGENT_DSO && agent[j].status.connected &&
	    !agent[j].status.madeDsoResult)
	    /* Living DSO's manage their own pmResult skeleton unless
	     * MakeBadResult was called to create the result.  The value sets
	     * within the skeleton need to be freed though!
	     */
	    __pmFreeResultValues(results[j]);
	else
	    /* For others it is dynamically allocated in __pmDecodeResult or
	     * MakeBadResult
	     */
	    pmFreeResult(results[j]);
    }
    if (results[nAgents] != NULL)
	pmFreeResult(results[nAgents]);
    __pmUnpinPDUBuf(pmidList);
    return 0;
}