vdlimit.c (8240B)
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 }