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