Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions nshlib/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions nshlib/nsh.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,12 +416,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
Expand Down Expand Up @@ -1001,6 +1002,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
Expand Down
5 changes: 5 additions & 0 deletions nshlib/nsh_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
233 changes: 233 additions & 0 deletions nshlib/nsh_fscmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
****************************************************************************/
Expand Down
Loading