|
Packit Service |
646995 |
/*
|
|
Packit Service |
646995 |
* iscsid communication helpers
|
|
Packit Service |
646995 |
*
|
|
Packit Service |
646995 |
* Copyright (C) 2004 Dmitry Yusupov, Alex Aizman
|
|
Packit Service |
646995 |
* Copyright (C) 2006 - 2010 Mike Christie
|
|
Packit Service |
646995 |
* Copyright (C) 2006 - 2010 Red Hat, Inc. All rights reserved.
|
|
Packit Service |
646995 |
* maintained by open-iscsi@googlegroups.com
|
|
Packit Service |
646995 |
*
|
|
Packit Service |
646995 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
646995 |
* it under the terms of the GNU General Public License as published
|
|
Packit Service |
646995 |
* by the Free Software Foundation; either version 2 of the License, or
|
|
Packit Service |
646995 |
* (at your option) any later version.
|
|
Packit Service |
646995 |
*
|
|
Packit Service |
646995 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit Service |
646995 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
646995 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
646995 |
* General Public License for more details.
|
|
Packit Service |
646995 |
*
|
|
Packit Service |
646995 |
* See the file COPYING included with this distribution for more details.
|
|
Packit Service |
646995 |
*/
|
|
Packit Service |
646995 |
#include <stdio.h>
|
|
Packit Service |
646995 |
#include <unistd.h>
|
|
Packit Service |
646995 |
#include <stdlib.h>
|
|
Packit Service |
646995 |
#include <string.h>
|
|
Packit Service |
646995 |
#include <errno.h>
|
|
Packit Service |
646995 |
#include <fcntl.h>
|
|
Packit Service |
646995 |
#include <sys/un.h>
|
|
Packit Service |
646995 |
#include <poll.h>
|
|
Packit Service |
646995 |
#include <sys/types.h>
|
|
Packit Service |
646995 |
#include <sys/socket.h>
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
#include "initiator.h"
|
|
Packit Service |
646995 |
#include "log.h"
|
|
Packit Service |
646995 |
#include "mgmt_ipc.h"
|
|
Packit Service |
646995 |
#include "iscsi_util.h"
|
|
Packit Service |
646995 |
#include "config.h"
|
|
Packit Service |
646995 |
#include "iscsi_err.h"
|
|
Packit Service |
646995 |
#include "iscsid_req.h"
|
|
Packit Service |
646995 |
#include "uip_mgmt_ipc.h"
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
static void iscsid_startup(void)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
char *startup_cmd;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
startup_cmd = cfg_get_string_param(CONFIG_FILE, "iscsid.startup");
|
|
Packit Service |
646995 |
if (!startup_cmd) {
|
|
Packit Service |
646995 |
log_error("iscsid is not running. Could not start it up "
|
|
Packit Service |
646995 |
"automatically using the startup command in the "
|
|
Packit Service |
646995 |
"/etc/iscsi/iscsid.conf iscsid.startup setting. "
|
|
Packit Service |
646995 |
"Please check that the file exists or that your "
|
|
Packit Service |
646995 |
"init scripts have started iscsid.");
|
|
Packit Service |
646995 |
return;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
if (system(startup_cmd) < 0)
|
|
Packit Service |
646995 |
log_error("Could not execute '%s' (err %d)",
|
|
Packit Service |
646995 |
startup_cmd, errno);
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
free(startup_cmd);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
#define MAXSLEEP 128
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
static int ipc_connect(int *fd, char *unix_sock_name, int start_iscsid)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
int nsec, addr_len;
|
|
Packit Service |
646995 |
struct sockaddr_un addr;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
*fd = socket(AF_LOCAL, SOCK_STREAM, 0);
|
|
Packit Service |
646995 |
if (*fd < 0) {
|
|
Packit Service |
646995 |
log_error("can not create IPC socket (%d)!", errno);
|
|
Packit Service |
646995 |
return ISCSI_ERR_ISCSID_NOTCONN;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
addr_len = setup_abstract_addr(&addr, unix_sock_name);
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
/*
|
|
Packit Service |
646995 |
* Trying to connect with exponential backoff
|
|
Packit Service |
646995 |
*/
|
|
Packit Service |
646995 |
for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) {
|
|
Packit Service |
646995 |
if (connect(*fd, (struct sockaddr *) &addr, addr_len) == 0)
|
|
Packit Service |
646995 |
/* Connection established */
|
|
Packit Service |
646995 |
return ISCSI_SUCCESS;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
/* If iscsid isn't there, there's no sense
|
|
Packit Service |
646995 |
* in retrying. */
|
|
Packit Service |
646995 |
if (errno == ECONNREFUSED) {
|
|
Packit Service |
646995 |
if (start_iscsid && nsec == 1)
|
|
Packit Service |
646995 |
iscsid_startup();
|
|
Packit Service |
646995 |
else
|
|
Packit Service |
646995 |
break;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
/*
|
|
Packit Service |
646995 |
* Delay before trying again
|
|
Packit Service |
646995 |
*/
|
|
Packit Service |
646995 |
if (nsec <= MAXSLEEP/2)
|
|
Packit Service |
646995 |
sleep(nsec);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
close(*fd);
|
|
Packit Service |
646995 |
*fd = -1;
|
|
Packit Service |
646995 |
log_error("can not connect to iSCSI daemon (%d)!", errno);
|
|
Packit Service |
646995 |
return ISCSI_ERR_ISCSID_NOTCONN;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
char iscsid_namespace[64] = ISCSIADM_NAMESPACE;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
void iscsid_set_namespace(pid_t pid) {
|
|
Packit Service |
646995 |
if (pid) {
|
|
Packit Service |
646995 |
snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE "-%d", pid);
|
|
Packit Service |
646995 |
} else {
|
|
Packit Service |
646995 |
snprintf(iscsid_namespace, 64, ISCSIADM_NAMESPACE);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
static int iscsid_connect(int *fd, int start_iscsid)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
return ipc_connect(fd, iscsid_namespace, start_iscsid);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_request(int *fd, iscsiadm_req_t *req, int start_iscsid)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
int err;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
err = iscsid_connect(fd, start_iscsid);
|
|
Packit Service |
646995 |
if (err)
|
|
Packit Service |
646995 |
return err;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
if ((err = write(*fd, req, sizeof(*req))) != sizeof(*req)) {
|
|
Packit Service |
646995 |
log_error("got write error (%d/%d) on cmd %d, daemon died?",
|
|
Packit Service |
646995 |
err, errno, req->command);
|
|
Packit Service |
646995 |
close(*fd);
|
|
Packit Service |
646995 |
return ISCSI_ERR_ISCSID_COMM_ERR;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
return ISCSI_SUCCESS;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_response(int fd, iscsiadm_cmd_e cmd, iscsiadm_rsp_t *rsp,
|
|
Packit Service |
646995 |
int timeout)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
size_t len = sizeof(*rsp);
|
|
Packit Service |
646995 |
int iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
|
|
Packit Service |
646995 |
int err;
|
|
Packit Service |
646995 |
int poll_wait = 0;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
if (timeout == -1) {
|
|
Packit Service |
646995 |
timeout = ISCSID_REQ_TIMEOUT;
|
|
Packit Service |
646995 |
poll_wait = 1;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
while (len) {
|
|
Packit Service |
646995 |
struct pollfd pfd;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
pfd.fd = fd;
|
|
Packit Service |
646995 |
pfd.events = POLLIN;
|
|
Packit Service |
646995 |
err = poll(&pfd, 1, timeout);
|
|
Packit Service |
646995 |
if (!err) {
|
|
Packit Service |
646995 |
if (poll_wait)
|
|
Packit Service |
646995 |
continue;
|
|
Packit Service |
646995 |
return ISCSI_ERR_ISCSID_NOTCONN;
|
|
Packit Service |
646995 |
} else if (err < 0) {
|
|
Packit Service |
646995 |
if (errno == EINTR)
|
|
Packit Service |
646995 |
continue;
|
|
Packit Service |
646995 |
log_error("got poll error (%d/%d), daemon died?",
|
|
Packit Service |
646995 |
err, errno);
|
|
Packit Service |
646995 |
return ISCSI_ERR_ISCSID_COMM_ERR;
|
|
Packit Service |
646995 |
} else if (pfd.revents & POLLIN) {
|
|
Packit Service |
646995 |
err = recv(fd, rsp, sizeof(*rsp), MSG_WAITALL);
|
|
Packit Service |
646995 |
if (err < 0) {
|
|
Packit Service |
646995 |
log_error("read error (%d/%d), daemon died?",
|
|
Packit Service |
646995 |
err, errno);
|
|
Packit Service |
646995 |
break;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
len -= err;
|
|
Packit Service |
646995 |
iscsi_err = rsp->err;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
close(fd);
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
if (!iscsi_err && cmd != rsp->command)
|
|
Packit Service |
646995 |
iscsi_err = ISCSI_ERR_ISCSID_COMM_ERR;
|
|
Packit Service |
646995 |
return iscsi_err;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_exec_req(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp,
|
|
Packit Service |
646995 |
int start_iscsid, int tmo)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
int fd;
|
|
Packit Service |
646995 |
int err;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
err = iscsid_request(&fd, req, start_iscsid);
|
|
Packit Service |
646995 |
if (err)
|
|
Packit Service |
646995 |
return err;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
return iscsid_response(fd, req->command, rsp, tmo);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
iscsiadm_rsp_t rsp;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
memset(&rsp, 0, sizeof(iscsiadm_rsp_t));
|
|
Packit Service |
646995 |
return iscsid_response(fd, cmd, &rsp, -1);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
iscsiadm_req_t req;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
memset(&req, 0, sizeof(iscsiadm_req_t));
|
|
Packit Service |
646995 |
req.command = cmd;
|
|
Packit Service |
646995 |
memcpy(&req.u.session.rec, rec, sizeof(node_rec_t));
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
return iscsid_request(fd, &req, 1);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_req_by_rec(iscsiadm_cmd_e cmd, node_rec_t *rec)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
int err, fd;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
err = iscsid_req_by_rec_async(cmd, rec, &fd;;
|
|
Packit Service |
646995 |
if (err)
|
|
Packit Service |
646995 |
return err;
|
|
Packit Service |
646995 |
return iscsid_req_wait(cmd, fd);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_req_by_sid_async(iscsiadm_cmd_e cmd, int sid, int *fd)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
iscsiadm_req_t req;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
memset(&req, 0, sizeof(iscsiadm_req_t));
|
|
Packit Service |
646995 |
req.command = cmd;
|
|
Packit Service |
646995 |
req.u.session.sid = sid;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
return iscsid_request(fd, &req, 1);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
int err, fd;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
err = iscsid_req_by_sid_async(cmd, sid, &fd;;
|
|
Packit Service |
646995 |
if (err)
|
|
Packit Service |
646995 |
return err;
|
|
Packit Service |
646995 |
return iscsid_req_wait(cmd, fd);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
static int uip_connect(int *fd)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
return ipc_connect(fd, ISCSID_UIP_NAMESPACE, 0);
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
int uip_broadcast(void *buf, size_t buf_len, int fd_flags, uint32_t *status)
|
|
Packit Service |
646995 |
{
|
|
Packit Service |
646995 |
int err;
|
|
Packit Service |
646995 |
int fd;
|
|
Packit Service |
646995 |
iscsid_uip_rsp_t rsp;
|
|
Packit Service |
646995 |
int flags;
|
|
Packit Service |
646995 |
int count;
|
|
Packit Service |
646995 |
size_t write_res;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
err = uip_connect(&fd;;
|
|
Packit Service |
646995 |
if (err) {
|
|
Packit Service |
646995 |
log_warning("uIP daemon is not up");
|
|
Packit Service |
646995 |
return err;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
log_debug(3, "connected to uIP daemon");
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
/* Send the data to uIP */
|
|
Packit Service |
646995 |
write_res = write(fd, buf, buf_len);
|
|
Packit Service |
646995 |
if (write_res != buf_len) {
|
|
Packit Service |
646995 |
log_error("got write error (%d/%d), daemon died?",
|
|
Packit Service |
646995 |
(int)write_res, errno);
|
|
Packit Service |
646995 |
close(fd);
|
|
Packit Service |
646995 |
return ISCSI_ERR_ISCSID_COMM_ERR;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
log_debug(3, "send iface config to uIP daemon");
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
/* Set the socket to a non-blocking read, this way if there are
|
|
Packit Service |
646995 |
* problems waiting for uIP, iscsid can bailout early */
|
|
Packit Service |
646995 |
flags = fcntl(fd, F_GETFL, 0);
|
|
Packit Service |
646995 |
if (flags == -1)
|
|
Packit Service |
646995 |
flags = 0;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
if (fd_flags)
|
|
Packit Service |
646995 |
flags |= fd_flags;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
err = fcntl(fd, F_SETFL, flags);
|
|
Packit Service |
646995 |
if (err) {
|
|
Packit Service |
646995 |
log_error("could not set uip broadcast to non-blocking: %d",
|
|
Packit Service |
646995 |
errno);
|
|
Packit Service |
646995 |
close(fd);
|
|
Packit Service |
646995 |
return ISCSI_ERR;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
#define MAX_UIP_BROADCAST_READ_TRIES 5
|
|
Packit Service |
646995 |
for (count = 0; count < MAX_UIP_BROADCAST_READ_TRIES; count++) {
|
|
Packit Service |
646995 |
/* Wait for the response */
|
|
Packit Service |
646995 |
err = read(fd, &rsp, sizeof(rsp));
|
|
Packit Service |
646995 |
if (err == sizeof(rsp)) {
|
|
Packit Service |
646995 |
log_debug(3, "Broadcasted to uIP with length: %zu cmd: 0x%x rsp: 0x%x",
|
|
Packit Service |
646995 |
buf_len, rsp.command, rsp.err);
|
|
Packit Service |
646995 |
err = 0;
|
|
Packit Service |
646995 |
break;
|
|
Packit Service |
646995 |
} else if ((err == -1) && (errno == EAGAIN)) {
|
|
Packit Service |
646995 |
usleep(1000000);
|
|
Packit Service |
646995 |
continue;
|
|
Packit Service |
646995 |
} else {
|
|
Packit Service |
646995 |
log_error("Could not read response (%d/%d), daemon "
|
|
Packit Service |
646995 |
"died?", err, errno);
|
|
Packit Service |
646995 |
err = ISCSI_ERR;
|
|
Packit Service |
646995 |
break;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
if (count == MAX_UIP_BROADCAST_READ_TRIES) {
|
|
Packit Service |
646995 |
log_error("Could not broadcast to uIP after %d tries",
|
|
Packit Service |
646995 |
count);
|
|
Packit Service |
646995 |
err = ISCSI_ERR_AGAIN;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
if (err)
|
|
Packit Service |
646995 |
goto done;
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
switch (rsp.command) {
|
|
Packit Service |
646995 |
case ISCSID_UIP_IPC_GET_IFACE:
|
|
Packit Service |
646995 |
if (rsp.err != ISCSID_UIP_MGMT_IPC_DEVICE_UP) {
|
|
Packit Service |
646995 |
log_debug(3, "Device is not ready\n");
|
|
Packit Service |
646995 |
err = ISCSI_ERR_AGAIN;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
break;
|
|
Packit Service |
646995 |
case ISCSID_UIP_IPC_PING:
|
|
Packit Service |
646995 |
*status = rsp.ping_sc;
|
|
Packit Service |
646995 |
if (rsp.err == ISCSID_UIP_MGMT_IPC_DEVICE_INITIALIZING) {
|
|
Packit Service |
646995 |
log_debug(3, "Device is not ready\n");
|
|
Packit Service |
646995 |
err = ISCSI_ERR_AGAIN;
|
|
Packit Service |
646995 |
} else if (*status) {
|
|
Packit Service |
646995 |
err = ISCSI_ERR;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
break;
|
|
Packit Service |
646995 |
default:
|
|
Packit Service |
646995 |
err = ISCSI_ERR;
|
|
Packit Service |
646995 |
}
|
|
Packit Service |
646995 |
|
|
Packit Service |
646995 |
done:
|
|
Packit Service |
646995 |
close(fd);
|
|
Packit Service |
646995 |
return err;
|
|
Packit Service |
646995 |
}
|