Line data Source code
1 : /********************************************************************\
2 :
3 : Name: history_common.cxx
4 : Created by: Konstantin Olchanski
5 :
6 : Contents: History functions common to all history implementations
7 :
8 : \********************************************************************/
9 :
10 : #include <stdio.h>
11 : #include <stdlib.h>
12 : #include <string.h>
13 : #include <assert.h>
14 :
15 : #include <map>
16 :
17 : #include "midas.h"
18 : #include "msystem.h"
19 : #include "history.h"
20 : #include "mstrlcpy.h"
21 :
22 0 : int hs_get_history(HNDLE hDB, HNDLE hKey, int flags, int debug_flag, MidasHistoryInterface **mh)
23 : {
24 : int status, size;
25 0 : std::string type;
26 : int active;
27 : int debug;
28 : KEY key;
29 :
30 0 : *mh = NULL;
31 :
32 0 : if (!hKey || (flags&HS_GET_DEFAULT)) {
33 0 : status = hs_find_reader_channel(hDB, &hKey, debug_flag);
34 0 : if (status != HS_SUCCESS)
35 0 : return status;
36 : }
37 :
38 0 : status = db_get_key(hDB, hKey, &key);
39 0 : assert(status == DB_SUCCESS);
40 :
41 0 : if (strcasecmp(key.name, "image") == 0) {
42 0 : if (debug_flag)
43 0 : cm_msg(MINFO, "hs_get_history", "History channel \'IMAGE\' handled by image facility");
44 0 : return DB_NO_KEY;
45 : }
46 :
47 0 : active = 0;
48 0 : size = sizeof(active);
49 0 : status = db_get_value(hDB, hKey, "Active", &active, &size, TID_BOOL, TRUE);
50 0 : assert(status == DB_SUCCESS);
51 :
52 0 : status = db_get_value_string(hDB, hKey, "Type", 0, &type, TRUE);
53 0 : assert(status == DB_SUCCESS);
54 :
55 0 : debug = 0;
56 0 : size = sizeof(debug);
57 0 : status = db_get_value(hDB, hKey, "Debug", &debug, &size, TID_INT, TRUE);
58 0 : assert(status == DB_SUCCESS);
59 :
60 0 : if (debug_flag)
61 0 : printf("hs_get_history: see channel hkey %d, name \'%s\', active %d, type [%s], debug %d\n", hKey, key.name, active, type.c_str(), debug);
62 :
63 0 : if (strcasecmp(type.c_str(), "MIDAS")==0) {
64 :
65 0 : std::string tmp;
66 : // create ODB "History dir"
67 0 : db_get_value_string(hDB, hKey, "History dir", 0, &tmp, TRUE);
68 :
69 0 : std::string path = cm_get_history_path(key.name);
70 :
71 : int i;
72 :
73 0 : i = 1;
74 0 : size = sizeof(i);
75 0 : status = db_get_value(hDB, 0, "/Logger/WriteFileHistory", &i, &size, TID_BOOL, FALSE);
76 0 : if (status==DB_SUCCESS) {
77 0 : cm_msg(MERROR, "hs_get_history", "mlogger ODB setting /Logger/WriteFileHistory is obsolete, please delete it. Use /Logger/History/MIDAS/Active instead");
78 0 : if (i==0)
79 0 : active = 0;
80 : }
81 :
82 0 : if (active || (flags & HS_GET_INACTIVE)) {
83 0 : *mh = MakeMidasHistory();
84 0 : assert(*mh);
85 :
86 0 : (*mh)->hs_set_debug(debug);
87 :
88 0 : status = (*mh)->hs_connect(path.c_str());
89 0 : if (status != HS_SUCCESS) {
90 0 : cm_msg(MERROR, "hs_get_history", "Cannot connect to MIDAS history, status %d", status);
91 0 : return status;
92 : }
93 :
94 0 : if (debug_flag)
95 0 : cm_msg(MINFO, "hs_get_history", "Connected history channel \'%s\' type MIDAS history in \"%s\"", key.name, path.c_str());
96 : }
97 :
98 0 : } else if (strcasecmp(type.c_str(), "ODBC")==0) {
99 :
100 : if (1) {
101 : int i;
102 :
103 0 : i = 0;
104 0 : size = sizeof(i);
105 0 : status = db_get_value(hDB, 0, "/Logger/ODBC_Debug", &i, &size, TID_INT, FALSE);
106 0 : if (status==DB_SUCCESS) {
107 0 : cm_msg(MERROR, "hs_get_history", "mlogger ODB setting /Logger/ODBC_Debug is obsolete, please delete it. Use /Logger/History/ODBC/Debug instead");
108 : }
109 :
110 0 : status = db_get_value(hDB, 0, "/History/ODBC_Debug", &i, &size, TID_INT, FALSE);
111 0 : if (status==DB_SUCCESS) {
112 0 : cm_msg(MERROR, "hs_get_history", "mhttpd ODB setting /History/ODBC_Debug is obsolete, please delete it. Use /Logger/History/ODBC/Debug instead");
113 : }
114 :
115 0 : std::string dsn;
116 :
117 0 : status = db_get_value_string(hDB, 0, "/Logger/ODBC_DSN", 0, &dsn, FALSE);
118 0 : if (status==DB_SUCCESS) {
119 0 : cm_msg(MERROR, "hs_get_history", "mlogger ODB setting /Logger/ODBC_DSN is obsolete, please delete it. Use /Logger/History/ODBC/Writer_ODBC_DSN instead");
120 : }
121 :
122 0 : status = db_get_value_string(hDB, 0, "/History/ODBC_DSN", 0, &dsn, FALSE);
123 0 : if (status==DB_SUCCESS) {
124 0 : cm_msg(MERROR, "hs_get_history", "mhttpd ODB setting /History/ODBC_DSN is obsolete, please delete it. Use /Logger/History/ODBC/Reader_ODBC_DSN instead");
125 : }
126 0 : }
127 :
128 0 : std::string writer_dsn = "history_writer";
129 0 : std::string reader_dsn = "history_reader";
130 :
131 0 : status = db_get_value_string(hDB, hKey, "Writer_ODBC_DSN", 0, &writer_dsn, TRUE);
132 0 : assert(status == DB_SUCCESS);
133 :
134 0 : status = db_get_value_string(hDB, hKey, "Reader_ODBC_DSN", 0, &reader_dsn, TRUE);
135 0 : assert(status == DB_SUCCESS);
136 :
137 0 : std::string dsn;
138 :
139 0 : if (flags & HS_GET_READER)
140 0 : dsn = reader_dsn;
141 0 : else if (flags & HS_GET_WRITER)
142 0 : dsn = writer_dsn;
143 :
144 0 : if (active || (flags & HS_GET_INACTIVE)) {
145 0 : if (debug == 2) {
146 0 : *mh = MakeMidasHistorySqlDebug();
147 0 : } else if (dsn.length() > 1) {
148 0 : *mh = MakeMidasHistoryODBC();
149 : }
150 :
151 0 : if (*mh == NULL)
152 0 : return HS_FILE_ERROR;
153 :
154 0 : (*mh)->hs_set_debug(debug);
155 :
156 0 : status = (*mh)->hs_connect(dsn.c_str());
157 0 : if (status != HS_SUCCESS) {
158 0 : cm_msg(MERROR, "hs_get_history", "Cannot connect to ODBC SQL driver \'%s\', status %d. Check .odbc.ini and MIDAS documentation", dsn.c_str(), status);
159 0 : return status;
160 : }
161 :
162 0 : if (debug_flag)
163 0 : cm_msg(MINFO, "hs_get_history", "Connected history channel \'%s\' type ODBC (MySQL), DSN \'%s\'", key.name, dsn.c_str());
164 : }
165 0 : } else if (strcasecmp(type.c_str(), "SQLITE")==0) {
166 :
167 0 : std::string tmp;
168 : // create ODB "History dir"
169 0 : db_get_value_string(hDB, hKey, "History dir", 0, &tmp, TRUE);
170 :
171 0 : std::string path = cm_get_history_path(key.name);
172 :
173 0 : if (active || (flags & HS_GET_INACTIVE)) {
174 0 : *mh = MakeMidasHistorySqlite();
175 0 : if (*mh == NULL)
176 0 : return HS_FILE_ERROR;
177 :
178 0 : (*mh)->hs_set_debug(debug);
179 :
180 0 : status = (*mh)->hs_connect(path.c_str());
181 0 : if (status != HS_SUCCESS) {
182 0 : cm_msg(MERROR, "hs_get_history", "Cannot connect to SQLITE history, status %d, see messages", status);
183 0 : return status;
184 : }
185 :
186 0 : if (debug_flag)
187 0 : cm_msg(MINFO, "hs_get_history", "Connected history channel \'%s\' type SQLITE in \'%s\'", key.name, path.c_str());
188 : }
189 0 : } else if (strcasecmp(type.c_str(), "FILE")==0) {
190 :
191 0 : std::string tmp;
192 : // create ODB "History dir"
193 0 : db_get_value_string(hDB, hKey, "History dir", 0, &tmp, TRUE);
194 :
195 0 : std::string path = cm_get_history_path(key.name);
196 :
197 : //printf("FILE path [%s], expt_path [%s], local History Dir [%s]\n", path.c_str(), expt_path, dir);
198 :
199 0 : if (active || (flags & HS_GET_INACTIVE)) {
200 0 : *mh = MakeMidasHistoryFile();
201 0 : if (*mh == NULL)
202 0 : return HS_FILE_ERROR;
203 :
204 0 : (*mh)->hs_set_debug(debug);
205 :
206 0 : status = (*mh)->hs_connect(path.c_str());
207 0 : if (status != HS_SUCCESS) {
208 0 : cm_msg(MERROR, "hs_get_history", "Cannot connect to FILE history, status %d, see messages", status);
209 0 : return status;
210 : }
211 :
212 0 : if (debug_flag)
213 0 : cm_msg(MINFO, "hs_get_history", "Connected history channel \'%s\' type FILE in \'%s\'", key.name, path.c_str());
214 : }
215 0 : } else if (strcasecmp(type.c_str(), "MYSQL")==0) {
216 :
217 0 : std::string writer_dsn = "mysql_writer.txt";
218 0 : std::string reader_dsn = "mysql_reader.txt";
219 :
220 0 : status = db_get_value_string(hDB, hKey, "MYSQL Writer", 0, &writer_dsn, TRUE);
221 0 : assert(status == DB_SUCCESS);
222 :
223 0 : status = db_get_value_string(hDB, hKey, "MYSQL Reader", 0, &reader_dsn, TRUE);
224 0 : assert(status == DB_SUCCESS);
225 :
226 0 : std::string dsn;
227 :
228 0 : if (flags & HS_GET_READER)
229 0 : dsn = reader_dsn;
230 0 : else if (flags & HS_GET_WRITER)
231 0 : dsn = writer_dsn;
232 :
233 0 : std::string path;
234 :
235 0 : if (dsn[0] == DIR_SEPARATOR)
236 0 : path = dsn;
237 : else {
238 0 : std::string expt_path = cm_get_path();
239 :
240 0 : path = expt_path;
241 : // normally expt_path has the trailing '/', see midas.c::cm_set_path()
242 0 : if (path[path.length() - 1] != DIR_SEPARATOR)
243 0 : path += DIR_SEPARATOR_STR;
244 0 : path += dsn;
245 0 : }
246 :
247 0 : if (active || (flags & HS_GET_INACTIVE)) {
248 0 : *mh = MakeMidasHistoryMysql();
249 0 : if (*mh == NULL)
250 0 : return HS_FILE_ERROR;
251 :
252 0 : (*mh)->hs_set_debug(debug);
253 :
254 0 : status = (*mh)->hs_connect(path.c_str());
255 0 : if (status != HS_SUCCESS) {
256 0 : cm_msg(MERROR, "hs_get_history", "Cannot connect to MYSQL history, status %d", status);
257 0 : return status;
258 : }
259 :
260 0 : if (debug_flag)
261 0 : cm_msg(MINFO, "hs_get_history", "Connected history channel \'%s\' type MYSQL at \'%s\'", key.name,
262 : path.c_str());
263 : }
264 0 : } else if (strcasecmp(type.c_str(), "PGSQL")==0) {
265 :
266 0 : std::string writer_dsn = "pgsql_writer.txt";
267 0 : std::string reader_dsn = "pgsql_reader.txt";
268 :
269 0 : status = db_get_value_string(hDB, hKey, "PGSQL Writer", 0, &writer_dsn, TRUE);
270 0 : assert(status == DB_SUCCESS);
271 :
272 0 : status = db_get_value_string(hDB, hKey, "PGSQL Reader", 0, &reader_dsn, TRUE);
273 0 : assert(status == DB_SUCCESS);
274 :
275 0 : std::string dsn;
276 :
277 0 : if (flags & HS_GET_READER)
278 0 : dsn = reader_dsn;
279 0 : else if (flags & HS_GET_WRITER)
280 0 : dsn = writer_dsn;
281 :
282 0 : std::string path;
283 :
284 0 : if (dsn[0] == DIR_SEPARATOR)
285 0 : path = dsn;
286 : else {
287 0 : std::string expt_path = cm_get_path();
288 :
289 0 : path = expt_path;
290 : // normally expt_path has the trailing '/', see midas.c::cm_set_path()
291 0 : if (path[path.length() - 1] != DIR_SEPARATOR)
292 0 : path += DIR_SEPARATOR_STR;
293 0 : path += dsn;
294 0 : }
295 :
296 0 : int downsample = 0;
297 0 : size = sizeof(downsample);
298 0 : status = db_get_value(hDB, hKey, "Enable downsampling queries", &downsample, &size, TID_BOOL, TRUE);
299 0 : assert(status == DB_SUCCESS);
300 :
301 0 : if (active || (flags & HS_GET_INACTIVE)) {
302 0 : *mh = MakeMidasHistoryPgsql();
303 0 : if (*mh == NULL)
304 0 : return HS_FILE_ERROR;
305 :
306 0 : (*mh)->hs_set_debug(debug);
307 : //(*mh)->hs_set_downsample(downsample);
308 :
309 0 : status = (*mh)->hs_connect(path.c_str());
310 0 : if (status != HS_SUCCESS) {
311 0 : cm_msg(MERROR, "hs_get_history", "Cannot connect to PGSQL history, status %d", status);
312 0 : return status;
313 : }
314 :
315 0 : if (debug_flag)
316 0 : cm_msg(MINFO, "hs_get_history", "Connected history channel \'%s\' type PGSQL at \'%s\'", key.name,
317 : path.c_str());
318 : }
319 0 : } else if (strcasecmp(type.c_str(), "IMAGE")==0) {
320 0 : if (debug_flag)
321 0 : cm_msg(MINFO, "hs_get_history", "History channel \'IMAGE\' handled by image facility");
322 : } else {
323 0 : cm_msg(MERROR, "hs_get_history", "Logger history channel /Logger/History/%s/Type has invalid value \'%s\', valid values are MIDAS, ODBC, SQLITE, MYSQL, FILE and IMAGE", key.name, type.c_str());
324 0 : return HS_FILE_ERROR;
325 : }
326 :
327 0 : if (*mh == NULL)
328 0 : return HS_FILE_ERROR;
329 :
330 0 : mstrlcpy((*mh)->name, key.name, sizeof((*mh)->name));
331 0 : mstrlcpy((*mh)->type, type.c_str(), sizeof((*mh)->type));
332 :
333 0 : return HS_SUCCESS;
334 0 : }
335 :
336 : // find history reader channel, returns ODB handle to the history channel definition in /Logger/History/...
337 0 : int hs_find_reader_channel(HNDLE hDB, HNDLE* hKeyOut, int debug_flag)
338 : {
339 : int status;
340 : int size;
341 : HNDLE hKeyChan;
342 : HNDLE hKey;
343 0 : std::string hschanname;
344 :
345 0 : *hKeyOut = 0;
346 :
347 0 : status = db_find_key(hDB, 0, "/Logger/History", &hKeyChan);
348 0 : if (status != DB_SUCCESS) {
349 0 : cm_msg(MERROR, "hs_find_reader_channel", "Cannot find /Logger/History, db_find_key() status %d", status);
350 0 : return status;
351 : }
352 :
353 : // get history channel name selected by user in ODB
354 :
355 0 : status = db_get_value_string(hDB, 0, "/History/LoggerHistoryChannel", 0, &hschanname, TRUE);
356 0 : assert(status == DB_SUCCESS);
357 :
358 0 : if (hschanname.length() > 0) {
359 0 : status = db_find_key(hDB, hKeyChan, hschanname.c_str(), &hKey);
360 0 : if (status == DB_NO_KEY) {
361 0 : cm_msg(MERROR, "hs_find_reader_channel", "Misconfigured history: history channel name in /History/LoggerHistoryChannel is \'%s\', not present in /Logger/History, db_find_key() status %d", hschanname.c_str(), status);
362 0 : return HS_FILE_ERROR;
363 : }
364 0 : assert(status == DB_SUCCESS);
365 0 : *hKeyOut = hKey;
366 0 : return HS_SUCCESS;
367 : }
368 :
369 : // if selected channel name is blank, find first active channel
370 :
371 0 : for (int ichan=0; ; ichan++) {
372 0 : status = db_enum_key(hDB, hKeyChan, ichan, &hKey);
373 0 : if (status != DB_SUCCESS)
374 0 : break;
375 :
376 0 : int active = 0;
377 0 : size = sizeof(active);
378 0 : status = db_get_value(hDB, hKey, "Active", &active, &size, TID_BOOL, FALSE);
379 0 : if (status == DB_SUCCESS && active != 0) {
380 0 : *hKeyOut = hKey;
381 0 : return HS_SUCCESS;
382 : }
383 0 : }
384 :
385 0 : cm_msg(MERROR, "hs_find_reader_channel", "Cannot find default history: /History/LoggerHistoryChannel is empty and there are no active history channels in /Logger/History");
386 0 : return HS_FILE_ERROR;
387 0 : }
388 :
389 0 : static std::string hs_event_list_filename()
390 : {
391 0 : std::string path = cm_get_path();
392 0 : return path + ".LOGGER_HISTORY_EVENTS.TXT";
393 0 : }
394 :
395 : // save list of active events
396 0 : int hs_save_event_list(const std::vector<std::string> *pevents)
397 : {
398 0 : std::string ss;
399 0 : for (unsigned i=0; i<pevents->size(); i++)
400 0 : ss += (*pevents)[i] + "\n";
401 :
402 0 : std::string fname = hs_event_list_filename();
403 :
404 0 : FILE *fp = fopen(fname.c_str(), "w");
405 0 : if (!fp) {
406 0 : cm_msg(MERROR, "hs_save_event_list", "Cannot open file \'%s\', errno %d (%s)", fname.c_str(), errno, strerror(errno));
407 0 : return HS_FILE_ERROR;
408 : }
409 :
410 0 : const char* s = ss.c_str();
411 0 : int len = strlen(s);
412 :
413 0 : int wr = write(fileno(fp), s, len);
414 :
415 0 : if (wr != len) {
416 0 : cm_msg(MERROR, "hs_save_event_list", "Cannot write to file \'%s\', errno %d (%s)", fname.c_str(), errno, strerror(errno));
417 0 : fclose(fp);
418 0 : return HS_FILE_ERROR;
419 : }
420 :
421 0 : fclose(fp);
422 0 : return HS_SUCCESS;
423 0 : }
424 :
425 : // get list of active events
426 0 : int hs_read_event_list(std::vector<std::string> *pevents)
427 : {
428 0 : std::string fname = hs_event_list_filename();
429 :
430 0 : FILE *fp = fopen(fname.c_str(), "r");
431 0 : if (!fp) {
432 0 : cm_msg(MERROR, "hs_read_event_list", "Cannot open file \'%s\', errno %d (%s)", fname.c_str(), errno, strerror(errno));
433 0 : return HS_FILE_ERROR;
434 : }
435 :
436 : while (1) {
437 : char buf[256];
438 0 : char *s = fgets(buf, sizeof(buf), fp);
439 0 : if (!s) // EOF
440 0 : break;
441 : // kill trailing \n and \r
442 0 : s = strchr(buf, '\n');
443 0 : if (s)
444 0 : *s = 0;
445 0 : s = strchr(buf, '\r');
446 0 : if (s)
447 0 : *s = 0;
448 0 : pevents->push_back(buf);
449 0 : }
450 :
451 0 : fclose(fp);
452 0 : return HS_SUCCESS;
453 0 : }
454 :
455 : /* emacs
456 : * Local Variables:
457 : * tab-width: 8
458 : * c-basic-offset: 3
459 : * indent-tabs-mode: nil
460 : * End:
461 : */
|