/* * convert_to_tpgt -- return a TPGT based on the target address * * If a target doesn't have a TPGT list then just return the default * value of 1. Otherwise determine which TPGT the target address is * part of and find that TPGT value in the list of TPGTs this target * is willing to expose. If the TPGT value is not found in the list * return zero which will break the connection. */ static int convert_to_tpgt(iscsi_conn_t *c, tgt_node_t *targ) { tgt_node_t *list; tgt_node_t *tpgt = NULL; int addr_tpgt, pos_tpgt; /* * If this target doesn't have a list of target portal group tags * just return the default which is 1. */ list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL); if (list == NULL) return (1); /* * If we don't find our IP in the general configuration list * we'll use the default value which is 1 according to RFC3720. */ addr_tpgt = find_main_tpgt(&(c->c_target_sockaddr)); while ((tpgt = tgt_node_next(list, XML_ELEMENT_TPGT, tpgt)) != NULL) { (void) tgt_find_value_int(tpgt, XML_ELEMENT_TPGT, &pos_tpgt); if (pos_tpgt == addr_tpgt) { return (addr_tpgt); } } return (0); }
static Boolean_t connection_parameters_get(iscsi_conn_t *c, char *targ_name) { tgt_node_t *targ, *alias; Boolean_t rval = False; if ((targ = find_target_node(targ_name)) != NULL) { if (check_access(targ, c->c_sess->s_i_name, False) == False) return (False); /* * Have a valid node for our target. Start looking * for connection oriented parameters. */ if ((c->c_tpgt = convert_to_tpgt(c, targ)) == 0) return (False); if ((alias = tgt_node_next(targ, XML_ELEMENT_ALIAS, NULL)) == NULL) { (void) tgt_find_value_str(targ, XML_ELEMENT_TARG, &c->c_targ_alias); } else { (void) tgt_find_value_str(alias, XML_ELEMENT_ALIAS, &c->c_targ_alias); } (void) tgt_find_value_int(targ, XML_ELEMENT_MAXCMDS, &c->c_maxcmdsn); rval = True; } return (rval); }
static int formatErrString(tgt_node_t *node) { int code = 0; int rtn = 0; char *msg = NULL; if (node == NULL) { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Unable to contact target daemon")); return (1); } if ((strcmp(node->x_name, XML_ELEMENT_ERROR) == 0) && (tgt_find_value_int(node, XML_ELEMENT_CODE, &code) == B_TRUE) && (tgt_find_value_str(node, XML_ELEMENT_MESSAGE, &msg) == B_TRUE)) { /* * 1000 is the success code, so we don't need to display * the success message. */ if (code != 1000) { (void) fprintf(stderr, "%s: %s %s\n", cmdName, gettext("Error"), msg); rtn = 1; } } else { (void) fprintf(stderr, "%s: %s\n", cmdName, gettext("Bad XML response")); rtn = 1; } if (msg) free(msg); return (rtn); }
/* * mgmt_convert_param() converts legacy params file of each LUN * to scf data. It will convert LUNs under one target each time. * Args: * dir - string of directory where param file is stored * tnode - node tree which contains to a target */ Boolean_t mgmt_convert_param(char *dir, tgt_node_t *tnode) { Boolean_t ret = False; char path[MAXPATHLEN]; int xml_fd = -1; int n; int lun_num; tgt_node_t *lun = NULL; tgt_node_t *params = NULL; xmlTextReaderPtr r; while ((lun = tgt_node_next(tnode, XML_ELEMENT_LUN, lun)) != NULL) { if ((tgt_find_value_int(lun, XML_ELEMENT_LUN, &lun_num)) == False) continue; (void) snprintf(path, sizeof (path), "%s/%s%d", dir, PARAMBASE, lun_num); if ((xml_fd = open(path, O_RDONLY)) < 0) continue; if ((r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0)) == NULL) continue; n = xmlTextReaderRead(r); while (n == 1) { if (tgt_node_process(r, ¶ms) == False) { break; } n = xmlTextReaderRead(r); } if (n < 0) { ret = False; break; } if (mgmt_param_save2scf(params, tnode->x_value, lun_num) != True) { ret = False; break; } else { backup(path, tnode->x_value); ret = True; } params = NULL; (void) close(xml_fd); xmlTextReaderClose(r); xmlFreeTextReader(r); } if (ret == False) syslog(LOG_ERR, "Converting target %s params failed", dir); return (ret); }
Boolean_t tgt_find_value_int(tgt_node_t *n, char *name, int *value) { tgt_node_t *c; if ((n == NULL) || (n->x_name == NULL)) return (False); if (strcmp(n->x_name, name) == 0) { if (n->x_value == NULL) return (False); *value = strtol(n->x_value, NULL, 0); return (True); } for (c = n->x_child; c; c = c->x_sibling) { if (tgt_find_value_int(c, name, value) == True) return (True); } return (False); }
static char * remove_target(tgt_node_t *x) { char *msg = NULL; char *prop = NULL; tgt_node_t *targ = NULL; tgt_node_t *list; tgt_node_t *c = NULL; Boolean_t change_made = False; int lun_num; if (tgt_find_value_str(x, XML_ELEMENT_NAME, &prop) == False) { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_NAME); return (msg); } while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ)) != NULL) { if (strcmp(targ->x_value, prop) == 0) break; } free(prop); if (targ == NULL) { xml_rtn_msg(&msg, ERR_TARG_NOT_FOUND); return (msg); } if (tgt_find_value_str(x, XML_ELEMENT_ACL, &prop) == True) { if (prop == NULL) { xml_rtn_msg(&msg, ERR_SYNTAX_EMPTY_ACL); return (msg); } if ((list = tgt_node_next(targ, XML_ELEMENT_ACLLIST, NULL)) == NULL) { free(prop); xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND); return (msg); } c = tgt_node_alloc(XML_ELEMENT_ACLINIT, String, prop); if (tgt_node_remove(list, c, MatchBoth) == False) { xml_rtn_msg(&msg, ERR_INIT_NOT_FOUND); goto error; } tgt_node_free(c); if (list->x_child == NULL) (void) tgt_node_remove(targ, list, MatchName); free(prop); 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); return (msg); } if ((list = tgt_node_next(targ, XML_ELEMENT_TPGTLIST, NULL)) == NULL) { free(prop); xml_rtn_msg(&msg, ERR_ACL_NOT_FOUND); return (msg); } c = tgt_node_alloc(XML_ELEMENT_TPGT, String, prop); if (tgt_node_remove(list, c, MatchBoth) == False) { xml_rtn_msg(&msg, ERR_TPGT_NOT_FOUND); goto error; } tgt_node_free(c); if (list->x_child == NULL) (void) tgt_node_remove(targ, list, MatchName); free(prop); /* update isns */ if (isns_enabled()) { if (isns_dev_update(targ->x_value, ISNS_MOD_TPGT) != 0) syslog(LOG_ALERT, "ISNS register failed\n"); } change_made = True; } if (tgt_find_value_int(x, XML_ELEMENT_LUN, &lun_num) == True) { if (tgt_find_value_intchk(x, XML_ELEMENT_LUN, &lun_num) == False) { xml_rtn_msg(&msg, ERR_LUN_INVALID_RANGE); return (msg); } /* * Save the iscsi-name which we'll need to remove LUNs. */ if (tgt_find_value_str(targ, XML_ELEMENT_INAME, &prop) == False) { xml_rtn_msg(&msg, ERR_TARGCFG_MISSING_INAME); return (msg); } logout_targ(prop); thick_provo_stop(prop, lun_num); remove_target_common(targ->x_value, lun_num, &msg); if (msg != NULL) goto error; /* ISNS de-register target if it's the last lun */ if (lun_num == 0 && isns_enabled() == True) { if (isns_dereg(prop) != 0) syslog(LOG_INFO, "ISNS dereg failed\n"); } iscsi_inventory_change(prop); free(prop); change_made = True; } if (change_made == True) { if (mgmt_config_save2scf() == True) xml_rtn_msg(&msg, ERR_SUCCESS); } else { xml_rtn_msg(&msg, ERR_SYNTAX_MISSING_OPERAND); } return (msg); error: if (c != NULL) tgt_node_free(c); if (prop != NULL) free(prop); return (msg); }
/* * []---- * | 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); }