Support for store user data in SAM

Ability to in-memory storing of user data which survives between
instances of process.

Also ability needed ability for bi-directional communication between
child and parent is added.

Regards,
  Honza
commit d6f2002ec4ce9384859e0952bffc72d677df9576
Author: Jan Friesse <[email protected]>
Date:   Thu Apr 15 14:18:53 2010 +0200

    Support for store user data in SAM
    
    Ability to in-memory storing of user data which survives between
    instances of process.
    
    Also ability needed ability for bi-directional communication between
    child and parent is added.

diff --git a/trunk/include/corosync/sam.h b/trunk/include/corosync/sam.h
index bf6b069..4e60e17 100644
--- a/trunk/include/corosync/sam.h
+++ b/trunk/include/corosync/sam.h
@@ -160,6 +160,49 @@ cs_error_t sam_hc_send (void);
  */
 cs_error_t sam_hc_callback_register (sam_hc_callback_t cb);
 
+/*
+ * Return size of stored data.
+ * @param size Pointer to variable, where stored data size is returned. If
+ * nothing or NULL is stored, then 0 is returned.
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE in case you call this function before sam_init or after
+ *   sam_finalize
+ * - CS_ERR_INVALID_PARAM if size parameter is NULL
+ */
+cs_error_t sam_data_getsize (size_t *size);
+
+/*
+ * Return stored data.
+ * @param data Pointer to place, where to store data
+ * @param size Allocated size of data
+ * @return
+ * - CS_OK if no problem appeared
+ * - CS_ERR_BAD_HANDLE if you call this function before sam_init or after 
sam_finalize
+ * - CS_ERR_INVALID_PARAM if data is NULL or size is less then currently saved 
user data length
+ */
+cs_error_t sam_data_restore (
+       void *data,
+       size_t size);
+
+/*
+ * Store user data. Such stored data survives restart of child.
+ * @param data Data to store. You can use NULL to delete data
+ * @param size Size of data to store.
+ * @return
+ * - CS_OK in case no problem appeared
+ * - CS_ERR_BAD_HANDLE if you call this function before sam_init or
+ *   after sam_finalize
+ * - CS_ERR_NO_MEMORY if data is too large and malloc/realloc was not
+ *   sucesfull
+ * - CS_ERR_LIBRARY if some internal error appeared (communication with parent
+ *   process)
+ */
+cs_error_t sam_data_store (
+       const void *data,
+       size_t size);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/trunk/lib/libsam.verso b/trunk/lib/libsam.verso
index ee74734..6aba2b2 100644
--- a/trunk/lib/libsam.verso
+++ b/trunk/lib/libsam.verso
@@ -1 +1 @@
-4.1.0
+4.2.0
diff --git a/trunk/lib/sam.c b/trunk/lib/sam.c
index 9487afd..207d4f9 100644
--- a/trunk/lib/sam.c
+++ b/trunk/lib/sam.c
@@ -38,6 +38,7 @@
 
 #include <config.h>
 
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -70,7 +71,13 @@ enum sam_internal_status_t {
 enum sam_command_t {
        SAM_COMMAND_START,
        SAM_COMMAND_STOP,
-       SAM_COMMAND_HB
+       SAM_COMMAND_HB,
+       SAM_COMMAND_DATA_STORE,
+};
+
+enum sam_reply_t {
+       SAM_REPLY_OK,
+       SAM_REPLY_ERROR,
 };
 
 enum sam_parent_action_t {
@@ -85,14 +92,20 @@ static struct {
        sam_recovery_policy_t recovery_policy;
        enum sam_internal_status_t internal_status;
        unsigned int instance_id;
-       int parent_fd;
+       int child_fd_out;
+       int child_fd_in;
        int term_send;
        int warn_signal;
+       int am_i_child;
 
        sam_hc_callback_t hc_callback;
        pthread_t cb_thread;
        int cb_rpipe_fd, cb_wpipe_fd;
        int cb_registered;
+
+       void *user_data;
+       size_t user_data_size;
+       size_t user_data_allocated;
 } sam_internal_data;
 
 cs_error_t sam_initialize (
@@ -115,6 +128,12 @@ cs_error_t sam_initialize (
 
        sam_internal_data.warn_signal = SIGTERM;
 
+       sam_internal_data.am_i_child = 0;
+
+       sam_internal_data.user_data = NULL;
+       sam_internal_data.user_data_size = 0;
+       sam_internal_data.user_data_allocated = 0;
+
        return (CS_OK);
 }
 
@@ -132,7 +151,8 @@ static size_t sam_safe_write (
        bytes_write = 0;
 
        do {
-               tmp_bytes_write = write (d, (const char *)buf + bytes_write, 
nbyte - bytes_write);
+               tmp_bytes_write = write (d, (const char *)buf + bytes_write,
+                       (nbyte - bytes_write > SSIZE_MAX) ? SSIZE_MAX : nbyte - 
bytes_write);
 
                if (tmp_bytes_write == -1) {
                        if (!(errno == EAGAIN || errno == EINTR))
@@ -142,7 +162,176 @@ static size_t sam_safe_write (
                }
        } while (bytes_write != nbyte);
 
-       return bytes_write;
+       return (bytes_write);
+}
+
+/*
+ * Wrapper on top of read(2) function. It handles EAGAIN and EINTR states and 
reads whole buffer if possible.
+ */
+static size_t sam_safe_read (
+       int d,
+       void *buf,
+       size_t nbyte)
+{
+       ssize_t bytes_read;
+       ssize_t tmp_bytes_read;
+
+       bytes_read = 0;
+
+       do {
+               tmp_bytes_read = read (d, (char *)buf + bytes_read,
+                       (nbyte - bytes_read > SSIZE_MAX) ? SSIZE_MAX : nbyte - 
bytes_read);
+
+               if (tmp_bytes_read == -1) {
+                       if (!(errno == EAGAIN || errno == EINTR))
+                               return -1;
+               } else {
+                       bytes_read += tmp_bytes_read;
+               }
+
+       } while (bytes_read != nbyte && tmp_bytes_read != 0);
+
+       return (bytes_read);
+}
+
+cs_error_t sam_data_getsize (size_t *size)
+{
+       if (size == NULL) {
+               return (CS_ERR_INVALID_PARAM);
+       }
+
+       if (sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_INITIALIZED &&
+               sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_REGISTERED &&
+               sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_STARTED) {
+
+               return (CS_ERR_BAD_HANDLE);
+       }
+
+       *size = sam_internal_data.user_data_size;
+
+       return (CS_OK);
+}
+
+cs_error_t sam_data_restore (
+       void *data,
+       size_t size)
+{
+       if (data == NULL) {
+               return (CS_ERR_INVALID_PARAM);
+       }
+
+       if (sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_INITIALIZED &&
+               sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_REGISTERED &&
+               sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_STARTED) {
+
+               return (CS_ERR_BAD_HANDLE);
+       }
+
+       if (sam_internal_data.user_data_size == 0) {
+               return (CS_OK);
+       }
+
+       if (size < sam_internal_data.user_data_size) {
+               return (CS_ERR_INVALID_PARAM);
+       }
+
+       memcpy (data, sam_internal_data.user_data, 
sam_internal_data.user_data_size);
+
+       return (CS_OK);
+}
+
+cs_error_t sam_data_store (
+       const void *data,
+       size_t size)
+{
+       cs_error_t err;
+       char command;
+       char *new_data;
+       char reply;
+
+       if (sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_INITIALIZED &&
+               sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_REGISTERED &&
+               sam_internal_data.internal_status != 
SAM_INTERNAL_STATUS_STARTED) {
+
+               return (CS_ERR_BAD_HANDLE);
+       }
+
+       if (sam_internal_data.user_data_allocated < size) {
+               if ((new_data = realloc (sam_internal_data.user_data, size)) == 
NULL) {
+                       return (CS_ERR_NO_MEMORY);
+               }
+
+               sam_internal_data.user_data_allocated = size;
+       } else {
+               new_data = sam_internal_data.user_data;
+       }
+
+       if (data == NULL) {
+               size = 0;
+       }
+
+       if (sam_internal_data.am_i_child) {
+               /*
+                * We are child so we must send data to parent
+                */
+               command = SAM_COMMAND_DATA_STORE;
+               if (sam_safe_write (sam_internal_data.child_fd_out, &command, 
sizeof (command)) != sizeof (command)) {
+                       return (CS_ERR_LIBRARY);
+               }
+
+               if (sam_safe_write (sam_internal_data.child_fd_out, &size, 
sizeof (size)) != sizeof (size)) {
+                       return (CS_ERR_LIBRARY);
+               }
+
+               if (data != NULL && sam_safe_write 
(sam_internal_data.child_fd_out, data, size) != size) {
+                       return (CS_ERR_LIBRARY);
+               }
+
+               /*
+                * And wait for reply
+                */
+               if (sam_safe_read (sam_internal_data.child_fd_in, &reply, 
sizeof (reply)) != sizeof (reply)) {
+                       return (CS_ERR_LIBRARY);
+               }
+
+               switch (reply) {
+               case SAM_REPLY_ERROR:
+                       /*
+                        * Read error and return that
+                        */
+                       if (sam_safe_read (sam_internal_data.child_fd_in, &err, 
sizeof (err)) != sizeof (err)) {
+                               return (CS_ERR_LIBRARY);
+                       }
+
+                       return (err);
+                       break;
+               case SAM_REPLY_OK:
+                       /*
+                        * Everything correct
+                        */
+                       break;
+               default:
+                       return (CS_ERR_LIBRARY);
+                       break;
+               }
+       }
+
+       /*
+        * We are parent or we received OK reply from parent -> do required 
action
+        */
+       if (data == NULL) {
+               free (sam_internal_data.user_data);
+               sam_internal_data.user_data = NULL;
+               sam_internal_data.user_data_allocated = 0;
+               sam_internal_data.user_data_size = 0;
+       } else {
+               sam_internal_data.user_data = new_data;
+               sam_internal_data.user_data_size = size;
+
+               memcpy (sam_internal_data.user_data, data, size);
+       }
+
+       return (CS_OK);
 }
 
 cs_error_t sam_start (void)
@@ -155,11 +344,11 @@ cs_error_t sam_start (void)
 
        command = SAM_COMMAND_START;
 
-       if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1)
+       if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof 
(command)) != sizeof (command))
                return (CS_ERR_LIBRARY);
 
        if (sam_internal_data.hc_callback)
-               if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 1) 
== -1)
+               if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 
sizeof (command)) != sizeof (command))
                        return (CS_ERR_LIBRARY);
 
        sam_internal_data.internal_status = SAM_INTERNAL_STATUS_STARTED;
@@ -177,11 +366,11 @@ cs_error_t sam_stop (void)
 
        command = SAM_COMMAND_STOP;
 
-       if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1)
+       if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof 
(command)) != sizeof (command))
                return (CS_ERR_LIBRARY);
 
        if (sam_internal_data.hc_callback)
-               if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 1) 
== -1)
+               if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, 
sizeof (command)) != sizeof (command))
                        return (CS_ERR_LIBRARY);
 
        sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
@@ -199,7 +388,7 @@ cs_error_t sam_hc_send (void)
 
        command = SAM_COMMAND_HB;
 
-       if (sam_safe_write (sam_internal_data.parent_fd, &command, 1) == -1)
+       if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof 
(command)) != sizeof (command))
                return (CS_ERR_LIBRARY);
 
        return (CS_OK);
@@ -223,6 +412,8 @@ cs_error_t sam_finalize (void)
 
        sam_internal_data.internal_status = SAM_INTERNAL_STATUS_FINALIZED;
 
+       free (sam_internal_data.user_data);
+
 exit_error:
        return (CS_OK);
 }
@@ -241,7 +432,69 @@ cs_error_t sam_warn_signal_set (int warn_signal)
        return (CS_OK);
 }
 
-static enum sam_parent_action_t sam_parent_handler (int pipe_fd, pid_t 
child_pid)
+static cs_error_t sam_parent_data_store (
+       int parent_fd_in,
+       int parent_fd_out)
+{
+       char reply;
+       char *user_data;
+       ssize_t size;
+       cs_error_t err;
+
+       err = CS_OK;
+       user_data = NULL;
+
+       if (sam_safe_read (parent_fd_in, &size, sizeof (size)) != sizeof 
(size)) {
+               err = CS_ERR_LIBRARY;
+               goto error_reply;
+       }
+
+       if (size > 0) {
+               user_data = malloc (size);
+               if (user_data == NULL) {
+                       err = CS_ERR_NO_MEMORY;
+                       goto error_reply;
+               }
+
+               if (sam_safe_read (parent_fd_in, user_data, size) != size) {
+                       err = CS_ERR_LIBRARY;
+                       goto free_error_reply;
+               }
+       }
+
+       err = sam_data_store (user_data, size);
+       if (err != CS_OK) {
+               goto free_error_reply;
+       }
+
+       reply = SAM_REPLY_OK;
+       if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof 
(reply)) {
+               err = CS_ERR_LIBRARY;
+               goto free_error_reply;
+       }
+
+       free (user_data);
+
+       return (CS_OK);
+
+free_error_reply:
+       free (user_data);
+error_reply:
+       reply = SAM_REPLY_ERROR;
+       if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof 
(reply)) {
+               return (CS_ERR_LIBRARY);
+       }
+       if (sam_safe_write (parent_fd_out, &err, sizeof (err)) != sizeof (err)) 
{
+               return (CS_ERR_LIBRARY);
+       }
+
+       return (err);
+}
+
+static enum sam_parent_action_t sam_parent_handler (
+       int parent_fd_in,
+       int parent_fd_out,
+       pid_t child_pid)
 {
        int poll_error;
        int action;
@@ -256,7 +509,7 @@ static enum sam_parent_action_t sam_parent_handler (int 
pipe_fd, pid_t child_pid
        action = SAM_PARENT_ACTION_CONTINUE;
 
        while (action == SAM_PARENT_ACTION_CONTINUE) {
-               pfds.fd = pipe_fd;
+               pfds.fd = parent_fd_in;
                pfds.events = POLLIN;
                pfds.revents = 0;
 
@@ -309,7 +562,7 @@ static enum sam_parent_action_t sam_parent_handler (int 
pipe_fd, pid_t child_pid
                        /*
                         *  We have EOF or command in pipe
                         */
-                       bytes_read = read (pipe_fd, &command, 1);
+                       bytes_read = sam_safe_read (parent_fd_in, &command, 1);
 
                        if (bytes_read == 0) {
                                /*
@@ -324,37 +577,33 @@ static enum sam_parent_action_t sam_parent_handler (int 
pipe_fd, pid_t child_pid
                        }
 
                        if (bytes_read == -1) {
-                               /*
-                                * Something really bad happened in read side
-                                */
-                               if (errno == EAGAIN || errno == EINTR) {
-                                       continue;
-                               }
-
                                action = SAM_PARENT_ACTION_ERROR;
                                goto action_exit;
                        }
 
                        /*
-                        * We have read command -> take status
+                        * We have read command
                         */
-                       switch (status) {
-                       case 0:
-                               /*
-                                *  Not started yet
-                                */
-                               if (command == SAM_COMMAND_START)
+                       switch (command) {
+                       case SAM_COMMAND_START:
+                               if (status == 0) {
+                                       /*
+                                        *  Not started yet
+                                        */
                                        status = 1;
-                       break;
-
-                       case 1:
-                               /*
-                                *  Started
-                                */
-                               if (command == SAM_COMMAND_STOP)
+                               }
+                               break;
+                       case SAM_COMMAND_STOP:
+                               if (status == 1) {
+                                       /*
+                                        *  Started
+                                        */
                                        status = 0;
-                       break;
-
+                               }
+                               break;
+                       case SAM_COMMAND_DATA_STORE:
+                               sam_parent_data_store (parent_fd_in, 
parent_fd_out);
+                               break;
                        }
                } /* select_error > 0 */
        } /* action == SAM_PARENT_ACTION_CONTINUE */
@@ -369,7 +618,7 @@ cs_error_t sam_register (
        cs_error_t error;
        pid_t pid;
        int pipe_error;
-       int pipe_fd[2];
+       int pipe_fd_out[2], pipe_fd_in[2];
        enum sam_parent_action_t action;
        int child_status;
 
@@ -380,12 +629,15 @@ cs_error_t sam_register (
        error = CS_OK;
 
        while (1) {
-               pipe_error = pipe (pipe_fd);
+               if ((pipe_error = pipe (pipe_fd_out)) != 0) {
+                       error = CS_ERR_LIBRARY;
+                       goto error_exit;
+               }
+
+               if ((pipe_error = pipe (pipe_fd_in)) != 0) {
+                       close (pipe_fd_out[0]);
+                       close (pipe_fd_out[1]);
 
-               if (pipe_error != 0) {
-                       /*
-                        *  Pipe creation error
-                        */
                        error = CS_ERR_LIBRARY;
                        goto error_exit;
                }
@@ -410,12 +662,16 @@ cs_error_t sam_register (
                        /*
                         *  Child process
                         */
-                       close (pipe_fd[0]);
+                       close (pipe_fd_out[0]);
+                       close (pipe_fd_in[1]);
+
+                       sam_internal_data.child_fd_out = pipe_fd_out[1];
+                       sam_internal_data.child_fd_in = pipe_fd_in[0];
 
-                       sam_internal_data.parent_fd = pipe_fd[1];
                        if (instance_id)
                                *instance_id = sam_internal_data.instance_id;
 
+                       sam_internal_data.am_i_child = 1;
                        sam_internal_data.internal_status = 
SAM_INTERNAL_STATUS_REGISTERED;
 
                        goto error_exit;
@@ -423,11 +679,13 @@ cs_error_t sam_register (
                        /*
                         *  Parent process
                         */
-                       close (pipe_fd[1]);
+                       close (pipe_fd_out[1]);
+                       close (pipe_fd_in[0]);
 
-                       action = sam_parent_handler (pipe_fd[0], pid);
+                       action = sam_parent_handler (pipe_fd_out[0], 
pipe_fd_in[1], pid);
 
-                       close (pipe_fd[0]);
+                       close (pipe_fd_out[0]);
+                       close (pipe_fd_in[1]);
 
                        if (action == SAM_PARENT_ACTION_ERROR) {
                                error = CS_ERR_LIBRARY;
@@ -498,7 +756,7 @@ static void *hc_callback_thread (void *unused_param)
                }
 
                if (poll_error > 0) {
-                       bytes_readed = read (sam_internal_data.cb_rpipe_fd, 
&command, 1);
+                       bytes_readed = sam_safe_read 
(sam_internal_data.cb_rpipe_fd, &command, 1);
 
                        if (bytes_readed > 0) {
                                if (status == 0 && command == SAM_COMMAND_START)
diff --git a/trunk/man/Makefile.am b/trunk/man/Makefile.am
index da01c2e..5817a1a 100644
--- a/trunk/man/Makefile.am
+++ b/trunk/man/Makefile.am
@@ -100,6 +100,9 @@ dist_man_MANS = \
        votequorum_qdisk_unregister.3 \
        votequorum_setexpected.3 \
        votequorum_setvotes.3 \
+       sam_data_getsize.3 \
+       sam_data_restore.3 \
+       sam_data_store.3 \
        sam_finalize.3 \
        sam_hc_callback_register.3 \
        sam_hc_send.3 \
diff --git a/trunk/man/sam_data_getsize.3 b/trunk/man/sam_data_getsize.3
new file mode 100644
index 0000000..33d527e
--- /dev/null
+++ b/trunk/man/sam_data_getsize.3
@@ -0,0 +1,68 @@
+.\"/*
+.\" * Copyright (c) 2010 Red Hat, Inc.
+.\" *
+.\" * All rights reserved.
+.\" *
+.\" * Author: Jan Friesse ([email protected])
+.\" *
+.\" * This software licensed under BSD license, the text of which follows:
+.\" *
+.\" * Redistribution and use in source and binary forms, with or without
+.\" * modification, are permitted provided that the following conditions are 
met:
+.\" *
+.\" * - Redistributions of source code must retain the above copyright notice,
+.\" *   this list of conditions and the following disclaimer.
+.\" * - Redistributions in binary form must reproduce the above copyright 
notice,
+.\" *   this list of conditions and the following disclaimer in the 
documentation
+.\" *   and/or other materials provided with the distribution.
+.\" * - Neither the name of the Red Hat, Inc. nor the names of its
+.\" *   contributors may be used to endorse or promote products derived from 
this
+.\" *   software without specific prior written permission.
+.\" *
+.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
IS"
+.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE
+.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+.\" * THE POSSIBILITY OF SUCH DAMAGE.
+.\" */
+.TH "SAM_DATA_GETSIZE" 3 "04/15/2010" "corosync Man Page" "Corosync Cluster 
Engine Programmer's Manual"
+
+.SH NAME
+.P
+sam_data_getsize \- Return size of stored data in bytes
+
+.SH SYNOPSIS
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_data_getsize (size_t *\fIsize\fB);\fR
+
+.SH DESCRIPTION
+.P
+The \fBsam_data_getsize\fR function is used to return size of stored
+data. Size is returned in bytes. If user data is NULL, zero is returned.
+Function is intended to be used before \fBsam_data_restore(3)\fR call to
+properly allocate buffer for restored data.
+
+.SH RETURN VALUE
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
+.SH ERRORS
+.TP
+CS_ERR_BAD_HANDLE
+component was not initialized by calling \fBsam_initialize(3)\fR or it was 
finalized.
+.TP
+CS_ERR_INVALID_PARAM
+size parameter is NULL
+
+.SH "SEE ALSO"
+.BR sam_data_store (3),
+.BR sam_data_restore (3)
diff --git a/trunk/man/sam_data_restore.3 b/trunk/man/sam_data_restore.3
new file mode 100644
index 0000000..32b816a
--- /dev/null
+++ b/trunk/man/sam_data_restore.3
@@ -0,0 +1,77 @@
+.\"/*
+.\" * Copyright (c) 2010 Red Hat, Inc.
+.\" *
+.\" * All rights reserved.
+.\" *
+.\" * Author: Jan Friesse ([email protected])
+.\" *
+.\" * This software licensed under BSD license, the text of which follows:
+.\" *
+.\" * Redistribution and use in source and binary forms, with or without
+.\" * modification, are permitted provided that the following conditions are 
met:
+.\" *
+.\" * - Redistributions of source code must retain the above copyright notice,
+.\" *   this list of conditions and the following disclaimer.
+.\" * - Redistributions in binary form must reproduce the above copyright 
notice,
+.\" *   this list of conditions and the following disclaimer in the 
documentation
+.\" *   and/or other materials provided with the distribution.
+.\" * - Neither the name of the Red Hat, Inc. nor the names of its
+.\" *   contributors may be used to endorse or promote products derived from 
this
+.\" *   software without specific prior written permission.
+.\" *
+.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
IS"
+.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE
+.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+.\" * THE POSSIBILITY OF SUCH DAMAGE.
+.\" */
+.TH "SAM_DATA_RESTORE" 3 "04/15/2010" "corosync Man Page" "Corosync Cluster 
Engine Programmer's Manual"
+
+.SH NAME
+.P
+sam_data_restore \- Restore previously saved user data
+
+.SH SYNOPSIS
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_data_restore (void *\fIdata\fB, size_t \fIsize\fB);\fR
+
+.SH DESCRIPTION
+.P
+The \fBsam_data_restore\fR function is used to restore data, previously
+saved by calling \fBsam_data_store(3)\fR. Such data survives between instances.
+
+.P
+The \fIdata\fR parameter is pointer to memory initialized by caller. Stored 
data
+are copied there. This also means, that caller is responsible for freeing 
memory.
+
+.P
+The \fIsize\fR parameter is length of \fIdata\fR. This one must be at least 
same
+length as previously stored data otherwise error is returned. Parameter can
+be larger but only stored data size bytes are changed.
+
+Use \fBsam_data_getsize(3)\fR to find out length of stored data.
+
+.SH RETURN VALUE
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
+.SH ERRORS
+.TP
+CS_ERR_BAD_HANDLE
+component was not initialized by calling \fBsam_initialize(3)\fR or it was 
finalized.
+.TP
+CS_ERR_INVALID_PARAM
+data parameter is NULL or size is less then currently stored data length
+
+.SH "SEE ALSO"
+.BR sam_data_getsize (3),
+.BR sam_data_store (3)
diff --git a/trunk/man/sam_data_store.3 b/trunk/man/sam_data_store.3
new file mode 100644
index 0000000..6e90651
--- /dev/null
+++ b/trunk/man/sam_data_store.3
@@ -0,0 +1,83 @@
+.\"/*
+.\" * Copyright (c) 2010 Red Hat, Inc.
+.\" *
+.\" * All rights reserved.
+.\" *
+.\" * Author: Jan Friesse ([email protected])
+.\" *
+.\" * This software licensed under BSD license, the text of which follows:
+.\" *
+.\" * Redistribution and use in source and binary forms, with or without
+.\" * modification, are permitted provided that the following conditions are 
met:
+.\" *
+.\" * - Redistributions of source code must retain the above copyright notice,
+.\" *   this list of conditions and the following disclaimer.
+.\" * - Redistributions in binary form must reproduce the above copyright 
notice,
+.\" *   this list of conditions and the following disclaimer in the 
documentation
+.\" *   and/or other materials provided with the distribution.
+.\" * - Neither the name of the Red Hat, Inc. nor the names of its
+.\" *   contributors may be used to endorse or promote products derived from 
this
+.\" *   software without specific prior written permission.
+.\" *
+.\" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
IS"
+.\" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE
+.\" * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+.\" * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+.\" * THE POSSIBILITY OF SUCH DAMAGE.
+.\" */
+.TH "SAM_DATA_STORE" 3 "04/15/2010" "corosync Man Page" "Corosync Cluster 
Engine Programmer's Manual"
+
+.SH NAME
+.P
+sam_data_store \- Store user data
+
+.SH SYNOPSIS
+.P
+\fB#include <corosync/sam.h>\fR
+
+.P
+\fBcs_error_t sam_data_store (const void *\fIdata\fB, size_t \fIsize\fB);\fR
+
+.SH DESCRIPTION
+.P
+The \fBsam_data_store\fR function is used to store data, which survives between
+instances.
+
+.P
+The \fIdata\fR parameter is pointer to memory with data to store. Data
+are stored in newly allocated memory inside library, so caller can safely 
remove
+them after call of function.
+
+You can use NULL as parameter to remove and free previously saved data. In this
+case \fIsize\fR argument is ignored.
+
+.P
+The \fIsize\fR parameter is length of \fIdata\fR.
+
+Use \fBsam_data_getsize(3)\fR to find out length of stored data and 
\fBsam_data_restore(3)\fR
+to restore stored data.
+
+.SH RETURN VALUE
+.P
+This call return CS_OK value if successful, otherwise and error is returned.
+
+.SH ERRORS
+.TP
+CS_ERR_BAD_HANDLE
+component was not initialized by calling \fBsam_initialize(3)\fR or it was 
finalized.
+.TP
+CS_ERR_NO_MEMORY
+internal  malloc/realloc failed because data are too large
+.TP
+CS_ERR_LIBRARY
+some internal error appeared (mostly because communication with parent process 
failed)
+
+.SH "SEE ALSO"
+.BR sam_data_getsize (3),
+.BR sam_data_restore (3)
diff --git a/trunk/man/sam_overview.8 b/trunk/man/sam_overview.8
index 4547212..b670723 100644
--- a/trunk/man/sam_overview.8
+++ b/trunk/man/sam_overview.8
@@ -115,9 +115,19 @@ or add timers to the active process to signal a 
healthcheck operation is
 successful.  To use event driven healthchecking,
 the \fBsam_hc_callback_register(3)\fR function should be executed.
 
+.SH Storing user data
+.P
+Sometimes there is need to store some data, which survives between instances.
+One can in such case use files, databases, ... or much simpler in memory 
solution
+presented by \fBsam_data_store(3)\fR, \fBsam_data_restore(3)\fR and 
\fBsam_data_getsize(3)\fR
+functions.
+
 .SH BUGS
 .SH "SEE ALSO"
 .BR sam_initialize (3),
+.BR sam_data_getsize (3),
+.BR sam_data_restore (3),
+.BR sam_data_store (3),
 .BR sam_finalize (3),
 .BR sam_start (3),
 .BR sam_stop (3),
diff --git a/trunk/test/testsam.c b/trunk/test/testsam.c
index ae9a4cf..bb21169 100644
--- a/trunk/test/testsam.c
+++ b/trunk/test/testsam.c
@@ -46,10 +46,11 @@
 #include <corosync/corotypes.h>
 #include <corosync/sam.h>
 #include <signal.h>
+#include <string.h>
 #include <sys/wait.h>
 
 static int test2_sig_delivered = 0;
-static int test4_hc_cb_count = 0;
+static int test5_hc_cb_count = 0;
 
 /*
  * First test will just register SAM, with policy restart. First instance will
@@ -273,11 +274,262 @@ static int test3 (void) {
 
 }
 
-static int test4_hc_cb (void)
+/*
+ * Test sam_data_store, sam_data_restore and sam_data_getsize
+ */
+static int test4 (void)
+{
+       size_t size;
+       cs_error_t err;
+       int i;
+       unsigned int instance_id;
+       char saved_data[128];
+       char saved_data2[128];
+
+       printf ("%s: sam_data_getsize 1\n", __FUNCTION__);
+       err = sam_data_getsize (&size);
+       if (err != CS_ERR_BAD_HANDLE) {
+               fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error 
returned %d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_data_getsize 2\n", __FUNCTION__);
+       err = sam_data_getsize (NULL);
+       if (err != CS_ERR_INVALID_PARAM) {
+               fprintf (stderr, "Test should return CS_ERR_INVALID_PARAM. 
Error returned %d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_data_store 1\n", __FUNCTION__);
+       err = sam_data_store (NULL, 0);
+       if (err != CS_ERR_BAD_HANDLE) {
+               fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error 
returned %d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_data_restore 1\n", __FUNCTION__);
+       err = sam_data_restore (saved_data, sizeof (saved_data));
+       if (err != CS_ERR_BAD_HANDLE) {
+               fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error 
returned %d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_initialize\n", __FUNCTION__);
+       err = sam_initialize (0, SAM_RECOVERY_POLICY_RESTART);
+       if (err != CS_OK) {
+               fprintf (stderr, "Can't initialize SAM API. Error %d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_data_getsize 3\n", __FUNCTION__);
+       err = sam_data_getsize (&size);
+       if (err != CS_OK) {
+               fprintf (stderr, "Test should return CS_ERR_BAD_HANDLE. Error 
returned %d\n", err);
+               return 1;
+       }
+       if (size != 0) {
+               fprintf (stderr, "Test should return size of 0. Returned %x\n", 
size);
+               return 1;
+       }
+
+       printf ("%s: sam_data_restore 2\n", __FUNCTION__);
+       err = sam_data_restore (NULL, sizeof (saved_data));
+       if (err != CS_ERR_INVALID_PARAM) {
+               fprintf (stderr, "Test should return CS_ERR_INVALID_PARAM. 
Error returned %d\n", err);
+               return 1;
+       }
+
+       /*
+        * Store some real data
+        */
+       for (i = 0; i < sizeof (saved_data); i++) {
+               saved_data[i] = (char)(i + 5);
+       }
+
+       printf ("%s: sam_data_store 2\n", __FUNCTION__);
+       err = sam_data_store (saved_data, sizeof (saved_data));
+       if (err != CS_OK) {
+               fprintf (stderr, "Test should return CS_OK. Error returned 
%d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_data_getsize 4\n", __FUNCTION__);
+       err = sam_data_getsize (&size);
+       if (err != CS_OK) {
+               fprintf (stderr, "Test should return CS_OK. Error returned 
%d\n", err);
+               return 1;
+       }
+       if (size != sizeof (saved_data)) {
+               fprintf (stderr, "Test should return size of 0. Returned %x\n", 
size);
+               return 1;
+       }
+
+       printf ("%s: sam_data_restore 3\n", __FUNCTION__);
+       err = sam_data_restore (saved_data2, sizeof (saved_data2) - 1);
+       if (err != CS_ERR_INVALID_PARAM) {
+               fprintf (stderr, "Test should return CS_ERR_INVALID_PARAM. 
Error returned %d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_data_restore 4\n", __FUNCTION__);
+       err = sam_data_restore (saved_data2, sizeof (saved_data2));
+       if (err != CS_OK) {
+               fprintf (stderr, "Test should return CS_OK. Error returned 
%d\n", err);
+               return 1;
+       }
+
+       if (memcmp (saved_data, saved_data2, sizeof (saved_data2)) != 0) {
+               fprintf (stderr, "Retored data are not same\n");
+               return 1;
+       }
+
+       memset (saved_data2, 0, sizeof (saved_data2));
+
+       printf ("%s: sam_data_store 3\n", __FUNCTION__);
+       err = sam_data_store (NULL, 1);
+       if (err != CS_OK) {
+               fprintf (stderr, "Test should return CS_OK. Error returned 
%d\n", err);
+               return 1;
+       }
+
+       printf ("%s: sam_data_getsize 5\n", __FUNCTION__);
+       err = sam_data_getsize (&size);
+       if (err != CS_OK) {
+               fprintf (stderr, "Test should return CS_OK. Error returned 
%d\n", err);
+               return 1;
+       }
+       if (size != 0) {
+               fprintf (stderr, "Test should return size of 0. Returned %x\n", 
size);
+               return 1;
+       }
+
+       printf ("%s: sam_data_store 4\n", __FUNCTION__);
+       err = sam_data_store (saved_data, sizeof (saved_data));
+       if (err != CS_OK) {
+               fprintf (stderr, "Test should return CS_OK. Error returned 
%d\n", err);
+               return 1;
+       }
+
+       printf ("%s: register\n", __FUNCTION__);
+       err = sam_register (&instance_id);
+       if (err != CS_OK) {
+               fprintf (stderr, "Can't register. Error %d\n", err);
+               return 1;
+       }
+
+       if (instance_id == 1) {
+               printf ("%s iid %d: sam_start\n", __FUNCTION__, instance_id);
+               err = sam_start ();
+               if (err != CS_OK) {
+                       fprintf (stderr, "Can't start hc. Error %d\n", err);
+                       return 1;
+               }
+
+               printf ("%s iid %d: sam_data_getsize 6\n", __FUNCTION__, 
instance_id);
+               err = sam_data_getsize (&size);
+               if (err != CS_OK) {
+                       fprintf (stderr, "Test should return CS_OK. Error 
returned %d\n", err);
+                       return 1;
+               }
+               if (size != sizeof (saved_data2)) {
+                       fprintf (stderr, "Test should return size of 0. 
Returned %x\n", size);
+                       return 1;
+               }
+
+               printf ("%s iid %d: sam_data_restore 5\n", __FUNCTION__, 
instance_id);
+               err = sam_data_restore (saved_data2, sizeof (saved_data2));
+               if (err != CS_OK) {
+                       fprintf (stderr, "Test should return CS_OK. Error 
returned %d\n", err);
+                       return 1;
+               }
+
+               if (memcmp (saved_data, saved_data2, sizeof (saved_data2)) != 
0) {
+                       fprintf (stderr, "Retored data are not same\n");
+                       return 1;
+               }
+
+               for (i = 0; i < sizeof (saved_data); i++) {
+                       saved_data[i] = (char)(i - 5);
+               }
+
+               printf ("%s iid %d: sam_data_store 5\n", __FUNCTION__, 
instance_id);
+               err = sam_data_store (saved_data, sizeof (saved_data) - 7);
+               if (err != CS_OK) {
+                       fprintf (stderr, "Test should return CS_OK. Error 
returned %d\n", err);
+                       return 1;
+               }
+
+               exit (1);
+       }
+
+       if (instance_id == 2) {
+               printf ("%s iid %d: sam_start\n", __FUNCTION__, instance_id);
+               err = sam_start ();
+               if (err != CS_OK) {
+                       fprintf (stderr, "Can't start hc. Error %d\n", err);
+                       return 1;
+               }
+
+               printf ("%s iid %d: sam_data_getsize 7\n", __FUNCTION__, 
instance_id);
+               err = sam_data_getsize (&size);
+               if (err != CS_OK) {
+                       fprintf (stderr, "Test should return CS_OK. Error 
returned %d\n", err);
+                       return 1;
+               }
+               if (size != sizeof (saved_data2) - 7) {
+                       fprintf (stderr, "Test should return size of 0. 
Returned %x\n", size);
+                       return 1;
+               }
+
+               printf ("%s iid %d: sam_data_restore 6\n", __FUNCTION__, 
instance_id);
+               err = sam_data_restore (saved_data2, sizeof (saved_data2));
+               if (err != CS_OK) {
+                       fprintf (stderr, "Test should return CS_OK. Error 
returned %d\n", err);
+                       return 1;
+               }
+
+               for (i = 0; i < sizeof (saved_data); i++) {
+                       saved_data[i] = (char)(i - 5);
+               }
+
+               if (memcmp (saved_data, saved_data2, sizeof (saved_data2) - 7) 
!= 0) {
+                       fprintf (stderr, "Retored data are not same\n");
+                       return 1;
+               }
+
+               printf ("%s iid %d: sam_data_store 6\n", __FUNCTION__, 
instance_id);
+               err = sam_data_store (NULL, 0);
+               if (err != CS_OK) {
+                       fprintf (stderr, "Test should return CS_OK. Error 
returned %d\n", err);
+                       return 1;
+               }
+
+               exit (1);
+       }
+
+       if (instance_id == 3) {
+               printf ("%s iid %d: sam_data_getsize 8\n", __FUNCTION__, 
instance_id);
+               err = sam_data_getsize (&size);
+               if (err != CS_OK) {
+                       fprintf (stderr, "Test should return CS_OK. Error 
returned %d\n", err);
+                       return 1;
+               }
+               if (size != 0) {
+                       fprintf (stderr, "Test should return size of 0. 
Returned %x\n", size);
+                       return 1;
+               }
+       }
+
+       return (0);
+}
+
+static int test5_hc_cb (void)
 {
-       printf ("%s %d\n", __FUNCTION__, ++test4_hc_cb_count);
+       printf ("%s %d\n", __FUNCTION__, ++test5_hc_cb_count);
+
+       sam_data_store (&test5_hc_cb_count, sizeof (test5_hc_cb_count));
 
-       if (test4_hc_cb_count > 10)
+       if (test5_hc_cb_count > 10)
                return 1;
 
        return 0;
@@ -285,10 +537,11 @@ static int test4_hc_cb (void)
 /*
  * Test event driven healtchecking.
  */
-static int test4 (void)
+static int test5 (void)
 {
        cs_error_t error;
        unsigned int instance_id;
+       int hc_cb_count;
 
        printf ("%s: initialize\n", __FUNCTION__);
        error = sam_initialize (100, SAM_RECOVERY_POLICY_RESTART);
@@ -305,7 +558,7 @@ static int test4 (void)
 
        if (instance_id == 1) {
                printf ("%s iid %d: hc callback register\n", __FUNCTION__, 
instance_id);
-               error = sam_hc_callback_register (test4_hc_cb);
+               error = sam_hc_callback_register (test5_hc_cb);
                if (error != CS_OK) {
                        fprintf (stderr, "Can't register hc cb. Error %d\n", 
error);
                        return 1;
@@ -326,12 +579,25 @@ static int test4 (void)
        }
 
        if (instance_id == 2) {
+               error = sam_data_restore (&hc_cb_count, sizeof (hc_cb_count));
+               if (error != CS_OK) {
+                       fprintf (stderr, "sam_data_restore should return CS_OK. 
Error returned %d\n", error);
+                       return 1;
+               }
+
+               if (hc_cb_count != 11) {
+                       fprintf (stderr, "%s iid %d: Premature killed. 
hc_cb_count should be 11 and it is %d\n",
+                               __FUNCTION__, instance_id - 1, hc_cb_count);
+                       return 1;
+
+               }
                return 0;
        }
 
        return 1;
 }
 
+
 int main(int argc, char *argv[])
 {
        pid_t pid;
@@ -347,17 +613,14 @@ int main(int argc, char *argv[])
        }
 
        if (pid == 0) {
-               err = test1 ();
-
-               fprintf (stderr, "test1 %s\n", (err == 0 ? "passed" : 
"failed"));
-               if (err != 0)
-                       all_passed = 0;
-
-               return err;
+               return (test1 ());
        }
 
-       waitpid (pid, NULL, 0);
+       waitpid (pid, &stat, 0);
 
+       fprintf (stderr, "test1 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : 
"failed"));
+       if (WEXITSTATUS (stat) != 0)
+               all_passed = 0;
 
        pid = fork ();
 
@@ -386,15 +649,31 @@ int main(int argc, char *argv[])
        }
 
        if (pid == 0) {
-               err = test3 ();
+               return (test3 ());
+       }
 
-               fprintf (stderr, "test3 %s\n", (err == 0 ? "passed" : 
"failed"));
-               if (err != 0)
-                       all_passed = 0;
-               return err;
+       waitpid (pid, &stat, 0);
+
+       fprintf (stderr, "test3 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : 
"failed"));
+       if (WEXITSTATUS (stat) != 0)
+               all_passed = 0;
+
+       pid = fork ();
+
+       if (pid == -1) {
+               fprintf (stderr, "Can't fork\n");
+               return 1;
        }
 
-       waitpid (pid, NULL, 0);
+       if (pid == 0) {
+               return (test4 ());
+       }
+
+       waitpid (pid, &stat, 0);
+
+       fprintf (stderr, "test4 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : 
"failed"));
+       if (WEXITSTATUS (stat) != 0)
+               all_passed = 0;
 
        pid = fork ();
 
@@ -404,15 +683,15 @@ int main(int argc, char *argv[])
        }
 
        if (pid == 0) {
-               err = test4 ();
+               err = test5 ();
 
-               fprintf (stderr, "test4 %s\n", (err == 0 ? "passed" : 
"failed"));
-               if (err != 0)
-                       all_passed = 0;
                return err;
        }
 
-       waitpid (pid, NULL, 0);
+       waitpid (pid, &stat, 0);
+       fprintf (stderr, "test5 %s\n", (WEXITSTATUS (stat) == 0 ? "passed" : 
"failed"));
+       if (WEXITSTATUS (stat) != 0)
+               all_passed = 0;
 
        if (all_passed)
                fprintf (stderr, "All tests passed\n");
_______________________________________________
Openais mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/openais

Reply via email to