2012-08-27 21:51:08 +02:00
|
|
|
/* ncdu - NCurses Disk Usage
|
|
|
|
|
2012-01-18 11:40:50 +01:00
|
|
|
Copyright (c) 2007-2012 Yoran Heling
|
2007-07-20 11:15:46 +00: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 21:51:08 +02:00
|
|
|
|
2007-07-20 11:15:46 +00:00
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
in all copies or substantial portions of the Software.
|
2012-08-27 21:51:08 +02:00
|
|
|
|
2007-07-20 11:15:46 +00: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 11:08:40 +02:00
|
|
|
#include "global.h"
|
2009-04-11 13:47:55 +02:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
2012-08-27 14:17:40 +02:00
|
|
|
#include <stdio.h>
|
2009-04-11 13:47:55 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <unistd.h>
|
2009-04-26 09:49:51 +02:00
|
|
|
#include <sys/time.h>
|
2009-10-18 12:05:36 +02:00
|
|
|
#include <locale.h>
|
2007-07-20 11:15:46 +00:00
|
|
|
|
|
|
|
|
2011-10-31 15:09:12 +01:00
|
|
|
int pstate;
|
2011-09-08 21:41:12 -03:00
|
|
|
int read_only = 0;
|
2011-10-31 15:09:12 +01:00
|
|
|
long update_delay = 100;
|
|
|
|
|
|
|
|
static int min_rows = 17, min_cols = 60;
|
2012-08-27 14:17:40 +02:00
|
|
|
static int ncurses_init = 0;
|
2012-08-29 09:49:06 +02:00
|
|
|
static int ncurses_tty = 0; /* Explicitely open /dev/tty instead of using stdio */
|
2011-10-31 15:09:12 +01:00
|
|
|
static long lastupdate = 999;
|
2009-04-26 09:49:51 +02:00
|
|
|
|
2007-08-11 20:01:16 +00:00
|
|
|
|
2011-10-31 15:09:12 +01:00
|
|
|
static void screen_draw() {
|
2009-04-11 09:58:33 +02:00
|
|
|
switch(pstate) {
|
2012-08-26 16:53:37 +02:00
|
|
|
case ST_CALC: dir_draw(); break;
|
2009-04-26 09:49:51 +02:00
|
|
|
case ST_BROWSE: browse_draw(); break;
|
|
|
|
case ST_HELP: help_draw(); break;
|
|
|
|
case ST_DEL: delete_draw(); break;
|
2009-04-10 18:16:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-26 09:49:51 +02: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 18:16:33 +02:00
|
|
|
int input_handle(int wait) {
|
|
|
|
int ch;
|
2009-04-26 09:49:51 +02:00
|
|
|
struct timeval tv;
|
2009-04-10 18:16:33 +02:00
|
|
|
|
2009-04-26 09:49:51 +02: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 14:17:40 +02: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 18:16:33 +02:00
|
|
|
while((ch = getch()) != ERR) {
|
|
|
|
if(ch == KEY_RESIZE) {
|
2009-04-18 14:12:30 +02:00
|
|
|
if(ncresize(min_rows, min_cols))
|
|
|
|
min_rows = min_cols = 0;
|
2012-08-18 08:47:39 +02:00
|
|
|
/* ncresize() may change nodelay state, make sure to revert it. */
|
|
|
|
nodelay(stdscr, wait?1:0);
|
2009-04-10 18:16:33 +02:00
|
|
|
screen_draw();
|
|
|
|
continue;
|
|
|
|
}
|
2009-04-11 09:58:33 +02:00
|
|
|
switch(pstate) {
|
2012-08-26 16:53:37 +02:00
|
|
|
case ST_CALC: return dir_key(ch);
|
2009-04-13 17:25:46 +02:00
|
|
|
case ST_BROWSE: return browse_key(ch);
|
2009-04-19 10:03:42 +02:00
|
|
|
case ST_HELP: return help_key(ch);
|
2009-04-19 11:35:24 +02:00
|
|
|
case ST_DEL: return delete_key(ch);
|
2009-04-10 18:16:33 +02:00
|
|
|
}
|
2009-04-13 17:25:46 +02:00
|
|
|
screen_draw();
|
2009-04-10 18:16:33 +02:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-11 20:01:16 +00:00
|
|
|
/* parse command line */
|
2012-09-05 13:52:12 +02:00
|
|
|
static void argv_parse(int argc, char **argv) {
|
2009-04-10 18:16:33 +02:00
|
|
|
int i, j, len;
|
2012-08-28 17:18:33 +02:00
|
|
|
char *export = NULL;
|
2012-09-05 13:52:12 +02:00
|
|
|
char *import = NULL;
|
2009-04-23 22:10:48 +02:00
|
|
|
char *dir = NULL;
|
2012-08-28 17:18:33 +02:00
|
|
|
dir_ui = -1;
|
2007-08-11 20:01:16 +00:00
|
|
|
|
2009-04-23 22:10:48 +02:00
|
|
|
/* read from commandline */
|
2007-08-11 20:01:16 +00:00
|
|
|
for(i=1; i<argc; i++) {
|
|
|
|
if(argv[i][0] == '-') {
|
2012-08-27 14:17:40 +02:00
|
|
|
/* flags requiring arguments */
|
2012-09-05 13:52:12 +02:00
|
|
|
if(!strcmp(argv[i], "-X") || !strcmp(argv[i], "-u") || !strcmp(argv[i], "-o") || !strcmp(argv[i], "-f")
|
2012-08-28 17:18:33 +02:00
|
|
|
|| !strcmp(argv[i], "--exclude-from") || !strcmp(argv[i], "--exclude")) {
|
2007-08-11 20:01:16 +00:00
|
|
|
if(i+1 >= argc) {
|
|
|
|
printf("Option %s requires an argument\n", argv[i]);
|
|
|
|
exit(1);
|
2012-08-27 14:17:40 +02:00
|
|
|
} else if(strcmp(argv[i], "-u") == 0) {
|
|
|
|
i++;
|
|
|
|
if(!(argv[i][0] == '0' || argv[i][0] == '1' || argv[i][0] == '2') || argv[i][1] != 0) {
|
|
|
|
printf("Option -u expects either 0, 1 or 2 as argument.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
dir_ui = argv[i][0]-'0';
|
2012-08-28 17:18:33 +02:00
|
|
|
} else if(strcmp(argv[i], "-o") == 0)
|
|
|
|
export = argv[++i];
|
2012-09-05 13:52:12 +02:00
|
|
|
else if(strcmp(argv[i], "-f") == 0)
|
|
|
|
import = argv[++i];
|
2012-08-28 17:18:33 +02:00
|
|
|
else if(strcmp(argv[i], "--exclude") == 0)
|
2009-04-11 10:48:24 +02:00
|
|
|
exclude_add(argv[++i]);
|
|
|
|
else if(exclude_addfile(argv[++i])) {
|
2007-08-11 20:01:16 +00:00
|
|
|
printf("Can't open %s: %s\n", argv[i], strerror(errno));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2012-08-27 14:17:40 +02:00
|
|
|
/* short flags */
|
2009-04-10 18:16:33 +02:00
|
|
|
len = strlen(argv[i]);
|
|
|
|
for(j=1; j<len; j++)
|
2007-08-11 20:01:16 +00:00
|
|
|
switch(argv[i][j]) {
|
2012-08-26 14:41:25 +02:00
|
|
|
case 'x': dir_scan_smfs = 1; break;
|
2011-09-08 21:41:12 -03:00
|
|
|
case 'r': read_only = 1; break;
|
2009-04-26 09:49:51 +02:00
|
|
|
case 'q': update_delay = 2000; break;
|
2007-08-11 20:01:16 +00:00
|
|
|
case '?':
|
|
|
|
case 'h':
|
2012-08-27 14:17:40 +02:00
|
|
|
printf("ncdu <options> <directory>\n\n");
|
2007-11-24 08:54:22 +00:00
|
|
|
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");
|
2011-09-08 21:41:12 -03:00
|
|
|
printf(" -r Read only\n");
|
2012-08-28 17:18:33 +02:00
|
|
|
printf(" -o FILE Export scanned directory to FILE\n");
|
2012-09-05 13:52:12 +02:00
|
|
|
printf(" -f FILE Import scanned directory from FILE\n");
|
2012-08-27 14:17:40 +02:00
|
|
|
printf(" -u <0-2> UI to use when scanning (0=minimal,2=verbose)\n");
|
2007-11-24 08:54:22 +00:00
|
|
|
printf(" --exclude PATTERN Exclude files that match PATTERN\n");
|
|
|
|
printf(" -X, --exclude-from FILE Exclude files that match any pattern in FILE\n");
|
2007-08-11 20:01:16 +00:00
|
|
|
exit(0);
|
|
|
|
case 'v':
|
|
|
|
printf("ncdu %s\n", PACKAGE_VERSION);
|
2012-08-27 14:17:40 +02:00
|
|
|
exit(0);
|
2007-08-11 20:01:16 +00:00
|
|
|
default:
|
2008-09-10 15:14:12 +00:00
|
|
|
printf("Unknown option: -%c\nSee '%s -h' for more information.\n", argv[i][j], argv[0]);
|
2007-08-11 20:01:16 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2009-04-23 22:10:48 +02:00
|
|
|
} else
|
|
|
|
dir = argv[i];
|
2007-08-11 20:01:16 +00:00
|
|
|
}
|
2012-08-28 17:18:33 +02:00
|
|
|
|
|
|
|
if(export) {
|
|
|
|
if(dir_export_init(export)) {
|
|
|
|
printf("Can't open %s: %s\n", export, strerror(errno));
|
|
|
|
exit(1);
|
|
|
|
}
|
2012-08-29 09:49:06 +02:00
|
|
|
if(strcmp(export, "-") == 0)
|
|
|
|
ncurses_tty = 1;
|
2012-08-28 17:18:33 +02:00
|
|
|
} else
|
|
|
|
dir_mem_init(NULL);
|
|
|
|
|
2012-09-05 13:52:12 +02:00
|
|
|
if(import) {
|
|
|
|
if(dir_import_init(import)) {
|
|
|
|
printf("Can't open %s: %s\n", import, strerror(errno));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if(strcmp(import, "-") == 0)
|
|
|
|
ncurses_tty = 1;
|
|
|
|
} else
|
|
|
|
dir_scan_init(dir ? dir : ".");
|
|
|
|
|
2012-08-29 09:49:06 +02:00
|
|
|
/* Use the single-line scan feedback by default when exporting to file, no
|
|
|
|
* feedback when exporting to stdout. */
|
2012-08-28 17:18:33 +02:00
|
|
|
if(dir_ui == -1)
|
2012-08-29 09:49:06 +02:00
|
|
|
dir_ui = export && strcmp(export, "-") == 0 ? 0 : export ? 1 : 2;
|
2007-08-11 20:01:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 14:17:40 +02:00
|
|
|
/* Initializes ncurses only when not done yet. */
|
|
|
|
static void init_nc() {
|
2012-08-29 09:49:06 +02:00
|
|
|
int ok = 0;
|
|
|
|
FILE *tty;
|
|
|
|
SCREEN *term;
|
|
|
|
|
2012-08-27 14:17:40 +02:00
|
|
|
if(ncurses_init)
|
|
|
|
return;
|
|
|
|
ncurses_init = 1;
|
2012-08-29 09:49:06 +02: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;
|
|
|
|
} else
|
|
|
|
ok = !!initscr();
|
|
|
|
|
|
|
|
if(!ok) {
|
|
|
|
fprintf(stderr, "Error while initializing ncurses.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2012-08-27 14:17:40 +02:00
|
|
|
cbreak();
|
|
|
|
noecho();
|
|
|
|
curs_set(0);
|
|
|
|
keypad(stdscr, TRUE);
|
|
|
|
if(ncresize(min_rows, min_cols))
|
|
|
|
min_rows = min_cols = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-20 11:15:46 +00:00
|
|
|
/* main program */
|
|
|
|
int main(int argc, char **argv) {
|
2009-10-18 12:05:36 +02:00
|
|
|
setlocale(LC_ALL, "");
|
2012-09-05 13:52:12 +02:00
|
|
|
argv_parse(argc, argv);
|
2007-08-11 20:01:16 +00:00
|
|
|
|
2012-08-27 14:17:40 +02:00
|
|
|
if(dir_ui == 2)
|
|
|
|
init_nc();
|
2009-04-08 19:40:18 +02:00
|
|
|
|
2009-05-12 18:48:30 +02:00
|
|
|
while(1) {
|
2012-08-27 14:17:40 +02: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 13:52:12 +02:00
|
|
|
if(dir_process()) {
|
2012-08-28 17:18:33 +02:00
|
|
|
if(dir_ui == 1)
|
|
|
|
fputc('\n', stderr);
|
2012-08-27 14:17:40 +02:00
|
|
|
break;
|
2012-08-28 17:18:33 +02:00
|
|
|
}
|
2012-08-27 14:17:40 +02:00
|
|
|
} else if(pstate == ST_DEL)
|
2009-04-19 11:35:24 +02:00
|
|
|
delete_process();
|
2009-04-13 17:25:46 +02:00
|
|
|
else if(input_handle(0))
|
2009-04-19 10:03:42 +02:00
|
|
|
break;
|
2009-04-10 18:16:33 +02:00
|
|
|
}
|
|
|
|
|
2012-08-27 14:17:40 +02:00
|
|
|
if(ncurses_init) {
|
|
|
|
erase();
|
|
|
|
refresh();
|
|
|
|
endwin();
|
|
|
|
}
|
2009-04-11 10:48:24 +02:00
|
|
|
exclude_clear();
|
2007-07-20 11:15:46 +00:00
|
|
|
|
2009-04-08 19:40:18 +02:00
|
|
|
return 0;
|
2007-07-20 11:15:46 +00:00
|
|
|
}
|
2007-07-24 07:58:22 +00:00
|
|
|
|