~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzleadmin.cc

pandora-build v0.100 - Fixes several bugs found by cb1kenobi. Add several thoughts from folks at LCA.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2008 Drizzle Open Source Project 
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 drizzle databases */
17
 
 
18
 
#include "client_priv.h"
19
 
#include <signal.h>
20
 
#include <mysys/my_pthread.h>                           /* because of signal()  */
21
 
#include <sys/stat.h>
22
 
 
23
 
/* Added this for string translation. */
24
 
#include <libdrizzle/gettext.h>
25
 
 
26
 
#define ADMIN_VERSION "8.42"
27
 
#define SHUTDOWN_DEF_TIMEOUT 3600               /* Wait for shutdown */
28
 
 
29
 
char *host= NULL, *user= NULL, *opt_password= NULL;
30
 
static bool interrupted= false, opt_verbose= false,tty_password= false; 
31
 
static uint8_t opt_protocol= DRIZZLE_PROTOCOL_TCP;  
32
 
static uint32_t tcp_port= 0, option_wait= 0, option_silent= 0;
33
 
static uint32_t my_end_arg;
34
 
static uint32_t opt_connect_timeout, opt_shutdown_timeout;
35
 
static myf error_flags; /* flags to pass to my_printf_error, like ME_BELL */
36
 
 
37
 
/*
38
 
  Forward declarations 
39
 
*/
40
 
static void usage(void);
41
 
static void print_version(void);
42
 
extern "C" sig_handler endprog(int signal_number);
43
 
extern "C" bool get_one_option(int optid, const struct my_option *opt,
44
 
                               char *argument);
45
 
static int execute_commands(DRIZZLE *drizzle,int argc, char **argv);
46
 
static bool sql_connect(DRIZZLE *drizzle, uint wait);
47
 
 
48
 
/*
49
 
  The order of commands must be the same as command_names,
50
 
  except ADMIN_ERROR
51
 
*/
52
 
enum commands {
53
 
  ADMIN_ERROR,
54
 
  ADMIN_SHUTDOWN,
55
 
  ADMIN_PING
56
 
};
57
 
 
58
 
static const char *command_names[]= {
59
 
  "shutdown",
60
 
  "ping",
61
 
  NullS
62
 
};
63
 
 
64
 
static TYPELIB command_typelib=
65
 
{ array_elements(command_names)-1,"commands", command_names, NULL };
66
 
 
67
 
static struct my_option my_long_options[] =
68
 
{
69
 
  {"help", '?', N_("Display this help and exit."), 0, 0, 0, GET_NO_ARG,
70
 
   NO_ARG, 0, 0, 0, 0, 0, 0},
71
 
  {"host", 'h', N_("Connect to host."), (char**) &host, (char**) &host, 0, GET_STR,
72
 
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
73
 
  {"password", 'p',
74
 
   N_("Password to use when connecting to server. If password is not given it's asked from the tty."),
75
 
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
76
 
  {"port", 'P', N_("Port number to use for connection or 0 for default to, in "
77
 
   "order of preference, my.cnf, $DRIZZLE_TCP_PORT, "
78
 
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ")."),
79
 
   (char**) &tcp_port,
80
 
   (char**) &tcp_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
81
 
  {"silent", 's', N_("Silently exit if one can't connect to server."),
82
 
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
83
 
#ifndef DONT_ALLOW_USER_CHANGE
84
 
  {"user", 'u', N_("User for login if not current user."), (char**) &user,
85
 
   (char**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
86
 
#endif
87
 
  {"verbose", 'v', N_("Write more information."), (char**) &opt_verbose,
88
 
   (char**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
89
 
  {"version", 'V', N_("Output version information and exit."), 0, 0, 0, GET_NO_ARG,
90
 
   NO_ARG, 0, 0, 0, 0, 0, 0},
91
 
  {"wait", 'w', N_("Wait and retry if connection is down."), 0, 0, 0, GET_UINT,
92
 
   OPT_ARG, 0, 0, 0, 0, 0, 0},
93
 
  {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (char**) &opt_connect_timeout,
94
 
   (char**) &opt_connect_timeout, 0, GET_ULONG, REQUIRED_ARG, 3600*12, 0,
95
 
   3600*12, 0, 1, 0},
96
 
  {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (char**) &opt_shutdown_timeout,
97
 
   (char**) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG,
98
 
   SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0},
99
 
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
100
 
};
101
 
 
102
 
 
103
 
static const char *load_default_groups[]= { "drizzleadmin","client",0 };
104
 
 
105
 
bool
106
 
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
107
 
               char *argument)
108
 
{
109
 
  int error = 0;
110
 
 
111
 
  switch(optid) {
112
 
  case 'p':
113
 
    if (argument)
114
 
    {
115
 
      char *start=argument;
116
 
      my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
117
 
      opt_password= my_strdup(argument,MYF(MY_FAE));
118
 
      while (*argument) *argument++= 'x';   /* Destroy argument */
119
 
      if (*start)
120
 
        start[1]=0; /* Cut length of argument */
121
 
      tty_password= 0;
122
 
    }
123
 
    else 
124
 
      tty_password= 1; 
125
 
    break;
126
 
  case 's':
127
 
    option_silent++;
128
 
    break;
129
 
  case 'V':
130
 
    print_version();
131
 
    exit(0);
132
 
    break;
133
 
  case 'w':
134
 
    if (argument)
135
 
    {
136
 
      if ((option_wait=atoi(argument)) <= 0)
137
 
        option_wait=1;
138
 
    }
139
 
    else
140
 
      option_wait= ~(uint)0;
141
 
    break;
142
 
  case '?':
143
 
  case 'I':                                     /* Info */
144
 
    error++;
145
 
    break;
146
 
  }
147
 
 
148
 
  if (error)
149
 
  {
150
 
    usage();
151
 
    exit(1);
152
 
  }
153
 
  return 0;
154
 
}
155
 
 
156
 
int main(int argc,char *argv[])
157
 
{
158
 
  int error= 0, ho_error;
159
 
  DRIZZLE drizzle;
160
 
  char **commands, **save_argv;
161
 
 
162
 
  MY_INIT(argv[0]);
163
 
  drizzle_create(&drizzle);
164
 
  load_defaults("my",load_default_groups,&argc,&argv);
165
 
  save_argv = argv;                             /* Save for free_defaults */
166
 
  if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
167
 
  {
168
 
    free_defaults(save_argv);
169
 
    exit(ho_error);
170
 
  }
171
 
 
172
 
  if (argc == 0)
173
 
  {
174
 
    usage();
175
 
    exit(1);
176
 
  }
177
 
 
178
 
  commands = argv;
179
 
  if (tty_password)
180
 
    opt_password = get_tty_password(NullS);
181
 
 
182
 
  VOID(signal(SIGINT,endprog));                 /* Here if abort */
183
 
  VOID(signal(SIGTERM,endprog));                /* Here if abort */
184
 
 
185
 
  if (opt_connect_timeout)
186
 
  {
187
 
    uint tmp=opt_connect_timeout;
188
 
    drizzle_options(&drizzle,DRIZZLE_OPT_CONNECT_TIMEOUT, (char*) &tmp);
189
 
  }
190
 
  /* force drizzleadmin to use TCP */
191
 
  drizzle_options(&drizzle, DRIZZLE_OPT_PROTOCOL, (char*)&opt_protocol);
192
 
 
193
 
  error_flags= (myf)0;
194
 
 
195
 
  if (sql_connect(&drizzle, option_wait))
196
 
  {
197
 
    unsigned int err= drizzle_errno(&drizzle);
198
 
    if (err >= CR_MIN_ERROR && err <= CR_MAX_ERROR)
199
 
      error= 1;
200
 
    else
201
 
    {
202
 
      /* Return 0 if all commands are PING */
203
 
      for (; argc > 0; argv++, argc--)
204
 
      {
205
 
        if (find_type(argv[0], &command_typelib, 2) != ADMIN_PING)
206
 
        {
207
 
          error= 1;
208
 
          break;
209
 
        }
210
 
      }
211
 
    }
212
 
  }
213
 
  else
214
 
  {
215
 
    error=execute_commands(&drizzle,argc,commands);
216
 
    drizzle_close(&drizzle);
217
 
  }
218
 
  my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR));
219
 
  my_free(user,MYF(MY_ALLOW_ZERO_PTR));
220
 
  free_defaults(save_argv);
221
 
  my_end(my_end_arg);
222
 
  exit(error ? 1 : 0);
223
 
}
224
 
 
225
 
sig_handler endprog(int signal_number __attribute__((unused)))
226
 
{
227
 
  interrupted=1;
228
 
}
229
 
 
230
 
static bool sql_connect(DRIZZLE *drizzle, uint wait)
231
 
{
232
 
  bool info=0;
233
 
 
234
 
  for (;;)
235
 
  {
236
 
    if (drizzle_connect(drizzle,host,user,opt_password,NullS,tcp_port,NULL,0))
237
 
    {
238
 
      drizzle->reconnect= 1;
239
 
      if (info)
240
 
      {
241
 
        fputs("\n",stderr);
242
 
        (void) fflush(stderr);
243
 
      }
244
 
      return 0;
245
 
    }
246
 
 
247
 
    if (!wait)
248
 
    {
249
 
      if (!option_silent)
250
 
      {
251
 
        if (!host)
252
 
          host= (char*) LOCAL_HOST;
253
 
 
254
 
        my_printf_error(0,_("connect to server at '%s' failed\nerror: '%s'"),
255
 
        error_flags, host, drizzle_error(drizzle));
256
 
 
257
 
        if (drizzle_errno(drizzle) == CR_CONN_HOST_ERROR ||
258
 
          drizzle_errno(drizzle) == CR_UNKNOWN_HOST)
259
 
        {
260
 
          fprintf(stderr,_("Check that drizzled is running on %s"),host);
261
 
          fprintf(stderr,_(" and that the port is %d.\n"),
262
 
          tcp_port ? tcp_port: drizzle_port);
263
 
          fprintf(stderr,_("You can check this by doing 'telnet %s %d'\n"),
264
 
                  host, tcp_port ? tcp_port: drizzle_port);
265
 
        }
266
 
      }
267
 
      return 1;
268
 
    }
269
 
    if (wait != (uint) ~0)
270
 
      wait--;                           /* One less retry */
271
 
    if ((drizzle_errno(drizzle) != CR_CONN_HOST_ERROR) &&
272
 
        (drizzle_errno(drizzle) != CR_CONNECTION_ERROR))
273
 
    {
274
 
      fprintf(stderr,_("Got error: %s\n"), drizzle_error(drizzle));
275
 
    }
276
 
    else if (!option_silent)
277
 
    {
278
 
      if (!info)
279
 
      {
280
 
        info=1;
281
 
        fputs(_("Waiting for Drizzle server to answer"),stderr);
282
 
        (void) fflush(stderr);
283
 
      }
284
 
      else
285
 
      {
286
 
        putc('.',stderr);
287
 
        (void) fflush(stderr);
288
 
      }
289
 
    }
290
 
    sleep(5);
291
 
  }
292
 
}
293
 
 
294
 
/*
295
 
  Execute a command.
296
 
  Return 0 on ok
297
 
         -1 on retryable error
298
 
         1 on fatal error
299
 
*/
300
 
static int execute_commands(DRIZZLE *drizzle,int argc, char **argv)
301
 
{
302
 
 
303
 
  /*
304
 
    DRIZZLE documentation relies on the fact that drizzleadmin will
305
 
    execute commands in the order specified.
306
 
    If this behaviour is ever changed, Docs should be notified.
307
 
  */
308
 
  for (; argc > 0 ; argv++,argc--)
309
 
  {
310
 
    switch (find_type(argv[0],&command_typelib,2)) {
311
 
    case ADMIN_SHUTDOWN:
312
 
    {
313
 
      if (opt_verbose)
314
 
        printf(_("shutting down drizzled...\n"));
315
 
 
316
 
      if (drizzle_shutdown(drizzle, SHUTDOWN_DEFAULT))
317
 
      {
318
 
        my_printf_error(0, _("shutdown failed; error: '%s'"), error_flags,
319
 
                        drizzle_error(drizzle));
320
 
        return -1;
321
 
      }
322
 
      drizzle_close(drizzle);   /* Close connection to avoid error messages */
323
 
 
324
 
      if (opt_verbose)
325
 
        printf(_("done\n"));
326
 
 
327
 
      argc=1;             /* Force SHUTDOWN to be the last command */
328
 
      break;
329
 
    }
330
 
    case ADMIN_PING:
331
 
      drizzle->reconnect=0;     /* We want to know of reconnects */
332
 
      if (!drizzle_ping(drizzle))
333
 
      {
334
 
        if (option_silent < 2)
335
 
          puts(_("drizzled is alive"));
336
 
      }
337
 
      else
338
 
      {
339
 
        if (drizzle_errno(drizzle) == CR_SERVER_GONE_ERROR)
340
 
        {
341
 
          drizzle->reconnect=1;
342
 
          if (!drizzle_ping(drizzle))
343
 
            puts(_("connection was down, but drizzled is now alive"));
344
 
        }
345
 
        else
346
 
              {
347
 
          my_printf_error(0,_("drizzled doesn't answer to ping, error: '%s'"),
348
 
          error_flags, drizzle_error(drizzle));
349
 
          return -1;
350
 
        }
351
 
      }
352
 
      drizzle->reconnect=1;     /* Automatic reconnect is default */
353
 
      break;
354
 
 
355
 
    default:
356
 
      my_printf_error(0, _("Unknown command: '%-.60s'"), error_flags, argv[0]);
357
 
      return 1;
358
 
    }
359
 
  }
360
 
  return 0;
361
 
}
362
 
 
363
 
static void print_version(void)
364
 
{
365
 
  printf(_("%s  Ver %s Distrib %s, for %s on %s\n"),my_progname,ADMIN_VERSION,
366
 
         drizzle_get_client_info(),SYSTEM_TYPE,MACHINE_TYPE);
367
 
}
368
 
 
369
 
static void usage(void)
370
 
{
371
 
  print_version();
372
 
  puts(_("Copyright (C) 2000-2008 MySQL AB"));
373
 
  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"));
374
 
  puts(_("Administration program for the drizzled daemon."));
375
 
  printf(_("Usage: %s [OPTIONS] command command....\n"), my_progname);
376
 
  my_print_help(my_long_options);
377
 
  puts(_("\
378
 
  ping         Check if server is down\n\
379
 
  shutdown     Take server down\n"));
380
 
}