**/
#include "utils_cmds.h"
+#include "daemon/common.h"
#include "utils_cmd_flush.h"
#include "utils_cmd_getval.h"
#include "utils_cmd_listval.h"
#include "utils_cmd_putval.h"
#include "utils_parse_option.h"
-#include "daemon/common.h"
#include <stdbool.h>
#include <string.h>
static cmd_options_t default_options = {
- /* identifier_default_host = */ NULL,
+ /* identifier_default_host = */ NULL,
};
/*
* private helper functions
*/
-static cmd_status_t cmd_split (char *buffer,
- size_t *ret_len, char ***ret_fields,
- cmd_error_handler_t *err)
-{
- char *field;
- bool in_field, in_quotes;
-
- size_t estimate, len;
- char **fields;
-
- estimate = 0;
- in_field = false;
- for (char *string = buffer; *string != '\0'; ++string)
- {
- /* Make a quick worst-case estimate of the number of fields by
- * counting spaces and ignoring quotation marks. */
- if (!isspace ((int)*string))
- {
- if (!in_field)
- {
- estimate++;
- in_field = true;
- }
- }
- else
- {
- in_field = false;
- }
- }
-
- /* fields will be NULL-terminated */
- fields = malloc ((estimate + 1) * sizeof (*fields));
- if (fields == NULL) {
- cmd_error (CMD_ERROR, err, "malloc failed.");
- return (CMD_ERROR);
- }
-
-#define END_FIELD() \
- do { \
- *field = '\0'; \
- field = NULL; \
- in_field = false; \
- } while (0)
-#define NEW_FIELD() \
- do { \
- field = string; \
- in_field = true; \
- assert (len < estimate); \
- fields[len] = field; \
- field++; \
- len++; \
- } while (0)
-
- len = 0;
- field = NULL;
- in_field = false;
- in_quotes = false;
- for (char *string = buffer; *string != '\0'; string++)
- {
- if (isspace ((int)string[0]))
- {
- if (! in_quotes)
- {
- if (in_field)
- END_FIELD ();
-
- /* skip space */
- continue;
- }
- }
- else if (string[0] == '"')
- {
- /* Note: Two consecutive quoted fields not separated by space are
- * treated as different fields. This is the collectd 5.x behavior
- * around splitting fields. */
-
- if (in_quotes)
- {
- /* end of quoted field */
- if (! in_field) /* empty quoted string */
- NEW_FIELD ();
- END_FIELD ();
- in_quotes = false;
- continue;
- }
-
- in_quotes = true;
- /* if (! in_field): add new field on next iteration
- * else: quoted string following an unquoted string (one field)
- * in either case: skip quotation mark */
- continue;
- }
- else if ((string[0] == '\\') && in_quotes)
- {
- /* Outside of quotes, a backslash is a regular character (mostly
- * for backward compatibility). */
-
- if (string[1] == '\0')
- {
- free (fields);
- cmd_error (CMD_PARSE_ERROR, err,
- "Backslash at end of string.");
- return (CMD_PARSE_ERROR);
- }
-
- /* un-escape the next character; skip backslash */
- string++;
- }
-
- if (! in_field)
- NEW_FIELD ();
- else {
- *field = string[0];
- field++;
- }
- }
-
- if (in_quotes)
- {
- free (fields);
- cmd_error (CMD_PARSE_ERROR, err, "Unterminated quoted string.");
- return (CMD_PARSE_ERROR);
- }
+static cmd_status_t cmd_split(char *buffer, size_t *ret_len, char ***ret_fields,
+ cmd_error_handler_t *err) {
+ char *field;
+ bool in_field, in_quotes;
+
+ size_t estimate, len;
+ char **fields;
+
+ estimate = 0;
+ in_field = false;
+ for (char *string = buffer; *string != '\0'; ++string) {
+ /* Make a quick worst-case estimate of the number of fields by
+ * counting spaces and ignoring quotation marks. */
+ if (!isspace((int)*string)) {
+ if (!in_field) {
+ estimate++;
+ in_field = true;
+ }
+ } else {
+ in_field = false;
+ }
+ }
+
+ /* fields will be NULL-terminated */
+ fields = malloc((estimate + 1) * sizeof(*fields));
+ if (fields == NULL) {
+ cmd_error(CMD_ERROR, err, "malloc failed.");
+ return CMD_ERROR;
+ }
+
+#define END_FIELD() \
+ do { \
+ *field = '\0'; \
+ field = NULL; \
+ in_field = false; \
+ } while (0)
+#define NEW_FIELD() \
+ do { \
+ field = string; \
+ in_field = true; \
+ assert(len < estimate); \
+ fields[len] = field; \
+ field++; \
+ len++; \
+ } while (0)
+
+ len = 0;
+ field = NULL;
+ in_field = false;
+ in_quotes = false;
+ for (char *string = buffer; *string != '\0'; string++) {
+ if (isspace((int)string[0])) {
+ if (!in_quotes) {
+ if (in_field)
+ END_FIELD();
+
+ /* skip space */
+ continue;
+ }
+ } else if (string[0] == '"') {
+ /* Note: Two consecutive quoted fields not separated by space are
+ * treated as different fields. This is the collectd 5.x behavior
+ * around splitting fields. */
+
+ if (in_quotes) {
+ /* end of quoted field */
+ if (!in_field) /* empty quoted string */
+ NEW_FIELD();
+ END_FIELD();
+ in_quotes = false;
+ continue;
+ }
+
+ in_quotes = true;
+ /* if (! in_field): add new field on next iteration
+ * else: quoted string following an unquoted string (one field)
+ * in either case: skip quotation mark */
+ continue;
+ } else if ((string[0] == '\\') && in_quotes) {
+ /* Outside of quotes, a backslash is a regular character (mostly
+ * for backward compatibility). */
+
+ if (string[1] == '\0') {
+ free(fields);
+ cmd_error(CMD_PARSE_ERROR, err, "Backslash at end of string.");
+ return CMD_PARSE_ERROR;
+ }
+
+ /* un-escape the next character; skip backslash */
+ string++;
+ }
+
+ if (!in_field)
+ NEW_FIELD();
+ else {
+ *field = string[0];
+ field++;
+ }
+ }
+
+ if (in_quotes) {
+ free(fields);
+ cmd_error(CMD_PARSE_ERROR, err, "Unterminated quoted string.");
+ return CMD_PARSE_ERROR;
+ }
#undef NEW_FIELD
#undef END_FIELD
- fields[len] = NULL;
- if (ret_len != NULL)
- *ret_len = len;
- if (ret_fields != NULL)
- *ret_fields = fields;
- else
- free (fields);
- return (CMD_OK);
+ fields[len] = NULL;
+ if (ret_len != NULL)
+ *ret_len = len;
+ if (ret_fields != NULL)
+ *ret_fields = fields;
+ else
+ free(fields);
+ return CMD_OK;
} /* int cmd_split */
/*
* public API
*/
-void cmd_error (cmd_status_t status, cmd_error_handler_t *err,
- const char *format, ...)
-{
- va_list ap;
+void cmd_error(cmd_status_t status, cmd_error_handler_t *err,
+ const char *format, ...) {
+ va_list ap;
- if ((err == NULL) || (err->cb == NULL))
- return;
+ if ((err == NULL) || (err->cb == NULL))
+ return;
- va_start (ap, format);
- err->cb (err->ud, status, format, ap);
- va_end (ap);
+ va_start(ap, format);
+ err->cb(err->ud, status, format, ap);
+ va_end(ap);
} /* void cmd_error */
-cmd_status_t cmd_parsev (size_t argc, char **argv, cmd_t *ret_cmd,
- const cmd_options_t *opts, cmd_error_handler_t *err)
-{
- char *command = NULL;
- cmd_status_t status;
-
- if ((argc < 1) || (argv == NULL) || (ret_cmd == NULL))
- {
- errno = EINVAL;
- cmd_error (CMD_ERROR, err, "Missing command.");
- return CMD_ERROR;
- }
-
- if (opts == NULL)
- opts = &default_options;
-
- memset (ret_cmd, 0, sizeof (*ret_cmd));
- command = argv[0];
- if (strcasecmp ("FLUSH", command) == 0)
- {
- ret_cmd->type = CMD_FLUSH;
- status = cmd_parse_flush (argc - 1, argv + 1,
- &ret_cmd->cmd.flush, opts, err);
- }
- else if (strcasecmp ("GETVAL", command) == 0)
- {
- ret_cmd->type = CMD_GETVAL;
- status = cmd_parse_getval (argc - 1, argv + 1,
- &ret_cmd->cmd.getval, opts, err);
- }
- else if (strcasecmp ("LISTVAL", command) == 0)
- {
- ret_cmd->type = CMD_LISTVAL;
- status = cmd_parse_listval (argc - 1, argv + 1,
- &ret_cmd->cmd.listval, opts, err);
- }
- else if (strcasecmp ("PUTVAL", command) == 0)
- {
- ret_cmd->type = CMD_PUTVAL;
- status = cmd_parse_putval (argc - 1, argv + 1,
- &ret_cmd->cmd.putval, opts, err);
- }
- else
- {
- ret_cmd->type = CMD_UNKNOWN;
- cmd_error (CMD_UNKNOWN_COMMAND, err,
- "Unknown command `%s'.", command);
- return (CMD_UNKNOWN_COMMAND);
- }
-
- if (status != CMD_OK)
- ret_cmd->type = CMD_UNKNOWN;
- return (status);
+cmd_status_t cmd_parsev(size_t argc, char **argv, cmd_t *ret_cmd,
+ const cmd_options_t *opts, cmd_error_handler_t *err) {
+ char *command = NULL;
+ cmd_status_t status;
+
+ if ((argc < 1) || (argv == NULL) || (ret_cmd == NULL)) {
+ errno = EINVAL;
+ cmd_error(CMD_ERROR, err, "Missing command.");
+ return CMD_ERROR;
+ }
+
+ if (opts == NULL)
+ opts = &default_options;
+
+ memset(ret_cmd, 0, sizeof(*ret_cmd));
+ command = argv[0];
+ if (strcasecmp("FLUSH", command) == 0) {
+ ret_cmd->type = CMD_FLUSH;
+ status =
+ cmd_parse_flush(argc - 1, argv + 1, &ret_cmd->cmd.flush, opts, err);
+ } else if (strcasecmp("GETVAL", command) == 0) {
+ ret_cmd->type = CMD_GETVAL;
+ status =
+ cmd_parse_getval(argc - 1, argv + 1, &ret_cmd->cmd.getval, opts, err);
+ } else if (strcasecmp("LISTVAL", command) == 0) {
+ ret_cmd->type = CMD_LISTVAL;
+ status =
+ cmd_parse_listval(argc - 1, argv + 1, &ret_cmd->cmd.listval, opts, err);
+ } else if (strcasecmp("PUTVAL", command) == 0) {
+ ret_cmd->type = CMD_PUTVAL;
+ status =
+ cmd_parse_putval(argc - 1, argv + 1, &ret_cmd->cmd.putval, opts, err);
+ } else {
+ ret_cmd->type = CMD_UNKNOWN;
+ cmd_error(CMD_UNKNOWN_COMMAND, err, "Unknown command `%s'.", command);
+ return CMD_UNKNOWN_COMMAND;
+ }
+
+ if (status != CMD_OK)
+ ret_cmd->type = CMD_UNKNOWN;
+ return status;
} /* cmd_status_t cmd_parsev */
-cmd_status_t cmd_parse (char *buffer, cmd_t *ret_cmd,
- const cmd_options_t *opts, cmd_error_handler_t *err)
-{
- char **fields = NULL;
- size_t fields_num = 0;
- cmd_status_t status;
+cmd_status_t cmd_parse(char *buffer, cmd_t *ret_cmd, const cmd_options_t *opts,
+ cmd_error_handler_t *err) {
+ char **fields = NULL;
+ size_t fields_num = 0;
+ cmd_status_t status;
- if ((status = cmd_split (buffer, &fields_num, &fields, err)) != CMD_OK)
- return status;
+ if ((status = cmd_split(buffer, &fields_num, &fields, err)) != CMD_OK)
+ return status;
- status = cmd_parsev (fields_num, fields, ret_cmd, opts, err);
- free (fields);
- return (status);
+ status = cmd_parsev(fields_num, fields, ret_cmd, opts, err);
+ free(fields);
+ return status;
} /* cmd_status_t cmd_parse */
-void cmd_destroy (cmd_t *cmd)
-{
- if (cmd == NULL)
- return;
-
- switch (cmd->type)
- {
- case CMD_UNKNOWN:
- /* nothing to do */
- break;
- case CMD_FLUSH:
- cmd_destroy_flush (&cmd->cmd.flush);
- break;
- case CMD_GETVAL:
- cmd_destroy_getval (&cmd->cmd.getval);
- break;
- case CMD_LISTVAL:
- cmd_destroy_listval (&cmd->cmd.listval);
- break;
- case CMD_PUTVAL:
- cmd_destroy_putval (&cmd->cmd.putval);
- break;
- }
+void cmd_destroy(cmd_t *cmd) {
+ if (cmd == NULL)
+ return;
+
+ switch (cmd->type) {
+ case CMD_UNKNOWN:
+ /* nothing to do */
+ break;
+ case CMD_FLUSH:
+ cmd_destroy_flush(&cmd->cmd.flush);
+ break;
+ case CMD_GETVAL:
+ cmd_destroy_getval(&cmd->cmd.getval);
+ break;
+ case CMD_LISTVAL:
+ cmd_destroy_listval(&cmd->cmd.listval);
+ break;
+ case CMD_PUTVAL:
+ cmd_destroy_putval(&cmd->cmd.putval);
+ break;
+ }
} /* void cmd_destroy */
-cmd_status_t cmd_parse_option (char *field,
- char **ret_key, char **ret_value, cmd_error_handler_t *err)
-{
- char *key, *value;
-
- if (field == NULL)
- {
- errno = EINVAL;
- cmd_error (CMD_ERROR, err, "Invalid argument to cmd_parse_option.");
- return (CMD_ERROR);
- }
- key = value = field;
-
- /* Look for the equal sign. */
- while (isalnum ((int)value[0]) || (value[0] == '_') || (value[0] == ':'))
- value++;
- if ((value[0] != '=') || (value == key))
- {
- /* Whether this is a fatal error is up to the caller. */
- return (CMD_NO_OPTION);
- }
- *value = '\0';
- value++;
-
- if (ret_key != NULL)
- *ret_key = key;
- if (ret_value != NULL)
- *ret_value = value;
-
- return (CMD_OK);
+cmd_status_t cmd_parse_option(char *field, char **ret_key, char **ret_value,
+ cmd_error_handler_t *err) {
+ char *key, *value;
+
+ if (field == NULL) {
+ errno = EINVAL;
+ cmd_error(CMD_ERROR, err, "Invalid argument to cmd_parse_option.");
+ return CMD_ERROR;
+ }
+ key = value = field;
+
+ /* Look for the equal sign. */
+ while (isalnum((int)value[0]) || (value[0] == '_') || (value[0] == ':'))
+ value++;
+ if ((value[0] != '=') || (value == key)) {
+ /* Whether this is a fatal error is up to the caller. */
+ return CMD_NO_OPTION;
+ }
+ *value = '\0';
+ value++;
+
+ if (ret_key != NULL)
+ *ret_key = key;
+ if (ret_value != NULL)
+ *ret_value = value;
+
+ return CMD_OK;
} /* cmd_status_t cmd_parse_option */
-void cmd_error_fh (void *ud, cmd_status_t status,
- const char *format, va_list ap)
-{
- FILE *fh = ud;
- int code = -1;
- char buf[1024];
-
- if (status == CMD_OK)
- code = 0;
-
- vsnprintf (buf, sizeof(buf), format, ap);
- buf[sizeof (buf) - 1] = '\0';
- if (fprintf (fh, "%i %s\n", code, buf) < 0)
- {
- char errbuf[1024];
- WARNING ("utils_cmds: failed to write to file-handle #%i: %s",
- fileno (fh), sstrerror (errno, errbuf, sizeof (errbuf)));
- return;
- }
-
- fflush (fh);
+void cmd_error_fh(void *ud, cmd_status_t status, const char *format,
+ va_list ap) {
+ FILE *fh = ud;
+ int code = -1;
+ char buf[1024];
+
+ if (status == CMD_OK)
+ code = 0;
+
+ vsnprintf(buf, sizeof(buf), format, ap);
+ buf[sizeof(buf) - 1] = '\0';
+ if (fprintf(fh, "%i %s\n", code, buf) < 0) {
+ char errbuf[1024];
+ WARNING("utils_cmds: failed to write to file-handle #%i: %s", fileno(fh),
+ sstrerror(errno, errbuf, sizeof(errbuf)));
+ return;
+ }
+
+ fflush(fh);
} /* void cmd_error_fh */
-
-/* vim: set sw=4 ts=4 tw=78 noexpandtab : */