osaf/services/saf/logsv/README                   |   31 ++-
 osaf/services/saf/logsv/config/logd.conf         |    6 +
 osaf/services/saf/logsv/config/logsv_classes.xml |    8 +-
 osaf/services/saf/logsv/lgs/Makefile.am          |    6 +-
 osaf/services/saf/logsv/lgs/lgs.h                |    3 +
 osaf/services/saf/logsv/lgs/lgs_cb.h             |    1 +
 osaf/services/saf/logsv/lgs/lgs_file.c           |    5 +
 osaf/services/saf/logsv/lgs/lgs_file.h           |    1 +
 osaf/services/saf/logsv/lgs/lgs_filehdl.c        |   93 +++++++++-
 osaf/services/saf/logsv/lgs/lgs_filehdl.h        |    6 +
 osaf/services/saf/logsv/lgs/lgs_imm.c            |  213 ++++++++++++++++++--
 osaf/services/saf/logsv/lgs/lgs_main.c           |    9 +-
 osaf/services/saf/logsv/lgs/lgs_mbcsv.c          |   83 ++++++--
 osaf/services/saf/logsv/lgs/lgs_mbcsv.h          |    5 +-
 osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.c       |  235 +++++++++++++++++++++++
 osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.h       |   64 ++++++
 osaf/services/saf/logsv/lgs/lgs_util.c           |   86 ++++++++
 osaf/services/saf/logsv/lgs/lgs_util.h           |    2 +
 18 files changed, 802 insertions(+), 55 deletions(-)


    New attribute has been added to log configuration object.
      logDataGroupname  <Empty> Groupname used to share log data.

    This attribute if set will be used to own log files.
    Users who want to read log data need to become member of this group.
    This attribute can be changed in runtime. All log files will be reowned
    accordingly to this new group.

    Also new environment variable has been added to log configuration file:
      LOGSV_DATA_GROUPNAME
    This variable will be ignored if configured in IMM object.

diff --git a/osaf/services/saf/logsv/README b/osaf/services/saf/logsv/README
--- a/osaf/services/saf/logsv/README
+++ b/osaf/services/saf/logsv/README
@@ -166,8 +166,9 @@ saLogAppLowLimit            0
 saLogMaxApplicationStreams  64
 logFileIoTimeout            500                   File I/O timeout (see file.c)
 logFileSysConfig            1                     Shared file system
+logDataGroupname            <Empty>               Groupname used to share log 
data.
 
-All the above attributes except saLogRootDirectory has a default value
+All the above attributes except saLogRootDirectory and logDataGroupname has a 
default value
 set in the class definition (see logsv_classes.xml). The value for parameter
 saLogRootDirectory is instead defined when the imm.xml file is created. In
 the logsv_objects.xml file the parameter value is set to "xxLOGDIRxx/saflog"
@@ -190,6 +191,16 @@ The following attributes can be changed 
    Can be changed in runtime if both SC nodes supports changes. Could not
    be changed in older versions.
 
+ - logDataGroupname
+   Can be changed to an existing group which is currently a supplementary group
+   of the user as which LOG service is running.
+   This new group then will be used to own all log files. Also the ownership of
+   all current log files will be changed to this group for consistent purpose.
+   Users who are member of this group then can read the log files.
+   After the deletion of the value of this attribute, the ownership of all 
current
+   log files won't be changed and behaviour will be kept as previous, i.e: new 
opened
+   log file will be owned by the primary group as which LOG service is 
running. 
+
 Other attributes cannot be changed in runtime.
 
 logFileIoTimeout
@@ -263,6 +274,12 @@ LOG_MAX_APPLICATION_STREAMS
 
 The maximum number of application log streams that can be created.
 
+LOGSV_DATA_GROUPNAME
+
+The group used to share log data to users.
+This group must be added as a supplementary group of user as which log service 
is running.
+Any user wants to read log data must become a member of this group.
+
 Don't forget the "export" keyword before the variable!
 
 3. Precedence, special case
@@ -468,7 +485,9 @@ open stream:
     creating the file names, creating a config file and creating and opening 
the
     log file. If this fails the files are created and opened when trying to
     write a log record to the stream. This is done in the event handler when
-    receiving an "stream open" event from the agent. 
+    receiving an "stream open" event from the agent.
+    After created, all these files will be owned by LOGSV_DATA_GROUPNAME if 
set (in
+    either config 1 or 2).
 
     If config 2:
 
@@ -497,9 +516,11 @@ cfg stream:
 cfg config:
     Attributes in the log service configuration object are changed. Internal
     data is updated. On active node this is handled with an object implementer
-    (lgs_imm) and changes are check pointed to standby. Currently only 
attribute
-    logRootDirectory can be changed in runtime. When this happen all files are
-    closed and new files are created at the new location for all open streams.
+    (lgs_imm) and changes are check pointed to standby. Currently only two 
attributes
+    logRootDirectory and logDataGroupname can be changed in runtime. When root
+    directory is changed, all files are closed and new files are created at the
+    new location for all open streams. Similarly, when data group changed, all
+    log files will be reowned by this new group.
 
     If config 2:
 
diff --git a/osaf/services/saf/logsv/config/logd.conf 
b/osaf/services/saf/logsv/config/logd.conf
--- a/osaf/services/saf/logsv/config/logd.conf
+++ b/osaf/services/saf/logsv/config/logd.conf
@@ -30,3 +30,9 @@ export LOGSV_ROOT_DIRECTORY=$pkglogdir/s
 
 # Uncomment the next line to enable info level logging
 #args="--loglevel=info"
+
+# Log data group used to share OpenSAF log to other users.
+# If set then any log created by the LOG service will be owned by this group.
+# Users want to read log data need to become member of this group.
+# NOTE: will not be used if defined in the OpenSafLogConfig object.
+# export LOGSV_DATA_GROUPNAME=<groupname>
diff --git a/osaf/services/saf/logsv/config/logsv_classes.xml 
b/osaf/services/saf/logsv/config/logsv_classes.xml
--- a/osaf/services/saf/logsv/config/logsv_classes.xml
+++ b/osaf/services/saf/logsv/config/logsv_classes.xml
@@ -236,7 +236,13 @@ to ensure that default global values in 
                        <type>SA_UINT32_T</type>
                        <category>SA_CONFIG</category>
                        <flag>SA_WRITABLE</flag>
-            <default-value>1</default-value>
+                       <default-value>1</default-value>
+               </attr>
+               <attr>
+                       <name>logDataGroupname</name>
+                       <type>SA_STRING_T</type>
+                       <category>SA_CONFIG</category>
+                       <flag>SA_WRITABLE</flag>
                </attr>
        </class>
 </imm:IMM-contents>
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
@@ -32,7 +32,8 @@ noinst_HEADERS = \
        lgs.h \
        lgs_stream.h \
        lgs_file.h \
-       lgs_filehdl.h
+       lgs_filehdl.h \
+       lgs_mbcsv_v3.h
 
 osaf_execbindir = $(pkglibdir)
 osaf_execbin_PROGRAMS = osaflogd
@@ -55,7 +56,8 @@ osaflogd_SOURCES = \
        lgs_stream.c \
        lgs_util.c \
        lgs_file.c \
-       lgs_filehdl.c
+       lgs_filehdl.c \
+       lgs_mbcsv_v3.c
 
 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
@@ -88,6 +88,7 @@
 /* Used with function lgs_imm_logconf_get(...) */
 typedef enum {
        LGS_IMM_LOG_ROOT_DIRECTORY,
+       LGS_IMM_DATA_GROUPNAME,
        LGS_IMM_LOG_MAX_LOGRECSIZE,
        LGS_IMM_LOG_STREAM_SYSTEM_HIGH_LIMIT,
        LGS_IMM_LOG_STREAM_SYSTEM_LOW_LIMIT,
@@ -132,5 +133,7 @@ extern const void *lgs_imm_logconf_get(l
 extern void lgs_imm_rootpathconf_set(const char *root_path_str);
 extern void logRootDirectory_filemove(const char *logRootDirectory, time_t 
*cur_time_in);
 extern void update_mailbox_limits(void);
+extern void lgs_imm_groupnameconf_set(const char *data_groupname_str);
+extern void logDataGroupname_fileown(const char *new_logDataGroupname);
 
 #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
@@ -88,6 +88,7 @@ typedef struct lgs_cb {
        const char *logsv_root_dir;     /* Root directory for log files */
        unsigned int max_logrecsize;
        bool nid_started;       /**< true if started by NID */
+       const char *logsv_data_groupname; /* Group used to share log data */
 } lgs_cb_t;
 
 extern uint32_t lgs_cb_init(lgs_cb_t *);
diff --git a/osaf/services/saf/logsv/lgs/lgs_file.c 
b/osaf/services/saf/logsv/lgs/lgs_file.c
--- a/osaf/services/saf/logsv/lgs/lgs_file.c
+++ b/osaf/services/saf/logsv/lgs/lgs_file.c
@@ -178,6 +178,11 @@ static void *file_hndl_thread(void *nopa
                        case LGSF_CHECKDIR:
                                hndl_rc = 
path_is_writeable_dir_hdl(lgs_com_data.indata_ptr,
                                                lgs_com_data.outdata_ptr, 
lgs_com_data.outdata_size);
+                               break;
+                       case LGSF_OWN_LOGFILES:
+                               hndl_rc = 
own_log_files_by_group_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
@@ -46,6 +46,7 @@ typedef enum {
        LGSF_RENAME_FILE,
        LGSF_CHECKPATH,
        LGSF_CHECKDIR,
+       LGSF_OWN_LOGFILES,
        LGSF_NOREQ
 }lgsf_treq_t;
 
diff --git a/osaf/services/saf/logsv/lgs/lgs_filehdl.c 
b/osaf/services/saf/logsv/lgs/lgs_filehdl.c
--- a/osaf/services/saf/logsv/lgs/lgs_filehdl.c
+++ b/osaf/services/saf/logsv/lgs/lgs_filehdl.c
@@ -459,7 +459,12 @@ open_retry:
                /* Do not log with higher severity here to avoid flooding the 
log.
                 * Can be called in context of log_stream_write */
                LOG_IN("Could not open: %s - %s", filepath, strerror(errno));
+       } else {
+               if (fchown(fd, (uid_t)-1, lgs_get_data_gid()) == -1){
+                       LOG_WA("Failed to change log file ownership, %s", 
strerror(errno));
+               }
        }
+
        osaf_mutex_lock_ordie(&lgs_ftcom_mutex); /* LOCK after critical section 
*/
 
        *errno_out_p = errno_save;
@@ -584,7 +589,8 @@ static char file_prefix[SA_MAX_NAME_LENG
 static int filter_func(const struct dirent *finfo)
 {
        int ret;
-       ret = strncmp(file_prefix, finfo->d_name, strlen(file_prefix));
+       int filenameLen = strlen(finfo->d_name) - strlen(".log");
+       ret = strncmp(file_prefix, finfo->d_name, strlen(file_prefix)) || 
strcmp(finfo->d_name + filenameLen, ".log");
        return !ret;
 }
 
@@ -680,3 +686,88 @@ done_exit:
        TRACE_LEAVE();
        return rc;
 }
+
+/**
+ * Change the ownership of all log files to a new group.
+ * The input directory will be scanned and any file suffixed by ".log"
+ * and prefixed by input file_name will be marked as log files.
+ * @param indata, see olfbgh_in_t
+ * @param outdata, not used
+ * @param max_outsize, not used
+ *
+ * @return int, 0 on success or -1 if error
+ */
+int own_log_files_by_group_hdl(void *indata, void *outdata, size_t 
max_outsize) {
+       struct dirent **namelist;
+       int n, files, i;
+       char path[PATH_MAX];
+       olfbgh_t *params_in;
+       int rc = 0;
+
+       TRACE_ENTER();
+
+       params_in = (olfbgh_t *) indata;
+
+       /* Initialize the filter */
+       n = snprintf(file_prefix, SA_MAX_NAME_LENGTH, "%s", 
params_in->file_name);
+       if (n >= SA_MAX_NAME_LENGTH) {
+               rc = -1;
+               LOG_WA("file_prefix > SA_MAX_NAME_LENGTH");
+               goto done_exit;
+       }
+
+       n = snprintf(path, PATH_MAX, "%s/%s",
+                       params_in->logsv_root_dir, params_in->pathName);
+       if (n >= PATH_MAX) {
+               LOG_WA("path > PATH_MAX");
+               rc = -1;
+               goto done_exit;
+       }
+
+       osaf_mutex_unlock_ordie(&lgs_ftcom_mutex); /* UNLOCK critical section */
+       files = n = scandir(path, &namelist, filter_func, alphasort);
+
+       if (n == -1 && errno == ENOENT) {
+               rc = 0;
+               goto done_exit;
+       }
+
+       if (n < 0) {
+               LOG_WA("scandir:%s - %s", strerror(errno), path);
+               rc = -1;
+               goto done_exit;
+       }
+
+       if (n == 0) {
+               rc = files;
+               goto done_exit;
+       }
+
+       gid_t gid = (gid_t) lgs_get_data_gid();
+
+       while (n--) {
+               char file[PATH_MAX];
+               int len = snprintf(file, PATH_MAX, "%s/%s",
+                                       path, namelist[n]->d_name);
+               if (len >= PATH_MAX) {
+                       LOG_WA("path > PATH_MAX");
+                       rc = -1;
+                       goto done_free;
+               }
+               TRACE_3("%s", file);
+               if (chown(file, (uid_t) -1, gid) != 0) {
+                       LOG_WA("Failed to change the ownership of %s - %s", 
namelist[n]->d_name, strerror(errno));
+               }
+       }
+
+done_free:
+       /* Free scandir allocated memory */
+       for (i = 0; i < files; i++)
+               free(namelist[i]);
+       free(namelist);
+
+done_exit:
+       osaf_mutex_lock_ordie(&lgs_ftcom_mutex); /* LOCK after critical section 
*/
+       TRACE_LEAVE();
+       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
@@ -123,6 +123,11 @@ typedef struct {
         * to the indata buffer directly after the ccfh_t
         */
 
+/* own_log_files_by_group_hdl(..)
+ * No out parameters
+ */
+typedef gnolfh_in_t olfbgh_t;
+
 /*
  * rename_file_hdl(..)
  * 
@@ -163,6 +168,7 @@ int fileopen_hdl(void *indata, void *out
 int fileclose_hdl(void *indata, void *outdata, size_t max_outsize);
 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);
 
 #ifdef __cplusplus
 }
diff --git a/osaf/services/saf/logsv/lgs/lgs_imm.c 
b/osaf/services/saf/logsv/lgs/lgs_imm.c
--- a/osaf/services/saf/logsv/lgs/lgs_imm.c
+++ b/osaf/services/saf/logsv/lgs/lgs_imm.c
@@ -26,12 +26,16 @@
  * Examples can be found in file lgs_stream.c, e.g. function fileopen(...)
  */
 
+#define _GNU_SOURCE
 #include <poll.h>
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <grp.h>
+#include <utmp.h>
 
 #include <saImmOm.h>
 #include <saImmOi.h>
@@ -44,6 +48,8 @@
 
 #include "lgs_mbcsv_v1.h"
 #include "lgs_mbcsv_v2.h"
+#include "lgs_mbcsv_v3.h"
+#include "osaf_secutil.h"
 
 /* TYPE DEFINITIONS
  * ----------------
@@ -51,6 +57,7 @@
 typedef struct {
        /* --- Corresponds to IMM Class SaLogConfig --- */
        char logRootDirectory[PATH_MAX];
+       char logDataGroupname[UT_NAMESIZE];
        SaUint32T logMaxLogrecsize;
        SaUint32T logStreamSystemHighLimit;
        SaUint32T logStreamSystemLowLimit;
@@ -76,6 +83,7 @@ typedef struct {
        bool logMaxApplicationStreams_noteflag;
        bool logFileIoTimeout_noteflag;
        bool logFileSysConfig_noteflag;
+       bool logDataGroupname_noteflag;
 } lgs_conf_t;
 
 /* DATA DECLARATIONS
@@ -98,6 +106,7 @@ static lgs_conf_t _lgs_conf = {
        .logMaxApplicationStreams = 64,
        .logFileIoTimeout = 500,
        .logFileSysConfig = 1,
+       .logDataGroupname = "",
 
        /*
         * For the following flags, true means that no external configuration
@@ -114,6 +123,7 @@ static lgs_conf_t _lgs_conf = {
        .logStreamAppHighLimit_noteflag = false,
        .logStreamAppLowLimit_noteflag = false,
        .logMaxApplicationStreams_noteflag = false,
+       .logDataGroupname_noteflag = false,
        /* 
         * The following attributes cannot be configured in the config file
         * Will be set to false if the attribute exists in the IMM config object
@@ -203,10 +213,12 @@ static void report_om_error(SaImmOiHandl
  * 
  * @return NCSCC_RC_... error code
  */
-static uint32_t ckpt_lgs_cfg(lgs_conf_t *lgs_conf)
+static uint32_t ckpt_lgs_cfg(lgs_conf_t *lgs_conf, bool is_root_dir_changed)
 {
-       lgsv_ckpt_msg_v2_t ckpt;
-       uint32_t rc;
+       void *ckpt = NULL;
+       lgsv_ckpt_msg_v2_t ckpt_v2;
+       lgsv_ckpt_msg_v3_t ckpt_v3;
+       uint32_t rc = NCSCC_RC_SUCCESS;
 
        TRACE_ENTER();
        
@@ -216,15 +228,32 @@ static uint32_t ckpt_lgs_cfg(lgs_conf_t 
                return NCSCC_RC_FAILURE;
        }
 
-       memset(&ckpt, 0, sizeof(ckpt));
-       ckpt.header.ckpt_rec_type = LGS_CKPT_LGS_CFG;
-       ckpt.header.num_ckpt_records = 1;
-       ckpt.header.data_len = 1;
+       if (lgs_is_peer_v4()) {
+               memset(&ckpt_v3, 0, sizeof(ckpt_v3));
+               ckpt_v3.header.ckpt_rec_type = LGS_CKPT_LGS_CFG_V3;
+               ckpt_v3.header.num_ckpt_records = 1;
+               ckpt_v3.header.data_len = 1;
+               ckpt_v3.ckpt_rec.lgs_cfg.logRootDirectory = 
lgs_conf->logRootDirectory;
+               ckpt_v3.ckpt_rec.lgs_cfg.logDataGroupname = 
lgs_conf->logDataGroupname;
+               ckpt_v3.ckpt_rec.lgs_cfg.c_file_close_time_stamp = 
lgs_conf->chkp_file_close_time;
 
-       ckpt.ckpt_rec.lgs_cfg.logRootDirectory = lgs_conf->logRootDirectory;
-       ckpt.ckpt_rec.lgs_cfg.c_file_close_time_stamp = 
lgs_conf->chkp_file_close_time;
+               ckpt = &ckpt_v3;
+       } else {
+               if (is_root_dir_changed) {
+                       memset(&ckpt_v2, 0, sizeof(ckpt_v2));
+                       ckpt_v2.header.ckpt_rec_type = LGS_CKPT_LGS_CFG;
+                       ckpt_v2.header.num_ckpt_records = 1;
+                       ckpt_v2.header.data_len = 1;
+                       ckpt_v2.ckpt_rec.lgs_cfg.logRootDirectory = 
lgs_conf->logRootDirectory;
+                       ckpt_v2.ckpt_rec.lgs_cfg.c_file_close_time_stamp = 
lgs_conf->chkp_file_close_time;
 
-       rc = lgs_ckpt_send_async(lgs_cb, &ckpt, NCS_MBCSV_ACT_ADD);
+                       ckpt = &ckpt_v2;
+               }
+       }
+
+       if (ckpt) {
+               rc = lgs_ckpt_send_async(lgs_cb, ckpt, NCS_MBCSV_ACT_ADD);
+       }
 
        TRACE_LEAVE();
        return rc;
@@ -784,6 +813,22 @@ static SaAisErrorT validate_config_ccb_c
 }
        
 /**
+ * Check if group is valid or not
+ * A group is valid if:
+ *     - It exists
+ *     - It contains the user as which LOGD is running
+ *     @param groupname
+ *     @return: true  - group is a valid group
+ *              false - group is not a valid group
+ */
+static bool group_is_valid(const char* groupname)
+{
+       uid_t uid = getuid();
+       bool rc = osaf_user_is_member_of_group(uid, groupname);
+       return rc;
+}
+
+/**
  * Modification of attributes in log service configuration object.
  * Only logRootDirectory can be modified
  * 
@@ -816,12 +861,13 @@ static SaAisErrorT config_ccb_completed_
 
        attrMod = opdata->param.modify.attrMods[i++];
        while (attrMod != NULL) {
-               void *value;
+               void *value = NULL;
                const SaImmAttrValuesT_2 *attribute = &attrMod->modAttr;
 
                TRACE("attribute %s", attribute->attrName);
 
-               if (attribute->attrValuesNumber == 0) {
+               /* Ignore deletion of attributes except for logDataGroupname*/
+               if ((strcmp(attribute->attrName, "logDataGroupname") != 0) && 
(attribute->attrValuesNumber == 0)) {
                        report_oi_error(immOiHandle, opdata->ccbId,
                                        "deletion of value is not allowed for 
attribute %s stream %s",
                                        attribute->attrName, 
opdata->objectName.value);
@@ -829,17 +875,34 @@ static SaAisErrorT config_ccb_completed_
                        goto done;
                }
 
-               value = attribute->attrValues[0];
+               if (attribute->attrValuesNumber != 0) {
+                       value = attribute->attrValues[0];
+               }
 
                if (!strcmp(attribute->attrName, "logRootDirectory")) {
-                       char *pathName = *((char **)value);
-                       if (!path_is_writeable_dir_h(pathName)) {
-                               report_oi_error(immOiHandle, opdata->ccbId,
-                                               "pathName: %s is NOT accepted", 
pathName);
-                               rc = SA_AIS_ERR_BAD_OPERATION;
-                               goto done;
+                       if (attribute->attrValuesNumber != 0) {
+                               char *pathName = *((char **)value);
+                               if (!path_is_writeable_dir_h(pathName)) {
+                                       report_oi_error(immOiHandle, 
opdata->ccbId,
+                                                       "pathName: %s is NOT 
accepted", pathName);
+                                       rc = SA_AIS_ERR_BAD_OPERATION;
+                                       goto done;
+                               }
+                               TRACE("pathName: %s is accepted", pathName);
                        }
-                       TRACE("pathName: %s is accepted", pathName);
+               } else if (!strcmp(attribute->attrName, "logDataGroupname")) {
+                       if (attribute->attrValuesNumber == 0) {
+                               TRACE("Deleting log data group");
+                       } else {
+                               char *groupname = *((char **)value);
+                               if (!group_is_valid(groupname)) {
+                                       report_oi_error(immOiHandle, 
opdata->ccbId,
+                                                       "groupname: %s is NOT 
accepted", groupname);
+                                       rc = SA_AIS_ERR_BAD_OPERATION;
+                                       goto done;
+                               }
+                               TRACE("groupname: %s is accepted", groupname);
+                       }
                } else if (!strcmp(attribute->attrName, "logMaxLogrecsize")) {
                        report_oi_error(immOiHandle, opdata->ccbId,
                                        "%s cannot be changed", 
attribute->attrName);
@@ -1869,6 +1932,46 @@ void logRootDirectory_filemove(const cha
 }
 
 /**
++ * Set logDataGroupname to new value
++ *   - Update lgs_conf with new group (logDataGroupname).
++ *   - Reown all log files by this new group.
++ *
++ * @param new_logDataGroupname[in]
++ *            String contains new group.
++ */
+void logDataGroupname_fileown(const char *new_logDataGroupname){
+       TRACE_ENTER();
+       log_stream_t *stream;
+
+       if (!new_logDataGroupname) {
+               LOG_ER("Data group is NULL");
+               return;
+       }
+
+       /* Shall never happen */
+       if (strlen(new_logDataGroupname) + 1 > UT_NAMESIZE) {
+               LOG_ER("%s data group > UT_NAMESIZE! Abort", __FUNCTION__);
+               osafassert(0);
+       }
+
+       /* Update data group configuration in lgs_conf */
+       lgs_imm_groupnameconf_set(new_logDataGroupname);
+
+       /* For each log stream, reown all log files */
+       if (strcmp(new_logDataGroupname, "")) {
+               /* Not attribute values deletion
+                * Change ownership of log files to this new group
+                */
+               stream = log_stream_getnext_by_name(NULL);
+               while (stream != NULL) {
+                       lgs_own_log_files(stream);
+                       stream = log_stream_getnext_by_name(stream->name);
+               }
+       }
+       TRACE_LEAVE();
+}
+
+/**
  * Apply validated changes
  *
  * @param opdata
@@ -1880,13 +1983,16 @@ static void config_ccb_apply_modify(cons
        bool checkpoint_flag = false;
        bool mbox_cfg_flag = false;
        struct timespec curtime_tspec;
+       bool is_root_dir_changed = false;
 
        TRACE_ENTER2("CCB ID %llu, '%s'", opdata->ccbId, 
opdata->objectName.value);
 
        attrMod = opdata->param.modify.attrMods[i++];
        while (attrMod != NULL) {
                const SaImmAttrValuesT_2 *attribute = &attrMod->modAttr;
-               void *value = attribute->attrValues[0];
+               void *value = NULL;
+               if (attribute->attrValuesNumber != 0)
+                       value = attribute->attrValues[0];
 
                TRACE("attribute %s", attribute->attrName);
 
@@ -1905,7 +2011,21 @@ static void config_ccb_apply_modify(cons
                        logRootDirectory_filemove(new_logRootDirectory, 
&cur_time);
 
                        lgs_conf->chkp_file_close_time = cur_time;
-               
+
+                       is_root_dir_changed = true;
+                       checkpoint_flag = true;
+               } else if (!strcmp(attribute->attrName, "logDataGroupname")) {
+                       /* Update saved configuration (on active. See 
ckpt_proc_lgs_cfg()
+                        * in lgs_mbcsv.c for corresponding update on standby)
+                        */
+                       if (attribute->attrValuesNumber == 0) {
+                               logDataGroupname_fileown("");
+                       } else {
+                               const char *new_dataGroupname = *((char 
**)value);
+
+                               /* Re-own all log files by this new group */
+                               logDataGroupname_fileown(new_dataGroupname);
+                       }
                        checkpoint_flag = true;
                } else if (!strcmp(attribute->attrName, 
"logStreamSystemHighLimit")) {
                        mbox_cfg_flag = true;
@@ -1932,7 +2052,7 @@ static void config_ccb_apply_modify(cons
        
        if (checkpoint_flag == true) {
                /* Check pointing lgs configuration change */
-               ckpt_lgs_cfg(lgs_conf);
+               ckpt_lgs_cfg(lgs_conf, is_root_dir_changed);
        }
 
        TRACE_LEAVE();
@@ -2519,6 +2639,16 @@ static SaAisErrorT read_logsv_config_obj
                        }
                        param_cnt++;
                        TRACE("Conf obj; logRootDirectory: %s", 
lgs_conf->logRootDirectory);
+               } else if (!strcmp(attribute->attrName, "logDataGroupname")) {
+                       n = snprintf(lgs_conf->logDataGroupname, UT_NAMESIZE, 
"%s",
+                                       *((char **) value));
+                       if (n >= UT_NAMESIZE) {
+                               LOG_WA("LOG data group name read from config 
object is > UT_NAMESIZE");
+                               lgs_conf->logDataGroupname[0] = '\0';
+                               lgs_conf->logDataGroupname_noteflag = true;
+                       }
+                       param_cnt++;
+                       TRACE("Conf obj; logDataGroupname: %s", 
lgs_conf->logDataGroupname);
                } else if (!strcmp(attribute->attrName, "logMaxLogrecsize")) {
                        lgs_conf->logMaxLogrecsize = *((SaUint32T *) value);
                        param_cnt++;
@@ -2614,6 +2744,22 @@ static void read_logsv_config_environ_va
        TRACE("logRootDirectory=%s, logRootDirectory_noteflag=%u",
                        lgs_conf->logRootDirectory, 
lgs_conf->logRootDirectory_noteflag);
 
+       /* logDataGroupname */
+       if ((val_str = getenv("LOGSV_DATA_GROUPNAME")) != NULL) {
+               lgs_conf->logDataGroupname_noteflag = false;
+               n = snprintf(lgs_conf->logDataGroupname, UT_NAMESIZE, "%s", 
val_str);
+               if (n >= UT_NAMESIZE) {
+                       LOG_WA("LOG data group name read from config file is > 
UT_NAMESIZE");
+                       lgs_conf->logDataGroupname[0] = '\0';
+                       lgs_conf->logDataGroupname_noteflag = true;
+               }
+       } else {
+               LOG_WA("LOGSV_DATA_GROUPNAME not found");
+               lgs_conf->logDataGroupname_noteflag = true;
+       }
+       TRACE("logDataGroupname=%s, logDataGroupname_noteflag=%u",
+                       lgs_conf->logDataGroupname, 
lgs_conf->logDataGroupname_noteflag);
+
        /* logMaxLogrecsize */
        if ((val_str = getenv("LOGSV_MAX_LOGRECSIZE")) != NULL) {
 /* errno = 0 is necessary as per the manpage of strtoul. Quoting here:
@@ -2881,6 +3027,11 @@ const void *lgs_imm_logconf_get(lgs_logc
                        *noteflag = lgs_conf->logRootDirectory_noteflag;
                }
                return (char *) lgs_conf->logRootDirectory;
+       case LGS_IMM_DATA_GROUPNAME:
+               if (noteflag != NULL) {
+                       *noteflag = lgs_conf->logDataGroupname_noteflag;
+               }
+               return (char *) lgs_conf->logDataGroupname;
        case LGS_IMM_LOG_MAX_LOGRECSIZE:
                if (noteflag != NULL) {
                        *noteflag = lgs_conf->logMaxLogrecsize_noteflag;
@@ -2956,6 +3107,22 @@ void lgs_imm_rootpathconf_set(const char
        LOG_NO("lgsv root path is changed to 
\"%s\"",lgs_conf->logRootDirectory);
 }
 
+/**
+ * Set the logDataGroupname parameter in the lgs_conf struct
+ * Used for holding data from config object
+ *
+ * @param root_path_str
+ */
+void lgs_imm_groupnameconf_set(const char *data_groupname_str)
+{
+       if ((strlen(data_groupname_str)+1) > UT_NAMESIZE)
+               osafassert(0);
+
+       strcpy(lgs_conf->logDataGroupname, data_groupname_str);
+       LOG_NO("lgsv data group is changed to %s", 
strcmp(lgs_conf->logDataGroupname, "") ?
+                               lgs_conf->logDataGroupname : "<Empty>");
+}
+
 static const SaImmOiCallbacksT_2 callbacks = {
        .saImmOiAdminOperationCallback = adminOperationCallback,
        .saImmOiCcbAbortCallback = ccbAbortCallback,
diff --git a/osaf/services/saf/logsv/lgs/lgs_main.c 
b/osaf/services/saf/logsv/lgs/lgs_main.c
--- a/osaf/services/saf/logsv/lgs/lgs_main.c
+++ b/osaf/services/saf/logsv/lgs/lgs_main.c
@@ -276,7 +276,14 @@ static uint32_t log_initialize(void)
                goto done;
        }
        LOG_NO("log root directory is: %s", lgs_cb->logsv_root_dir);
-       
+
+       lgs_cb->logsv_data_groupname = 
lgs_imm_logconf_get(LGS_IMM_DATA_GROUPNAME, &errorflag);
+       if (errorflag != false) {
+               LOG_ER("Valid LOGSV_LOG_DATA_GROUPNAME not found");
+               goto done;
+       }
+       LOG_NO("log data group is: %s", lgs_cb->logsv_data_groupname);
+
        /* Initialize stream class */
        if (log_stream_init() != NCSCC_RC_SUCCESS) {
                LOG_ER("log_stream_init FAILED");
diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv.c 
b/osaf/services/saf/logsv/lgs/lgs_mbcsv.c
--- a/osaf/services/saf/logsv/lgs/lgs_mbcsv.c
+++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv.c
@@ -21,6 +21,7 @@
 #include "lgs_fmt.h"
 #include "osaf_time.h"
 
+#include "lgs_mbcsv_v3.h"
 #include "lgs_mbcsv_v2.h"
 #include "lgs_mbcsv_v1.h"
 //#include "lgs_mbcsv_v1.h"
@@ -77,7 +78,8 @@ static LGS_CKPT_HDLR ckpt_data_handler[]
        ckpt_proc_open_stream,
        ckpt_proc_close_stream,
        ckpt_proc_cfg_stream,
-       ckpt_proc_lgs_cfg_v2
+       ckpt_proc_lgs_cfg_v2,
+       ckpt_proc_lgs_cfg_v3
 };
 
 /****************************************************************************
@@ -336,6 +338,19 @@ bool lgs_is_peer_v3(void)
 }
 
 /**
+ * Check if peer is version 4 (or later)
+ * @return bool
+ */
+bool lgs_is_peer_v4(void)
+{
+       if (lgs_cb->mbcsv_peer_version >= LGS_MBCSV_VERSION_4) {
+               return true;
+       } else {
+               return false;
+       }
+}
+
+/**
  * Check if configured for split file system.
  * If other node is version 1 split file system mode is not applicable.
  * 
@@ -734,6 +749,7 @@ static uint32_t edu_enc_reg_list(lgs_cb_
 
 static uint32_t ckpt_encode_async_update(lgs_cb_t *lgs_cb, EDU_HDL edu_hdl, 
NCS_MBCSV_CB_ARG *cbk_arg)
 {
+       lgsv_ckpt_msg_v3_t *data_v3 = NULL;
        lgsv_ckpt_msg_v2_t *data_v2 = NULL;
        lgsv_ckpt_msg_v1_t *data_v1 = NULL;
        void * vdata = NULL;
@@ -743,14 +759,18 @@ static uint32_t ckpt_encode_async_update
        
        TRACE_ENTER();
        /* Set reo_hdl from callback arg to ckpt_rec */
-       if (lgs_is_peer_v2()) {
+       if (lgs_is_peer_v4()) {
+               data_v3 = (lgsv_ckpt_msg_v3_t 
*)(long)cbk_arg->info.encode.io_reo_hdl;
+               vdata = data_v3;
+               edp_function = edp_ed_ckpt_msg_v3;
+       } else if (lgs_is_peer_v2()) {
                data_v2 = (lgsv_ckpt_msg_v2_t 
*)(long)cbk_arg->info.encode.io_reo_hdl;
                vdata = data_v2;
                edp_function = edp_ed_ckpt_msg_v2;
        } else {
                data_v1 = (lgsv_ckpt_msg_v1_t 
*)(long)cbk_arg->info.encode.io_reo_hdl;
                vdata = data_v1;
-               edp_function = edp_ed_ckpt_msg_v1;              
+               edp_function = edp_ed_ckpt_msg_v1;
        }
        
        if (vdata == NULL) {
@@ -1026,10 +1046,16 @@ static uint32_t ckpt_decode_log_cfg(lgs_
 {
        uint32_t rc = NCSCC_RC_SUCCESS;
        void *lgs_cfg = NULL;
-       EDU_PROG_HANDLER edp_function;
-       
-       if (lgs_is_peer_v2()) {
-               lgsv_ckpt_msg_v2_t *ckpt_msg_v2 = ckpt_msg;
+       EDU_PROG_HANDLER edp_function = NULL;
+       lgsv_ckpt_msg_v3_t *ckpt_msg_v3;
+       lgsv_ckpt_msg_v2_t *ckpt_msg_v2;
+
+       if (lgs_is_peer_v4()) {
+               ckpt_msg_v3 = ckpt_msg;
+               lgs_cfg = &ckpt_msg_v3->ckpt_rec.lgs_cfg;
+               edp_function = edp_ed_lgs_cfg_rec_v3;
+       } else if (lgs_is_peer_v2()) {
+               ckpt_msg_v2 = ckpt_msg;
                lgs_cfg = &ckpt_msg_v2->ckpt_rec.lgs_cfg;
                edp_function = edp_ed_lgs_cfg_rec_v2;
        } else {
@@ -1054,8 +1080,10 @@ static uint32_t ckpt_decode_async_update
        lgsv_ckpt_msg_v1_t *ckpt_msg_v1 = &msg_v1;
        lgsv_ckpt_msg_v2_t msg_v2;
        lgsv_ckpt_msg_v2_t *ckpt_msg_v2 = &msg_v2;
+       lgsv_ckpt_msg_v3_t msg_v3;
+       lgsv_ckpt_msg_v3_t *ckpt_msg_v3 = &msg_v3;
        void *ckpt_msg;
-       lgsv_ckpt_header_t *hdr;
+       lgsv_ckpt_header_t hdr, *hdr_ptr = &hdr;
        
        /* Same in both V1 and V2 */
        lgs_ckpt_initialize_msg_t *reg_rec;
@@ -1063,25 +1091,29 @@ static uint32_t ckpt_decode_async_update
        
        TRACE_ENTER();
 
-       if (lgs_is_peer_v2()) {
-               hdr = &ckpt_msg_v2->header;
-               ckpt_msg = ckpt_msg_v2;
-       } else {
-               hdr = &ckpt_msg_v1->header;
-               ckpt_msg = ckpt_msg_v1;
-       }
-       
        /* Decode the message header */
        rc = m_NCS_EDU_EXEC(&cb->edu_hdl, edp_ed_header_rec, 
&cbk_arg->info.decode.i_uba,
-                               EDP_OP_TYPE_DEC, &hdr, &ederror);
+                               EDP_OP_TYPE_DEC, &hdr_ptr, &ederror);
        if (rc != NCSCC_RC_SUCCESS) {
                m_NCS_EDU_PRINT_ERROR_STRING(ederror);
                TRACE("\tFail decode header");
        }
 
-       TRACE_2("\tckpt_rec_type: %d ", (int)hdr->ckpt_rec_type);
+       TRACE_2("\tckpt_rec_type: %d ", (int)hdr_ptr->ckpt_rec_type);
+
+       if (lgs_is_peer_v4() && (hdr_ptr->ckpt_rec_type == 
LGS_CKPT_LGS_CFG_V3)) {
+               ckpt_msg_v3->header = hdr;
+               ckpt_msg = ckpt_msg_v3;
+       } else if (lgs_is_peer_v2()) {
+               ckpt_msg_v2->header = hdr;
+               ckpt_msg = ckpt_msg_v2;
+       } else {
+               ckpt_msg_v1->header = hdr;
+               ckpt_msg = ckpt_msg_v1;
+       }
+
        /* Call decode routines appropriately */
-       switch (hdr->ckpt_rec_type) {
+       switch (hdr_ptr->ckpt_rec_type) {
        case LGS_CKPT_CLIENT_INITIALIZE:
                TRACE_2("\tINITIALIZE REC: UPDATE");
                if (lgs_is_peer_v2()) {
@@ -1146,6 +1178,7 @@ static uint32_t ckpt_decode_async_update
                }
                break;
        case LGS_CKPT_LGS_CFG:
+       case LGS_CKPT_LGS_CFG_V3:
                TRACE_2("\tLGS CFG REC: UPDATE");
                rc = ckpt_decode_log_cfg(cb, ckpt_msg, cbk_arg);
                if (rc != NCSCC_RC_SUCCESS) {
@@ -1341,13 +1374,17 @@ static uint32_t process_ckpt_data(lgs_cb
        lgsv_ckpt_msg_type_t lgsv_ckpt_msg_type;
        lgsv_ckpt_msg_v2_t *data_v1;
        lgsv_ckpt_msg_v2_t *data_v2;
+       lgsv_ckpt_msg_v3_t *data_v3;
        
        if ((!cb) || (data == NULL)) {
                TRACE("%s - FAILED: (!cb) || (data == NULL)",__FUNCTION__);
                return (rc = NCSCC_RC_FAILURE);
        }
        
-       if (lgs_is_peer_v2()) {
+       if (lgs_is_peer_v4()) {
+               data_v3 = data;
+               lgsv_ckpt_msg_type = data_v3->header.ckpt_rec_type;
+       } else if (lgs_is_peer_v2()) {
                data_v2 = data;
                lgsv_ckpt_msg_type = data_v2->header.ckpt_rec_type;
        } else {
@@ -2027,7 +2064,10 @@ uint32_t lgs_ckpt_send_async(lgs_cb_t *c
        
        TRACE_ENTER();
        
-       if (lgs_is_peer_v2()) {
+       if (lgs_is_peer_v4()) {
+               lgsv_ckpt_msg_v3_t *ckpt_rec_v3 = ckpt_rec;
+               ckpt_rec_type = ckpt_rec_v3->header.ckpt_rec_type;
+       } else if (lgs_is_peer_v2()) {
                lgsv_ckpt_msg_v2_t *ckpt_rec_v2 = ckpt_rec;
                ckpt_rec_type = ckpt_rec_v2->header.ckpt_rec_type;
        } else {
@@ -2334,6 +2374,7 @@ int32_t ckpt_msg_test_type(NCSCONTEXT ar
        case LGS_CKPT_CFG_STREAM:
                return LCL_TEST_JUMP_OFFSET_LGS_CKPT_CFG_STREAM;
        case LGS_CKPT_LGS_CFG:
+       case LGS_CKPT_LGS_CFG_V3:
                return LCL_TEST_JUMP_OFFSET_LGS_CKPT_LGS_CFG;
        default:
                return EDU_EXIT;
diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv.h 
b/osaf/services/saf/logsv/lgs/lgs_mbcsv.h
--- a/osaf/services/saf/logsv/lgs/lgs_mbcsv.h
+++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv.h
@@ -38,8 +38,9 @@ extern "C" {
 #define LGS_MBCSV_VERSION_1 1
 #define LGS_MBCSV_VERSION_2 2
 #define LGS_MBCSV_VERSION_3 3
+#define LGS_MBCSV_VERSION_4 4
 /* Current version */
-#define LGS_MBCSV_VERSION 3
+#define LGS_MBCSV_VERSION 4
 #define LGS_MBCSV_VERSION_MIN 1
        
 /* Checkpoint message types(Used as 'reotype' w.r.t mbcsv)  */
@@ -58,6 +59,7 @@ typedef enum {
        LGS_CKPT_CLOSE_STREAM = 5,
        LGS_CKPT_CFG_STREAM = 6,
        LGS_CKPT_LGS_CFG = 7,
+       LGS_CKPT_LGS_CFG_V3 = 8,
        LGS_CKPT_MSG_MAX
 } lgsv_ckpt_msg_type_t;
 
@@ -101,6 +103,7 @@ uint32_t lgs_mbcsv_init(lgs_cb_t *lgs_cb
 uint32_t lgs_mbcsv_change_HA_state(lgs_cb_t *cb);
 bool lgs_is_peer_v2(void);
 bool lgs_is_peer_v3(void);
+bool lgs_is_peer_v4(void);
 bool lgs_is_split_file_system(void);
 uint32_t lgs_mbcsv_dispatch(NCS_MBCSV_HDL mbcsv_hdl);
 void lgs_free_edu_mem(char *ptr);
diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.c 
b/osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.c
new file mode 100644
--- /dev/null
+++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.c
@@ -0,0 +1,235 @@
+/*      -*- OpenSAF  -*-
+ *
+ * (C) Copyright 2015 The OpenSAF Foundation
+ * File:   lgs_mbcsv_v3.c
+ *
+ * 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
+ *
+ */
+
+/*
+ * Contains functions for encoding/decoding check-point structures for
+ * version 3 check-pointing. See also lgs_mbcsv_v3.h
+ */
+
+#include "lgs_mbcsv_v3.h"
+#include "lgs_mbcsv_v2.h"
+#include "lgs_mbcsv.h"
+
+/****************************************************************************
+ * Name          : ckpt_proc_lgs_cfg
+ *
+ * Description   : This function configures updates log service configuration.
+ *
+ * Arguments     : cb - pointer to LGS  ControlBlock.
+ *                 data - pointer to  LGS_CHECKPOINT_DATA.
+ *
+ * Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
+ *
+ * Notes         : None.
+ ****************************************************************************/
+
+uint32_t ckpt_proc_lgs_cfg_v3(lgs_cb_t *cb, void *data)
+{
+       TRACE_ENTER();
+       if (!lgs_is_peer_v4()) {
+               /* Should never enter here */
+               LOG_ER("%s: Called when peer is not version 4. We should never 
enter here",__FUNCTION__);
+               osafassert(0);
+       }
+
+       lgsv_ckpt_msg_v3_t *data_v3 = data;
+       lgs_ckpt_lgs_cfg_v3_t *param = &data_v3->ckpt_rec.lgs_cfg;
+
+       if (strcmp(param->logRootDirectory, cb->logsv_root_dir) != 0) {
+               /* Root directory changed */
+               TRACE("Setting new root directory on standby 
%s",param->logRootDirectory);
+               if (lgs_is_split_file_system()) {
+                       /* Move log files on standby also */
+                       logRootDirectory_filemove(param->logRootDirectory, 
(time_t *) &param->c_file_close_time_stamp);
+               } else {
+                       /* Save new directory */
+                       lgs_imm_rootpathconf_set(param->logRootDirectory);
+               }
+       }
+
+       if (! param->logDataGroupname) {
+               /* Attribute value deletion */
+               if (strcmp(cb->logsv_data_groupname, "") != 0) {
+                       TRACE("Deleting data group on standby");
+                       lgs_imm_groupnameconf_set("");
+               }
+       } else if (strcmp(param->logDataGroupname, cb->logsv_data_groupname) != 
0) {
+               /* Data group changed */
+               TRACE("Setting new data group on standby 
%s",param->logDataGroupname);
+               if (lgs_is_split_file_system()) {
+                       /* Reown log files on standby also */
+                       logDataGroupname_fileown(param->logDataGroupname);
+               } else {
+                       /* Save new group */
+                       lgs_imm_groupnameconf_set(param->logDataGroupname);
+               }
+       }
+
+       /* Free strings allocated by the EDU encoder */
+       lgs_free_edu_mem(param->logRootDirectory);
+       lgs_free_edu_mem(param->logDataGroupname);
+
+       TRACE_LEAVE();
+       return NCSCC_RC_SUCCESS;
+}
+
+/****************************************************************************
+ * Name          : edp_ed_lgs_cfg_rec
+ *
+ * Description   : This function is an EDU program for encoding/decoding
+ *                 lgsv checkpoint log service configuration update.
+ *
+ * Arguments     : EDU_HDL - pointer to edu handle,
+ *                 EDU_TKN - internal edu token to help encode/decode,
+ *                 POINTER to the structure to encode/decode from/to,
+ *                 data length specifying number of structures,
+ *                 EDU_BUF_ENV - pointer to buffer for encoding/decoding.
+ *                 op - operation type being encode/decode.
+ *                 EDU_ERR - out param to indicate errors in processing.
+ *
+ * Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
+ *
+ * Notes         : None.
+ *****************************************************************************/
+
+uint32_t edp_ed_lgs_cfg_rec_v3(EDU_HDL *edu_hdl, EDU_TKN *edu_tkn,
+                                  NCSCONTEXT ptr, uint32_t *ptr_data_len,
+                                  EDU_BUF_ENV *buf_env, EDP_OP_TYPE op, 
EDU_ERR *o_err)
+{
+       uint32_t rc = NCSCC_RC_SUCCESS;
+       void *ckpt_lgs_cfg_msg_ptr = NULL;
+       lgs_ckpt_lgs_cfg_v3_t **ckpt_lgs_cfg_msg_dec_ptr_v3;
+
+       EDU_INST_SET ckpt_lgs_cfg_rec_ed_rules[] = {
+               {EDU_START, edp_ed_lgs_cfg_rec_v3, 0, 0, 0, 
sizeof(lgs_ckpt_lgs_cfg_v3_t), 0, NULL},
+               {EDU_EXEC, ncs_edp_string, 0, 0, 0, 
(long)&((lgs_ckpt_lgs_cfg_v3_t *)0)->logRootDirectory, 0, NULL},
+               {EDU_EXEC, ncs_edp_string, 0, 0, 0, 
(long)&((lgs_ckpt_lgs_cfg_v3_t *)0)->logDataGroupname, 0, NULL},
+               {EDU_EXEC, ncs_edp_uns64, 0, 0, 0, 
(long)&((lgs_ckpt_lgs_cfg_v3_t *)0)->c_file_close_time_stamp, 0, NULL},
+               {EDU_END, 0, 0, 0, 0, 0, 0, NULL},
+       };
+       if (op == EDP_OP_TYPE_ENC) {
+               ckpt_lgs_cfg_msg_ptr = (lgs_ckpt_lgs_cfg_v3_t *)ptr;
+       } else if (op == EDP_OP_TYPE_DEC) {
+               ckpt_lgs_cfg_msg_dec_ptr_v3 = (lgs_ckpt_lgs_cfg_v3_t **)ptr;
+               if (*ckpt_lgs_cfg_msg_dec_ptr_v3 == NULL) {
+                       *o_err = EDU_ERR_MEM_FAIL;
+                       return NCSCC_RC_FAILURE;
+               }
+               memset(*ckpt_lgs_cfg_msg_dec_ptr_v3, '\0', 
sizeof(lgs_ckpt_lgs_cfg_v3_t));
+               ckpt_lgs_cfg_msg_ptr = *ckpt_lgs_cfg_msg_dec_ptr_v3;
+       } else {
+               ckpt_lgs_cfg_msg_ptr = ptr;
+       }
+
+       rc = m_NCS_EDU_RUN_RULES(edu_hdl, edu_tkn, ckpt_lgs_cfg_rec_ed_rules, 
ckpt_lgs_cfg_msg_ptr, ptr_data_len,
+                               buf_env, op, o_err);
+       return rc;
+
+}
+
+/****************************************************************************
+ * Name          : edp_ed_ckpt_msg_v3
+ *
+ * Description   : This function is an EDU program for encoding/decoding
+ *                 lgsv checkpoint messages. This program runs the
+ *                 edp_ed_hdr_rec program first to decide the
+ *                 checkpoint message type based on which it will call the
+ *                 appropriate EDU programs for the different checkpoint
+ *                 messages.
+ *
+ * Arguments     : EDU_HDL - pointer to edu handle,
+ *                 EDU_TKN - internal edu token to help encode/decode,
+ *                 POINTER to the structure to encode/decode from/to,
+ *                 data length specifying number of structures,
+ *                 EDU_BUF_ENV - pointer to buffer for encoding/decoding.
+ *                 op - operation type being encode/decode.
+ *                 EDU_ERR - out param to indicate errors in processing.
+ *
+ * Return Values : NCSCC_RC_SUCCESS/NCSCC_RC_FAILURE
+ *
+ * Notes         : None.
+ *****************************************************************************/
+
+uint32_t edp_ed_ckpt_msg_v3(EDU_HDL *edu_hdl, EDU_TKN *edu_tkn,
+                               NCSCONTEXT ptr, uint32_t *ptr_data_len, 
EDU_BUF_ENV *buf_env,
+                               EDP_OP_TYPE op, EDU_ERR *o_err)
+{
+       uint32_t rc = NCSCC_RC_SUCCESS;
+       lgsv_ckpt_msg_v3_t *ckpt_msg_ptr = NULL, **ckpt_msg_dec_ptr;
+
+       EDU_INST_SET ckpt_msg_ed_rules[] = {
+               {EDU_START, edp_ed_ckpt_msg_v3, 0, 0, 0, 
sizeof(lgsv_ckpt_msg_v3_t), 0, NULL},
+               {EDU_EXEC, edp_ed_header_rec, 0, 0, 0, 
(long)&((lgsv_ckpt_msg_v3_t *)0)->header, 0, NULL},
+
+               {EDU_TEST, ncs_edp_uns32, 0, 0, 0, (long)&((lgsv_ckpt_msg_v3_t 
*)0)->header, 0,
+                (EDU_EXEC_RTINE)ckpt_msg_test_type},
+
+               /* Reg Record */
+               {EDU_EXEC, edp_ed_reg_rec, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.initialize_client, 
0, NULL},
+
+               /* Finalize record */
+               {EDU_EXEC, edp_ed_finalize_rec_v2, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.finalize_client, 0, 
NULL},
+
+               /* write log Record */
+               {EDU_EXEC, edp_ed_write_rec_v2, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.write_log, 0, NULL},
+
+               /* Open stream */
+               {EDU_EXEC, edp_ed_open_stream_rec, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.stream_open, 0, 
NULL},
+
+               /* Close stream */
+               {EDU_EXEC, edp_ed_close_stream_rec_v2, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.stream_close, 0, 
NULL},
+
+               /* Agent dest */
+               {EDU_EXEC, edp_ed_agent_down_rec_v2, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.stream_cfg, 0, 
NULL},
+
+
+               /* Cfg stream */
+               {EDU_EXEC, edp_ed_cfg_stream_rec_v2, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.stream_cfg, 0, 
NULL},
+
+               /* Lgs cfg */
+               {EDU_EXEC, edp_ed_lgs_cfg_rec_v3, 0, 0, EDU_EXIT,
+                (long)&((lgsv_ckpt_msg_v3_t *)0)->ckpt_rec.lgs_cfg, 0, NULL},
+
+               {EDU_END, 0, 0, 0, 0, 0, 0, NULL},
+       };
+
+       if (op == EDP_OP_TYPE_ENC) {
+               ckpt_msg_ptr = (lgsv_ckpt_msg_v3_t *)ptr;
+       } else if (op == EDP_OP_TYPE_DEC) {
+               ckpt_msg_dec_ptr = (lgsv_ckpt_msg_v3_t **)ptr;
+               if (*ckpt_msg_dec_ptr == NULL) {
+                       *o_err = EDU_ERR_MEM_FAIL;
+                       return NCSCC_RC_FAILURE;
+               }
+               memset(*ckpt_msg_dec_ptr, '\0', sizeof(lgsv_ckpt_msg_v3_t));
+               ckpt_msg_ptr = *ckpt_msg_dec_ptr;
+       } else {
+               ckpt_msg_ptr = ptr;
+       }
+
+       rc = m_NCS_EDU_RUN_RULES(edu_hdl, edu_tkn, ckpt_msg_ed_rules, 
ckpt_msg_ptr, ptr_data_len, buf_env, op, o_err);
+       return rc;
+
+}      /* End edu_enc_dec_ckpt_msg() */
diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.h 
b/osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.h
new file mode 100644
--- /dev/null
+++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv_v3.h
@@ -0,0 +1,64 @@
+/*      -*- OpenSAF  -*-
+ * File:   lgs_mbcsv_v3.h
+ *
+ * (C) Copyright 2015 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_MBCSV_V3_H
+#define LGS_MBCSV_V3_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "lgs.h"
+#include "lgs_mbcsv.h"
+#include "lgs_mbcsv_v2.h"
+
+/* Structures for Checkpoint data ver 3 (to be replicated at the standby) */
+
+typedef struct {
+       /* Attributes that can be updated */
+       char *logRootDirectory;
+       char *logDataGroupname;
+       uint64_t c_file_close_time_stamp; /* Time in sec for file rename */
+} lgs_ckpt_lgs_cfg_v3_t;
+
+typedef struct {
+       lgsv_ckpt_header_t header;
+       union {
+               lgs_ckpt_initialize_msg_t initialize_client;
+               lgs_ckpt_finalize_msg_v2_t finalize_client;
+               lgs_ckpt_write_log_v2_t write_log;
+               lgs_ckpt_agent_down_v2_t agent_down;
+               lgs_ckpt_stream_open_t stream_open;
+               lgs_ckpt_stream_close_v2_t stream_close;
+               lgs_ckpt_stream_cfg_v2_t stream_cfg;
+               lgs_ckpt_lgs_cfg_v3_t lgs_cfg;
+       } ckpt_rec;
+} lgsv_ckpt_msg_v3_t;
+
+uint32_t ckpt_proc_lgs_cfg_v3(lgs_cb_t *cb, void *data);
+uint32_t edp_ed_lgs_cfg_rec_v3(EDU_HDL *edu_hdl, EDU_TKN *edu_tkn,
+                                  NCSCONTEXT ptr, uint32_t *ptr_data_len,
+                                  EDU_BUF_ENV *buf_env, EDP_OP_TYPE op, 
EDU_ERR *o_err);
+uint32_t edp_ed_ckpt_msg_v3(EDU_HDL *edu_hdl, EDU_TKN *edu_tkn,
+                            NCSCONTEXT ptr, uint32_t *ptr_data_len, 
EDU_BUF_ENV *buf_env, EDP_OP_TYPE op, EDU_ERR *o_err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LGS_MBCSV_V3_H */
diff --git a/osaf/services/saf/logsv/lgs/lgs_util.c 
b/osaf/services/saf/logsv/lgs/lgs_util.c
--- a/osaf/services/saf/logsv/lgs/lgs_util.c
+++ b/osaf/services/saf/logsv/lgs/lgs_util.c
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <inttypes.h>
 #include <sys/stat.h>
+#include <grp.h>
 #include "immutil.h"
 #include "lgs.h"
 #include "lgs_util.h"
@@ -566,3 +567,88 @@ int lgs_check_path_exists_h(const char *
        TRACE_LEAVE2("rc = %d",rc);
        return rc;
 }
+
+/**
+ * Get data group GID
+ * @return: -1 if not set
+ *          gid of data group if set.
+ */
+int lgs_get_data_gid()
+{
+       char * groupname = (char *) lgs_imm_logconf_get(LGS_IMM_DATA_GROUPNAME, 
NULL);
+       if (strcmp(groupname, "") == 0){
+               return -1;
+       } else {
+               struct group *gr = getgrnam(groupname);
+               if (gr){
+                       return gr->gr_gid;
+               } else {
+                       LOG_ER("Could not get group struct for %s, %s", 
groupname, strerror(errno));
+                       return -1;
+               }
+       }
+}
+
+/**
+ * Own all log files of given stream by the data group
+ *
+ * @param: stream[in] : stream to own log files
+ * @return: 0 on success
+ *         -1 on error
+ */
+int lgs_own_log_files(log_stream_t *stream)
+{
+       lgsf_apipar_t apipar;
+       lgsf_retcode_t api_rc;
+       olfbgh_t *data_in = (olfbgh_t *) malloc(sizeof(olfbgh_t));
+       int rc = 0, n, path_len;
+
+       TRACE_ENTER2("stream %s",stream->name);
+
+       n = snprintf(data_in->file_name, SA_MAX_NAME_LENGTH, "%s", 
stream->fileName);
+       if (n >= SA_MAX_NAME_LENGTH) {
+               rc = -1;
+               LOG_WA("file_name > SA_MAX_NAME_LENGTH");
+               goto done;
+       }
+       n = snprintf(data_in->logsv_root_dir, PATH_MAX, "%s", 
lgs_cb->logsv_root_dir);
+       if (n >= PATH_MAX) {
+               rc = -1;
+               LOG_WA("logsv_root_dir > PATH_MAX");
+               goto done;
+       }
+       n = snprintf(data_in->pathName, PATH_MAX, "%s", stream->pathName);
+       if (n >= PATH_MAX) {
+               rc = -1;
+               LOG_WA("pathName > PATH_MAX");
+               goto done;
+       }
+
+       path_len =      strlen(data_in->file_name) +
+                               strlen(data_in->logsv_root_dir) +
+                               strlen(data_in->pathName);
+       if (path_len > PATH_MAX) {
+               LOG_WA("Path to log files > PATH_MAX");
+               rc = -1;
+               goto done;
+       }
+       /* Fill in API structure */
+       apipar.req_code_in = LGSF_OWN_LOGFILES;
+       apipar.data_in_size = sizeof(olfbgh_t);
+       apipar.data_in = data_in;
+       apipar.data_out_size = 0;
+       apipar.data_out = NULL;
+
+       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;
+       }
+
+done:
+       free(data_in);
+       TRACE_LEAVE2("rc = %d",rc);
+       return rc;
+}
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
@@ -60,5 +60,7 @@ extern void lgs_exit(const char *msg, Sa
 extern bool lgs_relative_path_check_ts(const char* path);
 extern int lgs_make_reldir_h(const char* path);
 extern int lgs_check_path_exists_h(const char *path_to_check);
+extern int lgs_get_data_gid();
+extern int lgs_own_log_files(log_stream_t *stream);
 
 #endif   /* ifndef __LGS_UTIL_H */


------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the 
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
Opensaf-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to