~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/* maintaince of mysql databases */
17
18
#include "client_priv.h"
19
#include <signal.h>
20
#include <my_pthread.h>				/* because of signal()	*/
21
#include <sys/stat.h>
22
#include <mysql.h>
23
24
#ifdef LATER_HAVE_NDBCLUSTER_DB
25
#include "../ndb/src/mgmclient/ndb_mgmclient.h"
26
#endif
27
28
#define ADMIN_VERSION "8.42"
29
#define MAX_MYSQL_VAR 256
30
#define SHUTDOWN_DEF_TIMEOUT 3600		/* Wait for shutdown */
31
#define MAX_TRUNC_LENGTH 3
32
33
char *host= NULL, *user= 0, *opt_password= 0,
34
     *default_charset= NULL;
35
char truncated_var_names[MAX_MYSQL_VAR][MAX_TRUNC_LENGTH];
36
char ex_var_names[MAX_MYSQL_VAR][FN_REFLEN];
37
ulonglong last_values[MAX_MYSQL_VAR];
38
static int interval=0;
39
static my_bool option_force=0,interrupted=0,new_line=0,
40
               opt_compress=0, opt_relative=0, opt_verbose=0, opt_vertical=0,
41
               tty_password= 0, opt_nobeep;
42
static my_bool debug_info_flag= 0, debug_check_flag= 0;
43
static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations;
44
static uint opt_count_iterations= 0, my_end_arg;
45
static ulong opt_connect_timeout, opt_shutdown_timeout;
46
static char * unix_port=0;
47
#ifdef LATER_HAVE_NDBCLUSTER_DB
48
static my_bool opt_ndbcluster=0;
49
static char *opt_ndb_connectstring=0;
50
#endif
51
52
#ifdef HAVE_SMEM
53
static char *shared_memory_base_name=0;
54
#endif
55
static uint opt_protocol=0;
56
static 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
64
static uint ex_val_max_len[MAX_MYSQL_VAR];
65
static my_bool ex_status_printed = 0; /* First output is not relative. */
66
static uint ex_var_count, max_var_length, max_val_length;
67
68
static void print_version(void);
69
static void usage(void);
70
extern "C" my_bool get_one_option(int optid, const struct my_option *opt,
71
                                  char *argument);
72
static my_bool sql_connect(MYSQL *mysql, uint wait);
73
static int execute_commands(MYSQL *mysql,int argc, char **argv);
74
static int drop_db(MYSQL *mysql,const char *db);
75
extern "C" sig_handler endprog(int signal_number);
76
static void nice_time(ulong sec,char *buff);
77
static void print_header(MYSQL_RES *result);
78
static void print_top(MYSQL_RES *result);
79
static void print_row(MYSQL_RES *result,MYSQL_ROW cur, uint row);
80
static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row);
81
static void print_relative_row_vert(MYSQL_RES *result, MYSQL_ROW cur, uint row);
82
static void print_relative_header();
83
static void print_relative_line();
84
static void truncate_names();
85
static my_bool get_pidfile(MYSQL *mysql, char *pidfile);
86
static my_bool wait_pidfile(char *pidfile, time_t last_modified,
87
			    struct stat *pidfile_status);
88
static void store_values(MYSQL_RES *result);
89
90
/*
91
  The order of commands must be the same as command_names,
92
  except ADMIN_ERROR
93
*/
94
enum commands {
95
  ADMIN_ERROR,
96
  ADMIN_CREATE,           ADMIN_DROP,            ADMIN_SHUTDOWN,
97
  ADMIN_RELOAD,           ADMIN_REFRESH,         ADMIN_VER,
98
  ADMIN_PROCESSLIST,      ADMIN_STATUS,          ADMIN_KILL,
99
  ADMIN_DEBUG,            ADMIN_VARIABLES,       ADMIN_FLUSH_LOGS,
100
  ADMIN_FLUSH_HOSTS,      ADMIN_FLUSH_TABLES,    ADMIN_PASSWORD,
101
  ADMIN_PING,             ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
102
  ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE,     ADMIN_STOP_SLAVE,
103
  ADMIN_FLUSH_THREADS,    ADMIN_OLD_PASSWORD
104
#ifdef LATER_HAVE_NDBCLUSTER_DB
105
  ,ADMIN_NDB_MGM
106
#endif
107
};
108
static const char *command_names[]= {
109
  "create",               "drop",                "shutdown",
110
  "reload",               "refresh",             "version",
111
  "processlist",          "status",              "kill",
112
  "debug",                "variables",           "flush-logs",
113
  "flush-hosts",          "flush-tables",        "password",
114
  "ping",                 "extended-status",     "flush-status",
115
  "flush-privileges",     "start-slave",         "stop-slave",
116
  "flush-threads","old-password",
117
#ifdef LATER_HAVE_NDBCLUSTER_DB
118
  "ndb-mgm",
119
#endif
120
  NullS
121
};
122
123
static TYPELIB command_typelib=
124
{ array_elements(command_names)-1,"commands", command_names, NULL};
125
126
static struct my_option my_long_options[] =
127
{
128
  {"count", 'c',
129
   "Number of iterations to make. This works with -i (--sleep) only.",
130
   (uchar**) &nr_iterations, (uchar**) &nr_iterations, 0, GET_UINT,
131
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
132
#ifndef DBUG_OFF
133
  {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
134
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
135
#endif
136
  {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
137
   (uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
138
   GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
139
  {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
140
   (uchar**) &debug_info_flag, (uchar**) &debug_info_flag,
141
   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
142
  {"force", 'f',
143
   "Don't ask for confirmation on drop database; with multiple commands, continue even if an error occurs.",
144
   (uchar**) &option_force, (uchar**) &option_force, 0, GET_BOOL, NO_ARG, 0, 0,
145
   0, 0, 0, 0},
146
  {"compress", 'C', "Use compression in server/client protocol.",
147
   (uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
148
   0, 0, 0},
149
  {"character-sets-dir", OPT_CHARSETS_DIR,
150
   "Directory where character sets are.", (uchar**) &charsets_dir,
151
   (uchar**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
152
  {"default-character-set", OPT_DEFAULT_CHARSET,
153
   "Set the default character set.", (uchar**) &default_charset,
154
   (uchar**) &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
155
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
156
   NO_ARG, 0, 0, 0, 0, 0, 0},
157
  {"host", 'h', "Connect to host.", (uchar**) &host, (uchar**) &host, 0, GET_STR,
158
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
159
  {"no-beep", 'b', "Turn off beep on error.", (uchar**) &opt_nobeep,
160
   (uchar**) &opt_nobeep, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 
161
  {"password", 'p',
162
   "Password to use when connecting to server. If password is not given it's asked from the tty.",
163
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
164
  {"port", 'P', "Port number to use for connection or 0 for default to, in "
165
   "order of preference, my.cnf, $MYSQL_TCP_PORT, "
166
#if MYSQL_PORT_DEFAULT == 0
167
   "/etc/services, "
168
#endif
169
   "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
170
   (uchar**) &tcp_port,
171
   (uchar**) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
172
  {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).",
173
    0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
174
  {"relative", 'r',
175
   "Show difference between current and previous values when used with -i. Currently works only with extended-status.",
176
   (uchar**) &opt_relative, (uchar**) &opt_relative, 0, GET_BOOL, NO_ARG, 0, 0, 0,
177
  0, 0, 0},
178
  {"set-variable", 'O',
179
   "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.",
180
   0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
181
#ifdef HAVE_SMEM
182
  {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
183
   "Base name of shared memory.", (uchar**) &shared_memory_base_name, (uchar**) &shared_memory_base_name,
184
   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
185
#endif
186
  {"silent", 's', "Silently exit if one can't connect to server.",
187
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
188
  {"socket", 'S', "Socket file to use for connection.",
189
   (uchar**) &unix_port, (uchar**) &unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0,
190
   0, 0, 0},
191
  {"sleep", 'i', "Execute commands again and again with a sleep between.",
192
   (uchar**) &interval, (uchar**) &interval, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0,
193
   0, 0},
194
#ifndef DONT_ALLOW_USER_CHANGE
195
  {"user", 'u', "User for login if not current user.", (uchar**) &user,
196
   (uchar**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
197
#endif
198
  {"verbose", 'v', "Write more information.", (uchar**) &opt_verbose,
199
   (uchar**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
200
  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
201
   NO_ARG, 0, 0, 0, 0, 0, 0},
202
  {"vertical", 'E',
203
   "Print output vertically. Is similar to --relative, but prints output vertically.",
204
   (uchar**) &opt_vertical, (uchar**) &opt_vertical, 0, GET_BOOL, NO_ARG, 0, 0, 0,
205
   0, 0, 0},
206
  {"wait", 'w', "Wait and retry if connection is down.", 0, 0, 0, GET_UINT,
207
   OPT_ARG, 0, 0, 0, 0, 0, 0},
208
  {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (uchar**) &opt_connect_timeout,
209
   (uchar**) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 3600*12, 0,
210
   3600*12, 0, 1, 0},
211
  {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (uchar**) &opt_shutdown_timeout,
212
   (uchar**) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG,
213
   SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0},
214
#ifdef LATER_HAVE_NDBCLUSTER_DB
215
  {"ndbcluster", OPT_NDBCLUSTER, ""
216
   "", (uchar**) &opt_ndbcluster,
217
   (uchar**) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
218
  {"ndb-connectstring", OPT_NDB_CONNECTSTRING, ""
219
   "", (uchar**) &opt_ndb_connectstring,
220
   (uchar**) &opt_ndb_connectstring, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
221
#endif
222
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
223
};
224
225
226
static const char *load_default_groups[]= { "mysqladmin","client",0 };
227
228
my_bool
229
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
230
	       char *argument)
231
{
232
  int error = 0;
233
234
  switch(optid) {
235
  case 'c':
236
    opt_count_iterations= 1;
237
    break;
238
  case 'p':
239
    if (argument)
240
    {
241
      char *start=argument;
242
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
243
      opt_password=my_strdup(argument,MYF(MY_FAE));
244
      while (*argument) *argument++= 'x';		/* Destroy argument */
245
      if (*start)
246
	start[1]=0;				/* Cut length of argument */
247
      tty_password= 0;
248
    }
249
    else
250
      tty_password=1;
251
    break;
252
  case 's':
253
    option_silent++;
254
    break;
255
  case '#':
256
    DBUG_PUSH(argument ? argument : "d:t:o,/tmp/mysqladmin.trace");
257
    break;
258
  case 'V':
259
    print_version();
260
    exit(0);
261
    break;
262
  case 'w':
263
    if (argument)
264
    {
265
      if ((option_wait=atoi(argument)) <= 0)
266
	option_wait=1;
267
    }
268
    else
269
      option_wait= ~(uint)0;
270
    break;
271
  case '?':
272
  case 'I':					/* Info */
273
    error++;
274
    break;
275
  case OPT_CHARSETS_DIR:
276
#if MYSQL_VERSION_ID > 32300
277
    charsets_dir = argument;
278
#endif
279
    break;
280
  case OPT_MYSQL_PROTOCOL:
281
    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
282
                                    opt->name);
283
    break;
284
  }
285
  if (error)
286
  {
287
    usage();
288
    exit(1);
289
  }
290
  return 0;
291
}
292
293
294
int main(int argc,char *argv[])
295
{
296
  int error= 0, ho_error;
297
  MYSQL mysql;
298
  char **commands, **save_argv;
299
300
  MY_INIT(argv[0]);
301
  mysql_init(&mysql);
302
  load_defaults("my",load_default_groups,&argc,&argv);
303
  save_argv = argv;				/* Save for free_defaults */
304
  if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
305
  {
306
    free_defaults(save_argv);
307
    exit(ho_error);
308
  }
309
  if (debug_info_flag)
310
    my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
311
  if (debug_check_flag)
312
    my_end_arg= MY_CHECK_ERROR;
313
314
  if (argc == 0)
315
  {
316
    usage();
317
    exit(1);
318
  }
319
  commands = argv;
320
  if (tty_password)
321
    opt_password = get_tty_password(NullS);
322
323
  VOID(signal(SIGINT,endprog));			/* Here if abort */
324
  VOID(signal(SIGTERM,endprog));		/* Here if abort */
325
326
  if (opt_compress)
327
    mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
328
  if (opt_connect_timeout)
329
  {
330
    uint tmp=opt_connect_timeout;
331
    mysql_options(&mysql,MYSQL_OPT_CONNECT_TIMEOUT, (char*) &tmp);
332
  }
333
  if (opt_protocol)
334
    mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
335
#ifdef HAVE_SMEM
336
  if (shared_memory_base_name)
337
    mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
338
#endif
339
  if (default_charset)
340
    mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
341
  error_flags= (myf)(opt_nobeep ? 0 : ME_BELL);
342
343
  if (sql_connect(&mysql, option_wait))
344
  {
345
    unsigned int err= mysql_errno(&mysql);
346
    if (err >= CR_MIN_ERROR && err <= CR_MAX_ERROR)
347
      error= 1;
348
    else
349
    {
350
      /* Return 0 if all commands are PING */
351
      for (; argc > 0; argv++, argc--)
352
      {
353
        if (find_type(argv[0], &command_typelib, 2) != ADMIN_PING)
354
        {
355
          error= 1;
356
          break;
357
        }
358
      }
359
    }
360
  }
361
  else
362
  {
363
    while (!interrupted && (!opt_count_iterations || nr_iterations))
364
    {
365
      new_line = 0;
366
      if ((error=execute_commands(&mysql,argc,commands)))
367
      {
368
	if (error > 0)
369
	  break;				/* Wrong command error */
370
	if (!option_force)
371
	{
372
	  if (option_wait && !interrupted)
373
	  {
374
	    mysql_close(&mysql);
375
	    if (!sql_connect(&mysql, option_wait))
376
	    {
377
	      sleep(1);				/* Don't retry too rapidly */
378
	      continue;				/* Retry */
379
	    }
380
	  }
381
	  error=1;
382
	  break;
383
	}
384
      }
385
      if (interval)
386
      {
387
	sleep(interval);
388
	if (new_line)
389
	  puts("");
390
	if (opt_count_iterations)
391
	  nr_iterations--;
392
      }
393
      else
394
	break;
395
    }
396
    mysql_close(&mysql);
397
  }
398
  my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
399
  my_free(user,MYF(MY_ALLOW_ZERO_PTR));
400
#ifdef HAVE_SMEM
401
  my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR));
402
#endif
403
  free_defaults(save_argv);
404
  my_end(my_end_arg);
405
  exit(error ? 1 : 0);
406
}
407
408
409
sig_handler endprog(int signal_number __attribute__((unused)))
410
{
411
  interrupted=1;
412
}
413
414
415
static my_bool sql_connect(MYSQL *mysql, uint wait)
416
{
417
  my_bool info=0;
418
419
  for (;;)
420
  {
421
    if (mysql_real_connect(mysql,host,user,opt_password,NullS,tcp_port,
422
			   unix_port, 0))
423
    {
424
      mysql->reconnect= 1;
425
      if (info)
426
      {
427
	fputs("\n",stderr);
428
	(void) fflush(stderr);
429
      }
430
      return 0;
431
    }
432
433
    if (!wait)
434
    {
435
      if (!option_silent)
436
      {
437
	if (!host)
438
	  host= (char*) LOCAL_HOST;
439
	my_printf_error(0,"connect to server at '%s' failed\nerror: '%s'",
440
			error_flags, host, mysql_error(mysql));
441
	if (mysql_errno(mysql) == CR_CONNECTION_ERROR)
442
	{
443
	  fprintf(stderr,
444
		  "Check that mysqld is running and that the socket: '%s' exists!\n",
445
		  unix_port ? unix_port : mysql_unix_port);
446
	}
447
	else if (mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
448
		 mysql_errno(mysql) == CR_UNKNOWN_HOST)
449
	{
450
	  fprintf(stderr,"Check that mysqld is running on %s",host);
451
	  fprintf(stderr," and that the port is %d.\n",
452
		  tcp_port ? tcp_port: mysql_port);
453
	  fprintf(stderr,"You can check this by doing 'telnet %s %d'\n",
454
		  host, tcp_port ? tcp_port: mysql_port);
455
	}
456
      }
457
      return 1;
458
    }
459
    if (wait != (uint) ~0)
460
      wait--;				/* One less retry */
461
    if ((mysql_errno(mysql) != CR_CONN_HOST_ERROR) &&
462
	(mysql_errno(mysql) != CR_CONNECTION_ERROR))
463
    {
464
      fprintf(stderr,"Got error: %s\n", mysql_error(mysql));
465
      if (!option_force)
466
	return 1;
467
    }
468
    else if (!option_silent)
469
    {
470
      if (!info)
471
      {
472
	info=1;
473
	fputs("Waiting for MySQL server to answer",stderr);
474
	(void) fflush(stderr);
475
      }
476
      else
477
      {
478
	putc('.',stderr);
479
	(void) fflush(stderr);
480
      }
481
    }
482
    sleep(5);
483
  }
484
}
485
486
487
/*
488
  Execute a command.
489
  Return 0 on ok
490
	 -1 on retryable error
491
	 1 on fatal error
492
*/
493
494
static int execute_commands(MYSQL *mysql,int argc, char **argv)
495
{
496
  const char *status;
497
  /*
498
    MySQL documentation relies on the fact that mysqladmin will
499
    execute commands in the order specified, e.g.
500
    mysqladmin -u root flush-privileges password "newpassword"
501
    to reset a lost root password.
502
    If this behaviour is ever changed, Docs should be notified.
503
  */
504
505
  struct rand_struct rand_st;
506
507
  for (; argc > 0 ; argv++,argc--)
508
  {
509
    switch (find_type(argv[0],&command_typelib,2)) {
510
    case ADMIN_CREATE:
511
    {
512
      char buff[FN_REFLEN+20];
513
      if (argc < 2)
514
      {
515
	my_printf_error(0, "Too few arguments to create", error_flags);
516
	return 1;
517
      }
518
      sprintf(buff,"create database `%.*s`",FN_REFLEN,argv[1]);
519
      if (mysql_query(mysql,buff))
520
      {
521
	my_printf_error(0,"CREATE DATABASE failed; error: '%-.200s'",
522
			error_flags, mysql_error(mysql));
523
	return -1;
524
      }
525
      argc--; argv++;
526
      break;
527
    }
528
    case ADMIN_DROP:
529
    {
530
      if (argc < 2)
531
      {
532
	my_printf_error(0, "Too few arguments to drop", error_flags);
533
	return 1;
534
      }
535
      if (drop_db(mysql,argv[1]))
536
	return -1;
537
      argc--; argv++;
538
      break;
539
    }
540
    case ADMIN_SHUTDOWN:
541
    {
542
      char pidfile[FN_REFLEN];
543
      my_bool got_pidfile= 0;
544
      time_t last_modified= 0;
545
      struct stat pidfile_status;
546
547
      /*
548
	Only wait for pidfile on local connections
549
	If pidfile doesn't exist, continue without pid file checking
550
      */
551
      if (mysql->unix_socket && (got_pidfile= !get_pidfile(mysql, pidfile)) &&
552
	  !stat(pidfile, &pidfile_status))
553
	last_modified= pidfile_status.st_mtime;
554
555
      if (mysql_shutdown(mysql, SHUTDOWN_DEFAULT))
556
      {
557
	my_printf_error(0, "shutdown failed; error: '%s'", error_flags,
558
			mysql_error(mysql));
559
	return -1;
560
      }
561
      mysql_close(mysql);	/* Close connection to avoid error messages */
562
      argc=1;                   /* force SHUTDOWN to be the last command    */
563
      if (got_pidfile)
564
      {
565
	if (opt_verbose)
566
	  printf("Shutdown signal sent to server;  Waiting for pid file to disappear\n");
567
568
	/* Wait until pid file is gone */
569
	if (wait_pidfile(pidfile, last_modified, &pidfile_status))
570
	  return -1;
571
      }
572
      break;
573
    }
574
    case ADMIN_FLUSH_PRIVILEGES:
575
    case ADMIN_RELOAD:
576
      if (mysql_query(mysql,"flush privileges"))
577
      {
578
	my_printf_error(0, "reload failed; error: '%s'", error_flags,
579
			mysql_error(mysql));
580
	return -1;
581
      }
582
      break;
583
    case ADMIN_REFRESH:
584
      if (mysql_refresh(mysql,
585
			(uint) ~(REFRESH_GRANT | REFRESH_STATUS |
586
				 REFRESH_READ_LOCK | REFRESH_SLAVE |
587
				 REFRESH_MASTER)))
588
      {
589
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
590
			mysql_error(mysql));
591
	return -1;
592
      }
593
      break;
594
    case ADMIN_FLUSH_THREADS:
595
      if (mysql_refresh(mysql,(uint) REFRESH_THREADS))
596
      {
597
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
598
			mysql_error(mysql));
599
	return -1;
600
      }
601
      break;
602
    case ADMIN_VER:
603
      new_line=1;
604
      print_version();
605
      puts("Copyright (C) 2000-2006 MySQL AB");
606
      puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
607
      printf("Server version\t\t%s\n", mysql_get_server_info(mysql));
608
      printf("Protocol version\t%d\n", mysql_get_proto_info(mysql));
609
      printf("Connection\t\t%s\n",mysql_get_host_info(mysql));
610
      if (mysql->unix_socket)
611
	printf("UNIX socket\t\t%s\n", mysql->unix_socket);
612
      else
613
	printf("TCP port\t\t%d\n", mysql->port);
614
      status=mysql_stat(mysql);
615
      {
616
	char *pos,buff[40];
617
	ulong sec;
618
	pos= (char*) strchr(status,' ');
619
	*pos++=0;
620
	printf("%s\t\t\t",status);			/* print label */
621
	if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec)))
622
	{
623
	  nice_time(sec,buff);
624
	  puts(buff);				/* print nice time */
625
	  while (*status == ' ') status++;	/* to next info */
626
	}
627
      }
628
      putc('\n',stdout);
629
      if (status)
630
	puts(status);
631
      break;
632
    case ADMIN_PROCESSLIST:
633
    {
634
      MYSQL_RES *result;
635
      MYSQL_ROW row;
636
637
      if (mysql_query(mysql, (opt_verbose ? "show full processlist" :
638
			      "show processlist")) ||
639
	  !(result = mysql_store_result(mysql)))
640
      {
641
	my_printf_error(0, "process list failed; error: '%s'", error_flags,
642
			mysql_error(mysql));
643
	return -1;
644
      }
645
      print_header(result);
646
      while ((row=mysql_fetch_row(result)))
647
	print_row(result,row,0);
648
      print_top(result);
649
      mysql_free_result(result);
650
      new_line=1;
651
      break;
652
    }
653
    case ADMIN_STATUS:
654
      status=mysql_stat(mysql);
655
      if (status)
656
	puts(status);
657
      break;
658
    case ADMIN_KILL:
659
      {
660
	uint error=0;
661
	char *pos;
662
	if (argc < 2)
663
	{
664
	  my_printf_error(0, "Too few arguments to 'kill'", error_flags);
665
	  return 1;
666
	}
667
	pos=argv[1];
668
	for (;;)
669
	{
670
	  if (mysql_kill(mysql,(ulong) atol(pos)))
671
	  {
672
	    my_printf_error(0, "kill failed on %ld; error: '%s'", error_flags,
673
			    atol(pos), mysql_error(mysql));
674
	    error=1;
675
	  }
676
	  if (!(pos=strchr(pos,',')))
677
	    break;
678
	  pos++;
679
	}
680
	argc--; argv++;
681
	if (error)
682
	  return -1;
683
	break;
684
      }
685
    case ADMIN_DEBUG:
686
      if (mysql_dump_debug_info(mysql))
687
      {
688
	my_printf_error(0, "debug failed; error: '%s'", error_flags,
689
			mysql_error(mysql));
690
	return -1;
691
      }
692
      break;
693
    case ADMIN_VARIABLES:
694
    {
695
      MYSQL_RES *res;
696
      MYSQL_ROW row;
697
698
      new_line=1;
699
      if (mysql_query(mysql,"show /*!40003 GLOBAL */ variables") ||
700
	  !(res=mysql_store_result(mysql)))
701
      {
702
	my_printf_error(0, "unable to show variables; error: '%s'", error_flags,
703
			mysql_error(mysql));
704
	return -1;
705
      }
706
      print_header(res);
707
      while ((row=mysql_fetch_row(res)))
708
	print_row(res,row,0);
709
      print_top(res);
710
      mysql_free_result(res);
711
      break;
712
    }
713
    case ADMIN_EXTENDED_STATUS:
714
    {
715
      MYSQL_RES *res;
716
      MYSQL_ROW row;
717
      uint rownr = 0;
718
      void (*func) (MYSQL_RES*, MYSQL_ROW, uint);
719
720
      new_line = 1;
721
      if (mysql_query(mysql, "show /*!50002 GLOBAL */ status") ||
722
	  !(res = mysql_store_result(mysql)))
723
      {
724
	my_printf_error(0, "unable to show status; error: '%s'", error_flags,
725
			mysql_error(mysql));
726
	return -1;
727
      }
728
      if (!opt_vertical)
729
	print_header(res);
730
      else
731
      {
732
	if (!ex_status_printed)
733
	{
734
	  store_values(res);
735
	  truncate_names();   /* Does some printing also */
736
	}
737
	else
738
	{
739
	  print_relative_line();
740
	  print_relative_header();
741
	  print_relative_line();
742
	}
743
      }
744
745
      /*      void (*func) (MYSQL_RES*, MYSQL_ROW, uint); */
746
      if (opt_relative && !opt_vertical)
747
	func = print_relative_row;
748
      else if (opt_vertical)
749
	func = print_relative_row_vert;
750
      else
751
	func = print_row;
752
753
      while ((row = mysql_fetch_row(res)))
754
	(*func)(res, row, rownr++);
755
      if (opt_vertical)
756
      {
757
	if (ex_status_printed)
758
	{
759
	  putchar('\n');
760
	  print_relative_line();
761
	}
762
      }
763
      else
764
	print_top(res);
765
766
      ex_status_printed = 1; /* From now on the output will be relative */
767
      mysql_free_result(res);
768
      break;
769
    }
770
    case ADMIN_FLUSH_LOGS:
771
    {
772
      if (mysql_refresh(mysql,REFRESH_LOG))
773
      {
774
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
775
			mysql_error(mysql));
776
	return -1;
777
      }
778
      break;
779
    }
780
    case ADMIN_FLUSH_HOSTS:
781
    {
782
      if (mysql_query(mysql,"flush hosts"))
783
      {
784
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
785
			mysql_error(mysql));
786
	return -1;
787
      }
788
      break;
789
    }
790
    case ADMIN_FLUSH_TABLES:
791
    {
792
      if (mysql_query(mysql,"flush tables"))
793
      {
794
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
795
			mysql_error(mysql));
796
	return -1;
797
      }
798
      break;
799
    }
800
    case ADMIN_FLUSH_STATUS:
801
    {
802
      if (mysql_query(mysql,"flush status"))
803
      {
804
	my_printf_error(0, "refresh failed; error: '%s'", error_flags,
805
			mysql_error(mysql));
806
	return -1;
807
      }
808
      break;
809
    }
810
    case ADMIN_OLD_PASSWORD:
811
    case ADMIN_PASSWORD:
812
    {
813
      char buff[128],crypted_pw[64];
814
      time_t start_time;
815
      /* Do initialization the same way as we do in mysqld */
816
      start_time=time((time_t*) 0);
817
      randominit(&rand_st,(ulong) start_time,(ulong) start_time/2);
818
819
      if (argc < 2)
820
      {
821
	my_printf_error(0, "Too few arguments to change password", error_flags);
822
	return 1;
823
      }
824
      if (argv[1][0])
825
      {
826
        char *pw= argv[1];
827
        bool old= (find_type(argv[0], &command_typelib, 2) ==
828
                   ADMIN_OLD_PASSWORD);
829
        /*
830
           If we don't already know to use an old-style password, see what
831
           the server is using
832
        */
833
        if (!old)
834
        {
835
          if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'"))
836
          {
837
            my_printf_error(0, "Could not determine old_passwords setting from server; error: '%s'",
838
                	    error_flags, mysql_error(mysql));
839
            return -1;
840
          }
841
          else
842
          {
843
            MYSQL_RES *res= mysql_store_result(mysql);
844
            if (!res)
845
            {
846
              my_printf_error(0,
847
                              "Could not get old_passwords setting from "
848
                              "server; error: '%s'",
849
        		      error_flags, mysql_error(mysql));
850
              return -1;
851
            }
852
            if (!mysql_num_rows(res))
853
              old= 1;
854
            else
855
            {
856
              MYSQL_ROW row= mysql_fetch_row(res);
857
              old= !strncmp(row[1], "ON", 2);
858
            }
859
            mysql_free_result(res);
860
          }
861
        }
862
        if (old)
863
          make_scrambled_password_323(crypted_pw, pw);
864
        else
865
          make_scrambled_password(crypted_pw, pw);
866
      }
867
      else
868
	crypted_pw[0]=0;			/* No password */
869
      sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
870
871
      if (mysql_query(mysql,"set sql_log_off=1"))
872
      {
873
	my_printf_error(0, "Can't turn off logging; error: '%s'",
874
			error_flags, mysql_error(mysql));
875
	return -1;
876
      }
877
      if (mysql_query(mysql,buff))
878
      {
879
	if (mysql_errno(mysql)!=1290)
880
	{
881
	  my_printf_error(0,"unable to change password; error: '%s'",
882
			  error_flags, mysql_error(mysql));
883
	  return -1;
884
	}
885
	else
886
	{
887
	  /*
888
	    We don't try to execute 'update mysql.user set..'
889
	    because we can't perfectly find out the host
890
	   */
891
	  my_printf_error(0,"\n"
892
			  "You cannot use 'password' command as mysqld runs\n"
893
			  " with grant tables disabled (was started with"
894
			  " --skip-grant-tables).\n"
895
			  "Use: \"mysqladmin flush-privileges password '*'\""
896
			  " instead", error_flags);
897
	  return -1;
898
	}
899
      }
900
      argc--; argv++;
901
      break;
902
    }
903
904
    case ADMIN_START_SLAVE:
905
      if (mysql_query(mysql, "START SLAVE"))
906
      {
907
	my_printf_error(0, "Error starting slave: %s", error_flags,
908
			mysql_error(mysql));
909
	return -1;
910
      }
911
      else
912
	puts("Slave started");
913
      break;
914
    case ADMIN_STOP_SLAVE:
915
      if (mysql_query(mysql, "STOP SLAVE"))
916
      {
917
	  my_printf_error(0, "Error stopping slave: %s", error_flags,
918
			  mysql_error(mysql));
919
	  return -1;
920
      }
921
      else
922
	puts("Slave stopped");
923
      break;
924
925
    case ADMIN_PING:
926
      mysql->reconnect=0;	/* We want to know of reconnects */
927
      if (!mysql_ping(mysql))
928
      {
929
	if (option_silent < 2)
930
	  puts("mysqld is alive");
931
      }
932
      else
933
      {
934
	if (mysql_errno(mysql) == CR_SERVER_GONE_ERROR)
935
	{
936
	  mysql->reconnect=1;
937
	  if (!mysql_ping(mysql))
938
	    puts("connection was down, but mysqld is now alive");
939
	}
940
	else
941
	{
942
	  my_printf_error(0,"mysqld doesn't answer to ping, error: '%s'",
943
			  error_flags, mysql_error(mysql));
944
	  return -1;
945
	}
946
      }
947
      mysql->reconnect=1;	/* Automatic reconnect is default */
948
      break;
949
#ifdef LATER_HAVE_NDBCLUSTER_DB
950
    case ADMIN_NDB_MGM:
951
    {
952
      if (argc < 2)
953
      {
954
	my_printf_error(0, "Too few arguments to ndb-mgm", error_flags);
955
	return 1;
956
      }
957
      {
958
        Ndb_mgmclient_handle cmd=
959
	  ndb_mgmclient_handle_create(opt_ndb_connectstring);
960
        ndb_mgmclient_execute(cmd, --argc, ++argv);
961
	ndb_mgmclient_handle_destroy(cmd);
962
      }
963
      argc= 0;
964
    }
965
    break;
966
#endif
967
    default:
968
      my_printf_error(0, "Unknown command: '%-.60s'", error_flags, argv[0]);
969
      return 1;
970
    }
971
  }
972
  return 0;
973
}
974
975
#include <help_start.h>
976
977
static void print_version(void)
978
{
979
  printf("%s  Ver %s Distrib %s, for %s on %s\n",my_progname,ADMIN_VERSION,
980
	 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
981
}
982
983
984
static void usage(void)
985
{
986
  print_version();
987
  puts("Copyright (C) 2000-2006 MySQL AB");
988
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
989
  puts("Administration program for the mysqld daemon.");
990
  printf("Usage: %s [OPTIONS] command command....\n", my_progname);
991
  my_print_help(my_long_options);
992
  my_print_variables(my_long_options);
993
  print_defaults("my",load_default_groups);
994
  puts("\nWhere command is a one or more of: (Commands may be shortened)\n\
995
  create databasename	Create a new database\n\
996
  debug			Instruct server to write debug information to log\n\
997
  drop databasename	Delete a database and all its tables\n\
998
  extended-status       Gives an extended status message from the server\n\
999
  flush-hosts           Flush all cached hosts\n\
1000
  flush-logs            Flush all logs\n\
1001
  flush-status		Clear status variables\n\
1002
  flush-tables          Flush all tables\n\
1003
  flush-threads         Flush the thread cache\n\
1004
  flush-privileges      Reload grant tables (same as reload)\n\
1005
  kill id,id,...	Kill mysql threads");
1006
#if MYSQL_VERSION_ID >= 32200
1007
  puts("\
1008
  password new-password Change old password to new-password, MySQL 4.1 hashing.\n\
1009
  old-password new-password Change old password to new-password in old format.\n");
1010
#endif
1011
  puts("\
1012
  ping			Check if mysqld is alive\n\
1013
  processlist		Show list of active threads in server\n\
1014
  reload		Reload grant tables\n\
1015
  refresh		Flush all tables and close and open logfiles\n\
1016
  shutdown		Take server down\n\
1017
  status		Gives a short status message from the server\n\
1018
  start-slave		Start slave\n\
1019
  stop-slave		Stop slave\n\
1020
  variables             Prints variables available\n\
1021
  version		Get version info from server");
1022
}
1023
1024
#include <help_end.h>
1025
1026
static int drop_db(MYSQL *mysql, const char *db)
1027
{
1028
  char name_buff[FN_REFLEN+20], buf[10];
1029
  if (!option_force)
1030
  {
1031
    puts("Dropping the database is potentially a very bad thing to do.");
1032
    puts("Any data stored in the database will be destroyed.\n");
1033
    printf("Do you really want to drop the '%s' database [y/N] ",db);
1034
    fflush(stdout);
1035
    VOID(fgets(buf,sizeof(buf)-1,stdin));
1036
    if ((*buf != 'y') && (*buf != 'Y'))
1037
    {
1038
      puts("\nOK, aborting database drop!");
1039
      return -1;
1040
    }
1041
  }
1042
  sprintf(name_buff,"drop database `%.*s`",FN_REFLEN,db);
1043
  if (mysql_query(mysql,name_buff))
1044
  {
1045
    my_printf_error(0, "DROP DATABASE %s failed;\nerror: '%s'", error_flags,
1046
		    db,mysql_error(mysql));
1047
    return 1;
1048
  }
1049
  printf("Database \"%s\" dropped\n",db);
1050
  return 0;
1051
}
1052
1053
1054
static void nice_time(ulong sec,char *buff)
1055
{
1056
  ulong tmp;
1057
1058
  if (sec >= 3600L*24)
1059
  {
1060
    tmp=sec/(3600L*24);
1061
    sec-=3600L*24*tmp;
1062
    buff=int10_to_str(tmp, buff, 10);
1063
    buff=strmov(buff,tmp > 1 ? " days " : " day ");
1064
  }
1065
  if (sec >= 3600L)
1066
  {
1067
    tmp=sec/3600L;
1068
    sec-=3600L*tmp;
1069
    buff=int10_to_str(tmp, buff, 10);
1070
    buff=strmov(buff,tmp > 1 ? " hours " : " hour ");
1071
  }
1072
  if (sec >= 60)
1073
  {
1074
    tmp=sec/60;
1075
    sec-=60*tmp;
1076
    buff=int10_to_str(tmp, buff, 10);
1077
    buff=strmov(buff," min ");
1078
  }
1079
  strmov(int10_to_str(sec, buff, 10)," sec");
1080
}
1081
1082
1083
static void print_header(MYSQL_RES *result)
1084
{
1085
  MYSQL_FIELD *field;
1086
1087
  print_top(result);
1088
  mysql_field_seek(result,0);
1089
  putchar('|');
1090
  while ((field = mysql_fetch_field(result)))
1091
  {
1092
    printf(" %-*s|",(int) field->max_length+1,field->name);
1093
  }
1094
  putchar('\n');
1095
  print_top(result);
1096
}
1097
1098
1099
static void print_top(MYSQL_RES *result)
1100
{
1101
  uint i,length;
1102
  MYSQL_FIELD *field;
1103
1104
  putchar('+');
1105
  mysql_field_seek(result,0);
1106
  while((field = mysql_fetch_field(result)))
1107
  {
1108
    if ((length=(uint) strlen(field->name)) > field->max_length)
1109
      field->max_length=length;
1110
    else
1111
      length=field->max_length;
1112
    for (i=length+2 ; i--> 0 ; )
1113
      putchar('-');
1114
    putchar('+');
1115
  }
1116
  putchar('\n');
1117
}
1118
1119
1120
/* 3.rd argument, uint row, is not in use. Don't remove! */
1121
static void print_row(MYSQL_RES *result, MYSQL_ROW cur,
1122
		      uint row __attribute__((unused)))
1123
{
1124
  uint i,length;
1125
  MYSQL_FIELD *field;
1126
1127
  putchar('|');
1128
  mysql_field_seek(result,0);
1129
  for (i=0 ; i < mysql_num_fields(result); i++)
1130
  {
1131
    field = mysql_fetch_field(result);
1132
    length=field->max_length;
1133
    printf(" %-*s|",length+1,cur[i] ? (char*) cur[i] : "");
1134
  }
1135
  putchar('\n');
1136
}
1137
1138
1139
static void print_relative_row(MYSQL_RES *result, MYSQL_ROW cur, uint row)
1140
{
1141
  ulonglong tmp;
1142
  char buff[22];
1143
  MYSQL_FIELD *field;
1144
1145
  mysql_field_seek(result, 0);
1146
  field = mysql_fetch_field(result);
1147
  printf("| %-*s|", (int) field->max_length + 1, cur[0]);
1148
1149
  field = mysql_fetch_field(result);
1150
  tmp = cur[1] ? strtoull(cur[1], NULL, 10) : (ulonglong) 0;
1151
  printf(" %-*s|\n", (int) field->max_length + 1,
1152
	 llstr((tmp - last_values[row]), buff));
1153
  last_values[row] = tmp;
1154
}
1155
1156
1157
static void print_relative_row_vert(MYSQL_RES *result __attribute__((unused)),
1158
				    MYSQL_ROW cur,
1159
				    uint row __attribute__((unused)))
1160
{
1161
  uint length;
1162
  ulonglong tmp;
1163
  char buff[22];
1164
1165
  if (!row)
1166
    putchar('|');
1167
1168
  tmp = cur[1] ? strtoull(cur[1], NULL, 10) : (ulonglong) 0;
1169
  printf(" %-*s|", ex_val_max_len[row] + 1,
1170
	 llstr((tmp - last_values[row]), buff));
1171
1172
  /* Find the minimum row length needed to output the relative value */
1173
  if ((length=(uint) strlen(buff) > ex_val_max_len[row]) && ex_status_printed)
1174
    ex_val_max_len[row] = length;
1175
  last_values[row] = tmp;
1176
}
1177
1178
1179
static void store_values(MYSQL_RES *result)
1180
{
1181
  uint i;
1182
  MYSQL_ROW row;
1183
  MYSQL_FIELD *field;
1184
1185
  field = mysql_fetch_field(result);
1186
  max_var_length = field->max_length;
1187
  field = mysql_fetch_field(result);
1188
  max_val_length = field->max_length;
1189
1190
  for (i = 0; (row = mysql_fetch_row(result)); i++)
1191
  {
1192
    strmov(ex_var_names[i], row[0]);
1193
    last_values[i]=strtoull(row[1],NULL,10);
1194
    ex_val_max_len[i]=2;		/* Default print width for values */
1195
  }
1196
  ex_var_count = i;
1197
  return;
1198
}
1199
1200
1201
static void print_relative_header()
1202
{
1203
  uint i;
1204
1205
  putchar('|');
1206
  for (i = 0; i < ex_var_count; i++)
1207
    printf(" %-*s|", ex_val_max_len[i] + 1, truncated_var_names[i]);
1208
  putchar('\n');
1209
}
1210
1211
1212
static void print_relative_line()
1213
{
1214
  uint i;
1215
1216
  putchar('+');
1217
  for (i = 0; i < ex_var_count; i++)
1218
  {
1219
    uint j;
1220
    for (j = 0; j < ex_val_max_len[i] + 2; j++)
1221
      putchar('-');
1222
    putchar('+');
1223
  }
1224
  putchar('\n');
1225
}
1226
1227
1228
static void truncate_names()
1229
{
1230
  uint i;
1231
  char *ptr,top_line[MAX_TRUNC_LENGTH+4+NAME_LEN+22+1],buff[22];
1232
1233
  ptr=top_line;
1234
  *ptr++='+';
1235
  ptr=strfill(ptr,max_var_length+2,'-');
1236
  *ptr++='+';
1237
  ptr=strfill(ptr,MAX_TRUNC_LENGTH+2,'-');
1238
  *ptr++='+';
1239
  ptr=strfill(ptr,max_val_length+2,'-');
1240
  *ptr++='+';
1241
  *ptr=0;
1242
  puts(top_line);
1243
1244
  for (i = 0 ; i < ex_var_count; i++)
1245
  {
1246
    uint sfx=1,j;
1247
    printf("| %-*s|", max_var_length + 1, ex_var_names[i]);
1248
    ptr = ex_var_names[i];
1249
    /* Make sure no two same truncated names will become */
1250
    for (j = 0; j < i; j++)
1251
      if (*truncated_var_names[j] == *ptr)
1252
	sfx++;
1253
1254
    truncated_var_names[i][0]= *ptr;		/* Copy first var char */
1255
    int10_to_str(sfx, truncated_var_names[i]+1,10);
1256
    printf(" %-*s|", MAX_TRUNC_LENGTH + 1, truncated_var_names[i]);
1257
    printf(" %-*s|\n", max_val_length + 1, llstr(last_values[i],buff));
1258
  }
1259
  puts(top_line);
1260
  return;
1261
}
1262
1263
1264
static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
1265
{
1266
  MYSQL_RES* result;
1267
1268
  if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'"))
1269
  {
1270
    my_printf_error(0, "query failed; error: '%s'", error_flags,
1271
		    mysql_error(mysql));
1272
  }
1273
  result = mysql_store_result(mysql);
1274
  if (result)
1275
  {
1276
    MYSQL_ROW row=mysql_fetch_row(result);
1277
    if (row)
1278
      strmov(pidfile, row[1]);
1279
    mysql_free_result(result);
1280
    return row == 0;				/* Error if row = 0 */
1281
  }
1282
  return 1;					/* Error */
1283
}
1284
1285
/*
1286
  Return 1 if pid file didn't disappear or change
1287
*/
1288
1289
static my_bool wait_pidfile(char *pidfile, time_t last_modified,
1290
			    struct stat *pidfile_status)
1291
{
1292
  char buff[FN_REFLEN];
1293
  int error= 1;
1294
  uint count= 0;
1295
  DBUG_ENTER("wait_pidfile");
1296
1297
  system_filename(buff, pidfile);
1298
  do
1299
  {
1300
    int fd;
1301
    if ((fd= my_open(buff, O_RDONLY, MYF(0))) < 0)
1302
    {
1303
      error= 0;
1304
      break;
1305
    }
1306
    (void) my_close(fd,MYF(0));
1307
    if (last_modified && !stat(pidfile, pidfile_status))
1308
    {
1309
      if (last_modified != pidfile_status->st_mtime)
1310
      {
1311
	/* File changed;  Let's assume that mysqld did restart */
1312
	if (opt_verbose)
1313
	  printf("pid file '%s' changed while waiting for it to disappear!\nmysqld did probably restart\n",
1314
		 buff);
1315
	error= 0;
1316
	break;
1317
      }
1318
    }
1319
    if (count++ == opt_shutdown_timeout)
1320
      break;
1321
    sleep(1);
1322
  } while (!interrupted);
1323
1324
  if (error)
1325
  {
1326
    DBUG_PRINT("warning",("Pid file didn't disappear"));
1327
    fprintf(stderr,
1328
	    "Warning;  Aborted waiting on pid file: '%s' after %d seconds\n",
1329
	    buff, count-1);
1330
  }
1331
  DBUG_RETURN(error);
1332
}