]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/ntp/sntp/kod_management.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / ntp / sntp / kod_management.c
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 #include "ntp_worker.h"
11 #include "ntp_debug.h"
12
13 int kod_init = 0, kod_db_cnt = 0;
14 const char *kod_db_file;
15 struct kod_entry **kod_db;      /* array of pointers to kod_entry */
16
17
18 /*
19  * Search for a KOD entry
20  */
21 int
22 search_entry(
23         const char *hostname,
24         struct kod_entry **dst
25         )
26 {
27         register int a, b, resc = 0;
28
29         for (a = 0; a < kod_db_cnt; a++)
30                 if (!strcmp(kod_db[a]->hostname, hostname))
31                         resc++;
32
33         if (!resc) {
34                 *dst = NULL;
35                 return 0;
36         }
37
38         *dst = eallocarray(resc, sizeof(**dst));
39
40         b = 0;
41         for (a = 0; a < kod_db_cnt; a++)
42                 if (!strcmp(kod_db[a]->hostname, hostname)) {
43                         (*dst)[b] = *kod_db[a];
44                         b++;
45                 }
46
47         return resc;
48 }
49
50
51 void
52 add_entry(
53         const char *    hostname,
54         const char *    type    /* 4 bytes not \0 terminated */
55         )
56 {
57         int n;
58         struct kod_entry *pke;
59
60         pke = emalloc_zero(sizeof(*pke));
61         pke->timestamp = time(NULL);
62         memcpy(pke->type, type, 4);
63         pke->type[sizeof(pke->type) - 1] = '\0';
64         strlcpy(pke->hostname, hostname, sizeof(pke->hostname));
65
66         /*
67          * insert in address ("hostname") order to find duplicates
68          */
69         for (n = 0; n < kod_db_cnt; n++)
70                 if (strcmp(kod_db[n]->hostname, pke->hostname) >= 0)
71                         break;
72
73         if (n < kod_db_cnt &&
74             0 == strcmp(kod_db[n]->hostname, pke->hostname)) {
75                 kod_db[n]->timestamp = pke->timestamp;
76                 free(pke);
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         const char *    hostname,
92         const char *    type
93         )
94 {
95         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 atexit_write_kod_db(void)
116 {
117 #ifdef WORK_FORK
118         if (worker_process)
119                 return;
120 #endif
121         write_kod_db();
122 }
123
124
125 int
126 write_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
178 void
179 kod_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 = eallocarray(kod_db_cnt, sizeof(kod_db[0]));
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 }