From: Florian Forster Date: Wed, 15 Jul 2020 12:01:18 +0000 (+0200) Subject: cmds: Implement the "PUTMETRIC" command. X-Git-Tag: 6.0.0-rc0~144^2~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2a3285726c93b238fcfe93ed73bae46751006efe;p=thirdparty%2Fcollectd.git cmds: Implement the "PUTMETRIC" command. --- diff --git a/Makefile.am b/Makefile.am index e55b03223..1e906133b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -552,6 +552,8 @@ libcmds_la_SOURCES = \ src/utils/cmds/getval.h \ src/utils/cmds/listval.c \ src/utils/cmds/listval.h \ + src/utils/cmds/putmetric.c \ + src/utils/cmds/putmetric.h \ src/utils/cmds/putnotif.c \ src/utils/cmds/putnotif.h \ src/utils/cmds/putval.c \ @@ -565,6 +567,7 @@ test_utils_cmds_SOURCES = \ src/testing.h test_utils_cmds_LDADD = \ libcmds.la \ + libmetric.la \ libplugin_mock.la liblookup_la_SOURCES = \ diff --git a/src/daemon/plugin_mock.c b/src/daemon/plugin_mock.c index 788503fc6..d8a1b67bf 100644 --- a/src/daemon/plugin_mock.c +++ b/src/daemon/plugin_mock.c @@ -121,6 +121,8 @@ DECLARE_UNREGISTER(notification) int plugin_dispatch_values(value_list_t const *vl) { return ENOTSUP; } +int plugin_dispatch_metric_family(metric_family_t const *fam) { return ENOTSUP; } + int plugin_dispatch_notification(__attribute__((unused)) const notification_t *notif) { return ENOTSUP; diff --git a/src/daemon/utils_cache_mock.c b/src/daemon/utils_cache_mock.c index d984c7e9b..e73ac2847 100644 --- a/src/daemon/utils_cache_mock.c +++ b/src/daemon/utils_cache_mock.c @@ -40,6 +40,10 @@ int uc_get_rate(__attribute__((unused)) metric_t const *m, return ENOTSUP; } +int uc_get_rate_by_name(const char *name, gauge_t *ret_value) { + return ENOTSUP; +} + int uc_get_rate_by_name_vl(const char *name, gauge_t **ret_values, size_t *ret_values_num) { return ENOTSUP; diff --git a/src/utils/cmds/cmds.c b/src/utils/cmds/cmds.c index 036cefa17..6994cf2fa 100644 --- a/src/utils/cmds/cmds.c +++ b/src/utils/cmds/cmds.c @@ -32,6 +32,7 @@ #include "utils/cmds/listval.h" #include "utils/cmds/parse_option.h" #include "utils/cmds/putval.h" +#include "utils/cmds/putmetric.h" #include "utils/common/common.h" #include @@ -211,6 +212,10 @@ cmd_status_t cmd_parsev(size_t argc, char **argv, cmd_t *ret_cmd, ret_cmd->type = CMD_PUTVAL; status = cmd_parse_putval(argc - 1, argv + 1, &ret_cmd->cmd.putval, opts, err); + } else if (strcasecmp("PUTMETRIC", command) == 0) { + ret_cmd->type = CMD_PUTMETRIC; + status = + cmd_parse_putmetric(argc - 1, argv + 1, &ret_cmd->cmd.putmetric, opts, err); } else { ret_cmd->type = CMD_UNKNOWN; cmd_error(CMD_UNKNOWN_COMMAND, err, "Unknown command `%s'.", command); @@ -255,6 +260,9 @@ void cmd_destroy(cmd_t *cmd) { case CMD_PUTVAL: cmd_destroy_putval(&cmd->cmd.putval); break; + case CMD_PUTMETRIC: + cmd_destroy_putmetric(&cmd->cmd.putmetric); + break; } } /* void cmd_destroy */ diff --git a/src/utils/cmds/cmds.h b/src/utils/cmds/cmds.h index 1e0e6fccf..b6c9a54ec 100644 --- a/src/utils/cmds/cmds.h +++ b/src/utils/cmds/cmds.h @@ -37,6 +37,7 @@ typedef enum { CMD_GETVAL = 2, CMD_LISTVAL = 3, CMD_PUTVAL = 4, + CMD_PUTMETRIC = 5, } cmd_type_t; #define CMD_TO_STRING(type) \ ((type) == CMD_FLUSH) \ @@ -45,7 +46,8 @@ typedef enum { ? "GETVAL" \ : ((type) == CMD_LISTVAL) \ ? "LISTVAL" \ - : ((type) == CMD_PUTVAL) ? "PUTVAL" : "UNKNOWN" + : ((type) == CMD_PUTVAL) ? "PUTVAL" \ + : ((type) == CMD_PUTMETRIC) ? "PUTMETRIC" : "UNKNOWN" typedef struct { double timeout; @@ -77,6 +79,19 @@ typedef struct { metric_family_t *family; } cmd_putval_t; +typedef struct { + /* Depending on the function, this is an input or output field: + * + * cmd_parse_putmetric: + * OUTPUT Receives parsed metric information. The metric family will + * contain a single metric. + * cmd_create_putmetric: + * INPUT Holds the metrics for which to format the PUTVAL command. The + * metric family may contain multiple metrics. + */ + metric_family_t *family; +} cmd_putmetric_t; + /* * NAME * cmd_t @@ -90,6 +105,7 @@ typedef struct { cmd_flush_t flush; cmd_getval_t getval; cmd_putval_t putval; + cmd_putmetric_t putmetric; } cmd; } cmd_t; diff --git a/src/utils/cmds/cmds_test.c b/src/utils/cmds/cmds_test.c index 9e7882031..d95fd59ab 100644 --- a/src/utils/cmds/cmds_test.c +++ b/src/utils/cmds/cmds_test.c @@ -29,9 +29,12 @@ * Explicit order is required or _FILE_OFFSET_BITS will have definition mismatches on Solaris * See Github Issue #3193 for details */ +#include "utils/cmds/cmds.h" + #include "utils/common/common.h" +#include "utils/strbuf/strbuf.h" #include "testing.h" -#include "utils/cmds/cmds.h" +#include "utils/cmds/putmetric.h" // clang-format on static void error_cb(void *ud, cmd_status_t status, const char *format, @@ -39,10 +42,20 @@ static void error_cb(void *ud, cmd_status_t status, const char *format, if (status == CMD_OK) return; - printf("ERROR[%d]: ", status); - vprintf(format, ap); - printf("\n"); - fflush(stdout); + strbuf_t *buf = ud; + + strbuf_printf(buf, "ERROR[%d]: ", status); + + va_list ap_copy; + va_copy(ap_copy, ap); + + int size = vsnprintf(NULL, 0, format, ap_copy); + assert(size > 0); + + char buffer[size]; + vsnprintf(buffer, sizeof(buffer), format, ap); + + strbuf_print(buf, buffer); } /* void error_cb */ static cmd_options_t default_host_opts = { @@ -168,6 +181,12 @@ static struct { }, /* Valid PUTVAL commands. */ + { + "PUTVAL unit_test N:42", + &default_host_opts, + CMD_OK, + CMD_PUTVAL, + }, { "PUTVAL magic/MAGIC N:42", &default_host_opts, @@ -276,6 +295,68 @@ static struct { }, */ + /* Valid PUTMETRIC commands. */ + { + "PUTMETRIC unit_test 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC gauge type=GAUGE 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC counter type=Counter 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC untyped type=untyped 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC quoted_gauge type=\"GAUGE\" 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC with_interval interval=10.0 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC with_time time=1594806526 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC with_label label:unquoted=bare 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC with_label label:quoted=\"with space\" 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + { + "PUTMETRIC multiple_label label:foo=1 label:bar=2 42", + NULL, + CMD_OK, + CMD_PUTMETRIC, + }, + /* Invalid commands. */ { "INVALID", @@ -292,21 +373,18 @@ static struct { }; DEF_TEST(parse) { - cmd_error_handler_t err = {error_cb, NULL}; int test_result = 0; for (size_t i = 0; i < STATIC_ARRAY_SIZE(parse_data); i++) { char *input = strdup(parse_data[i].input); - char description[1024]; - cmd_status_t status; - cmd_t cmd; - - bool result; + strbuf_t errbuf = STRBUF_CREATE; + cmd_error_handler_t err = {error_cb, &errbuf}; - memset(&cmd, 0, sizeof(cmd)); + cmd_t cmd = {0}; + cmd_status_t status = cmd_parse(input, &cmd, parse_data[i].opts, &err); - status = cmd_parse(input, &cmd, parse_data[i].opts, &err); + char description[1024]; ssnprintf(description, sizeof(description), "cmd_parse (\"%s\", opts=%p) = " "%d (type=%d [%s]); want %d " @@ -315,8 +393,14 @@ DEF_TEST(parse) { CMD_TO_STRING(cmd.type), parse_data[i].expected_status, parse_data[i].expected_type, CMD_TO_STRING(parse_data[i].expected_type)); - result = (status == parse_data[i].expected_status) && - (cmd.type == parse_data[i].expected_type); + + bool result = (status == parse_data[i].expected_status) && + (cmd.type == parse_data[i].expected_type); + + if (errbuf.ptr != NULL) { + printf("error buffer = \"%s\"\n", errbuf.ptr); + } + LOG(result, description); /* Run all tests before failing. */ @@ -330,7 +414,113 @@ DEF_TEST(parse) { return test_result; } +DEF_TEST(format_putmetric) { + struct { + metric_t m; + char *want; + int want_err; + } cases[] = { + { + .m = + { + .family = + &(metric_family_t){ + .name = "test", + .type = METRIC_TYPE_UNTYPED, + }, + .value.gauge = 42, + }, + .want = "PUTMETRIC test 42", + }, + { + .m = + { + .family = + &(metric_family_t){ + .name = "test", + .type = METRIC_TYPE_GAUGE, + }, + .value.gauge = 42, + }, + .want = "PUTMETRIC test type=GAUGE 42", + }, + { + .m = + { + .family = + &(metric_family_t){ + .name = "test", + .type = METRIC_TYPE_COUNTER, + }, + .value.counter = 42, + }, + .want = "PUTMETRIC test type=COUNTER 42", + }, + { + .m = + { + .family = + &(metric_family_t){ + .name = "test", + .type = METRIC_TYPE_UNTYPED, + }, + .value.gauge = 42, + .time = TIME_T_TO_CDTIME_T(1594809888), + }, + .want = "PUTMETRIC test time=1594809888.000 42", + }, + { + .m = + { + .family = + &(metric_family_t){ + .name = "test", + .type = METRIC_TYPE_UNTYPED, + }, + .value.gauge = 42, + .interval = TIME_T_TO_CDTIME_T(10), + }, + .want = "PUTMETRIC test interval=10.000 42", + }, + { + .m = + { + .family = + &(metric_family_t){ + .name = "test", + .type = METRIC_TYPE_UNTYPED, + }, + .value.gauge = 42, + .label.ptr = + &(label_pair_t){ + .name = "foo", + .value = "with \"quotes\"", + }, + .label.num = 1, + }, + .want = "PUTMETRIC test label:foo=\"with \\\"quotes\\\"\" 42", + }, + }; + + for (size_t i = 0; i < STATIC_ARRAY_SIZE(cases); i++) { + strbuf_t buf = STRBUF_CREATE; + + EXPECT_EQ_INT(cases[i].want_err, cmd_format_putmetric(&buf, &cases[i].m)); + if (cases[i].want_err) { + STRBUF_DESTROY(buf); + continue; + } + + EXPECT_EQ_STR(cases[i].want, buf.ptr); + + STRBUF_DESTROY(buf); + } + + return 0; +} + int main(int argc, char **argv) { RUN_TEST(parse); + RUN_TEST(format_putmetric); END_TEST; } diff --git a/src/utils/cmds/putmetric.c b/src/utils/cmds/putmetric.c new file mode 100644 index 000000000..d5727297a --- /dev/null +++ b/src/utils/cmds/putmetric.c @@ -0,0 +1,278 @@ +/** + * collectd - src/utils_cmd_putmetric.c + * Copyright (C) 2007-2009 Florian octo Forster + * Copyright (C) 2016 Sebastian tokkee Harl + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Florian octo Forster + * Sebastian tokkee Harl + **/ + +#include "collectd.h" + +#include "utils/cmds/putmetric.h" +#include "utils/common/common.h" + +/* + * private helper functions + */ + +/* TODO(octo): add an option to set metric->value_type */ +static int set_option(metric_t *m, char const *key, char const *value, + cmd_error_handler_t *err) { + if ((m == NULL) || (key == NULL) || (value == NULL)) + return -1; + + printf("set_option(\"%s\", \"%s\")\n", key, value); + + if (strcasecmp("type", key) == 0) { + if (strcasecmp("GAUGE", value) == 0) { + m->family->type = METRIC_TYPE_GAUGE; + } else if (strcasecmp("COUNTER", value) == 0) { + m->family->type = METRIC_TYPE_COUNTER; + } else if (strcasecmp("UNTYPED", value) == 0) { + m->family->type = METRIC_TYPE_UNTYPED; + } else { + return CMD_ERROR; + } + } else if (strcasecmp("interval", key) == 0) { + errno = 0; + char *endptr = NULL; + double d = strtod(value, &endptr); + + if ((errno != 0) || (endptr == NULL) || (*endptr != 0) || (d < 0)) { + return CMD_ERROR; + } + m->interval = DOUBLE_TO_CDTIME_T(d); + } else if (strcasecmp("time", key) == 0) { + errno = 0; + char *endptr = NULL; + double d = strtod(value, &endptr); + + if ((errno != 0) || (endptr == NULL) || (*endptr != 0) || (d < 0)) { + return CMD_ERROR; + } + m->time = DOUBLE_TO_CDTIME_T(d); + } else if (strncasecmp("label:", key, 5) == 0) { + char const *name = key + strlen("label:"); + return metric_label_set(m, name, value) ? CMD_ERROR : CMD_OK; + } else { + return CMD_ERROR; + } + return CMD_OK; +} /* int set_option */ + +/* + * public API + */ + +cmd_status_t cmd_parse_putmetric(size_t argc, char **argv, + cmd_putmetric_t *ret_putmetric, + __attribute__((unused)) + cmd_options_t const *opts, + cmd_error_handler_t *errhndl) { + if ((argc < 2) || (argv == NULL) || (ret_putmetric == NULL)) { + errno = EINVAL; + cmd_error(CMD_ERROR, errhndl, "Invalid arguments to cmd_parse_putmetric."); + return CMD_ERROR; + } + + if (argc < 2) { + cmd_error(CMD_PARSE_ERROR, errhndl, + "Missing identifier and/or value-list."); + return CMD_PARSE_ERROR; + } + + metric_family_t *fam = calloc(1, sizeof(*fam)); + if (fam == NULL) { + cmd_error(CMD_ERROR, errhndl, "calloc failed"); + return CMD_ERROR; + } + fam->type = METRIC_TYPE_UNTYPED; + + int status = metric_family_metric_append(fam, (metric_t){0}); + if (status != 0) { + return CMD_ERROR; + } + metric_t *m = fam->metric.ptr; + + int next_pos = 0; + cmd_status_t result = CMD_OK; + for (size_t i = 0; i < argc; ++i) { + char *key = NULL; + char *value = NULL; + + int status = cmd_parse_option(argv[i], &key, &value, errhndl); + if (status == CMD_OK) { + assert(key != NULL); + assert(value != NULL); + + result = set_option(m, key, value, errhndl); + if (result != CMD_OK) { + break; + } + continue; + } else if (status == CMD_NO_OPTION) { + /* Positional argument */ + if (next_pos == 0) { + fam->name = strdup(argv[i]); + if (fam->name == NULL) { + cmd_error(CMD_ERROR, errhndl, "calloc failed"); + result = CMD_ERROR; + break; + } + next_pos++; + continue; + } else if (next_pos == 1) { + int status = parse_value(argv[i], &m->value, fam->type); + if (status != 0) { + cmd_error(CMD_ERROR, errhndl, "parse_value failed"); + result = CMD_ERROR; + break; + } + next_pos++; + continue; + } else { + /* error is handled after the loop */ + next_pos++; + continue; + } + } else { + /* parse_option failed, buffer has been modified. + * => we need to abort */ + result = status; + break; + } + } + + if ((result == CMD_OK) && (next_pos != 2)) { + char errmsg[256]; + snprintf(errmsg, sizeof(errmsg), + "Found %d positional argument(s), expected 2.", next_pos); + cmd_error(CMD_PARSE_ERROR, errhndl, errmsg); + result = CMD_ERROR; + } + + if (result != CMD_OK) { + metric_family_free(fam); + return result; + } + + *ret_putmetric = (cmd_putmetric_t){ + .family = fam, + }; + return CMD_OK; +} /* cmd_status_t cmd_parse_putmetric */ + +void cmd_destroy_putmetric(cmd_putmetric_t *putmetric) { + if (putmetric == NULL) + return; + + metric_family_free(putmetric->family); + + (*putmetric) = (cmd_putmetric_t){0}; +} /* void cmd_destroy_putmetric */ + +cmd_status_t cmd_handle_putmetric(FILE *fh, char *buffer) { + cmd_error_handler_t err = {cmd_error_fh, fh}; + + DEBUG("utils_cmd_putmetric: cmd_handle_putmetric (fh = %p, buffer = %s);", + (void *)fh, buffer); + + cmd_t cmd = {0}; + int status; + if ((status = cmd_parse(buffer, &cmd, NULL, &err)) != CMD_OK) + return status; + if (cmd.type != CMD_PUTVAL) { + cmd_error(CMD_UNKNOWN_COMMAND, &err, "Unexpected command: `%s'.", + CMD_TO_STRING(cmd.type)); + cmd_destroy(&cmd); + return CMD_UNKNOWN_COMMAND; + } + + status = plugin_dispatch_metric_family(cmd.cmd.putmetric.family); + if (status != 0) { + cmd_error(CMD_ERROR, &err, + "plugin_dispatch_metric_list failed with status %d.", status); + cmd_destroy(&cmd); + return CMD_ERROR; + } + + if (fh != stdout) { + cmd_putmetric_t *putmetric = &cmd.cmd.putmetric; + size_t n = putmetric->family->metric.num; + cmd_error(CMD_OK, &err, "Success: %zu %s been dispatched.", n, + (n == 1) ? "metric has" : "metrics have"); + } + + cmd_destroy(&cmd); + return CMD_OK; +} /* int cmd_handle_putmetric */ + +/* TODO(octo): Improve the readability of the command. + * + * Currently, this assumes lines similar to: + * + * PUTVAL "metric_name{key=\"value\"}" interval=10.000 42 + * + * Encoding the labels in this way generates a lot of escaped quotes, which is + * not ideal. An alternative representation would be: + * + * PUTVAL metric_name label:key="value" interval=10.000 42 + */ +int cmd_format_putmetric(strbuf_t *buf, metric_t const *m) { /* {{{ */ + if ((buf == NULL) || (m == NULL)) { + return EINVAL; + } + + strbuf_print(buf, "PUTMETRIC "); + strbuf_print(buf, m->family->name); + switch (m->family->type) { + case METRIC_TYPE_UNTYPED: + /* no op */ + break; + case METRIC_TYPE_COUNTER: + strbuf_print(buf, " type=COUNTER"); + break; + case METRIC_TYPE_GAUGE: + strbuf_print(buf, " type=GAUGE"); + break; + default: + return EINVAL; + } + + if (m->time != 0) { + strbuf_printf(buf, " time=%.3f", CDTIME_T_TO_DOUBLE(m->time)); + } + if (m->interval != 0) { + strbuf_printf(buf, " interval=%.3f", CDTIME_T_TO_DOUBLE(m->interval)); + } + + for (size_t i = 0; i < m->label.num; i++) { + label_pair_t *l = m->label.ptr + i; + strbuf_printf(buf, " label:%s=\"", l->name); + strbuf_print_escaped(buf, l->value, "\\\"\n\r\t", '\\'); + strbuf_print(buf, "\""); + } + + strbuf_print(buf, " "); + return value_marshal_text(buf, m->value, m->family->type); +} /* }}} int cmd_format_putmetric */ diff --git a/src/utils/cmds/putmetric.h b/src/utils/cmds/putmetric.h new file mode 100644 index 000000000..150a0aea1 --- /dev/null +++ b/src/utils/cmds/putmetric.h @@ -0,0 +1,46 @@ +/** + * collectd - src/utils_cmd_putval.h + * Copyright (C) 2007–2020 Florian octo Forster + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Florian octo Forster + **/ + +#ifndef UTILS_CMD_PUTMETRIC_H +#define UTILS_CMD_PUTMETRIC_H 1 + +#include "plugin.h" +#include "utils/cmds/cmds.h" + +#include + +cmd_status_t cmd_parse_putmetric(size_t argc, char **argv, + cmd_putmetric_t *ret_putmetric, + const cmd_options_t *opts, + cmd_error_handler_t *err); + +cmd_status_t cmd_handle_putmetric(FILE *fh, char *buffer); + +void cmd_destroy_putmetric(cmd_putmetric_t *putmetric); + +int cmd_format_putmetric(strbuf_t *buf, metric_t const *m); + +#endif /* UTILS_CMD_PUTMETRIC_H */ diff --git a/src/utils/cmds/putval.c b/src/utils/cmds/putval.c index a27e6aec4..61dc8fda5 100644 --- a/src/utils/cmds/putval.c +++ b/src/utils/cmds/putval.c @@ -114,7 +114,7 @@ cmd_status_t cmd_parse_putval(size_t argc, char **argv, } char *identifier = strdup(argv[0]); - if (ret_putval->raw_identifier == NULL) { + if (identifier == NULL) { cmd_error(CMD_ERROR, errhndl, "malloc failed."); return CMD_ERROR; }