ha/service-mgmt/sm/src/sm_service_group_notificati...

808 lines
30 KiB
C

//
// Copyright (c) 2014-2016 Wind River Systems, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
#include "sm_service_group_notification.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "sm_types.h"
#include "sm_utils.h"
#include "sm_debug.h"
#include "sm_process_death.h"
#include "sm_service_domain_member_table.h"
#include "sm_service_group_table.h"
#include "sm_service_group_fsm.h"
typedef struct
{
char seqnum_str[24];
bool part_of_aggregate;
char service_group_aggregate_name[SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR];
SmServiceGroupStateT service_group_aggregate_desired_state;
SmServiceGroupStateT service_group_aggregate_state;
char service_group_name[SM_SERVICE_GROUP_NAME_MAX_CHAR];
SmServiceGroupStateT service_group_desired_state;
SmServiceGroupStateT service_group_state;
SmServiceGroupNotificationT service_group_notification;
} SmNotificationEnvT;
#define SM_NOTIFICATION_SCRIPT_TIMEOUT_IN_MS 30000
#define SM_NOTIFICATION_SCRIPT_SUCCESS 0
#define SM_NOTIFICATION_SCRIPT_TIMEOUT -65534
#define SM_NOTIFICATION_SCRIPT_FAILURE -65535
static unsigned long _seqnum = 0;
// ****************************************************************************
// Service Group Notification - Do Abort
// =====================================
static SmErrorT sm_service_group_notification_do_abort(
char service_group_name[], int process_id )
{
if( -1 == process_id )
{
DPRINTFE( "Trying to abort a process (%i) for service group (%s) "
"notificaton but pid is invalid.", process_id,
service_group_name );
return( SM_FAILED );
}
if( process_id == (int) getpid() )
{
DPRINTFE( "Trying to abort a process (%i) for service group (%s) "
"notification but pid is self.", process_id,
service_group_name );
return( SM_FAILED );
}
DPRINTFI( "Aborting service group (%s) notification with kill signal, "
"pid=%i.", service_group_name, process_id );
if( 0 > kill( process_id, SIGKILL ) )
{
if( ESRCH == errno )
{
DPRINTFD( "Service group (%s) notification script not running.",
service_group_name );
return( SM_OKAY );
} else {
DPRINTFE( "Failed to send kill signal to service group (%s) "
"notification script, error=%s.", service_group_name,
strerror( errno ) );
return( SM_FAILED );
}
}
DPRINTFD( "Kill signal sent to service groupt (%s) notification "
"script.", service_group_name );
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Service Group Aggregate
// ====================================================
static void sm_service_group_notification_service_group_aggregate(
void* user_data[], SmServiceDomainMemberT* member )
{
SmServiceGroupStateT* aggregate_desired_state;
SmServiceGroupStateT* aggregate_state;
SmServiceGroupStateT* transition_state;
SmServiceGroupT* service_group;
aggregate_desired_state = (SmServiceGroupStateT*) user_data[0];
aggregate_state = (SmServiceGroupStateT*) user_data[1];
transition_state = (SmServiceGroupStateT*) user_data[2];
service_group = sm_service_group_table_read( member->service_group_name );
if( NULL == service_group )
{
DPRINTFE( "Failed to read service group (%s), error=%s.",
member->service_group_name, sm_error_str(SM_NOT_FOUND) );
return;
}
switch( service_group->desired_state )
{
case SM_SERVICE_GROUP_STATE_ACTIVE:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_desired_state )||
( SM_SERVICE_GROUP_STATE_STANDBY != *aggregate_desired_state )||
( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_desired_state )||
( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_desired_state ))
*aggregate_desired_state = service_group->desired_state;
break;
case SM_SERVICE_GROUP_STATE_STANDBY:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_desired_state )||
( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_desired_state )||
( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_desired_state ))
*aggregate_desired_state = service_group->desired_state;
break;
case SM_SERVICE_GROUP_STATE_DISABLED:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_desired_state )||
( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_desired_state ))
*aggregate_desired_state = service_group->desired_state;
break;
case SM_SERVICE_GROUP_STATE_SHUTDOWN:
*aggregate_desired_state = service_group->desired_state;
break;
default:
// Ignore
break;
}
switch( service_group->state )
{
case SM_SERVICE_GROUP_STATE_ACTIVE:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_state )||
( SM_SERVICE_GROUP_STATE_STANDBY != *aggregate_state )||
( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_state )||
( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_state ))
*aggregate_state = service_group->state;
break;
case SM_SERVICE_GROUP_STATE_STANDBY:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_state )||
( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_state )||
( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_state ))
*aggregate_state = service_group->state;
break;
case SM_SERVICE_GROUP_STATE_DISABLED:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_state )||
( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_state ))
*aggregate_state = service_group->state;
break;
case SM_SERVICE_GROUP_STATE_SHUTDOWN:
*aggregate_state = service_group->state;
break;
case SM_SERVICE_GROUP_STATE_GO_ACTIVE:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *transition_state )||
( SM_SERVICE_GROUP_STATE_GO_STANDBY != *transition_state )||
( SM_SERVICE_GROUP_STATE_DISABLING != *transition_state ))
*transition_state = service_group->state;
break;
case SM_SERVICE_GROUP_STATE_GO_STANDBY:
if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *transition_state )||
( SM_SERVICE_GROUP_STATE_DISABLING != *transition_state ))
*transition_state = service_group->state;
break;
case SM_SERVICE_GROUP_STATE_DISABLING:
*transition_state = service_group->state;
break;
default:
// Ignore
break;
}
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Get Environment
// ============================================
static SmErrorT sm_service_group_notification_get_env(
char service_group_name[], SmServiceGroupNotificationT notification,
SmNotificationEnvT* env )
{
SmServiceGroupStateT aggregate_desired_state = SM_SERVICE_GROUP_STATE_UNKNOWN;
SmServiceGroupStateT aggregate_state = SM_SERVICE_GROUP_STATE_UNKNOWN;
SmServiceGroupStateT transition_state = SM_SERVICE_GROUP_STATE_UNKNOWN;
void* user_data[] = {&aggregate_desired_state, &aggregate_state,
&transition_state};
SmServiceDomainMemberT* service_domain_member = NULL;
SmServiceGroupT* service_group = NULL;
service_group = sm_service_group_table_read( service_group_name );
if( NULL == service_group )
{
DPRINTFE( "Failed to read service group (%s), error=%s.",
service_group_name, sm_error_str(SM_NOT_FOUND) );
return( SM_FAILED );
}
_seqnum++;
snprintf( &(env->seqnum_str[0]), sizeof(env->seqnum_str), "%lu", _seqnum );
snprintf( &(env->service_group_name[0]), SM_SERVICE_GROUP_NAME_MAX_CHAR,
"%s", service_group->name );
env->service_group_desired_state = service_group->desired_state;
env->service_group_state = service_group->state;
env->service_group_notification = notification;
service_domain_member =
sm_service_domain_member_table_read_service_group( service_group->name );
if( NULL != service_domain_member )
{
if( '\0' != service_domain_member->service_group_aggregate[0] )
{
sm_service_domain_member_table_foreach_service_group_aggregate(
service_domain_member->name,
service_domain_member->service_group_aggregate, user_data,
sm_service_group_notification_service_group_aggregate );
switch( aggregate_state )
{
case SM_SERVICE_GROUP_STATE_ACTIVE:
if(( SM_SERVICE_GROUP_STATE_GO_ACTIVE == transition_state )||
( SM_SERVICE_GROUP_STATE_GO_STANDBY == transition_state )||
( SM_SERVICE_GROUP_STATE_DISABLING == transition_state ))
aggregate_state = transition_state;
break;
case SM_SERVICE_GROUP_STATE_STANDBY:
if(( SM_SERVICE_GROUP_STATE_GO_STANDBY == transition_state )||
( SM_SERVICE_GROUP_STATE_DISABLING == transition_state ))
aggregate_state = transition_state;
break;
case SM_SERVICE_GROUP_STATE_DISABLED:
if( SM_SERVICE_GROUP_STATE_DISABLING == transition_state )
aggregate_state = transition_state;
break;
case SM_SERVICE_GROUP_STATE_UNKNOWN:
aggregate_state = transition_state;
break;
default:
// Ignore
break;
}
env->part_of_aggregate = true;
snprintf( &(env->service_group_aggregate_name[0]),
SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR, "%s",
service_domain_member->service_group_aggregate );
env->service_group_aggregate_desired_state = aggregate_desired_state;
env->service_group_aggregate_state = aggregate_state;
}
}
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Setup Environment
// ==============================================
static SmErrorT sm_service_group_notification_setup_env(
SmNotificationEnvT* env )
{
if( 0 > setenv( "NOTIFICATION_SEQNUM", env->seqnum_str, 1 ) )
{
DPRINTFE( "Failed to set environment variable (NOTIFICATION_SEQNUM), "
"error=%s.", strerror( errno ) );
return( SM_FAILED );
}
if( 0 > setenv( "SERVICE_GROUP_NAME", env->service_group_name, 1 ) )
{
DPRINTFE( "Failed to set environment variable (SERVICE_GROUP_NAME), "
"error=%s.", strerror( errno ) );
return( SM_FAILED );
}
if( 0 > setenv( "SERVICE_GROUP_DESIRED_STATE",
sm_service_group_state_str(
env->service_group_desired_state), 1 ) )
{
DPRINTFE( "Failed to set environment variable "
"(SERVICE_GROUP_DESIRED_STATE), error=%s.",
strerror( errno ) );
return( SM_FAILED );
}
if( 0 > setenv( "SERVICE_GROUP_STATE",
sm_service_group_state_str(env->service_group_state), 1 ) )
{
DPRINTFE( "Failed to set environment variable (SERVICE_GROUP_STATE), "
"error=%s.", strerror( errno ) );
return( SM_FAILED );
}
if( 0 > setenv( "SERVICE_GROUP_NOTIFICATION",
sm_service_group_notification_str(
env->service_group_notification), 1 ) )
{
DPRINTFE( "Failed to set environment variable "
"(SERVICE_GROUP_NOTIFICATION), error=%s.",
strerror( errno ) );
return( SM_FAILED );
}
if( env->part_of_aggregate )
{
if( 0 > setenv( "SERVICE_GROUP_AGGREGATE_NAME",
env->service_group_aggregate_name, 1 ) )
{
DPRINTFE( "Failed to set environment variable "
"(SERVICE_GROUP_AGGREGATE_NAME), error=%s.",
strerror( errno ) );
return ( SM_FAILED );
}
if( 0 > setenv( "SERVICE_GROUP_AGGREGATE_DESIRED_STATE",
sm_service_group_state_str(
env->service_group_aggregate_desired_state), 1 ) )
{
DPRINTFE( "Failed to set environment variable "
"(SERVICE_GROUP_AGGREGATE_DESIRED_STATE), error=%s.",
strerror( errno ) );
return ( SM_FAILED );
}
if( 0 > setenv( "SERVICE_GROUP_AGGREGATE_STATE",
sm_service_group_state_str(
env->service_group_aggregate_state), 1 ) )
{
DPRINTFE( "Failed to set environment variable "
"(SERVICE_GROUP_AGGREGATE_STATE), error=%s.",
strerror( errno ) );
return ( SM_FAILED );
}
}
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Run
// ================================
static SmErrorT sm_service_group_notification_run( char service_group_name[],
SmServiceGroupNotificationT notification, int* process_id )
{
pid_t pid;
struct stat stat_data;
int result;
char program_name[80];
SmNotificationEnvT env;
SmErrorT error;
*process_id = -1;
memset( &env, 0, sizeof(SmNotificationEnvT) );
if( 0 > access( SM_NOTIFICATION_SCRIPT, F_OK | X_OK ) )
{
DPRINTFE( "Service group notification script access failed, "
"error=%s.", strerror( errno ) );
return( SM_FAILED );
}
if( 0 > stat( SM_NOTIFICATION_SCRIPT, &stat_data ) )
{
DPRINTFE( "Service group notification script stat failed, "
"error=%s.", strerror( errno ) );
return( SM_FAILED );
}
if( 0 >= stat_data.st_size )
{
DPRINTFE( "Service group notification script has zero size." );
return( SM_FAILED );
}
error = sm_service_group_notification_get_env( service_group_name,
notification, &env );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to get environment for service group (%s) "
"notification (%s), error=%s.", service_group_name,
sm_service_group_notification_str(notification),
sm_error_str( error ) );
return( SM_FAILED );
}
pid = fork();
if( 0 > pid )
{
DPRINTFE( "Failed to fork notification process for service group "
"(%s), error=%s.", service_group_name, strerror( errno ) );
return( SM_FAILED );
} else if( 0 == pid ) {
// Child process.
struct rlimit file_limits;
DPRINTFD( "Child notification process created for service group "
"(%s).", service_group_name );
if( 0 > setpgid( 0, 0 ) )
{
DPRINTFE( "Failed to set notification process group id for "
"service group (%s) notification (%s), error=%s.",
service_group_name,
sm_service_group_notification_str(notification),
strerror( errno ) );
exit( SM_NOTIFICATION_SCRIPT_FAILURE );
}
if( 0 > getrlimit( RLIMIT_NOFILE, &file_limits ) )
{
DPRINTFE( "Failed to get file limits for service group (%s) "
"notification (%s), error=%s.", service_group_name,
sm_service_group_notification_str(notification),
strerror( errno ) );
exit( SM_NOTIFICATION_SCRIPT_FAILURE );
}
unsigned int fd_i;
for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i )
{
close( fd_i );
}
if( 0 > open( "/dev/null", O_RDONLY ) )
{
DPRINTFE( "Failed to open stdin to /dev/null for service group "
"(%s) notification (%s), error=%s.", service_group_name,
sm_service_group_notification_str(notification),
strerror( errno ) );
}
if( 0 > open( "/dev/null", O_WRONLY ) )
{
DPRINTFE( "Failed to open stdout to /dev/null for service group "
"(%s) notification (%s), error=%s.", service_group_name,
sm_service_group_notification_str(notification),
strerror( errno ) );
}
if( 0 > open( "/dev/null", O_WRONLY ) )
{
DPRINTFE( "Failed to open stderr to /dev/null for service group "
"(%s) notification (%s), error=%s.", service_group_name,
sm_service_group_notification_str(notification),
strerror( errno ) );
}
result = setpriority( PRIO_PROCESS, getpid(), -1 );
if( 0 > result )
{
DPRINTFE( "Failed to set priority of process, error=%s.",
strerror( errno ) );
exit( SM_NOTIFICATION_SCRIPT_FAILURE );
}
error = sm_service_group_notification_setup_env( &env );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to setup environment for service group (%s) "
"notification (%s), error=%s.", service_group_name,
sm_service_group_notification_str(notification),
sm_error_str( error ) );
exit( SM_NOTIFICATION_SCRIPT_FAILURE );
}
snprintf( program_name, sizeof(program_name), "%s",
SM_NOTIFICATION_SCRIPT );
char* argv[] = {program_name, NULL};
if( 0 > execv( program_name, argv ) )
{
DPRINTFE( "Failed to exec command for service group (%s) "
"notification (%s), error=%s.", service_group_name,
sm_service_group_notification_str(notification),
strerror( errno ) );
}
exit( SM_NOTIFICATION_SCRIPT_FAILURE );
} else {
// Parent process.
*process_id = (int) pid;
DPRINTFD( "Child notification process (%i) created for service "
"group (%s) notification (%s).", *process_id,
service_group_name,
sm_service_group_notification_str(notification) );
}
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Timeout
// ====================================
static bool sm_service_group_notification_timeout( SmTimerIdT timer_id,
int64_t user_data )
{
int64_t id = user_data;
SmServiceGroupT* service_group;
SmErrorT error;
service_group = sm_service_group_table_read_by_id( id );
if( NULL == service_group )
{
DPRINTFE( "Failed to read service group, error=%s.",
sm_error_str(SM_NOT_FOUND) );
return( false );
}
if( -1 == service_group->notification_pid )
{
DPRINTFE( "Service group (%s) notification script not running.",
service_group->name );
return( false );
}
DPRINTFI( "Notification (%s) timeout for service group (%s).",
service_group->notification_str, service_group->name );
error = sm_service_group_notification_do_abort(
service_group->name, service_group->notification_pid );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to abort notification script for service group "
"(%s), error=%s.", service_group->name,
sm_error_str( error ) );
}
service_group->notification_pid = -1;
service_group->notification_timer_id = SM_TIMER_ID_INVALID;
service_group->notification_complete = false;
service_group->notification_failed = true;
service_group->notification_timeout = true;
error = sm_service_group_fsm_event_handler( service_group->name,
SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT, NULL,
"notification script timed out" );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to notify service group (%s) fsm notification "
"timed out, error=%s.", service_group->name,
sm_error_str( error ) );
abort();
}
return( false );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Complete
// =====================================
static void sm_service_group_notification_complete( pid_t pid, int exit_code,
int64_t user_data )
{
SmServiceGroupT* service_group;
SmServiceGroupEventT event;
char reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR] = "";
SmErrorT error;
service_group = sm_service_group_table_read_by_notification_pid( (int) pid );
if( NULL == service_group )
{
DPRINTFE( "Failed to query service group based on pid (%i), error=%s.",
(int) pid, sm_error_str(SM_NOT_FOUND) );
return;
}
if( -1 == service_group->notification_pid )
{
DPRINTFE( "Service group (%s) not running notification script.",
service_group->name );
return;
}
if( SM_TIMER_ID_INVALID != service_group->notification_timer_id )
{
error = sm_timer_deregister( service_group->notification_timer_id );
if( SM_OKAY == error )
{
DPRINTFD( "Timer stopped for notification (%s) for service "
"group (%s).", service_group->notification_str,
service_group->name );
} else {
DPRINTFE( "Failed to stop timer for notification (%s) for "
"service group (%s), error=%s.",
service_group->notification_str, service_group->name,
sm_error_str( error ) );
}
}
service_group->notification_pid = -1;
service_group->notification_timer_id = SM_TIMER_ID_INVALID;
if( SM_NOTIFICATION_SCRIPT_SUCCESS == exit_code )
{
DPRINTFI( "Notification (%s) for service group (%s) passed.",
service_group->notification_str, service_group->name );
service_group->notification_complete = true;
service_group->notification_failed = false;
service_group->notification_timeout = false;
event = SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS;
} else {
DPRINTFI( "Notification (%s) for service group (%s) failed.",
service_group->notification_str, service_group->name );
service_group->notification_complete = true;
service_group->notification_failed = true;
service_group->notification_timeout = false;
event = SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED;
snprintf( reason_text, sizeof(reason_text), "notification script "
"failed" );
}
error = sm_service_group_fsm_event_handler( service_group->name,
event, NULL, reason_text );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to notify service group (%s) fsm, error=%s.",
service_group->name, sm_error_str( error ) );
abort();
}
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Notify
// ===================================
SmErrorT sm_service_group_notification_notify( SmServiceGroupT* service_group,
SmServiceGroupNotificationT notification )
{
const char* notification_str;
char timer_name[80] = "";
int process_id = -1;
int timeout_in_ms = SM_NOTIFICATION_SCRIPT_TIMEOUT_IN_MS;
SmTimerIdT timer_id = SM_TIMER_ID_INVALID;
SmErrorT error;
notification_str =
sm_service_group_notification_str(notification);
// Run notification script.
error = sm_service_group_notification_run( service_group->name,
notification, &process_id );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to run notification script for service group (%s), "
"error=%s.", service_group->name, sm_error_str( error ) );
return( error );
}
// Register for notification script exit.
error = sm_process_death_register( process_id, true,
sm_service_group_notification_complete,
0 );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to register for notification completion for "
"service group (%s), error=%s.", service_group->name,
sm_error_str( error ) );
abort();
}
// Create timer for notification completion.
snprintf( timer_name, sizeof(timer_name), "%s %s notification ",
service_group->name, notification_str );
error = sm_timer_register( timer_name, timeout_in_ms,
sm_service_group_notification_timeout,
service_group->id, &timer_id );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to create a timer for notification for service "
"group (%s), error=%s.", service_group->name,
sm_error_str( error ) );
abort();
}
service_group->notification = notification;
service_group->notification_str = notification_str;
service_group->notification_pid = process_id;
service_group->notification_timer_id = timer_id;
service_group->notification_complete = false;
service_group->notification_failed = false;
service_group->notification_timeout = false;
DPRINTFI( "Started notification (%s) process (%i) for service group "
"(%s).", service_group->notification_str, process_id,
service_group->name );
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Abort
// ==================================
SmErrorT sm_service_group_notification_abort( SmServiceGroupT* service_group )
{
const char* notification_str;
SmErrorT error;
notification_str =
sm_service_group_notification_str(service_group->notification);
DPRINTFI( "Aborting notification (%s) for service group (%s).",
notification_str, service_group->name );
if( -1 != service_group->notification_pid )
{
error = sm_service_group_notification_do_abort(
service_group->name, service_group->notification_pid );
if( SM_OKAY != error )
{
DPRINTFE( "Failed to abort notification (%s) for service group "
"(%s), error=%s.", notification_str, service_group->name,
sm_error_str( error ) );
return( error );
}
}
if( SM_TIMER_ID_INVALID != service_group->notification_timer_id )
{
error = sm_timer_deregister( service_group->notification_timer_id );
if( SM_OKAY != error )
{
DPRINTFE( "Cancel notification timer for service group (%s) "
"failed, error=%s.", service_group->name,
sm_error_str( error ) );
return( error );
}
}
service_group->notification = SM_SERVICE_GROUP_NOTIFICATION_NIL;
service_group->notification_str = NULL;
service_group->notification_pid = -1;
service_group->notification_timer_id = SM_TIMER_ID_INVALID;
service_group->notification_complete = false;
service_group->notification_failed = false;
service_group->notification_timeout = false;
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Initialize
// =======================================
SmErrorT sm_service_group_notification_initialize( void )
{
return( SM_OKAY );
}
// ****************************************************************************
// ****************************************************************************
// Service Group Notification - Finalize
// =====================================
SmErrorT sm_service_group_notification_finalize( void )
{
return( SM_OKAY );
}
// ****************************************************************************