summaryrefslogtreecommitdiff
path: root/src/dbpmda/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbpmda/src/util.c')
-rw-r--r--src/dbpmda/src/util.c587
1 files changed, 587 insertions, 0 deletions
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*/