diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-05-26 19:32:28 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-05-26 19:32:28 +0400 |
commit | 9bc32256427373e5bfa78f17c5854ac4e6a2fc31 (patch) | |
tree | 748fd55866bcbc4de5eee1c078ac8d2cad5b6fd7 /client/mysqltest.cc | |
parent | 77b2f55f61a4e3ba642049a01651c92bfb0a7d9d (diff) | |
parent | ca7cf69cb13285585922722063af888b957580ee (diff) | |
download | mariadb-git-9bc32256427373e5bfa78f17c5854ac4e6a2fc31.tar.gz |
Merge tag 'mariadb-10.2.6' into bb-10.2-ext
Diffstat (limited to 'client/mysqltest.cc')
-rw-r--r-- | client/mysqltest.cc | 229 |
1 files changed, 178 insertions, 51 deletions
diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 56d1083a5f6..c92281c59e9 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2016, Monty Program Ab. + Copyright (c) 2009, 2017, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1063,7 +1063,7 @@ void do_eval(DYNAMIC_STRING *query_eval, const char *query, if (!(v= var_get(p, &p, 0, 0))) { report_or_die( "Bad variable in eval"); - return; + DBUG_VOID_RETURN; } dynstr_append_mem(query_eval, v->str_val, v->str_val_len); } @@ -1776,7 +1776,7 @@ static int run_command(char* cmd, if (!(res_file= popen(cmd, "r"))) { report_or_die("popen(\"%s\", \"r\") failed", cmd); - return -1; + DBUG_RETURN(-1); } while (fgets(buf, sizeof(buf), res_file)) @@ -2873,7 +2873,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) dynstr_free(&ds_query); dynstr_free(&ds_col); eval_expr(var, "", 0); - return; + DBUG_VOID_RETURN; } { @@ -2898,7 +2898,7 @@ void var_set_query_get_value(struct st_command *command, VAR *var) ds_col.str, ds_query.str); dynstr_free(&ds_query); dynstr_free(&ds_col); - return; + DBUG_VOID_RETURN; } DBUG_PRINT("info", ("Found column %d with name '%s'", i, fields[i].name)); @@ -3344,7 +3344,7 @@ void do_exec(struct st_command *command) if (!*cmd) { report_or_die("Missing argument in exec"); - return; + DBUG_VOID_RETURN; } command->last_argument= command->end; @@ -3370,6 +3370,12 @@ void do_exec(struct st_command *command) #endif #endif + if (disable_result_log) + { + /* Collect stderr output as well, for the case app. crashes or returns error.*/ + dynstr_append(&ds_cmd, " 2>&1"); + } + DBUG_PRINT("info", ("Executing '%s' as '%s'", command->first_argument, ds_cmd.str)); @@ -3378,7 +3384,7 @@ void do_exec(struct st_command *command) dynstr_free(&ds_cmd); if (command->abort_on_error) report_or_die("popen(\"%s\", \"r\") failed", command->first_argument); - return; + DBUG_VOID_RETURN; } ds_result= &ds_res; @@ -3405,16 +3411,7 @@ void do_exec(struct st_command *command) len--; } #endif - if (disable_result_log) - { - if (len) - buf[len-1] = 0; - DBUG_PRINT("exec_result",("%s", buf)); - } - else - { - replace_dynstr_append_mem(ds_result, buf, len); - } + replace_dynstr_append_mem(ds_result, buf, len); } error= pclose(res_file); @@ -3424,7 +3421,7 @@ void do_exec(struct st_command *command) dynstr_free(&ds_sorted); } - if (error > 0) + if (error) { uint status= WEXITSTATUS(error); int i; @@ -3436,7 +3433,7 @@ void do_exec(struct st_command *command) ds_cmd.str, error, status, errno, ds_res.str); dynstr_free(&ds_cmd); - return; + DBUG_VOID_RETURN; } DBUG_PRINT("info", @@ -3470,6 +3467,12 @@ void do_exec(struct st_command *command) } dynstr_free(&ds_cmd); + + if (disable_result_log) + { + /* Disable output in case of successful exit.*/ + dynstr_set(&ds_res,""); + } DBUG_VOID_RETURN; } @@ -3569,7 +3572,7 @@ void do_system(struct st_command *command) if (strlen(command->first_argument) == 0) { report_or_die("Missing arguments to system, nothing to do!"); - return; + DBUG_VOID_RETURN; } init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256); @@ -3607,6 +3610,37 @@ void do_system(struct st_command *command) } +/* returns TRUE if path is inside a sandbox */ +bool is_sub_path(const char *path, size_t plen, const char *sandbox) +{ + size_t len= strlen(sandbox); + if (!sandbox || !len || plen <= len || memcmp(path, sandbox, len - 1) + || path[len] != '/') + return false; + return true; +} + + +/* returns TRUE if path cannot be modified */ +bool bad_path(const char *path) +{ + size_t plen= strlen(path); + + const char *vardir= getenv("MYSQLTEST_VARDIR"); + if (is_sub_path(path, plen, vardir)) + return false; + + const char *tmpdir= getenv("MYSQL_TMP_DIR"); + if (is_sub_path(path, plen, tmpdir)) + return false; + + report_or_die("Path '%s' is not a subdirectory of MYSQLTEST_VARDIR '%s'" + "or MYSQL_TMP_DIR '%s'", + path, vardir, tmpdir); + return true; +} + + /* SYNOPSIS set_wild_chars @@ -3665,6 +3699,9 @@ void do_remove_file(struct st_command *command) rm_args, sizeof(rm_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_filename.str)) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); error= my_delete(ds_filename.str, MYF(disable_warnings ? 0 : MY_WME)) != 0; handle_command_error(command, error, my_errno); @@ -3708,6 +3745,9 @@ void do_remove_files_wildcard(struct st_command *command) ' '); fn_format(dirname, ds_directory.str, "", "", MY_UNPACK_FILENAME); + if (bad_path(ds_directory.str)) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("listing directory: %s", dirname)); if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT | MY_WME)))) { @@ -3782,6 +3822,9 @@ void do_copy_file(struct st_command *command) sizeof(copy_file_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_to_file.str)) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str)); /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */ error= (my_copy(ds_from_file.str, ds_to_file.str, @@ -3819,6 +3862,9 @@ void do_move_file(struct st_command *command) sizeof(move_file_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_to_file.str)) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("Move %s to %s", ds_from_file.str, ds_to_file.str)); error= (my_rename(ds_from_file.str, ds_to_file.str, MYF(disable_warnings ? 0 : MY_WME)) != 0); @@ -3857,6 +3903,9 @@ void do_chmod_file(struct st_command *command) sizeof(chmod_file_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_file.str)) + DBUG_VOID_RETURN; + /* Parse what mode to set */ if (ds_mode.length != 4 || str2int(ds_mode.str, 8, 0, INT_MAX, &mode) == NullS) @@ -3928,6 +3977,9 @@ void do_mkdir(struct st_command *command) mkdir_args, sizeof(mkdir_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_dirname.str)) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("creating directory: %s", ds_dirname.str)); error= my_mkdir(ds_dirname.str, 0777, MYF(MY_WME)) != 0; handle_command_error(command, error, my_errno); @@ -3935,6 +3987,47 @@ void do_mkdir(struct st_command *command) DBUG_VOID_RETURN; } + +/* + Remove directory recursively. +*/ +static int rmtree(const char *dir) +{ + char path[FN_REFLEN]; + char sep[]={ FN_LIBCHAR, 0 }; + int err=0; + + MY_DIR *dir_info= my_dir(dir, MYF(MY_DONT_SORT | MY_WANT_STAT)); + if (!dir_info) + return 1; + + for (uint i= 0; i < dir_info->number_of_files; i++) + { + FILEINFO *file= dir_info->dir_entry + i; + /* Skip "." and ".." */ + if (!strcmp(file->name, ".") || !strcmp(file->name, "..")) + continue; + + strxnmov(path, sizeof(path), dir, sep, file->name, NULL); + + if (!MY_S_ISDIR(file->mystat->st_mode)) + err= my_delete(path, 0); + else + err= rmtree(path); + + if(err) + break; + } + + my_dirend(dir_info); + + if (!err) + err= rmdir(dir); + + return err; +} + + /* SYNOPSIS do_rmdir @@ -3942,12 +4035,11 @@ void do_mkdir(struct st_command *command) DESCRIPTION rmdir <dir_name> - Remove the empty directory <dir_name> + Remove the directory tree */ void do_rmdir(struct st_command *command) { - int error; static DYNAMIC_STRING ds_dirname; const struct command_arg rmdir_args[] = { { "dirname", ARG_STRING, TRUE, &ds_dirname, "Directory to remove" } @@ -3958,9 +4050,13 @@ void do_rmdir(struct st_command *command) rmdir_args, sizeof(rmdir_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_dirname.str)) + DBUG_VOID_RETURN; + DBUG_PRINT("info", ("removing directory: %s", ds_dirname.str)); - error= rmdir(ds_dirname.str) != 0; - handle_command_error(command, error, errno); + if (rmtree(ds_dirname.str)) + handle_command_error(command, 1, errno); + dynstr_free(&ds_dirname); DBUG_VOID_RETURN; } @@ -4073,6 +4169,9 @@ static void do_list_files_write_file_command(struct st_command *command, list_files_args, sizeof(list_files_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_filename.str)) + DBUG_VOID_RETURN; + init_dynamic_string(&ds_content, "", 1024, 1024); error= get_list_files(&ds_content, &ds_dirname, &ds_wild); handle_command_error(command, error, my_errno); @@ -4124,7 +4223,8 @@ void read_until_delimiter(DYNAMIC_STRING *ds, while (1) { c= my_getc(cur_file->file); - + if (c == '\r') + c= my_getc(cur_file->file); if (c == '\n') { cur_file->lineno++; @@ -4175,6 +4275,9 @@ void do_write_file_command(struct st_command *command, my_bool append) sizeof(write_file_args)/sizeof(struct command_arg), ' '); + if (bad_path(ds_filename.str)) + DBUG_VOID_RETURN; + if (!append && access(ds_filename.str, F_OK) == 0) { /* The file should not be overwritten */ @@ -4556,7 +4659,7 @@ void do_perl(struct st_command *command) if (command->abort_on_error) die("popen(\"%s\", \"r\") failed", buf); dynstr_free(&ds_delimiter); - return; + DBUG_VOID_RETURN; } while (fgets(buf, sizeof(buf), res_file)) @@ -9875,25 +9978,39 @@ bool parse_re_part(char *start_re, char *end_re, Returns: st_replace_regex struct with pairs of substitutions */ +void append_replace_regex(char*, char*, struct st_replace_regex*, char**); struct st_replace_regex* init_replace_regex(char* expr) { + char *expr_end, *buf_p; struct st_replace_regex* res; - char* buf,*expr_end; - char* p, start_re, end_re= 1; - char* buf_p; uint expr_len= strlen(expr); - struct st_regex reg; /* my_malloc() will die on fail with MY_FAE */ res=(struct st_replace_regex*)my_malloc( - sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME)); + sizeof(*res)+8192 ,MYF(MY_FAE+MY_WME)); my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex), 128, 128, MYF(0)); - buf= (char*)res + sizeof(*res); expr_end= expr + expr_len; + buf_p= (char*)res + sizeof(*res); + append_replace_regex(expr, expr_end, res, &buf_p); + + res->odd_buf_len= res->even_buf_len= 8192; + res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE)); + res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE)); + res->buf= res->even_buf; + + return res; +} + + +void append_replace_regex(char* expr, char *expr_end, struct st_replace_regex* res, + char **buf_p) +{ + char* p, start_re, end_re= 1; + struct st_regex reg; + p= expr; - buf_p= buf; /* for each regexp substitution statement */ while (p < expr_end) @@ -9912,13 +10029,34 @@ struct st_replace_regex* init_replace_regex(char* expr) } start_re= 0; - reg.pattern= buf_p; - if (parse_re_part(&start_re, &end_re, &p, expr_end, &buf_p)) - goto err; + reg.pattern= *buf_p; + + /* Allow variable for the *entire* list of replacements */ + if (*p == '$') + { + const char *v_end; + VAR *val= var_get(p, &v_end, 0, 1); + + if (val) + { + char *expr, *expr_end; + expr= val->str_val; + expr_end= expr + val->str_val_len; + append_replace_regex(expr, expr_end, res, buf_p); + } + + p= (char *) v_end + 1; + continue; + } + else + { + if (parse_re_part(&start_re, &end_re, &p, expr_end, buf_p)) + goto err; - reg.replace= buf_p; - if (parse_re_part(&start_re, &end_re, &p, expr_end, &buf_p)) - goto err; + reg.replace= *buf_p; + if (parse_re_part(&start_re, &end_re, &p, expr_end, buf_p)) + goto err; + } /* Check if we should do matching case insensitive */ if (p < expr_end && *p == 'i') @@ -9931,17 +10069,12 @@ struct st_replace_regex* init_replace_regex(char* expr) if (insert_dynamic(&res->regex_arr, ®)) die("Out of memory"); } - res->odd_buf_len= res->even_buf_len= 8192; - res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE)); - res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE)); - res->buf= res->even_buf; - return res; + return; err: my_free(res); die("Error parsing replace_regex \"%s\"", expr); - return 0; } /* @@ -10021,12 +10154,6 @@ void do_get_replace_regex(struct st_command *command) { char *expr= command->first_argument; free_replace_regex(); - /* Allow variable for the *entire* list of replacements */ - if (*expr == '$') - { - VAR *val= var_get(expr, NULL, 0, 1); - expr= val ? val->str_val : NULL; - } if (expr && *expr && !(glob_replace_regex=init_replace_regex(expr))) die("Could not init replace_regex"); command->last_argument= command->end; |