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) { nperror("opendir"); nfprintf(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_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; }
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) { 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))) { 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" //~ 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; }
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; pid_count = 0; if (proc_specifiq_name_cnt) { 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); search_all = 0; } if (proc_specifiq_pid) { pid_count += find_pid_by_id(proc_specifiq_pid, pidinfo_list + pid_count); search_all = 0; } if (search_all) { 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) { nfprintf(stderr, "Found too much procs (max = %d)\n",MAX_PIDS); break; } } } *nb_pid = pid_count; if (!pid_count) { if (flag_quiet) return 0; if (flag_monitor || flag_monitor_continous) { clear(); refresh(); } nfprintf(stderr,"No command currently running: "); for (i = 0 ; proc_names[i] ; i++) { nfprintf(stderr,"%s, ", proc_names[i]); } nfprintf(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 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) usleep(1000000 * throughput_wait_secs); if (flag_monitor || flag_monitor_continous) { clear(); refresh(); } copy_and_clean_results(results, result_count, 1); 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; } nprintf("[%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; 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"); // Need to work on window width when using screen/watch/... //~ printf(" ["); //~ print_bar(perc, ws.ws_col-6); //~ printf("]\n"); } copy_and_clean_results(results, result_count, 0); return 0; }