
On 12/07/2011 04:25 AM, Wayne Xia wrote:
this is the helper function for the lib.
Signed-off-by: Wayne Xia<xiawenc@linux.vnet.ibm.com> --- libxkutil/host_network_error.h | 28 ++ libxkutil/host_network_helper.c | 659 +++++++++++++++++++++++++++++++++++++++ libxkutil/host_network_helper.h | 192 ++++++++++++ 3 files changed, 879 insertions(+), 0 deletions(-) create mode 100644 libxkutil/host_network_error.h create mode 100644 libxkutil/host_network_helper.c create mode 100644 libxkutil/host_network_helper.h
diff --git a/libxkutil/host_network_error.h b/libxkutil/host_network_error.h new file mode 100644 index 0000000..d809033 --- /dev/null +++ b/libxkutil/host_network_error.h @@ -0,0 +1,28 @@ +#ifndef HOST_NETWORK_ERROR_H +#define HOST_NETWORK_ERROR_H + +#define ERR_REQUEST_NOT_SUPPORT -1 + +#define ERR_COMMAND_NOT_SET -11 +#define ERR_COMMAND_PIPE_ERR -12 +#define ERR_COMMAND_NOT_SUPPORT -13 +#define ERR_COMMAND_NO_PERMISSION -14 +#define ERR_COMMAND_NO_READY -15 +#define ERR_COMMAND_PARAMETER_WRONG -16 +#define ERR_COMMAND_EXECUTION -17 + +#define ERR_DEVICE_EXCEED_MAXNUM -100 +#define ERR_DEVICE_EXIST -101 +#define ERR_DEVICE_NOT_EXIST -102 +#define ERR_DEVICE_ALREADY_DONE -103 +#define ERR_DEVICE_CONNECT_OTHER -104 + +#define ERR_FILE_OP_FAIL -125 +#define ERR_FILE_EMPTY -126 +#define ERR_FILE_TOO_LARGE -127 +#define ERR_FILE_CONT_TOO_LARGE -128 +#define ERR_FILE_LOCK_FAIL -129 + +#define ERR_PERSIST_NOT_REDHAT -200 Any particular reason for negative numbers? + +#endif diff --git a/libxkutil/host_network_helper.c b/libxkutil/host_network_helper.c new file mode 100644 index 0000000..dc9f775 --- /dev/null +++ b/libxkutil/host_network_helper.c @@ -0,0 +1,659 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@cn.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + + +#include<string.h> +#include<sys/types.h> +#include<sys/stat.h> +#include<unistd.h> +#include<fcntl.h> + +#include "host_network_helper.h" +#include "host_network_error.h" + +#define CONFIGURE_FILE_MAX_SIZE 2048 + +#define PIPE_CMD_SUFFIX " 2>&1" + +static int g_linux_version = LINUX_UNKNOWN; I assume this is needed because the parse output varies? + +static int compare_qos_8021q(const void *p1, const void *p2) +{ + const VLAN_Qos_8021q_elem *qos1 = (VLAN_Qos_8021q_elem *)p1; + const VLAN_Qos_8021q_elem *qos2 = (VLAN_Qos_8021q_elem *)p2; + int ret = 0; + if ((qos1->from)> (qos2->from)) { + ret = 1; + } + return ret; +} + +/* it need to be checked see whether these are the conditions */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos) +{ + int ret = 1; + int i = 0; + int last_num = -1; + if ((pqos->count< 0) || (pqos->count> 8)) { + ret = 0; + goto out; + } else if (pqos->count == 0) { + goto out; + } + qsort((void *)pqos->values, pqos->count, sizeof(VLAN_Qos_8021q_elem), + compare_qos_8021q); + + while (i< pqos->count) { + if (pqos->values[i].from == last_num) { + CU_DEBUG("error: vlan 802.1.q qos setting have same<from> values: " + "last is %d, new is %d", last_num, pqos->values[i].from); + ret = 0; + goto out; + } + last_num = pqos->values[i].from; + if ((pqos->values[i].from< 0) || (pqos->values[i].from>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "from is %d.", pqos->values[i].from); + ret = 0; + goto out; + } + if ((pqos->values[i].to< 0) || (pqos->values[i].to>= 8)) { + CU_DEBUG("error: vlan 802.1.q qos setting have outbound value: " + "to is %d.", pqos->values[i].to); + ret = 0; + goto out; + } + i++; + } + + out: + return ret; +} + +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char* str) +{ + int ret = 1; + char *str_line = NULL; + char *temp; + char *saveptr = NULL; + char *invalptr1, *invalptr2; + int qos_num1, qos_num2; + VLAN_Qos_8021q qos; + + if (str == NULL) { + ret = 0; + goto out; + } + if (str[0] == '\0') { + ret = 1; + pqos->count = 0; + CU_DEBUG("empty vlan 802.1.q qos string found."); + goto out; + } + str_line = SAFE_STRDUP(str); + qos.count = 0; + + temp = strtok_r(str_line, " ",&saveptr); + while (temp != NULL) { + qos_num1 = strtol(temp,&invalptr1, 10); + if (temp == invalptr1) { + ret = 0; + goto out; + } + if (*invalptr1 != ':') { + ret = 0; + goto out; + } + invalptr1++; + qos_num2 = strtol(invalptr1,&invalptr2, 10); + if (invalptr1 == invalptr2) { + ret = 0; + goto out; + } + if (*invalptr2 != '\0') { + ret = 0; + goto out; + } + if (qos.count>= 8) { + ret = 0; + CU_DEBUG("too many settings found in vlan 802.1.q qos string [%s]", + str); + goto out; + } + qos.values[qos.count].from = qos_num1; + qos.values[qos.count].to = qos_num2; + qos.count++; + temp = strtok_r(NULL, " ",&saveptr); + } + ret = vlan_8021q_qos_check_valid(&qos); + if (ret == 1) { + *pqos = qos; + } + + out: + if (ret != 1) { + CU_DEBUG("vlan 802.1.q qos string [%s] is invalid.", str); + } + SAFE_FREE(str_line); + return ret; +} + +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos) +{ + char temp[16]; + int i; + VLAN_Qos_8021q qos = *pqos; + int ret = vlan_8021q_qos_check_valid(&qos); + if (ret != 1) { + goto out; + } + SAFE_MALLOC(*str, 64); + *str[0] = '\0'; + if (qos.count == 0) { + goto out; + } + i = 0; + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + while (i< qos.count) { + strcat(*str, " "); + snprintf(temp, sizeof(temp), "%d:%d", + qos.values[i].from, qos.values[i].to); + strcat(*str, temp); + i++; + } + + out: + return ret; +} + +int netmask_easy_to_inaddr(struct in_addr *paddr, const char* pmask) +{ + long mask_one_num = -1; + unsigned char *p; + int bitnum; + + mask_one_num = strtol(pmask, NULL, 10); + if ((mask_one_num< 0) || (mask_one_num> 32)) { + return 0; + } + + /* use network byte order */ + p = (unsigned char *)&paddr->s_addr; + memset(p, 0, 4); + while (mask_one_num> 8) { + *(p++) = 255; + mask_one_num -= 8; + } + bitnum = 7; + while (mask_one_num> 0) { + *p = *p + (1<<bitnum); + mask_one_num--; + bitnum--; + } + return 1; +} + +char *strtok_onetime(const char *str, const char *delim) +{ + char *t = strstr(str, delim); + char *ret_char; + int len; + if (t == NULL) { + return NULL; + } + len = t - str; + if (len<= 0) { + return NULL; + } + SAFE_MALLOC(ret_char, len+1); + strncpy(ret_char, str, len); + ret_char[len] = '\0'; + + return ret_char; +} + +char *combine_file_name(const char *prefix, const char *name) +{ + char *ret = NULL; + int size; + size = strlen(prefix) + strlen(name) + 1; + SAFE_CALLOC(ret, size, sizeof(char)); + snprintf(ret, size, "%s%s", prefix, name); + return ret; +} + +/* return the whole content length that need update. The data length keep + unchanged in the head part is returned in *unchanged_len which could be + used to avoid write whole data later. + requriement: cont must contain end character, prefix must be not NULL */ +static int replace_prop_str(char *cont, const int maxsize, const char *prefix, + const char *prop, int *unchanged_len) +{ + int target_len, origin_len; + int cont_len; + int valid_len = 0; + int prefix_len, prop_len = 0; + char *endchar1 = "\n"; + char *pprop_start, *pprop_end; + int head_len; + + cont_len = strlen(cont); + head_len = cont_len; + prefix_len = strlen(prefix); + if ((prop == NULL) || (*prop == '\0')) { + /* want the property removed */ + target_len = 0; + } else { + /* want the property changed */ + prop_len = strlen(prop); + target_len = prefix_len + prop_len; + } + + pprop_start = strstr(cont, prefix); + if (pprop_start == NULL) { + /* the content do not exist in original contents */ + if (target_len> 0) { + /* add the property */ + if ((cont_len + target_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + strcat(cont, prefix); + strcat(cont, prop); + valid_len = cont_len + target_len; + } else { + /* remove the property, but it do not exist, so skip */ + } + } else { + /* the content exist in original contents */ + /* locate the end of the property */ + pprop_end = strstr(pprop_start, endchar1); + if (pprop_end == NULL) { + /* last line */ + origin_len = strlen(pprop_start); + pprop_end = cont+cont_len; + } else { + origin_len = pprop_end - pprop_start; + } + if (target_len> 0) { + /* change the property */ + /* check the bound */ + if ((cont_len + target_len - origin_len)>= maxsize) { + CU_DEBUG("buffer is too small for the operation."); + valid_len = -1; + goto out; + } + /* move contents in the tail */ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + /* copy the content of the new string */ + memcpy(pprop_start+prefix_len, prop, prop_len); + head_len = pprop_start - cont + prefix_len; + } else { + /* remove the property */ + /* move contents in the tail to replace original string*/ + memmove(pprop_end+target_len-origin_len, pprop_end, + cont+cont_len+1-pprop_end); + head_len = pprop_start - cont; + } + valid_len = cont_len + target_len - origin_len; + } + + out: + if (unchanged_len != NULL) { + *unchanged_len = head_len; + } + return valid_len; +} + +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop) +{ + int fd = -1; + int fop_ret; + struct stat s; + struct flock lock; + int lock_state = -1; + char *cont = NULL; + char *pbuff; + int write_len; + int cont_len_update; + int cont_len_unchanged; + int ret = 0; + + if ((prefix == NULL) || (*prefix == '\0')) { + CU_DEBUG("no prefix for property set, could not replace the content."); + goto out; + } + + fd = open(path, O_RDWR, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + fstat(fd,&s); + if (s.st_size == 0) { + CU_DEBUG("file [%s] is empty, will not replace attr for it.", path); + ret = ERR_FILE_EMPTY; + goto out; + } else if (s.st_size>= CONFIGURE_FILE_MAX_SIZE) { + CU_DEBUG("file [%s] is too large, " + "it have %lld bytes, will not read it.", + path, (long long)s.st_size); + ret = ERR_FILE_TOO_LARGE; + goto out; + } + + SAFE_MALLOC(cont, CONFIGURE_FILE_MAX_SIZE); + lseek(fd, 0, SEEK_SET); + fop_ret = read(fd, cont, s.st_size); + cont[s.st_size] = '\0'; + cont_len_update = replace_prop_str(cont, CONFIGURE_FILE_MAX_SIZE, + prefix, prop,&cont_len_unchanged); + if (cont_len_update< 0) { + CU_DEBUG("file [%s] is too big to expand it with [%s%s].", + path, prefix, prop); + ret = ERR_FILE_TOO_LARGE; + goto out; + } else if (cont_len_update == 0) { + CU_DEBUG("the contents was not changed, do not need update it"); + ret = 1; + goto out; + } else { + if (ftruncate(fd, cont_len_unchanged) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + write_len = cont_len_update-cont_len_unchanged; + if (write_len> 0) { + lseek(fd, cont_len_unchanged, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset %d," + " cont is :\n%s\n", + path, write_len, cont_len_unchanged, cont); + pbuff = cont+cont_len_unchanged; + fop_ret = write(fd, pbuff, write_len); + } + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + SAFE_FREE(cont); + return ret; +} + +int configure_file_update(const char *path, const char *cont) +{ + int fd = -1; + int fop_ret; + struct flock lock; + int lock_state = -1; + int write_len; + int ret = 0; + + fd = open(path, O_RDWR|O_CREAT, 0644); + if (fd< 0) { + CU_DEBUG("Unable to open [%s], it does not exist.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock_state = fcntl(fd, F_SETLK,&lock); + if (lock_state< 0) { + CU_DEBUG("Failed to lock file [%s], it may be locked by other.", path); + ret = ERR_FILE_LOCK_FAIL; + goto out; + } + + if (ftruncate(fd, 0) != 0) { + CU_DEBUG("file [%s] Unable to truncate it", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + + write_len = strlen(cont); + if (write_len> 0) { + lseek(fd, 0, SEEK_SET); + CU_DEBUG("writing file [%s] for %d bytes with offset 0," + " cont is :\n%s\n", + path, write_len, cont); + fop_ret = write(fd, cont, write_len); + } + ret = 1; + + out: + if (fd>= 0) { + if (lock_state>= 0) { + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK,&lock); + } + close(fd); + } + return ret; +} + +int configure_file_remove(const char *path) +{ + int fd_ret; + int ret = 0; + if (access(path, F_OK) == 0) { + CU_DEBUG("Deleting %s.", path); + fd_ret = remove(path); + if (fd_ret != 0) { + CU_DEBUG("failed to remove %s.", path); + ret = ERR_FILE_OP_FAIL; + goto out; + } + } + + ret = 1; + out: + return ret; +} + +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting readonly cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + +out: + return stream; +} + +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno) +{ + FILE *stream = NULL; + char *suffix = PIPE_CMD_SUFFIX; + if ((strlen(cmd) + strlen(suffix))>= buf_size) { + CU_DEBUG("cmd [%s] is too long to append the suffix", cmd); + *errno = ERR_COMMAND_NO_READY; + goto out; + } + strcat(cmd, suffix); + CU_DEBUG("excuting system modification cmd [%s].", cmd); + stream = popen(cmd, type); + if (stream == NULL) { + CU_DEBUG("Failed to open pipe to run command"); + *errno = ERR_COMMAND_PIPE_ERR; + } + usleep(10000); + +out: + return stream; +} + +int get_host_linux_version(void) +{ + FILE *stream = NULL; + char cmd[64]; + char buff[256]; + int linenum; + int errno; + + if (g_linux_version != LINUX_UNKNOWN) { + goto out; + } + + cmd[0] = '\0'; + strcat(cmd, "lsb_release -a"); + stream = pipe_excute_command_type_read(cmd, sizeof(cmd), "r",&errno); + if (stream == NULL) { + goto out; + } + + linenum = -1; + g_linux_version = LINUX_OTHER; + while (fgets(buff, 256, stream) != NULL) { + linenum++; + if (linenum == 0) { + if (NULL == strstr(buff, "LSB")) { + CU_DEBUG("ERR: unable to get linux distribution version."); + g_linux_version = LINUX_FAIL_TO_GET; + } + } + if ((NULL != strstr(buff, "Red Hat")) || + (NULL != strstr(buff, "RedHat"))) { + g_linux_version = LINUX_REDHAT; + break; + } + } + + out: + if (stream != NULL) { + pclose(stream); + } + return g_linux_version; +} + +char *translate_error_no(int errno) +{ + char *ret = NULL; + switch (errno) { + case ERR_REQUEST_NOT_SUPPORT: + ret = "request is not supported now"; + break; + + case ERR_COMMAND_NOT_SET: + ret = "command is not set."; + break; + case ERR_COMMAND_PIPE_ERR: + ret = "failed in creating pipe to execute the command."; + break; + case ERR_COMMAND_NOT_SUPPORT: + ret = "command is not found, check u environment."; + break; + case ERR_COMMAND_NO_PERMISSION: + ret = "not enough authority to execute the command."; + break; + case ERR_COMMAND_NO_READY: + ret = "failed to build up the command line, check your input, " + "maybe it is too long."; + break; + case ERR_COMMAND_PARAMETER_WRONG: + ret = "got invalid paramenter, check your input."; + break; + case ERR_COMMAND_EXECUTION: + ret = "error happened in the excution of command."; + break; + + case ERR_DEVICE_EXCEED_MAXNUM: + ret = "too many devices found or set, check the environment."; + break; + case ERR_DEVICE_EXIST: + ret = "device already exist, can not execute the command."; + break; + case ERR_DEVICE_NOT_EXIST: + ret = "device do not exist, can not execute the command."; + break; + case ERR_DEVICE_ALREADY_DONE: + ret = "the operation you want have been done before, " + "will not do it again."; + break; + case ERR_DEVICE_CONNECT_OTHER: + ret = "the device you want to connect have been connect to another" + " device, can't change it directly."; + break; + + case ERR_FILE_OP_FAIL: + ret = "failed in accessing the file."; + break; + case ERR_FILE_EMPTY: + ret = "the file it want is empty."; + break; + case ERR_FILE_TOO_LARGE: + ret = "the file it want is too large."; + break; + case ERR_FILE_CONT_TOO_LARGE: + ret = "the content it want to combine to file is too large."; + break; + case ERR_FILE_LOCK_FAIL: + ret = "failed in locking the file, " + "check if other process is using it."; + break; + + case ERR_PERSIST_NOT_REDHAT: + ret = "host is not a RedHat distribution, can't persist the " + "configuration, it would not take effect after host is " + "rebooted. Other version would be supported in the future. " + "If you are sure host is RedHat, make sure command " + "<lsb_release -a> could work."; + break; + + default: + ret = "internal error."; + break; + } + return ret; +} diff --git a/libxkutil/host_network_helper.h b/libxkutil/host_network_helper.h new file mode 100644 index 0000000..a232221 --- /dev/null +++ b/libxkutil/host_network_helper.h @@ -0,0 +1,192 @@ +/* + * Copyright IBM Corp. 2011 + * + * Authors: + * Wenchao Xia<xiawenc@cn.ibm.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + */ + + +#ifndef HOST_NETWORK_HELPER_H +#define HOST_NETWORK_HELPER_H + +#include<stdio.h> +#include<stdlib.h> +#include<arpa/inet.h> + +#include "host_network_basic.h" + +#ifdef TESTLIB +#include "TestDefines.h" +#else +#include<libcmpiutil/libcmpiutil.h> +#endif + +#define LINUX_FAIL_TO_GET -2 +#define LINUX_UNKNOWN -1 +#define LINUX_OTHER 0 +#define LINUX_REDHAT 1 + +#define CMD_DEBUG_LEVEL 2 + +/* macro functions */ +#define CMD_DEBUG(lvl, fmt, args...) do { \ + if (CMD_DEBUG_LEVEL&& (lvl)<= CMD_DEBUG_LEVEL) { \ + debug_print(fmt, ##args); \ + } \ +} while (0) + +#define SAFE_MALLOC(p, size) \ +{ \ + (p) = malloc((size)); \ + if ((p) == NULL) { \ + CU_DEBUG("malloc failed."); \ + } \ +} + +#define SAFE_CALLOC(p, nmen, size) \ +{ \ + (p) = calloc((nmen), (size)); \ + if ((p) == NULL) { \ + CU_DEBUG("calloc failed."); \ + } \ +} + +#define SAFE_FREE(p) {free(p); (p) = NULL; } + + +/* Macro used to compare two char*, it would skip if ref is NULL. It would + only set the result when src != ref, user need to set the result to 1 by + default before use the macro. If not set, the it could be used to do + check multi times in "one fail all die" mode. Empty lines is the place + where result should be set to 1. */ +#define CHARS_COMPARE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define CHARS_COMPARE_CASE_BY_REF(src, ref, result) do { \ + if ((ref) == NULL) { \ + ; \ + } else { \ + if ((src) == NULL) { \ + (result) = 0; \ + } else { \ + if (0 == strcasecmp((src), (ref))) { \ + ; \ + } else { \ + (result) = 0; \ + } \ + } \ + } \ +} while (0) + +#define NUM_COMPARE_BY_REF(src, ref, result, default) do { \ + if ((ref) == (default)) { \ + ; \ + } else { \ + if ((src) == (ref)) { \ + ; \ + } else { \ + result = 0; \ + } \ + } \ +} while (0) + +#define CHARS_MERGE_NORMAL(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = strdup((src)); \ + } \ +} while (0) + +#define CHARS_MERGE_MOVE(dest, src) do { \ + if (((dest) == NULL)&& ((src) != NULL)) { \ + (dest) = (src); \ + (src) = NULL; \ + } \ +} while (0) + +#define NUM_MERGE(dest, src, default) do { \ + if ((dest) == (default)) { \ + (dest) = (src); \ + } \ +} while (0) + +/* this macro may cause "p" to be excuted twice if it is a function */ +#define SAFE_STRDUP(p) (p) == NULL ? NULL : strdup(p); + +/* this macro make sure "src" to be excuted once if it is function, so it is + safe for functions that have state logged, such as "strtok" */ +#define SAFE_STRDUP_WITH_FUNC(dest, src, iter) do { \ + (iter) = (src); \ + if ((iter) == NULL) { \ + (dest) = NULL; \ + } else { \ + (dest) = strdup((iter)); \ + } \ +} while (0) + +#define SAFE_PSTR_ARRAY_DUP(ppdest, dest_num, ppsrc, src_num, iter) do { \ + (dest_num) = (src_num); \ + (ppdest) = NULL; \ + if (((ppsrc) != NULL)&& ((src_num)> 0)) { \ + SAFE_CALLOC((ppdest), (src_num), sizeof(char *)); \ + (iter) = 0; \ + while ((iter)< (src_num)) { \ + *((ppdest)+(iter)) = SAFE_STRDUP(*((ppsrc)+(iter))); \ + (iter)++; \ + } \ + } \ +} while (0) + +/* functions */ +/* this function convert ip mask "24" in "192.1.0.9/24" to real mask num as + 255.255.255.0 */ +int netmask_easy_to_inaddr(struct in_addr *paddr, const char *pmask); + +/* this function would sort the pqos and check its values. */ +int vlan_8021q_qos_check_valid(VLAN_Qos_8021q *pqos); + +/* converting qos string of 802.1.Q, it should be as "0:0 1:0 2:0" */ +int vlan_8021q_qos_str_to_num(VLAN_Qos_8021q *pqos, const char *str); +int vlan_8021q_qos_num_to_str(char **str, const VLAN_Qos_8021q *pqos); + +/* following functions would return FILE popened, so it need pclose later, + cmd would be appended so it must be writable. */ +FILE *pipe_excute_command_type_read(char *cmd, const int buf_size, + const char *type, int *errno); +FILE *pipe_excute_command_type_write(char *cmd, const int buf_size, + const char *type, int *errno); + +/* following functions would return string by malloc, so it need free later */ +char *strtok_onetime(const char *str, const char *delim); +char *combine_file_name(const char *prefix, const char *name); + +/* write the configuration file */ +int configure_file_update(const char *path, const char *cont); +/* remove the configuration file */ +int configure_file_remove(const char *path); +/* replace one attribute, the file have format with one line for one propety */ +int configure_file_replace_attr(const char *path, const char *prefix, + const char *prop); + +int get_host_linux_version(void); + +char *translate_error_no(int errno); + +#endif
-- Chip Vincent Open Virtualization IBM Linux Technology Center cvincent@linux.vnet.ibm.com