vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

vlimit.c (11553B)


      1 // $Id$
      2 
      3 // Copyright (C) 2003 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; either version 2, or (at your option)
      8 // any later version.
      9 //  
     10 // This program is distributed in the hope that it will be useful,
     11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 // GNU General Public License for more details.
     14 //  
     15 // You should have received a copy of the GNU General Public License
     16 // along with this program; if not, write to the Free Software
     17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     18 
     19 /*
     20 	Set the global per context limit of a resource (memory, file handle).
     21 	This utility can do it either for the current context or a selected
     22 	one.
     23 
     24 	It uses the same options as ulimit, when possible
     25 */
     26 #ifdef HAVE_CONFIG_H
     27 #  include <config.h>
     28 #endif
     29 #include "compat.h"
     30 
     31 #include "vserver.h"
     32 #include "internal.h"
     33 #include "util.h"
     34 
     35 #include <getopt.h>
     36 #include <string.h>
     37 #include <unistd.h>
     38 #include <assert.h>
     39 #include <stdbool.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <libgen.h>
     43 #include <sys/resource.h>
     44 #include <errno.h>
     45 #include <fcntl.h>
     46 #include <sys/stat.h>
     47 #include <ctype.h>
     48 
     49 #define ENSC_WRAPPERS_PREFIX	"vlimit: "
     50 #define ENSC_WRAPPERS_UNISTD	1
     51 #define ENSC_WRAPPERS_VSERVER	1
     52 #include <wrappers.h>
     53 
     54 #define CMD_HELP		0x1000
     55 #define CMD_VERSION		0x1001
     56 #define CMD_XID			0x4000
     57 #define CMD_DIR			0x8000
     58 #define CMD_MISSINGOK		0x8001
     59 
     60 int		wrapper_exit_code = 255;
     61 
     62 #ifndef RLIMIT_MSGQUEUE
     63 #  define RLIMIT_MSGQUEUE	12
     64 #endif
     65 
     66 #define NUMLIM(X) \
     67 { #X, required_argument, 0, 2048|X }
     68 #define OPT_RESLIM(RES,V) \
     69   { #RES, required_argument, 0, 2048|RLIMIT_##V }
     70 #define OPT_VLIMIT(RES,V) \
     71   { #RES, required_argument, 0, 2048|VC_VLIMIT_##V }
     72 
     73 static struct option const
     74 CMDLINE_OPTIONS[] = {
     75   { "help",      no_argument,       0, CMD_HELP },
     76   { "version",   no_argument,       0, CMD_VERSION },
     77   { "all",       no_argument,       0, 'a' },
     78   { "xid",       required_argument, 0, CMD_XID },
     79   { "dir",       required_argument, 0, CMD_DIR },
     80   { "missingok", no_argument,       0, CMD_MISSINGOK },
     81   NUMLIM( 0), NUMLIM( 1), NUMLIM( 2), NUMLIM( 3),
     82   NUMLIM( 4), NUMLIM( 5), NUMLIM( 6), NUMLIM( 7),
     83   NUMLIM( 8), NUMLIM( 9), NUMLIM(10), NUMLIM(11),
     84   NUMLIM(12), NUMLIM(13), NUMLIM(14), NUMLIM(15),
     85   NUMLIM(16), NUMLIM(17), NUMLIM(18), NUMLIM(19),
     86   NUMLIM(20), NUMLIM(21), NUMLIM(22), NUMLIM(23),
     87   NUMLIM(24), NUMLIM(25), NUMLIM(26), NUMLIM(27),
     88   NUMLIM(28), NUMLIM(29), NUMLIM(30), NUMLIM(31),
     89   OPT_RESLIM(cpu,      CPU),
     90   OPT_RESLIM(fsize,    FSIZE),
     91   OPT_RESLIM(data,     DATA),
     92   OPT_RESLIM(stack,    STACK),
     93   OPT_RESLIM(core,     CORE),
     94   OPT_RESLIM(rss,      RSS),
     95   OPT_RESLIM(nproc,    NPROC),
     96   OPT_RESLIM(nofile,   NOFILE),
     97   OPT_RESLIM(memlock,  MEMLOCK),
     98   OPT_RESLIM(as,       AS),
     99   OPT_RESLIM(locks,    LOCKS),
    100   OPT_RESLIM(msgqueue, MSGQUEUE),
    101   OPT_VLIMIT(nsock,    NSOCK),
    102   OPT_VLIMIT(openfd,   OPENFD),
    103   OPT_VLIMIT(anon,     ANON),
    104   OPT_VLIMIT(shmem,    SHMEM),
    105   OPT_VLIMIT(semary,   SEMARY),
    106   OPT_VLIMIT(nsems,    NSEMS),
    107   OPT_VLIMIT(dentry,   DENTRY),
    108   { 0,0,0,0 }
    109 };
    110 
    111 #define REV_RESLIM(X)	[RLIMIT_##X] = #X
    112 #define REV_VLIMIT(X)	[VC_VLIMIT_##X] = #X
    113 static char const * const LIMIT_STR[] = {
    114   REV_RESLIM(CPU),     REV_RESLIM(FSIZE),  REV_RESLIM(DATA),  REV_RESLIM(STACK),
    115   REV_RESLIM(CORE),    REV_RESLIM(RSS),    REV_RESLIM(NPROC), REV_RESLIM(NOFILE),
    116   REV_RESLIM(MEMLOCK), REV_RESLIM(AS),     REV_RESLIM(LOCKS), REV_RESLIM(MSGQUEUE),
    117   REV_VLIMIT(NSOCK),   REV_VLIMIT(OPENFD), REV_VLIMIT(ANON),  REV_VLIMIT(SHMEM),
    118   REV_VLIMIT(SEMARY),  REV_VLIMIT(NSEMS),  REV_VLIMIT(DENTRY),
    119 };
    120 
    121 static void
    122 showHelp(int fd, char const *cmd, int res)
    123 {
    124   VSERVER_DECLARE_CMD(cmd);
    125   
    126   WRITE_MSG(fd, "Usage:  ");
    127   WRITE_STR(fd, cmd);
    128   WRITE_MSG(fd,
    129 	    " [--xid|-c <xid>] [-nd] [-a|--all] [[-MSH] --(<resource>|<nr>) <value>]*\n"
    130 	    "               [--dir <pathname> [--missingok]] [--] [<program> <args>*]\n\n"
    131 	    "Options:\n"
    132 	    "    -c|--xid <xid>\n"
    133 	    "                ...  operate on context <xid>\n"
    134 	    "    -a|--all    ...  show all available limits\n"
    135 	    "    -n          ...  do not resolve limit-names\n"
    136 	    "    -d          ...  show limits in decimal\n"
    137 	    "    -M          ...  set Minimum limit\n"
    138 	    "    -S          ...  set Soft limit\n"
    139 	    "    -H          ...  set Hard limit (assumed by default, when neither\n"
    140 	    "                     M nor S was requested)\n"
    141 	    "    --dir <pathname>\n"
    142 	    "                ...  read limits from <pathname>/; allowed filenames are\n"
    143 	    "                     <resource> and <resource>.{min,soft,hard}. When a limit\n"
    144 	    "                     was set by the CLI already, the corresponding file\n"
    145 	    "                     will be ignored\n"
    146 	    "    --missingok ...  do not fail when <pathname> does not exist\n"
    147 	    "    --<resource>|<nr> <value>\n"
    148 	    "                ...  set specified (MSH) limit for <resource> to <value>\n\n"
    149 	    "Valid values for resource are cpu, fsize, data, stack, core, rss, nproc,\n"
    150 	    "nofile, memlock, as, locks, msgqueue, nsock, openfd, anon, shmem, semary,\n"
    151 	    "nsems, and dentry.\n\n"
    152 	    "Please report bugs to " PACKAGE_BUGREPORT "\n");
    153   exit(res);
    154 }
    155 
    156 static void
    157 showVersion()
    158 {
    159   WRITE_MSG(1,
    160 	    "vlimit " VERSION " -- limits context-resources\n"
    161 	    "This program is part of " PACKAGE_STRING "\n\n"
    162 	    "Copyright (C) 2003 Enrico Scholz\n"
    163 	    VERSION_COPYRIGHT_DISCLAIMER);
    164   exit(0);
    165 }
    166 
    167 static size_t
    168 fmtHex(char *ptr, vc_limit_t lim)
    169 {
    170   memcpy(ptr, "0x", 2);
    171   return utilvserver_fmt_xuint64(ptr+2, lim) + 2;
    172 }
    173 
    174 static bool		do_resolve = true;
    175 static size_t		(*fmt_func)(char *, vc_limit_t) = fmtHex;
    176 
    177 static void *
    178 appendLimit(char *ptr, bool do_it, vc_limit_t lim)
    179 {
    180   memcpy(ptr, "  ", 2);
    181   ptr += 2;
    182   if (do_it) {
    183     if (lim==VC_LIM_INFINITY) {
    184       memcpy(ptr, "inf", 3);
    185       ptr += 3;
    186     }
    187     else {
    188       ptr += (*fmt_func)(ptr, lim);
    189       *ptr = ' ';
    190     }
    191   }
    192   else {
    193     memcpy(ptr, "N/A", 3);
    194     ptr += 3;
    195   }
    196 
    197   return ptr;
    198 }
    199 
    200 static void
    201 showAll(int ctx)
    202 {
    203   struct vc_rlimit_mask	mask;
    204   size_t		i;
    205 
    206   if (vc_get_rlimit_mask(ctx, &mask)==-1) {
    207     perror("vc_get_rlimit_mask()");
    208     exit(wrapper_exit_code);
    209   }
    210 
    211   for (i=0; i<32; ++i) {
    212     uint32_t		bitmask = (1<<i);
    213     struct vc_rlimit	limit;
    214     char		buf[128], *ptr=buf;
    215 
    216     if (((mask.min|mask.soft|mask.hard) & bitmask)==0) continue;
    217     if (vc_get_rlimit(ctx, i, &limit)==-1) {
    218       perror("vc_get_rlimit()");
    219       continue;
    220     }
    221 
    222     memset(buf, ' ', sizeof buf);
    223     if (do_resolve && i<DIM_OF(LIMIT_STR)) {
    224       size_t		l = strlen(LIMIT_STR[i]);
    225       memcpy(ptr, LIMIT_STR[i], l);
    226       ptr += l;
    227     }
    228     else {
    229       ptr += utilvserver_fmt_uint(ptr, i);
    230       *ptr = ' ';
    231     }
    232 
    233     ptr  = appendLimit(buf+10, mask.min &bitmask, limit.min);
    234     ptr  = appendLimit(buf+30, mask.soft&bitmask, limit.soft);
    235     ptr  = appendLimit(buf+50, mask.hard&bitmask, limit.hard);
    236 
    237     *ptr++ = '\n';
    238     Vwrite(1, buf, ptr-buf);
    239   }
    240 }
    241 
    242 static void
    243 setLimits(int ctx, struct vc_rlimit const limits[], uint32_t mask)
    244 {
    245   size_t		i;
    246   for (i=0; i<32; ++i) {
    247     if ((mask & (1<<i))==0) continue;
    248     if (vc_set_rlimit(ctx, i, limits+i)) {
    249       perror("vc_set_rlimit()");
    250     }
    251   }
    252 }
    253 
    254 static vc_limit_t
    255 readValue(int fd, char const *filename)
    256 {
    257   char		buf[128];
    258   size_t	len = Eread(fd, buf, sizeof(buf)-1);
    259   vc_limit_t	res;
    260 
    261   buf[len] = '\0';
    262 
    263   if (!vc_parseLimit(buf, &res)) {
    264     WRITE_MSG(2, "Invalid limit in '");
    265     WRITE_STR(2, filename);
    266     WRITE_STR(2, "'\n");
    267     exit(wrapper_exit_code);
    268   }
    269 
    270   return res;
    271 }
    272 
    273 static bool
    274 readFile(char const *file, char *base, char const *suffix,
    275 	 vc_limit_t *limit)
    276 {
    277   int		fd;
    278   
    279   strcpy(base, suffix);
    280   fd = open(file, O_RDONLY);
    281   if (fd!=-1) {
    282     *limit = readValue(fd, file);
    283     Eclose(fd);
    284   }
    285 
    286   return fd!=-1;
    287 }
    288 	 
    289 static void
    290 readFromDir(struct vc_rlimit limits[32], uint_least32_t *mask,
    291 	    char const *pathname, bool missing_ok)
    292 {
    293   struct stat		st;
    294   size_t		i;
    295   size_t		l_pathname = strlen(pathname);
    296   char			buf[l_pathname + sizeof("/memlock.hard") + 32];
    297   
    298   if (stat(pathname, &st)==-1) {
    299     if (errno==ENOENT && missing_ok) return;
    300     PERROR_Q("vlimit: fstat", pathname);
    301     exit(wrapper_exit_code);
    302   }
    303 
    304   memcpy(buf, pathname, l_pathname);
    305   if (l_pathname>0 && pathname[l_pathname-1]!='/')
    306     buf[l_pathname++] = '/';
    307     
    308   for (i=0; i<DIM_OF(LIMIT_STR); ++i) {
    309     size_t	l_res;
    310     char *	ptr   = buf+l_pathname;
    311 
    312     // ignore unimplemented limits
    313     if (LIMIT_STR[i]==0) continue;
    314     
    315     // ignore limits set on cli already
    316     if (*mask & (1<<i)) continue;
    317 
    318     l_res = strlen(LIMIT_STR[i]);
    319     memcpy(ptr, LIMIT_STR[i], l_res+1);
    320     while (*ptr) {
    321       *ptr = tolower(*ptr);
    322       ++ptr;
    323     }
    324 
    325     if (readFile(buf, ptr, "", &limits[i].min)) {
    326       limits[i].soft = limits[i].hard = limits[i].min;
    327       *mask |= (1<<i);
    328     }
    329 
    330     if (readFile(buf, ptr, ".min",  &limits[i].min))
    331       *mask |= (1<<i);
    332 
    333     if (readFile(buf, ptr, ".soft", &limits[i].soft))
    334       *mask |= (1<<i);
    335 
    336     if (readFile(buf, ptr, ".hard", &limits[i].hard))
    337       *mask |= (1<<i);
    338   }
    339 }
    340 
    341 int main (int argc, char *argv[])
    342 {
    343   // overall used limits
    344   uint32_t		lim_mask = 0;
    345   int			set_mask = 0;
    346   struct vc_rlimit	limits[32];
    347   bool			show_all   = false;
    348   xid_t			ctx        = VC_NOCTX;
    349   char const *		dir        = 0;
    350   bool			missing_ok = false;
    351 
    352   {
    353     size_t		i;
    354     for (i=0; i<32; ++i) {
    355       limits[i].min  = VC_LIM_KEEP;
    356       limits[i].soft = VC_LIM_KEEP;
    357       limits[i].hard = VC_LIM_KEEP;
    358     }
    359   }
    360   
    361   while (1) {
    362     int		c = getopt_long(argc, argv, "+MSHndac:", CMDLINE_OPTIONS, 0);
    363     if (c==-1) break;
    364 
    365     if (2048<=c && c<2048+32) {
    366       int		id  = c-2048;
    367       vc_limit_t	val;
    368       
    369       if (!vc_parseLimit(optarg, &val)) {
    370 	WRITE_MSG(2, "Can not parse limit '");
    371 	WRITE_STR(2, optarg);
    372 	WRITE_STR(2, "'\n");
    373 	exit(wrapper_exit_code);
    374       }
    375 
    376       if (set_mask==0)  set_mask=4;
    377       
    378       if (set_mask & 1) limits[id].min  = val;
    379       if (set_mask & 2) limits[id].soft = val;
    380       if (set_mask & 4) limits[id].hard = val;
    381 
    382       lim_mask |= (1<<id);
    383       set_mask  = 0;
    384     }
    385     else switch (c) {
    386       case CMD_HELP	:  showHelp(1, argv[0], 0);
    387       case CMD_VERSION	:  showVersion();
    388       case 'a'		:  show_all   = true;            break;
    389       case 'n'		:  do_resolve = false;           break;
    390       case CMD_DIR	:  dir        = optarg;          break;
    391       case CMD_MISSINGOK:  missing_ok = true;            break;
    392       case CMD_XID	:  /*@fallthrough@*/
    393       case 'c'		:  ctx = Evc_xidopt2xid(optarg,true);   break;
    394       case 'd'		:  fmt_func   = utilvserver_fmt_uint64; break;
    395       case 'M'		:
    396       case 'S'		:
    397       case 'H'		:
    398 	switch (c) {
    399 	  case 'M'	:  set_mask |= 1; break;
    400 	  case 'S'	:  set_mask |= 2; break;
    401 	  case 'H'	:  set_mask |= 4; break;
    402 	  default	:  assert(false);
    403 	}
    404 	break;
    405 	
    406       default		:
    407 	WRITE_MSG(2, "Try '");
    408 	WRITE_STR(2, argv[0]);
    409 	WRITE_MSG(2, " --help' for more information.\n");
    410 	exit(wrapper_exit_code) ;
    411 	break;
    412     }
    413   }
    414 
    415   if (ctx==VC_NOCTX)
    416     ctx = Evc_get_task_xid(0);
    417 
    418   if (dir)
    419     readFromDir(limits, &lim_mask, dir, missing_ok);
    420 
    421   setLimits(ctx, limits, lim_mask);
    422   if (show_all) showAll(ctx);
    423 
    424   if (optind<argc)
    425     EexecvpD(argv[optind], argv+optind);
    426 
    427   return EXIT_SUCCESS;
    428 }