1 : /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
2 :
3 : This program is free software; you can redistribute it and/or modify
4 : it under the terms of the GNU General Public License as published by
5 : the Free Software Foundation; version 2 of the License.
6 :
7 : This program is distributed in the hope that it will be useful,
8 : but WITHOUT ANY WARRANTY; without even the implied warranty of
9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 : GNU General Public License for more details.
11 :
12 : You should have received a copy of the GNU General Public License
13 : along with this program; if not, write to the Free Software
14 : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
15 :
16 : /* Unit test of the control file module of the Maria engine WL#3234 */
17 :
18 : /*
19 : Note that it is not possible to test the durability of the write (can't
20 : pull the plug programmatically :)
21 : */
22 :
23 : #include <my_global.h>
24 : #include <my_sys.h>
25 : #include <tap.h>
26 :
27 : #ifndef WITH_MARIA_STORAGE_ENGINE
28 : /*
29 : If Maria is not compiled in, normally we don't come to building this test.
30 : */
31 : #error "Maria engine is not compiled in, test cannot be built"
32 : #endif
33 :
34 : #include "maria.h"
35 : #include "../../../storage/maria/maria_def.h"
36 : #include <my_getopt.h>
37 :
38 : #define EXTRACT_DEFINITIONS
39 : #include "../ma_control_file.c"
40 : #undef EXTRACT_DEFINITIONS
41 :
42 : char file_name[FN_REFLEN];
43 :
44 : /* The values we'll set and expect the control file module to return */
45 : LSN expect_checkpoint_lsn;
46 : uint32 expect_logno;
47 : TrID expect_max_trid;
48 : uint8 expect_recovery_failures;
49 :
50 : static int delete_file(myf my_flags);
51 : /*
52 : Those are test-specific wrappers around the module's API functions: after
53 : calling the module's API functions they perform checks on the result.
54 : */
55 : static int close_file(void); /* wraps ma_control_file_end */
56 : /* wraps ma_control_file_open_or_create */
57 : static int open_file(void);
58 : /* wraps ma_control_file_write_and_force */
59 : static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
60 : uint8 rec_failures);
61 :
62 : /* Tests */
63 : static int test_one_log_and_recovery_failures(void);
64 : static int test_five_logs_and_max_trid(void);
65 : static int test_3_checkpoints_and_2_logs(void);
66 : static int test_binary_content(void);
67 : static int test_start_stop(void);
68 : static int test_2_open_and_2_close(void);
69 : static int test_bad_magic_string(void);
70 : static int test_bad_checksum(void);
71 : static int test_bad_hchecksum(void);
72 : static int test_future_size(void);
73 : static int test_bad_blocksize(void);
74 : static int test_bad_size(void);
75 :
76 : /* Utility */
77 : static int verify_module_values_match_expected(void);
78 : static int verify_module_values_are_impossible(void);
79 : static void usage(void);
80 : static void get_options(int argc, char *argv[]);
81 :
82 : /*
83 : If "expr" is FALSE, this macro will make the function print a diagnostic
84 : message and immediately return 1.
85 : This is inspired from assert() but does not crash the binary (sometimes we
86 : may want to see how other tests go even if one fails).
87 : RET_ERR means "return error".
88 : */
89 :
90 : #define RET_ERR_UNLESS(expr) \
91 : {if (!(expr)) {diag("line %d: failure: '%s'", __LINE__, #expr); assert(0);return 1;}}
92 :
93 :
94 : /* Used to ignore error messages from ma_control_file_open() */
95 :
96 : static int my_ignore_message(uint error __attribute__((unused)),
97 : const char *str __attribute__((unused)),
98 : myf MyFlags __attribute__((unused)))
99 6 : {
100 6 : DBUG_ENTER("my_message_no_curses");
101 6 : DBUG_PRINT("enter",("message: %s",str));
102 6 : DBUG_RETURN(0);
103 : }
104 :
105 : int (*default_error_handler_hook)(uint my_err, const char *str,
106 : myf MyFlags) = 0;
107 :
108 :
109 : /* like ma_control_file_open(), but without error messages */
110 :
111 : static CONTROL_FILE_ERROR local_ma_control_file_open(void)
112 22 : {
113 : CONTROL_FILE_ERROR error;
114 22 : error_handler_hook= my_ignore_message;
115 22 : error= ma_control_file_open(TRUE, TRUE);
116 22 : error_handler_hook= default_error_handler_hook;
117 22 : return error;
118 : }
119 :
120 :
121 :
122 : int main(int argc,char *argv[])
123 1 : {
124 1 : MY_INIT(argv[0]);
125 1 : my_init();
126 :
127 1 : maria_data_root= (char *)".";
128 1 : default_error_handler_hook= error_handler_hook;
129 :
130 1 : plan(12);
131 :
132 1 : diag("Unit tests for control file");
133 :
134 1 : get_options(argc,argv);
135 :
136 1 : diag("Deleting control file at startup, if there is an old one");
137 1 : RET_ERR_UNLESS(0 == delete_file(0)); /* if fails, can't continue */
138 :
139 1 : diag("Tests of normal conditions");
140 1 : ok(0 == test_one_log_and_recovery_failures(),
141 : "test of creating one log and recording recovery failures");
142 1 : ok(0 == test_five_logs_and_max_trid(),
143 : "test of creating five logs and many transactions");
144 1 : ok(0 == test_3_checkpoints_and_2_logs(),
145 : "test of creating three checkpoints and two logs");
146 1 : ok(0 == test_binary_content(), "test of the binary content of the file");
147 1 : ok(0 == test_start_stop(), "test of multiple starts and stops");
148 1 : diag("Tests of abnormal conditions");
149 1 : ok(0 == test_2_open_and_2_close(),
150 : "test of two open and two close (strange call sequence)");
151 1 : ok(0 == test_bad_magic_string(), "test of bad magic string");
152 1 : ok(0 == test_bad_checksum(), "test of bad checksum");
153 1 : ok(0 == test_bad_hchecksum(), "test of bad hchecksum");
154 1 : ok(0 == test_future_size(), "test of ability to handlr future versions");
155 1 : ok(0 == test_bad_blocksize(), "test of bad blocksize");
156 1 : ok(0 == test_bad_size(), "test of too small/big file");
157 :
158 1 : return exit_status();
159 : }
160 :
161 :
162 : static int delete_file(myf my_flags)
163 3 : {
164 3 : RET_ERR_UNLESS(fn_format(file_name, CONTROL_FILE_BASE_NAME,
165 : maria_data_root, "", MYF(MY_WME)) != NullS);
166 : /*
167 : Maybe file does not exist, ignore error.
168 : The error will however be printed on stderr.
169 : */
170 3 : my_delete(file_name, my_flags);
171 3 : expect_checkpoint_lsn= LSN_IMPOSSIBLE;
172 3 : expect_logno= FILENO_IMPOSSIBLE;
173 3 : expect_max_trid= expect_recovery_failures= 0;
174 :
175 3 : return 0;
176 : }
177 :
178 : /*
179 : Verifies that global values last_checkpoint_lsn, last_logno,
180 : max_trid_in_control_file (belonging to the module) match what we expect.
181 : */
182 : static int verify_module_values_match_expected(void)
183 28 : {
184 28 : RET_ERR_UNLESS(last_logno == expect_logno);
185 28 : RET_ERR_UNLESS(last_checkpoint_lsn == expect_checkpoint_lsn);
186 28 : RET_ERR_UNLESS(max_trid_in_control_file == expect_max_trid);
187 28 : RET_ERR_UNLESS(recovery_failures == expect_recovery_failures);
188 28 : return 0;
189 : }
190 :
191 :
192 : /*
193 : Verifies that global values last_checkpoint_lsn and last_logno (belonging
194 : to the module) are impossible (this is used when the file has been closed).
195 : */
196 : static int verify_module_values_are_impossible(void)
197 16 : {
198 16 : RET_ERR_UNLESS(last_logno == FILENO_IMPOSSIBLE);
199 16 : RET_ERR_UNLESS(last_checkpoint_lsn == LSN_IMPOSSIBLE);
200 16 : RET_ERR_UNLESS(max_trid_in_control_file == 0);
201 16 : return 0;
202 : }
203 :
204 :
205 : static int close_file(void)
206 16 : {
207 : /* Simulate shutdown */
208 16 : ma_control_file_end();
209 : /* Verify amnesia */
210 16 : RET_ERR_UNLESS(verify_module_values_are_impossible() == 0);
211 16 : return 0;
212 : }
213 :
214 : static int open_file(void)
215 16 : {
216 16 : RET_ERR_UNLESS(local_ma_control_file_open() == CONTROL_FILE_OK);
217 : /* Check that the module reports expected information */
218 16 : RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
219 16 : return 0;
220 : }
221 :
222 : static int write_file(LSN checkpoint_lsn, uint32 logno, TrID trid,
223 : uint8 rec_failures)
224 12 : {
225 12 : RET_ERR_UNLESS(ma_control_file_write_and_force(checkpoint_lsn, logno, trid,
226 : rec_failures)
227 : == 0);
228 : /* Check that the module reports expected information */
229 12 : RET_ERR_UNLESS(verify_module_values_match_expected() == 0);
230 12 : return 0;
231 : }
232 :
233 : static int test_one_log_and_recovery_failures(void)
234 1 : {
235 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
236 1 : expect_logno= 123;
237 1 : RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
238 : max_trid_in_control_file,
239 : recovery_failures) == 0);
240 1 : expect_recovery_failures= 158;
241 1 : RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
242 : max_trid_in_control_file,
243 : expect_recovery_failures) == 0);
244 1 : RET_ERR_UNLESS(close_file() == 0);
245 1 : return 0;
246 : }
247 :
248 : static int test_five_logs_and_max_trid(void)
249 1 : {
250 : uint i;
251 :
252 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
253 1 : expect_logno= 100;
254 1 : expect_max_trid= ULL(14111978111);
255 6 : for (i= 0; i<5; i++)
256 : {
257 5 : expect_logno*= 3;
258 5 : RET_ERR_UNLESS(write_file(last_checkpoint_lsn, expect_logno,
259 : expect_max_trid,
260 : recovery_failures) == 0);
261 : }
262 1 : RET_ERR_UNLESS(close_file() == 0);
263 1 : return 0;
264 : }
265 :
266 : static int test_3_checkpoints_and_2_logs(void)
267 1 : {
268 : /*
269 : Simulate one checkpoint, one log creation, two checkpoints, one
270 : log creation.
271 : */
272 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
273 1 : expect_checkpoint_lsn= MAKE_LSN(5, 10000);
274 1 : RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
275 : max_trid_in_control_file,
276 : recovery_failures) == 0);
277 :
278 1 : expect_logno= 17;
279 1 : RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
280 : max_trid_in_control_file,
281 : recovery_failures) == 0);
282 :
283 1 : expect_checkpoint_lsn= MAKE_LSN(17, 20000);
284 1 : RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
285 : max_trid_in_control_file,
286 : recovery_failures) == 0);
287 :
288 1 : expect_checkpoint_lsn= MAKE_LSN(17, 45000);
289 1 : RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
290 : max_trid_in_control_file,
291 : recovery_failures) == 0);
292 :
293 1 : expect_logno= 19;
294 1 : RET_ERR_UNLESS(write_file(expect_checkpoint_lsn, expect_logno,
295 : max_trid_in_control_file,
296 : recovery_failures) == 0);
297 1 : RET_ERR_UNLESS(close_file() == 0);
298 1 : return 0;
299 : }
300 :
301 : static int test_binary_content(void)
302 1 : {
303 : uint i;
304 : int fd;
305 :
306 : /*
307 : TEST4: actually check by ourselves the content of the file.
308 : Note that constants (offsets) are hard-coded here, precisely to prevent
309 : someone from changing them in the control file module and breaking
310 : backward-compatibility.
311 : TODO: when we reach the format-freeze state, we may even just do a
312 : comparison with a raw binary string, to not depend on any uint4korr
313 : future change/breakage.
314 : */
315 :
316 : uchar buffer[45];
317 1 : RET_ERR_UNLESS((fd= my_open(file_name,
318 : O_BINARY | O_RDWR,
319 : MYF(MY_WME))) >= 0);
320 1 : RET_ERR_UNLESS(my_read(fd, buffer, 45, MYF(MY_FNABP | MY_WME)) == 0);
321 1 : RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
322 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
323 1 : i= uint3korr(buffer + 34 );
324 1 : RET_ERR_UNLESS(i == LSN_FILE_NO(last_checkpoint_lsn));
325 1 : i= uint4korr(buffer + 37);
326 1 : RET_ERR_UNLESS(i == LSN_OFFSET(last_checkpoint_lsn));
327 1 : i= uint4korr(buffer + 41);
328 1 : RET_ERR_UNLESS(i == last_logno);
329 1 : RET_ERR_UNLESS(close_file() == 0);
330 1 : return 0;
331 : }
332 :
333 : static int test_start_stop(void)
334 1 : {
335 : /* TEST5: Simulate start/nothing/stop/start/nothing/stop/start */
336 :
337 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
338 1 : RET_ERR_UNLESS(close_file() == 0);
339 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
340 1 : RET_ERR_UNLESS(close_file() == 0);
341 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
342 1 : RET_ERR_UNLESS(close_file() == 0);
343 1 : return 0;
344 : }
345 :
346 : static int test_2_open_and_2_close(void)
347 1 : {
348 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
349 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
350 1 : RET_ERR_UNLESS(close_file() == 0);
351 1 : RET_ERR_UNLESS(close_file() == 0);
352 1 : return 0;
353 : }
354 :
355 :
356 : static int test_bad_magic_string(void)
357 1 : {
358 : uchar buffer[4];
359 : int fd;
360 :
361 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
362 1 : RET_ERR_UNLESS(close_file() == 0);
363 :
364 : /* Corrupt magic string */
365 1 : RET_ERR_UNLESS((fd= my_open(file_name,
366 : O_BINARY | O_RDWR,
367 : MYF(MY_WME))) >= 0);
368 1 : RET_ERR_UNLESS(my_pread(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0);
369 1 : RET_ERR_UNLESS(my_pwrite(fd, (const uchar *)"papa", 4, 0,
370 : MYF(MY_FNABP | MY_WME)) == 0);
371 :
372 : /* Check that control file module sees the problem */
373 1 : RET_ERR_UNLESS(local_ma_control_file_open() ==
374 : CONTROL_FILE_BAD_MAGIC_STRING);
375 : /* Restore magic string */
376 1 : RET_ERR_UNLESS(my_pwrite(fd, buffer, 4, 0, MYF(MY_FNABP | MY_WME)) == 0);
377 1 : RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
378 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
379 1 : RET_ERR_UNLESS(close_file() == 0);
380 1 : return 0;
381 : }
382 :
383 : static int test_bad_checksum(void)
384 1 : {
385 : uchar buffer[4];
386 : int fd;
387 :
388 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
389 1 : RET_ERR_UNLESS(close_file() == 0);
390 :
391 : /* Corrupt checksum */
392 1 : RET_ERR_UNLESS((fd= my_open(file_name,
393 : O_BINARY | O_RDWR,
394 : MYF(MY_WME))) >= 0);
395 1 : RET_ERR_UNLESS(my_pread(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
396 1 : buffer[0]+= 3; /* mangle checksum */
397 1 : RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
398 : /* Check that control file module sees the problem */
399 1 : RET_ERR_UNLESS(local_ma_control_file_open() ==
400 : CONTROL_FILE_BAD_CHECKSUM);
401 : /* Restore checksum */
402 1 : buffer[0]-= 3;
403 1 : RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 30, MYF(MY_FNABP | MY_WME)) == 0);
404 1 : RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
405 :
406 1 : return 0;
407 : }
408 :
409 :
410 : static int test_bad_blocksize(void)
411 1 : {
412 1 : maria_block_size<<= 1;
413 : /* Check that control file module sees the problem */
414 1 : RET_ERR_UNLESS(local_ma_control_file_open() ==
415 : CONTROL_FILE_WRONG_BLOCKSIZE);
416 : /* Restore blocksize */
417 1 : maria_block_size>>= 1;
418 :
419 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
420 1 : RET_ERR_UNLESS(close_file() == 0);
421 1 : return 0;
422 : }
423 :
424 :
425 : static int test_future_size(void)
426 1 : {
427 : /*
428 : Here we check ability to add fields only so we can use
429 : defined constants
430 : */
431 : uint32 sum;
432 : int fd;
433 : uchar buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 2];
434 1 : RET_ERR_UNLESS((fd= my_open(file_name,
435 : O_BINARY | O_RDWR,
436 : MYF(MY_WME))) >= 0);
437 1 : RET_ERR_UNLESS(my_read(fd, buffer,
438 : CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE,
439 : MYF(MY_FNABP | MY_WME)) == 0);
440 1 : RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
441 : /* "add" new field of 1 byte (value 1) to header and variable part */
442 1 : memmove(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1,
443 : buffer + CF_CREATE_TIME_TOTAL_SIZE,
444 : CF_CHANGEABLE_TOTAL_SIZE);
445 1 : buffer[CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE]= '\1';
446 1 : buffer[CF_CREATE_TIME_TOTAL_SIZE + CF_CHANGEABLE_TOTAL_SIZE + 1]= '\1';
447 : /* fix lengths */
448 1 : int2store(buffer + CF_CREATE_TIME_SIZE_OFFSET, CF_CREATE_TIME_TOTAL_SIZE + 1);
449 1 : int2store(buffer + CF_CHANGEABLE_SIZE_OFFSET, CF_CHANGEABLE_TOTAL_SIZE + 1);
450 : /* recalculete checksums */
451 1 : sum= (uint32) my_checksum(0, buffer, CF_CREATE_TIME_TOTAL_SIZE -
452 : CF_CHECKSUM_SIZE + 1);
453 1 : int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1, sum);
454 1 : sum= (uint32) my_checksum(0, buffer + CF_CREATE_TIME_TOTAL_SIZE + 1 +
455 : CF_CHECKSUM_SIZE,
456 : CF_CHANGEABLE_TOTAL_SIZE - CF_CHECKSUM_SIZE + 1);
457 1 : int4store(buffer + CF_CREATE_TIME_TOTAL_SIZE + 1, sum);
458 : /* write new file and check it */
459 1 : RET_ERR_UNLESS((fd= my_open(file_name,
460 : O_BINARY | O_RDWR,
461 : MYF(MY_WME))) >= 0);
462 1 : RET_ERR_UNLESS(my_pwrite(fd, buffer,
463 : CF_CREATE_TIME_TOTAL_SIZE +
464 : CF_CHANGEABLE_TOTAL_SIZE + 2,
465 : 0, MYF(MY_FNABP | MY_WME)) == 0);
466 1 : RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
467 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
468 1 : RET_ERR_UNLESS(close_file() == 0);
469 :
470 1 : return(0);
471 : }
472 :
473 : static int test_bad_hchecksum(void)
474 1 : {
475 : uchar buffer[4];
476 : int fd;
477 :
478 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
479 1 : RET_ERR_UNLESS(close_file() == 0);
480 :
481 : /* Corrupt checksum */
482 1 : RET_ERR_UNLESS((fd= my_open(file_name,
483 : O_BINARY | O_RDWR,
484 : MYF(MY_WME))) >= 0);
485 1 : RET_ERR_UNLESS(my_pread(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
486 1 : buffer[0]+= 3; /* mangle checksum */
487 1 : RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
488 : /* Check that control file module sees the problem */
489 1 : RET_ERR_UNLESS(local_ma_control_file_open() ==
490 : CONTROL_FILE_BAD_HEAD_CHECKSUM);
491 : /* Restore checksum */
492 1 : buffer[0]-= 3;
493 1 : RET_ERR_UNLESS(my_pwrite(fd, buffer, 1, 26, MYF(MY_FNABP | MY_WME)) == 0);
494 1 : RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
495 :
496 1 : return 0;
497 : }
498 :
499 :
500 : static int test_bad_size(void)
501 1 : {
502 : uchar buffer[]=
503 1 : "123456789012345678901234567890123456789012345678901234567890123456";
504 : int fd, i;
505 :
506 : /* A too short file */
507 1 : RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0);
508 1 : RET_ERR_UNLESS((fd= my_open(file_name,
509 : O_BINARY | O_RDWR | O_CREAT,
510 : MYF(MY_WME))) >= 0);
511 1 : RET_ERR_UNLESS(my_write(fd, buffer, 10, MYF(MY_FNABP | MY_WME)) == 0);
512 : /* Check that control file module sees the problem */
513 1 : RET_ERR_UNLESS(local_ma_control_file_open() ==
514 : CONTROL_FILE_TOO_SMALL);
515 9 : for (i= 0; i < 8; i++)
516 : {
517 8 : RET_ERR_UNLESS(my_write(fd, buffer, 66, MYF(MY_FNABP | MY_WME)) == 0);
518 : }
519 : /* Check that control file module sees the problem */
520 1 : RET_ERR_UNLESS(local_ma_control_file_open() ==
521 : CONTROL_FILE_TOO_BIG);
522 1 : RET_ERR_UNLESS(my_close(fd, MYF(MY_WME)) == 0);
523 :
524 : /* Leave a correct control file */
525 1 : RET_ERR_UNLESS(delete_file(MYF(MY_WME)) == 0);
526 1 : RET_ERR_UNLESS(open_file() == CONTROL_FILE_OK);
527 1 : RET_ERR_UNLESS(close_file() == 0);
528 :
529 1 : return 0;
530 : }
531 :
532 :
533 : static struct my_option my_long_options[] =
534 : {
535 : #ifndef DBUG_OFF
536 : {"debug", '#', "Debug log.",
537 : 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
538 : #endif
539 : {"help", '?', "Display help and exit",
540 : 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
541 : {"version", 'V', "Print version number and exit",
542 : 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
543 : { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
544 : };
545 :
546 :
547 : static void version(void)
548 0 : {
549 0 : printf("ma_control_file_test: unit test for the control file "
550 : "module of the Maria storage engine. Ver 1.0 \n");
551 : }
552 :
553 : static my_bool
554 : get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
555 : char *argument __attribute__((unused)))
556 0 : {
557 0 : switch(optid) {
558 : case 'V':
559 0 : version();
560 0 : exit(0);
561 : case '#':
562 0 : DBUG_PUSH (argument);
563 0 : break;
564 : case '?':
565 0 : version();
566 0 : usage();
567 0 : exit(0);
568 : }
569 0 : return 0;
570 : }
571 :
572 :
573 : /* Read options */
574 :
575 : static void get_options(int argc, char *argv[])
576 1 : {
577 : int ho_error;
578 :
579 1 : if ((ho_error=handle_options(&argc, &argv, my_long_options,
580 : get_one_option)))
581 0 : exit(ho_error);
582 :
583 : return;
584 : } /* get options */
585 :
586 :
587 : static void usage(void)
588 0 : {
589 0 : printf("Usage: %s [options]\n\n", my_progname);
590 0 : my_print_help(my_long_options);
591 0 : my_print_variables(my_long_options);
592 : }
|