Home | History | Annotate | Line # | Download | only in ksh
c_ulimit.c revision 1.12
      1 /*	$NetBSD: c_ulimit.c,v 1.12 2015/05/09 13:26:06 christos Exp $	*/
      2 
      3 /*
      4 	ulimit -- handle "ulimit" builtin
      5 
      6 	Reworked to use getrusage() and ulimit() at once (as needed on
      7 	some schizophrenic systems, eg, HP-UX 9.01), made argument parsing
      8 	conform to at&t ksh, added autoconf support.  Michael Rendell, May, '94
      9 
     10 	Eric Gisin, September 1988
     11 	Adapted to PD KornShell. Removed AT&T code.
     12 
     13 	last edit:	06-Jun-1987	D A Gwyn
     14 
     15 	This started out as the BRL UNIX System V system call emulation
     16 	for 4.nBSD, and was later extended by Doug Kingston to handle
     17 	the extended 4.nBSD resource limits.  It now includes the code
     18 	that was originally under case SYSULIMIT in source file "xec.c".
     19 */
     20 #include <sys/cdefs.h>
     21 
     22 #ifndef lint
     23 __RCSID("$NetBSD: c_ulimit.c,v 1.12 2015/05/09 13:26:06 christos Exp $");
     24 #endif
     25 
     26 
     27 #include "sh.h"
     28 #include "ksh_time.h"
     29 #ifdef HAVE_SYS_RESOURCE_H
     30 # include <sys/resource.h>
     31 #endif /* HAVE_SYS_RESOURCE_H */
     32 #ifdef HAVE_ULIMIT_H
     33 # include <ulimit.h>
     34 #else /* HAVE_ULIMIT_H */
     35 # ifdef HAVE_ULIMIT
     36 extern	long ulimit();
     37 # endif /* HAVE_ULIMIT */
     38 #endif /* HAVE_ULIMIT_H */
     39 
     40 #define SOFT	0x1
     41 #define HARD	0x2
     42 
     43 #ifdef RLIM_INFINITY
     44 # define KSH_RLIM_INFINITY RLIM_INFINITY
     45 #else
     46 # define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1)
     47 #endif /* RLIM_INFINITY */
     48 
     49 int
     50 c_ulimit(wp)
     51 	char **wp;
     52 {
     53 	static const struct limits {
     54 		const char	*name;
     55 		enum { RLIMIT, ULIMIT } which;
     56 		int	gcmd;	/* get command */
     57 		int	scmd;	/* set command (or -1, if no set command) */
     58 		int	factor;	/* multiply by to get rlim_{cur,max} values */
     59 		char	option;
     60 	} limits[] = {
     61 		/* Do not use options -H, -S or -a */
     62 #ifdef RLIMIT_CPU
     63 		{ "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' },
     64 #endif
     65 #ifdef RLIMIT_FSIZE
     66 		{ "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' },
     67 #else /* RLIMIT_FSIZE */
     68 # ifdef UL_GETFSIZE /* x/open */
     69 		{ "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' },
     70 # else /* UL_GETFSIZE */
     71 #  ifdef UL_GFILLIM /* svr4/xenix */
     72 		{ "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' },
     73 #  else /* UL_GFILLIM */
     74 		{ "file(blocks)", ULIMIT, 1, 2, 1, 'f' },
     75 #  endif /* UL_GFILLIM */
     76 # endif /* UL_GETFSIZE */
     77 #endif /* RLIMIT_FSIZE */
     78 #ifdef RLIMIT_CORE
     79 		{ "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' },
     80 #endif
     81 #ifdef RLIMIT_DATA
     82 		{ "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' },
     83 #endif
     84 #ifdef RLIMIT_STACK
     85 		{ "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' },
     86 #endif
     87 #ifdef RLIMIT_MEMLOCK
     88 		{ "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' },
     89 #endif
     90 #ifdef RLIMIT_RSS
     91 		{ "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' },
     92 #endif
     93 #ifdef RLIMIT_NOFILE
     94 		{ "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' },
     95 #else /* RLIMIT_NOFILE */
     96 # ifdef UL_GDESLIM /* svr4/xenix */
     97 		{ "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' },
     98 # endif /* UL_GDESLIM */
     99 #endif /* RLIMIT_NOFILE */
    100 #ifdef RLIMIT_NPROC
    101 		{ "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' },
    102 #endif
    103 #ifdef RLIMIT_NTHR
    104 		{ "threads", RLIMIT, RLIMIT_NTHR, RLIMIT_NTHR, 1, 'r' },
    105 #endif
    106 #ifdef RLIMIT_VMEM
    107 		{ "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' },
    108 #else /* RLIMIT_VMEM */
    109   /* These are not quite right - really should subtract etext or something */
    110 # ifdef UL_GMEMLIM /* svr4/xenix */
    111 		{ "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' },
    112 # else /* UL_GMEMLIM */
    113 #  ifdef UL_GETBREAK /* osf/1 */
    114 		{ "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' },
    115 #  else /* UL_GETBREAK */
    116 #   ifdef UL_GETMAXBRK /* hpux */
    117 		{ "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' },
    118 #   endif /* UL_GETMAXBRK */
    119 #  endif /* UL_GETBREAK */
    120 # endif /* UL_GMEMLIM */
    121 #endif /* RLIMIT_VMEM */
    122 #ifdef RLIMIT_SWAP
    123 		{ "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
    124 #endif
    125 #ifdef RLIMIT_SBSIZE
    126 		{ "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' },
    127 #endif
    128 		{ .name = NULL }
    129 	    };
    130 	static char	options[3 + NELEM(limits)];
    131 	rlim_t		UNINITIALIZED(val);
    132 	int		how = SOFT | HARD;
    133 	const struct limits	*l;
    134 	int		set, all = 0;
    135 	int		optc, what;
    136 #ifdef HAVE_SETRLIMIT
    137 	struct rlimit	limit;
    138 #endif /* HAVE_SETRLIMIT */
    139 
    140 	if (!options[0]) {
    141 		/* build options string on first call - yuck */
    142 		char *p = options;
    143 
    144 		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
    145 		for (l = limits; l->name; l++)
    146 			*p++ = l->option;
    147 		*p = '\0';
    148 	}
    149 	what = 'f';
    150 	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
    151 		switch (optc) {
    152 		  case 'H':
    153 			how = HARD;
    154 			break;
    155 		  case 'S':
    156 			how = SOFT;
    157 			break;
    158 		  case 'a':
    159 			all = 1;
    160 			break;
    161 		  case '?':
    162 			return 1;
    163 		  default:
    164 			what = optc;
    165 		}
    166 
    167 	for (l = limits; l->name && l->option != what; l++)
    168 		;
    169 	if (!l->name) {
    170 		internal_errorf(0, "ulimit: %c", what);
    171 		return 1;
    172 	}
    173 
    174 	wp += builtin_opt.optind;
    175 	set = *wp ? 1 : 0;
    176 	if (set) {
    177 		if (all || wp[1]) {
    178 			bi_errorf("too many arguments");
    179 			return 1;
    180 		}
    181 		if (strcmp(wp[0], "unlimited") == 0)
    182 			val = KSH_RLIM_INFINITY;
    183 		else {
    184 			long rval;
    185 
    186 			if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
    187 				return 1;
    188 			/* Avoid problems caused by typos that
    189 			 * evaluate misses due to evaluating unset
    190 			 * parameters to 0...
    191 			 * If this causes problems, will have to
    192 			 * add parameter to evaluate() to control
    193 			 * if unset params are 0 or an error.
    194 			 */
    195 			if (!rval && !digit(wp[0][0])) {
    196 			    bi_errorf("invalid limit: %s", wp[0]);
    197 			    return 1;
    198 			}
    199 			val = (u_long)rval * l->factor;
    200 		}
    201 	}
    202 	if (all) {
    203 		for (l = limits; l->name; l++) {
    204 #ifdef HAVE_SETRLIMIT
    205 			if (l->which == RLIMIT) {
    206 				if (getrlimit(l->gcmd, &limit) == -1) {
    207 					bi_errorf("can't get limit: %s",
    208 					    strerror(errno));
    209 					return 1;
    210 				}
    211 				if (how & SOFT)
    212 					val = limit.rlim_cur;
    213 				else if (how & HARD)
    214 					val = limit.rlim_max;
    215 			} else
    216 #endif /* HAVE_SETRLIMIT */
    217 #ifdef HAVE_ULIMIT
    218 			{
    219 				val = ulimit(l->gcmd, (rlim_t) 0);
    220 			}
    221 #else /* HAVE_ULIMIT */
    222 				;
    223 #endif /* HAVE_ULIMIT */
    224 			shprintf("%-20s ", l->name);
    225 #ifdef RLIM_INFINITY
    226 			if (val == RLIM_INFINITY)
    227 				shprintf("unlimited\n");
    228 			else
    229 #endif /* RLIM_INFINITY */
    230 			{
    231 				val /= l->factor;
    232 				shprintf("%ld\n", (long) val);
    233 			}
    234 		}
    235 		return 0;
    236 	}
    237 #ifdef HAVE_SETRLIMIT
    238 	if (l->which == RLIMIT) {
    239 		if (getrlimit(l->gcmd, &limit) == -1) {
    240 			bi_errorf("can't get limit: %s", strerror(errno));
    241 			return 1;
    242 		}
    243 		if (set) {
    244 			if (how & SOFT)
    245 				limit.rlim_cur = val;
    246 			if (how & HARD)
    247 				limit.rlim_max = val;
    248 			if (setrlimit(l->scmd, &limit) < 0) {
    249 				if (errno == EPERM)
    250 					bi_errorf("exceeds allowable limit");
    251 				else
    252 					bi_errorf("bad limit: %s",
    253 						strerror(errno));
    254 				return 1;
    255 			}
    256 		} else {
    257 			if (how & SOFT)
    258 				val = limit.rlim_cur;
    259 			else if (how & HARD)
    260 				val = limit.rlim_max;
    261 		}
    262 	} else
    263 #endif /* HAVE_SETRLIMIT */
    264 #ifdef HAVE_ULIMIT
    265 	{
    266 		if (set) {
    267 			if (l->scmd == -1) {
    268 				bi_errorf("can't change limit");
    269 				return 1;
    270 			} else if (ulimit(l->scmd, val) < 0) {
    271 				bi_errorf("bad limit: %s", strerror(errno));
    272 				return 1;
    273 			}
    274 		} else
    275 			val = ulimit(l->gcmd, (rlim_t) 0);
    276 	}
    277 #else /* HAVE_ULIMIT */
    278 		;
    279 #endif /* HAVE_ULIMIT */
    280 	if (!set) {
    281 #ifdef RLIM_INFINITY
    282 		if (val == RLIM_INFINITY)
    283 			shprintf("unlimited\n");
    284 		else
    285 #endif /* RLIM_INFINITY */
    286 		{
    287 			val /= l->factor;
    288 			shprintf("%ld\n", (long) val);
    289 		}
    290 	}
    291 	return 0;
    292 }
    293