gentoo: use /var/run for new /run compatibility
[util-vserver.git] / src / vdlimit.c
1 // $Id$    --*- 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.h>
25
26 #include <vserver.h>
27
28 #include <getopt.h>
29 #include <libgen.h>
30 #include <errno.h>
31 #include <signal.h>
32 #include <sched.h>
33
34 #define ENSC_WRAPPERS_PREFIX    "vdlimit: "
35 #define ENSC_WRAPPERS_UNISTD    1
36 #define ENSC_WRAPPERS_VSERVER   1
37 #include <wrappers.h>
38
39 #define CMD_HELP                0x1000
40 #define CMD_VERSION             0x1001
41
42 int             wrapper_exit_code  =  1;
43
44 struct option const
45 CMDLINE_OPTIONS[] = {
46   { "help",       no_argument,       0, CMD_HELP },
47   { "version",    no_argument,       0, CMD_VERSION },
48   { "xid",        required_argument, 0, 'x' },
49   { "set",        required_argument, 0, 's' },
50   { "remove",     no_argument,       0, 'd' },
51   { "flags",      required_argument, 0, 'f' },
52   {0,0,0,0}
53 };
54
55 static void
56 showHelp(int fd, char const *cmd)
57 {
58   WRITE_MSG(fd, "Usage: ");
59   WRITE_STR(fd, cmd);
60   WRITE_MSG(fd,
61             " --xid <xid> [--flags <flags>] (--set <limit>=<value>|--remove) <mount point>\n"
62             "\n"
63             "    --set|-s <limit>=<value>  ...  set <limit> to <value>, where limit is \n"
64             "                           one of: space_used, space_total, inodes_used,\n"
65             "                           inodes_total, reserved\n"
66             "    --remove|-d       ...  removes the disk limit for <xid> from <mount point>\n"
67             "\n"
68             "Please report bugs to " PACKAGE_BUGREPORT "\n");
69
70   exit(0);
71 }
72
73 static void
74 showVersion()
75 {
76   WRITE_MSG(1,
77             "vdlimit " VERSION " -- manages disk limits\n"
78             "This program is part of " PACKAGE_STRING "\n\n"
79             "Copyright (C) 2005 Enrico Scholz\n"
80             VERSION_COPYRIGHT_DISCLAIMER);
81   exit(0);
82 }
83
84 static void
85 setDlimit(char const *filename, xid_t xid, uint32_t flags, struct vc_ctx_dlimit const *limit)
86 {
87   bool          was_added = false;
88
89   if (vc_get_dlimit(filename, xid, flags, 0) == -1) {
90     if (vc_add_dlimit(filename, xid, flags) == -1) {
91       perror(ENSC_WRAPPERS_PREFIX "vc_add_dlimit()");
92       exit(wrapper_exit_code);
93     }
94
95     was_added = true;
96   }
97
98   if (vc_set_dlimit(filename, xid, flags, limit) == -1) {
99     perror(ENSC_WRAPPERS_PREFIX "vc_set_dlimit()");
100
101     if (was_added &&
102         vc_rem_dlimit(filename, xid, flags)==-1)
103       perror(ENSC_WRAPPERS_PREFIX "vc_rem_dlimit()");
104
105     exit(wrapper_exit_code);
106   }
107 }
108
109 static void
110 remDlimit(char const *filename, xid_t xid, uint32_t flags)
111 {
112   if (vc_rem_dlimit(filename, xid, flags) == -1) {
113     perror(ENSC_WRAPPERS_PREFIX "vc_rem_dlimit()");
114     exit(wrapper_exit_code);
115   }
116 }
117
118 static void
119 writeInt(int fd, char const *prefix, unsigned int val)
120 {
121   char          buf[sizeof(val)*3 + 2];
122   size_t        len = utilvserver_fmt_uint(buf, val);
123
124   if (prefix)
125     WRITE_STR(fd, prefix);
126   if (val == VC_CDLIM_INFINITY)
127     WRITE_STR(fd, "-1");
128   else
129     Vwrite(fd, buf, len);
130 }
131
132 static void
133 printDlimit(char const *filename, xid_t xid, uint32_t flags, bool formatted)
134 {
135   struct vc_ctx_dlimit          limit;
136   
137   if (vc_get_dlimit(filename, xid, flags, &limit) == -1) {
138     perror(ENSC_WRAPPERS_PREFIX "vc_get_dlimit()");
139     exit(wrapper_exit_code);
140   }
141
142   if (formatted) {
143     writeInt (1, 0, xid);
144     WRITE_MSG(1, " ");
145     WRITE_STR(1, filename);
146     writeInt (1, "\nspace_used=",   limit.space_used);
147     writeInt (1, "\nspace_total=",  limit.space_total);
148     writeInt (1, "\ninodes_used=",  limit.inodes_used);
149     writeInt (1, "\ninodes_total=", limit.inodes_total);
150     writeInt (1, "\nreserved=",     limit.reserved);
151     WRITE_MSG(1, "\n");
152   }
153   else {
154     writeInt (1, 0,   xid);
155     writeInt (1, " ", limit.space_used);
156     writeInt (1, " ", limit.space_total);
157     writeInt (1, " ", limit.inodes_used);
158     writeInt (1, " ", limit.inodes_total);
159     writeInt (1, " ", limit.reserved);
160     WRITE_MSG(1, " ");
161     WRITE_STR(1, filename);
162     WRITE_MSG(1, "\n");
163   }
164 }
165
166
167 static bool
168 setDLimitField(struct vc_ctx_dlimit *dst, char const *opt)
169 {
170   uint_least32_t        *ptr;
171   char const * const    orig_opt = opt;
172
173 #define GET_VAL_PTR(CMP, VAL)                                           \
174   (strncmp(opt, CMP "=", sizeof(CMP))==0) ?                             \
175   (opt+=sizeof(CMP), &VAL) : 0
176   
177   if      ((ptr=GET_VAL_PTR("space_used",   dst->space_used))!=0)   {}
178   else if ((ptr=GET_VAL_PTR("space_total",  dst->space_total))!=0)  {}
179   else if ((ptr=GET_VAL_PTR("inodes_used",  dst->inodes_used))!=0)  {}
180   else if ((ptr=GET_VAL_PTR("inodes_total", dst->inodes_total))!=0) {}
181   else if ((ptr=GET_VAL_PTR("reserved",     dst->reserved))!=0)     {}
182   else      ptr=0;
183
184 #undef  GET_VAL_PTR  
185
186   if (ptr!=0 && *ptr==VC_CDLIM_KEEP) {
187     char        *endptr;
188     long        val = strtol(opt, &endptr, 0);
189
190     if (*opt==0 || *endptr!='\0') {
191       WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not parse number in '");
192       WRITE_STR(2, orig_opt);
193       WRITE_MSG(2, "'\n");
194       return false;
195     }
196
197     *ptr = val;
198   }
199   else if (ptr!=0) {
200     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "value already set in '");
201     WRITE_STR(2, orig_opt);
202     WRITE_MSG(2, "'\n");
203     return false;
204   }
205   else {
206     WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unknown limit in '");
207     WRITE_STR(2, orig_opt);
208     WRITE_MSG(2, "'\n");
209     return false;
210   }
211
212   return true;
213 }
214
215 bool
216 isHigherLimit(uint_least32_t lhs, uint_least32_t rhs)
217 {
218   if (lhs==VC_CDLIM_KEEP || rhs==VC_CDLIM_KEEP) return false;
219
220   return lhs > rhs;
221 }
222
223 int main(int argc, char *argv[])
224 {
225   bool          do_set       = false;
226   bool          do_remove    = false;
227   xid_t         xid          = VC_NOCTX;
228   uint32_t      flags        = 0;
229   char          *endptr;
230   int           sum          = 0;
231
232   struct vc_ctx_dlimit          limit = {
233     .space_used   = VC_CDLIM_KEEP,
234     .space_total  = VC_CDLIM_KEEP,
235     .inodes_used  = VC_CDLIM_KEEP,
236     .inodes_total = VC_CDLIM_KEEP,
237     .reserved     = VC_CDLIM_KEEP
238   };
239   
240   while (1) {
241     int         c = getopt_long(argc, argv, "+x:s:df:", CMDLINE_OPTIONS, 0);
242     if (c==-1) break;
243
244     switch (c) {
245       case CMD_HELP     :  showHelp(1, argv[0]);
246       case CMD_VERSION  :  showVersion();
247       case 'x'          :  xid = Evc_xidopt2xid(optarg, true); break;
248       case 's'          :
249         if (!setDLimitField(&limit, optarg))
250           return EXIT_FAILURE;
251         else
252           do_set = true;
253         break;
254       case 'd'          :  do_remove = true; break;
255       case 'f'          :
256         {
257           flags = strtol(optarg, &endptr, 0);
258           if ((flags == 0 && errno != 0) || *endptr != '\0') {
259             WRITE_MSG(2, "Invalid flags argument: '");
260             WRITE_STR(2, optarg);
261             WRITE_MSG(2, "'; try '--help' for more information\n");
262             return EXIT_FAILURE;
263           }
264         }
265         break;
266
267       default           :
268         WRITE_MSG(2, "Try '");
269         WRITE_STR(2, argv[0]);
270         WRITE_MSG(2, " --help' for more information.\n");
271         return EXIT_FAILURE;
272         break;
273     }
274   }
275
276   sum = ((do_set ? 1 : 0) + (do_remove ? 1 : 0));
277   
278   if (sum>1)
279     WRITE_MSG(2, "Can not specify multiple operations; try '--help' for more information\n");
280   else if (optind==argc)
281     WRITE_MSG(2, "No mount point specified; try '--help' for more information\n");
282   else if (xid==VC_NOCTX)
283     WRITE_MSG(2, "No xid specified; try '--help' for more information\n");
284   else if (isHigherLimit(limit.space_used, limit.space_total))
285     WRITE_MSG(2, "invalid parameters: 'space_used' is larger than 'space_total'\n");
286   else if (isHigherLimit(limit.inodes_used, limit.inodes_total))
287     WRITE_MSG(2, "invalid parameters: 'inodes_used' is larger than 'inodes_total'\n");
288   else {
289     for (; optind < argc; ++optind) {
290       if      (do_set)     setDlimit(argv[optind], xid, flags, &limit);
291       else if (do_remove)  remDlimit(argv[optind], xid, flags);
292       else                 printDlimit(argv[optind], xid, flags, true);
293     }
294
295     return EXIT_SUCCESS;
296   }
297
298   return EXIT_FAILURE;
299 }