static void __pmInitContextLock(pthread_mutex_t *lock) { pthread_mutexattr_t attr; int sts; char errmsg[PM_MAXERRMSGLEN]; /* * Need context lock to be recursive as we sometimes call * __pmHandleToPtr() while the current context is already * locked */ if ((sts = pthread_mutexattr_init(&attr)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d lock pthread_mutexattr_init failed: %s", contexts_len-1, errmsg); exit(4); } if ((sts = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d lock pthread_mutexattr_settype failed: %s", contexts_len-1, errmsg); exit(4); } if ((sts = pthread_mutex_init(lock, &attr)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d lock pthread_mutex_init failed: %s", contexts_len-1, errmsg); exit(4); } }
static int negotiate_proxy(int fd, const char *hostname, int port) { char buf[MY_BUFLEN]; char *bp; int ok = 0; /* * version negotiation (converse to pmproxy logic) * __pmSend my client version message * __pmRecv server version message * __pmSend hostname and port */ if (__pmSend(fd, MY_VERSION, strlen(MY_VERSION), 0) != strlen(MY_VERSION)) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: send version string to pmproxy failed: %s\n", pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); return PM_ERR_IPC; } for (bp = buf; bp < &buf[MY_BUFLEN]; bp++) { if (__pmRecv(fd, bp, 1, 0) != 1) { *bp = '\0'; bp = &buf[MY_BUFLEN]; break; } if (*bp == '\n' || *bp == '\r') { *bp = '\0'; break; } } if (bp < &buf[MY_BUFLEN]) { if (strcmp(buf, "pmproxy-server 1") == 0) ok = 1; } if (!ok) { __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: bad version string from pmproxy: \"%s\"\n", buf); return PM_ERR_IPC; } snprintf(buf, sizeof(buf), "%s %d\n", hostname, port); if (__pmSend(fd, buf, strlen(buf), 0) != strlen(buf)) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: send hostname+port string to pmproxy failed: %s'\n", pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); return PM_ERR_IPC; } return ok; }
static void * func1(void *arg) { int sts; int i; char msgbuf[PM_MAXERRMSGLEN]; for (i = 0; i < ITER; i++) { nmetric = 0; sts = pmTraversePMNS("", dometric); if (sts >= 0) printf("traverse: found %d metrics, sts %d\n", nmetric, sts); else { /* * expect 0 metrics and PM_ERR_NOPMNS if the pmTraversePMNS * gets in between the pmUnloadPMNS and the pmLoadPMNS in the * other thread */ if (nmetric > 0 || sts != PM_ERR_NOPMNS) printf("traverse: found %d metrics, sts %s\n", nmetric, pmErrStr_r(sts, msgbuf, PM_MAXERRMSGLEN)); else { /* * nmetric == 0 && sts == PM_ERR_NOPMNS, so try again ... * won't loop forever because eventually func2() will * finish */ i--; } } } pthread_exit(NULL); }
char * pmErrStr(int code) { static char errmsg[PM_MAXERRMSGLEN]; pmErrStr_r(code, errmsg, sizeof(errmsg)); return errmsg; }
/* * Connect to the pmdaroot socket as a client, perform version exchange */ int pmdaRootConnect(const char *path) { __pmSockAddr *addr; char *tmpdir; char socketpath[MAXPATHLEN]; char errmsg[PM_MAXERRMSGLEN]; int fd, sts, version, features; /* Initialize the socket address. */ if ((addr = __pmSockAddrAlloc()) == NULL) return -ENOMEM; if (path == NULL) { if ((tmpdir = pmGetOptionalConfig("PCP_TMP_DIR")) == NULL) { __pmSockAddrFree(addr); return PM_ERR_GENERIC; } snprintf(socketpath, sizeof(socketpath), "%s/pmcd/root.socket", tmpdir); } else strncpy(socketpath, path, sizeof(socketpath)); socketpath[sizeof(socketpath)-1] = '\0'; __pmSockAddrSetFamily(addr, AF_UNIX); __pmSockAddrSetPath(addr, socketpath); /* Create client socket connection */ if ((fd = __pmCreateUnixSocket()) < 0) { __pmNotifyErr(LOG_ERR, "pmdaRootConnect: cannot create socket %s: %s\n", socketpath, osstrerror_r(errmsg, sizeof(errmsg))); __pmSockAddrFree(addr); return fd; } sts = __pmConnect(fd, addr, -1); __pmSockAddrFree(addr); if (sts < 0) { if (sts != -EPERM || (pmDebug & DBG_TRACE_LIBPMDA)) __pmNotifyErr(LOG_INFO, "pmdaRootConnect: cannot connect to %s: %s\n", socketpath, osstrerror_r(errmsg, sizeof(errmsg))); __pmCloseSocket(fd); return sts; } /* Check server connection information */ if ((sts = __pmdaRecvRootPDUInfo(fd, &version, &features)) < 0) { __pmNotifyErr(LOG_ERR, "pmdaRootConnect: cannot verify %s server: %s\n", socketpath, pmErrStr_r(sts, errmsg, sizeof(errmsg))); __pmCloseSocket(fd); return sts; } if (pmDebug & DBG_TRACE_LIBPMDA) __pmNotifyErr(LOG_INFO, "pmdaRootConnect: %s server fd=%d version=%d features=0x%x\n", socketpath, fd, version, features); return fd; }
static int unparseHostSpec(pmHostSpec *hostp, int count, char *string, size_t size, int prefix) { int off = 0, len = size; /* offset in string and space remaining */ int i, j, sts; for (i = 0; i < count; i++) { if (i > 0) { if ((sts = pmsprintf(string + off, len, "@")) >= size) { off = -E2BIG; goto done; } len -= sts; off += sts; } if (prefix && hostp[i].nports == PM_HOST_SPEC_NPORTS_LOCAL) { if ((sts = pmsprintf(string + off, len, "local:/%s", hostp[i].name + 1)) >= size) { off = -E2BIG; goto done; } } else if (prefix && hostp[i].nports == PM_HOST_SPEC_NPORTS_UNIX) { if ((sts = pmsprintf(string + off, len, "unix:/%s", hostp[i].name + 1)) >= size) { off = -E2BIG; goto done; } } else { if ((sts = pmsprintf(string + off, len, "%s", hostp[i].name)) >= size) { off = -E2BIG; goto done; } } len -= sts; off += sts; for (j = 0; j < hostp[i].nports; j++) { if ((sts = pmsprintf(string + off, len, "%c%u", (j == 0) ? ':' : ',', hostp[i].ports[j])) >= size) { off = -E2BIG; goto done; } len -= sts; off += sts; } } done: if (pmDebugOptions.context) { fprintf(stderr, "__pmUnparseHostSpec([name=%s ports=%p nport=%d], count=%d, ...) -> ", hostp->name, hostp->ports, hostp->nports, count); if (off < 0) { char errmsg[PM_MAXERRMSGLEN]; pmErrStr_r(off, errmsg, sizeof(errmsg)); fprintf(stderr, "%s\n", errmsg); } else fprintf(stderr, "%d \"%s\"\n", off, string); } return off; }
int main(int argc, char **argv) { pthread_t tid1; pthread_t tid2; int sts; char *msg; unsigned int in[PDU_MAX+1]; unsigned int out[PDU_MAX+1]; int i; char msgbuf[PM_MAXERRMSGLEN]; setvbuf(stdout, NULL, _IONBF, 0); if (argc != 1) { printf("Usage: multithread4\n"); exit(1); } for (i = 0; i <= PDU_MAX; i++) { in[i] = out[i] = 0; } __pmSetPDUCntBuf(in, out); if ((sts = pmLoadNameSpace(PM_NS_DEFAULT)) < 0) { printf("%s: pmLoadNameSpace: %s\n", argv[0], pmErrStr_r(sts, msgbuf, PM_MAXERRMSGLEN)); exit(1); } sts = pthread_create(&tid1, NULL, func1, NULL); if (sts != 0) { printf("thread_create: tid1: sts=%d\n", sts); exit(1); } sts = pthread_create(&tid2, NULL, func2, NULL); if (sts != 0) { printf("thread_create: tid2: sts=%d\n", sts); exit(1); } pthread_join(tid1, (void *)&msg); if (msg != NULL) printf("tid1: %s\n", msg); pthread_join(tid2, (void *)&msg); if (msg != NULL) printf("tid2: %s\n", msg); printf("Total PDU counts\n"); printf("in:"); for (i = 0; i <= PDU_MAX; i++) printf(" %d", in[i]); putchar('\n'); printf("out:"); for (i = 0; i <= PDU_MAX; i++) printf(" %d", out[i]); putchar('\n'); exit(0); }
char * pmiErrStr_r(int code, char *buf, int buflen) { const char *msg; if (code == -1 && current != NULL) code = current->last_sts; switch (code) { case PMI_ERR_DUPMETRICNAME: msg = "Metric name already defined"; break; case PMI_ERR_DUPMETRICID: msg = "Metric pmID already defined"; break; case PMI_ERR_DUPINSTNAME: msg = "External instance name already defined"; break; case PMI_ERR_DUPINSTID: msg = "Internal instance identifer already defined"; break; case PMI_ERR_INSTNOTNULL: msg = "Null instance expected for a singular metric"; break; case PMI_ERR_INSTNULL: msg = "Null instance not allowed for a non-singular metric"; break; case PMI_ERR_BADHANDLE: msg = "Illegal handle"; break; case PMI_ERR_DUPVALUE: msg = "Value already assigned for this metric-instance"; break; case PMI_ERR_BADTYPE: msg = "Illegal metric type"; break; case PMI_ERR_BADSEM: msg = "Illegal metric semantics"; break; case PMI_ERR_NODATA: msg = "No data to output"; break; case PMI_ERR_BADMETRICNAME: msg = "Illegal metric name"; break; case PMI_ERR_BADTIMESTAMP: msg = "Illegal result timestamp"; break; default: return pmErrStr_r(code, buf, buflen); } strncpy(buf, msg, buflen); buf[buflen-1] = '\0'; return buf; }
static void destroylock(pthread_mutex_t *lock, char *which) { int psts; char errmsg[PM_MAXERRMSGLEN]; if ((psts = pthread_mutex_destroy(lock)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmDestroyContext: pthread_mutex_destroy(%s) failed: %s\n", which, errmsg); /* * Most likely cause is the mutex still being locked ... this is a * a library bug, but potentially recoverable ... */ while (PM_UNLOCK(lock) >= 0) { fprintf(stderr, "pmDestroyContext: extra %s unlock?\n", which); } if ((psts = pthread_mutex_destroy(lock)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmDestroyContext: pthread_mutex_destroy(%s) failed second try: %s\n", which, errmsg); } } }
static void __pmInitChannelLock(pthread_mutex_t *lock) { int sts; char errmsg[PM_MAXERRMSGLEN]; if ((sts = pthread_mutex_init(lock, NULL)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d pmcd channel lock pthread_mutex_init failed: %s", contexts_len, errmsg); exit(4); } }
/** * @brief Constructor. * * If the optional \a message is not provided (or is empty), then either * pmErrStr_r (if available) or pmErrStr will be used to fetch PCP's message * for \a pm_error_code. * * @param pm_error_code PCP error code. * @param message Error message. * * @see pmErrStr * @see pmErrStr_r */ exception(const int pm_error_code, const std::string &message = std::string()) : pm_error_code(pm_error_code), message(message) { if (message.empty()) { #ifdef PM_MAXERRMSGLEN // pmErrStr_r and PM_MAXERRMSGLEN added in PCP 3.6.0. char buffer[PM_MAXERRMSGLEN]; pmErrStr_r(pm_error_code, buffer, sizeof(buffer)); this->message.assign(buffer); #else this->message.assign(pmErrStr(pm_error_code)); #endif } }
static void * func2(void *arg) { int sts; char *fn = "func2"; int i; char msgbuf[PM_MAXERRMSGLEN]; for (i = 0; i < ITER; i++) { pmUnloadNameSpace(); if ((sts = pmLoadNameSpace(PM_NS_DEFAULT)) < 0) { printf("%s: pmLoadNameSpace[%d]: %s\n", fn, i, pmErrStr_r(sts, msgbuf, PM_MAXERRMSGLEN)); exit(1); } } pthread_exit(NULL); }
static void load_proxy_hostspec(pmHostSpec *proxy) { char errmsg[PM_MAXERRMSGLEN]; char *envstr; if ((envstr = getenv("PMPROXY_HOST")) != NULL) { proxy->name = strdup(envstr); if (proxy->name == NULL) { __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: cannot save PMPROXY_HOST: %s\n", pmErrStr_r(-oserror(), errmsg, sizeof(errmsg))); } else { /* *__pmProxyAddPorts discovers at least one valid port, if it * returns. */ proxy->nports = __pmProxyAddPorts(&proxy->ports, proxy->nports); } } }
static void init(void) { if (need_init) { char *configpath; if ((configpath = getenv("PCP_DERIVED_CONFIG")) != NULL) { int sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { fprintf(stderr, "Derived metric initialization from $PCP_DERIVED_CONFIG\n"); } #endif sts = pmLoadDerivedConfig(configpath); #ifdef PCP_DEBUG if (sts < 0 && (pmDebug & DBG_TRACE_DERIVE)) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmLoadDerivedConfig -> %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif } need_init = 0; } }
/* result is pinned on successful return */ int __pmGetPDU(int fd, int mode, int timeout, __pmPDU **result) { int need; int len; static int maxsize = PDU_CHUNK; char *handle; __pmPDU *pdubuf; __pmPDU *pdubuf_prev; __pmPDUHdr *php; if ((pdubuf = __pmFindPDUBuf(maxsize)) == NULL) return -oserror(); /* First read - try to read the header */ len = pduread(fd, (void *)pdubuf, sizeof(__pmPDUHdr), HEADER, timeout); php = (__pmPDUHdr *)pdubuf; if (len < (int)sizeof(__pmPDUHdr)) { if (len == -1) { if (__pmSocketClosed()) { len = 0; } else { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg))); } } else if (len >= (int)sizeof(php->len)) { /* * Have part of a PDU header. Enough for the "len" * field to be valid, but not yet all of it - save * what we have received and try to read some more. * Note this can only happen once per PDU, so the * ntohl() below will _only_ be done once per PDU. */ goto check_read_len; /* continue, do not return */ } else if (len == PM_ERR_TIMEOUT) { __pmUnpinPDUBuf(pdubuf); return PM_ERR_TIMEOUT; } else if (len < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(len, errmsg, sizeof(errmsg))); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } else if (len > 0) { __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: bad len=%d", fd, len); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } /* * end-of-file with no data */ __pmUnpinPDUBuf(pdubuf); return 0; } check_read_len: php->len = ntohl(php->len); if (php->len < (int)sizeof(__pmPDUHdr)) { /* * PDU length indicates insufficient bytes for a PDU header * ... looks like DOS attack like PV 935490 */ __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU len=%d in hdr", fd, php->len); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } else if (mode == LIMIT_SIZE && php->len > ceiling) { /* * Guard against denial of service attack ... don't accept PDUs * from clients that are larger than 64 Kbytes (ceiling) * (note, pmcd and pmdas have to be able to _send_ large PDUs, * e.g. for a pmResult or instance domain enquiry) */ __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d bad PDU len=%d in hdr exceeds maximum client PDU size (%d)", fd, php->len, ceiling); __pmUnpinPDUBuf(pdubuf); return PM_ERR_TOOBIG; } if (len < php->len) { /* * need to read more ... */ int tmpsize; int have = len; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (php->len > maxsize) { tmpsize = PDU_CHUNK * ( 1 + php->len / PDU_CHUNK); maxsize = tmpsize; } else tmpsize = maxsize; PM_UNLOCK(__pmLock_libpcp); pdubuf_prev = pdubuf; if ((pdubuf = __pmFindPDUBuf(tmpsize)) == NULL) { __pmUnpinPDUBuf(pdubuf_prev); return -oserror(); } memmove((void *)pdubuf, (void *)php, len); __pmUnpinPDUBuf(pdubuf_prev); php = (__pmPDUHdr *)pdubuf; need = php->len - have; handle = (char *)pdubuf; /* block until all of the PDU is received this time */ len = pduread(fd, (void *)&handle[len], need, BODY, timeout); if (len != need) { if (len == PM_ERR_TIMEOUT) { __pmUnpinPDUBuf(pdubuf); return PM_ERR_TIMEOUT; } else if (len < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg))); } else __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: have %d, want %d, got %d", fd, have, need, len); /* * only report header fields if you've read enough bytes */ if (len > 0) have += len; if (have >= (int)(sizeof(php->len)+sizeof(php->type)+sizeof(php->from))) __pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x from=0x%x", php->len, (unsigned)ntohl(php->type), (unsigned)ntohl(php->from)); else if (have >= (int)(sizeof(php->len)+sizeof(php->type))) __pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x", php->len, (unsigned)ntohl(php->type)); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } } *result = (__pmPDU *)php; php->type = ntohl((unsigned int)php->type); if (php->type < 0) { /* * PDU type is bad ... could be a possible mem leak attack like * https://bugzilla.redhat.com/show_bug.cgi?id=841319 */ __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU type=%d in hdr", fd, php->type); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } php->from = ntohl((unsigned int)php->from); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int j; char *p; int jend = PM_PDU_SIZE(php->len); char strbuf[20]; /* clear the padding bytes, lest they contain garbage */ p = (char *)*result + php->len; while (p < (char *)*result + jend*sizeof(__pmPDU)) *p++ = '~'; /* buffer end */ if (mypid == -1) mypid = (int)getpid(); fprintf(stderr, "[%d]pmGetPDU: %s fd=%d len=%d from=%d", mypid, __pmPDUTypeStr_r(php->type, strbuf, sizeof(strbuf)), fd, php->len, php->from); for (j = 0; j < jend; j++) { if ((j % 8) == 0) fprintf(stderr, "\n%03d: ", j); fprintf(stderr, "%8x ", (*result)[j]); } putc('\n', stderr); } #endif if (php->type >= PDU_START && php->type <= PDU_FINISH) __pmPDUCntIn[php->type-PDU_START]++; /* * Note php points into the PDU buffer pdubuf that remains pinned * and php is returned via the result parameter ... see the * thread-safe comments above */ return php->type; }
int __pmConnectLocal(__pmHashCtl *attrs) { int i; __pmDSO *dp; char pathbuf[MAXPATHLEN]; const char *path; #if defined(HAVE_DLOPEN) unsigned int challenge; void (*initp)(pmdaInterface *); #ifdef HAVE_ATEXIT static int atexit_installed = 0; #endif #endif if (numdso == -1) { int sts; sts = build_dsotab(); if (sts < 0) return sts; } for (i = 0; i < numdso; i++) { dp = &dsotab[i]; if (dp->domain == -1 || dp->handle != NULL) continue; /* * __pmLocalPMDA() means the path to the DSO may be something * other than relative to $PCP_PMDAS_DIR ... need to try both * options and also with and without DSO_SUFFIX (so, dll, etc) */ snprintf(pathbuf, sizeof(pathbuf), "%s%c%s", pmGetConfig("PCP_PMDAS_DIR"), __pmPathSeparator(), dp->name); if ((path = __pmFindPMDA(pathbuf)) == NULL) { snprintf(pathbuf, sizeof(pathbuf), "%s%c%s.%s", pmGetConfig("PCP_PMDAS_DIR"), __pmPathSeparator(), dp->name, DSO_SUFFIX); if ((path = __pmFindPMDA(pathbuf)) == NULL) { if ((path = __pmFindPMDA(dp->name)) == NULL) { snprintf(pathbuf, sizeof(pathbuf), "%s.%s", dp->name, DSO_SUFFIX); if ((path = __pmFindPMDA(pathbuf)) == NULL) { pmprintf("__pmConnectLocal: Warning: cannot find DSO at \"%s\" or \"%s\"\n", pathbuf, dp->name); pmflush(); dp->domain = -1; dp->handle = NULL; continue; } } } } #if defined(HAVE_DLOPEN) dp->handle = dlopen(path, RTLD_NOW); if (dp->handle == NULL) { pmprintf("__pmConnectLocal: Warning: error attaching DSO " "\"%s\"\n%s\n\n", path, dlerror()); pmflush(); dp->domain = -1; } #else /* ! HAVE_DLOPEN */ dp->handle = NULL; pmprintf("__pmConnectLocal: Warning: error attaching DSO \"%s\"\n", path); pmprintf("No dynamic DSO/DLL support on this platform\n\n"); pmflush(); dp->domain = -1; #endif if (dp->handle == NULL) continue; #if defined(HAVE_DLOPEN) /* * rest of this only makes sense if the dlopen() worked */ if (dp->init == NULL) initp = NULL; else initp = (void (*)(pmdaInterface *))dlsym(dp->handle, dp->init); if (initp == NULL) { pmprintf("__pmConnectLocal: Warning: couldn't find init function " "\"%s\" in DSO \"%s\"\n", dp->init, path); pmflush(); dlclose(dp->handle); dp->domain = -1; continue; } /* * Pass in the expected domain id. * The PMDA initialization routine can (a) ignore it, (b) check it * is the expected value, or (c) self-adapt. */ dp->dispatch.domain = dp->domain; /* * the PMDA interface / PMAPI version discovery as a "challenge" ... * for pmda_interface it is all the bits being set, * for pmapi_version it is the complement of the one you are using now */ challenge = 0xff; dp->dispatch.comm.pmda_interface = challenge; dp->dispatch.comm.pmapi_version = ~PMAPI_VERSION; dp->dispatch.comm.flags = 0; dp->dispatch.status = 0; (*initp)(&dp->dispatch); if (dp->dispatch.status != 0) { /* initialization failed for some reason */ char errmsg[PM_MAXERRMSGLEN]; pmprintf("__pmConnectLocal: Warning: initialization " "routine \"%s\" failed in DSO \"%s\": %s\n", dp->init, path, pmErrStr_r(dp->dispatch.status, errmsg, sizeof(errmsg))); pmflush(); dlclose(dp->handle); dp->domain = -1; } else { if (dp->dispatch.comm.pmda_interface < PMDA_INTERFACE_2 || dp->dispatch.comm.pmda_interface > PMDA_INTERFACE_LATEST) { pmprintf("__pmConnectLocal: Error: Unknown PMDA interface " "version %d in \"%s\" DSO\n", dp->dispatch.comm.pmda_interface, path); pmflush(); dlclose(dp->handle); dp->domain = -1; } else if (dp->dispatch.comm.pmapi_version != PMAPI_VERSION_2) { pmprintf("__pmConnectLocal: Error: Unknown PMAPI version %d " "in \"%s\" DSO\n", dp->dispatch.comm.pmapi_version, path); pmflush(); dlclose(dp->handle); dp->domain = -1; } else if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_6 && (dp->dispatch.comm.flags & PDU_FLAG_AUTH) != 0) { /* Agent wants to know about connection attributes */ build_dsoattrs(&dp->dispatch, attrs); } } #ifdef HAVE_ATEXIT PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5 && atexit_installed == 0) { /* install end of local context handler */ atexit(EndLocalContext); atexit_installed = 1; } PM_UNLOCK(__pmLock_libpcp); #endif #endif /* HAVE_DLOPEN */ } return 0; }
int pmFetch(int numpmid, pmID pmidlist[], pmResult **result) { int n; if (numpmid < 1) { n = PM_ERR_TOOSMALL; goto done; } if ((n = pmWhichContext()) >= 0) { __pmContext *ctxp = __pmHandleToPtr(n); int newcnt; pmID *newlist = NULL; int have_dm; if (ctxp == NULL) { n = PM_ERR_NOCONTEXT; goto done; } if (ctxp->c_type == PM_CONTEXT_LOCAL && PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) { /* Local context requires single-threaded applications */ n = PM_ERR_THREAD; PM_UNLOCK(ctxp->c_lock); goto done; } /* for derived metrics, may need to rewrite the pmidlist */ have_dm = newcnt = __pmPrepareFetch(ctxp, numpmid, pmidlist, &newlist); if (newcnt > numpmid) { /* replace args passed into pmFetch */ numpmid = newcnt; pmidlist = newlist; } if (ctxp->c_type == PM_CONTEXT_HOST) { /* * Thread-safe note * * Need to be careful here, because the PMCD changed protocol * may mean several PDUs are returned, but __pmDecodeResult() * may request more info from PMCD if pmDebug is set. * * So unlock ctxp->c_pmcd->pc_lock as soon as possible. */ PM_LOCK(ctxp->c_pmcd->pc_lock); if ((n = request_fetch(n, ctxp, numpmid, pmidlist)) >= 0) { int changed = 0; do { __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_RESULT) { PM_UNLOCK(ctxp->c_pmcd->pc_lock); n = __pmDecodeResult(pb, result); } else if (n == PDU_ERROR) { __pmDecodeError(pb, &n); if (n > 0) /* PMCD state change protocol */ changed = n; else PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else { PM_UNLOCK(ctxp->c_pmcd->pc_lock); if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; } if (pinpdu > 0) __pmUnpinPDUBuf(pb); } while (n > 0); if (n == 0) n |= changed; } else PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { n = __pmFetchLocal(ctxp, numpmid, pmidlist, result); } else { /* assume PM_CONTEXT_ARCHIVE */ n = __pmLogFetch(ctxp, numpmid, pmidlist, result); if (n >= 0 && (ctxp->c_mode & __PM_MODE_MASK) != PM_MODE_INTERP) { ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec; ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec; } } /* process derived metrics, if any */ if (have_dm) { __pmFinishResult(ctxp, n, result); if (newlist != NULL) free(newlist); } PM_UNLOCK(ctxp->c_lock); } done: #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) { fprintf(stderr, "pmFetch returns ...\n"); if (n > 0) { fprintf(stderr, "PMCD state changes: agent(s)"); if (n & PMCD_ADD_AGENT) fprintf(stderr, " added"); if (n & PMCD_RESTART_AGENT) fprintf(stderr, " restarted"); if (n & PMCD_DROP_AGENT) fprintf(stderr, " dropped"); fputc('\n', stderr); } if (n >= 0) __pmDumpResult(stderr, *result); else { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "Error: %s\n", pmErrStr_r(n, errmsg, sizeof(errmsg))); } } #endif return n; }
int __pmLocalPMDA(int op, int domain, const char *name, const char *init) { int sts = 0; int i; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "__pmLocalPMDA(op="); if (op == PM_LOCAL_ADD) fprintf(stderr, "ADD"); else if (op == PM_LOCAL_DEL) fprintf(stderr, "DEL"); else if (op == PM_LOCAL_CLEAR) fprintf(stderr, "CLEAR"); else fprintf(stderr, "%d ???", op); fprintf(stderr, ", domain=%d, name=%s, init=%s)\n", domain, name, init); } #endif if (numdso == -1) { if (op != PM_LOCAL_CLEAR) if ((sts = build_dsotab()) < 0) return sts; } switch (op) { case PM_LOCAL_ADD: if ((dsotab = (__pmDSO *)realloc(dsotab, (numdso+1)*sizeof(__pmDSO))) == NULL) { __pmNoMem("__pmLocalPMDA realloc", (numdso+1)*sizeof(__pmDSO), PM_FATAL_ERR); /*NOTREACHED*/ } dsotab[numdso].domain = domain; if (name == NULL) { /* odd, will fail later at dlopen */ dsotab[numdso].name = NULL; } else { if ((dsotab[numdso].name = strdup(name)) == NULL) { sts = -oserror(); __pmNoMem("__pmLocalPMDA name", strlen(name)+1, PM_RECOV_ERR); return sts; } } if (init == NULL) { /* odd, will fail later at initialization call */ dsotab[numdso].init = NULL; } else { if ((dsotab[numdso].init = strdup(init)) == NULL) { sts = -oserror(); __pmNoMem("__pmLocalPMDA init", strlen(init)+1, PM_RECOV_ERR); return sts; } } dsotab[numdso].handle = NULL; numdso++; break; case PM_LOCAL_DEL: sts = PM_ERR_INDOM; for (i = 0; i < numdso; i++) { if ((domain != -1 && dsotab[i].domain == domain) || (name != NULL && strcmp(dsotab[i].name, name) == 0)) { if (dsotab[i].handle) { dlclose(dsotab[i].handle); dsotab[i].handle = NULL; } dsotab[i].domain = -1; sts = 0; } } break; case PM_LOCAL_CLEAR: for (i = 0; i < numdso; i++) { free(dsotab[i].name); free(dsotab[i].init); if (dsotab[i].handle) dlclose(dsotab[i].handle); } free(dsotab); dsotab = NULL; numdso = 0; break; default: sts = PM_ERR_CONV; break; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { if (sts != 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmLocalPMDA -> %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } fprintf(stderr, "Local Context PMDA Table"); if (numdso == 0) fprintf(stderr, " ... empty"); fputc('\n', stderr); for (i = 0; i < numdso; i++) { fprintf(stderr, PRINTF_P_PFX "%p [%d] domain=%d name=%s init=%s handle=" PRINTF_P_PFX "%p\n", &dsotab[i], i, dsotab[i].domain, dsotab[i].name, dsotab[i].init, dsotab[i].handle); } } #endif return sts; }
int __pmConnectPMCD(pmHostSpec *hosts, int nhosts, int ctxflags, __pmHashCtl *attrs) { int sts = -1; int fd = -1; /* Fd for socket connection to pmcd */ int *ports; int nports; int portIx; int version = -1; int proxyport; pmHostSpec *proxyhost; static int first_time = 1; static pmHostSpec proxy; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (first_time) { /* * One-trip check for use of pmproxy(1) in lieu of pmcd(1), * and to extract the optional environment variables ... * PMCD_PORT, PMPROXY_HOST and PMPROXY_PORT. * We also check for the presense of a certificate database * and load it up if either a user or system (global) DB is * found. */ first_time = 0; load_pmcd_ports(); load_proxy_hostspec(&proxy); } if (hosts[0].nports == 0) { nports = global_nports; ports = global_portlist; } else { nports = hosts[0].nports; ports = hosts[0].ports; } if (proxy.name == NULL && nhosts == 1) { const char *name = (const char *)hosts[0].name; /* * no proxy, connecting directly to pmcd */ PM_UNLOCK(__pmLock_libpcp); sts = -1; /* Try connecting via the local unix domain socket, if requested and supported. */ if (nports == PM_HOST_SPEC_NPORTS_LOCAL || nports == PM_HOST_SPEC_NPORTS_UNIX) { #if defined(HAVE_STRUCT_SOCKADDR_UN) if ((fd = __pmAuxConnectPMCDUnixSocket(name)) >= 0) { if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) { __pmCloseSocket(fd); } else sts = fd; portIx = -1; /* no port */ } #endif /* * If the connection failed, or is not supported, and the protocol was 'local:', * then try connecting to localhost via the default port(s). */ if (sts < 0) { if (nports == PM_HOST_SPEC_NPORTS_LOCAL) { name = "localhost"; nports = global_nports; ports = global_portlist; sts = -1; /* keep trying */ } else sts = -2; /* no more connection attempts. */ } } /* If still not connected, try via the given host name and ports, if requested. */ if (sts == -1) { for (portIx = 0; portIx < nports; portIx++) { if ((fd = __pmAuxConnectPMCDPort(name, ports[portIx])) >= 0) { if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) { __pmCloseSocket(fd); } else /* success */ break; } else sts = fd; } } if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=", hosts[0].name); for (portIx = 0; portIx < nports; portIx++) { if (portIx == 0) fprintf(stderr, "%d", ports[portIx]); else fprintf(stderr, ",%d", ports[portIx]); } fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif return sts; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { if (portIx >= 0) { fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=%d fd=%d PDU version=%u\n", hosts[0].name, ports[portIx], fd, __pmVersionIPC(fd)); } else { fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection path=%s fd=%d PDU version=%u\n", hosts[0].name, name, fd, __pmVersionIPC(fd)); } __pmPrintIPC(); } #endif return fd; } /* * connecting to pmproxy, and then to pmcd ... not a direct * connection to pmcd */ proxyhost = (nhosts > 1) ? &hosts[1] : &proxy; proxyport = (proxyhost->nports > 0) ? proxyhost->ports[0] : PROXY_PORT; for (portIx = 0; portIx < nports; portIx++) { fd = __pmAuxConnectPMCDPort(proxyhost->name, proxyport); if (fd < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): proxy to %s port=%d failed: %s \n", hosts[0].name, proxyhost->name, proxyport, pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); } #endif PM_UNLOCK(__pmLock_libpcp); return fd; } if ((sts = version = negotiate_proxy(fd, hosts[0].name, ports[portIx])) < 0) __pmCloseSocket(fd); else if ((sts = __pmConnectHandshake(fd, proxyhost->name, ctxflags, attrs)) < 0) __pmCloseSocket(fd); else /* success */ break; } if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): proxy connection to %s port=", hosts[0].name, proxyhost->name); for (portIx = 0; portIx < nports; portIx++) { if (portIx == 0) fprintf(stderr, "%d", ports[portIx]); else fprintf(stderr, ",%d", ports[portIx]); } fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif PM_UNLOCK(__pmLock_libpcp); return sts; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "__pmConnectPMCD(%s): proxy connection host=%s port=%d fd=%d version=%d\n", hosts[0].name, proxyhost->name, ports[portIx], fd, version); } #endif PM_UNLOCK(__pmLock_libpcp); return fd; }
/* * Parse a command line string that encodes arguments to __pmLocalPMDA(), * then call __pmLocalPMDA(). * * The syntax for the string is 1 to 4 fields separated by colons: * - op ("add" for add, "del" for delete, "clear" for clear) * - domain (PMDA's PMD) * - path (path to DSO PMDA) * - init (name of DSO's initialization routine) */ char * __pmSpecLocalPMDA(const char *spec) { int op; int domain = -1; char *name = NULL; char *init = NULL; int sts; char *arg; char *sbuf; char *ap; if ((arg = sbuf = strdup(spec)) == NULL) { sts = -oserror(); __pmNoMem("__pmSpecLocalPMDA dup spec", strlen(spec)+1, PM_RECOV_ERR); return "strdup failed"; } if (strncmp(arg, "add", 3) == 0) { op = PM_LOCAL_ADD; ap = &arg[3]; } else if (strncmp(arg, "del", 3) == 0) { op = PM_LOCAL_DEL; ap = &arg[3]; } else if (strncmp(arg, "clear", 5) == 0) { op = PM_LOCAL_CLEAR; ap = &arg[5]; if (*ap == '\0') goto doit; else { free(sbuf); return "unexpected text after clear op in spec"; } } else { free(sbuf); return "bad op in spec"; } if (*ap != ',') { free(sbuf); return "expected , after op in spec"; } /* ap-> , after add or del */ arg = ++ap; if (*ap == '\0') { free(sbuf); return "missing domain in spec"; } else if (*ap != ',') { /* ap-> domain */ domain = (int)strtol(arg, &ap, 10); if ((*ap != ',' && *ap != '\0') || domain < 0 || domain > 510) { free(sbuf); return "bad domain in spec"; } if (*ap != '\0') /* skip , after domain */ ap++; } else { if (op != PM_LOCAL_DEL) { /* found ,, where ,domain, expected */ free(sbuf); return "missing domain in spec"; } ap++; } /* ap -> char after , following domain */ if (*ap == ',') { /* no path, could have init (not useful but possible!) */ ap++; if (*ap != '\0') init = ap; } else if (*ap != '\0') { /* have path and possibly init */ name = ap; while (*ap != ',' && *ap != '\0') ap++; if (*ap == ',') { *ap++ = '\0'; if (*ap != '\0') init = ap; else { if (op != PM_LOCAL_DEL) { /* found end of string where init-routine expected */ free(sbuf); return "missing init-routine in spec"; } } } else { if (op != PM_LOCAL_DEL) { /* found end of string where init-routine expected */ free(sbuf); return "missing init-routine in spec"; } } } else { if (op != PM_LOCAL_DEL) { /* found end of string where path expected */ free(sbuf); return "missing dso-path in spec"; } } if (domain == -1 && name == NULL) { free(sbuf); return "missing domain and dso-path in spec"; } doit: sts = __pmLocalPMDA(op, domain, name, init); if (sts < 0) { /* see thread-safe note at the head of this file */ static char buffer[256]; char errmsg[PM_MAXERRMSGLEN]; snprintf(buffer, sizeof(buffer), "__pmLocalPMDA: %s", pmErrStr_r(sts, errmsg, sizeof(errmsg))); free(sbuf); return buffer; } free(sbuf); return NULL; }
/* * 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; }