/* $Id: turbo.c,v 1.1 2007-05-06 16:03:10 gophi Exp $ */

#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/mman.h>

#define die(...) do { \
	fprintf(stderr, __VA_ARGS__); \
	exit(EXIT_FAILURE); \
} while (0)

extern char *optarg;
extern int optind, opterr, optopt;

extern int errno;

static void help(void)
{
	static const char msg[] = 
		"turbo (C) 2007 Adam Wysocki <gophi at chmurka.net>\n"
		"\n"
		"Syntax: turbo [-hnsm] cmd [arg...]\n"
		"\n"
		"-h  this help\n"
		"-n  set maximum priority\n"
		"-s  set realtime scheduling\n"
		"-m  prevent swapping\n";

	fputs(msg, stdout);
}

static void opt_n(void)
{
	if (nice(-40) == -1)
		die("nice(): %s\n", strerror(errno));
}

static void opt_s(void)
{
	struct sched_param parm;

	memset(&parm, 0, sizeof(parm));
	if ((parm.sched_priority = sched_get_priority_max(SCHED_FIFO)) == -1)
		die("sched_get_priority_max(SCHED_FIFO): %s\n", strerror(errno));

	if (sched_setscheduler(0, SCHED_FIFO, &parm) == -1)
		die("sched_setscheduler(SCHED_FIFO): %s\n", strerror(errno));
}

static void opt_m(void)
{
	if (mlockall(MCL_FUTURE) == -1)
		die("mlockall(MCL_FUTURE): %s\n", strerror(errno));
}

static void prepare(int ac, char * const av[])
{
	static const char optstr[] = "hnsm";
	int done = 0;

	while (!done) {
		switch (getopt(ac, av, optstr)) {
			case 'h':
				help();
				exit(EXIT_SUCCESS);

			case 'n':
				opt_n();
				break;

			case 's':
				opt_s();
				break;

			case 'm':
				opt_m();
				break;

			case -1:
				done = 1;
				break;

			default:
				exit(EXIT_FAILURE);
		}
	}

	if (optind == ac) {
		help();
		exit(EXIT_SUCCESS);
	}
}

int main(int ac, char * const av[])
{
	prepare(ac, av);

	if (execv(av[optind], av + optind) == -1)
		die("execv(%s): %s\n", av[optind], strerror(errno));

	/* NOTREACHED */

	return 0;
}
