comparison usr/src/lib/libbe/common/be_create.c @ 13025:3c7681e3e323

PSARC 2010/059 SNAP BE Management 6964804 SNAP BE management into ON 6971379 libbe should capture and give useful error when installgrub or ict.py fails. 6971390 beadm does not support labeled brand zones 6971394 BEADM_ERR_BE_DOES_NOT_EXIST has an extra space 6971397 libbe error messages need internationalization 6971402 Remove be_get_last_zone_be_callback 6971409 be_create_menu returns errors from both be_errno_t and errno sets
author Glenn Lagasse <glenn.lagasse@oracle.com>
date Wed, 04 Aug 2010 12:28:19 -0700
parents
children 70ccb19abd77
comparison
equal deleted inserted replaced
13024:c176c071a066 13025:3c7681e3e323
1 /*
2 * CDDL HEADER START
3 *
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.
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 * System includes
28 */
29
30 #include <assert.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <libgen.h>
34 #include <libintl.h>
35 #include <libnvpair.h>
36 #include <libzfs.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/mnttab.h>
41 #include <sys/mount.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44 #include <sys/wait.h>
45 #include <unistd.h>
46
47 #include <libbe.h>
48 #include <libbe_priv.h>
49
50 /* Library wide variables */
51 libzfs_handle_t *g_zfs = NULL;
52
53 /* Private function prototypes */
54 static int _be_destroy(const char *, be_destroy_data_t *);
55 static int be_destroy_zones(char *, char *, be_destroy_data_t *);
56 static int be_destroy_zone_roots(char *, be_destroy_data_t *);
57 static int be_destroy_zone_roots_callback(zfs_handle_t *, void *);
58 static int be_copy_zones(char *, char *, char *);
59 static int be_clone_fs_callback(zfs_handle_t *, void *);
60 static int be_destroy_callback(zfs_handle_t *, void *);
61 static int be_send_fs_callback(zfs_handle_t *, void *);
62 static int be_demote_callback(zfs_handle_t *, void *);
63 static int be_demote_find_clone_callback(zfs_handle_t *, void *);
64 static int be_demote_get_one_clone(zfs_handle_t *, void *);
65 static int be_get_snap(char *, char **);
66 static int be_prep_clone_send_fs(zfs_handle_t *, be_transaction_data_t *,
67 char *, int);
68 static boolean_t be_create_container_ds(char *);
69 static char *be_get_zone_be_name(char *root_ds, char *container_ds);
70 static int be_zone_root_exists_callback(zfs_handle_t *, void *);
71
72 /* ******************************************************************** */
73 /* Public Functions */
74 /* ******************************************************************** */
75
76 /*
77 * Function: be_init
78 * Description: Creates the initial datasets for a BE and leaves them
79 * unpopulated. The resultant BE can be mounted but can't
80 * yet be activated or booted.
81 * Parameters:
82 * be_attrs - pointer to nvlist_t of attributes being passed in.
83 * The following attributes are used by this function:
84 *
85 * BE_ATTR_NEW_BE_NAME *required
86 * BE_ATTR_NEW_BE_POOL *required
87 * BE_ATTR_ZFS_PROPERTIES *optional
88 * BE_ATTR_FS_NAMES *optional
89 * BE_ATTR_FS_NUM *optional
90 * BE_ATTR_SHARED_FS_NAMES *optional
91 * BE_ATTR_SHARED_FS_NUM *optional
92 * Return:
93 * BE_SUCCESS - Success
94 * be_errno_t - Failure
95 * Scope:
96 * Public
97 */
98 int
99 be_init(nvlist_t *be_attrs)
100 {
101 be_transaction_data_t bt = { 0 };
102 zpool_handle_t *zlp;
103 nvlist_t *zfs_props = NULL;
104 char nbe_root_ds[MAXPATHLEN];
105 char child_fs[MAXPATHLEN];
106 char **fs_names = NULL;
107 char **shared_fs_names = NULL;
108 uint16_t fs_num = 0;
109 uint16_t shared_fs_num = 0;
110 int nelem;
111 int i;
112 int zret = 0, ret = BE_SUCCESS;
113
114 /* Initialize libzfs handle */
115 if (!be_zfs_init())
116 return (BE_ERR_INIT);
117
118 /* Get new BE name */
119 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name)
120 != 0) {
121 be_print_err(gettext("be_init: failed to lookup "
122 "BE_ATTR_NEW_BE_NAME attribute\n"));
123 return (BE_ERR_INVAL);
124 }
125
126 /* Validate new BE name */
127 if (!be_valid_be_name(bt.nbe_name)) {
128 be_print_err(gettext("be_init: invalid BE name %s\n"),
129 bt.nbe_name);
130 return (BE_ERR_INVAL);
131 }
132
133 /* Get zpool name */
134 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_POOL, &bt.nbe_zpool)
135 != 0) {
136 be_print_err(gettext("be_init: failed to lookup "
137 "BE_ATTR_NEW_BE_POOL attribute\n"));
138 return (BE_ERR_INVAL);
139 }
140
141 /* Get file system attributes */
142 nelem = 0;
143 if (nvlist_lookup_pairs(be_attrs, 0,
144 BE_ATTR_FS_NUM, DATA_TYPE_UINT16, &fs_num,
145 BE_ATTR_FS_NAMES, DATA_TYPE_STRING_ARRAY, &fs_names, &nelem,
146 NULL) != 0) {
147 be_print_err(gettext("be_init: failed to lookup fs "
148 "attributes\n"));
149 return (BE_ERR_INVAL);
150 }
151 if (nelem != fs_num) {
152 be_print_err(gettext("be_init: size of FS_NAMES array (%d) "
153 "does not match FS_NUM (%d)\n"), nelem, fs_num);
154 return (BE_ERR_INVAL);
155 }
156
157 /* Get shared file system attributes */
158 nelem = 0;
159 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
160 BE_ATTR_SHARED_FS_NUM, DATA_TYPE_UINT16, &shared_fs_num,
161 BE_ATTR_SHARED_FS_NAMES, DATA_TYPE_STRING_ARRAY, &shared_fs_names,
162 &nelem, NULL) != 0) {
163 be_print_err(gettext("be_init: failed to lookup "
164 "shared fs attributes\n"));
165 return (BE_ERR_INVAL);
166 }
167 if (nelem != shared_fs_num) {
168 be_print_err(gettext("be_init: size of SHARED_FS_NAMES "
169 "array does not match SHARED_FS_NUM\n"));
170 return (BE_ERR_INVAL);
171 }
172
173 /* Verify that nbe_zpool exists */
174 if ((zlp = zpool_open(g_zfs, bt.nbe_zpool)) == NULL) {
175 be_print_err(gettext("be_init: failed to "
176 "find existing zpool (%s): %s\n"), bt.nbe_zpool,
177 libzfs_error_description(g_zfs));
178 return (zfs_err_to_be_err(g_zfs));
179 }
180 zpool_close(zlp);
181
182 /*
183 * Verify BE container dataset in nbe_zpool exists.
184 * If not, create it.
185 */
186 if (!be_create_container_ds(bt.nbe_zpool))
187 return (BE_ERR_CREATDS);
188
189 /*
190 * Verify that nbe_name doesn't already exist in some pool.
191 */
192 if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name)) > 0) {
193 be_print_err(gettext("be_init: BE (%s) already exists\n"),
194 bt.nbe_name);
195 return (BE_ERR_BE_EXISTS);
196 } else if (zret < 0) {
197 be_print_err(gettext("be_init: zpool_iter failed: %s\n"),
198 libzfs_error_description(g_zfs));
199 return (zfs_err_to_be_err(g_zfs));
200 }
201
202 /* Generate string for BE's root dataset */
203 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
204 sizeof (nbe_root_ds));
205
206 /*
207 * Create property list for new BE root dataset. If some
208 * zfs properties were already provided by the caller, dup
209 * that list. Otherwise initialize a new property list.
210 */
211 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
212 BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
213 != 0) {
214 be_print_err(gettext("be_init: failed to lookup "
215 "BE_ATTR_ZFS_PROPERTIES attribute\n"));
216 return (BE_ERR_INVAL);
217 }
218 if (zfs_props != NULL) {
219 /* Make sure its a unique nvlist */
220 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
221 !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
222 be_print_err(gettext("be_init: ZFS property list "
223 "not unique\n"));
224 return (BE_ERR_INVAL);
225 }
226
227 /* Dup the list */
228 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
229 be_print_err(gettext("be_init: failed to dup ZFS "
230 "property list\n"));
231 return (BE_ERR_NOMEM);
232 }
233 } else {
234 /* Initialize new nvlist */
235 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
236 be_print_err(gettext("be_init: internal "
237 "error: out of memory\n"));
238 return (BE_ERR_NOMEM);
239 }
240 }
241
242 /* Set the mountpoint property for the root dataset */
243 if (nvlist_add_string(bt.nbe_zfs_props,
244 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), "/") != 0) {
245 be_print_err(gettext("be_init: internal error "
246 "out of memory\n"));
247 ret = BE_ERR_NOMEM;
248 goto done;
249 }
250
251 /* Set the 'canmount' property */
252 if (nvlist_add_string(bt.nbe_zfs_props,
253 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
254 be_print_err(gettext("be_init: internal error "
255 "out of memory\n"));
256 ret = BE_ERR_NOMEM;
257 goto done;
258 }
259
260 /* Create BE root dataset for the new BE */
261 if (zfs_create(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM,
262 bt.nbe_zfs_props) != 0) {
263 be_print_err(gettext("be_init: failed to "
264 "create BE root dataset (%s): %s\n"), nbe_root_ds,
265 libzfs_error_description(g_zfs));
266 ret = zfs_err_to_be_err(g_zfs);
267 goto done;
268 }
269
270 /* Set UUID for new BE */
271 if ((ret = be_set_uuid(nbe_root_ds)) != BE_SUCCESS) {
272 be_print_err(gettext("be_init: failed to "
273 "set uuid for new BE\n"));
274 }
275
276 /*
277 * Clear the mountpoint property so that the non-shared
278 * file systems created below inherit their mountpoints.
279 */
280 (void) nvlist_remove(bt.nbe_zfs_props,
281 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT), DATA_TYPE_STRING);
282
283 /* Create the new BE's non-shared file systems */
284 for (i = 0; i < fs_num && fs_names[i]; i++) {
285 /*
286 * If fs == "/", skip it;
287 * we already created the root dataset
288 */
289 if (strcmp(fs_names[i], "/") == 0)
290 continue;
291
292 /* Generate string for file system */
293 (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
294 nbe_root_ds, fs_names[i]);
295
296 /* Create file system */
297 if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
298 bt.nbe_zfs_props) != 0) {
299 be_print_err(gettext("be_init: failed to create "
300 "BE's child dataset (%s): %s\n"), child_fs,
301 libzfs_error_description(g_zfs));
302 ret = zfs_err_to_be_err(g_zfs);
303 goto done;
304 }
305 }
306
307 /* Create the new BE's shared file systems */
308 if (shared_fs_num > 0) {
309 nvlist_t *props = NULL;
310
311 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
312 be_print_err(gettext("be_init: nvlist_alloc failed\n"));
313 ret = BE_ERR_NOMEM;
314 goto done;
315 }
316
317 for (i = 0; i < shared_fs_num; i++) {
318 /* Generate string for shared file system */
319 (void) snprintf(child_fs, sizeof (child_fs), "%s%s",
320 bt.nbe_zpool, shared_fs_names[i]);
321
322 if (nvlist_add_string(props,
323 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
324 shared_fs_names[i]) != 0) {
325 be_print_err(gettext("be_init: "
326 "internal error: out of memory\n"));
327 nvlist_free(props);
328 ret = BE_ERR_NOMEM;
329 goto done;
330 }
331
332 /* Create file system if it doesn't already exist */
333 if (zfs_dataset_exists(g_zfs, child_fs,
334 ZFS_TYPE_FILESYSTEM)) {
335 continue;
336 }
337 if (zfs_create(g_zfs, child_fs, ZFS_TYPE_FILESYSTEM,
338 props) != 0) {
339 be_print_err(gettext("be_init: failed to "
340 "create BE's shared dataset (%s): %s\n"),
341 child_fs, libzfs_error_description(g_zfs));
342 ret = zfs_err_to_be_err(g_zfs);
343 nvlist_free(props);
344 goto done;
345 }
346 }
347
348 nvlist_free(props);
349 }
350
351 done:
352 if (bt.nbe_zfs_props != NULL)
353 nvlist_free(bt.nbe_zfs_props);
354
355 be_zfs_fini();
356
357 return (ret);
358 }
359
360 /*
361 * Function: be_destroy
362 * Description: Destroy a BE and all of its children datasets, snapshots and
363 * zones that belong to the parent BE.
364 * Parameters:
365 * be_attrs - pointer to nvlist_t of attributes being passed in.
366 * The following attributes are used by this function:
367 *
368 * BE_ATTR_ORIG_BE_NAME *required
369 * BE_ATTR_DESTROY_FLAGS *optional
370 * Return:
371 * BE_SUCCESS - Success
372 * be_errno_t - Failure
373 * Scope:
374 * Public
375 */
376 int
377 be_destroy(nvlist_t *be_attrs)
378 {
379 zfs_handle_t *zhp = NULL;
380 be_transaction_data_t bt = { 0 };
381 be_transaction_data_t cur_bt = { 0 };
382 be_destroy_data_t dd = { 0 };
383 int ret = BE_SUCCESS;
384 uint16_t flags = 0;
385 int zret;
386 char obe_root_ds[MAXPATHLEN];
387 char *mp = NULL;
388
389 /* Initialize libzfs handle */
390 if (!be_zfs_init())
391 return (BE_ERR_INIT);
392
393 /* Get name of BE to delete */
394 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name)
395 != 0) {
396 be_print_err(gettext("be_destroy: failed to lookup "
397 "BE_ATTR_ORIG_BE_NAME attribute\n"));
398 return (BE_ERR_INVAL);
399 }
400
401 /*
402 * Validate BE name. If valid, then check that the original BE is not
403 * the active BE. If it is the 'active' BE then return an error code
404 * since we can't destroy the active BE.
405 */
406 if (!be_valid_be_name(bt.obe_name)) {
407 be_print_err(gettext("be_destroy: invalid BE name %s\n"),
408 bt.obe_name);
409 return (BE_ERR_INVAL);
410 } else if (bt.obe_name != NULL) {
411 if ((ret = be_find_current_be(&cur_bt)) != BE_SUCCESS) {
412 return (ret);
413 }
414 if (strcmp(cur_bt.obe_name, bt.obe_name) == 0) {
415 return (BE_ERR_DESTROY_CURR_BE);
416 }
417 }
418
419 /* Get destroy flags if provided */
420 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
421 BE_ATTR_DESTROY_FLAGS, DATA_TYPE_UINT16, &flags, NULL)
422 != 0) {
423 be_print_err(gettext("be_destroy: failed to lookup "
424 "BE_ATTR_DESTROY_FLAGS attribute\n"));
425 return (BE_ERR_INVAL);
426 }
427
428 dd.destroy_snaps = flags & BE_DESTROY_FLAG_SNAPSHOTS;
429 dd.force_unmount = flags & BE_DESTROY_FLAG_FORCE_UNMOUNT;
430
431 /* Find which zpool obe_name lives in */
432 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
433 be_print_err(gettext("be_destroy: failed to find zpool "
434 "for BE (%s)\n"), bt.obe_name);
435 return (BE_ERR_BE_NOENT);
436 } else if (zret < 0) {
437 be_print_err(gettext("be_destroy: zpool_iter failed: %s\n"),
438 libzfs_error_description(g_zfs));
439 return (zfs_err_to_be_err(g_zfs));
440 }
441
442 /* Generate string for obe_name's root dataset */
443 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
444 sizeof (obe_root_ds));
445 bt.obe_root_ds = obe_root_ds;
446
447 /*
448 * Detect if the BE to destroy has the 'active on boot' property set.
449 * If so, set the 'active on boot' property on the the 'active' BE.
450 */
451 if (be_is_active_on_boot(bt.obe_name)) {
452 if ((ret = be_activate_current_be()) != BE_SUCCESS) {
453 be_print_err(gettext("be_destroy: failed to "
454 "make the current BE 'active on boot'\n"));
455 return (ret);
456 }
457 }
458
459 /* Get handle to BE's root dataset */
460 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
461 NULL) {
462 be_print_err(gettext("be_destroy: failed to "
463 "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
464 libzfs_error_description(g_zfs));
465 return (zfs_err_to_be_err(g_zfs));
466 }
467
468 /* Get the UUID of the global BE */
469 if (be_get_uuid(zfs_get_name(zhp), &dd.gz_be_uuid) != BE_SUCCESS) {
470 be_print_err(gettext("be_destroy: BE has no UUID (%s)\n"),
471 zfs_get_name(zhp));
472 }
473
474 /*
475 * If the global BE is mounted, make sure we've been given the
476 * flag to forcibly unmount it.
477 */
478 if (zfs_is_mounted(zhp, &mp)) {
479 if (!(dd.force_unmount)) {
480 be_print_err(gettext("be_destroy: "
481 "%s is currently mounted at %s, cannot destroy\n"),
482 bt.obe_name, mp != NULL ? mp : "<unknown>");
483
484 free(mp);
485 ZFS_CLOSE(zhp);
486 return (BE_ERR_MOUNTED);
487 }
488 free(mp);
489 }
490
491 /*
492 * Destroy the non-global zone BE's if we are in the global zone
493 * and there is a UUID associated with the global zone BE
494 */
495 if (getzoneid() == GLOBAL_ZONEID && !uuid_is_null(dd.gz_be_uuid)) {
496 if ((ret = be_destroy_zones(bt.obe_name, bt.obe_root_ds, &dd))
497 != BE_SUCCESS) {
498 be_print_err(gettext("be_destroy: failed to "
499 "destroy one or more zones for BE %s\n"),
500 bt.obe_name);
501 goto done;
502 }
503 }
504
505 /* Unmount the BE if it was mounted */
506 if (zfs_is_mounted(zhp, NULL)) {
507 if ((ret = _be_unmount(bt.obe_name, BE_UNMOUNT_FLAG_FORCE))
508 != BE_SUCCESS) {
509 be_print_err(gettext("be_destroy: "
510 "failed to unmount %s\n"), bt.obe_name);
511 ZFS_CLOSE(zhp);
512 return (ret);
513 }
514 }
515 ZFS_CLOSE(zhp);
516
517 /* Destroy this BE */
518 if ((ret = _be_destroy((const char *)bt.obe_root_ds, &dd))
519 != BE_SUCCESS) {
520 goto done;
521 }
522
523 /* Remove BE's entry from the boot menu */
524 if (getzoneid() == GLOBAL_ZONEID) {
525 if ((ret = be_remove_menu(bt.obe_name, bt.obe_zpool, NULL))
526 != BE_SUCCESS) {
527 be_print_err(gettext("be_destroy: failed to "
528 "remove BE %s from the boot menu\n"),
529 bt.obe_root_ds);
530 goto done;
531 }
532 }
533
534 done:
535 be_zfs_fini();
536
537 return (ret);
538 }
539
540 /*
541 * Function: be_copy
542 * Description: This function makes a copy of an existing BE. If the original
543 * BE and the new BE are in the same pool, it uses zfs cloning to
544 * create the new BE, otherwise it does a physical copy.
545 * If the original BE name isn't provided, it uses the currently
546 * booted BE. If the new BE name isn't provided, it creates an
547 * auto named BE and returns that name to the caller.
548 * Parameters:
549 * be_attrs - pointer to nvlist_t of attributes being passed in.
550 * The following attributes are used by this function:
551 *
552 * BE_ATTR_ORIG_BE_NAME *optional
553 * BE_ATTR_SNAP_NAME *optional
554 * BE_ATTR_NEW_BE_NAME *optional
555 * BE_ATTR_NEW_BE_POOL *optional
556 * BE_ATTR_NEW_BE_DESC *optional
557 * BE_ATTR_ZFS_PROPERTIES *optional
558 * BE_ATTR_POLICY *optional
559 *
560 * If the BE_ATTR_NEW_BE_NAME was not passed in, upon
561 * successful BE creation, the following attribute values
562 * will be returned to the caller by setting them in the
563 * be_attrs parameter passed in:
564 *
565 * BE_ATTR_SNAP_NAME
566 * BE_ATTR_NEW_BE_NAME
567 * Return:
568 * BE_SUCCESS - Success
569 * be_errno_t - Failure
570 * Scope:
571 * Public
572 */
573 int
574 be_copy(nvlist_t *be_attrs)
575 {
576 be_transaction_data_t bt = { 0 };
577 be_fs_list_data_t fld = { 0 };
578 zfs_handle_t *zhp = NULL;
579 nvlist_t *zfs_props = NULL;
580 uuid_t uu = { 0 };
581 char obe_root_ds[MAXPATHLEN];
582 char nbe_root_ds[MAXPATHLEN];
583 char ss[MAXPATHLEN];
584 char *new_mp = NULL;
585 boolean_t autoname = B_FALSE;
586 boolean_t be_created = B_FALSE;
587 int i;
588 int zret;
589 int ret = BE_SUCCESS;
590
591 /* Initialize libzfs handle */
592 if (!be_zfs_init())
593 return (BE_ERR_INIT);
594
595 /* Get original BE name */
596 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
597 BE_ATTR_ORIG_BE_NAME, DATA_TYPE_STRING, &bt.obe_name, NULL) != 0) {
598 be_print_err(gettext("be_copy: failed to lookup "
599 "BE_ATTR_ORIG_BE_NAME attribute\n"));
600 return (BE_ERR_INVAL);
601 }
602
603 /* If original BE name not provided, use current BE */
604 if (bt.obe_name == NULL) {
605 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
606 return (ret);
607 }
608 } else {
609 /* Validate original BE name */
610 if (!be_valid_be_name(bt.obe_name)) {
611 be_print_err(gettext("be_copy: "
612 "invalid BE name %s\n"), bt.obe_name);
613 return (BE_ERR_INVAL);
614 }
615 }
616
617 /* Find which zpool obe_name lives in */
618 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) {
619 be_print_err(gettext("be_copy: failed to "
620 "find zpool for BE (%s)\n"), bt.obe_name);
621 return (BE_ERR_BE_NOENT);
622 } else if (zret < 0) {
623 be_print_err(gettext("be_copy: "
624 "zpool_iter failed: %s\n"),
625 libzfs_error_description(g_zfs));
626 return (zfs_err_to_be_err(g_zfs));
627 }
628
629 /* Get snapshot name of original BE if one was provided */
630 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
631 BE_ATTR_SNAP_NAME, DATA_TYPE_STRING, &bt.obe_snap_name, NULL)
632 != 0) {
633 be_print_err(gettext("be_copy: failed to lookup "
634 "BE_ATTR_SNAP_NAME attribute\n"));
635 return (BE_ERR_INVAL);
636 }
637
638 /* Get new BE name */
639 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
640 BE_ATTR_NEW_BE_NAME, DATA_TYPE_STRING, &bt.nbe_name, NULL)
641 != 0) {
642 be_print_err(gettext("be_copy: failed to lookup "
643 "BE_ATTR_NEW_BE_NAME attribute\n"));
644 return (BE_ERR_INVAL);
645 }
646
647 /* Get zpool name to create new BE in */
648 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
649 BE_ATTR_NEW_BE_POOL, DATA_TYPE_STRING, &bt.nbe_zpool, NULL) != 0) {
650 be_print_err(gettext("be_copy: failed to lookup "
651 "BE_ATTR_NEW_BE_POOL attribute\n"));
652 return (BE_ERR_INVAL);
653 }
654
655 /* Get new BE's description if one was provided */
656 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
657 BE_ATTR_NEW_BE_DESC, DATA_TYPE_STRING, &bt.nbe_desc, NULL) != 0) {
658 be_print_err(gettext("be_copy: failed to lookup "
659 "BE_ATTR_NEW_BE_DESC attribute\n"));
660 return (BE_ERR_INVAL);
661 }
662
663 /* Get BE policy to create this snapshot under */
664 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
665 BE_ATTR_POLICY, DATA_TYPE_STRING, &bt.policy, NULL) != 0) {
666 be_print_err(gettext("be_copy: failed to lookup "
667 "BE_ATTR_POLICY attribute\n"));
668 return (BE_ERR_INVAL);
669 }
670
671 /*
672 * Create property list for new BE root dataset. If some
673 * zfs properties were already provided by the caller, dup
674 * that list. Otherwise initialize a new property list.
675 */
676 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
677 BE_ATTR_ZFS_PROPERTIES, DATA_TYPE_NVLIST, &zfs_props, NULL)
678 != 0) {
679 be_print_err(gettext("be_copy: failed to lookup "
680 "BE_ATTR_ZFS_PROPERTIES attribute\n"));
681 return (BE_ERR_INVAL);
682 }
683 if (zfs_props != NULL) {
684 /* Make sure its a unique nvlist */
685 if (!(zfs_props->nvl_nvflag & NV_UNIQUE_NAME) &&
686 !(zfs_props->nvl_nvflag & NV_UNIQUE_NAME_TYPE)) {
687 be_print_err(gettext("be_copy: ZFS property list "
688 "not unique\n"));
689 return (BE_ERR_INVAL);
690 }
691
692 /* Dup the list */
693 if (nvlist_dup(zfs_props, &bt.nbe_zfs_props, 0) != 0) {
694 be_print_err(gettext("be_copy: "
695 "failed to dup ZFS property list\n"));
696 return (BE_ERR_NOMEM);
697 }
698 } else {
699 /* Initialize new nvlist */
700 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
701 be_print_err(gettext("be_copy: internal "
702 "error: out of memory\n"));
703 return (BE_ERR_NOMEM);
704 }
705 }
706
707 /*
708 * If new BE name provided, validate the BE name and then verify
709 * that new BE name doesn't already exist in some pool.
710 */
711 if (bt.nbe_name) {
712 /* Validate original BE name */
713 if (!be_valid_be_name(bt.nbe_name)) {
714 be_print_err(gettext("be_copy: "
715 "invalid BE name %s\n"), bt.nbe_name);
716 ret = BE_ERR_INVAL;
717 goto done;
718 }
719
720 /* Verify it doesn't already exist */
721 if ((zret = zpool_iter(g_zfs, be_exists_callback, bt.nbe_name))
722 > 0) {
723 be_print_err(gettext("be_copy: BE (%s) already "
724 "exists\n"), bt.nbe_name);
725 ret = BE_ERR_BE_EXISTS;
726 goto done;
727 } else if (zret < 0) {
728 be_print_err(gettext("be_copy: zpool_iter failed: "
729 "%s\n"), libzfs_error_description(g_zfs));
730 ret = zfs_err_to_be_err(g_zfs);
731 goto done;
732 }
733 } else {
734 /*
735 * If an auto named BE is desired, it must be in the same
736 * pool is the original BE.
737 */
738 if (bt.nbe_zpool != NULL) {
739 be_print_err(gettext("be_copy: cannot specify pool "
740 "name when creating an auto named BE\n"));
741 ret = BE_ERR_INVAL;
742 goto done;
743 }
744
745 /*
746 * Generate auto named BE
747 */
748 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
749 == NULL) {
750 be_print_err(gettext("be_copy: "
751 "failed to generate auto BE name\n"));
752 ret = BE_ERR_AUTONAME;
753 goto done;
754 }
755
756 autoname = B_TRUE;
757 }
758
759 /*
760 * If zpool name to create new BE in is not provided,
761 * create new BE in original BE's pool.
762 */
763 if (bt.nbe_zpool == NULL) {
764 bt.nbe_zpool = bt.obe_zpool;
765 }
766
767 /* Get root dataset names for obe_name and nbe_name */
768 be_make_root_ds(bt.obe_zpool, bt.obe_name, obe_root_ds,
769 sizeof (obe_root_ds));
770 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, nbe_root_ds,
771 sizeof (nbe_root_ds));
772
773 bt.obe_root_ds = obe_root_ds;
774 bt.nbe_root_ds = nbe_root_ds;
775
776 /*
777 * If an existing snapshot name has been provided to create from,
778 * verify that it exists for the original BE's root dataset.
779 */
780 if (bt.obe_snap_name != NULL) {
781
782 /* Generate dataset name for snapshot to use. */
783 (void) snprintf(ss, sizeof (ss), "%s@%s", bt.obe_root_ds,
784 bt.obe_snap_name);
785
786 /* Verify snapshot exists */
787 if (!zfs_dataset_exists(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) {
788 be_print_err(gettext("be_copy: "
789 "snapshot does not exist (%s): %s\n"), ss,
790 libzfs_error_description(g_zfs));
791 ret = BE_ERR_SS_NOENT;
792 goto done;
793 }
794 } else {
795 /*
796 * Else snapshot name was not provided, generate an
797 * auto named snapshot to use as its origin.
798 */
799 if ((ret = _be_create_snapshot(bt.obe_name,
800 &bt.obe_snap_name, bt.policy)) != BE_SUCCESS) {
801 be_print_err(gettext("be_copy: "
802 "failed to create auto named snapshot\n"));
803 goto done;
804 }
805
806 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME,
807 bt.obe_snap_name) != 0) {
808 be_print_err(gettext("be_copy: "
809 "failed to add snap name to be_attrs\n"));
810 ret = BE_ERR_NOMEM;
811 goto done;
812 }
813 }
814
815 /* Get handle to original BE's root dataset. */
816 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM))
817 == NULL) {
818 be_print_err(gettext("be_copy: failed to "
819 "open BE root dataset (%s): %s\n"), bt.obe_root_ds,
820 libzfs_error_description(g_zfs));
821 ret = zfs_err_to_be_err(g_zfs);
822 goto done;
823 }
824
825 /* If original BE is currently mounted, record its altroot. */
826 if (zfs_is_mounted(zhp, &bt.obe_altroot) && bt.obe_altroot == NULL) {
827 be_print_err(gettext("be_copy: failed to "
828 "get altroot of mounted BE %s: %s\n"),
829 bt.obe_name, libzfs_error_description(g_zfs));
830 ret = zfs_err_to_be_err(g_zfs);
831 goto done;
832 }
833
834 if (strcmp(bt.obe_zpool, bt.nbe_zpool) == 0) {
835
836 /* Do clone */
837
838 /*
839 * Iterate through original BE's datasets and clone
840 * them to create new BE. This call will end up closing
841 * the zfs handle passed in whether it succeeds for fails.
842 */
843 if ((ret = be_clone_fs_callback(zhp, &bt)) != 0) {
844 zhp = NULL;
845 /* Creating clone BE failed */
846 if (!autoname || ret != BE_ERR_BE_EXISTS) {
847 be_print_err(gettext("be_copy: "
848 "failed to clone new BE (%s) from "
849 "orig BE (%s)\n"),
850 bt.nbe_name, bt.obe_name);
851 ret = BE_ERR_CLONE;
852 goto done;
853 }
854
855 /*
856 * We failed to create the new BE because a BE with
857 * the auto-name we generated above has since come
858 * into existence. Regenerate a new auto-name
859 * and retry.
860 */
861 for (i = 1; i < BE_AUTO_NAME_MAX_TRY; i++) {
862
863 /* Sleep 1 before retrying */
864 (void) sleep(1);
865
866 /* Generate new auto BE name */
867 free(bt.nbe_name);
868 if ((bt.nbe_name = be_auto_be_name(bt.obe_name))
869 == NULL) {
870 be_print_err(gettext("be_copy: "
871 "failed to generate auto "
872 "BE name\n"));
873 ret = BE_ERR_AUTONAME;
874 goto done;
875 }
876
877 /*
878 * Regenerate string for new BE's
879 * root dataset name
880 */
881 be_make_root_ds(bt.nbe_zpool, bt.nbe_name,
882 nbe_root_ds, sizeof (nbe_root_ds));
883 bt.nbe_root_ds = nbe_root_ds;
884
885 /*
886 * Get handle to original BE's root dataset.
887 */
888 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds,
889 ZFS_TYPE_FILESYSTEM)) == NULL) {
890 be_print_err(gettext("be_copy: "
891 "failed to open BE root dataset "
892 "(%s): %s\n"), bt.obe_root_ds,
893 libzfs_error_description(g_zfs));
894 ret = zfs_err_to_be_err(g_zfs);
895 goto done;
896 }
897
898 /*
899 * Try to clone the BE again. This
900 * call will end up closing the zfs
901 * handle passed in whether it
902 * succeeds or fails.
903 */
904 ret = be_clone_fs_callback(zhp, &bt);
905 zhp = NULL;
906 if (ret == 0) {
907 break;
908 } else if (ret != BE_ERR_BE_EXISTS) {
909 be_print_err(gettext("be_copy: "
910 "failed to clone new BE "
911 "(%s) from orig BE (%s)\n"),
912 bt.nbe_name, bt.obe_name);
913 ret = BE_ERR_CLONE;
914 goto done;
915 }
916 }
917
918 /*
919 * If we've exhausted the maximum number of
920 * tries, free the auto BE name and return
921 * error.
922 */
923 if (i == BE_AUTO_NAME_MAX_TRY) {
924 be_print_err(gettext("be_copy: failed "
925 "to create unique auto BE name\n"));
926 free(bt.nbe_name);
927 bt.nbe_name = NULL;
928 ret = BE_ERR_AUTONAME;
929 goto done;
930 }
931 }
932 zhp = NULL;
933
934 } else {
935
936 /* Do copy (i.e. send BE datasets via zfs_send/recv) */
937
938 /*
939 * Verify BE container dataset in nbe_zpool exists.
940 * If not, create it.
941 */
942 if (!be_create_container_ds(bt.nbe_zpool)) {
943 ret = BE_ERR_CREATDS;
944 goto done;
945 }
946
947 /*
948 * Iterate through original BE's datasets and send
949 * them to the other pool. This call will end up closing
950 * the zfs handle passed in whether it succeeds or fails.
951 */
952 if ((ret = be_send_fs_callback(zhp, &bt)) != 0) {
953 be_print_err(gettext("be_copy: failed to "
954 "send BE (%s) to pool (%s)\n"), bt.obe_name,
955 bt.nbe_zpool);
956 ret = BE_ERR_COPY;
957 zhp = NULL;
958 goto done;
959 }
960 zhp = NULL;
961 }
962
963 /*
964 * Set flag to note that the dataset(s) for the new BE have been
965 * successfully created so that if a failure happens from this point
966 * on, we know to cleanup these datasets.
967 */
968 be_created = B_TRUE;
969
970 /*
971 * Validate that the new BE is mountable.
972 * Do not attempt to mount non-global zone datasets
973 * since they are not cloned yet.
974 */
975 if ((ret = _be_mount(bt.nbe_name, &new_mp, BE_MOUNT_FLAG_NO_ZONES))
976 != BE_SUCCESS) {
977 be_print_err(gettext("be_copy: failed to "
978 "mount newly created BE\n"));
979 (void) _be_unmount(bt.nbe_name, 0);
980 goto done;
981 }
982
983 /* Set UUID for new BE */
984 if (be_set_uuid(bt.nbe_root_ds) != BE_SUCCESS) {
985 be_print_err(gettext("be_copy: failed to "
986 "set uuid for new BE\n"));
987 }
988
989 /*
990 * Process zones outside of the private BE namespace.
991 * This has to be done here because we need the uuid set in the
992 * root dataset of the new BE. The uuid is use to set the parentbe
993 * property for the new zones datasets.
994 */
995 if (getzoneid() == GLOBAL_ZONEID &&
996 be_get_uuid(bt.obe_root_ds, &uu) == BE_SUCCESS) {
997 if ((ret = be_copy_zones(bt.obe_name, bt.obe_root_ds,
998 bt.nbe_root_ds)) != BE_SUCCESS) {
999 be_print_err(gettext("be_copy: failed to process "
1000 "zones\n"));
1001 goto done;
1002 }
1003 }
1004
1005 /*
1006 * Generate a list of file systems from the original BE that are
1007 * legacy mounted. We use this list to determine which entries in
1008 * vfstab we need to update for the new BE we've just created.
1009 */
1010 if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL,
1011 &fld)) != BE_SUCCESS) {
1012 be_print_err(gettext("be_copy: failed to "
1013 "get legacy mounted file system list for %s\n"),
1014 bt.obe_name);
1015 goto done;
1016 }
1017
1018 /*
1019 * Update new BE's vfstab.
1020 */
1021 if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool,
1022 &fld, new_mp)) != BE_SUCCESS) {
1023 be_print_err(gettext("be_copy: failed to "
1024 "update new BE's vfstab (%s)\n"), bt.nbe_name);
1025 goto done;
1026 }
1027
1028 /* Unmount the new BE */
1029 if ((ret = _be_unmount(bt.nbe_name, 0)) != BE_SUCCESS) {
1030 be_print_err(gettext("be_copy: failed to "
1031 "unmount newly created BE\n"));
1032 goto done;
1033 }
1034
1035 /*
1036 * Add boot menu entry for newly created clone
1037 */
1038 if (getzoneid() == GLOBAL_ZONEID &&
1039 (ret = be_append_menu(bt.nbe_name, bt.nbe_zpool,
1040 NULL, bt.obe_root_ds, bt.nbe_desc)) != BE_SUCCESS) {
1041 be_print_err(gettext("be_copy: failed to "
1042 "add BE (%s) to boot menu\n"), bt.nbe_name);
1043 goto done;
1044 }
1045
1046 /*
1047 * If we succeeded in creating an auto named BE, set its policy
1048 * type and return the auto generated name to the caller by storing
1049 * it in the nvlist passed in by the caller.
1050 */
1051 if (autoname) {
1052 /* Get handle to new BE's root dataset. */
1053 if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds,
1054 ZFS_TYPE_FILESYSTEM)) == NULL) {
1055 be_print_err(gettext("be_copy: failed to "
1056 "open BE root dataset (%s): %s\n"), bt.nbe_root_ds,
1057 libzfs_error_description(g_zfs));
1058 ret = zfs_err_to_be_err(g_zfs);
1059 goto done;
1060 }
1061
1062 /*
1063 * Set the policy type property into the new BE's root dataset
1064 */
1065 if (bt.policy == NULL) {
1066 /* If no policy type provided, use default type */
1067 bt.policy = be_default_policy();
1068 }
1069
1070 if (zfs_prop_set(zhp, BE_POLICY_PROPERTY, bt.policy) != 0) {
1071 be_print_err(gettext("be_copy: failed to "
1072 "set BE policy for %s: %s\n"), bt.nbe_name,
1073 libzfs_error_description(g_zfs));
1074 ret = zfs_err_to_be_err(g_zfs);
1075 goto done;
1076 }
1077
1078 /*
1079 * Return the auto generated name to the caller
1080 */
1081 if (bt.nbe_name) {
1082 if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME,
1083 bt.nbe_name) != 0) {
1084 be_print_err(gettext("be_copy: failed to "
1085 "add snap name to be_attrs\n"));
1086 }
1087 }
1088 }
1089
1090 done:
1091 ZFS_CLOSE(zhp);
1092 be_free_fs_list(&fld);
1093
1094 if (bt.nbe_zfs_props != NULL)
1095 nvlist_free(bt.nbe_zfs_props);
1096
1097 free(bt.obe_altroot);
1098 free(new_mp);
1099
1100 /*
1101 * If a failure occurred and we already created the datasets for
1102 * the new boot environment, destroy them.
1103 */
1104 if (ret != BE_SUCCESS && be_created) {
1105 be_destroy_data_t cdd = { 0 };
1106
1107 cdd.force_unmount = B_TRUE;
1108
1109 be_print_err(gettext("be_copy: "
1110 "destroying partially created boot environment\n"));
1111
1112 if (getzoneid() == GLOBAL_ZONEID && be_get_uuid(bt.nbe_root_ds,
1113 &cdd.gz_be_uuid) == 0)
1114 (void) be_destroy_zones(bt.nbe_name, bt.nbe_root_ds,
1115 &cdd);
1116
1117 (void) _be_destroy(bt.nbe_root_ds, &cdd);
1118 }
1119
1120 be_zfs_fini();
1121
1122 return (ret);
1123 }
1124
1125 /* ******************************************************************** */
1126 /* Semi-Private Functions */
1127 /* ******************************************************************** */
1128
1129 /*
1130 * Function: be_find_zpool_callback
1131 * Description: Callback function used to find the pool that a BE lives in.
1132 * Parameters:
1133 * zlp - zpool_handle_t pointer for the current pool being
1134 * looked at.
1135 * data - be_transaction_data_t pointer providing information
1136 * about the BE that's being searched for.
1137 * This function uses the obe_name member of this
1138 * parameter to use as the BE name to search for.
1139 * Upon successfully locating the BE, it populates
1140 * obe_zpool with the pool name that the BE is found in.
1141 * Returns:
1142 * 1 - BE exists in this pool.
1143 * 0 - BE does not exist in this pool.
1144 * Scope:
1145 * Semi-private (library wide use only)
1146 */
1147 int
1148 be_find_zpool_callback(zpool_handle_t *zlp, void *data)
1149 {
1150 be_transaction_data_t *bt = data;
1151 const char *zpool = zpool_get_name(zlp);
1152 char be_root_ds[MAXPATHLEN];
1153
1154 /*
1155 * Generate string for the BE's root dataset
1156 */
1157 be_make_root_ds(zpool, bt->obe_name, be_root_ds, sizeof (be_root_ds));
1158
1159 /*
1160 * Check if dataset exists
1161 */
1162 if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1163 /* BE's root dataset exists in zpool */
1164 bt->obe_zpool = strdup(zpool);
1165 zpool_close(zlp);
1166 return (1);
1167 }
1168
1169 zpool_close(zlp);
1170 return (0);
1171 }
1172
1173 /*
1174 * Function: be_exists_callback
1175 * Description: Callback function used to find out if a BE exists.
1176 * Parameters:
1177 * zlp - zpool_handle_t pointer to the current pool being
1178 * looked at.
1179 * data - BE name to look for.
1180 * Return:
1181 * 1 - BE exists in this pool.
1182 * 0 - BE does not exist in this pool.
1183 * Scope:
1184 * Semi-private (library wide use only)
1185 */
1186 int
1187 be_exists_callback(zpool_handle_t *zlp, void *data)
1188 {
1189 const char *zpool = zpool_get_name(zlp);
1190 char *be_name = data;
1191 char be_root_ds[MAXPATHLEN];
1192
1193 /*
1194 * Generate string for the BE's root dataset
1195 */
1196 be_make_root_ds(zpool, be_name, be_root_ds, sizeof (be_root_ds));
1197
1198 /*
1199 * Check if dataset exists
1200 */
1201 if (zfs_dataset_exists(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) {
1202 /* BE's root dataset exists in zpool */
1203 zpool_close(zlp);
1204 return (1);
1205 }
1206
1207 zpool_close(zlp);
1208 return (0);
1209 }
1210
1211 /*
1212 * Function: be_set_uuid
1213 * Description: This function generates a uuid, unparses it into
1214 * string representation, and sets that string into
1215 * a zfs user property for a root dataset of a BE.
1216 * The name of the user property used to store the
1217 * uuid is org.opensolaris.libbe:uuid
1218 *
1219 * Parameters:
1220 * root_ds - Root dataset of the BE to set a uuid on.
1221 * Return:
1222 * be_errno_t - Failure
1223 * BE_SUCCESS - Success
1224 * Scope:
1225 * Semi-private (library wide ues only)
1226 */
1227 int
1228 be_set_uuid(char *root_ds)
1229 {
1230 zfs_handle_t *zhp = NULL;
1231 uuid_t uu = { 0 };
1232 char uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1233 int ret = BE_SUCCESS;
1234
1235 /* Generate a UUID and unparse it into string form */
1236 uuid_generate(uu);
1237 if (uuid_is_null(uu) != 0) {
1238 be_print_err(gettext("be_set_uuid: failed to "
1239 "generate uuid\n"));
1240 return (BE_ERR_GEN_UUID);
1241 }
1242 uuid_unparse(uu, uu_string);
1243
1244 /* Get handle to the BE's root dataset. */
1245 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1246 be_print_err(gettext("be_set_uuid: failed to "
1247 "open BE root dataset (%s): %s\n"), root_ds,
1248 libzfs_error_description(g_zfs));
1249 return (zfs_err_to_be_err(g_zfs));
1250 }
1251
1252 /* Set uuid property for the BE */
1253 if (zfs_prop_set(zhp, BE_UUID_PROPERTY, uu_string) != 0) {
1254 be_print_err(gettext("be_set_uuid: failed to "
1255 "set uuid property for BE: %s\n"),
1256 libzfs_error_description(g_zfs));
1257 ret = zfs_err_to_be_err(g_zfs);
1258 }
1259
1260 ZFS_CLOSE(zhp);
1261
1262 return (ret);
1263 }
1264
1265 /*
1266 * Function: be_get_uuid
1267 * Description: This function gets the uuid string from a BE root
1268 * dataset, parses it into internal format, and returns
1269 * it the caller via a reference pointer passed in.
1270 *
1271 * Parameters:
1272 * rootds - Root dataset of the BE to get the uuid from.
1273 * uu - reference pointer to a uuid_t to return uuid in.
1274 * Return:
1275 * be_errno_t - Failure
1276 * BE_SUCCESS - Success
1277 * Scope:
1278 * Semi-private (library wide use only)
1279 */
1280 int
1281 be_get_uuid(const char *root_ds, uuid_t *uu)
1282 {
1283 zfs_handle_t *zhp = NULL;
1284 nvlist_t *userprops = NULL;
1285 nvlist_t *propname = NULL;
1286 char *uu_string = NULL;
1287 int ret = BE_SUCCESS;
1288
1289 /* Get handle to the BE's root dataset. */
1290 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
1291 be_print_err(gettext("be_get_uuid: failed to "
1292 "open BE root dataset (%s): %s\n"), root_ds,
1293 libzfs_error_description(g_zfs));
1294 return (zfs_err_to_be_err(g_zfs));
1295 }
1296
1297 /* Get user properties for BE's root dataset */
1298 if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1299 be_print_err(gettext("be_get_uuid: failed to "
1300 "get user properties for BE root dataset (%s): %s\n"),
1301 root_ds, libzfs_error_description(g_zfs));
1302 ret = zfs_err_to_be_err(g_zfs);
1303 goto done;
1304 }
1305
1306 /* Get UUID string from BE's root dataset user properties */
1307 if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propname) != 0 ||
1308 nvlist_lookup_string(propname, ZPROP_VALUE, &uu_string) != 0) {
1309 /*
1310 * This probably just means that the BE is simply too old
1311 * to have a uuid or that we haven't created a uuid for
1312 * this BE yet.
1313 */
1314 be_print_err(gettext("be_get_uuid: failed to "
1315 "get uuid property from BE root dataset user "
1316 "properties.\n"));
1317 ret = BE_ERR_NO_UUID;
1318 goto done;
1319 }
1320 /* Parse uuid string into internal format */
1321 if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
1322 be_print_err(gettext("be_get_uuid: failed to "
1323 "parse uuid\n"));
1324 ret = BE_ERR_PARSE_UUID;
1325 goto done;
1326 }
1327
1328 done:
1329 ZFS_CLOSE(zhp);
1330 return (ret);
1331 }
1332
1333 /* ******************************************************************** */
1334 /* Private Functions */
1335 /* ******************************************************************** */
1336
1337 /*
1338 * Function: _be_destroy
1339 * Description: Destroy a BE and all of its children datasets and snapshots.
1340 * This function is called for both global BEs and non-global BEs.
1341 * The root dataset of either the global BE or non-global BE to be
1342 * destroyed is passed in.
1343 * Parameters:
1344 * root_ds - pointer to the name of the root dataset of the
1345 * BE to destroy.
1346 * dd - pointer to a be_destroy_data_t structure.
1347 *
1348 * Return:
1349 * BE_SUCCESS - Success
1350 * be_errno_t - Failure
1351 * Scope:
1352 * Private
1353 */
1354 static int
1355 _be_destroy(const char *root_ds, be_destroy_data_t *dd)
1356 {
1357 zfs_handle_t *zhp = NULL;
1358 char origin[MAXPATHLEN];
1359 char parent[MAXPATHLEN];
1360 char *snap = NULL;
1361 boolean_t has_origin = B_FALSE;
1362 int ret = BE_SUCCESS;
1363
1364 /* Get handle to BE's root dataset */
1365 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1366 NULL) {
1367 be_print_err(gettext("be_destroy: failed to "
1368 "open BE root dataset (%s): %s\n"), root_ds,
1369 libzfs_error_description(g_zfs));
1370 return (zfs_err_to_be_err(g_zfs));
1371 }
1372
1373 /*
1374 * Demote this BE in case it has dependent clones. This call
1375 * will end up closing the zfs handle passed in whether it
1376 * succeeds or fails.
1377 */
1378 if (be_demote_callback(zhp, NULL) != 0) {
1379 be_print_err(gettext("be_destroy: "
1380 "failed to demote BE %s\n"), root_ds);
1381 return (BE_ERR_DEMOTE);
1382 }
1383
1384 /* Get handle to BE's root dataset */
1385 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) ==
1386 NULL) {
1387 be_print_err(gettext("be_destroy: failed to "
1388 "open BE root dataset (%s): %s\n"), root_ds,
1389 libzfs_error_description(g_zfs));
1390 return (zfs_err_to_be_err(g_zfs));
1391 }
1392
1393 /*
1394 * Get the origin of this BE's root dataset. This will be used
1395 * later to destroy the snapshots originally used to create this BE.
1396 */
1397 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1398 NULL, 0, B_FALSE) == 0) {
1399 (void) strlcpy(parent, origin, sizeof (parent));
1400 if (be_get_snap(parent, &snap) != BE_SUCCESS) {
1401 ZFS_CLOSE(zhp);
1402 be_print_err(gettext("be_destroy: failed to "
1403 "get snapshot name from origin %s\n"), origin);
1404 return (BE_ERR_INVAL);
1405 }
1406 has_origin = B_TRUE;
1407 }
1408
1409 /*
1410 * Destroy the BE's root and its hierarchical children. This call
1411 * will end up closing the zfs handle passed in whether it succeeds
1412 * or fails.
1413 */
1414 if (be_destroy_callback(zhp, dd) != 0) {
1415 be_print_err(gettext("be_destroy: failed to "
1416 "destroy BE %s\n"), root_ds);
1417 return (BE_ERR_DESTROY);
1418 }
1419
1420 /* If BE has an origin */
1421 if (has_origin) {
1422
1423 /*
1424 * If origin snapshot doesn't have any other
1425 * dependents, delete the origin.
1426 */
1427 if ((zhp = zfs_open(g_zfs, origin, ZFS_TYPE_SNAPSHOT)) ==
1428 NULL) {
1429 be_print_err(gettext("be_destroy: failed to "
1430 "open BE's origin (%s): %s\n"), origin,
1431 libzfs_error_description(g_zfs));
1432 ret = zfs_err_to_be_err(g_zfs);
1433 return (ret);
1434 }
1435
1436 /* If origin has dependents, don't delete it. */
1437 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
1438 ZFS_CLOSE(zhp);
1439 return (ret);
1440 }
1441 ZFS_CLOSE(zhp);
1442
1443 /* Get handle to BE's parent's root dataset */
1444 if ((zhp = zfs_open(g_zfs, parent, ZFS_TYPE_FILESYSTEM)) ==
1445 NULL) {
1446 be_print_err(gettext("be_destroy: failed to "
1447 "open BE's parent root dataset (%s): %s\n"), parent,
1448 libzfs_error_description(g_zfs));
1449 ret = zfs_err_to_be_err(g_zfs);
1450 return (ret);
1451 }
1452
1453 /* Destroy the snapshot origin used to create this BE. */
1454 /*
1455 * The boolean set to B_FALSE and passed to zfs_destroy_snaps()
1456 * tells zfs to process and destroy the snapshots now.
1457 * Otherwise the call will potentially return where the
1458 * snapshot isn't actually destroyed yet, and ZFS is waiting
1459 * until all the references to the snapshot have been
1460 * released before actually destroying the snapshot.
1461 */
1462 if (zfs_destroy_snaps(zhp, snap, B_FALSE) != 0) {
1463 be_print_err(gettext("be_destroy: failed to "
1464 "destroy original snapshots used to create "
1465 "BE: %s\n"), libzfs_error_description(g_zfs));
1466
1467 /*
1468 * If a failure happened because a clone exists,
1469 * don't return a failure to the user. Above, we're
1470 * only checking that the root dataset's origin
1471 * snapshot doesn't have dependent clones, but its
1472 * possible that a subordinate dataset origin snapshot
1473 * has a clone. We really need to check for that
1474 * before trying to destroy the origin snapshot.
1475 */
1476 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1477 ret = zfs_err_to_be_err(g_zfs);
1478 ZFS_CLOSE(zhp);
1479 return (ret);
1480 }
1481 }
1482 ZFS_CLOSE(zhp);
1483 }
1484
1485 return (ret);
1486 }
1487
1488 /*
1489 * Function: be_destroy_zones
1490 * Description: Find valid zone's and call be_destroy_zone_roots to destroy its
1491 * corresponding dataset and all of its children datasets
1492 * and snapshots.
1493 * Parameters:
1494 * be_name - name of global boot environment being destroyed
1495 * be_root_ds - root dataset of global boot environment being
1496 * destroyed.
1497 * dd - be_destroy_data_t pointer
1498 * Return:
1499 * BE_SUCCESS - Success
1500 * be_errno_t - Failure
1501 * Scope:
1502 * Private
1503 *
1504 * NOTES - Requires that the BE being deleted has no dependent BEs. If it
1505 * does, the destroy will fail.
1506 */
1507 static int
1508 be_destroy_zones(char *be_name, char *be_root_ds, be_destroy_data_t *dd)
1509 {
1510 int i;
1511 int ret = BE_SUCCESS;
1512 int force_umnt = BE_UNMOUNT_FLAG_NULL;
1513 char *zonepath = NULL;
1514 char *zonename = NULL;
1515 char *zonepath_ds = NULL;
1516 char *mp = NULL;
1517 zoneList_t zlist = NULL;
1518 zoneBrandList_t *brands = NULL;
1519 zfs_handle_t *zhp = NULL;
1520
1521 /* If zones are not implemented, then get out. */
1522 if (!z_zones_are_implemented()) {
1523 return (BE_SUCCESS);
1524 }
1525
1526 /* Get list of supported brands */
1527 if ((brands = be_get_supported_brandlist()) == NULL) {
1528 be_print_err(gettext("be_destroy_zones: "
1529 "no supported brands\n"));
1530 return (BE_SUCCESS);
1531 }
1532
1533 /* Get handle to BE's root dataset */
1534 if ((zhp = zfs_open(g_zfs, be_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1535 NULL) {
1536 be_print_err(gettext("be_destroy_zones: failed to "
1537 "open BE root dataset (%s): %s\n"), be_root_ds,
1538 libzfs_error_description(g_zfs));
1539 z_free_brand_list(brands);
1540 return (zfs_err_to_be_err(g_zfs));
1541 }
1542
1543 /*
1544 * If the global BE is not mounted, we must mount it here to
1545 * gather data about the non-global zones in it.
1546 */
1547 if (!zfs_is_mounted(zhp, &mp)) {
1548 if ((ret = _be_mount(be_name, &mp,
1549 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1550 be_print_err(gettext("be_destroy_zones: failed to "
1551 "mount the BE (%s) for zones processing.\n"),
1552 be_name);
1553 ZFS_CLOSE(zhp);
1554 z_free_brand_list(brands);
1555 return (ret);
1556 }
1557 }
1558 ZFS_CLOSE(zhp);
1559
1560 z_set_zone_root(mp);
1561 free(mp);
1562
1563 /* Get list of supported zones. */
1564 if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1565 z_free_brand_list(brands);
1566 return (BE_SUCCESS);
1567 }
1568
1569 /* Unmount the BE before destroying the zones in it. */
1570 if (dd->force_unmount)
1571 force_umnt = BE_UNMOUNT_FLAG_FORCE;
1572 if ((ret = _be_unmount(be_name, force_umnt)) != BE_SUCCESS) {
1573 be_print_err(gettext("be_destroy_zones: failed to "
1574 "unmount the BE (%s)\n"), be_name);
1575 goto done;
1576 }
1577
1578 /* Iterate through the zones and destroy them. */
1579 for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1580
1581 /* Skip zones that aren't at least installed */
1582 if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1583 continue;
1584
1585 zonepath = z_zlist_get_zonepath(zlist, i);
1586
1587 /*
1588 * Get the dataset of this zonepath. If its not
1589 * a dataset, skip it.
1590 */
1591 if ((zonepath_ds = be_get_ds_from_dir(zonepath)) == NULL)
1592 continue;
1593
1594 /*
1595 * Check if this zone is supported based on the
1596 * dataset of its zonepath.
1597 */
1598 if (!be_zone_supported(zonepath_ds)) {
1599 free(zonepath_ds);
1600 continue;
1601 }
1602
1603 /* Find the zone BE root datasets for this zone. */
1604 if ((ret = be_destroy_zone_roots(zonepath_ds, dd))
1605 != BE_SUCCESS) {
1606 be_print_err(gettext("be_destroy_zones: failed to "
1607 "find and destroy zone roots for zone %s\n"),
1608 zonename);
1609 free(zonepath_ds);
1610 goto done;
1611 }
1612 free(zonepath_ds);
1613 }
1614
1615 done:
1616 z_free_brand_list(brands);
1617 z_free_zone_list(zlist);
1618
1619 return (ret);
1620 }
1621
1622 /*
1623 * Function: be_destroy_zone_roots
1624 * Description: This function will open the zone's root container dataset
1625 * and iterate the datasets within, looking for roots that
1626 * belong to the given global BE and destroying them.
1627 * If no other zone roots remain in the zone's root container
1628 * dataset, the function will destroy it and the zone's
1629 * zonepath dataset as well.
1630 * Parameters:
1631 * zonepath_ds - pointer to zone's zonepath dataset.
1632 * dd - pointer to a linked destroy data.
1633 * Returns:
1634 * BE_SUCCESS - Success
1635 * be_errno_t - Failure
1636 * Scope:
1637 * Private
1638 */
1639 static int
1640 be_destroy_zone_roots(char *zonepath_ds, be_destroy_data_t *dd)
1641 {
1642 zfs_handle_t *zhp;
1643 char zone_container_ds[MAXPATHLEN];
1644 int ret = BE_SUCCESS;
1645
1646 /* Generate string for the root container dataset for this zone. */
1647 be_make_container_ds(zonepath_ds, zone_container_ds,
1648 sizeof (zone_container_ds));
1649
1650 /* Get handle to this zone's root container dataset. */
1651 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1652 == NULL) {
1653 be_print_err(gettext("be_destroy_zone_roots: failed to "
1654 "open zone root container dataset (%s): %s\n"),
1655 zone_container_ds, libzfs_error_description(g_zfs));
1656 return (zfs_err_to_be_err(g_zfs));
1657 }
1658
1659 /*
1660 * Iterate through all of this zone's BEs, destroying the ones
1661 * that belong to the parent global BE.
1662 */
1663 if ((ret = zfs_iter_filesystems(zhp, be_destroy_zone_roots_callback,
1664 dd)) != 0) {
1665 be_print_err(gettext("be_destroy_zone_roots: failed to "
1666 "destroy zone roots under zonepath dataset %s: %s\n"),
1667 zonepath_ds, libzfs_error_description(g_zfs));
1668 ZFS_CLOSE(zhp);
1669 return (ret);
1670 }
1671 ZFS_CLOSE(zhp);
1672
1673 /* Get handle to this zone's root container dataset. */
1674 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
1675 == NULL) {
1676 be_print_err(gettext("be_destroy_zone_roots: failed to "
1677 "open zone root container dataset (%s): %s\n"),
1678 zone_container_ds, libzfs_error_description(g_zfs));
1679 return (zfs_err_to_be_err(g_zfs));
1680 }
1681
1682 /*
1683 * If there are no more zone roots in this zone's root container,
1684 * dataset, destroy it and the zonepath dataset as well.
1685 */
1686 if (zfs_iter_filesystems(zhp, be_zone_root_exists_callback, NULL)
1687 == 0) {
1688 /* Destroy the zone root container dataset */
1689 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1690 zfs_destroy(zhp, B_FALSE) != 0) {
1691 be_print_err(gettext("be_destroy_zone_roots: failed to "
1692 "destroy zone root container dataset (%s): %s\n"),
1693 zone_container_ds, libzfs_error_description(g_zfs));
1694 goto done;
1695 }
1696 ZFS_CLOSE(zhp);
1697
1698 /* Get handle to zonepath dataset */
1699 if ((zhp = zfs_open(g_zfs, zonepath_ds, ZFS_TYPE_FILESYSTEM))
1700 == NULL) {
1701 be_print_err(gettext("be_destroy_zone_roots: failed to "
1702 "open zonepath dataset (%s): %s\n"),
1703 zonepath_ds, libzfs_error_description(g_zfs));
1704 goto done;
1705 }
1706
1707 /* Destroy zonepath dataset */
1708 if (zfs_unmount(zhp, NULL, MS_FORCE) != 0 ||
1709 zfs_destroy(zhp, B_FALSE) != 0) {
1710 be_print_err(gettext("be_destroy_zone_roots: "
1711 "failed to destroy zonepath dataest %s: %s\n"),
1712 zonepath_ds, libzfs_error_description(g_zfs));
1713 goto done;
1714 }
1715 }
1716
1717 done:
1718 ZFS_CLOSE(zhp);
1719 return (ret);
1720 }
1721
1722 /*
1723 * Function: be_destroy_zone_roots_callback
1724 * Description: This function is used as a callback to iterate over all of
1725 * a zone's root datasets, finding the one's that
1726 * correspond to the current BE. The name's
1727 * of the zone root datasets are then destroyed by _be_destroy().
1728 * Parameters:
1729 * zhp - zfs_handle_t pointer to current dataset being processed
1730 * data - be_destroy_data_t pointer
1731 * Returns:
1732 * 0 - Success
1733 * be_errno_t - Failure
1734 * Scope:
1735 * Private
1736 */
1737 static int
1738 be_destroy_zone_roots_callback(zfs_handle_t *zhp, void *data)
1739 {
1740 be_destroy_data_t *dd = data;
1741 uuid_t parent_uuid = { 0 };
1742 int ret = 0;
1743
1744 if (be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid)
1745 != BE_SUCCESS) {
1746 be_print_err(gettext("be_destroy_zone_roots_callback: "
1747 "could not get parentuuid for zone root dataset %s\n"),
1748 zfs_get_name(zhp));
1749 ZFS_CLOSE(zhp);
1750 return (0);
1751 }
1752
1753 if (uuid_compare(dd->gz_be_uuid, parent_uuid) == 0) {
1754 /*
1755 * Found a zone root dataset belonging to the parent
1756 * BE being destroyed. Destroy this zone BE.
1757 */
1758 if ((ret = _be_destroy(zfs_get_name(zhp), dd)) != BE_SUCCESS) {
1759 be_print_err(gettext("be_destroy_zone_root_callback: "
1760 "failed to destroy zone root %s\n"),
1761 zfs_get_name(zhp));
1762 ZFS_CLOSE(zhp);
1763 return (ret);
1764 }
1765 }
1766 ZFS_CLOSE(zhp);
1767
1768 return (ret);
1769 }
1770
1771 /*
1772 * Function: be_copy_zones
1773 * Description: Find valid zones and clone them to create their
1774 * corresponding datasets for the BE being created.
1775 * Parameters:
1776 * obe_name - name of source global BE being copied.
1777 * obe_root_ds - root dataset of source global BE being copied.
1778 * nbe_root_ds - root dataset of target global BE.
1779 * Return:
1780 * BE_SUCCESS - Success
1781 * be_errno_t - Failure
1782 * Scope:
1783 * Private
1784 */
1785 static int
1786 be_copy_zones(char *obe_name, char *obe_root_ds, char *nbe_root_ds)
1787 {
1788 int i, num_retries;
1789 int ret = BE_SUCCESS;
1790 int iret = 0;
1791 char *zonename = NULL;
1792 char *zonepath = NULL;
1793 char *zone_be_name = NULL;
1794 char *temp_mntpt = NULL;
1795 char *new_zone_be_name = NULL;
1796 char zoneroot[MAXPATHLEN];
1797 char zoneroot_ds[MAXPATHLEN];
1798 char zone_container_ds[MAXPATHLEN];
1799 char new_zoneroot_ds[MAXPATHLEN];
1800 char ss[MAXPATHLEN];
1801 uuid_t uu = { 0 };
1802 char uu_string[UUID_PRINTABLE_STRING_LENGTH] = { 0 };
1803 be_transaction_data_t bt = { 0 };
1804 zfs_handle_t *obe_zhp = NULL;
1805 zfs_handle_t *nbe_zhp = NULL;
1806 zfs_handle_t *z_zhp = NULL;
1807 zoneList_t zlist = NULL;
1808 zoneBrandList_t *brands = NULL;
1809 boolean_t mounted_here = B_FALSE;
1810 char *snap_name = NULL;
1811
1812 /* If zones are not implemented, then get out. */
1813 if (!z_zones_are_implemented()) {
1814 return (BE_SUCCESS);
1815 }
1816
1817 /* Get list of supported brands */
1818 if ((brands = be_get_supported_brandlist()) == NULL) {
1819 be_print_err(gettext("be_copy_zones: "
1820 "no supported brands\n"));
1821 return (BE_SUCCESS);
1822 }
1823
1824 /* Get handle to origin BE's root dataset */
1825 if ((obe_zhp = zfs_open(g_zfs, obe_root_ds, ZFS_TYPE_FILESYSTEM))
1826 == NULL) {
1827 be_print_err(gettext("be_copy_zones: failed to open "
1828 "the origin BE root dataset (%s) for zones processing: "
1829 "%s\n"), obe_root_ds, libzfs_error_description(g_zfs));
1830 return (zfs_err_to_be_err(g_zfs));
1831 }
1832
1833 /* Get handle to newly cloned BE's root dataset */
1834 if ((nbe_zhp = zfs_open(g_zfs, nbe_root_ds, ZFS_TYPE_FILESYSTEM))
1835 == NULL) {
1836 be_print_err(gettext("be_copy_zones: failed to open "
1837 "the new BE root dataset (%s): %s\n"), nbe_root_ds,
1838 libzfs_error_description(g_zfs));
1839 ZFS_CLOSE(obe_zhp);
1840 return (zfs_err_to_be_err(g_zfs));
1841 }
1842
1843 /* Get the uuid of the newly cloned parent BE. */
1844 if (be_get_uuid(zfs_get_name(nbe_zhp), &uu) != BE_SUCCESS) {
1845 be_print_err(gettext("be_copy_zones: "
1846 "failed to get uuid for BE root "
1847 "dataset %s\n"), zfs_get_name(nbe_zhp));
1848 ZFS_CLOSE(nbe_zhp);
1849 goto done;
1850 }
1851 ZFS_CLOSE(nbe_zhp);
1852 uuid_unparse(uu, uu_string);
1853
1854 /*
1855 * If the origin BE is not mounted, we must mount it here to
1856 * gather data about the non-global zones in it.
1857 */
1858 if (!zfs_is_mounted(obe_zhp, &temp_mntpt)) {
1859 if ((ret = _be_mount(obe_name, &temp_mntpt,
1860 BE_MOUNT_FLAG_NULL)) != BE_SUCCESS) {
1861 be_print_err(gettext("be_copy_zones: failed to "
1862 "mount the BE (%s) for zones procesing.\n"),
1863 obe_name);
1864 goto done;
1865 }
1866 mounted_here = B_TRUE;
1867 }
1868
1869 z_set_zone_root(temp_mntpt);
1870
1871 /* Get list of supported zones. */
1872 if ((zlist = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1873 ret = BE_SUCCESS;
1874 goto done;
1875 }
1876
1877 for (i = 0; (zonename = z_zlist_get_zonename(zlist, i)) != NULL; i++) {
1878
1879 be_fs_list_data_t fld = { 0 };
1880 char zonepath_ds[MAXPATHLEN];
1881 char *ds = NULL;
1882
1883 /* Get zonepath of zone */
1884 zonepath = z_zlist_get_zonepath(zlist, i);
1885
1886 /* Skip zones that aren't at least installed */
1887 if (z_zlist_get_current_state(zlist, i) < ZONE_STATE_INSTALLED)
1888 continue;
1889
1890 /*
1891 * Get the dataset of this zonepath. If its not
1892 * a dataset, skip it.
1893 */
1894 if ((ds = be_get_ds_from_dir(zonepath)) == NULL)
1895 continue;
1896
1897 (void) strlcpy(zonepath_ds, ds, sizeof (zonepath_ds));
1898 free(ds);
1899 ds = NULL;
1900
1901 /* Get zoneroot directory */
1902 be_make_zoneroot(zonepath, zoneroot, sizeof (zoneroot));
1903
1904 /* If zonepath dataset not supported, skip it. */
1905 if (!be_zone_supported(zonepath_ds)) {
1906 continue;
1907 }
1908
1909 if ((ret = be_find_active_zone_root(obe_zhp, zonepath_ds,
1910 zoneroot_ds, sizeof (zoneroot_ds))) != BE_SUCCESS) {
1911 be_print_err(gettext("be_copy_zones: "
1912 "failed to find active zone root for zone %s "
1913 "in BE %s\n"), zonename, obe_name);
1914 goto done;
1915 }
1916
1917 be_make_container_ds(zonepath_ds, zone_container_ds,
1918 sizeof (zone_container_ds));
1919
1920 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1921 ZFS_TYPE_FILESYSTEM)) == NULL) {
1922 be_print_err(gettext("be_copy_zones: "
1923 "failed to open zone root dataset (%s): %s\n"),
1924 zoneroot_ds, libzfs_error_description(g_zfs));
1925 ret = zfs_err_to_be_err(g_zfs);
1926 goto done;
1927 }
1928
1929 zone_be_name =
1930 be_get_zone_be_name(zoneroot_ds, zone_container_ds);
1931
1932 if ((new_zone_be_name = be_auto_zone_be_name(zone_container_ds,
1933 zone_be_name)) == NULL) {
1934 be_print_err(gettext("be_copy_zones: failed "
1935 "to generate auto name for zone BE.\n"));
1936 ret = BE_ERR_AUTONAME;
1937 goto done;
1938 }
1939
1940 if ((snap_name = be_auto_snap_name()) == NULL) {
1941 be_print_err(gettext("be_copy_zones: failed to "
1942 "generate snapshot name for zone BE.\n"));
1943 ret = BE_ERR_AUTONAME;
1944 goto done;
1945 }
1946
1947 (void) snprintf(ss, sizeof (ss), "%s@%s", zoneroot_ds,
1948 snap_name);
1949
1950 if (zfs_snapshot(g_zfs, ss, B_TRUE, NULL) != 0) {
1951 be_print_err(gettext("be_copy_zones: "
1952 "failed to snapshot zone BE (%s): %s\n"),
1953 ss, libzfs_error_description(g_zfs));
1954 if (libzfs_errno(g_zfs) == EZFS_EXISTS)
1955 ret = BE_ERR_ZONE_SS_EXISTS;
1956 else
1957 ret = zfs_err_to_be_err(g_zfs);
1958
1959 goto done;
1960 }
1961
1962 (void) snprintf(new_zoneroot_ds, sizeof (new_zoneroot_ds),
1963 "%s/%s", zone_container_ds, new_zone_be_name);
1964
1965 bt.obe_name = zone_be_name;
1966 bt.obe_root_ds = zoneroot_ds;
1967 bt.obe_snap_name = snap_name;
1968 bt.obe_altroot = temp_mntpt;
1969 bt.nbe_name = new_zone_be_name;
1970 bt.nbe_root_ds = new_zoneroot_ds;
1971
1972 if (nvlist_alloc(&bt.nbe_zfs_props, NV_UNIQUE_NAME, 0) != 0) {
1973 be_print_err(gettext("be_copy_zones: "
1974 "internal error: out of memory\n"));
1975 ret = BE_ERR_NOMEM;
1976 goto done;
1977 }
1978
1979 /*
1980 * The call to be_clone_fs_callback always closes the
1981 * zfs_handle so there's no need to close z_zhp.
1982 */
1983 if ((iret = be_clone_fs_callback(z_zhp, &bt)) != 0) {
1984 z_zhp = NULL;
1985 if (iret != BE_ERR_BE_EXISTS) {
1986 be_print_err(gettext("be_copy_zones: "
1987 "failed to create zone BE clone for new "
1988 "zone BE %s\n"), new_zone_be_name);
1989 ret = iret;
1990 if (bt.nbe_zfs_props != NULL)
1991 nvlist_free(bt.nbe_zfs_props);
1992 goto done;
1993 }
1994 /*
1995 * We failed to create the new zone BE because a zone
1996 * BE with the auto-name we generated above has since
1997 * come into existence. Regenerate a new auto-name
1998 * and retry.
1999 */
2000 for (num_retries = 1;
2001 num_retries < BE_AUTO_NAME_MAX_TRY;
2002 num_retries++) {
2003
2004 /* Sleep 1 before retrying */
2005 (void) sleep(1);
2006
2007 /* Generate new auto zone BE name */
2008 free(new_zone_be_name);
2009 if ((new_zone_be_name = be_auto_zone_be_name(
2010 zone_container_ds,
2011 zone_be_name)) == NULL) {
2012 be_print_err(gettext("be_copy_zones: "
2013 "failed to generate auto name "
2014 "for zone BE.\n"));
2015 ret = BE_ERR_AUTONAME;
2016 if (bt.nbe_zfs_props != NULL)
2017 nvlist_free(bt.nbe_zfs_props);
2018 goto done;
2019 }
2020
2021 (void) snprintf(new_zoneroot_ds,
2022 sizeof (new_zoneroot_ds),
2023 "%s/%s", zone_container_ds,
2024 new_zone_be_name);
2025 bt.nbe_name = new_zone_be_name;
2026 bt.nbe_root_ds = new_zoneroot_ds;
2027
2028 /*
2029 * Get handle to original zone BE's root
2030 * dataset.
2031 */
2032 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
2033 ZFS_TYPE_FILESYSTEM)) == NULL) {
2034 be_print_err(gettext("be_copy_zones: "
2035 "failed to open zone root "
2036 "dataset (%s): %s\n"),
2037 zoneroot_ds,
2038 libzfs_error_description(g_zfs));
2039 ret = zfs_err_to_be_err(g_zfs);
2040 if (bt.nbe_zfs_props != NULL)
2041 nvlist_free(bt.nbe_zfs_props);
2042 goto done;
2043 }
2044
2045 /*
2046 * Try to clone the zone BE again. This
2047 * call will end up closing the zfs
2048 * handle passed in whether it
2049 * succeeds or fails.
2050 */
2051 iret = be_clone_fs_callback(z_zhp, &bt);
2052 z_zhp = NULL;
2053 if (iret == 0) {
2054 break;
2055 } else if (iret != BE_ERR_BE_EXISTS) {
2056 be_print_err(gettext("be_copy_zones: "
2057 "failed to create zone BE clone "
2058 "for new zone BE %s\n"),
2059 new_zone_be_name);
2060 ret = iret;
2061 if (bt.nbe_zfs_props != NULL)
2062 nvlist_free(bt.nbe_zfs_props);
2063 goto done;
2064 }
2065 }
2066 /*
2067 * If we've exhausted the maximum number of
2068 * tries, free the auto zone BE name and return
2069 * error.
2070 */
2071 if (num_retries == BE_AUTO_NAME_MAX_TRY) {
2072 be_print_err(gettext("be_copy_zones: failed "
2073 "to create a unique auto zone BE name\n"));
2074 free(bt.nbe_name);
2075 bt.nbe_name = NULL;
2076 ret = BE_ERR_AUTONAME;
2077 if (bt.nbe_zfs_props != NULL)
2078 nvlist_free(bt.nbe_zfs_props);
2079 goto done;
2080 }
2081 }
2082
2083 if (bt.nbe_zfs_props != NULL)
2084 nvlist_free(bt.nbe_zfs_props);
2085
2086 z_zhp = NULL;
2087
2088 if ((z_zhp = zfs_open(g_zfs, new_zoneroot_ds,
2089 ZFS_TYPE_FILESYSTEM)) == NULL) {
2090 be_print_err(gettext("be_copy_zones: "
2091 "failed to open the new zone BE root dataset "
2092 "(%s): %s\n"), new_zoneroot_ds,
2093 libzfs_error_description(g_zfs));
2094 ret = zfs_err_to_be_err(g_zfs);
2095 goto done;
2096 }
2097
2098 if (zfs_prop_set(z_zhp, BE_ZONE_PARENTBE_PROPERTY,
2099 uu_string) != 0) {
2100 be_print_err(gettext("be_copy_zones: "
2101 "failed to set parentbe property\n"));
2102 ZFS_CLOSE(z_zhp);
2103 ret = zfs_err_to_be_err(g_zfs);
2104 goto done;
2105 }
2106
2107 if (zfs_prop_set(z_zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
2108 be_print_err(gettext("be_copy_zones: "
2109 "failed to set active property\n"));
2110 ZFS_CLOSE(z_zhp);
2111 ret = zfs_err_to_be_err(g_zfs);
2112 goto done;
2113 }
2114
2115 /*
2116 * Generate a list of file systems from the original
2117 * zone BE that are legacy mounted. We use this list
2118 * to determine which entries in the vfstab we need to
2119 * update for the new zone BE we've just created.
2120 */
2121 if ((ret = be_get_legacy_fs(obe_name, obe_root_ds,
2122 zoneroot_ds, zoneroot, &fld)) != BE_SUCCESS) {
2123 be_print_err(gettext("be_copy_zones: "
2124 "failed to get legacy mounted file system "
2125 "list for zone %s\n"), zonename);
2126 ZFS_CLOSE(z_zhp);
2127 goto done;
2128 }
2129
2130 /*
2131 * Update new zone BE's vfstab.
2132 */
2133 if ((ret = be_update_zone_vfstab(z_zhp, bt.nbe_name,
2134 zonepath_ds, zonepath_ds, &fld)) != BE_SUCCESS) {
2135 be_print_err(gettext("be_copy_zones: "
2136 "failed to update new BE's vfstab (%s)\n"),
2137 bt.nbe_name);
2138 ZFS_CLOSE(z_zhp);
2139 be_free_fs_list(&fld);
2140 goto done;
2141 }
2142
2143 be_free_fs_list(&fld);
2144 ZFS_CLOSE(z_zhp);
2145 }
2146
2147 done:
2148 free(snap_name);
2149 if (brands != NULL)
2150 z_free_brand_list(brands);
2151 if (zlist != NULL)
2152 z_free_zone_list(zlist);
2153
2154 if (mounted_here)
2155 (void) _be_unmount(obe_name, 0);
2156
2157 ZFS_CLOSE(obe_zhp);
2158 return (ret);
2159 }
2160
2161 /*
2162 * Function: be_clone_fs_callback
2163 * Description: Callback function used to iterate through a BE's filesystems
2164 * to clone them for the new BE.
2165 * Parameters:
2166 * zhp - zfs_handle_t pointer for the filesystem being processed.
2167 * data - be_transaction_data_t pointer providing information
2168 * about original BE and new BE.
2169 * Return:
2170 * 0 - Success
2171 * be_errno_t - Failure
2172 * Scope:
2173 * Private
2174 */
2175 static int
2176 be_clone_fs_callback(zfs_handle_t *zhp, void *data)
2177 {
2178 be_transaction_data_t *bt = data;
2179 zfs_handle_t *zhp_ss = NULL;
2180 char prop_buf[MAXPATHLEN];
2181 char zhp_name[ZFS_MAXNAMELEN];
2182 char clone_ds[MAXPATHLEN];
2183 char ss[MAXPATHLEN];
2184 int ret = 0;
2185
2186 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
2187 ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) != 0) {
2188 be_print_err(gettext("be_clone_fs_callback: "
2189 "failed to get dataset mountpoint (%s): %s\n"),
2190 zfs_get_name(zhp), libzfs_error_description(g_zfs));
2191 ret = zfs_err_to_be_err(g_zfs);
2192 ZFS_CLOSE(zhp);
2193 return (ret);
2194 }
2195
2196 if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED) != 0 &&
2197 strcmp(prop_buf, "legacy") != 0) {
2198 /*
2199 * Since zfs can't currently handle setting the
2200 * mountpoint for a zoned dataset we'll have to skip
2201 * this dataset. This is because the mountpoint is not
2202 * set to "legacy".
2203 */
2204 goto zoned;
2205 }
2206 /*
2207 * Get a copy of the dataset name from the zfs handle
2208 */
2209 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2210
2211 /*
2212 * Get the clone dataset name and prepare the zfs properties for it.
2213 */
2214 if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2215 sizeof (clone_ds))) != BE_SUCCESS) {
2216 ZFS_CLOSE(zhp);
2217 return (ret);
2218 }
2219
2220 /*
2221 * Generate the name of the snapshot to use.
2222 */
2223 (void) snprintf(ss, sizeof (ss), "%s@%s", zhp_name,
2224 bt->obe_snap_name);
2225
2226 /*
2227 * Get handle to snapshot.
2228 */
2229 if ((zhp_ss = zfs_open(g_zfs, ss, ZFS_TYPE_SNAPSHOT)) == NULL) {
2230 be_print_err(gettext("be_clone_fs_callback: "
2231 "failed to get handle to snapshot (%s): %s\n"), ss,
2232 libzfs_error_description(g_zfs));
2233 ret = zfs_err_to_be_err(g_zfs);
2234 ZFS_CLOSE(zhp);
2235 return (ret);
2236 }
2237
2238 /*
2239 * Clone the dataset.
2240 */
2241 if (zfs_clone(zhp_ss, clone_ds, bt->nbe_zfs_props) != 0) {
2242 be_print_err(gettext("be_clone_fs_callback: "
2243 "failed to create clone dataset (%s): %s\n"),
2244 clone_ds, libzfs_error_description(g_zfs));
2245
2246 ZFS_CLOSE(zhp_ss);
2247 ZFS_CLOSE(zhp);
2248
2249 return (zfs_err_to_be_err(g_zfs));
2250 }
2251
2252 ZFS_CLOSE(zhp_ss);
2253
2254 zoned:
2255 /*
2256 * Iterate through zhp's children datasets (if any)
2257 * and clone them accordingly.
2258 */
2259 if ((ret = zfs_iter_filesystems(zhp, be_clone_fs_callback, bt)) != 0) {
2260 /*
2261 * Error occurred while processing a child dataset.
2262 * Destroy this dataset and return error.
2263 */
2264 zfs_handle_t *d_zhp = NULL;
2265
2266 ZFS_CLOSE(zhp);
2267
2268 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2269 == NULL) {
2270 return (ret);
2271 }
2272
2273 (void) zfs_destroy(d_zhp, B_FALSE);
2274 ZFS_CLOSE(d_zhp);
2275 return (ret);
2276 }
2277
2278 ZFS_CLOSE(zhp);
2279 return (0);
2280 }
2281
2282 /*
2283 * Function: be_send_fs_callback
2284 * Description: Callback function used to iterate through a BE's filesystems
2285 * to copy them for the new BE.
2286 * Parameters:
2287 * zhp - zfs_handle_t pointer for the filesystem being processed.
2288 * data - be_transaction_data_t pointer providing information
2289 * about original BE and new BE.
2290 * Return:
2291 * 0 - Success
2292 * be_errnot_t - Failure
2293 * Scope:
2294 * Private
2295 */
2296 static int
2297 be_send_fs_callback(zfs_handle_t *zhp, void *data)
2298 {
2299 be_transaction_data_t *bt = data;
2300 recvflags_t flags = { 0 };
2301 char zhp_name[ZFS_MAXNAMELEN];
2302 char clone_ds[MAXPATHLEN];
2303 sendflags_t send_flags = { 0 };
2304 int pid, status, retval;
2305 int srpipe[2];
2306 int ret = 0;
2307
2308 /*
2309 * Get a copy of the dataset name from the zfs handle
2310 */
2311 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2312
2313 /*
2314 * Get the clone dataset name and prepare the zfs properties for it.
2315 */
2316 if ((ret = be_prep_clone_send_fs(zhp, bt, clone_ds,
2317 sizeof (clone_ds))) != BE_SUCCESS) {
2318 ZFS_CLOSE(zhp);
2319 return (ret);
2320 }
2321
2322 /*
2323 * Create the new dataset.
2324 */
2325 if (zfs_create(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM, bt->nbe_zfs_props)
2326 != 0) {
2327 be_print_err(gettext("be_send_fs_callback: "
2328 "failed to create new dataset '%s': %s\n"),
2329 clone_ds, libzfs_error_description(g_zfs));
2330 ret = zfs_err_to_be_err(g_zfs);
2331 ZFS_CLOSE(zhp);
2332 return (ret);
2333 }
2334
2335 /*
2336 * Destination file system is already created
2337 * hence we need to set the force flag on
2338 */
2339 flags.force = B_TRUE;
2340
2341 /*
2342 * Initiate the pipe to be used for the send and recv
2343 */
2344 if (pipe(srpipe) != 0) {
2345 int err = errno;
2346 be_print_err(gettext("be_send_fs_callback: failed to "
2347 "open pipe\n"));
2348 ZFS_CLOSE(zhp);
2349 return (errno_to_be_err(err));
2350 }
2351
2352 /*
2353 * Fork off a child to send the dataset
2354 */
2355 if ((pid = fork()) == -1) {
2356 int err = errno;
2357 be_print_err(gettext("be_send_fs_callback: failed to fork\n"));
2358 (void) close(srpipe[0]);
2359 (void) close(srpipe[1]);
2360 ZFS_CLOSE(zhp);
2361 return (errno_to_be_err(err));
2362 } else if (pid == 0) { /* child process */
2363 (void) close(srpipe[0]);
2364
2365 /* Send dataset */
2366 if (zfs_send(zhp, NULL, bt->obe_snap_name, send_flags,
2367 srpipe[1], NULL, NULL, NULL) != 0) {
2368 _exit(1);
2369 }
2370 ZFS_CLOSE(zhp);
2371
2372 _exit(0);
2373 }
2374
2375 (void) close(srpipe[1]);
2376
2377 /* Receive dataset */
2378 if (zfs_receive(g_zfs, clone_ds, flags, srpipe[0], NULL) != 0) {
2379 be_print_err(gettext("be_send_fs_callback: failed to "
2380 "recv dataset (%s)\n"), clone_ds);
2381 }
2382 (void) close(srpipe[0]);
2383
2384 /* wait for child to exit */
2385 do {
2386 retval = waitpid(pid, &status, 0);
2387 if (retval == -1) {
2388 status = 0;
2389 }
2390 } while (retval != pid);
2391
2392 if (WEXITSTATUS(status) != 0) {
2393 be_print_err(gettext("be_send_fs_callback: failed to "
2394 "send dataset (%s)\n"), zhp_name);
2395 ZFS_CLOSE(zhp);
2396 return (BE_ERR_ZFS);
2397 }
2398
2399
2400 /*
2401 * Iterate through zhp's children datasets (if any)
2402 * and send them accordingly.
2403 */
2404 if ((ret = zfs_iter_filesystems(zhp, be_send_fs_callback, bt)) != 0) {
2405 /*
2406 * Error occurred while processing a child dataset.
2407 * Destroy this dataset and return error.
2408 */
2409 zfs_handle_t *d_zhp = NULL;
2410
2411 ZFS_CLOSE(zhp);
2412
2413 if ((d_zhp = zfs_open(g_zfs, clone_ds, ZFS_TYPE_FILESYSTEM))
2414 == NULL) {
2415 return (ret);
2416 }
2417
2418 (void) zfs_destroy(d_zhp, B_FALSE);
2419 ZFS_CLOSE(d_zhp);
2420 return (ret);
2421 }
2422
2423 ZFS_CLOSE(zhp);
2424 return (0);
2425 }
2426
2427 /*
2428 * Function: be_destroy_callback
2429 * Description: Callback function used to destroy a BEs children datasets
2430 * and snapshots.
2431 * Parameters:
2432 * zhp - zfs_handle_t pointer to the filesystem being processed.
2433 * data - Not used.
2434 * Returns:
2435 * 0 - Success
2436 * be_errno_t - Failure
2437 * Scope:
2438 * Private
2439 */
2440 static int
2441 be_destroy_callback(zfs_handle_t *zhp, void *data)
2442 {
2443 be_destroy_data_t *dd = data;
2444 int ret = 0;
2445
2446 /*
2447 * Iterate down this file system's hierarchical children
2448 * and destroy them first.
2449 */
2450 if ((ret = zfs_iter_filesystems(zhp, be_destroy_callback, dd)) != 0) {
2451 ZFS_CLOSE(zhp);
2452 return (ret);
2453 }
2454
2455 if (dd->destroy_snaps) {
2456 /*
2457 * Iterate through this file system's snapshots and
2458 * destroy them before destroying the file system itself.
2459 */
2460 if ((ret = zfs_iter_snapshots(zhp, be_destroy_callback, dd))
2461 != 0) {
2462 ZFS_CLOSE(zhp);
2463 return (ret);
2464 }
2465 }
2466
2467 /* Attempt to unmount the dataset before destroying it */
2468 if (dd->force_unmount) {
2469 if ((ret = zfs_unmount(zhp, NULL, MS_FORCE)) != 0) {
2470 be_print_err(gettext("be_destroy_callback: "
2471 "failed to unmount %s: %s\n"), zfs_get_name(zhp),
2472 libzfs_error_description(g_zfs));
2473 ret = zfs_err_to_be_err(g_zfs);
2474 ZFS_CLOSE(zhp);
2475 return (ret);
2476 }
2477 }
2478
2479 if (zfs_destroy(zhp, B_FALSE) != 0) {
2480 be_print_err(gettext("be_destroy_callback: "
2481 "failed to destroy %s: %s\n"), zfs_get_name(zhp),
2482 libzfs_error_description(g_zfs));
2483 ret = zfs_err_to_be_err(g_zfs);
2484 ZFS_CLOSE(zhp);
2485 return (ret);
2486 }
2487
2488 ZFS_CLOSE(zhp);
2489 return (0);
2490 }
2491
2492 /*
2493 * Function: be_demote_callback
2494 * Description: This callback function is used to iterate through the file
2495 * systems of a BE, looking for the right clone to promote such
2496 * that this file system is left without any dependent clones.
2497 * If the file system has no dependent clones, it doesn't need
2498 * to get demoted, and the function will return success.
2499 *
2500 * The demotion will be done in two passes. The first pass
2501 * will attempt to find the youngest snapshot that has a clone
2502 * that is part of some other BE. The second pass will attempt
2503 * to find the youngest snapshot that has a clone that is not
2504 * part of a BE. Doing this helps ensure the aggregated set of
2505 * file systems that compose a BE stay coordinated wrt BE
2506 * snapshots and BE dependents. It also prevents a random user
2507 * generated clone of a BE dataset to become the parent of other
2508 * BE datasets after demoting this dataset.
2509 *
2510 * Parameters:
2511 * zhp - zfs_handle_t pointer to the current file system being
2512 * processed.
2513 * data - not used.
2514 * Return:
2515 * 0 - Success
2516 * be_errno_t - Failure
2517 * Scope:
2518 * Private
2519 */
2520 static int
2521 /* LINTED */
2522 be_demote_callback(zfs_handle_t *zhp, void *data)
2523 {
2524 be_demote_data_t dd = { 0 };
2525 int i, ret = 0;
2526
2527 /*
2528 * Initialize be_demote_data for the first pass - this will find a
2529 * clone in another BE, if one exists.
2530 */
2531 dd.find_in_BE = B_TRUE;
2532
2533 for (i = 0; i < 2; i++) {
2534
2535 if (zfs_iter_snapshots(zhp, be_demote_find_clone_callback, &dd)
2536 != 0) {
2537 be_print_err(gettext("be_demote_callback: "
2538 "failed to iterate snapshots for %s: %s\n"),
2539 zfs_get_name(zhp), libzfs_error_description(g_zfs));
2540 ret = zfs_err_to_be_err(g_zfs);
2541 ZFS_CLOSE(zhp);
2542 return (ret);
2543 }
2544 if (dd.clone_zhp != NULL) {
2545 /* Found the clone to promote. Promote it. */
2546 if (zfs_promote(dd.clone_zhp) != 0) {
2547 be_print_err(gettext("be_demote_callback: "
2548 "failed to promote %s: %s\n"),
2549 zfs_get_name(dd.clone_zhp),
2550 libzfs_error_description(g_zfs));
2551 ret = zfs_err_to_be_err(g_zfs);
2552 ZFS_CLOSE(dd.clone_zhp);
2553 ZFS_CLOSE(zhp);
2554 return (ret);
2555 }
2556
2557 ZFS_CLOSE(dd.clone_zhp);
2558 }
2559
2560 /*
2561 * Reinitialize be_demote_data for the second pass.
2562 * This will find a user created clone outside of any BE
2563 * namespace, if one exists.
2564 */
2565 dd.clone_zhp = NULL;
2566 dd.origin_creation = 0;
2567 dd.snapshot = NULL;
2568 dd.find_in_BE = B_FALSE;
2569 }
2570
2571 /* Iterate down this file system's children and demote them */
2572 if ((ret = zfs_iter_filesystems(zhp, be_demote_callback, NULL)) != 0) {
2573 ZFS_CLOSE(zhp);
2574 return (ret);
2575 }
2576
2577 ZFS_CLOSE(zhp);
2578 return (0);
2579 }
2580
2581 /*
2582 * Function: be_demote_find_clone_callback
2583 * Description: This callback function is used to iterate through the
2584 * snapshots of a dataset, looking for the youngest snapshot
2585 * that has a clone. If found, it returns a reference to the
2586 * clone back to the caller in the callback data.
2587 * Parameters:
2588 * zhp - zfs_handle_t pointer to current snapshot being looked at
2589 * data - be_demote_data_t pointer used to store the clone that
2590 * is found.
2591 * Returns:
2592 * 0 - Successfully iterated through all snapshots.
2593 * 1 - Failed to iterate through all snapshots.
2594 * Scope:
2595 * Private
2596 */
2597 static int
2598 be_demote_find_clone_callback(zfs_handle_t *zhp, void *data)
2599 {
2600 be_demote_data_t *dd = data;
2601 time_t snap_creation;
2602 int zret = 0;
2603
2604 /* If snapshot has no clones, no need to look at it */
2605 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
2606 ZFS_CLOSE(zhp);
2607 return (0);
2608 }
2609
2610 dd->snapshot = zfs_get_name(zhp);
2611
2612 /* Get the creation time of this snapshot */
2613 snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
2614
2615 /*
2616 * If this snapshot's creation time is greater than (or younger than)
2617 * the current youngest snapshot found, iterate this snapshot to
2618 * check if it has a clone that we're looking for.
2619 */
2620 if (snap_creation >= dd->origin_creation) {
2621 /*
2622 * Iterate the dependents of this snapshot to find a
2623 * a clone that's a direct dependent.
2624 */
2625 if ((zret = zfs_iter_dependents(zhp, B_FALSE,
2626 be_demote_get_one_clone, dd)) == -1) {
2627 be_print_err(gettext("be_demote_find_clone_callback: "
2628 "failed to iterate dependents of %s\n"),
2629 zfs_get_name(zhp));
2630 ZFS_CLOSE(zhp);
2631 return (1);
2632 } else if (zret == 1) {
2633 /*
2634 * Found a clone, update the origin_creation time
2635 * in the callback data.
2636 */
2637 dd->origin_creation = snap_creation;
2638 }
2639 }
2640
2641 ZFS_CLOSE(zhp);
2642 return (0);
2643 }
2644
2645 /*
2646 * Function: be_demote_get_one_clone
2647 * Description: This callback function is used to iterate through a
2648 * snapshot's dependencies to find a filesystem that is a
2649 * direct clone of the snapshot being iterated.
2650 * Parameters:
2651 * zhp - zfs_handle_t pointer to current dataset being looked at
2652 * data - be_demote_data_t pointer used to store the clone
2653 * that is found, and also provides flag to note
2654 * whether or not the clone filesystem being searched
2655 * for needs to be found in a BE dataset hierarchy.
2656 * Return:
2657 * 1 - Success, found clone and its also a BE's root dataset.
2658 * 0 - Failure, clone not found.
2659 * Scope:
2660 * Private
2661 */
2662 static int
2663 be_demote_get_one_clone(zfs_handle_t *zhp, void *data)
2664 {
2665 be_demote_data_t *dd = data;
2666 char origin[ZFS_MAXNAMELEN];
2667 char ds_path[ZFS_MAXNAMELEN];
2668
2669 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
2670 ZFS_CLOSE(zhp);
2671 return (0);
2672 }
2673
2674 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
2675
2676 /*
2677 * Make sure this is a direct clone of the snapshot
2678 * we're iterating.
2679 */
2680 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
2681 NULL, 0, B_FALSE) != 0) {
2682 be_print_err(gettext("be_demote_get_one_clone: "
2683 "failed to get origin of %s: %s\n"), ds_path,
2684 libzfs_error_description(g_zfs));
2685 ZFS_CLOSE(zhp);
2686 return (0);
2687 }
2688 if (strcmp(origin, dd->snapshot) != 0) {
2689 ZFS_CLOSE(zhp);
2690 return (0);
2691 }
2692
2693 if (dd->find_in_BE) {
2694 if ((zpool_iter(g_zfs, be_check_be_roots_callback, ds_path))
2695 > 0) {
2696 if (dd->clone_zhp != NULL)
2697 ZFS_CLOSE(dd->clone_zhp);
2698 dd->clone_zhp = zhp;
2699 return (1);
2700 }
2701
2702 ZFS_CLOSE(zhp);
2703 return (0);
2704 }
2705
2706 if (dd->clone_zhp != NULL)
2707 ZFS_CLOSE(dd->clone_zhp);
2708
2709 dd->clone_zhp = zhp;
2710 return (1);
2711 }
2712
2713 /*
2714 * Function: be_get_snap
2715 * Description: This function takes a snapshot dataset name and separates
2716 * out the parent dataset portion from the snapshot name.
2717 * I.e. it finds the '@' in the snapshot dataset name and
2718 * replaces it with a '\0'.
2719 * Parameters:
2720 * origin - char pointer to a snapshot dataset name. Its
2721 * contents will be modified by this function.
2722 * *snap - pointer to a char pointer. Will be set to the
2723 * snapshot name portion upon success.
2724 * Return:
2725 * BE_SUCCESS - Success
2726 * 1 - Failure
2727 * Scope:
2728 * Private
2729 */
2730 static int
2731 be_get_snap(char *origin, char **snap)
2732 {
2733 char *cp;
2734
2735 /*
2736 * Separate out the origin's dataset and snapshot portions by
2737 * replacing the @ with a '\0'
2738 */
2739 cp = strrchr(origin, '@');
2740 if (cp != NULL) {
2741 if (cp[1] != NULL && cp[1] != '\0') {
2742 cp[0] = '\0';
2743 *snap = cp+1;
2744 } else {
2745 return (1);
2746 }
2747 } else {
2748 return (1);
2749 }
2750
2751 return (BE_SUCCESS);
2752 }
2753
2754 /*
2755 * Function: be_create_container_ds
2756 * Description: This function checks that the zpool passed has the BE
2757 * container dataset, and if not, then creates it.
2758 * Parameters:
2759 * zpool - name of pool to create BE container dataset in.
2760 * Return:
2761 * B_TRUE - Successfully created BE container dataset, or it
2762 * already existed.
2763 * B_FALSE - Failed to create container dataset.
2764 * Scope:
2765 * Private
2766 */
2767 static boolean_t
2768 be_create_container_ds(char *zpool)
2769 {
2770 nvlist_t *props = NULL;
2771 char be_container_ds[MAXPATHLEN];
2772
2773 /* Generate string for BE container dataset for this pool */
2774 be_make_container_ds(zpool, be_container_ds,
2775 sizeof (be_container_ds));
2776
2777 if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2778
2779 if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) {
2780 be_print_err(gettext("be_create_container_ds: "
2781 "nvlist_alloc failed\n"));
2782 return (B_FALSE);
2783 }
2784
2785 if (nvlist_add_string(props,
2786 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2787 ZFS_MOUNTPOINT_LEGACY) != 0) {
2788 be_print_err(gettext("be_create_container_ds: "
2789 "internal error: out of memory\n"));
2790 nvlist_free(props);
2791 return (B_FALSE);
2792 }
2793
2794 if (nvlist_add_string(props,
2795 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "off") != 0) {
2796 be_print_err(gettext("be_create_container_ds: "
2797 "internal error: out of memory\n"));
2798 nvlist_free(props);
2799 return (B_FALSE);
2800 }
2801
2802 if (zfs_create(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM,
2803 props) != 0) {
2804 be_print_err(gettext("be_create_container_ds: "
2805 "failed to create container dataset (%s): %s\n"),
2806 be_container_ds, libzfs_error_description(g_zfs));
2807 nvlist_free(props);
2808 return (B_FALSE);
2809 }
2810
2811 nvlist_free(props);
2812 }
2813
2814 return (B_TRUE);
2815 }
2816
2817 /*
2818 * Function: be_prep_clone_send_fs
2819 * Description: This function takes a zfs handle to a dataset from the
2820 * original BE, and generates the name of the clone dataset
2821 * to create for the new BE. It also prepares the zfs
2822 * properties to be used for the new BE.
2823 * Parameters:
2824 * zhp - pointer to zfs_handle_t of the file system being
2825 * cloned/copied.
2826 * bt - be_transaction_data pointer providing information
2827 * about the original BE and new BE.
2828 * clone_ds - buffer to store the name of the dataset
2829 * for the new BE.
2830 * clone_ds_len - length of clone_ds buffer
2831 * Return:
2832 * BE_SUCCESS - Success
2833 * be_errno_t - Failure
2834 * Scope:
2835 * Private
2836 */
2837 static int
2838 be_prep_clone_send_fs(zfs_handle_t *zhp, be_transaction_data_t *bt,
2839 char *clone_ds, int clone_ds_len)
2840 {
2841 zprop_source_t sourcetype;
2842 char source[ZFS_MAXNAMELEN];
2843 char zhp_name[ZFS_MAXNAMELEN];
2844 char mountpoint[MAXPATHLEN];
2845 char *child_fs = NULL;
2846 char *zhp_mountpoint = NULL;
2847 int err = 0;
2848
2849 /*
2850 * Get a copy of the dataset name zfs_name from zhp
2851 */
2852 (void) strlcpy(zhp_name, zfs_get_name(zhp), sizeof (zhp_name));
2853
2854 /*
2855 * Get file system name relative to the root.
2856 */
2857 if (strncmp(zhp_name, bt->obe_root_ds, strlen(bt->obe_root_ds))
2858 == 0) {
2859 child_fs = zhp_name + strlen(bt->obe_root_ds);
2860
2861 /*
2862 * if child_fs is NULL, this means we're processing the
2863 * root dataset itself; set child_fs to the empty string.
2864 */
2865 if (child_fs == NULL)
2866 child_fs = "";
2867 } else {
2868 return (BE_ERR_INVAL);
2869 }
2870
2871 /*
2872 * Generate the name of the clone file system.
2873 */
2874 (void) snprintf(clone_ds, clone_ds_len, "%s%s", bt->nbe_root_ds,
2875 child_fs);
2876
2877 /* Get the mountpoint and source properties of the existing dataset */
2878 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
2879 sizeof (mountpoint), &sourcetype, source, sizeof (source),
2880 B_FALSE) != 0) {
2881 be_print_err(gettext("be_prep_clone_send_fs: "
2882 "failed to get mountpoint for (%s): %s\n"),
2883 zhp_name, libzfs_error_description(g_zfs));
2884 return (zfs_err_to_be_err(g_zfs));
2885 }
2886
2887 /*
2888 * Workaround for 6668667 where a mountpoint property of "/" comes
2889 * back as "".
2890 */
2891 if (strcmp(mountpoint, "") == 0) {
2892 (void) snprintf(mountpoint, sizeof (mountpoint), "/");
2893 }
2894
2895 /*
2896 * Figure out what to set as the mountpoint for the new dataset.
2897 * If the source of the mountpoint property is local, use the
2898 * mountpoint value itself. Otherwise, remove it from the
2899 * zfs properties list so that it gets inherited.
2900 */
2901 if (sourcetype & ZPROP_SRC_LOCAL) {
2902 /*
2903 * If the BE that this file system is a part of is
2904 * currently mounted, strip off the BE altroot portion
2905 * from the mountpoint.
2906 */
2907 zhp_mountpoint = mountpoint;
2908
2909 if (strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) != 0 &&
2910 bt->obe_altroot != NULL && strcmp(bt->obe_altroot,
2911 "/") != 0 && zfs_is_mounted(zhp, NULL)) {
2912
2913 int altroot_len = strlen(bt->obe_altroot);
2914
2915 if (strncmp(bt->obe_altroot, mountpoint, altroot_len)
2916 == 0) {
2917 if (mountpoint[altroot_len] == '/')
2918 zhp_mountpoint = mountpoint +
2919 altroot_len;
2920 else if (mountpoint[altroot_len] == '\0')
2921 (void) snprintf(mountpoint,
2922 sizeof (mountpoint), "/");
2923 }
2924 }
2925
2926 if (nvlist_add_string(bt->nbe_zfs_props,
2927 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
2928 zhp_mountpoint) != 0) {
2929 be_print_err(gettext("be_prep_clone_send_fs: "
2930 "internal error: out of memory\n"));
2931 return (BE_ERR_NOMEM);
2932 }
2933 } else {
2934 err = nvlist_remove_all(bt->nbe_zfs_props,
2935 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT));
2936 if (err != 0 && err != ENOENT) {
2937 be_print_err(gettext("be_prep_clone_send_fs: "
2938 "failed to remove mountpoint from "
2939 "nvlist\n"));
2940 return (BE_ERR_INVAL);
2941 }
2942 }
2943
2944 /*
2945 * Set the 'canmount' property
2946 */
2947 if (nvlist_add_string(bt->nbe_zfs_props,
2948 zfs_prop_to_name(ZFS_PROP_CANMOUNT), "noauto") != 0) {
2949 be_print_err(gettext("be_prep_clone_send_fs: "
2950 "internal error: out of memory\n"));
2951 return (BE_ERR_NOMEM);
2952 }
2953
2954 return (BE_SUCCESS);
2955 }
2956
2957 /*
2958 * Function: be_get_zone_be_name
2959 * Description: This function takes the zones root dataset, the container
2960 * dataset and returns the zones BE name based on the zone
2961 * root dataset.
2962 * Parameters:
2963 * root_ds - the zones root dataset.
2964 * container_ds - the container dataset for the zone.
2965 * Returns:
2966 * char * - the BE name of this zone based on the root dataset.
2967 */
2968 static char *
2969 be_get_zone_be_name(char *root_ds, char *container_ds)
2970 {
2971 return (root_ds + (strlen(container_ds) + 1));
2972 }
2973
2974 /*
2975 * Function: be_zone_root_exists_callback
2976 * Description: This callback function is used to determine if a
2977 * zone root container dataset has any children. It always
2978 * returns 1, signifying a hierarchical child of the zone
2979 * root container dataset has been traversed and therefore
2980 * it has children.
2981 * Parameters:
2982 * zhp - zfs_handle_t pointer to current dataset being processed.
2983 * data - not used.
2984 * Returns:
2985 * 1 - dataset exists
2986 * Scope:
2987 * Private
2988 */
2989 static int
2990 /* LINTED */
2991 be_zone_root_exists_callback(zfs_handle_t *zhp, void *data)
2992 {
2993 ZFS_CLOSE(zhp);
2994 return (1);
2995 }