7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
28 */
29
30 /*
31 * System includes
32 */
33
34 #include <assert.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <libgen.h>
38 #include <libintl.h>
39 #include <libnvpair.h>
40 #include <libzfs.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/mnttab.h>
45 #include <sys/mount.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
433
434 dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
435 dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
436
437 /* Find which zpool obe_name lives in */
438 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
439 be_print_err(gettext("be_destroy: failed to find zpool "
440 "for BE (%s)\n"), bt.obe_name);
441 return (BE_ERR_BE_NOENT);
442 } else if (zret < 0) {
443 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
444 libzfs_error_description(g_zfs));
445 return (zfs_err_to_be_err(g_zfs));
446 }
447
448 /* Generate string for obe_name's root dataset */
449 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
450 sizeof (obe_root_ds));
451 bt.obe_root_ds = obe_root_ds;
452
453 /*
454 * Detect if the BE to destroy has the 'active on boot' property set.
455 * If so, set the 'active on boot' property on the the 'active' BE.
456 */
457 if (be_is_active_on_boot(bt.obe_name)) {
458 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
459 be_print_err(gettext("be_destroy: failed to "
460 "make the current BE 'active on boot'\n"));
461 return (ret);
462 }
463 }
464
465 /* Get handle to BE's root dataset */
466 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
467 NULL) {
468 be_print_err(gettext("be_destroy: failed to "
469 "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
470 libzfs_error_description(g_zfs));
471 return (zfs_err_to_be_err(g_zfs));
472 }
473
474 /*
475 * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
476 * is not set.
477 */
478 (void) zfs_iter_snapshots(zhp, be_has_snapshot_callback, &bs_found);
479 if (!dd.destroy_snaps && bs_found) {
480 ZFS_CLOSE(zhp);
481 return (BE_ERR_SS_EXISTS);
482 }
483
484 /* Get the UUID of the global BE */
485 if (be_get_uuid(zfs_get_name(zhp), &dd.gz_be_uuid) != BE_SUCCESS) {
486 be_print_err(gettext("be_destroy: BE has no UUID (%s)\n"),
487 zfs_get_name(zhp));
488 }
489
490 /*
491 * If the global BE is mounted, make sure we've been given the
492 * flag to forcibly unmount it.
493 */
494 if (zfs_is_mounted(zhp, &mp)) {
495 if (!(dd.force_unmount)) {
496 be_print_err(gettext("be_destroy: "
497 "%s is currently mounted at %s, cannot destroy\n"),
498 bt.obe_name, mp != NULL ? mp : "<unknown>");
499
500 free(mp);
501 ZFS_CLOSE(zhp);
502 return (BE_ERR_MOUNTED);
503 }
504 free(mp);
505 }
506
507 /*
508 * Destroy the non-global zone BE's if we are in the global zone
578 * will be returned to the caller by setting them in the
579 * be_attrs parameter passed in:
580 *
581 * BE_ATTR_SNAP_NAME
582 * BE_ATTR_NEW_BE_NAME
583 * Return:
584 * BE_SUCCESS - Success
585 * be_errno_t - Failure
586 * Scope:
587 * Public
588 */
589 int
590 be_copy(nvlist_t *be_attrs)
591 {
592 be_transaction_data_t bt = { 0 };
593 be_fs_list_data_t fld = { 0 };
594 zfs_handle_t *zhp = NULL;
595 zpool_handle_t *zphp = NULL;
596 nvlist_t *zfs_props = NULL;
597 uuid_t uu = { 0 };
598 char obe_root_ds[MAXPATHLEN];
599 char nbe_root_ds[MAXPATHLEN];
600 char ss[MAXPATHLEN];
601 char *new_mp = NULL;
602 char *obe_name = NULL;
603 boolean_t autoname = B_FALSE;
604 boolean_t be_created = B_FALSE;
605 int i;
606 int zret;
607 int ret = BE_SUCCESS;
608 struct be_defaults be_defaults;
609
610 /* Initialize libzfs handle */
611 if (!be_zfs_init())
612 return (BE_ERR_INIT);
613
614 /* Get original BE name */
615 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
616 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
617 be_print_err(gettext("be_copy: failed to lookup "
736 be_print_err(gettext("be_copy: internal "
737 "error: out of memory\n"));
738 return (BE_ERR_NOMEM);
739 }
740 }
741
742 /*
743 * If new BE name provided, validate the BE name and then verify
744 * that new BE name doesn't already exist in some pool.
745 */
746 if (bt.nbe_name) {
747 /* Validate original BE name */
748 if (!be_valid_be_name(bt.nbe_name)) {
749 be_print_err(gettext("be_copy: "
750 "invalid BE name %s\n"), bt.nbe_name);
751 ret = BE_ERR_INVAL;
752 goto done;
753 }
754
755 /* Verify it doesn't already exist */
756 if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name))
757 > 0) {
758 be_print_err(gettext("be_copy: BE (%s) already "
759 "exists\n"), bt.nbe_name);
760 ret = BE_ERR_BE_EXISTS;
761 goto done;
762 } else if (zret < 0) {
763 be_print_err(gettext("be_copy: zpool_iter failed: "
764 "%s\n"), libzfs_error_description(g_zfs));
765 ret = zfs_err_to_be_err(g_zfs);
766 goto done;
767 }
768 } else {
769 /*
770 * If an auto named BE is desired, it must be in the same
771 * pool is the original BE.
772 */
773 if (bt.nbe_zpool != NULL) {
774 be_print_err(gettext("be_copy: cannot specify pool "
775 "name when creating an auto named BE\n"));
776 ret = BE_ERR_INVAL;
777 goto done;
778 }
779
780 /*
781 * Generate auto named BE
782 */
783 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
784 == NULL) {
785 be_print_err(gettext("be_copy: "
786 "failed to generate auto BE name\n"));
787 ret = BE_ERR_AUTONAME;
788 goto done;
999 * Set flag to note that the dataset(s) for the new BE have been
1000 * successfully created so that if a failure happens from this point
1001 * on, we know to cleanup these datasets.
1002 */
1003 be_created = B_TRUE;
1004
1005 /*
1006 * Validate that the new BE is mountable.
1007 * Do not attempt to mount non-global zone datasets
1008 * since they are not cloned yet.
1009 */
1010 if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1011 != BE_SUCCESS) {
1012 be_print_err(gettext("be_copy: failed to "
1013 "mount newly created BE\n"));
1014 (void) _be_unmount(bt.nbe_name, 0);
1015 goto done;
1016 }
1017
1018 /* Set UUID for new BE */
1019 if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
1020 be_print_err(gettext("be_copy: failed to "
1021 "set uuid for new BE\n"));
1022 }
1023
1024 /*
1025 * Process zones outside of the private BE namespace.
1026 * This has to be done here because we need the uuid set in the
1027 * root dataset of the new BE. The uuid is use to set the parentbe
1028 * property for the new zones datasets.
1029 */
1030 if (getzoneid() == GLOBAL_ZONEID &&
1031 be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1032 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1033 bt.nbe_root_ds)) != BE_SUCCESS) {
1034 be_print_err(gettext("be_copy: failed to process "
1035 "zones\n"));
1036 goto done;
1037 }
1038 }
1039
1040 /*
1041 * Generate a list of file systems from the original BE that are
1042 * legacy mounted. We use this list to determine which entries in
|
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 */
29
30 /*
31 * System includes
32 */
33
34 #include <assert.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <libgen.h>
38 #include <libintl.h>
39 #include <libnvpair.h>
40 #include <libzfs.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/mnttab.h>
45 #include <sys/mount.h>
46 #include <sys/stat.h>
47 #include <sys/types.h>
433
434 dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
435 dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
436
437 /* Find which zpool obe_name lives in */
438 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
439 be_print_err(gettext("be_destroy: failed to find zpool "
440 "for BE (%s)\n"), bt.obe_name);
441 return (BE_ERR_BE_NOENT);
442 } else if (zret < 0) {
443 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
444 libzfs_error_description(g_zfs));
445 return (zfs_err_to_be_err(g_zfs));
446 }
447
448 /* Generate string for obe_name's root dataset */
449 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
450 sizeof (obe_root_ds));
451 bt.obe_root_ds = obe_root_ds;
452
453 if (getzoneid() != GLOBAL_ZONEID) {
454 if (!be_zone_compare_uuids(bt.obe_root_ds)) {
455 if (be_is_active_on_boot(bt.obe_name)) {
456 be_print_err(gettext("be_destroy: destroying "
457 "active zone root dataset from non-active "
458 "global BE is not supported\n"));
459 return (BE_ERR_NOTSUP);
460 }
461 }
462 }
463
464 /*
465 * Detect if the BE to destroy has the 'active on boot' property set.
466 * If so, set the 'active on boot' property on the the 'active' BE.
467 */
468 if (be_is_active_on_boot(bt.obe_name)) {
469 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
470 be_print_err(gettext("be_destroy: failed to "
471 "make the current BE 'active on boot'\n"));
472 return (ret);
473 }
474 }
475
476 /* Get handle to BE's root dataset */
477 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
478 NULL) {
479 be_print_err(gettext("be_destroy: failed to "
480 "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
481 libzfs_error_description(g_zfs));
482 return (zfs_err_to_be_err(g_zfs));
483 }
484
485 /*
486 * Check if BE has snapshots and BE_DESTROY_FLAG_SNAPSHOTS
487 * is not set.
488 */
489 (void) zfs_iter_snapshots(zhp, be_has_snapshot_callback, &bs_found);
490 if (!dd.destroy_snaps && bs_found) {
491 ZFS_CLOSE(zhp);
492 return (BE_ERR_SS_EXISTS);
493 }
494
495 /* Get the UUID of the global BE */
496 if (getzoneid() == GLOBAL_ZONEID) {
497 if (be_get_uuid(zfs_get_name(zhp),
498 &dd.gz_be_uuid) != BE_SUCCESS) {
499 be_print_err(gettext("be_destroy: BE has no "
500 "UUID (%s)\n"), zfs_get_name(zhp));
501 }
502 }
503
504 /*
505 * If the global BE is mounted, make sure we've been given the
506 * flag to forcibly unmount it.
507 */
508 if (zfs_is_mounted(zhp, &mp)) {
509 if (!(dd.force_unmount)) {
510 be_print_err(gettext("be_destroy: "
511 "%s is currently mounted at %s, cannot destroy\n"),
512 bt.obe_name, mp != NULL ? mp : "<unknown>");
513
514 free(mp);
515 ZFS_CLOSE(zhp);
516 return (BE_ERR_MOUNTED);
517 }
518 free(mp);
519 }
520
521 /*
522 * Destroy the non-global zone BE's if we are in the global zone
592 * will be returned to the caller by setting them in the
593 * be_attrs parameter passed in:
594 *
595 * BE_ATTR_SNAP_NAME
596 * BE_ATTR_NEW_BE_NAME
597 * Return:
598 * BE_SUCCESS - Success
599 * be_errno_t - Failure
600 * Scope:
601 * Public
602 */
603 int
604 be_copy(nvlist_t *be_attrs)
605 {
606 be_transaction_data_t bt = { 0 };
607 be_fs_list_data_t fld = { 0 };
608 zfs_handle_t *zhp = NULL;
609 zpool_handle_t *zphp = NULL;
610 nvlist_t *zfs_props = NULL;
611 uuid_t uu = { 0 };
612 uuid_t parent_uu = { 0 };
613 char obe_root_ds[MAXPATHLEN];
614 char nbe_root_ds[MAXPATHLEN];
615 char ss[MAXPATHLEN];
616 char *new_mp = NULL;
617 char *obe_name = NULL;
618 boolean_t autoname = B_FALSE;
619 boolean_t be_created = B_FALSE;
620 int i;
621 int zret;
622 int ret = BE_SUCCESS;
623 struct be_defaults be_defaults;
624
625 /* Initialize libzfs handle */
626 if (!be_zfs_init())
627 return (BE_ERR_INIT);
628
629 /* Get original BE name */
630 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
631 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &obe_name, NULL) != 0) {
632 be_print_err(gettext("be_copy: failed to lookup "
751 be_print_err(gettext("be_copy: internal "
752 "error: out of memory\n"));
753 return (BE_ERR_NOMEM);
754 }
755 }
756
757 /*
758 * If new BE name provided, validate the BE name and then verify
759 * that new BE name doesn't already exist in some pool.
760 */
761 if (bt.nbe_name) {
762 /* Validate original BE name */
763 if (!be_valid_be_name(bt.nbe_name)) {
764 be_print_err(gettext("be_copy: "
765 "invalid BE name %s\n"), bt.nbe_name);
766 ret = BE_ERR_INVAL;
767 goto done;
768 }
769
770 /* Verify it doesn't already exist */
771 if (getzoneid() == GLOBAL_ZONEID) {
772 if ((zret = zpool_iter(g_zfs, be_exists_callback,
773 bt.nbe_name)) > 0) {
774 be_print_err(gettext("be_copy: BE (%s) already "
775 "exists\n"), bt.nbe_name);
776 ret = BE_ERR_BE_EXISTS;
777 goto done;
778 } else if (zret < 0) {
779 be_print_err(gettext("be_copy: zpool_iter "
780 "failed: %s\n"),
781 libzfs_error_description(g_zfs));
782 ret = zfs_err_to_be_err(g_zfs);
783 goto done;
784 }
785 } else {
786 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
787 sizeof (nbe_root_ds));
788 if (zfs_dataset_exists(g_zfs, nbe_root_ds,
789 ZFS_TYPE_FILESYSTEM)) {
790 be_print_err(gettext("be_copy: BE (%s) already "
791 "exists\n"), bt.nbe_name);
792 ret = BE_ERR_BE_EXISTS;
793 goto done;
794 }
795 }
796 } else {
797 /*
798 * If an auto named BE is desired, it must be in the same
799 * pool is the original BE.
800 */
801 if (bt.nbe_zpool != NULL) {
802 be_print_err(gettext("be_copy: cannot specify pool "
803 "name when creating an auto named BE\n"));
804 ret = BE_ERR_INVAL;
805 goto done;
806 }
807
808 /*
809 * Generate auto named BE
810 */
811 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
812 == NULL) {
813 be_print_err(gettext("be_copy: "
814 "failed to generate auto BE name\n"));
815 ret = BE_ERR_AUTONAME;
816 goto done;
1027 * Set flag to note that the dataset(s) for the new BE have been
1028 * successfully created so that if a failure happens from this point
1029 * on, we know to cleanup these datasets.
1030 */
1031 be_created = B_TRUE;
1032
1033 /*
1034 * Validate that the new BE is mountable.
1035 * Do not attempt to mount non-global zone datasets
1036 * since they are not cloned yet.
1037 */
1038 if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
1039 != BE_SUCCESS) {
1040 be_print_err(gettext("be_copy: failed to "
1041 "mount newly created BE\n"));
1042 (void) _be_unmount(bt.nbe_name, 0);
1043 goto done;
1044 }
1045
1046 /* Set UUID for new BE */
1047 if (getzoneid() == GLOBAL_ZONEID) {
1048 if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
1049 be_print_err(gettext("be_copy: failed to "
1050 "set uuid for new BE\n"));
1051 }
1052 } else {
1053 if ((ret = be_zone_get_parent_uuid(bt.obe_root_ds,
1054 &parent_uu)) != BE_SUCCESS) {
1055 be_print_err(gettext("be_copy: failed to get "
1056 "parentbe uuid from orig BE\n"));
1057 ret = BE_ERR_ZONE_NO_PARENTBE;
1058 goto done;
1059 } else if ((ret = be_zone_set_parent_uuid(bt.nbe_root_ds,
1060 parent_uu)) != BE_SUCCESS) {
1061 be_print_err(gettext("be_copy: failed to set "
1062 "parentbe uuid for newly created BE\n"));
1063 goto done;
1064 }
1065 }
1066
1067 /*
1068 * Process zones outside of the private BE namespace.
1069 * This has to be done here because we need the uuid set in the
1070 * root dataset of the new BE. The uuid is use to set the parentbe
1071 * property for the new zones datasets.
1072 */
1073 if (getzoneid() == GLOBAL_ZONEID &&
1074 be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
1075 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
1076 bt.nbe_root_ds)) != BE_SUCCESS) {
1077 be_print_err(gettext("be_copy: failed to process "
1078 "zones\n"));
1079 goto done;
1080 }
1081 }
1082
1083 /*
1084 * Generate a list of file systems from the original BE that are
1085 * legacy mounted. We use this list to determine which entries in
|