Remove skygw_utils.h
The general purpose stuff in skygw_utils.h was moved to utils.h and the corresponding implementation from skygw_utils.cc to utils.c. Includes updated accordingly. Skygw_utils.h is now only used by log_manager and by mlist, which is only used by log_manager. Consequently, skygw_utils.h was moved to server/maxscale. Utils.h needs a separate overhaul.
This commit is contained in:
@ -29,16 +29,27 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <regex.h>
|
||||
#include <maxscale/gw.h>
|
||||
#include <maxscale/dcb.h>
|
||||
#include <maxscale/session.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/poll.h>
|
||||
#include <maxscale/skygw_utils.h>
|
||||
#include <maxscale/log_manager.h>
|
||||
#include <maxscale/secrets.h>
|
||||
#include <maxscale/random_jkiss.h>
|
||||
#include <maxscale/pcre2.h>
|
||||
|
||||
#if !defined(PATH_MAX)
|
||||
# if defined(__USE_POSIX)
|
||||
# define PATH_MAX _POSIX_PATH_MAX
|
||||
# else
|
||||
# define PATH_MAX 256
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define MAX_ERROR_MSG PATH_MAX
|
||||
|
||||
/* used in the hex2bin function */
|
||||
#define char_val(X) (X >= '0' && X <= '9' ? X-'0' : \
|
||||
@ -50,6 +61,29 @@
|
||||
char hex_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
char hex_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
/**
|
||||
* Check if the provided pathname is POSIX-compliant. The valid characters
|
||||
* are [a-z A-Z 0-9._-].
|
||||
* @param path A null-terminated string
|
||||
* @return true if it is a POSIX-compliant pathname, otherwise false
|
||||
*/
|
||||
bool is_valid_posix_path(char* path)
|
||||
{
|
||||
char* ptr = path;
|
||||
while (*ptr != '\0')
|
||||
{
|
||||
if (isalnum(*ptr) || *ptr == '/' || *ptr == '.' || *ptr == '-' || *ptr == '_')
|
||||
{
|
||||
ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* backend read event triggered by EPOLLIN
|
||||
*****************************************/
|
||||
@ -388,3 +422,461 @@ bool mxs_mkdir_all(const char *path, int mask)
|
||||
|
||||
return mkdir_all_internal(local_path, (mode_t)mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim leading and trailing whitespace from a string
|
||||
*
|
||||
* @param str String to trim
|
||||
* @return Trimmed string
|
||||
*/
|
||||
char* trim(char *str)
|
||||
{
|
||||
char* ptr = strchr(str, '\0') - 1;
|
||||
|
||||
while (ptr > str && isspace(*ptr))
|
||||
{
|
||||
ptr--;
|
||||
}
|
||||
|
||||
if (isspace(*(ptr + 1)))
|
||||
{
|
||||
*(ptr + 1) = '\0';
|
||||
}
|
||||
|
||||
ptr = str;
|
||||
|
||||
while (isspace(*ptr))
|
||||
{
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (ptr != str)
|
||||
{
|
||||
memmove(str, ptr, strlen(ptr) + 1);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace all whitespace with spaces and squeeze repeating whitespace characters
|
||||
*
|
||||
* @param str String to squeeze
|
||||
* @return Squeezed string
|
||||
*/
|
||||
char* squeeze_whitespace(char* str)
|
||||
{
|
||||
char* store = str;
|
||||
char* ptr = str;
|
||||
|
||||
/** Remove leading whitespace */
|
||||
while (isspace(*ptr) && *ptr != '\0')
|
||||
{
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/** Squeeze all repeating whitespace */
|
||||
while (*ptr != '\0')
|
||||
{
|
||||
while (isspace(*ptr) && isspace(*(ptr + 1)))
|
||||
{
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (isspace(*ptr))
|
||||
{
|
||||
*store++ = ' ';
|
||||
ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*store++ = *ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
*store = '\0';
|
||||
|
||||
/** Remove trailing whitespace */
|
||||
while (store > str && isspace(*(store - 1)))
|
||||
{
|
||||
store--;
|
||||
*store = '\0';
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip escape characters from a character string.
|
||||
* @param String to parse.
|
||||
* @return True if parsing was successful, false on errors.
|
||||
*/
|
||||
bool
|
||||
strip_escape_chars(char* val)
|
||||
{
|
||||
int cur, end;
|
||||
|
||||
if (val == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
end = strlen(val) + 1;
|
||||
cur = 0;
|
||||
|
||||
while (cur < end)
|
||||
{
|
||||
if (val[cur] == '\\')
|
||||
{
|
||||
memmove(val + cur, val + cur + 1, end - cur - 1);
|
||||
end--;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define BUFFER_GROWTH_RATE 1.2
|
||||
static pcre2_code* remove_comments_re = NULL;
|
||||
static const PCRE2_SPTR remove_comments_pattern = (PCRE2_SPTR)
|
||||
"(?:`[^`]*`\\K)|(\\/[*](?!(M?!)).*?[*]\\/)|(?:#.*|--[[:space:]].*)";
|
||||
|
||||
/**
|
||||
* Remove SQL comments from the end of a string
|
||||
*
|
||||
* The inline executable comments are not removed due to the fact that they can
|
||||
* alter the behavior of the query.
|
||||
* @param src Pointer to the string to modify.
|
||||
* @param srcsize Pointer to a size_t variable which holds the length of the string to
|
||||
* be modified.
|
||||
* @param dest The address of the pointer where the result will be stored. If the
|
||||
* value pointed by this parameter is NULL, new memory will be allocated as needed.
|
||||
* @param Pointer to a size_t variable where the size of the result string is stored.
|
||||
* @return Pointer to new modified string or NULL if memory allocation failed.
|
||||
* If NULL is returned and the value pointed by @c dest was not NULL, no new
|
||||
* memory will be allocated, the memory pointed by @dest will be freed and the
|
||||
* contents of @c dest and @c destsize will be invalid.
|
||||
*/
|
||||
char* remove_mysql_comments(const char** src, const size_t* srcsize, char** dest, size_t* destsize)
|
||||
{
|
||||
static const PCRE2_SPTR replace = (PCRE2_SPTR) "";
|
||||
pcre2_match_data* mdata;
|
||||
char* output = *dest;
|
||||
size_t orig_len = *srcsize;
|
||||
size_t len = output ? *destsize : orig_len;
|
||||
|
||||
if (orig_len > 0)
|
||||
{
|
||||
if ((output || (output = (char*) malloc(len * sizeof (char)))) &&
|
||||
(mdata = pcre2_match_data_create_from_pattern(remove_comments_re, NULL)))
|
||||
{
|
||||
while (pcre2_substitute(remove_comments_re, (PCRE2_SPTR) * src, orig_len, 0,
|
||||
PCRE2_SUBSTITUTE_GLOBAL, mdata, NULL,
|
||||
replace, PCRE2_ZERO_TERMINATED,
|
||||
(PCRE2_UCHAR8*) output, &len) == PCRE2_ERROR_NOMEMORY)
|
||||
{
|
||||
char* tmp = (char*) realloc(output, (len = (size_t) (len * BUFFER_GROWTH_RATE + 1)));
|
||||
if (tmp == NULL)
|
||||
{
|
||||
free(output);
|
||||
output = NULL;
|
||||
break;
|
||||
}
|
||||
output = tmp;
|
||||
}
|
||||
pcre2_match_data_free(mdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(output);
|
||||
output = NULL;
|
||||
}
|
||||
}
|
||||
else if (output == NULL)
|
||||
{
|
||||
output = strdup(*src);
|
||||
}
|
||||
|
||||
if (output)
|
||||
{
|
||||
*destsize = strlen(output);
|
||||
*dest = output;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
static pcre2_code* replace_values_re = NULL;
|
||||
static const PCRE2_SPTR replace_values_pattern = (PCRE2_SPTR) "(?i)([-=,+*/([:space:]]|\\b|[@])"
|
||||
"(?:[0-9.-]+|(?<=[@])[a-z_0-9]+)([-=,+*/)[:space:];]|$)";
|
||||
|
||||
/**
|
||||
* Replace literal numbers and user variables with a question mark.
|
||||
* @param src Pointer to the string to modify.
|
||||
* @param srcsize Pointer to a size_t variable which holds the length of the string to
|
||||
* be modified.
|
||||
* @param dest The address of the pointer where the result will be stored. If the
|
||||
* value pointed by this parameter is NULL, new memory will be allocated as needed.
|
||||
* @param Pointer to a size_t variable where the size of the result string is stored.
|
||||
* @return Pointer to new modified string or NULL if memory allocation failed.
|
||||
* If NULL is returned and the value pointed by @c dest was not NULL, no new
|
||||
* memory will be allocated, the memory pointed by @dest will be freed and the
|
||||
* contents of @c dest and @c destsize will be invalid.
|
||||
*/
|
||||
char* replace_values(const char** src, const size_t* srcsize, char** dest, size_t* destsize)
|
||||
{
|
||||
static const PCRE2_SPTR replace = (PCRE2_SPTR) "$1?$2";
|
||||
pcre2_match_data* mdata;
|
||||
char* output = *dest;
|
||||
size_t orig_len = *srcsize;
|
||||
size_t len = output ? *destsize : orig_len;
|
||||
|
||||
if (orig_len > 0)
|
||||
{
|
||||
if ((output || (output = (char*) malloc(len * sizeof (char)))) &&
|
||||
(mdata = pcre2_match_data_create_from_pattern(replace_values_re, NULL)))
|
||||
{
|
||||
while (pcre2_substitute(replace_values_re, (PCRE2_SPTR) * src, orig_len, 0,
|
||||
PCRE2_SUBSTITUTE_GLOBAL, mdata, NULL,
|
||||
replace, PCRE2_ZERO_TERMINATED,
|
||||
(PCRE2_UCHAR8*) output, &len) == PCRE2_ERROR_NOMEMORY)
|
||||
{
|
||||
char* tmp = (char*) realloc(output, (len = (size_t) (len * BUFFER_GROWTH_RATE + 1)));
|
||||
if (tmp == NULL)
|
||||
{
|
||||
free(output);
|
||||
output = NULL;
|
||||
break;
|
||||
}
|
||||
output = tmp;
|
||||
}
|
||||
pcre2_match_data_free(mdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(output);
|
||||
output = NULL;
|
||||
}
|
||||
}
|
||||
else if (output == NULL)
|
||||
{
|
||||
output = strdup(*src);
|
||||
}
|
||||
|
||||
if (output)
|
||||
{
|
||||
*destsize = strlen(output);
|
||||
*dest = output;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the given needle - user-provided literal - and replace it with
|
||||
* replacement string. Separate user-provided literals from matching table names
|
||||
* etc. by searching only substrings preceded by non-letter and non-number.
|
||||
*
|
||||
* @param haystack Plain text query string, not to be freed
|
||||
* @param needle Substring to be searched, not to be freed
|
||||
* @param replacement Replacement text, not to be freed
|
||||
*
|
||||
* @return newly allocated string where needle is replaced
|
||||
*/
|
||||
char* replace_literal(char* haystack, const char* needle, const char* replacement)
|
||||
{
|
||||
const char* prefix = "[ ='\",\\(]"; /*< ' ','=','(',''',''"',',' are allowed before needle */
|
||||
const char* suffix = "([^[:alnum:]]|$)"; /*< alpha-num chars aren't allowed after the needle */
|
||||
char* search_re;
|
||||
char* newstr;
|
||||
regex_t re;
|
||||
regmatch_t match;
|
||||
int rc;
|
||||
size_t rlen = strlen(replacement);
|
||||
size_t nlen = strlen(needle);
|
||||
size_t hlen = strlen(haystack);
|
||||
|
||||
search_re = (char *) malloc(strlen(prefix) + nlen + strlen(suffix) + 1);
|
||||
|
||||
if (search_re == NULL)
|
||||
{
|
||||
char errbuf[MXS_STRERROR_BUFLEN];
|
||||
fprintf(stderr, "Regex memory allocation failed : %s\n",
|
||||
strerror_r(errno, errbuf, sizeof (errbuf)));
|
||||
newstr = haystack;
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
sprintf(search_re, "%s%s%s", prefix, needle, suffix);
|
||||
/** Allocate memory for new string +1 for terminating byte */
|
||||
newstr = (char *) malloc(hlen - nlen + rlen + 1);
|
||||
|
||||
if (newstr == NULL)
|
||||
{
|
||||
char errbuf[MXS_STRERROR_BUFLEN];
|
||||
fprintf(stderr, "Regex memory allocation failed : %s\n",
|
||||
strerror_r(errno, errbuf, sizeof (errbuf)));
|
||||
free(search_re);
|
||||
free(newstr);
|
||||
newstr = haystack;
|
||||
goto retblock;
|
||||
}
|
||||
|
||||
rc = regcomp(&re, search_re, REG_EXTENDED | REG_ICASE);
|
||||
ss_info_dassert(rc == 0, "Regex check");
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
char error_message[MAX_ERROR_MSG];
|
||||
regerror(rc, &re, error_message, MAX_ERROR_MSG);
|
||||
fprintf(stderr, "Regex error compiling '%s': %s\n",
|
||||
search_re, error_message);
|
||||
free(search_re);
|
||||
free(newstr);
|
||||
newstr = haystack;
|
||||
goto retblock;
|
||||
}
|
||||
rc = regexec(&re, haystack, 1, &match, 0);
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
free(search_re);
|
||||
free(newstr);
|
||||
regfree(&re);
|
||||
newstr = haystack;
|
||||
goto retblock;
|
||||
}
|
||||
memcpy(newstr, haystack, match.rm_so + 1);
|
||||
memcpy(newstr + match.rm_so + 1, replacement, rlen);
|
||||
/** +1 is terminating byte */
|
||||
memcpy(newstr + match.rm_so + 1 + rlen, haystack + match.rm_so + 1 + nlen, hlen - (match.rm_so + 1) - nlen + 1);
|
||||
|
||||
regfree(&re);
|
||||
free(haystack);
|
||||
free(search_re);
|
||||
retblock:
|
||||
return newstr;
|
||||
}
|
||||
|
||||
static pcre2_code* replace_quoted_re = NULL;
|
||||
static const PCRE2_SPTR replace_quoted_pattern = (PCRE2_SPTR)
|
||||
"(?>[^'\"]*)(?|(?:\"\\K(?:(?:(?<=\\\\)\")|[^\"])*(\"))|(?:'\\K(?:(?:(?<=\\\\)')|[^'])*(')))";
|
||||
|
||||
/**
|
||||
* Replace contents of single or double quoted strings with question marks.
|
||||
* @param src Pointer to the string to modify.
|
||||
* @param srcsize Pointer to a size_t variable which holds the length of the string to
|
||||
* be modified.
|
||||
* @param dest The address of the pointer where the result will be stored. If the
|
||||
* value pointed by this parameter is NULL, new memory will be allocated as needed.
|
||||
* @param Pointer to a size_t variable where the size of the result string is stored.
|
||||
* @return Pointer to new modified string or NULL if memory allocation failed.
|
||||
* If NULL is returned and the value pointed by @c dest was not NULL, no new
|
||||
* memory will be allocated, the memory pointed by @dest will be freed and the
|
||||
* contents of @c dest and @c destsize will be invalid.
|
||||
*/
|
||||
char* replace_quoted(const char** src, const size_t* srcsize, char** dest, size_t* destsize)
|
||||
{
|
||||
static const PCRE2_SPTR replace = (PCRE2_SPTR) "?$1";
|
||||
pcre2_match_data* mdata;
|
||||
char* output = *dest;
|
||||
size_t orig_len = *srcsize;
|
||||
size_t len = output ? *destsize : orig_len;
|
||||
|
||||
if (orig_len > 0)
|
||||
{
|
||||
if ((output || (output = (char*) malloc(len * sizeof (char)))) &&
|
||||
(mdata = pcre2_match_data_create_from_pattern(replace_quoted_re, NULL)))
|
||||
{
|
||||
while (pcre2_substitute(replace_quoted_re, (PCRE2_SPTR) * src, orig_len, 0,
|
||||
PCRE2_SUBSTITUTE_GLOBAL, mdata, NULL,
|
||||
replace, PCRE2_ZERO_TERMINATED,
|
||||
(PCRE2_UCHAR8*) output, &len) == PCRE2_ERROR_NOMEMORY)
|
||||
{
|
||||
char* tmp = (char*) realloc(output, (len = (size_t) (len * BUFFER_GROWTH_RATE + 1)));
|
||||
if (tmp == NULL)
|
||||
{
|
||||
free(output);
|
||||
output = NULL;
|
||||
break;
|
||||
}
|
||||
output = tmp;
|
||||
}
|
||||
pcre2_match_data_free(mdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(output);
|
||||
output = NULL;
|
||||
}
|
||||
}
|
||||
else if (output == NULL)
|
||||
{
|
||||
output = strdup(*src);
|
||||
}
|
||||
|
||||
if (output)
|
||||
{
|
||||
*destsize = strlen(output);
|
||||
*dest = output;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dest = NULL;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the utils library
|
||||
*
|
||||
* This function initializes structures used in various functions.
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
bool utils_init()
|
||||
{
|
||||
bool rval = true;
|
||||
|
||||
PCRE2_SIZE erroffset;
|
||||
int errcode;
|
||||
|
||||
ss_info_dassert(remove_comments_re == NULL, "utils_init called multiple times");
|
||||
remove_comments_re = pcre2_compile(remove_comments_pattern, PCRE2_ZERO_TERMINATED, 0, &errcode,
|
||||
&erroffset, NULL);
|
||||
if (remove_comments_re == NULL)
|
||||
{
|
||||
rval = false;
|
||||
}
|
||||
|
||||
ss_info_dassert(replace_quoted_re == NULL, "utils_init called multiple times");
|
||||
replace_quoted_re = pcre2_compile(replace_quoted_pattern, PCRE2_ZERO_TERMINATED, 0, &errcode,
|
||||
&erroffset, NULL);
|
||||
if (replace_quoted_re == NULL)
|
||||
{
|
||||
rval = false;
|
||||
}
|
||||
|
||||
ss_info_dassert(replace_values_re == NULL, "utils_init called multiple times");
|
||||
replace_values_re = pcre2_compile(replace_values_pattern, PCRE2_ZERO_TERMINATED, 0, &errcode,
|
||||
&erroffset, NULL);
|
||||
if (replace_values_re == NULL)
|
||||
{
|
||||
rval = false;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the utils library. This should be the last call to this library.
|
||||
*/
|
||||
void utils_end()
|
||||
{
|
||||
pcre2_code_free(remove_comments_re);
|
||||
remove_comments_re = NULL;
|
||||
pcre2_code_free(replace_quoted_re);
|
||||
replace_quoted_re = NULL;
|
||||
pcre2_code_free(replace_values_re);
|
||||
replace_values_re = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user