1 // $Id: vlimit.c,v 1.20 2005/03/24 12:44:17 ensc Exp $
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or (at your option)
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 Set the global per context limit of a resource (memory, file handle).
21 This utility can do it either for the current context or a selected
24 It uses the same options as ulimit, when possible
43 #include <sys/resource.h>
49 #define ENSC_WRAPPERS_PREFIX "vlimit: "
50 #define ENSC_WRAPPERS_UNISTD 1
51 #define ENSC_WRAPPERS_VSERVER 1
54 #define CMD_HELP 0x1000
55 #define CMD_VERSION 0x1001
56 #define CMD_XID 0x4000
57 #define CMD_DIR 0x8000
58 #define CMD_MISSINGOK 0x8001
60 int wrapper_exit_code = 255;
63 { #X, required_argument, 0, 2048|X }
64 #define OPT_RESLIM(RES,V) \
65 { #RES, required_argument, 0, 2048|RLIMIT_##V }
67 static struct option const
69 { "help", no_argument, 0, CMD_HELP },
70 { "version", no_argument, 0, CMD_VERSION },
71 { "all", no_argument, 0, 'a' },
72 { "xid", required_argument, 0, CMD_XID },
73 { "dir", required_argument, 0, CMD_DIR },
74 { "missingok", no_argument, 0, CMD_MISSINGOK },
75 NUMLIM( 0), NUMLIM( 1), NUMLIM( 2), NUMLIM( 3),
76 NUMLIM( 4), NUMLIM( 5), NUMLIM( 6), NUMLIM( 7),
77 NUMLIM( 8), NUMLIM( 9), NUMLIM(10), NUMLIM(11),
78 NUMLIM(12), NUMLIM(13), NUMLIM(14), NUMLIM(15),
79 NUMLIM(16), NUMLIM(17), NUMLIM(18), NUMLIM(19),
80 NUMLIM(20), NUMLIM(21), NUMLIM(22), NUMLIM(23),
81 NUMLIM(24), NUMLIM(25), NUMLIM(26), NUMLIM(27),
82 NUMLIM(28), NUMLIM(29), NUMLIM(30), NUMLIM(31),
84 OPT_RESLIM(fsize, FSIZE),
85 OPT_RESLIM(data, DATA),
86 OPT_RESLIM(stack, STACK),
87 OPT_RESLIM(core, CORE),
89 OPT_RESLIM(nproc, NPROC),
90 OPT_RESLIM(nofile, NOFILE),
91 OPT_RESLIM(memlock, MEMLOCK),
93 OPT_RESLIM(locks, LOCKS),
97 #define REV_RESLIM(X) [RLIMIT_##X] = #X
98 static char const * const LIMIT_STR[] = {
99 REV_RESLIM(CPU), REV_RESLIM(FSIZE), REV_RESLIM(DATA), REV_RESLIM(STACK),
100 REV_RESLIM(CORE), REV_RESLIM(RSS), REV_RESLIM(NPROC), REV_RESLIM(NOFILE),
101 REV_RESLIM(MEMLOCK), REV_RESLIM(AS), REV_RESLIM(LOCKS)
105 showHelp(int fd, char const *cmd, int res)
107 VSERVER_DECLARE_CMD(cmd);
109 WRITE_MSG(fd, "Usage: ");
112 " [--xid|-c <xid>] [-nd] [-a|--all] [[-MSH] --(<resource>|<nr>) <value>]*\n"
113 " [--dir <pathname> [--missingok]] [--] [<program> <args>*]\n\n"
116 " ... operate on context <xid>\n"
117 " -a|--all ... show all available limits\n"
118 " -n ... do not resolve limit-names\n"
119 " -d ... show limits in decimal\n"
120 " -M ... set Minimum limit\n"
121 " -S ... set Soft limit\n"
122 " -H ... set Hard limit (assumed by default, when neither\n"
123 " M nor S was requested)\n"
124 " --dir <pathname>\n"
125 " ... read limits from <pathname>/; allowed filenames are\n"
126 " <resource> and <resource>.{min,soft,hard}. When a limit\n"
127 " was set by the CLI already, the corresponding file\n"
129 " --missingok ... do not fail when <pathname> does not exist\n"
130 " --<resource>|<nr> <value>\n"
131 " ... set specified (MSH) limit for <resource> to <value>\n\n"
132 "Valid values for resource are cpu, fsize, data, stack, core, rss, nproc,\n"
133 "nofile, memlock, as and locks.\n\n"
134 "Please report bugs to " PACKAGE_BUGREPORT "\n");
142 "vlimit " VERSION " -- limits context-resources\n"
143 "This program is part of " PACKAGE_STRING "\n\n"
144 "Copyright (C) 2003 Enrico Scholz\n"
145 VERSION_COPYRIGHT_DISCLAIMER);
150 fmtHex(char *ptr, vc_limit_t lim)
152 memcpy(ptr, "0x", 2);
153 return utilvserver_fmt_xuint64(ptr+2, lim) + 2;
156 static bool do_resolve = true;
157 static size_t (*fmt_func)(char *, vc_limit_t) = fmtHex;
160 appendLimit(char *ptr, bool do_it, vc_limit_t lim)
165 if (lim==VC_LIM_INFINITY) {
170 ptr += (*fmt_func)(ptr, lim);
175 memcpy(ptr, "N/A", 3);
185 struct vc_rlimit_mask mask;
188 if (vc_get_rlimit_mask(ctx, &mask)==-1) {
189 perror("vc_get_rlimit_mask()");
190 exit(wrapper_exit_code);
193 for (i=0; i<32; ++i) {
194 uint32_t bitmask = (1<<i);
195 struct vc_rlimit limit;
196 char buf[128], *ptr=buf;
198 if (((mask.min|mask.soft|mask.hard) & bitmask)==0) continue;
199 if (vc_get_rlimit(ctx, i, &limit)==-1) {
200 perror("vc_get_rlimit()");
204 memset(buf, ' ', sizeof buf);
205 if (do_resolve && i<DIM_OF(LIMIT_STR)) {
206 size_t l = strlen(LIMIT_STR[i]);
207 memcpy(ptr, LIMIT_STR[i], l);
211 ptr += utilvserver_fmt_uint(ptr, i);
215 ptr = appendLimit(buf+10, mask.min &bitmask, limit.min);
216 ptr = appendLimit(buf+30, mask.soft&bitmask, limit.soft);
217 ptr = appendLimit(buf+50, mask.hard&bitmask, limit.hard);
220 Vwrite(1, buf, ptr-buf);
225 setLimits(int ctx, struct vc_rlimit const limits[], uint32_t mask)
228 for (i=0; i<32; ++i) {
229 if ((mask & (1<<i))==0) continue;
230 if (vc_set_rlimit(ctx, i, limits+i)) {
231 perror("vc_set_rlimit()");
237 readValue(int fd, char const *filename)
240 size_t len = Eread(fd, buf, sizeof(buf)-1);
245 if (!vc_parseLimit(buf, &res)) {
246 WRITE_MSG(2, "Invalid limit in '");
247 WRITE_STR(2, filename);
249 exit(wrapper_exit_code);
256 readFile(char const *file, char *base, char const *suffix,
261 strcpy(base, suffix);
262 fd = open(file, O_RDONLY);
264 *limit = readValue(fd, file);
272 readFromDir(struct vc_rlimit limits[32], uint_least32_t *mask,
273 char const *pathname, bool missing_ok)
277 size_t l_pathname = strlen(pathname);
278 char buf[l_pathname + sizeof("/memlock.hard") + 32];
280 if (stat(pathname, &st)==-1) {
281 if (errno==ENOENT && missing_ok) return;
282 PERROR_Q("vlimit: fstat", pathname);
283 exit(wrapper_exit_code);
286 memcpy(buf, pathname, l_pathname);
287 if (l_pathname>0 && pathname[l_pathname-1]!='/')
288 buf[l_pathname++] = '/';
290 for (i=0; i<DIM_OF(LIMIT_STR); ++i) {
292 char * ptr = buf+l_pathname;
294 // ignore unimplemented limits
295 if (LIMIT_STR[i]==0) continue;
297 // ignore limits set on cli already
298 if (*mask & (1<<i)) continue;
300 l_res = strlen(LIMIT_STR[i]);
301 memcpy(ptr, LIMIT_STR[i], l_res+1);
303 *ptr = tolower(*ptr);
307 if (readFile(buf, ptr, "", &limits[i].min)) {
308 limits[i].soft = limits[i].hard = limits[i].min;
312 if (readFile(buf, ptr, ".min", &limits[i].min))
315 if (readFile(buf, ptr, ".soft", &limits[i].soft))
318 if (readFile(buf, ptr, ".hard", &limits[i].hard))
323 int main (int argc, char *argv[])
325 // overall used limits
326 uint32_t lim_mask = 0;
328 struct vc_rlimit limits[32];
329 bool show_all = false;
330 xid_t ctx = VC_NOCTX;
331 char const * dir = 0;
332 bool missing_ok = false;
336 for (i=0; i<32; ++i) {
337 limits[i].min = VC_LIM_KEEP;
338 limits[i].soft = VC_LIM_KEEP;
339 limits[i].hard = VC_LIM_KEEP;
344 int c = getopt_long(argc, argv, "+MSHndac:", CMDLINE_OPTIONS, 0);
347 if (2048<=c && c<2048+32) {
351 if (!vc_parseLimit(optarg, &val)) {
352 WRITE_MSG(2, "Can not parse limit '");
353 WRITE_STR(2, optarg);
355 exit(wrapper_exit_code);
358 if (set_mask==0) set_mask=4;
360 if (set_mask & 1) limits[id].min = val;
361 if (set_mask & 2) limits[id].soft = val;
362 if (set_mask & 4) limits[id].hard = val;
368 case CMD_HELP : showHelp(1, argv[0], 0);
369 case CMD_VERSION : showVersion();
370 case 'a' : show_all = true; break;
371 case 'n' : do_resolve = false; break;
372 case CMD_DIR : dir = optarg; break;
373 case CMD_MISSINGOK: missing_ok = true; break;
374 case CMD_XID : /*@fallthrough@*/
375 case 'c' : ctx = Evc_xidopt2xid(optarg,true); break;
376 case 'd' : fmt_func = utilvserver_fmt_uint64; break;
381 case 'M' : set_mask |= 1; break;
382 case 'S' : set_mask |= 2; break;
383 case 'H' : set_mask |= 4; break;
384 default : assert(false);
389 WRITE_MSG(2, "Try '");
390 WRITE_STR(2, argv[0]);
391 WRITE_MSG(2, " --help\" for more information.\n");
392 exit(wrapper_exit_code) ;
398 ctx = Evc_get_task_xid(0);
401 readFromDir(limits, &lim_mask, dir, missing_ok);
403 setLimits(ctx, limits, lim_mask);
404 if (show_all) showAll(ctx);
407 EexecvpD(argv[optind], argv+optind);