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:
Johan Wikman
2016-10-14 19:41:50 +03:00
parent 571919264f
commit 1333da0712
69 changed files with 521 additions and 567 deletions

View File

@ -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;
}