added '--dir' parameter
authorEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Fri, 5 Mar 2004 17:23:21 +0000 (17:23 +0000)
committerEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Fri, 5 Mar 2004 17:23:21 +0000 (17:23 +0000)
allow command-chaining
support limits with suffixes
make '-c' optionally and assume current ctx by default

git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@1102 94cd875c-1c1d-0410-91d2-eb244daf1a30

util-vserver/src/vlimit.c

index cf1b536..3aba2b7 100644 (file)
 #include <stdlib.h>
 #include <libgen.h>
 #include <sys/resource.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <ctype.h>
+
+#define ENSC_WRAPPERS_PREFIX   "vlimit: "
+#define ENSC_WRAPPERS_UNISTD   1
+#define ENSC_WRAPPERS_VSERVER  1
+#include <wrappers.h>
+
+#define CMD_DIR                0x8000
+#define CMD_MISSINGOK  0x8001
+
+int            wrapper_exit_code = 255;
 
 #define NUMLIM(X) \
 { #X, required_argument, 0, 2048|X }
-#define RESLIM(RES,V) \
+#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, 'h' },
+  { "version",   no_argument,       0, 'v' },
+  { "all",       no_argument,       0, 'a' },
+  { "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),
@@ -60,17 +76,17 @@ 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),
-  RESLIM(cpu,     CPU),
-  RESLIM(fsize,   FSIZE),
-  RESLIM(data,    DATA),
-  RESLIM(stack,   STACK),
-  RESLIM(core,    CORE),
-  RESLIM(rss,     RSS),
-  RESLIM(nproc,   NPROC),
-  RESLIM(nofile,  NOFILE),
-  RESLIM(memlock, MEMLOCK),
-  RESLIM(as,      AS),
-  RESLIM(locks,   LOCKS),
+  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 }
 };
 
@@ -89,7 +105,8 @@ showHelp(int fd, char const *cmd, int res)
   WRITE_MSG(fd, "Usage:  ");
   WRITE_STR(fd, cmd);
   WRITE_MSG(fd,
-           " -c <xid> [-nd] [-a|--all] [[-MSH] --(<resource>|<nr>) <value>]*\n\n"
+           " [-c <xid>] [-nd] [-a|--all] [[-MSH] --(<resource>|<nr>) <value>]*\n"
+           "               [--dir <pathname> [--missingok]] [--] [<program> <args>*]\n\n"
            "Options:\n"
            "    -c <xid>    ...  operate on context <xid>\n"
            "    -a|--all    ...  show all available limits\n"
@@ -99,6 +116,12 @@ showHelp(int fd, char const *cmd, int res)
            "    -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"
@@ -159,7 +182,7 @@ 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) {
@@ -205,14 +228,103 @@ setLimits(int ctx, struct vc_rlimit const limits[], uint32_t mask)
   }
 }
 
+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;
+  
+  memcpy(base, suffix, strlen(suffix)+1);
+  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;
@@ -231,8 +343,12 @@ int main (int argc, char *argv[])
       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;
       
@@ -250,6 +366,8 @@ int main (int argc, char *argv[])
       case 'a'         :  show_all   = true;         break;
       case 'n'         :  do_resolve = false;        break;
       case 'd'         :  fmt_func   = utilvserver_fmt_uint64; break;
+      case CMD_DIR     :  dir        = optarg;       break;
+      case CMD_MISSINGOK:  missing_ok = true;         break;
       case 'M'         :
       case 'S'         :
       case 'H'         :
@@ -265,18 +383,20 @@ 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);
 
+  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;
 }