Evc_create_context(), Evc_migrate_context(): added
[util-vserver.git] / util-vserver / src / vlimit.c
1 // $Id$
2
3 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
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)
8 // any later version.
9 //  
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.
14 //  
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.
18
19 /*
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
22         one.
23
24         It uses the same options as ulimit, when possible
25 */
26 #ifdef HAVE_CONFIG_H
27 #  include <config.h>
28 #endif
29 #include "compat.h"
30
31 #include "vserver.h"
32 #include "internal.h"
33 #include "util.h"
34
35 #include <getopt.h>
36 #include <string.h>
37 #include <unistd.h>
38 #include <assert.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <libgen.h>
43 #include <sys/resource.h>
44
45 #define NUMLIM(X) \
46 { #X, required_argument, 0, 2048|X }
47 #define RESLIM(RES,V) \
48   { #RES, required_argument, 0, 2048|RLIMIT_##V }
49
50 static struct option const
51 CMDLINE_OPTIONS[] = {
52   { "help",     no_argument,  0, 'h' },
53   { "version",  no_argument,  0, 'v' },
54   { "all",      no_argument,  0, 'a' },
55   NUMLIM( 0), NUMLIM( 1), NUMLIM( 2), NUMLIM( 3),
56   NUMLIM( 4), NUMLIM( 5), NUMLIM( 6), NUMLIM( 7),
57   NUMLIM( 8), NUMLIM( 9), NUMLIM(10), NUMLIM(11),
58   NUMLIM(12), NUMLIM(13), NUMLIM(14), NUMLIM(15),
59   NUMLIM(16), NUMLIM(17), NUMLIM(18), NUMLIM(19),
60   NUMLIM(20), NUMLIM(21), NUMLIM(22), NUMLIM(23),
61   NUMLIM(24), NUMLIM(25), NUMLIM(26), NUMLIM(27),
62   NUMLIM(28), NUMLIM(29), NUMLIM(30), NUMLIM(31),
63   RESLIM(cpu,     CPU),
64   RESLIM(fsize,   FSIZE),
65   RESLIM(data,    DATA),
66   RESLIM(stack,   STACK),
67   RESLIM(core,    CORE),
68   RESLIM(rss,     RSS),
69   RESLIM(nproc,   NPROC),
70   RESLIM(nofile,  NOFILE),
71   RESLIM(memlock, MEMLOCK),
72   RESLIM(as,      AS),
73   RESLIM(locks,   LOCKS),
74   { 0,0,0,0 }
75 };
76
77 #define REV_RESLIM(X)   [RLIMIT_##X] = #X
78 static char const * const LIMIT_STR[] = {
79   REV_RESLIM(CPU),     REV_RESLIM(FSIZE), REV_RESLIM(DATA),  REV_RESLIM(STACK),
80   REV_RESLIM(CORE),    REV_RESLIM(RSS),   REV_RESLIM(NPROC), REV_RESLIM(NOFILE),
81   REV_RESLIM(MEMLOCK), REV_RESLIM(AS),    REV_RESLIM(LOCKS)
82 };
83
84 static void
85 showHelp(int fd, char const *cmd, int res)
86 {
87   VSERVER_DECLARE_CMD(cmd);
88   
89   WRITE_MSG(fd, "Usage:  ");
90   WRITE_STR(fd, cmd);
91   WRITE_MSG(fd,
92             " -c <xid> [-nd] [-a|--all] [[-MSH] --(<resource>|<nr>) <value>]*\n\n"
93             "Options:\n"
94             "    -c <xid>    ...  operate on context <xid>\n"
95             "    -a|--all    ...  show all available limits\n"
96             "    -n          ...  do not resolve limit-names\n"
97             "    -d          ...  show limits in decimal\n"
98             "    -M          ...  set Minimum limit\n"
99             "    -S          ...  set Soft limit\n"
100             "    -H          ...  set Hard limit (assumed by default, when neither\n"
101             "                     M nor S was requested)\n"
102             "    --<resource>|<nr> <value>\n"
103             "                ...  set specified (MSH) limit for <resource> to <value>\n\n"
104             "Valid values for resource are cpu, fsize, data, stack, core, rss, nproc,\n"
105             "nofile, memlock, as and locks.\n\n"
106             "Please report bugs to " PACKAGE_BUGREPORT "\n");
107   exit(res);
108 }
109
110 static void
111 showVersion()
112 {
113   WRITE_MSG(1,
114             "vlimit " VERSION " -- limits context-resources\n"
115             "This program is part of " PACKAGE_STRING "\n\n"
116             "Copyright (C) 2003 Enrico Scholz\n"
117             VERSION_COPYRIGHT_DISCLAIMER);
118   exit(0);
119 }
120
121 static size_t
122 fmtHex(char *ptr, vc_limit_t lim)
123 {
124   memcpy(ptr, "0x", 2);
125   return utilvserver_fmt_xuint64(ptr+2, lim) + 2;
126 }
127
128 static bool             do_resolve = true;
129 static size_t           (*fmt_func)(char *, vc_limit_t) = fmtHex;
130
131 static void *
132 appendLimit(char *ptr, bool do_it, vc_limit_t lim)
133 {
134   memcpy(ptr, "  ", 2);
135   ptr += 2;
136   if (do_it) {
137     if (lim==VC_LIM_INFINITY) {
138       strcpy(ptr, "INF");
139       ptr += 3;
140     }
141     else {
142       ptr += (*fmt_func)(ptr, lim);
143       *ptr = ' ';
144     }
145   }
146   else {
147     memcpy(ptr, "N/A", 3);
148     ptr += 3;
149   }
150
151   return ptr;
152 }
153
154 static void
155 showAll(int ctx)
156 {
157   struct vc_rlimit_mask mask;
158   size_t                i;
159
160   if (vc_get_rlimit_mask(ctx, &mask)==-1) {
161     perror("vc_get_rlimit_mask()");
162     exit(1);
163   }
164
165   for (i=0; i<32; ++i) {
166     uint32_t            bitmask = (1<<i);
167     struct vc_rlimit    limit;
168     char                buf[128], *ptr=buf;
169
170     if (((mask.min|mask.soft|mask.hard) & bitmask)==0) continue;
171     if (vc_get_rlimit(ctx, i, &limit)==-1) {
172       perror("vc_get_rlimit()");
173       //continue;
174     }
175
176     memset(buf, ' ', sizeof buf);
177     if (do_resolve && i<DIM_OF(LIMIT_STR)) {
178       size_t            l = strlen(LIMIT_STR[i]);
179       memcpy(ptr, LIMIT_STR[i], l);
180       ptr += l;
181     }
182     else {
183       ptr += utilvserver_fmt_uint(ptr, i);
184       *ptr = ' ';
185     }
186
187     ptr  = appendLimit(buf+10, mask.min &bitmask, limit.min);
188     ptr  = appendLimit(buf+30, mask.soft&bitmask, limit.soft);
189     ptr  = appendLimit(buf+50, mask.hard&bitmask, limit.hard);
190
191     *ptr++ = '\n';
192     write(1, buf, ptr-buf);
193   }
194 }
195
196 static void
197 setLimits(int ctx, struct vc_rlimit const limits[], uint32_t mask)
198 {
199   size_t                i;
200   for (i=0; i<32; ++i) {
201     if ((mask & (1<<i))==0) continue;
202     if (vc_set_rlimit(ctx, i, limits+i)) {
203       perror("vc_set_rlimit()");
204     }
205   }
206 }
207
208 int main (int argc, char *argv[])
209 {
210   // overall used limits
211   uint32_t              lim_mask = 0;
212   int                   set_mask = 0;
213   struct vc_rlimit      limits[32];
214   bool                  show_all = false;
215   xid_t                 ctx      = VC_NOCTX;
216
217   {
218     size_t              i;
219     for (i=0; i<32; ++i) {
220       limits[i].min  = VC_LIM_KEEP;
221       limits[i].soft = VC_LIM_KEEP;
222       limits[i].hard = VC_LIM_KEEP;
223     }
224   }
225   
226   while (1) {
227     int         c = getopt_long(argc, argv, "MSHndhvac:", CMDLINE_OPTIONS, 0);
228     if (c==-1) break;
229
230     if (2048<=c && c<2048+32) {
231       int               id  = c-2048;
232       vc_limit_t        val;
233       
234       if (strcmp(optarg, "inf")==0) val = VC_LIM_INFINITY;
235       else                          val = atoll(optarg);
236
237       if (set_mask==0)  set_mask=4;
238       
239       if (set_mask & 1) limits[id].min  = val;
240       if (set_mask & 2) limits[id].soft = val;
241       if (set_mask & 4) limits[id].hard = val;
242
243       lim_mask |= (1<<id);
244       set_mask  = 0;
245     }
246     else switch (c) {
247       case 'h'          :  showHelp(1, argv[0], 0);
248       case 'v'          :  showVersion();
249       case 'c'          :  ctx        = atoi(optarg); break;
250       case 'a'          :  show_all   = true;         break;
251       case 'n'          :  do_resolve = false;        break;
252       case 'd'          :  fmt_func   = utilvserver_fmt_uint64; break;
253       case 'M'          :
254       case 'S'          :
255       case 'H'          :
256         switch (c) {
257           case 'M'      :  set_mask |= 1; break;
258           case 'S'      :  set_mask |= 2; break;
259           case 'H'      :  set_mask |= 4; break;
260           default       :  assert(false);
261         }
262         break;
263         
264       default           :
265         WRITE_MSG(2, "Try '");
266         WRITE_STR(2, argv[0]);
267         WRITE_MSG(2, " --help\" for more information.\n");
268         return EXIT_FAILURE;
269         break;
270     }
271   }
272
273   if (ctx==VC_NOCTX) {
274     WRITE_MSG(2, "No context specified; try '--help' for more information\n");
275     return EXIT_FAILURE;
276   }
277
278   setLimits(ctx, limits, lim_mask);
279   if (show_all) showAll(ctx);
280
281   return EXIT_SUCCESS;
282 }