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