<commit_before>#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>

#define DEFAULT_STDOUT_PRI "user.info"
#define DEFAULT_STDERR_PRI "user.err"

#define LOGGER_COMMAND "logger"
#define RESPAWN_CYCLE 60

int close_on_exec(int fileno) {
	int result = fcntl(fileno, F_GETFD, 0);
	if (result < 0) return result;
	return fcntl(fileno, F_SETFD, result | FD_CLOEXEC);
}

int pipe_to_logger(char* const log_priority, char* const log_tag, int fileno, sigset_t* blocked_signals) {
	int result;
	int pipe_handles[2];
	pid_t child;
	
	// create a pipe to talk to the child logger process over
	if (pipe(pipe_handles) < 0) {
		perror("Couldn't create a pipe");
		return -1;
	}
	
	// fork to give us a new process to run the logger
	child = fork();
	if (child < 0) {
		// hit the process limit
		close(pipe_handles[0]);
		close(pipe_handles[1]);
		perror("Couldn't fork to start logger");
		return -1;
		
	} else if (child == 0) {
		// we are the child; we're meant to run logger, which only needs stdin and produces (hopefully) no output.
		
		// the logger shouldn't ever output itself, and it really should close stdout and stderr after it starts 
		// up successfully.  but at least some common implementations don't, and we don't want loggers to hold
		// open pipes to previous loggers, since then we'd end up with a linked list of logger processes which
		// wouldn't go away until the last one has its inputs closed.  we don't want to close our output just yet
		// though, because we want somewhere to complain to if our execvp call fails, so instead we turn on the
		// close-on-exec flag for them.  the logger processes themselves still have nowhere to complain to, but
		// that's unavoidable - where could they send it?
		close_on_exec(STDOUT_FILENO); // ignore errors if these have already been closed
		close_on_exec(STDERR_FILENO);
		
		do { result = dup2(pipe_handles[0], STDIN_FILENO); } while (result < 0 && errno == EINTR); // closes STDIN_FILENO
		if (result < 0) {
			perror("Couldn't attach the pipe to the logger input");
			return -1;
		}
		
		close(pipe_handles[0]); // now it's been dupd, we don't need the allocated descriptor
		close(pipe_handles[1]); // and we won't write into the pipe, and want to notice when the actual writer closes it

		// execute the logger program, replacing this program
		char* const arguments[] = {LOGGER_COMMAND, "-p", log_priority, "-t", log_tag, NULL};
		sigprocmask(SIG_UNBLOCK, blocked_signals, NULL);
		execvp(LOGGER_COMMAND, arguments); // only returns if there's an error
		perror("Couldn't execute logger");
		return -1;
		
	} else {
		// we are the parent; we can write to pipe_handles[1], and it'll go to the child logger process
		do { result = dup2(pipe_handles[1], fileno); } while (result < 0 && errno == EINTR); // closes the original fileno, if it's currently open
		if (result < 0) {
			perror("Couldn't attach the pipe to the logger output");
			return -1;
		}

		close(pipe_handles[1]); // now it's been dupd, we don't need the allocated descriptor
		close(pipe_handles[0]); // and we won't read from the pipe
		return 0;
	}
}

void dummy_handler(int signo) {
	// do nothing
}

int install_signal_handler(int signo, void (*func)(int)) {
	struct sigaction action;
	action.sa_handler = func;
	action.sa_flags = 0; // no SA_RESTART (apparently on by default on some OSs)
	if (sigemptyset(&action.sa_mask) < 0 ||
		sigaction(signo, &action, NULL) < 0) {
		return -1;
	}
	return 0;
}

int install_signal_handlers(sigset_t* signals) {
	// we'll use sigwait to wait for any of the signals of interest to be delivered, since some of
	// the actions we want to take can't be taken inside a signal handler (ie. non-async-signal-safe
	// syscalls).  however, sigwait will only return for signals that were not ignored (since the OS
	// drops ignored signals early), so we set some handlers even though the handlers do nothing.
	if (install_signal_handler(SIGQUIT, &dummy_handler) < 0 ||
	    install_signal_handler(SIGTERM, &dummy_handler) < 0 ||
	    install_signal_handler(SIGCHLD, &dummy_handler) < 0 ||
	    install_signal_handler(SIGALRM, &dummy_handler) < 0 ||
	    install_signal_handler(SIGUSR1, &dummy_handler) < 0 ||
	    install_signal_handler(SIGUSR2, &dummy_handler) < 0 ||
	    install_signal_handler(SIGHUP,  &dummy_handler) < 0) {
		perror("Couldn't install signal handler");
		return -1;
	}

	if (sigemptyset(signals) < 0 ||
	    sigaddset(signals, SIGQUIT) < 0 ||
	    sigaddset(signals, SIGTERM) < 0 ||
	    sigaddset(signals, SIGCHLD) < 0 ||
	    sigaddset(signals, SIGALRM) < 0 ||
	    sigaddset(signals, SIGUSR1) < 0 ||
	    sigaddset(signals, SIGUSR2) < 0 ||
	    sigaddset(signals, SIGHUP)  < 0 ||
		sigprocmask(SIG_BLOCK, signals, NULL) < 0) {
		perror("Couldn't establish blocked signal set");
		return -1;
	}
	
	return 0;
}

void clear_pending_blocked_signals(int signo) {
	install_signal_handler(signo, signal(signo, SIG_IGN));
}

/**
 * Clears the alarm timer, clears any pending alarms (alarms that have timed out but whose signal
 * is currently blocked by the sigprocmask), and then if seconds is >0, starts the alarm timer.
 */
void reset_alarm(unsigned int seconds) {
	alarm(0);
	clear_pending_blocked_signals(SIGALRM);
	alarm(seconds);
}

long atoi_or_default(char* s, long def) {
	char* end = NULL;
	long result = strtol(s, &end, 10);
	if (end && *end == 0) return result;
	return def;
}

void write_pid_file(char* pid_file) {
	FILE* f = fopen(pid_file, "w");
	if (f) {
		fprintf(f, "%d\n", getpid());
		fclose(f);
	} else {
		fprintf(stderr, "Couldn't open %s for writing: %s (%d)\n", pid_file, strerror(errno), errno);
	}
}

void remove_pid_file(char* pid_file) {
	if (unlink(pid_file) < 0) {
		fprintf(stderr, "Couldn't unlink %s: %s (%d)\n", pid_file, strerror(errno), errno);
	}
}

char* program_name(char* command) {
	char* last_slash = strrchr(command, '/');
	if (!last_slash) return command;
	return last_slash;
}

int help() {
	fprintf(stderr, "%s",
		"Usage: niet /usr/bin/someprogram foo bar\n"
		"          - Runs someprogram with the arguments 'foo' and 'bar', restarting the program again if it\n"
		"            dies, waiting for up to %ds if it's dying in less than %ds. Sends output from the program\n"
		"            on its stdout and stderr to syslog using `logger`.  If sent a TERM signal, sends a TERM\n"
		"            signal to the program, waits for it to finish, and then restarts it.  If sent a QUIT\n"
		"            signal, sends a TERM signal to the program, waits for it to finish, and then quits.\n"
		"\n"
		"            niet requires no privileges and should be run as the user you want to run the daemon under.\n"
		"            It can be run as root, but running your daemons as root is generally discouraged.\n"
		"\n"
		"Options: -o daemon.notice  Changes the log priority of the syslog messages logged from the program's\n"
		"                           stdout to 'daemon.notice'.  Default: %s.\n"
		"         -e daemon.alert   Changes the log priority of the syslog messages logged from the program's\n"
		"                           stderr to 'daemon.alert'.  Default: %s.\n"
		"         -t syslog_tag     Changes the syslog tag of the syslog messages logged from the program's\n"
		"                           stdout & stderr to 'syslog_tag'.  Default: the program's command name.\n"
		"         -k 15             Sets a timeout of 15 seconds after the program is sent a TERM signal,\n"<commit_msg>omit the slash from syslog tags extracted from program commands; handle slashes at the end, though that will generally not be executable anyway<commit_after>#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>

#define DEFAULT_STDOUT_PRI "user.info"
#define DEFAULT_STDERR_PRI "user.err"

#define LOGGER_COMMAND "logger"
#define RESPAWN_CYCLE 60

int close_on_exec(int fileno) {
	int result = fcntl(fileno, F_GETFD, 0);
	if (result < 0) return result;
	return fcntl(fileno, F_SETFD, result | FD_CLOEXEC);
}

int pipe_to_logger(char* const log_priority, char* const log_tag, int fileno, sigset_t* blocked_signals) {
	int result;
	int pipe_handles[2];
	pid_t child;
	
	// create a pipe to talk to the child logger process over
	if (pipe(pipe_handles) < 0) {
		perror("Couldn't create a pipe");
		return -1;
	}
	
	// fork to give us a new process to run the logger
	child = fork();
	if (child < 0) {
		// hit the process limit
		close(pipe_handles[0]);
		close(pipe_handles[1]);
		perror("Couldn't fork to start logger");
		return -1;
		
	} else if (child == 0) {
		// we are the child; we're meant to run logger, which only needs stdin and produces (hopefully) no output.
		
		// the logger shouldn't ever output itself, and it really should close stdout and stderr after it starts 
		// up successfully.  but at least some common implementations don't, and we don't want loggers to hold
		// open pipes to previous loggers, since then we'd end up with a linked list of logger processes which
		// wouldn't go away until the last one has its inputs closed.  we don't want to close our output just yet
		// though, because we want somewhere to complain to if our execvp call fails, so instead we turn on the
		// close-on-exec flag for them.  the logger processes themselves still have nowhere to complain to, but
		// that's unavoidable - where could they send it?
		close_on_exec(STDOUT_FILENO); // ignore errors if these have already been closed
		close_on_exec(STDERR_FILENO);
		
		do { result = dup2(pipe_handles[0], STDIN_FILENO); } while (result < 0 && errno == EINTR); // closes STDIN_FILENO
		if (result < 0) {
			perror("Couldn't attach the pipe to the logger input");
			return -1;
		}
		
		close(pipe_handles[0]); // now it's been dupd, we don't need the allocated descriptor
		close(pipe_handles[1]); // and we won't write into the pipe, and want to notice when the actual writer closes it

		// execute the logger program, replacing this program
		char* const arguments[] = {LOGGER_COMMAND, "-p", log_priority, "-t", log_tag, NULL};
		sigprocmask(SIG_UNBLOCK, blocked_signals, NULL);
		execvp(LOGGER_COMMAND, arguments); // only returns if there's an error
		perror("Couldn't execute logger");
		return -1;
		
	} else {
		// we are the parent; we can write to pipe_handles[1], and it'll go to the child logger process
		do { result = dup2(pipe_handles[1], fileno); } while (result < 0 && errno == EINTR); // closes the original fileno, if it's currently open
		if (result < 0) {
			perror("Couldn't attach the pipe to the logger output");
			return -1;
		}

		close(pipe_handles[1]); // now it's been dupd, we don't need the allocated descriptor
		close(pipe_handles[0]); // and we won't read from the pipe
		return 0;
	}
}

void dummy_handler(int signo) {
	// do nothing
}

int install_signal_handler(int signo, void (*func)(int)) {
	struct sigaction action;
	action.sa_handler = func;
	action.sa_flags = 0; // no SA_RESTART (apparently on by default on some OSs)
	if (sigemptyset(&action.sa_mask) < 0 ||
		sigaction(signo, &action, NULL) < 0) {
		return -1;
	}
	return 0;
}

int install_signal_handlers(sigset_t* signals) {
	// we'll use sigwait to wait for any of the signals of interest to be delivered, since some of
	// the actions we want to take can't be taken inside a signal handler (ie. non-async-signal-safe
	// syscalls).  however, sigwait will only return for signals that were not ignored (since the OS
	// drops ignored signals early), so we set some handlers even though the handlers do nothing.
	if (install_signal_handler(SIGQUIT, &dummy_handler) < 0 ||
	    install_signal_handler(SIGTERM, &dummy_handler) < 0 ||
	    install_signal_handler(SIGCHLD, &dummy_handler) < 0 ||
	    install_signal_handler(SIGALRM, &dummy_handler) < 0 ||
	    install_signal_handler(SIGUSR1, &dummy_handler) < 0 ||
	    install_signal_handler(SIGUSR2, &dummy_handler) < 0 ||
	    install_signal_handler(SIGHUP,  &dummy_handler) < 0) {
		perror("Couldn't install signal handler");
		return -1;
	}

	if (sigemptyset(signals) < 0 ||
	    sigaddset(signals, SIGQUIT) < 0 ||
	    sigaddset(signals, SIGTERM) < 0 ||
	    sigaddset(signals, SIGCHLD) < 0 ||
	    sigaddset(signals, SIGALRM) < 0 ||
	    sigaddset(signals, SIGUSR1) < 0 ||
	    sigaddset(signals, SIGUSR2) < 0 ||
	    sigaddset(signals, SIGHUP)  < 0 ||
		sigprocmask(SIG_BLOCK, signals, NULL) < 0) {
		perror("Couldn't establish blocked signal set");
		return -1;
	}
	
	return 0;
}

void clear_pending_blocked_signals(int signo) {
	install_signal_handler(signo, signal(signo, SIG_IGN));
}

/**
 * Clears the alarm timer, clears any pending alarms (alarms that have timed out but whose signal
 * is currently blocked by the sigprocmask), and then if seconds is >0, starts the alarm timer.
 */
void reset_alarm(unsigned int seconds) {
	alarm(0);
	clear_pending_blocked_signals(SIGALRM);
	alarm(seconds);
}

long atoi_or_default(char* s, long def) {
	char* end = NULL;
	long result = strtol(s, &end, 10);
	if (end && *end == 0) return result;
	return def;
}

void write_pid_file(char* pid_file) {
	FILE* f = fopen(pid_file, "w");
	if (f) {
		fprintf(f, "%d\n", getpid());
		fclose(f);
	} else {
		fprintf(stderr, "Couldn't open %s for writing: %s (%d)\n", pid_file, strerror(errno), errno);
	}
}

void remove_pid_file(char* pid_file) {
	if (unlink(pid_file) < 0) {
		fprintf(stderr, "Couldn't unlink %s: %s (%d)\n", pid_file, strerror(errno), errno);
	}
}

char* program_name(char* command) {
	char* last_slash = strrchr(command, '/');
	if (!last_slash || !*(last_slash + 1)) return command;
	return last_slash + 1;
}

int help() {
	fprintf(stderr, "%s",
		"Usage: niet /usr/bin/someprogram foo bar\n"
		"          - Runs someprogram with the arguments 'foo' and 'bar', restarting the program again if it\n"
		"            dies, waiting for up to %ds if it's dying in less than %ds. Sends output from the program\n"
		"            on its stdout and stderr to syslog using `logger`.  If sent a TERM signal, sends a TERM\n"
		"            signal to the program, waits for it to finish, and then restarts it.  If sent a QUIT\n"
		"            signal, sends a TERM signal to the program, waits for it to finish, and then quits.\n"
		"\n"
		"            niet requires no privileges and should be run as the user you want to run the daemon under.\n"
		"            It can be run as root, but running your daemons as root is generally discouraged.\n"
		"\n"
		"Options: -o daemon.notice  Changes the log priority of the syslog messages logged from the program's\n"
		"                           stdout to 'daemon.notice'.  Default: %s.\n"
		"         -e daemon.alert   Changes the log priority of the syslog messages logged from the program's\n"
		"                           stderr to 'daemon.alert'.  Default: %s.\n"
		"         -t syslog_tag     Changes the syslog tag of the syslog messages logged from the program's\n"
		"                           stdout & stderr to 'syslog_tag'.  Default: the program's command name.\n"
		"         -k 15             Sets a timeout of 15 seconds after the program is sent a TERM signal,\n"
{'fraction_non_alphanumeric': 0.10903344745851988, 'fraction_numerical': 0.008954437713984725, 'mean_word_length': 3.442527054694355, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 19, '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': '6757505', 'n_tokens_mistral': 5380, 'n_tokens_neox': 4960, 'n_words': 1820}