1/* $NetBSD: c_ulimit.c,v 1.9 2008/09/14 05:00:23 sjg 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.9 2008/09/14 05:00:23 sjg 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 36extern 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 49int 50c_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_VMEM 104 { "vmemory(kbytes)", RLIMIT, RLIMIT_VMEM, RLIMIT_VMEM, 1024, 'v' }, 105#else /* RLIMIT_VMEM */ 106 /* These are not quite right - really should subtract etext or something */ 107# ifdef UL_GMEMLIM /* svr4/xenix */ 108 { "vmemory(maxaddr)", ULIMIT, UL_GMEMLIM, -1, 1, 'v' }, 109# else /* UL_GMEMLIM */ 110# ifdef UL_GETBREAK /* osf/1 */ 111 { "vmemory(maxaddr)", ULIMIT, UL_GETBREAK, -1, 1, 'v' }, 112# else /* UL_GETBREAK */ 113# ifdef UL_GETMAXBRK /* hpux */ 114 { "vmemory(maxaddr)", ULIMIT, UL_GETMAXBRK, -1, 1, 'v' }, 115# endif /* UL_GETMAXBRK */ 116# endif /* UL_GETBREAK */ 117# endif /* UL_GMEMLIM */ 118#endif /* RLIMIT_VMEM */ 119#ifdef RLIMIT_SWAP 120 { "swap(kbytes)", RLIMIT, RLIMIT_SWAP, RLIMIT_SWAP, 1024, 'w' }, 121#endif 122#ifdef RLIMIT_SBSIZE 123 { "sbsize(bytes)", RLIMIT, RLIMIT_SBSIZE, RLIMIT_SBSIZE, 1, 'b' }, 124#endif 125 { .name = NULL } 126 }; 127 static char options[3 + NELEM(limits)]; 128 rlim_t UNINITIALIZED(val); 129 int how = SOFT | HARD; 130 const struct limits *l; 131 int set, all = 0; 132 int optc, what; 133#ifdef HAVE_SETRLIMIT 134 struct rlimit limit; 135#endif /* HAVE_SETRLIMIT */ 136 137 if (!options[0]) { 138 /* build options string on first call - yuck */ 139 char *p = options; 140 141 *p++ = 'H'; *p++ = 'S'; *p++ = 'a'; 142 for (l = limits; l->name; l++) 143 *p++ = l->option; 144 *p = '\0'; 145 } 146 what = 'f'; 147 while ((optc = ksh_getopt(wp, &builtin_opt, options)) != EOF) 148 switch (optc) { 149 case 'H': 150 how = HARD; 151 break; 152 case 'S': 153 how = SOFT; 154 break; 155 case 'a': 156 all = 1; 157 break; 158 case '?': 159 return 1; 160 default: 161 what = optc; 162 } 163 164 for (l = limits; l->name && l->option != what; l++) 165 ; 166 if (!l->name) { 167 internal_errorf(0, "ulimit: %c", what); 168 return 1; 169 } 170 171 wp += builtin_opt.optind; 172 set = *wp ? 1 : 0; 173 if (set) { 174 if (all || wp[1]) { 175 bi_errorf("too many arguments"); 176 return 1; 177 } 178 if (strcmp(wp[0], "unlimited") == 0) 179 val = KSH_RLIM_INFINITY; 180 else { 181 long rval; 182 183 if (!evaluate(wp[0], &rval, KSH_RETURN_ERROR)) 184 return 1; 185 /* Avoid problems caused by typos that 186 * evaluate misses due to evaluating unset 187 * parameters to 0... 188 * If this causes problems, will have to 189 * add parameter to evaluate() to control 190 * if unset params are 0 or an error. 191 */ 192 if (!rval && !digit(wp[0][0])) { 193 bi_errorf("invalid limit: %s", wp[0]); 194 return 1; 195 } 196 val = (u_long)rval * l->factor; 197 } 198 } 199 if (all) { 200 for (l = limits; l->name; l++) { 201#ifdef HAVE_SETRLIMIT 202 if (l->which == RLIMIT) { 203 getrlimit(l->gcmd, &limit); 204 if (how & SOFT) 205 val = limit.rlim_cur; 206 else if (how & HARD) 207 val = limit.rlim_max; 208 } else 209#endif /* HAVE_SETRLIMIT */ 210#ifdef HAVE_ULIMIT 211 { 212 val = ulimit(l->gcmd, (rlim_t) 0); 213 } 214#else /* HAVE_ULIMIT */ 215 ; 216#endif /* HAVE_ULIMIT */ 217 shprintf("%-20s ", l->name); 218#ifdef RLIM_INFINITY 219 if (val == RLIM_INFINITY) 220 shprintf("unlimited\n"); 221 else 222#endif /* RLIM_INFINITY */ 223 { 224 val /= l->factor; 225 shprintf("%ld\n", (long) val); 226 } 227 } 228 return 0; 229 } 230#ifdef HAVE_SETRLIMIT 231 if (l->which == RLIMIT) { 232 getrlimit(l->gcmd, &limit); 233 if (set) { 234 if (how & SOFT) 235 limit.rlim_cur = val; 236 if (how & HARD) 237 limit.rlim_max = val; 238 if (setrlimit(l->scmd, &limit) < 0) { 239 if (errno == EPERM) 240 bi_errorf("exceeds allowable limit"); 241 else 242 bi_errorf("bad limit: %s", 243 strerror(errno)); 244 return 1; 245 } 246 } else { 247 if (how & SOFT) 248 val = limit.rlim_cur; 249 else if (how & HARD) 250 val = limit.rlim_max; 251 } 252 } else 253#endif /* HAVE_SETRLIMIT */ 254#ifdef HAVE_ULIMIT 255 { 256 if (set) { 257 if (l->scmd == -1) { 258 bi_errorf("can't change limit"); 259 return 1; 260 } else if (ulimit(l->scmd, val) < 0) { 261 bi_errorf("bad limit: %s", strerror(errno)); 262 return 1; 263 } 264 } else 265 val = ulimit(l->gcmd, (rlim_t) 0); 266 } 267#else /* HAVE_ULIMIT */ 268 ; 269#endif /* HAVE_ULIMIT */ 270 if (!set) { 271#ifdef RLIM_INFINITY 272 if (val == RLIM_INFINITY) 273 shprintf("unlimited\n"); 274 else 275#endif /* RLIM_INFINITY */ 276 { 277 val /= l->factor; 278 shprintf("%ld\n", (long) val); 279 } 280 } 281 return 0; 282} 283