#include <grp.h>
#include <dirent.h>
#include <ctype.h>
+#include <errno.h>
#include <sys/stat.h>
+
+typedef unsigned long long u64;
+
+
+/* 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"
static int forwards, nobanner, usestdin, raw, usages;
{ 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) {
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;
}
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;
scandev(fnbuf,levelsleft-1);
}
}
+ if (errno)
+ fprintf(stderr, "%s: readdir: %s\n", basename, strerror(errno));
closedir(dir);
free(fnbuf);
}
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();
}
-static void printrecord(const struct acct *as, const char *filename) {
+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;
struct deventry *deve, devlookfor;
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 {
- tm= localtime(&as->ac_btime);
- strftime(buf,sizeof(buf),"%Y-%m-%d %H:%M:%S",tm); buf[sizeof(buf)-1]= 0;
+ btime= as->ac_btime;
+ tm= localtime(&btime);
+ 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);
else printf("%-8ld ",(long)as->ac_gid);
if (raw) {
- if (as->ac_tty == (dev_t)-1) {
+ if (!(as->ac_tty + 1) /* check for -1 without knowing type */) {
printf("- ");
} else {
printf("%08lx ",(unsigned long)as->ac_tty);
}
} else {
- if (as->ac_tty == (dev_t)-1) {
+ if (!(as->ac_tty + 1)) {
printf("- ");
} else {
if (!walkeddev) {
}
}
- r= as->ac_flag;
+ r= FIELD_AC_FLAG(as);
for (i=1, fp= "FS4DX"; *fp; fp++, i<<=1) {
if (r&i) {
putchar(*fp);
printf("#%x",r);
}
putchar(' ');
-
+
+#ifdef HAVE_AC_EXITCODE
+ int dc;
dc= WCOREDUMP(as->ac_exitcode) ? 'd' : 'k';
if (raw) {
if (WIFEXITED(as->ac_exitcode)) {
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');
}
static void processfile(FILE *file, const char *filename) {
- fpos_t pos;
- struct acct as;
+ struct_acct as;
+ long pos;
int r;
if (forwards) {
}
} else {
r= fseek(file,0,SEEK_END); if (r) { perror(filename); exit(8); }
- r= fgetpos(file,&pos); 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 (;;) {
if (pos<sizeof(as)) break;
pos -= sizeof(as);
- r= fsetpos(file,&pos); if (r) { perror(filename); exit(8); }
+ 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);
}
if (usestdin) {
processfile(stdin,"<standard input>");
} else if (!*argv) {
- processnamedfile("/var/account/pacct");
+ processnamedfile("/var/log/account/pacct");
} else {
while (*argv) {
processnamedfile(*argv);