mysqladmin.cc 39.3 KB
Newer Older
1
/* Copyright (C) 2000-2006 MySQL AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4
   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
5
   the Free Software Foundation; version 2 of the License.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
6

bk@work.mysql.com's avatar
bk@work.mysql.com committed
7 8 9 10
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
11

bk@work.mysql.com's avatar
bk@work.mysql.com committed
12 13 14 15 16 17
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* maintaince of mysql databases */

monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
18
#include "client_priv.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
19 20 21 22
#include <signal.h>
#ifdef THREAD
#include <my_pthread.h>				/* because of signal()	*/
#endif
23
#include <sys/stat.h>
24
#include <mysql.h>
25
#include <sql_common.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26

27
#define ADMIN_VERSION "8.42"
28
#define MAX_MYSQL_VAR 512
29
#define SHUTDOWN_DEF_TIMEOUT 3600		/* Wait for shutdown */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
30 31
#define MAX_TRUNC_LENGTH 3

32
char *host= NULL, *user= 0, *opt_password= 0,
33
     *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
34 35 36 37
char truncated_var_names[MAX_MYSQL_VAR][MAX_TRUNC_LENGTH];
char ex_var_names[MAX_MYSQL_VAR][FN_REFLEN];
ulonglong last_values[MAX_MYSQL_VAR];
static int interval=0;
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
38
static my_bool option_force=0,interrupted=0,new_line=0,
39
               opt_compress=0, opt_relative=0, opt_verbose=0, opt_vertical=0,
40 41 42 43
               tty_password= 0, opt_nobeep;
static my_bool debug_info_flag= 0, debug_check_flag= 0;
static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations;
static uint opt_count_iterations= 0, my_end_arg;
44
static ulong opt_connect_timeout, opt_shutdown_timeout;
45
static char * unix_port=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
46

47 48 49 50
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
static uint opt_protocol=0;
51
static myf error_flags; /* flags to pass to my_printf_error, like ME_BELL */
52

53 54 55 56 57 58
/*
  When using extended-status relatively, ex_val_max_len is the estimated
  maximum length for any relative value printed by extended-status. The
  idea is to try to keep the length of output as short as possible.
*/

bk@work.mysql.com's avatar
bk@work.mysql.com committed
59 60 61 62
static uint ex_val_max_len[MAX_MYSQL_VAR];
static my_bool ex_status_printed = 0; /* First output is not relative. */
static uint ex_var_count, max_var_length, max_val_length;

63
#include <sslopt-vars.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
64 65 66

static void print_version(void);
static void usage(void);
67 68
extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
                                  char *argument);
69
static my_bool sql_connect(MYSQL *mysql, uint wait);
70
static int execute_commands(MYSQL *mysql,int argc, char **argv);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
71
static int drop_db(MYSQL *mysql,const char *db);
72
extern "C" sig_handler endprog(int signal_number);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
73 74 75 76 77 78 79 80 81 82
static void nice_time(ulong sec,char *buff);
static void print_header(MYSQL_RES *result);
static void print_top(MYSQL_RES *result);
static void print_row(MYSQL_RES *result,MYSQL_ROW cur, uint row);
static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row);
static void print_relative_row_vert(MYSQL_RES *result, MYSQL_ROW cur, uint row);
static void print_relative_header();
static void print_relative_line();
static void truncate_names();
static my_bool get_pidfile(MYSQL *mysql, char *pidfile);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
83 84
static my_bool wait_pidfile(char *pidfile, time_t last_modified,
			    struct stat *pidfile_status);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
85 86 87 88 89 90
static void store_values(MYSQL_RES *result);

/*
  The order of commands must be the same as command_names,
  except ADMIN_ERROR
*/
91 92
enum commands {
  ADMIN_ERROR,
93
  ADMIN_CREATE,           ADMIN_DROP,            ADMIN_SHUTDOWN,
94 95 96 97 98 99
  ADMIN_RELOAD,           ADMIN_REFRESH,         ADMIN_VER,
  ADMIN_PROCESSLIST,      ADMIN_STATUS,          ADMIN_KILL,
  ADMIN_DEBUG,            ADMIN_VARIABLES,       ADMIN_FLUSH_LOGS,
  ADMIN_FLUSH_HOSTS,      ADMIN_FLUSH_TABLES,    ADMIN_PASSWORD,
  ADMIN_PING,             ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
  ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE,     ADMIN_STOP_SLAVE,
100
  ADMIN_FLUSH_THREADS,    ADMIN_OLD_PASSWORD
bk@work.mysql.com's avatar
bk@work.mysql.com committed
101
};
102 103 104 105 106 107 108
static const char *command_names[]= {
  "create",               "drop",                "shutdown",
  "reload",               "refresh",             "version",
  "processlist",          "status",              "kill",
  "debug",                "variables",           "flush-logs",
  "flush-hosts",          "flush-tables",        "password",
  "ping",                 "extended-status",     "flush-status",
109 110
  "flush-privileges",     "start-slave",         "stop-slave",
  "flush-threads","old-password",
111 112 113
  NullS
};

bk@work.mysql.com's avatar
bk@work.mysql.com committed
114
static TYPELIB command_typelib=
bar@mysql.com's avatar
bar@mysql.com committed
115
{ array_elements(command_names)-1,"commands", command_names, NULL};
bk@work.mysql.com's avatar
bk@work.mysql.com committed
116

117 118
static struct my_option my_long_options[] =
{
119
#ifdef __NETWARE__
120
  {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
121
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
122
#endif
123
  {"count", 'c',
124
   "Number of iterations to make. This works with -i (--sleep) only.",
125
   (uchar**) &nr_iterations, (uchar**) &nr_iterations, 0, GET_UINT,
126
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
127
#ifndef DBUG_OFF
128
  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
129
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
130 131 132 133 134 135 136
#endif
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
   (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
   (uchar**) &debug_info_flag, (uchar**) &debug_info_flag,
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
137 138
  {"force", 'f',
   "Don't ask for confirmation on drop database; with multiple commands, continue even if an error occurs.",
139
   (uchar**) &option_force, (uchar**) &option_force, 0, GET_BOOL, NO_ARG, 0, 0,
140
   0, 0, 0, 0},
141
  {"compress", 'C', "Use compression in server/client protocol.",
142
   (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
143 144
   0, 0, 0},
  {"character-sets-dir", OPT_CHARSETS_DIR,
145 146
   "Directory where character sets are.", (uchar**) &charsets_dir,
   (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
147
  {"default-character-set", OPT_DEFAULT_CHARSET,
148 149
   "Set the default character set.", (uchar**) &default_charset,
   (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
150 151
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
152
  {"host", 'h', "Connect to host.", (uchar**) &host, (uchar**) &host, 0, GET_STR,
153
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
154 155
  {"no-beep", 'b', "Turn off beep on error.", (uchar**) &opt_nobeep,
   (uchar**) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 
156 157 158
  {"password", 'p',
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
159
#ifdef __WIN__
160 161
  {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
   NO_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
162
#endif
163 164 165 166 167 168
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
#if MYSQL_PORT_DEFAULT == 0
   "/etc/services, "
#endif
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
169
   (uchar**) &tcp_port,
170
   (uchar**) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
171
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
172
    0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
173 174
  {"relative", 'r',
   "Show difference between current and previous values when used with -i. Currently works only with extended-status.",
175
   (uchar**) &opt_relative, (uchar**) &opt_relative, 0, GET_BOOL, NO_ARG, 0, 0, 0,
176 177
  0, 0, 0},
  {"set-variable", 'O',
178
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
179
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
180
#ifdef HAVE_SMEM
181
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
182
   "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name,
183 184
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#endif
185
  {"silent", 's', "Silently exit if one can't connect to server.",
186 187
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
  {"socket", 'S', "Socket file to use for connection.",
188
   (uchar**) &unix_port, (uchar**) &unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
189
   0, 0, 0},
190
  {"sleep", 'i', "Execute commands again and again with a sleep between.",
191
   (uchar**) &interval, (uchar**) &interval, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0,
192
   0, 0},
193
#include <sslopt-longopts.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
194
#ifndef DONT_ALLOW_USER_CHANGE
195 196
  {"user", 'u', "User for login if not current user.", (uchar**) &user,
   (uchar**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
bk@work.mysql.com's avatar
bk@work.mysql.com committed
197
#endif
198 199
  {"verbose", 'v', "Write more information.", (uchar**) &opt_verbose,
   (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
200
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
201
   NO_ARG, 0, 0, 0, 0, 0, 0},
202
  {"vertical", 'E',
203
   "Print output vertically. Is similar to --relative, but prints output vertically.",
204
   (uchar**) &opt_vertical, (uchar**) &opt_vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0,
205
   0, 0, 0},
206
  {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_UINT,
207
   OPT_ARG, 0, 0, 0, 0, 0, 0},
208 209
  {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (uchar**) &opt_connect_timeout,
   (uchar**) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 3600*12, 0,
210
   3600*12, 0, 1, 0},
211 212
  {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (uchar**) &opt_shutdown_timeout,
   (uchar**) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG,
213 214
   SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0},
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
215 216
};

217

bk@work.mysql.com's avatar
bk@work.mysql.com committed
218 219
static const char *load_default_groups[]= { "mysqladmin","client",0 };

220
my_bool
221 222
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
	       char *argument)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
223
{
224 225 226
  int error = 0;

  switch(optid) {
227
#ifdef __NETWARE__
228 229
  case OPT_AUTO_CLOSE:
    setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
230 231
    break;
#endif
232 233 234
  case 'c':
    opt_count_iterations= 1;
    break;
235
  case 'p':
236 237
    if (argument == disabled_my_option)
      argument= (char*) "";			// Don't require password
238 239 240 241 242 243 244 245
    if (argument)
    {
      char *start=argument;
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
      opt_password=my_strdup(argument,MYF(MY_FAE));
      while (*argument) *argument++= 'x';		/* Destroy argument */
      if (*start)
	start[1]=0;				/* Cut length of argument */
246
      tty_password= 0;
247 248 249 250 251 252 253 254
    }
    else
      tty_password=1;
    break;
  case 's':
    option_silent++;
    break;
  case 'W':
bk@work.mysql.com's avatar
bk@work.mysql.com committed
255
#ifdef __WIN__
256
    opt_protocol = MYSQL_PROTOCOL_PIPE;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
257
#endif
258 259 260 261
    break;
  case '#':
    DBUG_PUSH(argument ? argument : "d:t:o,/tmp/mysqladmin.trace");
    break;
262
#include <sslopt-case.h>
263 264 265 266 267 268 269 270 271 272 273
  case 'V':
    print_version();
    exit(0);
    break;
  case 'w':
    if (argument)
    {
      if ((option_wait=atoi(argument)) <= 0)
	option_wait=1;
    }
    else
274
      option_wait= ~(uint)0;
275 276 277 278 279 280
    break;
  case '?':
  case 'I':					/* Info */
    error++;
    break;
  case OPT_CHARSETS_DIR:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
281
#if MYSQL_VERSION_ID > 32300
282
    charsets_dir = argument;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
283
#endif
284
    break;
285
  case OPT_MYSQL_PROTOCOL:
286 287
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
                                    opt->name);
288 289
    break;
  }
290
  if (error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
291 292 293 294
  {
    usage();
    exit(1);
  }
295 296 297 298 299 300
  return 0;
}


int main(int argc,char *argv[])
{
301
  int error= 0, ho_error;
302
  MYSQL mysql;
303 304
  char **commands, **save_argv;

305 306 307
  MY_INIT(argv[0]);
  mysql_init(&mysql);
  load_defaults("my",load_default_groups,&argc,&argv);
308
  save_argv = argv;				/* Save for free_defaults */
309
  if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
310 311
  {
    free_defaults(save_argv);
312
    exit(ho_error);
313
  }
314 315 316 317
  if (debug_info_flag)
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
  if (debug_check_flag)
    my_end_arg= MY_CHECK_ERROR;
318

319 320 321 322 323 324
  if (argc == 0)
  {
    usage();
    exit(1);
  }
  commands = argv;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
325
  if (tty_password)
326
    opt_password = get_tty_password(NullS);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
327 328 329 330 331 332

  VOID(signal(SIGINT,endprog));			/* Here if abort */
  VOID(signal(SIGTERM,endprog));		/* Here if abort */

  if (opt_compress)
    mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
333 334 335 336 337
  if (opt_connect_timeout)
  {
    uint tmp=opt_connect_timeout;
    mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT, (char*) &tmp);
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
338 339 340
#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
    mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
341
		  opt_ssl_capath, opt_ssl_cipher);
342 343
  mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
                (char*)&opt_ssl_verify_server_cert);
344
#endif
345 346 347 348 349
  if (opt_protocol)
    mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
#ifdef HAVE_SMEM
  if (shared_memory_base_name)
    mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
350
#endif
351
  mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
352 353
  error_flags= (myf)(opt_nobeep ? 0 : ME_BELL);

354
  if (sql_connect(&mysql, option_wait))
355
  {
356 357 358 359 360
    /*
      We couldn't get an initial connection and will definitely exit.
      The following just determines the exit-code we'll give.
    */

361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
    unsigned int err= mysql_errno(&mysql);
    if (err >= CR_MIN_ERROR && err <= CR_MAX_ERROR)
      error= 1;
    else
    {
      /* Return 0 if all commands are PING */
      for (; argc > 0; argv++, argc--)
      {
        if (find_type(argv[0], &command_typelib, 2) != ADMIN_PING)
        {
          error= 1;
          break;
        }
      }
    }
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
377 378
  else
  {
379 380 381 382 383 384 385 386 387
    /*
      --count=0 aborts right here. Otherwise iff --sleep=t ("interval")
      is given a t!=0, we get an endless loop, or n iterations if --count=n
      was given an n!=0. If --sleep wasn't given, we get one iteration.

      To wit, --wait loops the connection-attempts, while --sleep loops
      the command execution (endlessly if no --count is given).
    */

388
    while (!interrupted && (!opt_count_iterations || nr_iterations))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
389 390
    {
      new_line = 0;
391 392

      if ((error= execute_commands(&mysql,argc,commands)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
393
      {
394 395 396 397 398
        /*
          Unknown/malformed command always aborts and can't be --forced.
          If the user got confused about the syntax, proceeding would be
          dangerous ...
        */
399
	if (error > 0)
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
	  break;

        /*
          Command was well-formed, but failed on the server. Might succeed
          on retry (if conditions on server change etc.), but needs --force
          to retry.
        */
        if (!option_force)
          break;
      }                                         /* if((error= ... */

      if (interval)                             /* --sleep=interval given */
      {
        /*
          If connection was dropped (unintentionally, or due to SHUTDOWN),
          re-establish it if --wait ("retry-connect") was given and user
          didn't signal for us to die. Otherwise, signal failure.
        */

	if (mysql.net.vio == 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
420
	{
421 422
	  if (option_wait && !interrupted)
	  {
423 424 425 426 427 428 429
	    sleep(1);
	    sql_connect(&mysql, option_wait);
	    /*
	      continue normally and decrease counters so that
	      "mysqladmin --count=1 --wait=1 shutdown"
	      cannot loop endlessly.
	    */
430
	  }
431 432 433 434 435 436 437 438 439 440 441
	  else
	  {
	    /*
	      connexion broke, and we have no order to re-establish it. fail.
	    */
	    if (!option_force)
	      error= 1;
	    break;
	  }
	}                                       /* lost connection */

bk@work.mysql.com's avatar
bk@work.mysql.com committed
442 443 444 445 446
	sleep(interval);
	if (new_line)
	  puts("");
      }
      else
447 448 449 450 451
        break;                                  /* no --sleep, done looping */
    }                                           /* command-loop */
  }                                             /* got connection */

  mysql_close(&mysql);
452
  my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
453
  my_free(user,MYF(MY_ALLOW_ZERO_PTR));
454 455 456
#ifdef HAVE_SMEM
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
#endif
457
  free_defaults(save_argv);
458
  my_end(my_end_arg);
459
  exit(error ? 1 : 0);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
460 461 462 463
  return 0;
}


464
sig_handler endprog(int signal_number __attribute__((unused)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
465 466 467 468
{
  interrupted=1;
}

469 470 471 472 473 474 475 476 477 478 479
/**
   @brief connect to server, optionally waiting for same to come up

   @param  mysql     connection struct
   @param  wait      wait for server to come up?
                     (0: no, ~0: forever, n: cycles)

   @return Operation result
   @retval 0         success
   @retval 1         failure
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
480

481
static my_bool sql_connect(MYSQL *mysql, uint wait)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
482 483 484 485 486
{
  my_bool info=0;

  for (;;)
  {
487
    if (mysql_real_connect(mysql,host,user,opt_password,NullS,tcp_port,
488
			   unix_port, CLIENT_REMEMBER_OPTIONS))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
489
    {
490
      mysql->reconnect= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
491 492 493 494 495 496 497
      if (info)
      {
	fputs("\n",stderr);
	(void) fflush(stderr);
      }
      return 0;
    }
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
498

499
    if (!wait)                                  // was or reached 0, fail
bk@work.mysql.com's avatar
bk@work.mysql.com committed
500
    {
501
      if (!option_silent)                       // print diagnostics
bk@work.mysql.com's avatar
bk@work.mysql.com committed
502 503
      {
	if (!host)
504
	  host= (char*) LOCAL_HOST;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
505
	my_printf_error(0,"connect to server at '%s' failed\nerror: '%s'",
506
			error_flags, host, mysql_error(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
	if (mysql_errno(mysql) == CR_CONNECTION_ERROR)
	{
	  fprintf(stderr,
		  "Check that mysqld is running and that the socket: '%s' exists!\n",
		  unix_port ? unix_port : mysql_unix_port);
	}
	else if (mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
		 mysql_errno(mysql) == CR_UNKNOWN_HOST)
	{
	  fprintf(stderr,"Check that mysqld is running on %s",host);
	  fprintf(stderr," and that the port is %d.\n",
		  tcp_port ? tcp_port: mysql_port);
	  fprintf(stderr,"You can check this by doing 'telnet %s %d'\n",
		  host, tcp_port ? tcp_port: mysql_port);
	}
      }
      return 1;
    }
525

bk@work.mysql.com's avatar
bk@work.mysql.com committed
526
    if (wait != (uint) ~0)
527 528
      wait--;				/* count down, one less retry */

bk@work.mysql.com's avatar
bk@work.mysql.com committed
529 530
    if ((mysql_errno(mysql) != CR_CONN_HOST_ERROR) &&
	(mysql_errno(mysql) != CR_CONNECTION_ERROR))
531
    {
532 533 534 535 536
      /*
        Error is worse than "server doesn't answer (yet?)";
        fail even if we still have "wait-coins" unless --force
        was also given.
      */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
537 538 539 540
      fprintf(stderr,"Got error: %s\n", mysql_error(mysql));
      if (!option_force)
	return 1;
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
541
    else if (!option_silent)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
542
    {
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
543 544 545 546 547 548 549 550
      if (!info)
      {
	info=1;
	fputs("Waiting for MySQL server to answer",stderr);
	(void) fflush(stderr);
      }
      else
      {
551
	putc('.',stderr);
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
552 553
	(void) fflush(stderr);
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
554
    }
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
555
    sleep(5);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
556 557 558
  }
}

559

560 561 562 563 564 565 566 567 568 569 570 571
/**
   @brief Execute all commands

   @details We try to execute all commands we were given, in the order
            given, but return with non-zero as soon as we encounter trouble.
            By that token, individual commands can be considered a conjunction
            with boolean short-cut.

   @return success?
   @retval 0       Yes!  ALL commands worked!
   @retval 1       No, one failed and will never work (malformed): fatal error!
   @retval -1      No, one failed on the server, may work next time!
572
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
573

574
static int execute_commands(MYSQL *mysql,int argc, char **argv)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
575
{
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
576
  const char *status;
577 578 579 580 581 582 583
  /*
    MySQL documentation relies on the fact that mysqladmin will
    execute commands in the order specified, e.g.
    mysqladmin -u root flush-privileges password "newpassword"
    to reset a lost root password.
    If this behaviour is ever changed, Docs should be notified.
  */
584

585
  struct rand_struct rand_st;
586

bk@work.mysql.com's avatar
bk@work.mysql.com committed
587 588 589 590 591 592 593 594
  for (; argc > 0 ; argv++,argc--)
  {
    switch (find_type(argv[0],&command_typelib,2)) {
    case ADMIN_CREATE:
    {
      char buff[FN_REFLEN+20];
      if (argc < 2)
      {
595
	my_printf_error(0, "Too few arguments to create", error_flags);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
596 597
	return 1;
      }
598
      sprintf(buff,"create database `%.*s`",FN_REFLEN,argv[1]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
599
      if (mysql_query(mysql,buff))
600
      {
601
	my_printf_error(0,"CREATE DATABASE failed; error: '%-.200s'",
602
			error_flags, mysql_error(mysql));
603
	return -1;
604
      }
605
      argc--; argv++;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
606 607 608 609 610 611
      break;
    }
    case ADMIN_DROP:
    {
      if (argc < 2)
      {
612
	my_printf_error(0, "Too few arguments to drop", error_flags);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
613 614
	return 1;
      }
615
      if (drop_db(mysql,argv[1]))
616
	return -1;
617
      argc--; argv++;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
618 619 620 621 622
      break;
    }
    case ADMIN_SHUTDOWN:
    {
      char pidfile[FN_REFLEN];
623
      my_bool got_pidfile= 0;
624
      time_t last_modified= 0;
625 626
      struct stat pidfile_status;

627 628 629 630
      /*
	Only wait for pidfile on local connections
	If pidfile doesn't exist, continue without pid file checking
      */
631 632
      if (mysql->unix_socket && (got_pidfile= !get_pidfile(mysql, pidfile)) &&
	  !stat(pidfile, &pidfile_status))
633 634
	last_modified= pidfile_status.st_mtime;

635
      if (mysql_shutdown(mysql, SHUTDOWN_DEFAULT))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
636
      {
637
	my_printf_error(0, "shutdown failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
638
			mysql_error(mysql));
639
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
640
      }
641
      argc=1;                   /* force SHUTDOWN to be the last command    */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
642 643 644 645
      if (got_pidfile)
      {
	if (opt_verbose)
	  printf("Shutdown signal sent to server;  Waiting for pid file to disappear\n");
646 647

	/* Wait until pid file is gone */
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
648 649
	if (wait_pidfile(pidfile, last_modified, &pidfile_status))
	  return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
650 651 652 653 654
      }
      break;
    }
    case ADMIN_FLUSH_PRIVILEGES:
    case ADMIN_RELOAD:
655
      if (mysql_query(mysql,"flush privileges"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
656
      {
657
	my_printf_error(0, "reload failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
658
			mysql_error(mysql));
659
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
660 661 662 663 664
      }
      break;
    case ADMIN_REFRESH:
      if (mysql_refresh(mysql,
			(uint) ~(REFRESH_GRANT | REFRESH_STATUS |
665
				 REFRESH_READ_LOCK | REFRESH_SLAVE |
666
				 REFRESH_MASTER)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
667
      {
668
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
669
			mysql_error(mysql));
670
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
671 672 673
      }
      break;
    case ADMIN_FLUSH_THREADS:
674
      if (mysql_refresh(mysql,(uint) REFRESH_THREADS))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
675
      {
676
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
677
			mysql_error(mysql));
678
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
679 680 681 682 683
      }
      break;
    case ADMIN_VER:
      new_line=1;
      print_version();
684
      puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
685
      puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
686 687 688 689 690 691 692 693 694 695 696
      printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
      printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
      printf("Connection\t\t%s\n",mysql_get_host_info(mysql));
      if (mysql->unix_socket)
	printf("UNIX socket\t\t%s\n", mysql->unix_socket);
      else
	printf("TCP port\t\t%d\n", mysql->port);
      status=mysql_stat(mysql);
      {
	char *pos,buff[40];
	ulong sec;
697
	pos= (char*) strchr(status,' ');
bk@work.mysql.com's avatar
bk@work.mysql.com committed
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
	*pos++=0;
	printf("%s\t\t\t",status);			/* print label */
	if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
	{
	  nice_time(sec,buff);
	  puts(buff);				/* print nice time */
	  while (*status == ' ') status++;	/* to next info */
	}
      }
      putc('\n',stdout);
      if (status)
	puts(status);
      break;
    case ADMIN_PROCESSLIST:
    {
      MYSQL_RES *result;
      MYSQL_ROW row;

      if (mysql_query(mysql, (opt_verbose ? "show full processlist" :
			      "show processlist")) ||
	  !(result = mysql_store_result(mysql)))
      {
720
	my_printf_error(0, "process list failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
721
			mysql_error(mysql));
722
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
      }
      print_header(result);
      while ((row=mysql_fetch_row(result)))
	print_row(result,row,0);
      print_top(result);
      mysql_free_result(result);
      new_line=1;
      break;
    }
    case ADMIN_STATUS:
      status=mysql_stat(mysql);
      if (status)
	puts(status);
      break;
    case ADMIN_KILL:
      {
	uint error=0;
	char *pos;
	if (argc < 2)
	{
743
	  my_printf_error(0, "Too few arguments to 'kill'", error_flags);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
744 745 746 747 748
	  return 1;
	}
	pos=argv[1];
	for (;;)
	{
749 750 751 752 753 754
          /* We don't use mysql_kill(), since it only handles 32-bit IDs. */
          char buff[26], *out; /* "KILL " + max 20 digs + NUL */
          out= strxmov(buff, "KILL ", NullS);
          ullstr(strtoull(pos, NULL, 0), out);

          if (mysql_query(mysql, buff))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
755
	  {
756 757 758
            /* out still points to just the number */
	    my_printf_error(0, "kill failed on %s; error: '%s'", error_flags,
			    out, mysql_error(mysql));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
759 760 761 762 763 764 765 766
	    error=1;
	  }
	  if (!(pos=strchr(pos,',')))
	    break;
	  pos++;
	}
	argc--; argv++;
	if (error)
767
	  return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
768 769 770 771 772
	break;
      }
    case ADMIN_DEBUG:
      if (mysql_dump_debug_info(mysql))
      {
773
	my_printf_error(0, "debug failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
774
			mysql_error(mysql));
775
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
776 777 778 779 780 781 782 783
      }
      break;
    case ADMIN_VARIABLES:
    {
      MYSQL_RES *res;
      MYSQL_ROW row;

      new_line=1;
784
      if (mysql_query(mysql,"show /*!40003 GLOBAL */ variables") ||
bk@work.mysql.com's avatar
bk@work.mysql.com committed
785 786
	  !(res=mysql_store_result(mysql)))
      {
787
	my_printf_error(0, "unable to show variables; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
788
			mysql_error(mysql));
789
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
790 791 792 793 794 795 796 797 798 799 800 801 802
      }
      print_header(res);
      while ((row=mysql_fetch_row(res)))
	print_row(res,row,0);
      print_top(res);
      mysql_free_result(res);
      break;
    }
    case ADMIN_EXTENDED_STATUS:
    {
      MYSQL_RES *res;
      MYSQL_ROW row;
      uint rownr = 0;
803
      void (*func) (MYSQL_RES*, MYSQL_ROW, uint);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
804 805

      new_line = 1;
806
      if (mysql_query(mysql, "show /*!50002 GLOBAL */ status") ||
bk@work.mysql.com's avatar
bk@work.mysql.com committed
807 808
	  !(res = mysql_store_result(mysql)))
      {
809
	my_printf_error(0, "unable to show status; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
810
			mysql_error(mysql));
811
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
812
      }
813 814 815

      DBUG_ASSERT(mysql_num_rows(res) < MAX_MYSQL_VAR);

bk@work.mysql.com's avatar
bk@work.mysql.com committed
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
      if (!opt_vertical)
	print_header(res);
      else
      {
	if (!ex_status_printed)
	{
	  store_values(res);
	  truncate_names();   /* Does some printing also */
	}
	else
	{
	  print_relative_line();
	  print_relative_header();
	  print_relative_line();
	}
      }

      /*      void (*func) (MYSQL_RES*, MYSQL_ROW, uint); */
      if (opt_relative && !opt_vertical)
	func = print_relative_row;
      else if (opt_vertical)
	func = print_relative_row_vert;
      else
	func = print_row;

      while ((row = mysql_fetch_row(res)))
	(*func)(res, row, rownr++);
      if (opt_vertical)
      {
	if (ex_status_printed)
	{
	  putchar('\n');
	  print_relative_line();
	}
      }
      else
	print_top(res);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
853

bk@work.mysql.com's avatar
bk@work.mysql.com committed
854 855 856 857 858 859 860 861
      ex_status_printed = 1; /* From now on the output will be relative */
      mysql_free_result(res);
      break;
    }
    case ADMIN_FLUSH_LOGS:
    {
      if (mysql_refresh(mysql,REFRESH_LOG))
      {
862
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
863
			mysql_error(mysql));
864
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
865 866 867 868 869
      }
      break;
    }
    case ADMIN_FLUSH_HOSTS:
    {
870
      if (mysql_query(mysql,"flush hosts"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
871
      {
872
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
873
			mysql_error(mysql));
874
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
875 876 877 878 879
      }
      break;
    }
    case ADMIN_FLUSH_TABLES:
    {
880
      if (mysql_query(mysql,"flush tables"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
881
      {
882
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
883
			mysql_error(mysql));
884
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
885 886 887 888 889
      }
      break;
    }
    case ADMIN_FLUSH_STATUS:
    {
890
      if (mysql_query(mysql,"flush status"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
891
      {
892
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
893
			mysql_error(mysql));
894
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
895 896 897
      }
      break;
    }
898
    case ADMIN_OLD_PASSWORD:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
899 900
    case ADMIN_PASSWORD:
    {
901 902 903
      char buff[128],crypted_pw[64];
      time_t start_time;
      /* Do initialization the same way as we do in mysqld */
904
      start_time=time((time_t*) 0);
905
      randominit(&rand_st,(ulong) start_time,(ulong) start_time/2);
906

907
      if (argc < 2)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
908
      {
909
	my_printf_error(0, "Too few arguments to change password", error_flags);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
910 911 912
	return 1;
      }
      if (argv[1][0])
913
      {
914
        char *pw= argv[1];
monty@mysql.com's avatar
monty@mysql.com committed
915 916
        bool old= (find_type(argv[0], &command_typelib, 2) ==
                   ADMIN_OLD_PASSWORD);
917
#ifdef __WIN__
918
        uint pw_len= (uint) strlen(pw);
919 920 921 922
        if (pw_len > 1 && pw[0] == '\'' && pw[pw_len-1] == '\'')
          printf("Warning: single quotes were not trimmed from the password by"
                 " your command\nline client, as you might have expected.\n");
#endif
923 924 925 926
        /*
           If we don't already know to use an old-style password, see what
           the server is using
        */
monty@mysql.com's avatar
monty@mysql.com committed
927 928 929 930
        if (!old)
        {
          if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'"))
          {
931
            my_printf_error(0, "Could not determine old_passwords setting from server; error: '%s'",
932
                	    error_flags, mysql_error(mysql));
933
            return -1;
monty@mysql.com's avatar
monty@mysql.com committed
934 935 936
          }
          else
          {
937
            MYSQL_RES *res= mysql_store_result(mysql);
monty@mysql.com's avatar
monty@mysql.com committed
938 939 940 941 942
            if (!res)
            {
              my_printf_error(0,
                              "Could not get old_passwords setting from "
                              "server; error: '%s'",
943
        		      error_flags, mysql_error(mysql));
944 945
              return -1;
            }
monty@mysql.com's avatar
monty@mysql.com committed
946
            if (!mysql_num_rows(res))
947
              old= 1;
monty@mysql.com's avatar
monty@mysql.com committed
948 949
            else
            {
950 951 952 953 954 955 956
              MYSQL_ROW row= mysql_fetch_row(res);
              old= !strncmp(row[1], "ON", 2);
            }
            mysql_free_result(res);
          }
        }
        if (old)
957
          make_scrambled_password_323(crypted_pw, pw);
958
        else
959
          make_scrambled_password(crypted_pw, pw);
960
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
961 962 963 964 965 966 967
      else
	crypted_pw[0]=0;			/* No password */
      sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);

      if (mysql_query(mysql,"set sql_log_off=1"))
      {
	my_printf_error(0, "Can't turn off logging; error: '%s'",
968
			error_flags, mysql_error(mysql));
969
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
970 971 972
      }
      if (mysql_query(mysql,buff))
      {
973 974 975
	if (mysql_errno(mysql)!=1290)
	{
	  my_printf_error(0,"unable to change password; error: '%s'",
976
			  error_flags, mysql_error(mysql));
977 978 979 980
	  return -1;
	}
	else
	{
981 982 983 984 985 986 987 988 989
	  /*
	    We don't try to execute 'update mysql.user set..'
	    because we can't perfectly find out the host
	   */
	  my_printf_error(0,"\n"
			  "You cannot use 'password' command as mysqld runs\n"
			  " with grant tables disabled (was started with"
			  " --skip-grant-tables).\n"
			  "Use: \"mysqladmin flush-privileges password '*'\""
990
			  " instead", error_flags);
991
	  return -1;
992
	}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
993 994 995 996 997 998
      }
      argc--; argv++;
      break;
    }

    case ADMIN_START_SLAVE:
999
      if (mysql_query(mysql, "START SLAVE"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1000
      {
1001
	my_printf_error(0, "Error starting slave: %s", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1002
			mysql_error(mysql));
1003
	return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1004 1005 1006 1007 1008
      }
      else
	puts("Slave started");
      break;
    case ADMIN_STOP_SLAVE:
1009
      if (mysql_query(mysql, "STOP SLAVE"))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1010
      {
1011
	  my_printf_error(0, "Error stopping slave: %s", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1012
			  mysql_error(mysql));
1013
	  return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1014 1015 1016 1017
      }
      else
	puts("Slave stopped");
      break;
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1018

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1019 1020 1021
    case ADMIN_PING:
      mysql->reconnect=0;	/* We want to know of reconnects */
      if (!mysql_ping(mysql))
monty@donna.mysql.com's avatar
monty@donna.mysql.com committed
1022 1023 1024 1025
      {
	if (option_silent < 2)
	  puts("mysqld is alive");
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
      else
      {
	if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
	{
	  mysql->reconnect=1;
	  if (!mysql_ping(mysql))
	    puts("connection was down, but mysqld is now alive");
	}
	else
	{
	  my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
1037
			  error_flags, mysql_error(mysql));
1038
	  return -1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1039 1040 1041 1042 1043
	}
      }
      mysql->reconnect=1;	/* Automatic reconnect is default */
      break;
    default:
1044
      my_printf_error(0, "Unknown command: '%-.60s'", error_flags, argv[0]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1045 1046 1047 1048 1049 1050
      return 1;
    }
  }
  return 0;
}

monty@mysql.com's avatar
monty@mysql.com committed
1051
#include <help_start.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1052 1053 1054 1055 1056

static void print_version(void)
{
  printf("%s  Ver %s Distrib %s, for %s on %s\n",my_progname,ADMIN_VERSION,
	 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
monty@mysql.com's avatar
monty@mysql.com committed
1057
  NETWARE_SET_SCREEN_MODE(1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1058 1059 1060 1061 1062 1063
}


static void usage(void)
{
  print_version();
1064
  puts("Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1065
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
1066
  puts("Administration program for the mysqld daemon.");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1067
  printf("Usage: %s [OPTIONS] command command....\n", my_progname);
1068 1069
  my_print_help(my_long_options);
  my_print_variables(my_long_options);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1070 1071 1072
  print_defaults("my",load_default_groups);
  puts("\nWhere command is a one or more of: (Commands may be shortened)\n\
  create databasename	Create a new database\n\
1073
  debug			Instruct server to write debug information to log\n\
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084
  drop databasename	Delete a database and all its tables\n\
  extended-status       Gives an extended status message from the server\n\
  flush-hosts           Flush all cached hosts\n\
  flush-logs            Flush all logs\n\
  flush-status		Clear status variables\n\
  flush-tables          Flush all tables\n\
  flush-threads         Flush the thread cache\n\
  flush-privileges      Reload grant tables (same as reload)\n\
  kill id,id,...	Kill mysql threads");
#if MYSQL_VERSION_ID >= 32200
  puts("\
1085 1086
  password new-password Change old password to new-password, MySQL 4.1 hashing.\n\
  old-password new-password Change old password to new-password in old format.\n");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1087 1088 1089 1090 1091 1092 1093 1094
#endif
  puts("\
  ping			Check if mysqld is alive\n\
  processlist		Show list of active threads in server\n\
  reload		Reload grant tables\n\
  refresh		Flush all tables and close and open logfiles\n\
  shutdown		Take server down\n\
  status		Gives a short status message from the server\n\
1095 1096
  start-slave		Start slave\n\
  stop-slave		Stop slave\n\
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1097 1098 1099 1100
  variables             Prints variables available\n\
  version		Get version info from server");
}

monty@mysql.com's avatar
monty@mysql.com committed
1101 1102
#include <help_end.h>

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1103 1104 1105
static int drop_db(MYSQL *mysql, const char *db)
{
  char name_buff[FN_REFLEN+20], buf[10];
1106 1107
  char *input;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1108 1109 1110 1111
  if (!option_force)
  {
    puts("Dropping the database is potentially a very bad thing to do.");
    puts("Any data stored in the database will be destroyed.\n");
1112 1113
    printf("Do you really want to drop the '%s' database [y/N] ",db);
    fflush(stdout);
1114 1115
    input= fgets(buf, sizeof(buf)-1, stdin);
    if (!input || ((*input != 'y') && (*input != 'Y')))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1116 1117 1118 1119 1120
    {
      puts("\nOK, aborting database drop!");
      return -1;
    }
  }
1121
  sprintf(name_buff,"drop database `%.*s`",FN_REFLEN,db);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1122 1123
  if (mysql_query(mysql,name_buff))
  {
1124
    my_printf_error(0, "DROP DATABASE %s failed;\nerror: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
		    db,mysql_error(mysql));
    return 1;
  }
  printf("Database \"%s\" dropped\n",db);
  return 0;
}


static void nice_time(ulong sec,char *buff)
{
  ulong tmp;

  if (sec >= 3600L*24)
  {
    tmp=sec/(3600L*24);
    sec-=3600L*24*tmp;
1141
    buff=int10_to_str(tmp, buff, 10);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1142 1143 1144 1145 1146 1147
    buff=strmov(buff,tmp > 1 ? " days " : " day ");
  }
  if (sec >= 3600L)
  {
    tmp=sec/3600L;
    sec-=3600L*tmp;
1148
    buff=int10_to_str(tmp, buff, 10);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1149 1150 1151 1152 1153 1154
    buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
  }
  if (sec >= 60)
  {
    tmp=sec/60;
    sec-=60*tmp;
1155
    buff=int10_to_str(tmp, buff, 10);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1156 1157
    buff=strmov(buff," min ");
  }
1158
  strmov(int10_to_str(sec, buff, 10)," sec");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
}


static void print_header(MYSQL_RES *result)
{
  MYSQL_FIELD *field;

  print_top(result);
  mysql_field_seek(result,0);
  putchar('|');
  while ((field = mysql_fetch_field(result)))
  {
1171
    printf(" %-*s|",(int) field->max_length+1,field->name);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
  }
  putchar('\n');
  print_top(result);
}


static void print_top(MYSQL_RES *result)
{
  uint i,length;
  MYSQL_FIELD *field;

  putchar('+');
  mysql_field_seek(result,0);
  while((field = mysql_fetch_field(result)))
  {
1187
    if ((length=(uint) strlen(field->name)) > field->max_length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
      field->max_length=length;
    else
      length=field->max_length;
    for (i=length+2 ; i--> 0 ; )
      putchar('-');
    putchar('+');
  }
  putchar('\n');
}


/* 3.rd argument, uint row, is not in use. Don't remove! */
static void print_row(MYSQL_RES *result, MYSQL_ROW cur,
		      uint row __attribute__((unused)))
{
  uint i,length;
  MYSQL_FIELD *field;

  putchar('|');
  mysql_field_seek(result,0);
  for (i=0 ; i < mysql_num_fields(result); i++)
  {
    field = mysql_fetch_field(result);
    length=field->max_length;
    printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
  }
  putchar('\n');
}


static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row)
{
  ulonglong tmp;
  char buff[22];
  MYSQL_FIELD *field;

  mysql_field_seek(result, 0);
  field = mysql_fetch_field(result);
1226
  printf("| %-*s|", (int) field->max_length + 1, cur[0]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1227 1228

  field = mysql_fetch_field(result);
1229
  tmp = cur[1] ? strtoull(cur[1], NULL, 10) : (ulonglong) 0;
1230
  printf(" %-*s|\n", (int) field->max_length + 1,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
	 llstr((tmp - last_values[row]), buff));
  last_values[row] = tmp;
}


static void print_relative_row_vert(MYSQL_RES *result __attribute__((unused)),
				    MYSQL_ROW cur,
				    uint row __attribute__((unused)))
{
  uint length;
  ulonglong tmp;
  char buff[22];
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1243

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1244 1245 1246
  if (!row)
    putchar('|');

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1247
  tmp = cur[1] ? strtoull(cur[1], NULL, 10) : (ulonglong) 0;
1248
  printf(" %-*s|", ex_val_max_len[row] + 1,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1249 1250 1251
	 llstr((tmp - last_values[row]), buff));

  /* Find the minimum row length needed to output the relative value */
1252
  if ((length=(uint) strlen(buff) > ex_val_max_len[row]) && ex_status_printed)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
    ex_val_max_len[row] = length;
  last_values[row] = tmp;
}


static void store_values(MYSQL_RES *result)
{
  uint i;
  MYSQL_ROW row;
  MYSQL_FIELD *field;

  field = mysql_fetch_field(result);
  max_var_length = field->max_length;
  field = mysql_fetch_field(result);
  max_val_length = field->max_length;

  for (i = 0; (row = mysql_fetch_row(result)); i++)
  {
    strmov(ex_var_names[i], row[0]);
    last_values[i]=strtoull(row[1],NULL,10);
    ex_val_max_len[i]=2;		/* Default print width for values */
  }
  ex_var_count = i;
  return;
}


static void print_relative_header()
{
  uint i;

  putchar('|');
  for (i = 0; i < ex_var_count; i++)
    printf(" %-*s|", ex_val_max_len[i] + 1, truncated_var_names[i]);
  putchar('\n');
}


static void print_relative_line()
{
  uint i;

  putchar('+');
  for (i = 0; i < ex_var_count; i++)
  {
    uint j;
    for (j = 0; j < ex_val_max_len[i] + 2; j++)
      putchar('-');
    putchar('+');
  }
  putchar('\n');
}


static void truncate_names()
{
  uint i;
  char *ptr,top_line[MAX_TRUNC_LENGTH+4+NAME_LEN+22+1],buff[22];

  ptr=top_line;
  *ptr++='+';
  ptr=strfill(ptr,max_var_length+2,'-');
  *ptr++='+';
  ptr=strfill(ptr,MAX_TRUNC_LENGTH+2,'-');
  *ptr++='+';
  ptr=strfill(ptr,max_val_length+2,'-');
  *ptr++='+';
  *ptr=0;
  puts(top_line);
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1322

bk@work.mysql.com's avatar
bk@work.mysql.com committed
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
  for (i = 0 ; i < ex_var_count; i++)
  {
    uint sfx=1,j;
    printf("| %-*s|", max_var_length + 1, ex_var_names[i]);
    ptr = ex_var_names[i];
    /* Make sure no two same truncated names will become */
    for (j = 0; j < i; j++)
      if (*truncated_var_names[j] == *ptr)
	sfx++;

    truncated_var_names[i][0]= *ptr;		/* Copy first var char */
    int10_to_str(sfx, truncated_var_names[i]+1,10);
    printf(" %-*s|", MAX_TRUNC_LENGTH + 1, truncated_var_names[i]);
    printf(" %-*s|\n", max_val_length + 1, llstr(last_values[i],buff));
  }
  puts(top_line);
  return;
}


static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
{
  MYSQL_RES* result;

  if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'"))
  {
1349
    my_printf_error(0, "query failed; error: '%s'", error_flags,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1350 1351 1352 1353 1354
		    mysql_error(mysql));
  }
  result = mysql_store_result(mysql);
  if (result)
  {
1355 1356 1357
    MYSQL_ROW row=mysql_fetch_row(result);
    if (row)
      strmov(pidfile, row[1]);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1358
    mysql_free_result(result);
1359
    return row == 0;				/* Error if row = 0 */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1360 1361 1362 1363
  }
  return 1;					/* Error */
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1364 1365 1366
/*
  Return 1 if pid file didn't disappear or change
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1367

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1368 1369
static my_bool wait_pidfile(char *pidfile, time_t last_modified,
			    struct stat *pidfile_status)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1370 1371
{
  char buff[FN_REFLEN];
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1372 1373 1374
  int error= 1;
  uint count= 0;
  DBUG_ENTER("wait_pidfile");
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1375

1376
  system_filename(buff, pidfile);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1377
  do
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1378
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
    int fd;
    if ((fd= my_open(buff, O_RDONLY, MYF(0))) < 0)
    {
      error= 0;
      break;
    }
    (void) my_close(fd,MYF(0));
    if (last_modified && !stat(pidfile, pidfile_status))
    {
      if (last_modified != pidfile_status->st_mtime)
      {
	/* File changed;  Let's assume that mysqld did restart */
	if (opt_verbose)
	  printf("pid file '%s' changed while waiting for it to disappear!\nmysqld did probably restart\n",
		 buff);
	error= 0;
	break;
      }
    }
    if (count++ == opt_shutdown_timeout)
      break;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1400
    sleep(1);
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1401 1402 1403
  } while (!interrupted);

  if (error)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1404
  {
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1405
    DBUG_PRINT("warning",("Pid file didn't disappear"));
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1406 1407 1408 1409
    fprintf(stderr,
	    "Warning;  Aborted waiting on pid file: '%s' after %d seconds\n",
	    buff, count-1);
  }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1410
  DBUG_RETURN(error);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1411
}