#include <libgen.h>
#include "cfga_fp.h"
#define COPY_EXT ".cpy."
#define TMP_EXT ".tmp."
static char *HDR =
"#\n"
"# fabric_WWN_map\n"
"#\n"
"# The physical ap_id list of configured fabric devices.\n"
"# Do NOT edit this file by hand -- refer to the cfgadm_fp(8)\n"
"# man page and use cfgadm(8) instead.\n"
"#\n";
static int
search_line(char *buf, int buflen, char *srch_str, int slen,
int *write_offset, int *bytes_left)
{
int retval, sizeof_rep_hdr = strlen(HDR);
char *sol;
char *cur_pos;
*bytes_left = buflen;
*write_offset = 0;
if (buf == NULL || *buf == '\0' || buflen <= 0)
return (-2);
if (srch_str == NULL || *srch_str == '\0' || slen <= 0)
return (0);
sol = cur_pos = buf;
if (buflen >= sizeof_rep_hdr) {
sol = cur_pos = buf + sizeof_rep_hdr;
*bytes_left -= sizeof_rep_hdr;
}
while (*bytes_left >= slen) {
if ((retval = strncmp(sol, srch_str, slen)) >= 0) {
if ((retval == 0) && (*bytes_left > slen) &&
(*(sol+slen) != '\n'))
retval = 1;
*write_offset = sol - buf;
return (retval);
}
if ((cur_pos = strchr(sol, (int)'\n')) == NULL) {
*write_offset = buflen;
return (retval);
}
*cur_pos = '\0';
*bytes_left -= (strlen(sol) + 1);
*cur_pos = '\n';
sol = cur_pos = cur_pos + 1;
}
if (*bytes_left > 0) {
if ((retval = strncmp(sol, srch_str, *bytes_left)) >= 0) {
*write_offset = sol - buf;
} else {
*write_offset = buflen;
}
return (retval);
}
*write_offset = sol - buf;
return (-1);
}
int
lock_register(int fd, int cmd, int type, off_t offset, int whence, off_t len)
{
struct flock lock;
lock.l_type = type;
lock.l_start = offset;
lock.l_whence = whence;
lock.l_len = len;
return (fcntl(fd, cmd, &lock));
}
#define CLEANUP_N_RET(ret) \
if (fd != -1) { \
close(fd); \
} \
if (copy_fd != -1) { \
close(copy_fd); \
} \
if (tmp_fd != -1) { \
close(tmp_fd); \
} \
if (copy_rep != NULL) { \
remove(copy_rep); \
free(copy_rep); \
} \
if (tmp_rep != NULL) { \
remove(tmp_rep); \
free(tmp_rep); \
} \
if (upd_str != NULL) { \
free(upd_str); \
} \
if (repbuf != NULL) { \
munmap(repbuf, filesize); \
} \
if (c_repbuf != NULL) { \
munmap(c_repbuf, filesize); \
} \
if (t_repbuf != NULL) { \
munmap(t_repbuf, size); \
} \
return (ret)
int
update_fabric_wwn_list(int cmd, const char *update_str, char **errstring)
{
int fd, copy_fd, tmp_fd, new_file_flag = 0;
int len, write_offset, bytes_left;
int sizeof_rep_hdr = strlen(HDR);
char *repbuf, *c_repbuf, *t_repbuf;
char *copy_rep, *tmp_rep, *upd_str;
off_t filesize, size;
struct stat stbuf;
fd = copy_fd = tmp_fd = -1;
repbuf = c_repbuf = t_repbuf = NULL;
copy_rep = tmp_rep = upd_str = NULL;
size = filesize = write_offset = bytes_left = 0;
if ((chmod(FAB_REPOSITORY, S_IRUSR|S_IRGRP|S_IROTH) == -1) &&
(errno == ENOENT)) {
new_file_flag = 1;
mkdirp(FAB_REPOSITORY_DIR,
S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
}
if ((fd = open(FAB_REPOSITORY, O_RDWR | O_CREAT)) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
return (FPCFGA_LIB_ERR);
}
if (fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
close(fd);
cfga_err(errstring, errno, ERR_UPD_REP, 0);
return (FPCFGA_LIB_ERR);
}
if (lock_register(fd, F_SETLKW, F_WRLCK, 0, SEEK_SET, 0) < 0) {
close(fd);
cfga_err(errstring, 0, ERR_UPD_REP, 0);
return (FPCFGA_LIB_ERR);
}
if (fstat(fd, &stbuf) == -1) {
close(fd);
cfga_err(errstring, errno, ERR_UPD_REP, 0);
return (FPCFGA_LIB_ERR);
}
filesize = size = stbuf.st_size;
if (filesize && filesize < sizeof_rep_hdr) {
close(fd);
cfga_err(errstring, errno, ERR_UPD_REP, 0);
return (FPCFGA_LIB_ERR);
}
if ((len = strlen(update_str)) == 0) {
close(fd);
return (FPCFGA_OK);
}
if ((upd_str = calloc(1, len + 2)) == NULL) {
close(fd);
cfga_err(errstring, errno, ERR_UPD_REP, 0);
return (FPCFGA_LIB_ERR);
}
strcpy(upd_str, update_str);
strcat(upd_str, "\n");
len = strlen(upd_str);
if (filesize > 0) {
if ((copy_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
sizeof (COPY_EXT) + sizeof (pid_t))) == NULL) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
(void) sprintf(copy_rep, "%s%s%ld", FAB_REPOSITORY, COPY_EXT,
getpid());
if ((copy_fd = open(copy_rep, O_RDWR | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR)) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if ((repbuf = (char *)mmap(0, filesize, PROT_READ,
MAP_SHARED, fd, 0)) == MAP_FAILED) {
close(fd);
free(upd_str);
cfga_err(errstring, errno, ERR_UPD_REP, 0);
return (FPCFGA_LIB_ERR);
}
if (lseek(copy_fd, filesize - 1, SEEK_SET) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (write(copy_fd, "", 1) != 1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if ((c_repbuf = (char *)mmap(0, filesize,
PROT_READ | PROT_WRITE,
MAP_SHARED, copy_fd, 0)) == MAP_FAILED) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
memcpy(c_repbuf, repbuf, filesize);
munmap(repbuf, filesize);
repbuf = NULL;
}
if (new_file_flag != 0 || filesize == 0 || filesize == sizeof_rep_hdr) {
if ((filesize != sizeof_rep_hdr) &&
(write(fd, HDR, sizeof_rep_hdr) != sizeof_rep_hdr)) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
switch (cmd) {
case ADD_ENTRY:
if (lseek(fd, 0, SEEK_END) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (write(fd, upd_str, len) != len) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (filesize > 0) {
if (msync(c_repbuf, filesize, MS_SYNC) == -1) {
cfga_err(errstring, errno,
ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (fchmod(copy_fd,
S_IRUSR | S_IRGRP | S_IROTH) < 0) {
cfga_err(errstring, errno,
ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
rename(copy_rep, OLD_FAB_REPOSITORY);
}
CLEANUP_N_RET(FPCFGA_OK);
case REMOVE_ENTRY:
CLEANUP_N_RET(FPCFGA_OK);
default:
cfga_err(errstring, 0, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
}
switch (cmd) {
case ADD_ENTRY:
size += len;
if (search_line(c_repbuf, filesize, upd_str,
len - 1, &write_offset, &bytes_left) == 0) {
CLEANUP_N_RET(FPCFGA_OK);
}
if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
sizeof (TMP_EXT) + sizeof (pid_t))) == NULL) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
(void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
TMP_EXT, getpid());
if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
S_IRUSR | S_IWUSR)) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (write(tmp_fd, "", 1) != 1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if ((t_repbuf = (char *)mmap(0, size, PROT_READ|PROT_WRITE,
MAP_SHARED, tmp_fd, 0)) == MAP_FAILED) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
memcpy(t_repbuf, c_repbuf, write_offset);
strncpy(t_repbuf + write_offset, upd_str, len);
if (write_offset != filesize) {
memcpy(t_repbuf + write_offset + len,
c_repbuf + write_offset, bytes_left);
}
if (msync(c_repbuf, filesize, MS_SYNC) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (fchmod(copy_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (msync(t_repbuf, size, MS_SYNC) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (fchmod(tmp_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
close(copy_fd); copy_fd = -1;
close(tmp_fd); tmp_fd = -1;
rename(copy_rep, OLD_FAB_REPOSITORY);
rename(tmp_rep, FAB_REPOSITORY);
if (lock_register(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
CLEANUP_N_RET(FPCFGA_OK);
case REMOVE_ENTRY:
if (size >= sizeof_rep_hdr + len - 1) {
size -= len;
}
if (search_line(c_repbuf, filesize, upd_str, len - 1,
&write_offset, &bytes_left) != 0) {
CLEANUP_N_RET(FPCFGA_OK);
}
if ((tmp_rep = (char *)calloc(1, strlen(FAB_REPOSITORY) +
sizeof (TMP_EXT) + sizeof (pid_t))) == NULL) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
(void) sprintf(tmp_rep, "%s%s%ld", FAB_REPOSITORY,
TMP_EXT, getpid());
if ((tmp_fd = open(tmp_rep, O_RDWR|O_CREAT|O_TRUNC,
S_IRUSR | S_IWUSR)) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (size > 0) {
if (lseek(tmp_fd, size - 1, SEEK_SET) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (write(tmp_fd, "", 1) != 1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if ((t_repbuf = (char *)mmap(0, size,
PROT_READ|PROT_WRITE,
MAP_SHARED, tmp_fd, 0)) == MAP_FAILED) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
memcpy(t_repbuf, c_repbuf, write_offset);
if ((bytes_left - len) > 0) {
memcpy(t_repbuf + write_offset,
c_repbuf + write_offset + len,
bytes_left - len);
}
if (msync(t_repbuf, size, MS_SYNC) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
}
if (fchmod(tmp_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (msync(c_repbuf, filesize, MS_SYNC) == -1) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
if (fchmod(copy_fd, S_IRUSR | S_IRGRP | S_IROTH) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
close(copy_fd); copy_fd = -1;
close(tmp_fd); tmp_fd = -1;
rename(copy_rep, OLD_FAB_REPOSITORY);
rename(tmp_rep, FAB_REPOSITORY);
if (lock_register(fd, F_SETLK, F_UNLCK, 0, SEEK_SET, 0) < 0) {
cfga_err(errstring, errno, ERR_UPD_REP, 0);
CLEANUP_N_RET(FPCFGA_LIB_ERR);
}
CLEANUP_N_RET(FPCFGA_OK);
default:
break;
}
CLEANUP_N_RET(FPCFGA_OK);
}