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