iscsid.c revision aefdd1313598221872b3e520302b40e1874f2dc7
/*
* 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
* 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 <signal.h>
#include <locale.h>
#include <syslog.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <door.h>
#include <meta.h>
#include <libsysevent.h>
#include <wait.h>
#include <semaphore.h>
#include <libscf.h>
/*
* Local Defines
* -------------
*/
#define ISCSI_DOOR_DAEMON_SYSLOG_PP "iscsid"
#define ISCSI_SMF_OFFLINE_MAX_RETRY_TIMES 60
#if !defined(SMF_EXIT_ERR_OTHER)
#define SMF_EXIT_ERR_OTHER -1
#endif
/*
* Global Variables related to the synchronization of the child process
* --------------------------------------------------------------------
*/
static pid_t iscsi_child_pid;
static sem_t iscsi_child_sem;
static int iscsi_child_door_handle;
static int iscsi_child_smf_exit_code;
/*
* Global Variables related to the door accessed by the kernel
* -----------------------------------------------------------
*/
static int iscsi_dev_handle;
static int iscsi_kernel_door_handle;
/*
* Prototypes of Functions the body of which is defined farther down
* in this file.
* -----------------------------------------------------------------
*/
static void call_child_door(int value);
static void sigchld_handler(int sig);
static
void
void *cookie,
char *args,
);
static
void
void *cookie,
char *args,
);
static
int req_len,
);
/*
* main -- Entry point of the iSCSI door server daemon
*
* This function forks, waits for the child process feedback and exits.
*/
/* ARGSUSED */
int
main(
int argc,
char *argv[]
)
{
int i;
int sig;
int ret = -1;
int retry = 0;
/*
* Get the locale set up before calling any other routines
* with messages to ouput.
*/
/* The child semaphore is created. */
}
/* The door for the child is created. */
if (iscsi_child_door_handle == -1) {
(void) sem_destroy(&iscsi_child_sem);
}
/* A signal handler is set for SIGCHLD. */
/*
* Here begins the daemonizing code
* --------------------------------
*/
iscsi_child_pid = fork();
if (iscsi_child_pid < 0) {
/* The fork failed. */
(void) sem_destroy(&iscsi_child_sem);
}
if (iscsi_child_pid) {
/*
* The parent exits after the child has provided feedback. This
* waiting phase is to meet one of greenline's requirements.
* We shouldn't return till we are sure the service is ready to
* be provided.
*/
(void) sem_wait(&iscsi_child_sem);
(void) sem_destroy(&iscsi_child_sem);
}
/*
*/
(void) dup2(i, 1);
(void) dup2(i, 2);
/*
* Here ends the daemonizing code
* ------------------------------
*/
/*
* Block out all signals
*/
(void) sigfillset(&allsigs);
/* setup the door handle */
if (iscsi_kernel_door_handle == -1) {
}
/*
* The iSCSI driver is opened.
*/
if (iscsi_dev_handle == -1) {
/* The driver couldn't be opened. */
}
if (ioctl(
&iscsi_kernel_door_handle) == -1) {
(void) close(iscsi_dev_handle);
}
/*
* Keep the dev open, so to keep iscsi module from unloaded.
* This is crutial to guarantee the consistency of the
* door_handle and service state in kernel.
*/
/* We have to wait for the discovery process to finish. */
(void) discovery_event_wait(iscsi_dev_handle);
/* We let the parent know that everything is ok. */
/* now set up signals we care about */
(void) sigemptyset(&sigs);
/* make sure signals to be enqueued */
/* wait and process signals */
for (;;) {
if (sig < 0)
continue;
switch (sig) {
case SIGQUIT:
case SIGINT:
case SIGTERM:
do {
if (ret == -1) {
" iscsi initiator"));
/*
* Keep retrying if unable
* to stop
*/
(void) sleep(ISCSI_SMF_OFFLINE_DELAY);
retry++;
}
} while (ret == -1 &&
(void) close(iscsi_dev_handle);
return (0);
break;
default:
break;
}
}
}
/*
* sigchld_handler -- SIGCHLD Handler
*
*/
/* ARGSUSED */
static
void
int sig
)
{
int status;
/* This is the default code. */
if (ret_pid == iscsi_child_pid) {
}
}
(void) sem_post(&iscsi_child_sem);
}
/*
* iscsi_child_door -- Child process door entry point
*
* This function is executed when a driver calls door_ki_upcall().
*/
/* ARGSUSED */
static
void
void *cookie,
char *args,
)
{
if (alen >= sizeof (iscsi_child_smf_exit_code)) {
}
(void) sem_post(&iscsi_child_sem);
}
/*
* iscsi_kernel_door -- Kernel door entry point
*
* This function is executed when a driver calls door_ki_upcall().
*/
/* ARGSUSED */
static
void
void *cookie,
char *args,
)
{
char *err_txt;
int err_code;
/* Local variables pre-initialization */
/*
* The validity of the request is checked before going any farther.
*/
/*
* A request has to be passed.
*/
} else if (alen < sizeof (iscsi_door_msg_hdr_t)) {
/*
* The buffer containing the request must be at least as big
* as message header.
*/
/*
* The request must be correctly signed.
*/
/*
* The version of the request must be supported by the server.
*/
} else {
/*
* The request is treated according to the opcode.
*/
alen,
&cnf_len);
break;
default:
break;
}
}
switch (err_code) {
case E2BIG:
err_txt = "E2BIG";
break;
case EFAULT:
err_txt = "EFAULT";
break;
case EINVAL:
err_txt = "EINVAL";
break;
case EMFILE:
err_txt = "EMFILE";
break;
default:
err_txt = "?";
break;
}
gettext("!door_return error(%s,%d)"),
err_code);
}
/*
* _getipnodebyname_req
*
* This function executes the request ISCSI_DOOR_GETIPNODEBYNAME_REQ. It
* calls getipnodebyname() but doesn't return all the information. The
* confirmation structure only contains one IP address of the list returned
* by getipnodebyname().
*/
static
int req_len,
) {
char *name;
/* The opcode is changed immediately. */
/* The size of the request is checked against the minimum required. */
if (req_len < sizeof (getipnodebyname_cnf_t)) {
return ((iscsi_door_cnf_t *)cnf);
}
/*
* The pointer to the name has to stay inside the request but
* after the header.
*/
return ((iscsi_door_cnf_t *)cnf);
}
/* The library function is called. */
name,
if (hptr) {
/*
* The call was successful. Now starts the painful work of
* parsing the data. However, for version 1 we will only
* return the first address.
*/
cnf_len = sizeof (getipnodebyname_cnf_t);
cnf->h_alias_list_length = 0;
cnf->h_alias_list_offset = 0;
cnf->h_name_len = 0;
cnf->h_name_offset = 0;
(void) memcpy(
((char *)cnf + sizeof (getipnodebyname_cnf_t)),
*hptr->h_addr_list,
} else {
cnf->h_addr_list_length = 0;
}
} else {
cnf->h_addrtype = 0;
cnf->h_addr_list_length = 0;
cnf->h_name_len = 0;
cnf->h_alias_list_length = 0;
*pcnf_len = sizeof (getipnodebyname_cnf_t);
}
return ((iscsi_door_cnf_t *)cnf);
}
/*
* call_child_door -- This function calls the child door with the value
* provided by the caller.
*
*/
static
void
int value
)
{
}
/*
* get_luns_count --
*/
static
int did
)
{
for (;;) {
if (ioctl(
did,
lun_list) == -1) {
/* The Ioctl didn't go well. */
return (0);
}
/* We got it all. */
break;
}
/*
* We didn't get all the targets. Let's build a new Ioctl with
* a new size.
*/
/* No resources. */
return (0);
}
}
return (lun_count);
}
/*
* discovery_event_wait -- Waits for the discovery process to finish.
*
*/
static
int did
)
{
lun_count = 0;
lun_timer = 0;
discovery_flags = 0;
for (;;) {
/* The status discovery flags are read. */
if (ioctl(
did,
&discovery_flags) == -1) {
/* IO problem */
break;
}
if (discovery_flags == discovery_all) {
/* Discovery over */
break;
}
if (lun_timer >= ISCSI_DISCOVERY_POLL_DELAY2) {
/* Let's check if the driver is making progress. */
/* No progress */
break;
}
lun_timer = 0;
}
(void) sleep(ISCSI_DISCOVERY_POLL_DELAY1);
}
return (rc);
}
/*ARGSUSED*/
static void
{
}