xref: /netbsd-src/external/bsd/ntp/dist/sntp/kod_management.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
1 /*	$NetBSD: kod_management.c,v 1.2 2010/08/28 15:38:55 kardel Exp $	*/
2 
3 #include <string.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 
7 #include "kod_management.h"
8 #include "log.h"
9 #include "sntp-opts.h"
10 #include "ntp_stdlib.h"
11 
12 int kod_init = 0, kod_db_cnt = 0;
13 const char *kod_db_file;
14 struct kod_entry **kod_db;	/* array of pointers to kod_entry */
15 
16 
17 /*
18  * Search for a KOD entry
19  */
20 int
21 search_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 
50 void
51 add_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 		return;
78 	}
79 
80 	kod_db_cnt++;
81 	kod_db = erealloc(kod_db, kod_db_cnt * sizeof(kod_db[0]));
82 	if (n != kod_db_cnt - 1)
83 		memmove(&kod_db[n + 1], &kod_db[n],
84 			sizeof(kod_db[0]) * ((kod_db_cnt - 1) - n));
85 	kod_db[n] = pke;
86 }
87 
88 
89 void
90 delete_entry(
91 	char *hostname,
92 	char *type
93 	)
94 {
95 	register int a;
96 
97 	for (a = 0; a < kod_db_cnt; a++)
98 		if (!strcmp(kod_db[a]->hostname, hostname)
99 		    && !strcmp(kod_db[a]->type, type))
100 			break;
101 
102 	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 
114 void
115 write_kod_db(void)
116 {
117 	FILE *db_s;
118 	char *pch;
119 	int dirmode;
120 	register int a;
121 
122 	db_s = fopen(kod_db_file, "w");
123 
124 	/*
125 	 * If opening fails, blindly attempt to create each directory
126 	 * in the path first, then retry the open.
127 	 */
128 	if (NULL == db_s && strlen(kod_db_file)) {
129 		dirmode = S_IRUSR | S_IWUSR | S_IXUSR
130 			| S_IRGRP | S_IXGRP
131 			| S_IROTH | S_IXOTH;
132 		pch = strchr(kod_db_file + 1, DIR_SEP);
133 		while (NULL != pch) {
134 			*pch = '\0';
135 			mkdir(kod_db_file, dirmode);
136 			*pch = DIR_SEP;
137 			pch = strchr(pch + 1, DIR_SEP);
138 		}
139 		db_s = fopen(kod_db_file, "w");
140 	}
141 
142 	if (NULL == db_s) {
143 		char msg[80];
144 
145 		snprintf(msg, sizeof(msg),
146 			 "Can't open KOD db file %s for writing!",
147 			 kod_db_file);
148 #ifdef DEBUG
149 		debug_msg(msg);
150 #endif
151 		log_msg(msg, 2);
152 
153 		return;
154 	}
155 
156 	for (a = 0; a < kod_db_cnt; a++) {
157 		fprintf(db_s, "%16.16llx %s %s\n", (unsigned long long)
158 			kod_db[a]->timestamp, kod_db[a]->type,
159 			kod_db[a]->hostname);
160 	}
161 
162 	fflush(db_s);
163 	fclose(db_s);
164 }
165 
166 
167 void
168 kod_init_kod_db(
169 	const char *db_file
170 	)
171 {
172 	/*
173 	 * Max. of 254 characters for hostname, 10 for timestamp, 4 for
174 	 * kisscode, 2 for spaces, 1 for \n, and 1 for \0
175 	 */
176 	char fbuf[254+10+4+2+1+1];
177 	FILE *db_s;
178 	int a, b, sepc, len;
179 	unsigned long long ull;
180 	char *str_ptr;
181 	char error = 0;
182 
183 	atexit(write_kod_db);
184 
185 #ifdef DEBUG
186 	printf("Initializing KOD DB...\n");
187 #endif
188 
189 	kod_db_file = estrdup(db_file);
190 
191 
192 	db_s = fopen(db_file, "r");
193 
194 	if (NULL == db_s) {
195 		char msg[80];
196 
197 		snprintf(msg, sizeof(msg), "kod_init_kod_db(): Cannot open KoD db file %s", db_file);
198 #ifdef DEBUG
199 		debug_msg(msg);
200 		printf("%s\n", msg);
201 #endif
202 		log_msg(msg, 2);
203 
204 		return;
205 	}
206 
207 	if (ENABLED_OPT(NORMALVERBOSE))
208 		printf("Starting to read KoD file %s...\n", db_file);
209 	/* First let's see how many entries there are and check for right syntax */
210 
211 	while (!feof(db_s) && NULL != fgets(fbuf, sizeof(fbuf), db_s)) {
212 
213 		/* ignore blank lines */
214 		if ('\n' == fbuf[0])
215 			continue;
216 
217 		sepc = 0;
218 		len = strlen(fbuf);
219 		for (a = 0; a < len; a++) {
220 			if (' ' == fbuf[a])
221 				sepc++;
222 
223 			if ('\n' == fbuf[a]) {
224 				if (sepc != 2) {
225 					if (strcmp(db_file, "/dev/null")) {
226 						char msg[80];
227 						snprintf(msg, sizeof(msg),
228 							 "Syntax error in KoD db file %s in line %i (missing space)",
229 							 db_file, kod_db_cnt + 1);
230 	#ifdef DEBUG
231 						debug_msg(msg);
232 						printf("%s\n", msg);
233 	#endif
234 						log_msg(msg, 1);
235 					}
236 					fclose(db_s);
237 					return;
238 				}
239 				sepc = 0;
240 				kod_db_cnt++;
241 			}
242 		}
243 	}
244 
245 	if (0 == kod_db_cnt) {
246 #ifdef DEBUG
247 		printf("KoD DB %s empty.\n", db_file);
248 #endif
249 		fclose(db_s);
250 		return;
251 	}
252 
253 #ifdef DEBUG
254 	printf("KoD DB %s contains %d entries, reading...\n", db_file, kod_db_cnt);
255 #endif
256 
257 	rewind(db_s);
258 
259 	kod_db = emalloc(sizeof(kod_db[0]) * kod_db_cnt);
260 
261 	/* Read contents of file */
262 	for (b = 0;
263 	     !feof(db_s) && !ferror(db_s) && b < kod_db_cnt;
264 	     b++) {
265 
266 		str_ptr = fgets(fbuf, sizeof(fbuf), db_s);
267 		if (NULL == str_ptr) {
268 			error = 1;
269 			break;
270 		}
271 
272 		/* ignore blank lines */
273 		if ('\n' == fbuf[0]) {
274 			b--;
275 			continue;
276 		}
277 
278 		kod_db[b] = emalloc(sizeof(*kod_db[b]));
279 
280 		if (3 != sscanf(fbuf, "%llx %4s %254s", &ull,
281 		    kod_db[b]->type, kod_db[b]->hostname)) {
282 
283 			free(kod_db[b]);
284 			kod_db[b] = NULL;
285 			error = 1;
286 			break;
287 		}
288 
289 		kod_db[b]->timestamp = (time_t)ull;
290 	}
291 
292 	if (ferror(db_s) || error) {
293 		char msg[80];
294 
295 		kod_db_cnt = b;
296 		snprintf(msg, sizeof(msg), "An error occured while parsing the KoD db file %s", db_file);
297 #ifdef DEBUG
298 		debug_msg(msg);
299 #endif
300 		log_msg(msg, 2);
301 		fclose(db_s);
302 
303 		return;
304 	}
305 
306 	fclose(db_s);
307 #ifdef DEBUG
308 	for (a = 0; a < kod_db_cnt; a++)
309 		printf("KoD entry %d: %s at %llx type %s\n", a,
310 		       kod_db[a]->hostname,
311 		       (unsigned long long)kod_db[a]->timestamp,
312 		       kod_db[a]->type);
313 #endif
314 }
315