/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   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 */

#include "mysql_priv.h"
#include <mysql.h>
#include <m_ctype.h>
#include <my_dir.h>
#include "sql_acl.h"
#include "slave.h"
#include "sql_repl.h"
#include "repl_failsafe.h"
#include "stacktrace.h"
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
#endif
#ifdef HAVE_INNOBASE_DB
#include "ha_innobase.h"
#endif
#include "ha_myisam.h"
#include <nisam.h>
#include <thr_alarm.h>
#include <ft_global.h>

#ifndef DBUG_OFF
#define ONE_THREAD
#endif

/* do stack traces are only supported on linux intel */
#if defined(__linux__)  && defined(__i386__) && defined(USE_PSTACK)
#define	HAVE_STACK_TRACE_ON_SEGV
#include "../pstack/pstack.h"
char pstack_file_name[80];
#endif /* __linux__ */

#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ)
#define HAVE_CLOSE_SERVER_SOCK 1
#endif  

extern "C" {					// Because of SCO 3.2V4.2
#include <errno.h>
#include <sys/stat.h>
#ifndef __GNU_LIBRARY__
#define __GNU_LIBRARY__				// Skip warnings in getopt.h
#endif
#include <getopt.h>
#ifdef HAVE_SYSENT_H
#include <sysent.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>				// For getpwent
#endif
#ifdef HAVE_GRP_H
#include <grp.h>
#endif

#if defined(OS2)
#  include <sys/un.h>
#elif !defined( __WIN__)
#include <sys/resource.h>
#ifdef HAVE_SYS_UN_H
#  include <sys/un.h>
#endif
#include <netdb.h>
#ifdef HAVE_SELECT_H
#  include <select.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <sys/utsname.h>
#endif /* __WIN__ */

#ifdef HAVE_LIBWRAP
#include <tcpd.h>
#include <syslog.h>
#ifdef NEED_SYS_SYSLOG_H
#include <sys/syslog.h>
#endif /* NEED_SYS_SYSLOG_H */
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
#endif /* HAVE_LIBWRAP */

#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif

#ifdef _AIX41
int initgroups(const char *,unsigned int);
#endif

#if defined(__FreeBSD__) && defined(HAVE_IEEEFP_H)
#include <ieeefp.h>
#ifdef HAVE_FP_EXCEPT				// Fix type conflict
typedef fp_except fp_except_t;
#endif

  /* We can't handle floating point expections with threads, so disable
     this on freebsd
  */

inline void reset_floating_point_exceptions()
{
  /* Don't fall for overflow, underflow,divide-by-zero or loss of precision */
  fpsetmask(~(FP_X_INV | FP_X_DNML | FP_X_OFL | FP_X_UFL |
	      FP_X_DZ | FP_X_IMP));
}
#else
#define reset_floating_point_exceptions()
#endif /* __FreeBSD__ && HAVE_IEEEFP_H */

} /* cplusplus */


#if defined(HAVE_LINUXTHREADS)
#define THR_KILL_SIGNAL SIGINT
#else
#define THR_KILL_SIGNAL SIGUSR2		// Can't use this with LinuxThreads
#endif

#ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
#include <sys/types.h>
#else
#include <my_pthread.h>			// For thr_setconcurency()
#endif
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) && !defined(HAVE_mit_thread)
#define SET_RLIMIT_NOFILE
#endif

#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#endif

#define MYSQL_KILL_SIGNAL SIGTERM

#ifndef DBUG_OFF
static const char* default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace",
					      "d:t:i:o,/tmp/mysqld.trace");
#endif

#ifdef __NT__
static char szPipeName [ 257 ];
static SECURITY_ATTRIBUTES saPipeSecurity;
static SECURITY_DESCRIPTOR sdPipeDescriptor;
static HANDLE hPipe = INVALID_HANDLE_VALUE;
static pthread_cond_t COND_handler_count;
static uint handler_count;
#endif
#ifdef __WIN__
static bool opt_console=0,start_mode=0;
#endif

/* Set prefix for windows binary */
#ifdef __WIN__
#undef MYSQL_SERVER_SUFFIX
#ifdef __NT__
#if defined(HAVE_INNOBASE_DB) || defined(HAVE_BERKELEY_DB)
#define MYSQL_SERVER_SUFFIX "-max-nt"
#else
#define MYSQL_SERVER_SUFFIX "-nt"
#endif /* ...DB */
#elif defined(HAVE_INNOBASE_DB) || defined(HAVE_BERKELEY_DB)
#define MYSQL_SERVER_SUFFIX "-max"
#else
#define MYSQL_SERVER_SUFFIX ""
#endif /* __NT__ */
#endif

#ifdef HAVE_BERKELEY_DB
SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_NO;
#endif
#ifdef HAVE_INNOBASE_DB
SHOW_COMP_OPTION have_innodb=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_innodb=SHOW_OPTION_NO;
#endif
#ifdef HAVE_ISAM
SHOW_COMP_OPTION have_isam=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_isam=SHOW_OPTION_NO;
#endif
#ifdef USE_RAID
SHOW_COMP_OPTION have_raid=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_raid=SHOW_OPTION_NO;
#endif
#ifdef HAVE_OPENSSL
SHOW_COMP_OPTION have_openssl=SHOW_OPTION_YES;
#else
SHOW_COMP_OPTION have_openssl=SHOW_OPTION_NO;
#endif
SHOW_COMP_OPTION have_symlink=SHOW_OPTION_YES;


bool opt_skip_slave_start = 0; // If set, slave is not autostarted
static bool opt_do_pstack = 0;
static ulong opt_specialflag=SPECIAL_ENGLISH;
static ulong back_log,connect_timeout,concurrency;
static ulong opt_myisam_block_size;
static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET;
static my_string opt_logname=0,opt_update_logname=0,
       opt_binlog_index_name = 0,opt_slow_logname=0;
static char mysql_home[FN_REFLEN],pidfile_name[FN_REFLEN];
static pthread_t select_thread;
static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl,
	    opt_disable_networking=0, opt_bootstrap=0,opt_skip_show_db=0,
	    opt_myisam_log=0,
            opt_large_files=sizeof(my_off_t) > 4;
bool opt_sql_bin_update = 0, opt_log_slave_updates = 0, opt_safe_show_db=0,
  opt_show_slave_auth_info = 0, opt_old_rpl_compat = 0,
  opt_safe_user_create = 0, opt_no_mix_types = 0;
FILE *bootstrap_file=0;
int segfaulted = 0; // ensure we do not enter SIGSEGV handler twice

/*
  If sql_bin_update is true, SQL_LOG_UPDATE and SQL_LOG_BIN are kept in sync,
  and are treated as aliases for each other
*/

static bool kill_in_progress=FALSE;
static struct rand_struct sql_rand;
static int cleanup_done;
static char **defaults_argv,time_zone[30];
static const char *default_table_type_name;
char glob_hostname[FN_REFLEN];

#include "sslopt-vars.h"
#ifdef HAVE_OPENSSL
struct st_VioSSLAcceptorFd * ssl_acceptor_fd = 0;
#endif /* HAVE_OPENSSL */

I_List <i_string_pair> replicate_rewrite_db;
I_List<i_string> replicate_do_db, replicate_ignore_db;
// allow the user to tell us which db to replicate and which to ignore
I_List<i_string> binlog_do_db, binlog_ignore_db;

/* if we guessed server_id , we need to know about it */
uint32 server_id = 0;
bool server_id_supplied = 0;

uint mysql_port;
uint test_flags = 0, select_errors=0, dropping_tables=0,ha_open_options=0;
uint volatile thread_count=0, thread_running=0, kill_cached_threads=0,
	      wake_thread=0;
ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
			   OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE );
uint protocol_version=PROTOCOL_VERSION;
ulong keybuff_size,sortbuff_size,max_item_sort_length,table_cache_size,
      max_join_size,join_buff_size,tmp_table_size,thread_stack,
      thread_stack_min,net_wait_timeout,what_to_log= ~ (1L << (uint) COM_TIME),
      query_buff_size, lower_case_table_names, mysqld_net_retry_count,
      net_interactive_timeout, slow_launch_time = 2L,
      net_read_timeout,net_write_timeout,slave_open_temp_tables=0,
      open_files_limit=0, max_binlog_size, record_rnd_cache_size;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
volatile ulong cached_thread_count=0;

// replication parameters, if master_host is not NULL, we are a slave
my_string master_user = (char*) "test", master_password = 0, master_host=0,
  master_info_file = (char*) "master.info",
  relay_log_info_file = (char*) "relay-log.info",
  master_ssl_key=0, master_ssl_cert=0;
my_string report_user = 0, report_password = 0, report_host=0;
 
const char *localhost=LOCAL_HOST;
const char *delayed_user="DELAYED";
uint master_port = MYSQL_PORT, master_connect_retry = 60;
uint report_port = MYSQL_PORT;
bool master_ssl = 0;

ulong max_tmp_tables,max_heap_table_size,master_retry_count=0;
ulong bytes_sent = 0L, bytes_received = 0L;

bool opt_endinfo,using_udf_functions,low_priority_updates, locked_in_memory;
bool opt_using_transactions, using_update_log, opt_warnings=0;
bool volatile abort_loop,select_thread_in_use,grant_option;
bool volatile ready_to_exit,shutdown_in_progress;
ulong refresh_version=1L,flush_version=1L;	/* Increments on each reload */
ulong query_id=1L,long_query_count,long_query_time,aborted_threads,
      aborted_connects,delayed_insert_timeout,delayed_insert_limit,
      delayed_queue_size,delayed_insert_threads,delayed_insert_writes,
      delayed_rows_in_use,delayed_insert_errors,flush_time, thread_created;
ulong filesort_rows, filesort_range_count, filesort_scan_count;
ulong filesort_merge_passes;
ulong select_range_check_count, select_range_count, select_scan_count;
ulong select_full_range_join_count,select_full_join_count;
ulong specialflag=0,opened_tables=0,created_tmp_tables=0,
      created_tmp_disk_tables=0;
ulong max_connections,max_insert_delayed_threads,max_used_connections,
      max_connect_errors, max_user_connections = 0;
ulong thread_id=1L,current_pid;
ulong slow_launch_threads = 0;
ulong myisam_max_sort_file_size, myisam_max_extra_sort_file_size;
  
char mysql_real_data_home[FN_REFLEN],
     language[LIBLEN],reg_ext[FN_EXTLEN],
     default_charset[LIBLEN],mysql_charsets_dir[FN_REFLEN], *charsets_list,
     blob_newline,f_fyllchar,max_sort_char,*mysqld_user,*mysqld_chroot,
     *opt_init_file;
#ifndef EMBEDDED_LIBRARY
char mysql_data_home_buff[2], *mysql_data_home=mysql_data_home_buff;
bool mysql_embedded=0;
#else
char *mysql_data_home=mysql_real_data_home;
bool mysql_embedded=1;
#endif

char *opt_bin_logname = 0; // this one needs to be seen in sql_parse.cc
char *opt_relay_logname = 0, *opt_relaylog_index_name=0;
char server_version[SERVER_VERSION_LENGTH]=MYSQL_SERVER_VERSION;
const char *first_keyword="first";
const char **errmesg;			/* Error messages */
const char *myisam_recover_options_str="OFF";
const char *sql_mode_str="OFF";
const char *default_tx_isolation_name;
enum_tx_isolation default_tx_isolation=ISO_READ_COMMITTED;

uint rpl_recovery_rank=0;

my_string mysql_unix_port=NULL, mysql_tmpdir=NULL, allocated_mysql_tmpdir=NULL;
ulong my_bind_addr;			/* the address we bind to */
DATE_FORMAT dayord;
double log_10[32];			/* 10 potences */
I_List<THD> threads,thread_cache;
time_t start_time;

ulong opt_sql_mode = 0L;
const char *sql_mode_names[] =
{ "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
  "SERIALIZE","ONLY_FULL_GROUP_BY", NullS };
TYPELIB sql_mode_typelib= {array_elements(sql_mode_names)-1,"",
			   sql_mode_names};

MY_BITMAP temp_pool;
bool use_temp_pool=0;

pthread_key(MEM_ROOT*,THR_MALLOC);
pthread_key(THD*, THR_THD);
pthread_key(NET*, THR_NET);
pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
		LOCK_mapped_file, LOCK_status, LOCK_grant,
		LOCK_error_log,
		LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
		LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
	        LOCK_server_id,
		LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;

pthread_cond_t COND_refresh,COND_thread_count;
pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
pthread_t signal_thread;
pthread_attr_t connection_attrib;
enum db_type default_table_type=DB_TYPE_MYISAM;

#ifdef __WIN__
#undef	 getpid
#include <process.h>
HANDLE hEventShutdown;
#include "nt_servc.h"
static	 NTService  Service;	      // Service object for WinNT
#endif

#ifdef OS2
pthread_cond_t eventShutdown;
#endif

static void start_signal_handler(void);
static void *signal_hand(void *arg);
static void set_options(void);
static void get_options(int argc,char **argv);
static char *get_relative_path(const char *path);
static void fix_paths(void);
static pthread_handler_decl(handle_connections_sockets,arg);
static int bootstrap(FILE *file);
static void close_server_sock();
static bool read_init_file(char *file_name);
#ifdef __NT__
static pthread_handler_decl(handle_connections_namedpipes,arg);
#endif
extern pthread_handler_decl(handle_slave,arg);
#ifdef SET_RLIMIT_NOFILE
static uint set_maximum_open_files(uint max_file_limit);
#endif
static ulong find_bit_type(const char *x, TYPELIB *bit_lib);

/****************************************************************************
** Code to end mysqld
****************************************************************************/

static void close_connections(void)
{
#ifdef EXTRA_DEBUG
  int count=0;
#endif
  NET net;
  DBUG_ENTER("close_connections");

  /* Clear thread cache */
  kill_cached_threads++;
  flush_thread_cache();

  /* kill flush thread */
  (void) pthread_mutex_lock(&LOCK_manager);
  if (manager_thread_in_use)
  {
    DBUG_PRINT("quit",("killing manager thread: %lx",manager_thread));
   (void) pthread_cond_signal(&COND_manager);
  }
  (void) pthread_mutex_unlock(&LOCK_manager);

  /* kill connection thread */
#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
  DBUG_PRINT("quit",("waiting for select thread: %lx",select_thread));
  (void) pthread_mutex_lock(&LOCK_thread_count);

  while (select_thread_in_use)
  {
    struct timespec abstime;
    int error;
    LINT_INIT(error);
#ifndef DONT_USE_THR_ALARM
    if (pthread_kill(select_thread,THR_CLIENT_ALARM))
      break;					// allready dead
#endif
#ifdef HAVE_TIMESPEC_TS_SEC
    abstime.ts_sec=time(NULL)+2;		// Bsd 2.1
    abstime.ts_nsec=0;
#else
    struct timeval tv;
    gettimeofday(&tv,0);
    abstime.tv_sec=tv.tv_sec+2;
    abstime.tv_nsec=tv.tv_usec*1000;
#endif
    for (uint tmp=0 ; tmp < 10 ; tmp++)
    {
      error=pthread_cond_timedwait(&COND_thread_count,&LOCK_thread_count,
				   &abstime);
      if (error != EINTR)
	break;
    }
#ifdef EXTRA_DEBUG
    if (error != 0 && !count++)
      sql_print_error("Got error %d from pthread_cond_timedwait",error);
#endif
    close_server_sock();
  }
  (void) pthread_mutex_unlock(&LOCK_thread_count);
#endif /* __WIN__ */


  /* Abort listening to new connections */
  DBUG_PRINT("quit",("Closing sockets"));
  if ( !opt_disable_networking )
  {
    if (ip_sock != INVALID_SOCKET)
    {
      (void) shutdown(ip_sock,2);
      (void) closesocket(ip_sock);
      ip_sock= INVALID_SOCKET;
    }
  }
#ifdef __NT__
  if ( hPipe != INVALID_HANDLE_VALUE )
  {
    HANDLE hTempPipe = &hPipe;
    DBUG_PRINT( "quit", ("Closing named pipes") );
    hPipe = INVALID_HANDLE_VALUE;
    CancelIo( hTempPipe );
    DisconnectNamedPipe( hTempPipe );
    CloseHandle( hTempPipe );
  }
#endif
#ifdef HAVE_SYS_UN_H
  if (unix_sock != INVALID_SOCKET)
  {
    (void) shutdown(unix_sock,2);
    (void) closesocket(unix_sock);
    (void) unlink(mysql_unix_port);
    unix_sock= INVALID_SOCKET;
  }
#endif
  end_thr_alarm();			 // Don't allow alarms
  end_slave();

  /* First signal all threads that it's time to die */

  THD *tmp;
  (void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list

  I_List_iterator<THD> it(threads);
  while ((tmp=it++))
  {
    DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
		       tmp->thread_id));
    tmp->killed=1;
    if (tmp->mysys_var)
    {
      tmp->mysys_var->abort=1;
      pthread_mutex_lock(&tmp->mysys_var->mutex);
      if (tmp->mysys_var->current_cond)
      {
	pthread_mutex_lock(tmp->mysys_var->current_mutex);
	pthread_cond_broadcast(tmp->mysys_var->current_cond);
	pthread_mutex_unlock(tmp->mysys_var->current_mutex);
      }
      pthread_mutex_unlock(&tmp->mysys_var->mutex);
    }
  }
  (void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list

  if (thread_count)
  {
    sleep(1);					// Give threads time to die
  }

  /* Force remaining threads to die by closing the connection to the client */

  (void) my_net_init(&net, (st_vio*) 0);
  for (;;)
  {
    DBUG_PRINT("quit",("Locking LOCK_thread_count"));
    (void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
    if (!(tmp=threads.get()))
    {
      DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
      (void) pthread_mutex_unlock(&LOCK_thread_count);
      break;
    }
#ifndef __bsdi__				// Bug in BSDI kernel
    if ((net.vio=tmp->net.vio) != 0)
    {
      sql_print_error(ER(ER_FORCING_CLOSE),my_progname,
		      tmp->thread_id,tmp->user ? tmp->user : "");
      close_connection(&net,0,0);
    }
#endif
    DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
    (void) pthread_mutex_unlock(&LOCK_thread_count);
  }
  net_end(&net);
  /* All threads has now been aborted */
  DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count));
  (void) pthread_mutex_lock(&LOCK_thread_count);
  while (thread_count)
  {
    (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
    DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
  }
  (void) pthread_mutex_unlock(&LOCK_thread_count);

  mysql_log.close(1);
  mysql_slow_log.close(1);
  mysql_update_log.close(1);
  mysql_bin_log.close(1);
  DBUG_PRINT("quit",("close_connections thread"));
  DBUG_VOID_RETURN;
}

static void close_server_sock()
{
#ifdef HAVE_CLOSE_SERVER_SOCK
  DBUG_ENTER("close_server_sock");
  my_socket tmp_sock;
  tmp_sock=ip_sock;
  if (tmp_sock != INVALID_SOCKET)
  {
    ip_sock=INVALID_SOCKET;
    DBUG_PRINT("info",("closing TCP/IP socket"));
    VOID(shutdown(tmp_sock,2));
    VOID(closesocket(tmp_sock));
  }
  tmp_sock=unix_sock;
  if (tmp_sock != INVALID_SOCKET)
  {
    unix_sock=INVALID_SOCKET;
    DBUG_PRINT("info",("closing Unix socket"));
    VOID(shutdown(tmp_sock,2));
    VOID(closesocket(tmp_sock));
    VOID(unlink(mysql_unix_port));
  }
  DBUG_VOID_RETURN;
#endif
}

void kill_mysql(void)
{
  DBUG_ENTER("kill_mysql");

#ifdef SIGNALS_DONT_BREAK_READ
  close_server_sock(); /* force accept to wake up */
#endif  
  
#if defined(__WIN__)
  {
    if (!SetEvent(hEventShutdown))
    {
      DBUG_PRINT("error",("Got error: %ld from SetEvent",GetLastError()));
    }
    /*
      or:
      HANDLE hEvent=OpenEvent(0, FALSE, "MySqlShutdown");
      SetEvent(hEventShutdown);
      CloseHandle(hEvent);
    */
  }
#elif defined(OS2)
  pthread_cond_signal( &eventShutdown);		// post semaphore
#elif defined(HAVE_PTHREAD_KILL)
    if (pthread_kill(signal_thread,SIGTERM))	/* End everything nicely */
    {
      DBUG_PRINT("error",("Got error %d from pthread_kill",errno)); /* purecov: inspected */
    }
#else
    kill(current_pid,SIGTERM);
#endif
    DBUG_PRINT("quit",("After pthread_kill"));
    shutdown_in_progress=1;			// Safety if kill didn't work
#ifdef SIGNALS_DONT_BREAK_READ    
    abort_loop=1;
#endif    
    DBUG_VOID_RETURN;
}


	/* Force server down. kill all connections and threads and exit */

#if defined(OS2)
extern "C" void kill_server(int sig_ptr)
#define RETURN_FROM_KILL_SERVER return
#elif !defined(__WIN__)
static void *kill_server(void *sig_ptr)
#define RETURN_FROM_KILL_SERVER return 0
#else
static void __cdecl kill_server(int sig_ptr)
#define RETURN_FROM_KILL_SERVER return
#endif
{
  int sig=(int) (long) sig_ptr;			// This is passed a int
  DBUG_ENTER("kill_server");

  // if there is a signal during the kill in progress, ignore the other
  if (kill_in_progress)				// Safety
    RETURN_FROM_KILL_SERVER;
  kill_in_progress=TRUE;
  abort_loop=1;					// This should be set
  signal(sig,SIG_IGN);
  if (sig == MYSQL_KILL_SIGNAL || sig == 0)
    sql_print_error(ER(ER_NORMAL_SHUTDOWN),my_progname);
  else
    sql_print_error(ER(ER_GOT_SIGNAL),my_progname,sig); /* purecov: inspected */

#if defined(USE_ONE_SIGNAL_HAND) && !defined(__WIN__) && !defined(OS2)
  my_thread_init();				// If this is a new thread
#endif
  close_connections();
  if (sig != MYSQL_KILL_SIGNAL && sig != 0)
    unireg_abort(1);				/* purecov: inspected */
  else
    unireg_end(0);
  pthread_exit(0);				/* purecov: deadcode */
  RETURN_FROM_KILL_SERVER;
}


#ifdef USE_ONE_SIGNAL_HAND
pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
{
  my_thread_init();				// Initialize new thread
  kill_server(0);
  my_thread_end();				// Normally never reached
  return 0;
}
#endif

#if defined(__amiga__)
#undef sigset
#define sigset signal
#endif

static sig_handler print_signal_warning(int sig)
{
  sql_print_error("Warning: Got signal %d from thread %d",
		  sig,my_thread_id());
#ifdef DONT_REMEMBER_SIGNAL
  sigset(sig,print_signal_warning);		/* int. thread system calls */
#endif
#if !defined(__WIN__) && !defined(OS2)
  if (sig == SIGALRM)
    alarm(2);					/* reschedule alarm */
#endif
}


void unireg_end(int signal_number __attribute__((unused)))
{
  clean_up();
  my_thread_end();
  pthread_exit(0);				// Exit is in main thread
}


void unireg_abort(int exit_code)
{
  DBUG_ENTER("unireg_abort");
  if (exit_code)
    sql_print_error("Aborting\n");
  clean_up(); /* purecov: inspected */
  DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
  my_thread_end();
  exit(exit_code); /* purecov: inspected */
}


void clean_up(bool print_message)
{
  DBUG_PRINT("exit",("clean_up"));
  if (cleanup_done++)
    return; /* purecov: inspected */
  acl_free(1);
  grant_free();
  sql_cache_free();
  table_cache_free();
  hostname_cache_free();
  item_user_lock_free();
  lex_free();				/* Free some memory */
#ifdef HAVE_DLOPEN
  if (!opt_noacl)
    udf_free();
#endif
  (void) ha_panic(HA_PANIC_CLOSE);	/* close all tables and logs */
  end_key_cache();
#ifdef USE_RAID
  end_raid();
#endif
#ifdef HAVE_OPENSSL
  my_free(opt_ssl_key,MYF(MY_ALLOW_ZERO_PTR));
  my_free(opt_ssl_cert,MYF(MY_ALLOW_ZERO_PTR));
  my_free(opt_ssl_ca,MYF(MY_ALLOW_ZERO_PTR));
  my_free(opt_ssl_capath,MYF(MY_ALLOW_ZERO_PTR));
  my_free(opt_ssl_cipher,MYF(MY_ALLOW_ZERO_PTR));
  opt_ssl_key=opt_ssl_cert=opt_ssl_ca=opt_ssl_capath=0;
#endif /* HAVE_OPENSSL */
  free_defaults(defaults_argv);
  my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR));
  my_free(allocated_mysql_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
  my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
  x_free(opt_bin_logname);
  x_free(opt_relay_logname);
  bitmap_free(&temp_pool);
  free_max_user_conn();
  end_slave_list();

#if !defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
  if (!opt_bootstrap)
    (void) my_delete(pidfile_name,MYF(0));	// This may not always exist
#endif
  if (print_message && errmesg)
    sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname);
  x_free((gptr) my_errmsg[ERRMAPP]);	/* Free messages */
  DBUG_PRINT("quit", ("Error messages freed"));
  /* Tell main we are ready */
  (void) pthread_mutex_lock(&LOCK_thread_count);
  DBUG_PRINT("quit", ("got thread count lock"));
  ready_to_exit=1;
  /* do the broadcast inside the lock to ensure that my_end() is not called */
  (void) pthread_cond_broadcast(&COND_thread_count);
  (void) pthread_mutex_unlock(&LOCK_thread_count);
  DBUG_PRINT("quit", ("done with cleanup"));
} /* clean_up */



/****************************************************************************
** Init IP and UNIX socket
****************************************************************************/

static void set_ports()
{
  char	*env;
  if (!mysql_port && !opt_disable_networking)
  {					// Get port if not from commandline
    struct  servent *serv_ptr;
    mysql_port = MYSQL_PORT;
    if ((serv_ptr = getservbyname("mysql", "tcp")))
      mysql_port = ntohs((u_short) serv_ptr->s_port); /* purecov: inspected */
    if ((env = getenv("MYSQL_TCP_PORT")))
      mysql_port = (uint) atoi(env);		/* purecov: inspected */
  }
  if (!mysql_unix_port)
  {
#ifdef __WIN__
    mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
#else
    mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
#endif
    if ((env = getenv("MYSQL_UNIX_PORT")))
      mysql_unix_port = env;			/* purecov: inspected */
  }
}

/* Change to run as another user if started with --user */

static void set_user(const char *user)
{
#if !defined(__WIN__) && !defined(OS2)
    struct passwd *ent;

  // don't bother if we aren't superuser
  if (geteuid())
  {
    if (user)
      fprintf(stderr,
	      "Warning: One can only use the --user switch if running as root\n");
    return;
  }
  else if (!user)
  {
    if (!opt_bootstrap)
    {
      fprintf(stderr,"Fatal error: Please read \"Security\" section of the manual to find out how to run mysqld as root!\n");
      unireg_abort(1);
    }
    return;
  }
  if (!strcmp(user,"root"))
    return;				// Avoid problem with dynamic libraries

  if (!(ent = getpwnam(user)))
  {
    fprintf(stderr,"Fatal error: Can't change to run as user '%s' ;  Please check that the user exists!\n",user);
    unireg_abort(1);
  }
#ifdef HAVE_INITGROUPS
  initgroups((char*) user,ent->pw_gid);
#endif
  if (setgid(ent->pw_gid) == -1)
  {
    sql_perror("setgid");
    unireg_abort(1);
  }
  if (setuid(ent->pw_uid) == -1)
  {
    sql_perror("setuid");
    unireg_abort(1);
  }
#endif
}

/* Change root user if started with  --chroot */

static void set_root(const char *path)
{
#if !defined(__WIN__) && !defined(__EMX__) && !defined(OS2)
  if (chroot(path) == -1)
  {
    sql_perror("chroot");
    unireg_abort(1);
  }
#endif
}

static void server_init(void)
{
  struct sockaddr_in	IPaddr;
#ifdef HAVE_SYS_UN_H
  struct sockaddr_un	UNIXaddr;
#endif
  int	arg=1;
  DBUG_ENTER("server_init");

#ifdef	__WIN__
  if ( !opt_disable_networking )
  {
    WSADATA WsaData;
    if (SOCKET_ERROR == WSAStartup (0x0101, &WsaData))
    {
      my_message(0,"WSAStartup Failed\n",MYF(0));
      unireg_abort(1);
    }
  }
#endif /* __WIN__ */

  set_ports();

  if (mysql_port != 0 && !opt_disable_networking && !opt_bootstrap)
  {
    DBUG_PRINT("general",("IP Socket is %d",mysql_port));
    ip_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (ip_sock == INVALID_SOCKET)
    {
      DBUG_PRINT("error",("Got error: %d from socket()",socket_errno));
      sql_perror(ER(ER_IPSOCK_ERROR));		/* purecov: tested */
      unireg_abort(1);				/* purecov: tested */
    }
    bzero((char*) &IPaddr, sizeof(IPaddr));
    IPaddr.sin_family = AF_INET;
    IPaddr.sin_addr.s_addr = my_bind_addr;
    IPaddr.sin_port = (unsigned short) htons((unsigned short) mysql_port);
    (void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
    for(;;)
    {
      if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
	       sizeof(IPaddr)) >= 0)
	break;
      DBUG_PRINT("error",("Got error: %d from bind",socket_errno));
      sql_perror("Can't start server: Bind on TCP/IP port");/* Had a loop here */
      sql_print_error("Do you already have another mysqld server running on port: %d ?",mysql_port);
      unireg_abort(1);
    }
    if (listen(ip_sock,(int) back_log) < 0)
      sql_print_error("Warning:  listen() on TCP/IP failed with error %d",
		      socket_errno);
  }

  if (mysqld_chroot)
    set_root(mysqld_chroot);

  set_user(mysqld_user); // set_user now takes care of mysqld_user==NULL

#ifdef __NT__
  /* create named pipe */
  if (Service.IsNT() && mysql_unix_port[0] && !opt_bootstrap)
  {
    sprintf( szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port );
    ZeroMemory( &saPipeSecurity, sizeof(saPipeSecurity) );
    ZeroMemory( &sdPipeDescriptor, sizeof(sdPipeDescriptor) );
    if ( !InitializeSecurityDescriptor(&sdPipeDescriptor,
				       SECURITY_DESCRIPTOR_REVISION) )
    {
      sql_perror("Can't start server : Initialize security descriptor");
      unireg_abort(1);
    }
    if (!SetSecurityDescriptorDacl(&sdPipeDescriptor, TRUE, NULL, FALSE))
    {
      sql_perror("Can't start server : Set security descriptor");
      unireg_abort(1);
    }
    saPipeSecurity.nLength = sizeof( SECURITY_ATTRIBUTES );
    saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor;
    saPipeSecurity.bInheritHandle = FALSE;
    if ((hPipe = CreateNamedPipe(szPipeName,
				 PIPE_ACCESS_DUPLEX,
				 PIPE_TYPE_BYTE |
				 PIPE_READMODE_BYTE |
				 PIPE_WAIT,
				 PIPE_UNLIMITED_INSTANCES,
				 (int) net_buffer_length,
				 (int) net_buffer_length,
				 NMPWAIT_USE_DEFAULT_WAIT,
				 &saPipeSecurity )) == INVALID_HANDLE_VALUE)
      {
	LPVOID lpMsgBuf;
	int error=GetLastError();
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
		      FORMAT_MESSAGE_FROM_SYSTEM,
		      NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		      (LPTSTR) &lpMsgBuf, 0, NULL );
	MessageBox( NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
		    MB_OK|MB_ICONINFORMATION );
	LocalFree( lpMsgBuf );
	unireg_abort(1);
      }
  }
#endif

#if defined(HAVE_SYS_UN_H)
  /*
  ** Create the UNIX socket
  */
  if (mysql_unix_port[0] && !opt_bootstrap)
  {
    DBUG_PRINT("general",("UNIX Socket is %s",mysql_unix_port));

    if ((unix_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    {
      sql_perror("Can't start server : UNIX Socket "); /* purecov: inspected */
      unireg_abort(1);				/* purecov: inspected */
    }
    bzero((char*) &UNIXaddr, sizeof(UNIXaddr));
    UNIXaddr.sun_family = AF_UNIX;
    strmov(UNIXaddr.sun_path, mysql_unix_port);
    (void) unlink(mysql_unix_port);
    (void) setsockopt(unix_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,
		      sizeof(arg));
    umask(0);
    if (bind(unix_sock, my_reinterpret_cast(struct sockaddr *) (&UNIXaddr),
	     sizeof(UNIXaddr)) < 0)
    {
      sql_perror("Can't start server : Bind on unix socket"); /* purecov: tested */
      sql_print_error("Do you already have another mysqld server running on socket: %s ?",mysql_unix_port);
      unireg_abort(1);					/* purecov: tested */
    }
    umask(((~my_umask) & 0666));
#if defined(S_IFSOCK) && defined(SECURE_SOCKETS)
    (void) chmod(mysql_unix_port,S_IFSOCK);	/* Fix solaris 2.6 bug */
#endif
    if (listen(unix_sock,(int) back_log) < 0)
      sql_print_error("Warning:  listen() on Unix socket failed with error %d",
		      socket_errno);
  }
#endif
  DBUG_PRINT("info",("server started"));
  DBUG_VOID_RETURN;
}


void yyerror(const char *s)
{
  NET *net=my_pthread_getspecific_ptr(NET*,THR_NET);
  char *yytext=(char*) current_lex->tok_start;
  if (!strcmp(s,"parse error"))
    s=ER(ER_SYNTAX_ERROR);
  net_printf(net,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
	     current_lex->yylineno);
}


void close_connection(NET *net,uint errcode,bool lock)
{
  st_vio* vio;
  DBUG_ENTER("close_connection");
  DBUG_PRINT("enter",("fd: %s  error: '%s'",
                    net->vio? vio_description(net->vio):"(not connected)",
                    errcode ? ER(errcode) : ""));
  if (lock)
    (void) pthread_mutex_lock(&LOCK_thread_count);
  if ((vio=net->vio) != 0)
  {
    if (errcode)
      send_error(net,errcode,ER(errcode));	/* purecov: inspected */
    vio_close(vio);			/* vio is freed in delete thd */
  }
  if (lock)
    (void) pthread_mutex_unlock(&LOCK_thread_count);
  DBUG_VOID_RETURN;
}

	/* Called when a thread is aborted */
	/* ARGSUSED */

sig_handler end_thread_signal(int sig __attribute__((unused)))
{
  THD *thd=current_thd;
  DBUG_ENTER("end_thread_signal");
  if (thd)
    end_thread(thd,0);
  DBUG_VOID_RETURN;				/* purecov: deadcode */
}


void end_thread(THD *thd, bool put_in_cache)
{
  DBUG_ENTER("end_thread");
  thd->cleanup();
  (void) pthread_mutex_lock(&LOCK_thread_count);
  thread_count--;
  delete thd;

  if (put_in_cache && cached_thread_count < thread_cache_size &&
      ! abort_loop && !kill_cached_threads)
  {
    /* Don't kill the thread, just put it in cache for reuse */
    DBUG_PRINT("info", ("Adding thread to cache"))
    cached_thread_count++;
    while (!abort_loop && ! wake_thread && ! kill_cached_threads)
      (void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count);
    cached_thread_count--;
    if (kill_cached_threads)
      pthread_cond_signal(&COND_flush_thread_cache);
    if (wake_thread)
    {
      wake_thread--;
      thd=thread_cache.get();
      thd->real_id=pthread_self();
      (void) thd->store_globals();
      threads.append(thd);
      pthread_mutex_unlock(&LOCK_thread_count);
      DBUG_VOID_RETURN;
    }
  }

  DBUG_PRINT("info", ("sending a broadcast"))

  /* Tell main we are ready */
    // TODO: explain why we broadcast outside of the lock or
    // fix the bug - Sasha
  (void) pthread_mutex_unlock(&LOCK_thread_count);
  (void) pthread_cond_broadcast(&COND_thread_count);
  DBUG_PRINT("info", ("unlocked thread_count mutex"))
#ifdef ONE_THREAD
  if (!(test_flags & TEST_NO_THREADS))	// For debugging under Linux
#endif
  {
    my_thread_end();
    pthread_exit(0);
  }
  DBUG_VOID_RETURN;
}


/* Start a cached thread. LOCK_thread_count is locked on entry */

static void start_cached_thread(THD *thd)
{
  thread_cache.append(thd);
  wake_thread++;
  thread_count++;
  pthread_cond_signal(&COND_thread_cache);
}


void flush_thread_cache()
{
  (void) pthread_mutex_lock(&LOCK_thread_count);
  kill_cached_threads++;
  while (cached_thread_count)
  {
    pthread_cond_broadcast(&COND_thread_cache);
    pthread_cond_wait(&COND_flush_thread_cache,&LOCK_thread_count);
  }
  kill_cached_threads--;
  (void) pthread_mutex_unlock(&LOCK_thread_count);
}


	/*
	** Aborts a thread nicely. Commes here on SIGPIPE
	** TODO: One should have to fix that thr_alarm know about this
	** thread too
	*/

#ifdef THREAD_SPECIFIC_SIGPIPE
static sig_handler abort_thread(int sig __attribute__((unused)))
{
  THD *thd=current_thd;
  DBUG_ENTER("abort_thread");
  if (thd)
    thd->killed=1;
  DBUG_VOID_RETURN;
}
#endif

/******************************************************************************
** Setup a signal thread with handles all signals
** Because linux doesn't support scemas use a mutex to check that
** the signal thread is ready before continuing
******************************************************************************/

#if defined(__WIN__) || defined(OS2)
static void init_signals(void)
{
  int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
  for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
    signal( signals[i], kill_server) ;
#if defined(__WIN__)
  signal(SIGBREAK,SIG_IGN);	//ignore SIGBREAK for NT
#else
  signal(SIGBREAK, kill_server);
#endif
}

static void start_signal_handler(void)
{
}

#elif defined(__EMX__)
static void sig_reload(int signo)
{
  reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0); // Flush everything
  signal(signo, SIG_ACK);
}

static void sig_kill(int signo)
{
  if (!abort_loop)
  {
    abort_loop=1;				// mark abort for threads
    kill_server((void*) signo);
  }
  signal(signo, SIG_ACK);
}

static void init_signals(void)
{
  signal(SIGQUIT, sig_kill);
  signal(SIGKILL, sig_kill);
  signal(SIGTERM, sig_kill);
  signal(SIGINT,  sig_kill);
  signal(SIGHUP,  sig_reload);	// Flush everything
  signal(SIGALRM, SIG_IGN);
  signal(SIGBREAK,SIG_IGN);
  signal_thread = pthread_self();
}

static void start_signal_handler(void)
{
}

#else /* if ! __WIN__ && ! __EMX__ */

#ifdef HAVE_LINUXTHREADS
#define UNSAFE_DEFAULT_LINUX_THREADS 200
#endif

static sig_handler handle_segfault(int sig)
{
  THD *thd=current_thd;
  /*
    Strictly speaking, one needs a mutex here
    but since we have got SIGSEGV already, things are a mess
    so not having the mutex is not as bad as possibly using a buggy
    mutex - so we keep things simple
  */
  if (segfaulted)
  {
    fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
    exit(1);
  }
  
  segfaulted = 1;
  fprintf(stderr,"\
mysqld got signal %d;\n\
This could be because you hit a bug. It is also possible that this binary\n\
or one of the libraries it was linked against is corrupt, improperly built,\n\
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
	  sig);
  fprintf(stderr, "\
We will try our best to scrape up some info that will hopefully help diagnose\n\
the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n");
  fprintf(stderr, "key_buffer_size=%ld\n", keybuff_size);
  fprintf(stderr, "record_buffer=%ld\n", my_default_record_cache_size);
  fprintf(stderr, "sort_buffer=%ld\n", sortbuff_size);
  fprintf(stderr, "max_used_connections=%ld\n", max_used_connections);
  fprintf(stderr, "max_connections=%ld\n", max_connections);
  fprintf(stderr, "threads_connected=%d\n", thread_count);
  fprintf(stderr, "It is possible that mysqld could use up to \n\
key_buffer_size + (record_buffer + sort_buffer)*max_connections = %ld K\n\
bytes of memory\n", (keybuff_size + (my_default_record_cache_size +
			     sortbuff_size) * max_connections)/ 1024);
  fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
  
#if defined(HAVE_LINUXTHREADS)
  if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
  {
    fprintf(stderr, "\
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
If you have not changed STACK_SIZE in LinuxThreads and built the binary \n\
yourself, LinuxThreads is quite likely to steal a part of the global heap for\n\
the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
	    thread_count);
  }
#endif /* HAVE_LINUXTHREADS */

#ifdef HAVE_STACKTRACE
  if(!(test_flags & TEST_NO_STACKTRACE))
  {
    fprintf(stderr,"thd=%p\n",thd);
    print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0,
		     thread_stack);
  }
  if (thd)
  {
    fprintf(stderr, "Trying to get some variables.\n\
Some pointers may be invalid and cause the dump to abort...\n");
    safe_print_str("thd->query", thd->query, 1024);
    fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id);
    fprintf(stderr, "\n\
Successfully dumped variables, if you ran with --log, take a look at the\n\
details of what thread %ld did to cause the crash.  In some cases of really\n\
bad corruption, the values shown above may be invalid.\n\n",
	  thd->thread_id);
  }
  fprintf(stderr, "\
The manual page at http://www.mysql.com/doc/C/r/Crashing.html contains\n\
information that should help you find out what is causing the crash.\n");
  fflush(stderr);
#endif /* HAVE_STACKTRACE */

 if (test_flags & TEST_CORE_ON_SIGNAL)
   write_core(sig);
 exit(1);
}

#ifndef SA_RESETHAND
#define SA_RESETHAND 0
#endif
#ifndef SA_NODEFER
#define SA_NODEFER 0
#endif

static void init_signals(void)
{
  sigset_t set;
  DBUG_ENTER("init_signals");

  sigset(THR_KILL_SIGNAL,end_thread_signal);
  sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!

  if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
  {
    struct sigaction sa;
    sa.sa_flags = SA_RESETHAND | SA_NODEFER;
    sigemptyset(&sa.sa_mask);
    sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);

    init_stacktrace();
#if defined(__amiga__)
    sa.sa_handler=(void(*)())handle_segfault;
#else
    sa.sa_handler=handle_segfault;
#endif
    sigaction(SIGSEGV, &sa, NULL);
#ifdef SIGBUS
    sigaction(SIGBUS, &sa, NULL);
#endif
    sigaction(SIGILL, &sa, NULL);
  }
  (void) sigemptyset(&set);
#ifdef THREAD_SPECIFIC_SIGPIPE
  sigset(SIGPIPE,abort_thread);
  sigaddset(&set,SIGPIPE);
#else
  (void) signal(SIGPIPE,SIG_IGN);		// Can't know which thread
  sigaddset(&set,SIGPIPE);
#endif
  sigaddset(&set,SIGINT);
  sigaddset(&set,SIGQUIT);
  sigaddset(&set,SIGTERM);
  sigaddset(&set,SIGHUP);
  signal(SIGTERM,SIG_DFL);			// If it's blocked by parent
  signal(SIGHUP,SIG_DFL);			// If it's blocked by parent
#ifdef SIGTSTP
  sigaddset(&set,SIGTSTP);
#endif
  sigaddset(&set,THR_SERVER_ALARM);
  sigdelset(&set,THR_KILL_SIGNAL);		// May be SIGINT
  sigdelset(&set,THR_CLIENT_ALARM);		// For alarms
  (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
  DBUG_VOID_RETURN;
}


static void start_signal_handler(void)
{
  int error;
  pthread_attr_t thr_attr;
  DBUG_ENTER("start_signal_handler");

  (void) pthread_attr_init(&thr_attr);
#if !defined(HAVE_DEC_3_2_THREADS)
  pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_SYSTEM);
  (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
  if (!(opt_specialflag & SPECIAL_NO_PRIOR))
    my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR);
  pthread_attr_setstacksize(&thr_attr,32768);
#endif

  (void) pthread_mutex_lock(&LOCK_thread_count);
  if ((error=pthread_create(&signal_thread,&thr_attr,signal_hand,0)))
  {
    sql_print_error("Can't create interrupt-thread (error %d, errno: %d)",
		    error,errno);
    exit(1);
  }
  (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
  pthread_mutex_unlock(&LOCK_thread_count);

  (void) pthread_attr_destroy(&thr_attr);
  DBUG_VOID_RETURN;
}


/*
** This threads handles all signals and alarms
*/

/* ARGSUSED */
static void *signal_hand(void *arg __attribute__((unused)))
{
  sigset_t set;
  int sig;
  my_thread_init();				// Init new thread
  DBUG_ENTER("signal_hand");

  /* Setup alarm handler */
  init_thr_alarm(max_connections+max_insert_delayed_threads);
#if SIGINT != THR_KILL_SIGNAL
  (void) sigemptyset(&set);			// Setup up SIGINT for debug
  (void) sigaddset(&set,SIGINT);		// For debugging
  (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
#endif
  (void) sigemptyset(&set);			// Setup up SIGINT for debug
#ifdef USE_ONE_SIGNAL_HAND
  (void) sigaddset(&set,THR_SERVER_ALARM);	// For alarms
#endif
  (void) sigaddset(&set,SIGQUIT);
  (void) sigaddset(&set,SIGTERM);
#if THR_CLIENT_ALARM != SIGHUP
  (void) sigaddset(&set,SIGHUP);
#endif
  (void) sigaddset(&set,SIGTSTP);

  /* Save pid to this process (or thread on Linux) */
  if (!opt_bootstrap)
  {
    File pidFile;
    if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0)
    {
      char buff[21];
      sprintf(buff,"%lu",(ulong) getpid());
      (void) my_write(pidFile, buff,strlen(buff),MYF(MY_WME));
      (void) my_close(pidFile,MYF(0));
    }
  }
#ifdef HAVE_STACK_TRACE_ON_SEGV
  if (opt_do_pstack)
  {
    sprintf(pstack_file_name,"mysqld-%lu-%%d-%%d.backtrace", (ulong)getpid());
    pstack_install_segv_action(pstack_file_name);
  }
#endif /* HAVE_STACK_TRACE_ON_SEGV */

  // signal to start_signal_handler that we are ready
  (void) pthread_mutex_lock(&LOCK_thread_count);
  (void) pthread_cond_signal(&COND_thread_count);
  (void) pthread_mutex_unlock(&LOCK_thread_count);

  for (;;)
  {
    int error;					// Used when debugging
    if (shutdown_in_progress && !abort_loop)
    {
      sig=SIGTERM;
      error=0;
    }
    else
      while ((error=my_sigwait(&set,&sig)) == EINTR) ;
    if (cleanup_done)
      pthread_exit(0);				// Safety
    switch (sig) {
    case SIGTERM:
    case SIGQUIT:
    case SIGKILL:
#ifdef EXTRA_DEBUG
      sql_print_error("Got signal %d to shutdown mysqld",sig);
#endif
      DBUG_PRINT("info",("Got signal: %d  abort_loop: %d",sig,abort_loop));
      if (!abort_loop)
      {
	abort_loop=1;				// mark abort for threads
#ifdef USE_ONE_SIGNAL_HAND
	pthread_t tmp;
	if (!(opt_specialflag & SPECIAL_NO_PRIOR))
	  my_pthread_attr_setprio(&connection_attrib,INTERRUPT_PRIOR);
	if (pthread_create(&tmp,&connection_attrib, kill_server_thread,
			   (void*) sig))
	  sql_print_error("Error: Can't create thread to kill server");
#else
	  kill_server((void*) sig);		// MIT THREAD has a alarm thread
#endif
      }
      break;
    case SIGHUP:
      reload_acl_and_cache((THD*) 0,
			   (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
			    REFRESH_STATUS | REFRESH_GRANT | REFRESH_THREADS |
			    REFRESH_HOSTS),
			   (TABLE_LIST*) 0); // Flush logs
      mysql_print_status((THD*) 0);		// Send debug some info
      break;
#ifdef USE_ONE_SIGNAL_HAND
    case THR_SERVER_ALARM:
      process_alarm(sig);			// Trigger alarms.
      break;
#endif
    default:
#ifdef EXTRA_DEBUG
      sql_print_error("Warning: Got signal: %d, error: %d",sig,error); /* purecov: tested */
#endif
      break;					/* purecov: tested */
    }
  }
  return(0);					/* purecov: deadcode */
}

#endif	/* __WIN__*/


/*
** All global error messages are sent here where the first one is stored for
** the client
*/


/* ARGSUSED */
static int my_message_sql(uint error, const char *str,
			  myf MyFlags __attribute__((unused)))
{
  NET *net;
  DBUG_ENTER("my_message_sql");
  DBUG_PRINT("error",("Message: '%s'",str));
  if ((net=my_pthread_getspecific_ptr(NET*,THR_NET)))
  {
    if (!net->last_error[0])			// Return only first message
    {
      strmake(net->last_error,str,sizeof(net->last_error)-1);
      net->last_errno=error ? error : ER_UNKNOWN_ERROR;
    }
  }
  else
    sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
  DBUG_RETURN(0);
}

#ifdef __WIN__

struct utsname
{
  char nodename[FN_REFLEN];
};

int uname(struct utsname *a)
{
  return -1;
}
#endif


#ifdef __WIN__
pthread_handler_decl(handle_shutdown,arg)
{
  MSG msg;
  my_thread_init();

  /* this call should create the message queue for this thread */
  PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE);

  if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0)
     kill_server(MYSQL_KILL_SIGNAL);
  return 0;
}

int __stdcall handle_kill(ulong ctrl_type)
{
  if (ctrl_type == CTRL_CLOSE_EVENT ||
      ctrl_type == CTRL_SHUTDOWN_EVENT)
  {
    kill_server(MYSQL_KILL_SIGNAL);
    return TRUE;
  }
  return FALSE;
}
#endif

#ifdef OS2
pthread_handler_decl(handle_shutdown,arg)
{
  my_thread_init();

  // wait semaphore
  pthread_cond_wait( &eventShutdown, NULL);

  // close semaphore and kill server
  pthread_cond_destroy( &eventShutdown);

  /*
    Exit main loop on main thread, so kill will be done from
    main thread (this is thread 2)
  */
  abort_loop = 1;

  // unblock select()
  so_cancel( ip_sock);
  so_cancel( unix_sock);

  return 0;
}
#endif

const char *load_default_groups[]= { "mysqld","server",0 };

#ifdef HAVE_LIBWRAP
char *libwrapName=NULL;
#endif

void open_log(MYSQL_LOG *log, const char *hostname,
		     const char *opt_name, const char *extension,
		     enum_log_type type, bool read_append,
	             bool no_auto_events)
{
  char tmp[FN_REFLEN];
  if (!opt_name || !opt_name[0])
  {
    /*
      TODO: The following should be using fn_format();  We just need to
      first change fn_format() to cut the file name if it's too long.
    */
    strmake(tmp,hostname,FN_REFLEN-5);
    strmov(strcend(tmp,'.'),extension);
    opt_name=tmp;
  }
  // get rid of extention if the log is binary to avoid problems
  if (type == LOG_BIN)
  {
    char *p = fn_ext(opt_name);
    if (p)
    {
      uint length=(uint) (p-opt_name);
      strmake(tmp,opt_name,min(length,FN_REFLEN));
      opt_name=tmp;
    }
  }
  log->open(opt_name,type,0,(read_append) ? SEQ_READ_APPEND : WRITE_CACHE,
	    no_auto_events);
}



#ifdef __WIN__
int win_main(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
{
  DEBUGGER_OFF;

  my_umask=0660;		// Default umask for new files
  my_umask_dir=0700;		// Default umask for new directories
  MY_INIT(argv[0]);		// init my_sys library & pthreads
  tzset();			// Set tzname

  start_time=time((time_t*) 0);
#ifdef OS2
  {
    // fix timezone for daylight saving
    struct tm *ts = localtime(&start_time);
    if (ts->tm_isdst > 0)
      _timezone -= 3600;
  }
#endif
#ifdef HAVE_TZNAME
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
  {
    struct tm tm_tmp;
    localtime_r(&start_time,&tm_tmp);
    strmov(time_zone,tzname[tm_tmp.tm_isdst != 0 ? 1 : 0]);
  }
#else
  {
    struct tm *start_tm;
    start_tm=localtime(&start_time);
    strmov(time_zone,tzname[start_tm->tm_isdst != 0 ? 1 : 0]);
  }
#endif
#endif

  if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0)
    strmov(glob_hostname,"mysql");
  strmov(pidfile_name,glob_hostname);
  strmov(strcend(pidfile_name,'.'),".pid");	// Add extension
#ifndef DBUG_OFF
  strxmov(strend(server_version),MYSQL_SERVER_SUFFIX,"-debug",NullS);
#else
  strmov(strend(server_version),MYSQL_SERVER_SUFFIX);
#endif
#ifdef _CUSTOMSTARTUPCONFIG_
  if (_cust_check_startup())
  {
    /* _cust_check_startup will report startup failure error */
    exit( 1 );
  }
#endif
  load_defaults("my",load_default_groups,&argc,&argv);
  defaults_argv=argv;
  mysql_tmpdir=getenv("TMPDIR");	/* Use this if possible */
#if defined( __WIN__) || defined(OS2)
  if (!mysql_tmpdir)
    mysql_tmpdir=getenv("TEMP");
  if (!mysql_tmpdir)
    mysql_tmpdir=getenv("TMP");
#endif
  if (!mysql_tmpdir || !mysql_tmpdir[0])
    mysql_tmpdir=(char*) P_tmpdir;		/* purecov: inspected */

  set_options();
  get_options(argc,argv);
  if (opt_log || opt_update_log || opt_slow_log || opt_bin_log)
    strcat(server_version,"-log");
  DBUG_PRINT("info",("%s  Ver %s for %s on %s\n",my_progname,
		     server_version, SYSTEM_TYPE,MACHINE_TYPE));

  /* These must be set early */

  (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW);
  (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW);
  (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW);
  (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW);
  (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_server_id, MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
  (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
  (void) pthread_cond_init(&COND_thread_count,NULL);
  (void) pthread_cond_init(&COND_refresh,NULL);
  (void) pthread_cond_init(&COND_thread_cache,NULL);
  (void) pthread_cond_init(&COND_flush_thread_cache,NULL);
  (void) pthread_cond_init(&COND_manager,NULL);
  (void) pthread_cond_init(&COND_rpl_status, NULL);
  init_signals();

  if (set_default_charset_by_name(default_charset, MYF(MY_WME)))
    exit( 1 );
  charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS));

#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
  {
    ssl_acceptor_fd = new_VioSSLAcceptorFd(opt_ssl_key, opt_ssl_cert,
			   opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher);
    DBUG_PRINT("info",("ssl_acceptor_fd: %p",ssl_acceptor_fd));
    if (!ssl_acceptor_fd)
      opt_use_ssl=0;
    /* having ssl_acceptor_fd!=0 signals the use of SSL */
  }
#endif /* HAVE_OPENSSL */

#ifdef HAVE_LIBWRAP
  libwrapName= my_progname+dirname_length(my_progname);
  openlog(libwrapName, LOG_PID, LOG_AUTH);
#endif

  if (!(opt_specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(),CONNECT_PRIOR);
  /* Parameter for threads created for connections */
  (void) pthread_attr_init(&connection_attrib);
  (void) pthread_attr_setdetachstate(&connection_attrib,
				     PTHREAD_CREATE_DETACHED);
  pthread_attr_setstacksize(&connection_attrib,thread_stack);

  if (!(opt_specialflag & SPECIAL_NO_PRIOR))
    my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);
  pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);

#if defined( SET_RLIMIT_NOFILE) || defined( OS2)
  /* connections and databases needs lots of files */
  {
    uint wanted_files=10+(uint) max(max_connections*5,
				    max_connections+table_cache_size*2);
    set_if_bigger(wanted_files, open_files_limit);
    // Note that some system returns 0 if we succeed here:
    uint files=set_maximum_open_files(wanted_files);
    if (files && files < wanted_files && ! open_files_limit)
    {
      max_connections=	(ulong) min((files-10),max_connections);
      table_cache_size= (ulong) max((files-10-max_connections)/2,64);
      DBUG_PRINT("warning",
		 ("Changed limits: max_connections: %ld  table_cache: %ld",
		  max_connections,table_cache_size));
      sql_print_error("Warning: Changed limits: max_connections: %ld  table_cache: %ld",max_connections,table_cache_size);
    }
  }
#endif
  unireg_init(opt_specialflag); /* Set up extern variabels */
  init_errmessage();		/* Read error messages from file */
  lex_init();
  item_init();
  mysys_uses_curses=0;
#ifdef USE_REGEX
  regex_init();
#endif
  select_thread=pthread_self();
  select_thread_in_use=1;
  if (use_temp_pool && bitmap_init(&temp_pool,1024))
    unireg_abort(1);

  /*
  ** We have enough space for fiddling with the argv, continue
  */
  umask(((~my_umask) & 0666));
  if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
  {
    unireg_abort(1);				/* purecov: inspected */
  }
  mysql_data_home[0]=FN_CURLIB;		// all paths are relative from here
  mysql_data_home[1]=0;
  server_init();
  table_cache_init();
  hostname_cache_init();
  sql_cache_init();
  randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
  reset_floating_point_exceptions();
  init_thr_lock();
  init_slave_list();
  
  /* Setup log files */
  if (opt_log)
    open_log(&mysql_log, glob_hostname, opt_logname, ".log", LOG_NORMAL);
  if (opt_update_log)
  {
    open_log(&mysql_update_log, glob_hostname, opt_update_logname, "",
	     LOG_NEW);
    using_update_log=1;
  }
 
  init_slave();
  
  if (opt_bin_log && !server_id)
  {
    server_id= !master_host ? 1 : 2;
    switch (server_id) {
#ifdef EXTRA_DEBUG
    case 1:
      sql_print_error("\
Warning: You have enabled the binary log, but you haven't set server-id:\n\
Updates will be logged to the binary log, but connections to slaves will\n\
not be accepted.");
      break;
#endif
    case 2:
      sql_print_error("\
Warning: You should set server-id to a non-0 value if master_host is set.\n\
The server will not act as a slave.");
      break;
    }
  }
  if (opt_bin_log)
  {
    if (!opt_bin_logname)
    {
      char tmp[FN_REFLEN];
      /* TODO: The following should be using fn_format();  We just need to
	 first change fn_format() to cut the file name if it's too long.
      */
      strmake(tmp,glob_hostname,FN_REFLEN-5);
      strmov(strcend(tmp,'.'),"-bin");
      opt_bin_logname=my_strdup(tmp,MYF(MY_WME));
    }
    mysql_bin_log.set_index_file_name(opt_binlog_index_name);
    open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
	     LOG_BIN);
    using_update_log=1;
  }

  if (opt_slow_log)
    open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
	     LOG_NORMAL);
  if (ha_init())
  {
    sql_print_error("Can't init databases");
    exit(1);
  }
  ha_key_cache();
#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT)
  if (locked_in_memory && !geteuid())
  {
    if (mlockall(MCL_CURRENT))
    {
      sql_print_error("Warning: Failed to lock memory. Errno: %d\n",errno);
    }
    else
      locked_in_memory=1;
  }
#else
  locked_in_memory=0;
#endif

  if (opt_myisam_log)
    (void) mi_log( 1 );
  ft_init_stopwords(ft_precompiled_stopwords);

#ifdef __WIN__
#define MYSQL_ERR_FILE "mysql.err"
  if (!opt_console)
  {
    freopen(MYSQL_ERR_FILE,"a+",stdout);
    freopen(MYSQL_ERR_FILE,"a+",stderr);
    FreeConsole();				// Remove window
  }
#endif

  /*
    init signals & alarm
    After this we can't quit by a simple unireg_abort
  */
  error_handler_hook = my_message_sql;
  if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) ||
      pthread_key_create(&THR_MALLOC,NULL))
  {
    sql_print_error("Can't create thread-keys");
    exit(1);
  }
  start_signal_handler();				// Creates pidfile
  if (acl_init(opt_noacl))
  {
    select_thread_in_use=0;
    (void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL);
#ifndef __WIN__
    if (!opt_bootstrap)
      (void) my_delete(pidfile_name,MYF(MY_WME));	// Not needed anymore
#endif
    exit(1);
  }
  if (!opt_noacl)
    (void) grant_init();
  if (max_user_connections)
    init_max_user_conn();

#ifdef HAVE_DLOPEN
  if (!opt_noacl)
    udf_init();
#endif

  if (opt_bootstrap)
  {
    int error=bootstrap(stdin);
    end_thr_alarm();				// Don't allow alarms
    unireg_abort(error ? 1 : 0);
  }
  if (opt_init_file)
  {
    if (read_init_file(opt_init_file))
    {
      end_thr_alarm();				// Don't allow alarms
      unireg_abort(1);
    }
  }
  (void) thr_setconcurrency(concurrency);	// 10 by default
#ifdef __WIN__			        //IRENA
  {
    hEventShutdown=CreateEvent(0, FALSE, FALSE, "MySqlShutdown");
    pthread_t hThread;
    if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
      sql_print_error("Warning: Can't create thread to handle shutdown requests");

    // On "Stop Service" we have to do regular shutdown
    Service.SetShutdownEvent(hEventShutdown);
  }
#endif
#ifdef OS2
  {
    pthread_cond_init( &eventShutdown, NULL);
    pthread_t hThread;
    if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
      sql_print_error("Warning: Can't create thread to handle shutdown requests");
  }
#endif

  if (
#ifdef HAVE_BERKELEY_DB
      !berkeley_skip ||
#endif
      (flush_time && flush_time != ~(ulong) 0L))
  {
    pthread_t hThread;
    if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
      sql_print_error("Warning: Can't create thread to manage maintenance");
  }

  printf(ER(ER_READY),my_progname,server_version,"");
  fflush(stdout);

#ifdef __NT__
  if (hPipe == INVALID_HANDLE_VALUE && !have_tcpip)
  {
    sql_print_error("TCP/IP must be installed on Win98 platforms");
  }
  else
  {
    pthread_mutex_lock(&LOCK_thread_count);
    (void) pthread_cond_init(&COND_handler_count,NULL);
    {
      pthread_t hThread;
      handler_count=0;
      if ( hPipe != INVALID_HANDLE_VALUE )
      {
	handler_count++;
	if (pthread_create(&hThread,&connection_attrib,
			   handle_connections_namedpipes, 0))
	{
	  sql_print_error("Warning: Can't create thread to handle named pipes");
	  handler_count--;
	}
      }
      if (have_tcpip && !opt_disable_networking)
      {
	handler_count++;
	if (pthread_create(&hThread,&connection_attrib,
			   handle_connections_sockets, 0))
	{
	  sql_print_error("Warning: Can't create thread to handle named pipes");
	  handler_count--;
	}
      }
      while (handler_count > 0)
      {
	pthread_cond_wait(&COND_handler_count,&LOCK_thread_count);
      }
    }
    pthread_mutex_unlock(&LOCK_thread_count);
  }
#else
  handle_connections_sockets(0);
#ifdef EXTRA_DEBUG2
  sql_print_error("Exiting main thread");
#endif
#endif /* __NT__ */

  /* (void) pthread_attr_destroy(&connection_attrib); */

  DBUG_PRINT("quit",("Exiting main thread"));

#ifndef __WIN__
#ifdef EXTRA_DEBUG2
  sql_print_error("Before Lock_thread_count");
#endif
  (void) pthread_mutex_lock(&LOCK_thread_count);
  DBUG_PRINT("quit", ("Got thread_count mutex"));
  select_thread_in_use=0;			// For close_connections
  (void) pthread_cond_broadcast(&COND_thread_count);
  (void) pthread_mutex_unlock(&LOCK_thread_count);
#ifdef EXTRA_DEBUG2
  sql_print_error("After lock_thread_count");
#endif
#else
  if (Service.IsNT())
  {
    if(start_mode)
    {
      if (WaitForSingleObject(hEventShutdown,1000)==WAIT_TIMEOUT)
        Service.Stop();
    }
    else
    {
      Service.SetShutdownEvent(0);
      if(hEventShutdown) CloseHandle(hEventShutdown);
    }
  }
  else
  {
    Service.SetShutdownEvent(0);
    if(hEventShutdown) CloseHandle(hEventShutdown);
  }
#endif
#ifdef HAVE_OPENSSL
  my_free((gptr)ssl_acceptor_fd,MYF(MY_ALLOW_ZERO_PTR));
#endif /* HAVE_OPENSSL */
  /* Wait until cleanup is done */
  (void) pthread_mutex_lock(&LOCK_thread_count);
  DBUG_PRINT("quit", ("Got thread_count mutex for clean up wait"));
  
  while (!ready_to_exit)
  {
    DBUG_PRINT("quit", ("not yet ready to exit"));
    pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
  }
  DBUG_PRINT("quit", ("ready to exit"));
  (void) pthread_mutex_unlock(&LOCK_thread_count);
  my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
  exit(0);
  return(0);					/* purecov: deadcode */
}


#ifdef __WIN__
/* ------------------------------------------------------------------------
   main and thread entry function for Win32
   (all this is needed only to run mysqld as a service on WinNT)
 -------------------------------------------------------------------------- */
int mysql_service(void *p)
{
  win_main(Service.my_argc, Service.my_argv);
  return 0;
}

int main(int argc, char **argv)
{
  // check  environment variable OS
  if (Service.GetOS())	// "OS" defined; Should be NT
  {
    if (argc == 2)
    {
      char path[FN_REFLEN];
      my_path(path, argv[0], "");		   // Find name in path
      fn_format(path,argv[0],path,"",1+4+16);    // Force use of full path

      if (!strcmp(argv[1],"-install") || !strcmp(argv[1],"--install"))
      {
	Service.Install(1,MYSQL_SERVICENAME,MYSQL_SERVICENAME,path);
	return 0;
      }
      else if (!strcmp(argv[1],"-install-manual") || !strcmp(argv[1],"--install-manual"))
      {
        Service.Install(0,MYSQL_SERVICENAME,MYSQL_SERVICENAME,path);
	return 0;
      }
      else if (!strcmp(argv[1],"-remove") || !strcmp(argv[1],"--remove"))
      {
	Service.Remove(MYSQL_SERVICENAME);
	return 0;
      }
    }
    else if (argc == 1)		   // No arguments; start as a service
    {
      // init service
      start_mode = 1;
      long tmp=Service.Init(MYSQL_SERVICENAME,mysql_service);
      return 0;
    }
  }

  /*
    This is a WIN95 machine or a start of mysqld as a standalone program
    we have to pass the arguments, in case of NT-service this will be done
    by ServiceMain()
  */

  Service.my_argc=argc;
  Service.my_argv=argv;
  mysql_service(NULL);
  return 0;
}
/* ------------------------------------------------------------------------ */
#endif


static int bootstrap(FILE *file)
{
  THD *thd= new THD;
  int error;
  thd->bootstrap=1;
  thd->client_capabilities=0;
  my_net_init(&thd->net,(st_vio*) 0);
  thd->max_packet_length=thd->net.max_packet;
  thd->master_access= ~0;
  thd->thread_id=thread_id++;
  thread_count++;

  bootstrap_file=file;
  if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
		     (void*) thd))
  {
    sql_print_error("Warning: Can't create thread to handle bootstrap");    
    return -1;
  }
  /* Wait for thread to die */
  (void) pthread_mutex_lock(&LOCK_thread_count);
  while (thread_count)
  {
    (void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
    DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
  }
  (void) pthread_mutex_unlock(&LOCK_thread_count);
  error= thd->fatal_error;
  net_end(&thd->net);
  thd->cleanup();
  delete thd;
  return error;
}

static bool read_init_file(char *file_name)
{
  FILE *file;
  DBUG_ENTER("read_init_file");
  DBUG_PRINT("enter",("name: %s",file_name));
  if (!(file=my_fopen(file_name,O_RDONLY,MYF(MY_WME))))
    return(1);
  bootstrap(file);				/* Ignore errors from this */
  (void) my_fclose(file,MYF(MY_WME));
  return 0;
}


static void create_new_thread(THD *thd)
{
  DBUG_ENTER("create_new_thread");

  NET *net=&thd->net;				// For easy ref
  net->timeout = (uint) connect_timeout;	// Timeout for read
  if (protocol_version > 9)
    net->return_errno=1;

  /* don't allow too many connections */
  if (thread_count - delayed_insert_threads >= max_connections+1 || abort_loop)
  {
    DBUG_PRINT("error",("Too many connections"));
    close_connection(net,ER_CON_COUNT_ERROR);
    delete thd;
    DBUG_VOID_RETURN;
  }
  if (pthread_mutex_lock(&LOCK_thread_count))
  {
    DBUG_PRINT("error",("Can't lock LOCK_thread_count"));
    close_connection(net,ER_OUT_OF_RESOURCES);
    delete thd;
    DBUG_VOID_RETURN;
  }
  if (thread_count-delayed_insert_threads > max_used_connections)
    max_used_connections=thread_count-delayed_insert_threads;
  thd->thread_id=thread_id++;
  for (uint i=0; i < 8 ; i++)			// Generate password teststring
    thd->scramble[i]= (char) (rnd(&sql_rand)*94+33);
  thd->scramble[8]=0;
  thd->rand=sql_rand;
  thd->real_id=pthread_self();			// Keep purify happy

  /* Start a new thread to handle connection */
#ifdef ONE_THREAD
  if (test_flags & TEST_NO_THREADS)		// For debugging under Linux
  {
    thread_cache_size=0;			// Safety
    thread_count++;
    threads.append(thd);
    thd->real_id=pthread_self();
    (void) pthread_mutex_unlock(&LOCK_thread_count);
    handle_one_connection((void*) thd);
  }
  else
#endif
  {
    if (cached_thread_count > wake_thread)
    {
      start_cached_thread(thd);
      (void) pthread_mutex_unlock(&LOCK_thread_count);
    }
    else
    {
      int error;
      thread_count++;
      thread_created++;
      threads.append(thd);
      DBUG_PRINT("info",(("creating thread %d"), thd->thread_id));
      thd->connect_time = time(NULL);
      if ((error=pthread_create(&thd->real_id,&connection_attrib,
				handle_one_connection,
				(void*) thd)))
      {
	DBUG_PRINT("error",
		   ("Can't create thread to handle request (error %d)",
		    error));
	thread_count--;
	thd->killed=1;				// Safety
	(void) pthread_mutex_unlock(&LOCK_thread_count);
	net_printf(net,ER_CANT_CREATE_THREAD,error);
	(void) pthread_mutex_lock(&LOCK_thread_count);
	close_connection(net,0,0);
	delete thd;
	(void) pthread_mutex_unlock(&LOCK_thread_count);
	DBUG_VOID_RETURN;
      }
      
      (void) pthread_mutex_unlock(&LOCK_thread_count);
    }
  }
  DBUG_PRINT("info",("Thread created"));
  DBUG_VOID_RETURN;
}

#ifdef SIGNALS_DONT_BREAK_READ
inline void kill_broken_server()
{
  /* hack to get around signals ignored in syscalls for problem OS's */
  if (unix_sock == INVALID_SOCKET || ip_sock ==INVALID_SOCKET)
  {
    select_thread_in_use = 0;
    kill_server((void*)MYSQL_KILL_SIGNAL); /* never returns */
  }
}
#define MAYBE_BROKEN_SYSCALL kill_broken_server();
#else
#define MAYBE_BROKEN_SYSCALL
#endif

	/* Handle new connections and spawn new process to handle them */

pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
{
  my_socket sock,new_sock;
  uint error_count=0;
  uint max_used_connection= (uint) (max(ip_sock,unix_sock)+1);
  fd_set readFDs,clientFDs;
  THD *thd;
  struct sockaddr_in cAddr;
  int ip_flags=0,socket_flags=0,flags;
  st_vio *vio_tmp;
  DBUG_ENTER("handle_connections_sockets");

  LINT_INIT(new_sock);

  (void) my_pthread_getprio(pthread_self());		// For debugging

  FD_ZERO(&clientFDs);
  if (ip_sock != INVALID_SOCKET)
  {
    FD_SET(ip_sock,&clientFDs);
#ifdef HAVE_FCNTL
    ip_flags = fcntl(ip_sock, F_GETFL, 0);
#endif
  }
#ifdef HAVE_SYS_UN_H
  FD_SET(unix_sock,&clientFDs);
#ifdef HAVE_FCNTL
  socket_flags=fcntl(unix_sock, F_GETFL, 0);
#endif
#endif

  DBUG_PRINT("general",("Waiting for connections."));
  MAYBE_BROKEN_SYSCALL;
  while (!abort_loop)
  {
    readFDs=clientFDs;
#ifdef HPUX
    if (select(max_used_connection,(int*) &readFDs,0,0,0) < 0)
      continue;
#else
    if (select((int) max_used_connection,&readFDs,0,0,0) < 0)
    {
      if (socket_errno != SOCKET_EINTR)
      {
	if (!select_errors++ && !abort_loop)	/* purecov: inspected */
	  sql_print_error("mysqld: Got error %d from select",socket_errno); /* purecov: inspected */
      }
      MAYBE_BROKEN_SYSCALL
      continue;
    }
#endif	/* HPUX */
    if (abort_loop)
    {
      MAYBE_BROKEN_SYSCALL;
      break;
    }
    /*
    ** Is this a new connection request
    */

#ifdef HAVE_SYS_UN_H
    if (FD_ISSET(unix_sock,&readFDs))
    {
      sock = unix_sock;
      flags= socket_flags;
    }
    else
#endif
    {
      sock = ip_sock;
      flags= ip_flags;
    }

#if !defined(NO_FCNTL_NONBLOCK)
    if (!(test_flags & TEST_BLOCKING))
    {
#if defined(O_NONBLOCK)
      fcntl(sock, F_SETFL, flags | O_NONBLOCK);
#elif defined(O_NDELAY)
      fcntl(sock, F_SETFL, flags | O_NDELAY);
#endif
    }
#endif /* NO_FCNTL_NONBLOCK */
    for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
    {
      size_socket length=sizeof(struct sockaddr_in);
      new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr),
			&length);
      if (new_sock != INVALID_SOCKET ||
	  (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN))
	break;
      MAYBE_BROKEN_SYSCALL;
#if !defined(NO_FCNTL_NONBLOCK)
      if (!(test_flags & TEST_BLOCKING))
      {
	if (retry == MAX_ACCEPT_RETRY - 1)
	  fcntl(sock, F_SETFL, flags);		// Try without O_NONBLOCK
      }
#endif
    }
#if !defined(NO_FCNTL_NONBLOCK)
    if (!(test_flags & TEST_BLOCKING))
      fcntl(sock, F_SETFL, flags);
#endif
    if (new_sock == INVALID_SOCKET)
    {
      if ((error_count++ & 255) == 0)		// This can happen often
	sql_perror("Error in accept");
      MAYBE_BROKEN_SYSCALL;
      if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE)
	sleep(1);				// Give other threads some time
      continue;
    }

#ifdef HAVE_LIBWRAP
    {
      if (sock == ip_sock)
      {
	struct request_info req;
	signal(SIGCHLD, SIG_DFL);
	request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL);
	fromhost(&req);
	if (!hosts_access(&req))
	{
	  // This may be stupid but refuse() includes an exit(0)
	  // which we surely don't want...
	  // clean_exit() - same stupid thing ...
	  syslog(deny_severity, "refused connect from %s", eval_client(&req));
	  if (req.sink)
	    ((void (*)(int))req.sink)(req.fd);

	  // C++ sucks (the gibberish in front just translates the supplied
	  // sink function pointer in the req structure from a void (*sink)();
	  // to a void(*sink)(int) if you omit the cast, the C++ compiler
	  // will cry...

	  (void) shutdown(new_sock,2);  // This looks fine to me...
	  (void) closesocket(new_sock);
	  continue;
	}
      }
    }
#endif /* HAVE_LIBWRAP */

    {
      size_socket dummyLen;
      struct sockaddr dummy;
      dummyLen = sizeof(struct sockaddr);
      if (getsockname(new_sock,&dummy, &dummyLen) < 0)
      {
	sql_perror("Error on new connection socket");
	(void) shutdown(new_sock,2);
	(void) closesocket(new_sock);
	continue;
      }
    }

    /*
    ** Don't allow too many connections
    */

    if (!(thd= new THD))
    {
      (void) shutdown(new_sock,2); VOID(closesocket(new_sock));
      continue;
    }
    if (!(vio_tmp=vio_new(new_sock,
			  sock == unix_sock ? VIO_TYPE_SOCKET :
			  VIO_TYPE_TCPIP,
			  sock == unix_sock)) ||
	my_net_init(&thd->net,vio_tmp))
    {
      if (vio_tmp)
	vio_delete(vio_tmp);
      else
      {
	(void) shutdown(new_sock,2);
	(void) closesocket(new_sock);
      }
      delete thd;
      continue;
    }
    if (sock == unix_sock)
      thd->host=(char*) localhost;
    create_new_thread(thd);
  }

#ifdef OS2
  // kill server must be invoked from thread 1!
  kill_server(MYSQL_KILL_SIGNAL);
#endif

#ifdef __NT__
  pthread_mutex_lock(&LOCK_thread_count);
  handler_count--;
  pthread_mutex_unlock(&LOCK_thread_count);
  pthread_cond_signal(&COND_handler_count);
#endif
  DBUG_RETURN(0);
}


#ifdef __NT__
pthread_handler_decl(handle_connections_namedpipes,arg)
{
  HANDLE hConnectedPipe;
  BOOL fConnected;
  THD *thd;
  my_thread_init();
  DBUG_ENTER("handle_connections_namedpipes");
  (void) my_pthread_getprio(pthread_self());		// For debugging

  DBUG_PRINT("general",("Waiting for named pipe connections."));
  while (!abort_loop)
  {
    /* wait for named pipe connection */
    fConnected = ConnectNamedPipe( hPipe, NULL );
    if (abort_loop)
      break;
    if ( !fConnected )
      fConnected = GetLastError() == ERROR_PIPE_CONNECTED;
    if ( !fConnected )
    {
      CloseHandle( hPipe );
      if ((hPipe = CreateNamedPipe(szPipeName,
				   PIPE_ACCESS_DUPLEX,
				   PIPE_TYPE_BYTE |
				   PIPE_READMODE_BYTE |
				   PIPE_WAIT,
				   PIPE_UNLIMITED_INSTANCES,
				   (int) net_buffer_length,
				   (int) net_buffer_length,
				   NMPWAIT_USE_DEFAULT_WAIT,
				   &saPipeSecurity )) ==
	  INVALID_HANDLE_VALUE )
      {
	sql_perror("Can't create new named pipe!");
	break;					// Abort
      }
    }
    hConnectedPipe = hPipe;
    /* create new pipe for new connection */
    if ((hPipe = CreateNamedPipe(szPipeName,
				 PIPE_ACCESS_DUPLEX,
				 PIPE_TYPE_BYTE |
				 PIPE_READMODE_BYTE |
				 PIPE_WAIT,
				 PIPE_UNLIMITED_INSTANCES,
				 (int) net_buffer_length,
				 (int) net_buffer_length,
				 NMPWAIT_USE_DEFAULT_WAIT,
				 &saPipeSecurity)) ==
	INVALID_HANDLE_VALUE)
    {
      sql_perror("Can't create new named pipe!");
      hPipe=hConnectedPipe;
      continue;					// We have to try again
    }

    if ( !(thd = new THD))
    {
      DisconnectNamedPipe( hConnectedPipe );
      CloseHandle( hConnectedPipe );
      continue;
    }
    if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) ||
	my_net_init(&thd->net, thd->net.vio))
    {
      close_connection(&thd->net,ER_OUT_OF_RESOURCES);
      delete thd;
      continue;
    }
    /* host name is unknown */
    thd->host = my_strdup(localhost,MYF(0)); /* Host is unknown */
    create_new_thread(thd);
  }

  pthread_mutex_lock(&LOCK_thread_count);
  handler_count--;
  pthread_cond_signal(&COND_handler_count);
  pthread_mutex_unlock(&LOCK_thread_count);
  DBUG_RETURN(0);
}
#endif /* __NT__ */


/******************************************************************************
** handle start options
******************************************************************************/

enum options {
               OPT_ISAM_LOG=256,            OPT_SKIP_NEW, 
               OPT_SKIP_GRANT,              OPT_SKIP_LOCK, 
               OPT_ENABLE_LOCK,             OPT_USE_LOCKING,
               OPT_SOCKET,                  OPT_UPDATE_LOG, 
               OPT_BIN_LOG,                 OPT_SKIP_RESOLVE, 
               OPT_SKIP_NETWORKING,         OPT_BIN_LOG_INDEX,
               OPT_BIND_ADDRESS,            OPT_PID_FILE,
               OPT_SKIP_PRIOR,              OPT_BIG_TABLES,    
               OPT_STANDALONE,              OPT_ONE_THREAD,
               OPT_CONSOLE,                 OPT_LOW_PRIORITY_UPDATES,
               OPT_SKIP_HOST_CACHE,         OPT_LONG_FORMAT,   
               OPT_FLUSH,                   OPT_SAFE, 
               OPT_BOOTSTRAP,               OPT_SKIP_SHOW_DB,
               OPT_TABLE_TYPE,              OPT_INIT_FILE,   
               OPT_DELAY_KEY_WRITE,         OPT_SLOW_QUERY_LOG, 
               OPT_SKIP_DELAY_KEY_WRITE,    OPT_CHARSETS_DIR,
               OPT_BDB_HOME,                OPT_BDB_LOG,  
               OPT_BDB_TMP,                 OPT_BDB_NOSYNC,
               OPT_BDB_LOCK,                OPT_BDB_SKIP, 
               OPT_BDB_NO_RECOVER,	    OPT_BDB_SHARED,
	       OPT_MASTER_HOST,             OPT_MASTER_USER,
               OPT_MASTER_PASSWORD,         OPT_MASTER_PORT,
               OPT_MASTER_INFO_FILE,        OPT_MASTER_CONNECT_RETRY,
	       OPT_MASTER_RETRY_COUNT,
	       OPT_MASTER_SSL,             OPT_MASTER_SSL_KEY,
	       OPT_MASTER_SSL_CERT,            
               OPT_SQL_BIN_UPDATE_SAME,     OPT_REPLICATE_DO_DB,      
               OPT_REPLICATE_IGNORE_DB,     OPT_LOG_SLAVE_UPDATES,
               OPT_BINLOG_DO_DB,            OPT_BINLOG_IGNORE_DB,
               OPT_WANT_CORE,               OPT_SKIP_CONCURRENT_INSERT,
               OPT_MEMLOCK,                 OPT_MYISAM_RECOVER,
               OPT_REPLICATE_REWRITE_DB,    OPT_SERVER_ID, 
               OPT_SKIP_SLAVE_START,        OPT_SKIP_INNOBASE,
               OPT_SAFEMALLOC_MEM_LIMIT,    OPT_REPLICATE_DO_TABLE, 
               OPT_REPLICATE_IGNORE_TABLE,  OPT_REPLICATE_WILD_DO_TABLE, 
               OPT_REPLICATE_WILD_IGNORE_TABLE, 
               OPT_DISCONNECT_SLAVE_EVENT_COUNT, 
               OPT_ABORT_SLAVE_EVENT_COUNT,
	       OPT_INNODB_DATA_HOME_DIR,
               OPT_INNODB_DATA_FILE_PATH,
	       OPT_INNODB_LOG_GROUP_HOME_DIR, 
               OPT_INNODB_LOG_ARCH_DIR, 
               OPT_INNODB_LOG_ARCHIVE, 
               OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT, 
               OPT_INNODB_FLUSH_METHOD, 
               OPT_INNODB_FAST_SHUTDOWN, 
               OPT_SAFE_SHOW_DB,
	       OPT_INNODB_SKIP, OPT_SKIP_SAFEMALLOC,
               OPT_TEMP_POOL, OPT_TX_ISOLATION,
	       OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
	       OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
	       OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
               OPT_DO_PSTACK, OPT_REPORT_HOST,
	       OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT,
               OPT_SHOW_SLAVE_AUTH_INFO, OPT_OLD_RPL_COMPAT,
               OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
	       OPT_RPL_RECOVERY_RANK,OPT_INIT_RPL_ROLE,
	       OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE
};

static struct option long_options[] = {
  {"ansi",                  no_argument,       0, 'a'},
  {"basedir",               required_argument, 0, 'b'},
#ifdef HAVE_BERKELEY_DB
  {"bdb-home",              required_argument, 0, (int) OPT_BDB_HOME},
  {"bdb-lock-detect",       required_argument, 0, (int) OPT_BDB_LOCK},
  {"bdb-logdir",            required_argument, 0, (int) OPT_BDB_LOG},
  {"bdb-no-recover",        no_argument,       0, (int) OPT_BDB_NO_RECOVER},
  {"bdb-no-sync",           no_argument,       0, (int) OPT_BDB_NOSYNC},
  {"bdb-shared-data",       no_argument,       0, (int) OPT_BDB_SHARED},
  {"bdb-tmpdir",            required_argument, 0, (int) OPT_BDB_TMP},
#endif
  {"big-tables",            no_argument,       0, (int) OPT_BIG_TABLES},
  {"binlog-do-db",          required_argument, 0, (int) OPT_BINLOG_DO_DB},
  {"binlog-ignore-db",      required_argument, 0, (int) OPT_BINLOG_IGNORE_DB},
  {"bind-address",          required_argument, 0, (int) OPT_BIND_ADDRESS},
  {"bootstrap",             no_argument,       0, (int) OPT_BOOTSTRAP},
#ifdef __WIN__
  {"console",               no_argument,       0, (int) OPT_CONSOLE},
#endif
  {"core-file",             no_argument,       0, (int) OPT_WANT_CORE},
  {"chroot",                required_argument, 0, 'r'},
  {"character-sets-dir",    required_argument, 0, (int) OPT_CHARSETS_DIR},
  {"datadir",               required_argument, 0, 'h'},
  {"debug",                 optional_argument, 0, '#'},
  {"default-character-set", required_argument, 0, 'C'},
  {"default-table-type",    required_argument, 0, (int) OPT_TABLE_TYPE},
  {"delay-key-write-for-all-tables",
                            no_argument,       0, (int) OPT_DELAY_KEY_WRITE},
  {"enable-locking",        no_argument,       0, (int) OPT_ENABLE_LOCK},
  {"enable-pstack",         no_argument,       0, (int) OPT_DO_PSTACK},
  {"exit-info",             optional_argument, 0, 'T'},
  {"flush",                 no_argument,       0, (int) OPT_FLUSH},
  {"init-rpl-role",         required_argument, 0, (int) OPT_INIT_RPL_ROLE},
  /* We must always support this option to make scripts like mysqltest easier
     to do */
  {"innodb_data_file_path", required_argument, 0,
     OPT_INNODB_DATA_FILE_PATH},
#ifdef HAVE_INNOBASE_DB
  {"innodb_data_home_dir", required_argument, 0,
     OPT_INNODB_DATA_HOME_DIR},
  {"innodb_log_group_home_dir", required_argument, 0,
    OPT_INNODB_LOG_GROUP_HOME_DIR},
  {"innodb_log_arch_dir", required_argument, 0,
    OPT_INNODB_LOG_ARCH_DIR},
  {"innodb_log_archive", optional_argument, 0,
     OPT_INNODB_LOG_ARCHIVE},
  {"innodb_flush_log_at_trx_commit", optional_argument, 0,
     OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT},
  {"innodb_fast_shutdown", optional_argument, 0,
     OPT_INNODB_FAST_SHUTDOWN},
  {"innodb_flush_method", required_argument, 0,
    OPT_INNODB_FLUSH_METHOD},
#endif
  {"help",                  no_argument,       0, '?'},
  {"init-file",             required_argument, 0, (int) OPT_INIT_FILE},
  {"log",                   optional_argument, 0, 'l'},
  {"language",              required_argument, 0, 'L'},
  {"log-bin",               optional_argument, 0, (int) OPT_BIN_LOG},
  {"log-bin-index",         required_argument, 0, (int) OPT_BIN_LOG_INDEX},
  {"log-isam",              optional_argument, 0, (int) OPT_ISAM_LOG},
  {"log-update",            optional_argument, 0, (int) OPT_UPDATE_LOG},
  {"log-slow-queries",      optional_argument, 0, (int) OPT_SLOW_QUERY_LOG},
  {"log-long-format",       no_argument,       0, (int) OPT_LONG_FORMAT},
  {"log-slave-updates",     no_argument,       0, (int) OPT_LOG_SLAVE_UPDATES},
  {"low-priority-updates",  no_argument,       0, (int) OPT_LOW_PRIORITY_UPDATES},
  {"master-host",           required_argument, 0, (int) OPT_MASTER_HOST},
  {"master-user",           required_argument, 0, (int) OPT_MASTER_USER},
  {"master-password",       required_argument, 0, (int) OPT_MASTER_PASSWORD},
  {"master-port",           required_argument, 0, (int) OPT_MASTER_PORT},
  {"master-connect-retry",  required_argument, 0, (int) OPT_MASTER_CONNECT_RETRY},
  {"master-retry-count",    required_argument, 0, (int) OPT_MASTER_RETRY_COUNT},
  {"master-info-file",      required_argument, 0, (int) OPT_MASTER_INFO_FILE},
  {"master-ssl",      	    optional_argument, 0, (int) OPT_MASTER_SSL},
  {"master-ssl-key",        optional_argument, 0, (int) OPT_MASTER_SSL_KEY},
  {"master-ssl-cert",       optional_argument, 0, (int) OPT_MASTER_SSL_CERT},
  {"myisam-recover",	    optional_argument, 0, (int) OPT_MYISAM_RECOVER},
  {"memlock",		    no_argument,       0, (int) OPT_MEMLOCK},
  /*
    Option needs to be available for the test case to pass in non-debugging
    mode. is a no-op.
  */
  {"disconnect-slave-event-count",      required_argument, 0,
     (int) OPT_DISCONNECT_SLAVE_EVENT_COUNT},
  {"abort-slave-event-count",      required_argument, 0,
     (int) OPT_ABORT_SLAVE_EVENT_COUNT},
  {"max-binlog-dump-events",      required_argument, 0,
     (int) OPT_MAX_BINLOG_DUMP_EVENTS},
  {"sporadic-binlog-dump-fail", no_argument, 0,
     (int) OPT_SPORADIC_BINLOG_DUMP_FAIL},
  {"safemalloc-mem-limit",  required_argument, 0, (int)
     OPT_SAFEMALLOC_MEM_LIMIT},
  {"new",                   no_argument,       0, 'n'},
#ifdef NOT_YET
  {"no-mix-table-types",    no_argument,       0, (int) OPT_NO_MIX_TYPE},
#endif
  {"old-protocol",	    no_argument,       0, 'o'},
  {"old-rpl-compat",        no_argument,       0, (int) OPT_OLD_RPL_COMPAT},
#ifdef ONE_THREAD
  {"one-thread",            no_argument,       0, (int) OPT_ONE_THREAD},
#endif
  {"pid-file",              required_argument, 0, (int) OPT_PID_FILE},
  {"port",                  required_argument, 0, 'P'},
  {"replicate-do-db",       required_argument, 0, (int) OPT_REPLICATE_DO_DB},
  {"replicate-do-table",       required_argument, 0,
   (int) OPT_REPLICATE_DO_TABLE},
  {"replicate-wild-do-table",  required_argument, 0,
   (int) OPT_REPLICATE_WILD_DO_TABLE},
  {"replicate-ignore-db",      required_argument, 0,
   (int) OPT_REPLICATE_IGNORE_DB},
  {"replicate-ignore-table",   required_argument, 0,
   (int) OPT_REPLICATE_IGNORE_TABLE},
  {"replicate-wild-ignore-table",   required_argument, 0,
   (int) OPT_REPLICATE_WILD_IGNORE_TABLE},
  {"replicate-rewrite-db",     required_argument, 0,
     (int) OPT_REPLICATE_REWRITE_DB},
  // In replication, we may need to tell the other servers how to connect
  {"report-host",           required_argument, 0, (int) OPT_REPORT_HOST},
  {"report-user",           required_argument, 0, (int) OPT_REPORT_USER},
  {"report-password",       required_argument, 0, (int) OPT_REPORT_PASSWORD},
  {"report-port",           required_argument, 0, (int) OPT_REPORT_PORT},
  {"rpl-recovery-rank",     required_argument, 0, (int) OPT_RPL_RECOVERY_RANK},
  {"relay-log",             required_argument, 0, (int) OPT_RELAY_LOG},
  {"relay-log-index",       required_argument, 0, (int) OPT_RELAY_LOG_INDEX},
  {"safe-mode",             no_argument,       0, (int) OPT_SAFE},
  {"safe-show-database",    no_argument,       0, (int) OPT_SAFE_SHOW_DB},
  {"safe-user-create",	    no_argument,       0, (int) OPT_SAFE_USER_CREATE},
  {"server-id",		    required_argument, 0, (int) OPT_SERVER_ID},
  {"set-variable",          required_argument, 0, 'O'},
  {"show-slave-auth-info",  no_argument,       0,
     (int) OPT_SHOW_SLAVE_AUTH_INFO},
  {"skip-bdb",              no_argument,       0, (int) OPT_BDB_SKIP},
  {"skip-innodb",           no_argument,       0, (int) OPT_INNODB_SKIP},
  {"skip-concurrent-insert", no_argument,      0, (int) OPT_SKIP_CONCURRENT_INSERT},
  {"skip-delay-key-write",  no_argument,       0, (int) OPT_SKIP_DELAY_KEY_WRITE},
  {"skip-grant-tables",     no_argument,       0, (int) OPT_SKIP_GRANT},
  {"skip-locking",          no_argument,       0, (int) OPT_SKIP_LOCK},
  {"skip-host-cache",       no_argument,       0, (int) OPT_SKIP_HOST_CACHE},
  {"skip-name-resolve",     no_argument,       0, (int) OPT_SKIP_RESOLVE},
  {"skip-networking",       no_argument,       0, (int) OPT_SKIP_NETWORKING},
  {"skip-new",              no_argument,       0, (int) OPT_SKIP_NEW},
  {"skip-safemalloc",	    no_argument,       0, (int) OPT_SKIP_SAFEMALLOC},
  {"skip-show-database",    no_argument,       0, (int) OPT_SKIP_SHOW_DB},
  {"skip-slave-start",      no_argument,       0, (int) OPT_SKIP_SLAVE_START},
  {"skip-stack-trace",	    no_argument,       0, (int) OPT_SKIP_STACK_TRACE},
  {"skip-symlink",	    no_argument,       0, (int) OPT_SKIP_SYMLINKS},
  {"skip-thread-priority",  no_argument,       0, (int) OPT_SKIP_PRIOR},
  {"relay-log-info-file",      required_argument, 0,
   (int) OPT_RELAY_LOG_INFO_FILE},
  {"slave-load-tmpdir", required_argument, 0, (int) OPT_SLAVE_LOAD_TMPDIR},  
  {"socket",                required_argument, 0, (int) OPT_SOCKET},
  {"sql-bin-update-same",   no_argument,       0, (int) OPT_SQL_BIN_UPDATE_SAME},
  {"sql-mode",              required_argument, 0, (int) OPT_SQL_MODE},
#include "sslopt-longopts.h"
#ifdef __WIN__
  {"standalone",            no_argument,       0, (int) OPT_STANDALONE},
#endif
  {"transaction-isolation", required_argument, 0, (int) OPT_TX_ISOLATION},
  {"temp-pool",             no_argument,       0, (int) OPT_TEMP_POOL},
  {"tmpdir",                required_argument, 0, 't'},
  {"use-locking",           no_argument,       0, (int) OPT_USE_LOCKING},
#ifdef USE_SYMDIR
  {"use-symbolic-links",    no_argument,       0, 's'},
#endif
  {"user",                  required_argument, 0, 'u'},
  {"version",               no_argument,       0, 'V'},
  {"warnings",		    no_argument,       0, 'W'},
  {0, 0, 0, 0}
};

#define LONG_TIMEOUT ((ulong) 3600L*24L*365L)

CHANGEABLE_VAR changeable_vars[] = {
  { "back_log",                (long*) &back_log, 
      50, 1, 65535, 0, 1 },
#ifdef HAVE_BERKELEY_DB
  { "bdb_cache_size",          (long*) &berkeley_cache_size, 
      KEY_CACHE_SIZE, 20*1024, (long) ~0, 0, IO_SIZE },
  {"bdb_log_buffer_size",      (long*) &berkeley_log_buffer_size, 0, 256*1024L,
     ~0L, 0, 1024},
  { "bdb_max_lock",            (long*) &berkeley_max_lock, 
      10000, 0, (long) ~0, 0, 1 },
    /* QQ: The following should be removed soon! */
  { "bdb_lock_max",            (long*) &berkeley_max_lock, 
      10000, 0, (long) ~0, 0, 1 },
#endif
  { "binlog_cache_size",       (long*) &binlog_cache_size,
      32*1024L, IO_SIZE, ~0L, 0, IO_SIZE },
  { "connect_timeout",         (long*) &connect_timeout,
      CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1 },
  { "delayed_insert_timeout",  (long*) &delayed_insert_timeout, 
      DELAYED_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1 },
  { "delayed_insert_limit",    (long*) &delayed_insert_limit, 
      DELAYED_LIMIT, 1, ~0L, 0, 1 },
  { "delayed_queue_size",      (long*) &delayed_queue_size,
      DELAYED_QUEUE_SIZE, 1, ~0L, 0, 1 },
  { "flush_time",              (long*) &flush_time,
      FLUSH_TIME, 0, LONG_TIMEOUT, 0, 1 },
  { "ft_min_word_len",         (long*) &ft_min_word_len,
      4, 1, HA_FT_MAXLEN, 0, 1 },
  { "ft_max_word_len",         (long*) &ft_max_word_len,
      HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1 },
  { "ft_max_word_len_for_sort",(long*) &ft_max_word_len_for_sort,
      20, 4, HA_FT_MAXLEN, 0, 1 },
#ifdef HAVE_INNOBASE_DB
  {"innodb_mirrored_log_groups",
   (long*) &innobase_mirrored_log_groups, 1, 1, 10, 0, 1},
  {"innodb_log_files_in_group",
     (long*) &innobase_log_files_in_group, 2, 2, 100, 0, 1},
  {"innodb_log_file_size",
     (long*) &innobase_log_file_size, 5*1024*1024L, 1*1024*1024L,
     ~0L, 0, 1024*1024L},
  {"innodb_log_buffer_size",
     (long*) &innobase_log_buffer_size, 1024*1024L, 256*1024L,
     ~0L, 0, 1024},
  {"innodb_buffer_pool_size",
     (long*) &innobase_buffer_pool_size, 8*1024*1024L, 1024*1024L,
     ~0L, 0, 1024*1024L},
  {"innodb_additional_mem_pool_size",
   (long*) &innobase_additional_mem_pool_size, 1*1024*1024L, 512*1024L,
     ~0L, 0, 1024},
  {"innodb_file_io_threads",
     (long*) &innobase_file_io_threads, 9, 4, 64, 0, 1},
  {"innodb_lock_wait_timeout",
     (long*) &innobase_lock_wait_timeout, 1024 * 1024 * 1024, 1,
						1024 * 1024 * 1024, 0, 1},
  {"innodb_thread_concurrency",
     (long*) &innobase_thread_concurrency, 8, 1, 1000, 0, 1},
  {"innodb_force_recovery",
     (long*) &innobase_force_recovery, 0, 0, 6, 0, 1},
#endif
  { "interactive_timeout",     (long*) &net_interactive_timeout,
      NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1 },
  { "join_buffer_size",        (long*) &join_buff_size,
      128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
  { "key_buffer_size",         (long*) &keybuff_size,
      KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
  { "long_query_time",         (long*) &long_query_time,
      10, 1, LONG_TIMEOUT, 0, 1 },
  { "lower_case_table_names",  (long*) &lower_case_table_names,
      IF_WIN(1,0), 0, 1, 0, 1 },
  { "max_allowed_packet",      (long*) &max_allowed_packet,
      1024*1024L, 80, 64*1024*1024L, MALLOC_OVERHEAD, 1024 },
  { "max_binlog_cache_size",   (long*) &max_binlog_cache_size,
      ~0L, IO_SIZE, ~0L, 0, IO_SIZE },
  { "max_binlog_size",         (long*) &max_binlog_size,
      1024*1024L*1024L, 1024, 1024*1024L*1024L, 0, 1 },
  { "max_connections",         (long*) &max_connections,
      100, 1, 16384, 0, 1 },
  { "max_connect_errors",      (long*) &max_connect_errors,
      MAX_CONNECT_ERRORS, 1, ~0L, 0, 1 },
  { "max_delayed_threads",     (long*) &max_insert_delayed_threads,
      20, 1, 16384, 0, 1 },
  { "max_heap_table_size",     (long*) &max_heap_table_size,
      16*1024*1024L, 16384, ~0L, MALLOC_OVERHEAD, 1024 },
  { "max_join_size",           (long*) &max_join_size,
      ~0L, 1, ~0L, 0, 1 },
  { "max_sort_length",         (long*) &max_item_sort_length,
      1024, 4, 8192*1024L, 0, 1 },
  { "max_tmp_tables",          (long*) &max_tmp_tables,
      32, 1, ~0L, 0, 1 },
  { "max_user_connections",    (long*) &max_user_connections,
      0, 1, ~0L, 0, 1 },
  { "max_write_lock_count",    (long*) &max_write_lock_count,
      ~0L, 1, ~0L, 0, 1 },
  { "myisam_bulk_insert_tree_size", (long*) &myisam_bulk_insert_tree_size,
      8192*1024, 4, ~0L, 0, 1 },
  { "myisam_block_size", 	(long*) &opt_myisam_block_size,
      MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, MI_MAX_KEY_BLOCK_LENGTH,
    0, MI_MIN_KEY_BLOCK_LENGTH },
  { "myisam_max_extra_sort_file_size",
    (long*) &myisam_max_extra_sort_file_size,
    (long) (MI_MAX_TEMP_LENGTH/(1024L*1024L)), 0, ~0L, 0, 1 },
  { "myisam_max_sort_file_size", (long*) &myisam_max_sort_file_size,
    (long) (LONG_MAX/(1024L*1024L)), 0, ~0L, 0, 1 },
  { "myisam_sort_buffer_size", (long*) &myisam_sort_buffer_size,
      8192*1024, 4, ~0L, 0, 1 },
  { "net_buffer_length",       (long*) &net_buffer_length,
      16384, 1024, 1024*1024L, MALLOC_OVERHEAD, 1024 },
  { "net_retry_count",         (long*) &mysqld_net_retry_count,
      MYSQLD_NET_RETRY_COUNT, 1, ~0L, 0, 1 },
  { "net_read_timeout",        (long*) &net_read_timeout, 
      NET_READ_TIMEOUT, 1, LONG_TIMEOUT, 0, 1 },
  { "net_write_timeout",       (long*) &net_write_timeout,
      NET_WRITE_TIMEOUT, 1, LONG_TIMEOUT, 0, 1 },
  { "open_files_limit",        (long*) &open_files_limit,
      0, 0, 65535, 0, 1},
  { "query_buffer_size",       (long*) &query_buff_size,
      0, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE },
  { "record_buffer",           (long*) &my_default_record_cache_size,
      128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
  { "record_rnd_buffer",           (long*) &record_rnd_cache_size,
      0, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE },
  { "slave_net_timeout",        (long*) &slave_net_timeout, 
      SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1 },
  { "slow_launch_time",        (long*) &slow_launch_time, 
      2L, 0L, LONG_TIMEOUT, 0, 1 },
  { "sort_buffer",             (long*) &sortbuff_size,
      MAX_SORT_MEMORY, MIN_SORT_MEMORY+MALLOC_OVERHEAD*2, ~0L, MALLOC_OVERHEAD, 1 },
  { "table_cache",             (long*) &table_cache_size,
      64, 1, 16384, 0, 1 },
  { "thread_concurrency",      (long*) &concurrency,
      DEFAULT_CONCURRENCY, 1, 512, 0, 1 },
  { "thread_cache_size",       (long*) &thread_cache_size,
      0, 0, 16384, 0, 1 },
  { "tmp_table_size",          (long*) &tmp_table_size,
    32*1024*1024L, 1024, ~0L, 0, 1 },
  { "thread_stack",            (long*) &thread_stack,
      DEFAULT_THREAD_STACK, 1024*32, ~0L, 0, 1024 },
  { "wait_timeout",            (long*) &net_wait_timeout,
      NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1 },
  { NullS, (long*) 0, 0, 0, 0, 0, 0}
};


struct show_var_st init_vars[]= {
  {"back_log",                (char*) &back_log,                    SHOW_LONG},
  {"basedir",                 mysql_home,                           SHOW_CHAR},
#ifdef HAVE_BERKELEY_DB
  {"bdb_cache_size",          (char*) &berkeley_cache_size,         SHOW_LONG},
  {"bdb_log_buffer_size",     (char*) &berkeley_log_buffer_size,    SHOW_LONG},
  {"bdb_home",                (char*) &berkeley_home,               SHOW_CHAR_PTR},
  {"bdb_max_lock",            (char*) &berkeley_max_lock,	    SHOW_LONG},
  {"bdb_logdir",              (char*) &berkeley_logdir,             SHOW_CHAR_PTR},
  {"bdb_shared_data",	      (char*) &berkeley_shared_data,	    SHOW_BOOL},
  {"bdb_tmpdir",              (char*) &berkeley_tmpdir,             SHOW_CHAR_PTR},
  {"bdb_version",             (char*) DB_VERSION_STRING,            SHOW_CHAR},
#endif
  {"binlog_cache_size",       (char*) &binlog_cache_size,	    SHOW_LONG},
  {"character_set",           default_charset,                      SHOW_CHAR},
  {"character_sets",          (char*) &charsets_list,               SHOW_CHAR_PTR},
  {"concurrent_insert",       (char*) &myisam_concurrent_insert,    SHOW_MY_BOOL},
  {"connect_timeout",         (char*) &connect_timeout,             SHOW_LONG},
  {"datadir",                 mysql_real_data_home,                 SHOW_CHAR},
  {"delay_key_write",         (char*) &myisam_delay_key_write,      SHOW_MY_BOOL},
  {"delayed_insert_limit",    (char*) &delayed_insert_limit,        SHOW_LONG},
  {"delayed_insert_timeout",  (char*) &delayed_insert_timeout,      SHOW_LONG},
  {"delayed_queue_size",      (char*) &delayed_queue_size,          SHOW_LONG},
  {"flush",                   (char*) &myisam_flush,                SHOW_MY_BOOL},
  {"flush_time",              (char*) &flush_time,                  SHOW_LONG},
  {"ft_min_word_len",         (char*) &ft_min_word_len,             SHOW_LONG},
  {"ft_max_word_len",         (char*) &ft_max_word_len,             SHOW_LONG},
  {"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort,    SHOW_LONG},
  {"ft_boolean_syntax",       ft_boolean_syntax,           SHOW_CHAR},
  {"have_bdb",		      (char*) &have_berkeley_db,	    SHOW_HAVE},
  {"have_innodb",	      (char*) &have_innodb,		    SHOW_HAVE},
  {"have_isam",	      	      (char*) &have_isam,		    SHOW_HAVE},
  {"have_raid",		      (char*) &have_raid,		    SHOW_HAVE},
  {"have_symlink",            (char*) &have_symlink,         	    SHOW_HAVE},
  {"have_openssl",	      (char*) &have_openssl,		    SHOW_HAVE},
  {"init_file",               (char*) &opt_init_file,               SHOW_CHAR_PTR},
#ifdef HAVE_INNOBASE_DB
  {"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG },
  {"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONG },
  {"innodb_data_file_path", (char*) &innobase_data_file_path,	    SHOW_CHAR_PTR},
  {"innodb_data_home_dir",  (char*) &innobase_data_home_dir,	    SHOW_CHAR_PTR},
  {"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
  {"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG },
  {"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG },
  {"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_MY_BOOL},
  {"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL},
  {"innodb_flush_method",    (char*) &innobase_unix_file_flush_method, SHOW_CHAR_PTR},
  {"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG },
  {"innodb_log_arch_dir",   (char*) &innobase_log_arch_dir, 	    SHOW_CHAR_PTR},
  {"innodb_log_archive",    (char*) &innobase_log_archive, 	    SHOW_MY_BOOL},
  {"innodb_log_buffer_size", (char*) &innobase_log_buffer_size, SHOW_LONG },
  {"innodb_log_file_size", (char*) &innobase_log_file_size, SHOW_LONG},
  {"innodb_log_files_in_group", (char*) &innobase_log_files_in_group,	SHOW_LONG},
  {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR},
  {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG},
#endif
  {"interactive_timeout",     (char*) &net_interactive_timeout,     SHOW_LONG},
  {"join_buffer_size",        (char*) &join_buff_size,              SHOW_LONG},
  {"key_buffer_size",         (char*) &keybuff_size,                SHOW_LONG},
  {"language",                language,                             SHOW_CHAR},
  {"large_files_support",     (char*) &opt_large_files,             SHOW_BOOL},	
#ifdef HAVE_MLOCKALL
  {"locked_in_memory",	      (char*) &locked_in_memory,	    SHOW_BOOL},
#endif
  {"log",                     (char*) &opt_log,                     SHOW_BOOL},
  {"log_update",              (char*) &opt_update_log,              SHOW_BOOL},
  {"log_bin",                 (char*) &opt_bin_log,                 SHOW_BOOL},
  {"log_slave_updates",       (char*) &opt_log_slave_updates,       SHOW_BOOL},
  {"log_long_queries",        (char*) &opt_slow_log,                SHOW_BOOL},
  {"long_query_time",         (char*) &long_query_time,             SHOW_LONG},
  {"low_priority_updates",    (char*) &low_priority_updates,        SHOW_BOOL},
  {"lower_case_table_names",  (char*) &lower_case_table_names,      SHOW_LONG},
  {"max_allowed_packet",      (char*) &max_allowed_packet,          SHOW_LONG},
  {"max_binlog_cache_size",   (char*) &max_binlog_cache_size,	    SHOW_LONG},
  {"max_binlog_size",         (char*) &max_binlog_size,	            SHOW_LONG},
  {"max_connections",         (char*) &max_connections,             SHOW_LONG},
  {"max_connect_errors",      (char*) &max_connect_errors,          SHOW_LONG},
  {"max_delayed_threads",     (char*) &max_insert_delayed_threads,  SHOW_LONG},
  {"max_heap_table_size",     (char*) &max_heap_table_size,         SHOW_LONG},
  {"max_join_size",           (char*) &max_join_size,               SHOW_LONG},
  {"max_sort_length",         (char*) &max_item_sort_length,        SHOW_LONG},
  {"max_user_connections",    (char*) &max_user_connections,        SHOW_LONG},
  {"max_tmp_tables",          (char*) &max_tmp_tables,              SHOW_LONG},
  {"max_write_lock_count",    (char*) &max_write_lock_count,        SHOW_LONG},
  {"myisam_bulk_insert_tree_size", (char*) &myisam_bulk_insert_tree_size, SHOW_INT},
  {"myisam_max_extra_sort_file_size", (char*) &myisam_max_extra_sort_file_size,
   SHOW_LONG},
  {"myisam_max_sort_file_size",(char*) &myisam_max_sort_file_size,  SHOW_LONG},
  {"myisam_recover_options",  (char*) &myisam_recover_options_str,  SHOW_CHAR_PTR},
  {"myisam_sort_buffer_size", (char*) &myisam_sort_buffer_size,     SHOW_LONG},
  {"net_buffer_length",       (char*) &net_buffer_length,           SHOW_LONG},
  {"net_read_timeout",        (char*) &net_read_timeout,	    SHOW_LONG},
  {"net_retry_count",         (char*) &mysqld_net_retry_count,      SHOW_LONG},
  {"net_write_timeout",       (char*) &net_write_timeout,	    SHOW_LONG},
  {"open_files_limit",	      (char*) &open_files_limit,	    SHOW_LONG},
  {"pid_file",                (char*) pidfile_name,                 SHOW_CHAR},
  {"port",                    (char*) &mysql_port,                  SHOW_INT},
  {"protocol_version",        (char*) &protocol_version,            SHOW_INT},
  {"record_buffer",           (char*) &my_default_record_cache_size,SHOW_LONG},
  {"record_rnd_buffer",       (char*) &record_rnd_cache_size,	    SHOW_LONG},
  {"rpl_recovery_rank",       (char*) &rpl_recovery_rank,           SHOW_LONG},
  {"query_buffer_size",       (char*) &query_buff_size,		    SHOW_LONG},
  {"safe_show_database",      (char*) &opt_safe_show_db,            SHOW_BOOL},
  {"server_id",               (char*) &server_id,		    SHOW_LONG},
  {"slave_net_timeout",       (char*) &slave_net_timeout,	    SHOW_LONG},
  {"skip_locking",            (char*) &my_disable_locking,          SHOW_MY_BOOL},
  {"skip_networking",         (char*) &opt_disable_networking,      SHOW_BOOL},
  {"skip_show_database",      (char*) &opt_skip_show_db,            SHOW_BOOL},
  {"slow_launch_time",        (char*) &slow_launch_time,            SHOW_LONG},
  {"socket",                  (char*) &mysql_unix_port,             SHOW_CHAR_PTR},
  {"sort_buffer",             (char*) &sortbuff_size,               SHOW_LONG},
  {"sql_mode",                (char*) &opt_sql_mode,                SHOW_LONG},
  {"table_cache",             (char*) &table_cache_size,            SHOW_LONG},
  {"table_type",              (char*) &default_table_type_name,     SHOW_CHAR_PTR},
  {"thread_cache_size",       (char*) &thread_cache_size,           SHOW_LONG},
#ifdef HAVE_THR_SETCONCURRENCY
  {"thread_concurrency",      (char*) &concurrency,                 SHOW_LONG},
#endif
  {"thread_stack",            (char*) &thread_stack,                SHOW_LONG},
  {"transaction_isolation",   (char*) &default_tx_isolation_name,   SHOW_CHAR_PTR},
#ifdef HAVE_TZNAME
  {"timezone",                time_zone,                            SHOW_CHAR},
#endif
  {"tmp_table_size",          (char*) &tmp_table_size,              SHOW_LONG},
  {"tmpdir",                  (char*) &mysql_tmpdir,                SHOW_CHAR_PTR},
  {"version",                 server_version,                       SHOW_CHAR},
  {"wait_timeout",            (char*) &net_wait_timeout,            SHOW_LONG},
  {NullS, NullS, SHOW_LONG}
};

struct show_var_st status_vars[]= {
  {"Aborted_clients",          (char*) &aborted_threads,        SHOW_LONG},
  {"Aborted_connects",         (char*) &aborted_connects,       SHOW_LONG},
  {"Bytes_received",           (char*) &bytes_received,         SHOW_LONG},
  {"Bytes_sent",               (char*) &bytes_sent,             SHOW_LONG},
  {"Connections",              (char*) &thread_id,              SHOW_LONG_CONST},
  {"Created_tmp_disk_tables",  (char*) &created_tmp_disk_tables,SHOW_LONG},
  {"Created_tmp_tables",       (char*) &created_tmp_tables,     SHOW_LONG},
  {"Created_tmp_files",	       (char*) &my_tmp_file_created,	SHOW_LONG},
  {"Delayed_insert_threads",   (char*) &delayed_insert_threads, SHOW_LONG},
  {"Delayed_writes",           (char*) &delayed_insert_writes,  SHOW_LONG},
  {"Delayed_errors",           (char*) &delayed_insert_errors,  SHOW_LONG},
  {"Flush_commands",           (char*) &refresh_version,        SHOW_LONG_CONST},
  {"Handler_delete",           (char*) &ha_delete_count,        SHOW_LONG},
  {"Handler_read_first",       (char*) &ha_read_first_count,    SHOW_LONG},
  {"Handler_read_key",         (char*) &ha_read_key_count,      SHOW_LONG},
  {"Handler_read_next",        (char*) &ha_read_next_count,     SHOW_LONG},
  {"Handler_read_prev",        (char*) &ha_read_prev_count,     SHOW_LONG},
  {"Handler_read_rnd",         (char*) &ha_read_rnd_count,      SHOW_LONG},
  {"Handler_read_rnd_next",    (char*) &ha_read_rnd_next_count, SHOW_LONG},
  {"Handler_update",           (char*) &ha_update_count,        SHOW_LONG},
  {"Handler_write",            (char*) &ha_write_count,         SHOW_LONG},
  {"Key_blocks_used",          (char*) &_my_blocks_used,        SHOW_LONG_CONST},
  {"Key_read_requests",        (char*) &_my_cache_r_requests,   SHOW_LONG},
  {"Key_reads",                (char*) &_my_cache_read,         SHOW_LONG},
  {"Key_write_requests",       (char*) &_my_cache_w_requests,   SHOW_LONG},
  {"Key_writes",               (char*) &_my_cache_write,        SHOW_LONG},
  {"Max_used_connections",     (char*) &max_used_connections,   SHOW_LONG},
  {"Not_flushed_key_blocks",   (char*) &_my_blocks_changed,     SHOW_LONG_CONST},
  {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use,    SHOW_LONG_CONST},
  {"Open_tables",              (char*) 0,                       SHOW_OPENTABLES},
  {"Open_files",               (char*) &my_file_opened,         SHOW_INT_CONST},
  {"Open_streams",             (char*) &my_stream_opened,       SHOW_INT_CONST},
  {"Opened_tables",            (char*) &opened_tables,          SHOW_LONG},
  {"Questions",                (char*) 0,                       SHOW_QUESTION},
  {"Rpl_status",               (char*) 0,
   SHOW_RPL_STATUS},
  {"Select_full_join",         (char*) &select_full_join_count, SHOW_LONG},
  {"Select_full_range_join",   (char*) &select_full_range_join_count, SHOW_LONG},
  {"Select_range",             (char*) &select_range_count, 	SHOW_LONG},
  {"Select_range_check",       (char*) &select_range_check_count, SHOW_LONG},
  {"Select_scan",	       (char*) &select_scan_count,	SHOW_LONG},
  {"Slave_open_temp_tables",   (char*) &slave_open_temp_tables, SHOW_LONG},
  {"Slave_running",            (char*) 0, SHOW_SLAVE_RUNNING},
  {"Slow_launch_threads",      (char*) &slow_launch_threads,    SHOW_LONG},
  {"Slow_queries",             (char*) &long_query_count,       SHOW_LONG},
  {"Sort_merge_passes",	       (char*) &filesort_merge_passes,  SHOW_LONG},
  {"Sort_range",	       (char*) &filesort_range_count,   SHOW_LONG},
  {"Sort_rows",		       (char*) &filesort_rows,	        SHOW_LONG},
  {"Sort_scan",		       (char*) &filesort_scan_count,    SHOW_LONG},
#ifdef HAVE_OPENSSL
  {"ssl_accepts",              (char*) 0,  			SHOW_SSL_CTX_SESS_ACCEPT},
  {"ssl_finished_accepts",     (char*) 0,  			SHOW_SSL_CTX_SESS_ACCEPT_GOOD},
  {"ssl_finished_connects",    (char*) 0,  			SHOW_SSL_CTX_SESS_CONNECT_GOOD},
  {"ssl_accept_renegotiates",  (char*) 0, 			SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
  {"ssl_connect_renegotiates", (char*) 0, 		        SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE},
  {"ssl_callback_cache_hits",  (char*) 0,			SHOW_SSL_CTX_SESS_CB_HITS},
  {"ssl_session_cache_hits",   (char*) 0,		 	SHOW_SSL_CTX_SESS_HITS},
  {"ssl_session_cache_misses", (char*) 0,		 	SHOW_SSL_CTX_SESS_MISSES},
  {"ssl_session_cache_timeouts", (char*) 0,		 	SHOW_SSL_CTX_SESS_TIMEOUTS},
  {"ssl_used_session_cache_entries",(char*) 0,			SHOW_SSL_CTX_SESS_NUMBER},
  {"ssl_client_connects",      (char*) 0,			SHOW_SSL_CTX_SESS_CONNECT},
  {"ssl_session_cache_overflows", (char*) 0,		 	SHOW_SSL_CTX_SESS_CACHE_FULL},
  {"ssl_session_cache_size",   (char*) 0,		 	SHOW_SSL_CTX_SESS_GET_CACHE_SIZE},
  {"ssl_session_cache_mode",   (char*) 0,			SHOW_SSL_CTX_GET_SESSION_CACHE_MODE},
  {"ssl_sessions_reused",      (char*) 0,			SHOW_SSL_SESSION_REUSED},
  {"ssl_ctx_verify_mode",      (char*) 0,			SHOW_SSL_CTX_GET_VERIFY_MODE},
  {"ssl_ctx_verify_depth",     (char*) 0,			SHOW_SSL_CTX_GET_VERIFY_DEPTH},
  {"ssl_verify_mode",          (char*) 0,			SHOW_SSL_GET_VERIFY_MODE},
  {"ssl_verify_depth",         (char*) 0,			SHOW_SSL_GET_VERIFY_DEPTH},
  {"ssl_version",   	       (char*) 0,  			SHOW_SSL_GET_VERSION},
  {"ssl_cipher",               (char*) 0,  			SHOW_SSL_GET_CIPHER},
  {"ssl_cipher_list",          (char*) 0,  			SHOW_SSL_GET_CIPHER_LIST},
  {"ssl_default_timeout",      (char*) 0,  			SHOW_SSL_GET_DEFAULT_TIMEOUT},
#endif /* HAVE_OPENSSL */
  {"Table_locks_immediate",    (char*) &locks_immediate,        SHOW_LONG},
  {"Table_locks_waited",       (char*) &locks_waited,           SHOW_LONG},
  {"Threads_cached",           (char*) &cached_thread_count,    SHOW_LONG_CONST},
  {"Threads_created",	       (char*) &thread_created,		SHOW_LONG_CONST},
  {"Threads_connected",        (char*) &thread_count,           SHOW_INT_CONST},
  {"Threads_running",          (char*) &thread_running,         SHOW_INT_CONST},
  {"Uptime",                   (char*) 0,                       SHOW_STARTTIME},
  {NullS, NullS, SHOW_LONG}
};

static void print_version(void)
{
  printf("%s  Ver %s for %s on %s\n",my_progname,
	 server_version,SYSTEM_TYPE,MACHINE_TYPE);
}

static void use_help(void)
{
  print_version();
  printf("Use '--help' or '--no-defaults --help' for a list of available options\n");
}  

static void usage(void)
{
  print_version();
  puts("Copyright (C) 2000 MySQL AB & MySQL Finland AB, by Monty and others");
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,");
  puts("and you are welcome to modify and redistribute it under the GPL license\n");
  puts("Starts the MySQL server\n");

  printf("Usage: %s [OPTIONS]\n", my_progname);
  puts("\n\
  --ansi		Use ANSI SQL syntax instead of MySQL syntax\n\
  -b, --basedir=path	Path to installation directory. All paths are\n\
			usually resolved relative to this\n\
  --big-tables		Allow big result sets by saving all temporary sets\n\
			on file (Solves most 'table full' errors)\n\
  --bind-address=IP	Ip address to bind to\n\
  --bootstrap		Used by mysql installation scripts\n\
  --character-sets-dir=...\n\
                        Directory where character sets are\n\
  --chroot=path		Chroot mysqld daemon during startup\n\
  --core-file		Write core on errors\n\
  -h, --datadir=path	Path to the database root");
#ifndef DBUG_OFF
  printf("\
  -#, --debug[=...]     Debug log. Default is '%s'\n",default_dbug_option);
#ifdef SAFEMALLOC
  puts("\
  --skip-safemalloc     Don't use the memory allocation checking");
#endif
#endif
  puts("\
  --default-character-set=charset\n\
			Set the default character set\n\
  --default-table-type=type\n\
			Set the default table type for tables\n\
  --delay-key-write-for-all-tables\n\
			Don't flush key buffers between writes for any MyISAM\n\
			table\n\
  --enable-locking	Enable system locking\n\
  --enable-pstack	Print a symbolic stack trace on failure\n\
  -T, --exit-info	Used for debugging;  Use at your own risk!\n\
  --flush		Flush tables to disk between SQL commands\n\
  -?, --help		Display this help and exit\n\
  --init-file=file	Read SQL commands from this file at startup\n\
  -L, --language=...	Client error messages in given language. May be\n\
			given as a full path\n\
  -l, --log[=file]	Log connections and queries to file\n\
  --log-bin[=file]      Log queries in new binary format (for replication)\n\
  --log-bin-index=file  File that holds the names for last binary log files\n\
  --log-update[=file]	Log updates to file.# where # is a unique number\n\
			if not given.\n\
  --log-isam[=file]	Log all MyISAM changes to file\n\
  --log-long-format	Log some extra information to update log\n\
  --low-priority-updates INSERT/DELETE/UPDATE has lower priority than selects\n\
  --log-slow-queries=[file]\n\
			Log slow queries to this log file.  Defaults logging\n\
                        to hostname-slow.log\n\
  --pid-file=path	Pid file used by safe_mysqld\n\
  --myisam-recover[=option[,option...]] where options is one of DEAULT,\n\
			BACKUP or FORCE.\n\
  --memlock		Lock mysqld in memory\n\
  -n, --new		Use very new possible 'unsafe' functions\n\
  -o, --old-protocol	Use the old (3.20) protocol\n\
  -P, --port=...	Port number to use for connection\n");
#ifdef ONE_THREAD
  puts("\
  --one-thread		Only use one thread (for debugging under Linux)\n");
#endif
  puts("\
  -O, --set-variable var=option\n\
			Give a variable an value. --help lists variables\n\
  --safe-mode		Skip some optimize stages (for testing)\n\
  --safe-show-database  Don't show databases for which the user has no\n\
                        privileges\n\
  --safe-user-create	Don't allow new user creation by the user who has\n\
                        no write privileges to the mysql.user table\n\
  --skip-concurrent-insert\n\
		        Don't use concurrent insert with MyISAM\n\
  --skip-delay-key-write\n\
			Ignore the delay_key_write option for all tables\n\
  --skip-grant-tables	Start without grant tables. This gives all users\n\
			FULL ACCESS to all tables!\n\
  --skip-host-cache	Don't cache host names\n\
  --skip-locking	Don't use system locking. To use isamchk one has\n\
			to shut down the server.\n\
  --skip-name-resolve	Don't resolve hostnames.\n\
			All hostnames are IP's or 'localhost'\n\
  --skip-networking	Don't allow connection with TCP/IP.\n\
  --skip-new		Don't use new, possible wrong routines.\n");
  /* We have to break the string here because of VC++ limits */
  puts("\
  --skip-stack-trace    Don't print a stack trace on failure\n\
  --skip-symlink	Don't allow symlinking of tables\n\
  --skip-show-database  Don't allow 'SHOW DATABASE' commands\n\
  --skip-thread-priority\n\
			Don't give threads different priorities.\n\
  --socket=...		Socket file to use for connection\n\
  -t, --tmpdir=path	Path for temporary files\n\
  --sql-mode=option[,option[,option...]] where option can be one of:\n\
                        REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES,\n\
                        IGNORE_SPACE, SERIALIZE, ONLY_FULL_GROUP_BY.\n\
  --transaction-isolation\n\
		        Default transaction isolation level\n\
  --temp-pool           Use a pool of temporary files\n\
  -u, --user=user_name	Run mysqld daemon as user\n\
  -V, --version		output version information and exit\n\
  -W, --warnings        Log some not critical warnings to the log file\n");
#ifdef __WIN__
  puts("NT and Win32 specific options:\n\
  --console		Don't remove the console window\n\
  --install		Install mysqld as a service (NT)\n\
  --remove		Remove mysqld from the service list (NT)\n\
  --standalone		Dummy option to start as a standalone program (NT)\
");
#ifdef USE_SYMDIR
  puts("--use-symbolic-links	Enable symbolic link support");
#endif
  puts("");
#endif
#ifdef HAVE_BERKELEY_DB
  puts("\
  --bdb-home=  directory  Berkeley home direcory\n\
  --bdb-lock-detect=#	  Berkeley lock detect\n\
                          (DEFAULT, OLDEST, RANDOM or YOUNGEST, # sec)\n\
  --bdb-logdir=directory  Berkeley DB log file directory\n\
  --bdb-no-sync		  Don't synchronously flush logs\n\
  --bdb-no-recover	  Don't try to recover Berkeley DB tables on start\n\
  --bdb-shared-data	  Start Berkeley DB in multi-process mode\n\
  --bdb-tmpdir=directory  Berkeley DB tempfile name\n\
  --skip-bdb		  Don't use berkeley db (will save memory)\n\
");
#endif /* HAVE_BERKELEY_DB */
#ifdef HAVE_INNOBASE_DB
  puts("\
  --innodb_data_home_dir=dir   The common part for Innodb table spaces\n\
  --innodb_data_file_path=dir  Path to individual files and their sizes\n\
  --innodb_flush_method=#  With which method to flush data\n\
  --innodb_flush_log_at_trx_commit[=#]\n\
			       Set to 0 if you don't want to flush logs\n\
  --innodb_log_arch_dir=dir    Where full logs should be archived\n\
  --innodb_log_archive[=#]     Set to 1 if you want to have logs archived\n\
  --innodb_log_group_home_dir=dir  Path to innodb log files.\n\
  --skip-innodb		       Don't use Innodb (will save memory)\n\
");
#endif /* HAVE_INNOBASE_DB */
  print_defaults("my",load_default_groups);
  puts("");

#include "sslopt-usage.h"

  fix_paths();
  set_ports();
  printf("\
To see what values a running MySQL server is using, type\n\
'mysqladmin variables' instead of 'mysqld --help'.\n\
The default values (after parsing the command line arguments) are:\n\n");

  printf("basedir:     %s\n",mysql_home);
  printf("datadir:     %s\n",mysql_real_data_home);
  printf("tmpdir:      %s\n",mysql_tmpdir);
  printf("language:    %s\n",language);
#ifndef __WIN__
  printf("pid file:    %s\n",pidfile_name);
#endif
  if (opt_logname)
    printf("logfile:     %s\n",opt_logname);
  if (opt_update_logname)
    printf("update log:  %s\n",opt_update_logname);
  if (opt_bin_log)
  {
    printf("binary log:  %s\n",opt_bin_logname ? opt_bin_logname : "");
    printf("binary log index:  %s\n",
	   opt_binlog_index_name ? opt_binlog_index_name : "");
  }
  if (opt_slow_logname)
    printf("update log:  %s\n",opt_slow_logname);
  printf("TCP port:    %d\n",mysql_port);
#if defined(HAVE_SYS_UN_H)
  printf("Unix socket: %s\n",mysql_unix_port);
#endif
  if (my_disable_locking)
    puts("\nsystem locking is not in use");
  if (opt_noacl)
    puts("\nGrant tables are not used. All users have full access rights");
  printf("\nPossible variables for option --set-variable (-O) are:\n");
  for (uint i=0 ; changeable_vars[i].name ; i++)
    printf("%-20s  current value: %lu\n",
	   changeable_vars[i].name,
	   (ulong) *changeable_vars[i].varptr);
}


static void set_options(void)
{
  set_all_changeable_vars( changeable_vars );
#if !defined( my_pthread_setprio ) && !defined( HAVE_PTHREAD_SETSCHEDPARAM )
  opt_specialflag |= SPECIAL_NO_PRIOR;
#endif

  (void) strmov( default_charset, MYSQL_CHARSET);
  (void) strmov( language, LANGUAGE);
  (void) strmov( mysql_real_data_home, get_relative_path(DATADIR));
#ifdef __WIN__
  /* Allow Win32 users to move MySQL anywhere */
  {
    char prg_dev[LIBLEN];
    my_path(prg_dev,my_progname,"mysql/bin");
    strcat(prg_dev,"/../");			// Remove 'bin' to get base dir
    cleanup_dirname(mysql_home,prg_dev);
  }
#else
  const char *tmpenv;
  if ( !(tmpenv = getenv("MY_BASEDIR_VERSION")))
    tmpenv = DEFAULT_MYSQL_HOME;
  (void) strmov( mysql_home, tmpenv );
#endif

#if defined( HAVE_mit_thread ) || defined( __WIN__ ) || defined( HAVE_LINUXTHREADS )
  my_disable_locking=myisam_single_user= 1;
#endif
  my_bind_addr = htonl( INADDR_ANY );
}

	/* Initiates DEBUG - but no debugging here ! */

static void get_options(int argc,char **argv)
{
  int c,option_index=0;

  myisam_delay_key_write=1;			// Allow use of this
  my_use_symdir=1;				// Use internal symbolic links

  optind = 0;   // setup in case getopt() was called previously
  while ((c=getopt_long(argc,argv,"ab:C:h:#::T::?l::L:O:P:sS::t:u:noVvWI?",
			long_options, &option_index)) != EOF)
  {
    switch(c) {
    case '#':
#ifndef DBUG_OFF
      DBUG_PUSH(optarg ? optarg : default_dbug_option);
#endif
      opt_endinfo=1;				/* unireg: memory allocation */
      break;
    case 'W':
      opt_warnings=1;
      break;
    case 'a':
      opt_sql_mode = (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT |
		      MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE
		      | MODE_ONLY_FULL_GROUP_BY);
      default_tx_isolation= ISO_SERIALIZABLE;
      break;
    case 'b':
      strmov(mysql_home,optarg);
      break;
    case 'l':
      opt_log=1;
      opt_logname=optarg;			// Use hostname.log if null
      break;
    case 'h':
      strmov(mysql_real_data_home,optarg);
      break;
    case 'L':
      strmov(language,optarg);
      break;
    case 'n':
      opt_specialflag|= SPECIAL_NEW_FUNC;
      break;
    case 'o':
      protocol_version=PROTOCOL_VERSION-1;
      break;
    case 'O':
      if (set_changeable_var(optarg, changeable_vars))
      {
	use_help();
	exit(1);
      }
      break;
    case 'P':
      mysql_port= (unsigned int) atoi(optarg);
      break;
    case OPT_SAFEMALLOC_MEM_LIMIT:
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)      
      safemalloc_mem_limit = atoi(optarg);
#endif      
      break;
    case OPT_RPL_RECOVERY_RANK:
      rpl_recovery_rank=atoi(optarg);
      break;
    case OPT_SLAVE_LOAD_TMPDIR:
      slave_load_tmpdir = my_strdup(optarg, MYF(MY_FAE));
      break;
    case OPT_OLD_RPL_COMPAT:
      opt_old_rpl_compat = 1;
      break;
    case OPT_SHOW_SLAVE_AUTH_INFO:
      opt_show_slave_auth_info = 1;
      break;
    case OPT_SOCKET:
      mysql_unix_port= optarg;
      break;
    case 'r':
      mysqld_chroot=optarg;
      break;
#ifdef USE_SYMDIR
    case 's':
      my_use_symdir=1;			/* Use internal symbolic links */
      break;
#endif
    case 't':
      mysql_tmpdir=optarg;
      break;
    case OPT_TEMP_POOL:
      use_temp_pool=1;
      break;
    case 'u':
      mysqld_user=optarg;
      break;
    case 'v':
    case 'V':
      print_version();
      exit(0);
    case 'I':
    case '?':
      usage();
      exit(0);
    case 'T':
      test_flags= optarg ? (uint) atoi(optarg) : 0;
      opt_endinfo=1;
      break;
    case (int) OPT_BIG_TABLES:
      thd_startup_options|=OPTION_BIG_TABLES;
      break;
    case (int) OPT_ISAM_LOG:
      opt_myisam_log=1;
      if (optarg)
	myisam_log_filename=optarg;
      break;
    case (int) OPT_UPDATE_LOG:
      opt_update_log=1;
      opt_update_logname=optarg;		// Use hostname.# if null
      break;
   case (int) OPT_RELAY_LOG_INDEX:
      opt_relaylog_index_name = optarg;
      break;
    case (int) OPT_RELAY_LOG:
      x_free(opt_relay_logname);
      if (optarg && optarg[0])
	opt_relay_logname=my_strdup(optarg,MYF(0));
      break;
    case (int) OPT_BIN_LOG_INDEX:
      opt_binlog_index_name = optarg;
      break;
    case (int) OPT_BIN_LOG:
      opt_bin_log=1;
      x_free(opt_bin_logname);
      if (optarg && optarg[0])
	opt_bin_logname=my_strdup(optarg,MYF(0));
      break;
      // needs to be handled (as no-op) in non-debugging mode for test suite
    case (int)OPT_DISCONNECT_SLAVE_EVENT_COUNT:
#ifndef DBUG_OFF      
      disconnect_slave_event_count = atoi(optarg);
#endif      
      break;
    case (int)OPT_ABORT_SLAVE_EVENT_COUNT:
#ifndef DBUG_OFF      
      abort_slave_event_count = atoi(optarg);
#endif      
      break;
    case (int)OPT_SPORADIC_BINLOG_DUMP_FAIL:
#ifndef DBUG_OFF      
      opt_sporadic_binlog_dump_fail = 1;
#endif      
      break;
     case (int)OPT_MAX_BINLOG_DUMP_EVENTS:
#ifndef DBUG_OFF      
      max_binlog_dump_events = atoi(optarg);
#endif      
      break;

    case (int) OPT_LOG_SLAVE_UPDATES:
      opt_log_slave_updates = 1;
      break;

    case (int) OPT_INIT_RPL_ROLE:
    {
      int role;
      if ((role=find_type(optarg, &rpl_role_typelib, 2)) <= 0)
      {
	fprintf(stderr, "Unknown replication role: %s\n", optarg);
	exit(1);
      }
      rpl_status = (role == 1) ?  RPL_AUTH_MASTER : RPL_IDLE_SLAVE;
      break;
    }
    case (int)OPT_REPLICATE_IGNORE_DB:
      {
	i_string *db = new i_string(optarg);
	replicate_ignore_db.push_back(db);
        break;
      }
    case (int)OPT_REPLICATE_DO_DB:
      {
	i_string *db = new i_string(optarg);
	replicate_do_db.push_back(db);
        break;
      }
    case (int)OPT_REPLICATE_REWRITE_DB:
      {
	char* key = optarg,*p, *val;
	p = strstr(optarg, "->");
	if (!p)
	  {
	    fprintf(stderr,
		    "Bad syntax in replicate-rewrite-db - missing '->'!\n");
	    exit(1);
	  }
	val = p--;
	while(isspace(*p) && p > optarg) *p-- = 0;
	if(p == optarg)
	  {
	    fprintf(stderr,
		    "Bad syntax in replicate-rewrite-db - empty FROM db!\n");
	    exit(1);
	  }
	*val = 0;
	val += 2;
	while(*val && isspace(*val)) *val++;
	if (!*val)
	  {
	    fprintf(stderr,
		    "Bad syntax in replicate-rewrite-db - empty TO db!\n");
	    exit(1);
	  }

	i_string_pair* db_pair = new i_string_pair(key, val);
	replicate_rewrite_db.push_back(db_pair);
	break;
      }

    case (int)OPT_BINLOG_IGNORE_DB:
      {
	i_string *db = new i_string(optarg);
	binlog_ignore_db.push_back(db);
        break;
      }
    case (int)OPT_BINLOG_DO_DB:
      {
	i_string *db = new i_string(optarg);
	binlog_do_db.push_back(db);
        break;
      }
    case (int)OPT_REPLICATE_DO_TABLE:
      {
	if (!do_table_inited)
	  init_table_rule_hash(&replicate_do_table, &do_table_inited);
	if(add_table_rule(&replicate_do_table, optarg))
	  {
	    fprintf(stderr, "Could not add do table rule '%s'!\n", optarg);
	    exit(1);
	  }
	table_rules_on = 1;
	break;
      }
    case (int)OPT_REPLICATE_WILD_DO_TABLE:
      {
	if (!wild_do_table_inited)
	  init_table_rule_array(&replicate_wild_do_table,
				&wild_do_table_inited);
	if(add_wild_table_rule(&replicate_wild_do_table, optarg))
	  {
	    fprintf(stderr, "Could not add do table rule '%s'!\n", optarg);
	    exit(1);
	  }
	table_rules_on = 1;
	break;
      }
    case (int)OPT_REPLICATE_WILD_IGNORE_TABLE:
      {
	if (!wild_ignore_table_inited)
	  init_table_rule_array(&replicate_wild_ignore_table,
				&wild_ignore_table_inited);
	if(add_wild_table_rule(&replicate_wild_ignore_table, optarg))
	  {
	    fprintf(stderr, "Could not add ignore table rule '%s'!\n", optarg);
	    exit(1);
	  }
	table_rules_on = 1;
	break;
      }
    case (int)OPT_REPLICATE_IGNORE_TABLE:
      {
	if (!ignore_table_inited)
	  init_table_rule_hash(&replicate_ignore_table, &ignore_table_inited);
	if(add_table_rule(&replicate_ignore_table, optarg))
	  {
	    fprintf(stderr, "Could not add ignore table rule '%s'!\n", optarg);
	    exit(1);
	  }
	table_rules_on = 1;
	break;
      }
    case (int) OPT_SQL_BIN_UPDATE_SAME:
      opt_sql_bin_update  = 1;
      break;
    case (int) OPT_SLOW_QUERY_LOG:
      opt_slow_log=1;
      opt_slow_logname=optarg;
      break;
    case (int)OPT_SKIP_SLAVE_START:
      opt_skip_slave_start = 1;
      break;
    case (int) OPT_SKIP_NEW:
      opt_specialflag|= SPECIAL_NO_NEW_FUNC;
      default_table_type=DB_TYPE_ISAM;
      myisam_delay_key_write=0;
      myisam_concurrent_insert=0;
      myisam_recover_options= HA_RECOVER_NONE;
      my_disable_symlinks=1;
      my_use_symdir=0;
      have_symlink=SHOW_OPTION_DISABLED;
      ha_open_options&= ~HA_OPEN_ABORT_IF_CRASHED;
      break;
    case (int) OPT_SAFE:
      opt_specialflag|= SPECIAL_SAFE_MODE;
      myisam_delay_key_write=0;
      myisam_recover_options= HA_RECOVER_NONE;	// To be changed
      ha_open_options&= ~HA_OPEN_ABORT_IF_CRASHED;
      break;
    case (int) OPT_SKIP_CONCURRENT_INSERT:
      myisam_concurrent_insert=0;
      break;
    case (int) OPT_SKIP_PRIOR:
      opt_specialflag|= SPECIAL_NO_PRIOR;
      break;
    case (int) OPT_SKIP_GRANT:
      opt_noacl=1;
      break;
    case (int) OPT_SKIP_LOCK:
      my_disable_locking=myisam_single_user= 1;
      break;
    case (int) OPT_SKIP_HOST_CACHE:
      opt_specialflag|= SPECIAL_NO_HOST_CACHE;
      break;
    case (int) OPT_ENABLE_LOCK:
      my_disable_locking=myisam_single_user=0;
      break;
    case (int) OPT_USE_LOCKING:
      my_disable_locking=0;
      break;
    case (int) OPT_SKIP_RESOLVE:
      opt_specialflag|=SPECIAL_NO_RESOLVE;
      break;
    case (int) OPT_LONG_FORMAT:
      opt_specialflag|=SPECIAL_LONG_LOG_FORMAT;
      break;
    case (int) OPT_NO_MIX_TYPE:
      opt_no_mix_types = 1;
      break;
    case (int) OPT_SKIP_NETWORKING:
      opt_disable_networking=1;
      mysql_port=0;
      break;
    case (int) OPT_SKIP_SHOW_DB:
      opt_skip_show_db=1;
      opt_specialflag|=SPECIAL_SKIP_SHOW_DB;
      mysql_port=0;
      break;
    case (int) OPT_MEMLOCK:
      locked_in_memory=1;
      break;
    case (int) OPT_ONE_THREAD:
      test_flags |= TEST_NO_THREADS;
      break;
    case (int) OPT_WANT_CORE:
      test_flags |= TEST_CORE_ON_SIGNAL;
      break;
    case (int) OPT_SKIP_STACK_TRACE:
      test_flags|=TEST_NO_STACKTRACE;
      break;
    case (int) OPT_SKIP_SYMLINKS:
      my_disable_symlinks=1;
      my_use_symdir=0;
      have_symlink=SHOW_OPTION_DISABLED;
      break;
    case (int) OPT_BIND_ADDRESS:
      if (optarg && isdigit(optarg[0]))
      {
	my_bind_addr = (ulong) inet_addr(optarg);
      }
      else
      {
	struct hostent *ent;
	if (!optarg || !optarg[0])
	  ent=gethostbyname(optarg);
	else
	{
	  char myhostname[255];
	  if (gethostname(myhostname,sizeof(myhostname)) < 0)
	  {
	    sql_perror("Can't start server: cannot get my own hostname!");
	    exit(1);
	  }
	  ent=gethostbyname(myhostname);
	}
	if (!ent)
	{
	  sql_perror("Can't start server: cannot resolve hostname!");
	  exit(1);
	}
	my_bind_addr = (ulong) ((in_addr*)ent->h_addr_list[0])->s_addr;
      }
      break;
    case (int) OPT_PID_FILE:
      strmov(pidfile_name,optarg);
      break;
    case (int) OPT_INIT_FILE:
      opt_init_file=optarg;
      break;
#ifdef __WIN__
    case (int) OPT_STANDALONE:		/* Dummy option for NT */
      break;
    case (int) OPT_CONSOLE:
      opt_console=1;
      break;
#endif
    case (int) OPT_FLUSH:
#ifdef HAVE_ISAM
      nisam_flush=1;
#endif
      myisam_flush=1;
      flush_time=0;			// No auto flush
      break;
    case OPT_LOW_PRIORITY_UPDATES:
      thd_startup_options|=OPTION_LOW_PRIORITY_UPDATES;
      thr_upgraded_concurrent_insert_lock= TL_WRITE_LOW_PRIORITY;
      low_priority_updates=1;
      break;
    case OPT_BOOTSTRAP:
      opt_noacl=opt_bootstrap=1;
      break;
    case OPT_TABLE_TYPE:
    {
      int type;
      if ((type=find_type(optarg, &ha_table_typelib, 2)) <= 0)
      {
	fprintf(stderr,"Unknown table type: %s\n",optarg);
	exit(1);
      }
      default_table_type= (enum db_type) type;
      break;
    }
    case OPT_SERVER_ID:
      server_id = atoi(optarg);
      server_id_supplied = 1;
      break;
    case OPT_DELAY_KEY_WRITE:
      ha_open_options|=HA_OPEN_DELAY_KEY_WRITE;
      myisam_delay_key_write=1;
      break;
    case OPT_SKIP_DELAY_KEY_WRITE:
      myisam_delay_key_write=0;
      break;
    case 'C':
      strmov(default_charset,optarg);
      break;
    case OPT_CHARSETS_DIR:
      strmov(mysql_charsets_dir, optarg);
      charsets_dir = mysql_charsets_dir;
      break;
#include "sslopt-case.h"
    case OPT_TX_ISOLATION:
    {
      int type;
      if ((type=find_type(optarg, &tx_isolation_typelib, 2)) <= 0)
      {
	fprintf(stderr,"Unknown transaction isolation type: %s\n",optarg);
	exit(1);
      }
      default_tx_isolation= (enum_tx_isolation) (type-1);
      break;
    }
#ifdef HAVE_BERKELEY_DB
    case OPT_BDB_LOG:
      berkeley_logdir=optarg;
      break;
    case OPT_BDB_HOME:
      berkeley_home=optarg;
      break;
    case OPT_BDB_NOSYNC:
      berkeley_env_flags|=DB_TXN_NOSYNC;
      break;
    case OPT_BDB_NO_RECOVER:
      berkeley_init_flags&= ~(DB_RECOVER);
      break;
    case OPT_BDB_TMP:
      berkeley_tmpdir=optarg;
      break;
    case OPT_BDB_LOCK:
    {
      int type;
      if ((type=find_type(optarg, &berkeley_lock_typelib, 2)) > 0)
	berkeley_lock_type=berkeley_lock_types[type-1];
      else
      {
	if (test_if_int(optarg,(uint) strlen(optarg)))
	  berkeley_lock_scan_time=atoi(optarg);
	else
	{
	  fprintf(stderr,"Unknown lock type: %s\n",optarg);
	  exit(1);
	}
      }
      break;
    }
    case OPT_BDB_SHARED:
      berkeley_init_flags&= ~(DB_PRIVATE);
      berkeley_shared_data=1;
      break;
#endif /* HAVE_BERKELEY_DB */
    case OPT_BDB_SKIP:
#ifdef HAVE_BERKELEY_DB
      berkeley_skip=1;
      have_berkeley_db=SHOW_OPTION_DISABLED;
#endif
      break;
    case OPT_INNODB_SKIP:
#ifdef HAVE_INNOBASE_DB
      innodb_skip=1;
      have_innodb=SHOW_OPTION_DISABLED;
#endif
      break;
    case OPT_INNODB_DATA_FILE_PATH:
#ifdef HAVE_INNOBASE_DB
      innobase_data_file_path=optarg;
#endif
      break;
#ifdef HAVE_INNOBASE_DB
    case OPT_INNODB_DATA_HOME_DIR:
      innobase_data_home_dir=optarg;
      break;
    case OPT_INNODB_LOG_GROUP_HOME_DIR:
      innobase_log_group_home_dir=optarg;
      break;
    case OPT_INNODB_LOG_ARCH_DIR:
      innobase_log_arch_dir=optarg;
      break;
    case OPT_INNODB_LOG_ARCHIVE:
      innobase_log_archive= optarg ? test(atoi(optarg)) : 1;
      break;
    case OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT:
      innobase_flush_log_at_trx_commit= optarg ? test(atoi(optarg)) : 1;
    case OPT_INNODB_FAST_SHUTDOWN:
      innobase_fast_shutdown= optarg ? test(atoi(optarg)) : 1;
      break;
    case OPT_INNODB_FLUSH_METHOD:
      innobase_unix_file_flush_method=optarg;
      break;
#endif /* HAVE_INNOBASE_DB */
    case OPT_DO_PSTACK:
      opt_do_pstack = 1;
      break;
    case OPT_MYISAM_RECOVER:
    {
      if (!optarg || !optarg[0])
      {
	myisam_recover_options=    HA_RECOVER_DEFAULT;
	myisam_recover_options_str= myisam_recover_typelib.type_names[0];
      }
      else
      {
	myisam_recover_options_str=optarg;
	if ((myisam_recover_options=
		find_bit_type(optarg, &myisam_recover_typelib)) == ~(ulong) 0)
	{
	  fprintf(stderr, "Unknown option to myisam-recover: %s\n",optarg);
	  exit(1);
	}
      }
      ha_open_options|=HA_OPEN_ABORT_IF_CRASHED;
      break;
    }
    case OPT_SQL_MODE:
    {
      sql_mode_str = optarg;
      if ((opt_sql_mode =
	   find_bit_type(optarg, &sql_mode_typelib)) == ~(ulong) 0)
      {
	fprintf(stderr, "Unknown option to sql-mode: %s\n", optarg);
	exit(1);
      }
      default_tx_isolation= ((opt_sql_mode & MODE_SERIALIZABLE) ?
			     ISO_SERIALIZABLE :
			     ISO_READ_COMMITTED);
      break;
    }
    case OPT_MASTER_HOST:
      master_host=optarg;
      break;
    case OPT_MASTER_USER:
      master_user=optarg;
      break;
    case OPT_MASTER_PASSWORD:
      master_password=optarg;
      break;
    case OPT_MASTER_INFO_FILE:
      master_info_file=optarg;
      break;
    case OPT_RELAY_LOG_INFO_FILE:
      relay_log_info_file=optarg;
      break;
    case OPT_MASTER_PORT:
      master_port= atoi(optarg);
      break;
    case OPT_MASTER_SSL:
      master_ssl=atoi(optarg);
      break;
    case OPT_MASTER_SSL_KEY:
      master_ssl_key=optarg;
      break;
    case OPT_MASTER_SSL_CERT:
      master_ssl_cert=optarg;
      break;
    case OPT_REPORT_HOST:
      report_host=optarg;
      break;
    case OPT_REPORT_USER:
      report_user=optarg;
      break;
    case OPT_REPORT_PASSWORD:
      report_password=optarg;
      break;
    case OPT_REPORT_PORT:
      report_port= atoi(optarg);
      break;
    case OPT_MASTER_CONNECT_RETRY:
      master_connect_retry= atoi(optarg);
      break;
    case OPT_MASTER_RETRY_COUNT:
      master_retry_count= atoi(optarg);
      break;
    case OPT_SAFE_SHOW_DB:
      opt_safe_show_db=1;
      break;
    case OPT_SAFE_USER_CREATE:
      opt_safe_user_create=1;
      break;
    case OPT_SKIP_SAFEMALLOC:
#ifdef SAFEMALLOC
      sf_malloc_quick=1;
#endif
      break;
    default:
      fprintf(stderr,"%s: Unrecognized option: %c\n",my_progname,c);
      use_help();
      exit(1);
    }
  }
  // Skip empty arguments (from shell)
  while (argc != optind && !argv[optind][0])
    optind++;
  if (argc != optind)
  {
    fprintf(stderr,"%s: Too many parameters\n",my_progname);
    use_help();
    exit(1);
  }
  optind = 0;   // setup so that getopt_long() can be called again
  fix_paths();
  default_table_type_name=ha_table_typelib.type_names[default_table_type-1];
  default_tx_isolation_name=tx_isolation_typelib.type_names[default_tx_isolation];
  /* To be deleted in MySQL 4.0 */
  if (!record_rnd_cache_size)
    record_rnd_cache_size=my_default_record_cache_size;

  /* Fix variables that are base 1024*1024 */
  myisam_max_temp_length= (my_off_t) min(((ulonglong) myisam_max_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE);
  myisam_max_extra_temp_length= (my_off_t) min(((ulonglong) myisam_max_extra_sort_file_size)*1024*1024, (ulonglong) MAX_FILE_SIZE);

  myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size);
}


static char *get_relative_path(const char *path)
{
  if (test_if_hard_path(path) &&
      is_prefix(path,DEFAULT_MYSQL_HOME) &&
      strcmp(DEFAULT_MYSQL_HOME,FN_ROOTDIR))
  {
    path+=(uint) strlen(DEFAULT_MYSQL_HOME);
    while (*path == FN_LIBCHAR)
      path++;
  }
  return (char*) path;
}


/*
  Fix filename and replace extension where 'dir' is relative to
  mysql_real_data_home.
  Return 1 if len(path) > FN_REFLEN
*/

bool
fn_format_relative_to_data_home(my_string to, const char *name,
				const char *dir, const char *extension)
{
  char tmp_path[FN_REFLEN];
  if (!test_if_hard_path(dir))
  {
    strxnmov(tmp_path,sizeof(tmp_path)-1, mysql_real_data_home,
	     dir, NullS);
    dir=tmp_path;
  }
  return !fn_format(to, name, dir, extension,
		    MY_REPLACE_EXT | MY_UNPACK_FILENAME | MY_SAFE_PATH);
}


static void fix_paths(void)
{
  (void) fn_format(mysql_home,mysql_home,"","",16); // Remove symlinks
  convert_dirname(mysql_home,mysql_home,NullS);
  convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS);
  convert_dirname(language,language,NullS);
  (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
  (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home);
  (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home);

  char buff[FN_REFLEN],*sharedir=get_relative_path(SHAREDIR);
  if (test_if_hard_path(sharedir))
    strmov(buff,sharedir);			/* purecov: tested */
  else
    strxmov(buff,mysql_home,sharedir,NullS);
  convert_dirname(buff,buff,NullS);
  (void) my_load_path(language,language,buff);

  /* If --character-sets-dir isn't given, use shared library dir */
  if (charsets_dir != mysql_charsets_dir)
  {
    strmov(strmov(mysql_charsets_dir,buff),CHARSET_DIR);
    charsets_dir=mysql_charsets_dir;
  }

  /* Add '/' to TMPDIR if needed */
  char *tmp= (char*) my_malloc(FN_REFLEN,MYF(MY_FAE));
  if (tmp)
  {
    char *end=convert_dirname(tmp, mysql_tmpdir, NullS);

    mysql_tmpdir=(char*) my_realloc(tmp,(uint) (end-tmp)+1,
				    MYF(MY_HOLD_ON_ERROR));
    allocated_mysql_tmpdir=mysql_tmpdir;
  }
  if (!slave_load_tmpdir)
  {
    // no need to check return value, if we fail, my_malloc() never returns
    slave_load_tmpdir = (char*) my_strdup(mysql_tmpdir, MYF(MY_FAE));
  }
}


#ifdef SET_RLIMIT_NOFILE
static uint set_maximum_open_files(uint max_file_limit)
{
  struct rlimit rlimit;
  ulong old_cur;

  if (!getrlimit(RLIMIT_NOFILE,&rlimit))
  {
    old_cur=rlimit.rlim_cur;
    if (rlimit.rlim_cur >= max_file_limit)	// Nothing to do
      return rlimit.rlim_cur;			/* purecov: inspected */
    rlimit.rlim_cur=rlimit.rlim_max=max_file_limit;
    if (setrlimit(RLIMIT_NOFILE,&rlimit))
    {
      sql_print_error("Warning: setrlimit couldn't increase number of open files to more than %ld",
	      old_cur);		/* purecov: inspected */
      max_file_limit=old_cur;
    }
    else
    {
      (void) getrlimit(RLIMIT_NOFILE,&rlimit);
      if ((uint) rlimit.rlim_cur != max_file_limit)
	sql_print_error("Warning: setrlimit returned ok, but didn't change limits. Max open files is %ld",
			  (ulong) rlimit.rlim_cur); /* purecov: inspected */
      max_file_limit=rlimit.rlim_cur;
    }
  }
  return max_file_limit;
}
#endif

#ifdef OS2
static uint set_maximum_open_files(uint max_file_limit)
{
   LONG     cbReqCount;
   ULONG    cbCurMaxFH, cbCurMaxFH0;
   APIRET   ulrc;

   // get current limit
   cbReqCount = 0;
   DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH0);

   // set new limit
   cbReqCount = max_file_limit - cbCurMaxFH0;
   ulrc = DosSetRelMaxFH( &cbReqCount, &cbCurMaxFH);
   if (ulrc) {
      sql_print_error("Warning: DosSetRelMaxFH couldn't increase number of open files to more than %d",
         cbCurMaxFH0);
      cbCurMaxFH = cbCurMaxFH0;
   }

   return cbCurMaxFH;
}
#endif

	/*
	  Return a bitfield from a string of substrings separated by ','
	  returns ~(ulong) 0 on error.
	*/

static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
{
  bool found_end;
  int  found_count;
  const char *end,*i,*j;
  const char **array, *pos;
  ulong found,found_int,bit;
  DBUG_ENTER("find_bit_type");
  DBUG_PRINT("enter",("x: '%s'",x));

  found=0;
  found_end= 0;
  pos=(my_string) x;
  while (*pos == ' ') pos++;
  found_end= *pos == 0;
  while (!found_end)
  {
    if (!*(end=strcend(pos,',')))		/* Let end point at fieldend */
    {
      while (end > pos && end[-1] == ' ')
	end--;					/* Skip end-space */
      found_end=1;
    }
    found_int=0; found_count=0;
    for (array=bit_lib->type_names, bit=1 ; (i= *array++) ; bit<<=1)
    {
      j=pos;
      while (j != end)
      {
	if (toupper(*i++) != toupper(*j++))
	  goto skipp;
      }
      found_int=bit;
      if (! *i)
      {
	found_count=1;
	break;
      }
      else if (j != pos)			// Half field found
      {
	found_count++;				// Could be one of two values
      }
skipp: ;
    }
    if (found_count != 1)
      DBUG_RETURN(~(ulong) 0);				// No unique value
    found|=found_int;
    pos=end+1;
  }

  DBUG_PRINT("exit",("bit-field: %ld",(ulong) found));
  DBUG_RETURN(found);
} /* find_bit_type */


/*****************************************************************************
** Instantiate templates
*****************************************************************************/

#ifdef __GNUC__
/* Used templates */
template class I_List<THD>;
template class I_List_iterator<THD>;
template class I_List<i_string>;
template class I_List<i_string_pair>;
#endif