<commit_before>#define _GNU_SOURCE

#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <getopt.h>

#include <libncc/pidfile.h>

#include "client.h"
#include "proto.h"
#include "commondb/random.h"
#include "player.h"
#include "sleep.h"
#include "opt.h"

char *progname = NULL;
int check_child = 0;
int terminate = 0;

static void sig_child( int sig )
{
	check_child++;
	signal( sig, sig_child );
}

static void sig_term( int sig )
{
	terminate++;
	signal( sig, sig_child );
}

static void earliest( time_t *a, time_t b )
{
	if( b && b > *a )
		*a = b;
}

static void loop( void )
{
	fd_set fdread;
	int maxfd;
	time_t wakeup;
	struct timeval tv, *tvp;
	t_client *client;

	while( !terminate ){
		/* handle flag set by SIGCHLD handler */
		if( check_child ){
			player_check();
			check_child = 0;
		}

		/* initialize fdsets for select */
		FD_ZERO( &fdread );
		maxfd = 0;
		clients_fdset( &maxfd, &fdread );
		maxfd++;

		/* set timeout for select */
		tvp = NULL;
		wakeup = 0;
		earliest( &wakeup, player_wakeuptime() );
		earliest( &wakeup, sleep_get() );
		// TODO: check other scheduled events


		if( wakeup ){
			check_child++;

			wakeup -= time(NULL);
			if( wakeup < 0 )
				wakeup = 0;
			tv.tv_sec = wakeup;
			tv.tv_usec = 0;
			tvp = &tv;
		}

		if( 0 > select( maxfd, &fdread, NULL, NULL, tvp )){
			if( errno != EINTR ){
				syslog( LOG_CRIT, "select failed: %m" );
				exit( 1 );
			}

			/* 
			 * we got a signal - maybe sigchild. 
			 * as fdsets are invalid anyways, we restart again
			 */
			continue;
		}

		for( client = clients; client; client = client->next ){
			if( client->close )
				continue;

			client_poll( client, &fdread );
			proto_input( client );
		}

		sleep_check();

		// TODO: do other things

		clients_clean();
		client_accept( &fdread );
	}
}

// TODO: config file
// TODO: sighup handler - reread config

static void usage( void );

int main( int argc, char **argv )
{
	pid_t pid;
	char *pidfile = "/var/run/dudld/dudld.pid";
	int foreground = 0;
	int debug = 0;
	int port = 4445;
	int c;
	int needhelp = 0;
	struct option lopts[] = {
		{ "help", no_argument, NULL, 'h' },
		{ "foreground", no_argument, NULL, 'f' },
		{ "debug", no_argument, NULL, 'd' },
		{ "port", required_argument, NULL, 'p' },
	};

	progname = strrchr( argv[0], '/' );
	if( NULL != progname ){
		progname++;
	} else {
		progname = argv[0];
	}
	pid = getpid();

	while( -1 != ( c = getopt_long( argc, argv, "hfdp:",
					lopts, NULL ))){

		switch(c){
		  case 'h':
			  usage();
			  exit(0);
			  break;

		  case 'f':
			  foreground++;
			  break;

		  case 'd':
			  debug++;
			  break;

		  case 'p':
			  port = atoi(optarg);
			  break;

		  default:
			  needhelp++;
			  break;
		}
	}
	if( needhelp ){
		fprintf( stderr, "use --help for usage information\n" );
		exit( 1 );
	}

	openlog( progname, LOG_PID | LOG_PERROR, LOG_DAEMON );
	if( ! debug )
		setlogmask( LOG_UPTO(LOG_INFO) );


	if( pidfile_flock(pidfile)){
		syslog( LOG_ERR, "cannot create pidfile: %m");
		exit(1);
	}

	// TODO: use sigaction
	signal( SIGTERM, sig_term );
	signal( SIGINT, sig_term );
	signal( SIGCHLD, sig_child );
	signal( SIGPIPE, SIG_IGN );

	if( clients_init( port ) ){
		syslog( LOG_ERR, "clients_init(): %m" );
		return 1;
	}

	if( !foreground && daemon(0,0) == -1 ){
		syslog( LOG_ERR, "cannot daemonize: %m" );
		exit( 1 );
	}
	/* our pid changed - update pidfile */
	if( pidfile_ftake(pidfile, pid) ){
		syslog( LOG_ERR, "cannot update pidfile: %m" );
		exit(1);
	}

	syslog(LOG_INFO, "initializing" );

	db_init();
	random_init();
	//player_init();
	player_setgap( opt_gap );
	player_setrandom( opt_random );
	proto_init();
	
	{
		expr *e = NULL;
		char *msg;
		int pos;

		if( opt_filter && *opt_filter ){
			e = expr_parse_str( &pos, &msg, opt_filter );
			if( e == NULL ){
				syslog( LOG_ERR, "startup filter "
						"failed at %d: %s",
						pos, msg );
			}
		}

		/* at least initialize with an empty filter */
		random_setfilter( e );
	}


	syslog(LOG_INFO, "waiting" );
	loop();

	syslog(LOG_INFO, "terminating" );
	player_stop();
	clients_done();
	db_done();
	pidfile_funlock(pidfile);
	return 0;
}

static void usage( void )
{
	printf( "usage: %s [opt]\n", progname );
	printf(
		" -h --help          show this message\n"
		" -f --foreground    do not detach\n"
		" -d --debug         be more verbose\n"
		" -p --port <port>   set port to listen on\n"
	      );
}
<commit_msg>new pidfile option for testing<commit_after>#define _GNU_SOURCE

#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <getopt.h>

#include <libncc/pidfile.h>

#include "client.h"
#include "proto.h"
#include "commondb/random.h"
#include "player.h"
#include "sleep.h"
#include "opt.h"

char *progname = NULL;
int check_child = 0;
int terminate = 0;

static void sig_child( int sig )
{
	check_child++;
	signal( sig, sig_child );
}

static void sig_term( int sig )
{
	terminate++;
	signal( sig, sig_child );
}

static void earliest( time_t *a, time_t b )
{
	if( b && b > *a )
		*a = b;
}

static void loop( void )
{
	fd_set fdread;
	int maxfd;
	time_t wakeup;
	struct timeval tv, *tvp;
	t_client *client;

	while( !terminate ){
		/* handle flag set by SIGCHLD handler */
		if( check_child ){
			player_check();
			check_child = 0;
		}

		/* initialize fdsets for select */
		FD_ZERO( &fdread );
		maxfd = 0;
		clients_fdset( &maxfd, &fdread );
		maxfd++;

		/* set timeout for select */
		tvp = NULL;
		wakeup = 0;
		earliest( &wakeup, player_wakeuptime() );
		earliest( &wakeup, sleep_get() );
		// TODO: check other scheduled events


		if( wakeup ){
			check_child++;

			wakeup -= time(NULL);
			if( wakeup < 0 )
				wakeup = 0;
			tv.tv_sec = wakeup;
			tv.tv_usec = 0;
			tvp = &tv;
		}

		if( 0 > select( maxfd, &fdread, NULL, NULL, tvp )){
			if( errno != EINTR ){
				syslog( LOG_CRIT, "select failed: %m" );
				exit( 1 );
			}

			/* 
			 * we got a signal - maybe sigchild. 
			 * as fdsets are invalid anyways, we restart again
			 */
			continue;
		}

		for( client = clients; client; client = client->next ){
			if( client->close )
				continue;

			client_poll( client, &fdread );
			proto_input( client );
		}

		sleep_check();

		// TODO: do other things

		clients_clean();
		client_accept( &fdread );
	}
}

// TODO: config file
// TODO: sighup handler - reread config

static void usage( void );

int main( int argc, char **argv )
{
	pid_t pid;
	char *pidfile = "/var/run/dudld/dudld.pid";
	int foreground = 0;
	int debug = 0;
	int port = 4445;
	int c;
	int needhelp = 0;
	struct option lopts[] = {
		{ "help", no_argument, NULL, 'h' },
		{ "foreground", no_argument, NULL, 'f' },
		{ "debug", no_argument, NULL, 'd' },
		{ "port", required_argument, NULL, 'p' },
		{ "pidfile", required_argument, NULL, 'i' },
	};

	progname = strrchr( argv[0], '/' );
	if( NULL != progname ){
		progname++;
	} else {
		progname = argv[0];
	}
	pid = getpid();

	while( -1 != ( c = getopt_long( argc, argv, "hfdp:i:",
					lopts, NULL ))){

		switch(c){
		  case 'h':
			  usage();
			  exit(0);
			  break;

		  case 'f':
			  foreground++;
			  break;

		  case 'd':
			  debug++;
			  break;

		  case 'p':
			  port = atoi(optarg);
			  break;

		  case 'i':
			  pidfile = optarg;
			  break;

		  default:
			  needhelp++;
			  break;
		}
	}
	if( needhelp ){
		fprintf( stderr, "use --help for usage information\n" );
		exit( 1 );
	}

	openlog( progname, LOG_PID | LOG_PERROR, LOG_DAEMON );
	if( ! debug )
		setlogmask( LOG_UPTO(LOG_INFO) );


	if( pidfile_flock(pidfile)){
		syslog( LOG_ERR, "cannot create pidfile: %m");
		exit(1);
	}

	// TODO: use sigaction
	signal( SIGTERM, sig_term );
	signal( SIGINT, sig_term );
	signal( SIGCHLD, sig_child );
	signal( SIGPIPE, SIG_IGN );

	if( clients_init( port ) ){
		syslog( LOG_ERR, "clients_init(): %m" );
		return 1;
	}

	if( !foreground && daemon(0,0) == -1 ){
		syslog( LOG_ERR, "cannot daemonize: %m" );
		exit( 1 );
	}
	/* our pid changed - update pidfile */
	if( pidfile_ftake(pidfile, pid) ){
		syslog( LOG_ERR, "cannot update pidfile: %m" );
		exit(1);
	}

	syslog(LOG_INFO, "initializing" );

	db_init();
	random_init();
	//player_init();
	player_setgap( opt_gap );
	player_setrandom( opt_random );
	proto_init();
	
	{
		expr *e = NULL;
		char *msg;
		int pos;

		if( opt_filter && *opt_filter ){
			e = expr_parse_str( &pos, &msg, opt_filter );
			if( e == NULL ){
				syslog( LOG_ERR, "startup filter "
						"failed at %d: %s",
						pos, msg );
			}
		}

		/* at least initialize with an empty filter */
		random_setfilter( e );
	}


	syslog(LOG_INFO, "waiting" );
	loop();

	syslog(LOG_INFO, "terminating" );
	player_stop();
	clients_done();
	db_done();
	pidfile_funlock(pidfile);
	return 0;
}

static void usage( void )
{
	printf( "usage: %s [opt]\n", progname );
	printf(
		" -h --help          show this message\n"
		" -f --foreground    do not detach\n"
		" -d --debug         be more verbose\n"
		" -p --port <port>   set port to listen on\n"
	      );
}

{'fraction_non_alphanumeric': 0.1635322092520536, 'fraction_numerical': 0.00648508430609598, 'mean_word_length': 2.917442845046571, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4161003', 'n_tokens_mistral': 4131, 'n_tokens_neox': 3638, 'n_words': 975}