kod_management.c revision 280849
167555Smsmith#include <config.h>
267555Smsmith#include <string.h>
367555Smsmith#include <sys/types.h>
467555Smsmith#include <sys/stat.h>
567555Smsmith
667555Smsmith#include "kod_management.h"
767555Smsmith#include "log.h"
867555Smsmith#include "sntp-opts.h"
967555Smsmith#include "ntp_stdlib.h"
1067555Smsmith#include "ntp_worker.h"
1167555Smsmith#include "ntp_debug.h"
1267555Smsmith
1367555Smsmithint kod_init = 0, kod_db_cnt = 0;
1467555Smsmithconst char *kod_db_file;
1567555Smsmithstruct kod_entry **kod_db;	/* array of pointers to kod_entry */
1667555Smsmith
1767555Smsmith
1867555Smsmith/*
1967555Smsmith * Search for a KOD entry
2067555Smsmith */
2167555Smsmithint
2267555Smsmithsearch_entry(
2367555Smsmith	const char *hostname,
2467555Smsmith	struct kod_entry **dst
2567555Smsmith	)
2667555Smsmith{
2767555Smsmith	register int a, b, resc = 0;
2867555Smsmith
2967555Smsmith	for (a = 0; a < kod_db_cnt; a++)
3067555Smsmith		if (!strcmp(kod_db[a]->hostname, hostname))
3167555Smsmith			resc++;
3267555Smsmith
3367555Smsmith	if (!resc) {
3467555Smsmith		*dst = NULL;
3567555Smsmith		return 0;
3667555Smsmith	}
3767555Smsmith
3867555Smsmith	*dst = emalloc(resc * sizeof(**dst));
3967555Smsmith
4067555Smsmith	b = 0;
4167555Smsmith	for (a = 0; a < kod_db_cnt; a++)
4267555Smsmith		if (!strcmp(kod_db[a]->hostname, hostname)) {
4367555Smsmith			(*dst)[b] = *kod_db[a];
4467555Smsmith			b++;
4567555Smsmith		}
4667555Smsmith
4767555Smsmith	return resc;
4867555Smsmith}
4967555Smsmith
5067555Smsmith
5167555Smsmithvoid
5267555Smsmithadd_entry(
5367555Smsmith	const char *	hostname,
5467555Smsmith	const char *	type	/* 4 bytes not \0 terminated */
5567555Smsmith	)
5667555Smsmith{
5767555Smsmith	int n;
5867555Smsmith	struct kod_entry *pke;
5967555Smsmith
6067555Smsmith	pke = emalloc_zero(sizeof(*pke));
6167555Smsmith	pke->timestamp = time(NULL);
6267555Smsmith	memcpy(pke->type, type, 4);
6367555Smsmith	pke->type[sizeof(pke->type) - 1] = '\0';
6467555Smsmith	strlcpy(pke->hostname, hostname, sizeof(pke->hostname));
6567555Smsmith
6667555Smsmith	/*
6767555Smsmith	 * insert in address ("hostname") order to find duplicates
6867555Smsmith	 */
6967555Smsmith	for (n = 0; n < kod_db_cnt; n++)
7067555Smsmith		if (strcmp(kod_db[n]->hostname, pke->hostname) >= 0)
7167555Smsmith			break;
7267555Smsmith
7367555Smsmith	if (n < kod_db_cnt &&
7467555Smsmith	    0 == strcmp(kod_db[n]->hostname, pke->hostname)) {
7567555Smsmith		kod_db[n]->timestamp = pke->timestamp;
7667555Smsmith		free(pke);
7767555Smsmith		return;
7867555Smsmith	}
7967555Smsmith
8067555Smsmith	kod_db_cnt++;
8167555Smsmith	kod_db = erealloc(kod_db, kod_db_cnt * sizeof(kod_db[0]));
8267555Smsmith	if (n != kod_db_cnt - 1)
8367555Smsmith		memmove(&kod_db[n + 1], &kod_db[n],
8467555Smsmith			sizeof(kod_db[0]) * ((kod_db_cnt - 1) - n));
8567555Smsmith	kod_db[n] = pke;
8667555Smsmith}
8767555Smsmith
8867555Smsmith
8967555Smsmithvoid
9067555Smsmithdelete_entry(
9167555Smsmith	const char *	hostname,
9267555Smsmith	const char *	type
93118508Sps	)
94118508Sps{
95118508Sps	int a;
96118508Sps
97118508Sps	for (a = 0; a < kod_db_cnt; a++)
98118508Sps		if (!strcmp(kod_db[a]->hostname, hostname)
99118508Sps		    && !strcmp(kod_db[a]->type, type))
100118508Sps			break;
101118508Sps
102118508Sps	if (a == kod_db_cnt)
103		return;
104
105	free(kod_db[a]);
106	kod_db_cnt--;
107
108	if (a < kod_db_cnt)
109		memmove(&kod_db[a], &kod_db[a + 1],
110			(kod_db_cnt - a) * sizeof(kod_db[0]));
111}
112
113
114void
115atexit_write_kod_db(void)
116{
117#ifdef WORK_FORK
118	if (worker_process)
119		return;
120#endif
121	write_kod_db();
122}
123
124
125int
126write_kod_db(void)
127{
128	FILE *db_s;
129	char *pch;
130	int dirmode;
131	register int a;
132
133	db_s = fopen(kod_db_file, "w");
134
135	/*
136	 * If opening fails, blindly attempt to create each directory
137	 * in the path first, then retry the open.
138	 */
139	if (NULL == db_s && strlen(kod_db_file)) {
140		dirmode = S_IRUSR | S_IWUSR | S_IXUSR
141			| S_IRGRP | S_IXGRP
142			| S_IROTH | S_IXOTH;
143		pch = strchr(kod_db_file + 1, DIR_SEP);
144		while (NULL != pch) {
145			*pch = '\0';
146			if (-1 == mkdir(kod_db_file, dirmode)
147			    && errno != EEXIST) {
148				msyslog(LOG_ERR, "mkdir(%s) failed: %m",
149					kod_db_file);
150				return FALSE;
151			}
152			*pch = DIR_SEP;
153			pch = strchr(pch + 1, DIR_SEP);
154		}
155		db_s = fopen(kod_db_file, "w");
156	}
157
158	if (NULL == db_s) {
159		msyslog(LOG_WARNING, "Can't open KOD db file %s for writing: %m",
160			kod_db_file);
161
162		return FALSE;
163	}
164
165	for (a = 0; a < kod_db_cnt; a++) {
166		fprintf(db_s, "%16.16llx %s %s\n", (unsigned long long)
167			kod_db[a]->timestamp, kod_db[a]->type,
168			kod_db[a]->hostname);
169	}
170
171	fflush(db_s);
172	fclose(db_s);
173
174	return TRUE;
175}
176
177
178void
179kod_init_kod_db(
180	const char *	db_file,
181	int		readonly
182	)
183{
184	/*
185	 * Max. of 254 characters for hostname, 10 for timestamp, 4 for
186	 * kisscode, 2 for spaces, 1 for \n, and 1 for \0
187	 */
188	char fbuf[254+10+4+2+1+1];
189	FILE *db_s;
190	int a, b, sepc, len;
191	unsigned long long ull;
192	char *str_ptr;
193	char error = 0;
194
195	TRACE(2, ("Initializing KOD DB...\n"));
196
197	kod_db_file = estrdup(db_file);
198
199	db_s = fopen(db_file, "r");
200
201	if (NULL == db_s) {
202		msyslog(LOG_WARNING, "kod_init_kod_db(): Cannot open KoD db file %s: %m",
203			db_file);
204
205		return;
206	}
207
208	if (debug)
209		printf("Starting to read KoD file %s...\n", db_file);
210	/* First let's see how many entries there are and check for right syntax */
211
212	while (!feof(db_s) && NULL != fgets(fbuf, sizeof(fbuf), db_s)) {
213
214		/* ignore blank lines */
215		if ('\n' == fbuf[0])
216			continue;
217
218		sepc = 0;
219		len = strlen(fbuf);
220		for (a = 0; a < len; a++) {
221			if (' ' == fbuf[a])
222				sepc++;
223
224			if ('\n' == fbuf[a]) {
225				if (sepc != 2) {
226					if (strcmp(db_file, "/dev/null"))
227						msyslog(LOG_DEBUG,
228							"Syntax error in KoD db file %s in line %i (missing space)",
229							db_file,
230							kod_db_cnt + 1);
231					fclose(db_s);
232					return;
233				}
234				sepc = 0;
235				kod_db_cnt++;
236			}
237		}
238	}
239
240	if (0 == kod_db_cnt) {
241		TRACE(2, ("KoD DB %s empty.\n", db_file));
242		goto wrapup;
243	}
244
245	TRACE(2, ("KoD DB %s contains %d entries, reading...\n", db_file, kod_db_cnt));
246
247	rewind(db_s);
248
249	kod_db = emalloc(sizeof(kod_db[0]) * kod_db_cnt);
250
251	/* Read contents of file */
252	for (b = 0;
253	     !feof(db_s) && !ferror(db_s) && b < kod_db_cnt;
254	     b++) {
255
256		str_ptr = fgets(fbuf, sizeof(fbuf), db_s);
257		if (NULL == str_ptr) {
258			error = 1;
259			break;
260		}
261
262		/* ignore blank lines */
263		if ('\n' == fbuf[0]) {
264			b--;
265			continue;
266		}
267
268		kod_db[b] = emalloc(sizeof(*kod_db[b]));
269
270		if (3 != sscanf(fbuf, "%llx %4s %254s", &ull,
271		    kod_db[b]->type, kod_db[b]->hostname)) {
272
273			free(kod_db[b]);
274			kod_db[b] = NULL;
275			error = 1;
276			break;
277		}
278
279		kod_db[b]->timestamp = (time_t)ull;
280	}
281
282	if (ferror(db_s) || error) {
283		kod_db_cnt = b;
284		msyslog(LOG_WARNING, "An error occured while parsing the KoD db file %s",
285			db_file);
286		fclose(db_s);
287
288		return;
289	}
290
291    wrapup:
292	fclose(db_s);
293	for (a = 0; a < kod_db_cnt; a++)
294		TRACE(2, ("KoD entry %d: %s at %llx type %s\n", a,
295			  kod_db[a]->hostname,
296			  (unsigned long long)kod_db[a]->timestamp,
297			  kod_db[a]->type));
298
299	if (!readonly && write_kod_db())
300		atexit(&atexit_write_kod_db);
301}
302