project BLF > class TDaemonUtility > method StartDaemonInternal

Description

Internal method that physically starts the new daemon process. It is only called by the wrapper method "tDaemonUtility.StartDaemon".


Parameters


icDaemonNameinputcharacter
ocMessageoutputcharacter
oiReturnStatusoutputintegerReturn status of the method.


Internal usage


BLF
method TDaemonUtility.StartDaemon


program code (program1/tdaemonutility.p)

/* ================================================================= */
/*  First do some validations.                                       */
/* ================================================================= */
<Q-1 run DaemonLoginInfo (all) (Read) (NoCache)
          (input icDaemonName, (DaemonName)
           output dataset tqDaemonLoginInfo) in BBaseDaemon >
find first tqDaemonLoginInfo no-error.
if not available tqDaemonLoginInfo
then do :
    assign ocMessage = trim(substitute(#T-10'The daemon (&1) cannot be started since it has not yet been configured.':255(4381)T-10#,icDaemonName))
           oiReturnStatus = -3.
    return.
end.

if tqDaemonLoginInfo.tiDaemonMaxNumberOfInstances = 0
then do :
    assign ocMessage = #T-58'A disabled daemon (# instances is zero) cannot be started.':255(323576663)T-58#
           oiReturnStatus = -3.
    return.
end.

if tqDaemonLoginInfo.tcDaemonStatus = {&DAEMONSTATUS-RUNNING}
then assign viDaemonsStarted = tqDaemonLoginInfo.tiDaemonRunningProcesses
            viDaemonsToStart = tqDaemonLoginInfo.tiDaemonMaxNumberOfInstances - tqDaemonLoginInfo.tiDaemonRunningProcesses.
else assign viDaemonsStarted = 0
            viDaemonsToStart = tqDaemonLoginInfo.tiDaemonMaxNumberOfInstances.
if viDaemonsToStart <= 0
then do:
    assign ocMessage =  substitute(#T-93'The daemon (&1) is already running.':255(925698927)T-93#,icDaemonName).
           oiReturnStatus = -3.
    return.
end.

if tqDaemonLoginInfo.tcDaemonLogin          = "":U or 
   tqDaemonLoginInfo.tcDaemonLogin          = ? 
then assign ocMessage = ocMessage + chr(10) + trim(substitute(#T-11'The daemon (&1) cannot be started because the &2 is not specified. Please use the maintenance function on this daemon to correct this.':255(5184)T-11#,icDaemonName,trim(#T-12'Login':35(5183)T-12#))).

if tqDaemonLoginInfo.tcDaemonStartDirectory = "":U or
   tqDaemonLoginInfo.tcDaemonStartDirectory = ? 
then assign ocMessage = ocMessage + chr(10) + trim(substitute(#T-13'The daemon (&1) cannot be started because the &2 is not specified. Please use the maintenance function on this daemon to correct this.':255(5184)T-13#,icDaemonName,trim(#T-14'Start-directory':35(5185)T-14#))).
else do:
    file-info:file-name = tqDaemonLoginInfo.tcDaemonStartDirectory.
    if file-info:file-type <> "DRW"
    then ocMessage = ocMessage + chr(10) + #T-175'The specified directory does not exist or is not writable.':100(9034)T-175#
                                         + " ("
                                         + (if file-info:full-pathname = ? then tqDaemonLoginInfo.tcDaemonStartDirectory else file-info:full-pathname)
                                         + ")".
end.

if tqDaemonLoginInfo.tcDaemonLogFile        = "":U or 
   tqDaemonLoginInfo.tcDaemonLogFile        = ? 
then assign ocMessage = ocMessage + chr(10) + trim(substitute(#T-15'The daemon (&1) cannot be started because the &2 is not specified. Please use the maintenance function on this daemon to correct this.':255(5184)T-15#,icDaemonName,trim(#T-16'Log-file':35(5187)T-16#))).
else do:
    file-info:file-name = tqDaemonLoginInfo.tcDaemonLogFile.
    if file-info:full-pathname = ?
    then do:
        vcTemp = tqDaemonLoginInfo.tcDaemonLogFile.
        if num-entries(vcTemp,"/") > num-entries(vcTemp,"~\")
        then entry (num-entries(vcTemp,"/"),vcTemp,"/") = "".
        else entry (num-entries(vcTemp,"~\"),vcTemp,"~\") = "".
        file-info:file-name = vcTemp.
        if file-info:file-type <> "DRW"
        then ocMessage = ocMessage + chr(10) + #T-44'The directory for the log file is not valid.':255(5199)T-44#
                                             + " (" + vcTemp + ")".
    end.
    else do:
        if file-info:file-type <> "FRW"
        then ocMessage = ocMessage + chr(10) + #T-50'You do not have write permissions for this log file.':100(5198)T-50#
                                             + " ("
                                             + (if file-info:full-pathname = ? then tqDaemonLoginInfo.tcDaemonLogFile else file-info:full-pathname)
                                             + ")".
    end.
end.

if tqDaemonLoginInfo.tcDaemonOsCommand      = "":U  or
   tqDaemonLoginInfo.tcDaemonOsCommand      = ? 
then assign ocMessage = ocMessage + chr(10) + trim(substitute(#T-17'The daemon (&1) cannot be started because the &2 is not specified. Please use the maintenance function on this daemon to correct this.':255(5184)T-17#,icDaemonName,trim(#T-18'OS-Command':35(5188)T-18#))).

if ocMessage                        <> ? and 
   length(ocMessage,"character":U)  > 1
then do :
    assign ocMessage      = substring(ocMessage,2,-1,"character":U) + chr(10) + 
                            trim(substitute(#T-19'This daemon cannot be started because not all required properties are available.':255(5189)T-19#)) 
           oiReturnStatus = -3.
    return.
end. /* if ocMessage <> ? and  */

/* ================================================================= */
/* Start the daemon.                                                 */
/* ================================================================= */
if tqDaemonLoginInfo.tcDaemonStatus <> {&DAEMONSTATUS-RUNNING}
then do:
    vcArguments = "for each fcDaemon where fcDaemon.DaemonName = '" + icDaemonName + "'".
    run StartPersistenceInPool (input ?, output vhFcComponent, output viFcReturnSuper).
    <M-83 run WriteDirect
       (input  'fcDaemon' (icTableName), 
        input  vcArguments (icPrepare), 
        input  'DaemonStatus' (icFieldList), 
        input  'c' (icFieldListDataTypes), 
        input  {&DAEMONSTATUS-STARTING} (icAbsolute), 
        input  '' (icIncremental), 
        input  ? (ihClass), 
        input  '' (icUserLogin), 
        output viFcReturnSuper (oiReturnStatus)) in persistence>
end.

file-info:file-name = tqDaemonLoginInfo.tcDaemonStartDirectory.
vcStartDirectory = file-info:full-pathname.

/* =========================================================== *
 * Convert relative paths to full pathnames
 * ========================================================== */
assign vcArguments = ""
       vcPropath   = "":U.

assign vcConfigFile = search(Icdaemonname + ".config":U)
       vcTemp       = ''.
if vcConfigFile <> ?
then do :
    input from value(vcConfigFile).
    repeat on error undo, leave:  /* cannot use throw */
        import unformatted vcTemp.
        if vcTemp begins 'EXTRAPAR='
        then assign vcArguments = vcArguments + ' ' + substring (vcTemp,10,-1,'CHARACTER').
        if vcTemp begins "PROPATH=":U
        then do:
             assign vcTemp = substring (vcTemp,9,-1,'CHARACTER').
             do viIdx = 1 to num-entries (vcTemp,',') :
                assign vcPathEntry = entry (viIdx,vcTemp,',').
                file-info:file-name = vcPathEntry.
                if file-info:full-pathname <> ?
                then vcPropath = vcPropath + ",":U + file-info:full-pathname.
             end.
        end.
    end. /* repeat */
    input close.
end. /* if vcConfigFile <> ? */

do viIdx = 1 to num-entries(PROPATH):
    vcPathEntry = entry(viIdx, PROPATH).
    if vcPathEntry = "":U
    then vcPathEntry = ".":U.
    file-info:file-name = vcPathEntry.
    if file-info:full-pathname <> ?
    then vcPropath = vcPropath + ",":U + file-info:full-pathname.
end.
vcPropath = trim(vcPropath, ",":U).

/* ================================================================= *
 * Prepare the arguments
 * ================================================================= */
assign vlPF = no
       viCountStartupParams = num-entries(session:startup-parameters).


do viCount = 1 to viCountStartupParams:

    vcParameter = entry(viCount, session:startup-parameters).
    
    if vlPF
    then do:
        if vcParameter = "(end .pf)":U
        then vlPF = no.
        next.
    end.

    if not vcParameter begins "-":U or
       vcParameter begins "-logginglevel ":U or 
       vcParameter begins "-logentrytypes ":U or 
       vcParameter begins "-logfile ":U or 
       vcParameter begins "-ubpid ":U or 
       vcParameter begins "-logname ":U or 
       vcParameter begins "-logthreshold ":U or 
       vcParameter begins "-numlogfiles ":U or 
       vcParameter begins "-ASID ":U or 
       vcParameter begins "-ubpropfile ":U or
       vcParameter begins "-p ":U or 
       vcParameter begins "-param ":U or 
       vcParameter begins "-ininame ":U
    then next.

    if vcParameter begins "-pf "
    then do:
        vlPF = yes.
        if length(vcParameter, "CHARACTER") > 14 and
           replace(substr(vcParameter, length(vcParameter, "CHARACTER":U) - 10, 11, "CHARACTER":U), "~\":U, "/":U) <> "/startup.pf":U
        then vcArguments = vcArguments + " ":U + vcParameter.
        next.
    end.

    assign vcArguments = vcArguments + " ":U + vcParameter.

end. /* do viCount = 1 to viCountStartupParams: */

assign vcArguments = vcArguments + " -param ":U + icDaemonName + " -b -p program/tdaemon.p ":U.


vcDLC = os-getenv("DLC").
file-info:file-name = vcDLC.
if file-info:file-type = ?
then do:
    vcpromsgs = search("promsgs":U).
    if opsys = "UNIX":U
    then vcDLC = replace(vcpromsgs,"/promsgs":U,"").
    else vcDLC = replace(vcpromsgs,"~\promsgs":U,"").
end.
else do:
    file-info:file-name = vcDLC + (if opsys = "UNIX":U
                                   then "/promsgs":U
                                   else "~\promsgs":U).
    if file-info:file-type = ?
    then vcpromsgs = search("promsgs":U).
    else vcpromsgs = file-info:full-pathname.
end.

/* ================================================================= */
/*  Starting the daemon is done by spawning a new progress session   */
/*  on the server in which the specific daemon process is started.   */
/*  The mark in the database that the daemon is active, is done by   */
/*  the daemonprocessor itself.                                      */
/* ================================================================= */

do viA = 1 to viDaemonsToStart:

    assign viDaemonsStarted = viDaemonsStarted + 1.
    
    case OPSYS:

        when "UNIX":U
        then do:
            if viA = 1
            then assign vcStartDirectory = vcStartDirectory + "/":U
                        vcDaemonExec     = replace (tqDaemonLoginInfo.tcDaemonOsCommand, {&DAEMONOSCOMMAND-CONSTANT}, " ":U + <M-31 GetDaemonExecutable
                                                                                                                                 (input  icDaemonName (icDaemonName), 
                                                                                                                                  input  vcDLC (icDLC)) in TDaemonUtility>
                                           + vcArguments).
            
            assign vcProgress = "cd ":U + vcStartDirectory + " ; ":U + 
                                "DLC=":U + vcDLC + " ; ":U +
                                "PROMSGS=":U + vcpromsgs + " ; ":U +
                                "PROPATH=":U + vcPropath + " ; ":U +
                                "export DLC PROMSGS PROPATH ; nohup ":U +
                                vcDaemonExec +
                                " > ":U + vcStartDirectory + icDaemonName + "StdOut" + string(viA) + ".log":U +
                               " 2> ":U + vcStartDirectory + icDaemonName + "StdErr" + string(viA) + ".log&":U.

            os-command no-wait value(vcProgress).
            
            <M-39 run CheckDaemonStatusInternal
               (input  icDaemonName (icDaemonName), 
                input  viDaemonsStarted (iiStarted), 
                output viFcReturnSuper (oiReturnStatus)) in TDaemonUtility>

            /* We do not really need the process ID, but this process will avoid the previous nohup process from hanging around and becoming a zombie process. */
            /* (see BLF-3319) */
            input stream sProcessRead through "echo $PPID":U.
            import stream sProcessRead vcTemp.
            input stream sProcessRead close.

            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then do:
                assign ocMessage = 
                    trim(substitute(#T-85'The daemon cannot be started: (&1)':120(4766)T-85#,icDaemonName)) + chr (10) +
                    trim(substitute(#T-78'See daemon log file for detailed information: (&1)':120(4767)T-78#,tqDaemonLoginInfo.tcDaemonLogFile)).
                return.
            end.        

        end. /* when "UNIX":U */
        
        when "WIN32":U
        then do:
            if viA = 1
            then assign vcStartDirectory = vcStartDirectory + "~\":U
                        vcDaemonExec     = "~"":U + <M-30 GetDaemonExecutable
                                                       (input  icDaemonName (icDaemonName), 
                                                        input  vcDLC (icDLC)) in TDaemonUtility> + "~"":U.
                        
            assign vcIni = vcStartDirectory + "s":U + string(viA) + string(TIME) + ".ini":U.
            OUTPUT TO value(vcIni).
            
            PUT UNFORMATTED "[WinChar Startup]":U SKIP
                            "DLC=":U + vcDLC SKIP
                            "PROPATH=":U + replace(REPLACE(vcPropath,"~\":U,"/":U),"/gui":U,"/tty":U) SKIP.
                            
            OUTPUT CLOSE.
            

            ASSIGN vcQuotedIni = (IF vcIni MATCHES "* *":U THEN "~"":U + vcIni + "~"":U ELSE vcIni)
                   vcProgress = vcDaemonExec + " -ininame ":U + vcQuotedIni  + vcArguments
                   vcProgress = Trim(Replace (tqDaemonLoginInfo.tcDaemonOsCommand, {&DAEMONOSCOMMAND-CONSTANT}, " ":U + vcProgress + " ":U))
                   vhFcComponent = ?.
                   
            <M-4 run Main () in Win32Lib>                        

            /*redirect output*/
            assign vcProgress = vcProgress + " >>" + vcStartDirectory + "TDaemonUtility":U + string(time) + ".log":U.            

            /*this will start 2 processes, 1 cmd and 1 daemon*/            
            assign viReturn = <M-5 ShellExecuteExtended
                                 (input  'cmd':U (icFile), 
                                  input  '/c ' + vcProgress (icParameters), 
                                  input  vcStartDirectory (icDir), 
                                  input  'open':U (icVerb), 
                                  output viProcess (oiProcessHandle), 
                                  output viProcessId (oiProcessId)) in Win32Lib>.

            if viReturn = 0
            then do:
                /* BLF-4204
                 * If shellexecute fails try a simple os-command.
                 * You cannot check the result of the os-command so do not try.
                 * os-command should use silent in stead of no-wait but that does not work.
                 */
                 os-command no-wait value (vcProgress).
            end.
            else
            if viReturn < 0
            then do:
                output to value(tqDaemonLoginInfo.tcDaemonLogFile) append.
                put unformatted 
                    "TDaemonUtility : ":U + string(now) #T-20'The daemon did not start properly.':255(5130)T-20# skip.
                    
                if viReturn eq -1 /* wrong parameters */
                then do:
                    <M-6 run GetCBFError
                       (output tErrorFromWin32 (tCBFError), 
                        output viFcReturnSuper (oiReturnStatus)) in Win32Lib>
                    for each tErrorFromWin32 by tErrorFromWin32.tiCBFSequence:
                        put unformatted tErrorFromWin32.tcCBFMessage skip.
                    end.    
                end.
                output close.
 
                assign ocMessage = 
                    trim(substitute(#T-23'The daemon cannot be started: (&1)':120(4766)T-23#,icDaemonName)) + chr (10) +
                    trim(substitute(#T-24'See daemon log file for detailed information: (&1)':120(4767)T-24#,tqDaemonLoginInfo.tcDaemonLogFile)).
                oiReturnStatus = -3.
                
                OS-DELETE VALUE(vcIni).
                
                run gipr_DeleteProcedure in vhFcComponent.
                delete procedure vhFcComponent.
                return.
    
            end. /* if viReturn le 0 */
            
            <M-496 run CheckDaemonStatusInternal
               (input  icDaemonName (icDaemonName), 
                input  viDaemonsStarted (iiStarted), 
                output viFcReturnSuper (oiReturnStatus)) in TDaemonUtility>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then ocMessage = 
                    trim(substitute(#T-51'The daemon cannot be started: (&1)':120(4766)T-51#,icDaemonName)) + chr (10) +
                    trim(substitute(#T-77'See daemon log file for detailed information: (&1)':120(4767)T-77#,tqDaemonLoginInfo.tcDaemonLogFile)).

            OS-DELETE VALUE(vcIni).

            /*terminate the cmd process*/
            if viProcessid > 0
            then do:
            assign viReturn = <M-8 EndProcessNoOpen
                                 (input  viProcess (iiProcessHandle)) in Win32Lib>.

            if viReturn = 0 and viFcReturnSuper >= 0
            then do:
                assign vcErrorMessage = <M-9 GetLastErrorStr () in Win32Lib>.

                if vcErrorMessage = ?
                then vcErrorMessage = "".
                
                assign ocMessage = trim(substitute(#T-25'The daemon cmd process could not be terminated: (&1)':255(5109)T-25#,icDaemonName)) + chr (10) +
                                   trim(#T-26'It is possible that the cmd process was already gone because the daemon did not start correctlty.':255(5131)T-26#) + chr (10) +
                                   trim(substitute(#T-27'Check the daemon log files for errors: (&1)':255(5129)T-27#,tqDaemonLoginInfo.tcDaemonLogFile)).
                       oiReturnStatus = -3.
                
                /* write error to daemon log file */
                output to value(tqDaemonLoginInfo.tcDaemonLogFile) append.
                put unformatted 
                    "TDaemonUtility : ":U + string(now) " : The daemon cmd process could not be stopped" skip                    
                    trim(substitute(#T-28'Operating system message: (&1)':120(4768)T-28#,vcerrorMessage)) skip.
                output close.
            end.
            end.
            
            run gipr_DeleteProcedure in vhFcComponent.
            delete procedure vhFcComponent.

            if viFcReturnSuper < 0
            or viReturn = 0
            then return.

        end. /* when "WIN32":U */

        otherwise do:
            assign ocMessage = trim(substitute(#T-29'The daemon (&1) cannot be started since the operating system is not supported.':120(4388)T-29#,icDaemonName))
                   oiReturnStatus = -3.
            return.
        end. /* otherwise */
    end case.

    /* Pause before starting next daemon instance to avoid optimistic lock problems */
    Pause 10.

end. /* do viA = 1 to viDaemonsToStart */