1 /*
2    Copyright (c) 2000, 2014, Oracle and/or its affiliates.
3    Copyright (c) 2010, 2017, MariaDB
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; version 2 of the License.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA */
17 
18 /* maintaince of mysql databases */
19 
20 #include "client_priv.h"
21 #include <signal.h>
22 #include <my_pthread.h>				/* because of signal()	*/
23 #include <sys/stat.h>
24 #include <mysql.h>
25 #include <mysql_version.h>
26 #include <welcome_copyright_notice.h>
27 #include <my_rnd.h>
28 #include <password.h>
29 #include <my_sys.h>
30 
31 #define ADMIN_VERSION "9.1"
32 #define MAX_MYSQL_VAR 512
33 #define SHUTDOWN_DEF_TIMEOUT 3600		/* Wait for shutdown */
34 #define MAX_TRUNC_LENGTH 3
35 
36 char *host= NULL, *user= 0, *opt_password= 0,
37      *default_charset= (char*) MYSQL_AUTODETECT_CHARSET_NAME;
38 char truncated_var_names[MAX_MYSQL_VAR+100][MAX_TRUNC_LENGTH];
39 char ex_var_names[MAX_MYSQL_VAR+100][FN_REFLEN];
40 ulonglong last_values[MAX_MYSQL_VAR+100];
41 static int interval=0;
42 static my_bool option_force=0,interrupted=0,new_line=0,
43                opt_compress= 0, opt_local= 0, opt_relative= 0, opt_verbose= 0,
44                opt_vertical= 0, tty_password= 0, opt_nobeep;
45 static my_bool debug_info_flag= 0, debug_check_flag= 0;
46 static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations;
47 static uint opt_count_iterations= 0, my_end_arg;
48 static ulong opt_connect_timeout, opt_shutdown_timeout;
49 static char * unix_port=0;
50 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
51 static bool sql_log_bin_off= false;
52 
53 #ifdef HAVE_SMEM
54 static char *shared_memory_base_name=0;
55 #endif
56 static uint opt_protocol=0;
57 static myf error_flags; /* flags to pass to my_printf_error, like ME_BELL */
58 
59 /*
60   When using extended-status relatively, ex_val_max_len is the estimated
61   maximum length for any relative value printed by extended-status. The
62   idea is to try to keep the length of output as short as possible.
63 */
64 
65 static uint ex_val_max_len[MAX_MYSQL_VAR];
66 static my_bool ex_status_printed = 0; /* First output is not relative. */
67 static uint ex_var_count, max_var_length, max_val_length;
68 
69 #include <sslopt-vars.h>
70 
71 static void print_version(void);
72 static void usage(void);
73 extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
74                                   char *argument);
75 static my_bool sql_connect(MYSQL *mysql, uint wait);
76 static int execute_commands(MYSQL *mysql,int argc, char **argv);
77 static char **mask_password(int argc, char ***argv);
78 static int drop_db(MYSQL *mysql,const char *db);
79 extern "C" sig_handler endprog(int signal_number);
80 static void nice_time(ulong sec,char *buff);
81 static void print_header(MYSQL_RES *result);
82 static void print_top(MYSQL_RES *result);
83 static void print_row(MYSQL_RES *result,MYSQL_ROW cur, uint row);
84 static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row);
85 static void print_relative_row_vert(MYSQL_RES *result, MYSQL_ROW cur, uint row);
86 static void print_relative_header();
87 static void print_relative_line();
88 static void truncate_names();
89 static my_bool get_pidfile(MYSQL *mysql, char *pidfile);
90 static my_bool wait_pidfile(char *pidfile, time_t last_modified,
91 			    struct stat *pidfile_status);
92 static void store_values(MYSQL_RES *result);
93 
94 /*
95   The order of commands must be the same as command_names,
96   except ADMIN_ERROR
97 */
98 enum commands {
99   ADMIN_ERROR,
100   ADMIN_CREATE,           ADMIN_DROP,            ADMIN_SHUTDOWN,
101   ADMIN_RELOAD,           ADMIN_REFRESH,         ADMIN_VER,
102   ADMIN_PROCESSLIST,      ADMIN_STATUS,          ADMIN_KILL,
103   ADMIN_DEBUG,            ADMIN_VARIABLES,       ADMIN_FLUSH_LOGS,
104   ADMIN_FLUSH_HOSTS,      ADMIN_FLUSH_TABLES,    ADMIN_PASSWORD,
105   ADMIN_PING,             ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
106   ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE,     ADMIN_STOP_SLAVE,
107   ADMIN_START_ALL_SLAVES, ADMIN_STOP_ALL_SLAVES,
108   ADMIN_FLUSH_THREADS,    ADMIN_OLD_PASSWORD,    ADMIN_FLUSH_BINARY_LOG,
109   ADMIN_FLUSH_ENGINE_LOG, ADMIN_FLUSH_ERROR_LOG, ADMIN_FLUSH_GENERAL_LOG,
110   ADMIN_FLUSH_RELAY_LOG,  ADMIN_FLUSH_SLOW_LOG,
111   ADMIN_FLUSH_TABLE_STATISTICS, ADMIN_FLUSH_INDEX_STATISTICS,
112   ADMIN_FLUSH_USER_STATISTICS, ADMIN_FLUSH_CLIENT_STATISTICS,
113   ADMIN_FLUSH_USER_RESOURCES,
114   ADMIN_FLUSH_ALL_STATUS, ADMIN_FLUSH_ALL_STATISTICS
115 };
116 static const char *command_names[]= {
117   "create",               "drop",                "shutdown",
118   "reload",               "refresh",             "version",
119   "processlist",          "status",              "kill",
120   "debug",                "variables",           "flush-logs",
121   "flush-hosts",          "flush-tables",        "password",
122   "ping",                 "extended-status",     "flush-status",
123   "flush-privileges",     "start-slave",         "stop-slave",
124   "start-all-slaves", "stop-all-slaves",
125   "flush-threads", "old-password", "flush-binary-log", "flush-engine-log",
126   "flush-error-log", "flush-general-log", "flush-relay-log", "flush-slow-log",
127   "flush-table-statistics", "flush-index-statistics",
128   "flush-user-statistics", "flush-client-statistics", "flush-user-resources",
129   "flush-all-status", "flush-all-statistics",
130   NullS
131 };
132 
133 static TYPELIB command_typelib=
134 { array_elements(command_names)-1,"commands", command_names, NULL};
135 
136 static struct my_option my_long_options[] =
137 {
138   {"count", 'c',
139    "Number of iterations to make. This works with -i (--sleep) only.",
140    &nr_iterations, &nr_iterations, 0, GET_UINT,
141    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
142 #ifndef DBUG_OFF
143   {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
144    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
145 #endif
146   {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
147    &debug_check_flag, &debug_check_flag, 0,
148    GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
149   {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
150    &debug_info_flag, &debug_info_flag,
151    0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
152   {"force", 'f',
153    "Don't ask for confirmation on drop database; with multiple commands, "
154    "continue even if an error occurs.",
155    &option_force, &option_force, 0, GET_BOOL, NO_ARG, 0, 0,
156    0, 0, 0, 0},
157   {"compress", 'C', "Use compression in server/client protocol.",
158    &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
159    0, 0, 0},
160   {"character-sets-dir", OPT_CHARSETS_DIR,
161    "Directory for character set files.", &charsets_dir,
162    &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
163   {"default-character-set", OPT_DEFAULT_CHARSET,
164    "Set the default character set.", &default_charset,
165    &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
166   {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
167    NO_ARG, 0, 0, 0, 0, 0, 0},
168   {"host", 'h', "Connect to host.", &host, &host, 0, GET_STR,
169    REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
170   {"local", 'l', "Local command, don't write to binlog.",
171    &opt_local, &opt_local, 0, GET_BOOL, NO_ARG, 0, 0, 0,
172    0, 0, 0},
173   {"no-beep", 'b', "Turn off beep on error.", &opt_nobeep,
174    &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
175   {"password", 'p',
176    "Password to use when connecting to server. If password is not given it's asked from the tty.",
177    0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
178 #ifdef __WIN__
179   {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
180    NO_ARG, 0, 0, 0, 0, 0, 0},
181 #endif
182   {"port", 'P', "Port number to use for connection or 0 for default to, in "
183    "order of preference, my.cnf, $MYSQL_TCP_PORT, "
184 #if MYSQL_PORT_DEFAULT == 0
185    "/etc/services, "
186 #endif
187    "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
188    &tcp_port, &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
189   {"protocol", OPT_MYSQL_PROTOCOL, "The protocol to use for connection (tcp, socket, pipe, memory).",
190     0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
191   {"relative", 'r',
192    "Show difference between current and previous values when used with -i. "
193    "Currently only works with extended-status.",
194    &opt_relative, &opt_relative, 0, GET_BOOL, NO_ARG, 0, 0, 0,
195   0, 0, 0},
196 #ifdef HAVE_SMEM
197   {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
198    "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name,
199    0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
200 #endif
201   {"silent", 's', "Silently exit if one can't connect to server.",
202    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
203   {"socket", 'S', "The socket file to use for connection.",
204    &unix_port, &unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
205    0, 0, 0},
206   {"sleep", 'i', "Execute commands repeatedly with a sleep between.",
207    &interval, &interval, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0,
208    0, 0},
209 #include <sslopt-longopts.h>
210 #ifndef DONT_ALLOW_USER_CHANGE
211   {"user", 'u', "User for login if not current user.", &user,
212    &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
213 #endif
214   {"verbose", 'v', "Write more information.", &opt_verbose,
215    &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
216   {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
217    NO_ARG, 0, 0, 0, 0, 0, 0},
218   {"vertical", 'E',
219    "Print output vertically. Is similar to --relative, but prints output vertically.",
220    &opt_vertical, &opt_vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0,
221    0, 0, 0},
222   {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_UINT,
223    OPT_ARG, 0, 0, 0, 0, 0, 0},
224   {"connect_timeout", OPT_CONNECT_TIMEOUT, "", &opt_connect_timeout,
225    &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 3600*12, 0,
226    3600*12, 0, 1, 0},
227   {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", &opt_shutdown_timeout,
228    &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG,
229    SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0},
230   {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
231     &opt_plugin_dir, &opt_plugin_dir, 0,
232    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
233   {"default_auth", OPT_DEFAULT_AUTH,
234    "Default authentication client-side plugin to use.",
235    &opt_default_auth, &opt_default_auth, 0,
236    GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
237   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
238 };
239 
240 
241 static const char *load_default_groups[]=
242 { "mysqladmin", "client", "client-server", "client-mariadb", 0 };
243 
244 my_bool
get_one_option(int optid,const struct my_option * opt,char * argument)245 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
246 	       char *argument)
247 {
248   switch(optid) {
249   case 'c':
250     opt_count_iterations= 1;
251     break;
252   case 'p':
253     if (argument == disabled_my_option)
254       argument= (char*) "";			// Don't require password
255     if (argument)
256     {
257       char *start=argument;
258       my_free(opt_password);
259       opt_password=my_strdup(argument,MYF(MY_FAE));
260       while (*argument) *argument++= 'x';		/* Destroy argument */
261       if (*start)
262 	start[1]=0;				/* Cut length of argument */
263       tty_password= 0;
264     }
265     else
266       tty_password=1;
267     break;
268   case 's':
269     option_silent++;
270     break;
271   case 'W':
272 #ifdef __WIN__
273     opt_protocol = MYSQL_PROTOCOL_PIPE;
274 #endif
275     break;
276   case '#':
277     DBUG_PUSH(argument ? argument : "d:t:o,/tmp/mysqladmin.trace");
278     break;
279 #include <sslopt-case.h>
280   case 'V':
281     print_version();
282     exit(0);
283     break;
284   case 'w':
285     if (argument)
286     {
287       if ((option_wait=atoi(argument)) <= 0)
288 	option_wait=1;
289     }
290     else
291       option_wait= ~(uint)0;
292     break;
293   case '?':
294   case 'I':					/* Info */
295     usage();
296     exit(0);
297   case OPT_CHARSETS_DIR:
298 #if MYSQL_VERSION_ID > 32300
299     charsets_dir = argument;
300 #endif
301     break;
302   case OPT_MYSQL_PROTOCOL:
303     if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib,
304                                               opt->name)) <= 0)
305     {
306       sf_leaking_memory= 1; /* no memory leak reports here */
307       exit(1);
308     }
309     break;
310   }
311   return 0;
312 }
313 
314 
main(int argc,char * argv[])315 int main(int argc,char *argv[])
316 {
317   int error= 0, temp_argc;
318   MYSQL mysql;
319   char **commands, **save_argv, **temp_argv;
320 
321   MY_INIT(argv[0]);
322   sf_leaking_memory=1; /* don't report memory leaks on early exits */
323   load_defaults_or_exit("my", load_default_groups, &argc, &argv);
324   save_argv = argv;				/* Save for free_defaults */
325 
326   if ((error=handle_options(&argc, &argv, my_long_options, get_one_option)))
327     goto err2;
328   temp_argv= mask_password(argc, &argv);
329   temp_argc= argc;
330 
331   if (debug_info_flag)
332     my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
333   if (debug_check_flag)
334     my_end_arg= MY_CHECK_ERROR;
335 
336   if (argc == 0)
337   {
338     usage();
339     exit(1);
340   }
341   commands = temp_argv;
342   if (tty_password)
343     opt_password = get_tty_password(NullS);
344 
345   (void) signal(SIGINT,endprog);			/* Here if abort */
346   (void) signal(SIGTERM,endprog);		/* Here if abort */
347 
348   sf_leaking_memory=0; /* from now on we cleanup properly */
349 
350   mysql_init(&mysql);
351   if (opt_compress)
352     mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
353   if (opt_connect_timeout)
354   {
355     uint tmp=opt_connect_timeout;
356     mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT, (char*) &tmp);
357   }
358 #ifdef HAVE_OPENSSL
359   if (opt_use_ssl)
360   {
361     mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
362 		  opt_ssl_capath, opt_ssl_cipher);
363     mysql_options(&mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
364     mysql_options(&mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
365   }
366   mysql_options(&mysql,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
367                 (char*)&opt_ssl_verify_server_cert);
368 #endif
369   if (opt_protocol)
370     mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
371 #ifdef HAVE_SMEM
372   if (shared_memory_base_name)
373     mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
374 #endif
375   if (!strcmp(default_charset,MYSQL_AUTODETECT_CHARSET_NAME))
376     default_charset= (char *)my_default_csname();
377   mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
378   error_flags= (myf)(opt_nobeep ? 0 : ME_BELL);
379 
380   if (opt_plugin_dir && *opt_plugin_dir)
381     mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
382 
383   if (opt_default_auth && *opt_default_auth)
384     mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
385 
386   mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
387   mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
388                  "program_name", "mysqladmin");
389   if (sql_connect(&mysql, option_wait))
390   {
391     /*
392       We couldn't get an initial connection and will definitely exit.
393       The following just determines the exit-code we'll give.
394     */
395 
396     unsigned int err= mysql_errno(&mysql);
397     if (err >= CR_MIN_ERROR && err <= CR_MAX_ERROR)
398       error= 1;
399     else
400     {
401       /* Return 0 if all commands are PING */
402       for (; argc > 0; argv++, argc--)
403       {
404         if (find_type(argv[0], &command_typelib, FIND_TYPE_BASIC) !=
405             ADMIN_PING)
406         {
407           error= 1;
408           break;
409         }
410       }
411     }
412   }
413   else
414   {
415     /*
416       --count=0 aborts right here. Otherwise iff --sleep=t ("interval")
417       is given a t!=0, we get an endless loop, or n iterations if --count=n
418       was given an n!=0. If --sleep wasn't given, we get one iteration.
419 
420       To wit, --wait loops the connection-attempts, while --sleep loops
421       the command execution (endlessly if no --count is given).
422     */
423 
424     while (!interrupted && (!opt_count_iterations || nr_iterations))
425     {
426       new_line = 0;
427 
428       if ((error= execute_commands(&mysql,argc,commands)))
429       {
430         /*
431           Unknown/malformed command always aborts and can't be --forced.
432           If the user got confused about the syntax, proceeding would be
433           dangerous ...
434         */
435 	if (error > 0)
436 	  break;
437 
438         /*
439           Command was well-formed, but failed on the server. Might succeed
440           on retry (if conditions on server change etc.), but needs --force
441           to retry.
442         */
443         if (!option_force)
444           break;
445       }                                         /* if((error= ... */
446 
447       if (interval)                             /* --sleep=interval given */
448       {
449         if (opt_count_iterations && --nr_iterations == 0)
450           break;
451 
452         /*
453           If connection was dropped (unintentionally, or due to SHUTDOWN),
454           re-establish it if --wait ("retry-connect") was given and user
455           didn't signal for us to die. Otherwise, signal failure.
456         */
457 
458 	if (mysql.net.pvio == 0)
459 	{
460 	  if (option_wait && !interrupted)
461 	  {
462 	    sleep(1);
463 	    sql_connect(&mysql, option_wait);
464 	    /*
465 	      continue normally and decrease counters so that
466 	      "mysqladmin --count=1 --wait=1 shutdown"
467 	      cannot loop endlessly.
468 	    */
469 	  }
470 	  else
471 	  {
472 	    /*
473 	      connexion broke, and we have no order to re-establish it. fail.
474 	    */
475 	    if (!option_force)
476 	      error= 1;
477 	    break;
478 	  }
479 	}                                       /* lost connection */
480 
481 	sleep(interval);
482 	if (new_line)
483 	  puts("");
484       }
485       else
486         break;                                  /* no --sleep, done looping */
487     }                                           /* command-loop */
488   }                                             /* got connection */
489 
490   mysql_close(&mysql);
491   temp_argc--;
492   while(temp_argc >= 0)
493   {
494     my_free(temp_argv[temp_argc]);
495     temp_argc--;
496   }
497   my_free(temp_argv);
498 err2:
499   mysql_library_end();
500   my_free(opt_password);
501   my_free(user);
502 #ifdef HAVE_SMEM
503   my_free(shared_memory_base_name);
504 #endif
505   free_defaults(save_argv);
506   my_end(my_end_arg);
507   return error;
508 }
509 
510 
endprog(int signal_number)511 sig_handler endprog(int signal_number __attribute__((unused)))
512 {
513   interrupted=1;
514 }
515 
516 /**
517    @brief connect to server, optionally waiting for same to come up
518 
519    @param  mysql     connection struct
520    @param  wait      wait for server to come up?
521                      (0: no, ~0: forever, n: cycles)
522 
523    @return Operation result
524    @retval 0         success
525    @retval 1         failure
526 */
527 
sql_connect(MYSQL * mysql,uint wait)528 static my_bool sql_connect(MYSQL *mysql, uint wait)
529 {
530   my_bool info=0;
531 
532   for (;;)
533   {
534     if (mysql_real_connect(mysql,host,user,opt_password,NullS,tcp_port,
535 			   unix_port, CLIENT_REMEMBER_OPTIONS))
536     {
537       my_bool reconnect= 1;
538       mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
539       if (info)
540       {
541 	fputs("\n",stderr);
542 	(void) fflush(stderr);
543       }
544       return 0;
545     }
546 
547     if (!wait)                                  // was or reached 0, fail
548     {
549       if (!option_silent)                       // print diagnostics
550       {
551 	if (!host)
552 	  host= (char*) LOCAL_HOST;
553 	my_printf_error(0,"connect to server at '%s' failed\nerror: '%s'",
554 			error_flags, host, mysql_error(mysql));
555 	if (mysql_errno(mysql) == CR_CONNECTION_ERROR)
556 	{
557 	  fprintf(stderr,
558 		  "Check that mysqld is running and that the socket: '%s' exists!\n",
559 		  unix_port ? unix_port : mysql_unix_port);
560 	}
561 	else if (mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
562 		 mysql_errno(mysql) == CR_UNKNOWN_HOST)
563 	{
564 	  fprintf(stderr,"Check that mysqld is running on %s",host);
565 	  fprintf(stderr," and that the port is %d.\n",
566 		  tcp_port ? tcp_port: mysql_port);
567 	  fprintf(stderr,"You can check this by doing 'telnet %s %d'\n",
568 		  host, tcp_port ? tcp_port: mysql_port);
569 	}
570       }
571       return 1;
572     }
573 
574     if (wait != (uint) ~0)
575       wait--;				/* count down, one less retry */
576 
577     if ((mysql_errno(mysql) != CR_CONN_HOST_ERROR) &&
578 	(mysql_errno(mysql) != CR_CONNECTION_ERROR))
579     {
580       /*
581         Error is worse than "server doesn't answer (yet?)";
582         fail even if we still have "wait-coins" unless --force
583         was also given.
584       */
585       fprintf(stderr,"Got error: %s\n", mysql_error(mysql));
586       if (!option_force)
587 	return 1;
588     }
589     else if (!option_silent)
590     {
591       if (!info)
592       {
593 	info=1;
594 	fputs("Waiting for MySQL server to answer",stderr);
595 	(void) fflush(stderr);
596       }
597       else
598       {
599 	putc('.',stderr);
600 	(void) fflush(stderr);
601       }
602     }
603     sleep(5);
604   }
605 }
606 
607 
maybe_disable_binlog(MYSQL * mysql)608 static int maybe_disable_binlog(MYSQL *mysql)
609 {
610   if (opt_local && !sql_log_bin_off)
611   {
612     if (mysql_query(mysql,  "set local sql_log_bin=0"))
613     {
614       my_printf_error(0, "SET LOCAL SQL_LOG_BIN=0 failed; error: '%-.200s'",
615                       error_flags, mysql_error(mysql));
616       return -1;
617     }
618   }
619   sql_log_bin_off= true;
620   return 0;
621 }
622 
623 
flush(MYSQL * mysql,const char * what)624 int flush(MYSQL *mysql, const char *what)
625 {
626   char buf[FN_REFLEN];
627   my_snprintf(buf, sizeof(buf), "flush %s%s",
628               (opt_local && !sql_log_bin_off ? "local " : ""), what);
629   return mysql_query(mysql, buf);
630 }
631 
632 
633 /**
634    @brief Execute all commands
635 
636    @details We try to execute all commands we were given, in the order
637             given, but return with non-zero as soon as we encounter trouble.
638             By that token, individual commands can be considered a conjunction
639             with boolean short-cut.
640 
641    @return success?
642    @retval 0       Yes!  ALL commands worked!
643    @retval 1       No, one failed and will never work (malformed): fatal error!
644    @retval -1      No, one failed on the server, may work next time!
645 */
646 
execute_commands(MYSQL * mysql,int argc,char ** argv)647 static int execute_commands(MYSQL *mysql,int argc, char **argv)
648 {
649   int ret = 0;
650   const char *status;
651   /*
652     MySQL documentation relies on the fact that mysqladmin will
653     execute commands in the order specified, e.g.
654     mysqladmin -u root flush-privileges password "newpassword"
655     to reset a lost root password.
656     If this behaviour is ever changed, Docs should be notified.
657   */
658 
659   struct my_rnd_struct rand_st;
660   char buff[FN_REFLEN + 20];
661 
662   for (; argc > 0 ; argv++,argc--)
663   {
664     int command;
665     switch ((command= find_type(argv[0],&command_typelib,FIND_TYPE_BASIC))) {
666     case ADMIN_CREATE:
667     {
668       if (argc < 2)
669       {
670 	my_printf_error(0, "Too few arguments to create", error_flags);
671 	return 1;
672       }
673       if (maybe_disable_binlog(mysql))
674         return -1;
675       sprintf(buff,"create database `%.*s`",FN_REFLEN,argv[1]);
676       if (mysql_query(mysql,buff))
677       {
678 	my_printf_error(0,"CREATE DATABASE failed; error: '%-.200s'",
679 			error_flags, mysql_error(mysql));
680 	return -1;
681       }
682       argc--; argv++;
683       break;
684     }
685     case ADMIN_DROP:
686     {
687       if (argc < 2)
688       {
689 	my_printf_error(0, "Too few arguments to drop", error_flags);
690 	return 1;
691       }
692       if (maybe_disable_binlog(mysql))
693         return -1;
694       if (drop_db(mysql,argv[1]))
695 	return -1;
696       argc--; argv++;
697       break;
698     }
699     case ADMIN_SHUTDOWN:
700     {
701       char pidfile[FN_REFLEN];
702       my_bool got_pidfile= 0;
703       time_t last_modified= 0;
704       struct stat pidfile_status;
705 
706       /*
707 	Only wait for pidfile on local connections
708 	If pidfile doesn't exist, continue without pid file checking
709       */
710       if (mysql->unix_socket && (got_pidfile= !get_pidfile(mysql, pidfile)) &&
711 	  !stat(pidfile, &pidfile_status))
712 	last_modified= pidfile_status.st_mtime;
713 
714       if (mysql_shutdown(mysql, SHUTDOWN_DEFAULT))
715       {
716 	my_printf_error(0, "shutdown failed; error: '%s'", error_flags,
717 			mysql_error(mysql));
718 	return -1;
719       }
720       argc=1;                   /* force SHUTDOWN to be the last command    */
721       if (got_pidfile)
722       {
723 	if (opt_verbose)
724 	  printf("Shutdown signal sent to server;  Waiting for pid file to disappear\n");
725 
726 	/* Wait until pid file is gone */
727 	if (wait_pidfile(pidfile, last_modified, &pidfile_status))
728 	  return -1;
729       }
730       break;
731     }
732     case ADMIN_FLUSH_PRIVILEGES:
733     case ADMIN_RELOAD:
734       if (flush(mysql, "privileges"))
735       {
736 	my_printf_error(0, "reload failed; error: '%s'", error_flags,
737 			mysql_error(mysql));
738 	return -1;
739       }
740       break;
741     case ADMIN_REFRESH:
742       if (mysql_refresh(mysql,
743 			(uint) ~(REFRESH_GRANT | REFRESH_STATUS |
744 				 REFRESH_READ_LOCK | REFRESH_SLAVE |
745 				 REFRESH_MASTER)))
746       {
747 	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
748 			mysql_error(mysql));
749 	return -1;
750       }
751       break;
752     case ADMIN_FLUSH_THREADS:
753       if (mysql_refresh(mysql,(uint) REFRESH_THREADS))
754       {
755 	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
756 			mysql_error(mysql));
757 	return -1;
758       }
759       break;
760     case ADMIN_VER:
761       new_line=1;
762       print_version();
763       puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
764       printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
765       printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
766       printf("Connection\t\t%s\n",mysql_get_host_info(mysql));
767       if (mysql->unix_socket)
768 	printf("UNIX socket\t\t%s\n", mysql->unix_socket);
769       else
770 	printf("TCP port\t\t%d\n", mysql->port);
771       status=mysql_stat(mysql);
772       {
773 	char *pos,buff[40];
774 	ulong sec;
775 	pos= (char*) strchr(status,' ');
776 	*pos++=0;
777 	printf("%s\t\t\t",status);			/* print label */
778 	if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
779 	{
780 	  nice_time(sec,buff);
781 	  puts(buff);				/* print nice time */
782 	  while (*status == ' ') status++;	/* to next info */
783 	}
784       }
785       putc('\n',stdout);
786       if (status)
787 	puts(status);
788       break;
789     case ADMIN_PROCESSLIST:
790     {
791       MYSQL_RES *result;
792       MYSQL_ROW row;
793 
794       if (mysql_query(mysql, (opt_verbose ? "show full processlist" :
795 			      "show processlist")) ||
796 	  !(result = mysql_store_result(mysql)))
797       {
798 	my_printf_error(0, "process list failed; error: '%s'", error_flags,
799 			mysql_error(mysql));
800 	return -1;
801       }
802       print_header(result);
803       while ((row=mysql_fetch_row(result)))
804 	print_row(result,row,0);
805       print_top(result);
806       mysql_free_result(result);
807       new_line=1;
808       break;
809     }
810     case ADMIN_STATUS:
811       status=mysql_stat(mysql);
812       if (status)
813 	puts(status);
814       break;
815     case ADMIN_KILL:
816       {
817 	uint error=0;
818 	char *pos;
819 	if (argc < 2)
820 	{
821 	  my_printf_error(0, "Too few arguments to 'kill'", error_flags);
822 	  return 1;
823 	}
824 	pos=argv[1];
825 	for (;;)
826 	{
827           /* We don't use mysql_kill(), since it only handles 32-bit IDs. */
828           char buff[26], *out; /* "KILL " + max 20 digs + NUL */
829           out= strxmov(buff, "KILL ", NullS);
830           ullstr(strtoull(pos, NULL, 0), out);
831 
832           if (mysql_query(mysql, buff))
833 	  {
834             /* out still points to just the number */
835 	    my_printf_error(0, "kill failed on %s; error: '%s'", error_flags,
836 			    out, mysql_error(mysql));
837 	    error=1;
838 	  }
839 	  if (!(pos=strchr(pos,',')))
840 	    break;
841 	  pos++;
842 	}
843 	argc--; argv++;
844 	if (error)
845 	  return -1;
846 	break;
847       }
848     case ADMIN_DEBUG:
849       if (mysql_dump_debug_info(mysql))
850       {
851 	my_printf_error(0, "debug failed; error: '%s'", error_flags,
852 			mysql_error(mysql));
853 	return -1;
854       }
855       break;
856     case ADMIN_VARIABLES:
857     {
858       MYSQL_RES *res;
859       MYSQL_ROW row;
860 
861       new_line=1;
862       if (mysql_query(mysql,"show /*!40003 GLOBAL */ variables") ||
863 	  !(res=mysql_store_result(mysql)))
864       {
865 	my_printf_error(0, "unable to show variables; error: '%s'", error_flags,
866 			mysql_error(mysql));
867 	return -1;
868       }
869       print_header(res);
870       while ((row=mysql_fetch_row(res)))
871 	print_row(res,row,0);
872       print_top(res);
873       mysql_free_result(res);
874       break;
875     }
876     case ADMIN_EXTENDED_STATUS:
877     {
878       MYSQL_RES *res;
879       MYSQL_ROW row;
880       uint rownr = 0;
881       void (*func) (MYSQL_RES*, MYSQL_ROW, uint);
882 
883       new_line = 1;
884       if (mysql_query(mysql, "show /*!50002 GLOBAL */ status") ||
885 	  !(res = mysql_store_result(mysql)))
886       {
887 	my_printf_error(0, "unable to show status; error: '%s'", error_flags,
888 			mysql_error(mysql));
889 	return -1;
890       }
891 
892       DBUG_ASSERT(mysql_num_rows(res) < MAX_MYSQL_VAR+100);
893 
894       if (!opt_vertical)
895 	print_header(res);
896       else
897       {
898 	if (!ex_status_printed)
899 	{
900 	  store_values(res);
901 	  truncate_names();   /* Does some printing also */
902 	}
903 	else
904 	{
905 	  print_relative_line();
906 	  print_relative_header();
907 	  print_relative_line();
908 	}
909       }
910 
911       /*      void (*func) (MYSQL_RES*, MYSQL_ROW, uint); */
912       if (opt_relative && !opt_vertical)
913 	func = print_relative_row;
914       else if (opt_vertical)
915 	func = print_relative_row_vert;
916       else
917 	func = print_row;
918 
919       while ((row = mysql_fetch_row(res)))
920 	(*func)(res, row, rownr++);
921       if (opt_vertical)
922       {
923 	if (ex_status_printed)
924 	{
925 	  putchar('\n');
926 	  print_relative_line();
927 	}
928       }
929       else
930 	print_top(res);
931 
932       ex_status_printed = 1; /* From now on the output will be relative */
933       mysql_free_result(res);
934       break;
935     }
936     case ADMIN_FLUSH_LOGS:
937     {
938       if (flush(mysql, "logs"))
939       {
940 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
941 			mysql_error(mysql));
942 	return -1;
943       }
944       break;
945     }
946     case ADMIN_FLUSH_BINARY_LOG:
947     {
948       if (flush(mysql, "binary logs"))
949       {
950         my_printf_error(0, "flush failed; error: '%s'", error_flags,
951                         mysql_error(mysql));
952         return -1;
953       }
954       break;
955     }
956     case ADMIN_FLUSH_ENGINE_LOG:
957     {
958       if (flush(mysql, "engine logs"))
959       {
960         my_printf_error(0, "flush failed; error: '%s'", error_flags,
961                         mysql_error(mysql));
962         return -1;
963       }
964       break;
965     }
966     case ADMIN_FLUSH_ERROR_LOG:
967     {
968       if (flush(mysql, "error logs"))
969       {
970         my_printf_error(0, "flush failed; error: '%s'", error_flags,
971                         mysql_error(mysql));
972         return -1;
973       }
974       break;
975     }
976     case ADMIN_FLUSH_GENERAL_LOG:
977     {
978       if (flush(mysql, "general logs"))
979       {
980         my_printf_error(0, "flush failed; error: '%s'", error_flags,
981                         mysql_error(mysql));
982         return -1;
983       }
984       break;
985     }
986     case ADMIN_FLUSH_RELAY_LOG:
987     {
988       if (flush(mysql, "relay logs"))
989       {
990         my_printf_error(0, "flush failed; error: '%s'", error_flags,
991                         mysql_error(mysql));
992         return -1;
993       }
994       break;
995     }
996     case ADMIN_FLUSH_SLOW_LOG:
997     {
998       if (flush(mysql, "slow logs"))
999       {
1000 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1001 			mysql_error(mysql));
1002 	return -1;
1003       }
1004       break;
1005     }
1006     case ADMIN_FLUSH_HOSTS:
1007     {
1008       if (flush(mysql, "hosts"))
1009       {
1010 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1011 			mysql_error(mysql));
1012 	return -1;
1013       }
1014       break;
1015     }
1016     case ADMIN_FLUSH_TABLES:
1017     {
1018       if (flush(mysql, "tables"))
1019       {
1020 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1021 			mysql_error(mysql));
1022 	return -1;
1023       }
1024       break;
1025     }
1026     case ADMIN_FLUSH_STATUS:
1027     {
1028       if (flush(mysql, "status"))
1029       {
1030 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1031 			mysql_error(mysql));
1032 	return -1;
1033       }
1034       break;
1035     }
1036     case ADMIN_FLUSH_TABLE_STATISTICS:
1037     {
1038       if (flush(mysql, "table_statistics"))
1039       {
1040 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1041 			mysql_error(mysql));
1042 	return -1;
1043       }
1044       break;
1045     }
1046     case ADMIN_FLUSH_INDEX_STATISTICS:
1047     {
1048       if (flush(mysql, "index_statistics"))
1049       {
1050 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1051 			mysql_error(mysql));
1052 	return -1;
1053       }
1054       break;
1055     }
1056     case ADMIN_FLUSH_USER_STATISTICS:
1057     {
1058       if (flush(mysql, "user_statistics"))
1059       {
1060 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1061 			mysql_error(mysql));
1062 	return -1;
1063       }
1064       break;
1065     }
1066     case ADMIN_FLUSH_USER_RESOURCES:
1067     {
1068       if (flush(mysql, "user_resources"))
1069       {
1070         my_printf_error(0, "flush failed; error: '%s'", error_flags,
1071                         mysql_error(mysql));
1072         return -1;
1073       }
1074       break;
1075     }
1076     case ADMIN_FLUSH_CLIENT_STATISTICS:
1077     {
1078       if (flush(mysql, "client_statistics"))
1079       {
1080 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1081 			mysql_error(mysql));
1082 	return -1;
1083       }
1084       break;
1085     }
1086     case ADMIN_FLUSH_ALL_STATISTICS:
1087     {
1088       if (flush(mysql, "table_statistics,index_statistics,"
1089                        "user_statistics,client_statistics"))
1090       {
1091 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1092 			mysql_error(mysql));
1093 	return -1;
1094       }
1095       break;
1096     }
1097     case ADMIN_FLUSH_ALL_STATUS:
1098     {
1099       if (flush(mysql, "status,table_statistics,index_statistics,"
1100                        "user_statistics,client_statistics"))
1101       {
1102 	my_printf_error(0, "flush failed; error: '%s'", error_flags,
1103 			mysql_error(mysql));
1104 	return -1;
1105       }
1106       break;
1107     }
1108     case ADMIN_OLD_PASSWORD:
1109     case ADMIN_PASSWORD:
1110     {
1111       char buff[128],crypted_pw[64];
1112       time_t start_time;
1113       char *typed_password= NULL, *verified= NULL;
1114       /* Do initialization the same way as we do in mysqld */
1115       start_time=time((time_t*) 0);
1116       my_rnd_init(&rand_st,(ulong) start_time,(ulong) start_time/2);
1117 
1118       if (maybe_disable_binlog(mysql))
1119         return -1;
1120       if (argc < 1)
1121       {
1122 	my_printf_error(0, "Too few arguments to change password", error_flags);
1123 	return 1;
1124       }
1125       else if (argc == 1)
1126       {
1127         /* prompt for password */
1128         typed_password= get_tty_password("New password: ");
1129         verified= get_tty_password("Confirm new password: ");
1130         if (strcmp(typed_password, verified) != 0)
1131         {
1132           my_printf_error(0,"Passwords don't match",MYF(ME_BELL));
1133           ret = -1;
1134           goto password_done;
1135         }
1136       }
1137       else
1138         typed_password= argv[1];
1139 
1140       if (typed_password[0])
1141       {
1142         bool old= (find_type(argv[0], &command_typelib, FIND_TYPE_BASIC) ==
1143                    ADMIN_OLD_PASSWORD);
1144 #ifdef __WIN__
1145         size_t pw_len= strlen(typed_password);
1146         if (pw_len > 1 && typed_password[0] == '\'' &&
1147             typed_password[pw_len-1] == '\'')
1148           printf("Warning: single quotes were not trimmed from the password by"
1149                  " your command\nline client, as you might have expected.\n");
1150 #endif
1151         /*
1152            If we don't already know to use an old-style password, see what
1153            the server is using
1154         */
1155         if (!old)
1156         {
1157           if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'"))
1158           {
1159             my_printf_error(0, "Could not determine old_passwords setting from server; error: '%s'",
1160                 	    error_flags, mysql_error(mysql));
1161             ret = -1;
1162             goto password_done;
1163           }
1164           else
1165           {
1166             MYSQL_RES *res= mysql_store_result(mysql);
1167             if (!res)
1168             {
1169               my_printf_error(0,
1170                               "Could not get old_passwords setting from "
1171                               "server; error: '%s'",
1172         		      error_flags, mysql_error(mysql));
1173               ret = -1;
1174               goto password_done;
1175             }
1176             if (!mysql_num_rows(res))
1177               old= 1;
1178             else
1179             {
1180               MYSQL_ROW row= mysql_fetch_row(res);
1181               old= !strncmp(row[1], "ON", 2);
1182             }
1183             mysql_free_result(res);
1184           }
1185         }
1186         if (old)
1187           my_make_scrambled_password_323(crypted_pw, typed_password, strlen(typed_password));
1188         else
1189           my_make_scrambled_password(crypted_pw, typed_password, strlen(typed_password));
1190       }
1191       else
1192 	crypted_pw[0]=0;			/* No password */
1193       sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
1194 
1195       if (mysql_query(mysql,"set sql_log_off=1"))
1196       {
1197 	my_printf_error(0, "Can't turn off logging; error: '%s'",
1198 			error_flags, mysql_error(mysql));
1199         ret = -1;
1200       }
1201       else
1202       if (mysql_query(mysql,buff))
1203       {
1204 	if (mysql_errno(mysql)!=1290)
1205 	{
1206 	  my_printf_error(0,"unable to change password; error: '%s'",
1207 			  error_flags, mysql_error(mysql));
1208 	}
1209 	else
1210 	{
1211 	  /*
1212 	    We don't try to execute 'update mysql.user set..'
1213 	    because we can't perfectly find out the host
1214 	   */
1215 	  my_printf_error(0,"\n"
1216 			  "You cannot use 'password' command as mysqld runs\n"
1217 			  " with grant tables disabled (was started with"
1218 			  " --skip-grant-tables).\n"
1219 			  "Use: \"mysqladmin flush-privileges password '*'\""
1220 			  " instead", error_flags);
1221 	}
1222         ret = -1;
1223       }
1224 password_done:
1225       /* free up memory from prompted password */
1226       if (typed_password != argv[1])
1227       {
1228         my_free(typed_password);
1229         my_free(verified);
1230       }
1231       argc--; argv++;
1232       break;
1233     }
1234 
1235     case ADMIN_START_SLAVE:
1236     case ADMIN_START_ALL_SLAVES:
1237     {
1238       my_bool many_slaves= 0;
1239       const char *query= "START SLAVE";
1240       if (command == ADMIN_START_ALL_SLAVES && mariadb_connection(mysql) &&
1241           mysql_get_server_version(mysql) >= 100000)
1242       {
1243         query="START ALL SLAVES";
1244         many_slaves= 1;
1245       }
1246 
1247       if (mysql_query(mysql, query))
1248       {
1249 	my_printf_error(0, "Error starting slave: %s", error_flags,
1250 			mysql_error(mysql));
1251 	return -1;
1252       }
1253       else if (!many_slaves || mysql_warning_count(mysql) > 0)
1254       {
1255         if (!option_silent)
1256           puts("Slave('s) started");
1257       }
1258       else
1259       {
1260         if (!option_silent)
1261           puts("No slaves to start");
1262       }
1263       break;
1264     }
1265     case ADMIN_STOP_SLAVE:
1266     case ADMIN_STOP_ALL_SLAVES:
1267     {
1268       const char *query= "STOP SLAVE";
1269       my_bool many_slaves= 0;
1270 
1271       if (command == ADMIN_STOP_ALL_SLAVES && mariadb_connection(mysql) &&
1272           mysql_get_server_version(mysql) >= 100000)
1273       {
1274         query="STOP ALL SLAVES";
1275         many_slaves= 1;
1276       }
1277 
1278       if (mysql_query(mysql, query))
1279       {
1280 	  my_printf_error(0, "Error stopping slave: %s", error_flags,
1281 			  mysql_error(mysql));
1282 	  return -1;
1283       }
1284       else if (!many_slaves || mysql_warning_count(mysql) > 0)
1285       {
1286         /* We can't detect if there was any slaves to stop with STOP SLAVE */
1287         if (many_slaves && !option_silent)
1288           puts("Slave('s) stopped");
1289       }
1290       else
1291       {
1292         if (!option_silent)
1293           puts("All slaves was already stopped");
1294       }
1295       break;
1296     }
1297     case ADMIN_PING:
1298     {
1299       my_bool reconnect= 0;
1300       mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
1301       if (!mysql_ping(mysql))
1302       {
1303 	if (option_silent < 2)
1304 	  puts("mysqld is alive");
1305       }
1306       else
1307       {
1308 	if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
1309 	{
1310           reconnect= 1;
1311           mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
1312 	  if (!mysql_ping(mysql))
1313 	    puts("connection was down, but mysqld is now alive");
1314 	}
1315 	else
1316 	{
1317 	  my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
1318 			  error_flags, mysql_error(mysql));
1319 	  return -1;
1320 	}
1321       }
1322       reconnect=1;	/* Automatic reconnect is default */
1323       mysql_options(mysql, MYSQL_OPT_RECONNECT, &reconnect);
1324       break;
1325     }
1326     default:
1327       my_printf_error(0, "Unknown command: '%-.60s'", error_flags, argv[0]);
1328       return 1;
1329     }
1330   }
1331   return ret;
1332 }
1333 
1334 /**
1335    @brief Masking the password if it is passed as command line argument.
1336 
1337    @details It works in Linux and changes cmdline in ps and /proc/pid/cmdline,
1338             but it won't work for history file of shell.
1339             The command line arguments are copied to another array and the
1340             password in the argv is masked. This function is called just after
1341             "handle_options" because in "handle_options", the agrv pointers
1342             are altered which makes freeing of dynamically allocated memory
1343             difficult. The password masking is done before all other operations
1344             in order to minimise the time frame of password visibility via cmdline.
1345 
1346    @param argc            command line options (count)
1347    @param argv            command line options (values)
1348 
1349    @return temp_argv      copy of argv
1350 */
1351 
mask_password(int argc,char *** argv)1352 static char **mask_password(int argc, char ***argv)
1353 {
1354   char **temp_argv;
1355   if (!argc)
1356     return NULL;
1357 
1358   temp_argv= (char **)(my_malloc(sizeof(char *) * argc, MYF(MY_WME)));
1359   argc--;
1360   while (argc > 0)
1361   {
1362     temp_argv[argc]= my_strdup((*argv)[argc], MYF(MY_FAE));
1363     if (find_type((*argv)[argc - 1],&command_typelib, FIND_TYPE_BASIC) == ADMIN_PASSWORD ||
1364         find_type((*argv)[argc - 1],&command_typelib, FIND_TYPE_BASIC) == ADMIN_OLD_PASSWORD)
1365     {
1366       char *start= (*argv)[argc];
1367       while (*start)
1368         *start++= 'x';
1369       start= (*argv)[argc];
1370       if (*start)
1371         start[1]= 0;                         /* Cut length of argument */
1372      }
1373     argc--;
1374   }
1375   temp_argv[argc]= my_strdup((*argv)[argc], MYF(MY_FAE));
1376   return(temp_argv);
1377 }
1378 
print_version(void)1379 static void print_version(void)
1380 {
1381   printf("%s  Ver %s Distrib %s, for %s on %s\n",my_progname,ADMIN_VERSION,
1382 	 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
1383 }
1384 
1385 
usage(void)1386 static void usage(void)
1387 {
1388   print_version();
1389   puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
1390   puts("Administration program for the mysqld daemon.");
1391   printf("Usage: %s [OPTIONS] command command....\n", my_progname);
1392   print_defaults("my",load_default_groups);
1393   puts("");
1394   my_print_help(my_long_options);
1395   my_print_variables(my_long_options);
1396   puts("\nWhere command is a one or more of: (Commands may be shortened)\n\
1397   create databasename	  Create a new database\n\
1398   debug			  Instruct server to write debug information to log\n\
1399   drop databasename	  Delete a database and all its tables\n\
1400   extended-status         Gives an extended status message from the server\n\
1401   flush-all-statistics    Flush all statistics tables\n\
1402   flush-all-status        Flush status and statistics\n\
1403   flush-client-statistics Flush client statistics\n\
1404   flush-hosts             Flush all cached hosts\n\
1405   flush-index-statistics  Flush index statistics\n\
1406   flush-logs              Flush all logs\n\
1407   flush-privileges        Reload grant tables (same as reload)\n\
1408   flush-binary-log        Flush binary log\n\
1409   flush-engine-log        Flush engine log(s)\n\
1410   flush-error-log         Flush error log\n\
1411   flush-general-log       Flush general log\n\
1412   flush-relay-log         Flush relay log\n\
1413   flush-slow-log          Flush slow query log\n\
1414   flush-status            Clear status variables\n\
1415   flush-table-statistics  Clear table statistics\n\
1416   flush-tables            Flush all tables\n\
1417   flush-threads           Flush the thread cache\n\
1418   flush-user-statistics   Flush user statistics\n\
1419   flush-user-resources    Flush user resources\n\
1420   kill id,id,...	Kill mysql threads");
1421 #if MYSQL_VERSION_ID >= 32200
1422   puts("\
1423   password [new-password] Change old password to new-password in current format\n\
1424   old-password [new-password] Change old password to new-password in old format");
1425 #endif
1426   puts("\
1427   ping			Check if mysqld is alive\n\
1428   processlist		Show list of active threads in server\n\
1429   reload		Reload grant tables\n\
1430   refresh		Flush all tables and close and open logfiles\n\
1431   shutdown		Take server down\n\
1432   status		Gives a short status message from the server\n\
1433   start-slave		Start slave\n\
1434   stop-slave		Stop slave\n\
1435   variables             Prints variables available\n\
1436   version		Get version info from server");
1437 }
1438 
1439 
drop_db(MYSQL * mysql,const char * db)1440 static int drop_db(MYSQL *mysql, const char *db)
1441 {
1442   char name_buff[FN_REFLEN+20], buf[10];
1443   char *input;
1444 
1445   if (!option_force)
1446   {
1447     puts("Dropping the database is potentially a very bad thing to do.");
1448     puts("Any data stored in the database will be destroyed.\n");
1449     printf("Do you really want to drop the '%s' database [y/N] ",db);
1450     fflush(stdout);
1451     input= fgets(buf, sizeof(buf)-1, stdin);
1452     if (!input || ((*input != 'y') && (*input != 'Y')))
1453     {
1454       puts("\nOK, aborting database drop!");
1455       return -1;
1456     }
1457   }
1458   sprintf(name_buff,"drop database `%.*s`",FN_REFLEN,db);
1459   if (mysql_query(mysql,name_buff))
1460   {
1461     my_printf_error(0, "DROP DATABASE %s failed;\nerror: '%s'", error_flags,
1462 		    db,mysql_error(mysql));
1463     return 1;
1464   }
1465   printf("Database \"%s\" dropped\n",db);
1466   return 0;
1467 }
1468 
1469 
nice_time(ulong sec,char * buff)1470 static void nice_time(ulong sec,char *buff)
1471 {
1472   ulong tmp;
1473 
1474   if (sec >= 3600L*24)
1475   {
1476     tmp=sec/(3600L*24);
1477     sec-=3600L*24*tmp;
1478     buff=int10_to_str(tmp, buff, 10);
1479     buff=strmov(buff,tmp > 1 ? " days " : " day ");
1480   }
1481   if (sec >= 3600L)
1482   {
1483     tmp=sec/3600L;
1484     sec-=3600L*tmp;
1485     buff=int10_to_str(tmp, buff, 10);
1486     buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
1487   }
1488   if (sec >= 60)
1489   {
1490     tmp=sec/60;
1491     sec-=60*tmp;
1492     buff=int10_to_str(tmp, buff, 10);
1493     buff=strmov(buff," min ");
1494   }
1495   strmov(int10_to_str(sec, buff, 10)," sec");
1496 }
1497 
1498 
print_header(MYSQL_RES * result)1499 static void print_header(MYSQL_RES *result)
1500 {
1501   MYSQL_FIELD *field;
1502 
1503   print_top(result);
1504   mysql_field_seek(result,0);
1505   putchar('|');
1506   while ((field = mysql_fetch_field(result)))
1507   {
1508     printf(" %-*s|",(int) field->max_length+1,field->name);
1509   }
1510   putchar('\n');
1511   print_top(result);
1512 }
1513 
1514 
print_top(MYSQL_RES * result)1515 static void print_top(MYSQL_RES *result)
1516 {
1517   uint i,length;
1518   MYSQL_FIELD *field;
1519 
1520   putchar('+');
1521   mysql_field_seek(result,0);
1522   while((field = mysql_fetch_field(result)))
1523   {
1524     if ((length=(uint) strlen(field->name)) > field->max_length)
1525       field->max_length=length;
1526     else
1527       length=field->max_length;
1528     for (i=length+2 ; i--> 0 ; )
1529       putchar('-');
1530     putchar('+');
1531   }
1532   putchar('\n');
1533 }
1534 
1535 
1536 /* 3.rd argument, uint row, is not in use. Don't remove! */
print_row(MYSQL_RES * result,MYSQL_ROW cur,uint row)1537 static void print_row(MYSQL_RES *result, MYSQL_ROW cur,
1538 		      uint row __attribute__((unused)))
1539 {
1540   uint i,length;
1541   MYSQL_FIELD *field;
1542 
1543   putchar('|');
1544   mysql_field_seek(result,0);
1545   for (i=0 ; i < mysql_num_fields(result); i++)
1546   {
1547     field = mysql_fetch_field(result);
1548     length=field->max_length;
1549     printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
1550   }
1551   putchar('\n');
1552 }
1553 
1554 
print_relative_row(MYSQL_RES * result,MYSQL_ROW cur,uint row)1555 static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row)
1556 {
1557   ulonglong tmp;
1558   char buff[22];
1559   MYSQL_FIELD *field;
1560 
1561   mysql_field_seek(result, 0);
1562   field = mysql_fetch_field(result);
1563   printf("| %-*s|", (int) field->max_length + 1, cur[0]);
1564 
1565   field = mysql_fetch_field(result);
1566   tmp = cur[1] ? strtoull(cur[1], NULL, 10) : (ulonglong) 0;
1567   printf(" %-*s|\n", (int) field->max_length + 1,
1568 	 llstr((tmp - last_values[row]), buff));
1569   last_values[row] = tmp;
1570 }
1571 
1572 
print_relative_row_vert(MYSQL_RES * result,MYSQL_ROW cur,uint row)1573 static void print_relative_row_vert(MYSQL_RES *result __attribute__((unused)),
1574 				    MYSQL_ROW cur,
1575 				    uint row __attribute__((unused)))
1576 {
1577   uint length;
1578   ulonglong tmp;
1579   char buff[22];
1580 
1581   if (!row)
1582     putchar('|');
1583 
1584   tmp = cur[1] ? strtoull(cur[1], NULL, 10) : (ulonglong) 0;
1585   printf(" %-*s|", ex_val_max_len[row] + 1,
1586 	 llstr((tmp - last_values[row]), buff));
1587 
1588   /* Find the minimum row length needed to output the relative value */
1589   if ((length=(uint) strlen(buff) > ex_val_max_len[row]) && ex_status_printed)
1590     ex_val_max_len[row] = length;
1591   last_values[row] = tmp;
1592 }
1593 
1594 
store_values(MYSQL_RES * result)1595 static void store_values(MYSQL_RES *result)
1596 {
1597   uint i;
1598   MYSQL_ROW row;
1599   MYSQL_FIELD *field;
1600 
1601   field = mysql_fetch_field(result);
1602   max_var_length = field->max_length;
1603   field = mysql_fetch_field(result);
1604   max_val_length = field->max_length;
1605 
1606   for (i = 0; (row = mysql_fetch_row(result)); i++)
1607   {
1608     strmov(ex_var_names[i], row[0]);
1609     last_values[i]=strtoull(row[1],NULL,10);
1610     ex_val_max_len[i]=2;		/* Default print width for values */
1611   }
1612   ex_var_count = i;
1613   return;
1614 }
1615 
1616 
print_relative_header()1617 static void print_relative_header()
1618 {
1619   uint i;
1620 
1621   putchar('|');
1622   for (i = 0; i < ex_var_count; i++)
1623     printf(" %-*s|", ex_val_max_len[i] + 1, truncated_var_names[i]);
1624   putchar('\n');
1625 }
1626 
1627 
print_relative_line()1628 static void print_relative_line()
1629 {
1630   uint i;
1631 
1632   putchar('+');
1633   for (i = 0; i < ex_var_count; i++)
1634   {
1635     uint j;
1636     for (j = 0; j < ex_val_max_len[i] + 2; j++)
1637       putchar('-');
1638     putchar('+');
1639   }
1640   putchar('\n');
1641 }
1642 
1643 
truncate_names()1644 static void truncate_names()
1645 {
1646   uint i;
1647   char *ptr,top_line[MAX_TRUNC_LENGTH+4+NAME_LEN+22+1],buff[22];
1648 
1649   ptr=top_line;
1650   *ptr++='+';
1651   ptr=strfill(ptr,max_var_length+2,'-');
1652   *ptr++='+';
1653   ptr=strfill(ptr,MAX_TRUNC_LENGTH+2,'-');
1654   *ptr++='+';
1655   ptr=strfill(ptr,max_val_length+2,'-');
1656   *ptr++='+';
1657   *ptr=0;
1658   puts(top_line);
1659 
1660   for (i = 0 ; i < ex_var_count; i++)
1661   {
1662     uint sfx=1,j;
1663     printf("| %-*s|", max_var_length + 1, ex_var_names[i]);
1664     ptr = ex_var_names[i];
1665     /* Make sure no two same truncated names will become */
1666     for (j = 0; j < i; j++)
1667       if (*truncated_var_names[j] == *ptr)
1668 	sfx++;
1669 
1670     truncated_var_names[i][0]= *ptr;		/* Copy first var char */
1671     int10_to_str(sfx, truncated_var_names[i]+1,10);
1672     printf(" %-*s|", MAX_TRUNC_LENGTH + 1, truncated_var_names[i]);
1673     printf(" %-*s|\n", max_val_length + 1, llstr(last_values[i],buff));
1674   }
1675   puts(top_line);
1676   return;
1677 }
1678 
1679 
get_pidfile(MYSQL * mysql,char * pidfile)1680 static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
1681 {
1682   MYSQL_RES* result;
1683 
1684   if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'"))
1685   {
1686     my_printf_error(mysql_errno(mysql),
1687                     "The query to get the server's pid file failed,"
1688                     " error: '%s'. Continuing.", error_flags,
1689                     mysql_error(mysql));
1690   }
1691   result = mysql_store_result(mysql);
1692   if (result)
1693   {
1694     MYSQL_ROW row=mysql_fetch_row(result);
1695     if (row)
1696       strmov(pidfile, row[1]);
1697     mysql_free_result(result);
1698     return row == 0;				/* Error if row = 0 */
1699   }
1700   return 1;					/* Error */
1701 }
1702 
1703 /*
1704   Return 1 if pid file didn't disappear or change
1705 */
1706 
wait_pidfile(char * pidfile,time_t last_modified,struct stat * pidfile_status)1707 static my_bool wait_pidfile(char *pidfile, time_t last_modified,
1708 			    struct stat *pidfile_status)
1709 {
1710   char buff[FN_REFLEN];
1711   my_bool error= 1;
1712   uint count= 0;
1713   DBUG_ENTER("wait_pidfile");
1714 
1715   system_filename(buff, pidfile);
1716   do
1717   {
1718     int fd;
1719     if ((fd= my_open(buff, O_RDONLY, MYF(0))) < 0)
1720     {
1721       error= 0;
1722       break;
1723     }
1724     (void) my_close(fd,MYF(0));
1725     if (last_modified && !stat(pidfile, pidfile_status))
1726     {
1727       if (last_modified != pidfile_status->st_mtime)
1728       {
1729 	/* File changed;  Let's assume that mysqld did restart */
1730 	if (opt_verbose)
1731 	  printf("pid file '%s' changed while waiting for it to disappear!\nmysqld did probably restart\n",
1732 		 buff);
1733 	error= 0;
1734 	break;
1735       }
1736     }
1737     if (count++ == opt_shutdown_timeout)
1738       break;
1739     sleep(1);
1740   } while (!interrupted);
1741 
1742   if (error)
1743   {
1744     DBUG_PRINT("warning",("Pid file didn't disappear"));
1745     fprintf(stderr,
1746 	    "Warning;  Aborted waiting on pid file: '%s' after %d seconds\n",
1747 	    buff, count-1);
1748   }
1749   DBUG_RETURN(error);
1750 }
1751