2 Unix SMB/CIFS implementation.
3 SMB test generator - load and parse test config
4 Copyright (C) James Myers 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 static struct gentest_context_t *contextP;
26 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
28 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue);
29 static BOOL do_section(const char *pszSectionName);
31 /* prototypes for the special type handlers */
32 static BOOL handle_tests(const char *pszParmValue, char **ptr);
34 static BOOL handle_options(const char *pszParmValue, char **ptr);
35 static BOOL handle_fields(const char *pszParmValue, char **ptr);
37 static struct enum_list enum_command[] = {
39 SMBunlink, "SMBunlink"
41 {SMBclose, "SMBclosex"},
44 static struct enum_list enum_condition[] = {
46 TEST_COND_NEGPROT, "TEST_COND_NEGPROT"
48 {TEST_COND_SESSION, "TEST_COND_SESSION"},
49 {TEST_COND_TCON, "TEST_COND_TCON"},
50 {TEST_COND_FID, "TEST_COND_FID"},
53 static struct enum_list enum_test_type[] = {
55 testTypeConnected, "Connected"
57 {testTypeFilename, "Filename"},
61 static struct enum_list enum_options[] = {
62 {TEST_OPTION_FILE_EXISTS, "FILE_EXISTS"},
63 {TEST_OPTION_FILE_NOT_EXIST, "FILE_NOT_EXIST"},
64 {TEST_OPTION_FILE_HIDDEN, "FILE_HIDDEN"},
65 {TEST_OPTION_FILE_SYSTEM, "FILE_SYSTEM"},
66 {TEST_OPTION_FILE_INVISIBLE, "FILE_INVISIBLE"},
67 {TEST_OPTION_FILE_WILDCARD, "FILE_WILDCARD"},
68 {TEST_OPTION_FID_INVALID, "FID_INVALID"},
69 {TEST_OPTION_FID_VALID, "FID_VALID"},
72 static struct enum_list enum_execute[] = {
73 {(int)gen_execute_unlink, "gen_execute_unlink"},
74 {(int)gen_execute_close, "gen_execute_close"},
77 static struct enum_list enum_verify[] = {
79 (int)gen_verify_unlink, "gen_verify_unlink"
81 {(int)gen_verify_close, "gen_verify_close"},
84 static struct enum_list enum_field_type[] = {
86 testFieldTypeFilename, "Filename"
88 {testFieldTypeFileAttr, "FileAttr"},
89 {testFieldTypeFid, "FID"},
90 {testFieldTypeMtime, "Mtime"},
91 {testFieldTypeTrans2, "Trans2"},
94 static struct enum_list enum_function[] = {
96 (int)test_field_get_filename, "test_field_get_filename"
98 {(int)test_field_get_file_attr, "test_field_get_file_attr"},
102 /* Note: We do not initialise the defaults union - it is not allowed in ANSI C
104 #define GEN_FLAG_GLOBAL 0x0001 /* fundamental options */
105 #define GEN_FLAG_TEST 0x0002 /* test options */
106 #define GEN_FLAG_FIELD 0x0004 /* field options */
116 struct field_test_spec* fields;
132 static struct parm_struct parm_table[] = {
133 {"Base Options", P_SEP, P_SEPARATOR
135 /* global section parameters */
136 {"tests", P_LIST, P_GLOBAL, NULL, handle_tests, NULL, GEN_FLAG_GLOBAL},
138 /* test section parameters */
139 {"Test section", P_SEP, P_SEPARATOR},
140 {"command", P_ENUM, P_LOCAL, &test_section.command, NULL, enum_command, GEN_FLAG_TEST},
141 {"name", P_STRING, P_LOCAL, &test_section.name, NULL, NULL, GEN_FLAG_TEST},
142 {"debug", P_INTEGER, P_LOCAL, &test_section.debug, NULL, NULL, GEN_FLAG_TEST},
143 {"condition", P_ENUM, P_LOCAL, &test_section.condition, NULL, enum_condition, GEN_FLAG_TEST},
144 {"type", P_ENUM, P_LOCAL, &test_section.type, NULL, enum_test_type, GEN_FLAG_TEST},
145 {"options", P_LIST, P_LOCAL, &test_section.options, handle_options, NULL, GEN_FLAG_TEST},
146 {"word count", P_INTEGER, P_LOCAL, &test_section.words, NULL, NULL, GEN_FLAG_TEST},
147 {"fields", P_LIST, P_LOCAL, NULL, handle_fields, NULL, GEN_FLAG_TEST},
148 {"execute", P_ENUM, P_LOCAL, &test_section.execute, NULL, enum_execute, GEN_FLAG_TEST},
149 {"verify", P_ENUM, P_LOCAL, &test_section.verify, NULL, enum_verify, GEN_FLAG_TEST},
151 /* field section parameters */
152 {"Field section", P_SEP, P_SEPARATOR},
153 {"type", P_ENUM, P_LOCAL, &field_section.type, NULL, enum_field_type, GEN_FLAG_FIELD},
154 {"random", P_BOOL, P_LOCAL, &field_section.random, NULL, NULL, GEN_FLAG_FIELD},
155 {"word count", P_INTEGER, P_LOCAL, &field_section.words, NULL, NULL, GEN_FLAG_FIELD},
156 {"function", P_ENUM, P_LOCAL, &field_section.function, NULL, enum_function, GEN_FLAG_FIELD},
158 {NULL, P_BOOL, P_NONE, NULL, NULL, NULL, 0}
161 static BOOL handle_tests(const char *pszParmValue, char **ptr) {
162 contextP->testNames = str_list_make(pszParmValue, NULL);
165 static BOOL handle_options(const char *pszParmValue, char **ptr) {
166 /* convert option names (in enum_options) to flags */
169 str_array = str_list_make(pszParmValue, NULL);
173 for ( j = 0; str_array[j] != NULL; j++) {
174 BOOL optionValid = False;
175 for (i = 0; enum_options[i].name; i++) {
176 if (strequal(str_array[j],
177 enum_options[i].name)) {
178 *(int *)ptr |= enum_options[i].value;
184 DEBUG(0,("handle_options: '%s' invalid option\n",
188 DEBUG(9,("handle_options: %s -> %p\n", pszParmValue, *ptr));
193 static BOOL handle_fields(const char *pszParmValue, char **ptr) {
194 /* create initialized field structures for each name */
197 str_array = str_list_make(pszParmValue, NULL);
201 for ( i = 0; str_array[i] != NULL; i++)
202 test_section.field_count++;
203 /* allocate new field array */
204 test_section.fields = talloc(contextP->mem_ctx,
205 test_section.field_count * sizeof(struct field_test_spec));
206 for ( i = 0; str_array[i] != NULL; i++)
207 test_section.fields[i].name = str_array[i];
212 /***************************************************************************
213 Map a parameter's string representation to something we can use.
214 Returns False if the parameter string is not recognised, else TRUE.
215 ***************************************************************************/
217 static int map_parameter(const char *pszParmName, int section) {
219 unsigned validFlags = 0;
221 if (*pszParmName == '-')
224 /* Check for section-specific parameters.
225 * This allows the same parameter name to be used in
226 * different sections with different meanings.
228 if (section == GEN_SECTION_GLOBAL)
229 validFlags |= GEN_FLAG_GLOBAL;
230 if (section == GEN_SECTION_TEST)
231 validFlags |= GEN_FLAG_TEST;
232 if (section == GEN_SECTION_FIELD)
233 validFlags |= GEN_FLAG_FIELD;
234 for (iIndex = 0; parm_table[iIndex].label; iIndex++)
235 if ((parm_table[iIndex].flags & validFlags) &&
236 strwicmp(parm_table[iIndex].label, pszParmName) == 0)
239 /* Warn only if it isn't parametric option */
240 if (strchr(pszParmName, ':') == NULL)
241 DEBUG(0, ("Unknown parameter encountered: \"%s\"\n", pszParmName));
242 /* We do return 'fail' for parametric options as well because they are
243 stored in different storage
248 /***************************************************************************
249 Set a boolean variable from the text value stored in the passed string.
250 Returns True in success, False if the passed string does not correctly
252 ***************************************************************************/
254 static BOOL set_boolean(BOOL *pb, const char *pszParmValue) {
258 if (strwicmp(pszParmValue, "yes") == 0 ||
259 strwicmp(pszParmValue, "true") == 0 ||
260 strwicmp(pszParmValue, "1") == 0) {
262 } else if (strwicmp(pszParmValue, "no") == 0 ||
263 strwicmp(pszParmValue, "False") == 0 ||
264 strwicmp(pszParmValue, "0") == 0) {
268 ("ERROR: Badly formed boolean in configuration file: \"%s\".\n",
275 /***************************************************************************
277 ***************************************************************************/
279 static BOOL gen_do_parm(struct gentest_context_t *context,
280 const char *pszParmName, const char *pszParmValue) {
282 void *parm_ptr = NULL; /* where we are going to store the result */
283 void *def_ptr = NULL;
285 parmnum = map_parameter(pszParmName, context->iCurrentSectionType);
288 DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
291 DEBUG(19,("gen_do_parm: parm %s is valid\n", pszParmName));
292 def_ptr = parm_table[parmnum].ptr;
294 /* we might point at a test, a field or a global */
295 if (context->iCurrentSectionType == GEN_SECTION_GLOBAL) {
298 if (parm_table[parmnum].class == P_GLOBAL) {
300 ("Global parameter %s found in service section!\n",
307 /* if it is a special case then go ahead */
308 if (parm_table[parmnum].special) {
309 parm_table[parmnum].special(pszParmValue, (char **)parm_ptr);
312 DEBUG(19,("gen_do_parm: parm %s type=%d\n", pszParmName,
313 parm_table[parmnum].type));
315 /* now switch on the type of variable it is */
316 switch (parm_table[parmnum].type) {
318 set_boolean(parm_ptr, pszParmValue);
322 *(int *)parm_ptr = atoi(pszParmValue);
326 *(char ***)parm_ptr = str_list_make(pszParmValue, NULL);
330 parm_ptr = talloc_strdup(context->mem_ctx, pszParmValue);
334 for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
337 parm_table[parmnum].enum_list[i].name)) {
353 /***************************************************************************
355 ***************************************************************************/
357 static BOOL do_parameter(const char *pszParmName, const char *pszParmValue) {
360 DEBUG(4, ("doing parameter %s = %s\n", pszParmName, pszParmValue));
361 bRetval = gen_do_parm(contextP, pszParmName, pszParmValue);
366 /***************************************************************************
367 Check a test for consistency. Return False if the test is in any way
368 incomplete or faulty, else True.
369 ***************************************************************************/
371 static BOOL test_ok(struct gentest_context_t *context,int iTest) {
374 DEBUG(9,("test_ok: index=%d, tests@%p\n", iTest,
376 /* initialize new test section */
377 DEBUG(9,("test_ok: name=%s\n", test_section.name));
378 context->tests[iTest].name = test_section.name;
379 context->tests[iTest].debug = test_section.debug;
380 context->tests[iTest].type = test_section.type;
381 context->tests[iTest].command = test_section.command;
382 context->tests[iTest].initial_conditions = test_section.condition;
383 context->tests[iTest].options = test_section.options;
384 context->tests[iTest].word_count = test_section.words;
385 context->tests[iTest].fields = test_section.fields;
386 context->tests[iTest].field_count = test_section.field_count;
387 context->tests[iTest].execute = test_section.execute;
388 context->tests[iTest].verify = test_section.verify;
390 /* validate test entry */
391 DEBUG(9,("test_ok: validate name=%s\n", test_section.name));
392 if (context->tests[iTest].name[0] == '\0') {
393 DEBUG(0, ("The following message indicates an internal error:\n"));
394 DEBUG(0, ("No test name in test entry.\n"));
398 context->tests[iTest].valid = True;
399 DEBUG(9,("added valid test %s\n",test_section.name));
404 /***************************************************************************
405 Check a field for consistency. Return False if the field is in any way
406 incomplete or faulty, else True.
407 ***************************************************************************/
409 static BOOL field_ok(struct gentest_context_t *context,int iField) {
412 /* setup new field entry */
413 DEBUG(9,("field_ok: index=%d, fields@%p\n", iField,
415 context->fields[iField].name = field_section.name;
416 context->fields[iField].type = field_section.type;
417 context->fields[iField].random = field_section.random;
418 context->fields[iField].word_count = field_section.words;
419 context->fields[iField].function = field_section.function;
422 if (context->fields[iField].name[0] == '\0') {
423 DEBUG(0, ("The following message indicates an internal error:\n"));
424 DEBUG(0, ("No field name in field entry.\n"));
428 context->fields[iField].valid = True;
429 DEBUG(9,("added valid field %s\n",field_section.name));
434 /***************************************************************************
435 Find a test by name. Otherwise works like get_test.
436 ***************************************************************************/
438 static int gettestbyname(struct gentest_context_t *context,
439 const char *pszTestName) {
442 for (iTest = context->iNumTests - 1; iTest >= 0; iTest--)
443 if (context->tests[iTest].valid &&
444 strwicmp(context->tests[iTest].name, pszTestName) == 0) {
450 /***************************************************************************
451 Find a field by name. Otherwise works like get_field.
452 ***************************************************************************/
454 static int getfieldbyname(struct gentest_context_t *context,
455 const char *pszFieldName) {
458 for (iField = context->iNumFields - 1; iField >= 0; iField--)
459 if (context->fields[iField].valid &&
460 strwicmp(context->fields[iField].name, pszFieldName) == 0) {
466 /***************************************************************************
467 Add a new test to the tests array initialising it with the given
469 ***************************************************************************/
471 static int add_a_test(struct gentest_context_t *context,
474 int num_to_alloc = context->iNumTests + 1;
476 DEBUG(3, ("add_a_test: %s at index %d\n", name, num_to_alloc-1));
477 /* it might already exist */
479 i = gettestbyname(context, name);
484 /* find an invalid one */
485 for (i = 0; i < context->iNumTests; i++)
486 if (!context->tests[i].valid)
489 /* if not, then create one */
490 DEBUG(3, ("add_a_test: add %s at index %d\n", name, i));
491 if (i == context->iNumTests) {
492 struct enum_test *tsp;
494 tsp = talloc_realloc(context->mem_ctx, context->tests,
495 sizeof(struct enum_test) *
499 DEBUG(0,("add_a_test: failed to enlarge TestPtrs!\n"));
502 context->tests = tsp;
505 context->iNumTests++;
506 DEBUG(3, ("add_a_test: tests@%p\n", tsp));
508 //free_test(context->tests[i]);
509 /* reinitialize test section fields */
510 test_section.command = 0;
511 test_section.name = talloc_strdup(context->mem_ctx, name);
512 test_section.debug = 0;
513 test_section.condition = 0;
514 test_section.type = 0;
515 test_section.options = 0;
516 test_section.words = 0;
517 test_section.fields = NULL;
518 test_section.field_count = 0;
519 test_section.execute = NULL;
520 test_section.verify = NULL;
521 context->tests[i].valid = False;
524 context->tests[i].name = test_section.name;
525 DEBUG(3, ("add_a_test: added %s at index %d\n", name, i));
528 /***************************************************************************
529 Add a new field to the fields array initialising it with the given
531 ***************************************************************************/
533 static int add_a_field(struct gentest_context_t *context,
536 int num_to_alloc = context->iNumFields + 1;
538 DEBUG(3, ("add_a_field: %s at index %d\n", name, num_to_alloc-1));
539 /* it might already exist */
541 i = getfieldbyname(context, name);
546 /* find an invalid one */
547 for (i = 0; i < context->iNumFields; i++)
548 if (!context->fields[i].valid)
551 /* if not, then create one */
552 DEBUG(3, ("add_a_field: add %s at index %d\n", name, i));
553 if (i == context->iNumFields) {
554 field_test_spec *tsp;
556 tsp = talloc_realloc(context->mem_ctx, context->fields,
557 sizeof(field_test_spec) *
561 DEBUG(0,("add_a_field: failed to enlarge FieldPtrs!\n"));
564 context->fields = tsp;
567 context->iNumFields++;
568 DEBUG(3, ("add_a_field: fields@%p\n", tsp));
571 /* reinitialize field section fields */
572 field_section.name = NULL;
573 field_section.type = 0;
574 field_section.random = False;
575 field_section.words = 0;
576 field_section.function = NULL;
577 context->fields[i].valid = False;
580 field_section.name = talloc_strdup(context->mem_ctx, name);
581 DEBUG(3, ("add_a_field: added %s at index %d\n", name, i));
584 /***************************************************************************
585 Process a new section (test or field).
586 Returns True on success, False on failure.
587 ***************************************************************************/
589 static BOOL do_section(const char *pszSectionName) {
591 BOOL isglobal = (strwicmp(pszSectionName, GLOBAL_NAME) == 0);
592 char *sectionType, *sectionName, *p;
595 DEBUG(4, ("doing section %s\n", pszSectionName));
596 /* if we've just struck a global section, note the fact. */
597 contextP->bInGlobalSection = isglobal;
599 /* check for multiple global sections */
600 if (contextP->bInGlobalSection) {
601 DEBUG(3, ("Processing section \"[%s]\"\n", pszSectionName));
602 contextP->iCurrentSectionType = GEN_SECTION_GLOBAL;
604 } else if (contextP->iCurrentSectionType == GEN_SECTION_GLOBAL) {
605 /* just finished global section */
609 /* parse section name (form <type:name> */
610 sectionType = talloc_strdup(contextP->mem_ctx, pszSectionName);
611 p = strchr_m(sectionType,':');
614 sectionName = talloc_strdup(contextP->mem_ctx, p+1);
616 DEBUG(0, ("Invalid section name %s\n", pszSectionName));
620 /* if we have a current test or field, tidy it up before moving on */
623 if (contextP->iTestIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_TEST)
624 bRetval = test_ok(contextP, contextP->iTestIndex);
625 if (contextP->iFieldIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_FIELD)
626 bRetval = field_ok(contextP, contextP->iFieldIndex);
628 /* determine type of this section */
629 contextP->iCurrentSectionType = GEN_SECTION_INVALID;
630 if (strequal(sectionType, "test"))
631 contextP->iCurrentSectionType = GEN_SECTION_TEST;
632 if (strequal(sectionType, "field"))
633 contextP->iCurrentSectionType = GEN_SECTION_FIELD;
634 if (contextP->iCurrentSectionType == GEN_SECTION_INVALID) {
635 DEBUG(0, ("Invalid section type %s\n", sectionType));
639 /* if all is still well, move to the next record in the tests array */
641 /* We put this here to avoid an odd message order if messages are */
642 /* issued by the post-processing of a previous section. */
643 DEBUG(2, ("Processing section \"[%s]\"\n", pszSectionName));
645 if (contextP->iCurrentSectionType == GEN_SECTION_TEST) {
646 if ((contextP->iTestIndex = add_a_test(contextP, sectionName))
648 DEBUG(0, ("Failed to add a new test\n"));
652 if (contextP->iCurrentSectionType == GEN_SECTION_FIELD) {
653 if ((contextP->iFieldIndex = add_a_field(contextP, sectionName))
655 DEBUG(0, ("Failed to add a new field\n"));
664 /***************************************************************************
665 Load the test configuration from the test config file. Return True on success,
667 ***************************************************************************/
669 BOOL gen_load_config(struct gentest_context_t *contextPTR) {
673 contextP = contextPTR;
674 contextP->param_opt = NULL;
676 n2 = talloc_strdup(contextP->mem_ctx, contextP->config_filename);
678 /* We get sections first, so have to start 'behind' to make up */
679 contextP->iTestIndex = -1;
680 bRetval = pm_process(n2, do_section, do_parameter);
682 /* finish up the last section */
683 DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
685 /* if we have a current test or field, tidy it up before moving on */
686 if (contextP->iTestIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_TEST)
687 bRetval = test_ok(contextP, contextP->iTestIndex);
688 if (contextP->iFieldIndex >= 0 && contextP->iCurrentSectionType == GEN_SECTION_FIELD)
689 bRetval = field_ok(contextP, contextP->iFieldIndex);
691 /* OK, we've parsed the configuration, now we need to match
692 * the field sections to fields required by tests */
696 for (i=0; i<contextP->iNumTests; i++) {
697 DEBUG(19,("gen_load_config: process test %d %s\n",
698 i, contextP->tests[i].name));
699 for (j=0; j<contextP->tests[i].field_count; j++) {
701 DEBUG(19,("gen_load_config: look for field %s\n",
702 contextP->tests[i].fields[j].name));
703 for (k=0; k<contextP->iNumFields; k++) {
704 DEBUG(19,("gen_load_config: compare field %s\n",
705 contextP->fields[k].name));
706 if (strequal(contextP->tests[i].fields[j].name,
707 contextP->fields[k].name)) {
708 /* matching field found */
710 contextP->tests[i].fields[j].type = contextP->fields[k].type;
711 contextP->tests[i].fields[j].word_count = contextP->fields[k].word_count;
712 contextP->tests[i].fields[j].function = contextP->fields[k].function;
713 contextP->tests[i].fields[j].valid = contextP->fields[k].valid;
714 contextP->tests[i].fields[j].random = contextP->fields[k].random;
715 contextP->tests[i].fields[j].parms = contextP->fields[k].parms;
722 contextP->tests[i].fields[j].valid = False;
723 contextP->tests[i].fields[j].function = test_field_get_null;
724 DEBUG(0,("missing field section: %s\n",
725 contextP->tests[i].fields[j].name));