home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume13 / printacct < prev    next >
Text File  |  1988-01-31  |  22KB  |  900 lines

  1. Subject:  v13i033:  Print BSD accounting file
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Roy Smith <phri!roy>
  7. Posting-number: Volume 13, Issue 33
  8. Archive-name: printacct
  9.  
  10. [  This package displays the contents of the /usr/adm/acct files in
  11.    human-readable format, so you can use things like awk and perl to
  12.    print "better" accounting records.  It will probably need work to
  13.    run with the SystemV accounting stuff.  --r$ ]
  14.  
  15. # This is a shell archive.  Remove anything before this line,
  16. # then unpack it by saving it in a file and typing "sh file".
  17. # Contents:  README Makefile pracct.1 pracct.c yesterday.c accounting
  18.  
  19. echo x - README
  20. sed 's/^@//' > "README" <<'@//E*O*F README//'
  21. Mon Jan 25 23:15:18 EST 1988
  22.  
  23.     This is a little program I whipped up to help me do user cpu usage
  24. accounting.  On the surface, /etc/sa (or /usr/etc/sa if you're on a Sun) does
  25. cpu usage accounting, but it does so much damn processing that I kept finding
  26. myself being frustrated because I couldn't get exactly the statistics I
  27. wanted.  Very un-unix-like, sa is.  Doesn't let the user get at the actual
  28. data to do what he wants with it.
  29.  
  30.     My answer was to just convert the fields in /usr/adm/acct to ascii and
  31. hack together awk scripts to pull out whatever bits of information I happened
  32. to want that month.  Maybe not very efficient, but easy.  Contained herein is
  33. the program to print the /usr/adm/acct file, a man page, and a sample shell
  34. script that we run out of crontab at 15 minutes past midnight every day.  We
  35. run this on a network of Sun workstations, all of which remote mount a common
  36. /usr/local.  Since root permissions don't apply accross NFS mount points, I
  37. made /usr/local/acct owned by user "acct", and su to that when it comes time
  38. to move the daily summary file there.  You can't just make the whole script
  39. suid acct because it has to remove /usr/adm/acct (aka /private/usr/adm/acct),
  40. which needs root permission.  Isn't NFS fun?
  41.  
  42.     One last note.  I like to keep each day's stats in a file named for
  43. that day.  Since we run the stats for day X a few minutes into day X+1, I
  44. can't just use date to generate file names, because the names would be off by
  45. one day.  I whipped up yesterday.c to solve this problem.  A nicer solution
  46. (but decidedly feeping creatureism) would be to expand the Sys5 date to accept
  47. a (signed) offset which is added to the current date before going through the
  48. variable output formatting code.
  49.  
  50.     This was developed on SunOS-3.[02] systems, and hasn't been tested on
  51. any other systems.  I believe the format of /usr/adm/acct is BSD specific, so
  52. it probably won't run on Sys5 machines unmodified.
  53.  
  54.     This code is public domain.  Do with it what you want, including
  55. selling it for profit if you can find somebody stupid enough to pay money for
  56. it.  All I ask is that you retain this notice with the code, and keep my name
  57. on it.
  58.  
  59. Roy Smith, System Administrator
  60. Public Health Research Institute
  61. 455 First Avenue, New York, NY 10016
  62.  
  63. UUCP: {allegra,philabs,seismo!cmcl2}!phri!roy
  64. @//E*O*F README//
  65. chmod u=rw,g=r,o=r README
  66.  
  67. echo x - Makefile
  68. sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
  69. #
  70. # Makefile for pracct
  71. #
  72. # $Header: Makefile,v 1.3 86/12/09 17:41:42 roy Exp $
  73. # Copyright 1986 Roy Smith
  74. #
  75. # $Log:    Makefile,v $
  76. # Revision 1.3  86/12/09  17:41:42  roy
  77. # Added rules for yesterday.  Deleted rules for lint.
  78. # Revision 1.2  86/11/29  23:30:18  roy
  79. # Added rule to co source file if needed.
  80. # Added rule for "make lint"
  81. # Revision 1.1  86/11/29  23:12:19  roy
  82. # Initial revision
  83. #
  84.  
  85. CFLAGS = -O
  86.  
  87. programs:    pracct yesterday
  88.  
  89. pracct:        pracct.o
  90.         cc $(CFLAGS) -o pracct pracct.o
  91.  
  92. pracct.o:    pracct.c
  93.         cc $(CFLAGS) -c pracct.c
  94.  
  95. pracct.c:    RCS/pracct.c,v
  96.         co pracct.c
  97.  
  98. yesterday:    yesterday.o
  99.         cc $(CFLAGS) -o yesterday yesterday.o
  100.  
  101. yesterday.o:    yesterday.c
  102.         cc $(CFLAGS) -c yesterday.c
  103.  
  104. yesterday.c:    RCS/yesterday.c,v
  105.         co yesterday.c
  106. @//E*O*F Makefile//
  107. chmod u=rw,g=r,o=r Makefile
  108.  
  109. echo x - pracct.1
  110. sed 's/^@//' > "pracct.1" <<'@//E*O*F pracct.1//'
  111. @.TH DATE 1 "25 Jan 1988"
  112. @.SH NAME
  113. pracct \- print accounting information in human readable form
  114. @.SH SYNOPSIS
  115. @.B pracct
  116. [-v] [-a file] [-f [cvVsSxXeEbBuUgGmitTfF]]
  117. @.SH DESCRIPTION
  118. @.I Pracct
  119. prints out the system accounting file in human-readable form with a minimum
  120. of processing.
  121. This is sort of a RISC version of
  122. @.I /etc/sa.
  123. As the man page says,
  124. @.I sa
  125. has a near google of options; unfortunately, it is rare that it has exactly
  126. the right one.
  127. With
  128. @.I pracct,
  129. you can simply get an ascii dump of the fields of interest and
  130. use
  131. @.I awk
  132. (for example) to calculate whatever statistics you desire.
  133. The options are many:
  134. @.TP
  135. @.B -v
  136. Verbose output; each field is tagged with a (hopefully) descriptive label.
  137. @.TP
  138. @.BI -a " file"
  139. Alternate accounting file, used instead of default
  140. @.I
  141. /usr/adm/acct.
  142. @.TP
  143. @.BI -f " flags"
  144. Fields to print.
  145. Fields are printed in the order specified.
  146. Default is
  147. @.B UcXB.
  148. Fields are separated with spaces, and an attempt is made to ensure that no
  149. spaces appear within fields (i.e. -f F will give `F----' instead of
  150. `F\0\0\0\0').
  151. This may be defeated, however, by command, user, group, or tty names
  152. containing spaces within them.
  153. Also,
  154. @.B
  155. -B
  156. gives a date in ctime format, which has embedded spaces.
  157. The fields are:
  158. @.TP
  159. @.B
  160. c
  161. Command name
  162. @.TP
  163. @.B
  164. v
  165. Numeric user CPU time (seconds)
  166. @.TP
  167. @.B
  168. V
  169. Symbolic user time (DD+HH:MM:SS)
  170. @.TP
  171. @.B
  172. s
  173. Numeric system time (seconds)
  174. @.TP
  175. @.B
  176. S
  177. Symbolic system time (DD+HH:MM:SS)
  178. @.TP
  179. @.B
  180. x
  181. User+system time (seconds)
  182. @.TP
  183. @.B
  184. X
  185. Symbolic user+system time (DD+HH:MM:SS)
  186. @.TP
  187. @.B
  188. e
  189. Numeric elapsed time (seconds)
  190. @.TP
  191. @.B
  192. E
  193. Symbolic elapsed time (DD+HH:MM:SS)
  194. @.TP
  195. @.B
  196. b
  197. Numeric beginning time (seconds)
  198. @.TP
  199. @.B
  200. B
  201. Symbolic beginning time (ctime format)
  202. @.TP
  203. @.B
  204. u
  205. Numeric user I.D.
  206. @.TP
  207. @.B
  208. U
  209. Login name
  210. @.TP
  211. @.B
  212. g
  213. Numeric group I.D.
  214. @.TP
  215. @.B
  216. G
  217. Group name
  218. @.TP
  219. @.B
  220. m
  221. Average memory usage
  222. @.TP
  223. @.B
  224. i
  225. Disk I/O blocks
  226. @.TP
  227. @.B
  228. t
  229. Major/minor device for control tty
  230. @.TP
  231. @.B
  232. T
  233. Name of control tty (/dev/tty??); currently unimplemented
  234. @.TP
  235. @.B
  236. f
  237. Accounting flags in octal
  238. @.TP
  239. @.B
  240. F
  241. Flags as FSCDX
  242. @.SH "SEE ALSO"
  243. sa(8), acct(2)
  244. @.SH AUTHOR
  245. Roy Smith <phri!roy>
  246. @//E*O*F pracct.1//
  247. chmod u=rw,g=r,o=r pracct.1
  248.  
  249. echo x - pracct.c
  250. sed 's/^@//' > "pracct.c" <<'@//E*O*F pracct.c//'
  251. /*
  252.  * Pracct.c -- print out the system accounting file with a minimum of
  253.  * processing.  This is sort of a RISC version of /etc/sa.  As the man page
  254.  * says, sa has a near google of options; unfortunately, it is rare that
  255.  * it has exactly the right one.  With pracct, you can simply get an ascii
  256.  * dump of the fields of interest and let awk do the the rest.
  257.  */
  258.  
  259. # ifndef LINT
  260. static char rcsid[] = "$Header: pracct.c,v 1.7 88/01/25 22:57:16 roy Exp $";
  261. # endif
  262.  
  263. /*
  264.  * $Log:    pracct.c,v $
  265.  * Revision 1.7  88/01/25  22:57:16  roy
  266.  * Removed copyright notice; code placed in public domain.
  267.  * 
  268.  * Revision 1.6  87/11/17  15:10:55  roy
  269.  * Added uid/gid name caches.
  270.  * 
  271.  * Revision 1.5  86/12/02  17:31:43  roy
  272.  * Fixed but with printing ac_comm -- if command name is full
  273.  * length of ac_comm[], it isn't null terminated; we now are
  274.  * careful not to run past this.  Changed symbolic flag format
  275.  * to print '-' instead of ' ' for missing flags to keep the number
  276.  * of fields on an output line constant.
  277.  * 
  278.  * Revision 1.4  86/12/02  14:34:52  roy
  279.  * Added support for -v (verbose) and -a
  280.  * (alternate accounting file) options.
  281.  * 
  282.  * Revision 1.3  86/12/02  00:33:21  roy
  283.  * Added command-line option processing using getopt.
  284.  * 
  285.  * Revision 1.2  86/11/29  23:29:16  roy
  286.  * Fixed rcsid string (capitalized $ H e a d e r : $).
  287.  * Added type casts to keep lint happy.
  288.  * 
  289.  * Revision 1.1  86/11/29  23:07:16  roy
  290.  * Initial revision
  291.  * 
  292.  */
  293.  
  294. # include <sys/types.h>
  295. # include <sys/acct.h>
  296. # include <sys/file.h>
  297. # include <sys/time.h>
  298. # include <pwd.h>
  299. # include <grp.h>
  300. # include <stdio.h>
  301.  
  302. # define ACCT_FILE    "/usr/adm/acct"    /* raw accounting data file */
  303. # define DFLT_FLDS    "UcXB"        /* default fields to print */
  304. # define FIELD_SEP    ' '        /* how to delimit fields on output */
  305. # define GETOPT_FMT    "va:f:"        /* permissible command-line flags */
  306. # define USAGE_MSG    "pracct [-v] [-a file] [-f [cvVsSxXeEbBuUgGmitTfF]]"
  307.  
  308. /*
  309.  * Symbolic names and flags for fields in acct(5) structure
  310.  */
  311. # define COMM        'c'    /* command name */
  312. # define UTIME        'v'    /* numeric user CPU time (seconds) */
  313. # define SYM_UTIME    'V'    /* symbolic user time (DD+HH:MM:SS) */
  314. # define STIME        's'    /* numeric system time (seconds) */
  315. # define SYM_STIME    'S'    /* symbolic system time (DD+HH:MM:SS) */
  316. # define SUMTIME    'x'    /* user+system time (seconds) */
  317. # define SYM_SUMTIME    'X'    /* symbolic user+system time (DD+HH:MM:SS) */
  318. # define ETIME        'e'    /* numeric elapsed time (seconds) */
  319. # define SYM_ETIME    'E'    /* symbolic elapsed time (DD+HH:MM:SS) */
  320. # define BTIME        'b'    /* numeric beginning time (seconds) */
  321. # define SYM_BTIME    'B'    /* symbolic beginning time (ctime format) */
  322. # define UID        'u'    /* numeric user I.D. */
  323. # define SYM_UID    'U'    /* login name */
  324. # define GID        'g'    /* numeric group I.D. */
  325. # define SYM_GID    'G'    /* group name */
  326. # define MEM        'm'    /* average memory usage */
  327. # define IO        'i'    /* disk I/O blocks */
  328. # define TTY        't'    /* major/minor device for control tty */
  329. # define SYM_TTY    'T'    /* name of control tty /dev/tty?? */
  330. # define FLAG        'f'    /* flags in octal */
  331. # define SYM_FLAG    'F'    /* flags as FSCDX */
  332.  
  333. /*
  334.  * Name cache stuff.
  335.  */
  336. # define NC_NUID    256    /* size of uid cache; power of 2 */
  337. # define NC_UIDMASK    0xff    /* log base 2 (NC_NUID) - 1 */
  338. # define NC_NGID    64    /* size of gid cache;  power of 2 */
  339. # define NC_GIDMASK    0x3f    /* log base 2 (NC_NGID) - 1 */
  340.  
  341. struct nc
  342. {
  343.     int nc_n;        /* numeric uid or gid */
  344.     char *nc_name;        /* user or group name; NULL if unused */
  345. } unc[NC_NUID], gnc[NC_NGID];
  346.  
  347. main (argc, argv)
  348. int argc;
  349. char *argv[];
  350. {
  351.     struct acct ac;
  352.     int fd, acsize, first, nbytes, verbose, n, maxcom;
  353.     long utime, stime, etime, sumtime, btime;
  354.     char *fields, *f, *ct, *ctime(), *dhms(), *uid2name(), *gid2name();
  355.     char c, *afile;
  356.     extern int optind;
  357.     extern char *optarg;
  358.  
  359.     fields = DFLT_FLDS;
  360.     verbose = 0;
  361.     afile = ACCT_FILE;
  362.  
  363.     /*
  364.      * figure out the maximum number of characters
  365.      * stored for each command name.
  366.      */
  367.     maxcom = sizeof (ac.ac_comm) / sizeof (*ac.ac_comm);
  368.  
  369.     while ((c = getopt (argc, argv, GETOPT_FMT)) != EOF)
  370.     {
  371.         switch (c)
  372.         {
  373.         case 'f':
  374.             fields = optarg;
  375.             break;
  376.  
  377.         case 'v':
  378.             verbose = 1;
  379.             break;
  380.  
  381.         case 'a':
  382.             afile = optarg;
  383.             break;
  384.  
  385.         case '?':
  386.             fprintf (stderr, "pracct: illegal option (-%c)\n", c);
  387.             fprintf (stderr, "pracct: usage: %s\n", USAGE_MSG);
  388.             exit (1);
  389.  
  390.         default:
  391.             fprintf (stderr, "bad return from getopt (%o)!\n", c);
  392.             abort ();
  393.         }
  394.     }
  395.  
  396.     /*
  397.      * Open accounting file for reading.
  398.      */
  399.     if ((fd = open (afile, O_RDONLY, 0)) < 0)
  400.     {
  401.         perror ("pracct: can't open accounting file");
  402.         exit (1);
  403.     }
  404.  
  405.     /*
  406.      * Flush name cache.
  407.      */
  408.     for (n = 0; n < NC_NUID; n++)
  409.         unc[n].nc_name = NULL;
  410.  
  411.     for (n = 0; n < NC_NGID; n++)
  412.         gnc[n].nc_name = NULL;
  413.  
  414.     /*
  415.      * Read the accounting file, one accounting-structure-worth
  416.      * at a time, until EOF or error.
  417.      */
  418.     acsize = sizeof (ac) / sizeof (char);
  419.     while ((nbytes = read (fd, (char *) &ac, acsize)) == acsize)
  420.     {
  421.         /*
  422.          * Convert from snazzy compressed floating point format to
  423.          * plain old integers.  It's easier to just do all the
  424.          * conversions than to check to see which ones we actually
  425.          * need.  We often want sumtime, so we rarely lose big.
  426.          * This may get changed later if it proves to be important.
  427.          */
  428.         utime = expand (ac.ac_utime);
  429.         stime = expand (ac.ac_stime);
  430.         sumtime = utime + stime;
  431.         etime = expand (ac.ac_etime);
  432.  
  433.         /*
  434.          * Step though the desired fields in the order specified.
  435.          * Insert a field delimiter in front of every field except
  436.          * for the first one.  Warning: fields may have internal
  437.          * blanks, i.e. those in ctime format.
  438.          */
  439.         first = 1;
  440.         for (f = fields; *f != NULL; f++)
  441.         {
  442.             if (first)
  443.                 first = 0;
  444.             else
  445.                 putchar (FIELD_SEP);
  446.  
  447.             switch (*f)
  448.             {
  449.             case COMM:
  450.                 /*
  451.                  * We have to be careful not to print past
  452.                  * the end of the string because the command
  453.                  * name is only null terminated if it is
  454.                  * less than maxcom characters long.
  455.                  */
  456.                 printf ("%-*.*s", maxcom, maxcom, ac.ac_comm);
  457.                 continue;
  458.  
  459.             case UTIME:
  460.                 printf ("%8ld", utime);
  461.                 if (verbose)
  462.                     printf ("user");
  463.                 continue;
  464.  
  465.             case SYM_UTIME:
  466.                 printf ("%11s", dhms (utime));
  467.                 if (verbose)
  468.                     printf ("user");
  469.                 continue;
  470.  
  471.             case STIME:
  472.                 printf ("%8ld", stime);
  473.                 if (verbose)
  474.                     printf ("sys");
  475.                 continue;
  476.  
  477.             case SYM_STIME:
  478.                 printf ("%11s", dhms (stime));
  479.                 if (verbose)
  480.                     printf ("sys");
  481.                 continue;
  482.  
  483.             case SUMTIME:
  484.                 printf ("%8ld", sumtime);
  485.                 if (verbose)
  486.                     printf ("u+s");
  487.                 continue;
  488.  
  489.             case SYM_SUMTIME:
  490.                 printf ("%11s", dhms (sumtime));
  491.                 if (verbose)
  492.                     printf ("u+s");
  493.                 continue;
  494.  
  495.             case ETIME:
  496.                 printf ("%8ld", etime);
  497.                 if (verbose)
  498.                     printf ("real");
  499.                 continue;
  500.  
  501.             case SYM_ETIME:
  502.                 printf ("%11s", dhms (etime));
  503.                 if (verbose)
  504.                     printf ("real");
  505.                 continue;
  506.  
  507.             case BTIME:
  508.                 printf ("%10ld", (long) ac.ac_btime);
  509.                 if (verbose)
  510.                     printf ("begin");
  511.                 continue;
  512.  
  513.             case SYM_BTIME:
  514.                 /*
  515.                  * Beginning time in ctime format.  Ctime
  516.                  * does us a favor and sticks a newline at
  517.                  * the end of the string, which we then have
  518.                  * to be careful not to print.
  519.                  */
  520.                 btime = ac.ac_btime;
  521.                 ct = ctime (&btime);
  522.                 while (*ct != '\n'  && *ct != NULL)
  523.                     putchar (*(ct++));
  524.                 if (verbose)
  525.                     printf (" begin");
  526.                 continue;
  527.  
  528.             case UID:
  529.                 printf ("%5d", ac.ac_uid);
  530.                 if (verbose)
  531.                     printf ("uid");
  532.                 continue;
  533.  
  534.             case SYM_UID:
  535.                 printf ("%-8s", uid2name (ac.ac_uid));
  536.                 continue;
  537.  
  538.             case GID:
  539.                 printf ("%5d", ac.ac_gid);
  540.                 if (verbose)
  541.                     printf ("gid");
  542.                 continue;
  543.  
  544.             case SYM_GID:
  545.                 printf ("%-8s", gid2name (ac.ac_gid));
  546.                 continue;
  547.  
  548.             case MEM:
  549.                 printf ("%5d", ac.ac_mem);
  550.                 if (verbose)
  551.                     printf ("mem");
  552.                 continue;
  553.  
  554.             case IO:
  555.                 printf ("%10ld", (long) expand (ac.ac_io));
  556.                 if (verbose)
  557.                     printf ("io");
  558.                 continue;
  559.  
  560.             case TTY:
  561.                 if (verbose)
  562.                 {
  563.                     printf ("%3d", major (ac.ac_tty));
  564.                     printf ("/%3d", minor (ac.ac_tty));
  565.                 }
  566.                 else
  567.                 {
  568.                     printf ("%3d", major (ac.ac_tty));
  569.                     printf (" %3d", minor (ac.ac_tty));
  570.                 }
  571.                 continue;
  572.  
  573.             case SYM_TTY:
  574.                 printf ("no SYM_TTY yet");
  575.                 continue;
  576.  
  577.             case FLAG:
  578.                 printf ("%03o", ac.ac_flag);
  579.                 continue;
  580.  
  581.             case SYM_FLAG:
  582.                 putchar (ac.ac_flag & AFORK   ? 'F' : '-');
  583.                 putchar (ac.ac_flag & ASU     ? 'S' : '-');
  584.                 putchar (ac.ac_flag & ACOMPAT ? 'C' : '-');
  585.                 putchar (ac.ac_flag & ACORE   ? 'D' : '-');
  586.                 putchar (ac.ac_flag & AXSIG   ? 'X' : '-');
  587.                 continue;
  588.             }
  589.         }
  590.         /*
  591.          * After all the required fields, end the line.
  592.          */
  593.         putchar ('\n');
  594.     }
  595.  
  596.     if (nbytes > 0)
  597.     {
  598.         fprintf (stderr, "pracct: short read on accounting file\n");
  599.         exit (1);
  600.     }
  601.     if (nbytes < 0)
  602.     {
  603.         perror ("pracct: read error on accounting file");
  604.         exit (1);
  605.     }
  606.     exit (0);
  607. }
  608.  
  609. /*
  610.  * Dhms -- convert time in seconds to DD+HH:MM:SS format.  If
  611.  * time is negative or greater than 99+23:59:59, return all ?'s.
  612.  * Result is returned as a fixed-width, null-terminated, static
  613.  * string which is overwritten on each call.
  614.  */
  615. char *dhms (time)
  616. register long time;    /* , no see :-) */
  617. {
  618.     int sec, min, hour, day;
  619.     static char buf[(sizeof ("DD+HH:MM:SS") / sizeof (char)) + 1];
  620.  
  621.     sec = time % 60;
  622.     time = time / 60;
  623.     min = time % 60;
  624.     time = time / 60;
  625.     hour = time % 24;
  626.     time = time / 24;
  627.     day = time;
  628.  
  629.     if (time < 0 || day > 99)
  630.         sprintf (buf, "??+??:??:??");
  631.     else
  632.         sprintf (buf, "%02d+%02d:%02d:%02d", day, hour, min, sec);
  633.  
  634.     return (buf);
  635. }
  636.  
  637. /*
  638.  * Expand -- convert time from compressed floating point format to normal
  639.  * integer.  This routine is based on one in the 4.2BSD /etc/sa.c source
  640.  * file.  Warning: this depends on the format of t being exactly as in
  641.  * 4.2BSD -- 3 bit power-of-8 exponent in high-order bits and 13 bit
  642.  * mantissa in low-order bits.
  643.  */
  644. time_t expand (t)
  645. comp_t t;
  646. {
  647.     register time_t xtime;
  648.     register exp;
  649.  
  650.     /*
  651.      * Get mantissa and exponent.
  652.      */
  653.     xtime = t & 017777;
  654.     exp = (t >> 13) & 07;
  655.  
  656.     /*
  657.      * Compute time = mantissa * 8^exp.
  658.      */
  659.     while (exp != 0)
  660.     {
  661.         exp--;
  662.         xtime <<= 3;
  663.     }
  664.  
  665.     return(xtime);
  666. }
  667.  
  668. /*
  669.  * Uid2name -- convert a numeric user i.d. to a login name by looking it
  670.  * up in /etc/passwd.  The login name is returned as a null-terminated,
  671.  * static string which is overwritten on each call.  A name cache speeds
  672.  * this up many fold (without it, over two-thirds of the user cpu time can
  673.  * be spent here).
  674.  */
  675. char *uid2name (uid)
  676. register int uid;
  677. {
  678.     struct passwd *getpwuid(), *pw;
  679.     register struct nc *entry;
  680.     char *malloc();
  681.     register char *name, *temp;
  682.     register int l;
  683.  
  684.     entry = &unc[uid & NC_UIDMASK];
  685.     if (entry->nc_name == NULL || entry->nc_n != uid)
  686.     {
  687.         entry->nc_n = uid;
  688.         if (entry->nc_name != NULL)
  689.             free (entry->nc_name);
  690.  
  691.         if ((pw = getpwuid (uid)) == NULL)
  692.             name = "???";
  693.         else
  694.             name = pw->pw_name;
  695.  
  696.         l = 0;
  697.         for (temp = name; *temp != NULL; temp++)
  698.             l++;
  699.         if ((entry->nc_name = malloc (l+1)) == NULL)
  700.         {
  701.             fprintf (stderr, "out of memory in uid2name\n");
  702.             exit (1);
  703.         }
  704.         temp = entry->nc_name;
  705.         while ((*(temp++) = *(name++)) != NULL)
  706.             ;
  707.     }
  708.     return (entry->nc_name);
  709. }
  710.  
  711. /*
  712.  * Gid2name -- convert a numeric group i.d. to a group name by
  713.  * looking it up in /etc/group.  Similar to uid2name, q.v.
  714.  */
  715. char *gid2name (gid)
  716. register int gid;
  717. {
  718.     struct group *getgrgid(), *gr;
  719.     register struct nc *entry;
  720.     char *malloc();
  721.     register char *name, *temp;
  722.     register int l;
  723.  
  724.     entry = &gnc[gid & NC_GIDMASK];
  725.     if (entry->nc_name == NULL || entry->nc_n != gid)
  726.     {
  727.         entry->nc_n = gid;
  728.         if (entry->nc_name != NULL)
  729.             free (entry->nc_name);
  730.  
  731.         if ((gr = getgrgid (gid)) == NULL)
  732.             name = "???";
  733.         else
  734.             name = gr->gr_name;
  735.  
  736.         l = 0;
  737.         for (temp = name; *temp != NULL; temp++)
  738.             l++;
  739.         if ((entry->nc_name = malloc (l+1)) == NULL)
  740.         {
  741.             fprintf (stderr, "out of memory in gid2name\n");
  742.             exit (1);
  743.         }
  744.         temp = entry->nc_name;
  745.         while ((*(temp++) = *(name++)) != NULL)
  746.             ;
  747.     }
  748.     return (entry->nc_name);
  749. }
  750. @//E*O*F pracct.c//
  751. chmod u=r,g=r,o=r pracct.c
  752.  
  753. echo x - yesterday.c
  754. sed 's/^@//' > "yesterday.c" <<'@//E*O*F yesterday.c//'
  755. /*
  756.  * Yesterday -- print out yesterday's date.
  757.  */
  758.  
  759. # ifndef LINT
  760. static char rcsid[] = "$Header: yesterday.c,v 1.3 88/01/25 22:57:34 roy Exp $";
  761. # endif
  762.  
  763. /*
  764.  * $Log:    yesterday.c,v $
  765.  * Revision 1.3  88/01/25  22:57:34  roy
  766.  * Removed copyright notice; code placed in public domain.
  767.  * 
  768.  * Revision 1.2  86/12/09  17:40:44  roy
  769.  * Fixed typo (prerror->perror) and added missing arguments to printf.
  770.  * 
  771.  */
  772.  
  773. # include <sys/time.h>
  774. # define SEC_PER_DAY    (60*60*24)    /* Let's see them change this one! */
  775.  
  776. char *months[] =
  777. {
  778.     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  779.     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  780. };
  781.  
  782. char *days[] =
  783. {
  784.     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  785. };
  786.  
  787. main ()
  788. {
  789.     register struct tm *timebuf;
  790.     struct timeval t;
  791.     struct timezone tz;
  792.     long yesterday;
  793.     int status;
  794.  
  795.     status = 0;
  796.     if ((status = gettimeofday (&t, &tz)) < 0)
  797.     {
  798.         perror ("yesterday: gettimeofday failed");
  799.         yesterday = 0;
  800.     }
  801.     else
  802.     {
  803.         yesterday = t.tv_sec - SEC_PER_DAY;
  804.     }
  805.  
  806.     timebuf = localtime (&yesterday);
  807.  
  808.     printf ("%s %s %2d 19%02d\n",    days[timebuf->tm_wday],
  809.                     months[timebuf->tm_mon],
  810.                     timebuf->tm_mday,
  811.                     timebuf->tm_year);
  812.     exit (status);
  813. }
  814. @//E*O*F yesterday.c//
  815. chmod u=r,g=r,o=r yesterday.c
  816.  
  817. echo x - accounting
  818. sed 's/^@//' > "accounting" <<'@//E*O*F accounting//'
  819. #!/bin/sh
  820.  
  821. #
  822. # Generate per-user cpu time stats.  Stats are kept in $acctdir/hostname/date.
  823. # Note that since we do this a few minutes after midnight, date is yesterday,
  824. # not today.  If $acctdir/hostname doesn't exist, we create it.
  825. #
  826.  
  827. #
  828. # Change these to put things in different places
  829. #
  830. pracct=/usr/local/etc/pracct
  831. yesterday=/usr/local/etc/yesterday
  832. acctdir=/usr/local/acct
  833.  
  834. #
  835. # Make a copy of the accounting file, then do the normal daily summary
  836. # and truncate the accounting file.  Accounting is temporarily turned
  837. # off while we snarf a copy of the file and do the statistics to keep
  838. # things in sync.
  839. #
  840. /usr/etc/accton
  841. cp /usr/adm/acct /tmp/acct1.$$
  842. /usr/etc/sa -s > /dev/null
  843. rm /usr/adm/acct
  844. touch /usr/adm/acct
  845. /usr/etc/accton /usr/adm/acct
  846.  
  847. #
  848. # Generate the per-user stats.
  849. #
  850. $pracct -a /tmp/acct1.$$ -f Ux | awk '
  851.         {time[$1] = time[$1] + $2}
  852.         END {for (name in time) print name, time[name]}
  853.     ' > /tmp/acct2.$$
  854.  
  855. rm -f /tmp/acct1.$$
  856.  
  857. #
  858. # Make sure a directory exists for this machine.  If not, try to create it.
  859. # Move daily summary temp file to accounting directory.  This must be done
  860. # as user "acct" so we can write on the common accounting directory.
  861. #
  862. su acct << EOF_SU_ACCT
  863.     if test ! -d $acctdir/`hostname`
  864.     then
  865.         mkdir $acctdir/`hostname`
  866.     fi
  867.     cp /tmp/acct2.$$ $acctdir/`hostname`/`$yesterday | tr ' ' '-'`
  868. EOF_SU_ACCT
  869.  
  870. rm -f /tmp/acct2.$$
  871. @//E*O*F accounting//
  872. chmod u=rwx,g=rx,o=rx accounting
  873.  
  874. echo Inspecting for damage in transit...
  875. temp=/tmp/shar$$; dtemp=/tmp/.shar$$
  876. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  877. cat > $temp <<\!!!
  878.       43     405    2316 README
  879.       40     114     755 Makefile
  880.      135     366    2061 pracct.1
  881.      499    1907   11883 pracct.c
  882.       59     170    1153 yesterday.c
  883.       52     215    1364 accounting
  884.      828    3177   19532 total
  885. !!!
  886. wc  README Makefile pracct.1 pracct.c yesterday.c accounting | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
  887. if [ -s $dtemp ]
  888. then echo "Ouch [diff of wc output]:" ; cat $dtemp
  889. else echo "No problems found."
  890. fi
  891. exit 0
  892. -- 
  893. Roy Smith, {allegra,cmcl2,philabs}!phri!roy
  894. System Administrator, Public Health Research Institute
  895. 455 First Avenue, New York, NY 10016
  896.  
  897.