diff --git a/backup.c b/backup.c new file mode 100644 index 0000000..57b5c9b --- /dev/null +++ b/backup.c @@ -0,0 +1,1257 @@ +/* + Copyright (C) 2016 Xfennec, CQFD Corp. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +// for the BLKGETSIZE64 code section +#include +#include +#ifdef __APPLE__ +# include +# include +# include +# include +#endif // __APPLE__ +#ifdef __linux__ +# include +#endif // __linux__ +#ifdef __FreeBSD__ +# include +#endif // __FreeBSD__ + +#ifdef __FreeBSD__ +# include +# include +# include +# include +# include +# include +#endif + +#include "progress.h" +#include "sizes.h" +#include "hlist.h" + +// Given -a will dynamically add values to this list, move it to be a dynamic +// list and generate it at runtime. +static int proc_names_cnt; +static char **proc_names; +char *default_proc_names[] = {"cp", "mv", "dd", "tar", "bsdtar", "cat", "rsync", "scp", + "grep", "fgrep", "egrep", "cut", "sort", "md5sum", "sha1sum", + "sha224sum", "sha256sum", "sha384sum", "sha512sum", +#ifdef __FreeBSD__ + "md5", "sha1", "sha224", "sha256", "sha512", "sha512t256", "rmd160", + "skein256", "skein512", "skein1024", +#endif + "adb", + "gzip", "gunzip", "bzip2", "bunzip2", "xz", "unxz", "lzma", "unlzma", "7z", "7za", "zip", "unzip", + "zcat", "bzcat", "lzcat", + "coreutils", + "split", + "gpg", +#if defined(__APPLE__) || defined(__FreeBSD__) + "gcp", "gmv", +#endif + NULL +}; + +// static means initialized to 0/NULL (C standard, §6.7.8/10) +static int proc_specifiq_name_cnt; +static char **proc_specifiq_name; +static int ignore_file_list_cnt; +static char **ignore_file_list; +static int proc_specifiq_pid_cnt; +static pid_t *proc_specifiq_pid; + +signed char flag_quiet = 0; +signed char flag_debug = 0; +signed char flag_throughput = 0; +signed char flag_monitor = 0; +signed char flag_monitor_continuous = 0; +signed char flag_open_mode = 0; +double throughput_wait_secs = 1; + +WINDOW *mainwin; + +signed char is_numeric(char *str) +{ +while (*str) { + if(!isdigit(*str)) + return 0; + str++; +} +return 1; +} + +void nprintf(char *format, ...) +{ +va_list args; + +va_start(args, format); +if (flag_monitor || flag_monitor_continuous) + vw_printw(mainwin, format, args); +else + vprintf(format, args); +va_end(args); +} + +void nfprintf(FILE *file, char *format, ...) { +va_list args; + +va_start(args, format); +if (flag_monitor || flag_monitor_continuous) + vw_printw(mainwin, format, args); +else + vfprintf(file, format, args); +va_end(args); +} + +void nperror(const char *s) { +if (flag_monitor || flag_monitor_continuous) + printw("%s:%s", s, strerror(errno)); +else + perror(s); +} + + +signed char is_ignored_file(char *str) +{ +int i; +for (i = 0 ; i < ignore_file_list_cnt ; i++) + if (!strcmp(ignore_file_list[i], str)) + return 1; +return 0; +} + +#ifdef __APPLE__ +int find_pid_by_id(pid_t pid, pidinfo_t *pid_list) +{ +char exe[MAXPATHLEN + 1]; + +exe[0] = '\0'; +proc_name(pid, exe, sizeof(exe)); +if (exe[0] == '\0') + return 0; + +pid_list[0].pid = pid; +strcpy(pid_list[0].name, exe); +return 1; +} + +int find_pids_by_binary_name(char *bin_name, pidinfo_t *pid_list, int max_pids) +{ +int pid_count=0; +int nb_processes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); +char exe[1024]; +pid_t *pids; +int i; + +pids = malloc(nb_processes * sizeof(pid_t)); +assert(pids != NULL); + +proc_listpids(PROC_ALL_PIDS, 0, pids, nb_processes); +for(i = 0; i < nb_processes; ++i) { + if (pids[i] == 0) { + continue; + } + proc_name(pids[i], exe, sizeof(exe)); + if(!strcmp(exe, bin_name)) { + pid_list[pid_count].pid=pids[i]; + strcpy(pid_list[pid_count].name, bin_name); + pid_count++; + if(pid_count==max_pids) + break; + } +} +free(pids); +return pid_count; +} +#endif // __APPLE__ +#ifdef __linux__ +int find_pid_by_id(pid_t pid, pidinfo_t *pid_list) +{ +char fullpath_exe[MAXPATHLEN + 1]; +char exe[MAXPATHLEN + 1]; +ssize_t len; + +snprintf(fullpath_exe, MAXPATHLEN, "%s/%i/exe", PROC_PATH, pid); + +len=readlink(fullpath_exe, exe, MAXPATHLEN); +if (len != -1) + exe[len] = 0; +else + return 0; + +pid_list[0].pid = pid; +strcpy(pid_list[0].name, basename(exe)); +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; +int res; + +proc=opendir(PROC_PATH); +if (!proc) { + nperror("opendir"); + nfprintf(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_debug) + nperror("stat (find_pids_by_binary_name)"); + continue; + } + + if ((S_ISDIR(stat_buf.st_mode) && is_numeric(direntp->d_name))) { + res = snprintf(fullpath_exe, MAXPATHLEN, "%s/exe", fullpath_dir); + if (res < 0) { + fprintf(stderr, "path is too long: %s\n", fullpath_dir); + exit(EXIT_FAILURE); + } + len=readlink(fullpath_exe, exe, MAXPATHLEN); + if (len != -1) + exe[len] = 0; + else { + // Will be mostly "Permission denied" + //~ nperror("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; +} +#endif // __linux__ +#ifdef __FreeBSD__ +int find_pid_by_id(pid_t pid, pidinfo_t *pid_list) +{ +struct procstat *procstat; +struct kinfo_proc *procs; +unsigned int proc_count; + +struct kinfo_proc *proc; +char pathname[PATH_MAX]; + +int i, found = 0; + +procstat = procstat_open_sysctl(); +assert(procstat != NULL); + +procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); +if (procs == NULL) + goto done; + +for (i = 0; i < proc_count; i++) { + proc = &procs[i]; + procstat_getpathname(procstat, proc, pathname, sizeof(pathname)); + if (strlen(pathname) == 0) + // kernel thread I guess? + continue; + + pid_list[0].pid = pid; + strcpy(pid_list[0].name, basename(pathname)); + found = 1; + break; +} + +procstat_freeprocs(procstat, procs); +done: +procstat_close(procstat); + +return found; +} + +int find_pids_by_binary_name(char *bin_name, pidinfo_t *pid_list, int max_pids) +{ +struct procstat *procstat; +struct kinfo_proc *procs; +unsigned int proc_count; + +struct kinfo_proc *proc; +char pathname[PATH_MAX]; + +int pid_count = 0; +int i; + +procstat = procstat_open_sysctl(); +assert(procstat != NULL); + +procs = procstat_getprocs(procstat, KERN_PROC_PROC, 0, &proc_count); +if (procs == NULL) + goto done; + +for (i = 0; i < proc_count; i++) { + proc = &procs[i]; + procstat_getpathname(procstat, proc, pathname, sizeof(pathname)); + if (strlen(pathname) == 0) + // kernel thread I guess? see proc->ki_comm instead + continue; + + if (!strcmp(basename(pathname), bin_name)) { + pid_list[pid_count].pid = proc->ki_pid; + strcpy(pid_list[pid_count].name, bin_name); + pid_count++; + if (pid_count == max_pids) + break; + } +} + +procstat_freeprocs(procstat, procs); +done: +procstat_close(procstat); + +return pid_count; +} +#endif // __FreeBSD__ + +#ifdef __APPLE__ +int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd) +{ +int count = 0; +int bufferSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, 0, 0); +struct stat stat_buf; + +if (bufferSize < 0) { + printf("Error :/, cannot proc_pidinfo\n"); + return 0; +} +struct proc_fdinfo *procFDInfo = (struct proc_fdinfo *)malloc(bufferSize); +assert(procFDInfo != NULL); +proc_pidinfo(pid, PROC_PIDLISTFDS, 0, procFDInfo, bufferSize); +int numberOfProcFDs = bufferSize / PROC_PIDLISTFD_SIZE; +int i; + +for(i = 0; i < numberOfProcFDs; i++) { + if(procFDInfo[i].proc_fdtype == PROX_FDTYPE_VNODE) { + struct vnode_fdinfowithpath vnodeInfo; + proc_pidfdinfo(pid, procFDInfo[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE); + if (stat(vnodeInfo.pvip.vip_path, &stat_buf) < 0) { + if (flag_debug) + perror("sstat"); + continue; + } + if (!S_ISREG(stat_buf.st_mode) && !S_ISBLK(stat_buf.st_mode)) + continue; + + if (is_ignored_file(vnodeInfo.pvip.vip_path)) + continue; + + // OK, we've found a potential interesting file. + + fd_list[count++] = procFDInfo[i].proc_fd; + //~ printf("[debug] %s\n",vnodeInfo.pvip.vip_path); + if(count == max_fd) + break; + } +} +return count; +} +#endif // __APPLE__ +#ifdef __linux__ +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; +int res; + +snprintf(path_dir, MAXPATHLEN, "%s/%d/fd", PROC_PATH, pid); + +proc = opendir(path_dir); +if (!proc) { + nperror("opendir"); + nfprintf(stderr,"Can't open %s\n",path_dir); + return 0; +} + +while ((direntp = readdir(proc)) != NULL) { + res = snprintf(fullpath, MAXPATHLEN, "%s/%s", path_dir, direntp->d_name); + if (res < 0) { + fprintf(stderr, "path is too long: %s/%s\n", path_dir, direntp->d_name); + exit(EXIT_FAILURE); + } + if (stat(fullpath, &stat_buf) == -1) { + if (flag_debug) + nperror("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; + + if (is_ignored_file(fullpath) || is_ignored_file(link_dest)) + 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; +} +#endif // __linux__ +#ifdef __FreeBSD__ +int find_fd_for_pid(pid_t pid, int *fd_list, int max_fd) +{ +struct procstat *procstat; +struct kinfo_proc *procs; +unsigned int proc_count; + +struct kinfo_proc *proc; +struct filestat *fstat; +struct filestat_list *fstat_list; + +int count = 0; +int i; + +procstat = procstat_open_sysctl(); +assert(procstat != NULL); + +procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); +if (procs == NULL) + goto done; + +for (i = 0; i < proc_count; i++) { + proc = &procs[i]; + + fstat_list = procstat_getfiles(procstat, proc, 0); + if (fstat_list == NULL) + continue; + STAILQ_FOREACH(fstat, fstat_list, next) { + if (fstat->fs_type != PS_FST_TYPE_VNODE) + continue; + if (fstat->fs_fd < 0) // usually non-zero fs_uflags: PS_FST_UFLAG_{TEXT,CTTY,...} + continue; + + struct vnstat vn; + char errbuf[_POSIX2_LINE_MAX]; + + if (procstat_get_vnode_info(procstat, fstat, &vn, errbuf) != 0) + // see errbuf + continue; + + if (!(vn.vn_type == PS_FST_VTYPE_VREG || vn.vn_type == PS_FST_VTYPE_VBLK)) + continue; + + if (is_ignored_file(fstat->fs_path)) + continue; + + // OK, we've found a potential interesting file. + fd_list[count++] = fstat->fs_fd; + // fstat->fs_offset is looked up once again in get_fdinfo() + + if (count == max_fd) + break; + } + + procstat_freefiles(procstat, fstat_list); +} + +procstat_freeprocs(procstat, procs); +done: +procstat_close(procstat); + +return count; +} +#endif // __FreeBSD__ + + +signed char get_fdinfo(pid_t pid, int fdnum, fdinfo_t *fd_info) +{ +struct stat stat_buf; +#ifdef __linux__ +char fdpath[MAXPATHLEN + 1]; +char line[LINE_LEN]; +FILE *fp; +int flags; +#endif +struct timezone tz; + +fd_info->num = fdnum; +fd_info->mode = PM_NONE; + +#ifdef __APPLE__ +struct vnode_fdinfowithpath vnodeInfo; +if (proc_pidfdinfo(pid, fdnum, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE) <= 0) + return 0; +strncpy(fd_info->name, vnodeInfo.pvip.vip_path, MAXPATHLEN); +#endif // __APPLE__ +#ifdef __linux__ +ssize_t len; +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 { + //~ nperror("readlink"); + return 0; +} +#endif +#ifdef __FreeBSD__ +struct procstat *procstat; +struct kinfo_proc *procs; +unsigned int proc_count; + +struct kinfo_proc *proc; +struct filestat *fstat; +struct filestat_list *fstat_list; + +int i; + +procstat = procstat_open_sysctl(); +assert(procstat != NULL); + +procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); +if (procs == NULL) + goto done; + +for (i = 0; i < proc_count; i++) { + proc = &procs[i]; + + fstat_list = procstat_getfiles(procstat, proc, 0); + if (fstat_list == NULL) + continue; + + gettimeofday(&fd_info->tv, &tz); + + STAILQ_FOREACH(fstat, fstat_list, next) { + if (fstat->fs_fd != fdnum) + continue; + + strncpy(fd_info->name, fstat->fs_path, MAXPATHLEN); + + struct vnstat vn; + char errbuf[_POSIX2_LINE_MAX]; + + if (procstat_get_vnode_info(procstat, fstat, &vn, errbuf) != 0) + // see errbuf + continue; + + fd_info->pos = fstat->fs_offset; + // XXX PS_FST_FFLAG_APPEND? + fd_info->mode = ( + fstat->fs_fflags & (PS_FST_FFLAG_WRITE | PS_FST_FFLAG_READ) ? PM_READWRITE : + fstat->fs_fflags & PS_FST_FFLAG_WRITE ? PM_WRITE : + fstat->fs_fflags & PS_FST_FFLAG_READ ? PM_READ : + 0 + ); + } + + procstat_freefiles(procstat, fstat_list); +} + +procstat_freeprocs(procstat, procs); +done: +procstat_close(procstat); +#endif // __FreeBSD__ + +if (stat(fd_info->name, &stat_buf) == -1) { + //~ printf("[debug] %i - %s\n",pid,fd_info->name); + if (flag_debug) + nperror("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_debug) + nperror("open (get_fdinfo)"); + return 0; + } + +#ifdef __APPLE__ + uint64_t bc; + uint32_t bs; + + bs = 0; + bc = 0; + if (ioctl(fd, DKIOCGETBLOCKSIZE, &bs) < 0 || ioctl(fd, DKIOCGETBLOCKCOUNT, &bc) < 0) { + if (flag_debug) + perror("ioctl (get_fdinfo)"); + return 0; + } + fd_info->size = bc*bs; + printf("Size: %lld\n", fd_info->size); +#endif +#ifdef __FreeBSD__ + if (ioctl(fd, DIOCGMEDIASIZE, &fd_info->size) < 0) { + if (flag_debug) + nperror("ioctl (get_fdinfo)"); + close(fd); + return 0; + } +#endif +#ifdef __linux__ + if (ioctl(fd, BLKGETSIZE64, &fd_info->size) < 0) { + if (flag_debug) + nperror("ioctl (get_fdinfo)"); + close(fd); + return 0; + } +#endif + close(fd); +} else { + fd_info->size = stat_buf.st_size; +} + +#ifdef __APPLE__ +fd_info->pos = vnodeInfo.pfi.fi_offset; +gettimeofday(&fd_info->tv, &tz); +if (vnodeInfo.pfi.fi_openflags & FREAD) + fd_info->mode = PM_READ; +if (vnodeInfo.pfi.fi_openflags & FWRITE) + fd_info->mode = PM_WRITE; +if (vnodeInfo.pfi.fi_openflags & FREAD && vnodeInfo.pfi.fi_openflags & FWRITE) + fd_info->mode = PM_READWRITE; +#endif // __APPLE__ +#ifdef __linux__ +flags = 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_debug) + nperror("fopen (get_fdinfo)"); + return 0; +} + +while (fgets(line, LINE_LEN - 1, fp) != NULL) { + if (!strncmp(line, "pos:", 4)) + fd_info->pos = atoll(line + 5); + if (!strncmp(line, "flags:", 6)) + flags = atoll(line + 7); +} + +if ((flags & O_ACCMODE) == O_RDONLY) + fd_info->mode = PM_READ; +if ((flags & O_ACCMODE) == O_WRONLY) + fd_info->mode = PM_WRITE; +if ((flags & O_ACCMODE) == O_RDWR) + fd_info->mode = PM_READWRITE; + +fclose(fp); +#endif // __linux__ +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++) { + putchar('='); +} +putchar('>'); +i++; + +for ( ; i < char_available ; i++) + putchar(' '); + +} + + +void parse_options(int argc, char *argv[]) +{ +static struct option long_options[] = { + {"timeline", no_argument, 0, 't'}, + {"timeline-remove", no_argument, 0, 'T'}, + {"version", no_argument, 0, 'v'}, + {"quiet", no_argument, 0, 'q'}, + {"debug", no_argument, 0, 'd'}, + {"wait", no_argument, 0, 'w'}, + {"wait-delay", required_argument, 0, 'W'}, + {"monitor", no_argument, 0, 'm'}, + {"monitor-continuously", no_argument, 0, 'M'}, + {"help", no_argument, 0, 'h'}, + {"additional-command", required_argument, 0, 'a'}, + {"command", required_argument, 0, 'c'}, + {"pid", required_argument, 0, 'p'}, + {"ignore-file", required_argument, 0, 'i'}, + {"open-mode", required_argument, 0, 'o'}, + {0, 0, 0, 0} +}; + +static char *options_string = "TtvqdwmMha:c:p:W:i:o:"; +int c,i; +int option_index = 0; +char *rp; + +optind = 1; // reset getopt + +while(1) { + c = getopt_long (argc, argv, options_string, long_options, &option_index); + + // no more options + if (c == -1) + break; + + switch (c) { + case 'T': + timeline=fopen("timeline.txt","w"); + fclose(timeline); + exit(EXIT_SUCCESS); + case 't': + timeline=fopen("timeline.txt","r"); + char buffer[1024]; + if(timeline==NULL) + printf("no file or not opened"); + for(;;){ + if(fgets(buffer, sizeof(buffer), timeline)==NULL) break; + printf("%s",buffer);} + fclose(timeline); + exit(EXIT_SUCCESS); + case 'v': + printf("B889056 progress version %s\n", PROGRESS_VERSION); + exit(EXIT_SUCCESS); + break; + + case 'h': + printf("progress - Coreutils Viewer\n"); + printf("---------------------\n"); + printf("Shows progress on file manipulations (cp, mv, dd, ...)\n\n"); + printf("Monitored commands (default, you can add virtually anything):\n"); + for(i = 0 ; i < proc_names_cnt ; i++) + printf("%s ", proc_names[i]); + printf("\n\n"); + printf("Usage: %s [-qdwmM] [-W secs] [-c command] [-p pid]\n",argv[0]); + printf(" -q --quiet hides all messages\n"); + printf(" -d --debug shows all warning/error messages\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(" -m --monitor loop while monitored processes are still running\n"); + printf(" -M --monitor-continuously like monitor but never stop (similar to watch %s)\n", argv[0]); + printf(" -a --additional-command cmd add additional command to default command list\n"); + printf(" -c --command cmd monitor only this command name (ex: firefox)\n"); + printf(" -p --pid id monitor only this process ID (ex: `pidof firefox`)\n"); + printf(" -i --ignore-file file do not report process if using file\n"); + printf(" -o --open-mode {r|w} report only files opened for read or write\n"); + printf(" -v --version show program version and exit\n"); + printf(" -t --timeline show coreutils timeline while monitoring\n"); + printf(" -T --timeline-remove remove timeline\n"); + printf(" -h --help display this help and exit\n"); + printf("\n\n"); + printf("Multiple options allowed for: -a -c -p -i. Use PROGRESS_ARGS for permanent arguments.\n"); + exit(EXIT_SUCCESS); + break; + + case 'q': + flag_quiet = 1; + break; + + case 'd': + flag_debug = 1; + break; + + case 'i': + rp = realpath(optarg, NULL); + ignore_file_list_cnt++; + ignore_file_list = realloc(ignore_file_list, ignore_file_list_cnt * sizeof(char *)); + assert(ignore_file_list != NULL); + if (rp) + ignore_file_list[ignore_file_list_cnt - 1] = rp; + else + ignore_file_list[ignore_file_list_cnt - 1] = strdup(optarg); // file does not exist yet, it seems + break; + + case 'a': + proc_names_cnt++; + proc_names = realloc(proc_names, proc_names_cnt * sizeof(char *)); + assert(proc_names != NULL); + proc_names[proc_names_cnt - 1] = strdup(optarg); + break; + + case 'c': + proc_specifiq_name_cnt++; + proc_specifiq_name = realloc(proc_specifiq_name, proc_specifiq_name_cnt * sizeof(char *)); + assert(proc_specifiq_name != NULL); + proc_specifiq_name[proc_specifiq_name_cnt - 1] = strdup(optarg); + break; + + case 'p': + proc_specifiq_pid_cnt++; + proc_specifiq_pid = realloc(proc_specifiq_pid, proc_specifiq_pid_cnt * sizeof(pid_t)); + assert(proc_specifiq_pid != NULL); + proc_specifiq_pid[proc_specifiq_pid_cnt - 1] = atof(optarg); + break; + + case 'w': + flag_throughput = 1; + break; + + case 'm': + flag_monitor = 1; + break; + + case 'M': + flag_monitor_continuous = 1; + break; + + case 'W': + flag_throughput = 1; + throughput_wait_secs = atof(optarg); + break; + + case 'o': + if (!strcmp("r", optarg)) + flag_open_mode = PM_READ; + else if (!strcmp("w", optarg)) + flag_open_mode = PM_WRITE; + else { + fprintf(stderr,"Invalid --open-mode option value '%s'.\n", optarg); + exit(EXIT_FAILURE); + } + break; + case '?': + default: + exit(EXIT_FAILURE); + } +} + +if (optind < argc) { + fprintf(stderr,"Invalid arguments.\n"); + exit(EXIT_FAILURE); +} + +} + +void print_eta(time_t seconds) +{ +struct tm *p; + +if (!seconds) + return; + +p = gmtime(&seconds); + +nprintf(" remaining "); +if (p->tm_yday) + nprintf("%d day%s ", p->tm_yday, p->tm_yday > 1 ? "s" : ""); +nprintf("%d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); +} + +void copy_and_clean_results(result_t *results, int result_count, char copy) +{ +static result_t old_results[MAX_RESULTS]; +static int old_result_count = 0; + +if (copy) { + int i; + for (i = 0; i < old_result_count; ++i) { + int j; + char found = 0; + for (j = 0; j < result_count; ++j) { + if (results[j].pid.pid == old_results[i].pid.pid) { + found = 1; + results[j].hbegin = old_results[i].hbegin; + results[j].hend = old_results[i].hend; + results[j].hsize = old_results[i].hsize; + break; + } + } + if (!found) + free_hlist(old_results[i].hbegin); + } +} +else { + memcpy(old_results, results, sizeof(old_results)); + old_result_count = result_count; + } +} + +int monitor_processes(int *nb_pid) +{ +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]; +float perc; +result_t results[MAX_RESULTS]; +signed char still_there; +signed char search_all = 1; +static signed char first_pass = 1; +timeline=fopen("timeline.txt","a+"); +int flag; +char buffer[128]; +char command[128]; + +pid_count = 0; +if (!flag_monitor && !flag_monitor_continuous) + first_pass = 0; + + +if (proc_specifiq_name_cnt) { + search_all = 0; + for (i = 0 ; i < proc_specifiq_name_cnt ; ++i) { + pid_count += find_pids_by_binary_name(proc_specifiq_name[i], + pidinfo_list + pid_count, + MAX_PIDS - pid_count); + if(pid_count >= MAX_PIDS) { + nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); + return 0; + } + } +} + +if (proc_specifiq_pid) { + search_all = 0; + for (i = 0 ; i < proc_specifiq_pid_cnt ; ++i) { + pid_count += find_pid_by_id(proc_specifiq_pid[i], + pidinfo_list + pid_count); + + if(pid_count >= MAX_PIDS) { + nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); + return 0; + } + } +} + +if (search_all) { + for (i = 0 ; i < proc_names_cnt ; i++) { + pid_count += find_pids_by_binary_name(proc_names[i], + pidinfo_list + pid_count, + MAX_PIDS - pid_count); + if(pid_count >= MAX_PIDS) { + nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); + return 0; + } + } +} + +*nb_pid = pid_count; + +if (!pid_count) { + if (flag_quiet) + return 0; + if (flag_monitor || flag_monitor_continuous) { + clear(); + refresh(); + } + if (proc_specifiq_pid_cnt) { + nfprintf(stderr, "No such pid: "); + for (i = 0 ; i < proc_specifiq_pid_cnt; ++i) { + nfprintf(stderr, "%d, ", proc_specifiq_pid[i]); + } + } + if (proc_specifiq_name_cnt) + { + nfprintf(stderr, "No such command(s) running: "); + for (i = 0 ; i < proc_specifiq_name_cnt; ++i) { + nfprintf(stderr, "%s, ", proc_specifiq_name[i]); + } + } + if (!proc_specifiq_pid && !proc_specifiq_name_cnt) { + nfprintf(stderr,"No command currently running: "); + for (i = 0 ; i < proc_names_cnt ; i++) { + nfprintf(stderr,"%s, ", proc_names[i]); + } + } + nfprintf(stderr,"or wrong permissions.\n"); + first_pass = 0; + 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 (flag_open_mode == PM_READ && fdinfo.mode != PM_READ && fdinfo.mode != PM_READWRITE) + continue; + if (flag_open_mode == PM_WRITE && fdinfo.mode != PM_WRITE && fdinfo.mode != PM_READWRITE) + continue; + + if (fdinfo.size > max_size) { + biggest_fd = fdinfo; + max_size = fdinfo.size; + } + } + + if (!max_size) { // nothing found + // this display is the root of too many confusion for the users, let's + // remove it. And it does not play well with --i option. +/* nprintf("[%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; + results[result_count].hbegin = NULL; + results[result_count].hend = NULL; + results[result_count].hsize = 0; + + result_count++; +} + +// wait a bit, so we can estimate the throughput +if (flag_throughput && !first_pass) + usleep(1000000 * throughput_wait_secs); +if (flag_monitor || flag_monitor_continuous) { + clear(); +} +copy_and_clean_results(results, result_count, 1); +for (i = 0 ; i < result_count ; i++) { + + if (flag_throughput && !first_pass) { + 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; + + } + + nprintf("[%5d] %s %s\n\t%.1f%% (%s / %s)", + results[i].pid.pid, + results[i].pid.name, + results[i].fd.name, + perc, + fpos, + fsize); + + sprintf(command,"[%5d] %s %s\n", + results[i].pid.pid, + results[i].pid.name, + results[i].fd.name); + + flag=1; + + for (;;) { + if (fgets(buffer, sizeof(buffer), timeline) == NULL) + break; + flag = strcmp(buffer, command); + if(flag==0) + break; + } + + if(flag!=0) + fprintf(timeline,command); + + if (flag_throughput && still_there && !first_pass) { + // 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; + results[i].hsize += add_to_hlist(&results[i].hbegin, &results[i].hend, results[i].hsize, byte_diff / (usec_diff / 1000000.0)); + bytes_per_sec = get_hlist_average(results[i].hbegin, results[i].hsize); + + format_size(bytes_per_sec, ftroughput); + nprintf(" %s/s", ftroughput); + if (bytes_per_sec && fdinfo.size - fdinfo.pos >= 0) { + print_eta((fdinfo.size - fdinfo.pos) / bytes_per_sec); + } + } + + + nprintf("\n\n"); + + // Need to work on window width when using screen/watch/... + //~ printf(" ["); + //~ print_bar(perc, ws.ws_col-6); + //~ printf("]\n"); +} +if (flag_monitor || flag_monitor_continuous) { + if (!result_count) + nprintf("No PID(s) currently monitored\n"); + refresh(); +} +copy_and_clean_results(results, result_count, 0); +first_pass = 0; +return 0; +} + +void int_handler(int sig) +{ +if(flag_monitor || flag_monitor_continuous) + endwin(); +exit(0); +} + +// Setup the default commands as a dynamic list +void populate_proc_names() { + int i; + for(i = 0 ; default_proc_names[i] ; i++) { + proc_names_cnt++; + proc_names = realloc(proc_names, proc_names_cnt * sizeof(char *)); + assert(proc_names != NULL); + proc_names[proc_names_cnt - 1] = default_proc_names[i]; + } +} + +int main(int argc, char *argv[]) +{ +pid_t nb_pid; +struct winsize ws; +wordexp_t env_wordexp; +char *env_progress_args; +char *env_progress_args_full; + +populate_proc_names(); + +env_progress_args = getenv("PROGRESS_ARGS"); + +if (env_progress_args) { + int full_len; + + // prefix with (real) argv[0] + // argv[0] + ' ' + env_progress_args + '\0' + full_len = strlen(argv[0]) + 1 + strlen(env_progress_args) + 1; + env_progress_args_full = malloc(full_len * sizeof(char)); + assert(env_progress_args_full != NULL); + sprintf(env_progress_args_full, "%s %s", argv[0], env_progress_args); + + if (wordexp(env_progress_args_full, &env_wordexp, 0)) { + fprintf(stderr,"Unable to parse PROGRESS_ARGS environment variable.\n"); + exit(EXIT_FAILURE); + } + parse_options(env_wordexp.we_wordc,env_wordexp.we_wordv); +} +parse_options(argc,argv); + +// ws.ws_row, ws.ws_col +ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); +if (flag_monitor || flag_monitor_continuous) { + setlocale(LC_CTYPE, ""); + if ((mainwin = initscr()) == NULL ) { + fprintf(stderr, "Error initialising ncurses.\n"); + exit(EXIT_FAILURE); + } + if (!flag_throughput) { + flag_throughput = 1; + throughput_wait_secs = 1; + } + set_hlist_size(throughput_wait_secs); + signal(SIGINT, int_handler); + do { + monitor_processes(&nb_pid); + refresh(); + if(flag_monitor_continuous && !nb_pid) { + usleep(1000000 * throughput_wait_secs); + } + } while ((flag_monitor && nb_pid) || flag_monitor_continuous); + endwin(); +} +else { + set_hlist_size(throughput_wait_secs); + monitor_processes(&nb_pid); +} +return 0; +} diff --git a/progress.c b/progress.c index b329023..097a8d2 100644 --- a/progress.c +++ b/progress.c @@ -69,9 +69,10 @@ // Given -a will dynamically add values to this list, move it to be a dynamic // list and generate it at runtime. +struct winsize ws; static int proc_names_cnt; -static char **proc_names; -char *default_proc_names[] = {"cp", "mv", "dd", "tar", "bsdtar", "cat", "rsync", "scp", +static char** proc_names; +char* default_proc_names[] = { "cp", "mv", "dd", "tar", "bsdtar", "cat", "rsync", "scp", "grep", "fgrep", "egrep", "cut", "sort", "md5sum", "sha1sum", "sha224sum", "sha256sum", "sha384sum", "sha512sum", #ifdef __FreeBSD__ @@ -90,13 +91,24 @@ char *default_proc_names[] = {"cp", "mv", "dd", "tar", "bsdtar", "cat", "rsync", NULL }; +typedef struct id { + int pid; + char name[MAXPATHLEN + 1]; + char loc[MAXPATHLEN + 1]; + float perc; + char fpos[64]; + char fsize[64]; + time_t eta; + char ftroughput[64]; +} id; + // static means initialized to 0/NULL (C standard, §6.7.8/10) static int proc_specifiq_name_cnt; -static char **proc_specifiq_name; +static char** proc_specifiq_name; static int ignore_file_list_cnt; -static char **ignore_file_list; +static char** ignore_file_list; static int proc_specifiq_pid_cnt; -static pid_t *proc_specifiq_pid; +static pid_t* proc_specifiq_pid; signed char flag_quiet = 0; signed char flag_debug = 0; @@ -106,673 +118,709 @@ signed char flag_monitor_continuous = 0; signed char flag_open_mode = 0; double throughput_wait_secs = 1; -WINDOW *mainwin; +signed char order_by_pid = 1; +signed char descending = 0; +signed char order_by_eta = 0; +signed char one_by_one = 0; +signed char order_by_perc = 0; + +WINDOW* mainwin; -signed char is_numeric(char *str) +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; } -void nprintf(char *format, ...) +void nprintf(char* format, ...) { -va_list args; - -va_start(args, format); -if (flag_monitor || flag_monitor_continuous) - vw_printw(mainwin, format, args); -else - vprintf(format, args); -va_end(args); + va_list args; + + va_start(args, format); + if (flag_monitor || flag_monitor_continuous) + vw_printw(mainwin, format, args); + else + vprintf(format, args); + va_end(args); } -void nfprintf(FILE *file, char *format, ...) { -va_list args; +void nfprintf(FILE* file, char* format, ...) { + va_list args; -va_start(args, format); -if (flag_monitor || flag_monitor_continuous) - vw_printw(mainwin, format, args); -else - vfprintf(file, format, args); -va_end(args); + va_start(args, format); + if (flag_monitor || flag_monitor_continuous) + vw_printw(mainwin, format, args); + else + vfprintf(file, format, args); + va_end(args); } -void nperror(const char *s) { -if (flag_monitor || flag_monitor_continuous) - printw("%s:%s", s, strerror(errno)); -else - perror(s); +void nperror(const char* s) { + if (flag_monitor || flag_monitor_continuous) + printw("%s:%s", s, strerror(errno)); + else + perror(s); } -signed char is_ignored_file(char *str) +signed char is_ignored_file(char* str) { -int i; -for (i = 0 ; i < ignore_file_list_cnt ; i++) - if (!strcmp(ignore_file_list[i], str)) - return 1; -return 0; + int i; + for (i = 0; i < ignore_file_list_cnt; i++) + if (!strcmp(ignore_file_list[i], str)) + return 1; + return 0; } #ifdef __APPLE__ -int find_pid_by_id(pid_t pid, pidinfo_t *pid_list) +int find_pid_by_id(pid_t pid, pidinfo_t* pid_list) { -char exe[MAXPATHLEN + 1]; + char exe[MAXPATHLEN + 1]; -exe[0] = '\0'; -proc_name(pid, exe, sizeof(exe)); -if (exe[0] == '\0') - return 0; + exe[0] = '\0'; + proc_name(pid, exe, sizeof(exe)); + if (exe[0] == '\0') + return 0; -pid_list[0].pid = pid; -strcpy(pid_list[0].name, exe); -return 1; + pid_list[0].pid = pid; + strcpy(pid_list[0].name, exe); + 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_name, pidinfo_t* pid_list, int max_pids) { -int pid_count=0; -int nb_processes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); -char exe[1024]; -pid_t *pids; -int i; - -pids = malloc(nb_processes * sizeof(pid_t)); -assert(pids != NULL); - -proc_listpids(PROC_ALL_PIDS, 0, pids, nb_processes); -for(i = 0; i < nb_processes; ++i) { - if (pids[i] == 0) { - continue; - } - proc_name(pids[i], exe, sizeof(exe)); - if(!strcmp(exe, bin_name)) { - pid_list[pid_count].pid=pids[i]; - strcpy(pid_list[pid_count].name, bin_name); - pid_count++; - if(pid_count==max_pids) - break; + int pid_count = 0; + int nb_processes = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); + char exe[1024]; + pid_t* pids; + int i; + + pids = malloc(nb_processes * sizeof(pid_t)); + assert(pids != NULL); + + proc_listpids(PROC_ALL_PIDS, 0, pids, nb_processes); + for (i = 0; i < nb_processes; ++i) { + if (pids[i] == 0) { + continue; + } + proc_name(pids[i], exe, sizeof(exe)); + if (!strcmp(exe, bin_name)) { + pid_list[pid_count].pid = pids[i]; + strcpy(pid_list[pid_count].name, bin_name); + pid_count++; + if (pid_count == max_pids) + break; + } } -} -free(pids); -return pid_count; + free(pids); + return pid_count; } #endif // __APPLE__ #ifdef __linux__ -int find_pid_by_id(pid_t pid, pidinfo_t *pid_list) +int find_pid_by_id(pid_t pid, pidinfo_t* pid_list) { -char fullpath_exe[MAXPATHLEN + 1]; -char exe[MAXPATHLEN + 1]; -ssize_t len; + char fullpath_exe[MAXPATHLEN + 1]; + char exe[MAXPATHLEN + 1]; + ssize_t len; -snprintf(fullpath_exe, MAXPATHLEN, "%s/%i/exe", PROC_PATH, pid); + snprintf(fullpath_exe, MAXPATHLEN, "%s/%i/exe", PROC_PATH, pid); -len=readlink(fullpath_exe, exe, MAXPATHLEN); -if (len != -1) - exe[len] = 0; -else - return 0; + len = readlink(fullpath_exe, exe, MAXPATHLEN); + if (len != -1) + exe[len] = 0; + else + return 0; -pid_list[0].pid = pid; -strcpy(pid_list[0].name, basename(exe)); -return 1; + pid_list[0].pid = pid; + strcpy(pid_list[0].name, basename(exe)); + 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_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; -int res; - -proc=opendir(PROC_PATH); -if (!proc) { - nperror("opendir"); - nfprintf(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_debug) - nperror("stat (find_pids_by_binary_name)"); - continue; + 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; + int res; + + proc = opendir(PROC_PATH); + if (!proc) { + nperror("opendir"); + nfprintf(stderr, "Can't open %s\n", PROC_PATH); + exit(EXIT_FAILURE); } - if ((S_ISDIR(stat_buf.st_mode) && is_numeric(direntp->d_name))) { - res = snprintf(fullpath_exe, MAXPATHLEN, "%s/exe", fullpath_dir); - if (res < 0) { - fprintf(stderr, "path is too long: %s\n", fullpath_dir); - exit(EXIT_FAILURE); - } - len=readlink(fullpath_exe, exe, MAXPATHLEN); - if (len != -1) - exe[len] = 0; - else { - // Will be mostly "Permission denied" - //~ nperror("readlink"); + 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_debug) + nperror("stat (find_pids_by_binary_name)"); 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; + if ((S_ISDIR(stat_buf.st_mode) && is_numeric(direntp->d_name))) { + res = snprintf(fullpath_exe, MAXPATHLEN, "%s/exe", fullpath_dir); + if (res < 0) { + fprintf(stderr, "path is too long: %s\n", fullpath_dir); + exit(EXIT_FAILURE); + } + len = readlink(fullpath_exe, exe, MAXPATHLEN); + if (len != -1) + exe[len] = 0; + else { + // Will be mostly "Permission denied" + //~ nperror("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; + closedir(proc); + return pid_count; } #endif // __linux__ #ifdef __FreeBSD__ -int find_pid_by_id(pid_t pid, pidinfo_t *pid_list) +int find_pid_by_id(pid_t pid, pidinfo_t* pid_list) { -struct procstat *procstat; -struct kinfo_proc *procs; -unsigned int proc_count; + struct procstat* procstat; + struct kinfo_proc* procs; + unsigned int proc_count; -struct kinfo_proc *proc; -char pathname[PATH_MAX]; + struct kinfo_proc* proc; + char pathname[PATH_MAX]; -int i, found = 0; + int i, found = 0; -procstat = procstat_open_sysctl(); -assert(procstat != NULL); + procstat = procstat_open_sysctl(); + assert(procstat != NULL); -procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); -if (procs == NULL) - goto done; + procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); + if (procs == NULL) + goto done; -for (i = 0; i < proc_count; i++) { - proc = &procs[i]; - procstat_getpathname(procstat, proc, pathname, sizeof(pathname)); - if (strlen(pathname) == 0) - // kernel thread I guess? - continue; + for (i = 0; i < proc_count; i++) { + proc = &procs[i]; + procstat_getpathname(procstat, proc, pathname, sizeof(pathname)); + if (strlen(pathname) == 0) + // kernel thread I guess? + continue; - pid_list[0].pid = pid; - strcpy(pid_list[0].name, basename(pathname)); - found = 1; - break; -} + pid_list[0].pid = pid; + strcpy(pid_list[0].name, basename(pathname)); + found = 1; + break; + } -procstat_freeprocs(procstat, procs); + procstat_freeprocs(procstat, procs); done: -procstat_close(procstat); + procstat_close(procstat); -return found; + return found; } -int find_pids_by_binary_name(char *bin_name, pidinfo_t *pid_list, int max_pids) +int find_pids_by_binary_name(char* bin_name, pidinfo_t* pid_list, int max_pids) { -struct procstat *procstat; -struct kinfo_proc *procs; -unsigned int proc_count; - -struct kinfo_proc *proc; -char pathname[PATH_MAX]; - -int pid_count = 0; -int i; - -procstat = procstat_open_sysctl(); -assert(procstat != NULL); - -procs = procstat_getprocs(procstat, KERN_PROC_PROC, 0, &proc_count); -if (procs == NULL) - goto done; - -for (i = 0; i < proc_count; i++) { - proc = &procs[i]; - procstat_getpathname(procstat, proc, pathname, sizeof(pathname)); - if (strlen(pathname) == 0) - // kernel thread I guess? see proc->ki_comm instead - continue; - - if (!strcmp(basename(pathname), bin_name)) { - pid_list[pid_count].pid = proc->ki_pid; - strcpy(pid_list[pid_count].name, bin_name); - pid_count++; - if (pid_count == max_pids) - break; + struct procstat* procstat; + struct kinfo_proc* procs; + unsigned int proc_count; + + struct kinfo_proc* proc; + char pathname[PATH_MAX]; + + int pid_count = 0; + int i; + + procstat = procstat_open_sysctl(); + assert(procstat != NULL); + + procs = procstat_getprocs(procstat, KERN_PROC_PROC, 0, &proc_count); + if (procs == NULL) + goto done; + + for (i = 0; i < proc_count; i++) { + proc = &procs[i]; + procstat_getpathname(procstat, proc, pathname, sizeof(pathname)); + if (strlen(pathname) == 0) + // kernel thread I guess? see proc->ki_comm instead + continue; + + if (!strcmp(basename(pathname), bin_name)) { + pid_list[pid_count].pid = proc->ki_pid; + strcpy(pid_list[pid_count].name, bin_name); + pid_count++; + if (pid_count == max_pids) + break; + } } -} -procstat_freeprocs(procstat, procs); + procstat_freeprocs(procstat, procs); done: -procstat_close(procstat); + procstat_close(procstat); -return pid_count; + return pid_count; } #endif // __FreeBSD__ #ifdef __APPLE__ -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) { -int count = 0; -int bufferSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, 0, 0); -struct stat stat_buf; + int count = 0; + int bufferSize = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, 0, 0); + struct stat stat_buf; -if (bufferSize < 0) { - printf("Error :/, cannot proc_pidinfo\n"); - return 0; -} -struct proc_fdinfo *procFDInfo = (struct proc_fdinfo *)malloc(bufferSize); -assert(procFDInfo != NULL); -proc_pidinfo(pid, PROC_PIDLISTFDS, 0, procFDInfo, bufferSize); -int numberOfProcFDs = bufferSize / PROC_PIDLISTFD_SIZE; -int i; - -for(i = 0; i < numberOfProcFDs; i++) { - if(procFDInfo[i].proc_fdtype == PROX_FDTYPE_VNODE) { - struct vnode_fdinfowithpath vnodeInfo; - proc_pidfdinfo(pid, procFDInfo[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE); - if (stat(vnodeInfo.pvip.vip_path, &stat_buf) < 0) { - if (flag_debug) - perror("sstat"); - continue; - } - if (!S_ISREG(stat_buf.st_mode) && !S_ISBLK(stat_buf.st_mode)) - continue; + if (bufferSize < 0) { + printf("Error :/, cannot proc_pidinfo\n"); + return 0; + } + struct proc_fdinfo* procFDInfo = (struct proc_fdinfo*)malloc(bufferSize); + assert(procFDInfo != NULL); + proc_pidinfo(pid, PROC_PIDLISTFDS, 0, procFDInfo, bufferSize); + int numberOfProcFDs = bufferSize / PROC_PIDLISTFD_SIZE; + int i; - if (is_ignored_file(vnodeInfo.pvip.vip_path)) - continue; + for (i = 0; i < numberOfProcFDs; i++) { + if (procFDInfo[i].proc_fdtype == PROX_FDTYPE_VNODE) { + struct vnode_fdinfowithpath vnodeInfo; + proc_pidfdinfo(pid, procFDInfo[i].proc_fd, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE); + if (stat(vnodeInfo.pvip.vip_path, &stat_buf) < 0) { + if (flag_debug) + perror("sstat"); + continue; + } + if (!S_ISREG(stat_buf.st_mode) && !S_ISBLK(stat_buf.st_mode)) + continue; - // OK, we've found a potential interesting file. + if (is_ignored_file(vnodeInfo.pvip.vip_path)) + continue; - fd_list[count++] = procFDInfo[i].proc_fd; - //~ printf("[debug] %s\n",vnodeInfo.pvip.vip_path); - if(count == max_fd) - break; + // OK, we've found a potential interesting file. + + fd_list[count++] = procFDInfo[i].proc_fd; + //~ printf("[debug] %s\n",vnodeInfo.pvip.vip_path); + if (count == max_fd) + break; + } } -} -return count; + return count; } #endif // __APPLE__ #ifdef __linux__ -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) { -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; -int res; - -snprintf(path_dir, MAXPATHLEN, "%s/%d/fd", PROC_PATH, pid); - -proc = opendir(path_dir); -if (!proc) { - nperror("opendir"); - nfprintf(stderr,"Can't open %s\n",path_dir); - return 0; -} - -while ((direntp = readdir(proc)) != NULL) { - res = snprintf(fullpath, MAXPATHLEN, "%s/%s", path_dir, direntp->d_name); - if (res < 0) { - fprintf(stderr, "path is too long: %s/%s\n", path_dir, direntp->d_name); - exit(EXIT_FAILURE); - } - if (stat(fullpath, &stat_buf) == -1) { - if (flag_debug) - nperror("stat (find_fd_for_pid)"); - continue; + 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; + int res; + + snprintf(path_dir, MAXPATHLEN, "%s/%d/fd", PROC_PATH, pid); + + proc = opendir(path_dir); + if (!proc) { + nperror("opendir"); + nfprintf(stderr, "Can't open %s\n", path_dir); + return 0; } - // if not a regular file or a block device - if(!S_ISREG(stat_buf.st_mode) && !S_ISBLK(stat_buf.st_mode)) - continue; + while ((direntp = readdir(proc)) != NULL) { + res = snprintf(fullpath, MAXPATHLEN, "%s/%s", path_dir, direntp->d_name); + if (res < 0) { + fprintf(stderr, "path is too long: %s/%s\n", path_dir, direntp->d_name); + exit(EXIT_FAILURE); + } + if (stat(fullpath, &stat_buf) == -1) { + if (flag_debug) + nperror("stat (find_fd_for_pid)"); + continue; + } - // try to read link ... - len = readlink(fullpath, link_dest, MAXPATHLEN); - if (len != -1) - link_dest[len] = 0; - else - 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 stat link target (invalid link ?) - if (stat(link_dest, &stat_buf) == -1) - continue; + // try to read link ... + len = readlink(fullpath, link_dest, MAXPATHLEN); + if (len != -1) + link_dest[len] = 0; + else + continue; - if (is_ignored_file(fullpath) || is_ignored_file(link_dest)) - continue; + // try to stat link target (invalid link ?) + if (stat(link_dest, &stat_buf) == -1) + continue; - // OK, we've found a potential interesting file. + if (is_ignored_file(fullpath) || is_ignored_file(link_dest)) + continue; - fd_list[count++] = atoi(direntp->d_name); - //~ printf("[debug] %s\n",fullpath); - if (count == max_fd) - break; -} + // 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; + closedir(proc); + return count; } #endif // __linux__ #ifdef __FreeBSD__ -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) { -struct procstat *procstat; -struct kinfo_proc *procs; -unsigned int proc_count; + struct procstat* procstat; + struct kinfo_proc* procs; + unsigned int proc_count; -struct kinfo_proc *proc; -struct filestat *fstat; -struct filestat_list *fstat_list; + struct kinfo_proc* proc; + struct filestat* fstat; + struct filestat_list* fstat_list; -int count = 0; -int i; + int count = 0; + int i; -procstat = procstat_open_sysctl(); -assert(procstat != NULL); + procstat = procstat_open_sysctl(); + assert(procstat != NULL); -procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); -if (procs == NULL) - goto done; + procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); + if (procs == NULL) + goto done; -for (i = 0; i < proc_count; i++) { - proc = &procs[i]; + for (i = 0; i < proc_count; i++) { + proc = &procs[i]; - fstat_list = procstat_getfiles(procstat, proc, 0); - if (fstat_list == NULL) - continue; - STAILQ_FOREACH(fstat, fstat_list, next) { - if (fstat->fs_type != PS_FST_TYPE_VNODE) - continue; - if (fstat->fs_fd < 0) // usually non-zero fs_uflags: PS_FST_UFLAG_{TEXT,CTTY,...} + fstat_list = procstat_getfiles(procstat, proc, 0); + if (fstat_list == NULL) continue; + STAILQ_FOREACH(fstat, fstat_list, next) { + if (fstat->fs_type != PS_FST_TYPE_VNODE) + continue; + if (fstat->fs_fd < 0) // usually non-zero fs_uflags: PS_FST_UFLAG_{TEXT,CTTY,...} + continue; - struct vnstat vn; - char errbuf[_POSIX2_LINE_MAX]; + struct vnstat vn; + char errbuf[_POSIX2_LINE_MAX]; - if (procstat_get_vnode_info(procstat, fstat, &vn, errbuf) != 0) - // see errbuf - continue; + if (procstat_get_vnode_info(procstat, fstat, &vn, errbuf) != 0) + // see errbuf + continue; - if (!(vn.vn_type == PS_FST_VTYPE_VREG || vn.vn_type == PS_FST_VTYPE_VBLK)) - continue; + if (!(vn.vn_type == PS_FST_VTYPE_VREG || vn.vn_type == PS_FST_VTYPE_VBLK)) + continue; - if (is_ignored_file(fstat->fs_path)) - continue; + if (is_ignored_file(fstat->fs_path)) + continue; - // OK, we've found a potential interesting file. - fd_list[count++] = fstat->fs_fd; - // fstat->fs_offset is looked up once again in get_fdinfo() + // OK, we've found a potential interesting file. + fd_list[count++] = fstat->fs_fd; + // fstat->fs_offset is looked up once again in get_fdinfo() - if (count == max_fd) - break; - } + if (count == max_fd) + break; + } - procstat_freefiles(procstat, fstat_list); -} + procstat_freefiles(procstat, fstat_list); + } -procstat_freeprocs(procstat, procs); + procstat_freeprocs(procstat, procs); done: -procstat_close(procstat); + procstat_close(procstat); -return count; + return count; } #endif // __FreeBSD__ -signed char get_fdinfo(pid_t pid, int fdnum, fdinfo_t *fd_info) +signed char get_fdinfo(pid_t pid, int fdnum, fdinfo_t* fd_info) { -struct stat stat_buf; + struct stat stat_buf; #ifdef __linux__ -char fdpath[MAXPATHLEN + 1]; -char line[LINE_LEN]; -FILE *fp; -int flags; + char fdpath[MAXPATHLEN + 1]; + char line[LINE_LEN]; + FILE* fp; + int flags; #endif -struct timezone tz; + struct timezone tz; -fd_info->num = fdnum; -fd_info->mode = PM_NONE; + fd_info->num = fdnum; + fd_info->mode = PM_NONE; #ifdef __APPLE__ -struct vnode_fdinfowithpath vnodeInfo; -if (proc_pidfdinfo(pid, fdnum, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE) <= 0) - return 0; -strncpy(fd_info->name, vnodeInfo.pvip.vip_path, MAXPATHLEN); + struct vnode_fdinfowithpath vnodeInfo; + if (proc_pidfdinfo(pid, fdnum, PROC_PIDFDVNODEPATHINFO, &vnodeInfo, PROC_PIDFDVNODEPATHINFO_SIZE) <= 0) + return 0; + strncpy(fd_info->name, vnodeInfo.pvip.vip_path, MAXPATHLEN); #endif // __APPLE__ #ifdef __linux__ -ssize_t len; -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 { - //~ nperror("readlink"); - return 0; -} + ssize_t len; + 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 { + //~ nperror("readlink"); + return 0; + } #endif #ifdef __FreeBSD__ -struct procstat *procstat; -struct kinfo_proc *procs; -unsigned int proc_count; + struct procstat* procstat; + struct kinfo_proc* procs; + unsigned int proc_count; -struct kinfo_proc *proc; -struct filestat *fstat; -struct filestat_list *fstat_list; + struct kinfo_proc* proc; + struct filestat* fstat; + struct filestat_list* fstat_list; -int i; + int i; -procstat = procstat_open_sysctl(); -assert(procstat != NULL); + procstat = procstat_open_sysctl(); + assert(procstat != NULL); -procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); -if (procs == NULL) - goto done; + procs = procstat_getprocs(procstat, KERN_PROC_PID, pid, &proc_count); + if (procs == NULL) + goto done; -for (i = 0; i < proc_count; i++) { - proc = &procs[i]; + for (i = 0; i < proc_count; i++) { + proc = &procs[i]; - fstat_list = procstat_getfiles(procstat, proc, 0); - if (fstat_list == NULL) - continue; + fstat_list = procstat_getfiles(procstat, proc, 0); + if (fstat_list == NULL) + continue; - gettimeofday(&fd_info->tv, &tz); + gettimeofday(&fd_info->tv, &tz); - STAILQ_FOREACH(fstat, fstat_list, next) { - if (fstat->fs_fd != fdnum) - continue; + STAILQ_FOREACH(fstat, fstat_list, next) { + if (fstat->fs_fd != fdnum) + continue; - strncpy(fd_info->name, fstat->fs_path, MAXPATHLEN); + strncpy(fd_info->name, fstat->fs_path, MAXPATHLEN); - struct vnstat vn; - char errbuf[_POSIX2_LINE_MAX]; + struct vnstat vn; + char errbuf[_POSIX2_LINE_MAX]; - if (procstat_get_vnode_info(procstat, fstat, &vn, errbuf) != 0) - // see errbuf - continue; + if (procstat_get_vnode_info(procstat, fstat, &vn, errbuf) != 0) + // see errbuf + continue; - fd_info->pos = fstat->fs_offset; - // XXX PS_FST_FFLAG_APPEND? - fd_info->mode = ( - fstat->fs_fflags & (PS_FST_FFLAG_WRITE | PS_FST_FFLAG_READ) ? PM_READWRITE : - fstat->fs_fflags & PS_FST_FFLAG_WRITE ? PM_WRITE : - fstat->fs_fflags & PS_FST_FFLAG_READ ? PM_READ : - 0 - ); - } + fd_info->pos = fstat->fs_offset; + // XXX PS_FST_FFLAG_APPEND? + fd_info->mode = ( + fstat->fs_fflags & (PS_FST_FFLAG_WRITE | PS_FST_FFLAG_READ) ? PM_READWRITE : + fstat->fs_fflags & PS_FST_FFLAG_WRITE ? PM_WRITE : + fstat->fs_fflags & PS_FST_FFLAG_READ ? PM_READ : + 0 + ); + } - procstat_freefiles(procstat, fstat_list); -} + procstat_freefiles(procstat, fstat_list); + } -procstat_freeprocs(procstat, procs); + procstat_freeprocs(procstat, procs); done: -procstat_close(procstat); + procstat_close(procstat); #endif // __FreeBSD__ -if (stat(fd_info->name, &stat_buf) == -1) { - //~ printf("[debug] %i - %s\n",pid,fd_info->name); - if (flag_debug) - nperror("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 (stat(fd_info->name, &stat_buf) == -1) { + //~ printf("[debug] %i - %s\n",pid,fd_info->name); if (flag_debug) - nperror("open (get_fdinfo)"); + nperror("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_debug) + nperror("open (get_fdinfo)"); + return 0; + } + #ifdef __APPLE__ - uint64_t bc; - uint32_t bs; + uint64_t bc; + uint32_t bs; - bs = 0; - bc = 0; - if (ioctl(fd, DKIOCGETBLOCKSIZE, &bs) < 0 || ioctl(fd, DKIOCGETBLOCKCOUNT, &bc) < 0) { - if (flag_debug) - perror("ioctl (get_fdinfo)"); - return 0; - } - fd_info->size = bc*bs; - printf("Size: %lld\n", fd_info->size); + bs = 0; + bc = 0; + if (ioctl(fd, DKIOCGETBLOCKSIZE, &bs) < 0 || ioctl(fd, DKIOCGETBLOCKCOUNT, &bc) < 0) { + if (flag_debug) + perror("ioctl (get_fdinfo)"); + return 0; + } + fd_info->size = bc * bs; + printf("Size: %lld\n", fd_info->size); #endif #ifdef __FreeBSD__ - if (ioctl(fd, DIOCGMEDIASIZE, &fd_info->size) < 0) { - if (flag_debug) - nperror("ioctl (get_fdinfo)"); - close(fd); - return 0; - } + if (ioctl(fd, DIOCGMEDIASIZE, &fd_info->size) < 0) { + if (flag_debug) + nperror("ioctl (get_fdinfo)"); + close(fd); + return 0; + } #endif #ifdef __linux__ - if (ioctl(fd, BLKGETSIZE64, &fd_info->size) < 0) { - if (flag_debug) - nperror("ioctl (get_fdinfo)"); + if (ioctl(fd, BLKGETSIZE64, &fd_info->size) < 0) { + if (flag_debug) + nperror("ioctl (get_fdinfo)"); + close(fd); + return 0; + } +#endif close(fd); - return 0; } -#endif - close(fd); -} else { - fd_info->size = stat_buf.st_size; -} + else { + fd_info->size = stat_buf.st_size; + } #ifdef __APPLE__ -fd_info->pos = vnodeInfo.pfi.fi_offset; -gettimeofday(&fd_info->tv, &tz); -if (vnodeInfo.pfi.fi_openflags & FREAD) - fd_info->mode = PM_READ; -if (vnodeInfo.pfi.fi_openflags & FWRITE) - fd_info->mode = PM_WRITE; -if (vnodeInfo.pfi.fi_openflags & FREAD && vnodeInfo.pfi.fi_openflags & FWRITE) - fd_info->mode = PM_READWRITE; + fd_info->pos = vnodeInfo.pfi.fi_offset; + gettimeofday(&fd_info->tv, &tz); + if (vnodeInfo.pfi.fi_openflags & FREAD) + fd_info->mode = PM_READ; + if (vnodeInfo.pfi.fi_openflags & FWRITE) + fd_info->mode = PM_WRITE; + if (vnodeInfo.pfi.fi_openflags & FREAD && vnodeInfo.pfi.fi_openflags & FWRITE) + fd_info->mode = PM_READWRITE; #endif // __APPLE__ #ifdef __linux__ -flags = 0; -fd_info->pos = 0; + flags = 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); + snprintf(fdpath, MAXPATHLEN, "%s/%d/fdinfo/%d", PROC_PATH, pid, fdnum); + fp = fopen(fdpath, "rt"); + gettimeofday(&fd_info->tv, &tz); -if (!fp) { - if (flag_debug) - nperror("fopen (get_fdinfo)"); - return 0; -} + if (!fp) { + if (flag_debug) + nperror("fopen (get_fdinfo)"); + return 0; + } -while (fgets(line, LINE_LEN - 1, fp) != NULL) { - if (!strncmp(line, "pos:", 4)) - fd_info->pos = atoll(line + 5); - if (!strncmp(line, "flags:", 6)) - flags = atoll(line + 7); -} + while (fgets(line, LINE_LEN - 1, fp) != NULL) { + if (!strncmp(line, "pos:", 4)) + fd_info->pos = atoll(line + 5); + if (!strncmp(line, "flags:", 6)) + flags = atoll(line + 7); + } -if ((flags & O_ACCMODE) == O_RDONLY) - fd_info->mode = PM_READ; -if ((flags & O_ACCMODE) == O_WRONLY) - fd_info->mode = PM_WRITE; -if ((flags & O_ACCMODE) == O_RDWR) - fd_info->mode = PM_READWRITE; + if ((flags & O_ACCMODE) == O_RDONLY) + fd_info->mode = PM_READ; + if ((flags & O_ACCMODE) == O_WRONLY) + fd_info->mode = PM_WRITE; + if ((flags & O_ACCMODE) == O_RDWR) + fd_info->mode = PM_READWRITE; -fclose(fp); + fclose(fp); #endif // __linux__ -return 1; + return 1; } -void print_bar(float perc, int char_available) +void print_bar(float perc, int max_size) { -int i; -int num; + const char bar = '='; + const char blank = ' '; + const char tip = '>'; -num = (char_available / 100.0) * perc; + int i; + int tick; + int max = max_size - 2; + tick = (max / 100.0) * perc; -for (i = 0 ; i < num-1 ; i++) { - putchar('='); -} -putchar('>'); -i++; + for (i = 0; i < tick - 1; i++) { + nprintf("%c", bar); + } + nprintf("%c", tip); + i++; -for ( ; i < char_available ; i++) - putchar(' '); + for (; i < max; i++) + nprintf("%c", blank); } -void parse_options(int argc, char *argv[]) +void parse_options(int argc, char* argv[]) { -static struct option long_options[] = { - {"version", no_argument, 0, 'v'}, - {"quiet", no_argument, 0, 'q'}, - {"debug", no_argument, 0, 'd'}, - {"wait", no_argument, 0, 'w'}, - {"wait-delay", required_argument, 0, 'W'}, - {"monitor", no_argument, 0, 'm'}, - {"monitor-continuously", no_argument, 0, 'M'}, - {"help", no_argument, 0, 'h'}, - {"additional-command", required_argument, 0, 'a'}, - {"command", required_argument, 0, 'c'}, - {"pid", required_argument, 0, 'p'}, - {"ignore-file", required_argument, 0, 'i'}, - {"open-mode", required_argument, 0, 'o'}, - {0, 0, 0, 0} -}; - -static char *options_string = "vqdwmMha:c:p:W:i:o:"; -int c,i; -int option_index = 0; -char *rp; + static struct option long_options[] = { + {"timeline", no_argument, 0, 't'},//옵션 추가 + {"timeline-remove", no_argument, 0, 'T'},//옵션 추가 + {"version", no_argument, 0, 'v'}, + {"process-one-by-one", no_argument, 0, 'b'}, + {"quiet", no_argument, 0, 'q'}, + {"debug", no_argument, 0, 'd'}, + {"descending", no_argument, 0, 's'}, + {"order-by-eta", no_argument, 0, 'e'}, + {"wait", no_argument, 0, 'w'}, + {"wait-delay", required_argument, 0, 'W'}, + {"monitor", no_argument, 0, 'm'}, + {"monitor-continuously", no_argument, 0, 'M'}, + {"help", no_argument, 0, 'h'}, + {"additional-command", required_argument, 0, 'a'}, + {"command", required_argument, 0, 'c'}, + {"pid", required_argument, 0, 'p'}, + {"ignore-file", required_argument, 0, 'i'}, + {"open-mode", required_argument, 0, 'o'}, + + {0, 0, 0, 0} + }; + + static char* options_string = "TtvbrqdwsemMha:c:p:W:i:o:";//옵션 추가 + + int c, i; + int option_index = 0; + char* rp; + + optind = 1; // reset getopt + + while (1) { + c = getopt_long(argc, argv, options_string, long_options, &option_index); + + // no more options + if (c == -1) + break; -optind = 1; // reset getopt + switch (c) { + case 'T'://타임라인 삭제 + timeline = fopen("timeline.txt", "w"); + fclose(timeline); + exit(EXIT_SUCCESS); -while(1) { - c = getopt_long (argc, argv, options_string, long_options, &option_index); + case 't'://타임라인 읽기 + timeline = fopen("timeline.txt", "r"); + char buffer[1024]; - // no more options - if (c == -1) - break; + if (timeline == NULL) + printf("no file or not opened"); + for (;;) { + if (fgets(buffer, sizeof(buffer), timeline) == NULL) break; + printf("%s", buffer); + } + fclose(timeline); + exit(EXIT_SUCCESS); - switch (c) { case 'v': printf("progress version %s\n", PROGRESS_VERSION); exit(EXIT_SUCCESS); @@ -783,10 +831,10 @@ while(1) { printf("---------------------\n"); printf("Shows progress on file manipulations (cp, mv, dd, ...)\n\n"); printf("Monitored commands (default, you can add virtually anything):\n"); - for(i = 0 ; i < proc_names_cnt ; i++) + for (i = 0; i < proc_names_cnt; i++) printf("%s ", proc_names[i]); printf("\n\n"); - printf("Usage: %s [-qdwmM] [-W secs] [-c command] [-p pid]\n",argv[0]); + printf("Usage: %s [-qdwmM] [-W secs] [-c command] [-p pid]\n", argv[0]); printf(" -q --quiet hides all messages\n"); printf(" -d --debug shows all warning/error messages\n"); printf(" -w --wait estimate I/O throughput and ETA (slower display)\n"); @@ -799,12 +847,40 @@ while(1) { printf(" -i --ignore-file file do not report process if using file\n"); printf(" -o --open-mode {r|w} report only files opened for read or write\n"); printf(" -v --version show program version and exit\n"); + printf(" -t --timeline show coreutils timeline while monitoring\n"); //명령어 설명 추가 + printf(" -T --timeline-remove remove timeline\n");//명령어 설명 추가 printf(" -h --help display this help and exit\n"); + printf(" -s --descending print by descending\n"); + printf(" -e --order by eta order by eta\n"); + printf(" -r --order by perc order by perc\n"); + printf(" -b --process one by one process one by one\n"); printf("\n\n"); printf("Multiple options allowed for: -a -c -p -i. Use PROGRESS_ARGS for permanent arguments.\n"); exit(EXIT_SUCCESS); break; + case 'r': + order_by_pid = 0; + order_by_perc = 1; + case 'b': + order_by_pid = 0; + one_by_one = 1; + flag_monitor = 1; + flag_throughput = 1; + order_by_eta = 1; + break; + + + case 'e': + flag_throughput = 1; + order_by_pid = 0; + order_by_eta = 1; + break; + + case 's': + descending = 1; + break; + case 'q': flag_quiet = 1; break; @@ -816,7 +892,7 @@ while(1) { case 'i': rp = realpath(optarg, NULL); ignore_file_list_cnt++; - ignore_file_list = realloc(ignore_file_list, ignore_file_list_cnt * sizeof(char *)); + ignore_file_list = realloc(ignore_file_list, ignore_file_list_cnt * sizeof(char*)); assert(ignore_file_list != NULL); if (rp) ignore_file_list[ignore_file_list_cnt - 1] = rp; @@ -826,14 +902,14 @@ while(1) { case 'a': proc_names_cnt++; - proc_names = realloc(proc_names, proc_names_cnt * sizeof(char *)); + proc_names = realloc(proc_names, proc_names_cnt * sizeof(char*)); assert(proc_names != NULL); proc_names[proc_names_cnt - 1] = strdup(optarg); break; case 'c': proc_specifiq_name_cnt++; - proc_specifiq_name = realloc(proc_specifiq_name, proc_specifiq_name_cnt * sizeof(char *)); + proc_specifiq_name = realloc(proc_specifiq_name, proc_specifiq_name_cnt * sizeof(char*)); assert(proc_specifiq_name != NULL); proc_specifiq_name[proc_specifiq_name_cnt - 1] = strdup(optarg); break; @@ -868,7 +944,7 @@ while(1) { else if (!strcmp("w", optarg)) flag_open_mode = PM_WRITE; else { - fprintf(stderr,"Invalid --open-mode option value '%s'.\n", optarg); + fprintf(stderr, "Invalid --open-mode option value '%s'.\n", optarg); exit(EXIT_FAILURE); } break; @@ -876,343 +952,598 @@ while(1) { case '?': default: exit(EXIT_FAILURE); + } + } + + if (optind < argc) { + fprintf(stderr, "Invalid arguments.\n"); + exit(EXIT_FAILURE); } -} -if (optind < argc) { - fprintf(stderr,"Invalid arguments.\n"); - exit(EXIT_FAILURE); } +int compare_eta_by_ascending(const void* ids_a, const void* ids_b) { + int num1 = ((id*)ids_a)->eta; + int num2 = ((id*)ids_b)->eta; + if (num1 < num2) + return -1; + + if (num1 > num2) + return 1; + + return 0; } -void print_eta(time_t seconds) -{ -struct tm *p; +int compare_eta_by_descending(const void* ids_a, const void* ids_b) { + int num1 = ((id*)ids_a)->eta; + int num2 = ((id*)ids_b)->eta; + if (num1 > num2) + return -1; -if (!seconds) - return; + if (num1 < num2) + return 1; + + return 0; +} +int cnt = 0; +void print_by_remain_eta_descending(int size_ids, id* ids) { + + qsort(ids, size_ids, sizeof(id), compare_eta_by_descending); + for (int i = 0; i < size_ids; i++) { + + nprintf("[%5d] %s %s\n\t%.1f%% (%s / %s)", + (ids + i)->pid, + (ids + i)->name, + (ids + i)->loc, + (ids + i)->perc, + (ids + i)->fpos, + (ids + i)->fsize); + nprintf(" %s/s", (ids + i)->ftroughput); + print_eta((ids + i)->eta); + nprintf("\n\n"); + } +} -p = gmtime(&seconds); +void print_by_remain_eta_ascending(int size_ids, id* ids) { + + qsort(ids, size_ids, sizeof(id), compare_eta_by_ascending); + nprintf("ids size is %d", size_ids); + for (int i = 0; i < size_ids; i++) { + + nprintf("[%5d] %s %s\n\t%.1f%% (%s / %s)", + (ids + i)->pid, + (ids + i)->name, + (ids + i)->loc, + (ids + i)->perc, + (ids + i)->fpos, + (ids + i)->fsize); + nprintf(" %s/s", (ids + i)->ftroughput); + print_eta((ids + i)->eta); + nprintf("\n\n"); + } + if (one_by_one == 1) { + cnt++; + if (cnt > 3) { + process_one_by_one(size_ids, ids); + } + } -nprintf(" remaining "); -if (p->tm_yday) - nprintf("%d day%s ", p->tm_yday, p->tm_yday > 1 ? "s" : ""); -nprintf("%d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); } -void copy_and_clean_results(result_t *results, int result_count, char copy) -{ -static result_t old_results[MAX_RESULTS]; -static int old_result_count = 0; +void process_one_by_one(int size_ids, id* ids) { + int stopped = 0; + for (int i = 0; i < size_ids; i++) { + if (0 == strcmp((ids + i)->ftroughput, "0")) + stopped++; + } + nprintf("this is on by one\n"); -if (copy) { - int i; - for (i = 0; i < old_result_count; ++i) { - int j; - char found = 0; - for (j = 0; j < result_count; ++j) { - if (results[j].pid.pid == old_results[i].pid.pid) { - found = 1; - results[j].hbegin = old_results[i].hbegin; - results[j].hend = old_results[i].hend; - results[j].hsize = old_results[i].hsize; - break; - } + if (size_ids - stopped == 1) { //경우 5 + return 0; + } + else if (size_ids == 1 && stopped == 1) { //경우 4 + nprintf("case 4"); + char cmd[100]; + sprintf(cmd, "kill -18 %d", (ids)->pid); + nprintf("%s \n", cmd); + nprintf("%s", cmd); + system(cmd); + } + else if (size_ids == stopped) { //경우 경우 2 모두 다 킨다 + for (int i = 0; i < size_ids; i++) { + ; + char cmd[100]; + sprintf(cmd, "kill -18 %d", (ids + i)->pid); + + nprintf("%s", cmd); + system(cmd); + + } + cnt = 0; + } + else if (size_ids > 1 && size_ids - stopped > 1) {//경우 3 + nprintf("case 3"); + for (int i = 1; i < size_ids - stopped; i++) { + char cmd[100]; + sprintf(cmd, "kill -tstp %d", (ids + i)->pid); + + nprintf("%s", cmd); + system(cmd); } - if (!found) - free_hlist(old_results[i].hbegin); + cnt = 0; } } -else { - memcpy(old_results, results, sizeof(old_results)); - old_result_count = result_count; - } + +int compare_perc_by_ascending(const void* ids_a, const void* ids_b) { + int num1 = ((id*)ids_a)->perc; + int num2 = ((id*)ids_b)->perc; + if (num1 < num2) + return -1; + + if (num1 > num2) + return 1; + + return 0; } -int monitor_processes(int *nb_pid) -{ -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]; -float perc; -result_t results[MAX_RESULTS]; -signed char still_there; -signed char search_all = 1; -static signed char first_pass = 1; - -pid_count = 0; -if (!flag_monitor && !flag_monitor_continuous) - first_pass = 0; +int compare_perc_by_descending(const void* ids_a, const void* ids_b) { + int num1 = ((id*)ids_a)->perc; + int num2 = ((id*)ids_b)->perc; + if (num1 > num2) + return -1; + if (num1 < num2) + return 1; -if (proc_specifiq_name_cnt) { - search_all = 0; - for (i = 0 ; i < proc_specifiq_name_cnt ; ++i) { - pid_count += find_pids_by_binary_name(proc_specifiq_name[i], - pidinfo_list + pid_count, - MAX_PIDS - pid_count); - if(pid_count >= MAX_PIDS) { - nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); - return 0; + return 0; +} + +void print_by_remain_perc_descending(int size_ids, id* ids) { + + qsort(ids, size_ids, sizeof(id), compare_perc_by_descending); + for (int i = 0; i < size_ids; i++) { + + nprintf("[%5d] %s %s\n\t%.1f%% (%s / %s)", + (ids + i)->pid, + (ids + i)->name, + (ids + i)->loc, + (ids + i)->perc, + (ids + i)->fpos, + (ids + i)->fsize); + if (flag_throughput == 1) { + nprintf(" %s/s", (ids + i)->ftroughput); + print_eta((ids + i)->eta); } + nprintf("\n\n"); } } -if (proc_specifiq_pid) { - search_all = 0; - for (i = 0 ; i < proc_specifiq_pid_cnt ; ++i) { - pid_count += find_pid_by_id(proc_specifiq_pid[i], - pidinfo_list + pid_count); - - if(pid_count >= MAX_PIDS) { - nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); - return 0; +void print_by_remain_perc_ascending(int size_ids, id* ids) { + + qsort(ids, size_ids, sizeof(id), compare_perc_by_ascending); + for (int i = 0; i < size_ids; i++) { + + nprintf("[%5d] %s %s\n\t%.1f%% (%s / %s)", + (ids + i)->pid, + (ids + i)->name, + (ids + i)->loc, + (ids + i)->perc, + (ids + i)->fpos, + (ids + i)->fsize); + if (flag_throughput == 1) { + nprintf(" %s/s", (ids + i)->ftroughput); + print_eta((ids + i)->eta); } + nprintf("\n\n"); } + + } -if (search_all) { - for (i = 0 ; i < proc_names_cnt ; i++) { - pid_count += find_pids_by_binary_name(proc_names[i], - pidinfo_list + pid_count, - MAX_PIDS - pid_count); - if(pid_count >= MAX_PIDS) { - nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); - return 0; + +void print_eta(time_t seconds) +{ + struct tm* p; + time_t ct; + struct tm tm; + ct=time(NULL)+seconds; + tm = *gmtime(&ct); + + if (!seconds) + return; + + p = gmtime(&seconds); + + nprintf(" remaining "); + if (p->tm_yday) + nprintf("%d day%s ", p->tm_yday, p->tm_yday > 1 ? "s" : ""); + nprintf("%d:%02d:%02d", p->tm_hour, p->tm_min, p->tm_sec); + nprintf(" End at "); + nprintf("%d.%d.%d %d:%d:%d\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +} + +void copy_and_clean_results(result_t* results, int result_count, char copy) +{ + static result_t old_results[MAX_RESULTS]; + static int old_result_count = 0; + + if (copy) { + int i; + for (i = 0; i < old_result_count; ++i) { + int j; + char found = 0; + for (j = 0; j < result_count; ++j) { + if (results[j].pid.pid == old_results[i].pid.pid) { + found = 1; + results[j].hbegin = old_results[i].hbegin; + results[j].hend = old_results[i].hend; + results[j].hsize = old_results[i].hsize; + break; + } + } + if (!found) + free_hlist(old_results[i].hbegin); } } + else { + memcpy(old_results, results, sizeof(old_results)); + old_result_count = result_count; + } } -*nb_pid = pid_count; - -if (!pid_count) { - if (flag_quiet) - return 0; - if (flag_monitor || flag_monitor_continuous) { - clear(); - refresh(); +int monitor_processes(int* nb_pid) +{ + 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]; + float perc; + result_t results[MAX_RESULTS]; + signed char still_there; + signed char search_all = 1; + static signed char first_pass = 1; + timeline = fopen("timeline.txt", "a+");//파일 불러오기 + int flag;//중복 확인용 변수 + char buffer[128];//파일 읽기 용 + char command[128];//명령어용 + + pid_count = 0; + if (!flag_monitor && !flag_monitor_continuous) + first_pass = 0; + + + if (proc_specifiq_name_cnt) { + search_all = 0; + for (i = 0; i < proc_specifiq_name_cnt; ++i) { + pid_count += find_pids_by_binary_name(proc_specifiq_name[i], + pidinfo_list + pid_count, + MAX_PIDS - pid_count); + if (pid_count >= MAX_PIDS) { + nfprintf(stderr, "Found too much procs (max = %d)\n", MAX_PIDS); + return 0; + } + } } - if (proc_specifiq_pid_cnt) { - nfprintf(stderr, "No such pid: "); - for (i = 0 ; i < proc_specifiq_pid_cnt; ++i) { - nfprintf(stderr, "%d, ", proc_specifiq_pid[i]); + + if (proc_specifiq_pid) { + search_all = 0; + for (i = 0; i < proc_specifiq_pid_cnt; ++i) { + pid_count += find_pid_by_id(proc_specifiq_pid[i], + pidinfo_list + pid_count); + + if (pid_count >= MAX_PIDS) { + nfprintf(stderr, "Found too much procs (max = %d)\n", MAX_PIDS); + return 0; + } } } - if (proc_specifiq_name_cnt) - { - nfprintf(stderr, "No such command(s) running: "); - for (i = 0 ; i < proc_specifiq_name_cnt; ++i) { - nfprintf(stderr, "%s, ", proc_specifiq_name[i]); + + if (search_all) { + for (i = 0; i < proc_names_cnt; i++) { + pid_count += find_pids_by_binary_name(proc_names[i], + pidinfo_list + pid_count, + MAX_PIDS - pid_count); + if (pid_count >= MAX_PIDS) { + nfprintf(stderr, "Found too much procs (max = %d)\n", MAX_PIDS); + return 0; + } } } - if (!proc_specifiq_pid && !proc_specifiq_name_cnt) { - nfprintf(stderr,"No command currently running: "); - for (i = 0 ; i < proc_names_cnt ; i++) { - nfprintf(stderr,"%s, ", proc_names[i]); + + *nb_pid = pid_count; + + if (!pid_count) { + if (flag_quiet) + return 0; + if (flag_monitor || flag_monitor_continuous) { + clear(); + refresh(); } + if (proc_specifiq_pid_cnt) { + nfprintf(stderr, "No such pid: "); + for (i = 0; i < proc_specifiq_pid_cnt; ++i) { + nfprintf(stderr, "%d, ", proc_specifiq_pid[i]); + } + } + if (proc_specifiq_name_cnt) + { + nfprintf(stderr, "No such command(s) running: "); + for (i = 0; i < proc_specifiq_name_cnt; ++i) { + nfprintf(stderr, "%s, ", proc_specifiq_name[i]); + } + } + if (!proc_specifiq_pid && !proc_specifiq_name_cnt) { + nfprintf(stderr, "No command currently running: "); + for (i = 0; i < proc_names_cnt; i++) { + nfprintf(stderr, "%s, ", proc_names[i]); + } + } + nfprintf(stderr, "or wrong permissions.\n"); + first_pass = 0; + return 0; } - nfprintf(stderr,"or wrong permissions.\n"); - first_pass = 0; - return 0; -} -result_count = 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); + for (i = 0; i < pid_count; i++) { + fd_count = find_fd_for_pid(pidinfo_list[i].pid, fdnum_list, MAX_FD_PER_PID); - if (flag_open_mode == PM_READ && fdinfo.mode != PM_READ && fdinfo.mode != PM_READWRITE) - continue; - if (flag_open_mode == PM_WRITE && fdinfo.mode != PM_WRITE && fdinfo.mode != PM_READWRITE) - continue; + max_size = 0; - if (fdinfo.size > max_size) { - biggest_fd = fdinfo; - max_size = fdinfo.size; + // 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 (flag_open_mode == PM_READ && fdinfo.mode != PM_READ && fdinfo.mode != PM_READWRITE) + continue; + if (flag_open_mode == PM_WRITE && fdinfo.mode != PM_WRITE && fdinfo.mode != PM_READWRITE) + continue; + + if (fdinfo.size > max_size) { + biggest_fd = fdinfo; + max_size = fdinfo.size; + } + } + + if (!max_size) { // nothing found + // this display is the root of too many confusion for the users, let's + // remove it. And it does not play well with --i option. + /* nprintf("[%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; + results[result_count].hbegin = NULL; + results[result_count].hend = NULL; + results[result_count].hsize = 0; + + result_count++; } - if (!max_size) { // nothing found - // this display is the root of too many confusion for the users, let's - // remove it. And it does not play well with --i option. -/* nprintf("[%5d] %s inactive/flushing/streaming/...\n", - pidinfo_list[i].pid, - pidinfo_list[i].name);*/ - continue; + // wait a bit, so we can estimate the throughput + if (flag_throughput && !first_pass) + usleep(1000000 * throughput_wait_secs); + if (flag_monitor || flag_monitor_continuous) { + clear(); } + id ids[result_count]; + copy_and_clean_results(results, result_count, 1); + for (i = 0; i < result_count; i++) { + + if (flag_throughput && !first_pass) { + 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; - // We've our biggest_fd now, let's store the result - results[result_count].pid = pidinfo_list[i]; - results[result_count].fd = biggest_fd; - results[result_count].hbegin = NULL; - results[result_count].hend = NULL; - results[result_count].hsize = 0; + } + if (order_by_pid == 1) { + nprintf("[%5d] %s %s\n\t%.1f%% (%s / %s)", + results[i].pid.pid, + results[i].pid.name, + results[i].fd.name, + perc, + fpos, + fsize); + } + else { + ids[i].pid = results[i].pid.pid; + strcpy(ids[i].name, results[i].pid.name); + strcpy(ids[i].loc, results[i].fd.name); + ids[i].perc = perc; + strcpy(ids[i].fpos, fpos); + strcpy(ids[i].fsize, fsize); + } - result_count++; -} + sprintf(command, "[%5d] %s %s\n", //명령어 command 에 복사 + results[i].pid.pid, + results[i].pid.name, + results[i].fd.name); -// wait a bit, so we can estimate the throughput -if (flag_throughput && !first_pass) - usleep(1000000 * throughput_wait_secs); -if (flag_monitor || flag_monitor_continuous) { - clear(); -} -copy_and_clean_results(results, result_count, 1); -for (i = 0 ; i < result_count ; i++) { - - if (flag_throughput && !first_pass) { - 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; + flag = 1; //flag 초기화 - } + for (;;) { + if (fgets(buffer, sizeof(buffer), timeline) == NULL)//중복 체크 + break; + flag = strcmp(buffer, command); + if (flag == 0) + break; + } - nprintf("[%5d] %s %s\n\t%.1f%% (%s / %s)", - results[i].pid.pid, - results[i].pid.name, - results[i].fd.name, - perc, - fpos, - fsize); - - if (flag_throughput && still_there && !first_pass) { - // 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; - results[i].hsize += add_to_hlist(&results[i].hbegin, &results[i].hend, results[i].hsize, byte_diff / (usec_diff / 1000000.0)); - bytes_per_sec = get_hlist_average(results[i].hbegin, results[i].hsize); - - format_size(bytes_per_sec, ftroughput); - nprintf(" %s/s", ftroughput); - if (bytes_per_sec && fdinfo.size - fdinfo.pos >= 0) { - print_eta((fdinfo.size - fdinfo.pos) / bytes_per_sec); + if (flag != 0) + fprintf(timeline, command);//명령어 타임라인 삽입 + + + if (flag_throughput && still_there && !first_pass) { + // 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; + results[i].hsize += add_to_hlist(&results[i].hbegin, &results[i].hend, results[i].hsize, byte_diff / (usec_diff / 1000000.0)); + bytes_per_sec = get_hlist_average(results[i].hbegin, results[i].hsize); + + format_size(bytes_per_sec, ftroughput); + + if (order_by_pid == 1) + { + nprintf(" %s/s", ftroughput); + } + else + { + strcpy(ids[i].ftroughput, ftroughput); + } + if (bytes_per_sec && fdinfo.size - fdinfo.pos >= 0) { + if (order_by_pid == 1) { + print_eta((fdinfo.size - fdinfo.pos) / bytes_per_sec); + } + else { + ids[i].eta = (fdinfo.size - fdinfo.pos) / bytes_per_sec; + } + } + } + + if (order_by_pid == 1) + { + nprintf("\n\n"); } + + nprintf(" ["); + print_bar(perc, ws.ws_col - 4); + nprintf("]\n"); + } + if ((order_by_pid == 0 && descending == 0 && order_by_eta == 1) || (order_by_pid == 0 && descending == 0 && one_by_one == 1)) + { + print_by_remain_eta_ascending(result_count, &ids); + } + else if (order_by_pid == 0 && descending == 1 && order_by_eta == 1) { + print_by_remain_eta_descending(result_count, &ids); } + if ((order_by_pid == 0 && descending == 0 && order_by_perc == 1)) + { + print_by_remain_perc_ascending(result_count, &ids); + } + else if (order_by_pid == 0 && descending == 1 && order_by_perc == 1) { + print_by_remain_perc_descending(result_count, &ids); + } - nprintf("\n\n"); - // Need to work on window width when using screen/watch/... - //~ printf(" ["); - //~ print_bar(perc, ws.ws_col-6); - //~ printf("]\n"); -} -if (flag_monitor || flag_monitor_continuous) { - if (!result_count) - nprintf("No PID(s) currently monitored\n"); - refresh(); -} -copy_and_clean_results(results, result_count, 0); -first_pass = 0; -return 0; + if (flag_monitor || flag_monitor_continuous) { + if (!result_count) + nprintf("No PID(s) currently monitored\n"); + refresh(); + } + copy_and_clean_results(results, result_count, 0); + first_pass = 0; + return 0; } void int_handler(int sig) { -if(flag_monitor || flag_monitor_continuous) - endwin(); -exit(0); + if (flag_monitor || flag_monitor_continuous) + endwin(); + exit(0); } // Setup the default commands as a dynamic list void populate_proc_names() { int i; - for(i = 0 ; default_proc_names[i] ; i++) { + for (i = 0; default_proc_names[i]; i++) { proc_names_cnt++; - proc_names = realloc(proc_names, proc_names_cnt * sizeof(char *)); + proc_names = realloc(proc_names, proc_names_cnt * sizeof(char*)); assert(proc_names != NULL); proc_names[proc_names_cnt - 1] = default_proc_names[i]; } } -int main(int argc, char *argv[]) + +int main(int argc, char* argv[]) { -pid_t nb_pid; -struct winsize ws; -wordexp_t env_wordexp; -char *env_progress_args; -char *env_progress_args_full; + pid_t nb_pid; + wordexp_t env_wordexp; + char* env_progress_args; + char* env_progress_args_full; -populate_proc_names(); + populate_proc_names(); -env_progress_args = getenv("PROGRESS_ARGS"); + env_progress_args = getenv("PROGRESS_ARGS"); -if (env_progress_args) { - int full_len; + if (env_progress_args) { + int full_len; - // prefix with (real) argv[0] - // argv[0] + ' ' + env_progress_args + '\0' - full_len = strlen(argv[0]) + 1 + strlen(env_progress_args) + 1; - env_progress_args_full = malloc(full_len * sizeof(char)); - assert(env_progress_args_full != NULL); - sprintf(env_progress_args_full, "%s %s", argv[0], env_progress_args); + // prefix with (real) argv[0] + // argv[0] + ' ' + env_progress_args + '\0' + full_len = strlen(argv[0]) + 1 + strlen(env_progress_args) + 1; + env_progress_args_full = malloc(full_len * sizeof(char)); + assert(env_progress_args_full != NULL); + sprintf(env_progress_args_full, "%s %s", argv[0], env_progress_args); - if (wordexp(env_progress_args_full, &env_wordexp, 0)) { - fprintf(stderr,"Unable to parse PROGRESS_ARGS environment variable.\n"); - exit(EXIT_FAILURE); - } - parse_options(env_wordexp.we_wordc,env_wordexp.we_wordv); -} -parse_options(argc,argv); - -// ws.ws_row, ws.ws_col -ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); -if (flag_monitor || flag_monitor_continuous) { - setlocale(LC_CTYPE, ""); - if ((mainwin = initscr()) == NULL ) { - fprintf(stderr, "Error initialising ncurses.\n"); - exit(EXIT_FAILURE); + if (wordexp(env_progress_args_full, &env_wordexp, 0)) { + fprintf(stderr, "Unable to parse PROGRESS_ARGS environment variable.\n"); + exit(EXIT_FAILURE); + } + parse_options(env_wordexp.we_wordc, env_wordexp.we_wordv); } - if (!flag_throughput) { - flag_throughput = 1; - throughput_wait_secs = 1; + parse_options(argc, argv); + + // ws.ws_row, ws.ws_col + ioctl(0, TIOCGWINSZ, &ws); + if (flag_monitor || flag_monitor_continuous) { + setlocale(LC_CTYPE, ""); + if ((mainwin = initscr()) == NULL) { + fprintf(stderr, "Error initialising ncurses.\n"); + exit(EXIT_FAILURE); + } + if (!flag_throughput) { + flag_throughput = 1; + throughput_wait_secs = 1; + } + set_hlist_size(throughput_wait_secs); + signal(SIGINT, int_handler); + do { + monitor_processes(&nb_pid); + refresh(); + if (flag_monitor_continuous && !nb_pid) { + usleep(1000000 * throughput_wait_secs); + } + } while ((flag_monitor && nb_pid) || flag_monitor_continuous); + endwin(); } - set_hlist_size(throughput_wait_secs); - signal(SIGINT, int_handler); - do { + else { + set_hlist_size(throughput_wait_secs); monitor_processes(&nb_pid); - refresh(); - if(flag_monitor_continuous && !nb_pid) { - usleep(1000000 * throughput_wait_secs); - } - } while ((flag_monitor && nb_pid) || flag_monitor_continuous); - endwin(); -} -else { - set_hlist_size(throughput_wait_secs); - monitor_processes(&nb_pid); -} -return 0; + } + return 0; } diff --git a/progress.h b/progress.h index ee7b800..d912734 100644 --- a/progress.h +++ b/progress.h @@ -59,5 +59,6 @@ typedef struct result_t { hlist *hend; int hsize; } result_t; +FILE *timeline; #endif diff --git a/timeline.txt b/timeline.txt new file mode 100644 index 0000000..c9b4e57 --- /dev/null +++ b/timeline.txt @@ -0,0 +1,8 @@ +[3128355] gzip /home/ec2-user/directory1/dumy300-2 +[3128355] gzip /home/ec2-user/directory1/dumy500-2 +[3129815] cp /home/ec2-user/directory1/dumy300 +[3128355] gzip /home/ec2-user/directory1/dumy500-2 +[3129846] cp /home/ec2-user/directory1/dumy300 +[3128355] gzip /home/ec2-user/directory1/dumy500-2 +[3129920] cp /home/ec2-user/directory1/dumy300 +[3128355] gzip /home/ec2-user/directory1/dumy500-2