Quick fix for a small problem. If you run 'nmbd -?' you'd get the usage
[samba.git] / source3 / nmbd / nmbd.c
index 11f005b78521fcbc88bfc3e0d09e9ff3d5cbf68f..9df30adc8c850327c1b19eb02c40a0414377bc5c 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    NBT netbios routines and daemon - version 2
-   Copyright (C) Andrew Tridgell 1994-1997
+   Copyright (C) Andrew Tridgell 1994-1998
    
    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
@@ -34,540 +34,727 @@ pstring servicesf = CONFIGFILE;
 
 extern pstring scope;
 
-int ClientNMB   = -1;
-int ClientDGRAM = -1;
+int ClientNMB       = -1;
+int ClientDGRAM     = -1;
+int global_nmb_port = -1;
 
 extern pstring myhostname;
 static pstring host_file;
-extern pstring myname;
-extern fstring myworkgroup;
+extern pstring global_myname;
+extern fstring global_myworkgroup;
+extern char **my_netbios_names;
+
+extern BOOL global_in_nmbd;
 
 /* are we running as a daemon ? */
 static BOOL is_daemon = False;
 
+/* have we found LanMan clients yet? */
+BOOL found_lm_clients = False;
+
 /* what server type are we currently */
 
-time_t StartupTime =0;
+time_t StartupTime = 0;
 
 extern struct in_addr ipzero;
 
- /****************************************************************************
+/**************************************************************************** **
   catch a sigterm
 ****************************************************************************/
-static int sig_term()
**************************************************************************** */
+static int sig_term(void)
 {
   BlockSignals(True,SIGTERM);
   
   DEBUG(0,("Got SIGTERM: going down...\n"));
   
-  /* write out wins.dat file if samba is a WINS server */
-  dump_names();
+  /* Write out wins.dat file if samba is a WINS server */
+  wins_write_database();
   
-  /* remove all samba names, with wins server if necessary. */
-  remove_my_names();
+  /* Remove all SELF registered names. */
+  release_my_names();
   
-  /* announce all server entries as 0 time-to-live, 0 type */
-  /* XXXX don't care if we never receive a response back... yet */
+  /* Announce all server entries as 0 time-to-live, 0 type. */
   announce_my_servers_removed();
 
-  /* XXXX other things: if we are a master browser, force an election? */
-  
+  /* If there was an async dns child - kill it. */
+  kill_async_dns_child();
+
   exit(0);
-}
 
+  /* Keep compiler happy.. */
+  return 0;
+} /* sig_term */
 
-/****************************************************************************
-catch a sighup
-****************************************************************************/
+/**************************************************************************** **
+ catch a sighup
+ **************************************************************************** */
 static int sig_hup(void)
 {
-  BlockSignals(True,SIGHUP);
+  BlockSignals( True, SIGHUP );
 
-  DEBUG(0,("Got SIGHUP (reload not implemented)\n"));
-  dump_names();
-  reload_services(True);
+  DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) );
+
+  write_browse_list( 0, True );
+
+  dump_all_namelists();
+  reload_services( True );
 
   set_samba_nb_type();
 
   BlockSignals(False,SIGHUP);
-#ifndef DONT_REINSTALL_SIG
-  signal(SIGHUP,SIGNAL_CAST sig_hup);
-#endif
+
   return(0);
-}
+} /* sig_hup */
 
-/****************************************************************************
-catch a sigpipe
-****************************************************************************/
+/**************************************************************************** **
+ catch a sigpipe
+ **************************************************************************** */
 static int sig_pipe(void)
 {
-  BlockSignals(True,SIGPIPE);
+  BlockSignals( True, SIGPIPE );
 
-  DEBUG(0,("Got SIGPIPE\n"));
-  if (!is_daemon)
+  DEBUG( 0, ("Got SIGPIPE\n") );
+  if ( !is_daemon )
     exit(1);
-  BlockSignals(False,SIGPIPE);
+  BlockSignals( False, SIGPIPE );
   return(0);
-}
+} /* sig_pipe */
 
 #if DUMP_CORE
-/*******************************************************************
-prepare to dump a core file - carefully!
-********************************************************************/
+/**************************************************************************** **
+ prepare to dump a core file - carefully!
+ **************************************************************************** */
 static BOOL dump_core(void)
 {
   char *p;
   pstring dname;
-  strcpy(dname,debugf);
-  if ((p=strrchr(dname,'/'))) *p=0;
-  strcat(dname,"/corefiles");
-  mkdir(dname,0700);
-  sys_chown(dname,getuid(),getgid());
-  chmod(dname,0700);
-  if (chdir(dname)) return(False);
-  umask(~(0700));
-
-#ifndef NO_GETRLIMIT
+  pstrcpy( dname, debugf );
+  if ((p=strrchr(dname,'/')))
+    *p=0;
+  pstrcat( dname, "/corefiles" );
+  mkdir( dname, 0700 );
+  sys_chown( dname, getuid(), getgid() );
+  chmod( dname, 0700 );
+  if ( chdir(dname) )
+    return( False );
+  umask( ~(0700) );
+
+#ifdef HAVE_GETRLIMIT
 #ifdef RLIMIT_CORE
   {
     struct rlimit rlp;
-    getrlimit(RLIMIT_CORE, &rlp);
-    rlp.rlim_cur = MAX(4*1024*1024,rlp.rlim_cur);
-    setrlimit(RLIMIT_CORE, &rlp);
-    getrlimit(RLIMIT_CORE, &rlp);
-    DEBUG(3,("Core limits now %d %d\n",rlp.rlim_cur,rlp.rlim_max));
+    getrlimit( RLIMIT_CORE, &rlp );
+    rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
+    setrlimit( RLIMIT_CORE, &rlp );
+    getrlimit( RLIMIT_CORE, &rlp );
+    DEBUG( 3, ( "Core limits now %d %d\n", rlp.rlim_cur, rlp.rlim_max ) );
   }
 #endif
 #endif
 
 
-  DEBUG(0,("Dumping core in %s\n",dname));
-  return(True);
-}
+  DEBUG( 0, ( "Dumping core in %s\n",dname ) );
+  return( True );
+} /* dump_core */
 #endif
 
 
-/****************************************************************************
-possibly continue after a fault
-****************************************************************************/
+/**************************************************************************** **
+ possibly continue after a fault
+ **************************************************************************** */
 static void fault_continue(void)
 {
 #if DUMP_CORE
   dump_core();
 #endif
-}
+} /* fault_continue */
 
-/*******************************************************************
 expire old names from the namelist and server list
 ******************************************************************/
+/**************************************************************************** **
+ expire old names from the namelist and server list
**************************************************************************** */
 static void expire_names_and_servers(time_t t)
 {
   static time_t lastrun = 0;
   
-  if (!lastrun) lastrun = t;
-  if (t < lastrun + 5) return;
+  if ( !lastrun )
+    lastrun = t;
+  if ( t < (lastrun + 5) )
+    return;
   lastrun = t;
-  
+
+  /*
+   * Expire any timed out names on all the broadcast
+   * subnets and those registered with the WINS server.
+   * (nmbd_namelistdb.c)
+   */
   expire_names(t);
-  expire_servers(t);
-}
 
-/*****************************************************************************
+  /*
+   * Go through all the broadcast subnets and for each
+   * workgroup known on that subnet remove any expired
+   * server names. If a workgroup has an empty serverlist
+   * and has itself timed out then remove the workgroup.
+   * (nmbd_workgroupdb.c)
+   */
+  expire_workgroups_and_servers(t);
+} /* expire_names_and_servers */
+
+/**************************************************************************** **
   reload the services file
 **************************************************************************/
**************************************************************************** */
 BOOL reload_services(BOOL test)
 {
   BOOL ret;
   extern fstring remote_machine;
 
-  strcpy(remote_machine,"nmbd");
+  fstrcpy( remote_machine, "nmb" );
 
-  if (lp_loaded())
+  if ( lp_loaded() )
+  {
+    pstring fname;
+    pstrcpy( fname,lp_configfile());
+    if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
     {
-      pstring fname;
-      strcpy(fname,lp_configfile());
-      if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
-       {
-         strcpy(servicesf,fname);
-         test = False;
-       }
+      pstrcpy(servicesf,fname);
+      test = False;
     }
+  }
 
-  if (test && !lp_file_list_changed())
+  if ( test && !lp_file_list_changed() )
     return(True);
 
-  ret = lp_load(servicesf,True);
+  ret = lp_load( servicesf, True , False, False);
 
   /* perhaps the config filename is now set */
-  if (!test) {
-    DEBUG(3,("services not loaded\n"));
-    reload_services(True);
+  if ( !test )
+  {
+    DEBUG( 3, ( "services not loaded\n" ) );
+    reload_services( True );
   }
 
   /* Do a sanity check for a misconfigured nmbd */
-  if(lp_wins_support() && *lp_wins_server()) {
+  if( lp_wins_support() && *lp_wins_server() )
+  {
     DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
 cannot be set in the smb.conf file. nmbd aborting.\n"));
     exit(10);
   }
 
   return(ret);
-}
-
-
-
-/****************************************************************************
-load a netbios hosts file
-****************************************************************************/
-static void load_hosts_file(char *fname)
-{
-  FILE *f = fopen(fname,"r");
-  pstring line;
-  if (!f) {
-    DEBUG(2,("Can't open lmhosts file %s\n",fname));
-    return;
-  }
+} /* reload_services */
 
-  while (!feof(f))
-    {
-      pstring ip,name,flags,extra;
-      struct subnet_record *d;
-      char *ptr;
-      int count = 0;
-      struct in_addr ipaddr;
-      enum name_source source = LMHOSTS;
-
-      if (!fgets_slash(line,sizeof(pstring),f)) continue;
-
-      if (*line == '#') continue;
-
-      strcpy(ip,"");
-      strcpy(name,"");
-      strcpy(flags,"");
-      
-      ptr = line;
-      
-      if (next_token(&ptr,ip   ,NULL)) ++count;
-      if (next_token(&ptr,name ,NULL)) ++count;
-      if (next_token(&ptr,flags,NULL)) ++count;
-      if (next_token(&ptr,extra,NULL)) ++count;
-      
-      if (count <= 0) continue;
-      
-      if (count > 0 && count < 2) {
-       DEBUG(0,("Ill formed hosts line [%s]\n",line));     
-       continue;
-      }
-      
-      if (count >= 4) {
-       DEBUG(0,("too many columns in %s (obsolete syntax)\n",fname));
-       continue;
-      }
-      
-      DEBUG(4, ("lmhost entry: %s %s %s\n", ip, name, flags));
-      
-      if (strchr(flags,'G') || strchr(flags,'S')) {
-       DEBUG(0,("group flag in %s ignored (obsolete)\n",fname));
-       continue;
-      }
-      
-      if (strchr(flags,'M')) {
-       source = SELF;
-       strcpy(myname,name);
-      }
-      
-      ipaddr = *interpret_addr2(ip);
-      d = find_subnet_all(ipaddr);
-      if (d) {
-       add_netbios_entry(d,name,0x00,NB_ACTIVE,0,source,ipaddr,True,True);
-       add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
-      } 
-    }
-  
-  fclose(f);
-}
-
-
-/****************************************************************************
-  The main select loop.
-  ***************************************************************************/
+/**************************************************************************** **
+ The main select loop.
+ **************************************************************************** */
 static void process(void)
 {
   BOOL run_election;
 
-  while (True)
-    {
-      time_t t = time(NULL);
-      run_election = check_elections();
-      listen_for_packets(run_election);
-
-      run_packet_queue();
-      run_elections(t);
-
-      announce_host(t);
-      announce_master(t);
-      announce_remote(t);
-
-      query_refresh_names(t);
-
-      expire_names_and_servers(t);
-      expire_netbios_response_entries(t);
-      refresh_my_names(t);
-
-      write_browse_list(t);
-      do_browser_lists(t);
-      check_master_browser(t);
-      add_domain_names(t);
-    }
-}
+  while( True )
+  {
+    time_t t = time(NULL);
+
+    /*
+     * Check all broadcast subnets to see if
+     * we need to run an election on any of them.
+     * (nmbd_elections.c)
+     */
+    run_election = check_elections();
+
+    /*
+     * Read incoming UDP packets.
+     * (nmbd_packets.c)
+     */
+    if(listen_for_packets(run_election))
+      return;
+
+    /*
+     * Process all incoming packets
+     * read above. This calls the success and
+     * failure functions registered when response
+     * packets arrrive, and also deals with request
+     * packets from other sources.
+     * (nmbd_packets.c)
+     */
+    run_packet_queue();
+
+    /*
+     * Run any elections - initiate becoming
+     * a local master browser if we have won.
+     * (nmbd_elections.c)
+     */
+    run_elections(t);
+
+    /*
+     * Send out any broadcast announcements
+     * of our server names. This also announces
+     * the workgroup name if we are a local
+     * master browser.
+     * (nmbd_sendannounce.c)
+     */
+    announce_my_server_names(t);
+
+    /*
+     * Send out any LanMan broadcast announcements
+     * of our server names.
+     * (nmbd_sendannounce.c)
+     */
+    announce_my_lm_server_names(t);
+
+    /*
+     * If we are a local master browser, periodically
+     * announce ourselves to the domain master browser.
+     * This also deals with syncronising the domain master
+     * browser server lists with ourselves as a local
+     * master browser.
+     * (nmbd_sendannounce.c)
+     */
+    announce_myself_to_domain_master_browser(t);
+
+    /*
+     * Fullfill any remote announce requests.
+     * (nmbd_sendannounce.c)
+     */
+    announce_remote(t);
+
+    /*
+     * Fullfill any remote browse sync announce requests.
+     * (nmbd_sendannounce.c)
+     */
+    browse_sync_remote(t);
+
+    /*
+     * Scan the broadcast subnets, and WINS client
+     * namelists and refresh any that need refreshing.
+     * (nmbd_mynames.c)
+     */
+    refresh_my_names(t);
+
+    /*
+     * Scan the subnet namelists and server lists and
+     * expire thos that have timed out.
+     * (nmbd.c)
+     */
+    expire_names_and_servers(t);
+
+    /*
+     * Write out a snapshot of our current browse list into
+     * the browse.dat file. This is used by smbd to service
+     * incoming NetServerEnum calls - used to synchronise
+     * browse lists over subnets.
+     * (nmbd_serverlistdb.c)
+     */
+    write_browse_list(t, False);
+
+    /*
+     * If we are a domain master browser, we have a list of
+     * local master browsers we should synchronise browse
+     * lists with (these are added by an incoming local
+     * master browser announcement packet). Expire any of
+     * these that are no longer current, and pull the server
+     * lists from each of these known local master browsers.
+     * (nmbd_browsesync.c)
+     */
+    dmb_expire_and_sync_browser_lists(t);
+
+    /*
+     * Check that there is a local master browser for our
+     * workgroup for all our broadcast subnets. If one
+     * is not found, start an election (which we ourselves
+     * may or may not participate in, depending on the
+     * setting of the 'local master' parameter.
+     * (nmbd_elections.c)
+     */
+    check_master_browser_exists(t);
+
+    /*
+     * If we are configured as a logon server, attempt to
+     * register the special NetBIOS names to become such
+     * (WORKGROUP<1c> name) on all broadcast subnets and
+     * with the WINS server (if used). If we are configured
+     * to become a domain master browser, attempt to register
+     * the special NetBIOS name (WORKGROUP<1b> name) to
+     * become such.
+     * (nmbd_become_dmb.c)
+     */
+    add_domain_names(t);
+
+    /*
+     * If we are a WINS server, do any timer dependent
+     * processing required.
+     * (nmbd_winsserver.c)
+     */
+    initiate_wins_processing(t);
+
+    /*
+     * If we are a domain master browser, attempt to contact the
+     * WINS server to get a list of all known WORKGROUPS/DOMAINS.
+     * This will only work to a Samba WINS server.
+     * (nmbd_browsesync.c)
+     */
+    collect_all_workgroup_names_from_wins_server(t);
+
+    /*
+     * Go through the response record queue and time out or re-transmit
+     * and expired entries.
+     * (nmbd_packets.c)
+     */
+    retransmit_or_expire_response_records(t);
+  }
+} /* process */
 
 
-/****************************************************************************
 open the socket communication
-****************************************************************************/
+/**************************************************************************** **
+ open the socket communication
+ **************************************************************************** */
 static BOOL open_sockets(BOOL isdaemon, int port)
 {
-  struct hostent *hp;
-  /* get host info */
-  if ((hp = Get_Hostbyname(myhostname)) == 0) {
-    DEBUG(0,( "Get_Hostbyname: Unknown host. %s\n",myhostname));
-    return False;
-  }   
-
-  if (isdaemon)
-    ClientNMB = open_socket_in(SOCK_DGRAM, port,0,interpret_addr(lp_socket_address()));
+  /* The sockets opened here will be used to receive broadcast
+     packets *only*. Interface specific sockets are opened in
+     make_subnet() in namedbsubnet.c. Thus we bind to the
+     address "0.0.0.0". The parameter 'socket address' is
+     now deprecated.
+   */
+
+  if ( isdaemon )
+    ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0);
   else
     ClientNMB = 0;
   
-  ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,interpret_addr(lp_socket_address()));
+  ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0);
 
-  if (ClientNMB == -1)
-    return(False);
+  if ( ClientNMB == -1 )
+    return( False );
 
-  signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+  CatchSignal( SIGPIPE, SIGNAL_CAST sig_pipe );
 
-  set_socket_options(ClientNMB,"SO_BROADCAST");
-  set_socket_options(ClientDGRAM,"SO_BROADCAST");
+  set_socket_options( ClientNMB,   "SO_BROADCAST" );
+  set_socket_options( ClientDGRAM, "SO_BROADCAST" );
 
-  DEBUG(3,("Sockets opened.\n"));
-  return True;
-}
+  DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) );
+  return( True );
+} /* open_sockets */
 
 
-/****************************************************************************
 initialise connect, service and file structs
-****************************************************************************/
-static BOOL init_structs()
+/**************************************************************************** **
+ initialise connect, service and file structs
+ **************************************************************************** */
+static BOOL init_structs(void)
 {
   extern fstring local_machine;
-  char *p;
+  char *p, *ptr;
+  int namecount;
+  int n;
+  int nodup;
+  pstring nbname;
 
-  if (! *myname) {
-    strcpy(myname,myhostname);
-    p = strchr(myname,'.');
-    if (p) *p = 0;
+  if (! *global_myname)
+  {
+    fstrcpy( global_myname, myhostname );
+    p = strchr( global_myname, '.' );
+    if (p)
+      *p = 0;
   }
-  strupper(myname);
-
-  strcpy(local_machine,myname);
-  trim_string(local_machine," "," ");
-  p = strchr(local_machine,' ');
-  if (p) *p = 0;
-  strlower(local_machine);
-
-  return True;
-}
-
-/****************************************************************************
-usage on the program
-****************************************************************************/
+  strupper( global_myname );
+
+  /* Add any NETBIOS name aliases. Ensure that the first entry
+     is equal to global_myname.
+   */
+  /* Work out the max number of netbios aliases that we have */
+  ptr = lp_netbios_aliases();
+  for( namecount=0; next_token(&ptr,nbname,NULL); namecount++ )
+    ;
+  if ( *global_myname )
+    namecount++;
+
+  /* Allocate space for the netbios aliases */
+  my_netbios_names = (char **)malloc( sizeof(char *) * (namecount+1) );
+  if( NULL == my_netbios_names )
+  {
+     DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
+     return( False );
+  }
+  /* Use the global_myname string first */
+  namecount=0;
+  if ( *global_myname )
+    my_netbios_names[namecount++] = global_myname;
+  
+  ptr = lp_netbios_aliases();
+  while ( next_token( &ptr, nbname, NULL ) )
+  {
+    strupper( nbname );
+    /* Look for duplicates */
+    nodup=1;
+    for( n=0; n<namecount; n++ )
+    {
+      if( 0 == strcmp( nbname, my_netbios_names[n] ) )
+        nodup=0;
+    }
+    if (nodup)
+      my_netbios_names[namecount++] = strdup( nbname );
+  }
+  
+  /* Check the strdups succeeded. */
+  for( n = 0; n < namecount; n++ )
+    if( NULL == my_netbios_names[n] )
+    {
+      DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
+      return False;
+    }
+  
+  /* Terminate name list */
+  my_netbios_names[namecount++] = NULL;
+  
+  fstrcpy( local_machine, global_myname );
+  trim_string( local_machine, " ", " " );
+  p = strchr( local_machine, ' ' );
+  if (p)
+    *p = 0;
+  strlower( local_machine );
+
+  DEBUG( 5, ("Netbios name list:-\n") );
+  for( n=0; my_netbios_names[n]; n++ )
+    DEBUGADD( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n] ) );
+
+  return( True );
+} /* init_structs */
+
+/**************************************************************************** **
+ usage on the program
+ **************************************************************************** */
 static void usage(char *pname)
 {
   DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
 
-  printf("Usage: %s [-n name] [-D] [-p port] [-d debuglevel] [-l log basename]\n",pname);
-  printf("Version %s\n",VERSION);
-  printf("\t-D                    become a daemon\n");
-  printf("\t-p port               listen on the specified port\n");
-  printf("\t-d debuglevel         set the debuglevel\n");
-  printf("\t-l log basename.      Basename for log/debug files\n");
-  printf("\t-n netbiosname.       the netbios name to advertise for this host\n");
-  printf("\t-H hosts file        load a netbios hosts file\n");
-  printf("\n");
-}
-
-
-/****************************************************************************
-  main program
-  **************************************************************************/
- int main(int argc,char *argv[])
+  printf( "Usage: %s [-n name] [-D] [-p port] [-d debuglevel] ", pname );
+  printf( "[-l log basename]\n" );
+  printf( "Version %s\n", VERSION );
+  printf( "\t-D                    become a daemon\n" );
+  printf( "\t-p port               listen on the specified port\n" );
+  printf( "\t-d debuglevel         set the debuglevel\n" );
+  printf( "\t-l log basename.      Basename for log/debug files\n" );
+  printf( "\t-n netbiosname.       " );
+  printf( "the netbios name to advertise for this host\n");
+  printf( "\t-H hosts file         load a netbios hosts file\n" );
+  printf( "\n");
+} /* usage */
+
+
+/**************************************************************************** **
+ main program
+ **************************************************************************** */
+int main(int argc,char *argv[])
 {
-  int port = NMB_PORT;
   int opt;
   extern FILE *dbf;
   extern char *optarg;
-  char pidFile[100] = { 0 };
 
+  global_nmb_port = NMB_PORT;
   *host_file = 0;
+  global_in_nmbd = True;
 
   StartupTime = time(NULL);
 
   TimeInit();
 
-  strcpy(debugf,NMBLOGFILE);
+  pstrcpy( debugf, NMBLOGFILE );
 
-  setup_logging(argv[0],False);
+  setup_logging( argv[0], False );
 
   charset_initialise();
 
+  if(!initialize_password_db())
+    exit(1);
+
 #ifdef LMHOSTSFILE
-  strcpy(host_file,LMHOSTSFILE);
+  pstrcpy( host_file, LMHOSTSFILE );
 #endif
 
   /* this is for people who can't start the program correctly */
-  while (argc > 1 && (*argv[1] != '-')) {
+  while (argc > 1 && (*argv[1] != '-'))
+  {
     argv++;
     argc--;
   }
 
-  fault_setup(fault_continue);
+  fault_setup((void (*)(void *))fault_continue );
+
+  CatchSignal( SIGHUP,  SIGNAL_CAST sig_hup );
+  CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
+
+  /* Setup the signals that allow the debug log level
+     to by dynamically changed. */
 
-  signal(SIGHUP ,SIGNAL_CAST sig_hup);
-  signal(SIGTERM,SIGNAL_CAST sig_term);
+  /* If we are using the malloc debug code we can't use
+     SIGUSR1 and SIGUSR2 to do debug level changes. */
+#ifndef MEM_MAN
+#if defined(SIGUSR1)
+  CatchSignal( SIGUSR1, SIGNAL_CAST sig_usr1 );
+#endif /* SIGUSR1 */
 
-  while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
+#if defined(SIGUSR2)
+  CatchSignal( SIGUSR2, SIGNAL_CAST sig_usr2 );
+#endif /* SIGUSR2 */
+#endif /* MEM_MAN */
+
+  while((opt = getopt(argc, argv, "as:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:f:")) != EOF)
     {
       switch (opt)
-       {
-        case 'f':
-          strncpy(pidFile, optarg, sizeof(pidFile));
+        {
+        case 's':
+          pstrcpy(servicesf,optarg);
+          break;          
+        case 'N':
+        case 'B':
+        case 'I':
+        case 'C':
+        case 'G':
+          DEBUG(0,("Obsolete option '%c' used\n",opt));
+          break;
+        case 'H':
+          pstrcpy(host_file,optarg);
+          break;
+        case 'n':
+          pstrcpy(global_myname,optarg);
+          strupper(global_myname);
+          break;
+        case 'l':
+          slprintf(debugf,sizeof(debugf)-1, "%s.nmb",optarg);
+          break;
+        case 'i':
+          pstrcpy(scope,optarg);
+          strupper(scope);
+          break;
+        case 'a':
+          {
+          extern BOOL append_log;
+          append_log = !append_log;
+          }
+          break;
+        case 'D':
+          is_daemon = True;
+          break;
+        case 'd':
+          DEBUGLEVEL = atoi(optarg);
+          break;
+        case 'p':
+          global_nmb_port = atoi(optarg);
           break;
-       case 's':
-         strcpy(servicesf,optarg);
-         break;          
-       case 'N':
-       case 'B':
-       case 'I':
-       case 'C':
-       case 'G':
-         DEBUG(0,("Obsolete option '%c' used\n",opt));
-         break;
-       case 'H':
-         strcpy(host_file,optarg);
-         break;
-       case 'n':
-         strcpy(myname,optarg);
-         strupper(myname);
-         break;
-       case 'l':
-         sprintf(debugf,"%s.nmb",optarg);
-         break;
-       case 'i':
-         strcpy(scope,optarg);
-         strupper(scope);
-         break;
-       case 'D':
-         is_daemon = True;
-         break;
-       case 'd':
-         DEBUGLEVEL = atoi(optarg);
-         break;
-       case 'p':
-         port = atoi(optarg);
-         break;
-       case 'h':
-         usage(argv[0]);
-         exit(0);
-         break;
-       default:
-         if (!is_a_socket(0)) {
-           usage(argv[0]);
-         }
-         break;
-       }
+        case 'h':
+          usage(argv[0]);
+          exit(0);
+          break;
+        default:
+          if( !is_a_socket(0) )
+          {
+            usage(argv[0]);
+            exit(0);
+          }
+          break;
+        }
     }
 
-  DEBUG(1,("%s netbios nameserver version %s started\n",timestring(),VERSION));
-  DEBUG(1,("Copyright Andrew Tridgell 1994\n"));
+  reopen_logs();
+
+  DEBUG( 1, ( "Netbios nameserver version %s started.\n", VERSION ) );
+  DEBUGADD( 1, ( "Copyright Andrew Tridgell 1994-1997\n" ) );
+
+  if( !get_myname( myhostname, NULL) )
+  {
+    DEBUG( 0, ( "Unable to get my hostname - exiting.\n" ) );
+    return -1;
+  }
 
-  get_myname(myhostname,NULL);
+  if ( !reload_services(False) )
+    return(-1);
 
-  if (!reload_services(False))
-    return(-1);        
+  codepage_initialise(lp_client_code_page());
 
-  init_structs();
+  if(!init_structs())
+    return -1;
 
-  reload_services(True);
+  reload_services( True );
 
-  strcpy(myworkgroup, lp_workgroup());
+  fstrcpy( global_myworkgroup, lp_workgroup() );
+
+  if (strequal(global_myworkgroup,"*"))
+  {
+    DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
+    exit(1);
+  }
 
   set_samba_nb_type();
 
-  if (!is_daemon && !is_a_socket(0)) {
+  if (!is_daemon && !is_a_socket(0))
+  {
     DEBUG(0,("standard input is not a socket, assuming -D option\n"));
     is_daemon = True;
   }
   
-  if (is_daemon) {
-    DEBUG(2,("%s becoming a daemon\n",timestring()));
+  if (is_daemon)
+  {
+    DEBUG( 2, ( "Becoming a daemon.\n" ) );
     become_daemon();
   }
 
-  if (*pidFile)
-    {
-      int     fd;
-      char    buf[20];
+  if (!directory_exist(lp_lockdir(), NULL)) {
+         mkdir(lp_lockdir(), 0755);
+  }
 
-      if ((fd = open(pidFile,
-        O_NONBLOCK | O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0)
-        {
-          DEBUG(0,("ERROR: can't open %s: %s\n", pidFile, strerror(errno)));
-          exit(1);
-        }
-      if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)==False)
-        {
-          DEBUG(0,("ERROR: nmbd is already running\n"));
-          exit(1);
-        }
-      sprintf(buf, "%u\n", (unsigned int) getpid());
-      if (write(fd, buf, strlen(buf)) < 0)
-        {
-          DEBUG(0,("ERROR: can't write to %s: %s\n", pidFile, strerror(errno)));
-          exit(1);
-        }
-      /* Leave pid file open & locked for the duration... */
-    }
+  pidfile_create("nmbd");
 
+  DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
 
-  DEBUG(3,("Opening sockets %d\n", port));
+  if ( !open_sockets( is_daemon, global_nmb_port ) )
+    return 1;
 
-  if (!open_sockets(is_daemon,port)) return 1;
+  /* Determine all the IP addresses we have. */
+  load_interfaces();
 
-  if (*host_file) {
-    load_hosts_file(host_file);
-    DEBUG(3,("Loaded hosts file\n"));
+  /* Create an nmbd subnet record for each of the above. */
+  if( False == create_subnets() )
+  {
+    DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
+    exit(1);
   }
 
-  load_interfaces();
-  add_my_subnets(myworkgroup);
-
-  add_my_names();
+  /* Load in any static local names. */ 
+  if ( *host_file )
+  {
+    load_lmhosts_file(host_file);
+    DEBUG(3,("Loaded hosts file\n"));
+  }
 
-  if (strequal(myworkgroup,"*")) {
-    DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
+  /* If we are acting as a WINS server, initialise data structures. */
+  if( !initialise_wins() )
+  {
+    DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
     exit(1);
   }
 
-  DEBUG(3,("Checked names\n"));
-  
-  load_netbios_names();
-
-  DEBUG(3,("Loaded names\n"));
+  /* 
+   * Register nmbd primary workgroup and nmbd names on all
+   * the broadcast subnets, and on the WINS server (if specified).
+   * Also initiate the startup of our primary workgroup (start
+   * elections if we are setup as being able to be a local
+   * master browser.
+   */
 
-  write_browse_list(time(NULL));
+  if( False == register_my_workgroup_and_names() )
+  {
+    DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
+    exit(1);
+  }
 
-  DEBUG(3,("Dumped names\n"));
+  /* We can only take signals in the select. */
+  BlockSignals( True, SIGTERM );
+#if defined(SIGUSR1)
+  BlockSignals( True, SIGUSR1);
+#endif /* SIGUSR1 */
+#if defined(SIGUSR2)
+  BlockSignals( True, SIGUSR2);
+#endif /* SIGUSR2 */
 
   process();
   close_sockets();
@@ -575,4 +762,6 @@ static void usage(char *pname)
   if (dbf)
     fclose(dbf);
   return(0);
-}
+} /* main */
+
+/* ========================================================================== */