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(¶ms, 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