]> granicus.if.org Git - psmisc/commitdiff
first cut of prtstat
authorCraig Small <csmall@users.sourceforge.net>
Tue, 6 Oct 2009 08:17:38 +0000 (08:17 +0000)
committerCraig Small <csmall@users.sourceforge.net>
Tue, 6 Oct 2009 08:17:38 +0000 (08:17 +0000)
src/.cvsignore
src/Makefile.am
src/prtstat.c [new file with mode: 0644]
src/prtstat.h [new file with mode: 0644]

index db9155bd355390263e2324452c0e13bd78dd06bc..79fb0bf34c87a4e90d421245e9df229d1a646160 100644 (file)
@@ -2,6 +2,7 @@ fuser
 oldfuser
 peekfd
 killall
+prtstat
 pstree
 pstree.x11
 signames.h
index 5aa171e4287f213f5ba7764ca2e077eef9ae489e..0bf2893c5a2a3fe1b7f0cc251b551e3ae4d87e59 100644 (file)
@@ -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 (file)
index 0000000..16de3a9
--- /dev/null
@@ -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 <madduck@madduck.net>
+ *
+ * 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 <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..973c459
--- /dev/null
@@ -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;
+};