Skip to content

Commit 908af6e

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 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>
1 parent 865393d commit 908af6e

4 files changed

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

0 commit comments

Comments
 (0)