Gcm_input also detects packages that are removed from the system.
authorarjen <arjen>
Fri, 21 Feb 2003 08:08:05 +0000 (08:08 +0000)
committerarjen <arjen>
Fri, 21 Feb 2003 08:08:05 +0000 (08:08 +0000)
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.

src/gcm_input/message.cpp

index 4d5b962..96214b5 100644 (file)
@@ -8,7 +8,7 @@
 ***********************
 **      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.
 
@@ -48,8 +54,9 @@
 
 *****************************/
 
-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 */
@@ -88,7 +95,7 @@ bool operator >> (message_buffer &b, String &s)
          b.buffer.push_back(l);
 
          //   next_line keeps pointing to the end.
+
          s = l;
          input_ok = true;
       }
@@ -281,7 +288,7 @@ double client_message::classify(String host, UTC arriv, String serv)
 **  VARS CHANGED   :
 **  FUNCTIONS USED :
 **  SEE ALSO       :
-**  LAST MODIFIED  : Jan 31, 2003
+**  LAST MODIFIED  : Feb 19, 2003
 **=========================================================================
 */
 
@@ -289,9 +296,13 @@ int client_message::enter()
 {
    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 */
@@ -304,7 +315,7 @@ int client_message::enter()
    if (mail_header)
    {
       //  Skip the mail header.
+
       while (input >> line && line != "");
    }
 
@@ -323,6 +334,27 @@ int client_message::enter()
       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
@@ -411,7 +443,7 @@ int client_message::enter()
                insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
                insertion += "'" + SQL_Escape(line) + "',FALSE";
                insertion += ")";
-            
+
                if (testmode)
                {
                   std::cout << insertion << "\n";
@@ -451,7 +483,7 @@ int client_message::enter()
             insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
             insertion += "'" + SQL_Escape(line) + "',FALSE";
             insertion += ")";
-            
+
             if (testmode)
             {
                std::cout << insertion << "\n";
@@ -485,7 +517,7 @@ int client_message::enter()
             insertion += "'" + arrival.format("%Y-%m-%d %T") + "',";
             insertion += "'" + SQL_Escape(line) + "',FALSE";
             insertion += ")";
-            
+
             if (testmode)
             {
                std::cout << insertion << "\n";
@@ -505,28 +537,39 @@ int client_message::enter()
 
          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;
@@ -545,6 +588,18 @@ int client_message::enter()
 
             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'";
@@ -577,11 +632,18 @@ int client_message::enter()
                      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
                {
@@ -640,11 +702,18 @@ int client_message::enter()
                         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";
+                     }
                   }
                }
             }
@@ -665,6 +734,73 @@ int client_message::enter()
       }
    }
 
+   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";