~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzleadmin.cc

Removed dependency for hex convert, fixed a few Protocol class issues for Solaris.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 MySQL
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 */
 
20
 
 
21
/* maintaince of drizzle databases */
 
22
 
 
23
#include "client_priv.h"
 
24
#include <signal.h>
 
25
#include <mysys/my_pthread.h>                           /* because of signal()  */
 
26
#include <sys/stat.h>
 
27
#include <vector>
 
28
#include <algorithm>
 
29
#include <string>
 
30
 
 
31
/* Added this for string translation. */
 
32
#include <drizzled/gettext.h>
 
33
 
 
34
#define ADMIN_VERSION "8.42"
 
35
#define SHUTDOWN_DEF_TIMEOUT 3600               /* Wait for shutdown */
 
36
#define NUM_COMMAND_NAMES 2
 
37
 
 
38
char *host= NULL, *user= NULL, *opt_password= NULL;
 
39
static bool interrupted= false, opt_verbose= false,tty_password= false;
 
40
static uint32_t tcp_port= 0, option_wait= 0, option_silent= 0;
 
41
static uint32_t my_end_arg;
 
42
static uint32_t opt_connect_timeout, opt_shutdown_timeout;
 
43
 
 
44
using namespace std;
 
45
 
 
46
/*
 
47
  Forward declarations
 
48
*/
 
49
static void usage(void);
 
50
static void print_version(void);
 
51
extern "C" void endprog(int signal_number);
 
52
extern "C" bool get_one_option(int optid, const struct my_option *opt,
 
53
                               char *argument);
 
54
static int execute_commands(drizzle_con_st *con,int argc, char **argv);
 
55
static bool sql_connect(drizzle_con_st *con, uint32_t wait);
 
56
 
 
57
/*
 
58
  The order of commands must be the same as command_names,
 
59
  except ADMIN_ERROR
 
60
*/
 
61
enum commands {
 
62
  ADMIN_ERROR,
 
63
  ADMIN_SHUTDOWN,
 
64
  ADMIN_PING
 
65
};
 
66
 
 
67
static string command_names[]= {
 
68
  "shutdown",
 
69
  "ping"
 
70
};
 
71
 
 
72
static vector<string> 
 
73
  command_vector(command_names, command_names + NUM_COMMAND_NAMES);
 
74
 
 
75
static struct my_option my_long_options[] =
 
76
{
 
77
  {"help", '?', N_("Display this help and exit."), 0, 0, 0, GET_NO_ARG,
 
78
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
79
  {"host", 'h', N_("Connect to host."), (char**) &host, (char**) &host, 0, GET_STR,
 
80
   REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
81
  {"password", 'P',
 
82
   N_("Password to use when connecting to server. If password is not given it's asked from the tty."),
 
83
   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
 
84
  {"port", 'p', N_("Port number to use for connection or 0 for default to, in "
 
85
   "order of preference, drizzle.cnf, $DRIZZLE_TCP_PORT, "
 
86
   "built-in default (" STRINGIFY_ARG(DRIZZLE_PORT) ")."),
 
87
   0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
88
  {"silent", 's', N_("Silently exit if one can't connect to server."),
 
89
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
 
90
#ifndef DONT_ALLOW_USER_CHANGE
 
91
  {"user", 'u', N_("User for login if not current user."), (char**) &user,
 
92
   (char**) &user, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
 
93
#endif
 
94
  {"verbose", 'v', N_("Write more information."), (char**) &opt_verbose,
 
95
   (char**) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
 
96
  {"version", 'V', N_("Output version information and exit."), 0, 0, 0, GET_NO_ARG,
 
97
   NO_ARG, 0, 0, 0, 0, 0, 0},
 
98
  {"wait", 'w', N_("Wait and retry if connection is down."), 0, 0, 0, GET_UINT,
 
99
   OPT_ARG, 0, 0, 0, 0, 0, 0},
 
100
  {"connect_timeout", OPT_CONNECT_TIMEOUT, "", (char**) &opt_connect_timeout,
 
101
   (char**) &opt_connect_timeout, 0, GET_UINT32, REQUIRED_ARG, 3600*12, 0,
 
102
   3600*12, 0, 1, 0},
 
103
  {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (char**) &opt_shutdown_timeout,
 
104
   (char**) &opt_shutdown_timeout, 0, GET_UINT32, REQUIRED_ARG,
 
105
   SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0},
 
106
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 
107
};
 
108
 
 
109
 
 
110
static const char *load_default_groups[]= { "drizzleadmin","client",0 };
 
111
 
 
112
inline string lower_string(const char * from_string)
 
113
{
 
114
  string to_string= from_string;
 
115
  transform(to_string.begin(), to_string.end(),
 
116
            to_string.begin(), ::tolower);
 
117
  return to_string;
 
118
}
 
119
 
 
120
/*
 
121
 * Searches for the given command and determines
 
122
 * its type.
 
123
 *
 
124
 * Returns the type of the command corresponding
 
125
 * to the commands enum defined in drizzleadmin.cc
 
126
 * If the command is not supported, return ADMIN_ERROR.
 
127
 *
 
128
 * @param command name to search for
 
129
 */
 
130
static int get_command_type(const char *name)
 
131
{
 
132
  int type= ADMIN_ERROR;
 
133
  string comp_string= lower_string(name);
 
134
  vector<string>::iterator it= 
 
135
    std::find(command_vector.begin(), command_vector.end(),
 
136
           comp_string);
 
137
  if (it != command_vector.end())
 
138
  {
 
139
    /* add 1 due to the way the commands ENUM is defined */
 
140
    type= distance(command_vector.begin(), it) + 1;
 
141
  }
 
142
  return type;
 
143
}
 
144
 
 
145
bool
 
146
get_one_option(int optid, const struct my_option *, char *argument)
 
147
{
 
148
  char *endchar= NULL;
 
149
  uint64_t temp_drizzle_port= 0;
 
150
  int error= 0;
 
151
 
 
152
  switch(optid) {
 
153
  case 'p':
 
154
    temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
 
155
    /* if there is an alpha character this is not a valid port */
 
156
    if (strlen(endchar) != 0)
 
157
    {
 
158
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
 
159
      exit(1);
 
160
    }
 
161
    /* If the port number is > 65535 it is not a valid port
 
162
       This also helps with potential data loss casting unsigned long to a
 
163
       uint32_t. */
 
164
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
 
165
    {
 
166
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
167
      exit(1);
 
168
    }
 
169
    else
 
170
    {
 
171
      tcp_port= (uint32_t) temp_drizzle_port;
 
172
    }
 
173
    break;
 
174
  case 'P':
 
175
    if (argument)
 
176
    {
 
177
      char *start= argument;
 
178
      if (opt_password)
 
179
        free(opt_password);
 
180
 
 
181
      opt_password= strdup(argument);
 
182
      if (opt_password == NULL)
 
183
      {
 
184
        fprintf(stderr, _("Memory allocation error while copying password. "
 
185
                          "Aborting.\n"));
 
186
        exit(ENOMEM);
 
187
      }
 
188
      while (*argument)
 
189
      {
 
190
        /* Overwriting password with 'x' */
 
191
        *argument++= 'x';
 
192
      }
 
193
      if (*start)
 
194
      {
 
195
        /* Cut length of argument */
 
196
        start[1]= 0;
 
197
      }
 
198
      tty_password= 0;
 
199
    }
 
200
    else
 
201
      tty_password= 1;
 
202
    break;
 
203
  case 's':
 
204
    option_silent++;
 
205
    break;
 
206
  case 'V':
 
207
    print_version();
 
208
    exit(0);
 
209
  case 'w':
 
210
    if (argument)
 
211
    {
 
212
      if ((option_wait=atoi(argument)) <= 0)
 
213
        option_wait= 1;
 
214
    }
 
215
    else
 
216
      option_wait= ~(uint32_t)0;
 
217
    break;
 
218
  case '?':
 
219
  case 'I':                                     /* Info */
 
220
    error++;
 
221
    break;
 
222
  }
 
223
 
 
224
  if (error)
 
225
  {
 
226
    usage();
 
227
    exit(1);
 
228
  }
 
229
  return 0;
 
230
}
 
231
 
 
232
int main(int argc,char *argv[])
 
233
{
 
234
  int error= 0, ho_error;
 
235
  drizzle_st drizzle;
 
236
  drizzle_con_st con;
 
237
  char **commands, **save_argv;
 
238
 
 
239
  MY_INIT(argv[0]);
 
240
  drizzle_create(&drizzle);
 
241
  drizzle_con_create(&drizzle, &con);
 
242
  load_defaults("drizzle",load_default_groups,&argc,&argv);
 
243
  save_argv= argv;                              /* Save for free_defaults */
 
244
  if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
 
245
  {
 
246
    free_defaults(save_argv);
 
247
    exit(ho_error);
 
248
  }
 
249
 
 
250
  if (argc == 0)
 
251
  {
 
252
    usage();
 
253
    exit(1);
 
254
  }
 
255
 
 
256
  commands= argv;
 
257
  if (tty_password)
 
258
    opt_password = client_get_tty_password(NULL);
 
259
 
 
260
  signal(SIGINT,endprog);                       /* Here if abort */
 
261
  signal(SIGTERM,endprog);              /* Here if abort */
 
262
 
 
263
/* XXX
 
264
  if (opt_connect_timeout)
 
265
  {
 
266
    uint32_t tmp= opt_connect_timeout;
 
267
    drizzleclient_options(&drizzle,DRIZZLE_OPT_CONNECT_TIMEOUT, (char*) &tmp);
 
268
  }
 
269
*/
 
270
 
 
271
  if (sql_connect(&con, option_wait))
 
272
  {
 
273
    /* Return 0 if all commands are PING */
 
274
    for (; argc > 0; argv++, argc--)
 
275
    {
 
276
      int type= get_command_type(argv[0]);
 
277
      if (type != ADMIN_PING)
 
278
      {
 
279
        error= 1;
 
280
        break;
 
281
      }
 
282
    }
 
283
  }
 
284
  else
 
285
  {
 
286
    error=execute_commands(&con,argc,commands);
 
287
  }
 
288
  drizzle_con_free(&con);
 
289
  drizzle_free(&drizzle);
 
290
  free(opt_password);
 
291
  free(user);
 
292
  free_defaults(save_argv);
 
293
  my_end(my_end_arg);
 
294
  return error ? 1 : 0;
 
295
}
 
296
 
 
297
void endprog(int)
 
298
{
 
299
  interrupted= 1;
 
300
}
 
301
 
 
302
static bool sql_connect(drizzle_con_st *con, uint32_t wait)
 
303
{
 
304
  bool info= 0;
 
305
  drizzle_return_t ret;
 
306
 
 
307
  drizzle_con_set_tcp(con, host, tcp_port);
 
308
  drizzle_con_set_auth(con, user, opt_password);
 
309
 
 
310
  for (;;)
 
311
  {
 
312
    ret= drizzle_con_connect(con);
 
313
    if (ret == DRIZZLE_RETURN_OK)
 
314
    {
 
315
      if (info)
 
316
      {
 
317
        fputs("\n",stderr);
 
318
        (void) fflush(stderr);
 
319
      }
 
320
      return 0;
 
321
    }
 
322
 
 
323
    if (!wait)
 
324
    {
 
325
      if (!option_silent)
 
326
      {
 
327
        if (!host)
 
328
          host= (char *)DRIZZLE_DEFAULT_TCP_HOST;
 
329
 
 
330
        fprintf(stderr,_("connect to server at '%s' failed\nerror: '%s'"),
 
331
                host, drizzle_con_error(con));
 
332
 
 
333
        if (ret == DRIZZLE_RETURN_GETADDRINFO ||
 
334
            ret == DRIZZLE_RETURN_COULD_NOT_CONNECT)
 
335
        {
 
336
          fprintf(stderr,_("Check that drizzled is running on %s"),host);
 
337
          fprintf(stderr,_(" and that the port is %d.\n"),
 
338
          tcp_port ? tcp_port: DRIZZLE_DEFAULT_TCP_PORT);
 
339
          fprintf(stderr,_("You can check this by doing 'telnet %s %d'\n"),
 
340
                  host, tcp_port ? tcp_port: DRIZZLE_DEFAULT_TCP_PORT);
 
341
        }
 
342
      }
 
343
      return 1;
 
344
    }
 
345
    if (wait != UINT32_MAX)
 
346
      wait--;                           /* One less retry */
 
347
    if (ret != DRIZZLE_RETURN_GETADDRINFO &&
 
348
        ret != DRIZZLE_RETURN_COULD_NOT_CONNECT)
 
349
    {
 
350
      fprintf(stderr,_("Got error: %s\n"), drizzle_con_error(con));
 
351
    }
 
352
    else if (!option_silent)
 
353
    {
 
354
      if (!info)
 
355
      {
 
356
        info= 1;
 
357
        fputs(_("Waiting for Drizzle server to answer"),stderr);
 
358
        (void) fflush(stderr);
 
359
      }
 
360
      else
 
361
      {
 
362
        putc('.',stderr);
 
363
        (void) fflush(stderr);
 
364
      }
 
365
    }
 
366
    sleep(5);
 
367
  }
 
368
}
 
369
 
 
370
/*
 
371
  Execute a command.
 
372
  Return 0 on ok
 
373
         -1 on retryable error
 
374
         1 on fatal error
 
375
*/
 
376
static int execute_commands(drizzle_con_st *con,int argc, char **argv)
 
377
{
 
378
  drizzle_result_st result;
 
379
  drizzle_return_t ret;
 
380
 
 
381
  /*
 
382
    DRIZZLE documentation relies on the fact that drizzleadmin will
 
383
    execute commands in the order specified.
 
384
    If this behaviour is ever changed, Docs should be notified.
 
385
  */
 
386
  for (; argc > 0 ; argv++,argc--)
 
387
  {
 
388
    int type= get_command_type(argv[0]);
 
389
    switch (type) {
 
390
    case ADMIN_SHUTDOWN:
 
391
    {
 
392
      if (opt_verbose)
 
393
        printf(_("shutting down drizzled...\n"));
 
394
 
 
395
      if (drizzle_shutdown(con, &result, DRIZZLE_SHUTDOWN_DEFAULT,
 
396
                           &ret) == NULL ||
 
397
          ret != DRIZZLE_RETURN_OK)
 
398
      {
 
399
        if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
400
        {
 
401
          fprintf(stderr, _("shutdown failed; error: '%s'"),
 
402
                  drizzle_result_error(&result));
 
403
          drizzle_result_free(&result);
 
404
        }
 
405
        else
 
406
        {
 
407
          fprintf(stderr, _("shutdown failed; error: '%s'"),
 
408
                  drizzle_con_error(con));
 
409
        }
 
410
        return -1;
 
411
      }
 
412
 
 
413
      drizzle_result_free(&result);
 
414
      if (opt_verbose)
 
415
        printf(_("done\n"));
 
416
 
 
417
      argc= 1;             /* Force SHUTDOWN to be the last command */
 
418
      break;
 
419
    }
 
420
    case ADMIN_PING:
 
421
      if (drizzle_ping(con, &result, &ret) != NULL && ret == DRIZZLE_RETURN_OK)
 
422
      {
 
423
        if (option_silent < 2)
 
424
          puts(_("drizzled is alive"));
 
425
      }
 
426
      else
 
427
      {
 
428
        if (ret == DRIZZLE_RETURN_SERVER_GONE)
 
429
        {
 
430
          if (drizzle_ping(con, &result, &ret) != NULL &&
 
431
              ret == DRIZZLE_RETURN_OK)
 
432
          {
 
433
            puts(_("connection was down, but drizzled is now alive"));
 
434
          }
 
435
        }
 
436
        else
 
437
        {
 
438
          if (ret == DRIZZLE_RETURN_ERROR_CODE)
 
439
          {
 
440
            fprintf(stderr, _("shutdown failed; error: '%s'"),
 
441
                    drizzle_result_error(&result));
 
442
            drizzle_result_free(&result);
 
443
          }
 
444
          else
 
445
          {
 
446
            fprintf(stderr,_("drizzled doesn't answer to ping, error: '%s'"),
 
447
                    drizzle_con_error(con));
 
448
          }
 
449
          return -1;
 
450
        }
 
451
      }
 
452
      drizzle_result_free(&result);
 
453
      break;
 
454
 
 
455
    default:
 
456
      fprintf(stderr, _("Unknown command: '%-.60s'"), argv[0]);
 
457
      return 1;
 
458
    }
 
459
  }
 
460
  return 0;
 
461
}
 
462
 
 
463
static void print_version(void)
 
464
{
 
465
  printf(_("%s  Ver %s Distrib %s, for %s on %s\n"),my_progname,ADMIN_VERSION,
 
466
         drizzle_version(),SYSTEM_TYPE,MACHINE_TYPE);
 
467
}
 
468
 
 
469
static void usage(void)
 
470
{
 
471
  print_version();
 
472
  puts(_("Copyright (C) 2000-2008 MySQL AB"));
 
473
  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"));
 
474
  puts(_("Administration program for the drizzled daemon."));
 
475
  printf(_("Usage: %s [OPTIONS] command command....\n"), my_progname);
 
476
  my_print_help(my_long_options);
 
477
  puts(_("\
 
478
  ping         Check if server is down\n\
 
479
  shutdown     Take server down\n"));
 
480
}