Home | History | Annotate | Line # | Download | only in ksh
c_ulimit.c revision 1.6
      1 /*	$NetBSD: c_ulimit.c,v 1.6 2004/04/17 15:40:12 christos 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.6 2004/04/17 15:40:12 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_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, 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 		{ (char *) 0 }
    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 #ifdef __GNUC__
    138 	/* This outrageous construct just to shut up a GCC warning. */
    139 	(void) &val;
    140 #endif
    141 
    142 	if (!options[0]) {
    143 		/* build options string on first call - yuck */
    144 		char *p = options;
    145 
    146 		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
    147 		for (l = limits; l->name; l++)
    148 			*p++ = l->option;
    149 		*p = '\0';
    150 	}
    151 	what = 'f';
    152 	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF)
    153 		switch (optc) {
    154 		  case 'H':
    155 			how = HARD;
    156 			break;
    157 		  case 'S':
    158 			how = SOFT;
    159 			break;
    160 		  case 'a':
    161 			all = 1;
    162 			break;
    163 		  case '?':
    164 			return 1;
    165 		  default:
    166 			what = optc;
    167 		}
    168 
    169 	for (l = limits; l->name && l->option != what; l++)
    170 		;
    171 	if (!l->name) {
    172 		internal_errorf(0, "ulimit: %c", what);
    173 		return 1;
    174 	}
    175 
    176 	wp += builtin_opt.optind;
    177 	set = *wp ? 1 : 0;
    178 	if (set) {
    179 		if (all || wp[1]) {
    180 			bi_errorf("too many arguments");
    181 			return 1;
    182 		}
    183 		if (strcmp(wp[0], "unlimited") == 0)
    184 			val = KSH_RLIM_INFINITY;
    185 		else {
    186 			long rval;
    187 
    188 			if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR))
    189 				return 1;
    190 			/* Avoid problems caused by typos that
    191 			 * evaluate misses due to evaluating unset
    192 			 * parameters to 0...
    193 			 * If this causes problems, will have to
    194 			 * add parameter to evaluate() to control
    195 			 * if unset params are 0 or an error.
    196 			 */
    197 			if (!rval && !digit(wp[0][0])) {
    198 			    bi_errorf("invalid limit: %s", wp[0]);
    199 			    return 1;
    200 			}
    201 			val = rval * l->factor;
    202 		}
    203 	}
    204 	if (all) {
    205 		for (l = limits; l->name; l++) {
    206 #ifdef HAVE_SETRLIMIT
    207 			if (l->which == RLIMIT) {
    208 				getrlimit(l->gcmd, &limit);
    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 		getrlimit(l->gcmd, &limit);
    238 		if (set) {
    239 			if (how & SOFT)
    240 				limit.rlim_cur = val;
    241 			if (how & HARD)
    242 				limit.rlim_max = val;
    243 			if (setrlimit(l->scmd, &limit) < 0) {
    244 				if (errno == EPERM)
    245 					bi_errorf("exceeds allowable limit");
    246 				else
    247 					bi_errorf("bad limit: %s",
    248 						strerror(errno));
    249 				return 1;
    250 			}
    251 		} else {
    252 			if (how & SOFT)
    253 				val = limit.rlim_cur;
    254 			else if (how & HARD)
    255 				val = limit.rlim_max;
    256 		}
    257 	} else
    258 #endif /* HAVE_SETRLIMIT */
    259 #ifdef HAVE_ULIMIT
    260 	{
    261 		if (set) {
    262 			if (l->scmd == -1) {
    263 				bi_errorf("can't change limit");
    264 				return 1;
    265 			} else if (ulimit(l->scmd, val) < 0) {
    266 				bi_errorf("bad limit: %s", strerror(errno));
    267 				return 1;
    268 			}
    269 		} else
    270 			val = ulimit(l->gcmd, (rlim_t) 0);
    271 	}
    272 #else /* HAVE_ULIMIT */
    273 		;
    274 #endif /* HAVE_ULIMIT */
    275 	if (!set) {
    276 #ifdef RLIM_INFINITY
    277 		if (val == RLIM_INFINITY)
    278 			shprintf("unlimited\n");
    279 		else
    280 #endif /* RLIM_INFINITY */
    281 		{
    282 			val /= l->factor;
    283 			shprintf("%ld\n", (long) val);
    284 		}
    285 	}
    286 	return 0;
    287 }
    288