Loading server-tools/instance-manager/commands.cc +471 −7 Original line number Diff line number Diff line Loading @@ -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: */ Loading Loading @@ -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; } Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -365,19 +378,470 @@ 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); } /* Implementation for Stop_instance: */ 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; } Loading @@ -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; } } Loading server-tools/instance-manager/commands.h +86 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "command.h" #include "instance.h" #include "parse.h" /* Print all instances of this instance manager. Loading Loading @@ -115,6 +116,45 @@ class Stop_instance : public Command }; /* Print requested part of the log Grammar: SHOW <instance_name> log {ERROR | SLOW | GENERAL} size[, offset_from_end] */ class Show_instance_log : public Command { public: 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); int do_command(struct st_net *net, const char *instance_name); int execute(struct st_net *net, ulong connection_id); Log_type log_type; const char *instance_name; uint size; uint offset; }; /* Shows the list of the log files, used by an instance. Grammar: SHOW <instance_name> LOG FILES */ class Show_instance_log_files : public Command { public: Show_instance_log_files(Instance_map *instance_map_arg, const char *name, uint len); int do_command(struct st_net *net, const char *instance_name); int execute(struct st_net *net, ulong connection_id); const char *instance_name; const char *option; }; /* Syntax error command. This command is issued if parser reported a syntax error. We need it to distinguish the parse error and the situation when parser internal Loading @@ -128,4 +168,50 @@ class Syntax_error : public Command int execute(struct st_net *net, ulong connection_id); }; /* Set an option for the instance. Grammar: SET instance_name.option=option_value */ class Set_option : public Command { public: Set_option(Instance_map *instance_map_arg, const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len); /* the following function is virtual to let Unset_option to use */ virtual int do_command(struct st_net *net); int execute(struct st_net *net, ulong connection_id); protected: int correct_file(bool skip); public: const char *instance_name; uint instance_name_len; /* buffer for the option */ enum { MAX_OPTION_LEN= 1024 }; char option[MAX_OPTION_LEN]; char option_value[MAX_OPTION_LEN]; }; /* Remove option of the instance from config file Grammar: UNSET instance_name.option */ class Unset_option: public Set_option { public: Unset_option(Instance_map *instance_map_arg, const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len): Set_option(instance_map_arg, name, len, option_arg, option_len, option_value_arg, option_value_len) {} int do_command(struct st_net *net); }; #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */ server-tools/instance-manager/factory.cc +45 −0 Original line number Diff line number Diff line Loading @@ -16,40 +16,85 @@ #include "factory.h" Show_instances *Command_factory::new_Show_instances() { return new Show_instances(&instance_map); } Flush_instances *Command_factory::new_Flush_instances() { return new Flush_instances(&instance_map); } Show_instance_status *Command_factory:: new_Show_instance_status(const char *name, uint len) { return new Show_instance_status(&instance_map, name, len); } Show_instance_options *Command_factory:: new_Show_instance_options(const char *name, uint len) { return new Show_instance_options(&instance_map, name, len); } Start_instance *Command_factory:: new_Start_instance(const char *name, uint len) { return new Start_instance(&instance_map, name, len); } Stop_instance *Command_factory::new_Stop_instance(const char *name, uint len) { return new Stop_instance(&instance_map, name, len); } Syntax_error *Command_factory::new_Syntax_error() { return new Syntax_error(); } Set_option *Command_factory:: new_Set_option(const char* name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len) { return new Set_option(&instance_map, name, len, option_arg, option_len, option_value_arg, option_value_len); } Unset_option *Command_factory:: new_Unset_option(const char* name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len) { return new Unset_option(&instance_map, name, len, option_arg, option_len, option_value_arg, option_value_len); } Show_instance_log *Command_factory:: new_Show_instance_log(const char *name, uint len, Log_type log_type_arg, const char *size, const char *offset) { return new Show_instance_log(&instance_map, name, len, log_type_arg, size, offset); } Show_instance_log_files *Command_factory:: new_Show_instance_log_files(const char *name, uint len) { return new Show_instance_log_files(&instance_map, name, len); } server-tools/instance-manager/factory.h +18 −2 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ Http_command_factory e.t.c. Also see comment in the instance_map.cc */ class Show_instances; class Command_factory { public: Loading @@ -33,12 +35,26 @@ class Command_factory {} Show_instances *new_Show_instances (); Flush_instances *new_Flush_instances (); Syntax_error *new_Syntax_error (); Show_instance_status *new_Show_instance_status (const char *name, uint len); Show_instance_options *new_Show_instance_options (const char *name, uint len); Start_instance *new_Start_instance (const char *name, uint len); Stop_instance *new_Stop_instance (const char *name, uint len); Flush_instances *new_Flush_instances (); Syntax_error *new_Syntax_error (); Show_instance_log *new_Show_instance_log (const char *name, uint len, Log_type log_type_arg, const char *size, const char *offset); Set_option *new_Set_option (const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len); Unset_option *new_Unset_option (const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len); Show_instance_log_files *new_Show_instance_log_files (const char *name, uint len); Instance_map &instance_map; }; Loading server-tools/instance-manager/instance_options.cc +133 −2 Original line number Diff line number Diff line Loading @@ -21,10 +21,10 @@ #include "instance_options.h" #include "parse_output.h" #include "parse.h" #include "buffer.h" #include <my_sys.h> #include <mysql.h> #include <signal.h> #include <m_string.h> Loading Loading @@ -76,6 +76,135 @@ int Instance_options::get_default_option(char *result, size_t result_len, } int Instance_options::fill_log_options() { /* array for the log option for mysqld */ enum { MAX_LOG_OPTIONS= 8 }; enum { MAX_LOG_OPTION_LENGTH= 256 }; /* the last option must be '\0', so we reserve space for it */ char log_options[MAX_LOG_OPTIONS + 1][MAX_LOG_OPTION_LENGTH]; Buffer buff; uint position= 0; char **tmp_argv= argv; char datadir[MAX_LOG_OPTION_LENGTH]; char hostname[MAX_LOG_OPTION_LENGTH]; uint hostname_length; struct log_files_st { const char *name; uint length; const char **value; const char *default_suffix; } logs[]= { {"--log-error", 11, &error_log, ".err"}, {"--log", 5, &query_log, ".log"}, {"--log-slow-queries", 18, &slow_log, "-slow.log"}, {NULL, 0, NULL, NULL} }; struct log_files_st *log_files; /* clean the buffer before usage */ bzero(log_options, sizeof(log_options)); /* create a "mysqld <argv_options>" command in the buffer */ buff.append(position, mysqld_path, strlen(mysqld_path)); position= strlen(mysqld_path); /* skip the first option */ tmp_argv++; while (*tmp_argv != 0) { buff.append(position, " ", 1); position++; buff.append(position, *tmp_argv, strlen(*tmp_argv)); position+= strlen(*tmp_argv); tmp_argv++; } buff.append(position, "\0", 1); position++; /* get options and parse them */ if (parse_arguments(buff.buffer, "--log", (char *) log_options, MAX_LOG_OPTIONS + 1, MAX_LOG_OPTION_LENGTH)) goto err; /* compute hostname and datadir for the instance */ if (mysqld_datadir == NULL) { if (get_default_option(datadir, MAX_LOG_OPTION_LENGTH, "--datadir")) goto err; } else /* below is safe, as --datadir always has a value */ strncpy(datadir, strchr(mysqld_datadir, '=') + 1, MAX_LOG_OPTION_LENGTH); if (gethostname(hostname,sizeof(hostname)-1) < 0) strmov(hostname, "mysql"); hostname[MAX_LOG_OPTION_LENGTH - 1]= 0; /* Safety */ hostname_length= strlen(hostname); for (log_files= logs; log_files->name; log_files++) { for (int i=0; (i < MAX_LOG_OPTIONS) && (log_options[i][0] != '\0'); i++) { if (!strncmp(log_options[i], log_files->name, log_files->length)) { /* This is really log_files->name option if and only if it is followed by '=', '\0' or space character. This way we can distinguish such options as '--log' and '--log-bin'. This is checked in the following two statements. */ if (log_options[i][log_files->length] == '\0' || my_isspace(default_charset_info, log_options[i][log_files->length])) { char full_name[MAX_LOG_OPTION_LENGTH]; fn_format(full_name, hostname, datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) > strlen(log_files->default_suffix)) { strcpy(full_name + strlen(full_name), log_files->default_suffix); } else goto err; *(log_files->value)= strdup_root(&alloc, datadir); } if (log_options[i][log_files->length] == '=') { char full_name[MAX_LOG_OPTION_LENGTH]; fn_format(full_name, log_options[i] +log_files->length + 1, datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); if (!(*(log_files->value)= strdup_root(&alloc, full_name))) goto err; } } } } return 0; err: return 1; } int Instance_options::get_pid_filename(char *result) { const char *pid_file= mysqld_pid_file; Loading Loading @@ -190,6 +319,8 @@ int Instance_options::complete_initialization(const char *default_path, options_array.elements*sizeof(char*)); argv[filled_default_options + options_array.elements]= 0; fill_log_options(); return 0; err: Loading Loading
server-tools/instance-manager/commands.cc +471 −7 Original line number Diff line number Diff line Loading @@ -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: */ Loading Loading @@ -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; } Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; } Loading @@ -365,19 +378,470 @@ 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); } /* Implementation for Stop_instance: */ 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; } Loading @@ -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; } } Loading
server-tools/instance-manager/commands.h +86 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include "command.h" #include "instance.h" #include "parse.h" /* Print all instances of this instance manager. Loading Loading @@ -115,6 +116,45 @@ class Stop_instance : public Command }; /* Print requested part of the log Grammar: SHOW <instance_name> log {ERROR | SLOW | GENERAL} size[, offset_from_end] */ class Show_instance_log : public Command { public: 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); int do_command(struct st_net *net, const char *instance_name); int execute(struct st_net *net, ulong connection_id); Log_type log_type; const char *instance_name; uint size; uint offset; }; /* Shows the list of the log files, used by an instance. Grammar: SHOW <instance_name> LOG FILES */ class Show_instance_log_files : public Command { public: Show_instance_log_files(Instance_map *instance_map_arg, const char *name, uint len); int do_command(struct st_net *net, const char *instance_name); int execute(struct st_net *net, ulong connection_id); const char *instance_name; const char *option; }; /* Syntax error command. This command is issued if parser reported a syntax error. We need it to distinguish the parse error and the situation when parser internal Loading @@ -128,4 +168,50 @@ class Syntax_error : public Command int execute(struct st_net *net, ulong connection_id); }; /* Set an option for the instance. Grammar: SET instance_name.option=option_value */ class Set_option : public Command { public: Set_option(Instance_map *instance_map_arg, const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len); /* the following function is virtual to let Unset_option to use */ virtual int do_command(struct st_net *net); int execute(struct st_net *net, ulong connection_id); protected: int correct_file(bool skip); public: const char *instance_name; uint instance_name_len; /* buffer for the option */ enum { MAX_OPTION_LEN= 1024 }; char option[MAX_OPTION_LEN]; char option_value[MAX_OPTION_LEN]; }; /* Remove option of the instance from config file Grammar: UNSET instance_name.option */ class Unset_option: public Set_option { public: Unset_option(Instance_map *instance_map_arg, const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len): Set_option(instance_map_arg, name, len, option_arg, option_len, option_value_arg, option_value_len) {} int do_command(struct st_net *net); }; #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */
server-tools/instance-manager/factory.cc +45 −0 Original line number Diff line number Diff line Loading @@ -16,40 +16,85 @@ #include "factory.h" Show_instances *Command_factory::new_Show_instances() { return new Show_instances(&instance_map); } Flush_instances *Command_factory::new_Flush_instances() { return new Flush_instances(&instance_map); } Show_instance_status *Command_factory:: new_Show_instance_status(const char *name, uint len) { return new Show_instance_status(&instance_map, name, len); } Show_instance_options *Command_factory:: new_Show_instance_options(const char *name, uint len) { return new Show_instance_options(&instance_map, name, len); } Start_instance *Command_factory:: new_Start_instance(const char *name, uint len) { return new Start_instance(&instance_map, name, len); } Stop_instance *Command_factory::new_Stop_instance(const char *name, uint len) { return new Stop_instance(&instance_map, name, len); } Syntax_error *Command_factory::new_Syntax_error() { return new Syntax_error(); } Set_option *Command_factory:: new_Set_option(const char* name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len) { return new Set_option(&instance_map, name, len, option_arg, option_len, option_value_arg, option_value_len); } Unset_option *Command_factory:: new_Unset_option(const char* name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len) { return new Unset_option(&instance_map, name, len, option_arg, option_len, option_value_arg, option_value_len); } Show_instance_log *Command_factory:: new_Show_instance_log(const char *name, uint len, Log_type log_type_arg, const char *size, const char *offset) { return new Show_instance_log(&instance_map, name, len, log_type_arg, size, offset); } Show_instance_log_files *Command_factory:: new_Show_instance_log_files(const char *name, uint len) { return new Show_instance_log_files(&instance_map, name, len); }
server-tools/instance-manager/factory.h +18 −2 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ Http_command_factory e.t.c. Also see comment in the instance_map.cc */ class Show_instances; class Command_factory { public: Loading @@ -33,12 +35,26 @@ class Command_factory {} Show_instances *new_Show_instances (); Flush_instances *new_Flush_instances (); Syntax_error *new_Syntax_error (); Show_instance_status *new_Show_instance_status (const char *name, uint len); Show_instance_options *new_Show_instance_options (const char *name, uint len); Start_instance *new_Start_instance (const char *name, uint len); Stop_instance *new_Stop_instance (const char *name, uint len); Flush_instances *new_Flush_instances (); Syntax_error *new_Syntax_error (); Show_instance_log *new_Show_instance_log (const char *name, uint len, Log_type log_type_arg, const char *size, const char *offset); Set_option *new_Set_option (const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len); Unset_option *new_Unset_option (const char *name, uint len, const char *option_arg, uint option_len, const char *option_value_arg, uint option_value_len); Show_instance_log_files *new_Show_instance_log_files (const char *name, uint len); Instance_map &instance_map; }; Loading
server-tools/instance-manager/instance_options.cc +133 −2 Original line number Diff line number Diff line Loading @@ -21,10 +21,10 @@ #include "instance_options.h" #include "parse_output.h" #include "parse.h" #include "buffer.h" #include <my_sys.h> #include <mysql.h> #include <signal.h> #include <m_string.h> Loading Loading @@ -76,6 +76,135 @@ int Instance_options::get_default_option(char *result, size_t result_len, } int Instance_options::fill_log_options() { /* array for the log option for mysqld */ enum { MAX_LOG_OPTIONS= 8 }; enum { MAX_LOG_OPTION_LENGTH= 256 }; /* the last option must be '\0', so we reserve space for it */ char log_options[MAX_LOG_OPTIONS + 1][MAX_LOG_OPTION_LENGTH]; Buffer buff; uint position= 0; char **tmp_argv= argv; char datadir[MAX_LOG_OPTION_LENGTH]; char hostname[MAX_LOG_OPTION_LENGTH]; uint hostname_length; struct log_files_st { const char *name; uint length; const char **value; const char *default_suffix; } logs[]= { {"--log-error", 11, &error_log, ".err"}, {"--log", 5, &query_log, ".log"}, {"--log-slow-queries", 18, &slow_log, "-slow.log"}, {NULL, 0, NULL, NULL} }; struct log_files_st *log_files; /* clean the buffer before usage */ bzero(log_options, sizeof(log_options)); /* create a "mysqld <argv_options>" command in the buffer */ buff.append(position, mysqld_path, strlen(mysqld_path)); position= strlen(mysqld_path); /* skip the first option */ tmp_argv++; while (*tmp_argv != 0) { buff.append(position, " ", 1); position++; buff.append(position, *tmp_argv, strlen(*tmp_argv)); position+= strlen(*tmp_argv); tmp_argv++; } buff.append(position, "\0", 1); position++; /* get options and parse them */ if (parse_arguments(buff.buffer, "--log", (char *) log_options, MAX_LOG_OPTIONS + 1, MAX_LOG_OPTION_LENGTH)) goto err; /* compute hostname and datadir for the instance */ if (mysqld_datadir == NULL) { if (get_default_option(datadir, MAX_LOG_OPTION_LENGTH, "--datadir")) goto err; } else /* below is safe, as --datadir always has a value */ strncpy(datadir, strchr(mysqld_datadir, '=') + 1, MAX_LOG_OPTION_LENGTH); if (gethostname(hostname,sizeof(hostname)-1) < 0) strmov(hostname, "mysql"); hostname[MAX_LOG_OPTION_LENGTH - 1]= 0; /* Safety */ hostname_length= strlen(hostname); for (log_files= logs; log_files->name; log_files++) { for (int i=0; (i < MAX_LOG_OPTIONS) && (log_options[i][0] != '\0'); i++) { if (!strncmp(log_options[i], log_files->name, log_files->length)) { /* This is really log_files->name option if and only if it is followed by '=', '\0' or space character. This way we can distinguish such options as '--log' and '--log-bin'. This is checked in the following two statements. */ if (log_options[i][log_files->length] == '\0' || my_isspace(default_charset_info, log_options[i][log_files->length])) { char full_name[MAX_LOG_OPTION_LENGTH]; fn_format(full_name, hostname, datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) > strlen(log_files->default_suffix)) { strcpy(full_name + strlen(full_name), log_files->default_suffix); } else goto err; *(log_files->value)= strdup_root(&alloc, datadir); } if (log_options[i][log_files->length] == '=') { char full_name[MAX_LOG_OPTION_LENGTH]; fn_format(full_name, log_options[i] +log_files->length + 1, datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); if (!(*(log_files->value)= strdup_root(&alloc, full_name))) goto err; } } } } return 0; err: return 1; } int Instance_options::get_pid_filename(char *result) { const char *pid_file= mysqld_pid_file; Loading Loading @@ -190,6 +319,8 @@ int Instance_options::complete_initialization(const char *default_path, options_array.elements*sizeof(char*)); argv[filled_default_options + options_array.elements]= 0; fill_log_options(); return 0; err: Loading