1 /*
   2  * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * This program is part of a stress test for ::Exacct and libexacct.
   5  * See README for details.
   6  */
   7 
   8 /* Turn largefile support on. */
   9 #define _FILE_OFFSET_BITS 64
  10 
  11 #include <stdlib.h>
  12 #include <stdio.h>
  13 #include <strings.h>
  14 #include <signal.h>
  15 #include <errno.h>
  16 #include <fcntl.h>
  17 #include <exacct.h>
  18 #include <exacct_impl.h>
  19 
  20 static char *ea_errstr[] = {
  21         "EXR_OK",
  22         "EXR_SYSCALL_FAIL",
  23         "EXR_CORRUPT_FILE",
  24         "EXR_EOF",
  25         "EXR_NO_CREATOR",
  26         "EXR_INVALID_BUF",
  27         "EXR_NOTSUPP",
  28         "EXR_UNKN_VERSION",
  29         "EXR_INVALID_OBJ",
  30 };
  31 
  32 #define LOGSZ 100
  33 #define LINESZ 81
  34 static char log[LOGSZ][LINESZ];
  35 static int log_op, log_pos;
  36 
  37 static char *type_str(ea_object_type_t type)
  38 {
  39         switch (type & EXT_TYPE_MASK) {
  40         case EXT_NONE:
  41                 return ("NONE");
  42         case EXT_UINT8:
  43                 return ("UINT8");
  44         case EXT_UINT16:
  45                 return ("UINT16");
  46         case EXT_UINT32:
  47                 return ("UINT32");
  48         case EXT_UINT64:
  49                 return ("UINT64");
  50         case EXT_DOUBLE:
  51                 return ("DOUBLE");
  52         case EXT_STRING:
  53                 return ("STRING");
  54         case EXT_EXACCT_OBJECT:
  55                 return ("OBJECT");
  56         case EXT_RAW:
  57                 return ("RAW");
  58         case EXT_GROUP:
  59                 return ("GROUP");
  60         default:
  61                 return ("INVALID");
  62         }
  63 }
  64 
  65 static void logmsg(const char *msg, char dir, ea_file_t *f, ea_object_t *obj)
  66 {
  67         ea_file_impl_t *fi;
  68         off_t pos;
  69         char buf[LINESZ];
  70         char posbuf[10];
  71 
  72         fi = (ea_file_impl_t *)f;
  73         pos = ftello(fi->ef_fp);
  74         log_op++;
  75         if (fi->ef_ndeep < 0) {
  76                 (void) strlcpy(posbuf, "0/0", sizeof (posbuf));
  77         } else {
  78                 (void) snprintf(posbuf, sizeof (posbuf), "%d/%d",
  79                     fi->ef_depth[fi->ef_ndeep].efd_obj + 1,
  80                     fi->ef_depth[fi->ef_ndeep].efd_nobjs);
  81         }
  82         (void) snprintf(log[log_pos], LINESZ,
  83             "%-6d %c off=0x%-5llx depth=%-2d pos=%-7s adv=0x%-3llx %s",
  84             log_op, dir, pos, fi->ef_ndeep, posbuf, fi->ef_advance, msg);
  85         if (obj != NULL) {
  86                 if ((obj->eo_type & EXT_TYPE_MASK) == EXT_GROUP) {
  87                         (void) snprintf(buf, LINESZ, " %s #%d len=%d",
  88                             type_str(obj->eo_catalog),
  89                             obj->eo_catalog & EXD_DATA_MASK,
  90                             obj->eo_group.eg_nobjs);
  91                 } else {
  92                         (void) snprintf(buf, LINESZ, " %s #%d",
  93                             type_str(obj->eo_catalog),
  94                             obj->eo_catalog & EXD_DATA_MASK);
  95                 }
  96                 (void) strlcat(log[log_pos], buf, LINESZ);
  97         }
  98         log_pos = (log_pos + 1) % LOGSZ;
  99 }
 100 
 101 static void die(ea_file_t *f, const char *msg)
 102 {
 103         int i, l;
 104         char buf[LINESZ];
 105 
 106         bzero(buf, sizeof (buf));
 107         if (ea_error() == EXR_SYSCALL_FAIL) {
 108                 (void) strlcat(buf, strerror(errno), sizeof (buf));
 109         }
 110         (void) printf("\nError at offset 0x%lx: %s: %s %s\n",
 111             ftell(((ea_file_impl_t *)f)->ef_fp), msg,
 112             ea_errstr[ea_error()], buf);
 113         (void) printf("Last %d operations:\n", LOGSZ);
 114         for (i = LOGSZ, l = log_pos; i > 0; i--, l = (l + 1) % LOGSZ) {
 115                 if (log[l][0] != '\0') {
 116                         (void) printf("%s\n", log[l]);
 117                 }
 118         }
 119         exit(1);
 120 }
 121 
 122 /* ARGSUSED */
 123 static void stop(int sig)
 124 {
 125         exit(2);
 126 }
 127 
 128 static int
 129 do_reads(ea_file_t *f, char dir, int sz)
 130 {
 131         ea_object_t     obj;
 132         unsigned char   act;
 133 
 134         bzero(&obj, sizeof (obj));
 135         while (sz--) {
 136 
 137                 act = 0x01 << (lrand48() & 0x01);
 138 
 139                 /* If reading backwards */
 140                 if (dir == 'B') {
 141                         logmsg("> ea_previous_object", dir, f, NULL);
 142                         if (ea_previous_object(f, &obj) == EO_ERROR) {
 143                                 if (ea_error() == EXR_EOF) {
 144                                         logmsg("! SOF", dir, f, NULL);
 145                                         return ('F');
 146                                 } else {
 147                                         die(f, "ea_previous_object");
 148                                 }
 149                         }
 150                         logmsg("< ea_previous_object", dir, f, NULL);
 151                 }
 152 
 153                 /* Do a ea_next_object 50% of the time */
 154                 if (act & 0x01) {
 155                         logmsg("> ea_next_object", dir, f, NULL);
 156                         if (ea_next_object(f, &obj) == EO_ERROR) {
 157                                 if (ea_error() == EXR_EOF) {
 158                                         logmsg("! EOF", dir, f, NULL);
 159                                         return (dir == 'F' ? 'B' : 'F');
 160                                 } else {
 161                                         die(f, "ea_next_object");
 162                                 }
 163                         }
 164                         logmsg("< ea_next_object", dir, f, NULL);
 165                 }
 166 
 167                 /* Do a ea_get_object 50% of the time */
 168                 if (act & 0x02) {
 169                         logmsg("> ea_get_object", dir, f, NULL);
 170                         if (ea_get_object(f, &obj) == EO_ERROR) {
 171                                 if (ea_error() == EXR_EOF) {
 172                                         logmsg("! EOF", dir, f, NULL);
 173                                         return (dir == 'F' ? 'B' : 'F');
 174                                 } else {
 175                                         die(f, "ea_get_object");
 176                                 }
 177                         }
 178                         logmsg("< ea_get_object", dir, f, &obj);
 179                         (void) ea_free_item(&obj, EUP_ALLOC);
 180                 }
 181 
 182                 /* If reading backwards */
 183                 if (dir == 'B') {
 184                         logmsg("> ea_previous_object", dir, f, NULL);
 185                         if (ea_previous_object(f, &obj) == EO_ERROR) {
 186                                 if (ea_error() == EXR_EOF) {
 187                                         logmsg("! SOF", dir, f, NULL);
 188                                         return ('F');
 189                                 } else {
 190                                         die(f, "ea_get_object");
 191                                 }
 192                         }
 193                         logmsg("< ea_previous_object", dir, f, NULL);
 194                 }
 195         }
 196         return (' ');
 197 }
 198 
 199 int
 200 main(int argc, char **argv)
 201 {
 202         int             iters, maxsz, sz;
 203         char            dir;
 204         ea_file_t       f;
 205 
 206         (void) signal(SIGINT, stop);
 207         (void) signal(SIGTERM, stop);
 208         (void) signal(SIGHUP, stop);
 209 
 210         if (argc != 4) {
 211                 (void) fprintf(stderr,
 212                     "Usage: randtest <iters> <maxsz> <file>\n");
 213                 return (2);
 214         }
 215         iters = atoi(argv[1]);
 216         maxsz = atoi(argv[2]);
 217         bzero(log, sizeof (log));
 218         log_pos = log_op = 0;
 219 
 220         if (ea_open(&f, argv[3], NULL, EO_HEAD, O_RDONLY, 0) == -1) {
 221                 perror("open failed");
 222                 return (1);
 223         }
 224         srand48((long)(gethrtime() & ~0L));
 225         dir = 'F';
 226         while (iters--) {
 227                 if (dir == ' ') {
 228                         dir = (lrand48() % 2) ? 'F' : 'B';
 229                 }
 230                 sz = (lrand48() % maxsz) + 1;
 231                 dir = do_reads(&f, dir, sz);
 232         }
 233         (void) ea_close(&f);
 234         return (0);
 235 }