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