Imported from ../bash-2.05.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, 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 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 #define LIMIT_HARD 0x01
158 #define LIMIT_SOFT 0x02
159
160 static int ulimit_internal __P((int, char *, int, int));
161 static void printone __P((int, RLIMTYPE, int));
162 static void print_all_limits __P((int));
163
164 static int get_limit __P((int, int, RLIMTYPE *));
165 static int set_limit __P((int, RLIMTYPE, int));
166
167 static int filesize __P((RLIMTYPE *));
168 static int pipesize __P((RLIMTYPE *));
169 static int getmaxuprc __P((int, RLIMTYPE *));
170 static int getmaxvm __P((int, RLIMTYPE *));
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 #ifdef RLIMIT_SWAP
206   { 'w',        RLIMIT_SWAP,    1024,   "swap size (kbytes)" },
207 #endif
208   { -1, -1, -1, (char *)NULL }
209 };
210 #define NCMDS   (sizeof(limits) / sizeof(limits[0]))
211
212 typedef struct _cmd {
213   int cmd;
214   char *arg;
215 } ULCMD;
216
217 static ULCMD *cmdlist;
218 static int ncmd;
219 static int cmdlistsz;
220
221 #if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
222 long
223 ulimit (cmd, newlim)
224      int cmd;
225      long newlim;
226 {
227   errno = EINVAL;
228   return -1;
229 }
230 #endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
231
232 static int
233 _findlim (opt)
234      int opt;
235 {
236   register int i;
237
238   for (i = 0; limits[i].option > 0; i++)
239     if (limits[i].option == opt)
240       return i;
241   return -1;
242 }
243
244 static char optstring[4 + 2 * NCMDS];
245
246 /* Report or set limits associated with certain per-process resources.
247    See the help documentation in builtins.c for a full description. */
248 int
249 ulimit_builtin (list)
250      register WORD_LIST *list;
251 {
252   register char *s;
253   int c, limind, mode, opt, all_limits;
254
255   mode = 0;
256
257   all_limits = 0;
258
259   /* Idea stolen from pdksh -- build option string the first time called. */
260   if (optstring[0] == 0)
261     {
262       s = optstring;
263       *s++ = 'a'; *s++ = 'S'; *s++ = 'H';
264       for (c = 0; limits[c].option > 0; c++)
265         {
266           *s++ = limits[c].option;
267           *s++ = ';';
268         }
269       *s = '\0';
270     }
271
272   /* Initialize the command list. */
273   if (cmdlistsz == 0)
274     cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
275   ncmd = 0;
276
277   reset_internal_getopt ();
278   while ((opt = internal_getopt (list, optstring)) != -1)
279     {
280       switch (opt)
281         {
282         case 'a':
283           all_limits++;
284           break;
285
286         /* -S and -H are modifiers, not real options.  */
287         case 'S':
288           mode |= LIMIT_SOFT;
289           break;
290
291         case 'H':
292           mode |= LIMIT_HARD;
293           break;
294
295         case '?':
296           builtin_usage ();
297           return (EX_USAGE);
298
299         default:
300           if (ncmd >= cmdlistsz)
301             cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
302           cmdlist[ncmd].cmd = opt;
303           cmdlist[ncmd++].arg = list_optarg;
304           break;
305         }
306     }
307   list = loptend;
308
309   if (all_limits)
310     {
311       print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
312       return (EXECUTION_SUCCESS);
313     }
314
315   /* default is `ulimit -f' */
316   if (ncmd == 0)
317     {
318       cmdlist[ncmd].cmd = 'f';
319       /* `ulimit something' is same as `ulimit -f something' */
320       cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
321       if (list)
322         list = list->next;
323     }
324
325   /* verify each command in the list. */
326   for (c = 0; c < ncmd; c++)
327     {
328       limind = _findlim (cmdlist[c].cmd);
329       if (limind == -1)
330         {
331           builtin_error ("bad command: `%c'", cmdlist[c].cmd);
332           return (EX_USAGE);
333         }
334     }
335
336   for (c = 0; c < ncmd; c++)
337     if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
338       return (EXECUTION_FAILURE);
339
340   return (EXECUTION_SUCCESS);
341 }
342
343 static int
344 ulimit_internal (cmd, cmdarg, mode, multiple)
345      int cmd;
346      char *cmdarg;
347      int mode, multiple;
348 {
349   int opt, limind, setting;
350   long block_factor;
351   RLIMTYPE current_limit, real_limit, limit;
352
353   setting = cmdarg != 0;
354   limind = _findlim (cmd);
355   if (mode == 0)
356     mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
357   opt = get_limit (limind, mode, &current_limit);
358   if (opt < 0)
359     {
360       builtin_error ("cannot get limit: %s", strerror (errno));
361       return (EXECUTION_FAILURE);
362     }
363
364   if (setting == 0)     /* print the value of the specified limit */
365     {
366       printone (limind, current_limit, multiple);
367       return (EXECUTION_SUCCESS);
368     }
369  
370   /* Setting the limit. */
371   if (STREQ (cmdarg, "unlimited"))
372     limit = RLIM_INFINITY;
373   else if (all_digits (cmdarg))
374     limit = string_to_rlimtype (cmdarg);
375   else
376     {
377       builtin_error ("bad non-numeric arg `%s'", cmdarg);
378       return (EXECUTION_FAILURE);
379     }
380
381   block_factor = (limit == RLIM_INFINITY) ? 1 : limits[limind].block_factor;
382   real_limit = limit * block_factor;
383
384   if (real_limit < 0 || (real_limit == 0 && limit != 0))
385     {
386       builtin_error ("limit out of range: %d", limit);
387       return (EXECUTION_FAILURE);
388     }
389
390   if (set_limit (limind, real_limit, mode) < 0)
391     {
392       builtin_error ("cannot modify limit: %s", strerror (errno));
393       return (EXECUTION_FAILURE);
394     }
395   return (EXECUTION_SUCCESS);
396 }
397
398 static int
399 get_limit (ind, mode, limptr)
400      int ind, mode;
401      RLIMTYPE *limptr;
402 {
403   RLIMTYPE value;
404 #if defined (HAVE_RESOURCE)
405   struct rlimit limit;
406 #endif
407
408   if (limits[ind].parameter >= 256)
409     {
410       switch (limits[ind].parameter)
411         {
412         case RLIMIT_FILESIZE:
413           if (filesize (&value) < 0)
414             return -1;
415           break;
416         case RLIMIT_PIPESIZE:
417           if (pipesize (&value) < 0)
418             return -1;
419           break;
420         case RLIMIT_OPENFILES:
421           value = (RLIMTYPE)getdtablesize ();
422           break;
423         case RLIMIT_VIRTMEM:
424           if (getmaxvm (mode, &value) < 0)
425             return -1;
426           break;
427         case RLIMIT_MAXUPROC:
428           if (getmaxuprc (mode, &value) < 0)
429             return -1;
430           break;
431         default:
432           errno = EINVAL;
433           return -1;
434         }
435       *limptr = value;
436       return (0);
437     }
438   else
439     {
440 #if defined (HAVE_RESOURCE)
441       if (getrlimit (limits[ind].parameter, &limit) < 0)
442         return -1;
443       value = (mode & LIMIT_SOFT) ? limit.rlim_cur : limit.rlim_max;
444 #  if defined (HPUX9)
445       if (limits[ind].parameter == RLIMIT_FILESIZE)
446         *limptr = value * 512;                  /* Ugh. */
447       else
448 #  endif /* HPUX9 */
449       *limptr = value;
450       return 0;
451 #else
452       errno = EINVAL;
453       return -1;
454 #endif
455     }
456 }
457
458 static int
459 set_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
523 static int
524 getmaxvm (mode, valuep)
525      int mode;
526      RLIMTYPE *valuep;
527 {
528 #if defined (HAVE_RESOURCE)
529   struct rlimit rl;
530   RLIMTYPE maxdata, maxstack;
531
532   if (getrlimit (RLIMIT_DATA, &rl) < 0)
533     return -1;
534   else
535     maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
536
537   if (getrlimit (RLIMIT_STACK, &rl) < 0)
538     return -1;
539   else
540     maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
541
542   /* Protect against overflow. */
543   *valuep = (maxdata / 1024L) + (maxstack / 1024L);
544   return 0;
545 #else
546   errno = EINVAL;
547   return -1;
548 #endif /* HAVE_RESOURCE */
549 }
550
551 static int
552 filesize(valuep)
553      RLIMTYPE *valuep;
554 {
555 #if !defined (HAVE_RESOURCE)
556   long result;
557   if ((result = ulimit (1, 0L)) < 0)
558     return -1;
559   else
560 #  if 0
561     *valuep = (RLIMTYPE) result;
562 #  else
563     *valuep = (RLIMTYPE) result * 512L;
564 #  endif
565   return 0;
566 #else
567   errno = EINVAL;
568   return -1;
569 #endif
570 }
571
572 static int
573 pipesize (valuep)
574      RLIMTYPE *valuep;
575 {
576 #if defined (PIPE_BUF)
577   /* This is defined on Posix systems. */
578   *valuep = (RLIMTYPE) PIPE_BUF;
579   return 0;
580 #else
581 #  if defined (PIPESIZE)
582   /* This is defined by running a program from the Makefile. */
583   *valuep = (RLIMTYPE) PIPESIZE;
584   return 0;
585 #  else
586   errno = EINVAL;
587   return -1;  
588 #  endif /* PIPESIZE */
589 #endif /* PIPE_BUF */
590 }
591
592 static int
593 getmaxuprc (mode, valuep)
594      int mode;
595      RLIMTYPE *valuep;
596 {
597 #  if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
598   long maxchild;
599   maxchild = sysconf (_SC_CHILD_MAX);
600   if (maxchild < 0)
601     return -1;
602   else
603     *valuep = (RLIMTYPE) maxchild;
604   return 0;
605 #  else /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
606 #    if defined (MAXUPRC)
607   *valuep = (RLIMTYPE) MAXUPRC;
608   return 0;
609 #    else /* MAXUPRC */
610   errno = EINVAL;
611   return -1;
612 #    endif /* !MAXUPRC */
613 #  endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
614 }
615
616 static void
617 print_all_limits (mode)
618      int mode;
619 {
620   register int i;
621   RLIMTYPE value;
622
623   if (mode == 0)
624     mode |= LIMIT_SOFT;
625
626   for (i = 0; limits[i].option > 0; i++)
627     {
628       if (get_limit (i, mode, &value) < 0)
629         {
630           fprintf (stderr, DESCFMT, limits[i].description);
631           builtin_error ("cannot get limit: %s", strerror (errno));
632         }
633       else
634         printone (i, value, 1);     
635     }
636 }
637
638 static void
639 printone (limind, curlim, pdesc)
640      int limind;
641      RLIMTYPE curlim;
642      int pdesc;
643 {
644   if (pdesc)
645     printf (DESCFMT, limits[limind].description);
646   if (curlim == RLIM_INFINITY)
647     puts ("unlimited");
648   else
649     print_rlimtype ((curlim / limits[limind].block_factor), 1);
650 }
651 #endif /* !_MINIX */