1 /**
2  * @file db.c Database routines for ndo2db daemon
3  */
4 /*
5  * Copyright 2009-2014 Nagios Core Development Team and Community Contributors
6  * Copyright 2005-2009 Ethan Galstad
7  *
8  * This file is part of NDOUtils.
9  *
10  * NDOUtils is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * NDOUtils is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with NDOUtils. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /* include our project's header files */
24 #include "../include/config.h"
25 #include "../include/common.h"
26 #include "../include/io.h"
27 #include "../include/utils.h"
28 #include "../include/protoapi.h"
29 #include "../include/ndo2db.h"
30 #include "../include/dbhandlers.h"
31 #include "../include/db.h"
32 
33 extern int errno;
34 
35 extern ndo2db_dbconfig ndo2db_db_settings;
36 extern time_t ndo2db_db_last_checkin_time;
37 
38 char *ndo2db_db_rawtablenames[NDO2DB_MAX_DBTABLES]={
39 	"instances",
40 	"conninfo",
41 	"objects",
42 	"objecttypes",
43 	"logentries",
44 	"systemcommands",
45 	"eventhandlers",
46 	"servicechecks",
47 	"hostchecks",
48 	"programstatus",
49 	"externalcommands",
50 	"servicestatus",
51 	"hoststatus",
52 	"processevents",
53 	"timedevents",
54 	"timedeventqueue",
55 	"flappinghistory",
56 	"commenthistory",
57 	"comments",
58 	"notifications",
59 	"contactnotifications",
60 	"contactnotificationmethods",
61 	"acknowledgements",
62 	"statehistory",
63 	"downtimehistory",
64 	"scheduleddowntime",
65 	"configfiles",
66 	"configfilevariables",
67 	"runtimevariables",
68 	"contactstatus",
69 	"customvariablestatus",
70 	"",
71 	"",
72 	"",
73 	"",
74 	"",
75 	"",
76 	"",
77 	"",
78 	"",
79 	"commands",
80 	"timeperiods",
81 	"timeperiod_timeranges",
82 	"contactgroups",
83 	"contactgroup_members",
84 	"hostgroups",
85 	"hostgroup_members",
86 	"servicegroups",
87 	"servicegroup_members",
88 	"hostescalations",
89 	"hostescalation_contacts",
90 	"serviceescalations",
91 	"serviceescalation_contacts",
92 	"hostdependencies",
93 	"servicedependencies",
94 	"contacts",
95 	"contact_addresses",
96 	"contact_notificationcommands",
97 	"hosts",
98 	"host_parenthosts",
99 	"host_contacts",
100 	"services",
101 	"service_contacts",
102 	"customvariables",
103 	"host_contactgroups",
104 	"service_contactgroups",
105 	"hostescalation_contactgroups",
106 	"serviceescalation_contactgroups",
107 	"service_parentservices",
108         };
109 
110 
111 char *ndo2db_db_tablenames[NDO2DB_MAX_DBTABLES];
112 
113 /*
114 #define DEBUG_NDO2DB_QUERIES 1
115 */
116 
117 /****************************************************************************/
118 /* CONNECTION FUNCTIONS                                                     */
119 /****************************************************************************/
120 
121 /* initialize database structures */
ndo2db_db_init(ndo2db_idi * idi)122 int ndo2db_db_init(ndo2db_idi *idi){
123 	register int x;
124 
125 	if(idi==NULL)
126 		return NDO_ERROR;
127 
128 	/* initialize db server type */
129 	idi->dbinfo.server_type=ndo2db_db_settings.server_type;
130 
131 	/* initialize table names */
132 	for(x=0;x<NDO2DB_MAX_DBTABLES;x++){
133 		if((ndo2db_db_tablenames[x]=(char *)malloc(strlen(ndo2db_db_rawtablenames[x])+((ndo2db_db_settings.dbprefix==NULL)?0:strlen(ndo2db_db_settings.dbprefix))+1))==NULL)
134 			return NDO_ERROR;
135 		sprintf(ndo2db_db_tablenames[x],"%s%s",(ndo2db_db_settings.dbprefix==NULL)?"":ndo2db_db_settings.dbprefix,ndo2db_db_rawtablenames[x]);
136 	        }
137 
138 	/* initialize other variables */
139 	idi->dbinfo.connected=NDO_FALSE;
140 	idi->dbinfo.error=NDO_FALSE;
141 	idi->dbinfo.instance_id=0L;
142 	idi->dbinfo.conninfo_id=0L;
143 	idi->dbinfo.latest_program_status_time=(time_t)0L;
144 	idi->dbinfo.latest_host_status_time=(time_t)0L;
145 	idi->dbinfo.latest_service_status_time=(time_t)0L;
146 	idi->dbinfo.latest_queued_event_time=(time_t)0L;
147 	idi->dbinfo.latest_realtime_data_time=(time_t)0L;
148 	idi->dbinfo.latest_comment_time=(time_t)0L;
149 	idi->dbinfo.clean_event_queue=NDO_FALSE;
150 	idi->dbinfo.last_notification_id=0L;
151 	idi->dbinfo.last_contact_notification_id=0L;
152 	idi->dbinfo.max_timedevents_age=ndo2db_db_settings.max_timedevents_age;
153 	idi->dbinfo.max_systemcommands_age=ndo2db_db_settings.max_systemcommands_age;
154 	idi->dbinfo.max_servicechecks_age=ndo2db_db_settings.max_servicechecks_age;
155 	idi->dbinfo.max_hostchecks_age=ndo2db_db_settings.max_hostchecks_age;
156 	idi->dbinfo.max_eventhandlers_age=ndo2db_db_settings.max_eventhandlers_age;
157 	idi->dbinfo.max_externalcommands_age=ndo2db_db_settings.max_externalcommands_age;
158 	idi->dbinfo.max_notifications_age=ndo2db_db_settings.max_notifications_age;
159 	idi->dbinfo.max_contactnotifications_age=ndo2db_db_settings.max_contactnotifications_age;
160 	idi->dbinfo.max_contactnotificationmethods_age=ndo2db_db_settings.max_contactnotificationmethods_age;
161 	idi->dbinfo.max_logentries_age=ndo2db_db_settings.max_logentries_age;
162 	idi->dbinfo.max_acknowledgements_age=ndo2db_db_settings.max_acknowledgements_age;
163 	idi->dbinfo.last_table_trim_time=(time_t)0L;
164 	idi->dbinfo.last_logentry_time=(time_t)0L;
165 	idi->dbinfo.last_logentry_data=NULL;
166 	idi->dbinfo.object_hashlist=NULL;
167 
168 	/* initialize db structures, etc. */
169 	if(!mysql_init(&idi->dbinfo.mysql_conn)){
170 		syslog(LOG_USER|LOG_INFO,"Error: mysql_init() failed\n");
171 		return NDO_ERROR;
172 	}
173 
174 	return NDO_OK;
175         }
176 
177 
178 /* clean up database structures */
ndo2db_db_deinit(ndo2db_idi * idi)179 int ndo2db_db_deinit(ndo2db_idi *idi){
180 	register int x;
181 
182 	if(idi==NULL)
183 		return NDO_ERROR;
184 
185 	/* free table names */
186 	for(x=0;x<NDO2DB_MAX_DBTABLES;x++){
187 		if(ndo2db_db_tablenames[x])
188 			free(ndo2db_db_tablenames[x]);
189 		ndo2db_db_tablenames[x]=NULL;
190 	        }
191 
192 	/* free cached object ids */
193 	ndo2db_free_cached_object_ids(idi);
194 
195 	return NDO_OK;
196         }
197 
198 
199 /* connects to the database server */
ndo2db_db_connect(ndo2db_idi * idi)200 int ndo2db_db_connect(ndo2db_idi *idi){
201 	int result=NDO_OK;
202 
203 	if(idi==NULL)
204 		return NDO_ERROR;
205 
206 	/* we're already connected... */
207 	if(idi->dbinfo.connected==NDO_TRUE)
208 		return NDO_OK;
209 
210 	if (!mysql_real_connect(
211 			&idi->dbinfo.mysql_conn,
212 			ndo2db_db_settings.host,
213 			ndo2db_db_settings.username,
214 			ndo2db_db_settings.password,
215 			ndo2db_db_settings.dbname,
216 			ndo2db_db_settings.port,
217 			ndo2db_db_settings.socket,
218 			CLIENT_REMEMBER_OPTIONS
219 	)) {
220 		mysql_close(&idi->dbinfo.mysql_conn);
221 		syslog(LOG_USER|LOG_INFO,"Error: Could not connect to MySQL database: %s",mysql_error(&idi->dbinfo.mysql_conn));
222 		result=NDO_ERROR;
223 		idi->disconnect_client=NDO_TRUE;
224 	} else {
225 		idi->dbinfo.connected=NDO_TRUE;
226 		syslog(LOG_USER|LOG_DEBUG,"Successfully connected to MySQL database");
227 	}
228 
229 	return result;
230         }
231 
232 
233 /* disconnects from the database server */
ndo2db_db_disconnect(ndo2db_idi * idi)234 int ndo2db_db_disconnect(ndo2db_idi *idi){
235 
236 	if(idi==NULL)
237 		return NDO_ERROR;
238 
239 	/* we're not connected... */
240 	if(idi->dbinfo.connected==NDO_FALSE)
241 		return NDO_OK;
242 
243 	/* close the connection to the database server */
244 	mysql_close(&idi->dbinfo.mysql_conn);
245 	idi->dbinfo.connected=NDO_FALSE;
246 	syslog(LOG_USER|LOG_DEBUG,"Successfully disconnected from MySQL database");
247 
248 	return NDO_OK;
249         }
250 
251 
252 /* post-connect routines */
ndo2db_db_hello(ndo2db_idi * idi)253 int ndo2db_db_hello(ndo2db_idi *idi){
254 	char *buf=NULL;
255 	char *ts=NULL;
256 	int result=NDO_OK;
257 	int have_instance=NDO_FALSE;
258 	time_t current_time;
259 
260 	/* make sure we have an instance name */
261 	if(idi->instance_name==NULL)
262 		idi->instance_name=strdup("default");
263 
264 	/* get existing instance */
265 	if(asprintf(&buf,"SELECT instance_id FROM %s WHERE instance_name='%s'",ndo2db_db_tablenames[NDO2DB_DBTABLE_INSTANCES],idi->instance_name)==-1)
266 		buf=NULL;
267 	if((result=ndo2db_db_query(idi,buf))==NDO_OK){
268 		idi->dbinfo.mysql_result=mysql_store_result(&idi->dbinfo.mysql_conn);
269 		if((idi->dbinfo.mysql_row=mysql_fetch_row(idi->dbinfo.mysql_result))!=NULL){
270 			ndo2db_convert_string_to_unsignedlong(idi->dbinfo.mysql_row[0],&idi->dbinfo.instance_id);
271 			have_instance=NDO_TRUE;
272 		}
273 		mysql_free_result(idi->dbinfo.mysql_result);
274 		idi->dbinfo.mysql_result=NULL;
275 	}
276 	free(buf);
277 
278 	/* insert new instance if necessary */
279 	if(have_instance==NDO_FALSE){
280 		if(asprintf(&buf,"INSERT INTO %s SET instance_name='%s'",ndo2db_db_tablenames[NDO2DB_DBTABLE_INSTANCES],idi->instance_name)==-1)
281 			buf=NULL;
282 		if((result=ndo2db_db_query(idi,buf))==NDO_OK){
283 			idi->dbinfo.instance_id=mysql_insert_id(&idi->dbinfo.mysql_conn);
284 		}
285 		free(buf);
286 	        }
287 
288 	ts=ndo2db_db_timet_to_sql(idi,idi->data_start_time);
289 
290 	/* record initial connection information */
291 	if(asprintf(&buf,"INSERT INTO %s SET instance_id='%lu', connect_time=NOW(), last_checkin_time=NOW(), bytes_processed='0', lines_processed='0', entries_processed='0', agent_name='%s', agent_version='%s', disposition='%s', connect_source='%s', connect_type='%s', data_start_time=%s"
292 		    ,ndo2db_db_tablenames[NDO2DB_DBTABLE_CONNINFO]
293 		    ,idi->dbinfo.instance_id
294 		    ,idi->agent_name
295 		    ,idi->agent_version
296 		    ,idi->disposition
297 		    ,idi->connect_source
298 		    ,idi->connect_type
299 		    ,ts
300 		   )==-1)
301 		buf=NULL;
302 	if((result=ndo2db_db_query(idi,buf))==NDO_OK){
303 		idi->dbinfo.conninfo_id=mysql_insert_id(&idi->dbinfo.mysql_conn);
304 	}
305 	free(buf);
306 	free(ts);
307 
308 	/* get cached object ids... */
309 	ndo2db_get_cached_object_ids(idi);
310 
311 	/* get latest times from various tables... */
312 	ndo2db_db_get_latest_data_time(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_PROGRAMSTATUS],"status_update_time",(unsigned long *)&idi->dbinfo.latest_program_status_time);
313 	ndo2db_db_get_latest_data_time(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_HOSTSTATUS],"status_update_time",(unsigned long *)&idi->dbinfo.latest_host_status_time);
314 	ndo2db_db_get_latest_data_time(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_SERVICESTATUS],"status_update_time",(unsigned long *)&idi->dbinfo.latest_service_status_time);
315 	ndo2db_db_get_latest_data_time(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_CONTACTSTATUS],"status_update_time",(unsigned long *)&idi->dbinfo.latest_contact_status_time);
316 	ndo2db_db_get_latest_data_time(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_TIMEDEVENTQUEUE],"queued_time",(unsigned long *)&idi->dbinfo.latest_queued_event_time);
317 	ndo2db_db_get_latest_data_time(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_COMMENTS],"entry_time",(unsigned long *)&idi->dbinfo.latest_comment_time);
318 
319 	/* calculate time of latest realtime data */
320 	idi->dbinfo.latest_realtime_data_time=(time_t)0L;
321 	if(idi->dbinfo.latest_program_status_time>idi->dbinfo.latest_realtime_data_time)
322 		idi->dbinfo.latest_realtime_data_time=idi->dbinfo.latest_program_status_time;
323 	if(idi->dbinfo.latest_host_status_time>idi->dbinfo.latest_realtime_data_time)
324 		idi->dbinfo.latest_realtime_data_time=idi->dbinfo.latest_host_status_time;
325 	if(idi->dbinfo.latest_service_status_time>idi->dbinfo.latest_realtime_data_time)
326 		idi->dbinfo.latest_realtime_data_time=idi->dbinfo.latest_service_status_time;
327 	if(idi->dbinfo.latest_contact_status_time>idi->dbinfo.latest_realtime_data_time)
328 		idi->dbinfo.latest_realtime_data_time=idi->dbinfo.latest_contact_status_time;
329 	if(idi->dbinfo.latest_queued_event_time>idi->dbinfo.latest_realtime_data_time)
330 		idi->dbinfo.latest_realtime_data_time=idi->dbinfo.latest_queued_event_time;
331 
332 	/* get current time */
333 	/* make sure latest time stamp isn't in the future - this will cause problems if a backwards system time change occurs */
334 	time(&current_time);
335 	if(idi->dbinfo.latest_realtime_data_time>current_time)
336 		idi->dbinfo.latest_realtime_data_time=current_time;
337 
338 	/* set flags to clean event queue, etc. */
339 	idi->dbinfo.clean_event_queue=NDO_TRUE;
340 
341 	/* set misc data */
342 	idi->dbinfo.last_notification_id=0L;
343 	idi->dbinfo.last_contact_notification_id=0L;
344 
345 	return result;
346         }
347 
348 
349 /* pre-disconnect routines */
ndo2db_db_goodbye(ndo2db_idi * idi)350 int ndo2db_db_goodbye(ndo2db_idi *idi){
351 	int result=NDO_OK;
352 	char *buf=NULL;
353 	char *ts=NULL;
354 
355 	ts=ndo2db_db_timet_to_sql(idi,idi->data_end_time);
356 
357 	/* record last connection information */
358 	if(asprintf(&buf,"UPDATE %s SET disconnect_time=NOW(), last_checkin_time=NOW(), data_end_time=%s, bytes_processed='%lu', lines_processed='%lu', entries_processed='%lu' WHERE conninfo_id='%lu'"
359 		    ,ndo2db_db_tablenames[NDO2DB_DBTABLE_CONNINFO]
360 		    ,ts
361 		    ,idi->bytes_processed
362 		    ,idi->lines_processed
363 		    ,idi->entries_processed
364 		    ,idi->dbinfo.conninfo_id
365 		   )==-1)
366 		buf=NULL;
367 	result=ndo2db_db_query(idi,buf);
368 	free(buf);
369 
370 	free(ts);
371 
372 	return result;
373         }
374 
375 
376 /* checking routines */
ndo2db_db_checkin(ndo2db_idi * idi)377 int ndo2db_db_checkin(ndo2db_idi *idi){
378 	int result=NDO_OK;
379 	char *buf=NULL;
380 
381 	/* record last connection information */
382 	if(asprintf(&buf,"UPDATE %s SET last_checkin_time=NOW(), bytes_processed='%lu', lines_processed='%lu', entries_processed='%lu' WHERE conninfo_id='%lu'"
383 		    ,ndo2db_db_tablenames[NDO2DB_DBTABLE_CONNINFO]
384 		    ,idi->bytes_processed
385 		    ,idi->lines_processed
386 		    ,idi->entries_processed
387 		    ,idi->dbinfo.conninfo_id
388 		   )==-1)
389 		buf=NULL;
390 	result=ndo2db_db_query(idi,buf);
391 	free(buf);
392 
393 	time(&ndo2db_db_last_checkin_time);
394 
395 	return result;
396         }
397 
398 
399 
400 /****************************************************************************/
401 /* MISC FUNCTIONS                                                           */
402 /****************************************************************************/
403 
404 /* escape a string for a SQL statement */
ndo2db_db_escape_string(ndo2db_idi * idi,char * buf)405 char *ndo2db_db_escape_string(ndo2db_idi *idi, char *buf){
406 	register int x,y,z;
407 	char *newbuf=NULL;
408 
409 	if(idi==NULL || buf==NULL)
410 		return NULL;
411 
412 	z=strlen(buf);
413 
414 	/* allocate space for the new string */
415 	if((newbuf=(char *)malloc((z*2)+1))==NULL)
416 		return NULL;
417 
418 	/* escape characters */
419 	for(x=0,y=0;x<z;x++){
420 
421 		if(buf[x]=='\'' || buf[x]=='\"' || buf[x]=='*' || buf[x]=='\\' || buf[x]=='$' || buf[x]=='?' || buf[x]=='.' || buf[x]=='^' || buf[x]=='+' || buf[x]=='[' || buf[x]==']' || buf[x]=='(' || buf[x]==')')
422 			newbuf[y++]='\\';
423 
424 		newbuf[y++]=buf[x];
425 	        }
426 
427 	/* terminate escape string */
428 	newbuf [y]='\0';
429 
430 	return newbuf;
431         }
432 
433 
434 /* SQL query conversion of time_t format to date/time format */
ndo2db_db_timet_to_sql(ndo2db_idi * idi,time_t t)435 char *ndo2db_db_timet_to_sql(ndo2db_idi *idi, time_t t){
436 	char *buf=NULL;
437 	(void)idi; /* Unused, don't warn. */
438 
439 	asprintf(&buf,"FROM_UNIXTIME(%lu)",(unsigned long)t);
440 
441 	return buf;
442         }
443 
444 
445 /* SQL query conversion of date/time format to time_t format */
ndo2db_db_sql_to_timet(ndo2db_idi * idi,char * field)446 char *ndo2db_db_sql_to_timet(ndo2db_idi *idi, char *field){
447 	char *buf=NULL;
448 	(void)idi; /* Unused, don't warn. */
449 
450 	asprintf(&buf,"UNIX_TIMESTAMP(%s)",(field==NULL)?"":field);
451 
452 	return buf;
453         }
454 
455 
456 /* executes a SQL statement */
ndo2db_db_query(ndo2db_idi * idi,char * buf)457 int ndo2db_db_query(ndo2db_idi *idi, char *buf){
458 	int result=NDO_OK;
459 	int query_result=0;
460 
461 	if(idi==NULL || buf==NULL)
462 		return NDO_ERROR;
463 
464 	/* if we're not connected, try and reconnect... */
465 	if(idi->dbinfo.connected==NDO_FALSE){
466 		if(ndo2db_db_connect(idi)==NDO_ERROR)
467 			return NDO_ERROR;
468 		ndo2db_db_hello(idi);
469 	        }
470 
471 #ifdef DEBUG_NDO2DB_QUERIES
472 	printf("%s\n\n",buf);
473 #endif
474 
475 	ndo2db_log_debug_info(NDO2DB_DEBUGL_SQL,0,"%s\n",buf);
476 
477 	if (mysql_query(&idi->dbinfo.mysql_conn,buf)) {
478 		syslog(LOG_USER|LOG_INFO,"Error: mysql_query() failed for '%s'\n",buf);
479 		syslog(LOG_USER|LOG_INFO,"mysql_error: '%s'\n", mysql_error(&idi->dbinfo.mysql_conn));
480 		result=NDO_ERROR;
481 	}
482 
483 	/* handle errors */
484 	if(result==NDO_ERROR)
485 		ndo2db_handle_db_error(idi,query_result);
486 
487 	return result;
488         }
489 
490 
491 /* frees memory associated with a query */
ndo2db_db_free_query(ndo2db_idi * idi)492 int ndo2db_db_free_query(ndo2db_idi *idi){
493 
494 	if(idi==NULL)
495 		return NDO_ERROR;
496 
497 	return NDO_OK;
498         }
499 
500 
501 /* handles SQL query errors */
ndo2db_handle_db_error(ndo2db_idi * idi,int query_result)502 int ndo2db_handle_db_error(ndo2db_idi *idi, int query_result){
503 	int result=0;
504 
505 	if(idi==NULL)
506 		return NDO_ERROR;
507 
508 	/* we're not currently connected... */
509 	if(idi->dbinfo.connected==NDO_FALSE)
510 		return NDO_OK;
511 
512 	result=mysql_errno(&idi->dbinfo.mysql_conn);
513 	if(result==CR_SERVER_LOST || result==CR_SERVER_GONE_ERROR){
514 		syslog(LOG_USER|LOG_INFO,"Error: Connection to MySQL database has been lost!\n");
515 		ndo2db_db_disconnect(idi);
516 		idi->disconnect_client=NDO_TRUE;
517 	}
518 
519 	return NDO_OK;
520         }
521 
522 
523 /* clears data from a given table (current instance only) */
ndo2db_db_clear_table(ndo2db_idi * idi,char * table_name)524 int ndo2db_db_clear_table(ndo2db_idi *idi, char *table_name){
525 	char *buf=NULL;
526 	int result=NDO_OK;
527 
528 	if(idi==NULL || table_name==NULL)
529 		return NDO_ERROR;
530 
531 	if(asprintf(&buf,"DELETE FROM %s WHERE instance_id='%lu'"
532 		    ,table_name
533 		    ,idi->dbinfo.instance_id
534 		   )==-1)
535 		buf=NULL;
536 
537 	result=ndo2db_db_query(idi,buf);
538 	free(buf);
539 
540 	return result;
541         }
542 
543 
544 /* gets latest data time value from a given table */
ndo2db_db_get_latest_data_time(ndo2db_idi * idi,char * table_name,char * field_name,unsigned long * t)545 int ndo2db_db_get_latest_data_time(ndo2db_idi *idi, char *table_name, char *field_name, unsigned long *t){
546 	char *buf=NULL;
547 	char *ts[1];
548 	int result=NDO_OK;
549 
550 	if(idi==NULL || table_name==NULL || field_name==NULL || t==NULL)
551 		return NDO_ERROR;
552 
553 	*t=(time_t)0L;
554 	ts[0]=ndo2db_db_sql_to_timet(idi,field_name);
555 
556 	if(asprintf(&buf,"SELECT %s AS latest_time FROM %s WHERE instance_id='%lu' ORDER BY %s DESC LIMIT 0,1"
557 		    ,ts[0]
558 		    ,table_name
559 		    ,idi->dbinfo.instance_id
560 		    ,field_name
561 		   )==-1)
562 		buf=NULL;
563 
564 	if((result=ndo2db_db_query(idi,buf))==NDO_OK){
565 		idi->dbinfo.mysql_result=mysql_store_result(&idi->dbinfo.mysql_conn);
566 		if((idi->dbinfo.mysql_row=mysql_fetch_row(idi->dbinfo.mysql_result))!=NULL){
567 			ndo2db_convert_string_to_unsignedlong(idi->dbinfo.mysql_row[0],t);
568 		}
569 		mysql_free_result(idi->dbinfo.mysql_result);
570 		idi->dbinfo.mysql_result=NULL;
571 	}
572 	free(buf);
573 	free(ts[0]);
574 
575 	return result;
576         }
577 
578 
579 /* trim/delete old data from a given table */
ndo2db_db_trim_data_table(ndo2db_idi * idi,char * table_name,char * field_name,unsigned long t)580 int ndo2db_db_trim_data_table(ndo2db_idi *idi, char *table_name, char *field_name, unsigned long t){
581 	char *buf=NULL;
582 	char *ts[1];
583 	int result=NDO_OK;
584 
585 	if(idi==NULL || table_name==NULL || field_name==NULL)
586 		return NDO_ERROR;
587 
588 	ts[0]=ndo2db_db_timet_to_sql(idi,(time_t)t);
589 
590 	if(asprintf(&buf,"DELETE FROM %s WHERE instance_id='%lu' AND %s<%s"
591 		    ,table_name
592 		    ,idi->dbinfo.instance_id
593 		    ,field_name
594 		    ,ts[0]
595 		   )==-1)
596 		buf=NULL;
597 
598 	result=ndo2db_db_query(idi,buf);
599 	free(buf);
600 	free(ts[0]);
601 
602 	return result;
603         }
604 
605 
606 /* performs some periodic table maintenance... */
ndo2db_db_perform_maintenance(ndo2db_idi * idi)607 int ndo2db_db_perform_maintenance(ndo2db_idi *idi){
608 	time_t current_time;
609 
610 	/* get the current time */
611 	time(&current_time);
612 
613 	/* trim tables */
614 	if ((current_time-(time_t)60)>idi->dbinfo.last_table_trim_time) {
615 		if (idi->dbinfo.max_timedevents_age>0L) {
616 			syslog(LOG_USER|LOG_INFO,"Trimming timedevents.");
617 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_TIMEDEVENTS],"scheduled_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_timedevents_age));
618 		}
619 		if (idi->dbinfo.max_systemcommands_age>0L) {
620 			syslog(LOG_USER|LOG_INFO,"Trimming systemcommands.");
621 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_SYSTEMCOMMANDS],"start_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_systemcommands_age));
622 		}
623 		if (idi->dbinfo.max_servicechecks_age>0L) {
624 			syslog(LOG_USER|LOG_INFO,"Trimming servicechecks.");
625 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_SERVICECHECKS],"start_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_servicechecks_age));
626 		}
627 		if (idi->dbinfo.max_hostchecks_age>0L) {
628 			syslog(LOG_USER|LOG_INFO,"Trimming hostchecks.");
629 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_HOSTCHECKS],"start_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_hostchecks_age));
630 		}
631 		if (idi->dbinfo.max_eventhandlers_age>0L) {
632 			syslog(LOG_USER|LOG_INFO,"Trimming eventhandlers.");
633 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_EVENTHANDLERS],"start_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_eventhandlers_age));
634 		}
635 		if (idi->dbinfo.max_externalcommands_age>0L) {
636 			syslog(LOG_USER|LOG_INFO,"Trimming externalcommands.");
637 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_EXTERNALCOMMANDS],"entry_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_externalcommands_age));
638 		}
639 		if (idi->dbinfo.max_notifications_age>0L) {
640 			syslog(LOG_USER|LOG_INFO,"Trimming notifications.");
641 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_NOTIFICATIONS],"start_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_notifications_age));
642 		}
643 		if (idi->dbinfo.max_contactnotifications_age>0L) {
644 			syslog(LOG_USER|LOG_INFO,"Trimming contactnotifications.");
645 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_CONTACTNOTIFICATIONS],"start_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_contactnotifications_age));
646 		}
647 		if (idi->dbinfo.max_contactnotificationmethods_age>0L) {
648 			syslog(LOG_USER|LOG_INFO,"Trimming contactnotificationmethods.");
649 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_CONTACTNOTIFICATIONMETHODS],"start_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_contactnotificationmethods_age));
650 		}
651 		if (idi->dbinfo.max_logentries_age>0L) {
652 			syslog(LOG_USER|LOG_INFO,"Trimming logentries.");
653 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_LOGENTRIES],"entry_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_logentries_age));
654 		}
655 		if (idi->dbinfo.max_acknowledgements_age>0L) {
656 			syslog(LOG_USER|LOG_INFO,"Trimming acknowledgements.");
657 			ndo2db_db_trim_data_table(idi,ndo2db_db_tablenames[NDO2DB_DBTABLE_ACKNOWLEDGEMENTS],"entry_time",(time_t)((unsigned long)current_time-idi->dbinfo.max_acknowledgements_age));
658 		}
659 		idi->dbinfo.last_table_trim_time=current_time;
660 	}
661 
662 	return NDO_OK;
663 }
664