Home | History | Annotate | Download | only in iscsitgtd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 
     28 #define	FD_SETSIZE	65536
     29 #include <sys/types.h>
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <strings.h>
     33 #include <time.h>
     34 #include <unistd.h>
     35 #include <pthread.h>
     36 #include <sys/conf.h>
     37 #include <sys/socket.h>
     38 #include <netinet/in.h>
     39 #include <arpa/inet.h>
     40 #include <stdint.h>
     41 #include <dirent.h>
     42 #include <sys/stat.h>
     43 #include <fcntl.h>
     44 #include <assert.h>
     45 #include <errno.h>
     46 #include <door.h>
     47 #include <signal.h>
     48 #include <siginfo.h>
     49 #include <sys/ethernet.h>
     50 #include <libscf.h>
     51 #include <syslog.h>
     52 #include <synch.h>
     53 #include <libxml/xmlreader.h>
     54 #include <sys/resource.h>
     55 #include <syslog.h>
     56 #include <sys/select.h>
     57 #include <iscsitgt_impl.h>
     58 #include <umem.h>
     59 
     60 #include "queue.h"
     61 #include "port.h"
     62 #include "iscsi_conn.h"
     63 #include "target.h"
     64 #include "utility.h"
     65 #include "iscsi_ffp.h"
     66 #include "errcode.h"
     67 #include "t10.h"
     68 #include "mgmt_scf.h"
     69 
     70 #include "isns_client.h"
     71 
     72 #define	EMPTY_CONFIG "<config version='1.0'>\n</config>\n"
     73 
     74 /* ---- Forward declarations ---- */
     75 static void variable_handler(tgt_node_t *, target_queue_t *, target_queue_t *,
     76     ucred_t *);
     77 
     78 
     79 /* ---- Global configuration data. ---- */
     80 char		*target_basedir		= NULL;
     81 char		*target_log		= DEFAULT_TARGET_LOG;
     82 char		*config_file		= DEFAULT_CONFIG_LOCATION;
     83 char		*pgr_basedir		= NULL;
     84 int		iscsi_port		= 3260, /* defined by the spec */
     85 		dbg_lvl			= 0,
     86 		door_min_space;
     87 tgt_node_t	*main_config,
     88 		*targets_config;
     89 Boolean_t	enforce_strict_guid	= True,
     90 		thin_provisioning	= False,
     91 		disable_tpgs		= False,
     92 		dbg_timestamps		= False,
     93 		pgr_persist		= True;
     94 int		targets_vers_maj,
     95 		targets_vers_min,
     96 		main_vers_maj,
     97 		main_vers_min;
     98 pthread_rwlock_t	targ_config_mutex;
     99 umem_cache_t	*iscsi_cmd_cache,
    100 		*t10_cmd_cache,
    101 		*queue_cache;
    102 
    103 typedef struct var_table {
    104 	char	*v_name;
    105 	int	*v_value;
    106 } var_table_t;
    107 
    108 typedef struct cmd_table {
    109 	char	*c_name;
    110 	void	(*c_func)(tgt_node_t *, target_queue_t *, target_queue_t *,
    111 		ucred_t *);
    112 } cmd_table_t;
    113 
    114 admin_table_t admin_prop_list[] = {
    115 	{XML_ELEMENT_BASEDIR,		update_basedir,	NULL},
    116 	{XML_ELEMENT_CHAPSECRET,	0,	NULL},
    117 	{XML_ELEMENT_CHAPNAME,		0,	NULL},
    118 	{XML_ELEMENT_RAD_ACCESS,	0,	NULL},
    119 	{XML_ELEMENT_RAD_SERV,		valid_radius_srv, NULL},
    120 	{XML_ELEMENT_RAD_SECRET,	0,	NULL},
    121 	{XML_ELEMENT_ISNS_ACCESS,	0,	NULL},
    122 	{XML_ELEMENT_ISNS_SERV,		valid_isns_srv,	NULL},
    123 	{XML_ELEMENT_FAST,		0,	NULL},
    124 	{XML_ELEMENT_DELETE_CHAPSECRET,	0,	XML_ELEMENT_CHAPSECRET},
    125 	{XML_ELEMENT_DELETE_CHAPNAME,	0,	XML_ELEMENT_CHAPNAME},
    126 	{XML_ELEMENT_DELETE_RAD_SECRET,	0,	XML_ELEMENT_RAD_SECRET},
    127 	{XML_ELEMENT_DELETE_RAD_SERV,	0,	XML_ELEMENT_RAD_SERV},
    128 	{0,				0}
    129 };
    130 
    131 /*
    132  * Global variables which can be set via the management XML interface
    133  * with the syntax of "<variable><dbg_lvl>0x033</dbg_lvl></variable>"
    134  */
    135 var_table_t var_table[] = {
    136 	{ "dbg_lvl", &dbg_lvl },
    137 	{ "qlog_lvl", &qlog_lvl },
    138 	/* ---- End of Table marker ---- */
    139 	{ NULL, 0 }
    140 };
    141 
    142 /*
    143  * Commands which are run via the management XML interface
    144  */
    145 cmd_table_t cmd_table[] = {
    146 	{ "variable",	variable_handler },
    147 	{ "create",	create_func },
    148 	{ "modify",	modify_func },
    149 	{ "delete",	remove_func },
    150 	{ "list",	list_func },
    151 	/* ---- End of Table marker ---- */
    152 	{ NULL,		NULL }
    153 };
    154 
    155 /*
    156  * []----
    157  * | process_config -- parse the main configuration file
    158  * |
    159  * | Everything in the configuratin file is optional. That's because
    160  * | the management CLI can set the value to everything and update
    161  * | the configuration.
    162  * []----
    163  */
    164 static Boolean_t
    165 process_config()
    166 {
    167 	tgt_node_t		*node = NULL;
    168 
    169 #ifndef lint
    170 	LIBXML_TEST_VERSION;
    171 #endif
    172 
    173 	if (mgmt_get_main_config(&node) == False) {
    174 		return (False);
    175 	}
    176 
    177 	main_vers_maj = XML_VERS_MAIN_MAJ;
    178 	main_vers_min = XML_VERS_MAIN_MIN;
    179 	if (validate_version(node, &main_vers_maj, &main_vers_min) ==
    180 	    False) {
    181 		syslog(LOG_ERR, "Target main config invalid");
    182 		return (False);
    183 	}
    184 
    185 	/*
    186 	 * The base directory is optional in the sense that the daemon
    187 	 * can start without it, but the daemon can't really do
    188 	 * anything until the administrator sets the value.
    189 	 */
    190 	(void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR,
    191 	    &target_basedir);
    192 
    193 	/*
    194 	 * These are optional settings for the target. Each of
    195 	 * these has a default value which can be overwritten in
    196 	 * the configuration.
    197 	 */
    198 	(void) tgt_find_value_str(node, XML_ELEMENT_TARGLOG,
    199 	    &target_log);
    200 	(void) tgt_find_value_int(node, XML_ELEMENT_ISCSIPORT,
    201 	    &iscsi_port);
    202 	(void) tgt_find_value_intchk(node, XML_ELEMENT_DBGLVL, &dbg_lvl);
    203 	(void) tgt_find_value_boolean(node, XML_ELEMENT_ENFORCE,
    204 	    &enforce_strict_guid);
    205 	(void) tgt_find_value_boolean(node, XML_ELEMENT_THIN_PROVO,
    206 	    &thin_provisioning);
    207 	(void) tgt_find_value_boolean(node, XML_ELEMENT_DISABLE_TPGS,
    208 	    &disable_tpgs);
    209 	(void) tgt_find_value_boolean(node, XML_ELEMENT_TIMESTAMPS,
    210 	    &dbg_timestamps);
    211 	(void) tgt_find_value_boolean(node, XML_ELEMENT_PGR_PERSIST,
    212 	    &pgr_persist);
    213 	(void) tgt_find_value_str(node, XML_ELEMENT_PGR_BASEDIR,
    214 	    &pgr_basedir);
    215 	if (tgt_find_value_intchk(node, XML_ELEMENT_LOGLVL,
    216 	    &qlog_lvl) == True)
    217 		queue_log(True);
    218 
    219 	main_config = node;
    220 	targets_config = node;
    221 
    222 	return (True);
    223 }
    224 
    225 /*
    226  * []----
    227  * | logout_cleanup -- see if the initiator did what was requested
    228  * |
    229  * | When a target issues an asynchrouns event with the code set to
    230  * | "logout requested" the initiator is supposed to respond with
    231  * | a LogoutRequested PDU within a certain amount of time. If it
    232  * | fails to do so, it's the targets responsibility to clean up.
    233  * | We will check logout status in a 1 second interval, if the
    234  * | initiators responded to the logout request then logout is
    235  * | conpleted, if ASYNC_LOGOUT_TIMEOUT seconds (currently 10)
    236  * | is reached then we will reissue the management request to
    237  * | to logout which will cause the connections to close.
    238  * []----
    239  */
    240 static void *
    241 logout_cleanup(void *v)
    242 {
    243 	int		msg_sent, i;
    244 	char		*targ = (char *)v;
    245 	mgmt_request_t	m;
    246 	iscsi_conn_t	*conn;
    247 	extern pthread_mutex_t port_mutex;
    248 	Boolean_t	logout = False;
    249 
    250 	bzero(&m, sizeof (m));
    251 	m.m_request	= mgmt_logout;
    252 	m.m_q		= queue_alloc();
    253 	msg_sent	= 0;
    254 
    255 	/*
    256 	 * The for loop is to manage the wait time for the
    257 	 * logout request to complete, if logout completed
    258 	 * before ASYNC_LOGOUT_TIMEOUT then done
    259 	 */
    260 	for (i = 0; i < ASYNC_LOGOUT_TIMEOUT; i++) {
    261 		logout = True;
    262 		(void) pthread_mutex_lock(&port_mutex);
    263 		for (conn = conn_head; conn; conn = conn->c_next) {
    264 			if ((conn->c_state == S7_LOGOUT_REQUESTED) &&
    265 			    (strcmp(conn->c_sess->s_t_name, targ) == 0)) {
    266 				logout = False;
    267 				break;
    268 			}
    269 		}
    270 		(void) pthread_mutex_unlock(&port_mutex);
    271 		if (logout)
    272 			break;
    273 		else
    274 			(void) sleep(1);
    275 	}
    276 
    277 	/*
    278 	 * Logout did not complete, queue message to shutdown
    279 	 * connection.
    280 	 */
    281 	if (logout == False) {
    282 		(void) pthread_mutex_lock(&port_mutex);
    283 		for (conn = conn_head; conn; conn = conn->c_next) {
    284 			if ((conn->c_state == S7_LOGOUT_REQUESTED) &&
    285 			    (strcmp(conn->c_sess->s_t_name, targ) == 0)) {
    286 				queue_message_set(conn->c_dataq, 0,
    287 				    msg_mgmt_rqst, &m);
    288 				msg_sent++;
    289 			}
    290 		}
    291 		(void) pthread_mutex_unlock(&port_mutex);
    292 	}
    293 
    294 	/*
    295 	 * Wait to see if they received the message.
    296 	 */
    297 	for (i = 0; i < msg_sent; i++)
    298 		queue_message_free(queue_message_get(m.m_q));
    299 	queue_free(m.m_q, NULL);
    300 	free(targ);
    301 
    302 	queue_message_set(mgmtq, 0, msg_pthread_join,
    303 	    (void *)(uintptr_t)pthread_self());
    304 	return ((void *)0);
    305 }
    306 
    307 void
    308 logout_targ(char *targ)
    309 {
    310 	mgmt_request_t	m;
    311 	iscsi_conn_t	*conn;
    312 	int		i, msg_sent;
    313 	pthread_t	junk;
    314 	extern pthread_mutex_t	port_mutex;
    315 
    316 	/*
    317 	 * Now we look for connections to this target and issue
    318 	 * a request to asynchronously logout.
    319 	 */
    320 	bzero(&m, sizeof (m));
    321 	m.m_request	= mgmt_logout;
    322 	m.m_q		= queue_alloc();
    323 	msg_sent	= 0;
    324 
    325 	(void) pthread_mutex_lock(&port_mutex);
    326 	for (conn = conn_head; conn; conn = conn->c_next) {
    327 		if (conn->c_state != S5_LOGGED_IN)
    328 			continue;
    329 		if (conn->c_sess->s_type == SessionDiscovery)
    330 			continue;
    331 
    332 		if (strcmp(conn->c_sess->s_t_name, targ) == 0) {
    333 			queue_message_set(conn->c_dataq, 0, msg_mgmt_rqst, &m);
    334 			msg_sent++;
    335 		}
    336 	}
    337 	(void) pthread_mutex_unlock(&port_mutex);
    338 
    339 	/* ---- Wait to see if they received the message. ---- */
    340 	for (i = 0; i < msg_sent; i++)
    341 		queue_message_free(queue_message_get(m.m_q));
    342 
    343 	queue_free(m.m_q, NULL);
    344 
    345 	/* ---- Start housecleaning thread ---- */
    346 	(void) pthread_create(&junk, NULL, logout_cleanup,
    347 	    (void *)strdup(targ));
    348 }
    349 
    350 /*
    351  * [] ---- XML Management Handlers ---- []
    352  */
    353 
    354 /*
    355  * []----
    356  * | variable_handler -- used to set a couple of internal global variables
    357  * []----
    358  */
    359 /*ARGSUSED*/
    360 void
    361 variable_handler(tgt_node_t *x, target_queue_t *reply, target_queue_t *mgmt,
    362     ucred_t *cred)
    363 {
    364 	char			*reply_buf	= NULL;
    365 	var_table_t		*v;
    366 	tgt_node_t		*c;
    367 
    368 	if (check_auth_modify(cred) != True) {
    369 		xml_rtn_msg(&reply_buf, ERR_NO_PERMISSION);
    370 		queue_str(reply, 0, msg_mgmt_rply, reply_buf);
    371 		return;
    372 	}
    373 	for (c = x->x_child; c; c = c->x_sibling) {
    374 
    375 		for (v = var_table; v->v_name; v++) {
    376 			if (strcmp(c->x_name, v->v_name) == 0) {
    377 				*v->v_value = strtol(c->x_value, NULL, 0);
    378 				if (strcmp(v->v_name, "qlog_lvl") == 0)
    379 					queue_log(True);
    380 				xml_rtn_msg(&reply_buf, ERR_SUCCESS);
    381 				break;
    382 			}
    383 		}
    384 		if (v->v_name == NULL)
    385 			xml_rtn_msg(&reply_buf, ERR_NO_MATCH);
    386 
    387 		queue_str(reply, 0, msg_mgmt_rply, reply_buf);
    388 	}
    389 }
    390 
    391 /*
    392  * []----
    393  * | parse_xml -- incoming management requests are sent here for processing
    394  * []----
    395  */
    396 static void
    397 parse_xml(tgt_node_t *x, target_queue_t *reply, target_queue_t *mgmt,
    398     ucred_t *cred)
    399 {
    400 	char		*reply_msg	= NULL;
    401 	cmd_table_t	*c;
    402 
    403 	if ((x->x_name == NULL) || (x->x_state == NodeFree)) {
    404 		xml_rtn_msg(&reply_msg, ERR_SYNTAX_EMPTY);
    405 		queue_message_set(reply, 0, msg_mgmt_rply, reply_msg);
    406 		return;
    407 	}
    408 
    409 	for (c = cmd_table; c->c_name != NULL; c++)
    410 		if (strcmp(c->c_name, x->x_name) == 0)
    411 			break;
    412 	if (c->c_name == NULL) {
    413 		xml_rtn_msg(&reply_msg, ERR_INVALID_COMMAND);
    414 		queue_message_set(reply, 0, msg_mgmt_rply, reply_msg);
    415 	} else {
    416 		(c->c_func)(x, reply, mgmt, cred);
    417 	}
    418 }
    419 
    420 /*
    421  * space_message -- create a message indicating the amount of space needed.
    422  *
    423  * This code could have been inline in the server_for_door function, but
    424  * at system startup we'll determine the minimum amount of space needed for
    425  * a door call return pointer. This minimum amount of space will be either
    426  * a "need more space" or a "success" message. So, have this code as a function
    427  * reduces any duplication.
    428  */
    429 static void
    430 space_message(char **buf, int size)
    431 {
    432 	char	lbuf[16];
    433 	tgt_buf_add_tag_and_attr(buf, XML_ELEMENT_ERROR, "version='1.0'");
    434 	(void) snprintf(lbuf, sizeof (lbuf), "%d", size);
    435 	tgt_buf_add(buf, XML_ELEMENT_MORESPACE, lbuf);
    436 	tgt_buf_add_tag(buf, XML_ELEMENT_ERROR, Tag_End);
    437 }
    438 
    439 /*ARGSUSED*/
    440 static void
    441 server_for_door(void *cookie, char *argp, size_t arg_size, door_desc_t *dp,
    442     uint_t n_desc)
    443 {
    444 	target_queue_t		*mgmtq		= (target_queue_t *)cookie;
    445 	mgmt_request_t		m;
    446 	msg_t			*msg		= NULL;
    447 	tgt_node_t		*node		= NULL;
    448 	xmlTextReaderPtr	r;
    449 	char			*err_rply	= NULL;
    450 	ucred_t			*uc		= NULL;
    451 	size_t			cur_space;
    452 
    453 	/*
    454 	 * A well written application will always give us enough space
    455 	 * to send either a "success" message or a "more space needed".
    456 	 * If the minimum amount of space isn't given then just return
    457 	 * with a NULL pointer.
    458 	 */
    459 	if (arg_size < door_min_space) {
    460 		(void) door_return(NULL, 0, NULL, 0);
    461 		return;
    462 	}
    463 
    464 	/*
    465 	 * Pick up the user credentials of the client application. Used to
    466 	 * validate that the effective user ID is either root or the process
    467 	 * has the privilege to complete the operation.
    468 	 */
    469 	if (door_ucred(&uc) != 0) {
    470 		xml_rtn_msg(&err_rply, ERR_BAD_CREDS);
    471 		(void) strlcpy(argp, err_rply, arg_size);
    472 		free(err_rply);
    473 		(void) door_return(argp, strlen(argp) + 1, NULL, 0);
    474 		return;
    475 	}
    476 
    477 	if (validate_xml(argp) != True) {
    478 		xml_rtn_msg(&err_rply, ERR_INVALID_XML_REQUEST);
    479 		(void) strlcpy(argp, err_rply, arg_size);
    480 		free(err_rply);
    481 		(void) door_return(argp, strlen(argp) + 1, NULL, 0);
    482 		return;
    483 	}
    484 
    485 	bzero(&m, sizeof (m));
    486 
    487 	if ((r = (xmlTextReaderPtr)xmlReaderForMemory(argp, strlen(argp),
    488 	    NULL, NULL, 0)) != NULL) {
    489 		while (xmlTextReaderRead(r)) {
    490 			if (tgt_node_process(r, &node) == False)
    491 				break;
    492 		}
    493 		if (node != NULL) {
    494 			m.m_q		= queue_alloc();
    495 			m.m_request	= mgmt_parse_xml;
    496 			m.m_time	= time(NULL);
    497 			m.m_targ_name	= NULL;
    498 			m.m_u.m_node	= node;
    499 			m.m_cred	= uc;
    500 
    501 			queue_message_set(mgmtq, 0, msg_mgmt_rqst, &m);
    502 			if ((msg = queue_message_get(m.m_q)) == NULL) {
    503 				(void) xmlFreeTextReader(r);
    504 				(void) xmlCleanupParser();
    505 				(void) ucred_free(uc);
    506 				tgt_node_free(node);
    507 				if (m.m_q != NULL)
    508 					queue_free(m.m_q, NULL);
    509 				(void) door_return("", 1, NULL, 0);
    510 				return;
    511 			}
    512 
    513 			/*
    514 			 * Check to see if the response can fit into the
    515 			 * incoming argument buffer. If so, copy the response
    516 			 * to that buffer so that we can free the data.
    517 			 * If it's not big enough we'll request an updated
    518 			 * space message, then delete the current data, allowing
    519 			 * the request to be requeued again.
    520 			 */
    521 			if ((cur_space = strlen(msg->msg_data)) < arg_size) {
    522 				(void) strlcpy(argp, msg->msg_data, arg_size);
    523 			} else {
    524 				/*
    525 				 * err_rply will be copied to argp at the end
    526 				 */
    527 				space_message(&err_rply, cur_space + 1);
    528 			}
    529 			free(msg->msg_data);
    530 			queue_message_free(msg);
    531 		} else {
    532 			xml_rtn_msg(&err_rply, ERR_NULL_XML_MESSAGE);
    533 		}
    534 
    535 		xmlFreeTextReader(r);
    536 		xmlCleanupParser();
    537 
    538 	} else {
    539 		xml_rtn_msg(&err_rply, ERR_INIT_XML_READER_FAILED);
    540 	}
    541 
    542 	if (node != NULL)
    543 		tgt_node_free(node);
    544 	if (err_rply != NULL) {
    545 		(void) strlcpy(argp, err_rply, arg_size);
    546 		free(err_rply);
    547 	}
    548 	if (m.m_q != NULL)
    549 		queue_free(m.m_q, NULL);
    550 
    551 	ucred_free(uc);
    552 	(void) door_return(argp, strlen(argp) + 1, NULL, 0);
    553 }
    554 
    555 /*
    556  * []----
    557  * | setup_door -- Create a door portal for management requests
    558  * |
    559  * | First check to see if another daemon is already running by attempting
    560  * | to send an empty request to the door. If successful it means this
    561  * | daemon should exit.
    562  * []----
    563  */
    564 static void
    565 setup_door(target_queue_t *q, char *door_name)
    566 {
    567 	int		did, fd;
    568 	struct stat	s;
    569 	door_arg_t	d;
    570 	char		*msg = NULL;
    571 
    572 	/*
    573 	 * Figure out what the minimum amount of space required to send back
    574 	 * either a success message or a need more space one.
    575 	 *
    576 	 * Commands fall into one of three categories.
    577 	 * (1) Idempotent commands, like list operations, which can
    578 	 *    return large ammounts of data. If there's not enough room
    579 	 *    the client is informed and the command is run again with a
    580 	 *    larger buffer.
    581 	 * (2) Create, modify, or delete operations that fail. These
    582 	 *    commands may return an error message which is larger than
    583 	 *    the incoming request buffer. If so, the client is informed
    584 	 *    that a larger buffer is needed and the command is rerun. This
    585 	 *    time it'll recieve the full error message. So, these commands
    586 	 *    are idempotent because no state changes occur on failure.
    587 	 * (3) Create, modify, or delete operations which are successful.
    588 	 *    Since successful completion means state has change the daemon
    589 	 *    must always be able to report success, other wise a second
    590 	 *    attempt with a larger buffer would then fail, where the first
    591 	 *    one actually succeeded.
    592 	 */
    593 	xml_rtn_msg(&msg, ERR_SUCCESS);
    594 	door_min_space = strlen(msg);
    595 	free(msg);
    596 	msg = NULL;
    597 	/*
    598 	 * Use an impossibly big number which will create the longest string
    599 	 */
    600 	space_message(&msg, 0x80000000);
    601 	door_min_space = MAX(door_min_space, strlen(msg));
    602 	free(msg);
    603 
    604 	door_min_space++;	/* add 1 for the NULL byte */
    605 
    606 	/*
    607 	 * DOOR_MIN_SPACE will be the amount used by the library as the default.
    608 	 * Currently this will be set to 128 (check iscsitgt_impl.h for value).
    609 	 * Since this will be a compiled value and the "success" or "more space"
    610 	 * messages could grown we need to detect if there will be a problem.
    611 	 * By failing here consistently, SMF will put the daemon in maintenance
    612 	 * state and this will be caught during testing. Otherwise the library
    613 	 * would receive a NULL back, but not know how much space is really
    614 	 * required.
    615 	 */
    616 	if (door_min_space > DOOR_MIN_SPACE) {
    617 		syslog(LOG_ERR,
    618 		    "Calculated min space (%d) is larger than default (%d)",
    619 		    door_min_space, DOOR_MIN_SPACE);
    620 		assert(0);
    621 	}
    622 
    623 	if ((fd = open(door_name, 0)) >= 0) {
    624 
    625 		/*
    626 		 * There's at least a file with the same name as our
    627 		 * door. Let's see if someone is currently answering
    628 		 * by sending an empty XML request.
    629 		 */
    630 		d.data_ptr	= "<config></config>";
    631 		d.data_size	= strlen(d.data_ptr) + 1;
    632 		d.desc_ptr	= NULL;
    633 		d.desc_num	= 0;
    634 		d.rbuf		= NULL;
    635 		d.rsize		= 0;
    636 
    637 		if (door_call(fd, &d) == 0) {
    638 
    639 			/*
    640 			 * If the door_call succeeds that means another
    641 			 * daemon is already running so let's just exit.
    642 			 */
    643 			exit(0);
    644 		}
    645 		(void) close(fd);
    646 	}
    647 
    648 	if ((did = door_create(server_for_door, (void *)q, 0)) < 0) {
    649 		syslog(LOG_ERR, "door_create");
    650 		exit(1);
    651 	}
    652 
    653 	if (stat(door_name, &s) < 0) {
    654 		int	newfd;
    655 		if ((newfd = creat(door_name, 0666)) < 0) {
    656 			syslog(LOG_ERR, "creat failed");
    657 			exit(1);
    658 		}
    659 		(void) close(newfd);
    660 	}
    661 	(void) fdetach(door_name);
    662 
    663 	/*
    664 	 * Open the door for general access. As the calls come in we'll
    665 	 * get the credentials and validate within each operation as to the
    666 	 * required privileges.
    667 	 */
    668 	(void) chmod(door_name, 0666);
    669 
    670 	if (fattach(did, door_name) < 0) {
    671 		syslog(LOG_ERR, "fattach failed errno=%d", errno);
    672 		exit(2);
    673 	}
    674 }
    675 
    676 /*ARGSUSED*/
    677 void
    678 exit_after_door_setup(int sig, siginfo_t *sip, void *v)
    679 {
    680 	exit(SMF_EXIT_OK);
    681 }
    682 
    683 int
    684 main(int argc, char **argv)
    685 {
    686 	char			c, *p, *door_name;
    687 	msg_t			*msg;
    688 	target_queue_t		*q;
    689 	port_args_t		port1, port2;
    690 	Boolean_t		mgmt_up		= False;
    691 	Boolean_t		daemonize	= True;
    692 	Boolean_t		console_output	= True;
    693 	pthread_t		junk;
    694 	mgmt_request_t		*mgmt;
    695 	struct sigaction	act;
    696 	struct rlimit		rl;
    697 	void			*thr_status;
    698 
    699 	door_name	= ISCSI_TARGET_MGMT_DOOR;
    700 
    701 	while ((c = getopt(argc, argv, "c:d:")) != EOF) {
    702 		switch (c) {
    703 		case 'c':
    704 			config_file = optarg;
    705 			break;
    706 		case 'd':
    707 			door_name = optarg;
    708 			break;
    709 		}
    710 	}
    711 
    712 	/*
    713 	 * If the initiator closes the socket because of a protocol error
    714 	 * or bad digest on the header packet we'll receive a SIGPIPE if we're
    715 	 * in the middle of a write operation. There's no need to receive
    716 	 * a signal when a -1 from the write will handle things correctly.
    717 	 * So, ignore SIGPIPE's.
    718 	 */
    719 	(void) sigignore(SIGPIPE);
    720 
    721 	/*
    722 	 * Setup memory caches
    723 	 */
    724 	if ((iscsi_cmd_cache = umem_cache_create("iSCSI conn cmds",
    725 	    sizeof (iscsi_cmd_t), 8, NULL, NULL, NULL, NULL, NULL, 0)) ==
    726 	    NULL) {
    727 		perror("cache create");
    728 		exit(SMF_EXIT_ERR_CONFIG);
    729 	}
    730 	if ((t10_cmd_cache = umem_cache_create("T10 cmds",
    731 	    sizeof (t10_cmd_t), 8, NULL, NULL, NULL, NULL, NULL, 0)) == NULL) {
    732 		perror("cache create");
    733 		exit(SMF_EXIT_ERR_CONFIG);
    734 	}
    735 	if ((queue_cache = umem_cache_create("Queue messages",
    736 	    sizeof (msg_t), 8, NULL, NULL, NULL, NULL, NULL, 0)) == NULL) {
    737 		perror("cache create");
    738 		exit(SMF_EXIT_ERR_CONFIG);
    739 	}
    740 
    741 	/*
    742 	 * Look at the function lu_buserr_handler() in t10_sam.c to see the
    743 	 * details of why we need to handle segmentation violations.
    744 	 */
    745 	bzero(&act, sizeof (act));
    746 	act.sa_sigaction	= lu_buserr_handler;
    747 	act.sa_flags		= SA_SIGINFO;
    748 
    749 	if (sigaction(SIGBUS, &act, NULL) == -1) {
    750 		perror("sigaction");
    751 		exit(SMF_EXIT_ERR_CONFIG);
    752 	}
    753 
    754 
    755 	if (mgmt_convert_conf() == CONVERT_FAIL)
    756 		exit(SMF_EXIT_ERR_CONFIG);
    757 
    758 	if (process_config() == False)
    759 		exit(SMF_EXIT_ERR_CONFIG);
    760 
    761 	/*
    762 	 * During the normal corse of events 'target_basedir' will be
    763 	 * free when the administrator changes the base directory. Instead
    764 	 * of trying to check for the initial case of this value being set
    765 	 * to some static string, always allocate that string.
    766 	 * NOTE: This must be done *after* process_config() is called since
    767 	 * it's possible and very likely that this value will be set at that
    768 	 * time.
    769 	 */
    770 	if (target_basedir == NULL)
    771 		target_basedir = strdup(DEFAULT_TARGET_BASEDIR);
    772 
    773 	(void) tgt_find_value_boolean(main_config, XML_ELEMENT_DBGDAEMON,
    774 	    &daemonize);
    775 
    776 	q = queue_alloc();
    777 	if (daemonize == True) {
    778 		closefrom(0);
    779 
    780 		/*
    781 		 * Set up a signal handler to catch SIGUSR2. Once the child
    782 		 * has setup the door, it will signal the parent that it's
    783 		 * safe to exit. Without doing this it's possible that the
    784 		 * daemon will start and the parent exit before the child has
    785 		 * setup the door. If that happens 'zfs share -a iscsi' which
    786 		 * is run from svc-iscsitgt will fail to open the door and try
    787 		 * to wait for the iscsitgt service to come online. Since
    788 		 * the zfs command is part of the service start, the service
    789 		 * will not come online and we'll fail to share any ZVOLs.
    790 		 */
    791 		bzero(&act, sizeof (act));
    792 		act.sa_sigaction	= exit_after_door_setup;
    793 		act.sa_flags		= SA_SIGINFO;
    794 		if (sigaction(SIGUSR2, &act, NULL) == -1) {
    795 			perror("sigaction");
    796 			exit(SMF_EXIT_ERR_CONFIG);
    797 		}
    798 
    799 		switch (fork()) {
    800 		case 0:
    801 			/*
    802 			 * As the child process, setup the door and then
    803 			 * signal the parent that it can exit since the child
    804 			 * is now ready to start accepting requests on the
    805 			 * door.
    806 			 */
    807 			setup_door(q, door_name);
    808 			(void) kill(getppid(), SIGUSR2);
    809 			break;
    810 
    811 		case -1:
    812 			/* ---- Failed to fork!. Trouble ---- */
    813 			exit(SMF_EXIT_ERR_CONFIG);
    814 
    815 		default:
    816 			/*
    817 			 * If pause() returns with an error something
    818 			 * interrupted the process which was not a SIGUSR2.
    819 			 * Exit with an error code such that SMF can flag
    820 			 * this problem.
    821 			 */
    822 			if (pause() == -1)
    823 				exit(SMF_EXIT_ERR_CONFIG);
    824 		}
    825 	} else {
    826 
    827 		/*
    828 		 * The daemon is working in debug mode, so go ahead and
    829 		 * setup the door now.
    830 		 */
    831 		setup_door(q, door_name);
    832 	}
    833 
    834 	/*
    835 	 * Initialize the various subsystems. In most cases these are
    836 	 * just initializing mutexs.
    837 	 */
    838 	(void) pthread_rwlock_init(&targ_config_mutex, NULL);
    839 	iscsi_cmd_init();
    840 	session_init();
    841 	t10_init(q);
    842 	port_init();
    843 	queue_init();
    844 	util_init();
    845 	(void) isns_init(q);
    846 
    847 	/*
    848 	 * If there's no MAC address currently available don't worry about
    849 	 * it. The first time an initiator connects the SAM-3 layer will
    850 	 * attempt to create a GUID and force another look for a MAC address.
    851 	 */
    852 	if (if_find_mac(q) == False)
    853 		queue_prt(q, Q_GEN_DETAILS, "MAIN: No MAC address available");
    854 
    855 	/*
    856 	 * At a minimum we need two file descriptors for each target, one for
    857 	 * the socket and one for the backing store. If there's more than one
    858 	 * initiator attached to a given target than that number goes up by 1.
    859 	 * Once we have multiple sessions per connection that to will cause
    860 	 * an increase.
    861 	 */
    862 	if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) &&
    863 	    (rl.rlim_cur < TARGET_NOFILE)) {
    864 		rl.rlim_cur = TARGET_NOFILE;
    865 		if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
    866 			syslog(LOG_NOTICE,
    867 			    "Can't set new limit for open files");
    868 	}
    869 
    870 	port1.port_mgmtq	= q;
    871 	port1.port_num		= iscsi_port;
    872 	(void) pthread_create(&junk, NULL, port_watcher, &port1);
    873 
    874 	if ((tgt_find_value_int(main_config, XML_ELEMENT_MGMTPORT,
    875 	    &port2.port_num) == True) && (port2.port_num != -1)) {
    876 		port2.port_mgmtq	= q;
    877 		port2.port_dataq	= queue_alloc();
    878 		(void) pthread_create(&junk, NULL, port_management, &port2);
    879 	}
    880 
    881 	do {
    882 		msg = queue_message_get(q);
    883 
    884 		switch (msg->msg_type) {
    885 		case msg_pthread_join:
    886 			(void) pthread_join((pthread_t)(uintptr_t)msg->msg_data,
    887 			    &thr_status);
    888 			if (thr_status != 0)
    889 				queue_prt(q, Q_GEN_ERRS,
    890 				    "Thread %d exit with %d",
    891 				    msg->msg_data, thr_status);
    892 			msg->msg_data = NULL;
    893 			break;
    894 
    895 		case msg_log:
    896 			if ((p = strchr(msg->msg_data, '\n')) != NULL)
    897 				*p = '\0';
    898 			p = (char *)msg->msg_data;
    899 			if ((msg->msg_pri_level & dbg_lvl) == 0)
    900 				break;
    901 
    902 			if (mgmt_up == True)
    903 				queue_str(port2.port_dataq, Q_GEN_DETAILS,
    904 				    msg_log, p);
    905 			if (console_output == True)
    906 				(void) printf("%s\n", p);
    907 			break;
    908 
    909 		case msg_mgmt_rqst:
    910 			mgmt = (mgmt_request_t *)msg->msg_data;
    911 			if (mgmt->m_request == mgmt_parse_xml)
    912 				parse_xml(mgmt->m_u.m_node, mgmt->m_q, q,
    913 				    mgmt->m_cred);
    914 			msg->msg_data = NULL;
    915 			break;
    916 
    917 		case msg_status:
    918 			p = (char *)msg->msg_data;
    919 			/*
    920 			 * NOTE:
    921 			 * These are real error conditons being sent from
    922 			 * the other threads and should be logged in
    923 			 * some manner, either syslog() or using a FMA
    924 			 * interface.
    925 			 */
    926 			(void) printf("STATUS: %s\n", p);
    927 			break;
    928 
    929 		default:
    930 			break;
    931 		}
    932 
    933 		if (msg->msg_data != NULL)
    934 			free(msg->msg_data);
    935 		queue_message_free(msg);
    936 	/*CONSTANTCONDITION*/
    937 	} while (1);
    938 
    939 	return (0);
    940 }
    941