From c37bfce4e19e66f93df4715cde93eec00422d845 Mon Sep 17 00:00:00 2001
From: Arno Schoenmakers <schoenmakers@astron.nl>
Date: Tue, 20 Jun 2017 07:21:40 +0000
Subject: [PATCH] Task #10977: Put timeouts around shell commands, removed
 /opt/lofar/sbin path to tci, deleted old centos5 rubidium_logger.py

---
 .gitattributes                                |   1 -
 MAC/Tools/Rubidium/rubidium_logger.py         | 450 ------------------
 MAC/Tools/Rubidium/rubidium_logger_centos7.py |  12 +-
 3 files changed, 7 insertions(+), 456 deletions(-)
 delete mode 100755 MAC/Tools/Rubidium/rubidium_logger.py

diff --git a/.gitattributes b/.gitattributes
index fbda6a14321..67e28975af3 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -4137,7 +4137,6 @@ MAC/Tools/Power/turn_on_lcu.py -text
 MAC/Tools/Rubidium/filter.py -text
 MAC/Tools/Rubidium/rlp.py -text
 MAC/Tools/Rubidium/rr.py -text
-MAC/Tools/Rubidium/rubidium_logger.py -text
 MAC/Tools/Rubidium/rubidium_logger_centos7.py -text
 MAC/Tools/Rubidium/tci.c -text
 MAC/Tools/ethereal-0.9.8.tar.gz -text svneol=unset#unset
diff --git a/MAC/Tools/Rubidium/rubidium_logger.py b/MAC/Tools/Rubidium/rubidium_logger.py
deleted file mode 100755
index 1fec802e0e4..00000000000
--- a/MAC/Tools/Rubidium/rubidium_logger.py
+++ /dev/null
@@ -1,450 +0,0 @@
-#!/usr/bin/python
-
-import subprocess
-from subprocess import Popen, PIPE
-import sys
-import time
-from time import sleep
-import termios
-import resource
-import os
-import datetime
-import glob
-import logging
-import logging.handlers
-
-
-try:
-    import codecs
-except ImportError:
-    codecs = None
-
-ttMeanSpec  =   100 # +/- 100ns limit
-ttMeanSs    =   100 # sample count of which mean should be lower then ttMeanSpec
-ttLogLength = 86400 # Maximum number of history, 24 hours
-                    # Lost lock is always resulting in wrong
-
-logFp = None
-ttHistList = []
-ttMeanList = []
-loHistList = []
-lastOKay = False
-noPPS = False
-st5 = -1
-
-workingSettings = [1280, 5, 3261, 35387, 13, 13, ['\x03', '\x1c', '\x7f', '\x15', '\x04', '\x00', '\x01', '\x00', '\x11', '\x13', '\x1a', '\x00', '\x12', '\x0f', '\x17', '\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00']]
-
-rub_logger = None
-msgBuffer = []
-statusFile = ""
-
-cmdList = ['ST?', 'TT?']
-advCmdList = ['AD0?', 'AD1?', 'AD2?', 'AD3?', 'AD4?', 'AD5?', 'AD6?', 'AD7?', 'AD8?', 'AD9?', 'AD10?', 'AD11?', 'AD12?', 'AD13?', 'AD14?', 'AD15?', 'AD16?', 'AD17?', 'AD18?','SD0?', 'SD1?', 'SD2?', 'SD3?', 'SD4?', 'SD5?', 'SD6?', 'SD7?','SP?','SF?','SS?','MO?','MR?','MS?','LO?','GA?','PH?','EP?','FC?','DS?', 'TO?','TS?','PS?','PL?','PT?','PF?','PI?','LM?']
-
-
-
-def checkSettings(fp):
-    curSet = termios.tcgetattr(fp)
-    if curSet != workingSettings:
-        cmd = 'stty < /dev/ttyS0'
-        cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
-        (result, resultErr) = cf.communicate()
-        print result, resultErr
-    else:
-        return True
-
-
-def callCommand(cmd):
-
-    cmd1 = "/opt/lofar/sbin/tci "
-    cmd1 += cmd
-    result = None
-    cf = Popen(cmd1, shell = True, stdout = PIPE, stderr = PIPE)
-        
-    (res,resErr) = cf.communicate()
-    if cf.returncode != -1 and len(res)>0:
-        result = res
-    else:
-        result = "Fail"
-    return result
-
-
-
-# How to become a daemon
-# ----------------------
-# See Advanced Programming in the UNIX Environment by Stevens and Rago, section 13.3, pp. 425/426.
-# See also the UNIX Programming FAW (http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16)
-#
-# 1. call umask(0) to clear the file mode creation mask. the umask is inherited and may be set to
-#    deny certain permissions.
-# 2. fork() and let the parent exit. this returns control to the shell. also, the child inherits
-#    the parent's process group id, but gets its own process id. by definition, it is therefore
-#    not a process group leader. this is a prerequisite for calling setsid(), which is the next
-#    step.
-# 3. call setsid() to create a new session. the process becomes leader of a new sessions, process
-#    group leader of a new process group and has no controlling terminal.
-# 4. fork() again to ensure the process is not a session leader. (System V systems may allocate a
-#    controlling terminal for session leaders under certain conditions).
-# 5. chdir("/") to ensure that the daemon does not tie up any mounted file systems.
-# 6. close all open file descriptors we may have inherited from our parent.
-# 7. re-open stdin, stdout, and stderr; for instance, point stdout and stderr to a log file, or
-#    simply redirect to /dev/null.
-#
-def daemonize(logfile):
-    try:
-        no_file = resource.getrlimit(resource.RLIMIT_NOFILE)
-    except ValueError, ex:
-        print "error: unable to determine NOFILE resource limit; daemon not started (%s)" % ex
-        sys.exit(EXIT_ERROR)
-
-    # 1. clear umask
-    try:
-        os.umask(0)
-    except OSError, ex:
-        print "error: unable to set umask; daemon not started %s" % ex
-        sys.exit(EXIT_ERROR)
-
-    # 2. fork and let parent exit
-    try:
-        pid = os.fork()
-    except OSError, ex:
-        print "error: unable to fork; daemon not started (%s)" % ex
-        sys.exit(EXIT_ERROR)
-
-    if pid != 0:
-        # parent exits
-        # NOTE: Steven and Rago specify a standard exit(0) here, while the UNIX Programming FAQ
-        # recommends _exit(0) (see http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC6). We favour
-        # the latter approach, because it seems correct to only do user-mode clean-up once.
-        os._exit(0)
-
-    #
-    #    FIRST CHILD PROCESS
-    #
-
-    # 3. create a new session
-    try:
-        sid = os.setsid()
-    except OSError, ex:
-        print "error: unable to create a new session; daemon not started (%s)" % ex
-        sys.exit(EXIT_ERROR)
-
-    # 4. second fork
-    try:
-        pid = os.fork()
-    except OSError, ex:
-        print "error: unable to fork; daemon not started (%s)" % ex
-        sys.exit(EXIT_ERROR)
-
-    if pid != 0:
-        # parent exits
-        # NOTE: Steven and Rago specify a standard exit(0) here, while the UNIX Programming FAQ
-        # recommends _exit(0) (see http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC6). We favour
-        # the latter approach, because it seems correct to only do user-mode clean-up once.
-        os._exit(0)
-
-    #
-    #    SECOND CHILD PROCESS
-    #
-
-    try:
-        # 5. change the working directory
-        os.chdir("/")
-
-        # 6. closing stdout; from this moment on, any errors will be sent to the syslog.
-        # 6a. flush stdout and stderr
-        sys.stdout.flush()
-        sys.stderr.flush()
-
-        # 6b. close all open file descriptors (uses soft NO_FILE limit)
-        for fd in range(0, max(no_file[0], 1024)):
-            try:
-                os.close(fd)
-            except OSError:
-                pass
-
-        # 7. re-open stdin, stdout, and stderr as /dev/null
-        # for python >= 2.4 use os.devnull
-        sys.stdin = open("/dev/null", "r")
-        sys.stdout = open(logfile, "a")
-        sys.stderr = open(logfile, "a")
-    except (IOError, OSError), ex:
-        syslog.syslog(syslog.LOG_ERR, "unable to chdir, close open file descriptors, or open %s; daemon not started (%s)" % logfile, ex)
-        sys.exit(EXIT_ERROR)
-
-    #
-    # properly daemonized from now on...
-    #
-
-
-def statusHandler(cmd, response):
-    global ttHistList, loHistList, noPPS, st5
-    statusLine = "Rubidium_Status at "
-    logLine = ""
-    curLo = 0
-    
-    okay = True
-        
-    if cmd.find("TT?") != -1:
-        if response != "Fail":
-            conVal = 0
-            try:
-                conVal = int(response.strip())
-                if conVal == -1:
-                    noPPS = True
-                else:
-                    noPPS = False
-                if conVal > 500000000 :
-                    conVal = conVal - 1000000000
-            except:
-                conVal = -127
-            ttHistList.append(abs(conVal))
-        else:
-            ttHistList.append(-127)
-        if len(ttHistList) > ttLogLength:
-            ttHistList.pop(0)
-    elif cmd.find("ST?") != -1:
-        if response != "Fail":
-            parts = response.split(',')
-            try:
-                if len(parts)==6:
-                    st5 = int(parts[4])
-            except:
-                st5 = -1
-        else:
-            st5 = -1
-    elif cmd.find("LO?") != -1:
-        resStr = response.strip()
-        if resStr.find('1') != -1:
-            curLo = 1
-            loHistList.append(1)
-        elif resStr.find('0') != -1:
-            loHistList.append(0)
-            curLo = 0
-
-        if len(loHistList) > (ttLogLength/60):
-            loHistList.pop(0)
-
-        subSet = None
-        if len(ttHistList) > ttMeanSs:
-            subSet =  ttHistList[ttMeanSs*-1:-1]
-        else:
-            subSet =  ttHistList[:]
-        sum = 0
-        count = 0
-        for val in subSet:
-            if val != -127:
-                sum += val
-                count += 1
-        try:
-            mean = float(sum) / float(count)
-        except:
-            mean = 2 * ttMeanSpec
-
-        outSpec = False
-        if mean > ttMeanSpec:
-            outSpec = True
-        outOfSpecCount = 0
-        for i in ttHistList:
-            if i > ttMeanSpec:
-                outOfSpecCount += 1
-
-        outOfLocCount = loHistList.count(0)
-        comErrorCount = ttHistList.count(-127)
-
-        if response == "Fail" or outSpec or curLo == 0 or st5 != 4 and st5 != 20 or noPPS:
-            logLine += ": fail"
-        else:
-            logLine += ": okay"
-
-        if curLo == 1 and not noPPS and (st5 == 4 or st5 == 20):
-            logLine += ", rubidium lock=okay"
-        else:
-            logLine += ", rubidium lock=fail"
-
-        logLine += ", pps input="
-        if noPPS:
-            logLine += "fail"
-        else:
-            logLine += "okay"
-        logLine += ", status=" + str(st5)            
-            
-        logLine += ", communication error=" + str(comErrorCount) + " sec"
-        logLine += ", outside spec +- 100 ns=" + str(outOfSpecCount) + " sec"
-        logLine += ", lost lock=" + str(outOfLocCount) + " times\n"
-
-        logTime = datetime.datetime.utcnow()
-        line =  statusLine + logTime.isoformat() + logLine
-#        logFp.truncate(0)
-        logFp = None
-        try:
-            logFp = open(statusFile,"w+")
-        except Exception, e:
-            print "Trouble while opening a log file, details: " + e.__str__()
-        logFp.write(line)
-        logFp.flush()
-        logFp.close()
-        
-
-def getHostName():
-    cmd = 'hostname -s' 
-    cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
-        
-    (res,resErr) = cf.communicate()
-    if cf.returncode != -1 and len(res)>0:
-        result = res.strip()
-    else:
-        result = "CS000"
-    return result
-
-def main():
-
-    # Now make yourself a daemon...!
-    daemonize("/var/log/ntpstats/rubidium_logger.log")
-    global ttyFp, logFp, rub_logger, statusFile
-
-    args = sys.argv[1:]
-    
-    hostName = getHostName()
-    
-    if hostName == None:
-        hostName = ''
-    logFilePath = '/var/log/ntpstats/'
-    statusFile = '/var/log/ntpstats/rubidium_status_' + hostName + ".log"
-    logFileBase = 'rubidium_log'
-    logPath  = os.path.join(logFilePath, logFileBase)
-
-    # Set up a specific logger with our desired output level
-    rub_logger = logging.getLogger('Rubidium Logger')
-    rub_logger.setLevel(logging.INFO)
-
-    # Add the log message handler to the logger 
-    handler = MyTimedRotatingFileHandler(logPath)
-    rub_logger.addHandler(handler)
-        
-    try:
-        # check if ttyS0 can be opened
-        ttyFp = open("/dev/ttyS0", "w+")
-    except Exception, e:
-        print "Trouble while opening the serial port, details: " + e.__str__()
-        sys.exit()
-
-    checkSettings(ttyFp)
-    if ttyFp != None:
-        ttyFp.close()
-
-    print "running"
-
-    first = True
-    oldCur = -1
-    cur = -1
-    count = 0
-    interval = 60
-    cmdIndex = 0
-    cmdStep = 4
-    #Logger loop, read rubidium
-    while True:
-        count += 1
-        #Wait loop, every second one read loop
-        while cur == oldCur:
-            sleep(0.01)
-            cur = round(time.time())
-            
-        oldCur = cur
-        logStr = ''
-        for cmd in cmdList:
-            line = callCommand(cmd)
-            statusHandler(cmd,line)
-            if cmd.find("TT?")!= -1:
-                # Modify clock response if it returns a high value
-                if line != "Fail":
-                    conVal = -127
-                    try:
-                        conVal = int(line.strip())
-                    except:
-                        conVal = -127
-                    if conVal > 500000000 :
-                        conVal = conVal - 1000000000
-                    line = str(conVal)
-            logStr += cmd.strip('?') + ' ' + line.strip() + "; "
-        if count >= interval or cmdIndex != 0:
-            # Every 60 seconds, call all advanced commands, in groups of 4 / second
-            if cmdIndex == 0:
-                count = 0
-            for i in range(cmdStep):
-                curCmdIndex = cmdIndex + i
-                if curCmdIndex < len(advCmdList):
-                    cmd = advCmdList[curCmdIndex]
-                    line = callCommand(cmd)
-                    logStr += cmd.strip('?') + ' ' + line.strip() + "; "
-                    if cmd.find("LO?")!= -1:
-                        statusHandler(cmd,line)
-                        
-            cmdIndex += cmdStep
-            if cmdIndex > len(advCmdList):
-                cmdIndex = 0 
-                
-        printAndLog(logStr)
-        if count > (round(float(len(advCmdList))/cmdStep)+1):
-            sleep(0.5)
-        else:
-            sleep(0.2)
-            
-    if logFp != None:
-        logFp.close()
-
-
-def printAndLog(text):
-    # print to log file
-    global  msgBuffer
-    logTime = datetime.datetime.utcnow()
-    line =  logTime.isoformat() + '; ' + text
-    sLine = line.strip()
-    if rub_logger == None:
-        msgBuffer.append(sLine)
-    else:
-        if len(msgBuffer)!= 0:
-            for bLine in msgBuffer:
-                rub_logger.info(bLine)
-            msgBuffer = []
-        rub_logger.info(sLine)
-
-
-
-#Class to modify the standard python timed rotating file handler, 
-# now with the specified filename structure: filename.YYmmdd
-class MyTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
-  def __init__(self,dir_log):
-   self.dir_log = dir_log
-   filename =  self.dir_log + "." + time.strftime("%Y%m%d")
-   logging.handlers.TimedRotatingFileHandler.__init__(self,filename, when='midnight', interval=1, backupCount=0, encoding=None)
-   cmd = 'ln -fs ' + filename + ' ' + self.dir_log
-   cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
-   (res,resErr) = cf.communicate()
-   
-  def doRollover(self):
-   """
-   TimedRotatingFileHandler remix - rotates logs on daily basis, and filename of current logfile is time.strftime("%Y%m%d") always
-   """ 
-   self.stream.close()
-   # get the time that this sequence started at and make it a TimeTuple
-   t = self.rolloverAt - self.interval
-   timeTuple = time.localtime(t)
-   self.baseFilename = self.dir_log + "." + time.strftime("%Y%m%d")
-    
-   if self.encoding:
-     self.stream = codecs.open(self.baseFilename, 'a', self.encoding)
-   else:
-     self.stream = open(self.baseFilename, 'a')
-
-   cmd = 'ln -fs ' + self.baseFilename + ' ' + self.dir_log
-   cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
-   (res,resErr) = cf.communicate()
-   self.rolloverAt = self.rolloverAt + self.interval
-
-
-
-#Call main, execute this script
-main()
-
-
diff --git a/MAC/Tools/Rubidium/rubidium_logger_centos7.py b/MAC/Tools/Rubidium/rubidium_logger_centos7.py
index 6fdc91b1c3e..8c0f6708f04 100755
--- a/MAC/Tools/Rubidium/rubidium_logger_centos7.py
+++ b/MAC/Tools/Rubidium/rubidium_logger_centos7.py
@@ -2,6 +2,8 @@
 #
 # Rubidium logger implementation for CentOS7 (uses daemonize PIP package)
 #
+# Install/Copy this in /usr/local/bin on stations, DO NOT INSTALL IN /opt/lofar !!!!
+#
 
 import subprocess
 from subprocess import Popen, PIPE
@@ -50,7 +52,7 @@ advCmdList = ['AD0?', 'AD1?', 'AD2?', 'AD3?', 'AD4?', 'AD5?', 'AD6?', 'AD7?', 'A
 def checkSettings(fp):
     curSet = termios.tcgetattr(fp)
     if curSet != workingSettings:
-        cmd = 'stty < /dev/rubidium'
+        cmd = 'timeout 5s stty < /dev/rubidium'
         cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
         (result, resultErr) = cf.communicate()
         print result, resultErr
@@ -60,7 +62,7 @@ def checkSettings(fp):
 
 def callCommand(cmd):
 
-    cmd1 = "/opt/lofar/sbin/tci "
+    cmd1 = "timeout 5s tci "
     cmd1 += cmd
     result = None
     cf = Popen(cmd1, shell = True, stdout = PIPE, stderr = PIPE)
@@ -182,7 +184,7 @@ def statusHandler(cmd, response):
         
 
 def getHostName():
-    cmd = 'hostname -s' 
+    cmd = 'timeout 1s hostname -s' 
     cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
         
     (res,resErr) = cf.communicate()
@@ -294,7 +296,7 @@ class MyTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    self.dir_log = dir_log
    filename =  self.dir_log + "." + time.strftime("%Y%m%d")
    logging.handlers.TimedRotatingFileHandler.__init__(self,filename, when='midnight', interval=1, backupCount=0, encoding=None)
-   cmd = 'ln -fs ' + filename + ' ' + self.dir_log
+   cmd = 'timeout 5s ln -fs ' + filename + ' ' + self.dir_log
    cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
    (res,resErr) = cf.communicate()
    os.chmod(filename,0644)
@@ -314,7 +316,7 @@ class MyTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    else:
      self.stream = open(self.baseFilename, 'a')
 
-   cmd = 'ln -fs ' + self.baseFilename + ' ' + self.dir_log
+   cmd = 'timeout 5s ln -fs ' + self.baseFilename + ' ' + self.dir_log
    cf = Popen(cmd, shell = True, stdout = PIPE, stderr = PIPE)
    (res,resErr) = cf.communicate()
    os.chmod(self.baseFilename,0644)
-- 
GitLab