1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
31*0Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
34*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
35*0Sstevel@tonic-gate #endif
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate #include <meta.h>
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #include <ctype.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate  * free md.tab struct
43*0Sstevel@tonic-gate  */
44*0Sstevel@tonic-gate void
45*0Sstevel@tonic-gate meta_tab_free(
46*0Sstevel@tonic-gate 	md_tab_t	*tabp
47*0Sstevel@tonic-gate )
48*0Sstevel@tonic-gate {
49*0Sstevel@tonic-gate 	size_t		line;
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate 	Free(tabp->filename);
52*0Sstevel@tonic-gate 	Free(tabp->data);
53*0Sstevel@tonic-gate 	if (tabp->lines != NULL) {
54*0Sstevel@tonic-gate 		assert(tabp->alloc > 0);
55*0Sstevel@tonic-gate 		for (line = 0; (line < tabp->nlines); ++line) {
56*0Sstevel@tonic-gate 			md_tab_line_t	*linep = &tabp->lines[line];
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate 			if (linep->context != NULL)
59*0Sstevel@tonic-gate 				Free(linep->context);
60*0Sstevel@tonic-gate 			if (linep->cname != NULL)
61*0Sstevel@tonic-gate 				Free(linep->cname);
62*0Sstevel@tonic-gate 			if (linep->argv != NULL) {
63*0Sstevel@tonic-gate 				assert(linep->alloc > 0);
64*0Sstevel@tonic-gate 				Free(linep->argv);
65*0Sstevel@tonic-gate 			}
66*0Sstevel@tonic-gate 		}
67*0Sstevel@tonic-gate 		Free(tabp->lines);
68*0Sstevel@tonic-gate 	}
69*0Sstevel@tonic-gate 	Free(tabp);
70*0Sstevel@tonic-gate }
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /*
73*0Sstevel@tonic-gate  * (re)allocate argv array
74*0Sstevel@tonic-gate  */
75*0Sstevel@tonic-gate static void
76*0Sstevel@tonic-gate realloc_argv(
77*0Sstevel@tonic-gate 	md_tab_line_t	*linep,
78*0Sstevel@tonic-gate 	size_t		argc
79*0Sstevel@tonic-gate )
80*0Sstevel@tonic-gate {
81*0Sstevel@tonic-gate 	/* allocate in chunks */
82*0Sstevel@tonic-gate 	argc = roundup(argc, TAB_ARG_ALLOC);
83*0Sstevel@tonic-gate 	if (argc < linep->alloc)
84*0Sstevel@tonic-gate 		return;
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	/* (re)allocate */
87*0Sstevel@tonic-gate 	if (linep->alloc == 0) {
88*0Sstevel@tonic-gate 		linep->argv = Malloc(argc * sizeof (*linep->argv));
89*0Sstevel@tonic-gate 	} else {
90*0Sstevel@tonic-gate 		assert(linep->argv != NULL);
91*0Sstevel@tonic-gate 		linep->argv =
92*0Sstevel@tonic-gate 		    Realloc(linep->argv, (argc * sizeof (*linep->argv)));
93*0Sstevel@tonic-gate 	}
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate 	/* zero out new stuff */
96*0Sstevel@tonic-gate 	(void) memset(&linep->argv[linep->alloc], 0,
97*0Sstevel@tonic-gate 	    ((argc - linep->alloc) * sizeof (*linep->argv)));
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	/* adjust for new size */
100*0Sstevel@tonic-gate 	linep->alloc = argc;
101*0Sstevel@tonic-gate }
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate /*
104*0Sstevel@tonic-gate  * (re)allocate line array
105*0Sstevel@tonic-gate  */
106*0Sstevel@tonic-gate static void
107*0Sstevel@tonic-gate realloc_lines(
108*0Sstevel@tonic-gate 	md_tab_t	*tabp,
109*0Sstevel@tonic-gate 	size_t		nlines
110*0Sstevel@tonic-gate )
111*0Sstevel@tonic-gate {
112*0Sstevel@tonic-gate 	/* allocate in chunks */
113*0Sstevel@tonic-gate 	nlines = roundup(nlines, TAB_LINE_ALLOC);
114*0Sstevel@tonic-gate 	if (nlines < tabp->alloc)
115*0Sstevel@tonic-gate 		return;
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	/* (re)allocate */
118*0Sstevel@tonic-gate 	if (tabp->alloc == 0) {
119*0Sstevel@tonic-gate 		assert(tabp->lines == NULL);
120*0Sstevel@tonic-gate 		tabp->lines = Malloc(nlines * sizeof (*tabp->lines));
121*0Sstevel@tonic-gate 	} else {
122*0Sstevel@tonic-gate 		assert(tabp->lines != NULL);
123*0Sstevel@tonic-gate 		tabp->lines =
124*0Sstevel@tonic-gate 		    Realloc(tabp->lines, (nlines * sizeof (*tabp->lines)));
125*0Sstevel@tonic-gate 	}
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	/* zero out new stuff */
128*0Sstevel@tonic-gate 	(void) memset(&tabp->lines[tabp->alloc], 0,
129*0Sstevel@tonic-gate 	    ((nlines - tabp->alloc) * sizeof (*tabp->lines)));
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	/* adjust for new size */
132*0Sstevel@tonic-gate 	tabp->alloc = nlines;
133*0Sstevel@tonic-gate }
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate /*
136*0Sstevel@tonic-gate  * parse up md.tab struct
137*0Sstevel@tonic-gate  */
138*0Sstevel@tonic-gate static void
139*0Sstevel@tonic-gate parse_tab(
140*0Sstevel@tonic-gate 	md_tab_t	*tabp
141*0Sstevel@tonic-gate )
142*0Sstevel@tonic-gate {
143*0Sstevel@tonic-gate 	uint_t		lineno = 1;
144*0Sstevel@tonic-gate 	char		*p = tabp->data;
145*0Sstevel@tonic-gate 	char		*e = tabp->data + tabp->total - 1;
146*0Sstevel@tonic-gate 	char		*context;
147*0Sstevel@tonic-gate 	size_t		len;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	/* we can count on '\n\0' as the last characters */
150*0Sstevel@tonic-gate 	assert(tabp->total >= 2);
151*0Sstevel@tonic-gate 	assert(tabp->data[tabp->total - 2] == '\n');
152*0Sstevel@tonic-gate 	assert(tabp->data[tabp->total - 1] == '\0');
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	/* allocate context buffer "file line XXX" */
155*0Sstevel@tonic-gate 	assert(tabp->filename != NULL);
156*0Sstevel@tonic-gate 	len = strlen(tabp->filename) +
157*0Sstevel@tonic-gate 	    strlen(dgettext(TEXT_DOMAIN, "%s line %u")) + 20 + 1;
158*0Sstevel@tonic-gate 	context = Malloc(len);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	/* parse lines */
161*0Sstevel@tonic-gate 	while (p < e) {
162*0Sstevel@tonic-gate 		md_tab_line_t	*linep;
163*0Sstevel@tonic-gate 		char		*t;
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 		/* allocate new line */
166*0Sstevel@tonic-gate 		realloc_lines(tabp, (tabp->nlines + 1));
167*0Sstevel@tonic-gate 		linep = &tabp->lines[tabp->nlines];
168*0Sstevel@tonic-gate 		(void) snprintf(context, len,
169*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "%s line %u"), tabp->filename,
170*0Sstevel@tonic-gate 		    lineno);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 		/* comments */
173*0Sstevel@tonic-gate 		if (*p == '#') {
174*0Sstevel@tonic-gate 			while (*p != '\n')
175*0Sstevel@tonic-gate 				++p;
176*0Sstevel@tonic-gate 		}
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 		/* coalesce \ continuations */
179*0Sstevel@tonic-gate 		t = p;
180*0Sstevel@tonic-gate 		while (*t != '\n') {
181*0Sstevel@tonic-gate 			if ((*t == '\\') && (*(t + 1) == '\n')) {
182*0Sstevel@tonic-gate 				*t++ = ' ';
183*0Sstevel@tonic-gate 				*t = ' ';
184*0Sstevel@tonic-gate 				++lineno;
185*0Sstevel@tonic-gate 			}
186*0Sstevel@tonic-gate 			++t;
187*0Sstevel@tonic-gate 		}
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate 		/* leading whitespace */
190*0Sstevel@tonic-gate 		while ((*p != '\n') && (isspace(*p)))
191*0Sstevel@tonic-gate 			++p;
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 		/* count lines */
194*0Sstevel@tonic-gate 		if (*p == '\n') {
195*0Sstevel@tonic-gate 			++p;
196*0Sstevel@tonic-gate 			++lineno;
197*0Sstevel@tonic-gate 			continue;
198*0Sstevel@tonic-gate 		}
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 		/* tokenize line */
201*0Sstevel@tonic-gate 		while ((p < e) && (*p != '\n')) {
202*0Sstevel@tonic-gate 			char	**argvp;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 			/* allocate new token */
205*0Sstevel@tonic-gate 			realloc_argv(linep, (linep->argc + 1));
206*0Sstevel@tonic-gate 			argvp = &linep->argv[linep->argc++];
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 			/* find end of token */
209*0Sstevel@tonic-gate 			*argvp = p;
210*0Sstevel@tonic-gate 			while ((*p != '\n') && (! isspace(*p)))
211*0Sstevel@tonic-gate 				++p;
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 			/* terminate */
214*0Sstevel@tonic-gate 			if (*p == '\n') {
215*0Sstevel@tonic-gate 				*p++ = '\0';
216*0Sstevel@tonic-gate 				++lineno;
217*0Sstevel@tonic-gate 				break;
218*0Sstevel@tonic-gate 			}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 			/* eat white space */
221*0Sstevel@tonic-gate 			*p++ = '\0';
222*0Sstevel@tonic-gate 			while ((p < e) && (*p != '\n') && (isspace(*p)))
223*0Sstevel@tonic-gate 				++p;
224*0Sstevel@tonic-gate 		}
225*0Sstevel@tonic-gate 		tabp->nlines++;
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 		/* fill in the rest */
228*0Sstevel@tonic-gate 		assert((linep->argc > 0) && (linep->argv != NULL) &&
229*0Sstevel@tonic-gate 		    (linep->argv[0][0] != '\0') &&
230*0Sstevel@tonic-gate 		    (! isspace(linep->argv[0][0])));
231*0Sstevel@tonic-gate 		linep->context = Strdup(context);
232*0Sstevel@tonic-gate 		linep->type = meta_get_init_type(linep->argc, linep->argv);
233*0Sstevel@tonic-gate 		linep->cname = Strdup(meta_canonicalize(NULL, linep->argv[0]));
234*0Sstevel@tonic-gate 		assert(linep->cname != NULL);
235*0Sstevel@tonic-gate 	}
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	/* cleanup */
238*0Sstevel@tonic-gate 	Free(context);
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate /*
242*0Sstevel@tonic-gate  * read in md.tab file and return struct
243*0Sstevel@tonic-gate  */
244*0Sstevel@tonic-gate md_tab_t *
245*0Sstevel@tonic-gate meta_tab_parse(
246*0Sstevel@tonic-gate 	char		*filename,
247*0Sstevel@tonic-gate 	md_error_t	*ep
248*0Sstevel@tonic-gate )
249*0Sstevel@tonic-gate {
250*0Sstevel@tonic-gate 	md_tab_t	*tabp = NULL;
251*0Sstevel@tonic-gate 	int		fd = -1;
252*0Sstevel@tonic-gate 	struct stat	statbuf;
253*0Sstevel@tonic-gate 	size_t		sofar;
254*0Sstevel@tonic-gate 	char		*p;
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	/* open tab file */
257*0Sstevel@tonic-gate 	if (filename == NULL)
258*0Sstevel@tonic-gate 		filename = METATAB;
259*0Sstevel@tonic-gate 	if ((fd = open(filename, O_RDONLY, 0)) < 0) {
260*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, filename);
261*0Sstevel@tonic-gate 		goto out;
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 	if (fstat(fd, &statbuf) != 0) {
264*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, filename);
265*0Sstevel@tonic-gate 		goto out;
266*0Sstevel@tonic-gate 	}
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	/* allocate table */
269*0Sstevel@tonic-gate 	tabp = Zalloc(sizeof (*tabp));
270*0Sstevel@tonic-gate 	tabp->filename = Strdup(filename);
271*0Sstevel@tonic-gate 	tabp->total = statbuf.st_size + 2;	/* terminating "\n\0" */
272*0Sstevel@tonic-gate 	tabp->data = Malloc(tabp->total);
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	/* read in data */
275*0Sstevel@tonic-gate 	sofar = 0;
276*0Sstevel@tonic-gate 	p = tabp->data;
277*0Sstevel@tonic-gate 	while (sofar < statbuf.st_size) {
278*0Sstevel@tonic-gate 		int	cnt;
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 		if ((cnt = read(fd, p, 8192)) < 0) {
281*0Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, filename);
282*0Sstevel@tonic-gate 			goto out;
283*0Sstevel@tonic-gate 		} else if (cnt == 0) {
284*0Sstevel@tonic-gate 			(void) mderror(ep, MDE_SYNTAX, filename);
285*0Sstevel@tonic-gate 			goto out;
286*0Sstevel@tonic-gate 		}
287*0Sstevel@tonic-gate 		sofar += cnt;
288*0Sstevel@tonic-gate 		p += cnt;
289*0Sstevel@tonic-gate 	}
290*0Sstevel@tonic-gate 	tabp->data[tabp->total - 2] = '\n';
291*0Sstevel@tonic-gate 	tabp->data[tabp->total - 1] = '\0';
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	/* close file */
294*0Sstevel@tonic-gate 	if (close(fd) != 0) {
295*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, filename);
296*0Sstevel@tonic-gate 		fd = -1;
297*0Sstevel@tonic-gate 		goto out;
298*0Sstevel@tonic-gate 	}
299*0Sstevel@tonic-gate 	fd = -1;
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 	/* parse it up */
302*0Sstevel@tonic-gate 	parse_tab(tabp);
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	/* return success */
305*0Sstevel@tonic-gate 	return (tabp);
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	/* cleanup, return error */
308*0Sstevel@tonic-gate out:
309*0Sstevel@tonic-gate 	if (fd >= 0)
310*0Sstevel@tonic-gate 		(void) close(fd);
311*0Sstevel@tonic-gate 	if (tabp != NULL)
312*0Sstevel@tonic-gate 		meta_tab_free(tabp);
313*0Sstevel@tonic-gate 	return (NULL);
314*0Sstevel@tonic-gate }
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate /*
317*0Sstevel@tonic-gate  * find line in md.tab
318*0Sstevel@tonic-gate  */
319*0Sstevel@tonic-gate md_tab_line_t *
320*0Sstevel@tonic-gate meta_tab_find(
321*0Sstevel@tonic-gate 	mdsetname_t	*sp,
322*0Sstevel@tonic-gate 	md_tab_t	*tabp,
323*0Sstevel@tonic-gate 	char		*name,
324*0Sstevel@tonic-gate 	mdinittypes_t	type
325*0Sstevel@tonic-gate )
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	char		*cname = meta_canonicalize(sp, name);
328*0Sstevel@tonic-gate 	size_t		line;
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	for (line = 0; (line < tabp->nlines); ++line) {
331*0Sstevel@tonic-gate 		md_tab_line_t	*linep = &tabp->lines[line];
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 		assert((linep->argc > 0) && (linep->argv[0] != NULL));
334*0Sstevel@tonic-gate 		if (((linep->type & type) != 0) &&
335*0Sstevel@tonic-gate 		    (strcmp(linep->cname, cname) == 0)) {
336*0Sstevel@tonic-gate 			Free(cname);
337*0Sstevel@tonic-gate 			return (linep);
338*0Sstevel@tonic-gate 		}
339*0Sstevel@tonic-gate 	}
340*0Sstevel@tonic-gate 	Free(cname);
341*0Sstevel@tonic-gate 	return (NULL);
342*0Sstevel@tonic-gate }
343