| 1 |  |  | /*	$OpenBSD: c_ulimit.c,v 1.24 2015/12/14 13:59:42 tb 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 |  |  |  | 
    
    | 21 |  |  | #include <sys/resource.h> | 
    
    | 22 |  |  |  | 
    
    | 23 |  |  | #include <ctype.h> | 
    
    | 24 |  |  | #include <errno.h> | 
    
    | 25 |  |  | #include <string.h> | 
    
    | 26 |  |  |  | 
    
    | 27 |  |  | #include "sh.h" | 
    
    | 28 |  |  |  | 
    
    | 29 |  |  | #define SOFT	0x1 | 
    
    | 30 |  |  | #define HARD	0x2 | 
    
    | 31 |  |  |  | 
    
    | 32 |  |  | struct limits { | 
    
    | 33 |  |  | 	const char *name; | 
    
    | 34 |  |  | 	int	resource;	/* resource to get/set */ | 
    
    | 35 |  |  | 	int	factor;		/* multiply by to get rlim_{cur,max} values */ | 
    
    | 36 |  |  | 	char	option;		/* option character (-d, -f, ...) */ | 
    
    | 37 |  |  | }; | 
    
    | 38 |  |  |  | 
    
    | 39 |  |  | static void print_ulimit(const struct limits *, int); | 
    
    | 40 |  |  | static int set_ulimit(const struct limits *, const char *, int); | 
    
    | 41 |  |  |  | 
    
    | 42 |  |  | int | 
    
    | 43 |  |  | c_ulimit(char **wp) | 
    
    | 44 |  | 2 | { | 
    
    | 45 |  |  | 	static const struct limits limits[] = { | 
    
    | 46 |  |  | 		/* Do not use options -H, -S or -a or change the order. */ | 
    
    | 47 |  |  | 		{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' }, | 
    
    | 48 |  |  | 		{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, | 
    
    | 49 |  |  | 		{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, | 
    
    | 50 |  |  | 		{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, | 
    
    | 51 |  |  | 		{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, | 
    
    | 52 |  |  | 		{ "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, | 
    
    | 53 |  |  | 		{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, | 
    
    | 54 |  |  | 		{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, | 
    
    | 55 |  |  | 		{ "processes", RLIMIT_NPROC, 1, 'p' }, | 
    
    | 56 |  |  | #ifdef RLIMIT_VMEM | 
    
    | 57 |  |  | 		{ "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, | 
    
    | 58 |  |  | #endif /* RLIMIT_VMEM */ | 
    
    | 59 |  |  | 		{ NULL } | 
    
    | 60 |  |  | 	}; | 
    
    | 61 |  |  | 	static char	options[4 + NELEM(limits) * 2]; | 
    
    | 62 |  | 2 | 	int		how = SOFT | HARD; | 
    
    | 63 |  |  | 	const struct limits	*l; | 
    
    | 64 |  | 2 | 	int		optc, all = 0; | 
    
    | 65 |  |  |  | 
    
    | 66 | ✓✗ | 2 | 	if (!options[0]) { | 
    
    | 67 |  |  | 		/* build options string on first call - yuck */ | 
    
    | 68 |  | 2 | 		char *p = options; | 
    
    | 69 |  |  |  | 
    
    | 70 |  | 2 | 		*p++ = 'H'; *p++ = 'S'; *p++ = 'a'; | 
    
    | 71 | ✓✓ | 20 | 		for (l = limits; l->name; l++) { | 
    
    | 72 |  | 18 | 			*p++ = l->option; | 
    
    | 73 |  | 18 | 			*p++ = '#'; | 
    
    | 74 |  |  | 		} | 
    
    | 75 |  | 2 | 		*p = '\0'; | 
    
    | 76 |  |  | 	} | 
    
    | 77 |  |  | 	/* First check for -a, -H and -S. */ | 
    
    | 78 | ✓✓ | 4 | 	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) | 
    
    | 79 | ✗✗✗✗ ✓
 | 2 | 		switch (optc) { | 
    
    | 80 |  |  | 		case 'H': | 
    
    | 81 |  |  | 			how = HARD; | 
    
    | 82 |  |  | 			break; | 
    
    | 83 |  |  | 		case 'S': | 
    
    | 84 |  |  | 			how = SOFT; | 
    
    | 85 |  |  | 			break; | 
    
    | 86 |  |  | 		case 'a': | 
    
    | 87 |  |  | 			all = 1; | 
    
    | 88 |  |  | 			break; | 
    
    | 89 |  |  | 		case '?': | 
    
    | 90 |  |  | 			return 1; | 
    
    | 91 |  |  | 		default: | 
    
    | 92 |  |  | 			break; | 
    
    | 93 |  |  | 		} | 
    
    | 94 |  |  |  | 
    
    | 95 | ✗✓ | 2 | 	if (wp[builtin_opt.optind] != NULL) { | 
    
    | 96 |  |  | 		bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]"); | 
    
    | 97 |  |  | 		return 1; | 
    
    | 98 |  |  | 	} | 
    
    | 99 |  |  |  | 
    
    | 100 |  |  | 	/* Then parse and act on the actual limits, one at a time */ | 
    
    | 101 |  | 2 | 	ksh_getopt_reset(&builtin_opt, GF_ERROR); | 
    
    | 102 | ✓✓ | 6 | 	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) | 
    
    | 103 | ✗✓✗ | 2 | 		switch (optc) { | 
    
    | 104 |  |  | 		case 'a': | 
    
    | 105 |  |  | 		case 'H': | 
    
    | 106 |  |  | 		case 'S': | 
    
    | 107 |  |  | 			break; | 
    
    | 108 |  |  | 		case '?': | 
    
    | 109 |  |  | 			return 1; | 
    
    | 110 |  |  | 		default: | 
    
    | 111 | ✓✗✓✓ 
 | 2 | 			for (l = limits; l->name && l->option != optc; l++) | 
    
    | 112 |  |  | 				; | 
    
    | 113 | ✗✓ | 2 | 			if (!l->name) { | 
    
    | 114 |  |  | 				internal_errorf(0, "ulimit: %c", optc); | 
    
    | 115 |  |  | 				return 1; | 
    
    | 116 |  |  | 			} | 
    
    | 117 | ✓✗ | 2 | 			if (builtin_opt.optarg) { | 
    
    | 118 | ✗✓ | 2 | 				if (set_ulimit(l, builtin_opt.optarg, how)) | 
    
    | 119 |  |  | 					return 1; | 
    
    | 120 |  |  | 			} else | 
    
    | 121 |  |  | 				print_ulimit(l, how); | 
    
    | 122 |  |  | 			break; | 
    
    | 123 |  |  | 		} | 
    
    | 124 |  |  |  | 
    
    | 125 |  | 2 | 	wp += builtin_opt.optind; | 
    
    | 126 |  |  |  | 
    
    | 127 | ✗✓ | 2 | 	if (all) { | 
    
    | 128 |  |  | 		for (l = limits; l->name; l++) { | 
    
    | 129 |  |  | 			shprintf("%-20s ", l->name); | 
    
    | 130 |  |  | 			print_ulimit(l, how); | 
    
    | 131 |  |  | 		} | 
    
    | 132 | ✗✓ | 2 | 	} else if (builtin_opt.optind == 1) { | 
    
    | 133 |  |  | 		/* No limit specified, use file size */ | 
    
    | 134 |  |  | 		l = &limits[1]; | 
    
    | 135 |  |  | 		if (wp[0] != NULL) { | 
    
    | 136 |  |  | 			if (set_ulimit(l, wp[0], how)) | 
    
    | 137 |  |  | 				return 1; | 
    
    | 138 |  |  | 			wp++; | 
    
    | 139 |  |  | 		} else { | 
    
    | 140 |  |  | 			print_ulimit(l, how); | 
    
    | 141 |  |  | 		} | 
    
    | 142 |  |  | 	} | 
    
    | 143 |  |  |  | 
    
    | 144 |  | 2 | 	return 0; | 
    
    | 145 |  |  | } | 
    
    | 146 |  |  |  | 
    
    | 147 |  |  | static int | 
    
    | 148 |  |  | set_ulimit(const struct limits *l, const char *v, int how) | 
    
    | 149 |  | 2 | { | 
    
    | 150 |  | 2 | 	rlim_t		val = 0; | 
    
    | 151 |  |  | 	struct rlimit	limit; | 
    
    | 152 |  |  |  | 
    
    | 153 | ✗✓ | 2 | 	if (strcmp(v, "unlimited") == 0) | 
    
    | 154 |  |  | 		val = RLIM_INFINITY; | 
    
    | 155 |  |  | 	else { | 
    
    | 156 |  |  | 		long rval; | 
    
    | 157 |  |  |  | 
    
    | 158 | ✗✓ | 2 | 		if (!evaluate(v, &rval, KSH_RETURN_ERROR, false)) | 
    
    | 159 |  |  | 			return 1; | 
    
    | 160 |  |  | 		/* | 
    
    | 161 |  |  | 		 * Avoid problems caused by typos that evaluate misses due | 
    
    | 162 |  |  | 		 * to evaluating unset parameters to 0... | 
    
    | 163 |  |  | 		 * If this causes problems, will have to add parameter to | 
    
    | 164 |  |  | 		 * evaluate() to control if unset params are 0 or an error. | 
    
    | 165 |  |  | 		 */ | 
    
    | 166 | ✓✗✗✓ 
 | 2 | 		if (!rval && !digit(v[0])) { | 
    
    | 167 |  |  | 			bi_errorf("invalid limit: %s", v); | 
    
    | 168 |  |  | 			return 1; | 
    
    | 169 |  |  | 		} | 
    
    | 170 |  | 2 | 		val = (rlim_t)rval * l->factor; | 
    
    | 171 |  |  | 	} | 
    
    | 172 |  |  |  | 
    
    | 173 |  | 2 | 	getrlimit(l->resource, &limit); | 
    
    | 174 | ✓✗ | 2 | 	if (how & SOFT) | 
    
    | 175 |  | 2 | 		limit.rlim_cur = val; | 
    
    | 176 | ✓✗ | 2 | 	if (how & HARD) | 
    
    | 177 |  | 2 | 		limit.rlim_max = val; | 
    
    | 178 | ✗✓ | 2 | 	if (setrlimit(l->resource, &limit) < 0) { | 
    
    | 179 |  |  | 		if (errno == EPERM) | 
    
    | 180 |  |  | 			bi_errorf("-%c exceeds allowable limit", l->option); | 
    
    | 181 |  |  | 		else | 
    
    | 182 |  |  | 			bi_errorf("bad -%c limit: %s", l->option, | 
    
    | 183 |  |  | 			    strerror(errno)); | 
    
    | 184 |  |  | 		return 1; | 
    
    | 185 |  |  | 	} | 
    
    | 186 |  | 2 | 	return 0; | 
    
    | 187 |  |  | } | 
    
    | 188 |  |  |  | 
    
    | 189 |  |  | static void | 
    
    | 190 |  |  | print_ulimit(const struct limits *l, int how) | 
    
    | 191 |  |  | { | 
    
    | 192 |  |  | 	rlim_t		val = 0; | 
    
    | 193 |  |  | 	struct rlimit	limit; | 
    
    | 194 |  |  |  | 
    
    | 195 |  |  | 	getrlimit(l->resource, &limit); | 
    
    | 196 |  |  | 	if (how & SOFT) | 
    
    | 197 |  |  | 		val = limit.rlim_cur; | 
    
    | 198 |  |  | 	else if (how & HARD) | 
    
    | 199 |  |  | 		val = limit.rlim_max; | 
    
    | 200 |  |  | 	if (val == RLIM_INFINITY) | 
    
    | 201 |  |  | 		shprintf("unlimited\n"); | 
    
    | 202 |  |  | 	else { | 
    
    | 203 |  |  | 		val /= l->factor; | 
    
    | 204 |  |  | 		shprintf("%ld\n", (long) val); | 
    
    | 205 |  |  | 	} | 
    
    | 206 |  |  | } |