#include <signal.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <errno.h>
#include <asm/unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#ifdef __i386__
#define __NR_getluid            510
#define __NR_setluid            511
#define __NR_setublimit         512
#define __NR_ubstat             513
#else
#error "syscall numbers are not defined"
#endif

// long sys_setublimit(uid_t uid, unsigned long resource,
//                                    unsigned long *limits)
static _syscall3(long, setublimit, 
		int, uid, unsigned long, resource, 
		unsigned long *, limits);
// long sys_setluid(uid_t uid)
static _syscall1(long, setluid, int, uid);

void usage(char *name)
{
	fprintf(stderr, "%s commands\n"
			"\tset uid resource barrier [limit]\n"
			"\t\t set barrier end limit\n"
			"\tenter uid\n"
			"\t\tset luid and exec SHELL\n"
			, name);
}

int main(int argc, char **argv)
{
	uid_t uid;
	unsigned long resource;
	long ret;
	char *endptr;
 
	if (argc <3) {
		usage(argv[0]);
		exit(1);
	}
	uid = strtol(argv[2], &endptr, 0);
	if (*endptr != '\0') {
		usage(argv[0]);
		exit(1);
	}
	if (strstr(argv[1], "set") == argv[1]) {
		unsigned long limits[2];
		if (argc < 5) {
			usage(argv[0]);
			exit(1);
		}
		resource = strtol(argv[3], &endptr, 0);
		if (*endptr != '\0') {
			usage(argv[0]);
			exit(1);
		}
		limits[0] = strtol(argv[4], &endptr, 0);
		if (*endptr != '\0') {
			usage(argv[0]);
			exit(1);
		}
		limits[1] = limits[0];
		if (argc > 5) {
			limits[1] = strtol(argv[5], &endptr, 0);
			if (*endptr != '\0') {
				usage(argv[0]);
				exit(1);
			}
		}
		ret = setublimit(uid, resource, limits);
		if (ret < 0) {
			perror("setublimit:");
			exit(1);
		}
	} else if (strstr(argv[1], "enter") == argv[1]) {
		char *shell;

		ret = setluid(uid);
		if (ret < 0) {
			perror("setluid:");
			exit(1);
		}
		shell = getenv("SHELL");
		if (shell == NULL)
			shell = "/bin/sh";
		execl(shell, shell, NULL);
		perror("execl");
		exit(1);
	} else {
			usage(argv[0]);
			exit(1);
	}
	return 0;
}
