From 5d16517c2561f0f9f4e8d26b6d4eed12f1d71697 Mon Sep 17 00:00:00 2001 From: Craig Small Date: Tue, 6 Oct 2009 08:17:38 +0000 Subject: [PATCH] first cut of prtstat --- src/.cvsignore | 1 + src/Makefile.am | 4 +- src/prtstat.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++ src/prtstat.h | 20 ++++ 4 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 src/prtstat.c create mode 100644 src/prtstat.h diff --git a/src/.cvsignore b/src/.cvsignore index db9155b..79fb0bf 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -2,6 +2,7 @@ fuser oldfuser peekfd killall +prtstat pstree pstree.x11 signames.h diff --git a/src/Makefile.am b/src/Makefile.am index 5aa171e..0bf2893 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ AM_CFLAGS = -Wall -DLOCALEDIR=\"/usr/share/locale\" -bin_PROGRAMS = fuser killall pstree +bin_PROGRAMS = fuser killall pstree prtstat if WANT_PEEKFD_I386 bin_PROGRAMS += peekfd AM_CFLAGS += -DI386 @@ -27,6 +27,8 @@ pstree_SOURCES = pstree.c comm.h i18n.h pstree_LDADD = @TERMCAP_LIB@ @SELINUX_LIB@ +prtstat_SOURCES = prtstat.c + BUILT_SOURCES = signames.h EXTRA_DIST = signames.c diff --git a/src/prtstat.c b/src/prtstat.c new file mode 100644 index 0000000..16de3a9 --- /dev/null +++ b/src/prtstat.c @@ -0,0 +1,296 @@ +/* + * prtstat.c - Print a processes stat file + * + * Copyright (C) 2009 Craig Small + * Based upon a shell script pstat by martin f. krafft + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i18n.h" +#include "prtstat.h" + +#define NORETURN __attribute__((__noreturn__)) + +static long sc_clk_tck; + +static void usage(const char *errormsg) NORETURN; + +static void usage(const char *errormsg) +{ + if (errormsg != NULL) + fprintf(stderr, "%s\n", errormsg); + fprintf(stderr, + _ + ("Usage: prtstat [options] PID ...\n" + " prtstat -V\n" + "Print information about a process\n" + " -r,--raw Raw display of information\n" + " -V,--version Display version information and exit\n" + )); + exit(1); +} + +static void print_version(void) +{ + fprintf(stderr, _("prtstat (PSmisc) %s\n"), VERSION); + fprintf(stderr, _( "Copyright (C) 2009 Craig Small\n\n")); + fprintf(stderr, _( + "PSmisc comes with ABSOLUTELY NO WARRANTY.\n" + "This is free software, and you are welcome to redistribute it under\n" + "the terms of the GNU General Public License.\n" + "For more information about these matters, see the files named COPYING.\n")); +} + +static char *print_state(const char state) +{ + switch(state) { + case 'R': + return _("running"); + case 'S': + return _("sleeping"); + case 'D': + return _("disk sleep"); + case 'Z': + return _("zombie"); + case 'T': + return _("traced"); + case 'W': + return _("paging"); + } + return _("unknown"); +} + +#define RAW_STAT(afmt,aname, aval, bfmt, bname, bval) \ + printf("%12.11s: %-15"afmt"\t%22.21s: %"bfmt"\n",(aname),(aval),(bname),(bval)) + +static double convert_time(const unsigned long ticks) +{ + assert(sc_clk_tck > 0); + return (float)ticks / (float)sc_clk_tck; +} + +static void convert_bytes(char *buf, const long bytes) +{ + if (bytes > (2^30)) + sprintf(buf, "%lu GB",bytes << 30); + if (bytes > (2^20)) + sprintf(buf, "%lu MB",bytes << 20); + else if (bytes > (2^10)) + sprintf(buf, "%lu kB", bytes << 10); + else + sprintf(buf, "%lu B", bytes); +} + +static void print_raw_stat(const int pid,struct proc_info *pr) +{ + RAW_STAT("d","pid",pid,"s","comm",pr->comm); + RAW_STAT("c","state",pr->state, "d","ppid",pr->ppid); + RAW_STAT("d","pgrp",pr->pgrp, "d","session",pr->session); + RAW_STAT("d","tty_nr",pr->tty_nr, "d","tpgid",pr->tp_gid); + RAW_STAT("x","flags",pr->flags, "lu","minflt",pr->minflt); + RAW_STAT("lu","cminflt",pr->cminflt, "lu","majflt",pr->majflt); + RAW_STAT("lu","cmajflt",pr->cmajflt, "lu","utime",pr->utime); + RAW_STAT("lu","stime",pr->stime, "ld","cutime",pr->cutime); + RAW_STAT("ld","cstime",pr->cstime, "ld","priority",pr->priority); + RAW_STAT("ld","nice",pr->nice, "ld","num_threads",pr->num_threads); + RAW_STAT("ld","itrealvalue",pr->itrealvalue, "llu","starttime",pr->starttime); + RAW_STAT("lu","vsize",pr->vsize, "ld","rss",pr->rss); + RAW_STAT("lu","rsslim",pr->rsslim, "lu","startcode",pr->startcode); + RAW_STAT("lu","endcode",pr->endcode, "lu","startstack",pr->startstack); + RAW_STAT("lX","kstkesp",pr->kstesp, "lX","kstkeip",pr->ksteip); + RAW_STAT("lu","wchan",pr->wchan, "lu","nswap",pr->nswap); + RAW_STAT("lu","cnswap",pr->wchan, "d","exit_signal",pr->exit_signal); + RAW_STAT("d","processor",pr->processor, "u","rt_priority",pr->rt_priority); + RAW_STAT("u","policy",pr->policy, "llu","delayaccr_blkio_ticks",pr->blkio); + RAW_STAT("lu","guest_time",pr->guest_time, "ld","cguest_time",pr->cguest_time); +} +static void print_formated_stat(const int pid,struct proc_info *pr) +{ + char buf_vsize[200]; + char buf_rsslim[200]; + + printf(_("Process: %s\t\tState: %c (%s)\n"), pr->comm, + pr->state, print_state(pr->state)); + printf(_( + "Process, Group and Session IDs\n" + " Process ID: %d\t\t Parent ID: %d\n" + " Group ID: %d\t\t Session ID: %d\n" + " T Group ID: %d\n\n"), + pid, pr->ppid, pr->pgrp, pr->session, pr->tp_gid); + printf(_( + "Page Faults\n" + " This - Minor: %-10lu\t\t Major:%lu\n" + " Children - Minor: %-10lu\t\t Major:%lu\n"), + pr->minflt, pr->majflt, pr->cminflt, pr->cmajflt); + printf(_( + "CPU Times\n" + " This - User: %-10.2f\t System: %-10.2f\t Guest: %-10.2f\n" + " Children - User: %-10.2f\t System: %-10.2f\t Guest: %-10.2f\n"), + convert_time(pr->utime), convert_time(pr->stime), convert_time(pr->guest_time), + convert_time(pr->cutime), convert_time(pr->cstime), convert_time(pr->cguest_time)); + convert_bytes(buf_vsize, pr->vsize); + convert_bytes(buf_rsslim, pr->rsslim); + printf(_( + "Memory\n" + " Vsize: %-10s\n" + " RSS: %-10lu\t\t pages RSS Limit: %s\n" + " Code Area: %#10lx - %#10lx\tEIP: %#10lx\n" + " Stack: %#10lx\t\tStack Pointer: %#10lx\n"), + buf_vsize, pr->rss, buf_rsslim, + pr->startcode, pr->endcode, pr->ksteip, + pr->startstack, pr->kstesp); + + + +} +static void print_stat(const int pid, const opt_type options) +{ + char *pathname; + char buf[BUFSIZ]; + char *bptr; + FILE *fp; + + struct proc_info *pr; + pr = malloc(sizeof(struct proc_info)); + + if ( (asprintf(&pathname, "/proc/%d/stat",(int)pid)) < 0) { + perror(_("asprintf in print_stat failed.\n")); + exit(1); + } + if ( (fp = fopen(pathname,"r")) == NULL) { + if (errno == ENOENT) + fprintf(stderr, _("Process PID=%d does not exist.\n"), pid); + else + fprintf(stderr, _("Unable to open stat file for pid %d (%s)\n"),(int)pid,strerror(errno)); + free(pathname); + return; + } + free(pathname); + + fgets(buf,BUFSIZ,fp); + bptr = strchr(buf, '('); + if (bptr == NULL) return; + bptr++; + sscanf(bptr, + "%a[^)]) " + "%c " + "%d %d %d %d %d %d" + "%lu %lu %lu %lu " /*flts*/ + "%lu %lu %lu %lu " /*times */ + "%ld %ld %ld %ld " /* nice, priority, threads, itreal*/ + "%llu " /*startime*/ + "%lu %ld %lu " /* vsize, rss, rslim */ + "%lu %lu %lu " /* startcode endcode startstack */ + "%lu %lu " /* stack and ip */ + "%*s %*s %*s %*s " /* signals - ignore as they are obsolete */ + "%lu %lu %lu " /* wchan nswap cnswap */ + "%d %d %u" + "%u %llu " /* policy blkio */ + "%lu %lu ", /* guest time cguest time */ + &pr->comm, + &pr->state, + &pr->ppid, &pr->pgrp, &pr->session, &pr->tty_nr, &pr->tp_gid, &pr->flags, + &pr->minflt, &pr->cminflt, &pr->majflt, &pr->cmajflt, + &pr->utime, &pr->stime, &pr->cutime, &pr->cstime, + &pr->priority, &pr->nice, &pr->num_threads, &pr->itrealvalue, + &pr->starttime, + &pr->vsize, &pr->rss, &pr->rsslim, + &pr->startcode, &pr->endcode, &pr->startstack, + &pr->kstesp, &pr->ksteip, + &pr->wchan, &pr->nswap, &pr->cnswap, + &pr->exit_signal, &pr->processor, &pr->rt_priority, + &pr->policy, &pr->blkio, + &pr->guest_time, &pr->cguest_time + ); + if (options & OPT_RAW) { + print_raw_stat(pid, pr); + return; + } + print_formated_stat(pid, pr); + + +} + +int main(int argc, char *argv[]) +{ + int optc; + struct stat st; + int pptr; + int pid; + opt_type opt_flags = 0; + + struct option options[] = { + {"raw" ,0, NULL, 'r' }, + {"version", 0, NULL, 'V'} + }; + +#ifdef ENABLE_NLS + /* Set up the i18n */ + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); +#endif + + while ((optc = getopt_long(argc, argv, "rV", options, NULL)) != -1) { + switch(optc) { + case 'r': + opt_flags |= OPT_RAW; + break; + case 'V': + print_version(); + return 0; + case '?': + usage(_("Invalid option")); + break; + } + } /* while */ + if (argc <= optind) + usage(_("You must provide at least one PID.")); + + if (stat("/proc/self/stat", &st) == -1) + { + fprintf(stderr, _("/proc is not mounted, cannot stat /proc/self/stat.\n")); + exit(1); + } + sc_clk_tck = sysconf(_SC_CLK_TCK); + for(pptr = optind; pptr < argc; pptr++) + { + pid = atoi(argv[pptr]); + print_stat(pid, opt_flags); + } + + return 0; +} + + + diff --git a/src/prtstat.h b/src/prtstat.h new file mode 100644 index 0000000..973c459 --- /dev/null +++ b/src/prtstat.h @@ -0,0 +1,20 @@ + +typedef unsigned char opt_type; +#define OPT_RAW 1 + +struct proc_info +{ + char *comm; + char state; + int ppid, pgrp, session, tty_nr, tp_gid, + exit_signal, processor; + unsigned int flags, rt_priority, policy; + unsigned long minflt, cminflt, majflt, cmajflt, + utime, stime, vsize, rsslim, + startcode, endcode, startstack, + kstesp, ksteip, + wchan, nswap, cnswap, guest_time; + long cutime, cstime, priority, nice, num_threads, + itrealvalue, rss, cguest_time; + unsigned long long starttime, blkio; +}; -- 2.40.0