PSARC 2010/059 SNAP BE Management
[illumos-gate.git] / usr / src / lib / libbe / common / be_zones.c
blob886b0dacad77f42c14248d8430b8aa989dc33f44
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * System includes
29 #include <assert.h>
30 #include <errno.h>
31 #include <libintl.h>
32 #include <libnvpair.h>
33 #include <libzfs.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/mntent.h>
38 #include <sys/mnttab.h>
39 #include <sys/mount.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/vfstab.h>
43 #include <unistd.h>
45 #include <libbe.h>
46 #include <libbe_priv.h>
48 typedef struct active_zone_root_data {
49 uuid_t parent_uuid;
50 char *zoneroot_ds;
51 } active_zone_root_data_t;
53 typedef struct mounted_zone_root_data {
54 char *zone_altroot;
55 char *zoneroot_ds;
56 } mounted_zone_root_data_t;
58 /* Private function prototypes */
59 static int be_find_active_zone_root_callback(zfs_handle_t *, void *);
60 static int be_find_mounted_zone_root_callback(zfs_handle_t *, void *);
61 static boolean_t be_zone_get_active(zfs_handle_t *);
64 /* ******************************************************************** */
65 /* Semi-Private Functions */
66 /* ******************************************************************** */
69 * Function: be_make_zoneroot
70 * Description: Generate a string for a zone's zoneroot given the
71 * zone's zonepath.
72 * Parameters:
73 * zonepath - pointer to zonepath
74 * zoneroot - pointer to buffer to retrn zoneroot in.
75 * zoneroot_size - size of zoneroot
76 * Returns:
77 * None
78 * Scope:
79 * Semi-private (library wise use only)
81 void
82 be_make_zoneroot(char *zonepath, char *zoneroot, int zoneroot_size)
84 (void) snprintf(zoneroot, zoneroot_size, "%s/root", zonepath);
88 * Function: be_find_active_zone_root
89 * Description: This function will find the active zone root of a zone for
90 * a given global BE. It will iterate all of the zone roots
91 * under a zonepath, find the zone roots that belong to the
92 * specified global BE, and return the one that is active.
93 * Parameters:
94 * be_zhp - zfs handle to global BE root dataset.
95 * zonepath_ds - pointer to zone's zonepath dataset.
96 * zoneroot_ds - pointer to a buffer to store the dataset name of
97 * the zone's zoneroot that's currently active for this
98 * given global BE..
99 * zoneroot-ds_size - size of zoneroot_ds.
100 * Returns:
101 * BE_SUCCESS - Success
102 * be_errno_t - Failure
103 * Scope:
104 * Semi-private (library wide use only)
107 be_find_active_zone_root(zfs_handle_t *be_zhp, char *zonepath_ds,
108 char *zoneroot_ds, int zoneroot_ds_size)
110 active_zone_root_data_t azr_data = { 0 };
111 zfs_handle_t *zhp;
112 char zone_container_ds[MAXPATHLEN];
113 int ret = BE_SUCCESS;
115 /* Get the uuid of the parent global BE */
116 if ((ret = be_get_uuid(zfs_get_name(be_zhp), &azr_data.parent_uuid))
117 != BE_SUCCESS) {
118 be_print_err(gettext("be_find_active_zone_root: failed to "
119 "get uuid for BE root dataset %s\n"), zfs_get_name(be_zhp));
120 return (ret);
123 /* Generate string for the root container dataset for this zone. */
124 be_make_container_ds(zonepath_ds, zone_container_ds,
125 sizeof (zone_container_ds));
127 /* Get handle to this zone's root container dataset */
128 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
129 == NULL) {
130 be_print_err(gettext("be_find_active_zone_root: failed to "
131 "open zone root container dataset (%s): %s\n"),
132 zone_container_ds, libzfs_error_description(g_zfs));
133 return (zfs_err_to_be_err(g_zfs));
137 * Iterate through all of this zone's BEs, looking for ones
138 * that belong to the parent global BE, and finding the one
139 * that is marked active.
141 if ((ret = zfs_iter_filesystems(zhp, be_find_active_zone_root_callback,
142 &azr_data)) != 0) {
143 be_print_err(gettext("be_find_active_zone_root: failed to "
144 "find active zone root in zonepath dataset %s: %s\n"),
145 zonepath_ds, be_err_to_str(ret));
146 goto done;
149 if (azr_data.zoneroot_ds != NULL) {
150 (void) strlcpy(zoneroot_ds, azr_data.zoneroot_ds,
151 zoneroot_ds_size);
152 free(azr_data.zoneroot_ds);
153 } else {
154 be_print_err(gettext("be_find_active_zone_root: failed to "
155 "find active zone root in zonepath dataset %s\n"),
156 zonepath_ds);
157 ret = BE_ERR_ZONE_NO_ACTIVE_ROOT;
160 done:
161 ZFS_CLOSE(zhp);
162 return (ret);
166 * Function: be_find_mounted_zone_root
167 * Description: This function will find the dataset mounted as the zoneroot
168 * of a zone for a given mounted global BE.
169 * Parameters:
170 * zone_altroot - path of zoneroot wrt the mounted global BE.
171 * zonepath_ds - dataset of the zone's zonepath.
172 * zoneroot_ds - pointer to a buffer to store the dataset of
173 * the zoneroot that currently mounted for this zone
174 * in the mounted global BE.
175 * zoneroot_ds_size - size of zoneroot_ds
176 * Returns:
177 * BE_SUCCESS - Success
178 * be_errno_t - Failure
179 * Scope:
180 * Semi-private (library wide use only)
183 be_find_mounted_zone_root(char *zone_altroot, char *zonepath_ds,
184 char *zoneroot_ds, int zoneroot_ds_size)
186 mounted_zone_root_data_t mzr_data = { 0 };
187 zfs_handle_t *zhp = NULL;
188 char zone_container_ds[MAXPATHLEN];
189 int ret = BE_SUCCESS;
190 int zret = 0;
192 /* Generate string for the root container dataset for this zone. */
193 be_make_container_ds(zonepath_ds, zone_container_ds,
194 sizeof (zone_container_ds));
196 /* Get handle to this zone's root container dataset. */
197 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
198 == NULL) {
199 be_print_err(gettext("be_find_mounted_zone_root: failed to "
200 "open zone root container dataset (%s): %s\n"),
201 zone_container_ds, libzfs_error_description(g_zfs));
202 return (zfs_err_to_be_err(g_zfs));
205 mzr_data.zone_altroot = zone_altroot;
208 * Iterate through all of the zone's BEs, looking for the one
209 * that is currently mounted at the zone altroot in the mounted
210 * global BE.
212 if ((zret = zfs_iter_filesystems(zhp,
213 be_find_mounted_zone_root_callback, &mzr_data)) == 0) {
214 be_print_err(gettext("be_find_mounted_zone_root: did not "
215 "find mounted zone under altroot zonepath %s\n"),
216 zonepath_ds);
217 ret = BE_ERR_NO_MOUNTED_ZONE;
218 goto done;
219 } else if (zret < 0) {
220 be_print_err(gettext("be_find_mounted_zone_root: "
221 "zfs_iter_filesystems failed: %s\n"),
222 libzfs_error_description(g_zfs));
223 ret = zfs_err_to_be_err(g_zfs);
224 goto done;
227 if (mzr_data.zoneroot_ds != NULL) {
228 (void) strlcpy(zoneroot_ds, mzr_data.zoneroot_ds,
229 zoneroot_ds_size);
230 free(mzr_data.zoneroot_ds);
233 done:
234 ZFS_CLOSE(zhp);
235 return (ret);
239 * Function: be_zone_supported
240 * Description: This function will determine if a zone is supported
241 * based on its zonepath dataset. The zonepath dataset
242 * must:
243 * - not be under any global BE root dataset.
244 * - have a root container dataset underneath it.
246 * Parameters:
247 * zonepath_ds - name of dataset of the zonepath of the
248 * zone to check.
249 * Returns:
250 * B_TRUE - zone is supported
251 * B_FALSE - zone is not supported
252 * Scope:
253 * Semi-private (library wide use only)
255 boolean_t
256 be_zone_supported(char *zonepath_ds)
258 char zone_container_ds[MAXPATHLEN];
259 int ret = 0;
262 * Make sure the dataset for the zonepath is not hierarchically
263 * under any reserved BE root container dataset of any pool.
265 if ((ret = zpool_iter(g_zfs, be_check_be_roots_callback,
266 zonepath_ds)) > 0) {
267 be_print_err(gettext("be_zone_supported: "
268 "zonepath dataset %s not supported\n"), zonepath_ds);
269 return (B_FALSE);
270 } else if (ret < 0) {
271 be_print_err(gettext("be_zone_supported: "
272 "zpool_iter failed: %s\n"),
273 libzfs_error_description(g_zfs));
274 return (B_FALSE);
278 * Make sure the zonepath has a zone root container dataset
279 * underneath it.
281 be_make_container_ds(zonepath_ds, zone_container_ds,
282 sizeof (zone_container_ds));
284 if (!zfs_dataset_exists(g_zfs, zone_container_ds,
285 ZFS_TYPE_FILESYSTEM)) {
286 be_print_err(gettext("be_zone_supported: "
287 "zonepath dataset (%s) does not have a zone root container "
288 "dataset, zone is not supported, skipping ...\n"),
289 zonepath_ds);
290 return (B_FALSE);
293 return (B_TRUE);
297 * Function: be_get_supported_brandlist
298 * Desciption: This functions retuns a list of supported brands in
299 * a zoneBrandList_t object.
300 * Parameters:
301 * None
302 * Returns:
303 * Failure - NULL if no supported brands found.
304 * Success - pointer to zoneBrandList structure.
305 * Scope:
306 * Semi-private (library wide use only)
308 zoneBrandList_t *
309 be_get_supported_brandlist(void)
311 return (z_make_brand_list(BE_ZONE_SUPPORTED_BRANDS,
312 BE_ZONE_SUPPORTED_BRANDS_DELIM));
316 * Function: be_zone_get_parent_uuid
317 * Description: This function gets the parentbe property of a zone root
318 * dataset, parsed it into internal uuid format, and returns
319 * it in the uuid_t reference pointer passed in.
320 * Parameters:
321 * root_ds - dataset name of a zone root dataset
322 * uu - pointer to a uuid_t to return the parentbe uuid in
323 * Returns:
324 * BE_SUCCESS - Success
325 * be_errno_t - Failure
326 * Scope:
327 * Private
330 be_zone_get_parent_uuid(const char *root_ds, uuid_t *uu)
332 zfs_handle_t *zhp = NULL;
333 nvlist_t *userprops = NULL;
334 nvlist_t *propname = NULL;
335 char *uu_string = NULL;
336 int ret = BE_SUCCESS;
338 /* Get handle to zone root dataset */
339 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
340 be_print_err(gettext("be_zone_get_parent_uuid: failed to "
341 "open zone root dataset (%s): %s\n"), root_ds,
342 libzfs_error_description(g_zfs));
343 return (zfs_err_to_be_err(g_zfs));
346 /* Get user properties for zone root dataset */
347 if ((userprops = zfs_get_user_props(zhp)) == NULL) {
348 be_print_err(gettext("be_zone_get_parent_uuid: "
349 "failed to get user properties for zone root "
350 "dataset (%s): %s\n"), root_ds,
351 libzfs_error_description(g_zfs));
352 ret = zfs_err_to_be_err(g_zfs);
353 goto done;
356 /* Get UUID string from zone's root dataset user properties */
357 if (nvlist_lookup_nvlist(userprops, BE_ZONE_PARENTBE_PROPERTY,
358 &propname) != 0 || nvlist_lookup_string(propname, ZPROP_VALUE,
359 &uu_string) != 0) {
360 be_print_err(gettext("be_zone_get_parent_uuid: failed to "
361 "get parent uuid property from zone root dataset user "
362 "properties.\n"));
363 ret = BE_ERR_ZONE_NO_PARENTBE;
364 goto done;
367 /* Parse the uuid string into internal format */
368 if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
369 be_print_err(gettext("be_zone_get_parent_uuid: failed to "
370 "parse parentuuid\n"));
371 ret = BE_ERR_PARSE_UUID;
374 done:
375 ZFS_CLOSE(zhp);
376 return (ret);
379 /* ******************************************************************** */
380 /* Private Functions */
381 /* ******************************************************************** */
384 * Function: be_find_active_zone_root_callback
385 * Description: This function is used as a callback to iterate over all of
386 * a zone's root datasets, finding the one that is marked active
387 * for the parent BE specified in the data passed in. The name
388 * of the zone's active root dataset is returned in heap storage
389 * in the active_zone_root_data_t structure passed in, so the
390 * caller is responsible for freeing it.
391 * Parameters:
392 * zhp - zfs_handle_t pointer to current dataset being processed
393 * data - active_zone_root_data_t pointer
394 * Returns:
395 * 0 - Success
396 * >0 - Failure
397 * Scope:
398 * Private
400 static int
401 be_find_active_zone_root_callback(zfs_handle_t *zhp, void *data)
403 active_zone_root_data_t *azr_data = data;
404 uuid_t parent_uuid = { 0 };
405 int iret = 0;
406 int ret = 0;
408 if ((iret = be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid))
409 != BE_SUCCESS) {
410 be_print_err(gettext("be_find_active_zone_root_callback: "
411 "skipping zone root dataset (%s): %s\n"),
412 zfs_get_name(zhp), be_err_to_str(iret));
413 goto done;
416 if (uuid_compare(azr_data->parent_uuid, parent_uuid) == 0) {
418 * Found a zone root dataset belonging to the right parent,
419 * check if its active.
421 if (be_zone_get_active(zhp)) {
423 * Found active zone root dataset, if its already
424 * set in the callback data, that means this
425 * is the second one we've found. Return error.
427 if (azr_data->zoneroot_ds != NULL) {
428 ret = BE_ERR_ZONE_MULTIPLE_ACTIVE;
429 goto done;
432 azr_data->zoneroot_ds = strdup(zfs_get_name(zhp));
433 if (azr_data->zoneroot_ds == NULL) {
434 ret = BE_ERR_NOMEM;
439 done:
440 ZFS_CLOSE(zhp);
441 return (ret);
445 * Function: be_find_mounted_zone_root_callback
446 * Description: This function is used as a callback to iterate over all of
447 * a zone's root datasets, find the one that is currently
448 * mounted for the parent BE specified in the data passed in.
449 * The name of the zone's mounted root dataset is returned in
450 * heap storage the mounted_zone_data_t structure passed in,
451 * so the caller is responsible for freeing it.
452 * Parameters:
453 * zhp - zfs_handle_t pointer to the current dataset being
454 * processed
455 * data - mounted_zone_data_t pointer
456 * Returns:
457 * 0 - not mounted as zone's root
458 * 1 - this dataset is mounted as zone's root
459 * Scope:
460 * Private
462 static int
463 be_find_mounted_zone_root_callback(zfs_handle_t *zhp, void *data)
465 mounted_zone_root_data_t *mzr_data = data;
466 char *mp = NULL;
468 if (zfs_is_mounted(zhp, &mp) && mp != NULL &&
469 strcmp(mp, mzr_data->zone_altroot) == 0) {
470 mzr_data->zoneroot_ds = strdup(zfs_get_name(zhp));
471 free(mp);
472 return (1);
475 free(mp);
476 return (0);
480 * Function: be_zone_get_active
481 * Description: This function gets the active property of a zone root
482 * dataset, and returns true if active property is on.
483 * Parameters:
484 * zfs - zfs_handle_t pointer to zone root dataset to check
485 * Returns:
486 * B_TRUE - zone root dataset is active
487 * B_FALSE - zone root dataset is not active
488 * Scope:
489 * Private
491 static boolean_t
492 be_zone_get_active(zfs_handle_t *zhp)
494 nvlist_t *userprops = NULL;
495 nvlist_t *propname = NULL;
496 char *active_str = NULL;
498 /* Get user properties for the zone root dataset */
499 if ((userprops = zfs_get_user_props(zhp)) == NULL) {
500 be_print_err(gettext("be_zone_get_active: "
501 "failed to get user properties for zone root "
502 "dataset (%s): %s\n"), zfs_get_name(zhp),
503 libzfs_error_description(g_zfs));
504 return (B_FALSE);
507 /* Get active property from the zone root dataset user properties */
508 if (nvlist_lookup_nvlist(userprops, BE_ZONE_ACTIVE_PROPERTY, &propname)
509 != 0 || nvlist_lookup_string(propname, ZPROP_VALUE, &active_str)
510 != 0) {
511 return (B_FALSE);
514 if (strcmp(active_str, "on") == 0)
515 return (B_TRUE);
517 return (B_FALSE);