Imported from ../bash-2.0.tar.gz.
[platform/upstream/bash.git] / builtins / ulimit.def
index 1947c36..546dfd4 100644 (file)
@@ -24,7 +24,7 @@ $PRODUCES ulimit.c
 $BUILTIN ulimit
 $FUNCTION ulimit_builtin
 $DEPENDS_ON !MINIX
-$SHORT_DOC ulimit [-SHacdfmstpnuv [limit]]
+$SHORT_DOC ulimit [-SHacdflmnpstuv] [limit]
 Ulimit provides control over the resources available to processes
 started by the shell, on systems that allow such control.  If an
 option is given, it is interpreted as follows:
@@ -34,52 +34,68 @@ option is given, it is interpreted as follows:
     -a all current limits are reported
     -c the maximum size of core files created
     -d the maximum size of a process's data segment
+    -f the maximum size of files created by the shell
+    -l  the maximum size a process may lock into memory
     -m the maximum resident set size
+    -n the maximum number of open file descriptors
+    -p the pipe buffer size
     -s the maximum stack size
     -t the maximum amount of cpu time in seconds
-    -f the maximum size of files created by the shell
-    -p the pipe buffer size
-    -n the maximum number of open file descriptors
     -u the maximum number of user processes
     -v the size of virtual memory 
 
 If LIMIT is given, it is the new value of the specified resource.
 Otherwise, the current value of the specified resource is printed.
-If no option is given, then -f is assumed.  Values are in 1k
+If no option is given, then -f is assumed.  Values are in 1024-byte
 increments, except for -t, which is in seconds, -p, which is in
 increments of 512 bytes, and -u, which is an unscaled number of
 processes.
 $END
 
-#include <stdio.h>
-#include <sys/types.h>
+#include <config.h>
+
+#include "../bashtypes.h"
 #include <sys/param.h>
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <stdio.h>
 #include <errno.h>
+
 #include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
 #include "pipesize.h"
 
 #if !defined (errno)
 extern int errno;
 #endif
 
+/* For some reason, HPUX chose to make these definitions visible only if
+   _KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
+   and #undef it afterward. */
 #if defined (HAVE_RESOURCE)
 #  include <sys/time.h>
+#  if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
+#    define _KERNEL
+#  endif
 #  include <sys/resource.h>
+#  if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
+#    undef _KERNEL
+#  endif
 #else
 #  include <sys/times.h>
 #endif
 
-#if defined (HAVE_UNISTD_H)
-#  include <unistd.h>
-#endif
-
 #if defined (HAVE_LIMITS_H)
 #  include <limits.h>
 #endif
 
 /* Check for the most basic symbols.  If they aren't present, this
    system's <sys/resource.h> isn't very useful to us. */
-#if !defined (RLIMIT_FSIZE) || defined (GETRLIMIT_MISSING)
+#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
 #  undef HAVE_RESOURCE
 #endif
 
@@ -89,509 +105,412 @@ extern int errno;
 #  define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
 #endif
 
-static void print_long ();
+#define DESCFMT        "%-28s"
 
-/* **************************************************************** */
-/*                                                                 */
-/*                     Ulimit builtin and Hacks.                   */
-/*                                                                 */
-/* **************************************************************** */
+/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
+#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
+#  define RLIMIT_NOFILE RLIMIT_OFILE
+#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
 
-/* Block size for ulimit operations. */
-#define ULIMIT_BLOCK_SIZE ((long)1024)
+/* Some systems have these, some do not. */
+#ifdef RLIMIT_FSIZE
+#  define RLIMIT_FILESIZE      RLIMIT_FSIZE
+#else
+#  define RLIMIT_FILESIZE      256
+#endif
+
+#define RLIMIT_PIPESIZE        257
 
-#define u_FILE_SIZE            0x001
-#define u_MAX_BREAK_VAL                0x002
-#define u_PIPE_SIZE            0x004
-#define u_CORE_FILE_SIZE       0x008
-#define u_DATA_SEG_SIZE                0x010
-#define u_PHYS_MEM_SIZE                0x020
-#define u_CPU_TIME_LIMIT       0x040
-#define u_STACK_SIZE           0x080
-#define u_NUM_OPEN_FILES       0x100
-#define u_MAX_VIRTUAL_MEM      0x200
-#define u_MAX_USER_PROCS       0x400
+#ifdef RLIMIT_NOFILE
+#  define RLIMIT_OPENFILES     RLIMIT_NOFILE
+#else
+#  define RLIMIT_OPENFILES     258
+#endif
 
-#define u_ALL_LIMITS           0x7ff
+#ifdef RLIMIT_VMEM
+#  define RLIMIT_VIRTMEM       RLIMIT_VMEM
+#  define RLIMIT_VMBLKSZ       1024
+#else
+#  ifdef RLIMIT_AS
+#    define RLIMIT_VIRTMEM     RLIMIT_AS
+#    define RLIMIT_VMBLKSZ     1024
+#  else
+#    define RLIMIT_VIRTMEM     259
+#    define RLIMIT_VMBLKSZ     1
+#  endif
+#endif
+
+#ifdef RLIMIT_NPROC
+#  define RLIMIT_MAXUPROC      RLIMIT_NPROC
+#else
+#  define RLIMIT_MAXUPROC      260
+#endif
 
 #if !defined (RLIM_INFINITY)
-#  define RLIM_INFINITY  0x7fffffff
+#  define RLIM_INFINITY 0x7fffffff
 #endif
 
-/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
-#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
-#  define RLIMIT_NOFILE RLIMIT_OFILE
-#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
+#if !defined (RLIM_INVALID)
+#  define RLIM_INVALID (RLIMTYPE)-1
+#endif
 
 #define LIMIT_HARD 0x01
 #define LIMIT_SOFT 0x02
 
-static RLIMTYPE shell_ulimit ();
+static int ulimit_internal ();
+static void printone ();
+static void print_all_limits ();
+
+static int get_limit ();
+static int set_limit ();
+
+static RLIMTYPE filesize ();
 static RLIMTYPE pipesize ();
-static RLIMTYPE open_files ();
+static RLIMTYPE getmaxuprc ();
+static RLIMTYPE getmaxvm ();
+
+typedef struct {
+  int  option;                 /* The ulimit option for this limit. */
+  int  parameter;              /* Parameter to pass to get_limit (). */
+  int  block_factor;           /* Blocking factor for specific limit. */
+  char *description;           /* Descriptive string to output. */
+} RESOURCE_LIMITS;
 
+static RESOURCE_LIMITS limits[] = {
+#ifdef RLIMIT_CORE
+  { 'c',       RLIMIT_CORE,  1024, "core file size (blocks)" },
+#endif
+#ifdef RLIMIT_DATA
+  { 'd',       RLIMIT_DATA,  1024, "data seg size (kbytes)" },
+#endif
+  { 'f',       RLIMIT_FILESIZE, 1024, "file size (blocks)" },
+#ifdef RLIMIT_MEMLOCK
+  { 'l',       RLIMIT_MEMLOCK, 1024, "max locked memory (kbytes)" },
+#endif
+#ifdef RLIMIT_RSS
+  { 'm',       RLIMIT_RSS,   1024, "max memory size (kbytes)" },
+#endif /* RLIMIT_RSS */
+  { 'n',       RLIMIT_OPENFILES, 1, "open files" },
+  { 'p',       RLIMIT_PIPESIZE, 512, "pipe size (512 bytes)" },
+#ifdef RLIMIT_STACK
+  { 's',       RLIMIT_STACK, 1024, "stack size (kbytes)" },
+#endif
+#ifdef RLIMIT_CPU
+  { 't',       RLIMIT_CPU,      1, "cpu time (seconds)" },
+#endif /* RLIMIT_CPU */
+  { 'u',       RLIMIT_MAXUPROC, 1, "max user processes" },
 #if defined (HAVE_RESOURCE)
-static RLIMTYPE getmaxvm ();
-#endif /* HAVE_RESOURCE */
+  { 'v',       RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory (kbytes)" },
+#endif
+  { -1, -1, -1, (char *)NULL }
+};
+#define NCMDS  (sizeof(limits) / sizeof(limits[0]))
 
-static void print_specific_limits ();
-static void print_all_limits ();
+typedef struct _cmd {
+  int cmd;
+  char *arg;
+} ULCMD;
 
-static char t[2];
+static ULCMD *cmdlist;
+static int ncmd;
+static int cmdlistsz;
 
-/* Return 1 if the limit associated with CMD can be raised from CURRENT
-   to NEW.  This is for USG systems without HAVE_RESOURCE, most of which
-   do not allow any user other than root to raise limits.  There are,
-   however, exceptions. */
-#if !defined (HAVE_RESOURCE)
 static int
-canraise (cmd, current, new)
-     int cmd;
-     RLIMTYPE current, new;
+_findlim (opt)
+     int opt;
 {
-#  if defined (HAVE_SETDTABLESIZE)
-  if (cmd == u_NUM_OPEN_FILES)
-    return (1);
-#  endif /* HAVE_SETDTABLSIZE */
+  register int i;
 
-  return ((current > new) || (current_user.uid == 0));
+  for (i = 0; limits[i].option > 0; i++)
+    if (limits[i].option == opt)
+      return i;
+  return -1;
 }
-#endif /* !HAVE_RESOURCE */
 
-/* Report or set limits associated with certain per-process resources.
-   See the help documentation in builtins.c for a full description.
+static char optstring[4 + 2 * NCMDS];
 
-   Rewritten by Chet Ramey 6/30/91. */
+/* Report or set limits associated with certain per-process resources.
+   See the help documentation in builtins.c for a full description. */
 int
 ulimit_builtin (list)
      register WORD_LIST *list;
 {
   register char *s;
-  int c, setting, cmd, mode, verbose_print, opt_eof;
-  int all_limits, specific_limits;
-  long block_factor;
-  RLIMTYPE current_limit, real_limit, limit;
+  int c, limind, mode, opt, all_limits;
 
-  c = mode = verbose_print = opt_eof = 0;
-  limit = (RLIMTYPE)-1;
+  mode = 0;
 
-  do
-    {
-      cmd = setting = all_limits = specific_limits = 0;
-      block_factor = ULIMIT_BLOCK_SIZE;
+  all_limits = 0;
 
-      /* read_options: */
-      if (list && !opt_eof && *list->word->word == '-')
+  /* Idea stolen from pdksh -- build option string the first time called. */
+  if (optstring[0] == 0)
+    {
+      s = optstring;
+      *s++ = 'a'; *s++ = 'S'; *s++ = 'H';
+      for (c = 0; limits[c].option > 0; c++)
        {
-         s = &(list->word->word[1]);
-         list = list->next;
-
-         while (*s && (c = *s++))
-           {
-             switch (c)
-               {
-#define ADD_CMD(x) { if (cmd) specific_limits++; cmd |= (x); }
-
-               case '-':       /* ulimit -- */
-                 opt_eof++;
-                 break;
-                 
-               case 'a':
-                 all_limits++;
-                 break;
-
-               case 'f':
-                 ADD_CMD (u_FILE_SIZE);
-                 break;
-
-#if defined (HAVE_RESOURCE)
-               /* -S and -H are modifiers, not real options.  */
-               case 'S':
-                 mode |= LIMIT_SOFT;
-                 break;
-
-               case 'H':
-                 mode |= LIMIT_HARD;
-                 break;
-
-               case 'c':
-                 ADD_CMD (u_CORE_FILE_SIZE);
-                 break;
-
-               case 'd':
-                 ADD_CMD (u_DATA_SEG_SIZE);
-                 break;
-
-#if !defined (USGr4)
-               case 'm':
-                 ADD_CMD (u_PHYS_MEM_SIZE);
-                 break;
-#endif /* USGr4 */
-
-               case 't':
-                 ADD_CMD (u_CPU_TIME_LIMIT);
-                 block_factor = 1;     /* seconds */
-                 break;
-
-               case 's':
-                 ADD_CMD (u_STACK_SIZE);
-                 break;
-
-               case 'v':
-                 ADD_CMD (u_MAX_VIRTUAL_MEM);
-                 block_factor = 1;
-                 break;
-
-               case 'u':
-                 ADD_CMD (u_MAX_USER_PROCS);
-                 block_factor = 1;
-                 break;
-
-#endif /* HAVE_RESOURCE */
-
-               case 'p':
-                 ADD_CMD (u_PIPE_SIZE);
-                 block_factor = 512;
-                 break;
-
-               case 'n':
-                 ADD_CMD (u_NUM_OPEN_FILES);
-                 block_factor = 1;
-                 break;
-
-               default:                /* error_case: */
-                 t[0] = c;
-                 t[1] = '\0';
-                 bad_option (t);
-#if !defined (HAVE_RESOURCE)
-                 builtin_error("usage: ulimit [-afnp] [new limit]");
-#else
-                 builtin_error("usage: ulimit [-SHacmdstfnpuv] [new limit]");
-#endif
-                 return (EX_USAGE);
-               }
-           }
+         *s++ = limits[c].option;
+         *s++ = ';';
        }
+      *s = '\0';
+    }
 
-       if (all_limits)
-         {
-           print_all_limits (mode);
-           return (EXECUTION_SUCCESS);
-         }
-
-       if (specific_limits)
-         {
-           print_specific_limits (cmd, mode);
-           if (list)
-             verbose_print++;
-           continue;
-         }
-
-       if (cmd == 0)
-         cmd = u_FILE_SIZE;
-
-       /* If an argument was supplied for the command, then we want to
-          set the limit.  Note that `ulimit something' means a command
-          of -f with argument `something'. */
-       if (list)
-         {
-           if (opt_eof || (*list->word->word != '-'))
-             {
-               s = list->word->word;
-               list = list->next;
-
-               if (STREQ (s, "unlimited"))
-                 limit = RLIM_INFINITY;
-               else if (all_digits (s))
-                 limit = string_to_rlimtype (s);
-               else
-                 {
-                   builtin_error ("bad non-numeric arg `%s'", s);
-                   return (EXECUTION_FAILURE);
-                 }
-               setting++;
-             }
-           else if (!opt_eof)
-             verbose_print++;
-         }
-
-      if (limit == RLIM_INFINITY)
-       block_factor = 1;
-
-      real_limit = limit * block_factor;
-
-      /* If more than one option is given, list each in a verbose format,
-        the same that is used for -a. */
-      if (!setting && verbose_print)
+  /* Initialize the command list. */
+  if (cmdlistsz == 0)
+    cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
+  ncmd = 0;
+
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, optstring)) != -1)
+    {
+      switch (opt)
        {
-         print_specific_limits (cmd, mode);
-         continue;
+       case 'a':
+         all_limits++;
+         break;
+
+       /* -S and -H are modifiers, not real options.  */
+       case 'S':
+         mode |= LIMIT_SOFT;
+         break;
+
+       case 'H':
+         mode |= LIMIT_HARD;
+         break;
+
+       case '?':
+         builtin_usage ();
+         return (EX_USAGE);
+
+       default:
+         if (ncmd >= cmdlistsz)
+           cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
+         cmdlist[ncmd].cmd = opt;
+         cmdlist[ncmd++].arg = list_optarg;
+         break;
        }
+    }
+  list = loptend;
 
-      current_limit = shell_ulimit (cmd, real_limit, 0, mode);
+  if (all_limits)
+    {
+      print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
+      return (EXECUTION_SUCCESS);
+    }
 
-      if (setting)
-       {
-#if !defined (HAVE_RESOURCE)
-         /* Most USG systems do not most allow limits to be raised by any
-            user other than root.  There are, however, exceptions. */
-         if (canraise (cmd, current_limit, real_limit) == 0)
-           {
-             builtin_error ("cannot raise limit: %s", strerror (EPERM));
-             return (EXECUTION_FAILURE);
-           }
-#endif /* !HAVE_RESOURCE */
-
-         if (shell_ulimit (cmd, real_limit, 1, mode) == (RLIMTYPE)-1)
-           {
-             builtin_error ("cannot raise limit: %s", strerror (errno));
-             return (EXECUTION_FAILURE);
-           }
-
-         continue;
-       }
-      else
+  /* default is `ulimit -f' */
+  if (ncmd == 0)
+    {
+      cmdlist[ncmd].cmd = 'f';
+      /* `ulimit something' is same as `ulimit -f something' */
+      cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
+      if (list)
+       list = list->next;
+    }
+
+  /* verify each command in the list. */
+  for (c = 0; c < ncmd; c++)
+    {
+      limind = _findlim (cmdlist[c].cmd);
+      if (limind == -1)
        {
-         if (current_limit < 0)
-           builtin_error ("cannot get limit: %s", strerror (errno));
-         else if (current_limit != RLIM_INFINITY)
-           print_rlimtype ((current_limit / block_factor), 1);
-         else
-           printf ("unlimited\n");
+         builtin_error ("bad command: `%c'", cmdlist[c].cmd);
+         return (EX_USAGE);
        }
     }
-  while (list);
+
+  for (c = 0; c < ncmd; c++)
+    if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
+      return (EXECUTION_FAILURE);
 
   return (EXECUTION_SUCCESS);
 }
 
-/* The ulimit that we call from within Bash.
+static int
+ulimit_internal (cmd, cmdarg, mode, multiple)
+     int cmd;
+     char *cmdarg;
+     int mode, multiple;
+{
+  int opt, limind, setting;
+  long block_factor;
+  RLIMTYPE current_limit, real_limit, limit;
 
-   WHICH says which limit to twiddle; SETTING is non-zero if NEWLIM
-   contains the desired new limit.  Otherwise, the existing limit is
-   returned.  If mode & LIMIT_HARD, the hard limit is used; if
-   mode & LIMIT_SOFT, the soft limit.  Both may be set by specifying
-   -H and -S; if both are specified, or if neither is specified, the
-   soft limit will be returned.
+  limit = RLIM_INVALID;
+  setting = cmdarg != 0;
+  limind = _findlim (cmd);
+  if (mode == 0)
+    mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
+  opt = get_limit (limind, mode, &current_limit);
+  if (opt < 0)
+    {
+      builtin_error ("cannot get limit: %s", strerror (errno));
+      return (EXECUTION_FAILURE);
+    }
 
-   Systems without BSD resource limits can specify only u_FILE_SIZE.
-   This includes most USG systems.
+  if (setting == 0)    /* print the value of the specified limit */
+    {
+      printone (limind, current_limit, multiple);
+      return (EXECUTION_SUCCESS);
+    }
+  /* Setting the limit. */
+  if (STREQ (cmdarg, "unlimited"))
+    limit = RLIM_INFINITY;
+  else if (all_digits (cmdarg))
+    limit = string_to_rlimtype (cmdarg);
+  else
+    {
+      builtin_error ("bad non-numeric arg `%s'", cmdarg);
+      return (EXECUTION_FAILURE);
+    }
 
-   Chet Ramey supplied the BSD resource limit code. */
-static RLIMTYPE
-shell_ulimit (which, newlim, setting, mode)
-     int which, setting, mode;
-     RLIMTYPE newlim;
+  block_factor = (limit == RLIM_INFINITY) ? 1 : limits[limind].block_factor;
+  real_limit = limit * block_factor;
+
+  if (set_limit (limind, real_limit, mode) < 0)
+    {
+      builtin_error ("cannot modify limit: %s", strerror (errno));
+      return (EXECUTION_FAILURE);
+    }
+  return (EXECUTION_SUCCESS);
+}
+
+static int
+get_limit (ind, mode, limptr)
+     int ind, mode;
+     RLIMTYPE *limptr;
 {
+  RLIMTYPE value;
 #if defined (HAVE_RESOURCE)
   struct rlimit limit;
-  int cmd;
-
-  if (mode == 0)
-    mode |= LIMIT_SOFT;
 #endif
 
-  switch (which)
+  if (limits[ind].parameter >= 256)
     {
-#if !defined (HAVE_RESOURCE)
-
-    case u_FILE_SIZE:
-      if (!setting)
+      switch (limits[ind].parameter)
        {
-         /* ulimit () returns a number that is in 512 byte blocks, thus we
-            must multiply it by 512 to get back to bytes.  This is false
-            only under HP/UX 6.x. */
-         RLIMTYPE result;
-
-         result = ulimit (1, 0L);
-
-#  if defined (hpux) && !defined (_POSIX_VERSION)
-         return (result);
-#  else
-         return (result * 512);
-#  endif /* hpux 6.x */
+       case RLIMIT_FILESIZE:
+         value = filesize ();
+         break;
+       case RLIMIT_PIPESIZE:
+         value = pipesize ();
+         break;
+       case RLIMIT_OPENFILES:
+         value = (RLIMTYPE)getdtablesize ();
+         break;
+       case RLIMIT_VIRTMEM:
+         value = getmaxvm (mode);
+         break;
+       case RLIMIT_MAXUPROC:
+         value = getmaxuprc (mode);
+         break;
+       default:
+         errno = EINVAL;
+         return -1;
        }
-      else
-       return (ulimit (2, newlim / 512L));
-
-      break;
-
-#else /* defined (HAVE_RESOURCE) */
-
-    case u_FILE_SIZE:
-      cmd = RLIMIT_FSIZE;
-      goto do_ulimit;
-
-    case u_CORE_FILE_SIZE:
-      cmd = RLIMIT_CORE;
-      goto do_ulimit;
-
-    case u_DATA_SEG_SIZE:
-      cmd = RLIMIT_DATA;
-      goto do_ulimit;
-
-#if !defined (USGr4)
-    case u_PHYS_MEM_SIZE:
-#  if defined (RLIMIT_RSS)
-      cmd = RLIMIT_RSS;
-#  else /* !RLIMIT_RSS */
-      errno = EINVAL;
-      return ((RLIMTYPE)-1);
-#  endif /* !RLIMIT_RSS */
-
-      goto do_ulimit;
-#endif /* USGr4 */
-
-    case u_CPU_TIME_LIMIT:
-#if defined (RLIMIT_CPU)
-      cmd = RLIMIT_CPU;
-      goto do_ulimit;
+      *limptr = value;
+      return ((value == RLIM_INVALID) ? -1 : 0);
+    }
+  else
+    {
+#if defined (HAVE_RESOURCE)
+      if (getrlimit (limits[ind].parameter, &limit) < 0)
+       return -1;
+      value = (mode & LIMIT_SOFT) ? limit.rlim_cur : limit.rlim_max;
+      *limptr = value;
+      return 0;
 #else
       errno = EINVAL;
-      return ((RLIMTYPE)-1);
-#  endif /* !RLIMIT_CPU */
-
-
-    case u_STACK_SIZE:
-      cmd = RLIMIT_STACK;
-
-    do_ulimit:
-
-      if (getrlimit (cmd, &limit) != 0)
-       return ((RLIMTYPE)-1);
-
-      if (!setting)
-       {
-         if (mode & LIMIT_SOFT)
-           return (limit.rlim_cur);
-         else
-           return (limit.rlim_max);
-       }
-      else
-       {
-         if (mode & LIMIT_SOFT)
-           {
-             /* Non-root users are only allowed to raise a limit up to the
-                hard limit, not to infinity. */
-             if (current_user.euid != 0 && newlim == RLIM_INFINITY)
-               limit.rlim_cur = limit.rlim_max;
-             else
-               limit.rlim_cur = newlim;
-           }
-         if (mode & LIMIT_HARD)
-           limit.rlim_max = newlim;
-
-         return (setrlimit (cmd, &limit));
-       }
-
-      break;
-
-#endif /* HAVE_RESOURCE */
+      return -1;
+#endif
+    }
+}
 
-      /* You can't get or set the pipe size with getrlimit, so we have to
-        cheat.  */
-    case u_PIPE_SIZE:
-      if (setting)
-       {
-         errno = EINVAL;
-         return ((RLIMTYPE)-1);
-       }
-      return (pipesize ());
+static int
+set_limit (ind, newlim, mode)
+     int ind;
+     RLIMTYPE newlim;
+     int mode;
+{
+#if defined (HAVE_RESOURCE)
+   struct rlimit limit;
+   RLIMTYPE val;
+#endif
 
-    case u_NUM_OPEN_FILES:
-      if (setting)
-       {
-#if defined (HAVE_RESOURCE) && defined (RLIMIT_NOFILE)
-         cmd = RLIMIT_NOFILE;
-         goto do_ulimit;
-#else
-#  if defined (HAVE_SETDTABLESIZE)
-         return (setdtablesize (newlim));
-#  else
-         errno = EINVAL;
-         return ((RLIMTYPE)-1);
-#  endif /* HAVE_SETDTABLESIZE */
-#endif /* !HAVE_RESOURCE || !RLIMIT_NOFILE */
-       }
-      else
-       return (open_files (mode));
+  if (limits[ind].parameter >= 256)
+    switch (limits[ind].parameter)
+      {
+      case RLIMIT_FILESIZE:
+#if !defined (HAVE_RESOURCE)
+       return (ulimit (2, newlim / 512L));
+#endif
 
-    case u_MAX_VIRTUAL_MEM:
-      if (setting)
-       {
-         errno = EINVAL;
-         return ((RLIMTYPE)-1);
-       }
-      else
-       {
+      case RLIMIT_OPENFILES:
+#if defined (HAVE_SETDTABLESIZE)
+       return (setdtablesize (newlim));
+#endif
+      case RLIMIT_PIPESIZE:
+      case RLIMIT_VIRTMEM:
+      case RLIMIT_MAXUPROC:
+      default:
+       errno = EINVAL;
+       return -1;
+      }
+  else
+    {
 #if defined (HAVE_RESOURCE)
-         return (getmaxvm (mode));
-#else /* !HAVE_RESOURCE */
-         errno = EINVAL;
-         return ((RLIMTYPE)-1);
-#endif /* !HAVE_RESOURCE */
-       }
-
-    case u_MAX_USER_PROCS:
-#if defined (HAVE_RESOURCE) && defined (RLIMIT_NPROC)
-      cmd = RLIMIT_NPROC;
-      goto do_ulimit;
-#else /* !HAVE_RESOURCE || !RLIMIT_NPROC */
-      errno = EINVAL;
-      return ((RLIMTYPE)-1);
-#endif /* !HAVE_RESOURCE || !RLIMIT_NPROC */
-      
-    default:
+      if (getrlimit (limits[ind].parameter, &limit) < 0)
+       return -1;
+      val = (current_user.euid != 0 && newlim == RLIM_INFINITY)
+               ? limit.rlim_max : newlim;
+      if (mode & LIMIT_SOFT)
+       limit.rlim_cur = val;
+      if (mode & LIMIT_HARD)
+       limit.rlim_max = val;
+         
+      return (setrlimit (limits[ind].parameter, &limit));
+#else
       errno = EINVAL;
-      return ((RLIMTYPE)-1);
+      return -1;
+#endif
     }
 }
 
-#if defined (HAVE_RESOURCE)
 static RLIMTYPE
 getmaxvm (mode)
      int mode;
 {
+#if defined (HAVE_RESOURCE)
   struct rlimit rl;
-
-#if defined (RLIMIT_VMEM)
-  if (getrlimit (RLIMIT_VMEM, &rl) < 0)
-    return ((RLIMTYPE)-1);
-  else
-    return (((mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max) / 1024L);
-#else /* !RLIMIT_VMEM */
   RLIMTYPE maxdata, maxstack;
 
   if (getrlimit (RLIMIT_DATA, &rl) < 0)
-    return ((RLIMTYPE)-1);
+    return (RLIM_INVALID);
   else
     maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
 
   if (getrlimit (RLIMIT_STACK, &rl) < 0)
-    return ((RLIMTYPE)-1);
+    return (RLIM_INVALID);
   else
     maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
 
   /* Protect against overflow. */
   return ((maxdata / 1024L) + (maxstack / 1024L));
-#endif /* !RLIMIT_VMEM */
-}
+#else
+  errno = EINVAL;
+  return RLIM_INVALID;
 #endif /* HAVE_RESOURCE */
+}
 
 static RLIMTYPE
-open_files (mode)
-     int mode;
+filesize()
 {
-#if !defined (RLIMIT_NOFILE)
-  return ((RLIMTYPE)getdtablesize ());
+#if !defined (HAVE_RESOURCE)
+  return ((RLIMTYPE)ulimit (1, 0L));
 #else
-  struct rlimit rl;
-
-  getrlimit (RLIMIT_NOFILE, &rl);
-  if (mode & LIMIT_SOFT)
-    return (rl.rlim_cur);
-  else
-    return (rl.rlim_max);
+  errno = EINVAL;
+  return RLIM_INVALID;
 #endif
 }
 
@@ -607,125 +526,57 @@ pipesize ()
   return ((RLIMTYPE) PIPESIZE);
 #  else
   errno = EINVAL;
-  return ((RLIMTYPE)-1);
+  return RLIM_INVALID;  
 #  endif /* PIPESIZE */
 #endif /* PIPE_BUF */
 }
 
-/* ulimit(2) returns information about file size limits in terms of 512-byte
-   blocks.  This is the factor by which to divide to turn it into information
-   in terms of 1024-byte blocks.  Except for hpux 6.x, which returns it in
-   terms of bytes. */
-#if !defined (hpux) || defined (_POSIX_VERSION)
-#  define ULIMIT_DIVISOR 2
-#else
-#  define ULIMIT_DIVISOR 1024
-#endif
-
-#if defined (HAVE_RESOURCE)
-
-typedef struct {
-  int  option_cmd;             /* The ulimit command for this limit. */
-  int  parameter;              /* Parameter to pass to getrlimit (). */
-  int  block_factor;           /* Blocking factor for specific limit. */
-  char *description;           /* Descriptive string to output. */
-} BSD_RESOURCE_LIMITS;
-
-static BSD_RESOURCE_LIMITS limits[] = {
-  { u_CORE_FILE_SIZE, RLIMIT_CORE,  1024, "core file size (blocks)" },
-  { u_DATA_SEG_SIZE,  RLIMIT_DATA,  1024, "data seg size (kbytes)" },
-  { u_FILE_SIZE,      RLIMIT_FSIZE, 1024, "file size (blocks)" },
-#if !defined (USGr4) && defined (RLIMIT_RSS)
-  { u_PHYS_MEM_SIZE,  RLIMIT_RSS,   1024, "max memory size (kbytes)" },
-#endif /* USGr4 && RLIMIT_RSS */
-  { u_STACK_SIZE,     RLIMIT_STACK, 1024, "stack size (kbytes)" },
-#if defined (RLIMIT_CPU)
-  { u_CPU_TIME_LIMIT, RLIMIT_CPU,      1, "cpu time (seconds)" },
-#endif /* RLIMIT_CPU */
-#if defined (RLIMIT_NPROC)
-  { u_MAX_USER_PROCS, RLIMIT_NPROC,    1, "max user processes" },
-#endif /* RLIMIT_NPROC */
-  { 0, 0, 0, (char *)NULL }
-};
-
-static void
-print_bsd_limit (i, mode)
-     int i, mode;
+static RLIMTYPE
+getmaxuprc (mode)
+     int mode;
 {
-  struct rlimit rl;
-  RLIMTYPE limit;
-
-  getrlimit (limits[i].parameter, &rl);
-  if (mode & LIMIT_HARD)
-    limit = rl.rlim_max;
-  else
-    limit = rl.rlim_cur;
-  printf ("%-25s", limits[i].description);
-  if (limit == RLIM_INFINITY)
-    printf ("unlimited\n");
-  else
-    print_rlimtype ((limit / limits[i].block_factor), 1);
+#  if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
+  return ((RLIMTYPE)sysconf (_SC_CHILD_MAX));
+#  else /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
+#    if defined (MAXUPRC)
+  return ((RLIMTYPE)MAXUPRC);
+#    else /* MAXUPRC */
+  errno = EINVAL;
+  return RLIM_INVALID;
+#    endif /* !MAXUPRC */
+#  endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
 }
 
 static void
-print_specific_bsd_limits (cmd, mode)
-     int cmd, mode;
+print_all_limits (mode)
+     int mode;
 {
   register int i;
+  RLIMTYPE value;
 
-  for (i = 0; limits[i].option_cmd; i++)
-    if (cmd & limits[i].option_cmd)
-      print_bsd_limit (i, mode);
-}
-#endif /* HAVE_RESOURCE */
-
-/* Print the limits corresponding to a specific set of resources.  This is
-   called when an option string contains more than one character (e.g. -at),
-   because limits may not be specified with that kind of argument. */
-static void
-print_specific_limits (cmd, mode)
-     int cmd, mode;
-{
   if (mode == 0)
-    mode = LIMIT_SOFT;
-
-#if defined (HAVE_RESOURCE)
-  print_specific_bsd_limits (cmd, mode);
-#else /* !HAVE_RESOURCE */
-  if (cmd & u_FILE_SIZE)
-    {
-      printf ("%-25s", "file size (blocks)");
-      print_rlimtype ((ulimit (1, 0L) / ULIMIT_DIVISOR), 1);
-    }
-#endif /* !HAVE_RESOURCE */
-
-  if (cmd & u_PIPE_SIZE)
-    {
-      printf ("%-25s", "pipe size (512 bytes)");
-      print_rlimtype ((pipesize () / 512), 1);
-    }
-
-  if (cmd & u_NUM_OPEN_FILES)
-    {
-      printf ("%-25s", "open files");
-      print_rlimtype (open_files (mode), 1);
-    }
+    mode |= LIMIT_SOFT;
 
-#if defined (HAVE_RESOURCE)
-  if (cmd & u_MAX_VIRTUAL_MEM)
+  for (i = 0; limits[i].option > 0; i++)
     {
-      printf ("%-25s", "virtual memory (kbytes)");
-      print_rlimtype (getmaxvm (mode), 1);
+      if (get_limit (i, mode, &value) < 0)
+       value = RLIM_INVALID;
+      printone (i, value, 1);     
     }
-#endif /* HAVE_RESOURCE */
 }
 
 static void
-print_all_limits (mode)
-     int mode;
+printone (limind, curlim, pdesc)
+     int limind;
+     RLIMTYPE curlim;
+     int pdesc;
 {
-  if (mode == 0)
-    mode |= LIMIT_SOFT;
-
-  print_specific_limits (u_ALL_LIMITS, mode);
+  if (pdesc)
+    printf (DESCFMT, limits[limind].description);
+  if (curlim == RLIM_INFINITY)
+    puts ("unlimited");
+  else if (curlim == RLIM_INVALID)
+    printf ("cannot get limit: %s\n", strerror (errno));
+  else
+    print_rlimtype ((curlim / limits[limind].block_factor), 1);
 }