This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit d72ddce7f711b3494dd48385aa0884e8b948b2d8
Author: Marco Casaroli <[email protected]>
AuthorDate: Sun Oct 18 19:54:26 2026 +0200

    nshlib: Add the ulimit command.
    
    NSH had no way to show or change the resource limits of the shell, which
    the programs that it starts inherit.
    
    Add ulimit [-H|-S] [-a|-c|-d|-f|-l|-n|-s|-t|-v] [<limit>|unlimited], as
    in other shells.  It runs in the shell, so a limit applies to the shell
    and to the programs that it starts.  Without an option it shows the
    file size limit, as POSIX says.  Sizes are in KiB, -n is a number of
    files and -t is in seconds.  -H and -S select the hard or the soft
    limit; without them, a new value sets both.  -a shows all limits.
    
    The command is off by default, because it adds about 1 KiB to the
    image; CONFIG_NSH_DISABLE_ULIMIT=n adds it.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 nshlib/Kconfig       |   7 +++
 nshlib/nsh.h         |   4 ++
 nshlib/nsh_command.c |   5 ++
 nshlib/nsh_syscmds.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 191 insertions(+)

diff --git a/nshlib/Kconfig b/nshlib/Kconfig
index 8f1740a18..026d9acbc 100644
--- a/nshlib/Kconfig
+++ b/nshlib/Kconfig
@@ -722,6 +722,13 @@ config NSH_DISABLE_UNAME
        bool "Disable uname"
        default DEFAULT_SMALL
 
+config NSH_DISABLE_ULIMIT
+       bool "Disable ulimit"
+       default y
+       ---help---
+               The ulimit command is off by default, because it adds about
+               1 KiB to the image.
+
 config NSH_DISABLE_UNSET
        bool "Disable unset"
        default DEFAULT_SMALL
diff --git a/nshlib/nsh.h b/nshlib/nsh.h
index 3ca066867..1f98d4bf2 100644
--- a/nshlib/nsh.h
+++ b/nshlib/nsh.h
@@ -1188,6 +1188,10 @@ int cmd_switchboot(FAR struct nsh_vtbl_s *vtbl, int 
argc, FAR char **argv);
   int cmd_shutdown(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
 #endif
 
+#ifndef CONFIG_NSH_DISABLE_ULIMIT
+  int cmd_ulimit(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
+#endif
+
 #ifndef CONFIG_NSH_DISABLE_UNAME
   int cmd_uname(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
 #endif
diff --git a/nshlib/nsh_command.c b/nshlib/nsh_command.c
index 45fa3f9f5..d4e3654a1 100644
--- a/nshlib/nsh_command.c
+++ b/nshlib/nsh_command.c
@@ -657,6 +657,11 @@ static const struct cmdmap_s g_cmdmap[] =
   CMD_MAP("whoami",   cmd_whoami,   1, 1, NULL),
 #endif
 
+#ifndef CONFIG_NSH_DISABLE_ULIMIT
+  CMD_MAP("ulimit",   cmd_ulimit,   1, 4,
+          "[-H|-S] [-a|-c|-d|-f|-l|-n|-s|-t|-v] [<limit>|unlimited]"),
+#endif
+
 #ifndef CONFIG_NSH_DISABLE_UNAME
 #  ifdef CONFIG_NET
   CMD_MAP("uname",    cmd_uname,    1, 7, "[-a | -imnoprsv]"),
diff --git a/nshlib/nsh_syscmds.c b/nshlib/nsh_syscmds.c
index ec509baaf..34059bea2 100644
--- a/nshlib/nsh_syscmds.c
+++ b/nshlib/nsh_syscmds.c
@@ -32,6 +32,8 @@
 #include <nuttx/streams.h>
 #include <sys/boardctl.h>
 #include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/resource.h>
 #include <sys/utsname.h>
 #include <dirent.h>
 #include <fcntl.h>
@@ -89,6 +91,32 @@
 static const char g_unknown[] = "unknown";
 #endif
 
+#ifndef CONFIG_NSH_DISABLE_ULIMIT
+/* The options of ulimit.  The first ones select a resource: its resource,
+ * bytes per unit and name are in the tables below.
+ */
+
+static const char g_ulimit_opts[] = "cdflnstvHSa";
+
+static const int g_ulimit_resources[] =
+{
+  RLIMIT_CORE, RLIMIT_DATA, RLIMIT_FSIZE, RLIMIT_MEMLOCK,
+  RLIMIT_NOFILE, RLIMIT_STACK, RLIMIT_CPU, RLIMIT_AS
+};
+
+static const unsigned int g_ulimit_units[] =
+{
+  1024, 1024, 1024, 1024, 1, 1024, 1, 1024
+};
+
+static FAR const char * const g_ulimit_names[] =
+{
+  "core file size (KiB)", "data seg size (KiB)", "file size (KiB)",
+  "max locked memory (KiB)", "open files", "stack size (KiB)",
+  "cpu time (seconds)", "virtual memory (KiB)"
+};
+#endif
+
 #if defined(CONFIG_BOARDCTL_RESET_CAUSE) && 
!defined(CONFIG_NSH_DISABLE_RESET_CAUSE)
 
 /* Keep update with nuttx kernel definition */
@@ -932,3 +960,150 @@ int cmd_uname(FAR struct nsh_vtbl_s *vtbl, int argc, FAR 
char **argv)
   return OK;
 }
 #endif
+
+/****************************************************************************
+ * Name: cmd_ulimit
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_ULIMIT
+int cmd_ulimit(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
+{
+  unsigned long long number;
+  FAR char *endptr;
+  struct rlimit rl;
+  unsigned long long shown;
+  rlim_t value;
+  bool hard = false;
+  bool soft = false;
+  bool all = false;
+  bool badarg = false;
+  int sel = 2;       /* -f, as POSIX says */
+  int option;
+  int first;
+  int last;
+  int i;
+
+  while ((option = getopt(argc, argv, g_ulimit_opts)) != ERROR)
+    {
+      switch (option)
+        {
+          case 'H':
+            hard = true;
+            break;
+
+          case 'S':
+            soft = true;
+            break;
+
+          case 'a':
+            all = true;
+            break;
+
+          default:
+            for (i = 0; i < nitems(g_ulimit_resources); i++)
+              {
+                if (g_ulimit_opts[i] == option)
+                  {
+                    sel = i;
+                    break;
+                  }
+              }
+
+            if (i == nitems(g_ulimit_resources))
+              {
+                nsh_error(vtbl, g_fmtarginvalid, argv[0]);
+                badarg = true;
+              }
+            break;
+        }
+    }
+
+  if (badarg || argc - optind > 1 || (all && argc - optind > 0))
+    {
+      if (!badarg)
+        {
+          nsh_error(vtbl, g_fmttoomanyargs, argv[0]);
+        }
+
+      return ERROR;
+    }
+
+  /* Show the limits: the soft limit, or the hard limit with -H */
+
+  if (argc == optind)
+    {
+      first = all ? 0 : sel;
+      last  = all ? nitems(g_ulimit_resources) - 1 : sel;
+      for (i = first; i <= last; i++)
+        {
+          if (getrlimit(g_ulimit_resources[i], &rl) < 0)
+            {
+              nsh_error(vtbl, g_fmtcmdfailed, argv[0], "getrlimit",
+                        NSH_ERRNO);
+              return ERROR;
+            }
+
+          shown = hard ? rl.rlim_max : rl.rlim_cur;
+          if (all)
+            {
+              nsh_output(vtbl, "%-26s (-%c) ", g_ulimit_names[i],
+                         g_ulimit_opts[i]);
+            }
+
+          if (shown == RLIM_INFINITY)
+            {
+              nsh_output(vtbl, "unlimited\n");
+            }
+          else
+            {
+              nsh_output(vtbl, "%llu\n", shown / g_ulimit_units[i]);
+            }
+        }
+
+      return OK;
+    }
+
+  /* Set a limit: both the soft and the hard limit without -H or -S */
+
+  if (strcmp(argv[optind], "unlimited") == 0)
+    {
+      value = RLIM_INFINITY;
+    }
+  else
+    {
+      number = strtoull(argv[optind], &endptr, 10);
+      if (*argv[optind] == '\0' || *endptr != '\0' ||
+          number >= RLIM_INFINITY / g_ulimit_units[sel])
+        {
+          nsh_error(vtbl, g_fmtarginvalid, argv[0]);
+          return ERROR;
+        }
+
+      value = number * g_ulimit_units[sel];
+    }
+
+  if (getrlimit(g_ulimit_resources[sel], &rl) < 0)
+    {
+      nsh_error(vtbl, g_fmtcmdfailed, argv[0], "getrlimit", NSH_ERRNO);
+      return ERROR;
+    }
+
+  if (hard || !soft)
+    {
+      rl.rlim_max = value;
+    }
+
+  if (soft || !hard)
+    {
+      rl.rlim_cur = value;
+    }
+
+  if (setrlimit(g_ulimit_resources[sel], &rl) < 0)
+    {
+      nsh_error(vtbl, g_fmtcmdfailed, argv[0], "setrlimit", NSH_ERRNO);
+      return ERROR;
+    }
+
+  return OK;
+}
+#endif

Reply via email to