mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-01 20:29:00 +00:00
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 <zhengjunbo1@xiaomi.com>
This commit is contained in:
parent
6ca1272b99
commit
101b713be6
4 changed files with 249 additions and 3 deletions
|
|
@ -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
|
||||
|
|
|
|||
10
nshlib/nsh.h
10
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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue