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
type_str(ea_object_type_t type)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
logmsg(const char * msg,char dir,ea_file_t * f,ea_object_t * obj)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
die(ea_file_t * f,const char * msg)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 */
stop(int sig)123 static void stop(int sig)
124 {
125 exit(2);
126 }
127
128 static int
do_reads(ea_file_t * f,char dir,int sz)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
main(int argc,char ** argv)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 }
236