diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbcb06f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.swp +*.swo +*.o +cv diff --git a/Makefile b/Makefile index aa2158b..5dce11c 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,12 @@ OBJ=cv -CFLAGS=-g -Wall -D_FILE_OFFSET_BITS=64 - +CFLAGS = -g -Wall -D_FILE_OFFSET_BITS=64 -std=gnu99 +CFLAGS += -DBUILD_DAEMON=1 +CFLAGS += $(shell pkg-config --cflags --libs libnotify glib) PREFIX = $(DESTDIR)/usr/local BINDIR = $(PREFIX)/bin -$(OBJ) : cv.o sizes.o - gcc -Wall $^ -o $@ -%.o : %.c - gcc $(CFLAGS) -c $^ +$(OBJ) : cv.c sizes.c + gcc $(CFLAGS) $^ -o $@ clean : rm -f *.o $(OBJ) install : $(OBJ) diff --git a/cv.c b/cv.c index 8ac82ae..751be49 100644 --- a/cv.c +++ b/cv.c @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . -*/ + */ #include #include @@ -31,450 +31,419 @@ #include -// for the BLKGETSIZE64 code section +/* for O_PATH */ +#define __USE_GNU +/* for the BLKGETSIZE64 code section */ #include #include +#include #include +#ifdef BUILD_DAEMON +#include +#endif + #include "cv.h" #include "sizes.h" char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", "cut", "sort", NULL}; -char *proc_specifiq = NULL; -signed char flag_quiet = 0; -signed char flag_throughput = 0; +char *proc_specific = NULL; +int flag_quiet = 0; +int flag_throughput = 0; double throughput_wait_secs = 1; +int flag_daemon = 0; -signed char is_numeric(char *str) -{ -while(*str) { - if(!isdigit(*str)) - return 0; - str++; -} -return 1; -} - -int find_pids_by_binary_name(char *bin_name, pidinfo_t *pid_list, int max_pids) -{ -DIR *proc; -struct dirent *direntp; -struct stat stat_buf; -char fullpath_dir[MAXPATHLEN + 1]; -char fullpath_exe[MAXPATHLEN + 1]; -char exe[MAXPATHLEN + 1]; -ssize_t len; -int pid_count=0; - -proc=opendir(PROC_PATH); -if(!proc) { - perror("opendir"); - fprintf(stderr,"Can't open %s\n",PROC_PATH); - exit(EXIT_FAILURE); -} - -while((direntp = readdir(proc)) != NULL) { - snprintf(fullpath_dir, MAXPATHLEN, "%s/%s", PROC_PATH, direntp->d_name); - - if(stat(fullpath_dir, &stat_buf) == -1) { - if (!flag_quiet) - perror("stat (find_pids_by_binary_name)"); - 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 { - // Will be mostly "Permission denied" - //~ perror("readlink"); - continue; - } - - 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; - } - } -} - -closedir(proc); -return pid_count; -} - -int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd) -{ -DIR *proc; -struct dirent *direntp; -char path_dir[MAXPATHLEN + 1]; -char fullpath[MAXPATHLEN + 1]; -char link_dest[MAXPATHLEN + 1]; -struct stat stat_buf; -int count = 0; -ssize_t len; - -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); - return 0; -} - -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)"); - continue; - } - - // if not a regular file or a block device - if(!S_ISREG(stat_buf.st_mode) && !S_ISBLK(stat_buf.st_mode)) - continue; - - // try to read link ... - len=readlink(fullpath, link_dest, MAXPATHLEN); - if(len != -1) - link_dest[len] = 0; - else - continue; - - // try to stat link target (invalid link ?) - if(stat(link_dest, &stat_buf) == -1) - continue; - - // OK, we've found a potential interesting file. - - fd_list[count++] = atoi(direntp->d_name); - //~ printf("[debug] %s\n",fullpath); - if(count == max_fd) - break; -} - -closedir(proc); -return count; -} +ssize_t size_for_stat(struct stat *fd_target, int fdfd, char *name){ + if(!S_ISBLK(fd_target->st_mode)) + return fd_target->st_size; + int fd = openat(fdfd, name, O_RDONLY); + if(fd < 0) + return -1; -signed char get_fdinfo(pid_t pid, int fdnum, fdinfo_t *fd_info) -{ -struct stat stat_buf; -char fdpath[MAXPATHLEN + 1]; -char line[LINE_LEN]; -ssize_t len; -FILE *fp; -struct timezone tz; - -fd_info->num = fdnum; - -snprintf(fdpath, MAXPATHLEN, "%s/%d/fd/%d", PROC_PATH, pid, fdnum); - -len=readlink(fdpath, fd_info->name, MAXPATHLEN); -if(len != -1) - fd_info->name[len] = 0; -else { - //~ perror("readlink"); - return 0; -} - -if(stat(fd_info->name, &stat_buf) == -1) { - //~ printf("[debug] %i - %s\n",pid,fd_info->name); - if (!flag_quiet) - perror("stat (get_fdinfo)"); - return 0; + ssize_t rv = 0; + if(ioctl(fd, BLKGETSIZE64, &rv) < 0) + rv = -1; + close(fd); + return rv; } -if(S_ISBLK(stat_buf.st_mode)) { - int fd; - - fd = open(fd_info->name, O_RDONLY); - - if (fd < 0) { - if (!flag_quiet) - perror("open (get_fdinfo)"); - return 0; - } - - if (ioctl(fd, BLKGETSIZE64, &fd_info->size) < 0) { - if (!flag_quiet) - perror("ioctl (get_fdinfo)"); - return 0; - } -} else { - fd_info->size = stat_buf.st_size; +int diropen(int entryfd, char *name, int *fdout, DIR** dirout){ + int fd = openat(entryfd, name, O_RDONLY | O_DIRECTORY); + if(fd < 0) /* Likely permission denied */ + return 1; + *fdout = fd; + + DIR *adir = fdopendir(fd); + if(!adir) + return 2; + *dirout = adir; + return 0; } -fd_info->pos = 0; - -snprintf(fdpath, MAXPATHLEN, "%s/%d/fdinfo/%d", PROC_PATH, pid, fdnum); -fp = fopen(fdpath, "rt"); -gettimeofday(&fd_info->tv, &tz); - -if(!fp) { - if (!flag_quiet) - perror("fopen (get_fdinfo)"); - return 0; +int biggest_file_for_entry(int entryfd, fdinfo_t *res){ + int rc = 0; + /* /proc/2342/fd */ + int fdfd = 0; + DIR *fddir = NULL; + /* /proc/2342/fdinfo/23 */ + int infofd = 0; + + if(diropen(entryfd, "fd", &fdfd, &fddir)){ + rc = 1; + goto cleanup; + } + + size_t max_size = 0; + char max_size_info[sizeof("fdinfo") + sizeof("2147483648")]; + strcpy(max_size_info, "fdinfo/"); + ino_t max_size_inode = 0; + + struct dirent *fdent; + while((fdent = readdir(fddir))){ + if(fdent->d_type != DT_LNK) + continue; + + struct stat fd_target; + if(fstatat(fdfd, fdent->d_name, &fd_target, 0)) + continue; + + size_t size_tmp = size_for_stat(&fd_target, fdfd, fdent->d_name); + if(size_tmp < max_size) + continue; + + max_size = size_tmp; + strncpy(max_size_info + sizeof("fdinfo"), fdent->d_name, sizeof("2147483648")); + max_size_inode = fd_target.st_ino; + } + + infofd = openat(entryfd, max_size_info, O_RDONLY); + if(infofd < 0){ + rc = 1; + goto cleanup; + } + + /* According to seq_show in fs/proc/fd.c in the linux kernel sources, the fdinfo file will always start with the + * "pos" line. The pos field is printfed as a long long, i.e. 64 bit and thus never larger/smaller than ±2**63 */ + char buf[32]; + if((read(infofd, buf, 5) != 5) || strncmp(buf, "pos:", 4)) { + rc = 1; + goto cleanup; + } + + ssize_t len = read(infofd, buf, sizeof(buf)-1); + buf[len] = 0; + + res->pos = atoll(buf); + res->size = max_size; + res->inode= max_size_inode; + res->num = atoi(max_size_info+sizeof("fdinfo")); + gettimeofday(&res->tv, NULL); + + char *fbuf = malloc(MAXPATHLEN); + if(!fbuf) { + rc = 2; + goto cleanup; + } + + if(readlinkat(fdfd, max_size_info+sizeof("fdinfo"), fbuf, MAXPATHLEN) < 0) { + free(fbuf); + rc = 1; + goto cleanup; + } + res->filename = fbuf; + +cleanup: + if(infofd > 0) + close(infofd); + if(fddir) + closedir(fddir); + if(fdfd > 0) + close(fdfd); + + return rc; } -while(fgets(line, LINE_LEN - 1, fp) != NULL) { - line[4]=0; - if(!strcmp(line, "pos:")) { - fd_info->pos = atoll(line + 5); - break; - } +int is_numeric(char *str) { + while(isdigit(*str++)) + if(!*str) + return 1; + return 0; } -return 1; +int inlist(char *str, char **list) { + while(*list) + if(!strcmp(str, *list++)) + return 1; + return 0; } -void print_bar(float perc, int char_available) -{ -int i; -int num; - -num = (char_available / 100.0) * perc; - -for(i = 0 ; i < num-1 ; i++) { - putchar('='); -} -putchar('>'); -i++; - -for( ; i < char_available ; i++) - putchar(' '); - -} - - void parse_options(int argc, char *argv[]) { -static struct option long_options[] = { - {"version", no_argument, 0, 'v'}, - {"quiet", no_argument, 0, 'q'}, - {"wait", no_argument, 0, 'w'}, - {"wait-delay", required_argument, 0, 'W'}, - {"help", no_argument, 0, 'h'}, - {"command", required_argument, 0, 'c'}, - {0, 0, 0, 0} -}; - -static char *options_string = "vqwhc:W:"; -int c,i; -int option_index = 0; - -while(1) { - c = getopt_long (argc, argv, options_string, long_options, &option_index); - - // no more options - if (c == -1) - break; - - switch(c) { - case 'v': - printf("cv version %s\n",CV_VERSION); - exit(EXIT_SUCCESS); - break; - - case 'h': - printf("cv - Coreutils Viewer\n"); - printf("---------------------\n"); - printf("Shows running coreutils basic commands and displays stats.\n"); - printf("Supported commands: "); - 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(" -v --version show version\n"); - printf(" -q --quiet hides some warning/error messages\n"); - printf(" -w --wait estimate I/O throughput (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"); - - exit(EXIT_SUCCESS); - break; - - case 'q': - flag_quiet = 1; - break; - - case 'c': - proc_specifiq = strdup(optarg); - break; - - case 'w': - flag_throughput = 1; - break; - - case 'W': - flag_throughput = 1; - throughput_wait_secs = atof(optarg); - break; - - case '?': - default: - exit(EXIT_FAILURE); - } -} - -if (optind < argc) { - fprintf(stderr,"Invalid arguments.\n"); - exit(EXIT_FAILURE); -} + static struct option long_options[] = { + {"version", no_argument, 0, 'v'}, + {"quiet", no_argument, 0, 'q'}, + {"wait", no_argument, 0, 'w'}, + {"wait-delay", required_argument, 0, 'W'}, +#ifdef BUILD_DAEMON + {"daemonize", no_argument, 0, 'd'}, +#endif + {"help", no_argument, 0, 'h'}, + {"command", required_argument, 0, 'c'}, + {0, 0, 0, 0} + }; + +#ifdef BUILD_DAEMON + static char *options_string = "vqwdhc:W:"; +#else + static char *options_string = "vqwhc:W:"; +#endif + int c,i; + int option_index = 0; + + while(1) { + c = getopt_long (argc, argv, options_string, long_options, &option_index); + + // no more options + if (c == -1) + break; + + switch(c) { + case 'v': + printf("cv version %s\n",CV_VERSION); + exit(EXIT_SUCCESS); + break; + + case 'h': + printf("cv - Coreutils Viewer\n"); + printf("---------------------\n"); + printf("Shows running coreutils basic commands and displays stats.\n"); + printf("Supported commands: "); + 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(" -v --version show version\n"); + printf(" -q --quiet hides some warning/error messages\n"); + printf(" -w --wait estimate I/O throughput (slower display)\n"); + printf(" -W --wait-delay secs wait 'secs' seconds for I/O estimation (implies -w, default=%.1f)\n", throughput_wait_secs); +#ifdef BUILD_DAEMON + printf(" -d --daemonize Daemonize and show results using libnotify (implies -w)\n"); +#endif + printf(" -h --help this message\n"); + printf(" -c --command cmd monitor only this command name (ex: firefox)\n"); + + exit(EXIT_SUCCESS); + break; + case 'q': + flag_quiet = 1; + break; + case 'c': + proc_specific = strdup(optarg); + break; + case 'w': + flag_throughput = 1; + break; + case 'W': + flag_throughput = 1; + throughput_wait_secs = atof(optarg); + break; + case 'd': + flag_daemon = 1; + break; + case '?': + default: + exit(EXIT_FAILURE); + } + } + + if (optind < argc) { + fprintf(stderr,"Invalid arguments.\n"); + exit(EXIT_FAILURE); + } } // TODO: deal with --help -int main(int argc, char *argv[]) -{ -int pid_count, fd_count, result_count; -int i,j; -pidinfo_t pidinfo_list[MAX_PIDS]; -fdinfo_t fdinfo; -fdinfo_t biggest_fd; -int fdnum_list[MAX_FD_PER_PID]; -off_t max_size; -char fsize[64]; -char fpos[64]; -char ftroughput[64]; -struct winsize ws; -float perc; -result_t results[MAX_RESULTS]; -signed char still_there; - -parse_options(argc,argv); - -// ws.ws_row, ws.ws_col -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; - } - } -} else { - pid_count += find_pids_by_binary_name(proc_specifiq, - pidinfo_list + pid_count, - MAX_PIDS - pid_count); -} - - -if(!pid_count) { - if(flag_quiet) - return 0; - - fprintf(stderr,"No command currently running: "); - for(i = 0 ; proc_names[i] ; i++) { - fprintf(stderr,"%s, ", proc_names[i]); - } - fprintf(stderr,"exiting.\n"); - return 0; -} - -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); - - max_size = 0; - - // let's find the biggest opened file - for(j = 0 ; j < fd_count ; j++) { - get_fdinfo(pidinfo_list[i].pid, fdnum_list[j], &fdinfo); - - if(fdinfo.size > max_size) { - biggest_fd = fdinfo; - max_size = fdinfo.size; - } - } - - if(!max_size) { // nothing found - printf("[%5d] %s inactive/flushing/streaming/...\n", - pidinfo_list[i].pid, - pidinfo_list[i].name); - continue; - } - - // We've our biggest_fd now, let's store the result - results[result_count].pid = pidinfo_list[i]; - results[result_count].fd = biggest_fd; - - result_count++; -} - -// wait a bit, so we can estimate the throughput -if (flag_throughput) - usleep(1000000 * throughput_wait_secs); - -for (i = 0 ; i < result_count ; i++) { - - if (flag_throughput) { - still_there = get_fdinfo(results[i].pid.pid, results[i].fd.num, &fdinfo); - if (still_there && strcmp(results[i].fd.name, fdinfo.name)) - still_there = 0; // still there, but it's not the same file ! - } else - still_there = 0; - - if (!still_there) { - // pid is no more here (or no throughput was asked), use initial info - format_size(results[i].fd.pos, fpos); - format_size(results[i].fd.size, fsize); - perc = ((double)100 / (double)results[i].fd.size) * (double)results[i].fd.pos; - } else { - // use the newest info - format_size(fdinfo.pos, fpos); - format_size(fdinfo.size, fsize); - perc = ((double)100 / (double)fdinfo.size) * (double)fdinfo.pos; - - } - - printf("[%5d] %s %s %.1f%% (%s / %s)", - results[i].pid.pid, - results[i].pid.name, - results[i].fd.name, - perc, - fpos, - fsize); - - if (flag_throughput && still_there) { - // results[i] vs fdinfo - long long usec_diff; - off_t byte_diff; - off_t bytes_per_sec; - - usec_diff = (fdinfo.tv.tv_sec - results[i].fd.tv.tv_sec) * 1000000L - + (fdinfo.tv.tv_usec - results[i].fd.tv.tv_usec); - byte_diff = fdinfo.pos - results[i].fd.pos; - bytes_per_sec = byte_diff / (usec_diff / 1000000.0); - - format_size(bytes_per_sec, ftroughput); - printf(" %s/s", ftroughput); - } - - - printf("\n"); - - // Need to work on window width when using screen/watch/... - //~ printf(" ["); - //~ print_bar(perc, ws.ws_col-6); - //~ printf("]\n"); - +int compare_results(const void *a, const void *b){ + return ((fdinfo_t*)b)->pid - ((fdinfo_t*)a)->pid; } -return 0; +int main(int argc, char *argv[]) { + int rc = 0; + fdinfo_t results1[MAX_RESULTS]; + fdinfo_t results2[MAX_RESULTS]; + fdinfo_t *new_results = results1; + fdinfo_t *old_results = results2; + size_t old_result_count = 0; + + parse_options(argc,argv); + +#ifdef BUILD_DAEMON + notify_init("cv"); +#endif + + int procfd = 0; + DIR* procdir = NULL; + if(diropen(AT_FDCWD, "/proc", &procfd, &procdir)) { + fprintf(stderr, "Can't open /proc: %s (%d)\n", strerror(errno), errno); + rc = 1; + goto cleanup; + } + + char *proc_specific_list[] = {proc_specific, NULL}; + char **name_list = proc_specific ? proc_specific_list : proc_names; + + while(1) { + /* Search /proc */ + size_t new_result_count = 0; + int thisfd = 0; + struct dirent *procent; + while((procent = readdir(procdir)) && new_result_count < MAX_RESULTS) { + if(thisfd) + close(thisfd); + + if(procent->d_type != DT_DIR || !is_numeric(procent->d_name)) + continue; + + thisfd = openat(procfd, procent->d_name, O_RDONLY | O_DIRECTORY); + if(thisfd < 0) /* Will be mostly "Permission denied" */ + continue; + + char path_buf[MAXPATHLEN]; + ssize_t len = readlinkat(thisfd, "exe", path_buf, sizeof(path_buf)); + if(len < 0) /* Will be mostly "Permission denied" */ + continue; + path_buf[len] = 0; + + if(!inlist(basename(path_buf), name_list)) + continue; + + fdinfo_t *result = new_results+new_result_count; + result->pid = atol(procent->d_name); + result->procname = strdup(basename(path_buf)); + if(biggest_file_for_entry(thisfd, new_results+new_result_count)) { + if(!flag_quiet) + fprintf(stderr, "Found no large open files for %s [%5d]\n", result->procname, result->pid); + continue; + } + + new_result_count++; + } + if(thisfd) + close(thisfd); + rewinddir(procdir); + + /* Depending on the order in which the kernel returns the entries of /proc, this might not be necessary. */ + qsort(new_results, sizeof(new_results)/sizeof(fdinfo_t), sizeof(fdinfo_t), compare_results); + + /* Print results, merging old and new lists on the way */ + fdinfo_t *old_result = old_results; + fdinfo_t *new_result = new_results; +#ifdef BUILD_DAEMON + if(new_result_count == 0) { + while(old_result < old_results+old_result_count){ /* process terminated */ + notify_notification_close(old_result->notification, NULL); + g_object_unref(G_OBJECT(old_result->notification)); + old_result++; + } + } +#endif + while(new_result < new_results+new_result_count) { + off_t throughput = -1; +#ifdef BUILD_DAEMON + new_result->notification = NULL; +#endif + if(old_result < old_results+old_result_count) { + while(new_result->pid > old_result->pid) { /* process terminated */ +#ifdef BUILD_DAEMON + notify_notification_close(old_result->notification, NULL); + g_object_unref(G_OBJECT(old_result->notification)); +#endif + old_result++; + } + + if(new_result->pid == old_result->pid) { + if(new_result->inode == old_result->inode){ + uint64_t time_delta = (new_result->tv.tv_sec - old_result->tv.tv_sec) + + (new_result->tv.tv_usec - old_result->tv.tv_usec)/1000000L; + throughput = (new_result->pos - old_result->pos)/time_delta; +#ifdef BUILD_DAEMON + new_result->notification = old_result->notification; +#endif + } + + if(old_result < old_results+(old_result_count-1)) + old_result++; + } + } + + char fsize[32]; + char fpos[32]; + format_size(new_result->pos, fpos, sizeof(fpos)); + format_size(new_result->size, fsize, sizeof(fsize)); + float ratio = (float)new_result->pos/new_result->size; + + char strbuf[MAXPATHLEN]; + int pos = 0; + pos += snprintf(strbuf, sizeof(strbuf)-pos, "[%5d] %s %s %.1f%% (%s/%s", + new_result->pid, + new_result->procname, + new_result->filename, + ratio*100, + fpos, + fsize); + + free(new_result->filename); + + char fthroughput[32]; + if(throughput < 0) { + pos += snprintf(strbuf+pos, sizeof(strbuf)-pos, ")"); + } else { + format_size(throughput, fthroughput, sizeof(fthroughput)); + pos += snprintf(strbuf+pos, sizeof(strbuf)-pos, " @ %s/s)", fthroughput); + } + + if(!flag_daemon) { + printf("%s\n", strbuf); +#ifdef BUILD_DAEMON + } else { + NotifyNotification *notf = new_result->notification; + if(!notf) { + notf = notify_notification_new("cv", strbuf, NULL); + notify_notification_set_hint(notf, "synchronous", g_variant_new_string("volume")); + }else{ + notify_notification_update(notf, "cv", strbuf, NULL); + } + notify_notification_set_hint(notf, "value", g_variant_new_int32(ratio*100)); + notify_notification_show(notf, NULL); + new_result->notification = notf; +#endif + } + + new_result++; + } + + /* Exchange pointers */ + fdinfo_t *tmpr = new_results; + new_results = old_results; + old_results = tmpr; + old_result_count = new_result_count; + + if(!flag_daemon && !flag_throughput) + break; + flag_throughput = !flag_throughput; + usleep(1000000 * throughput_wait_secs); + } + +cleanup: +#ifdef BUILD_DAEMON + notify_uninit(); +#endif + if(procfd > 0) + close(procfd); + if(procdir) + closedir(procdir); + return rc; } diff --git a/cv.h b/cv.h index 78905f7..a72310a 100644 --- a/cv.h +++ b/cv.h @@ -6,31 +6,27 @@ #include #include +#ifdef BUILD_DAEMON +#include +#endif + #define CV_VERSION "0.3" -#define PROC_PATH "/proc" -#define MAX_PIDS 32 #define MAX_RESULTS 32 -#define MAX_FD_PER_PID 512 -#define LINE_LEN 256 //~ #define MINMUM_SIZE 8192 typedef struct fdinfo_t { + int pid; int num; off_t size; off_t pos; - char name[MAXPATHLEN + 1]; + char *filename; + char *procname; + ino_t inode; struct timeval tv; +#ifdef BUILD_DAEMON + NotifyNotification *notification; +#endif } fdinfo_t; -typedef struct pidinfo_t { - pid_t pid; - char name[MAXPATHLEN + 1]; -} pidinfo_t; - -typedef struct result_t { - pidinfo_t pid; - fdinfo_t fd; -} result_t; - #endif diff --git a/sizes.c b/sizes.c index a6cd696..775944e 100644 --- a/sizes.c +++ b/sizes.c @@ -4,27 +4,18 @@ #define DIM(x) (sizeof(x)/sizeof(*(x))) -static const char *sizes[] = { "EiB", "PiB", "TiB", "GiB", "MiB", "KiB", "B" }; -static const uint64_t exbibytes = 1024ULL * 1024ULL * 1024ULL * - 1024ULL * 1024ULL * 1024ULL; +static const char *sizes[] = {"B", "kiB", "MiB", "GiB", "TiB", "PiB", "EiB", NULL}; -void format_size(uint64_t size, char *result) -{ -uint64_t multiplier; -int i; - -multiplier = exbibytes; - -for (i = 0 ; i < DIM(sizes) ; i++, multiplier /= 1024) { - if (size < multiplier) - continue; - if (size % multiplier == 0) - sprintf(result, "%" PRIu64 " %s", size / multiplier, sizes[i]); - else - sprintf(result, "%.1f %s", (float) size / multiplier, sizes[i]); - return; -} - -strcpy(result, "0"); -return; +void format_size(uint64_t size, char *result, size_t result_len) { + const char **str = sizes; + uint64_t omult, mult = 1; + do { + omult = mult; + mult <<= 10; + if(size < mult){ + snprintf(result, result_len, "%.1f%s", (float)size/omult, *str); + return; + } + } while(*++str); + snprintf(result, result_len, "%.1f%s", (float)size/omult, str[-1]); } diff --git a/sizes.h b/sizes.h index d274ce8..ac36f83 100644 --- a/sizes.h +++ b/sizes.h @@ -6,6 +6,6 @@ #include #include -void format_size(uint64_t size, char *result); +void format_size(uint64_t size, char *result, size_t result_len); #endif