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
The following commit(s) were added to refs/heads/master by this push:
new 101b713be nshlib: add du command support
101b713be is described below
commit 101b713be6c42dd757e63c020af3aacbd14d257e
Author: Junbo Zheng <[email protected]>
AuthorDate: Thu Jul 23 19:47:13 2026 +0800
nshlib: add du command support
Add a du command to NSH that recursively summarizes the size of each
path argument in 1K-blocks, or human-readable form with -h.
Supports -s (summary only), -a (all files), -d N (max-depth), and -h,
matching GNU du semantics.
Testing:
Built and ran on sim:nsh with:
```bash
cmake -B out/nuttx_sim_nsh -S nuttx -DBOARD_CONFIG=sim:nsh -GNinja
ninja -C out/nuttx_sim_nsh
./out/nuttx_sim_nsh/nuttx
nsh> du
397449 /data/test/elf
71993 /data/test/coredump
5 /data/test/log2
3251 /data/test/log1
472700 /data/test
nsh> du -h
388.1M /data/test/elf
70.3M /data/test/coredump
4.1K /data/test/log2
3.1M /data/test/log1
461.6M /data/test
```
Host Ubuntu22.04 du on the same directory:
```bash
$ du
397456 ./elf
72000 ./coredump
8 ./log2
3252 ./log1
472720 .
$ du -h
389M ./elf
71M ./coredump
8.0K ./log2
3.2M ./log1
462M .
```
Signed-off-by: Junbo Zheng <[email protected]>
---
nshlib/Kconfig | 4 +
nshlib/nsh.h | 10 ++-
nshlib/nsh_command.c | 5 ++
nshlib/nsh_fscmds.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 249 insertions(+), 3 deletions(-)
diff --git a/nshlib/Kconfig b/nshlib/Kconfig
index 165bcc8b3..499f09345 100644
--- a/nshlib/Kconfig
+++ b/nshlib/Kconfig
@@ -413,6 +413,10 @@ config NSH_DISABLE_DMESG
bool "Disable dmesg"
default DEFAULT_SMALL
+config NSH_DISABLE_DU
+ bool "Disable du"
+ default DEFAULT_SMALL
+
config NSH_DISABLE_ECHO
bool "Disable echo"
default DEFAULT_SMALL
diff --git a/nshlib/nsh.h b/nshlib/nsh.h
index d2b7abc44..a7ceb7c95 100644
--- a/nshlib/nsh.h
+++ b/nshlib/nsh.h
@@ -411,12 +411,13 @@
#define NSH_HAVE_IOBUFFER 1
-/* The I/O buffer is needed for the ls, cp, and ps commands. It is also
- * needed if the platform supplied MOTD is configured.
+/* The I/O buffer is needed for the ls, cp, du, and ps commands. It is
+ * also needed if the platform supplied MOTD is configured.
*/
#if defined(CONFIG_NSH_DISABLE_LS) && defined(CONFIG_NSH_DISABLE_CP) && \
- defined(CONFIG_NSH_DISABLE_PS) && !defined(CONFIG_NSH_PLATFORM_MOTD) && \
+ defined(CONFIG_NSH_DISABLE_DU) && defined(CONFIG_NSH_DISABLE_PS) && \
+ !defined(CONFIG_NSH_PLATFORM_MOTD) && \
defined(CONFIG_DISABLE_ENVIRON)
# undef NSH_HAVE_IOBUFFER
#endif
@@ -996,6 +997,9 @@ int cmd_irqinfo(FAR struct nsh_vtbl_s *vtbl, int argc, FAR
char **argv);
#ifndef CONFIG_NSH_DISABLE_LS
int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
#endif
+#ifndef CONFIG_NSH_DISABLE_DU
+ int cmd_du(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
+#endif
#if defined(CONFIG_SYSLOG_DEVPATH) && !defined(CONFIG_NSH_DISABLE_DMESG)
int cmd_dmesg(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 a50e223c9..098abaa76 100644
--- a/nshlib/nsh_command.c
+++ b/nshlib/nsh_command.c
@@ -354,6 +354,11 @@ static const struct cmdmap_s g_cmdmap[] =
CMD_MAP("ls", cmd_ls, 1, 5, "[-lRsh] <dir-path>"),
#endif
+#ifndef CONFIG_NSH_DISABLE_DU
+ CMD_MAP("du", cmd_du, 1, 7,
+ "[-h] [-s] [-a] [-d N] <path>..."),
+#endif
+
#if defined(CONFIG_MODULE) && !defined(CONFIG_NSH_DISABLE_MODCMDS)
# if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
CMD_MAP("lsmod", cmd_lsmod, 1, 1, NULL),
diff --git a/nshlib/nsh_fscmds.c b/nshlib/nsh_fscmds.c
index a3423494c..0a6fd945f 100644
--- a/nshlib/nsh_fscmds.c
+++ b/nshlib/nsh_fscmds.c
@@ -1855,6 +1855,239 @@ int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, FAR
char **argv)
}
#endif
+/****************************************************************************
+ * Name: du_print
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_DU
+#define DU_FLAG_HUMANREADABLE (1 << 0) /* -h: human readable sizes */
+#define DU_FLAG_ALL (1 << 1) /* -a: list all files, not only dirs */
+
+static void du_print(FAR struct nsh_vtbl_s *vtbl, FAR const char *path,
+ off_t bytes, unsigned int flags)
+{
+ off_t kblocks = (bytes + 1023) / 1024;
+
+ if ((flags & DU_FLAG_HUMANREADABLE) != 0)
+ {
+ off_t unit;
+ char suffix;
+
+ if (bytes >= GB)
+ {
+ unit = GB;
+ suffix = 'G';
+ }
+ else if (bytes >= MB)
+ {
+ unit = MB;
+ suffix = 'M';
+ }
+ else if (bytes >= KB)
+ {
+ unit = KB;
+ suffix = 'K';
+ }
+ else
+ {
+ nsh_output(vtbl, "%" PRIdOFF "B\t%s\n", bytes, path);
+ return;
+ }
+
+ /* Use integer arithmetic to avoid floating point */
+
+ nsh_output(vtbl, "%" PRIdOFF ".%" PRIdOFF "%c\t%s\n",
+ bytes / unit, (bytes % unit) * 10 / unit, suffix, path);
+ }
+ else
+ {
+ nsh_output(vtbl, "%" PRIdOFF "\t%s\n", kblocks, path);
+ }
+}
+
+static off_t du_recursive(FAR struct nsh_vtbl_s *vtbl, FAR const char *path,
+ unsigned int flags, int printlimit, int depth)
+{
+ FAR struct dirent *entry;
+ FAR char *child;
+ struct stat st;
+ off_t total;
+ DIR *dp;
+
+ if (lstat(path, &st) < 0)
+ {
+ nsh_error(vtbl, g_fmtcmdfailed, "du", "stat", NSH_ERRNO);
+ return 0;
+ }
+
+ /* st_size not st_blocks: units differ (NuttX FS=st_blksize, hostfs=512) */
+
+ total = st.st_size;
+
+ /* A file argument (depth 0) is always shown; nested files need -a. */
+
+ if (!S_ISDIR(st.st_mode))
+ {
+ if (depth == 0 ||
+ ((flags & DU_FLAG_ALL) != 0 && depth <= printlimit))
+ {
+ du_print(vtbl, path, total, flags);
+ }
+
+ return total;
+ }
+
+ dp = opendir(path);
+ if (dp == NULL)
+ {
+ nsh_error(vtbl, g_fmtcmdfailed, "du", "opendir", NSH_ERRNO);
+ }
+ else
+ {
+ while ((entry = readdir(dp)) != NULL)
+ {
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0)
+ {
+ continue;
+ }
+
+ child = nsh_getdirpath(vtbl, path, entry->d_name);
+ if (child == NULL)
+ {
+ nsh_error(vtbl, g_fmtcmdfailed, "du", "nsh_getdirpath",
+ NSH_ERRNO);
+ continue;
+ }
+
+ total += du_recursive(vtbl, child, flags, printlimit, depth + 1);
+ free(child);
+ }
+
+ closedir(dp);
+ }
+
+ /* Print this directory's cumulative total unless suppressed by -s/-d. */
+
+ if (depth <= printlimit)
+ {
+ du_print(vtbl, path, total, flags);
+ }
+
+ return total;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_du
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_DU
+int cmd_du(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
+{
+ unsigned int flags = 0;
+ int printlimit = INT_MAX;
+ bool summary = false;
+ bool badarg = false;
+ int option;
+ int i;
+ int ret = OK;
+
+ /* Get the du options */
+
+ while ((option = getopt(argc, argv, "hsad:")) != ERROR)
+ {
+ switch (option)
+ {
+ case 'h':
+ flags |= DU_FLAG_HUMANREADABLE;
+ break;
+
+ case 's':
+ summary = true;
+ break;
+
+ case 'a':
+ flags |= DU_FLAG_ALL;
+ break;
+
+ case 'd':
+ printlimit = atoi(optarg);
+ break;
+
+ case '?':
+ default:
+ nsh_error(vtbl, g_fmtarginvalid, argv[0]);
+ badarg = true;
+ break;
+ }
+ }
+
+ /* If a bad argument was encountered,
+ * then return without processing the command
+ */
+
+ if (badarg)
+ {
+ return ERROR;
+ }
+
+ /* -s reports only each argument's own total (depth 0); -d N overrides -s
+ * when both are given. -s also suppresses the -a file listing.
+ */
+
+ if (summary)
+ {
+ if (printlimit == INT_MAX)
+ {
+ printlimit = 0;
+ }
+
+ flags &= ~DU_FLAG_ALL;
+ }
+
+ /* Walk each path argument (default: current directory). */
+
+ if (optind >= argc)
+ {
+#ifndef CONFIG_DISABLE_ENVIRON
+ FAR char *fullpath = nsh_getfullpath(vtbl, nsh_getcwd(vtbl));
+
+ if (fullpath == NULL)
+ {
+ nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
+ return ERROR;
+ }
+
+ du_recursive(vtbl, fullpath, flags, printlimit, 0);
+ nsh_freefullpath(fullpath);
+#else
+ nsh_error(vtbl, g_fmtargrequired, argv[0]);
+ return ERROR;
+#endif
+ }
+ else
+ {
+ for (i = optind; i < argc; i++)
+ {
+ FAR char *fullpath = nsh_getfullpath(vtbl, argv[i]);
+
+ if (fullpath == NULL)
+ {
+ nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
+ ret = ERROR;
+ continue;
+ }
+
+ du_recursive(vtbl, fullpath, flags, printlimit, 0);
+ nsh_freefullpath(fullpath);
+ }
+ }
+
+ return ret;
+}
+#endif
+
/****************************************************************************
* Name: cmd_mkdir
****************************************************************************/