Home | History | Annotate | Line # | Download | only in ksh
c_ulimit.c revision 1.13
      1 /*	$NetBSD: c_ulimit.c,v 1.13 2017/06/22 13:35:47 kamil 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.13 2017/06/22 13:35:47 kamil 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 #  endif /* UL_GETBREAK */
    117 # endif /* UL_GMEMLIM */
    118 #endif /* RLIMIT_VMEM */
    119 #ifdef RLIMIT_SWAP
    120 		{ "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' },
    121 #endif
    122 #ifdef RLIMIT_SBSIZE
    123 		{ "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' },
    124 #endif
    125 		{ .name = NULL }
    126 	    };
    127 	static char	options[3 + NELEM(limits)];
    128 	rlim_t		UNINITIALIZED(val);
    129 	int		how = SOFT | HARD;
    130 	const struct limits	*l;
    131 	int		set, all = 0;
    132 	int		optc, what;
    133 #ifdef HAVE_SETRLIMIT
    134 	struct rlimit	limit;
    135 #endif /* HAVE_SETRLIMIT */
    136 
    137 	if (!options[0]) {
    138 		/* build options string on first call - yuck */
    139 		char *p = options;
    140 
    141 		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
    142 		for (l = limits; l->name; l++)
    143 			*p++ = l->option;
    144 		*p = '\0';
    145 	}
    146 	what = 'f';
    147 	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
    148 		switch (optc) {
    149 		  case 'H':
    150 			how = HARD;
    151 			break;
    152 		  case 'S':
    153 			how = SOFT;
    154 			break;
    155 		  case 'a':
    156 			all = 1;
    157 			break;
    158 		  case '?':
    159 			return 1;
    160 		  default:
    161 			what = optc;
    162 		}
    163 
    164 	for (l = limits; l->name && l->option != what; l++)
    165 		;
    166 	if (!l->name) {
    167 		internal_errorf(0, "ulimit: %c", what);
    168 		return 1;
    169 	}
    170 
    171 	wp += builtin_opt.optind;
    172 	set = *wp ? 1 : 0;
    173 	if (set) {
    174 		if (all || wp[1]) {
    175 			bi_errorf("too many arguments");
    176 			return 1;
    177 		}
    178 		if (strcmp(wp[0], "unlimited") == 0)
    179 			val = KSH_RLIM_INFINITY;
    180 		else {
    181 			long rval;
    182 
    183 			if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
    184 				return 1;
    185 			/* Avoid problems caused by typos that
    186 			 * evaluate misses due to evaluating unset
    187 			 * parameters to 0...
    188 			 * If this causes problems, will have to
    189 			 * add parameter to evaluate() to control
    190 			 * if unset params are 0 or an error.
    191 			 */
    192 			if (!rval && !digit(wp[0][0])) {
    193 			    bi_errorf("invalid limit: %s", wp[0]);
    194 			    return 1;
    195 			}
    196 			val = (u_long)rval * l->factor;
    197 		}
    198 	}
    199 	if (all) {
    200 		for (l = limits; l->name; l++) {
    201 #ifdef HAVE_SETRLIMIT
    202 			if (l->which == RLIMIT) {
    203 				if (getrlimit(l->gcmd, &limit) == -1) {
    204 					bi_errorf("can't get limit: %s",
    205 					    strerror(errno));
    206 					return 1;
    207 				}
    208 				if (how & SOFT)
    209 					val = limit.rlim_cur;
    210 				else if (how & HARD)
    211 					val = limit.rlim_max;
    212 			} else
    213 #endif /* HAVE_SETRLIMIT */
    214 #ifdef HAVE_ULIMIT
    215 			{
    216 				val = ulimit(l->gcmd, (rlim_t) 0);
    217 			}
    218 #else /* HAVE_ULIMIT */
    219 				;
    220 #endif /* HAVE_ULIMIT */
    221 			shprintf("%-20s ", l->name);
    222 #ifdef RLIM_INFINITY
    223 			if (val == RLIM_INFINITY)
    224 				shprintf("unlimited\n");
    225 			else
    226 #endif /* RLIM_INFINITY */
    227 			{
    228 				val /= l->factor;
    229 				shprintf("%ld\n", (long) val);
    230 			}
    231 		}
    232 		return 0;
    233 	}
    234 #ifdef HAVE_SETRLIMIT
    235 	if (l->which == RLIMIT) {
    236 		if (getrlimit(l->gcmd, &limit) == -1) {
    237 			bi_errorf("can't get limit: %s", strerror(errno));
    238 			return 1;
    239 		}
    240 		if (set) {
    241 			if (how & SOFT)
    242 				limit.rlim_cur = val;
    243 			if (how & HARD)
    244 				limit.rlim_max = val;
    245 			if (setrlimit(l->scmd, &limit) < 0) {
    246 				if (errno == EPERM)
    247 					bi_errorf("exceeds allowable limit");
    248 				else
    249 					bi_errorf("bad limit: %s",
    250 						strerror(errno));
    251 				return 1;
    252 			}
    253 		} else {
    254 			if (how & SOFT)
    255 				val = limit.rlim_cur;
    256 			else if (how & HARD)
    257 				val = limit.rlim_max;
    258 		}
    259 	} else
    260 #endif /* HAVE_SETRLIMIT */
    261 #ifdef HAVE_ULIMIT
    262 	{
    263 		if (set) {
    264 			if (l->scmd == -1) {
    265 				bi_errorf("can't change limit");
    266 				return 1;
    267 			} else if (ulimit(l->scmd, val) < 0) {
    268 				bi_errorf("bad limit: %s", strerror(errno));
    269 				return 1;
    270 			}
    271 		} else
    272 			val = ulimit(l->gcmd, (rlim_t) 0);
    273 	}
    274 #else /* HAVE_ULIMIT */
    275 		;
    276 #endif /* HAVE_ULIMIT */
    277 	if (!set) {
    278 #ifdef RLIM_INFINITY
    279 		if (val == RLIM_INFINITY)
    280 			shprintf("unlimited\n");
    281 		else
    282 #endif /* RLIM_INFINITY */
    283 		{
    284 			val /= l->factor;
    285 			shprintf("%ld\n", (long) val);
    286 		}
    287 	}
    288 	return 0;
    289 }
    290