options.cc 11.7 KB
Newer Older
1
/* Copyright (C) 2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

17
#if defined(__GNUC__) && defined(USE_PRAGMA_IMPLEMENTATION)
18
#pragma implementation
19 20
#endif

21 22
#include "options.h"

23
#include "priv.h"
24
#include "portability.h"
25 26
#include <my_sys.h>
#include <my_getopt.h>
27 28
#include <m_string.h>
#include <mysql_com.h>
29 30 31

#define QUOTE2(x) #x
#define QUOTE(x) QUOTE2(x)
32

33
#ifdef __WIN__
34 35
char Options::install_as_service;
char Options::remove_service;
36
char Options::stand_alone;
37 38 39 40
char windows_config_file[FN_REFLEN];
char default_password_file_name[FN_REFLEN];
char default_log_file_name[FN_REFLEN];
const char *Options::config_file= windows_config_file;
41 42 43
#else
char Options::run_as_service;
const char *Options::user= 0;                   /* No default value */
44 45
const char *default_password_file_name= QUOTE(DEFAULT_PASSWORD_FILE_NAME);
const char *default_log_file_name= QUOTE(DEFAULT_LOG_FILE_NAME);
46
const char *Options::config_file= QUOTE(DEFAULT_CONFIG_FILE);
47
const char *Options::angel_pid_file_name= NULL;
48
const char *Options::socket_file_name= QUOTE(DEFAULT_SOCKET_FILE_NAME);
49
#endif
50
const char *Options::log_file_name= default_log_file_name;
51
const char *Options::pid_file_name= QUOTE(DEFAULT_PID_FILE_NAME);
52
const char *Options::password_file_name= default_password_file_name;
53
const char *Options::default_mysqld_path= QUOTE(DEFAULT_MYSQLD_PATH);
54
const char *Options::bind_address= 0;           /* No default value */
55 56
uint Options::monitoring_interval= DEFAULT_MONITORING_INTERVAL;
uint Options::port_number= DEFAULT_PORT;
57
/* just to declare */
58
char **Options::saved_argv= NULL;
59 60
/* Remember if the config file was forced */
bool Options::is_forced_default_file= 0;
61

62 63 64
static const char * const ANGEL_PID_FILE_SUFFIX= ".angel.pid";
static const int ANGEL_PID_FILE_SUFFIX_LEN= strlen(ANGEL_PID_FILE_SUFFIX);

65 66 67 68 69 70 71 72 73
/*
  List of options, accepted by the instance manager.
  List must be closed with empty option.
*/

enum options {
  OPT_LOG= 256,
  OPT_PID_FILE,
  OPT_SOCKET,
74 75
  OPT_PASSWORD_FILE,
  OPT_MYSQLD_PATH,
76
#ifndef __WIN__
77 78
  OPT_RUN_AS_SERVICE,
  OPT_USER,
79
  OPT_ANGEL_PID_FILE,
80 81 82
#else
  OPT_INSTALL_SERVICE,
  OPT_REMOVE_SERVICE,
83
  OPT_STAND_ALONE,
84
#endif
85 86
  OPT_MONITORING_INTERVAL,
  OPT_PORT,
87
  OPT_WAIT_TIMEOUT,
88
  OPT_BIND_ADDRESS
89
};
90

91 92 93 94 95 96 97 98 99 100 101
static struct my_option my_long_options[] =
{
  { "help", '?', "Display this help and exit.",
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },

  { "log", OPT_LOG, "Path to log file. Used only with --run-as-service.",
    (gptr *) &Options::log_file_name, (gptr *) &Options::log_file_name,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },

  { "pid-file", OPT_PID_FILE, "Pid file to use.",
    (gptr *) &Options::pid_file_name, (gptr *) &Options::pid_file_name,
102 103 104 105 106 107 108
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },

#ifndef __WIN__
  { "angel-pid-file", OPT_ANGEL_PID_FILE, "Pid file for angel process.",
    (gptr *) &Options::angel_pid_file_name,
    (gptr *) &Options::angel_pid_file_name,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
109

110 111 112
  { "socket", OPT_SOCKET, "Socket file to use for connection.",
    (gptr *) &Options::socket_file_name, (gptr *) &Options::socket_file_name,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
113
#endif
114

115 116 117
  { "passwd", 'P', "Prepare entry for passwd file and exit.", 0, 0, 0,
    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },

petr@mysql.com's avatar
petr@mysql.com committed
118
  { "bind-address", OPT_BIND_ADDRESS, "Bind address to use for connection.",
119 120 121 122 123
    (gptr *) &Options::bind_address, (gptr *) &Options::bind_address,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },

  { "port", OPT_PORT, "Port number to use for connections",
    (gptr *) &Options::port_number, (gptr *) &Options::port_number,
124
    0, GET_UINT, REQUIRED_ARG, DEFAULT_PORT, 0, 0, 0, 0, 0 },
125

paul@frost.snake.net's avatar
paul@frost.snake.net committed
126
  { "password-file", OPT_PASSWORD_FILE, "Look for Instance Manager users"
127 128 129 130 131
                                        " and passwords here.",
    (gptr *) &Options::password_file_name,
    (gptr *) &Options::password_file_name,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },

petr@mysql.com's avatar
petr@mysql.com committed
132
  { "default-mysqld-path", OPT_MYSQLD_PATH, "Where to look for MySQL"
petr@mysql.com's avatar
petr@mysql.com committed
133 134 135
    " Server binary.",
    (gptr *) &Options::default_mysqld_path,
    (gptr *) &Options::default_mysqld_path,
136
    0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0 },
137

petr@mysql.com's avatar
petr@mysql.com committed
138 139 140 141 142 143
  { "monitoring-interval", OPT_MONITORING_INTERVAL, "Interval to monitor"
    " instances in seconds.",
    (gptr *) &Options::monitoring_interval,
    (gptr *) &Options::monitoring_interval,
    0, GET_UINT, REQUIRED_ARG, DEFAULT_MONITORING_INTERVAL,
    0, 0, 0, 0, 0 },
144
#ifdef __WIN__
petr@mysql.com's avatar
petr@mysql.com committed
145 146
  { "install", OPT_INSTALL_SERVICE, "Install as system service.",
    (gptr *) &Options::install_as_service, (gptr*) &Options::install_as_service,
147
    0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
petr@mysql.com's avatar
petr@mysql.com committed
148 149
  { "remove", OPT_REMOVE_SERVICE, "Remove system service.",
    (gptr *)&Options::remove_service, (gptr*) &Options::remove_service,
150
    0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
151 152 153
  { "standalone", OPT_STAND_ALONE, "Run the application in stand alone mode.",
    (gptr *)&Options::stand_alone, (gptr*) &Options::stand_alone,
    0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
154
#else
155 156 157 158
  { "run-as-service", OPT_RUN_AS_SERVICE,
    "Daemonize and start angel process.", (gptr *) &Options::run_as_service,
    0, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },

159
  { "user", OPT_USER, "Username to start mysqlmanager",
petr@mysql.com's avatar
petr@mysql.com committed
160 161 162
    (gptr *) &Options::user,
    (gptr *) &Options::user,
    0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
163
#endif
164
  { "version", 'V', "Output version information and exit.", 0, 0, 0,
petr@mysql.com's avatar
petr@mysql.com committed
165
    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
166

167 168 169 170 171
  { "wait-timeout", OPT_WAIT_TIMEOUT, "The number of seconds IM waits "
    "for activity on a connection before closing it.",
    (gptr *) &net_read_timeout, (gptr *) &net_read_timeout, 0, GET_ULONG,
    REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0 },

172 173 174 175 176
  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }
};

static void version()
{
177
  printf("%s Ver %s for %s on %s\n", my_progname, mysqlmanager_version,
178 179 180
         SYSTEM_TYPE, MACHINE_TYPE);
}

181

petr@mysql.com's avatar
petr@mysql.com committed
182
static const char *default_groups[]= { "manager", 0 };
183 184


185 186 187
static void usage()
{
  version();
188 189 190 191 192 193

  printf("Copyright (C) 2003, 2004 MySQL AB\n"
  "This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
  "and you are welcome to modify and redistribute it under the GPL license\n");
  printf("Usage: %s [OPTIONS] \n", my_progname);

194
  my_print_help(my_long_options);
195 196 197 198 199 200
  printf("\nThe following options may be given as the first argument:\n"
  "--print-defaults        Print the program argument list and exit\n"
  "--defaults-file=#       Only read manager configuration and instance\n"
  "                        setings from the given file #. The same file\n"
  "                        will be used to modify configuration of instances\n"
  "                        with SET commands.\n");
201
  my_print_variables(my_long_options);
202 203
}

204 205 206

static void passwd()
{
207 208 209 210
  char user[1024], *p;
  const char *pw1, *pw2;
  char pw1msg[]= "Enter password: ";
  char pw2msg[]= "Re-type password: ";
211 212 213 214
  char crypted_pw[SCRAMBLED_PASSWORD_CHAR_LENGTH + 1];

  fprintf(stderr, "Creating record for new user.\n");
  fprintf(stderr, "Enter user name: ");
petr@mysql.com's avatar
petr@mysql.com committed
215
  if (!fgets(user, sizeof(user), stdin))
216 217 218 219 220 221
  {
    fprintf(stderr, "Unable to read user.\n");
    return;
  }
  if ((p= strchr(user, '\n'))) *p= 0;

222 223 224 225
  pw1= get_tty_password(pw1msg);
  pw2= get_tty_password(pw2msg);

  if (strcmp(pw1, pw2))
226
  {
227
    fprintf(stderr, "Sorry, passwords do not match.\n");
228 229 230
    return;
  }

231
  make_scrambled_password(crypted_pw, pw1);
232 233 234 235
  printf("%s:%s\n", user, crypted_pw);
}


236 237 238 239 240 241 242 243 244 245 246
C_MODE_START

static my_bool
get_one_option(int optid,
               const struct my_option *opt __attribute__((unused)),
               char *argument __attribute__((unused)))
{
  switch(optid) {
  case 'V':
    version();
    exit(0);
247 248 249
  case 'P':
    passwd();
    exit(0);
250 251 252 253 254 255 256 257 258 259
  case '?':
    usage();
    exit(0);
  }
  return 0;
}

C_MODE_END


260
/*
261 262 263 264
  - Process argv of original program: get tid of --defaults-extra-file
    and print a message if met there.
  - call load_defaults to load configuration file section and save the pointer
    for free_defaults.
265
  - call handle_options to assign defaults and command-line arguments
266 267
  to the class members.
  if either of these function fail, return the error code.
268 269
*/

270
int Options::load(int argc, char **argv)
271
{
272
  if (argc >= 2)
273
  {
274
    if (is_prefix(argv[1], "--defaults-file="))
275
    {
276
      Options::config_file= strchr(argv[1], '=') + 1;
277
      Options::is_forced_default_file= 1;
278
    }
279 280
    if (is_prefix(argv[1], "--defaults-extra-file=") ||
        is_prefix(argv[1], "--no-defaults"))
281 282
    {
      /* the log is not enabled yet */
283
      fprintf(stderr, "The --defaults-extra-file and --no-defaults options"
petr@mysql.com's avatar
petr@mysql.com committed
284 285
              " are not supported by\n"
              "Instance Manager. Program aborted.\n");
286
      goto err;
287
    }
288 289
  }

290
#ifdef __WIN__
291 292
  if (setup_windows_defaults())
    goto err;
293
#endif
294 295
  /* load_defaults will reset saved_argv with a new allocated list */
  saved_argv= argv;
296

297
  /* config-file options are prepended to command-line ones */
298
  load_defaults(config_file, default_groups, &argc,
299 300
                &saved_argv);

301 302
  if ((handle_options(&argc, &saved_argv, my_long_options,
                      get_one_option)) != 0)
303
    goto err;
304

305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
#ifndef __WIN__
  if (Options::run_as_service)
  {
    if (Options::angel_pid_file_name == NULL)
    {
      /*
        Calculate angel pid file on the IM pid file basis: replace the
        extension (everything after the last dot) of the pid file basename to
        '.angel.pid'.
      */

      char *angel_pid_file_name;
      char *base_name_ptr;
      char *ext_ptr;

      angel_pid_file_name= (char *) malloc(strlen(Options::pid_file_name) +
                                           ANGEL_PID_FILE_SUFFIX_LEN);

      strcpy(angel_pid_file_name, Options::pid_file_name);

      base_name_ptr= strrchr(angel_pid_file_name, '/');

      if (!base_name_ptr)
        base_name_ptr= angel_pid_file_name + 1;

      ext_ptr= strrchr(base_name_ptr, '.');
      if (ext_ptr)
        *ext_ptr= 0;

      strcat(angel_pid_file_name, ANGEL_PID_FILE_SUFFIX);

      Options::angel_pid_file_name= angel_pid_file_name;
    }
    else
    {
      Options::angel_pid_file_name= strdup(Options::angel_pid_file_name);
    }
  }
#endif

345
  return 0;
346 347

err:
348
  return 1;
349 350
}

351 352 353
void Options::cleanup()
{
  /* free_defaults returns nothing */
354 355
  if (Options::saved_argv != NULL)
    free_defaults(Options::saved_argv);
356

357
#ifndef __WIN__
358 359
  if (Options::run_as_service)
    free((void *) Options::angel_pid_file_name);
360
#endif
361
}
362 363 364

#ifdef __WIN__

365
int Options::setup_windows_defaults()
366
{
367 368
  if (!GetModuleFileName(NULL, default_password_file_name,
                         sizeof(default_password_file_name)))
369
    return 1;
370
  char *filename= strstr(default_password_file_name, ".exe");
371
  strcpy(filename, ".passwd");
372
 
373 374
  if (!GetModuleFileName(NULL, default_log_file_name,
                         sizeof(default_log_file_name)))
375
    return 1;
376
  filename= strstr(default_log_file_name, ".exe");
377 378 379 380
  strcpy(filename, ".log");

  if (!GetModuleFileName(NULL, windows_config_file,
                         sizeof(windows_config_file)))
381
    return 1;
382
  char *slash= strrchr(windows_config_file, '\\');
383 384
  strcpy(slash, "\\my.ini");
  return 0;
385 386 387
}

#endif