From 16661cfb6df2a6c91211a96d226cb985e6f18d9e Mon Sep 17 00:00:00 2001
From: Fred Gleason <fredg@paraelsystems.com>
Date: Mon, 13 Aug 2018 16:27:12 -0400
Subject: [PATCH] 2018-08-13 Fred Gleason <fredg@paravelsystems.com> 	*
 Moved execution of maintenance routines from ripcd(8) to 	rdservice(8).

---
 ChangeLog                    |   3 +
 rdservice/Makefile.am        |   3 +-
 rdservice/maint_routines.cpp | 120 +++++++++++++++++++++++++++++++++++
 rdservice/rdservice.cpp      |  17 +++++
 rdservice/rdservice.h        |  12 +++-
 ripcd/Makefile.am            |   2 +-
 ripcd/maint_routines.cpp     |  54 ----------------
 ripcd/ripcd.cpp              |  57 -----------------
 ripcd/ripcd.h                |   5 --
 9 files changed, 154 insertions(+), 119 deletions(-)
 create mode 100644 rdservice/maint_routines.cpp
 delete mode 100644 ripcd/maint_routines.cpp

diff --git a/ChangeLog b/ChangeLog
index ed5cc6f4..eb30980a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17372,3 +17372,6 @@
 	* Removed sysconfig support.
 2018-08-11 Fred Gleason <fredg@paravelsystems.com>
 	* Added a debug block for saving raw post data to 'RDFormPost'.
+2018-08-13 Fred Gleason <fredg@paravelsystems.com>
+	* Moved execution of maintenance routines from ripcd(8) to
+	rdservice(8).
diff --git a/rdservice/Makefile.am b/rdservice/Makefile.am
index e106b512..26cd7fbb 100644
--- a/rdservice/Makefile.am
+++ b/rdservice/Makefile.am
@@ -31,7 +31,8 @@ moc_%.cpp:	%.h
 
 sbin_PROGRAMS = rdservice
 
-dist_rdservice_SOURCES = process.cpp process.h\
+dist_rdservice_SOURCES = maint_routines.cpp\
+                         process.cpp process.h\
                          rdservice.cpp rdservice.h\
                          shutdown.cpp\
                          startup.cpp
diff --git a/rdservice/maint_routines.cpp b/rdservice/maint_routines.cpp
new file mode 100644
index 00000000..ccdd275f
--- /dev/null
+++ b/rdservice/maint_routines.cpp
@@ -0,0 +1,120 @@
+// main_routines.cpp
+//
+// Rivendell Maintenance Routines
+//
+//   (C) Copyright 2008-2018 Fred Gleason <fredg@paravelsystems.com>
+//
+//   This program is free software; you can redistribute it and/or modify
+//   it under the terms of the GNU General Public License version 2 as
+//   published by the Free Software Foundation.
+//
+//   This program is distributed in the hope that it will be useful,
+//   but WITHOUT ANY WARRANTY; without even the implied warranty of
+//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//   GNU General Public License for more details.
+//
+//   You should have received a copy of the GNU General Public
+//   License along with this program; if not, write to the Free Software
+//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include <stdlib.h>
+
+#include <rd.h>
+#include <rdapplication.h>
+#include <rdpaths.h>
+
+#include "rdservice.h"
+
+void MainObject::checkMaintData()
+{
+  QString sql;
+  RDSqlQuery *q;
+  QDateTime current_datetime=
+    QDateTime(QDate::currentDate(),QTime::currentTime());
+  bool run=false;
+
+  RunLocalMaintRoutine();
+
+  //
+  // Should we try to run system maintenance?
+  //
+  if(!rda->station()->systemMaint()) {
+    return;
+  }
+
+  //
+  // Get the system-wide maintenance timestamp
+  //
+  sql="lock tables VERSION write";
+  q=new RDSqlQuery(sql);
+  delete q;
+  sql="select LAST_MAINT_DATETIME from VERSION";
+  q=new RDSqlQuery(sql);
+  if(q->first()) {
+    run=1000*q->value(0).toDateTime().secsTo(current_datetime)>
+      RD_MAINT_MAX_INTERVAL;
+  }
+  delete q;
+  sql="unlock tables";
+  q=new RDSqlQuery(sql);
+  delete q;
+
+  //
+  // Run the routines
+  //
+  if(run) {
+    RunSystemMaintRoutine();
+  }
+}
+
+
+void MainObject::RunSystemMaintRoutine()
+{
+  QStringList args;
+
+  args.clear();
+  args.push_back("--system");
+  RunEphemeralProcess(RDSERVICE_SYSTEMMAINT_ID,
+		      QString(RD_PREFIX)+"/bin/rdmaint",args);
+
+  args.clear();
+  RunEphemeralProcess(RDSERVICE_PURGECASTS_ID,
+		      QString(RD_PREFIX)+"/bin/rdpurgecasts",args);
+
+  rda->log(RDConfig::LogInfo,"ran system-wide maintenance routines");
+}
+
+
+void MainObject::RunLocalMaintRoutine()
+{
+  RunEphemeralProcess(RDSERVICE_SYSTEMMAINT_ID,
+		      QString(RD_PREFIX)+"/bin/rdmaint",QStringList());
+
+  rda->log(RDConfig::LogInfo,"ran local maintenance routines");
+}
+
+
+int MainObject::GetMaintInterval() const
+{
+  return (int)(RD_MAINT_MIN_INTERVAL+
+	       (RD_MAINT_MAX_INTERVAL-RD_MAINT_MIN_INTERVAL)*
+	       (double)random()/(double)RAND_MAX);
+}
+
+
+void MainObject::RunEphemeralProcess(int id,const QString &program,
+				     const QStringList &args)
+{
+  svc_processes[id]=new Process(id,this);
+  connect(svc_processes[id],SIGNAL(finished(int)),
+	  this,SLOT(processFinishedData(int)));
+  svc_processes[id]->start(program,args);
+  if(!svc_processes[id]->process()->waitForStarted()) {
+    QString err_msg=tr("unable to start")+"\""+program+"\": "+
+      svc_processes[id]->errorText();
+    rda->log(RDConfig::LogWarning,err_msg);
+    delete svc_processes[id];
+    svc_processes.remove(id);
+  }
+}
diff --git a/rdservice/rdservice.cpp b/rdservice/rdservice.cpp
index 8b939bf5..378d2ad6 100644
--- a/rdservice/rdservice.cpp
+++ b/rdservice/rdservice.cpp
@@ -89,6 +89,21 @@ MainObject::MainObject(QObject *parent)
     exit(1);
   }
 
+  //
+  // Maintenance Routine Timer
+  //
+  srandom(QTime::currentTime().msec());
+  svc_maint_timer=new QTimer(this);
+  svc_maint_timer->setSingleShot(true);
+  connect(svc_maint_timer,SIGNAL(timeout()),this,SLOT(checkMaintData()));
+  int interval=GetMaintInterval();
+  if(!rda->config()->disableMaintChecks()) {
+    svc_maint_timer->start(interval);
+  }
+  else {
+    rda->log(RDConfig::LogInfo,"maintenance checks disabled on this host!");
+  }
+
   if(!RDWritePid(RD_PID_DIR,"rdservice.pid",getuid())) {
     fprintf(stderr,"rdservice: can't write pid file\n");
   }
@@ -97,6 +112,8 @@ MainObject::MainObject(QObject *parent)
 
 void MainObject::processFinishedData(int id)
 {
+  svc_processes[id]->deleteLater();
+  svc_processes.remove(id);
 }
 
 
diff --git a/rdservice/rdservice.h b/rdservice/rdservice.h
index 993f14d1..9a524a02 100644
--- a/rdservice/rdservice.h
+++ b/rdservice/rdservice.h
@@ -33,7 +33,10 @@
 #define RDSERVICE_RDCATCHD_ID 2
 #define RDSERVICE_RDVAIRPLAYD_ID 3
 #define RDSERVICE_RDREPLD_ID 4
-#define RDSERVICE_LAST_ID 5
+#define RDSERVICE_LOCALMAINT_ID 5
+#define RDSERVICE_SYSTEMMAINT_ID 6
+#define RDSERVICE_PURGECASTS_ID 7
+#define RDSERVICE_LAST_ID 8
 #define RDSERVICE_FIRST_DROPBOX_ID 100
 
 class MainObject : public QObject
@@ -44,6 +47,7 @@ class MainObject : public QObject
 
  private slots:
   void processFinishedData(int id);
+  void checkMaintData();
   void exitData();
 
  private:
@@ -52,7 +56,13 @@ class MainObject : public QObject
   void KillProgram(const QString &program);
   void Shutdown();
   void ShutdownDropboxes();
+  void RunSystemMaintRoutine();
+  void RunLocalMaintRoutine();
+  int GetMaintInterval() const;
+  void RunEphemeralProcess(int id,const QString &program,
+			   const QStringList &args);
   QMap<int,Process *> svc_processes;
+  QTimer *svc_maint_timer;
   QTimer *svc_exit_timer;
 };
 
diff --git a/ripcd/Makefile.am b/ripcd/Makefile.am
index 1fe3c8c8..bd614fd0 100644
--- a/ripcd/Makefile.am
+++ b/ripcd/Makefile.am
@@ -57,7 +57,7 @@ dist_ripcd_SOURCES = acu1p.cpp acu1p.h\
                      livewire_mcastgpio.cpp livewire_mcastgpio.h\
                      local_audio.cpp local_audio.h\
                      local_gpio.cpp local_gpio.h\
-                     local_macros.cpp maint_routines.cpp\
+                     local_macros.cpp\
                      loaddrivers.cpp\
                      modbus.cpp modbus.h\
                      modemlines.cpp modemlines.h\
diff --git a/ripcd/maint_routines.cpp b/ripcd/maint_routines.cpp
deleted file mode 100644
index 46915e8d..00000000
--- a/ripcd/maint_routines.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-// ripcd.cpp
-//
-// Rivendell Maintenance Routines
-//
-//   (C) Copyright 2008,2016 Fred Gleason <fredg@paravelsystems.com>
-//
-//   This program is free software; you can redistribute it and/or modify
-//   it under the terms of the GNU General Public License version 2 as
-//   published by the Free Software Foundation.
-//
-//   This program is distributed in the hope that it will be useful,
-//   but WITHOUT ANY WARRANTY; without even the implied warranty of
-//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//   GNU General Public License for more details.
-//
-//   You should have received a copy of the GNU General Public
-//   License along with this program; if not, write to the Free Software
-//   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-//
-
-#include <stdlib.h>
-
-#include <rd.h>
-
-#include <ripcd.h>
-
-void MainObject::RunSystemMaintRoutine()
-{
-  if(fork()==0) {
-    system("rdmaint --system");
-    system("rdpurgecasts");
-    exit(0);
-  }
-
-  LogLine(RDConfig::LogInfo,"ran system-wide maintenance routines");
-}
-
-
-void MainObject::RunLocalMaintRoutine()
-{
-  if(fork()==0) {
-    system("rdmaint");
-    exit(0);
-  }
-  LogLine(RDConfig::LogInfo,"ran local maintenance routines");
-}
-
-
-int MainObject::GetMaintInterval() const
-{
-  return (int)(RD_MAINT_MIN_INTERVAL+
-	       (RD_MAINT_MAX_INTERVAL-RD_MAINT_MIN_INTERVAL)*
-	       (double)random()/(double)RAND_MAX);
-}
diff --git a/ripcd/ripcd.cpp b/ripcd/ripcd.cpp
index ddc8b89c..5122cccd 100644
--- a/ripcd/ripcd.cpp
+++ b/ripcd/ripcd.cpp
@@ -180,20 +180,6 @@ MainObject::MainObject(QObject *parent)
   connect(ripcd_backup_timer,SIGNAL(timeout()),this,SLOT(databaseBackup()));
   ripcd_backup_timer->start(86400000);
 
-  //
-  // Maintenance Routine Timer
-  //
-  srandom(QTime::currentTime().msec());
-  ripcd_maint_timer=new QTimer(this);
-  connect(ripcd_maint_timer,SIGNAL(timeout()),this,SLOT(checkMaintData()));
-  int interval=GetMaintInterval();
-  if(!rda->config()->disableMaintChecks()) {
-    ripcd_maint_timer->start(interval);
-  }
-  else {
-    log(RDConfig::LogInfo,"maintenance checks disabled on this host!");
-  }
-
   //
   // Exit Timer
   //
@@ -371,49 +357,6 @@ void MainObject::killData(int conn_id)
 }
 
 
-void MainObject::checkMaintData()
-{
-  QString sql;
-  RDSqlQuery *q;
-  QDateTime current_datetime=
-    QDateTime(QDate::currentDate(),QTime::currentTime());
-  bool run=false;
-
-  RunLocalMaintRoutine();
-
-  //
-  // Should we try to run system maintenance?
-  //
-  if(!rda->station()->systemMaint()) {
-    return;
-  }
-
-  //
-  // Get the system-wide maintenance timestamp
-  //
-  sql="lock tables VERSION write";
-  q=new RDSqlQuery(sql);
-  delete q;
-  sql="select LAST_MAINT_DATETIME from VERSION";
-  q=new RDSqlQuery(sql);
-  if(q->first()) {
-    run=1000*q->value(0).toDateTime().secsTo(current_datetime)>
-      RD_MAINT_MAX_INTERVAL;
-  }
-  delete q;
-  sql="unlock tables";
-  q=new RDSqlQuery(sql);
-  delete q;
-
-  //
-  // Run the routines
-  //
-  if(run) {
-    RunSystemMaintRoutine();
-  }
-}
-
-
 void MainObject::macroTimerData(int num)
 {
   ExecCart(ripc_macro_cart[num]);
diff --git a/ripcd/ripcd.h b/ripcd/ripcd.h
index fb19a096..5a69905f 100644
--- a/ripcd/ripcd.h
+++ b/ripcd/ripcd.h
@@ -78,7 +78,6 @@ class MainObject : public QObject
   void macroTimerData(int num);
   void readyReadData(int conn_id);
   void killData(int conn_id);
-  void checkMaintData();
   void exitTimerData();
   void garbageData();
   
@@ -100,9 +99,6 @@ class MainObject : public QObject
   void SendGpoMask(int ch,int matrix);
   void SendGpiCart(int ch,int matrix);
   void SendGpoCart(int ch,int matrix);
-  void RunSystemMaintRoutine();
-  void RunLocalMaintRoutine();
-  int GetMaintInterval() const;
   RDMacro ForwardConvert(const RDMacro &rml) const;
   bool LoadSwitchDriver(int matrix_num);
   QSqlDatabase *ripcd_db;
@@ -133,7 +129,6 @@ class MainObject : public QObject
   bool ripc_onair_flag;
   QTimer *ripc_macro_timer[RD_MAX_MACRO_TIMERS];
   unsigned ripc_macro_cart[RD_MAX_MACRO_TIMERS];
-  QTimer *ripcd_maint_timer;
   RDMulticaster *ripcd_notification_mcaster;
   QTimer *ripcd_garbage_timer;
 };