conffile.c revision 1.1
1/* $NetBSD: conffile.c,v 1.1 2010/12/30 11:29:21 kefren Exp $ */
2
3/*
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mihai Chelaru <kefren@NetBSD.org>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <arpa/inet.h>
33#include <netinet/in.h>
34
35#include <ctype.h>
36#include <fcntl.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#include "conffile.h"
42#include "ldp_errors.h"
43
44#define NextCommand(x) strsep(&x, " ")
45#define LINEMAXSIZE 1024
46
47extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
48	min_label, max_label;
49int confh;
50struct in_addr conf_ldp_id;
51
52static int conf_dispatch(char*);
53static int conf_readline(char*, int);
54static int checkeol(char*);
55static int Fhellotime(char*);
56static int Fport(char*);
57static int Fholddown(char*);
58static int Fkeepalive(char*);
59static int Fmaxlabel(char*);
60static int Fminlabel(char*);
61static int Fldpid(char*);
62static int Fneighbour(char*);
63static int Gneighbour(struct conf_neighbour *, char *);
64
65struct conf_func {
66	char com[64];
67	int (* func)(char *);
68};
69
70struct conf_func main_commands[] = {
71	{ "hello-time", Fhellotime },
72	{ "keepalive-time", Fkeepalive },
73	{ "holddown-time", Fholddown },
74	{ "command-port", Fport },
75	{ "min-label", Fminlabel },
76	{ "max-label", Fmaxlabel },
77	{ "LDP-ID", Fldpid },
78	{ "neighbor", Fneighbour },
79	{ "neighbour", Fneighbour },
80	{ "", NULL },
81};
82
83/*
84 * Parses config file
85 */
86int
87conf_parsefile(char *fname)
88{
89	int i;
90	char buf[LINEMAXSIZE + 1];
91
92	SLIST_INIT(&conei_head);
93	conf_ldp_id.s_addr = 0;
94
95	confh = open(fname, O_RDONLY, 0);
96
97	if (confh == -1)
98		return E_CONF_IO;
99
100	for (i = 1; conf_readline(buf, sizeof(buf)) >= 0; i++)
101		if (conf_dispatch(buf) != 0) {
102			close(confh);
103			return i;
104		}
105
106	close(confh);
107	return 0;
108}
109
110/*
111 * Reads a line from config file
112 */
113int
114conf_readline(char *buf, int bufsize)
115{
116	int i;
117
118	for (i = 0; i < bufsize; i++) {
119		if (read(confh, &buf[i], 1) != 1) {
120			if (i == 0)
121				return E_CONF_IO;
122			break;
123		}
124		if (buf[i] == '\n')
125			break;
126		if (i == 0 && isspace((int)buf[i]) != 0) {
127			i--;
128			continue;
129		}
130	}
131	if (i == bufsize)
132		return E_CONF_MEM;
133	buf[i] = '\0';
134	return i;
135}
136
137/*
138 * Looks for a matching command on a line
139 */
140int
141conf_dispatch(char *line)
142{
143	int i, last_match = -1, matched = 0;
144	char *command, *nline = line;
145
146	if (strlen(line) == 0 || line[0] == '#')
147		return E_CONF_OK;
148	command = NextCommand(nline);
149	for (i = 0; main_commands[i].func != NULL; i++)
150		if (strncasecmp(main_commands[i].com, command,
151		    strlen(command)) == 0) {
152			matched++;
153			last_match = i;
154		}
155	if (matched == 0)
156		return E_CONF_NOMATCH;
157	else if (matched > 1)
158		return E_CONF_AMBIGUOUS;
159
160	if (checkeol(nline) != 0)
161		return E_CONF_PARAM;
162	return main_commands[last_match].func(nline);
163}
164
165/*
166 * Checks if a line is terminated or else if it contains
167 * a start block bracket. If it's semicolon terminated
168 * then trim it.
169 */
170int
171checkeol(char *line)
172{
173	if (line[strlen(line) - 1] == ';') {
174		line[strlen(line) - 1] = '\0';
175		return 0;
176	}
177	for (uint i = 0; i < strlen(line); i++)
178		if (line[i] == '{')
179			return 0;
180	return -1;
181}
182
183/*
184 * Sets hello time
185 */
186int
187Fhellotime(char *line)
188{
189	int ht = atoi(line);
190	if (ht <= 0)
191		return E_CONF_PARAM;
192	ldp_hello_time = ht;
193	return 0;
194}
195
196/*
197 * Sets command port
198 */
199int
200Fport(char *line)
201{
202	int cp = atoi(line);
203	if (cp <= 0 || cp > 65535)
204		return E_CONF_PARAM;
205	command_port = cp;
206	return 0;
207}
208
209/*
210 * Sets neighbour keepalive
211 */
212int
213Fkeepalive(char *line)
214{
215	int kt = atoi(line);
216	if (kt <= 0)
217		return E_CONF_PARAM;
218	ldp_keepalive_time = kt;
219	return 0;
220}
221
222/*
223 * Sets neighbour holddown timer
224 */
225int
226Fholddown(char *line)
227{
228	int hdt = atoi(line);
229	if (hdt <= 0)
230		return E_CONF_PARAM;
231	ldp_holddown_time = hdt;
232	return 0;
233}
234
235int
236Fminlabel(char *line)
237{
238	int ml = atoi(line);
239	if (ml <= 0)
240		return E_CONF_PARAM;
241	min_label = ml;
242	return 0;
243}
244
245int
246Fmaxlabel(char *line)
247{
248	int ml = atoi(line);
249	if (ml <= 0)
250		return E_CONF_PARAM;
251	max_label = ml;
252	return 0;
253}
254
255int
256Fldpid(char *line)
257{
258	if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
259		return E_CONF_PARAM;
260	return 0;
261}
262
263int
264Fneighbour(char *line)
265{
266	char *peer;
267	struct conf_neighbour *nei;
268	struct in_addr ad;
269	char buf[1024];
270
271	peer = NextCommand(line);
272	if (inet_pton(AF_INET, peer, &ad) != 1)
273		return E_CONF_PARAM;
274
275	nei = calloc(1, sizeof(*nei));
276	nei->address.s_addr = ad.s_addr;
277	SLIST_INSERT_HEAD(&conei_head, nei, neilist);
278
279	while(conf_readline(buf, sizeof(buf)) >= 0) {
280		if (buf[0] == '}')
281			return 0;
282		if (Gneighbour(nei, buf) == -1)
283			return -1;
284	}
285	return -1;
286}
287
288/*
289 * neighbour { } sub-commands
290 */
291int
292Gneighbour(struct conf_neighbour *nei, char *line)
293{
294	if (strncasecmp("authenticate", line, 12) == 0) {
295		nei->authenticate = 1;
296		return 0;
297	}
298	return -1;
299}
300