/* Copyright 2004 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define SLACK 1024

static void bump_rlimit(int num)
{
    struct rlimit lim;

    if (getrlimit(RLIMIT_NOFILE, &lim)) {
        perror("getrlimit/RLIMIT_NOFILE");
        exit(1);
    }

    if (lim.rlim_cur < num + SLACK) {
        lim.rlim_cur = lim.rlim_max = num + SLACK;
        if (setrlimit(RLIMIT_NOFILE, &lim)) {
            perror("setrlimit/RLIMIT_NOFILE");
            exit(1);
        }
    }
}

int main(int argc, char **argv)
{
    int n, num;

    if (argc < 3) {
        fprintf(stderr, "Usage: %s NUM PROGRAM [ARGS...]\n", argv[0]);
        fprintf(stderr, 
                "  bumpfd uses up NUM fd numbers, raising the rlimit if necessary,\n"
                "  then execs PROGRAM, passing ARGS on argv.\n");
        return 1;
    }

    num = atoi(argv[1]);
    argv += 2;
    argc -= 2;
    
    bump_rlimit(num);

    for (n = 0; n < num; n++) {
        int fd = open("/dev/null", O_RDONLY);
        if (fd < 0) {
            perror("open");
            fprintf(stderr, "bumpfd: Failed to use fd %d\n", n);
            return 2;
        }
    }
    
    execvp(argv[0], argv);
    perror("execvp");
    return 3;
}

