fc287e9619f5cd098c32b5d01b095124d898c2b9
[util-vserver.git] / src / vdlimit.c
1 // $Id: vdlimit.c,v 1.2 2005/08/21 22:16:22 mlhuang Exp $    --*- c -*--
2
3 // Copyright (C) 2005 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; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "util.h"
24 #include <lib_internal/sys_clone.h>
25 #include <lib/internal.h>
26
27 #include <vserver.h>
28
29 #include <getopt.h>
30 #include <libgen.h>
31 #include <errno.h>
32 #include <signal.h>
33 #include <sched.h>
34
35 #define ENSC_WRAPPERS_PREFIX    "vdlimit: "
36 #define ENSC_WRAPPERS_UNISTD    1
37 #define ENSC_WRAPPERS_VSERVER   1
38 #include <wrappers.h>
39
40 #define CMD_HELP                0x1000
41 #define CMD_VERSION             0x1001
42
43 int             wrapper_exit_code  =  1;
44
45 struct option const
46 CMDLINE_OPTIONS[] = {
47   { "help",       no_argument,       0, CMD_HELP },
48   { "version",    no_argument,       0, CMD_VERSION },
49   { "xid",        required_argument, 0, 'x' },
50   { "set",        required_argument, 0, 's' },
51   { "remove",     no_argument,       0, 'd' },
52   { "flags",      required_argument, 0, 'f' },
53   {0,0,0,0}
54 };
55
56 static void
57 showHelp(int fd, char const *cmd)
58 {
59   WRITE_MSG(fd, "Usage: ");
60   WRITE_STR(fd, cmd);
61   WRITE_MSG(fd,
62             " --xid <xid> [--flags <flags>] (--set <limit>=<value>|--remove) <mount point>\n"
63             "\n"
64             "    --set|-s <limit>=<value>  ...  set <limit> to <value>, where limit is \n"
65             "                           one of: space_used, space_total, inodes_used,\n"
66             "                           inodes_total, reserved\n"
67             "    --remove|-d       ...  removes the disk limit for <xid> from <mount point>\n"
68             "\n"
69             "Please report bugs to " PACKAGE_BUGREPORT "\n");
70
71   exit(0);
72 }
73
74 static void
75 showVersion()
76 {
77   WRITE_MSG(1,
78             "vdlimit " VERSION " -- manages disk limits\n"
79             "This program is part of " PACKAGE_STRING "\n\n"
80             "Copyright (C) 2005 Enrico Scholz\n"
81             VERSION_COPYRIGHT_DISCLAIMER);
82   exit(0);
83 }
84
85 static void
86 setDlimit(char const *filename, xid_t xid, uint32_t flags, struct vc_ctx_dlimit const *limit)
87 {
88   if (vc_get_dlimit(filename, xid, flags, 0) == -1) {
89     if (vc_add_dlimit(filename, xid, flags) == -1) {
90       perror(ENSC_WRAPPERS_PREFIX "vc_add_dlimit()");
91       exit(wrapper_exit_code);
92     }
93   }
94   if (vc_set_dlimit(filename, xid, flags, limit) == -1) {
95     perror(ENSC_WRAPPERS_PREFIX "vc_set_dlimit()");
96     exit(wrapper_exit_code);
97   }
98 }
99
100 static void
101 remDlimit(char const *filename, xid_t xid, uint32_t flags)
102 {
103   if (vc_rem_dlimit(filename, xid, flags) == -1) {
104     perror(ENSC_WRAPPERS_PREFIX "vc_rem_dlimit()");
105     exit(wrapper_exit_code);
106   }
107 }
108
109 static void
110 writeInt(int fd, char const *prefix, int val)
111 {
112   char          buf[sizeof(val)*3 + 2];
113   size_t        len = utilvserver_fmt_int(buf, val);
114
115   if (prefix)
116     WRITE_STR(fd, prefix);
117   Vwrite(fd, buf, len);
118 }
119
120 static void
121 printDlimit(char const *filename, xid_t xid, uint32_t flags, bool formatted)
122 {
123   struct vc_ctx_dlimit          limit;
124   
125   if (vc_get_dlimit(filename, xid, flags, &limit) == -1) {
126     perror(ENSC_WRAPPERS_PREFIX "vc_get_dlimit()");
127     exit(wrapper_exit_code);
128   }
129
130   if (formatted) {
131     writeInt (1, 0, xid);
132     WRITE_MSG(1, " ");
133     WRITE_STR(1, filename);
134     writeInt (1, "\nspace_used=",   limit.space_used);
135     writeInt (1, "\nspace_total=",  limit.space_total);
136     writeInt (1, "\ninodes_used=",  limit.inodes_used);
137     writeInt (1, "\ninodes_total=", limit.inodes_total);
138     writeInt (1, "\nreserved=",     limit.reserved);
139     WRITE_MSG(1, "\n");
140   }
141   else {
142     writeInt (1, 0,   xid);
143     writeInt (1, " ", limit.space_used);
144     writeInt (1, " ", limit.space_total);
145     writeInt (1, " ", limit.inodes_used);
146     writeInt (1, " ", limit.inodes_total);
147     writeInt (1, " ", limit.reserved);
148     WRITE_MSG(1, " ");
149     WRITE_STR(1, filename);
150     WRITE_MSG(1, "\n");
151   }
152 }
153
154
155 static bool
156 setDLimitField(struct vc_ctx_dlimit *dst, char const *opt)
157 {
158   uint_least32_t        *ptr;
159   char const * const    orig_opt = opt;
160
161 #define GET_VAL_PTR(CMP, VAL)                                           \
162   (strncmp(opt, CMP "=", sizeof(CMP))==0) ?                             \
163   (opt+=sizeof(CMP), &VAL) : 0
164   
165   if      ((ptr=GET_VAL_PTR("space_used",   dst->space_used))!=0)   {}
166   else if ((ptr=GET_VAL_PTR("space_total",  dst->space_total))!=0)  {}
167   else if ((ptr=GET_VAL_PTR("inodes_used",  dst->inodes_used))!=0)  {}
168   else if ((ptr=GET_VAL_PTR("inodes_total", dst->inodes_total))!=0) {}
169   else if ((ptr=GET_VAL_PTR("reserved",     dst->reserved))!=0)     {}
170   else      ptr=0;
171
172 #undef  GET_VAL_PTR  
173
174   if (ptr!=0 && *ptr==VC_CDLIM_KEEP) {
175     char        *endptr;
176     long        val = strtol(opt, &endptr, 0);
177
178     if (*opt==0 || *endptr!='\0') {
179       WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not parse number in '");
180       WRITE_STR(2, orig_opt);
181       WRITE_MSG(2, "'\n");
182       return false;
183     }
184
185     *ptr = val;
186   }
187   else if (ptr!=0) {
188     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "value already set in '");
189     WRITE_STR(2, orig_opt);
190     WRITE_MSG(2, "'\n");
191     return false;
192   }
193   else {
194     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unknown limit in '");
195     WRITE_STR(2, orig_opt);
196     WRITE_MSG(2, "'\n");
197     return false;
198   }
199
200   return true;
201 }
202
203 int main(int argc, char *argv[])
204 {
205   bool          do_set       = false;
206   bool          do_remove    = false;
207   xid_t         xid          = VC_NOCTX;
208   uint32_t      flags        = 0;
209   char          *endptr;
210   int           sum          = 0;
211
212   struct vc_ctx_dlimit          limit = {
213     .space_used   = VC_CDLIM_KEEP,
214     .space_total  = VC_CDLIM_KEEP,
215     .inodes_used  = VC_CDLIM_KEEP,
216     .inodes_total = VC_CDLIM_KEEP,
217     .reserved     = VC_CDLIM_KEEP
218   };
219   
220   while (1) {
221     int         c = getopt_long(argc, argv, "+x:s:df:", CMDLINE_OPTIONS, 0);
222     if (c==-1) break;
223
224     switch (c) {
225       case CMD_HELP     :  showHelp(1, argv[0]);
226       case CMD_VERSION  :  showVersion();
227       case 'x'          :  xid = Evc_xidopt2xid(optarg, true); break;
228       case 's'          :
229         if (!setDLimitField(&limit, optarg))
230           return EXIT_FAILURE;
231         else
232           do_set = true;
233         break;
234       case 'd'          :  do_remove = true; break;
235       case 'f'          :
236         {
237           flags = strtol(optarg, &endptr, 0);
238           if ((flags == 0 && errno != 0) || *endptr != '\0') {
239             WRITE_MSG(2, "Invalid flags argument: '");
240             WRITE_STR(2, optarg);
241             WRITE_MSG(2, "'; try '--help' for more information\n");
242             return EXIT_FAILURE;
243           }
244         }
245         break;
246
247       default           :
248         WRITE_MSG(2, "Try '");
249         WRITE_STR(2, argv[0]);
250         WRITE_MSG(2, " --help' for more information.\n");
251         return EXIT_FAILURE;
252         break;
253     }
254   }
255
256   sum = ((do_set ? 1 : 0) + (do_remove ? 1 : 0));
257   
258   if (sum>1)
259     WRITE_MSG(2, "Can not specify multiple operations; try '--help' for more information\n");
260   else if (optind==argc)
261     WRITE_MSG(2, "No mount point specified; try '--help' for more information\n");
262   else if (xid==VC_NOCTX)
263     WRITE_MSG(2, "No xid specified; try '--help' for more information\n");
264   else {
265     for (; optind < argc; ++optind) {
266       if      (do_set)     setDlimit(argv[optind], xid, flags, &limit);
267       else if (do_remove)  remDlimit(argv[optind], xid, flags);
268       else                 printDlimit(argv[optind], xid, flags, true);
269     }
270
271     return EXIT_SUCCESS;
272   }
273
274   return EXIT_FAILURE;
275 }