1290001Sglebius#include <config.h> 2290001Sglebius#include <string.h> 3290001Sglebius#include <sys/types.h> 4290001Sglebius#include <sys/stat.h> 5290001Sglebius 6290001Sglebius#include "kod_management.h" 7290001Sglebius#include "log.h" 8290001Sglebius#include "sntp-opts.h" 9290001Sglebius#include "ntp_stdlib.h" 10290001Sglebius#include "ntp_worker.h" 11290001Sglebius#include "ntp_debug.h" 12290001Sglebius 13290001Sglebiusint kod_init = 0, kod_db_cnt = 0; 14290001Sglebiusconst char *kod_db_file; 15290001Sglebiusstruct kod_entry **kod_db; /* array of pointers to kod_entry */ 16290001Sglebius 17290001Sglebius 18290001Sglebius/* 19290001Sglebius * Search for a KOD entry 20290001Sglebius */ 21290001Sglebiusint 22290001Sglebiussearch_entry( 23290001Sglebius const char *hostname, 24290001Sglebius struct kod_entry **dst 25290001Sglebius ) 26290001Sglebius{ 27290001Sglebius register int a, b, resc = 0; 28290001Sglebius 29290001Sglebius for (a = 0; a < kod_db_cnt; a++) 30290001Sglebius if (!strcmp(kod_db[a]->hostname, hostname)) 31290001Sglebius resc++; 32290001Sglebius 33290001Sglebius if (!resc) { 34290001Sglebius *dst = NULL; 35290001Sglebius return 0; 36290001Sglebius } 37290001Sglebius 38290001Sglebius *dst = eallocarray(resc, sizeof(**dst)); 39290001Sglebius 40290001Sglebius b = 0; 41290001Sglebius for (a = 0; a < kod_db_cnt; a++) 42290001Sglebius if (!strcmp(kod_db[a]->hostname, hostname)) { 43290001Sglebius (*dst)[b] = *kod_db[a]; 44290001Sglebius b++; 45290001Sglebius } 46290001Sglebius 47290001Sglebius return resc; 48290001Sglebius} 49290001Sglebius 50290001Sglebius 51290001Sglebiusvoid 52290001Sglebiusadd_entry( 53290001Sglebius const char * hostname, 54290001Sglebius const char * type /* 4 bytes not \0 terminated */ 55290001Sglebius ) 56290001Sglebius{ 57290001Sglebius int n; 58290001Sglebius struct kod_entry *pke; 59290001Sglebius 60290001Sglebius pke = emalloc_zero(sizeof(*pke)); 61290001Sglebius pke->timestamp = time(NULL); 62290001Sglebius memcpy(pke->type, type, 4); 63290001Sglebius pke->type[sizeof(pke->type) - 1] = '\0'; 64290001Sglebius strlcpy(pke->hostname, hostname, sizeof(pke->hostname)); 65290001Sglebius 66290001Sglebius /* 67290001Sglebius * insert in address ("hostname") order to find duplicates 68290001Sglebius */ 69290001Sglebius for (n = 0; n < kod_db_cnt; n++) 70290001Sglebius if (strcmp(kod_db[n]->hostname, pke->hostname) >= 0) 71290001Sglebius break; 72290001Sglebius 73290001Sglebius if (n < kod_db_cnt && 74290001Sglebius 0 == strcmp(kod_db[n]->hostname, pke->hostname)) { 75290001Sglebius kod_db[n]->timestamp = pke->timestamp; 76290001Sglebius free(pke); 77290001Sglebius return; 78290001Sglebius } 79290001Sglebius 80290001Sglebius kod_db_cnt++; 81290001Sglebius kod_db = erealloc(kod_db, kod_db_cnt * sizeof(kod_db[0])); 82290001Sglebius if (n != kod_db_cnt - 1) 83290001Sglebius memmove(&kod_db[n + 1], &kod_db[n], 84290001Sglebius sizeof(kod_db[0]) * ((kod_db_cnt - 1) - n)); 85290001Sglebius kod_db[n] = pke; 86290001Sglebius} 87290001Sglebius 88290001Sglebius 89290001Sglebiusvoid 90290001Sglebiusdelete_entry( 91290001Sglebius const char * hostname, 92290001Sglebius const char * type 93290001Sglebius ) 94290001Sglebius{ 95290001Sglebius int a; 96290001Sglebius 97290001Sglebius for (a = 0; a < kod_db_cnt; a++) 98290001Sglebius if (!strcmp(kod_db[a]->hostname, hostname) 99290001Sglebius && !strcmp(kod_db[a]->type, type)) 100290001Sglebius break; 101290001Sglebius 102290001Sglebius if (a == kod_db_cnt) 103290001Sglebius return; 104290001Sglebius 105290001Sglebius free(kod_db[a]); 106290001Sglebius kod_db_cnt--; 107290001Sglebius 108290001Sglebius if (a < kod_db_cnt) 109290001Sglebius memmove(&kod_db[a], &kod_db[a + 1], 110290001Sglebius (kod_db_cnt - a) * sizeof(kod_db[0])); 111290001Sglebius} 112290001Sglebius 113290001Sglebius 114290001Sglebiusvoid 115290001Sglebiusatexit_write_kod_db(void) 116290001Sglebius{ 117290001Sglebius#ifdef WORK_FORK 118290001Sglebius if (worker_process) 119290001Sglebius return; 120290001Sglebius#endif 121290001Sglebius write_kod_db(); 122290001Sglebius} 123290001Sglebius 124290001Sglebius 125290001Sglebiusint 126290001Sglebiuswrite_kod_db(void) 127290001Sglebius{ 128290001Sglebius FILE *db_s; 129290001Sglebius char *pch; 130290001Sglebius int dirmode; 131290001Sglebius register int a; 132290001Sglebius 133290001Sglebius db_s = fopen(kod_db_file, "w"); 134290001Sglebius 135290001Sglebius /* 136290001Sglebius * If opening fails, blindly attempt to create each directory 137290001Sglebius * in the path first, then retry the open. 138290001Sglebius */ 139290001Sglebius if (NULL == db_s && strlen(kod_db_file)) { 140290001Sglebius dirmode = S_IRUSR | S_IWUSR | S_IXUSR 141290001Sglebius | S_IRGRP | S_IXGRP 142290001Sglebius | S_IROTH | S_IXOTH; 143290001Sglebius pch = strchr(kod_db_file + 1, DIR_SEP); 144290001Sglebius while (NULL != pch) { 145290001Sglebius *pch = '\0'; 146290001Sglebius if (-1 == mkdir(kod_db_file, dirmode) 147290001Sglebius && errno != EEXIST) { 148290001Sglebius msyslog(LOG_ERR, "mkdir(%s) failed: %m", 149290001Sglebius kod_db_file); 150290001Sglebius return FALSE; 151290001Sglebius } 152290001Sglebius *pch = DIR_SEP; 153290001Sglebius pch = strchr(pch + 1, DIR_SEP); 154290001Sglebius } 155290001Sglebius db_s = fopen(kod_db_file, "w"); 156290001Sglebius } 157290001Sglebius 158290001Sglebius if (NULL == db_s) { 159290001Sglebius msyslog(LOG_WARNING, "Can't open KOD db file %s for writing: %m", 160290001Sglebius kod_db_file); 161290001Sglebius 162290001Sglebius return FALSE; 163290001Sglebius } 164290001Sglebius 165290001Sglebius for (a = 0; a < kod_db_cnt; a++) { 166290001Sglebius fprintf(db_s, "%16.16llx %s %s\n", (unsigned long long) 167290001Sglebius kod_db[a]->timestamp, kod_db[a]->type, 168290001Sglebius kod_db[a]->hostname); 169290001Sglebius } 170290001Sglebius 171290001Sglebius fflush(db_s); 172290001Sglebius fclose(db_s); 173290001Sglebius 174290001Sglebius return TRUE; 175290001Sglebius} 176290001Sglebius 177290001Sglebius 178290001Sglebiusvoid 179290001Sglebiuskod_init_kod_db( 180290001Sglebius const char * db_file, 181290001Sglebius int readonly 182290001Sglebius ) 183290001Sglebius{ 184290001Sglebius /* 185290001Sglebius * Max. of 254 characters for hostname, 10 for timestamp, 4 for 186290001Sglebius * kisscode, 2 for spaces, 1 for \n, and 1 for \0 187290001Sglebius */ 188290001Sglebius char fbuf[254+10+4+2+1+1]; 189290001Sglebius FILE *db_s; 190290001Sglebius int a, b, sepc, len; 191290001Sglebius unsigned long long ull; 192290001Sglebius char *str_ptr; 193290001Sglebius char error = 0; 194290001Sglebius 195290001Sglebius TRACE(2, ("Initializing KOD DB...\n")); 196290001Sglebius 197290001Sglebius kod_db_file = estrdup(db_file); 198290001Sglebius 199290001Sglebius db_s = fopen(db_file, "r"); 200290001Sglebius 201290001Sglebius if (NULL == db_s) { 202290001Sglebius msyslog(LOG_WARNING, "kod_init_kod_db(): Cannot open KoD db file %s: %m", 203290001Sglebius db_file); 204290001Sglebius 205290001Sglebius return; 206290001Sglebius } 207290001Sglebius 208290001Sglebius if (debug) 209290001Sglebius printf("Starting to read KoD file %s...\n", db_file); 210290001Sglebius /* First let's see how many entries there are and check for right syntax */ 211290001Sglebius 212290001Sglebius while (!feof(db_s) && NULL != fgets(fbuf, sizeof(fbuf), db_s)) { 213290001Sglebius 214290001Sglebius /* ignore blank lines */ 215290001Sglebius if ('\n' == fbuf[0]) 216290001Sglebius continue; 217290001Sglebius 218290001Sglebius sepc = 0; 219290001Sglebius len = strlen(fbuf); 220290001Sglebius for (a = 0; a < len; a++) { 221290001Sglebius if (' ' == fbuf[a]) 222290001Sglebius sepc++; 223290001Sglebius 224290001Sglebius if ('\n' == fbuf[a]) { 225290001Sglebius if (sepc != 2) { 226290001Sglebius if (strcmp(db_file, "/dev/null")) 227290001Sglebius msyslog(LOG_DEBUG, 228290001Sglebius "Syntax error in KoD db file %s in line %i (missing space)", 229290001Sglebius db_file, 230290001Sglebius kod_db_cnt + 1); 231290001Sglebius fclose(db_s); 232290001Sglebius return; 233290001Sglebius } 234290001Sglebius sepc = 0; 235290001Sglebius kod_db_cnt++; 236290001Sglebius } 237290001Sglebius } 238290001Sglebius } 239290001Sglebius 240290001Sglebius if (0 == kod_db_cnt) { 241290001Sglebius TRACE(2, ("KoD DB %s empty.\n", db_file)); 242290001Sglebius goto wrapup; 243290001Sglebius } 244290001Sglebius 245290001Sglebius TRACE(2, ("KoD DB %s contains %d entries, reading...\n", db_file, kod_db_cnt)); 246290001Sglebius 247290001Sglebius rewind(db_s); 248290001Sglebius 249290001Sglebius kod_db = eallocarray(kod_db_cnt, sizeof(kod_db[0])); 250290001Sglebius 251290001Sglebius /* Read contents of file */ 252290001Sglebius for (b = 0; 253290001Sglebius !feof(db_s) && !ferror(db_s) && b < kod_db_cnt; 254290001Sglebius b++) { 255290001Sglebius 256290001Sglebius str_ptr = fgets(fbuf, sizeof(fbuf), db_s); 257290001Sglebius if (NULL == str_ptr) { 258290001Sglebius error = 1; 259290001Sglebius break; 260290001Sglebius } 261290001Sglebius 262290001Sglebius /* ignore blank lines */ 263290001Sglebius if ('\n' == fbuf[0]) { 264290001Sglebius b--; 265290001Sglebius continue; 266290001Sglebius } 267290001Sglebius 268290001Sglebius kod_db[b] = emalloc(sizeof(*kod_db[b])); 269290001Sglebius 270290001Sglebius if (3 != sscanf(fbuf, "%llx %4s %254s", &ull, 271290001Sglebius kod_db[b]->type, kod_db[b]->hostname)) { 272290001Sglebius 273290001Sglebius free(kod_db[b]); 274290001Sglebius kod_db[b] = NULL; 275290001Sglebius error = 1; 276290001Sglebius break; 277290001Sglebius } 278290001Sglebius 279290001Sglebius kod_db[b]->timestamp = (time_t)ull; 280290001Sglebius } 281290001Sglebius 282290001Sglebius if (ferror(db_s) || error) { 283290001Sglebius kod_db_cnt = b; 284290001Sglebius msyslog(LOG_WARNING, "An error occured while parsing the KoD db file %s", 285290001Sglebius db_file); 286290001Sglebius fclose(db_s); 287290001Sglebius 288290001Sglebius return; 289290001Sglebius } 290290001Sglebius 291290001Sglebius wrapup: 292290001Sglebius fclose(db_s); 293290001Sglebius for (a = 0; a < kod_db_cnt; a++) 294290001Sglebius TRACE(2, ("KoD entry %d: %s at %llx type %s\n", a, 295290001Sglebius kod_db[a]->hostname, 296290001Sglebius (unsigned long long)kod_db[a]->timestamp, 297290001Sglebius kod_db[a]->type)); 298290001Sglebius 299290001Sglebius if (!readonly && write_kod_db()) 300290001Sglebius atexit(&atexit_write_kod_db); 301290001Sglebius} 302