Compare commits

...

48 commits
zig ... v1.22

Author SHA1 Message Date
Yorhel
7a14373896 Version 1.22 2025-03-05 11:23:10 +01:00
Yorhel
61fda79ddf List all options in --help
Backport of 2e5c767d4c
2025-03-03 13:40:04 +01:00
Yorhel
ff830ac2bf Add support for @-prefix to ignore errors in config file
Primary motivation being that this would allow one to share a config
file between systems with different ncdu versions and set options
available in version 2 that aren't supported in version 1. But of course
that only works if all systems a recent enough version to support this
@-prefixing, which probably won't be the case for a while.
2025-03-01 12:08:22 +01:00
Yorhel
d6a129ff5a Add --graph-style + use integer calculations
Backport from the Zig branch.
2025-02-28 20:11:21 +01:00
Yorhel
b853185413 Fix supported range of uid/gid numbers
POSIX says they must be positive numbers, so why was I using an 'int'!?

Fixes #253.
2025-02-05 20:41:10 +01:00
Yorhel
61feee5657 Use kB instead of KB in --si mode
Backport of db96bc698c from the Zig
branch.
2024-12-23 10:13:59 +01:00
Yorhel
b4b82d96a3 Version 1.21 2024-11-19 14:40:43 +01:00
Yorhel
93edebc81c Expand ~ and ~user in config file
Fixes #243
2024-11-16 07:20:56 +01:00
Yorhel
73ef3294e8 Fix displaying and exporting zero values when extended info is not available
Backport from 2.6.
2024-11-15 14:37:48 +01:00
Yorhel
bc8129cad1 JSON import: Fix parsing of escaped UTF-16 surrogate pairs
Fixes #245
2024-11-03 11:05:49 +01:00
Yorhel
88c9b8718e Fix JSON export of "otherfs" excluded type
Corresponds to 08d373881c on the zig
branch.
2024-07-24 10:40:45 +02:00
Yorhel
ed7c5b2b93 Version 1.20 2024-04-21 10:56:54 +02:00
Yorhel
a9d608fab1 Copyright: remove year & use alias
Same as d60bcb2113
2024-04-21 10:55:23 +02:00
Yorhel
97cf0fc234 Change default color scheme back to "off", fix some mdoc lints 2024-04-21 10:46:13 +02:00
Yorhel
7af05149d6 Remove old POD man page 2024-02-03 18:44:02 +01:00
Yorhel
cded7d376a Rewrite man page in mdoc 2024-01-21 10:04:54 +01:00
Yorhel
1ca0c5769b Version 1.19 2023-09-11 21:00:53 +02:00
Roberto Ricci
6143a03a77 main.c: fix misspelled option 2023-09-11 09:16:05 +02:00
Yorhel
b93acabd59 Add --(enable|disable)-natsort options
Backport of zig/46b88bcb5ca584ff2c976af40a182e8e048892be
2023-03-05 08:37:23 +01:00
Yorhel
960661e93a UI: Add * indicator to apparent size/disk usage selection + spacing
Backport of zig/ca1f293310d5eaa00cf143f4c7e85965a4e76999
2023-03-03 08:46:12 +01:00
Yorhel
c08340ee08 Year + version bump for 1.18.1 2023-02-12 08:44:13 +01:00
Yorhel
daaca0a903 Really fix build failure if exclude-kernfs option is not available
Fixes #218, for real this time.
2023-02-08 14:23:48 +01:00
Yorhel
6993941646 Fix build failure if exclude-kernfs option is not available
Fixes #218
2023-02-08 08:14:44 +01:00
Yorhel
3ef0ac93c7 Version 1.18 2022-12-06 10:46:50 +01:00
Yorhel
6dd159d489 Backport --(enable|disable)-(shell|delete|refresh) from 2.x
Only remaining options missing from this C implementation are
--graph-style (sounds doable, but pretty low priority) and
--shared-column (unlikely to happen).
2022-11-30 11:44:08 +01:00
Yorhel
49e4b061a5 Backport configuration file support from 2.x 2022-11-06 13:37:33 +01:00
Yorhel
b45f8e4c06 Backport a bunch of CLI options from 2.x + sync manpage changes 2022-11-05 16:43:57 +01:00
Yorhel
9670ca66ed Backport argument parser from ncdu 2.x + add a few inverted arguments
This makes way for backporting the various new configuration options
and config file support from 2.x.
2022-11-05 12:21:30 +01:00
Yorhel
dc78e8db19 Properly mark functions without arguments as (void)
Fixes compilation with -Werror=old-style-definition
2022-11-05 10:54:37 +01:00
Yorhel
a5e8a43943 Set default attributes to the whole window during curses init
Based on 058b26bf9a
2022-06-15 06:26:18 +02:00
Yorhel
683eb26ad1 Year + version bump for 1.17 2022-04-28 11:19:27 +02:00
Yorhel
23e3eba5d2 Remove static build script
I'm not building static binaries for the 1.x branch anymore, the Zig
version replaces those binaries just fine.
2022-04-28 11:11:22 +02:00
François Revol
e29a42a02a Some more compatibility improvements for C89 environments
This compiles now fine with gcc 2.95 on Haiku.
2022-02-08 10:02:10 +01:00
Yorhel
15ebd21195 Some compatibility improvements for older (C89) environments
Whether this actually works on older environments, I don't really know.
2022-02-07 13:28:15 +01:00
Ciprian Tomoiaga
b340c04450 moved natSort files to deps 2021-12-23 09:07:54 +00:00
Ciprian Tomoiaga
8137444062 Use Natural Sort by Name in v1.x 2021-12-22 14:26:42 +00:00
rofl0r
e1a9b30803 dir_scan: call strlen only once 2021-10-27 13:44:01 +00:00
rofl0r
abab9d360d dir_scan: fix wrong assumption that errno can only be changed by readdir()
this breaks ncdu with musl 1.2.2, if the madvise syscall isn't implemented,
in which case realloc sets errno.
if errno is to be used, it needs to be set to 0 and checked after every
single libc call that could modify it.
interestingly, in the condition that the error is set here, ncdu just
prints nothing and silently quits with exit status 0 (success).
(maybe an error is being printed, but before the terminal is put back into
 a normal state.)
2021-10-27 13:40:41 +00:00
Oğuz Ersen
96a9231927
Make options, keys and file flags bold in man page 2021-10-06 20:07:17 +03:00
Yorhel
376aad0d35 Add dark-bg color scheme + enable colors by default if !NO_COLOR
The dark-bg scheme draws an explicit black background, so should also be
readable in terminals with a light background. That's been the main
show-stopper for enabling colors by default, as the 'dark' color scheme
is totally unreadable on light backgrounds and there's no way to detect
what background the terminal is actually using.
2021-08-16 16:07:51 +02:00
Yorhel
f982af81b0 Year + version bump for 1.16 2021-07-02 13:30:55 +02:00
Yorhel
52daeafcd8 Display setuid/setgid and sticky bits in file mode
Same way that coreutils 'ls -l' displays them.
2021-06-11 11:13:14 +02:00
Yorhel
bd01f5773d JSON import: accept fractional mtime values
For sub-second precision, if we ever want to add that.
2021-05-27 10:33:01 +02:00
Yorhel
67a1d84216 Mark apparent size or disk usage label in footer as bold
Depending on what is being displayed. Not *super* happy with this
solution, but it works.

Fixes #110.
2021-05-24 10:42:51 +02:00
Yorhel
ebeee7be01 browser.c: Fix bar width floating point calculation
In some cases the bar width may be 1 block short due to imprecise
floating point calculations. i.e. (max_width * a) / a != max_width,
whereas (max_width * (a/a)) == max_width. Or, at least, that's what I've
observed so far.
2021-05-23 14:26:29 +02:00
Yorhel
a6b4aead43 Add $NCDU_LEVEL environment variable when spawning a shell
Similar to $SHLVL and $RANGER_LEVEL.
2021-05-12 16:30:43 +02:00
Yorhel
e278660464 dir_import: Accept JSON data after the last object
This should really have been accepted from the start. Adding extra
elements to the top-level array might be useful for aux. data related to
the scanned files, e.g. map of seen uid/gids to names, information about
the scanned dev ids, etc. But since ncdu would throw an error on further
array elements, adding such information can't be done without breaking
compat with older versions. :(
2021-05-12 16:04:36 +02:00
Yorhel
ca51d4ed1a JSON Export: only export ino for hlinks and include hlink count
Bumping the minor version of the file format to '2'.

The "ino" field is only interesting for hardlinks, so we can save space
by not exporting it for other entries.

The hlink count will be interesting later on when I implement tracking
of shared data between directories. It's currently ignored on import.
The "nlink" field makes the "hlnkc" field redundant, but let's keep
including that field anyway for backwards compatibility.
2021-05-12 11:28:26 +02:00
38 changed files with 1502 additions and 1119 deletions

1
.gitignore vendored
View file

@ -16,7 +16,6 @@ missing
*.o
stamp-h1
ncdu
ncdu.1
*~
*.swp
static/*

View file

@ -1,4 +1,4 @@
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -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
- (Linux) Fix build on older Linux systems (Christian Göttsche)
- (MacOS) Revert "Exclude firmlinks by default" behavior (until we have a better solution)

View file

@ -16,11 +16,13 @@ ncdu_SOURCES=\
src/quit.c\
src/main.c\
src/path.c\
src/util.c
src/util.c\
deps/strnatcmp.c
noinst_HEADERS=\
deps/yopt.h\
deps/khashl.h\
deps/strnatcmp.h\
src/browser.h\
src/delete.h\
src/dir.h\
@ -35,13 +37,11 @@ noinst_HEADERS=\
man_MANS=ncdu.1
EXTRA_DIST=ncdu.1 doc/ncdu.pod
# 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
EXTRA_DIST=ncdu.1
# This target exists more for documentation purposes than actual use; some
# dependencies have minor ncdu-specific changes.
update-deps:
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
View file

@ -1,5 +1,5 @@
ncdu 1.15.1
===========
ncdu 1.22
=========
DESCRIPTION
@ -25,15 +25,14 @@ INSTALL
make
make install
If you're building directly from the git repository, make sure you have perl
(or rather, pod2man), pkg-config and GNU autoconf/automake installed, then
run 'autoreconf -i', and you're ready to continue with the usual ./configure
and make route.
If you're building directly from the git repository, make sure you have
pkg-config and GNU autoconf/automake installed, then run 'autoreconf -i',
and you're ready to continue with the usual ./configure and make route.
COPYING
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -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_HEADER([config.h])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign std-options subdir-objects])
# Check for programs.
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_RANLIB
@ -22,6 +23,8 @@ AC_TYPE_INT64_T
AC_TYPE_UINT64_T
AC_SYS_LARGEFILE
AC_STRUCT_ST_BLOCKS
AC_C_INLINE
AC_C_FLEXIBLE_ARRAY_MEMBER
# Check for library functions.
AC_CHECK_FUNCS(

164
deps/strnatcmp.c vendored Normal file
View 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
View 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
View file

@ -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: */

View file

@ -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
View 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

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -31,7 +31,7 @@
#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;
@ -68,15 +68,21 @@ static void browse_draw_info(struct dir *dr) {
ncaddstr(2, 9, cropstr(dr->name, 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) {
ncaddstr(4, 9, fmtmode(e->mode));
ncprint(4, 26, "%d", e->uid);
ncprint(4, 38, "%d", e->gid);
if(!e)
ncaddstr(4, 9, dr->flags & FF_DIR ? "Directory" : dr->flags & FF_FILE ? "File" : "Other");
else {
time_t t = (time_t)e->mtime;
strftime(mbuf, sizeof(mbuf), "%Y-%m-%d %H:%M:%S %z", localtime(&t));
ncaddstr(5, 18, mbuf);
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));
ncaddstr(5, 18, mbuf);
} else ncaddstr(5, 18, "N/A");
}
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) {
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;
if(!graph)
@ -160,9 +173,21 @@ static void browse_draw_graph(struct dir *n, int *x) {
/* graph (10+ columns) */
if(graph == 1 || graph == 3) {
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));
for(i=0; i<bar_size; i++)
addch(i < o ? '#' : ' ');
max = show_as ? dirlist_maxa : dirlist_maxs;
num = show_as ? n->asize : n->size;
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, ']');
@ -256,7 +281,7 @@ static void browse_draw_item(struct dir *n, int row) {
}
void browse_draw() {
void browse_draw(void) {
struct dir *t;
const char *tmp;
int selected = 0, i;
@ -272,7 +297,7 @@ void browse_draw() {
addstrc(UIC_HD, " for help");
if(dir_import_active)
mvaddstr(0, wincols-10, "[imported]");
else if(read_only)
else if(!can_delete)
mvaddstr(0, wincols-11, "[read-only]");
/* second line - the path */
@ -288,12 +313,19 @@ void browse_draw() {
uic_set(UIC_HD);
mvhline(winrows-1, 0, ' ', wincols);
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);
addstrc(UIC_HD, " Apparent size: ");
if(show_as) attron(A_BOLD);
addstrc(UIC_HD, " ");
addchc(UIC_HD, show_as ? '*' : ' ');
addstrc(UIC_HD, "Apparent size: ");
if(show_as) attroff(A_BOLD);
uic_set(UIC_NUM_HD);
printsize(UIC_HD, t->parent->asize);
addstrc(UIC_HD, " Items: ");
addstrc(UIC_HD, " Items: ");
uic_set(UIC_NUM_HD);
printw("%d", t->parent->items);
} else
@ -319,7 +351,7 @@ void browse_draw() {
if(message) {
nccreate(6, 60, "Message");
ncaddstr(2, 2, message);
ncaddstr(4, 34, "Press any key to continue");
ncaddstr(4, 33, "Press any key to continue");
}
/* draw information window */
@ -484,8 +516,8 @@ int browse_key(int ch) {
/* and other stuff */
case 'r':
if(dir_import_active) {
message = "Directory imported from file, won't refresh.";
if(!can_refresh) {
message = "Directory refresh feature disabled.";
break;
}
if(dirlist_par) {
@ -523,14 +555,12 @@ int browse_key(int ch) {
info_show = 0;
break;
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)
break;
if(!can_delete) {
message = "Deletion feature disabled.";
break;
}
info_show = 0;
if((t = dirlist_get(1)) == sel)
if((t = dirlist_get(-1)) == sel || t == dirlist_parent)
@ -538,10 +568,8 @@ int browse_key(int ch) {
delete_init(sel, t);
break;
case 'b':
if(read_only >= 2 || dir_import_active) {
message = read_only >= 2
? "Shell feature disabled in read-only mode."
: "Shell feature not available for imported directories.";
if(!can_shell) {
message = "Shell feature disabled.";
break;
}
shell_init();

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -35,9 +35,10 @@
#define DS_PROGRESS 1
#define DS_FAILED 2
int delete_confirm = 1;
static struct dir *root, *nextsel, *curdir;
static char noconfirm = 0, ignoreerr = 0, state;
static char ignoreerr = 0, state;
static signed char seloption;
static int lasterrno;
@ -98,7 +99,7 @@ static void delete_draw_error(void) {
}
void delete_draw() {
void delete_draw(void) {
browse_draw();
switch(state) {
case DS_CONFIRM: delete_draw_confirm(); break;
@ -126,7 +127,7 @@ int delete_key(int ch) {
if(seloption == 1)
return 1;
if(seloption == 2)
noconfirm++;
delete_confirm = 0;
state = DS_PROGRESS;
break;
case 'q':
@ -211,12 +212,12 @@ delete_nxt:
}
void delete_process() {
void delete_process(void) {
struct dir *par;
/* confirm */
seloption = 1;
while(state == DS_CONFIRM && !noconfirm)
while(state == DS_CONFIRM && delete_confirm)
if(input_handle(0)) {
browse_init(root->parent);
return;

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -28,6 +28,8 @@
#include "global.h"
extern int delete_confirm;
void delete_process(void);
int delete_key(int);
void delete_draw(void);

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
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
* 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
* 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 */
extern int dir_scan_smfs;
extern int exclude_kernfs;
void dir_scan_init(const char *path);
/* Importing a file */
extern int dir_import_active;
int dir_import_init(const char *fn);
#if HAVE_LINUX_MAGIC_H && HAVE_SYS_STATFS_H && HAVE_STATFS
extern int exclude_kernfs;
#endif
/* The currently configured output functions. */
extern struct dir_output dir_output;

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
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. */
struct dir_output dir_output;
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 char *lasterr; /* Path where the last error occurred. */
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 */
void dir_curpath_leave() {
void dir_curpath_leave(void) {
char *tmp;
if((tmp = strrchr(dir_curpath, '/')) == NULL)
strcpy(dir_curpath, "/");
@ -77,13 +77,14 @@ void dir_curpath_leave() {
void dir_setlasterr(const char *path) {
int req;
if(!path) {
free(lasterr);
lasterr = NULL;
lasterrl = 0;
return;
}
int req = strlen(path)+1;
req = strlen(path)+1;
if(lasterrl < req) {
lasterrl = req;
lasterr = xrealloc(lasterr, lasterrl);
@ -93,12 +94,12 @@ void dir_setlasterr(const char *path) {
void dir_seterr(const char *fmt, ...) {
va_list va;
free(dir_fatalerr);
dir_fatalerr = NULL;
if(!fmt)
return;
va_list va;
va_start(va, fmt);
dir_fatalerr = xmalloc(1024); /* Should be enough for everything... */
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;
const char *unit;

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
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))
e = NULL;
@ -96,23 +96,32 @@ static void output_info(struct dir *d, const char *name, struct dir_ext *e) {
fputs(",\"dev\":", stream);
output_int(d->dev);
}
fputs(",\"ino\":", stream);
output_int(d->ino);
if(e) {
fputs(",\"uid\":", stream);
output_int(e->uid);
fputs(",\"gid\":", stream);
output_int(e->gid);
fputs(",\"mode\":", stream);
output_int(e->mode);
fputs(",\"mtime\":", stream);
output_int(e->mtime);
if(e->flags & FFE_UID) {
fputs(",\"uid\":", stream);
output_int(e->uid);
}
if(e->flags & FFE_GID) {
fputs(",\"gid\":", stream);
output_int(e->gid);
}
if(e->flags & FFE_MODE) {
fputs(",\"mode\":", stream);
output_int(e->mode);
}
if(e->flags & FFE_MTIME) {
fputs(",\"mtime\":", stream);
output_int(e->mtime);
}
}
/* TODO: Including the actual number of links would be nicer. */
if(d->flags & FF_HLNKC)
fputs(",\"hlnkc\":true", stream);
if(d->flags & FF_HLNKC) {
fputs(",\"ino\":", stream);
output_int(d->ino);
fputs(",\"hlnkc\":true,\"nlink\":", stream);
output_int(nlink);
}
if(d->flags & FF_ERR)
fputs(",\"read_error\":true", stream);
/* 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)
fputs(",\"excluded\":\"pattern\"", stream);
else if(d->flags & FF_OTHFS)
fputs(",\"excluded\":\"othfs\"", stream);
fputs(",\"excluded\":\"otherfs\"", stream);
else if(d->flags & FF_KERNFS)
fputs(",\"excluded\":\"kernfs\"", stream);
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
* assumes that calls to fwrite()/fput./etc don't do any weird stuff when
* 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) {
nstack_pop(&stack);
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.
* TODO: Add scan options? */
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));
fputc('}', stream);
}
@ -161,7 +170,7 @@ static int item(struct dir *item, const char *name, struct dir_ext *ext) {
if(item->flags & FF_DIR)
fputc('[', stream);
output_info(item, name, ext);
output_info(item, name, ext, nlink);
if(item->flags & FF_DIR)
nstack_push(&stack, item->dev);

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -72,6 +72,7 @@ static struct ctx {
/* scratch space */
struct dir *buf_dir;
struct dir_ext buf_ext[1];
unsigned int nlink;
char buf_name[MAX_VAL];
char val[MAX_VAL];
@ -186,7 +187,7 @@ static int cons(void) {
static int rstring_esc(char **dest, int *destlen) {
unsigned int n;
unsigned int n, s;
C(rfill1);
@ -203,8 +204,22 @@ static int rstring_esc(char **dest, int *destlen) {
case 'u':
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)
n = (hn(ctx->buf[1])<<12) + (hn(ctx->buf[2])<<8) + (hn(ctx->buf[3])<<4) + hn(ctx->buf[4]);
#undef hn
#define h4(b) (hn((b)[0])<<12) + (hn((b)[1])<<8) + (hn((b)[2])<<4) + hn((b)[3])
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) {
ap(n);
} else if(n <= 0x07FF) {
@ -214,9 +229,14 @@ static int rstring_esc(char **dest, int *destlen) {
ap(0xE0 | (n>>12));
ap(0x80 | ((n>>6) & 0x3F));
ap(0x80 | (n & 0x3F));
} else /* this happens if there was an invalid character (n >= (1<<16)) */
E(1, "Invalid character in \\u escape");
con(5);
} else {
ap(0xF0 | (n>>18));\
ap(0x80 | ((n>>12) & 0x3F));
ap(0x80 | ((n>>6) & 0x3F));
ap(0x80 | (n & 0x3F));
}
#undef hn
#undef h4
break;
default:
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
* 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) {
uint64_t iv;
@ -449,27 +469,42 @@ static int iteminfo(void) {
C(rint64(&iv, UINT64_MAX));
ctx->buf_dir->ino = iv;
} 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_ext->flags |= FFE_UID;
ctx->buf_ext->uid = iv;
} 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_ext->flags |= FFE_GID;
ctx->buf_ext->gid = iv;
} else if(strcmp(ctx->val, "mode") == 0) { /* mode */
C(rint64(&iv, UINT16_MAX));
ctx->buf_dir->flags |= FF_EXT;
ctx->buf_ext->flags |= FFE_MODE;
ctx->buf_ext->mode = iv;
} else if(strcmp(ctx->val, "mtime") == 0) { /* mtime */
C(rint64(&iv, UINT64_MAX));
ctx->buf_dir->flags |= FF_EXT;
ctx->buf_ext->flags |= FFE_MTIME;
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 */
if(*ctx->buf == 't') {
C(rlit("true", 4));
ctx->buf_dir->flags |= FF_HLNKC;
} else
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 */
if(*ctx->buf == 't') {
C(rlit("true", 4));
@ -478,7 +513,7 @@ static int iteminfo(void) {
C(rlit("false", 5));
} else if(strcmp(ctx->val, "excluded") == 0) { /* excluded */
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;
else if(strcmp(ctx->val, "kernfs") == 0)
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_ext, 0, sizeof(struct dir_ext));
ctx->nlink = 0;
*ctx->buf_name = 0;
ctx->buf_dir->flags |= isdir ? FF_DIR : FF_FILE;
ctx->buf_dir->dev = dev;
@ -539,16 +575,16 @@ static int item(uint64_t dev) {
dir_curpath_enter(ctx->buf_name);
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));
return 1;
}
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));
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));
return 1;
}
@ -561,8 +597,14 @@ static int item(uint64_t dev) {
static int footer(void) {
C(cons());
E(*ctx->buf != ']', "Expected ']'");
while(1) {
C(cons());
if(*ctx->buf == ']')
break;
E(*ctx->buf != ',', "Expected ',' or ']'");
con(1);
C(cons() || rval());
}
con(1);
C(cons());
E(*ctx->buf, "Trailing garbage");

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
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 */
static void hlink_init(struct dir *d) {
struct dir *t;
int r;
for(t=d->sub; t!=NULL; t=t->next)
hlink_init(t);
if(!(d->flags & FF_HLNKC))
return;
int 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;
(void)nlink;
/* Go back to parent 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));
memcpy(item, dir, offsetof(struct dir, 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));
item_add(item);

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -51,16 +51,17 @@
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 */
/* scratch space */
static struct dir *buf_dir;
static struct dir_ext buf_ext[1];
static unsigned int buf_nlink;
#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) {
if(
@ -120,8 +121,11 @@ static void stat_to_dir(struct stat *fs) {
else if(S_ISDIR(fs->st_mode))
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_nlink = fs->st_nlink;
} else
buf_nlink = 0;
if(dir_scan_smfs && curdev != buf_dir->dev)
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->mtime = fs->st_mtime;
buf_ext->uid = (int)fs->st_uid;
buf_ext->gid = (int)fs->st_gid;
buf_ext->uid = (unsigned int)fs->st_uid;
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);
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)))
continue;
size_t req = off+3+strlen(item->d_name);
len = strlen(item->d_name);
req = off+3+len;
if(req > buflen) {
buflen = req < buflen*2 ? buflen*2 : req;
buf = xrealloc(buf, buflen);
}
strcpy(buf+off, item->d_name);
off += strlen(item->d_name)+1;
off += len+1;
}
if(errno)
*err = 1;
if(closedir(dir) < 0)
*err = 1;
@ -193,7 +203,7 @@ static int dir_scan_recurse(const char *name) {
if(chdir(name)) {
dir_setlasterr(dir_curpath);
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));
return 1;
}
@ -203,7 +213,7 @@ static int dir_scan_recurse(const char *name) {
if((dir = dir_read(&fail)) == NULL) {
dir_setlasterr(dir_curpath);
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));
return 1;
}
@ -218,12 +228,12 @@ static int dir_scan_recurse(const char *name) {
if(fail)
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));
return 1;
}
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));
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)))
fail = dir_scan_recurse(name);
else if(buf_dir->flags & FF_DIR) {
if(dir_output.item(buf_dir, name, buf_ext) || dir_output.item(NULL, 0, NULL)) {
if(dir_output.item(buf_dir, name, buf_ext, 0) || dir_output.item(NULL, 0, NULL, 0)) {
dir_seterr("Output error: %s", strerror(errno));
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));
fail = 1;
}
@ -333,6 +343,7 @@ static int dir_walk(char *dir) {
dir_curpath_enter(cur);
memset(buf_dir, 0, offsetof(struct dir, name));
memset(buf_ext, 0, sizeof(struct dir_ext));
buf_nlink = 0;
fail = dir_scan_item(cur);
dir_curpath_leave();
}
@ -350,6 +361,7 @@ static int process(void) {
memset(buf_dir, 0, offsetof(struct dir, name));
memset(buf_ext, 0, sizeof(struct dir_ext));
buf_nlink = 0;
if((path = path_real(dir_curpath)) == NULL)
dir_seterr("Error obtaining full path: %s", strerror(errno));
@ -376,13 +388,13 @@ static int process(void) {
buf_dir->flags |= FF_ERR;
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));
fail = 1;
}
if(!fail)
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));
fail = 1;
}

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -24,6 +24,7 @@
*/
#include "global.h"
#include "strnatcmp.h"
#include <string.h>
#include <stdlib.h>
@ -38,7 +39,8 @@ int64_t dirlist_maxs = 0,
int dirlist_sort_desc = 1,
dirlist_sort_col = DL_COL_SIZE,
dirlist_sort_df = 0,
dirlist_hidden = 0;
dirlist_hidden = 0,
dirlist_natsort = 1;
/* private state vars */
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 :-)
*/
#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_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))
@ -395,4 +397,3 @@ void dirlist_set_hidden(int hidden) {
dirlist_fixup();
dirlist_top(-5);
}

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
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() */
extern int dirlist_hidden;
extern int dirlist_natsort;
/* maximum size of an item in the opened dir */
extern int64_t dirlist_maxs, dirlist_maxa;

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -46,8 +46,7 @@ void exclude_add(char *pat) {
n = &((*n)->next);
*n = (struct exclude *) xcalloc(1, sizeof(struct exclude));
(*n)->pattern = (char *) xmalloc(strlen(pat)+1);
strcpy((*n)->pattern, pat);
(*n)->pattern = xstrdup(pat);
}
@ -89,7 +88,7 @@ int exclude_match(char *path) {
}
void exclude_clear() {
void exclude_clear(void) {
struct exclude *n, *l;
for(n=excludes; n!=NULL; n=l) {

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
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_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 */
#define ST_CALC 0
#define ST_BROWSE 1
@ -70,7 +76,7 @@ struct dir {
struct dir *parent, *next, *prev, *sub, *hlnk;
int items;
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,
@ -88,15 +94,18 @@ struct dir {
* macros to help manage this. */
struct dir_ext {
uint64_t mtime;
int uid, gid;
unsigned int uid, gid;
unsigned short mode;
unsigned char flags;
};
/* program state */
extern int pstate;
/* read-only flag, 1+ = disable deletion, 2+ = also disable shell */
extern int read_only;
/* enabled features */
extern int can_delete;
extern int can_shell;
extern int can_refresh;
/* minimum screen update interval when calculating, in ms */
extern long update_delay;
/* filter directories with CACHEDIR.TAG */
@ -109,6 +118,17 @@ extern int extended_info;
extern int follow_symlinks;
/* flag whether we want to 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 */
int input_handle(int);

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -70,7 +70,7 @@ static const char *flags[FLAGS*2] = {
"F", "Excluded firmlink",
};
void help_draw() {
void help_draw(void) {
int i, line;
browse_draw();
@ -156,7 +156,7 @@ void help_draw() {
ncaddstr(y+1, x+30, "Disk");
ncaddstr(y+2, x+30, "Usage");
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/");
break;
}
@ -203,7 +203,7 @@ int help_key(int ch) {
}
void help_init() {
void help_init(void) {
page = 1;
start = 0;
pstate = ST_HELP;

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -33,17 +33,23 @@
#include <unistd.h>
#include <sys/time.h>
#include <yopt.h>
int pstate;
int read_only = 0;
int can_delete = -1;
int can_shell = -1;
int can_refresh = -1;
long update_delay = 100;
int cachedir_tags = 0;
int extended_info = 0;
int follow_symlinks = 0;
int follow_firmlinks = 1;
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 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) {
yopt_t yopt;
int v;
char *val;
int r;
char *export = NULL;
char *import = NULL;
char *dir = NULL;
static yopt_opt_t opts[] = {
{ 'h', 0, "-h,-?,--help" },
{ 'q', 0, "-q" },
{ 'v', 0, "-v,-V,--version" },
{ '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}
};
memset(&argparser_state, 0, sizeof(struct argparser));
argparser_state.argv = argv;
argparser_state.argc = argc;
argparser_next(&argparser_state); /* skip program name */
dir_ui = -1;
si = 0;
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':
while((r = argparser_next(&argparser_state)) > 0) {
if(r == 2) dir = argparser_state.last;
else if(OPT("-v") || OPT("-V") || OPT("--version")) {
printf("ncdu %s\n", PACKAGE_VERSION);
exit(0);
case 'x': dir_scan_smfs = 1; break;
case 'e': extended_info = 1; break;
case 'r': read_only++; break;
case 's': si = 1; break;
case 'o': export = val; break;
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
exclude_kernfs = 1; break;
#else
fprintf(stderr, "This feature is not supported on your platform\n");
exit(1);
#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);
}
} else if(OPT("-h") || OPT("-?") || OPT("--help")) arg_help();
else if(OPT("-o")) export = ARG;
else if(OPT("-f")) import = ARG;
else if(OPT("--ignore-config")) {}
else if(!arg_option(0)) die("Unknown option '%s'.\n", argparser_state.last);
}
#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");
#endif
if(export) {
if(dir_export_init(export)) {
fprintf(stderr, "Can't open %s: %s\n", export, strerror(errno));
exit(1);
}
if(strcmp(export, "-") == 0)
ncurses_tty = 1;
if(dir_export_init(export)) die("Can't open %s: %s\n", export, strerror(errno));
if(strcmp(export, "-") == 0) ncurses_tty = 1;
} else
dir_mem_init(NULL);
if(import) {
if(dir_import_init(import)) {
fprintf(stderr, "Can't open %s: %s\n", import, strerror(errno));
exit(1);
}
if(strcmp(import, "-") == 0)
ncurses_tty = 1;
if(dir_import_init(import)) die("Can't open %s: %s\n", import, strerror(errno));
if(strcmp(import, "-") == 0) ncurses_tty = 1;
} else
dir_scan_init(dir ? dir : ".");
@ -264,6 +461,10 @@ static void argv_parse(int argc, char **argv) {
* feedback when exporting to stdout. */
if(dir_ui == -1)
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) {
tty = fopen("/dev/tty", "r+");
if(!tty) {
fprintf(stderr, "Error opening /dev/tty: %s\n", strerror(errno));
exit(1);
}
if(!tty) die("Error opening /dev/tty: %s\n", strerror(errno));
term = newterm(NULL, tty, tty);
if(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
* input without using "-f -". An annoying input sequence could result in
* the deletion of your files, which we want to prevent at all costs. */
if(!isatty(0)) {
fprintf(stderr, "Standard input is not a TTY. Did you mean to import a file using '-f -'?\n");
exit(1);
}
if(!isatty(0)) die("Standard input is not a TTY. Did you mean to import a file using '-f -'?\n");
ok = !!initscr();
}
if(!ok) {
fprintf(stderr, "Error while initializing ncurses.\n");
exit(1);
}
if(!ok) die("Error while initializing ncurses.\n");
uic_init();
cbreak();
noecho();
curs_set(0);
keypad(stdscr, TRUE);
bkgd(COLOR_PAIR(UIC_DEFAULT+1));
if(ncresize(min_rows, min_cols))
min_rows = min_cols = 0;
}
void close_nc() {
void close_nc(void) {
if(ncurses_init) {
erase();
refresh();
@ -322,9 +515,9 @@ void close_nc() {
}
/* main program */
int main(int argc, char **argv) {
read_locale();
config_load(argc, argv);
argv_parse(argc, argv);
if(dir_ui == 2)

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2015-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -38,13 +38,13 @@ int quit_key(int ch) {
return 0;
}
void quit_draw() {
void quit_draw(void) {
browse_draw();
nccreate(4,30, "ncdu confirm quit");
ncaddstr(2,2, "Really quit? (y/N)");
}
void quit_init() {
void quit_init(void) {
pstate = ST_QUIT;
}

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2015-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Shell support: Copyright (c) 2014 Thomas Jarosch
Permission is hereby granted, free of charge, to any person obtaining
@ -34,7 +34,24 @@
#include <unistd.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;
int res;
@ -59,6 +76,7 @@ void shell_draw() {
shell = DEFAULT_SHELL;
}
set_level();
res = system(shell);
/* resume ncurses mode */
@ -77,6 +95,6 @@ void shell_draw() {
pstate = ST_BROWSE;
}
void shell_init() {
void shell_init(void) {
pstate = ST_SHELL;
}

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Shell support: Copyright (c) 2014 Thomas Jarosch
Permission is hereby granted, free of charge, to any person obtaining

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -30,17 +30,27 @@
#include <ncurses.h>
#include <stdarg.h>
#include <unistd.h>
#include <pwd.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
int uic_theme;
int uic_theme = 0;
int winrows, wincols;
int subwinr, subwinc;
int si;
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) {
static char dat[4096];
int i, j, o = strlen(from);
@ -66,7 +76,7 @@ float formatsize(int64_t from, const char **unit) {
float r = from;
if (si) {
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 < 1e12f){ *unit = "GB"; r/=1e9f; }
else if(r < 1e15f){ *unit = "TB"; r/=1e12f; }
@ -134,23 +144,26 @@ char *fmtmode(unsigned short mode) {
: ft == S_IFBLK ? 'b' : '?';
buf[1] = mode & 0400 ? 'r' : '-';
buf[2] = mode & 0200 ? 'w' : '-';
buf[3] = mode & 0100 ? 'x' : '-';
buf[3] = mode &04000 ? 's' : mode & 0100 ? 'x' : '-';
buf[4] = mode & 0040 ? 'r' : '-';
buf[5] = mode & 0020 ? 'w' : '-';
buf[6] = mode & 0010 ? 'x' : '-';
buf[6] = mode &02000 ? 's' : mode & 0010 ? 'x' : '-';
buf[7] = mode & 0004 ? 'r' : '-';
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;
return buf;
}
void read_locale() {
void read_locale(void) {
#ifdef HAVE_LOCALE_H
char *locale_thou_sep;
#endif
thou_sep = '.';
#ifdef HAVE_LOCALE_H
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))
thou_sep = locale_thou_sep[0];
#endif
@ -250,21 +263,27 @@ static const struct {
short fg, bg;
int attr;
} color_defs[] = {
#define C(name, off_fg, off_bg, off_a, dark_fg, dark_bg, dark_a) \
{off_fg, off_bg, off_a}, \
{dark_fg, dark_bg, dark_a},
#define COLOR__ -1
#define B A_BOLD
#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
#undef B
#undef R
#undef C
{0,0,0}
};
void uic_init() {
void uic_init(void) {
size_t i, j;
start_color();
use_default_colors();
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);
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];\
while((ptr = f) == NULL) {\
close_nc();\
write(2, oom_msg, sizeof(oom_msg));\
write(2, oom_msg, sizeof(oom_msg)-1);\
read(0, buf, sizeof(buf));\
}\
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 *xcalloc(size_t n, size_t size) { wrap_oom(calloc(n, 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;
}

View file

@ -1,6 +1,6 @@
/* ncdu - NCurses Disk Usage
Copyright (c) 2007-2020 Yoran Heling
Copyright (c) Yorhel
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -30,25 +30,27 @@
#include <ncurses.h>
void die(const char *, ...);
/* UI colors: (foreground, background, attrs)
* NAME OFF DARK
*/
* NAME OFF DARK DARK-BG */
#define UI_COLORS \
C(DEFAULT, -1,-1,0 , -1, -1, 0 )\
C(BOX_TITLE, -1,-1,A_BOLD , COLOR_BLUE, -1, A_BOLD)\
C(HD, -1,-1,A_REVERSE , COLOR_BLACK, COLOR_CYAN, 0 ) /* header & footer */\
C(SEL, -1,-1,A_REVERSE , COLOR_WHITE, COLOR_GREEN,A_BOLD)\
C(NUM, -1,-1,0 , COLOR_YELLOW, -1, A_BOLD)\
C(NUM_HD, -1,-1,A_REVERSE , COLOR_YELLOW, COLOR_CYAN, A_BOLD)\
C(NUM_SEL, -1,-1,A_REVERSE , COLOR_YELLOW, COLOR_GREEN,A_BOLD)\
C(KEY, -1,-1,A_BOLD , COLOR_YELLOW, -1, A_BOLD)\
C(KEY_HD, -1,-1,A_BOLD|A_REVERSE, COLOR_YELLOW, COLOR_CYAN, A_BOLD)\
C(DIR, -1,-1,0 , COLOR_BLUE, -1, A_BOLD)\
C(DIR_SEL, -1,-1,A_REVERSE , COLOR_BLUE, COLOR_GREEN,A_BOLD)\
C(FLAG, -1,-1,0 , COLOR_RED, -1, 0 )\
C(FLAG_SEL, -1,-1,A_REVERSE , COLOR_RED, COLOR_GREEN,0 )\
C(GRAPH, -1,-1,0 , COLOR_MAGENTA,-1, 0 )\
C(GRAPH_SEL, -1,-1,A_REVERSE , COLOR_MAGENTA,COLOR_GREEN,0 )
C(DEFAULT, _,_,0 , _, _, 0, WHITE, BLACK,0)\
C(BOX_TITLE, _,_,B , BLUE, _, B, BLUE, BLACK,B)\
C(HD, _,_,R , BLACK, CYAN, 0, BLACK, CYAN, 0) /* header & footer */\
C(SEL, _,_,R , WHITE, GREEN,B, WHITE, GREEN,B)\
C(NUM, _,_,0 , YELLOW, _, B, YELLOW, BLACK,B)\
C(NUM_HD, _,_,R , YELLOW, CYAN, B, YELLOW, CYAN, B)\
C(NUM_SEL, _,_,R , YELLOW, GREEN,B, YELLOW, GREEN,B)\
C(KEY, _,_,B , YELLOW, _, B, YELLOW, BLACK,B)\
C(KEY_HD, _,_,B|R, YELLOW, CYAN, B, YELLOW, CYAN, B)\
C(DIR, _,_,0 , BLUE, _, B, BLUE, BLACK,B)\
C(DIR_SEL, _,_,R , BLUE, GREEN,B, BLUE, GREEN,B)\
C(FLAG, _,_,0 , RED, _, 0, RED, BLACK,0)\
C(FLAG_SEL, _,_,R , RED, GREEN,0, RED, GREEN,0)\
C(GRAPH, _,_,0 , MAGENTA,_, 0, MAGENTA,BLACK,0)\
C(GRAPH_SEL, _,_,R , MAGENTA,GREEN,0, MAGENTA,GREEN,0)
enum ui_coltype {
#define C(name, ...) UIC_##name,
@ -74,17 +76,12 @@ extern int subwinr, subwinc;
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_ext_offset(n) ((dir_memsize(n) + 7) & ~7)
#define dir_ext_memsize(n) (dir_ext_offset(n) + sizeof(struct dir_ext))
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;
}
#define dir_ext_ptr(d) ((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.
@ -191,5 +188,9 @@ void *xmalloc(size_t);
void *xcalloc(size_t, size_t);
void *xrealloc(void *, size_t);
char *xstrdup(const char *);
char *expanduser(const char *);
#endif

View file

@ -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