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