util-vserver-0.30.208
[util-vserver.git] / src / vdlimit.c
index beea0c5..4e5b09e 100644 (file)
+// $Id: vdlimit.c,v 1.2 2005/03/24 12:44:17 ensc Exp $    --*- c -*--
+
+// Copyright (C) 2005 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-/*
-** (c) 2004 Herbert Poetzl
-**
-** V0.01       ioctls so far
-**
-*/
 
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
-#include "compat.h"
 
-#include <stdio.h>
-#include <stdlib.h>
+#include "util.h"
+#include <lib_internal/sys_clone.h>
+#include <lib/internal.h>
+
+#include <vserver.h>
+
+#include <getopt.h>
+#include <libgen.h>
 #include <errno.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdint.h>
-
-#include "vserver.h"
-#include "vserver-internal.h"
-#include "dlimit.h"
-#ifdef O_LARGEFILE
-#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE)
-#else
-#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK)
-#endif
+#include <signal.h>
+#include <sched.h>
 
-static char    err_flag = 0;
+#define ENSC_WRAPPERS_PREFIX   "vdlimit: "
+#define ENSC_WRAPPERS_UNISTD   1
+#define ENSC_WRAPPERS_VSERVER  1
+#include <wrappers.h>
 
-static char    opt_xid = 0;
-static char    opt_flag = 0;
-static char    opt_vers = 0;
-static char    opt_add = 0;
-static char    opt_rem = 0;
-static char    opt_set = 0;
+#define CMD_HELP               0x1000
+#define CMD_VERSION            0x1001
 
-static char *  cmd_name = NULL;
-static char *  set_arg = NULL;
+int            wrapper_exit_code  =  1;
 
-static int     num_xid = 0;
-static int     num_flag = 0;
+struct option const
+CMDLINE_OPTIONS[] = {
+  { "help",       no_argument,       0, CMD_HELP },
+  { "version",    no_argument,       0, CMD_VERSION },
+  { "xid",        required_argument, 0, 'x' },
+  { "set",        required_argument, 0, 's' },
+  { "remove",     no_argument,       0, 'd' },
+  { "flags",      required_argument, 0, 'f' },
+  {0,0,0,0}
+};
 
+static void
+showHelp(int fd, char const *cmd)
+{
+  WRITE_MSG(fd, "Usage: ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " --xid <xid> [--flags <flags>] (--set <limit>=<value>|--remove) <mount point>\n"
+           "\n"
+           "    --set|-s <limit>=<value>  ...  set <limit> to <value>, where limit is \n"
+           "                           one of: space_used, space_total, inodes_used,\n"
+           "                           inodes_total, reserved\n"
+           "    --remove|-d       ...  removes the disk limit for <xid> from <mount point>\n"
+           "\n"
+           "Please report bugs to " PACKAGE_BUGREPORT "\n");
 
+  exit(0);
+}
 
+static void
+showVersion()
+{
+  WRITE_MSG(1,
+           "vdlimit " VERSION " -- manages disk limits\n"
+           "This program is part of " PACKAGE_STRING "\n\n"
+           "Copyright (C) 2005 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
+}
 
-#define OPTIONS "+hadf:x:S:V"
+static void
+setDlimit(char const *filename, xid_t xid, uint32_t flags, struct vc_ctx_dlimit const *limit)
+{
+  if (vc_get_dlimit(filename, xid, flags, 0) == -1) {
+    if (vc_add_dlimit(filename, xid, flags) == -1) {
+      perror(ENSC_WRAPPERS_PREFIX "vc_add_dlimit()");
+      exit(wrapper_exit_code);
+    }
+  }
+  if (vc_set_dlimit(filename, xid, flags, limit) == -1) {
+    perror(ENSC_WRAPPERS_PREFIX "vc_set_dlimit()");
+    exit(wrapper_exit_code);
+  }
+}
 
-int    main(int argc, char *argv[])
+static void
+remDlimit(char const *filename, xid_t xid, uint32_t flags)
 {
-        extern int optind;
-        extern char *optarg;
-        char c, errflg = 0;
-       int r;
-
-
-        cmd_name = argv[0];
-        while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
-            switch (c) {
-            case 'h':
-                fprintf(stderr,
-                    "This is %s " VERSION "\n"
-                    "options are:\n"
-                    "-h        print this help message\n"
-                    "-a        add dlimit entry\n"
-                    "-d        delete dlimit entry\n"
-                    "-f <num>  flag value in decimal\n"
-                    "-x <num>  context id\n"
-                    "-S <vals> current/limit values\n"
-                    "-V        verify interface version\n"
-                    "--        end of options\n"
-                    ,cmd_name);
-                exit(0);
-                break;
-            case 'a':
-                opt_add = 1;
-                break;
-            case 'd':
-                opt_rem = 1;
-                break;
-            case 'f':
-                num_flag = atol(optarg);
-                opt_flag = 1;
-                break;
-            case 'x':
-                num_xid = atol(optarg);
-                opt_xid = 1;
-                break;
-            case 'S':
-                set_arg = optarg;
-                opt_set = 1;
-                break;
-            case 'V':
-                opt_vers = 1;
-                break;
-            case '?':
-            default:
-                errflg++;
-                break;
-            }
-        }
-        if (errflg) {
-            fprintf(stderr, 
-                "Usage: %s -[" OPTIONS "] <path> ...\n"
-                "%s -h for help.\n",
-                cmd_name, cmd_name);
-            exit(2);
-        }
-
-       if (opt_vers) {
-           r = vc_get_version();
-           if (r<0)
-               perror("vc_get_version");
-           else 
-               printf("version: %04x:%04x\n", 
-                   (r>>16)&0xFFFF, r&0xFFFF);
-       }
+  if (vc_rem_dlimit(filename, xid, flags) == -1) {
+    perror(ENSC_WRAPPERS_PREFIX "vc_rem_dlimit()");
+    exit(wrapper_exit_code);
+  }
+}
 
-        for (; optind < argc; optind++) {
-           struct vcmd_ctx_dlimit_base_v0 init;
-           struct vcmd_ctx_dlimit_v0 data;
-
-           init.name = argv[optind];
-           init.flags = num_flag;
-
-           if (opt_rem) {
-               r = vserver(VCMD_rem_dlimit, num_xid, &init);
-               if (r<0)
-                   perror("vc_rem_dlimit");
-           } 
-           if (opt_add) {
-               r = vserver(VCMD_add_dlimit, num_xid, &init);
-               if (r<0)
-                   perror("vc_add_dlimit");
-           }
-                   
-           memset(&data, 0, sizeof(data));
-           data.name = argv[optind];
-           data.flags = num_flag;
-
-           if (opt_set) {
-               sscanf(set_arg, "%u,%u,%u,%u,%u",
-                   &data.space_used, &data.space_total,
-                   &data.inodes_used, &data.inodes_total,
-                   &data.reserved);
-
-               r = vserver(VCMD_set_dlimit, num_xid, &data);
-               if (r<0)
-                   perror("vc_set_dlimit");
-           }
-
-           memset(&data, 0, sizeof(data));
-           data.name = argv[optind];
-           data.flags = num_flag;
-
-           r = vserver(VCMD_get_dlimit, num_xid, &data);
-           if (r<0)
-               perror("vc_get_dlimit");
-
-           printf("%s: %u,%u,%u,%u,%u\n", argv[optind],
-               data.space_used, data.space_total,
-               data.inodes_used, data.inodes_total,
-               data.reserved);
-       }
-       
-       exit((err_flag)?1:0);
+static void
+writeInt(int fd, char const *prefix, int val)
+{
+  char         buf[sizeof(val)*3 + 2];
+  size_t       len = utilvserver_fmt_int(buf, val);
+
+  if (prefix)
+    WRITE_STR(fd, prefix);
+  Vwrite(fd, buf, len);
+}
+
+static void
+printDlimit(char const *filename, xid_t xid, uint32_t flags, bool formatted)
+{
+  struct vc_ctx_dlimit         limit;
+  
+  if (vc_get_dlimit(filename, xid, flags, &limit) == -1) {
+    perror(ENSC_WRAPPERS_PREFIX "vc_get_dlimit()");
+    exit(wrapper_exit_code);
+  }
+
+  if (formatted) {
+    writeInt (1, 0, xid);
+    WRITE_MSG(1, " ");
+    WRITE_STR(1, filename);
+    writeInt (1, "\nspace_used=",   limit.space_used);
+    writeInt (1, "\nspace_total=",  limit.space_total);
+    writeInt (1, "\ninodes_used=",  limit.inodes_used);
+    writeInt (1, "\ninodes_total=", limit.inodes_total);
+    writeInt (1, "\nreserved=",     limit.reserved);
+    WRITE_MSG(1, "\n");
+  }
+  else {
+    writeInt (1, 0,   xid);
+    writeInt (1, " ", limit.space_used);
+    writeInt (1, " ", limit.space_total);
+    writeInt (1, " ", limit.inodes_used);
+    writeInt (1, " ", limit.inodes_total);
+    writeInt (1, " ", limit.reserved);
+    WRITE_MSG(1, " ");
+    WRITE_STR(1, filename);
+    WRITE_MSG(1, "\n");
+  }
 }
 
+
+static bool
+setDLimitField(struct vc_ctx_dlimit *dst, char const *opt)
+{
+  uint_least32_t       *ptr;
+  char const * const   orig_opt = opt;
+
+#define GET_VAL_PTR(CMP, VAL)                                          \
+  (strncmp(opt, CMP "=", sizeof(CMP))==0) ?                            \
+  (opt+=sizeof(CMP), &VAL) : 0
+  
+  if      ((ptr=GET_VAL_PTR("space_used",   dst->space_used))!=0)   {}
+  else if ((ptr=GET_VAL_PTR("space_total",  dst->space_total))!=0)  {}
+  else if ((ptr=GET_VAL_PTR("inodes_used",  dst->inodes_used))!=0)  {}
+  else if ((ptr=GET_VAL_PTR("inodes_total", dst->inodes_total))!=0) {}
+  else if ((ptr=GET_VAL_PTR("reserved",     dst->reserved))!=0)     {}
+  else      ptr=0;
+
+#undef  GET_VAL_PTR  
+
+  if (ptr!=0 && *ptr==VC_CDLIM_KEEP) {
+    char       *endptr;
+    long       val = strtol(opt, &endptr, 0);
+
+    if (*opt==0 || *endptr!='\0') {
+      WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "can not parse number in '");
+      WRITE_STR(2, orig_opt);
+      WRITE_MSG(2, "'\n");
+      return false;
+    }
+
+    *ptr = val;
+  }
+  else if (ptr!=0) {
+    WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "value already set in '");
+    WRITE_STR(2, orig_opt);
+    WRITE_MSG(2, "'\n");
+    return false;
+  }
+  else {
+    WRITE_MSG(2, ENSC_WRAPPERS_PREFIX "unknown limit in '");
+    WRITE_STR(2, orig_opt);
+    WRITE_MSG(2, "'\n");
+    return false;
+  }
+
+  return true;
+}
+
+int main(int argc, char *argv[])
+{
+  bool         do_set       = false;
+  bool         do_remove    = false;
+  xid_t                xid          = VC_NOCTX;
+  uint32_t     flags        = 0;
+  char         *endptr;
+  int          sum          = 0;
+
+  struct vc_ctx_dlimit         limit = {
+    .space_used   = VC_CDLIM_KEEP,
+    .space_total  = VC_CDLIM_KEEP,
+    .inodes_used  = VC_CDLIM_KEEP,
+    .inodes_total = VC_CDLIM_KEEP,
+    .reserved     = VC_CDLIM_KEEP
+  };
+  
+  while (1) {
+    int                c = getopt_long(argc, argv, "+x:s:df:", CMDLINE_OPTIONS, 0);
+    if (c==-1) break;
+
+    switch (c) {
+      case CMD_HELP    :  showHelp(1, argv[0]);
+      case CMD_VERSION :  showVersion();
+      case 'x'         :  xid = Evc_xidopt2xid(optarg, true); break;
+      case 's'         :
+       if (!setDLimitField(&limit, optarg))
+         return EXIT_FAILURE;
+       else
+         do_set = true;
+       break;
+      case 'd'         :  do_remove = true; break;
+      case 'f'         :
+       {
+         flags = strtol(optarg, &endptr, 0);
+         if ((flags == 0 && errno != 0) || *endptr != '\0') {
+           WRITE_MSG(2, "Invalid flags argument: '");
+           WRITE_STR(2, optarg);
+           WRITE_MSG(2, "'; try '--help' for more information\n");
+           return EXIT_FAILURE;
+         }
+       }
+       break;
+
+      default          :
+       WRITE_MSG(2, "Try '");
+       WRITE_STR(2, argv[0]);
+       WRITE_MSG(2, " --help' for more information.\n");
+       return EXIT_FAILURE;
+       break;
+    }
+  }
+
+  sum = ((do_set ? 1 : 0) + (do_remove ? 1 : 0));
+  
+  if (sum>1)
+    WRITE_MSG(2, "Can not specify multiple operations; try '--help' for more information\n");
+  else if (optind==argc)
+    WRITE_MSG(2, "No mount point specified; try '--help' for more information\n");
+  else if (xid==VC_NOCTX)
+    WRITE_MSG(2, "No xid specified; try '--help' for more information\n");
+  else {
+    for (; optind < argc; ++optind) {
+      if      (do_set)     setDlimit(argv[optind], xid, flags, &limit);
+      else if (do_remove)  remDlimit(argv[optind], xid, flags);
+      else                 printDlimit(argv[optind], xid, flags, true);
+    }
+
+    return EXIT_SUCCESS;
+  }
+
+  return EXIT_FAILURE;
+}