***********************
** FILE NAME : message.cpp
** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
-** VERSION NUMBER : $Revision: 1.10 $
+** VERSION NUMBER : $Revision: 1.15 $
**
** DESCRIPTION : Implementation of the message handling classes
**
********************************
** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
** CREATION DATE : Sep 16, 2002
-** LAST UPDATE : Apr 29, 2003
+** LAST UPDATE : Jul 24, 2003
** MODIFICATIONS :
**************************************************************************/
/*****************************
$Log: message.cpp,v $
- Revision 1.10 2003-04-29 09:16:44 arjen
+ Revision 1.15 2003-10-27 11:28:27 arjen
+ Do not add another parameter_notification record is the notification
+ already exists for that parameter.
+
+ Revision 1.14 2003/09/01 06:57:14 arjen
+ Reject log entries that are found to be invalid.
+
+ Revision 1.13 2003/08/16 15:28:45 arjen
+ Fixed a namespace problem
+
+ Revision 1.12 2003/08/11 16:56:16 arjen
+ Different kinds of log files are parsed by a collection of objects
+ of different classes, derived from the base class line_cooker
+ Depending on the message content or the message_type element in
+ XML, one of these objects is selected.
+
+ Logrunner is integrated with gcm_input. Although its functionality
+ is still limited, a connection between logrunner and gcm_input
+ is beginning to form.
+
+ Revision 1.11 2003/08/05 08:15:00 arjen
+ Debug output to the log stream instead of cerr.
+ Fixed namespace problems in XPath searches of the DOM.
+ Moved string utility functions to a separate file.
+
+ Revision 1.10 2003/04/29 09:16:44 arjen
Read XML input,
Only cooked log entries for now.
*****************************/
-static const char *RCSID = "$Id: message.cpp,v 1.10 2003-04-29 09:16:44 arjen Exp $";
+static const char *RCSID = "$Id: message.cpp,v 1.15 2003-10-27 11:28:27 arjen Exp $";
#include <algorithm>
#include <libxml/xpath.h>
#include <libxml/debugXML.h>
#include "message.h"
+//#define DEBUG
+
extern bool verbose; /* Defined in the main application */
extern bool testmode;
+extern bool incremental;
+extern std::ostream *log;
/* Utility functions */
-String SQL_Escape(String s);
+extern String SQL_Escape(String s);
/*=========================================================================
** NAME : operator >>
certainty = 0.0;
}
-static const String syslog_date_re("[[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}");
static const String mail_date_re("[[:alpha:]]{3}, [ 123]?[0-9] [[:alpha:]]{3} [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} [+-][0-9]{4}");
static const String unix_date_re("[[:alpha:]]{3} [[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4}");
-static const String email_address_re("[[:alnum:]_.-]+@[[:alnum:]_.-]+");
-static const regex re_syslog(syslog_date_re + " [[:alnum:]]+ [[:alpha:]]+.*:.+");
-static const regex re_syslog_irix(syslog_date_re + " [0-7][A-T]:[[:alnum:]]+ [[:alpha:]]+.*:.+");
static const regex re_PGP("-----BEGIN PGP MESSAGE-----");
static const regex re_dump("^ *DUMP: Date of this level");
-static const regex re_accesslog("(GET|POST) .+ HTTP");
-static const regex re_errorlog("^\\[" + unix_date_re + "\\] \\[(error|notice)\\] .+");
static const regex re_rpm("[[:alnum:]+-]+-[0-9][[:alnum:].-]");
-static const regex re_syslog_date("[[:alpha:]]{3} [ 123][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2}");
static const regex re_uxmail_from("^From [^ \t]+[ ]+" + unix_date_re);
static const regex re_mail_From("^From:[[:blank:]]+");
static const regex re_mail_Date("^Date:[[:blank:]]+" + mail_date_re);
static const regex re_mail_MsId("^Message-Id:[[:blank:]]+");
static const regex re_email_address("[[:alnum:]_.-]+@[[:alnum:]_.-]+");
static const regex re_email_user("[[:alnum:]_.-]+@");
-static const regex re_xml_header("\?xml .*\?>$");
+static const regex re_xml_header("xml .*\?>$");
/*=========================================================================
** NAME : readXMLinput
** VARS CHANGED :
** FUNCTIONS USED :
** SEE ALSO :
-** LAST MODIFIED : Apr 28, 2003
+** LAST MODIFIED : Jul 24, 2003
**=========================================================================
*/
xmlParserCtxtPtr ctxt;
String line;
xmlNodePtr root, item;
+ xmlNsPtr namespaces[1];
xmlXPathObjectPtr res;
xmlXPathContextPtr pathcontext;
xmlFreeParserCtxt(ctxt);
root = xmlDocGetRootElement(xmlDom);
+ namespaces[0] = root->ns;
+
//TODO Ought to check root->name and root->ns->href
pathcontext = xmlXPathNewContext(xmlDom);
pathcontext->node = xmlDocGetRootElement(xmlDom);
+ pathcontext->namespaces = namespaces;
+ pathcontext->nsNr = 1;
- res = xmlXPathEval((const xmlChar *)"header/messagetype/text()", pathcontext);
+#ifdef DEBUG
+ xmlDebugDumpNodeList(stdout, pathcontext->node, 0);
+#endif
+
+ res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:messagetype/text()", pathcontext);
if (res->nodesetval != NULL)
{
+#ifdef DEBUG
+ xmlDebugDumpNodeList(stdout, *res->nodesetval->nodeTab, 0);
+#endif
item = *res->nodesetval->nodeTab;
+
+ // Select a line cooker based on the message type.
+
+#ifdef DEBUG
+ std::cout << "Looking for a line cooker for " << item->content << "\n";
+#endif
+ std::list<line_cooker *>::iterator lci = kitchen.begin();
+ pan = 0;
+ while (pan == 0 && lci != kitchen.end())
+ {
+ pan = *lci;
+ if (pan->message_type() != (const char *)(item->content))
+ {
+ pan = 0;
+ }
+ lci++;
+ }
+ if (pan == 0)
+ {
+ *log << "Can not find a line cooker for message type " << item->content << "\n";
+ }
}
- res = xmlXPathEval((const xmlChar *)"header/hostname/text()", pathcontext);
+ else
+ {
+ *log << "Message type not found in XML header.\n";
+ }
+
+ res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:hostname/text()", pathcontext);
if (res->nodesetval != NULL)
{
+#ifdef DEBUG
+ xmlDebugDumpNodeList(stdout, *res->nodesetval->nodeTab, 0);
+#endif
item = *res->nodesetval->nodeTab;
hostname = (const char *)item->content;
}
- res = xmlXPathEval((const xmlChar *)"header/service/text()", pathcontext);
+ else
+ {
+ *log << "Hostname not found in XML header.\n";
+ }
+
+ res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:service/text()", pathcontext);
if (res->nodesetval != NULL)
{
item = *res->nodesetval->nodeTab;
service = (const char *)item->content;
}
- res = xmlXPathEval((const xmlChar *)"header/time/text()", pathcontext);
+ res = xmlXPathEval((const xmlChar *)"gcmt:header/gcmt:time/text()", pathcontext);
if (res->nodesetval != NULL)
{
item = *res->nodesetval->nodeTab;
** VARS CHANGED :
** FUNCTIONS USED :
** SEE ALSO :
-** LAST MODIFIED : Apr 28, 2003
+** LAST MODIFIED : Aug 11, 2003
**=========================================================================
*/
{
from_address = line(re_email_address);
from_address(re_email_user) = ""; // Remove the user part;
- if (from_address != "")
+ if (from_address != "" && ~hostname < ~from_address)
{
+ *log << "Detected hostname " << from_address << "\n";
hostname = from_address;
}
}
{
from_address = line(re_email_address);
from_address(re_email_user) = ""; // Remove the user part;
- if (from_address != "")
+ if (from_address != "" && ~hostname < ~from_address)
{
- hostname = from_address;
+ *log << "Detected hostname " << from_address << "\n";
+ hostname = from_address;
}
}
if (line == re_mail_Date)
}
+ pan = 0;
+
/*
* Now that we have the mail header out of the way, try to figure
* out what the content of the message is.
{
if (verbose)
{
- std::cout << " testing: " << line << "\n";
+ *log << " testing: " << line << "\n";
}
if (line == re_xml_header)
classification = XML;
if (verbose)
{
- std::cout << "XML input detected.\n";
+ *log << "XML input detected.\n";
}
readXMLinput(line);
}
- else if (line == re_syslog)
- {
- certainty = 1.0;
- classification = SYSLOG;
- if (verbose)
- {
- std::cout << "Syslog detected.\n";
- }
- }
- else if (line == re_syslog_irix)
- {
- certainty = 1.0;
- classification = SYSLOG_IRIX;
- if (verbose)
- {
- std::cout << "IRIX Syslog detected.\n";
- }
- }
else if (line == re_PGP)
{
certainty = 1.0;
gpg_encrypted = true;
- std::cerr << "The message is PGP/GnuPG encrypted.\n";
+ *log << "The message is PGP/GnuPG encrypted.\n";
}
else if (line == re_dump)
{
certainty = 1.0;
if (verbose)
{
- std::cout << "DUMP output detected.\n";
- }
- }
- else if (line == re_accesslog)
- {
- certainty = 1.0;
- classification = ACCESSLOG;
- service = "httpd";
- if (verbose)
- {
- std::cout << "HTTP access log detected.\n";
- }
- }
- else if (line == re_errorlog)
- {
- certainty = 1.0;
- classification = ERRORLOG;
- service = "httpd";
- if (verbose)
- {
- std::cout << "HTTP error log detected.\n";
+ *log << "DUMP output detected.\n";
}
}
else if (line == re_rpm)
service = "";
if (verbose)
{
- std::cout << "RPM package list detected.\n";
+ *log << "RPM package list detected.\n";
}
}
+ else
+ {
+ // Scan the list of line cookers if there is anything familiar.
+
+ std::list<line_cooker *>::iterator lci = kitchen.begin();
+ pan = 0;
+ while (pan == 0 && lci != kitchen.end())
+ {
+ pan = *lci;
+ if (!pan->check_pattern(line))
+ {
+ pan = 0;
+ }
+ lci++;
+ }
+ if (pan != 0)
+ {
+ certainty = 1.0;
+ classification = COOKER_OBJECT;
+ if (verbose)
+ {
+ *log << "Detected message type " << pan->message_type() << "\n";
+ }
+ }
+ }
}
input.rewind();
if (hostname == "")
{
- std::cerr << "Can not determine the hostname where the message came from.\n";
+ *log << "Can not determine the hostname where the message came from.\n";
certainty = 0.0;
}
else if (!arrival.proper())
{
- std::cerr << "Arrival time is not knwon.\n";
+ *log << "Arrival time is not known.\n";
certainty = 0.0;
}
else
** VARS CHANGED :
** FUNCTIONS USED :
** SEE ALSO :
-** LAST MODIFIED : Apr 29, 2003
+** LAST MODIFIED : Jul 24, 2003
**=========================================================================
*/
{
xmlXPathObjectPtr res;
xmlXPathContextPtr pathcontext;
+ xmlNsPtr namespaces[1];
/* Try to find the host in the database */
objectid = database.find_host(hostname);
if (objectid == "")
{
- std::cerr << "Please define the host " << hostname << " in the database.\n";
+ *log << "Please define the host " << hostname << " in the database.\n";
return;
}
if (verbose)
{
- std::cout << "Object id for " << hostname << " is " << objectid << "\n";
+ *log << "Object id for " << hostname << " is " << objectid << "\n";
}
pathcontext = xmlXPathNewContext(xmlDom);
pathcontext->node = xmlDocGetRootElement(xmlDom);
- res = xmlXPathEval((const xmlChar *)"data/node()", pathcontext);
+ namespaces[0] = pathcontext->node->ns;
+ pathcontext->namespaces = namespaces;
+ pathcontext->nsNr = 1;
+
+ res = xmlXPathEval((const xmlChar *)"gcmt:data/node()", pathcontext);
if (res->nodesetval != NULL)
{
{
if (node->type == XML_ELEMENT_NODE)
{
+ xmlNodePtr item;
+ String log_hostname;
+ UTC log_date;
+ String raw("");;
+ String log_service;
+
if (strcmp((char *)node->name, "raw") == 0)
{
- std::cerr << "Can not cook <raw> log elements yet.\n";
+ item = node->children;
+ if (pan == 0)
+ {
+ *log << "Can not cook this type of <raw> log element.\n";
+ }
+ else
+ {
+ raw = String((const char *)item->content);
+ if (pan->cook_this(raw, arrival))
+ {
+ log_hostname = pan->hostname();
+ if (log_hostname == "")
+ {
+ log_hostname = hostname;
+ }
+ log_service = pan->service();
+ log_date = pan->timestamp();
+ }
+ else
+ {
+ *log << "Log line " << raw << " does not match.\n";
+ raw = "";
+ }
+ }
}
else if (strcmp((char *)node->name, "cooked") == 0)
{
// Find the parts of the log entry
- xmlNodePtr item;
- String log_hostname;
- UTC log_date;
- String raw("");;
- String log_service;
-
if (verbose)
{
- std::cout << "Analyzing cooked element.\n";
+ *log << "Analyzing cooked element.\n";
}
pathcontext->node = node;
log_hostname = (const char *)item->content;
if (log_hostname != hostname(0, ~log_hostname))
{
- std::cerr << "Hostname " << log_hostname << " does not match.\n";
+ *log << "Hostname " << log_hostname << " does not match.\n";
log_hostname = "";
}
}
}
else
{
- std::cerr << "<timestamp> missing from cooked log element.\n";
+ *log << "<timestamp> missing from cooked log element.\n";
}
res = xmlXPathEval((const xmlChar *)"raw/text()", pathcontext);
}
else
{
- std::cerr << "<raw> missing from cooked log element.\n";
+ *log << "<raw> missing from cooked log element.\n";
}
- if (raw != "" && log_hostname != "" && log_date.proper())
- {
- String insertion("insert into log (objectid, servicecode,"
- " object_timestamp, timestamp, rawdata, processed) values (");
+ }
- /* Insert a new record into the log table */
+ // Insert a new log record into the database.
+ if (raw != "" && log_hostname != "" && log_date.proper())
+ {
+ String insertion("insert into log (objectid, servicecode,"
+ " object_timestamp, timestamp, rawdata, processed) values (");
- insertion += "'" + objectid + "',";
- insertion += "'" + log_service + "',";
- insertion += "'" + log_date.format("%Y-%m-%d %T") + "',";
- insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
- insertion += "'" + SQL_Escape(raw) + "',FALSE";
- insertion += ")";
+ /* Insert a new record into the log table */
- if (testmode)
- {
- std::cout << insertion << "\n";
- }
- else
- {
- database.Query(insertion);
- }
+ insertion += "'" + objectid + "',";
+ insertion += "'" + log_service + "',";
+ insertion += "'" + log_date.format("%Y-%m-%d %T") + "',";
+ insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
+ insertion += "'" + SQL_Escape(raw) + "',FALSE";
+ insertion += ")";
- if (verbose)
- {
- std::cout << "\n\n";
- }
+ if (testmode)
+ {
+ *log << insertion << "\n";
+ }
+ else
+ {
+ database.Query(insertion);
+ }
+
+ if (verbose)
+ {
+ *log << "\n\n";
}
}
+
}
node = node->next;
}
}
else
{
- std::cerr << "Data element " << node->name << " is not supported.\n";
+ *log << "Data element " << node->name << " is not supported.\n";
}
}
else
{
- std::cerr << "Data node not found.\n";
+ *log << "Data node not found.\n";
}
}
** VARS CHANGED :
** FUNCTIONS USED :
** SEE ALSO :
-** LAST MODIFIED : Mar 28, 2003
+** LAST MODIFIED : Jul 24, 2003
**=========================================================================
*/
objectid = database.find_host(hostname);
if (objectid == "")
{
- std::cerr << "Please define the host " << hostname << " in the database.\n";
+ *log << "Please define the host " << hostname << " in the database.\n";
return 0;
}
if (verbose)
{
- std::cout << "Object id for " << hostname << " is " << objectid << "\n";
+ *log << "Object id for " << hostname << " is " << objectid << "\n";
}
if (classification == RPMLIST)
n_packages = database.Query(qry);
initial_entry = n_packages == 0;
- std::cout << n_packages << " packages in database.\n";
+#ifdef DEBUG
+ *log << n_packages << " packages in database.\n";
+#endif
for (int t = 0; t < n_packages; t++)
{
packages.push_back(database.Field(t, "name"));
}
- std::cout << "Package list built: " << packages.size() << ".\n";
+#ifdef DEBUG
+ *log << "Package list built: " << packages.size() << ".\n";
+#endif
}
/* Scan the input line by line, entring records into the database */
String rest; // Rest of the line to be parsed
+ regex re_any(".*");
while (input >> line)
{
if (verbose)
{
- std::cout << line << "\n";
+ *log << line << "\n";
}
switch (classification)
{
- case SYSLOG:
- check = &re_syslog;
- break;
- case SYSLOG_IRIX:
- check = &re_syslog_irix;
- break;
- case ACCESSLOG:
- check = &re_accesslog;
- break;
- case ERRORLOG:
- check = &re_errorlog;
- break;
case RPMLIST:
check = &re_rpm;
break;
+ case COOKER_OBJECT:
+ check = &re_any;
+ break;
}
if (line == *check)
switch (classification)
{
- case SYSLOG:
- log_date = line;
- log_time = line;
- if (log_date.Year() < 0 || log_date.Year() > 2500)
- {
- // The year is not in the log file. Assume the year of arrival,
- // unless this puts the log entry at a later date than the arrival date.
- // This happens e.g. when a log entry from December arrives in Januari.
-
- log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year());
- if (log_date > date(arrival))
- {
- log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year() - 1);
- }
- }
-
- if (verbose)
- {
- std::cout << " Log timestamp = " << log_date << " " << log_time << "\n";
- }
- rest = line << 16;
- i = rest.index(' ');
- if (rest(0,i) == hostname(0,i))
- {
- rest <<= i + 1;
- if (verbose)
- {
- std::cout << " Hostname matches.\n";
- std::cout << " rest = " << rest << "\n";
- }
- for (i = 0; isalpha(rest[i]) && i < ~rest; i++);
- if (verbose)
- {
- std::cout << " Service name = " << rest(0,i) << "\n";
- }
-
- /* Insert a new record into the log table */
-
- insertion += "'" + objectid + "',";
- insertion += "'" + rest(0,i) + "',";
- insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',";
- insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
- insertion += "'" + SQL_Escape(line) + "',FALSE";
- insertion += ")";
-
- if (testmode)
- {
- std::cout << insertion << "\n";
- }
- else
- {
- database.Query(insertion);
- }
-
- if (verbose)
- {
- std::cout << "\n\n";
- }
-
- nr_lines++;
- }
- else
- {
- std::cerr << " Hostname " << rest(0,i) << " does not match.\n";
- }
- break;
-
- case SYSLOG_IRIX:
- log_date = line;
- log_time = line;
- if (log_date.Year() < 0 || log_date.Year() > 2500)
- {
- // The year is not in the log file. Assume the year of arrival,
- // unless this puts the log entry at a later date than the arrival date.
- // This happens e.g. when a log entry from December arrives in Januari.
-
- log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year());
- if (log_date > date(arrival))
- {
- log_date = date(log_date.Day(), log_date.Month(), date(arrival).Year() - 1);
- }
- }
-
- if (verbose)
- {
- std::cout << " Log timestamp = " << log_date << " " << log_time << "\n";
- }
- rest = line << 19;
- i = rest.index(' ');
- if (rest(0,i) == hostname(0,i))
+ case COOKER_OBJECT:
+#ifdef DEBUG
+ std::cerr << "\ncooker check: " << pan->check_pattern(line) << "\n";
+#endif
+ if (pan->cook_this(line, arrival))
{
- rest <<= i + 1;
- if (verbose)
+ if (pan->hostname() == hostname(0,~pan->hostname()))
{
- std::cout << " Hostname matches.\n";
- std::cout << " rest = " << rest << "\n";
- }
- for (i = 0; isalpha(rest[i]) && i < ~rest; i++);
- if (verbose)
- {
- std::cout << " Service name = " << rest(0,i) << "\n";
- }
- /* Insert a new record into the log table */
+#ifdef DEBUG
+ std::cerr << " Information from cooker:\n";
+ std::cerr << " timestamp = " << pan->timestamp() << "\n";
+ std::cerr << " hostname = " << pan->hostname() << "\n";
+ std::cerr << " service = " << pan->service() << "\n";
+#endif
+ /* Insert a new record into the log table */
+
+ insertion += "'" + objectid + "',";
+ insertion += "'" + pan->service() + "',";
+ insertion += "'" + pan->timestamp().format("%Y-%m-%d %T") + "',";
+ insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
+ insertion += "'" + SQL_Escape(line) + "',FALSE";
+ insertion += ")";
+
+ if (testmode)
+ {
+ *log << insertion << "\n";
+ }
+ else
+ {
+ database.Query(insertion);
+ }
- insertion += "'" + objectid + "',";
- insertion += "'" + rest(0,i) + "',";
- insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',";
- insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
- insertion += "'" + SQL_Escape(line) + "',FALSE";
- insertion += ")";
+ if (verbose)
+ {
+ *log << "\n\n";
+ }
- if (testmode)
- {
- std::cout << insertion << "\n";
+ nr_lines++;
}
else
{
- database.Query(insertion);
- }
-
- if (verbose)
- {
- std::cout << "\n\n";
+ *log << " Hostname " << pan->hostname() << " does not match.\n";
}
-
- nr_lines++;
- }
- else
- {
- std::cerr << " Hostname " << rest(0,i) << " does not match.\n";
- }
- break;
-
- case ACCESSLOG:
- datestring = line(regex("\\[.+\\]"));
- datestring <<= 1;
- datestring >>= 1;
- datestring[datestring.index(':')] = ' ';
- log_date = datestring;
- log_time = datestring;
- if (verbose)
- {
- std::cout << " Log timestamp = " << log_date << " " << log_time << "\n";
- }
- insertion += "'" + objectid + "',";
- insertion += "'" + service + "',";
- insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',";
- insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
- insertion += "'" + SQL_Escape(line) + "',FALSE";
- insertion += ")";
-
- if (testmode)
- {
- std::cout << insertion << "\n";
}
else
{
- database.Query(insertion);
+ *log << "gcm_input WARNING: Not a valid line: " << line << "\n";
}
-
- if (verbose)
- {
- std::cout << "\n\n";
- }
-
- nr_lines++;
break;
- case ERRORLOG:
- datestring = line(regex("\\[.+\\]"));
- datestring <<= 1;
- datestring >>= 1;
- log_date = datestring;
- log_time = datestring;
- if (verbose)
- {
- std::cout << " Log timestamp = " << log_date << " " << log_time << "\n";
- }
- insertion += "'" + objectid + "',";
- insertion += "'" + service + "',";
- insertion += "'" + log_date.format("%Y-%m-%d") + " " + log_time.format() + "',";
- insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
- insertion += "'" + SQL_Escape(line) + "',FALSE";
- insertion += ")";
-
- if (testmode)
- {
- std::cout << insertion << "\n";
- }
- else
- {
- database.Query(insertion);
- }
-
- if (verbose)
- {
- std::cout << "\n\n";
- }
-
- nr_lines++;
- break;
case RPMLIST:
// Scan a list of packages and versions from "rpm -a".
if (verbose)
{
- std::cout << "Package is " << package;
- std::cout << ", version is " << version << "\n";
+ *log << "Package is " << package;
+ *log << ", version is " << version << "\n";
}
// Construct a qry to check the package's existance
}
else
{
- std::cerr << "Could NOT find " << package << " in list.\n";
+ *log << "Could NOT find " << package << " in list.\n";
}
paramid = database.Field(0, "paramid");
qry += paramid + "' and name='version'";
if (database.Query(qry) == 0)
{
- std::cerr << "Database corruption: Package " << package;
- std::cerr << " does not have a 'version' property.\n";
+ *log << "Database corruption: Package " << package;
+ *log << " does not have a 'version' property.\n";
}
else if (database.Field(0, "value") != version)
{
if (verbose)
{
- std::cout << " Parameter " << package << " has different version\n";
+ *log << " Parameter " << package << " has different version\n";
}
insertion = "update property set value='";
insertion += version + "' where paramid='";
{
remark = "Gnucomo detected a different version for package parameter(s) ";
change_notification = database.new_notification(objectid, "property modified", remark);
+ change_notification = database.new_notification(objectid, "property modified", remark);
}
if (change_notification != "")
{
- insertion = "insert into parameter_notification (notificationid, paramid) values ('";
- insertion += change_notification + "', '";
- insertion += paramid + "')";
+ qry = "select * from parameter_notification where notificationid='";
+ qry += change_notification + "' and paramid='";
+ qry += paramid + "'";
- database.Query(insertion);
+ if (database.Query(qry) == 0)
+ {
+ insertion = "insert into parameter_notification (notificationid, paramid) values ('";
+ insertion += change_notification + "', '";
+ insertion += paramid + "')";
+
+ database.Query(insertion);
+ }
}
else
{
- std::cerr << "gcm_input ERROR: Cannot create 'property modified' notification.\n";
+ *log << "gcm_input ERROR: Cannot create 'property modified' notification.\n";
}
}
else
{
if (verbose)
{
- std::cout << " Parameter " << package << " has not changed.\n";
+ *log << " Parameter " << package << " has not changed.\n";
}
}
}
if (verbose)
{
- std::cout << " Parameter " << package << " does not exist.\n";
+ *log << " Parameter " << package << " does not exist.\n";
}
// Create a new package parameter, including version property and history record
if (testmode)
{
paramid = "0";
- std::cout << insertion << "\n";
+ *log << insertion << "\n";
}
else
{
if (testmode)
{
- std::cout << insertion << "\n" << insert_h << "\n";
+ *log << insertion << "\n" << insert_h << "\n";
}
else
{
}
else
{
- std::cerr << "gcm_input ERROR: Cannot create 'parameter created' notification.\n";
+ *log << "gcm_input ERROR: Cannot create 'parameter created' notification.\n";
}
}
}
if (verbose)
{
- std::cout << "\n";
+ *log << "\n";
}
nr_lines++;
}
else
{
- std::cerr << "gcm_input WARNING: Not a valid line: " << line << "\n";
+ *log << "gcm_input WARNING: Not a valid line: " << line << "\n";
}
}
- if (classification == RPMLIST)
+ if (classification == RPMLIST && !incremental)
{
std::list<String>::iterator lp;
String remove_notification("");
qry += paramid + "' order by modified desc";
if (database.Query(qry) <= 0)
{
- std::cerr << "Database ERROR: no history record for parameter " << *lp << ".\n";
+ *log << "Database ERROR: no history record for parameter " << *lp << ".\n";
}
else if (database.Field(0, "change_nature") != "REMOVED")
{
if (verbose)
{
- std::cout << "Removing parameter " << *lp << ".\n";
+ *log << "Removing parameter " << *lp << ".\n";
}
insert = "insert into history (paramid, modified, change_nature)";
}
else
{
- std::cerr << "gcm_input ERROR: Cannot create 'parameter removed' notification.\n";
+ *log << "gcm_input ERROR: Cannot create 'parameter removed' notification.\n";
}
}
}
if (verbose)
{
- std::cout << nr_lines << " lines parsed from the log file.\n";
+ *log << nr_lines << " lines parsed from the log file.\n";
}
return nr_lines;
}
-
-/*=========================================================================
-** NAME : SQL_Escape
-** SYNOPSIS : String SQL_Escape(String)
-** PARAMETERS :
-** RETURN VALUE :
-**
-** DESCRIPTION : Insert backslashes before single quotes.
-**
-** VARS USED :
-** VARS CHANGED :
-** FUNCTIONS USED :
-** SEE ALSO :
-** LAST MODIFIED :
-**=========================================================================
-*/
-
-String SQL_Escape(String s)
-{
- int i;
-
- for (i = 0; i < ~s; i++)
- {
- if (s[i] == '\'')
- {
- s(i,0) = "\\";
- i++;
- }
- }
-
- return s;
-}