chiark / gitweb /
As submitted as bug and sent to PJB and RJK.
authorian <ian>
Wed, 8 Apr 1998 02:50:27 +0000 (02:50 +0000)
committerian <ian>
Wed, 8 Apr 1998 02:50:27 +0000 (02:50 +0000)
cprogs/.cvsignore [new file with mode: 0644]
cprogs/Makefile [new file with mode: 0644]
cprogs/acctdump.c [new file with mode: 0644]
cprogs/myopt.c [new file with mode: 0644]
cprogs/myopt.h [new file with mode: 0644]

diff --git a/cprogs/.cvsignore b/cprogs/.cvsignore
new file mode 100644 (file)
index 0000000..f750d64
--- /dev/null
@@ -0,0 +1 @@
+acctdump
diff --git a/cprogs/Makefile b/cprogs/Makefile
new file mode 100644 (file)
index 0000000..48e6d93
--- /dev/null
@@ -0,0 +1,6 @@
+CC=    gcc -g -Wall
+CFLAGS=        -Werror -Wstrict-prototypes -Wmissing-prototypes \
+       -Wwrite-strings -Wpointer-arith $(OPTIMISE)
+OPTIMISE=-O2
+
+acctdump:      acctdump.o myopt.o
diff --git a/cprogs/acctdump.c b/cprogs/acctdump.c
new file mode 100644 (file)
index 0000000..2bc85f3
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * acctdump.c - accounting data dump utility
+ *
+ * Copyright (C) 1998 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdarg.h>
+#include <wait.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/acct.h>
+
+#include "myopt.h"
+
+static int forwards, nobanner, usestdin, raw, usages;
+
+static int de_used, de_allocd;
+static struct deventry {
+  const char *fn;
+  dev_t dev;
+} *deventries;
+
+static const struct cmdinfo cmdinfos[]= {
+  { "--forwards",  'f',  0, &forwards, 0, 0, 1, 0, 0 },
+  { "--no-banner", 'q',  0, &nobanner, 0, 0, 1, 0, 0 },
+  { "--stdin",     'p',  0, &usestdin, 0, 0, 1, 0, 0 },
+  { "--raw",       'r',  0, &raw,      0, 0, 1, 0, 0 },
+  { "--resource",  'u',  0, &usages,   0, 0, 1, 0, 0 },
+  {  0                                                 }
+};
+
+static const char *sigabbrev[]= {
+  "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "BUS", "FPE",
+  "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT",
+  "CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "URG", "XCPU",
+  "XFSZ", "VTALRM", "PROF", "WINCH", "IO"
+};
+
+static void usage(FILE *file) {
+  fputs("usage: acctdump [<options>] [<file> ...]\n"
+       "options: -f|--forwards -q|--no-banner -p|--stdin -r|--raw -u|--resource\n",
+       file);
+  if (ferror(file)) { perror("print usage"); exit(8); }
+}
+
+void badusage(const char *fmt, ...) {
+  va_list al;
+
+  fputs("usage error: ",stderr);
+  va_start(al,fmt);
+  vfprintf(stderr,fmt,al);
+  va_end(al);
+  fputs("\n",stderr);
+  usage(stderr);
+  exit(12);
+}
+
+static void checkstdout(void) {
+  if (ferror(stdout)) { perror("stdout"); exit(8); }
+}
+
+static void scandev(const char *basename, int levelsleft) {
+  /* We deliberately ignore most errors */
+  DIR *dir;
+  struct dirent *de;
+  struct stat stab;
+  int fnbufalloc, fnbufreq, r, basel, nallocd;
+  char *fnbuf, *nfnbuf;
+  struct deventry *ndeventries;
+  
+  if (levelsleft==0) return;
+
+  dir= opendir(basename); if (!dir) return;
+  fnbufalloc= 0;
+  fnbuf= 0;
+  basel= strlen(basename);
+
+  while ((de= readdir(dir))) {
+    fnbufreq= basel+1+strlen(de->d_name)+1;
+    if (fnbufalloc<fnbufreq) {
+      fnbufalloc= fnbufreq+10;
+      nfnbuf= realloc(fnbuf,fnbufalloc);
+      if (!nfnbuf) { free(fnbuf); fnbufalloc=0; continue; }
+      fnbuf= nfnbuf;
+    }
+    sprintf(fnbuf,"%s/%s",basename,de->d_name);
+    r= lstat(fnbuf,&stab);
+    if (S_ISCHR(stab.st_mode)) {
+      if (de_used >= de_allocd) {
+       nallocd= (de_allocd+10)<<1;
+       ndeventries= realloc(deventries,nallocd*sizeof(*deventries));
+       if (!ndeventries) continue;
+       de_allocd= nallocd;
+       deventries= ndeventries;
+      }
+      deventries[de_used].fn= strdup(fnbuf+5); /* remove /dev */
+      if (!deventries[de_used].fn) continue;
+      deventries[de_used].dev= stab.st_rdev;
+      de_used++;
+    } else if (S_ISDIR(stab.st_mode) && de->d_name[0] != '.') {
+      scandev(fnbuf,levelsleft-1);
+    }
+  }
+  closedir(dir);
+  free(fnbuf);
+}
+
+static int walkdev_cptr(const void *av, const void *bv) {
+  const struct deventry *a= av;
+  const struct deventry *b= bv;
+  return a->dev - b->dev;
+}
+  
+static void printbanner(void) {
+  if (raw) {
+    fputs("begin date command          "
+         "uid      gid      tty dev  FSDX exit",
+         stdout);
+  } else {
+    fputs("begin date and time command          "
+         "user     group    tty dev    FSDX sigexit",
+         stdout);
+  }
+  if (usages) {
+    fputs("  user time   sys time  elap time   minflt   maxflt",
+         stdout);
+  }
+  putchar('\n');
+  checkstdout();
+}
+
+static void printrecord(const struct acct *as, const char *filename) {
+  static int walkeddev;
+
+  int i, dc, r;
+  const char *fp;
+  char buf[100];
+  struct tm *tm;
+  struct deventry *deve, devlookfor;
+  struct passwd *pw;
+  struct group *gr;
+
+  if (raw) {
+    printf("%10lu ",(unsigned long)as->ac_btime);
+  } else {
+    tm= localtime(&as->ac_btime);
+    strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S",tm); buf[sizeof(buf)-1]= 0;
+    printf("%19s ",buf);
+  }
+  
+  printf("%-16.16s ", as->ac_comm);
+  
+  pw= raw ? 0 : getpwuid(as->ac_uid);
+  if (pw) printf("%-8s ",pw->pw_name);
+  else printf("%-8ld ",(long)as->ac_uid);
+  
+  gr= raw ? 0 : getgrgid(as->ac_gid);
+  if (gr) printf("%-8s ",gr->gr_name);
+  else printf("%-8ld ",(long)as->ac_gid);
+
+  if (raw) {
+    if (as->ac_tty == (dev_t)-1) {
+      printf("-        ");
+    } else {
+      printf("%08lx ",(unsigned long)as->ac_tty);
+    }
+  } else {
+    if (as->ac_tty == (dev_t)-1) {
+      printf("-          ");
+    } else {
+      if (!walkeddev) {
+       scandev("/dev",4);
+       qsort(deventries,de_used,sizeof(*deventries),walkdev_cptr);
+       walkeddev= 1;
+      }
+      devlookfor.fn= 0;
+      devlookfor.dev= as->ac_tty;
+      deve= bsearch(&devlookfor,deventries,de_used,sizeof(*deventries),walkdev_cptr);
+      if (deve) {
+       printf("%-10s ",deve->fn);
+      } else {
+       printf("%08lx   ",(unsigned long)as->ac_tty);
+      }
+    }
+  }
+
+  r= as->ac_flag;
+  for (i=1, fp= "FSDX"; *fp; fp++, i<<=1) {
+    if (r&i) {
+      putchar(*fp);
+      r &= ~i;
+    } else {
+      putchar(' ');
+    }
+  }
+  if (r) {
+    printf("#%x",r);
+  }
+  putchar(' ');
+  
+  dc= WCOREDUMP(as->ac_exitcode) ? 'd' : 'k';
+  if (raw) {
+    if (WIFEXITED(as->ac_exitcode)) {
+      printf(" %3d",WEXITSTATUS(as->ac_exitcode));
+    } else if (WIFSIGNALED(as->ac_exitcode)) {
+      printf("%c%3d",
+            dc,
+            WTERMSIG(as->ac_exitcode));
+    } else {
+      printf("%04lx",(unsigned long)as->ac_exitcode);
+    }
+  } else {
+    if (WIFEXITED(as->ac_exitcode)) {
+      printf(" %6d",WEXITSTATUS(as->ac_exitcode));
+    } else if (WIFSIGNALED(as->ac_exitcode)) {
+      r= WTERMSIG(as->ac_exitcode);
+      if (r>0 && r<=sizeof(sigabbrev)/sizeof(*sigabbrev)) {
+       printf("%c%6s",
+              dc,
+              sigabbrev[r-1]);
+      } else {
+       printf("%cSIG%-3d",
+              dc,
+              r);
+      }
+    } else {
+      printf("#%04lx",(unsigned long)as->ac_exitcode);
+    }
+  }
+
+  if (usages) {
+    printf(" %10lu %10lu %10lu %8ld %8ld",
+          (unsigned long)as->ac_utime,
+          (unsigned long)as->ac_stime,
+          (unsigned long)as->ac_etime,
+          (unsigned long)as->ac_minflt,
+          (unsigned long)as->ac_majflt);
+  }
+  putchar('\n');
+
+  checkstdout();
+}
+
+static void processfile(FILE *file, const char *filename) {
+  fpos_t pos;
+  struct acct as;
+  int r;
+  
+  if (forwards) {
+    while ((r= fread(&as,1,sizeof(as),file)) == sizeof(as)) {
+      printrecord(&as,filename);
+    }
+  } else {
+    r= fseek(file,0,SEEK_END); if (r) { perror(filename); exit(8); }
+    r= fgetpos(file,&pos); if (r) { perror(filename); exit(8); }
+    for (;;) {
+      if (pos<sizeof(as)) break;
+      pos -= sizeof(as);
+      r= fsetpos(file,&pos); if (r) { perror(filename); exit(8); }
+      r= fread(&as,1,sizeof(as),file); if (r!=sizeof(as)) { perror(filename); exit(8); }
+      printrecord(&as,filename);
+    }
+  }
+  if (ferror(file) || fclose(file)) { perror(filename); exit(8); }
+}
+
+static void processnamedfile(const char *filename) {
+  FILE *file;
+
+  file= fopen(filename,"rb"); if (!file) { perror(filename); exit(8); }
+  processfile(file,filename);
+}
+
+int main(int argc, const char *const *argv) {
+  myopt(&argv,cmdinfos);
+  if (!nobanner) printbanner();
+  if (usestdin) {
+    processfile(stdin,"<standard input>");
+  } else if (!*argv) {
+    processnamedfile("/var/account/pacct");
+  } else {
+    while (*argv) {
+      processnamedfile(*argv);
+      argv++;
+    }
+  }
+  checkstdout();
+  if (fflush(stdout)) { perror("flush stdout"); exit(8); }
+  return 0;
+}
diff --git a/cprogs/myopt.c b/cprogs/myopt.c
new file mode 100644 (file)
index 0000000..e776f92
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * myopt.c - my very own option parsing
+ *
+ * Copyright (C) 1994,1995,1998 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+
+#include "myopt.h"
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos) {
+  const struct cmdinfo *cip;
+  const char *p, *value;
+  int l;
+
+  ++(*argvp);
+  while ((p= **argvp) && *p == '-') {
+    ++(*argvp);
+    if (!strcmp(p,"--")) break;
+    if (*++p == '-') {
+      ++p; value=0;
+      for (cip= cmdinfos;
+           cip->olong || cip->oshort;
+           cip++) {
+        if (!cip->olong) continue;
+        if (!strcmp(p,cip->olong)) break;
+        l= strlen(cip->olong);
+        if (!strncmp(p,cip->olong,l) &&
+            (p[l]== ((cip->takesvalue==2) ? '-' : '='))) { value=p+l+1; break; }
+      }
+      if (!cip->olong) badusage("unknown option --%s",p);
+      if (cip->takesvalue) {
+        if (!value) {
+          value= *(*argvp)++;
+          if (!value) badusage("--%s option takes a value",cip->olong);
+        }
+        if (cip->call) cip->call(cip,value);
+        else *cip->sassignto= value;
+      } else {
+        if (value) badusage("--%s option does not take a value",cip->olong);
+        if (cip->call) cip->call(cip,0);
+        else *cip->iassignto= cip->arg;
+      }
+    } else {
+      while (*p) {
+        for (cip= cmdinfos; (cip->olong || cip->oshort) && *p != cip->oshort; cip++);
+        if (!cip->oshort) badusage("unknown option -%c",*p);
+        p++;
+        if (cip->takesvalue) {
+          if (!*p) {
+            value= *(*argvp)++;
+            if (!value) badusage("-%c option takes a value",cip->oshort);
+          } else {
+            value= p; p="";
+            if (*value == '=') value++;
+          }
+          if (cip->call) cip->call(cip,value);
+          else *cip->sassignto= value;
+        } else {
+          if (*p == '=') badusage("-%c option does not take a value",cip->oshort);
+          if (cip->call) cip->call(cip,0);
+          else *cip->iassignto= cip->arg;
+        }
+      }
+    }
+  }
+}
diff --git a/cprogs/myopt.h b/cprogs/myopt.h
new file mode 100644 (file)
index 0000000..227d108
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * myopt.h - declarations for my very own option parsing
+ *
+ * Copyright (C) 1994,1995,1998 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MYOPT_H
+#define MYOPT_H
+
+typedef void (*voidfnp)(void);
+
+struct cmdinfo {
+  const char *olong;
+  char oshort;
+  int takesvalue; /* 0 = normal   1 = standard value   2 = option string cont */
+  int *iassignto;
+  const char **sassignto;
+  void (*call)(const struct cmdinfo*, const char *value);
+  int arg;
+  void *parg;
+  voidfnp farg;
+};
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos);
+
+void badusage(const char *fmt, ...);
+
+#endif /* MYOPT_H */