1f169c0eaSGlenn Lagasse /*
2f169c0eaSGlenn Lagasse * CDDL HEADER START
3f169c0eaSGlenn Lagasse *
4f169c0eaSGlenn Lagasse * The contents of this file are subject to the terms of the
5f169c0eaSGlenn Lagasse * Common Development and Distribution License (the "License").
6f169c0eaSGlenn Lagasse * You may not use this file except in compliance with the License.
7f169c0eaSGlenn Lagasse *
8f169c0eaSGlenn Lagasse * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f169c0eaSGlenn Lagasse * or http://www.opensolaris.org/os/licensing.
10f169c0eaSGlenn Lagasse * See the License for the specific language governing permissions
11f169c0eaSGlenn Lagasse * and limitations under the License.
12f169c0eaSGlenn Lagasse *
13f169c0eaSGlenn Lagasse * When distributing Covered Code, include this CDDL HEADER in each
14f169c0eaSGlenn Lagasse * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f169c0eaSGlenn Lagasse * If applicable, add the following below this CDDL HEADER, with the
16f169c0eaSGlenn Lagasse * fields enclosed by brackets "[]" replaced with your own identifying
17f169c0eaSGlenn Lagasse * information: Portions Copyright [yyyy] [name of copyright owner]
18f169c0eaSGlenn Lagasse *
19f169c0eaSGlenn Lagasse * CDDL HEADER END
20f169c0eaSGlenn Lagasse */
21f169c0eaSGlenn Lagasse
22f169c0eaSGlenn Lagasse /*
23f169c0eaSGlenn Lagasse * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24f169c0eaSGlenn Lagasse */
25f169c0eaSGlenn Lagasse
26f169c0eaSGlenn Lagasse /*
27*7e0e2549SAlexander Eremin * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28*7e0e2549SAlexander Eremin */
29*7e0e2549SAlexander Eremin
30*7e0e2549SAlexander Eremin /*
31f169c0eaSGlenn Lagasse * System includes
32f169c0eaSGlenn Lagasse */
33f169c0eaSGlenn Lagasse #include <assert.h>
34f169c0eaSGlenn Lagasse #include <errno.h>
35f169c0eaSGlenn Lagasse #include <libintl.h>
36f169c0eaSGlenn Lagasse #include <libnvpair.h>
37f169c0eaSGlenn Lagasse #include <libzfs.h>
38f169c0eaSGlenn Lagasse #include <stdio.h>
39f169c0eaSGlenn Lagasse #include <stdlib.h>
40f169c0eaSGlenn Lagasse #include <string.h>
41f169c0eaSGlenn Lagasse #include <sys/mntent.h>
42f169c0eaSGlenn Lagasse #include <sys/mnttab.h>
43f169c0eaSGlenn Lagasse #include <sys/mount.h>
44f169c0eaSGlenn Lagasse #include <sys/stat.h>
45f169c0eaSGlenn Lagasse #include <sys/types.h>
46f169c0eaSGlenn Lagasse #include <sys/vfstab.h>
47f169c0eaSGlenn Lagasse #include <unistd.h>
48f169c0eaSGlenn Lagasse
49f169c0eaSGlenn Lagasse #include <libbe.h>
50f169c0eaSGlenn Lagasse #include <libbe_priv.h>
51f169c0eaSGlenn Lagasse
52f169c0eaSGlenn Lagasse typedef struct active_zone_root_data {
53f169c0eaSGlenn Lagasse uuid_t parent_uuid;
54f169c0eaSGlenn Lagasse char *zoneroot_ds;
55f169c0eaSGlenn Lagasse } active_zone_root_data_t;
56f169c0eaSGlenn Lagasse
57f169c0eaSGlenn Lagasse typedef struct mounted_zone_root_data {
58f169c0eaSGlenn Lagasse char *zone_altroot;
59f169c0eaSGlenn Lagasse char *zoneroot_ds;
60f169c0eaSGlenn Lagasse } mounted_zone_root_data_t;
61f169c0eaSGlenn Lagasse
62f169c0eaSGlenn Lagasse /* Private function prototypes */
63f169c0eaSGlenn Lagasse static int be_find_active_zone_root_callback(zfs_handle_t *, void *);
64f169c0eaSGlenn Lagasse static int be_find_mounted_zone_root_callback(zfs_handle_t *, void *);
65f169c0eaSGlenn Lagasse static boolean_t be_zone_get_active(zfs_handle_t *);
66f169c0eaSGlenn Lagasse
67f169c0eaSGlenn Lagasse
68f169c0eaSGlenn Lagasse /* ******************************************************************** */
69f169c0eaSGlenn Lagasse /* Semi-Private Functions */
70f169c0eaSGlenn Lagasse /* ******************************************************************** */
71f169c0eaSGlenn Lagasse
72f169c0eaSGlenn Lagasse /*
73f169c0eaSGlenn Lagasse * Function: be_make_zoneroot
74f169c0eaSGlenn Lagasse * Description: Generate a string for a zone's zoneroot given the
75f169c0eaSGlenn Lagasse * zone's zonepath.
76f169c0eaSGlenn Lagasse * Parameters:
77f169c0eaSGlenn Lagasse * zonepath - pointer to zonepath
78f169c0eaSGlenn Lagasse * zoneroot - pointer to buffer to retrn zoneroot in.
79f169c0eaSGlenn Lagasse * zoneroot_size - size of zoneroot
80f169c0eaSGlenn Lagasse * Returns:
81f169c0eaSGlenn Lagasse * None
82f169c0eaSGlenn Lagasse * Scope:
83f169c0eaSGlenn Lagasse * Semi-private (library wise use only)
84f169c0eaSGlenn Lagasse */
85f169c0eaSGlenn Lagasse void
be_make_zoneroot(char * zonepath,char * zoneroot,int zoneroot_size)86f169c0eaSGlenn Lagasse be_make_zoneroot(char *zonepath, char *zoneroot, int zoneroot_size)
87f169c0eaSGlenn Lagasse {
88f169c0eaSGlenn Lagasse (void) snprintf(zoneroot, zoneroot_size, "%s/root", zonepath);
89f169c0eaSGlenn Lagasse }
90f169c0eaSGlenn Lagasse
91f169c0eaSGlenn Lagasse /*
92f169c0eaSGlenn Lagasse * Function: be_find_active_zone_root
93f169c0eaSGlenn Lagasse * Description: This function will find the active zone root of a zone for
94f169c0eaSGlenn Lagasse * a given global BE. It will iterate all of the zone roots
95f169c0eaSGlenn Lagasse * under a zonepath, find the zone roots that belong to the
96f169c0eaSGlenn Lagasse * specified global BE, and return the one that is active.
97f169c0eaSGlenn Lagasse * Parameters:
98f169c0eaSGlenn Lagasse * be_zhp - zfs handle to global BE root dataset.
99f169c0eaSGlenn Lagasse * zonepath_ds - pointer to zone's zonepath dataset.
100f169c0eaSGlenn Lagasse * zoneroot_ds - pointer to a buffer to store the dataset name of
101f169c0eaSGlenn Lagasse * the zone's zoneroot that's currently active for this
102f169c0eaSGlenn Lagasse * given global BE..
103f169c0eaSGlenn Lagasse * zoneroot-ds_size - size of zoneroot_ds.
104f169c0eaSGlenn Lagasse * Returns:
105f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
106f169c0eaSGlenn Lagasse * be_errno_t - Failure
107f169c0eaSGlenn Lagasse * Scope:
108f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
109f169c0eaSGlenn Lagasse */
110f169c0eaSGlenn Lagasse int
be_find_active_zone_root(zfs_handle_t * be_zhp,char * zonepath_ds,char * zoneroot_ds,int zoneroot_ds_size)111f169c0eaSGlenn Lagasse be_find_active_zone_root(zfs_handle_t *be_zhp, char *zonepath_ds,
112f169c0eaSGlenn Lagasse char *zoneroot_ds, int zoneroot_ds_size)
113f169c0eaSGlenn Lagasse {
114f169c0eaSGlenn Lagasse active_zone_root_data_t azr_data = { 0 };
115f169c0eaSGlenn Lagasse zfs_handle_t *zhp;
116f169c0eaSGlenn Lagasse char zone_container_ds[MAXPATHLEN];
117f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
118f169c0eaSGlenn Lagasse
119f169c0eaSGlenn Lagasse /* Get the uuid of the parent global BE */
120*7e0e2549SAlexander Eremin if (getzoneid() == GLOBAL_ZONEID) {
121*7e0e2549SAlexander Eremin if ((ret = be_get_uuid(zfs_get_name(be_zhp),
122*7e0e2549SAlexander Eremin &azr_data.parent_uuid)) != BE_SUCCESS) {
123*7e0e2549SAlexander Eremin be_print_err(gettext("be_find_active_zone_root: failed "
124*7e0e2549SAlexander Eremin "to get uuid for BE root dataset %s\n"),
125*7e0e2549SAlexander Eremin zfs_get_name(be_zhp));
126f169c0eaSGlenn Lagasse return (ret);
127f169c0eaSGlenn Lagasse }
128*7e0e2549SAlexander Eremin } else {
129*7e0e2549SAlexander Eremin if ((ret = be_zone_get_parent_uuid(zfs_get_name(be_zhp),
130*7e0e2549SAlexander Eremin &azr_data.parent_uuid)) != BE_SUCCESS) {
131*7e0e2549SAlexander Eremin be_print_err(gettext("be_find_active_zone_root: failed "
132*7e0e2549SAlexander Eremin "to get parentbe uuid for zone root dataset %s\n"),
133*7e0e2549SAlexander Eremin zfs_get_name(be_zhp));
134*7e0e2549SAlexander Eremin return (ret);
135*7e0e2549SAlexander Eremin }
136*7e0e2549SAlexander Eremin }
137f169c0eaSGlenn Lagasse
138f169c0eaSGlenn Lagasse /* Generate string for the root container dataset for this zone. */
139f169c0eaSGlenn Lagasse be_make_container_ds(zonepath_ds, zone_container_ds,
140f169c0eaSGlenn Lagasse sizeof (zone_container_ds));
141f169c0eaSGlenn Lagasse
142f169c0eaSGlenn Lagasse /* Get handle to this zone's root container dataset */
143f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
144f169c0eaSGlenn Lagasse == NULL) {
145f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_active_zone_root: failed to "
146f169c0eaSGlenn Lagasse "open zone root container dataset (%s): %s\n"),
147f169c0eaSGlenn Lagasse zone_container_ds, libzfs_error_description(g_zfs));
148f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
149f169c0eaSGlenn Lagasse }
150f169c0eaSGlenn Lagasse
151f169c0eaSGlenn Lagasse /*
152f169c0eaSGlenn Lagasse * Iterate through all of this zone's BEs, looking for ones
153f169c0eaSGlenn Lagasse * that belong to the parent global BE, and finding the one
154f169c0eaSGlenn Lagasse * that is marked active.
155f169c0eaSGlenn Lagasse */
156f169c0eaSGlenn Lagasse if ((ret = zfs_iter_filesystems(zhp, be_find_active_zone_root_callback,
157f169c0eaSGlenn Lagasse &azr_data)) != 0) {
158f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_active_zone_root: failed to "
159f169c0eaSGlenn Lagasse "find active zone root in zonepath dataset %s: %s\n"),
160f169c0eaSGlenn Lagasse zonepath_ds, be_err_to_str(ret));
161f169c0eaSGlenn Lagasse goto done;
162f169c0eaSGlenn Lagasse }
163f169c0eaSGlenn Lagasse
164f169c0eaSGlenn Lagasse if (azr_data.zoneroot_ds != NULL) {
165f169c0eaSGlenn Lagasse (void) strlcpy(zoneroot_ds, azr_data.zoneroot_ds,
166f169c0eaSGlenn Lagasse zoneroot_ds_size);
167f169c0eaSGlenn Lagasse free(azr_data.zoneroot_ds);
168f169c0eaSGlenn Lagasse } else {
169f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_active_zone_root: failed to "
170f169c0eaSGlenn Lagasse "find active zone root in zonepath dataset %s\n"),
171f169c0eaSGlenn Lagasse zonepath_ds);
172f169c0eaSGlenn Lagasse ret = BE_ERR_ZONE_NO_ACTIVE_ROOT;
173f169c0eaSGlenn Lagasse }
174f169c0eaSGlenn Lagasse
175f169c0eaSGlenn Lagasse done:
176f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
177f169c0eaSGlenn Lagasse return (ret);
178f169c0eaSGlenn Lagasse }
179f169c0eaSGlenn Lagasse
180f169c0eaSGlenn Lagasse /*
181f169c0eaSGlenn Lagasse * Function: be_find_mounted_zone_root
182f169c0eaSGlenn Lagasse * Description: This function will find the dataset mounted as the zoneroot
183f169c0eaSGlenn Lagasse * of a zone for a given mounted global BE.
184f169c0eaSGlenn Lagasse * Parameters:
185f169c0eaSGlenn Lagasse * zone_altroot - path of zoneroot wrt the mounted global BE.
186f169c0eaSGlenn Lagasse * zonepath_ds - dataset of the zone's zonepath.
187f169c0eaSGlenn Lagasse * zoneroot_ds - pointer to a buffer to store the dataset of
188f169c0eaSGlenn Lagasse * the zoneroot that currently mounted for this zone
189f169c0eaSGlenn Lagasse * in the mounted global BE.
190f169c0eaSGlenn Lagasse * zoneroot_ds_size - size of zoneroot_ds
191f169c0eaSGlenn Lagasse * Returns:
192f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
193f169c0eaSGlenn Lagasse * be_errno_t - Failure
194f169c0eaSGlenn Lagasse * Scope:
195f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
196f169c0eaSGlenn Lagasse */
197f169c0eaSGlenn Lagasse int
be_find_mounted_zone_root(char * zone_altroot,char * zonepath_ds,char * zoneroot_ds,int zoneroot_ds_size)198f169c0eaSGlenn Lagasse be_find_mounted_zone_root(char *zone_altroot, char *zonepath_ds,
199f169c0eaSGlenn Lagasse char *zoneroot_ds, int zoneroot_ds_size)
200f169c0eaSGlenn Lagasse {
201f169c0eaSGlenn Lagasse mounted_zone_root_data_t mzr_data = { 0 };
202f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
203f169c0eaSGlenn Lagasse char zone_container_ds[MAXPATHLEN];
204f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
205f169c0eaSGlenn Lagasse int zret = 0;
206f169c0eaSGlenn Lagasse
207f169c0eaSGlenn Lagasse /* Generate string for the root container dataset for this zone. */
208f169c0eaSGlenn Lagasse be_make_container_ds(zonepath_ds, zone_container_ds,
209f169c0eaSGlenn Lagasse sizeof (zone_container_ds));
210f169c0eaSGlenn Lagasse
211f169c0eaSGlenn Lagasse /* Get handle to this zone's root container dataset. */
212f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
213f169c0eaSGlenn Lagasse == NULL) {
214f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_mounted_zone_root: failed to "
215f169c0eaSGlenn Lagasse "open zone root container dataset (%s): %s\n"),
216f169c0eaSGlenn Lagasse zone_container_ds, libzfs_error_description(g_zfs));
217f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
218f169c0eaSGlenn Lagasse }
219f169c0eaSGlenn Lagasse
220f169c0eaSGlenn Lagasse mzr_data.zone_altroot = zone_altroot;
221f169c0eaSGlenn Lagasse
222f169c0eaSGlenn Lagasse /*
223f169c0eaSGlenn Lagasse * Iterate through all of the zone's BEs, looking for the one
224f169c0eaSGlenn Lagasse * that is currently mounted at the zone altroot in the mounted
225f169c0eaSGlenn Lagasse * global BE.
226f169c0eaSGlenn Lagasse */
227f169c0eaSGlenn Lagasse if ((zret = zfs_iter_filesystems(zhp,
228f169c0eaSGlenn Lagasse be_find_mounted_zone_root_callback, &mzr_data)) == 0) {
229f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_mounted_zone_root: did not "
230f169c0eaSGlenn Lagasse "find mounted zone under altroot zonepath %s\n"),
231f169c0eaSGlenn Lagasse zonepath_ds);
232f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MOUNTED_ZONE;
233f169c0eaSGlenn Lagasse goto done;
234f169c0eaSGlenn Lagasse } else if (zret < 0) {
235f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_mounted_zone_root: "
236f169c0eaSGlenn Lagasse "zfs_iter_filesystems failed: %s\n"),
237f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
238f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
239f169c0eaSGlenn Lagasse goto done;
240f169c0eaSGlenn Lagasse }
241f169c0eaSGlenn Lagasse
242f169c0eaSGlenn Lagasse if (mzr_data.zoneroot_ds != NULL) {
243f169c0eaSGlenn Lagasse (void) strlcpy(zoneroot_ds, mzr_data.zoneroot_ds,
244f169c0eaSGlenn Lagasse zoneroot_ds_size);
245f169c0eaSGlenn Lagasse free(mzr_data.zoneroot_ds);
246f169c0eaSGlenn Lagasse }
247f169c0eaSGlenn Lagasse
248f169c0eaSGlenn Lagasse done:
249f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
250f169c0eaSGlenn Lagasse return (ret);
251f169c0eaSGlenn Lagasse }
252f169c0eaSGlenn Lagasse
253f169c0eaSGlenn Lagasse /*
254f169c0eaSGlenn Lagasse * Function: be_zone_supported
255f169c0eaSGlenn Lagasse * Description: This function will determine if a zone is supported
256f169c0eaSGlenn Lagasse * based on its zonepath dataset. The zonepath dataset
257f169c0eaSGlenn Lagasse * must:
258f169c0eaSGlenn Lagasse * - not be under any global BE root dataset.
259f169c0eaSGlenn Lagasse * - have a root container dataset underneath it.
260f169c0eaSGlenn Lagasse *
261f169c0eaSGlenn Lagasse * Parameters:
262f169c0eaSGlenn Lagasse * zonepath_ds - name of dataset of the zonepath of the
263f169c0eaSGlenn Lagasse * zone to check.
264f169c0eaSGlenn Lagasse * Returns:
265f169c0eaSGlenn Lagasse * B_TRUE - zone is supported
266f169c0eaSGlenn Lagasse * B_FALSE - zone is not supported
267f169c0eaSGlenn Lagasse * Scope:
268f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
269f169c0eaSGlenn Lagasse */
270f169c0eaSGlenn Lagasse boolean_t
be_zone_supported(char * zonepath_ds)271f169c0eaSGlenn Lagasse be_zone_supported(char *zonepath_ds)
272f169c0eaSGlenn Lagasse {
273f169c0eaSGlenn Lagasse char zone_container_ds[MAXPATHLEN];
274f169c0eaSGlenn Lagasse int ret = 0;
275f169c0eaSGlenn Lagasse
276f169c0eaSGlenn Lagasse /*
277f169c0eaSGlenn Lagasse * Make sure the dataset for the zonepath is not hierarchically
278f169c0eaSGlenn Lagasse * under any reserved BE root container dataset of any pool.
279f169c0eaSGlenn Lagasse */
280f169c0eaSGlenn Lagasse if ((ret = zpool_iter(g_zfs, be_check_be_roots_callback,
281f169c0eaSGlenn Lagasse zonepath_ds)) > 0) {
282f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_supported: "
283f169c0eaSGlenn Lagasse "zonepath dataset %s not supported\n"), zonepath_ds);
284f169c0eaSGlenn Lagasse return (B_FALSE);
285f169c0eaSGlenn Lagasse } else if (ret < 0) {
286f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_supported: "
287f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"),
288f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
289f169c0eaSGlenn Lagasse return (B_FALSE);
290f169c0eaSGlenn Lagasse }
291f169c0eaSGlenn Lagasse
292f169c0eaSGlenn Lagasse /*
293f169c0eaSGlenn Lagasse * Make sure the zonepath has a zone root container dataset
294f169c0eaSGlenn Lagasse * underneath it.
295f169c0eaSGlenn Lagasse */
296f169c0eaSGlenn Lagasse be_make_container_ds(zonepath_ds, zone_container_ds,
297f169c0eaSGlenn Lagasse sizeof (zone_container_ds));
298f169c0eaSGlenn Lagasse
299f169c0eaSGlenn Lagasse if (!zfs_dataset_exists(g_zfs, zone_container_ds,
300f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) {
301f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_supported: "
302f169c0eaSGlenn Lagasse "zonepath dataset (%s) does not have a zone root container "
303f169c0eaSGlenn Lagasse "dataset, zone is not supported, skipping ...\n"),
304f169c0eaSGlenn Lagasse zonepath_ds);
305f169c0eaSGlenn Lagasse return (B_FALSE);
306f169c0eaSGlenn Lagasse }
307f169c0eaSGlenn Lagasse
308f169c0eaSGlenn Lagasse return (B_TRUE);
309f169c0eaSGlenn Lagasse }
310f169c0eaSGlenn Lagasse
311f169c0eaSGlenn Lagasse /*
312f169c0eaSGlenn Lagasse * Function: be_get_supported_brandlist
313f169c0eaSGlenn Lagasse * Desciption: This functions retuns a list of supported brands in
314f169c0eaSGlenn Lagasse * a zoneBrandList_t object.
315f169c0eaSGlenn Lagasse * Parameters:
316f169c0eaSGlenn Lagasse * None
317f169c0eaSGlenn Lagasse * Returns:
318f169c0eaSGlenn Lagasse * Failure - NULL if no supported brands found.
319f169c0eaSGlenn Lagasse * Success - pointer to zoneBrandList structure.
320f169c0eaSGlenn Lagasse * Scope:
321f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
322f169c0eaSGlenn Lagasse */
323f169c0eaSGlenn Lagasse zoneBrandList_t *
be_get_supported_brandlist(void)324f169c0eaSGlenn Lagasse be_get_supported_brandlist(void)
325f169c0eaSGlenn Lagasse {
326f169c0eaSGlenn Lagasse return (z_make_brand_list(BE_ZONE_SUPPORTED_BRANDS,
327f169c0eaSGlenn Lagasse BE_ZONE_SUPPORTED_BRANDS_DELIM));
328f169c0eaSGlenn Lagasse }
329f169c0eaSGlenn Lagasse
330f169c0eaSGlenn Lagasse /*
331f169c0eaSGlenn Lagasse * Function: be_zone_get_parent_uuid
332f169c0eaSGlenn Lagasse * Description: This function gets the parentbe property of a zone root
333f169c0eaSGlenn Lagasse * dataset, parsed it into internal uuid format, and returns
334f169c0eaSGlenn Lagasse * it in the uuid_t reference pointer passed in.
335f169c0eaSGlenn Lagasse * Parameters:
336f169c0eaSGlenn Lagasse * root_ds - dataset name of a zone root dataset
337f169c0eaSGlenn Lagasse * uu - pointer to a uuid_t to return the parentbe uuid in
338f169c0eaSGlenn Lagasse * Returns:
339f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
340f169c0eaSGlenn Lagasse * be_errno_t - Failure
341f169c0eaSGlenn Lagasse * Scope:
342f169c0eaSGlenn Lagasse * Private
343f169c0eaSGlenn Lagasse */
344f169c0eaSGlenn Lagasse int
be_zone_get_parent_uuid(const char * root_ds,uuid_t * uu)345f169c0eaSGlenn Lagasse be_zone_get_parent_uuid(const char *root_ds, uuid_t *uu)
346f169c0eaSGlenn Lagasse {
347f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
348f169c0eaSGlenn Lagasse nvlist_t *userprops = NULL;
349f169c0eaSGlenn Lagasse nvlist_t *propname = NULL;
350f169c0eaSGlenn Lagasse char *uu_string = NULL;
351f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
352f169c0eaSGlenn Lagasse
353f169c0eaSGlenn Lagasse /* Get handle to zone root dataset */
354f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
355f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_get_parent_uuid: failed to "
356f169c0eaSGlenn Lagasse "open zone root dataset (%s): %s\n"), root_ds,
357f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
358f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
359f169c0eaSGlenn Lagasse }
360f169c0eaSGlenn Lagasse
361f169c0eaSGlenn Lagasse /* Get user properties for zone root dataset */
362f169c0eaSGlenn Lagasse if ((userprops = zfs_get_user_props(zhp)) == NULL) {
363f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_get_parent_uuid: "
364f169c0eaSGlenn Lagasse "failed to get user properties for zone root "
365f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), root_ds,
366f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
367f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
368f169c0eaSGlenn Lagasse goto done;
369f169c0eaSGlenn Lagasse }
370f169c0eaSGlenn Lagasse
371f169c0eaSGlenn Lagasse /* Get UUID string from zone's root dataset user properties */
372f169c0eaSGlenn Lagasse if (nvlist_lookup_nvlist(userprops, BE_ZONE_PARENTBE_PROPERTY,
373f169c0eaSGlenn Lagasse &propname) != 0 || nvlist_lookup_string(propname, ZPROP_VALUE,
374f169c0eaSGlenn Lagasse &uu_string) != 0) {
375f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_get_parent_uuid: failed to "
376f169c0eaSGlenn Lagasse "get parent uuid property from zone root dataset user "
377f169c0eaSGlenn Lagasse "properties.\n"));
378f169c0eaSGlenn Lagasse ret = BE_ERR_ZONE_NO_PARENTBE;
379f169c0eaSGlenn Lagasse goto done;
380f169c0eaSGlenn Lagasse }
381f169c0eaSGlenn Lagasse
382f169c0eaSGlenn Lagasse /* Parse the uuid string into internal format */
383f169c0eaSGlenn Lagasse if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
384f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_get_parent_uuid: failed to "
385f169c0eaSGlenn Lagasse "parse parentuuid\n"));
386f169c0eaSGlenn Lagasse ret = BE_ERR_PARSE_UUID;
387f169c0eaSGlenn Lagasse }
388f169c0eaSGlenn Lagasse
389f169c0eaSGlenn Lagasse done:
390f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
391f169c0eaSGlenn Lagasse return (ret);
392f169c0eaSGlenn Lagasse }
393f169c0eaSGlenn Lagasse
394*7e0e2549SAlexander Eremin /*
395*7e0e2549SAlexander Eremin * Function: be_zone_set_parent_uuid
396*7e0e2549SAlexander Eremin * Description: This function sets parentbe uuid into
397*7e0e2549SAlexander Eremin * a zfs user property for a root zone dataset.
398*7e0e2549SAlexander Eremin * Parameters:
399*7e0e2549SAlexander Eremin * root_ds - Root zone dataset of the BE to set a uuid on.
400*7e0e2549SAlexander Eremin * Return:
401*7e0e2549SAlexander Eremin * be_errno_t - Failure
402*7e0e2549SAlexander Eremin * BE_SUCCESS - Success
403*7e0e2549SAlexander Eremin * Scope:
404*7e0e2549SAlexander Eremin * Semi-private (library wide uses only)
405*7e0e2549SAlexander Eremin */
406*7e0e2549SAlexander Eremin int
be_zone_set_parent_uuid(char * root_ds,uuid_t uu)407*7e0e2549SAlexander Eremin be_zone_set_parent_uuid(char *root_ds, uuid_t uu)
408*7e0e2549SAlexander Eremin {
409*7e0e2549SAlexander Eremin zfs_handle_t *zhp = NULL;
410*7e0e2549SAlexander Eremin char uu_string[UUID_PRINTABLE_STRING_LENGTH];
411*7e0e2549SAlexander Eremin int ret = BE_SUCCESS;
412*7e0e2549SAlexander Eremin
413*7e0e2549SAlexander Eremin uuid_unparse(uu, uu_string);
414*7e0e2549SAlexander Eremin
415*7e0e2549SAlexander Eremin /* Get handle to the root zone dataset. */
416*7e0e2549SAlexander Eremin if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
417*7e0e2549SAlexander Eremin be_print_err(gettext("be_zone_set_parent_uuid: failed to "
418*7e0e2549SAlexander Eremin "open root zone dataset (%s): %s\n"), root_ds,
419*7e0e2549SAlexander Eremin libzfs_error_description(g_zfs));
420*7e0e2549SAlexander Eremin return (zfs_err_to_be_err(g_zfs));
421*7e0e2549SAlexander Eremin }
422*7e0e2549SAlexander Eremin
423*7e0e2549SAlexander Eremin /* Set parentbe uuid property for the root zone dataset */
424*7e0e2549SAlexander Eremin if (zfs_prop_set(zhp, BE_ZONE_PARENTBE_PROPERTY, uu_string) != 0) {
425*7e0e2549SAlexander Eremin be_print_err(gettext("be_zone_set_parent_uuid: failed to "
426*7e0e2549SAlexander Eremin "set parentbe uuid property for root zone dataset: %s\n"),
427*7e0e2549SAlexander Eremin libzfs_error_description(g_zfs));
428*7e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs);
429*7e0e2549SAlexander Eremin }
430*7e0e2549SAlexander Eremin
431*7e0e2549SAlexander Eremin ZFS_CLOSE(zhp);
432*7e0e2549SAlexander Eremin return (ret);
433*7e0e2549SAlexander Eremin }
434*7e0e2549SAlexander Eremin
435*7e0e2549SAlexander Eremin /*
436*7e0e2549SAlexander Eremin * Function: be_zone_compare_uuids
437*7e0e2549SAlexander Eremin * Description: This function compare the parentbe uuid of the
438*7e0e2549SAlexander Eremin * current running root zone dataset with the parentbe
439*7e0e2549SAlexander Eremin * uuid of the given root zone dataset.
440*7e0e2549SAlexander Eremin * Parameters:
441*7e0e2549SAlexander Eremin * root_ds - Root zone dataset of the BE to compare.
442*7e0e2549SAlexander Eremin * Return:
443*7e0e2549SAlexander Eremin * B_TRUE - root dataset has right parentbe uuid
444*7e0e2549SAlexander Eremin * B_FALSE - root dataset has wrong parentbe uuid
445*7e0e2549SAlexander Eremin * Scope:
446*7e0e2549SAlexander Eremin * Semi-private (library wide uses only)
447*7e0e2549SAlexander Eremin */
448*7e0e2549SAlexander Eremin boolean_t
be_zone_compare_uuids(char * root_ds)449*7e0e2549SAlexander Eremin be_zone_compare_uuids(char *root_ds)
450*7e0e2549SAlexander Eremin {
451*7e0e2549SAlexander Eremin char *active_ds;
452*7e0e2549SAlexander Eremin uuid_t parent_uuid = {0};
453*7e0e2549SAlexander Eremin uuid_t cur_parent_uuid = {0};
454*7e0e2549SAlexander Eremin
455*7e0e2549SAlexander Eremin /* Get parentbe uuid from given zone root dataset */
456*7e0e2549SAlexander Eremin if ((be_zone_get_parent_uuid(root_ds,
457*7e0e2549SAlexander Eremin &parent_uuid)) != BE_SUCCESS) {
458*7e0e2549SAlexander Eremin be_print_err(gettext("be_zone_compare_uuids: failed to get "
459*7e0e2549SAlexander Eremin "parentbe uuid from the given BE\n"));
460*7e0e2549SAlexander Eremin return (B_FALSE);
461*7e0e2549SAlexander Eremin }
462*7e0e2549SAlexander Eremin
463*7e0e2549SAlexander Eremin /*
464*7e0e2549SAlexander Eremin * Find current running zone root dataset and get it's parentbe
465*7e0e2549SAlexander Eremin * uuid property.
466*7e0e2549SAlexander Eremin */
467*7e0e2549SAlexander Eremin if ((active_ds = be_get_ds_from_dir("/")) != NULL) {
468*7e0e2549SAlexander Eremin if ((be_zone_get_parent_uuid(active_ds,
469*7e0e2549SAlexander Eremin &cur_parent_uuid)) != BE_SUCCESS) {
470*7e0e2549SAlexander Eremin be_print_err(gettext("be_zone_compare_uuids: failed "
471*7e0e2549SAlexander Eremin "to get parentbe uuid from the current running zone "
472*7e0e2549SAlexander Eremin "root dataset\n"));
473*7e0e2549SAlexander Eremin return (B_FALSE);
474*7e0e2549SAlexander Eremin }
475*7e0e2549SAlexander Eremin } else {
476*7e0e2549SAlexander Eremin be_print_err(gettext("be_zone_compare_uuids: zone root dataset "
477*7e0e2549SAlexander Eremin "is not mounted\n"));
478*7e0e2549SAlexander Eremin return (B_FALSE);
479*7e0e2549SAlexander Eremin }
480*7e0e2549SAlexander Eremin
481*7e0e2549SAlexander Eremin if (uuid_compare(parent_uuid, cur_parent_uuid) != 0) {
482*7e0e2549SAlexander Eremin return (B_FALSE);
483*7e0e2549SAlexander Eremin }
484*7e0e2549SAlexander Eremin
485*7e0e2549SAlexander Eremin return (B_TRUE);
486*7e0e2549SAlexander Eremin }
487*7e0e2549SAlexander Eremin
488f169c0eaSGlenn Lagasse /* ******************************************************************** */
489f169c0eaSGlenn Lagasse /* Private Functions */
490f169c0eaSGlenn Lagasse /* ******************************************************************** */
491f169c0eaSGlenn Lagasse
492f169c0eaSGlenn Lagasse /*
493f169c0eaSGlenn Lagasse * Function: be_find_active_zone_root_callback
494f169c0eaSGlenn Lagasse * Description: This function is used as a callback to iterate over all of
495f169c0eaSGlenn Lagasse * a zone's root datasets, finding the one that is marked active
496f169c0eaSGlenn Lagasse * for the parent BE specified in the data passed in. The name
497f169c0eaSGlenn Lagasse * of the zone's active root dataset is returned in heap storage
498f169c0eaSGlenn Lagasse * in the active_zone_root_data_t structure passed in, so the
499f169c0eaSGlenn Lagasse * caller is responsible for freeing it.
500f169c0eaSGlenn Lagasse * Parameters:
501f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to current dataset being processed
502f169c0eaSGlenn Lagasse * data - active_zone_root_data_t pointer
503f169c0eaSGlenn Lagasse * Returns:
504f169c0eaSGlenn Lagasse * 0 - Success
505f169c0eaSGlenn Lagasse * >0 - Failure
506f169c0eaSGlenn Lagasse * Scope:
507f169c0eaSGlenn Lagasse * Private
508f169c0eaSGlenn Lagasse */
509f169c0eaSGlenn Lagasse static int
be_find_active_zone_root_callback(zfs_handle_t * zhp,void * data)510f169c0eaSGlenn Lagasse be_find_active_zone_root_callback(zfs_handle_t *zhp, void *data)
511f169c0eaSGlenn Lagasse {
512f169c0eaSGlenn Lagasse active_zone_root_data_t *azr_data = data;
513f169c0eaSGlenn Lagasse uuid_t parent_uuid = { 0 };
514f169c0eaSGlenn Lagasse int iret = 0;
515f169c0eaSGlenn Lagasse int ret = 0;
516f169c0eaSGlenn Lagasse
517f169c0eaSGlenn Lagasse if ((iret = be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid))
518f169c0eaSGlenn Lagasse != BE_SUCCESS) {
519f169c0eaSGlenn Lagasse be_print_err(gettext("be_find_active_zone_root_callback: "
520f169c0eaSGlenn Lagasse "skipping zone root dataset (%s): %s\n"),
521f169c0eaSGlenn Lagasse zfs_get_name(zhp), be_err_to_str(iret));
522f169c0eaSGlenn Lagasse goto done;
523f169c0eaSGlenn Lagasse }
524f169c0eaSGlenn Lagasse
525f169c0eaSGlenn Lagasse if (uuid_compare(azr_data->parent_uuid, parent_uuid) == 0) {
526f169c0eaSGlenn Lagasse /*
527f169c0eaSGlenn Lagasse * Found a zone root dataset belonging to the right parent,
528f169c0eaSGlenn Lagasse * check if its active.
529f169c0eaSGlenn Lagasse */
530f169c0eaSGlenn Lagasse if (be_zone_get_active(zhp)) {
531f169c0eaSGlenn Lagasse /*
532f169c0eaSGlenn Lagasse * Found active zone root dataset, if its already
533f169c0eaSGlenn Lagasse * set in the callback data, that means this
534f169c0eaSGlenn Lagasse * is the second one we've found. Return error.
535f169c0eaSGlenn Lagasse */
536f169c0eaSGlenn Lagasse if (azr_data->zoneroot_ds != NULL) {
537f169c0eaSGlenn Lagasse ret = BE_ERR_ZONE_MULTIPLE_ACTIVE;
538f169c0eaSGlenn Lagasse goto done;
539f169c0eaSGlenn Lagasse }
540f169c0eaSGlenn Lagasse
541f169c0eaSGlenn Lagasse azr_data->zoneroot_ds = strdup(zfs_get_name(zhp));
542f169c0eaSGlenn Lagasse if (azr_data->zoneroot_ds == NULL) {
543f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
544f169c0eaSGlenn Lagasse }
545f169c0eaSGlenn Lagasse }
546f169c0eaSGlenn Lagasse }
547f169c0eaSGlenn Lagasse
548f169c0eaSGlenn Lagasse done:
549f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
550f169c0eaSGlenn Lagasse return (ret);
551f169c0eaSGlenn Lagasse }
552f169c0eaSGlenn Lagasse
553f169c0eaSGlenn Lagasse /*
554f169c0eaSGlenn Lagasse * Function: be_find_mounted_zone_root_callback
555f169c0eaSGlenn Lagasse * Description: This function is used as a callback to iterate over all of
556f169c0eaSGlenn Lagasse * a zone's root datasets, find the one that is currently
557f169c0eaSGlenn Lagasse * mounted for the parent BE specified in the data passed in.
558f169c0eaSGlenn Lagasse * The name of the zone's mounted root dataset is returned in
559f169c0eaSGlenn Lagasse * heap storage the mounted_zone_data_t structure passed in,
560f169c0eaSGlenn Lagasse * so the caller is responsible for freeing it.
561f169c0eaSGlenn Lagasse * Parameters:
562f169c0eaSGlenn Lagasse * zhp - zfs_handle_t pointer to the current dataset being
563f169c0eaSGlenn Lagasse * processed
564f169c0eaSGlenn Lagasse * data - mounted_zone_data_t pointer
565f169c0eaSGlenn Lagasse * Returns:
566f169c0eaSGlenn Lagasse * 0 - not mounted as zone's root
567f169c0eaSGlenn Lagasse * 1 - this dataset is mounted as zone's root
568f169c0eaSGlenn Lagasse * Scope:
569f169c0eaSGlenn Lagasse * Private
570f169c0eaSGlenn Lagasse */
571f169c0eaSGlenn Lagasse static int
be_find_mounted_zone_root_callback(zfs_handle_t * zhp,void * data)572f169c0eaSGlenn Lagasse be_find_mounted_zone_root_callback(zfs_handle_t *zhp, void *data)
573f169c0eaSGlenn Lagasse {
574f169c0eaSGlenn Lagasse mounted_zone_root_data_t *mzr_data = data;
575f169c0eaSGlenn Lagasse char *mp = NULL;
576f169c0eaSGlenn Lagasse
577f169c0eaSGlenn Lagasse if (zfs_is_mounted(zhp, &mp) && mp != NULL &&
578f169c0eaSGlenn Lagasse strcmp(mp, mzr_data->zone_altroot) == 0) {
579f169c0eaSGlenn Lagasse mzr_data->zoneroot_ds = strdup(zfs_get_name(zhp));
580f169c0eaSGlenn Lagasse free(mp);
581f169c0eaSGlenn Lagasse return (1);
582f169c0eaSGlenn Lagasse }
583f169c0eaSGlenn Lagasse
584f169c0eaSGlenn Lagasse free(mp);
585f169c0eaSGlenn Lagasse return (0);
586f169c0eaSGlenn Lagasse }
587f169c0eaSGlenn Lagasse
588f169c0eaSGlenn Lagasse /*
589f169c0eaSGlenn Lagasse * Function: be_zone_get_active
590f169c0eaSGlenn Lagasse * Description: This function gets the active property of a zone root
591f169c0eaSGlenn Lagasse * dataset, and returns true if active property is on.
592f169c0eaSGlenn Lagasse * Parameters:
593f169c0eaSGlenn Lagasse * zfs - zfs_handle_t pointer to zone root dataset to check
594f169c0eaSGlenn Lagasse * Returns:
595f169c0eaSGlenn Lagasse * B_TRUE - zone root dataset is active
596f169c0eaSGlenn Lagasse * B_FALSE - zone root dataset is not active
597f169c0eaSGlenn Lagasse * Scope:
598f169c0eaSGlenn Lagasse * Private
599f169c0eaSGlenn Lagasse */
600f169c0eaSGlenn Lagasse static boolean_t
be_zone_get_active(zfs_handle_t * zhp)601f169c0eaSGlenn Lagasse be_zone_get_active(zfs_handle_t *zhp)
602f169c0eaSGlenn Lagasse {
603f169c0eaSGlenn Lagasse nvlist_t *userprops = NULL;
604f169c0eaSGlenn Lagasse nvlist_t *propname = NULL;
605f169c0eaSGlenn Lagasse char *active_str = NULL;
606f169c0eaSGlenn Lagasse
607f169c0eaSGlenn Lagasse /* Get user properties for the zone root dataset */
608f169c0eaSGlenn Lagasse if ((userprops = zfs_get_user_props(zhp)) == NULL) {
609f169c0eaSGlenn Lagasse be_print_err(gettext("be_zone_get_active: "
610f169c0eaSGlenn Lagasse "failed to get user properties for zone root "
611f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), zfs_get_name(zhp),
612f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
613f169c0eaSGlenn Lagasse return (B_FALSE);
614f169c0eaSGlenn Lagasse }
615f169c0eaSGlenn Lagasse
616f169c0eaSGlenn Lagasse /* Get active property from the zone root dataset user properties */
617f169c0eaSGlenn Lagasse if (nvlist_lookup_nvlist(userprops, BE_ZONE_ACTIVE_PROPERTY, &propname)
618f169c0eaSGlenn Lagasse != 0 || nvlist_lookup_string(propname, ZPROP_VALUE, &active_str)
619f169c0eaSGlenn Lagasse != 0) {
620f169c0eaSGlenn Lagasse return (B_FALSE);
621f169c0eaSGlenn Lagasse }
622f169c0eaSGlenn Lagasse
623f169c0eaSGlenn Lagasse if (strcmp(active_str, "on") == 0)
624f169c0eaSGlenn Lagasse return (B_TRUE);
625f169c0eaSGlenn Lagasse
626f169c0eaSGlenn Lagasse return (B_FALSE);
627f169c0eaSGlenn Lagasse }
628