1    	/* ----------------------------------------------------------------------------
2    	 * Copyright CEA/DAM/DIF  (2007)
3    	 * contributeur : Thomas LEIBOVICI  thomas.leibovici@cea.fr
4    	 *
5    	 * This program is free software; you can redistribute it and/or
6    	 * modify it under the terms of the GNU Lesser General Public License
7    	 * as published by the Free Software Foundation; either version 3 of
8    	 * the License, or (at your option) any later version.
9    	 *
10   	 * This program is distributed in the hope that it will be useful, but
11   	 * WITHOUT ANY WARRANTY; without even the implied warranty of
12   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   	 * Lesser General Public License for more details.
14   	 *
15   	 * You should have received a copy of the GNU Lesser General Public
16   	 * License along with this library; if not, write to the Free Software
17   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18   	 * 02110-1301 USA
19   	 *
20   	 * ---------------------------------------
21   	 */
22   	#include "config.h"
23   	#include <stdio.h>
24   	#include <errno.h>
25   	#include <assert.h>
26   	#if HAVE_STRING_H
27   	#include <string.h>
28   	#endif
29   	#include <sys/types.h>
30   	#include <ctype.h>
31   	#include <arpa/inet.h>
32   	#include <netdb.h>
33   	#include <sys/socket.h>
34   	#include "config_parsing.h"
35   	#include "analyse.h"
36   	#include "abstract_mem.h"
37   	#include "conf_yacc.h"
38   	#include "log.h"
39   	#include "fsal_convert.h"
40   	
41   	/* config_ParseFile:
42   	 * Reads the content of a configuration file and
43   	 * stores it in a memory structure.
44   	 */
45   	
46   	config_file_t config_ParseFile(char *file_path,
47   				       struct config_error_type *err_type)
48   	{
49   		struct parser_state st;
50   		struct config_root *root;
51   		int rc;
52   	
53   		glist_init(&all_blocks);
54   		memset(&st, 0, sizeof(struct parser_state));
55   		st.err_type = err_type;
56   		rc = ganeshun_yy_init_parser(file_path, &st);
57   		if (rc) {
58   			return NULL;
59   		}
60   		rc = ganesha_yyparse(&st);
61   		root = st.root_node;
62   		if (rc != 0)
63   			config_proc_error(root, err_type,
64   					  (rc == 1
65   					   ? "Configuration syntax errors found"
66   					   : "Configuration parse ran out of memory"));
67   	#ifdef DUMP_PARSE_TREE
68   		print_parse_tree(stderr, root);
69   	#endif
70   		ganeshun_yy_cleanup_parser(&st);
71   		return (config_file_t)root;
72   	}
73   	
74   	/**
75   	 *  Return the first node in the global config block list with
76   	 *  name == block_name
77   	 */
78   	void *config_GetBlockNode(const char *block_name)
79   	{
80   		struct glist_head *glh;
81   		struct config_node *node;
82   	
83   		glist_for_each(glh, &all_blocks) {
84   			node = glist_entry(glh, struct config_node, blocks);
85   			if (!strcasecmp(node->u.nterm.name, block_name)) {
86   				return node;
87   			}
88   		}
89   		return NULL;
90   	}
91   	
92   	/**
93   	 * config_Print:
94   	 * Print the content of the syntax tree
95   	 * to a file.
96   	 */
97   	void config_Print(FILE * output, config_file_t config)
98   	{
99   		print_parse_tree(output, (struct config_root *)config);
100  	}
101  	
102  	/**
103  	 * config_Free:
104  	 * Free the memory structure that store the configuration.
105  	 */
106  	
107  	void config_Free(config_file_t config)
108  	{
109  		if (config != NULL)
110  			free_parse_tree((struct config_root *)config);
111  		return;
112  	
113  	}
114  	
115  	/**
116  	 * @brief Return an error string constructed from an err_type
117  	 *
118  	 * The string is constructed in allocate memory that must be freed
119  	 * by the caller.
120  	 *
121  	 * @param err_type [IN] the err_type struct in question.
122  	 *
123  	 * @return a NULL term'd string or NULL on failure.
124  	 */
125  	
126  	char *err_type_str(struct config_error_type *err_type)
127  	{
128  		char *buf = NULL;
129  		size_t bufsize;
130  		FILE *fp;
131  	
132  		if (config_error_no_error(err_type))
133  			return gsh_strdup("(no errors)");
134  		fp = open_memstream(&buf, &bufsize);
135  		if (fp == NULL) {
136  			LogCrit(COMPONENT_CONFIG,
137  				"Could not open memstream for err_type string");
138  			return NULL;
139  		}
140  		fputc('(', fp);
141  		if (err_type->scan)
142  			fputs("token scan, ", fp);
143  		if (err_type->parse)
144  			fputs("parser rule, ", fp);
145  		if (err_type->init)
146  			fputs("block init, ", fp);
147  		if (err_type->fsal)
148  			fputs("fsal load, ", fp);
149  		if (err_type->export_)
150  			fputs("export create, ", fp);
151  		if (err_type->resource)
152  			fputs("resource alloc, ", fp);
153  		if (err_type->unique)
154  			fputs("not unique param, ", fp);
155  		if (err_type->invalid)
156  			fputs("invalid param value, ", fp);
157  		if (err_type->missing)
158  			fputs("missing mandatory param, ", fp);
159  		if (err_type->validate)
160  			fputs("block validation, ", fp);
161  		if (err_type->exists)
162  			fputs("block exists, ", fp);
163  		if (err_type->internal)
164  			fputs("internal error, ", fp);
165  		if (err_type->bogus)
166  			fputs("unknown param, ", fp);
167  		if (err_type->deprecated)
168  			fputs("deprecated param, ", fp);
169  		if (ferror(fp))
170  			LogCrit(COMPONENT_CONFIG,
171  				"file error while constructing err_type string");
172  		fclose(fp);
173  		if (buf == NULL) {
174  			LogCrit(COMPONENT_CONFIG,
175  				"close of memstream for err_type string failed");
176  			return NULL;
177  		}
178  		/* each of the above strings (had better) have ', ' at the end! */
179  		if (buf[strlen(buf) -1] == ' ') {
180  			buf[bufsize - 2] = ')';
181  			buf[bufsize - 1] = '\0';
182  		}
183  		return buf;
184  	}
185  	
186  	bool init_error_type(struct config_error_type *err_type)
187  	{
188  		memset(err_type, 0, sizeof(struct config_error_type));
189  		err_type->fp = open_memstream(&err_type->diag_buf,
190  					     &err_type->diag_buf_size);
191  		if (err_type->fp == NULL) {
192  			LogCrit(COMPONENT_MAIN,
193  				 "Could not open memory stream for parser errors");
194  			return false;
195  		}
196  		return true;
197  	}
198  	
199  	/**
200  	 * @brief Log an error to the parse error stream
201  	 *
202  	 * cnode is void * because struct config_node is hidden outside parse code
203  	 * and we can report errors in fsal_manager.c etc.
204  	 */
205  	
206  	void config_proc_error(void *cnode,
207  			       struct config_error_type *err_type,
208  			       char *format, ...)
209  	{
210  		struct config_node *node = cnode;
211  		FILE *fp = err_type->fp;
212  		char *filename = "<unknown file>";
213  		int linenumber = 0;
214  		va_list arguments;
215  	
216  		if (fp == NULL)
217  			return;  /* no stream, no message */
218  		if (node != NULL && node->filename != NULL) {
219  			filename = node->filename;
220  			linenumber = node->linenumber;
221  		}
222  		va_start(arguments, format);
223  		config_error(fp, filename, linenumber,
224  			     format, arguments);
225  		va_end(arguments);
226  	}
227  	void config_errs_to_log(char *err, void *dest,
228  				struct config_error_type *err_type)
229  	{
230  		log_levels_t log_level;
231  	
232  		if (config_error_is_fatal(err_type) ||
233  		    config_error_is_crit(err_type))
234  			log_level = NIV_CRIT;
235  		else if (config_error_is_harmless(err_type))
236  			log_level = NIV_WARN;
237  		else
238  			log_level = NIV_EVENT;
239  		DisplayLogComponentLevel(COMPONENT_CONFIG,
240  					 __FILE__, __LINE__, (char *)__func__,
241  					  log_level, "%s", err);
242  	}
243  	
244  	void report_config_errors(struct config_error_type *err_type, void *dest,
245  				  void (*logger)(char *msg, void *dest,
246  						 struct config_error_type *err_type))
247  	{
248  		char *msgp, *cp;
249  	
250  		if (err_type->fp == NULL)
251  			return;
252  		fclose(err_type->fp);
253  		err_type->fp = NULL;
254  		msgp = err_type->diag_buf;
255  		if (msgp == NULL)
256  			return;
257  		while (*msgp != '\0') {
258  			cp = index(msgp, '\f');
259  			if (cp != NULL) {
260  				*cp++ = '\0';
261  				logger(msgp, dest, err_type);
262  				msgp = cp;
263  			} else {
264  				logger(msgp, dest, err_type);
265  				break;
266  			}
267  		}
268  		gsh_free(err_type->diag_buf);
269  		err_type->diag_buf = NULL;
270  	}
271  	
272  	static bool convert_bool(struct config_node *node,
273  				 bool *b,
274  				 struct config_error_type *err_type)
275  	{
276  		if (node->u.term.type == TERM_TRUE)
277  			*b = true;
278  		else if (node->u.term.type == TERM_FALSE)
279  			*b = false;
280  		else {
281  			config_proc_error(node, err_type,
282  			 "Expected boolean (true/false) got (%s)",
283  			 node->u.term.varvalue);
284  			err_type->errors++;
285  			err_type->invalid = true;
286  			return false;
287  		}
288  		return true;
289  	}
290  	
291  	static bool convert_number(struct config_node *node,
292  				   struct config_item *item,
293  				   uint64_t *num,
294  				   struct config_error_type *err_type)
295  	{
296  		uint64_t val, mask, min, max;
297  		int64_t sval, smin, smax;
298  		char *endptr;
299  		int base;
300  		bool signed_int = false;
301  	
302  		if (node->type != TYPE_TERM) {
303  			config_proc_error(node, err_type,
304  					  "Expected a number, got a %s",
305  					  (node->type == TYPE_ROOT
306  					   ? "root node"
307  					   : (node->type == TYPE_BLOCK
308  					      ? "block" : "statement")));
309  			goto errout;
310  		} else if (node->u.term.type == TERM_DECNUM) {
311  			base = 10;
312  		} else if (node->u.term.type == TERM_HEXNUM) {
313  			base = 16;
314  		} else if (node->u.term.type == TERM_OCTNUM) {
315  			base = 8;
316  		} else {
317  			config_proc_error(node, err_type,
318  					  "Expected a number, got a %s",
319  					  config_term_desc(node->u.term.type));
320  			goto errout;
321  		}
322  		errno = 0;
323  		assert(*node->u.term.varvalue != '\0');
324  		val = strtoull(node->u.term.varvalue, &endptr, base);
325  		if (*endptr != '\0' || errno != 0) {
326  			config_proc_error(node, err_type,
327  					  "(%s) is not an integer",
328  					  node->u.term.varvalue);
329  			goto errout;
330  		}
331  		switch (item->type) {
332  		case CONFIG_INT16:
333  			smin = item->u.i16.minval;
334  			smax = item->u.i16.maxval;
335  			signed_int = true;
336  			break;
337  		case CONFIG_UINT16:
338  			mask = UINT16_MAX;
339  			min = item->u.ui16.minval;
340  			max = item->u.ui16.maxval;
341  			break;
342  		case CONFIG_INT32:
343  			smin = item->u.i32.minval;
344  			smax = item->u.i32.maxval;
345  			signed_int = true;
346  			break;
347  		case CONFIG_UINT32:
348  			mask = UINT32_MAX;
349  			min = item->u.ui32.minval;
350  			max = item->u.ui32.maxval;
351  			break;
352  		case CONFIG_ANON_ID:
353  			/* Internal to config, anonymous id is treated as int64_t */
354  			smin = item->u.i64.minval;
355  			smax = item->u.i64.maxval;
356  			signed_int = true;
357  			break;
358  		case CONFIG_INT64:
359  			smin = item->u.i64.minval;
360  			smax = item->u.i64.maxval;
361  			signed_int = true;
362  			break;
363  		case CONFIG_UINT64:
364  			mask = UINT64_MAX;
365  			min = item->u.ui64.minval;
366  			max = item->u.ui64.maxval;
367  			break;
368  		default:
369  			goto errout;
370  		}
371  	
372  		if (signed_int) {
373  			if (node->u.term.op_code == NULL) {
374  				/* Check for overflow of int64_t on positive */
375  				if (val > (uint64_t) INT64_MAX) {
376  					config_proc_error(node, err_type,
377  						  "(%s) is out of range",
378  						  node->u.term.varvalue);
379  					goto errout;
380  				}
381  				sval = val;
382  			} else if (*node->u.term.op_code == '-') {
383  				/* Check for underflow of int64_t on negative */
384  				if (val > ((uint64_t) INT64_MAX) + 1) {
385  					config_proc_error(node, err_type,
386  						  "(%s) is out of range",
387  						  node->u.term.varvalue);
388  					goto errout;
389  				}
390  				sval = -((int64_t) val);
391  			} else {
392  				config_proc_error(node, err_type,
393  					  "(%c) is not allowed for signed values",
394  					  *node->u.term.op_code);
395  				goto errout;
396  			}
397  			if (sval < smin || sval > smax) {
398  				config_proc_error(node, err_type,
399  					  "(%s) is out of range",
400  					  node->u.term.varvalue);
401  				goto errout;
402  			}
403  			val = (uint64_t) sval;
404  		} else {
405  			if (node->u.term.op_code != NULL &&
406  			    *node->u.term.op_code == '~') {
407  				/* Check for overflow before negation */
408  				if ((val & ~mask) != 0) {
409  					config_proc_error(node, err_type,
410  						  "(%s) is out of range",
411  						  node->u.term.varvalue);
412  					goto errout;
413  				}
414  				val = ~val & mask;
415  			} else if (node->u.term.op_code != NULL) {
416  				config_proc_error(node, err_type,
417  					  "(%c) is not allowed for signed values",
418  					  *node->u.term.op_code);
419  				goto errout;
420  			}
421  			if (val < min || val > max) {
422  				config_proc_error(node, err_type,
423  					  "(%s) is out of range",
424  					  node->u.term.varvalue);
425  				goto errout;
426  			}
427  		}
428  	
429  		*num = val;
430  		return true;
431  	
432  	errout:
433  		err_type->errors++;
434  		err_type->invalid = true;
435  		return false;
436  	}
437  	
438  	/**
439  	 * @brief convert an fsid which is a "<64bit num>.<64bit num"
440  	 *
441  	 * NOTE: using assert() here because the parser has already
442  	 * validated so bad things have happened to the parse tree if...
443  	 *
444  	 */
445  	
446  	static bool convert_fsid(struct config_node *node, void *param,
447  				 struct config_error_type *err_type)
448  	{
449  		struct fsal_fsid__ *fsid = (struct fsal_fsid__ *)param;
450  		uint64_t major, minor;
451  		char *endptr, *sp;
452  		int base;
453  	
454  		if (node->type != TYPE_TERM) {
455  			config_proc_error(node, err_type,
456  					  "Expected an FSID, got a %s",
457  					  (node->type == TYPE_ROOT
458  					   ? "root node"
459  					   : (node->type == TYPE_BLOCK
460  					      ? "block" : "statement")));
461  			goto errout;
462  		}
463  		if (node->u.term.type != TERM_FSID) {
464  			config_proc_error(node, err_type,
465  					  "Expected an FSID, got a %s",
466  					  config_term_desc(node->u.term.type));
467  			goto errout;
468  		}
469  		errno = 0;
470  		sp = node->u.term.varvalue;
471  		if (sp[0] == '0') {
472  			if (sp[1] == 'x' || sp[1] == 'X')
473  				base = 16;
474  			else
475  				base = 8;
476  		} else
477  			base = 10;
478  		major = strtoull(sp, &endptr, base);
479  		assert(*endptr == '.');
480  		if (errno != 0 || major == ULLONG_MAX) {
481  			config_proc_error(node, err_type,
482  					  "(%s) major is out of range",
483  					  node->u.term.varvalue);
484  			goto errout;
485  		}
486  		sp = endptr + 1;
487  		if (sp[0] == '0') {
488  			if (sp[1] == 'x' || sp[1] == 'X')
489  				base = 16;
490  			else
491  				base = 8;
492  		} else
493  			base = 10;
494  		minor = strtoull(sp, &endptr, base);
495  		assert(*endptr == '\0');
496  		if (errno != 0 || minor == ULLONG_MAX) {
497  			config_proc_error(node, err_type,
498  					  "(%s) minor is out of range",
499  					  node->u.term.varvalue);
500  			goto errout;
501  		}
502  		fsid->major = major;
503  		fsid->minor = minor;
504  		return true;
505  	
506  	errout:
507  		err_type->invalid = true;
508  		err_type->errors++;
509  		return false;
510  	}
511  	
512  	/**
513  	 * @brief Scan a list of CSV tokens.
514  	 *
515  	 */
516  	
517  	static bool convert_list(struct config_node *node,
518  				 struct config_item *item,
519  				 uint32_t *flags,
520  				 struct config_error_type *err_type)
521  	{
522  		struct config_item_list *tok;
523  		struct config_node *sub_node;
524  		struct glist_head *nsi, *nsn;
525  		bool found;
526  		int errors = 0;
527  	
528  		*flags = 0;
529  		glist_for_each_safe(nsi, nsn, &node->u.nterm.sub_nodes) {
530  			sub_node = glist_entry(nsi, struct config_node, node);
531  			assert(sub_node->type == TYPE_TERM);
532  			found = false;
533  			for (tok = item->u.lst.tokens;
534  			     tok->token != NULL;
535  			     tok++) {
536  				if (strcasecmp(sub_node->u.term.varvalue,
537  					       tok->token) == 0) {
538  					*flags |= tok->value;
539  					found = true;
540  				}
541  			}
542  			if (!found) {
543  				config_proc_error(node, err_type,
544  						  "Unknown token (%s)",
545  						  sub_node->u.term.varvalue);
546  				err_type->bogus = true;
547  				errors++;
548  			}
549  		}
550  		err_type->errors += errors;
551  		return errors == 0;
552  	}
553  	
554  	static bool convert_enum(struct config_node *node,
555  				 struct config_item *item,
556  				 uint32_t *val,
557  				 struct config_error_type *err_type)
558  	{
559  		struct config_item_list *tok;
560  		bool found;
561  	
562  		tok = item->u.lst.tokens;
563  		found = false;
564  		while (tok->token != NULL) {
565  			if (strcasecmp(node->u.term.varvalue, tok->token) == 0) {
566  				*val = tok->value;
567  				found = true;
568  			}
569  			tok++;
570  		}
571  		if (!found) {
572  			config_proc_error(node, err_type,
573  				 "Unknown token (%s)",
574  				 node->filename,
575  				 node->linenumber,
576  				 node->u.term.varvalue);
577  			err_type->bogus = true;
578  			err_type->errors++;
579  		}
580  		return found;
581  	}
582  	
583  	static void convert_inet_addr(struct config_node *node,
584  				     struct config_item *item,
585  				     sockaddr_t *sock,
586  				     struct config_error_type *err_type)
587  	{
588  		struct addrinfo hints;
589  		struct addrinfo *res = NULL;
590  		int rc;
591  	
592  		if (node->u.term.type != TERM_V4ADDR &&
593  		    node->u.term.type != TERM_V4_ANY &&
594  		    node->u.term.type != TERM_V6ADDR) {
595  			config_proc_error(node, err_type,
596  					  "Expected an IP address, got a %s",
597  					  config_term_desc(node->u.term.type));
598  			err_type->invalid = true;
599  			err_type->errors++;
600  			return;
601  		}
602  	
603  		/* Try IPv6 (with mapping) first.  If this fails, fall back on IPv4, if
604  		 * a v4 address was given. */
605  		hints.ai_family = AF_INET6;
606  		hints.ai_flags = AI_ADDRCONFIG | AI_V4MAPPED;
607  		hints.ai_socktype = 0;
608  		hints.ai_protocol = 0;
609  		rc = getaddrinfo(node->u.term.varvalue, NULL,
610  				 &hints, &res);
611  	
612  		if (rc != 0 && (node->u.term.type == TERM_V4ADDR ||
613  				node->u.term.type == TERM_V4_ANY)) {
614  			hints.ai_family = AF_INET;
615  			rc = getaddrinfo(node->u.term.varvalue, NULL,
616  					 &hints, &res);
617  		}
618  		if (rc == 0) {
619  			memcpy(sock, res->ai_addr, res->ai_addrlen);
620  		} else {
621  			config_proc_error(node, err_type,
622  					  "No IP address found for %s because:%s",
623  					  node->u.term.varvalue,
624  					  gai_strerror(rc));
625  			err_type->invalid = true;
626  			err_type->errors++;
627  		}
628  		if (res != NULL)
629  			freeaddrinfo(res);
630  		return;
631  	}
632  	
633  	/**
634  	 * @brief Walk the term node list and call handler for each node
635  	 *
636  	 * This is effectively a callback on each token in the list.
637  	 * Pass along a type hint based on what the parser recognized.
638  	 *
639  	 * @param node [IN] pointer to the statement node
640  	 * @param item [IN] pointer to the config_item table entry
641  	 * @param param_addr [IN] pointer to target struct member
642  	 * @param err_type [OUT] error handling ref
643  	 * @return number of errors
644  	 */
645  	
646  	static void do_proc(struct config_node *node,
647  			    struct config_item *item,
648  			    void *param_addr,
649  			    struct config_error_type *err_type)
650  	{
651  		struct config_node *term_node;
652  		struct glist_head *nsi, *nsn;
653  		int rc = 0;
654  	
655  		assert(node->type == TYPE_STMT);
656  		glist_for_each_safe(nsi, nsn,
657  				    &node->u.nterm.sub_nodes) {
658  			term_node = glist_entry(nsi,
659  					       struct config_node,
660  					       node);
661  			rc += item->u.proc.handler(term_node->u.term.varvalue,
662  						   term_node->u.term.type,
663  						   item,
664  						   param_addr,
665  						   term_node,
666  						   err_type);
667  		}
668  		err_type->errors += rc;
669  	}
670  	
671  	/**
672  	 * @brief Lookup the first node in the list by this name
673  	 *
674  	 * @param list - head of the glist
675  	 * @param name - node name of interest
676  	 *
677  	 * @return first matching node or NULL
678  	 */
679  	
680  	static struct config_node *lookup_node(struct glist_head *list,
681  					       const char *name)
682  	{
683  		struct config_node *node;
684  		struct glist_head *ns;
685  		
686  		glist_for_each(ns, list) {
687  			node = glist_entry(ns, struct config_node, node);
688  			assert(node->type == TYPE_BLOCK ||
689  			       node->type == TYPE_STMT);
690  			if (strcasecmp(name, node->u.nterm.name) == 0) {
691  				node->found = true;
692  				return node;
693  			}
694  		}
695  		return NULL;
696  	}
697  	
698  	/**
699  	 * @brief Lookup the next node in list
700  	 *
701  	 * @param list - head of the glist
702  	 * @param start - continue the lookup from here
703  	 * @param name - node name of interest
704  	 *
705  	 * @return first matching node or NULL
706  	 */
707  	
708  	
709  	static struct config_node *lookup_next_node(struct glist_head *list,
710  					     struct glist_head *start,
711  					     const char *name)
712  	{
713  		struct config_node *node;
714  		struct glist_head *ns;
715  	
716  		glist_for_each_next(start, ns, list) {
717  			node = glist_entry(ns, struct config_node, node);
718  			assert(node->type == TYPE_BLOCK ||
719  			       node->type == TYPE_STMT);
720  			if (strcasecmp(name, node->u.nterm.name) == 0) {
721  				node->found = true;
722  				return node;
723  			}
724  		}
725  		return NULL;
726  	}
727  	
728  	static const char *config_type_str(enum config_type type)
729  	{
730  		switch(type) {
731  		case CONFIG_NULL:
732  			return "CONFIG_NULL";
733  		case CONFIG_INT16:
734  			return "CONFIG_INT16";
735  		case CONFIG_UINT16:
736  			return "CONFIG_UINT16";
737  		case CONFIG_INT32:
738  			return "CONFIG_INT32";
739  		case CONFIG_UINT32:
740  			return "CONFIG_UINT32";
741  		case CONFIG_INT64:
742  			return "CONFIG_INT64";
743  		case CONFIG_UINT64:
744  			return "CONFIG_UINT64";
745  		case CONFIG_FSID:
746  			return "CONFIG_FSID";
747  		case CONFIG_ANON_ID:
748  			return "CONFIG_ANON_ID";
749  		case CONFIG_STRING:
750  			return "CONFIG_STRING";
751  		case CONFIG_PATH:
752  			return "CONFIG_PATH";
753  		case CONFIG_LIST:
754  			return "CONFIG_LIST";
755  		case CONFIG_ENUM:
756  			return "CONFIG_ENUM";
757  		case CONFIG_TOKEN:
758  			return "CONFIG_TOKEN";
759  		case CONFIG_BOOL:
760  			return "CONFIG_BOOL";
761  		case CONFIG_BOOLBIT:
762  			return "CONFIG_BOOLBIT";
763  		case CONFIG_IP_ADDR:
764  			return "CONFIG_IP_ADDR";
765  		case CONFIG_BLOCK:
766  			return "CONFIG_BLOCK";
767  		case CONFIG_PROC:
768  			return "CONFIG_PROC";
769  		case CONFIG_DEPRECATED:
770  			return "CONFIG_DEPRECATED";
771  		}
772  		return "unknown";
773  	}
774  	
775  	static bool do_block_init(struct config_node *blk_node,
776  				  struct config_item *params,
777  				  void *param_struct,
778  				  struct config_error_type *err_type)
779  	{
780  		struct config_item *item;
781  		void *param_addr;
782  		sockaddr_t *sock;
783  		struct addrinfo hints;
784  		struct addrinfo *res = NULL;
785  		int rc;
786  		int errors = 0;
787  	
(1) Event cond_true: Condition "item->name != NULL", taking true branch.
(9) Event loop_begin: Jumped back to beginning of loop.
(10) Event cond_true: Condition "item->name != NULL", taking true branch.
(24) Event loop_begin: Jumped back to beginning of loop.
(25) Event cond_true: Condition "item->name != NULL", taking true branch.
(38) Event loop_begin: Jumped back to beginning of loop.
(39) Event cond_true: Condition "item->name != NULL", taking true branch.
(52) Event loop_begin: Jumped back to beginning of loop.
(53) Event cond_true: Condition "item->name != NULL", taking true branch.
(67) Event loop_begin: Jumped back to beginning of loop.
(68) Event cond_true: Condition "item->name != NULL", taking true branch.
788  		for (item = params; item->name != NULL; item++) {
789  			param_addr = ((char *)param_struct + item->off);
(2) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(3) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(11) Event cond_false: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking false branch.
(12) Event cond_false: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking false branch.
(13) Event if_end: End of if statement.
(26) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(27) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(40) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(41) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(54) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(55) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(69) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
(70) Event cond_true: Condition "!!(component_log_level[COMPONENT_CONFIG] >= NIV_FULL_DEBUG)", taking true branch.
790  			LogFullDebug(COMPONENT_CONFIG,
791  				     "%p name=%s type=%s",
792  				     param_addr, item->name, config_type_str(item->type));
(4) Event switch: Switch case value "CONFIG_NULL".
(14) Event switch: Switch case value "CONFIG_STRING".
(28) Event switch: Switch case value "CONFIG_IP_ADDR".
(42) Event switch: Switch case value "CONFIG_IP_ADDR".
(56) Event switch: Switch case value "CONFIG_IP_ADDR".
(71) Event switch: Switch case value "CONFIG_IP_ADDR".
793  			switch (item->type) {
(5) Event switch_case: Reached case "CONFIG_NULL".
794  			case CONFIG_NULL:
(6) Event break: Breaking from switch.
795  				break;
796  			case CONFIG_INT16:
797  				*(int16_t *)param_addr = item->u.i16.def;
798  				break;
799  			case CONFIG_UINT16:
800  				*(uint16_t *)param_addr = item->u.ui16.def;
801  				break;
802  			case CONFIG_INT32:
803  				*(int32_t *)param_addr = item->u.i32.def;
804  				break;
805  			case CONFIG_UINT32:
806  				*(uint32_t *)param_addr = item->u.ui32.def;
807  				break;
808  			case CONFIG_INT64:
809  				*(int64_t *)param_addr = item->u.i64.def;
810  				break;
811  			case CONFIG_UINT64:
812  				*(uint64_t *)param_addr = item->u.ui64.def;
813  				break;
814  			case CONFIG_ANON_ID:
815  				*(uid_t *)param_addr = item->u.i64.def;
816  				break;
817  			case CONFIG_FSID:
818  				((struct fsal_fsid__ *)param_addr)->major
819  					= item->u.fsid.def_maj;
820  				((struct fsal_fsid__ *)param_addr)->minor
821  					= item->u.fsid.def_min;
822  				break;
(15) Event switch_case: Reached case "CONFIG_STRING".
823  			case CONFIG_STRING:
824  			case CONFIG_PATH:
(16) Event cond_true: Condition "item->u.str.def", taking true branch.
825  				if (item->u.str.def)
(19) Event if_fallthrough: Falling through to end of if statement.
826  					*(char **)param_addr
(17) Event cond_false: Condition "p_ == NULL", taking false branch.
(18) Event if_end: End of if statement.
827  						= gsh_strdup(item->u.str.def);
828  				else
(20) Event if_end: End of if statement.
829  					*(char **)param_addr = NULL;
(21) Event break: Breaking from switch.
830  				break;
831  			case CONFIG_TOKEN:
832  				*(uint32_t *)param_addr = item->u.lst.def;
833  				break;
834  			case CONFIG_BOOL:
835  				*(bool *)param_addr = item->u.b.def;
836  				break;
837  			case CONFIG_BOOLBIT:
838  				if (item->u.bit.def)
839  					*(uint32_t *)param_addr |= item->u.bit.bit;
840  				else
841  					*(uint32_t *)param_addr &= ~item->u.bit.bit;
842  				break;
843  			case CONFIG_LIST:
844  				*(uint32_t *)param_addr |= item->u.lst.def;
845  				LogFullDebug(COMPONENT_CONFIG,
846  					     "%p CONFIG_LIST %s mask=%08x def=%08x"
847  					     " value=%08"PRIx32,
848  					     param_addr,
849  					     item->name,
850  					     item->u.lst.mask, item->u.lst.def,
851  					     *(uint32_t *)param_addr);
852  				break;
853  			case CONFIG_ENUM:
854  				*(uint32_t *)param_addr |= item->u.lst.def;
855  				LogFullDebug(COMPONENT_CONFIG,
856  					     "%p CONFIG_ENUM %s mask=%08x def=%08x"
857  					     " value=%08"PRIx32,
858  					     param_addr,
859  					     item->name,
860  					     item->u.lst.mask, item->u.lst.def,
861  					     *(uint32_t *)param_addr);
862  				break;
(29) Event switch_case: Reached case "CONFIG_IP_ADDR".
(43) Event switch_case: Reached case "CONFIG_IP_ADDR".
(57) Event switch_case: Reached case "CONFIG_IP_ADDR".
(72) Event switch_case: Reached case "CONFIG_IP_ADDR".
863  			case CONFIG_IP_ADDR:
864  				sock = (sockaddr_t *)param_addr;
865  				memset(sock, 0, sizeof(sockaddr_t));
866  				errno = 0;
867  				/* Try IPv6 (with mapping) first.  If this fails, fall
868  				 * back on IPv4, if a v4 address was given. */
869  				memset(&hints, 0, sizeof(struct addrinfo));
870  				hints.ai_family = AF_INET6;
871  				hints.ai_flags = AI_PASSIVE;
872  				hints.ai_socktype = 0;
873  				hints.ai_protocol = 0;
874  				/* We don't actually pass "0.0.0.0" to this, so that it
875  				 * gets the correct address for each address family.
876  				 * AI_PASSIVE assures this. */
877  				rc = getaddrinfo(NULL, "0", &hints, &res);
878  	
(30) Event cond_true: Condition "rc != 0", taking true branch.
(44) Event cond_true: Condition "rc != 0", taking true branch.
(58) Event cond_true: Condition "rc != 0", taking true branch.
(73) Event cond_true: Condition "rc != 0", taking true branch.
879  				if (rc != 0) {
880  					hints.ai_family = AF_INET;
881  					rc = getaddrinfo(NULL, "0", &hints, &res);
882  				}
(31) Event cond_false: Condition "rc == 0", taking false branch.
(45) Event cond_false: Condition "rc == 0", taking false branch.
(59) Event cond_true: Condition "rc == 0", taking true branch.
(74) Event cond_false: Condition "rc == 0", taking false branch.
883  				if (rc == 0) {
884  					memcpy(sock, res->ai_addr, res->ai_addrlen);
(32) Event else_branch: Reached else branch.
(46) Event else_branch: Reached else branch.
(60) Event if_fallthrough: Falling through to end of if statement.
(75) Event else_branch: Reached else branch.
885  				} else {
886  					config_proc_error(blk_node, err_type,
887  							  "Cannot set IP default for %s to %s because %s",
888  							  item->name,
889  							  item->u.ip.def,
890  							  gai_strerror(rc));
891  					errors++;
(61) Event if_end: End of if statement.
892  				}
(33) Event cond_false: Condition "res != NULL", taking false branch.
(47) Event cond_false: Condition "res != NULL", taking false branch.
(62) Event cond_true: Condition "res != NULL", taking true branch.
(76) Event cond_true: Condition "res != NULL", taking true branch.
893  				if (res != NULL)
(34) Event if_end: End of if statement.
(48) Event if_end: End of if statement.
(63) Event freed_arg: "freeaddrinfo" frees "res".
(77) Event double_free: Calling "freeaddrinfo" frees pointer "res" which has already been freed.
894  					freeaddrinfo(res);
(35) Event break: Breaking from switch.
(49) Event break: Breaking from switch.
(64) Event break: Breaking from switch.
895  				break;
896  			case CONFIG_BLOCK:
897  				(void) item->u.blk.init(NULL, param_addr);
898  				break;
899  			case CONFIG_PROC:
900  				(void) item->u.proc.init(NULL, param_addr);
901  				break;
902  			case CONFIG_DEPRECATED:
903  				break;
904  			default:
905  				config_proc_error(blk_node, err_type,
906  						  "Cannot set default for parameter %s, type(%d) yet",
907  						  item->name, item->type);
908  				errors++;
909  				break;
(7) Event switch_end: Reached end of switch.
(22) Event switch_end: Reached end of switch.
(36) Event switch_end: Reached end of switch.
(50) Event switch_end: Reached end of switch.
(65) Event switch_end: Reached end of switch.
910  			}
(8) Event loop: Jumping back to the beginning of the loop.
(23) Event loop: Jumping back to the beginning of the loop.
(37) Event loop: Jumping back to the beginning of the loop.
(51) Event loop: Jumping back to the beginning of the loop.
(66) Event loop: Jumping back to the beginning of the loop.
911  		}
912  		err_type->errors += errors;
913  		return errors == 0;
914  	}
915  	
916  	/**
917  	 * @brief This is the NOOP init for block and proc parsing
918  	 *
919  	 * @param link_mem [IN] pointer to member in referencing structure
920  	 * @param self_struct [IN] pointer to space reserved/allocated for block
921  	 *
922  	 * @return a pointer depending on context
923  	 */
924  	
925  	void *noop_conf_init(void *link_mem, void *self_struct)
926  	{
927  		assert(link_mem != NULL || self_struct != NULL);
928  	
929  		if (link_mem == NULL)
930  			return self_struct;
931  		else if (self_struct == NULL)
932  			return link_mem;
933  		else
934  			return NULL;
935  	}
936  	
937  	int noop_conf_commit(void *node, void *link_mem, void *self_struct,
938  			     struct config_error_type *err_type)
939  	{
940  		return 0;
941  	}
942  	
943  	static bool proc_block(struct config_node *node,
944  			      struct config_item *item,
945  			      void *link_mem,
946  			      struct config_error_type *err_type);
947  	
948  	/*
949  	 * All the types of integers supported by the config processor
950  	 */
951  	
952  	union gen_int {
953  		bool b;
954  		int16_t i16;
955  		uint16_t ui16;
956  		int32_t i32;
957  		uint32_t ui32;
958  		int64_t i64;
959  		uint64_t ui64;
960  	};
961  	
962  	/**
963  	 * @brief Process the defined tokens in the params table
964  	 *
965  	 * The order of the parameter table is important.  If any
966  	 * parameter requires that another parameter in the table be
967  	 * processed first, order the table appropriately.
968  	 *
969  	 * @param blk    [IN] a parse tree node of type CONFIG_BLOCK
970  	 * @param params [IN] points to a NULL term'd table of config_item's
971  	 * @param relax  [IN] if true, don't report unrecognized params.
972  	 * @param param_struct [IN/OUT] the structure to be filled.
973  	 *
974  	 * @returns 0 on success, number of errors on failure.
975  	 */
976  	
977  	static int do_block_load(struct config_node *blk,
978  				 struct config_item *params,
979  				 bool relax,
980  				 void *param_struct,
981  				 struct config_error_type *err_type)
982  	{
983  		struct config_item *item;
984  		void *param_addr;
985  		struct config_node *node, *term_node, *next_node = NULL;
986  		struct glist_head *ns;
987  		int errors = 0;
988  	
989  		for (item = params; item->name != NULL; item++) {
990  			uint64_t num64;
991  			bool bool_val;
992  			uint32_t num32 = 0;
993  	
994  			node = lookup_node(&blk->u.nterm.sub_nodes, item->name);
995  			if ((item->flags & CONFIG_MANDATORY) && (node == NULL)) {
996  				err_type->missing = true;
997  				errors = ++err_type->errors;
998  				config_proc_error(blk, err_type,
999  						  "Mandatory field, %s is missing from block (%s)",
1000 						  item->name, blk->u.nterm.name);
1001 				continue;
1002 			}
1003 			while (node != NULL) {
1004 				next_node = lookup_next_node(&blk->u.nterm.sub_nodes,
1005 							     &node->node, item->name);
1006 				if (next_node != NULL &&
1007 				    (item->flags & CONFIG_UNIQUE)) {
1008 					config_proc_error(next_node, err_type,
1009 							  "Parameter %s set more than once",
1010 							  next_node->u.nterm.name);
1011 					err_type->unique = true;
1012 					errors = ++err_type->errors;
1013 					node = next_node;
1014 					continue;
1015 				}
1016 				param_addr = ((char *)param_struct + item->off);
1017 				LogFullDebug(COMPONENT_CONFIG,
1018 					     "%p name=%s type=%s",
1019 					     param_addr, item->name,
1020 					     config_type_str(item->type));
1021 				if (glist_empty(&node->u.nterm.sub_nodes)) {
1022 					LogInfo(COMPONENT_CONFIG,
1023 						"%s %s is empty",
1024 						(node->type == TYPE_STMT
1025 						 ? "Statement" : "Block"),
1026 						node->u.nterm.name);
1027 					node = next_node;
1028 					continue;
1029 				}
1030 				term_node = glist_first_entry(&node->u.nterm.sub_nodes,
1031 							      struct config_node,
1032 							      node);
1033 				if ((item->type != CONFIG_BLOCK &&
1034 				     item->type != CONFIG_PROC &&
1035 				     item->type != CONFIG_LIST) &&
1036 				    glist_length(&node->u.nterm.sub_nodes) > 1) {
1037 					config_proc_error(node, err_type,
1038 							  "%s can have only one option.  First one is (%s)",
1039 							  node->u.nterm.name,
1040 							  term_node->u.term.varvalue);
1041 					err_type->invalid = true;
1042 					errors = ++err_type->errors;
1043 					node = next_node;
1044 					continue;
1045 				}
1046 				switch (item->type) {
1047 				case CONFIG_NULL:
1048 					break;
1049 				case CONFIG_INT16:
1050 					if (convert_number(term_node, item,
1051 							   &num64, err_type))
1052 						*(int16_t *)param_addr = num64;
1053 					break;
1054 				case CONFIG_UINT16:
1055 					if (convert_number(term_node, item,
1056 							   &num64, err_type))
1057 						*(uint16_t *)param_addr	= num64;
1058 					break;
1059 				case CONFIG_INT32:
1060 					if (convert_number(term_node, item,
1061 							   &num64, err_type)) {
1062 						*(int32_t *)param_addr = num64;
1063 						if (item->flags & CONFIG_MARK_SET) {
1064 							void *mask_addr;
1065 	
1066 							mask_addr =
1067 								((char *)param_struct
1068 								 + item->u.i32.set_off);
1069 							*(uint32_t *)mask_addr
1070 								|= item->u.i32.bit;
1071 						}
1072 					}
1073 					break;
1074 				case CONFIG_UINT32:
1075 					if (convert_number(term_node, item,
1076 							   &num64, err_type))
1077 						*(uint32_t *)param_addr	= num64;
1078 					break;
1079 				case CONFIG_INT64:
1080 					if (convert_number(term_node, item,
1081 							   &num64, err_type))
1082 						*(int64_t *)param_addr = num64;
1083 					break;
1084 				case CONFIG_UINT64:
1085 					if (convert_number(term_node, item,
1086 							   &num64, err_type)) {
1087 						*(uint64_t *)param_addr = num64;
1088 						if (item->flags & CONFIG_MARK_SET) {
1089 							void *mask_addr;
1090 	
1091 							mask_addr =
1092 							((char *)param_struct
1093 							 + item->u.ui64.set_off);
1094 							*(uint32_t *)mask_addr
1095 							|= item->u.ui64.bit;
1096 						}
1097 					}
1098 					break;
1099 				case CONFIG_ANON_ID:
1100 					if (convert_number(term_node, item,
1101 							   &num64, err_type)) {
1102 						*(uid_t *)param_addr = num64;
1103 						if (item->flags & CONFIG_MARK_SET) {
1104 							void *mask_addr;
1105 	
1106 							mask_addr =
1107 								((char *)param_struct
1108 								 + item->u.i64.set_off);
1109 							*(uint32_t *)mask_addr
1110 								|= item->u.i64.bit;
1111 						}
1112 					}
1113 					break;
1114 				case CONFIG_FSID:
1115 					if (convert_fsid(term_node, param_addr,
1116 							 err_type)) {
1117 						if (item->flags & CONFIG_MARK_SET) {
1118 							void *mask_addr;
1119 	
1120 							mask_addr =
1121 								((char *)param_struct
1122 								+ item->u.fsid.set_off);
1123 							*(uint32_t *)mask_addr
1124 								|= item->u.fsid.bit;
1125 						}
1126 					}
1127 					break;
1128 				case CONFIG_STRING:
1129 					if (*(char **)param_addr != NULL)
1130 						gsh_free(*(char **)param_addr);
1131 					*(char **)param_addr =
1132 						gsh_strdup(term_node->u.term.varvalue);
1133 					break;
1134 				case CONFIG_PATH:
1135 					if (*(char **)param_addr != NULL)
1136 						gsh_free(*(char **)param_addr);
1137 					/** @todo validate path with access() */
1138 					*(char **)param_addr =
1139 						gsh_strdup(term_node->u.term.varvalue);
1140 					break;
1141 				case CONFIG_TOKEN:
1142 					if (convert_enum(term_node, item, &num32,
1143 							 err_type))
1144 						*(uint32_t *)param_addr = num32;
1145 					break;
1146 				case CONFIG_BOOL:
1147 					if (convert_bool(term_node, &bool_val,
1148 							 err_type))
1149 						*(bool *)param_addr = bool_val;
1150 					break;
1151 				case CONFIG_BOOLBIT:
1152 					if (convert_bool(term_node, &bool_val,
1153 							 err_type)) {
1154 						if (bool_val)
1155 							*(uint32_t *)param_addr
1156 								|= item->u.bit.bit;
1157 						else
1158 							*(uint32_t *)param_addr
1159 								&= ~item->u.bit.bit;
1160 						if (item->flags & CONFIG_MARK_SET) {
1161 							void *mask_addr;
1162 	
1163 							mask_addr =
1164 								((char *)param_struct
1165 								+ item->u.bit.set_off);
1166 							*(uint32_t *)mask_addr
1167 								|= item->u.bit.bit;
1168 						}	
1169 					}
1170 					break;
1171 				case CONFIG_LIST:
1172 					if (item->u.lst.def ==
1173 					   (*(uint32_t *)param_addr & item->u.lst.mask))
1174 						*(uint32_t *)param_addr &=
1175 								~item->u.lst.mask;
1176 					if (convert_list(node, item, &num32,
1177 							 err_type)) {
1178 						*(uint32_t *)param_addr |= num32;
1179 						if (item->flags & CONFIG_MARK_SET) {
1180 							void *mask_addr;
1181 	
1182 							mask_addr =
1183 								((char *)param_struct
1184 								+ item->u.lst.set_off);
1185 							*(uint32_t *)mask_addr
1186 								|= item->u.lst.mask;
1187 						}	
1188 					}
1189 					LogFullDebug(COMPONENT_CONFIG,
1190 						     "%p CONFIG_LIST %s mask=%08x flags=%08x"
1191 						     " value=%08"PRIx32,
1192 						     param_addr,
1193 						     item->name,
1194 						     item->u.lst.mask, num32,
1195 						     *(uint32_t *)param_addr);
1196 					break;
1197 				case CONFIG_ENUM:
1198 					if (item->u.lst.def ==
1199 					   (*(uint32_t *)param_addr & item->u.lst.mask))
1200 						*(uint32_t *)param_addr &=
1201 								~item->u.lst.mask;
1202 					if (convert_enum(term_node, item, &num32,
1203 							 err_type)) {
1204 						*(uint32_t *)param_addr |= num32;
1205 						if (item->flags & CONFIG_MARK_SET) {
1206 							void *mask_addr;
1207 	
1208 							mask_addr =
1209 								((char *)param_struct
1210 								+ item->u.lst.set_off);
1211 							*(uint32_t *)mask_addr
1212 								|= item->u.lst.mask;
1213 						}	
1214 					}
1215 					LogFullDebug(COMPONENT_CONFIG,
1216 						     "%p CONFIG_ENUM %s mask=%08x flags=%08x"
1217 						     " value=%08"PRIx32,
1218 						     param_addr,
1219 						     item->name,
1220 						     item->u.lst.mask, num32,
1221 						     *(uint32_t *)param_addr);
1222 					break;
1223 				case CONFIG_IP_ADDR:
1224 					convert_inet_addr(term_node, item,
1225 							  (sockaddr_t *)param_addr,
1226 							  err_type);
1227 					break;
1228 				case CONFIG_BLOCK:
1229 					if (!proc_block(node, item, param_addr,
1230 							err_type))
1231 						config_proc_error(node, err_type,
1232 								  "Errors processing block (%s)",
1233 								  node->u.nterm.name);
1234 					break;
1235 				case CONFIG_PROC:
1236 					do_proc(node, item, param_addr,	err_type);
1237 					break;
1238 				case CONFIG_DEPRECATED:
1239 					config_proc_error(node, err_type,
1240 						"Deprectated parameter (%s)%s%s",
1241 						item->name,
1242 						item->u.deprecated.message
1243 							? " - "
1244 							: "",
1245 						item->u.deprecated.message
1246 							? item->u.deprecated.message
1247 							: "");
1248 					err_type->deprecated = true;
1249 					errors++;
1250 					break;
1251 				default:
1252 					config_proc_error(term_node, err_type,
1253 							  "Cannot set value for type(%d) yet",
1254 							  item->type);
1255 					err_type->internal = true;
1256 					errors = ++err_type->errors;
1257 					break;
1258 					}
1259 				node = next_node;
1260 			}
1261 		}
1262 		if (relax)
1263 			return errors;
1264 	
1265 		/* We've been marking config nodes as being "seen" during the
1266 		 * scans.  Report the bogus and typo inflicted bits.
1267 		 */
1268 		glist_for_each(ns, &blk->u.nterm.sub_nodes) {
1269 			node = glist_entry(ns, struct config_node, node);
1270 			if (node->found)
1271 				node->found = false;
1272 			else {
1273 				config_proc_error(node, err_type,
1274 						  "Unknown parameter (%s)",
1275 						  node->u.nterm.name);
1276 				err_type->bogus = true;
1277 				errors++;
1278 			}
1279 		}
1280 		return errors;
1281 	}
1282 	
1283 	/**
1284 	 * @brief Process a block
1285 	 *
1286 	 * The item arg supplies two function pointers that
1287 	 * are defined as follows:
1288 	 *
1289 	 * init
1290 	 *  This function manages memory for the sub-block's processing.
1291 	 *  It has two arguments, a pointer to the link_mem param struct and
1292 	 *  a pointer to the self_struct param struct.
1293 	 *  If the self_struct argument is NULL, it returns a pointer to a usable
1294 	 *  self_struct param struct.  This can either be allocate memory
1295 	 *  or a pointer to existing memory.
1296 	 *
1297 	 *  If the self_struct argument is not NULL, it is the pointer it returned above.
1298 	 *  The function reverts whatever it did above.
1299 	 *
1300 	 * commit
1301 	 *  This function attaches the build param struct to its link_mem.
1302 	 *  Before it does the attach, it will do validation of input if required.
1303 	 *  Returns 0 if validation passes and the attach is successful.  Otherwise,
1304 	 *  it returns an error which will trigger a release of resourcs acquired
1305 	 *  by the self_struct_init.
1306 	 *
1307 	 * Both of these functions are called in the context of the link_mem parse.
1308 	 * It is assumed that the link_mem has already been initialized including
1309 	 * the init of any glists before this function is called.
1310 	 * The self_struct does its own init of things like glist in param_mem.
1311 	 *
1312 	 * @param node - parse node of the subblock
1313 	 * @param item - config_item describing block
1314 	 * @param link_mem - pointer to the link_mem structure
1315 	 * @param err_type [OUT] pointer to error type return
1316 	 *
1317 	 * @ return true on success, false on errors.
1318 	 */
1319 	
1320 	static bool proc_block(struct config_node *node,
1321 			      struct config_item *item,
1322 			      void *link_mem,
1323 			      struct config_error_type *err_type)
1324 	{
1325 		void *param_struct;
1326 		int errors = 0;
1327 	
1328 		assert(item->type == CONFIG_BLOCK);
1329 	
1330 		if (node->type != TYPE_BLOCK) {
1331 			config_proc_error(node, err_type,
1332 					  "%s is not a block!",
1333 					  item->name);
1334 			err_type->invalid = true;
1335 			err_type->errors++;
1336 			return false;
1337 		}
1338 		param_struct = item->u.blk.init(link_mem, NULL);
1339 		if (param_struct == NULL) {
1340 			config_proc_error(node, err_type,
1341 					  "Could not init block for %s",
1342 					  item->name);
1343 			err_type->init = true;
1344 			err_type->errors++;
1345 			return false;
1346 		}
1347 		LogFullDebug(COMPONENT_CONFIG,
1348 			     "------ At (%s:%d): do_block_init %s",
1349 			     node->filename,
1350 			     node->linenumber,
1351 			     item->name);
1352 		if (!do_block_init(node, item->u.blk.params,
1353 				   param_struct, err_type)) {
1354 			config_proc_error(node, err_type,
1355 					  "Could not initialize parameters for %s",
1356 					  item->name);
1357 			err_type->init = true;
1358 			goto err_out;
1359 		}
1360 		if (item->u.blk.display != NULL)
1361 			item->u.blk.display("DEFAULTS", node,
1362 					      link_mem, param_struct);
1363 		LogFullDebug(COMPONENT_CONFIG,
1364 			     "------ At (%s:%d): do_block_load %s",
1365 			     node->filename,
1366 			     node->linenumber,
1367 			     item->name);
1368 		errors = do_block_load(node,
1369 				   item->u.blk.params,
1370 				   (item->flags & CONFIG_RELAX) ? true : false,
1371 				   param_struct, err_type);
1372 		if (errors > 0 && !config_error_is_harmless(err_type)) {
1373 			config_proc_error(node, err_type,
1374 					  "%d errors while processing parameters for %s",
1375 					  errors,
1376 					  item->name);
1377 			goto err_out;
1378 		}
1379 		LogFullDebug(COMPONENT_CONFIG,
1380 			     "------ At (%s:%d): commit %s",
1381 			     node->filename,
1382 			     node->linenumber,
1383 			     item->name);
1384 		errors = item->u.blk.commit(node, link_mem, param_struct, err_type);
1385 		if (errors > 0 && !config_error_is_harmless(err_type)) {
1386 			config_proc_error(node, err_type,
1387 					  "%d validation errors in block %s",
1388 					  errors,
1389 					  item->name);
1390 			goto err_out;
1391 		}
1392 		if (item->u.blk.display != NULL)
1393 			item->u.blk.display("RESULT", node, link_mem, param_struct);
1394 	
1395 		if (err_type->dispose) {
1396 			/* We had a config update case where this block must be
1397 			 * disposed of. Need to clear the flag so the next config
1398 			 * block processed gets a clear slate.
1399 			 */
1400 			LogFullDebug(COMPONENT_CONFIG,
1401 				     "Releasing block %p/%p", link_mem, param_struct);
1402 			(void)item->u.blk.init(link_mem, param_struct);
1403 			err_type->dispose = false;
1404 		}
1405 	
1406 		return true;
1407 	
1408 	err_out:
1409 		LogFullDebug(COMPONENT_CONFIG,
1410 			     "Releasing block %p/%p", link_mem, param_struct);
1411 		(void)item->u.blk.init(link_mem, param_struct);
1412 		err_type->dispose = false;
1413 		return false;
1414 	}
1415 	
1416 	/**
1417 	 * @brief Find the root of the parse tree given a node.
1418 	 *
1419 	 * @param node [IN] pointer to a TYPE_BLOCK node.
1420 	 *
1421 	 * @return the root of the tree.  Errors are asserted.
1422 	 */
1423 	
1424 	config_file_t get_parse_root(void *node)
1425 	{
1426 		struct config_node *parent;
1427 		struct config_root *root;
1428 	
1429 		parent = (struct config_node *)node;
1430 		assert(parent->type == TYPE_BLOCK);
1431 		while (parent->u.nterm.parent != NULL) {
1432 			parent = parent->u.nterm.parent;
1433 			assert(parent->type == TYPE_ROOT ||
1434 			       parent->type == TYPE_BLOCK);
1435 		}
1436 		assert(parent->type == TYPE_ROOT);
1437 		root = container_of(parent, struct config_root, root);
1438 		return (config_file_t)root;
1439 	}
1440 	
1441 	uint64_t get_config_generation(struct config_root *root)
1442 	{
1443 		return root->generation;
1444 	}
1445 	
1446 	uint64_t get_parse_root_generation(void *node)
1447 	{
1448 		struct config_root *root = (struct config_root *)get_parse_root(node);
1449 	
1450 		return get_config_generation(root);
1451 	}
1452 	
1453 	/**
1454 	 * @brief Data structures for walking parse trees
1455 	 *
1456 	 * These structures hold the result of the parse of a block
1457 	 * description string that is passed to find_config_nodes
1458 	 *
1459 	 * expr_parse is for blocks
1460 	 *
1461 	 * expr_parse_arg is for indexing/matching parameters.
1462 	 */
1463 	
1464 	struct expr_parse_arg {
1465 		char *name;
1466 		char *value;
1467 		struct expr_parse_arg *next;
1468 	};
1469 	
1470 	struct expr_parse {
1471 		char *name;
1472 		struct expr_parse_arg *arg;
1473 		struct expr_parse *next;
1474 	};
1475 	
1476 	/**
1477 	 * @brief Skip 0 or more white space chars
1478 	 *
1479 	 * @return pointer to first non-white space char
1480 	 */
1481 	
1482 	static inline char *skip_white(char *sp)
1483 	{
1484 		while (isspace(*sp))
1485 			sp++;
1486 		return sp;
1487 	}
1488 	
1489 	/**
1490 	 * @brief Find the end of a token, i.e. [A-Za-z0-9_]+
1491 	 *
1492 	 * @return pointer to first unmatched char.
1493 	 */
1494 	
1495 	static inline char *end_of_token(char *sp)
1496 	{
1497 		while (isalnum(*sp) || *sp == '_')
1498 			sp++;
1499 		return sp;
1500 	}
1501 	
1502 	/**
1503 	 * @brief Find end of a value string.
1504 	 *
1505 	 * @return pointer to first white or syntax token
1506 	 */
1507 	
1508 	static inline char *end_of_value(char *sp)
1509 	{
1510 		while (*sp != '\0') {
1511 			if (isspace(*sp) || *sp == ',' || *sp == ')' || *sp == '(')
1512 				break;
1513 			sp++;
1514 		 }
1515 		return sp;
1516 	}
1517 	
1518 	/**
1519 	 * @brief Release storage for arg list
1520 	 */
1521 	
1522 	static void free_expr_parse_arg(struct expr_parse_arg *argp)
1523 	{
1524 		struct expr_parse_arg *nxtarg, *arg = NULL;
1525 	
1526 		if (argp == NULL)
1527 			return;
1528 		for (arg = argp; arg != NULL; arg = nxtarg) {
1529 			nxtarg = arg->next;
1530 			gsh_free(arg->name);
1531 			gsh_free(arg->value);
1532 			gsh_free(arg);
1533 		}
1534 	}
1535 	
1536 	/**
1537 	 * @brief Release storage for the expression parse tree
1538 	 */
1539 	
1540 	static void free_expr_parse(struct expr_parse *snode)
1541 	{
1542 		struct expr_parse *nxtnode, *node = NULL;
1543 	
1544 		if (snode == NULL)
1545 			return;
1546 		for (node = snode; node != NULL; node = nxtnode) {
1547 			nxtnode = node->next;
1548 			gsh_free(node->name);
1549 			free_expr_parse_arg(node->arg);
1550 			gsh_free(node);
1551 		}
1552 	}
1553 	
1554 	/**
1555 	 * @brief Parse "token = string" or "token1 = string1, ..."
1556 	 *
1557 	 * @param arg_str [IN] pointer to first char to parse
1558 	 * @param argp    [OUT] list of parsed expr_parse_arg
1559 	 *
1560 	 * @return pointer to first unmatching char or NULL on parse error
1561 	 */
1562 	
1563 	static char *parse_args(char *arg_str, struct expr_parse_arg **argp)
1564 	{
1565 		char *sp, *name, *val;
1566 		int saved_char;
1567 		struct expr_parse_arg *arg = NULL;
1568 	
1569 		sp = skip_white(arg_str);
1570 		if (*sp == '\0')
1571 			return NULL;
1572 		name = sp;		/* name matches [A-Za-z_][A-Za-z0-9_]* */
1573 		if (!(isalpha(*sp) || *sp == '_'))
1574 			return NULL;
1575 		sp = end_of_token(sp);
1576 		if (isspace(*sp))
1577 			*sp++ = '\0';
1578 		sp = skip_white(sp);
1579 		if (*sp != '=')
1580 			return NULL;
1581 		*sp++ = '\0';		/* name = ... */
1582 		sp = skip_white(sp);
1583 		if (*sp == '\0')
1584 			return NULL;
1585 		val = sp;
1586 		sp = end_of_value(sp);
1587 		if (*sp == '\0')
1588 			return NULL;
1589 		if (isspace(*sp)) {	/* name = val */
1590 			*sp++ = '\0';
1591 			sp = skip_white(sp);
1592 		}
1593 		if (*sp == '\0')
1594 			return NULL;
1595 		saved_char = *sp;
1596 		*sp = '\0';
1597 		arg = gsh_calloc(1, sizeof(struct expr_parse_arg));
1598 		arg->name = gsh_strdup(name);
1599 		arg->value = gsh_strdup(val);
1600 		*argp = arg;
1601 		if (saved_char != ',') {
1602 			*sp = saved_char;
1603 			return sp;
1604 		}
1605 		sp++;			/* name = val , ... */
1606 		return parse_args(sp, &arg->next);
1607 	}
1608 	
1609 	/**
1610 	 * @brief Parse "token ( .... )" and "token ( .... ) . token ( ... )"
1611 	 *
1612 	 * @param str   [IN] pointer to first char to be parsed
1613 	 * @param node  [OUT] reference pointer to returned expr_parse list
1614 	 *
1615 	 * @return pointer to first char after parse or NULL on errors
1616 	 */
1617 	
1618 	static char *parse_block(char *str, struct expr_parse **node)
1619 	{
1620 		char *sp, *name;
1621 		struct expr_parse_arg *arg = NULL;
1622 		struct expr_parse *new_node;
1623 	
1624 		sp = skip_white(str);
1625 		if (*sp == '\0')
1626 			return NULL;
1627 		name = sp;		/* name matches [A-Za-z_][A-Za-z0-9_]* */
1628 		if (!(isalpha(*sp) || *sp != '_'))
1629 			return NULL;
1630 		if (*sp == '_')
1631 			sp++;
1632 		sp = end_of_token(sp);
1633 		if (isspace(*sp))
1634 			*sp++ = '\0';
1635 		sp = skip_white(sp);
1636 		if (*sp != '(')
1637 			return NULL;
1638 		*sp++ = '\0';	/* name ( ... */
1639 		sp = parse_args(sp, &arg);
1640 		if (sp == NULL)
1641 			goto errout;
1642 		sp = skip_white(sp);
1643 		if (*sp == ')') {	/* name ( ... ) */
1644 			new_node = gsh_calloc(1, sizeof(struct expr_parse));
1645 			new_node->name = gsh_strdup(name);
1646 			new_node->arg = arg;
1647 			*node = new_node;
1648 			return sp + 1;
1649 		}
1650 	
1651 	errout:
1652 		free_expr_parse_arg(arg);
1653 		return NULL;
1654 	}
1655 	
1656 	/**
1657 	 * @brief Parse a treewalk expression
1658 	 *
1659 	 * A full expression describes the path down a parse tree with
1660 	 * each node described as "block_name ( qualifiers )".
1661 	 * Each node in the path is a series of block name and qualifiers
1662 	 * separated by '.'.
1663 	 *
1664 	 * The parse errors are detected as either ret val == NULL
1665 	 * or *retval != '\0', i.e. pointing to a garbage char
1666 	 *
1667 	 * @param expr   [IN] pointer to the expression to be parsed
1668 	 * @param expr_node [OUT] pointer to expression parse tree
1669 	 *
1670 	 * @return pointer to first char past parse or NULL for erros.
1671 	 */
1672 	
1673 	static char *parse_expr(char *expr, struct expr_parse **expr_node)
1674 	{
1675 		char *sp;
1676 		struct expr_parse *node = NULL, *prev_node = NULL, *root_node = NULL;
1677 		char *lexpr = alloca(strlen(expr) + 1);
1678 	
1679 		strcpy(lexpr, expr);
1680 		sp = lexpr;
1681 		while (sp != NULL && *sp != '\0') {
1682 			sp = parse_block(sp, &node);	/* block is name ( ... ) */
1683 			if (root_node == NULL)
1684 				root_node = node;
1685 			else
1686 				prev_node->next = node;
1687 			prev_node = node;
1688 			if (sp == NULL)
1689 				break;
1690 			sp = skip_white(sp);
1691 			if (*sp == '.') {
1692 				sp++;		/* boock '.' block ... */
1693 			} else if (*sp != '\0') {
1694 				sp = NULL;
1695 				break;
1696 			}
1697 		}
1698 		*expr_node = root_node;
1699 		if (sp != NULL)
1700 			return expr + (sp - lexpr);
1701 		else
1702 			return NULL;
1703 	}
1704 	
1705 	static inline bool match_one_term(char *value, struct config_node *node)
1706 	{
1707 		struct config_node *term_node;
1708 		struct glist_head *ts;
1709 	
1710 		glist_for_each(ts, &node->u.nterm.sub_nodes) {
1711 			term_node = glist_entry(ts, struct config_node,	node);
1712 			assert(term_node->type == TYPE_TERM);
1713 			if (strcasecmp(value, term_node->u.term.varvalue) == 0)
1714 				return true;
1715 		}
1716 		return false;
1717 	}
1718 	
1719 	/**
1720 	 * @brief Select block based on the evaluation of the qualifier args
1721 	 *
1722 	 * use each qualifier to match.  The token name is found in the block.
1723 	 * once found, the token value is compared.  '*' matches anything. else
1724 	 * it is a case-insensitive string compare.
1725 	 *
1726 	 * @param blk   [IN] pointer to config_node descibing the block
1727 	 * @param expr  [IN] expr_parse node to match
1728 	 *
1729 	 * @return true if matched, else false
1730 	 */
1731 	
1732 	static bool match_block(struct config_node *blk,
1733 				struct expr_parse *expr)
1734 	{
1735 		struct glist_head *ns;
1736 		struct config_node *sub_node;
1737 		struct expr_parse_arg *arg;
1738 		bool found = false;
1739 	
1740 		assert(blk->type == TYPE_BLOCK);
1741 		for (arg = expr->arg; arg != NULL; arg = arg->next) {
1742 			glist_for_each(ns, &blk->u.nterm.sub_nodes) {
1743 				sub_node = glist_entry(ns, struct config_node, node);
1744 				if (sub_node->type == TYPE_STMT &&
1745 				    strcasecmp(arg->name,
1746 					       sub_node->u.nterm.name) == 0) {
1747 					found = true;
1748 					if (expr->next == NULL &&
1749 					    strcasecmp(arg->value, "*") == 0)
1750 						continue;
1751 					if (!match_one_term(arg->value, sub_node))
1752 						return false;
1753 				}
1754 			}
1755 		}
1756 		return found;
1757 	}
1758 	
1759 	/**
1760 	 * @brief Find nodes in parse tree using expression
1761 	 *
1762 	 * Lookup signature describes the nested block it is of the form:
1763 	 * block_name '(' param_name '=' param_value ')' ...
1764 	 * where block_name and param_name are alphanumerics and param_value is
1765 	 * and arbitrary token.
1766 	 * This can name a subblock (the ...) part by a '.' sub-block_name...
1767 	 * as in:
1768 	
1769 	 *   some_block(indexing_param = foo).the_subblock(its_index = baz)
1770 	 *
1771 	 * NOTE: This will return ENOENT not only if the the comparison
1772 	 * fails but also if the search cannot find the token. In other words,
1773 	 * the match succeeds only if there is a node in the parse tree and it
1774 	 * matches.
1775 	 *
1776 	 * @param config    [IN] root of parse tree
1777 	 * @param expr_str  [IN] expression description of block
1778 	 * @param node_list [OUT] pointer to store node list
1779 	 * @param err_type  [OUT] error processing
1780 	 *
1781 	 * @return 0 on success, errno for errors
1782 	 */
1783 	
1784 	int find_config_nodes(config_file_t config, char *expr_str,
1785 			      struct config_node_list **node_list,
1786 			      struct config_error_type *err_type)
1787 	{
1788 		struct config_root *tree = (struct config_root *)config;
1789 		struct glist_head *ns;
1790 		struct config_node *sub_node;
1791 		struct config_node *top;
1792 		struct expr_parse *expr, *expr_head = NULL;
1793 		struct config_node_list *list = NULL, *list_tail = NULL;
1794 		char *ep;
1795 		int rc = EINVAL;
1796 		bool found = false;
1797 	
1798 		if (tree->root.type != TYPE_ROOT) {
1799 			config_proc_error(&tree->root, err_type,
1800 					  "Expected to start at parse tree root for (%s)",
1801 					  expr_str);
1802 			goto out;
1803 		}
1804 		top = &tree->root;
1805 		ep = parse_expr(expr_str, &expr_head);
1806 		if (ep == NULL || *ep != '\0')
1807 			goto out;
1808 		expr = expr_head;
1809 		*node_list = NULL;
1810 	again:
1811 		glist_for_each(ns, &top->u.nterm.sub_nodes) {
1812 	#ifdef DS_ONLY_WAS
1813 			/* recent changes to parsing may prevent this,
1814 			 * but retain code here for future reference.
1815 			 * -- WAS
1816 			 */
1817 			if (ns == NULL) {
1818 				config_proc_error(top, err_type,
1819 					 "Missing sub_node for (%s)",
1820 					 expr_str);
1821 				break;
1822 			}
1823 	#endif
1824 			sub_node = glist_entry(ns, struct config_node, node);
1825 			if (strcasecmp(expr->name, sub_node->u.nterm.name) == 0 &&
1826 			    sub_node->type == TYPE_BLOCK &&
1827 			    match_block(sub_node, expr)) {
1828 				if (expr->next != NULL) {
1829 					top = sub_node;
1830 					expr = expr->next;
1831 					goto again;
1832 				}
1833 				list = gsh_calloc(1, sizeof(struct config_node_list));
1834 				list->tree_node = sub_node;
1835 				if (*node_list == NULL)
1836 					*node_list = list;
1837 				else
1838 					list_tail->next = list;
1839 				list_tail = list;
1840 				found = true;
1841 			}
1842 		}
1843 		if (found)
1844 			rc = 0;
1845 		else
1846 			rc = ENOENT;
1847 	out:
1848 		free_expr_parse(expr_head);
1849 		return rc;
1850 	}
1851 	
1852 	/**
1853 	 * @brief Fill configuration structure from a parse tree node
1854 	 *
1855 	 * If param == NULL, there is no link_mem and the self_struct storage
1856 	 * is allocated and attached to its destination dynamically.
1857 	 *
1858 	 * @param tree_node   [IN] A CONFIG_BLOCK node in the parse tree
1859 	 * @param conf_blk    [IN] pointer to configuration description
1860 	 * @param param       [IN] pointer to struct to fill or NULL
1861 	 * @param unique      [IN] bool if true, more than one is an error
1862 	 * @param err_type    [OUT] error type return
1863 	 *
1864 	 * @returns -1 on errors, 0 for success
1865 	 */
1866 	
1867 	int load_config_from_node(void *tree_node,
1868 				  struct config_block *conf_blk,
1869 				  void *param,
1870 				  bool unique,
1871 				  struct config_error_type *err_type)
1872 	{
1873 		struct config_node *node = (struct config_node *)tree_node;
1874 		char *blkname = conf_blk->blk_desc.name;
1875 	
1876 		if (node == NULL) {
1877 			config_proc_error(NULL, err_type,
1878 					  "Missing tree_node for (%s)",
1879 					  blkname);
1880 			err_type->missing = true;
1881 			return -1;
1882 		}
1883 		if (node->type == TYPE_BLOCK) {
1884 			if (strcasecmp(node->u.nterm.name, blkname) != 0) {
1885 				config_proc_error(node, err_type,
1886 						  "Looking for block (%s), got (%s)",
1887 						  blkname, node->u.nterm.name);
1888 				err_type->invalid = true;
1889 				err_type->errors++;
1890 				return -1;
1891 			}
1892 		} else {
1893 			config_proc_error(node, err_type,
1894 					  "Unrecognized parse tree node type for block (%s)",
1895 					  blkname);
1896 			err_type->invalid = true;
1897 			err_type->errors++;
1898 			return -1;
1899 		}
1900 		if (!proc_block(node, &conf_blk->blk_desc, param, err_type)) {
1901 			config_proc_error(node, err_type,
1902 					  "Errors found in configuration block %s",
1903 					  blkname);
1904 			return -1;
1905 		}
1906 		return 0;
1907 	}
1908 	
1909 	/**
1910 	 * @brief Fill configuration structure from parse tree
1911 	 *
1912 	 * If param == NULL, there is no link_mem and the self_struct storage
1913 	 * is allocated and attached to its destination dynamically.
1914 	 *
1915 	 * @param config   [IN] root of parse tree
1916 	 * @param conf_blk [IN] pointer to configuration description
1917 	 * @param param    [IN] pointer to struct to fill or NULL
1918 	 * @param unique   [IN] bool if true, more than one is an error
1919 	 * @param err_type [OUT] pointer to error type return
1920 	 *
1921 	 * @returns number of blocks found. -1 on errors, errors are in err_type
1922 	 */
1923 	
1924 	int load_config_from_parse(config_file_t config,
1925 				   struct config_block *conf_blk,
1926 				   void *param,
1927 				   bool unique,
1928 				   struct config_error_type *err_type)
1929 	{
1930 		struct config_root *tree = (struct config_root *)config;
1931 		struct config_node *node = NULL;
1932 		struct glist_head *ns;
1933 		char *blkname = conf_blk->blk_desc.name;
1934 		int found = 0;
1935 		int prev_errs = err_type->errors;
1936 		void *blk_mem = NULL;
1937 	
1938 		if (tree == NULL) {
1939 			config_proc_error(NULL, err_type,
1940 					  "Missing parse tree root for (%s)",
1941 					  blkname);
1942 			err_type->missing = true;
1943 			return -1;
1944 		}
1945 		if (tree->root.type != TYPE_ROOT) {
1946 			config_proc_error(&tree->root, err_type,
1947 					  "Expected to start at parse tree root for (%s)",
1948 					  blkname);
1949 			err_type->internal = true;
1950 			return -1;
1951 		}
1952 		if (param != NULL) {
1953 			blk_mem = conf_blk->blk_desc.u.blk.init(NULL, param);
1954 			if (blk_mem == NULL) {
1955 				config_proc_error(&tree->root, err_type,
1956 						  "Top level block init failed for (%s)",
1957 						  blkname);
1958 				err_type->internal = true;
1959 				return -1;
1960 			}
1961 		}
1962 		glist_for_each(ns, &tree->root.u.nterm.sub_nodes) {
1963 			node = glist_entry(ns, struct config_node, node);
1964 			if (node->type == TYPE_BLOCK &&
1965 			    strcasecmp(blkname, node->u.nterm.name) == 0) {
1966 				if (found > 0 &&
1967 				    (conf_blk->blk_desc.flags & CONFIG_UNIQUE)) {
1968 					config_proc_error(node, err_type,
1969 							  "Only one %s block allowed",
1970 							  blkname);
1971 				} else {
1972 					if (!proc_block(node,
1973 							&conf_blk->blk_desc,
1974 							blk_mem,
1975 							err_type))
1976 						config_proc_error(node, err_type,
1977 								  "Errors processing block (%s)",
1978 								  blkname);
1979 					else
1980 						found++;
1981 				}
1982 			}
1983 		}
1984 		if (found == 0) {
1985 			/* Found nothing but we have to do the allocate and init
1986 			 * at least. Use a fake, not NULL link_mem */
1987 			blk_mem = param != NULL ?
1988 				param : conf_blk->blk_desc.u.blk.init((void *)~0UL,
1989 								      NULL);
1990 			assert(blk_mem != NULL);
1991 			if (!do_block_init(&tree->root,
1992 					   conf_blk->blk_desc.u.blk.params,
1993 					   blk_mem, err_type)) {
1994 				config_proc_error(&tree->root, err_type,
1995 						  "Could not initialize defaults for block %s",
1996 						  blkname);
1997 				err_type->init = true;
1998 			}
1999 		}
2000 		if (err_type->errors > prev_errs) {
2001 			char *errstr = err_type_str(err_type);
2002 	
2003 			config_proc_error(node, err_type,
2004 				 "%d %s errors found block %s",
2005 				 err_type->errors - prev_errs,
2006 				 errstr != NULL ? errstr : "unknown",
2007 				 blkname);
2008 			if (errstr != NULL)
2009 				gsh_free(errstr);
2010 		}
2011 		return found;
2012 	}
2013