/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include "cfga_ib.h"
#include "cfga_conf.h"
#include <sys/stat.h>
/*
* cfga_conf.c
*
* This file supports adding/deleting/listing services from IBCONF_FILE.
*/
/*
* function prototypes:
*/
static ib_service_type_t ib_get_var_type(char *);
static ib_token_t ib_lex(char *, char **);
static void ib_find_eol();
static int ib_get_string(char **, char *);
static int ib_service_record_add(char *,
ib_service_type_t);
static ib_token_t ib_get_services(char **);
static boolean_t ib_cmp_service();
static void ib_free_service_recs(void);
static int ib_cleanup_file(int);
static int ib_init_file(char **);
int ib_add_service(char **);
int ib_delete_service(char **);
int ib_list_services(struct cfga_msg *, char **);
static cfga_ib_ret_t ib_conf_control_ioctl(char *, uint_t);
static int ib_service_record_valid(char *);
extern void cfga_msg(struct cfga_msg *, const char *);
/* Global variables */
/*
* supported "name=value" pairs from IBCONF_FILE
*/
static ibcfg_var_t ibcfg_varlist[] = {
{ "name", IB_NAME },
{ "class", IB_CLASS },
{ "port-svc-list", IB_PORT_SERVICE },
{ "vppa-svc-list", IB_VPPA_SERVICE },
{ "hca-svc-list", IB_HCASVC_SERVICE },
{ NULL, IB_NONE }
};
static char ibconf_file[] = IBCONF_FILE; /* file being read */
static int ibcfg_linenum = 1; /* track line#s */
static int ibcfg_cntr = 0; /* current char read */
static int ibcfg_brec = 0; /* beginning of rec */
static int bvpparec = 0; /* begin of vppa rec */
static int bportrec = 0; /* begin of port rec */
static int bhcarec = 0; /* begin of HCA rec */
static int ibcfg_btoken = 0; /* begin of new token */
static mutex_t ibcfg_lock = DEFAULTMUTEX; /* lock for the file */
static int ibcfg_fd = -1; /* file descriptor */
static int ibcfg_tmpfd = 0; /* tmp file "fd" */
static char *file_buf = (char *)NULL; /* read file into buf */
static char *tmpnamef = (char *)NULL; /* tmp file name */
static boolean_t wrote_tmp = B_FALSE; /* tmp file write in */
/* progress indicator */
static struct stat ibcfg_st; /* file stat struct */
static int ibcfg_nport_services; /* # of PORT services */
static int ibcfg_nvppa_services; /* # of VPPA services */
static int ibcfg_nhca_services; /* # of HCA services */
static ib_svc_rec_t *ibcfg_vppa_head; /* VPPA service recs */
static ib_svc_rec_t *ibcfg_port_head; /* PORT service recs */
static ib_svc_rec_t *ibcfg_hca_head; /* HCA service recs */
extern char *service_name; /* service name */
extern ib_service_type_t service_type; /* service type */
/*
* Function:
* ib_get_var_type
* Input:
* str - A parsed string from IBCONF_FILE
* Output:
* NONE
* Returns:
* Service type
* Description:
* Returns the field from the token
*/
static ib_service_type_t
ib_get_var_type(char *str)
{
register ibcfg_var_t *cfgvar;
cfgvar = &ibcfg_varlist[0];
while (cfgvar->type != IB_NONE) {
if (strcasecmp(cfgvar->name, str) == NULL)
break;
else
cfgvar++;
}
return (cfgvar->type);
}
/*
* Function:
* ib_lex
* Input:
* NONE
* Output:
* val - value just read
* errmsg - pointer to error message string, if there are any errors
* Returns:
* valid IB token
* Description:
* Read tokens from the IBCONF_FILE and parse them
*/
/* ARGSUSED */
static ib_token_t
ib_lex(char *val, char **errmsg)
{
int ch, oval, badquote;
char *cp = val;
ib_token_t token;
while ((ch = GETC(file_buf, ibcfg_cntr)) == ' ' || ch == '\t')
;
/* make a note of the beginning of token */
ibcfg_btoken = ibcfg_cntr - 1;
*cp++ = (char)ch;
switch (ch) {
case '=':
token = EQUALS;
break;
case '&':
token = AMPERSAND;
break;
case '|':
token = BIT_OR;
break;
case '*':
token = STAR;
break;
case '#':
token = POUND;
break;
case ':':
token = COLON;
break;
case ';':
token = SEMICOLON;
break;
case ',':
token = COMMA;
break;
case '/':
token = SLASH;
break;
case ' ':
case '\t':
case '\f':
while ((ch = GETC(file_buf, ibcfg_cntr)) == ' ' ||
ch == '\t' || ch == '\f')
*cp++ = (char)ch;
(void) UNGETC(ibcfg_cntr);
token = WHITE_SPACE;
break;
case '\n':
case '\r':
token = NEWLINE;
break;
case '"':
cp--;
badquote = 0;
while (!badquote && (ch = GETC(file_buf, ibcfg_cntr)) != '"') {
switch (ch) {
case '\n':
case -1:
(void) snprintf(*errmsg, MAXPATHLEN,
"Missing \"");
cp = val;
*cp++ = '\n';
badquote = 1;
/* since we consumed the newline/EOF */
(void) UNGETC(ibcfg_cntr);
break;
case '\\':
ch = (char)GETC(file_buf, ibcfg_cntr);
if (!isdigit(ch)) {
/* escape the character */
*cp++ = (char)ch;
break;
}
oval = 0;
while (ch >= '0' && ch <= '7') {
ch -= '0';
oval = (oval << 3) + ch;
ch = (char)GETC(file_buf, ibcfg_cntr);
}
(void) UNGETC(ibcfg_cntr);
/* check for character overflow? */
if (oval > 127) {
(void) snprintf(*errmsg, MAXPATHLEN,
"Character overflow detected.\n");
}
*cp++ = (char)oval;
break;
default:
*cp++ = (char)ch;
break;
}
}
token = STRING;
break;
default:
if (ch == -1) {
token = EOF;
break;
}
/*
* detect a lone '-' (including at the end of a line), and
* identify it as a 'name'
*/
if (ch == '-') {
*cp++ = (char)(ch = GETC(file_buf, ibcfg_cntr));
if (iswhite(ch) || (ch == '\n')) {
(void) UNGETC(ibcfg_cntr);
cp--;
token = NAME;
break;
}
} else if (isunary(ch)) {
*cp++ = (char)(ch = GETC(file_buf, ibcfg_cntr));
}
if (isdigit(ch)) {
if (ch == '0') {
if ((ch = GETC(file_buf, ibcfg_cntr)) == 'x') {
*cp++ = (char)ch;
ch = GETC(file_buf, ibcfg_cntr);
while (isxdigit(ch)) {
*cp++ = (char)ch;
ch = GETC(file_buf, ibcfg_cntr);
}
(void) UNGETC(ibcfg_cntr);
token = HEXVAL;
} else {
goto digit;
}
} else {
ch = GETC(file_buf, ibcfg_cntr);
digit:
while (isdigit(ch)) {
*cp++ = (char)ch;
ch = GETC(file_buf, ibcfg_cntr);
}
(void) UNGETC(ibcfg_cntr);
token = DECVAL;
}
} else if (isalpha(ch) || ch == '\\') {
if (ch != '\\') {
ch = GETC(file_buf, ibcfg_cntr);
} else {
/*
* if the character was a backslash,
* back up so we can overwrite it with
* the next (i.e. escaped) character.
*/
cp--;
}
while (isnamechar(ch) || ch == '\\') {
if (ch == '\\')
ch = GETC(file_buf, ibcfg_cntr);
*cp++ = (char)ch;
ch = GETC(file_buf, ibcfg_cntr);
}
(void) UNGETC(ibcfg_cntr);
token = NAME;
} else
return (-1);
break;
}
*cp = '\0';
return (token);
}
/*
* Function:
* ib_find_eol
* Input:
* NONE
* Output:
* NONE
* Returns:
* NONE
* Description:
* Leave NEWLINE as the next character.
*/
static void
ib_find_eol()
{
int ch;
while ((ch = GETC(file_buf, ibcfg_cntr)) != -1) {
if (isnewline(ch)) {
(void) UNGETC(ibcfg_cntr);
break;
}
}
}
/*
* Function:
* ib_get_string
* Input:
* tchar - name of the string
* Output:
* llptr - Valid string
* Returns:
* 1 for success, NULL for errors.
* Description:
* The next item on the line is a string value. Allocate memory for
* it and copy the string. Return 1, and set arg ptr to newly allocated
* and initialized buffer, or NULL if an error occurs.
*/
static int
ib_get_string(char **llptr, char *tchar)
{
int tlen = strlen(tchar);
char *cp;
char *start = (char *)0;
start = tchar;
/* copy string */
if ((cp = (char *)calloc(tlen + 1, sizeof (char))) == (char *)NULL) {
*llptr = NULL;
return (0);
}
bzero(cp, tlen + 1);
*llptr = cp;
for (; tlen > 0; tlen--) {
/* convert some common escape sequences */
if (*start == '\\') {
switch (*(start + 1)) {
case 't':
/* tab */
*cp++ = '\t';
tlen--;
start += 2;
break;
case 'n':
/* new line */
*cp++ = '\n';
tlen--;
start += 2;
break;
case 'b':
/* back space */
*cp++ = '\b';
tlen--;
start += 2;
break;
default:
/* simply copy it */
*cp++ = *start++;
break;
}
} else {
*cp++ = *start++;
}
}
*cp = '\0';
return (1);
}
/*
* Function:
* ib_service_record_add
* Input:
* service - name of the service
* type - type of the service
* Output:
* rec - one valid service record
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* Add one record to internal data structures
*/
static int
ib_service_record_add(char *service, ib_service_type_t type)
{
ib_svc_rec_t *tmp, *recp;
DPRINTF("ib_service_record_add: (%x, %s) "
"(#port = %d #vppa = %d #hca = %d)\n", type, service,
ibcfg_nport_services, ibcfg_nvppa_services,
ibcfg_nhca_services);
recp = (ib_svc_rec_t *)calloc(1, sizeof (ib_svc_rec_t));
if (recp == NULL)
return (CFGA_IB_ALLOC_FAIL);
recp->type = type;
recp->name = strdup((char *)service);
if (type == IB_PORT_SERVICE) {
if (ibcfg_port_head) {
for (tmp = ibcfg_port_head; tmp->next != NULL; )
tmp = tmp->next;
tmp->next = recp;
} else
ibcfg_port_head = recp;
ibcfg_nport_services++;
} else if (type == IB_VPPA_SERVICE) {
if (ibcfg_vppa_head) {
for (tmp = ibcfg_vppa_head; tmp->next != NULL; )
tmp = tmp->next;
tmp->next = recp;
} else
ibcfg_vppa_head = recp;
ibcfg_nvppa_services++;
} else if (type == IB_HCASVC_SERVICE) {
if (ibcfg_hca_head) {
for (tmp = ibcfg_hca_head; tmp->next != NULL; )
tmp = tmp->next;
tmp->next = recp;
} else
ibcfg_hca_head = recp;
ibcfg_nhca_services++;
}
return (CFGA_IB_OK);
}
/*
* Function:
* ib_get_services
* Input:
* errmsg - Error message filled in case of a failure
* Output:
* rec - one valid service record
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* Fetch one record from the IBCONF_FILE
*/
static ib_token_t
ib_get_services(char **errmsg)
{
char tokval[MAXLINESIZE];
char *llptr;
boolean_t sor = B_TRUE;
ib_token_t token;
ib_service_type_t cfgvar;
ib_parse_state_t parse_state = IB_NEWVAR;
token = ib_lex(tokval, errmsg);
while ((token != EOF) && (token != SEMICOLON)) {
if (token == STAR || token == POUND) {
/* skip comments */
ib_find_eol();
} else if (token == NEWLINE) {
ibcfg_linenum++;
} else if (token == NAME || token == STRING) {
if (parse_state == IB_NEWVAR) {
cfgvar = ib_get_var_type(tokval);
if (cfgvar == IB_NONE) {
parse_state = IB_ERROR;
(void) snprintf(*errmsg, MAXPATHLEN,
"Syntax Error: Invalid type %s",
tokval);
} else {
/* Note the beginning of the entry */
if (sor) {
ibcfg_brec = ibcfg_btoken;
sor = B_FALSE;
}
parse_state = IB_CONFIG_VAR;
if (cfgvar == IB_PORT_SERVICE)
bportrec = ibcfg_cntr + 1;
else if (cfgvar == IB_VPPA_SERVICE)
bvpparec = ibcfg_cntr + 1;
else if (cfgvar == IB_HCASVC_SERVICE)
bhcarec = ibcfg_cntr + 1;
}
} else if (parse_state == IB_VAR_VALUE) {
llptr = NULL;
if (ib_get_string(&llptr, tokval)) {
if ((cfgvar == IB_PORT_SERVICE) ||
(cfgvar == IB_VPPA_SERVICE) ||
(cfgvar == IB_HCASVC_SERVICE)) {
if (ib_service_record_valid(
llptr) &&
ib_service_record_add(
(char *)llptr, cfgvar) !=
CFGA_IB_OK) {
return (E_O_F);
} else {
parse_state =
IB_CONFIG_VAR;
}
} else if ((cfgvar == IB_NAME) ||
(cfgvar == IB_CLASS)) {
free((char *)llptr);
parse_state = IB_NEWVAR;
} else {
free((char *)llptr);
parse_state = IB_ERROR;
}
} else {
parse_state = IB_ERROR;
(void) snprintf(*errmsg, MAXPATHLEN,
"Syntax Error: Invalid value %s "
"for type: %s\n", tokval,
ibcfg_varlist[cfgvar].name);
}
} else if (parse_state == IB_ERROR) {
/* just skip */
DPRINTF("ib_get_services: ERROR\n");
} else {
parse_state = IB_ERROR;
(void) snprintf(*errmsg, MAXPATHLEN,
"Syntax Error: at %s", tokval);
}
} else if (token == COMMA || token == EQUALS) {
if (parse_state == IB_CONFIG_VAR) {
if (cfgvar == IB_NONE) {
parse_state = IB_ERROR;
(void) snprintf(*errmsg, MAXPATHLEN,
"Syntax Error: unexpected '='");
} else {
parse_state = IB_VAR_VALUE;
}
} else if (parse_state != IB_ERROR) {
(void) snprintf(*errmsg, MAXPATHLEN,
"Syntax Error: unexpected '='");
parse_state = IB_ERROR;
}
} else {
(void) snprintf(*errmsg, MAXPATHLEN,
"Syntax Error: at: %s", tokval);
parse_state = IB_ERROR;
}
token = ib_lex(tokval, errmsg);
if (ib_get_var_type(tokval) != IB_NONE)
parse_state = IB_NEWVAR;
}
return (token);
}
/*
* Function:
* ib_cmp_service
* Input:
* NONE
* Output:
* NONE
* Returns:
* B_TRUE if this service is already seen. B_FALSE if not.
* Description:
* Compare the service just read from the services already seen.
* Check if this service was already seen or not.
*/
static boolean_t
ib_cmp_service()
{
ib_svc_rec_t *recp;
DPRINTF("ib_cmp_service: (%x, %s) "
"(#port = %d #vppa = %d #hca = %d)\n", service_type,
service_name, ibcfg_nport_services, ibcfg_nvppa_services,
ibcfg_nhca_services);
for (recp = ibcfg_port_head; recp != NULL; recp = recp->next) {
DPRINTF("ib_cmp_service:P usvc = %s, usvc_name = %s\n",
service_name, recp->name ? recp->name : "NONE");
if (recp->name && strcmp(recp->name, service_name) == 0)
return (B_TRUE);
}
for (recp = ibcfg_vppa_head; recp != NULL; recp = recp->next) {
DPRINTF("ib_cmp_service:V utype = %x, usvc_name = %s\n",
recp->type, recp->name ? recp->name : "NONE");
if (recp->name && strcmp(recp->name, service_name) == 0)
return (B_TRUE);
}
for (recp = ibcfg_hca_head; recp != NULL; recp = recp->next) {
DPRINTF("ib_cmp_service:V utype = %x, usvc_name = %s\n",
recp->type, recp->name ? recp->name : "NONE");
if (recp->name && strcmp(recp->name, service_name) == 0)
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Function:
* ib_free_service_recs
* Input:
* NONE
* Output:
* NONE
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* Free the service records allocated in ib_get_services
*/
static void
ib_free_service_recs(void)
{
ib_svc_rec_t *tmp, *recp;
DPRINTF("ib_free_service_recs: "
"#port_services = %d, #vppa_services = %d, #hca_services = %d\n",
ibcfg_nport_services, ibcfg_nvppa_services, ibcfg_nhca_services);
for (recp = ibcfg_port_head; recp != NULL; ) {
if (recp && strlen(recp->name))
S_FREE(recp->name);
tmp = recp;
recp = recp->next;
S_FREE(tmp);
}
for (recp = ibcfg_vppa_head; recp != NULL; ) {
if (recp && strlen(recp->name))
S_FREE(recp->name);
tmp = recp;
recp = recp->next;
S_FREE(tmp);
}
for (recp = ibcfg_hca_head; recp != NULL; ) {
if (recp && strlen(recp->name))
S_FREE(recp->name);
tmp = recp;
recp = recp->next;
S_FREE(tmp);
}
}
/*
* Function:
* ib_cleanup_file
* Input:
* rval - error return value
* Output:
* NONE
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* Cleanup IBCONF_FILE etc.
*/
static int
ib_cleanup_file(int rval)
{
int rv = rval;
ib_free_service_recs();
if (lockf(ibcfg_fd, F_ULOCK, 0) == -1) {
DPRINTF("ib_cleanup_file: unlock file %s failed\n",
ibconf_file);
rv = CFGA_IB_UNLOCK_FILE_ERR;
}
S_FREE(file_buf);
close(ibcfg_fd);
ibcfg_fd = -1;
if (ibcfg_tmpfd && wrote_tmp == B_TRUE) {
DPRINTF("ib_cleanup_file: tmpfile %s being renamed to %s\n",
tmpnamef, IBCONF_FILE);
close(ibcfg_tmpfd);
rename((const char *)tmpnamef, (const char *)IBCONF_FILE);
unlink(tmpnamef);
}
(void) mutex_unlock(&ibcfg_lock);
return (rv);
}
/*
* Function:
* ib_init_file
* Input:
* NONE
* Output:
* errmsg - Error message filled in case of a failure
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* Initialize IBCONF_FILE for reading
*/
static int
ib_init_file(char **errmsg)
{
(void) mutex_lock(&ibcfg_lock);
if (*errmsg == (char *)NULL) {
if ((*errmsg = calloc(MAXPATHLEN, 1)) == (char *)NULL) {
(void) mutex_unlock(&ibcfg_lock);
DPRINTF("ib_init_file: calloc errmsg failed\n");
return (CFGA_IB_CONFIG_FILE_ERR);
}
}
/* Open the .conf file */
if ((ibcfg_fd = open(ibconf_file, O_RDWR, 0666)) == -1) {
(void) snprintf(*errmsg, MAXPATHLEN,
"failed to open %s file\n", ibconf_file);
(void) mutex_unlock(&ibcfg_lock);
return (CFGA_IB_CONFIG_FILE_ERR);
}
/* Lock the file so that another cfgadm instance doesn't modify it */
if (lockf(ibcfg_fd, F_TLOCK, 0) == -1) {
(void) snprintf(*errmsg, MAXPATHLEN,
"failed to lock %s file\n", ibconf_file);
close(ibcfg_fd);
ibcfg_fd = -1;
(void) mutex_unlock(&ibcfg_lock);
return (CFGA_IB_LOCK_FILE_ERR);
}
if (fstat(ibcfg_fd, &ibcfg_st) != 0) {
DPRINTF("ib_init_file: failed to fstat %s file\n", ibconf_file);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
/* Allocate a buffer for the file */
if ((file_buf = (char *)malloc(ibcfg_st.st_size)) == NULL) {
DPRINTF("ib_init_file: failed to fstat %s file\n",
ibconf_file);
return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
}
/* Check if size matches */
if (ibcfg_st.st_size != read(ibcfg_fd, file_buf, ibcfg_st.st_size)) {
DPRINTF("ib_init_file: failed to read %s file\n", ibconf_file);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
/*
* These variables need to be reinitialized here as they may
* have been modified by a previous thread that called this
* function
*/
ibcfg_linenum = 1;
ibcfg_cntr = 0;
ibcfg_brec = 0;
ibcfg_btoken = 0;
ibcfg_nport_services = 0;
ibcfg_nvppa_services = 0;
ibcfg_nhca_services = 0;
ibcfg_port_head = (ib_svc_rec_t *)NULL;
ibcfg_vppa_head = (ib_svc_rec_t *)NULL;
ibcfg_hca_head = (ib_svc_rec_t *)NULL;
return (CFGA_IB_OK);
}
/*
* Function:
* ib_add_service
* Input:
* NONE
* Output:
* errmsg - Error message filled in case of a failure
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* open IBCONF_FILE and add "service_name".
*/
int
ib_add_service(char **errmsg)
{
int rval;
char *sbuf;
boolean_t found = B_FALSE;
ib_token_t token = NEWLINE;
DPRINTF("ib_add_service: type = %x, service_name=%s\n", service_type,
service_name);
if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) {
DPRINTF("ib_add_service: initializing file failed\n");
return (rval);
}
/* Start reading the file */
while (token != EOF) {
token = ib_get_services(errmsg);
found = ib_cmp_service();
if (found == B_TRUE) {
DPRINTF("ib_add_service: token=%x, found=%x\n",
token, found);
break;
}
}
/* Service shouldn't already exist while adding */
if (found) {
(void) snprintf(*errmsg, MAXPATHLEN, "service entry %s exists ",
service_name);
DPRINTF("ib_add_service: invalid add operation\n");
return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR));
}
DPRINTF("!FOUND and adding\n");
switch (service_type) {
case IB_PORT_SERVICE :
ibcfg_brec = bportrec;
break;
case IB_VPPA_SERVICE :
ibcfg_brec = bvpparec;
break;
case IB_HCASVC_SERVICE :
ibcfg_brec = bhcarec;
break;
default :
DPRINTF("ib_add_service: invalid add operation\n");
return (ib_cleanup_file(CFGA_IB_SVC_INVAL_ERR));
}
if ((sbuf = (char *)calloc(12, sizeof (char))) == NULL) {
DPRINTF("ib_add_service: failed to calloc sbuf %s file\n",
ibconf_file);
return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
}
if (file_buf[ibcfg_brec] == '"' && file_buf[ibcfg_brec + 1] == '"') {
(void) snprintf(sbuf, 9, "%s", service_name);
ibcfg_brec += 1;
} else
(void) snprintf(sbuf, 9, "\"%s\", ", service_name);
/* Seek to the beginning of the file */
if (lseek(ibcfg_fd, ibcfg_brec, SEEK_SET) == -1) {
DPRINTF("ib_add_service: lseek %s file failed\n", ibconf_file);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
/* Add service to w/ IBNEX */
if (ib_conf_control_ioctl(service_name, IBNEX_CONF_ENTRY_ADD)) {
DPRINTF("ib_add_service: ioctl add failed %d\n", errno);
(void) snprintf(*errmsg, MAXPATHLEN, "failed to add "
"%s service incore ", service_name);
return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR));
}
/* Write the modified file */
if (write(ibcfg_fd, sbuf, strlen(sbuf)) == -1) {
DPRINTF("ib_add_service: write %s file failed\n", ibconf_file);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
/* Write the rest of the file as it was */
if (write(ibcfg_fd, file_buf + ibcfg_brec,
ibcfg_st.st_size - ibcfg_brec) == -1) {
DPRINTF("ib_add_service: write %s file failed 2\n",
ibconf_file);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
return (ib_cleanup_file(rval));
}
/*
* Function:
* ib_delete_service
* Input:
* NONE
* Output:
* errmsg - Error message filled in case of a failure
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* open ib.conf file and delete "service_name"
*/
int
ib_delete_service(char **errmsg)
{
int rval;
int num_svcs;
int skip_len;
int sbuf_len;
int tot_len;
char tmp[12];
char *sbuf = (char *)NULL;
boolean_t found = B_FALSE;
ib_token_t token = NEWLINE;
ib_svc_rec_t *recp;
DPRINTF("ib_delete_service: type = %x, service_name=%s\n",
service_type, service_name);
if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) {
DPRINTF("ib_delete_service: initializing file failed\n");
return (rval);
}
/* Start reading the file */
while (token != EOF) {
token = ib_get_services(errmsg);
found = ib_cmp_service(); /* search for a match */
if (found == B_TRUE) {
DPRINTF("ib_delete_service: token=%x, found=%x\n",
token, found);
break;
}
}
/* No service found, return */
if (!found) {
DPRINTF("ib_delete_service: invalid delete operation\n");
(void) snprintf(*errmsg, MAXPATHLEN, "service entry %s "
"does not exist ", service_name);
return (ib_cleanup_file(CFGA_IB_SVC_NO_EXIST_ERR));
}
DPRINTF("FOUND and deleting \n");
switch (service_type) {
case IB_PORT_SERVICE :
ibcfg_brec = bportrec;
num_svcs = ibcfg_nport_services;
break;
case IB_VPPA_SERVICE :
ibcfg_brec = bvpparec;
num_svcs = ibcfg_nvppa_services;
break;
case IB_HCASVC_SERVICE :
ibcfg_brec = bhcarec;
num_svcs = ibcfg_nhca_services;
break;
default :
DPRINTF("ib_delete_service: invalid delete "
"operation\n");
return (ib_cleanup_file(CFGA_IB_SVC_INVAL_ERR));
}
if ((sbuf = (char *)calloc(num_svcs * 8, sizeof (char))) == NULL) {
DPRINTF("ib_delete_service: sbuf alloc failed %s\n",
ibconf_file);
return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
}
if (num_svcs == 1) {
(void) snprintf(sbuf, 9, "\"\"");
sbuf_len = 2;
skip_len = 0;
} else {
if (service_type == IB_PORT_SERVICE) {
for (recp = ibcfg_port_head; recp; recp = recp->next) {
if (strcmp(recp->name, service_name) == 0)
continue;
(void) snprintf(tmp, 9, "\"%s\", ", recp->name);
(void) strcat(sbuf, tmp);
}
} else if (service_type == IB_VPPA_SERVICE) {
for (recp = ibcfg_vppa_head; recp; recp = recp->next) {
if (strcmp(recp->name, service_name) == 0)
continue;
(void) snprintf(tmp, 9, "\"%s\", ", recp->name);
(void) strcat(sbuf, tmp);
}
} else {
for (recp = ibcfg_hca_head; recp; recp = recp->next) {
if (strcmp(recp->name, service_name) == 0)
continue;
(void) snprintf(tmp, 9, "\"%s\", ", recp->name);
(void) strcat(sbuf, tmp);
}
}
skip_len = 4;
sbuf_len = strlen(sbuf);
sbuf[sbuf_len - 2] = '\0';
sbuf_len -= 2;
}
tot_len = strlen(service_name) + skip_len;
tmpnamef = tmpnam(ibconf_file);
DPRINTF("ib_delete_service: tmpnamef = %s\n", tmpnamef);
if ((ibcfg_tmpfd = creat(tmpnamef, 0666)) == -1) {
(void) snprintf(*errmsg, MAXPATHLEN,
"failed to creat %s file\n", ibconf_file);
DPRINTF("ib_delete_service: failed to creat tmpnamef\n");
return (ib_cleanup_file(CFGA_IB_ALLOC_FAIL));
}
/* Delete service from IBNEX */
if (ib_conf_control_ioctl(service_name, IBNEX_CONF_ENTRY_DEL)) {
DPRINTF("ib_delete_service: ioctl delete failed %d\n", errno);
(void) snprintf(*errmsg, MAXPATHLEN, "failed to delete "
"in core %s entry ", service_name);
close(ibcfg_tmpfd);
unlink(tmpnamef);
return (ib_cleanup_file(CFGA_IB_SVC_EXISTS_ERR));
}
/* write till ibcfg_brec */
if (write(ibcfg_tmpfd, file_buf, ibcfg_brec) == -1) {
DPRINTF("ib_delete_service: write %s file failed 1\n",
ibconf_file);
close(ibcfg_tmpfd);
unlink(tmpnamef);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
/* write modified buffer */
if (write(ibcfg_tmpfd, sbuf, sbuf_len) == -1) {
DPRINTF("ib_delete_service: write %s file failed 2\n",
ibconf_file);
close(ibcfg_tmpfd);
unlink(tmpnamef);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
/* Write the rest of the file as it was */
if (write(ibcfg_tmpfd, file_buf + ibcfg_brec + sbuf_len + tot_len,
ibcfg_st.st_size - ibcfg_brec - sbuf_len - tot_len) == -1) {
DPRINTF("ib_delete_service: write %s file failed 3\n",
ibconf_file);
close(ibcfg_tmpfd);
unlink(tmpnamef);
return (ib_cleanup_file(CFGA_IB_CONFIG_FILE_ERR));
}
wrote_tmp = B_TRUE;
/* No error encountered */
return (ib_cleanup_file(rval));
}
/*
* Function:
* ib_list_services
* Input:
* msgp - CFGADM message pointer
* Output:
* errmsg - Error message filled in case of a failure
* Returns:
* CFGA_IB_OK on success or an appropriate error
* Description:
* open IBCONF_FILE and list services.
*/
int
ib_list_services(struct cfga_msg *msgp, char **errmsg)
{
int rval = CFGA_IB_OK;
char pbuf[IBCONF_SERVICE_HDR_LEN];
ib_token_t token = NEWLINE;
ib_svc_rec_t *recp;
DPRINTF("ib_list_services:\n");
if ((rval = ib_init_file(errmsg)) != CFGA_IB_OK) {
DPRINTF("ib_list_services: initializing file failed\n");
return (rval);
}
/* start reading the file */
while (token != EOF)
token = ib_get_services(errmsg);
DPRINTF("ib_list_services: #port_services = %d, #vppa_services = %d,"
" #hca_services = %d\n", ibcfg_nport_services,
ibcfg_nvppa_services, ibcfg_nhca_services);
bzero(pbuf, IBCONF_SERVICE_HDR_LEN);
if (ibcfg_nport_services) {
(void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN,
IBCONF_PORT_SERVICE_HDR);
cfga_msg(msgp, pbuf);
for (recp = ibcfg_port_head; recp; recp = recp->next) {
DPRINTF("ib_list_services: svc_name = %s\n",
recp->name ? recp->name : "NONE");
(void) snprintf(pbuf, 14, "\t\t%s\n", recp->name);
cfga_msg(msgp, pbuf);
}
(void) snprintf(pbuf, 2, "\n");
cfga_msg(msgp, pbuf);
}
if (ibcfg_nvppa_services) {
(void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN,
IBCONF_VPPA_SERVICE_HDR);
cfga_msg(msgp, pbuf);
for (recp = ibcfg_vppa_head; recp; recp = recp->next) {
DPRINTF("ib_list_services: svc_name = %s\n",
strlen(recp->name) > 0 ? recp->name : "NONE");
(void) snprintf(pbuf, 14, "\t\t%s\n", recp->name);
cfga_msg(msgp, pbuf);
}
}
if (ibcfg_nhca_services) {
(void) snprintf(pbuf, IBCONF_SERVICE_HDR_LEN,
IBCONF_HCA_SERVICE_HDR);
cfga_msg(msgp, pbuf);
for (recp = ibcfg_hca_head; recp; recp = recp->next) {
DPRINTF("ib_list_services: svc_name = %s\n",
strlen(recp->name) > 0 ? recp->name : "NONE");
(void) snprintf(pbuf, 14, "\t\t%s\n", recp->name);
cfga_msg(msgp, pbuf);
}
}
return (ib_cleanup_file(CFGA_IB_OK));
}
/*
* Function:
* ib_conf_control_ioctl
* Input:
* svc - Service being added/deleted
* cmd - Command to DEVCTL_AP_CONTROL devctl
* Output:
* NONE
* Returns:
* CFGA_IB_OK if it succeeds or an appropriate error.
* Description:
* Issues DEVCTL_AP_CONTROL devctl with cmd
*/
static cfga_ib_ret_t
ib_conf_control_ioctl(char *svc, uint_t cmd)
{
int apid_fd = -1;
cfga_ib_ret_t rv = CFGA_IB_OK;
struct ibnex_ioctl_data ioctl_data;
DPRINTF("Service = %s len = %x, type = %x\n", svc,
strlen(svc), service_type);
/* try to open the static IB ap_id */
if ((apid_fd = open(IB_STATIC_APID, O_RDONLY)) == -1) {
DPRINTF("ib_conf_control_ioctl: open failed: errno = %d\n",
errno);
/* Provides a more useful error msg */
rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_OPEN_ERR;
return (rv);
}
ioctl_data.cmd = cmd;
ioctl_data.misc_arg = (uint_t)service_type;
ioctl_data.buf = (caddr_t)svc;
ioctl_data.bufsiz = strlen(svc);
ioctl_data.ap_id = (caddr_t)IB_STATIC_APID;
ioctl_data.ap_id_len = strlen(IB_STATIC_APID);
if (ioctl(apid_fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
DPRINTF("ib_conf_control_ioctl: size ioctl ERR, errno: %d\n",
errno);
rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
}
(void) close(apid_fd);
return (rv);
}
/*
* This functions checks if the service name is valid. Valid
* service names have :
* 0 < strlen(name) <= 4
* Service name is unique
* Returns: 0 - Name is not valid, 1 - Name is valid
*/
static int
ib_service_record_valid(char *sname)
{
int rc = 1, len;
char *tmp_service_name;
tmp_service_name = service_name;
service_name = strdup(sname);
len = strlen(sname);
if (len == 0 || len > 4) {
S_FREE(service_name);
service_name = tmp_service_name;
return (0);
}
if (ib_cmp_service() == B_TRUE)
rc = 0;
S_FREE(service_name);
service_name = tmp_service_name;
return (rc);
}