/*********************************************************************** * * psinfo.c * * psinfo: process info * * Copyright (C) 2008-2010 Ward van Wanrooij * * This software may be distributed according to the terms of the GNU * General Public License, version 2 or (at your option) any later * version. * ***********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "defines.h" #include "psinfo.h" #define CHECK_ERROR(x) { if (x) fprintf(stderr, "psinfo:%s:%d: error at %s\n", __FILE__, __LINE__, #x); } int parse_proc_io(FILE * f, struct process_info *p) { char key[1024], value[1024]; while (fscanf(f, "%1023[^:]:%1023[^\n]\n", key, value) == 2) { if (!strcasecmp(key, "rchar")) { p->has_io = 1; p->rchar = atoll(value); } else if (!strcasecmp(key, "wchar")) { p->wchar = atoll(value); } else if (!strcasecmp(key, "syscr")) { p->syscr = atoll(value); } else if (!strcasecmp(key, "syscw")) { p->syscw = atoll(value); } else if (!strcasecmp(key, "read_bytes")) { p->read_bytes = atoll(value); } else if (!strcasecmp(key, "write_bytes")) { p->write_bytes = atoll(value); } else if (!strcasecmp(key, "cancelled_write_bytes")) { p->cancelled_write_bytes = atoll(value); } } return 0; } int parse_proc_oomscore(FILE * f, struct process_info *p) { p->has_oom_score = (fscanf(f, "%d", &p->oom_score) == 1); return !p->has_oom_score; } int parse_proc_oomadj(FILE * f, struct process_info *p) { p->has_oom_adj = (fscanf(f, "%d", &p->oom_adj) == 1); return !p->has_oom_adj; } int parse_proc_schedstat(FILE * f, struct process_info *p) { p->has_schedstat = (fscanf(f, "%llu %llu %llu", &p->run_ticks, &p->wait_ticks, &p->nran) == 3); return !p->has_schedstat; } int parse_proc_stat(FILE * f, struct process_info *p) { int m; if ((m = fscanf(f, "%d (%1023[^)]) %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %*d %llu %lu %ld %lu %lu %lu %lu %lu %lu %*u %*u %*u %*u %lu %*u %*u %d %d %u %u %llu %lu %ld", &p->pid, p->tcomm, &p->state, &p->ppid, &p->pgrp, &p->sid, &p->tty_nr, &p->tty_pgrp, &p->flags, &p->min_flt, &p->cmin_flt, &p->maj_flt, &p->cmaj_flt, &p->utime, &p->stime, &p->cutime, &p->cstime, &p->priority, &p->nice, &p->num_threads, &p->start_time, &p->vsize, &p->rss, &p->rlim, &p->start_code, &p->end_code, &p->start_stack, &p->esp, &p->eip, &p->wchan, &p->exit_signal, &p->task_cpu, &p->rt_priority, &p->policy, &p->blkio_ticks, &p->gtime, &p->cgtime)) >= 32) { p->has_blkio_ticks = (m >= 33); p->has_gtime = (m >= 35); p->utime -= p->gtime; p->cutime -= p->cgtime; return 0; } else { return 1; } } int parse_proc_statm(FILE * f, struct process_info *p) { return (fscanf(f, "%d %d %d", &p->vmsizep, &p->vmresidentp, &p->vmsharedp) != 3); } int parse_proc_capbnd(FILE * f, struct process_info *p) { p->has_capbnd = (fscanf(f, "%ld", &p->capbnd) == 1); return !p->has_capbnd; } int parse_proc_status(FILE * f, struct process_info *p) { char key[1024], value[1024]; while (fscanf(f, "%1023[^:]:%1023[^\n]\n", key, value) == 2) { if (!strcasecmp(key, "sleepavg")) { p->sleepavg = atoi(value); } else if (!strcasecmp(key, "tracerpid")) { p->tracerpid = atoi(value); } else if (!strcasecmp(key, "uid")) { CHECK_ERROR(sscanf(value, "%d %d %d %d", &p->uid, &p->euid, &p->suid, &p->fsuid) != 4); } else if (!strcasecmp(key, "gid")) { CHECK_ERROR(sscanf(value, "%d %d %d %d", &p->gid, &p->egid, &p->sgid, &p->fsgid) != 4); } else if (!strcasecmp(key, "fdsize")) { p->fdsize = atoi(value); } else if (!strcasecmp(key, "vmpeak")) { p->has_vmpeak = 1; p->vmpeak = atol(value); } else if (!strcasecmp(key, "vmsize")) { p->vmsize = atol(value); } else if (!strcasecmp(key, "vmlck")) { p->vmlck = atol(value); } else if (!strcasecmp(key, "vmhwm")) { p->has_vmhwm = 1; p->vmhwm = atol(value); } else if (!strcasecmp(key, "vmrss")) { p->vmrss = atol(value); } else if (!strcasecmp(key, "vmdata")) { p->vmdata = atol(value); } else if (!strcasecmp(key, "vmstk")) { p->vmstk = atol(value); } else if (!strcasecmp(key, "vmexe")) { p->vmexe = atol(value); } else if (!strcasecmp(key, "vmlib")) { p->vmlib = atol(value); } else if (!strcasecmp(key, "vmpte")) { p->has_vmpte = 1; p->vmpte = atol(value); } else if (!strcasecmp(key, "sigq")) { p->has_sigq = 1; CHECK_ERROR(sscanf(value, "%lu/%lu", &p->sigqsize, &p->sigqlim) != 2); } else if (!strcasecmp(key, "sigpnd")) { CHECK_ERROR(sscanf(value, "%lx", &p->sigpending) != 1); } else if (!strcasecmp(key, "shapnd")) { CHECK_ERROR(sscanf(value, "%lx", &p->sigshpending) != 1); } else if (!strcasecmp(key, "sigblk")) { CHECK_ERROR(sscanf(value, "%lx", &p->sigblocked) != 1); } else if (!strcasecmp(key, "sigign")) { CHECK_ERROR(sscanf(value, "%lx", &p->sigignored) != 1); } else if (!strcasecmp(key, "sigcgt")) { CHECK_ERROR(sscanf(value, "%lx", &p->sigcaught) != 1); } else if (!strcasecmp(key, "capinh")) { CHECK_ERROR(sscanf(value, "%lx", &p->capinh) != 1); } else if (!strcasecmp(key, "capprm")) { CHECK_ERROR(sscanf(value, "%lx", &p->capprm) != 1); } else if (!strcasecmp(key, "capeff")) { CHECK_ERROR(sscanf(value, "%lx", &p->capeff) != 1); } else if (!strcasecmp(key, "capbnd")) { p->has_capbnd = 1; CHECK_ERROR(sscanf(value, "%lx", &p->capbnd) != 1); } } return 0; } int parse_proc_wchan(FILE * f, struct process_info *p) { return (fscanf(f, "%1023s", p->wchan_decoded) != 1); } int parse_proc_arrayfile(char *name, char ***s) { FILE *f; int res = 1; if ((f = fopen(name, "r")) != NULL) { char *buf; int len = 0, bufsize = 1024, count = 0; buf = malloc(bufsize); while ((buf[len++] = fgetc(f)) != EOF) { if (buf[len - 1] == 0) { *s = realloc(*s, (count + 2) * sizeof(char *)); (*s)[count] = malloc(len); strncpy((*s)[count], buf, len); count++; len = 0; } if (len == bufsize) { bufsize <<= 2; buf = realloc(buf, bufsize); } } if (*s != NULL) (*s)[count] = NULL; res = 0; fclose(f); } return res; } int parse_proc_file(char *name, struct process_info *p, int (*process) (FILE * f, struct process_info * p)) { FILE *f; if ((f = fopen(name, "r")) != NULL) { int res; res = process(f, p); fclose(f); return res; } else { return 1; } } int parse_proc_symlink(char *name, char **s) { int count, res = 1; char buf[1024]; if ((count = readlink(name, buf, sizeof(buf) - 1)) != -1) { *s = realloc(*s, count + 1); memcpy(*s, buf, count); (*s)[count] = 0; res = 0; } return res; } int parse_proc_task(char *name, int **s) { struct dirent **files; int cnt; if ((cnt = scandir(name, &files, NULL, NULL)) > 0) { int sz; sz = 0; *s = realloc(*s, sizeof(int) * cnt); memset(*s, 0, sizeof(int) * cnt); while (cnt--) { if (files[cnt]->d_name[0] != '.') { int tpid; tpid = atoi(files[cnt]->d_name); if (tpid != 0) (*s)[sz++] = tpid; } free(files[cnt]); } free(files); } return 0; } int tty_dev_to_name(unsigned int major, unsigned int minor, char *buf, int bufsize) { FILE *f; if ((f = fopen("/proc/tty/drivers", "r")) != NULL) { int res; res = 1; while (!feof(f)) { unsigned int matches, lmajor, lminorstart, lminorend; char lname[32]; lminorend = 0; if ((matches = fscanf(f, "%*s %31s %u %u-%u", lname, &lmajor, &lminorstart, &lminorend)) >= 3) if ((lmajor == major) && (((matches == 3) && (lminorstart == minor)) || ((matches == 4) && (lminorstart <= minor) && (lminorend >= minor)))) { snprintf(buf, bufsize, "%s%u", lname, minor - lminorstart); res = 0; break; } fscanf(f, "%*[^\n]\n"); } fclose(f); return res; } else { return 1; } } void print_general(struct process_info *p) { int i; time_t start_time; struct sysinfo info; char tty_name[32]; start_time = time(NULL); if (!sysinfo(&info)) start_time -= info.uptime; start_time += p->start_time / sysconf(_SC_CLK_TCK); if (p->tty_nr == 0) { snprintf(tty_name, sizeof(tty_name), "(none)"); } else { unsigned int majordev, minordev; majordev = (p->tty_nr & 0xfff00) >> 8; minordev = (p->tty_nr & 0xff) | ((p->tty_nr >> 12) & 0xfff00); if (tty_dev_to_name(majordev, minordev, tty_name, sizeof(tty_name))) snprintf(tty_name, sizeof(tty_name), "%u:%u", majordev, minordev); } printf("General\n"); printf("\tProcess id: %d\n", p->pid); printf("\tParent process id: %d\n", p->ppid); printf("\tProcess group: %d\n", p->pgrp); printf("\tSession id: %d\n", p->sid); printf("\tThreads: %d (", p->num_threads); for (i = 0; i < p->num_threads; i++) printf("%d%c", p->threads[i], (i == (p->num_threads - 1)) ? ')' : ' '); printf("\n"); printf("\tState: "); switch (p->state) { case 'R': printf("R running at cpu %d\n", p->task_cpu); break; case 'S': printf("S interruptable sleeping %s\n", ((p->wchan == 0) || (p->wchan == (unsigned long)-1)) ? "" : p->wchan_decoded); break; case 'D': printf("D uninterruptable sleeping %s\n", ((p->wchan == 0) || (p->wchan == (unsigned long)-1)) ? "" : p->wchan_decoded); break; case 'T': printf("T tracing by pid %d\n", p->tracerpid); break; case 'Z': printf("Z zombie\n"); break; case 'X': printf("X dead\n"); break; default: printf("%c n/a\n", p->state); break; } printf("\tSleeping average: %d %%\n", p->sleepavg); printf("\tTTY: %s\n", tty_name); printf("\tStart time: %s", ctime(&start_time)); printf("\tProcess name: %s\n", p->tcomm == NULL ? "n/a" : p->tcomm); printf("\tExecutable: %s\n", p->exe == NULL ? "n/a" : p->exe); printf("\tRoot directory: %s\n", p->root == NULL ? "n/a" : p->root); printf("\tWorking directory: %s\n", p->cwd == NULL ? "n/a" : p->cwd); printf("\tArguments: "); if (p->argv == NULL) printf("n/a\n"); else for (i = 0; p->argv[i] != NULL; i++) printf("%s%d - %s\n", i == 0 ? "" : "\t ", i, p->argv[i]); printf("\tEnvironment: "); if (p->env == NULL) printf("n/a\n"); else for (i = 0; p->env[i] != NULL; i++) printf("%s%d - %s\n", i == 0 ? "" : "\t ", i, p->env[i]); print_processflags("Flags:", p->flags); } void print_processflags(char *desc, long unsigned flags) { #define TEST_FLAG(x) if (flags & x) printf("\t %016lx - %s\n", (long unsigned)x, #x); printf("\t%s %016lx\n", desc, flags); TEST_FLAG(PF_ALIGNWARN); TEST_FLAG(PF_STARTING); TEST_FLAG(PF_EXITING); TEST_FLAG(PF_EXITPIDONE); TEST_FLAG(PF_VCPU); TEST_FLAG(PF_FORKNOEXEC); TEST_FLAG(PF_SUPERPRIV); TEST_FLAG(PF_DUMPCORE); TEST_FLAG(PF_SIGNALED); TEST_FLAG(PF_MEMALLOC); TEST_FLAG(PF_FLUSHER); TEST_FLAG(PF_USED_MATH); TEST_FLAG(PF_NOFREEZE); TEST_FLAG(PF_FROZEN); TEST_FLAG(PF_FSTRANS); TEST_FLAG(PF_KSWAPD); TEST_FLAG(PF_SWAPOFF); TEST_FLAG(PF_LESS_THROTTLE); TEST_FLAG(PF_BORROWED_MM); TEST_FLAG(PF_RANDOMIZE); TEST_FLAG(PF_SWAPWRITE); TEST_FLAG(PF_SPREAD_PAGE); TEST_FLAG(PF_SPREAD_SLAB); TEST_FLAG(PF_MEMPOLICY); TEST_FLAG(PF_MUTEX_TESTER); TEST_FLAG(PF_FREEZER_SKIP); } void print_cpu(struct process_info *p) { printf("CPU usage\n"); printf("\tNice: %ld\n", p->nice); printf("\tPriority level: %ld\n", p->priority); printf("\tRealtime priority: %u\n", p->rt_priority); printf("\tScheduling policy: "); switch (p->policy) { case SCHED_OTHER: printf("default Linux time-sharing\n"); break; case SCHED_FIFO: printf("first in-first out\n"); break; case SCHED_RR: printf("round robin\n"); break; case SCHED_BATCH: printf("batch\n"); break; default: printf("n/a\n"); } printf("\tRuns:"); if (p->has_schedstat) printf(" %llu\n", p->nran); else printf(" n/a\n"); printf("\tSeconds:\n"); printf("\t user system guest total\n"); printf("\tprocess %8.2f %8.2f", (double) p->utime / KERNEL_HZ, (double) p->stime / KERNEL_HZ); if (p->has_gtime) printf(" %8.2f", (double) p->gtime / KERNEL_HZ); else printf(" n/a"); printf(" %8.2f\n", (double) (p->utime + p->stime + p->gtime) / KERNEL_HZ); printf("\tchildren %8.2f %8.2f", (double) p->cutime / KERNEL_HZ, (double) p->cstime / KERNEL_HZ); if (p->has_gtime) printf(" %8.2f", (double) p->cgtime / KERNEL_HZ); else printf(" n/a"); printf(" %8.2f\n", (double) (p->cutime + p->cstime + p->cgtime) / KERNEL_HZ); printf("\ttotal %8.2f %8.2f", (double) (p->utime + p->cutime) / KERNEL_HZ, (double) (p->stime + p->cstime) / KERNEL_HZ); if (p->has_gtime) printf(" %8.2f", (double) (p->gtime + p->cgtime) / KERNEL_HZ); else printf(" n/a"); printf(" %8.2f\n", (double) (p->utime + p->stime + p->gtime + p->cutime + p->cstime + p->cgtime) / KERNEL_HZ); } void print_signal(struct process_info *p) { printf("Signals\n"); printf("\tUser signal queue:"); if (p->has_sigq) printf(" %lu/%lu\n", p->sigqsize, p->sigqlim); else printf(" n/a\n"); print_sigset("Pending private:", p->sigpending); print_sigset("Pending shared: ", p->sigshpending); print_sigset("Blocked: ", p->sigblocked); print_sigset("Ignored: ", p->sigignored); print_sigset("Caught: ", p->sigcaught); } void print_sigset(char *desc, long unsigned sig) { #define TEST_SIGNAL(x) if (sig & (1 << (x - 1))) printf("\t %d - %s\n", x, #x); printf("\t%s %016lx\n", desc, sig); TEST_SIGNAL(SIGHUP); TEST_SIGNAL(SIGINT); TEST_SIGNAL(SIGQUIT); TEST_SIGNAL(SIGILL); TEST_SIGNAL(SIGTRAP); TEST_SIGNAL(SIGABRT); TEST_SIGNAL(SIGIOT); TEST_SIGNAL(SIGBUS); TEST_SIGNAL(SIGFPE); TEST_SIGNAL(SIGKILL); TEST_SIGNAL(SIGUSR1); TEST_SIGNAL(SIGSEGV); TEST_SIGNAL(SIGUSR2); TEST_SIGNAL(SIGPIPE); TEST_SIGNAL(SIGALRM); TEST_SIGNAL(SIGTERM); TEST_SIGNAL(SIGSTKFLT); TEST_SIGNAL(SIGCHLD); TEST_SIGNAL(SIGCONT); TEST_SIGNAL(SIGSTOP); TEST_SIGNAL(SIGTSTP); TEST_SIGNAL(SIGTTIN); TEST_SIGNAL(SIGTTOU); TEST_SIGNAL(SIGURG); TEST_SIGNAL(SIGXCPU); TEST_SIGNAL(SIGXFSZ); TEST_SIGNAL(SIGVTALRM); TEST_SIGNAL(SIGPROF); TEST_SIGNAL(SIGWINCH); TEST_SIGNAL(SIGIO); TEST_SIGNAL(SIGPOLL); TEST_SIGNAL(SIGPWR); TEST_SIGNAL(SIGSYS); TEST_SIGNAL(SIGUNUSED); } void print_memory(struct process_info *p) { printf("Memory\n"); printf("\tOut-of-memory killer score:"); if (p->has_oom_score) printf(" %d\n", p->oom_score); else printf(" n/a\n"); printf("\tOut-of-memory killer adjustment:"); if (p->has_oom_adj) printf(" %d\n", p->oom_adj); else printf(" n/a\n"); printf("\tVM size: %lu kB", p->vmsize); if (p->has_vmpeak) printf(" (peak %lu kB)\n", p->vmpeak); else printf(" (peak n/a)\n"); printf("\tVM locked size: %lu kB\n", p->vmlck); printf("\tVM resident set size: %lu kB", p->vmrss); if (p->has_vmhwm) printf(" (peak %lu kB)\n", p->vmhwm); else printf(" (peak n/a)\n"); printf("\tVM data segment size: %lu kB\n", p->vmdata); printf("\tVM stack segment size: %lu kB\n", p->vmstk); printf("\tVM text segment size: %lu kB\n", p->vmexe); printf("\tVM shared library size: %lu kB\n", p->vmlib); printf("\tVM page table entries size:"); if (p->has_vmpte) printf(" %lu kB\n", p->vmpte); else printf(" n/a\n"); printf("\tPagefaults:\n"); printf("\t minor major\n"); printf("\tprocess %8lu %8lu\n", p->min_flt, p->maj_flt); printf("\tchildren %8lu %8lu\n", p->cmin_flt, p->cmaj_flt); printf("\ttotal %8lu %8lu\n", p->min_flt + p->cmin_flt, p->maj_flt + p->cmaj_flt); } void print_privilege(struct process_info *p) { printf("Privilege\n"); printf("\tIdentity:\n"); printf("\t real effective saved fs\n"); printf("\tuser %8d %8d %8d %8d\n", p->uid, p->euid, p->suid, p->fsuid); printf("\tgroup %8d %8d %8d %8d\n", p->gid, p->egid, p->sgid, p->fsgid); print_capability("Cap inheritable: ", p->capinh); print_capability("Cap permitted: ", p->capprm); print_capability("Cap effective: ", p->capeff); if (p->has_capbnd) print_capability("Cap bounding set:", p->capbnd); else printf("\tCap bounding set: n/a\n"); } void print_capability(char *desc, long unsigned cap) { #define TEST_CAPABILITY(x) if (cap & (1 << x)) printf("\t %d - %s\n", x, #x); printf("\t%s %016lx\n", desc, cap); TEST_CAPABILITY(CAP_CHOWN); TEST_CAPABILITY(CAP_DAC_OVERRIDE); TEST_CAPABILITY(CAP_DAC_READ_SEARCH); TEST_CAPABILITY(CAP_FOWNER); TEST_CAPABILITY(CAP_FSETID); TEST_CAPABILITY(CAP_KILL); TEST_CAPABILITY(CAP_SETGID); TEST_CAPABILITY(CAP_SETUID); TEST_CAPABILITY(CAP_SETPCAP); TEST_CAPABILITY(CAP_LINUX_IMMUTABLE); TEST_CAPABILITY(CAP_NET_BIND_SERVICE); TEST_CAPABILITY(CAP_NET_BROADCAST); TEST_CAPABILITY(CAP_NET_ADMIN); TEST_CAPABILITY(CAP_NET_RAW); TEST_CAPABILITY(CAP_IPC_LOCK); TEST_CAPABILITY(CAP_IPC_OWNER); TEST_CAPABILITY(CAP_SYS_MODULE); TEST_CAPABILITY(CAP_SYS_RAWIO); TEST_CAPABILITY(CAP_SYS_CHROOT); TEST_CAPABILITY(CAP_SYS_PTRACE); TEST_CAPABILITY(CAP_SYS_PACCT); TEST_CAPABILITY(CAP_SYS_ADMIN); TEST_CAPABILITY(CAP_SYS_BOOT); TEST_CAPABILITY(CAP_SYS_NICE); TEST_CAPABILITY(CAP_SYS_RESOURCE); TEST_CAPABILITY(CAP_SYS_TIME); TEST_CAPABILITY(CAP_SYS_TTY_CONFIG); TEST_CAPABILITY(CAP_MKNOD); TEST_CAPABILITY(CAP_LEASE); TEST_CAPABILITY(CAP_AUDIT_WRITE); TEST_CAPABILITY(CAP_AUDIT_CONTROL); TEST_CAPABILITY(CAP_FS_MASK); } void print_io(struct process_info *p) { printf("I/O\n"); printf("\tFile descriptor table size: %d\n", p->fdsize); printf("\tTime spent waiting for blocking I/O:"); if (p->has_blkio_ticks) printf(" %.2f s\n", (double) p->blkio_ticks / KERNEL_HZ); else printf(" n/a\n"); printf("\tStatistics:"); if (p->has_io) { printf("\n"); printf("\t syscalls tput kB disk kB\n"); printf("\tread %8llu %8llu %8llu\n", p->syscr, p->rchar / 1024, p->read_bytes / 1024); printf("\twritten %8llu %8llu %8llu\n", p->syscw, p->wchar / 1024, p->write_bytes / 1024); printf("\tcancelled - - %8llu\n", p->cancelled_write_bytes / 1024); } else { printf(" n/a\n"); } } int parse_proc(char *base, int pid, struct process_info *p) { char filename[FILENAME_MAX]; snprintf(filename, sizeof(filename), "%s/%d/stat", base, pid); if (parse_proc_file(filename, p, &parse_proc_stat)) { fprintf(stderr, "psinfo: process %d does not exist\n", pid); return 1; } snprintf(filename, sizeof(filename), "%s/%d/statm", base, pid); CHECK_ERROR(parse_proc_file(filename, p, &parse_proc_statm)); parse_proc_file("/proc/sys/kernel/cap-bound", p, &parse_proc_capbnd); snprintf(filename, sizeof(filename), "%s/%d/status", base, pid); CHECK_ERROR(parse_proc_file(filename, p, &parse_proc_status)); snprintf(filename, sizeof(filename), "%s/%d/cmdline", base, pid); CHECK_ERROR(parse_proc_arrayfile(filename, &p->argv)); snprintf(filename, sizeof(filename), "%s/%d/task", base, pid); CHECK_ERROR(parse_proc_task(filename, &p->threads)); snprintf(filename, sizeof(filename), "%s/%d/cwd", base, pid); parse_proc_symlink(filename, &p->cwd); snprintf(filename, sizeof(filename), "%s/%d/environ", base, pid); parse_proc_arrayfile(filename, &p->env); snprintf(filename, sizeof(filename), "%s/%d/root", base, pid); parse_proc_symlink(filename, &p->root); snprintf(filename, sizeof(filename), "%s/%d/exe", base, pid); parse_proc_symlink(filename, &p->exe); snprintf(filename, sizeof(filename), "%s/%d/io", base, pid); parse_proc_file(filename, p, &parse_proc_io); snprintf(filename, sizeof(filename), "%s/%d/oom_adj", base, pid); parse_proc_file(filename, p, &parse_proc_oomadj); snprintf(filename, sizeof(filename), "%s/%d/oom_score", base, pid); parse_proc_file(filename, p, &parse_proc_oomscore); snprintf(filename, sizeof(filename), "%s/%d/schedstat", base, pid); parse_proc_file(filename, p, &parse_proc_schedstat); snprintf(filename, sizeof(filename), "%s/%d/wchan", base, pid); parse_proc_file(filename, p, &parse_proc_wchan); return 0; } void print_help() { printf("psinfo 0.12\n"); printf("Copyright (C) 2008-2010 Ward van Wanrooij \n"); printf("This software may be distributed according to the terms of the GNU\n"); printf("General Public License, version 2 or (at your option) any later version.\n"); printf("\n"); printf("Syntax: psinfo -agcimpsHV pid\n"); printf("\t-a show all information (default)\n"); printf("\t-g show general information\n"); printf("\t-c show cpu information\n"); printf("\t-i show i/o information\n"); printf("\t-m show memory information\n"); printf("\t-p show privilege information\n"); printf("\t-s show signal information\n"); printf("\t-H show help\n"); printf("\t-V show version\n"); } int main(int argc, char **argv) { struct process_info *p; int pid, output_general = 0, output_cpu = 0, output_io = 0, output_memory = 0, output_privilege = 0, output_signal = 0, result = 0; char c; opterr = 0; if (argc <= 1) { print_help(); return 0; } while ((c = getopt(argc, argv, "agcimpsHV")) != -1) { switch (c) { case 'H': case 'V': print_help(); return 0; case 'a': break; case 'g': output_general = 1; break; case 'c': output_cpu = 1; break; case 'i': output_io = 1; break; case 'm': output_memory = 1; break; case 'p': output_privilege = 1; break; case 's': output_signal = 1; break; default: fprintf(stderr, "psinfo: invalid command line option '%c'\n", c); return 1; } } if (optind < argc) { char *end; errno = 0; pid = strtol(argv[optind], &end, 10); if (errno || (argv[optind] == end)) { fprintf(stderr, "psinfo: invalid process identifier '%s'\n", argv[optind]); return 1; } } else { fprintf(stderr, "psinfo: no process identifier specified\n"); return 1; } if ((output_general | output_cpu | output_io | output_memory | output_privilege | output_signal) == 0) { output_general = 1; output_cpu = 1; output_io = 1; output_memory = 1; output_privilege = 1; output_signal = 1; } if ((p = malloc(sizeof(struct process_info))) != NULL) { tzset(); memset(p, 0, sizeof(struct process_info)); if (!(result = (parse_proc("/proc", pid, p)))) { if (output_general) print_general(p); if (output_cpu) print_cpu(p); if (output_io) print_io(p); if (output_memory) print_memory(p); if (output_privilege) print_privilege(p); if (output_signal) print_signal(p); } free(p->threads); free(p); } return result; }