3 * Change processes' resource limits.
5 * (c) 2011 Mark Wooding
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the Toys utilties collection.
12 * Toys is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * Toys is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with Toys; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /*----- Header files ------------------------------------------------------*/
30 #define _FILE_OFFSET_BITS 64
39 #include <sys/resource.h>
41 #include <mLib/alloc.h>
42 #include <mLib/mdwopt.h>
43 #include <mLib/quis.h>
44 #include <mLib/report.h>
46 /*----- Static variables --------------------------------------------------*/
48 /*----- Argument parsing functions ----------------------------------------*/
50 static const struct limittab
{
54 /* ;;; Emacs Lisp to generate the table below. Place your cursor just
55 ;;; after the closing `)' and press C-x C-e.
57 (let ((resources '(as core cpu data fsize locks memlock
58 msgqueue nice nofile nproc rss rtprio
59 rttime sigpending stack)))
61 (goto-char (point-min))
62 (search-forward (concat "***" "BEGIN rlimittab" "***"))
64 (delete-region (point)
66 (search-forward "***END***")
69 (dolist (rsc (sort (copy-list resources) #'string<))
70 (let ((up (upcase (symbol-name rsc))))
71 (insert (format "#ifdef RLIMIT_%s\n" up))
72 (insert (format " { \"%s\", RLIMIT_%s },\n" rsc up))
73 (insert "#endif\n")))))
75 /***BEGIN rlimittab***/
80 { "core", RLIMIT_CORE
},
83 { "cpu", RLIMIT_CPU
},
86 { "data", RLIMIT_DATA
},
89 { "fsize", RLIMIT_FSIZE
},
92 { "locks", RLIMIT_LOCKS
},
95 { "memlock", RLIMIT_MEMLOCK
},
97 #ifdef RLIMIT_MSGQUEUE
98 { "msgqueue", RLIMIT_MSGQUEUE
},
101 { "nice", RLIMIT_NICE
},
104 { "nofile", RLIMIT_NOFILE
},
107 { "nproc", RLIMIT_NPROC
},
110 { "rss", RLIMIT_RSS
},
113 { "rtprio", RLIMIT_RTPRIO
},
116 { "rttime", RLIMIT_RTTIME
},
118 #ifdef RLIMIT_SIGPENDING
119 { "sigpending", RLIMIT_SIGPENDING
},
122 { "stack", RLIMIT_STACK
},
128 static rlim_t
parselong(const char *p
, char **qq
)
134 if (strcmp(p
, "inf") == 0) return (RLIM_INFINITY
);
136 l
= strtol(p
, &q
, 0);
140 else if (*q
) goto err
;
144 die(EXIT_FAILURE
, "bad integer `%s'\n", p
);
148 static rlim_t
parselimit(const char *p
)
153 if (strcmp(p
, "inf") == 0) return (RLIM_INFINITY
);
154 l
= parselong(p
, &q
);
156 case 't': case 'T': l
*= 1024;
157 case 'g': case 'G': l
*= 1024;
158 case 'm': case 'M': l
*= 1024;
159 case 'k': case 'K': l
*= 1024;
160 case 'b': case 'B': q
++;
166 die(EXIT_FAILURE
, "bad size `%s'\n", p
);
170 static const struct limittab
*findlimit(const char *p
, size_t n
)
172 const struct limittab
*lt
;
174 for (lt
= limittab
; lt
->name
; lt
++) {
175 if (strncmp(lt
->name
, p
, n
) == 0 && !lt
->name
[n
])
178 die(EXIT_FAILURE
, "unknown resource limit `%.*s'\n", n
, p
);
182 /*----- Help functions ----------------------------------------------------*/
184 static void usage(FILE *fp
)
185 { pquis(fp
, "Usage: % -l | "
186 "{hard | soft | both | PID | RSRC[=VALUE]}...\n"); }
188 static void version(FILE *fp
)
189 { pquis(fp
, "$, version " VERSION
"\n"); }
191 static void help(FILE *fp
)
193 version(fp
); putchar('\n');
196 Alter use limits for running processes. The resource assignments are\n\
197 applied to the given process ids. Resource names without values cause\n\
198 processes' current resource limits to be printed.\n\
202 -h, --help Show this help text.\n\
203 -v, --version Show the program's version number.\n\
204 -u, --usage Show a terse usage reminder.\n\
206 -l, --list List the resource limit names.\n\
210 /*----- Main program ------------------------------------------------------*/
214 const struct limittab
*lt
;
218 static void showlimit(const struct limittab
*lt
, rlim_t val
)
220 if (val
== RLIM_INFINITY
) printf("%s=inf", lt
->name
);
222 static const char *suff
[] = { "", "k", "M", "G", "T", 0 };
223 const char **s
= suff
;
224 while (s
[1] && val
&& !(val
&0x3ff)) { s
++; val
>>= 10; }
225 printf("%s=%lu%s", lt
->name
, (unsigned long)val
, *s
);
229 int main(int argc
, char *argv
[])
233 const struct limittab
*lt
;
235 size_t nassign
, npid
;
236 struct assign
*assign
;
242 #define f_which (f_soft | f_hard)
247 static const struct option opts
[] = {
248 { "help", 0, 0, 'h' },
249 { "version", 0, 0, 'v' },
250 { "usage", 0, 0, 'u' },
251 { "list", 0, 0, 'l' },
254 int i
= mdwopt(argc
, argv
, "hvul", opts
, 0, 0, 0);
258 case 'h': help(stdout
); exit(0);
259 case 'v': version(stdout
); exit(0);
260 case 'u': usage(stdout
); exit(0);
262 for (lt
= limittab
; lt
->name
; lt
++) puts(lt
->name
);
264 default: f
|= f_bogus
; break;
267 if ((f
& f_bogus
) || (argc
- optind
) < 1) {
272 pid
= xmalloc(sizeof(*pid
) * (argc
- optind
));
273 assign
= xmalloc(sizeof(*assign
) * (argc
- optind
));
275 f
|= f_hard
| f_soft
;
277 for (i
= optind
; i
< argc
; i
++) {
278 if (strcmp(argv
[i
], "soft") == 0) f
= (f
& ~f_which
) | f_soft
;
279 else if (strcmp(argv
[i
], "hard") == 0) f
= (f
& ~f_which
) | f_hard
;
280 else if (strcmp(argv
[i
], "both") == 0) f
|= f
| f_soft
| f_hard
;
281 else if ((p
= strchr(argv
[i
], '=')) != 0) {
282 lt
= findlimit(argv
[i
], p
- argv
[i
]);
283 assign
[nassign
].which
= f
& f_which
;
284 assign
[nassign
].lt
= lt
;
285 assign
[nassign
].val
= parselimit(p
+ 1);
287 } else if (isalpha((unsigned char)*argv
[i
])) {
288 lt
= findlimit(argv
[i
], strlen(argv
[i
]));
289 assign
[nassign
].which
= 0;
290 assign
[nassign
].lt
= lt
;
293 pid
[npid
++] = parselong(argv
[i
], 0);
296 if (!npid
) die(EXIT_FAILURE
, "no processes to act on");
297 if (!nassign
) die(EXIT_FAILURE
, "no limits to apply or show");
299 for (i
= 0; i
< npid
; i
++) {
300 for (j
= 0; j
< nassign
; j
++) {
301 if (prlimit(pid
[i
], assign
[j
].lt
->id
, 0, &lim
)) {
302 moan("failed to read `%s' limit for pid %ld: %s",
303 assign
[j
].lt
->name
, (long)pid
[i
], strerror(errno
));
306 if (!assign
[j
].which
) {
307 printf("%ld soft ", (long)pid
[i
]); showlimit(lt
, lim
.rlim_cur
);
308 printf(" hard "); showlimit(lt
, lim
.rlim_max
); putchar('\n');
310 if (assign
[j
].which
& f_soft
) lim
.rlim_cur
= assign
[j
].val
;
311 if (assign
[j
].which
& f_hard
) lim
.rlim_max
= assign
[j
].val
;
312 if (prlimit(pid
[i
], assign
[j
].lt
->id
, &lim
, 0)) {
313 moan("failed to set `%s' limit for pid %ld: %s\n",
314 assign
[j
].lt
->name
, (long)pid
[i
], strerror(errno
));
324 return (f
& f_bogus ? EXIT_FAILURE
: 0);
327 /*----- That's all, folks -------------------------------------------------*/