dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libbe / common / be_zones.c
blob047fb899cea6091dde1ef85e201591a2fd9ea4ef
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.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
34 * System includes
36 #include <assert.h>
37 #include <errno.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/mntent.h>
45 #include <sys/mnttab.h>
46 #include <sys/mount.h>
47 #include <sys/stat.h>
48 #include <sys/types.h>
49 #include <sys/vfstab.h>
50 #include <unistd.h>
52 #include <libbe.h>
53 #include <libbe_priv.h>
55 typedef struct active_zone_root_data {
56 uuid_t parent_uuid;
57 char *zoneroot_ds;
58 } active_zone_root_data_t;
60 typedef struct mounted_zone_root_data {
61 char *zone_altroot;
62 char *zoneroot_ds;
63 } mounted_zone_root_data_t;
65 /* Private function prototypes */
66 static int be_find_active_zone_root_callback(zfs_handle_t *, void *);
67 static int be_find_mounted_zone_root_callback(zfs_handle_t *, void *);
68 static boolean_t be_zone_get_active(zfs_handle_t *);
71 /* ******************************************************************** */
72 /* Semi-Private Functions */
73 /* ******************************************************************** */
76 * Function: be_make_zoneroot
77 * Description: Generate a string for a zone's zoneroot given the
78 * zone's zonepath.
79 * Parameters:
80 * zonepath - pointer to zonepath
81 * zoneroot - pointer to buffer to retrn zoneroot in.
82 * zoneroot_size - size of zoneroot
83 * Returns:
84 * None
85 * Scope:
86 * Semi-private (library wise use only)
88 void
89 be_make_zoneroot(char *zonepath, char *zoneroot, int zoneroot_size)
91 (void) snprintf(zoneroot, zoneroot_size, "%s/root", zonepath);
95 * Function: be_find_active_zone_root
96 * Description: This function will find the active zone root of a zone for
97 * a given global BE. It will iterate all of the zone roots
98 * under a zonepath, find the zone roots that belong to the
99 * specified global BE, and return the one that is active.
100 * Parameters:
101 * be_zhp - zfs handle to global BE root dataset.
102 * zonepath_ds - pointer to zone's zonepath dataset.
103 * zoneroot_ds - pointer to a buffer to store the dataset name of
104 * the zone's zoneroot that's currently active for this
105 * given global BE..
106 * zoneroot-ds_size - size of zoneroot_ds.
107 * Returns:
108 * BE_SUCCESS - Success
109 * be_errno_t - Failure
110 * Scope:
111 * Semi-private (library wide use only)
114 be_find_active_zone_root(zfs_handle_t *be_zhp, char *zonepath_ds,
115 char *zoneroot_ds, int zoneroot_ds_size)
117 active_zone_root_data_t azr_data = { { 0 }, NULL };
118 zfs_handle_t *zhp;
119 char zone_container_ds[MAXPATHLEN];
120 int ret = BE_SUCCESS;
122 /* Get the uuid of the parent global BE */
123 if (getzoneid() == GLOBAL_ZONEID) {
124 if ((ret = be_get_uuid(zfs_get_name(be_zhp),
125 &azr_data.parent_uuid)) != BE_SUCCESS) {
126 be_print_err(gettext("be_find_active_zone_root: failed "
127 "to get uuid for BE root dataset %s\n"),
128 zfs_get_name(be_zhp));
129 return (ret);
131 } else {
132 if ((ret = be_zone_get_parent_uuid(zfs_get_name(be_zhp),
133 &azr_data.parent_uuid)) != BE_SUCCESS) {
134 be_print_err(gettext("be_find_active_zone_root: failed "
135 "to get parentbe uuid for zone root dataset %s\n"),
136 zfs_get_name(be_zhp));
137 return (ret);
141 /* Generate string for the root container dataset for this zone. */
142 be_make_container_ds(zonepath_ds, zone_container_ds,
143 sizeof (zone_container_ds));
145 /* Get handle to this zone's root container dataset */
146 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
147 == NULL) {
148 be_print_err(gettext("be_find_active_zone_root: failed to "
149 "open zone root container dataset (%s): %s\n"),
150 zone_container_ds, libzfs_error_description(g_zfs));
151 return (zfs_err_to_be_err(g_zfs));
155 * Iterate through all of this zone's BEs, looking for ones
156 * that belong to the parent global BE, and finding the one
157 * that is marked active.
159 if ((ret = zfs_iter_filesystems(zhp, be_find_active_zone_root_callback,
160 &azr_data)) != 0) {
161 be_print_err(gettext("be_find_active_zone_root: failed to "
162 "find active zone root in zonepath dataset %s: %s\n"),
163 zonepath_ds, be_err_to_str(ret));
164 goto done;
167 if (azr_data.zoneroot_ds != NULL) {
168 (void) strlcpy(zoneroot_ds, azr_data.zoneroot_ds,
169 zoneroot_ds_size);
170 free(azr_data.zoneroot_ds);
171 } else {
172 be_print_err(gettext("be_find_active_zone_root: failed to "
173 "find active zone root in zonepath dataset %s\n"),
174 zonepath_ds);
175 ret = BE_ERR_ZONE_NO_ACTIVE_ROOT;
178 done:
179 ZFS_CLOSE(zhp);
180 return (ret);
184 * Function: be_find_mounted_zone_root
185 * Description: This function will find the dataset mounted as the zoneroot
186 * of a zone for a given mounted global BE.
187 * Parameters:
188 * zone_altroot - path of zoneroot wrt the mounted global BE.
189 * zonepath_ds - dataset of the zone's zonepath.
190 * zoneroot_ds - pointer to a buffer to store the dataset of
191 * the zoneroot that currently mounted for this zone
192 * in the mounted global BE.
193 * zoneroot_ds_size - size of zoneroot_ds
194 * Returns:
195 * BE_SUCCESS - Success
196 * be_errno_t - Failure
197 * Scope:
198 * Semi-private (library wide use only)
201 be_find_mounted_zone_root(char *zone_altroot, char *zonepath_ds,
202 char *zoneroot_ds, int zoneroot_ds_size)
204 mounted_zone_root_data_t mzr_data = { 0 };
205 zfs_handle_t *zhp = NULL;
206 char zone_container_ds[MAXPATHLEN];
207 int ret = BE_SUCCESS;
208 int zret = 0;
210 /* Generate string for the root container dataset for this zone. */
211 be_make_container_ds(zonepath_ds, zone_container_ds,
212 sizeof (zone_container_ds));
214 /* Get handle to this zone's root container dataset. */
215 if ((zhp = zfs_open(g_zfs, zone_container_ds, ZFS_TYPE_FILESYSTEM))
216 == NULL) {
217 be_print_err(gettext("be_find_mounted_zone_root: failed to "
218 "open zone root container dataset (%s): %s\n"),
219 zone_container_ds, libzfs_error_description(g_zfs));
220 return (zfs_err_to_be_err(g_zfs));
223 mzr_data.zone_altroot = zone_altroot;
226 * Iterate through all of the zone's BEs, looking for the one
227 * that is currently mounted at the zone altroot in the mounted
228 * global BE.
230 if ((zret = zfs_iter_filesystems(zhp,
231 be_find_mounted_zone_root_callback, &mzr_data)) == 0) {
232 be_print_err(gettext("be_find_mounted_zone_root: did not "
233 "find mounted zone under altroot zonepath %s\n"),
234 zonepath_ds);
235 ret = BE_ERR_NO_MOUNTED_ZONE;
236 goto done;
237 } else if (zret < 0) {
238 be_print_err(gettext("be_find_mounted_zone_root: "
239 "zfs_iter_filesystems failed: %s\n"),
240 libzfs_error_description(g_zfs));
241 ret = zfs_err_to_be_err(g_zfs);
242 goto done;
245 if (mzr_data.zoneroot_ds != NULL) {
246 (void) strlcpy(zoneroot_ds, mzr_data.zoneroot_ds,
247 zoneroot_ds_size);
248 free(mzr_data.zoneroot_ds);
251 done:
252 ZFS_CLOSE(zhp);
253 return (ret);
257 * Function: be_zone_supported
258 * Description: This function will determine if a zone is supported
259 * based on its zonepath dataset. The zonepath dataset
260 * must:
261 * - not be under any global BE root dataset.
262 * - have a root container dataset underneath it.
264 * Parameters:
265 * zonepath_ds - name of dataset of the zonepath of the
266 * zone to check.
267 * Returns:
268 * B_TRUE - zone is supported
269 * B_FALSE - zone is not supported
270 * Scope:
271 * Semi-private (library wide use only)
273 boolean_t
274 be_zone_supported(char *zonepath_ds)
276 char zone_container_ds[MAXPATHLEN];
277 int ret = 0;
280 * Make sure the dataset for the zonepath is not hierarchically
281 * under any reserved BE root container dataset of any pool.
283 if ((ret = zpool_iter(g_zfs, be_check_be_roots_callback,
284 zonepath_ds)) > 0) {
285 be_print_err(gettext("be_zone_supported: "
286 "zonepath dataset %s not supported\n"), zonepath_ds);
287 return (B_FALSE);
288 } else if (ret < 0) {
289 be_print_err(gettext("be_zone_supported: "
290 "zpool_iter failed: %s\n"),
291 libzfs_error_description(g_zfs));
292 return (B_FALSE);
296 * Make sure the zonepath has a zone root container dataset
297 * underneath it.
299 be_make_container_ds(zonepath_ds, zone_container_ds,
300 sizeof (zone_container_ds));
302 if (!zfs_dataset_exists(g_zfs, zone_container_ds,
303 ZFS_TYPE_FILESYSTEM)) {
304 be_print_err(gettext("be_zone_supported: "
305 "zonepath dataset (%s) does not have a zone root container "
306 "dataset, zone is not supported, skipping ...\n"),
307 zonepath_ds);
308 return (B_FALSE);
311 return (B_TRUE);
315 * Function: be_zone_get_parent_uuid
316 * Description: This function gets the parentbe property of a zone root
317 * dataset, parsed it into internal uuid format, and returns
318 * it in the uuid_t reference pointer passed in.
319 * Parameters:
320 * root_ds - dataset name of a zone root dataset
321 * uu - pointer to a uuid_t to return the parentbe uuid in
322 * Returns:
323 * BE_SUCCESS - Success
324 * be_errno_t - Failure
325 * Scope:
326 * Private
329 be_zone_get_parent_uuid(const char *root_ds, uuid_t *uu)
331 zfs_handle_t *zhp = NULL;
332 nvlist_t *userprops = NULL;
333 nvlist_t *propname = NULL;
334 char *uu_string = NULL;
335 int ret = BE_SUCCESS;
337 /* Get handle to zone root dataset */
338 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
339 be_print_err(gettext("be_zone_get_parent_uuid: failed to "
340 "open zone root dataset (%s): %s\n"), root_ds,
341 libzfs_error_description(g_zfs));
342 return (zfs_err_to_be_err(g_zfs));
345 /* Get user properties for zone root dataset */
346 if ((userprops = zfs_get_user_props(zhp)) == NULL) {
347 be_print_err(gettext("be_zone_get_parent_uuid: "
348 "failed to get user properties for zone root "
349 "dataset (%s): %s\n"), root_ds,
350 libzfs_error_description(g_zfs));
351 ret = zfs_err_to_be_err(g_zfs);
352 goto done;
355 /* Get UUID string from zone's root dataset user properties */
356 if (nvlist_lookup_nvlist(userprops, BE_ZONE_PARENTBE_PROPERTY,
357 &propname) != 0 || nvlist_lookup_string(propname, ZPROP_VALUE,
358 &uu_string) != 0) {
359 be_print_err(gettext("be_zone_get_parent_uuid: failed to "
360 "get parent uuid property from zone root dataset user "
361 "properties.\n"));
362 ret = BE_ERR_ZONE_NO_PARENTBE;
363 goto done;
366 /* Parse the uuid string into internal format */
367 if (uuid_parse(uu_string, *uu) != 0 || uuid_is_null(*uu)) {
368 be_print_err(gettext("be_zone_get_parent_uuid: failed to "
369 "parse parentuuid\n"));
370 ret = BE_ERR_PARSE_UUID;
373 done:
374 ZFS_CLOSE(zhp);
375 return (ret);
379 * Function: be_zone_set_parent_uuid
380 * Description: This function sets parentbe uuid into
381 * a zfs user property for a root zone dataset.
382 * Parameters:
383 * root_ds - Root zone dataset of the BE to set a uuid on.
384 * Return:
385 * be_errno_t - Failure
386 * BE_SUCCESS - Success
387 * Scope:
388 * Semi-private (library wide uses only)
391 be_zone_set_parent_uuid(char *root_ds, uuid_t uu)
393 zfs_handle_t *zhp = NULL;
394 char uu_string[UUID_PRINTABLE_STRING_LENGTH];
395 int ret = BE_SUCCESS;
397 uuid_unparse(uu, uu_string);
399 /* Get handle to the root zone dataset. */
400 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
401 be_print_err(gettext("be_zone_set_parent_uuid: failed to "
402 "open root zone dataset (%s): %s\n"), root_ds,
403 libzfs_error_description(g_zfs));
404 return (zfs_err_to_be_err(g_zfs));
407 /* Set parentbe uuid property for the root zone dataset */
408 if (zfs_prop_set(zhp, BE_ZONE_PARENTBE_PROPERTY, uu_string) != 0) {
409 be_print_err(gettext("be_zone_set_parent_uuid: failed to "
410 "set parentbe uuid property for root zone dataset: %s\n"),
411 libzfs_error_description(g_zfs));
412 ret = zfs_err_to_be_err(g_zfs);
415 ZFS_CLOSE(zhp);
416 return (ret);
420 * Function: be_zone_compare_uuids
421 * Description: This function compare the parentbe uuid of the
422 * current running root zone dataset with the parentbe
423 * uuid of the given root zone dataset.
424 * Parameters:
425 * root_ds - Root zone dataset of the BE to compare.
426 * Return:
427 * B_TRUE - root dataset has right parentbe uuid
428 * B_FALSE - root dataset has wrong parentbe uuid
429 * Scope:
430 * Semi-private (library wide uses only)
432 boolean_t
433 be_zone_compare_uuids(char *root_ds)
435 char *active_ds;
436 uuid_t parent_uuid = {0};
437 uuid_t cur_parent_uuid = {0};
439 /* Get parentbe uuid from given zone root dataset */
440 if ((be_zone_get_parent_uuid(root_ds,
441 &parent_uuid)) != BE_SUCCESS) {
442 be_print_err(gettext("be_zone_compare_uuids: failed to get "
443 "parentbe uuid from the given BE\n"));
444 return (B_FALSE);
448 * Find current running zone root dataset and get it's parentbe
449 * uuid property.
451 if ((active_ds = be_get_ds_from_dir("/")) != NULL) {
452 if ((be_zone_get_parent_uuid(active_ds,
453 &cur_parent_uuid)) != BE_SUCCESS) {
454 be_print_err(gettext("be_zone_compare_uuids: failed "
455 "to get parentbe uuid from the current running zone "
456 "root dataset\n"));
457 return (B_FALSE);
459 } else {
460 be_print_err(gettext("be_zone_compare_uuids: zone root dataset "
461 "is not mounted\n"));
462 return (B_FALSE);
465 if (uuid_compare(parent_uuid, cur_parent_uuid) != 0) {
466 return (B_FALSE);
469 return (B_TRUE);
472 /* ******************************************************************** */
473 /* Private Functions */
474 /* ******************************************************************** */
477 * Function: be_find_active_zone_root_callback
478 * Description: This function is used as a callback to iterate over all of
479 * a zone's root datasets, finding the one that is marked active
480 * for the parent BE specified in the data passed in. The name
481 * of the zone's active root dataset is returned in heap storage
482 * in the active_zone_root_data_t structure passed in, so the
483 * caller is responsible for freeing it.
484 * Parameters:
485 * zhp - zfs_handle_t pointer to current dataset being processed
486 * data - active_zone_root_data_t pointer
487 * Returns:
488 * 0 - Success
489 * >0 - Failure
490 * Scope:
491 * Private
493 static int
494 be_find_active_zone_root_callback(zfs_handle_t *zhp, void *data)
496 active_zone_root_data_t *azr_data = data;
497 uuid_t parent_uuid = { 0 };
498 int iret = 0;
499 int ret = 0;
501 if ((iret = be_zone_get_parent_uuid(zfs_get_name(zhp), &parent_uuid))
502 != BE_SUCCESS) {
503 be_print_err(gettext("be_find_active_zone_root_callback: "
504 "skipping zone root dataset (%s): %s\n"),
505 zfs_get_name(zhp), be_err_to_str(iret));
506 goto done;
509 if (uuid_compare(azr_data->parent_uuid, parent_uuid) == 0) {
511 * Found a zone root dataset belonging to the right parent,
512 * check if its active.
514 if (be_zone_get_active(zhp)) {
516 * Found active zone root dataset, if its already
517 * set in the callback data, that means this
518 * is the second one we've found. Return error.
520 if (azr_data->zoneroot_ds != NULL) {
521 ret = BE_ERR_ZONE_MULTIPLE_ACTIVE;
522 goto done;
525 azr_data->zoneroot_ds = strdup(zfs_get_name(zhp));
526 if (azr_data->zoneroot_ds == NULL) {
527 ret = BE_ERR_NOMEM;
532 done:
533 ZFS_CLOSE(zhp);
534 return (ret);
538 * Function: be_find_mounted_zone_root_callback
539 * Description: This function is used as a callback to iterate over all of
540 * a zone's root datasets, find the one that is currently
541 * mounted for the parent BE specified in the data passed in.
542 * The name of the zone's mounted root dataset is returned in
543 * heap storage the mounted_zone_data_t structure passed in,
544 * so the caller is responsible for freeing it.
545 * Parameters:
546 * zhp - zfs_handle_t pointer to the current dataset being
547 * processed
548 * data - mounted_zone_data_t pointer
549 * Returns:
550 * 0 - not mounted as zone's root
551 * 1 - this dataset is mounted as zone's root
552 * Scope:
553 * Private
555 static int
556 be_find_mounted_zone_root_callback(zfs_handle_t *zhp, void *data)
558 mounted_zone_root_data_t *mzr_data = data;
559 char *mp = NULL;
561 if (zfs_is_mounted(zhp, &mp) && mp != NULL &&
562 strcmp(mp, mzr_data->zone_altroot) == 0) {
563 mzr_data->zoneroot_ds = strdup(zfs_get_name(zhp));
564 free(mp);
565 return (1);
568 free(mp);
569 return (0);
573 * Function: be_zone_get_active
574 * Description: This function gets the active property of a zone root
575 * dataset, and returns true if active property is on.
576 * Parameters:
577 * zfs - zfs_handle_t pointer to zone root dataset to check
578 * Returns:
579 * B_TRUE - zone root dataset is active
580 * B_FALSE - zone root dataset is not active
581 * Scope:
582 * Private
584 static boolean_t
585 be_zone_get_active(zfs_handle_t *zhp)
587 nvlist_t *userprops = NULL;
588 nvlist_t *propname = NULL;
589 char *active_str = NULL;
591 /* Get user properties for the zone root dataset */
592 if ((userprops = zfs_get_user_props(zhp)) == NULL) {
593 be_print_err(gettext("be_zone_get_active: "
594 "failed to get user properties for zone root "
595 "dataset (%s): %s\n"), zfs_get_name(zhp),
596 libzfs_error_description(g_zfs));
597 return (B_FALSE);
600 /* Get active property from the zone root dataset user properties */
601 if (nvlist_lookup_nvlist(userprops, BE_ZONE_ACTIVE_PROPERTY, &propname)
602 != 0 || nvlist_lookup_string(propname, ZPROP_VALUE, &active_str)
603 != 0) {
604 return (B_FALSE);
607 if (strcmp(active_str, "on") == 0)
608 return (B_TRUE);
610 return (B_FALSE);