Ack for patch 1,
You could use %PRIx64 for MDS addresses.
Mathi.

----- vu.m.ngu...@dektech.com.au wrote:

> osaf/services/saf/logsv/lgs/Makefile.am    |    6 +-
>  osaf/services/saf/logsv/lgs/lgs.h          |   12 +
>  osaf/services/saf/logsv/lgs/lgs_cb.h       |   14 +
>  osaf/services/saf/logsv/lgs/lgs_evt.cc     |   66 ++-
>  osaf/services/saf/logsv/lgs/lgs_evt.h      |    5 +
>  osaf/services/saf/logsv/lgs/lgs_file.cc    |    5 +
>  osaf/services/saf/logsv/lgs/lgs_file.h     |    1 +
>  osaf/services/saf/logsv/lgs/lgs_filehdl.cc |  424 ++++++++++++++++-
>  osaf/services/saf/logsv/lgs/lgs_filehdl.h  |   21 +
>  osaf/services/saf/logsv/lgs/lgs_imm.cc     |  541
> ++++++++++++++++++++-
>  osaf/services/saf/logsv/lgs/lgs_main.cc    |  134 ++++-
>  osaf/services/saf/logsv/lgs/lgs_mbcsv.cc   |   22 +-
>  osaf/services/saf/logsv/lgs/lgs_recov.cc   |  758
> +++++++++++++++++++++++++++++
>  osaf/services/saf/logsv/lgs/lgs_recov.h    |   37 +
>  osaf/services/saf/logsv/lgs/lgs_stream.cc  |   65 +-
>  osaf/services/saf/logsv/lgs/lgs_stream.h   |   28 +-
>  osaf/services/saf/logsv/lgs/lgs_util.cc    |   50 +-
>  osaf/services/saf/logsv/lgs/lgs_util.h     |    4 +
>  18 files changed, 2121 insertions(+), 72 deletions(-)
> 
> 
> The patch makes LOG service be able to handle the case that both SC
> nodes
> are down at the same time.
> When one or both nodes go up again the log service must be able to
> resume its work preferably without actions by the clients.
> 
> A log client should not have to be aware of if one or both SC nodes
> are down.
> The only thing that should happen is that a TRY AGAIN (and in some
> cases TIMEOUT) returned.
> It is the responsibility of the client to decide how to handle this.
> 
> diff --git a/osaf/services/saf/logsv/lgs/Makefile.am
> b/osaf/services/saf/logsv/lgs/Makefile.am
> --- a/osaf/services/saf/logsv/lgs/Makefile.am
> +++ b/osaf/services/saf/logsv/lgs/Makefile.am
> @@ -35,7 +35,8 @@ noinst_HEADERS = \
>       lgs_mbcsv_v1.h \
>       lgs_mbcsv_v2.h \
>       lgs_mbcsv_v3.h \
> -     lgs_mbcsv_v5.h
> +     lgs_mbcsv_v5.h \
> +     lgs_recov.h
>  
>  osaf_execbindir = $(pkglibdir)
>  osaf_execbin_PROGRAMS = osaflogd
> @@ -63,7 +64,8 @@ osaflogd_SOURCES = \
>       lgs_mbcsv_v1.cc \
>       lgs_mbcsv_v2.cc \
>       lgs_mbcsv_v3.cc \
> -     lgs_mbcsv_v5.cc
> +     lgs_mbcsv_v5.cc \
> +     lgs_recov.cc
>  
>  osaflogd_LDADD = \
>       $(top_builddir)/osaf/tools/safimm/src/libimmutil.la \
> diff --git a/osaf/services/saf/logsv/lgs/lgs.h
> b/osaf/services/saf/logsv/lgs/lgs.h
> --- a/osaf/services/saf/logsv/lgs/lgs.h
> +++ b/osaf/services/saf/logsv/lgs/lgs.h
> @@ -30,6 +30,8 @@
>  #include <ncs_edu_pub.h>
>  #include <ncs_util.h>
>  #include <saAis.h>
> +#include <saf_error.h>
> +#include <saImmOm.h>
>  
>  /* LGS files */
>  #include "lgsv_defs.h"
> @@ -111,6 +113,16 @@ extern void lgs_imm_impl_reinit_nonblock
>  extern void lgs_imm_init_OI_handle(SaImmOiHandleT *immOiHandle,
>                                     SaSelectionObjectT
> *immSelectionObject);
>  extern void lgs_imm_impl_set(SaImmOiHandleT immOiHandle);
> +extern  SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t *cb);
>  
> +// Functions for recovery handling
> +void lgs_clean_stream_objects(void);
> +void lgs_delete_one_stream_object(char *name_str);
> +void lgs_search_stream_objects(void);
> +SaUint32T *lgs_get_scAbsenceAllowed_attr(SaUint32T *attr_val);
> +int lgs_get_streamobj_attr(SaImmAttrValuesT_2 ***attrib_out,
> +                        char *object_name,
> +                        SaImmHandleT *immOmHandle);
> +int lgs_free_streamobj_attr(SaImmHandleT immHandle);
>  
>  #endif   /* ifndef __LGS_H */
> diff --git a/osaf/services/saf/logsv/lgs/lgs_cb.h
> b/osaf/services/saf/logsv/lgs/lgs_cb.h
> --- a/osaf/services/saf/logsv/lgs/lgs_cb.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_cb.h
> @@ -26,6 +26,14 @@
>  
>  #include "lgs_stream.h"
>  
> +/* LGS Recovery states */
> +typedef enum {
> +    LGS_NORMAL,     /* No recovery is ongoing. All requests are
> handled normally */
> +    LGS_RECOVERY    /* Recover streams if in recovery list when
> stream open
> +                                      * request with no parameters
> +                                      */
> +} lgs_state_t;
> +
>  /* Default HA state assigned locally during lgs initialization */
>  #define LGS_HA_INIT_STATE 0
>  
> @@ -87,6 +95,12 @@ typedef struct lgs_cb {
>       LGA_DOWN_LIST *lga_down_list_tail;
>  
>       bool nid_started;       /**< true if started by NID */
> +     SaUint32T scAbsenceAllowed; /* OpenSAF global configuration for
> recovery handling */
> +     lgs_state_t lgs_recovery_state; /* Indicate current recovery state
> for the server */
> +
> +     // Initialize default value in contructor
> +     lgs_cb() : lgs_recovery_state(LGS_NORMAL) {};
> +
>  } lgs_cb_t;
>  
>  extern uint32_t lgs_cb_init(lgs_cb_t *);
> diff --git a/osaf/services/saf/logsv/lgs/lgs_evt.cc
> b/osaf/services/saf/logsv/lgs/lgs_evt.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_evt.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_evt.cc
> @@ -21,6 +21,7 @@
>  
>  #include "lgs_mbcsv_v1.h"
>  #include "lgs_mbcsv_v2.h"
> +#include "lgs_recov.h"
>  
>  /* Macro to validate the version */
>  #define m_LOG_VER_IS_VALID(ver)   \
> @@ -375,6 +376,8 @@ static uint32_t proc_lga_updn_mds_msg(lg
>               break;
>  
>       case LGSV_LGS_EVT_LGA_DOWN:
> +             TRACE("%s: LGSV_LGS_EVT_LGA_DOWN mds_dest = %" PRIu64,
> +                   __FUNCTION__, evt->fr_dest);
>               if ((lgs_cb->ha_state == SA_AMF_HA_ACTIVE) || (lgs_cb->ha_state 
> ==
> SA_AMF_HA_QUIESCED)) {
>               /* Remove this LGA entry from our processing lists */
>                       osaf_clock_gettime(CLOCK_REALTIME, &closetime_tspec);
> @@ -772,11 +775,17 @@ static uint32_t lgs_ckpt_stream_open(lgs
>  
>  /**
>   * Create a new application stream
> - * @param open_sync_param
> - * @param o_stream
> - * @return 
> + *
> + * @param open_sync_param[in] Parameters used to create the stream
> + * @param o_stream[out]       The created stream
> + * @param create_object_f     IMM stream object is created
> + *
> + * @return AIS return code
>   */
> -static SaAisErrorT create_new_app_stream(lgsv_stream_open_req_t
> *open_sync_param, log_stream_t **o_stream)
> +SaAisErrorT create_new_app_stream(
> +             lgsv_stream_open_req_t *open_sync_param,
> +             log_stream_t **o_stream,
> +             int creationFlag)
>  {
>       SaAisErrorT rc = SA_AIS_OK;
>       log_stream_t *stream;
> @@ -870,7 +879,7 @@ static SaAisErrorT create_new_app_stream
>               goto done;
>       }
>  
> -     stream = log_stream_new(&open_sync_param->lstr_name,
> +     stream = log_stream_new_1(&open_sync_param->lstr_name,
>                               open_sync_param->logFileName,
>                               open_sync_param->logFilePathName,
>                               open_sync_param->maxLogFileSize,
> @@ -878,7 +887,11 @@ static SaAisErrorT create_new_app_stream
>                               open_sync_param->logFileFullAction,
>                               open_sync_param->maxFilesRotated,
>                               open_sync_param->logFileFmt,
> -                             STREAM_TYPE_APPLICATION, STREAM_NEW, 
> twelveHourModeFlag, 0);
> +                             STREAM_TYPE_APPLICATION,
> +                             STREAM_NEW,
> +                             twelveHourModeFlag,
> +                             0,
> +                             creationFlag);
>  
>       if (stream == NULL) {
>               rc = SA_AIS_ERR_NO_MEMORY;
> @@ -960,6 +973,7 @@ static uint32_t proc_stream_open_msg(lgs
>       log_stream_t *logStream;
>       char name[SA_MAX_NAME_LENGTH + 1];
>       time_t file_closetime = 0;
> +     int i_rc = 0;
>  
>       /* Create null-terminated stream name */
>       memcpy(name, open_sync_param->lstr_name.value,
> open_sync_param->lstr_name.length);
> @@ -981,10 +995,12 @@ static uint32_t proc_stream_open_msg(lgs
>                       /* One of the well-known log streams */
>                       if (open_sync_param->lstr_open_flags & 
> SA_LOG_STREAM_CREATE) {
>                               ais_rv = SA_AIS_ERR_INVALID_PARAM;
> +                             rc = NCSCC_RC_FAILURE;
>                               goto snd_rsp;
>                       }
>               }
>       } else {
> +             /* Stream does not exist */
>               if (cb->immOiHandle == 0) {
>                       TRACE("IMM service unavailable, open stream failed");
>                       ais_rv = SA_AIS_ERR_TRY_AGAIN;
> @@ -992,20 +1008,48 @@ static uint32_t proc_stream_open_msg(lgs
>               }
>  
>               if ((open_sync_param->lstr_open_flags & SA_LOG_STREAM_CREATE) 
> == 0)
> {
> -                     ais_rv = SA_AIS_ERR_NOT_EXIST;
> -                     goto snd_rsp;
> +                     /* The stream does not exist but the create flag is not
> +                      * set. If lgs_state is LGS_RECOVERY then:
> +                      * Check if the stream is in the list of stream objects
> +                      * not recovered. If in list, recover the stream and
> +                      * add it to the client
> +                      */
> +                     if (lgs_cb->lgs_recovery_state == LGS_RECOVERY) {
> +                             TRACE("%s LGS_RECOVERY",__FUNCTION__);
> +                             i_rc = lgs_restore_one_app_stream(name,
> +                                     open_sync_param->client_id,
> +                                     &logStream);
> +                             if (i_rc == -1) {
> +                                     TRACE("%s lgs_restore_one_stream Fail", 
> __FUNCTION__);
> +                                     ais_rv = SA_AIS_ERR_NOT_EXIST;
> +                                     goto snd_rsp;
> +                             }
> +                             TRACE("%s Stream %s is recovered", 
> __FUNCTION__, name);
> +                             log_stream_print(logStream); /* TRACE */
> +                             lstr_id = logStream->streamId;
> +                             goto snd_rsp;
> +                     } else {
> +                             /* Trying to open a non existing stream */
> +                             TRACE("%s Attempt to open not existing stream", 
> __FUNCTION__);
> +                             ais_rv = SA_AIS_ERR_NOT_EXIST;
> +                             goto snd_rsp;
> +                     }
>               }
>  
>               /* Create the stream: 
>                *  - Check parameters
>                *  - Create the stream in the stream "data base"
>                *  - If active create IMM runtime object
> +              *  - If recover do not create IMM object
>                * 
>                * Note: Files are not created here
>                */
> -             ais_rv = create_new_app_stream(open_sync_param, &logStream);
> -             if (ais_rv != SA_AIS_OK)
> +             ais_rv = create_new_app_stream(open_sync_param, &logStream, 1);
> +             if (ais_rv != SA_AIS_OK) {
> +                     TRACE("%s create_new_app_stream Fail \"%s\"",
> +                             __FUNCTION__, saf_error(ais_rv));
>                       goto snd_rsp;
> +             }
>       }
>  
>       /* Create the log files:
> @@ -1030,7 +1074,7 @@ static uint32_t proc_stream_open_msg(lgs
>               goto snd_rsp;
>       }
>  
> -     TRACE_4("logStream->streamId = %u", logStream->streamId);
> +     TRACE_4("logStream->streamId = %u is created",
> logStream->streamId);
>       lstr_id = logStream->streamId;
>  
>   snd_rsp:
> diff --git a/osaf/services/saf/logsv/lgs/lgs_evt.h
> b/osaf/services/saf/logsv/lgs/lgs_evt.h
> --- a/osaf/services/saf/logsv/lgs/lgs_evt.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_evt.h
> @@ -77,4 +77,9 @@ extern uint32_t lgs_remove_lga_down_rec(
>  extern void lgs_send_write_log_ack(uint32_t client_id, SaInvocationT
> invocation, SaAisErrorT error, MDS_DEST mds_dest);
>  extern void lgs_free_write_log(const lgsv_write_log_async_req_t
> *param);
>  
> +SaAisErrorT create_new_app_stream(
> +             lgsv_stream_open_req_t *open_sync_param,
> +             log_stream_t **o_stream,
> +             int creationFlag);
> +
>  #endif   /*!LGS_EVT_H */
> diff --git a/osaf/services/saf/logsv/lgs/lgs_file.cc
> b/osaf/services/saf/logsv/lgs/lgs_file.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_file.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_file.cc
> @@ -184,6 +184,11 @@ static void *file_hndl_thread(void *nopa
>                               hndl_rc = 
> own_log_files_by_group_hdl(lgs_com_data.indata_ptr,
>                                               lgs_com_data.outdata_ptr, 
> lgs_com_data.outdata_size);
>                               break;
> +                     case LGSF_GET_FILE_PAR:
> +                             hndl_rc = 
> lgs_get_file_params_hdl(lgs_com_data.indata_ptr,
> +                                                               
> lgs_com_data.outdata_ptr,
> +                                                               
> lgs_com_data.outdata_size);
> +                             break;
>                       default:
>                               break;
>                       }
> diff --git a/osaf/services/saf/logsv/lgs/lgs_file.h
> b/osaf/services/saf/logsv/lgs/lgs_file.h
> --- a/osaf/services/saf/logsv/lgs/lgs_file.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_file.h
> @@ -43,6 +43,7 @@ typedef enum {
>       LGSF_CHECKPATH,
>       LGSF_CHECKDIR,
>       LGSF_OWN_LOGFILES,
> +     LGSF_GET_FILE_PAR,
>       LGSF_NOREQ
>  }lgsf_treq_t;
>  
> diff --git a/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> b/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_filehdl.cc
> @@ -23,7 +23,6 @@
>  #include <dirent.h>
>  #include <fcntl.h>
>  #include <sys/stat.h>
> -
>  #include <unistd.h>
>  
>  #include <logtrace.h>
> @@ -731,3 +730,426 @@ done_exit:
>       TRACE_LEAVE();
>       return rc;
>  }
> +
> +/*
> ****************************************************************************
> + * lgs_get_file_params_hdl() with help functions
> + *
> + * Find the file that was current log file before server down.
> + * Get file size
> + * Get last written record Id by reading the first characters of the
> last
> + * log record in the file
> + *
> + */
> +
> +/**
> + * Count the occurrences  of character <c> in a string
> + * Count from end of string and stop when lim <c> is found or
> + * beginning of string
> + *
> + * @param str[in] '\0' terminated string to count characters in
> + * @param c[in]   Character to count
> + * @param lim[in] Stop count when lim characters found
> + * @return number of occurrences
> + */
> +static int chr_cnt_b(char *str, char c, int lim)
> +{
> +     int cnt = 0;
> +
> +     if ((str == NULL) || (*str == '\0')) {
> +             TRACE("%s: Parameter error", __FUNCTION__);
> +             return 0;
> +     }
> +
> +     char *ptr_str_end = strchr(str, '\0');
> +     char *ptr_str_pos = ptr_str_end - 1;
> +
> +     while (1) {
> +             if (*ptr_str_pos == c)
> +                     cnt++;
> +
> +             /* End if beginning of file or char limit */
> +             if ((ptr_str_pos == str) || (cnt >= lim))
> +                     break;
> +
> +             ptr_str_pos--;
> +     }
> +
> +     return cnt;
> +}
> +
> +/**
> + * Filter function used by scandir.
> + * Find a current log file if it exist
> + * - name as in file_name_find[]
> + * - extension .log
> + * - two timestamps (other log files has four)
> + */
> +/* Filename prefix (no timestamps or extension */
> +static std::string file_name_find_g;
> +static int filter_logfile_name(const struct dirent *finfo)
> +{
> +     bool name_found = false, ext_found = false;
> +
> +     if (strstr(finfo->d_name, file_name_find_g.c_str()) != NULL)
> +             name_found = true;
> +     if (strstr(finfo->d_name, ".log") != NULL)
> +             ext_found = true;
> +
> +     return (int) (name_found && ext_found);
> +}
> +
> +/**
> + * Get name and size of log file containing the last record Id. Is
> current log
> + * file if not empty or last rotated if current log file is empty
> + * Also give name of current log file if exist
> + *
> + * @param filepath_i[in]    Path to log file directory
> + * @param filename_i[in]    Name prefix for file to search for
> + * @param filename_o[out]   Name of file with Id. "" if no file
> found
> + * @param curname_o[out]    Name of current log  file or "" if no
> current found
> + * @param fsize[out]        Size of current log file
> + * @return -1 on error filename_o is not valid
> + */
> +static int filename_get(
> +     char *filepath_i, char *filename_i,
> +     std::string &filename_o, std::string &curname_o,
> +     uint32_t *fsize)
> +{
> +     int rc = 0;
> +     int num_files = 0;
> +     int i = 0;
> +     struct dirent **namelist;
> +     struct stat statbuf;
> +     std::string file_path;
> +     double time_tmp;
> +     char *str_p = NULL;
> +     int len = 0;
> +     /* Time newest file */
> +     double time_new = 0;
> +     /* Index in namelist for newest and second newest file */
> +     int name_ix_prv = 0, name_ix_new = 0;
> +     /* Set to true if file is empty */
> +     bool empty_flg_prv = true, empty_flg_new = true;
> +
> +     TRACE_ENTER();
> +
> +     // /* Initiate out data */
> +     filename_o.clear();
> +     curname_o.clear();
> +     *fsize = 0;
> +
> +     /* Create a list of all .log files that has
> +      * <filename_i> in <filepath_i>
> +      */
> +     file_name_find_g = filename_i;
> +     num_files = scandir(filepath_i, &namelist, filter_logfile_name,
> alphasort);
> +     if (num_files == -1) {
> +             TRACE("%s: scandir Fail %s", __FUNCTION__, strerror(errno));
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     if (num_files == 0) {
> +             /* There is no log file at all */
> +             TRACE("\t No log file at all found");
> +             goto done_free;
> +     }
> +
> +     /* Special case, only one file is found
> +      */
> +     if (num_files == 1) {
> +             file_path = std::string(filepath_i) + "/" + namelist[0]->d_name;
> +             if (stat(file_path.c_str(), &statbuf) == -1) {
> +                     TRACE("%s: stat() Fail %s", __FUNCTION__, 
> strerror(errno));
> +                     rc = -1;
> +                     goto done_free;
> +             }
> +
> +             /* Save found file name */
> +             filename_o = namelist[0]->d_name;
> +
> +             /* Handle current log file output */
> +             goto done_hdl_cur;
> +     }
> +
> +     /* Find the newest and the second newest file in the list
> +      * Return in filename_o name of newest file if not empty else
> +      * the second newest (if that also is empty return error)
> +      */
> +     time_new = time_tmp = 0;
> +     name_ix_prv = name_ix_new = 0;
> +     empty_flg_prv = empty_flg_new = false;
> +
> +     for (i = 0; i < num_files; i++) {
> +             file_path = std::string(filepath_i) + "/" + namelist[i]->d_name;
> +             if (stat(file_path.c_str(), &statbuf) == -1) {
> +                     TRACE("%s: stat() Fail %s", __FUNCTION__, 
> strerror(errno));
> +                     rc = -1;
> +                     goto done_free;
> +             }
> +
> +             time_tmp = osaf_timespec_to_double(&statbuf.st_mtim);
> +             if (time_tmp > time_new) {
> +                     name_ix_prv = name_ix_new;
> +                     name_ix_new = i;
> +                     time_new = time_tmp;
> +                     empty_flg_prv = empty_flg_new;
> +                     if (statbuf.st_size == 0)
> +                             empty_flg_new = true;
> +                     else
> +                             empty_flg_new = false;
> +             }
> +     }
> +
> +     /* Give found filename for output */
> +     *fsize = 0;
> +     if (empty_flg_new == false) {
> +             /* Give the newest filename and its size. File is not empty */
> +             filename_o = namelist[name_ix_new]->d_name;
> +             *fsize = statbuf.st_size;
> +     } else if (empty_flg_prv == false) {
> +             /* Give the second newest filename. File is not empty */
> +             filename_o = namelist[name_ix_prv]->d_name;
> +     } else {
> +             /* Both files are empty. This is an error */
> +             TRACE("%s: Both newest and second newest are empy", 
> __FUNCTION__);
> +             filename_o.clear();
> +             rc = -1;
> +     }
> +
> +done_hdl_cur:
> +     /* Handle current log file output */
> +     len = strlen(filename_i);
> +     str_p = namelist[name_ix_new]->d_name + len;
> +     if (chr_cnt_b(str_p, '_', 4) == 2) {
> +             /* Newest is current log file */
> +             curname_o = namelist[name_ix_new]->d_name;
> +     }
> +
> +done_free:
> +     /* Free namelist */
> +     for (i = 0; i < num_files; i++) {
> +             free(namelist[i]);
> +     }
> +
> +     free(namelist);
> +
> +done:
> +     TRACE_LEAVE();
> +     return rc;
> +}
> +
> +/**
> + * Get last record Id from the given file.
> + * Each record begins with a record Id number. The wanted Id is the
> last Id
> + * in the file
> + *
> + * @param file_name[in] Complete path to the file
> + * @return record Id or -1 on error. Set to 0 if no error but no Id
> is found
> + */
> +static int record_id_get(const char *file_path)
> +{
> +     FILE *fd = NULL;
> +     int id_rc = 0;
> +     int i;
> +     int c;
> +     long endpos;
> +
> +     char *read_line = NULL;
> +     size_t dummy_n = 0;
> +     ssize_t line_len;
> +
> +     TRACE_ENTER();
> +
> +     /* Open the file */
> +     while (1) {
> +             fd = fopen(file_path, "r");
> +             if (fd != NULL) {
> +                     break;
> +             } else if (errno != EINTR){
> +                     TRACE("%s fopen Fail %s",
> +                             __FUNCTION__, strerror(errno));
> +                     id_rc = -1;
> +                     goto done;
> +             }
> +     }
> +
> +     /* Get last pos in file */
> +     while(1) {
> +             if (fseek(fd, 0, SEEK_END) == -1) {
> +                     if (errno == EINTR)
> +                             continue;
> +                     TRACE("\t %d fseek Fail %s",__LINE__, strerror(errno));
> +                     id_rc = -1;
> +                     goto done;
> +             }
> +             break;
> +     }
> +     endpos = ftell(fd);
> +
> +     if (endpos == 0) {
> +             /* The file is empty. No Id to find */
> +             id_rc = 0;
> +             goto done;
> +     }
> +
> +     /* Search from the end for '\n' (end of prev record)
> +      * or beginning of file
> +      */
> +     for (i = 2; i < endpos; i++) {
> +             while(1) {
> +                     if (fseek(fd, -i, SEEK_END) == -1) {
> +                             if (errno == EINTR)
> +                                     continue;
> +                             TRACE("\t %d fseek Fail %s",
> +                                     __LINE__, strerror(errno));
> +                             id_rc = -1;
> +                             goto done;
> +                     }
> +                     break;
> +             }
> +
> +             c = getc(fd);
> +             if (c == '\n')
> +                     break;
> +     }
> +
> +     /* Get pos for line start */
> +     c = getc(fd); /* Dummy read '\n' */
> +
> +     /* Read the last record and get record id */
> +     line_len = getline(&read_line, &dummy_n, fd);
> +     if (line_len == -1) {
> +             TRACE("%s: getline Fail %s",
> +                     __FUNCTION__, strerror(errno));
> +             id_rc = -1;
> +             goto done;
> +     }
> +     id_rc = atoi(read_line);
> +     if (id_rc == 0) {
> +             TRACE("%s: \"%s\" has no number. Id set to 0",
> +                     __FUNCTION__, read_line);
> +             id_rc = 0;
> +             goto done_free;
> +     }
> +
> +done_free:
> +     free(read_line);
> +
> +done:
> +     if (fd != NULL)
> +             fclose(fd);
> +
> +     TRACE_LEAVE();
> +     return id_rc;
> +}
> +
> +/**
> + * Get log file information:
> + * - Name of current log file: <name prefix>_YYMMDD_HHMMSS
> + * - Log record id
> + *
> + * Rules:
> + * - If current log file not empty: Name = cur log file, Size = file
> size,
> + *                                  Id = fr file, rc = OK
> + * - If current log file empty no rotated: Name = cur log file, Size
> = 0,
> + *                                         Id = 1, rc = OK
> + * - If current log file empty is rotated: Name = cur log file, Size
> = 0,
> + *                                         Id = fr last rotated, rc =
> OK
> + * - If no log file at all:  Name = NULL, Size = 0, Id = 1, rc = OK
> + * - If only rotated log file: Name = NULL, Size = 0, Id = fr rotated
> file,
> + *                             rc = OK
> + *
> + * @param indata[in]      gfp_in_t
> + *        file_name: File name prefix (name part before time stamps)
> + *        file_path: Full path to directory root path + rel path
> + *
> + * @param outdata[out]    gfp_out_t
> + *        curFileName: Current file name <name prefix>_YYMMDD_HHMMSS
> + *        curFileSize: Bytes written to current log file (file size)
> + *        logRecordId: log record identifier for last written log
> record
> +
> + * @param max_outsize[in] sizeof gfp_out_t (not used)
> + *
> + * @return (-1) on error, out data not valid
> + */
> +int lgs_get_file_params_hdl(void *indata, void *outdata, size_t
> max_outsize)
> +{
> +     gfp_in_t *par_in = static_cast<gfp_in_t *>(indata);
> +     gfp_out_t *par_out = static_cast<gfp_out_t *>(outdata);
> +     int rc = 0, int_rc = 0;
> +     std::string file_name;
> +     std::string file_name_cur;
> +     std::string file_path;
> +     int rec_id = 0;
> +     char *ptr_str;
> +
> +     uint32_t file_size = 0;
> +
> +     TRACE_ENTER();
> +
> +     osaf_mutex_unlock_ordie(&lgs_ftcom_mutex); /* UNLOCK  Critical
> section */
> +
> +     /* Initialize out parameters */
> +     par_out->curFileName = NULL;
> +     par_out->curFileSize = 0;
> +     par_out->logRecordId = 0;
> +
> +     /* Get log file to get info from and its size */
> +     int_rc = filename_get(
> +             par_in->file_path, par_in->file_name,
> +             file_name, file_name_cur, &file_size
> +             );
> +     if (int_rc == -1) {
> +             TRACE("%s: filename_get Fail",__FUNCTION__);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     if (file_name[0] == '\0') {
> +             TRACE("No file found.");
> +             rc = -1;
> +             par_out->logRecordId = 0;
> +             goto done;
> +     }
> +
> +     /* Create the file path */
> +     file_path = std::string(par_in->file_path) + "/" + file_name;
> +
> +     /* Find record id in file */
> +     rec_id = record_id_get(file_path.c_str());
> +     if (rec_id == -1) {
> +             TRACE("%s: record_id_get Fail", __FUNCTION__);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     /* Fill in out data */
> +     par_out->logRecordId = rec_id;
> +     par_out->curFileSize = file_size;
> +     if (file_name_cur.empty() == false) {
> +             // This memory will be deleted in log_stream_open_file_restore()
> +             // who wants to get the info from this memory -
> par_out->curFileName
> +             par_out->curFileName = static_cast<char *>(
> +                     calloc(1, file_name_cur.size() + 1));
> +             if (par_out->curFileName == NULL) {
> +                     LOG_ER("%s Failed to allocate memory", __FUNCTION__);
> +                     rc = -1;
> +                     goto done;
> +             }
> +
> +             strcpy(par_out->curFileName, file_name_cur.c_str());
> +             /* Remove extension */
> +             ptr_str = strstr(par_out->curFileName, ".log");
> +             if (ptr_str == NULL) {
> +                     TRACE("%s: Could not find .log extension Fail", 
> __FUNCTION__);
> +                     rc = -1;
> +             }
> +             *ptr_str = '\0';
> +     }
> +
> +done:
> +     osaf_mutex_lock_ordie(&lgs_ftcom_mutex); /* LOCK after critical
> section */
> +     TRACE_LEAVE2("rc = %d", rc);
> +     return rc;
> +}
> diff --git a/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> b/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> --- a/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_filehdl.h
> @@ -155,6 +155,26 @@ typedef struct {
>   * No out parameters
>   */
>  
> +/*
> + * lgs_get_file_params_hdl(...)
> + * Ret code -1 if error
> + */
> +/* IN params */
> +typedef struct {
> +     /* File name prefix (name part before time stamps) */
> +     char *file_name;
> +     /* Full path to directory root path + rel path */
> +     char *file_path;
> +} gfp_in_t;
> +
> +/* OUT params */
> +typedef struct {
> +     char *curFileName;
> +     uint32_t curFileSize;   /* Bytes written to current log file */
> +     uint32_t logRecordId;   /* log record identifier increased for each
> record */
> +} gfp_out_t;
> +
> +
>  int path_is_writeable_dir_hdl(void *indata, void *outdata, size_t
> max_outsize);
>  int check_path_exists_hdl(void *indata, void *outdata, size_t
> max_outsize);
>  int rename_file_hdl(void *indata, void *outdata, size_t
> max_outsize);
> @@ -166,6 +186,7 @@ int fileclose_hdl(void *indata, void *ou
>  int delete_file_hdl(void *indata, void *outdata, size_t
> max_outsize);
>  int get_number_of_log_files_hdl(void *indata, void *outdata, size_t
> max_outsize);
>  int own_log_files_by_group_hdl(void *indata, void *outdata, size_t
> max_outsize);
> +int lgs_get_file_params_hdl(void *indata, void *outdata, size_t
> max_outsize);
>  
>  #endif       /* LGS_FILEHDL_H */
>  
> diff --git a/osaf/services/saf/logsv/lgs/lgs_imm.cc
> b/osaf/services/saf/logsv/lgs/lgs_imm.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_imm.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_imm.cc
> @@ -42,6 +42,7 @@
>  #include "lgs.h"
>  #include "lgs_util.h"
>  #include "lgs_file.h"
> +#include "lgs_recov.h"
>  #include "lgs_config.h"
>  #include "saf_error.h"
>  
> @@ -2507,7 +2508,8 @@ done:
>   * @return SaAisErrorT
>   */
>  static SaAisErrorT stream_create_and_configure(const char *dn,
> -             log_stream_t **in_stream, int stream_id, SaImmAccessorHandleT
> accessorHandle)
> +             log_stream_t **in_stream, int stream_id,
> +             SaImmAccessorHandleT accessorHandle)
>  {
>       SaAisErrorT rc = SA_AIS_OK;
>       SaNameT objectName;
> @@ -2606,6 +2608,15 @@ static SaAisErrorT stream_create_and_con
>               } else if (!strcmp(attribute->attrName,
> "saLogStreamSeverityFilter")) {
>                       stream->severityFilter = *((SaUint32T *)value);
>                       TRACE("severityFilter: %u", stream->severityFilter);
> +             } else if (!strcmp(attribute->attrName,
> "saLogStreamCreationTimestamp")) {
> +                     if (attribute->attrValuesNumber != 0) {
> +                             /* Restore creation timestamp if exist
> +                              * Note: Creation timestamp in stream is set to
> +                              * current time which will be the value if no
> +                              * value found in object
> +                              */
> +                             stream->creationTimeStamp = 
> *(static_cast<SaTimeT *>(value));
> +                     }
>               }
>       }
>  
> @@ -2648,11 +2659,15 @@ static const SaImmOiCallbacksT_2 callbac
>   * IMM-OM interface and initialize the corresponding information
>   * in the LOG control block. Initialize the LOG IMM-OI
>   * interface. Become class implementer.
> + *
> + * @param immOiHandle[in]
> + * @return
>   */
> -SaAisErrorT lgs_imm_create_configStream(lgs_cb_t *cb)
> +SaAisErrorT lgs_imm_init_configStreams(lgs_cb_t *cb)
>  {
> -     SaAisErrorT rc = SA_AIS_OK;
> +     SaAisErrorT ais_rc = SA_AIS_OK;
>       SaAisErrorT om_rc;
> +     int int_rc = 0;
>       log_stream_t *stream;
>       SaImmHandleT omHandle;
>       SaImmAccessorHandleT accessorHandle;
> @@ -2685,9 +2700,13 @@ SaAisErrorT lgs_imm_create_configStream(
>                       &immSearchHandle)) == SA_AIS_OK) {
>  
>               while (immutil_saImmOmSearchNext_2(immSearchHandle, &objectName,
> &attributes) == SA_AIS_OK) {
> -                     if ((rc = stream_create_and_configure((char*) 
> objectName.value,
> -                                     &stream, streamId, accessorHandle)) != 
> SA_AIS_OK) {
> -                             LOG_ER("stream_create_and_configure failed %d", 
> rc);
> +                     /* Note: Here is creationTimeStamp and severityFilter 
> set
> +                      * Can be recovered if scAbseceAllowed
> +                      */
> +                     ais_rc = stream_create_and_configure((char*) 
> objectName.value,
> +                                     &stream, streamId, accessorHandle);
> +                     if (ais_rc != SA_AIS_OK) {
> +                             LOG_WA("stream_create_and_configure failed %d", 
> ais_rc);
>                               goto done;
>                       }
>                       streamId += 1;
> @@ -2709,12 +2728,35 @@ SaAisErrorT lgs_imm_create_configStream(
>  
>       stream = log_stream_getnext_by_name(NULL);
>       while (stream != NULL) {
> -             (void)immutil_update_one_rattr(cb->immOiHandle, stream->name,
> -                                           
> const_cast<SaImmAttrNameT>("saLogStreamCreationTimestamp"),
> -                                            SA_IMM_ATTR_SATIMET,
> -                                            &stream->creationTimeStamp);
> -
> -             log_stream_open_fileinit(stream);
> +             if (cb->scAbsenceAllowed != 0) {
> +                     /**
> +                      * This code to make LOG distinguish b/w headless and 
> cluster
> start-up/restarts
> +                      * 1) If data reading from IMM differs with default 
> ones, headless
> just occurs
> +                      * 2) If data reading from IMM equals to default ones, 
> continue
> checking:
> +                      *  2.1) If info in cfg file are equal to data reading 
> from IMM,
> can reuse the cfg/log files
> +                      *  2.2) If info in cfg are not equal to, can not 
> re-use cfg/log
> file. Creating new ones instead.
> +                      */
> +                     int_rc = log_stream_open_file_restore(stream);
> +                     if (int_rc == -1) {
> +                             /* Restore failed. Initialize instead */
> +                             LOG_NO("%s: log_stream_open_file_restore Fail", 
> __FUNCTION__);
> +                             log_stream_open_fileinit(stream);
> +                             stream->creationTimeStamp = lgs_get_SaTime();
> +                     }
> +             } else {
> +                     /* Always create new files and set current timestamp to
> +                      * current time
> +                      */
> +                     log_stream_open_fileinit(stream);
> +                     stream->creationTimeStamp = lgs_get_SaTime();
> +             }
> +
> +             (void)immutil_update_one_rattr(
> +                     cb->immOiHandle, stream->name,
> +                     
> const_cast<SaImmAttrNameT>("saLogStreamCreationTimestamp"),
> +                     SA_IMM_ATTR_SATIMET,
> +                     &stream->creationTimeStamp);
> +
>               stream = log_stream_getnext_by_name(stream->name);
>       }
>  
> @@ -2740,7 +2782,7 @@ SaAisErrorT lgs_imm_create_configStream(
>       immutilWrapperProfile.errorsAreFatal = errorsAreFatal; /* Enable
> again */
>  
>       TRACE_LEAVE();
> -     return rc;
> +     return ais_rc;
>  }
>  
>  /**
> @@ -2951,3 +2993,476 @@ void lgs_imm_impl_reinit_nonblocking(lgs
>  
>       TRACE_LEAVE();
>  }
> +
> +/******************************************************************************
> + * Functions used for recovery handling
> +
> ******************************************************************************/
> +/**
> + * Search for old runtime stream objects and put their names in a
> list.
> + * Become OI for the runtime stream class if any objects found
> + *
> + * @param object_list
> + */
> +void lgs_search_stream_objects(void)
> +{
> +     int rc = 0;
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +     SaImmHandleT immOmHandle;
> +     SaImmSearchHandleT immSearchHandle;
> +     const char* class_name = "SaLogStream";
> +
> +     TRACE_ENTER();
> +
> +     /* Save immutil settings and reconfigure immutil
> +      */
> +     struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> +     tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> +     tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> +     tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> +     immutilWrapperProfile.errorsAreFatal = 0;
> +     immutilWrapperProfile.nTries = 500;
> +     immutilWrapperProfile.retryInterval = 1000;
> +
> +
> +     /* Intialize Om API
> +      */
> +     ais_rc = immutil_saImmOmInitialize(&immOmHandle, NULL,
> &immVersion);
> +     if (ais_rc != SA_AIS_OK) {
> +             LOG_WA("%s saImmOmInitialize FAIL %d", __FUNCTION__, ais_rc);
> +             goto done;
> +     }
> +
> +     /* Initialize search for application stream runtime objects
> +      * Search for all objects of class 'SaLogStream'
> +      * Search criteria:
> +      * Attribute SaImmAttrClassName == SaLogStream
> +      */
> +     SaImmSearchParametersT_2 searchParam;
> +     searchParam.searchOneAttr.attrName = const_cast<char
> *>("SaImmAttrClassName");
> +     searchParam.searchOneAttr.attrValueType = SA_IMM_ATTR_SASTRINGT;
> +     searchParam.searchOneAttr.attrValue = &class_name;
> +     SaNameT root_name;
> +     root_name.value[0] = '\0';
> +     root_name.length = 1;
> +
> +     ais_rc = immutil_saImmOmSearchInitialize_2(
> +                     immOmHandle,
> +                     &root_name,
> +                     SA_IMM_SUBTREE,
> +                     SA_IMM_SEARCH_ONE_ATTR | SA_IMM_SEARCH_GET_NO_ATTR,
> +                     &searchParam,
> +                     NULL,
> +                     &immSearchHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             LOG_WA("%s saImmOmSearchInitialize FAIL %d", __FUNCTION__,
> ais_rc);
> +             goto done_fin_Om;
> +     }
> +
> +     /* Iterate the search and save objects in list until all objects
> found
> +      */
> +     SaNameT object_name;
> +     SaImmAttrValuesT_2 **attributes;
> +
> +     ais_rc = immutil_saImmOmSearchNext_2(immSearchHandle, &object_name,
> &attributes);
> +     if (ais_rc == SA_AIS_ERR_NOT_EXIST) {
> +             TRACE("\tNo objects found");
> +     }
> +
> +     while (ais_rc == SA_AIS_OK) {
> +             TRACE("\tFound object \"%s\"", reinterpret_cast<char
> *>(object_name.value));
> +             /* Add the string to the list
> +              */
> +             rc = log_rtobj_list_add(reinterpret_cast<char
> *>(object_name.value));
> +             if (rc == -1) {
> +                     TRACE("%s Could not add %s to list Fail",
> +                           __FUNCTION__, reinterpret_cast<char 
> *>(object_name.value));
> +             }
> +
> +             /* Get next object */
> +             ais_rc = immutil_saImmOmSearchNext_2(immSearchHandle,
> +                     &object_name, &attributes);
> +     }
> +     if (ais_rc == SA_AIS_ERR_NOT_EXIST) {
> +             TRACE("\tAll objects found OK");
> +     } else {
> +             LOG_WA("\t%s saImmOmSearchNext FAILED %d", __FUNCTION__, 
> ais_rc);
> +     }
> +
> +     /* Finalize the serach API
> +      */
> +     ais_rc = immutil_saImmOmSearchFinalize(immSearchHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("\tsaImmOmSearchFinalize FAIL %d", ais_rc);
> +     }
> +
> +done_fin_Om:
> +     /* Finalize the Om API
> +      */
> +     ais_rc = immutil_saImmOmFinalize(immOmHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("\tsaImmOmFinalize FAIL %d", ais_rc);
> +     }
> +
> +done:
> +     /* Restore immutil settings */
> +     immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> +     immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> +     immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> +     TRACE_LEAVE();
> +}
> +
> +void lgs_delete_one_stream_object(char *name_str)
> +{
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +     SaNameT object_name;
> +
> +     if (name_str == NULL) {
> +             TRACE("%s No object name given", __FUNCTION__);
> +             return;
> +     }
> +
> +     /* Save immutil settings and reconfigure */
> +     struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> +     tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> +     tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> +     tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> +     immutilWrapperProfile.errorsAreFatal = 0;
> +     immutilWrapperProfile.nTries = 500;
> +     immutilWrapperProfile.retryInterval = 1000;
> +
> +     /* Copy name to a SaNameT */
> +     (void) strncpy(reinterpret_cast<char *>(object_name.value),
> +                    name_str, SA_MAX_NAME_LENGTH);
> +     object_name.length = strlen(name_str) + 1;
> +
> +     /* and delete the object */
> +     ais_rc = immutil_saImmOiRtObjectDelete(lgs_cb->immOiHandle,
> &object_name);
> +     if (ais_rc == SA_AIS_OK) {
> +             TRACE("%s Object \"%s\" deleted", __FUNCTION__,
> +                   reinterpret_cast<char *>(object_name.value));
> +     } else {
> +             LOG_WA("%s saImmOiRtObjectDelete for \"%s\" FAILED %d",
> +                    __FUNCTION__, reinterpret_cast<char 
> *>(object_name.value),
> ais_rc);
> +     }
> +
> +     /* Restore immutil settings */
> +     immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> +     immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> +     immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +}
> +
> +/**
> + * Delete all stream objects in the stream object list.
> + * See also: lgs_search_stream_objects()
> + *
> + */
> +void lgs_clean_stream_objects(void)
> +{
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +     int pos = 0;
> +     char *name_str;
> +     SaNameT object_name;
> +
> +     TRACE_ENTER();
> +     /* Check if there are any objects to delete. If not do nothing  */
> +     if (log_rtobj_list_no() <= 0) {
> +             TRACE("%s\t No objects to delete is found", __FUNCTION__);
> +             return;
> +     }
> +
> +     /* Save immutil settings and reconfigure */
> +     struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> +     tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> +     tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> +     tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> +     immutilWrapperProfile.errorsAreFatal = 0;
> +     immutilWrapperProfile.nTries = 500;
> +     immutilWrapperProfile.retryInterval = 1000;
> +
> +     pos = log_rtobj_list_getnamepos();
> +     while (pos != -1) {
> +             /* Get found name */
> +             name_str = log_rtobj_list_getname(pos);
> +
> +             /* Delete the object if in object list. Note this is an Oi
> operation
> +              * Remove name from list
> +              */
> +             if (name_str != NULL) {
> +                     /* Copy name to a SaNameT */
> +                     (void) strncpy(reinterpret_cast<char 
> *>(object_name.value),
> +                                    name_str, SA_MAX_NAME_LENGTH);
> +                     object_name.length = strlen(name_str) + 1;
> +                     /* and delete the object */
> +                     ais_rc = 
> immutil_saImmOiRtObjectDelete(lgs_cb->immOiHandle,
> +                             &object_name);
> +                     if (ais_rc == SA_AIS_OK) {
> +                             TRACE("\tObject \"%s\" deleted",
> +                                   reinterpret_cast<char 
> *>(object_name.value));
> +                     } else {
> +                             LOG_WA("%s saImmOiRtObjectDelete for \"%s\" 
> FAILED %d",
> +                                    __FUNCTION__,
> +                                    reinterpret_cast<char 
> *>(object_name.value), ais_rc);
> +                     }
> +             } else {
> +                     /* Should never happen! */
> +                     TRACE("%s\tFound name has NULL pointer!", __FUNCTION__);
> +             }
> +             /* Remove deleted object name from list */
> +             log_rtobj_list_erase_one_pos(pos);
> +
> +             /* Get next object */
> +             pos = log_rtobj_list_getnamepos();
> +     }
> +
> +     /* Restore immutil settings */
> +     immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> +     immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> +     immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> +     TRACE_LEAVE();
> +}
> +
> +/**
> + * Get cached stream attributes for given object name
> + *
> + * @param attrib_out[out] Pointer to a NULL terminated
> SaImmAttrValuesT_2 vector
> + * @param object_name[in]  String containing the object name
> + * @param immOmHandle[out]
> + * @return -1 on error
> + */
> +int lgs_get_streamobj_attr(SaImmAttrValuesT_2 ***attrib_out, char
> *object_name_in,
> +     SaImmHandleT *immOmHandle)
> +{
> +     int rc = 0;
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +     SaImmAccessorHandleT accessorHandle;
> +     char *attribute_names[] = {
> +             const_cast<char *>("saLogStreamFileName"),
> +             const_cast<char *>("saLogStreamPathName"),
> +             const_cast<char *>("saLogStreamMaxLogFileSize"),
> +             const_cast<char *>("saLogStreamFixedLogRecordSize"),
> +             const_cast<char *>("saLogStreamHaProperty"),
> +             const_cast<char *>("saLogStreamLogFullAction"),
> +             const_cast<char *>("saLogStreamMaxFilesRotated"),
> +             const_cast<char *>("saLogStreamLogFileFormat"),
> +             const_cast<char *>("saLogStreamSeverityFilter"),
> +             const_cast<char *>("saLogStreamCreationTimestamp"),
> +             NULL
> +     };
> +
> +     TRACE_ENTER2("object_name_in \"%s\"", object_name_in);
> +
> +     SaNameT object_name;
> +
> +     /* Save immutil settings and reconfigure */
> +     struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> +     tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> +     tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> +     tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> +     immutilWrapperProfile.errorsAreFatal = 0;
> +     immutilWrapperProfile.nTries = 500;
> +     immutilWrapperProfile.retryInterval = 1000;
> +
> +     if (object_name_in == NULL) {
> +             TRACE("%s No object name given (NULL)", __FUNCTION__);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     /* Initialize Om API
> +      */
> +     ais_rc = immutil_saImmOmInitialize(immOmHandle, NULL, &immVersion);
> +     if (ais_rc != SA_AIS_OK) {
> +             LOG_WA("\t%s saImmOmInitialize FAIL %d", __FUNCTION__, ais_rc);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     /* Initialize accessor for reading attributes
> +      */
> +     ais_rc = immutil_saImmOmAccessorInitialize(*immOmHandle,
> &accessorHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("%s\t saImmOmAccessorInitialize Fail '%s'",
> +                     __FUNCTION__, saf_error(ais_rc));
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     strncpy(reinterpret_cast<char *>(object_name.value),
> +             object_name_in, SA_MAX_NAME_LENGTH);
> +     object_name.length = strlen(reinterpret_cast<char
> *>(object_name.value)) + 1;
> +
> +     ais_rc = immutil_saImmOmAccessorGet_2(accessorHandle, &object_name,
> +                     attribute_names, attrib_out);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("%s\t saImmOmAccessorGet_2 Fail '%s'",
> +                     __FUNCTION__, saf_error(ais_rc));
> +             rc = -1;
> +             goto done_fin_Om;
> +     } else {
> +             goto done;
> +     }
> +
> +done_fin_Om:
> +     /* Free resources if fail */
> +     ais_rc = immutil_saImmOmFinalize(*immOmHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("%s\t saImmOmFinalize Fail '%s'",
> +                     __FUNCTION__, saf_error(ais_rc));
> +     }
> +
> +done:
> +     /* Restore immutil settings */
> +     immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> +     immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> +     immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> +     TRACE_LEAVE();
> +     return rc;
> +}
> +
> +/**
> + * Free resources claimed when calling lgs_get_streamobj_attr()
> + *
> + * @param immHandle[in]
> + * @return -1 on error
> + */
> +int lgs_free_streamobj_attr(SaImmHandleT immOmHandle)
> +{
> +     int rc = 0;
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +
> +     TRACE_ENTER();
> +
> +     /* Save immutil settings and reconfigure */
> +     struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> +     tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> +     tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> +     tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> +     immutilWrapperProfile.errorsAreFatal = 0;
> +     immutilWrapperProfile.nTries = 500;
> +     immutilWrapperProfile.retryInterval = 1000;
> +
> +     ais_rc = immutil_saImmOmFinalize(immOmHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("%s\t saImmOmFinalize Fail '%s'",
> +                     __FUNCTION__, saf_error(ais_rc));
> +             rc = -1;
> +     }
> +
> +     /* Restore immutil settings */
> +     immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> +     immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> +     immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> +     TRACE_LEAVE();
> +     return rc;
> +}
> +
> +/**
> + * Read the scAbsenceAllowed attribute in
> + * opensafImm=opensafImm,safApp=safImmService object.
> + * No value means that "absence handling" is not allowed. For Log
> this means
> + * that no recovery shall be done.
> + *
> + * @param attr_val[out] Value read from scAbsenceAllowed attribute. 0
> = No value
> + * @return Pointer to attr_val if value is read. NULL if no value. If
> NULL the
> + *         value in attr_val is not valid
> + */
> +SaUint32T *lgs_get_scAbsenceAllowed_attr(SaUint32T *attr_val)
> +{
> +     SaUint32T *rc_attr_val = NULL;
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +     SaImmAccessorHandleT accessorHandle;
> +     SaImmHandleT immOmHandle;
> +     SaImmAttrValuesT_2 *attribute;
> +     SaImmAttrValuesT_2 **attributes;
> +
> +     TRACE_ENTER();
> +     char *attribute_names[] = {
> +             const_cast<char *>("scAbsenceAllowed"),
> +             NULL
> +     };
> +     char object_name_str[] =
> "opensafImm=opensafImm,safApp=safImmService";
> +
> +     SaNameT object_name;
> +     strncpy(reinterpret_cast<char *>(object_name.value),
> +             object_name_str, SA_MAX_NAME_LENGTH);
> +     object_name.length = strlen(reinterpret_cast<char
> *>(object_name.value)) + 1;
> +
> +     /* Default restore handling shall be disabled. Is enabled if the
> +      * scAbsenceAllowed attribute is not empty
> +      */
> +     *attr_val = 0;
> +
> +     /* Save immutil settings and reconfigure */
> +     struct ImmutilWrapperProfile tmp_immutilWrapperProfile;
> +     tmp_immutilWrapperProfile.errorsAreFatal =
> immutilWrapperProfile.errorsAreFatal;
> +     tmp_immutilWrapperProfile.nTries = immutilWrapperProfile.nTries;
> +     tmp_immutilWrapperProfile.retryInterval =
> immutilWrapperProfile.retryInterval;
> +
> +     immutilWrapperProfile.errorsAreFatal = 0;
> +     immutilWrapperProfile.nTries = 500;
> +     immutilWrapperProfile.retryInterval = 1000;
> +
> +     /* Initialize Om API
> +      */
> +     ais_rc = immutil_saImmOmInitialize(&immOmHandle, NULL,
> &immVersion);
> +     if (ais_rc != SA_AIS_OK) {
> +             LOG_WA("\t%s saImmOmInitialize FAIL %d", __FUNCTION__, ais_rc);
> +             goto done;
> +     }
> +
> +     /* Initialize accessor for reading attributes
> +      */
> +     ais_rc = immutil_saImmOmAccessorInitialize(immOmHandle,
> &accessorHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("%s\t saImmOmAccessorInitialize Fail '%s'",
> +                     __FUNCTION__, saf_error(ais_rc));
> +             goto done;
> +     }
> +
> +
> +     ais_rc = immutil_saImmOmAccessorGet_2(accessorHandle, &object_name,
> +                     attribute_names, &attributes);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("%s\t saImmOmAccessorGet_2 Fail '%s'",
> +                     __FUNCTION__, saf_error(ais_rc));
> +             goto done_fin_Om;
> +     }
> +
> +     void *value;
> +
> +     /* Handle the global scAbsenceAllowed_flag */
> +     attribute = attributes[0];
> +     TRACE("%s\t attrName \"%s\"", __FUNCTION__, attribute->attrName);
> +     if ((attribute != NULL) && (attribute->attrValuesNumber != 0)) {
> +             /* scAbsenceAllowed has value. Get the value */
> +             value = attribute->attrValues[0];
> +             *attr_val = *(static_cast<SaUint32T *>(value));
> +             rc_attr_val = attr_val;
> +     }
> +
> +done_fin_Om:
> +     /* Free Om resources */
> +     ais_rc = immutil_saImmOmFinalize(immOmHandle);
> +     if (ais_rc != SA_AIS_OK) {
> +             TRACE("%s\t saImmOmFinalize Fail '%s'",
> +                     __FUNCTION__, saf_error(ais_rc));
> +     }
> +
> +done:
> +     /* Restore immutil settings */
> +     immutilWrapperProfile.errorsAreFatal =
> tmp_immutilWrapperProfile.errorsAreFatal;
> +     immutilWrapperProfile.nTries = tmp_immutilWrapperProfile.nTries;
> +     immutilWrapperProfile.retryInterval =
> tmp_immutilWrapperProfile.retryInterval;
> +
> +     TRACE_LEAVE();
> +     return rc_attr_val;
> +}
> diff --git a/osaf/services/saf/logsv/lgs/lgs_main.cc
> b/osaf/services/saf/logsv/lgs/lgs_main.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_main.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_main.cc
> @@ -31,21 +31,26 @@
>  #include <daemon.h>
>  #include <nid_api.h>
>  #include <ncs_main_papi.h>
> +#include <osaf_time.h>
>  
>  #include "lgs.h"
>  #include "lgs_file.h"
>  #include "osaf_utility.h"
> +#include "lgs_recov.h"
>  
>  /*
> ========================================================================
>   *   DEFINITIONS
>   *
> ========================================================================
>   */
> -
> -#define FD_TERM 0
> -#define FD_AMF 1
> -#define FD_MBCSV 2
> -#define FD_MBX 3
> -#define FD_IMM 4             /* Must be the last in the fds array */
> +enum {
> +     FD_TERM = 0,
> +     FD_AMF,
> +     FD_MBCSV,
> +     FD_MBX,
> +     FD_CLTIMER,
> +     FD_IMM,         /* Must be the last in the fds array */
> +     FD_NUM
> +};
>  
>  #ifndef LOG_STREAM_LOW_LIMIT_PERCENT
>  #define LOG_STREAM_LOW_LIMIT_PERCENT 0.6 // default value for low is
> 60%
> @@ -62,6 +67,7 @@
>   */
>  
>  static lgs_cb_t _lgs_cb;
> +
>  lgs_cb_t *lgs_cb = &_lgs_cb;
>  SYSF_MBX lgs_mbx; /* LGS's mailbox */
>  
> @@ -83,8 +89,8 @@ uint32_t mbox_low[NCS_IPC_PRIORITY_MAX];
>   */
>  pthread_mutex_t lgs_mbox_init_mutex = PTHREAD_MUTEX_INITIALIZER;
>  
> -static struct pollfd fds[5];
> -static nfds_t nfds = 5;
> +static struct pollfd fds[FD_NUM];
> +static nfds_t nfds = FD_NUM;
>  static NCS_SEL_OBJ usr1_sel_obj;
>  
>  /**
> @@ -195,6 +201,69 @@ uint32_t lgs_configure_mailbox(void)
>  }
>  
>  /**
> + * Get OpenSAF global scAbsenceAllowed configuration
> + */
> +static void init_scAbsenceAllowed()
> +{
> +     SaUint32T scAbsenceAllowed_val = 0;
> +
> +     TRACE_ENTER();
> +
> +     if (lgs_get_scAbsenceAllowed_attr(&scAbsenceAllowed_val) != NULL) {
> +             TRACE("%s\t Got scAbsenceAllowed_val = %d", __FUNCTION__,
> +                     scAbsenceAllowed_val);
> +     }
> +
> +     lgs_cb->scAbsenceAllowed = scAbsenceAllowed_val;
> +
> +     TRACE_LEAVE();
> +}
> +
> +/**
> + * Initiate recovery handling.
> + * Note1: This must be done during init before any streams are
> created
> + * Note2: Recovery state timer is started in the main() function
> + *
> + * If absence is allowed configuration is set:
> + * - Create a list of recoverable streams
> + * - If list is not empty set recovery state to LGS_RECOVERY
> + */
> +static void init_recovery()
> +{
> +     int list_num = 0;
> +
> +     TRACE_ENTER();
> +
> +     /* Set default state */
> +     lgs_cb->lgs_recovery_state = LGS_NORMAL;
> +
> +     /* Get the value of the scAbsenceAllowed IMM attribute for
> configuring
> +      * SC node absence handling
> +      */
> +     init_scAbsenceAllowed();
> +
> +     if (lgs_cb->scAbsenceAllowed == 0) {
> +             TRACE("%s Absence is not allowded", __FUNCTION__);
> +             TRACE_LEAVE();
> +             return;
> +     }
> +
> +     /* Create a list of recoverable (IMM object exist) streams */
> +     lgs_search_stream_objects();
> +     list_num = log_rtobj_list_no();
> +
> +     TRACE("Number of runtime objects found = %d", list_num);
> +
> +     /* set recovery state if the list is not empty */
> +     if (list_num != 0) {
> +             /* There are objects in list */
> +             lgs_cb->lgs_recovery_state = LGS_RECOVERY;
> +     }
> +
> +     TRACE_LEAVE2();
> +}
> +
> +/**
>   * Initialize log
>   * 
>   * @return uns32
> @@ -254,6 +323,9 @@ static uint32_t log_initialize(void)
>               goto done;
>       }
>  
> +     /* Initiate "headless" recovery handling */
> +     init_recovery();
> +
>       /* Initialize configuration stream class
>        * Configuration must have been initialized
>        */
> @@ -324,7 +396,11 @@ static uint32_t log_initialize(void)
>               /* Create streams that has configuration objects and become
>                * class implementer for the SaLogStreamConfig class
>                */
> -             if (lgs_imm_create_configStream(lgs_cb) != SA_AIS_OK) {
> +
> +             /* Note1: lgs_cb->immOiHandle is set in lgs_imm_init()
> +              * Note2: lgs_cb->logsv_root_dir must be set
> +              */
> +             if (lgs_imm_init_configStreams(lgs_cb) != SA_AIS_OK) {
>                       LOG_ER("lgs_imm_create_configStream FAILED");
>                       rc = NCSCC_RC_FAILURE;
>                       goto done;
> @@ -362,6 +438,18 @@ int main(int argc, char *argv[])
>       uint32_t rc;
>       int term_fd;
>  
> +     /* File descriptor for timeout to delete not used stream runtime
> objects.
> +      * May exist after 'headless' state.
> +      */
> +     int cltimer_fd = -1;
> +
> +     /* Timeout time in seconds before clean up of runtime objects that
> may
> +      * still exist after a "headless" situation. After timeout recovery
> of
> +      * "lost" streams is no longer possible.
> +      */
> +     const time_t CLEAN_TIMEOUT = 600; /* 10 min */
> +     //const time_t CLEAN_TIMEOUT = 60; /* 1 min LLDTEST */
> +
>       daemonize(argc, argv);
>       
>       if (log_initialize() != NCSCC_RC_SUCCESS) {
> @@ -372,6 +460,13 @@ int main(int argc, char *argv[])
>       mbx_fd = ncs_ipc_get_sel_obj(&lgs_mbx);
>       daemon_sigterm_install(&term_fd);
>  
> +     if (log_rtobj_list_no() != 0) {
> +             /* Needed only if any "lost" objects are found
> +              * See log_initialize */
> +             cltimer_fd = lgs_init_timer(CLEAN_TIMEOUT);
> +             TRACE("%s Recovery timeout started", __FUNCTION__);
> +     }
> +
>       /* Set up all file descriptors to listen to */
>       fds[FD_TERM].fd = term_fd;
>       fds[FD_TERM].events = POLLIN;
> @@ -382,6 +477,8 @@ int main(int argc, char *argv[])
>       fds[FD_MBCSV].events = POLLIN;
>       fds[FD_MBX].fd = mbx_fd.rmv_obj;
>       fds[FD_MBX].events = POLLIN;
> +     fds[FD_CLTIMER].fd = cltimer_fd;
> +     fds[FD_CLTIMER].events = POLLIN;
>       fds[FD_IMM].fd = lgs_cb->immSelectionObject;
>       fds[FD_IMM].events = POLLIN;
>  
> @@ -440,6 +537,25 @@ int main(int argc, char *argv[])
>                       }
>               }
>  
> +             if (fds[FD_CLTIMER].revents & POLLIN) {
> +                     /* To avoid 'stray objects', after a timeout all runtime
> +                      * objects that has not been restored shall be deleted
> +                      */
> +                     TRACE("Recover state End. Clean objects");
> +
> +                     /* Close timer to free resources and stop timer poll */
> +                     lgs_close_timer(cltimer_fd);
> +                     fds[FD_CLTIMER].fd = -1;
> +
> +                     if (lgs_cb->ha_state == SA_AMF_HA_ACTIVE) {
> +                             /* Delete objects left if active */
> +                             lgs_clean_stream_objects();
> +                     }
> +
> +                     /* Remove the found objects list */
> +                     log_rtobj_list_free();
> +             }
> +
>               if (fds[FD_MBX].revents & POLLIN)
>                       lgs_process_mbx(&lgs_mbx);
>  
> diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> b/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc
> @@ -24,6 +24,7 @@
>  #include "lgs_mbcsv_v3.h"
>  #include "lgs_mbcsv_v2.h"
>  #include "lgs_mbcsv_v1.h"
> +#include "lgs_recov.h"
>  
>  /*
>  LGS_CKPT_DATA_HEADER
> @@ -1856,6 +1857,7 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t 
>  {
>       lgs_ckpt_stream_open_t *param;
>       log_stream_t *stream;
> +     int pos = 0;
>  
>       TRACE_ENTER();
>       
> @@ -1871,7 +1873,8 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t 
>       /* Check that client still exist */
>       if ((param->clientId != invalidClient) &&
>               (lgs_client_get_by_id(param->clientId) == NULL)) {
> -             LOG_WA("\tClient %u does not exist, failed to create stream 
> '%s'",
> param->clientId, param->logStreamName);
> +             LOG_WA("\tClient %u does not exist, failed to create stream 
> '%s'",
> +                        param->clientId, param->logStreamName);
>               goto done;
>       }
>  
> @@ -1890,7 +1893,7 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t 
>               strcpy((char *)name.value, param->logStreamName);
>               name.length = strlen(param->logStreamName);
>  
> -             stream = log_stream_new(&name,
> +             stream = log_stream_new_1(&name,
>                               param->logFile,
>                               param->logPath,
>                               param->maxFileSize,
> @@ -1901,11 +1904,12 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t 
>                               param->streamType,
>                               param->streamId,
>                               SA_FALSE,       // FIX sync or calculate?
> -                             param->logRecordId);
> +                             param->logRecordId,
> +                             0);
>  
>               if (stream == NULL) {
>                       /* Do not allow standby to get out of sync */
> -                     LOG_ER("%s - Failed to create stream '%s'",__FUNCTION__,
> +                     LOG_ER("%s - Failed to create stream '%s'", 
> __FUNCTION__,
>                                       param->logStreamName);
>                       goto done;
>               }
> @@ -1923,6 +1927,9 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t 
>        */
>       if (lgs_is_split_file_system()) {
>               if (stream->numOpeners <= 1) {
> +                     TRACE("%s: log_initiate_stream_files(%s)",
> +                               __FUNCTION__, stream->fileName.c_str());
> +
>                       log_initiate_stream_files(stream);
>               }
>       }
> @@ -1935,11 +1942,16 @@ uint32_t ckpt_proc_open_stream(lgs_cb_t 
>       if ((param->clientId != invalidClient) &&
>               lgs_client_stream_add(param->clientId, stream->streamId) != 0) {
>               /* Do not allow standby to get out of sync */
> -             LOG_ER("%s - Failed to add stream '%s' to client 
> %u",__FUNCTION__,
> +             LOG_ER("%s - Failed to add stream '%s' to client %u",
> __FUNCTION__,
>                               param->logStreamName, param->clientId);
>               lgs_exit("Could not add stream to client",
> SA_AMF_COMPONENT_RESTART);
>       }
>  
> +     /* Stream is opened  on standby. Remove from rtobj list if exist */
> +     pos = log_rtobj_list_find(param->logStreamName);
> +     if (pos != -1)
> +             log_rtobj_list_erase_one_pos(pos);
> +
>   done:
>       /* Free strings allocated by the EDU encoder */
>       lgs_free_edu_mem(param->logFile);
> diff --git a/osaf/services/saf/logsv/lgs/lgs_recov.cc
> b/osaf/services/saf/logsv/lgs/lgs_recov.cc
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/logsv/lgs/lgs_recov.cc
> @@ -0,0 +1,758 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF 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. This file and program are
> licensed
> + * under the GNU Lesser General Public License Version 2.1, February
> 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for
> full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#include "lgs_recov.h"
> +#include "lgs_file.h"
> +#include "lgs_filehdl.h"
> +
> +/***
> + * The following functions are used to handle a list of runtime
> stream objects
> + * (application streams with runtime objects) that may be found
> during start of
> + * the log server.
> + * The list consists of a vector of strings containing runtime stream
> object
> + * dn:s
> + */
> +
> +static char **rtobj_list = NULL;
> +static bool rtobj_list_init_f = false;
> +static uint32_t rtobj_cnt = 0; /* Number of object names in list */
> +static SaUint32T rtobj_list_len = 0; /* Also the length of the list
> */
> +
> +/**
> + * Initiate the list by allocating memory for a vector of pointers to
> strings
> + * (char *). The number of elements will be
> "logMaxApplicationStreams", see log
> + * configuration object.
> + *
> + * @return true if initiated (list exist)
> + */
> +static bool log_rtobj_list_init()
> +{
> +     TRACE_ENTER();
> +
> +     if (rtobj_list_init_f == true)
> +             goto done; /* Already initiated */
> +
> +     rtobj_list_len = *static_cast<const SaUint32T *>(
> +             lgs_cfg_get(LGS_IMM_LOG_MAX_APPLICATION_STREAMS));
> +
> +     rtobj_list = static_cast<char **>(calloc(rtobj_list_len, sizeof(char
> *)));
> +     if (rtobj_list != NULL) {
> +             rtobj_list_init_f = true;
> +     } else {
> +             TRACE("%s\tFail to alloc memory for rtobj_list", __FUNCTION__);
> +     }
> +
> +done:
> +     TRACE_LEAVE2("rtobj_list_init_f = %d", rtobj_list_init_f);
> +     return rtobj_list_init_f;
> +}
> +
> +/**
> + * Free an initialized rtobj list
> + *
> + */
> +void log_rtobj_list_free()
> +{
> +     TRACE_ENTER();
> +
> +     if (rtobj_list == NULL)
> +             return; /* No list to free */
> +
> +     /* Free positions in the list if needed */
> +     uint32_t pos;
> +     for (pos = 0; pos < rtobj_list_len; pos++) {
> +             if (rtobj_list[pos] != NULL)
> +                     free(rtobj_list[pos]);
> +     }
> +
> +     free(rtobj_list);
> +     rtobj_cnt = 0;
> +     rtobj_list_len = 0;
> +     rtobj_list = NULL;
> +
> +     TRACE_LEAVE();
> +}
> +
> +/**
> + * Add a dn name of an rt-object
> + *
> + * @param dn_str[in] '\0' terminated string containing a dn
> + * @return -1 on error
> + */
> +int log_rtobj_list_add(char *dn_str)
> +{
> +     char *str_ptr = NULL;
> +     size_t len = 0;
> +     int rc = 0;
> +
> +     TRACE_ENTER();
> +
> +     if (log_rtobj_list_init() == false) {
> +             TRACE("%s\trtobj_list not initiated!", __FUNCTION__);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     if (rtobj_cnt >= rtobj_list_len) {
> +             /* Should be impossible */
> +             LOG_WA("%s\trtobj_cnt >= maxApplicationStreams!",
> +                     __FUNCTION__);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     /* Save dn string */
> +     len = strlen(dn_str) + 1; /* Including '\0' */
> +     if (len > SA_MAX_NAME_LENGTH) {
> +             /* Should never happen */
> +             LOG_WA("%s\tToo long dn string!",__FUNCTION__);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     str_ptr = static_cast<char *>(calloc(1, len));
> +     if (str_ptr == NULL) {
> +             LOG_WA("%s\tcalloc Fail",__FUNCTION__);
> +             rc = -1;
> +             goto done;
> +     }
> +
> +     strcpy(str_ptr, dn_str);
> +
> +     /* Add dn to list */
> +     rtobj_list[rtobj_cnt] = str_ptr;
> +     rtobj_cnt++;
> +
> +     done:
> +     TRACE_LEAVE2("rc = %d", rc);
> +     return rc;
> +}
> +
> +/**
> + * Return number of names in list
> + *
> + * @return Number of names
> + */
> +int log_rtobj_list_no()
> +{
> +     return rtobj_cnt;
> +}
> +
> +/**
> + * Find pos of the given given name in list
> + *
> + * @param dn_str[in] '\0' terminated string with dn to find
> + * @return Position of found name or -1 if name not found
> + */
> +int log_rtobj_list_find(char *dn_str)
> +{
> +     uint32_t i = 0;
> +     int pos = -1;
> +
> +     TRACE_ENTER2("dn_str \"%s\"", dn_str);
> +
> +     if (rtobj_list == NULL) {
> +             TRACE("\t No rtobj_list exist");
> +             goto done;
> +     }
> +
> +     for (i = 0; i < rtobj_list_len; i++) {
> +             if (rtobj_list[i] == NULL)
> +                     continue;
> +             if (strcmp(rtobj_list[i], dn_str) == 0) {
> +                     /* Found! */
> +                     pos = (int) i;
> +                     break;
> +             }
> +     }
> +
> +done:
> +     TRACE_LEAVE2("pos = %d", pos);
> +     return pos;
> +}
> +
> +/**
> + * Get pos of first name found in list.
> + *
> + * @return Position of found name or -1 if no name found
> + */
> +int log_rtobj_list_getnamepos()
> +{
> +     uint32_t i = 0;
> +     int pos = -1;
> +
> +     for (i = 0; i < rtobj_list_len; i++) {
> +             if (rtobj_list[i] == NULL) {
> +                     continue;
> +             } else {
> +                     pos = static_cast<int>(i);
> +                     break;
> +             }
> +     }
> +
> +     return pos;
> +}
> +
> +/**
> + * Get name at given pos in list.
> + *
> + * @param pos[in] Position for name to get
> + * @return A pointer to the string in given pos.
> + *         If there is no string in pos or pos is outside the list
> + *         NULL is returned.
> + */
> +char *log_rtobj_list_getname(int pos)
> +{
> +     if (pos >= static_cast<int>(rtobj_list_len))
> +             return NULL;
> +
> +     return rtobj_list[pos];
> +}
> +
> +/**
> + * "Erase" dn name at pos in list
> + *
> + * @param pos[in] Position in list to erase
> + */
> +void log_rtobj_list_erase_one_pos(int pos)
> +{
> +     TRACE_ENTER2("pos = %d", pos);
> +     if (pos > static_cast<int>(rtobj_list_len)) {
> +             TRACE_LEAVE2("%s\tPosition %d outside list!", __FUNCTION__, 
> pos);
> +             return;
> +     }
> +
> +     if (rtobj_list[pos] == NULL) {
> +             TRACE_LEAVE2("%s\tNo string in pos %d", __FUNCTION__, pos);
> +             return;
> +     }
> +
> +     free(rtobj_list[pos]);
> +     rtobj_list[pos] = NULL;
> +
> +     if (rtobj_cnt > 0)
> +             rtobj_cnt--;
> +
> +     TRACE_LEAVE();
> +}
> +
> +/***
> + * Restore a lost runtime stream.
> + * Get attributes from given runtime object (if exists).
> + * Find the last open logfile. From the file get number of log
> records written
> + * and latest used log record id
> + * If fail delete the stream IMM object (if exist)
> + * Always delete the object name from the rtobj list
> + */
> +
> +/**
> + * Local help function
> + * Find the file that was current log file before server down.
> + * Get file size
> + * Get last written record Id by reading the first characters of the
> last
> + * log record in the file
> + *
> + * NOTE:
> + * All file handling must be done in the file thread
> + * See lgs_get_file_params_hdl() in lgs_filehdl.c
> + *
> + * @param fileName[in]   The name in saLogStreamFileName e.g. "app1"
> + * @param pathName[in]        Full path to the dir where the log file can
> be found
> + *                       root path + relative path
> + * @param logFileCurrent[out]
> + * @param curFileSize[out]
> + * @param logRecordId[out]
> + *
> + * @return -1 on error
> + */
> +//static int lgs_get_file_params_h(gfp_in_t *par_in, gfp_out_t
> *par_out)
> +static int lgs_get_file_params_h(gfp_in_t *par_in, gfp_out_t
> *par_out)
> +{
> +     lgsf_retcode_t api_rc;
> +     lgsf_apipar_t apipar;
> +     int rc = 0;
> +
> +     TRACE_ENTER();
> +
> +     /* Fill in API structure */
> +     apipar.req_code_in = LGSF_GET_FILE_PAR;
> +     apipar.data_in_size = sizeof(gfp_in_t);
> +     apipar.data_in = par_in;
> +     apipar.data_out_size = sizeof(gfp_out_t);
> +     apipar.data_out = par_out;
> +
> +     api_rc = log_file_api(&apipar);
> +     if (api_rc != LGSF_SUCESS) {
> +             TRACE("%s - API error %s", __FUNCTION__,
> +                   lgsf_retcode_str(api_rc));
> +             rc = -1;
> +     } else {
> +             rc = apipar.hdl_ret_code_out;
> +             TRACE("\t hdl_ret_code_out = %d", rc);
> +     }
> +
> +     TRACE_LEAVE();
> +     return rc;
> +}
> +
> +static void lgs_remove_stream(uint32_t client_id, log_stream_t
> *log_stream)
> +{
> +     TRACE_ENTER();
> +
> +     /* Remove the stream handle and
> +      * remove the stream resources
> +      */
> +       if (lgs_client_stream_rmv(client_id, log_stream->streamId) <
> 0) {
> +            TRACE("%s lgs_client_stream_rmv Fail", __FUNCTION__);
> +       }
> +
> +       log_free_stream_resources(log_stream);
> +
> +       log_stream = NULL;
> +
> +       TRACE_LEAVE();
> +}
> +
> +/**
> + * Restore parameters for a lost runtime (application) stream, create
> the
> + * stream in the local stream list and associate with a client.
> + * Remove the stream object name from the found objects list.
> + *
> + * @param stream_name[in]  The name of the stream
> + * @param client_id[in]    Client to recover stream for
> + * @param o_stream[out]    The recovered stream
> + *                         stream
> + * @return -1 on error
> + */
> +int lgs_restore_one_app_stream(
> +     char *stream_name, uint32_t client_id,
> +     log_stream_t **o_stream)
> +{
> +     int int_rc = 0;
> +     int rc_out = 0;
> +     SaAisErrorT ais_rc = SA_AIS_OK;
> +     SaImmHandleT immOmHandle;
> +     SaImmAttrValuesT_2 *attribute;
> +     SaImmAttrValuesT_2 **attributes;
> +     gfp_in_t par_in;
> +     gfp_out_t par_out;
> +     int list_pos;
> +     int n;
> +     int i = 0;
> +
> +     lgsv_stream_open_req_t open_stream_param;
> +     log_stream_t *log_stream = NULL;
> +     SaTimeT restored_creationTimeStamp = 0;
> +     SaUint32T restored_severityFilter = 0;
> +
> +     std::string fileName;
> +     std::string pathName;
> +
> +     // Make it safe for free
> +     par_out.curFileName = NULL;
> +
> +     TRACE_ENTER2("object_name \"%s\", client_id=%d", stream_name,
> client_id);
> +
> +     memset(&open_stream_param, 0, sizeof(open_stream_param));
> +
> +     /* Check and save stream file name */
> +     if (stream_name == NULL) {
> +             TRACE("%s: No object name <NULL>", __FUNCTION__);
> +             rc_out = -1;
> +             goto done;
> +     }
> +     n = snprintf(reinterpret_cast<char
> *>(open_stream_param.lstr_name.value),
> +             SA_MAX_NAME_LENGTH, "%s", stream_name);
> +
> +     open_stream_param.lstr_name.length = strlen(stream_name) + 1;
> +     if (n >= SA_MAX_NAME_LENGTH) {
> +             TRACE("Log stream name \"%s\" is truncated",
> +                     open_stream_param.lstr_name.value);
> +             rc_out = -1;
> +             goto done;
> +     }
> +
> +     /* Check if in found objects list */
> +     list_pos = log_rtobj_list_find(stream_name);
> +     if (list_pos == -1) {
> +             TRACE("%s: No stream \"%s\" found to restore", __FUNCTION__,
> stream_name);
> +             rc_out = -1;
> +             goto done;
> +     }
> +
> +     /* Remove from list */
> +     log_rtobj_list_erase_one_pos(list_pos);
> +
> +     /* Get the cached attributes for the object
> +      */
> +     int_rc = lgs_get_streamobj_attr(&attributes, stream_name,
> &immOmHandle);
> +     if (int_rc == -1) {
> +             TRACE("%s:\t lgs_get_streamobj_attr Fail", __FUNCTION__);
> +             rc_out = -1;
> +             goto done;
> +     }
> +
> +     /* Fill in the "lgsv_stream_open_req_t open_stream_param" struct
> with
> +      * recovered parameters, re-create the stream and add it to the
> client
> +      * Note: Before restoring a stream the client to own the stream
> must
> +      *       exist.
> +      */
> +     i = 0;
> +     while ((attribute = attributes[i++]) != NULL) {
> +             void *value;
> +             char *name;
> +             char *str_val;
> +
> +             /* Fill in parameters read from the app stream object
> +              */
> +             name = attribute->attrName;
> +             if (attribute->attrValuesNumber != 0)
> +                     value = attribute->attrValues[0];
> +             else {
> +                     value = NULL;
> +             }
> +
> +             TRACE("\t attribute name \"%s\"", name);
> +             if (!strcmp(name, "saLogStreamFileName")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +
> +                     fileName = *(static_cast<char **>(value));
> +                     TRACE("\t saLogStreamFileName \"%s\"", 
> fileName.c_str());
> +             } else if (!strcmp(name, "saLogStreamPathName")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +
> +                     pathName = *(static_cast<char **>(value));
> +                     TRACE("\t saLogStreamPathName \"%s\"", 
> pathName.c_str());
> +             } else if (!strcmp(name, "saLogStreamMaxLogFileSize")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +
> +                     open_stream_param.maxLogFileSize = 
> *(static_cast<SaUint64T
> *>(value));
> +                     TRACE("\t saLogStreamMaxLogFileSize = %lld",
> +                             open_stream_param.maxLogFileSize);
> +
> +             } else if (!strcmp(name, "saLogStreamFixedLogRecordSize")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     open_stream_param.maxLogRecordSize = 
> *(static_cast<SaUint32T
> *>(value));
> +                     TRACE("\t saLogStreamFixedLogRecordSize = %d",
> +                             open_stream_param.maxLogRecordSize);
> +
> +             } else if (!strcmp(name, "saLogStreamHaProperty")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     open_stream_param.haProperty = *(static_cast<SaBoolT 
> *>(value));
> +                     TRACE("\t saLogStreamHaProperty=%d",
> +                             open_stream_param.haProperty);
> +
> +             } else if (!strcmp(name, "saLogStreamLogFullAction")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     open_stream_param.logFileFullAction =
> *(static_cast<SaLogFileFullActionT *>(value));
> +                     TRACE("\t saLogStreamLogFullAction=%d",
> +                             open_stream_param.logFileFullAction);
> +
> +             } else if (!strcmp(name, "saLogStreamMaxFilesRotated")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     open_stream_param.maxFilesRotated = 
> *(static_cast<SaUint16T
> *>(value));
> +                     TRACE("\t saLogStreamMaxFilesRotated=%d",
> +                             open_stream_param.maxFilesRotated);
> +
> +             } else if (!strcmp(name, "saLogStreamLogFileFormat")) {
> +                     /*TBD Is this correct way of handling format?
> +                      * - Must be checked!
> +                      * - Use better max length than PATH_MAX!
> +                      */
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     str_val = *(static_cast<char **>(value));
> +                     open_stream_param.logFileFmt = NULL;
> +                     open_stream_param.logFileFmt = static_cast<char *>(
> +                             calloc(1, strlen(str_val) + 1));
> +                     if (open_stream_param.logFileFmt == NULL) {
> +                             TRACE("%s [%d] calloc Fail",
> +                                     __FUNCTION__, __LINE__);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     n = snprintf(open_stream_param.logFileFmt,
> +                             PATH_MAX, "%s", str_val);
> +                     open_stream_param.logFileFmtLength =
> +                             strlen(open_stream_param.logFileFmt);
> +                     if (n >= PATH_MAX) {
> +                             TRACE("Format string \"%s\" too long",
> +                                     str_val);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     TRACE("\t saLogStreamLogFileFormat \"%s\"",
> +                             open_stream_param.logFileFmt);
> +
> +             } else if (!strcmp(name, "saLogStreamCreationTimestamp")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     restored_creationTimeStamp = *(static_cast<SaTimeT 
> *>(value));
> +                     TRACE("\t saLogStreamCreationTimestamp=%lld",
> +                             restored_creationTimeStamp);
> +
> +             } else if (!strcmp(name, "saLogStreamSeverityFilter")) {
> +                     if (value == NULL) {
> +                             TRACE("%s: Fail, has empty value", name);
> +                             rc_out = -1;
> +                             goto done_free_attr;
> +                     }
> +                     restored_severityFilter = *(static_cast<SaUint32T 
> *>(value));
> +                     TRACE("\t saLogStreamSeverityFilter=%d",
> +                             restored_severityFilter);
> +             }
> +     }
> +
> +     /* Fill in the rest of the stream open parameters
> +      * and create the stream. Do not create an IMM object
> +      */
> +     open_stream_param.client_id = client_id;
> +     open_stream_param.lstr_open_flags = 0; /* Dummy not used here */
> +
> +     open_stream_param.logFileName = const_cast<char
> *>(fileName.c_str());
> +     open_stream_param.logFilePathName = const_cast<char
> *>(pathName.c_str());
> +
> +     ais_rc = create_new_app_stream(&open_stream_param, &log_stream, 0);
> +     if ( ais_rc != SA_AIS_OK) {
> +             TRACE("%s: create_new_app_stream Fail %s",
> +                     __FUNCTION__, saf_error(ais_rc));
> +             rc_out = -1;
> +             goto done_free_attr;
> +     }
> +
> +     /* Create an association between this client and the stream */
> +     int_rc = lgs_client_stream_add(client_id, log_stream->streamId);
> +     if (int_rc == -1) {
> +             TRACE("%s: lgs_client_stream_add Fail", __FUNCTION__);
> +             log_free_stream_resources(log_stream); /* Undo create new stream
> */
> +             rc_out = -1;
> +             goto done_free_attr;
> +     }
> +
> +     /* Set values for attributes not restored when creating a stream.
> +      * The value must be set after the stream is created.
> +      * Cached:
> +      * - saLogStreamSeverityFilter (cached)
> +      * - saLogStreamCreationTimestamp (cached)
> +      *
> +      * Pure runtime:
> +      * - saLogStreamNumOpeners
> +      *   Handled when streams are opened. No recovery needed
> +      * - logStreamDiscardedCounter
> +      *   Cannot be restored. Initialized with 0
> +      */
> +     log_stream->creationTimeStamp = restored_creationTimeStamp;
> +     log_stream->severityFilter = restored_severityFilter;
> +     log_stream->filtered = 0;
> +
> +     TRACE("\t Stream obj attributes handled and stream is created");
> +
> +     /* Get recovery data from the log file and update the stream
> +      */
> +     pathName = static_cast<const char *>(
> +             lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> +     pathName = pathName + "/" + open_stream_param.logFilePathName;
> +
> +     par_in.file_name = open_stream_param.logFileName;
> +     par_in.file_path = const_cast<char *>(pathName.c_str());
> +
> +     int_rc = lgs_get_file_params_h(&par_in, &par_out);
> +     if (int_rc == -1) {
> +             TRACE("%s:\t lgs_get_file_params_h Fail", __FUNCTION__);
> +              /* Remove the stream handle and
> +               * remove the stream resources
> +               */
> +             lgs_remove_stream(client_id, log_stream);
> +             rc_out = -1;
> +             goto done_free_attr;
> +     }
> +
> +     /* If no current log file create a file name
> +      */
> +     if (par_out.curFileName == NULL) {
> +             /* There is no current log file. Create a file name */
> +             log_stream->logFileCurrent = log_stream->fileName + "_" +
> lgs_get_time(NULL);
> +             TRACE("\t A new file name for current log file is created");
> +     } else {
> +             log_stream->logFileCurrent = par_out.curFileName;
> +     }
> +
> +     TRACE("\t Current log file \"%s\"",
> log_stream->logFileCurrent.c_str());
> +
> +     log_stream->curFileSize = par_out.curFileSize;
> +     log_stream->logRecordId = par_out.logRecordId;
> +
> +     /* The stream is open again and opened for the first time so far */
> +     log_stream->numOpeners = 1;
> +
> +     /* Set the stream file descriptor to -1. The file will then be
> opened
> +      * at next write.
> +      */
> +     *log_stream->p_fd = -1;
> +
> +done_free_attr:
> +     /* Free resources used for finding attribute values */
> +     int_rc = lgs_free_streamobj_attr(immOmHandle);
> +     if (int_rc == -1) {
> +             TRACE("%s:\t lgs_free_streamobj_attr Fail", __FUNCTION__);
> +             rc_out = -1;
> +     }
> +
> +done:
> +     free(open_stream_param.logFileFmt);
> +     if (par_out.curFileName != NULL) {
> +             // This memory is allocated in lgs_get_file_params_hdl()
> +             free(par_out.curFileName);
> +     }
> +
> +     /* Return recovered stream. Will be NULL if not recovered (rc_out =
> -1) */
> +     *o_stream = log_stream;
> +     TRACE_LEAVE2("rc_out = %d", rc_out);
> +     return rc_out;
> +}
> +
> +/**
> + * Restore lost files for a configuration stream.
> + * Update the stream with current log file and log record Id
> + *
> + *
> + * @param log_stream[in/out]
> + * Will/May modify the following stream parameters:
> + *   logFileCurrent
> + *   curFileSize
> + *   logRecordId
> + *   creationTimeStamp
> + *   *p_fd
> + *   numOpeners
> + *
> + * @return -1 on error
> + */
> +int log_stream_open_file_restore(log_stream_t *stream)
> +{
> +     int int_rc = 0;
> +     int rc_out = 0;
> +     gfp_in_t par_in;
> +     gfp_out_t par_out;
> +     std::string pathName, log_root_path;
> +     size_t name_length = lgs_max_nlength();
> +
> +     TRACE_ENTER();
> +
> +     pathName = static_cast<const char
> *>(lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> +     pathName = pathName + "/" + stream->pathName;
> +
> +     par_in.file_name = const_cast<char *>(stream->fileName.c_str());
> +     par_in.file_path = const_cast<char *>(pathName.c_str());
> +
> +     TRACE("pathName = %s, fileName = %s, name_length = %zu",
> +           pathName.c_str(), stream->fileName.c_str(), name_length);
> +
> +     // Initialize the output
> +     par_out.curFileSize = 0;
> +     par_out.logRecordId = 0;
> +     par_out.curFileName = NULL;
> +
> +     int_rc = lgs_get_file_params_h(&par_in, &par_out);
> +
> +     /****
> +      * Rules for lgs_get_file_params_h():
> +      * - If current log file not empty: Name = cur log file, Size = file
> size,
> +      *                                  Id = fr file, rc = OK
> +      * - If current log file empty no rotated: Name = cur log file, Size
> = 0,
> +      *                                         Id = 1, rc = OK
> +      * - If current log file empty is rotated: Name = cur log file, Size
> = 0,
> +      *                                         Id = fr last rotated, rc
> = OK
> +      * - If no log file at all:  Name = NULL, Size = 0, Id = 1, rc = OK
> +      * - If only rotated log file: Name = NULL, Size = 0, Id = fr
> rotated file,
> +      *                             rc = OK
> +      */
> +
> +     if (int_rc == -1) {
> +             /* No relevant file info found. Recovery fail */
> +             TRACE("%s: lgs_get_file_params_h Fail", __FUNCTION__);
> +             rc_out = -1;
> +             goto done;
> +     }
> +
> +     stream->logFileCurrent = par_out.curFileName;
> +     stream->curFileSize = par_out.curFileSize;
> +     stream->logRecordId = par_out.logRecordId;
> +
> +     TRACE("Out: curFileSize = %u, logRecordId = %u, logFileCurrent =
> %s",
> +           stream->curFileSize, stream->logRecordId,
> stream->logFileCurrent.c_str());
> +
> +     if (stream->numOpeners != 0) {
> +             TRACE("%s: numOpeners = %u Fail", __FUNCTION__,
> stream->numOpeners);
> +             rc_out = -1;
> +             goto done;
> +     }
> +
> +     int errno_save;
> +     log_root_path = static_cast<const char
> *>(lgs_cfg_get(LGS_IMM_LOG_ROOT_DIRECTORY));
> +     *stream->p_fd = -1;
> +
> +     if ((*stream->p_fd = log_file_open(log_root_path, stream,
> +                                        stream->logFileCurrent,
> +                                        &errno_save)) == -1) {
> +             TRACE("%s - Could not open '%s' - %s", __FUNCTION__,
> +                   stream->logFileCurrent.c_str(), strerror(errno_save));
> +     }
> +
> +     stream->numOpeners++;
> +
> +done:
> +     // This memory is allocated in lgs_get_file_params_hdl()
> +     if (par_out.curFileName != NULL)
> +             free(par_out.curFileName);
> +
> +     TRACE_LEAVE2("rc_out = %d", rc_out);
> +     return rc_out;
> +}
> diff --git a/osaf/services/saf/logsv/lgs/lgs_recov.h
> b/osaf/services/saf/logsv/lgs/lgs_recov.h
> new file mode 100644
> --- /dev/null
> +++ b/osaf/services/saf/logsv/lgs/lgs_recov.h
> @@ -0,0 +1,37 @@
> +/*      -*- OpenSAF  -*-
> + *
> + * (C) Copyright 2016 The OpenSAF 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. This file and program are
> licensed
> + * under the GNU Lesser General Public License Version 2.1, February
> 1999.
> + * The complete license can be accessed from the following location:
> + * http://opensource.org/licenses/lgpl-license.php
> + * See the Copying file included with the OpenSAF distribution for
> full
> + * licensing terms.
> + *
> + * Author(s): Ericsson AB
> + *
> + */
> +
> +#ifndef LGS_STATE_H
> +#define      LGS_STATE_H
> +
> +#include "lgs.h"
> +
> +int log_rtobj_list_add(char *dn_str);
> +int log_rtobj_list_no();
> +int log_rtobj_list_find(char *stream_name);
> +int log_rtobj_list_getnamepos();
> +char *log_rtobj_list_getname(int pos);
> +void log_rtobj_list_erase_one_pos(int pos);
> +void log_rtobj_list_free();
> +int lgs_restore_one_app_stream(
> +     char *stream_name,
> +     uint32_t client_id,
> +     log_stream_t **o_stream
> +     );
> +int log_stream_open_file_restore(log_stream_t *log_stream);
> +
> +#endif       /* LGS_STATE_H */
> diff --git a/osaf/services/saf/logsv/lgs/lgs_stream.cc
> b/osaf/services/saf/logsv/lgs/lgs_stream.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_stream.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_stream.cc
> @@ -409,6 +409,33 @@ void log_stream_print(log_stream_t *stre
>       TRACE_2("  filtered:             %llu", stream->filtered);
>  }
>  
> +/**
> + * Free stream resources
> + *
> + * @param stream[in]
> + */
> +void log_free_stream_resources(log_stream_t *stream)
> +{
> +     if (stream->streamId != 0)
> +             lgs_stream_array_remove(stream->streamId);
> +
> +     if (stream->pat_node.key_info != NULL)
> +             log_stream_remove(stream->name);
> +
> +     if (stream->logFileFormat != NULL)
> +             free(stream->logFileFormat);
> +
> +     delete stream;
> +     stream = NULL;
> +}
> +
> +/**
> + * Remove a log stream including:
> + * - Runtime object if application stream and active
> + * - Remove stream resources (allocated memory)
> + *
> + * @param s[in] Pointer to the array of streams
> + */
>  void log_stream_delete(log_stream_t **s)
>  {
>       log_stream_t *stream;
> @@ -469,6 +496,12 @@ static void init_log_stream_fd(log_strea
>   * Create a new stream object. If HA state active, create the
>   * correspronding IMM runtime object.
>   * 
> + * Note: log_stream_new() is replaced by this function.
> + *       The new function is doing the same as the old but the
> possibility
> + *       to create a stream without creating a corresponding runtime
> object
> + *       is added. See creationFlag parameter
> + *
> + * Stream attributes[in]:
>   * @param name
>   * @param filename
>   * @param pathname
> @@ -484,17 +517,21 @@ static void init_log_stream_fd(log_strea
>   * 
>   * @return log_stream_t*
>   */
> -log_stream_t *log_stream_new(SaNameT *dn,
> -                              const std::string &filename,
> -                              const std::string &pathname,
> -                          SaUint64T maxLogFileSize,
> -                          SaUint32T fixedLogRecordSize,
> -                          SaLogFileFullActionT logFullAction,
> -                          SaUint32T maxFilesRotated,
> -                          const char *logFileFormat,
> -                          logStreamTypeT streamType, int stream_id,
> -                              SaBoolT twelveHourModeFlag,
> -                              uint32_t logRecordId)
> +log_stream_t *log_stream_new_1(
> +     SaNameT *dn,
> +     const std::string &filename,
> +     const std::string &pathname,
> +     SaUint64T maxLogFileSize,
> +     SaUint32T fixedLogRecordSize,
> +     SaLogFileFullActionT logFullAction,
> +     SaUint32T maxFilesRotated,
> +     const char *logFileFormat,
> +     logStreamTypeT streamType,
> +     int stream_id,
> +     SaBoolT twelveHourModeFlag,
> +     uint32_t logRecordId,
> +     int creationFlag
> +     )
>  {
>       int rc;
>       log_stream_t *stream = NULL;
> @@ -690,10 +727,10 @@ log_stream_t *log_stream_new(SaNameT *dn
>  }
>  
>  /**
> - * Create a new stream object. Do not create an IMM runtime object.
> + * Create a new default stream. Do not create an IMM runtime object.
>   * @param name
>   * @param stream_id
> - * 
> + *
>   * @return log_stream_t*
>   */
>  log_stream_t *log_stream_new_2(SaNameT *name, int stream_id)
> @@ -704,7 +741,7 @@ log_stream_t *log_stream_new_2(SaNameT *
>       osafassert(name != NULL);
>       TRACE_ENTER2("%s, l: %u", name->value, (unsigned int)name->length);
>  
> -     stream = new (std::nothrow) (log_stream_t)();
> +     stream = new (std::nothrow) log_stream_t();
>       if (stream == NULL) {
>               LOG_WA("calloc FAILED");
>               goto done;
> diff --git a/osaf/services/saf/logsv/lgs/lgs_stream.h
> b/osaf/services/saf/logsv/lgs/lgs_stream.h
> --- a/osaf/services/saf/logsv/lgs/lgs_stream.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_stream.h
> @@ -79,18 +79,21 @@ extern uint32_t log_stream_init();
>  extern void log_stream_delete(log_stream_t **s);
>  
>  #define STREAM_NEW -1
> -extern log_stream_t *log_stream_new(SaNameT *name,
> -                                 const std::string &filename,
> -                                 const std::string &pathname,
> -                                 SaUint64T maxLogFileSize,
> -                                 SaUint32T fixedLogRecordSize,
> -                                 SaLogFileFullActionT logFullAction,
> -                                 SaUint32T maxFilesRotated,
> -                                 const char *logFileFormat,
> -                                 logStreamTypeT streamType,
> -                                 int stream_id,
> -                                 SaBoolT twelveHourModeFlag,
> -                                 uint32_t logRecordId);
> +extern log_stream_t *log_stream_new_1(
> +     SaNameT *name,
> +     const std::string &filename,
> +     const std::string &pathname,
> +     SaUint64T maxLogFileSize,
> +     SaUint32T fixedLogRecordSize,
> +     SaLogFileFullActionT logFullAction,
> +     SaUint32T maxFilesRotated,
> +     const char *logFileFormat,
> +     logStreamTypeT streamType,
> +     int stream_id,
> +     SaBoolT twelveHourModeFlag,
> +     uint32_t logRecordId,
> +     int creationFlag
> +     );
>  
>  extern log_stream_t *log_stream_new_2(SaNameT *name, int stream_id);
>  
> @@ -118,5 +121,6 @@ extern log_stream_t *log_stream_get_by_n
>  extern log_stream_t *log_stream_getnext_by_name(const char *name);
>  extern void log_stream_print(log_stream_t *stream);
>  extern log_stream_t *log_stream_get_by_id(uint32_t id);
> +void log_free_stream_resources(log_stream_t *stream);
>  
>  #endif
> diff --git a/osaf/services/saf/logsv/lgs/lgs_util.cc
> b/osaf/services/saf/logsv/lgs/lgs_util.cc
> --- a/osaf/services/saf/logsv/lgs/lgs_util.cc
> +++ b/osaf/services/saf/logsv/lgs/lgs_util.cc
> @@ -30,12 +30,13 @@
>  
>  #include <stdlib.h>
>  #include <grp.h>
> +#include <osaf_time.h>
>  
>  #include "immutil.h"
>  #include "lgs.h"
>  #include "lgs_file.h"
>  #include "lgs_filehdl.h"
> -#include "osaf_time.h"
> +#include "osaf_timerfd.h"
>  
>  #define ALARM_STREAM_ENV_PREFIX "ALARM"
>  #define NOTIFICATION_STREAM_ENV_PREFIX "NOTIFICATION"
> @@ -239,14 +240,14 @@ SaTimeT lgs_get_SaTime()
>   * @param root_path[in]
>   * @param rel_path[in]
>   * @param old_name[in]
> - * @param time_stamp[in] 
> + * @param time_stamp[in]
>   *        Can be set to NULL but then new_name must be the complete
> new name
>   *        including time stamps but without suffix
>   * @param suffix[in]
> - * @param new_name[in/out] 
> - *        Pointer to char string of NAME_MAX size
> + * @param new_name[in/out]
> + *        Pointer to char string
>   *        Filename of renamed file. Can be set to NULL
> - * 
> + *
>   * @return -1 if error
>   */
>  int lgs_file_rename_h(
> @@ -638,6 +639,45 @@ done:
>  }
>  
>  /**
> + * Initiate a timer:
> + * Creates a timeout timer, set timeout time and starts the timer
> + * returns a file descriptor to the timer that can be used with
> poll()
> + * See also osaf_timerfd.h
> + *
> + * @param timeout_s[in] Timeout time in seconds
> + * @return fd  File descriptor referring to the created timer
> + */
> +int lgs_init_timer(time_t timeout_s)
> +{
> +     int fd;
> +     struct itimerspec lgs_cltimer;
> +
> +     fd = osaf_timerfd_create(CLOCK_MONOTONIC, 0);
> +
> +     /* Set timeout time. Do not use as interval timer */
> +     lgs_cltimer.it_interval.tv_sec = 0;
> +     lgs_cltimer.it_interval.tv_nsec = 0;
> +     /* Set timeout in seconds */
> +     lgs_cltimer.it_value.tv_sec = timeout_s;
> +     lgs_cltimer.it_value.tv_nsec = 0;
> +
> +     osaf_timerfd_settime(fd, 0, &lgs_cltimer, NULL);
> +
> +     return fd;
> +}
> +
> +/**
> + * Close a timer created with lgs_init_timer()
> + * See also osaf_timerfd.h
> + *
> + * @param ufd[in]
> + */
> +void lgs_close_timer(int ufd)
> +{
> +     osaf_timerfd_close(ufd);
> +}
> +
> +/**
>   * Validate if string contains special characters or not
>   *
>   * @param: str [in] input string for checking
> diff --git a/osaf/services/saf/logsv/lgs/lgs_util.h
> b/osaf/services/saf/logsv/lgs/lgs_util.h
> --- a/osaf/services/saf/logsv/lgs/lgs_util.h
> +++ b/osaf/services/saf/logsv/lgs/lgs_util.h
> @@ -77,4 +77,8 @@ bool lgs_is_valid_pathlength(const std::
>                               const std::string &fileName,
>                            const std::string &rootPath = "");
>  
> +/* Timer functions */
> +int lgs_init_timer(time_t timeout_s);
> +void lgs_close_timer(int ufd);
> +
>  #endif   /* ifndef __LGS_UTIL_H */

------------------------------------------------------------------------------
Site24x7 APM Insight: Get Deep Visibility into Application Performance
APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month
Monitor end-to-end web transactions and take corrective actions now
Troubleshoot faster and improve end-user experience. Signup Now!
http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140
_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to