diff --git a/configure.ac b/configure.ac index fcc7cdd095f183ed8be21e2af66e58693f5671a0..f23813766336c3b8c0740f4331abfc7afb02b9ff 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ AC_CHECK_HEADERS( [limits.h sys/time.h sys/types.h sys/stat.h dirent.h unistd.h fnmatch.h ncurses.h],[], AC_MSG_ERROR([required header file not found])) -AC_CHECK_HEADERS(locale.h) +AC_CHECK_HEADERS([locale.h sys/statfs.h linux/magic.h]) # Check for typedefs, structures, and compiler characteristics. AC_TYPE_INT64_T @@ -28,6 +28,7 @@ AC_CHECK_FUNCS( [getcwd gettimeofday fnmatch chdir rmdir unlink lstat system getenv],[], AC_MSG_ERROR([required function missing])) +AC_CHECK_FUNCS(statfs) # Look for ncurses library to link to diff --git a/doc/ncdu.pod b/doc/ncdu.pod index 784500f3a20d5dd39a950e96ce3e76b537b1ace4..ad6783b1e4e3ed7bd1bc8f259721b811a31df0d0 100644 --- a/doc/ncdu.pod +++ b/doc/ncdu.pod @@ -179,6 +179,15 @@ this option will not follow symlinks to directories and will count each symlinked file as a unique file (i.e. unlike how hard links are handled). This is subject to change in later versions. +=item --exclude-kernfs + +Exclude Linux pseudo filesystems, e.g. /proc (procfs), /sys (sysfs). +This option is only available on Linux, but exported statistics can be loaded on +all platforms. + +The complete list of currently known pseudo filesystems is: binfmt, bpf, cgroup, +cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace. + =back @@ -307,6 +316,10 @@ File or directory is excluded from the statistics by using exlude patterns. Directory is on another filesystem. +=item ^ + +Directory is excluded from the statistics due to being a Linux pseudo filesystem. + =item @ This is neither a file nor a folder (symlink, socket, ...). diff --git a/src/browser.c b/src/browser.c index 61c38a454071a6dfe578660d69fd17b0c3403251..3a9971f1b1ac71098a7820862c733636decb941a 100644 --- a/src/browser.c +++ b/src/browser.c @@ -118,6 +118,7 @@ static void browse_draw_flag(struct dir *n, int *x) { n->flags & FF_ERR ? '!' : n->flags & FF_SERR ? '.' : n->flags & FF_OTHFS ? '>' : + n->flags & FF_KERNFS ? '^' : n->flags & FF_HLNKC ? 'H' : !(n->flags & FF_FILE || n->flags & FF_DIR) ? '@' : diff --git a/src/dir.h b/src/dir.h index 8c145f1265654e4de00ebcc1c9feb66d3e5063f6..ec927337c8c8bf38e5b277ca948e00e7434c1f3a 100644 --- a/src/dir.h +++ b/src/dir.h @@ -113,6 +113,10 @@ void dir_scan_init(const char *path); extern int dir_import_active; int dir_import_init(const char *fn); +#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS +extern int exclude_kernfs; +#endif + /* The currently configured output functions. */ extern struct dir_output dir_output; diff --git a/src/dir_export.c b/src/dir_export.c index 6a7fe8dde8a4d531b9624dd0c59a7d043db0415d..f60242121a30c7ff9be98ef321a55f695e114928 100644 --- a/src/dir_export.c +++ b/src/dir_export.c @@ -116,12 +116,14 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) { if(d->flags & FF_ERR) fputs(",\"read_error\":true", stream); /* excluded/error'd files are "unknown" with respect to the "notreg" field. */ - if(!(d->flags & (FF_DIR|FF_FILE|FF_ERR|FF_EXL|FF_OTHFS))) + if(!(d->flags & (FF_DIR|FF_FILE|FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS))) fputs(",\"notreg\":true", stream); if(d->flags & FF_EXL) fputs(",\"excluded\":\"pattern\"", stream); else if(d->flags & FF_OTHFS) fputs(",\"excluded\":\"othfs\"", stream); + else if(d->flags & FF_KERNFS) + fputs(",\"excluded\":\"kernfs\"", stream); fputc('}', stream); } diff --git a/src/dir_import.c b/src/dir_import.c index 3a5c2a35bcb1dbdbb2975692f3ef6652edee6457..b3aeb7bcf1d08606bfe9ed3ee00382f1b639555e 100644 --- a/src/dir_import.c +++ b/src/dir_import.c @@ -480,6 +480,8 @@ static int iteminfo(void) { C(rstring(ctx->val, 8)); if(strcmp(ctx->val, "otherfs") == 0) ctx->buf_dir->flags |= FF_OTHFS; + else if(strcmp(ctx->val, "kernfs") == 0) + ctx->buf_dir->flags |= FF_KERNFS; else ctx->buf_dir->flags |= FF_EXL; } else if(strcmp(ctx->val, "notreg") == 0) { /* notreg */ diff --git a/src/dir_scan.c b/src/dir_scan.c index 8706e9c1aab394ac981d3ec8d6f5641172741aa1..879e13de2833769db9a6777ddb05a0e1ff24abb3 100644 --- a/src/dir_scan.c +++ b/src/dir_scan.c @@ -34,6 +34,11 @@ #include <sys/stat.h> #include <dirent.h> +#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS +#include <sys/statfs.h> +#include <linux/magic.h> +#endif + /* set S_BLKSIZE if not defined already in sys/stat.h */ #ifndef S_BLKSIZE @@ -50,6 +55,27 @@ static struct dir *buf_dir; static struct dir_ext buf_ext[1]; +#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS +int exclude_kernfs; /* Exlude Linux pseudo filesystems */ + +static int is_kernfs(unsigned long type) { + if(type == BINFMTFS_MAGIC || + type == BPF_FS_MAGIC || + type == CGROUP_SUPER_MAGIC || + type == CGROUP2_SUPER_MAGIC|| + type == DEBUGFS_MAGIC || + type == DEVPTS_SUPER_MAGIC || + type == PROC_SUPER_MAGIC || + type == PSTOREFS_MAGIC || + type == SECURITYFS_MAGIC || + type == SELINUX_MAGIC || + type == SYSFS_MAGIC || + type == TRACEFS_MAGIC) + return 1; + + return 0; +} +#endif /* Populates the buf_dir and buf_ext with information from the stat struct. * Sets everything necessary for output_dir.item() except FF_ERR and FF_EXL. */ @@ -69,7 +95,7 @@ static void stat_to_dir(struct stat *fs) { if(dir_scan_smfs && curdev != buf_dir->dev) buf_dir->flags |= FF_OTHFS; - if(!(buf_dir->flags & (FF_OTHFS|FF_EXL))) { + if(!(buf_dir->flags & (FF_OTHFS|FF_EXL|FF_KERNFS))) { buf_dir->size = fs->st_blocks * S_BLKSIZE; buf_dir->asize = fs->st_size; } @@ -204,6 +230,17 @@ static int dir_scan_item(const char *name) { dir_setlasterr(dir_curpath); } +#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS + if(exclude_kernfs && !(buf_dir->flags & (FF_ERR|FF_EXL)) && S_ISDIR(st.st_mode)) { + struct statfs fst; + if(statfs(dir_curpath, &fst)) { + buf_dir->flags |= FF_ERR; + dir_setlasterr(dir_curpath); + } else if(is_kernfs(fst.f_type)) + buf_dir->flags |= FF_KERNFS; + } +#endif + if(!(buf_dir->flags & (FF_ERR|FF_EXL))) { if(follow_symlinks && S_ISLNK(st.st_mode) && !stat(name, &stl) && !S_ISDIR(stl.st_mode)) stat_to_dir(&stl); @@ -211,14 +248,14 @@ static int dir_scan_item(const char *name) { stat_to_dir(&st); } - if(cachedir_tags && (buf_dir->flags & FF_DIR) && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS))) + if(cachedir_tags && (buf_dir->flags & FF_DIR) && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS))) if(has_cachedir_tag(name)) { buf_dir->flags |= FF_EXL; buf_dir->size = buf_dir->asize = 0; } /* Recurse into the dir or output the item */ - if(buf_dir->flags & FF_DIR && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS))) + if(buf_dir->flags & FF_DIR && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS))) fail = dir_scan_recurse(name); else if(buf_dir->flags & FF_DIR) { if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) { diff --git a/src/global.h b/src/global.h index f9b59cb716b63da58f60db666359646f25ae60d6..fb0405a6d44ff62bc835fc9a3ca8bcb5ddbb9fd6 100644 --- a/src/global.h +++ b/src/global.h @@ -42,15 +42,16 @@ #endif /* File Flags (struct dir -> flags) */ -#define FF_DIR 0x01 -#define FF_FILE 0x02 -#define FF_ERR 0x04 /* error while reading this item */ -#define FF_OTHFS 0x08 /* excluded because it was another filesystem */ -#define FF_EXL 0x10 /* excluded using exlude patterns */ -#define FF_SERR 0x20 /* error in subdirectory */ -#define FF_HLNKC 0x40 /* hard link candidate (file with st_nlink > 1) */ -#define FF_BSEL 0x80 /* selected */ -#define FF_EXT 0x100 /* extended struct available */ +#define FF_DIR 0x01 +#define FF_FILE 0x02 +#define FF_ERR 0x04 /* error while reading this item */ +#define FF_OTHFS 0x08 /* excluded because it was another filesystem */ +#define FF_EXL 0x10 /* excluded using exlude patterns */ +#define FF_SERR 0x20 /* error in subdirectory */ +#define FF_HLNKC 0x40 /* hard link candidate (file with st_nlink > 1) */ +#define FF_BSEL 0x80 /* selected */ +#define FF_EXT 0x100 /* extended struct available */ +#define FF_KERNFS 0x200 /* excluded because it was a Linux pseudo filesystem */ /* Program states */ #define ST_CALC 0 diff --git a/src/main.c b/src/main.c index 0651a6ec08fb6d3e13142bc81b5bc534c63a328b..cc7d43b46e935170f964a37e012dd04e94f3fda0 100644 --- a/src/main.c +++ b/src/main.c @@ -137,6 +137,7 @@ static void argv_parse(int argc, char **argv) { { 'X', 1, "-X,--exclude-from" }, { 'L', 0, "-L,--follow-symlinks" }, { 'C', 0, "--exclude-caches" }, + { 2, 0, "--exclude-kernfs" }, { 's', 0, "--si" }, { 'Q', 0, "--confirm-quit" }, { 'c', 1, "--color" }, @@ -166,6 +167,9 @@ static void argv_parse(int argc, char **argv) { printf(" -X, --exclude-from FILE Exclude files that match any pattern in FILE\n"); printf(" -L, --follow-symlinks Follow symbolic links (excluding directories)\n"); printf(" --exclude-caches Exclude directories containing CACHEDIR.TAG\n"); +#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS + printf(" --exclude-kernfs Exclude Linux pseudo filesystems (procfs,sysfs,cgroup,...)\n"); +#endif printf(" --confirm-quit Confirm quitting ncdu\n"); printf(" --color SCHEME Set color scheme (off/dark)\n"); exit(0); @@ -194,6 +198,14 @@ static void argv_parse(int argc, char **argv) { case 'C': cachedir_tags = 1; break; + + case 2 : +#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS + exclude_kernfs = 1; break; +#else + fprintf(stderr, "This feature is not supported on your platform\n"); + exit(1); +#endif case 'c': if(strcmp(val, "off") == 0) { uic_theme = 0; } else if(strcmp(val, "dark") == 0) { uic_theme = 1; }