ramkomd.c 17.6 KB
Newer Older
Linus Tolke Y's avatar
Linus Tolke Y committed
1
/*
2
 * $Id: ramkomd.c,v 0.120 2003/07/31 23:02:47 ceder Exp $
Per Cederqvist's avatar
Per Cederqvist committed
3
 * Copyright (C) 1991-1999, 2001-2002  Lysator Academic Computer Association.
Linus Tolke Y's avatar
Linus Tolke Y committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This file is part of the LysKOM server.
 * 
 * LysKOM 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 1, or (at your option) 
 * any later version.
 * 
 * LysKOM 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 LysKOM; see the file COPYING.  If not, write to
 * Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
 * or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, 
 * MA 02139, USA.
 *
 * Please mail bug reports to bug-lyskom@lysator.liu.se. 
 */
25 26 27 28 29 30 31
/*
 * The next comment block is a historic comment, written in Swedish
 * using ISO 646 since nobody in Lysator knew about ISO 8859-1 by
 * then.  It translates, rougly, to "This is the main program of the
 * server.  It will hopefully be bigger than it is at the moment.
 * Created by Willfr 31-mar-1990."
 */
Per Cederqvist's avatar
Per Cederqvist committed
32 33 34 35 36 37 38 39 40
/*
 * Detta {r serverns huvudprogram. Det kommer f|rhoppningsvis bli st|rre
 * {n det {r just nu...
 *
 * Created by Willf|r 31/3-90
 *
 * It has grown! /ceder
 */

David Byers's avatar
David Byers committed
41 42 43 44 45

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

46 47 48
#ifdef HAVE_LOCALE_H
#  include <locale.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
49
#include <stdio.h>
Per Cederqvist's avatar
Per Cederqvist committed
50
#include <signal.h>
51 52 53 54 55 56
#ifdef HAVE_STDLIB_H
#  include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#  include <string.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
57
#include <sys/wait.h>
58
#include "timewrap.h"
59 60 61
#ifdef HAVE_SYS_RESOURCE_H
#  include <sys/resource.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
62
#include <unistd.h>
Per Cederqvist's avatar
Per Cederqvist committed
63 64 65 66
#include <setjmp.h>
#if defined(HAVE_SYS_PARAM_H) && !defined(HAVE_GETCWD)
# include <sys/param.h>
#endif
Per Cederqvist's avatar
Per Cederqvist committed
67
#include <errno.h>
Per Cederqvist's avatar
Per Cederqvist committed
68
#include <sys/types.h>
69
#include <sys/socket.h>
Per Cederqvist's avatar
Per Cederqvist committed
70
#include <fcntl.h>
Per Cederqvist's avatar
Per Cederqvist committed
71

72 73
#include "oop.h"

Per Cederqvist's avatar
Per Cederqvist committed
74
#include "exp.h"
75
#include "s-string.h"
Per Cederqvist's avatar
Per Cederqvist committed
76
#include "misc-types.h"
77
#include "kom-types.h"
Per Cederqvist's avatar
Per Cederqvist committed
78
#include "com.h"
79
#include "async.h"
Per Cederqvist's avatar
Per Cederqvist committed
80 81 82
#include "connections.h"
#include "internal-connections.h"
#include "kom-errno.h"
83
#include "oop-malloc.h"
Per Cederqvist's avatar
Per Cederqvist committed
84
#include "isc-malloc.h"
85
#include "isc-interface.h"
David Byers's avatar
David Byers committed
86
#include "kom-config.h"
Per Cederqvist's avatar
Per Cederqvist committed
87
#include "cache.h"
Per Cederqvist's avatar
Per Cederqvist committed
88 89
#include "string-malloc.h"
#include "lyskomd.h"
Per Cederqvist's avatar
Per Cederqvist committed
90
#include "log.h"
Per Cederqvist's avatar
Per Cederqvist committed
91 92
#include "server/smalloc.h"
#include "kom-memory.h"
93 94
#include "conf-file.h"
#include "param.h"
95 96
#include "server-config.h"
#include "manipulate.h"
97
#include "version-info.h"
98
#include "aux-items.h"
David Byers's avatar
David Byers committed
99
#include "admin.h"
100
#include "unused.h"
Per Cederqvist's avatar
Per Cederqvist committed
101
#include "sigflags.h"
Per Cederqvist's avatar
Per Cederqvist committed
102
#include "local-to-global.h"
103
#include "server-time.h"
104
#include "lockdb.h"
Per Cederqvist's avatar
Per Cederqvist committed
105
#include "linkansi.h"
106 107 108
#ifdef TRACED_ALLOCATIONS
#  include "trace-alloc.h"
#endif
109
#include "eintr.h"
110
#include "stats.h"
111

112 113 114 115
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
#  define RLIMIT_NOFILE RLIMIT_OFILE
#endif

116 117 118 119
#if !HAVE_RLIM_T
typedef int rlim_t;
#endif

120
struct timeval current_time = { 0, 0 };
121 122


Per Cederqvist's avatar
Per Cederqvist committed
123
#ifndef NDEBUG
124
int	buglevel = 0;
125
#endif
Per Cederqvist's avatar
Per Cederqvist committed
126

127 128 129 130 131
/* Don't place lyskomd in the background.  Write the log to stdout.
   Prompt for input on stdin before exiting.  This is primarily
   intended for debugging and the test suite. */
static int foreground = 0;

132 133
static oop_adapter_signal *kom_signal_adapter;

134
static void dump_exit_statistics(void);
David Byers's avatar
David Byers committed
135
static void free_kom_info(void);
136 137 138 139 140 141
static oop_call_signal sighandler_hup;
static oop_call_signal sighandler_quit;
static oop_call_signal sighandler_usr1;
static oop_call_signal sighandler_usr2;
static oop_call_signal sighandler_winch;

142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
#ifdef HAVE_STRUCT_SIGACTION

/* Assigning SIG_IGN to sa_handler results in

    ramkomd.c:310: warning: function declaration isn't a prototype

  on certain compilers.  By performing the assignment in a function
  the number of warnings are reduced. */

static inline void
set_handler_sig_ign(struct sigaction *ptr)
{
    ptr->sa_handler = SIG_IGN;
}

#endif

Per Cederqvist's avatar
Per Cederqvist committed
160
static void
Per Cederqvist's avatar
Per Cederqvist committed
161
server_init(const char *host, const char * client_port)
Per Cederqvist's avatar
Per Cederqvist committed
162
{
163 164 165
    struct isc_scb *listen_client;
    union isc_address *isc_adr = NULL;
    oop_source *src;
166 167 168 169
#ifdef HAVE_STRUCT_SIGACTION
    struct sigaction act;
#endif

170 171 172 173 174 175 176
    oop_malloc = &oop_malloc_wrapper;
    oop_realloc = &oop_realloc_wrapper;
    oop_free = &oop_free_wrapper;

    kom_server_oop_src = oop_sys_new();
    if (kom_server_oop_src == NULL)
	restart_kom("server_init: can't get system event source\n");
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

    kom_signal_adapter = oop_signal_new(oop_sys_source(kom_server_oop_src));
    if (kom_signal_adapter == NULL)
	restart_kom("server_init: can't create signal adapter\n");

    /* Ignore the signals before we register them with liboop.  That
       way, when liboop reinstalls the old signal handler during
       shutdown, we will ignore them rather than stop prematurely
       during the shutdown.  This is especially important for the
       SIGHUP signal, which is sent periodically by updateLysKOM. */
#ifdef HAVE_STRUCT_SIGACTION
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    set_handler_sig_ign(&act);
    sigaction(SIGHUP, &act, NULL);
    sigaction(SIGQUIT, &act, NULL);
    sigaction(SIGUSR1, &act, NULL);
    sigaction(SIGUSR2, &act, NULL);
    sigaction(SIGWINCH, &act, NULL);
#else
    signal(SIGHUP, SIG_IGN);
    signal(SIGQUIT, SIG_IGN);
    signal(SIGUSR1, SIG_IGN);
    signal(SIGUSR2, SIG_IGN);
    signal(SIGWINCH, SIG_IGN);
#endif

    src = oop_signal_source(kom_signal_adapter);
    oop_signal_use_sa_restart();
206 207 208 209 210 211
    src->on_signal(src, SIGHUP, sighandler_hup, NULL);
    src->on_signal(src, SIGQUIT, sighandler_quit, NULL);
    src->on_signal(src, SIGUSR1, sighandler_usr1, NULL);
    src->on_signal(src, SIGUSR2, sighandler_usr2, NULL);
    src->on_signal(src, SIGWINCH, sighandler_winch, NULL);

Per Cederqvist's avatar
Per Cederqvist committed
212 213 214
    /*
    ** Setup some parameters here
    */
215 216 217 218 219
    isc_setallocfn(&isc_malloc_wrapper,
		   &isc_realloc_wrapper,
		   &isc_free_wrapper);

    kom_server_mcb  = isc_initialize(oop_sys_source(kom_server_oop_src));
Per Cederqvist's avatar
Per Cederqvist committed
220
    if ( kom_server_mcb == NULL )
Per Cederqvist's avatar
Per Cederqvist committed
221
	restart_kom("server_init: can't isc_initialize()\n");
222
    isc_cfg_fd_relocate(kom_server_mcb, PROTECTED_FDS);
223
    isc_cfg_stale_timeout(kom_server_mcb, param.stale_timeout);
Per Cederqvist's avatar
Per Cederqvist committed
224

225 226
    listen_client = isc_listentcp(kom_server_mcb, host, client_port,
				  handle_accept_event);
Per Cederqvist's avatar
Per Cederqvist committed
227 228
    if (listen_client == NULL)
        restart_kom("server_init: can't isc_listentcp(CLIENT)\n");
Per Cederqvist's avatar
Per Cederqvist committed
229

230 231 232 233
    isc_adr = isc_getladdress (listen_client);
    if (isc_adr == NULL)
	restart_kom("server_init(): can't isc_getladdress (listen_client)\n");

David Byers's avatar
David Byers committed
234
    kom_log("Listening for clients on %d.\n", isc_getportnum(isc_adr));
235 236
    isc_freeaddress (isc_adr);
    
Per Cederqvist's avatar
Per Cederqvist committed
237 238 239 240 241 242

    /*
     * Ignore SIGPIPE, which the server gets if it tries to write to a
     * socket and the client has died. The server will anyhow handle
     * this situation correct.
     */
243 244 245
#ifdef HAVE_STRUCT_SIGACTION
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
246
    set_handler_sig_ign(&act);
247
    sigaction(SIGPIPE, &act, NULL);
248
#else
Per Cederqvist's avatar
Per Cederqvist committed
249
    signal(SIGPIPE, SIG_IGN);
250
#endif
Per Cederqvist's avatar
Per Cederqvist committed
251 252 253
}

static void
254
init_data_base(void)
Per Cederqvist's avatar
Per Cederqvist committed
255
{
David Byers's avatar
David Byers committed
256 257 258
    kom_log("Database = %s\n",  param.datafile_name);
    kom_log("Backup = %s\n", param.backupfile_name);
    kom_log("2nd Backup = %s\n", param.backupfile_name_2);
259
    kom_log("Lock File = %s\n", param.lockfile_name);
Per Cederqvist's avatar
Per Cederqvist committed
260 261
    
    if ( init_cache() == FAILURE )
262
	restart_kom ("Cannot find database.\n");
Per Cederqvist's avatar
Per Cederqvist committed
263 264
}

265 266 267 268
static void *
sighandler_hup(oop_source *UNUSED(source),
	       int UNUSED(sig),
	       void *UNUSED(user))
Per Cederqvist's avatar
Per Cederqvist committed
269
{
David Byers's avatar
David Byers committed
270
    kom_log ("Signal HUP received. Shutting down server.\n");
271
    go_and_die = TRUE;
272
    return OOP_HALT;
Per Cederqvist's avatar
Per Cederqvist committed
273 274
}

275 276 277 278
static void *
sighandler_quit(oop_source *UNUSED(source),
		int UNUSED(sig),
		void *UNUSED(user))
Per Cederqvist's avatar
Per Cederqvist committed
279
{
David Byers's avatar
David Byers committed
280
    kom_log ("Signal QUIT received - syncing...\n");
Per Cederqvist's avatar
Per Cederqvist committed
281
    cache_sync_all();
David Byers's avatar
David Byers committed
282
    kom_log ("Dumping core now.\n");
Per Cederqvist's avatar
Per Cederqvist committed
283 284 285
    abort();
}

286 287 288 289
static void *
sighandler_usr1(oop_source *UNUSED(source),
		int UNUSED(sig),
		void *UNUSED(user))
Per Cederqvist's avatar
Per Cederqvist committed
290
{
291 292
    dump_statistics();
    return OOP_CONTINUE;
Per Cederqvist's avatar
Per Cederqvist committed
293 294
}

295 296 297 298
static void *
sighandler_usr2(oop_source *UNUSED(source),
		int UNUSED(sig),
		void *UNUSED(user))
Per Cederqvist's avatar
Per Cederqvist committed
299 300 301
{
    int		  child;

David Byers's avatar
David Byers committed
302
    kom_log ("Signal USR2 received - will dump core now.  (Check that child dies.)\n");
Per Cederqvist's avatar
Per Cederqvist committed
303 304 305
    if ((child = fork()) == 0)
    {
	abort();
306
	kom_log ("Abort() failed!!!\n");
Per Cederqvist's avatar
Per Cederqvist committed
307 308 309 310
	exit(1);
    }
    else if (child < 0)
    {
David Byers's avatar
David Byers committed
311
	kom_log ("Couldn't fork.\n");
Per Cederqvist's avatar
Per Cederqvist committed
312 313 314 315 316
    }
    else
    {
	wait (NULL);
    }
317
    return OOP_CONTINUE;
Per Cederqvist's avatar
Per Cederqvist committed
318 319
}

320 321 322 323
static void *
sighandler_winch(oop_source *UNUSED(source),
		 int UNUSED(sig),
		 void *UNUSED(user))
324
{
325 326 327 328
    free_aux_item_definitions();
    initialize_aux_items(param.aux_def_file);
    kom_log("Signal WINCH received. aux definitions reloaded.\n");
    return OOP_CONTINUE;
329 330
}

Per Cederqvist's avatar
Per Cederqvist committed
331
static void
Per Cederqvist's avatar
Per Cederqvist committed
332 333 334 335
save_pid(void)
{
    FILE *fp;

336
    if ((fp = i_fopen(param.pid_name, "w")) == NULL)
Per Cederqvist's avatar
Per Cederqvist committed
337 338
	return;

339
    fprintf(fp, "%ld\n", (long)getpid());
340
    i_fclose(fp);
Per Cederqvist's avatar
Per Cederqvist committed
341 342
}

Per Cederqvist's avatar
Per Cederqvist committed
343
static void
344
go_daemon(void)
Per Cederqvist's avatar
Per Cederqvist committed
345 346 347
{
    pid_t child;
    int fd;
348 349 350 351
#ifdef HAVE_STRUCT_SIGACTION
    struct sigaction act;
#endif
    
352
    if (foreground != 0)
353 354 355 356
    {
	return;
    }

Per Cederqvist's avatar
Per Cederqvist committed
357 358 359 360 361
    if (getppid() != 1)
    {
	/* We were not invoked from /etc/inittab, so
	   disassociate from controlling terminal. */

362 363 364
#ifdef HAVE_STRUCT_SIGACTION
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
365
	set_handler_sig_ign(&act);
366 367 368 369 370 371 372 373 374 375 376 377 378 379

#  ifdef SIGTTOU
	sigaction(SIGTTOU, &act, NULL);
#  endif
#  ifdef SIGTTIN
	sigaction(SIGTTIN, &act, NULL);
#  endif
#  ifdef SIGTSTP
	sigaction(SIGTSTP, &act, NULL);
#  endif

#else  /* !HAVE_STRUCT_SIGACTION */

#  ifdef SIGTTOU
Per Cederqvist's avatar
Per Cederqvist committed
380
	signal(SIGTTOU, SIG_IGN);
381 382
#  endif
#  ifdef SIGTTIN
Per Cederqvist's avatar
Per Cederqvist committed
383
	signal(SIGTTIN, SIG_IGN);
384 385
#  endif
#  ifdef SIGTSTP
Per Cederqvist's avatar
Per Cederqvist committed
386
	signal(SIGTSTP, SIG_IGN);
387 388
#  endif

Per Cederqvist's avatar
Per Cederqvist committed
389 390 391 392 393 394 395 396 397 398 399 400
#endif

	child = fork();
	if (child < 0)
	    restart_kom("fork failed: %d\n", errno);
	else if (child > 0)
	    exit (0);		/* parent */
	
	setsid();
    }

    /* Close all file descriptors */
401
    for (fd = 0; fd < fd_ceiling; fd++)
Per Cederqvist's avatar
Per Cederqvist committed
402 403 404
	close(fd);
    if (open("/dev/null", O_RDONLY) != 0
	||open("/dev/null", O_WRONLY) != 1
405
	||open(param.logfile_name, O_WRONLY|O_CREAT|O_APPEND, 0644) != 2)
Per Cederqvist's avatar
Per Cederqvist committed
406 407 408
    {
	/* Kinda stupid to try to log an error message now, but
	   who knows? */
409
	restart_kom("open of log file failed: %d\n", errno);
Per Cederqvist's avatar
Per Cederqvist committed
410
    }
David Byers's avatar
David Byers committed
411 412
    kom_log("*** Version %s (process %lu) coming up.\n",
            kom_version_info.server_version, (unsigned long)getpid());
Per Cederqvist's avatar
Per Cederqvist committed
413 414
}

415
static void
416
initialize(const char *config_file)
417
{
418
#ifdef USING_RLIMIT_NOFILE
419 420 421
    struct rlimit rlim;
#endif

422
    read_configuration(config_file);
423
    initialize_aux_items(param.aux_def_file);
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439

#ifdef HAVE_LOCALE_H
    if (param.use_locale != NULL)
	if (setlocale(LC_CTYPE, param.use_locale) == NULL)
	{
	    fprintf(stderr, "setlocale: ");
	    perror(param.use_locale);
	    exit(1);
	}
#else
    if (param.use_locale != NULL)
    {
	fprintf(stderr, "locale not supported in your environment.\n");
	exit(1);
    }
#endif
440

441 442 443 444 445 446 447 448
    if (param.no_files != -1 && param.no_files > FD_SETSIZE)
    {
	fprintf(stderr,
		"The \"Open files: %ld\" is too large: FD_SETSIZE is %ld\n",
		(long)param.no_files, (long)FD_SETSIZE);
	exit(1);
    }

449
#ifdef USING_RLIMIT_NOFILE
450 451 452 453 454 455
    if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
    {
	perror("getrlimit(RLIMIT_NOFILE) failed");
	exit(1);
    }

Per Cederqvist's avatar
Per Cederqvist committed
456
    if (param.no_files != -1)
457
    {
458
	if ((rlim_t)param.no_files > rlim.rlim_max)
459
	{
460 461 462 463
	    fprintf(stderr, "attempt to raise open files from %ld to %ld, "
		    "but only %ld is allowed\n",
		    (long)rlim.rlim_cur, (long)param.no_files,
		    (long)rlim.rlim_max);
464 465 466 467 468 469 470 471 472 473
	    rlim.rlim_cur = rlim.rlim_max;
	}
	else
	    rlim.rlim_cur = param.no_files;
	
	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
	{
	    perror("setrlimit failed");
	    exit(1);
	}
474 475 476 477 478 479 480 481
	if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
	{
	    perror("getrlimit(RLIMIT_NOFILE) failed");
	    exit(1);
	}
	if (rlim.rlim_cur != (rlim_t)param.no_files)
	    restart_kom("getrlimit after setrlimit returns %ld, not %ld.\n",
			(long)rlim.rlim_cur, (long)param.no_files);
482
    }
483 484 485 486 487
    fd_ceiling = rlim.rlim_cur;
#elif HAVE_GETDTABLESIZE
    if (param.no_files == -1)
	fd_ceiling = getdtablesize();
    else if (param.no_files >= getdtablesize())
488
    {
489 490
	fprintf(stderr, "getdtablesize() indicates that at most %ld files"
		" can be used.\n", (long)getdtablesize());
491 492
	exit(1);
    }
493 494 495 496 497 498 499 500 501 502 503 504 505
    else
	fd_ceiling = param.no_files;
#elif defined(OPEN_MAX)
    if (param.no_files == -1)
	fd_ceiling = OPEN_MAX;
    else if (param.no_files >= OPEN_MAX)
    {
	fprintf(stderr, "OPEN_MAX indicates that at most %ld files"
		" can be used.\n", (long)OPEN_MAX);
	exit(1);
    }
    else
	fd_ceiling = param.no_files;
506
#else
507
#  error Do not know how to find maximum number of open files.
508 509
#endif

510 511 512
    if (fd_ceiling > FD_SETSIZE)
	fd_ceiling = FD_SETSIZE;

513
    go_daemon();
514
    if (lock_db() < 0)
515 516 517 518 519
    {
	/* Don't actually die until something is entered on stdin in debug
	   mode.  This is mainly here for the benefit of the test suite,
	   but is could also be useful to be able to attach a debugger and
	   do pre-mortem debugging of the process at this point.  */
520
	kom_log("Cannot obtain database lock.  Exiting.\n");
521
	if (foreground)
522 523 524 525 526
	{
	    kom_log("Press enter to terminate lyskomd\n");
	    getchar();
	}

527
	exit(1);
528 529
    }

Per Cederqvist's avatar
Per Cederqvist committed
530
    server_init(param.ip_client_host, param.ip_client_port);
531
    init_data_base();
532 533
}

Per Cederqvist's avatar
Per Cederqvist committed
534 535 536
/* Stop complaint from gcc 2.0 about "no previous prototype for `main'". */
int main(int argc, char **argv);

537
	
Per Cederqvist's avatar
Per Cederqvist committed
538 539 540 541 542
int
main (int    argc,
      char **argv)
{
    int i;
543 544
    char *default_config_file;
    char *config_file;
545
    oop_source *src;
Per Cederqvist's avatar
Per Cederqvist committed
546 547 548

    link_ansi();

549 550
    if (gettimeofday(&current_time, NULL) < 0)
	restart_kom("gettimeofday failed: %s\n", strerror(errno));
Per Cederqvist's avatar
Per Cederqvist committed
551

552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
#ifdef TRACED_ALLOCATIONS
    /* We must do this before we allocate any memory... */
    {
      char buf[1024];
      char *nl;

      fputs("Where does the trace want to go today? [stderr]\n", stdout);
      fflush(stdout);
      if (fgets(buf, sizeof(buf), stdin) != buf)
	  restart_kom("main(): unable to read trace location\n");
      if ((nl = strchr(buf, '\n')) != NULL)
	  *nl = '\0';
      trace_alloc_file(buf);
    }
#endif

David Byers's avatar
David Byers committed
568
    kom_log("*** Version %s (process %lu) started.\n",
569
	kom_version_info.server_version, (unsigned long)getpid());
570
#ifdef DEBUG_CALLS
David Byers's avatar
David Byers committed
571 572
    kom_log("WARNING: This server was compiled with --with-debug-calls.\n");
    kom_log("It isn't safe to use in a production environment.\n");
573
#endif
574

Per Cederqvist's avatar
Per Cederqvist committed
575
#ifdef ENCRYPT_PASSWORDS
576
    /* Seed the random number generator. */
577
    /* FIXME (bug 1068): This is not a good way to seed it... */
Per Cederqvist's avatar
Per Cederqvist committed
578 579
    srand(time(NULL) + getpid());
#endif
Per Cederqvist's avatar
Per Cederqvist committed
580

581 582
    /* Initialize the string handling package. */
    s_set_storage_management(string_malloc, string_realloc, string_free);
583

584
    /* Parse command line arguments. */
Per Cederqvist's avatar
Per Cederqvist committed
585 586 587 588 589 590 591
    for (i = 1; i < argc && argv[i][0] == '-'; i++)
	switch (argv[i][1])
	{
	case 'd':
	    buglevel++;
	    break;

592 593 594 595
	case 'f':
	    foreground = 1;
	    break;

596
	default:
597
	    restart_kom("usage: %s [-f] [-d ...] [config-file]\n", argv[0]);
598
	}
Per Cederqvist's avatar
Per Cederqvist committed
599

600

601
    /* Read in the configuration file. */
602

603 604 605
    default_config_file = smalloc(strlen(DEFAULT_DBASE_DIR) +
				  strlen(CONFIG_FILE) + 2);
    sprintf(default_config_file, "%s/%s", DEFAULT_DBASE_DIR, CONFIG_FILE);
Per Cederqvist's avatar
Per Cederqvist committed
606
    if (i < argc)
607 608 609
	config_file = argv[i++];
    else
	config_file = default_config_file;
Per Cederqvist's avatar
Per Cederqvist committed
610

611 612
    if (i < argc)
	    restart_kom("usage: %s [-d ...] [config-file]\n", argv[0]);
613

614
    init_stats();
615
    initialize(config_file);	/* Read config, listen, and start db */
616
    chdir(param.core_dir);
617 618 619

    read_config_file = smalloc(strlen(config_file) + 1);
    strcpy(read_config_file, config_file);
620 621
    sfree(default_config_file);

Per Cederqvist's avatar
Per Cederqvist committed
622
    save_pid();
623
    check_all_stats("init");
Per Cederqvist's avatar
Per Cederqvist committed
624

Per Cederqvist's avatar
Per Cederqvist committed
625
    toploop();
Per Cederqvist's avatar
Per Cederqvist committed
626

627 628 629
    /* There is no use sending logout messages to all sessions. */
    param.send_async_messages = FALSE;
    
Per Cederqvist's avatar
Per Cederqvist committed
630
    logout_all_clients();
631
    isc_shutdown(kom_server_mcb);
Per Cederqvist's avatar
Per Cederqvist committed
632
    cache_sync_all();
633
    unlock_db();
634
    src = oop_signal_source(kom_signal_adapter);
635 636 637 638 639
    src->cancel_signal(src, SIGWINCH, sighandler_winch, NULL);
    src->cancel_signal(src, SIGUSR2, sighandler_usr2, NULL);
    src->cancel_signal(src, SIGUSR1, sighandler_usr1, NULL);
    src->cancel_signal(src, SIGQUIT, sighandler_quit, NULL);
    src->cancel_signal(src, SIGHUP, sighandler_hup, NULL);
640
    oop_signal_delete(kom_signal_adapter);
641
    oop_sys_delete(kom_server_oop_src);
Per Cederqvist's avatar
Per Cederqvist committed
642

David Byers's avatar
David Byers committed
643 644
    /* Finish */

645
    dump_exit_statistics();
646
    check_all_stats("shutdown");
647

David Byers's avatar
David Byers committed
648
    kom_log("%s terminated normally.\n", argv[0]);
649 650 651 652 653

    /* Don't actually die until something is entered on stdin in debug
       mode.  This is mainly here for the benefit of the test suite,
       but is could also be useful to be able to attach a debugger and
       do pre-mortem debugging of the process at this point.  */
654
    if (foreground)
655
    {
David Byers's avatar
David Byers committed
656
	kom_log("Press enter to terminate lyskomd\n");
657 658
	getchar();
    }
David Byers's avatar
David Byers committed
659

660
    exit(0);
661 662 663 664 665 666 667 668
}

static void 
dump_exit_statistics(void)
{
    FILE *stat_file;
    time_t now;

669 670
    time(&now);
    stat_file = i_fopen(param.memuse_name, "a");
Per Cederqvist's avatar
Per Cederqvist committed
671 672 673 674

    if ( stat_file == NULL )
	restart_kom("Can't open file to save memory usage to.\n");

675 676
    fprintf(stat_file, "\nLysKOM Server going down at %s\n", ctime(&now));

677 678 679 680
    dump_cache_stats (stat_file);

    free_all_tmp();
    free_all_cache();
681
    free_all_jubel();
David Byers's avatar
David Byers committed
682 683 684
    free_kom_info();
    free_aux_item_definitions();
    free_configuration();
685
    sfree(read_config_file);
686

Per Cederqvist's avatar
Per Cederqvist committed
687 688
    dump_smalloc_counts(stat_file);
    dump_alloc_counts(stat_file);
689
    dump_cache_mem_usage(stat_file);
Per Cederqvist's avatar
Per Cederqvist committed
690
    dump_string_alloc_counts(stat_file);
691
    dump_allocated_connections(stat_file);
692
    dump_isc_alloc_counts(stat_file);
693
    dump_oop_alloc_counts(stat_file);
694
    dump_l2g_stats(stat_file);
695
    i_fclose (stat_file);
Per Cederqvist's avatar
Per Cederqvist committed
696
}
David Byers's avatar
David Byers committed
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713

static void
free_kom_info(void)
{
    unsigned long i;

    if (kom_info.aux_item_list.items != NULL)
    {
        for (i = 0; i < kom_info.aux_item_list.length; i++)
        {
            s_clear(&kom_info.aux_item_list.items[i].data);
        }
        sfree(kom_info.aux_item_list.items);
    }
    kom_info.aux_item_list.length = 0;
    kom_info.aux_item_list.items = 0;
}