/* * []---- * | add_targets -- add TargetName and TargetAddress to text argument * | * | Add targets which this initiator is allowed to see based on * | the access_list associated with a target. If a target doesn't * | have an access list then let everyone see it. * []---- */ static Boolean_t add_targets(iscsi_conn_t *c, char **text, int *text_length) { tgt_node_t *targ = NULL; Boolean_t rval = True; char *targ_name = NULL; while ((rval == True) && ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, targ)) != NULL)) { if (check_access(targ, c->c_sess->s_i_name, False) == True) { if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &targ_name) == False) { rval = False; break; } queue_prt(c->c_mgmtq, Q_CONN_LOGIN, "CON%x %24s = %s\n", c->c_num, "TargetName", targ_name); (void) add_text(text, text_length, "TargetName", targ_name); free(targ_name); add_target_address(c, text, text_length, targ); } } return (rval); }
/* * Perform operation on all targets */ static int isns_op_all(uint16_t op) { int so; tgt_node_t *tgt = NULL; char *iname; if (isns_server_connection_thr_running == False) { syslog(LOG_ERR, "isns_op_all: iSNS discovery is not running." " Check the previous iSNS initialization error."); return (-1); } if ((so = isns_open(isns_args.server)) == -1) { syslog(LOG_ERR, "isns_op_all: failed to open isns server %s", isns_args.server); return (-1); } while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &iname) == FALSE) { continue; } switch (op) { case ISNS_DEV_DEREG: if (isns_dev_attr_dereg(so, iname) == -1) { syslog(LOG_ERR, "ISNS de-register failed\n"); } num_reg = 0; break; case ISNS_SCN_DEREG: if (isns_scn_dereg(so, iname) == -1) { syslog(LOG_ERR, "ISNS SCN de-register failed\n"); } break; case ISNS_SCN_REG: if (isns_scn_reg(so, iname) == -1) { syslog(LOG_ERR, "ISNS SCN register failed\n"); } break; case ISNS_TGT_LOGOUT: logout_targ(iname); break; default: break; } free(iname); } isns_close(so); return (0); }
/* * []---- * | convert_local_tpgt -- Convert a local tpgt name to real addresses * | * | To simplify the configuration files targets only have a target portal * | group tag string(s) associated. In the main configuration file there's * | a tpgt element which has one or more ip-address elements. So the tag * | is located and the actual data is inserted into the outgoing stream. * []---- */ static Boolean_t convert_local_tpgt(char **text, int *text_length, char *local_tpgt) { tgt_node_t *tpgt = NULL; tgt_node_t *x; char buf[80]; char ipaddr[4]; while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tpgt)) != NULL) { if (strcmp(tpgt->x_value, local_tpgt) == 0) { /* * The only children of the tpgt element are * ip-address elements. The value of each element is * the string we need to use. So, we don't need to * check the node's name to see if this is correct or * not. */ if ((tpgt = tgt_node_next(tpgt, XML_ELEMENT_IPADDRLIST, NULL)) == NULL) { return (False); } x = NULL; while ((x = tgt_node_next(tpgt, XML_ELEMENT_IPADDR, x)) != NULL) { if (inet_pton(AF_INET, x->x_value, &ipaddr) == 1) { /* * Valid IPv4 address */ (void) snprintf(buf, sizeof (buf), "%s,%s", x->x_value, local_tpgt); } else { /* * Invalid IPv4 address * try with brackets (RFC2732) */ (void) snprintf(buf, sizeof (buf), "[%s],%s", x->x_value, local_tpgt); } (void) add_text(text, text_length, "TargetAddress", buf); } break; } } return (True); }
static tgt_node_t * find_next_tgt(tgt_node_t *tgt, char **iname) { while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname) == FALSE) { continue; } return (tgt); } return (NULL); }
/*ARGSUSED*/ char * update_basedir(char *name, char *prop) { tgt_node_t *targ = NULL; char *msg = NULL; char *v; if ((prop == NULL) || (strlen(prop) == 0) || (prop[0] != '/')) { xml_rtn_msg(&msg, ERR_INVALID_BASEDIR); return (msg); } while ((targ = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, targ)) != NULL) { /* * Traverse the list of configured targets, serching for any * target that is using the current base-directory. Fail the * update if found. * * The only targets that do not use the base-directory at this * time are those targets persisted in ZFS. */ if (tgt_find_attr_str(targ, XML_ELEMENT_INCORE, &v) == True) { if (v != NULL) { if (strcmp(v, XML_VALUE_TRUE) == 0) { free(v); continue; } free(v); } } /* * Found at least one target, so fail */ xml_rtn_msg(&msg, ERR_VALID_TARG_EXIST); return (msg); } if (target_basedir) { free(target_basedir); } target_basedir = strdup(prop); if ((mkdir(target_basedir, 0700) != 0) && (errno != EEXIST)) { xml_rtn_msg(&msg, ERR_CREATE_TARGET_DIR_FAILED); free(target_basedir); target_basedir = NULL; } return (msg); }
/* * []---- * | find_main_tpgt -- Looks up the IP address and finds a match TPGT * | * | If no TPGT for this address exists the routine returns 0 which * | is an illegal TPGT value. * []---- */ static int find_main_tpgt(struct sockaddr_storage *pst) { char ip_addr[16]; tgt_node_t *tpgt = NULL; tgt_node_t *ip_node = NULL; struct in_addr addr; struct in6_addr addr6; /* * Hardly can you believe that such struct-to-struct * assignment IS valid. */ addr = ((struct sockaddr_in *)pst)->sin_addr; addr6 = ((struct sockaddr_in6 *)pst)->sin6_addr; while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tpgt)) != NULL) { ip_node = NULL; while ((ip_node = tgt_node_next(tpgt, XML_ELEMENT_IPADDR, ip_node)) != NULL) { if (pst->ss_family == AF_INET) { if (inet_pton(AF_INET, ip_node->x_value, ip_addr) != 1) { continue; } if (bcmp(ip_addr, &addr, sizeof (struct in_addr)) == 0) { return (atoi(tpgt->x_value)); } } else if (pst->ss_family == AF_INET6) { if (inet_pton(AF_INET6, ip_node->x_value, ip_addr) != 1) { continue; } if (bcmp(ip_addr, &addr6, sizeof (struct in6_addr)) == 0) { return (atoi(tpgt->x_value)); } } } } return (0); }
/* * []---- * | add_target_address -- find and add any target address information * []---- */ static void add_target_address(iscsi_conn_t *c, char **text, int *text_length, tgt_node_t *targ) { tgt_node_t *tpgt_list; tgt_node_t *tpgt = NULL; struct sockaddr_in *sp4; struct sockaddr_in6 *sp6; /* * 7 is enough room for the largest TPGT of "65536", the ',' and a NULL */ char buf[INET6_ADDRSTRLEN + 7]; char net_buf[INET6_ADDRSTRLEN]; if ((tpgt_list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL)) == NULL) { if_target_address(text, text_length, (struct sockaddr *)&c->c_target_sockaddr); return; } while ((tpgt = tgt_node_next_child(tpgt_list, XML_ELEMENT_TPGT, tpgt)) != NULL) { if (convert_local_tpgt(text, text_length, tpgt->x_value) == False) { if (c->c_target_sockaddr.ss_family == AF_INET) { sp4 = (struct sockaddr_in *) &c->c_target_sockaddr; (void) snprintf(buf, sizeof (buf), "%s,%s", inet_ntop(sp4->sin_family, (void *)&sp4->sin_addr, net_buf, sizeof (net_buf)), tpgt->x_value); } else { sp6 = (struct sockaddr_in6 *) &c->c_target_sockaddr; (void) snprintf(buf, sizeof (buf), "[%s],%s", inet_ntop(sp6->sin6_family, (void *)&sp6->sin6_addr, net_buf, sizeof (net_buf)), tpgt->x_value); } (void) add_text(text, text_length, "TargetAddress", buf); } } }
/* * Just checking the existance of the given target. Here we check whether * both zfs and iscsitarget aware of the given target/volume. It neither * care about the credentials nor SHAREISCSI properties. */ static char * validate_zfs_iscsitgt(tgt_node_t *x) { char *msg = NULL; char *prop = NULL; char *dataset = NULL; libzfs_handle_t *zh = NULL; zfs_handle_t *zfsh = NULL; tgt_node_t *n = NULL; if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); return (msg); } if (((zh = libzfs_init()) == NULL) || ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_DATASET)) == NULL)) { xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); goto error; } while ((n = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, n)) != NULL) { if (strcmp(n->x_value, dataset) == 0) break; } if (n == NULL) { xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); goto error; } xml_rtn_msg(&msg, ERR_SUCCESS); error: if (zfsh) zfs_close(zfsh); if (prop) free(prop); if (zh) libzfs_fini(zh); if (dataset) free(dataset); return (msg); }
/* * []---- * | find_target_node -- given a target IQN name, return the XML node * []---- */ tgt_node_t * find_target_node(char *targ_name) { tgt_node_t *tnode = NULL; char *iname; while ((tnode = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tnode)) != NULL) { if (tgt_find_value_str(tnode, XML_ELEMENT_INAME, &iname) == True) { if (strcmp(iname, targ_name) == 0) { free(iname); return (tnode); } else free(iname); } } return (NULL); }
/* * find_tgt_by_name searches DB by iscsi name or local name, if found * returns tgt_node_t. iname needs to be free by caller. */ static tgt_node_t * find_tgt_by_name(char *targ, char **iname) { tgt_node_t *tgt = NULL; while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, iname) == FALSE) { syslog(LOG_ALERT, "ISNS: Missing iscsi name\n"); break; } /* match either iscsi name or local name */ if (strcmp(targ, tgt->x_value) == 0 || strcmp(targ, *iname) == 0) { return (tgt); } free(*iname); } return (NULL); }
/* * []---- * | check_access -- see if the requesting initiator is in the ACL * | * | Optionally will also check to see if this initiator requires * | authentication. * []---- */ Boolean_t check_access(tgt_node_t *targ, char *initiator_name, Boolean_t req_chap) { tgt_node_t *acl; tgt_node_t *inode = NULL; tgt_node_t *tgt_initiator = NULL; char *dummy; Boolean_t valid = False; Boolean_t found_chap = False; Boolean_t access = False; /* * If ISNS is enable check for access privilege from isns server */ if (isns_enabled() == True) { if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &dummy) == False) { return (False); } access = isns_qry_initiator(dummy, initiator_name); free(dummy); if (req_chap == False) { return (access); } /* Need to check if CHAP is needed for initiator */ while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, inode)) != NULL) { if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy) == True) { if (strcmp(dummy, initiator_name) == 0) { free(dummy); if (tgt_find_value_str(inode, XML_ELEMENT_CHAPSECRET, &dummy) == True) { free(dummy); found_chap = True; break; } } } } if (access == True) { if ((req_chap == True) && (found_chap == True)) access = False; } return (access); } /* * If there's no ACL for this target everyone has access. */ if ((acl = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == NULL) return (True); /* * Find the local initiator name and also save the knowledge * if the initiator had a CHAP secret. */ inode = NULL; while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, inode)) != NULL) { if (tgt_find_value_str(inode, XML_ELEMENT_INAME, &dummy) == True) { if (strcmp(dummy, initiator_name) == 0) { free(dummy); if (tgt_find_value_str(inode, XML_ELEMENT_CHAPSECRET, &dummy) == True) { free(dummy); found_chap = True; } break; } else { free(dummy); } } } if ((acl != NULL) && (inode == NULL)) return (False); while ((tgt_initiator = tgt_node_next(acl, XML_ELEMENT_INIT, tgt_initiator)) != NULL) { if (strcmp(inode->x_value, tgt_initiator->x_value) == 0) { valid = True; break; } } if (valid == True) { /* * If req_chap is True it means the login code hasn't gone * through the authentication phase and it's trying to * determine if the initiator should have done so. If * we find a CHAP-secret then this routine will fail. * No CHAP-secret for an initiator just means that a * simple ACL list is used. This can be spoofed easily * enough and is mainly used to limit the number of * targets an initiator would see. */ if ((req_chap == True) && (found_chap == True)) valid = False; } return (valid); }
/* * Find ip-addr associated with TPGT, don't send if no ip-addr is * found for a TPGT */ static int append_tpgt(tgt_node_t *tgt, isns_pdu_t *cmd) { tgt_node_t *t, *x; tgt_node_t *pgt = NULL; tgt_node_t *iplist = NULL; tgt_node_t *tpgt = NULL; ip_t eid; /* Always add the default TPGT (1) */ (void) isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, ISNS_PG_TAG_SZ, NULL, 1); if (isns_append_attr(cmd, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, eid_ip.ip_len) != 0) { return (-1); } if (isns_append_attr(cmd, ISNS_PG_PORTAL_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, iscsi_port) != 0) { return (-1); } /* Get the remainning TPGT-LIST */ if ((t = tgt_node_next(tgt, XML_ELEMENT_TPGTLIST, NULL)) != NULL) { /* find tgpt from tpgt-list */ while ((pgt = tgt_node_next(t, XML_ELEMENT_TPGT, pgt)) != NULL) { /* update isns only if TPGT contains ip_addr */ while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tpgt)) != NULL) { if (strcmp(pgt->x_value, tpgt->x_value) != 0) continue; if ((iplist = tgt_node_next(tpgt, XML_ELEMENT_IPADDRLIST, NULL)) != NULL) break; } if (tpgt == NULL || iplist == NULL) continue; if (isns_append_attr(cmd, ISNS_PG_TAG_ATTR_ID, ISNS_PG_TAG_SZ, NULL, strtol(pgt->x_value, NULL, 0)) != 0) { return (-1); } /* get ip-addr & port */ for (x = iplist->x_child; x; x = x->x_sibling) { if (get_ip_addr(x->x_value, &eid) < 0) continue; if (isns_append_attr(cmd, ISNS_PG_PORTAL_IP_ADDR_ATTR_ID, eid.ai_addrlen, (void *)&eid.ip_adr, eid.ip_len) != 0) { return (-1); } if (isns_append_attr(cmd, ISNS_PG_PORTAL_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, iscsi_port) != 0) { return (-1); } } } } return (0); }
/* * Register all iscsi target nodes from the XML database * Alway use the ISNS_FLAG_REPLACE_REG flag */ int isns_reg_all() { int so; uint32_t flags = ISNS_FLAG_REPLACE_REG; isns_pdu_t *cmd = NULL; isns_rsp_t *rsp = NULL; char *n = NULL; char *a = NULL; char alias[MAXNAMELEN]; char iname[MAXNAMELEN]; tgt_node_t *tgt = NULL; int ret = -1; int tgt_cnt = 0; if (isns_server_connection_thr_running == False) { syslog(LOG_ERR, "isns_reg_all: iSNS discovery is not running." " Check the previous iSNS initialization error."); return (-1); } /* * get the 1st target and use it for the source attribute */ if ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt)) == NULL) { return (0); } if (tgt->x_value == NULL) { syslog(LOG_ALERT, "ISNS: target with NULL local name\n"); return (-1); } if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n) == FALSE) { syslog(LOG_ALERT, "ISNS: no XML_ELEMENT_INAME found\n"); return (-1); } (void) strcpy(iname, n); free(n); if ((so = isns_open(isns_args.server)) == -1) { syslog(LOG_ALERT, "ISNS: fails to connect to %s\n", isns_args.server); return (-1); } if (isns_create_pdu(ISNS_DEV_ATTR_REG, flags, &cmd) != 0) { goto error; } /* source attribute */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(iname), iname, 0) != 0) { goto error; } /* add message key attribute */ if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { goto error; } /* add delimiter */ if (isns_append_attr(cmd, ISNS_DELIMITER_ATTR_ID, 0, NULL, 0) != 0) { goto error; } /* entity id */ if (isns_append_attr(cmd, ISNS_EID_ATTR_ID, STRLEN(isns_args.entity), isns_args.entity, 0) != 0) { goto error; } /* entity type */ if (isns_append_attr(cmd, ISNS_ENTITY_PROTOCOL_ATTR_ID, ISNS_ENTITY_TYP_SZ, NULL, ISNS_ENTITY_PROTOCOL_ISCSI) != 0) { goto error; } /* portal ip-addr */ if (isns_append_attr(cmd, ISNS_PORTAL_IP_ADDR_ATTR_ID, eid_ip.ai_addrlen, (void *)&eid_ip.ip_adr, eid_ip.ip_len) != 0) { goto error; } /* portal port */ if (isns_append_attr(cmd, ISNS_PORTAL_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, iscsi_port) != 0) { goto error; } /* ESI interval */ if (isns_append_attr(cmd, ISNS_ESI_INTERVAL_ATTR_ID, ISNS_ESI_TICK_SZ, NULL, 10) != 0) { goto error; } /* scn port */ if (isns_append_attr(cmd, ISNS_SCN_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, scn_port) != 0) { goto error; } /* esi port */ if (isns_append_attr(cmd, ISNS_ESI_PORT_ATTR_ID, ISNS_PORT_SZ, NULL, scn_port) != 0) { goto error; } /* * Open targets_config and devAttrReg all nodes */ tgt = NULL; while ((tgt = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, tgt)) != NULL) { if (tgt->x_value == NULL) { syslog(LOG_ALERT, "ISNS: target with NULL name\n"); continue; } /* use this value as alias if alias is not set */ (void) strcpy(alias, tgt->x_value); if (tgt_find_value_str(tgt, XML_ELEMENT_INAME, &n) == FALSE) { continue; } (void) strcpy(iname, n); free(n); /* find alias */ if (tgt_find_value_str(tgt, XML_ELEMENT_ALIAS, &a) == TRUE) { (void) strcpy(alias, a); free(a); } tgt_cnt++; /* increment target count */ /* operation attributes */ if (isns_append_attr(cmd, ISNS_ISCSI_NAME_ATTR_ID, STRLEN(iname), iname, 0) != 0) { goto error; } if (isns_append_attr(cmd, ISNS_ISCSI_NODE_TYPE_ATTR_ID, 4, NULL, ISNS_TARGET_NODE_TYPE) != 0) { goto error; } if (isns_append_attr(cmd, ISNS_ISCSI_ALIAS_ATTR_ID, STRLEN(alias), alias, 0) != 0) { goto error; } if (append_tpgt(tgt, cmd) != 0) { goto error; } } /* send pdu */ if (isns_send(so, cmd) == -1) { goto error; } /* get isns response */ if (isns_recv(so, &rsp) == -1) { goto error; } /* process response */ if (process_rsp(cmd, rsp) == 0) { ret = 0; num_reg = tgt_cnt; queue_prt(mgmtq, Q_ISNS_DBG, "DevAttrRegAll successful"); } else { syslog(LOG_ALERT, "DevAttrReg failed"); } error: if (cmd) isns_free_pdu(cmd); if (rsp) isns_free_pdu(rsp); isns_close(so); return (ret); }
/* * []---- * | modify_target -- updates one or more properties for a target * []---- */ static char * modify_target(tgt_node_t *x, ucred_t *cred) { char *msg = NULL; char *name = NULL; char iscsi_path[MAXPATHLEN]; char targ_name[64]; char *iscsi = NULL; char *prop = NULL; char path[MAXPATHLEN]; char *m; char buf[512]; /* one sector size block */ tgt_node_t *t = NULL; tgt_node_t *list = NULL; tgt_node_t *c = NULL; tgt_node_t *node = NULL; tgt_node_t *tpgt = NULL; Boolean_t change_made = False; int lun = 0; int fd; uint64_t val, new_lu_size, cur_lu_size; struct stat st; uint32_t isns_mods = 0; (void) pthread_rwlock_wrlock(&targ_config_mutex); if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); goto error; } while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t)) != NULL) { if (strcmp(t->x_value, name) == 0) { break; } } if (t == NULL) { free(name); xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); goto error; } if (tgt_find_attr_str(t, XML_ELEMENT_INCORE, &m) == True) { if (strcmp(m, "true") == 0) { free(m); free(name); (void) pthread_rwlock_unlock(&targ_config_mutex); return (modify_zfs(x, cred)); } free(m); } /* * Under base dir, file 'target name' is a symbolic link * to the real directory 'IQN name' which stores params and back * storage. Therefore we can easily get IQN name from target * name by read the symbolic link content. */ (void) snprintf(path, sizeof (path), "%s/%s", target_basedir, name); bzero(iscsi_path, sizeof (iscsi_path)); (void) readlink(path, iscsi_path, sizeof (iscsi_path)); iscsi = basename(iscsi_path); /* ---- Finished with these so go ahead and release the memory ---- */ (void) strncpy(targ_name, name, sizeof (targ_name)); free(name); /* * Grow the LU. We currently do not support shrinking the LU and * that is only because it's unknown if any applications could support * that type of data loss. To support shrinking all that would be * needed is to remove the new/old size check and perform a truncation. * The actually truncation request should be shipped off to the T10 * layer so that the LU thread can remap the smaller size without * anyone accessing the data. */ if (tgt_find_value_str(x, XML_ELEMENT_SIZE, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); goto error; } if (strtoll_multiplier(prop, &new_lu_size) == False) { free(prop); xml_rtn_msg(&msg, ERR_INVALID_SIZE); goto error; } free(prop); if ((new_lu_size % 512LL) != 0) { xml_rtn_msg(&msg, ERR_SIZE_MOD_BLOCK); goto error; } new_lu_size /= 512LL; /* ---- default to LUN 0 ---- */ (void) tgt_find_value_int(x, XML_ELEMENT_LUN, &lun); /* ---- read in current parameters ---- */ if (mgmt_get_param(&node, targ_name, lun) == False) { xml_rtn_msg(&msg, ERR_OPEN_PARAM_FILE_FAILED); goto error; } /* ---- validate that we're indeed growing the LU ---- */ if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &prop) == False) { xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); goto error; } if (strtoll_multiplier(prop, &cur_lu_size) == False) { free(prop); xml_rtn_msg(&msg, ERR_INVALID_SIZE); goto error; } free(prop); if (new_lu_size < cur_lu_size) { xml_rtn_msg(&msg, ERR_CANT_SHRINK_LU); goto error; } /* ---- check that this LU is of type 'disk' or 'tape' ---- */ if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &prop) == False) { xml_rtn_msg(&msg, ERR_INIT_XML_READER_FAILED); goto error; } if ((strcmp(prop, TGT_TYPE_DISK) != 0) && (strcmp(prop, TGT_TYPE_TAPE) != 0)) { xml_rtn_msg(&msg, ERR_RESIZE_WRONG_DTYPE); free(prop); goto error; } free(prop); /* ---- validate the backing store is a regular file ---- */ (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, iscsi, LUNBASE, lun); if (stat(path, &st) == -1) { xml_rtn_msg(&msg, ERR_STAT_BACKING_FAILED); goto error; } if ((st.st_mode & S_IFMT) != S_IFREG) { xml_rtn_msg(&msg, ERR_DISK_BACKING_MUST_BE_REGULAR_FILE); goto error; } /* ---- update the parameter node with new size ---- */ if ((c = tgt_node_alloc(XML_ELEMENT_SIZE, Uint64, &new_lu_size)) == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_replace(node, c, MatchName); tgt_node_free(c); /* ---- now update params file ---- */ (void) mgmt_param_save2scf(node, targ_name, lun); /* ---- grow lu backing store ---- */ (void) snprintf(path, sizeof (path), "%s/%s/%s%d", target_basedir, iscsi, LUNBASE, lun); if ((fd = open(path, O_RDWR|O_CREAT|O_LARGEFILE, 0600)) < 0) { xml_rtn_msg(&msg, ERR_LUN_NOT_FOUND); goto error; } (void) lseek(fd, (new_lu_size * 512LL) - 512LL, 0); bzero(buf, sizeof (buf)); if (write(fd, buf, sizeof (buf)) != sizeof (buf)) { xml_rtn_msg(&msg, ERR_LUN_NOT_GROWN); (void) close(fd); goto error; } (void) close(fd); /* ---- send updates to current initiators via ASC/ASCQ ---- */ iscsi_capacity_change(iscsi, lun); prop = NULL; tgt_node_free(node); node = NULL; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); goto error; } /* * Validate that the Target Portal Group Tag is reasonable. */ val = strtoll(prop, &m, 0); if ((val < TPGT_MIN) || (val > TPGT_MAX) || ((m != NULL) && (*m != '\0'))) { xml_rtn_msg(&msg, ERR_INVALID_TPGT); free(prop); goto error; } /* update isns only if TPGT contains ip_addr */ tpgt = NULL; while ((tpgt = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tpgt)) != NULL) { if (strcmp(prop, tpgt->x_value) != 0) continue; if (tgt_node_next(tpgt, XML_ELEMENT_IPADDR, NULL) != NULL) { isns_mods |= ISNS_MOD_TPGT; break; } else { xml_rtn_msg(&msg, ERR_TPGT_NO_IPADDR); free(prop); goto error; } } if ((c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) == NULL) { free(prop); xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL)) != NULL) { tgt_node_replace(list, c, MatchBoth); /* * tgt_node_replace will duplicate the child node * tgt_node_add which is used below just links it * into the tree. */ tgt_node_free(c); } else { list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); if (list == NULL) { free(prop); xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(list, c); tgt_node_add(t, list); } free(prop); prop = NULL; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); goto error; } c = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); if (c == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); free(prop); goto error; } if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL)) != NULL) { tgt_node_replace(list, c, MatchBoth); /* ---- See above usage ---- */ tgt_node_free(c); } else { list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); free(prop); goto error; } tgt_node_add(list, c); tgt_node_add(t, list); } free(prop); prop = NULL; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_ALIAS, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ALIAS); goto error; } if (modify_element(XML_ELEMENT_ALIAS, prop, t, MatchName) == False) { xml_rtn_msg(&msg, ERR_NO_MEM); free(prop); goto error; } free(prop); prop = NULL; isns_mods |= ISNS_MOD_ALIAS; change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_MAXRECV, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_MAXRECV); goto error; } if ((strtoll_multiplier(prop, &val) == False) || (val < MAXRCVDATA_MIN) || (val > MAXRCVDATA_MAX)) { free(prop); xml_rtn_msg(&msg, ERR_INVALID_MAXRECV); goto error; } free(prop); if ((prop = malloc(32)) == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } (void) snprintf(prop, 32, "%d", val); if (modify_element(XML_ELEMENT_MAXRECV, prop, t, MatchName) == False) { free(prop); xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } free(prop); prop = NULL; change_made = True; } if (change_made == True) { if (mgmt_config_save2scf() == False) { xml_rtn_msg(&msg, ERR_UPDATE_TARGCFG_FAILED); goto error; } if (isns_enabled() == True) { if (isns_dev_update(t->x_value, isns_mods) != 0) { xml_rtn_msg(&msg, ERR_ISNS_ERROR); goto error; } } xml_rtn_msg(&msg, ERR_SUCCESS); } else { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); } error: (void) pthread_rwlock_unlock(&targ_config_mutex); if (node) tgt_node_free(node); return (msg); }
static int showStats(int operandLen, char *operand[], cmdOptions_t *options) { char *first_str = NULL; char scale_buf[16]; tgt_node_t *node, *n1; int interval = -1; int count = -1; int header; stat_delta_t cur_data, *pd; tgt_buf_add_tag(&first_str, "list", Tag_Start); tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start); tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE); if (operandLen) tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); for (; options->optval; options++) { switch (options->optval) { case 0: break; case 'I': /* optarg = refresh interval */ interval = atoi(options->optarg); if (interval == 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("interval must be non-zero")); free(first_str); return (1); } break; case 'N': count = atoi(options->optarg); if (count == 0) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("count must be non-zero")); free(first_str); return (1); } break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, options->optval, gettext("unknown option")); free(first_str); return (1); } } tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End); tgt_buf_add_tag(&first_str, "list", Tag_End); header = 1; /*CONSTANTCONDITION*/ while (1) { if (--header == 0) { (void) printf("%20s %12s %12s\n", " ", gettext("operations"), gettext("bandwidth ")); (void) printf("%-20s %5s %5s %5s %5s\n", gettext("device"), gettext("read"), gettext("write"), gettext("read"), gettext("write")); (void) printf("%-20s %5s %5s %5s %5s\n", "--------------------", "-----", "-----", "-----", "-----"); header = 20; } if ((node = tgt_door_call(first_str, 0)) == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("No reponse from daemon")); return (1); } if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Bad XML response")); free(first_str); tgt_node_free(node); stats_free(); return (1); } n1 = NULL; while (n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) { stats_load_counts(n1, &cur_data); if ((pd = stats_prev_counts(&cur_data)) == NULL) { free(first_str); tgt_node_free(node); return (1); } (void) printf("%-20s ", pd->device); (void) printf("%5s ", number_to_scaled_string(scale_buf, cur_data.read_cmds - pd->read_cmds, 1, 1024)); (void) printf("%5s ", number_to_scaled_string(scale_buf, cur_data.write_cmds - pd->write_cmds, 1, 1024)); (void) printf("%5s ", number_to_scaled_string(scale_buf, cur_data.read_blks - pd->read_blks, 512, 1024)); (void) printf("%5s\n", number_to_scaled_string(scale_buf, cur_data.write_blks - pd->write_blks, 512, 1024)); stats_update_counts(pd, &cur_data); } tgt_node_free(node); if (count == -1) { if (interval == -1) /* No count or internal, do it just once */ break; else (void) sleep(interval); } else if (--count) { if (interval == -1) break; else (void) sleep(interval); } else break; } stats_free(); free(first_str); return (0); }
/*ARGSUSED*/ static int showAdmin(int operandLen, char *operand[], cmdOptions_t *options) { char *first_str = NULL; tgt_node_t *node = NULL; tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ if (operand == NULL) return (1); tgt_buf_add_tag(&first_str, "list", Tag_Start); tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_Start); tgt_buf_add_tag(&first_str, XML_ELEMENT_ADMIN, Tag_End); tgt_buf_add_tag(&first_str, "list", Tag_End); if ((node = tgt_door_call(first_str, 0)) == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("No reponse from daemon")); return (1); } free(first_str); if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Bad XML response")); return (1); } (void) printf("%s:\n", cmdName); n1 = tgt_node_next_child(node, XML_ELEMENT_ADMIN, NULL); if (n1 == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Bad XML response")); return (1); } n2 = tgt_node_next_child(n1, XML_ELEMENT_BASEDIR, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("Base Directory"), n2 ? n2->x_value : gettext("Not set")); n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"), n2 ? n2->x_value : gettext("Not set")); n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_ACCESS, NULL); (void) printf("%s%s: ", dospace(1), gettext("RADIUS Access")); if (n2) { if (strcmp(n2->x_value, OPT_TRUE) == 0) (void) printf("%s\n", gettext("Enabled")); else (void) printf("%s\n", gettext("Disabled")); } else (void) printf("%s\n", gettext("Not set")); n2 = tgt_node_next_child(n1, XML_ELEMENT_RAD_SERV, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("RADIUS Server"), n2 ? n2->x_value : gettext("Not set")); n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_ACCESS, NULL); (void) printf("%s%s: ", dospace(1), gettext("iSNS Access")); if (n2) { if (strcmp(n2->x_value, OPT_TRUE) == 0) (void) printf("%s\n", gettext("Enabled")); else (void) printf("%s\n", gettext("Disabled")); } else (void) printf("%s\n", gettext("Not set")); n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERV, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("iSNS Server"), n2 ? n2->x_value : gettext("Not set")); n2 = tgt_node_next_child(n1, XML_ELEMENT_ISNS_SERVER_STATUS, NULL); if (n2) { /* * if NULL, that means either the isns discovery is * disabled or the server address is not set. */ if (n2->x_value != NULL) { (void) printf("%s%s: ", dospace(1), gettext("iSNS Server Status")); (void) printf("%s\n", n2->x_value); } } n2 = tgt_node_next_child(n1, XML_ELEMENT_FAST, NULL); (void) printf("%s%s: ", dospace(1), gettext("Fast Write ACK")); if (n2) { if (strcmp(n2->x_value, OPT_TRUE) == 0) (void) printf("%s\n", gettext("Enabled")); else (void) printf("%s\n", gettext("Disabled")); } else (void) printf("%s\n", gettext("Not set")); return (0); }
static int listTpgt(int operandLen, char *operand[], cmdOptions_t *options) { char *first_str = NULL; tgt_node_t *node = NULL; tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ cmdOptions_t *optionList = options; Boolean_t verbose = False; int addrs; if (operand == NULL) return (1); tgt_buf_add_tag(&first_str, "list", Tag_Start); tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_Start); if (operandLen) tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); if (optionList) { switch (optionList->optval) { case 0: /* no options, treat as --verbose */ break; case 'v': verbose = True; tgt_buf_add(&first_str, XML_ELEMENT_VERBOSE, OPT_TRUE); break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); free(first_str); return (1); } } tgt_buf_add_tag(&first_str, XML_ELEMENT_TPGT, Tag_End); tgt_buf_add_tag(&first_str, "list", Tag_End); if ((node = tgt_door_call(first_str, 0)) == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("No reponse from daemon")); return (1); } free(first_str); if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Bad XML response")); return (1); } n1 = NULL; while (n1 = tgt_node_next_child(node, XML_ELEMENT_TPGT, n1)) { (void) printf("%s: %s\n", gettext("TPGT"), n1->x_value); n2 = NULL; addrs = 0; while (n2 = tgt_node_next(n1, XML_ELEMENT_IPADDR, n2)) { if (verbose == True) (void) printf("%s%s: %s\n", dospace(1), gettext("IP Address"), n2 ? n2->x_value : gettext("Not set")); addrs++; } if (verbose == False) { (void) printf("%s%s: %d\n", dospace(1), gettext("IP Address count"), addrs); } else if (addrs == 0) { /* * Verbose is true, but there where no addresses * for this TPGT. To keep the output consistent * dump a "Not set" string out. */ (void) printf("%s%s: %s\n", dospace(1), gettext("IP Address"), gettext("Not set")); } } return (0); }
static int listInitiator(int operandLen, char *operand[], cmdOptions_t *options) { char *first_str = NULL; tgt_node_t *node; tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ Boolean_t verbose = False; cmdOptions_t *optionList = options; if (operand == NULL) return (1); tgt_buf_add_tag(&first_str, "list", Tag_Start); tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_Start); if (operandLen) { tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); } if (optionList) { switch (optionList->optval) { case 0: break; case 'v': verbose = True; tgt_buf_add(&first_str, XML_ELEMENT_VERBOSE, OPT_TRUE); break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, optionList->optval, gettext("unknown option")); free(first_str); return (1); } } tgt_buf_add_tag(&first_str, XML_ELEMENT_INIT, Tag_End); tgt_buf_add_tag(&first_str, "list", Tag_End); if ((node = tgt_door_call(first_str, 0)) == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("No reponse from daemon")); return (1); } free(first_str); if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Bad XML response")); return (1); } n1 = NULL; while (n1 = tgt_node_next_child(node, XML_ELEMENT_INIT, n1)) { (void) printf("%s: %s\n", gettext("Initiator"), n1->x_value); n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"), n2 ? n2->x_value : gettext("Not set")); n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPNAME, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Name"), n2 ? n2->x_value : gettext("Not set")); if (verbose == True) { n2 = tgt_node_next_child(n1, XML_ELEMENT_CHAPSECRET, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("CHAP Secret"), n2 ? gettext("Set") : gettext("Not set")); } } return (0); }
/* * []---- * | modify_initiator -- store the CHAP information for an initiator * []---- */ static char * modify_initiator(tgt_node_t *x) { char *msg = NULL; char *name = NULL; char *prop = NULL; tgt_node_t *inode = NULL; Boolean_t changes_made = False; (void) pthread_rwlock_wrlock(&targ_config_mutex); if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); goto error; } while ((inode = tgt_node_next_child(main_config, XML_ELEMENT_INIT, inode)) != NULL) { if (strcmp(inode->x_value, name) == 0) break; } /* * We no longer need the name since we should have found the node * it refers to and this way we don't have to worry about freeing * the storage later. */ free(name); if (inode == NULL) { xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); goto error; } if (tgt_find_value_str(x, XML_ELEMENT_CHAPSECRET, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPSECRET); goto error; } if (modify_element(XML_ELEMENT_CHAPSECRET, prop, inode, MatchName) == False) { free(prop); xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } free(prop); changes_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPSECRET, &prop) == True) { if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) { if (prop != NULL) free(prop); xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); goto error; } free(prop); if (delete_element(XML_ELEMENT_CHAPSECRET, inode, MatchName) == False) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } changes_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_CHAPNAME, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_CHAPNAME); goto error; } if (modify_element(XML_ELEMENT_CHAPNAME, prop, inode, MatchName) == False) { xml_rtn_msg(&msg, ERR_NO_MEM); free(prop); goto error; } free(prop); changes_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_DELETE_CHAPNAME, &prop) == True) { if (prop == NULL || strcmp(prop, XML_VALUE_TRUE) != 0) { if (prop != NULL) free(prop); xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); goto error; } free(prop); if (delete_element(XML_ELEMENT_CHAPNAME, inode, MatchName) == False) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } changes_made = True; } if (changes_made == True) { if (mgmt_config_save2scf() == True) { xml_rtn_msg(&msg, ERR_SUCCESS); } else { xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); } } else { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); } error: (void) pthread_rwlock_unlock(&targ_config_mutex); return (msg); }
/* * modify_zfs -- test for the existence of a certain dataset being shared * * Called when someone uses the iscsitgt_is_shared() function from libiscsitgt. * All that */ static char * modify_zfs(tgt_node_t *x, ucred_t *cred) { char *msg = NULL; char *dataset = NULL; char *prop; char *m; tgt_node_t *n = NULL; tgt_node_t *t = NULL; tgt_node_t *list = NULL; tgt_node_t *c1, *c2; Boolean_t change_made = False; uint64_t size; int status; int val; char *tru = "true"; (void) pthread_rwlock_wrlock(&targ_config_mutex); if (tgt_find_value_str(x, XML_ELEMENT_NAME, &dataset) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); goto error; } /* * Validate request */ if (tgt_find_value_str(x, XML_ELEMENT_VALIDATE, &tru)) { (void) pthread_rwlock_unlock(&targ_config_mutex); if (tru) free(tru); free(dataset); return (validate_zfs_iscsitgt(x)); } /* * Check for existance of ZFS shareiscsi properties */ status = get_zfs_shareiscsi(dataset, &n, &size, cred); if ((status != ERR_SUCCESS) && (status != ERR_NULL_XML_MESSAGE)) { xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); goto error; } while ((t = tgt_node_next_child(targets_config, XML_ELEMENT_TARG, t)) != NULL) { if (strcmp(t->x_value, dataset) == 0) break; } if (t == NULL) { xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); goto error; } if (tgt_find_value_str(x, XML_ELEMENT_TPGT, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_TPGT); goto error; } /* * Validate that the Target Portal Group Tag is reasonable. */ val = strtoll(prop, &m, 0); if ((val < TPGT_MIN) || (val > TPGT_MAX) || ((m != NULL) && (*m != '\0'))) { xml_rtn_msg(&msg, ERR_INVALID_TPGT); goto error; } if ((c1 = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop)) == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } /* * Due to the fact that the targets_config differs from the * ZVOL properties stored in zfs_shareiscsi, two lists need to * be updated */ c2 = tgt_node_dup(c1); if ((list = tgt_node_next(t, XML_ELEMENT_TPGTLIST, NULL)) != NULL) { /* * tgt_node_replace will duplicate the child node * tgt_node_add which is used below just links it * into the tree. */ tgt_node_replace(list, c1, MatchBoth); tgt_node_free(c1); } else { list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(list, c1); tgt_node_add(t, list); } if ((list = tgt_node_next(n, XML_ELEMENT_TPGTLIST, NULL)) != NULL) { /* * tgt_node_replace will duplicate the child node * tgt_node_add which is used below just links it * into the tree. */ tgt_node_replace(list, c2, MatchBoth); tgt_node_free(c2); } else { list = tgt_node_alloc(XML_ELEMENT_TPGTLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(list, c2); tgt_node_add(n, list); } change_made = True; } if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); goto error; } c1 = tgt_node_alloc(XML_ELEMENT_INIT, String, prop); if (c1 == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } /* * Due to the fact that the targets_config differs from the * ZVOL properties stored in zfs_shareiscsi, two lists need to * be updated */ c2 = tgt_node_dup(c1); if ((list = tgt_node_next(t, XML_ELEMENT_ACLLIST, NULL)) != NULL) { /* * tgt_node_replace will duplicate the child node * tgt_node_add which is used below just links it * into the tree. */ tgt_node_replace(list, c1, MatchBoth); tgt_node_free(c1); } else { list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(list, c1); tgt_node_add(t, list); } if ((list = tgt_node_next(n, XML_ELEMENT_ACLLIST, NULL)) != NULL) { /* * tgt_node_replace will duplicate the child node * tgt_node_add which is used below just links it * into the tree. */ tgt_node_replace(list, c2, MatchBoth); tgt_node_free(c2); } else { list = tgt_node_alloc(XML_ELEMENT_ACLLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(list, c2); tgt_node_add(n, list); } change_made = True; } if (change_made == True) { status = put_zfs_shareiscsi(dataset, n); if (status != ERR_SUCCESS) { xml_rtn_msg(&msg, status); goto error; } else { xml_rtn_msg(&msg, ERR_SUCCESS); } } else { xml_rtn_msg(&msg, ERR_SUCCESS); } error: if (n) tgt_node_free(n); if (dataset) free(dataset); (void) pthread_rwlock_unlock(&targ_config_mutex); return (msg); }
/* * []---- * | modify_tpgt -- add an IP-address to a target portal group * []---- */ static char * modify_tpgt(tgt_node_t *x) { struct addrinfo *res = NULL; char *msg = NULL; char *name = NULL; char *ip_str = NULL; tgt_node_t *tnode = NULL; tgt_node_t *list = NULL; (void) pthread_rwlock_wrlock(&targ_config_mutex); if (tgt_find_value_str(x, XML_ELEMENT_NAME, &name) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); goto error; } if (tgt_find_value_str(x, XML_ELEMENT_IPADDR, &ip_str) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_IPADDR); goto error; } if ((getaddrinfo(ip_str, NULL, NULL, &res) != 0) || (res == NULL)) { xml_rtn_msg(&msg, ERR_INVALID_IP); goto error; } while ((tnode = tgt_node_next_child(main_config, XML_ELEMENT_TPGT, tnode)) != NULL) { if (strcmp(tnode->x_value, name) == 0) break; } if (tnode == NULL) { xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); goto error; } if ((list = tgt_node_next(tnode, XML_ELEMENT_IPADDRLIST, NULL)) == NULL) { list = tgt_node_alloc(XML_ELEMENT_IPADDRLIST, String, ""); if (list == NULL) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } tgt_node_add(tnode, list); } if (modify_element(XML_ELEMENT_IPADDR, ip_str, list, MatchBoth) == False) { xml_rtn_msg(&msg, ERR_NO_MEM); goto error; } if (mgmt_config_save2scf() == True) { xml_rtn_msg(&msg, ERR_SUCCESS); } else { /* tpgt change should be updated to smf */ xml_rtn_msg(&msg, ERR_INTERNAL_ERROR); } /* * Re-register all targets, currently there's no method to * update TPGT for individual target */ if (isns_enabled() == True) { (void) isns_reg_all(); } error: if (name) free(name); if (ip_str) free(ip_str); if (res) freeaddrinfo(res); (void) pthread_rwlock_unlock(&targ_config_mutex); return (msg); }
/* * mgmt_get_main_config() loads main configuration * from scf into a node tree. * Main configuration includes: admin/target/tpgt/initiator info. * admin info is stored in "iscsitgt" property group * target info is stored in "target_<name>" property group * initiator info is stored in "initiator_<name>" property group * tpgt info is stored in "tpgt_<number>" property group */ Boolean_t mgmt_get_main_config(tgt_node_t **node) { targ_scf_t *h = NULL; scf_property_t *prop = NULL; scf_value_t *value = NULL; scf_iter_t *iter = NULL; scf_iter_t *iter_v = NULL; scf_iter_t *iter_pv = NULL; char pname[32]; char valuebuf[MAXPATHLEN]; char passcode[32]; unsigned int outlen; tgt_node_t *n; tgt_node_t *pn; tgt_node_t *vn; Boolean_t status = False; h = mgmt_handle_init(); if (h == NULL) return (status); prop = scf_property_create(h->t_handle); value = scf_value_create(h->t_handle); iter = scf_iter_create(h->t_handle); (void) pthread_mutex_lock(&scf_conf_mutex); /* Basic Information is stored in iscsitgt pg */ if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == -1) { goto error; } *node = NULL; *node = tgt_node_alloc("main_config", String, NULL); if (*node == NULL) goto error; if (scf_iter_pg_properties(iter, h->t_pg) == -1) { goto error; } while (scf_iter_next_property(iter, prop) > 0) { scf_property_get_value(prop, value); scf_value_get_as_string(value, valuebuf, MAXPATHLEN); scf_property_get_name(prop, pname, sizeof (pname)); /* avoid load auth to incore data */ if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) continue; n = tgt_node_alloc(pname, String, valuebuf); if (n == NULL) goto error; /* put version info into root node's attr */ if (strcmp(pname, XML_ELEMENT_VERS) == 0) { tgt_node_add_attr(*node, n); } else { /* add other basic info into root node */ tgt_node_add(*node, n); } } /* * targets/initiators/tpgt information is * stored as type "configuration" in scf * each target's param is stored as type "parameter" */ if (scf_iter_service_pgs_typed(iter, h->t_service, "configuration") == -1) { goto error; } while (scf_iter_next_pg(iter, h->t_pg) > 0) { char *iname; scf_pg_get_name(h->t_pg, pname, sizeof (pname)); iname = strchr(pname, '_'); if (iname == NULL) { /* the pg found here is not a tgt/initiator/tpgt */ continue; } *iname = '\0'; iname++; /* * now pname is "target" or "initiator" or "tpgt" * meanwhile iname is the actual name of the item */ n = tgt_node_alloc(pname, String, iname); if (n == NULL) goto error; iter_v = scf_iter_create(h->t_handle); if (scf_iter_pg_properties(iter_v, h->t_pg) == -1) { goto error; } while (scf_iter_next_property(iter_v, prop) > 0) { /* there may be many values in one property */ char *vname; scf_property_get_name(prop, pname, sizeof (pname)); /* avoid load auth to incore data */ if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) continue; vname = strstr(pname, "-list"); if (vname == NULL) { scf_property_get_value(prop, value); scf_value_get_as_string(value, valuebuf, MAXPATHLEN); pn = tgt_node_alloc(pname, String, valuebuf); if (pn == NULL) goto error; tgt_node_add(n, pn); } else { pn = tgt_node_alloc(pname, String, NULL); if (pn == NULL) goto error; tgt_node_add(n, pn); *vname = '\0'; iter_pv = scf_iter_create(h->t_handle); scf_iter_property_values(iter_pv, prop); while (scf_iter_next_value(iter_pv, value) > 0) { scf_value_get_as_string(value, valuebuf, MAXPATHLEN); vn = tgt_node_alloc(pname, String, valuebuf); if (vn == NULL) goto error; tgt_node_add(pn, vn); } scf_iter_destroy(iter_pv); iter_pv = NULL; } } tgt_node_add(*node, n); scf_iter_destroy(iter_v); iter_v = NULL; } /* chap-secrets are stored in "passwords" pgroup as "application" */ if (scf_service_get_pg(h->t_service, "passwords", h->t_pg) == 0) { if (scf_iter_pg_properties(iter, h->t_pg) == -1) { goto error; } while (scf_iter_next_property(iter, prop) > 0) { scf_property_get_value(prop, value); scf_value_get_as_string(value, valuebuf, MAXPATHLEN); scf_property_get_name(prop, pname, sizeof (pname)); /* avoid load auth to incore data */ if (strcmp(pname, ISCSI_READ_AUTHNAME) == 0 || strcmp(pname, ISCSI_MODIFY_AUTHNAME) == 0 || strcmp(pname, ISCSI_VALUE_AUTHNAME) == 0) continue; /* max length of decoded passwd is 16B */ sasl_decode64(valuebuf, strlen(valuebuf), passcode, sizeof (passcode), &outlen); if (strcmp(pname, "radius") == 0) { pn = tgt_node_alloc(XML_ELEMENT_RAD_SECRET, String, passcode); tgt_node_add(*node, pn); } else if (strcmp(pname, "main") == 0) { pn = tgt_node_alloc(XML_ELEMENT_CHAPSECRET, String, passcode); tgt_node_add(*node, pn); } else { /* find corresponding initiator */ n = NULL; while (n = tgt_node_next_child(*node, XML_ELEMENT_INIT, n)) { if (strcmp(pname + 2, n->x_value) != 0) continue; pn = tgt_node_alloc( XML_ELEMENT_CHAPSECRET, String, passcode); tgt_node_add(n, pn); } } } } status = True; error: if ((status != True) && (*node != NULL)) tgt_node_free(*node); (void) pthread_mutex_unlock(&scf_conf_mutex); if (iter_pv != NULL) scf_iter_destroy(iter_pv); if (iter_v != NULL) scf_iter_destroy(iter_v); scf_iter_destroy(iter); scf_value_destroy(value); scf_property_destroy(prop); mgmt_handle_fini(h); return (status); }
static int listTarget(int operandLen, char *operand[], cmdOptions_t *options) { char *first_str = NULL; tgt_node_t *node = NULL; tgt_node_t *n1 = NULL; /* pointer to node (depth=1) */ tgt_node_t *n2 = NULL; /* pointer to node (depth=2) */ tgt_node_t *n3 = NULL; /* pointer to node (depth=3) */ tgt_node_t *n4 = NULL; /* pointer to node (depth=4) */ int conns; char buf[32]; Boolean_t verbose = False; if (operand == NULL) return (1); tgt_buf_add_tag(&first_str, "list", Tag_Start); tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_Start); if (operandLen) tgt_buf_add(&first_str, XML_ELEMENT_NAME, operand[0]); /* * Always retrieve the iostats which will give us the * connection count information even if we're not doing * a verbose output. */ tgt_buf_add(&first_str, XML_ELEMENT_IOSTAT, OPT_TRUE); if (options) { switch (options->optval) { case 0: break; case 'v': tgt_buf_add(&first_str, XML_ELEMENT_LUNINFO, OPT_TRUE); verbose = True; break; default: (void) fprintf(stderr, "%s: %c: %s\n", cmdName, options->optval, gettext("unknown option")); free(first_str); return (1); } } tgt_buf_add_tag(&first_str, XML_ELEMENT_TARG, Tag_End); tgt_buf_add_tag(&first_str, "list", Tag_End); if ((node = tgt_door_call(first_str, 0)) == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("No reponse from daemon")); return (1); } free(first_str); if (strcmp(node->x_name, XML_ELEMENT_RESULT)) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Bad XML response")); return (1); } n1 = NULL; while ((n1 = tgt_node_next_child(node, XML_ELEMENT_TARG, n1)) != NULL) { (void) printf("%s: %s\n", gettext("Target"), n1->x_value); n2 = tgt_node_next_child(n1, XML_ELEMENT_INAME, NULL); (void) printf("%s%s: %s\n", dospace(1), gettext("iSCSI Name"), n2 ? n2->x_value : gettext("Not set")); if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_ALIAS, NULL)) != NULL) (void) printf("%s%s: %s\n", dospace(1), gettext("Alias"), n2->x_value); if ((n2 = tgt_node_next_child(n1, XML_ELEMENT_MAXRECV, NULL)) != NULL) (void) printf("%s%s: %s\n", dospace(1), gettext("MaxRecv"), n2->x_value); /* * Count the number of connections available. */ n2 = NULL; conns = 0; while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2)) conns++; (void) printf("%s%s: %d\n", dospace(1), gettext("Connections"), conns); if (verbose == False) continue; /* * Displaying the individual connections must be done * first when verbose is turned on because you'll notice * above that we've left the output hanging with a label * indicating connections are coming next. */ n2 = NULL; while (n2 = tgt_node_next_child(n1, XML_ELEMENT_CONN, n2)) { (void) printf("%s%s:\n", dospace(2), gettext("Initiator")); (void) printf("%s%s: %s\n", dospace(3), gettext("iSCSI Name"), n2->x_value); n3 = tgt_node_next_child(n2, XML_ELEMENT_ALIAS, NULL); (void) printf("%s%s: %s\n", dospace(3), gettext("Alias"), n3 ? n3->x_value : gettext("unknown")); } (void) printf("%s%s:\n", dospace(1), gettext("ACL list")); n2 = tgt_node_next_child(n1, XML_ELEMENT_ACLLIST, NULL); n3 = NULL; while (n3 = tgt_node_next_child(n2, XML_ELEMENT_INIT, n3)) { (void) printf("%s%s: %s\n", dospace(2), gettext("Initiator"), n3->x_value); } (void) printf("%s%s:\n", dospace(1), gettext("TPGT list")); n2 = tgt_node_next_child(n1, XML_ELEMENT_TPGTLIST, NULL); n3 = NULL; while (n3 = tgt_node_next_child(n2, XML_ELEMENT_TPGT, n3)) { (void) printf("%s%s: %s\n", dospace(2), gettext("TPGT"), n3->x_value); } (void) printf("%s%s:\n", dospace(1), gettext("LUN information")); n2 = tgt_node_next_child(n1, XML_ELEMENT_LUNINFO, NULL); n3 = NULL; while (n3 = tgt_node_next_child(n2, XML_ELEMENT_LUN, n3)) { (void) printf("%s%s: %s\n", dospace(2), gettext("LUN"), n3->x_value); n4 = tgt_node_next_child(n3, XML_ELEMENT_GUID, NULL); (void) printf("%s%s: %s\n", dospace(3), gettext("GUID"), n4 ? n4->x_value : gettext("unknown")); n4 = tgt_node_next_child(n3, XML_ELEMENT_VID, NULL); (void) printf("%s%s: %s\n", dospace(3), gettext("VID"), n4 ? n4->x_value : gettext("unknown")); n4 = tgt_node_next_child(n3, XML_ELEMENT_PID, NULL); (void) printf("%s%s: %s\n", dospace(3), gettext("PID"), n4 ? n4->x_value : gettext("unknown")); n4 = tgt_node_next_child(n3, XML_ELEMENT_DTYPE, NULL); (void) printf("%s%s: %s\n", dospace(3), gettext("Type"), n4 ? n4->x_value : gettext("unknown")); n4 = tgt_node_next_child(n3, XML_ELEMENT_SIZE, NULL); if (n4 && (strtol(n4->x_value, NULL, 0) != 0)) { (void) printf("%s%s: %s\n", dospace(3), gettext("Size"), number_to_scaled_string(buf, strtoll(n4->x_value, NULL, 0), 512, 1024)); } else { (void) printf("%s%s: %s\n", dospace(3), gettext("Size"), gettext("unknown")); } n4 = tgt_node_next_child(n3, XML_ELEMENT_BACK, NULL); if (n4) { (void) printf("%s%s: %s\n", dospace(3), gettext("Backing store"), n4->x_value); } n4 = tgt_node_next_child(n3, XML_ELEMENT_STATUS, NULL); (void) printf("%s%s: %s\n", dospace(3), gettext("Status"), n4 ? n4->x_value : gettext("unknown")); } } return (0); }