4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2016 Toomas Soome <tsoome@me.com>
26 * Copyright (c) 2015 by Delphix. All rights reserved.
37 #include <libnvpair.h>
44 #include <sys/types.h>
45 #include <sys/vfstab.h>
46 #include <sys/param.h>
47 #include <sys/systeminfo.h>
54 #include <libdevinfo.h>
58 #include <libbe_priv.h>
59 #include <boot_utils.h>
61 #include <ficlplatform/emu.h>
63 /* Private function prototypes */
64 static int update_dataset(char *, int, char *, char *, char *);
65 static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t
*);
66 static int be_open_menu(char *, char *, FILE **, char *, boolean_t
);
67 static int be_create_menu(char *, char *, FILE **, char *);
68 static char *be_get_auto_name(char *, char *, boolean_t
);
71 * Global error printing
73 boolean_t do_print
= B_FALSE
;
78 typedef struct zone_be_name_cb_data
{
81 } zone_be_name_cb_data_t
;
83 /* ******************************************************************** */
84 /* Public Functions */
85 /* ******************************************************************** */
88 * Callback for ficl to suppress all output from ficl, as we do not
89 * want to confuse user with messages from ficl, and we are only
90 * checking results from function calls.
94 ficlSuppressTextOutput(ficlCallback
*cb
, char *text
)
96 /* This function is intentionally doing nothing. */
100 * Function: be_get_boot_args
101 * Description: Returns the fast boot argument string for enumerated BE.
103 * fbarg - pointer to argument string.
104 * entry - index of BE.
106 * fast boot argument string.
111 be_get_boot_args(char **fbarg
, int entry
)
113 be_node_list_t
*node
, *be_nodes
= NULL
;
114 be_transaction_data_t bt
= {0};
115 char *mountpoint
= NULL
;
116 boolean_t be_mounted
= B_FALSE
;
117 int ret
= BE_SUCCESS
;
123 return (BE_ERR_INIT
);
126 * need pool name, menu.lst has entries from our pool only
128 ret
= be_find_current_be(&bt
);
129 if (ret
!= BE_SUCCESS
) {
134 ret
= _be_list(NULL
, &be_nodes
);
135 if (ret
!= BE_SUCCESS
)
139 * iterate through be_nodes,
140 * if entry == -1, stop if be_active_on_boot,
141 * else stop if index == entry.
144 for (node
= be_nodes
; node
!= NULL
; node
= node
->be_next_node
) {
145 if (strcmp(node
->be_rpool
, bt
.obe_zpool
) != 0)
147 if (entry
== BE_ENTRY_DEFAULT
&&
148 node
->be_active_on_boot
== B_TRUE
)
155 be_free_list(be_nodes
);
160 /* try to mount inactive be */
161 if (node
->be_active
== B_FALSE
) {
162 ret
= _be_mount(node
->be_node_name
, &mountpoint
,
163 BE_MOUNT_FLAG_NO_ZONES
);
164 if (ret
!= BE_SUCCESS
&& ret
!= BE_ERR_MOUNTED
) {
165 be_free_list(be_nodes
);
171 vm
= bf_init("", ficlSuppressTextOutput
);
174 * zfs MAXNAMELEN is 256, so we need to pick buf large enough
175 * to contain such names.
177 char buf
[MAXNAMELEN
* 2];
178 char *kernel_options
= NULL
;
184 * just try to interpret following words. on error
185 * we will be missing kernelname, and will get out.
187 (void) snprintf(buf
, sizeof (buf
), "set currdev=zfs:%s:",
189 ret
= ficlVmEvaluate(vm
, buf
);
190 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
191 be_print_err(gettext("be_get_boot_args: error "
192 "interpreting boot config: %d\n"), ret
);
194 ret
= BE_ERR_NO_MENU
;
197 (void) snprintf(buf
, sizeof (buf
),
198 "include /boot/forth/loader.4th");
199 ret
= ficlVmEvaluate(vm
, buf
);
200 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
201 be_print_err(gettext("be_get_boot_args: error "
202 "interpreting boot config: %d\n"), ret
);
204 ret
= BE_ERR_NO_MENU
;
207 (void) snprintf(buf
, sizeof (buf
), "start");
208 ret
= ficlVmEvaluate(vm
, buf
);
209 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
210 be_print_err(gettext("be_get_boot_args: error "
211 "interpreting boot config: %d\n"), ret
);
213 ret
= BE_ERR_NO_MENU
;
216 (void) snprintf(buf
, sizeof (buf
), "boot");
217 ret
= ficlVmEvaluate(vm
, buf
);
219 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
220 be_print_err(gettext("be_get_boot_args: error "
221 "interpreting boot config: %d\n"), ret
);
222 ret
= BE_ERR_NO_MENU
;
226 kernel_options
= getenv("boot-args");
227 kernel
= getenv("kernelname");
229 if (kernel
== NULL
) {
230 be_print_err(gettext("be_get_boot_args: no kernel\n"));
235 if ((zph
= zpool_open(g_zfs
, node
->be_rpool
)) == NULL
) {
236 be_print_err(gettext("be_get_boot_args: failed to "
237 "open root pool (%s): %s\n"), node
->be_rpool
,
238 libzfs_error_description(g_zfs
));
239 ret
= zfs_err_to_be_err(g_zfs
);
242 ret
= zpool_get_physpath(zph
, buf
, sizeof (buf
));
245 be_print_err(gettext("be_get_boot_args: failed to "
250 /* zpool_get_physpath() can return space separated list */
252 tmp
= strsep(&tmp
, " ");
254 if (kernel_options
== NULL
|| *kernel_options
== '\0')
255 (void) asprintf(fbarg
, "/ %s "
256 "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel
,
257 node
->be_root_ds
, tmp
);
259 (void) asprintf(fbarg
, "/ %s %s "
260 "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel
,
261 kernel_options
, node
->be_root_ds
, tmp
);
270 if (be_mounted
== B_TRUE
)
271 (void) _be_unmount(node
->be_node_name
, BE_UNMOUNT_FLAG_FORCE
);
272 be_free_list(be_nodes
);
276 free(bt
.obe_root_ds
);
278 free(bt
.obe_snap_name
);
279 free(bt
.obe_altroot
);
285 * Function: be_max_avail
286 * Description: Returns the available size for the zfs dataset passed in.
288 * dataset - The dataset we want to get the available space for.
289 * ret - The available size will be returned in this.
291 * The error returned by the zfs get property function.
296 be_max_avail(char *dataset
, uint64_t *ret
)
301 /* Initialize libzfs handle */
303 return (BE_ERR_INIT
);
305 zhp
= zfs_open(g_zfs
, dataset
, ZFS_TYPE_DATASET
);
308 * The zfs_open failed return an error
310 err
= zfs_err_to_be_err(g_zfs
);
312 err
= be_maxsize_avail(zhp
, ret
);
320 * Function: libbe_print_errors
321 * Description: Turns on/off error output for the library.
323 * set_do_print - Boolean that turns library error
324 * printing on or off.
331 libbe_print_errors(boolean_t set_do_print
)
333 do_print
= set_do_print
;
336 /* ******************************************************************** */
337 /* Semi-Private Functions */
338 /* ******************************************************************** */
341 * Function: be_zfs_init
342 * Description: Initializes the libary global libzfs handle.
349 * Semi-private (library wide use only)
356 if ((g_zfs
= libzfs_init()) == NULL
) {
357 be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
366 * Function: be_zfs_fini
367 * Description: Closes the library global libzfs handle if it currently open.
373 * Semi-private (library wide use only)
385 * Function: be_get_defaults
386 * Description: Open defaults and gets be default paramets
388 * defaults - be defaults struct
392 * Semi-private (library wide use only)
395 be_get_defaults(struct be_defaults
*defaults
)
399 defaults
->be_deflt_rpool_container
= B_FALSE
;
400 defaults
->be_deflt_bename_starts_with
[0] = '\0';
402 if ((defp
= defopen_r(BE_DEFAULTS
)) != NULL
) {
403 const char *res
= defread_r(BE_DFLT_BENAME_STARTS
, defp
);
404 if (res
!= NULL
&& res
[0] != '\0') {
405 (void) strlcpy(defaults
->be_deflt_bename_starts_with
,
406 res
, ZFS_MAX_DATASET_NAME_LEN
);
407 defaults
->be_deflt_rpool_container
= B_TRUE
;
414 * Function: be_make_root_ds
415 * Description: Generate string for BE's root dataset given the pool
416 * it lives in and the BE name.
418 * zpool - pointer zpool name.
419 * be_name - pointer to BE name.
420 * be_root_ds - pointer to buffer to return BE root dataset in.
421 * be_root_ds_size - size of be_root_ds
425 * Semi-private (library wide use only)
428 be_make_root_ds(const char *zpool
, const char *be_name
, char *be_root_ds
,
431 struct be_defaults be_defaults
;
432 be_get_defaults(&be_defaults
);
433 char *root_ds
= NULL
;
435 if (getzoneid() == GLOBAL_ZONEID
) {
436 if (be_defaults
.be_deflt_rpool_container
) {
437 (void) snprintf(be_root_ds
, be_root_ds_size
,
438 "%s/%s", zpool
, be_name
);
440 (void) snprintf(be_root_ds
, be_root_ds_size
,
441 "%s/%s/%s", zpool
, BE_CONTAINER_DS_NAME
, be_name
);
445 * In non-global zone we can use path from mounted root dataset
446 * to generate BE's root dataset string.
448 if ((root_ds
= be_get_ds_from_dir("/")) != NULL
) {
449 (void) snprintf(be_root_ds
, be_root_ds_size
, "%s/%s",
450 dirname(root_ds
), be_name
);
452 be_print_err(gettext("be_make_root_ds: zone root "
453 "dataset is not mounted\n"));
460 * Function: be_make_container_ds
461 * Description: Generate string for the BE container dataset given a pool name.
463 * zpool - pointer zpool name.
464 * container_ds - pointer to buffer to return BE container
466 * container_ds_size - size of container_ds
470 * Semi-private (library wide use only)
473 be_make_container_ds(const char *zpool
, char *container_ds
,
474 int container_ds_size
)
476 struct be_defaults be_defaults
;
477 be_get_defaults(&be_defaults
);
478 char *root_ds
= NULL
;
480 if (getzoneid() == GLOBAL_ZONEID
) {
481 if (be_defaults
.be_deflt_rpool_container
) {
482 (void) snprintf(container_ds
, container_ds_size
,
485 (void) snprintf(container_ds
, container_ds_size
,
486 "%s/%s", zpool
, BE_CONTAINER_DS_NAME
);
489 if ((root_ds
= be_get_ds_from_dir("/")) != NULL
) {
490 (void) strlcpy(container_ds
, dirname(root_ds
),
493 be_print_err(gettext("be_make_container_ds: zone root "
494 "dataset is not mounted\n"));
501 * Function: be_make_name_from_ds
502 * Description: This function takes a dataset name and strips off the
503 * BE container dataset portion from the beginning. The
504 * returned name is allocated in heap storage, so the caller
505 * is responsible for freeing it.
507 * dataset - dataset to get name from.
508 * rc_loc - dataset underwhich the root container dataset lives.
510 * name of dataset relative to BE container dataset.
511 * NULL if dataset is not under a BE root dataset.
513 * Semi-primate (library wide use only)
516 be_make_name_from_ds(const char *dataset
, char *rc_loc
)
518 char ds
[ZFS_MAX_DATASET_NAME_LEN
];
521 struct be_defaults be_defaults
;
522 int rlen
= strlen(rc_loc
);
524 be_get_defaults(&be_defaults
);
527 * First token is the location of where the root container dataset
528 * lives; it must match rc_loc.
530 if (strncmp(dataset
, rc_loc
, rlen
) == 0 && dataset
[rlen
] == '/')
531 (void) strlcpy(ds
, dataset
+ rlen
+ 1, sizeof (ds
));
535 if (be_defaults
.be_deflt_rpool_container
) {
536 if ((name
= strdup(ds
)) == NULL
) {
537 be_print_err(gettext("be_make_name_from_ds: "
538 "memory allocation failed\n"));
542 /* Second token must be BE container dataset name */
543 if ((tok
= strtok(ds
, "/")) == NULL
||
544 strcmp(tok
, BE_CONTAINER_DS_NAME
) != 0)
547 /* Return the remaining token if one exists */
548 if ((tok
= strtok(NULL
, "")) == NULL
)
551 if ((name
= strdup(tok
)) == NULL
) {
552 be_print_err(gettext("be_make_name_from_ds: "
553 "memory allocation failed\n"));
562 * Function: be_maxsize_avail
563 * Description: Returns the available size for the zfs handle passed in.
565 * zhp - A pointer to the open zfs handle.
566 * ret - The available size will be returned in this.
568 * The error returned by the zfs get property function.
570 * Semi-private (library wide use only)
573 be_maxsize_avail(zfs_handle_t
*zhp
, uint64_t *ret
)
575 return ((*ret
= zfs_prop_get_int(zhp
, ZFS_PROP_AVAILABLE
)));
579 * Function: be_append_menu
580 * Description: Appends an entry for a BE into the menu.lst.
582 * be_name - pointer to name of BE to add boot menu entry for.
583 * be_root_pool - pointer to name of pool BE lives in.
584 * boot_pool - Used if the pool containing the menu is
585 * different than the one containing the BE. This
586 * will normally be NULL.
587 * be_orig_root_ds - The root dataset for the BE. This is
588 * used to check to see if an entry already exists
590 * description - pointer to description of BE to be added in
591 * the title line for this BEs entry.
593 * BE_SUCCESS - Success
594 * be_errno_t - Failure
596 * Semi-private (library wide use only)
599 be_append_menu(char *be_name
, char *be_root_pool
, char *boot_pool
,
600 char *be_orig_root_ds
, char *description
)
602 zfs_handle_t
*zhp
= NULL
;
603 char menu_file
[MAXPATHLEN
];
604 char be_root_ds
[MAXPATHLEN
];
606 char temp_line
[BUFSIZ
];
607 char title
[MAXPATHLEN
];
608 char *entries
[BUFSIZ
];
609 char *tmp_entries
[BUFSIZ
];
610 char *pool_mntpnt
= NULL
;
611 char *ptmp_mntpnt
= NULL
;
612 char *orig_mntpnt
= NULL
;
613 boolean_t found_be
= B_FALSE
;
614 boolean_t found_orig_be
= B_FALSE
;
615 boolean_t found_title
= B_FALSE
;
616 boolean_t pool_mounted
= B_FALSE
;
617 boolean_t collect_lines
= B_FALSE
;
618 FILE *menu_fp
= NULL
;
619 int err
= 0, ret
= BE_SUCCESS
;
620 int i
, num_tmp_lines
= 0, num_lines
= 0;
622 if (be_name
== NULL
|| be_root_pool
== NULL
)
623 return (BE_ERR_INVAL
);
625 if (boot_pool
== NULL
)
626 boot_pool
= be_root_pool
;
628 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
629 be_print_err(gettext("be_append_menu: failed to open "
630 "pool dataset for %s: %s\n"), be_root_pool
,
631 libzfs_error_description(g_zfs
));
632 return (zfs_err_to_be_err(g_zfs
));
636 * Check to see if the pool's dataset is mounted. If it isn't we'll
637 * attempt to mount it.
639 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
640 &pool_mounted
)) != BE_SUCCESS
) {
641 be_print_err(gettext("be_append_menu: pool dataset "
642 "(%s) could not be mounted\n"), be_root_pool
);
648 * Get the mountpoint for the root pool dataset.
650 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
651 be_print_err(gettext("be_append_menu: pool "
652 "dataset (%s) is not mounted. Can't append "
653 "the BE into the boot menu.\n"), be_root_pool
);
654 ret
= BE_ERR_NO_MENU
;
658 (void) snprintf(menu_file
, sizeof (menu_file
),
659 "%s%s", pool_mntpnt
, BE_SPARC_MENU
);
661 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
664 * Iterate through menu first to make sure the BE doesn't already
665 * have an entry in the menu.
667 * Additionally while iterating through the menu, if we have an
668 * original root dataset for a BE we're cloning from, we need to keep
669 * track of that BE's menu entry. We will then use the lines from
670 * that entry to create the entry for the new BE.
672 if ((ret
= be_open_menu(be_root_pool
, menu_file
,
673 &menu_fp
, "r", B_TRUE
)) != BE_SUCCESS
) {
675 } else if (menu_fp
== NULL
) {
676 ret
= BE_ERR_NO_MENU
;
683 while (fgets(line
, BUFSIZ
, menu_fp
)) {
686 (void) strlcpy(temp_line
, line
, BUFSIZ
);
687 tok
= strtok(line
, BE_WHITE_SPACE
);
689 if (tok
== NULL
|| tok
[0] == '#') {
691 } else if (strcmp(tok
, "title") == 0) {
692 collect_lines
= B_FALSE
;
693 if ((tok
= strtok(NULL
, "\n")) == NULL
)
694 (void) strlcpy(title
, "", sizeof (title
));
696 (void) strlcpy(title
, tok
, sizeof (title
));
697 found_title
= B_TRUE
;
699 if (num_tmp_lines
!= 0) {
700 for (i
= 0; i
< num_tmp_lines
; i
++) {
701 free(tmp_entries
[i
]);
702 tmp_entries
[i
] = NULL
;
706 } else if (strcmp(tok
, "bootfs") == 0) {
707 char *bootfs
= strtok(NULL
, BE_WHITE_SPACE
);
708 found_title
= B_FALSE
;
712 if (strcmp(bootfs
, be_root_ds
) == 0) {
717 if (be_orig_root_ds
!= NULL
&&
718 strcmp(bootfs
, be_orig_root_ds
) == 0 &&
721 found_orig_be
= B_TRUE
;
724 * Store the new title line
726 (void) snprintf(str
, BUFSIZ
, "title %s\n",
727 description
? description
: be_name
);
728 entries
[num_lines
] = strdup(str
);
731 * If there are any lines between the title
732 * and the bootfs line store these. Also
733 * free the temporary lines.
735 for (i
= 0; i
< num_tmp_lines
; i
++) {
736 entries
[num_lines
] = tmp_entries
[i
];
737 tmp_entries
[i
] = NULL
;
742 * Store the new bootfs line.
744 (void) snprintf(str
, BUFSIZ
, "bootfs %s\n",
746 entries
[num_lines
] = strdup(str
);
748 collect_lines
= B_TRUE
;
750 } else if (found_orig_be
&& collect_lines
) {
752 * get the rest of the lines for the original BE and
755 entries
[num_lines
] = strdup(temp_line
);
757 } else if (found_title
&& !found_orig_be
) {
758 tmp_entries
[num_tmp_lines
] = strdup(temp_line
);
763 (void) fclose(menu_fp
);
767 * If an entry for this BE was already in the menu, then if
768 * that entry's title matches what we would have put in
769 * return success. Otherwise return failure.
771 char *new_title
= description
? description
: be_name
;
773 if (strcmp(title
, new_title
) == 0) {
777 if (be_remove_menu(be_name
, be_root_pool
,
778 boot_pool
) != BE_SUCCESS
) {
779 be_print_err(gettext("be_append_menu: "
780 "Failed to remove existing unusable "
781 "entry '%s' in boot menu.\n"), be_name
);
782 ret
= BE_ERR_BE_EXISTS
;
788 /* Append BE entry to the end of the file */
789 menu_fp
= fopen(menu_file
, "a+");
791 if (menu_fp
== NULL
) {
792 be_print_err(gettext("be_append_menu: failed "
793 "to open menu.lst file %s\n"), menu_file
);
794 ret
= errno_to_be_err(err
);
800 * write out all the stored lines
802 for (i
= 0; i
< num_lines
; i
++) {
803 (void) fprintf(menu_fp
, "%s", entries
[i
]);
809 (void) fprintf(menu_fp
, "title %s\n",
810 description
? description
: be_name
);
811 (void) fprintf(menu_fp
, "bootfs %s\n", be_root_ds
);
814 (void) fclose(menu_fp
);
817 int err
= BE_SUCCESS
;
818 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
819 if (ret
== BE_SUCCESS
)
825 if (num_tmp_lines
> 0) {
826 for (i
= 0; i
< num_tmp_lines
; i
++) {
827 free(tmp_entries
[i
]);
828 tmp_entries
[i
] = NULL
;
832 for (i
= 0; i
< num_lines
; i
++) {
841 * Function: be_remove_menu
842 * Description: Removes a BE's entry from a menu.lst file.
844 * be_name - the name of BE whose entry is to be removed from
846 * be_root_pool - the pool that be_name lives in.
847 * boot_pool - the pool where the BE is, if different than
848 * the pool containing the boot menu. If this is
849 * NULL it will be set to be_root_pool.
851 * BE_SUCCESS - Success
852 * be_errno_t - Failure
854 * Semi-private (library wide use only)
857 be_remove_menu(char *be_name
, char *be_root_pool
, char *boot_pool
)
859 zfs_handle_t
*zhp
= NULL
;
860 char be_root_ds
[MAXPATHLEN
];
861 char **buffer
= NULL
;
862 char menu_buf
[BUFSIZ
];
863 char menu
[MAXPATHLEN
];
864 char *pool_mntpnt
= NULL
;
865 char *ptmp_mntpnt
= NULL
;
866 char *orig_mntpnt
= NULL
;
867 char *tmp_menu
= NULL
;
868 FILE *menu_fp
= NULL
;
869 FILE *tmp_menu_fp
= NULL
;
871 int ret
= BE_SUCCESS
;
878 int num_entry_del
= 0;
879 int tmp_menu_len
= 0;
880 boolean_t write
= B_TRUE
;
881 boolean_t do_buffer
= B_FALSE
;
882 boolean_t pool_mounted
= B_FALSE
;
884 if (boot_pool
== NULL
)
885 boot_pool
= be_root_pool
;
887 /* Get name of BE's root dataset */
888 be_make_root_ds(be_root_pool
, be_name
, be_root_ds
, sizeof (be_root_ds
));
890 /* Get handle to pool dataset */
891 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
892 be_print_err(gettext("be_remove_menu: "
893 "failed to open pool dataset for %s: %s"),
894 be_root_pool
, libzfs_error_description(g_zfs
));
895 return (zfs_err_to_be_err(g_zfs
));
899 * Check to see if the pool's dataset is mounted. If it isn't we'll
900 * attempt to mount it.
902 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
903 &pool_mounted
)) != BE_SUCCESS
) {
904 be_print_err(gettext("be_remove_menu: pool dataset "
905 "(%s) could not be mounted\n"), be_root_pool
);
911 * Get the mountpoint for the root pool dataset.
913 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
914 be_print_err(gettext("be_remove_menu: pool "
915 "dataset (%s) is not mounted. Can't remove "
916 "the BE from the boot menu.\n"), be_root_pool
);
917 ret
= BE_ERR_NO_MENU
;
921 /* Get path to boot menu */
922 (void) strlcpy(menu
, pool_mntpnt
, sizeof (menu
));
923 (void) strlcat(menu
, BE_SPARC_MENU
, sizeof (menu
));
925 /* Get handle to boot menu file */
926 if ((ret
= be_open_menu(be_root_pool
, menu
, &menu_fp
, "r",
927 B_TRUE
)) != BE_SUCCESS
) {
929 } else if (menu_fp
== NULL
) {
930 ret
= BE_ERR_NO_MENU
;
937 /* Grab the stats of the original menu file */
938 if (stat(menu
, &sb
) != 0) {
940 be_print_err(gettext("be_remove_menu: "
941 "failed to stat file %s: %s\n"), menu
, strerror(err
));
942 ret
= errno_to_be_err(err
);
946 /* Create a tmp file for the modified menu.lst */
947 tmp_menu_len
= strlen(menu
) + 7;
948 if ((tmp_menu
= (char *)malloc(tmp_menu_len
)) == NULL
) {
949 be_print_err(gettext("be_remove_menu: malloc failed\n"));
953 (void) memset(tmp_menu
, 0, tmp_menu_len
);
954 (void) strlcpy(tmp_menu
, menu
, tmp_menu_len
);
955 (void) strlcat(tmp_menu
, "XXXXXX", tmp_menu_len
);
956 if ((fd
= mkstemp(tmp_menu
)) == -1) {
958 be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
959 ret
= errno_to_be_err(err
);
964 if ((tmp_menu_fp
= fdopen(fd
, "w")) == NULL
) {
966 be_print_err(gettext("be_remove_menu: "
967 "could not open tmp file for write: %s\n"), strerror(err
));
969 ret
= errno_to_be_err(err
);
973 while (fgets(menu_buf
, BUFSIZ
, menu_fp
)) {
977 (void) strlcpy(tline
, menu_buf
, sizeof (tline
));
980 tok
= strtok(tline
, BE_WHITE_SPACE
);
982 if (tok
== NULL
|| tok
[0] == '#') {
983 /* Found empty line or comment line */
985 /* Buffer this line */
986 if ((buffer
= reallocarray(buffer
, nlines
+ 1,
987 sizeof (char *))) == NULL
) {
991 if ((buffer
[nlines
++] = strdup(menu_buf
))
997 } else if (write
!= 0) {
998 /* Write this line out */
999 (void) fputs(menu_buf
, tmp_menu_fp
);
1001 } else if (strcmp(tok
, "title") == 0) {
1003 * If we've reached a 'title' line and do_buffer is
1004 * is true, that means we've just buffered an entire
1005 * entry without finding a 'bootfs' directive. We
1006 * need to write that entry out and keep searching.
1009 for (i
= 0; i
< nlines
; i
++) {
1010 (void) fputs(buffer
[i
], tmp_menu_fp
);
1019 * Turn writing off and buffering on, and increment
1020 * our entry counter.
1026 /* Buffer this 'title' line */
1027 if ((buffer
= reallocarray(buffer
, nlines
+ 1,
1028 sizeof (char *))) == NULL
) {
1032 if ((buffer
[nlines
++] = strdup(menu_buf
)) == NULL
) {
1037 } else if (strcmp(tok
, "bootfs") == 0) {
1038 char *bootfs
= NULL
;
1041 * Found a 'bootfs' line. See if it matches the
1042 * BE we're looking for.
1044 if ((bootfs
= strtok(NULL
, BE_WHITE_SPACE
)) == NULL
||
1045 strcmp(bootfs
, be_root_ds
) != 0) {
1047 * Either there's nothing after the 'bootfs'
1048 * or this is not the BE we're looking for,
1049 * write out the line(s) we've buffered since
1050 * finding the title.
1052 for (i
= 0; i
< nlines
; i
++) {
1053 (void) fputs(buffer
[i
], tmp_menu_fp
);
1061 * Turn writing back on, and turn off buffering
1062 * since this isn't the entry we're looking
1066 do_buffer
= B_FALSE
;
1068 /* Write this 'bootfs' line out. */
1069 (void) fputs(menu_buf
, tmp_menu_fp
);
1072 * Found the entry we're looking for.
1073 * Record its entry number, increment the
1074 * number of entries we've deleted, and turn
1075 * writing off. Also, throw away the lines
1076 * we've buffered for this entry so far, we
1079 entry_del
= entry_cnt
- 1;
1082 do_buffer
= B_FALSE
;
1084 for (i
= 0; i
< nlines
; i
++) {
1093 /* Buffer this line */
1094 if ((buffer
= reallocarray(buffer
, nlines
+ 1,
1095 sizeof (char *))) == NULL
) {
1099 if ((buffer
[nlines
++] = strdup(menu_buf
))
1105 /* Write this line out */
1106 (void) fputs(menu_buf
, tmp_menu_fp
);
1111 (void) fclose(menu_fp
);
1113 (void) fclose(tmp_menu_fp
);
1116 /* Copy the modified menu.lst into place */
1117 if (rename(tmp_menu
, menu
) != 0) {
1119 be_print_err(gettext("be_remove_menu: "
1120 "failed to rename file %s to %s: %s\n"),
1121 tmp_menu
, menu
, strerror(err
));
1122 ret
= errno_to_be_err(err
);
1128 /* Set the perms and ownership of the updated file */
1129 if (chmod(menu
, sb
.st_mode
) != 0) {
1131 be_print_err(gettext("be_remove_menu: "
1132 "failed to chmod %s: %s\n"), menu
, strerror(err
));
1133 ret
= errno_to_be_err(err
);
1136 if (chown(menu
, sb
.st_uid
, sb
.st_gid
) != 0) {
1138 be_print_err(gettext("be_remove_menu: "
1139 "failed to chown %s: %s\n"), menu
, strerror(err
));
1140 ret
= errno_to_be_err(err
);
1146 int err
= BE_SUCCESS
;
1147 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1148 if (ret
== BE_SUCCESS
)
1156 if (menu_fp
!= NULL
)
1157 (void) fclose(menu_fp
);
1158 if (tmp_menu_fp
!= NULL
)
1159 (void) fclose(tmp_menu_fp
);
1160 if (tmp_menu
!= NULL
) {
1161 (void) unlink(tmp_menu
);
1169 * Function: be_update_menu
1170 * Description: This function is used by be_rename to change the BE name in
1171 * an existing entry in the menu to the new name of the BE.
1173 * be_orig_name - the original name of the BE
1174 * be_new_name - the new name the BE is being renameed to.
1175 * be_root_pool - The pool which contains the boot menu
1176 * boot_pool - the pool where the BE is, if different than
1177 * the pool containing the boot menu. If this is
1178 * NULL it will be set to be_root_pool.
1180 * BE_SUCCESS - Success
1181 * be_errno_t - Failure
1183 * Semi-private (library wide use only)
1186 be_update_menu(char *be_orig_name
, char *be_new_name
, char *be_root_pool
,
1189 zfs_handle_t
*zhp
= NULL
;
1190 char menu_file
[MAXPATHLEN
];
1191 char be_root_ds
[MAXPATHLEN
];
1192 char be_new_root_ds
[MAXPATHLEN
];
1194 char *pool_mntpnt
= NULL
;
1195 char *ptmp_mntpnt
= NULL
;
1196 char *orig_mntpnt
= NULL
;
1197 char *temp_menu
= NULL
;
1198 FILE *menu_fp
= NULL
;
1199 FILE *new_fp
= NULL
;
1201 int temp_menu_len
= 0;
1203 int ret
= BE_SUCCESS
;
1205 boolean_t pool_mounted
= B_FALSE
;
1209 if (boot_pool
== NULL
)
1210 boot_pool
= be_root_pool
;
1212 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1213 be_print_err(gettext("be_update_menu: failed to open "
1214 "pool dataset for %s: %s\n"), be_root_pool
,
1215 libzfs_error_description(g_zfs
));
1216 return (zfs_err_to_be_err(g_zfs
));
1220 * Check to see if the pool's dataset is mounted. If it isn't we'll
1221 * attempt to mount it.
1223 if ((ret
= be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1224 &pool_mounted
)) != BE_SUCCESS
) {
1225 be_print_err(gettext("be_update_menu: pool dataset "
1226 "(%s) could not be mounted\n"), be_root_pool
);
1232 * Get the mountpoint for the root pool dataset.
1234 if (!zfs_is_mounted(zhp
, &pool_mntpnt
)) {
1235 be_print_err(gettext("be_update_menu: failed "
1236 "to get mount point for the root pool. Can't update "
1237 "the BE in the boot menu.\n"));
1238 ret
= BE_ERR_NO_MENU
;
1242 (void) snprintf(menu_file
, sizeof (menu_file
),
1243 "%s%s", pool_mntpnt
, BE_SPARC_MENU
);
1245 be_make_root_ds(be_root_pool
, be_orig_name
, be_root_ds
,
1246 sizeof (be_root_ds
));
1247 be_make_root_ds(be_root_pool
, be_new_name
, be_new_root_ds
,
1248 sizeof (be_new_root_ds
));
1250 if ((ret
= be_open_menu(be_root_pool
, menu_file
,
1251 &menu_fp
, "r", B_TRUE
)) != BE_SUCCESS
) {
1253 } else if (menu_fp
== NULL
) {
1254 ret
= BE_ERR_NO_MENU
;
1261 /* Grab the stat of the original menu file */
1262 if (stat(menu_file
, &sb
) != 0) {
1264 be_print_err(gettext("be_update_menu: "
1265 "failed to stat file %s: %s\n"), menu_file
, strerror(err
));
1266 (void) fclose(menu_fp
);
1267 ret
= errno_to_be_err(err
);
1271 /* Create tmp file for modified menu.lst */
1272 temp_menu_len
= strlen(menu_file
) + 7;
1273 if ((temp_menu
= (char *)malloc(temp_menu_len
))
1275 be_print_err(gettext("be_update_menu: "
1276 "malloc failed\n"));
1277 (void) fclose(menu_fp
);
1281 (void) memset(temp_menu
, 0, temp_menu_len
);
1282 (void) strlcpy(temp_menu
, menu_file
, temp_menu_len
);
1283 (void) strlcat(temp_menu
, "XXXXXX", temp_menu_len
);
1284 if ((tmp_fd
= mkstemp(temp_menu
)) == -1) {
1286 be_print_err(gettext("be_update_menu: "
1287 "mkstemp failed: %s\n"), strerror(err
));
1288 (void) fclose(menu_fp
);
1290 ret
= errno_to_be_err(err
);
1293 if ((new_fp
= fdopen(tmp_fd
, "w")) == NULL
) {
1295 be_print_err(gettext("be_update_menu: "
1296 "fdopen failed: %s\n"), strerror(err
));
1297 (void) close(tmp_fd
);
1298 (void) fclose(menu_fp
);
1300 ret
= errno_to_be_err(err
);
1304 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1306 char new_line
[BUFSIZ
];
1309 (void) strlcpy(tline
, line
, sizeof (tline
));
1312 c
= strtok(tline
, BE_WHITE_SPACE
);
1315 /* Found empty line, write it out. */
1316 (void) fputs(line
, new_fp
);
1317 } else if (c
[0] == '#') {
1318 /* Found a comment line, write it out. */
1319 (void) fputs(line
, new_fp
);
1320 } else if (strcmp(c
, "title") == 0) {
1325 * Found a 'title' line, parse out BE name or
1328 name
= strtok(NULL
, BE_WHITE_SPACE
);
1332 * Nothing after 'title', just push
1335 (void) fputs(line
, new_fp
);
1338 * Grab the remainder of the title which
1339 * could be a multi worded description
1341 desc
= strtok(NULL
, "\n");
1343 if (strcmp(name
, be_orig_name
) == 0) {
1345 * The first token of the title is
1346 * the old BE name, replace it with
1347 * the new one, and write it out
1348 * along with the remainder of
1349 * description if there is one.
1352 (void) snprintf(new_line
,
1357 (void) snprintf(new_line
,
1359 "title %s\n", be_new_name
);
1362 (void) fputs(new_line
, new_fp
);
1364 (void) fputs(line
, new_fp
);
1367 } else if (strcmp(c
, "bootfs") == 0) {
1369 * Found a 'bootfs' line, parse out the BE root
1372 char *root_ds
= strtok(NULL
, BE_WHITE_SPACE
);
1374 if (root_ds
== NULL
) {
1376 * Nothing after 'bootfs', just push
1379 (void) fputs(line
, new_fp
);
1382 * If this bootfs is the one we're renaming,
1383 * write out the new root dataset value
1385 if (strcmp(root_ds
, be_root_ds
) == 0) {
1386 (void) snprintf(new_line
,
1387 sizeof (new_line
), "bootfs %s\n",
1390 (void) fputs(new_line
, new_fp
);
1392 (void) fputs(line
, new_fp
);
1397 * Found some other line we don't care
1398 * about, write it out.
1400 (void) fputs(line
, new_fp
);
1404 (void) fclose(menu_fp
);
1405 (void) fclose(new_fp
);
1406 (void) close(tmp_fd
);
1408 if (rename(temp_menu
, menu_file
) != 0) {
1410 be_print_err(gettext("be_update_menu: "
1411 "failed to rename file %s to %s: %s\n"),
1412 temp_menu
, menu_file
, strerror(err
));
1413 ret
= errno_to_be_err(err
);
1417 /* Set the perms and ownership of the updated file */
1418 if (chmod(menu_file
, sb
.st_mode
) != 0) {
1420 be_print_err(gettext("be_update_menu: "
1421 "failed to chmod %s: %s\n"), menu_file
, strerror(err
));
1422 ret
= errno_to_be_err(err
);
1425 if (chown(menu_file
, sb
.st_uid
, sb
.st_gid
) != 0) {
1427 be_print_err(gettext("be_update_menu: "
1428 "failed to chown %s: %s\n"), menu_file
, strerror(err
));
1429 ret
= errno_to_be_err(err
);
1434 int err
= BE_SUCCESS
;
1435 err
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1436 if (ret
== BE_SUCCESS
)
1446 * Function: be_has_menu_entry
1447 * Description: Checks to see if the BEs root dataset has an entry in the menu.
1449 * be_dataset - The root dataset of the BE
1450 * be_root_pool - The pool which contains the boot menu
1451 * entry - A pointer the the entry number of the BE if found.
1456 * Semi-private (library wide use only)
1459 be_has_menu_entry(char *be_dataset
, char *be_root_pool
, int *entry
)
1461 zfs_handle_t
*zhp
= NULL
;
1462 char menu_file
[MAXPATHLEN
];
1466 char *rpool_mntpnt
= NULL
;
1467 char *ptmp_mntpnt
= NULL
;
1468 char *orig_mntpnt
= NULL
;
1471 boolean_t pool_mounted
= B_FALSE
;
1474 if ((zhp
= zfs_open(g_zfs
, be_root_pool
, ZFS_TYPE_DATASET
)) == NULL
) {
1475 be_print_err(gettext("be_has_menu_entry: failed to open "
1476 "pool dataset for %s: %s\n"), be_root_pool
,
1477 libzfs_error_description(g_zfs
));
1482 * Check to see if the pool's dataset is mounted. If it isn't we'll
1483 * attempt to mount it.
1485 if (be_mount_pool(zhp
, &ptmp_mntpnt
, &orig_mntpnt
,
1486 &pool_mounted
) != 0) {
1487 be_print_err(gettext("be_has_menu_entry: pool dataset "
1488 "(%s) could not be mounted\n"), be_root_pool
);
1494 * Get the mountpoint for the root pool dataset.
1496 if (!zfs_is_mounted(zhp
, &rpool_mntpnt
)) {
1497 be_print_err(gettext("be_has_menu_entry: pool "
1498 "dataset (%s) is not mounted. Can't set "
1499 "the BE in the boot menu.\n"), be_root_pool
);
1504 (void) snprintf(menu_file
, MAXPATHLEN
, "/%s%s",
1505 rpool_mntpnt
, BE_SPARC_MENU
);
1507 if (be_open_menu(be_root_pool
, menu_file
, &menu_fp
, "r",
1511 } else if (menu_fp
== NULL
) {
1517 rpool_mntpnt
= NULL
;
1519 while (fgets(line
, BUFSIZ
, menu_fp
)) {
1520 char *tok
= strtok_r(line
, BE_WHITE_SPACE
, &last
);
1522 if (tok
!= NULL
&& tok
[0] != '#') {
1523 if (strcmp(tok
, "bootfs") == 0) {
1524 tok
= strtok_r(last
, BE_WHITE_SPACE
, &last
);
1525 if (tok
!= NULL
&& strcmp(tok
,
1527 (void) fclose(menu_fp
);
1529 * The entry number needs to be
1530 * decremented here because the title
1531 * will always be the first line for
1532 * an entry. Because of this we'll
1533 * always be off by one entry when we
1536 *entry
= ent_num
- 1;
1540 } else if (strcmp(tok
, "title") == 0)
1547 (void) be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1552 (void) fclose(menu_fp
);
1557 * Function: be_update_vfstab
1558 * Description: This function digs into a BE's vfstab and updates all
1559 * entries with file systems listed in be_fs_list_data_t.
1560 * The entry's root container dataset and be_name will be
1561 * updated with the parameters passed in.
1563 * be_name - name of BE to update
1564 * old_rc_loc - dataset under which the root container dataset
1565 * of the old BE resides in.
1566 * new_rc_loc - dataset under which the root container dataset
1567 * of the new BE resides in.
1568 * fld - be_fs_list_data_t pointer providing the list of
1569 * file systems to look for in vfstab.
1570 * mountpoint - directory of where BE is currently mounted.
1571 * If NULL, then BE is not currently mounted.
1573 * BE_SUCCESS - Success
1574 * be_errno_t - Failure
1576 * Semi-private (library wide use only)
1579 be_update_vfstab(char *be_name
, char *old_rc_loc
, char *new_rc_loc
,
1580 be_fs_list_data_t
*fld
, char *mountpoint
)
1582 char *tmp_mountpoint
= NULL
;
1583 char alt_vfstab
[MAXPATHLEN
];
1584 int ret
= BE_SUCCESS
, err
= BE_SUCCESS
;
1586 if (fld
== NULL
|| fld
->fs_list
== NULL
|| fld
->fs_num
== 0)
1587 return (BE_SUCCESS
);
1589 /* If BE not already mounted, mount the BE */
1590 if (mountpoint
== NULL
) {
1591 if ((ret
= _be_mount(be_name
, &tmp_mountpoint
,
1592 BE_MOUNT_FLAG_NO_ZONES
)) != BE_SUCCESS
) {
1593 be_print_err(gettext("be_update_vfstab: "
1594 "failed to mount BE (%s)\n"), be_name
);
1598 tmp_mountpoint
= mountpoint
;
1601 /* Get string for vfstab in the mounted BE. */
1602 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
1605 /* Update the vfstab */
1606 ret
= _update_vfstab(alt_vfstab
, be_name
, old_rc_loc
, new_rc_loc
,
1609 /* Unmount BE if we mounted it */
1610 if (mountpoint
== NULL
) {
1611 if ((err
= _be_unmount(be_name
, 0)) == BE_SUCCESS
) {
1612 /* Remove temporary mountpoint */
1613 (void) rmdir(tmp_mountpoint
);
1615 be_print_err(gettext("be_update_vfstab: "
1616 "failed to unmount BE %s mounted at %s\n"),
1617 be_name
, tmp_mountpoint
);
1618 if (ret
== BE_SUCCESS
)
1622 free(tmp_mountpoint
);
1629 * Function: be_update_zone_vfstab
1630 * Description: This function digs into a zone BE's vfstab and updates all
1631 * entries with file systems listed in be_fs_list_data_t.
1632 * The entry's root container dataset and be_name will be
1633 * updated with the parameters passed in.
1635 * zhp - zfs_handle_t pointer to zone root dataset.
1636 * be_name - name of zone BE to update
1637 * old_rc_loc - dataset under which the root container dataset
1638 * of the old zone BE resides in.
1639 * new_rc_loc - dataset under which the root container dataset
1640 * of the new zone BE resides in.
1641 * fld - be_fs_list_data_t pointer providing the list of
1642 * file systems to look for in vfstab.
1644 * BE_SUCCESS - Success
1645 * be_errno_t - Failure
1647 * Semi-private (library wide use only)
1650 be_update_zone_vfstab(zfs_handle_t
*zhp
, char *be_name
, char *old_rc_loc
,
1651 char *new_rc_loc
, be_fs_list_data_t
*fld
)
1653 be_mount_data_t md
= { 0 };
1654 be_unmount_data_t ud
= { 0 };
1655 char alt_vfstab
[MAXPATHLEN
];
1656 boolean_t mounted_here
= B_FALSE
;
1657 int ret
= BE_SUCCESS
;
1660 * If zone root not already mounted, mount it at a
1661 * temporary location.
1663 if (!zfs_is_mounted(zhp
, &md
.altroot
)) {
1664 /* Generate temporary mountpoint to mount zone root */
1665 if ((ret
= be_make_tmp_mountpoint(&md
.altroot
)) != BE_SUCCESS
) {
1666 be_print_err(gettext("be_update_zone_vfstab: "
1667 "failed to make temporary mountpoint to "
1668 "mount zone root\n"));
1672 if (be_mount_zone_root(zhp
, &md
) != BE_SUCCESS
) {
1673 be_print_err(gettext("be_update_zone_vfstab: "
1674 "failed to mount zone root %s\n"),
1677 return (BE_ERR_MOUNT_ZONEROOT
);
1679 mounted_here
= B_TRUE
;
1682 /* Get string from vfstab in the mounted zone BE */
1683 (void) snprintf(alt_vfstab
, sizeof (alt_vfstab
), "%s/etc/vfstab",
1686 /* Update the vfstab */
1687 ret
= _update_vfstab(alt_vfstab
, be_name
, old_rc_loc
, new_rc_loc
,
1690 /* Unmount zone root if we mounted it */
1694 if (be_unmount_zone_root(zhp
, &ud
) == BE_SUCCESS
) {
1695 /* Remove the temporary mountpoint */
1696 (void) rmdir(md
.altroot
);
1698 be_print_err(gettext("be_update_zone_vfstab: "
1699 "failed to unmount zone root %s from %s\n"),
1700 zfs_get_name(zhp
), md
.altroot
);
1702 ret
= BE_ERR_UMOUNT_ZONEROOT
;
1711 * Function: be_auto_snap_name
1712 * Description: Generate an auto snapshot name constructed based on the
1713 * current date and time. The auto snapshot name is of the form:
1717 * where <date> is in ISO standard format, so the resultant name
1725 * Success - pointer to auto generated snapshot name. The name
1726 * is allocated in heap storage so the caller is
1727 * responsible for free'ing the name.
1730 * Semi-private (library wide use only)
1733 be_auto_snap_name(void)
1736 struct tm
*gmt_tm
= NULL
;
1737 char gmt_time_str
[64];
1738 char *auto_snap_name
= NULL
;
1740 if (time(&utc_tm
) == -1) {
1741 be_print_err(gettext("be_auto_snap_name: time() failed\n"));
1745 if ((gmt_tm
= gmtime(&utc_tm
)) == NULL
) {
1746 be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
1750 (void) strftime(gmt_time_str
, sizeof (gmt_time_str
), "%F-%T", gmt_tm
);
1752 if ((auto_snap_name
= strdup(gmt_time_str
)) == NULL
) {
1753 be_print_err(gettext("be_auto_snap_name: "
1754 "memory allocation failed\n"));
1758 return (auto_snap_name
);
1762 * Function: be_auto_be_name
1763 * Description: Generate an auto BE name constructed based on the BE name
1764 * of the original BE being cloned.
1766 * obe_name - name of the original BE being cloned.
1768 * Success - pointer to auto generated BE name. The name
1769 * is allocated in heap storage so the caller is
1770 * responsible for free'ing the name.
1773 * Semi-private (library wide use only)
1776 be_auto_be_name(char *obe_name
)
1778 return (be_get_auto_name(obe_name
, NULL
, B_FALSE
));
1782 * Function: be_auto_zone_be_name
1783 * Description: Generate an auto BE name for a zone constructed based on
1784 * the BE name of the original zone BE being cloned.
1786 * container_ds - container dataset for the zone.
1787 * zbe_name - name of the original zone BE being cloned.
1789 * Success - pointer to auto generated BE name. The name
1790 * is allocated in heap storage so the caller is
1791 * responsible for free'ing the name.
1794 * Semi-private (library wide use only)
1797 be_auto_zone_be_name(char *container_ds
, char *zbe_name
)
1799 return (be_get_auto_name(zbe_name
, container_ds
, B_TRUE
));
1803 * Function: be_valid_be_name
1804 * Description: Validates a BE name.
1806 * be_name - name of BE to validate
1808 * B_TRUE - be_name is valid
1809 * B_FALSE - be_name is invalid
1811 * Semi-private (library wide use only)
1815 be_valid_be_name(const char *be_name
)
1817 const char *c
= NULL
;
1818 struct be_defaults be_defaults
;
1820 if (be_name
== NULL
)
1823 be_get_defaults(&be_defaults
);
1826 * A BE name must not be a multi-level dataset name. We also check
1827 * that it does not contain the ' ' and '%' characters. The ' ' is
1828 * a valid character for datasets, however we don't allow that in a
1829 * BE name. The '%' is invalid, but zfs_name_valid() allows it for
1830 * internal reasons, so we explicitly check for it here.
1833 while (*c
!= '\0' && *c
!= '/' && *c
!= ' ' && *c
!= '%')
1840 * The BE name must comply with a zfs dataset filesystem. We also
1841 * verify its length to be < BE_NAME_MAX_LEN.
1843 if (!zfs_name_valid(be_name
, ZFS_TYPE_FILESYSTEM
) ||
1844 strlen(be_name
) > BE_NAME_MAX_LEN
)
1847 if (be_defaults
.be_deflt_bename_starts_with
[0] != '\0' &&
1848 strstr(be_name
, be_defaults
.be_deflt_bename_starts_with
) == NULL
) {
1856 * Function: be_valid_auto_snap_name
1857 * Description: This function checks that a snapshot name is a valid auto
1858 * generated snapshot name. A valid auto generated snapshot
1859 * name is of the form:
1863 * An older form of the auto generated snapshot name also
1864 * included the snapshot's BE cleanup policy and a reserved
1865 * field. Those names will also be verified by this function.
1867 * Examples of valid auto snapshot names are:
1869 * 2008-03-31-18:41:30
1870 * 2008-03-31-22:17:24
1871 * <policy>:-:2008:04-05-09:12:55
1872 * <policy>:-:2008:04-06-15:34:12
1875 * name - name of the snapshot to be validated.
1877 * B_TRUE - the name is a valid auto snapshot name.
1878 * B_FALSE - the name is not a valid auto snapshot name.
1880 * Semi-private (library wide use only)
1883 be_valid_auto_snap_name(char *name
)
1887 char *policy
= NULL
;
1888 char *reserved
= NULL
;
1892 /* Validate the snapshot name by converting it into utc time */
1893 if (strptime(name
, "%Y-%m-%d-%T", &gmt_tm
) != NULL
&&
1894 (mktime(&gmt_tm
) != -1)) {
1899 * Validate the snapshot name against the older form of an
1900 * auto generated snapshot name.
1902 policy
= strdup(name
);
1905 * Get the first field from the snapshot name,
1906 * which is the BE policy
1908 c
= strchr(policy
, ':');
1915 /* Validate the policy name */
1916 if (!valid_be_policy(policy
)) {
1921 /* Get the next field, which is the reserved field. */
1927 c
= strchr(reserved
, ':');
1934 /* Validate the reserved field */
1935 if (strcmp(reserved
, "-") != 0) {
1940 /* The remaining string should be the date field */
1947 /* Validate the date string by converting it into utc time */
1948 if (strptime(date
, "%Y-%m-%d-%T", &gmt_tm
) == NULL
||
1949 (mktime(&gmt_tm
) == -1)) {
1950 be_print_err(gettext("be_valid_auto_snap_name: "
1951 "invalid auto snapshot name\n"));
1961 * Function: be_default_policy
1962 * Description: Temporary hardcoded policy support. This function returns
1963 * the default policy type to be used to create a BE or a BE
1968 * Name of default BE policy.
1970 * Semi-private (library wide use only)
1973 be_default_policy(void)
1975 return (BE_PLCY_STATIC
);
1979 * Function: valid_be_policy
1980 * Description: Temporary hardcoded policy support. This function valids
1981 * whether a policy is a valid known policy or not.
1983 * policy - name of policy to validate.
1985 * B_TRUE - policy is a valid.
1986 * B_FALSE - policy is invalid.
1988 * Semi-private (library wide use only)
1991 valid_be_policy(char *policy
)
1996 if (strcmp(policy
, BE_PLCY_STATIC
) == 0 ||
1997 strcmp(policy
, BE_PLCY_VOLATILE
) == 0) {
2005 * Function: be_print_err
2006 * Description: This function prints out error messages if do_print is
2007 * set to B_TRUE or if the BE_PRINT_ERR environment variable
2010 * prnt_str - the string we wish to print and any arguments
2011 * for the format of that string.
2015 * Semi-private (library wide use only)
2018 be_print_err(char *prnt_str
, ...)
2023 static boolean_t env_checked
= B_FALSE
;
2026 if ((env_buf
= getenv("BE_PRINT_ERR")) != NULL
) {
2027 if (strcasecmp(env_buf
, "true") == 0) {
2031 env_checked
= B_TRUE
;
2035 va_start(ap
, prnt_str
);
2036 /* LINTED variable format specifier */
2037 (void) vsnprintf(buf
, BUFSIZ
, prnt_str
, ap
);
2038 (void) fputs(buf
, stderr
);
2044 * Function: be_find_current_be
2045 * Description: Find the currently "active" BE. Fill in the
2046 * passed in be_transaction_data_t reference with the
2051 * BE_SUCCESS - Success
2052 * be_errnot_t - Failure
2054 * Semi-private (library wide use only)
2056 * The caller is responsible for initializing the libzfs handle
2057 * and freeing the memory used by the active be_name.
2060 be_find_current_be(be_transaction_data_t
*bt
)
2064 if ((zret
= zpool_iter(g_zfs
, be_zpool_find_current_be_callback
,
2066 be_print_err(gettext("be_find_current_be: failed to "
2067 "find current BE name\n"));
2068 return (BE_ERR_BE_NOENT
);
2069 } else if (zret
< 0) {
2070 be_print_err(gettext("be_find_current_be: "
2071 "zpool_iter failed: %s\n"),
2072 libzfs_error_description(g_zfs
));
2073 return (zfs_err_to_be_err(g_zfs
));
2076 return (BE_SUCCESS
);
2080 * Function: be_zpool_find_current_be_callback
2081 * Description: Callback function used to iterate through all existing pools
2082 * to find the BE that is the currently booted BE.
2084 * zlp - zpool_handle_t pointer to the current pool being
2086 * data - be_transaction_data_t pointer.
2087 * Upon successfully finding the current BE, the
2088 * obe_zpool member of this parameter is set to the
2089 * pool it is found in.
2091 * 1 - Found current BE in this pool.
2092 * 0 - Did not find current BE in this pool.
2094 * Semi-private (library wide use only)
2097 be_zpool_find_current_be_callback(zpool_handle_t
*zlp
, void *data
)
2099 be_transaction_data_t
*bt
= data
;
2100 zfs_handle_t
*zhp
= NULL
;
2101 const char *zpool
= zpool_get_name(zlp
);
2102 char be_container_ds
[MAXPATHLEN
];
2106 * Generate string for BE container dataset
2108 if (getzoneid() != GLOBAL_ZONEID
) {
2109 if ((zpath
= be_get_ds_from_dir("/")) != NULL
) {
2110 (void) strlcpy(be_container_ds
, dirname(zpath
),
2111 sizeof (be_container_ds
));
2113 be_print_err(gettext(
2114 "be_zpool_find_current_be_callback: "
2115 "zone root dataset is not mounted\n"));
2119 be_make_container_ds(zpool
, be_container_ds
,
2120 sizeof (be_container_ds
));
2124 * Check if a BE container dataset exists in this pool.
2126 if (!zfs_dataset_exists(g_zfs
, be_container_ds
, ZFS_TYPE_FILESYSTEM
)) {
2132 * Get handle to this zpool's BE container dataset.
2134 if ((zhp
= zfs_open(g_zfs
, be_container_ds
, ZFS_TYPE_FILESYSTEM
)) ==
2136 be_print_err(gettext("be_zpool_find_current_be_callback: "
2137 "failed to open BE container dataset (%s)\n"),
2144 * Iterate through all potential BEs in this zpool
2146 if (zfs_iter_filesystems(zhp
, be_zfs_find_current_be_callback
, bt
)) {
2148 * Found current BE dataset; set obe_zpool
2150 if ((bt
->obe_zpool
= strdup(zpool
)) == NULL
) {
2151 be_print_err(gettext(
2152 "be_zpool_find_current_be_callback: "
2153 "memory allocation failed\n"));
2171 * Function: be_zfs_find_current_be_callback
2172 * Description: Callback function used to iterate through all BEs in a
2173 * pool to find the BE that is the currently booted BE.
2175 * zhp - zfs_handle_t pointer to current filesystem being checked.
2176 * data - be_transaction-data_t pointer
2177 * Upon successfully finding the current BE, the
2178 * obe_name and obe_root_ds members of this parameter
2179 * are set to the BE name and BE's root dataset
2182 * 1 - Found current BE.
2183 * 0 - Did not find current BE.
2185 * Semi-private (library wide use only)
2188 be_zfs_find_current_be_callback(zfs_handle_t
*zhp
, void *data
)
2190 be_transaction_data_t
*bt
= data
;
2194 * Check if dataset is mounted, and if so where.
2196 if (zfs_is_mounted(zhp
, &mp
)) {
2198 * If mounted at root, set obe_root_ds and obe_name
2200 if (mp
!= NULL
&& strcmp(mp
, "/") == 0) {
2203 if ((bt
->obe_root_ds
= strdup(zfs_get_name(zhp
)))
2205 be_print_err(gettext(
2206 "be_zfs_find_current_be_callback: "
2207 "memory allocation failed\n"));
2212 if ((bt
->obe_name
= strdup(basename(bt
->obe_root_ds
)))
2214 be_print_err(gettext(
2215 "be_zfs_find_current_be_callback: "
2216 "memory allocation failed\n"));
2233 * Function: be_check_be_roots_callback
2234 * Description: This function checks whether or not the dataset name passed
2235 * is hierachically located under the BE root container dataset
2238 * zlp - zpool_handle_t pointer to current pool being processed.
2239 * data - name of dataset to check
2241 * 0 - dataset is not in this pool's BE root container dataset
2242 * 1 - dataset is in this pool's BE root container dataset
2244 * Semi-private (library wide use only)
2247 be_check_be_roots_callback(zpool_handle_t
*zlp
, void *data
)
2249 const char *zpool
= zpool_get_name(zlp
);
2251 char be_container_ds
[MAXPATHLEN
];
2253 /* Generate string for this pool's BE root container dataset */
2254 be_make_container_ds(zpool
, be_container_ds
, sizeof (be_container_ds
));
2257 * If dataset lives under the BE root container dataset
2258 * of this pool, return failure.
2260 if (strncmp(be_container_ds
, ds
, strlen(be_container_ds
)) == 0 &&
2261 ds
[strlen(be_container_ds
)] == '/') {
2271 * Function: zfs_err_to_be_err
2272 * Description: This function takes the error stored in the libzfs handle
2273 * and maps it to an be_errno_t. If there are no matching
2274 * be_errno_t's then BE_ERR_ZFS is returned.
2276 * zfsh - The libzfs handle containing the error we're looking up.
2280 * Semi-private (library wide use only)
2283 zfs_err_to_be_err(libzfs_handle_t
*zfsh
)
2285 int err
= libzfs_errno(zfsh
);
2289 return (BE_SUCCESS
);
2291 return (BE_ERR_PERM
);
2293 return (BE_ERR_INTR
);
2295 return (BE_ERR_NOENT
);
2297 return (BE_ERR_NOSPC
);
2298 case EZFS_MOUNTFAILED
:
2299 return (BE_ERR_MOUNT
);
2300 case EZFS_UMOUNTFAILED
:
2301 return (BE_ERR_UMOUNT
);
2303 return (BE_ERR_BE_EXISTS
);
2305 return (BE_ERR_DEV_BUSY
);
2306 case EZFS_POOLREADONLY
:
2307 return (BE_ERR_ROFS
);
2308 case EZFS_NAMETOOLONG
:
2309 return (BE_ERR_NAMETOOLONG
);
2311 return (BE_ERR_NODEV
);
2312 case EZFS_POOL_INVALARG
:
2313 return (BE_ERR_INVAL
);
2315 return (BE_ERR_INVALPROP
);
2317 return (BE_ERR_DSTYPE
);
2318 case EZFS_PROPNONINHERIT
:
2319 return (BE_ERR_NONINHERIT
);
2320 case EZFS_PROPREADONLY
:
2321 return (BE_ERR_READONLYPROP
);
2322 case EZFS_RESILVERING
:
2323 case EZFS_POOLUNAVAIL
:
2324 return (BE_ERR_UNAVAIL
);
2325 case EZFS_DSREADONLY
:
2326 return (BE_ERR_READONLYDS
);
2328 return (BE_ERR_ZFS
);
2333 * Function: errno_to_be_err
2334 * Description: This function takes an errno and maps it to an be_errno_t.
2335 * If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
2338 * err - The errno we're compairing against.
2342 * Semi-private (library wide use only)
2345 errno_to_be_err(int err
)
2349 return (BE_ERR_PERM
);
2351 return (BE_ERR_ACCESS
);
2353 return (BE_ERR_CANCELED
);
2355 return (BE_ERR_INTR
);
2357 return (BE_ERR_NOENT
);
2360 return (BE_ERR_NOSPC
);
2362 return (BE_ERR_BE_EXISTS
);
2364 return (BE_ERR_BUSY
);
2366 return (BE_ERR_ROFS
);
2368 return (BE_ERR_NAMETOOLONG
);
2370 return (BE_ERR_NXIO
);
2372 return (BE_ERR_INVAL
);
2374 return (BE_ERR_FAULT
);
2376 return (BE_ERR_UNKNOWN
);
2381 * Function: be_err_to_str
2382 * Description: This function takes a be_errno_t and maps it to a message.
2383 * If there are no matching be_errno_t's then NULL is returned.
2385 * be_errno_t - The be_errno_t we're mapping.
2387 * string or NULL if the error code is not known.
2389 * Semi-private (library wide use only)
2392 be_err_to_str(int err
)
2396 return (gettext("Permission denied."));
2397 case BE_ERR_ACTIVATE_CURR
:
2398 return (gettext("Activation of current BE failed."));
2399 case BE_ERR_AUTONAME
:
2400 return (gettext("Auto naming failed."));
2401 case BE_ERR_BE_NOENT
:
2402 return (gettext("No such BE."));
2404 return (gettext("Mount busy."));
2405 case BE_ERR_DEV_BUSY
:
2406 return (gettext("Device busy."));
2407 case BE_ERR_CANCELED
:
2408 return (gettext("Operation canceled."));
2410 return (gettext("BE clone failed."));
2412 return (gettext("BE copy failed."));
2413 case BE_ERR_CREATDS
:
2414 return (gettext("Dataset creation failed."));
2415 case BE_ERR_CURR_BE_NOT_FOUND
:
2416 return (gettext("Can't find current BE."));
2417 case BE_ERR_DESTROY
:
2418 return (gettext("Failed to destroy BE or snapshot."));
2419 case BE_ERR_DESTROY_CURR_BE
:
2420 return (gettext("Cannot destroy current BE."));
2422 return (gettext("BE demotion failed."));
2424 return (gettext("Invalid dataset type."));
2425 case BE_ERR_BE_EXISTS
:
2426 return (gettext("BE exists."));
2428 return (gettext("be_zfs_init failed."));
2430 return (gettext("Interupted system call."));
2432 return (gettext("Invalid argument."));
2433 case BE_ERR_INVALPROP
:
2434 return (gettext("Invalid property for dataset."));
2435 case BE_ERR_INVALMOUNTPOINT
:
2436 return (gettext("Unexpected mountpoint."));
2438 return (gettext("Mount failed."));
2439 case BE_ERR_MOUNTED
:
2440 return (gettext("Already mounted."));
2441 case BE_ERR_NAMETOOLONG
:
2442 return (gettext("name > BUFSIZ."));
2444 return (gettext("Doesn't exist."));
2445 case BE_ERR_POOL_NOENT
:
2446 return (gettext("No such pool."));
2448 return (gettext("No such device."));
2449 case BE_ERR_NOTMOUNTED
:
2450 return (gettext("File system not mounted."));
2452 return (gettext("Not enough memory."));
2453 case BE_ERR_NONINHERIT
:
2455 "Property is not inheritable for the BE dataset."));
2457 return (gettext("No such device or address."));
2459 return (gettext("No space on device."));
2461 return (gettext("Operation not supported."));
2463 return (gettext("Open failed."));
2465 return (gettext("Not owner."));
2466 case BE_ERR_UNAVAIL
:
2467 return (gettext("The BE is currently unavailable."));
2468 case BE_ERR_PROMOTE
:
2469 return (gettext("BE promotion failed."));
2471 return (gettext("Read only file system."));
2472 case BE_ERR_READONLYDS
:
2473 return (gettext("Read only dataset."));
2474 case BE_ERR_READONLYPROP
:
2475 return (gettext("Read only property."));
2476 case BE_ERR_RENAME_ACTIVE
:
2477 return (gettext("Renaming the active BE is not supported."));
2478 case BE_ERR_SS_EXISTS
:
2479 return (gettext("Snapshot exists."));
2480 case BE_ERR_SS_NOENT
:
2481 return (gettext("No such snapshot."));
2483 return (gettext("Unmount failed."));
2484 case BE_ERR_UMOUNT_CURR_BE
:
2485 return (gettext("Can't unmount the current BE."));
2486 case BE_ERR_UMOUNT_SHARED
:
2487 return (gettext("Unmount of a shared File System failed."));
2489 return (gettext("Bad address."));
2490 case BE_ERR_UNKNOWN
:
2491 return (gettext("Unknown error."));
2493 return (gettext("ZFS returned an error."));
2494 case BE_ERR_GEN_UUID
:
2495 return (gettext("Failed to generate uuid."));
2496 case BE_ERR_PARSE_UUID
:
2497 return (gettext("Failed to parse uuid."));
2498 case BE_ERR_NO_UUID
:
2499 return (gettext("No uuid"));
2500 case BE_ERR_ZONE_NO_PARENTBE
:
2501 return (gettext("No parent uuid"));
2502 case BE_ERR_ZONE_MULTIPLE_ACTIVE
:
2503 return (gettext("Multiple active zone roots"));
2504 case BE_ERR_ZONE_NO_ACTIVE_ROOT
:
2505 return (gettext("No active zone root"));
2506 case BE_ERR_ZONE_ROOT_NOT_LEGACY
:
2507 return (gettext("Zone root not legacy"));
2508 case BE_ERR_MOUNT_ZONEROOT
:
2509 return (gettext("Failed to mount a zone root."));
2510 case BE_ERR_UMOUNT_ZONEROOT
:
2511 return (gettext("Failed to unmount a zone root."));
2512 case BE_ERR_NO_MOUNTED_ZONE
:
2513 return (gettext("Zone is not mounted"));
2514 case BE_ERR_ZONES_UNMOUNT
:
2515 return (gettext("Unable to unmount a zone BE."));
2516 case BE_ERR_NO_MENU
:
2517 return (gettext("Missing boot menu file."));
2518 case BE_ERR_BAD_MENU_PATH
:
2519 return (gettext("Invalid path for menu.lst file"));
2520 case BE_ERR_ZONE_SS_EXISTS
:
2521 return (gettext("Zone snapshot exists."));
2522 case BE_ERR_BOOTFILE_INST
:
2523 return (gettext("Error installing boot files."));
2525 return (gettext("Error running an external command."));
2532 * Function: be_is_isa
2533 * Description: Boolean function indicating whether the instruction set
2534 * architecture of the executing system matches the name provided.
2535 * The string must match a system defined architecture (e.g.
2536 * "i386", "sparc") and is case sensitive.
2537 * Parameters: name - string representing the name of instruction set
2538 * architecture being tested
2539 * Returns: B_FALSE - the system instruction set architecture is different
2540 * from the one specified
2541 * B_TRUE - the system instruction set architecture is the same
2542 * as the one specified
2544 * Semi-private (library wide use only)
2547 be_is_isa(char *name
)
2549 return ((strcmp((char *)be_get_default_isa(), name
) == 0));
2553 * Function: be_get_default_isa
2555 * Returns the default instruction set architecture of the
2556 * machine it is executed on. (eg. sparc, i386, ...)
2557 * NOTE: SYS_INST environment variable may override default
2562 * NULL - the architecture returned by sysinfo() was too
2563 * long for local variables
2564 * char * - pointer to a string containing the default
2567 * Semi-private (library wide use only)
2570 be_get_default_isa(void)
2574 static char default_inst
[ARCH_LENGTH
] = "";
2576 if (default_inst
[0] == '\0') {
2577 if ((envp
= getenv("SYS_INST")) != NULL
) {
2578 if ((int)strlen(envp
) >= ARCH_LENGTH
)
2581 (void) strcpy(default_inst
, envp
);
2583 i
= sysinfo(SI_ARCHITECTURE
, default_inst
, ARCH_LENGTH
);
2584 if (i
< 0 || i
> ARCH_LENGTH
)
2588 return (default_inst
);
2592 * Function: be_get_platform
2594 * Returns the platfom name
2598 * NULL - the platform name returned by sysinfo() was too
2599 * long for local variables
2600 * char * - pointer to a string containing the platform name
2602 * Semi-private (library wide use only)
2605 be_get_platform(void)
2608 static char default_inst
[ARCH_LENGTH
] = "";
2610 if (default_inst
[0] == '\0') {
2611 i
= sysinfo(SI_PLATFORM
, default_inst
, ARCH_LENGTH
);
2612 if (i
< 0 || i
> ARCH_LENGTH
)
2615 return (default_inst
);
2619 * Function: be_run_cmd
2621 * Runs a command in a separate subprocess. Splits out stdout from stderr
2622 * and sends each to its own buffer. Buffers must be pre-allocated and
2623 * passed in as arguments. Buffer sizes are also passed in as arguments.
2626 * - Command being run is assumed to not have any stdout or stderr
2628 * - Commands which emit total stderr output of greater than PIPE_BUF
2629 * bytes can hang. For such commands, a different implementation
2630 * which uses poll(2) must be used.
2631 * - stdout_buf can be NULL. In this case, stdout_bufsize is ignored, and
2632 * the stream which would have gone to it is sent to the bit
2634 * - stderr_buf cannot be NULL.
2635 * - Only subprocess errors are appended to the stderr_buf. Errors
2636 * running the command are reported through be_print_err().
2637 * - Data which would overflow its respective buffer is sent to the bit
2641 * command: command to run. Assumed not to have embedded stdout
2642 * or stderr redirection. May have stdin redirection,
2644 * stderr_buf: buffer returning subprocess stderr data. Errors
2645 * reported by this function are reported through
2647 * stderr_bufsize: size of stderr_buf
2648 * stdout_buf: buffer returning subprocess stdout data.
2649 * stdout_bufsize: size of stdout_buf
2651 * BE_SUCCESS - The command ran successfully without returning
2654 * - The command could not be run.
2655 * - The command terminated with error status.
2656 * - There were errors extracting or returning subprocess
2658 * BE_ERR_NOMEM - The command exceeds the command buffer size.
2659 * BE_ERR_INVAL - An invalid argument was specified.
2661 * Semi-private (library wide use only)
2664 be_run_cmd(char *command
, char *stderr_buf
, int stderr_bufsize
,
2665 char *stdout_buf
, int stdout_bufsize
)
2667 char *temp_filename
= strdup(tmpnam(NULL
));
2668 FILE *stdout_str
= NULL
;
2669 FILE *stderr_str
= NULL
;
2670 char cmdline
[BUFSIZ
];
2671 char oneline
[BUFSIZ
];
2673 int rval
= BE_SUCCESS
;
2675 if ((command
== NULL
) || (stderr_buf
== NULL
) ||
2676 (stderr_bufsize
<= 0) || (stdout_bufsize
< 0) ||
2677 ((stdout_buf
!= NULL
) ^ (stdout_bufsize
!= 0))) {
2678 return (BE_ERR_INVAL
);
2681 /* Set up command so popen returns stderr, not stdout */
2682 if (snprintf(cmdline
, BUFSIZ
, "%s 2> %s", command
,
2683 temp_filename
) >= BUFSIZ
) {
2684 rval
= BE_ERR_NOMEM
;
2688 /* Set up the fifo that will make stderr available. */
2689 if (mkfifo(temp_filename
, 0600) != 0) {
2690 (void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
2692 rval
= BE_ERR_EXTCMD
;
2696 if ((stdout_str
= popen(cmdline
, "r")) == NULL
) {
2697 (void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
2699 rval
= BE_ERR_EXTCMD
;
2703 if ((stderr_str
= fopen(temp_filename
, "r")) == NULL
) {
2704 (void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
2706 (void) pclose(stdout_str
);
2707 rval
= BE_ERR_EXTCMD
;
2711 /* Read stdout first, as it usually outputs more than stderr. */
2712 oneline
[BUFSIZ
-1] = '\0';
2713 while (fgets(oneline
, BUFSIZ
-1, stdout_str
) != NULL
) {
2714 if (stdout_str
!= NULL
) {
2715 (void) strlcat(stdout_buf
, oneline
, stdout_bufsize
);
2719 while (fgets(oneline
, BUFSIZ
-1, stderr_str
) != NULL
) {
2720 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
2723 /* Close pipe, get exit status. */
2724 if ((exit_status
= pclose(stdout_str
)) == -1) {
2725 (void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
2727 rval
= BE_ERR_EXTCMD
;
2728 } else if (WIFEXITED(exit_status
)) {
2729 exit_status
= (int)((char)WEXITSTATUS(exit_status
));
2731 * error code BC_NOUPDT means more recent version
2734 if (exit_status
!= BC_SUCCESS
&& exit_status
!= BC_NOUPDT
) {
2735 (void) snprintf(oneline
, BUFSIZ
, gettext("be_run_cmd: "
2736 "command terminated with error status: %d\n"),
2738 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
2739 rval
= BE_ERR_EXTCMD
;
2742 (void) snprintf(oneline
, BUFSIZ
, gettext("be_run_cmd: command "
2743 "terminated on signal: %s\n"),
2744 strsignal(WTERMSIG(exit_status
)));
2745 (void) strlcat(stderr_buf
, oneline
, stderr_bufsize
);
2746 rval
= BE_ERR_EXTCMD
;
2750 (void) unlink(temp_filename
);
2751 (void) free(temp_filename
);
2756 /* ******************************************************************** */
2757 /* Private Functions */
2758 /* ******************************************************************** */
2761 * Function: update_dataset
2762 * Description: This function takes a dataset name and replaces the zpool
2763 * and be_name components of the dataset with the new be_name
2766 * dataset - name of dataset
2767 * dataset_len - lenth of buffer in which dataset is passed in.
2768 * be_name - name of new BE name to update to.
2769 * old_rc_loc - dataset under which the root container dataset
2770 * for the old BE lives.
2771 * new_rc_loc - dataset under which the root container dataset
2772 * for the new BE lives.
2774 * BE_SUCCESS - Success
2775 * be_errno_t - Failure
2780 update_dataset(char *dataset
, int dataset_len
, char *be_name
,
2781 char *old_rc_loc
, char *new_rc_loc
)
2784 char *sub_ds
= NULL
;
2786 /* Tear off the BE container dataset */
2787 if ((ds
= be_make_name_from_ds(dataset
, old_rc_loc
)) == NULL
) {
2788 return (BE_ERR_INVAL
);
2791 /* Get dataset name relative to BE root, if there is one */
2792 sub_ds
= strchr(ds
, '/');
2794 /* Generate the BE root dataset name */
2795 be_make_root_ds(new_rc_loc
, be_name
, dataset
, dataset_len
);
2797 /* If a subordinate dataset name was found, append it */
2799 (void) strlcat(dataset
, sub_ds
, dataset_len
);
2802 return (BE_SUCCESS
);
2806 * Function: _update_vfstab
2807 * Description: This function updates a vfstab file to reflect the new
2808 * root container dataset location and be_name for all
2809 * entries listed in the be_fs_list_data_t structure passed in.
2811 * vfstab - vfstab file to modify
2812 * be_name - name of BE to update.
2813 * old_rc_loc - dataset under which the root container dataset
2814 * of the old BE resides in.
2815 * new_rc_loc - dataset under which the root container dataset
2816 * of the new BE resides in.
2817 * fld - be_fs_list_data_t pointer providing the list of
2818 * file systems to look for in vfstab.
2820 * BE_SUCCESS - Success
2821 * be_errno_t - Failure
2826 _update_vfstab(char *vfstab
, char *be_name
, char *old_rc_loc
,
2827 char *new_rc_loc
, be_fs_list_data_t
*fld
)
2830 char *tmp_vfstab
= NULL
;
2831 char comments_buf
[BUFSIZ
];
2832 FILE *comments
= NULL
;
2833 FILE *vfs_ents
= NULL
;
2836 char dev
[MAXPATHLEN
];
2839 int ret
= BE_SUCCESS
, err
= 0;
2841 int tmp_vfstab_len
= 0;
2846 * Open vfstab for reading twice. First is for comments,
2847 * second is for actual entries.
2849 if ((comments
= fopen(vfstab
, "r")) == NULL
||
2850 (vfs_ents
= fopen(vfstab
, "r")) == NULL
) {
2852 be_print_err(gettext("_update_vfstab: "
2853 "failed to open vfstab (%s): %s\n"), vfstab
,
2855 ret
= errno_to_be_err(err
);
2859 /* Grab the stats of the original vfstab file */
2860 if (stat(vfstab
, &sb
) != 0) {
2862 be_print_err(gettext("_update_vfstab: "
2863 "failed to stat file %s: %s\n"), vfstab
,
2865 ret
= errno_to_be_err(err
);
2869 /* Create tmp file for modified vfstab */
2870 if ((tmp_vfstab
= (char *)malloc(strlen(vfstab
) + 7))
2872 be_print_err(gettext("_update_vfstab: "
2873 "malloc failed\n"));
2877 tmp_vfstab_len
= strlen(vfstab
) + 7;
2878 (void) memset(tmp_vfstab
, 0, tmp_vfstab_len
);
2879 (void) strlcpy(tmp_vfstab
, vfstab
, tmp_vfstab_len
);
2880 (void) strlcat(tmp_vfstab
, "XXXXXX", tmp_vfstab_len
);
2881 if ((fd
= mkstemp(tmp_vfstab
)) == -1) {
2883 be_print_err(gettext("_update_vfstab: "
2884 "mkstemp failed: %s\n"), strerror(err
));
2885 ret
= errno_to_be_err(err
);
2888 if ((tfile
= fdopen(fd
, "w")) == NULL
) {
2890 be_print_err(gettext("_update_vfstab: "
2891 "could not open file for write\n"));
2893 ret
= errno_to_be_err(err
);
2897 while (fgets(comments_buf
, BUFSIZ
, comments
)) {
2898 for (c
= comments_buf
; *c
!= '\0' && isspace(*c
); c
++)
2902 } else if (*c
== '#') {
2904 * If line is a comment line, just put
2905 * it through to the tmp vfstab.
2907 (void) fputs(comments_buf
, tfile
);
2910 * Else line is a vfstab entry, grab it
2911 * into a vfstab struct.
2913 if (getvfsent(vfs_ents
, &vp
) != 0) {
2915 be_print_err(gettext("_update_vfstab: "
2916 "getvfsent failed: %s\n"), strerror(err
));
2917 ret
= errno_to_be_err(err
);
2921 if (vp
.vfs_special
== NULL
|| vp
.vfs_mountp
== NULL
) {
2922 (void) putvfsent(tfile
, &vp
);
2927 * If the entry is one of the entries in the list
2928 * of file systems to update, modify it's device
2929 * field to be correct for this BE.
2931 for (i
= 0; i
< fld
->fs_num
; i
++) {
2932 if (strcmp(vp
.vfs_special
, fld
->fs_list
[i
])
2935 * Found entry that needs an update.
2936 * Replace the root container dataset
2937 * location and be_name in the
2940 (void) strlcpy(dev
, vp
.vfs_special
,
2943 if ((ret
= update_dataset(dev
,
2944 sizeof (dev
), be_name
, old_rc_loc
,
2945 new_rc_loc
)) != 0) {
2947 gettext("_update_vfstab: "
2948 "Failed to update device "
2949 "field for vfstab entry "
2950 "%s\n"), fld
->fs_list
[i
]);
2954 vp
.vfs_special
= dev
;
2959 /* Put entry through to tmp vfstab */
2960 (void) putvfsent(tfile
, &vp
);
2964 (void) fclose(comments
);
2966 (void) fclose(vfs_ents
);
2968 (void) fclose(tfile
);
2971 /* Copy tmp vfstab into place */
2972 if (rename(tmp_vfstab
, vfstab
) != 0) {
2974 be_print_err(gettext("_update_vfstab: "
2975 "failed to rename file %s to %s: %s\n"), tmp_vfstab
,
2976 vfstab
, strerror(err
));
2977 ret
= errno_to_be_err(err
);
2981 /* Set the perms and ownership of the updated file */
2982 if (chmod(vfstab
, sb
.st_mode
) != 0) {
2984 be_print_err(gettext("_update_vfstab: "
2985 "failed to chmod %s: %s\n"), vfstab
, strerror(err
));
2986 ret
= errno_to_be_err(err
);
2989 if (chown(vfstab
, sb
.st_uid
, sb
.st_gid
) != 0) {
2991 be_print_err(gettext("_update_vfstab: "
2992 "failed to chown %s: %s\n"), vfstab
, strerror(err
));
2993 ret
= errno_to_be_err(err
);
2998 if (comments
!= NULL
)
2999 (void) fclose(comments
);
3000 if (vfs_ents
!= NULL
)
3001 (void) fclose(vfs_ents
);
3002 (void) unlink(tmp_vfstab
);
3003 (void) free(tmp_vfstab
);
3005 (void) fclose(tfile
);
3012 * Function: be_get_auto_name
3013 * Description: Generate an auto name constructed based on the BE name
3014 * of the original BE or zone BE being cloned.
3016 * obe_name - name of the original BE or zone BE being cloned.
3017 * container_ds - container dataset for the zone.
3018 * Note: if zone_be is false this should be
3020 * zone_be - flag that indicates if we are operating on a zone BE.
3022 * Success - pointer to auto generated BE name. The name
3023 * is allocated in heap storage so the caller is
3024 * responsible for free'ing the name.
3030 be_get_auto_name(char *obe_name
, char *be_container_ds
, boolean_t zone_be
)
3032 be_node_list_t
*be_nodes
= NULL
;
3033 be_node_list_t
*cur_be
= NULL
;
3034 char auto_be_name
[MAXPATHLEN
];
3035 char base_be_name
[MAXPATHLEN
];
3036 char cur_be_name
[MAXPATHLEN
];
3037 char *num_str
= NULL
;
3045 * Check if obe_name is already in an auto BE name format.
3046 * If it is, then strip off the increment number to get the
3049 (void) strlcpy(base_be_name
, obe_name
, sizeof (base_be_name
));
3051 if ((num_str
= strrchr(base_be_name
, BE_AUTO_NAME_DELIM
))
3053 /* Make sure remaining string is all digits */
3055 while (c
[0] != '\0' && isdigit(c
[0]))
3058 * If we're now at the end of the string strip off the
3066 if (be_container_ds
== NULL
)
3068 if (be_get_zone_be_list(obe_name
, be_container_ds
,
3069 &be_nodes
) != BE_SUCCESS
) {
3070 be_print_err(gettext("be_get_auto_name: "
3071 "be_get_zone_be_list failed\n"));
3074 } else if (_be_list(NULL
, &be_nodes
) != BE_SUCCESS
) {
3075 be_print_err(gettext("be_get_auto_name: be_list failed\n"));
3079 for (cur_be
= be_nodes
; cur_be
!= NULL
; cur_be
= cur_be
->be_next_node
) {
3080 (void) strlcpy(cur_be_name
, cur_be
->be_node_name
,
3081 sizeof (cur_be_name
));
3083 /* If cur_be_name doesn't match at least base be name, skip. */
3084 if (strncmp(cur_be_name
, base_be_name
, strlen(base_be_name
))
3088 /* Get the string following the base be name */
3089 num_str
= cur_be_name
+ strlen(base_be_name
);
3092 * If nothing follows the base be name, this cur_be_name
3093 * is the BE named with the base be name, skip.
3095 if (num_str
== NULL
|| num_str
[0] == '\0')
3099 * Remove the name delimiter. If its not there,
3100 * cur_be_name isn't part of this BE name stream, skip.
3102 if (num_str
[0] == BE_AUTO_NAME_DELIM
)
3107 /* Make sure remaining string is all digits */
3109 while (c
[0] != '\0' && isdigit(c
[0]))
3114 /* Convert the number string to an int */
3115 cur_num
= atoi(num_str
);
3118 * If failed to convert the string, skip it. If its too
3119 * long to be converted to an int, we wouldn't auto generate
3120 * this number anyway so there couldn't be a conflict.
3121 * We treat it as a manually created BE name.
3123 if (cur_num
== 0 && errno
== EINVAL
)
3127 * Compare current number to current max number,
3128 * take higher of the two.
3135 * Store off a copy of 'num' incase we need it later. If incrementing
3136 * 'num' causes it to roll over, this means 'num' is the largest
3137 * positive int possible; we'll need it later in the loop to determine
3138 * if we've exhausted all possible increment numbers. We store it in
3143 /* Increment 'num' to get new auto BE name number */
3148 * Since incrementing 'num' caused it to rollover, start
3149 * over at 0 and find the first available number.
3151 for (num
= 0; num
< cur_num
; num
++) {
3153 (void) snprintf(cur_be_name
, sizeof (cur_be_name
),
3154 "%s%c%d", base_be_name
, BE_AUTO_NAME_DELIM
, num
);
3156 ret
= zpool_iter(g_zfs
, be_exists_callback
,
3161 * BE name doesn't exist, break out
3165 } else if (ret
== 1) {
3166 /* BE name exists, continue looking */
3169 be_print_err(gettext("be_get_auto_name: "
3170 "zpool_iter failed: %s\n"),
3171 libzfs_error_description(g_zfs
));
3172 be_free_list(be_nodes
);
3178 * If 'num' equals 'cur_num', we've exhausted all possible
3179 * auto BE names for this base BE name.
3181 if (num
== cur_num
) {
3182 be_print_err(gettext("be_get_auto_name: "
3183 "No more available auto BE names for base "
3184 "BE name %s\n"), base_be_name
);
3185 be_free_list(be_nodes
);
3190 be_free_list(be_nodes
);
3193 * Generate string for auto BE name.
3195 (void) snprintf(auto_be_name
, sizeof (auto_be_name
), "%s%c%d",
3196 base_be_name
, BE_AUTO_NAME_DELIM
, num
);
3198 if ((c
= strdup(auto_be_name
)) == NULL
) {
3199 be_print_err(gettext("be_get_auto_name: "
3200 "memory allocation failed\n"));
3208 * Function: be_create_menu
3210 * This function is used if no menu.lst file exists. In
3211 * this case a new file is created and if needed default
3212 * lines are added to the file.
3214 * pool - The name of the pool the menu.lst file is on
3215 * menu_file - The name of the file we're creating.
3216 * menu_fp - A pointer to the file pointer of the file we
3217 * created. This is also used to pass back the file
3218 * pointer to the newly created file.
3219 * mode - the original mode used for the failed attempt to
3220 * non-existent file.
3222 * BE_SUCCESS - Success
3223 * be_errno_t - Failure
3234 be_node_list_t
*be_nodes
= NULL
;
3235 char *menu_path
= NULL
;
3236 char *be_rpool
= NULL
;
3237 char *be_name
= NULL
;
3240 if (menu_file
== NULL
|| menu_fp
== NULL
|| mode
== NULL
)
3241 return (BE_ERR_INVAL
);
3243 menu_path
= strdup(menu_file
);
3244 if (menu_path
== NULL
)
3245 return (BE_ERR_NOMEM
);
3247 (void) dirname(menu_path
);
3248 if (*menu_path
== '.') {
3250 return (BE_ERR_BAD_MENU_PATH
);
3252 if (mkdirp(menu_path
,
3253 S_IRWXU
| S_IRGRP
| S_IXGRP
| S_IROTH
| S_IXOTH
) == -1 &&
3256 be_print_err(gettext("be_create_menu: Failed to create the %s "
3257 "directory: %s\n"), menu_path
, strerror(errno
));
3258 return (errno_to_be_err(errno
));
3263 * The menu file doesn't exist so we need to create a
3266 FILE *temp_fp
= fopen(menu_file
, "w+");
3267 if (temp_fp
== NULL
) {
3269 return (errno_to_be_err(errno
));
3271 (void) fclose(temp_fp
);
3274 * Now we need to add all the BE's back into the the file.
3276 if (_be_list(NULL
, &be_nodes
) == BE_SUCCESS
) {
3277 while (be_nodes
!= NULL
) {
3278 if (strcmp(pool
, be_nodes
->be_rpool
) == 0) {
3279 (void) be_append_menu(be_nodes
->be_node_name
,
3280 be_nodes
->be_rpool
, NULL
, NULL
, NULL
);
3282 if (be_nodes
->be_active_on_boot
) {
3283 be_rpool
= strdup(be_nodes
->be_rpool
);
3284 be_name
= strdup(be_nodes
->be_node_name
);
3287 be_nodes
= be_nodes
->be_next_node
;
3290 be_free_list(be_nodes
);
3292 *menu_fp
= fopen(menu_file
, mode
);
3293 if (*menu_fp
== NULL
)
3294 return (errno_to_be_err(errno
));
3296 return (BE_SUCCESS
);
3300 * Function: be_open_menu
3302 * This function is used it open the menu.lst file. If this
3303 * file does not exist be_create_menu is called to create it
3304 * and the open file pointer is returned. If the file does
3305 * exist it is simply opened using the mode passed in.
3307 * pool - The name of the pool the menu.lst file is on
3308 * menu_file - The name of the file we're opening.
3309 * menu_fp - A pointer to the file pointer of the file we're
3310 * opening. This is also used to pass back the file
3312 * mode - the original mode to be used for opening the menu.lst
3314 * create_menu - If this is true and the menu.lst file does not
3315 * exist we will attempt to re-create it. However
3316 * if it's false the error returned from the fopen
3319 * BE_SUCCESS - Success
3320 * be_errno_t - Failure
3330 boolean_t create_menu
)
3333 boolean_t set_print
= B_FALSE
;
3335 *menu_fp
= fopen(menu_file
, mode
);
3337 if (*menu_fp
== NULL
) {
3338 if (err
== ENOENT
&& create_menu
) {
3339 be_print_err(gettext("be_open_menu: menu.lst "
3340 "file %s does not exist,\n"), menu_file
);
3345 be_print_err(gettext("WARNING: menu.lst "
3346 "file %s does not exist,\n generating "
3347 "a new menu.lst file\n"), menu_file
);
3351 if ((err
= be_create_menu(pool
, menu_file
,
3352 menu_fp
, mode
)) == ENOENT
)
3353 return (BE_ERR_NO_MENU
);
3354 else if (err
!= BE_SUCCESS
)
3356 else if (*menu_fp
== NULL
)
3357 return (BE_ERR_NO_MENU
);
3359 be_print_err(gettext("be_open_menu: failed "
3360 "to open menu.lst file %s\n"), menu_file
);
3362 return (BE_ERR_NO_MENU
);
3364 return (errno_to_be_err(err
));
3367 return (BE_SUCCESS
);