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