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