Change sample command-line.
[irspy-moved-to-github.git] / bin / setrlimit.c
1 /*
2  * A simple wrapper program for the setrlimit(2) system call, which
3  * can be used to run a subprocess under a different regime -- much
4  * like "nice", "time", etc.  This is needed for IRSpy, since when it
5  * runs against many servers simultaneously, it runs out of file
6  * descriptors -- a condition, by the way, which Perl sometimes
7  * reports very misleadingly (e.g. "Can't locate Scalar/Util.pm in
8  * @INC" when the open() failure was due to EMFILE rather than
9  * ENOENT).
10  *
11  * Since the file-descriptor limit can be raised (from the default of
12  * 1024 in Ubuntu) only by root, this program often needs to run as
13  * root -- hence the option for resetting the UID after performing the
14  * limit-change.
15  */
16
17 #include <getopt.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <sys/time.h>
23 #include <sys/resource.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <pwd.h>
27
28 static struct {
29     int c;
30     char *name;
31     int value;
32     long multiplier;
33 } types[] = {
34     { 'a', "AS", RLIMIT_AS, 1024*1024 },
35     { 'n', "NOFILE", RLIMIT_NOFILE, 1 },
36 };
37
38
39 int main(int argc, char **argv) {
40     int verbose = 0;
41     long values[26];
42     char *user = 0;
43     int i, c;
44
45     for (i = 0; i < 26; i++) {
46         values[i] = 0;
47     }
48
49     while ((c = getopt(argc, argv, "vu:a:n:")) != -1) {
50         switch (c) {
51         case 'v':
52             verbose++;
53             break;
54         case 'u':
55             user = optarg;
56             break;
57         case 'a':
58         case 'n': 
59             values[c-'a'] = strtol(optarg, (char**) 0, 0);
60             break;
61         default:
62         USAGE:
63             fprintf(stderr, "Usage: %s [options] <command>\n\
64         -v              Verbose mode\n\
65         -u <user>       Run subcommand as <user>\n\
66         -a <Mbytes>     Set maximum size of address-space (memory)\n\
67         -n <number>     Set maximum open files to <number>\n",
68                     argv[0]);
69             exit(1);
70         }
71     }
72
73     if (optind == argc)
74         goto USAGE;
75
76     for (c = 'a'; c <= 'z'; c++) {
77         long n = values[c - 'a'];
78         if (n != 0) {
79             int i, ntypes = sizeof types/sizeof *types;
80             struct rlimit old, new;
81
82             for (i = 0; i < ntypes; i++) {
83                 if (types[i].c == c)
84                     break;
85             }
86
87             if (i == ntypes) {
88                 fprintf(stderr, "%s: no such type '%c'\n", argv[0], c);
89                 exit(2);
90             }
91
92             n *= types[i].multiplier;
93             getrlimit(types[i].value, &old);
94             new = old;
95             new.rlim_cur = n;
96             if (n > new.rlim_max)
97                 new.rlim_max = n;
98             if (verbose) {
99                 if (new.rlim_cur != old.rlim_cur)
100                     fprintf(stderr, "%s: changing soft %s from %ld to %ld\n",
101                             argv[0], types[i].name,
102                             (long) old.rlim_cur, (long) new.rlim_cur);
103                 if (new.rlim_max != old.rlim_max)
104                     fprintf(stderr, "%s: changing hard %s from %ld to %ld\n",
105                             argv[0], types[i].name,
106                             (long) old.rlim_max, (long) new.rlim_max);
107             }
108             if (setrlimit(types[i].value, &new) < 0) {
109                 fprintf(stderr, "%s: setrlimit(%s=%ld): %s\n",
110                         argv[0], types[i].name, n, strerror(errno));
111                 exit(3);
112             }
113         }
114     }
115
116     if (user != 0) {
117         struct passwd *pwd;
118         if ((pwd = getpwnam(user)) == 0) {
119             fprintf(stderr, "%s: user '%s' not known\n", argv[0], user);
120             exit(4);
121         }
122
123         if (setuid(pwd->pw_uid) < 0) {
124             fprintf(stderr, "%s: setuid('%s'=%ld): %s\n",
125                     argv[0], user, (long) pwd->pw_uid, strerror(errno));
126             exit(5);
127         }
128     }
129
130     if (verbose)
131         fprintf(stderr, "%s: user='%s', optind=%d, new argc=%d, argv[0]='%s'\n",
132                 argv[0], user, optind, argc-optind, argv[optind]);
133
134     execvp(argv[optind], argv+optind);
135     fprintf(stderr, "%s: execvp('%s'): %s\n",
136             argv[0], argv[optind], strerror(errno));
137     exit(6);
138 }