You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
heartbeat/cim/utils.c

557 lines
12 KiB

/*
* utils.c: utilities
*
* Author: Jia Ming Pan <jmltc@cn.ibm.com>
* Copyright (c) 2005 International Business Machines
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include <lha_internal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <regex.h>
#include <hb_api.h>
#include <errno.h>
#include <heartbeat.h>
#include "cluster_info.h"
#include "utils.h"
int debug_level = 10;
static char * pathname_encode(const char *);
int
cim_init_logger(const char * entity)
{
char * inherit_debuglevel;
int debug_level = 2;
inherit_debuglevel = getenv(HADEBUGVAL);
if (inherit_debuglevel != NULL) {
debug_level = atoi(inherit_debuglevel);
if (debug_level > 2) {
debug_level = 2;
}
}
cl_log_set_entity(entity);
cl_log_enable_stderr(debug_level?TRUE:FALSE);
cl_log_set_facility(HA_LOG_FACILITY);
return HA_OK;
}
int
run_shell_cmnd(const char *cmnd, int *ret, char ***out, char ***err)
/* err not used currently */
{
FILE * fstream = NULL;
char buffer [4096];
int cmnd_rc, rc, i;
DEBUG_ENTER();
if ( (fstream = popen(cmnd, "r")) == NULL ){
cl_log(LOG_ERR, "run_shell_cmnd: popen error: %s",
strerror(errno));
return HA_FAIL;
}
if ( (*out = cim_malloc(sizeof(char*)) ) == NULL ) {
cl_log(LOG_ERR, "run_shell_cmnd: failed malloc.");
return HA_FAIL;
}
(*out)[0] = NULL;
i = 0;
while (!feof(fstream)) {
if ( fgets(buffer, 4096, fstream) != NULL ){
/** add buffer to out **/
*out = cim_realloc(*out, (i+2) * sizeof(char*));
if ( *out == NULL ) {
rc = HA_FAIL;
goto exit;
}
(*out)[i] = cim_strdup(buffer);
(*out)[i+1] = NULL;
}else{
continue;
}
i++;
}
rc = HA_OK;
exit:
if ( (cmnd_rc = pclose(fstream)) == -1 ){
/*** WARNING log ***/
cl_log(LOG_WARNING, "failed to close pipe.");
}
*ret = cmnd_rc;
DEBUG_LEAVE();
return rc;
}
char **
regex_search(const char * reg, const char * str, int * len)
{
regex_t regexp;
const int maxmatch = 16;
regmatch_t pm[16];
int i, ret, nmatch = 0;
char **match = NULL;
DEBUG_ENTER();
*len = 0;
ret = regcomp(&regexp, reg, REG_EXTENDED);
if ( ret != 0) {
cl_log(LOG_ERR, "regex_search: error regcomp regex %s.", reg);
return HA_FAIL;
}
ret = regexec(&regexp, str, nmatch, pm, 0);
if ( ret == REG_NOMATCH ){
regfree(&regexp);
cl_log(LOG_ERR, "regex_search: no match.");
return NULL;
}else if (ret != 0){
cl_log(LOG_ERR, "regex_search: error regexec.\n");
regfree(&regexp);
return NULL;
}
for(nmatch=0; pm[nmatch].rm_so != -1 && nmatch < maxmatch; nmatch++);
if ( (match = cim_malloc(nmatch*sizeof(char *))) == NULL ) {
cl_log(LOG_ERR, "regex_search: alloc_failed.");
regfree(&regexp);
return NULL;
}
*len = nmatch;
for(i = 0; i < maxmatch && i < nmatch; i++){
int str_len = pm[i].rm_eo - pm[i].rm_so;
if ((match[i] = cim_malloc(str_len + 1))) {
strncpy( match[i], str + pm[i].rm_so, str_len);
match[i][str_len] = EOS;
}
}
regfree(&regexp);
DEBUG_LEAVE();
return match;
}
void
free_2d_zarray(void *zarray, cim_free_t free)
{
void ** z = (void **)zarray;
int i = 0;
void * p;
while ((p=z[i++])) {
free(p);
}
cim_free(z);
}
void
free_2d_array(void * a, int len, cim_free_t free)
{
int i;
void ** array = (void **)a;
for (i=0; i<len; i++){
if (array[i]) {
free(array[i]);
}
}
cim_free(array);
}
char *
uuid_to_str(const cl_uuid_t * uuid){
int i, len = 0;
char * str = cim_malloc(256);
if ( str == NULL ) {
return NULL;
}
memset(str, 0, 256);
for ( i = 0; i < sizeof(cl_uuid_t); i++){
len += snprintf(str + len, 2, "%.2X", uuid->uuid[i]);
}
return str;
}
void
cim_assert(const char * assertion, int line, const char * file)
{
cl_log(LOG_ERR, "Assertion \"%s\" failed on line %d in file \"%s\""
, assertion, line, file);
exit(1);
}
char **
split_string(const char* string, int *len, const char *delim)
{
char **strings = NULL;
const char *p;
*len = 0;
while(*string){
char * token = NULL;
/* eat up delim chars */
while (*string && strchr(delim, *string)) {
string++;
continue;
}
if(!*string) {
break;
}
/* reach a delim char */
p = string;
while ( *p && !strchr(delim, *p) ) {
p ++;
continue;
}
/* copy string~(p-1) to token */
token = cim_malloc(p-string+1);
if ( token == NULL ) {
return strings;
}
memcpy(token, string, p - string);
token[p-string] = EOS;
strings = cim_realloc(strings, (*len+1) * sizeof(char *));
if ( strings == NULL ) {
return NULL;
}
strings[*len] = token;
*len = *len + 1;
string = p;
}
return strings;
}
int
cim_msg2disk(const char *objpathname, struct ha_msg *msg)
{
struct stat st;
FILE *fobj;
char pathname[MAXLEN], *buf;
char *msgstr = NULL;
if ( stat(HA_CIM_VARDIR, &st) < 0 ) {
if ( errno == ENOENT ) { /* not exist, create */
if ( mkdir(HA_CIM_VARDIR, 0660) < 0){
cl_log(LOG_ERR,"msg2disk: mkdir failed.");
cl_log(LOG_ERR,"reason:%s",strerror(errno));
return HA_FAIL;
}
} else {
cl_log(LOG_ERR, "msg2disk: stat faild.");
cl_log(LOG_ERR,"reason:%d(%s)",errno,strerror(errno));
return HA_FAIL;
}
}
/* check stat */
/* write msg*/
if((buf = pathname_encode(objpathname))== NULL ) {
return HA_FAIL;
}
snprintf(pathname, MAXLEN, "%s/%s", HA_CIM_VARDIR, buf);
cim_free(buf);
if ( ( fobj = fopen(pathname, "w") ) == NULL ) {
cl_log(LOG_WARNING, "msg2disk: can't open file.");
cl_log(LOG_WARNING, "reason:%d(%s)", errno, strerror(errno));
return HA_FAIL;
}
if ( msg->nfields == 0 ) {
fclose(fobj);
return HA_OK;
}
if ((msgstr = msg2string(msg)) == NULL ) {
cl_log(LOG_ERR, "cim_msg2disk: msgstr NULL.");
return HA_FAIL;
}
fprintf(fobj, "%s", msgstr);
fclose(fobj);
return HA_OK;
}
struct ha_msg*
cim_disk2msg(const char *objpathname)
{
char pathname[MAXLEN], *buf;
FILE *fobj = NULL;
int ret;
int bytes = 0;
struct stat st;
struct ha_msg *msg = NULL;
if((buf = pathname_encode(objpathname))== NULL ) {
return NULL;
}
snprintf(pathname, MAXLEN, "%s/%s", HA_CIM_VARDIR, buf);
cim_free(buf);
if ( ( ret = stat(pathname, &st)) < 0 ) {
cl_log(LOG_WARNING, "disk2msg: stat faild for %s.", pathname);
cl_log(LOG_WARNING,"reason:%d(%s)",errno,strerror(errno));
return NULL;
}
if (st.st_size == 0 ) {
cl_log(LOG_WARNING, "disk2msg: size of %s is zero.", objpathname);
return NULL;
}
if ((buf = cim_malloc(st.st_size)) == NULL ) {
cl_log(LOG_ERR, "disk2msg: alloc msg failed for %s.", objpathname);
return NULL;
}
if ( (fobj = fopen(pathname, "r")) == NULL ) {
cl_log(LOG_WARNING, "msg2disk: can't open file %s.", pathname);
cl_log(LOG_WARNING, "reason:%d(%s)", errno, strerror(errno));
return NULL;
}
while ( (ret = fread(buf, st.st_size, 1, fobj))){
bytes += ret*st.st_size;
}
if ( !feof(fobj) ) {
cl_log(LOG_ERR, "msg2disk: read error for %s.", objpathname);
cl_log(LOG_ERR, "reason: %d(%s).", errno, strerror(errno));
cim_free(msg);
return NULL;
}
if ( bytes != st.st_size ) {
cl_log(LOG_ERR, "msg2disk: incompete read:");
cl_log(LOG_ERR, "read: %d vs size: %d.", bytes, (int)st.st_size);
cim_free(msg);
return NULL;
}
msg = string2msg(buf, bytes);
cim_free(buf);
fclose(fobj);
return msg;
}
int
cim_disk_msg_del(const char *objpathname)
{
char fullpathname[MAXLEN];
char * pathname = pathname_encode(objpathname);
snprintf(fullpathname, MAXLEN, "%s/%s", HA_CIM_VARDIR, pathname);
cim_debug2(LOG_INFO, "%s: unlink %s", __FUNCTION__, fullpathname);
unlink(fullpathname);
cim_free(pathname);
return HA_OK;
}
char*
cim_dbget(const char *pathname, const char*key)
{
struct ha_msg *db = cim_disk2msg(pathname);
const char * value;
if ( db == NULL ) {
return NULL;
}
value = cl_get_string(db, key);
if ( value == NULL || strncmp(value, "null", MAXLEN) == 0) {
return NULL;
}
return cim_strdup(value);
}
int
cim_dbput(const char *pathname, const char*key, const char*value)
{
int ret;
struct ha_msg* db = cim_disk2msg(pathname);
if ( db == NULL ) {
if ( (db = ha_msg_new(1)) == NULL ) {
cl_log(LOG_ERR, "cim_dbput: alloc db failed.");
return HA_FAIL;
}
}
if ((cl_msg_modstring(db, key, value?value:"null")) != HA_OK ) {
ha_msg_del(db);
cl_log(LOG_ERR, "cim_dbput: put value failed.");
return HA_FAIL;
}
ret = cim_msg2disk(pathname, db);
ha_msg_del(db);
return HA_OK;
}
int
cim_dbdel(const char *pathname, const char*key)
{
int ret;
struct ha_msg* db = cim_disk2msg(pathname);
if ( db == NULL ) {
cl_log(LOG_ERR, "cim_dbdel: get db failed.");
return HA_FAIL;
}
if ((cl_msg_remove(db, key)) != HA_OK ) {
ha_msg_del(db);
cl_log(LOG_ERR, "cim_dbdel: remove failed.");
return HA_FAIL;
}
ret = cim_msg2disk(pathname, db);
ha_msg_del(db);
return HA_OK;
}
struct ha_msg*
cim_dbkeys(const char *pathname)
{
struct ha_msg * db = cim_disk2msg(pathname);
struct ha_msg * list;
int i;
if ( db == NULL ) {
cl_log(LOG_ERR, "cim_dbkeys: get db failed.");
return NULL;
}
if ( (list = ha_msg_new(1)) == NULL ) {
ha_msg_del(db);
cl_log(LOG_ERR, "cim_dbkeys: alloc list failed.");
return NULL;
}
for (i = 0; i < db->nfields; i++) {
cim_list_add(list, db->names[i]);
}
ha_msg_del(db);
return list;
}
static char*
pathname_encode(const char *pathname)
{
char *new_pathname = NULL;
char ch, *p;
if ((new_pathname = cim_malloc(strlen(pathname)+1)) == NULL ) {
cl_log(LOG_ERR, "pathname_enocde: alloc pathname failed.");
return NULL;
}
p = new_pathname;
while( (ch = *(pathname++)) ) {
if (ch == '\\' || ch == '/') {
*(p++) = '_';
} else {
*(p++) = ch;
}
}
*p = EOS;
return new_pathname;
}
/****************************************************
* msg
****************************************************/
int
cim_msg_children_count(struct ha_msg *parent)
{
int i, count = 0;
for (i = 0; i < parent->nfields; i++) {
if ( parent->types[i] == FT_STRUCT ) {
count++;
}
}
return count;
}
const char *
cim_msg_child_name(struct ha_msg *parent, int index)
{
int i, current = 0;
for (i = 0; i < parent->nfields; i++) {
if ( parent->types[i] == FT_STRUCT ) {
if ( index == current) {
return parent->names[i];
}
current++;
}
}
return NULL;
}
struct ha_msg *
cim_msg_child_index(struct ha_msg *parent, int index)
{
int i, current = 0;
for (i = 0; i < parent->nfields; i++) {
if ( parent->types[i] == FT_STRUCT ) {
if ( index == current) {
return parent->values[i];
}
current++;
}
}
return NULL;
}
int
cim_list_find(struct ha_msg *list, const char *value)
{
int len = cim_list_length(list);
int i = 0;
for (i = 0; i<len; i++) {
char * v = cim_list_index(list, i);
if ( v && (strncmp(v, value, MAXLEN) == 0)) {
return TRUE;
}
}
return FALSE;
}