/*
 *	Simple inetd replacement for one server only.
 *
 *	Usage: startup -s <service> -p <protocol> -w <wait> -f <prog>
 *
 *		<service>  -- name of the server program, for
 *				example `tftp'
 *
 *		<protocol> -- protocol to use, eg `udp'.
 *
 *		<wait>     -- possible values:
 *				`yes' -- wait until child exits before
 *				listening for new requests.
 *				`no'  -- don't wait ...
 *
 *		<prog>     -- server program
 *
 *	(w) 1994, Kay Roemer.
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>

long _stksize = 10000;

static int dowait = 1;
static char *proto = 0, *serv = 0, *prog = 0;

void
usage (void)
{
	printf ("startup -s <service> -p <protocol> -f <program> -w yes|no\n");
}
 
int
main(argc, argv)
	int argc;
	char *argv[];
{
	struct servent *sent;
	struct sockaddr_in sin;
	int r, s, c;
	extern char *optarg;

	while ((c = getopt (argc, argv, "s:p:w:f:")) != EOF) {
		switch (c) {
		case 's':
			serv = optarg;
			break;
			
		case 'p':
			proto = optarg;
			break;
			
		case 'w':
			dowait = (stricmp (optarg, "yes") ? 0 : 1);
			break;

		case 'f':
			prog = optarg;
			break;
			
		case '?':
		default:
			usage ();
			exit (0);			
		}
	}
	if (!serv || !proto || !prog) {
		usage ();
		exit (0);
	}
	sent = getservbyname (serv, proto);
	if (!sent) {
		printf ("service %s/%s not found.\n", serv, proto);
		exit (0);
	}
	if (!stricmp ("udp", proto)) {
		c = SOCK_DGRAM;
	} else if (!stricmp ("tcp", proto)) {
		c = SOCK_STREAM;
	} else {
		printf ("protocol %s not supported\n", proto);
		exit (0);
	}

	s = socket (PF_INET, c, 0);
	if (s < 0) {
		perror ("socket");
		exit (0);
	}
	
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = sent->s_port;

	r = bind (s, (struct sockaddr *)&sin, sizeof (sin));
	if (r < 0) {
		perror ("bind");
		exit (0);
	}

	while (1) {
		fd_set rset;

		FD_ZERO (&rset);
		FD_SET (s, &rset);
		
		r = select (FD_SETSIZE, &rset, 0, 0, 0);
		if (r <= 0) continue;

		if (!fork ()) {
			dup2 (s, 0);
			execlp (prog, prog, 0);
			printf ("exec failed");
			exit (0);
		} else if (dowait) {
			int stat;
			waitpid (-1, &stat, 0);
		}
	}
	return 0;
}
