Imported from ../bash-2.01.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 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 #if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
219 long
220 ulimit (cmd, newlim)
221      int cmd;
222      long newlim;
223 {
224   errno = EINVAL;
225   return -1;
226 }
227 #endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
228
229 static int
230 _findlim (opt)
231      int opt;
232 {
233   register int i;
234
235   for (i = 0; limits[i].option > 0; i++)
236     if (limits[i].option == opt)
237       return i;
238   return -1;
239 }
240
241 static char optstring[4 + 2 * NCMDS];
242
243 /* Report or set limits associated with certain per-process resources.
244    See the help documentation in builtins.c for a full description. */
245 int
246 ulimit_builtin (list)
247      register WORD_LIST *list;
248 {
249   register char *s;
250   int c, limind, mode, opt, all_limits;
251
252   mode = 0;
253
254   all_limits = 0;
255
256   /* Idea stolen from pdksh -- build option string the first time called. */
257   if (optstring[0] == 0)
258     {
259       s = optstring;
260       *s++ = 'a'; *s++ = 'S'; *s++ = 'H';
261       for (c = 0; limits[c].option > 0; c++)
262         {
263           *s++ = limits[c].option;
264           *s++ = ';';
265         }
266       *s = '\0';
267     }
268
269   /* Initialize the command list. */
270   if (cmdlistsz == 0)
271     cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
272   ncmd = 0;
273
274   reset_internal_getopt ();
275   while ((opt = internal_getopt (list, optstring)) != -1)
276     {
277       switch (opt)
278         {
279         case 'a':
280           all_limits++;
281           break;
282
283         /* -S and -H are modifiers, not real options.  */
284         case 'S':
285           mode |= LIMIT_SOFT;
286           break;
287
288         case 'H':
289           mode |= LIMIT_HARD;
290           break;
291
292         case '?':
293           builtin_usage ();
294           return (EX_USAGE);
295
296         default:
297           if (ncmd >= cmdlistsz)
298             cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
299           cmdlist[ncmd].cmd = opt;
300           cmdlist[ncmd++].arg = list_optarg;
301           break;
302         }
303     }
304   list = loptend;
305
306   if (all_limits)
307     {
308       print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
309       return (EXECUTION_SUCCESS);
310     }
311
312   /* default is `ulimit -f' */
313   if (ncmd == 0)
314     {
315       cmdlist[ncmd].cmd = 'f';
316       /* `ulimit something' is same as `ulimit -f something' */
317       cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
318       if (list)
319         list = list->next;
320     }
321
322   /* verify each command in the list. */
323   for (c = 0; c < ncmd; c++)
324     {
325       limind = _findlim (cmdlist[c].cmd);
326       if (limind == -1)
327         {
328           builtin_error ("bad command: `%c'", cmdlist[c].cmd);
329           return (EX_USAGE);
330         }
331     }
332
333   for (c = 0; c < ncmd; c++)
334     if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
335       return (EXECUTION_FAILURE);
336
337   return (EXECUTION_SUCCESS);
338 }
339
340 static int
341 ulimit_internal (cmd, cmdarg, mode, multiple)
342      int cmd;
343      char *cmdarg;
344      int mode, multiple;
345 {
346   int opt, limind, setting;
347   long block_factor;
348   RLIMTYPE current_limit, real_limit, limit;
349
350   limit = RLIM_INVALID;
351   setting = cmdarg != 0;
352   limind = _findlim (cmd);
353   if (mode == 0)
354     mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
355   opt = get_limit (limind, mode, &current_limit);
356   if (opt < 0)
357     {
358       builtin_error ("cannot get limit: %s", strerror (errno));
359       return (EXECUTION_FAILURE);
360     }
361
362   if (setting == 0)     /* print the value of the specified limit */
363     {
364       printone (limind, current_limit, multiple);
365       return (EXECUTION_SUCCESS);
366     }
367  
368   /* Setting the limit. */
369   if (STREQ (cmdarg, "unlimited"))
370     limit = RLIM_INFINITY;
371   else if (all_digits (cmdarg))
372     limit = string_to_rlimtype (cmdarg);
373   else
374     {
375       builtin_error ("bad non-numeric arg `%s'", cmdarg);
376       return (EXECUTION_FAILURE);
377     }
378
379   block_factor = (limit == RLIM_INFINITY) ? 1 : limits[limind].block_factor;
380   real_limit = limit * block_factor;
381
382   if (real_limit < 0 || (real_limit == 0 && limit != 0))
383     {
384       builtin_error ("limit out of range: %d", limit);
385       return (EXECUTION_FAILURE);
386     }
387
388   if (set_limit (limind, real_limit, mode) < 0)
389     {
390       builtin_error ("cannot modify limit: %s", strerror (errno));
391       return (EXECUTION_FAILURE);
392     }
393   return (EXECUTION_SUCCESS);
394 }
395
396 static int
397 get_limit (ind, mode, limptr)
398      int ind, mode;
399      RLIMTYPE *limptr;
400 {
401   RLIMTYPE value;
402 #if defined (HAVE_RESOURCE)
403   struct rlimit limit;
404 #endif
405
406   if (limits[ind].parameter >= 256)
407     {
408       switch (limits[ind].parameter)
409         {
410         case RLIMIT_FILESIZE:
411           value = filesize ();
412           break;
413         case RLIMIT_PIPESIZE:
414           value = pipesize ();
415           break;
416         case RLIMIT_OPENFILES:
417           value = (RLIMTYPE)getdtablesize ();
418           break;
419         case RLIMIT_VIRTMEM:
420           value = getmaxvm (mode);
421           break;
422         case RLIMIT_MAXUPROC:
423           value = getmaxuprc (mode);
424           break;
425         default:
426           errno = EINVAL;
427           return -1;
428         }
429       *limptr = value;
430       return ((value == RLIM_INVALID) ? -1 : 0);
431     }
432   else
433     {
434 #if defined (HAVE_RESOURCE)
435       if (getrlimit (limits[ind].parameter, &limit) < 0)
436         return -1;
437       value = (mode & LIMIT_SOFT) ? limit.rlim_cur : limit.rlim_max;
438       *limptr = value;
439       return 0;
440 #else
441       errno = EINVAL;
442       return -1;
443 #endif
444     }
445 }
446
447 static int
448 set_limit (ind, newlim, mode)
449      int ind;
450      RLIMTYPE newlim;
451      int mode;
452 {
453 #if defined (HAVE_RESOURCE)
454    struct rlimit limit;
455    RLIMTYPE val;
456 #endif
457
458   if (limits[ind].parameter >= 256)
459     switch (limits[ind].parameter)
460       {
461       case RLIMIT_FILESIZE:
462 #if !defined (HAVE_RESOURCE)
463         return (ulimit (2, newlim / 512L));
464 #else
465         errno = EINVAL;
466         return -1;
467 #endif
468
469       case RLIMIT_OPENFILES:
470 #if defined (HAVE_SETDTABLESIZE)
471         return (setdtablesize (newlim));
472 #endif
473       case RLIMIT_PIPESIZE:
474       case RLIMIT_VIRTMEM:
475       case RLIMIT_MAXUPROC:
476       default:
477         errno = EINVAL;
478         return -1;
479       }
480   else
481     {
482 #if defined (HAVE_RESOURCE)
483       if (getrlimit (limits[ind].parameter, &limit) < 0)
484         return -1;
485       val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
486                (limit.rlim_cur <= limit.rlim_max))
487                  ? limit.rlim_max : newlim;
488       if (mode & LIMIT_SOFT)
489         limit.rlim_cur = val;
490       if (mode & LIMIT_HARD)
491         limit.rlim_max = val;
492           
493       return (setrlimit (limits[ind].parameter, &limit));
494 #else
495       errno = EINVAL;
496       return -1;
497 #endif
498     }
499 }
500
501 static RLIMTYPE
502 getmaxvm (mode)
503      int mode;
504 {
505 #if defined (HAVE_RESOURCE)
506   struct rlimit rl;
507   RLIMTYPE maxdata, maxstack;
508
509   if (getrlimit (RLIMIT_DATA, &rl) < 0)
510     return (RLIM_INVALID);
511   else
512     maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
513
514   if (getrlimit (RLIMIT_STACK, &rl) < 0)
515     return (RLIM_INVALID);
516   else
517     maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
518
519   /* Protect against overflow. */
520   return ((maxdata / 1024L) + (maxstack / 1024L));
521 #else
522   errno = EINVAL;
523   return RLIM_INVALID;
524 #endif /* HAVE_RESOURCE */
525 }
526
527 static RLIMTYPE
528 filesize()
529 {
530 #if !defined (HAVE_RESOURCE)
531   return ((RLIMTYPE)ulimit (1, 0L));
532 #else
533   errno = EINVAL;
534   return RLIM_INVALID;
535 #endif
536 }
537
538 static RLIMTYPE
539 pipesize ()
540 {
541 #if defined (PIPE_BUF)
542   /* This is defined on Posix systems. */
543   return ((RLIMTYPE) PIPE_BUF);
544 #else
545 #  if defined (PIPESIZE)
546   /* This is defined by running a program from the Makefile. */
547   return ((RLIMTYPE) PIPESIZE);
548 #  else
549   errno = EINVAL;
550   return RLIM_INVALID;  
551 #  endif /* PIPESIZE */
552 #endif /* PIPE_BUF */
553 }
554
555 static RLIMTYPE
556 getmaxuprc (mode)
557      int mode;
558 {
559 #  if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
560   return ((RLIMTYPE)sysconf (_SC_CHILD_MAX));
561 #  else /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
562 #    if defined (MAXUPRC)
563   return ((RLIMTYPE)MAXUPRC);
564 #    else /* MAXUPRC */
565   errno = EINVAL;
566   return RLIM_INVALID;
567 #    endif /* !MAXUPRC */
568 #  endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
569 }
570
571 static void
572 print_all_limits (mode)
573      int mode;
574 {
575   register int i;
576   RLIMTYPE value;
577
578   if (mode == 0)
579     mode |= LIMIT_SOFT;
580
581   for (i = 0; limits[i].option > 0; i++)
582     {
583       if (get_limit (i, mode, &value) < 0)
584         value = RLIM_INVALID;
585       printone (i, value, 1);     
586     }
587 }
588
589 static void
590 printone (limind, curlim, pdesc)
591      int limind;
592      RLIMTYPE curlim;
593      int pdesc;
594 {
595   if (pdesc)
596     printf (DESCFMT, limits[limind].description);
597   if (curlim == RLIM_INFINITY)
598     puts ("unlimited");
599   else if (curlim == RLIM_INVALID)
600     printf ("cannot get limit: %s\n", strerror (errno));
601   else
602     print_rlimtype ((curlim / limits[limind].block_factor), 1);
603 }