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; }
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)); } }
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; }