#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <syslog.h>
#include <libdevice.h>
#include <sys/fibre-channel/fcio.h>
#include "common.h"
static int parse_line(char *line, char *path, char *wwn, char *filename);
static int create_ap_instance(char *ap_id, char *wwn_string,
char *filename, char *line);
static void log_error(char *msg_id, char *input_tmplt, ...);
static char ctoi(char c);
static void
log_error(char *msg_id, char *input_tmplt, ...)
{
va_list ap;
char input_merged_msg[200];
char *msg_template = "ID[luxadm.create_fabric_device.%s] %s";
char *merged_msg;
va_start(ap, input_tmplt);
(void) vsprintf(input_merged_msg, input_tmplt, ap);
va_end(ap);
merged_msg = (char *)malloc(strlen(msg_template) +
strlen(input_merged_msg) +
strlen(msg_id) + 1);
if (merged_msg == NULL) {
syslog(LOG_ERR, "ID[luxadm.create_fabric_device.2317] "
"malloc failure, %s", strerror(errno));
} else {
sprintf(merged_msg, msg_template, msg_id, input_merged_msg);
syslog(LOG_ERR, merged_msg, "");
(void) puts(merged_msg);
free(merged_msg);
}
}
#define COMMENT_CHAR '#'
int
read_repos_file(char *repos_filename)
{
int fd;
char *line;
char *tmp_ptr, *mmap_ptr;
char path[MAXPATHLEN];
int ret;
char wwn[FC_WWN_SIZE*2+1];
struct stat stbuf;
unsigned int filesize;
unsigned int bytes_read;
if (repos_filename == NULL || *repos_filename == '\0') {
log_error("2310",
"filename missing for -f option of "
"luxadm -e create_fabric_device");
return (-1);
}
fd = open(repos_filename, O_RDONLY);
if (fd == -1) {
log_error("2311",
"fopen failed: cannot open repository file %s. %d",
repos_filename, strerror(errno));
return (-1);
}
if (fstat(fd, &stbuf) == -1) {
close(fd);
log_error("2312", "stat failed on file %s. %s",
repos_filename, strerror(errno));
return (-1);
}
filesize = stbuf.st_size;
tmp_ptr = mmap_ptr = mmap((caddr_t)0, filesize,
(PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0);
if (mmap_ptr == MAP_FAILED) {
log_error("2315", "Failed to mmap file %s. %s",
repos_filename, strerror(errno));
return (-1);
}
bytes_read = 0;
while (bytes_read < filesize) {
line = tmp_ptr;
while (bytes_read < filesize && *tmp_ptr != '\n') {
bytes_read++;
tmp_ptr++;
}
if (*tmp_ptr == '\n') {
*tmp_ptr = '\0';
tmp_ptr++;
bytes_read++;
}
if (*line == COMMENT_CHAR) {
continue;
}
ret = parse_line(line, path, wwn, repos_filename);
if (ret == 0) {
ret = create_ap_instance(path,
wwn, repos_filename, line);
}
}
ret = close(fd);
ret = munmap(mmap_ptr, filesize);
return (ret);
}
#define WWN_DELIM "::"
static int
parse_line(char *line, char *path, char *wwn, char *filename)
{
char *p_path, *p_wwn, *p_delim;
char *line_copy;
line_copy = strdup(line);
if (line_copy == NULL) {
log_error("2317", "malloc failure, %s", strerror(errno));
}
p_path = line_copy;
p_delim = strstr(p_path, WWN_DELIM);
if (p_delim == NULL) {
log_error("2313",
"Invalid line (%s) in file %s.", line, filename);
free(line_copy);
return (-1);
}
*p_delim = '\0';
if (strlcpy(path, p_path, MAXPATHLEN) >= MAXPATHLEN) {
log_error("2318",
"Path too long (%s) in file %s.", p_path, filename);
free(line_copy);
return (-1);
}
p_wwn = p_delim + strlen(WWN_DELIM);
p_delim = strchr(p_wwn, ' ');
if (p_delim != NULL) {
*p_delim = '\0';
} else {
char *p_last_char;
p_last_char = p_wwn+strlen(p_wwn)-1;
if (*p_last_char == '\n') {
*p_last_char = '\0';
}
}
strcpy(wwn, p_wwn);
free(line_copy);
return (0);
}
static char
ctoi(char c)
{
if ((c >= '0') && (c <= '9'))
c -= '0';
else if ((c >= 'A') && (c <= 'F'))
c = c - 'A' + 10;
else if ((c >= 'a') && (c <= 'f'))
c = c - 'a' + 10;
else
c = -1;
return (c);
}
static int
string_to_wwn(const uchar_t *string, uchar_t *port_wwn)
{
int i;
char c, c1;
uchar_t *wwnp;
wwnp = port_wwn;
for (i = 0; i < WWN_SIZE; i++, wwnp++) {
c = ctoi(*string++);
c1 = ctoi(*string++);
if (c == -1 || c1 == -1)
return (-1);
*wwnp = ((c << 4) + c1);
}
return (0);
}
static int
create_ap_instance(char *ap_id, char *wwn_string,
char *filename, char *line)
{
devctl_hdl_t bus_handle, dev_handle;
devctl_ddef_t ddef_handle;
int ret;
uchar_t wwn_array[FC_WWN_SIZE];
ddef_handle = devctl_ddef_alloc("dummy", 0);
if (ddef_handle == NULL) {
log_error("2314",
"Internal error to process line (%s) in file: %s. %s",
line, filename, strerror(errno));
return (-1);
}
if (string_to_wwn((uchar_t *)wwn_string, wwn_array) != 0) {
log_error("2314",
"Internal error to process line (%s) in file: %s. %s",
line, filename, strerror(errno));
devctl_ddef_free(ddef_handle);
return (-1);
}
(void) devctl_ddef_byte_array(ddef_handle,
"port-wwn", FC_WWN_SIZE, wwn_array);
if ((bus_handle = devctl_bus_acquire(ap_id, 0)) == NULL) {
devctl_ddef_free(ddef_handle);
log_error("2314",
"Internal error to process line (%s) in file: %s. %s",
line, filename, strerror(errno));
return (-1);
}
if (ret =
devctl_bus_dev_create(bus_handle, ddef_handle, 0, &dev_handle)) {
devctl_ddef_free(ddef_handle);
devctl_release(bus_handle);
log_error("2316",
"configuration failed for line (%s) in file: %s. %s",
line, filename, strerror(errno));
return (-1);
}
devctl_release(dev_handle);
devctl_ddef_free(ddef_handle);
devctl_release(bus_handle);
return (ret);
}