int __pmAFregister(const struct timeval *delta, void *data, void (*func)(int, void *)) { qelt *qp; struct timeval now; struct timeval interval; if (PM_MULTIPLE_THREADS(PM_SCOPE_AF)) return PM_ERR_THREAD; if (!block) AFhold(); if (afid == 0x8000 && !block) /* first time */ AFrearm(); if ((qp = (qelt *)malloc(sizeof(qelt))) == NULL) { return -oserror(); } qp->q_afid = ++afid; qp->q_data = data; qp->q_delta = *delta; qp->q_func = func; __pmtimevalNow(&qp->q_when); tadd(&qp->q_when, &qp->q_delta); enqueue(qp); if (root == qp) { /* we ended up at the head of the list, set itimer */ interval = qp->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } if (!block) AFrelse(); return qp->q_afid; }
static void enqueue(qelt *qp) { qelt *tqp; qelt *priorp; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { struct timeval now; __pmtimevalNow(&now); __pmPrintStamp(stderr, &now); fprintf(stderr, " AFenqueue " PRINTF_P_PFX "%p(%d, " PRINTF_P_PFX "%p) for ", qp->q_func, qp->q_afid, qp->q_data); __pmPrintStamp(stderr, &qp->q_when); fputc('\n', stderr); } #endif for (tqp = root, priorp = NULL; tqp != NULL && tcmp(&qp->q_when, &tqp->q_when) >= 0; tqp = tqp->q_next) priorp = tqp; if (priorp == NULL) { qp->q_next = root; root = qp; } else { qp->q_next = priorp->q_next; priorp->q_next = qp; } }
/* return real time */ RealTime getReal(void) { struct timeval t; __pmtimevalNow(&t); return __pmtimevalToReal(&t); }
/* Establish a new socket connection to a client */ ClientInfo * AcceptNewClient(int reqfd) { static unsigned int seq = 0; int i, fd; __pmSockLen addrlen; struct timeval now; i = NewClient(); addrlen = __pmSockAddrSize(); fd = __pmAccept(reqfd, client[i].addr, &addrlen); if (fd == -1) { if (neterror() == EPERM) { __pmNotifyErr(LOG_NOTICE, "AcceptNewClient(%d): " "Permission Denied\n", reqfd); client[i].fd = -1; DeleteClient(&client[i]); return NULL; } else { __pmNotifyErr(LOG_ERR, "AcceptNewClient(%d) __pmAccept: %s\n", reqfd, netstrerror()); Shutdown(); exit(1); } } if (fd > maxClientFd) maxClientFd = fd; pmcd_openfds_sethi(fd); __pmFD_SET(fd, &clientFds); __pmSetVersionIPC(fd, UNKNOWN_VERSION); /* before negotiation */ __pmSetSocketIPC(fd); client[i].fd = fd; client[i].status.connected = 1; client[i].status.changes = 0; memset(&client[i].attrs, 0, sizeof(__pmHashCtl)); /* * Note seq needs to be unique, but we're using a free running counter * and not bothering to check here ... unless we churn through * 4,294,967,296 (2^32) clients while one client remains connected * we won't have a problem */ client[i].seq = seq++; __pmtimevalNow(&now); client[i].start = now.tv_sec; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "AcceptNewClient(%d): client[%d] (fd %d)\n", reqfd, i, fd); #endif pmcd_trace(TR_ADD_CLIENT, i, 0, 0); return &client[i]; }
int __pmAFunregister(int afid) { qelt *qp; qelt *priorp; struct timeval now; struct timeval interval; if (PM_MULTIPLE_THREADS(PM_SCOPE_AF)) return PM_ERR_THREAD; if (!block) AFhold(); for (qp = root, priorp = NULL; qp != NULL && qp->q_afid != afid; qp = qp->q_next) priorp = qp; if (qp == NULL) { if (!block) AFrelse(); return -1; } if (priorp == NULL) { root = qp->q_next; if (root != NULL) { /* * we removed the head of the queue, set itimer for the * new head of queue */ interval = root->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } } else priorp->q_next = qp->q_next; free(qp); if (!block) AFrelse(); return 0; }
static void sleeptill(struct timeval sched) { int sts; struct timeval curr; /* current time */ struct timespec delay; /* interval to sleep */ struct timespec left; /* remaining sleep time */ __pmtimevalNow(&curr); tospec(tsub(sched, curr), &delay); for (;;) { /* loop to catch early wakeup by nanosleep */ sts = nanosleep(&delay, &left); if (sts == 0 || (sts < 0 && errno != EINTR)) break; delay = left; } }
/* sleep until given timeval */ void __pmtimevalPause(struct timeval sched) { int sts; struct timeval curr; /* current time */ struct timespec delay; /* interval to sleep */ struct timespec left; /* remaining sleep time */ __pmtimevalNow(&curr); __pmtimevalDec(&sched, &curr); tospec(&sched, &delay); for (;;) { /* loop to catch early wakeup by nanosleep */ sts = nanosleep(&delay, &left); if (sts == 0 || (sts < 0 && oserror() != EINTR)) break; delay = left; } }
int pmiWrite(int sec, int usec) { int sts; if (current == NULL) return PM_ERR_NOCONTEXT; if (current->result == NULL) return current->last_sts = PMI_ERR_NODATA; if (sec < 0) { __pmtimevalNow(¤t->result->timestamp); } else { current->result->timestamp.tv_sec = sec; current->result->timestamp.tv_usec = usec; } if (current->result->timestamp.tv_sec < current->last_stamp.tv_sec || (current->result->timestamp.tv_sec == current->last_stamp.tv_sec && current->result->timestamp.tv_usec < current->last_stamp.tv_usec)) { fprintf(stderr, "Fatal Error: timestamp "); printstamp(stderr, ¤t->result->timestamp); fprintf(stderr, " not greater than previous valid timestamp "); printstamp(stderr, ¤t->last_stamp); fputc('\n', stderr); sts = PMI_ERR_BADTIMESTAMP; } else { sts = _pmi_put_result(current, current->result); current->last_stamp = current->result->timestamp; } pmFreeResult(current->result); current->result = NULL; return current->last_sts = 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; }
int main(int argc, char **argv) { int c; int sts; int sep = __pmPathSeparator(); int use_localtime = 0; int isdaemon = 0; char *pmnsfile = PM_NS_DEFAULT; char *username; char *logfile = "pmlogger.log"; /* default log (not archive) file name */ char *endnum; int i; task_t *tp; optcost_t ocp; __pmFdSet readyfds; char *p; char *runtime = NULL; int ctx; /* handle corresponding to ctxp below */ __pmContext *ctxp; /* pmlogger has just this one context */ int niter; pid_t target_pid = 0; __pmGetUsername(&username); /* * Warning: * If any of the pmlogger options change, make sure the * corresponding changes are made to pmnewlog when pmlogger * options are passed through from the control file */ while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) { switch (c) { case 'c': /* config file */ if (access(opts.optarg, F_OK) == 0) configfile = opts.optarg; else { /* does not exist as given, try the standard place */ char *sysconf = pmGetConfig("PCP_VAR_DIR"); int sz = strlen(sysconf)+strlen("/config/pmlogger/")+strlen(opts.optarg)+1; if ((configfile = (char *)malloc(sz)) == NULL) __pmNoMem("config file name", sz, PM_FATAL_ERR); snprintf(configfile, sz, "%s%c" "config%c" "pmlogger%c" "%s", sysconf, sep, sep, sep, opts.optarg); if (access(configfile, F_OK) != 0) { /* still no good, error handling happens below */ free(configfile); configfile = opts.optarg; } } break; case 'D': /* debug flag */ sts = __pmParseDebug(opts.optarg); if (sts < 0) { pmprintf("%s: unrecognized debug flag specification (%s)\n", pmProgname, opts.optarg); opts.errors++; } else pmDebug |= sts; break; case 'h': /* hostname for PMCD to contact */ pmcd_host_conn = opts.optarg; break; case 'l': /* log file name */ logfile = opts.optarg; break; case 'L': /* linger if not primary logger */ linger = 1; break; case 'm': /* note for port map file */ note = opts.optarg; isdaemon = ((strcmp(note, "pmlogger_check") == 0) || (strcmp(note, "pmlogger_daily") == 0)); break; case 'n': /* alternative name space file */ pmnsfile = opts.optarg; break; case 'p': target_pid = (int)strtol(opts.optarg, &endnum, 10); if (*endnum != '\0') { pmprintf("%s: invalid process identifier (%s)\n", pmProgname, opts.optarg); opts.errors++; } else if (!__pmProcessExists(target_pid)) { pmprintf("%s: PID error - no such process (%d)\n", pmProgname, target_pid); opts.errors++; } break; case 'P': /* this is the primary pmlogger */ primary = 1; isdaemon = 1; break; case 'r': /* report sizes of pmResult records */ rflag = 1; break; case 's': /* exit size */ sts = ParseSize(opts.optarg, &exit_samples, &exit_bytes, &exit_time); if (sts < 0) { pmprintf("%s: illegal size argument '%s' for exit size\n", pmProgname, opts.optarg); opts.errors++; } else if (exit_time.tv_sec > 0) { __pmAFregister(&exit_time, NULL, run_done_callback); } break; case 'T': /* end time */ runtime = opts.optarg; break; case 't': /* change default logging interval */ if (pmParseInterval(opts.optarg, &delta, &p) < 0) { pmprintf("%s: illegal -t argument\n%s", pmProgname, p); free(p); opts.errors++; } break; case 'U': /* run as named user */ username = opts.optarg; isdaemon = 1; break; case 'u': /* flush output buffers after each fetch */ /* * all archive write I/O is unbuffered now, so maintain -u * for backwards compatibility only */ break; case 'v': /* volume switch after given size */ sts = ParseSize(opts.optarg, &vol_switch_samples, &vol_switch_bytes, &vol_switch_time); if (sts < 0) { pmprintf("%s: illegal size argument '%s' for volume size\n", pmProgname, opts.optarg); opts.errors++; } else if (vol_switch_time.tv_sec > 0) { vol_switch_afid = __pmAFregister(&vol_switch_time, NULL, vol_switch_callback); } break; case 'V': archive_version = (int)strtol(opts.optarg, &endnum, 10); if (*endnum != '\0' || archive_version != PM_LOG_VERS02) { pmprintf("%s: -V requires a version number of %d\n", pmProgname, PM_LOG_VERS02); opts.errors++; } break; case 'x': /* recording session control fd */ rsc_fd = (int)strtol(opts.optarg, &endnum, 10); if (*endnum != '\0' || rsc_fd < 0) { pmprintf("%s: -x requires a non-negative numeric argument\n", pmProgname); opts.errors++; } else { time(&rsc_start); } break; case 'y': use_localtime = 1; break; case '?': default: opts.errors++; break; } } if (primary && pmcd_host != NULL) { pmprintf( "%s: -P and -h are mutually exclusive; use -P only when running\n" "%s on the same (local) host as the PMCD to which it connects.\n", pmProgname, pmProgname); opts.errors++; } if (!opts.errors && opts.optind != argc - 1) { pmprintf("%s: insufficient arguments\n", pmProgname); opts.errors++; } if (opts.errors) { pmUsageMessage(&opts); exit(1); } if (rsc_fd != -1 && note == NULL) { /* add default note to indicate running with -x */ static char xnote[10]; snprintf(xnote, sizeof(xnote), "-x %d", rsc_fd); note = xnote; } /* if we are running as a daemon, change user early */ if (isdaemon) __pmSetProcessIdentity(username); __pmOpenLog("pmlogger", logfile, stderr, &sts); if (sts != 1) { fprintf(stderr, "%s: Warning: log file (%s) creation failed\n", pmProgname, logfile); /* continue on ... writing to stderr */ } /* base name for archive is here ... */ archBase = argv[opts.optind]; if (pmcd_host_conn == NULL) pmcd_host_conn = "local:"; /* initialise access control */ if (__pmAccAddOp(PM_OP_LOG_ADV) < 0 || __pmAccAddOp(PM_OP_LOG_MAND) < 0 || __pmAccAddOp(PM_OP_LOG_ENQ) < 0) { fprintf(stderr, "%s: access control initialisation failed\n", pmProgname); exit(1); } if (pmnsfile != PM_NS_DEFAULT) { if ((sts = pmLoadASCIINameSpace(pmnsfile, 1)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } if ((ctx = pmNewContext(PM_CONTEXT_HOST, pmcd_host_conn)) < 0) { fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, pmcd_host_conn, pmErrStr(ctx)); exit(1); } pmcd_host = (char *)pmGetContextHostName(ctx); if (strlen(pmcd_host) == 0) { fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n", pmProgname, ctx); exit(1); } if (rsc_fd == -1) { /* no -x, so register client id with pmcd */ __pmSetClientIdArgv(argc, argv); } /* * discover fd for comms channel to PMCD ... */ if ((ctxp = __pmHandleToPtr(ctx)) == NULL) { fprintf(stderr, "%s: botch: __pmHandleToPtr(%d) returns NULL!\n", pmProgname, ctx); exit(1); } pmcdfd = ctxp->c_pmcd->pc_fd; PM_UNLOCK(ctxp->c_lock); if (configfile != NULL) { if ((yyin = fopen(configfile, "r")) == NULL) { fprintf(stderr, "%s: Cannot open config file \"%s\": %s\n", pmProgname, configfile, osstrerror()); exit(1); } } else { /* **ANY** Lex would read from stdin automagically */ configfile = "<stdin>"; } __pmOptFetchGetParams(&ocp); ocp.c_scope = 1; __pmOptFetchPutParams(&ocp); /* prevent early timer events ... */ __pmAFblock(); if (yyparse() != 0) exit(1); if (configfile != NULL) fclose(yyin); yyend(); #ifdef PCP_DEBUG fprintf(stderr, "Config parsed\n"); #endif fprintf(stderr, "Starting %slogger for host \"%s\" via \"%s\"\n", primary ? "primary " : "", pmcd_host, pmcd_host_conn); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "optFetch Cost Parameters: pmid=%d indom=%d fetch=%d scope=%d\n", ocp.c_pmid, ocp.c_indom, ocp.c_fetch, ocp.c_scope); fprintf(stderr, "\nAfter loading config ...\n"); for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (tp->t_numvalid == 0) continue; fprintf(stderr, " state: %sin log, %savail, %s, %s", PMLC_GET_INLOG(tp->t_state) ? "" : "not ", PMLC_GET_AVAIL(tp->t_state) ? "" : "un", PMLC_GET_MAND(tp->t_state) ? "mand" : "adv", PMLC_GET_ON(tp->t_state) ? "on" : "off"); fprintf(stderr, " delta: %ld usec", (long)1000 * tp->t_delta.tv_sec + tp->t_delta.tv_usec); fprintf(stderr, " numpmid: %d\n", tp->t_numpmid); for (i = 0; i < tp->t_numpmid; i++) { fprintf(stderr, " %s (%s):\n", pmIDStr(tp->t_pmidlist[i]), tp->t_namelist[i]); } __pmOptFetchDump(stderr, tp->t_fetch); } } #endif if (!primary && tasklist == NULL && !linger) { fprintf(stderr, "Nothing to log, and not the primary logger instance ... good-bye\n"); exit(1); } if ((sts = __pmLogCreate(pmcd_host, archBase, archive_version, &logctl)) < 0) { fprintf(stderr, "__pmLogCreate: %s\n", pmErrStr(sts)); exit(1); } else { /* * try and establish $TZ from the remote PMCD ... * Note the label record has been set up, but not written yet */ char *name = "pmcd.timezone"; pmID pmid; pmResult *resp; __pmtimevalNow(&epoch); sts = pmUseContext(ctx); if (sts >= 0) sts = pmLookupName(1, &name, &pmid); if (sts >= 0) sts = pmFetch(1, &pmid, &resp); if (sts >= 0) { if (resp->vset[0]->numval > 0) { /* pmcd.timezone present */ strcpy(logctl.l_label.ill_tz, resp->vset[0]->vlist[0].value.pval->vbuf); /* prefer to use remote time to avoid clock drift problems */ epoch = resp->timestamp; /* struct assignment */ if (! use_localtime) pmNewZone(logctl.l_label.ill_tz); } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "main: Could not get timezone from host %s\n", pmcd_host); } #endif pmFreeResult(resp); } } /* do ParseTimeWindow stuff for -T */ if (runtime) { struct timeval res_end; /* time window end */ struct timeval start; struct timeval end; struct timeval last_delta; char *err_msg; /* parsing error message */ time_t now; struct timeval now_tv; time(&now); now_tv.tv_sec = now; now_tv.tv_usec = 0; start = now_tv; end.tv_sec = INT_MAX; end.tv_usec = INT_MAX; sts = __pmParseTime(runtime, &start, &end, &res_end, &err_msg); if (sts < 0) { fprintf(stderr, "%s: illegal -T argument\n%s", pmProgname, err_msg); exit(1); } last_delta = res_end; tsub(&last_delta, &now_tv); __pmAFregister(&last_delta, NULL, run_done_callback); last_stamp = res_end; } fprintf(stderr, "Archive basename: %s\n", archBase); #ifndef IS_MINGW /* detach yourself from the launching process */ if (isdaemon) setpgid(getpid(), 0); #endif /* set up control port */ init_ports(); __pmFD_ZERO(&fds); for (i = 0; i < CFD_NUM; ++i) { if (ctlfds[i] >= 0) __pmFD_SET(ctlfds[i], &fds); } #ifndef IS_MINGW __pmFD_SET(pmcdfd, &fds); #endif if (rsc_fd != -1) __pmFD_SET(rsc_fd, &fds); numfds = maxfd() + 1; if ((sts = do_preamble()) < 0) fprintf(stderr, "Warning: problem writing archive preamble: %s\n", pmErrStr(sts)); sts = 0; /* default exit status */ parse_done = 1; /* enable callback processing */ __pmAFunblock(); for ( ; ; ) { int nready; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "before __pmSelectRead(%d,...): run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, run_done_alarm, vol_switch_alarm, log_alarm); } #endif niter = 0; while (log_alarm && niter++ < 10) { __pmAFblock(); log_alarm = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "delayed callback: log_alarm\n"); #endif for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (tp->t_alarm) { tp->t_alarm = 0; do_work(tp); } } __pmAFunblock(); } if (vol_switch_alarm) { __pmAFblock(); vol_switch_alarm = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "delayed callback: vol_switch_alarm\n"); #endif newvolume(VOL_SW_TIME); __pmAFunblock(); } if (run_done_alarm) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "delayed callback: run_done_alarm\n"); #endif run_done(0, NULL); /*NOTREACHED*/ } __pmFD_COPY(&readyfds, &fds); nready = __pmSelectRead(numfds, &readyfds, NULL); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "__pmSelectRead(%d,...) done: nready=%d run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, nready, run_done_alarm, vol_switch_alarm, log_alarm); } #endif __pmAFblock(); if (nready > 0) { /* handle request on control port */ for (i = 0; i < CFD_NUM; ++i) { if (ctlfds[i] >= 0 && __pmFD_ISSET(ctlfds[i], &readyfds)) { if (control_req(ctlfds[i])) { /* new client has connected */ __pmFD_SET(clientfd, &fds); if (clientfd >= numfds) numfds = clientfd + 1; } } } if (clientfd >= 0 && __pmFD_ISSET(clientfd, &readyfds)) { /* process request from client, save clientfd in case client * closes connection, resetting clientfd to -1 */ int fd = clientfd; if (client_req()) { /* client closed connection */ __pmFD_CLR(fd, &fds); __pmCloseSocket(clientfd); clientfd = -1; numfds = maxfd() + 1; qa_case = 0; } } #ifndef IS_MINGW if (pmcdfd >= 0 && __pmFD_ISSET(pmcdfd, &readyfds)) { /* * do not expect this, given synchronous commumication with the * pmcd ... either pmcd has terminated, or bogus PDU ... or its * Win32 and we are operating under the different conditions of * our AF.c implementation there, which has to deal with a lack * of signal support on Windows - race condition exists between * this check and the async event timer callback. */ __pmPDU *pb; __pmPDUHdr *php; sts = __pmGetPDU(pmcdfd, ANY_SIZE, TIMEOUT_NEVER, &pb); if (sts <= 0) { if (sts < 0) fprintf(stderr, "Error: __pmGetPDU: %s\n", pmErrStr(sts)); disconnect(sts); } else { php = (__pmPDUHdr *)pb; fprintf(stderr, "Error: Unsolicited %s PDU from PMCD\n", __pmPDUTypeStr(php->type)); disconnect(PM_ERR_IPC); } if (sts > 0) __pmUnpinPDUBuf(pb); } #endif if (rsc_fd >= 0 && __pmFD_ISSET(rsc_fd, &readyfds)) { /* * some action on the recording session control fd * end-of-file means launcher has quit, otherwise we * expect one of these commands * V<number>\n - version * F<folio>\n - folio name * P<name>\n - launcher's name * R\n - launcher can replay * D\n - detach from launcher * Q\n - quit pmlogger */ char rsc_buf[MAXPATHLEN]; char *rp = rsc_buf; char myc; int fake_x = 0; for (rp = rsc_buf; ; rp++) { if (read(rsc_fd, &myc, 1) <= 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "recording session control: eof\n"); #endif if (rp != rsc_buf) { *rp = '\0'; fprintf(stderr, "Error: incomplete recording session control message: \"%s\"\n", rsc_buf); } fake_x = 1; break; } if (rp >= &rsc_buf[MAXPATHLEN]) { fprintf(stderr, "Error: absurd recording session control message: \"%100.100s ...\"\n", rsc_buf); fake_x = 1; break; } if (myc == '\n') { *rp = '\0'; break; } *rp = myc; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { if (fake_x == 0) fprintf(stderr, "recording session control: \"%s\"\n", rsc_buf); } #endif if (fake_x) do_dialog('X'); else if (strcmp(rsc_buf, "Q") == 0 || strcmp(rsc_buf, "D") == 0 || strcmp(rsc_buf, "?") == 0) do_dialog(rsc_buf[0]); else if (rsc_buf[0] == 'F') folio_name = strdup(&rsc_buf[1]); else if (rsc_buf[0] == 'P') rsc_prog = strdup(&rsc_buf[1]); else if (strcmp(rsc_buf, "R") == 0) rsc_replay = 1; else if (rsc_buf[0] == 'V' && rsc_buf[1] == '0') { /* * version 0 of the recording session control ... * this is all we grok at the moment */ ; } else { fprintf(stderr, "Error: illegal recording session control message: \"%s\"\n", rsc_buf); do_dialog('X'); } } } else if (vol_switch_flag) { newvolume(VOL_SW_SIGHUP); vol_switch_flag = 0; } else if (nready < 0 && neterror() != EINTR) fprintf(stderr, "Error: select: %s\n", netstrerror()); __pmAFunblock(); if (target_pid && !__pmProcessExists(target_pid)) exit(EXIT_SUCCESS); if (exit_code) break; } exit(exit_code); }
int newvolume(int vol_switch_type) { FILE *newfp; int nextvol = logctl.l_curvol + 1; time_t now; static char *vol_sw_strs[] = { "SIGHUP", "pmlc request", "sample counter", "sample byte size", "sample time", "max data volume size" }; vol_samples_counter = 0; vol_bytes += ftell(logctl.l_mfp); if (exit_bytes != -1) { if (vol_bytes >= exit_bytes) run_done(0, "Byte limit reached"); } /* * If we are not part of a callback but instead a * volume switch from "pmlc" or a "SIGHUP" then * get rid of pending volume switch in event queue * as it will now be wrong, and schedule a new * volume switch event. */ if (vol_switch_afid >= 0 && vol_switch_type != VOL_SW_TIME) { __pmAFunregister(vol_switch_afid); vol_switch_afid = __pmAFregister(&vol_switch_time, NULL, vol_switch_callback); } if ((newfp = __pmLogNewFile(archBase, nextvol)) != NULL) { if (logctl.l_state == PM_LOG_STATE_NEW) { /* * nothing has been logged as yet, force out the label records */ __pmtimevalNow(&last_stamp); logctl.l_label.ill_start.tv_sec = (__int32_t)last_stamp.tv_sec; logctl.l_label.ill_start.tv_usec = (__int32_t)last_stamp.tv_usec; logctl.l_label.ill_vol = PM_LOG_VOL_TI; __pmLogWriteLabel(logctl.l_tifp, &logctl.l_label); logctl.l_label.ill_vol = PM_LOG_VOL_META; __pmLogWriteLabel(logctl.l_mdfp, &logctl.l_label); logctl.l_label.ill_vol = 0; __pmLogWriteLabel(logctl.l_mfp, &logctl.l_label); logctl.l_state = PM_LOG_STATE_INIT; } #if 0 if (last_stamp.tv_sec != 0) { __pmTimeval tmp; tmp.tv_sec = (__int32_t)last_stamp.tv_sec; tmp.tv_usec = (__int32_t)last_stamp.tv_usec; __pmLogPutIndex(&logctl, &tmp); } #endif fclose(logctl.l_mfp); logctl.l_mfp = newfp; logctl.l_label.ill_vol = logctl.l_curvol = nextvol; __pmLogWriteLabel(logctl.l_mfp, &logctl.l_label); time(&now); fprintf(stderr, "New log volume %d, via %s at %s", nextvol, vol_sw_strs[vol_switch_type], ctime(&now)); return nextvol; } else return -oserror(); }
/* * Called with valid context locked ... */ int __pmFetchLocal(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result) { int sts; int ctx; int j; int k; int n; pmResult *ans; pmResult *tmp_ans; __pmDSO *dp; int need; static pmID * splitlist=NULL; static int splitmax=0; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ return PM_ERR_THREAD; if (numpmid < 1) return PM_ERR_TOOSMALL; ctx = __pmPtrToHandle(ctxp); /* * this is very ugly ... the DSOs have a high-water mark * allocation algorithm for the result skeleton, but the * code that calls us assumes it has freedom to retain * this result structure for as long as it wishes, and * then to call pmFreeResult * * we make another skeleton, selectively copy and return that * * (numpmid - 1) because there's room for one valueSet * in a pmResult */ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *); if ((ans = (pmResult *)malloc(need)) == NULL) return -oserror(); /* * Check if we have enough space to accomodate "best" case scenario - * all pmids are from the same domain */ if (splitmax < numpmid) { splitmax = numpmid; pmID *tmp_list = (pmID *)realloc(splitlist, sizeof(pmID)*splitmax); if (tmp_list == NULL) { free(splitlist); splitmax = 0; free(ans); return -oserror(); } splitlist = tmp_list; } ans->numpmid = numpmid; __pmtimevalNow(&ans->timestamp); for (j = 0; j < numpmid; j++) ans->vset[j] = NULL; for (j = 0; j < numpmid; j++) { int cnt; if (ans->vset[j] != NULL) /* picked up in a previous fetch */ continue; sts = 0; if ((dp = __pmLookupDSO(((__pmID_int *)&pmidlist[j])->domain)) == NULL) /* based on domain, unknown PMDA */ sts = PM_ERR_NOAGENT; else { if (ctxp->c_sent != dp->domain) { /* * current profile is _not_ already cached at other end of * IPC, so send get current profile ... * Note: trickier than the non-local case, as no per-PMDA * caching at the PMCD end, so need to remember the * last domain to receive a profile */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) fprintf(stderr, "__pmFetchLocal: calling ???_profile(domain: %d), " "context: %d\n", dp->domain, ctx); #endif if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; sts = dp->dispatch.version.any.profile(ctxp->c_instprof, dp->dispatch.version.any.ext); if (sts >= 0) ctxp->c_sent = dp->domain; } } /* Copy all pmID for the current domain into the temp. list */ for (cnt=0, k=j; k < numpmid; k++ ) { if (((__pmID_int*)(pmidlist+k))->domain == ((__pmID_int*)(pmidlist+j))->domain) splitlist[cnt++] = pmidlist[k]; } if (sts >= 0) { if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; sts = dp->dispatch.version.any.fetch(cnt, splitlist, &tmp_ans, dp->dispatch.version.any.ext); } /* Copy results back * * Note: We DO NOT have to free tmp_ans since DSO PMDA would * ALWAYS return a pointer to the static area. */ for (n = 0, k = j; k < numpmid && n < cnt; k++) { if (pmidlist[k] == splitlist[n]) { if (sts < 0) { ans->vset[k] = (pmValueSet *)malloc(sizeof(pmValueSet)); if (ans->vset[k] == NULL) { /* cleanup all partial allocations for ans->vset[] */ for (k--; k >=0; k--) free(ans->vset[k]); free(ans); return -oserror(); } ans->vset[k]->numval = sts; ans->vset[k]->pmid = pmidlist[k]; } else { ans->vset[k] = tmp_ans->vset[n]; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmFetchLocal: [%d] PMID=%s nval=", k, pmIDStr_r(pmidlist[k], strbuf, sizeof(strbuf))); if (ans->vset[k]->numval < 0) fprintf(stderr, "%s\n", pmErrStr_r(ans->vset[k]->numval, errmsg, sizeof(errmsg))); else fprintf(stderr, "%d\n", ans->vset[k]->numval); } #endif n++; } } } *result = ans; return 0; }
static void onalarm(int dummy) { struct timeval now; struct timeval tmp; struct timeval interval; qelt *qp; if (!block) AFhold(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmtimevalNow(&now); __pmPrintStamp(stderr, &now); fprintf(stderr, " AFonalarm(%d)\n", dummy); } #endif if (root != NULL) { /* something to do ... */ while (root != NULL) { /* compute difference between scheduled time and now */ __pmtimevalNow(&now); tmp = root->q_when; tsub(&tmp, &now); if (tmp.tv_sec == 0 && tmp.tv_usec <= 10000) { /* * within one 10msec tick, the time has passed for this one, * execute the callback and reschedule */ qp = root; root = root->q_next; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFcallback " PRINTF_P_PFX "%p(%d, " PRINTF_P_PFX "%p)\n", qp->q_func, qp->q_afid, qp->q_data); } #endif qp->q_func(qp->q_afid, qp->q_data); if (qp->q_delta.tv_sec == 0 && qp->q_delta.tv_usec == 0) { /* * if delta is zero, this is a single-shot event, * so do not reschedule it */ free(qp); } else { /* * avoid falling too far behind * if the scheduled time is more than q_delta in the * past we will never catch up ... better to skip some * events to catch up ... * * <------------ next q_when range -----------------> * * cannot catchup | may catchup | on schedule * | | * --------------------|---------------|------------> time * | | * | +-- now * +-- now - q_delta */ __pmtimevalNow(&now); for ( ; ; ) { tadd(&qp->q_when, &qp->q_delta); tmp = qp->q_when; tsub_real(&tmp, &now); tadd(&tmp, &qp->q_delta); if (tmp.tv_sec >= 0) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFcallback event %d too slow, skip callback for ", qp->q_afid); __pmPrintStamp(stderr, &qp->q_when); fputc('\n', stderr); } #endif } enqueue(qp); } } else /* * head of the queue (and hence all others) are too far in * the future ... done for this time */ break; } if (root == NULL) { pmprintf("Warning: AF event queue is empty, nothing more will be scheduled\n"); pmflush(); } else { /* set itimer for head of queue */ interval = root->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } } if (!block) { AFrearm(); AFrelse(); } }
int pmtracebegin(const char *tag) { static int first = 1; _pmTraceLibdata *hptr; _pmTraceLibdata hash; int len, a_sts = 0, b_sts = 0, protocol; if (tag == NULL || *tag == '\0') return PMTRACE_ERR_TAGNAME; if ((len = strlen(tag)+1) >= MAXTAGNAMELEN) return PMTRACE_ERR_TAGLENGTH; hash.tag = (char *)tag; hash.taglength = len; hash.id = _pmtraceid(); hash.tracetype = TRACE_TYPE_TRANSACT; /* * We need to do both the connect and hash table manipulation, * otherwise the reconnect isn't reliable and the hash table * (potentially) becomes completely wrong, and we reject some * transact calls which actually were in a valid call sequence. */ protocol = __pmtraceprotocol(TRACE_PROTOCOL_QUERY); if (_pmtimedout && (a_sts = _pmtraceconnect(1)) < 0) { if (first || protocol == TRACE_PROTOCOL_ASYNC) return a_sts; /* exception to the rule */ a_sts = _pmtraceremaperr(a_sts); if (a_sts == PMTRACE_ERR_IPC && protocol == TRACE_PROTOCOL_SYNC) { _pmtimedout = 1; /* try reconnect */ a_sts = 0; } } if (a_sts >= 0) first = 0; /* lock hash table for search and subsequent insert/update */ TRACE_LOCK; if ((hptr = __pmhashlookup(&_pmtable, tag, &hash)) == NULL) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtracebegin: new transaction '%s' " "(id=0x%" PRIx64 ")\n", tag, hash.id); #endif hash.pad = 0; if ((hash.tag = strdup(tag)) == NULL) b_sts = -oserror(); __pmtimevalNow(&hash.start); if (b_sts >= 0) { hash.inprogress = 1; b_sts = __pmhashinsert(&_pmtable, tag, &hash); } if (b_sts < 0 && hash.tag != NULL) free(hash.tag); } else if (hptr->inprogress == 1) b_sts = PMTRACE_ERR_INPROGRESS; else if (hptr->tracetype != TRACE_TYPE_TRANSACT) b_sts = PMTRACE_ERR_TAGTYPE; else { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtracebegin: updating transaction '%s' " "(id=0x%" PRIx64 ")\n", tag, hash.id); #endif __pmtimevalNow(&hptr->start); hptr->inprogress = 1; } /* unlock hash table */ if (TRACE_UNLOCK != 0) b_sts = -oserror(); if (a_sts < 0) return a_sts; return b_sts; }
/* * sendstatus */ static int sendstatus(void) { int rv; int end; int version; static int firsttime = 1; static char *tzlogger; struct timeval now; if (firsttime) { tzlogger = __pmTimezone(); firsttime = 0; } if ((version = __pmVersionIPC(clientfd)) < 0) return version; if (version >= LOG_PDU_VERSION2) { __pmLoggerStatus ls; if ((ls.ls_state = logctl.l_state) == PM_LOG_STATE_NEW) ls.ls_start.tv_sec = ls.ls_start.tv_usec = 0; else memcpy(&ls.ls_start, &logctl.l_label.ill_start, sizeof(ls.ls_start)); memcpy(&ls.ls_last, &last_stamp, sizeof(ls.ls_last)); __pmtimevalNow(&now); ls.ls_timenow.tv_sec = (__int32_t)now.tv_sec; ls.ls_timenow.tv_usec = (__int32_t)now.tv_usec; ls.ls_vol = logctl.l_curvol; ls.ls_size = ftell(logctl.l_mfp); assert(ls.ls_size >= 0); /* be careful of buffer size mismatches when copying strings */ end = sizeof(ls.ls_hostname) - 1; strncpy(ls.ls_hostname, logctl.l_label.ill_hostname, end); ls.ls_hostname[end] = '\0'; /* BTW, that string should equal pmcd_host[]. */ /* NB: FQDN cleanup: there is no such thing as 'the fully qualified domain name' of a server: it may have several or none; the set may have changed since the time the log archive was collected. Now that we store the then-current pmcd.hostname in the ill_hostname (and thus get it reported in ls_hostname), we could pass something else informative in the ls_fqdn slot. Namely, pmcd_host_conn[], which is the access path pmlogger's using to get to the pmcd. */ end = sizeof(ls.ls_fqdn) - 1; strncpy(ls.ls_fqdn, pmcd_host_conn, end); ls.ls_fqdn[end] = '\0'; end = sizeof(ls.ls_tz) - 1; strncpy(ls.ls_tz, logctl.l_label.ill_tz, end); ls.ls_tz[end] = '\0'; end = sizeof(ls.ls_tzlogger) - 1; if (tzlogger != NULL) strncpy(ls.ls_tzlogger, tzlogger, end); else end = 0; ls.ls_tzlogger[end] = '\0'; rv = __pmSendLogStatus(clientfd, &ls); } else rv = PM_ERR_IPC; return rv; }
int pmtraceend(const char *tag) { _pmTraceLibdata hash; _pmTraceLibdata *hptr; struct timeval now; int len, protocol, sts = 0; if (tag == NULL || *tag == '\0') return PMTRACE_ERR_TAGNAME; if ((len = strlen(tag)+1) >= MAXTAGNAMELEN) return PMTRACE_ERR_TAGLENGTH; __pmtimevalNow(&now); /* give just enough info for comparison routine */ hash.tag = (char *)tag; hash.taglength = len; hash.id = _pmtraceid(); hash.tracetype = TRACE_TYPE_TRANSACT; /* lock hash table for search and update then send data */ TRACE_LOCK; if ((hptr = __pmhashlookup(&_pmtable, tag, &hash)) == NULL) sts = PMTRACE_ERR_NOSUCHTAG; else if (hptr->inprogress != 1) sts = PMTRACE_ERR_NOPROGRESS; else if (hptr->tracetype != TRACE_TYPE_TRANSACT) sts = PMTRACE_ERR_TAGTYPE; else { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtraceend: sending transaction data '%s' " "(id=0x%" PRIx64 ")\n", tag, hash.id); #endif hptr->inprogress = 0; hptr->data = __pmtracetvsub(&now, &hptr->start); if (sts >= 0 && _pmtimedout) { sts = _pmtracereconnect(); sts = _pmtraceremaperr(sts); } if (sts >= 0) { sts = __pmtracesenddata(__pmfd, hptr->tag, hptr->taglength, TRACE_TYPE_TRANSACT, hptr->data); sts = _pmtraceremaperr(sts); } protocol = __pmtraceprotocol(TRACE_PROTOCOL_QUERY); if (sts >= 0 && protocol == TRACE_PROTOCOL_SYNC) sts = _pmtracegetack(sts, TRACE_TYPE_TRANSACT); if (sts == PMTRACE_ERR_IPC && protocol == TRACE_PROTOCOL_SYNC) { _pmtimedout = 1; /* try reconnect */ sts = 0; } } if (TRACE_UNLOCK != 0) return -oserror(); return sts; }