- sync to util-vserver-0.30.208
authorMark Huang <mlhuang@cs.princeton.edu>
Sun, 21 Aug 2005 22:21:04 +0000 (22:21 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Sun, 21 Aug 2005 22:21:04 +0000 (22:21 +0000)
- mef: please verify that this version of the tool works the same as the
  one that you backported

src/vdlimit.c
src/vlimit.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;
+}
index 6fd955b..158e166 100644 (file)
@@ -1,4 +1,4 @@
-// $Id: vlimit.c,v 1.1.2.3 2004/02/20 19:35:50 ensc Exp $
+// $Id: vlimit.c,v 1.20 2005/03/24 12:44:17 ensc Exp $
 
 // Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
 //  
@@ -29,7 +29,8 @@
 #include "compat.h"
 
 #include "vserver.h"
-#include "vserver-internal.h"
+#include "internal.h"
+#include "util.h"
 
 #include <getopt.h>
 #include <string.h>
 #include <assert.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <ctype.h>
 
-#define VERSION_COPYRIGHT_DISCLAIMER
+#define ENSC_WRAPPERS_PREFIX   "vlimit: "
+#define ENSC_WRAPPERS_UNISTD   1
+#define ENSC_WRAPPERS_VSERVER  1
+#include <wrappers.h>
 
-inline static void UNUSED
-writeStr(int fd, char const *cmd)
-{
-  (void)write(fd, cmd, strlen(cmd));
-}
+#define CMD_HELP               0x1000
+#define CMD_VERSION            0x1001
+#define CMD_XID                        0x4000
+#define CMD_DIR                        0x8000
+#define CMD_MISSINGOK          0x8001
 
-#define WRITE_MSG(FD,X)         (void)(write(FD,X,sizeof(X)-1))
-#define WRITE_STR(FD,X)         writeStr(FD,X)
+int            wrapper_exit_code = 255;
 
 #define NUMLIM(X) \
 { #X, required_argument, 0, 2048|X }
+#define OPT_RESLIM(RES,V) \
+  { #RES, required_argument, 0, 2048|RLIMIT_##V }
 
 static struct option const
 CMDLINE_OPTIONS[] = {
-  { "help",     no_argument,  0, 'h' },
-  { "version",  no_argument,  0, 'v' },
-  { "all",      no_argument,  0, 'a' },
+  { "help",      no_argument,       0, CMD_HELP },
+  { "version",   no_argument,       0, CMD_VERSION },
+  { "all",       no_argument,       0, 'a' },
+  { "xid",       required_argument, 0, CMD_XID },
+  { "dir",       required_argument, 0, CMD_DIR },
+  { "missingok", no_argument,       0, CMD_MISSINGOK },
   NUMLIM( 0), NUMLIM( 1), NUMLIM( 2), NUMLIM( 3),
   NUMLIM( 4), NUMLIM( 5), NUMLIM( 6), NUMLIM( 7),
   NUMLIM( 8), NUMLIM( 9), NUMLIM(10), NUMLIM(11),
@@ -65,16 +80,57 @@ CMDLINE_OPTIONS[] = {
   NUMLIM(20), NUMLIM(21), NUMLIM(22), NUMLIM(23),
   NUMLIM(24), NUMLIM(25), NUMLIM(26), NUMLIM(27),
   NUMLIM(28), NUMLIM(29), NUMLIM(30), NUMLIM(31),
+  OPT_RESLIM(cpu,     CPU),
+  OPT_RESLIM(fsize,   FSIZE),
+  OPT_RESLIM(data,    DATA),
+  OPT_RESLIM(stack,   STACK),
+  OPT_RESLIM(core,    CORE),
+  OPT_RESLIM(rss,     RSS),
+  OPT_RESLIM(nproc,   NPROC),
+  OPT_RESLIM(nofile,  NOFILE),
+  OPT_RESLIM(memlock, MEMLOCK),
+  OPT_RESLIM(as,      AS),
+  OPT_RESLIM(locks,   LOCKS),
   { 0,0,0,0 }
 };
 
+#define REV_RESLIM(X)  [RLIMIT_##X] = #X
+static char const * const LIMIT_STR[] = {
+  REV_RESLIM(CPU),     REV_RESLIM(FSIZE), REV_RESLIM(DATA),  REV_RESLIM(STACK),
+  REV_RESLIM(CORE),    REV_RESLIM(RSS),   REV_RESLIM(NPROC), REV_RESLIM(NOFILE),
+  REV_RESLIM(MEMLOCK), REV_RESLIM(AS),    REV_RESLIM(LOCKS)
+};
+
 static void
 showHelp(int fd, char const *cmd, int res)
 {
+  VSERVER_DECLARE_CMD(cmd);
+  
   WRITE_MSG(fd, "Usage:  ");
   WRITE_STR(fd, cmd);
   WRITE_MSG(fd,
-           " -c <xid> [-a|--all] [-MSH  --<nr> <value>]*\n"
+           " [--xid|-c <xid>] [-nd] [-a|--all] [[-MSH] --(<resource>|<nr>) <value>]*\n"
+           "               [--dir <pathname> [--missingok]] [--] [<program> <args>*]\n\n"
+           "Options:\n"
+           "    -c|--xid <xid>\n"
+           "                ...  operate on context <xid>\n"
+           "    -a|--all    ...  show all available limits\n"
+           "    -n          ...  do not resolve limit-names\n"
+           "    -d          ...  show limits in decimal\n"
+           "    -M          ...  set Minimum limit\n"
+           "    -S          ...  set Soft limit\n"
+           "    -H          ...  set Hard limit (assumed by default, when neither\n"
+           "                     M nor S was requested)\n"
+           "    --dir <pathname>\n"
+           "                ...  read limits from <pathname>/; allowed filenames are\n"
+           "                     <resource> and <resource>.{min,soft,hard}. When a limit\n"
+           "                     was set by the CLI already, the corresponding file\n"
+           "                     will be ignored\n"
+           "    --missingok ...  do not fail when <pathname> does not exist\n"
+           "    --<resource>|<nr> <value>\n"
+           "                ...  set specified (MSH) limit for <resource> to <value>\n\n"
+           "Valid values for resource are cpu, fsize, data, stack, core, rss, nproc,\n"
+           "nofile, memlock, as and locks.\n\n"
            "Please report bugs to " PACKAGE_BUGREPORT "\n");
   exit(res);
 }
@@ -90,6 +146,16 @@ showVersion()
   exit(0);
 }
 
+static size_t
+fmtHex(char *ptr, vc_limit_t lim)
+{
+  memcpy(ptr, "0x", 2);
+  return utilvserver_fmt_xuint64(ptr+2, lim) + 2;
+}
+
+static bool            do_resolve = true;
+static size_t          (*fmt_func)(char *, vc_limit_t) = fmtHex;
+
 static void *
 appendLimit(char *ptr, bool do_it, vc_limit_t lim)
 {
@@ -97,15 +163,11 @@ appendLimit(char *ptr, bool do_it, vc_limit_t lim)
   ptr += 2;
   if (do_it) {
     if (lim==VC_LIM_INFINITY) {
-      strcpy(ptr, "INF");
+      strcpy(ptr, "inf");
       ptr += 3;
     }
     else {
-      memcpy(ptr, "0x", 2);
-      ptr += 2;
-
-      ptr += utilvserver_uint2str(ptr, 20, (lim>>32),      16);
-      ptr += utilvserver_uint2str(ptr, 20, lim&0xffffffff, 16);
+      ptr += (*fmt_func)(ptr, lim);
       *ptr = ' ';
     }
   }
@@ -125,14 +187,14 @@ showAll(int ctx)
 
   if (vc_get_rlimit_mask(ctx, &mask)==-1) {
     perror("vc_get_rlimit_mask()");
-    exit(1);
+    exit(wrapper_exit_code);
   }
 
   for (i=0; i<32; ++i) {
     uint32_t           bitmask = (1<<i);
     struct vc_rlimit   limit;
-    char               buf[100], *ptr=buf;
-    
+    char               buf[128], *ptr=buf;
+
     if (((mask.min|mask.soft|mask.hard) & bitmask)==0) continue;
     if (vc_get_rlimit(ctx, i, &limit)==-1) {
       perror("vc_get_rlimit()");
@@ -140,20 +202,27 @@ showAll(int ctx)
     }
 
     memset(buf, ' ', sizeof buf);
-    ptr += utilvserver_uint2str(ptr, 100, i, 10);
-    *ptr = ' ';
+    if (do_resolve && i<DIM_OF(LIMIT_STR)) {
+      size_t           l = strlen(LIMIT_STR[i]);
+      memcpy(ptr, LIMIT_STR[i], l);
+      ptr += l;
+    }
+    else {
+      ptr += utilvserver_fmt_uint(ptr, i);
+      *ptr = ' ';
+    }
 
     ptr  = appendLimit(buf+10, mask.min &bitmask, limit.min);
     ptr  = appendLimit(buf+30, mask.soft&bitmask, limit.soft);
     ptr  = appendLimit(buf+50, mask.hard&bitmask, limit.hard);
 
     *ptr++ = '\n';
-    write(1, buf, ptr-buf);
- }
+    Vwrite(1, buf, ptr-buf);
 }
 }
 
 static void
-  setLimits(int ctx, struct vc_rlimit const limits[], uint32_t mask)
+setLimits(int ctx, struct vc_rlimit const limits[], uint32_t mask)
 {
   size_t               i;
   for (i=0; i<32; ++i) {
@@ -164,14 +233,103 @@ static void
   }
 }
 
+static vc_limit_t
+readValue(int fd, char const *filename)
+{
+  char         buf[128];
+  size_t       len = Eread(fd, buf, sizeof(buf)-1);
+  vc_limit_t   res;
+
+  buf[len] = '\0';
+
+  if (!vc_parseLimit(buf, &res)) {
+    WRITE_MSG(2, "Invalid limit in '");
+    WRITE_STR(2, filename);
+    WRITE_STR(2, "'\n");
+    exit(wrapper_exit_code);
+  }
+
+  return res;
+}
+
+static bool
+readFile(char const *file, char *base, char const *suffix,
+        vc_limit_t *limit)
+{
+  int          fd;
+  
+  strcpy(base, suffix);
+  fd = open(file, O_RDONLY);
+  if (fd!=-1) {
+    *limit = readValue(fd, file);
+    Eclose(fd);
+  }
+
+  return fd!=-1;
+}
+        
+static void
+readFromDir(struct vc_rlimit limits[32], uint_least32_t *mask,
+           char const *pathname, bool missing_ok)
+{
+  struct stat          st;
+  size_t               i;
+  size_t               l_pathname = strlen(pathname);
+  char                 buf[l_pathname + sizeof("/memlock.hard") + 32];
+  
+  if (stat(pathname, &st)==-1) {
+    if (errno==ENOENT && missing_ok) return;
+    PERROR_Q("vlimit: fstat", pathname);
+    exit(wrapper_exit_code);
+  }
+
+  memcpy(buf, pathname, l_pathname);
+  if (l_pathname>0 && pathname[l_pathname-1]!='/')
+    buf[l_pathname++] = '/';
+    
+  for (i=0; i<DIM_OF(LIMIT_STR); ++i) {
+    size_t     l_res;
+    char *     ptr   = buf+l_pathname;
+
+    // ignore unimplemented limits
+    if (LIMIT_STR[i]==0) continue;
+    
+    // ignore limits set on cli already
+    if (*mask & (1<<i)) continue;
+
+    l_res = strlen(LIMIT_STR[i]);
+    memcpy(ptr, LIMIT_STR[i], l_res+1);
+    while (*ptr) {
+      *ptr = tolower(*ptr);
+      ++ptr;
+    }
+
+    if (readFile(buf, ptr, "", &limits[i].min)) {
+      limits[i].soft = limits[i].hard = limits[i].min;
+      *mask |= (1<<i);
+    }
+
+    if (readFile(buf, ptr, ".min",  &limits[i].min))
+      *mask |= (1<<i);
+
+    if (readFile(buf, ptr, ".soft", &limits[i].soft))
+      *mask |= (1<<i);
+
+    if (readFile(buf, ptr, ".hard", &limits[i].hard))
+      *mask |= (1<<i);
+  }
+}
+
 int main (int argc, char *argv[])
 {
   // overall used limits
   uint32_t             lim_mask = 0;
   int                  set_mask = 0;
   struct vc_rlimit     limits[32];
-  bool                 show_all = false;
-  xid_t                        ctx      = VC_NOCTX;
+  bool                 show_all   = false;
+  xid_t                        ctx        = VC_NOCTX;
+  char const *         dir        = 0;
+  bool                 missing_ok = false;
 
   {
     size_t             i;
@@ -183,16 +341,22 @@ int main (int argc, char *argv[])
   }
   
   while (1) {
-    int                c = getopt_long(argc, argv, "MSHhvac:", CMDLINE_OPTIONS, 0);
+    int                c = getopt_long(argc, argv, "+MSHndac:", CMDLINE_OPTIONS, 0);
     if (c==-1) break;
 
     if (2048<=c && c<2048+32) {
       int              id  = c-2048;
       vc_limit_t       val;
       
-      if (strcmp(optarg, "inf")==0) val = VC_LIM_INFINITY;
-      else                         val = atoll(optarg);
+      if (!vc_parseLimit(optarg, &val)) {
+       WRITE_MSG(2, "Can not parse limit '");
+       WRITE_STR(2, optarg);
+       WRITE_STR(2, "'\n");
+       exit(wrapper_exit_code);
+      }
 
+      if (set_mask==0)  set_mask=4;
+      
       if (set_mask & 1) limits[id].min  = val;
       if (set_mask & 2) limits[id].soft = val;
       if (set_mask & 4) limits[id].hard = val;
@@ -201,10 +365,15 @@ int main (int argc, char *argv[])
       set_mask  = 0;
     }
     else switch (c) {
-      case 'h'         :  showHelp(1, argv[0], 0);
-      case 'v'         :  showVersion();
-      case 'c'         :  ctx      = atoi(optarg); break;
-      case 'a'         :  show_all = true;         break;
+      case CMD_HELP    :  showHelp(1, argv[0], 0);
+      case CMD_VERSION :  showVersion();
+      case 'a'         :  show_all   = true;            break;
+      case 'n'         :  do_resolve = false;           break;
+      case CMD_DIR     :  dir        = optarg;          break;
+      case CMD_MISSINGOK:  missing_ok = true;            break;
+      case CMD_XID     :  /*@fallthrough@*/
+      case 'c'         :  ctx = Evc_xidopt2xid(optarg,true);   break;
+      case 'd'         :  fmt_func   = utilvserver_fmt_uint64; break;
       case 'M'         :
       case 'S'         :
       case 'H'         :
@@ -220,18 +389,22 @@ int main (int argc, char *argv[])
        WRITE_MSG(2, "Try '");
        WRITE_STR(2, argv[0]);
        WRITE_MSG(2, " --help\" for more information.\n");
-       return EXIT_FAILURE;
+       exit(wrapper_exit_code) ;
        break;
     }
   }
 
-  if (ctx==VC_NOCTX) {
-    WRITE_MSG(2, "No context specified; try '--help' for more information\n");
-    return EXIT_FAILURE;
-  }
+  if (ctx==VC_NOCTX)
+    ctx = Evc_get_task_xid(0);
+
+  if (dir)
+    readFromDir(limits, &lim_mask, dir, missing_ok);
 
   setLimits(ctx, limits, lim_mask);
   if (show_all) showAll(ctx);
 
+  if (optind<argc)
+    EexecvpD(argv[optind], argv+optind);
+
   return EXIT_SUCCESS;
 }