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
  ****************************************************************************/

Reply via email to