/* vi: set sw=4 ts=4: */ /* * Utility routines. * * Copyright 1998 by Albert Cahalan; all rights reserved. * Copyright (C) 2002 by Vladimir Oleynik * SELinux support: (c) 2007 by Yuichi Nakamura * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ #include #include #include #include #include #include #include #include #include #include #define PROCPS_BUFSIZE (4*1024) typedef struct { DIR *dir; unsigned pid; /* Fields are set to 0/NULL if failed to determine (or not requested) */ unsigned long long stat_vsz; /* we round it to kbytes */ unsigned long long stat_rss; /* we round it to kbytes */ unsigned long long status_vmsize; unsigned long long status_vmlck ; unsigned long long status_vmhwm ; unsigned long long status_vmrss ; unsigned long long status_vmdata; unsigned long long status_vmstk ; unsigned long long status_vmexe ; unsigned long long status_vmlib ; unsigned long long status_vmpte ; unsigned long long smaps_shared_clean ; unsigned long long smaps_shared_dirty ; unsigned long long smaps_private_clean; unsigned long long smaps_private_dirty; unsigned long long smaps_referenced ; char argv0[32]; } procps_status_t; static int read_to_buf(const char *filename, void *buf) { int fd; ssize_t ret = -1; fd = open(filename, O_RDONLY); if (fd >= 0) { ret = read(fd, buf, PROCPS_BUFSIZE-1); close(fd); } ((char *)buf)[ret > 0 ? ret : 0] = '\0'; return ret; } procps_status_t *alloc_procps_scan(void) { procps_status_t* sp = malloc(sizeof(*sp)); memset(sp, 0, sizeof(*sp)); sp->dir = opendir("/proc"); return sp; } void free_procps_scan(procps_status_t* sp) { closedir(sp->dir); free(sp); } procps_status_t *procps_scan(procps_status_t* sp) { struct dirent *entry; char buf[PROCPS_BUFSIZE]; char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; char *filename_tail; long tasknice; unsigned pid; int n; struct stat sb; if (!sp) sp = alloc_procps_scan(); for (;;) { FILE *file; char *cp; unsigned long long vsz, rss; unsigned long long tmp_ull; entry = readdir(sp->dir); if (entry == NULL) { free_procps_scan(sp); return NULL; } pid = strtoul(entry->d_name, &cp, 10); if (cp[0]) continue; /* After this point we have to break, not continue * ("continue" would mean that current /proc/NNN * is not a valid process info) */ memset(&sp->pid, 0, sizeof(*sp) - offsetof(procps_status_t, pid)); sp->pid = pid; filename_tail = filename + sprintf(filename, "/proc/%d", pid); strcpy(filename_tail, "/stat"); n = read_to_buf(filename, buf); if (n < 0) break; cp = strrchr(buf, ')'); /* split into "PID (cmd" and "" */ *cp = '\0'; strncpy(sp->argv0, strchr(buf, '(') + 1, sizeof(sp->argv0) - 1); sp->argv0[sizeof(sp->argv0) - 1] = '\0'; sscanf(cp+2, "%*s %*s " /* state, ppid */ "%*s %*s %*s %*s " /* pgid, sid, tty, tpgid */ "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ "%*s %*s " /* utime, stime */ "%*s %*s %*s " /* cutime, cstime, priority */ "%*s " /* nice */ "%*s %*s %*s " /* timeout, it_real_value, start_time */ "%llu " /* vsize */ "%llu " /* rss */ /* "%lu %lu %lu %lu %lu %lu " rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ /* "%u %u %u %u " signal, blocked, sigignore, sigcatch */ /* "%lu %lu %lu" wchan, nswap, cnswap */ , &vsz, &rss); sp->stat_vsz = vsz >> 10; /* vsize is in bytes and we want kb */ sp->stat_rss = rss * (getpagesize() >> 10); /* or sysconf(_SC_PAGESIZE) */ strcpy(filename_tail, "/status"); n = read_to_buf(filename, buf); if (n < 0) break; #define SCAN(str, name) \ do { \ cp = strstr(buf, str); \ if (cp) sscanf(cp, str ": %llu ", &sp->status_##name); \ } while (0) SCAN("VmSize", vmsize); SCAN("VmLck" , vmlck ); SCAN("VmHWM" , vmhwm ); SCAN("VmRSS" , vmrss ); SCAN("VmData", vmdata); SCAN("VmStk" , vmstk ); SCAN("VmExe" , vmexe ); SCAN("VmLib" , vmlib ); SCAN("VmPTE" , vmpte ); #undef SCAN strcpy(filename_tail, "/smaps"); file = fopen(filename, "r"); if (!file) break; while (fgets(buf, sizeof(buf), file)) { #define SCAN(str, name) \ if (strncmp(buf, str, sizeof(str)-1) == 0) { \ sscanf(buf, str ": %llu ", &tmp_ull); \ sp->smaps_##name += tmp_ull; \ continue; \ } SCAN("Shared_Clean" , shared_clean ); SCAN("Shared_Dirty" , shared_dirty ); SCAN("Private_Clean", private_clean); SCAN("Private_Dirty", private_dirty); SCAN("Referenced" , referenced ); #undef SCAN } fclose(file); strcpy(filename_tail, "/cmdline"); n = read_to_buf(filename, buf); if (n <= 0) break; cp = strrchr(buf, '/'); if (!cp) cp = buf - 1; strncpy(sp->argv0, cp + 1, sizeof(sp->argv0) - 1); sp->argv0[sizeof(sp->argv0) - 1] = '\0'; break; } return sp; } int main() { int stat_vsz_eq_status_vmsize = 1; int stat_rss_eq_status_vmrss = 1; int stat_rss_eq_smaps_total = 1; int status_vmhwm_eq_status_vmrss = 1; procps_status_t *sp = NULL; printf( " stat status smaps\n"); printf( "PID.. vsz... rss... vmsize vmlck. vmhwm. vmdata vmstk. vmexe. vmlib. vmpte. total. (shr). dirty. (shr).\n"); while ((sp = procps_scan(sp)) != NULL) { if (getpid() == sp->pid) continue; unsigned long long smaps_total = sp->smaps_shared_clean + sp->smaps_shared_dirty + sp->smaps_private_clean + sp->smaps_private_dirty; printf("%5u %6llu %6llu %6llu %6llu %6llu %6llu %6llu %6llu %6llu %6llu %6llu %6llu %6llu %6llu", sp->pid , sp->stat_vsz , sp->stat_rss , sp->status_vmsize , sp->status_vmlck , sp->status_vmhwm , //sp->status_vmrss , sp->status_vmdata , sp->status_vmstk , sp->status_vmexe , sp->status_vmlib , sp->status_vmpte , smaps_total, //sp->smaps_shared_clean + sp->smaps_shared_dirty + sp->smaps_private_clean + sp->smaps_private_dirty, sp->smaps_shared_clean + sp->smaps_shared_dirty, sp->smaps_shared_dirty + sp->smaps_private_dirty, sp->smaps_shared_dirty //sp->smaps_referenced ); if (sp->stat_vsz != sp->status_vmsize) stat_vsz_eq_status_vmsize = 0, printf(" !1"); if (sp->stat_rss != sp->status_vmrss) stat_rss_eq_status_vmrss = 0, printf(" !2"); if (sp->status_vmhwm != sp->status_vmrss) status_vmhwm_eq_status_vmrss = 0, printf(" !3"); if (sp->stat_rss != smaps_total) stat_rss_eq_smaps_total = 0, printf(" !4"); printf(" %s\n", sp->argv0); } printf("stat_vsz == status_vmsize: %d\n", stat_vsz_eq_status_vmsize ); printf("stat_rss == status_vmrss: %d\n", stat_rss_eq_status_vmrss ); printf("status_vmhwm == status_vmrss: %d\n", status_vmhwm_eq_status_vmrss); printf("stat_rss == smaps_total: %d\n", stat_rss_eq_smaps_total ); return 0; }