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