/*****************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * $Id: ulimiter.c,v 1.1 2005-12-09 10:40:19 bagder Exp $
 *
 * Little tool to raise the amount of maximum file descriptor and then run the
 * given command line (using the hard-coded uid/gid).
 *
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <errno.h>
#include <string.h> /* for errno translation */

/* ulimiter
 *
 * Source code inspiration from:
 *  http://www.cs.wisc.edu/condor/condorg/linux_scalability.html
 */

#define UID 1000 /* the user who must run this */

#define GID 1000 /* group id to run the program as */

/* Number of open files to increase to */
#define NEW_MAX 10000

int main(int argc, char *argv[])
{
  int ret;
  struct rlimit rl;
  char *brgv[20];
  int brgc=argc-1;
  int i;

  for(i=1; i< argc; i++)
    brgv[i-1]=argv[i];
  brgv[i-1]=NULL; /* terminate the list */

  if(getuid() != UID) {
    fprintf(stderr, "Only uid %d is allowed to run this\n", UID);
    return 1;
  }

  ret = getrlimit(RLIMIT_NOFILE, &rl);
  if(ret != 0) {
    fprintf(stderr, "Unable to read open file limit.\n"
            "(getrlimit(RLIMIT_NOFILE, &rl) failed)\n"
            "(%d, %s)", errno, strerror(errno));
    return 1;
  }

  fprintf(stderr, "Limit was %d (max %d), setting to %d\n",
          rl.rlim_cur, rl.rlim_max, NEW_MAX);

  rl.rlim_cur = rl.rlim_max = NEW_MAX;
  ret = setrlimit(RLIMIT_NOFILE, &rl);
  if(ret != 0) {
    fprintf(stderr, "Unable to set open file limit.\n"
            "(setrlimit(RLIMIT_NOFILE, &rl) failed)\n"
            "(%d, %s)", errno, strerror(errno));
    return 1;
  }

  ret = getrlimit(RLIMIT_NOFILE, &rl);
  if(ret != 0) {
    fprintf(stderr, "Unable to read new open file limit.\n"
            "(getrlimit(RLIMIT_NOFILE, &rl) failed)\n"
            "(%d, %s)", errno, strerror(errno));
    return 1;
  }
  if(rl.rlim_cur < NEW_MAX) {
    fprintf(stderr, "Failed to set new open file limit.\n"
            "Limit is %d, expected %d\n",
            rl.rlim_cur, NEW_MAX);
    return 1;
  }

  if(setgid(GID) != 0) {
    fprintf(stderr, "setgid failed (%d, %s)\n", errno, strerror(errno));
    return 1;
  }
  if(setuid(UID) != 0) {
    fprintf(stderr, "setuid failed (%d, %s)\n", errno, strerror(errno));
    return 1;
  }

  ret = execv(brgv[0], brgv);

  fprintf(stderr, "execl returned, failure\n"
          "returned %d, errno is %d (%s)\n",
          ret, errno, strerror(errno));
  return 1;
}
