1/* ulimit.c, created from ulimit.def. */ 2#line 23 "ulimit.def" 3 4#line 61 "ulimit.def" 5 6#if !defined (_MINIX) 7 8#include <config.h> 9 10#include "../bashtypes.h" 11#ifndef _MINIX 12# include <sys/param.h> 13#endif 14 15#if defined (HAVE_UNISTD_H) 16# include <unistd.h> 17#endif 18 19#include <stdio.h> 20#include <errno.h> 21 22#include "../bashintl.h" 23 24#include "../shell.h" 25#include "common.h" 26#include "bashgetopt.h" 27#include "pipesize.h" 28 29#if !defined (errno) 30extern int errno; 31#endif 32 33/* For some reason, HPUX chose to make these definitions visible only if 34 _KERNEL is defined, so we define _KERNEL before including <sys/resource.h> 35 and #undef it afterward. */ 36#if defined (HAVE_RESOURCE) 37# include <sys/time.h> 38# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) 39# define _KERNEL 40# endif 41# include <sys/resource.h> 42# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL) 43# undef _KERNEL 44# endif 45#else 46# include <sys/times.h> 47#endif 48 49#if defined (HAVE_LIMITS_H) 50# include <limits.h> 51#endif 52 53/* Check for the most basic symbols. If they aren't present, this 54 system's <sys/resource.h> isn't very useful to us. */ 55#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT) 56# undef HAVE_RESOURCE 57#endif 58 59#if !defined (RLIMTYPE) 60# define RLIMTYPE long 61# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10) 62# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "") 63#endif 64 65/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */ 66#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE) 67# define RLIMIT_NOFILE RLIMIT_OFILE 68#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */ 69 70/* Some systems have these, some do not. */ 71#ifdef RLIMIT_FSIZE 72# define RLIMIT_FILESIZE RLIMIT_FSIZE 73#else 74# define RLIMIT_FILESIZE 256 75#endif 76 77#define RLIMIT_PIPESIZE 257 78 79#ifdef RLIMIT_NOFILE 80# define RLIMIT_OPENFILES RLIMIT_NOFILE 81#else 82# define RLIMIT_OPENFILES 258 83#endif 84 85#ifdef RLIMIT_VMEM 86# define RLIMIT_VIRTMEM RLIMIT_VMEM 87# define RLIMIT_VMBLKSZ 1024 88#else 89# ifdef RLIMIT_AS 90# define RLIMIT_VIRTMEM RLIMIT_AS 91# define RLIMIT_VMBLKSZ 1024 92# else 93# define RLIMIT_VIRTMEM 259 94# define RLIMIT_VMBLKSZ 1 95# endif 96#endif 97 98#ifdef RLIMIT_NPROC 99# define RLIMIT_MAXUPROC RLIMIT_NPROC 100#else 101# define RLIMIT_MAXUPROC 260 102#endif 103 104#if !defined (RLIM_INFINITY) 105# define RLIM_INFINITY 0x7fffffff 106#endif 107 108#if !defined (RLIM_SAVED_CUR) 109# define RLIM_SAVED_CUR RLIM_INFINITY 110#endif 111 112#if !defined (RLIM_SAVED_MAX) 113# define RLIM_SAVED_MAX RLIM_INFINITY 114#endif 115 116#define LIMIT_HARD 0x01 117#define LIMIT_SOFT 0x02 118 119static int _findlim __P((int)); 120 121static int ulimit_internal __P((int, char *, int, int)); 122 123static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *)); 124static int set_limit __P((int, RLIMTYPE, int)); 125 126static void printone __P((int, RLIMTYPE, int)); 127static void print_all_limits __P((int)); 128 129static int set_all_limits __P((int, RLIMTYPE)); 130 131static int filesize __P((RLIMTYPE *)); 132static int pipesize __P((RLIMTYPE *)); 133static int getmaxuprc __P((RLIMTYPE *)); 134static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *)); 135 136typedef struct { 137 int option; /* The ulimit option for this limit. */ 138 int parameter; /* Parameter to pass to get_limit (). */ 139 int block_factor; /* Blocking factor for specific limit. */ 140 char *description; /* Descriptive string to output. */ 141 char *units; /* scale */ 142} RESOURCE_LIMITS; 143 144static RESOURCE_LIMITS limits[] = { 145#ifdef RLIMIT_CORE 146 { 'c', RLIMIT_CORE, 1024, "core file size", "blocks" }, 147#endif 148#ifdef RLIMIT_DATA 149 { 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" }, 150#endif 151#ifdef RLIMIT_NICE 152 { 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL }, 153#endif 154 { 'f', RLIMIT_FILESIZE, 1024, "file size", "blocks" }, 155#ifdef RLIMIT_SIGPENDING 156 { 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL }, 157#endif 158#ifdef RLIMIT_MEMLOCK 159 { 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" }, 160#endif 161#ifdef RLIMIT_RSS 162 { 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" }, 163#endif /* RLIMIT_RSS */ 164 { 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL}, 165 { 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" }, 166#ifdef RLIMIT_MSGQUEUE 167 { 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" }, 168#endif 169#ifdef RLIMIT_RTPRIO 170 { 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL }, 171#endif 172#ifdef RLIMIT_STACK 173 { 's', RLIMIT_STACK, 1024, "stack size", "kbytes" }, 174#endif 175#ifdef RLIMIT_CPU 176 { 't', RLIMIT_CPU, 1, "cpu time", "seconds" }, 177#endif /* RLIMIT_CPU */ 178 { 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL }, 179#if defined (HAVE_RESOURCE) 180 { 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" }, 181#endif 182#ifdef RLIMIT_SWAP 183 { 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" }, 184#endif 185#ifdef RLIMIT_LOCKS 186 { 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL }, 187#endif 188 { -1, -1, -1, (char *)NULL, (char *)NULL } 189}; 190#define NCMDS (sizeof(limits) / sizeof(limits[0])) 191 192typedef struct _cmd { 193 int cmd; 194 char *arg; 195} ULCMD; 196 197static ULCMD *cmdlist; 198static int ncmd; 199static int cmdlistsz; 200 201#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT) 202long 203ulimit (cmd, newlim) 204 int cmd; 205 long newlim; 206{ 207 errno = EINVAL; 208 return -1; 209} 210#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */ 211 212static int 213_findlim (opt) 214 int opt; 215{ 216 register int i; 217 218 for (i = 0; limits[i].option > 0; i++) 219 if (limits[i].option == opt) 220 return i; 221 return -1; 222} 223 224static char optstring[4 + 2 * NCMDS]; 225 226/* Report or set limits associated with certain per-process resources. 227 See the help documentation in builtins.c for a full description. */ 228int 229ulimit_builtin (list) 230 register WORD_LIST *list; 231{ 232 register char *s; 233 int c, limind, mode, opt, all_limits; 234 235 mode = 0; 236 237 all_limits = 0; 238 239 /* Idea stolen from pdksh -- build option string the first time called. */ 240 if (optstring[0] == 0) 241 { 242 s = optstring; 243 *s++ = 'a'; *s++ = 'S'; *s++ = 'H'; 244 for (c = 0; limits[c].option > 0; c++) 245 { 246 *s++ = limits[c].option; 247 *s++ = ';'; 248 } 249 *s = '\0'; 250 } 251 252 /* Initialize the command list. */ 253 if (cmdlistsz == 0) 254 cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD)); 255 ncmd = 0; 256 257 reset_internal_getopt (); 258 while ((opt = internal_getopt (list, optstring)) != -1) 259 { 260 switch (opt) 261 { 262 case 'a': 263 all_limits++; 264 break; 265 266 /* -S and -H are modifiers, not real options. */ 267 case 'S': 268 mode |= LIMIT_SOFT; 269 break; 270 271 case 'H': 272 mode |= LIMIT_HARD; 273 break; 274 275 case '?': 276 builtin_usage (); 277 return (EX_USAGE); 278 279 default: 280 if (ncmd >= cmdlistsz) 281 cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD)); 282 cmdlist[ncmd].cmd = opt; 283 cmdlist[ncmd++].arg = list_optarg; 284 break; 285 } 286 } 287 list = loptend; 288 289 if (all_limits) 290 { 291#ifdef NOTYET 292 if (list) /* setting */ 293 { 294 if (STREQ (list->word->word, "unlimited") == 0) 295 { 296 builtin_error (_("%s: invalid limit argument"), list->word->word); 297 return (EXECUTION_FAILURE); 298 } 299 return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY)); 300 } 301#endif 302 print_all_limits (mode == 0 ? LIMIT_SOFT : mode); 303 return (EXECUTION_SUCCESS); 304 } 305 306 /* default is `ulimit -f' */ 307 if (ncmd == 0) 308 { 309 cmdlist[ncmd].cmd = 'f'; 310 /* `ulimit something' is same as `ulimit -f something' */ 311 cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL; 312 if (list) 313 list = list->next; 314 } 315 316 /* verify each command in the list. */ 317 for (c = 0; c < ncmd; c++) 318 { 319 limind = _findlim (cmdlist[c].cmd); 320 if (limind == -1) 321 { 322 builtin_error (_("`%c': bad command"), cmdlist[c].cmd); 323 return (EX_USAGE); 324 } 325 } 326 327 for (c = 0; c < ncmd; c++) 328 if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE) 329 return (EXECUTION_FAILURE); 330 331 return (EXECUTION_SUCCESS); 332} 333 334static int 335ulimit_internal (cmd, cmdarg, mode, multiple) 336 int cmd; 337 char *cmdarg; 338 int mode, multiple; 339{ 340 int opt, limind, setting; 341 int block_factor; 342 RLIMTYPE soft_limit, hard_limit, real_limit, limit; 343 344 setting = cmdarg != 0; 345 limind = _findlim (cmd); 346 if (mode == 0) 347 mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT; 348 opt = get_limit (limind, &soft_limit, &hard_limit); 349 if (opt < 0) 350 { 351 builtin_error (_("%s: cannot get limit: %s"), limits[limind].description, 352 strerror (errno)); 353 return (EXECUTION_FAILURE); 354 } 355 356 if (setting == 0) /* print the value of the specified limit */ 357 { 358 printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple); 359 return (EXECUTION_SUCCESS); 360 } 361 362 /* Setting the limit. */ 363 if (STREQ (cmdarg, "hard")) 364 real_limit = hard_limit; 365 else if (STREQ (cmdarg, "soft")) 366 real_limit = soft_limit; 367 else if (STREQ (cmdarg, "unlimited")) 368 real_limit = RLIM_INFINITY; 369 else if (all_digits (cmdarg)) 370 { 371 limit = string_to_rlimtype (cmdarg); 372 block_factor = limits[limind].block_factor; 373 real_limit = limit * block_factor; 374 375 if ((real_limit / block_factor) != limit) 376 { 377 sh_erange (cmdarg, "limit"); 378 return (EXECUTION_FAILURE); 379 } 380 } 381 else 382 { 383 sh_invalidnum (cmdarg); 384 return (EXECUTION_FAILURE); 385 } 386 387 if (set_limit (limind, real_limit, mode) < 0) 388 { 389 builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description, 390 strerror (errno)); 391 return (EXECUTION_FAILURE); 392 } 393 394 return (EXECUTION_SUCCESS); 395} 396 397static int 398get_limit (ind, softlim, hardlim) 399 int ind; 400 RLIMTYPE *softlim, *hardlim; 401{ 402 RLIMTYPE value; 403#if defined (HAVE_RESOURCE) 404 struct rlimit limit; 405#endif 406 407 if (limits[ind].parameter >= 256) 408 { 409 switch (limits[ind].parameter) 410 { 411 case RLIMIT_FILESIZE: 412 if (filesize (&value) < 0) 413 return -1; 414 break; 415 case RLIMIT_PIPESIZE: 416 if (pipesize (&value) < 0) 417 return -1; 418 break; 419 case RLIMIT_OPENFILES: 420 value = (RLIMTYPE)getdtablesize (); 421 break; 422 case RLIMIT_VIRTMEM: 423 return (getmaxvm (softlim, hardlim)); 424 case RLIMIT_MAXUPROC: 425 if (getmaxuprc (&value) < 0) 426 return -1; 427 break; 428 default: 429 errno = EINVAL; 430 return -1; 431 } 432 *softlim = *hardlim = value; 433 return (0); 434 } 435 else 436 { 437#if defined (HAVE_RESOURCE) 438 if (getrlimit (limits[ind].parameter, &limit) < 0) 439 return -1; 440 *softlim = limit.rlim_cur; 441 *hardlim = limit.rlim_max; 442# if defined (HPUX9) 443 if (limits[ind].parameter == RLIMIT_FILESIZE) 444 { 445 *softlim *= 512; 446 *hardlim *= 512; /* Ugh. */ 447 } 448 else 449# endif /* HPUX9 */ 450 return 0; 451#else 452 errno = EINVAL; 453 return -1; 454#endif 455 } 456} 457 458static int 459set_limit (ind, newlim, mode) 460 int ind; 461 RLIMTYPE newlim; 462 int mode; 463{ 464#if defined (HAVE_RESOURCE) 465 struct rlimit limit; 466 RLIMTYPE val; 467#endif 468 469 if (limits[ind].parameter >= 256) 470 switch (limits[ind].parameter) 471 { 472 case RLIMIT_FILESIZE: 473#if !defined (HAVE_RESOURCE) 474 return (ulimit (2, newlim / 512L)); 475#else 476 errno = EINVAL; 477 return -1; 478#endif 479 480 case RLIMIT_OPENFILES: 481#if defined (HAVE_SETDTABLESIZE) 482# if defined (__CYGWIN__) 483 /* Grrr... Cygwin declares setdtablesize as void. */ 484 setdtablesize (newlim); 485 return 0; 486# else 487 return (setdtablesize (newlim)); 488# endif 489#endif 490 case RLIMIT_PIPESIZE: 491 case RLIMIT_VIRTMEM: 492 case RLIMIT_MAXUPROC: 493 default: 494 errno = EINVAL; 495 return -1; 496 } 497 else 498 { 499#if defined (HAVE_RESOURCE) 500 if (getrlimit (limits[ind].parameter, &limit) < 0) 501 return -1; 502# if defined (HPUX9) 503 if (limits[ind].parameter == RLIMIT_FILESIZE) 504 newlim /= 512; /* Ugh. */ 505# endif /* HPUX9 */ 506 val = (current_user.euid != 0 && newlim == RLIM_INFINITY && 507 (mode & LIMIT_HARD) == 0 && /* XXX -- test */ 508 (limit.rlim_cur <= limit.rlim_max)) 509 ? limit.rlim_max : newlim; 510 if (mode & LIMIT_SOFT) 511 limit.rlim_cur = val; 512 if (mode & LIMIT_HARD) 513 limit.rlim_max = val; 514 515 return (setrlimit (limits[ind].parameter, &limit)); 516#else 517 errno = EINVAL; 518 return -1; 519#endif 520 } 521} 522 523static int 524getmaxvm (softlim, hardlim) 525 RLIMTYPE *softlim, *hardlim; 526{ 527#if defined (HAVE_RESOURCE) 528 struct rlimit datalim, stacklim; 529 530 if (getrlimit (RLIMIT_DATA, &datalim) < 0) 531 return -1; 532 533 if (getrlimit (RLIMIT_STACK, &stacklim) < 0) 534 return -1; 535 536 /* Protect against overflow. */ 537 *softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L); 538 *hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L); 539 return 0; 540#else 541 errno = EINVAL; 542 return -1; 543#endif /* HAVE_RESOURCE */ 544} 545 546static int 547filesize(valuep) 548 RLIMTYPE *valuep; 549{ 550#if !defined (HAVE_RESOURCE) 551 long result; 552 if ((result = ulimit (1, 0L)) < 0) 553 return -1; 554 else 555 *valuep = (RLIMTYPE) result * 512; 556 return 0; 557#else 558 errno = EINVAL; 559 return -1; 560#endif 561} 562 563static int 564pipesize (valuep) 565 RLIMTYPE *valuep; 566{ 567#if defined (PIPE_BUF) 568 /* This is defined on Posix systems. */ 569 *valuep = (RLIMTYPE) PIPE_BUF; 570 return 0; 571#else 572# if defined (_POSIX_PIPE_BUF) 573 *valuep = (RLIMTYPE) _POSIX_PIPE_BUF; 574 return 0; 575# else 576# if defined (PIPESIZE) 577 /* This is defined by running a program from the Makefile. */ 578 *valuep = (RLIMTYPE) PIPESIZE; 579 return 0; 580# else 581 errno = EINVAL; 582 return -1; 583# endif /* PIPESIZE */ 584# endif /* _POSIX_PIPE_BUF */ 585#endif /* PIPE_BUF */ 586} 587 588static int 589getmaxuprc (valuep) 590 RLIMTYPE *valuep; 591{ 592 long maxchild; 593 594 maxchild = getmaxchild (); 595 if (maxchild < 0) 596 { 597 errno = EINVAL; 598 return -1; 599 } 600 else 601 { 602 *valuep = (RLIMTYPE) maxchild; 603 return 0; 604 } 605} 606 607static void 608print_all_limits (mode) 609 int mode; 610{ 611 register int i; 612 RLIMTYPE softlim, hardlim; 613 614 if (mode == 0) 615 mode |= LIMIT_SOFT; 616 617 for (i = 0; limits[i].option > 0; i++) 618 { 619 if (get_limit (i, &softlim, &hardlim) == 0) 620 printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1); 621 else if (errno != EINVAL) 622 builtin_error ("%s: cannot get limit: %s", limits[i].description, 623 strerror (errno)); 624 } 625} 626 627static void 628printone (limind, curlim, pdesc) 629 int limind; 630 RLIMTYPE curlim; 631 int pdesc; 632{ 633 char unitstr[64]; 634 635 if (pdesc) 636 { 637 if (limits[limind].units) 638 sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option); 639 else 640 sprintf (unitstr, "(-%c) ", limits[limind].option); 641 642 printf ("%-20s %16s", limits[limind].description, unitstr); 643 } 644 if (curlim == RLIM_INFINITY) 645 puts ("unlimited"); 646 else if (curlim == RLIM_SAVED_MAX) 647 puts ("hard"); 648 else if (curlim == RLIM_SAVED_CUR) 649 puts ("soft"); 650 else 651 print_rlimtype ((curlim / limits[limind].block_factor), 1); 652} 653 654/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which 655 causes all limits to be set as high as possible depending on mode (like 656 csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits 657 were set successfully, and 1 if at least one limit could not be set. 658 659 To raise all soft limits to their corresponding hard limits, use 660 ulimit -S -a unlimited 661 To attempt to raise all hard limits to infinity (superuser-only), use 662 ulimit -H -a unlimited 663 To attempt to raise all soft and hard limits to infinity, use 664 ulimit -a unlimited 665*/ 666 667static int 668set_all_limits (mode, newlim) 669 int mode; 670 RLIMTYPE newlim; 671{ 672 register int i; 673 int retval = 0; 674 675 if (newlim != RLIM_INFINITY) 676 { 677 errno = EINVAL; 678 return -1; 679 } 680 681 if (mode == 0) 682 mode = LIMIT_SOFT|LIMIT_HARD; 683 684 for (retval = i = 0; limits[i].option > 0; i++) 685 if (set_limit (i, newlim, mode) < 0) 686 { 687 builtin_error ("%s: cannot modify limit: %s", limits[i].description, 688 strerror (errno)); 689 retval = 1; 690 } 691 return retval; 692} 693 694#endif /* !_MINIX */ 695