static int ctxflags(__pmHashCtl *attrs, int *flags) { int sts; char *name = NULL; char *secure = NULL; char *container = NULL; __pmHashNode *node; if ((node = __pmHashSearch(PCP_ATTR_PROTOCOL, attrs)) != NULL) { if (strcmp((char *)node->data, "pcps") == 0) { if ((node = __pmHashSearch(PCP_ATTR_SECURE, attrs)) != NULL) secure = (char *)node->data; else secure = "enforce"; } } if (!secure) secure = getenv("PCP_SECURE_SOCKETS"); if (secure) { if (secure[0] == '\0' || (strcmp(secure, "1")) == 0 || (strcmp(secure, "enforce")) == 0) { *flags |= PM_CTXFLAG_SECURE; } else if (strcmp(secure, "relaxed") == 0) { *flags |= PM_CTXFLAG_RELAXED; } } if (__pmHashSearch(PCP_ATTR_COMPRESS, attrs) != NULL) *flags |= PM_CTXFLAG_COMPRESS; if (__pmHashSearch(PCP_ATTR_USERAUTH, attrs) != NULL || __pmHashSearch(PCP_ATTR_USERNAME, attrs) != NULL || __pmHashSearch(PCP_ATTR_PASSWORD, attrs) != NULL || __pmHashSearch(PCP_ATTR_METHOD, attrs) != NULL || __pmHashSearch(PCP_ATTR_REALM, attrs) != NULL) *flags |= PM_CTXFLAG_AUTH; if (__pmHashSearch(PCP_ATTR_CONTAINER, attrs) != NULL) *flags |= PM_CTXFLAG_CONTAINER; else if ((container = getenv("PCP_CONTAINER")) != NULL) { if ((name = strdup(container)) == NULL) return -ENOMEM; if ((sts = __pmHashAdd(PCP_ATTR_CONTAINER, (void *)name, attrs)) < 0) { free(name); return sts; } *flags |= PM_CTXFLAG_CONTAINER; } if (__pmHashSearch(PCP_ATTR_EXCLUSIVE, attrs) != NULL) *flags |= PM_CTXFLAG_EXCLUSIVE; return 0; }
int __pmUnparseHostAttrsSpec( pmHostSpec *hosts, int count, __pmHashCtl *attrs, char *string, size_t size) { __pmHashNode *node; int off = 0, len = size; /* offset in string and space remaining */ int sts, first; if ((node = __pmHashSearch(PCP_ATTR_PROTOCOL, attrs)) != NULL) { if ((sts = pmsprintf(string, len, "%s://", (char *)node->data)) >= len) return -E2BIG; len -= sts; off += sts; } else if (__pmHashSearch(PCP_ATTR_UNIXSOCK, attrs) != NULL) { if ((sts = pmsprintf(string, len, "unix:/")) >= len) return -E2BIG; len -= sts; off += sts; } else if (__pmHashSearch(PCP_ATTR_LOCAL, attrs) != NULL) { if ((sts = pmsprintf(string, len, "local:/")) >= len) return -E2BIG; len -= sts; off += sts; } if ((sts = unparseHostSpec(hosts, count, string + off, len, 0)) >= len) return sts; len -= sts; off += sts; first = 1; for (node = __pmHashWalk(attrs, PM_HASH_WALK_START); node != NULL; node = __pmHashWalk(attrs, PM_HASH_WALK_NEXT)) { if (node->key == PCP_ATTR_PROTOCOL || node->key == PCP_ATTR_UNIXSOCK || node->key == PCP_ATTR_LOCAL) continue; if ((sts = pmsprintf(string + off, len, "%c", first ? '?' : '&')) >= len) return -E2BIG; len -= sts; off += sts; first = 0; if ((sts = unparseAttribute(node, string + off, len)) >= len) return -E2BIG; len -= sts; off += sts; } return off; }
/* logging (or is mandatory if no indom) */ static int find_metric(pmID pmid) { __pmHashNode *hp; optreq_t *rqp; int result = 0; int found = 0; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; if (found++ == 0) if (rqp->r_desc->indom != PM_INDOM_NULL) { result |= MF_HAS_INDOM; if (rqp->r_numinst == 0) result |= MF_HAS_ALL; else result |= MF_HAS_INST; } if (PMLC_GET_MAND(((task_t *)(rqp->r_fetch->f_aux))->t_state)) result |= MF_HAS_MAND; } return found ? result : -1; }
static int addindom(__pmLogCtl *lcp, pmInDom indom, const __pmTimeval *tp, int numinst, int *instlist, char **namelist, int *indom_buf, int allinbuf) { __pmLogInDom *idp; __pmHashNode *hp; int sts; if ((idp = (__pmLogInDom *)malloc(sizeof(__pmLogInDom))) == NULL) return -errno; idp->stamp = *tp; /* struct assignment */ idp->numinst = numinst; idp->instlist = instlist; idp->namelist = namelist; idp->buf = indom_buf; idp->allinbuf = allinbuf; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) fprintf(stderr, "addindom( ..., %s, %s, numinst=%d)\n", pmInDomStr(indom), StrTimeval((__pmTimeval *)tp), numinst); #endif if ((hp = __pmHashSearch((unsigned int)indom, &lcp->l_hashindom)) == NULL) { idp->next = NULL; sts = __pmHashAdd((unsigned int)indom, (void *)idp, &lcp->l_hashindom); } else { idp->next = (__pmLogInDom *)hp->data; hp->data = (void *)idp; sts = 0; } return sts; }
int CheckAccountAccess(ClientInfo *cp) { __pmHashNode *node; const char *userid; const char *groupid; userid = ((node = __pmHashSearch(PCP_ATTR_USERID, &cp->attrs)) ? (const char *)node->data : NULL); groupid = ((node = __pmHashSearch(PCP_ATTR_GROUPID, &cp->attrs)) ? (const char *)node->data : NULL); if (!userid || !groupid) if (__pmServerHasFeature(PM_SERVER_FEATURE_CREDS_REQD)) return PM_ERR_PERMISSION; return __pmAccAddAccount(userid, groupid, &cp->denyOps); }
/* Return a mask containing the history flags for a given metric/instance. * the history flags indicate whether the metric/instance is in the log at all * and whether the last fetch of the metric/instance was successful. * * The result is suitable for ORing into the result returned by a control log * request. */ static int gethistflags(pmID pmid, int inst) { __pmHashNode *hp; pmidhist_t *php; insthist_t *ihp; int i, found; int val; for (hp = __pmHashSearch(pmid, &hist_hash); hp != NULL; hp = hp->next) if ((pmID)hp->key == pmid) break; if (hp == NULL) return 0; php = (pmidhist_t *)hp->data; ihp = &php->ph_instlist[0]; val = 0; if (php->ph_indom != PM_INDOM_NULL) { for (i = 0; i < php->ph_numinst; i++, ihp++) if (ihp->ih_inst == inst) break; found = i < php->ph_numinst; } else found = php->ph_numinst > 0; if (found) { PMLC_SET_INLOG(val, 1); val |= ihp->ih_flags; /* only "available flag" is ever set */ } return val; }
int __pmSecureServerHandshake(int fd, int flags, __pmHashCtl *attrs) { int sts, ssf = DEFAULT_SECURITY_STRENGTH; /* protect from unsupported requests from future/oddball clients */ if (flags & ~(PDU_FLAG_SECURE | PDU_FLAG_SECURE_ACK | PDU_FLAG_COMPRESS | PDU_FLAG_AUTH | PDU_FLAG_CREDS_REQD | PDU_FLAG_CONTAINER | PDU_FLAG_CERT_REQD)) return PM_ERR_IPC; if (flags & PDU_FLAG_CREDS_REQD) { if (__pmHashSearch(PCP_ATTR_USERID, attrs) != NULL) return 0; /* unix domain socket */ else flags |= PDU_FLAG_AUTH; /* force authentication */ } if ((sts = __pmSecureServerIPCFlags(fd, flags)) < 0) return sts; if (((flags & PDU_FLAG_SECURE) != 0) && ((sts = __pmSecureServerNegotiation(fd, &ssf)) < 0)) return sts; if (((flags & PDU_FLAG_AUTH) != 0) && ((sts = __pmAuthServerNegotiation(fd, ssf, attrs)) < 0)) return sts; return 0; }
static void myvaluesetdump(pmValueSet *xvsp, int idx, int *flagsp) { int sts, flags = *flagsp; DescHash *hp; __pmHashNode *hnp; static __pmHashCtl hash = { 0, 0, NULL }; if ((hnp = __pmHashSearch((unsigned int)xvsp->pmid, &hash)) == NULL) { /* first time for this pmid */ hp = (DescHash *)malloc(sizeof(DescHash)); if (hp == NULL) { __pmNoMem("DescHash", sizeof(DescHash), PM_FATAL_ERR); /*NOTREACHED*/ } if ((sts = pmNameID(xvsp->pmid, &hp->name)) < 0) { printf(" %s: pmNameID: %s\n", pmIDStr(xvsp->pmid), pmErrStr(sts)); free(hp); return; } else { if (xvsp->pmid != pmid_flags && xvsp->pmid != pmid_missed && (sts = pmLookupDesc(xvsp->pmid, &hp->desc)) < 0) { printf(" %s: pmLookupDesc: %s\n", hp->name, pmErrStr(sts)); free(hp->name); free(hp); return; } if ((sts = __pmHashAdd((unsigned int)xvsp->pmid, (void *)hp, &hash)) < 0) { printf(" %s: __pmHashAdd: %s\n", hp->name, pmErrStr(sts)); free(hp->name); free(hp); return; } } } else hp = (DescHash *)hnp->data; if (idx == 0) { if (xvsp->pmid == pmid_flags) { flags = *flagsp = xvsp->vlist[0].value.lval; printf(" flags 0x%x", flags); printf(" (%s) ---\n", pmEventFlagsStr(flags)); return; } else printf(" ---\n"); } if ((flags & PM_EVENT_FLAG_MISSED) && (idx == 1) && (xvsp->pmid == pmid_missed)) { printf(" ==> %d missed event records\n", xvsp->vlist[0].value.lval); return; } mydump(hp->name, &hp->desc, xvsp); }
static pmdaMetric * __pmdaHashedSearch(pmID pmid, __pmHashCtl *hash) { __pmHashNode *node; if ((node = __pmHashSearch(pmid, hash)) == NULL) return NULL; return (pmdaMetric *)node->data; }
/* Delete every instance of a given metric from the data structure. * The pmid is deleted from the pmidlist of every task containing an instance. * Return a pointer to the first pmDesc found (the only thing salvaged from the * smoking ruins), or nil if no instances were found. */ static pmDesc * del_insts(pmID pmid) { optreq_t *rqp; __pmHashNode *hp; task_t *tp; pmDesc *dp = NULL; int i, sts, keep; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; ) { /* Do that BEFORE we nuke the node */ __pmHashNode * nextnode = hp->next; if (pmid == (pmID)hp->key) { rqp = (optreq_t *)hp->data; tp = (task_t *)rqp->r_fetch->f_aux; if ((sts = __pmOptFetchDel(&tp->t_fetch, rqp)) < 0) die("del_insts: __pmOptFetchDel", sts); if ((sts = __pmHashDel(pmid, (void *)rqp, &pm_hash)) < 0) die("del_insts: __pmHashDel", sts); /* save the first pmDesc pointer for return and subsequent * re-use, but free all the others */ if (dp != NULL) free(rqp->r_desc); else dp = rqp->r_desc; if (rqp->r_numinst) free(rqp->r_instlist); free(rqp); /* remove pmid from the task's pmid list */ for (i = 0; i < tp->t_numpmid; i++) if (tp->t_pmidlist[i] == pmid) break; keep = (tp->t_numpmid - 1 - i) * sizeof(tp->t_pmidlist[0]); if (keep) { memmove(&tp->t_pmidlist[i], &tp->t_pmidlist[i+1], keep); memmove(&tp->t_desclist[i], &tp->t_desclist[i+1], keep); memmove(&tp->t_namelist[i], &tp->t_namelist[i+1], keep); } /* don't bother shrinking the pmidlist */ tp->t_numpmid--; if (tp->t_numpmid == 0) { /* TODO: nuke the task if that was the last pmID */ } } hp = nextnode; } return dp; }
/* Print event performance metric values */ void printevents(Context *x, pmValueSet *vset, int cols) { int i, sts, highres = (x->desc.type != PM_TYPE_EVENT); unsigned inst; for (i = 0; i < vset->numval; i++) { inst = (unsigned int)vset->vlist[i].inst; if (inst == PM_IN_NULL) printf("%s:", x->metric); else { int k; char *iname = NULL; if (x->inum > 0) { for (k = 0; k < x->inum; k++) { if (x->iids[k] == inst) { iname = x->inames[k]; break; } } } else { /* all instances selected */ __pmHashNode *hnp; hnp = __pmHashSearch(inst, &x->ihash); if (hnp == NULL) { if (archive) sts = pmNameInDomArchive(x->desc.indom, inst, &iname); else sts = pmNameInDom(x->desc.indom, inst, &iname); if (sts < 0) { fprintf(stderr, "%s: pmNameInDom: %s[%u]: %s\n", pmProgname, x->metric, inst, pmErrStr(sts)); exit(EXIT_FAILURE); } if ((sts = __pmHashAdd(inst, (void *)iname, &x->ihash)) < 0) { fprintf(stderr, "%s: __pmHashAdd: %s[%s (%u)]: %s\n", pmProgname, x->metric, iname, inst, pmErrStr(sts)); exit(EXIT_FAILURE); } } else iname = (char *)hnp->data; } if (iname == NULL) continue; printf("%s[%s]:", x->metric, iname); } myeventdump(vset, i, highres); } }
int CheckAccountAccess(ClientInfo *cp) { __pmHashNode *node; const char *userid; const char *groupid; userid = ((node = __pmHashSearch(PCP_ATTR_USERID, &cp->attrs)) ? (const char *)node->data : NULL); groupid = ((node = __pmHashSearch(PCP_ATTR_GROUPID, &cp->attrs)) ? (const char *)node->data : NULL); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "CheckAccountAccess: client fd=%d userid=%s groupid=%s\n", cp->fd, userid, groupid); #endif if (!userid || !groupid) if (__pmServerHasFeature(PM_SERVER_FEATURE_CREDS_REQD)) return PM_ERR_PERMISSION; return __pmAccAddAccount(userid, groupid, &cp->denyOps); }
/* This crawls over the data structure looking for weirdness */ void reality_check(void) { __pmHashNode *hp; task_t *tp; task_t *tp2; fetchctl_t *fp; optreq_t *rqp; pmID pmid; int i = 0, j, k; /* check that all fetch_t's f_aux point back to their parent task */ for (tp = tasklist; tp != NULL; tp = tp->t_next, i++) { if (tp->t_fetch == NULL) fprintf(stderr, "task[%d] @" PRINTF_P_PFX "%p has no fetch group\n", i, tp); j = 0; for (fp = tp->t_fetch; fp != NULL; fp = fp->f_next) { if (fp->f_aux != (void *)tp) fprintf(stderr, "task[%d] fetch group[%d] has invalid task pointer\n", i, j); j++; } /* check that all optreq_t's in hash list have valid r_fetch->f_aux * pointing to a task in the task list. */ for (j = 0; j < tp->t_numpmid; j++) { pmid = tp->t_pmidlist[j]; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; for (tp2 = tasklist; tp2 != NULL; tp2 = tp2->t_next) if (rqp->r_fetch->f_aux == (void *)tp2) break; if (tp2 == NULL) { fprintf(stderr, "task[%d] pmid %s optreq " PRINTF_P_PFX "%p for [", i, pmIDStr(pmid), rqp); if (rqp->r_numinst == 0) fputs("`all instances' ", stderr); else for (k = 0; k < rqp->r_numinst; k++) fprintf(stderr, "%d ", rqp->r_instlist[k]); fputs("] bad task pointer\n", stderr); } } } } }
int __pmSecureServerHandshake(int fd, int flags, __pmHashCtl *attrs) { (void)fd; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmSecureServerHandshake: flags=%d: ", __FILE__, flags); #endif /* for things that require a secure server, return -EOPNOTSUPP */ if ((flags & (PDU_FLAG_SECURE | PDU_FLAG_SECURE_ACK | PDU_FLAG_COMPRESS | PDU_FLAG_AUTH)) != 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "not allowed\n"); #endif return -EOPNOTSUPP; } /* * CREDS_REQD is a special case that does not need a secure server * provided we've connected on a unix domain socket */ if ((flags & PDU_FLAG_CREDS_REQD) != 0 && __pmHashSearch(PCP_ATTR_USERID, attrs) != NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "ok\n"); #endif return 0; } /* remove all of the known good flags */ flags &= ~(PDU_FLAG_SECURE | PDU_FLAG_SECURE_ACK | PDU_FLAG_COMPRESS | PDU_FLAG_AUTH | PDU_FLAG_CREDS_REQD | PDU_FLAG_CONTAINER); if (!flags) return 0; /* any remaining flags are unexpected */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "bad\n"); #endif return PM_ERR_IPC; }
optreq_t * findoptreq(pmID pmid, int inst) { __pmHashNode *hp; optreq_t *rqp; optreq_t *all_rqp = NULL; int j; /* * Note: * The logic here assumes that for each metric-inst pair, there is * at most one optreq_t structure, corresponding to the logging * state of ON (mandatory or advisory) else OFF (mandatory). Other * requests change the data structures, but do not leave optreq_t * structures lying about, i.e. MAYBE (mandatory) is the default, * and does not have to be explicitly stored, while OFF (advisory) * reverts to MAYBE (mandatory). * There is one exception to the above assumption, namely for * cases where the initial specification includes "all" instances, * then some later concurrent specification may refer to specific * instances ... in this case, the specific optreq_t structure is * the one that applies. */ for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; if (rqp->r_numinst == 0) { all_rqp = rqp; continue; } for (j = 0; j < rqp->r_numinst; j++) if (inst == rqp->r_instlist[j]) return rqp; } if (all_rqp != NULL) return all_rqp; else return NULL; }
/* Given a task and a pmID, find an optreq_t associated with the task suitable * for inserting a new instance into. * The one with the smallest number of instances is chosen. We could also * have just used the first, but smallest-first gives a more even distribution. */ static optreq_t * find_instoptreq(task_t *tp, pmID pmid) { optreq_t *result = NULL; optreq_t *rqp; int ni = 0; __pmHashNode *hp; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; if ((task_t *)rqp->r_fetch->f_aux != tp) continue; if (rqp->r_numinst == 0) continue; /* don't want "all instances" cases */ if (ni == 0 || rqp->r_numinst < ni) { result = rqp; ni = rqp->r_numinst; } } return result; }
static void docheck(pmResult *result) { int i, j, k; int sts; pmDesc desc; pmAtomValue av; pmValue *vp; pmValueSet *vsp; __pmHashNode *hptr = NULL; checkData *checkdata = NULL; double diff; struct timeval timediff; for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { if (vsp->numval == 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": no values returned\n"); continue; } else if (vsp->numval < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": error from numval: %s\n", pmErrStr(vsp->numval)); continue; } } #endif if (vsp->numval <= 0) continue; /* check if pmid already in hash list */ if ((hptr = __pmHashSearch(vsp->pmid, &hashlist)) == NULL) { if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": pmLookupDesc failed: %s\n", pmErrStr(sts)); continue; } if (desc.type != PM_TYPE_32 && desc.type != PM_TYPE_U32 && desc.type != PM_TYPE_64 && desc.type != PM_TYPE_U64 && desc.type != PM_TYPE_FLOAT && desc.type != PM_TYPE_DOUBLE) { continue; /* no checks for non-numeric metrics */ } /* create a new one & add to list */ checkdata = (checkData*) malloc(sizeof(checkData)); newHashItem(vsp, &desc, checkdata, &result->timestamp); if (__pmHashAdd(checkdata->desc.pmid, (void*)checkdata, &hashlist) < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": __pmHashAdd failed (internal pmlogcheck error)\n"); /* free memory allocated above on insert failure */ for (j = 0; j < vsp->numval; j++) { if (checkdata->instlist[j] != NULL) free(checkdata->instlist[j]); } if (checkdata->instlist != NULL) free(checkdata->instlist); continue; } } else { /* pmid exists - update statistics */ checkdata = (checkData *)hptr->data; for (j = 0; j < vsp->numval; j++) { /* iterate thro result values */ vp = &vsp->vlist[j]; k = j; /* index into stored inst list, result may differ */ if ((vsp->numval > 1) || (checkdata->desc.indom != PM_INDOM_NULL)) { /* must store values using correct inst - probably in correct order already */ if ((k < checkdata->listsize) && (checkdata->instlist[k]->inst != vp->inst)) { for (k = 0; k < checkdata->listsize; k++) { if (vp->inst == checkdata->instlist[k]->inst) { break; /* k now correct */ } } if (k == checkdata->listsize) { /* no matching inst was found */ newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } } else if (k >= checkdata->listsize) { k = checkdata->listsize; newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } } if (k >= checkdata->listsize) { /* only error values observed so far */ k = checkdata->listsize; newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } timediff = result->timestamp; tsub(&timediff, &(checkdata->instlist[k]->lasttime)); if (timediff.tv_sec < 0) { /* clip negative values at zero */ timediff.tv_sec = 0; timediff.tv_usec = 0; } diff = __pmtimevalToReal(&timediff); if ((sts = pmExtractValue(vsp->valfmt, vp, checkdata->desc.type, &av, PM_TYPE_DOUBLE)) < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": pmExtractValue failed: %s\n", pmErrStr(sts)); continue; } if (checkdata->desc.sem == PM_SEM_COUNTER) { if (diff == 0.0) continue; diff *= checkdata->scale; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, checkdata->desc.pmid); fprintf(stderr, ": current counter value is %.0f\n", av.d); } #endif unwrap(av.d, &(result->timestamp), checkdata, k); } checkdata->instlist[k]->lastval = av.d; checkdata->instlist[k]->lasttime = result->timestamp; } } } }
/* create a pmValueSet large enough to contain the union of the current * instance domain of the specified metric and any previous instances from * the history list. */ static pmValueSet * build_vset(pmID pmid, int usehist) { __pmHashNode *hp; pmidhist_t *php = NULL; insthist_t *ihp; int need = 0; int i, numindom = 0; pmDesc desc; int have_desc; int *instlist = NULL; char **namelist = NULL; pmValueSet *vsp; if (usehist) { /* find the number of instances of the metric in the history (1 if * single-valued metric) */ for (hp = __pmHashSearch(pmid, &hist_hash); hp != NULL; hp = hp->next) if ((pmID)hp->key == pmid) break; if (hp != NULL) { php = (pmidhist_t *)hp->data; need = php->ph_numinst; } } /* * get the current instance domain, so that if the metric hasn't been * logged yet a sensible result is returned. */ if ((have_desc = pmLookupDesc(pmid, &desc)) < 0) goto no_info; if (desc.indom == PM_INDOM_NULL) need = 1; /* will be same in history */ else { int j; if ((numindom = pmGetInDom(desc.indom, &instlist, &namelist)) < 0) { have_desc = numindom; goto no_info; } /* php will be null if usehist is false or there is no history yet */ if (php == NULL) need = numindom; /* no history => use indom */ else for (i = 0; i < numindom; i++) { int inst = instlist[i]; for (j = 0; j < php->ph_numinst; j++) if (inst == php->ph_instlist[j].ih_inst) break; /* * if instance is in history but not instance domain, leave * extra space for it in vset, otherwise use the USEINDOM * flag to avoid another NxM comparison when building the vset * instances later. */ if (j >= php->ph_numinst) need++; else PMLC_SET_USEINDOM(php->ph_instlist[j].ih_flags, 1); } } no_info: need = sizeof(pmValueSet) + (need - 1) * sizeof(pmValue); vsp = (pmValueSet *)malloc(need); if (vsp == NULL) { __pmNoMem("build_vset for control/enquire", need, PM_FATAL_ERR); } vsp->pmid = pmid; if (have_desc < 0) { vsp->numval = have_desc; } else if (desc.indom == PM_INDOM_NULL) { vsp->vlist[0].inst = PM_IN_NULL; vsp->numval = 1; } else { int j; i = 0; /* get instances out of instance domain first */ if (numindom > 0) for (j = 0; j < numindom; j++) vsp->vlist[i++].inst = instlist[j]; /* then any not in instance domain from history */ if (php != NULL) { ihp = &php->ph_instlist[0]; for (j = 0; j < php->ph_numinst; j++, ihp++) if (PMLC_GET_USEINDOM(ihp->ih_flags)) /* it's already in the indom */ PMLC_SET_USEINDOM(ihp->ih_flags, 0); else vsp->vlist[i++].inst = ihp->ih_inst; } vsp->numval = i; } if (instlist) free(instlist); if (namelist) free(namelist); return vsp; }
/* Update an existing metric (given a pmValueSet) adding it to the specified * task. Allocate and return a new task_t if the specified task pointer is nil. */ static int update_metric(pmValueSet *vsp, int reqstate, int mflags, task_t **result) { pmID pmid = vsp->pmid; task_t *ntp = *result; /* pointer to new task */ task_t *ctp; /* pointer to current task */ optreq_t *rqp; pmDesc *dp; int i, j, inst; int sts, need = 0; int addpmid = 0; int freedp; /* allocate a new task if null task pointer passed in */ if (ntp == NULL) { ntp = calloc(1, sizeof(task_t)); if (ntp == NULL) { __pmNoMem("update_metric: new task calloc", sizeof(task_t), PM_FATAL_ERR); } *result = ntp; } if ((mflags & MF_HAS_INDOM) == 0) { rqp = findoptreq(pmid, 0); ctp = (task_t *)(rqp->r_fetch->f_aux); if (!update_ok(ctp->t_state, reqstate)) return 1; /* if the new state is advisory off, just remove the metric */ if ((PMLC_GET_MAYBE(reqstate)) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) del_optreq(rqp); else { /* update the optreq. For single valued metrics there are no * instances involved so the sole optreq can just be re-used. */ if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0) die("update_metric: 1 metric __pmOptFetchDel", sts); __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); addpmid = 1; } } else { /* metric has an instance domain */ if (vsp->numval > 0) { /* tricky: since optFetch can't handle instance profiles of the * form "all except these specific instances", and managing it * manually is just too hard, reject requests for specific * metric instances if "all instances" of the metric are already * being logged. * Note: advisory off "all instances" is excepted since ANY request * overrides and advisory off. E.g. "advisory off all" followed by * "advisory on someinsts" turns on advisory logging for * "someinsts". mflags will be zero for "advisory off" metrics. */ if (mflags & MF_HAS_ALL) return 1; /* can't turn "all" into specific insts */ for (i = 0; i < vsp->numval; i++) { dp = NULL; freedp = 0; inst = vsp->vlist[i].inst; rqp = findoptreq(pmid, inst); if (rqp != NULL) { dp = rqp->r_desc; ctp = (task_t *)(rqp->r_fetch->f_aux); /* no work required if new task and current are the same */ if (ntp == ctp) continue; if (!update_ok(ctp->t_state, reqstate)) continue; /* remove inst's group from current task */ if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0) die("update_metric: instance add __pmOptFetchDel", sts); /* put group back if there are any instances left */ if (rqp->r_numinst > 1) { /* remove inst from group */ for (j = 0; j < rqp->r_numinst; j++) if (inst == rqp->r_instlist[j]) break; /* don't call memmove to move zero bytes */ if (j < rqp->r_numinst - 1) memmove(&rqp->r_instlist[j], &rqp->r_instlist[j+1], (rqp->r_numinst - 1 - j) * sizeof(rqp->r_instlist[0])); rqp->r_numinst--; /* (don't bother realloc-ing the instlist to a smaller size) */ __pmOptFetchAdd(&ctp->t_fetch, rqp); linkback(ctp); /* no need to update hash list, rqp already there */ } /* if that was the last instance, free the group */ else { if (( sts = __pmHashDel(pmid, (void *)rqp, &pm_hash)) < 0) die("update_metric: instance __pmHashDel", sts); freedp = 1; free(rqp->r_instlist); free(rqp); } } /* advisory off (mandatory maybe) metrics don't get put into * the data structure */ if (PMLC_GET_MAYBE(reqstate) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) { if (freedp) free(dp); continue; } addpmid = 1; /* try to find an existing optreq_t for the instance */ rqp = find_instoptreq(ntp, pmid); if (rqp != NULL) { if ((sts = __pmOptFetchDel(&ntp->t_fetch, rqp)) < 0) die("update_metric: instance add __pmOptFetchDel", sts); } /* no existing optreq_t found, allocate & populate a new one */ else { rqp = (optreq_t *)calloc(1, sizeof(optreq_t)); if (rqp == NULL) { __pmNoMem("update_metric: optreq calloc", sizeof(optreq_t), PM_FATAL_ERR); } /* if the metric existed but the instance didn't, we don't * have a valid pmDesc (dp), so find one. */ if (dp == NULL) { /* find metric and associated pmDesc */ __pmHashNode *hp; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid == (pmID)hp->key) break; } assert(hp != NULL); dp = ((optreq_t *)hp->data)->r_desc; } /* recycle pmDesc from the old group, if possible */ if (freedp) { rqp->r_desc = dp; freedp = 0; } /* otherwise allocate & copy a new pmDesc via dp */ else { need = sizeof(pmDesc); rqp->r_desc = (pmDesc *)malloc(need); if (rqp->r_desc == NULL) { __pmNoMem("update_metric: new inst pmDesc malloc", need, PM_FATAL_ERR); } memcpy(rqp->r_desc, dp, need); } if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0) die("update_metric: __pmHashAdd", sts); } need = (rqp->r_numinst + 1) * sizeof(rqp->r_instlist[0]); rqp->r_instlist = (int *)realloc(rqp->r_instlist, need); if (rqp->r_instlist == NULL) { __pmNoMem("update_metric: inst list resize", need, PM_FATAL_ERR); } rqp->r_instlist[rqp->r_numinst++] = inst; __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); if (freedp) free(dp); } } /* the vset has numval == 0, a request for "all instances" */ else { /* if the metric is a singular instance that has mandatory logging * or has at least one instance with mandatory logging on, a * request for advisory logging cannot be honoured */ if ((mflags & MF_HAS_MAND) && PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_MAYBE(reqstate) == 0) return 1; if (mflags & MF_HAS_ALL) { /* if there is an "all instances" for the metric, it will be * the only optreq_t for the metric */ rqp = findoptreq(pmid, 0); ctp = (task_t *)rqp->r_fetch->f_aux; /* if the metric is "advisory on, all instances" and the * request is for "mandatory maybe, all instances" the current * advisory logging state of the metric is retained */ if (PMLC_GET_MAND(ctp->t_state) == 0 && PMLC_GET_MAYBE(reqstate)) return 0; /* advisory off & mandatory maybe metrics don't get put into * the data structure */ if (PMLC_GET_MAYBE(reqstate) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) { del_optreq(rqp); return 0; } addpmid = 1; if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0) die("update_metric: all inst __pmOptFetchDel", sts); /* don't delete from hash list, rqp re-used */ __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); } else { /* there are one or more specific instances for the metric. * The metric cannot have an "all instances" at the same time. * * if the request is for "mandatory maybe, all instances" and * the only instances of the metric all have advisory logging * on, retain the current advisory semantics. */ if (PMLC_GET_MAYBE(reqstate) && (mflags & MF_HAS_INST) && !(mflags & MF_HAS_MAND)) return 0; dp = del_insts(pmid); /* advisory off (mandatory maybe) metrics don't get put into * the data structure */ if (PMLC_GET_MAYBE(reqstate) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) { free(dp); return 0; } addpmid = 1; rqp = (optreq_t *)calloc(1, sizeof(optreq_t)); if (rqp == NULL) { __pmNoMem("update_metric: all inst calloc", sizeof(optreq_t), PM_FATAL_ERR); } rqp->r_desc = dp; __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0) die("update_metric: all inst __pmHashAdd", sts); } } } if (!addpmid) return 0; /* add pmid to new task if not already there */ for (i = 0; i < ntp->t_numpmid; i++) if (pmid == ntp->t_pmidlist[i]) break; if (i >= ntp->t_numpmid) { pmDesc desc; char *name; int need; if ((sts = pmLookupDesc(pmid, &desc)) < 0) die("update_metric: cannot lookup desc", sts); if ((sts = pmNameID(pmid, &name)) < 0) die("update_metric: cannot lookup name", sts); need = (ntp->t_numpmid + 1) * sizeof(pmID); if (!(ntp->t_pmidlist = (pmID *)realloc(ntp->t_pmidlist, need))) __pmNoMem("update_metric: grow task pmidlist", need, PM_FATAL_ERR); need = (ntp->t_numpmid + 1) * sizeof(char *); if (!(ntp->t_namelist = (char **)realloc(ntp->t_namelist, need))) __pmNoMem("update_metric: grow task namelist", need, PM_FATAL_ERR); need = (ntp->t_numpmid + 1) * sizeof(pmDesc); if (!(ntp->t_desclist = (pmDesc *)realloc(ntp->t_desclist, need))) __pmNoMem("update_metric: grow task desclist", need, PM_FATAL_ERR); i = ntp->t_numpmid; ntp->t_pmidlist[i] = pmid; ntp->t_namelist[i] = name; ntp->t_desclist[i] = desc; ntp->t_numpmid++; } return 0; }