在SMF框架中,start和stop方法是服务必须提供的,这是由于SMF需要调用start和stop方法来启动和停止相应的服务。而refresh方法则不是必要的,前提是用户服务不需要动态刷新启用新配置属性。如果用户服务需要动态刷新配置属性,则用户服务在定义时,必须提供服务refresh方法,而相应服务程序也必须实现适时重新读取配置的逻辑。
使用libscf.so的API实现refresh方法
正如前文提到的,配置有多种存在形式,不同存在形式读取方法也不同。另外,实现SMF的refresh方法也有多种方式,比如通过信号(singal)通知服务进程读取最新配置就是一种简单实用的方法。本节下文将结合一个例子讲述如何利用libscf.so提供的API读取保存在SMF全局资源库中的配置,并通过信号方式通知服务进程重新读取配置,从而实现SMF所需的refresh方法。
服务程序
表1是一个简单的程序myapp.c,它运行后将成为后台守护进程存在于系统中,并每间隔5秒钟向日志文件插入一行记录以报告自己的存在。虽然它实际上不向外提供任何服务,但该程序模拟了一般服务程序的设计结构和运行模式。即,程序运行后以守护进程形式存在于系统,程序头部有服务配置读取逻辑read_config()和服务初始化逻辑app_init(),中部使用sleep(5)模拟等待服务请求逻辑,通过向日志插入记录模拟服务请求处理逻辑,然后返回至循环开始处sleep(5)继续等待下一个服务请求等。只要在此结构上修改和扩充相应的逻辑就可以将此程序修改为一个真正的服务程序。
表1. /export/home/smfdemo/myapp.c
/*****************************************************************************/
/* myapp.c */
/*****************************************************************************/
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <strings.h>
#include <signal.h>
#include <libscf.h>
/* global exit status code */
#define RUN_OK 0
#define CONFIG_ERROR 1
#define FATAL_ERROR 2
/* global variable declaration */
char filename[1025];
scf_handle_t *handle = NULL;
scf_scope_t *sc = NULL;
scf_service_t *svc = NULL;
scf_propertygroup_t *pg = NULL;
scf_property_t *prop = NULL;
scf_value_t *value = NULL;
/* function declaration */
int read_config(void);
int app_init(void);
void daemonize(void);
void sig_usr(int signo);
void destroy_scf(void);
int main(int argc, char **argv)
{
FILE *fp;
time_t t;
/* Read the app configuration here. */
/* If error occurred, return non-zero. */
if (read_config() != RUN_OK)
{
printf("%s: read configuration failuren", argv[0]);
exit(CONFIG_ERROR);
}
/* Initialize application. Any error, return non-zero. */
if (app_init() != RUN_OK)
{
printf("%s: initialization failuren", argv[0]);
exit(FATAL_ERROR);
}
daemonize(); /* Make the application a daemon. */
/* Service logic is placed here. */
while (1)
{
sleep(5); /* Sleep for 5 seconds. In a real application, it could be */
/* waiting for service requests, e.g. waiting on message */
/* queue, etc. */
/* service logic */
if ((fp = fopen(filename,"a")) != NULL)
{
t = time(0);
fprintf(fp, "myapp is running at %sn",asctime(localtime(&t)));
fclose(fp);
}
else
{
exit(FATAL_ERROR);
}
}
}
/* make the application a daemon */
void daemonize(void)
{
int pid;
int i;
if (pid = fork())
exit(RUN_OK); /* parent exits */
else if (pid < 0)
exit(FATAL_ERROR); /* fork() failed */
/* first child process */
setsid();
if (pid = fork())
exit(RUN_OK); /* first child exits */
else if(pid < 0)
exit(FATAL_ERROR); /* fork() failed */
/* second child */
for (i = 0; i < NOFILE; ++i) /* close all files */
close(i);
chdir("/"); /* change Directory to root(/) directory */
umask(0); /* setup proper file mask */
}
/* read configurations in SMF repository */
int read_config(void)
{
memset(filename, 0, sizeof(filename));
/* connect to the current SMF global repository */
handle = scf_handle_create(SCF_VERSION);
/* allocate scf resources */
sc = scf_scope_create(handle);
svc = scf_service_create(handle);
pg = scf_pg_create(handle);
prop = scf_property_create(handle);
value = scf_value_create(handle);
/* if failed to allocate resources, exit */
if (handle == NULL || sc == NULL || svc == NULL ||
pg == NULL || prop == NULL || value == NULL)
{
destroy_scf();
return CONFIG_ERROR;
}
/* bind scf handle to the running svc.configd daemon */
if ((scf_handle_bind(handle)) == -1)
{
destroy_scf();
return CONFIG_ERROR;
}
/* get the scope of the localhost in the current repository */
if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) == -1)
{
destroy_scf();
return CONFIG_ERROR;
}
/* get the service of "application/myapp" within the scope */
if (scf_scope_get_service(sc, "application/myapp", svc) == -1)
{
destroy_scf();
return CONFIG_ERROR;
}
/* get the property group of "myapp" within the given service */
if (scf_service_get_pg(svc, "myapp", pg) == -1)
{
destroy_scf();
return CONFIG_ERROR;
}
/* get the propery of "log_filename" within the given property group */
if (scf_pg_get_property(pg, "log_filename", prop) == -1)
{
destroy_scf();
return CONFIG_ERROR;
}
/* get the value of the given property */
if (scf_property_get_value(prop, value) == -1)
{
destroy_scf();
return CONFIG_ERROR;
}
/* retrIEve the value as a string */
if (scf_value_get_astring(value, filename, sizeof(filename)) == -1)
{
destroy_scf();
return CONFIG_ERROR;
}
/* free all resources */
destroy_scf();
return RUN_OK; /* OK */
}
/* free all allocated scf resources */
void destroy_scf(void)
{
if (value != NULL) scf_value_destroy(value);
if (prop != NULL) scf_property_destroy(prop);
if (pg != NULL) scf_pg_destroy(pg);
if (svc != NULL) scf_service_destroy(svc);
if (sc != NULL) scf_scope_destroy(sc);
if (handle != NULL) scf_handle_destroy(handle);
}
/* initialize application */
int app_init(void)
{
/* setup the SIGUSR1 signal handler */
signal(SIGUSR1, sig_usr);
return RUN_OK; /* OK */
}
/* signal handler for SIGUSR1 */
void sig_usr(int signo)
{
/* re-read the configuration when signal is received */
if (read_config() != RUN_OK) exit(CONFIG_ERROR);
}
标签: