546dfd4f38ea77ec3bfd5fe963ca1ce93d0795c9
[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 1, 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, 675 Mass Ave, Cambridge, MA 02139, 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 Otherwise, the current value of the specified resource is printed.
49 If no option is given, then -f is assumed.  Values are in 1024-byte
50 increments, except for -t, which is in seconds, -p, which is in
51 increments of 512 bytes, and -u, which is an unscaled number of
52 processes.
53 $END
54
55 #include <config.h>
56
57 #include "../bashtypes.h"
58 #include <sys/param.h>
59
60 #if defined (HAVE_UNISTD_H)
61 #  include <unistd.h>
62 #endif
63
64 #include <stdio.h>
65 #include <errno.h>
66
67 #include "../shell.h"
68 #include "common.h"
69 #include "bashgetopt.h"
70 #include "pipesize.h"
71
72 #if !defined (errno)
73 extern int errno;
74 #endif
75
76 /* For some reason, HPUX chose to make these definitions visible only if
77    _KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
78    and #undef it afterward. */
79 #if defined (HAVE_RESOURCE)
80 #  include <sys/time.h>
81 #  if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
82 #    define _KERNEL
83 #  endif
84 #  include <sys/resource.h>
85 #  if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
86 #    undef _KERNEL
87 #  endif
88 #else
89 #  include <sys/times.h>
90 #endif
91
92 #if defined (HAVE_LIMITS_H)
93 #  include <limits.h>
94 #endif
95
96 /* Check for the most basic symbols.  If they aren't present, this
97    system's <sys/resource.h> isn't very useful to us. */
98 #if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
99 #  undef HAVE_RESOURCE
100 #endif
101
102 #if !defined (RLIMTYPE)
103 #  define RLIMTYPE long
104 #  define string_to_rlimtype string_to_long
105 #  define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
106 #endif
107
108 #define DESCFMT "%-28s"
109
110 /* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
111 #if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
112 #  define RLIMIT_NOFILE RLIMIT_OFILE
113 #endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
114
115 /* Some systems have these, some do not. */
116 #ifdef RLIMIT_FSIZE
117 #  define RLIMIT_FILESIZE       RLIMIT_FSIZE
118 #else
119 #  define RLIMIT_FILESIZE       256
120 #endif
121
122 #define RLIMIT_PIPESIZE 257
123
124 #ifdef RLIMIT_NOFILE
125 #  define RLIMIT_OPENFILES      RLIMIT_NOFILE
126 #else
127 #  define RLIMIT_OPENFILES      258
128 #endif
129
130 #ifdef RLIMIT_VMEM
131 #  define RLIMIT_VIRTMEM        RLIMIT_VMEM
132 #  define RLIMIT_VMBLKSZ        1024
133 #else
134 #  ifdef RLIMIT_AS
135 #    define RLIMIT_VIRTMEM      RLIMIT_AS
136 #    define RLIMIT_VMBLKSZ      1024
137 #  else
138 #    define RLIMIT_VIRTMEM      259
139 #    define RLIMIT_VMBLKSZ      1
140 #  endif
141 #endif
142
143 #ifdef RLIMIT_NPROC
144 #  define RLIMIT_MAXUPROC       RLIMIT_NPROC
145 #else
146 #  define RLIMIT_MAXUPROC       260
147 #endif
148
149 #if !defined (RLIM_INFINITY)
150 #  define RLIM_INFINITY 0x7fffffff
151 #endif
152
153 #if !defined (RLIM_INVALID)
154 #  define RLIM_INVALID  (RLIMTYPE)-1
155 #endif
156
157 #define LIMIT_HARD 0x01
158 #define LIMIT_SOFT 0x02
159
160 static int ulimit_internal ();
161 static void printone ();
162 static void print_all_limits ();
163
164 static int get_limit ();
165 static int set_limit ();
166
167 static RLIMTYPE filesize ();
168 static RLIMTYPE pipesize ();
169 static RLIMTYPE getmaxuprc ();
170 static RLIMTYPE getmaxvm ();
171
172 typedef struct {
173   int  option;                  /* The ulimit option for this limit. */
174   int  parameter;               /* Parameter to pass to get_limit (). */
175   int  block_factor;            /* Blocking factor for specific limit. */
176   char *description;            /* Descriptive string to output. */
177 } RESOURCE_LIMITS;
178
179 static RESOURCE_LIMITS limits[] = {
180 #ifdef RLIMIT_CORE
181   { 'c',        RLIMIT_CORE,  1024, "core file size (blocks)" },
182 #endif
183 #ifdef RLIMIT_DATA
184   { 'd',        RLIMIT_DATA,  1024, "data seg size (kbytes)" },
185 #endif
186   { 'f',        RLIMIT_FILESIZE, 1024, "file size (blocks)" },
187 #ifdef RLIMIT_MEMLOCK
188   { 'l',        RLIMIT_MEMLOCK, 1024, "max locked memory (kbytes)" },
189 #endif
190 #ifdef RLIMIT_RSS
191   { 'm',        RLIMIT_RSS,   1024, "max memory size (kbytes)" },
192 #endif /* RLIMIT_RSS */
193   { 'n',        RLIMIT_OPENFILES, 1, "open files" },
194   { 'p',        RLIMIT_PIPESIZE, 512, "pipe size (512 bytes)" },
195 #ifdef RLIMIT_STACK
196   { 's',        RLIMIT_STACK, 1024, "stack size (kbytes)" },
197 #endif
198 #ifdef RLIMIT_CPU
199   { 't',        RLIMIT_CPU,      1, "cpu time (seconds)" },
200 #endif /* RLIMIT_CPU */
201   { 'u',        RLIMIT_MAXUPROC, 1, "max user processes" },
202 #if defined (HAVE_RESOURCE)
203   { 'v',        RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory (kbytes)" },
204 #endif
205   { -1, -1, -1, (char *)NULL }
206 };
207 #define NCMDS   (sizeof(limits) / sizeof(limits[0]))
208
209 typedef struct _cmd {
210   int cmd;
211   char *arg;
212 } ULCMD;
213
214 static ULCMD *cmdlist;
215 static int ncmd;
216 static int cmdlistsz;
217
218 static int
219 _findlim (opt)
220      int opt;
221 {
222   register int i;
223
224   for (i = 0; limits[i].option > 0; i++)
225     if (limits[i].option == opt)
226       return i;
227   return -1;
228 }
229
230 static char optstring[4 + 2 * NCMDS];
231
232 /* Report or set limits associated with certain per-process resources.
233    See the help documentation in builtins.c for a full description. */
234 int
235 ulimit_builtin (list)
236      register WORD_LIST *list;
237 {
238   register char *s;
239   int c, limind, mode, opt, all_limits;
240
241   mode = 0;
242
243   all_limits = 0;
244
245   /* Idea stolen from pdksh -- build option string the first time called. */
246   if (optstring[0] == 0)
247     {
248       s = optstring;
249       *s++ = 'a'; *s++ = 'S'; *s++ = 'H';
250       for (c = 0; limits[c].option > 0; c++)
251         {
252           *s++ = limits[c].option;
253           *s++ = ';';
254         }
255       *s = '\0';
256     }
257
258   /* Initialize the command list. */
259   if (cmdlistsz == 0)
260     cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
261   ncmd = 0;
262
263   reset_internal_getopt ();
264   while ((opt = internal_getopt (list, optstring)) != -1)
265     {
266       switch (opt)
267         {
268         case 'a':
269           all_limits++;
270           break;
271
272         /* -S and -H are modifiers, not real options.  */
273         case 'S':
274           mode |= LIMIT_SOFT;
275           break;
276
277         case 'H':
278           mode |= LIMIT_HARD;
279           break;
280
281         case '?':
282           builtin_usage ();
283           return (EX_USAGE);
284
285         default:
286           if (ncmd >= cmdlistsz)
287             cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
288           cmdlist[ncmd].cmd = opt;
289           cmdlist[ncmd++].arg = list_optarg;
290           break;
291         }
292     }
293   list = loptend;
294
295   if (all_limits)
296     {
297       print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
298       return (EXECUTION_SUCCESS);
299     }
300
301   /* default is `ulimit -f' */
302   if (ncmd == 0)
303     {
304       cmdlist[ncmd].cmd = 'f';
305       /* `ulimit something' is same as `ulimit -f something' */
306       cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
307       if (list)
308         list = list->next;
309     }
310
311   /* verify each command in the list. */
312   for (c = 0; c < ncmd; c++)
313     {
314       limind = _findlim (cmdlist[c].cmd);
315       if (limind == -1)
316         {
317           builtin_error ("bad command: `%c'", cmdlist[c].cmd);
318           return (EX_USAGE);
319         }
320     }
321
322   for (c = 0; c < ncmd; c++)
323     if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
324       return (EXECUTION_FAILURE);
325
326   return (EXECUTION_SUCCESS);
327 }
328
329 static int
330 ulimit_internal (cmd, cmdarg, mode, multiple)
331      int cmd;
332      char *cmdarg;
333      int mode, multiple;
334 {
335   int opt, limind, setting;
336   long block_factor;
337   RLIMTYPE current_limit, real_limit, limit;
338
339   limit = RLIM_INVALID;
340   setting = cmdarg != 0;
341   limind = _findlim (cmd);
342   if (mode == 0)
343     mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
344   opt = get_limit (limind, mode, &current_limit);
345   if (opt < 0)
346     {
347       builtin_error ("cannot get limit: %s", strerror (errno));
348       return (EXECUTION_FAILURE);
349     }
350
351   if (setting == 0)     /* print the value of the specified limit */
352     {
353       printone (limind, current_limit, multiple);
354       return (EXECUTION_SUCCESS);
355     }
356  
357   /* Setting the limit. */
358   if (STREQ (cmdarg, "unlimited"))
359     limit = RLIM_INFINITY;
360   else if (all_digits (cmdarg))
361     limit = string_to_rlimtype (cmdarg);
362   else
363     {
364       builtin_error ("bad non-numeric arg `%s'", cmdarg);
365       return (EXECUTION_FAILURE);
366     }
367
368   block_factor = (limit == RLIM_INFINITY) ? 1 : limits[limind].block_factor;
369   real_limit = limit * block_factor;
370
371   if (set_limit (limind, real_limit, mode) < 0)
372     {
373       builtin_error ("cannot modify limit: %s", strerror (errno));
374       return (EXECUTION_FAILURE);
375     }
376   return (EXECUTION_SUCCESS);
377 }
378
379 static int
380 get_limit (ind, mode, limptr)
381      int ind, mode;
382      RLIMTYPE *limptr;
383 {
384   RLIMTYPE value;
385 #if defined (HAVE_RESOURCE)
386   struct rlimit limit;
387 #endif
388
389   if (limits[ind].parameter >= 256)
390     {
391       switch (limits[ind].parameter)
392         {
393         case RLIMIT_FILESIZE:
394           value = filesize ();
395           break;
396         case RLIMIT_PIPESIZE:
397           value = pipesize ();
398           break;
399         case RLIMIT_OPENFILES:
400           value = (RLIMTYPE)getdtablesize ();
401           break;
402         case RLIMIT_VIRTMEM:
403           value = getmaxvm (mode);
404           break;
405         case RLIMIT_MAXUPROC:
406           value = getmaxuprc (mode);
407           break;
408         default:
409           errno = EINVAL;
410           return -1;
411         }
412       *limptr = value;
413       return ((value == RLIM_INVALID) ? -1 : 0);
414     }
415   else
416     {
417 #if defined (HAVE_RESOURCE)
418       if (getrlimit (limits[ind].parameter, &limit) < 0)
419         return -1;
420       value = (mode & LIMIT_SOFT) ? limit.rlim_cur : limit.rlim_max;
421       *limptr = value;
422       return 0;
423 #else
424       errno = EINVAL;
425       return -1;
426 #endif
427     }
428 }
429
430 static int
431 set_limit (ind, newlim, mode)
432      int ind;
433      RLIMTYPE newlim;
434      int mode;
435 {
436 #if defined (HAVE_RESOURCE)
437    struct rlimit limit;
438    RLIMTYPE val;
439 #endif
440
441   if (limits[ind].parameter >= 256)
442     switch (limits[ind].parameter)
443       {
444       case RLIMIT_FILESIZE:
445 #if !defined (HAVE_RESOURCE)
446         return (ulimit (2, newlim / 512L));
447 #endif
448
449       case RLIMIT_OPENFILES:
450 #if defined (HAVE_SETDTABLESIZE)
451         return (setdtablesize (newlim));
452 #endif
453       case RLIMIT_PIPESIZE:
454       case RLIMIT_VIRTMEM:
455       case RLIMIT_MAXUPROC:
456       default:
457         errno = EINVAL;
458         return -1;
459       }
460   else
461     {
462 #if defined (HAVE_RESOURCE)
463       if (getrlimit (limits[ind].parameter, &limit) < 0)
464         return -1;
465       val = (current_user.euid != 0 && newlim == RLIM_INFINITY)
466                 ? limit.rlim_max : newlim;
467       if (mode & LIMIT_SOFT)
468         limit.rlim_cur = val;
469       if (mode & LIMIT_HARD)
470         limit.rlim_max = val;
471           
472       return (setrlimit (limits[ind].parameter, &limit));
473 #else
474       errno = EINVAL;
475       return -1;
476 #endif
477     }
478 }
479
480 static RLIMTYPE
481 getmaxvm (mode)
482      int mode;
483 {
484 #if defined (HAVE_RESOURCE)
485   struct rlimit rl;
486   RLIMTYPE maxdata, maxstack;
487
488   if (getrlimit (RLIMIT_DATA, &rl) < 0)
489     return (RLIM_INVALID);
490   else
491     maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
492
493   if (getrlimit (RLIMIT_STACK, &rl) < 0)
494     return (RLIM_INVALID);
495   else
496     maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
497
498   /* Protect against overflow. */
499   return ((maxdata / 1024L) + (maxstack / 1024L));
500 #else
501   errno = EINVAL;
502   return RLIM_INVALID;
503 #endif /* HAVE_RESOURCE */
504 }
505
506 static RLIMTYPE
507 filesize()
508 {
509 #if !defined (HAVE_RESOURCE)
510   return ((RLIMTYPE)ulimit (1, 0L));
511 #else
512   errno = EINVAL;
513   return RLIM_INVALID;
514 #endif
515 }
516
517 static RLIMTYPE
518 pipesize ()
519 {
520 #if defined (PIPE_BUF)
521   /* This is defined on Posix systems. */
522   return ((RLIMTYPE) PIPE_BUF);
523 #else
524 #  if defined (PIPESIZE)
525   /* This is defined by running a program from the Makefile. */
526   return ((RLIMTYPE) PIPESIZE);
527 #  else
528   errno = EINVAL;
529   return RLIM_INVALID;  
530 #  endif /* PIPESIZE */
531 #endif /* PIPE_BUF */
532 }
533
534 static RLIMTYPE
535 getmaxuprc (mode)
536      int mode;
537 {
538 #  if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
539   return ((RLIMTYPE)sysconf (_SC_CHILD_MAX));
540 #  else /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
541 #    if defined (MAXUPRC)
542   return ((RLIMTYPE)MAXUPRC);
543 #    else /* MAXUPRC */
544   errno = EINVAL;
545   return RLIM_INVALID;
546 #    endif /* !MAXUPRC */
547 #  endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
548 }
549
550 static void
551 print_all_limits (mode)
552      int mode;
553 {
554   register int i;
555   RLIMTYPE value;
556
557   if (mode == 0)
558     mode |= LIMIT_SOFT;
559
560   for (i = 0; limits[i].option > 0; i++)
561     {
562       if (get_limit (i, mode, &value) < 0)
563         value = RLIM_INVALID;
564       printone (i, value, 1);     
565     }
566 }
567
568 static void
569 printone (limind, curlim, pdesc)
570      int limind;
571      RLIMTYPE curlim;
572      int pdesc;
573 {
574   if (pdesc)
575     printf (DESCFMT, limits[limind].description);
576   if (curlim == RLIM_INFINITY)
577     puts ("unlimited");
578   else if (curlim == RLIM_INVALID)
579     printf ("cannot get limit: %s\n", strerror (errno));
580   else
581     print_rlimtype ((curlim / limits[limind].block_factor), 1);
582 }