~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to client/drizzleadmin.cc

  • Committer: Brian Aker
  • Date: 2009-04-07 20:09:30 UTC
  • mfrom: (971.1.17 mordred)
  • Revision ID: brian@gaz-20090407200930-27jkul7lkwkjs2to
Merge from Monty

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
 
}