Skip to content

Commit 0661bc3

Browse files
committed
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 ``` CONFIG_LIBC_FLOATINGPOINT off (sim default) -- -h uses integer K/M/G: ```bash nsh> du 397449 /data/test/elf 71993 /data/test/coredump 5 /data/test/log2 3251 /data/test/log1 472700 /data/test nsh> du -h 388M /data/test/elf 70M /data/test/coredump 4K /data/test/log2 3M /data/test/log1 461M /data/test ``` CONFIG_LIBC_FLOATINGPOINT=y in sim:nsh defconfig -- -h prints one decimal: ```bash nsh> du -h 388.1M /data/test/elf 70.3M /data/test/coredump 4.2K /data/test/log2 3.2M /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>
1 parent 865393d commit 0661bc3

4 files changed

Lines changed: 287 additions & 0 deletions

File tree

nshlib/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,10 @@ config NSH_DISABLE_DMESG
413413
bool "Disable dmesg"
414414
default DEFAULT_SMALL
415415

416+
config NSH_DISABLE_DU
417+
bool "Disable du"
418+
default DEFAULT_SMALL
419+
416420
config NSH_DISABLE_ECHO
417421
bool "Disable echo"
418422
default DEFAULT_SMALL

nshlib/nsh.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,9 @@ int cmd_irqinfo(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
10011001
#ifndef CONFIG_NSH_DISABLE_LS
10021002
int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
10031003
#endif
1004+
#ifndef CONFIG_NSH_DISABLE_DU
1005+
int cmd_du(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
1006+
#endif
10041007
#if defined(CONFIG_SYSLOG_DEVPATH) && !defined(CONFIG_NSH_DISABLE_DMESG)
10051008
int cmd_dmesg(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
10061009
#endif

nshlib/nsh_command.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,11 @@ static const struct cmdmap_s g_cmdmap[] =
354354
CMD_MAP("ls", cmd_ls, 1, 5, "[-lRsh] <dir-path>"),
355355
#endif
356356

357+
#ifndef CONFIG_NSH_DISABLE_DU
358+
CMD_MAP("du", cmd_du, 1, 7,
359+
"[-h] [-s] [-a] [-d N] <path>..."),
360+
#endif
361+
357362
#if defined(CONFIG_MODULE) && !defined(CONFIG_NSH_DISABLE_MODCMDS)
358363
# if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
359364
CMD_MAP("lsmod", cmd_lsmod, 1, 1, NULL),

nshlib/nsh_fscmds.c

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,281 @@ int cmd_ls(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
18551855
}
18561856
#endif
18571857

1858+
/****************************************************************************
1859+
* Name: du_print
1860+
****************************************************************************/
1861+
1862+
#ifndef CONFIG_NSH_DISABLE_DU
1863+
#define DU_FLAG_HUMANREADABLE (1 << 0) /* -h: human readable sizes */
1864+
#define DU_FLAG_ALL (1 << 1) /* -a: list all files, not only dirs */
1865+
1866+
static void du_print(FAR struct nsh_vtbl_s *vtbl, FAR const char *path,
1867+
off_t bytes, unsigned int duflags)
1868+
{
1869+
off_t kblocks = (bytes + 1023) / 1024;
1870+
1871+
if ((duflags & DU_FLAG_HUMANREADABLE) != 0)
1872+
{
1873+
off_t divisor;
1874+
const char *unit;
1875+
1876+
if (bytes >= GB)
1877+
{
1878+
divisor = GB;
1879+
unit = "G";
1880+
}
1881+
else if (bytes >= MB)
1882+
{
1883+
divisor = MB;
1884+
unit = "M";
1885+
}
1886+
else if (bytes >= KB)
1887+
{
1888+
divisor = KB;
1889+
unit = "K";
1890+
}
1891+
else
1892+
{
1893+
divisor = 1;
1894+
unit = "B";
1895+
}
1896+
1897+
#if defined(CONFIG_HAVE_FLOAT) && defined(CONFIG_LIBC_FLOATINGPOINT)
1898+
nsh_output(vtbl, "%.1f%s\t%s\n", (float)bytes / divisor, unit, path);
1899+
#else
1900+
nsh_output(vtbl, "%" PRIdOFF "%s\t%s\n", bytes / divisor, unit, path);
1901+
#endif
1902+
}
1903+
else
1904+
{
1905+
nsh_output(vtbl, "%" PRIdOFF "\t%s\n", kblocks, path);
1906+
}
1907+
}
1908+
1909+
static off_t du_recursive(FAR struct nsh_vtbl_s *vtbl, FAR const char *path,
1910+
FAR const struct stat *pst, unsigned int duflags,
1911+
int printlimit, int depth)
1912+
{
1913+
FAR struct dirent *entry;
1914+
FAR char *child;
1915+
struct stat st;
1916+
off_t total;
1917+
DIR *dp;
1918+
1919+
if (pst != NULL)
1920+
{
1921+
st = *pst;
1922+
}
1923+
else if (lstat(path, &st) < 0)
1924+
{
1925+
nsh_error(vtbl, g_fmtcmdfailed, "du", "stat", NSH_ERRNO);
1926+
return 0;
1927+
}
1928+
1929+
/* st_size not st_blocks: units differ (NuttX FS=st_blksize, hostfs=512) */
1930+
1931+
total = st.st_size;
1932+
1933+
/* A file argument (depth 0) is always shown; nested files need -a. */
1934+
1935+
if (!S_ISDIR(st.st_mode))
1936+
{
1937+
if (depth == 0 ||
1938+
((duflags & DU_FLAG_ALL) != 0 && depth <= printlimit))
1939+
{
1940+
du_print(vtbl, path, total, duflags);
1941+
}
1942+
1943+
return total;
1944+
}
1945+
1946+
dp = opendir(path);
1947+
if (dp == NULL)
1948+
{
1949+
nsh_error(vtbl, g_fmtcmdfailed, "du", "opendir", NSH_ERRNO);
1950+
}
1951+
else
1952+
{
1953+
while ((entry = readdir(dp)) != NULL)
1954+
{
1955+
if (strcmp(entry->d_name, ".") == 0 ||
1956+
strcmp(entry->d_name, "..") == 0)
1957+
{
1958+
continue;
1959+
}
1960+
1961+
child = nsh_getdirpath(vtbl, path, entry->d_name);
1962+
if (child == NULL)
1963+
{
1964+
nsh_error(vtbl, g_fmtcmdfailed, "du", "nsh_getdirpath",
1965+
NSH_ERRNO);
1966+
continue;
1967+
}
1968+
1969+
total += du_recursive(vtbl, child, NULL, duflags, printlimit,
1970+
depth + 1);
1971+
free(child);
1972+
}
1973+
1974+
closedir(dp);
1975+
}
1976+
1977+
/* Print this directory's cumulative total unless suppressed by -s/-d. */
1978+
1979+
if (depth <= printlimit)
1980+
{
1981+
du_print(vtbl, path, total, duflags);
1982+
}
1983+
1984+
return total;
1985+
}
1986+
#endif
1987+
1988+
/****************************************************************************
1989+
* Name: cmd_du
1990+
****************************************************************************/
1991+
1992+
#ifndef CONFIG_NSH_DISABLE_DU
1993+
int cmd_du(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
1994+
{
1995+
unsigned int duflags = 0;
1996+
int printlimit = INT_MAX;
1997+
bool summary = false;
1998+
bool d_given = false;
1999+
bool badarg = false;
2000+
int option;
2001+
int i;
2002+
int ret = OK;
2003+
2004+
/* Get the du options */
2005+
2006+
while ((option = getopt(argc, argv, "hsad:")) != ERROR)
2007+
{
2008+
switch (option)
2009+
{
2010+
case 'h':
2011+
duflags |= DU_FLAG_HUMANREADABLE;
2012+
break;
2013+
2014+
case 's':
2015+
summary = true;
2016+
break;
2017+
2018+
case 'a':
2019+
duflags |= DU_FLAG_ALL;
2020+
break;
2021+
2022+
case 'd':
2023+
{
2024+
FAR char *endp;
2025+
long d = strtol(optarg, &endp, 10);
2026+
2027+
if (endp == optarg || *endp != '\0' || d < 0)
2028+
{
2029+
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
2030+
badarg = true;
2031+
}
2032+
else
2033+
{
2034+
printlimit = (int)d;
2035+
d_given = true;
2036+
}
2037+
}
2038+
break;
2039+
2040+
case '?':
2041+
default:
2042+
nsh_error(vtbl, g_fmtarginvalid, argv[0]);
2043+
badarg = true;
2044+
break;
2045+
}
2046+
}
2047+
2048+
/* If a bad argument was encountered,
2049+
* then return without processing the command
2050+
*/
2051+
2052+
if (badarg)
2053+
{
2054+
return ERROR;
2055+
}
2056+
2057+
/* -s reports only each argument's own total (depth 0); -d N overrides -s
2058+
* when both are given. -s also suppresses the -a file listing.
2059+
*/
2060+
2061+
if (summary)
2062+
{
2063+
if (!d_given)
2064+
{
2065+
printlimit = 0;
2066+
}
2067+
2068+
duflags &= ~DU_FLAG_ALL;
2069+
}
2070+
2071+
/* Walk each path argument (default: current directory). */
2072+
2073+
if (optind >= argc)
2074+
{
2075+
#ifndef CONFIG_DISABLE_ENVIRON
2076+
FAR char *fullpath = nsh_getfullpath(vtbl, nsh_getcwd(vtbl));
2077+
struct stat st;
2078+
2079+
if (fullpath == NULL)
2080+
{
2081+
nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
2082+
return ERROR;
2083+
}
2084+
2085+
if (lstat(fullpath, &st) < 0)
2086+
{
2087+
nsh_error(vtbl, g_fmtcmdfailed, "du", "stat", NSH_ERRNO);
2088+
ret = ERROR;
2089+
}
2090+
else
2091+
{
2092+
du_recursive(vtbl, fullpath, &st, duflags, printlimit, 0);
2093+
}
2094+
2095+
nsh_freefullpath(fullpath);
2096+
#else
2097+
nsh_error(vtbl, g_fmtargrequired, argv[0]);
2098+
return ERROR;
2099+
#endif
2100+
}
2101+
else
2102+
{
2103+
for (i = optind; i < argc; i++)
2104+
{
2105+
FAR char *fullpath = nsh_getfullpath(vtbl, argv[i]);
2106+
struct stat st;
2107+
2108+
if (fullpath == NULL)
2109+
{
2110+
nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
2111+
ret = ERROR;
2112+
continue;
2113+
}
2114+
2115+
if (lstat(fullpath, &st) < 0)
2116+
{
2117+
nsh_error(vtbl, g_fmtcmdfailed, "du", "stat", NSH_ERRNO);
2118+
ret = ERROR;
2119+
}
2120+
else
2121+
{
2122+
du_recursive(vtbl, fullpath, &st, duflags, printlimit, 0);
2123+
}
2124+
2125+
nsh_freefullpath(fullpath);
2126+
}
2127+
}
2128+
2129+
return ret;
2130+
}
2131+
#endif
2132+
18582133
/****************************************************************************
18592134
* Name: cmd_mkdir
18602135
****************************************************************************/

0 commit comments

Comments
 (0)