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 }