OpenSolaris_b135/lib/lvm/libmeta/common/meta_tab.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * Just in case we're not in a build environment, make sure that
 * TEXT_DOMAIN gets set to something.
 */
#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SYS_TEST"
#endif

#include <meta.h>

#include <ctype.h>

/*
 * free md.tab struct
 */
void
meta_tab_free(
	md_tab_t	*tabp
)
{
	size_t		line;

	Free(tabp->filename);
	Free(tabp->data);
	if (tabp->lines != NULL) {
		assert(tabp->alloc > 0);
		for (line = 0; (line < tabp->nlines); ++line) {
			md_tab_line_t	*linep = &tabp->lines[line];

			if (linep->context != NULL)
				Free(linep->context);
			if (linep->cname != NULL)
				Free(linep->cname);
			if (linep->argv != NULL) {
				assert(linep->alloc > 0);
				Free(linep->argv);
			}
		}
		Free(tabp->lines);
	}
	Free(tabp);
}

/*
 * (re)allocate argv array
 */
static void
realloc_argv(
	md_tab_line_t	*linep,
	size_t		argc
)
{
	/* allocate in chunks */
	argc = roundup(argc, TAB_ARG_ALLOC);
	if (argc < linep->alloc)
		return;

	/* (re)allocate */
	if (linep->alloc == 0) {
		linep->argv = Malloc(argc * sizeof (*linep->argv));
	} else {
		assert(linep->argv != NULL);
		linep->argv =
		    Realloc(linep->argv, (argc * sizeof (*linep->argv)));
	}

	/* zero out new stuff */
	(void) memset(&linep->argv[linep->alloc], 0,
	    ((argc - linep->alloc) * sizeof (*linep->argv)));

	/* adjust for new size */
	linep->alloc = argc;
}

/*
 * (re)allocate line array
 */
static void
realloc_lines(
	md_tab_t	*tabp,
	size_t		nlines
)
{
	/* allocate in chunks */
	nlines = roundup(nlines, TAB_LINE_ALLOC);
	if (nlines < tabp->alloc)
		return;

	/* (re)allocate */
	if (tabp->alloc == 0) {
		assert(tabp->lines == NULL);
		tabp->lines = Malloc(nlines * sizeof (*tabp->lines));
	} else {
		assert(tabp->lines != NULL);
		tabp->lines =
		    Realloc(tabp->lines, (nlines * sizeof (*tabp->lines)));
	}

	/* zero out new stuff */
	(void) memset(&tabp->lines[tabp->alloc], 0,
	    ((nlines - tabp->alloc) * sizeof (*tabp->lines)));

	/* adjust for new size */
	tabp->alloc = nlines;
}

/*
 * parse up md.tab struct
 */
static void
parse_tab(
	md_tab_t	*tabp,
	char		*metatab_name,
	md_error_t	*ep
)
{
	uint_t		lineno = 1;
	char		*p = tabp->data;
	char		*e = tabp->data + tabp->total - 1;
	char		*context;
	size_t		len;

	/* we can count on '\n\0' as the last characters */
	assert(tabp->total >= 2);
	assert(tabp->data[tabp->total - 2] == '\n');
	assert(tabp->data[tabp->total - 1] == '\0');

	/* allocate context buffer "file line XXX" */
	assert(tabp->filename != NULL);
	len = strlen(tabp->filename) +
	    strlen(dgettext(TEXT_DOMAIN, "%s line %u")) + 20 + 1;
	context = Malloc(len);

	/* parse lines */
	while (p < e && *p != '\0') {
		md_tab_line_t	*linep;
		char		*t;

		/* allocate new line */
		realloc_lines(tabp, (tabp->nlines + 1));
		linep = &tabp->lines[tabp->nlines];
		(void) snprintf(context, len,
		    dgettext(TEXT_DOMAIN, "%s line %u"), tabp->filename,
		    lineno);

		/* comments */
		if (*p == '#') {
			while (*p != '\n')
				++p;
		}

		/* coalesce \ continuations */
		t = p;
		while (*t != '\n') {
			if ((*t == '\\') && (*(t + 1) == '\n')) {
				*t++ = ' ';
				*t = ' ';
				++lineno;
			}
			++t;
		}

		/* leading whitespace */
		while ((*p != '\n') && (isspace(*p)))
			++p;

		/* count lines */
		if (*p == '\n') {
			++p;
			++lineno;
			continue;
		}

		/* tokenize line */
		while ((p < e) && (*p != '\n')) {
			char	**argvp;

			/* allocate new token */
			realloc_argv(linep, (linep->argc + 1));
			argvp = &linep->argv[linep->argc++];

			/* find end of token */
			*argvp = p;
			while ((*p != '\n') && (! isspace(*p)))
				++p;

			/* terminate */
			if (*p == '\n') {
				*p++ = '\0';
				++lineno;
				break;
			}

			/* eat white space */
			*p++ = '\0';
			while ((p < e) && (*p != '\n') && (isspace(*p)))
				++p;
		}
		tabp->nlines++;

		/* fill in the rest */
		assert((linep->argc > 0) && (linep->argv != NULL) &&
		    (linep->argv[0][0] != '\0') &&
		    (! isspace(linep->argv[0][0])));
		linep->context = Strdup(context);
		linep->type = meta_get_init_type(linep->argc, linep->argv);
		linep->cname = meta_canonicalize(NULL, linep->argv[0]);
		/* if cname is NULL then the meta/hsp name is invalid */
		if (linep->cname == NULL) {
			(void) mderror(ep, MDE_SYNTAX, metatab_name);
			break;
		}
	}

	/* cleanup */
	Free(context);
}

/*
 * read in md.tab file and return struct
 */
md_tab_t *
meta_tab_parse(
	char		*filename,
	md_error_t	*ep
)
{
	md_tab_t	*tabp = NULL;
	int		fd = -1;
	struct stat	statbuf;
	size_t		sofar;
	char		*p;

	/* open tab file */
	if (filename == NULL)
		filename = METATAB;
	if ((fd = open(filename, O_RDONLY, 0)) < 0) {
		(void) mdsyserror(ep, errno, filename);
		goto out;
	}
	if (fstat(fd, &statbuf) != 0) {
		(void) mdsyserror(ep, errno, filename);
		goto out;
	}

	/* allocate table */
	tabp = Zalloc(sizeof (*tabp));
	tabp->filename = Strdup(filename);
	tabp->total = statbuf.st_size + 2;	/* terminating "\n\0" */
	tabp->data = Malloc(tabp->total);

	/* read in data */
	sofar = 0;
	p = tabp->data;
	while (sofar < statbuf.st_size) {
		int	cnt;

		if ((cnt = read(fd, p, 8192)) < 0) {
			(void) mdsyserror(ep, errno, filename);
			goto out;
		} else if (cnt == 0) {
			(void) mderror(ep, MDE_SYNTAX, filename);
			goto out;
		}
		sofar += cnt;
		p += cnt;
	}
	tabp->data[tabp->total - 2] = '\n';
	tabp->data[tabp->total - 1] = '\0';

	/* close file */
	if (close(fd) != 0) {
		(void) mdsyserror(ep, errno, filename);
		fd = -1;
		goto out;
	}
	fd = -1;

	/* parse it up */
	parse_tab(tabp, filename, ep);

	/* return success if file was correctly parsed */
	if (mdisok(ep))
		return (tabp);

	/* cleanup, return error */
out:
	if (fd >= 0)
		(void) close(fd);
	if (tabp != NULL)
		meta_tab_free(tabp);
	return (NULL);
}

/*
 * find line in md.tab
 */
md_tab_line_t *
meta_tab_find(
	mdsetname_t	*sp,
	md_tab_t	*tabp,
	char		*name,
	mdinittypes_t	type
)
{
	char		*cname = meta_canonicalize(sp, name);
	size_t		line;

	/* if name is not legal meta name then return NULL */
	if (cname == NULL)
		return (NULL);

	for (line = 0; (line < tabp->nlines); ++line) {
		md_tab_line_t	*linep = &tabp->lines[line];

		assert((linep->argc > 0) && (linep->argv[0] != NULL));
		if (((linep->type & type) != 0) &&
		    (strcmp(linep->cname, cname) == 0)) {
			Free(cname);
			return (linep);
		}
	}
	Free(cname);
	return (NULL);
}