if we are adding a new sambaAccount, make sure that we add a
[Samba.git] / source / nmbd / nmbd.c
blob122bd8ba42ae05a94ce1143bfa35f43690564eb6
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 Revision History:
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
28 #include "includes.h"
30 pstring servicesf = CONFIGFILE;
32 int ClientNMB = -1;
33 int ClientDGRAM = -1;
34 int global_nmb_port = -1;
36 static pstring host_file;
37 extern pstring global_myname;
38 extern fstring global_myworkgroup;
39 extern char **my_netbios_names;
41 extern BOOL global_in_nmbd;
43 /* are we running as a daemon ? */
44 static BOOL is_daemon = False;
46 /* have we found LanMan clients yet? */
47 BOOL found_lm_clients = False;
49 /* what server type are we currently */
51 time_t StartupTime = 0;
53 /**************************************************************************** **
54 Handle a SIGTERM in band.
55 **************************************************************************** */
57 static void terminate(void)
59 DEBUG(0,("Got SIGTERM: going down...\n"));
61 /* Write out wins.dat file if samba is a WINS server */
62 wins_write_database(False);
64 /* Remove all SELF registered names. */
65 release_my_names();
67 /* Announce all server entries as 0 time-to-live, 0 type. */
68 announce_my_servers_removed();
70 /* If there was an async dns child - kill it. */
71 kill_async_dns_child();
73 exit(0);
76 /**************************************************************************** **
77 Catch a SIGTERM signal.
78 **************************************************************************** */
80 static SIG_ATOMIC_T got_sig_term;
82 static void sig_term(int sig)
84 got_sig_term = 1;
85 sys_select_signal();
88 /**************************************************************************** **
89 Catch a SIGHUP signal.
90 **************************************************************************** */
92 static SIG_ATOMIC_T reload_after_sighup;
94 static void sig_hup(int sig)
96 reload_after_sighup = 1;
97 sys_select_signal();
100 #if DUMP_CORE
101 /**************************************************************************** **
102 Prepare to dump a core file - carefully!
103 **************************************************************************** */
105 static BOOL dump_core(void)
107 char *p;
108 pstring dname;
109 pstrcpy( dname, lp_logfile() );
110 if ((p=strrchr(dname,'/')))
111 *p=0;
112 pstrcat( dname, "/corefiles" );
113 mkdir( dname, 0700 );
114 sys_chown( dname, getuid(), getgid() );
115 chmod( dname, 0700 );
116 if ( chdir(dname) )
117 return( False );
118 umask( ~(0700) );
120 #ifdef HAVE_GETRLIMIT
121 #ifdef RLIMIT_CORE
123 struct rlimit rlp;
124 getrlimit( RLIMIT_CORE, &rlp );
125 rlp.rlim_cur = MAX( 4*1024*1024, rlp.rlim_cur );
126 setrlimit( RLIMIT_CORE, &rlp );
127 getrlimit( RLIMIT_CORE, &rlp );
128 DEBUG( 3, ( "Core limits now %d %d\n", (int)rlp.rlim_cur, (int)rlp.rlim_max ) );
130 #endif
131 #endif
134 DEBUG(0,("Dumping core in %s\n",dname));
135 abort();
136 return( True );
137 } /* dump_core */
138 #endif
140 /**************************************************************************** **
141 Possibly continue after a fault.
142 **************************************************************************** */
144 static void fault_continue(void)
146 #if DUMP_CORE
147 dump_core();
148 #endif
149 } /* fault_continue */
151 /**************************************************************************** **
152 Expire old names from the namelist and server list.
153 **************************************************************************** */
155 static void expire_names_and_servers(time_t t)
157 static time_t lastrun = 0;
159 if ( !lastrun )
160 lastrun = t;
161 if ( t < (lastrun + 5) )
162 return;
163 lastrun = t;
166 * Expire any timed out names on all the broadcast
167 * subnets and those registered with the WINS server.
168 * (nmbd_namelistdb.c)
170 expire_names(t);
173 * Go through all the broadcast subnets and for each
174 * workgroup known on that subnet remove any expired
175 * server names. If a workgroup has an empty serverlist
176 * and has itself timed out then remove the workgroup.
177 * (nmbd_workgroupdb.c)
179 expire_workgroups_and_servers(t);
180 } /* expire_names_and_servers */
182 /************************************************************************** **
183 Reload the list of network interfaces.
184 ************************************************************************** */
186 static BOOL reload_interfaces(time_t t)
188 static time_t lastt;
189 int n;
190 struct subnet_record *subrec;
191 extern BOOL rescan_listen_set;
192 extern struct in_addr loopback_ip;
194 if (t && ((t - lastt) < NMBD_INTERFACES_RELOAD)) return False;
195 lastt = t;
197 if (!interfaces_changed()) return False;
199 /* the list of probed interfaces has changed, we may need to add/remove
200 some subnets */
201 load_interfaces();
203 /* find any interfaces that need adding */
204 for (n=iface_count() - 1; n >= 0; n--) {
205 struct interface *iface = get_interface(n);
208 * We don't want to add a loopback interface, in case
209 * someone has added 127.0.0.1 for smbd, nmbd needs to
210 * ignore it here. JRA.
213 if (ip_equal(iface->ip, loopback_ip)) {
214 DEBUG(2,("reload_interfaces: Ignoring loopback interface %s\n", inet_ntoa(iface->ip)));
215 continue;
218 for (subrec=subnetlist; subrec; subrec=subrec->next) {
219 if (ip_equal(iface->ip, subrec->myip) &&
220 ip_equal(iface->nmask, subrec->mask_ip)) break;
223 if (!subrec) {
224 /* it wasn't found! add it */
225 DEBUG(2,("Found new interface %s\n",
226 inet_ntoa(iface->ip)));
227 subrec = make_normal_subnet(iface);
228 if (subrec) register_my_workgroup_one_subnet(subrec);
232 /* find any interfaces that need deleting */
233 for (subrec=subnetlist; subrec; subrec=subrec->next) {
234 for (n=iface_count() - 1; n >= 0; n--) {
235 struct interface *iface = get_interface(n);
236 if (ip_equal(iface->ip, subrec->myip) &&
237 ip_equal(iface->nmask, subrec->mask_ip)) break;
239 if (n == -1) {
240 /* oops, an interface has disapeared. This is
241 tricky, we don't dare actually free the
242 interface as it could be being used, so
243 instead we just wear the memory leak and
244 remove it from the list of interfaces without
245 freeing it */
246 DEBUG(2,("Deleting dead interface %s\n",
247 inet_ntoa(subrec->myip)));
248 close_subnet(subrec);
252 rescan_listen_set = True;
254 /* We need to shutdown if there are no subnets... */
255 if (FIRST_SUBNET == NULL) {
256 DEBUG(0,("reload_interfaces: No subnets to listen to. Shutting down...\n"));
257 return True;
259 return False;
262 /**************************************************************************** **
263 Reload the services file.
264 **************************************************************************** */
266 static BOOL reload_nmbd_services(BOOL test)
268 BOOL ret;
269 extern fstring remote_machine;
271 fstrcpy( remote_machine, "nmbd" );
273 if ( lp_loaded() )
275 pstring fname;
276 pstrcpy( fname,lp_configfile());
277 if (file_exist(fname,NULL) && !strcsequal(fname,servicesf))
279 pstrcpy(servicesf,fname);
280 test = False;
284 if ( test && !lp_file_list_changed() )
285 return(True);
287 ret = lp_load( servicesf, True , False, False);
289 /* perhaps the config filename is now set */
290 if ( !test )
292 DEBUG( 3, ( "services not loaded\n" ) );
293 reload_nmbd_services( True );
296 /* Do a sanity check for a misconfigured nmbd */
297 if( lp_wins_support() && *lp_wins_server() )
299 DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = <server>' \
300 cannot be set in the smb.conf file. nmbd aborting.\n"));
301 exit(10);
304 return(ret);
305 } /* reload_nmbd_services */
307 /**************************************************************************** **
308 The main select loop.
309 **************************************************************************** */
311 static void process(void)
313 BOOL run_election;
315 while( True )
317 time_t t = time(NULL);
319 /* check for internal messages */
320 message_dispatch();
323 * Check all broadcast subnets to see if
324 * we need to run an election on any of them.
325 * (nmbd_elections.c)
327 run_election = check_elections();
330 * Read incoming UDP packets.
331 * (nmbd_packets.c)
333 if(listen_for_packets(run_election))
334 return;
337 * Handle termination inband.
340 if (got_sig_term) {
341 got_sig_term = 0;
342 terminate();
346 * Process all incoming packets
347 * read above. This calls the success and
348 * failure functions registered when response
349 * packets arrrive, and also deals with request
350 * packets from other sources.
351 * (nmbd_packets.c)
353 run_packet_queue();
356 * Run any elections - initiate becoming
357 * a local master browser if we have won.
358 * (nmbd_elections.c)
360 run_elections(t);
363 * Send out any broadcast announcements
364 * of our server names. This also announces
365 * the workgroup name if we are a local
366 * master browser.
367 * (nmbd_sendannounce.c)
369 announce_my_server_names(t);
372 * Send out any LanMan broadcast announcements
373 * of our server names.
374 * (nmbd_sendannounce.c)
376 announce_my_lm_server_names(t);
379 * If we are a local master browser, periodically
380 * announce ourselves to the domain master browser.
381 * This also deals with syncronising the domain master
382 * browser server lists with ourselves as a local
383 * master browser.
384 * (nmbd_sendannounce.c)
386 announce_myself_to_domain_master_browser(t);
389 * Fullfill any remote announce requests.
390 * (nmbd_sendannounce.c)
392 announce_remote(t);
395 * Fullfill any remote browse sync announce requests.
396 * (nmbd_sendannounce.c)
398 browse_sync_remote(t);
401 * Scan the broadcast subnets, and WINS client
402 * namelists and refresh any that need refreshing.
403 * (nmbd_mynames.c)
405 refresh_my_names(t);
408 * Scan the subnet namelists and server lists and
409 * expire thos that have timed out.
410 * (nmbd.c)
412 expire_names_and_servers(t);
415 * Write out a snapshot of our current browse list into
416 * the browse.dat file. This is used by smbd to service
417 * incoming NetServerEnum calls - used to synchronise
418 * browse lists over subnets.
419 * (nmbd_serverlistdb.c)
421 write_browse_list(t, False);
424 * If we are a domain master browser, we have a list of
425 * local master browsers we should synchronise browse
426 * lists with (these are added by an incoming local
427 * master browser announcement packet). Expire any of
428 * these that are no longer current, and pull the server
429 * lists from each of these known local master browsers.
430 * (nmbd_browsesync.c)
432 dmb_expire_and_sync_browser_lists(t);
435 * Check that there is a local master browser for our
436 * workgroup for all our broadcast subnets. If one
437 * is not found, start an election (which we ourselves
438 * may or may not participate in, depending on the
439 * setting of the 'local master' parameter.
440 * (nmbd_elections.c)
442 check_master_browser_exists(t);
445 * If we are configured as a logon server, attempt to
446 * register the special NetBIOS names to become such
447 * (WORKGROUP<1c> name) on all broadcast subnets and
448 * with the WINS server (if used). If we are configured
449 * to become a domain master browser, attempt to register
450 * the special NetBIOS name (WORKGROUP<1b> name) to
451 * become such.
452 * (nmbd_become_dmb.c)
454 add_domain_names(t);
457 * If we are a WINS server, do any timer dependent
458 * processing required.
459 * (nmbd_winsserver.c)
461 initiate_wins_processing(t);
464 * If we are a domain master browser, attempt to contact the
465 * WINS server to get a list of all known WORKGROUPS/DOMAINS.
466 * This will only work to a Samba WINS server.
467 * (nmbd_browsesync.c)
469 if (lp_enhanced_browsing()) {
470 collect_all_workgroup_names_from_wins_server(t);
474 * Go through the response record queue and time out or re-transmit
475 * and expired entries.
476 * (nmbd_packets.c)
478 retransmit_or_expire_response_records(t);
481 * check to see if any remote browse sync child processes have completed
483 sync_check_completion();
486 * regularly sync with any other DMBs we know about
488 if (lp_enhanced_browsing()) {
489 sync_all_dmbs(t);
493 * clear the unexpected packet queue
495 clear_unexpected(t);
498 * Reload the services file if we got a sighup.
501 if(reload_after_sighup) {
502 DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) );
503 write_browse_list( 0, True );
504 dump_all_namelists();
505 reload_nmbd_services( True );
506 reopen_logs();
507 if(reload_interfaces(0))
508 return;
509 reload_after_sighup = 0;
512 /* check for new network interfaces */
513 if(reload_interfaces(t))
514 return;
516 /* free up temp memory */
517 lp_talloc_free();
519 } /* process */
521 /**************************************************************************** **
522 Open the socket communication.
523 **************************************************************************** */
525 static BOOL open_sockets(BOOL isdaemon, int port)
527 /* The sockets opened here will be used to receive broadcast
528 packets *only*. Interface specific sockets are opened in
529 make_subnet() in namedbsubnet.c. Thus we bind to the
530 address "0.0.0.0". The parameter 'socket address' is
531 now deprecated.
534 if ( isdaemon )
535 ClientNMB = open_socket_in(SOCK_DGRAM, port,0,0,True);
536 else
537 ClientNMB = 0;
539 ClientDGRAM = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3,0,True);
541 if ( ClientNMB == -1 )
542 return( False );
544 /* we are never interested in SIGPIPE */
545 BlockSignals(True,SIGPIPE);
547 set_socket_options( ClientNMB, "SO_BROADCAST" );
548 set_socket_options( ClientDGRAM, "SO_BROADCAST" );
550 DEBUG( 3, ( "open_sockets: Broadcast sockets opened.\n" ) );
551 return( True );
552 } /* open_sockets */
554 /**************************************************************************** **
555 Initialise connect, service and file structs.
556 **************************************************************************** */
558 static BOOL init_structs(void)
560 extern fstring local_machine;
561 char *p, *ptr;
562 int namecount;
563 int n;
564 int nodup;
565 pstring nbname;
567 if (! *global_myname)
569 fstrcpy( global_myname, myhostname() );
570 p = strchr( global_myname, '.' );
571 if (p)
572 *p = 0;
574 strupper( global_myname );
576 /* Add any NETBIOS name aliases. Ensure that the first entry
577 is equal to global_myname.
579 /* Work out the max number of netbios aliases that we have */
580 ptr = lp_netbios_aliases();
581 for( namecount=0; next_token(&ptr,nbname,NULL, sizeof(nbname)); namecount++ )
583 if ( *global_myname )
584 namecount++;
586 /* Allocate space for the netbios aliases */
587 my_netbios_names = (char **)malloc( sizeof(char *) * (namecount+1) );
588 if( NULL == my_netbios_names )
590 DEBUG( 0, ( "init_structs: malloc fail.\n" ) );
591 return( False );
594 /* Use the global_myname string first */
595 namecount=0;
596 if ( *global_myname )
597 my_netbios_names[namecount++] = global_myname;
599 ptr = lp_netbios_aliases();
600 while ( next_token( &ptr, nbname, NULL, sizeof(nbname) ) )
602 strupper( nbname );
603 /* Look for duplicates */
604 nodup=1;
605 for( n=0; n<namecount; n++ )
607 if( 0 == strcmp( nbname, my_netbios_names[n] ) )
608 nodup=0;
610 if (nodup)
611 my_netbios_names[namecount++] = strdup( nbname );
614 /* Check the strdups succeeded. */
615 for( n = 0; n < namecount; n++ )
616 if( NULL == my_netbios_names[n] )
618 DEBUG(0,("init_structs: malloc fail when allocating names.\n"));
619 return False;
622 /* Terminate name list */
623 my_netbios_names[namecount++] = NULL;
625 fstrcpy( local_machine, global_myname );
626 trim_string( local_machine, " ", " " );
627 p = strchr( local_machine, ' ' );
628 if (p)
629 *p = 0;
630 strlower( local_machine );
632 DEBUG( 5, ("Netbios name list:-\n") );
633 for( n=0; my_netbios_names[n]; n++ )
634 DEBUGADD( 5, ( "my_netbios_names[%d]=\"%s\"\n", n, my_netbios_names[n] ) );
636 return( True );
637 } /* init_structs */
639 /**************************************************************************** **
640 Usage on the program.
641 **************************************************************************** */
643 static void usage(char *pname)
646 printf( "Usage: %s [-DaiohV] [-H lmhosts file] [-d debuglevel] [-l log basename]\n", pname );
647 printf( " [-n name] [-p port] [-s configuration file]\n" );
648 printf( "\t-D Become a daemon (default)\n" );
649 printf( "\t-a Append to log file (default)\n" );
650 printf( "\t-i Run interactive (not a daemon)\n" );
651 printf( "\t-o Overwrite log file, don't append\n" );
652 printf( "\t-h Print usage\n" );
653 printf( "\t-V Print version\n" );
654 printf( "\t-H hosts file Load a netbios hosts file\n" );
655 printf( "\t-d debuglevel Set the debuglevel\n" );
656 printf( "\t-l log basename. Basename for log/debug files\n" );
657 printf( "\t-n netbiosname. Primary netbios name\n" );
658 printf( "\t-p port Listen on the specified port\n" );
659 printf( "\t-s configuration file Configuration file name\n" );
660 printf( "\n");
661 } /* usage */
664 /**************************************************************************** **
665 Main program.
666 **************************************************************************** */
668 int main(int argc,char *argv[])
670 int opt;
671 extern FILE *dbf;
672 extern char *optarg;
673 extern BOOL append_log;
674 extern BOOL AllowDebugChange;
675 BOOL opt_interactive = False;
676 pstring logfile;
678 append_log = True; /* Default, override with '-o' option. */
680 global_nmb_port = NMB_PORT;
681 *host_file = 0;
682 global_in_nmbd = True;
684 StartupTime = time(NULL);
686 sys_srandom(time(NULL) ^ sys_getpid());
688 TimeInit();
690 slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", LOGFILEBASE);
691 lp_set_logfile(logfile);
693 charset_initialise();
695 #ifdef LMHOSTSFILE
696 pstrcpy( host_file, LMHOSTSFILE );
697 #endif
699 /* this is for people who can't start the program correctly */
700 while (argc > 1 && (*argv[1] != '-'))
702 argv++;
703 argc--;
706 fault_setup((void (*)(void *))fault_continue );
708 /* POSIX demands that signals are inherited. If the invoking process has
709 * these signals masked, we will have problems, as we won't recieve them. */
710 BlockSignals(False, SIGHUP);
711 BlockSignals(False, SIGUSR1);
712 BlockSignals(False, SIGTERM);
714 CatchSignal( SIGHUP, SIGNAL_CAST sig_hup );
715 CatchSignal( SIGTERM, SIGNAL_CAST sig_term );
717 #if defined(SIGFPE)
718 /* we are never interested in SIGFPE */
719 BlockSignals(True,SIGFPE);
720 #endif
722 /* We no longer use USR2... */
723 #if defined(SIGUSR2)
724 BlockSignals(True, SIGUSR2);
725 #endif
727 while( EOF !=
728 (opt = getopt( argc, argv, "Vaos:T:I:C:bAB:N:Rn:l:d:Dip:hSH:G:f:" )) )
730 switch (opt)
732 case 's':
733 pstrcpy(servicesf,optarg);
734 break;
735 case 'N':
736 case 'B':
737 case 'I':
738 case 'C':
739 case 'G':
740 DEBUG(0,("Obsolete option '%c' used\n",opt));
741 break;
742 case 'H':
743 pstrcpy(host_file,optarg);
744 break;
745 case 'n':
746 pstrcpy(global_myname,optarg);
747 strupper(global_myname);
748 break;
749 case 'l':
750 slprintf(logfile, sizeof(logfile)-1, "%s/log.nmbd", optarg);
751 lp_set_logfile(logfile);
752 break;
753 case 'a':
754 append_log = True;
755 break;
756 case 'o':
757 append_log = False;
758 break;
759 case 'i':
760 opt_interactive = True;
761 break;
762 case 'D':
763 is_daemon = True;
764 break;
765 case 'd':
766 DEBUGLEVEL = atoi(optarg);
767 AllowDebugChange = False;
768 break;
769 case 'p':
770 global_nmb_port = atoi(optarg);
771 break;
772 case 'h':
773 usage(argv[0]);
774 exit(0);
775 break;
776 case 'V':
777 printf( "Version %s\n", VERSION );
778 exit(0);
779 break;
780 default:
781 if( !is_a_socket(0) )
783 DEBUG(0,("Incorrect program usage - is the command line correct?\n"));
784 usage(argv[0]);
785 exit(0);
787 break;
791 setup_logging( argv[0], opt_interactive );
792 reopen_logs();
794 DEBUG( 0, ( "Netbios nameserver version %s started.\n", VERSION ) );
795 DEBUGADD( 0, ( "Copyright Andrew Tridgell and the Samba Team 1994-2002\n" ) );
797 if ( !reload_nmbd_services(False) )
798 return(-1);
800 #ifdef WITH_PROFILE
801 if (!profile_setup(False)) {
802 DEBUG(0,("ERROR: failed to setup profiling shared memory\n"));
803 return -1;
805 #endif /* WITH_PROFILE */
807 codepage_initialise(lp_client_code_page());
809 if(!init_structs())
810 return -1;
812 reload_nmbd_services( True );
814 fstrcpy( global_myworkgroup, lp_workgroup() );
816 if (strequal(global_myworkgroup,"*"))
818 DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n"));
819 exit(1);
822 set_samba_nb_type();
824 if (!is_daemon && !is_a_socket(0))
826 DEBUG(0,("standard input is not a socket, assuming -D option\n"));
827 is_daemon = True;
830 if (is_daemon && !opt_interactive)
832 DEBUG( 2, ( "Becoming a daemon.\n" ) );
833 become_daemon();
836 #if HAVE_SETPGID
838 * If we're interactive we want to set our own process group for
839 * signal management.
841 if (opt_interactive)
842 setpgid( (pid_t)0, (pid_t)0 );
843 #endif
845 #ifndef SYNC_DNS
846 /* Setup the async dns. We do it here so it doesn't have all the other
847 stuff initialised and thus chewing memory and sockets */
848 if(lp_we_are_a_wins_server()) {
849 start_async_dns();
851 #endif
853 if (!directory_exist(lp_lockdir(), NULL)) {
854 mkdir(lp_lockdir(), 0755);
857 pidfile_create("nmbd");
858 message_init();
859 message_register(MSG_FORCE_ELECTION, nmbd_message_election);
861 DEBUG( 3, ( "Opening sockets %d\n", global_nmb_port ) );
863 if ( !open_sockets( is_daemon, global_nmb_port ) )
864 return 1;
866 /* Determine all the IP addresses we have. */
867 load_interfaces();
869 /* Create an nmbd subnet record for each of the above. */
870 if( False == create_subnets() )
872 DEBUG(0,("ERROR: Failed when creating subnet lists. Exiting.\n"));
873 exit(1);
876 /* Load in any static local names. */
877 if ( *host_file )
879 load_lmhosts_file(host_file);
880 DEBUG(3,("Loaded hosts file\n"));
883 /* If we are acting as a WINS server, initialise data structures. */
884 if( !initialise_wins() )
886 DEBUG( 0, ( "nmbd: Failed when initialising WINS server.\n" ) );
887 exit(1);
891 * Register nmbd primary workgroup and nmbd names on all
892 * the broadcast subnets, and on the WINS server (if specified).
893 * Also initiate the startup of our primary workgroup (start
894 * elections if we are setup as being able to be a local
895 * master browser.
898 if( False == register_my_workgroup_and_names() )
900 DEBUG(0,("ERROR: Failed when creating my my workgroup. Exiting.\n"));
901 exit(1);
904 /* We can only take signals in the select. */
905 BlockSignals( True, SIGTERM );
907 process();
909 if (dbf)
910 fclose(dbf);
911 return(0);
912 } /* main */