1This file is ulimit.def, from which is created ulimit.c.
2It implements the builtin "ulimit" in Bash.
3
4Copyright (C) 1987-2020 Free Software Foundation, Inc.
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
12
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with Bash.  If not, see <http://www.gnu.org/licenses/>.
20
21$PRODUCES ulimit.c
22
23$BUILTIN ulimit
24$FUNCTION ulimit_builtin
25$DEPENDS_ON !_MINIX
26$SHORT_DOC ulimit [-SHabcdefiklmnpqrstuvxPT] [limit]
27Modify shell resource limits.
28
29Provides control over the resources available to the shell and processes
30it creates, on systems that allow such control.
31
32Options:
33  -S	use the `soft' resource limit
34  -H	use the `hard' resource limit
35  -a	all current limits are reported
36  -b	the socket buffer size
37  -c	the maximum size of core files created
38  -d	the maximum size of a process's data segment
39  -e	the maximum scheduling priority (`nice')
40  -f	the maximum size of files written by the shell and its children
41  -i	the maximum number of pending signals
42  -k	the maximum number of kqueues allocated for this process
43  -l	the maximum size a process may lock into memory
44  -m	the maximum resident set size
45  -n	the maximum number of open file descriptors
46  -p	the pipe buffer size
47  -q	the maximum number of bytes in POSIX message queues
48  -r	the maximum real-time scheduling priority
49  -s	the maximum stack size
50  -t	the maximum amount of cpu time in seconds
51  -u	the maximum number of user processes
52  -v	the size of virtual memory
53  -x	the maximum number of file locks
54  -P	the maximum number of pseudoterminals
55  -R	the maximum time a real-time process can run before blocking
56  -T	the maximum number of threads
57
58Not all options are available on all platforms.
59
60If LIMIT is given, it is the new value of the specified resource; the
61special LIMIT values `soft', `hard', and `unlimited' stand for the
62current soft limit, the current hard limit, and no limit, respectively.
63Otherwise, the current value of the specified resource is printed.  If
64no option is given, then -f is assumed.
65
66Values are in 1024-byte increments, except for -t, which is in seconds,
67-p, which is in increments of 512 bytes, and -u, which is an unscaled
68number of processes.
69
70Exit Status:
71Returns success unless an invalid option is supplied or an error occurs.
72$END
73
74#if !defined (_MINIX)
75
76#include <config.h>
77
78#include "../bashtypes.h"
79#if defined (HAVE_SYS_PARAM_H)
80#  include <sys/param.h>
81#endif
82
83#if defined (HAVE_UNISTD_H)
84#  include <unistd.h>
85#endif
86
87#include <stdio.h>
88#include <errno.h>
89
90#include "../bashintl.h"
91
92#include "../shell.h"
93#include "common.h"
94#include "bashgetopt.h"
95#include "pipesize.h"
96
97#if !defined (errno)
98extern int errno;
99#endif
100
101/* For some reason, HPUX chose to make these definitions visible only if
102   _KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
103   and #undef it afterward. */
104#if defined (HAVE_RESOURCE)
105#  include <sys/time.h>
106#  if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
107#    define _KERNEL
108#  endif
109#  include <sys/resource.h>
110#  if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
111#    undef _KERNEL
112#  endif
113#elif defined (HAVE_SYS_TIMES_H)
114#  include <sys/times.h>
115#endif
116
117#if defined (HAVE_LIMITS_H)
118#  include <limits.h>
119#endif
120
121/* Check for the most basic symbols.  If they aren't present, this
122   system's <sys/resource.h> isn't very useful to us. */
123#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
124#  undef HAVE_RESOURCE
125#endif
126
127#if !defined (HAVE_RESOURCE) && defined (HAVE_ULIMIT_H)
128#  include <ulimit.h>
129#endif
130
131#if !defined (RLIMTYPE)
132#  define RLIMTYPE long
133#  define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
134#  define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
135#endif
136
137/* Alternate names */
138
139/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
140#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
141#  define RLIMIT_NOFILE RLIMIT_OFILE
142#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
143
144#if defined (HAVE_RESOURCE) && defined (RLIMIT_POSIXLOCKS) && !defined (RLIMIT_LOCKS)
145#  define RLIMIT_LOCKS RLIMIT_POSIXLOCKS
146#endif /* HAVE_RESOURCE && RLIMIT_POSIXLOCKS && !RLIMIT_LOCKS */
147
148/* Some systems have these, some do not. */
149#ifdef RLIMIT_FSIZE
150#  define RLIMIT_FILESIZE	RLIMIT_FSIZE
151#else
152#  define RLIMIT_FILESIZE	256
153#endif
154
155#define RLIMIT_PIPESIZE	257
156
157#ifdef RLIMIT_NOFILE
158#  define RLIMIT_OPENFILES	RLIMIT_NOFILE
159#else
160#  define RLIMIT_OPENFILES	258
161#endif
162
163#ifdef RLIMIT_VMEM
164#  define RLIMIT_VIRTMEM	RLIMIT_VMEM
165#  define RLIMIT_VMBLKSZ	1024
166#else
167#  ifdef RLIMIT_AS
168#    define RLIMIT_VIRTMEM	RLIMIT_AS
169#    define RLIMIT_VMBLKSZ	1024
170#  else
171#    define RLIMIT_VIRTMEM	259
172#    define RLIMIT_VMBLKSZ	1
173#  endif
174#endif
175
176#ifdef RLIMIT_NPROC
177#  define RLIMIT_MAXUPROC	RLIMIT_NPROC
178#else
179#  define RLIMIT_MAXUPROC	260
180#endif
181
182#if !defined (RLIMIT_PTHREAD) && defined (RLIMIT_NTHR)
183#  define RLIMIT_PTHREAD RLIMIT_NTHR
184#endif
185
186#if !defined (RLIM_INFINITY)
187#  define RLIM_INFINITY 0x7fffffff
188#endif
189
190#if !defined (RLIM_SAVED_CUR)
191#  define RLIM_SAVED_CUR RLIM_INFINITY
192#endif
193
194#if !defined (RLIM_SAVED_MAX)
195#  define RLIM_SAVED_MAX RLIM_INFINITY
196#endif
197
198#define LIMIT_HARD 0x01
199#define LIMIT_SOFT 0x02
200
201/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
202   otherwise. */
203#define POSIXBLK	-2
204
205#define BLOCKSIZE(x)	(((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
206
207static int _findlim PARAMS((int));
208
209static int ulimit_internal PARAMS((int, char *, int, int));
210
211static int get_limit PARAMS((int, RLIMTYPE *, RLIMTYPE *));
212static int set_limit PARAMS((int, RLIMTYPE, int));
213
214static void printone PARAMS((int, RLIMTYPE, int));
215static void print_all_limits PARAMS((int));
216
217static int set_all_limits PARAMS((int, RLIMTYPE));
218
219static int filesize PARAMS((RLIMTYPE *));
220static int pipesize PARAMS((RLIMTYPE *));
221static int getmaxuprc PARAMS((RLIMTYPE *));
222static int getmaxvm PARAMS((RLIMTYPE *, RLIMTYPE *));
223
224typedef struct {
225  int  option;			/* The ulimit option for this limit. */
226  int  parameter;		/* Parameter to pass to get_limit (). */
227  int  block_factor;		/* Blocking factor for specific limit. */
228  const char * const description;	/* Descriptive string to output. */
229  const char * const units;	/* scale */
230} RESOURCE_LIMITS;
231
232static RESOURCE_LIMITS limits[] = {
233#ifdef RLIMIT_NPTS
234  { 'P',	RLIMIT_NPTS,  1,	"number of pseudoterminals",	(char *)NULL },
235#endif
236#ifdef RLIMIT_RTTIME
237  { 'R',	RLIMIT_RTTIME,  1,	"real-time non-blocking time",	"microseconds" },
238#endif
239#ifdef RLIMIT_PTHREAD
240  { 'T',	RLIMIT_PTHREAD, 1,	"number of threads",	(char *)NULL },
241#endif
242#ifdef RLIMIT_SBSIZE
243  { 'b',	RLIMIT_SBSIZE,  1,	"socket buffer size",	"bytes" },
244#endif
245#ifdef RLIMIT_CORE
246  { 'c',	RLIMIT_CORE,  POSIXBLK,	"core file size",	"blocks" },
247#endif
248#ifdef RLIMIT_DATA
249  { 'd',	RLIMIT_DATA,  1024,	"data seg size",	"kbytes" },
250#endif
251#ifdef RLIMIT_NICE
252  { 'e',	RLIMIT_NICE,  1,	"scheduling priority",	(char *)NULL },
253#endif
254  { 'f',	RLIMIT_FILESIZE, POSIXBLK,	"file size",		"blocks" },
255#ifdef RLIMIT_SIGPENDING
256  { 'i',	RLIMIT_SIGPENDING, 1,	"pending signals",	(char *)NULL },
257#endif
258#ifdef RLIMIT_KQUEUES
259  { 'k',	RLIMIT_KQUEUES, 1,	"max kqueues",		(char *)NULL },
260#endif
261#ifdef RLIMIT_MEMLOCK
262  { 'l',	RLIMIT_MEMLOCK, 1024,	"max locked memory",	"kbytes" },
263#endif
264#ifdef RLIMIT_RSS
265  { 'm',	RLIMIT_RSS,   1024,	"max memory size",	"kbytes" },
266#endif /* RLIMIT_RSS */
267  { 'n',	RLIMIT_OPENFILES, 1,	"open files",		(char *)NULL},
268  { 'p',	RLIMIT_PIPESIZE, 512,	"pipe size", 		"512 bytes" },
269#ifdef RLIMIT_MSGQUEUE
270  { 'q',	RLIMIT_MSGQUEUE, 1,	"POSIX message queues",	"bytes" },
271#endif
272#ifdef RLIMIT_RTPRIO
273  { 'r',	RLIMIT_RTPRIO,  1,	"real-time priority",	(char *)NULL },
274#endif
275#ifdef RLIMIT_STACK
276  { 's',	RLIMIT_STACK, 1024,	"stack size",		"kbytes" },
277#endif
278#ifdef RLIMIT_CPU
279  { 't',	RLIMIT_CPU,      1,	"cpu time",		"seconds" },
280#endif /* RLIMIT_CPU */
281  { 'u',	RLIMIT_MAXUPROC, 1,	"max user processes",	(char *)NULL },
282#if defined (HAVE_RESOURCE)
283  { 'v',	RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" },
284#endif
285#ifdef RLIMIT_SWAP
286  { 'w',	RLIMIT_SWAP,	1024,	"swap size",		"kbytes" },
287#endif
288#ifdef RLIMIT_LOCKS
289  { 'x',	RLIMIT_LOCKS,	1,	"file locks",		(char *)NULL },
290#endif
291  { -1, -1, -1, (char *)NULL, (char *)NULL }
292};
293#define NCMDS	(sizeof(limits) / sizeof(limits[0]))
294
295typedef struct _cmd {
296  int cmd;
297  char *arg;
298} ULCMD;
299
300static ULCMD *cmdlist;
301static int ncmd;
302static int cmdlistsz;
303
304#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
305long
306ulimit (cmd, newlim)
307     int cmd;
308     long newlim;
309{
310  errno = EINVAL;
311  return -1;
312}
313#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
314
315static int
316_findlim (opt)
317     int opt;
318{
319  register int i;
320
321  for (i = 0; limits[i].option > 0; i++)
322    if (limits[i].option == opt)
323      return i;
324  return -1;
325}
326
327static char optstring[4 + 2 * NCMDS];
328
329/* Report or set limits associated with certain per-process resources.
330   See the help documentation in builtins.c for a full description. */
331int
332ulimit_builtin (list)
333     register WORD_LIST *list;
334{
335  register char *s;
336  int c, limind, mode, opt, all_limits;
337
338  mode = 0;
339
340  all_limits = 0;
341
342  /* Idea stolen from pdksh -- build option string the first time called. */
343  if (optstring[0] == 0)
344    {
345      s = optstring;
346      *s++ = 'a'; *s++ = 'S'; *s++ = 'H';
347      for (c = 0; limits[c].option > 0; c++)
348	{
349	  *s++ = limits[c].option;
350	  *s++ = ';';
351	}
352      *s = '\0';
353    }
354
355  /* Initialize the command list. */
356  if (cmdlistsz == 0)
357    cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
358  ncmd = 0;
359
360  reset_internal_getopt ();
361  while ((opt = internal_getopt (list, optstring)) != -1)
362    {
363      switch (opt)
364	{
365	case 'a':
366	  all_limits++;
367	  break;
368
369	/* -S and -H are modifiers, not real options.  */
370	case 'S':
371	  mode |= LIMIT_SOFT;
372	  break;
373
374	case 'H':
375	  mode |= LIMIT_HARD;
376	  break;
377
378	CASE_HELPOPT;
379	case '?':
380	  builtin_usage ();
381	  return (EX_USAGE);
382
383	default:
384	  if (ncmd >= cmdlistsz)
385	    cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
386	  cmdlist[ncmd].cmd = opt;
387	  cmdlist[ncmd++].arg = list_optarg;
388	  break;
389	}
390    }
391  list = loptend;
392
393  if (all_limits)
394    {
395#ifdef NOTYET
396      if (list)		/* setting */
397        {
398          if (STREQ (list->word->word, "unlimited") == 0)
399            {
400              builtin_error (_("%s: invalid limit argument"), list->word->word);
401              return (EXECUTION_FAILURE);
402            }
403          return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
404        }
405#endif
406      print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
407      return (sh_chkwrite (EXECUTION_SUCCESS));
408    }
409
410  /* default is `ulimit -f' */
411  if (ncmd == 0)
412    {
413      cmdlist[ncmd].cmd = 'f';
414      /* `ulimit something' is same as `ulimit -f something' */
415      cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
416      if (list)
417	list = list->next;
418    }
419
420  /* verify each command in the list. */
421  for (c = 0; c < ncmd; c++)
422    {
423      limind = _findlim (cmdlist[c].cmd);
424      if (limind == -1)
425	{
426	  builtin_error (_("`%c': bad command"), cmdlist[c].cmd);
427	  return (EX_USAGE);
428	}
429    }
430
431  for (c = 0; c < ncmd; c++)
432    if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
433      return (EXECUTION_FAILURE);
434
435  return (EXECUTION_SUCCESS);
436}
437
438static int
439ulimit_internal (cmd, cmdarg, mode, multiple)
440     int cmd;
441     char *cmdarg;
442     int mode, multiple;
443{
444  int opt, limind, setting;
445  int block_factor;
446  RLIMTYPE soft_limit, hard_limit, real_limit, limit;
447
448  setting = cmdarg != 0;
449  limind = _findlim (cmd);
450  if (mode == 0)
451    mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
452  opt = get_limit (limind, &soft_limit, &hard_limit);
453  if (opt < 0)
454    {
455      builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
456						 strerror (errno));
457      return (EXECUTION_FAILURE);
458    }
459
460  if (setting == 0)	/* print the value of the specified limit */
461    {
462      printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
463      return (EXECUTION_SUCCESS);
464    }
465
466  /* Setting the limit. */
467  if (STREQ (cmdarg, "hard"))
468    real_limit = hard_limit;
469  else if (STREQ (cmdarg, "soft"))
470    real_limit = soft_limit;
471  else if (STREQ (cmdarg, "unlimited"))
472    real_limit = RLIM_INFINITY;
473  else if (all_digits (cmdarg))
474    {
475      limit = string_to_rlimtype (cmdarg);
476      block_factor = BLOCKSIZE(limits[limind].block_factor);
477      real_limit = limit * block_factor;
478
479      if ((real_limit / block_factor) != limit)
480	{
481	  sh_erange (cmdarg, _("limit"));
482	  return (EXECUTION_FAILURE);
483	}
484    }
485  else
486    {
487      sh_invalidnum (cmdarg);
488      return (EXECUTION_FAILURE);
489    }
490
491  if (set_limit (limind, real_limit, mode) < 0)
492    {
493      builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description,
494						    strerror (errno));
495      return (EXECUTION_FAILURE);
496    }
497
498  return (EXECUTION_SUCCESS);
499}
500
501static int
502get_limit (ind, softlim, hardlim)
503     int ind;
504     RLIMTYPE *softlim, *hardlim;
505{
506  RLIMTYPE value;
507#if defined (HAVE_RESOURCE)
508  struct rlimit limit;
509#endif
510
511  if (limits[ind].parameter >= 256)
512    {
513      switch (limits[ind].parameter)
514	{
515	case RLIMIT_FILESIZE:
516	  if (filesize (&value) < 0)
517	    return -1;
518	  break;
519	case RLIMIT_PIPESIZE:
520	  if (pipesize (&value) < 0)
521	    return -1;
522	  break;
523	case RLIMIT_OPENFILES:
524	  value = (RLIMTYPE)getdtablesize ();
525	  break;
526	case RLIMIT_VIRTMEM:
527	  return (getmaxvm (softlim, hardlim));
528	case RLIMIT_MAXUPROC:
529	  if (getmaxuprc (&value) < 0)
530	    return -1;
531	  break;
532	default:
533	  errno = EINVAL;
534	  return -1;
535	}
536      *softlim = *hardlim = value;
537      return (0);
538    }
539  else
540    {
541#if defined (HAVE_RESOURCE)
542      if (getrlimit (limits[ind].parameter, &limit) < 0)
543	return -1;
544      *softlim = limit.rlim_cur;
545      *hardlim = limit.rlim_max;
546#  if defined (HPUX9)
547      if (limits[ind].parameter == RLIMIT_FILESIZE)
548	{
549	  *softlim *= 512;
550	  *hardlim *= 512;			/* Ugh. */
551	}
552      else
553#  endif /* HPUX9 */
554      return 0;
555#else
556      errno = EINVAL;
557      return -1;
558#endif
559    }
560}
561
562static int
563set_limit (ind, newlim, mode)
564     int ind;
565     RLIMTYPE newlim;
566     int mode;
567{
568#if defined (HAVE_RESOURCE)
569   struct rlimit limit;
570   RLIMTYPE val;
571#endif
572
573  if (limits[ind].parameter >= 256)
574    switch (limits[ind].parameter)
575      {
576      case RLIMIT_FILESIZE:
577#if !defined (HAVE_RESOURCE)
578	return (ulimit (2, newlim / 512L));
579#else
580	errno = EINVAL;
581	return -1;
582#endif
583
584      case RLIMIT_OPENFILES:
585#if defined (HAVE_SETDTABLESIZE)
586#  if defined (__CYGWIN__)
587	/* Grrr... Cygwin declares setdtablesize as void. */
588	setdtablesize (newlim);
589	return 0;
590#  else
591	return (setdtablesize (newlim));
592#  endif
593#endif
594      case RLIMIT_PIPESIZE:
595      case RLIMIT_VIRTMEM:
596      case RLIMIT_MAXUPROC:
597      default:
598	errno = EINVAL;
599	return -1;
600      }
601  else
602    {
603#if defined (HAVE_RESOURCE)
604      if (getrlimit (limits[ind].parameter, &limit) < 0)
605	return -1;
606#  if defined (HPUX9)
607      if (limits[ind].parameter == RLIMIT_FILESIZE)
608	newlim /= 512;				/* Ugh. */
609#  endif /* HPUX9 */
610      val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
611	       (mode & LIMIT_HARD) == 0 &&		/* XXX -- test */
612	       (limit.rlim_cur <= limit.rlim_max))
613		 ? limit.rlim_max : newlim;
614      if (mode & LIMIT_SOFT)
615	limit.rlim_cur = val;
616      if (mode & LIMIT_HARD)
617	limit.rlim_max = val;
618
619      return (setrlimit (limits[ind].parameter, &limit));
620#else
621      errno = EINVAL;
622      return -1;
623#endif
624    }
625}
626
627static int
628getmaxvm (softlim, hardlim)
629     RLIMTYPE *softlim, *hardlim;
630{
631#if defined (HAVE_RESOURCE)
632  struct rlimit datalim, stacklim;
633
634  if (getrlimit (RLIMIT_DATA, &datalim) < 0)
635    return -1;
636
637  if (getrlimit (RLIMIT_STACK, &stacklim) < 0)
638    return -1;
639
640  /* Protect against overflow. */
641  *softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L);
642  *hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L);
643  return 0;
644#else
645  errno = EINVAL;
646  return -1;
647#endif /* HAVE_RESOURCE */
648}
649
650static int
651filesize(valuep)
652     RLIMTYPE *valuep;
653{
654#if !defined (HAVE_RESOURCE)
655  long result;
656  if ((result = ulimit (1, 0L)) < 0)
657    return -1;
658  else
659    *valuep = (RLIMTYPE) result * 512;
660  return 0;
661#else
662  errno = EINVAL;
663  return -1;
664#endif
665}
666
667static int
668pipesize (valuep)
669     RLIMTYPE *valuep;
670{
671#if defined (PIPE_BUF)
672  /* This is defined on Posix systems. */
673  *valuep = (RLIMTYPE) PIPE_BUF;
674  return 0;
675#else
676#  if defined (_POSIX_PIPE_BUF)
677  *valuep = (RLIMTYPE) _POSIX_PIPE_BUF;
678  return 0;
679#  else
680#    if defined (PIPESIZE)
681  /* This is defined by running a program from the Makefile. */
682  *valuep = (RLIMTYPE) PIPESIZE;
683  return 0;
684#    else
685  errno = EINVAL;
686  return -1;
687#    endif /* PIPESIZE */
688#  endif /* _POSIX_PIPE_BUF */
689#endif /* PIPE_BUF */
690}
691
692static int
693getmaxuprc (valuep)
694     RLIMTYPE *valuep;
695{
696  long maxchild;
697
698  maxchild = getmaxchild ();
699  if (maxchild < 0)
700    {
701      errno = EINVAL;
702      return -1;
703    }
704  else
705    {
706      *valuep = (RLIMTYPE) maxchild;
707      return 0;
708    }
709}
710
711static void
712print_all_limits (mode)
713     int mode;
714{
715  register int i;
716  RLIMTYPE softlim, hardlim;
717
718  if (mode == 0)
719    mode |= LIMIT_SOFT;
720
721  for (i = 0; limits[i].option > 0; i++)
722    {
723      if (get_limit (i, &softlim, &hardlim) == 0)
724	printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1);
725      else if (errno != EINVAL)
726	builtin_error ("%s: cannot get limit: %s", limits[i].description,
727						   strerror (errno));
728    }
729}
730
731static void
732printone (limind, curlim, pdesc)
733     int limind;
734     RLIMTYPE curlim;
735     int pdesc;
736{
737  char unitstr[64];
738  int factor;
739
740  factor = BLOCKSIZE(limits[limind].block_factor);
741  if (pdesc)
742    {
743      if (limits[limind].units)
744	sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
745      else
746        sprintf (unitstr, "(-%c) ", limits[limind].option);
747
748      printf ("%-20s %20s", limits[limind].description, unitstr);
749    }
750  if (curlim == RLIM_INFINITY)
751    puts ("unlimited");
752  else if (curlim == RLIM_SAVED_MAX)
753    puts ("hard");
754  else if (curlim == RLIM_SAVED_CUR)
755    puts ("soft");
756  else
757    print_rlimtype ((curlim / factor), 1);
758}
759
760/* Set all limits to NEWLIM.  NEWLIM currently must be RLIM_INFINITY, which
761   causes all limits to be set as high as possible depending on mode (like
762   csh `unlimit').  Returns -1 if NEWLIM is invalid, 0 if all limits
763   were set successfully, and 1 if at least one limit could not be set.
764
765   To raise all soft limits to their corresponding hard limits, use
766	ulimit -S -a unlimited
767   To attempt to raise all hard limits to infinity (superuser-only), use
768	ulimit -H -a unlimited
769   To attempt to raise all soft and hard limits to infinity, use
770	ulimit -a unlimited
771*/
772
773static int
774set_all_limits (mode, newlim)
775     int mode;
776     RLIMTYPE newlim;
777{
778  register int i;
779  int retval = 0;
780
781  if (newlim != RLIM_INFINITY)
782    {
783      errno = EINVAL;
784      return -1;
785    }
786
787  if (mode == 0)
788    mode = LIMIT_SOFT|LIMIT_HARD;
789
790  for (retval = i = 0; limits[i].option > 0; i++)
791    if (set_limit (i, newlim, mode) < 0)
792      {
793	builtin_error (_("%s: cannot modify limit: %s"), limits[i].description,
794						      strerror (errno));
795	retval = 1;
796      }
797  return retval;
798}
799
800#endif /* !_MINIX */
801