1 /*-
2 * Public Domain 2014-2018 MongoDB, Inc.
3 * Public Domain 2008-2014 WiredTiger, Inc.
4 *
5 * This is free and unencumbered software released into the public domain.
6 *
7 * Anyone is free to copy, modify, publish, use, compile, sell, or
8 * distribute this software, either in source code form or as a compiled
9 * binary, for any purpose, commercial or non-commercial, and by any
10 * means.
11 *
12 * In jurisdictions that recognize copyright laws, the author or authors
13 * of this software dedicate any and all copyright interest in the
14 * software to the public domain. We make this dedication for the benefit
15 * of the public at large and to the detriment of our heirs and
16 * successors. We intend this dedication to be an overt act of
17 * relinquishment in perpetuity of all present and future rights to this
18 * software under copyright law.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28 #include "test_util.h"
29
30 #ifndef _WIN32
31 #include <sys/wait.h>
32 #endif
33
34 void (*custom_die)(void) = NULL;
35 const char *progname = "program name not set";
36
37 /*
38 * testutil_die --
39 * Report an error and abort.
40 */
41 void
testutil_die(int e,const char * fmt,...)42 testutil_die(int e, const char *fmt, ...)
43 {
44 va_list ap;
45
46 /* Flush output to be sure it doesn't mix with fatal errors. */
47 (void)fflush(stdout);
48 (void)fflush(stderr);
49
50 /* Allow test programs to cleanup on fatal error. */
51 if (custom_die != NULL)
52 (*custom_die)();
53
54 fprintf(stderr, "%s: FAILED", progname);
55 if (fmt != NULL) {
56 fprintf(stderr, ": ");
57 va_start(ap, fmt);
58 vfprintf(stderr, fmt, ap);
59 va_end(ap);
60 }
61 if (e != 0)
62 fprintf(stderr, ": %s", wiredtiger_strerror(e));
63 fprintf(stderr, "\n");
64 fprintf(stderr, "process aborting\n");
65
66 abort();
67 }
68
69 /*
70 * testutil_set_progname --
71 * Set the global program name for error handling.
72 */
73 const char *
testutil_set_progname(char * const * argv)74 testutil_set_progname(char * const *argv)
75 {
76 if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL)
77 progname = argv[0];
78 else
79 ++progname;
80 return (progname);
81 }
82
83 /*
84 * testutil_work_dir_from_path --
85 * Takes a buffer, its size and the intended work directory.
86 * Creates the full intended work directory in buffer.
87 */
88 void
testutil_work_dir_from_path(char * buffer,size_t len,const char * dir)89 testutil_work_dir_from_path(char *buffer, size_t len, const char *dir)
90 {
91 /* If no directory is provided, use the default. */
92 if (dir == NULL)
93 dir = DEFAULT_DIR;
94
95 if (len < strlen(dir) + 1)
96 testutil_die(ENOMEM,
97 "Not enough memory in buffer for directory %s", dir);
98
99 strcpy(buffer, dir);
100 }
101
102 /*
103 * testutil_clean_work_dir --
104 * Remove the work directory.
105 */
106 void
testutil_clean_work_dir(const char * dir)107 testutil_clean_work_dir(const char *dir)
108 {
109 size_t len;
110 int ret;
111 char *buf;
112
113 #ifdef _WIN32
114 /* Additional bytes for the Windows rd command. */
115 len = 2 * strlen(dir) + strlen(RM_COMMAND) +
116 strlen(DIR_EXISTS_COMMAND) + 4;
117 if ((buf = malloc(len)) == NULL)
118 testutil_die(ENOMEM, "Failed to allocate memory");
119
120 testutil_check(__wt_snprintf(
121 buf, len, "%s %s %s %s", DIR_EXISTS_COMMAND, dir, RM_COMMAND, dir));
122 #else
123 len = strlen(dir) + strlen(RM_COMMAND) + 1;
124 if ((buf = malloc(len)) == NULL)
125 testutil_die(ENOMEM, "Failed to allocate memory");
126
127 testutil_check(__wt_snprintf(buf, len, "%s%s", RM_COMMAND, dir));
128 #endif
129
130 if ((ret = system(buf)) != 0 && ret != ENOENT)
131 testutil_die(ret, "%s", buf);
132 free(buf);
133 }
134
135 /*
136 * testutil_make_work_dir --
137 * Delete the existing work directory, then create a new one.
138 */
139 void
testutil_make_work_dir(const char * dir)140 testutil_make_work_dir(const char *dir)
141 {
142 size_t len;
143 char *buf;
144
145 testutil_clean_work_dir(dir);
146
147 /* Additional bytes for the mkdir command */
148 len = strlen(dir) + strlen(MKDIR_COMMAND) + 1;
149 if ((buf = malloc(len)) == NULL)
150 testutil_die(ENOMEM, "Failed to allocate memory");
151
152 /* mkdir shares syntax between Windows and Linux */
153 testutil_check(__wt_snprintf(buf, len, "%s%s", MKDIR_COMMAND, dir));
154 testutil_check(system(buf));
155 free(buf);
156 }
157
158 /*
159 * testutil_progress --
160 * Print a progress message to the progress file.
161 */
162 void
testutil_progress(TEST_OPTS * opts,const char * message)163 testutil_progress(TEST_OPTS *opts, const char *message)
164 {
165 FILE *fp;
166 time_t now;
167
168 if ((fp = fopen(opts->progress_file_name, "a")) == NULL)
169 testutil_die(errno, "fopen");
170 (void)time(&now);
171 fprintf(fp, "[%" PRIuMAX "] %s\n", (uintmax_t)now, message);
172 if (fclose(fp) != 0)
173 testutil_die(errno, "fclose");
174 }
175
176 /*
177 * testutil_cleanup --
178 * Delete the existing work directory and free the options structure.
179 */
180 void
testutil_cleanup(TEST_OPTS * opts)181 testutil_cleanup(TEST_OPTS *opts)
182 {
183 if (opts->conn != NULL)
184 testutil_check(opts->conn->close(opts->conn, NULL));
185
186 if (!opts->preserve)
187 testutil_clean_work_dir(opts->home);
188
189 free(opts->uri);
190 free(opts->progress_file_name);
191 free(opts->home);
192 }
193
194 /*
195 * testutil_is_flag_set --
196 * Return if an environment variable flag is set.
197 */
198 bool
testutil_is_flag_set(const char * flag)199 testutil_is_flag_set(const char *flag)
200 {
201 const char *res;
202 bool enable_long_tests;
203
204 if (__wt_getenv(NULL, flag, &res) != 0 || res == NULL)
205 return (false);
206
207 /*
208 * This is a boolean test. So if the environment variable is set to any
209 * value other than 0, we return success.
210 */
211 enable_long_tests = res[0] != '0';
212
213 free((void *)res);
214
215 return (enable_long_tests);
216 }
217
218 #ifndef _WIN32
219 /*
220 * testutil_sleep_wait --
221 * Wait for a process up to a number of seconds.
222 */
223 void
testutil_sleep_wait(uint32_t seconds,pid_t pid)224 testutil_sleep_wait(uint32_t seconds, pid_t pid)
225 {
226 pid_t got;
227 int status;
228
229 while (seconds > 0) {
230 if ((got = waitpid(pid, &status, WNOHANG|WUNTRACED)) == pid) {
231 if (WIFEXITED(status))
232 testutil_die(EINVAL,
233 "Child process %" PRIu64 " exited early"
234 " with status %d", (uint64_t)pid,
235 WEXITSTATUS(status));
236 if (WIFSIGNALED(status))
237 testutil_die(EINVAL,
238 "Child process %" PRIu64 " terminated "
239 " with signal %d", (uint64_t)pid,
240 WTERMSIG(status));
241 } else if (got == -1)
242 testutil_die(errno, "waitpid");
243
244 --seconds;
245 sleep(1);
246 }
247 }
248 #endif
249
250 /*
251 * dcalloc --
252 * Call calloc, dying on failure.
253 */
254 void *
dcalloc(size_t number,size_t size)255 dcalloc(size_t number, size_t size)
256 {
257 void *p;
258
259 if ((p = calloc(number, size)) != NULL)
260 return (p);
261 testutil_die(errno, "calloc: %" WT_SIZET_FMT "B", number * size);
262 }
263
264 /*
265 * dmalloc --
266 * Call malloc, dying on failure.
267 */
268 void *
dmalloc(size_t len)269 dmalloc(size_t len)
270 {
271 void *p;
272
273 if ((p = malloc(len)) != NULL)
274 return (p);
275 testutil_die(errno, "malloc: %" WT_SIZET_FMT "B", len);
276 }
277
278 /*
279 * drealloc --
280 * Call realloc, dying on failure.
281 */
282 void *
drealloc(void * p,size_t len)283 drealloc(void *p, size_t len)
284 {
285 void *t;
286
287 if ((t = realloc(p, len)) != NULL)
288 return (t);
289 testutil_die(errno, "realloc: %" WT_SIZET_FMT "B", len);
290 }
291
292 /*
293 * dstrdup --
294 * Call strdup, dying on failure.
295 */
296 void *
dstrdup(const void * str)297 dstrdup(const void *str)
298 {
299 char *p;
300
301 if ((p = strdup(str)) != NULL)
302 return (p);
303 testutil_die(errno, "strdup");
304 }
305
306 /*
307 * dstrndup --
308 * Call emulating strndup, dying on failure. Don't use actual strndup here
309 * as it is not supported within MSVC.
310 */
311 void *
dstrndup(const char * str,size_t len)312 dstrndup(const char *str, size_t len)
313 {
314 char *p;
315
316 p = dcalloc(len + 1, sizeof(char));
317 memcpy(p, str, len);
318 return (p);
319 }
320
321 /*
322 * example_setup --
323 * Set the program name, create a home directory for the example programs.
324 */
325 const char *
example_setup(int argc,char * const * argv)326 example_setup(int argc, char * const *argv)
327 {
328 const char *home;
329
330 (void)argc; /* Unused variable */
331
332 (void)testutil_set_progname(argv);
333
334 /*
335 * Create a clean test directory for this run of the test program if the
336 * environment variable isn't already set (as is done by make check).
337 */
338 if ((home = getenv("WIREDTIGER_HOME")) == NULL)
339 home = "WT_HOME";
340 testutil_make_work_dir(home);
341 return (home);
342 }
343