X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Futils_cmds.c;h=3ea7c9d0d2757de04ad4c6fffa7349fa27c22e49;hp=1f53ad1d6a4da8bc966d2c67f024a29d2517ddef;hb=936c450a86c841eea89888c8550c9118fae90c25;hpb=77ad300d75ce59bf4d49d839a2af72e90590033c diff --git a/src/utils_cmds.c b/src/utils_cmds.c index 1f53ad1d..3ea7c9d0 100644 --- a/src/utils_cmds.c +++ b/src/utils_cmds.c @@ -26,327 +26,288 @@ * Sebastian 'tokkee' Harl **/ -#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_cmds.h" #include "utils_parse_option.h" -#include "daemon/common.h" #include #include 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 : */