be_utils.c revision de1ab35c09a8c3ae1b531c0a613d2cc1c61cee9d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
*/
/*
* System includes
*/
#include <assert.h>
#include <errno.h>
#include <libgen.h>
#include <libintl.h>
#include <libnvpair.h>
#include <libzfs.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/systeminfo.h>
#include <ctype.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <deflt.h>
#include <wait.h>
#include <libdevinfo.h>
#include <libbe.h>
#include <libbe_priv.h>
/* Private function prototypes */
static int update_dataset(char *, int, char *, char *, char *);
static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
static int be_create_menu(char *, char *, FILE **, char *);
static char *be_get_auto_name(char *, char *, boolean_t);
/*
* Global error printing
*/
/*
* Private datatypes
*/
typedef struct zone_be_name_cb_data {
char *base_be_name;
int num;
/* ******************************************************************** */
/* Public Functions */
/* ******************************************************************** */
/*
* Function: be_max_avail
* Description: Returns the available size for the zfs dataset passed in.
* Parameters:
* dataset - The dataset we want to get the available space for.
* ret - The available size will be returned in this.
* Returns:
* The error returned by the zfs get property function.
* Scope:
* Public
*/
int
{
int err = 0;
/* Initialize libzfs handle */
if (!be_zfs_init())
return (BE_ERR_INIT);
/*
* The zfs_open failed return an error
*/
} else {
}
be_zfs_fini();
return (err);
}
/*
* Function: libbe_print_errors
* Parameter:
* set_do_print - Boolean that turns library error
* printing on or off.
* Returns:
* None
* Scope:
* Public;
*/
void
{
}
/* ******************************************************************** */
/* Semi-Private Functions */
/* ******************************************************************** */
/*
* Function: be_zfs_init
* Description: Initializes the libary global libzfs handle.
* Parameters:
* None
* Returns:
* B_TRUE - Success
* B_FALSE - Failure
* Scope:
* Semi-private (library wide use only)
*/
be_zfs_init(void)
{
be_zfs_fini();
"library\n"));
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Function: be_zfs_fini
* Description: Closes the library global libzfs handle if it currently open.
* Parameter:
* None
* Returns:
* None
* Scope:
* Semi-private (library wide use only)
*/
void
be_zfs_fini(void)
{
if (g_zfs)
}
/*
* Function: be_get_defaults
* Description: Open defaults and gets be default paramets
* Parameters:
* defaults - be defaults struct
* Returns:
* None
* Scope:
* Semi-private (library wide use only)
*/
void
{
void *defp;
}
}
}
/*
* Function: be_make_root_ds
* Description: Generate string for BE's root dataset given the pool
* it lives in and the BE name.
* Parameters:
* zpool - pointer zpool name.
* be_name - pointer to BE name.
* be_root_ds - pointer to buffer to return BE root dataset in.
* be_root_ds_size - size of be_root_ds
* Returns:
* None
* Scope:
* Semi-private (library wide use only)
*/
void
int be_root_ds_size)
{
struct be_defaults be_defaults;
be_name);
else
}
/*
* Function: be_make_container_ds
* Description: Generate string for the BE container dataset given a pool name.
* Parameters:
* zpool - pointer zpool name.
* container_ds - pointer to buffer to return BE container
* dataset in.
* container_ds_size - size of container_ds
* Returns:
* None
* Scope:
* Semi-private (library wide use only)
*/
void
int container_ds_size)
{
struct be_defaults be_defaults;
else
}
/*
* Function: be_make_name_from_ds
* Description: This function takes a dataset name and strips off the
* BE container dataset portion from the beginning. The
* returned name is allocated in heap storage, so the caller
* is responsible for freeing it.
* Parameters:
* dataset - dataset to get name from.
* rc_loc - dataset underwhich the root container dataset lives.
* Returns:
* name of dataset relative to BE container dataset.
* NULL if dataset is not under a BE root dataset.
* Scope:
* Semi-primate (library wide use only)
*/
char *
{
char ds[ZFS_MAXNAMELEN];
struct be_defaults be_defaults;
/*
* First token is the location of where the root container dataset
* lives; it must match rc_loc.
*/
else
return (NULL);
"memory allocation failed\n"));
return (NULL);
}
} else {
/* Second token must be BE container dataset name */
return (NULL);
/* Return the remaining token if one exists */
return (NULL);
"memory allocation failed\n"));
return (NULL);
}
}
return (name);
}
/*
* Function: be_maxsize_avail
* Description: Returns the available size for the zfs handle passed in.
* Parameters:
* zhp - A pointer to the open zfs handle.
* ret - The available size will be returned in this.
* Returns:
* The error returned by the zfs get property function.
* Scope:
* Semi-private (library wide use only)
*/
int
{
}
/*
* Function: be_append_menu
* Description: Appends an entry for a BE into the menu.lst.
* Parameters:
* be_name - pointer to name of BE to add boot menu entry for.
* be_root_pool - pointer to name of pool BE lives in.
* boot_pool - Used if the pool containing the grub menu is
* different than the one contaiing the BE. This
* will normally be NULL.
* be_orig_root_ds - The root dataset for the BE. This is
* used to check to see if an entry already exists
* for this BE.
* description - pointer to description of BE to be added in
* the title line for this BEs entry.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
char *be_orig_root_ds, char *description)
{
char menu_file[MAXPATHLEN];
char be_root_ds[MAXPATHLEN];
char title[MAXPATHLEN];
char *tmp_entries[BUFSIZ];
char *pool_mntpnt = NULL;
char *ptmp_mntpnt = NULL;
char *orig_mntpnt = NULL;
int i, num_tmp_lines = 0, num_lines = 0;
return (BE_ERR_INVAL);
"pool dataset for %s: %s\n"), be_root_pool,
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.
*/
&pool_mounted)) != BE_SUCCESS) {
"(%s) could not be mounted\n"), be_root_pool);
return (ret);
}
/*
* Get the mountpoint for the root pool dataset.
*/
"dataset (%s) is not mounted. Can't set "
"the default BE in the grub menu.\n"), be_root_pool);
goto cleanup;
}
/*
* Check to see if this system supports grub
*/
if (be_has_grub()) {
} else {
}
/*
* Iterate through menu first to make sure the BE doesn't already
* have an entry in the menu.
*
* Additionally while iterating through the menu, if we have an
* original root dataset for a BE we're cloning from, we need to keep
* track of that BE's menu entry. We will then use the lines from
* that entry to create the entry for the new BE.
*/
goto cleanup;
goto cleanup;
}
pool_mntpnt = NULL;
continue;
else
if (num_tmp_lines != 0) {
for (i = 0; i < num_tmp_lines; i++) {
free(tmp_entries[i]);
tmp_entries[i] = NULL;
}
num_tmp_lines = 0;
}
continue;
break;
}
if (be_orig_root_ds != NULL &&
!found_orig_be) {
num_lines = 0;
/*
* Store the new title line
*/
num_lines++;
/*
* If there are any lines between the title
* and the bootfs line store these. Also
* free the temporary lines.
*/
for (i = 0; i < num_tmp_lines; i++) {
tmp_entries[i] = NULL;
num_lines++;
}
num_tmp_lines = 0;
/*
* Store the new bootfs line.
*/
num_lines++;
}
} else if (found_orig_be && collect_lines) {
/*
* get the rest of the lines for the original BE and
* store them.
*/
continue;
strdup("splashimage "
"/boot/splashimage.xpm\n");
} else {
}
num_lines++;
} else if (found_title && !found_orig_be) {
}
}
if (found_be) {
/*
* If an entry for this BE was already in the menu, then if
* that entry's title matches what we would have put in
* return success. Otherwise return failure.
*/
ret = BE_SUCCESS;
goto cleanup;
} else {
boot_pool) != BE_SUCCESS) {
"Failed to remove existing unusable "
"entry '%s' in boot menu.\n"), be_name);
goto cleanup;
}
}
}
/* Append BE entry to the end of the file */
"to open menu.lst file %s\n"), menu_file);
goto cleanup;
}
if (found_orig_be) {
/*
* write out all the stored lines
*/
for (i = 0; i < num_lines; i++) {
}
num_lines = 0;
/*
* Check to see if this system supports grub
*/
if (be_has_grub())
ret = BE_SUCCESS;
} else {
/*
* Check to see if this system supports grub
*/
if (be_has_grub()) {
"$ZFS-BOOTFS\n");
"/platform/i86pc/$ISADIR/boot_archive\n");
}
ret = BE_SUCCESS;
}
if (pool_mounted) {
int err = BE_SUCCESS;
if (ret == BE_SUCCESS)
}
if (num_tmp_lines > 0) {
for (i = 0; i < num_tmp_lines; i++) {
free(tmp_entries[i]);
tmp_entries[i] = NULL;
}
}
if (num_lines > 0) {
for (i = 0; i < num_lines; i++) {
}
}
return (ret);
}
/*
* Function: be_remove_menu
* Description: Removes a BE's entry from a menu.lst file.
* Parameters:
* be_name - the name of BE whose entry is to be removed from
* the menu.lst file.
* be_root_pool - the pool that be_name lives in.
* boot_pool - the pool where the BE is, if different than
* the pool containing the boot menu. If this is
* NULL it will be set to be_root_pool.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
{
char be_root_ds[MAXPATHLEN];
char menu[MAXPATHLEN];
char *pool_mntpnt = NULL;
char *ptmp_mntpnt = NULL;
char *orig_mntpnt = NULL;
int ret = BE_SUCCESS;
int i;
int fd;
int err = 0;
int nlines = 0;
int default_entry = 0;
int entry_cnt = 0;
int entry_del = 0;
int num_entry_del = 0;
int tmp_menu_len = 0;
/* Get name of BE's root dataset */
/* Get handle to pool dataset */
"failed to open pool dataset for %s: %s"),
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.
*/
&pool_mounted)) != BE_SUCCESS) {
"(%s) could not be mounted\n"), be_root_pool);
return (ret);
}
/*
* Get the mountpoint for the root pool dataset.
*/
"dataset (%s) is not mounted. Can't set "
"the default BE in the grub menu.\n"), be_root_pool);
goto cleanup;
}
/* Get path to boot menu */
/*
* Check to see if this system supports grub
*/
if (be_has_grub())
else
/* Get handle to boot menu file */
B_TRUE)) != BE_SUCCESS) {
goto cleanup;
goto cleanup;
}
pool_mntpnt = NULL;
/* Grab the stats of the original menu file */
goto cleanup;
}
/* Create a tmp file for the modified menu.lst */
ret = BE_ERR_NOMEM;
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
/* Tokenize line */
/* Found empty line or comment line */
if (do_buffer) {
/* Buffer this line */
ret = BE_ERR_NOMEM;
goto cleanup;
}
== NULL) {
ret = BE_ERR_NOMEM;
goto cleanup;
}
strlen(BE_GRUB_COMMENT)) != 0) {
/* Write this line out */
}
/*
* Record what 'default' is set to because we might
* need to adjust this upon deleting an entry.
*/
}
/*
* If we've reached a 'title' line and do_buffer is
* is true, that means we've just buffered an entire
* entry without finding a 'bootfs' directive. We
* need to write that entry out and keep searching.
*/
if (do_buffer) {
for (i = 0; i < nlines; i++) {
}
nlines = 0;
}
/*
* Turn writing off and buffering on, and increment
* our entry counter.
*/
entry_cnt++;
/* Buffer this 'title' line */
ret = BE_ERR_NOMEM;
goto cleanup;
}
ret = BE_ERR_NOMEM;
goto cleanup;
}
/*
* Found a 'bootfs' line. See if it matches the
* BE we're looking for.
*/
/*
* Either there's nothing after the 'bootfs'
* or this is not the BE we're looking for,
* write out the line(s) we've buffered since
* finding the title.
*/
for (i = 0; i < nlines; i++) {
}
nlines = 0;
/*
* Turn writing back on, and turn off buffering
* since this isn't the entry we're looking
* for.
*/
/* Write this 'bootfs' line out. */
} else {
/*
* Found the entry we're looking for.
* Record its entry number, increment the
* number of entries we've deleted, and turn
* writing off. Also, throw away the lines
* we've buffered for this entry so far, we
* don't need them.
*/
for (i = 0; i < nlines; i++) {
}
nlines = 0;
}
} else {
if (do_buffer) {
/* Buffer this line */
ret = BE_ERR_NOMEM;
goto cleanup;
}
== NULL) {
ret = BE_ERR_NOMEM;
goto cleanup;
}
} else if (write) {
/* Write this line out */
}
}
}
(void) fclose(tmp_menu_fp);
tmp_menu_fp = NULL;
/* Copy the modified menu.lst into place */
"failed to rename file %s to %s: %s\n"),
goto cleanup;
}
/*
* If we've removed an entry, see if we need to
* adjust the default value in the menu.lst. If the
* entry we've deleted comes before the default entry
* we need to adjust the default value accordingly.
*
* be_has_grub is used here to check to see if this system
* supports grub.
*/
if (be_has_grub() && num_entry_del > 0) {
if (entry_del <= default_entry) {
if (default_entry < 0)
default_entry = 0;
/*
* Adjust the default value by rewriting the
* menu.lst file. This may be overkill, but to
* preserve the location of the 'default' entry
* in the file, we need to do this.
*/
/* Get handle to boot menu file */
"failed to open menu.lst (%s): %s\n"),
goto cleanup;
}
/* Create a tmp file for the modified menu.lst */
== NULL) {
"malloc failed\n"));
ret = BE_ERR_NOMEM;
goto cleanup;
}
goto cleanup;
}
"could not open tmp file for write: %s\n"),
goto cleanup;
}
/* Tokenize line */
/* Found empty line, write it out */
/* Found the default line, adjust it */
"default %d\n", default_entry);
} else {
/* Pass through all other lines */
}
}
(void) fclose(tmp_menu_fp);
tmp_menu_fp = NULL;
/* Copy the modified menu.lst into place */
"failed to rename file %s to %s: %s\n"),
goto cleanup;
}
}
}
/* Set the perms and ownership of the updated file */
goto cleanup;
}
goto cleanup;
}
if (pool_mounted) {
int err = BE_SUCCESS;
if (ret == BE_SUCCESS)
}
if (tmp_menu_fp != NULL)
(void) fclose(tmp_menu_fp);
}
return (ret);
}
/*
* Function: be_default_grub_bootfs
* Description: This function returns the dataset in the default entry of
* the grub menu. If no default entry is found with a valid bootfs
* entry NULL is returned.
* Parameters:
* be_root_pool - This is the name of the root pool where the
* grub menu can be found.
* def_bootfs - This is used to pass back the bootfs string. On
* error NULL is returned here.
* Returns:
* Success - BE_SUCCESS is returned.
* Failure - a be_errno_t is returned.
* Scope:
* Semi-private (library wide use only)
*/
int
{
char grub_file[MAXPATHLEN];
char *pool_mntpnt = NULL;
char *ptmp_mntpnt = NULL;
char *orig_mntpnt = NULL;
int default_entry = 0, entries = 0;
int found_default = 0;
int ret = BE_SUCCESS;
errno = 0;
/*
* Check to see if this system supports grub
*/
if (!be_has_grub()) {
"not supported on this architecture\n"));
return (BE_ERR_NOTSUP);
}
*def_bootfs = NULL;
/* Get handle to pool dataset */
"failed to open pool dataset for %s: %s"),
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.
*/
&pool_mounted)) != BE_SUCCESS) {
"(%s) could not be mounted\n"), be_root_pool);
return (ret);
}
/*
* Get the mountpoint for the root pool dataset.
*/
"to get mount point for the root pool. Can't set "
"the default BE in the grub menu.\n"));
goto cleanup;
}
goto cleanup;
goto cleanup;
}
pool_mntpnt = NULL;
if (!found_default) {
found_default = 1;
}
}
continue;
}
entries++;
ret = BE_SUCCESS;
goto cleanup;
}
NULL) {
ret = BE_SUCCESS;
goto cleanup;
}
"be_default_grub_bootfs: "
"memory allocation failed\n"));
ret = BE_ERR_NOMEM;
goto cleanup;
}
/*
* no bootfs entry for the default entry.
*/
break;
}
}
}
if (pool_mounted) {
int err = BE_SUCCESS;
if (ret == BE_SUCCESS)
}
return (ret);
}
/*
* Function: be_change_grub_default
* Description: This function takes two parameters. These are the name of
* the BE we want to have as the default booted in the grub
* menu and the root pool where the path to the grub menu exists.
* The code takes this and finds the BE's entry in the grub menu
* and changes the default entry to point to that entry in the
* list.
* Parameters:
* be_name - This is the name of the BE wanted as the default
* for the next boot.
* be_root_pool - This is the name of the root pool where the
* grub menu can be found.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
{
char grub_file[MAXPATHLEN];
char *temp_grub;
char *pool_mntpnt = NULL;
char *ptmp_mntpnt = NULL;
char *orig_mntpnt = NULL;
char be_root_ds[MAXPATHLEN];
int temp_grub_len = 0;
int err = 0;
int ret = BE_SUCCESS;
errno = 0;
/*
* Check to see if this system supports grub
*/
if (!be_has_grub()) {
"not supported on this architecture\n"));
return (BE_ERR_NOTSUP);
}
/* Generate string for BE's root dataset */
/* Get handle to pool dataset */
"failed to open pool dataset for %s: %s"),
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.
*/
&pool_mounted)) != BE_SUCCESS) {
"(%s) could not be mounted\n"), be_root_pool);
return (ret);
}
/*
* Get the mountpoint for the root pool dataset.
*/
"dataset (%s) is not mounted. Can't set "
"the default BE in the grub menu.\n"), be_root_pool);
goto cleanup;
}
goto cleanup;
goto cleanup;
}
pool_mntpnt = NULL;
/* Grab the stats of the original menu file */
goto cleanup;
}
/* Create a tmp file for the modified menu.lst */
"malloc failed\n"));
ret = BE_ERR_NOMEM;
goto cleanup;
}
goto cleanup;
}
"failed to open %s file: %s\n"),
goto cleanup;
}
continue;
entries++;
continue;
continue;
break;
}
}
}
if (!found_default) {
"to find entry for %s in the grub menu\n"),
be_name);
goto cleanup;
}
} else {
}
}
"failed to rename file %s to %s: %s\n"),
goto cleanup;
}
/* Set the perms and ownership of the updated file */
goto cleanup;
}
}
if (pool_mounted) {
int err = BE_SUCCESS;
if (ret == BE_SUCCESS)
}
}
return (ret);
}
/*
* Function: be_update_menu
* Description: This function is used by be_rename to change the BE name in
* an existing entry in the grub menu to the new name of the BE.
* Parameters:
* be_orig_name - the original name of the BE
* be_new_name - the new name the BE is being renameed to.
* be_root_pool - The pool which contains the grub menu
* boot_pool - the pool where the BE is, if different than
* the pool containing the boot menu. If this is
* NULL it will be set to be_root_pool.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
char *boot_pool)
{
char menu_file[MAXPATHLEN];
char be_root_ds[MAXPATHLEN];
char be_new_root_ds[MAXPATHLEN];
char *pool_mntpnt = NULL;
char *ptmp_mntpnt = NULL;
char *orig_mntpnt = NULL;
int temp_menu_len = 0;
int tmp_fd;
int ret = BE_SUCCESS;
int err = 0;
errno = 0;
"pool dataset for %s: %s\n"), be_root_pool,
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.
*/
&pool_mounted)) != BE_SUCCESS) {
"(%s) could not be mounted\n"), be_root_pool);
return (ret);
}
/*
* Get the mountpoint for the root pool dataset.
*/
"to get mount point for the root pool. Can't set "
"the default BE in the grub menu.\n"));
goto cleanup;
}
/*
* Check to see if this system supports grub
*/
if (be_has_grub()) {
} else {
}
sizeof (be_root_ds));
sizeof (be_new_root_ds));
goto cleanup;
goto cleanup;
}
pool_mntpnt = NULL;
/* Grab the stat of the original menu file */
goto cleanup;
}
/* Create tmp file for modified menu.lst */
== NULL) {
"malloc failed\n"));
ret = BE_ERR_NOMEM;
goto cleanup;
}
goto cleanup;
}
goto cleanup;
}
char *c = NULL;
/* Tokenize line */
if (c == NULL) {
/* Found empty line, write it out. */
} else if (c[0] == '#') {
/* Found a comment line, write it out. */
} else if (strcmp(c, "title") == 0) {
/*
* Found a 'title' line, parse out BE name or
* the description.
*/
/*
* Nothing after 'title', just push
* this line through
*/
} else {
/*
* Grab the remainder of the title which
* could be a multi worded description
*/
/*
* The first token of the title is
* the old BE name, replace it with
* the new one, and write it out
* along with the remainder of
* description if there is one.
*/
if (desc) {
sizeof (new_line),
"title %s %s\n",
be_new_name, desc);
} else {
sizeof (new_line),
"title %s\n", be_new_name);
}
} else {
}
}
} else if (strcmp(c, "bootfs") == 0) {
/*
* Found a 'bootfs' line, parse out the BE root
* dataset value.
*/
/*
* Nothing after 'bootfs', just push
* this line through
*/
} else {
/*
* If this bootfs is the one we're renaming,
* write out the new root dataset value
*/
sizeof (new_line), "bootfs %s\n",
} else {
}
}
} else {
/*
* Found some other line we don't care
* about, write it out.
*/
}
}
"failed to rename file %s to %s: %s\n"),
}
/* Set the perms and ownership of the updated file */
goto cleanup;
}
}
if (pool_mounted) {
int err = BE_SUCCESS;
if (ret == BE_SUCCESS)
}
return (ret);
}
/*
* Function: be_has_menu_entry
* Description: Checks to see if the BEs root dataset has an entry in the grub
* menu.
* Parameters:
* be_dataset - The root dataset of the BE
* be_root_pool - The pool which contains the boot menu
* entry - A pointer the the entry number of the BE if found.
* Returns:
* B_TRUE - Success
* B_FALSE - Failure
* Scope:
* Semi-private (library wide use only)
*/
{
char menu_file[MAXPATHLEN];
char *last;
char *rpool_mntpnt = NULL;
char *ptmp_mntpnt = NULL;
char *orig_mntpnt = NULL;
int ent_num = 0;
/*
* Check to see if this system supports grub
*/
"pool dataset for %s: %s\n"), be_root_pool,
return (B_FALSE);
}
/*
* Check to see if the pool's dataset is mounted. If it isn't we'll
* attempt to mount it.
*/
&pool_mounted) != 0) {
"(%s) could not be mounted\n"), be_root_pool);
return (B_FALSE);
}
/*
* Get the mountpoint for the root pool dataset.
*/
"dataset (%s) is not mounted. Can't set "
"the default BE in the grub menu.\n"), be_root_pool);
goto cleanup;
}
if (be_has_grub()) {
} else {
}
B_FALSE) != 0) {
goto cleanup;
goto cleanup;
}
rpool_mntpnt = NULL;
be_dataset) == 0) {
/*
* The entry number needs to be
* decremented here because the title
* will always be the first line for
* an entry. Because of this we'll
* always be off by one entry when we
* check for bootfs.
*/
goto cleanup;
}
ent_num++;
}
}
if (pool_mounted) {
}
return (ret);
}
/*
* Function: be_update_vfstab
* Description: This function digs into a BE's vfstab and updates all
* entries with file systems listed in be_fs_list_data_t.
* The entry's root container dataset and be_name will be
* updated with the parameters passed in.
* Parameters:
* be_name - name of BE to update
* old_rc_loc - dataset under which the root container dataset
* of the old BE resides in.
* new_rc_loc - dataset under which the root container dataset
* of the new BE resides in.
* fld - be_fs_list_data_t pointer providing the list of
* file systems to look for in vfstab.
* mountpoint - directory of where BE is currently mounted.
* If NULL, then BE is not currently mounted.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
{
char *tmp_mountpoint = NULL;
char alt_vfstab[MAXPATHLEN];
return (BE_SUCCESS);
/* If BE not already mounted, mount the BE */
if (mountpoint == NULL) {
BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
"failed to mount BE (%s)\n"), be_name);
return (ret);
}
} else {
}
/* Get string for vfstab in the mounted BE. */
/* Update the vfstab */
fld);
/* Unmount BE if we mounted it */
if (mountpoint == NULL) {
/* Remove temporary mountpoint */
(void) rmdir(tmp_mountpoint);
} else {
"failed to unmount BE %s mounted at %s\n"),
if (ret == BE_SUCCESS)
}
}
return (ret);
}
/*
* Function: be_update_zone_vfstab
* Description: This function digs into a zone BE's vfstab and updates all
* entries with file systems listed in be_fs_list_data_t.
* The entry's root container dataset and be_name will be
* updated with the parameters passed in.
* Parameters:
* zhp - zfs_handle_t pointer to zone root dataset.
* be_name - name of zone BE to update
* old_rc_loc - dataset under which the root container dataset
* of the old zone BE resides in.
* new_rc_loc - dataset under which the root container dataset
* of the new zone BE resides in.
* fld - be_fs_list_data_t pointer providing the list of
* file systems to look for in vfstab.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Semi-private (library wide use only)
*/
int
{
be_mount_data_t md = { 0 };
be_unmount_data_t ud = { 0 };
char alt_vfstab[MAXPATHLEN];
int ret = BE_SUCCESS;
/*
* If zone root not already mounted, mount it at a
* temporary location.
*/
/* Generate temporary mountpoint to mount zone root */
"failed to make temporary mountpoint to "
"mount zone root\n"));
return (ret);
}
"failed to mount zone root %s\n"),
zfs_get_name(zhp));
return (BE_ERR_MOUNT_ZONEROOT);
}
}
/* Get string from vfstab in the mounted zone BE */
/* Update the vfstab */
fld);
/* Unmount zone root if we mounted it */
if (mounted_here) {
/* Remove the temporary mountpoint */
} else {
"failed to unmount zone root %s from %s\n"),
if (ret == 0)
}
}
return (ret);
}
/*
* Function: be_auto_snap_name
* Description: Generate an auto snapshot name constructed based on the
* current date and time. The auto snapshot name is of the form:
*
* <date>-<time>
*
* where <date> is in ISO standard format, so the resultant name
* is of the form:
*
* %Y-%m-%d-%H:%M:%S
*
* Parameters:
* None
* Returns:
* Success - pointer to auto generated snapshot name. The name
* is allocated in heap storage so the caller is
* responsible for free'ing the name.
* Failure - NULL
* Scope:
* Semi-private (library wide use only)
*/
char *
be_auto_snap_name(void)
{
char gmt_time_str[64];
char *auto_snap_name = NULL;
return (NULL);
}
return (NULL);
}
"memory allocation failed\n"));
return (NULL);
}
return (auto_snap_name);
}
/*
* Function: be_auto_be_name
* Description: Generate an auto BE name constructed based on the BE name
* of the original BE being cloned.
* Parameters:
* obe_name - name of the original BE being cloned.
* Returns:
* Success - pointer to auto generated BE name. The name
* is allocated in heap storage so the caller is
* responsible for free'ing the name.
* Failure - NULL
* Scope:
* Semi-private (library wide use only)
*/
char *
be_auto_be_name(char *obe_name)
{
}
/*
* Function: be_auto_zone_be_name
* Description: Generate an auto BE name for a zone constructed based on
* the BE name of the original zone BE being cloned.
* Parameters:
* container_ds - container dataset for the zone.
* zbe_name - name of the original zone BE being cloned.
* Returns:
* Success - pointer to auto generated BE name. The name
* is allocated in heap storage so the caller is
* responsible for free'ing the name.
* Failure - NULL
* Scope:
* Semi-private (library wide use only)
*/
char *
{
}
/*
* Function: be_valid_be_name
* Description: Validates a BE name.
* Parameters:
* be_name - name of BE to validate
* Returns:
* B_TRUE - be_name is valid
* B_FALSE - be_name is invalid
* Scope:
* Semi-private (library wide use only)
*/
be_valid_be_name(const char *be_name)
{
const char *c = NULL;
struct be_defaults be_defaults;
return (B_FALSE);
/*
* A BE name must not be a multi-level dataset name. We also check
* that it does not contain the ' ' and '%' characters. The ' ' is
* a valid character for datasets, however we don't allow that in a
* BE name. The '%' is invalid, but zfs_name_valid() allows it for
* internal reasons, so we explicitly check for it here.
*/
c = be_name;
while (*c != '\0' && *c != '/' && *c != ' ' && *c != '%')
c++;
if (*c != '\0')
return (B_FALSE);
/*
* The BE name must comply with a zfs dataset filesystem. We also
* verify its length to be < BE_NAME_MAX_LEN.
*/
return (B_FALSE);
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Function: be_valid_auto_snap_name
* Description: This function checks that a snapshot name is a valid auto
* generated snapshot name. A valid auto generated snapshot
* name is of the form:
*
* %Y-%m-%d-%H:%M:%S
*
* An older form of the auto generated snapshot name also
* included the snapshot's BE cleanup policy and a reserved
* field. Those names will also be verified by this function.
*
* Examples of valid auto snapshot names are:
*
* 2008-03-31-18:41:30
* 2008-03-31-22:17:24
* <policy>:-:2008:04-05-09:12:55
* <policy>:-:2008:04-06-15:34:12
*
* Parameters:
* name - name of the snapshot to be validated.
* Returns:
* B_TRUE - the name is a valid auto snapshot name.
* B_FALSE - the name is not a valid auto snapshot name.
* Scope:
* Semi-private (library wide use only)
*/
be_valid_auto_snap_name(char *name)
{
char *c = NULL;
/* Validate the snapshot name by converting it into utc time */
return (B_TRUE);
}
/*
* Validate the snapshot name against the older form of an
* auto generated snapshot name.
*/
/*
* Get the first field from the snapshot name,
* which is the BE policy
*/
if (c == NULL) {
return (B_FALSE);
}
c[0] = '\0';
/* Validate the policy name */
if (!valid_be_policy(policy)) {
return (B_FALSE);
}
/* Get the next field, which is the reserved field. */
return (B_FALSE);
}
reserved = c+1;
if (c == NULL) {
return (B_FALSE);
}
c[0] = '\0';
/* Validate the reserved field */
return (B_FALSE);
}
/* The remaining string should be the date field */
return (B_FALSE);
}
date = c+1;
/* Validate the date string by converting it into utc time */
"invalid auto snapshot name\n"));
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Function: be_default_policy
* Description: Temporary hardcoded policy support. This function returns
* the default policy type to be used to create a BE or a BE
* snapshot.
* Parameters:
* None
* Returns:
* Name of default BE policy.
* Scope:
* Semi-private (library wide use only)
*/
char *
be_default_policy(void)
{
return (BE_PLCY_STATIC);
}
/*
* Function: valid_be_policy
* Description: Temporary hardcoded policy support. This function valids
* whether a policy is a valid known policy or not.
* Paramters:
* policy - name of policy to validate.
* Returns:
* B_TRUE - policy is a valid.
* B_FALSE - policy is invalid.
* Scope:
* Semi-private (library wide use only)
*/
valid_be_policy(char *policy)
{
return (B_FALSE);
return (B_TRUE);
}
return (B_FALSE);
}
/*
* Function: be_print_err
* Description: This function prints out error messages if do_print is
* set to B_TRUE or if the BE_PRINT_ERR environment variable
* is set to true.
* Paramters:
* prnt_str - the string we wish to print and any arguments
* for the format of that string.
* Returns:
* void
* Scope:
* Semi-private (library wide use only)
*/
void
be_print_err(char *prnt_str, ...)
{
char *env_buf;
if (!env_checked) {
}
}
}
if (do_print) {
/* LINTED variable format specifier */
}
}
/*
* Function: be_find_current_be
* Description: Find the currently "active" BE. Fill in the
* passed in be_transaction_data_t reference with the
* active BE's data.
* Paramters:
* none
* Returns:
* BE_SUCCESS - Success
* be_errnot_t - Failure
* Scope:
* Semi-private (library wide use only)
* Notes:
* The caller is responsible for initializing the libzfs handle
* and freeing the memory used by the active be_name.
*/
int
{
int zret;
bt)) == 0) {
"find current BE name\n"));
return (BE_ERR_BE_NOENT);
} else if (zret < 0) {
"zpool_iter failed: %s\n"),
return (zfs_err_to_be_err(g_zfs));
}
return (BE_SUCCESS);
}
/*
* Function: be_zpool_find_current_be_callback
* Description: Callback function used to iterate through all existing pools
* to find the BE that is the currently booted BE.
* Parameters:
* zlp - zpool_handle_t pointer to the current pool being
* looked at.
* data - be_transaction_data_t pointer.
* Upon successfully finding the current BE, the
* obe_zpool member of this parameter is set to the
* pool it is found in.
* Return:
* 1 - Found current BE in this pool.
* 0 - Did not find current BE in this pool.
* Scope:
* Semi-private (library wide use only)
*/
int
{
char be_container_ds[MAXPATHLEN];
/*
* Generate string for BE container dataset
*/
/*
* Check if a BE container dataset exists in this pool.
*/
return (0);
}
/*
* Get handle to this zpool's BE container dataset.
*/
NULL) {
"failed to open BE container dataset (%s)\n"),
return (0);
}
/*
* Iterate through all potential BEs in this zpool
*/
/*
* Found current BE dataset; set obe_zpool
*/
"be_zpool_find_current_be_callback: "
"memory allocation failed\n"));
return (0);
}
return (1);
}
return (0);
}
/*
* Function: be_zfs_find_current_be_callback
* Description: Callback function used to iterate through all BEs in a
* pool to find the BE that is the currently booted BE.
* Parameters:
* zhp - zfs_handle_t pointer to current filesystem being checked.
* data - be_transaction-data_t pointer
* Upon successfully finding the current BE, the
* obe_name and obe_root_ds members of this parameter
* are set to the BE name and BE's root dataset
* respectively.
* Return:
* 1 - Found current BE.
* 0 - Did not find current BE.
* Scope:
* Semi-private (library wide use only)
*/
int
{
/*
* Check if dataset is mounted, and if so where.
*/
/*
* If mounted at root, set obe_root_ds and obe_name
*/
== NULL) {
"be_zfs_find_current_be_callback: "
"memory allocation failed\n"));
return (0);
}
== NULL) {
"be_zfs_find_current_be_callback: "
"memory allocation failed\n"));
return (0);
}
return (1);
}
}
return (0);
}
/*
* Function: be_check_be_roots_callback
* Description: This function checks whether or not the dataset name passed
* is hierachically located under the BE root container dataset
* for this pool.
* Parameters:
* zlp - zpool_handle_t pointer to current pool being processed.
* data - name of dataset to check
* Returns:
* 0 - dataset is not in this pool's BE root container dataset
* 1 - dataset is in this pool's BE root container dataset
* Scope:
* Semi-private (library wide use only)
*/
int
{
char be_container_ds[MAXPATHLEN];
/* Generate string for this pool's BE root container dataset */
/*
* If dataset lives under the BE root container dataset
* of this pool, return failure.
*/
return (1);
}
return (0);
}
/*
* Function: zfs_err_to_be_err
* Description: This function takes the error stored in the libzfs handle
* and maps it to an be_errno_t. If there are no matching
* be_errno_t's then BE_ERR_ZFS is returned.
* Paramters:
* zfsh - The libzfs handle containing the error we're looking up.
* Returns:
* be_errno_t
* Scope:
* Semi-private (library wide use only)
*/
int
{
switch (err) {
case 0:
return (BE_SUCCESS);
case EZFS_PERM:
return (BE_ERR_PERM);
case EZFS_INTR:
return (BE_ERR_INTR);
case EZFS_NOENT:
return (BE_ERR_NOENT);
case EZFS_NOSPC:
return (BE_ERR_NOSPC);
case EZFS_MOUNTFAILED:
return (BE_ERR_MOUNT);
case EZFS_UMOUNTFAILED:
return (BE_ERR_UMOUNT);
case EZFS_EXISTS:
return (BE_ERR_BE_EXISTS);
case EZFS_BUSY:
return (BE_ERR_DEV_BUSY);
case EZFS_POOLREADONLY:
return (BE_ERR_ROFS);
case EZFS_NAMETOOLONG:
return (BE_ERR_NAMETOOLONG);
case EZFS_NODEVICE:
return (BE_ERR_NODEV);
case EZFS_POOL_INVALARG:
return (BE_ERR_INVAL);
case EZFS_PROPTYPE:
return (BE_ERR_INVALPROP);
case EZFS_BADTYPE:
return (BE_ERR_DSTYPE);
case EZFS_PROPNONINHERIT:
return (BE_ERR_NONINHERIT);
case EZFS_PROPREADONLY:
return (BE_ERR_READONLYPROP);
case EZFS_RESILVERING:
case EZFS_POOLUNAVAIL:
return (BE_ERR_UNAVAIL);
case EZFS_DSREADONLY:
return (BE_ERR_READONLYDS);
default:
return (BE_ERR_ZFS);
}
}
/*
* Function: errno_to_be_err
* Description: This function takes an errno and maps it to an be_errno_t.
* If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
* returned.
* Paramters:
* err - The errno we're compairing against.
* Returns:
* be_errno_t
* Scope:
* Semi-private (library wide use only)
*/
int
errno_to_be_err(int err)
{
switch (err) {
case EPERM:
return (BE_ERR_PERM);
case EACCES:
return (BE_ERR_ACCESS);
case ECANCELED:
return (BE_ERR_CANCELED);
case EINTR:
return (BE_ERR_INTR);
case ENOENT:
return (BE_ERR_NOENT);
case ENOSPC:
case EDQUOT:
return (BE_ERR_NOSPC);
case EEXIST:
return (BE_ERR_BE_EXISTS);
case EBUSY:
return (BE_ERR_BUSY);
case EROFS:
return (BE_ERR_ROFS);
case ENAMETOOLONG:
return (BE_ERR_NAMETOOLONG);
case ENXIO:
return (BE_ERR_NXIO);
case EINVAL:
return (BE_ERR_INVAL);
case EFAULT:
return (BE_ERR_FAULT);
default:
return (BE_ERR_UNKNOWN);
}
}
/*
* Function: be_err_to_str
* Description: This function takes a be_errno_t and maps it to a message.
* If there are no matching be_errno_t's then NULL is returned.
* Paramters:
* be_errno_t - The be_errno_t we're mapping.
* Returns:
* string or NULL if the error code is not known.
* Scope:
* Semi-private (library wide use only)
*/
char *
be_err_to_str(int err)
{
switch (err) {
case BE_ERR_ACCESS:
return (gettext("Permission denied."));
case BE_ERR_ACTIVATE_CURR:
return (gettext("Activation of current BE failed."));
case BE_ERR_AUTONAME:
return (gettext("Auto naming failed."));
case BE_ERR_BE_NOENT:
return (gettext("No such BE."));
case BE_ERR_BUSY:
return (gettext("Mount busy."));
case BE_ERR_DEV_BUSY:
return (gettext("Device busy."));
case BE_ERR_CANCELED:
return (gettext("Operation canceled."));
case BE_ERR_CLONE:
return (gettext("BE clone failed."));
case BE_ERR_COPY:
return (gettext("BE copy failed."));
case BE_ERR_CREATDS:
return (gettext("Dataset creation failed."));
case BE_ERR_CURR_BE_NOT_FOUND:
return (gettext("Can't find current BE."));
case BE_ERR_DESTROY:
return (gettext("Failed to destroy BE or snapshot."));
case BE_ERR_DESTROY_CURR_BE:
return (gettext("Cannot destroy current BE."));
case BE_ERR_DEMOTE:
return (gettext("BE demotion failed."));
case BE_ERR_DSTYPE:
return (gettext("Invalid dataset type."));
case BE_ERR_BE_EXISTS:
return (gettext("BE exists."));
case BE_ERR_INIT:
return (gettext("be_zfs_init failed."));
case BE_ERR_INTR:
return (gettext("Interupted system call."));
case BE_ERR_INVAL:
return (gettext("Invalid argument."));
case BE_ERR_INVALPROP:
return (gettext("Invalid property for dataset."));
case BE_ERR_INVALMOUNTPOINT:
return (gettext("Unexpected mountpoint."));
case BE_ERR_MOUNT:
return (gettext("Mount failed."));
case BE_ERR_MOUNTED:
return (gettext("Already mounted."));
case BE_ERR_NAMETOOLONG:
return (gettext("name > BUFSIZ."));
case BE_ERR_NOENT:
return (gettext("Doesn't exist."));
case BE_ERR_POOL_NOENT:
return (gettext("No such pool."));
case BE_ERR_NODEV:
return (gettext("No such device."));
case BE_ERR_NOTMOUNTED:
return (gettext("File system not mounted."));
case BE_ERR_NOMEM:
return (gettext("Not enough memory."));
case BE_ERR_NONINHERIT:
return (gettext(
"Property is not inheritable for the BE dataset."));
case BE_ERR_NXIO:
return (gettext("No such device or address."));
case BE_ERR_NOSPC:
return (gettext("No space on device."));
case BE_ERR_NOTSUP:
return (gettext("Operation not supported."));
case BE_ERR_OPEN:
return (gettext("Open failed."));
case BE_ERR_PERM:
return (gettext("Not owner."));
case BE_ERR_UNAVAIL:
return (gettext("The BE is currently unavailable."));
case BE_ERR_PROMOTE:
return (gettext("BE promotion failed."));
case BE_ERR_ROFS:
return (gettext("Read only file system."));
case BE_ERR_READONLYDS:
return (gettext("Read only dataset."));
case BE_ERR_READONLYPROP:
return (gettext("Read only property."));
case BE_ERR_RENAME_ACTIVE:
return (gettext("Renaming the active BE is not supported."));
case BE_ERR_SS_EXISTS:
return (gettext("Snapshot exists."));
case BE_ERR_SS_NOENT:
return (gettext("No such snapshot."));
case BE_ERR_UMOUNT:
return (gettext("Unmount failed."));
case BE_ERR_UMOUNT_CURR_BE:
return (gettext("Can't unmount the current BE."));
case BE_ERR_UMOUNT_SHARED:
return (gettext("Unmount of a shared File System failed."));
case BE_ERR_FAULT:
return (gettext("Bad address."));
case BE_ERR_UNKNOWN:
return (gettext("Unknown error."));
case BE_ERR_ZFS:
return (gettext("ZFS returned an error."));
case BE_ERR_GEN_UUID:
return (gettext("Failed to generate uuid."));
case BE_ERR_PARSE_UUID:
return (gettext("Failed to parse uuid."));
case BE_ERR_NO_UUID:
return (gettext("No uuid"));
case BE_ERR_ZONE_NO_PARENTBE:
return (gettext("No parent uuid"));
return (gettext("Multiple active zone roots"));
return (gettext("No active zone root"));
return (gettext("Zone root not legacy"));
case BE_ERR_MOUNT_ZONEROOT:
return (gettext("Failed to mount a zone root."));
case BE_ERR_UMOUNT_ZONEROOT:
return (gettext("Failed to unmount a zone root."));
case BE_ERR_NO_MOUNTED_ZONE:
return (gettext("Zone is not mounted"));
case BE_ERR_ZONES_UNMOUNT:
return (gettext("Unable to unmount a zone BE."));
case BE_ERR_NO_MENU:
return (gettext("Missing boot menu file."));
case BE_ERR_BAD_MENU_PATH:
return (gettext("Invalid path for menu.lst file"));
case BE_ERR_ZONE_SS_EXISTS:
return (gettext("Zone snapshot exists."));
case BE_ERR_BOOTFILE_INST:
return (gettext("Error installing boot files."));
case BE_ERR_EXTCMD:
return (gettext("Error running an external command."));
default:
return (NULL);
}
}
/*
* Function: be_has_grub
* Description: Boolean function indicating whether the current system
* uses grub.
* Return: B_FALSE - the system does not have grub
* B_TRUE - the system does have grub.
* Scope:
* Semi-private (library wide use only)
*/
be_has_grub(void)
{
/*
* TODO: This will need to be expanded to check for the existence of
* grub if and when there is grub support for SPARC.
*/
return (be_is_isa("i386"));
}
/*
* Function: be_is_isa
* Description: Boolean function indicating whether the instruction set
* architecture of the executing system matches the name provided.
* The string must match a system defined architecture (e.g.
* "i386", "sparc") and is case sensitive.
* Parameters: name - string representing the name of instruction set
* architecture being tested
* Returns: B_FALSE - the system instruction set architecture is different
* from the one specified
* B_TRUE - the system instruction set architecture is the same
* as the one specified
* Scope:
* Semi-private (library wide use only)
*/
{
}
/*
* Function: be_get_default_isa
* Description:
* Returns the default instruction set architecture of the
* machine it is executed on. (eg. sparc, i386, ...)
* NOTE: SYS_INST environment variable may override default
* return value
* Parameters:
* none
* Returns:
* NULL - the architecture returned by sysinfo() was too
* long for local variables
* char * - pointer to a string containing the default
* implementation
* Scope:
* Semi-private (library wide use only)
*/
char *
be_get_default_isa(void)
{
int i;
char *envp;
if (default_inst[0] == '\0') {
return (NULL);
else
} else {
if (i < 0 || i > ARCH_LENGTH)
return (NULL);
}
}
return (default_inst);
}
/*
* Function: be_run_cmd
* Description:
* Runs a command in a separate subprocess. Splits out stdout from stderr
* and sends each to its own buffer. Buffers must be pre-allocated and
* passed in as arguments. Buffer sizes are also passed in as arguments.
*
* Notes / caveats:
* - Command being run is assumed to not have any stdout or stderr
* redirection.
* - Commands which emit total stderr output of greater than PIPE_BUF
* bytes can hang. For such commands, a different implementation
* which uses poll(2) must be used.
* - stdout_buf can be NULL. In this case, stdout_bufsize is ignored, and
* the stream which would have gone to it is sent to the bit
* bucket.
* - stderr_buf cannot be NULL.
* - Only subprocess errors are appended to the stderr_buf. Errors
* running the command are reported through be_print_err().
* - Data which would overflow its respective buffer is sent to the bit
* bucket.
*
* Parameters:
* command: command to run. Assumed not to have embedded stdout
* or stderr redirection. May have stdin redirection,
* however.
* stderr_buf: buffer returning subprocess stderr data. Errors
* reported by this function are reported through
* be_print_err().
* stderr_bufsize: size of stderr_buf
* stdout_buf: buffer returning subprocess stdout data.
* stdout_bufsize: size of stdout_buf
* Returns:
* BE_SUCCESS - The command ran successfully without returning
* errors.
* BE_ERR_EXTCMD
* - The command could not be run.
* - The command terminated with error status.
* - There were errors extracting or returning subprocess
* data.
* BE_ERR_NOMEM - The command exceeds the command buffer size.
* BE_ERR_INVAL - An invalid argument was specified.
* Scope:
* Semi-private (library wide use only)
*/
int
char *stdout_buf, int stdout_bufsize)
{
int exit_status;
int rval = BE_SUCCESS;
(stderr_bufsize <= 0) || (stdout_bufsize < 0) ||
return (BE_ERR_INVAL);
}
/* Set up command so popen returns stderr, not stdout */
temp_filename) >= BUFSIZ) {
rval = BE_ERR_NOMEM;
goto cleanup;
}
/* Set up the fifo that will make stderr available. */
goto cleanup;
}
goto cleanup;
}
(void) pclose(stdout_str);
goto cleanup;
}
/* Read stdout first, as it usually outputs more than stderr. */
if (stdout_str != NULL) {
}
}
}
/* Close pipe, get exit status. */
} else if (WIFEXITED(exit_status)) {
if (exit_status != 0) {
"command terminated with error status: %d\n"),
}
} else {
"terminated on signal: %s\n"),
}
(void) unlink(temp_filename);
(void) free(temp_filename);
return (rval);
}
/* ******************************************************************** */
/* Private Functions */
/* ******************************************************************** */
/*
* Function: update_dataset
* Description: This function takes a dataset name and replaces the zpool
* and be_name components of the dataset with the new be_name
* zpool passed in.
* Parameters:
* dataset - name of dataset
* dataset_len - lenth of buffer in which dataset is passed in.
* be_name - name of new BE name to update to.
* old_rc_loc - dataset under which the root container dataset
* for the old BE lives.
* new_rc_loc - dataset under which the root container dataset
* for the new BE lives.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
char *old_rc_loc, char *new_rc_loc)
{
/* Tear off the BE container dataset */
return (BE_ERR_INVAL);
}
/* Get dataset name relative to BE root, if there is one */
/* Generate the BE root dataset name */
/* If a subordinate dataset name was found, append it */
return (BE_SUCCESS);
}
/*
* Function: _update_vfstab
* Description: This function updates a vfstab file to reflect the new
* root container dataset location and be_name for all
* entries listed in the be_fs_list_data_t structure passed in.
* Parameters:
* vfstab - vfstab file to modify
* be_name - name of BE to update.
* old_rc_loc - dataset under which the root container dataset
* of the old BE resides in.
* new_rc_loc - dataset under which the root container dataset
* of the new BE resides in.
* fld - be_fs_list_data_t pointer providing the list of
* file systems to look for in vfstab.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
{
char *tmp_vfstab = NULL;
char comments_buf[BUFSIZ];
char dev[MAXPATHLEN];
char *c;
int fd;
int i;
int tmp_vfstab_len = 0;
errno = 0;
/*
* Open vfstab for reading twice. First is for comments,
* second is for actual entries.
*/
"failed to open vfstab (%s): %s\n"), vfstab,
goto cleanup;
}
/* Grab the stats of the original vfstab file */
"failed to stat file %s: %s\n"), vfstab,
goto cleanup;
}
/* Create tmp file for modified vfstab */
== NULL) {
"malloc failed\n"));
ret = BE_ERR_NOMEM;
goto cleanup;
}
goto cleanup;
}
"could not open file for write\n"));
goto cleanup;
}
;
if (*c == '\0') {
continue;
} else if (*c == '#') {
/*
* If line is a comment line, just put
* it through to the tmp vfstab.
*/
} else {
/*
* Else line is a vfstab entry, grab it
* into a vfstab struct.
*/
goto cleanup;
}
continue;
}
/*
* If the entry is one of the entries in the list
* of file systems to update, modify it's device
* field to be correct for this BE.
*/
== 0) {
/*
* Found entry that needs an update.
* Replace the root container dataset
* location and be_name in the
* entry's device.
*/
sizeof (dev));
new_rc_loc)) != 0) {
gettext("_update_vfstab: "
"Failed to update device "
"field for vfstab entry "
goto cleanup;
}
break;
}
}
/* Put entry through to tmp vfstab */
}
}
/* Copy tmp vfstab into place */
"failed to rename file %s to %s: %s\n"), tmp_vfstab,
goto cleanup;
}
/* Set the perms and ownership of the updated file */
goto cleanup;
}
goto cleanup;
}
(void) unlink(tmp_vfstab);
(void) free(tmp_vfstab);
return (ret);
}
/*
* Function: be_get_auto_name
* Description: Generate an auto name constructed based on the BE name
* of the original BE or zone BE being cloned.
* Parameters:
* obe_name - name of the original BE or zone BE being cloned.
* container_ds - container dataset for the zone.
* Note: if zone_be is false this should be
* NULL.
* zone_be - flag that indicates if we are operating on a zone BE.
* Returns:
* Success - pointer to auto generated BE name. The name
* is allocated in heap storage so the caller is
* responsible for free'ing the name.
* Failure - NULL
* Scope:
* Private
*/
static char *
{
char auto_be_name[MAXPATHLEN];
char base_be_name[MAXPATHLEN];
char cur_be_name[MAXPATHLEN];
char *c = NULL;
int num = 0;
int cur_num = 0;
errno = 0;
/*
* Check if obe_name is already in an auto BE name format.
* If it is, then strip off the increment number to get the
* base name.
*/
!= NULL) {
/* Make sure remaining string is all digits */
c = num_str + 1;
while (c[0] != '\0' && isdigit(c[0]))
c++;
/*
* If we're now at the end of the string strip off the
* increment number.
*/
if (c[0] == '\0')
num_str[0] = '\0';
}
if (zone_be) {
if (be_container_ds == NULL)
return (NULL);
&be_nodes) != BE_SUCCESS) {
"be_get_zone_be_list failed\n"));
return (NULL);
}
return (NULL);
}
sizeof (cur_be_name));
/* If cur_be_name doesn't match at least base be name, skip. */
!= 0)
continue;
/* Get the string following the base be name */
/*
* If nothing follows the base be name, this cur_be_name
* is the BE named with the base be name, skip.
*/
continue;
/*
* Remove the name delimiter. If its not there,
* cur_be_name isn't part of this BE name stream, skip.
*/
if (num_str[0] == BE_AUTO_NAME_DELIM)
num_str++;
else
continue;
/* Make sure remaining string is all digits */
c = num_str;
while (c[0] != '\0' && isdigit(c[0]))
c++;
if (c[0] != '\0')
continue;
/* Convert the number string to an int */
/*
* If failed to convert the string, skip it. If its too
* long to be converted to an int, we wouldn't auto generate
* this number anyway so there couldn't be a conflict.
* We treat it as a manually created BE name.
*/
continue;
/*
* Compare current number to current max number,
* take higher of the two.
*/
}
/*
* Store off a copy of 'num' incase we need it later. If incrementing
* 'num' causes it to roll over, this means 'num' is the largest
* positive int possible; we'll need it later in the loop to determine
* if we've exhausted all possible increment numbers. We store it in
* 'cur_num'.
*/
/* Increment 'num' to get new auto BE name number */
if (++num <= 0) {
int ret = 0;
/*
* Since incrementing 'num' caused it to rollover, start
* over at 0 and find the first available number.
*/
if (ret == 0) {
/*
* BE name doesn't exist, break out
* to use 'num'.
*/
break;
} else if (ret == 1) {
/* BE name exists, continue looking */
continue;
} else {
"zpool_iter failed: %s\n"),
return (NULL);
}
}
/*
* If 'num' equals 'cur_num', we've exhausted all possible
* auto BE names for this base BE name.
*/
"No more available auto BE names for base "
"BE name %s\n"), base_be_name);
return (NULL);
}
}
/*
* Generate string for auto BE name.
*/
"memory allocation failed\n"));
return (NULL);
}
return (c);
}
/*
* Function: be_get_console_prop
* Description: Determine console device.
* Returns:
* Success - pointer to console setting.
* Failure - NULL
* Scope:
* Private
*/
static char *
be_get_console_prop(void)
{
"di_init() failed\n"));
return (NULL);
}
return (console);
}
}
}
/*
* Default console to text
*/
}
return (console);
}
/*
* Function: be_create_menu
* Description:
* This function is used if no menu.lst file exists. In
* this case a new file is created and if needed default
* lines are added to the file.
* Parameters:
* pool - The name of the pool the menu.lst file is on
* menu_file - The name of the file we're creating.
* menu_fp - A pointer to the file pointer of the file we
* created. This is also used to pass back the file
* pointer to the newly created file.
* mode - the original mode used for the failed attempt to
* non-existent file.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
char *pool,
char *menu_file,
char *mode)
{
errno = 0;
return (BE_ERR_INVAL);
return (BE_ERR_NOMEM);
if (*menu_path == '.') {
return (BE_ERR_BAD_MENU_PATH);
}
return (errno_to_be_err(errno));
}
/*
* Check to see if this system supports grub
*/
if (be_has_grub()) {
/*
* The grub menu is missing so we need to create it
* and fill in the first few lines.
*/
return (errno_to_be_err(errno));
}
/*
* If console is redirected to serial line,
* GRUB splash screen will not be enabled.
*/
strlen("graphics")) == 0) {
} else {
"console on serial line, "
"GRUB splash image will be disabled\n"));
}
}
} else {
/*
* The menu file doesn't exist so we need to create a
* blank file.
*/
return (errno_to_be_err(errno));
}
}
/*
* Now we need to add all the BE's back into the the file.
*/
}
if (be_nodes->be_active_on_boot) {
}
}
}
/*
* Check to see if this system supports grub
*/
if (be_has_grub()) {
if (err != BE_SUCCESS)
return (err);
}
return (errno_to_be_err(errno));
return (BE_SUCCESS);
}
/*
* Function: be_open_menu
* Description:
* This function is used it open the menu.lst file. If this
* file does not exist be_create_menu is called to create it
* and the open file pointer is returned. If the file does
* exist it is simply opened using the mode passed in.
* Parameters:
* pool - The name of the pool the menu.lst file is on
* menu_file - The name of the file we're opening.
* menu_fp - A pointer to the file pointer of the file we're
* opening. This is also used to pass back the file
* pointer.
* mode - the original mode to be used for opening the menu.lst
* file.
* create_menu - If this is true and the menu.lst file does not
* exist we will attempt to re-create it. However
* if it's false the error returned from the fopen
* will be returned.
* Returns:
* BE_SUCCESS - Success
* be_errno_t - Failure
* Scope:
* Private
*/
static int
char *pool,
char *menu_file,
char *mode,
{
int err = 0;
"file %s does not exist,\n"), menu_file);
if (!do_print) {
}
"file %s does not exist,\n generating "
"a new menu.lst file\n"), menu_file);
if (set_print)
err = 0;
return (BE_ERR_NO_MENU);
else if (err != BE_SUCCESS)
return (err);
return (BE_ERR_NO_MENU);
} else {
"to open menu.lst file %s\n"), menu_file);
return (BE_ERR_NO_MENU);
else
return (errno_to_be_err(err));
}
}
return (BE_SUCCESS);
}