static void posix_formatter(char *var, char *prefix, char *val) { /* +40 bytes for max PCP env variable name */ char envbuf[MAXPATHLEN+40]; char *vp; char *vend; snprintf(envbuf, sizeof(envbuf), "%s=", var); vend = &val[strlen(val)-1]; if (val[0] == *vend && (val[0] == '\'' || val[0] == '"')) { /* * have quoted value like "gawk --posix" for $PCP_AWK_PROG ... * strip quotes */ vp = &val[1]; vend--; } else vp = val; strncat(envbuf, vp, vend-vp+1); envbuf[strlen(var)+1+vend-vp+1+1] = '\0'; PM_LOCK(__pmLock_libpcp); putenv(strdup(envbuf)); PM_UNLOCK(__pmLock_libpcp); (void)prefix; }
static int ping_pmcd(int ctx) { /* * We're going to leveraging an existing host context, just make sure * pmcd is still alive at the other end ... we don't have a "ping" * pdu, but sending a pmDesc request for PM_ID_NULL is pretty much * the same thing ... expect a PM_ERR_PMID error PDU back. * The code here is based on pmLookupDesc() with some short cuts * because we know it is a host context and we already hold the * __pmLock_libpcp lock */ __pmContext *ctxp = contexts[ctx]; int sts; PM_LOCK(ctxp->c_pmcd->pc_lock); if ((sts = __pmSendDescReq(ctxp->c_pmcd->pc_fd, ctx, PM_ID_NULL)) >= 0) { int pinpdu; __pmPDU *pb; pinpdu = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (pinpdu == PDU_ERROR) __pmDecodeError(pb, &sts); if (pinpdu > 0) __pmUnpinPDUBuf(pb); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); if (sts != PM_ERR_PMID) { /* pmcd is not well on this context ... */ return 0; } return 1; }
const struct timeval * __pmDefaultRequestTimeout(void) { static int done_default = 0; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (!done_default) { char *timeout_str; char *end_ptr; if ((timeout_str = getenv("PMCD_REQUEST_TIMEOUT")) != NULL) { def_timeout = strtod(timeout_str, &end_ptr); if (*end_ptr != '\0' || def_timeout < 0.0) { __pmNotifyErr(LOG_WARNING, "ignored bad PMCD_REQUEST_TIMEOUT = '%s'\n", timeout_str); } else { __pmtimevalFromReal(def_timeout, &def_wait); } } done_default = 1; } PM_UNLOCK(__pmLock_libpcp); return (&def_wait); }
int __pmSecureServerCertificateSetup(const char *db, const char *passwd, const char *cert_nickname) { PM_INIT_LOCKS(); PM_LOCK(secureserver_lock); /* Configure optional (cmdline) password file in case DB locked */ secure_server.password_file = passwd; /* * Configure location of the NSS database with a sane default. * For servers, we default to the shared (sql) system-wide database. * If command line db specified, pass it directly through - allowing * any old database format, at the users discretion. */ if (db) { /* shortened-buffer-size (-2) guarantees null-termination */ strncpy(secure_server.database_path, db, MAXPATHLEN-2); } if (cert_nickname) { strncpy(secure_server.cert_nickname, cert_nickname, MAX_CERT_NAME_LENGTH-2); } else { strncpy(secure_server.cert_nickname, SECURE_SERVER_CERTIFICATE, MAX_CERT_NAME_LENGTH-2); } PM_UNLOCK(secureserver_lock); return 0; }
int main(int argc, char **argv) { char *p; struct timeval delta = { 1, 0 }; if (argc != 2) _usage(); __pmAFregister(&delta, NULL, timeout); #ifdef DBG_TRACE_DESPERATE pmDebug |= DBG_TRACE_DESPERATE; #endif for (p = argv[1]; *p; p++) { switch (*p) { case 'i': fprintf(stderr, "initialize\n"); PM_INIT_LOCKS(); break; case 'l': fprintf(stderr, "lock\n"); PM_LOCK(__pmLock_libpcp); break; case 'u': fprintf(stderr, "unlock\n"); PM_UNLOCK(__pmLock_libpcp); break; default: _usage(); } } return 0; }
void __pmConfig(__pmConfigCallback formatter) { /* * Scan ${PCP_CONF-$PCP_DIR/etc/pcp.conf} and put all PCP config * variables found therein into the environment. */ FILE *fp; char confpath[32]; char dir[MAXPATHLEN]; char var[MAXPATHLEN]; char *prefix; char *conf; char *val; char *p; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); prefix = getenv("PCP_DIR"); if ((conf = getenv("PCP_CONF")) == NULL) { strncpy(confpath, "/etc/pcp.conf", sizeof(confpath)); if (prefix == NULL) conf = __pmNativePath(confpath); else { snprintf(dir, sizeof(dir), "%s%s", prefix, __pmNativePath(confpath)); conf = dir; } } if (access((const char *)conf, R_OK) < 0 || (fp = fopen(conf, "r")) == (FILE *)NULL) { char errmsg[PM_MAXERRMSGLEN]; pmprintf("FATAL PCP ERROR: could not open config file \"%s\" : %s\n", conf, osstrerror_r(errmsg, sizeof(errmsg))); pmprintf("You may need to set PCP_CONF or PCP_DIR in your environment.\n"); pmflush(); PM_UNLOCK(__pmLock_libpcp); exit(1); } while (fgets(var, sizeof(var), fp) != NULL) { if (var[0] == '#' || (p = strchr(var, '=')) == NULL) continue; *p = '\0'; val = p+1; if ((p = strrchr(val, '\n')) != NULL) *p = '\0'; if ((p = getenv(var)) != NULL) val = p; else formatter(var, prefix, val); if (pmDebug & DBG_TRACE_CONFIG) fprintf(stderr, "pmGetConfig: (init) %s=%s\n", var, val); } fclose(fp); PM_UNLOCK(__pmLock_libpcp); }
int __pmUnpinPDUBuf(void *handle) { bufctl_t *pcp, pcp_search; void *bcp; assert(((__psint_t)handle % sizeof(int)) == 0); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); /* * Initialize a dummy bufctl_t to use only as search key; * only its bc_buf & bc_size fields need to be set, as that's * all that bufctl_t_compare will look at. */ pcp_search.bc_buf = handle; pcp_search.bc_size = 1; bcp = tfind(&pcp_search, &buf_tree, &bufctl_t_compare); /* * NB: don't release the lock until final disposition of this object; * we don't want to play TOCTOU. */ if (likely(bcp != NULL)) { pcp = *(bufctl_t **)bcp; } else { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) { fprintf(stderr, "__pmUnpinPDUBuf(" PRINTF_P_PFX "%p) -> fails\n", handle); pdubufdump(); } #endif PM_UNLOCK(__pmLock_libpcp); return 0; } #ifdef PCP_DEBUG if (unlikely(pmDebug & DBG_TRACE_PDUBUF)) fprintf(stderr, "__pmUnpinPDUBuf(" PRINTF_P_PFX "%p) -> pdubuf=" PRINTF_P_PFX "%p, pincnt=%d\n", handle, pcp->bc_buf, pcp->bc_pincnt - 1); #endif assert((&pcp->bc_buf[0] <= (char*)handle) && ((char*)handle < &pcp->bc_buf[pcp->bc_size])); if (likely(--pcp->bc_pincnt == 0)) { tdelete(pcp, &buf_tree, &bufctl_t_compare); PM_UNLOCK(__pmLock_libpcp); free(pcp); } else { PM_UNLOCK(__pmLock_libpcp); } return 1; }
/* * On success, context is locked and caller should unlock it */ __pmContext * __pmHandleToPtr(int handle) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (handle < 0 || handle >= contexts_len || contexts[handle]->c_type == PM_CONTEXT_FREE) { PM_UNLOCK(__pmLock_libpcp); return NULL; } else { __pmContext *sts; sts = contexts[handle]; PM_UNLOCK(__pmLock_libpcp); PM_LOCK(sts->c_lock); return sts; } }
/* * For native Win32 console tools, we need to translate the paths * used in scripts to native paths with PCP_DIR prefix prepended. * * For Win32 MSYS shell usage, we need to translate the paths * used in scripts to paths with PCP_DIR prefix prepended AND * drive letter path mapping done AND posix-style separators. * * Choose which way to go based on our environment (SHELL). */ static int posix_style(void) { char *s; int sts; PM_LOCK(__pmLock_libpcp); s = getenv("SHELL"); sts = (s && strncmp(s, "/bin/", 5) == 0); PM_UNLOCK(__pmLock_libpcp); return sts; }
static char * pmgetconfig(const char *name, int fatal) { /* * state controls one-trip initialization, and recursion guard * for pathological failures in initialization */ static int state = 0; char *val; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (state == 0) { state = 1; PM_UNLOCK(__pmLock_libpcp); __pmconfig(__pmNativeConfig, fatal); PM_LOCK(__pmLock_libpcp); state = 2; } else if (state == 1) { /* recursion from error in __pmConfig() ... no value is possible */ PM_UNLOCK(__pmLock_libpcp); if (pmDebug & DBG_TRACE_CONFIG) fprintf(stderr, "pmgetconfig: %s= ... recursion error\n", name); if (!fatal) return NULL; val = ""; return val; } PM_UNLOCK(__pmLock_libpcp); if ((val = getenv(name)) == NULL) { if (!fatal) return NULL; val = ""; } if (pmDebug & DBG_TRACE_CONFIG) fprintf(stderr, "pmgetconfig: %s=%s\n", name, val); return val; }
static void AFsetup(void) { PM_LOCK(__pmLock_libpcp); if (afsetup) { PM_UNLOCK(__pmLock_libpcp); return; } afsetup = 1; afblock = CreateMutex(NULL, FALSE, NULL); aftimer = CreateWaitableTimer(NULL, TRUE, NULL); PM_UNLOCK(__pmLock_libpcp); }
static int __pmSecureServerNegotiation(int fd, int *strength) { PRIntervalTime timer; PRFileDesc *sslsocket; SECStatus secsts; int enabled, keysize; int msec; sslsocket = (PRFileDesc *)__pmGetSecureSocket(fd); if (!sslsocket) return PM_ERR_IPC; PM_INIT_LOCKS(); PM_LOCK(secureserver_lock); secsts = SSL_ConfigSecureServer(sslsocket, secure_server.certificate, secure_server.private_key, secure_server.certificate_KEA); PM_UNLOCK(secureserver_lock); if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Unable to configure secure server: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); return PM_ERR_IPC; } secsts = SSL_ResetHandshake(sslsocket, PR_TRUE /*server*/); if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Unable to reset secure handshake: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); return PM_ERR_IPC; } /* Server initiates handshake now to get early visibility of errors */ msec = __pmConvertTimeout(TIMEOUT_DEFAULT); timer = PR_MillisecondsToInterval(msec); secsts = SSL_ForceHandshakeWithTimeout(sslsocket, timer); if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Unable to force secure handshake: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); return PM_ERR_IPC; } secsts = SSL_SecurityStatus(sslsocket, &enabled, NULL, &keysize, NULL, NULL, NULL); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); *strength = (enabled > 0) ? keysize : DEFAULT_SECURITY_STRENGTH; return 0; }
void __pmConnectGetPorts(pmHostSpec *host) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); load_pmcd_ports(); if (__pmAddHostPorts(host, global_portlist, global_nports) < 0) { __pmNotifyErr(LOG_WARNING, "__pmConnectGetPorts: portlist dup failed, " "using default PMCD_PORT (%d)\n", SERVER_PORT); host->ports[0] = SERVER_PORT; host->nports = 1; } PM_UNLOCK(__pmLock_libpcp); }
static void pdubufdump(void) { /* * There is no longer a pdubuf free list, ergo no * fprintf(stderr, " free pdubuf[size]:\n"); */ PM_LOCK(__pmLock_libpcp); if (buf_tree != NULL) { fprintf(stderr, " pinned pdubuf[size](pincnt):"); twalk(buf_tree, &pdubufdump1); fprintf(stderr, "\n"); } PM_UNLOCK(__pmLock_libpcp); }
int __pmPtrToHandle(__pmContext *ctxp) { int i; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (i = 0; i < contexts_len; i++) { if (ctxp == contexts[i]) { PM_UNLOCK(__pmLock_libpcp); return i; } } PM_UNLOCK(__pmLock_libpcp); return PM_CONTEXT_UNDEF; }
void __pmCountPDUBuf(int need, int *alloc, int *free) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); pdu_bufcnt_need = need; pdu_bufcnt = 0; twalk(buf_tree, &pdubufcount); *alloc = pdu_bufcnt; *free = 0; /* We don't retain freed nodes. */ PM_UNLOCK(__pmLock_libpcp); }
static void waitawhile(__pmPMCDCtl *ctl) { /* * after failure, compute delay before trying again ... */ PM_LOCK(__pmLock_libpcp); if (n_backoff == 0) { char *q; /* first time ... try for PMCD_RECONNECT_TIMEOUT from env */ if ((q = getenv("PMCD_RECONNECT_TIMEOUT")) != NULL) { char *pend; char *p; int val; for (p = q; *p != '\0'; ) { val = (int)strtol(p, &pend, 10); if (val <= 0 || (*pend != ',' && *pend != '\0')) { __pmNotifyErr(LOG_WARNING, "pmReconnectContext: ignored bad PMCD_RECONNECT_TIMEOUT = '%s'\n", q); n_backoff = 0; if (backoff != NULL) free(backoff); break; } if ((backoff = (int *)realloc(backoff, (n_backoff+1) * sizeof(backoff[0]))) == NULL) { __pmNoMem("pmReconnectContext", (n_backoff+1) * sizeof(backoff[0]), PM_FATAL_ERR); } backoff[n_backoff++] = val; if (*pend == '\0') break; p = &pend[1]; } } if (n_backoff == 0) { /* use default */ n_backoff = 5; backoff = def_backoff; } } PM_UNLOCK(__pmLock_libpcp); if (ctl->pc_timeout == 0) ctl->pc_timeout = 1; else if (ctl->pc_timeout < n_backoff) ctl->pc_timeout++; ctl->pc_again = time(NULL) + backoff[ctl->pc_timeout-1]; }
static void dos_formatter(char *var, char *prefix, char *val) { char envbuf[MAXPATHLEN]; int msys = posix_style(); if (prefix && dos_rewrite_path(var, val, msys)) { char *p = msys ? msys_native_path(prefix) : prefix; snprintf(envbuf, sizeof(envbuf), "%s=%s%s", var, p, val); } else { snprintf(envbuf, sizeof(envbuf), "%s=%s", var, val); } PM_LOCK(__pmLock_libpcp); putenv(strdup(envbuf)); PM_UNLOCK(__pmLock_libpcp); }
__pmPDU * __pmFindPDUBuf(int need) { bufctl_t *pcp; void *bcp; PM_INIT_LOCKS(); if (unlikely(need < 0)) { /* special diagnostic case ... dump buffer state */ #ifdef PCP_DEBUG fprintf(stderr, "__pmFindPDUBuf(DEBUG)\n"); pdubufdump(); #endif return NULL; } if ((pcp = (bufctl_t *)malloc(sizeof(*pcp) + need)) == NULL) { return NULL; } pcp->bc_pincnt = 1; pcp->bc_size = need; pcp->bc_buf = ((char *)pcp) + sizeof(*pcp); PM_LOCK(__pmLock_libpcp); /* Insert the node in the tree. */ bcp = tsearch((void *)pcp, &buf_tree, &bufctl_t_compare); if (unlikely(bcp == NULL)) { /* ENOMEM */ PM_UNLOCK(__pmLock_libpcp); free(pcp); return NULL; } PM_UNLOCK(__pmLock_libpcp); #ifdef PCP_DEBUG if (unlikely(pmDebug & DBG_TRACE_PDUBUF)) { fprintf(stderr, "__pmFindPDUBuf(%d) -> " PRINTF_P_PFX "%p\n", need, pcp->bc_buf); pdubufdump(); } #endif return (__pmPDU *)pcp->bc_buf; }
int pmWhichContext(void) { /* * return curcontext, provided it is defined */ int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (PM_TPD(curcontext) > PM_CONTEXT_UNDEF) sts = PM_TPD(curcontext); else sts = PM_ERR_NOCONTEXT; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmWhichContext() -> %d, cur=%d\n", sts, PM_TPD(curcontext)); #endif PM_UNLOCK(__pmLock_libpcp); return sts; }
void __pmSecureServerShutdown(void) { PM_INIT_LOCKS(); PM_LOCK(secureserver_lock); if (secure_server.certificate) { CERT_DestroyCertificate(secure_server.certificate); secure_server.certificate = NULL; } if (secure_server.private_key) { SECKEY_DestroyPrivateKey(secure_server.private_key); secure_server.private_key = NULL; } if (secure_server.ssl_session_cache_setup) { SSL_ShutdownServerSessionIDCache(); secure_server.ssl_session_cache_setup = 0; } if (secure_server.initialized) { NSS_Shutdown(); secure_server.initialized = 0; } PM_UNLOCK(secureserver_lock); }
int __pmSecureServerSetup(const char *db, const char *passwd) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); /* Configure optional (cmdline) password file in case DB locked */ secure_server.password_file = passwd; /* * Configure location of the NSS database with a sane default. * For servers, we default to the shared (sql) system-wide database. * If command line db specified, pass it directly through - allowing * any old database format, at the users discretion. */ if (db) { /* shortened-buffer-size (-2) guarantees null-termination */ strncpy(secure_server.database_path, db, MAXPATHLEN-2); } PM_UNLOCK(__pmLock_libpcp); return 0; }
static char * certificate_database_password(PK11SlotInfo *info, PRBool retry, void *arg) { size_t length = MAX_NSSDB_PASSWORD_LENGTH; char *password = NULL; char passfile[MAXPATHLEN]; int sts; (void)arg; (void)info; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); passfile[0] = '\0'; if (secure_server.password_file) strncpy(passfile, secure_server.password_file, MAXPATHLEN-1); passfile[MAXPATHLEN-1] = '\0'; PM_UNLOCK(__pmLock_libpcp); if (passfile[0] == '\0') { __pmNotifyErr(LOG_ERR, "Password sought but no password file given"); return NULL; } if (retry) { __pmNotifyErr(LOG_ERR, "Retry attempted during password extraction"); return NULL; /* no soup^Wretries for you */ } sts = secure_file_contents(passfile, &password, &length); if (sts < 0) { __pmNotifyErr(LOG_ERR, "Cannot read password file \"%s\": %s", passfile, pmErrStr(sts)); return NULL; } return password; }
int __pmSecureServerInit(void) { const PRUint16 *cipher; SECStatus secsts; int pathSpecified; int sts = 0; PM_INIT_LOCKS(); PM_LOCK(secureserver_lock); /* Only attempt this once. */ if (secure_server.initialized) goto done; secure_server.initialized = 1; if (PR_Initialized() != PR_TRUE) PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); /* Configure optional (cmdline) password file in case DB locked */ PK11_SetPasswordFunc(certificate_database_password); /* * Configure location of the NSS database with a sane default. * For servers, we default to the shared (sql) system-wide database. * If command line db specified, pass it directly through - allowing * any old database format, at the users discretion. */ if (!secure_server.database_path[0]) { const char *path; pathSpecified = 0; path = serverdb(secure_server.database_path, MAXPATHLEN, "sql:"); /* this is the default case on some platforms, so no log spam */ if (access(path, R_OK|X_OK) < 0) { if (pmDebugOptions.context) pmNotifyErr(LOG_INFO, "Cannot access system security database: %s", secure_server.database_path); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } else pathSpecified = 1; /* * pmproxy acts as both a client and server. Since the * server init path happens first, the db previously * got opened readonly. Instead try to open RW. * Fallback if there is an error. */ secsts = NSS_InitReadWrite(secure_server.database_path); if( secsts != SECSuccess ) secsts = NSS_Init(secure_server.database_path); if (secsts != SECSuccess && !pathSpecified) { /* fallback, older versions of NSS do not support sql: */ serverdb(secure_server.database_path, MAXPATHLEN, ""); secsts = NSS_Init(secure_server.database_path); } if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Cannot setup certificate DB (%s): %s", secure_server.database_path, pmErrStr(__pmSecureSocketsError(PR_GetError()))); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */ for (cipher = SSL_GetImplementedCiphers(); *cipher != 0; ++cipher) SSL_CipherPolicySet(*cipher, SSL_ALLOWED); /* Configure SSL session cache for multi-process server, using defaults */ secsts = SSL_ConfigMPServerSIDCache(1, 0, 0, NULL); if (secsts != SECSuccess) { pmNotifyErr(LOG_ERR, "Unable to configure SSL session ID cache: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } else { secure_server.ssl_session_cache_setup = 1; } /* * Iterate over any/all PCP Collector nickname certificates, * seeking one valid certificate. No-such-nickname is not an * error (not configured by admin at all) but anything else is. */ CERTCertList *certlist; CERTCertDBHandle *nssdb = CERT_GetDefaultCertDB(); CERTCertificate *dbcert = PK11_FindCertFromNickname(secure_server.cert_nickname, NULL); if (dbcert) { PRTime now = PR_Now(); SECItem *name = &dbcert->derSubject; CERTCertListNode *node; certlist = CERT_CreateSubjectCertList(NULL, nssdb, name, now, PR_FALSE); if (certlist) { for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node, certlist); node = CERT_LIST_NEXT (node)) { if (pmDebugOptions.context) __pmDumpCertificate(stderr, secure_server.cert_nickname, node->cert); if (!__pmValidCertificate(nssdb, node->cert, now)) continue; secure_server.certificate_verified = 1; break; } CERT_DestroyCertList(certlist); } if (secure_server.certificate_verified) { secure_server.certificate_KEA = NSS_FindCertKEAType(dbcert); secure_server.private_key = PK11_FindKeyByAnyCert(dbcert, NULL); if (!secure_server.private_key) { pmNotifyErr(LOG_ERR, "Unable to extract %s private key", secure_server.cert_nickname); CERT_DestroyCertificate(dbcert); secure_server.certificate_verified = 0; sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } else { pmNotifyErr(LOG_ERR, "Unable to find a valid %s", secure_server.cert_nickname); CERT_DestroyCertificate(dbcert); sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } } if (! secure_server.certificate_verified) { if (pmDebugOptions.context) { pmNotifyErr(LOG_INFO, "No valid %s in security database: %s", secure_server.cert_nickname, secure_server.database_path); } sts = -EOPNOTSUPP; /* not fatal - just no secure connections */ secure_server.init_failed = 1; goto done; } secure_server.certificate = dbcert; secure_server.init_failed = 0; sts = 0; done: PM_UNLOCK(secureserver_lock); return sts; }
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; }
/* 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 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; }
char * pmErrStr_r(int code, char *buf, int buflen) { int i; #ifndef IS_MINGW static int first = 1; static char *unknown = NULL; #else static char unknown[] = "Unknown error"; #endif if (code == 0) { strncpy(buf, "No error", buflen); buf[buflen-1] = '\0'; return buf; } /* * Is the code from a library wrapped by libpcp? (e.g. NSS/SSL/SASL) * By good fortune, these libraries are using error codes that do not * overlap - by design for NSS/SSL/NSPR, and by sheer luck with SASL. */ if (code < PM_ERR_NYI) { #ifdef HAVE_SECURE_SOCKETS #define DECODE_SECURE_SOCKETS_ERROR(c) ((c) - PM_ERR_NYI) /* negative */ #define DECODE_SASL_SPECIFIC_ERROR(c) ((c) < -1000 ? 0 : (c)) int error = DECODE_SECURE_SOCKETS_ERROR(code); if (DECODE_SASL_SPECIFIC_ERROR(error)) { PM_LOCK(__pmLock_extcall); pmsprintf(buf, buflen, "Authentication - %s", sasl_errstring(error, NULL, NULL)); /* THREADSAFE */ PM_UNLOCK(__pmLock_extcall); } else strncpy(buf, PR_ErrorToString(error, PR_LANGUAGE_EN), buflen); buf[buflen-1] = '\0'; return buf; #endif } #ifndef IS_MINGW PM_LOCK(err_lock); if (first) { /* * reference message for an unrecognized error code. * For IRIX, strerror() returns NULL in this case. */ strerror_x(-1, buf, buflen); if (buf[0] != '\0') { /* * For Linux et al, strip the last word, expected to be the * error number as in ... * Unknown error -1 * or * Unknown error 4294967295 */ char *sp = strrchr(buf, ' '); char *p; if (sp != NULL) { sp++; if (*sp == '-') sp++; for (p = sp; *p != '\0'; p++) { if (!isdigit((int)*p)) break; } if (*p == '\0') { PM_FAULT_POINT("libpcp/" __FILE__ ":1", PM_FAULT_ALLOC); *sp = '\0'; if ((unknown = strdup(buf)) != NULL) unknown[sp - buf] = '\0'; } } } first = 0; } PM_UNLOCK(err_lock); if (code < 0 && code > -PM_ERR_BASE) { /* intro(2) / errno(3) errors, maybe */ strerror_x(-code, buf, buflen); if (unknown == NULL) { if (buf[0] != '\0') return buf; } else { /* The intention here is to catch variants of "Unknown * error XXX" - in this case we're going to fail the * stncmp() below, fall through and return a pcp error * message, otherwise return the system error message */ if (strncmp(buf, unknown, strlen(unknown)) != 0) return buf; } } #else /* WIN32 */ if (code > -PM_ERR_BASE || code < -PM_ERR_NYI) { const char *bp; if ((bp = wsastrerror(-code)) != NULL) { strncpy(buf, bp, buflen); buf[buflen-1] = '\0'; } else { /* No strerror_r in MinGW, so need to lock */ char *tbp; PM_LOCK(__pmLock_extcall); tbp = strerror(-code); /* THREADSAFE */ strncpy(buf, tbp, buflen); buf[buflen-1] = '\0'; PM_UNLOCK(__pmLock_extcall); } if (strncmp(buf, unknown, strlen(unknown)) != 0) return buf; } #endif for (i = 0; errtab[i].err; i++) { if (errtab[i].err == code) { strncpy(buf, errtab[i].errmess, buflen); buf[buflen-1] = '\0'; return buf; } } /* failure */ pmsprintf(buf, buflen, BADCODE, code); return buf; }
static void foo(FILE *f, char *fn, int i, void *closure) { int sts; int numnames; int j; int leaf; pmID pmids[NMETRIC]; char **names; char *name; int *stsset; char strbuf[20]; if ((sts = pmLookupName(NMETRIC-i, &namelist[i], pmids)) < 0) { if (sts != PM_ERR_NONLEAF) { fprintf(f, "%s: %s ...: pmLookupName Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } } for (j = i; j < NMETRIC; j++) { if (pmids[j-i] != pmidlist[j]) { fprintf(f, "%s: %s: Botch: expecting %s", fn, namelist[j], pmIDStr_r(pmidlist[j], strbuf, sizeof(strbuf))); fprintf(f, ", got %s\n", pmIDStr_r(pmids[j-i], strbuf, sizeof(strbuf))); pthread_exit("botch"); } } fprintf(f, "%s: %s ... pmLookupName OK\n", fn, namelist[i]); fprintf(f, "%s: %s", fn, namelist[i]); if (pmidlist[i] != PM_ID_NULL) { /* leaf node in PMNS */ if ((numnames = pmNameAll(pmidlist[i], &names)) < 0) { fprintf(f, "\n%s: %s ...: pmNameAll Error: %s\n", fn, namelist[i], pmErrStr(numnames)); pthread_exit("botch"); } for (j = 0; j < numnames; j++) { if (strcmp(names[j], namelist[i]) == 0) break; } if (j == numnames) { fprintf(f, "\n%s: %s: Botch: expecting %s, got {", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)), namelist[i]); __pmPrintMetricNames(f, numnames, names, ","); fprintf(f, "}\n"); pthread_exit("botch"); } fprintf(f, " pmNameAll OK"); if ((sts = pmNameID(pmidlist[i], &name)) < 0) { fprintf(f, "\n%s: %s ...: pmNameID Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } for (j = 0; j < numnames; j++) { if (strcmp(name, names[j]) == 0) break; } if (j == numnames) { fprintf(f, "\n%s: %s: Botch: expecting one of {", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); __pmPrintMetricNames(f, numnames, names, ","); fprintf(f, "}, got %s\n", name); pthread_exit("botch"); } free(names); free(name); fprintf(f, " pmNameID OK"); } else { /* non-leaf node in PMNS */ int keep = 0; if ((sts = pmGetChildrenStatus(namelist[i], &names, &stsset)) < 0) { fprintf(f, "\n%s: %s ...: pmGetChildrenStatus Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } leaf = 0; for (j = 0; j < sts; j++) { if (stsset[j] == PMNS_LEAF_STATUS) leaf++; } PM_LOCK(chn_lock); if (leaf_chn[i] == -1) { leaf_chn[i] = leaf; nonleaf_chn[i] = sts - leaf; chn[i] = names; keep = 1; } else { if (leaf != leaf_chn[i] || sts - leaf != nonleaf_chn[i]) { fprintf(f, "\n%s: %s: Botch: expecting %d leaf & %d non-leaf, got %d leaf & %d non-leaf\n", fn, namelist[i], leaf_chn[i], nonleaf_chn[i], leaf, sts - leaf); pthread_exit("botch"); } for (j = 0; j < sts; j++) { if (strcmp(chn[i][j], names[j]) != 0) { fprintf(f, "\n%s: %s: Botch: child[%d] expecting %s, got %s\n", fn, namelist[i], j, chn[i][j], names[j]); PM_UNLOCK(chn_lock); pthread_exit("botch"); } } } if (keep == 0) { free(names); names = NULL; /* silence coverity */ } free(stsset); fprintf(f, " pmGetChildrenStatus OK"); if ((sts = pmGetChildren(namelist[i], &names)) < 0) { fprintf(f, "\n%s: %s ...: pmGetChildren Error: %s\n", fn, namelist[i], pmErrStr(sts)); PM_UNLOCK(chn_lock); pthread_exit("botch"); } if (sts != leaf_chn[i] + nonleaf_chn[i]) { fprintf(f, "\n%s: %s: Botch: expecting %d children, got %d\n", fn, namelist[i], leaf_chn[i] + nonleaf_chn[i], sts); PM_UNLOCK(chn_lock); pthread_exit("botch"); } for (j = 0; j < sts; j++) { if (strcmp(chn[i][j], names[j]) != 0) { fprintf(f, "\n%s: %s: Botch: child[%d] expecting %s, got %s\n", fn, namelist[i], j, chn[i][j], names[j]); PM_UNLOCK(chn_lock); pthread_exit("botch"); } } PM_UNLOCK(chn_lock); free(names); fprintf(f, " pmGetChildren OK"); *((int *)closure) = 0; if ((sts = pmTraversePMNS_r(namelist[i], dometric, closure)) < 0) { fprintf(f, "\n%s: %s ...: pmTraversePMNS_r Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } if (sum_traverse[i] != *((int *)closure)) { fprintf(f, "\n%s: %s: Botch: sum strlen(descendent names) expecting %d, got %d\n", fn, namelist[i], sum_traverse[i], *((int *)closure)); pthread_exit("botch"); } fprintf(f, " pmTraversePMNS_r OK"); } fputc('\n', f); }
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; }