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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <sys/types.h>
     30 #include <sys/stat.h>
     31 #include <time.h>
     32 #include <sys/utsname.h>
     33 #include <unistd.h>
     34 #include <sys/param.h>
     35 #include <fcntl.h>
     36 #include <errno.h>
     37 #include <strings.h>
     38 #include <dirent.h>
     39 #include <priv.h>
     40 #include <syslog.h>
     41 
     42 #include <iscsitgt_impl.h>
     43 #include "utility.h"
     44 #include "queue.h"
     45 #include "target.h"
     46 #include "iscsi_cmd.h"
     47 #include "iscsi_conn.h"
     48 #include "port.h"
     49 #include "errcode.h"
     50 #include "mgmt_scf.h"
     51 #include "isns_client.h"
     52 
     53 static char *list_targets(tgt_node_t *x);
     54 static char *list_initiator(tgt_node_t *x);
     55 static char *list_tpgt(tgt_node_t *x);
     56 static char *list_admin(tgt_node_t *x);
     57 static void target_info(char **msg, char *targ_name, tgt_node_t *tnode);
     58 static void target_stat(char **msg, char *iname, mgmt_type_t type);
     59 
     60 /*ARGSUSED*/
     61 void
     62 list_func(tgt_node_t *p, target_queue_t *reply, target_queue_t *mgmt,
     63     ucred_t *cred)
     64 {
     65 	tgt_node_t	*x;
     66 	char		msgbuf[80];
     67 	char		*reply_msg	= NULL;
     68 
     69 	if (p->x_child == NULL) {
     70 		xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
     71 	} else {
     72 		x = p->x_child;
     73 
     74 		if (x->x_name == NULL) {
     75 			xml_rtn_msg(&reply_msg, ERR_SYNTAX_MISSING_OBJECT);
     76 		} else if (strcmp(x->x_name, XML_ELEMENT_TARG) == 0) {
     77 			reply_msg = list_targets(x);
     78 		} else if (strcmp(x->x_name, XML_ELEMENT_INIT) == 0) {
     79 			reply_msg = list_initiator(x);
     80 		} else if (strcmp(x->x_name, XML_ELEMENT_TPGT) == 0) {
     81 			reply_msg = list_tpgt(x);
     82 		} else if (strcmp(x->x_name, XML_ELEMENT_ADMIN) == 0) {
     83 			reply_msg = list_admin(x);
     84 		} else {
     85 			(void) snprintf(msgbuf, sizeof (msgbuf),
     86 			    "Unknown object '%s' for list element",
     87 			    x->x_name);
     88 			xml_rtn_msg(&reply_msg, ERR_INVALID_OBJECT);
     89 		}
     90 	}
     91 	queue_message_set(reply, 0, msg_mgmt_rply, reply_msg);
     92 }
     93 
     94 /*ARGSUSED*/
     95 static char *
     96 list_targets(tgt_node_t *x)
     97 {
     98 	char		*msg	= NULL;
     99 	char		*prop	= NULL;
    100 	char		*iname	= NULL;
    101 	tgt_node_t	*targ	= NULL;
    102 	Boolean_t	luninfo	= False;
    103 	Boolean_t	dostat	= False;
    104 
    105 	/*
    106 	 * It's okay to not supply a "name" element. That just means the
    107 	 * administrator wants a complete list of targets. However if a
    108 	 * "name" is supplied then there must be a value for that element.
    109 	 */
    110 	if ((tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) &&
    111 	    (prop == NULL)) {
    112 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    113 		return (msg);
    114 	}
    115 
    116 	/* ---- optional arguments ---- */
    117 	(void) tgt_find_value_boolean(x, XML_ELEMENT_LUNINFO, &luninfo);
    118 	(void) tgt_find_value_boolean(x, XML_ELEMENT_IOSTAT, &dostat);
    119 
    120 	tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'");
    121 	while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG,
    122 	    targ)) != NULL) {
    123 		if (targ->x_value == NULL) {
    124 			tgt_buf_add(&msg, XML_ELEMENT_TARG,
    125 			    "bogus entry");
    126 			continue;
    127 		}
    128 		if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &iname) ==
    129 		    False) {
    130 			tgt_buf_add(&msg, XML_ELEMENT_TARG,
    131 			    "missing iscsi-name");
    132 			continue;
    133 		}
    134 		if (prop != NULL) {
    135 			if (strcmp(prop, targ->x_value) == 0) {
    136 				tgt_buf_add_tag(&msg, XML_ELEMENT_TARG,
    137 				    Tag_Start);
    138 				tgt_buf_add_tag(&msg, targ->x_value,
    139 				    Tag_String);
    140 				tgt_buf_add(&msg, XML_ELEMENT_INAME, iname);
    141 				if (luninfo == True)
    142 					target_info(&msg, iname, targ);
    143 				if (dostat == True)
    144 					target_stat(&msg, iname,
    145 					    mgmt_full_phase_statistics);
    146 				tgt_buf_add_tag(&msg, XML_ELEMENT_TARG,
    147 				    Tag_End);
    148 			}
    149 		} else {
    150 			tgt_buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_Start);
    151 			tgt_buf_add_tag(&msg, targ->x_value, Tag_String);
    152 			tgt_buf_add(&msg, XML_ELEMENT_INAME, iname);
    153 			if (dostat == True)
    154 				target_stat(&msg, iname,
    155 				    mgmt_full_phase_statistics);
    156 			if (luninfo == True)
    157 				target_info(&msg, iname, targ);
    158 			tgt_buf_add_tag(&msg, XML_ELEMENT_TARG, Tag_End);
    159 		}
    160 		free(iname);
    161 	}
    162 	tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End);
    163 	free(prop);
    164 
    165 	return (msg);
    166 }
    167 
    168 /*ARGSUSED*/
    169 static char *
    170 list_initiator(tgt_node_t *x)
    171 {
    172 	char		*msg	= NULL;
    173 	char		*attr	= NULL;
    174 	char		*prop	= NULL;
    175 	Boolean_t	verbose	= False;
    176 	tgt_node_t	*init	= NULL;
    177 
    178 	/* ---- Optional arguments ---- */
    179 	if ((tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) &&
    180 	    (prop == NULL)) {
    181 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    182 		return (msg);
    183 	}
    184 	(void) tgt_find_value_boolean(x, XML_ELEMENT_VERBOSE, &verbose);
    185 
    186 	tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'");
    187 	while ((init = tgt_node_next_child(main_config, XML_ELEMENT_INIT, init))
    188 	    != NULL) {
    189 		if ((prop == NULL) ||
    190 		    ((prop != NULL) && (strcmp(prop, init->x_value) == 0))) {
    191 
    192 			tgt_buf_add_tag(&msg, XML_ELEMENT_INIT, Tag_Start);
    193 			tgt_buf_add_tag(&msg, init->x_value, Tag_String);
    194 
    195 			if (tgt_find_value_str(init, XML_ELEMENT_INAME,
    196 			    &attr) == True) {
    197 				tgt_buf_add(&msg, XML_ELEMENT_INAME, attr);
    198 				free(attr);
    199 			}
    200 
    201 			if (tgt_find_value_str(init, XML_ELEMENT_CHAPSECRET,
    202 			    &attr) == True) {
    203 				tgt_buf_add(&msg, XML_ELEMENT_CHAPSECRET,
    204 				    "Set");
    205 				free(attr);
    206 			}
    207 
    208 			if (tgt_find_value_str(init, XML_ELEMENT_CHAPNAME,
    209 			    &attr) == True) {
    210 				tgt_buf_add(&msg, XML_ELEMENT_CHAPNAME, attr);
    211 				free(attr);
    212 			}
    213 
    214 			tgt_buf_add_tag(&msg, XML_ELEMENT_INIT, Tag_End);
    215 		}
    216 	}
    217 
    218 	if (prop != NULL)
    219 		free(prop);
    220 
    221 	tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End);
    222 
    223 	return (msg);
    224 }
    225 
    226 /*ARGSUSED*/
    227 static char *
    228 list_tpgt(tgt_node_t *x)
    229 {
    230 	char		*msg	= NULL;
    231 	char		*prop	= NULL;
    232 	Boolean_t	verbose	= False;
    233 	tgt_node_t	*tpgt	= NULL;
    234 	tgt_node_t	*ip	= NULL;
    235 
    236 	/* ---- Optional arguments ---- */
    237 	if ((tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == True) &&
    238 	    (prop == NULL)) {
    239 		xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME);
    240 		return (msg);
    241 	}
    242 	(void) tgt_find_value_boolean(x, XML_ELEMENT_VERBOSE, &verbose);
    243 
    244 	tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'");
    245 	while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tpgt))
    246 	    != NULL) {
    247 		if ((prop == NULL) ||
    248 		    ((prop != NULL) && (strcmp(prop, tpgt->x_value) == 0))) {
    249 
    250 			tgt_buf_add_tag(&msg, XML_ELEMENT_TPGT, Tag_Start);
    251 			tgt_buf_add_tag(&msg, tpgt->x_value, Tag_String);
    252 
    253 			while ((ip = tgt_node_next(tpgt, XML_ELEMENT_IPADDR,
    254 			    ip)) != NULL) {
    255 				tgt_buf_add(&msg, ip->x_name, ip->x_value);
    256 			}
    257 
    258 			tgt_buf_add_tag(&msg, XML_ELEMENT_TPGT, Tag_End);
    259 		}
    260 	}
    261 	tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End);
    262 
    263 	if (prop != NULL)
    264 		free(prop);
    265 	return (msg);
    266 }
    267 
    268 /*ARGSUSED*/
    269 static char *
    270 list_admin(tgt_node_t *x)
    271 {
    272 	char		*msg	= NULL;
    273 	admin_table_t	*p;
    274 	tgt_node_t	*node	= NULL;
    275 	tgt_node_t	*isns_srv_node	= NULL;
    276 	Boolean_t	enabled = False;
    277 
    278 	tgt_buf_add_tag_and_attr(&msg, XML_ELEMENT_RESULT, "version='1.0'");
    279 	tgt_buf_add_tag(&msg, XML_ELEMENT_ADMIN, Tag_Start);
    280 
    281 	node = NULL;
    282 	for (p = admin_prop_list; p->name != NULL; p++) {
    283 		node = tgt_node_next_child(main_config, p->name, NULL);
    284 		if (node) {
    285 			if (strcmp(p->name, XML_ELEMENT_CHAPSECRET) == 0) {
    286 				tgt_buf_add(&msg, p->name, "Set");
    287 			} else if (strcmp(p->name, XML_ELEMENT_ISNS_ACCESS)
    288 			    == 0) {
    289 				tgt_buf_add(&msg, p->name, node->x_value);
    290 				/* check the isns discovery */
    291 				if (node->x_value &&
    292 				    strcmp(node->x_value, "true") == 0) {
    293 					enabled = True;
    294 				}
    295 			} else if (strcmp(p->name, XML_ELEMENT_ISNS_SERV)
    296 			    == 0) {
    297 				tgt_buf_add(&msg, p->name, node->x_value);
    298 				/*
    299 				 * check the state of isns server connection.
    300 				 */
    301 				if (node->x_value != NULL) {
    302 					isns_srv_node = node;
    303 				}
    304 			} else {
    305 				tgt_buf_add(&msg, p->name, node->x_value);
    306 			}
    307 		}
    308 	}
    309 
    310 	/*
    311 	 * check the state of isns server connection and add the node.
    312 	 * the conncection state is dynamic so it doesn't get stored in
    313 	 * incore config.
    314 	 */
    315 	if (enabled && isns_srv_node) {
    316 		if (isns_open(isns_srv_node->x_value) == -1) {
    317 			tgt_buf_add(&msg, XML_ELEMENT_ISNS_SERVER_STATUS,
    318 			    "Unavailable");
    319 		} else {
    320 			tgt_buf_add(&msg, XML_ELEMENT_ISNS_SERVER_STATUS,
    321 			    "Available");
    322 		}
    323 	} else {
    324 		tgt_buf_add(&msg, XML_ELEMENT_ISNS_SERVER_STATUS,
    325 		"Not applicable");
    326 	}
    327 
    328 	tgt_buf_add_tag(&msg, XML_ELEMENT_ADMIN, Tag_End);
    329 	tgt_buf_add_tag(&msg, XML_ELEMENT_RESULT, Tag_End);
    330 
    331 	return (msg);
    332 }
    333 
    334 static void
    335 target_stat(char **msg, char *targ_name, mgmt_type_t type)
    336 {
    337 	iscsi_conn_t	*c;
    338 	msg_t		*m;
    339 	target_queue_t	*q = queue_alloc();
    340 	mgmt_request_t	mgmt_rqst;
    341 	int		msg_sent;
    342 	int		i;
    343 	extern pthread_mutex_t	port_mutex;
    344 
    345 	mgmt_rqst.m_q		= q;
    346 	mgmt_rqst.m_u.m_resp	= msg;
    347 	mgmt_rqst.m_time	= time(NULL);
    348 	mgmt_rqst.m_request	= type;
    349 	(void) pthread_mutex_init(&mgmt_rqst.m_resp_mutex, NULL);
    350 
    351 	(void) pthread_mutex_lock(&port_mutex);
    352 	mgmt_rqst.m_targ_name	= targ_name;
    353 	msg_sent		= 0;
    354 	for (c = conn_head; c; c = c->c_next) {
    355 		if (c->c_state == S5_LOGGED_IN) {
    356 			/*
    357 			 * Only send requests for statistics to
    358 			 * connections that are up. Could even
    359 			 * go further and only look at connections
    360 			 * which are S5_LOGGED_IN, but there may
    361 			 * be statistics, such as connection time,
    362 			 * which we'd like to have.
    363 			 */
    364 			queue_message_set(c->c_dataq, 0, msg_mgmt_rqst,
    365 			    &mgmt_rqst);
    366 			msg_sent++;
    367 		}
    368 	}
    369 	(void) pthread_mutex_unlock(&port_mutex);
    370 
    371 	/*
    372 	 * Comment: main.c:list_targets:1
    373 	 * We wait for the responses without the port_mutex
    374 	 * being held. There is a small window between when the
    375 	 * connection last listens for a message and when the
    376 	 * queue is freed. During that time the connection will
    377 	 * attempt to grab the port_mutex lock so that it
    378 	 * can unlink itself and call queueu_free(). If we sent
    379 	 * the message with the lock held and then wait for a response
    380 	 * it's possible that the connection will deadlock waiting
    381 	 * to get the port_mutex.
    382 	 */
    383 	for (i = 0; i < msg_sent; i++) {
    384 		m = queue_message_get(q);
    385 		queue_message_free(m);
    386 	}
    387 	queue_free(q, NULL);
    388 }
    389 
    390 static void
    391 target_info(char **msg, char *targ_name, tgt_node_t *tnode)
    392 {
    393 	char			lun_buf[16];
    394 	char			*prop;
    395 	char			*local_name = NULL;
    396 	tgt_node_t		*lnode;	/* list node */
    397 	tgt_node_t		*lnp; /* list node pointer */
    398 	tgt_node_t		*lun;
    399 	tgt_node_t		*params;
    400 	int			lun_num;
    401 	Boolean_t		incore;
    402 	struct stat		s;
    403 
    404 	if ((lnode = tgt_node_next(tnode, XML_ELEMENT_ACLLIST, NULL)) !=
    405 	    NULL) {
    406 		lnp = NULL;
    407 		tgt_buf_add_tag(msg, XML_ELEMENT_ACLLIST, Tag_Start);
    408 		while ((lnp = tgt_node_next(lnode, XML_ELEMENT_INIT, lnp)) !=
    409 		    NULL)
    410 			tgt_buf_add(msg, XML_ELEMENT_INIT, lnp->x_value);
    411 		tgt_buf_add_tag(msg, XML_ELEMENT_ACLLIST, Tag_End);
    412 	}
    413 
    414 	if ((lnode = tgt_node_next(tnode, XML_ELEMENT_TPGTLIST, NULL)) !=
    415 	    NULL) {
    416 		lnp = NULL;
    417 		tgt_buf_add_tag(msg, XML_ELEMENT_TPGTLIST, Tag_Start);
    418 		while ((lnp = tgt_node_next(lnode, XML_ELEMENT_TPGT, lnp)) !=
    419 		    NULL)
    420 			tgt_buf_add(msg, XML_ELEMENT_TPGT, lnp->x_value);
    421 		tgt_buf_add_tag(msg, XML_ELEMENT_TPGTLIST, Tag_End);
    422 	}
    423 
    424 	if ((lnode = tgt_node_next(tnode, XML_ELEMENT_ALIAS, NULL)) != NULL)
    425 		tgt_buf_add(msg, XML_ELEMENT_ALIAS, lnode->x_value);
    426 
    427 	if ((lnode = tgt_node_next(tnode, XML_ELEMENT_MAXRECV, NULL)) != NULL)
    428 		tgt_buf_add(msg, XML_ELEMENT_MAXRECV, lnode->x_value);
    429 
    430 	if ((lnode = tgt_node_next(tnode, XML_ELEMENT_LUNLIST, NULL)) == NULL)
    431 		return;
    432 
    433 	if (tgt_find_attr_str(tnode, XML_ELEMENT_INCORE, &prop) == True) {
    434 		if (strcmp(prop, "true") == 0)
    435 			incore = True;
    436 		else
    437 			incore = False;
    438 		free(prop);
    439 	} else
    440 		incore = False;
    441 
    442 	tgt_buf_add_tag(msg, XML_ELEMENT_LUNINFO, Tag_Start);
    443 	lun = NULL;
    444 	while ((lun = tgt_node_next(lnode, XML_ELEMENT_LUN, lun)) != NULL) {
    445 		if ((tgt_find_value_int(lun, XML_ELEMENT_LUN, &lun_num)) ==
    446 		    False)
    447 			continue;
    448 		if (incore == False) {
    449 			local_name = get_local_name(targ_name);
    450 			if (local_name != NULL) {
    451 				(void) mgmt_get_param(&params, local_name,
    452 				    lun_num);
    453 				free(local_name);
    454 			} else {
    455 				continue;
    456 			}
    457 		} else {
    458 			params = lun;
    459 		}
    460 
    461 		tgt_buf_add_tag(msg, XML_ELEMENT_LUN, Tag_Start);
    462 		(void) snprintf(lun_buf, sizeof (lun_buf), "%d", lun_num);
    463 		tgt_buf_add_tag(msg, lun_buf, Tag_String);
    464 
    465 		if (tgt_find_value_str(params, XML_ELEMENT_GUID, &prop) ==
    466 		    True) {
    467 			tgt_buf_add(msg, XML_ELEMENT_GUID, prop);
    468 			free(prop);
    469 		}
    470 		if (tgt_find_value_str(params, XML_ELEMENT_VID, &prop) ==
    471 		    True) {
    472 			tgt_buf_add(msg, XML_ELEMENT_VID, prop);
    473 			free(prop);
    474 		}
    475 		if (tgt_find_value_str(params, XML_ELEMENT_PID, &prop) ==
    476 		    True) {
    477 			tgt_buf_add(msg, XML_ELEMENT_PID, prop);
    478 			free(prop);
    479 		}
    480 		if (tgt_find_value_str(params, XML_ELEMENT_DTYPE, &prop) ==
    481 		    True) {
    482 			tgt_buf_add(msg, XML_ELEMENT_DTYPE, prop);
    483 			free(prop);
    484 		}
    485 		if (tgt_find_value_str(params, XML_ELEMENT_SIZE, &prop) ==
    486 		    True) {
    487 			tgt_buf_add(msg, XML_ELEMENT_SIZE, prop);
    488 			free(prop);
    489 		}
    490 		if (tgt_find_value_str(params, XML_ELEMENT_BACK, &prop) ==
    491 		    True) {
    492 			tgt_buf_add(msg, XML_ELEMENT_BACK, prop);
    493 			if (stat(prop, &s) == 0) {
    494 				tgt_buf_add(msg, XML_ELEMENT_STATUS,
    495 				    TGT_STATUS_ONLINE);
    496 			} else {
    497 				tgt_buf_add(msg, XML_ELEMENT_STATUS,
    498 				    strerror(errno));
    499 			}
    500 			free(prop);
    501 		}
    502 		tgt_buf_add_tag(msg, XML_ELEMENT_LUN, Tag_End);
    503 
    504 		if (incore == False)
    505 			tgt_node_free(params);
    506 	}
    507 	tgt_buf_add_tag(msg, XML_ELEMENT_LUNINFO, Tag_End);
    508 }
    509