kod_management.c revision 258945
1#include <config.h>
2#include <string.h>
3#include <sys/types.h>
4#include <sys/stat.h>
5
6#include "kod_management.h"
7#include "log.h"
8#include "sntp-opts.h"
9#include "ntp_stdlib.h"
10//#define DEBUG
11
12int kod_init = 0, kod_db_cnt = 0;
13const char *kod_db_file;
14struct kod_entry **kod_db;	/* array of pointers to kod_entry */
15
16
17/*
18 * Search for a KOD entry
19 */
20int
21search_entry (
22		char *hostname,
23		struct kod_entry **dst
24	     )
25{
26	register int a, b, resc = 0;
27
28	for (a = 0; a < kod_db_cnt; a++)
29		if (!strcmp(kod_db[a]->hostname, hostname))
30			resc++;
31
32	if (!resc) {
33		*dst = NULL;
34		return 0;
35	}
36
37	*dst = emalloc(resc * sizeof(**dst));
38
39	b = 0;
40	for (a = 0; a < kod_db_cnt; a++)
41		if (!strcmp(kod_db[a]->hostname, hostname)) {
42			(*dst)[b] = *kod_db[a];
43			b++;
44		}
45
46	return resc;
47}
48
49
50void
51add_entry(
52	char *hostname,
53	char *type	/* 4 bytes not \0 terminated */
54	)
55{
56	int n;
57	struct kod_entry *pke;
58
59	pke = emalloc(sizeof(*pke));
60	pke->timestamp = time(NULL);
61	memcpy(pke->type, type, 4);
62	pke->type[sizeof(pke->type) - 1] = '\0';
63	strncpy(pke->hostname, hostname,
64		sizeof(pke->hostname));
65	pke->hostname[sizeof(pke->hostname) - 1] = '\0';
66
67	/*
68	 * insert in address ("hostname") order to find duplicates
69	 */
70	for (n = 0; n < kod_db_cnt; n++)
71		if (strcmp(kod_db[n]->hostname, pke->hostname) >= 0)
72			break;
73
74	if (n < kod_db_cnt &&
75	    0 == strcmp(kod_db[n]->hostname, pke->hostname)) {
76		kod_db[n]->timestamp = pke->timestamp;
77		free(pke);
78		return;
79	}
80
81	kod_db_cnt++;
82	kod_db = erealloc(kod_db, kod_db_cnt * sizeof(kod_db[0]));
83	if (n != kod_db_cnt - 1)
84		memmove(&kod_db[n + 1], &kod_db[n],
85			sizeof(kod_db[0]) * ((kod_db_cnt - 1) - n));
86	kod_db[n] = pke;
87}
88
89
90void
91delete_entry(
92	char *hostname,
93	char *type
94	)
95{
96	register int a;
97
98	for (a = 0; a < kod_db_cnt; a++)
99		if (!strcmp(kod_db[a]->hostname, hostname)
100		    && !strcmp(kod_db[a]->type, type))
101			break;
102
103	if (a == kod_db_cnt)
104		return;
105
106	free(kod_db[a]);
107	kod_db_cnt--;
108
109	if (a < kod_db_cnt)
110		memmove(&kod_db[a], &kod_db[a + 1],
111			(kod_db_cnt - a) * sizeof(kod_db[0]));
112}
113
114
115void
116write_kod_db(void)
117{
118	FILE *db_s;
119	char *pch;
120	int dirmode;
121	register int a;
122
123	db_s = fopen(kod_db_file, "w");
124
125	/*
126	 * If opening fails, blindly attempt to create each directory
127	 * in the path first, then retry the open.
128	 */
129	if (NULL == db_s && strlen(kod_db_file)) {
130		dirmode = S_IRUSR | S_IWUSR | S_IXUSR
131			| S_IRGRP | S_IXGRP
132			| S_IROTH | S_IXOTH;
133		pch = strchr(kod_db_file + 1, DIR_SEP);
134		while (NULL != pch) {
135			*pch = '\0';
136			mkdir(kod_db_file, dirmode);
137			*pch = DIR_SEP;
138			pch = strchr(pch + 1, DIR_SEP);
139		}
140		db_s = fopen(kod_db_file, "w");
141	}
142
143	if (NULL == db_s) {
144		msyslog(LOG_WARNING, "Can't open KOD db file %s for writing!",
145			kod_db_file);
146
147		return;
148	}
149
150	for (a = 0; a < kod_db_cnt; a++) {
151		fprintf(db_s, "%16.16llx %s %s\n", (unsigned long long)
152			kod_db[a]->timestamp, kod_db[a]->type,
153			kod_db[a]->hostname);
154	}
155
156	fflush(db_s);
157	fclose(db_s);
158}
159
160
161void
162kod_init_kod_db(
163	const char *db_file
164	)
165{
166	/*
167	 * Max. of 254 characters for hostname, 10 for timestamp, 4 for
168	 * kisscode, 2 for spaces, 1 for \n, and 1 for \0
169	 */
170	char fbuf[254+10+4+2+1+1];
171	FILE *db_s;
172	int a, b, sepc, len;
173	unsigned long long ull;
174	char *str_ptr;
175	char error = 0;
176
177	atexit(write_kod_db);
178
179#ifdef DEBUG
180	printf("Initializing KOD DB...\n");
181#endif
182
183	kod_db_file = estrdup(db_file);
184
185
186	db_s = fopen(db_file, "r");
187
188	if (NULL == db_s) {
189		msyslog(LOG_WARNING, "kod_init_kod_db(): Cannot open KoD db file %s",
190			db_file);
191
192		return;
193	}
194
195	if (ENABLED_OPT(NORMALVERBOSE))
196		printf("Starting to read KoD file %s...\n", db_file);
197	/* First let's see how many entries there are and check for right syntax */
198
199	while (!feof(db_s) && NULL != fgets(fbuf, sizeof(fbuf), db_s)) {
200
201		/* ignore blank lines */
202		if ('\n' == fbuf[0])
203			continue;
204
205		sepc = 0;
206		len = strlen(fbuf);
207		for (a = 0; a < len; a++) {
208			if (' ' == fbuf[a])
209				sepc++;
210
211			if ('\n' == fbuf[a]) {
212				if (sepc != 2) {
213					if (strcmp(db_file, "/dev/null"))
214						msyslog(LOG_DEBUG,
215							"Syntax error in KoD db file %s in line %i (missing space)",
216							db_file,
217							kod_db_cnt + 1);
218					fclose(db_s);
219					return;
220				}
221				sepc = 0;
222				kod_db_cnt++;
223			}
224		}
225	}
226
227	if (0 == kod_db_cnt) {
228#ifdef DEBUG
229		printf("KoD DB %s empty.\n", db_file);
230#endif
231		fclose(db_s);
232		return;
233	}
234
235#ifdef DEBUG
236	printf("KoD DB %s contains %d entries, reading...\n", db_file, kod_db_cnt);
237#endif
238
239	rewind(db_s);
240
241	kod_db = emalloc(sizeof(kod_db[0]) * kod_db_cnt);
242
243	/* Read contents of file */
244	for (b = 0;
245	     !feof(db_s) && !ferror(db_s) && b < kod_db_cnt;
246	     b++) {
247
248		str_ptr = fgets(fbuf, sizeof(fbuf), db_s);
249		if (NULL == str_ptr) {
250			error = 1;
251			break;
252		}
253
254		/* ignore blank lines */
255		if ('\n' == fbuf[0]) {
256			b--;
257			continue;
258		}
259
260		kod_db[b] = emalloc(sizeof(*kod_db[b]));
261
262		if (3 != sscanf(fbuf, "%llx %4s %254s", &ull,
263		    kod_db[b]->type, kod_db[b]->hostname)) {
264
265			free(kod_db[b]);
266			kod_db[b] = NULL;
267			error = 1;
268			break;
269		}
270
271		kod_db[b]->timestamp = (time_t)ull;
272	}
273
274	if (ferror(db_s) || error) {
275		kod_db_cnt = b;
276		msyslog(LOG_WARNING, "An error occured while parsing the KoD db file %s",
277			db_file);
278		fclose(db_s);
279
280		return;
281	}
282
283	fclose(db_s);
284#ifdef DEBUG
285	for (a = 0; a < kod_db_cnt; a++)
286		printf("KoD entry %d: %s at %llx type %s\n", a,
287		       kod_db[a]->hostname,
288		       (unsigned long long)kod_db[a]->timestamp,
289		       kod_db[a]->type);
290#endif
291}
292