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