mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-13 01:08:41 -09:00
Compare commits
48 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a14373896 | ||
|
|
61fda79ddf | ||
|
|
ff830ac2bf | ||
|
|
d6a129ff5a | ||
|
|
b853185413 | ||
|
|
61feee5657 | ||
|
|
b4b82d96a3 | ||
|
|
93edebc81c | ||
|
|
73ef3294e8 | ||
|
|
bc8129cad1 | ||
|
|
88c9b8718e | ||
|
|
ed7c5b2b93 | ||
|
|
a9d608fab1 | ||
|
|
97cf0fc234 | ||
|
|
7af05149d6 | ||
|
|
cded7d376a | ||
|
|
1ca0c5769b | ||
|
|
6143a03a77 | ||
|
|
b93acabd59 | ||
|
|
960661e93a | ||
|
|
c08340ee08 | ||
|
|
daaca0a903 | ||
|
|
6993941646 | ||
|
|
3ef0ac93c7 | ||
|
|
6dd159d489 | ||
|
|
49e4b061a5 | ||
|
|
b45f8e4c06 | ||
|
|
9670ca66ed | ||
|
|
dc78e8db19 | ||
|
|
a5e8a43943 | ||
|
|
683eb26ad1 | ||
|
|
23e3eba5d2 | ||
|
|
e29a42a02a | ||
|
|
15ebd21195 | ||
|
|
b340c04450 | ||
|
|
8137444062 | ||
|
|
e1a9b30803 | ||
|
|
abab9d360d | ||
|
|
96a9231927 | ||
|
|
376aad0d35 | ||
|
|
f982af81b0 | ||
|
|
52daeafcd8 | ||
|
|
bd01f5773d | ||
|
|
67a1d84216 | ||
|
|
ebeee7be01 | ||
|
|
a6b4aead43 | ||
|
|
e278660464 | ||
|
|
ca51d4ed1a |
38 changed files with 1502 additions and 1119 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -16,7 +16,6 @@ missing
|
||||||
*.o
|
*.o
|
||||||
stamp-h1
|
stamp-h1
|
||||||
ncdu
|
ncdu
|
||||||
ncdu.1
|
|
||||||
*~
|
*~
|
||||||
*.swp
|
*.swp
|
||||||
static/*
|
static/*
|
||||||
|
|
|
||||||
2
COPYING
2
COPYING
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
57
ChangeLog
57
ChangeLog
|
|
@ -1,3 +1,60 @@
|
||||||
|
1.22 - 2025-03-05
|
||||||
|
- Add support for @-prefixed lines to ignore errors in config file (from 2.8)
|
||||||
|
- List all supported options in `--help` (from 2.8)
|
||||||
|
- Use `kB` instead of `KB` in `--si` mode (from 2.8)
|
||||||
|
- Add `--graph-style` option (from 2.1)
|
||||||
|
- Fix supported range of uid/gid numbers
|
||||||
|
|
||||||
|
1.21 - 2024-11-19
|
||||||
|
- Perform tilde expansion on paths in the config file (from 2.7)
|
||||||
|
- Fix JSON import of escaped UTF-16 surrogate pairs (from 2.7)
|
||||||
|
- Fix displaying and exporting zero values when extended info is not
|
||||||
|
available (from 2.6)
|
||||||
|
- Fix JSON export and import of the “other filesystem” flag (from 2.5)
|
||||||
|
|
||||||
|
1.20 - 2024-04-21
|
||||||
|
- Revert default color scheme back to 'off'
|
||||||
|
- Rewrite man page in mdoc, drop pod2man dependency
|
||||||
|
|
||||||
|
1.19 - 2023-09-11
|
||||||
|
- Fix typo in --exclude-from argument
|
||||||
|
- Add --(enable|disable)-natsort options
|
||||||
|
- Add indicator to apparent size/disk usage selection in the footer
|
||||||
|
|
||||||
|
1.18.1 - 2023-02-12
|
||||||
|
- Fix build on non-Linux platforms
|
||||||
|
|
||||||
|
1.18 - 2022-12-06
|
||||||
|
- Fix 'dark-bg' color scheme to actually have a dark background
|
||||||
|
- Backport configuration file support from 2.x
|
||||||
|
- Backport many new CLI options from 2.x
|
||||||
|
- Negation of existing flags: --no-si, --no-confirm-quit, --no-follow-symlinks, --include-caches, --include-kernfs
|
||||||
|
- --[no-]extended in addition to -e
|
||||||
|
- --one-file-system and --cross-file-system in addition to -x
|
||||||
|
- --slow-ui-updates, --fast-ui-updates in addition to -q
|
||||||
|
- Column visibility options: --(show|hide)-(hidden|itemcount|mtime|graph|percent)
|
||||||
|
- Sorting: --sort, --[no-]group-directories-first
|
||||||
|
- Feature selection: --(enable|disable)-(shell|delete|refresh)
|
||||||
|
- Deletion confirmation: --[no-]confirm-delete
|
||||||
|
- Hidden file visibility: --show-hidden, --hide-hidden
|
||||||
|
- Size display: --apparent-size, --disk-usage
|
||||||
|
|
||||||
|
1.17 - 2022-04-28
|
||||||
|
- Add 'dark-bg' color scheme and use that by default
|
||||||
|
- Use natural sort order when sorting by file name
|
||||||
|
- Improve compatibility with C89 environments
|
||||||
|
- Fix wrong assumption about errno not being set by realloc()
|
||||||
|
|
||||||
|
1.16 - 2021-07-02
|
||||||
|
- Increase width of size bar depending on terminal size (Christian Göttsche)
|
||||||
|
- Set/increment $NCDU_LEVEL variable when spawning a shell
|
||||||
|
- Indicate whether apparent size or disk usage is being displayed
|
||||||
|
- Display setuid, setgid and sticky bits in file flags in extended mode
|
||||||
|
- Fix error handling while reading --exclude-from file
|
||||||
|
- Improve JSON import to allow for several future extensions to the format
|
||||||
|
- Export link count in JSON dumps
|
||||||
|
- Don't export inode in JSON dumps for non-hardlinks
|
||||||
|
|
||||||
1.15.1 - 2020-06-10
|
1.15.1 - 2020-06-10
|
||||||
- (Linux) Fix build on older Linux systems (Christian Göttsche)
|
- (Linux) Fix build on older Linux systems (Christian Göttsche)
|
||||||
- (MacOS) Revert "Exclude firmlinks by default" behavior (until we have a better solution)
|
- (MacOS) Revert "Exclude firmlinks by default" behavior (until we have a better solution)
|
||||||
|
|
|
||||||
18
Makefile.am
18
Makefile.am
|
|
@ -16,11 +16,13 @@ ncdu_SOURCES=\
|
||||||
src/quit.c\
|
src/quit.c\
|
||||||
src/main.c\
|
src/main.c\
|
||||||
src/path.c\
|
src/path.c\
|
||||||
src/util.c
|
src/util.c\
|
||||||
|
deps/strnatcmp.c
|
||||||
|
|
||||||
|
|
||||||
noinst_HEADERS=\
|
noinst_HEADERS=\
|
||||||
deps/yopt.h\
|
|
||||||
deps/khashl.h\
|
deps/khashl.h\
|
||||||
|
deps/strnatcmp.h\
|
||||||
src/browser.h\
|
src/browser.h\
|
||||||
src/delete.h\
|
src/delete.h\
|
||||||
src/dir.h\
|
src/dir.h\
|
||||||
|
|
@ -35,13 +37,11 @@ noinst_HEADERS=\
|
||||||
|
|
||||||
|
|
||||||
man_MANS=ncdu.1
|
man_MANS=ncdu.1
|
||||||
EXTRA_DIST=ncdu.1 doc/ncdu.pod
|
EXTRA_DIST=ncdu.1
|
||||||
|
|
||||||
# Don't "clean" ncdu.1, it should be in the tarball so that pod2man isn't a
|
|
||||||
# build dependency for those who use the tarball.
|
|
||||||
ncdu.1: $(srcdir)/doc/ncdu.pod
|
|
||||||
pod2man --center "ncdu manual" --release "@PACKAGE@-@VERSION@" "$(srcdir)/doc/ncdu.pod" >ncdu.1
|
|
||||||
|
|
||||||
|
# This target exists more for documentation purposes than actual use; some
|
||||||
|
# dependencies have minor ncdu-specific changes.
|
||||||
update-deps:
|
update-deps:
|
||||||
wget -q https://raw.github.com/attractivechaos/klib/master/khashl.h -O "$(srcdir)/deps/khashl.h"
|
wget -q https://raw.github.com/attractivechaos/klib/master/khashl.h -O "$(srcdir)/deps/khashl.h"
|
||||||
wget -q http://g.blicky.net/ylib.git/plain/yopt.h -O "$(srcdir)/deps/yopt.h"
|
wget -q https://raw.githubusercontent.com/sourcefrog/natsort/master/strnatcmp.h -O "$(srcdir)/deps/strnatcmp.h"
|
||||||
|
wget -q https://raw.githubusercontent.com/sourcefrog/natsort/master/strnatcmp.c -O "$(srcdir)/deps/strnatcmp.c"
|
||||||
|
|
|
||||||
13
README
13
README
|
|
@ -1,5 +1,5 @@
|
||||||
ncdu 1.15.1
|
ncdu 1.22
|
||||||
===========
|
=========
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
|
|
||||||
|
|
@ -25,15 +25,14 @@ INSTALL
|
||||||
make
|
make
|
||||||
make install
|
make install
|
||||||
|
|
||||||
If you're building directly from the git repository, make sure you have perl
|
If you're building directly from the git repository, make sure you have
|
||||||
(or rather, pod2man), pkg-config and GNU autoconf/automake installed, then
|
pkg-config and GNU autoconf/automake installed, then run 'autoreconf -i',
|
||||||
run 'autoreconf -i', and you're ready to continue with the usual ./configure
|
and you're ready to continue with the usual ./configure and make route.
|
||||||
and make route.
|
|
||||||
|
|
||||||
|
|
||||||
COPYING
|
COPYING
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
AC_INIT([ncdu],[1.15.1],[projects@yorhel.nl])
|
AC_INIT([ncdu],[1.22],[projects@yorhel.nl])
|
||||||
AC_CONFIG_SRCDIR([src/global.h])
|
AC_CONFIG_SRCDIR([src/global.h])
|
||||||
AC_CONFIG_HEADER([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AM_INIT_AUTOMAKE([foreign std-options subdir-objects])
|
AM_INIT_AUTOMAKE([foreign std-options subdir-objects])
|
||||||
|
|
||||||
# Check for programs.
|
# Check for programs.
|
||||||
|
AC_USE_SYSTEM_EXTENSIONS
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
AC_PROG_RANLIB
|
AC_PROG_RANLIB
|
||||||
|
|
@ -22,6 +23,8 @@ AC_TYPE_INT64_T
|
||||||
AC_TYPE_UINT64_T
|
AC_TYPE_UINT64_T
|
||||||
AC_SYS_LARGEFILE
|
AC_SYS_LARGEFILE
|
||||||
AC_STRUCT_ST_BLOCKS
|
AC_STRUCT_ST_BLOCKS
|
||||||
|
AC_C_INLINE
|
||||||
|
AC_C_FLEXIBLE_ARRAY_MEMBER
|
||||||
|
|
||||||
# Check for library functions.
|
# Check for library functions.
|
||||||
AC_CHECK_FUNCS(
|
AC_CHECK_FUNCS(
|
||||||
|
|
|
||||||
164
deps/strnatcmp.c
vendored
Normal file
164
deps/strnatcmp.c
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* partial change history:
|
||||||
|
*
|
||||||
|
* 2004-10-10 mbp: Lift out character type dependencies into macros.
|
||||||
|
*
|
||||||
|
* Eric Sosman pointed out that ctype functions take a parameter whose
|
||||||
|
* value must be that of an unsigned int, even on platforms that have
|
||||||
|
* negative chars in their default char type.
|
||||||
|
*
|
||||||
|
* ncdu edits:
|
||||||
|
* - static inline -> #define for better compatibility
|
||||||
|
* - don't use ctype.h, for more predictable results
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h> /* size_t */
|
||||||
|
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* These are defined as macros to make it easier to adapt this code to
|
||||||
|
* different characters types or comparison functions. */
|
||||||
|
#define nat_isdigit(a) ((a) >= '0' && (a) <= '9')
|
||||||
|
#define nat_isspace(a) ((a) == ' ' || (a) == '\t' || (a) == '\r' || (a) == '\n')
|
||||||
|
#define nat_toupper(a) (a)
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_right(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
int bias = 0;
|
||||||
|
|
||||||
|
/* The longest run of digits wins. That aside, the greatest
|
||||||
|
value wins, but we can't know that it will until we've scanned
|
||||||
|
both numbers to know that they have the same magnitude, so we
|
||||||
|
remember it in BIAS. */
|
||||||
|
for (;; a++, b++) {
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return bias;
|
||||||
|
if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
if (*a < *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = -1;
|
||||||
|
} else if (*a > *b) {
|
||||||
|
if (!bias)
|
||||||
|
bias = +1;
|
||||||
|
} else if (!*a && !*b)
|
||||||
|
return bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_left(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
/* Compare two left-aligned numbers: the first to have a
|
||||||
|
different value wins. */
|
||||||
|
for (;; a++, b++) {
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return 0;
|
||||||
|
if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
if (*a < *b)
|
||||||
|
return -1;
|
||||||
|
if (*a > *b)
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
strnatcmp0(nat_char const *a, nat_char const *b, int fold_case)
|
||||||
|
{
|
||||||
|
int ai, bi;
|
||||||
|
nat_char ca, cb;
|
||||||
|
int fractional, result;
|
||||||
|
|
||||||
|
ai = bi = 0;
|
||||||
|
while (1) {
|
||||||
|
ca = a[ai]; cb = b[bi];
|
||||||
|
|
||||||
|
/* skip over leading spaces or zeros */
|
||||||
|
while (nat_isspace(ca))
|
||||||
|
ca = a[++ai];
|
||||||
|
|
||||||
|
while (nat_isspace(cb))
|
||||||
|
cb = b[++bi];
|
||||||
|
|
||||||
|
/* process run of digits */
|
||||||
|
if (nat_isdigit(ca) && nat_isdigit(cb)) {
|
||||||
|
fractional = (ca == '0' || cb == '0');
|
||||||
|
|
||||||
|
if (fractional) {
|
||||||
|
if ((result = compare_left(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
if ((result = compare_right(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ca && !cb) {
|
||||||
|
/* The strings compare the same. Perhaps the caller
|
||||||
|
will want to call strcmp to break the tie. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fold_case) {
|
||||||
|
ca = nat_toupper(ca);
|
||||||
|
cb = nat_toupper(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ca < cb)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (ca > cb)
|
||||||
|
return +1;
|
||||||
|
|
||||||
|
++ai; ++bi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
strnatcmp(nat_char const *a, nat_char const *b) {
|
||||||
|
return strnatcmp0(a, b, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compare, recognizing numeric string and ignoring case. */
|
||||||
|
int
|
||||||
|
strnatcasecmp(nat_char const *a, nat_char const *b) {
|
||||||
|
return strnatcmp0(a, b, 1);
|
||||||
|
}
|
||||||
31
deps/strnatcmp.h
vendored
Normal file
31
deps/strnatcmp.h
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* CUSTOMIZATION SECTION
|
||||||
|
*
|
||||||
|
* You can change this typedef, but must then also change the inline
|
||||||
|
* functions in strnatcmp.c */
|
||||||
|
typedef char nat_char;
|
||||||
|
|
||||||
|
int strnatcmp(nat_char const *a, nat_char const *b);
|
||||||
|
int strnatcasecmp(nat_char const *a, nat_char const *b);
|
||||||
198
deps/yopt.h
vendored
198
deps/yopt.h
vendored
|
|
@ -1,198 +0,0 @@
|
||||||
/* Copyright (c) 2012-2013 Yoran Heling
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
|
||||||
in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
||||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* This is a simple command-line option parser. Operation is similar to
|
|
||||||
* getopt_long(), except with a cleaner API.
|
|
||||||
*
|
|
||||||
* This is implemented in a single header file, as it's pretty small and you
|
|
||||||
* generally only use an option parser in a single .c file in your program.
|
|
||||||
*
|
|
||||||
* Supports (examples from GNU tar(1)):
|
|
||||||
* "--gzip"
|
|
||||||
* "--file <arg>"
|
|
||||||
* "--file=<arg>"
|
|
||||||
* "-z"
|
|
||||||
* "-f <arg>"
|
|
||||||
* "-f<arg>"
|
|
||||||
* "-zf <arg>"
|
|
||||||
* "-zf<arg>"
|
|
||||||
* "--" (To stop looking for further options)
|
|
||||||
* "<arg>" (Non-option arguments)
|
|
||||||
*
|
|
||||||
* Issues/non-features:
|
|
||||||
* - An option either requires an argument or it doesn't.
|
|
||||||
* - No way to specify how often an option can/should be used.
|
|
||||||
* - No way to specify the type of an argument (filename/integer/enum/whatever)
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef YOPT_H
|
|
||||||
#define YOPT_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* Value yopt_next() will return for this option */
|
|
||||||
int val;
|
|
||||||
/* Whether this option needs an argument */
|
|
||||||
int needarg;
|
|
||||||
/* Name(s) of this option, prefixed with '-' or '--' and separated by a
|
|
||||||
* comma. E.g. "-z", "--gzip", "-z,--gzip".
|
|
||||||
* An option can have any number of aliases.
|
|
||||||
*/
|
|
||||||
const char *name;
|
|
||||||
} yopt_opt_t;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int argc;
|
|
||||||
int cur;
|
|
||||||
int argsep; /* '--' found */
|
|
||||||
char **argv;
|
|
||||||
char *sh;
|
|
||||||
const yopt_opt_t *opts;
|
|
||||||
char errbuf[128];
|
|
||||||
} yopt_t;
|
|
||||||
|
|
||||||
|
|
||||||
/* opts must be an array of options, terminated with an option with val=0 */
|
|
||||||
static inline void yopt_init(yopt_t *o, int argc, char **argv, const yopt_opt_t *opts) {
|
|
||||||
o->argc = argc;
|
|
||||||
o->argv = argv;
|
|
||||||
o->opts = opts;
|
|
||||||
o->cur = 0;
|
|
||||||
o->argsep = 0;
|
|
||||||
o->sh = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline const yopt_opt_t *_yopt_find(const yopt_opt_t *o, const char *v) {
|
|
||||||
const char *tn, *tv;
|
|
||||||
|
|
||||||
for(; o->val; o++) {
|
|
||||||
tn = o->name;
|
|
||||||
while(*tn) {
|
|
||||||
tv = v;
|
|
||||||
while(*tn && *tn != ',' && *tv && *tv != '=' && *tn == *tv) {
|
|
||||||
tn++;
|
|
||||||
tv++;
|
|
||||||
}
|
|
||||||
if(!(*tn && *tn != ',') && !(*tv && *tv != '='))
|
|
||||||
return o;
|
|
||||||
while(*tn && *tn != ',')
|
|
||||||
tn++;
|
|
||||||
while(*tn == ',')
|
|
||||||
tn++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int _yopt_err(yopt_t *o, char **val, const char *fmt, ...) {
|
|
||||||
va_list va;
|
|
||||||
va_start(va, fmt);
|
|
||||||
vsnprintf(o->errbuf, sizeof(o->errbuf), fmt, va);
|
|
||||||
va_end(va);
|
|
||||||
*val = o->errbuf;
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return values:
|
|
||||||
* 0 -> Non-option argument, val is its value
|
|
||||||
* -1 -> Last argument has been processed
|
|
||||||
* -2 -> Error, val will contain the error message.
|
|
||||||
* x -> Option with val = x found. If the option requires an argument, its
|
|
||||||
* value will be in val.
|
|
||||||
*/
|
|
||||||
static inline int yopt_next(yopt_t *o, char **val) {
|
|
||||||
const yopt_opt_t *opt;
|
|
||||||
char sh[3];
|
|
||||||
|
|
||||||
*val = NULL;
|
|
||||||
if(o->sh)
|
|
||||||
goto inshort;
|
|
||||||
|
|
||||||
if(++o->cur >= o->argc)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if(!o->argsep && o->argv[o->cur][0] == '-' && o->argv[o->cur][1] == '-' && o->argv[o->cur][2] == 0) {
|
|
||||||
o->argsep = 1;
|
|
||||||
if(++o->cur >= o->argc)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(o->argsep || *o->argv[o->cur] != '-') {
|
|
||||||
*val = o->argv[o->cur];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(o->argv[o->cur][1] != '-') {
|
|
||||||
o->sh = o->argv[o->cur]+1;
|
|
||||||
goto inshort;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now we're supposed to have a long option */
|
|
||||||
if(!(opt = _yopt_find(o->opts, o->argv[o->cur])))
|
|
||||||
return _yopt_err(o, val, "Unknown option '%s'", o->argv[o->cur]);
|
|
||||||
if((*val = strchr(o->argv[o->cur], '=')) != NULL)
|
|
||||||
(*val)++;
|
|
||||||
if(!opt->needarg && *val)
|
|
||||||
return _yopt_err(o, val, "Option '%s' does not accept an argument", o->argv[o->cur]);
|
|
||||||
if(opt->needarg && !*val) {
|
|
||||||
if(o->cur+1 >= o->argc)
|
|
||||||
return _yopt_err(o, val, "Option '%s' requires an argument", o->argv[o->cur]);
|
|
||||||
*val = o->argv[++o->cur];
|
|
||||||
}
|
|
||||||
return opt->val;
|
|
||||||
|
|
||||||
/* And here we're supposed to have a short option */
|
|
||||||
inshort:
|
|
||||||
sh[0] = '-';
|
|
||||||
sh[1] = *o->sh;
|
|
||||||
sh[2] = 0;
|
|
||||||
if(!(opt = _yopt_find(o->opts, sh)))
|
|
||||||
return _yopt_err(o, val, "Unknown option '%s'", sh);
|
|
||||||
o->sh++;
|
|
||||||
if(opt->needarg && *o->sh)
|
|
||||||
*val = o->sh;
|
|
||||||
else if(opt->needarg) {
|
|
||||||
if(++o->cur >= o->argc)
|
|
||||||
return _yopt_err(o, val, "Option '%s' requires an argument", sh);
|
|
||||||
*val = o->argv[o->cur];
|
|
||||||
}
|
|
||||||
if(!*o->sh || opt->needarg)
|
|
||||||
o->sh = NULL;
|
|
||||||
return opt->val;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* vim: set noet sw=4 ts=4: */
|
|
||||||
445
doc/ncdu.pod
445
doc/ncdu.pod
|
|
@ -1,445 +0,0 @@
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
B<ncdu> - NCurses Disk Usage
|
|
||||||
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
B<ncdu> [I<options>] I<dir>
|
|
||||||
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
ncdu (NCurses Disk Usage) is a curses-based version of the well-known 'du', and
|
|
||||||
provides a fast way to see what directories are using your disk space.
|
|
||||||
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
|
||||||
|
|
||||||
=head2 Mode Selection
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item -h, --help
|
|
||||||
|
|
||||||
Print a short help message and quit.
|
|
||||||
|
|
||||||
=item -v, -V, --version
|
|
||||||
|
|
||||||
Print ncdu version and quit.
|
|
||||||
|
|
||||||
=item -f I<FILE>
|
|
||||||
|
|
||||||
Load the given file, which has earlier been created with the C<-o> option. If
|
|
||||||
I<FILE> is equivalent to C<->, the file is read from standard input.
|
|
||||||
|
|
||||||
For the sake of preventing a screw-up, the current version of ncdu will assume
|
|
||||||
that the directory information in the imported file does not represent the
|
|
||||||
filesystem on which the file is being imported. That is, the refresh, file
|
|
||||||
deletion and shell spawning options in the browser will be disabled.
|
|
||||||
|
|
||||||
=item I<dir>
|
|
||||||
|
|
||||||
Scan the given directory.
|
|
||||||
|
|
||||||
=item -o I<FILE>
|
|
||||||
|
|
||||||
Export all necessary information to I<FILE> instead of opening the browser
|
|
||||||
interface. If I<FILE> is C<->, the data is written to standard output. See the
|
|
||||||
examples section below for some handy use cases.
|
|
||||||
|
|
||||||
Be warned that the exported data may grow quite large when exporting a
|
|
||||||
directory with many files. 10.000 files will get you an export in the order of
|
|
||||||
600 to 700 KiB uncompressed, or a little over 100 KiB when compressed with
|
|
||||||
gzip. This scales linearly, so be prepared to handle a few tens of megabytes
|
|
||||||
when dealing with millions of files.
|
|
||||||
|
|
||||||
=item -e
|
|
||||||
|
|
||||||
Enable extended information mode. This will, in addition to the usual file
|
|
||||||
information, also read the ownership, permissions and last modification time
|
|
||||||
for each file. This will result in higher memory usage (by roughly ~30%) and in
|
|
||||||
a larger output file when exporting.
|
|
||||||
|
|
||||||
When using the file export/import function, this flag will need to be added
|
|
||||||
both when exporting (to make sure the information is added to the export), and
|
|
||||||
when importing (to read this extra information in memory). This flag has no
|
|
||||||
effect when importing a file that has been exported without the extended
|
|
||||||
information.
|
|
||||||
|
|
||||||
This enables viewing and sorting by the latest child mtime, or modified time,
|
|
||||||
using 'm' and 'M', respectively.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 Interface options
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item -0
|
|
||||||
|
|
||||||
Don't give any feedback while scanning a directory or importing a file, other
|
|
||||||
than when a fatal error occurs. Ncurses will not be initialized until the scan
|
|
||||||
is complete. When exporting the data with C<-o>, ncurses will not be
|
|
||||||
initialized at all. This option is the default when exporting to standard
|
|
||||||
output.
|
|
||||||
|
|
||||||
=item -1
|
|
||||||
|
|
||||||
Similar to C<-0>, but does give feedback on the scanning progress with a single
|
|
||||||
line of output. This option is the default when exporting to a file.
|
|
||||||
|
|
||||||
In some cases, the ncurses browser interface which you'll see after the
|
|
||||||
scan/import is complete may look garbled when using this option. If you're not
|
|
||||||
exporting to a file, C<-2> is probably a better choice.
|
|
||||||
|
|
||||||
=item -2
|
|
||||||
|
|
||||||
Provide a full-screen ncurses interface while scanning a directory or importing
|
|
||||||
a file. This is the only interface that provides feedback on any non-fatal
|
|
||||||
errors while scanning.
|
|
||||||
|
|
||||||
=item -q
|
|
||||||
|
|
||||||
Quiet mode. While scanning or importing the directory, ncdu will update the
|
|
||||||
screen 10 times a second by default, this will be decreased to once every 2
|
|
||||||
seconds in quiet mode. Use this feature to save bandwidth over remote
|
|
||||||
connections. This option has no effect when C<-0> is used.
|
|
||||||
|
|
||||||
=item -r
|
|
||||||
|
|
||||||
Read-only mode. This will disable the built-in file deletion feature. This
|
|
||||||
option has no effect when C<-o> is used, because there will not be a browser
|
|
||||||
interface in that case. It has no effect when C<-f> is used, either, because
|
|
||||||
the deletion feature is disabled in that case anyway.
|
|
||||||
|
|
||||||
WARNING: This option will only prevent deletion through the file browser. It is
|
|
||||||
still possible to spawn a shell from ncdu and delete or modify files from
|
|
||||||
there. To disable that feature as well, pass the C<-r> option twice (see
|
|
||||||
C<-rr>).
|
|
||||||
|
|
||||||
=item -rr
|
|
||||||
|
|
||||||
In addition to C<-r>, this will also disable the shell spawning feature of the
|
|
||||||
file browser.
|
|
||||||
|
|
||||||
=item --si
|
|
||||||
|
|
||||||
List sizes using base 10 prefixes, that is, powers of 1000 (KB, MB, etc), as
|
|
||||||
defined in the International System of Units (SI), instead of the usual base 2
|
|
||||||
prefixes, that is, powers of 1024 (KiB, MiB, etc).
|
|
||||||
|
|
||||||
=item --confirm-quit
|
|
||||||
|
|
||||||
Requires a confirmation before quitting ncdu. Very helpful when you
|
|
||||||
accidentally press 'q' during or after a very long scan.
|
|
||||||
|
|
||||||
=item --color I<SCHEME>
|
|
||||||
|
|
||||||
Select a color scheme. Currently only two schemes are recognized: I<off> to
|
|
||||||
disable colors (the default) and I<dark> for a color scheme intended for dark
|
|
||||||
backgrounds.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 Scan Options
|
|
||||||
|
|
||||||
These options affect the scanning progress, and have no effect when importing
|
|
||||||
directory information from a file.
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item -x
|
|
||||||
|
|
||||||
Do not cross filesystem boundaries, i.e. only count files and directories on
|
|
||||||
the same filesystem as the directory being scanned.
|
|
||||||
|
|
||||||
=item --exclude I<PATTERN>
|
|
||||||
|
|
||||||
Exclude files that match I<PATTERN>. The files will still be displayed by
|
|
||||||
default, but are not counted towards the disk usage statistics. This argument
|
|
||||||
can be added multiple times to add more patterns.
|
|
||||||
|
|
||||||
=item -X I<FILE>, --exclude-from I<FILE>
|
|
||||||
|
|
||||||
Exclude files that match any pattern in I<FILE>. Patterns should be separated
|
|
||||||
by a newline.
|
|
||||||
|
|
||||||
=item --exclude-caches
|
|
||||||
|
|
||||||
Exclude directories containing CACHEDIR.TAG. The directories will still be
|
|
||||||
displayed, but not their content, and they are not counted towards the disk
|
|
||||||
usage statistics.
|
|
||||||
See http://www.brynosaurus.com/cachedir/
|
|
||||||
|
|
||||||
=item -L, --follow-symlinks
|
|
||||||
|
|
||||||
Follow symlinks and count the size of the file they point to. As of ncdu 1.14,
|
|
||||||
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-firmlinks
|
|
||||||
|
|
||||||
(MacOS only) Exclude firmlinks.
|
|
||||||
|
|
||||||
=item --exclude-kernfs
|
|
||||||
|
|
||||||
(Linux only) Exclude Linux pseudo filesystems, e.g. /proc (procfs), /sys (sysfs).
|
|
||||||
|
|
||||||
The complete list of currently known pseudo filesystems is: binfmt, bpf, cgroup,
|
|
||||||
cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
|
|
||||||
=head1 KEYS
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item ?
|
|
||||||
|
|
||||||
Show help + keys + about screen
|
|
||||||
|
|
||||||
=item up, down j, k
|
|
||||||
|
|
||||||
Cycle through the items
|
|
||||||
|
|
||||||
=item right, enter, l
|
|
||||||
|
|
||||||
Open selected directory
|
|
||||||
|
|
||||||
=item left, <, h
|
|
||||||
|
|
||||||
Go to parent directory
|
|
||||||
|
|
||||||
=item n
|
|
||||||
|
|
||||||
Order by filename (press again for descending order)
|
|
||||||
|
|
||||||
=item s
|
|
||||||
|
|
||||||
Order by filesize (press again for descending order)
|
|
||||||
|
|
||||||
=item C
|
|
||||||
|
|
||||||
Order by number of items (press again for descending order)
|
|
||||||
|
|
||||||
=item a
|
|
||||||
|
|
||||||
Toggle between showing disk usage and showing apparent size.
|
|
||||||
|
|
||||||
=item M
|
|
||||||
|
|
||||||
Order by latest child mtime, or modified time. (press again for descending order)
|
|
||||||
Requires the -e flag.
|
|
||||||
|
|
||||||
=item d
|
|
||||||
|
|
||||||
Delete the selected file or directory. An error message will be shown when the
|
|
||||||
contents of the directory do not match or do not exist anymore on the
|
|
||||||
filesystem.
|
|
||||||
|
|
||||||
=item t
|
|
||||||
|
|
||||||
Toggle dirs before files when sorting.
|
|
||||||
|
|
||||||
=item g
|
|
||||||
|
|
||||||
Toggle between showing percentage, graph, both, or none. Percentage is relative
|
|
||||||
to the size of the current directory, graph is relative to the largest item in
|
|
||||||
the current directory.
|
|
||||||
|
|
||||||
=item c
|
|
||||||
|
|
||||||
Toggle display of child item counts.
|
|
||||||
|
|
||||||
=item m
|
|
||||||
|
|
||||||
Toggle display of latest child mtime, or modified time. Requires the -e flag.
|
|
||||||
|
|
||||||
=item e
|
|
||||||
|
|
||||||
Show/hide 'hidden' or 'excluded' files and directories. Please note that even
|
|
||||||
though you can't see the hidden files and directories, they are still there and
|
|
||||||
they are still included in the directory sizes. If you suspect that the totals
|
|
||||||
shown at the bottom of the screen are not correct, make sure you haven't
|
|
||||||
enabled this option.
|
|
||||||
|
|
||||||
=item i
|
|
||||||
|
|
||||||
Show information about the current selected item.
|
|
||||||
|
|
||||||
=item r
|
|
||||||
|
|
||||||
Refresh/recalculate the current directory.
|
|
||||||
|
|
||||||
=item b
|
|
||||||
|
|
||||||
Spawn shell in current directory.
|
|
||||||
|
|
||||||
Ncdu will determine your preferred shell from the C<NCDU_SHELL> or C<SHELL>
|
|
||||||
variable (in that order), or will call C</bin/sh> if neither are set. This
|
|
||||||
allows you to also configure another command to be run when he 'b' key is
|
|
||||||
pressed. For example, to spawn the L<vifm(1)> file manager instead of a shell,
|
|
||||||
run ncdu as follows:
|
|
||||||
|
|
||||||
export NCDU_SHELL=vifm
|
|
||||||
ncdu
|
|
||||||
|
|
||||||
=item q
|
|
||||||
|
|
||||||
Quit
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
|
|
||||||
=head1 FILE FLAGS
|
|
||||||
|
|
||||||
Entries in the browser interface may be prefixed by a one-character flag. These
|
|
||||||
flags have the following meaning:
|
|
||||||
|
|
||||||
=over
|
|
||||||
|
|
||||||
=item !
|
|
||||||
|
|
||||||
An error occurred while reading this directory.
|
|
||||||
|
|
||||||
=item .
|
|
||||||
|
|
||||||
An error occurred while reading a subdirectory, so the indicated size may not be
|
|
||||||
correct.
|
|
||||||
|
|
||||||
=item <
|
|
||||||
|
|
||||||
File or directory is excluded from the statistics by using exclude patterns.
|
|
||||||
|
|
||||||
=item >
|
|
||||||
|
|
||||||
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, ...).
|
|
||||||
|
|
||||||
=item H
|
|
||||||
|
|
||||||
Same file was already counted (hard link).
|
|
||||||
|
|
||||||
=item e
|
|
||||||
|
|
||||||
Empty directory.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
|
|
||||||
=head1 EXAMPLES
|
|
||||||
|
|
||||||
To scan and browse the directory you're currently in, all you need is a simple:
|
|
||||||
|
|
||||||
ncdu
|
|
||||||
|
|
||||||
If you want to scan a full filesystem, your root filesystem, for example, then
|
|
||||||
you'll want to use C<-x>:
|
|
||||||
|
|
||||||
ncdu -x /
|
|
||||||
|
|
||||||
Since scanning a large directory may take a while, you can scan a directory and
|
|
||||||
export the results for later viewing:
|
|
||||||
|
|
||||||
ncdu -1xo- / | gzip >export.gz
|
|
||||||
# ...some time later:
|
|
||||||
zcat export.gz | ncdu -f-
|
|
||||||
|
|
||||||
To export from a cron job, make sure to replace C<-1> with C<-0> to suppress
|
|
||||||
any unnecessary output.
|
|
||||||
|
|
||||||
You can also export a directory and browse it once scanning is done:
|
|
||||||
|
|
||||||
ncdu -o- | tee export.file | ./ncdu -f-
|
|
||||||
|
|
||||||
The same is possible with gzip compression, but is a bit kludgey:
|
|
||||||
|
|
||||||
ncdu -o- | gzip | tee export.gz | gunzip | ./ncdu -f-
|
|
||||||
|
|
||||||
To scan a system remotely, but browse through the files locally:
|
|
||||||
|
|
||||||
ssh -C user@system ncdu -o- / | ./ncdu -f-
|
|
||||||
|
|
||||||
The C<-C> option to ssh enables compression, which will be very useful over
|
|
||||||
slow links. Remote scanning and local viewing has two major advantages when
|
|
||||||
compared to running ncdu directly on the remote system: You can browse through
|
|
||||||
the scanned directory on the local system without any network latency, and ncdu
|
|
||||||
does not keep the entire directory structure in memory when exporting, so you
|
|
||||||
won't consume much memory on the remote system.
|
|
||||||
|
|
||||||
|
|
||||||
=head1 HARD LINKS
|
|
||||||
|
|
||||||
Every disk usage analysis utility has its own way of (not) counting hard links.
|
|
||||||
There does not seem to be any universally agreed method of handling hard links,
|
|
||||||
and it is even inconsistent among different versions of ncdu. This section
|
|
||||||
explains what each version of ncdu does.
|
|
||||||
|
|
||||||
ncdu 1.5 and below does not support any hard link detection at all: each link
|
|
||||||
is considered a separate inode and its size is counted for every link. This
|
|
||||||
means that the displayed directory sizes are incorrect when analyzing
|
|
||||||
directories which contain hard links.
|
|
||||||
|
|
||||||
ncdu 1.6 has basic hard link detection: When a link to a previously encountered
|
|
||||||
inode is detected, the link is considered to have a file size of zero bytes.
|
|
||||||
Its size is not counted again, and the link is indicated in the browser
|
|
||||||
interface with a 'H' mark. The displayed directory sizes are only correct when
|
|
||||||
all links to an inode reside within that directory. When this is not the case,
|
|
||||||
the sizes may or may not be correct, depending on which links were considered
|
|
||||||
as "duplicate" and which as "original". The indicated size of the topmost
|
|
||||||
directory (that is, the one specified on the command line upon starting ncdu)
|
|
||||||
is always correct.
|
|
||||||
|
|
||||||
ncdu 1.7 and later has improved hard link detection. Each file that has more
|
|
||||||
than two links has the "H" mark visible in the browser interface. Each hard
|
|
||||||
link is counted exactly once for every directory it appears in. The indicated
|
|
||||||
size of each directory is therefore, correctly, the sum of the sizes of all
|
|
||||||
unique inodes that can be found in that directory. Note, however, that this may
|
|
||||||
not always be same as the space that will be reclaimed after deleting the
|
|
||||||
directory, as some inodes may still be accessible from hard links outside it.
|
|
||||||
|
|
||||||
|
|
||||||
=head1 BUGS
|
|
||||||
|
|
||||||
Directory hard links are not supported. They will not be detected as being hard
|
|
||||||
links, and will thus be scanned and counted multiple times.
|
|
||||||
|
|
||||||
Some minor glitches may appear when displaying filenames that contain multibyte
|
|
||||||
or multicolumn characters.
|
|
||||||
|
|
||||||
All sizes are internally represented as a signed 64bit integer. If you have a
|
|
||||||
directory larger than 8 EiB minus one byte, ncdu will clip its size to 8 EiB
|
|
||||||
minus one byte. When deleting items in a directory with a clipped size, the
|
|
||||||
resulting sizes will be incorrect.
|
|
||||||
|
|
||||||
Item counts are stored in a signed 32-bit integer without overflow detection.
|
|
||||||
If you have a directory with more than 2 billion files, quite literally
|
|
||||||
anything can happen.
|
|
||||||
|
|
||||||
On macOS 10.15 and later, running ncdu on the root directory without
|
|
||||||
`--exclude-firmlinks` may cause directories to be scanned and counted multiple
|
|
||||||
times. Firmlink cycles are currently (1.15.1) not detected, so it may also
|
|
||||||
cause ncdu to get stuck in an infinite loop and eventually run out of memory.
|
|
||||||
|
|
||||||
Please report any other bugs you may find at the bug tracker, which can be
|
|
||||||
found on the web site at https://dev.yorhel.nl/ncdu
|
|
||||||
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
Written by Yoran Heling <projects@yorhel.nl>.
|
|
||||||
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<du(1)>
|
|
||||||
513
ncdu.1
Normal file
513
ncdu.1
Normal file
|
|
@ -0,0 +1,513 @@
|
||||||
|
.\" SPDX-FileCopyrightText: Yorhel <projects@yorhel.nl>
|
||||||
|
.\" SPDX-License-Identifier: MIT
|
||||||
|
.Dd March 5, 2025
|
||||||
|
.Dt NCDU 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm ncdu
|
||||||
|
.Nd NCurses Disk Usage
|
||||||
|
.
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl f Ar file
|
||||||
|
.Op Fl o Ar file
|
||||||
|
.Op Fl e , \-extended , \-no\-extended
|
||||||
|
.Op Fl \-ignore\-config
|
||||||
|
.Op Fl x , \-one\-file\-system , \-cross\-file\-system
|
||||||
|
.Op Fl \-exclude Ar pattern
|
||||||
|
.Op Fl X , \-exclude\-from Ar file
|
||||||
|
.Op Fl \-include\-caches , \-exclude\-caches
|
||||||
|
.Op Fl L , \-follow\-symlinks , \-no\-follow\-symlinks
|
||||||
|
.Op Fl \-include\-kernfs , \-exclude\-kernfs
|
||||||
|
.Op Fl \-exclude\-firmlinks , \-follow\-firmlinks
|
||||||
|
.Op Fl 0 , 1 , 2
|
||||||
|
.Op Fl q , \-slow\-ui\-updates , \-fast\-ui\-updates
|
||||||
|
.Op Fl \-enable\-shell , \-disable\-shell
|
||||||
|
.Op Fl \-enable\-delete , \-disable\-delete
|
||||||
|
.Op Fl \-enable\-refresh , \-disable\-refresh
|
||||||
|
.Op Fl r
|
||||||
|
.Op Fl \-si , \-no\-si
|
||||||
|
.Op Fl \-disk\-usage , \-apparent\-size
|
||||||
|
.Op Fl \-show\-hidden , \-hide\-hidden
|
||||||
|
.Op Fl \-show\-itemcount , \-hide\-itemcount
|
||||||
|
.Op Fl \-show\-mtime , \-hide\-mtime
|
||||||
|
.Op Fl \-show\-graph , \-hide\-graph
|
||||||
|
.Op Fl \-show\-percent , \-hide\-percent
|
||||||
|
.Op Fl \-graph\-style Ar hash | half\-block | eighth\-block
|
||||||
|
.Op Fl \-sort Ar column
|
||||||
|
.Op Fl \-enable\-natsort , \-disable\-natsort
|
||||||
|
.Op Fl \-group\-directories\-first , \-no\-group\-directories\-first
|
||||||
|
.Op Fl \-confirm\-quit , \-no\-confirm\-quit
|
||||||
|
.Op Fl \-confirm\-delete , \-no\-confirm\-delete
|
||||||
|
.Op Fl \-color Ar off | dark | dark-bg
|
||||||
|
.Op Ar path
|
||||||
|
.Nm
|
||||||
|
.Op Fl h , \-help
|
||||||
|
.Nm
|
||||||
|
.Op Fl v , V , \-version
|
||||||
|
.
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
(NCurses Disk Usage) is an interactive curses-based version of the well-known
|
||||||
|
.Xr du 1 ,
|
||||||
|
and provides a fast way to see what directories are using your disk space.
|
||||||
|
.
|
||||||
|
.Sh OPTIONS
|
||||||
|
.Ss Mode Selection
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl h , \-help
|
||||||
|
Print a short help message and quit.
|
||||||
|
.It Fl v , V , \-version
|
||||||
|
Print version and quit.
|
||||||
|
.It Fl f Ar file
|
||||||
|
Load the given file, which has earlier been created with the
|
||||||
|
.Fl o
|
||||||
|
flag.
|
||||||
|
If
|
||||||
|
.Ar file
|
||||||
|
is equivalent to '\-', the file is read from standard input.
|
||||||
|
.Pp
|
||||||
|
For the sake of preventing a screw-up, the current version of
|
||||||
|
.Nm
|
||||||
|
will assume that the directory information in the imported file does not
|
||||||
|
represent the filesystem on which the file is being imported.
|
||||||
|
That is, the refresh, file deletion and shell spawning options in the browser
|
||||||
|
will be disabled.
|
||||||
|
.It Ar dir
|
||||||
|
Scan the given directory.
|
||||||
|
.It Fl o Ar file
|
||||||
|
Export all necessary information to
|
||||||
|
.Ar file
|
||||||
|
instead of opening the browser interface.
|
||||||
|
If
|
||||||
|
.Ar file
|
||||||
|
is '\-', the data is written to standard output.
|
||||||
|
See the examples section below for some handy use cases.
|
||||||
|
.Pp
|
||||||
|
Be warned that the exported data may grow quite large when exporting a
|
||||||
|
directory with many files.
|
||||||
|
10.000 files will get you an export in the order of 600 to 700 KiB
|
||||||
|
uncompressed, or a little over 100 KiB when compressed with gzip.
|
||||||
|
This scales linearly, so be prepared to handle a few tens of megabytes when
|
||||||
|
dealing with millions of files.
|
||||||
|
.It Fl e , \-extended , \-no\-extended
|
||||||
|
Enable/disable extended information mode.
|
||||||
|
This will, in addition to the usual file information, also read the ownership,
|
||||||
|
permissions and last modification time for each file.
|
||||||
|
This will result in higher memory usage (by roughly ~30%) and in a larger
|
||||||
|
output file when exporting.
|
||||||
|
.Pp
|
||||||
|
When using the file export/import function, this flag should be added both when
|
||||||
|
exporting (to make sure the information is added to the export) and when
|
||||||
|
importing (to read this extra information in memory).
|
||||||
|
This flag has no effect when importing a file that has been exported without
|
||||||
|
the extended information.
|
||||||
|
.Pp
|
||||||
|
This enables viewing and sorting by the latest child mtime, or modified time,
|
||||||
|
using 'm' and 'M', respectively.
|
||||||
|
.It Fl \-ignore\-config
|
||||||
|
Do not attempt to load any configuration files.
|
||||||
|
.El
|
||||||
|
.
|
||||||
|
.Ss Scan Options
|
||||||
|
These options affect the scanning progress, they have no effect when importing
|
||||||
|
directory information from a file.
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl x , \-one\-file\-system
|
||||||
|
Do not cross filesystem boundaries, i.e. only count files and directories on
|
||||||
|
the same filesystem as the directory being scanned.
|
||||||
|
.It Fl \-cross\-file\-system
|
||||||
|
Do cross filesystem boundaries.
|
||||||
|
This is the default, but can be specified to overrule a previously configured
|
||||||
|
.Fl x .
|
||||||
|
.It Fl \-exclude Ar pattern
|
||||||
|
Exclude files that match
|
||||||
|
.Ar pattern .
|
||||||
|
The files are still displayed by default, but are not counted towards the disk
|
||||||
|
usage statistics.
|
||||||
|
This argument can be added multiple times to add more patterns.
|
||||||
|
.It Fl X , \-exclude\-from Ar file
|
||||||
|
Exclude files that match any pattern in
|
||||||
|
.Ar file .
|
||||||
|
Patterns should be separated by a newline.
|
||||||
|
.It Fl \-include\-caches , \-exclude\-caches
|
||||||
|
Include (default) or exclude directories containing
|
||||||
|
.Pa CACHEDIR.TAG .
|
||||||
|
Excluded cache directories are still displayed, but their contents will not be
|
||||||
|
scanned or counted towards the disk usage statistics.
|
||||||
|
.Lk https://bford.info/cachedir/
|
||||||
|
.It Fl L , \-follow\-symlinks , \-no\-follow\-symlinks
|
||||||
|
Follow (or not) symlinks and count the size of the file they point to.
|
||||||
|
This option does not follow symlinks to directories and will cause each
|
||||||
|
symlinked file to count as a unique file.
|
||||||
|
This is different from how hard links are handled.
|
||||||
|
The exact counting behavior of this flag is subject to change in the future.
|
||||||
|
.It Fl \-include\-kernfs , \-exclude\-kernfs
|
||||||
|
(Linux only) Include (default) or exclude Linux pseudo filesystems such as
|
||||||
|
.Pa /proc
|
||||||
|
(procfs) and
|
||||||
|
.Pa /sys
|
||||||
|
(sysfs).
|
||||||
|
.Pp
|
||||||
|
The complete list of currently known pseudo filesystems is: binfmt, bpf, cgroup,
|
||||||
|
cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace.
|
||||||
|
.It Fl \-exclude\-firmlinks , \-follow\-firmlinks
|
||||||
|
(MacOS only) Exclude or follow firmlinks.
|
||||||
|
.El
|
||||||
|
.Ss Interface Options
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl 0
|
||||||
|
Don't give any feedback while scanning a directory or importing a file, except
|
||||||
|
when a fatal error occurs.
|
||||||
|
Ncurses will not be initialized until the scan is complete.
|
||||||
|
When exporting the data with
|
||||||
|
.Fl o ,
|
||||||
|
ncurses will not be initialized at all.
|
||||||
|
This option is the default when exporting to standard output.
|
||||||
|
.It Fl 1
|
||||||
|
Write progress information to the terminal, but don't open a full-screen
|
||||||
|
ncurses interface.
|
||||||
|
This option is the default when exporting to a file.
|
||||||
|
.Pp
|
||||||
|
In some cases, the ncurses browser interface which you'll see after the
|
||||||
|
scan/import is complete may look garbled when using this option.
|
||||||
|
If you're not exporting to a file,
|
||||||
|
.Fl 2
|
||||||
|
is usually a better choice.
|
||||||
|
.It Fl 2
|
||||||
|
Show a full-screen ncurses interface while scanning a directory or importing
|
||||||
|
a file.
|
||||||
|
This is the only interface that provides feedback on any non-fatal errors while
|
||||||
|
scanning.
|
||||||
|
.It Fl q , \-slow\-ui\-updates , \-fast\-ui\-updates
|
||||||
|
Change the UI update interval while scanning or importing.
|
||||||
|
.Nm
|
||||||
|
updates the screen 10 times a second by default (with
|
||||||
|
.Fl \-fast\-ui\-updates
|
||||||
|
), this can be decreased to once every 2 seconds with
|
||||||
|
.Fl q
|
||||||
|
or
|
||||||
|
.Fl \-slow\-ui\-updates .
|
||||||
|
This option can be used to save bandwidth over remote connections.
|
||||||
|
This option has no effect in combination with
|
||||||
|
.Fl 0 .
|
||||||
|
.It Fl \-enable\-shell , \-disable\-shell
|
||||||
|
Enable or disable shell spawning from the file browser.
|
||||||
|
This feature is enabled by default when scanning a live directory and disabled
|
||||||
|
when importing from file.
|
||||||
|
.It Fl \-enable\-delete , \-disable\-delete
|
||||||
|
Enable or disable the built-in file deletion feature.
|
||||||
|
This feature is enabled by default when scanning a live directory and disabled
|
||||||
|
when importing from file.
|
||||||
|
Explicitly disabling the deletion feature can work as a safeguard to prevent
|
||||||
|
accidental data loss.
|
||||||
|
.It Fl \-enable\-refresh , \-disable\-refresh
|
||||||
|
Enable or disable directory refreshing from the file browser.
|
||||||
|
This feature is enabled by default when scanning a live directory and disabled
|
||||||
|
when importing from file.
|
||||||
|
.It Fl r
|
||||||
|
Read-only mode.
|
||||||
|
When given once, this is an alias for
|
||||||
|
.Fl \-disable\-delete ,
|
||||||
|
when given twice it will also add
|
||||||
|
.Fl \-disable\-shell ,
|
||||||
|
thus ensuring that there is no way to modify the file system from within
|
||||||
|
.Nm .
|
||||||
|
.It Fl \-si , \-no\-si
|
||||||
|
List sizes using base 10 prefixes, that is, powers of 1000 (kB, MB, etc), as
|
||||||
|
defined in the International System of Units (SI), instead of the usual base 2
|
||||||
|
prefixes (KiB, MiB, etc).
|
||||||
|
.It Fl \-disk\-usage , \-apparent\-size
|
||||||
|
Select whether to display disk usage (default) or apparent sizes.
|
||||||
|
Can also be toggled in the file browser with the 'a' key.
|
||||||
|
.It Fl \-show\-hidden , \-hide\-hidden
|
||||||
|
Show (default) or hide "hidden" and excluded files.
|
||||||
|
Can also be toggled in the file browser with the 'e' key.
|
||||||
|
.It Fl \-show\-itemcount , \-hide\-itemcount
|
||||||
|
Show or hide (default) the item counts column.
|
||||||
|
Can also be toggled in the file browser with the 'c' key.
|
||||||
|
.It Fl \-show\-mtime , \-hide\-mtime
|
||||||
|
Show or hide (default) the last modification time column.
|
||||||
|
Can also be toggled in the file browser with the 'm' key.
|
||||||
|
This option is ignored when not in extended mode, see
|
||||||
|
.Fl e .
|
||||||
|
.It Fl \-show\-graph , \-hide\-graph
|
||||||
|
Show (default) or hide the relative size bar column.
|
||||||
|
Can also be toggled in the file browser with the 'g' key.
|
||||||
|
.It Fl \-show\-percent , \-hide\-percent
|
||||||
|
Show (default) or hide the relative size percent column.
|
||||||
|
Can also be toggled in the file browser with the 'g' key.
|
||||||
|
.It Fl \-graph\-style Ar hash | half\-block | eighth\-block
|
||||||
|
Change the way that the relative size bar column is drawn.
|
||||||
|
Recognized values are
|
||||||
|
.Ar hash
|
||||||
|
to draw ASCII '#' characters (default and most portable),
|
||||||
|
.Ar half\-block
|
||||||
|
to use half-block drawing characters or
|
||||||
|
.Ar eighth\-block
|
||||||
|
to use eighth-block drawing characters.
|
||||||
|
Eighth-block characters are the most precise but may not render correctly in
|
||||||
|
all terminals.
|
||||||
|
.It Fl \-sort Ar column
|
||||||
|
Change the default column to sort on.
|
||||||
|
Accepted values are
|
||||||
|
.Ar disk\-usage
|
||||||
|
(the default),
|
||||||
|
.Ar name , apparent\-size , itemcount
|
||||||
|
or
|
||||||
|
.Ar mtime .
|
||||||
|
The latter only makes sense in extended mode, see
|
||||||
|
.Fl e .
|
||||||
|
.Pp
|
||||||
|
The column name can be suffixed with
|
||||||
|
.Li \-asc
|
||||||
|
or
|
||||||
|
.Li \-desc
|
||||||
|
to change the order to ascending or descending, respectively.
|
||||||
|
For example,
|
||||||
|
.Li \-\-sort=name\-desc
|
||||||
|
to sort by name in descending order.
|
||||||
|
.It Fl \-enable\-natsort , \-disable\-natsort
|
||||||
|
Enable (default) or disable natural sort when sorting by file name.
|
||||||
|
.It Fl \-group\-directories\-first , \-no\-group\-directories\-first
|
||||||
|
Sort (or not) directories before files.
|
||||||
|
.It Fl \-confirm\-quit , \-no\-confirm\-quit
|
||||||
|
Require a confirmation before quitting ncdu.
|
||||||
|
Can be helpful when you accidentally press 'q' during or after a very long scan.
|
||||||
|
.It Fl \-confirm\-delete , \-no\-confirm\-delete
|
||||||
|
Require a confirmation before deleting a file or directory.
|
||||||
|
Enabled by default, but can be disabled if you're absolutely sure you won't
|
||||||
|
accidentally press 'd'.
|
||||||
|
.It Fl \-color Ar off | dark | dark-bg
|
||||||
|
Set the color scheme.
|
||||||
|
The following schemes are recognized:
|
||||||
|
.Ar off
|
||||||
|
to disable colors,
|
||||||
|
.Ar dark
|
||||||
|
for a color scheme intended for dark backgrounds and
|
||||||
|
.Ar dark\-bg
|
||||||
|
for a variation of the
|
||||||
|
.Ar dark
|
||||||
|
color scheme that also works in terminals with a light background.
|
||||||
|
.Pp
|
||||||
|
The default is
|
||||||
|
.Ar off .
|
||||||
|
.El
|
||||||
|
.
|
||||||
|
.Sh CONFIGURATION
|
||||||
|
.Nm
|
||||||
|
can be configured by placing command-line options in
|
||||||
|
.Pa /etc/ncdu.conf
|
||||||
|
or
|
||||||
|
.Pa $HOME/.config/ncdu/config .
|
||||||
|
If both files exist, the system configuration will be loaded before the user
|
||||||
|
configuration, allowing users to override options set in the system
|
||||||
|
configuration.
|
||||||
|
Options given on the command line will override options set in the
|
||||||
|
configuration files.
|
||||||
|
The files will not be read at all when
|
||||||
|
.Fl \-ignore\-config
|
||||||
|
is given on the command line.
|
||||||
|
.Pp
|
||||||
|
The configuration file format is simply one command line option per line.
|
||||||
|
Lines starting with '#' are ignored.
|
||||||
|
A line can be prefixed with '@' to suppress errors while parsing the option.
|
||||||
|
Example configuration file:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
# Always enable extended mode
|
||||||
|
\-e
|
||||||
|
|
||||||
|
# Disable file deletion
|
||||||
|
\-\-disable\-delete
|
||||||
|
|
||||||
|
# Exclude .git directories
|
||||||
|
\-\-exclude .git
|
||||||
|
|
||||||
|
# Read excludes from ~/.ncduexcludes, ignore error if the file does not exist
|
||||||
|
@--exclude-from ~/.ncduexcludes
|
||||||
|
.Ed
|
||||||
|
.
|
||||||
|
.Sh KEYS
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It ?
|
||||||
|
Open help + keys + about screen
|
||||||
|
.It up , down , j , k
|
||||||
|
Cycle through the items
|
||||||
|
.It right, enter, l
|
||||||
|
Open selected directory
|
||||||
|
.It left, <, h
|
||||||
|
Go to parent directory
|
||||||
|
.It n
|
||||||
|
Order by filename (press again for descending order)
|
||||||
|
.It s
|
||||||
|
Order by filesize (press again for descending order)
|
||||||
|
.It C
|
||||||
|
Order by number of items (press again for descending order)
|
||||||
|
.It a
|
||||||
|
Toggle between showing disk usage and showing apparent size.
|
||||||
|
.It M
|
||||||
|
Order by latest child mtime, or modified time (press again for descending
|
||||||
|
order).
|
||||||
|
Requires the
|
||||||
|
.Fl e
|
||||||
|
flag.
|
||||||
|
.It d
|
||||||
|
Delete the selected file or directory.
|
||||||
|
An error message will be shown when the contents of the directory do not match
|
||||||
|
or do not exist anymore on the filesystem.
|
||||||
|
.It t
|
||||||
|
Toggle dirs before files when sorting.
|
||||||
|
.It g
|
||||||
|
Toggle between showing percentage, graph, both, or none.
|
||||||
|
Percentage is relative to the size of the current directory, graph is relative
|
||||||
|
to the largest item in the current directory.
|
||||||
|
.It c
|
||||||
|
Toggle display of child item counts.
|
||||||
|
.It m
|
||||||
|
Toggle display of latest child mtime, or modified time.
|
||||||
|
Requires the
|
||||||
|
.Fl e
|
||||||
|
flag.
|
||||||
|
.It e
|
||||||
|
Show/hide 'hidden' or 'excluded' files and directories.
|
||||||
|
Be aware that even if you can't see the hidden files and directories, they are
|
||||||
|
still there and they are still included in the directory sizes.
|
||||||
|
If you suspect that the totals shown at the bottom of the screen are not
|
||||||
|
correct, make sure you haven't enabled this option.
|
||||||
|
.It i
|
||||||
|
Show information about the current selected item.
|
||||||
|
.It r
|
||||||
|
Refresh/recalculate the current directory.
|
||||||
|
.It b
|
||||||
|
Spawn shell in current directory.
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
determines your preferred shell from the
|
||||||
|
.Ev NCDU_SHELL
|
||||||
|
or
|
||||||
|
.Ev SHELL
|
||||||
|
environment variable (in that order), or calls
|
||||||
|
.Pa /bin/sh
|
||||||
|
if neither are set.
|
||||||
|
This allows you to also configure another command to be run when he 'b' key is
|
||||||
|
pressed.
|
||||||
|
For example, to spawn the
|
||||||
|
.Xr vifm 1
|
||||||
|
file manager instead of a shell, run
|
||||||
|
.Nm
|
||||||
|
as follows:
|
||||||
|
.Dl NCDU_SHELL=vifm ncdu
|
||||||
|
The
|
||||||
|
.Ev NCDU_LEVEL
|
||||||
|
environment variable is set or incremented before spawning the shell, allowing
|
||||||
|
you to detect if your shell is running from within
|
||||||
|
.Nm .
|
||||||
|
This can be useful to avoid nesting multiple instances, although
|
||||||
|
.Nm
|
||||||
|
itself does not (currently) warn about or prevent this situation.
|
||||||
|
.It q
|
||||||
|
Quit
|
||||||
|
.El
|
||||||
|
.
|
||||||
|
.Sh FILE FLAGS
|
||||||
|
Entries in the browser interface may be prefixed by a one\-character flag.
|
||||||
|
These flags have the following meaning:
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It !
|
||||||
|
An error occurred while reading this directory.
|
||||||
|
.It \.
|
||||||
|
An error occurred while reading a subdirectory, so the indicated size may not
|
||||||
|
be correct.
|
||||||
|
.It <
|
||||||
|
File or directory is excluded from the statistics by using exclude patterns.
|
||||||
|
.It >
|
||||||
|
Directory is on another filesystem.
|
||||||
|
.It ^
|
||||||
|
Directory is excluded from the statistics due to being a Linux pseudo
|
||||||
|
filesystem.
|
||||||
|
.It @
|
||||||
|
This is neither a file nor a folder (symlink, socket, ...).
|
||||||
|
.It H
|
||||||
|
Same file was already counted (hard link).
|
||||||
|
.It e
|
||||||
|
Empty directory.
|
||||||
|
.El
|
||||||
|
.
|
||||||
|
.Sh EXAMPLES
|
||||||
|
To scan and browse the directory you're currently in, all you need is a simple:
|
||||||
|
.Dl ncdu
|
||||||
|
To scan a full filesystem, for example your root filesystem, you'll want to use
|
||||||
|
.Fl x :
|
||||||
|
.Dl ncdu \-x /
|
||||||
|
.Pp
|
||||||
|
Since scanning a large directory may take a while, you can scan a directory and
|
||||||
|
export the results for later viewing:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
ncdu \-1xo\- / | gzip >export.gz
|
||||||
|
# ...some time later:
|
||||||
|
zcat export.gz | ncdu \-f\-
|
||||||
|
.Ed
|
||||||
|
To export from a cron job, make sure to replace
|
||||||
|
.Fl 1
|
||||||
|
with
|
||||||
|
.Fl 0
|
||||||
|
to suppress unnecessary progress output.
|
||||||
|
.Pp
|
||||||
|
You can also export a directory and browse it once scanning is done:
|
||||||
|
.Dl ncdu \-o\- | tee export.file | ./ncdu \-f\-
|
||||||
|
The same is possible with gzip compression, but is a bit kludgey:
|
||||||
|
.Dl ncdu \-o\- | gzip | tee export.gz | gunzip | ./ncdu \-f\-
|
||||||
|
.Pp
|
||||||
|
To scan a system remotely, but browse through the files locally:
|
||||||
|
.Dl ssh \-C user@system ncdu \-o\- / | ./ncdu \-f\-
|
||||||
|
The
|
||||||
|
.Fl C
|
||||||
|
option to ssh enables compression, which will be very useful over slow links.
|
||||||
|
Remote scanning and local viewing has two major advantages when
|
||||||
|
compared to running
|
||||||
|
.Nm
|
||||||
|
directly on the remote system: You can browse through the scanned directory on
|
||||||
|
the local system without any network latency, and
|
||||||
|
.Nm
|
||||||
|
does not keep the entire directory structure in memory when exporting, so this
|
||||||
|
won't consume much memory on the remote system.
|
||||||
|
.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr du 1 ,
|
||||||
|
.Xr tree 1 .
|
||||||
|
.Pp
|
||||||
|
.Nm
|
||||||
|
has a website:
|
||||||
|
.Lk https://dev.yorhel.nl/ncdu
|
||||||
|
.
|
||||||
|
.Sh AUTHORS
|
||||||
|
Written by
|
||||||
|
.An Yorhel Aq Mt projects@yorhel.nl
|
||||||
|
.
|
||||||
|
.Sh BUGS
|
||||||
|
Directory hard links are not supported.
|
||||||
|
They are not detected as being hard links, and will thus get scanned and
|
||||||
|
counted multiple times.
|
||||||
|
.Pp
|
||||||
|
Some minor glitches may appear when displaying filenames that contain multibyte
|
||||||
|
or multicolumn characters.
|
||||||
|
.Pp
|
||||||
|
All sizes are internally represented as a signed 64bit integer.
|
||||||
|
If you have a directory larger than 8 EiB minus one byte, ncdu will clip its
|
||||||
|
size to 8 EiB minus one byte.
|
||||||
|
When deleting or refreshing items in a directory with a clipped size, the
|
||||||
|
resulting sizes will be incorrect.
|
||||||
|
Item counts are stored in a 32-bit integer without overflow detection.
|
||||||
|
If you have a directory with more than 2 billion files, quite literally
|
||||||
|
anything can happen.
|
||||||
|
.Pp
|
||||||
|
On macOS 10.15 and later, running ncdu on the root directory without
|
||||||
|
.Fl \-exclude\-firmlinks
|
||||||
|
may cause directories to be scanned and counted multiple times.
|
||||||
|
Firmlink cycles are not detected, so it may also cause
|
||||||
|
.Nm
|
||||||
|
to get stuck in an infinite loop and eventually run out of memory.
|
||||||
|
.Pp
|
||||||
|
Please report any other bugs you may find at the bug tracker, which can be
|
||||||
|
found on the web site at
|
||||||
|
.Lk https://dev.yorhel.nl/ncdu
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
static int graph = 1, show_as = 0, info_show = 0, info_page = 0, info_start = 0, show_items = 0, show_mtime = 0;
|
static int info_show = 0, info_page = 0, info_start = 0;
|
||||||
static const char *message = NULL;
|
static const char *message = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -68,15 +68,21 @@ static void browse_draw_info(struct dir *dr) {
|
||||||
|
|
||||||
ncaddstr(2, 9, cropstr(dr->name, 49));
|
ncaddstr(2, 9, cropstr(dr->name, 49));
|
||||||
ncaddstr(3, 9, cropstr(getpath(dr->parent), 49));
|
ncaddstr(3, 9, cropstr(getpath(dr->parent), 49));
|
||||||
ncaddstr(4, 9, dr->flags & FF_DIR ? "Directory" : dr->flags & FF_FILE ? "File" : "Other");
|
|
||||||
|
|
||||||
if(e) {
|
if(!e)
|
||||||
ncaddstr(4, 9, fmtmode(e->mode));
|
ncaddstr(4, 9, dr->flags & FF_DIR ? "Directory" : dr->flags & FF_FILE ? "File" : "Other");
|
||||||
ncprint(4, 26, "%d", e->uid);
|
else {
|
||||||
ncprint(4, 38, "%d", e->gid);
|
|
||||||
time_t t = (time_t)e->mtime;
|
time_t t = (time_t)e->mtime;
|
||||||
|
if(e->flags & FFE_MODE) ncaddstr(4, 9, fmtmode(e->mode));
|
||||||
|
else ncaddstr(4, 9, "N/A");
|
||||||
|
if(e->flags & FFE_UID) ncprint(4, 26, "%u", e->uid);
|
||||||
|
else ncaddstr(4, 26, "N/A");
|
||||||
|
if(e->flags & FFE_GID) ncprint(4, 38, "%u", e->gid);
|
||||||
|
else ncaddstr(4, 38, "N/A");
|
||||||
|
if(e->flags & FFE_MTIME) {
|
||||||
strftime(mbuf, sizeof(mbuf), "%Y-%m-%d %H:%M:%S %z", localtime(&t));
|
strftime(mbuf, sizeof(mbuf), "%Y-%m-%d %H:%M:%S %z", localtime(&t));
|
||||||
ncaddstr(5, 18, mbuf);
|
ncaddstr(5, 18, mbuf);
|
||||||
|
} else ncaddstr(5, 18, "N/A");
|
||||||
}
|
}
|
||||||
|
|
||||||
ncmove(6, 18);
|
ncmove(6, 18);
|
||||||
|
|
@ -130,9 +136,16 @@ static void browse_draw_flag(struct dir *n, int *x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *graph_styles[3][9] = {
|
||||||
|
{ " ", " ", " ", " ", " ", " ", " ", " ", "#" },
|
||||||
|
{ " ", " ", " ", " ", "▌", "▌", "▌", "▌", "█" },
|
||||||
|
{ " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█" },
|
||||||
|
};
|
||||||
|
|
||||||
static void browse_draw_graph(struct dir *n, int *x) {
|
static void browse_draw_graph(struct dir *n, int *x) {
|
||||||
float pc = 0.0f;
|
float pc = 0.0f;
|
||||||
int o, i, bar_size = wincols/7 > 10 ? wincols/7 : 10;
|
int64_t max, num, perblock, frac;
|
||||||
|
int i, bar_size = wincols/7 > 10 ? wincols/7 : 10;
|
||||||
enum ui_coltype c = n->flags & FF_BSEL ? UIC_SEL : UIC_DEFAULT;
|
enum ui_coltype c = n->flags & FF_BSEL ? UIC_SEL : UIC_DEFAULT;
|
||||||
|
|
||||||
if(!graph)
|
if(!graph)
|
||||||
|
|
@ -160,9 +173,21 @@ static void browse_draw_graph(struct dir *n, int *x) {
|
||||||
/* graph (10+ columns) */
|
/* graph (10+ columns) */
|
||||||
if(graph == 1 || graph == 3) {
|
if(graph == 1 || graph == 3) {
|
||||||
uic_set(c == UIC_SEL ? UIC_GRAPH_SEL : UIC_GRAPH);
|
uic_set(c == UIC_SEL ? UIC_GRAPH_SEL : UIC_GRAPH);
|
||||||
o = (int)((float)bar_size*(float)(show_as ? n->asize : n->size) / (float)(show_as ? dirlist_maxa : dirlist_maxs));
|
max = show_as ? dirlist_maxa : dirlist_maxs;
|
||||||
for(i=0; i<bar_size; i++)
|
num = show_as ? n->asize : n->size;
|
||||||
addch(i < o ? '#' : ' ');
|
if (max < bar_size) {
|
||||||
|
max *= bar_size;
|
||||||
|
num *= bar_size;
|
||||||
|
} else if (max > ((int64_t)1)<<56) { /* Prevent overflow in calculation below */
|
||||||
|
max <<= 5;
|
||||||
|
num <<= 5;
|
||||||
|
}
|
||||||
|
perblock = max / bar_size;
|
||||||
|
for(i=0; i<bar_size; i++) {
|
||||||
|
frac = (num * 8) / (perblock < 1 ? 1 : perblock);
|
||||||
|
addstr(graph_styles[graph_style][frac > 8 ? 8 : frac < 0 ? 0 : frac]);
|
||||||
|
num -= perblock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addchc(c, ']');
|
addchc(c, ']');
|
||||||
|
|
@ -256,7 +281,7 @@ static void browse_draw_item(struct dir *n, int row) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void browse_draw() {
|
void browse_draw(void) {
|
||||||
struct dir *t;
|
struct dir *t;
|
||||||
const char *tmp;
|
const char *tmp;
|
||||||
int selected = 0, i;
|
int selected = 0, i;
|
||||||
|
|
@ -272,7 +297,7 @@ void browse_draw() {
|
||||||
addstrc(UIC_HD, " for help");
|
addstrc(UIC_HD, " for help");
|
||||||
if(dir_import_active)
|
if(dir_import_active)
|
||||||
mvaddstr(0, wincols-10, "[imported]");
|
mvaddstr(0, wincols-10, "[imported]");
|
||||||
else if(read_only)
|
else if(!can_delete)
|
||||||
mvaddstr(0, wincols-11, "[read-only]");
|
mvaddstr(0, wincols-11, "[read-only]");
|
||||||
|
|
||||||
/* second line - the path */
|
/* second line - the path */
|
||||||
|
|
@ -288,9 +313,16 @@ void browse_draw() {
|
||||||
uic_set(UIC_HD);
|
uic_set(UIC_HD);
|
||||||
mvhline(winrows-1, 0, ' ', wincols);
|
mvhline(winrows-1, 0, ' ', wincols);
|
||||||
if(t) {
|
if(t) {
|
||||||
mvaddstr(winrows-1, 0, " Total disk usage: ");
|
if(!show_as) attron(A_BOLD);
|
||||||
|
mvaddchc(UIC_HD, winrows-1, 0, show_as ? ' ' : '*');
|
||||||
|
addstr("Total disk usage: ");
|
||||||
|
if(!show_as) attroff(A_BOLD);
|
||||||
printsize(UIC_HD, t->parent->size);
|
printsize(UIC_HD, t->parent->size);
|
||||||
|
if(show_as) attron(A_BOLD);
|
||||||
|
addstrc(UIC_HD, " ");
|
||||||
|
addchc(UIC_HD, show_as ? '*' : ' ');
|
||||||
addstrc(UIC_HD, "Apparent size: ");
|
addstrc(UIC_HD, "Apparent size: ");
|
||||||
|
if(show_as) attroff(A_BOLD);
|
||||||
uic_set(UIC_NUM_HD);
|
uic_set(UIC_NUM_HD);
|
||||||
printsize(UIC_HD, t->parent->asize);
|
printsize(UIC_HD, t->parent->asize);
|
||||||
addstrc(UIC_HD, " Items: ");
|
addstrc(UIC_HD, " Items: ");
|
||||||
|
|
@ -319,7 +351,7 @@ void browse_draw() {
|
||||||
if(message) {
|
if(message) {
|
||||||
nccreate(6, 60, "Message");
|
nccreate(6, 60, "Message");
|
||||||
ncaddstr(2, 2, message);
|
ncaddstr(2, 2, message);
|
||||||
ncaddstr(4, 34, "Press any key to continue");
|
ncaddstr(4, 33, "Press any key to continue");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* draw information window */
|
/* draw information window */
|
||||||
|
|
@ -484,8 +516,8 @@ int browse_key(int ch) {
|
||||||
|
|
||||||
/* and other stuff */
|
/* and other stuff */
|
||||||
case 'r':
|
case 'r':
|
||||||
if(dir_import_active) {
|
if(!can_refresh) {
|
||||||
message = "Directory imported from file, won't refresh.";
|
message = "Directory refresh feature disabled.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(dirlist_par) {
|
if(dirlist_par) {
|
||||||
|
|
@ -523,14 +555,12 @@ int browse_key(int ch) {
|
||||||
info_show = 0;
|
info_show = 0;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if(read_only >= 1 || dir_import_active) {
|
|
||||||
message = read_only >= 1
|
|
||||||
? "File deletion disabled in read-only mode."
|
|
||||||
: "File deletion not available for imported directories.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(sel == NULL || sel == dirlist_parent)
|
if(sel == NULL || sel == dirlist_parent)
|
||||||
break;
|
break;
|
||||||
|
if(!can_delete) {
|
||||||
|
message = "Deletion feature disabled.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
info_show = 0;
|
info_show = 0;
|
||||||
if((t = dirlist_get(1)) == sel)
|
if((t = dirlist_get(1)) == sel)
|
||||||
if((t = dirlist_get(-1)) == sel || t == dirlist_parent)
|
if((t = dirlist_get(-1)) == sel || t == dirlist_parent)
|
||||||
|
|
@ -538,10 +568,8 @@ int browse_key(int ch) {
|
||||||
delete_init(sel, t);
|
delete_init(sel, t);
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
if(read_only >= 2 || dir_import_active) {
|
if(!can_shell) {
|
||||||
message = read_only >= 2
|
message = "Shell feature disabled.";
|
||||||
? "Shell feature disabled in read-only mode."
|
|
||||||
: "Shell feature not available for imported directories.";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
shell_init();
|
shell_init();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
13
src/delete.c
13
src/delete.c
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -35,9 +35,10 @@
|
||||||
#define DS_PROGRESS 1
|
#define DS_PROGRESS 1
|
||||||
#define DS_FAILED 2
|
#define DS_FAILED 2
|
||||||
|
|
||||||
|
int delete_confirm = 1;
|
||||||
|
|
||||||
static struct dir *root, *nextsel, *curdir;
|
static struct dir *root, *nextsel, *curdir;
|
||||||
static char noconfirm = 0, ignoreerr = 0, state;
|
static char ignoreerr = 0, state;
|
||||||
static signed char seloption;
|
static signed char seloption;
|
||||||
static int lasterrno;
|
static int lasterrno;
|
||||||
|
|
||||||
|
|
@ -98,7 +99,7 @@ static void delete_draw_error(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void delete_draw() {
|
void delete_draw(void) {
|
||||||
browse_draw();
|
browse_draw();
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case DS_CONFIRM: delete_draw_confirm(); break;
|
case DS_CONFIRM: delete_draw_confirm(); break;
|
||||||
|
|
@ -126,7 +127,7 @@ int delete_key(int ch) {
|
||||||
if(seloption == 1)
|
if(seloption == 1)
|
||||||
return 1;
|
return 1;
|
||||||
if(seloption == 2)
|
if(seloption == 2)
|
||||||
noconfirm++;
|
delete_confirm = 0;
|
||||||
state = DS_PROGRESS;
|
state = DS_PROGRESS;
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
|
|
@ -211,12 +212,12 @@ delete_nxt:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void delete_process() {
|
void delete_process(void) {
|
||||||
struct dir *par;
|
struct dir *par;
|
||||||
|
|
||||||
/* confirm */
|
/* confirm */
|
||||||
seloption = 1;
|
seloption = 1;
|
||||||
while(state == DS_CONFIRM && !noconfirm)
|
while(state == DS_CONFIRM && delete_confirm)
|
||||||
if(input_handle(0)) {
|
if(input_handle(0)) {
|
||||||
browse_init(root->parent);
|
browse_init(root->parent);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
|
extern int delete_confirm;
|
||||||
|
|
||||||
void delete_process(void);
|
void delete_process(void);
|
||||||
int delete_key(int);
|
int delete_key(int);
|
||||||
void delete_draw(void);
|
void delete_draw(void);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -69,7 +69,7 @@ struct dir_output {
|
||||||
* The function should return non-zero on error, at which point errno is
|
* The function should return non-zero on error, at which point errno is
|
||||||
* assumed to be set to something sensible.
|
* assumed to be set to something sensible.
|
||||||
*/
|
*/
|
||||||
int (*item)(struct dir *, const char *, struct dir_ext *);
|
int (*item)(struct dir *, const char *, struct dir_ext *, unsigned int);
|
||||||
|
|
||||||
/* Finalizes the output to go to the next program state or exit ncdu. Called
|
/* Finalizes the output to go to the next program state or exit ncdu. Called
|
||||||
* after item(NULL) has been called for the root item or before any item()
|
* after item(NULL) has been called for the root item or before any item()
|
||||||
|
|
@ -107,16 +107,13 @@ extern int (*dir_process)(void);
|
||||||
|
|
||||||
/* Scanning a live directory */
|
/* Scanning a live directory */
|
||||||
extern int dir_scan_smfs;
|
extern int dir_scan_smfs;
|
||||||
|
extern int exclude_kernfs;
|
||||||
void dir_scan_init(const char *path);
|
void dir_scan_init(const char *path);
|
||||||
|
|
||||||
/* Importing a file */
|
/* Importing a file */
|
||||||
extern int dir_import_active;
|
extern int dir_import_active;
|
||||||
int dir_import_init(const char *fn);
|
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. */
|
/* The currently configured output functions. */
|
||||||
extern struct dir_output dir_output;
|
extern struct dir_output dir_output;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -35,7 +35,7 @@ int (*dir_process)(void);
|
||||||
char *dir_curpath; /* Full path of the last seen item. */
|
char *dir_curpath; /* Full path of the last seen item. */
|
||||||
struct dir_output dir_output;
|
struct dir_output dir_output;
|
||||||
char *dir_fatalerr; /* Error message on a fatal error. (NULL if there was no fatal error) */
|
char *dir_fatalerr; /* Error message on a fatal error. (NULL if there was no fatal error) */
|
||||||
int dir_ui; /* User interface to use */
|
int dir_ui = -1; /* User interface to use */
|
||||||
static int confirm_quit_while_scanning_stage_1_passed; /* Additional check before quitting */
|
static int confirm_quit_while_scanning_stage_1_passed; /* Additional check before quitting */
|
||||||
static char *lasterr; /* Path where the last error occurred. */
|
static char *lasterr; /* Path where the last error occurred. */
|
||||||
static int curpathl; /* Allocated length of dir_curpath */
|
static int curpathl; /* Allocated length of dir_curpath */
|
||||||
|
|
@ -65,7 +65,7 @@ void dir_curpath_enter(const char *name) {
|
||||||
|
|
||||||
|
|
||||||
/* removes last component from dir_curpath */
|
/* removes last component from dir_curpath */
|
||||||
void dir_curpath_leave() {
|
void dir_curpath_leave(void) {
|
||||||
char *tmp;
|
char *tmp;
|
||||||
if((tmp = strrchr(dir_curpath, '/')) == NULL)
|
if((tmp = strrchr(dir_curpath, '/')) == NULL)
|
||||||
strcpy(dir_curpath, "/");
|
strcpy(dir_curpath, "/");
|
||||||
|
|
@ -77,13 +77,14 @@ void dir_curpath_leave() {
|
||||||
|
|
||||||
|
|
||||||
void dir_setlasterr(const char *path) {
|
void dir_setlasterr(const char *path) {
|
||||||
|
int req;
|
||||||
if(!path) {
|
if(!path) {
|
||||||
free(lasterr);
|
free(lasterr);
|
||||||
lasterr = NULL;
|
lasterr = NULL;
|
||||||
lasterrl = 0;
|
lasterrl = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int req = strlen(path)+1;
|
req = strlen(path)+1;
|
||||||
if(lasterrl < req) {
|
if(lasterrl < req) {
|
||||||
lasterrl = req;
|
lasterrl = req;
|
||||||
lasterr = xrealloc(lasterr, lasterrl);
|
lasterr = xrealloc(lasterr, lasterrl);
|
||||||
|
|
@ -93,12 +94,12 @@ void dir_setlasterr(const char *path) {
|
||||||
|
|
||||||
|
|
||||||
void dir_seterr(const char *fmt, ...) {
|
void dir_seterr(const char *fmt, ...) {
|
||||||
|
va_list va;
|
||||||
free(dir_fatalerr);
|
free(dir_fatalerr);
|
||||||
dir_fatalerr = NULL;
|
dir_fatalerr = NULL;
|
||||||
if(!fmt)
|
if(!fmt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
dir_fatalerr = xmalloc(1024); /* Should be enough for everything... */
|
dir_fatalerr = xmalloc(1024); /* Should be enough for everything... */
|
||||||
vsnprintf(dir_fatalerr, 1023, fmt, va);
|
vsnprintf(dir_fatalerr, 1023, fmt, va);
|
||||||
|
|
@ -179,7 +180,7 @@ static void draw_error(char *cur, char *msg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void dir_draw() {
|
void dir_draw(void) {
|
||||||
float f;
|
float f;
|
||||||
const char *unit;
|
const char *unit;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -74,7 +74,7 @@ static void output_int(uint64_t n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void output_info(struct dir *d, const char *name, struct dir_ext *e) {
|
static void output_info(struct dir *d, const char *name, struct dir_ext *e, unsigned int nlink) {
|
||||||
if(!extended_info || !(d->flags & FF_EXT))
|
if(!extended_info || !(d->flags & FF_EXT))
|
||||||
e = NULL;
|
e = NULL;
|
||||||
|
|
||||||
|
|
@ -96,23 +96,32 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) {
|
||||||
fputs(",\"dev\":", stream);
|
fputs(",\"dev\":", stream);
|
||||||
output_int(d->dev);
|
output_int(d->dev);
|
||||||
}
|
}
|
||||||
fputs(",\"ino\":", stream);
|
|
||||||
output_int(d->ino);
|
|
||||||
|
|
||||||
if(e) {
|
if(e) {
|
||||||
|
if(e->flags & FFE_UID) {
|
||||||
fputs(",\"uid\":", stream);
|
fputs(",\"uid\":", stream);
|
||||||
output_int(e->uid);
|
output_int(e->uid);
|
||||||
|
}
|
||||||
|
if(e->flags & FFE_GID) {
|
||||||
fputs(",\"gid\":", stream);
|
fputs(",\"gid\":", stream);
|
||||||
output_int(e->gid);
|
output_int(e->gid);
|
||||||
|
}
|
||||||
|
if(e->flags & FFE_MODE) {
|
||||||
fputs(",\"mode\":", stream);
|
fputs(",\"mode\":", stream);
|
||||||
output_int(e->mode);
|
output_int(e->mode);
|
||||||
|
}
|
||||||
|
if(e->flags & FFE_MTIME) {
|
||||||
fputs(",\"mtime\":", stream);
|
fputs(",\"mtime\":", stream);
|
||||||
output_int(e->mtime);
|
output_int(e->mtime);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: Including the actual number of links would be nicer. */
|
if(d->flags & FF_HLNKC) {
|
||||||
if(d->flags & FF_HLNKC)
|
fputs(",\"ino\":", stream);
|
||||||
fputs(",\"hlnkc\":true", stream);
|
output_int(d->ino);
|
||||||
|
fputs(",\"hlnkc\":true,\"nlink\":", stream);
|
||||||
|
output_int(nlink);
|
||||||
|
}
|
||||||
if(d->flags & FF_ERR)
|
if(d->flags & FF_ERR)
|
||||||
fputs(",\"read_error\":true", stream);
|
fputs(",\"read_error\":true", stream);
|
||||||
/* excluded/error'd files are "unknown" with respect to the "notreg" field. */
|
/* excluded/error'd files are "unknown" with respect to the "notreg" field. */
|
||||||
|
|
@ -121,7 +130,7 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) {
|
||||||
if(d->flags & FF_EXL)
|
if(d->flags & FF_EXL)
|
||||||
fputs(",\"excluded\":\"pattern\"", stream);
|
fputs(",\"excluded\":\"pattern\"", stream);
|
||||||
else if(d->flags & FF_OTHFS)
|
else if(d->flags & FF_OTHFS)
|
||||||
fputs(",\"excluded\":\"othfs\"", stream);
|
fputs(",\"excluded\":\"otherfs\"", stream);
|
||||||
else if(d->flags & FF_KERNFS)
|
else if(d->flags & FF_KERNFS)
|
||||||
fputs(",\"excluded\":\"kernfs\"", stream);
|
fputs(",\"excluded\":\"kernfs\"", stream);
|
||||||
else if(d->flags & FF_FRMLNK)
|
else if(d->flags & FF_FRMLNK)
|
||||||
|
|
@ -136,7 +145,7 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) {
|
||||||
* item() call do we check for ferror(). This greatly simplifies the code, but
|
* item() call do we check for ferror(). This greatly simplifies the code, but
|
||||||
* assumes that calls to fwrite()/fput./etc don't do any weird stuff when
|
* assumes that calls to fwrite()/fput./etc don't do any weird stuff when
|
||||||
* called with a stream that's in an error state. */
|
* called with a stream that's in an error state. */
|
||||||
static int item(struct dir *item, const char *name, struct dir_ext *ext) {
|
static int item(struct dir *item, const char *name, struct dir_ext *ext, unsigned int nlink) {
|
||||||
if(!item) {
|
if(!item) {
|
||||||
nstack_pop(&stack);
|
nstack_pop(&stack);
|
||||||
if(!stack.top) { /* closing of the root item */
|
if(!stack.top) { /* closing of the root item */
|
||||||
|
|
@ -152,7 +161,7 @@ static int item(struct dir *item, const char *name, struct dir_ext *ext) {
|
||||||
/* File header.
|
/* File header.
|
||||||
* TODO: Add scan options? */
|
* TODO: Add scan options? */
|
||||||
if(!stack.top) {
|
if(!stack.top) {
|
||||||
fputs("[1,1,{\"progname\":\""PACKAGE"\",\"progver\":\""PACKAGE_VERSION"\",\"timestamp\":", stream);
|
fputs("[1,2,{\"progname\":\""PACKAGE"\",\"progver\":\""PACKAGE_VERSION"\",\"timestamp\":", stream);
|
||||||
output_int((uint64_t)time(NULL));
|
output_int((uint64_t)time(NULL));
|
||||||
fputc('}', stream);
|
fputc('}', stream);
|
||||||
}
|
}
|
||||||
|
|
@ -161,7 +170,7 @@ static int item(struct dir *item, const char *name, struct dir_ext *ext) {
|
||||||
if(item->flags & FF_DIR)
|
if(item->flags & FF_DIR)
|
||||||
fputc('[', stream);
|
fputc('[', stream);
|
||||||
|
|
||||||
output_info(item, name, ext);
|
output_info(item, name, ext, nlink);
|
||||||
|
|
||||||
if(item->flags & FF_DIR)
|
if(item->flags & FF_DIR)
|
||||||
nstack_push(&stack, item->dev);
|
nstack_push(&stack, item->dev);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -72,6 +72,7 @@ static struct ctx {
|
||||||
/* scratch space */
|
/* scratch space */
|
||||||
struct dir *buf_dir;
|
struct dir *buf_dir;
|
||||||
struct dir_ext buf_ext[1];
|
struct dir_ext buf_ext[1];
|
||||||
|
unsigned int nlink;
|
||||||
|
|
||||||
char buf_name[MAX_VAL];
|
char buf_name[MAX_VAL];
|
||||||
char val[MAX_VAL];
|
char val[MAX_VAL];
|
||||||
|
|
@ -186,7 +187,7 @@ static int cons(void) {
|
||||||
|
|
||||||
|
|
||||||
static int rstring_esc(char **dest, int *destlen) {
|
static int rstring_esc(char **dest, int *destlen) {
|
||||||
unsigned int n;
|
unsigned int n, s;
|
||||||
|
|
||||||
C(rfill1);
|
C(rfill1);
|
||||||
|
|
||||||
|
|
@ -203,8 +204,22 @@ static int rstring_esc(char **dest, int *destlen) {
|
||||||
case 'u':
|
case 'u':
|
||||||
C(rfill(5));
|
C(rfill(5));
|
||||||
#define hn(n) (n >= '0' && n <= '9' ? n-'0' : n >= 'A' && n <= 'F' ? n-'A'+10 : n >= 'a' && n <= 'f' ? n-'a'+10 : 1<<16)
|
#define hn(n) (n >= '0' && n <= '9' ? n-'0' : n >= 'A' && n <= 'F' ? n-'A'+10 : n >= 'a' && n <= 'f' ? n-'a'+10 : 1<<16)
|
||||||
n = (hn(ctx->buf[1])<<12) + (hn(ctx->buf[2])<<8) + (hn(ctx->buf[3])<<4) + hn(ctx->buf[4]);
|
#define h4(b) (hn((b)[0])<<12) + (hn((b)[1])<<8) + (hn((b)[2])<<4) + hn((b)[3])
|
||||||
#undef hn
|
n = h4(ctx->buf+1);
|
||||||
|
con(5);
|
||||||
|
E(n >= (1<<16), "Invalid \\u escape");
|
||||||
|
E((n & 0xfc00) == 0xdc00, "Unexpected low surrogate");
|
||||||
|
if((n & 0xfc00) == 0xd800) { /* high surrogate */
|
||||||
|
C(rfill(7));
|
||||||
|
E(ctx->buf[0] != '\\', "Expected low surrogate");
|
||||||
|
E(ctx->buf[1] != 'u', "Expected low surrogate");
|
||||||
|
s = h4(ctx->buf+2);
|
||||||
|
con(6);
|
||||||
|
E(s >= (1<<16), "Invalid \\u escape");
|
||||||
|
E((s & 0xfc00) != 0xdc00, "Expected low surrogate");
|
||||||
|
n = 0x10000 + (((n & 0x03ff) << 10) | (s & 0x03ff));
|
||||||
|
}
|
||||||
|
|
||||||
if(n <= 0x007F) {
|
if(n <= 0x007F) {
|
||||||
ap(n);
|
ap(n);
|
||||||
} else if(n <= 0x07FF) {
|
} else if(n <= 0x07FF) {
|
||||||
|
|
@ -214,9 +229,14 @@ static int rstring_esc(char **dest, int *destlen) {
|
||||||
ap(0xE0 | (n>>12));
|
ap(0xE0 | (n>>12));
|
||||||
ap(0x80 | ((n>>6) & 0x3F));
|
ap(0x80 | ((n>>6) & 0x3F));
|
||||||
ap(0x80 | (n & 0x3F));
|
ap(0x80 | (n & 0x3F));
|
||||||
} else /* this happens if there was an invalid character (n >= (1<<16)) */
|
} else {
|
||||||
E(1, "Invalid character in \\u escape");
|
ap(0xF0 | (n>>18));\
|
||||||
con(5);
|
ap(0x80 | ((n>>12) & 0x3F));
|
||||||
|
ap(0x80 | ((n>>6) & 0x3F));
|
||||||
|
ap(0x80 | (n & 0x3F));
|
||||||
|
}
|
||||||
|
#undef hn
|
||||||
|
#undef h4
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
E(1, "Invalid escape sequence");
|
E(1, "Invalid escape sequence");
|
||||||
|
|
@ -421,7 +441,7 @@ static int itemdir(uint64_t dev) {
|
||||||
|
|
||||||
|
|
||||||
/* Reads a JSON object representing a struct dir/dir_ext item. Writes to
|
/* Reads a JSON object representing a struct dir/dir_ext item. Writes to
|
||||||
* ctx->buf_dir, ctx->buf_ext and ctx->buf_name. */
|
* ctx->buf_dir, ctx->buf_ext, ctx->buf_name and ctx->nlink. */
|
||||||
static int iteminfo(void) {
|
static int iteminfo(void) {
|
||||||
uint64_t iv;
|
uint64_t iv;
|
||||||
|
|
||||||
|
|
@ -449,27 +469,42 @@ static int iteminfo(void) {
|
||||||
C(rint64(&iv, UINT64_MAX));
|
C(rint64(&iv, UINT64_MAX));
|
||||||
ctx->buf_dir->ino = iv;
|
ctx->buf_dir->ino = iv;
|
||||||
} else if(strcmp(ctx->val, "uid") == 0) { /* uid */
|
} else if(strcmp(ctx->val, "uid") == 0) { /* uid */
|
||||||
C(rint64(&iv, INT32_MAX));
|
C(rint64(&iv, UINT32_MAX));
|
||||||
ctx->buf_dir->flags |= FF_EXT;
|
ctx->buf_dir->flags |= FF_EXT;
|
||||||
|
ctx->buf_ext->flags |= FFE_UID;
|
||||||
ctx->buf_ext->uid = iv;
|
ctx->buf_ext->uid = iv;
|
||||||
} else if(strcmp(ctx->val, "gid") == 0) { /* gid */
|
} else if(strcmp(ctx->val, "gid") == 0) { /* gid */
|
||||||
C(rint64(&iv, INT32_MAX));
|
C(rint64(&iv, UINT32_MAX));
|
||||||
ctx->buf_dir->flags |= FF_EXT;
|
ctx->buf_dir->flags |= FF_EXT;
|
||||||
|
ctx->buf_ext->flags |= FFE_GID;
|
||||||
ctx->buf_ext->gid = iv;
|
ctx->buf_ext->gid = iv;
|
||||||
} else if(strcmp(ctx->val, "mode") == 0) { /* mode */
|
} else if(strcmp(ctx->val, "mode") == 0) { /* mode */
|
||||||
C(rint64(&iv, UINT16_MAX));
|
C(rint64(&iv, UINT16_MAX));
|
||||||
ctx->buf_dir->flags |= FF_EXT;
|
ctx->buf_dir->flags |= FF_EXT;
|
||||||
|
ctx->buf_ext->flags |= FFE_MODE;
|
||||||
ctx->buf_ext->mode = iv;
|
ctx->buf_ext->mode = iv;
|
||||||
} else if(strcmp(ctx->val, "mtime") == 0) { /* mtime */
|
} else if(strcmp(ctx->val, "mtime") == 0) { /* mtime */
|
||||||
C(rint64(&iv, UINT64_MAX));
|
C(rint64(&iv, UINT64_MAX));
|
||||||
ctx->buf_dir->flags |= FF_EXT;
|
ctx->buf_dir->flags |= FF_EXT;
|
||||||
|
ctx->buf_ext->flags |= FFE_MTIME;
|
||||||
ctx->buf_ext->mtime = iv;
|
ctx->buf_ext->mtime = iv;
|
||||||
|
/* Accept decimal numbers, but discard the fractional part because our data model doesn't support it. */
|
||||||
|
if(*ctx->buf == '.') {
|
||||||
|
con(1);
|
||||||
|
while(*ctx->buf >= '0' && *ctx->buf <= '9')
|
||||||
|
con(1);
|
||||||
|
}
|
||||||
} else if(strcmp(ctx->val, "hlnkc") == 0) { /* hlnkc */
|
} else if(strcmp(ctx->val, "hlnkc") == 0) { /* hlnkc */
|
||||||
if(*ctx->buf == 't') {
|
if(*ctx->buf == 't') {
|
||||||
C(rlit("true", 4));
|
C(rlit("true", 4));
|
||||||
ctx->buf_dir->flags |= FF_HLNKC;
|
ctx->buf_dir->flags |= FF_HLNKC;
|
||||||
} else
|
} else
|
||||||
C(rlit("false", 5));
|
C(rlit("false", 5));
|
||||||
|
} else if(strcmp(ctx->val, "nlink") == 0) { /* nlink */
|
||||||
|
C(rint64(&iv, UINT32_MAX));
|
||||||
|
if(iv > 1)
|
||||||
|
ctx->buf_dir->flags |= FF_HLNKC;
|
||||||
|
ctx->nlink = iv;
|
||||||
} else if(strcmp(ctx->val, "read_error") == 0) { /* read_error */
|
} else if(strcmp(ctx->val, "read_error") == 0) { /* read_error */
|
||||||
if(*ctx->buf == 't') {
|
if(*ctx->buf == 't') {
|
||||||
C(rlit("true", 4));
|
C(rlit("true", 4));
|
||||||
|
|
@ -478,7 +513,7 @@ static int iteminfo(void) {
|
||||||
C(rlit("false", 5));
|
C(rlit("false", 5));
|
||||||
} else if(strcmp(ctx->val, "excluded") == 0) { /* excluded */
|
} else if(strcmp(ctx->val, "excluded") == 0) { /* excluded */
|
||||||
C(rstring(ctx->val, 8));
|
C(rstring(ctx->val, 8));
|
||||||
if(strcmp(ctx->val, "otherfs") == 0)
|
if(strcmp(ctx->val, "otherfs") == 0 || strcmp(ctx->val, "othfs") == 0)
|
||||||
ctx->buf_dir->flags |= FF_OTHFS;
|
ctx->buf_dir->flags |= FF_OTHFS;
|
||||||
else if(strcmp(ctx->val, "kernfs") == 0)
|
else if(strcmp(ctx->val, "kernfs") == 0)
|
||||||
ctx->buf_dir->flags |= FF_KERNFS;
|
ctx->buf_dir->flags |= FF_KERNFS;
|
||||||
|
|
@ -526,6 +561,7 @@ static int item(uint64_t dev) {
|
||||||
|
|
||||||
memset(ctx->buf_dir, 0, offsetof(struct dir, name));
|
memset(ctx->buf_dir, 0, offsetof(struct dir, name));
|
||||||
memset(ctx->buf_ext, 0, sizeof(struct dir_ext));
|
memset(ctx->buf_ext, 0, sizeof(struct dir_ext));
|
||||||
|
ctx->nlink = 0;
|
||||||
*ctx->buf_name = 0;
|
*ctx->buf_name = 0;
|
||||||
ctx->buf_dir->flags |= isdir ? FF_DIR : FF_FILE;
|
ctx->buf_dir->flags |= isdir ? FF_DIR : FF_FILE;
|
||||||
ctx->buf_dir->dev = dev;
|
ctx->buf_dir->dev = dev;
|
||||||
|
|
@ -539,16 +575,16 @@ static int item(uint64_t dev) {
|
||||||
dir_curpath_enter(ctx->buf_name);
|
dir_curpath_enter(ctx->buf_name);
|
||||||
|
|
||||||
if(isdir) {
|
if(isdir) {
|
||||||
if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext)) {
|
if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext, ctx->nlink)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
C(itemdir(dev));
|
C(itemdir(dev));
|
||||||
if(dir_output.item(NULL, 0, NULL)) {
|
if(dir_output.item(NULL, 0, NULL, 0)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext)) {
|
} else if(dir_output.item(ctx->buf_dir, ctx->buf_name, ctx->buf_ext, ctx->nlink)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -561,8 +597,14 @@ static int item(uint64_t dev) {
|
||||||
|
|
||||||
|
|
||||||
static int footer(void) {
|
static int footer(void) {
|
||||||
|
while(1) {
|
||||||
C(cons());
|
C(cons());
|
||||||
E(*ctx->buf != ']', "Expected ']'");
|
if(*ctx->buf == ']')
|
||||||
|
break;
|
||||||
|
E(*ctx->buf != ',', "Expected ',' or ']'");
|
||||||
|
con(1);
|
||||||
|
C(cons() || rval());
|
||||||
|
}
|
||||||
con(1);
|
con(1);
|
||||||
C(cons());
|
C(cons());
|
||||||
E(*ctx->buf, "Trailing garbage");
|
E(*ctx->buf, "Trailing garbage");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -45,13 +45,13 @@ static hl_t *links = NULL;
|
||||||
/* recursively checks a dir structure for hard links and fills the lookup array */
|
/* recursively checks a dir structure for hard links and fills the lookup array */
|
||||||
static void hlink_init(struct dir *d) {
|
static void hlink_init(struct dir *d) {
|
||||||
struct dir *t;
|
struct dir *t;
|
||||||
|
int r;
|
||||||
|
|
||||||
for(t=d->sub; t!=NULL; t=t->next)
|
for(t=d->sub; t!=NULL; t=t->next)
|
||||||
hlink_init(t);
|
hlink_init(t);
|
||||||
|
|
||||||
if(!(d->flags & FF_HLNKC))
|
if(!(d->flags & FF_HLNKC))
|
||||||
return;
|
return;
|
||||||
int r;
|
|
||||||
hl_put(links, d, &r);
|
hl_put(links, d, &r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,8 +109,9 @@ static void item_add(struct dir *item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int item(struct dir *dir, const char *name, struct dir_ext *ext) {
|
static int item(struct dir *dir, const char *name, struct dir_ext *ext, unsigned int nlink) {
|
||||||
struct dir *t, *item;
|
struct dir *t, *item;
|
||||||
|
(void)nlink;
|
||||||
|
|
||||||
/* Go back to parent dir */
|
/* Go back to parent dir */
|
||||||
if(!dir) {
|
if(!dir) {
|
||||||
|
|
@ -126,7 +127,7 @@ static int item(struct dir *dir, const char *name, struct dir_ext *ext) {
|
||||||
item = xmalloc(dir->flags & FF_EXT ? dir_ext_memsize(name) : dir_memsize(name));
|
item = xmalloc(dir->flags & FF_EXT ? dir_ext_memsize(name) : dir_memsize(name));
|
||||||
memcpy(item, dir, offsetof(struct dir, name));
|
memcpy(item, dir, offsetof(struct dir, name));
|
||||||
strcpy(item->name, name);
|
strcpy(item->name, name);
|
||||||
if(dir->flags & FF_EXT)
|
if(item->flags & FF_EXT)
|
||||||
memcpy(dir_ext_ptr(item), ext, sizeof(struct dir_ext));
|
memcpy(dir_ext_ptr(item), ext, sizeof(struct dir_ext));
|
||||||
|
|
||||||
item_add(item);
|
item_add(item);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -51,16 +51,17 @@
|
||||||
|
|
||||||
|
|
||||||
int dir_scan_smfs; /* Stay on the same filesystem */
|
int dir_scan_smfs; /* Stay on the same filesystem */
|
||||||
|
int exclude_kernfs; /* Exclude Linux pseudo filesystems */
|
||||||
|
|
||||||
static uint64_t curdev; /* current device we're scanning on */
|
static uint64_t curdev; /* current device we're scanning on */
|
||||||
|
|
||||||
/* scratch space */
|
/* scratch space */
|
||||||
static struct dir *buf_dir;
|
static struct dir *buf_dir;
|
||||||
static struct dir_ext buf_ext[1];
|
static struct dir_ext buf_ext[1];
|
||||||
|
static unsigned int buf_nlink;
|
||||||
|
|
||||||
|
|
||||||
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
|
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
|
||||||
int exclude_kernfs; /* Exclude Linux pseudo filesystems */
|
|
||||||
|
|
||||||
static int is_kernfs(unsigned long type) {
|
static int is_kernfs(unsigned long type) {
|
||||||
if(
|
if(
|
||||||
|
|
@ -120,8 +121,11 @@ static void stat_to_dir(struct stat *fs) {
|
||||||
else if(S_ISDIR(fs->st_mode))
|
else if(S_ISDIR(fs->st_mode))
|
||||||
buf_dir->flags |= FF_DIR;
|
buf_dir->flags |= FF_DIR;
|
||||||
|
|
||||||
if(!S_ISDIR(fs->st_mode) && fs->st_nlink > 1)
|
if(!S_ISDIR(fs->st_mode) && fs->st_nlink > 1) {
|
||||||
buf_dir->flags |= FF_HLNKC;
|
buf_dir->flags |= FF_HLNKC;
|
||||||
|
buf_nlink = fs->st_nlink;
|
||||||
|
} else
|
||||||
|
buf_nlink = 0;
|
||||||
|
|
||||||
if(dir_scan_smfs && curdev != buf_dir->dev)
|
if(dir_scan_smfs && curdev != buf_dir->dev)
|
||||||
buf_dir->flags |= FF_OTHFS;
|
buf_dir->flags |= FF_OTHFS;
|
||||||
|
|
@ -133,8 +137,9 @@ static void stat_to_dir(struct stat *fs) {
|
||||||
|
|
||||||
buf_ext->mode = fs->st_mode;
|
buf_ext->mode = fs->st_mode;
|
||||||
buf_ext->mtime = fs->st_mtime;
|
buf_ext->mtime = fs->st_mtime;
|
||||||
buf_ext->uid = (int)fs->st_uid;
|
buf_ext->uid = (unsigned int)fs->st_uid;
|
||||||
buf_ext->gid = (int)fs->st_gid;
|
buf_ext->gid = (unsigned int)fs->st_gid;
|
||||||
|
buf_ext->flags = FFE_MTIME | FFE_UID | FFE_GID | FFE_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -158,21 +163,26 @@ static char *dir_read(int *err) {
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = xmalloc(buflen);
|
buf = xmalloc(buflen);
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
while((item = readdir(dir)) != NULL) {
|
while(1) {
|
||||||
|
size_t len, req;
|
||||||
|
errno = 0;
|
||||||
|
if ((item = readdir(dir)) == NULL) {
|
||||||
|
if(errno)
|
||||||
|
*err = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(item->d_name[0] == '.' && (item->d_name[1] == 0 || (item->d_name[1] == '.' && item->d_name[2] == 0)))
|
if(item->d_name[0] == '.' && (item->d_name[1] == 0 || (item->d_name[1] == '.' && item->d_name[2] == 0)))
|
||||||
continue;
|
continue;
|
||||||
size_t req = off+3+strlen(item->d_name);
|
len = strlen(item->d_name);
|
||||||
|
req = off+3+len;
|
||||||
if(req > buflen) {
|
if(req > buflen) {
|
||||||
buflen = req < buflen*2 ? buflen*2 : req;
|
buflen = req < buflen*2 ? buflen*2 : req;
|
||||||
buf = xrealloc(buf, buflen);
|
buf = xrealloc(buf, buflen);
|
||||||
}
|
}
|
||||||
strcpy(buf+off, item->d_name);
|
strcpy(buf+off, item->d_name);
|
||||||
off += strlen(item->d_name)+1;
|
off += len+1;
|
||||||
}
|
}
|
||||||
if(errno)
|
|
||||||
*err = 1;
|
|
||||||
if(closedir(dir) < 0)
|
if(closedir(dir) < 0)
|
||||||
*err = 1;
|
*err = 1;
|
||||||
|
|
||||||
|
|
@ -193,7 +203,7 @@ static int dir_scan_recurse(const char *name) {
|
||||||
if(chdir(name)) {
|
if(chdir(name)) {
|
||||||
dir_setlasterr(dir_curpath);
|
dir_setlasterr(dir_curpath);
|
||||||
buf_dir->flags |= FF_ERR;
|
buf_dir->flags |= FF_ERR;
|
||||||
if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) {
|
if(dir_output.item(buf_dir, name, buf_ext, buf_nlink) || dir_output.item(NULL, 0, NULL, 0)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +213,7 @@ static int dir_scan_recurse(const char *name) {
|
||||||
if((dir = dir_read(&fail)) == NULL) {
|
if((dir = dir_read(&fail)) == NULL) {
|
||||||
dir_setlasterr(dir_curpath);
|
dir_setlasterr(dir_curpath);
|
||||||
buf_dir->flags |= FF_ERR;
|
buf_dir->flags |= FF_ERR;
|
||||||
if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) {
|
if(dir_output.item(buf_dir, name, buf_ext, buf_nlink) || dir_output.item(NULL, 0, NULL, 0)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -218,12 +228,12 @@ static int dir_scan_recurse(const char *name) {
|
||||||
if(fail)
|
if(fail)
|
||||||
buf_dir->flags |= FF_ERR;
|
buf_dir->flags |= FF_ERR;
|
||||||
|
|
||||||
if(dir_output.item(buf_dir, name, buf_ext)) {
|
if(dir_output.item(buf_dir, name, buf_ext, buf_nlink)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
fail = dir_walk(dir);
|
fail = dir_walk(dir);
|
||||||
if(dir_output.item(NULL, 0, NULL)) {
|
if(dir_output.item(NULL, 0, NULL, 0)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -308,11 +318,11 @@ static int dir_scan_item(const char *name) {
|
||||||
if(buf_dir->flags & FF_DIR && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS|FF_FRMLNK)))
|
if(buf_dir->flags & FF_DIR && !(buf_dir->flags & (FF_ERR|FF_EXL|FF_OTHFS|FF_KERNFS|FF_FRMLNK)))
|
||||||
fail = dir_scan_recurse(name);
|
fail = dir_scan_recurse(name);
|
||||||
else if(buf_dir->flags & FF_DIR) {
|
else if(buf_dir->flags & FF_DIR) {
|
||||||
if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) {
|
if(dir_output.item(buf_dir, name, buf_ext, 0) || dir_output.item(NULL, 0, NULL, 0)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
fail = 1;
|
fail = 1;
|
||||||
}
|
}
|
||||||
} else if(dir_output.item(buf_dir, name, buf_ext)) {
|
} else if(dir_output.item(buf_dir, name, buf_ext, buf_nlink)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
fail = 1;
|
fail = 1;
|
||||||
}
|
}
|
||||||
|
|
@ -333,6 +343,7 @@ static int dir_walk(char *dir) {
|
||||||
dir_curpath_enter(cur);
|
dir_curpath_enter(cur);
|
||||||
memset(buf_dir, 0, offsetof(struct dir, name));
|
memset(buf_dir, 0, offsetof(struct dir, name));
|
||||||
memset(buf_ext, 0, sizeof(struct dir_ext));
|
memset(buf_ext, 0, sizeof(struct dir_ext));
|
||||||
|
buf_nlink = 0;
|
||||||
fail = dir_scan_item(cur);
|
fail = dir_scan_item(cur);
|
||||||
dir_curpath_leave();
|
dir_curpath_leave();
|
||||||
}
|
}
|
||||||
|
|
@ -350,6 +361,7 @@ static int process(void) {
|
||||||
|
|
||||||
memset(buf_dir, 0, offsetof(struct dir, name));
|
memset(buf_dir, 0, offsetof(struct dir, name));
|
||||||
memset(buf_ext, 0, sizeof(struct dir_ext));
|
memset(buf_ext, 0, sizeof(struct dir_ext));
|
||||||
|
buf_nlink = 0;
|
||||||
|
|
||||||
if((path = path_real(dir_curpath)) == NULL)
|
if((path = path_real(dir_curpath)) == NULL)
|
||||||
dir_seterr("Error obtaining full path: %s", strerror(errno));
|
dir_seterr("Error obtaining full path: %s", strerror(errno));
|
||||||
|
|
@ -376,13 +388,13 @@ static int process(void) {
|
||||||
buf_dir->flags |= FF_ERR;
|
buf_dir->flags |= FF_ERR;
|
||||||
stat_to_dir(&fs);
|
stat_to_dir(&fs);
|
||||||
|
|
||||||
if(dir_output.item(buf_dir, dir_curpath, buf_ext)) {
|
if(dir_output.item(buf_dir, dir_curpath, buf_ext, buf_nlink)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
fail = 1;
|
fail = 1;
|
||||||
}
|
}
|
||||||
if(!fail)
|
if(!fail)
|
||||||
fail = dir_walk(dir);
|
fail = dir_walk(dir);
|
||||||
if(!fail && dir_output.item(NULL, 0, NULL)) {
|
if(!fail && dir_output.item(NULL, 0, NULL, 0)) {
|
||||||
dir_seterr("Output error: %s", strerror(errno));
|
dir_seterr("Output error: %s", strerror(errno));
|
||||||
fail = 1;
|
fail = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
#include "strnatcmp.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -38,7 +39,8 @@ int64_t dirlist_maxs = 0,
|
||||||
int dirlist_sort_desc = 1,
|
int dirlist_sort_desc = 1,
|
||||||
dirlist_sort_col = DL_COL_SIZE,
|
dirlist_sort_col = DL_COL_SIZE,
|
||||||
dirlist_sort_df = 0,
|
dirlist_sort_df = 0,
|
||||||
dirlist_hidden = 0;
|
dirlist_hidden = 0,
|
||||||
|
dirlist_natsort = 1;
|
||||||
|
|
||||||
/* private state vars */
|
/* private state vars */
|
||||||
static struct dir *parent_alloc, *head, *head_real, *selected, *top = NULL;
|
static struct dir *parent_alloc, *head, *head_real, *selected, *top = NULL;
|
||||||
|
|
@ -79,7 +81,7 @@ static int dirlist_cmp(struct dir *x, struct dir *y) {
|
||||||
*
|
*
|
||||||
* Note that the method used below is supposed to be fast, not readable :-)
|
* Note that the method used below is supposed to be fast, not readable :-)
|
||||||
*/
|
*/
|
||||||
#define CMP_NAME strcmp(x->name, y->name)
|
#define CMP_NAME (dirlist_natsort ? strnatcmp(x->name, y->name) : strcmp(x->name, y->name))
|
||||||
#define CMP_SIZE (x->size > y->size ? 1 : (x->size == y->size ? 0 : -1))
|
#define CMP_SIZE (x->size > y->size ? 1 : (x->size == y->size ? 0 : -1))
|
||||||
#define CMP_ASIZE (x->asize > y->asize ? 1 : (x->asize == y->asize ? 0 : -1))
|
#define CMP_ASIZE (x->asize > y->asize ? 1 : (x->asize == y->asize ? 0 : -1))
|
||||||
#define CMP_ITEMS (x->items > y->items ? 1 : (x->items == y->items ? 0 : -1))
|
#define CMP_ITEMS (x->items > y->items ? 1 : (x->items == y->items ? 0 : -1))
|
||||||
|
|
@ -395,4 +397,3 @@ void dirlist_set_hidden(int hidden) {
|
||||||
dirlist_fixup();
|
dirlist_fixup();
|
||||||
dirlist_top(-5);
|
dirlist_top(-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -78,6 +78,8 @@ extern int dirlist_sort_desc, dirlist_sort_col, dirlist_sort_df;
|
||||||
/* set with dirlist_set_hidden() */
|
/* set with dirlist_set_hidden() */
|
||||||
extern int dirlist_hidden;
|
extern int dirlist_hidden;
|
||||||
|
|
||||||
|
extern int dirlist_natsort;
|
||||||
|
|
||||||
/* maximum size of an item in the opened dir */
|
/* maximum size of an item in the opened dir */
|
||||||
extern int64_t dirlist_maxs, dirlist_maxa;
|
extern int64_t dirlist_maxs, dirlist_maxa;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -46,8 +46,7 @@ void exclude_add(char *pat) {
|
||||||
n = &((*n)->next);
|
n = &((*n)->next);
|
||||||
|
|
||||||
*n = (struct exclude *) xcalloc(1, sizeof(struct exclude));
|
*n = (struct exclude *) xcalloc(1, sizeof(struct exclude));
|
||||||
(*n)->pattern = (char *) xmalloc(strlen(pat)+1);
|
(*n)->pattern = xstrdup(pat);
|
||||||
strcpy((*n)->pattern, pat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -89,7 +88,7 @@ int exclude_match(char *path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void exclude_clear() {
|
void exclude_clear(void) {
|
||||||
struct exclude *n, *l;
|
struct exclude *n, *l;
|
||||||
|
|
||||||
for(n=excludes; n!=NULL; n=l) {
|
for(n=excludes; n!=NULL; n=l) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
30
src/global.h
30
src/global.h
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -54,6 +54,12 @@
|
||||||
#define FF_KERNFS 0x200 /* excluded because it was a Linux pseudo filesystem */
|
#define FF_KERNFS 0x200 /* excluded because it was a Linux pseudo filesystem */
|
||||||
#define FF_FRMLNK 0x400 /* excluded because it was a firmlink */
|
#define FF_FRMLNK 0x400 /* excluded because it was a firmlink */
|
||||||
|
|
||||||
|
/* Ext mode flags (struct dir_ext -> flags) */
|
||||||
|
#define FFE_MTIME 0x01
|
||||||
|
#define FFE_UID 0x02
|
||||||
|
#define FFE_GID 0x04
|
||||||
|
#define FFE_MODE 0x08
|
||||||
|
|
||||||
/* Program states */
|
/* Program states */
|
||||||
#define ST_CALC 0
|
#define ST_CALC 0
|
||||||
#define ST_BROWSE 1
|
#define ST_BROWSE 1
|
||||||
|
|
@ -70,7 +76,7 @@ struct dir {
|
||||||
struct dir *parent, *next, *prev, *sub, *hlnk;
|
struct dir *parent, *next, *prev, *sub, *hlnk;
|
||||||
int items;
|
int items;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
char name[];
|
char name[FLEXIBLE_ARRAY_MEMBER];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A note on the ino and dev fields above: ino is usually represented as ino_t,
|
/* A note on the ino and dev fields above: ino is usually represented as ino_t,
|
||||||
|
|
@ -88,15 +94,18 @@ struct dir {
|
||||||
* macros to help manage this. */
|
* macros to help manage this. */
|
||||||
struct dir_ext {
|
struct dir_ext {
|
||||||
uint64_t mtime;
|
uint64_t mtime;
|
||||||
int uid, gid;
|
unsigned int uid, gid;
|
||||||
unsigned short mode;
|
unsigned short mode;
|
||||||
|
unsigned char flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* program state */
|
/* program state */
|
||||||
extern int pstate;
|
extern int pstate;
|
||||||
/* read-only flag, 1+ = disable deletion, 2+ = also disable shell */
|
/* enabled features */
|
||||||
extern int read_only;
|
extern int can_delete;
|
||||||
|
extern int can_shell;
|
||||||
|
extern int can_refresh;
|
||||||
/* minimum screen update interval when calculating, in ms */
|
/* minimum screen update interval when calculating, in ms */
|
||||||
extern long update_delay;
|
extern long update_delay;
|
||||||
/* filter directories with CACHEDIR.TAG */
|
/* filter directories with CACHEDIR.TAG */
|
||||||
|
|
@ -109,6 +118,17 @@ extern int extended_info;
|
||||||
extern int follow_symlinks;
|
extern int follow_symlinks;
|
||||||
/* flag whether we want to follow firmlinks */
|
/* flag whether we want to follow firmlinks */
|
||||||
extern int follow_firmlinks;
|
extern int follow_firmlinks;
|
||||||
|
/* display SI units */
|
||||||
|
extern int si;
|
||||||
|
/* show apparent sizes */
|
||||||
|
extern int show_as;
|
||||||
|
/* graph display setting */
|
||||||
|
extern int graph;
|
||||||
|
extern int graph_style;
|
||||||
|
/* column visibility */
|
||||||
|
extern int show_items;
|
||||||
|
extern int show_mtime;
|
||||||
|
|
||||||
|
|
||||||
/* handle input from keyboard and update display */
|
/* handle input from keyboard and update display */
|
||||||
int input_handle(int);
|
int input_handle(int);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -70,7 +70,7 @@ static const char *flags[FLAGS*2] = {
|
||||||
"F", "Excluded firmlink",
|
"F", "Excluded firmlink",
|
||||||
};
|
};
|
||||||
|
|
||||||
void help_draw() {
|
void help_draw(void) {
|
||||||
int i, line;
|
int i, line;
|
||||||
|
|
||||||
browse_draw();
|
browse_draw();
|
||||||
|
|
@ -156,7 +156,7 @@ void help_draw() {
|
||||||
ncaddstr(y+1, x+30, "Disk");
|
ncaddstr(y+1, x+30, "Disk");
|
||||||
ncaddstr(y+2, x+30, "Usage");
|
ncaddstr(y+2, x+30, "Usage");
|
||||||
ncprint( y+4, x+30, "%s", PACKAGE_VERSION);
|
ncprint( y+4, x+30, "%s", PACKAGE_VERSION);
|
||||||
ncaddstr( 9, 7, "Written by Yoran Heling <projects@yorhel.nl>");
|
ncaddstr( 9, 11, "Written by Yorhel <projects@yorhel.nl>");
|
||||||
ncaddstr(10, 16, "https://dev.yorhel.nl/ncdu/");
|
ncaddstr(10, 16, "https://dev.yorhel.nl/ncdu/");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +203,7 @@ int help_key(int ch) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void help_init() {
|
void help_init(void) {
|
||||||
page = 1;
|
page = 1;
|
||||||
start = 0;
|
start = 0;
|
||||||
pstate = ST_HELP;
|
pstate = ST_HELP;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
483
src/main.c
483
src/main.c
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -33,17 +33,23 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <yopt.h>
|
|
||||||
|
|
||||||
|
|
||||||
int pstate;
|
int pstate;
|
||||||
int read_only = 0;
|
int can_delete = -1;
|
||||||
|
int can_shell = -1;
|
||||||
|
int can_refresh = -1;
|
||||||
long update_delay = 100;
|
long update_delay = 100;
|
||||||
int cachedir_tags = 0;
|
int cachedir_tags = 0;
|
||||||
int extended_info = 0;
|
int extended_info = 0;
|
||||||
int follow_symlinks = 0;
|
int follow_symlinks = 0;
|
||||||
int follow_firmlinks = 1;
|
int follow_firmlinks = 1;
|
||||||
int confirm_quit = 0;
|
int confirm_quit = 0;
|
||||||
|
int si = 0;
|
||||||
|
int show_as = 0;
|
||||||
|
int graph = 1;
|
||||||
|
int graph_style = 0;
|
||||||
|
int show_items = 0;
|
||||||
|
int show_mtime = 0;
|
||||||
|
|
||||||
static int min_rows = 17, min_cols = 60;
|
static int min_rows = 17, min_cols = 60;
|
||||||
static int ncurses_init = 0;
|
static int ncurses_init = 0;
|
||||||
|
|
@ -113,150 +119,341 @@ int input_handle(int wait) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* parse command line */
|
/* This is a backport of the argument parser in the Zig version.
|
||||||
|
* Minor differences in that this implementation can modify argv in-place and has a slightly different API. */
|
||||||
|
struct argparser {
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
char *shortopt;
|
||||||
|
char *last;
|
||||||
|
char *last_arg;
|
||||||
|
char shortbuf[2];
|
||||||
|
char argsep;
|
||||||
|
char ignerror;
|
||||||
|
} argparser_state;
|
||||||
|
|
||||||
|
static char *argparser_pop(struct argparser *p) {
|
||||||
|
char *a;
|
||||||
|
if(p->argc == 0) return NULL;
|
||||||
|
a = *p->argv;
|
||||||
|
p->argv++;
|
||||||
|
p->argc--;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int argparser_shortopt(struct argparser *p, char *buf) {
|
||||||
|
p->shortbuf[0] = '-';
|
||||||
|
p->shortbuf[1] = *buf;
|
||||||
|
p->shortopt = buf[1] ? buf+1 : NULL;
|
||||||
|
p->last = p->shortbuf;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns -1 on error (only when ignerror), 0 when done, 1 if there's an option, 2 if there's a positional argument. */
|
||||||
|
static int argparser_next(struct argparser *p) {
|
||||||
|
if(p->last_arg) { if(p->ignerror) return -1; die("Option '%s' does not expect an argument.\n", p->last); }
|
||||||
|
if(p->shortopt) return argparser_shortopt(p, p->shortopt);
|
||||||
|
p->last = argparser_pop(p);
|
||||||
|
if(!p->last) return 0;
|
||||||
|
if(p->argsep || !*p->last || *p->last != '-') return 2;
|
||||||
|
if(!p->last[1]) { if(p->ignerror) return -1; die("Invalid option '-'.\n"); }
|
||||||
|
if(p->last[1] == '-' && !p->last[2]) { /* '--' argument separator */
|
||||||
|
p->argsep = 1;
|
||||||
|
return argparser_next(p);
|
||||||
|
}
|
||||||
|
if(p->last[1] == '-') { /* long option */
|
||||||
|
p->last_arg = strchr(p->last, '=');
|
||||||
|
if(p->last_arg) {
|
||||||
|
*p->last_arg = 0;
|
||||||
|
p->last_arg++;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* otherwise: short option */
|
||||||
|
return argparser_shortopt(p, p->last+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *argparser_arg(struct argparser *p) {
|
||||||
|
char *tmp;
|
||||||
|
if(p->shortopt) {
|
||||||
|
tmp = p->shortopt;
|
||||||
|
p->shortopt = NULL;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
if(p->last_arg) {
|
||||||
|
tmp = p->last_arg;
|
||||||
|
p->last_arg = NULL;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
tmp = argparser_pop(p);
|
||||||
|
if(!tmp) { if(p->ignerror) return NULL; die("Option '%s' requires an argument.\n", p->last); }
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPT(_s) (strcmp(argparser_state.last, (_s)) == 0)
|
||||||
|
#define ARG (argparser_arg(&argparser_state))
|
||||||
|
|
||||||
|
static int arg_option(int infile) {
|
||||||
|
char *arg, *tmp;
|
||||||
|
if(OPT("-q") || OPT("--slow-ui-updates")) update_delay = 2000;
|
||||||
|
else if(OPT("--fast-ui-updates")) update_delay = 100;
|
||||||
|
else if(OPT("-x") || OPT("--one-file-system")) dir_scan_smfs = 1;
|
||||||
|
else if(OPT("--cross-file-system")) dir_scan_smfs = 0;
|
||||||
|
else if(OPT("-e") || OPT("--extended")) extended_info = 1;
|
||||||
|
else if(OPT("--no-extended")) extended_info = 0;
|
||||||
|
else if(OPT("-r") && !can_delete) can_shell = 0;
|
||||||
|
else if(OPT("-r")) can_delete = 0;
|
||||||
|
else if(OPT("--enable-shell")) can_shell = 1;
|
||||||
|
else if(OPT("--disable-shell")) can_shell = 0;
|
||||||
|
else if(OPT("--enable-delete")) can_delete = 1;
|
||||||
|
else if(OPT("--disable-delete")) can_delete = 0;
|
||||||
|
else if(OPT("--enable-refresh")) can_refresh = 1;
|
||||||
|
else if(OPT("--disable-refresh")) can_refresh = 0;
|
||||||
|
else if(OPT("--show-hidden")) dirlist_hidden = 0;
|
||||||
|
else if(OPT("--hide-hidden")) dirlist_hidden = 1;
|
||||||
|
else if(OPT("--show-itemcount")) show_items = 1;
|
||||||
|
else if(OPT("--hide-itemcount")) show_items = 0;
|
||||||
|
else if(OPT("--show-mtime")) show_mtime = 1;
|
||||||
|
else if(OPT("--hide-mtime")) show_mtime = 0;
|
||||||
|
else if(OPT("--show-graph")) graph |= 1;
|
||||||
|
else if(OPT("--hide-graph")) graph &= 2;
|
||||||
|
else if(OPT("--show-percent")) graph |= 2;
|
||||||
|
else if(OPT("--hide-percent")) graph &= 1;
|
||||||
|
else if(OPT("--group-directories-first")) dirlist_sort_df = 1;
|
||||||
|
else if(OPT("--no-group-directories-first")) dirlist_sort_df = 0;
|
||||||
|
else if(OPT("--enable-natsort")) dirlist_natsort = 1;
|
||||||
|
else if(OPT("--disable-natsort")) dirlist_natsort = 0;
|
||||||
|
else if(OPT("--graph-style")) {
|
||||||
|
arg = ARG;
|
||||||
|
if (!arg) return 1;
|
||||||
|
else if (strcmp(arg, "hash") == 0) graph_style = 0;
|
||||||
|
else if (strcmp(arg, "half-block") == 0) graph_style = 1;
|
||||||
|
else if (strcmp(arg, "eighth-block") == 0 || strcmp(arg, "eigth-block") == 0) graph_style = 2;
|
||||||
|
else if (!argparser_state.ignerror) die("Unknown --graph-style option: %s.\n", arg);
|
||||||
|
} else if(OPT("--sort")) {
|
||||||
|
arg = ARG;
|
||||||
|
if (!arg) return 1;
|
||||||
|
tmp = strrchr(arg, '-');
|
||||||
|
if(tmp && (strcmp(tmp, "-asc") == 0 || strcmp(tmp, "-desc") == 0)) *tmp = 0;
|
||||||
|
|
||||||
|
if(strcmp(arg, "name") == 0) {
|
||||||
|
dirlist_sort_col = DL_COL_NAME;
|
||||||
|
dirlist_sort_desc = 0;
|
||||||
|
} else if(strcmp(arg, "disk-usage") == 0) {
|
||||||
|
dirlist_sort_col = DL_COL_SIZE;
|
||||||
|
dirlist_sort_desc = 1;
|
||||||
|
} else if(strcmp(arg, "apparent-size") == 0) {
|
||||||
|
dirlist_sort_col = DL_COL_ASIZE;
|
||||||
|
dirlist_sort_desc = 1;
|
||||||
|
} else if(strcmp(arg, "itemcount") == 0) {
|
||||||
|
dirlist_sort_col = DL_COL_ITEMS;
|
||||||
|
dirlist_sort_desc = 1;
|
||||||
|
} else if(strcmp(arg, "mtime") == 0) {
|
||||||
|
dirlist_sort_col = DL_COL_MTIME;
|
||||||
|
dirlist_sort_desc = 0;
|
||||||
|
} else if(argparser_state.ignerror) return 1;
|
||||||
|
else die("Invalid argument to --sort: '%s'.\n", arg);
|
||||||
|
|
||||||
|
if(tmp && !*tmp) dirlist_sort_desc = tmp[1] == 'd';
|
||||||
|
} else if(OPT("--apparent-size")) show_as = 1;
|
||||||
|
else if(OPT("--disk-usage")) show_as = 0;
|
||||||
|
else if(OPT("-0")) dir_ui = 0;
|
||||||
|
else if(OPT("-1")) dir_ui = 1;
|
||||||
|
else if(OPT("-2")) dir_ui = 2;
|
||||||
|
else if(OPT("--si")) si = 1;
|
||||||
|
else if(OPT("--no-si")) si = 0;
|
||||||
|
else if(OPT("-L") || OPT("--follow-symlinks")) follow_symlinks = 1;
|
||||||
|
else if(OPT("--no-follow-symlinks")) follow_symlinks = 0;
|
||||||
|
else if(OPT("--exclude")) {
|
||||||
|
arg = ARG;
|
||||||
|
if(!arg) return 1;
|
||||||
|
if(infile) arg = expanduser(arg);
|
||||||
|
exclude_add(arg);
|
||||||
|
if(infile) free(arg);
|
||||||
|
} else if(OPT("-X") || OPT("--exclude-from")) {
|
||||||
|
arg = ARG;
|
||||||
|
if(!arg) return 1;
|
||||||
|
if(infile) arg = expanduser(arg);
|
||||||
|
if(exclude_addfile(arg)) { if (argparser_state.ignerror) return 1; die("Can't open %s: %s\n", arg, strerror(errno)); }
|
||||||
|
if(infile) free(arg);
|
||||||
|
} else if(OPT("--exclude-caches")) cachedir_tags = 1;
|
||||||
|
else if(OPT("--include-caches")) cachedir_tags = 0;
|
||||||
|
else if(OPT("--exclude-kernfs")) exclude_kernfs = 1;
|
||||||
|
else if(OPT("--include-kernfs")) exclude_kernfs = 0;
|
||||||
|
else if(OPT("--follow-firmlinks")) follow_firmlinks = 1;
|
||||||
|
else if(OPT("--exclude-firmlinks")) follow_firmlinks = 0;
|
||||||
|
else if(OPT("--confirm-quit")) confirm_quit = 1;
|
||||||
|
else if(OPT("--no-confirm-quit")) confirm_quit = 0;
|
||||||
|
else if(OPT("--confirm-delete")) delete_confirm = 1;
|
||||||
|
else if(OPT("--no-confirm-delete")) delete_confirm = 0;
|
||||||
|
else if(OPT("--color")) {
|
||||||
|
arg = ARG;
|
||||||
|
if (!arg) return 1;
|
||||||
|
else if(strcmp(arg, "off") == 0) uic_theme = 0;
|
||||||
|
else if(strcmp(arg, "dark") == 0) uic_theme = 1;
|
||||||
|
else if(strcmp(arg, "dark-bg") == 0) uic_theme = 2;
|
||||||
|
else if (!argparser_state.ignerror) die("Unknown --color option: %s\n", arg);
|
||||||
|
} else return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arg_help(void) {
|
||||||
|
printf(
|
||||||
|
"ncdu <options> <directory>\n"
|
||||||
|
"\n"
|
||||||
|
"Mode selection:\n"
|
||||||
|
" -h, --help This help message\n"
|
||||||
|
" -v, -V, --version Print version\n"
|
||||||
|
" -f FILE Import scanned directory from FILE\n"
|
||||||
|
" -o FILE Export scanned directory to FILE in JSON format\n"
|
||||||
|
" -e, --extended Enable extended information\n"
|
||||||
|
" --ignore-config Don't load config files\n"
|
||||||
|
"\n"
|
||||||
|
"Scan options:\n"
|
||||||
|
" -x, --one-file-system Stay on the same filesystem\n"
|
||||||
|
" --exclude PATTERN Exclude files that match PATTERN\n"
|
||||||
|
" -X, --exclude-from FILE Exclude files that match any pattern in FILE\n"
|
||||||
|
" --exclude-caches Exclude directories containing CACHEDIR.TAG\n"
|
||||||
|
" -L, --follow-symlinks Follow symbolic links (excluding directories)\n"
|
||||||
|
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
|
||||||
|
" --exclude-kernfs Exclude Linux pseudo filesystems (procfs,sysfs,cgroup,...)\n"
|
||||||
|
#endif
|
||||||
|
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
||||||
|
" --exclude-firmlinks Exclude firmlinks on macOS\n"
|
||||||
|
#endif
|
||||||
|
"\n"
|
||||||
|
"Interface options:\n"
|
||||||
|
" -0, -1, -2 UI to use when scanning (0=none,2=full ncurses)\n"
|
||||||
|
" -q, --slow-ui-updates \"Quiet\" mode, refresh interval 2 seconds\n"
|
||||||
|
" --enable-shell Enable/disable shell spawning feature\n"
|
||||||
|
" --enable-delete Enable/disable file deletion feature\n"
|
||||||
|
" --enable-refresh Enable/disable directory refresh feature\n"
|
||||||
|
" -r Read only (--disable-delete)\n"
|
||||||
|
" -rr Read only++ (--disable-delete & --disable-shell)\n"
|
||||||
|
" --si Use base 10 (SI) prefixes instead of base 2\n"
|
||||||
|
" --apparent-size Show apparent size instead of disk usage by default\n"
|
||||||
|
" --hide-hidden Hide \"hidden\" or excluded files by default\n"
|
||||||
|
" --show-itemcount Show item count column by default\n"
|
||||||
|
" --show-mtime Show mtime column by default (requires `-e`)\n"
|
||||||
|
" --show-graph Show graph column by default\n"
|
||||||
|
" --show-percent Show percent column by default\n"
|
||||||
|
" --graph-style STYLE hash / half-block / eighth-block\n"
|
||||||
|
" --sort COLUMN-(asc/desc) disk-usage / name / apparent-size / itemcount / mtime\n"
|
||||||
|
" --enable-natsort Use natural order when sorting by name\n"
|
||||||
|
" --group-directories-first Sort directories before files\n"
|
||||||
|
" --confirm-quit Ask confirmation before quitting ncdu\n"
|
||||||
|
" --no-confirm-delete Don't ask confirmation before deletion\n"
|
||||||
|
" --color SCHEME off / dark / dark-bg\n"
|
||||||
|
"\n"
|
||||||
|
"Refer to `man ncdu` for more information.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void config_read(const char *fn) {
|
||||||
|
FILE *f;
|
||||||
|
char buf[1024], *line, *tmp, *args[3];
|
||||||
|
int r, len;
|
||||||
|
|
||||||
|
if((f = fopen(fn, "r")) == NULL) {
|
||||||
|
if(errno == ENOENT || errno == ENOTDIR) return;
|
||||||
|
die("Error opening %s: %s.\nRun with --ignore-config to skip reading config files.\n", fn, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
while(fgets(buf, 1024, f) != NULL) {
|
||||||
|
line = buf;
|
||||||
|
while(*line == ' ' || *line == '\t') line++;
|
||||||
|
len = strlen(line);
|
||||||
|
while(len > 0 && (line[len-1] == ' ' || line[len-1] == '\t' || line[len-1] == '\r' || line[len-1] == '\n')) len -= 1;
|
||||||
|
line[len] = 0;
|
||||||
|
if(len == 0 || *line == '#') continue;
|
||||||
|
|
||||||
|
memset(&argparser_state, 0, sizeof(struct argparser));
|
||||||
|
argparser_state.argv = args;
|
||||||
|
|
||||||
|
if (*line == '@') {
|
||||||
|
argparser_state.ignerror = 1;
|
||||||
|
line++;
|
||||||
|
if (!*line || *line == '#') continue;
|
||||||
|
}
|
||||||
|
args[argparser_state.argc++] = line;
|
||||||
|
|
||||||
|
for(tmp=line; *tmp && *tmp != ' ' && *tmp != '\t'; tmp++);
|
||||||
|
while(*tmp && (*tmp == ' ' || *tmp == '\t')) {
|
||||||
|
*tmp = 0;
|
||||||
|
tmp++;
|
||||||
|
}
|
||||||
|
if(*tmp) args[argparser_state.argc++] = tmp;
|
||||||
|
args[argparser_state.argc] = NULL;
|
||||||
|
|
||||||
|
while((r = argparser_next(&argparser_state)) > 0) {
|
||||||
|
if(r == 2 || !arg_option(1)) {
|
||||||
|
if (argparser_state.ignerror) break;
|
||||||
|
die("Unknown option in config file '%s': %s.\nRun with --ignore-config to skip reading config files.\n", fn, argparser_state.last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ferror(f))
|
||||||
|
die("Error reading from %s: %s\nRun with --ignore-config to skip reading config files.\n", fn, strerror(errno));
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void config_load(int argc, char **argv) {
|
||||||
|
char *env, buf[1024];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
for(r=0; r<argc; r++)
|
||||||
|
if(strcmp(argv[r], "--ignore-config") == 0) return;
|
||||||
|
|
||||||
|
config_read("/etc/ncdu.conf");
|
||||||
|
|
||||||
|
if((env = getenv("XDG_CONFIG_HOME")) != NULL) {
|
||||||
|
r = snprintf(buf, 1024, "%s/ncdu/config", env);
|
||||||
|
if(r > 0 && r < 1024) config_read(buf);
|
||||||
|
} else if((env = getenv("HOME")) != NULL) {
|
||||||
|
r = snprintf(buf, 1024, "%s/.config/ncdu/config", env);
|
||||||
|
if(r > 0 && r < 1024) config_read(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void argv_parse(int argc, char **argv) {
|
static void argv_parse(int argc, char **argv) {
|
||||||
yopt_t yopt;
|
int r;
|
||||||
int v;
|
|
||||||
char *val;
|
|
||||||
char *export = NULL;
|
char *export = NULL;
|
||||||
char *import = NULL;
|
char *import = NULL;
|
||||||
char *dir = NULL;
|
char *dir = NULL;
|
||||||
|
|
||||||
static yopt_opt_t opts[] = {
|
memset(&argparser_state, 0, sizeof(struct argparser));
|
||||||
{ 'h', 0, "-h,-?,--help" },
|
argparser_state.argv = argv;
|
||||||
{ 'q', 0, "-q" },
|
argparser_state.argc = argc;
|
||||||
{ 'v', 0, "-v,-V,--version" },
|
argparser_next(&argparser_state); /* skip program name */
|
||||||
{ 'x', 0, "-x" },
|
|
||||||
{ 'e', 0, "-e" },
|
|
||||||
{ 'r', 0, "-r" },
|
|
||||||
{ 'o', 1, "-o" },
|
|
||||||
{ 'f', 1, "-f" },
|
|
||||||
{ '0', 0, "-0" },
|
|
||||||
{ '1', 0, "-1" },
|
|
||||||
{ '2', 0, "-2" },
|
|
||||||
{ 1, 1, "--exclude" },
|
|
||||||
{ 'X', 1, "-X,--exclude-from" },
|
|
||||||
{ 'L', 0, "-L,--follow-symlinks" },
|
|
||||||
{ 'C', 0, "--exclude-caches" },
|
|
||||||
{ 2, 0, "--exclude-kernfs" },
|
|
||||||
{ 3, 0, "--follow-firmlinks" }, /* undocumented, this behavior is the current default */
|
|
||||||
{ 4, 0, "--exclude-firmlinks" },
|
|
||||||
{ 's', 0, "--si" },
|
|
||||||
{ 'Q', 0, "--confirm-quit" },
|
|
||||||
{ 'c', 1, "--color" },
|
|
||||||
{0,0,NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
dir_ui = -1;
|
while((r = argparser_next(&argparser_state)) > 0) {
|
||||||
si = 0;
|
if(r == 2) dir = argparser_state.last;
|
||||||
|
else if(OPT("-v") || OPT("-V") || OPT("--version")) {
|
||||||
yopt_init(&yopt, argc, argv, opts);
|
|
||||||
while((v = yopt_next(&yopt, &val)) != -1) {
|
|
||||||
switch(v) {
|
|
||||||
case 0 : dir = val; break;
|
|
||||||
case 'h':
|
|
||||||
printf("ncdu <options> <directory>\n\n");
|
|
||||||
printf(" -h,--help This help message\n");
|
|
||||||
printf(" -q Quiet mode, refresh interval 2 seconds\n");
|
|
||||||
printf(" -v,-V,--version Print version\n");
|
|
||||||
printf(" -x Same filesystem\n");
|
|
||||||
printf(" -e Enable extended information\n");
|
|
||||||
printf(" -r Read only\n");
|
|
||||||
printf(" -o FILE Export scanned directory to FILE\n");
|
|
||||||
printf(" -f FILE Import scanned directory from FILE\n");
|
|
||||||
printf(" -0,-1,-2 UI to use when scanning (0=none,2=full ncurses)\n");
|
|
||||||
printf(" --si Use base 10 (SI) prefixes instead of base 2\n");
|
|
||||||
printf(" --exclude PATTERN Exclude files that match PATTERN\n");
|
|
||||||
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
|
|
||||||
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
|
||||||
printf(" --exclude-firmlinks Exclude firmlinks on macOS\n");
|
|
||||||
#endif
|
|
||||||
printf(" --confirm-quit Confirm quitting ncdu\n");
|
|
||||||
printf(" --color SCHEME Set color scheme (off/dark)\n");
|
|
||||||
exit(0);
|
|
||||||
case 'q': update_delay = 2000; break;
|
|
||||||
case 'v':
|
|
||||||
printf("ncdu %s\n", PACKAGE_VERSION);
|
printf("ncdu %s\n", PACKAGE_VERSION);
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'x': dir_scan_smfs = 1; break;
|
} else if(OPT("-h") || OPT("-?") || OPT("--help")) arg_help();
|
||||||
case 'e': extended_info = 1; break;
|
else if(OPT("-o")) export = ARG;
|
||||||
case 'r': read_only++; break;
|
else if(OPT("-f")) import = ARG;
|
||||||
case 's': si = 1; break;
|
else if(OPT("--ignore-config")) {}
|
||||||
case 'o': export = val; break;
|
else if(!arg_option(0)) die("Unknown option '%s'.\n", argparser_state.last);
|
||||||
case 'f': import = val; break;
|
|
||||||
case '0': dir_ui = 0; break;
|
|
||||||
case '1': dir_ui = 1; break;
|
|
||||||
case '2': dir_ui = 2; break;
|
|
||||||
case 'Q': confirm_quit = 1; break;
|
|
||||||
case 1 : exclude_add(val); break; /* --exclude */
|
|
||||||
case 'X':
|
|
||||||
if(exclude_addfile(val)) {
|
|
||||||
fprintf(stderr, "Can't open %s: %s\n", val, strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 'L': follow_symlinks = 1; break;
|
|
||||||
case 'C':
|
|
||||||
cachedir_tags = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2 : /* --exclude-kernfs */
|
#if !(HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS)
|
||||||
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
|
if(exclude_kernfs) die("The --exclude-kernfs flag is currently only supported on Linux.\n");
|
||||||
exclude_kernfs = 1; break;
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "This feature is not supported on your platform\n");
|
|
||||||
exit(1);
|
|
||||||
#endif
|
#endif
|
||||||
case 3 : /* --follow-firmlinks */
|
|
||||||
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
|
||||||
follow_firmlinks = 1; break;
|
|
||||||
#else
|
|
||||||
fprintf(stderr, "This feature is not supported on your platform\n");
|
|
||||||
exit(1);
|
|
||||||
#endif
|
|
||||||
case 4 : /* --exclude-firmlinks */
|
|
||||||
#if HAVE_SYS_ATTR_H && HAVE_GETATTRLIST && HAVE_DECL_ATTR_CMNEXT_NOFIRMLINKPATH
|
|
||||||
follow_firmlinks = 0; 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; }
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "Unknown --color option: %s\n", val);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case -2:
|
|
||||||
fprintf(stderr, "ncdu: %s.\n", val);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(export) {
|
if(export) {
|
||||||
if(dir_export_init(export)) {
|
if(dir_export_init(export)) die("Can't open %s: %s\n", export, strerror(errno));
|
||||||
fprintf(stderr, "Can't open %s: %s\n", export, strerror(errno));
|
if(strcmp(export, "-") == 0) ncurses_tty = 1;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if(strcmp(export, "-") == 0)
|
|
||||||
ncurses_tty = 1;
|
|
||||||
} else
|
} else
|
||||||
dir_mem_init(NULL);
|
dir_mem_init(NULL);
|
||||||
|
|
||||||
if(import) {
|
if(import) {
|
||||||
if(dir_import_init(import)) {
|
if(dir_import_init(import)) die("Can't open %s: %s\n", import, strerror(errno));
|
||||||
fprintf(stderr, "Can't open %s: %s\n", import, strerror(errno));
|
if(strcmp(import, "-") == 0) ncurses_tty = 1;
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
if(strcmp(import, "-") == 0)
|
|
||||||
ncurses_tty = 1;
|
|
||||||
} else
|
} else
|
||||||
dir_scan_init(dir ? dir : ".");
|
dir_scan_init(dir ? dir : ".");
|
||||||
|
|
||||||
|
|
@ -264,6 +461,10 @@ static void argv_parse(int argc, char **argv) {
|
||||||
* feedback when exporting to stdout. */
|
* feedback when exporting to stdout. */
|
||||||
if(dir_ui == -1)
|
if(dir_ui == -1)
|
||||||
dir_ui = export && strcmp(export, "-") == 0 ? 0 : export ? 1 : 2;
|
dir_ui = export && strcmp(export, "-") == 0 ? 0 : export ? 1 : 2;
|
||||||
|
|
||||||
|
if(can_delete == -1) can_delete = import ? 0 : 1;
|
||||||
|
if(can_shell == -1) can_shell = import ? 0 : 1;
|
||||||
|
if(can_refresh == -1) can_refresh = import ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -279,10 +480,7 @@ static void init_nc(void) {
|
||||||
|
|
||||||
if(ncurses_tty) {
|
if(ncurses_tty) {
|
||||||
tty = fopen("/dev/tty", "r+");
|
tty = fopen("/dev/tty", "r+");
|
||||||
if(!tty) {
|
if(!tty) die("Error opening /dev/tty: %s\n", strerror(errno));
|
||||||
fprintf(stderr, "Error opening /dev/tty: %s\n", strerror(errno));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
term = newterm(NULL, tty, tty);
|
term = newterm(NULL, tty, tty);
|
||||||
if(term)
|
if(term)
|
||||||
set_term(term);
|
set_term(term);
|
||||||
|
|
@ -291,29 +489,24 @@ static void init_nc(void) {
|
||||||
/* Make sure the user doesn't accidentally pipe in data to ncdu's standard
|
/* Make sure the user doesn't accidentally pipe in data to ncdu's standard
|
||||||
* input without using "-f -". An annoying input sequence could result in
|
* input without using "-f -". An annoying input sequence could result in
|
||||||
* the deletion of your files, which we want to prevent at all costs. */
|
* the deletion of your files, which we want to prevent at all costs. */
|
||||||
if(!isatty(0)) {
|
if(!isatty(0)) die("Standard input is not a TTY. Did you mean to import a file using '-f -'?\n");
|
||||||
fprintf(stderr, "Standard input is not a TTY. Did you mean to import a file using '-f -'?\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
ok = !!initscr();
|
ok = !!initscr();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ok) {
|
if(!ok) die("Error while initializing ncurses.\n");
|
||||||
fprintf(stderr, "Error while initializing ncurses.\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
uic_init();
|
uic_init();
|
||||||
cbreak();
|
cbreak();
|
||||||
noecho();
|
noecho();
|
||||||
curs_set(0);
|
curs_set(0);
|
||||||
keypad(stdscr, TRUE);
|
keypad(stdscr, TRUE);
|
||||||
|
bkgd(COLOR_PAIR(UIC_DEFAULT+1));
|
||||||
if(ncresize(min_rows, min_cols))
|
if(ncresize(min_rows, min_cols))
|
||||||
min_rows = min_cols = 0;
|
min_rows = min_cols = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void close_nc() {
|
void close_nc(void) {
|
||||||
if(ncurses_init) {
|
if(ncurses_init) {
|
||||||
erase();
|
erase();
|
||||||
refresh();
|
refresh();
|
||||||
|
|
@ -322,9 +515,9 @@ void close_nc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* main program */
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
read_locale();
|
read_locale();
|
||||||
|
config_load(argc, argv);
|
||||||
argv_parse(argc, argv);
|
argv_parse(argc, argv);
|
||||||
|
|
||||||
if(dir_ui == 2)
|
if(dir_ui == 2)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2015-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -38,13 +38,13 @@ int quit_key(int ch) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void quit_draw() {
|
void quit_draw(void) {
|
||||||
browse_draw();
|
browse_draw();
|
||||||
|
|
||||||
nccreate(4,30, "ncdu confirm quit");
|
nccreate(4,30, "ncdu confirm quit");
|
||||||
ncaddstr(2,2, "Really quit? (y/N)");
|
ncaddstr(2,2, "Really quit? (y/N)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void quit_init() {
|
void quit_init(void) {
|
||||||
pstate = ST_QUIT;
|
pstate = ST_QUIT;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2015-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
|
||||||
24
src/shell.c
24
src/shell.c
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
Shell support: Copyright (c) 2014 Thomas Jarosch
|
Shell support: Copyright (c) 2014 Thomas Jarosch
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
|
@ -34,7 +34,24 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
void shell_draw() {
|
static void set_level(void) {
|
||||||
|
static int done = 0;
|
||||||
|
const char *lvl;
|
||||||
|
char nlvl[2];
|
||||||
|
if(done)
|
||||||
|
return;
|
||||||
|
lvl = getenv("NCDU_LEVEL");
|
||||||
|
/* too lazy to count beyond 9 */
|
||||||
|
if(lvl && *lvl >= '1' && *lvl < '9' && lvl[1] == 0) {
|
||||||
|
nlvl[0] = 1 + *lvl;
|
||||||
|
nlvl[1] = 0;
|
||||||
|
setenv("NCDU_LEVEL", nlvl, 1);
|
||||||
|
} else
|
||||||
|
setenv("NCDU_LEVEL", "1", 1);
|
||||||
|
done++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void shell_draw(void) {
|
||||||
const char *full_path;
|
const char *full_path;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
|
@ -59,6 +76,7 @@ void shell_draw() {
|
||||||
shell = DEFAULT_SHELL;
|
shell = DEFAULT_SHELL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_level();
|
||||||
res = system(shell);
|
res = system(shell);
|
||||||
|
|
||||||
/* resume ncurses mode */
|
/* resume ncurses mode */
|
||||||
|
|
@ -77,6 +95,6 @@ void shell_draw() {
|
||||||
pstate = ST_BROWSE;
|
pstate = ST_BROWSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void shell_init() {
|
void shell_init(void) {
|
||||||
pstate = ST_SHELL;
|
pstate = ST_SHELL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
Shell support: Copyright (c) 2014 Thomas Jarosch
|
Shell support: Copyright (c) 2014 Thomas Jarosch
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
|
|
||||||
93
src/util.c
93
src/util.c
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -30,17 +30,27 @@
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
#ifdef HAVE_LOCALE_H
|
#ifdef HAVE_LOCALE_H
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int uic_theme;
|
int uic_theme = 0;
|
||||||
int winrows, wincols;
|
int winrows, wincols;
|
||||||
int subwinr, subwinc;
|
int subwinr, subwinc;
|
||||||
int si;
|
|
||||||
static char thou_sep;
|
static char thou_sep;
|
||||||
|
|
||||||
|
|
||||||
|
void die(const char *fmt, ...) {
|
||||||
|
va_list arg;
|
||||||
|
va_start(arg, fmt);
|
||||||
|
vfprintf(stderr, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char *cropstr(const char *from, int s) {
|
char *cropstr(const char *from, int s) {
|
||||||
static char dat[4096];
|
static char dat[4096];
|
||||||
int i, j, o = strlen(from);
|
int i, j, o = strlen(from);
|
||||||
|
|
@ -66,7 +76,7 @@ float formatsize(int64_t from, const char **unit) {
|
||||||
float r = from;
|
float r = from;
|
||||||
if (si) {
|
if (si) {
|
||||||
if(r < 1000.0f) { *unit = " B"; }
|
if(r < 1000.0f) { *unit = " B"; }
|
||||||
else if(r < 1e6f) { *unit = "KB"; r/=1e3f; }
|
else if(r < 1e6f) { *unit = "kB"; r/=1e3f; }
|
||||||
else if(r < 1e9f) { *unit = "MB"; r/=1e6f; }
|
else if(r < 1e9f) { *unit = "MB"; r/=1e6f; }
|
||||||
else if(r < 1e12f){ *unit = "GB"; r/=1e9f; }
|
else if(r < 1e12f){ *unit = "GB"; r/=1e9f; }
|
||||||
else if(r < 1e15f){ *unit = "TB"; r/=1e12f; }
|
else if(r < 1e15f){ *unit = "TB"; r/=1e12f; }
|
||||||
|
|
@ -134,23 +144,26 @@ char *fmtmode(unsigned short mode) {
|
||||||
: ft == S_IFBLK ? 'b' : '?';
|
: ft == S_IFBLK ? 'b' : '?';
|
||||||
buf[1] = mode & 0400 ? 'r' : '-';
|
buf[1] = mode & 0400 ? 'r' : '-';
|
||||||
buf[2] = mode & 0200 ? 'w' : '-';
|
buf[2] = mode & 0200 ? 'w' : '-';
|
||||||
buf[3] = mode & 0100 ? 'x' : '-';
|
buf[3] = mode &04000 ? 's' : mode & 0100 ? 'x' : '-';
|
||||||
buf[4] = mode & 0040 ? 'r' : '-';
|
buf[4] = mode & 0040 ? 'r' : '-';
|
||||||
buf[5] = mode & 0020 ? 'w' : '-';
|
buf[5] = mode & 0020 ? 'w' : '-';
|
||||||
buf[6] = mode & 0010 ? 'x' : '-';
|
buf[6] = mode &02000 ? 's' : mode & 0010 ? 'x' : '-';
|
||||||
buf[7] = mode & 0004 ? 'r' : '-';
|
buf[7] = mode & 0004 ? 'r' : '-';
|
||||||
buf[8] = mode & 0002 ? 'w' : '-';
|
buf[8] = mode & 0002 ? 'w' : '-';
|
||||||
buf[9] = mode & 0001 ? 'x' : '-';
|
buf[9] = mode &01000 ? (S_ISDIR(mode) ? 't' : 'T') : mode & 0001 ? 'x' : '-';
|
||||||
buf[10] = 0;
|
buf[10] = 0;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void read_locale() {
|
void read_locale(void) {
|
||||||
|
#ifdef HAVE_LOCALE_H
|
||||||
|
char *locale_thou_sep;
|
||||||
|
#endif
|
||||||
thou_sep = '.';
|
thou_sep = '.';
|
||||||
#ifdef HAVE_LOCALE_H
|
#ifdef HAVE_LOCALE_H
|
||||||
setlocale(LC_ALL, "");
|
setlocale(LC_ALL, "");
|
||||||
char *locale_thou_sep = localeconv()->thousands_sep;
|
locale_thou_sep = localeconv()->thousands_sep;
|
||||||
if(locale_thou_sep && 1 == strlen(locale_thou_sep))
|
if(locale_thou_sep && 1 == strlen(locale_thou_sep))
|
||||||
thou_sep = locale_thou_sep[0];
|
thou_sep = locale_thou_sep[0];
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -250,21 +263,27 @@ static const struct {
|
||||||
short fg, bg;
|
short fg, bg;
|
||||||
int attr;
|
int attr;
|
||||||
} color_defs[] = {
|
} color_defs[] = {
|
||||||
#define C(name, off_fg, off_bg, off_a, dark_fg, dark_bg, dark_a) \
|
#define COLOR__ -1
|
||||||
{off_fg, off_bg, off_a}, \
|
#define B A_BOLD
|
||||||
{dark_fg, dark_bg, dark_a},
|
#define R A_REVERSE
|
||||||
|
#define C(name, off_fg, off_bg, off_a, dark_fg, dark_bg, dark_a, darkbg_fg, darkbg_bg, darkbg_a) \
|
||||||
|
{COLOR_##off_fg, COLOR_##off_bg, off_a}, \
|
||||||
|
{COLOR_##dark_fg, COLOR_##dark_bg, dark_a}, \
|
||||||
|
{COLOR_##darkbg_fg, COLOR_##darkbg_bg, darkbg_a},
|
||||||
UI_COLORS
|
UI_COLORS
|
||||||
|
#undef B
|
||||||
|
#undef R
|
||||||
#undef C
|
#undef C
|
||||||
{0,0,0}
|
{0,0,0}
|
||||||
};
|
};
|
||||||
|
|
||||||
void uic_init() {
|
void uic_init(void) {
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
start_color();
|
start_color();
|
||||||
use_default_colors();
|
use_default_colors();
|
||||||
for(i=0; i<sizeof(colors)/sizeof(*colors)-1; i++) {
|
for(i=0; i<sizeof(colors)/sizeof(*colors)-1; i++) {
|
||||||
j = i*2 + uic_theme;
|
j = i*3 + uic_theme;
|
||||||
init_pair(i+1, color_defs[j].fg, color_defs[j].bg);
|
init_pair(i+1, color_defs[j].fg, color_defs[j].bg);
|
||||||
colors[i] = color_defs[j].attr | COLOR_PAIR(i+1);
|
colors[i] = color_defs[j].attr | COLOR_PAIR(i+1);
|
||||||
}
|
}
|
||||||
|
|
@ -424,7 +443,7 @@ void addparentstats(struct dir *d, int64_t size, int64_t asize, uint64_t mtime,
|
||||||
char buf[128];\
|
char buf[128];\
|
||||||
while((ptr = f) == NULL) {\
|
while((ptr = f) == NULL) {\
|
||||||
close_nc();\
|
close_nc();\
|
||||||
write(2, oom_msg, sizeof(oom_msg));\
|
write(2, oom_msg, sizeof(oom_msg)-1);\
|
||||||
read(0, buf, sizeof(buf));\
|
read(0, buf, sizeof(buf));\
|
||||||
}\
|
}\
|
||||||
return ptr;
|
return ptr;
|
||||||
|
|
@ -432,3 +451,47 @@ void addparentstats(struct dir *d, int64_t size, int64_t asize, uint64_t mtime,
|
||||||
void *xmalloc(size_t size) { wrap_oom(malloc(size)) }
|
void *xmalloc(size_t size) { wrap_oom(malloc(size)) }
|
||||||
void *xcalloc(size_t n, size_t size) { wrap_oom(calloc(n, size)) }
|
void *xcalloc(size_t n, size_t size) { wrap_oom(calloc(n, size)) }
|
||||||
void *xrealloc(void *mem, size_t size) { wrap_oom(realloc(mem, size)) }
|
void *xrealloc(void *mem, size_t size) { wrap_oom(realloc(mem, size)) }
|
||||||
|
|
||||||
|
char *xstrdup(const char *str) {
|
||||||
|
char *r = xmalloc(strlen(str)+1);
|
||||||
|
strcpy(r, str);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Expands '~' and '~user' */
|
||||||
|
char *expanduser(const char *path) {
|
||||||
|
size_t len, size;
|
||||||
|
struct passwd *pwd;
|
||||||
|
char *home = NULL, *tmp;
|
||||||
|
|
||||||
|
if(path[0] != '~') return xstrdup(path);
|
||||||
|
len = strcspn(path+1, "/");
|
||||||
|
|
||||||
|
if(len == 0) {
|
||||||
|
home = getenv("HOME");
|
||||||
|
if(!home) {
|
||||||
|
pwd = getpwuid(getuid());
|
||||||
|
if(pwd) home = pwd->pw_dir;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmp = xmalloc(len+1);
|
||||||
|
memcpy(tmp, path+1, len);
|
||||||
|
tmp[len] = 0;
|
||||||
|
pwd = getpwnam(tmp);
|
||||||
|
free(tmp);
|
||||||
|
if(pwd) home = pwd->pw_dir;
|
||||||
|
}
|
||||||
|
if(!home) return xstrdup(path);
|
||||||
|
|
||||||
|
size = strlen(home);
|
||||||
|
while(size > 0 && home[size-1] == '/') size--;
|
||||||
|
home[size] = 0;
|
||||||
|
|
||||||
|
if(size == 0 && path[len+1] == 0) return xstrdup("/");
|
||||||
|
|
||||||
|
size += strlen(path) - len;
|
||||||
|
tmp = xmalloc(size);
|
||||||
|
snprintf(tmp, size, "%s%s", home, path+1+len);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
|
||||||
51
src/util.h
51
src/util.h
|
|
@ -1,6 +1,6 @@
|
||||||
/* ncdu - NCurses Disk Usage
|
/* ncdu - NCurses Disk Usage
|
||||||
|
|
||||||
Copyright (c) 2007-2020 Yoran Heling
|
Copyright (c) Yorhel
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|
@ -30,25 +30,27 @@
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
|
||||||
|
void die(const char *, ...);
|
||||||
|
|
||||||
|
|
||||||
/* UI colors: (foreground, background, attrs)
|
/* UI colors: (foreground, background, attrs)
|
||||||
* NAME OFF DARK
|
* NAME OFF DARK DARK-BG */
|
||||||
*/
|
|
||||||
#define UI_COLORS \
|
#define UI_COLORS \
|
||||||
C(DEFAULT, -1,-1,0 , -1, -1, 0 )\
|
C(DEFAULT, _,_,0 , _, _, 0, WHITE, BLACK,0)\
|
||||||
C(BOX_TITLE, -1,-1,A_BOLD , COLOR_BLUE, -1, A_BOLD)\
|
C(BOX_TITLE, _,_,B , BLUE, _, B, BLUE, BLACK,B)\
|
||||||
C(HD, -1,-1,A_REVERSE , COLOR_BLACK, COLOR_CYAN, 0 ) /* header & footer */\
|
C(HD, _,_,R , BLACK, CYAN, 0, BLACK, CYAN, 0) /* header & footer */\
|
||||||
C(SEL, -1,-1,A_REVERSE , COLOR_WHITE, COLOR_GREEN,A_BOLD)\
|
C(SEL, _,_,R , WHITE, GREEN,B, WHITE, GREEN,B)\
|
||||||
C(NUM, -1,-1,0 , COLOR_YELLOW, -1, A_BOLD)\
|
C(NUM, _,_,0 , YELLOW, _, B, YELLOW, BLACK,B)\
|
||||||
C(NUM_HD, -1,-1,A_REVERSE , COLOR_YELLOW, COLOR_CYAN, A_BOLD)\
|
C(NUM_HD, _,_,R , YELLOW, CYAN, B, YELLOW, CYAN, B)\
|
||||||
C(NUM_SEL, -1,-1,A_REVERSE , COLOR_YELLOW, COLOR_GREEN,A_BOLD)\
|
C(NUM_SEL, _,_,R , YELLOW, GREEN,B, YELLOW, GREEN,B)\
|
||||||
C(KEY, -1,-1,A_BOLD , COLOR_YELLOW, -1, A_BOLD)\
|
C(KEY, _,_,B , YELLOW, _, B, YELLOW, BLACK,B)\
|
||||||
C(KEY_HD, -1,-1,A_BOLD|A_REVERSE, COLOR_YELLOW, COLOR_CYAN, A_BOLD)\
|
C(KEY_HD, _,_,B|R, YELLOW, CYAN, B, YELLOW, CYAN, B)\
|
||||||
C(DIR, -1,-1,0 , COLOR_BLUE, -1, A_BOLD)\
|
C(DIR, _,_,0 , BLUE, _, B, BLUE, BLACK,B)\
|
||||||
C(DIR_SEL, -1,-1,A_REVERSE , COLOR_BLUE, COLOR_GREEN,A_BOLD)\
|
C(DIR_SEL, _,_,R , BLUE, GREEN,B, BLUE, GREEN,B)\
|
||||||
C(FLAG, -1,-1,0 , COLOR_RED, -1, 0 )\
|
C(FLAG, _,_,0 , RED, _, 0, RED, BLACK,0)\
|
||||||
C(FLAG_SEL, -1,-1,A_REVERSE , COLOR_RED, COLOR_GREEN,0 )\
|
C(FLAG_SEL, _,_,R , RED, GREEN,0, RED, GREEN,0)\
|
||||||
C(GRAPH, -1,-1,0 , COLOR_MAGENTA,-1, 0 )\
|
C(GRAPH, _,_,0 , MAGENTA,_, 0, MAGENTA,BLACK,0)\
|
||||||
C(GRAPH_SEL, -1,-1,A_REVERSE , COLOR_MAGENTA,COLOR_GREEN,0 )
|
C(GRAPH_SEL, _,_,R , MAGENTA,GREEN,0, MAGENTA,GREEN,0)
|
||||||
|
|
||||||
enum ui_coltype {
|
enum ui_coltype {
|
||||||
#define C(name, ...) UIC_##name,
|
#define C(name, ...) UIC_##name,
|
||||||
|
|
@ -74,17 +76,12 @@ extern int subwinr, subwinc;
|
||||||
extern int si;
|
extern int si;
|
||||||
|
|
||||||
|
|
||||||
/* Macros/functions for managing struct dir and struct dir_ext */
|
/* Macros for managing struct dir and struct dir_ext */
|
||||||
|
|
||||||
#define dir_memsize(n) (offsetof(struct dir, name)+1+strlen(n))
|
#define dir_memsize(n) (offsetof(struct dir, name)+1+strlen(n))
|
||||||
#define dir_ext_offset(n) ((dir_memsize(n) + 7) & ~7)
|
#define dir_ext_offset(n) ((dir_memsize(n) + 7) & ~7)
|
||||||
#define dir_ext_memsize(n) (dir_ext_offset(n) + sizeof(struct dir_ext))
|
#define dir_ext_memsize(n) (dir_ext_offset(n) + sizeof(struct dir_ext))
|
||||||
|
#define dir_ext_ptr(d) ((d)->flags & FF_EXT ? (struct dir_ext *) ( ((char *)(d)) + dir_ext_offset((d)->name) ) : NULL)
|
||||||
static inline struct dir_ext *dir_ext_ptr(struct dir *d) {
|
|
||||||
return d->flags & FF_EXT
|
|
||||||
? (struct dir_ext *) ( ((char *)d) + dir_ext_offset(d->name) )
|
|
||||||
: NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Instead of using several ncurses windows, we only draw to stdscr.
|
/* Instead of using several ncurses windows, we only draw to stdscr.
|
||||||
|
|
@ -191,5 +188,9 @@ void *xmalloc(size_t);
|
||||||
void *xcalloc(size_t, size_t);
|
void *xcalloc(size_t, size_t);
|
||||||
void *xrealloc(void *, size_t);
|
void *xrealloc(void *, size_t);
|
||||||
|
|
||||||
|
char *xstrdup(const char *);
|
||||||
|
|
||||||
|
char *expanduser(const char *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
130
static/build.sh
130
static/build.sh
|
|
@ -1,130 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This script is based on static/build.sh from the ncdc git repo.
|
|
||||||
# Only i486 and arm arches are supported. i486 should perform well enough, so
|
|
||||||
# x86_64 isn't really necessary. I can't test any other arches.
|
|
||||||
#
|
|
||||||
# This script assumes that you have the musl-cross cross compilers installed in
|
|
||||||
# $MUSL_CROSS_PATH.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# ./build.sh $arch
|
|
||||||
# where $arch = 'arm', 'i486' or 'x86_64'
|
|
||||||
|
|
||||||
MUSL_CROSS_PATH=/opt/cross
|
|
||||||
NCURSES_VERSION=6.0
|
|
||||||
|
|
||||||
export CFLAGS="-O3 -g -static"
|
|
||||||
|
|
||||||
# (The variables below are automatically set by the functions, they're defined
|
|
||||||
# here to make sure they have global scope and for documentation purposes.)
|
|
||||||
|
|
||||||
# This is the arch we're compiling for, e.g. arm/mipsel.
|
|
||||||
TARGET=
|
|
||||||
# This is the name of the toolchain we're using, and thus the value we should
|
|
||||||
# pass to autoconf's --host argument.
|
|
||||||
HOST=
|
|
||||||
# Installation prefix.
|
|
||||||
PREFIX=
|
|
||||||
# Path of the extracted source code of the package we're currently building.
|
|
||||||
srcdir=
|
|
||||||
|
|
||||||
mkdir -p tarballs
|
|
||||||
|
|
||||||
|
|
||||||
# "Fetch, Extract, Move"
|
|
||||||
fem() { # base-url name targerdir extractdir
|
|
||||||
echo "====== Fetching and extracting $1 $2"
|
|
||||||
cd tarballs
|
|
||||||
if [ -n "$4" ]; then
|
|
||||||
EDIR="$4"
|
|
||||||
else
|
|
||||||
EDIR=$(basename $(basename $(basename $2 .tar.bz2) .tar.gz) .tar.xz)
|
|
||||||
fi
|
|
||||||
if [ ! -e "$2" ]; then
|
|
||||||
wget "$1$2" || exit
|
|
||||||
fi
|
|
||||||
if [ ! -d "$3" ]; then
|
|
||||||
tar -xvf "$2" || exit
|
|
||||||
mv "$EDIR" "$3"
|
|
||||||
fi
|
|
||||||
cd ..
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
prebuild() { # dirname
|
|
||||||
if [ -e "$TARGET/$1/_built" ]; then
|
|
||||||
echo "====== Skipping build for $TARGET/$1 (assumed to be done)"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
echo "====== Starting build for $TARGET/$1"
|
|
||||||
rm -rf "$TARGET/$1"
|
|
||||||
mkdir -p "$TARGET/$1"
|
|
||||||
cd "$TARGET/$1"
|
|
||||||
srcdir="../../tarballs/$1"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
postbuild() {
|
|
||||||
touch _built
|
|
||||||
cd ../..
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getncurses() {
|
|
||||||
fem http://ftp.gnu.org/pub/gnu/ncurses/ ncurses-$NCURSES_VERSION.tar.gz ncurses
|
|
||||||
prebuild ncurses || return
|
|
||||||
$srcdir/configure --prefix=$PREFIX\
|
|
||||||
--without-cxx --without-cxx-binding --without-ada --without-manpages --without-progs\
|
|
||||||
--without-tests --without-curses-h --without-pkg-config --without-shared --without-debug\
|
|
||||||
--without-gpm --without-sysmouse --enable-widec --with-default-terminfo-dir=/usr/share/terminfo\
|
|
||||||
--with-terminfo-dirs=/usr/share/terminfo:/lib/terminfo:/usr/local/share/terminfo\
|
|
||||||
--with-fallbacks="screen linux vt100 xterm xterm-256color" --host=$HOST\
|
|
||||||
CPPFLAGS=-D_GNU_SOURCE || exit
|
|
||||||
make || exit
|
|
||||||
make install.libs || exit
|
|
||||||
postbuild
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
getncdu() {
|
|
||||||
prebuild ncdu || return
|
|
||||||
srcdir=../../..
|
|
||||||
$srcdir/configure --host=$HOST --with-ncursesw PKG_CONFIG=false\
|
|
||||||
CPPFLAGS="-I$PREFIX/include -I$PREFIX/include/ncursesw"\
|
|
||||||
LDFLAGS="-static -L$PREFIX/lib -lncursesw" CFLAGS="$CFLAGS -Wall -Wextra" || exit
|
|
||||||
make || exit
|
|
||||||
|
|
||||||
VER=`cd '../../..' && git describe --abbrev=5 --dirty= | sed s/^v//`
|
|
||||||
tar -czf ../../ncdu-linux-$TARGET-$VER-unstripped.tar.gz ncdu
|
|
||||||
$HOST-strip ncdu
|
|
||||||
tar -czf ../../ncdu-linux-$TARGET-$VER.tar.gz ncdu
|
|
||||||
echo "====== ncdu-linux-$TARGET-$VER.tar.gz and -unstripped created."
|
|
||||||
|
|
||||||
postbuild
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
buildarch() {
|
|
||||||
TARGET=$1
|
|
||||||
case $TARGET in
|
|
||||||
arm) HOST=arm-linux-musleabi DIR=arm-linux-musleabi ;;
|
|
||||||
aarch64)HOST=aarch64-linux-musl DIR=aarch64-linux-musl ;;
|
|
||||||
i486) HOST=i486-linux-musl DIR=i486-linux-musl ;;
|
|
||||||
x86_64) HOST=x86_64-linux-musl DIR=x86_64-linux-musl ;;
|
|
||||||
*) echo "Unknown target: $TARGET" ;;
|
|
||||||
esac
|
|
||||||
PREFIX="`pwd`/$TARGET/inst"
|
|
||||||
mkdir -p $TARGET $PREFIX
|
|
||||||
ln -s lib $PREFIX/lib64
|
|
||||||
|
|
||||||
OLDPATH="$PATH"
|
|
||||||
export PATH="$PATH:$MUSL_CROSS_PATH/$DIR/bin"
|
|
||||||
getncurses
|
|
||||||
getncdu
|
|
||||||
PATH="$OLDPATH"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
buildarch $1
|
|
||||||
Loading…
Reference in a new issue