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