Beispiel #1
0
Datei: xml.c Projekt: imp/slist
void
tgt_node_replace(tgt_node_t *parent, tgt_node_t *child, match_type_t m)
{
	tgt_node_t	*s;
	tgt_node_t	*c;

	if ((parent == NULL) || (child == NULL))
		return;

	for (s = parent->x_child; s; s = s->x_sibling) {

		/*
		 * See if the new child node matches one of the children
		 * in the parent.
		 */
		if ((strcmp(s->x_name, child->x_name) == 0) &&
		    ((m == MatchName) || (strcmp(s->x_value,
		    child->x_value) == 0))) {

			/*
			 * We have a match. Now save the values of the new
			 * child in this current node.
			 */
			free(s->x_name);
			free(s->x_value);
			s->x_name	= strdup(child->x_name);
			s->x_value	= strdup(child->x_value);
			if (s->x_child) {
				tgt_node_free(s->x_child);
				s->x_child = NULL;
			}
			for (c = child->x_child; c; c = c->x_sibling)
				(void) tgt_node_add(s, tgt_node_dup(c));
			break;
		}
	}

	if (s == NULL) {
		/*
		 * Never found the child so add it
		 */
		(void) tgt_node_add(parent, tgt_node_dup(child));
	}
}
Beispiel #2
0
Datei: xml.c Projekt: imp/slist
tgt_node_t *
tgt_node_dup(tgt_node_t *n)
{
	tgt_node_t	*d = node_alloc();
	tgt_node_t	*c;

	if (d == NULL)
		return (NULL);
	if (node_name(d, (xmlChar *)n->x_name) == False)
		return (NULL);
	if (n->x_value && (node_value(d, (xmlChar *)n->x_value, True) == False))
		return (NULL);
	for (c = n->x_child; c; c = c->x_sibling)
		(void) tgt_node_add(d, tgt_node_dup(c));
	for (c = n->x_attr; c; c = c->x_sibling)
		(void) tgt_node_add_attr(d, tgt_node_dup(c));
	return (d);
}
Beispiel #3
0
/*
 * this function tries to convert configuration in files into scf
 * it loads xml conf into node tree then dump them to scf with
 * mgmt_config_save2scf()
 * this function has 3 return values:
 * CONVERT_OK: successfully converted
 * CONVERT_INIT_NEW: configuration files dont exist, created a new scf entry
 * CONVERT_FAIL: some error occurred in conversion and no scf entry created.
 *               In this case, user have to check files manually and try
 *               conversion again.
 */
convert_ret_t
mgmt_convert_conf()
{
	targ_scf_t		*h = NULL;
	xmlTextReaderPtr	r;
	convert_ret_t		ret = CONVERT_FAIL;
	int			xml_fd = -1;
	int			n;
	tgt_node_t		*node = NULL;
	tgt_node_t		*next = NULL;
	char			path[MAXPATHLEN];
	char			*target = NULL;

	h = mgmt_handle_init();
	if (h == NULL)
		return (CONVERT_FAIL);

	/* check main config in pgroup iscsitgt */
	if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == 0) {
		ret = CONVERT_OK;
		goto done;
	}

	/* check the conf files */
	if (access(config_file, R_OK) != 0) {
		/*
		 * if there is no configuration file, initialize
		 * an empty scf entry
		 */
		if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
			ret = CONVERT_INIT_NEW;

			node = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0");
			new_property(h, node);
			tgt_node_free(node);
			/* "daemonize" is set to true by default */
			node = tgt_node_alloc(XML_ELEMENT_DBGDAEMON, String,
			    "true");
			new_property(h, node);
			tgt_node_free(node);
			node = NULL;
			node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
			    ISCSI_AUTH_MODIFY);
			new_property(h, node);
			tgt_node_free(node);
			node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
			    ISCSI_AUTH_VALUE);
			new_property(h, node);
			tgt_node_free(node);
			mgmt_transaction_end(h);
		} else {
			syslog(LOG_ERR, "Creating empty entry failed");
			ret = CONVERT_FAIL;
			goto done;
		}
		if (mgmt_transaction_start(h, "passwords", "application") ==
		    True) {
			node = tgt_node_alloc(ISCSI_READ_AUTHNAME, String,
			    ISCSI_AUTH_READ);
			new_property(h, node);
			tgt_node_free(node);
			node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
			    ISCSI_AUTH_MODIFY);
			new_property(h, node);
			tgt_node_free(node);
			node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
			    ISCSI_AUTH_VALUE);
			new_property(h, node);
			tgt_node_free(node);
			mgmt_transaction_end(h);
		} else {
			syslog(LOG_ERR, "Creating empty entry failed");
			ret = CONVERT_FAIL;
		}
		goto done;
	}

	if ((xml_fd = open(config_file, O_RDONLY)) >= 0)
		r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0);

	if (r != NULL) {
		n = xmlTextReaderRead(r);
		while (n == 1) {
			if (tgt_node_process(r, &node) == False) {
				break;
			}
			n = xmlTextReaderRead(r);
		}
		if (n < 0) {
			syslog(LOG_ERR, "Parsing main config failed");
			ret = CONVERT_FAIL;
			goto done;
		}

		main_config = node;

		(void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR,
		    &target_basedir);

		if (target_basedir == NULL)
			target_basedir = strdup(DEFAULT_TARGET_BASEDIR);

		/* Now convert targets' config if possible */
		if (xml_fd != -1)
			(void) close(xml_fd);
		xmlTextReaderClose(r);
		xmlFreeTextReader(r);
		xmlCleanupParser();
		r = NULL;
		xml_fd = -1;
		node = NULL;

		(void) snprintf(path, MAXPATHLEN, "%s/%s",
		    target_basedir, "config.xml");

		if ((xml_fd = open(path, O_RDONLY)) >= 0)
			r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd,
			    NULL, NULL, 0);

		if (r != NULL) {
			n = xmlTextReaderRead(r);
			while (n == 1) {
				if (tgt_node_process(r, &node) == False) {
					break;
				}
				n = xmlTextReaderRead(r);
			}
			if (n < 0) {
				syslog(LOG_ERR, "Parsing target conf failed");
				ret = CONVERT_FAIL;
				goto done;
			}

			/* now combine main_config and node */
			if (node) {
				next = NULL;
				while ((next = tgt_node_next(node,
				    XML_ELEMENT_TARG, next)) != NULL) {
					tgt_node_add(main_config,
					    tgt_node_dup(next));
				}
				tgt_node_free(node);
			}

			if (mgmt_config_save2scf() != True) {
				syslog(LOG_ERR, "Converting config failed");
				if (xml_fd != -1)
					(void) close(xml_fd);
				xmlTextReaderClose(r);
				xmlFreeTextReader(r);
				xmlCleanupParser();
				ret = CONVERT_FAIL;
				goto done;
			}

			/* Copy files into backup dir */
			(void) snprintf(path, sizeof (path), "%s/backup",
			    target_basedir);
			if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) {
				syslog(LOG_ERR, "Creating backup dir failed");
				ret = CONVERT_FAIL;
				goto done;
			}
			backup(config_file, NULL);
			(void) snprintf(path, MAXPATHLEN, "%s/%s",
			    target_basedir, "config.xml");
			backup(path, NULL);


			while ((next = tgt_node_next(main_config,
			    XML_ELEMENT_TARG, next)) != NULL) {
				if (tgt_find_value_str(next, XML_ELEMENT_INAME,
				    &target) == False) {
					continue;
				}
				(void) snprintf(path, MAXPATHLEN, "%s/%s",
				    target_basedir, target);
				if (mgmt_convert_param(path, next)
				    != True) {
					ret = CONVERT_FAIL;
					goto done;
				}
				free(target);
			}

			ret = CONVERT_OK;
			syslog(LOG_NOTICE, "Conversion succeeded");

			xmlTextReaderClose(r);
			xmlFreeTextReader(r);
			xmlCleanupParser();
		} else {
			syslog(LOG_ERR, "Reading targets config failed");
			ret = CONVERT_FAIL;
			goto done;
		}
	} else {
		syslog(LOG_ERR, "Reading main config failed");
		ret = CONVERT_FAIL;
		goto done;
	}

done:
	if (xml_fd != -1)
		(void) close(xml_fd);
	mgmt_handle_fini(h);
	return (ret);
}
Beispiel #4
0
/*
 * 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);
}
Beispiel #5
0
/*
 * mgmt_get_param() get parameter of a specific LUN from scf
 * Args:
 *  node - the node which parameters will be stored in mem
 *  target_name - the local target name
 *  lun - the LUN number
 * See also : mgmt_param_save2scf()
 */
Boolean_t
mgmt_get_param(tgt_node_t **node, char *target_name, int lun)
{
	targ_scf_t *h = NULL;
	scf_property_t *prop = NULL;
	scf_value_t *value = NULL;
	scf_iter_t *iter = NULL;
	char pname[64];
	char pgname[64];
	char valuebuf[MAXPATHLEN];
	tgt_node_t	*n;
	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);

	snprintf(pgname, sizeof (pgname), "param_%s_%d", target_name, lun);

	(void) pthread_mutex_lock(&scf_param_mutex);

	if (scf_service_get_pg(h->t_service, pgname, h->t_pg) == -1) {
		goto error;
	}

	*node = tgt_node_alloc(XML_ELEMENT_PARAMS, 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);
		}
	}

	status = True;
error:
	(void) pthread_mutex_unlock(&scf_param_mutex);
	scf_iter_destroy(iter);
	scf_value_destroy(value);
	scf_property_destroy(prop);
	mgmt_handle_fini(h);
	return (status);
}
Beispiel #6
0
/*
 * 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);
}
Beispiel #7
0
/*
 * []----
 * | 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);
}
Beispiel #8
0
/*
 * []----
 * | 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);
}
Beispiel #9
0
/*
 * mgmt_get_param() get parameter of a specific LUN from scf
 * Args:
 *  node - the node which parameters will be stored in mem
 *  target_name - the local target name
 *  lun - the LUN number
 * See also : mgmt_param_save2scf()
 */
Boolean_t
mgmt_get_param(tgt_node_t **node, char *target_name, int lun)
{
	targ_scf_t *h = NULL;
	scf_property_t *prop = NULL;
	scf_value_t *value = NULL;
	scf_iter_t *iter = NULL;
	char *pname = NULL;
	char *expgname = NULL;
	char *pgname = NULL;
	char *valuebuf = NULL;
	ssize_t max_name_len;
	ssize_t expg_max_name_len;
	ssize_t max_value_len;
	tgt_node_t	*n;
	Boolean_t status = False;

	/* Set NULL as default output value */
	*node = NULL;
	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);

	if ((alloc_scf_name(&max_name_len, (void *)&pname) == NULL) ||
	    (alloc_scf_name(&max_name_len, (void *)&pgname) == NULL) ||
	    (alloc_scf_value(&max_value_len, (void *)&valuebuf) == NULL)) {
		goto error;
	}

	/*
	 * Allocate memory for an "expanded" (or "decoded") Property Group
	 * name.
	 */
	expg_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH) * PG_FACTOR
	    + 1;
	if ((expgname = malloc(expg_max_name_len)) == NULL) {
		goto error;
	}

	(void) snprintf(pgname, max_name_len, "param_%s_%d", target_name,
	    lun);
	pgname_encode(pgname, expgname, max_name_len);

	(void) pthread_mutex_lock(&scf_param_mutex);

	if (scf_service_get_pg(h->t_service, expgname, h->t_pg) == -1) {
		goto error;
	}

	*node = tgt_node_alloc(XML_ELEMENT_PARAMS, 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) {
		(void) scf_property_get_value(prop, value);
		(void) scf_value_get_as_string(value, valuebuf, max_value_len);
		(void) scf_property_get_name(prop, pname, max_name_len);

		/* 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);
		}
	}

	status = True;
error:
	(void) pthread_mutex_unlock(&scf_param_mutex);

	free(valuebuf);
	free(expgname);
	free(pgname);
	free(pname);

	scf_iter_destroy(iter);
	scf_value_destroy(value);
	scf_property_destroy(prop);
	mgmt_handle_fini(h);
	return (status);
}
Beispiel #10
0
/*
 * Convert legacy (XML) configuration files into an equivalent SCF
 * representation.
 *
 * Read the XML from disk, translate the XML into a tree of nodes of
 * type tgt_node_t, and write the in-memory tree to SCF's persistent
 * data-store using mgmt_config_save2scf().
 *
 * Return Values:
 * CONVERT_OK:	     successfully converted
 * CONVERT_INIT_NEW: configuration files don't exist; created an SCF entry
 * CONVERT_FAIL: some conversion error occurred; no SCF entry created.
 *		 In this case, user has to manually check files and try
 *		 conversion again.
 */
convert_ret_t
mgmt_convert_conf()
{
	targ_scf_t		*h = NULL;
	xmlTextReaderPtr	r;
	convert_ret_t		ret = CONVERT_FAIL;
	int			xml_fd = -1;
	int			n;
	tgt_node_t		*node = NULL;
	tgt_node_t		*next = NULL;
	char			path[MAXPATHLEN];
	char			*target = NULL;

	h = mgmt_handle_init();
	if (h == NULL)
		return (CONVERT_FAIL);

	/*
	 * Check if the "iscsitgt" PropertyGroup has already been added
	 * to the "iscsitgt" SMF Service.  If so, then we have already
	 * converted the legacy configuration files (and there is no work
	 * to do).
	 */
	if (scf_service_get_pg(h->t_service, "iscsitgt", h->t_pg) == 0) {
		ret = CONVERT_OK;
		goto done;
	}

	if (access(config_file, R_OK) != 0) {
		/*
		 * then the Main Config file is not present; initialize
		 * SCF Properties to default values.
		 */
		if (mgmt_transaction_start(h, "iscsitgt", "basic") == True) {
			ret = CONVERT_INIT_NEW;

			node = tgt_node_alloc(XML_ELEMENT_VERS, String, "1.0");
			new_property(h, node);
			tgt_node_free(node);
			/* "daemonize" is set to true by default */
			node = tgt_node_alloc(XML_ELEMENT_DBGDAEMON, String,
			    "true");
			new_property(h, node);
			tgt_node_free(node);
			node = NULL;
			node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
			    ISCSI_AUTH_MODIFY);
			new_property(h, node);
			tgt_node_free(node);
			node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
			    ISCSI_AUTH_VALUE);
			new_property(h, node);
			tgt_node_free(node);
			(void) mgmt_transaction_end(h);
		} else {
			syslog(LOG_ERR, "Creating empty entry failed");
			ret = CONVERT_FAIL;
			goto done;
		}
		if (mgmt_transaction_start(h, "passwords", "application") ==
		    True) {
			node = tgt_node_alloc(ISCSI_READ_AUTHNAME, String,
			    ISCSI_AUTH_READ);
			new_property(h, node);
			tgt_node_free(node);
			node = tgt_node_alloc(ISCSI_MODIFY_AUTHNAME, String,
			    ISCSI_AUTH_MODIFY);
			new_property(h, node);
			tgt_node_free(node);
			node = tgt_node_alloc(ISCSI_VALUE_AUTHNAME, String,
			    ISCSI_AUTH_VALUE);
			new_property(h, node);
			tgt_node_free(node);
			(void) mgmt_transaction_end(h);
		} else {
			syslog(LOG_ERR, "Creating empty entry failed");
			ret = CONVERT_FAIL;
		}
		goto done;
	}

	if ((xml_fd = open(config_file, O_RDONLY)) >= 0)
		r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL, 0);

	if (r != NULL) {
		int is_target_config;

		n = xmlTextReaderRead(r);
		while (n == 1) {
			if (tgt_node_process(r, &node) == False) {
				break;
			}
			n = xmlTextReaderRead(r);
		}
		if (n < 0) {
			syslog(LOG_ERR, "Parsing main config failed");
			ret = CONVERT_FAIL;
			goto done;
		}

		main_config = node;

		/*
		 * Initialize the Base Directory (global) variable by
		 * using the value specified in the XML_ELEMENT_BASEDIR
		 * XML tag.  If a tag is not specified, use a default.
		 */
		(void) tgt_find_value_str(node, XML_ELEMENT_BASEDIR,
		    &target_basedir);

		if (target_basedir == NULL)
			target_basedir = strdup(DEFAULT_TARGET_BASEDIR);

		if (xml_fd != -1) {
			(void) close(xml_fd);
			xml_fd = -1;
		}
		(void) xmlTextReaderClose(r);
		xmlFreeTextReader(r);
		xmlCleanupParser();

		/*
		 * If a Target Config file is present, read and translate
		 * its XML representation into a tree of tgt_node_t.
		 * Merge that tree with the tree of tgt_node_t rooted at
		 * 'main_config'.  The merged tree will then be archived
		 * using an SCF representation.
		 */
		(void) snprintf(path, MAXPATHLEN, "%s/%s",
		    target_basedir, "config.xml");

		if ((xml_fd = open(path, O_RDONLY)) >= 0) {
			is_target_config = 1;
			r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd,
			    NULL, NULL, 0);
		} else {
			is_target_config = 0;
			r = NULL;
		}

		if (r != NULL) {
			/* then the Target Config file is available. */

			node = NULL;

			/*
			 * Create a tree of tgt_node_t rooted at 'node' by
			 * processing each XML Tag in the file.
			 */
			n = xmlTextReaderRead(r);
			while (n == 1) {
				if (tgt_node_process(r, &node) == False) {
					break;
				}
				n = xmlTextReaderRead(r);
			}
			if (n < 0) {
				syslog(LOG_ERR, "Parsing target conf failed");
				ret = CONVERT_FAIL;
				goto done;
			}

			/*
			 * Merge the tree at 'node' into the tree rooted at
			 * 'main_config'.
			 */
			if (node != NULL) {
				next = NULL;
				while ((next = tgt_node_next(node,
				    XML_ELEMENT_TARG, next)) != NULL) {
					tgt_node_add(main_config,
					    tgt_node_dup(next));
				}
				tgt_node_free(node);
			}
		}

		/*
		 * Iterate over the in-memory tree rooted at 'main_config'
		 * and write a representation of the appropriate nodes to
		 * SCF's persistent data-store.
		 */
		if (mgmt_config_save2scf() != True) {
			syslog(LOG_ERR, "Converting config failed");
			if (xml_fd != -1) {
				(void) close(xml_fd);
				xml_fd = -1;
			}
			(void) xmlTextReaderClose(r);
			xmlFreeTextReader(r);
			xmlCleanupParser();
			ret = CONVERT_FAIL;
			goto done;
		}

		/*
		 * Move the configuration files into a well-known backup
		 * directory.  This allows a user to restore their
		 * configuration, if they choose.
		 */
		(void) snprintf(path, sizeof (path), "%s/backup",
		    target_basedir);
		if ((mkdir(path, 0755) == -1) && (errno != EEXIST)) {
			syslog(LOG_ERR, "Creating backup dir failed");
			ret = CONVERT_FAIL;
			goto done;
		}
		/* Save the Main Config file. */
		backup(config_file, NULL);

		/* Save the Target Config file, if it was present. */
		if (is_target_config != 0) {
			(void) snprintf(path, MAXPATHLEN, "%s/%s",
			    target_basedir, "config.xml");
			backup(path, NULL);
		}

		/*
		 * For each tgt_node_t node in 'main_config' whose value is
		 * an iSCSI Name as defined in the RFC (3720) standard (eg,
		 * "iqn.1986..."), read its XML-encoded attributes from a
		 * flat-file and write an equivalent representation to SCF's
		 * data-store.
		 */
		while ((next = tgt_node_next(main_config,
		    XML_ELEMENT_TARG, next)) != NULL) {
			if (tgt_find_value_str(next, XML_ELEMENT_INAME,
			    &target) == False) {
				continue;
			}
			(void) snprintf(path, MAXPATHLEN, "%s/%s",
			    target_basedir, target);
			if (mgmt_convert_param(path, next)
			    != True) {
				ret = CONVERT_FAIL;
				goto done;
			}
			free(target);
		}

		ret = CONVERT_OK;
		syslog(LOG_NOTICE, "Conversion succeeded");

		(void) xmlTextReaderClose(r);
		xmlFreeTextReader(r);
		xmlCleanupParser();
	} else {
		syslog(LOG_ERR, "Reading main config failed");
		ret = CONVERT_FAIL;
		goto done;
	}

done:
	if (xml_fd != -1)
		(void) close(xml_fd);
	mgmt_handle_fini(h);
	return (ret);
}