Beispiel #1
0
/*
 * Function:	get_ver_from_capfile
 * Description: Parses the capability file passed in looking for the VERSION
 *              line. If found the version is returned in vers, if not then
 *              NULL is returned in vers.
 *
 * Parameters:
 *              file - the path to the capability file we want to parse.
 *              vers - the version string that will be passed back.
 * Return:
 *              BE_SUCCESS - Success
 *              be_errno_t - Failed to find version
 * Scope:
 *		Private
 */
static int
get_ver_from_capfile(char *file, char **vers)
{
	FILE *fp = NULL;
	char line[BUFSIZ];
	char *last = NULL;
	int err = BE_SUCCESS;
	errno = 0;

	if (!be_has_grub()) {
		be_print_err(gettext("get_ver_from_capfile: Not supported "
		    "on this architecture\n"));
		return (BE_ERR_NOTSUP);
	}

	/*
	 * Set version string to NULL; the only case this shouldn't be set
	 * to be NULL is when we've actually found a version in the capability
	 * file, which is set below.
	 */
	*vers = NULL;

	/*
	 * If the capability file doesn't exist, we're returning success
	 * because on older releases, the capability file did not exist
	 * so this is a valid scenario.
	 */
	if (access(file, F_OK) == 0) {
		if ((fp = fopen(file, "r")) == NULL) {
			err = errno;
			be_print_err(gettext("get_ver_from_capfile: failed to "
			    "open file %s with error %s\n"), file,
			    strerror(err));
			err = errno_to_be_err(err);
			return (err);
		}

		while (fgets(line, BUFSIZ, fp)) {
			char *tok = strtok_r(line, "=", &last);

			if (tok == NULL || tok[0] == '#') {
				continue;
			} else if (strcmp(tok, "VERSION") == 0) {
				*vers = strdup(last);
				break;
			}
		}
		(void) fclose(fp);
	}

	return (BE_SUCCESS);
}
Beispiel #2
0
/*
 * Function:	be_get_ss_data
 * Description: Helper function used by be_add_children_callback to collect
 *		the dataset related information that will be returned by
 *		be_list.
 * Parameters:
 *		zhp - Handle to the zfs snapshot whose information we're
 *		      collecting.
 *		name - The name of the snapshot we're processing.
 *		shapshot - A pointer to the be_snapshot_list structure
 *			   we're filling in.
 *		node - The node structure that this snapshot belongs to.
 * Returns:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 * Scope:
 *		Private
 */
static int
be_get_ss_data(
	zfs_handle_t *zfshp,
	char *name,
	be_snapshot_list_t *snapshot,
	be_node_list_t *node)
{
	nvlist_t	*propval = NULL;
	nvlist_t	*userprops = NULL;
	char		*prop_str = NULL;
	int		err = 0;

	if (zfshp == NULL || name == NULL || snapshot == NULL || node == NULL) {
		be_print_err(gettext("be_get_ss_data: invalid arguments, "
		    "can not be NULL\n"));
		return (BE_ERR_INVAL);
	}

	errno = 0;

	snapshot->be_snapshot_name = strdup(name);
	if ((err = errno) != 0) {
		be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
		return (errno_to_be_err(err));
	}

	snapshot->be_snapshot_creation = (time_t)zfs_prop_get_int(zfshp,
	    ZFS_PROP_CREATION);

	/*
	 * Try to get this snapshot's cleanup policy from its
	 * user properties first.  If not there, use default
	 * cleanup policy.
	 */
	if ((userprops = zfs_get_user_props(zfshp)) != NULL &&
	    nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
	    &propval) == 0 && nvlist_lookup_string(propval,
	    ZPROP_VALUE, &prop_str) == 0) {
		snapshot->be_snapshot_type =
		    strdup(prop_str);
	} else {
		snapshot->be_snapshot_type =
		    strdup(be_default_policy());
	}

	snapshot->be_snapshot_space_used = zfs_prop_get_int(zfshp,
	    ZFS_PROP_USED);

	node->be_node_num_snapshots++;
	return (BE_SUCCESS);
}
Beispiel #3
0
/*
 * Function:	be_get_ds_data
 * Description:	Helper function used by be_add_children_callback to collect
 *		the dataset related information that will be returned by
 *		be_list.
 * Parameters:
 *		zhp - Handle to the zfs dataset whose information we're
 *		      collecting.
 *		name - The name of the dataset we're processing.
 *		dataset - A pointer to the be_dataset_list structure
 *			  we're filling in.
 *		node - The node structure that this dataset belongs to.
 * Return:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 * Scope:
 *		Private
 */
static int
be_get_ds_data(
	zfs_handle_t *zfshp,
	char *name,
	be_dataset_list_t *dataset,
	be_node_list_t *node)
{
	char			prop_buf[ZFS_MAXPROPLEN];
	nvlist_t		*propval = NULL;
	nvlist_t		*userprops = NULL;
	char			*prop_str = NULL;
	int			err = 0;

	if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) {
		be_print_err(gettext("be_get_ds_data: invalid arguments, "
		    "can not be NULL\n"));
		return (BE_ERR_INVAL);
	}

	errno = 0;

	dataset->be_dataset_name = strdup(name);
	if ((err = errno) != 0) {
		be_print_err(gettext("be_get_ds_data: failed to copy "
		    "dataset name\n"));
		return (errno_to_be_err(err));
	}

	dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);

	/*
	 * If the dataset is mounted use the mount point
	 * returned from the zfs_is_mounted call. If the
	 * dataset is not mounted then pull the mount
	 * point information out of the zfs properties.
	 */
	if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp,
	    &(dataset->be_ds_mntpt)))) {
		if (zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
		    prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
		    B_FALSE) == 0)
			dataset->be_ds_mntpt = strdup(prop_buf);
		else
			return (zfs_err_to_be_err(g_zfs));
	}
	dataset->be_ds_creation =
	    (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);

	/*
	 * Get the user property used for the libbe
	 * cleaup policy
	 */
	if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
		dataset->be_ds_plcy_type =
		    strdup(node->be_policy_type);
	} else {
		if (nvlist_lookup_nvlist(userprops,
		    BE_POLICY_PROPERTY, &propval) != 0 ||
		    propval == NULL) {
			dataset->be_ds_plcy_type =
			    strdup(node->be_policy_type);
		} else {
			verify(nvlist_lookup_string(propval,
			    ZPROP_VALUE, &prop_str) == 0);
			if (prop_str == NULL ||
			    strcmp(prop_str, "-") == 0 ||
			    strcmp(prop_str, "") == 0)
				dataset->be_ds_plcy_type
				    = strdup(node->be_policy_type);
			else
				dataset->be_ds_plcy_type = strdup(prop_str);
		}
	}

	node->be_node_num_datasets++;
	return (BE_SUCCESS);
}
Beispiel #4
0
/*
 * Function:	be_get_node_data
 * Description:	Helper function used to collect all the information to fill
 *		in the be_node_list structure to be returned by be_list.
 * Parameters:
 *		zhp - Handle to the root dataset for the BE whose information
 *		      we're collecting.
 *		be_node - a pointer to the node structure we're filling in.
 *		be_name - The BE name of the node whose information we're
 *		          collecting.
 *		current_be - the name of the currently active BE.
 *		be_ds - The dataset name for the BE.
 *
 * Returns:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 * Scope:
 *		Private
 */
static int
be_get_node_data(
	zfs_handle_t *zhp,
	be_node_list_t *be_node,
	char *be_name,
	const char *rpool,
	char *current_be,
	char *be_ds)
{
	char prop_buf[MAXPATHLEN];
	nvlist_t *userprops = NULL;
	nvlist_t *propval = NULL;
	nvlist_t *zone_propval = NULL;
	char *prop_str = NULL;
	char *zone_prop_str = NULL;
	char *grub_default_bootfs = NULL;
	zpool_handle_t *zphp = NULL;
	int err = 0;

	if (be_node == NULL || be_name == NULL || current_be == NULL ||
	    be_ds == NULL) {
		be_print_err(gettext("be_get_node_data: invalid arguments, "
		    "can not be NULL\n"));
		return (BE_ERR_INVAL);
	}

	errno = 0;

	be_node->be_root_ds = strdup(be_ds);
	if ((err = errno) != 0 || be_node->be_root_ds == NULL) {
		be_print_err(gettext("be_get_node_data: failed to "
		    "copy root dataset name\n"));
		return (errno_to_be_err(err));
	}

	be_node->be_node_name = strdup(be_name);
	if ((err = errno) != 0 || be_node->be_node_name == NULL) {
		be_print_err(gettext("be_get_node_data: failed to "
		    "copy BE name\n"));
		return (errno_to_be_err(err));
	}
	if (strncmp(be_name, current_be, MAXPATHLEN) == 0)
		be_node->be_active = B_TRUE;
	else
		be_node->be_active = B_FALSE;

	be_node->be_rpool = strdup(rpool);
	if (be_node->be_rpool == NULL || (err = errno) != 0) {
		be_print_err(gettext("be_get_node_data: failed to "
		    "copy root pool name\n"));
		return (errno_to_be_err(err));
	}

	be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);

	if (getzoneid() == GLOBAL_ZONEID) {
		if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
			be_print_err(gettext("be_get_node_data: failed to open "
			    "pool (%s): %s\n"), rpool,
			    libzfs_error_description(g_zfs));
			return (zfs_err_to_be_err(g_zfs));
		}

		(void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
		    ZFS_MAXPROPLEN, NULL, B_FALSE);
		if (be_has_grub() && (be_default_grub_bootfs(rpool,
		    &grub_default_bootfs) == BE_SUCCESS) &&
		    grub_default_bootfs != NULL)
			if (strcmp(grub_default_bootfs, be_ds) == 0)
				be_node->be_active_on_boot = B_TRUE;
			else
				be_node->be_active_on_boot = B_FALSE;
		else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0)
			be_node->be_active_on_boot = B_TRUE;
		else
			be_node->be_active_on_boot = B_FALSE;

		be_node->be_global_active = B_TRUE;

		free(grub_default_bootfs);
		zpool_close(zphp);
	} else {
		if (be_zone_compare_uuids(be_node->be_root_ds))
			be_node->be_global_active = B_TRUE;
		else
			be_node->be_global_active = B_FALSE;
	}

	/*
	 * If the dataset is mounted use the mount point
	 * returned from the zfs_is_mounted call. If the
	 * dataset is not mounted then pull the mount
	 * point information out of the zfs properties.
	 */
	be_node->be_mounted = zfs_is_mounted(zhp,
	    &(be_node->be_mntpt));
	if (!be_node->be_mounted) {
		if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
		    ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0)
			be_node->be_mntpt = strdup(prop_buf);
		else
			return (zfs_err_to_be_err(g_zfs));
	}

	be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp,
	    ZFS_PROP_CREATION);

	/* Get all user properties used for libbe */
	if ((userprops = zfs_get_user_props(zhp)) == NULL) {
		be_node->be_policy_type = strdup(be_default_policy());
	} else {
		if (getzoneid() != GLOBAL_ZONEID) {
			if (nvlist_lookup_nvlist(userprops,
			    BE_ZONE_ACTIVE_PROPERTY, &zone_propval) != 0 ||
			    zone_propval == NULL) {
				be_node->be_active_on_boot = B_FALSE;
			} else {
				verify(nvlist_lookup_string(zone_propval,
				    ZPROP_VALUE, &zone_prop_str) == 0);
				if (strcmp(zone_prop_str, "on") == 0) {
					be_node->be_active_on_boot = B_TRUE;
				} else {
					be_node->be_active_on_boot = B_FALSE;
				}
			}
		}

		if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
		    &propval) != 0 || propval == NULL) {
			be_node->be_policy_type =
			    strdup(be_default_policy());
		} else {
			verify(nvlist_lookup_string(propval, ZPROP_VALUE,
			    &prop_str) == 0);
			if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
			    strcmp(prop_str, "") == 0)
				be_node->be_policy_type =
				    strdup(be_default_policy());
			else
				be_node->be_policy_type = strdup(prop_str);
		}
		if (getzoneid() != GLOBAL_ZONEID) {
			if (nvlist_lookup_nvlist(userprops,
			    BE_ZONE_PARENTBE_PROPERTY, &propval) != 0 &&
			    nvlist_lookup_string(propval, ZPROP_VALUE,
			    &prop_str) == 0) {
				be_node->be_uuid_str = strdup(prop_str);
			}
		} else {
			if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY,
			    &propval) == 0 && nvlist_lookup_string(propval,
			    ZPROP_VALUE, &prop_str) == 0) {
				be_node->be_uuid_str = strdup(prop_str);
			}
		}
	}

	/*
	 * Increment the dataset counter to include the root dataset
	 * of the BE.
	 */
	be_node->be_node_num_datasets++;

	return (BE_SUCCESS);
}
Beispiel #5
0
/*
 * Function:	be_do_installgrub
 * Description:	This function runs installgrub using the grub loader files
 *              from the BE we're activating and installing them on the
 *              pool the BE lives in.
 *
 * Parameters:
 *              bt - The transaction data for the BE we're activating.
 * Return:
 *		BE_SUCCESS - Success
 *		be_errno_t - Failure
 *
 * Scope:
 *		Private
 */
static int
be_do_installgrub(be_transaction_data_t *bt)
{
	zpool_handle_t  *zphp = NULL;
	zfs_handle_t	*zhp = NULL;
	nvlist_t **child, *nv, *config;
	uint_t c, children = 0;
	char *tmp_mntpt = NULL;
	char *pool_mntpnt = NULL;
	char *ptmp_mntpnt = NULL;
	char *orig_mntpnt = NULL;
	FILE *cap_fp = NULL;
	FILE *zpool_cap_fp = NULL;
	char line[BUFSIZ];
	char cap_file[MAXPATHLEN];
	char zpool_cap_file[MAXPATHLEN];
	char stage1[MAXPATHLEN];
	char stage2[MAXPATHLEN];
	char installgrub_cmd[MAXPATHLEN];
	char *vname;
	char be_run_cmd_errbuf[BUFSIZ];
	int ret = BE_SUCCESS;
	int err = 0;
	boolean_t be_mounted = B_FALSE;
	boolean_t pool_mounted = B_FALSE;

	if (!be_has_grub()) {
		be_print_err(gettext("be_do_installgrub: Not supported "
		    "on this architecture\n"));
		return (BE_ERR_NOTSUP);
	}

	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
	    NULL) {
		be_print_err(gettext("be_do_installgrub: failed to "
		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		return (ret);
	}
	if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
		if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
			be_print_err(gettext("be_do_installgrub: failed to "
			    "mount BE (%s)\n"), bt->obe_name);
			ZFS_CLOSE(zhp);
			return (ret);
		}
		be_mounted = B_TRUE;
	}
	ZFS_CLOSE(zhp);

	(void) snprintf(stage1, sizeof (stage1), "%s%s", tmp_mntpt, BE_STAGE_1);
	(void) snprintf(stage2, sizeof (stage2), "%s%s", tmp_mntpt, BE_STAGE_2);

	if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
		be_print_err(gettext("be_do_installgrub: failed to open "
		    "pool (%s): %s\n"), bt->obe_zpool,
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		if (be_mounted)
			(void) _be_unmount(bt->obe_name, 0);
		free(tmp_mntpt);
		return (ret);
	}

	if ((config = zpool_get_config(zphp, NULL)) == NULL) {
		be_print_err(gettext("be_do_installgrub: failed to get zpool "
		    "configuration information. %s\n"),
		    libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	/*
	 * Get the vdev tree
	 */
	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
		be_print_err(gettext("be_do_installgrub: failed to get vdev "
		    "tree: %s\n"), libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}

	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
	    &children) != 0) {
		be_print_err(gettext("be_do_installgrub: failed to traverse "
		    "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
		ret = zfs_err_to_be_err(g_zfs);
		goto done;
	}
	for (c = 0; c < children; c++) {
		uint_t i, nchildren = 0;
		nvlist_t **nvchild;
		vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
		if (vname == NULL) {
			be_print_err(gettext(
			    "be_do_installgrub: "
			    "failed to get device name: %s\n"),
			    libzfs_error_description(g_zfs));
			ret = zfs_err_to_be_err(g_zfs);
			goto done;
		}
		if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {

			if (nvlist_lookup_nvlist_array(child[c],
			    ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
				be_print_err(gettext("be_do_installgrub: "
				    "failed to traverse the vdev tree: %s\n"),
				    libzfs_error_description(g_zfs));
				ret = zfs_err_to_be_err(g_zfs);
				goto done;
			}

			for (i = 0; i < nchildren; i++) {
				vname = zpool_vdev_name(g_zfs, zphp,
				    nvchild[i], B_FALSE);
				if (vname == NULL) {
					be_print_err(gettext(
					    "be_do_installgrub: "
					    "failed to get device name: %s\n"),
					    libzfs_error_description(g_zfs));
					ret = zfs_err_to_be_err(g_zfs);
					goto done;
				}

				(void) snprintf(installgrub_cmd,
				    sizeof (installgrub_cmd),
				    "%s %s %s /dev/rdsk/%s",
				    BE_INSTALL_GRUB, stage1, stage2, vname);
				if (be_run_cmd(installgrub_cmd,
				    be_run_cmd_errbuf, BUFSIZ, NULL, 0) !=
				    BE_SUCCESS) {
					be_print_err(gettext(
					    "be_do_installgrub: installgrub "
					    "failed for device %s.\n"), vname);
					/* Assume localized cmd err output. */
					be_print_err(gettext(
					    "  Command: \"%s\"\n"),
					    installgrub_cmd);
					be_print_err("%s", be_run_cmd_errbuf);
					free(vname);
					ret = BE_ERR_BOOTFILE_INST;
					goto done;
				}
				free(vname);
			}
		} else {
			(void) snprintf(installgrub_cmd,
			    sizeof (installgrub_cmd), "%s %s %s /dev/rdsk/%s",
			    BE_INSTALL_GRUB, stage1, stage2, vname);
			if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf,
			    BUFSIZ, NULL, 0) != BE_SUCCESS) {
				be_print_err(gettext(
				    "be_do_installgrub: installgrub "
				    "failed for device %s.\n"), vname);
				/* Assume localized cmd err output. */
				be_print_err(gettext("  Command: \"%s\"\n"),
				    installgrub_cmd);
				be_print_err("%s", be_run_cmd_errbuf);
				free(vname);
				ret = BE_ERR_BOOTFILE_INST;
				goto done;
			}
			free(vname);
		}
	}

	/*
	 * Copy the grub capability file from the BE we're activating into
	 * the root pool.
	 */
	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpt,
	    BE_CAP_FILE);

	if ((zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
	    NULL) {
		be_print_err(gettext("be_do_installgrub: zfs_open "
		    "failed: %s\n"), libzfs_error_description(g_zfs));
		zpool_close(zphp);
		return (zfs_err_to_be_err(g_zfs));
	}

	/*
	 * Check to see if the pool's dataset is mounted. If it isn't we'll
	 * attempt to mount it.
	 */
	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
		be_print_err(gettext("be_do_installgrub: pool dataset "
		    "(%s) could not be mounted\n"), bt->obe_zpool);
		ZFS_CLOSE(zhp);
		zpool_close(zphp);
		return (ret);
	}

	/*
	 * Get the mountpoint for the root pool dataset.
	 */
	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
		be_print_err(gettext("be_do_installgrub: pool "
		    "dataset (%s) is not mounted. Can't check the grub "
		    "version from the grub capability file.\n"), bt->obe_zpool);
		ret = BE_ERR_NO_MENU;
		goto done;
	}

	(void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
	    pool_mntpnt, BE_CAP_FILE);

	free(pool_mntpnt);
	pool_mntpnt = NULL;

	if ((cap_fp = fopen(cap_file, "r")) == NULL) {
		err = errno;
		be_print_err(gettext("be_do_installgrub: failed to open grub "
		    "capability file\n"));
		ret = errno_to_be_err(err);
		goto done;
	}
	if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
		err = errno;
		be_print_err(gettext("be_do_installgrub: failed to open new "
		    "grub capability file\n"));
		ret = errno_to_be_err(err);
		(void) fclose(cap_fp);
		goto done;
	}

	while (fgets(line, BUFSIZ, cap_fp)) {
		(void) fputs(line, zpool_cap_fp);
	}

	(void) fclose(zpool_cap_fp);
	(void) fclose(cap_fp);

done:
	if (pool_mounted) {
		int iret = 0;
		iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
		if (ret == BE_SUCCESS)
			ret = iret;
		free(orig_mntpnt);
		free(ptmp_mntpnt);
	}
	ZFS_CLOSE(zhp);
	if (be_mounted)
		(void) _be_unmount(bt->obe_name, 0);
	zpool_close(zphp);
	free(tmp_mntpt);
	return (ret);
}