2012-08-27 11:51:08 -08:00
|
|
|
/* ncdu - NCurses Disk Usage
|
|
|
|
|
|
2018-01-29 01:48:49 -09:00
|
|
|
Copyright (c) 2007-2018 Yoran Heling
|
2007-07-20 03:15:46 -08:00
|
|
|
|
|
|
|
|
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:
|
2012-08-27 11:51:08 -08:00
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
|
in all copies or substantial portions of the Software.
|
2012-08-27 11:51:08 -08:00
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2009-04-26 01:08:40 -08:00
|
|
|
#include "global.h"
|
2009-04-11 03:47:55 -08:00
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2012-08-27 04:17:40 -08:00
|
|
|
#include <stdio.h>
|
2009-04-11 03:47:55 -08:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
2009-04-25 23:49:51 -08:00
|
|
|
#include <sys/time.h>
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2013-04-24 22:11:39 -08:00
|
|
|
#include <yopt.h>
|
2012-09-08 04:38:15 -08:00
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2011-10-31 06:09:12 -08:00
|
|
|
int pstate;
|
2011-09-08 16:41:12 -08:00
|
|
|
int read_only = 0;
|
2011-10-31 06:09:12 -08:00
|
|
|
long update_delay = 100;
|
2013-04-10 06:41:26 -08:00
|
|
|
int cachedir_tags = 0;
|
2018-01-23 03:40:12 -09:00
|
|
|
int extended_info = 0;
|
2011-10-31 06:09:12 -08:00
|
|
|
|
|
|
|
|
static int min_rows = 17, min_cols = 60;
|
2012-08-27 04:17:40 -08:00
|
|
|
static int ncurses_init = 0;
|
2012-08-28 23:49:06 -08:00
|
|
|
static int ncurses_tty = 0; /* Explicitely open /dev/tty instead of using stdio */
|
2011-10-31 06:09:12 -08:00
|
|
|
static long lastupdate = 999;
|
2009-04-25 23:49:51 -08:00
|
|
|
|
2007-08-11 12:01:16 -08:00
|
|
|
|
2011-10-31 06:09:12 -08:00
|
|
|
static void screen_draw() {
|
2009-04-10 23:58:33 -08:00
|
|
|
switch(pstate) {
|
2012-08-26 06:53:37 -08:00
|
|
|
case ST_CALC: dir_draw(); break;
|
2009-04-25 23:49:51 -08:00
|
|
|
case ST_BROWSE: browse_draw(); break;
|
|
|
|
|
case ST_HELP: help_draw(); break;
|
2014-12-13 14:24:35 -09:00
|
|
|
case ST_SHELL: shell_draw(); break;
|
2009-04-25 23:49:51 -08:00
|
|
|
case ST_DEL: delete_draw(); break;
|
2015-09-17 23:43:37 -08:00
|
|
|
case ST_QUIT: quit_draw(); break;
|
2009-04-10 08:16:33 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-04-25 23:49:51 -08:00
|
|
|
/* wait:
|
|
|
|
|
* -1: non-blocking, always draw screen
|
|
|
|
|
* 0: blocking wait for input and always draw screen
|
|
|
|
|
* 1: non-blocking, draw screen only if a configured delay has passed or after keypress
|
|
|
|
|
*/
|
2009-04-10 08:16:33 -08:00
|
|
|
int input_handle(int wait) {
|
|
|
|
|
int ch;
|
2009-04-25 23:49:51 -08:00
|
|
|
struct timeval tv;
|
2009-04-10 08:16:33 -08:00
|
|
|
|
2009-04-25 23:49:51 -08:00
|
|
|
if(wait != 1)
|
|
|
|
|
screen_draw();
|
|
|
|
|
else {
|
|
|
|
|
gettimeofday(&tv, (void *)NULL);
|
|
|
|
|
tv.tv_usec = (1000*(tv.tv_sec % 1000) + (tv.tv_usec / 1000)) / update_delay;
|
|
|
|
|
if(lastupdate != tv.tv_usec) {
|
|
|
|
|
screen_draw();
|
|
|
|
|
lastupdate = tv.tv_usec;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-08-27 04:17:40 -08:00
|
|
|
|
|
|
|
|
/* No actual input handling is done if ncurses hasn't been initialized yet. */
|
|
|
|
|
if(!ncurses_init)
|
|
|
|
|
return wait == 0 ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
nodelay(stdscr, wait?1:0);
|
2009-04-10 08:16:33 -08:00
|
|
|
while((ch = getch()) != ERR) {
|
|
|
|
|
if(ch == KEY_RESIZE) {
|
2009-04-18 04:12:30 -08:00
|
|
|
if(ncresize(min_rows, min_cols))
|
|
|
|
|
min_rows = min_cols = 0;
|
2012-08-17 22:47:39 -08:00
|
|
|
/* ncresize() may change nodelay state, make sure to revert it. */
|
|
|
|
|
nodelay(stdscr, wait?1:0);
|
2009-04-10 08:16:33 -08:00
|
|
|
screen_draw();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2009-04-10 23:58:33 -08:00
|
|
|
switch(pstate) {
|
2012-08-26 06:53:37 -08:00
|
|
|
case ST_CALC: return dir_key(ch);
|
2009-04-13 07:25:46 -08:00
|
|
|
case ST_BROWSE: return browse_key(ch);
|
2009-04-19 00:03:42 -08:00
|
|
|
case ST_HELP: return help_key(ch);
|
2009-04-19 01:35:24 -08:00
|
|
|
case ST_DEL: return delete_key(ch);
|
2015-09-17 23:43:37 -08:00
|
|
|
case ST_QUIT: return quit_key(ch);
|
2009-04-10 08:16:33 -08:00
|
|
|
}
|
2009-04-13 07:25:46 -08:00
|
|
|
screen_draw();
|
2009-04-10 08:16:33 -08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-08-11 12:01:16 -08:00
|
|
|
/* parse command line */
|
2012-09-05 03:52:12 -08:00
|
|
|
static void argv_parse(int argc, char **argv) {
|
2012-09-08 04:38:15 -08:00
|
|
|
yopt_t yopt;
|
|
|
|
|
int v;
|
|
|
|
|
char *val;
|
2012-08-28 07:18:33 -08:00
|
|
|
char *export = NULL;
|
2012-09-05 03:52:12 -08:00
|
|
|
char *import = NULL;
|
2009-04-23 12:10:48 -08:00
|
|
|
char *dir = NULL;
|
2012-09-08 04:38:15 -08:00
|
|
|
|
|
|
|
|
static yopt_opt_t opts[] = {
|
|
|
|
|
{ 'h', 0, "-h,-?" },
|
|
|
|
|
{ 'q', 0, "-q" },
|
|
|
|
|
{ 'v', 0, "-v" },
|
|
|
|
|
{ 'x', 0, "-x" },
|
2018-01-23 03:40:12 -09:00
|
|
|
{ 'e', 0, "-e" },
|
2012-09-08 04:38:15 -08:00
|
|
|
{ '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" },
|
2013-04-12 04:53:33 -08:00
|
|
|
{ 'C', 0, "--exclude-caches" },
|
2013-07-23 00:33:24 -08:00
|
|
|
{ 's', 0, "--si" },
|
2015-09-19 15:11:12 -08:00
|
|
|
{ 'Q', 0, "--confirm-quit" },
|
2018-01-21 05:38:36 -09:00
|
|
|
{ 'c', 1, "--color" },
|
2012-09-08 04:38:15 -08:00
|
|
|
{0,0,NULL}
|
|
|
|
|
};
|
|
|
|
|
|
2012-08-28 07:18:33 -08:00
|
|
|
dir_ui = -1;
|
2013-07-23 00:33:24 -08:00
|
|
|
si = 0;
|
2007-08-11 12:01:16 -08:00
|
|
|
|
2012-09-08 04:38:15 -08:00
|
|
|
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 This help message\n");
|
|
|
|
|
printf(" -q Quiet mode, refresh interval 2 seconds\n");
|
|
|
|
|
printf(" -v Print version\n");
|
|
|
|
|
printf(" -x Same filesystem\n");
|
2018-01-23 03:40:12 -09:00
|
|
|
printf(" -e Enable extended information\n");
|
2012-09-08 04:38:15 -08:00
|
|
|
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");
|
2013-07-23 00:33:24 -08:00
|
|
|
printf(" --si Use base 10 (SI) prefixes instead of base 2\n");
|
2012-09-08 04:38:15 -08:00
|
|
|
printf(" --exclude PATTERN Exclude files that match PATTERN\n");
|
|
|
|
|
printf(" -X, --exclude-from FILE Exclude files that match any pattern in FILE\n");
|
2013-04-12 04:53:33 -08:00
|
|
|
printf(" --exclude-caches Exclude directories containing CACHEDIR.TAG\n");
|
2015-09-19 15:11:12 -08:00
|
|
|
printf(" --confirm-quit Confirm quitting ncdu\n");
|
2018-01-23 03:40:12 -09:00
|
|
|
printf(" --color SCHEME Set color scheme\n");
|
2012-09-08 04:38:15 -08:00
|
|
|
exit(0);
|
|
|
|
|
case 'q': update_delay = 2000; break;
|
|
|
|
|
case 'v':
|
|
|
|
|
printf("ncdu %s\n", PACKAGE_VERSION);
|
|
|
|
|
exit(0);
|
|
|
|
|
case 'x': dir_scan_smfs = 1; break;
|
2018-01-23 03:40:12 -09:00
|
|
|
case 'e': extended_info = 1; break;
|
2017-01-06 08:35:30 -09:00
|
|
|
case 'r': read_only++; break;
|
2013-07-23 00:33:24 -08:00
|
|
|
case 's': si = 1; break;
|
2012-09-08 04:38:15 -08:00
|
|
|
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;
|
2015-09-19 15:11:12 -08:00
|
|
|
case 'Q': confirm_quit = 1; break;
|
2012-09-08 04:38:15 -08:00
|
|
|
case 1 : exclude_add(val); break; /* --exclude */
|
|
|
|
|
case 'X':
|
|
|
|
|
if(exclude_addfile(val)) {
|
2016-01-12 10:00:24 -09:00
|
|
|
fprintf(stderr, "Can't open %s: %s\n", val, strerror(errno));
|
2012-09-08 04:38:15 -08:00
|
|
|
exit(1);
|
2007-08-11 12:01:16 -08:00
|
|
|
}
|
2012-09-08 04:38:15 -08:00
|
|
|
break;
|
2013-04-10 06:41:26 -08:00
|
|
|
case 'C':
|
|
|
|
|
cachedir_tags = 1;
|
|
|
|
|
break;
|
2018-01-21 05:38:36 -09:00
|
|
|
case 'c':
|
|
|
|
|
if(strcmp(val, "off") == 0) { uic_theme = 0; }
|
2018-03-29 07:20:43 -08:00
|
|
|
else if(strcmp(val, "dark") == 0) { uic_theme = 1; }
|
2018-01-21 05:38:36 -09:00
|
|
|
else {
|
|
|
|
|
fprintf(stderr, "Unknown --color option: %s\n", val);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2012-09-08 04:38:15 -08:00
|
|
|
case -2:
|
2016-01-12 10:00:24 -09:00
|
|
|
fprintf(stderr, "ncdu: %s.\n", val);
|
2012-09-08 04:38:15 -08:00
|
|
|
exit(1);
|
|
|
|
|
}
|
2007-08-11 12:01:16 -08:00
|
|
|
}
|
2012-08-28 07:18:33 -08:00
|
|
|
|
|
|
|
|
if(export) {
|
|
|
|
|
if(dir_export_init(export)) {
|
2016-01-12 10:00:24 -09:00
|
|
|
fprintf(stderr, "Can't open %s: %s\n", export, strerror(errno));
|
2012-08-28 07:18:33 -08:00
|
|
|
exit(1);
|
|
|
|
|
}
|
2012-08-28 23:49:06 -08:00
|
|
|
if(strcmp(export, "-") == 0)
|
|
|
|
|
ncurses_tty = 1;
|
2012-08-28 07:18:33 -08:00
|
|
|
} else
|
|
|
|
|
dir_mem_init(NULL);
|
|
|
|
|
|
2012-09-05 03:52:12 -08:00
|
|
|
if(import) {
|
|
|
|
|
if(dir_import_init(import)) {
|
2016-01-12 10:00:24 -09:00
|
|
|
fprintf(stderr, "Can't open %s: %s\n", import, strerror(errno));
|
2012-09-05 03:52:12 -08:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
if(strcmp(import, "-") == 0)
|
|
|
|
|
ncurses_tty = 1;
|
|
|
|
|
} else
|
|
|
|
|
dir_scan_init(dir ? dir : ".");
|
|
|
|
|
|
2012-08-28 23:49:06 -08:00
|
|
|
/* Use the single-line scan feedback by default when exporting to file, no
|
|
|
|
|
* feedback when exporting to stdout. */
|
2012-08-28 07:18:33 -08:00
|
|
|
if(dir_ui == -1)
|
2012-08-28 23:49:06 -08:00
|
|
|
dir_ui = export && strcmp(export, "-") == 0 ? 0 : export ? 1 : 2;
|
2007-08-11 12:01:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-08-27 04:17:40 -08:00
|
|
|
/* Initializes ncurses only when not done yet. */
|
|
|
|
|
static void init_nc() {
|
2012-08-28 23:49:06 -08:00
|
|
|
int ok = 0;
|
|
|
|
|
FILE *tty;
|
|
|
|
|
SCREEN *term;
|
|
|
|
|
|
2012-08-27 04:17:40 -08:00
|
|
|
if(ncurses_init)
|
|
|
|
|
return;
|
|
|
|
|
ncurses_init = 1;
|
2012-08-28 23:49:06 -08:00
|
|
|
|
|
|
|
|
if(ncurses_tty) {
|
|
|
|
|
tty = fopen("/dev/tty", "r+");
|
|
|
|
|
if(!tty) {
|
|
|
|
|
fprintf(stderr, "Error opening /dev/tty: %s\n", strerror(errno));
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
term = newterm(NULL, tty, tty);
|
|
|
|
|
if(term)
|
|
|
|
|
set_term(term);
|
|
|
|
|
ok = !!term;
|
2012-09-05 23:33:58 -08:00
|
|
|
} else {
|
|
|
|
|
/* 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);
|
|
|
|
|
}
|
2012-08-28 23:49:06 -08:00
|
|
|
ok = !!initscr();
|
2012-09-05 23:33:58 -08:00
|
|
|
}
|
2012-08-28 23:49:06 -08:00
|
|
|
|
|
|
|
|
if(!ok) {
|
|
|
|
|
fprintf(stderr, "Error while initializing ncurses.\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-08 06:29:31 -08:00
|
|
|
uic_init();
|
2012-08-27 04:17:40 -08:00
|
|
|
cbreak();
|
|
|
|
|
noecho();
|
|
|
|
|
curs_set(0);
|
|
|
|
|
keypad(stdscr, TRUE);
|
|
|
|
|
if(ncresize(min_rows, min_cols))
|
|
|
|
|
min_rows = min_cols = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-07-20 03:15:46 -08:00
|
|
|
/* main program */
|
|
|
|
|
int main(int argc, char **argv) {
|
2013-01-13 03:35:25 -09:00
|
|
|
read_locale();
|
2012-09-05 03:52:12 -08:00
|
|
|
argv_parse(argc, argv);
|
2007-08-11 12:01:16 -08:00
|
|
|
|
2012-08-27 04:17:40 -08:00
|
|
|
if(dir_ui == 2)
|
|
|
|
|
init_nc();
|
2009-04-08 09:40:18 -08:00
|
|
|
|
2009-05-12 08:48:30 -08:00
|
|
|
while(1) {
|
2012-08-27 04:17:40 -08:00
|
|
|
/* We may need to initialize/clean up the screen when switching from the
|
|
|
|
|
* (sometimes non-ncurses) CALC state to something else. */
|
|
|
|
|
if(pstate != ST_CALC) {
|
|
|
|
|
if(dir_ui == 1)
|
|
|
|
|
fputc('\n', stderr);
|
|
|
|
|
init_nc();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pstate == ST_CALC) {
|
2012-09-05 03:52:12 -08:00
|
|
|
if(dir_process()) {
|
2012-08-28 07:18:33 -08:00
|
|
|
if(dir_ui == 1)
|
|
|
|
|
fputc('\n', stderr);
|
2012-08-27 04:17:40 -08:00
|
|
|
break;
|
2012-08-28 07:18:33 -08:00
|
|
|
}
|
2012-08-27 04:17:40 -08:00
|
|
|
} else if(pstate == ST_DEL)
|
2009-04-19 01:35:24 -08:00
|
|
|
delete_process();
|
2009-04-13 07:25:46 -08:00
|
|
|
else if(input_handle(0))
|
2009-04-19 00:03:42 -08:00
|
|
|
break;
|
2009-04-10 08:16:33 -08:00
|
|
|
}
|
|
|
|
|
|
2012-08-27 04:17:40 -08:00
|
|
|
if(ncurses_init) {
|
|
|
|
|
erase();
|
|
|
|
|
refresh();
|
|
|
|
|
endwin();
|
|
|
|
|
}
|
2009-04-11 00:48:24 -08:00
|
|
|
exclude_clear();
|
2007-07-20 03:15:46 -08:00
|
|
|
|
2009-04-08 09:40:18 -08:00
|
|
|
return 0;
|
2007-07-20 03:15:46 -08:00
|
|
|
}
|
2007-07-23 23:58:22 -08:00
|
|
|
|