xref: /illumos-gate/usr/src/common/definit/definit.c (revision a28480fe)
1*a28480feSAndy Fiddaman /*
2*a28480feSAndy Fiddaman  * CDDL HEADER START
3*a28480feSAndy Fiddaman  *
4*a28480feSAndy Fiddaman  * The contents of this file are subject to the terms of the
5*a28480feSAndy Fiddaman  * Common Development and Distribution License (the "License").
6*a28480feSAndy Fiddaman  * You may not use this file except in compliance with the License.
7*a28480feSAndy Fiddaman  *
8*a28480feSAndy Fiddaman  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a28480feSAndy Fiddaman  * or http://www.opensolaris.org/os/licensing.
10*a28480feSAndy Fiddaman  * See the License for the specific language governing permissions
11*a28480feSAndy Fiddaman  * and limitations under the License.
12*a28480feSAndy Fiddaman  *
13*a28480feSAndy Fiddaman  * When distributing Covered Code, include this CDDL HEADER in each
14*a28480feSAndy Fiddaman  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a28480feSAndy Fiddaman  * If applicable, add the following below this CDDL HEADER, with the
16*a28480feSAndy Fiddaman  * fields enclosed by brackets "[]" replaced with your own identifying
17*a28480feSAndy Fiddaman  * information: Portions Copyright [yyyy] [name of copyright owner]
18*a28480feSAndy Fiddaman  *
19*a28480feSAndy Fiddaman  * CDDL HEADER END
20*a28480feSAndy Fiddaman  */
21*a28480feSAndy Fiddaman /*
22*a28480feSAndy Fiddaman  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*a28480feSAndy Fiddaman  * Use is subject to license terms.
24*a28480feSAndy Fiddaman  *
25*a28480feSAndy Fiddaman  * Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
26*a28480feSAndy Fiddaman  */
27*a28480feSAndy Fiddaman 
28*a28480feSAndy Fiddaman #include <stdio.h>
29*a28480feSAndy Fiddaman #include <stdlib.h>
30*a28480feSAndy Fiddaman #include <string.h>
31*a28480feSAndy Fiddaman #include <errno.h>
32*a28480feSAndy Fiddaman #include <sys/types.h>
33*a28480feSAndy Fiddaman #include <definit.h>
34*a28480feSAndy Fiddaman 
35*a28480feSAndy Fiddaman /* Tokens are separated by spaces, tabs and newlines. */
36*a28480feSAndy Fiddaman #define	SEPARATORS " \t\n"
37*a28480feSAndy Fiddaman 
38*a28480feSAndy Fiddaman typedef struct definit {
39*a28480feSAndy Fiddaman 	FILE *di_fp;
40*a28480feSAndy Fiddaman 	char *di_line;
41*a28480feSAndy Fiddaman 	char *di_tok;
42*a28480feSAndy Fiddaman } definit_t;
43*a28480feSAndy Fiddaman 
44*a28480feSAndy Fiddaman int
definit_open(const char * file,void ** statep)45*a28480feSAndy Fiddaman definit_open(const char *file, void **statep)
46*a28480feSAndy Fiddaman {
47*a28480feSAndy Fiddaman 	FILE *fp;
48*a28480feSAndy Fiddaman 	int _errno;
49*a28480feSAndy Fiddaman 	definit_t *state = NULL;
50*a28480feSAndy Fiddaman 
51*a28480feSAndy Fiddaman 	if ((fp = fopen(file, "r")) == NULL)
52*a28480feSAndy Fiddaman 		return (-1);
53*a28480feSAndy Fiddaman 
54*a28480feSAndy Fiddaman 	if ((state = calloc(1, sizeof (*state))) == NULL)
55*a28480feSAndy Fiddaman 		goto err;
56*a28480feSAndy Fiddaman 
57*a28480feSAndy Fiddaman 	if ((state->di_line = calloc(DEFINIT_MAXLINE, sizeof (char))) == NULL)
58*a28480feSAndy Fiddaman 		goto err;
59*a28480feSAndy Fiddaman 
60*a28480feSAndy Fiddaman 	state->di_fp = fp;
61*a28480feSAndy Fiddaman 	*statep = state;
62*a28480feSAndy Fiddaman 
63*a28480feSAndy Fiddaman 	return (0);
64*a28480feSAndy Fiddaman 
65*a28480feSAndy Fiddaman err:
66*a28480feSAndy Fiddaman 	_errno = errno;
67*a28480feSAndy Fiddaman 	(void) fclose(fp);
68*a28480feSAndy Fiddaman 	if (state != NULL) {
69*a28480feSAndy Fiddaman 		free(state->di_line);
70*a28480feSAndy Fiddaman 		free(state);
71*a28480feSAndy Fiddaman 	}
72*a28480feSAndy Fiddaman 	errno = _errno;
73*a28480feSAndy Fiddaman 	return (-1);
74*a28480feSAndy Fiddaman }
75*a28480feSAndy Fiddaman 
76*a28480feSAndy Fiddaman void
definit_close(void * statep)77*a28480feSAndy Fiddaman definit_close(void *statep)
78*a28480feSAndy Fiddaman {
79*a28480feSAndy Fiddaman 	definit_t *state = statep;
80*a28480feSAndy Fiddaman 
81*a28480feSAndy Fiddaman 	(void) fclose(state->di_fp);
82*a28480feSAndy Fiddaman 	free(state->di_line);
83*a28480feSAndy Fiddaman 	free(state);
84*a28480feSAndy Fiddaman }
85*a28480feSAndy Fiddaman 
86*a28480feSAndy Fiddaman /*
87*a28480feSAndy Fiddaman  * This parser was written to produce the same output as the ones it replaced
88*a28480feSAndy Fiddaman  * in init and svc.startd. As such it has some shortcomings:
89*a28480feSAndy Fiddaman  * - Values may be quoted but the quotes are just stripped and separators such
90*a28480feSAndy Fiddaman  *   as whitespace are not treated specially within quotes;
91*a28480feSAndy Fiddaman  * - Lines which are longer than DEFINIT_MAXLINE -1 bytes are split. Tokens
92*a28480feSAndy Fiddaman  *   which span a split will be truncated, one way or another.
93*a28480feSAndy Fiddaman  * - Comments at the end of a line (after a token) are not supported.
94*a28480feSAndy Fiddaman  * These could be corrected in the future if strict backwards compatibility is
95*a28480feSAndy Fiddaman  * not required.
96*a28480feSAndy Fiddaman  */
97*a28480feSAndy Fiddaman 
98*a28480feSAndy Fiddaman static char *
definit_nextline(definit_t * state)99*a28480feSAndy Fiddaman definit_nextline(definit_t *state)
100*a28480feSAndy Fiddaman {
101*a28480feSAndy Fiddaman 	char *line;
102*a28480feSAndy Fiddaman 
103*a28480feSAndy Fiddaman 	while ((line = fgets(state->di_line, DEFINIT_MAXLINE, state->di_fp))
104*a28480feSAndy Fiddaman 	    != NULL) {
105*a28480feSAndy Fiddaman 		boolean_t inquotes;
106*a28480feSAndy Fiddaman 		char *p, *bp;
107*a28480feSAndy Fiddaman 		size_t wslength;
108*a28480feSAndy Fiddaman 
109*a28480feSAndy Fiddaman 		/*
110*a28480feSAndy Fiddaman 		 * Ignore blank or comment lines.
111*a28480feSAndy Fiddaman 		 */
112*a28480feSAndy Fiddaman 		if (line[0] == '#' || line[0] == '\0' ||
113*a28480feSAndy Fiddaman 		    (wslength = strspn(line, SEPARATORS)) == strlen(line) ||
114*a28480feSAndy Fiddaman 		    line[wslength] == '#') {
115*a28480feSAndy Fiddaman 			continue;
116*a28480feSAndy Fiddaman 		}
117*a28480feSAndy Fiddaman 
118*a28480feSAndy Fiddaman 		/*
119*a28480feSAndy Fiddaman 		 * Make a pass through the line and:
120*a28480feSAndy Fiddaman 		 * - Replace any non-quoted semicolons with spaces;
121*a28480feSAndy Fiddaman 		 * - Remove any quote characters.
122*a28480feSAndy Fiddaman 		 *
123*a28480feSAndy Fiddaman 		 * While walking this, 'p' is the current position in the line
124*a28480feSAndy Fiddaman 		 * and, if any characters have been found which need to be
125*a28480feSAndy Fiddaman 		 * removed, 'bp' tracks the position in the line where
126*a28480feSAndy Fiddaman 		 * subsequent characters need to be written in order to close
127*a28480feSAndy Fiddaman 		 * the gap; 'bp' trails 'p'.
128*a28480feSAndy Fiddaman 		 * If 'bp' is NULL, no characters to remove have been found.
129*a28480feSAndy Fiddaman 		 */
130*a28480feSAndy Fiddaman 		inquotes = B_FALSE;
131*a28480feSAndy Fiddaman 		for (p = line, bp = NULL; *p != '\0'; p++) {
132*a28480feSAndy Fiddaman 			switch (*p) {
133*a28480feSAndy Fiddaman 			case '"':
134*a28480feSAndy Fiddaman 			case '\'':
135*a28480feSAndy Fiddaman 				inquotes = !inquotes;
136*a28480feSAndy Fiddaman 				if (bp == NULL)
137*a28480feSAndy Fiddaman 					bp = p;
138*a28480feSAndy Fiddaman 				break;
139*a28480feSAndy Fiddaman 			case ';':
140*a28480feSAndy Fiddaman 				if (!inquotes)
141*a28480feSAndy Fiddaman 					*p = ' ';
142*a28480feSAndy Fiddaman 				/* FALLTHROUGH */
143*a28480feSAndy Fiddaman 			default:
144*a28480feSAndy Fiddaman 				if (bp != NULL)
145*a28480feSAndy Fiddaman 					*bp++ = *p;
146*a28480feSAndy Fiddaman 				break;
147*a28480feSAndy Fiddaman 			}
148*a28480feSAndy Fiddaman 		}
149*a28480feSAndy Fiddaman 		if (bp != NULL)
150*a28480feSAndy Fiddaman 			*bp = '\0';
151*a28480feSAndy Fiddaman 
152*a28480feSAndy Fiddaman 		/*
153*a28480feSAndy Fiddaman 		 * Perform an initial strtok_r() call on the new line.
154*a28480feSAndy Fiddaman 		 * definit_token() will repeatedly call strtok_r() until the
155*a28480feSAndy Fiddaman 		 * line is consumed, and then call this function again for
156*a28480feSAndy Fiddaman 		 * more input.
157*a28480feSAndy Fiddaman 		 */
158*a28480feSAndy Fiddaman 		if ((p = strtok_r(line, SEPARATORS, &state->di_tok)) != NULL)
159*a28480feSAndy Fiddaman 			return (p);
160*a28480feSAndy Fiddaman 	}
161*a28480feSAndy Fiddaman 
162*a28480feSAndy Fiddaman 	return (NULL);
163*a28480feSAndy Fiddaman }
164*a28480feSAndy Fiddaman 
165*a28480feSAndy Fiddaman const char *
definit_token(void * statep)166*a28480feSAndy Fiddaman definit_token(void *statep)
167*a28480feSAndy Fiddaman {
168*a28480feSAndy Fiddaman 	definit_t *state = statep;
169*a28480feSAndy Fiddaman 	char *tok;
170*a28480feSAndy Fiddaman 
171*a28480feSAndy Fiddaman 	for (;;) {
172*a28480feSAndy Fiddaman 		tok = NULL;
173*a28480feSAndy Fiddaman 
174*a28480feSAndy Fiddaman 		if (state->di_tok != NULL)
175*a28480feSAndy Fiddaman 			tok = strtok_r(NULL, SEPARATORS, &state->di_tok);
176*a28480feSAndy Fiddaman 
177*a28480feSAndy Fiddaman 		if (tok == NULL)
178*a28480feSAndy Fiddaman 			tok = definit_nextline(state);
179*a28480feSAndy Fiddaman 
180*a28480feSAndy Fiddaman 		if (tok == NULL)
181*a28480feSAndy Fiddaman 			break;
182*a28480feSAndy Fiddaman 
183*a28480feSAndy Fiddaman 		if (strchr(tok, '=') != NULL && *tok != '=')
184*a28480feSAndy Fiddaman 			return (tok);
185*a28480feSAndy Fiddaman 	}
186*a28480feSAndy Fiddaman 
187*a28480feSAndy Fiddaman 	return (NULL);
188*a28480feSAndy Fiddaman }
189