From 8c5a4db2fe277a0d9bc7748365e63393b87a8a59 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sat, 12 Jul 2014 14:01:07 +0200 Subject: [PATCH 1/3] cv.c: Fixed indentation --- cv.c | 796 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 398 insertions(+), 398 deletions(-) diff --git a/cv.c b/cv.c index 8ac82ae..4bcb032 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 @@ -47,287 +47,287 @@ double throughput_wait_secs = 1; signed char is_numeric(char *str) { -while(*str) { - if(!isdigit(*str)) - return 0; - str++; -} -return 1; + 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; + 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; + 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; } 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; -} - -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; -} - -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; -} - -while(fgets(line, LINE_LEN - 1, fp) != NULL) { - line[4]=0; - if(!strcmp(line, "pos:")) { - fd_info->pos = atoll(line + 5); - break; - } -} - -return 1; + 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; + } + + 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; + } + + 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; + } + + while(fgets(line, LINE_LEN - 1, fp) != NULL) { + line[4]=0; + if(!strcmp(line, "pos:")) { + fd_info->pos = atoll(line + 5); + break; + } + } + + return 1; } void print_bar(float perc, int char_available) { -int i; -int num; + int i; + int num; -num = (char_available / 100.0) * perc; + num = (char_available / 100.0) * perc; -for(i = 0 ; i < num-1 ; i++) { - putchar('='); -} -putchar('>'); -i++; + for(i = 0 ; i < num-1 ; i++) { + putchar('='); + } + putchar('>'); + i++; -for( ; i < char_available ; i++) - putchar(' '); + 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'}, + {"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); + } } @@ -335,146 +335,146 @@ if (optind < argc) { 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"); - -} - -return 0; + 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"); + + } + + return 0; } From 2d2bf8042c5c2a8d42e1a0218e3e6e4494f1bb71 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 13 Jul 2014 13:59:47 +0200 Subject: [PATCH 2/3] Refactoring --- .gitignore | 4 + Makefile | 4 +- cv.c | 491 +++++++++++++++++++++-------------------------------- cv.h | 17 +- 4 files changed, 202 insertions(+), 314 deletions(-) create mode 100644 .gitignore 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..09e02d0 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ OBJ=cv CFLAGS=-g -Wall -D_FILE_OFFSET_BITS=64 - +ifdef BUILD_DAEMON + CFLAGS += -DBUILD_DAEMON $(pkg-config --cflags --libs libnotify) +endif PREFIX = $(DESTDIR)/usr/local BINDIR = $(PREFIX)/bin diff --git a/cv.c b/cv.c index 4bcb032..0de2252 100644 --- a/cv.c +++ b/cv.c @@ -36,222 +36,139 @@ #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; +int flag_daemon = 0; double throughput_wait_secs = 1; -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); - } +ssize_t size_for_stat(struct struct stat *fd_target, int fdfd, char *name){ + if(!S_ISBLK(fd_target->st_mode)) + return fd_target->st_size; - while((direntp = readdir(proc)) != NULL) { - snprintf(fullpath_dir, MAXPATHLEN, "%s/%s", PROC_PATH, direntp->d_name); + int fd = openat(fdfd, name, O_RDONLY); + if(fd < 0) + return -1; - if(stat(fullpath_dir, &stat_buf) == -1) { - if (!flag_quiet) - perror("stat (find_pids_by_binary_name)"); - continue; - } + ssize_t rv = 0; + if(ioctl(fd, BLKGETSIZE64, &rv) < 0) + rv = -1; + close(fd); + return rv; +} - 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; - } +int diropen(int entryfd, char *name, int *fdout, DIR** dirout){ + int fd = openat(entryfd, "fd", O_SEARCH); + if(!fd) /* Likely permission denied */ + return 1; + *fdout = fd; - 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; + DIR *adir = fdopendir(fd); + if(!adir) + return 1; + *dirout = adir; } -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; +int biggest_file_for_pid(int pid, 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; } - 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; - } + size_t max_size = 0; + struct max_size_info[sizeof("fdinfo") + sizeof("2147483648")]; + strcpy(max_size_info, "fdinfo/"); - // if not a regular file or a block device - if(!S_ISREG(stat_buf.st_mode) && !S_ISBLK(stat_buf.st_mode)) + struct dirent *fdent; + while(fdent = readdir(fddir)){ + if(fdent->d_type != DT_LNK) continue; - // try to read link ... - len=readlink(fullpath, link_dest, MAXPATHLEN); - if(len != -1) - link_dest[len] = 0; - else + struct stat fd_target; + if(fstatat(fdfd, fdent->d_name, &fd_target, 0)) continue; - // try to stat link target (invalid link ?) - if(stat(link_dest, &stat_buf) == -1) + size_t size_tmp = size_for_stat(&fd_target, fdfd, fdent->d_name); + if(size_tmp < max_size) 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; -} - - -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; - } - - 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; + max_size = size_tmp; + strncpy(max_size_info + sizeof("fdinfo"), fdent->d_name, sizeof("2147483648")); } - 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; + infofd = openat(entryfd, max_size_info, O_RDONLY); + if(infofd < 0){ + rc = 1; + goto cleanup; } - while(fgets(line, LINE_LEN - 1, fp) != NULL) { - line[4]=0; - if(!strcmp(line, "pos:")) { - fd_info->pos = atoll(line + 5); - break; - } + /* 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 || strcmp(buf, "pos:")) { + rc = 1; + goto cleanup; } + + ssize_t len = read(infofd, buf, sizeof(buf)-1); + buf[len] = 0; + + res->pos = atoll(buf); + res->pid = pid; + res->size = max_size; + res->num = atoi(max_size_fd); + +cleanup: + if(infofd > 0) + close(infofd); + if(fddir) + closedir(fddir); + if(fdfd > 0) + close(fdfd); return 1; } -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++) { +void print_bar(float ratio, int width) { + width -= 2; /* '[', ']' */ + putchar('['); + int pos = 0; + for(; pos<(width*ratio)-1; pos++) putchar('='); - } putchar('>'); - i++; - - for( ; i < char_available ; i++) + for(pos++; pos= 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); + DIR* proc = opendir("/proc"); + if(!proc) { + fprintf(stderr, "Can't open /proc\n"); + exit(1); + } + int procfd = open("/proc"); + if(!proc) { + fprintf(stderr, "Can't open /proc\n"); + exit(1); } + char *proc_specific_list[] = {proc_specific, NULL}; + char **name_list = proc_specific ? proc_names : proc_specific_list; - 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; - } + do { + size_t result_count = 0; + int thisfd = 0; + struct dirent *procent; + while(procent = readdir(proc) && result_count < MAX_RESULTS) { + if(thisfd) + close(thisfd); - result_count = 0; + if(procent->d_type != DT_DIR || !is_numeric(procent->d_name)) + continue; - for(i = 0 ; i < pid_count ; i++) { - fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID); + thisfd = openat(procfd, procent->d_name, O_SEARCH); + if(!thisfd) // Will be mostly "Permission denied" + continue; - max_size = 0; + 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; - // 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(!inlist(basename(exe), name_list)) + continue; - if(fdinfo.size > max_size) { - biggest_fd = fdinfo; - max_size = fdinfo.size; + pid_t pid = atol(procent->d_name); + if(!biggest_file_for_pid(pid, results+result_count)){ + if(!flag_quiet) { + fprintf(stderr, "Found no large open files for %s [%5d]\n", pid, name); + continue; } - } - if(!max_size) { // nothing found - printf("[%5d] %s inactive/flushing/streaming/...\n", - pidinfo_list[i].pid, - pidinfo_list[i].name); - continue; + //FIXME + result_count++; } + if(thisfd) + close(thisfd); + + // wait a bit, so we can estimate the throughput + if(flag_throughput) + usleep(1000000 * throughput_wait_secs); + + for(size_t i=0; i Date: Sun, 13 Jul 2014 17:37:35 +0200 Subject: [PATCH 3/3] More refactoring, also screwed it onto libnotify. --- Makefile | 13 +-- cv.c | 296 ++++++++++++++++++++++++++++++++++--------------------- cv.h | 11 ++- sizes.c | 35 +++---- sizes.h | 2 +- 5 files changed, 214 insertions(+), 143 deletions(-) diff --git a/Makefile b/Makefile index 09e02d0..5dce11c 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,12 @@ OBJ=cv -CFLAGS=-g -Wall -D_FILE_OFFSET_BITS=64 -ifdef BUILD_DAEMON - CFLAGS += -DBUILD_DAEMON $(pkg-config --cflags --libs libnotify) -endif +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 0de2252..751be49 100644 --- a/cv.c +++ b/cv.c @@ -31,9 +31,12 @@ #include -// for the BLKGETSIZE64 code section +/* for O_PATH */ +#define __USE_GNU +/* for the BLKGETSIZE64 code section */ #include #include +#include #include #ifdef BUILD_DAEMON @@ -47,10 +50,10 @@ char *proc_names[] = {"cp", "mv", "dd", "tar", "gzip", "gunzip", "cat", "grep", char *proc_specific = NULL; int flag_quiet = 0; int flag_throughput = 0; -int flag_daemon = 0; double throughput_wait_secs = 1; +int flag_daemon = 0; -ssize_t size_for_stat(struct struct stat *fd_target, int fdfd, char *name){ +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; @@ -66,18 +69,19 @@ ssize_t size_for_stat(struct struct stat *fd_target, int fdfd, char *name){ } int diropen(int entryfd, char *name, int *fdout, DIR** dirout){ - int fd = openat(entryfd, "fd", O_SEARCH); - if(!fd) /* Likely permission denied */ + 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 1; + return 2; *dirout = adir; + return 0; } -int biggest_file_for_pid(int pid, int entryfd, fdinfo_t *res){ +int biggest_file_for_entry(int entryfd, fdinfo_t *res){ int rc = 0; /* /proc/2342/fd */ int fdfd = 0; @@ -91,11 +95,12 @@ int biggest_file_for_pid(int pid, int entryfd, fdinfo_t *res){ } size_t max_size = 0; - struct max_size_info[sizeof("fdinfo") + sizeof("2147483648")]; + 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)){ + while((fdent = readdir(fddir))){ if(fdent->d_type != DT_LNK) continue; @@ -109,6 +114,7 @@ int biggest_file_for_pid(int pid, int entryfd, fdinfo_t *res){ 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); @@ -120,7 +126,7 @@ int biggest_file_for_pid(int pid, int entryfd, fdinfo_t *res){ /* 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 || strcmp(buf, "pos:")) { + if((read(infofd, buf, 5) != 5) || strncmp(buf, "pos:", 4)) { rc = 1; goto cleanup; } @@ -128,10 +134,24 @@ int biggest_file_for_pid(int pid, int entryfd, fdinfo_t *res){ ssize_t len = read(infofd, buf, sizeof(buf)-1); buf[len] = 0; - res->pos = atoll(buf); - res->pid = pid; + res->pos = atoll(buf); res->size = max_size; - res->num = atoi(max_size_fd); + 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) @@ -141,31 +161,19 @@ int biggest_file_for_pid(int pid, int entryfd, fdinfo_t *res){ if(fdfd > 0) close(fdfd); - return 1; -} - -void print_bar(float ratio, int width) { - width -= 2; /* '[', ']' */ - putchar('['); - int pos = 0; - for(; pos<(width*ratio)-1; pos++) - putchar('='); - putchar('>'); - for(pos++; pospid - ((fdinfo_t*)a)->pid; +} + +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); - DIR* proc = opendir("/proc"); - if(!proc) { - fprintf(stderr, "Can't open /proc\n"); - exit(1); - } - int procfd = open("/proc"); - if(!proc) { - fprintf(stderr, "Can't open /proc\n"); - exit(1); +#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_names : proc_specific_list; + char **name_list = proc_specific ? proc_specific_list : proc_names; - do { - size_t result_count = 0; + while(1) { + /* Search /proc */ + size_t new_result_count = 0; int thisfd = 0; struct dirent *procent; - while(procent = readdir(proc) && result_count < MAX_RESULTS) { + 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_SEARCH); - if(!thisfd) // Will be mostly "Permission denied" + 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" + if(len < 0) /* Will be mostly "Permission denied" */ continue; path_buf[len] = 0; - if(!inlist(basename(exe), name_list)) + if(!inlist(basename(path_buf), name_list)) continue; - pid_t pid = atol(procent->d_name); - if(!biggest_file_for_pid(pid, results+result_count)){ - if(!flag_quiet) { - fprintf(stderr, "Found no large open files for %s [%5d]\n", pid, name); + 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; } - //FIXME - result_count++; + 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 + } - // wait a bit, so we can estimate the throughput - if(flag_throughput) - usleep(1000000 * throughput_wait_secs); - - for(size_t i=0; ipos, 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); - 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); + free(new_result->filename); - format_size(bytes_per_sec, ftroughput); - printf(" %s/s", ftroughput); + 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 + } - printf("\n"); + new_result++; } - }while(flag_daemon || flag_throughput); + + /* 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: - closedir(proc); - return 0; +#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 2ab16e4..a72310a 100644 --- a/cv.h +++ b/cv.h @@ -6,6 +6,10 @@ #include #include +#ifdef BUILD_DAEMON +#include +#endif + #define CV_VERSION "0.3" #define MAX_RESULTS 32 @@ -16,8 +20,13 @@ typedef struct fdinfo_t { int num; off_t size; off_t pos; - char *name; + char *filename; + char *procname; + ino_t inode; struct timeval tv; +#ifdef BUILD_DAEMON + NotifyNotification *notification; +#endif } fdinfo_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