chiark / gitweb /
cgi-fcgi-interp: new garbage collection approach, spec
[chiark-utils.git] / cprogs / acctdump.c
index e1b76746efa514255b95dbe30c38f8b0a6a5c010..b9040ac710f91eebe6a83af73262a2027a4e4e29 100644 (file)
 #include <sys/stat.h>
 
 typedef unsigned long long u64;
-#include "acct.h"
-/*#include <sys/acct.h>*/
+
+
+/* Sadly this thing is not very portable */
+
+#if defined(__linux__)
+
+#include <sys/types.h>
+#include <sys/acct.h>
+
 typedef struct acct_v3 struct_acct;
+#define HAVE_AC_EXITCODE
+#define HAVE_AC_FLT
+#define FIELD_AC_FLAG(as) ((as)->ac_flag)
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/acct.h>
+
+typedef struct acctv2 struct_acct;
+#define HAVE_AC_IO_MEM
+#define FIELD_AC_FLAG(as) ((as)->ac_flagx & ~ANVER)
+
+#else
+
+#error Do not know what struct_acct to use on this platform
+
+#endif
+
 
 #include "myopt.h"
 
@@ -55,30 +82,20 @@ static const struct cmdinfo cmdinfos[]= {
   {  0                                                 }
 };
 
+#ifdef HAVE_AC_EXITCODE
 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"
 };
+#endif
 
-static void usage(FILE *file) {
+void usagemessage(void) {
   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);
+       stderr);
+  if (ferror(stderr)) { perror("print usage"); exit(8); }
 }
 
 static void checkstdout(void) {
@@ -96,12 +113,16 @@ static void scandev(const char *basename, int levelsleft) {
   
   if (levelsleft==0) return;
 
-  dir= opendir(basename); if (!dir) return;
+  dir= opendir(basename); 
+  if (!dir) {
+    fprintf(stderr, "%s: opendir: %s\n", basename, strerror(errno));
+    return;
+  }
   fnbufalloc= 0;
   fnbuf= 0;
   basel= strlen(basename);
 
-  while ((de= readdir(dir))) {
+  while ((errno=0, de= readdir(dir))) {
     fnbufreq= basel+1+strlen(de->d_name)+1;
     if (fnbufalloc<fnbufreq) {
       fnbufalloc= fnbufreq+10;
@@ -111,6 +132,10 @@ static void scandev(const char *basename, int levelsleft) {
     }
     sprintf(fnbuf,"%s/%s",basename,de->d_name);
     r= lstat(fnbuf,&stab);
+    if (r) {
+      fprintf(stderr, "%s: %s\n", fnbuf, strerror(errno));
+      continue;
+    }
     if (S_ISCHR(stab.st_mode)) {
       if (de_used >= de_allocd) {
        nallocd= (de_allocd+10)<<1;
@@ -127,6 +152,8 @@ static void scandev(const char *basename, int levelsleft) {
       scandev(fnbuf,levelsleft-1);
     }
   }
+  if (errno)
+      fprintf(stderr, "%s: readdir: %s\n", basename, strerror(errno));
   closedir(dir);
   free(fnbuf);
 }
@@ -140,16 +167,28 @@ static int walkdev_cptr(const void *av, const void *bv) {
 static void printbanner(void) {
   if (raw) {
     fputs("begin date command          "
-         "uid      gid      tty dev  FSDX exit",
-         stdout);
+         "uid      gid      tty dev  FSDX "
+#ifdef HAVE_AC_EXITCODE
+         "exit"
+#endif
+         , stdout);
   } else {
     fputs("begin date and time command          "
-         "user     group    tty dev    FSDX sigexit",
-         stdout);
+         "user     group    tty dev    FSDX "
+#ifdef HAVE_AC_EXITCODE
+         "sigexit"
+#endif
+         , stdout);
   }
   if (usages) {
-    fputs("  user time   sys time  elap time   minflt   maxflt",
-         stdout);
+    fputs("  user time   sys time  elap time "
+#ifdef HAVE_AC_FLT
+         "  minflt   maxflt"
+#endif
+#ifdef HAVE_AC_IO_MEM
+         "  avg.mem      io"
+#endif
+         , stdout);
   }
   putchar('\n');
   checkstdout();
@@ -158,7 +197,7 @@ static void printbanner(void) {
 static void printrecord(const struct_acct *as, const char *filename) {
   static int walkeddev;
 
-  int i, dc, r;
+  int i, r;
   const char *fp;
   char buf[100];
   struct tm *tm;
@@ -166,17 +205,26 @@ static void printrecord(const struct_acct *as, const char *filename) {
   struct passwd *pw;
   struct group *gr;
   time_t btime;
+  char commbuf[sizeof(as->ac_comm)];
 
   if (raw) {
     printf("%10lu ",(unsigned long)as->ac_btime);
   } else {
     btime= as->ac_btime;
     tm= localtime(&btime);
-    strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S",tm); buf[sizeof(buf)-1]= 0;
+    if (tm) {
+      strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S",tm); buf[sizeof(buf)-1]= 0;
+    } else {
+      snprintf(buf,sizeof(buf),"@%lu",(unsigned long)btime);
+    }
     printf("%19s ",buf);
   }
-  
-  printf("%-16.16s ", as->ac_comm);
+
+  for (i=0; i<sizeof(as->ac_comm); i++) {
+    int c=as->ac_comm[i];
+    commbuf[i]= ((c!=0 && c<=32) || c>=127) ? '?' : c;
+  }
+  printf("%-*.*s ", (int)sizeof(commbuf),(int)sizeof(commbuf), commbuf);
   
   pw= raw ? 0 : getpwuid(as->ac_uid);
   if (pw) printf("%-8s ",pw->pw_name);
@@ -212,7 +260,7 @@ static void printrecord(const struct_acct *as, const char *filename) {
     }
   }
 
-  r= as->ac_flag;
+  r= FIELD_AC_FLAG(as);
   for (i=1, fp= "FS4DX"; *fp; fp++, i<<=1) {
     if (r&i) {
       putchar(*fp);
@@ -225,7 +273,9 @@ static void printrecord(const struct_acct *as, const char *filename) {
     printf("#%x",r);
   }
   putchar(' ');
-  
+
+#ifdef HAVE_AC_EXITCODE
+  int dc;
   dc= WCOREDUMP(as->ac_exitcode) ? 'd' : 'k';
   if (raw) {
     if (WIFEXITED(as->ac_exitcode)) {
@@ -255,14 +305,23 @@ static void printrecord(const struct_acct *as, const char *filename) {
       printf("#%04lx",(unsigned long)as->ac_exitcode);
     }
   }
+#endif /*HAVE_AC_EXITCODE*/
 
   if (usages) {
-    printf(" %10lu %10lu %10lu %8ld %8ld",
+    printf(" %10lu %10lu %10lu",
           (unsigned long)as->ac_utime,
           (unsigned long)as->ac_stime,
-          (unsigned long)as->ac_etime,
+          (unsigned long)as->ac_etime);
+#ifdef HAVE_AC_FLT
+    printf(" %8lu %8lu",
           (unsigned long)as->ac_minflt,
           (unsigned long)as->ac_majflt);
+#endif
+#ifdef HAVE_AC_IO_MEM
+    printf(" %4e %4e",
+          as->ac_mem,
+          as->ac_io);
+#endif
   }
   putchar('\n');
 
@@ -271,6 +330,7 @@ static void printrecord(const struct_acct *as, const char *filename) {
 
 static void processfile(FILE *file, const char *filename) {
   struct_acct as;
+  long pos;
   int r;
   
   if (forwards) {
@@ -278,18 +338,19 @@ static void processfile(FILE *file, const char *filename) {
       printrecord(&as,filename);
     }
   } else {
-    long seekdist= -(long)sizeof(as);
     r= fseek(file,0,SEEK_END); if (r) { perror(filename); exit(8); }
+    pos= ftell(file); if (pos==-1) { perror(filename); exit(8); }
+    if (pos % sizeof(as)) { 
+      fprintf(stderr, "%s: File size is not an integral number "
+             "of accounting records\n", filename);
+      exit(8);
+    }
     for (;;) {
-      r= fseek(file,seekdist,SEEK_CUR);
-      if (r) {
-       if (errno=EINVAL) break;
-       perror(filename); exit(8);
-      }
-      r= fread(&as,1,sizeof(as),file);
-      if (r!=sizeof(as)) { perror(filename); exit(8); }
+      if (pos<sizeof(as)) break;
+      pos -= sizeof(as);
+      r= fseek(file,pos,SEEK_SET); if (r==-1) { perror(filename); exit(8); }
+      r= fread(&as,1,sizeof(as),file); if (r!=sizeof(as)) { perror(filename); exit(8); }
       printrecord(&as,filename);
-      seekdist= -2*(long)sizeof(as);
     }
   }
   if (ferror(file) || fclose(file)) { perror(filename); exit(8); }
@@ -303,15 +364,12 @@ static void processnamedfile(const char *filename) {
 }
 
 int main(int argc, const char *const *argv) {
-union { struct_acct ac; char c[1]; } xu;
   myopt(&argv,cmdinfos);
   if (!nobanner) printbanner();
-fprintf(stdout,"s=%d %d\n",(int)sizeof(struct_acct),
-       (int)((char*)&xu.ac.ac_comm - xu.c));
   if (usestdin) {
     processfile(stdin,"<standard input>");
   } else if (!*argv) {
-    processnamedfile("/var/account/pacct");
+    processnamedfile("/var/log/account/pacct");
   } else {
     while (*argv) {
       processnamedfile(*argv);