***********************
** FILE NAME : message.cpp
** SYSTEM NAME : Gnucomo - Gnu Computer Monitoring
-** VERSION NUMBER : $Revision: 1.6 $
+** VERSION NUMBER : $Revision: 1.7 $
**
** DESCRIPTION : Implementation of the message handling classes
**
********************************
** ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
** CREATION DATE : Sep 16, 2002
-** LAST UPDATE : Jan 31, 2003
+** LAST UPDATE : Feb 19, 2003
** MODIFICATIONS :
**************************************************************************/
/*****************************
$Log: message.cpp,v $
- Revision 1.6 2003-02-05 09:37:51 arjen
+ Revision 1.7 2003-02-21 08:08:05 arjen
+ Gcm_input also detects packages that are removed from the system.
+ Determining the version number of a package in a RPM
+ list is improved. Only the last one or two parts of the string that
+ begin with a '-' and a number are considered the version.
+
+ Revision 1.6 2003/02/05 09:37:51 arjen
Create notifications when a new package is discovered
in a 'rpm -qa' list or when the version of a package is changed.
*****************************/
-static const char *RCSID = "$Id: message.cpp,v 1.6 2003-02-05 09:37:51 arjen Exp $";
+static const char *RCSID = "$Id: message.cpp,v 1.7 2003-02-21 08:08:05 arjen Exp $";
+#include <algorithm>
#include "message.h"
extern bool verbose; /* Defined in the main application */
b.buffer.push_back(l);
// next_line keeps pointing to the end.
-
+
s = l;
input_ok = true;
}
** VARS CHANGED :
** FUNCTIONS USED :
** SEE ALSO :
-** LAST MODIFIED : Jan 31, 2003
+** LAST MODIFIED : Feb 19, 2003
**=========================================================================
*/
{
long nr_lines = 0;
String line;
+ String qry;
String change_notification("");
String create_notification("");
+ bool initial_entry = false;
+
+ std::list<String> packages;
/* Double-check the classification of the message */
if (mail_header)
{
// Skip the mail header.
-
+
while (input >> line && line != "");
}
std::cout << "Object id for " << hostname << " is " << objectid << "\n";
}
+ if (classification == RPMLIST)
+ {
+
+ int n_packages;
+
+ /* Read all packages, so we will know which ones are */
+ /* missing at the end. */
+
+ qry = "select name from parameter where objectid='";
+ qry += objectid + "' and class='package'";
+ n_packages = database.Query(qry);
+ initial_entry = n_packages == 0;
+
+ std::cout << n_packages << " packages in database.\n";
+ for (int t = 0; t < n_packages; t++)
+ {
+ packages.push_back(database.Field(t, "name"));
+ }
+ std::cout << "Package list built: " << packages.size() << ".\n";
+ }
+
/* Scan the input line by line, entring records into the database */
String rest; // Rest of the line to be parsed
insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
insertion += "'" + SQL_Escape(line) + "',FALSE";
insertion += ")";
-
+
if (testmode)
{
std::cout << insertion << "\n";
insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
insertion += "'" + SQL_Escape(line) + "',FALSE";
insertion += ")";
-
+
if (testmode)
{
std::cout << insertion << "\n";
insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
insertion += "'" + SQL_Escape(line) + "',FALSE";
insertion += ")";
-
+
if (testmode)
{
std::cout << insertion << "\n";
case RPMLIST:
// Scan a list of packages and versions from "rpm -a".
- // A similar listing can be created on IRIX 6.5 by using the
- // command "showprods -3 -n|awk '{printf "%s-%s\n",$2,$3}'|grep -v '^[-=]' \
- // |grep -v Version-Description".
- //
+ // A similar listing can be created on IRIX 6.5 by using the
+ // command "showprods -3 -n|awk '{printf "%s-%s\n",$2,$3}'|grep -v '^[-=]' \
+ // |grep -v Version-Description".
+ //
// We have to separate the package name and the version.
// The separation is marked by a '-', followed by a digit.
-
- String qry = "select count(paramid) from parameter where objectid='";
- qry += objectid + "' and class='package'";
-
- database.Query(qry);
- long n_packages = String(database.Field(0, "count"));
+ // However, there may be other sequences of '-'digit in the package name,
+ // do we have to scan ahead until there is at most one such sequence
+ // left in the version string. The '-'digit seqeunce inside the
+ // version usually separates the version and the release number.
- bool initial_entry = n_packages == 0;
+ int version_start, next_version_start;
i = line.index('-');
- while (!(line[i] == '-' && isdigit(line[i + 1])))
+ version_start = i;
+ next_version_start = i;
+
+ while (i < ~line - 1)
{
+ while (i < ~line - 1 && !(line[i] == '-' && isdigit(line[i + 1])))
+ {
+ i++;
+ }
+ if (i < ~line - 1)
+ {
+ version_start = next_version_start;
+ next_version_start = i;
+ }
i++;
}
- String package(line(0,i));
- String version(line(i+1, ~line));
+
+ String package(line(0,version_start));
+ String version(line(version_start + 1, ~line));
String paramid;
String remark;
String insert_h;
if (database.Query(qry) == 1)
{
+ std::list<String>::iterator lp;
+
+ lp = find(packages.begin(), packages.end(), package);
+ if (lp != packages.end())
+ {
+ packages.erase(lp);
+ }
+ else
+ {
+ std::cerr << "Could NOT find " << package << " in list.\n";
+ }
+
paramid = database.Field(0, "paramid");
qry = "select value from property where paramid='";
qry += paramid + "' and name='version'";
change_notification = database.new_notification(objectid, "property modified", remark);
}
- insertion = "insert into parameter_notification (notificationid, paramid) values ('";
- insertion += change_notification + "', '";
- insertion += paramid + "')";
+ if (change_notification != "")
+ {
+ insertion = "insert into parameter_notification (notificationid, paramid) values ('";
+ insertion += change_notification + "', '";
+ insertion += paramid + "')";
- database.Query(insertion);
+ database.Query(insertion);
+ }
+ else
+ {
+ std::cerr << "gcm_input ERROR: Cannot create 'property modified' notification.\n";
+ }
}
else
{
remark = "Gnucomo detected new parameter(s) of class package";
create_notification = database.new_notification(objectid, "parameter created", remark);
}
- insertion = "insert into parameter_notification (notificationid, paramid) values ('";
- insertion += create_notification + "', '";
- insertion += paramid + "')";
+ if (create_notification != "")
+ {
+ insertion = "insert into parameter_notification (notificationid, paramid) values ('";
+ insertion += create_notification + "', '";
+ insertion += paramid + "')";
- database.Query(insertion);
+ database.Query(insertion);
+ }
+ else
+ {
+ std::cerr << "gcm_input ERROR: Cannot create 'parameter created' notification.\n";
+ }
}
}
}
}
}
+ if (classification == RPMLIST)
+ {
+ std::list<String>::iterator lp;
+ String remove_notification("");
+
+ /*
+ * If there are any packages left in the list, they seem to have
+ * disappeared from the system.
+ */
+
+ for (lp = packages.begin(); lp != packages.end(); lp++)
+ {
+ String paramid;
+ String remark;
+ String insert;
+
+ // Construct a qry to check the package's existance
+
+ qry = "select paramid from parameter where objectid='";
+ qry += objectid + "' and class='package' and name='";
+ qry += *lp + "'";
+
+ if (database.Query(qry) == 1)
+ {
+ paramid = database.Field(0, "paramid");
+ qry ="select change_nature from history where paramid='";
+ qry += paramid + "' order by modified desc";
+ if (database.Query(qry) <= 0)
+ {
+ std::cerr << "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";
+ }
+
+ insert = "insert into history (paramid, modified, change_nature)";
+ insert += " values ('";
+ insert += paramid + "', '" + arrival.format("%Y-%m-%d %T") + "', 'REMOVED')";
+
+ database.Query(insert);
+
+ if (remove_notification == "")
+ {
+ remark = "Gnucomo detected that package(s) have disappeared ";
+ remove_notification = database.new_notification(objectid, "parameter removed", remark);
+ }
+
+ if (remove_notification != "")
+ {
+ insert = "insert into parameter_notification (notificationid, paramid) values ('";
+ insert += remove_notification + "', '";
+ insert += paramid + "')";
+
+ database.Query(insert);
+ }
+ else
+ {
+ std::cerr << "gcm_input ERROR: Cannot create 'parameter removed' notification.\n";
+ }
+ }
+ }
+ }
+ }
+
if (verbose)
{
std::cout << nr_lines << " lines parsed from the log file.\n";