/* * called before regular exit() or as atexit() handler */ static void cleanup() { if (connmode == CONN_DSO) closedso(); else if (connmode == CONN_DAEMON) closepmda(); connmode = NO_CONN; }
void opendso(char *dso, char *init, int domain) { #ifdef HAVE_DLOPEN struct stat buf; unsigned int challenge; dispatch.status = -1; if (stat(dso, &buf) < 0) { fprintf(stderr, "opendso: %s: %s\n", dso, osstrerror()); return; } closedso(); /* * RTLD_NOW would be better in terms of detecting unresolved symbols * now, rather than taking a SEGV later ... but various combinations * of dynamic and static libraries used to create the DSO PMDA, * combined with hiding symbols in the DSO PMDA may result in benign * unresolved symbols remaining and the dlopen() would fail under * these circumstances. */ handle = dlopen(dso, RTLD_LAZY); if (handle == NULL) { printf("Error attaching DSO \"%s\"\n", dso); printf("%s\n\n", dlerror()); } else { void (*initp)(pmdaInterface *); initp = (void (*)(pmdaInterface *))dlsym(handle, init); if (initp == NULL) { printf("Error: couldn't find init function \"%s\" in DSO \"%s\"\n", init, dso); dlclose(handle); } else { /* * 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; dispatch.comm.pmda_interface = challenge; dispatch.comm.pmapi_version = ~PMAPI_VERSION; dispatch.comm.flags = 0; dispatch.status = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) fprintf(stderr, "DSO init %s->"PRINTF_P_PFX"%p() domain=%d challenge: pmda_interface=0x%x pmapi_version=%d\n", init, initp, dispatch.domain, dispatch.comm.pmda_interface, (~dispatch.comm.pmapi_version) & 0xff); #endif dispatch.domain = domain; (*initp)(&dispatch); if (dispatch.status != 0) { printf("Error: initialization routine \"%s\" failed in DSO \"%s\": %s\n", init, dso, pmErrStr(dispatch.status)); dispatch.status = -1; dlclose(handle); } else { if (dispatch.comm.pmda_interface < PMDA_INTERFACE_2 || dispatch.comm.pmda_interface > PMDA_INTERFACE_LATEST) { printf("Error: Unsupported PMDA interface version %d returned by DSO \"%s\"\n", dispatch.comm.pmda_interface, dso); dispatch.status = -1; dlclose(handle); } if (dispatch.comm.pmapi_version != PMAPI_VERSION_2) { printf("Error: Unsupported PMAPI version %d returned by DSO \"%s\"\n", dispatch.comm.pmapi_version, dso); dispatch.status = -1; dlclose(handle); } } if (dispatch.status == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { fprintf(stderr, "DSO has domain=%d", dispatch.domain); fprintf(stderr, " pmda_interface=%d pmapi_version=%d\n", dispatch.comm.pmda_interface, dispatch.comm.pmapi_version); } #endif dsoname = strdup(dso); connmode = CONN_DSO; reset_profile(); if (myPmdaName != NULL) free(myPmdaName); myPmdaName = strdup(dso); /* * set here once and used by all subsequent calls into the * PMDA */ if (dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dispatch.version.four.ext->e_context = 0; } } } #else /* ! HAVE_DLOPEN */ dispatch.status = -1; fprintf(stderr, "opendso: %s: No dynamic DSO/DLL support on this platform\n", dso); #endif }
int main(int argc, char **argv) { int c; int sts; char *endnum; iflag = isatty(0); while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) { switch (c) { case 'D': /* debug flag */ sts = __pmParseDebug(opts.optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, opts.optarg); opts.errors++; } else pmDebug |= sts; break; case 'e': /* echo input */ eflag++; break; case 'f': /* skip .dbpmdarc processing */ fflag++; break; case 'i': /* be interactive */ iflag = 1; break; case 'n': /* alternative name space file */ pmnsfile = opts.optarg; break; case 'q': sts = (int)strtol(opts.optarg, &endnum, 10); if (*endnum != '\0' || sts <= 0.0) { pmprintf("%s: -q requires a positive numeric argument\n", pmProgname); opts.errors++; } else { _creds_timeout = sts; } break; case 'U': /* run under alternate user account */ __pmSetProcessIdentity(opts.optarg); break; default: case '?': opts.errors++; break; } } if ((c = argc - opts.optind) > 0) { if (c > 1) opts.errors++; else { /* pid was specified */ if (primary) { pmprintf("%s: you may not specify both -P and a pid\n", pmProgname); opts.errors++; } else { pid = (int)strtol(argv[opts.optind], &endnum, 10); if (*endnum != '\0') { pmprintf("%s: pid must be a numeric process id\n", pmProgname); opts.errors++; } } } } if (opts.errors) { pmUsageMessage(&opts); exit(1); } if (pmnsfile == PM_NS_DEFAULT) { if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: Cannot load default namespace: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } else { if ((sts = pmLoadASCIINameSpace(pmnsfile, 1)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } /* initialize the "fake context" ... */ setup_context(); setlinebuf(stdout); setlinebuf(stderr); #ifdef HAVE_ATEXIT atexit(cleanup); #endif for ( ; ; ) { initmetriclist(); yyparse(); if (yywrap()) { if (iflag) putchar('\n'); break; } __pmSetInternalState(PM_STATE_PMCS); switch (stmt_type) { case OPEN: profile_changed = 1; break; case CLOSE: switch (connmode) { case CONN_DSO: closedso(); break; case CONN_DAEMON: closepmda(); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } connmode = NO_CONN; break; case DESC: switch (connmode) { case CONN_DSO: dodso(PDU_DESC_REQ); break; case CONN_DAEMON: dopmda(PDU_DESC_REQ); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case FETCH: switch (connmode) { case CONN_DSO: dodso(PDU_FETCH); break; case CONN_DAEMON: dopmda(PDU_FETCH); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case INSTANCE: switch (connmode) { case CONN_DSO: dodso(PDU_INSTANCE_REQ); break; case CONN_DAEMON: dopmda(PDU_INSTANCE_REQ); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case STORE: switch (connmode) { case CONN_DSO: dodso(PDU_RESULT); break; case CONN_DAEMON: dopmda(PDU_RESULT); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case HELP: dohelp(param.number, param.pmid); break; case WATCH: break; case DBG: pmDebug = param.number; break; case QUIT: goto done; case STATUS: dostatus(); break; case INFO: switch (connmode) { case CONN_DSO: dodso(PDU_TEXT_REQ); break; case CONN_DAEMON: dopmda(PDU_TEXT_REQ); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case NAMESPACE: if (cmd_namespace != NULL) free(cmd_namespace); cmd_namespace = strdup(param.name); if (cmd_namespace == NULL) { fprintf(stderr, "%s: No memory for new namespace\n", pmProgname); exit(1); } pmUnloadNameSpace(); strcpy(cmd_namespace, param.name); if ((sts = pmLoadASCIINameSpace(cmd_namespace, 1)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, cmd_namespace, pmErrStr(sts)); pmUnloadNameSpace(); if (pmnsfile == PM_NS_DEFAULT) { fprintf(stderr, "%s: Reload default namespace\n", pmProgname); if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: Cannot load default namespace: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } else { fprintf(stderr, "%s: Reload namespace from \"%s\"\n", pmProgname, pmnsfile); if ((sts = pmLoadASCIINameSpace(pmnsfile, 1)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\"" ": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } } break; case EOL: break; case PMNS_NAME: switch (connmode) { case CONN_DSO: dodso(PDU_PMNS_IDS); break; case CONN_DAEMON: dopmda(PDU_PMNS_IDS); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case PMNS_PMID: switch (connmode) { case CONN_DSO: dodso(PDU_PMNS_NAMES); break; case CONN_DAEMON: dopmda(PDU_PMNS_NAMES); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case PMNS_CHILDREN: switch (connmode) { case CONN_DSO: dodso(PDU_PMNS_CHILD); break; case CONN_DAEMON: dopmda(PDU_PMNS_CHILD); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case PMNS_TRAVERSE: switch (connmode) { case CONN_DSO: dodso(PDU_PMNS_TRAVERSE); break; case CONN_DAEMON: dopmda(PDU_PMNS_TRAVERSE); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; case ATTR: switch (connmode) { case CONN_DSO: dodso(PDU_AUTH); break; case CONN_DAEMON: dopmda(PDU_AUTH); break; case NO_CONN: yywarn("No PMDA currently opened"); break; } break; default: printf("Unexpected result (%d) from parser?\n", stmt_type); break; } __pmSetInternalState(PM_STATE_APPL); } done: cleanup(); exit(0); }