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 { 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 int how = SOFT | HARD; 63 const struct limits *l; 64 int optc, all = 0; 65 66 if (!options[0]) { 67 /* build options string on first call - yuck */ 68 char *p = options; 69 70 *p++ = 'H'; *p++ = 'S'; *p++ = 'a'; 71 for (l = limits; l->name; l++) { 72 *p++ = l->option; 73 *p++ = '#'; 74 } 75 *p = '\0'; 76 } 77 /* First check for -a, -H and -S. */ 78 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) 79 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 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 ksh_getopt_reset(&builtin_opt, GF_ERROR); 102 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1) 103 switch (optc) { 104 case 'a': 105 case 'H': 106 case 'S': 107 break; 108 case '?': 109 return 1; 110 default: 111 for (l = limits; l->name && l->option != optc; l++) 112 ; 113 if (!l->name) { 114 internal_errorf(0, "ulimit: %c", optc); 115 return 1; 116 } 117 if (builtin_opt.optarg) { 118 if (set_ulimit(l, builtin_opt.optarg, how)) 119 return 1; 120 } else 121 print_ulimit(l, how); 122 break; 123 } 124 125 wp += builtin_opt.optind; 126 127 if (all) { 128 for (l = limits; l->name; l++) { 129 shprintf("%-20s ", l->name); 130 print_ulimit(l, how); 131 } 132 } 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 return 0; 145 } 146 147 static int 148 set_ulimit(const struct limits *l, const char *v, int how) 149 { 150 rlim_t val = 0; 151 struct rlimit limit; 152 153 if (strcmp(v, "unlimited") == 0) 154 val = RLIM_INFINITY; 155 else { 156 long rval; 157 158 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 if (!rval && !digit(v[0])) { 167 bi_errorf("invalid limit: %s", v); 168 return 1; 169 } 170 val = (rlim_t)rval * l->factor; 171 } 172 173 getrlimit(l->resource, &limit); 174 if (how & SOFT) 175 limit.rlim_cur = val; 176 if (how & HARD) 177 limit.rlim_max = val; 178 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 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 } 207