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