good for merge

On Thu, 2010-04-15 at 14:22 +0200, Jan Friesse wrote:
> 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
> plain text document attachment (2010-04-15-sam-user-data-store.patch)
> commit d6f2002ec4ce9384859e0952bffc72d677df9576
> Author: Jan Friesse <jfrie...@redhat.com>
> 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 (jfrie...@redhat.com)
> +.\" *
> +.\" * 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 (jfrie...@redhat.com)
> +.\" *
> +.\" * 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 (jfrie...@redhat.com)
> +.\" *
> +.\" * 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
> Openais@lists.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/openais

_______________________________________________
Openais mailing list
Openais@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/openais

Reply via email to