diff options
author | petr@mysql.com <> | 2005-04-21 01:27:03 +0400 |
---|---|---|
committer | petr@mysql.com <> | 2005-04-21 01:27:03 +0400 |
commit | 0584756fb4bb0e43952da99a8c3e6c29a89a8396 (patch) | |
tree | 45465eae243cec77531a886fcd7559dbea6efe9a /server-tools/instance-manager/commands.cc | |
parent | ab0ff5349d72481c87646efbddfac98a714e3f67 (diff) | |
parent | 83f9ee0786b97352b9926780df36145fc41c4524 (diff) | |
download | mariadb-git-0584756fb4bb0e43952da99a8c3e6c29a89a8396.tar.gz |
merge
Diffstat (limited to 'server-tools/instance-manager/commands.cc')
-rw-r--r-- | server-tools/instance-manager/commands.cc | 478 |
1 files changed, 471 insertions, 7 deletions
diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc index e1f811ef57d..3b4c43d289c 100644 --- a/server-tools/instance-manager/commands.cc +++ b/server-tools/instance-manager/commands.cc @@ -27,6 +27,19 @@ #include <mysql.h> +/* some useful functions */ + +static int put_to_buff(Buffer *buff, const char *str, uint *position) +{ + uint len= strlen(str); + if (buff->append(*position, str, len)) + return 1; + + *position+= len; + return 0; +} + + /* implementation for Show_instances: */ @@ -106,7 +119,7 @@ int Flush_instances::execute(struct st_net *net, ulong connection_id) if (instance_map->flush_instances()) return ER_OUT_OF_RESOURCES; - net_send_ok(net, connection_id); + net_send_ok(net, connection_id, NULL); return 0; } @@ -119,7 +132,7 @@ Show_instance_status::Show_instance_status(Instance_map *instance_map_arg, { Instance *instance; - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) { instance_name= instance->options.instance_name; @@ -225,7 +238,7 @@ Show_instance_options::Show_instance_options(Instance_map *instance_map_arg, { Instance *instance; - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) { instance_name= instance->options.instance_name; @@ -344,7 +357,7 @@ Start_instance::Start_instance(Instance_map *instance_map_arg, const char *name, uint len) :Command(instance_map_arg) { - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) instance_name= instance->options.instance_name; } @@ -365,9 +378,460 @@ int Start_instance::execute(struct st_net *net, ulong connection_id) if (!(instance->options.nonguarded)) instance_map->guardian->guard(instance); - net_send_ok(net, connection_id); + net_send_ok(net, connection_id, "Instance started"); + return 0; + } +} + + +/* implementation for Show_instance_log: */ + +Show_instance_log::Show_instance_log(Instance_map *instance_map_arg, + const char *name, uint len, + Log_type log_type_arg, + const char *size_arg, + const char *offset_arg) + :Command(instance_map_arg) +{ + Instance *instance; + + if (offset_arg != NULL) + offset= atoi(offset_arg); + else + offset= 0; + size= atoi(size_arg); + log_type= log_type_arg; + + /* we make a search here, since we don't want to store the name */ + if ((instance= instance_map->find(name, len))) + { + instance_name= instance->options.instance_name; + } + else + instance_name= NULL; +} + + +int Show_instance_log::do_command(struct st_net *net, + const char *instance_name) +{ + enum { MAX_VERSION_LENGTH= 40 }; + Buffer send_buff; /* buffer for packets */ + LIST name; + LIST *field_list; + NAME_WITH_LENGTH name_field; + uint position=0; + + /* create list of the fileds to be passed to send_fields */ + name_field.name= (char *) "Log"; + name_field.length= 20; + name.data= &name_field; + field_list= list_add(NULL, &name); + + /* cannot read negative number of bytes */ + if (offset > size) + return ER_SYNTAX_ERROR; + + send_fields(net, field_list); + + { + Instance *instance; + const char *logpath; + File fd; + + if ((instance= instance_map->find(instance_name, strlen(instance_name))) == NULL) + goto err; + + switch (log_type) + { + case LOG_ERROR: + logpath= instance->options.error_log; + break; + case LOG_GENERAL: + logpath= instance->options.query_log; + break; + case LOG_SLOW: + logpath= instance->options.slow_log; + break; + default: + logpath= NULL; + } + + /* Instance has no such log */ + if (logpath == NULL) + { + return ER_NO_SUCH_LOG; + } + else if (*logpath == '\0') + { + return ER_GUESS_LOGFILE; + } + + + if ((fd= open(logpath, O_RDONLY))) + { + size_t buff_size; + int read_len; + /* calculate buffer size */ + struct stat file_stat; + + if(fstat(fd, &file_stat)) + goto err; + + buff_size= (size - offset); + + /* read in one chunk */ + read_len= my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0)); + + char *bf= (char *) malloc(sizeof(char)*buff_size); + read_len= my_read(fd, bf, buff_size, MYF(0)); + store_to_string(&send_buff, (char *) bf, &position, read_len); + close(fd); + } + else + { + return ER_OPEN_LOGFILE; + } + + if (my_net_write(net, send_buff.buffer, (uint) position)) + goto err; + } + + send_eof(net); + net_flush(net); + + return 0; + +err: + return ER_OUT_OF_RESOURCES; +} + + +int Show_instance_log::execute(struct st_net *net, ulong connection_id) +{ + if (instance_name != NULL) + { + return do_command(net, instance_name); + } + else + { + return ER_BAD_INSTANCE_NAME; + } +} + + + +/* implementation for Show_instance_log_files: */ + +Show_instance_log_files::Show_instance_log_files + (Instance_map *instance_map_arg, const char *name, uint len) + :Command(instance_map_arg) +{ + Instance *instance; + + /* we make a search here, since we don't want to store the name */ + if ((instance= instance_map->find(name, len))) + { + instance_name= instance->options.instance_name; + } + else + instance_name= NULL; +} + + +/* + The method sends a table with a the list of the log files + used by the instance. + + SYNOPSYS + Show_instance_log_files::do_command() + net The network connection to the client. + instance_name The name of the instance. + + RETURN + 0 - ok + 1 - error occured +*/ + + +int Show_instance_log_files::do_command(struct st_net *net, + const char *instance_name) +{ + enum { MAX_VERSION_LENGTH= 40 }; + Buffer send_buff; /* buffer for packets */ + LIST name, path, size; + LIST *field_list; + NAME_WITH_LENGTH name_field, path_field, size_field; + uint position=0; + + /* create list of the fileds to be passed to send_fields */ + name_field.name= (char *) "Logfile"; + name_field.length= 20; + name.data= &name_field; + path_field.name= (char *) "Path"; + path_field.length= 20; + path.data= &path_field; + size_field.name= (char *) "Filesize"; + size_field.length= 20; + size.data= &size_field; + field_list= list_add(NULL, &size); + field_list= list_add(field_list, &path); + field_list= list_add(field_list, &name); + + send_fields(net, field_list); + + Instance *instance; + + if ((instance= instance_map-> + find(instance_name, strlen(instance_name))) == NULL) + goto err; + { + /* + We have alike structure in instance_options.cc. We use such to be able + to loop througt the options, which we need to handle in some common way. + */ + struct log_files_st + { + const char *name; + const char *value; + } logs[]= + { + {"ERROR LOG", instance->options.error_log}, + {"GENERAL LOG", instance->options.query_log}, + {"SLOW LOG", instance->options.slow_log}, + {NULL, NULL} + }; + struct log_files_st *log_files; + + + instance->options.print_argv(); + for (log_files= logs; log_files->name; log_files++) + { + if (log_files->value != NULL) + { + struct stat file_stat; + char buff[20]; + + position= 0; + /* store the type of the log in the send buffer */ + store_to_string(&send_buff, log_files->name, &position); + switch (stat(log_files->value, &file_stat)) { + case 0: + if (S_ISREG(file_stat.st_mode)) + { + store_to_string(&send_buff, + (char *) log_files->value, + &position); + int10_to_str(file_stat.st_size, buff, 10); + store_to_string(&send_buff, (char *) buff, &position); + break; + } + default: + store_to_string(&send_buff, + "", + &position); + store_to_string(&send_buff, (char *) "0", &position); + } + if (my_net_write(net, send_buff.buffer, (uint) position)) + goto err; + } + } + } + + send_eof(net); + net_flush(net); + + return 0; + +err: + return 1; +} +int Show_instance_log_files::execute(struct st_net *net, ulong connection_id) +{ + if (instance_name != NULL) + { + if (do_command(net, instance_name)) + return ER_OUT_OF_RESOURCES; return 0; } + else + { + return ER_BAD_INSTANCE_NAME; + } +} + + +/* implementation for SET nstance_name.option=option_value: */ + +Set_option::Set_option(Instance_map *instance_map_arg, + const char *name, uint len, + const char *option_arg, uint option_len_arg, + const char *option_value_arg, uint option_value_len_arg) + :Command(instance_map_arg) +{ + Instance *instance; + + /* we make a search here, since we don't want to store the name */ + if ((instance= instance_map->find(name, len))) + { + instance_name= instance->options.instance_name; + /* add prefix for add_option */ + if ((option_len_arg < MAX_OPTION_LEN - 1) || + (option_value_len_arg < MAX_OPTION_LEN - 1)) + { + strncpy(option, option_arg, option_len_arg); + option[option_len_arg]= 0; + strncpy(option_value, option_value_arg, option_value_len_arg); + option_value[option_value_len_arg]= 0; + } + else + { + option[0]= 0; + option_value[0]= 0; + } + instance_name_len= len; + } + else + { + instance_name= NULL; + instance_name_len= 0; + } +} + + +/* + Correct the file. skip option could be used in future if we don't want to + let user change the options file (E.g. he lacks permissions to do that) +*/ +int Set_option::correct_file(bool skip) +{ + FILE *cnf_file; + const char *default_location="/etc/my.cnf"; + char linebuff[4096], *ptr; + uint optlen; + Buffer file_buffer; + uint position= 0; + bool isfound= false; + + optlen= strlen(option); + + if (!(cnf_file= my_fopen(default_location, O_RDONLY, MYF(0)))) + goto err_fopen; + + while (fgets(linebuff, sizeof(linebuff), cnf_file)) + { + /* if the section is found traverse it */ + if (isfound) + { + /* skip the old value of the option we are changing */ + if (strncmp(linebuff, option, optlen)) + { + /* copy all other lines line */ + put_to_buff(&file_buffer, linebuff, &position); + } + } + else + put_to_buff(&file_buffer, linebuff, &position); + + /* looking for appropriate instance section */ + for (ptr= linebuff ; my_isspace(&my_charset_latin1,*ptr) ; ptr++); + if (*ptr == '[') + { + /* copy the line to the buffer */ + if (!strncmp(++ptr, instance_name, instance_name_len)) + { + isfound= true; + /* add option */ + if (!skip) + { + put_to_buff(&file_buffer, option, &position); + if (option_value[0] != 0) + { + put_to_buff(&file_buffer, "=", &position); + put_to_buff(&file_buffer, option_value, &position); + } + /* add a newline */ + put_to_buff(&file_buffer, "\n", &position); + } + } + else + isfound= false; /* mark that this section is of no interest to us */ + } + + } + + if (my_fclose(cnf_file, MYF(0))) + goto err; + + /* we must hold an instance_map mutex while changing config file */ + instance_map->lock(); + + if (!(cnf_file= my_fopen(default_location, O_WRONLY|O_TRUNC, MYF(0)))) + goto err; + if (my_fwrite(cnf_file, file_buffer.buffer, position, MYF(MY_NABP))) + goto err; + + if (my_fclose(cnf_file, MYF(0))) + goto err; + + instance_map->unlock(); + + return 0; + +err: + my_fclose(cnf_file, MYF(0)); + return ER_OUT_OF_RESOURCES; +err_fopen: + return ER_ACCESS_OPTION_FILE; +} + + +/* + The method sets an option in the the default config file (/etc/my.cnf). + + SYNOPSYS + Set_option::do_command() + net The network connection to the client. + + RETURN + 0 - ok + 1 - error occured +*/ + + +int Set_option::do_command(struct st_net *net) +{ + return correct_file(false); +} + + +int Set_option::execute(struct st_net *net, ulong connection_id) +{ + if (instance_name != NULL) + { + int val; + + val= do_command(net); + if (val == 0) + { + net_send_ok(net, connection_id, NULL); + return 0; + } + + return val; + } + else + { + return ER_BAD_INSTANCE_NAME; + } +} + + +/* the only function from Unset_option we need to Implement */ + +int Unset_option::do_command(struct st_net *net) +{ + return correct_file(true); } @@ -377,7 +841,7 @@ Stop_instance::Stop_instance(Instance_map *instance_map_arg, const char *name, uint len) :Command(instance_map_arg) { - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) instance_name= instance->options.instance_name; } @@ -398,7 +862,7 @@ int Stop_instance::execute(struct st_net *net, ulong connection_id) stop_guard(instance); if ((err_code= instance->stop())) return err_code; - net_send_ok(net, connection_id); + net_send_ok(net, connection_id, NULL); return 0; } } |