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