mirror of
https://code.blicky.net/yorhel/ncdu.git
synced 2026-01-13 01:08:41 -09:00
Compare commits
48 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a14373896 | ||
|
|
61fda79ddf | ||
|
|
ff830ac2bf | ||
|
|
d6a129ff5a | ||
|
|
b853185413 | ||
|
|
61feee5657 | ||
|
|
b4b82d96a3 | ||
|
|
93edebc81c | ||
|
|
73ef3294e8 | ||
|
|
bc8129cad1 | ||
|
|
88c9b8718e | ||
|
|
ed7c5b2b93 | ||
|
|
a9d608fab1 | ||
|
|
97cf0fc234 | ||
|
|
7af05149d6 | ||
|
|
cded7d376a | ||
|
|
1ca0c5769b | ||
|
|
6143a03a77 | ||
|
|
b93acabd59 | ||
|
|
960661e93a | ||
|
|
c08340ee08 | ||
|
|
daaca0a903 | ||
|
|
6993941646 | ||
|
|
3ef0ac93c7 | ||
|
|
6dd159d489 | ||
|
|
49e4b061a5 | ||
|
|
b45f8e4c06 | ||
|
|
9670ca66ed | ||
|
|
dc78e8db19 | ||
|
|
a5e8a43943 | ||
|
|
683eb26ad1 | ||
|
|
23e3eba5d2 | ||
|
|
e29a42a02a | ||
|
|
15ebd21195 | ||
|
|
b340c04450 | ||
|
|
8137444062 | ||
|
|
e1a9b30803 | ||
|
|
abab9d360d | ||
|
|
96a9231927 | ||
|
|
376aad0d35 | ||
|
|
f982af81b0 | ||
|
|
52daeafcd8 | ||
|
|
bd01f5773d | ||
|
|
67a1d84216 | ||
|
|
ebeee7be01 | ||
|
|
a6b4aead43 | ||
|
|
e278660464 | ||
|
|
ca51d4ed1a |
38 changed files with 1502 additions and 1119 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -16,7 +16,6 @@ missing
|
|||
*.o
|
||||
stamp-h1
|
||||
ncdu
|
||||
ncdu.1
|
||||
*~
|
||||
*.swp
|
||||
static/*
|
||||
|
|
|
|||
2
COPYING
2
COPYING
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2007-2020 Yoran Heling
|
||||
Copyright (c) Yorhel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
|
|
|||
57
ChangeLog
57
ChangeLog
|
|
@ -1,3 +1,60 @@
|
|||
1.22 - 2025-03-05
|
||||
- Add support for @-prefixed lines to ignore errors in config file (from 2.8)
|
||||
- List all supported options in `--help` (from 2.8)
|
||||
- Use `kB` instead of `KB` in `--si` mode (from 2.8)
|
||||
- Add `--graph-style` option (from 2.1)
|
||||
- Fix supported range of uid/gid numbers
|
||||
|
||||
1.21 - 2024-11-19
|
||||
- Perform tilde expansion on paths in the config file (from 2.7)
|
||||
- Fix JSON import of escaped UTF-16 surrogate pairs (from 2.7)
|
||||
- Fix displaying and exporting zero values when extended info is not
|
||||
available (from 2.6)
|
||||
- Fix JSON export and import of the “other filesystem” flag (from 2.5)
|
||||
|
||||
1.20 - 2024-04-21
|
||||
- Revert default color scheme back to 'off'
|
||||
- Rewrite man page in mdoc, drop pod2man dependency
|
||||
|
||||
1.19 - 2023-09-11
|
||||
- Fix typo in --exclude-from argument
|
||||
- Add --(enable|disable)-natsort options
|
||||
- Add indicator to apparent size/disk usage selection in the footer
|
||||
|
||||
1.18.1 - 2023-02-12
|
||||
- Fix build on non-Linux platforms
|
||||
|
||||
1.18 - 2022-12-06
|
||||
- Fix 'dark-bg' color scheme to actually have a dark background
|
||||
- Backport configuration file support from 2.x
|
||||
- Backport many new CLI options from 2.x
|
||||
- Negation of existing flags: --no-si, --no-confirm-quit, --no-follow-symlinks, --include-caches, --include-kernfs
|
||||
- --[no-]extended in addition to -e
|
||||
- --one-file-system and --cross-file-system in addition to -x
|
||||
- --slow-ui-updates, --fast-ui-updates in addition to -q
|
||||
- Column visibility options: --(show|hide)-(hidden|itemcount|mtime|graph|percent)
|
||||
- Sorting: --sort, --[no-]group-directories-first
|
||||
- Feature selection: --(enable|disable)-(shell|delete|refresh)
|
||||
- Deletion confirmation: --[no-]confirm-delete
|
||||
- Hidden file visibility: --show-hidden, --hide-hidden
|
||||
- Size display: --apparent-size, --disk-usage
|
||||
|
||||
1.17 - 2022-04-28
|
||||
- Add 'dark-bg' color scheme and use that by default
|
||||
- Use natural sort order when sorting by file name
|
||||
- Improve compatibility with C89 environments
|
||||
- Fix wrong assumption about errno not being set by realloc()
|
||||
|
||||
1.16 - 2021-07-02
|
||||
- Increase width of size bar depending on terminal size (Christian Göttsche)
|
||||
- Set/increment $NCDU_LEVEL variable when spawning a shell
|
||||
- Indicate whether apparent size or disk usage is being displayed
|
||||
- Display setuid, setgid and sticky bits in file flags in extended mode
|
||||
- Fix error handling while reading --exclude-from file
|
||||
- Improve JSON import to allow for several future extensions to the format
|
||||
- Export link count in JSON dumps
|
||||
- Don't export inode in JSON dumps for non-hardlinks
|
||||
|
||||
1.15.1 - 2020-06-10
|
||||
- (Linux) Fix build on older Linux systems (Christian Göttsche)
|
||||
- (MacOS) Revert "Exclude firmlinks by default" behavior (until we have a better solution)
|
||||
|
|
|
|||
18
Makefile.am
18
Makefile.am
|
|
@ -16,11 +16,13 @@ ncdu_SOURCES=\
|
|||
src/quit.c\
|
||||
src/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
13
README
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
164
deps/strnatcmp.c
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||
|
||||
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
/* partial change history:
|
||||
*
|
||||
* 2004-10-10 mbp: Lift out character type dependencies into macros.
|
||||
*
|
||||
* Eric Sosman pointed out that ctype functions take a parameter whose
|
||||
* value must be that of an unsigned int, even on platforms that have
|
||||
* negative chars in their default char type.
|
||||
*
|
||||
* ncdu edits:
|
||||
* - static inline -> #define for better compatibility
|
||||
* - don't use ctype.h, for more predictable results
|
||||
*/
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
#include "strnatcmp.h"
|
||||
|
||||
|
||||
/* These are defined as macros to make it easier to adapt this code to
|
||||
* different characters types or comparison functions. */
|
||||
#define nat_isdigit(a) ((a) >= '0' && (a) <= '9')
|
||||
#define nat_isspace(a) ((a) == ' ' || (a) == '\t' || (a) == '\r' || (a) == '\n')
|
||||
#define nat_toupper(a) (a)
|
||||
|
||||
|
||||
static int
|
||||
compare_right(nat_char const *a, nat_char const *b)
|
||||
{
|
||||
int bias = 0;
|
||||
|
||||
/* The longest run of digits wins. That aside, the greatest
|
||||
value wins, but we can't know that it will until we've scanned
|
||||
both numbers to know that they have the same magnitude, so we
|
||||
remember it in BIAS. */
|
||||
for (;; a++, b++) {
|
||||
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||
return bias;
|
||||
if (!nat_isdigit(*a))
|
||||
return -1;
|
||||
if (!nat_isdigit(*b))
|
||||
return +1;
|
||||
if (*a < *b) {
|
||||
if (!bias)
|
||||
bias = -1;
|
||||
} else if (*a > *b) {
|
||||
if (!bias)
|
||||
bias = +1;
|
||||
} else if (!*a && !*b)
|
||||
return bias;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
compare_left(nat_char const *a, nat_char const *b)
|
||||
{
|
||||
/* Compare two left-aligned numbers: the first to have a
|
||||
different value wins. */
|
||||
for (;; a++, b++) {
|
||||
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||
return 0;
|
||||
if (!nat_isdigit(*a))
|
||||
return -1;
|
||||
if (!nat_isdigit(*b))
|
||||
return +1;
|
||||
if (*a < *b)
|
||||
return -1;
|
||||
if (*a > *b)
|
||||
return +1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
strnatcmp0(nat_char const *a, nat_char const *b, int fold_case)
|
||||
{
|
||||
int ai, bi;
|
||||
nat_char ca, cb;
|
||||
int fractional, result;
|
||||
|
||||
ai = bi = 0;
|
||||
while (1) {
|
||||
ca = a[ai]; cb = b[bi];
|
||||
|
||||
/* skip over leading spaces or zeros */
|
||||
while (nat_isspace(ca))
|
||||
ca = a[++ai];
|
||||
|
||||
while (nat_isspace(cb))
|
||||
cb = b[++bi];
|
||||
|
||||
/* process run of digits */
|
||||
if (nat_isdigit(ca) && nat_isdigit(cb)) {
|
||||
fractional = (ca == '0' || cb == '0');
|
||||
|
||||
if (fractional) {
|
||||
if ((result = compare_left(a+ai, b+bi)) != 0)
|
||||
return result;
|
||||
} else {
|
||||
if ((result = compare_right(a+ai, b+bi)) != 0)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ca && !cb) {
|
||||
/* The strings compare the same. Perhaps the caller
|
||||
will want to call strcmp to break the tie. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fold_case) {
|
||||
ca = nat_toupper(ca);
|
||||
cb = nat_toupper(cb);
|
||||
}
|
||||
|
||||
if (ca < cb)
|
||||
return -1;
|
||||
|
||||
if (ca > cb)
|
||||
return +1;
|
||||
|
||||
++ai; ++bi;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
strnatcmp(nat_char const *a, nat_char const *b) {
|
||||
return strnatcmp0(a, b, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Compare, recognizing numeric string and ignoring case. */
|
||||
int
|
||||
strnatcasecmp(nat_char const *a, nat_char const *b) {
|
||||
return strnatcmp0(a, b, 1);
|
||||
}
|
||||
31
deps/strnatcmp.h
vendored
Normal file
31
deps/strnatcmp.h
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||
|
||||
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
|
||||
/* CUSTOMIZATION SECTION
|
||||
*
|
||||
* You can change this typedef, but must then also change the inline
|
||||
* functions in strnatcmp.c */
|
||||
typedef char nat_char;
|
||||
|
||||
int strnatcmp(nat_char const *a, nat_char const *b);
|
||||
int strnatcasecmp(nat_char const *a, nat_char const *b);
|
||||
198
deps/yopt.h
vendored
198
deps/yopt.h
vendored
|
|
@ -1,198 +0,0 @@
|
|||
/* Copyright (c) 2012-2013 Yoran Heling
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* This is a simple command-line option parser. Operation is similar to
|
||||
* getopt_long(), except with a cleaner API.
|
||||
*
|
||||
* This is implemented in a single header file, as it's pretty small and you
|
||||
* generally only use an option parser in a single .c file in your program.
|
||||
*
|
||||
* Supports (examples from GNU tar(1)):
|
||||
* "--gzip"
|
||||
* "--file <arg>"
|
||||
* "--file=<arg>"
|
||||
* "-z"
|
||||
* "-f <arg>"
|
||||
* "-f<arg>"
|
||||
* "-zf <arg>"
|
||||
* "-zf<arg>"
|
||||
* "--" (To stop looking for further options)
|
||||
* "<arg>" (Non-option arguments)
|
||||
*
|
||||
* Issues/non-features:
|
||||
* - An option either requires an argument or it doesn't.
|
||||
* - No way to specify how often an option can/should be used.
|
||||
* - No way to specify the type of an argument (filename/integer/enum/whatever)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef YOPT_H
|
||||
#define YOPT_H
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* Value yopt_next() will return for this option */
|
||||
int val;
|
||||
/* Whether this option needs an argument */
|
||||
int needarg;
|
||||
/* Name(s) of this option, prefixed with '-' or '--' and separated by a
|
||||
* comma. E.g. "-z", "--gzip", "-z,--gzip".
|
||||
* An option can have any number of aliases.
|
||||
*/
|
||||
const char *name;
|
||||
} yopt_opt_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int argc;
|
||||
int cur;
|
||||
int argsep; /* '--' found */
|
||||
char **argv;
|
||||
char *sh;
|
||||
const yopt_opt_t *opts;
|
||||
char errbuf[128];
|
||||
} yopt_t;
|
||||
|
||||
|
||||
/* opts must be an array of options, terminated with an option with val=0 */
|
||||
static inline void yopt_init(yopt_t *o, int argc, char **argv, const yopt_opt_t *opts) {
|
||||
o->argc = argc;
|
||||
o->argv = argv;
|
||||
o->opts = opts;
|
||||
o->cur = 0;
|
||||
o->argsep = 0;
|
||||
o->sh = NULL;
|
||||
}
|
||||
|
||||
|
||||
static inline const yopt_opt_t *_yopt_find(const yopt_opt_t *o, const char *v) {
|
||||
const char *tn, *tv;
|
||||
|
||||
for(; o->val; o++) {
|
||||
tn = o->name;
|
||||
while(*tn) {
|
||||
tv = v;
|
||||
while(*tn && *tn != ',' && *tv && *tv != '=' && *tn == *tv) {
|
||||
tn++;
|
||||
tv++;
|
||||
}
|
||||
if(!(*tn && *tn != ',') && !(*tv && *tv != '='))
|
||||
return o;
|
||||
while(*tn && *tn != ',')
|
||||
tn++;
|
||||
while(*tn == ',')
|
||||
tn++;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static inline int _yopt_err(yopt_t *o, char **val, const char *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vsnprintf(o->errbuf, sizeof(o->errbuf), fmt, va);
|
||||
va_end(va);
|
||||
*val = o->errbuf;
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
/* Return values:
|
||||
* 0 -> Non-option argument, val is its value
|
||||
* -1 -> Last argument has been processed
|
||||
* -2 -> Error, val will contain the error message.
|
||||
* x -> Option with val = x found. If the option requires an argument, its
|
||||
* value will be in val.
|
||||
*/
|
||||
static inline int yopt_next(yopt_t *o, char **val) {
|
||||
const yopt_opt_t *opt;
|
||||
char sh[3];
|
||||
|
||||
*val = NULL;
|
||||
if(o->sh)
|
||||
goto inshort;
|
||||
|
||||
if(++o->cur >= o->argc)
|
||||
return -1;
|
||||
|
||||
if(!o->argsep && o->argv[o->cur][0] == '-' && o->argv[o->cur][1] == '-' && o->argv[o->cur][2] == 0) {
|
||||
o->argsep = 1;
|
||||
if(++o->cur >= o->argc)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(o->argsep || *o->argv[o->cur] != '-') {
|
||||
*val = o->argv[o->cur];
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(o->argv[o->cur][1] != '-') {
|
||||
o->sh = o->argv[o->cur]+1;
|
||||
goto inshort;
|
||||
}
|
||||
|
||||
/* Now we're supposed to have a long option */
|
||||
if(!(opt = _yopt_find(o->opts, o->argv[o->cur])))
|
||||
return _yopt_err(o, val, "Unknown option '%s'", o->argv[o->cur]);
|
||||
if((*val = strchr(o->argv[o->cur], '=')) != NULL)
|
||||
(*val)++;
|
||||
if(!opt->needarg && *val)
|
||||
return _yopt_err(o, val, "Option '%s' does not accept an argument", o->argv[o->cur]);
|
||||
if(opt->needarg && !*val) {
|
||||
if(o->cur+1 >= o->argc)
|
||||
return _yopt_err(o, val, "Option '%s' requires an argument", o->argv[o->cur]);
|
||||
*val = o->argv[++o->cur];
|
||||
}
|
||||
return opt->val;
|
||||
|
||||
/* And here we're supposed to have a short option */
|
||||
inshort:
|
||||
sh[0] = '-';
|
||||
sh[1] = *o->sh;
|
||||
sh[2] = 0;
|
||||
if(!(opt = _yopt_find(o->opts, sh)))
|
||||
return _yopt_err(o, val, "Unknown option '%s'", sh);
|
||||
o->sh++;
|
||||
if(opt->needarg && *o->sh)
|
||||
*val = o->sh;
|
||||
else if(opt->needarg) {
|
||||
if(++o->cur >= o->argc)
|
||||
return _yopt_err(o, val, "Option '%s' requires an argument", sh);
|
||||
*val = o->argv[o->cur];
|
||||
}
|
||||
if(!*o->sh || opt->needarg)
|
||||
o->sh = NULL;
|
||||
return opt->val;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set noet sw=4 ts=4: */
|
||||
445
doc/ncdu.pod
445
doc/ncdu.pod
|
|
@ -1,445 +0,0 @@
|
|||
=head1 NAME
|
||||
|
||||
B<ncdu> - NCurses Disk Usage
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<ncdu> [I<options>] I<dir>
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
ncdu (NCurses Disk Usage) is a curses-based version of the well-known 'du', and
|
||||
provides a fast way to see what directories are using your disk space.
|
||||
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=head2 Mode Selection
|
||||
|
||||
=over
|
||||
|
||||
=item -h, --help
|
||||
|
||||
Print a short help message and quit.
|
||||
|
||||
=item -v, -V, --version
|
||||
|
||||
Print ncdu version and quit.
|
||||
|
||||
=item -f I<FILE>
|
||||
|
||||
Load the given file, which has earlier been created with the C<-o> option. If
|
||||
I<FILE> is equivalent to C<->, the file is read from standard input.
|
||||
|
||||
For the sake of preventing a screw-up, the current version of ncdu will assume
|
||||
that the directory information in the imported file does not represent the
|
||||
filesystem on which the file is being imported. That is, the refresh, file
|
||||
deletion and shell spawning options in the browser will be disabled.
|
||||
|
||||
=item I<dir>
|
||||
|
||||
Scan the given directory.
|
||||
|
||||
=item -o I<FILE>
|
||||
|
||||
Export all necessary information to I<FILE> instead of opening the browser
|
||||
interface. If I<FILE> is C<->, the data is written to standard output. See the
|
||||
examples section below for some handy use cases.
|
||||
|
||||
Be warned that the exported data may grow quite large when exporting a
|
||||
directory with many files. 10.000 files will get you an export in the order of
|
||||
600 to 700 KiB uncompressed, or a little over 100 KiB when compressed with
|
||||
gzip. This scales linearly, so be prepared to handle a few tens of megabytes
|
||||
when dealing with millions of files.
|
||||
|
||||
=item -e
|
||||
|
||||
Enable extended information mode. This will, in addition to the usual file
|
||||
information, also read the ownership, permissions and last modification time
|
||||
for each file. This will result in higher memory usage (by roughly ~30%) and in
|
||||
a larger output file when exporting.
|
||||
|
||||
When using the file export/import function, this flag will need to be added
|
||||
both when exporting (to make sure the information is added to the export), and
|
||||
when importing (to read this extra information in memory). This flag has no
|
||||
effect when importing a file that has been exported without the extended
|
||||
information.
|
||||
|
||||
This enables viewing and sorting by the latest child mtime, or modified time,
|
||||
using 'm' and 'M', respectively.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Interface options
|
||||
|
||||
=over
|
||||
|
||||
=item -0
|
||||
|
||||
Don't give any feedback while scanning a directory or importing a file, other
|
||||
than when a fatal error occurs. Ncurses will not be initialized until the scan
|
||||
is complete. When exporting the data with C<-o>, ncurses will not be
|
||||
initialized at all. This option is the default when exporting to standard
|
||||
output.
|
||||
|
||||
=item -1
|
||||
|
||||
Similar to C<-0>, but does give feedback on the scanning progress with a single
|
||||
line of output. This option is the default when exporting to a file.
|
||||
|
||||
In some cases, the ncurses browser interface which you'll see after the
|
||||
scan/import is complete may look garbled when using this option. If you're not
|
||||
exporting to a file, C<-2> is probably a better choice.
|
||||
|
||||
=item -2
|
||||
|
||||
Provide a full-screen ncurses interface while scanning a directory or importing
|
||||
a file. This is the only interface that provides feedback on any non-fatal
|
||||
errors while scanning.
|
||||
|
||||
=item -q
|
||||
|
||||
Quiet mode. While scanning or importing the directory, ncdu will update the
|
||||
screen 10 times a second by default, this will be decreased to once every 2
|
||||
seconds in quiet mode. Use this feature to save bandwidth over remote
|
||||
connections. This option has no effect when C<-0> is used.
|
||||
|
||||
=item -r
|
||||
|
||||
Read-only mode. This will disable the built-in file deletion feature. This
|
||||
option has no effect when C<-o> is used, because there will not be a browser
|
||||
interface in that case. It has no effect when C<-f> is used, either, because
|
||||
the deletion feature is disabled in that case anyway.
|
||||
|
||||
WARNING: This option will only prevent deletion through the file browser. It is
|
||||
still possible to spawn a shell from ncdu and delete or modify files from
|
||||
there. To disable that feature as well, pass the C<-r> option twice (see
|
||||
C<-rr>).
|
||||
|
||||
=item -rr
|
||||
|
||||
In addition to C<-r>, this will also disable the shell spawning feature of the
|
||||
file browser.
|
||||
|
||||
=item --si
|
||||
|
||||
List sizes using base 10 prefixes, that is, powers of 1000 (KB, MB, etc), as
|
||||
defined in the International System of Units (SI), instead of the usual base 2
|
||||
prefixes, that is, powers of 1024 (KiB, MiB, etc).
|
||||
|
||||
=item --confirm-quit
|
||||
|
||||
Requires a confirmation before quitting ncdu. Very helpful when you
|
||||
accidentally press 'q' during or after a very long scan.
|
||||
|
||||
=item --color I<SCHEME>
|
||||
|
||||
Select a color scheme. Currently only two schemes are recognized: I<off> to
|
||||
disable colors (the default) and I<dark> for a color scheme intended for dark
|
||||
backgrounds.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Scan Options
|
||||
|
||||
These options affect the scanning progress, and have no effect when importing
|
||||
directory information from a file.
|
||||
|
||||
=over
|
||||
|
||||
=item -x
|
||||
|
||||
Do not cross filesystem boundaries, i.e. only count files and directories on
|
||||
the same filesystem as the directory being scanned.
|
||||
|
||||
=item --exclude I<PATTERN>
|
||||
|
||||
Exclude files that match I<PATTERN>. The files will still be displayed by
|
||||
default, but are not counted towards the disk usage statistics. This argument
|
||||
can be added multiple times to add more patterns.
|
||||
|
||||
=item -X I<FILE>, --exclude-from I<FILE>
|
||||
|
||||
Exclude files that match any pattern in I<FILE>. Patterns should be separated
|
||||
by a newline.
|
||||
|
||||
=item --exclude-caches
|
||||
|
||||
Exclude directories containing CACHEDIR.TAG. The directories will still be
|
||||
displayed, but not their content, and they are not counted towards the disk
|
||||
usage statistics.
|
||||
See http://www.brynosaurus.com/cachedir/
|
||||
|
||||
=item -L, --follow-symlinks
|
||||
|
||||
Follow symlinks and count the size of the file they point to. As of ncdu 1.14,
|
||||
this option will not follow symlinks to directories and will count each
|
||||
symlinked file as a unique file (i.e. unlike how hard links are handled). This
|
||||
is subject to change in later versions.
|
||||
|
||||
=item --exclude-firmlinks
|
||||
|
||||
(MacOS only) Exclude firmlinks.
|
||||
|
||||
=item --exclude-kernfs
|
||||
|
||||
(Linux only) Exclude Linux pseudo filesystems, e.g. /proc (procfs), /sys (sysfs).
|
||||
|
||||
The complete list of currently known pseudo filesystems is: binfmt, bpf, cgroup,
|
||||
cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 KEYS
|
||||
|
||||
=over
|
||||
|
||||
=item ?
|
||||
|
||||
Show help + keys + about screen
|
||||
|
||||
=item up, down j, k
|
||||
|
||||
Cycle through the items
|
||||
|
||||
=item right, enter, l
|
||||
|
||||
Open selected directory
|
||||
|
||||
=item left, <, h
|
||||
|
||||
Go to parent directory
|
||||
|
||||
=item n
|
||||
|
||||
Order by filename (press again for descending order)
|
||||
|
||||
=item s
|
||||
|
||||
Order by filesize (press again for descending order)
|
||||
|
||||
=item C
|
||||
|
||||
Order by number of items (press again for descending order)
|
||||
|
||||
=item a
|
||||
|
||||
Toggle between showing disk usage and showing apparent size.
|
||||
|
||||
=item M
|
||||
|
||||
Order by latest child mtime, or modified time. (press again for descending order)
|
||||
Requires the -e flag.
|
||||
|
||||
=item d
|
||||
|
||||
Delete the selected file or directory. An error message will be shown when the
|
||||
contents of the directory do not match or do not exist anymore on the
|
||||
filesystem.
|
||||
|
||||
=item t
|
||||
|
||||
Toggle dirs before files when sorting.
|
||||
|
||||
=item g
|
||||
|
||||
Toggle between showing percentage, graph, both, or none. Percentage is relative
|
||||
to the size of the current directory, graph is relative to the largest item in
|
||||
the current directory.
|
||||
|
||||
=item c
|
||||
|
||||
Toggle display of child item counts.
|
||||
|
||||
=item m
|
||||
|
||||
Toggle display of latest child mtime, or modified time. Requires the -e flag.
|
||||
|
||||
=item e
|
||||
|
||||
Show/hide 'hidden' or 'excluded' files and directories. Please note that even
|
||||
though you can't see the hidden files and directories, they are still there and
|
||||
they are still included in the directory sizes. If you suspect that the totals
|
||||
shown at the bottom of the screen are not correct, make sure you haven't
|
||||
enabled this option.
|
||||
|
||||
=item i
|
||||
|
||||
Show information about the current selected item.
|
||||
|
||||
=item r
|
||||
|
||||
Refresh/recalculate the current directory.
|
||||
|
||||
=item b
|
||||
|
||||
Spawn shell in current directory.
|
||||
|
||||
Ncdu will determine your preferred shell from the C<NCDU_SHELL> or C<SHELL>
|
||||
variable (in that order), or will call C</bin/sh> if neither are set. This
|
||||
allows you to also configure another command to be run when he 'b' key is
|
||||
pressed. For example, to spawn the L<vifm(1)> file manager instead of a shell,
|
||||
run ncdu as follows:
|
||||
|
||||
export NCDU_SHELL=vifm
|
||||
ncdu
|
||||
|
||||
=item q
|
||||
|
||||
Quit
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 FILE FLAGS
|
||||
|
||||
Entries in the browser interface may be prefixed by a one-character flag. These
|
||||
flags have the following meaning:
|
||||
|
||||
=over
|
||||
|
||||
=item !
|
||||
|
||||
An error occurred while reading this directory.
|
||||
|
||||
=item .
|
||||
|
||||
An error occurred while reading a subdirectory, so the indicated size may not be
|
||||
correct.
|
||||
|
||||
=item <
|
||||
|
||||
File or directory is excluded from the statistics by using exclude patterns.
|
||||
|
||||
=item >
|
||||
|
||||
Directory is on another filesystem.
|
||||
|
||||
=item ^
|
||||
|
||||
Directory is excluded from the statistics due to being a Linux pseudo filesystem.
|
||||
|
||||
=item @
|
||||
|
||||
This is neither a file nor a folder (symlink, socket, ...).
|
||||
|
||||
=item H
|
||||
|
||||
Same file was already counted (hard link).
|
||||
|
||||
=item e
|
||||
|
||||
Empty directory.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
To scan and browse the directory you're currently in, all you need is a simple:
|
||||
|
||||
ncdu
|
||||
|
||||
If you want to scan a full filesystem, your root filesystem, for example, then
|
||||
you'll want to use C<-x>:
|
||||
|
||||
ncdu -x /
|
||||
|
||||
Since scanning a large directory may take a while, you can scan a directory and
|
||||
export the results for later viewing:
|
||||
|
||||
ncdu -1xo- / | gzip >export.gz
|
||||
# ...some time later:
|
||||
zcat export.gz | ncdu -f-
|
||||
|
||||
To export from a cron job, make sure to replace C<-1> with C<-0> to suppress
|
||||
any unnecessary output.
|
||||
|
||||
You can also export a directory and browse it once scanning is done:
|
||||
|
||||
ncdu -o- | tee export.file | ./ncdu -f-
|
||||
|
||||
The same is possible with gzip compression, but is a bit kludgey:
|
||||
|
||||
ncdu -o- | gzip | tee export.gz | gunzip | ./ncdu -f-
|
||||
|
||||
To scan a system remotely, but browse through the files locally:
|
||||
|
||||
ssh -C user@system ncdu -o- / | ./ncdu -f-
|
||||
|
||||
The C<-C> option to ssh enables compression, which will be very useful over
|
||||
slow links. Remote scanning and local viewing has two major advantages when
|
||||
compared to running ncdu directly on the remote system: You can browse through
|
||||
the scanned directory on the local system without any network latency, and ncdu
|
||||
does not keep the entire directory structure in memory when exporting, so you
|
||||
won't consume much memory on the remote system.
|
||||
|
||||
|
||||
=head1 HARD LINKS
|
||||
|
||||
Every disk usage analysis utility has its own way of (not) counting hard links.
|
||||
There does not seem to be any universally agreed method of handling hard links,
|
||||
and it is even inconsistent among different versions of ncdu. This section
|
||||
explains what each version of ncdu does.
|
||||
|
||||
ncdu 1.5 and below does not support any hard link detection at all: each link
|
||||
is considered a separate inode and its size is counted for every link. This
|
||||
means that the displayed directory sizes are incorrect when analyzing
|
||||
directories which contain hard links.
|
||||
|
||||
ncdu 1.6 has basic hard link detection: When a link to a previously encountered
|
||||
inode is detected, the link is considered to have a file size of zero bytes.
|
||||
Its size is not counted again, and the link is indicated in the browser
|
||||
interface with a 'H' mark. The displayed directory sizes are only correct when
|
||||
all links to an inode reside within that directory. When this is not the case,
|
||||
the sizes may or may not be correct, depending on which links were considered
|
||||
as "duplicate" and which as "original". The indicated size of the topmost
|
||||
directory (that is, the one specified on the command line upon starting ncdu)
|
||||
is always correct.
|
||||
|
||||
ncdu 1.7 and later has improved hard link detection. Each file that has more
|
||||
than two links has the "H" mark visible in the browser interface. Each hard
|
||||
link is counted exactly once for every directory it appears in. The indicated
|
||||
size of each directory is therefore, correctly, the sum of the sizes of all
|
||||
unique inodes that can be found in that directory. Note, however, that this may
|
||||
not always be same as the space that will be reclaimed after deleting the
|
||||
directory, as some inodes may still be accessible from hard links outside it.
|
||||
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
Directory hard links are not supported. They will not be detected as being hard
|
||||
links, and will thus be scanned and counted multiple times.
|
||||
|
||||
Some minor glitches may appear when displaying filenames that contain multibyte
|
||||
or multicolumn characters.
|
||||
|
||||
All sizes are internally represented as a signed 64bit integer. If you have a
|
||||
directory larger than 8 EiB minus one byte, ncdu will clip its size to 8 EiB
|
||||
minus one byte. When deleting items in a directory with a clipped size, the
|
||||
resulting sizes will be incorrect.
|
||||
|
||||
Item counts are stored in a signed 32-bit integer without overflow detection.
|
||||
If you have a directory with more than 2 billion files, quite literally
|
||||
anything can happen.
|
||||
|
||||
On macOS 10.15 and later, running ncdu on the root directory without
|
||||
`--exclude-firmlinks` may cause directories to be scanned and counted multiple
|
||||
times. Firmlink cycles are currently (1.15.1) not detected, so it may also
|
||||
cause ncdu to get stuck in an infinite loop and eventually run out of memory.
|
||||
|
||||
Please report any other bugs you may find at the bug tracker, which can be
|
||||
found on the web site at https://dev.yorhel.nl/ncdu
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Written by Yoran Heling <projects@yorhel.nl>.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<du(1)>
|
||||
513
ncdu.1
Normal file
513
ncdu.1
Normal file
|
|
@ -0,0 +1,513 @@
|
|||
.\" SPDX-FileCopyrightText: Yorhel <projects@yorhel.nl>
|
||||
.\" SPDX-License-Identifier: MIT
|
||||
.Dd March 5, 2025
|
||||
.Dt NCDU 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ncdu
|
||||
.Nd NCurses Disk Usage
|
||||
.
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl f Ar file
|
||||
.Op Fl o Ar file
|
||||
.Op Fl e , \-extended , \-no\-extended
|
||||
.Op Fl \-ignore\-config
|
||||
.Op Fl x , \-one\-file\-system , \-cross\-file\-system
|
||||
.Op Fl \-exclude Ar pattern
|
||||
.Op Fl X , \-exclude\-from Ar file
|
||||
.Op Fl \-include\-caches , \-exclude\-caches
|
||||
.Op Fl L , \-follow\-symlinks , \-no\-follow\-symlinks
|
||||
.Op Fl \-include\-kernfs , \-exclude\-kernfs
|
||||
.Op Fl \-exclude\-firmlinks , \-follow\-firmlinks
|
||||
.Op Fl 0 , 1 , 2
|
||||
.Op Fl q , \-slow\-ui\-updates , \-fast\-ui\-updates
|
||||
.Op Fl \-enable\-shell , \-disable\-shell
|
||||
.Op Fl \-enable\-delete , \-disable\-delete
|
||||
.Op Fl \-enable\-refresh , \-disable\-refresh
|
||||
.Op Fl r
|
||||
.Op Fl \-si , \-no\-si
|
||||
.Op Fl \-disk\-usage , \-apparent\-size
|
||||
.Op Fl \-show\-hidden , \-hide\-hidden
|
||||
.Op Fl \-show\-itemcount , \-hide\-itemcount
|
||||
.Op Fl \-show\-mtime , \-hide\-mtime
|
||||
.Op Fl \-show\-graph , \-hide\-graph
|
||||
.Op Fl \-show\-percent , \-hide\-percent
|
||||
.Op Fl \-graph\-style Ar hash | half\-block | eighth\-block
|
||||
.Op Fl \-sort Ar column
|
||||
.Op Fl \-enable\-natsort , \-disable\-natsort
|
||||
.Op Fl \-group\-directories\-first , \-no\-group\-directories\-first
|
||||
.Op Fl \-confirm\-quit , \-no\-confirm\-quit
|
||||
.Op Fl \-confirm\-delete , \-no\-confirm\-delete
|
||||
.Op Fl \-color Ar off | dark | dark-bg
|
||||
.Op Ar path
|
||||
.Nm
|
||||
.Op Fl h , \-help
|
||||
.Nm
|
||||
.Op Fl v , V , \-version
|
||||
.
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
(NCurses Disk Usage) is an interactive curses-based version of the well-known
|
||||
.Xr du 1 ,
|
||||
and provides a fast way to see what directories are using your disk space.
|
||||
.
|
||||
.Sh OPTIONS
|
||||
.Ss Mode Selection
|
||||
.Bl -tag -width Ds
|
||||
.It Fl h , \-help
|
||||
Print a short help message and quit.
|
||||
.It Fl v , V , \-version
|
||||
Print version and quit.
|
||||
.It Fl f Ar file
|
||||
Load the given file, which has earlier been created with the
|
||||
.Fl o
|
||||
flag.
|
||||
If
|
||||
.Ar file
|
||||
is equivalent to '\-', the file is read from standard input.
|
||||
.Pp
|
||||
For the sake of preventing a screw-up, the current version of
|
||||
.Nm
|
||||
will assume that the directory information in the imported file does not
|
||||
represent the filesystem on which the file is being imported.
|
||||
That is, the refresh, file deletion and shell spawning options in the browser
|
||||
will be disabled.
|
||||
.It Ar dir
|
||||
Scan the given directory.
|
||||
.It Fl o Ar file
|
||||
Export all necessary information to
|
||||
.Ar file
|
||||
instead of opening the browser interface.
|
||||
If
|
||||
.Ar file
|
||||
is '\-', the data is written to standard output.
|
||||
See the examples section below for some handy use cases.
|
||||
.Pp
|
||||
Be warned that the exported data may grow quite large when exporting a
|
||||
directory with many files.
|
||||
10.000 files will get you an export in the order of 600 to 700 KiB
|
||||
uncompressed, or a little over 100 KiB when compressed with gzip.
|
||||
This scales linearly, so be prepared to handle a few tens of megabytes when
|
||||
dealing with millions of files.
|
||||
.It Fl e , \-extended , \-no\-extended
|
||||
Enable/disable extended information mode.
|
||||
This will, in addition to the usual file information, also read the ownership,
|
||||
permissions and last modification time for each file.
|
||||
This will result in higher memory usage (by roughly ~30%) and in a larger
|
||||
output file when exporting.
|
||||
.Pp
|
||||
When using the file export/import function, this flag should be added both when
|
||||
exporting (to make sure the information is added to the export) and when
|
||||
importing (to read this extra information in memory).
|
||||
This flag has no effect when importing a file that has been exported without
|
||||
the extended information.
|
||||
.Pp
|
||||
This enables viewing and sorting by the latest child mtime, or modified time,
|
||||
using 'm' and 'M', respectively.
|
||||
.It Fl \-ignore\-config
|
||||
Do not attempt to load any configuration files.
|
||||
.El
|
||||
.
|
||||
.Ss Scan Options
|
||||
These options affect the scanning progress, they have no effect when importing
|
||||
directory information from a file.
|
||||
.Bl -tag -width Ds
|
||||
.It Fl x , \-one\-file\-system
|
||||
Do not cross filesystem boundaries, i.e. only count files and directories on
|
||||
the same filesystem as the directory being scanned.
|
||||
.It Fl \-cross\-file\-system
|
||||
Do cross filesystem boundaries.
|
||||
This is the default, but can be specified to overrule a previously configured
|
||||
.Fl x .
|
||||
.It Fl \-exclude Ar pattern
|
||||
Exclude files that match
|
||||
.Ar pattern .
|
||||
The files are still displayed by default, but are not counted towards the disk
|
||||
usage statistics.
|
||||
This argument can be added multiple times to add more patterns.
|
||||
.It Fl X , \-exclude\-from Ar file
|
||||
Exclude files that match any pattern in
|
||||
.Ar file .
|
||||
Patterns should be separated by a newline.
|
||||
.It Fl \-include\-caches , \-exclude\-caches
|
||||
Include (default) or exclude directories containing
|
||||
.Pa CACHEDIR.TAG .
|
||||
Excluded cache directories are still displayed, but their contents will not be
|
||||
scanned or counted towards the disk usage statistics.
|
||||
.Lk https://bford.info/cachedir/
|
||||
.It Fl L , \-follow\-symlinks , \-no\-follow\-symlinks
|
||||
Follow (or not) symlinks and count the size of the file they point to.
|
||||
This option does not follow symlinks to directories and will cause each
|
||||
symlinked file to count as a unique file.
|
||||
This is different from how hard links are handled.
|
||||
The exact counting behavior of this flag is subject to change in the future.
|
||||
.It Fl \-include\-kernfs , \-exclude\-kernfs
|
||||
(Linux only) Include (default) or exclude Linux pseudo filesystems such as
|
||||
.Pa /proc
|
||||
(procfs) and
|
||||
.Pa /sys
|
||||
(sysfs).
|
||||
.Pp
|
||||
The complete list of currently known pseudo filesystems is: binfmt, bpf, cgroup,
|
||||
cgroup2, debug, devpts, proc, pstore, security, selinux, sys, trace.
|
||||
.It Fl \-exclude\-firmlinks , \-follow\-firmlinks
|
||||
(MacOS only) Exclude or follow firmlinks.
|
||||
.El
|
||||
.Ss Interface Options
|
||||
.Bl -tag -width Ds
|
||||
.It Fl 0
|
||||
Don't give any feedback while scanning a directory or importing a file, except
|
||||
when a fatal error occurs.
|
||||
Ncurses will not be initialized until the scan is complete.
|
||||
When exporting the data with
|
||||
.Fl o ,
|
||||
ncurses will not be initialized at all.
|
||||
This option is the default when exporting to standard output.
|
||||
.It Fl 1
|
||||
Write progress information to the terminal, but don't open a full-screen
|
||||
ncurses interface.
|
||||
This option is the default when exporting to a file.
|
||||
.Pp
|
||||
In some cases, the ncurses browser interface which you'll see after the
|
||||
scan/import is complete may look garbled when using this option.
|
||||
If you're not exporting to a file,
|
||||
.Fl 2
|
||||
is usually a better choice.
|
||||
.It Fl 2
|
||||
Show a full-screen ncurses interface while scanning a directory or importing
|
||||
a file.
|
||||
This is the only interface that provides feedback on any non-fatal errors while
|
||||
scanning.
|
||||
.It Fl q , \-slow\-ui\-updates , \-fast\-ui\-updates
|
||||
Change the UI update interval while scanning or importing.
|
||||
.Nm
|
||||
updates the screen 10 times a second by default (with
|
||||
.Fl \-fast\-ui\-updates
|
||||
), this can be decreased to once every 2 seconds with
|
||||
.Fl q
|
||||
or
|
||||
.Fl \-slow\-ui\-updates .
|
||||
This option can be used to save bandwidth over remote connections.
|
||||
This option has no effect in combination with
|
||||
.Fl 0 .
|
||||
.It Fl \-enable\-shell , \-disable\-shell
|
||||
Enable or disable shell spawning from the file browser.
|
||||
This feature is enabled by default when scanning a live directory and disabled
|
||||
when importing from file.
|
||||
.It Fl \-enable\-delete , \-disable\-delete
|
||||
Enable or disable the built-in file deletion feature.
|
||||
This feature is enabled by default when scanning a live directory and disabled
|
||||
when importing from file.
|
||||
Explicitly disabling the deletion feature can work as a safeguard to prevent
|
||||
accidental data loss.
|
||||
.It Fl \-enable\-refresh , \-disable\-refresh
|
||||
Enable or disable directory refreshing from the file browser.
|
||||
This feature is enabled by default when scanning a live directory and disabled
|
||||
when importing from file.
|
||||
.It Fl r
|
||||
Read-only mode.
|
||||
When given once, this is an alias for
|
||||
.Fl \-disable\-delete ,
|
||||
when given twice it will also add
|
||||
.Fl \-disable\-shell ,
|
||||
thus ensuring that there is no way to modify the file system from within
|
||||
.Nm .
|
||||
.It Fl \-si , \-no\-si
|
||||
List sizes using base 10 prefixes, that is, powers of 1000 (kB, MB, etc), as
|
||||
defined in the International System of Units (SI), instead of the usual base 2
|
||||
prefixes (KiB, MiB, etc).
|
||||
.It Fl \-disk\-usage , \-apparent\-size
|
||||
Select whether to display disk usage (default) or apparent sizes.
|
||||
Can also be toggled in the file browser with the 'a' key.
|
||||
.It Fl \-show\-hidden , \-hide\-hidden
|
||||
Show (default) or hide "hidden" and excluded files.
|
||||
Can also be toggled in the file browser with the 'e' key.
|
||||
.It Fl \-show\-itemcount , \-hide\-itemcount
|
||||
Show or hide (default) the item counts column.
|
||||
Can also be toggled in the file browser with the 'c' key.
|
||||
.It Fl \-show\-mtime , \-hide\-mtime
|
||||
Show or hide (default) the last modification time column.
|
||||
Can also be toggled in the file browser with the 'm' key.
|
||||
This option is ignored when not in extended mode, see
|
||||
.Fl e .
|
||||
.It Fl \-show\-graph , \-hide\-graph
|
||||
Show (default) or hide the relative size bar column.
|
||||
Can also be toggled in the file browser with the 'g' key.
|
||||
.It Fl \-show\-percent , \-hide\-percent
|
||||
Show (default) or hide the relative size percent column.
|
||||
Can also be toggled in the file browser with the 'g' key.
|
||||
.It Fl \-graph\-style Ar hash | half\-block | eighth\-block
|
||||
Change the way that the relative size bar column is drawn.
|
||||
Recognized values are
|
||||
.Ar hash
|
||||
to draw ASCII '#' characters (default and most portable),
|
||||
.Ar half\-block
|
||||
to use half-block drawing characters or
|
||||
.Ar eighth\-block
|
||||
to use eighth-block drawing characters.
|
||||
Eighth-block characters are the most precise but may not render correctly in
|
||||
all terminals.
|
||||
.It Fl \-sort Ar column
|
||||
Change the default column to sort on.
|
||||
Accepted values are
|
||||
.Ar disk\-usage
|
||||
(the default),
|
||||
.Ar name , apparent\-size , itemcount
|
||||
or
|
||||
.Ar mtime .
|
||||
The latter only makes sense in extended mode, see
|
||||
.Fl e .
|
||||
.Pp
|
||||
The column name can be suffixed with
|
||||
.Li \-asc
|
||||
or
|
||||
.Li \-desc
|
||||
to change the order to ascending or descending, respectively.
|
||||
For example,
|
||||
.Li \-\-sort=name\-desc
|
||||
to sort by name in descending order.
|
||||
.It Fl \-enable\-natsort , \-disable\-natsort
|
||||
Enable (default) or disable natural sort when sorting by file name.
|
||||
.It Fl \-group\-directories\-first , \-no\-group\-directories\-first
|
||||
Sort (or not) directories before files.
|
||||
.It Fl \-confirm\-quit , \-no\-confirm\-quit
|
||||
Require a confirmation before quitting ncdu.
|
||||
Can be helpful when you accidentally press 'q' during or after a very long scan.
|
||||
.It Fl \-confirm\-delete , \-no\-confirm\-delete
|
||||
Require a confirmation before deleting a file or directory.
|
||||
Enabled by default, but can be disabled if you're absolutely sure you won't
|
||||
accidentally press 'd'.
|
||||
.It Fl \-color Ar off | dark | dark-bg
|
||||
Set the color scheme.
|
||||
The following schemes are recognized:
|
||||
.Ar off
|
||||
to disable colors,
|
||||
.Ar dark
|
||||
for a color scheme intended for dark backgrounds and
|
||||
.Ar dark\-bg
|
||||
for a variation of the
|
||||
.Ar dark
|
||||
color scheme that also works in terminals with a light background.
|
||||
.Pp
|
||||
The default is
|
||||
.Ar off .
|
||||
.El
|
||||
.
|
||||
.Sh CONFIGURATION
|
||||
.Nm
|
||||
can be configured by placing command-line options in
|
||||
.Pa /etc/ncdu.conf
|
||||
or
|
||||
.Pa $HOME/.config/ncdu/config .
|
||||
If both files exist, the system configuration will be loaded before the user
|
||||
configuration, allowing users to override options set in the system
|
||||
configuration.
|
||||
Options given on the command line will override options set in the
|
||||
configuration files.
|
||||
The files will not be read at all when
|
||||
.Fl \-ignore\-config
|
||||
is given on the command line.
|
||||
.Pp
|
||||
The configuration file format is simply one command line option per line.
|
||||
Lines starting with '#' are ignored.
|
||||
A line can be prefixed with '@' to suppress errors while parsing the option.
|
||||
Example configuration file:
|
||||
.Bd -literal -offset indent
|
||||
# Always enable extended mode
|
||||
\-e
|
||||
|
||||
# Disable file deletion
|
||||
\-\-disable\-delete
|
||||
|
||||
# Exclude .git directories
|
||||
\-\-exclude .git
|
||||
|
||||
# Read excludes from ~/.ncduexcludes, ignore error if the file does not exist
|
||||
@--exclude-from ~/.ncduexcludes
|
||||
.Ed
|
||||
.
|
||||
.Sh KEYS
|
||||
.Bl -tag -width Ds
|
||||
.It ?
|
||||
Open help + keys + about screen
|
||||
.It up , down , j , k
|
||||
Cycle through the items
|
||||
.It right, enter, l
|
||||
Open selected directory
|
||||
.It left, <, h
|
||||
Go to parent directory
|
||||
.It n
|
||||
Order by filename (press again for descending order)
|
||||
.It s
|
||||
Order by filesize (press again for descending order)
|
||||
.It C
|
||||
Order by number of items (press again for descending order)
|
||||
.It a
|
||||
Toggle between showing disk usage and showing apparent size.
|
||||
.It M
|
||||
Order by latest child mtime, or modified time (press again for descending
|
||||
order).
|
||||
Requires the
|
||||
.Fl e
|
||||
flag.
|
||||
.It d
|
||||
Delete the selected file or directory.
|
||||
An error message will be shown when the contents of the directory do not match
|
||||
or do not exist anymore on the filesystem.
|
||||
.It t
|
||||
Toggle dirs before files when sorting.
|
||||
.It g
|
||||
Toggle between showing percentage, graph, both, or none.
|
||||
Percentage is relative to the size of the current directory, graph is relative
|
||||
to the largest item in the current directory.
|
||||
.It c
|
||||
Toggle display of child item counts.
|
||||
.It m
|
||||
Toggle display of latest child mtime, or modified time.
|
||||
Requires the
|
||||
.Fl e
|
||||
flag.
|
||||
.It e
|
||||
Show/hide 'hidden' or 'excluded' files and directories.
|
||||
Be aware that even if you can't see the hidden files and directories, they are
|
||||
still there and they are still included in the directory sizes.
|
||||
If you suspect that the totals shown at the bottom of the screen are not
|
||||
correct, make sure you haven't enabled this option.
|
||||
.It i
|
||||
Show information about the current selected item.
|
||||
.It r
|
||||
Refresh/recalculate the current directory.
|
||||
.It b
|
||||
Spawn shell in current directory.
|
||||
.Pp
|
||||
.Nm
|
||||
determines your preferred shell from the
|
||||
.Ev NCDU_SHELL
|
||||
or
|
||||
.Ev SHELL
|
||||
environment variable (in that order), or calls
|
||||
.Pa /bin/sh
|
||||
if neither are set.
|
||||
This allows you to also configure another command to be run when he 'b' key is
|
||||
pressed.
|
||||
For example, to spawn the
|
||||
.Xr vifm 1
|
||||
file manager instead of a shell, run
|
||||
.Nm
|
||||
as follows:
|
||||
.Dl NCDU_SHELL=vifm ncdu
|
||||
The
|
||||
.Ev NCDU_LEVEL
|
||||
environment variable is set or incremented before spawning the shell, allowing
|
||||
you to detect if your shell is running from within
|
||||
.Nm .
|
||||
This can be useful to avoid nesting multiple instances, although
|
||||
.Nm
|
||||
itself does not (currently) warn about or prevent this situation.
|
||||
.It q
|
||||
Quit
|
||||
.El
|
||||
.
|
||||
.Sh FILE FLAGS
|
||||
Entries in the browser interface may be prefixed by a one\-character flag.
|
||||
These flags have the following meaning:
|
||||
.Bl -tag -width Ds
|
||||
.It !
|
||||
An error occurred while reading this directory.
|
||||
.It \.
|
||||
An error occurred while reading a subdirectory, so the indicated size may not
|
||||
be correct.
|
||||
.It <
|
||||
File or directory is excluded from the statistics by using exclude patterns.
|
||||
.It >
|
||||
Directory is on another filesystem.
|
||||
.It ^
|
||||
Directory is excluded from the statistics due to being a Linux pseudo
|
||||
filesystem.
|
||||
.It @
|
||||
This is neither a file nor a folder (symlink, socket, ...).
|
||||
.It H
|
||||
Same file was already counted (hard link).
|
||||
.It e
|
||||
Empty directory.
|
||||
.El
|
||||
.
|
||||
.Sh EXAMPLES
|
||||
To scan and browse the directory you're currently in, all you need is a simple:
|
||||
.Dl ncdu
|
||||
To scan a full filesystem, for example your root filesystem, you'll want to use
|
||||
.Fl x :
|
||||
.Dl ncdu \-x /
|
||||
.Pp
|
||||
Since scanning a large directory may take a while, you can scan a directory and
|
||||
export the results for later viewing:
|
||||
.Bd -literal -offset indent
|
||||
ncdu \-1xo\- / | gzip >export.gz
|
||||
# ...some time later:
|
||||
zcat export.gz | ncdu \-f\-
|
||||
.Ed
|
||||
To export from a cron job, make sure to replace
|
||||
.Fl 1
|
||||
with
|
||||
.Fl 0
|
||||
to suppress unnecessary progress output.
|
||||
.Pp
|
||||
You can also export a directory and browse it once scanning is done:
|
||||
.Dl ncdu \-o\- | tee export.file | ./ncdu \-f\-
|
||||
The same is possible with gzip compression, but is a bit kludgey:
|
||||
.Dl ncdu \-o\- | gzip | tee export.gz | gunzip | ./ncdu \-f\-
|
||||
.Pp
|
||||
To scan a system remotely, but browse through the files locally:
|
||||
.Dl ssh \-C user@system ncdu \-o\- / | ./ncdu \-f\-
|
||||
The
|
||||
.Fl C
|
||||
option to ssh enables compression, which will be very useful over slow links.
|
||||
Remote scanning and local viewing has two major advantages when
|
||||
compared to running
|
||||
.Nm
|
||||
directly on the remote system: You can browse through the scanned directory on
|
||||
the local system without any network latency, and
|
||||
.Nm
|
||||
does not keep the entire directory structure in memory when exporting, so this
|
||||
won't consume much memory on the remote system.
|
||||
.
|
||||
.Sh SEE ALSO
|
||||
.Xr du 1 ,
|
||||
.Xr tree 1 .
|
||||
.Pp
|
||||
.Nm
|
||||
has a website:
|
||||
.Lk https://dev.yorhel.nl/ncdu
|
||||
.
|
||||
.Sh AUTHORS
|
||||
Written by
|
||||
.An Yorhel Aq Mt projects@yorhel.nl
|
||||
.
|
||||
.Sh BUGS
|
||||
Directory hard links are not supported.
|
||||
They are not detected as being hard links, and will thus get scanned and
|
||||
counted multiple times.
|
||||
.Pp
|
||||
Some minor glitches may appear when displaying filenames that contain multibyte
|
||||
or multicolumn characters.
|
||||
.Pp
|
||||
All sizes are internally represented as a signed 64bit integer.
|
||||
If you have a directory larger than 8 EiB minus one byte, ncdu will clip its
|
||||
size to 8 EiB minus one byte.
|
||||
When deleting or refreshing items in a directory with a clipped size, the
|
||||
resulting sizes will be incorrect.
|
||||
Item counts are stored in a 32-bit integer without overflow detection.
|
||||
If you have a directory with more than 2 billion files, quite literally
|
||||
anything can happen.
|
||||
.Pp
|
||||
On macOS 10.15 and later, running ncdu on the root directory without
|
||||
.Fl \-exclude\-firmlinks
|
||||
may cause directories to be scanned and counted multiple times.
|
||||
Firmlink cycles are not detected, so it may also cause
|
||||
.Nm
|
||||
to get stuck in an infinite loop and eventually run out of memory.
|
||||
.Pp
|
||||
Please report any other bugs you may find at the bug tracker, which can be
|
||||
found on the web site at
|
||||
.Lk https://dev.yorhel.nl/ncdu
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/* ncdu - NCurses Disk Usage
|
||||
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
13
src/delete.c
13
src/delete.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
src/global.h
30
src/global.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
487
src/main.c
487
src/main.c
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
24
src/shell.c
24
src/shell.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
93
src/util.c
93
src/util.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
51
src/util.h
51
src/util.h
|
|
@ -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
|
||||
|
||||
|
|
|
|||
130
static/build.sh
130
static/build.sh
|
|
@ -1,130 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script is based on static/build.sh from the ncdc git repo.
|
||||
# Only i486 and arm arches are supported. i486 should perform well enough, so
|
||||
# x86_64 isn't really necessary. I can't test any other arches.
|
||||
#
|
||||
# This script assumes that you have the musl-cross cross compilers installed in
|
||||
# $MUSL_CROSS_PATH.
|
||||
#
|
||||
# Usage:
|
||||
# ./build.sh $arch
|
||||
# where $arch = 'arm', 'i486' or 'x86_64'
|
||||
|
||||
MUSL_CROSS_PATH=/opt/cross
|
||||
NCURSES_VERSION=6.0
|
||||
|
||||
export CFLAGS="-O3 -g -static"
|
||||
|
||||
# (The variables below are automatically set by the functions, they're defined
|
||||
# here to make sure they have global scope and for documentation purposes.)
|
||||
|
||||
# This is the arch we're compiling for, e.g. arm/mipsel.
|
||||
TARGET=
|
||||
# This is the name of the toolchain we're using, and thus the value we should
|
||||
# pass to autoconf's --host argument.
|
||||
HOST=
|
||||
# Installation prefix.
|
||||
PREFIX=
|
||||
# Path of the extracted source code of the package we're currently building.
|
||||
srcdir=
|
||||
|
||||
mkdir -p tarballs
|
||||
|
||||
|
||||
# "Fetch, Extract, Move"
|
||||
fem() { # base-url name targerdir extractdir
|
||||
echo "====== Fetching and extracting $1 $2"
|
||||
cd tarballs
|
||||
if [ -n "$4" ]; then
|
||||
EDIR="$4"
|
||||
else
|
||||
EDIR=$(basename $(basename $(basename $2 .tar.bz2) .tar.gz) .tar.xz)
|
||||
fi
|
||||
if [ ! -e "$2" ]; then
|
||||
wget "$1$2" || exit
|
||||
fi
|
||||
if [ ! -d "$3" ]; then
|
||||
tar -xvf "$2" || exit
|
||||
mv "$EDIR" "$3"
|
||||
fi
|
||||
cd ..
|
||||
}
|
||||
|
||||
|
||||
prebuild() { # dirname
|
||||
if [ -e "$TARGET/$1/_built" ]; then
|
||||
echo "====== Skipping build for $TARGET/$1 (assumed to be done)"
|
||||
return 1
|
||||
fi
|
||||
echo "====== Starting build for $TARGET/$1"
|
||||
rm -rf "$TARGET/$1"
|
||||
mkdir -p "$TARGET/$1"
|
||||
cd "$TARGET/$1"
|
||||
srcdir="../../tarballs/$1"
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
postbuild() {
|
||||
touch _built
|
||||
cd ../..
|
||||
}
|
||||
|
||||
|
||||
getncurses() {
|
||||
fem http://ftp.gnu.org/pub/gnu/ncurses/ ncurses-$NCURSES_VERSION.tar.gz ncurses
|
||||
prebuild ncurses || return
|
||||
$srcdir/configure --prefix=$PREFIX\
|
||||
--without-cxx --without-cxx-binding --without-ada --without-manpages --without-progs\
|
||||
--without-tests --without-curses-h --without-pkg-config --without-shared --without-debug\
|
||||
--without-gpm --without-sysmouse --enable-widec --with-default-terminfo-dir=/usr/share/terminfo\
|
||||
--with-terminfo-dirs=/usr/share/terminfo:/lib/terminfo:/usr/local/share/terminfo\
|
||||
--with-fallbacks="screen linux vt100 xterm xterm-256color" --host=$HOST\
|
||||
CPPFLAGS=-D_GNU_SOURCE || exit
|
||||
make || exit
|
||||
make install.libs || exit
|
||||
postbuild
|
||||
}
|
||||
|
||||
|
||||
getncdu() {
|
||||
prebuild ncdu || return
|
||||
srcdir=../../..
|
||||
$srcdir/configure --host=$HOST --with-ncursesw PKG_CONFIG=false\
|
||||
CPPFLAGS="-I$PREFIX/include -I$PREFIX/include/ncursesw"\
|
||||
LDFLAGS="-static -L$PREFIX/lib -lncursesw" CFLAGS="$CFLAGS -Wall -Wextra" || exit
|
||||
make || exit
|
||||
|
||||
VER=`cd '../../..' && git describe --abbrev=5 --dirty= | sed s/^v//`
|
||||
tar -czf ../../ncdu-linux-$TARGET-$VER-unstripped.tar.gz ncdu
|
||||
$HOST-strip ncdu
|
||||
tar -czf ../../ncdu-linux-$TARGET-$VER.tar.gz ncdu
|
||||
echo "====== ncdu-linux-$TARGET-$VER.tar.gz and -unstripped created."
|
||||
|
||||
postbuild
|
||||
}
|
||||
|
||||
|
||||
buildarch() {
|
||||
TARGET=$1
|
||||
case $TARGET in
|
||||
arm) HOST=arm-linux-musleabi DIR=arm-linux-musleabi ;;
|
||||
aarch64)HOST=aarch64-linux-musl DIR=aarch64-linux-musl ;;
|
||||
i486) HOST=i486-linux-musl DIR=i486-linux-musl ;;
|
||||
x86_64) HOST=x86_64-linux-musl DIR=x86_64-linux-musl ;;
|
||||
*) echo "Unknown target: $TARGET" ;;
|
||||
esac
|
||||
PREFIX="`pwd`/$TARGET/inst"
|
||||
mkdir -p $TARGET $PREFIX
|
||||
ln -s lib $PREFIX/lib64
|
||||
|
||||
OLDPATH="$PATH"
|
||||
export PATH="$PATH:$MUSL_CROSS_PATH/$DIR/bin"
|
||||
getncurses
|
||||
getncdu
|
||||
PATH="$OLDPATH"
|
||||
}
|
||||
|
||||
|
||||
buildarch $1
|
||||
Loading…
Reference in a new issue