1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00
This commit is contained in:
petr@mysql.com
2005-04-21 01:27:03 +04:00
15 changed files with 1043 additions and 42 deletions

View File

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