1 /* $NetBSD: c_ulimit.c,v 1.12 2015/05/09 13:26:06 christos 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 #include <sys/cdefs.h> 21 22 #ifndef lint 23 __RCSID("$NetBSD: c_ulimit.c,v 1.12 2015/05/09 13:26:06 christos Exp $"); 24 #endif 25 26 27 #include "sh.h" 28 #include "ksh_time.h" 29 #ifdef HAVE_SYS_RESOURCE_H 30 # include <sys/resource.h> 31 #endif /* HAVE_SYS_RESOURCE_H */ 32 #ifdef HAVE_ULIMIT_H 33 # include <ulimit.h> 34 #else /* HAVE_ULIMIT_H */ 35 # ifdef HAVE_ULIMIT 36 extern long ulimit(); 37 # endif /* HAVE_ULIMIT */ 38 #endif /* HAVE_ULIMIT_H */ 39 40 #define SOFT 0x1 41 #define HARD 0x2 42 43 #ifdef RLIM_INFINITY 44 # define KSH_RLIM_INFINITY RLIM_INFINITY 45 #else 46 # define KSH_RLIM_INFINITY ((rlim_t) 1 << (sizeof(rlim_t) * 8 - 1) - 1) 47 #endif /* RLIM_INFINITY */ 48 49 int 50 c_ulimit(wp) 51 char **wp; 52 { 53 static const struct limits { 54 const char *name; 55 enum { RLIMIT, ULIMIT } which; 56 int gcmd; /* get command */ 57 int scmd; /* set command (or -1, if no set command) */ 58 int factor; /* multiply by to get rlim_{cur,max} values */ 59 char option; 60 } limits[] = { 61 /* Do not use options -H, -S or -a */ 62 #ifdef RLIMIT_CPU 63 { "time(cpu-seconds)", RLIMIT, RLIMIT_CPU, RLIMIT_CPU, 1, 't' }, 64 #endif 65 #ifdef RLIMIT_FSIZE 66 { "file(blocks)", RLIMIT, RLIMIT_FSIZE, RLIMIT_FSIZE, 512, 'f' }, 67 #else /* RLIMIT_FSIZE */ 68 # ifdef UL_GETFSIZE /* x/open */ 69 { "file(blocks)", ULIMIT, UL_GETFSIZE, UL_SETFSIZE, 1, 'f' }, 70 # else /* UL_GETFSIZE */ 71 # ifdef UL_GFILLIM /* svr4/xenix */ 72 { "file(blocks)", ULIMIT, UL_GFILLIM, UL_SFILLIM, 1, 'f' }, 73 # else /* UL_GFILLIM */ 74 { "file(blocks)", ULIMIT, 1, 2, 1, 'f' }, 75 # endif /* UL_GFILLIM */ 76 # endif /* UL_GETFSIZE */ 77 #endif /* RLIMIT_FSIZE */ 78 #ifdef RLIMIT_CORE 79 { "coredump(blocks)", RLIMIT, RLIMIT_CORE, RLIMIT_CORE, 512, 'c' }, 80 #endif 81 #ifdef RLIMIT_DATA 82 { "data(kbytes)", RLIMIT, RLIMIT_DATA, RLIMIT_DATA, 1024, 'd' }, 83 #endif 84 #ifdef RLIMIT_STACK 85 { "stack(kbytes)", RLIMIT, RLIMIT_STACK, RLIMIT_STACK, 1024, 's' }, 86 #endif 87 #ifdef RLIMIT_MEMLOCK 88 { "lockedmem(kbytes)", RLIMIT, RLIMIT_MEMLOCK, RLIMIT_MEMLOCK, 1024, 'l' }, 89 #endif 90 #ifdef RLIMIT_RSS 91 { "memory(kbytes)", RLIMIT, RLIMIT_RSS, RLIMIT_RSS, 1024, 'm' }, 92 #endif 93 #ifdef RLIMIT_NOFILE 94 { "nofiles(descriptors)", RLIMIT, RLIMIT_NOFILE, RLIMIT_NOFILE, 1, 'n' }, 95 #else /* RLIMIT_NOFILE */ 96 # ifdef UL_GDESLIM /* svr4/xenix */ 97 { "nofiles(descriptors)", ULIMIT, UL_GDESLIM, -1, 1, 'n' }, 98 # endif /* UL_GDESLIM */ 99 #endif /* RLIMIT_NOFILE */ 100 #ifdef RLIMIT_NPROC 101 { "processes", RLIMIT, RLIMIT_NPROC, RLIMIT_NPROC, 1, 'p' }, 102 #endif 103 #ifdef RLIMIT_NTHR 104 { "threads", RLIMIT, RLIMIT_NTHR, RLIMIT_NTHR, 1, 'r' }, 105 #endif 106 #ifdef RLIMIT_VMEM 107 { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' }, 108 #else /* RLIMIT_VMEM */ 109 /* These are not quite right - really should subtract etext or something */ 110 # ifdef UL_GMEMLIM /* svr4/xenix */ 111 { "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' }, 112 # else /* UL_GMEMLIM */ 113 # ifdef UL_GETBREAK /* osf/1 */ 114 { "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' }, 115 # else /* UL_GETBREAK */ 116 # ifdef UL_GETMAXBRK /* hpux */ 117 { "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' }, 118 # endif /* UL_GETMAXBRK */ 119 # endif /* UL_GETBREAK */ 120 # endif /* UL_GMEMLIM */ 121 #endif /* RLIMIT_VMEM */ 122 #ifdef RLIMIT_SWAP 123 { "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' }, 124 #endif 125 #ifdef RLIMIT_SBSIZE 126 { "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' }, 127 #endif 128 { .name = NULL } 129 }; 130 static char options[3 + NELEM(limits)]; 131 rlim_t UNINITIALIZED(val); 132 int how = SOFT | HARD; 133 const struct limits *l; 134 int set, all = 0; 135 int optc, what; 136 #ifdef HAVE_SETRLIMIT 137 struct rlimit limit; 138 #endif /* HAVE_SETRLIMIT */ 139 140 if (!options[0]) { 141 /* build options string on first call - yuck */ 142 char *p = options; 143 144 *p++ = 'H'; *p++ = 'S'; *p++ = 'a'; 145 for (l = limits; l->name; l++) 146 *p++ = l->option; 147 *p = '\0'; 148 } 149 what = 'f'; 150 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) 151 switch (optc) { 152 case 'H': 153 how = HARD; 154 break; 155 case 'S': 156 how = SOFT; 157 break; 158 case 'a': 159 all = 1; 160 break; 161 case '?': 162 return 1; 163 default: 164 what = optc; 165 } 166 167 for (l = limits; l->name && l->option != what; l++) 168 ; 169 if (!l->name) { 170 internal_errorf(0, "ulimit: %c", what); 171 return 1; 172 } 173 174 wp += builtin_opt.optind; 175 set = *wp ? 1 : 0; 176 if (set) { 177 if (all || wp[1]) { 178 bi_errorf("too many arguments"); 179 return 1; 180 } 181 if (strcmp(wp[0], "unlimited") == 0) 182 val = KSH_RLIM_INFINITY; 183 else { 184 long rval; 185 186 if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR)) 187 return 1; 188 /* Avoid problems caused by typos that 189 * evaluate misses due to evaluating unset 190 * parameters to 0... 191 * If this causes problems, will have to 192 * add parameter to evaluate() to control 193 * if unset params are 0 or an error. 194 */ 195 if (!rval && !digit(wp[0][0])) { 196 bi_errorf("invalid limit: %s", wp[0]); 197 return 1; 198 } 199 val = (u_long)rval * l->factor; 200 } 201 } 202 if (all) { 203 for (l = limits; l->name; l++) { 204 #ifdef HAVE_SETRLIMIT 205 if (l->which == RLIMIT) { 206 if (getrlimit(l->gcmd, &limit) == -1) { 207 bi_errorf("can't get limit: %s", 208 strerror(errno)); 209 return 1; 210 } 211 if (how & SOFT) 212 val = limit.rlim_cur; 213 else if (how & HARD) 214 val = limit.rlim_max; 215 } else 216 #endif /* HAVE_SETRLIMIT */ 217 #ifdef HAVE_ULIMIT 218 { 219 val = ulimit(l->gcmd, (rlim_t) 0); 220 } 221 #else /* HAVE_ULIMIT */ 222 ; 223 #endif /* HAVE_ULIMIT */ 224 shprintf("%-20s ", l->name); 225 #ifdef RLIM_INFINITY 226 if (val == RLIM_INFINITY) 227 shprintf("unlimited\n"); 228 else 229 #endif /* RLIM_INFINITY */ 230 { 231 val /= l->factor; 232 shprintf("%ld\n", (long) val); 233 } 234 } 235 return 0; 236 } 237 #ifdef HAVE_SETRLIMIT 238 if (l->which == RLIMIT) { 239 if (getrlimit(l->gcmd, &limit) == -1) { 240 bi_errorf("can't get limit: %s", strerror(errno)); 241 return 1; 242 } 243 if (set) { 244 if (how & SOFT) 245 limit.rlim_cur = val; 246 if (how & HARD) 247 limit.rlim_max = val; 248 if (setrlimit(l->scmd, &limit) < 0) { 249 if (errno == EPERM) 250 bi_errorf("exceeds allowable limit"); 251 else 252 bi_errorf("bad limit: %s", 253 strerror(errno)); 254 return 1; 255 } 256 } else { 257 if (how & SOFT) 258 val = limit.rlim_cur; 259 else if (how & HARD) 260 val = limit.rlim_max; 261 } 262 } else 263 #endif /* HAVE_SETRLIMIT */ 264 #ifdef HAVE_ULIMIT 265 { 266 if (set) { 267 if (l->scmd == -1) { 268 bi_errorf("can't change limit"); 269 return 1; 270 } else if (ulimit(l->scmd, val) < 0) { 271 bi_errorf("bad limit: %s", strerror(errno)); 272 return 1; 273 } 274 } else 275 val = ulimit(l->gcmd, (rlim_t) 0); 276 } 277 #else /* HAVE_ULIMIT */ 278 ; 279 #endif /* HAVE_ULIMIT */ 280 if (!set) { 281 #ifdef RLIM_INFINITY 282 if (val == RLIM_INFINITY) 283 shprintf("unlimited\n"); 284 else 285 #endif /* RLIM_INFINITY */ 286 { 287 val /= l->factor; 288 shprintf("%ld\n", (long) val); 289 } 290 } 291 return 0; 292 } 293