/* 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 "sql_acl.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

#ifdef	__cplusplus
extern "C" {					// Because of SCO 3.2V4.2
#endif
#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

#ifndef __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>
#else
#include <windows.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

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

#ifdef	__cplusplus
}
#endif

#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(__linux__) && !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;
#endif

static bool opt_skip_slave_start = 0; // if set, slave is not autostarted
static ulong opt_specialflag=SPECIAL_ENGLISH;
static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET;
static ulong back_log,connect_timeout,concurrency;
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 pthread_t flush_thread;			// Used when debugging
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_ansi_mode=0,opt_myisam_log=0;
bool opt_sql_bin_update = 0, opt_log_slave_updates = 0;
extern MASTER_INFO glob_mi;
extern int init_master_info(MASTER_INFO* mi);

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

#ifdef HAVE_OPENSSL
static bool opt_use_ssl = false;
static char *opt_ssl_key = 0;
static char *opt_ssl_cert = 0;
static char *opt_ssl_ca = 0;
static char *opt_ssl_capath = 0;
static VioSSLAcceptorFd* ssl_acceptor_fd = 0;
#endif /* HAVE_OPENSSL */

extern bool slave_running;

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;

uint32 server_id = 0; // server id for replication
uint mysql_port;
uint test_flags, 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, global_read_lock=0;
ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
			   OPTION_BIN_LOG | OPTION_AUTO_COMMIT |
			   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;
ulong thread_cache_size=0;
volatile ulong cached_thread_count=0;

// replication parameters, if master_host is not NULL, we are slaving off the master
my_string master_user = (char*) "test", master_password = 0, master_host=0,
  master_info_file = (char*) "master.info";
const char *localhost=LOCAL_HOST;
uint master_port = MYSQL_PORT, master_connect_retry = 60;

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

bool opt_endinfo,using_udf_functions,low_priority_updates, locked_in_memory;
bool volatile abort_loop,select_thread_in_use,flush_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;
ulong filesort_rows, filesort_range_count, filesort_scan_count;
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;
ulong thread_id=1L,current_pid;
ulong slow_launch_threads = 0;
char mysql_real_data_home[FN_REFLEN],
     mysql_data_home[2],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;
char *opt_bin_logname = 0; // this one needs to be seen in sql_parse.cc
char server_version[50]=MYSQL_SERVER_VERSION;
const char *first_keyword="first";
const char **errmesg;			/* Error messages */
const char *myisam_recover_options_str="OFF";
byte last_ref[MAX_REFLENGTH];		/* Index ref of keys */
my_string mysql_unix_port=NULL,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;

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_flush, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
                LOCK_binlog_update, LOCK_slave, LOCK_server_id;

pthread_cond_t COND_refresh,COND_thread_count,COND_flush, COND_binlog_update,
  COND_slave_stopped;
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

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 bool read_init_file(char *file_name);
#ifdef __NT__
static pthread_handler_decl(handle_connections_namedpipes,arg);
#endif
#ifdef __WIN__
static int get_service_parameters();
#endif
static pthread_handler_decl(handle_flush,arg);
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_flush);
  if (flush_thread_in_use)
  {
    DBUG_PRINT("quit",("killing flush thread: %lx",flush_thread));
   (void) pthread_cond_signal(&COND_flush);
  }
  (void) pthread_mutex_unlock(&LOCK_flush);

  /* kill connection thread */
#if !defined(__WIN__) && !defined(__EMX__)
  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
#if defined(AIX_3_2) || defined(HAVE_DEC_3_2_THREADS)
    if (ip_sock != INVALID_SOCKET)
    {
      VOID(shutdown(ip_sock,2));
      VOID(closesocket(ip_sock));
      VOID(shutdown(unix_sock,2));
      VOID(closesocket(unix_sock));
      VOID(unlink(mysql_unix_port));
      ip_sock=unix_sock= INVALID_SOCKET;
    }
#endif
  }
  (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

  /* 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;
      if (tmp->mysys_var->current_mutex)
      {
	pthread_mutex_lock(tmp->mysys_var->current_mutex);
	pthread_cond_broadcast(tmp->mysys_var->current_cond);
	pthread_mutex_unlock(tmp->mysys_var->current_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, (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();
  mysql_update_log.close();
  mysql_bin_log.close();
  my_free(charsets_list, MYF(0));
  DBUG_PRINT("quit",("close_connections thread"));
  DBUG_VOID_RETURN;
}

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

#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(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
    DBUG_VOID_RETURN;
}


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

#ifndef __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, we do not need
  // another one
  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__)
  my_thread_init();				// If this is a new thread
#endif
  close_connections();
  sql_print_error(ER(ER_SHUTDOWN_COMPLETE),my_progname);
  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

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
#ifndef __WIN__
  if (sig == SIGALRM)
    alarm(2);					/* reschedule alarm */
#endif
}


void unireg_end(int signal_number __attribute__((unused)))
{
  (void) my_delete(pidfile_name,MYF(0));	// This may not always exist
  clean_up();
  pthread_exit(0);				// Exit is in main thread
}


void unireg_abort(int exit_code)
{
  if (exit_code)
    sql_print_error("Aborting\n");
  (void) my_delete(pidfile_name,MYF(0));	// This may not always exist
  clean_up(); /* purecov: inspected */
  exit(exit_code); /* purecov: inspected */
}


void clean_up(void)
{
  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
  end_key_cache();			/* This is usually freed automaticly */
  (void) ha_panic(HA_PANIC_CLOSE);	/* close all tables and logs */
#ifdef USE_RAID
  end_raid();
#endif
  x_free((gptr) errmsg[ERRMAPP]);	/* Free messages */
  free_defaults(defaults_argv);
  my_free(mysql_tmpdir,MYF(0));
  x_free(opt_bin_logname);
  my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);

  /* Tell main we are ready */
  (void) pthread_mutex_lock(&LOCK_thread_count);
  ready_to_exit=1;
  (void) pthread_cond_broadcast(&COND_thread_count);
  (void) pthread_mutex_unlock(&LOCK_thread_count);
} /* clean_up */



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

static void set_ports()
{
  char	*env;
  if (!mysql_port)
  {					// 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)
{
#ifndef __WIN__
    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__)
  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);
    }
    (void) listen(ip_sock,(int) back_log);
  }

  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
    (void) listen(unix_sock,(int) back_log);
  }
#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)
{
  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");
  (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 */
  (void) pthread_cond_broadcast(&COND_thread_count);
  (void) pthread_mutex_unlock(&LOCK_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
******************************************************************************/

#ifdef __WIN__
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) ;
  signal(SIGBREAK,SIG_IGN);	//ignore SIGBREAK for NT
}

#elif defined(__EMX__)
static void sig_reload(int signo)
{
  reload_acl_and_cache(~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();
}
#else

#ifdef HAVE_LINUXTHREADS

/* Produce a core for the thread */

static sig_handler write_core(int sig)
{
  fprintf(stderr,"Got signal %s in thread %d\n",sys_siglist[sig],getpid());
  signal(sig, SIG_DFL);
  if (fork() != 0) exit(1);			// Abort main program
  // Core will be written at exit
}
#endif


static void init_signals(void)
{
  sigset_t set;
  pthread_attr_t thr_attr;
  int error;
  DBUG_ENTER("init_signals");

  sigset(THR_KILL_SIGNAL,end_thread_signal);
  sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
#ifdef HAVE_LINUXTHREADS
  if (test_flags & TEST_CORE_ON_SIGNAL)
  {
    struct sigaction sa; sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
    sa.sa_handler=write_core;
    sigaction(SIGSEGV, &sa, NULL);
  }
#endif
  (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);

  (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) */
  {
    FILE	*pidFile;
    if ((pidFile = my_fopen(pidfile_name,O_WRONLY,MYF(MY_WME))))
    {
      fprintf(pidFile,"%lu",(ulong) getpid());
      (void) my_fclose(pidFile,MYF(0));
      (void) chmod(pidfile_name,0644);
    }
  }

  (void) pthread_mutex_lock(&LOCK_thread_count);
  (void) pthread_cond_signal(&COND_thread_count); /* continue init_signals */
  (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,~0, (TABLE_LIST*) 0); // Flush everything
      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__
#undef errno
#undef EINTR
#define errno WSAGetLastError()
#define EINTR WSAEINTR

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

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

#ifdef HAVE_LIBWRAP
char *libwrapName=NULL;
#endif

static void open_log(MYSQL_LOG *log, const char *hostname,
		     const char *opt_name, const char *extension,
		     enum_log_type type)
{
  char tmp[FN_REFLEN];
  if (!opt_name || !opt_name[0])
  {
    strnmov(tmp,hostname,FN_REFLEN-5);
    strmov(strcend(tmp,'.'),extension);
    opt_name=tmp;
  }
  log->open(opt_name,type);
}



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

  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 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 == 1 ? 1 : 0]);
  }
#else
  {
    struct tm *start_tm;
    start_tm=localtime(&start_time);
    strmov(time_zone=tzname[start_tm->tm_isdst == 1 ? 1 : 0]);
  }
#endif
#endif

  if (gethostname(hostname,sizeof(hostname)-4) < 0)
    strmov(hostname,"mysql");
  strmov(pidfile_name,hostname);
  strmov(strcend(pidfile_name,'.'),".pid");	// Add extension
#ifdef DEMO_VERSION
  strcat(server_version,"-demo");
#endif
#ifdef SHAREWARE_VERSION
  strcat(server_version,"-shareware");
#endif
#ifndef DBUG_OFF
  strcat(server_version,"-debug");
#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 */
#ifdef __WIN__
  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();
#ifdef __WIN__
  /* service parameters can be overwritten by options */
  if (get_service_parameters())
  {
    my_message( 0, "Can't read MySQL service parameters", MYF(0) );
    exit( 1 );
  }
#endif
  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_cond_init(&COND_thread_count,NULL);
  (void) pthread_mutex_init(&LOCK_mysql_create_db,NULL);
  (void) pthread_mutex_init(&LOCK_Acl,NULL);
  (void) pthread_mutex_init(&LOCK_grant,NULL);
  (void) pthread_mutex_init(&LOCK_open,NULL);
  (void) pthread_mutex_init(&LOCK_thread_count,NULL);
  (void) pthread_mutex_init(&LOCK_mapped_file,NULL);
  (void) pthread_mutex_init(&LOCK_status,NULL);
  (void) pthread_mutex_init(&LOCK_error_log,NULL);
  (void) pthread_mutex_init(&LOCK_delayed_insert,NULL);
  (void) pthread_mutex_init(&LOCK_delayed_status,NULL);
  (void) pthread_mutex_init(&LOCK_delayed_create,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_flush,NULL);
  (void) pthread_mutex_init(&LOCK_flush,NULL);
  (void) pthread_mutex_init(&LOCK_crypt,NULL);
  (void) pthread_mutex_init(&LOCK_bytes_sent,NULL);
  (void) pthread_mutex_init(&LOCK_bytes_received,NULL);
  (void) pthread_mutex_init(&LOCK_timezone,NULL);
  (void) pthread_mutex_init(&LOCK_binlog_update, NULL);
  (void) pthread_mutex_init(&LOCK_slave, NULL);
  (void) pthread_mutex_init(&LOCK_server_id, NULL);
  (void) pthread_cond_init(&COND_binlog_update, NULL);
  (void) pthread_cond_init(&COND_slave_stopped, NULL);

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

#ifdef HAVE_OPENSSL
  if (opt_use_ssl)
  {
    ssl_acceptor_fd = VioSSLAcceptorFd_new(opt_ssl_key, opt_ssl_cert,
					   opt_ssl_ca, opt_ssl_capath);
    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);

#ifdef SET_RLIMIT_NOFILE
  /* connections and databases neads lots of files */
  {
    uint wanted_files=10+(uint) max(max_connections*5,
				    max_connections+table_cache_size*2);
    uint files=set_maximum_open_files(wanted_files);
    if (files && files < wanted_files)		// Some systems return 0
    {
      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;

  /*
  ** 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();

  /* Setup log files */
  if (opt_log)
    open_log(&mysql_log, hostname, opt_logname, ".log", LOG_NORMAL);
  if (opt_update_log)
    open_log(&mysql_update_log, hostname, opt_update_logname, "",
	     LOG_NEW);
  if (opt_bin_log)
  {
    if(server_id)
      {
	if (!opt_bin_logname)
	  {
	    char tmp[FN_REFLEN];
	    strnmov(tmp,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, hostname, opt_bin_logname, "-bin",
		 LOG_BIN);
      }
    else
      sql_print_error("Server id is not set - binary logging disabled");
  }
  
  if (opt_slow_log)
    open_log(&mysql_slow_log, hostname, opt_slow_logname, "-slow.log",
	     LOG_NORMAL);
  if (ha_init())
  {
    sql_print_error("Can't init databases");
    exit(1);
  }
#ifdef HAVE_MLOCKALL
  if (locked_in_memory && !geteuid())
  {
    ha_key_cache();
    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);       /* SerG */

#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);
  }
  init_signals();				// Creates pidfile
  if (acl_init(opt_noacl))
  {
    select_thread_in_use=0;
    (void) pthread_kill(signal_thread,MYSQL_KILL_SIGNAL);
#ifndef __WIN__
    (void) my_delete(pidfile_name,MYF(MY_WME));		// Not neaded anymore
#endif
    exit(1);
  }
  if (!opt_noacl)
    (void) grant_init();

#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

  if (flush_time && flush_time != ~(ulong) 0L)
  {
    pthread_t hThread;
    if (pthread_create(&hThread,&connection_attrib,handle_flush,0))
      sql_print_error("Warning: Can't create thread to handle flush");
  }

  // slave thread
  if(master_host)
  {
    if(server_id)
      {
	pthread_t hThread;
	if(!opt_skip_slave_start &&
	   pthread_create(&hThread, &connection_attrib, handle_slave, 0))
	  sql_print_error("Warning: Can't create thread to handle slave");
	else if(opt_skip_slave_start)
	  init_master_info(&glob_mi);
      }
    else
      sql_print_error("Server id is not set, slave thread will not be started");
  }

  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)
      {
	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_DEBUG
  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_DEBUG
  sql_print_error("Before Lock_thread_count");
#endif
  (void) pthread_mutex_lock(&LOCK_thread_count);
  select_thread_in_use=0;			// For close_connections
  (void) pthread_cond_broadcast(&COND_thread_count);
  (void) pthread_mutex_unlock(&LOCK_thread_count);
#ifdef EXTRA_DEBUG
  sql_print_error("After lock_thread_count");
#endif
#else
  // remove the event, because it will not be valid anymore
  Service.SetShutdownEvent(0);
  if(hEventShutdown) CloseHandle(hEventShutdown);
  // if it was started as service on NT try to stop the service
  if(Service.IsNT())
     Service.Stop();
#endif

  /* Wait until cleanup is done */
  (void) pthread_mutex_lock(&LOCK_thread_count);
  while (!ready_to_exit)
  {
    pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
  }
  (void) pthread_mutex_unlock(&LOCK_thread_count);
#ifndef __WIN__
  (void) my_delete(pidfile_name,MYF(0));	// Not neaded anymore
#endif
  my_thread_end();
  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)
    {
      if (!strcmp(argv[1],"-install") || !strcmp(argv[1],"--install"))
      {
	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 (!Service.Install(MYSQL_SERVICENAME,MYSQL_SERVICENAME,path))
	  MessageBox(NULL,"Failed to install Service",MYSQL_SERVICENAME,
		     MB_OK|MB_ICONSTOP);
	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
      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,(Vio*) 0);
  thd->max_packet_length=thd->net.max_packet;
  thd->master_access= ~0;
  thread_count++;
  thd->real_id=pthread_self();
  error=handle_bootstrap(thd,file);
  net_end(&thd->net);
  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++;
      threads.append(thd);
      DBUG_PRINT("info",(("creating thread %d"), thd->thread_id));
      thd->connect_time = time(NULL);
      (void) pthread_mutex_unlock(&LOCK_thread_count);
      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));
	(void) pthread_mutex_lock(&LOCK_thread_count);
	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;
      }
    }
  }
  DBUG_PRINT("info",(("Thread %d created"), thd->thread_id));
  DBUG_VOID_RETURN;
}


	/* 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;
  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);
  socket_flags=fcntl(unix_sock, F_GETFL, 0);
#endif

  DBUG_PRINT("general",("Waiting for connections."));
  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 (errno != EINTR)
      {
	if (!select_errors++ && !abort_loop)	/* purecov: inspected */
	  sql_print_error("mysqld: Got error %d from select",errno); /* purecov: inspected */
      }
      continue;
    }
#endif	/* HPUX */
    if (abort_loop)
      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 || (errno != EINTR && errno != EAGAIN))
	break;
#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 < 0)
    {
      if ((error_count++ & 255) == 0)		// This can happen often
	sql_perror("Error in accept");
      if (errno == ENFILE || errno == 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 __NT__
  pthread_mutex_lock(&LOCK_thread_count);
  handler_count--;
  pthread_cond_signal(&COND_handler_count);
  pthread_mutex_unlock(&LOCK_thread_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__ */

/****************************************************************************
**  Create thread that automaticly flush all tables after a given time
****************************************************************************/

pthread_handler_decl(handle_flush,arg __attribute__((unused)))
{
  my_thread_init();
  DBUG_ENTER("handle_flush");

  pthread_detach_this_thread();
  flush_thread=pthread_self();
  flush_thread_in_use=1;

  pthread_mutex_lock(&LOCK_flush);
  while (flush_time)
  {
    struct timespec abstime;
#ifdef HAVE_TIMESPEC_TS_SEC
    abstime.ts_sec=time(NULL)+flush_time;	// Bsd 2.1
    abstime.ts_nsec=0;
#else
    abstime.tv_sec=time(NULL)+flush_time;	// Linux or Solairs
    abstime.tv_nsec=0;
#endif
    (void) pthread_cond_timedwait(&COND_flush,&LOCK_flush, &abstime);
    if (abort_loop)
      break;
    flush_tables();
  }
  flush_thread_in_use=0;
  pthread_mutex_unlock(&LOCK_flush);
  my_thread_end();
  DBUG_RETURN(0);
}


/******************************************************************************
** 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_RECOVER,          OPT_MASTER_HOST,  
               OPT_MASTER_USER,          OPT_MASTER_PASSWORD,
               OPT_MASTER_PORT,          OPT_MASTER_INFO_FILE,
               OPT_MASTER_CONNECT_RETRY, 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
};

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-recover",           no_argument,       0, (int) OPT_BDB_RECOVER},
  {"bdb-no-sync",           no_argument,       0, (int) OPT_BDB_NOSYNC},
  {"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'},
#ifndef DBUG_OFF
  {"debug",                 optional_argument, 0, '#'},
#endif
  {"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},
  {"exit-info",             optional_argument, 0, 'T'},
  {"flush",                 no_argument,       0, (int) OPT_FLUSH},
  {"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-info-file",      required_argument, 0, (int) OPT_MASTER_INFO_FILE},
  {"myisam-recover",	    optional_argument, 0, (int) OPT_MYISAM_RECOVER},
  {"memlock",		    no_argument,       0, (int) OPT_MEMLOCK},
  {"new",                   no_argument,       0, 'n'},
  {"old-protocol",          no_argument,       0, 'o'},
#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-ignore-db",   required_argument, 0, (int) OPT_REPLICATE_IGNORE_DB},
  {"replicate-rewrite-db",   required_argument, 0,
     (int) OPT_REPLICATE_REWRITE_DB},
  {"safe-mode",             no_argument,       0, (int) OPT_SAFE},
  {"socket",                required_argument, 0, (int) OPT_SOCKET},
  {"server-id",          required_argument, 0, (int)OPT_SERVER_ID},
  {"set-variable",          required_argument, 0, 'O'},
#ifdef HAVE_BERKELEY_DB
  {"skip-bdb",              no_argument,       0, (int) OPT_BDB_SKIP},
#endif
#ifdef HAVE_INNOBASE_DB
  {"skip-innobase",         no_argument,       0, (int) OPT_INNOBASE_SKIP},
#endif
  {"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-new",              no_argument,       0, (int) OPT_SKIP_NEW},
  {"skip-show-database",    no_argument,       0, (int) OPT_SKIP_SHOW_DB},
  {"skip-slave-start",    no_argument,       0, (int) OPT_SKIP_SLAVE_START},
  {"skip-networking",       no_argument,       0, (int) OPT_SKIP_NETWORKING},
  {"skip-thread-priority",  no_argument,       0, (int) OPT_SKIP_PRIOR},
  {"sql-bin-update-same",   no_argument,       0, (int) OPT_SQL_BIN_UPDATE_SAME},
#include "sslopt-longopts.h"
#ifdef __WIN__
  {"standalone",            no_argument,       0, (int) OPT_STANDALONE},
#endif
  {"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'},
  {0, 0, 0, 0}
};

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_lock_max",            (long*) &berkeley_lock_max, 
      1000, 0, (long) ~0, 0, 1 },
#endif
  { "connect_timeout",         (long*) &connect_timeout,
      CONNECT_TIMEOUT, 2, 65535, 0, 1 },
  { "delayed_insert_timeout", (long*) &delayed_insert_timeout, 
      DELAYED_WAIT_TIMEOUT, 1, ~0L, 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, ~0L, 0, 1 },
  { "interactive_timeout",     (long*) &net_interactive_timeout,
      NET_WAIT_TIMEOUT, 1, 31*24*60*60, 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, ~0L, 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, 17*1024*1024L, MALLOC_OVERHEAD, 1024 },
  { "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_write_lock_count",    (long*) &max_write_lock_count,
      ~0L, 1, ~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, 65535, 0, 1 },
  { "net_write_timeout",       (long*) &net_write_timeout,
      NET_WRITE_TIMEOUT, 1, 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 },
  { "slow_launch_time",        (long*) &slow_launch_time, 
      2L, 0L, ~0L, 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, 1, 16384, 0, 1 },
  { "tmp_table_size",          (long*) &tmp_table_size,
      1024*1024L, 1024, ~0L, MALLOC_OVERHEAD, 1 },
  { "thread_stack",            (long*) &thread_stack,
      DEFAULT_THREAD_STACK, 1024*32, ~0L, 0, 1024 },
  { "wait_timeout",            (long*) &net_wait_timeout,
      NET_WAIT_TIMEOUT, 1, ~0L, 0, 1 },
  { NullS, (long*) 0, 0, 0, 0, 0, 0}
};


struct show_var_st init_vars[]= {
  {"ansi_mode",               (char*) &opt_ansi_mode,               SHOW_BOOL},
  {"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_home",                (char*) &berkeley_home,               SHOW_CHAR_PTR},
  {"bdb_lock_max",            (char*) &berkeley_lock_max,	    SHOW_LONG},
  {"bdb_logdir",              (char*) &berkeley_logdir,             SHOW_CHAR_PTR},
  {"bdb_tmpdir",              (char*) &berkeley_tmpdir,             SHOW_CHAR_PTR},
#endif
  {"character_set",           default_charset,                      SHOW_CHAR},
  {"character_sets",          (char*) &charsets_list,               SHOW_CHAR_PTR},
  {"connect_timeout",         (char*) &connect_timeout,             SHOW_LONG},
  {"concurrent_insert",       (char*) &myisam_concurrent_insert,    SHOW_MY_BOOL},
  {"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},
  {"join_buffer_size",        (char*) &join_buff_size,              SHOW_LONG},
  {"flush",                   (char*) &myisam_flush,                SHOW_MY_BOOL},
  {"flush_time",              (char*) &flush_time,                  SHOW_LONG},
  {"init_file",               (char*) &opt_init_file,               SHOW_CHAR_PTR},
  {"interactive_timeout",     (char*) &net_interactive_timeout,     SHOW_LONG},
  {"key_buffer_size",         (char*) &keybuff_size,                SHOW_LONG},
  {"language",                language,                             SHOW_CHAR},
#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},
  {"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_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_tmp_tables",          (char*) &max_tmp_tables,              SHOW_LONG},
  {"max_write_lock_count",    (char*) &max_write_lock_count,        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_retry_count",         (char*) &mysqld_net_retry_count,      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},
  {"server_id",           (char*) &server_id, 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},
  {"table_cache",             (char*) &table_cache_size,            SHOW_LONG},
  {"table_type",              (char*) &default_table_type_name,     SHOW_CHAR_PTR},
#ifdef HAVE_THR_SETCONCURRENCY
  {"thread_concurrency",      (char*) &concurrency,                 SHOW_LONG},
#endif
  {"thread_stack",            (char*) &thread_stack,                SHOW_LONG},
  {"thread_cache_size",       (char*) &thread_cache_size,           SHOW_LONG},
#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},
  {"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},
  {"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_running",            (char*) &slave_running,          SHOW_BOOL},
  {"Slow_launch_threads",      (char*) &slow_launch_threads,    SHOW_LONG},
  {"Slow_queries",             (char*) &long_query_count,       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},
  {"Threads_cached",           (char*) &cached_thread_count,    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);
#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\
  -T, --exit-info	Print some debug info at exit\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\
  -Sg, --skip-grant-tables\n\
			Start without grant tables. This gives all users\n\
			FULL ACCESS to all tables!\n\
  --safe-mode		Skip some optimize stages (for testing)\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-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\
  --skip-host-cache	Don't cache host names\n");
  /* We have to break the string here because of VC++ limits */
  puts("\
  --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\
  -u, --user=user_name	Run mysqld daemon as user\n\
  -V, --version		output version information and exit");
#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)\n\
");
#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-nosync		  Don't synchronously flush logs\n\
  --bdb-recover		  Start Berkeley DB in recover mode\n\
  --bdb-tmpdir=directory  Berkeley DB tempfile name\n\
  --skip-bdb		  Don't use berkeley db (will save memory)\n\
");
#endif
#ifdef HAVE_INNOBASE_DB
  puts("\
  --skip-innobase	  Don't use innobase (will save memory)\n\
");
#endif
  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 = 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
  while ((c=getopt_long(argc,argv,"ab:C:h:#::T::?l::L:O:P:sS::t:u:noVvI?",
			long_options, &option_index)) != EOF)
  {
    switch(c) {
#ifndef DBUG_OFF
    case '#':
      DBUG_PUSH(optarg ? optarg : default_dbug_option);
      opt_endinfo=1;				/* unireg: memory allocation */
      break;
#endif
    case 'a':
      opt_ansi_mode=1;
      thd_startup_options|=OPTION_ANSI_MODE;
      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_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 '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) : (uint) ~0;
      opt_endinfo=1;
      break;
    case 'S':
      if (!optarg)
	opt_specialflag|= SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE;
      else if (!strcmp(optarg,"l"))
	my_disable_locking=1;
      else if (!strcmp(optarg,"g"))
	opt_noacl=1;
      else
      {
	fprintf(stderr,"%s: Unrecognized option: %s\n",my_progname,optarg);
	use_help();
	exit(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_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;
    case (int) OPT_LOG_SLAVE_UPDATES:
      opt_log_slave_updates = 1;
      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_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;
      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=1;
      break;
    case (int) OPT_SKIP_HOST_CACHE:
      opt_specialflag|= SPECIAL_NO_HOST_CACHE;
      break;
    case (int) OPT_ENABLE_LOCK:
      my_disable_locking=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_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_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:
      nisam_flush=myisam_flush=1;
      flush_time=0;			// No auto flush
      break;
    case OPT_LOW_PRIORITY_UPDATES:
      thd_startup_options|=OPTION_LOW_PRIORITY_UPDATES;
      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);
      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"
#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_init_flags|=DB_TXN_NOSYNC;
      break;
    case OPT_BDB_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_SKIP:
      berkeley_skip=1;
      break;
#endif
#ifdef HAVE_INNOBASE_DB
    case OPT_INNOBASE_SKIP:
      innobase_skip=1;
      break;
#endif
    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_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_MASTER_PORT:
      master_port= atoi(optarg);
      break;
    case OPT_MASTER_CONNECT_RETRY:
      master_connect_retry= atoi(optarg);
      break;

    default:
      fprintf(stderr,"%s: Unrecognized option: %c\n",my_progname,c);
      use_help();
      exit(1);
    }
  }
  // Skipp 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);
  }
  fix_paths();
  default_table_type_name=ha_table_typelib.type_names[default_table_type-1];
}


#ifdef __WIN__

#ifndef KEY_SERVICE_PARAMETERS
#define KEY_SERVICE_PARAMETERS	"SYSTEM\\CurrentControlSet\\Services\\MySql\\Parameters"
#endif

#define COPY_KEY_VALUE(value) if (copy_key_value(hParametersKey,&(value),lpszValue)) return 1
#define CHECK_KEY_TYPE(type,name) if ( type != dwKeyValueType ) { key_type_error(hParametersKey,name); return 1; }
#define SET_CHANGEABLE_VARVAL(varname) if (set_varval(hParametersKey,varname,szKeyValueName,dwKeyValueType,lpdwValue)) return 1;

static void key_type_error(HKEY hParametersKey,const char *szKeyValueName)
{
 TCHAR szErrorMsg[512];
 RegCloseKey( hParametersKey );
 strxmov(szErrorMsg,TEXT("Value \""),
	 szKeyValueName,
	 TEXT("\" of registry key \"" KEY_SERVICE_PARAMETERS "\" has wrong type\n"),NullS);
 fprintf(stderr, szErrorMsg); /* not unicode compatible */
}

static bool copy_key_value(HKEY hParametersKey, char **var, const char *value)
{
  if (!(*var=my_strdup(value,MYF(MY_WME))))
  {
    RegCloseKey(hParametersKey);
    fprintf(stderr, "Couldn't allocate memory for registry key value\n");
    return 1;
  }
  return 0;
}

static bool set_varval(HKEY hParametersKey,const char *var,
		       const char *szKeyValueName, DWORD dwKeyValueType,
		       LPDWORD lpdwValue)
{
  CHECK_KEY_TYPE(dwKeyValueType, szKeyValueName );
  if (set_changeable_varval(var, *lpdwValue, changeable_vars))
  {
    TCHAR szErrorMsg [ 512 ];
    RegCloseKey( hParametersKey );
    strxmov(szErrorMsg,
	    TEXT("Value \""),
	    szKeyValueName,
	    TEXT("\" of registry key \"" KEY_SERVICE_PARAMETERS  "\" is invalid\n"),NullS);
    fprintf( stderr, szErrorMsg ); /* not unicode compatible */
    return 1;
  }
  return 0;
}


static int get_service_parameters()
{
  DWORD dwLastError;
  HKEY hParametersKey;
  DWORD dwIndex;
  TCHAR szKeyValueName [ 256 ];
  DWORD dwKeyValueName;
  DWORD dwKeyValueType;
  BYTE bKeyValueBuffer [ 512 ];
  DWORD dwKeyValueBuffer;
  LPDWORD lpdwValue = (LPDWORD) &bKeyValueBuffer[0];
  LPCTSTR lpszValue = (LPCTSTR) &bKeyValueBuffer[0];

  /* open parameters of service */
  dwLastError = (DWORD) RegOpenKeyEx( HKEY_LOCAL_MACHINE,
				      TEXT(KEY_SERVICE_PARAMETERS), 0,
				      KEY_READ, &hParametersKey );
  if ( dwLastError == ERROR_FILE_NOT_FOUND ) /* no parameters available */
    return 0;
  if ( dwLastError != ERROR_SUCCESS )
  {
    fprintf(stderr,"Can't open registry key \"" KEY_SERVICE_PARAMETERS "\" for reading\n" );
    return 1;
  }

  /* enumerate all values of key */
  dwIndex = 0;
  dwKeyValueName = sizeof( szKeyValueName ) / sizeof( TCHAR );
  dwKeyValueBuffer = sizeof( bKeyValueBuffer );
  while ( (dwLastError = (DWORD) RegEnumValue(hParametersKey, dwIndex,
					      szKeyValueName, &dwKeyValueName,
					      NULL, &dwKeyValueType,
					      &bKeyValueBuffer[0],
					      &dwKeyValueBuffer))
	  != ERROR_NO_MORE_ITEMS )
  {
    /* check if error occured */
    if ( dwLastError != ERROR_SUCCESS )
    {
      RegCloseKey( hParametersKey );
      fprintf( stderr, "Can't enumerate values of registry key \"" KEY_SERVICE_PARAMETERS "\"\n" );
      return 1;
    }
    if ( lstrcmp(szKeyValueName, TEXT("BaseDir")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName);
      strmov( mysql_home, lpszValue ); /* not unicode compatible */
    }
    else if ( lstrcmp(szKeyValueName, TEXT("BindAddress")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName);

      my_bind_addr = (ulong) inet_addr( lpszValue );
      if ( my_bind_addr == (ulong) INADDR_NONE )
      {
	struct hostent* ent;

	if ( !(*lpszValue) )
	{
	  char szHostName [ 256 ];
	  if ( gethostname(szHostName, sizeof(szHostName)) == SOCKET_ERROR )
	  {
	    RegCloseKey( hParametersKey );
	    fprintf( stderr, "Can't get my own hostname\n" );
	    return 1;
	  }
	  ent = gethostbyname( szHostName );
	}
	else ent = gethostbyname( lpszValue );
	if ( !ent )
	{
	  RegCloseKey( hParametersKey );
	  fprintf( stderr, "Can't resolve hostname!\n" );
	  return 1;
	}
	my_bind_addr = (ulong) ((in_addr*)ent->h_addr_list[0])->s_addr;
      }
    }
    else if ( lstrcmp(szKeyValueName, TEXT("BigTables")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName);
      if ( *lpdwValue )
	thd_startup_options |= OPTION_BIG_TABLES;
      else
	thd_startup_options &= ~((ulong)OPTION_BIG_TABLES);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("DataDir")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      strmov( mysql_real_data_home, lpszValue ); /* not unicode compatible */
    }
    else if ( lstrcmp(szKeyValueName, TEXT("Locking")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      my_disable_locking = !(*lpdwValue);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("LogFile")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      opt_log = 1;
      COPY_KEY_VALUE( opt_logname );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("UpdateLogFile")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      opt_update_log = 1;
      COPY_KEY_VALUE( opt_update_logname );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("BinaryLogFile")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      opt_bin_log = 1;
      COPY_KEY_VALUE( opt_bin_logname );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("BinaryLogIndexFile")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      opt_bin_log = 1;
      COPY_KEY_VALUE( opt_binlog_index_name );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("ISAMLogFile")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      COPY_KEY_VALUE( myisam_log_filename );
      opt_myisam_log=1;
    }
    else if ( lstrcmp(szKeyValueName, TEXT("LongLogFormat")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      if ( *lpdwValue )
	opt_specialflag |= SPECIAL_LONG_LOG_FORMAT;
      else
	opt_specialflag &= ~((ulong)SPECIAL_LONG_LOG_FORMAT);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("LowPriorityUpdates")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      if ( *lpdwValue )
      {
	thd_startup_options |= OPTION_LOW_PRIORITY_UPDATES;
	low_priority_updates = 1;
      }
      else
      {
	thd_startup_options &= ~((ulong)OPTION_LOW_PRIORITY_UPDATES);
	low_priority_updates = 0;
      }
    }
    else if ( lstrcmp(szKeyValueName, TEXT("Port")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      mysql_port = (unsigned int) *lpdwValue;
    }
    else if ( lstrcmp(szKeyValueName, TEXT("OldProtocol")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      protocol_version = *lpdwValue ? PROTOCOL_VERSION - 1 : PROTOCOL_VERSION;
    }
    else if ( lstrcmp(szKeyValueName, TEXT("HostnameResolving")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      if ( !*lpdwValue )
	opt_specialflag |= SPECIAL_NO_RESOLVE;
      else
	opt_specialflag &= ~((ulong)SPECIAL_NO_RESOLVE);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("Networking")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      opt_disable_networking = !(*lpdwValue);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("ShowDatabase")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      opt_disable_networking = !(*lpdwValue);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("HostnameCaching")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      if ( !*lpdwValue )
	opt_specialflag |= SPECIAL_NO_HOST_CACHE;
      else
	opt_specialflag &= ~((ulong)SPECIAL_NO_HOST_CACHE);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("ThreadPriority")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      if ( !(*lpdwValue) )
	opt_specialflag |= SPECIAL_NO_PRIOR;
      else
	opt_specialflag &= ~((ulong)SPECIAL_NO_PRIOR);
    }
    else if ( lstrcmp(szKeyValueName, TEXT("NamedPipe")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      COPY_KEY_VALUE( mysql_unix_port );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("TempDir")) == 0 )
    {
      CHECK_KEY_TYPE( REG_SZ, szKeyValueName );
      COPY_KEY_VALUE( mysql_tmpdir );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("FlushTables")) == 0 )
    {
      CHECK_KEY_TYPE( REG_DWORD, szKeyValueName );
      nisam_flush = myisam_flush= *lpdwValue ? 1 : 0;
    }
    else if ( lstrcmp(szKeyValueName, TEXT("BackLog")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "back_log" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("ConnectTimeout")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "connect_timeout" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("JoinBufferSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "join_buffer" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("KeyBufferSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "key_buffer" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("LongQueryTime")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "long_query_time" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxAllowedPacket")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "max_allowed_packet" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxConnections")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "max_connections" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxConnectErrors")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "max_connect_errors" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxInsertDelayedThreads")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "max_delayed_threads" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxJoinSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "max_join_size" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxSortLength")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "max_sort_length" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("NetBufferLength")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "net_buffer_length" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("RecordBufferSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "record_buffer" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("SortBufferSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "sort_buffer" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("TableCacheSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "table_cache" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("TmpTableSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "tmp_table_size" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("ThreadStackSize")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "thread_stack" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("WaitTimeout")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "wait_timeout" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("DelayedInsertTimeout"))
	      == 0 )
    {
      SET_CHANGEABLE_VARVAL( "delayed_insert_timeout" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("DelayedInsertLimit")) ==
	      0 )
    {
      SET_CHANGEABLE_VARVAL( "delayed_insert_limit" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("DelayedQueueSize")) == 0
	      )
    {
      SET_CHANGEABLE_VARVAL( "delayed_queue_size" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("FlushTime")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "flush_time" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("InteractiveTimeout")) ==
	      0 )
    {
      SET_CHANGEABLE_VARVAL( "interactive_timeout" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("LowerCaseTableNames"))
	      == 0 )
    {
      SET_CHANGEABLE_VARVAL( "lower_case_table_names" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxHeapTableSize")) == 0
	      )
    {
      SET_CHANGEABLE_VARVAL( "max_heap_table_size" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxTmpTables")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "max_tmp_tables" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("MaxWriteLockCount")) ==
	      0 )
    {
      SET_CHANGEABLE_VARVAL( "max_write_lock_count" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("NetRetryCount")) == 0 )
    {
      SET_CHANGEABLE_VARVAL( "net_retry_count" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("QueryBufferSize")) == 0
	      )
    {
      SET_CHANGEABLE_VARVAL( "query_buffer_size" );
    }
    else if ( lstrcmp(szKeyValueName, TEXT("ThreadConcurrency")) ==
	      0 )
    {
      SET_CHANGEABLE_VARVAL( "thread_concurrency" );
    }
    else
    {
      TCHAR szErrorMsg [ 512 ];
      RegCloseKey( hParametersKey );
      lstrcpy( szErrorMsg, TEXT("Value \"") );
      lstrcat( szErrorMsg, szKeyValueName );
      lstrcat( szErrorMsg, TEXT("\" of registry key \"" KEY_SERVICE_PARAMETERS "\" is not defined by MySQL\n") );
      fprintf( stderr, szErrorMsg ); /* not unicode compatible */
      return 1;
    }

    dwIndex++;
    dwKeyValueName = sizeof( szKeyValueName ) / sizeof( TCHAR );
    dwKeyValueBuffer = sizeof( bKeyValueBuffer );
  }
  RegCloseKey( hParametersKey );

  /* paths are fixed by method get_options() */
  return 0;
}
#endif


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;
}


static void fix_paths(void)
{
  (void) fn_format(mysql_home,mysql_home,"","",16); // Remove symlinks
  convert_dirname(mysql_home);
  convert_dirname(mysql_real_data_home);
  convert_dirname(language);
  (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);
  (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)
  {
    strmov(tmp,mysql_tmpdir);
    mysql_tmpdir=tmp;
    convert_dirname(mysql_tmpdir);
    mysql_tmpdir=(char*) my_realloc(mysql_tmpdir,(uint) strlen(mysql_tmpdir)+1,
				    MYF(MY_HOLD_ON_ERROR));
  }
}


#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


	/*
	  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;
  do
  {
    if (!*(end=strcend(pos,',')))		/* Let end point at fieldend */
    {
      while (end > pos && end[-1] == ' ')
	end--;					/* Skipp 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;
  } while (! found_end);

  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>;
#endif
