1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-30 17:18:21 +03:00

dmstats: support group aliases with embedded whitespace

Creating a group with a name that contains whitespace causes an error in
the @stats_set_aux message:

device-mapper: message ioctl on  (253:0) failed: Invalid argument
Could not create regions from file /var/tmp/File With Spaces.

Fix this by quoting the group alias and backslash escaping any
embedded space characters.
This commit is contained in:
Bryn M. Reeves 2023-09-25 18:38:13 +01:00 committed by Zdeněk Kabeláč
parent 33931431c3
commit 7d8981dd3f

View File

@ -136,6 +136,36 @@ struct dm_stats {
uint64_t cur_area;
};
static char *_stats_escape_aux_data(const char *aux_data)
{
size_t aux_data_len = strlen(aux_data);
char *escaped = dm_malloc((3 * aux_data_len + 1) * sizeof(char));
size_t index = 0;
if (!escaped) {
log_error("Could not allocate memory for escaped "
"aux_data string.");
return NULL;
}
for (size_t i = 0; i < aux_data_len; i++) {
if (aux_data[i] == ' ') {
escaped[index++] = '\\';
escaped[index++] = ' ';
} else if (aux_data[i] == '\\') {
escaped[index++] = '\\';
escaped[index++] = '\\';
} else if (aux_data[i] == '\t') {
escaped[index++] = '\\';
escaped[index++] = '\t';
} else {
escaped[index++] = aux_data[i];
}
}
escaped[index] = '\0';
return escaped;
}
#define PROC_SELF_COMM "/proc/self/comm"
static char *_program_id_from_proc(void)
{
@ -697,6 +727,8 @@ static void _check_group_regions_present(struct dm_stats *dms,
#define DMS_GROUP_TAG_LEN (sizeof(DMS_GROUP_TAG) - 1)
#define DMS_GROUP_SEP ':'
#define DMS_AUX_SEP "#"
#define DMS_AUX_SEP_CHAR '#'
#define DMS_GROUP_QUOTE '"'
static int _parse_aux_data_group(struct dm_stats *dms,
struct dm_stats_region *region,
@ -713,7 +745,8 @@ static int _parse_aux_data_group(struct dm_stats *dms,
if (!c)
return 1; /* no group is not an error */
alias = c + strlen(DMS_GROUP_TAG);
/* extract alias from quotes */
alias = c + strlen(DMS_GROUP_TAG) + 1;
c = strchr(c, DMS_GROUP_SEP);
@ -722,8 +755,9 @@ static int _parse_aux_data_group(struct dm_stats *dms,
return 0;
}
/* terminate alias and advance to members */
*(c++) = '\0';
/* terminate alias and advance to members accounting for closing quote */
*(c - 1) = '\0';
c++;
log_debug("Read alias '%s' from aux_data", alias);
@ -904,7 +938,7 @@ bad:
static int _stats_parse_string_data(char *string_data, char **program_id,
char **aux_data, char **stats_args)
{
char *p, *next_space, *empty_string = (char *)"";
char *p, *next_gap, *empty_string = (char *)"";
size_t len;
/*
@ -927,14 +961,26 @@ static int _stats_parse_string_data(char *string_data, char **program_id,
*program_id = string_data;
p++;
next_space = strchr(p, ' ');
if (next_space) {
*next_space = '\0';
if (strstr(p, DMS_GROUP_TAG)) {
*aux_data = p;
*stats_args = next_space + 1;
/* Skip over the group tag */
next_gap = strchr(p, DMS_AUX_SEP_CHAR);
next_gap = strchr(next_gap, ' ');
if (next_gap) {
*(next_gap++) = '\0';
*stats_args = next_gap++;
} else
*stats_args = empty_string;
} else {
*aux_data = p;
*stats_args = empty_string;
next_gap = strchr(p, ' ');
if (next_gap) {
*next_gap = '\0';
*aux_data = p;
*stats_args = next_gap + 1;
} else {
*aux_data = p;
*stats_args = empty_string;
}
}
if (!strncmp(*program_id, "-", 1))
@ -1864,7 +1910,7 @@ static char *_build_group_tag(struct dm_stats *dms, uint64_t group_id)
return_0;
buflen += DMS_GROUP_TAG_LEN;
buflen += 1 + (alias ? strlen(alias) : 0); /* 'alias:' */
buflen += 1 + (alias ? strlen(alias) + 2 : 0); /* 'alias:' */
buf = aux_string = dm_malloc(buflen);
if (!buf) {
@ -1878,7 +1924,11 @@ static char *_build_group_tag(struct dm_stats *dms, uint64_t group_id)
buf += DMS_GROUP_TAG_LEN;
buflen -= DMS_GROUP_TAG_LEN;
r = dm_snprintf(buf, buflen, "%s%c", alias ? alias : "", DMS_GROUP_SEP);
if (alias)
r = dm_snprintf(buf, buflen, "\"%s\"%c", alias, DMS_GROUP_SEP);
else
r = dm_snprintf(buf, buflen, "%c", DMS_GROUP_SEP);
if (r < 0)
goto_bad;
@ -1907,6 +1957,7 @@ static int _stats_set_aux(struct dm_stats *dms,
const char *group_tag = NULL;
struct dm_task *dmt = NULL;
char msg[STATS_MSG_BUF_LEN];
char *group_tag_escaped = NULL;
/* group data required? */
if (_stats_group_id_present(dms, region_id)) {
@ -1916,10 +1967,15 @@ static int _stats_set_aux(struct dm_stats *dms,
"region ID " FMTu64, region_id);
goto bad;
}
}
group_tag_escaped = _stats_escape_aux_data(group_tag);
if (!group_tag_escaped)
goto bad;
} else
group_tag_escaped = dm_strdup("");
if (dm_snprintf(msg, sizeof(msg), "@stats_set_aux " FMTu64 " %s%s%s ",
region_id, (group_tag) ? group_tag : "",
(group_tag) ? DMS_AUX_SEP : "",
region_id, (group_tag_escaped) ? group_tag_escaped : "",
(group_tag_escaped) ? DMS_AUX_SEP : "",
(strlen(user_data)) ? user_data : "-") < 0) {
log_error("Could not prepare @stats_set_aux message");
goto bad;
@ -1929,6 +1985,7 @@ static int _stats_set_aux(struct dm_stats *dms,
goto_bad;
dm_free((char *) group_tag);
dm_free(group_tag_escaped);
/* no response to a @stats_set_aux message */
dm_task_destroy(dmt);
@ -1953,6 +2010,7 @@ static int _stats_create_region(struct dm_stats *dms, uint64_t *region_id,
const char *err_fmt = "Could not prepare @stats_create %s.";
const char *precise_str = PRECISE_ARG;
const char *resp, *opt_args = NULL;
char *aux_data_escaped = NULL;
struct dm_task *dmt = NULL;
int r = 0, nr_opt = 0;
@ -1983,6 +2041,10 @@ static int _stats_create_region(struct dm_stats *dms, uint64_t *region_id,
else
hist_arg = "";
aux_data_escaped = _stats_escape_aux_data(aux_data);
if (!aux_data_escaped)
return_0;
if (nr_opt) {
if ((dm_asprintf((char **)&opt_args, "%d %s %s%s", nr_opt,
precise_str,
@ -2026,6 +2088,7 @@ out:
if (dmt)
dm_task_destroy(dmt);
dm_free((void *) opt_args);
dm_free(aux_data_escaped);
return r;
}