/*
 * Copyright 2001, 2002, 2003 Adam Sampson <ats@offog.org>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "iolib.h"
#include "freedt.h"
#include "config.h"
const char *progname = "softlimit";
const char *proghelp =
	"Usage: softlimit [OPTIONS] command ...\n"
	"Run a command with soft limits set.\n\n"
	"-m N      Limit DATA, STACK, MEMLOCK and AS\n"
#if HAVE_DECL_RLIMIT_DATA
	"-d N      Limit DATA\n"
#endif
#if HAVE_DECL_RLIMIT_STACK
	"-s N      Limit STACK\n"
#endif
#if HAVE_DECL_RLIMIT_MEMLOCK
	"-l N      Limit MEMLOCK\n"
#endif
#if HAVE_DECL_RLIMIT_AS
	"-a N      Limit AS\n"
#endif
#if HAVE_DECL_RLIMIT_NOFILE
	"-o N      Limit NOFILE\n"
#endif
#if HAVE_DECL_RLIMIT_NPROC
	"-p N      Limit NPROC\n"
#endif
#if HAVE_DECL_RLIMIT_FSIZE
	"-f N      Limit FSIZE\n"
#endif
#if HAVE_DECL_RLIMIT_CORE
	"-c N      Limit CORE\n"
#endif
#if HAVE_DECL_RLIMIT_RSS
	"-r N      Limit RSS\n"
#endif
#if HAVE_DECL_RLIMIT_CPU
	"-t N      Limit CPU\n"
#endif
#if HAVE_DECL_RLIMIT_SBSIZE
	"-b N      Limit SBSIZE\n"
#endif
#if HAVE_DECL_RLIMIT_VMEM
	"-v N      Limit VMEM\n"
#endif
	"(N above is limit, or \"=\" to use the hard limit.)\n";

void set(int resource, char *value) {
	struct rlimit lim;

	if (getrlimit(resource, &lim) < 0)
		die("failed to get limit");

	if (strcmp(value, "=") == 0) {
		lim.rlim_cur = lim.rlim_max;
	} else {
		lim.rlim_cur = atoi(value);
	}

	if (setrlimit(resource, &lim) < 0)
		die("failed to set limit");
}

int main(int argc, char **argv) {
	while (1) {
		int c = getopt(argc, argv, "+V?m:d:s:l:a:o:p:f:c:r:t:b:v:");
		if (c == -1)
			break;

		switch (c) {
		case 'm':
#if HAVE_DECL_RLIMIT_DATA
			set(RLIMIT_DATA, optarg);
#endif
#if HAVE_DECL_RLIMIT_STACK
			set(RLIMIT_STACK, optarg);
#endif
#if HAVE_DECL_RLIMIT_MEMLOCK
			set(RLIMIT_MEMLOCK, optarg);
#endif
#if HAVE_DECL_RLIMIT_AS
			set(RLIMIT_AS, optarg);
#endif
			break;
#if HAVE_DECL_RLIMIT_DATA
		case 'd':
			set(RLIMIT_DATA, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_STACK
		case 's':
			set(RLIMIT_STACK, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_MEMLOCK
		case 'l':
			set(RLIMIT_MEMLOCK, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_AS
		case 'a':
			set(RLIMIT_AS, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_NOFILE
		case 'o':
			set(RLIMIT_NOFILE, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_NPROC
		case 'p':
			set(RLIMIT_NPROC, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_FSIZE
		case 'f':
			set(RLIMIT_FSIZE, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_CORE
		case 'c':
			set(RLIMIT_CORE, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_RSS
		case 'r':
			set(RLIMIT_RSS, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_CPU
		case 't':
			set(RLIMIT_CPU, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_SBSIZE
		case 'b':
			set(RLIMIT_SBSIZE, optarg);
			break;
#endif
#if HAVE_DECL_RLIMIT_VMEM
		case 'v':
			set(RLIMIT_VMEM, optarg);
			break;
#endif
		case 'V':
			version();
		default:
			help();
		}
	}

	if ((argc - optind) < 1)
		help();

	execvp(argv[optind], &argv[optind]);
	die2(argv[optind], "unable to exec");

	return 0; /* NOTREACHED */
}

