summaryrefslogtreecommitdiff
path: root/src/pmstore
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
committerIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
commit47e6e7c84f008a53061e661f31ae96629bc694ef (patch)
tree648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmstore
downloadpcp-47e6e7c84f008a53061e661f31ae96629bc694ef.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmstore')
-rw-r--r--src/pmstore/GNUmakefile32
-rw-r--r--src/pmstore/pmstore.c385
2 files changed, 417 insertions, 0 deletions
diff --git a/src/pmstore/GNUmakefile b/src/pmstore/GNUmakefile
new file mode 100644
index 0000000..e04cdd9
--- /dev/null
+++ b/src/pmstore/GNUmakefile
@@ -0,0 +1,32 @@
+#
+# 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
+
+CFILES = pmstore.c
+CMDTARGET = pmstore$(EXECSUFFIX)
+LLDLIBS = $(PCPLIB)
+LDIRT = $(TARGET)
+
+default: $(CMDTARGET)
+
+include $(BUILDRULES)
+
+install: $(CMDTARGET)
+ $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET)
+
+default_pcp: default
+
+install_pcp: install
diff --git a/src/pmstore/pmstore.c b/src/pmstore/pmstore.c
new file mode 100644
index 0000000..5dcacb0
--- /dev/null
+++ b/src/pmstore/pmstore.c
@@ -0,0 +1,385 @@
+/*
+ * pmstore [-h hostname ] [-i inst[,inst...]] [-n pmnsfile ] metric value
+ *
+ * Copyright (c) 2013-2014 Red Hat.
+ * Copyright (c) 1995,2004-2008 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"
+#include <ctype.h>
+#include <limits.h>
+#ifdef HAVE_VALUES_H
+#include <values.h>
+#endif
+#include <float.h>
+
+#define IS_UNKNOWN 15
+#define IS_STRING 1
+#define IS_INTEGER 2
+#define IS_FLOAT 4
+#define IS_HEX 8
+
+static pmLongOptions longopts[] = {
+ PMAPI_OPTIONS_HEADER("General options"),
+ PMOPT_DEBUG,
+ PMOPT_HOST,
+ PMOPT_LOCALPMDA,
+ PMOPT_SPECLOCAL,
+ PMOPT_NAMESPACE,
+ PMOPT_HELP,
+ PMAPI_OPTIONS_HEADER("Value options"),
+ { "force", 0, 'f', 0, "store the value even if there is no current value set" },
+ { "insts", 1, 'i', "INSTS", "restrict store to comma-separated list of instances" },
+ PMAPI_OPTIONS_END
+};
+
+static pmOptions opts = {
+ .flags = PM_OPTFLAG_POSIX,
+ .short_options = "D:fh:K:Li:n:?",
+ .long_options = longopts,
+ .short_usage = "[options] metricname value",
+};
+
+#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
+
+static void
+mkAtom(pmAtomValue *avp, int type, char *buf)
+{
+ char *p = buf;
+ char *endbuf;
+ int vtype = IS_UNKNOWN;
+ int seendot = 0;
+ int base;
+ double d;
+ __int64_t temp_l;
+ __uint64_t temp_ul;
+
+ /*
+ * for strtol() et al, start with optional white space, then
+ * optional sign, then optional hex prefix, then stuff ...
+ */
+ p = buf;
+ while (*p && isspace((int)*p)) p++;
+ if (*p && *p == '-') p++;
+
+ if (*p && *p == '0' && p[1] && tolower((int)p[1]) == 'x') {
+ p += 2;
+ }
+ else {
+ vtype &= ~IS_HEX; /* hex MUST start with 0x or 0X */
+ }
+
+ /*
+ * does it smell like a hex number or a floating point number?
+ */
+ while (*p) {
+ if (!isdigit((int)*p)) {
+ vtype &= ~IS_INTEGER;
+ if (!isxdigit((int)*p) ) {
+ vtype &= ~IS_HEX;
+ if (*p == '.')
+ seendot++;
+ }
+ }
+ p++;
+ }
+
+ if (seendot != 1)
+ /* more or less than one '.' and it is not a floating point number */
+ vtype &= ~IS_FLOAT;
+
+ endbuf = buf;
+ base = (vtype & IS_HEX) ? 16:10;
+
+ switch (type) {
+ case PM_TYPE_32:
+ temp_l = strtol(buf, &endbuf, base);
+ if (oserror() != ERANGE) {
+ /*
+ * ugliness here is for cases where pmstore is compiled
+ * 64-bit (e.g. on ia64) and then strtol() may return
+ * values larger than 32-bits with no error indication
+ * ... if this is being compiled 32-bit, then the
+ * condition will be universally false, and a smart
+ * compiler may notice and warn.
+ */
+#ifdef HAVE_64BIT_LONG
+ if (temp_l > 0x7fffffffLL || temp_l < (-0x7fffffffLL - 1))
+ setoserror(ERANGE);
+ else
+#endif
+ {
+ avp->l = (__int32_t)temp_l;
+ }
+ }
+ break;
+
+ case PM_TYPE_U32:
+ temp_ul = strtoul(buf, &endbuf, base);
+ if (oserror() != ERANGE) {
+#ifdef HAVE_64BIT_LONG
+ if (temp_ul > 0xffffffffLL)
+ setoserror(ERANGE);
+ else
+#endif
+ {
+ avp->ul = (__uint32_t)temp_ul;
+ }
+ }
+ break;
+
+ case PM_TYPE_64:
+ avp->ll = strtoll(buf, &endbuf, base);
+ /* trust library to set error code to ERANGE as appropriate */
+ break;
+
+ case PM_TYPE_U64:
+ /* trust library to set error code to ERANGE as appropriate */
+ avp->ull = strtoull(buf, &endbuf, base);
+ break;
+
+ case PM_TYPE_FLOAT:
+ if (vtype & IS_HEX) {
+ /* strtod from GNU libc would try to convert it using some
+ * strange algo - we don't want it */
+ endbuf = buf;
+ }
+ else {
+ d = strtod(buf, &endbuf);
+ if (d < FLT_MIN || d > FLT_MAX)
+ setoserror(ERANGE);
+ else {
+ avp->f = (float)d;
+ }
+ }
+ break;
+
+ case PM_TYPE_DOUBLE:
+ if (vtype & IS_HEX) {
+ /* strtod from GNU libc would try to convert it using some
+ * strange algo - we don't want it */
+ endbuf = buf;
+ }
+ else {
+ avp->d = strtod(buf, &endbuf);
+ }
+ break;
+
+ case PM_TYPE_STRING:
+ if ((avp->cp = strdup(buf)) == NULL) {
+ __pmNoMem("pmstore", strlen(buf)+1, PM_FATAL_ERR);
+ }
+ endbuf = "";
+ break;
+
+ }
+ if (*endbuf != '\0') {
+ fprintf(stderr,
+ "The value \"%s\" is incompatible with the data "
+ "type (PM_TYPE_%s)\n",
+ buf, pmTypeStr(type));
+ exit(1);
+ }
+ if (oserror() == ERANGE) {
+ fprintf(stderr,
+ "The value \"%s\" is out of range for the data "
+ "type (PM_TYPE_%s)\n",
+ buf, pmTypeStr(type));
+ exit(1);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int sts;
+ int n;
+ int c;
+ int i;
+ char *p;
+ char *source;
+ char *namelist[1];
+ pmID pmidlist[1];
+ pmResult *result;
+ char **instnames = NULL;
+ int numinst = 0;
+ int force = 0;
+ pmDesc desc;
+ pmAtomValue nav;
+ pmValueSet *vsp;
+ char *subopt;
+
+ while ((c = pmGetOptions(argc, argv, &opts)) != EOF) {
+ switch (c) {
+ case 'f':
+ force++;
+ break;
+
+ case 'i': /* list of instances */
+#define WHITESPACE ", \t\n"
+ subopt = strtok(opts.optarg, WHITESPACE);
+ while (subopt != NULL) {
+ numinst++;
+ n = numinst * sizeof(char *);
+ instnames = (char **)realloc(instnames, n);
+ if (instnames == NULL)
+ __pmNoMem("pmstore.instnames", n, PM_FATAL_ERR);
+ instnames[numinst-1] = subopt;
+ subopt = strtok(NULL, WHITESPACE);
+ }
+#undef WHITESPACE
+ break;
+
+ default:
+ opts.errors++;
+ break;
+ }
+ }
+
+ if (opts.errors || opts.optind != argc - 2) {
+ pmUsageMessage(&opts);
+ exit(1);
+ }
+
+ if (opts.context == PM_CONTEXT_HOST)
+ source = opts.hosts[0];
+ else if (opts.context == PM_CONTEXT_LOCAL)
+ source = NULL;
+ else {
+ opts.context = PM_CONTEXT_HOST;
+ source = "local:";
+ }
+ if ((sts = pmNewContext(opts.context, source)) < 0) {
+ if (opts.context == PM_CONTEXT_LOCAL)
+ fprintf(stderr, "%s: Cannot make standalone local connection: %s\n",
+ pmProgname, pmErrStr(sts));
+ else
+ fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n",
+ pmProgname, source, pmErrStr(sts));
+ exit(1);
+ }
+
+ namelist[0] = argv[opts.optind++];
+ if ((n = pmLookupName(1, namelist, pmidlist)) < 0) {
+ printf("%s: pmLookupName: %s\n", namelist[0], pmErrStr(n));
+ exit(1);
+ }
+ if (pmidlist[0] == PM_ID_NULL) {
+ printf("%s: unknown metric\n", namelist[0]);
+ exit(1);
+ }
+ if ((n = pmLookupDesc(pmidlist[0], &desc)) < 0) {
+ printf("%s: pmLookupDesc: %s\n", namelist[0], pmErrStr(n));
+ exit(1);
+ }
+ if (desc.type == PM_TYPE_AGGREGATE || desc.type == PM_TYPE_AGGREGATE_STATIC) {
+ fprintf(stderr, "%s: Cannot modify values for PM_TYPE_AGGREGATE metrics\n",
+ pmProgname);
+ exit(1);
+ }
+ if (desc.type == PM_TYPE_EVENT || desc.type == PM_TYPE_HIGHRES_EVENT) {
+ fprintf(stderr, "%s: Cannot modify values for event type metrics\n",
+ pmProgname);
+ exit(1);
+ }
+ if (instnames != NULL) {
+ pmDelProfile(desc.indom, 0, NULL);
+ for (i = 0; i < numinst; i++) {
+ if ((n = pmLookupInDom(desc.indom, instnames[i])) < 0) {
+ printf("pmLookupInDom %s[%s]: %s\n",
+ namelist[0], instnames[i], pmErrStr(n));
+ exit(1);
+ }
+ if ((sts = pmAddProfile(desc.indom, 1, &n)) < 0) {
+ printf("pmAddProfile %s[%s]: %s\n",
+ namelist[0], instnames[i], pmErrStr(sts));
+ exit(1);
+ }
+ }
+ }
+ if ((n = pmFetch(1, pmidlist, &result)) < 0) {
+ printf("%s: pmFetch: %s\n", namelist[0], pmErrStr(n));
+ exit(1);
+ }
+
+ /* value is argv[opts.optind] */
+ mkAtom(&nav, desc.type, argv[opts.optind]);
+
+ vsp = result->vset[0];
+ if (vsp->numval < 0) {
+ printf("%s: Error: %s\n", namelist[0], pmErrStr(vsp->numval));
+ exit(1);
+ }
+
+ if (vsp->numval == 0) {
+ if (!force) {
+ printf("%s: No value(s) available!\n", namelist[0]);
+ exit(1);
+ }
+ else {
+ pmAtomValue tmpav;
+
+ mkAtom(&tmpav, PM_TYPE_STRING, "(none)");
+
+ vsp->numval = 1;
+ vsp->valfmt = __pmStuffValue(&tmpav, &vsp->vlist[0], PM_TYPE_STRING);
+ }
+ }
+
+ for (i = 0; i < vsp->numval; i++) {
+ pmValue *vp = &vsp->vlist[i];
+ printf("%s", namelist[0]);
+ if (desc.indom != PM_INDOM_NULL) {
+ if ((n = pmNameInDom(desc.indom, vp->inst, &p)) < 0)
+ printf(" inst [%d]", vp->inst);
+ else {
+ printf(" inst [%d or \"%s\"]", vp->inst, p);
+ free(p);
+ }
+ }
+ printf(" old value=");
+ pmPrintValue(stdout, vsp->valfmt, desc.type, vp, 1);
+ vsp->valfmt = __pmStuffValue(&nav, &vsp->vlist[i], desc.type);
+ printf(" new value=");
+ pmPrintValue(stdout, vsp->valfmt, desc.type, vp, 1);
+ putchar('\n');
+ }
+ if ((n = pmStore(result)) < 0) {
+ printf("%s: pmStore: %s\n", namelist[0], pmErrStr(n));
+ exit(1);
+ }
+ pmFreeResult(result);
+ exit(0);
+}