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