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
