From 24830b801a059024757b513b5e19c3eaaaae7209 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 09:27:09 +1200 Subject: [PATCH 01/15] Check /cmdline for programe name as well as /exe. This is useful for when the program was called via a symlink. For example on my system `mplayer` is an alias to `mplayer2`. Since I launch it with `mplayer` if I wanted to check the progress using cv I would expect to use `cv -c mplayer` but that currently doesn't work. The original command line (assuming argv[0] hasn't been modified) has this information: $ readlink `which mplayer` /etc/alternatives/mplayer $ readlink -f `which mplayer` /usr/bin/mplayer2 $ readlink /proc/`pidof mplayer`/exe /usr/bin/mplayer2 $ cat /proc/`pidof mplayer`/cmdline | tr '\0' ' ' | cut -d' ' -f1 mplayer Currently I am checking for a full basename match on the executable but it may be nice to add a -f,--full like pgrep does. Also -g,--glob (fnmatch) my be useful for partial matches with -c. This adds an more overhead for every unsuccessful /exe lookup though :(. If this becomes an option there are a couple of options like: only do this extra check if -c was passed (but then symlinks for cp (eg from busybox) wouldn't work), hiding it behind an option, caching. --- cv.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/cv.c b/cv.c index c42fa82..8df039f 100644 --- a/cv.c +++ b/cv.c @@ -65,7 +65,7 @@ char fullpath_dir[MAXPATHLEN + 1]; char fullpath_exe[MAXPATHLEN + 1]; char exe[MAXPATHLEN + 1]; ssize_t len; -int pid_count=0; +int pid_count=0, cmdlfd=-1; proc=opendir(PROC_PATH); if(!proc) { @@ -100,6 +100,33 @@ while((direntp = readdir(proc)) != NULL) { pid_count++; if(pid_count==max_pids) break; + continue; + } + + // In case the binary name is different then $0 + snprintf(fullpath_exe, MAXPATHLEN, "%s/cmdline", fullpath_dir); + cmdlfd = open(fullpath_exe, O_RDONLY); + if (cmdlfd < 0) { + // Will be mostly "Permission denied" + //~ perror("open"); + } else { + len = read(cmdlfd, exe, MAXPATHLEN); + if (len < 0) { + perror("read"); + close(cmdlfd); + } else { + exe[len]=0; + close(cmdlfd); + + if (!strcmp(basename(exe), bin_name)) { + pid_list[pid_count].pid=atol(direntp->d_name); + strcpy(pid_list[pid_count].name, bin_name); + pid_count++; + if(pid_count==max_pids) + break; + continue; + } + } } } } From 59a129f8d53fc0f61afcd4e40d90d891d9b78e26 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 10:17:09 +1200 Subject: [PATCH 02/15] Allow passing multiple names to -c comma delimited. Might be nice to allow -c to be present on the CLI multiple times too. --- cv.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/cv.c b/cv.c index 8df039f..5b175ae 100644 --- a/cv.c +++ b/cv.c @@ -324,7 +324,7 @@ while(1) { printf(" -w --wait estimate I/O throughput and ETA (slower display)\n"); printf(" -W --wait-delay secs wait 'secs' seconds for I/O estimation (implies -w, default=%.1f)\n", throughput_wait_secs); printf(" -h --help this message\n"); - printf(" -c --command cmd monitor only this command name (ex: firefox)\n"); + printf(" -c --command cmd monitor only these commands name (ex: firefox,wget)\n"); exit(EXIT_SUCCESS); break; @@ -387,6 +387,7 @@ struct winsize ws; float perc; result_t results[MAX_RESULTS]; signed char still_there; +char *pnext=NULL; parse_options(argc,argv); @@ -406,9 +407,21 @@ if(!proc_specifiq) { } } } else { - pid_count += find_pids_by_binary_name(proc_specifiq, - pidinfo_list + pid_count, - MAX_PIDS - pid_count); + //split on comma. + while (proc_specifiq) { + pnext = strchr(proc_specifiq, ','); + if (pnext) *pnext = 0; + pid_count += find_pids_by_binary_name(proc_specifiq, + pidinfo_list + pid_count, + MAX_PIDS - pid_count); + if (!pnext) break; + proc_specifiq = pnext+1; + + if(pid_count >= MAX_PIDS) { + fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); + break; + } + } } From 2dfdca7044d6ee9d4ab752d58f85c4e3b7c2fe1b Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 10:26:08 +1200 Subject: [PATCH 03/15] Add alternatives section in readme. Mostly from the HN thread: https://news.ycombinator.com/item?id=8023713 --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index c8229bc..35400e9 100644 --- a/README.md +++ b/README.md @@ -65,3 +65,24 @@ directories to find opened files and seek position, and reports status for the biggest file. It's very light, and compatible with virtually any command. + +Alternatives +------------ + +* [pycp](https://github.com/yannicklm/pycp) + cp and mv with a progress bar (re-implementation in python). + +* rsync --progress or -P + +* kill -s USR1 `pidof dd` + +* SIGINFO (ctrl+t) on OS X and BSDs + +* pv plus tar + +* Patched coreutils like [advanced + copy](http://www.zwicke.org/web/advancedcopy.html) or + [gcp](http://wiki.goffi.org/wiki/Gcp/en). + +* [strace](https://chris-lamb.co.uk/posts/can-you-get-cp-to-give-a-progress-bar-like-wget) + From 9de9fbc94976a32796a103432e2fffd83bf940a6 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 10:44:27 +1200 Subject: [PATCH 04/15] Add --verbose flag for tedious permission errors etc. Using strerror instead of perror so we can print the pid/path info as well. --- cv.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/cv.c b/cv.c index 5b175ae..c7345ea 100644 --- a/cv.c +++ b/cv.c @@ -42,7 +42,7 @@ char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "fgrep", "egrep", "cut", "sort", NULL}; char *proc_specifiq = NULL; -signed char flag_quiet = 0; +signed char flag_quiet = 0, flag_verbose = 0; signed char flag_throughput = 0; double throughput_wait_secs = 1; @@ -89,8 +89,9 @@ while((direntp = readdir(proc)) != NULL) { if(len != -1) exe[len] = 0; else { - // Will be mostly "Permission denied" - //~ perror("readlink"); + if (flag_verbose) + // Will be mostly "Permission denied" + fprintf(stderr, "readlink: %s: %s\n", strerror(errno), fullpath_exe); continue; } @@ -108,7 +109,8 @@ while((direntp = readdir(proc)) != NULL) { cmdlfd = open(fullpath_exe, O_RDONLY); if (cmdlfd < 0) { // Will be mostly "Permission denied" - //~ perror("open"); + if (flag_verbose) + fprintf(stderr, "open: %s: %s\n", strerror(errno), fullpath_exe); } else { len = read(cmdlfd, exe, MAXPATHLEN); if (len < 0) { @@ -208,7 +210,8 @@ len=readlink(fdpath, fd_info->name, MAXPATHLEN); if(len != -1) fd_info->name[len] = 0; else { - //~ perror("readlink"); + if (flag_verbose) + fprintf(stderr, "readlink: %s: %s\n", strerror(errno), fdpath); return 0; } @@ -286,6 +289,7 @@ void parse_options(int argc, char *argv[]) static struct option long_options[] = { {"version", no_argument, 0, 'v'}, {"quiet", no_argument, 0, 'q'}, + {"verbose", no_argument, 0, 'V'}, {"wait", no_argument, 0, 'w'}, {"wait-delay", required_argument, 0, 'W'}, {"help", no_argument, 0, 'h'}, @@ -293,7 +297,7 @@ static struct option long_options[] = { {0, 0, 0, 0} }; -static char *options_string = "vqwhc:W:"; +static char *options_string = "vqVwhc:W:"; int c,i; int option_index = 0; @@ -318,9 +322,10 @@ while(1) { for(i = 0 ; proc_names[i] ; i++) printf("%s ", proc_names[i]); printf("\n"); - printf("Usage: %s [-vqwh] [-W] [-c command]\n",argv[0]); + printf("Usage: %s [-vqVwh] [-W] [-c command]\n",argv[0]); printf(" -v --version show version\n"); printf(" -q --quiet hides some warning/error messages\n"); + printf(" -V --verbose print non-exceptional errors (eg permission denied)\n"); printf(" -w --wait estimate I/O throughput and ETA (slower display)\n"); printf(" -W --wait-delay secs wait 'secs' seconds for I/O estimation (implies -w, default=%.1f)\n", throughput_wait_secs); printf(" -h --help this message\n"); @@ -333,6 +338,10 @@ while(1) { flag_quiet = 1; break; + case 'V': + flag_verbose = 1; + break; + case 'c': proc_specifiq = strdup(optarg); break; From f7b5dc2a5d1a2507939f4639c6717e74343fc847 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 10:48:22 +1200 Subject: [PATCH 05/15] Add pid/path info to error messages. --- cv.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/cv.c b/cv.c index c7345ea..952b3a6 100644 --- a/cv.c +++ b/cv.c @@ -79,7 +79,7 @@ while((direntp = readdir(proc)) != NULL) { if(stat(fullpath_dir, &stat_buf) == -1) { if (!flag_quiet) - perror("stat (find_pids_by_binary_name)"); + fprintf(stderr, "stat (find_pids_by_binary_name): %s: %s\n", strerror(errno), fullpath_dir); continue; } @@ -114,7 +114,7 @@ while((direntp = readdir(proc)) != NULL) { } else { len = read(cmdlfd, exe, MAXPATHLEN); if (len < 0) { - perror("read"); + fprintf(stderr, "read: %s: %s\n", strerror(errno), fullpath_exe); close(cmdlfd); } else { exe[len]=0; @@ -152,8 +152,7 @@ snprintf(path_dir, MAXPATHLEN, "%s/%d/fd", PROC_PATH, pid); proc=opendir(path_dir); if(!proc) { - perror("opendir"); - fprintf(stderr,"Can't open %s\n",path_dir); + fprintf(stderr, "opendir: %s: %s\n", strerror(errno), path_dir); return 0; } @@ -161,7 +160,7 @@ while((direntp = readdir(proc)) != NULL) { snprintf(fullpath, MAXPATHLEN, "%s/%s", path_dir, direntp->d_name); if(stat(fullpath, &stat_buf) == -1) { if (!flag_quiet) - perror("stat (find_fd_for_pid)"); + fprintf(stderr, "stat (find_fd_for_pid): %s: %s\n", strerror(errno), fullpath); continue; } @@ -218,7 +217,7 @@ else { if(stat(fd_info->name, &stat_buf) == -1) { //~ printf("[debug] %i - %s\n",pid,fd_info->name); if (!flag_quiet) - perror("stat (get_fdinfo)"); + fprintf(stderr, "stat (get_fdinfo): %s: %s\n", strerror(errno), fd_info->name); return 0; } @@ -229,13 +228,13 @@ if(S_ISBLK(stat_buf.st_mode)) { if (fd < 0) { if (!flag_quiet) - perror("open (get_fdinfo)"); + fprintf(stderr, "open (get_fdinfo): %s: %s\n", strerror(errno), fd_info->name); return 0; } if (ioctl(fd, BLKGETSIZE64, &fd_info->size) < 0) { if (!flag_quiet) - perror("ioctl (get_fdinfo)"); + fprintf(stderr, "ioctl (get_fdinfo): %s: %s\n", strerror(errno), fd_info->name); return 0; } } else { @@ -250,7 +249,7 @@ gettimeofday(&fd_info->tv, &tz); if(!fp) { if (!flag_quiet) - perror("fopen (get_fdinfo)"); + fprintf(stderr, "fopen (get_fdinfo): %s: %s\n", strerror(errno), fdpath); return 0; } From c94fea1cb7d6b366d72883184d0281d247a3dae4 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 11:02:25 +1200 Subject: [PATCH 06/15] Add --glob argument to use fnmatch() instead of strcmp(). Now you can eg `cv -gc chrome\*,mplay\*`. Not sure about the flags to fnmatch, just read through the man page and thought they looked appropriate. Had to switch the printouts (`pid_list[N].name`) to use `basename(exe)` rather than bn_name because printing out the search pattern with glob isn't all that useful. --- cv.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/cv.c b/cv.c index 952b3a6..c4a953f 100644 --- a/cv.c +++ b/cv.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,7 @@ char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "fgrep", "egrep", "cut", "sort", NULL}; char *proc_specifiq = NULL; -signed char flag_quiet = 0, flag_verbose = 0; +signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0; signed char flag_throughput = 0; double throughput_wait_secs = 1; @@ -65,7 +66,7 @@ char fullpath_dir[MAXPATHLEN + 1]; char fullpath_exe[MAXPATHLEN + 1]; char exe[MAXPATHLEN + 1]; ssize_t len; -int pid_count=0, cmdlfd=-1; +int pid_count=0, cmdlfd=-1, res=-1; proc=opendir(PROC_PATH); if(!proc) { @@ -95,9 +96,14 @@ while((direntp = readdir(proc)) != NULL) { continue; } - if(!strcmp(basename(exe), bin_name)) { + res=-1; + if (flag_glob) + res = fnmatch(bin_name, basename(exe), FNM_PATHNAME|FNM_PERIOD); + else + res = strcmp(basename(exe), bin_name); + if(res==0) { pid_list[pid_count].pid=atol(direntp->d_name); - strcpy(pid_list[pid_count].name, bin_name); + strcpy(pid_list[pid_count].name, basename(exe)); pid_count++; if(pid_count==max_pids) break; @@ -120,9 +126,14 @@ while((direntp = readdir(proc)) != NULL) { exe[len]=0; close(cmdlfd); - if (!strcmp(basename(exe), bin_name)) { + res=-1; + if (flag_glob) + res = fnmatch(bin_name, basename(exe), FNM_PATHNAME|FNM_PERIOD); + else + res = strcmp(basename(exe), bin_name); + if(res==0) { pid_list[pid_count].pid=atol(direntp->d_name); - strcpy(pid_list[pid_count].name, bin_name); + strcpy(pid_list[pid_count].name, basename(exe)); pid_count++; if(pid_count==max_pids) break; @@ -293,10 +304,11 @@ static struct option long_options[] = { {"wait-delay", required_argument, 0, 'W'}, {"help", no_argument, 0, 'h'}, {"command", required_argument, 0, 'c'}, + {"glob", no_argument, 0, 'g'}, {0, 0, 0, 0} }; -static char *options_string = "vqVwhc:W:"; +static char *options_string = "vqVwhc:W:g"; int c,i; int option_index = 0; @@ -321,7 +333,7 @@ while(1) { for(i = 0 ; proc_names[i] ; i++) printf("%s ", proc_names[i]); printf("\n"); - printf("Usage: %s [-vqVwh] [-W] [-c command]\n",argv[0]); + printf("Usage: %s [-vqVwhg] [-W] [-c command]\n",argv[0]); printf(" -v --version show version\n"); printf(" -q --quiet hides some warning/error messages\n"); printf(" -V --verbose print non-exceptional errors (eg permission denied)\n"); @@ -329,6 +341,7 @@ while(1) { printf(" -W --wait-delay secs wait 'secs' seconds for I/O estimation (implies -w, default=%.1f)\n", throughput_wait_secs); printf(" -h --help this message\n"); printf(" -c --command cmd monitor only these commands name (ex: firefox,wget)\n"); + printf(" -g --glob use fnmatch() when matching process names instead of strcmp()\n"); exit(EXIT_SUCCESS); break; @@ -354,6 +367,10 @@ while(1) { throughput_wait_secs = atof(optarg); break; + case 'g': + flag_glob = 1; + break; + case '?': default: exit(EXIT_FAILURE); From 18d9a236188155edc28df0c9ca11559922e957fb Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 11:23:25 +1200 Subject: [PATCH 07/15] Add --full argument to match against the entire command line. Matches the search pattern against the entire command line from /proc/pid/cmdline instead of just the command name (argv[0]). Since we are currently doing an exact match it is only really useful with eg `cv -fgc \*pattern\*`. Hence implies `--glob`. If we do support substring matches at some point it might be nice to make `-f` require `-c`. Since this modifies the string that is copied to `pidinfo_list[i].name` it could print the wrong process name in the info printout. Specifically since the null characters from /proc/pid/cmdline are converted to spaces we lose the distinction between arguments with spaces in them and argument delimiters. Since we only care about the binary name here then this means that if your binary has a space in it only the first bit of the name will be printed. This is surely rare though, no processes in my PATH have spaces in the name. Removed FNM_PATHNAME on the fnmatch(..., cmdline) call or else it wasn't matching patterns like `myprog\*` against `myprog /target/dir`. Also, with `--full` the comparison is no longer against the command basename, in case people wan't to match against the path or `./thinger` or whatever. --- cv.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/cv.c b/cv.c index c4a953f..cdb1cdc 100644 --- a/cv.c +++ b/cv.c @@ -43,7 +43,7 @@ char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "fgrep", "egrep", "cut", "sort", NULL}; char *proc_specifiq = NULL; -signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0; +signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0, flag_full = 0; signed char flag_throughput = 0; double throughput_wait_secs = 1; @@ -67,6 +67,7 @@ char fullpath_exe[MAXPATHLEN + 1]; char exe[MAXPATHLEN + 1]; ssize_t len; int pid_count=0, cmdlfd=-1, res=-1; +char *pnext=NULL; proc=opendir(PROC_PATH); if(!proc) { @@ -126,13 +127,33 @@ while((direntp = readdir(proc)) != NULL) { exe[len]=0; close(cmdlfd); + if (flag_full) { + // cmdline is null seperated, convert to spaces for + // fnmatch. + pnext = exe; + while (pnext && pnext < exe+len-1) { + pnext = strchr(pnext, '\0'); + if (pnext) *pnext = ' '; + } + pnext = exe; + } else { + pnext = basename(exe); + } + res=-1; if (flag_glob) - res = fnmatch(bin_name, basename(exe), FNM_PATHNAME|FNM_PERIOD); + res = fnmatch(bin_name, pnext, FNM_PERIOD); else - res = strcmp(basename(exe), bin_name); + res = strcmp(pnext, bin_name); if(res==0) { pid_list[pid_count].pid=atol(direntp->d_name); + + if (flag_full) { + // re-null terminate so basename doesn't get + // confused. + pnext = strchr(exe, ' '); + if (pnext) *pnext = 0; + } strcpy(pid_list[pid_count].name, basename(exe)); pid_count++; if(pid_count==max_pids) @@ -305,10 +326,11 @@ static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"command", required_argument, 0, 'c'}, {"glob", no_argument, 0, 'g'}, + {"full", no_argument, 0, 'f'}, {0, 0, 0, 0} }; -static char *options_string = "vqVwhc:W:g"; +static char *options_string = "vqVwhc:W:gf"; int c,i; int option_index = 0; @@ -333,7 +355,7 @@ while(1) { for(i = 0 ; proc_names[i] ; i++) printf("%s ", proc_names[i]); printf("\n"); - printf("Usage: %s [-vqVwhg] [-W] [-c command]\n",argv[0]); + printf("Usage: %s [-vqVwhgf] [-W] [-c command]\n",argv[0]); printf(" -v --version show version\n"); printf(" -q --quiet hides some warning/error messages\n"); printf(" -V --verbose print non-exceptional errors (eg permission denied)\n"); @@ -342,6 +364,8 @@ while(1) { printf(" -h --help this message\n"); printf(" -c --command cmd monitor only these commands name (ex: firefox,wget)\n"); printf(" -g --glob use fnmatch() when matching process names instead of strcmp()\n"); + printf(" -f --full match against the entire command line instead of just the command name, implies --glob\n"); + printf(" Note that this is an exact match, use -g and \\*pattern\\* to get a substring match\n"); exit(EXIT_SUCCESS); break; @@ -371,6 +395,15 @@ while(1) { flag_glob = 1; break; + case 'f': + flag_full = 1; + // Since we are doing an exact match --full isn't useful without + // --glob so imply it for now. Note that this doesn't enable + // substring match, the user still needs to wrap their search + // string in asterisks. + flag_glob = 1; + break; + case '?': default: exit(EXIT_FAILURE); From fa646539c977e171bafee3b10bd6162d3a83bd09 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 11:57:15 +1200 Subject: [PATCH 08/15] Add --case-insensitive argument. Converts the current binary name/command line to lower case before comparing. Since this modifies the string that is saved to `pid_list[N].name` then if your program hase capitals in the name it will be printed out wrong. The only relevant procces in my PATH is GET. --- cv.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/cv.c b/cv.c index cdb1cdc..387e095 100644 --- a/cv.c +++ b/cv.c @@ -43,7 +43,8 @@ char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "fgrep", "egrep", "cut", "sort", NULL}; char *proc_specifiq = NULL; -signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0, flag_full = 0; +signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0, flag_full = 0, + flag_icase = 0; signed char flag_throughput = 0; double throughput_wait_secs = 1; @@ -97,6 +98,10 @@ while((direntp = readdir(proc)) != NULL) { continue; } + if (flag_icase) + for (pnext=exe; pnext Date: Sun, 13 Jul 2014 13:16:23 +1200 Subject: [PATCH 09/15] Optimization: only go through /proc once. Now instead of going through proc for each binary we are interested in go through proc once and loop in the process names for each pid. I wasn't actually seeing any performance issues so this is really a premature optimisation... The diff for `find_pids_by_binary_name` may look really big but that is only because the indentation changed because of the new inner loop. The only thing that changed in the inner loop is that I changed a couple of `break`s into `goto`s to break out of the outer loop. If you don't like `goto`s you could just add an additional `max_procs` check at the top of the outer loop. Changed proc_names to be no longer null terminated just so it matches up with the array generated from the `-c` argument. --- cv.c | 234 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 122 insertions(+), 112 deletions(-) diff --git a/cv.c b/cv.c index 387e095..ef844f5 100644 --- a/cv.c +++ b/cv.c @@ -41,7 +41,7 @@ #include "cv.h" #include "sizes.h" -char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "fgrep", "egrep", "cut", "sort", NULL}; +char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "fgrep", "egrep", "cut", "sort"}; char *proc_specifiq = NULL; signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0, flag_full = 0, flag_icase = 0; @@ -58,7 +58,7 @@ while(*str) { return 1; } -int find_pids_by_binary_name(char *bin_name, pidinfo_t *pid_list, int max_pids) +int find_pids_by_binary_name(char **bin_names, int num_names, pidinfo_t *pid_list, int max_pids) { DIR *proc; struct dirent *direntp; @@ -67,8 +67,8 @@ char fullpath_dir[MAXPATHLEN + 1]; char fullpath_exe[MAXPATHLEN + 1]; char exe[MAXPATHLEN + 1]; ssize_t len; -int pid_count=0, cmdlfd=-1, res=-1; -char *pnext=NULL; +int pid_count=0, cmdlfd=-1, res=-1, cur_name=0; +char *pnext=NULL, *bin_name=NULL; proc=opendir(PROC_PATH); if(!proc) { @@ -78,102 +78,104 @@ if(!proc) { } while((direntp = readdir(proc)) != NULL) { - snprintf(fullpath_dir, MAXPATHLEN, "%s/%s", PROC_PATH, direntp->d_name); + for (cur_name=0; cur_name < num_names; cur_name++) { + bin_name=bin_names[cur_name]; + snprintf(fullpath_dir, MAXPATHLEN, "%s/%s", PROC_PATH, direntp->d_name); - if(stat(fullpath_dir, &stat_buf) == -1) { - if (!flag_quiet) - fprintf(stderr, "stat (find_pids_by_binary_name): %s: %s\n", strerror(errno), fullpath_dir); - continue; - } - - if((S_ISDIR(stat_buf.st_mode) && is_numeric(direntp->d_name))) { - snprintf(fullpath_exe, MAXPATHLEN, "%s/exe", fullpath_dir); - len=readlink(fullpath_exe, exe, MAXPATHLEN); - if(len != -1) - exe[len] = 0; - else { - if (flag_verbose) - // Will be mostly "Permission denied" - fprintf(stderr, "readlink: %s: %s\n", strerror(errno), fullpath_exe); + if(stat(fullpath_dir, &stat_buf) == -1) { + if (!flag_quiet) + fprintf(stderr, "stat (find_pids_by_binary_name): %s: %s\n", strerror(errno), fullpath_dir); continue; } - if (flag_icase) - for (pnext=exe; pnextd_name); - strcpy(pid_list[pid_count].name, basename(exe)); - pid_count++; - if(pid_count==max_pids) - break; - continue; - } + if((S_ISDIR(stat_buf.st_mode) && is_numeric(direntp->d_name))) { + snprintf(fullpath_exe, MAXPATHLEN, "%s/exe", fullpath_dir); + len=readlink(fullpath_exe, exe, MAXPATHLEN); + if(len != -1) + exe[len] = 0; + else { + if (flag_verbose) + // Will be mostly "Permission denied" + fprintf(stderr, "readlink: %s: %s\n", strerror(errno), fullpath_exe); + continue; + } + + if (flag_icase) + for (pnext=exe; pnextd_name); + strcpy(pid_list[pid_count].name, basename(exe)); + pid_count++; + if(pid_count==max_pids) goto leave; + continue; + } - // In case the binary name is different then $0 - snprintf(fullpath_exe, MAXPATHLEN, "%s/cmdline", fullpath_dir); - cmdlfd = open(fullpath_exe, O_RDONLY); - if (cmdlfd < 0) { - // Will be mostly "Permission denied" - if (flag_verbose) - fprintf(stderr, "open: %s: %s\n", strerror(errno), fullpath_exe); - } else { - len = read(cmdlfd, exe, MAXPATHLEN); - if (len < 0) { - fprintf(stderr, "read: %s: %s\n", strerror(errno), fullpath_exe); - close(cmdlfd); + // In case the binary name is different then $0 + snprintf(fullpath_exe, MAXPATHLEN, "%s/cmdline", fullpath_dir); + cmdlfd = open(fullpath_exe, O_RDONLY); + if (cmdlfd < 0) { + // Will be mostly "Permission denied" + if (flag_verbose) + fprintf(stderr, "open: %s: %s\n", strerror(errno), fullpath_exe); } else { - exe[len]=0; - close(cmdlfd); - - if (flag_icase) - for (pnext=exe; pnextd_name); + if (flag_icase) + for (pnext=exe; pnextd_name); + + if (flag_full) { + // re-null terminate so basename doesn't get + // confused. + pnext = strchr(exe, ' '); + if (pnext) *pnext = 0; + } + strcpy(pid_list[pid_count].name, basename(exe)); + pid_count++; + if(pid_count==max_pids) goto leave; + continue; } - strcpy(pid_list[pid_count].name, basename(exe)); - pid_count++; - if(pid_count==max_pids) - break; - continue; } } } } } +leave: closedir(proc); return pid_count; } @@ -362,7 +364,7 @@ while(1) { printf("---------------------\n"); printf("Shows running coreutils basic commands and displays stats.\n"); printf("Supported commands: "); - for(i = 0 ; proc_names[i] ; i++) + for(i = 0 ; i < sizeof(proc_names)/sizeof(proc_names[0]); i++) printf("%s ", proc_names[i]); printf("\n"); printf("Usage: %s [-vqVwhgfi] [-W] [-c command]\n",argv[0]); @@ -459,6 +461,7 @@ char ftroughput[64]; struct winsize ws; float perc; result_t results[MAX_RESULTS]; +char *specifiq_batch[MAX_PIDS]; signed char still_there; char *pnext=NULL; @@ -470,34 +473,35 @@ ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); pid_count = 0; if(!proc_specifiq) { - for(i = 0 ; proc_names[i] ; i++) { - pid_count += find_pids_by_binary_name(proc_names[i], - pidinfo_list + pid_count, - MAX_PIDS - pid_count); - if(pid_count >= MAX_PIDS) { - fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); - break; - } + pid_count = find_pids_by_binary_name(proc_names, + sizeof(proc_names)/sizeof(proc_names[0]), + pidinfo_list, + MAX_PIDS); + if(pid_count >= MAX_PIDS) { + fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); } } else { - //split on comma. - while (proc_specifiq) { - if (flag_icase) - for (pnext=proc_specifiq; *pnext; pnext++) - *pnext=tolower(*pnext); - - pnext = strchr(proc_specifiq, ','); - if (pnext) *pnext = 0; - pid_count += find_pids_by_binary_name(proc_specifiq, - pidinfo_list + pid_count, - MAX_PIDS - pid_count); - if (!pnext) break; - proc_specifiq = pnext+1; - - if(pid_count >= MAX_PIDS) { - fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); - break; - } + //split on comma, put into array + i=1; + pnext = proc_specifiq; + specifiq_batch[0] = pnext; + + if (flag_icase) { + for (;*pnext; pnext++) *pnext=tolower(*pnext); + pnext = specifiq_batch[0]; + } + + while ((pnext = strchr(pnext, ','))) { + *pnext = 0; + specifiq_batch[i++] = ++pnext; + } + + pid_count = find_pids_by_binary_name(specifiq_batch, i, + pidinfo_list, + MAX_PIDS); + + if(pid_count >= MAX_PIDS) { + fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); } } @@ -507,8 +511,14 @@ if(!pid_count) { return 0; fprintf(stderr,"No command currently running: "); - for(i = 0 ; proc_names[i] ; i++) { - fprintf(stderr,"%s, ", proc_names[i]); + if (proc_specifiq) { + for (j=0; j < i; j++) { + fprintf(stderr,"%s, ", specifiq_batch[j]); + } + } else { + for(i = 0 ; i < sizeof(proc_names)/sizeof(proc_names[0]); i++) { + fprintf(stderr,"%s, ", proc_names[i]); + } } fprintf(stderr,"exiting.\n"); return 0; From 672f73c9fc54b0ec76fff6385f30603c32966f4a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 14:13:15 +1200 Subject: [PATCH 10/15] Factor out "".split(",") method. So that it can be used for other comma separated argument lists. --- cv.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/cv.c b/cv.c index ef844f5..d7e35d5 100644 --- a/cv.c +++ b/cv.c @@ -444,6 +444,28 @@ if (p->tm_yday) printf("%d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); } +// Split on sep, put pointers int dest. +// Modifies src by replacing sep with '\0', up to len_dest occurrences only. +int split(char *dest[], int len_dest, char *src, char sep) { + int i=0; + char *pnext = src; + if (pnext); + dest[0] = pnext; + i++; + + if (flag_icase) { + for (;*pnext; pnext++) *pnext=tolower(*pnext); + pnext = dest[0]; + } + + while ((pnext = strchr(pnext, sep))) { + *pnext = 0; + if (i==len_dest) break; + dest[i++] = ++pnext; + } + return i; +} + // TODO: deal with --help int main(int argc, char *argv[]) @@ -463,7 +485,6 @@ float perc; result_t results[MAX_RESULTS]; char *specifiq_batch[MAX_PIDS]; signed char still_there; -char *pnext=NULL; parse_options(argc,argv); @@ -481,20 +502,8 @@ if(!proc_specifiq) { fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); } } else { - //split on comma, put into array - i=1; - pnext = proc_specifiq; - specifiq_batch[0] = pnext; - - if (flag_icase) { - for (;*pnext; pnext++) *pnext=tolower(*pnext); - pnext = specifiq_batch[0]; - } - - while ((pnext = strchr(pnext, ','))) { - *pnext = 0; - specifiq_batch[i++] = ++pnext; - } + i = split(specifiq_batch, sizeof(specifiq_batch)/sizeof(specifiq_batch[0]), + proc_specifiq, ','); pid_count = find_pids_by_binary_name(specifiq_batch, i, pidinfo_list, From e20a56470d54dd028b9842eadddc9ee2576e944a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 14:15:37 +1200 Subject: [PATCH 11/15] Add --directory argument to filter proc/fd list by directory. Not implemented yet. --- cv.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/cv.c b/cv.c index d7e35d5..45ae953 100644 --- a/cv.c +++ b/cv.c @@ -43,6 +43,7 @@ char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "fgrep", "egrep", "cut", "sort"}; char *proc_specifiq = NULL; +char *dir_filter = NULL; signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0, flag_full = 0, flag_icase = 0; signed char flag_throughput = 0; @@ -339,10 +340,11 @@ static struct option long_options[] = { {"glob", no_argument, 0, 'g'}, {"full", no_argument, 0, 'f'}, {"case-insensitively",no_argument,0, 'i'}, + {"directory", required_argument, 0, 'D'}, {0, 0, 0, 0} }; -static char *options_string = "vqVwhc:W:gfi"; +static char *options_string = "vqVwhc:W:gfiD:"; int c,i; int option_index = 0; @@ -367,7 +369,7 @@ while(1) { for(i = 0 ; i < sizeof(proc_names)/sizeof(proc_names[0]); i++) printf("%s ", proc_names[i]); printf("\n"); - printf("Usage: %s [-vqVwhgfi] [-W] [-c command]\n",argv[0]); + printf("Usage: %s [-vqVwhgfi] [-W] [-c command] [-D dir]\n",argv[0]); printf(" -v --version show version\n"); printf(" -q --quiet hides some warning/error messages\n"); printf(" -V --verbose print non-exceptional errors (eg permission denied)\n"); @@ -379,6 +381,7 @@ while(1) { printf(" -f --full match against the entire command line instead of just the command name, implies --glob\n"); printf(" Note that this is an exact match, use -g and \\*pattern\\* to get a substring match\n"); printf(" -i --case-insensitive match case insensitively\n"); + printf(" -D --directory dir filter results to processes handling files in dir, comma separated\n"); exit(EXIT_SUCCESS); break; @@ -421,6 +424,10 @@ while(1) { flag_icase = 1; break; + case 'D': + dir_filter = optarg; + break; + case '?': default: exit(EXIT_FAILURE); @@ -485,6 +492,8 @@ float perc; result_t results[MAX_RESULTS]; char *specifiq_batch[MAX_PIDS]; signed char still_there; +char *dir_names[MAX_PIDS]; +int num_dirs=0; parse_options(argc,argv); @@ -493,6 +502,11 @@ ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); pid_count = 0; +if (dir_filter) { + num_dirs = split(dir_names, sizeof(dir_names)/sizeof(dir_names[0]), + dir_filter, ','); +} + if(!proc_specifiq) { pid_count = find_pids_by_binary_name(proc_names, sizeof(proc_names)/sizeof(proc_names[0]), From 53f1d5918df1df67f4b612ac65884db7467a4195 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 14:20:30 +1200 Subject: [PATCH 12/15] Allow to filter proc/fd results by directory. Implement an `lsof` alike `-D` argument. Eg cv -gc \* -D /tmp will look through all processes to see if they have a file open in /tmp. The fd selection for the actual printout is also filtered although it is possible to not filter it there, I can't think of a reason why you would want that though. Changes to the two main functions to accept directory filter arguments and to accept NULL/0 for some values. If you call `find_fd_for_pid` with NULL for the output list it will just return a count of interesting fds. TODO: Only works for absolute paths at the moment. Need to use realpath. --- cv.c | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/cv.c b/cv.c index 45ae953..74503de 100644 --- a/cv.c +++ b/cv.c @@ -49,6 +49,8 @@ signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0, flag_full = 0, signed char flag_throughput = 0; double throughput_wait_secs = 1; +int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd, char **dir_names, int num_dirs); + signed char is_numeric(char *str) { while(*str) { @@ -59,7 +61,9 @@ while(*str) { return 1; } -int find_pids_by_binary_name(char **bin_names, int num_names, pidinfo_t *pid_list, int max_pids) +int find_pids_by_binary_name(char **bin_names, int num_names, + char **dir_names, int num_dirs, + pidinfo_t *pid_list, int max_pids) { DIR *proc; struct dirent *direntp; @@ -113,7 +117,10 @@ while((direntp = readdir(proc)) != NULL) { if(res==0) { pid_list[pid_count].pid=atol(direntp->d_name); strcpy(pid_list[pid_count].name, basename(exe)); - pid_count++; + + if (num_dirs == 0 || find_fd_for_pid(pid_list[pid_count].pid, NULL, 0, dir_names, num_dirs) > 0) + pid_count++; + if(pid_count==max_pids) goto leave; continue; } @@ -181,7 +188,7 @@ closedir(proc); return pid_count; } -int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd) +int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd, char **dir_names, int num_dirs) { DIR *proc; struct dirent *direntp; @@ -189,7 +196,7 @@ char path_dir[MAXPATHLEN + 1]; char fullpath[MAXPATHLEN + 1]; char link_dest[MAXPATHLEN + 1]; struct stat stat_buf; -int count = 0; +int count = 0, i = 0; ssize_t len; snprintf(path_dir, MAXPATHLEN, "%s/%d/fd", PROC_PATH, pid); @@ -224,10 +231,22 @@ while((direntp = readdir(proc)) != NULL) { continue; // OK, we've found a potential interesting file. - - fd_list[count++] = atoi(direntp->d_name); + if (num_dirs == 0) { + if (fd_list) fd_list[count] = atoi(direntp->d_name); + count++; + } else { + for (i=0; i < num_dirs; i++) { + if (strstr(link_dest, dir_names[i]) == link_dest) { + if (fd_list) { + fd_list[count] = atoi(direntp->d_name); + if(count == max_fd) break; + } + count++; + } + } + } //~ printf("[debug] %s\n",fullpath); - if(count == max_fd) + if(fd_list && count == max_fd) break; } @@ -510,6 +529,7 @@ if (dir_filter) { if(!proc_specifiq) { pid_count = find_pids_by_binary_name(proc_names, sizeof(proc_names)/sizeof(proc_names[0]), + dir_names, num_dirs, pidinfo_list, MAX_PIDS); if(pid_count >= MAX_PIDS) { @@ -520,6 +540,7 @@ if(!proc_specifiq) { proc_specifiq, ','); pid_count = find_pids_by_binary_name(specifiq_batch, i, + dir_names, num_dirs, pidinfo_list, MAX_PIDS); @@ -550,7 +571,7 @@ if(!pid_count) { result_count = 0; for(i = 0 ; i < pid_count ; i++) { - fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID); + fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID, dir_names, num_dirs); max_size = 0; From 004fd6c3fd412daaba3b3725a69bdafc438220ac Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 14:37:17 +1200 Subject: [PATCH 13/15] Allow directory filter to user relative paths, symlinks. Use realpath. I am re-using the fullpath array because I like premature optimization. Also, realpath expands all symlinks. This may lead to a confusing user experience. Except that the links under /proc/pid/fd/ all have symlinks expanded to so it is really unavoidable. --- cv.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cv.c b/cv.c index 74503de..7c255ac 100644 --- a/cv.c +++ b/cv.c @@ -236,7 +236,12 @@ while((direntp = readdir(proc)) != NULL) { count++; } else { for (i=0; i < num_dirs; i++) { - if (strstr(link_dest, dir_names[i]) == link_dest) { + if (realpath(dir_names[i], fullpath) == NULL) { + if (flag_verbose) + fprintf(stderr, "realpath: %s: %s\n", strerror(errno), dir_names[i]); + continue; + } + if (strstr(link_dest, fullpath) == link_dest) { if (fd_list) { fd_list[count] = atoi(direntp->d_name); if(count == max_fd) break; @@ -245,7 +250,7 @@ while((direntp = readdir(proc)) != NULL) { } } } - //~ printf("[debug] %s\n",fullpath); + //~ printf("[debug] %s\n",link_dest); if(fd_list && count == max_fd) break; } From bf3a63203bf17e8844c3447426b6f380c421c303 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 15:45:49 +1200 Subject: [PATCH 14/15] Allow to filter proc/fd results by size. So now you can just check the seex status of any large files: cv -gc \* -S $((1024*1024*1024)) TODO: Implement size suffixes like 1M, 1m, 1G etc. This argument is probably of dubious worth, but it wasn't hard to add it anyway. --- cv.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/cv.c b/cv.c index 7c255ac..f39aef8 100644 --- a/cv.c +++ b/cv.c @@ -48,8 +48,9 @@ signed char flag_quiet = 0, flag_verbose = 0, flag_glob = 0, flag_full = 0, flag_icase = 0; signed char flag_throughput = 0; double throughput_wait_secs = 1; +long long size_filter = -1; -int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd, char **dir_names, int num_dirs); +int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd, char **dir_names, int num_dirs, long long min_size); signed char is_numeric(char *str) { @@ -63,7 +64,7 @@ return 1; int find_pids_by_binary_name(char **bin_names, int num_names, char **dir_names, int num_dirs, - pidinfo_t *pid_list, int max_pids) + pidinfo_t *pid_list, int max_pids, long long min_size) { DIR *proc; struct dirent *direntp; @@ -118,7 +119,7 @@ while((direntp = readdir(proc)) != NULL) { pid_list[pid_count].pid=atol(direntp->d_name); strcpy(pid_list[pid_count].name, basename(exe)); - if (num_dirs == 0 || find_fd_for_pid(pid_list[pid_count].pid, NULL, 0, dir_names, num_dirs) > 0) + if ((num_dirs <= 0 && min_size <= 0) || find_fd_for_pid(pid_list[pid_count].pid, NULL, 0, dir_names, num_dirs, min_size) > 0) pid_count++; if(pid_count==max_pids) goto leave; @@ -173,7 +174,10 @@ while((direntp = readdir(proc)) != NULL) { if (pnext) *pnext = 0; } strcpy(pid_list[pid_count].name, basename(exe)); - pid_count++; + + if ((num_dirs <= 0 && min_size <= 0) || find_fd_for_pid(pid_list[pid_count].pid, NULL, 0, dir_names, num_dirs, min_size) > 0) + pid_count++; + if(pid_count==max_pids) goto leave; continue; } @@ -188,7 +192,7 @@ closedir(proc); return pid_count; } -int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd, char **dir_names, int num_dirs) +int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd, char **dir_names, int num_dirs, long long min_size) { DIR *proc; struct dirent *direntp; @@ -230,6 +234,8 @@ while((direntp = readdir(proc)) != NULL) { if(stat(link_dest, &stat_buf) == -1) continue; + if (min_size > 0 && stat_buf.st_size < min_size) continue; + // OK, we've found a potential interesting file. if (num_dirs == 0) { if (fd_list) fd_list[count] = atoi(direntp->d_name); @@ -365,10 +371,11 @@ static struct option long_options[] = { {"full", no_argument, 0, 'f'}, {"case-insensitively",no_argument,0, 'i'}, {"directory", required_argument, 0, 'D'}, + {"size", required_argument, 0, 'S'}, {0, 0, 0, 0} }; -static char *options_string = "vqVwhc:W:gfiD:"; +static char *options_string = "vqVwhc:W:gfiD:S:"; int c,i; int option_index = 0; @@ -393,7 +400,7 @@ while(1) { for(i = 0 ; i < sizeof(proc_names)/sizeof(proc_names[0]); i++) printf("%s ", proc_names[i]); printf("\n"); - printf("Usage: %s [-vqVwhgfi] [-W] [-c command] [-D dir]\n",argv[0]); + printf("Usage: %s [-vqVwhgfi] [-W] [-c command] [-D dir] [-S bytes]\n",argv[0]); printf(" -v --version show version\n"); printf(" -q --quiet hides some warning/error messages\n"); printf(" -V --verbose print non-exceptional errors (eg permission denied)\n"); @@ -406,6 +413,7 @@ while(1) { printf(" Note that this is an exact match, use -g and \\*pattern\\* to get a substring match\n"); printf(" -i --case-insensitive match case insensitively\n"); printf(" -D --directory dir filter results to processes handling files in dir, comma separated\n"); + printf(" -S --size bytes filter results to processes handling files larger than bytes\n"); exit(EXIT_SUCCESS); break; @@ -452,6 +460,10 @@ while(1) { dir_filter = optarg; break; + case 'S': + size_filter = atoi(optarg); + break; + case '?': default: exit(EXIT_FAILURE); @@ -536,7 +548,7 @@ if(!proc_specifiq) { sizeof(proc_names)/sizeof(proc_names[0]), dir_names, num_dirs, pidinfo_list, - MAX_PIDS); + MAX_PIDS, size_filter); if(pid_count >= MAX_PIDS) { fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); } @@ -547,7 +559,7 @@ if(!proc_specifiq) { pid_count = find_pids_by_binary_name(specifiq_batch, i, dir_names, num_dirs, pidinfo_list, - MAX_PIDS); + MAX_PIDS, size_filter); if(pid_count >= MAX_PIDS) { fprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); @@ -576,7 +588,7 @@ if(!pid_count) { result_count = 0; for(i = 0 ; i < pid_count ; i++) { - fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID, dir_names, num_dirs); + fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID, dir_names, num_dirs, size_filter); max_size = 0; From 532d59ce70f36c227cdbf7e6ff90f23319c05ef7 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 13 Jul 2014 16:49:11 +1200 Subject: [PATCH 15/15] Allow passing human readable sizes to --size. This is a lot nice than raw bytes. --- cv.c | 2 +- sizes.c | 20 ++++++++++++++++++++ sizes.h | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cv.c b/cv.c index f39aef8..c0ab817 100644 --- a/cv.c +++ b/cv.c @@ -461,7 +461,7 @@ while(1) { break; case 'S': - size_filter = atoi(optarg); + size_filter = htob(optarg); break; case '?': diff --git a/sizes.c b/sizes.c index a6cd696..03f3baf 100644 --- a/sizes.c +++ b/sizes.c @@ -1,3 +1,5 @@ +#include + #include "sizes.h" // Thanks to Jonathan Leffler for this code @@ -28,3 +30,21 @@ for (i = 0 ; i < DIM(sizes) ; i++, multiplier /= 1024) { strcpy(result, "0"); return; } + +long long htob(char *src) { + uint64_t multiplier=1; + int i; + char *p=src; + + while (*p && !isalpha(*p)) p++; + if (!*p) return atoll(src); + + for (i=DIM(sizes)-1; i >= 0; i--) { + if (toupper(*p) == sizes[i][0]) { + return multiplier*atoll(src); + } + multiplier = 1024*multiplier; + } + + return atoll(src); +} diff --git a/sizes.h b/sizes.h index 436a9db..02380cc 100644 --- a/sizes.h +++ b/sizes.h @@ -7,5 +7,6 @@ #include void format_size(uint64_t size, char *result); +long long htob(char *src); #endif