Fixed vlimit. This program lets us set various per-vserver limits. In
[util-vserver.git] / src / vlimit.c
1 // $Id: vlimit.c,v 1.1.2.3 2004/02/20 19:35:50 ensc Exp $
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 "vserver-internal.h"
33
34 #include <getopt.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <assert.h>
38 #include <stdbool.h>
39 #include <stdio.h>
40
41 #define VERSION_COPYRIGHT_DISCLAIMER
42
43 inline static void UNUSED
44 writeStr(int fd, char const *cmd)
45 {
46   (void)write(fd, cmd, strlen(cmd));
47 }
48
49 #define WRITE_MSG(FD,X)         (void)(write(FD,X,sizeof(X)-1))
50 #define WRITE_STR(FD,X)         writeStr(FD,X)
51
52 #define NUMLIM(X) \
53 { #X, required_argument, 0, 2048|X }
54
55 static struct option const
56 CMDLINE_OPTIONS[] = {
57   { "help",     no_argument,  0, 'h' },
58   { "version",  no_argument,  0, 'v' },
59   { "all",      no_argument,  0, 'a' },
60   NUMLIM( 0), NUMLIM( 1), NUMLIM( 2), NUMLIM( 3),
61   NUMLIM( 4), NUMLIM( 5), NUMLIM( 6), NUMLIM( 7),
62   NUMLIM( 8), NUMLIM( 9), NUMLIM(10), NUMLIM(11),
63   NUMLIM(12), NUMLIM(13), NUMLIM(14), NUMLIM(15),
64   NUMLIM(16), NUMLIM(17), NUMLIM(18), NUMLIM(19),
65   NUMLIM(20), NUMLIM(21), NUMLIM(22), NUMLIM(23),
66   NUMLIM(24), NUMLIM(25), NUMLIM(26), NUMLIM(27),
67   NUMLIM(28), NUMLIM(29), NUMLIM(30), NUMLIM(31),
68   { 0,0,0,0 }
69 };
70
71 static void
72 showHelp(int fd, char const *cmd, int res)
73 {
74   WRITE_MSG(fd, "Usage:  ");
75   WRITE_STR(fd, cmd);
76   WRITE_MSG(fd,
77             " -c <xid> [-a|--all] [-MSH  --<nr> <value>]*\n"
78             "Please report bugs to " PACKAGE_BUGREPORT "\n");
79   exit(res);
80 }
81
82 static void
83 showVersion()
84 {
85   WRITE_MSG(1,
86             "vlimit " VERSION " -- limits context-resources\n"
87             "This program is part of " PACKAGE_STRING "\n\n"
88             "Copyright (C) 2003 Enrico Scholz\n"
89             VERSION_COPYRIGHT_DISCLAIMER);
90   exit(0);
91 }
92
93 static void *
94 appendLimit(char *ptr, bool do_it, vc_limit_t lim)
95 {
96   memcpy(ptr, "  ", 2);
97   ptr += 2;
98   if (do_it) {
99     if (lim==VC_LIM_INFINITY) {
100       strcpy(ptr, "INF");
101       ptr += 3;
102     }
103     else {
104       memcpy(ptr, "0x", 2);
105       ptr += 2;
106
107       ptr += utilvserver_uint2str(ptr, 20, (lim>>32),      16);
108       ptr += utilvserver_uint2str(ptr, 20, lim&0xffffffff, 16);
109       *ptr = ' ';
110     }
111   }
112   else {
113     memcpy(ptr, "N/A", 3);
114     ptr += 3;
115   }
116
117   return ptr;
118 }
119
120 static void
121 showAll(int ctx)
122 {
123   struct vc_rlimit_mask mask;
124   size_t                i;
125
126   if (vc_get_rlimit_mask(ctx, &mask)==-1) {
127     perror("vc_get_rlimit_mask()");
128     exit(1);
129   }
130
131   for (i=0; i<32; ++i) {
132     uint32_t            bitmask = (1<<i);
133     struct vc_rlimit    limit;
134     char                buf[100], *ptr=buf;
135     
136     if (((mask.min|mask.soft|mask.hard) & bitmask)==0) continue;
137     if (vc_get_rlimit(ctx, i, &limit)==-1) {
138       perror("vc_get_rlimit()");
139       //continue;
140     }
141
142     memset(buf, ' ', sizeof buf);
143     ptr += utilvserver_uint2str(ptr, 100, i, 10);
144     *ptr = ' ';
145
146     ptr  = appendLimit(buf+10, mask.min &bitmask, limit.min);
147     ptr  = appendLimit(buf+30, mask.soft&bitmask, limit.soft);
148     ptr  = appendLimit(buf+50, mask.hard&bitmask, limit.hard);
149
150     *ptr++ = '\n';
151     write(1, buf, ptr-buf);
152  }
153 }
154
155 static void
156   setLimits(int ctx, struct vc_rlimit const limits[], uint32_t mask)
157 {
158   size_t                i;
159   for (i=0; i<32; ++i) {
160     if ((mask & (1<<i))==0) continue;
161     if (vc_set_rlimit(ctx, i, limits+i)) {
162       perror("vc_set_rlimit()");
163     }
164   }
165 }
166
167 int main (int argc, char *argv[])
168 {
169   // overall used limits
170   uint32_t              lim_mask = 0;
171   int                   set_mask = 0;
172   struct vc_rlimit      limits[32];
173   bool                  show_all = false;
174   xid_t                 ctx      = VC_NOCTX;
175
176   {
177     size_t              i;
178     for (i=0; i<32; ++i) {
179       limits[i].min  = VC_LIM_KEEP;
180       limits[i].soft = VC_LIM_KEEP;
181       limits[i].hard = VC_LIM_KEEP;
182     }
183   }
184   
185   while (1) {
186     int         c = getopt_long(argc, argv, "MSHhvac:", CMDLINE_OPTIONS, 0);
187     if (c==-1) break;
188
189     if (2048<=c && c<2048+32) {
190       int               id  = c-2048;
191       vc_limit_t        val;
192       
193       if (strcmp(optarg, "inf")==0) val = VC_LIM_INFINITY;
194       else                          val = atoll(optarg);
195
196       if (set_mask & 1) limits[id].min  = val;
197       if (set_mask & 2) limits[id].soft = val;
198       if (set_mask & 4) limits[id].hard = val;
199
200       lim_mask |= (1<<id);
201       set_mask  = 0;
202     }
203     else switch (c) {
204       case 'h'          :  showHelp(1, argv[0], 0);
205       case 'v'          :  showVersion();
206       case 'c'          :  ctx      = atoi(optarg); break;
207       case 'a'          :  show_all = true;         break;
208       case 'M'          :
209       case 'S'          :
210       case 'H'          :
211         switch (c) {
212           case 'M'      :  set_mask |= 1; break;
213           case 'S'      :  set_mask |= 2; break;
214           case 'H'      :  set_mask |= 4; break;
215           default       :  assert(false);
216         }
217         break;
218         
219       default           :
220         WRITE_MSG(2, "Try '");
221         WRITE_STR(2, argv[0]);
222         WRITE_MSG(2, " --help\" for more information.\n");
223         return EXIT_FAILURE;
224         break;
225     }
226   }
227
228   if (ctx==VC_NOCTX) {
229     WRITE_MSG(2, "No context specified; try '--help' for more information\n");
230     return EXIT_FAILURE;
231   }
232
233   setLimits(ctx, limits, lim_mask);
234   if (show_all) showAll(ctx);
235
236   return EXIT_SUCCESS;
237 }