diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/dbpmda | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/dbpmda')
-rw-r--r-- | src/dbpmda/GNUmakefile | 32 | ||||
-rw-r--r-- | src/dbpmda/src/GNUmakefile | 47 | ||||
-rw-r--r-- | src/dbpmda/src/dbpmda.c | 437 | ||||
-rw-r--r-- | src/dbpmda/src/dbpmda.h | 98 | ||||
-rw-r--r-- | src/dbpmda/src/dso.c | 479 | ||||
-rw-r--r-- | src/dbpmda/src/gram.y | 634 | ||||
-rw-r--r-- | src/dbpmda/src/lex.h | 32 | ||||
-rw-r--r-- | src/dbpmda/src/lex.l | 611 | ||||
-rw-r--r-- | src/dbpmda/src/pmda.c | 840 | ||||
-rw-r--r-- | src/dbpmda/src/util.c | 587 |
10 files changed, 3797 insertions, 0 deletions
diff --git a/src/dbpmda/GNUmakefile b/src/dbpmda/GNUmakefile new file mode 100644 index 0000000..4c4ed0e --- /dev/null +++ b/src/dbpmda/GNUmakefile @@ -0,0 +1,32 @@ +#!gmake +# +# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +TOPDIR = ../.. +include $(TOPDIR)/src/include/builddefs + +SUBDIRS = src + +default install: $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) + +default_pcp : default + +install_pcp : install diff --git a/src/dbpmda/src/GNUmakefile b/src/dbpmda/src/GNUmakefile new file mode 100644 index 0000000..e74eb80 --- /dev/null +++ b/src/dbpmda/src/GNUmakefile @@ -0,0 +1,47 @@ +# +# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + +CMDTARGET = dbpmda$(EXECSUFFIX) +CFILES = dbpmda.c dso.c util.c pmda.c +HFILES = lex.h dbpmda.h +LFILES = lex.l +YFILES = gram.y + +LDIRT = *.log foo.* gram.h $(YFILES:%.y=%.tab.?) $(LFILES:%.l=%.c) +LLDLIBS = $(PCPLIB) $(LIB_FOR_DLOPEN) $(LIB_FOR_READLINE) $(LIB_FOR_CURSES) + +default: $(CMDTARGET) + +include $(BUILDRULES) + +$(CMDTARGET): $(OBJECTS) + +install: $(CMDTARGET) + $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) + +dbpmda.o: gram.h +lex.o: gram.tab.h + +.NOTPARALLEL: +gram.tab.h gram.tab.c: gram.y + +gram.h: gram.tab.h + rm -f $@ && $(LN_S) $< $@ + +default_pcp: default + +install_pcp: install diff --git a/src/dbpmda/src/dbpmda.c b/src/dbpmda/src/dbpmda.c new file mode 100644 index 0000000..9af6e23 --- /dev/null +++ b/src/dbpmda/src/dbpmda.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2012-2014 Red Hat. + * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "dbpmda.h" +#include "lex.h" +#include "gram.h" +#include <ctype.h> + +char *configfile; +__pmLogCtl logctl; +int parse_done; +int primary; /* Non-zero for primary pmlc */ +pid_t pid = (pid_t) -1; +char *pmnsfile = PM_NS_DEFAULT; +char *cmd_namespace = NULL; /* namespace given from command */ +int _creds_timeout = 3; /* Timeout for agents credential PDU */ + +int connmode = NO_CONN; +int stmt_type; +int eflag; +int iflag; + +extern int yyparse(void); + +static pmLongOptions longopts[] = { + PMAPI_OPTIONS_HEADER("General options"), + PMOPT_DEBUG, + PMOPT_NAMESPACE, + { "creds-timeout", 1, 'q', "N", "initial negotiation timeout (seconds)" }, + { "username", 1, 'U', "USER", "run under named user account" }, + PMOPT_HELP, + PMAPI_OPTIONS_HEADER("Input options"), + { "echo-input", 0, 'e', 0, "echo input" }, + { "interactive", 0, 'i', 0, "be interactive and prompt" }, + PMAPI_OPTIONS_END +}; + +static pmOptions opts = { + .flags = PM_OPTFLAG_POSIX, + .short_options = "q:D:ein:U:?", + .long_options = longopts, +}; + +/* + * 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; +} + +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 '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 ((sts = pmLoadNameSpace(pmnsfile)) < 0) { + if (pmnsfile == PM_NS_DEFAULT) { + fprintf(stderr, "%s: Cannot load default namespace: %s\n", + pmProgname, pmErrStr(sts)); + } else { + 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 = pmLoadNameSpace(cmd_namespace)) < 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); + } else { + fprintf(stderr, "%s: Reload namespace from \"%s\"\n", + pmProgname, pmnsfile); + } + if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { + if (pmnsfile == PM_NS_DEFAULT) { + fprintf(stderr, + "%s: Cannot load default namespace: %s\n", + pmProgname, pmErrStr(sts)); + } else { + 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); +} diff --git a/src/dbpmda/src/dbpmda.h b/src/dbpmda/src/dbpmda.h new file mode 100644 index 0000000..6e35cdf --- /dev/null +++ b/src/dbpmda/src/dbpmda.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" + +/* yacc/lex routines */ +extern char lastinput(void); +extern void yyerror(const char *); +extern void yywarn(char *); +extern int yywrap(void); +extern int yylex(void); +extern int markpos(void); +extern void locateError(void); + +/* utiltity routines */ +extern void setup_context(void); +extern void reset_profile(void); +extern char *strcons(char *, char *); +extern char *strnum(int); +extern void initmetriclist(void); +extern void addmetriclist(pmID); +extern void initarglist(void); +extern void addarglist(char *); +extern void doargs(void); +extern void printindom(FILE *, __pmInResult *); +extern void dohelp(int, int); +extern void dostatus(void); +extern int fillResult(pmResult *, int); +extern void _dbDumpResult(FILE *, pmResult *, pmDesc *); + +/* pmda exerciser routines */ +extern void opendso(char *, char *, int); +extern void closedso(void); +extern void dodso(int); +extern void openpmda(char *); +extern void closepmda(void); +extern void dopmda(int); +extern void watch(char *); +extern void open_unix_socket(char *); +extern void open_inet_socket(int); +extern void open_ipv6_socket(int); + +/* + * connection states + */ +#define NO_CONN -1 +#define CONN_DSO 0 +#define CONN_DAEMON 1 +extern int connmode; + +/* parameters for action routines ... */ +typedef struct { + int number; + char *name; + pmID pmid; + pmInDom indom; + int numpmid; + pmID *pmidlist; + int argc; + char **argv; +} param_t; + +extern param_t param; + +/* the single profile */ +extern __pmProfile *profile; +extern int profile_changed; + +/* status info */ +extern char *myPmdaName; + +/* help text formats */ +#define HELP_USAGE 0 +#define HELP_FULL 1 + +/* timing information */ +extern int timer; + +/* get descriptor for fetch or not */ +extern int get_desc; + +/* namespace pathnames */ +extern char *pmnsfile; +extern char *cmd_namespace; diff --git a/src/dbpmda/src/dso.c b/src/dbpmda/src/dso.c new file mode 100644 index 0000000..5dc7c16 --- /dev/null +++ b/src/dbpmda/src/dso.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <sys/stat.h> +#include "./dbpmda.h" +#include "pmapi.h" + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +static char *dsoname; +static void *handle; +pmdaInterface dispatch; + +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 +} + +void +closedso(void) +{ + if (dsoname != NULL) { + if (dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) { + if (dispatch.version.four.ext->e_endCallBack != NULL) { + (*(dispatch.version.four.ext->e_endCallBack))(0); + } + } +#ifdef HAVE_DLOPEN + dlclose(handle); +#endif + free(dsoname); + dsoname = NULL; + connmode = NO_CONN; + } +} + +/* + * Do a descriptor pdu. + * Abstracted here for several calls. + */ +int +dodso_desc(pmID pmid, pmDesc *desc) +{ + int sts; + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_PDU) + fprintf(stderr, "DSO desc()\n"); +#endif + sts = dispatch.version.any.desc(pmid, desc, dispatch.version.four.ext); + +#ifdef PCP_DEBUG + if (sts >= 0 && (pmDebug & DBG_TRACE_PDU)) + __pmPrintDesc(stdout, desc); +#endif + + return sts; +}/*dodso_desc*/ + + +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)); + } +} diff --git a/src/dbpmda/src/gram.y b/src/dbpmda/src/gram.y new file mode 100644 index 0000000..b9a83a6 --- /dev/null +++ b/src/dbpmda/src/gram.y @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +%{ +#include "./dbpmda.h" +#include "./lex.h" + +extern int stmt_type; + +static union { + pmID whole; + __pmID_int part; +} pmid; + +static union { + pmInDom whole; + __pmInDom_int part; +} indom; + + +static int sts; +static int inst; +static char *str; +static char warnStr[80]; + +param_t param; + +/* + * pmidp may contain a dynamic PMID ... if so, ask the PMDA to + * translate name if possible + */ +static int +fix_dynamic_pmid(char *name, pmID *pmidp) +{ + int sts; + __pmPDU *pb; + extern int outfd; + extern int infd; + extern pmdaInterface dispatch; + + if (pmid_domain(*pmidp) == DYNAMIC_PMID && pmid_item(*pmidp) == 0) { + if (connmode == CONN_DSO) { + if (dispatch.comm.pmda_interface >= PMDA_INTERFACE_4) { + sts = dispatch.version.four.pmid(name, pmidp, dispatch.version.four.ext); + if (sts < 0) return sts; + } + } + else if (connmode == CONN_DAEMON) { + sts = __pmSendNameList(outfd, FROM_ANON, 1, &name, NULL); + if (sts < 0) return sts; + sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb); + if (sts < 0) return sts; + if (sts == PDU_PMNS_IDS) { + int xsts; + sts = __pmDecodeIDList(pb, 1, pmidp, &xsts); + __pmUnpinPDUBuf(pb); + if (sts < 0) return sts; + return xsts; + } + else if (sts == PDU_ERROR) { + __pmDecodeError(pb, &sts); + __pmUnpinPDUBuf(pb); + return sts; + } + } + } + return 0; +} + + +%} + +%union { + char *y_str; + int y_num; + twodot_num y_2num; + threedot_num y_3num; + } + +%token <y_2num> + NUMBER2D + +%token <y_3num> + NUMBER3D + +%token <y_num> + NUMBER + NEGNUMBER + FLAG + +%token <y_str> + NAME + PATHNAME + MACRO + STRING + +%term COMMA EQUAL + OPEN CLOSE DESC GETDESC FETCH INSTANCE PROFILE HELP + WATCH DBG QUIT STATUS STORE INFO TIMER NAMESPACE WAIT + PMNS_NAME PMNS_PMID PMNS_CHILDREN PMNS_TRAVERSE ATTR + DSO PIPE SOCK UNIX INET IPV6 + ADD DEL ALL NONE INDOM ON OFF + PLUS EOL + +%type <y_num> + metric + indom + optdomain + debug + raw_pmid + attribute + servport + +%type <y_str> + fname + arglist + inst + +%% + +stmt : OPEN EOL { + param.number = OPEN; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | OPEN DSO fname NAME optdomain EOL { + opendso($3, $4, $5); + stmt_type = OPEN; YYACCEPT; + } + | OPEN PIPE fname arglist { + openpmda($3); + stmt_type = OPEN; YYACCEPT; + } + | OPEN SOCK fname { + open_unix_socket($3); + stmt_type = OPEN; YYACCEPT; + } + | OPEN SOCK UNIX fname { + open_unix_socket($4); + stmt_type = OPEN; YYACCEPT; + } + | OPEN SOCK INET servport { + open_inet_socket($4); + stmt_type = OPEN; YYACCEPT; + } + | OPEN SOCK IPV6 servport { + open_ipv6_socket($4); + stmt_type = OPEN; YYACCEPT; + } + | CLOSE EOL { + stmt_type = CLOSE; YYACCEPT; + } + | DESC EOL { + param.number = DESC; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | DESC metric EOL { + param.pmid = $2; + stmt_type = DESC; YYACCEPT; + } + | FETCH EOL { + param.number = FETCH; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | FETCH metriclist EOL { + stmt_type = FETCH; YYACCEPT; + } + | STORE EOL { + param.number = STORE; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | STORE metric STRING EOL { + param.name = $3; + param.pmid = (pmID)$2; + stmt_type = STORE; YYACCEPT; + } + | INFO EOL { + param.number = INFO; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | INFO metric EOL { + param.number = PM_TEXT_PMID; + param.pmid = (pmID)$2; + stmt_type = INFO; YYACCEPT; + } + | INFO INDOM indom EOL { + param.number = PM_TEXT_INDOM; + param.indom = indom.whole; + stmt_type = INFO; YYACCEPT; + } + | INSTANCE EOL { + param.number = INSTANCE; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | INSTANCE indom EOL { + param.indom = indom.whole; + param.number = PM_IN_NULL; + param.name = NULL; + stmt_type = INSTANCE; YYACCEPT; + } + | INSTANCE indom NUMBER EOL { + param.indom = indom.whole; + param.number = $3; + param.name = NULL; + stmt_type = INSTANCE; YYACCEPT; + } + | INSTANCE indom inst EOL { + param.indom = indom.whole; + param.number = PM_IN_NULL; + param.name = $3; + stmt_type = INSTANCE; YYACCEPT; + } + | PROFILE EOL { + param.number = PROFILE; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | PROFILE indom ALL EOL { + sts = pmAddProfile($2, 0, NULL); + if (sts < 0) { + yyerror(pmErrStr(sts)); + YYERROR; + } + profile_changed = 1; + stmt_type = EOL; + YYACCEPT; + } + | PROFILE indom NONE EOL { + sts = pmDelProfile($2, 0, NULL); + if (sts < 0) { + yyerror(pmErrStr(sts)); + YYERROR; + } + profile_changed = 1; + stmt_type = EOL; + YYACCEPT; + } + | PROFILE indom ADD NUMBER EOL { + inst = $4; + sts = pmAddProfile($2, 1, &inst); + if (sts < 0) { + yyerror(pmErrStr(sts)); + YYERROR; + } + profile_changed = 1; + stmt_type = EOL; + YYACCEPT; + } + | PROFILE indom DEL NUMBER EOL { + inst = $4; + sts = pmDelProfile($2, 1, &inst); + if (sts < 0) { + yyerror(pmErrStr(sts)); + YYERROR; + } + profile_changed = 1; + stmt_type = EOL; + YYACCEPT; + } + | WATCH EOL { + param.number = WATCH; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | WATCH fname EOL { + watch($2); + stmt_type = WATCH; YYACCEPT; + } + | PMNS_NAME EOL { + param.number = PMNS_NAME; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | PMNS_NAME raw_pmid EOL { + param.pmid = $2; + stmt_type = PMNS_NAME; YYACCEPT; + } + | PMNS_PMID EOL { + param.number = PMNS_PMID; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | PMNS_PMID NAME EOL { + param.name = $2; + stmt_type = PMNS_PMID; YYACCEPT; + } + | PMNS_CHILDREN EOL { + param.number = PMNS_CHILDREN; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | PMNS_CHILDREN NAME EOL { + param.name = $2; + stmt_type = PMNS_CHILDREN; YYACCEPT; + } + | PMNS_TRAVERSE EOL { + param.number = PMNS_TRAVERSE; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | PMNS_TRAVERSE NAME EOL { + param.name = $2; + stmt_type = PMNS_TRAVERSE; YYACCEPT; + } + | NAMESPACE fname EOL { + param.name = $2; + stmt_type = NAMESPACE; YYACCEPT; + } + | ATTR EOL { + param.number = ATTR; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | ATTR attribute EOL { + param.number = $2; + param.name = NULL; + stmt_type = ATTR; YYACCEPT; + } + | ATTR attribute STRING EOL { + param.number = $2; + param.name = $3; + stmt_type = ATTR; YYACCEPT; + } + + | HELP EOL { + param.number = -1; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP CLOSE EOL { + param.number = CLOSE; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP DBG EOL { + param.number = DBG; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP DESC EOL { + param.number = DESC; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP FETCH EOL { + param.number = FETCH; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP GETDESC EOL { + param.number = GETDESC; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP INFO EOL { + param.number = INFO; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP INSTANCE EOL { + param.number = INSTANCE; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP NAMESPACE EOL { + param.number = NAMESPACE; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP OPEN EOL { + param.number = OPEN; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP PMNS_CHILDREN EOL { + param.number = PMNS_CHILDREN; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP PMNS_NAME EOL { + param.number = PMNS_NAME; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP PMNS_PMID EOL { + param.number = PMNS_PMID; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP PMNS_TRAVERSE EOL { + param.number = PMNS_TRAVERSE; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP ATTR EOL { + param.number = ATTR; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP PROFILE EOL { + param.number = PROFILE; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP QUIT EOL { + param.number = QUIT; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP STATUS EOL { + param.number = STATUS; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP STORE EOL { + param.number = STORE; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP TIMER EOL { + param.number = TIMER; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP WAIT EOL { + param.number = WAIT; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + | HELP WATCH EOL { + param.number = WATCH; param.pmid = HELP_FULL; + stmt_type = HELP; YYACCEPT; + } + + | QUIT EOL { stmt_type = QUIT; YYACCEPT; } + | DBG EOL { + param.number = DBG; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | DBG ALL EOL { + param.number = -1; + stmt_type = DBG; YYACCEPT; + } + | DBG NONE EOL { + param.number = 0; + stmt_type = DBG; YYACCEPT; + } + | DBG debug EOL { + param.number = $2; + stmt_type = DBG; YYACCEPT; + } + | STATUS EOL { + stmt_type = STATUS; YYACCEPT; + } + | TIMER EOL { + param.number = TIMER; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | TIMER ON EOL { + timer = 1; stmt_type = EOL; YYACCEPT; + } + | TIMER OFF EOL { + timer = 0; stmt_type = EOL; YYACCEPT; + } + | GETDESC EOL { + param.number = GETDESC; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | GETDESC ON EOL { + get_desc = 1; stmt_type = EOL; YYACCEPT; + } + | GETDESC OFF EOL { + get_desc = 0; stmt_type = EOL; YYACCEPT; + } + | WAIT EOL { + param.number = WAIT; param.pmid = HELP_USAGE; + stmt_type = HELP; YYACCEPT; + } + | WAIT NUMBER EOL { + stmt_type = EOL; sleep($2); YYACCEPT; + } + | EOL { stmt_type = EOL; YYACCEPT; } + | { + if (yywrap()) + YYACCEPT; + else { + yyerror("Unrecognized command"); + YYERROR; + } + } + ; + +fname : NAME { $$ = strcons("./", $1); } + | PATHNAME { $$ = $1; } + ; + +optdomain : NUMBER { $$ = $1; } + | /* nothing */ { $$ = 0; } + ; + +attribute : NUMBER { + sts = __pmAttrKeyStr_r($1, warnStr, sizeof(warnStr)); + if (sts <= 0) { + sprintf(warnStr, "Attribute (%d) is not recognised", $1); + yyerror(warnStr); + YYERROR; + } + $$ = $1; + } + | STRING { + sts = __pmLookupAttrKey($1, strlen($1)+1); + if (sts <= 0) { + sprintf(warnStr, "Attribute (%s) is not recognised", $1); + yyerror(warnStr); + YYERROR; + } + $$ = sts; + } + ; + +servport : NUMBER { $$ = $1; } + | STRING { + struct servent *srv = getservbyname($1, NULL); + if (srv == NULL) { + sprintf(warnStr, "Failed to map (%s) to a port number", $1); + yyerror(warnStr); + YYERROR; + } + sprintf(warnStr, "Mapped %s to port number %d", $1, srv->s_port); + yywarn(warnStr); + $$ = srv->s_port; + } + ; + +metric : NUMBER { + pmid.whole = $1; + sts = pmNameID(pmid.whole, &str); + if (sts < 0) { + sprintf(warnStr, "PMID (%s) is not defined in the PMNS", + pmIDStr(pmid.whole)); + yywarn(warnStr); + } + else + free(str); + $$ = (int)pmid.whole; + } + | NUMBER2D { + pmid.whole = 0; + pmid.part.cluster = $1.num1; + pmid.part.item = $1.num2; + sts = pmNameID(pmid.whole, &str); + if (sts < 0) { + sprintf(warnStr, "PMID (%s) is not defined in the PMNS", + pmIDStr(pmid.whole)); + yywarn(warnStr); + } + else + free(str); + $$ = (int)pmid.whole; + } + | NUMBER3D { + pmid.whole = 0; + pmid.part.domain = $1.num1; + pmid.part.cluster = $1.num2; + pmid.part.item = $1.num3; + sts = pmNameID(pmid.whole, &str); + if (sts < 0) { + sprintf(warnStr, "PMID (%s) is not defined in the PMNS", + pmIDStr(pmid.whole)); + yywarn(warnStr); + } + else + free(str); + $$ = (int)pmid.whole; + } + | NAME { + sts = pmLookupName(1, &$1, &pmid.whole); + if (sts < 0) { + yyerror(pmErrStr(sts)); + YYERROR; + } + sts = fix_dynamic_pmid($1, &pmid.whole); + if (sts < 0) { + yyerror(pmErrStr(sts)); + YYERROR; + } + $$ = (int)pmid.whole; + } + ; + +indom : NUMBER { + indom.whole = $1; + $$ = (int)indom.whole; + } + | NEGNUMBER { + indom.whole = $1; + $$ = (int)indom.whole; + } + | NUMBER2D { + indom.whole = 0; + indom.part.domain = $1.num1; + indom.part.serial = $1.num2; + $$ = (int)indom.whole; + } + ; + +raw_pmid: NUMBER3D { + pmid.whole = 0; + pmid.part.domain = $1.num1; + pmid.part.cluster = $1.num2; + pmid.part.item = $1.num3; + $$ = (int)pmid.whole; + } + ; + +metriclist : metric { addmetriclist((pmID)$1); } + | metriclist metric { addmetriclist((pmID)$2); } + | metriclist COMMA metric { addmetriclist((pmID)$3); } + ; + + +arglist : /* nothing, a trick */ { doargs(); } + ; + +inst : STRING { $$ = $1; } + | NAME { $$ = $1; } + ; + +debug : NUMBER { $$ = $1; } + | NAME { + sts = __pmParseDebug($1); + if (sts < 0) { + sprintf(warnStr, "Bad debug flag (%s)", $1); + yywarn(warnStr); + YYERROR; + } + $$ = sts; + } + | NUMBER debug { $$ = $1 | $2; } + | NAME debug { + sts = __pmParseDebug($1); + if (sts < 0) { + sprintf(warnStr, "Bad debug flag (%s)", $1); + yywarn(warnStr); + YYERROR; + } + $$ = sts | $2; + } + ; + +%% diff --git a/src/dbpmda/src/lex.h b/src/dbpmda/src/lex.h new file mode 100644 index 0000000..7426571 --- /dev/null +++ b/src/dbpmda/src/lex.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _LEX_H +#define _LEX_H + +typedef struct { + int num1; + int num2; +}twodot_num; + +typedef struct { + int num1; + int num2; + int num3; +}threedot_num; + +#endif diff --git a/src/dbpmda/src/lex.l b/src/dbpmda/src/lex.l new file mode 100644 index 0000000..2a9cebf --- /dev/null +++ b/src/dbpmda/src/lex.l @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +%{ +#include "pmapi.h" +#include "impl.h" + +static int lineno = 0; +static int using_readline = 0; + +#include "./lex.h" + +#ifdef HAVE_READLINE +#include <readline/readline.h> +#include <readline/history.h> +#endif + +#ifdef FLEX_SCANNER +#include "./gram.tab.h" +static int dbpmdaFlexInput (char *, int); +#else +#include "./gram.h" +#endif + +#include "./dbpmda.h" + +%} + +%s FNAME +%a 2200 + +%option noinput +%option nounput + +%{ +#ifdef FLEX_SCANNER +#ifndef YY_NO_UNPUT +#define YY_NO_UNPUT +#endif +#undef YY_INPUT +#define YY_INPUT(b,r,ms) (r=dbpmdaFlexInput(b, ms)) +#else +#undef input +#undef unput +#undef yywrap +#undef yyinput +#endif +%} + +%% + +add { return ADD; } +all { return ALL; } +attr { return ATTR; } +attribute { return ATTR; } +children { return PMNS_CHILDREN; } +close { return CLOSE; } +debug { return DBG; } +delete { return DEL; } +desc { return DESC; } +dso { BEGIN FNAME; return DSO; } +exit { return QUIT; } +fetch { return FETCH; } +getdesc { return GETDESC; } +help { return HELP; } +indom { return INDOM; } +inet { return INET; } +instance { return INSTANCE; } +ipv6 { return IPV6; } +name { return PMNS_NAME; } +namespace { BEGIN FNAME; return NAMESPACE; } +none { return NONE; } +off { return OFF; } +on { return ON; } +open { return OPEN; } +pipe { BEGIN FNAME; return PIPE; } +pmid { return PMNS_PMID; } +profile { return PROFILE; } +q { return QUIT; } +quit { return QUIT; } +socket { BEGIN FNAME; return SOCK; } +status { return STATUS; } +store { return STORE; } +text { return INFO; } +timer { return TIMER; } +traverse { return PMNS_TRAVERSE; } +unix { return UNIX; } +wait { return WAIT; } +watch { BEGIN FNAME; return WATCH; } +\? { return HELP; } +\= { return EQUAL; } +\, { return COMMA; } +\+ { return PLUS; } + +[A-Za-z][A-Za-z0-9_\./:-]* { + yylval.y_str = (char *)malloc(yyleng+1); + strcpy(yylval.y_str, yytext); + return NAME; + } + +\$[A-Za-z][A-Za-z0-9_-]* { + yylval.y_str = (char *)malloc(yyleng+1); + strcpy(yylval.y_str, yytext); + return MACRO; + } + +0[xX][0-9]+ { + yylval.y_num = (int)strtol(&yytext[2], NULL, 16); + return NUMBER; + } + +[0-9]+ { + yylval.y_num = atoi(yytext); + return NUMBER; + } + +-[0-9]+ { + yylval.y_num = atoi(yytext); + return NEGNUMBER; + } + +[0-9]+\.[0-9]+ { + sscanf(yytext, "%d.%d", &yylval.y_2num.num1, + &yylval.y_2num.num2); + return NUMBER2D; + } + +[0-9]+\.[0-9]+\.[0-9]+ { + sscanf(yytext, "%d.%d.%d", &yylval.y_3num.num1, + &yylval.y_3num.num2, &yylval.y_3num.num3); + return NUMBER3D; + } + + +\"[^\"\n][^\"\n]*\" { + yylval.y_str = (char *)malloc(yyleng-1); + strncpy(yylval.y_str, &yytext[1], yyleng-2); + yylval.y_str[yyleng-2] = '\0'; + return STRING; + } + +\"[^\"\n][^\"\n]*\n { + yyerror("Expected \""); + } + +\#.*\n { return EOL; } + +[\r\t ]+ { } + +\n { return EOL; } + +<FNAME>[^\t \n]+ { + yylval.y_str = (char *)malloc(yyleng+1); + strcpy(yylval.y_str, yytext); + BEGIN 0; + return PATHNAME; + } + + +. { + yyerror("Illegal character"); + } +%% + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +static char *prompt = "dbpmda"; +static char *line = NULL; +static int lastc = '\n'; +static int linepos = 0; +static int linelen = 0; +static int mark = -1; + +extern char *configfile; + +extern int eflag; +extern int iflag; + +#ifdef FLEX_SCANNER + +static int +dbpmdaGetc (char * inbuf) +{ + int inch; + +#ifdef HAVE_READLINE + char rl_prompt_storage[64]; + char *rl_prompt = rl_prompt_storage; + static char *str = NULL; + static int strpos = 0; + + if (using_readline) { + if (iflag) + snprintf(rl_prompt_storage, 64, "%s> ", prompt); + else + rl_prompt = NULL; + + rl_instream = yyin; + + if (!str) { + do { + str = readline(rl_prompt); + if (!str) { + /* EOF */ + inbuf[0] = inch = '\0'; + goto done; + } + } while (!str[0]); + } + + inch = str[strpos++]; + if (inch == '\r') + inch = str[strpos++]; + + if (!inch) { + /* end of input line, fake out \n so parser notices */ + inch = '\n'; + /* and setup to call readline() next time */ + free(str); + str = NULL; + strpos = 0; + } + + inbuf[0] = inch; + goto done; + } + /* else fall through to the non-readline method */ +#endif + + while ((inch = fgetc (yyin)) != EOF) { + inbuf[0] = inch & 0xFFU; + if (inbuf[0] == '\r') { + /* for windows, eat carriage returns */ + continue; + } + if (eflag) { + putchar(inch); + fflush(stdout); + } + break; + } + if (inch == EOF) + inch = '\0'; + +#ifdef HAVE_READLINE +done: +#endif +#ifdef DESPERATE + fprintf(stderr, "dbpmdaGetc: yyin=%p (%d) using_readline=%d lastc=%x \"%c\" inch=%x \"%c\"\n", yyin, fileno(yyin), using_readline, lastc & 0xff, lastc, inch & 0xff, inch); +#endif + return inch; +} + +static int +dbpmdaFlexInput (char * inbuf, int ms) +{ + static FILE * inf = NULL; + static int first = 1; + static int save_iflag, save_eflag; + + if (first) { + first = 0; + if (!access (".dbpmdarc", R_OK)) { + inf = yyin; + if ((yyin = fopen (".dbpmdarc", "r")) != NULL) { + save_eflag = eflag; + save_iflag = iflag; + eflag = 1; + iflag = 1; + prompt = ".dbpmdarc"; + configfile = ".dbpmdarc"; + lineno = 0; + } else { + yyin = inf; + } + } +#ifdef HAVE_READLINE + else { + using_readline = isatty(fileno(yyin)); + } +#endif + } + + if (lastc == '\n') { +#ifdef HAVE_READLINE + if (line != NULL && *line != '\0' && *line != '\n') { + /* line is not empty, push it into history */ + char *newline = strchr(line, '\n'); + if (newline != NULL) *newline = '\0'; + add_history(line); + if (newline != NULL) *newline = '\n'; + } +#endif + if (iflag && !using_readline) { + printf ("%s> ", prompt); + fflush (stdout); + } + lineno++; + linepos = 0; + } + + if (linepos == linelen) { + linelen = (linelen) ? linelen * 2 : 128; + if ((line = (char *)realloc(line, linelen * sizeof(char))) == NULL) { + fprintf(stderr, "%s: Lexer internal error\n", pmProgname); + exit(1); + } + } + + if (ms > 0) { + while (1) { + if ((lastc = dbpmdaGetc(inbuf))) { + line[linepos++] = inbuf[0]; + return (1); + } else { + /* It maybe an EOF */ + if ((inf != NULL) && (inf != yyin)) { + yyin = inf; + lineno = 1; +#ifdef HAVE_READLINE + using_readline = isatty(fileno(yyin)); +#endif + prompt = "dbpmda"; + configfile = NULL; + iflag = save_iflag; + if (iflag) { + if (using_readline) + putchar('\n'); + else + printf("%s> ", prompt); + fflush(stdout); + } + eflag = save_eflag; + } else { + return 0; + } + } + } + } + + return ms; +} + +#else /* AT&T Lex */ + +static char peekc = '\0'; + +char +input(void) +{ + int get; + static int first = 1; + static int save_eflag; + static int save_iflag; + static int inrc; + + if (first) { + if (access(".dbpmdarc", R_OK) == 0) { + int fd = open(".dbpmdarc", O_RDONLY); + if (fd >= 0) { + inrc = dup(0); + close(0); + dup(fd); + close(fd); + save_eflag = eflag; + save_iflag = iflag; + eflag = 1; + iflag = 1; + prompt = ".dbpmdarc"; + configfile = ".dbpmdarc"; + } + } + } + + if (peekc) { + lastc = peekc; + peekc = '\0'; + return lastc; + } + + again: + if (lastc == '\n' || first) { + if (iflag) { + printf("%s> ", prompt); + fflush(stdout); + } + if (first) + first = 0; + else + lineno++; + linepos = 0; + } + else if (lastc == '\0') { + linepos = 0; + return lastc; + } + + if (linepos == linelen) { + if (linelen == 0) + linelen = 128; + else + linelen *= 2; + line = (char*)realloc(line, linelen * sizeof(char)); + } + + get = getchar(); + + line[linepos++] = (char)get; + + if (get == EOF) { + if (inrc) { + close(0); + dup(inrc); + close(inrc); + inrc = 0; + eflag = save_eflag; + iflag = save_iflag; + prompt = "dbpmda"; + configfile = NULL; + putchar('\n'); + lineno = 0; + lastc = '\n'; + goto again; + } + lastc = '\0'; + } + else { + lastc = get; + if (eflag) { + putchar(lastc); + fflush(stdout); + } + } + + return lastc; +} + +void +unput(char c) +{ + peekc = c; +} +#endif + +int +yywrap(void) +{ + return lastc == '\0'; +} + +char +lastinput(void) +{ + return lastc; +} + +int +markpos(void) +{ + mark = linepos; + return mark; +} + +void +locateError(void) +{ + int i; + + if (mark < 0) { + fprintf(stderr, "%s: Unrecoverable internal error in locateError()\n", + pmProgname); + exit(1); + } + + for (i = 0; prompt[i]; i++) + putchar(' '); + + putchar(' '); + + for (i = 0; i < mark; i++) { + if (line[i] == '\t') + putchar('\t'); + else if (line[i] == '\n' || line[i] == '\0') + break; + else + putchar(' '); + } + + putchar('^'); + printf(" at or near here\n"); + fflush(stdout); +} + + +void +doargs(void) +{ + /* + * a hack ... slide underneath lex/yacc to do the cmd-line args + */ + char buf[256]; /* big enough for a single arg? */ + char *p; + char c; + char delim = '\0'; + + initarglist(); + + if (lastc == '\n') { + addarglist(NULL); + return; + } + + p = buf; + for ( ; ; ) { +#ifdef FLEX_SCANNER + dbpmdaFlexInput (&c, 1); +#else + c = input(); +#endif + if (delim) { + if (c == delim) { + delim = '\0'; + continue; + } + } + else if (c == ' ' || c == '\t' || c == '\n' || c == '\0') { + if (p > buf) { + *p = '\0'; + addarglist(buf); + p = buf; + } + if (c == '\n' || c == '\0') { + /* + * EOL removed from grammar after arglist, so no + * need push \n or \0 back into the input stream + * (which was not working well!) + */ + addarglist(NULL); + return; + } + continue; + } + else if (c == '"' || c == '\'') { + delim = c; + continue; + } + *p++ = c; + } +} + +void +yywarn(char *s) +{ + extern int lineno; + + if (configfile == NULL) + fprintf(stderr, "Warning: %s\n", s); + else + fprintf(stderr, "Warning [%s, line %d]\n%s\n", + configfile, lineno, s); +} + +void +yyerror(const char *s) +{ + extern int lineno; + extern int stmt_type; + char c; + + markpos(); + + c = lastinput(); + for ( ; ; ) { + if (c == '\0') + break; + if (c == '\n') + break; +#ifdef FLEX_SCANNER + dbpmdaFlexInput (&c, 1); +#else + c = input(); +#endif + } + stmt_type = EOL; + + locateError(); + + if (configfile == NULL) + fprintf(stderr, "Error: %s\nType 'help' for a list of commands.\n", s); + else + fprintf(stderr, + "Error [%s, line %d]: %s\nType 'help' for a list of commands.\n", + configfile, lineno, s); + + +} diff --git a/src/dbpmda/src/pmda.c b/src/dbpmda/src/pmda.c new file mode 100644 index 0000000..d9b454b --- /dev/null +++ b/src/dbpmda/src/pmda.c @@ -0,0 +1,840 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 1995,2003,2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <sys/stat.h> +#include "pmapi.h" +#include "impl.h" + +#ifdef HAVE_VALUES_H +#include <values.h> +#endif +#include <float.h> +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif + +#include "./dbpmda.h" +#include "./lex.h" +#include "./gram.h" + +static __pmTimeval now = { 0, 0 }; + +int infd; +int outfd; +char *myPmdaName = 0; + +extern int _creds_timeout; + +#ifndef HAVE_STRTOLL +/* + * cheap hack ...won't work for large values! + */ +static __int64_t +strtoll(char *p, char **endp, int base) +{ + return (__int64_t)strtol(p, endp, base); +} +#endif + +#ifndef HAVE_STRTOULL +/* + * cheap hack ...won't work for large values! + */ +static __uint64_t +strtoull(char *p, char **endp, int base) +{ + return (__uint64_t)strtoul(p, endp, base); +} +#endif + +/* version exchange - get a credentials PDU from 2.0 agents */ + +static int +agent_creds(__pmPDU *pb) +{ + int i; + int sts = 0; + int version = UNKNOWN_VERSION; + int credcount = 0; + int sender = 0; + int vflag = 0; + __pmCred *credlist = NULL; + + if ((sts = __pmDecodeCreds(pb, &sender, &credcount, &credlist)) < 0) + return sts; + + for (i = 0; i < credcount; i++) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_CONTEXT) + fprintf(stderr, "agent_creds: doing cred #%d from PID %d\n", i+1, sender); +#endif + switch(credlist[i].c_type) { + case CVERSION: + version = credlist[i].c_vala; + vflag = 1; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_CONTEXT) + fprintf(stderr, "agent_creds: version cred (%u)\n", version); +#endif + break; + } + } + + if (credlist) + free(credlist); + + if (((sts = __pmSetVersionIPC(infd, version)) < 0) || + ((sts = __pmSetVersionIPC(outfd, version)) < 0)) + return sts; + + if (vflag) { /* complete the version exchange - respond to agent */ + __pmCred handshake[1]; + + handshake[0].c_type = CVERSION; + handshake[0].c_vala = PDU_VERSION; + handshake[0].c_valb = 0; + handshake[0].c_valc = 0; + if ((sts = __pmSendCreds(outfd, (int)getpid(), 1, handshake)) < 0) + return sts; + } + + return 0; +} + +static void +pmdaversion(void) +{ + int sts; + __pmPDU *ack; + int pinpdu; + + pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, _creds_timeout, &ack); + if (sts == PDU_CREDS) { + if ((sts = agent_creds(ack)) < 0) { + fprintf(stderr, "Warning: version exchange failed " + "for PMDA %s: %s\n", myPmdaName, pmErrStr(sts)); + } + } + else { + if (sts < 0) + fprintf(stderr, "__pmGetPDU(%d): %s\n", infd, pmErrStr(sts)); + else + fprintf(stderr, "pmdaversion: expecting PDU_CREDS, got PDU type %d\n", sts); + fprintf(stderr, "Warning: no version exchange with PMDA %s\n", + myPmdaName); + } + if (pinpdu > 0) + __pmUnpinPDUBuf(ack); +} + +void +openpmda(char *fname) +{ + int i; + struct stat buf; + + if (stat(fname, &buf) < 0) { + fprintf(stderr, "openpmda: %s: %s\n", fname, osstrerror()); + return; + } + + closepmda(); + free(param.argv[0]); + param.argv[0] = strdup(fname); + param.argc--; + printf("Start %s PMDA: %s", basename(param.argv[0]), fname); + for (i = 1; i < param.argc; i++) + printf(" %s", param.argv[i]); + putchar('\n'); + + if (__pmProcessCreate(param.argv, &infd, &outfd) < (pid_t)0) { + fprintf(stderr, "openpmda: create process: %s\n", osstrerror()); + } + else { + connmode = CONN_DAEMON; + reset_profile(); + if (myPmdaName != NULL) + free(myPmdaName); + myPmdaName = strdup(fname); + pmdaversion(); + } +} + +#ifdef HAVE_STRUCT_SOCKADDR_UN +void +open_unix_socket(char *fname) +{ + int fd; + struct stat buf; + struct sockaddr_un s_un; + int len; + + if (stat(fname, &buf) < 0) { + fprintf(stderr, "opensocket: %s: %s\n", fname, osstrerror()); + return; + } + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + fprintf(stderr, "opensocket: socket: %s\n", netstrerror()); + return; + } + + memset(&s_un, 0, sizeof(s_un)); + s_un.sun_family = AF_UNIX; + strncpy(s_un.sun_path, fname, strlen(fname)); + len = (int)offsetof(struct sockaddr_un, sun_path) + (int)strlen(s_un.sun_path); + + closepmda(); + + if (connect(fd, (struct sockaddr *)&s_un, len) < 0) { + fprintf(stderr, "opensocket: connect: %s\n", netstrerror()); + close(fd); + return; + } + + infd = fd; + outfd = fd; + + printf("Connect to PMDA on socket %s\n", fname); + + connmode = CONN_DAEMON; + reset_profile(); + if (myPmdaName != NULL) + free(myPmdaName); + myPmdaName = strdup(fname); + pmdaversion(); +} +#else +void +open_unix_socket(char *fname) +{ + __pmNotifyErr(LOG_CRIT, "UNIX domain sockets unsupported\n"); +} +#endif + +static void +open_socket(int port, int family, const char *protocol) +{ + __pmSockAddr *addr; + int fd, sts; + char socket[64]; + + fd = (family == AF_INET) ? __pmCreateSocket() : __pmCreateIPv6Socket(); + if (fd < 0) { + fprintf(stderr, "opensocket: socket: %s\n", netstrerror()); + return; + } + + addr = __pmLoopBackAddress(family); + if (addr == NULL) { + fprintf(stderr, "opensocket: loopback: %s\n", netstrerror()); + __pmCloseSocket(fd); + return; + } + + closepmda(); + + __pmSockAddrSetPort(addr, port); + sts = __pmConnect(fd, addr, __pmSockAddrSize()); + __pmSockAddrFree(addr); + + if (sts < 0) { + fprintf(stderr, "opensocket: connect: %s\n", netstrerror()); + __pmCloseSocket(fd); + return; + } + + infd = fd; + outfd = fd; + + sprintf(socket, "%s port %d", protocol, port); + printf("Connect to PMDA on %s\n", socket); + + connmode = CONN_DAEMON; + reset_profile(); + if (myPmdaName != NULL) + free(myPmdaName); + myPmdaName = strdup(socket); + pmdaversion(); +} + +void +open_inet_socket(int port) +{ + open_socket(port, AF_INET, "inet"); +} + +void +open_ipv6_socket(int port) +{ + open_socket(port, AF_INET6, "ipv6"); +} + +void +closepmda(void) +{ + if (connmode != NO_CONN) { + /* End of context logic mimics PMCD, no error checking is needed. */ + __pmSendError(outfd, FROM_ANON, PM_ERR_NOTCONN); + close(outfd); + close(infd); + __pmResetIPC(infd); + connmode = NO_CONN; + if (myPmdaName != NULL) { + free(myPmdaName); + myPmdaName = NULL; + } + } +} + + +int +dopmda_desc(pmID pmid, pmDesc *desc, int print) +{ + int sts; + __pmPDU *pb; + int i; + int pinpdu; + + if ((sts = __pmSendDescReq(outfd, FROM_ANON, pmid)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_DESC) { + if ((sts = __pmDecodeDesc(pb, desc)) >= 0) { + if (print) + __pmPrintDesc(stdout, desc); +#ifdef PCP_DEBUG + else if (pmDebug & DBG_TRACE_PDU) + __pmPrintDesc(stdout, desc); +#endif + } + else + printf("Error: __pmDecodeDesc() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else if (sts == 0) + printf("Error: __pmGetPDU() failed: PDU empty, PMDA may have died\n"); + else + printf("Error: __pmGetPDU() failed: wrong PDU (%x)\n", sts); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendDescReq() failed: %s\n", pmErrStr(sts)); + + return sts; +} + +void +dopmda(int pdu) +{ + int sts; + pmDesc desc; + pmDesc *desc_list = NULL; + pmResult *result = NULL; + __pmInResult *inresult; + __pmPDU *pb; + int i; + int j; + int ident; + int length; + char *buffer; + struct timeval start; + struct timeval end; + char name[32]; + char **namelist; + int *statuslist; + int numnames; + pmID pmid; + int pinpdu; + + if (timer != 0) + __pmtimevalNow(&start); + + switch (pdu) { + + case PDU_DESC_REQ: + printf("PMID: %s\n", pmIDStr(param.pmid)); + sts = dopmda_desc(param.pmid, &desc, 1); + 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: PDU fetch() failed: %s\n", pmErrStr(ENOMEM)); + return; + } + for (i = 0; i < param.numpmid; i++) { + if ((sts = dopmda_desc(param.pmidlist[i], &desc_list[i], 0)) < 0) { + free(desc_list); + return; + } + } + } + + sts = 0; + if (profile_changed) { + if ((sts = __pmSendProfile(outfd, FROM_ANON, 0, profile)) < 0) + printf("Error: __pmSendProfile() failed: %s\n", pmErrStr(sts)); + else + profile_changed = 0; + } + if (sts >= 0) { + if ((sts = __pmSendFetch(outfd, FROM_ANON, 0, NULL, param.numpmid, param.pmidlist)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_RESULT) { + if ((sts = __pmDecodeResult(pb, &result)) >= 0) { + if (get_desc) + _dbDumpResult(stdout, result, desc_list); + else + __pmDumpResult(stdout, result); + pmFreeResult(result); + } + else + printf("Error: __pmDecodeResult() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else if (sts == 0) + printf("Error: __pmGetPDU() failed: PDU empty, PMDA may have died\n"); + else + printf("Error: __pmGetPDU() failed: wrong PDU (%x)\n", sts); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendFetch() failed: %s\n", pmErrStr(sts)); + } + if (desc_list) + free(desc_list); + break; + + case PDU_INSTANCE_REQ: + printf("pmInDom: %s\n", pmInDomStr(param.indom)); + if ((sts = __pmSendInstanceReq(outfd, FROM_ANON, &now, param.indom, param.number, param.name)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_INSTANCE) { + if ((sts = __pmDecodeInstance(pb, &inresult)) >= 0) { + printindom(stdout, inresult); + __pmFreeInResult(inresult); + } + else + printf("Error: __pmDecodeInstance() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendInstanceReq() failed: %s\n", pmErrStr(sts)); + break; + + case PDU_RESULT: + printf("PMID: %s\n", pmIDStr(param.pmid)); + + printf("Getting description...\n"); + + if ((sts = dopmda_desc(param.pmid, &desc, 0)) < 0) + return; + + if (profile_changed) { + printf("Sending Profile...\n"); + if ((sts = __pmSendProfile(outfd, FROM_ANON, 0, profile)) < 0) { + printf("Error: __pmSendProfile() failed: %s\n", pmErrStr(sts)); + return; + } + else + profile_changed = 0; + } + + printf("Getting Result Structure...\n"); + pinpdu = 0; + if ((sts = __pmSendFetch(outfd, FROM_ANON, 0, NULL, + 1, &(desc.pmid))) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, + &pb)) == PDU_RESULT) { + if ((sts = __pmDecodeResult(pb, &result)) < 0) + printf("Error: __pmDecodeResult() failed: %s\n", + pmErrStr(sts)); +#ifdef PCP_DEBUG + else if (pmDebug & DBG_TRACE_FETCH) + __pmDumpResult(stdout, result); +#endif + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + } + else + printf("Error: __pmSendFetch() failed: %s\n", pmErrStr(sts)); + /* + * pb is still pinned, and result may contain pointers into + * a second PDU buffer from __pmDecodeResult() ... need to + * ensure all PDU buffers are unpinned once we're done with + * result or giving up + */ + + if (sts < 0) { + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + return; + } + + if ((sts = fillResult(result, desc.type)) < 0) { + pmFreeResult(result); + __pmUnpinPDUBuf(pb); + return; + } + + printf("Sending Result...\n"); + sts = __pmSendResult(outfd, FROM_ANON, result); + pmFreeResult(result); + __pmUnpinPDUBuf(pb); + if (sts >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, + &pb)) == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) { + if (sts < 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + } + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendResult() failed: %s\n", pmErrStr(sts)); + + break; + + case PDU_TEXT_REQ: + if (param.number == PM_TEXT_PMID) { + printf("PMID: %s\n", pmIDStr(param.pmid)); + ident = param.pmid; + } + else { + printf("pmInDom: %s\n", pmInDomStr(param.indom)); + ident = 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; + } + + if ((sts = __pmSendTextReq(outfd, FROM_ANON, ident, param.number)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_TEXT) { + if ((sts = __pmDecodeText(pb, &i, &buffer)) >= 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"); + free(buffer); + } + else + printf("Error: __pmDecodeText() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + + } + else + printf("Error: __pmSendTextReq() failed: %s\n", pmErrStr(sts)); + + } + break; + + case PDU_PMNS_IDS: + printf("PMID: %s\n", pmIDStr(param.pmid)); + if ((sts = __pmSendIDList(outfd, FROM_ANON, 1, ¶m.pmid, 0)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_PMNS_NAMES) { + if ((sts = __pmDecodeNameList(pb, &numnames, &namelist, NULL)) >= 0) { + for (i = 0; i < sts; i++) { + printf(" %s\n", namelist[i]); + } + free(namelist); + } + else + printf("Error: __pmDecodeNameList() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendIDList() failed: %s\n", pmErrStr(sts)); + break; + + case PDU_PMNS_NAMES: + printf("Metric: %s\n", param.name); + if ((sts = __pmSendNameList(outfd, FROM_ANON, 1, ¶m.name, NULL)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_PMNS_IDS) { + int xsts; + + if ((sts = __pmDecodeIDList(pb, 1, &pmid, &xsts)) >= 0) + printf(" %s\n", pmIDStr(pmid)); + else + printf("Error: __pmDecodeIDList() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendIDList() failed: %s\n", pmErrStr(sts)); + break; + + case PDU_PMNS_CHILD: + printf("Metric: %s\n", param.name); + if ((sts = __pmSendChildReq(outfd, FROM_ANON, param.name, 1)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_PMNS_NAMES) { + if ((sts = __pmDecodeNameList(pb, &numnames, &namelist, &statuslist)) >= 0) { + for (i = 0; i < numnames; i++) { + printf(" %8.8s %s\n", statuslist[i] == 1 ? "non-leaf" : "leaf", namelist[i]); + } + free(namelist); + free(statuslist); + } + else + printf("Error: __pmDecodeNameList() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendChildReq() failed: %s\n", pmErrStr(sts)); + break; + + case PDU_PMNS_TRAVERSE: + printf("Metric: %s\n", param.name); + if ((sts = __pmSendTraversePMNSReq(outfd, FROM_ANON, param.name)) >= 0) { + if ((pinpdu = sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb)) == PDU_PMNS_NAMES) { + if ((sts = __pmDecodeNameList(pb, &numnames, &namelist, NULL)) >= 0) { + for (i = 0; i < numnames; i++) { + printf(" %s\n", namelist[i]); + } + free(namelist); + } + else + printf("Error: __pmDecodeNameList() failed: %s\n", pmErrStr(sts)); + } + else if (sts == PDU_ERROR) { + if ((i = __pmDecodeError(pb, &sts)) >= 0) + printf("Error PDU: %s\n", pmErrStr(sts)); + else + printf("Error: __pmDecodeError() failed: %s\n", pmErrStr(i)); + } + else + printf("Error: __pmGetPDU() failed: %s\n", pmErrStr(sts)); + + if (pinpdu > 0) + __pmUnpinPDUBuf(pb); + } + else + printf("Error: __pmSendTraversePMNS() failed: %s\n", pmErrStr(sts)); + break; + + case PDU_AUTH: + j = param.number; /* attribute key */ + buffer = param.name; /* attribute value */ + length = !buffer ? 0 : strlen(buffer) + 1; /* value length */ + i = 0; /* client ID */ + + __pmAttrKeyStr_r(j, name, sizeof(name)-1); + name[sizeof(name)-1] = '\0'; + + printf("Attribute: %s=%s\n", name, buffer ? buffer : "''"); + if ((sts = __pmSendAuth(outfd, 0 /* context */, j, buffer, length)) >= 0) + printf("Success\n"); + else + printf("Error: __pmSendAuth() failed: %s\n", pmErrStr(sts)); + break; + + default: + printf("Error: Daemon PDU (%s) botch!\n", __pmPDUTypeStr(pdu)); + sts = PDU_ERROR; + break; + } + + if (sts >= 0 && timer != 0) { + __pmtimevalNow(&end); + printf("Timer: %f seconds\n", __pmtimevalSub(&end, &start)); + } +} + +int +fillResult(pmResult *result, int type) +{ + int i; + int sts = 0; + pmAtomValue atom; + pmValueSet *vsp; + char *endbuf = NULL; + + switch(type) { + case PM_TYPE_32: + atom.l = (int)strtol(param.name, &endbuf, 10); + break; + case PM_TYPE_U32: + atom.ul = (unsigned int)strtoul(param.name, &endbuf, 10); + break; + case PM_TYPE_64: + atom.ll = strtoll(param.name, &endbuf, 10); + break; + case PM_TYPE_U64: + atom.ull = strtoull(param.name, &endbuf, 10); + break; + case PM_TYPE_FLOAT: + atom.d = strtod(param.name, &endbuf); + if (atom.d < FLT_MIN || atom.d > FLT_MAX) + sts = -ERANGE; + else { + atom.f = atom.d; + } + break; + case PM_TYPE_DOUBLE: + atom.d = strtod(param.name, &endbuf); + break; + case PM_TYPE_STRING: + atom.cp = (char *)malloc(strlen(param.name) + 1); + if (atom.cp == NULL) + sts = -ENOMEM; + else { + strcpy(atom.cp, param.name); + endbuf = ""; + } + break; + default: + printf("Error: dbpmda does not support storing into %s metrics\n", pmTypeStr(type)); + sts = PM_ERR_TYPE; + } + + if (sts < 0) { + if (sts != PM_ERR_TYPE) + printf("Error: Decoding value: %s\n", pmErrStr(sts)); + } + else if (endbuf != NULL && *endbuf != '\0') { + printf("Error: Value \"%s\" is incompatible with metric type (PM_TYPE_%s)\n", + param.name, pmTypeStr(type)); + sts = PM_ERR_VALUE; + } + + if (sts >= 0) { + vsp = result->vset[0]; + + if (vsp->numval == 0) { + printf("Error: %s not available!\n", pmIDStr(param.pmid)); + return PM_ERR_VALUE; + } + + if (vsp->numval < 0) { + printf("Error: %s: %s\n", pmIDStr(param.pmid), pmErrStr(vsp->numval)); + return vsp->numval; + } + + for (i = 0; i < vsp->numval; i++) { + if (vsp->numval > 1) + printf("%s [%d]: ", pmIDStr(param.pmid), i); + else + printf("%s: ", pmIDStr(param.pmid)); + + pmPrintValue(stdout, vsp->valfmt, type, &vsp->vlist[i], 1); + vsp->valfmt = __pmStuffValue(&atom, &vsp->vlist[i], type); + printf(" -> "); + pmPrintValue(stdout, vsp->valfmt, type, &vsp->vlist[i], 1); + putchar('\n'); + } + } + + return sts; +} + diff --git a/src/dbpmda/src/util.c b/src/dbpmda/src/util.c new file mode 100644 index 0000000..c81832a --- /dev/null +++ b/src/dbpmda/src/util.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2013 Red Hat. + * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "./dbpmda.h" +#include "./lex.h" +#include "./gram.h" + +extern pmdaInterface dispatch; +extern int infd; +extern int outfd; + +__pmProfile *profile; +int profile_changed; +int timer; +int get_desc; + +static pmID *pmidlist; +static int numpmid; +static __pmContext *ctxp; + +static char **argv; +static int argc; + +/* + * Warning: order of these strings _must_ match bit field sequence defined + * in impl.h for DBG_TRACE_* macros + */ +static char* debugFlags[] = { + "pdu", "fetch", "profile", "value", "context", "indom", "pdubuf", "log", + "logmeta", "optfetch", "af", "appl0", "appl1", "appl2", "pmns", "libpmda", + "timecontrol", "pmc", "derive", "lock", "interp", "config", "loop", "fault" +}; + +static int numFlags = sizeof(debugFlags)/sizeof(debugFlags[0]); + +void +reset_profile(void) +{ + if ((profile = (__pmProfile *)realloc(profile, sizeof(__pmProfile))) == NULL) { + __pmNoMem("reset_profile", sizeof(__pmProfile), PM_FATAL_ERR); + exit(1); + } + ctxp->c_instprof = profile; + memset(profile, 0, sizeof(__pmProfile)); + profile->state = PM_PROFILE_INCLUDE; /* default global state */ + profile_changed = 1; +} + +void +setup_context(void) +{ + int sts; +#ifdef PM_MULTI_THREAD + pthread_mutex_t save_c_lock; +#endif + + if ((sts = pmNewContext(PM_CONTEXT_LOCAL, NULL)) < 0) { + fprintf(stderr, "setup_context: creation failed: %s\n", pmErrStr(sts)); + exit(1); + } + + ctxp = __pmHandleToPtr(sts); + if (ctxp == NULL) { + fprintf(stderr, "botch: setup_context: __pmHandleToPtr(%d) returns NULL!\n", sts); + exit(1); + } + /* + * Note: ctxp->c_lock remains locked throughout ... setup_context() + * is only called once, and a single context is used throughout + * to "fake" out the connection to the current PMDA ... so + * there is no PM_UNLOCK(ctxp->c_lock) anywhere in the dbpmda + * code. + * This works because ctxp->c_lock is a recursive lock and + * dbpmda is single-threaded. + */ + +#ifdef PM_MULTI_THREAD + /* need to be careful about the initialized lock */ + save_c_lock = ctxp->c_lock; +#endif + memset(ctxp, 0, sizeof(__pmContext)); +#ifdef PM_MULTI_THREAD + ctxp->c_lock = save_c_lock; +#endif + ctxp->c_type = PM_CONTEXT_HOST; + reset_profile(); +} + +char * +strcons(char *s1, char *s2) +{ + int i; + char *buf; + + i = (int)strlen(s1) + (int)strlen(s2) + 1; + + buf = (char *)malloc(i); + if (buf == NULL) { + fprintf(stderr, "strcons: malloc failed: %s\n", osstrerror()); + exit(1); + } + + strcpy(buf, s1); + strcat(buf, s2); + + return buf; +} + +char * +strnum(int n) +{ + char *buf; + + buf = (char *)malloc(13); + if (buf == NULL) { + fprintf(stderr, "strnum: malloc failed: %s\n", osstrerror()); + exit(1); + } + sprintf(buf, "%d", n); + return buf; +} + +void +initmetriclist(void) +{ + param.numpmid = 0; + param.pmidlist = NULL; +} + +void +addmetriclist(pmID pmid) +{ + param.numpmid++; + + if (param.numpmid >= numpmid) { + numpmid = param.numpmid; + pmidlist = (pmID *)realloc(pmidlist, numpmid * sizeof(pmidlist[0])); + if (pmidlist == NULL) { + fprintf(stderr, "addmetriclist: realloc failed: %s\n", osstrerror()); + exit(1); + } + } + + pmidlist[param.numpmid-1] = pmid; + param.pmidlist = pmidlist; +} + +void +initarglist(void) +{ + int i; + + for (i = 0; i < param.argc; i++) + if (param.argv[i] != NULL) + free(param.argv[i]); + param.argc = 0; + param.argv = NULL; + addarglist(""); +} + +void +addarglist(char *arg) +{ + param.argc++; + + if (param.argc >= argc) { + argc = param.argc; + argv = (char **)realloc(argv, argc * sizeof(pmProgname)); + if (argv == NULL) { + fprintf(stderr, "addarglist: realloc failed: %s\n", osstrerror()); + exit(1); + } + } + + if (arg != NULL) + argv[param.argc-1] = strdup(arg); + else + argv[param.argc-1] = arg; + param.argv = argv; +} + +void +watch(char *fname) +{ + char cmd[200]; + + sprintf(cmd, "xterm -hold -title \"dbpmda watch %s\" -geom 80x16 -bg dodgerblue4 -e tail -f %s &", + fname, fname); + + if (system(cmd) != 0) + fprintf(stderr, "watch cmd: %s failed: %s\n", cmd, pmErrStr(-oserror())); +} + +void +printindom(FILE *f, __pmInResult *irp) +{ + int i; + + for (i = 0; i < irp->numinst; i++) { + fprintf(f, "[%3d]", i); + if (irp->instlist != NULL) + fprintf(f, " inst: %d", irp->instlist[i]); + if (irp->namelist != NULL) + fprintf(f, " name: \"%s\"", irp->namelist[i]); + fputc('\n', f); + } +} + +void +dohelp(int command, int full) +{ + if (command < 0) { + puts("help [ command ]\n"); + dohelp(ATTR, HELP_USAGE); + dohelp(PMNS_CHILDREN, HELP_USAGE); + dohelp(CLOSE, HELP_USAGE); + dohelp(DBG, HELP_USAGE); + dohelp(DESC, HELP_USAGE); + dohelp(FETCH, HELP_USAGE); + dohelp(GETDESC, HELP_USAGE); + dohelp(INSTANCE, HELP_USAGE); + dohelp(PMNS_NAME, HELP_USAGE); + dohelp(NAMESPACE, HELP_USAGE); + dohelp(OPEN, HELP_USAGE); + dohelp(PMNS_PMID, HELP_USAGE); + dohelp(PROFILE, HELP_USAGE); + dohelp(QUIT, HELP_USAGE); + dohelp(STATUS, HELP_USAGE); + dohelp(STORE, HELP_USAGE); + dohelp(INFO, HELP_USAGE); + dohelp(TIMER, HELP_USAGE); + dohelp(PMNS_TRAVERSE, HELP_USAGE); + dohelp(WAIT, HELP_USAGE); + dohelp(WATCH, HELP_USAGE); + putchar('\n'); + } + else { + if (full == HELP_FULL) + putchar('\n'); + + switch (command) { + case ATTR: + puts("attr name [value]"); + puts("attr attr# [value]"); + break; + case CLOSE: + puts("close"); + break; + case DBG: + puts("debug all | none"); + puts("debug flag [ flag ... ] (flag is decimal or symbolic name)"); + break; + case DESC: + puts("desc metric"); + break; + case FETCH: + puts("fetch metric [ metric ... ]"); + break; + case GETDESC: + puts("getdesc on | off"); + break; + case INFO: + puts("text metric"); + puts("text indom indom#"); + break; + case INSTANCE: + puts("instance indom# [ number | name | \"name\" ]"); + break; + case NAMESPACE: + puts("namespace fname"); + break; + case OPEN: + puts("open dso dsoname init_routine [ domain# ]"); + puts("open pipe execname [ arg ... ]"); + puts("open socket unix sockname"); + puts("open socket inet port#|service"); + puts("open socket ipv6 port#|service"); + break; + case PMNS_CHILDREN: + puts("children metric-name"); + break; + case PMNS_NAME: + puts("name pmid#"); + break; + case PMNS_PMID: + puts("pmid metric-name"); + break; + case PMNS_TRAVERSE: + puts("traverse metric-name"); + break; + case PROFILE: + puts("profile indom# [ all | none ]"); + puts("profile indom# [ add | delete ] number"); + break; + case QUIT: + puts("quit"); + break; + case STATUS: + puts("status"); + break; + case STORE: + puts("store metric \"value\""); + break; + case WATCH: + puts("watch logfilename"); + break; + case TIMER: + puts("timer on | off"); + break; + case WAIT: + puts("wait seconds"); + break; + default: + fprintf(stderr, "Help for that command (%d) not supported!\n", command); + } + + if (full == HELP_FULL) { + putchar('\n'); + switch (command) { + case ATTR: + puts( +"Set a security attribute. These set aspects of per-user authentication,\n" +"allowing a PMDA to provide different metric views for different users.\n"); + break; + case CLOSE: + puts( +"Close the pipe to a daemon PMDA or dlclose(3) a DSO PMDA. dbpmda does not\n" +"exit, allowing another PMDA to be opened.\n"); + break; + case DBG: + puts( +"Specify which debugging flags should be active (see pmdbg(1)). Flags may\n" +"be specified as integers or by name, with multiple flags separated by\n" +"white space. All flags may be selected or deselected if 'all' or 'none' is\n" +"specified. The current setting is displayed by the status command.\n\n"); + break; + case DESC: + puts( +"Print out the meta data description for the 'metric'. The metric may be\n" +"specified by name, or as a PMID of the form N, N.N or N.N.N.\n"); + break; + case FETCH: + puts( +"Fetch metrics from the PMDA. The metrics may be specified as a list of\n" +"metric names, or PMIDs of the form N, N.N or N.N.N.\n"); + break; + case GETDESC: + puts( +"Before doing a fetch, get the descriptor so that the result of a fetch\n" +"can be printed out correctly.\n"); + break; + case INFO: + puts( +"Retrieve the help text for the 'metric' or 'indom' from the PMDA. The one\n" +"line message is shown between '[' and ']' with the long message on the next\n" +"line. To get the help text for an instance domain requires the word\n" +"``indom'' before the indom number\n"); + break; + case INSTANCE: + puts( +"List the instances in 'indom'. The list may be restricted to a specific\n" +"instance 'name' or 'number'.\n"); + break; + case NAMESPACE: + puts( +"Unload the current Name Space and load up the given Name Space.\n" +"If unsuccessful then will try to reload the previous Name Space.\n"); + break; + case OPEN: + puts( +"Open a PMDA as either a DSO, via a network socket (unix/inet/ipv6), or as a\n" +"daemon (connected with a pipe). The 'dsoname' and 'execname' fields are\n" +"the path to the PMDA shared object file or executable. The first socket PMDA\n" +"field is the type - either unix (if supported), inet or ipv6. The 'sockname'\n" +"argument for unix sockets is a path of a named pipe where a PMDA is listening\n" +"for connections. The 'port' argument is a port number, 'serv' a service name\n" +"typically defined in /etc/services (resolved to a port via getservent(3)).\n" +"The arguments to this command are similar to a line in the pmcd.conf file.\n"); + break; + case PMNS_CHILDREN: + puts( +"Fetch and print the next name component of the direct decendents of\n" +"metric-name in the PMNS, reporting for each if it is a leaf node or a\n" +"non-leaf node.\n" +"Most useful for PMDAs that support dynamic metrics in the PMNS.\n"); + break; + case PMNS_NAME: + puts( +"Print the name of the metric with PMID pmid#. The pmid# syntax follows\n" +"the source PMNS syntax, namely 3 numbers separated by '.' to encode\n" +"the domain, cluster and item components of the PMID, e.g.\n" +" name 29.0.1004\n" +"Most useful for PMDAs that support dynamic metrics in the PMNS.\n"); + break; + case PMNS_PMID: + puts( +"Print the PMID for the named metric\n" +"Most useful for PMDAs that support dynamic metrics in the PMNS.\n"); + break; + case PMNS_TRAVERSE: + puts( +"Fetch and print all of the decendent metric names below metric-name\n" +"in the PMNS.\n" +"Most useful for PMDAs that support dynamic metrics in the PMNS.\n"); + break; + case PROFILE: + puts( +"For the instance domain specified, the profile may be changed to include\n" +"'all' instances, no instances, add an instance or delete an instance.\n"); + break; + case QUIT: + puts("Exit dbpmda. This also closes any open PMDAs.\n"); + break; + case STATUS: + puts( +"Display the state of dbpmda, including which PMDA is connected, which\n" +"pmDebug flags are set, and the current profile.\n"); + break; + case STORE: + puts( +"Store the value (int, real or string) into the 'metric'. The metric may be\n" +"specified by name or as a PMID with the format N, N.N, N.N.N. The value to\n" +"be stored must be enclosed in quotes. Unlike the other commands, a store\n" +"must request a metric description and fetch the metric to determine how to\n" +"interpret the value, and to allocate the PDU for transmitting the value,\n" +"respectively. The current profile will be used.\n"); + break; + case TIMER: + puts( +"Report the response time of the PMDA when sending and receiving PDUs.\n"); + break; + case WATCH: + puts( +"A xwsh window is opened which tails the specified log file. This window\n" +"must be closed by the user when no longer required.\n"); + break; + case WAIT: + puts("Sleep for this number of seconds\n"); + break; + } + } + } +} + +void +dostatus(void) +{ + int i = 0; + + putchar('\n'); + printf("Namespace: "); + if (cmd_namespace != NULL) + printf("%s\n", cmd_namespace); + else { + if (pmnsfile == NULL) + printf("(default)\n"); + else + printf("%s\n", pmnsfile); + } + + if (myPmdaName == NULL || connmode == NO_CONN) + printf("PMDA: none\n"); + else { + printf("PMDA: %s\n", myPmdaName); + printf("Connection: "); + switch (connmode) { + case CONN_DSO: + printf("dso\n"); + printf("DSO Interface Version: %d\n", dispatch.comm.pmda_interface); + printf("PMDA PMAPI Version: %d\n", dispatch.comm.pmapi_version); + break; + case CONN_DAEMON: + printf("daemon\n"); + printf("PMDA PMAPI Version: "); + i = __pmVersionIPC(infd); + if (i == UNKNOWN_VERSION) + printf("unknown!\n"); + else + printf("%d\n", i); + break; + default: + printf("unknown!\n"); + break; + } + } + + printf("pmDebug: "); + if (pmDebug == (unsigned int) -1) + printf("-1 (all)\n"); + else if (pmDebug == 0) + printf("0 (none)\n"); + else { + printf("%u", pmDebug); + for (i = 0; i < numFlags; i++) + if (pmDebug & (1 << i)) { + printf(" ( %s", debugFlags[i]); + break; + } + for (i++; i < numFlags; i++) + if (pmDebug & (1 << i)) + printf(" + %s", debugFlags[i]); + printf(" )\n"); + } + + printf("Timer: "); + if (timer == 0) + printf("off\n"); + else + printf("on\n"); + + printf("Getdesc: "); + if (get_desc == 0) + printf("off\n"); + else + printf("on\n"); + + putchar('\n'); + __pmDumpProfile(stdout, PM_INDOM_NULL, profile); + putchar('\n'); +} + + +/* + * Modified version of __pmDumpResult to use a descriptor list + * instead of calling pmLookupDesc. + * Notes: + * - desc_list should not be NULL + */ + +void +_dbDumpResult(FILE *f, pmResult *resp, pmDesc *desc_list) +{ + int i; + int j; + int n; + char *p; + + fprintf(f,"pmResult dump from " PRINTF_P_PFX "%p timestamp: %d.%06d ", + resp, (int)resp->timestamp.tv_sec, (int)resp->timestamp.tv_usec); + __pmPrintStamp(f, &resp->timestamp); + fprintf(f, " numpmid: %d\n", resp->numpmid); + for (i = 0; i < resp->numpmid; i++) { + pmValueSet *vsp = resp->vset[i]; + n = pmNameID(vsp->pmid, &p); + if (n < 0) + fprintf(f," %s (%s):", pmIDStr(vsp->pmid), "<noname>"); + else { + fprintf(f," %s (%s):", pmIDStr(vsp->pmid), p); + free(p); + } + if (vsp->numval == 0) { + fprintf(f, " No values returned!\n"); + continue; + } + else if (vsp->numval < 0) { + fprintf(f, " %s\n", pmErrStr(vsp->numval)); + continue; + } + fprintf(f, " numval: %d", vsp->numval); + fprintf(f, " valfmt: %d vlist[]:\n", vsp->valfmt); + for (j = 0; j < vsp->numval; j++) { + pmValue *vp = &vsp->vlist[j]; + if (vsp->numval > 1 || desc_list[i].indom != PM_INDOM_NULL) { + fprintf(f," inst [%d", vp->inst); + fprintf(f, " or ???]"); + fputc(' ', f); + } + else + fprintf(f, " "); + fprintf(f, "value "); + pmPrintValue(f, vsp->valfmt, desc_list[i].type, vp, 1); + fputc('\n', f); + }/*for*/ + }/*for*/ +}/*_dbDumpResult*/ |