/*
 *
 * transit.c 
 *
 * Main routines
 *
 * Author: Landon Fuller <landonf@go2net.com>
 *
 * Copyright (c) 2000-2001 InfoSpace, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *         This product includes software developed by InfoSpace, Inc.
 *         and its contributors.
 * 4. Neither the name of InfoSpace, Inc nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "../autoconf.h"

#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <lber.h>
#include <ldap.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include "yp.h"
#ifdef HAVE_RPC_SVC_SOC_H
#include <rpc/svc_soc.h>
#endif
#include <rpc/pmap_clnt.h>
#include <rpcsvc/ypclnt.h>

#include "../lib/getopt.h"

#include "../include/config.h"
#include "../include/servconf.h"
#include "../include/transit.h"
#include "../include/modules.h"
#include "../include/log.h"

extern void ypprog_1 (struct svc_req *, register SVCXPRT *);
extern void ypprog_2 (struct svc_req *, register SVCXPRT *);
extern int children;

static void print_version (void)
{
	printf ("%s (%s) Copyright (C) %s InfoSpace, Inc\n",
			PROGNAME, VERSION, COPYDATE);
	printf ("Written by %s\n", AUTHOR);
}

static void print_usage (FILE *stream)
{
	fprintf (stream, "Usage: %s [-d domain] [--debug] [--version] [-f config file]\n",
			PROGNAME);
}

static void print_help (void)
{
	print_usage (stdout);
	printf ("%s - NIS to LDAP gateway daemon\n",
			PROGNAME);
	printf ("  -f config file	Server config file\n");
	printf ("  -d domain		NIS domain name\n");
	printf ("  --debug		Do not fork\n");
	printf ("  --help		Display this help list\n");
	printf ("  --version		Display program version\n");
}

static void print_error (void)
{
	print_usage (stderr);
	fprintf (stderr, "Try `%s --help' or `%s --usage'\n",
			PROGNAME, PROGNAME);
}

static void unregister (void)
{
#ifdef NISV1
	(void) pmap_unset (YPPROG, YPOLDVERS);
#endif
	(void) pmap_unset (YPPROG, YPVERS);
}

void fatal_cleanup (void)
{
	unregister();
	exit(1);
}

static void reaper(int signal)
{
	int status;
	if (signal == SIGCHLD)
	{
		while (wait4(-1, &status, WNOHANG, NULL) > 0)
			children--;
	} else {
		fatal_cleanup();
	}
	return;
}

int main (int argc, char **argv)
{
	int j;
	register SVCXPRT *transp = NULL;
	/* misc pref inits */
	prefs.dflag = 0;
	prefs.configfile = TRANSIT_CONFIG_FILE;
	while(1)
	{
		int c;
		int option_index = 0;
		static struct option long_options[] =
		{
			{"debug", 0, NULL, '\255'},
			{"usage", 0, NULL, '\254'},
			{"help", 0, NULL, '\253'},
			{"version", 0, NULL, '\252'},
			{NULL, 0, NULL, '\0'}
		};

		c = getopt_long (argc, argv, "f:", long_options, &option_index);
		if (c == (-1))
			break;
		switch (c)
		{
			case 'f':
				prefs.configfile = optarg;
				break;
			case '\255':
				prefs.dflag = 1;
				break;
			case '\254':
				print_usage (stdout);
				return 0;
			case '\253':
				print_help ();
				return 0;
			case '\252':
				print_version ();
				return 0;
			default:
				print_error ();
				fatal_cleanup();
		}
	}
	if (optind < argc)
	{
		print_usage (stderr);
		fatal_cleanup();
	}

	/* init the config structure. */
	init_server_config();

	/* read in server configuration file, and set prefs.structure options */
	read_server_config (prefs.configfile);

	/* fill unset values with defaults, and fatal() on unset required values */
	fill_server_config ();

	modules_init(prefs.yp_modulelist);

	/* this block of code forks the daemon, closes all fds
	 * and redirects stdin, stdout and stderr to /dev/null */
	if (prefs.dflag != 1)
	{
		/* since we're forking, switch to syslog */
		prefs.perr = 0;

		if ((j = fork()) > 0)
			exit (0);

		if (j < 0)
		{
			log (LOG_ERR, "Fork failed: %s\n", strerror (errno));
			exit (-1);
		}

		if (setsid() == -1)
		{
			log (LOG_ERR, "Setsid failed: %s\n", strerror (errno));
			exit (-1);
		}

		if ((j = fork()) > 0)
			exit (0);

		if (j < 0)
		{
			log (LOG_ERR, "Fork failed: %s\n", strerror (errno));
			exit (-1);
		}

		for (j = 0; j < getdtablesize(); ++j)
			close (j);
		errno = 0;
		chdir("/");
		umask(022);
	
		j = open ("/dev/null", O_RDWR);
		dup (j);
		dup (j);
	}
	/* end of forking */

	/* RPC code */

#ifdef NISV1
	(void) pmap_unset (YPPROG, YPOLDVERS);
#endif
	(void) pmap_unset(YPPROG, YPVERS);

	transp = svcudp_create(RPC_ANYSOCK);
	if (transp == NULL) {
		fatal("cannot create udp service.\n");
	}
#ifdef NISV1
	if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, IPPROTO_UDP)) {
		fatal("unable to register (YPPROG, YPOLDVERS, udp).\n");
	}
#endif
	if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, IPPROTO_UDP)) {
		fatal("unable to register (YPPROG, YPVERS, udp).\n");
	}
	
	transp = svctcp_create(RPC_ANYSOCK, 0, 0);
	if (transp == NULL) {
		fatal("cannot create tcp service.\n");
	}
#ifdef NISV1
	if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, IPPROTO_TCP)) {
		fatal("unable to register (YPPROG, YPOLDVERS, tcp).\n");
	}
#endif
	if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, IPPROTO_TCP)) {
		fatal("unable to register (YPPROG, YPVERS, tcp).\n");
	}
	/*
	 * Make sure we survive a SIGPIPE
	 */
	(void) signal(SIGPIPE, SIG_IGN);
	(void) signal(SIGTERM, (void *) fatal_cleanup);
	(void) signal(SIGINT, (void *) fatal_cleanup);
	(void) signal(SIGCHLD, reaper);
	(void) signal(SIGHUP, SIG_IGN);
	svc_run();
	fprintf(stderr, "svc_run returned");
	exit(1);
	/* NOTREACHED */
}


syntax highlighted by Code2HTML, v. 0.9.1