0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * CDDL HEADER START
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * The contents of this file are subject to the terms of the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Common Development and Distribution License (the "License").
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * You may not use this file except in compliance with the License.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * or http://www.opensolaris.org/os/licensing.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * See the License for the specific language governing permissions
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * and limitations under the License.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * When distributing Covered Code, include this CDDL HEADER in each
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * If applicable, add the following below this CDDL HEADER, with the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * fields enclosed by brackets "[]" replaced with your own identifying
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * information: Portions Copyright [yyyy] [name of copyright owner]
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * CDDL HEADER END
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
dd9c3b29f8e9f6b99b80e1fd8fc03241abd67311Jerry Jelinek * Copyright (c) 2012, Joyent, Inc. All rights reserved.
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska * Copyright (c) 2016 Martin Matuska. All rights reserved.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * This file contains the functions used to support the ZFS integration
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * with zones. This includes validation (e.g. zonecfg dataset), cloning,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * file system creation and destruction.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <stdio.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <errno.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <unistd.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <string.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <locale.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <libintl.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <sys/stat.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <sys/statvfs.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <libgen.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <libzonecfg.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <sys/mnttab.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include <libzfs.h>
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek#include <sys/mntent.h>
286822dd6ee35fa0959e7b55e659b92ea1c12f71#include <values.h>
0094b373ead542a342e4250eaf37854ccd3e50c0jv#include <strings.h>
0094b373ead542a342e4250eaf37854ccd3e50c0jv#include <assert.h>
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek#include "zoneadm.h"
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
99653d4ee642c6528e88224f12409a5f23060994eschrocklibzfs_handle_t *g_zfs;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinektypedef struct zfs_mount_data {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char *match_name;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *match_handle;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek} zfs_mount_data_t;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinektypedef struct zfs_snapshot_data {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 char *match_name; /* zonename@SUNWzone */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 int len; /* strlen of match_name */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 int max; /* highest digit appended to snap name */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 int num; /* number of snapshots to rename */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 int cntr; /* counter for renaming snapshots */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek} zfs_snapshot_data_t;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
286822dd6ee35fa0959e7b55e659b92ea1c12f71typedef struct clone_data {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_handle_t *clone_zhp; /* clone dataset to promote */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 time_t origin_creation; /* snapshot creation time of clone */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 const char *snapshot; /* snapshot of dataset being demoted */
286822dd6ee35fa0959e7b55e659b92ea1c12f71} clone_data_t;
286822dd6ee35fa0959e7b55e659b92ea1c12f71
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * A ZFS file system iterator call-back function which returns the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * zfs_handle_t for a ZFS file system on the specified mount point.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekmatch_mountpoint(zfs_handle_t *zhp, void *data)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int res;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_mount_data_t *cbp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char mp[ZFS_MAXPROPLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (0);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek /* First check if the dataset is mounted. */
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL,
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek 0, B_FALSE) != 0 || strcmp(mp, "no") == 0) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek zfs_close(zhp);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek return (0);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek /* Now check mount point. */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek 0, B_FALSE) != 0) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek zfs_close(zhp);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek return (0);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek cbp = (zfs_mount_data_t *)data;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if (strcmp(mp, "legacy") == 0) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek /* If legacy, must look in mnttab for mountpoint. */
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek FILE *fp;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek struct mnttab entry;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek const char *nm;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek nm = zfs_get_name(zhp);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if ((fp = fopen(MNTTAB, "r")) == NULL) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek zfs_close(zhp);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek return (0);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek while (getmntent(fp, &entry) == 0) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if (strcmp(nm, entry.mnt_special) == 0) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if (strcmp(entry.mnt_mountp, cbp->match_name)
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek == 0) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek (void) fclose(fp);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek cbp->match_handle = zhp;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek return (1);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek break;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek (void) fclose(fp);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek } else if (strcmp(mp, cbp->match_name) == 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cbp->match_handle = zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (1);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek /* Iterate over any nested datasets. */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek res = zfs_iter_filesystems(zhp, match_mountpoint, data);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (res);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Get ZFS handle for the specified mount point.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic zfs_handle_t *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekmount2zhandle(char *mountpoint)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_mount_data_t cb;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cb.match_name = mountpoint;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cb.match_handle = NULL;
99653d4ee642c6528e88224f12409a5f23060994eschrock (void) zfs_iter_root(g_zfs, match_mountpoint, &cb);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (cb.match_handle);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Check if there is already a file system (zfs or any other type) mounted on
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * path.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic boolean_t
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekis_mountpnt(char *path)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek FILE *fp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek struct mnttab entry;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if ((fp = fopen(MNTTAB, "r")) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek while (getmntent(fp, &entry) == 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (strcmp(path, entry.mnt_mountp) == 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fclose(fp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_TRUE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fclose(fp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
ff17c8bf86c3e567734be83f90267edee20f580fgjelinekpre_snapshot(char *presnapbuf)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek int status;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek /* No brand-specific handler */
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (presnapbuf[0] == '\0')
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek /* Run the hook */
c75cc341903ca38e644edfae5357a4020418f9be status = do_subproc(presnapbuf);
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if ((status = subproc_status(gettext("brand-specific presnapshot"),
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
ff17c8bf86c3e567734be83f90267edee20f580fgjelinekpost_snapshot(char *postsnapbuf)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek int status;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek /* No brand-specific handler */
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (postsnapbuf[0] == '\0')
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek /* Run the hook */
c75cc341903ca38e644edfae5357a4020418f9be status = do_subproc(postsnapbuf);
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if ((status = subproc_status(gettext("brand-specific postsnapshot"),
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * This is a ZFS snapshot iterator call-back function which returns the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * highest number of SUNWzone snapshots that have been taken.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekget_snap_max(zfs_handle_t *zhp, void *data)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int res;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_snapshot_data_t *cbp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (0);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cbp = (zfs_snapshot_data_t *)data;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char *nump;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int num;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cbp->num++;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek nump = (char *)(zfs_get_name(zhp) + cbp->len);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek num = atoi(nump);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (num > cbp->max)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cbp->max = num;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska res = zfs_iter_snapshots(zhp, B_FALSE, get_snap_max, data);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (res);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Take a ZFS snapshot to be used for cloning the zone.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
ff17c8bf86c3e567734be83f90267edee20f580fgjelinektake_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size,
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek char *presnapbuf, char *postsnapbuf)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int res;
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char template[ZFS_MAX_DATASET_NAME_LEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_snapshot_data_t cb;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * First we need to figure out the next available name for the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * zone snapshot. Look through the list of zones snapshots for
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * this file system to determine the maximum snapshot name.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (snprintf(template, sizeof (template), "%s@SUNWzone",
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_get_name(zhp)) >= sizeof (template))
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cb.match_name = template;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cb.len = strlen(template);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cb.max = 0;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska if (zfs_iter_snapshots(zhp, B_FALSE, get_snap_max, &cb) != 0)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek cb.max++;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_get_name(zhp), cb.max) >= snap_size)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (pre_snapshot(presnapbuf) != Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
bb0ade0978a02d3fe0b0165cd4725fdcb593fbfbahrens res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL);
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (post_snapshot(postsnapbuf) != Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (res != 0)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * We are using an explicit snapshot from some earlier point in time so
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek * we need to validate it. Run the brand specific hook.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
ff17c8bf86c3e567734be83f90267edee20f580fgjelinekvalidate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek int status;
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek char cmdbuf[MAXPATHLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek /* No brand-specific handler */
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (validsnapbuf[0] == '\0')
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek /* pass args - snapshot_name & snap_path */
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf,
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek snapshot_name, snap_path) >= sizeof (cmdbuf)) {
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek zerror("Command line too long");
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek /* Run the hook */
c75cc341903ca38e644edfae5357a4020418f9be status = do_subproc(cmdbuf);
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if ((status = subproc_status(gettext("brand-specific validatesnapshot"),
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek status, B_FALSE)) != ZONE_SUBPROC_OK)
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Remove the sw inventory file from inside this zonepath that we picked up out
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * of the snapshot.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekclean_out_clone()
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int err;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zone_dochandle_t handle;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((handle = zonecfg_init_handle()) == NULL) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek errno = err;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zperror(cmd_to_str(CMD_CLONE), B_TRUE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zonecfg_fini_handle(handle);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zonecfg_rm_detached(handle, B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zonecfg_fini_handle(handle);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Make a ZFS clone on zonepath from snapshot_name.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekclone_snap(char *snapshot_name, char *zonepath)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int res = Z_OK;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int err;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *clone;
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock nvlist_t *props = NULL;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
99653d4ee642c6528e88224f12409a5f23060994eschrock if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_NO_ENTRY);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul /*
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul * We turn off zfs SHARENFS and SHARESMB properties on the
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul * zoneroot dataset in order to prevent the GZ from sharing
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul * NGZ data by accident.
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul */
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul if ((nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) ||
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul "off") != 0) ||
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARESMB),
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul "off") != 0)) {
aab83bb83be7342f6cfccaed8d5fe0b2f404855dJosef 'Jeff' Sipek nvlist_free(props);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock (void) fprintf(stderr, gettext("could not create ZFS clone "
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock "%s: out of memory\n"), zonepath);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock return (Z_ERR);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock }
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock err = zfs_clone(zhp, zonepath, props);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock nvlist_free(props);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (err != 0)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /* create the mountpoint if necessary */
990b4856d0eaada6f8140335733a1b1771ed2746lling if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * The clone has been created so we need to print a diagnostic
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * message if one of the following steps fails for some reason.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_mount(clone, NULL, 0) != 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("could not mount ZFS clone "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "%s\n"), zfs_get_name(clone));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek res = Z_ERR;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock } else if (clean_out_clone() != Z_OK) {
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock (void) fprintf(stderr, gettext("could not remove the "
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock "software inventory from ZFS clone %s\n"),
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock zfs_get_name(clone));
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock res = Z_ERR;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(clone);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (res);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * This function takes a zonepath and attempts to determine what the ZFS
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * file system name (not mountpoint) should be for that path. We do not
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * assume that zonepath is an existing directory or ZFS fs since we use
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * this function as part of the process of creating a new ZFS fs or clone.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * The way this works is that we look at the parent directory of the zonepath
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * append the last component of the zonepath to generate the ZFS name for the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * zonepath. This matches the algorithm that ZFS uses for automatically
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * mounting a new fs after it is created.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Although a ZFS fs can be mounted anywhere, we don't worry about handling
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * all of the complexity that a user could possibly configure with arbitrary
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * mounts since there is no way to generate a ZFS name from a random path in
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * the file system. We only try to handle the automatic mounts that ZFS does
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * for each file system. ZFS restricts this so that a new fs must be created
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * in an existing parent ZFS fs. It then automatically mounts the new fs
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * directly under the mountpoint for the parent fs using the last component
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * of the name as the mountpoint directory.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * For example:
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Name Mountpoint
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Z_ERR.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekpath2name(char *zonepath, char *zfs_name, int len)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int res;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek char *bnm, *dnm, *dname, *bname;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek struct stat stbuf;
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek /*
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek * We need two tmp strings to handle paths directly in / (e.g. /foo)
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek * since dirname will overwrite the first char after "/" in this case.
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek */
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if ((bnm = strdup(zonepath)) == NULL)
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if ((dnm = strdup(zonepath)) == NULL) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek free(bnm);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek bname = basename(bnm);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek dname = dirname(dnm);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek * This is a quick test to save iterating over all of the zfs datasets
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek * on the system (which can be a lot). If the parent dir is not in a
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek * ZFS fs, then we're done.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) ||
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek free(bnm);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek free(dnm);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek /* See if the parent directory is its own ZFS dataset. */
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek if ((zhp = mount2zhandle(dname)) == NULL) {
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek /*
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek * The parent is not a ZFS dataset so we can't automatically
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek * create a dataset on the given path.
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek */
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek free(bnm);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek free(dnm);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek return (Z_ERR);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek free(bnm);
11506c4105b984bf64636b0e2f9e88bd67fb9651gjelinek free(dnm);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (res >= len)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * A ZFS file system iterator call-back function used to determine if the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * file system has dependents (snapshots & clones).
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/* ARGSUSED */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekhas_dependent(zfs_handle_t *zhp, void *data)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (1);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Given a snapshot name, get the file system path where the snapshot lives.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * A snapshot name is of the form fs_name@snap_name. For example, snapshot
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * pl/zones/z1@SUNWzone1 would have a path of
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekstatic int
0b5de56d26c0148ad33bb3a9201091502f24d910gjelineksnap2path(char *snap_name, char *path, int len)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char *p;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char mp[ZFS_MAXPROPLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((p = strrchr(snap_name, '@')) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /* Get the file system name from the snap_name. */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *p = '\0';
990b4856d0eaada6f8140335733a1b1771ed2746lling zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *p = '@';
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zhp == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /* Get the file system mount point. */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
99653d4ee642c6528e88224f12409a5f23060994eschrock 0, B_FALSE) != 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek p++;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
286822dd6ee35fa0959e7b55e659b92ea1c12f71/*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * This callback function is used to iterate through a snapshot's dependencies
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * to find a filesystem that is a direct clone of the snapshot being iterated.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71static int
286822dd6ee35fa0959e7b55e659b92ea1c12f71get_direct_clone(zfs_handle_t *zhp, void *data)
286822dd6ee35fa0959e7b55e659b92ea1c12f71{
286822dd6ee35fa0959e7b55e659b92ea1c12f71 clone_data_t *cd = data;
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char origin[ZFS_MAX_DATASET_NAME_LEN];
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char ds_path[ZFS_MAX_DATASET_NAME_LEN];
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* Make sure this is a direct clone of the snapshot we're iterating. */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
286822dd6ee35fa0959e7b55e659b92ea1c12f71 NULL, 0, B_FALSE) != 0 || strcmp(origin, cd->snapshot) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (cd->clone_zhp != NULL)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(cd->clone_zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cd->clone_zhp = zhp;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (1);
286822dd6ee35fa0959e7b55e659b92ea1c12f71}
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71/*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * A ZFS file system iterator call-back function used to determine the clone
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * to promote. This function finds the youngest (i.e. last one taken) snapshot
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * that has a clone. If found, it returns a reference to that clone in the
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * callback data.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71static int
286822dd6ee35fa0959e7b55e659b92ea1c12f71find_clone(zfs_handle_t *zhp, void *data)
286822dd6ee35fa0959e7b55e659b92ea1c12f71{
286822dd6ee35fa0959e7b55e659b92ea1c12f71 clone_data_t *cd = data;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 time_t snap_creation;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 int zret = 0;
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* If snapshot has no clones, skip it */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cd->snapshot = zfs_get_name(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* Get the creation time of this snapshot */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * If this snapshot's creation time is greater than (i.e. younger than)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * the current youngest snapshot found, iterate this snapshot to
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * get the right clone.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (snap_creation >= cd->origin_creation) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * Iterate the dependents of this snapshot to find a clone
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * that's a direct dependent.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if ((zret = zfs_iter_dependents(zhp, B_FALSE, get_direct_clone,
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cd)) == -1) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (1);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 } else if (zret == 1) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * Found a clone, update the origin_creation time
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * in the callback data.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cd->origin_creation = snap_creation;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71}
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71/*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * A ZFS file system iterator call-back function used to remove standalone
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * snapshots.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71/* ARGSUSED */
286822dd6ee35fa0959e7b55e659b92ea1c12f71static int
286822dd6ee35fa0959e7b55e659b92ea1c12f71rm_snap(zfs_handle_t *zhp, void *data)
286822dd6ee35fa0959e7b55e659b92ea1c12f71{
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* If snapshot has clones, something is wrong */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (1);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_unmount(zhp, NULL, 0) == 0) {
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby (void) zfs_destroy(zhp, B_FALSE);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71}
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71/*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * A ZFS snapshot iterator call-back function which renames snapshots.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71static int
286822dd6ee35fa0959e7b55e659b92ea1c12f71rename_snap(zfs_handle_t *zhp, void *data)
286822dd6ee35fa0959e7b55e659b92ea1c12f71{
286822dd6ee35fa0959e7b55e659b92ea1c12f71 int res;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_snapshot_data_t *cbp;
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char template[ZFS_MAX_DATASET_NAME_LEN];
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cbp = (zfs_snapshot_data_t *)data;
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * When renaming snapshots with the iterator, the iterator can see
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * the same snapshot after we've renamed up in the namespace. To
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * prevent this we check the count for the number of snapshots we have
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * to rename and stop at that point.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (cbp->cntr >= cbp->num) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* Only rename the snapshots we automatically generate when we clone. */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) snprintf(template, sizeof (template), "%s%d", cbp->match_name,
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cbp->max++);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
6a9cb0ea17f11529b1bb8ca31944abd37736b99eEric Schrock res = (zfs_rename(zhp, template, B_FALSE, B_FALSE) != 0);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (res != 0)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) fprintf(stderr, gettext("failed to rename snapshot %s "
286822dd6ee35fa0959e7b55e659b92ea1c12f71 "to %s: %s\n"), zfs_get_name(zhp), template,
286822dd6ee35fa0959e7b55e659b92ea1c12f71 libzfs_error_description(g_zfs));
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cbp->cntr++;
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (res);
286822dd6ee35fa0959e7b55e659b92ea1c12f71}
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71/*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * Rename the source dataset's snapshots that are automatically generated when
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * we clone a zone so that there won't be a name collision when we promote the
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * cloned dataset. Once the snapshots have been renamed, then promote the
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * clone.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 *
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * The snapshot rename process gets the highest number on the snapshot names
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * (the format is zonename@SUNWzoneXX where XX are digits) on both the source
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * and clone datasets, then renames the source dataset snapshots starting at
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * the next number.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71static int
286822dd6ee35fa0959e7b55e659b92ea1c12f71promote_clone(zfs_handle_t *src_zhp, zfs_handle_t *cln_zhp)
286822dd6ee35fa0959e7b55e659b92ea1c12f71{
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_snapshot_data_t sd;
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char nm[ZFS_MAX_DATASET_NAME_LEN];
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char template[ZFS_MAX_DATASET_NAME_LEN];
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) strlcpy(nm, zfs_get_name(cln_zhp), sizeof (nm));
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * Start by getting the clone's snapshot max which we use
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * during the rename of the original dataset's snapshots.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) snprintf(template, sizeof (template), "%s@SUNWzone", nm);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.match_name = template;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.len = strlen(template);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.max = 0;
286822dd6ee35fa0959e7b55e659b92ea1c12f71
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska if (zfs_iter_snapshots(cln_zhp, B_FALSE, get_snap_max, &sd) != 0)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * Now make sure the source's snapshot max is at least as high as
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * the clone's snapshot max.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) snprintf(template, sizeof (template), "%s@SUNWzone",
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_get_name(src_zhp));
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.match_name = template;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.len = strlen(template);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.num = 0;
286822dd6ee35fa0959e7b55e659b92ea1c12f71
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska if (zfs_iter_snapshots(src_zhp, B_FALSE, get_snap_max, &sd) != 0)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * Now rename the source dataset's snapshots so there's no
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * conflict when we promote the clone.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.max++;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 sd.cntr = 0;
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska if (zfs_iter_snapshots(src_zhp, B_FALSE, rename_snap, &sd) != 0)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* close and reopen the clone dataset to get the latest info */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(cln_zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if ((cln_zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_promote(cln_zhp) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) fprintf(stderr, gettext("failed to promote %s: %s\n"),
286822dd6ee35fa0959e7b55e659b92ea1c12f71 nm, libzfs_error_description(g_zfs));
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(cln_zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_OK);
286822dd6ee35fa0959e7b55e659b92ea1c12f71}
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71/*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * Promote the youngest clone. That clone will then become the origin of all
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * of the other clones that were hanging off of the source dataset.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 */
286822dd6ee35fa0959e7b55e659b92ea1c12f71int
286822dd6ee35fa0959e7b55e659b92ea1c12f71promote_all_clones(zfs_handle_t *zhp)
286822dd6ee35fa0959e7b55e659b92ea1c12f71{
286822dd6ee35fa0959e7b55e659b92ea1c12f71 clone_data_t cd;
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char nm[ZFS_MAX_DATASET_NAME_LEN];
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cd.clone_zhp = NULL;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cd.origin_creation = 0;
286822dd6ee35fa0959e7b55e659b92ea1c12f71 cd.snapshot = NULL;
286822dd6ee35fa0959e7b55e659b92ea1c12f71
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska if (zfs_iter_snapshots(zhp, B_FALSE, find_clone, &cd) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* Nothing to promote. */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (cd.clone_zhp == NULL)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_OK);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* Found the youngest clone to promote. Promote it. */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (promote_clone(zhp, cd.clone_zhp) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(cd.clone_zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* close and reopen the main dataset to get the latest info */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) strlcpy(nm, zfs_get_name(zhp), sizeof (nm));
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_OK);
286822dd6ee35fa0959e7b55e659b92ea1c12f71}
286822dd6ee35fa0959e7b55e659b92ea1c12f71
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * possible, or by copying the data from the snapshot to the zonepath.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekint
ff17c8bf86c3e567734be83f90267edee20f580fgjelinekclone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int err = Z_OK;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char clone_name[MAXPATHLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char snap_path[MAXPATHLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("unable to find path for %s.\n"),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek snap_name);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_NO_ENTRY);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * The zonepath cannot be ZFS cloned, try to copy the data from
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * within the snapshot to the zonepath.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (clean_out_clone() != Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek gettext("could not remove the "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "software inventory from %s\n"), zonepath);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (err);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (err != Z_NO_ENTRY) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Cloning the snapshot failed. Fall back to trying
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * to install the zone by copying from the snapshot.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (clean_out_clone() != Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek gettext("could not remove the "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "software inventory from %s\n"),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zonepath);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek } else {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * The snapshot is unusable for some reason so restore
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * the zone state to configured since we were unable to
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * actually do anything about getting the zone
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * installed.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int tmp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((tmp = zone_set_state(target_zone,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek ZONE_STATE_CONFIGURED)) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek errno = tmp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zperror2(target_zone,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek gettext("could not set state"));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (err);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekint
ff17c8bf86c3e567734be83f90267edee20f580fgjelinekclone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf,
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek char *postsnapbuf)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char clone_name[MAXPATHLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char snap_name[MAXPATHLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Try to get a zfs handle for the source_zonepath. If this fails
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * the source_zonepath is not ZFS so return an error.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((zhp = mount2zhandle(source_zonepath)) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Check if there is a file system already mounted on zonepath. If so,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * we can't clone to the path so we should fall back to copying.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (is_mountpnt(zonepath)) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek gettext("A file system is already mounted on %s,\n"
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "preventing use of a ZFS clone.\n"), zonepath);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Instead of using path2name to get the clone name from the zonepath,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * we could generate a name from the source zone ZFS name. However,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * this would mean we would create the clone under the ZFS fs of the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * source instead of what the zonepath says. For example,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * source_zonepath zonepath
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * /pl/zones/dev/z1 /pl/zones/deploy/z2
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * We don't want the clone to be under "dev", we want it under
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * "deploy", so that we can leverage the normal attribute inheritance
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * that ZFS provides in the fs hierarchy.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf,
ff17c8bf86c3e567734be83f90267edee20f580fgjelinek postsnapbuf) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek if (clone_snap(snap_name, clone_name) != Z_OK) {
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek /* Clean up the snapshot we just took. */
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT))
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek != NULL) {
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek if (zfs_unmount(zhp, NULL, 0) == 0)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby (void) zfs_destroy(zhp, B_FALSE);
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek zfs_close(zhp);
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek }
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) printf(gettext("Instead of copying, a ZFS clone has been "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "created for this zone.\n"));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Attempt to create a ZFS file system for the specified zonepath.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * We either will successfully create a ZFS file system and get it mounted
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * on the zonepath or we don't. The caller doesn't care since a regular
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * directory is used for the zonepath if no ZFS file system is mounted there.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekvoid
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekcreate_zfs_zonepath(char *zonepath)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char zfs_name[MAXPATHLEN];
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock nvlist_t *props = NULL;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
d1f855d73e0bf529109aa3dc1b967fc6ac19b4fc /* Check if the dataset already exists. */
d1f855d73e0bf529109aa3dc1b967fc6ac19b4fc if ((zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) != NULL) {
d1f855d73e0bf529109aa3dc1b967fc6ac19b4fc zfs_close(zhp);
d1f855d73e0bf529109aa3dc1b967fc6ac19b4fc return;
d1f855d73e0bf529109aa3dc1b967fc6ac19b4fc }
d1f855d73e0bf529109aa3dc1b967fc6ac19b4fc
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul /*
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul * We turn off zfs SHARENFS and SHARESMB properties on the
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul * zoneroot dataset in order to prevent the GZ from sharing
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul * NGZ data by accident.
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul */
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul if ((nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) ||
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul "off") != 0) ||
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARESMB),
2b6c28b8b605a28e1a671f5d6b484cd697e51da6batschul "off") != 0)) {
aab83bb83be7342f6cfccaed8d5fe0b2f404855dJosef 'Jeff' Sipek nvlist_free(props);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock "out of memory\n"), zfs_name);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock }
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 ||
990b4856d0eaada6f8140335733a1b1771ed2746lling (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) {
99653d4ee642c6528e88224f12409a5f23060994eschrock (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
99653d4ee642c6528e88224f12409a5f23060994eschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs));
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock nvlist_free(props);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock nvlist_free(props);
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_mount(zhp, NULL, 0) != 0) {
99653d4ee642c6528e88224f12409a5f23060994eschrock (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
99653d4ee642c6528e88224f12409a5f23060994eschrock "%s\n"), zfs_name, libzfs_error_description(g_zfs));
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby (void) zfs_destroy(zhp, B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek } else {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (chmod(zonepath, S_IRWXU) != 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("file system %s "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "successfully created, but chmod %o failed: %s\n"),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_name, S_IRWXU, strerror(errno));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) destroy_zfs(zonepath);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek } else {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) printf(gettext("A ZFS file system has been "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "created for this zone.\n"));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * which means the caller should clean up the zonepath in the traditional
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * way.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekint
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekdestroy_zfs(char *zonepath)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek boolean_t is_clone = B_FALSE;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char origin[ZFS_MAXPROPLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
99653d4ee642c6528e88224f12409a5f23060994eschrock if ((zhp = mount2zhandle(zonepath)) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (promote_all_clones(zhp) != 0)
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71
286822dd6ee35fa0959e7b55e659b92ea1c12f71 /* Now cleanup any snapshots remaining. */
0d8fa8f8eba3ea46bc79d73445009505d1dd5d7dMartin Matuska if (zfs_iter_snapshots(zhp, B_FALSE, rm_snap, NULL) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * We can't destroy the file system if it has still has dependents.
286822dd6ee35fa0959e7b55e659b92ea1c12f71 * There shouldn't be any at this point, but we'll double check.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) fprintf(stderr, gettext("zfs destroy %s failed: the "
286822dd6ee35fa0959e7b55e659b92ea1c12f71 "dataset still has dependents\n"), zfs_get_name(zhp));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * This might be a clone. Try to get the snapshot so we can attempt
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * to destroy that as well.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
99653d4ee642c6528e88224f12409a5f23060994eschrock NULL, 0, B_FALSE) == 0)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek is_clone = B_TRUE;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
286822dd6ee35fa0959e7b55e659b92ea1c12f71 if (zfs_unmount(zhp, NULL, 0) != 0) {
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) fprintf(stderr, gettext("zfs unmount %s failed: %s\n"),
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_get_name(zhp), libzfs_error_description(g_zfs));
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_close(zhp);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 return (Z_ERR);
286822dd6ee35fa0959e7b55e659b92ea1c12f71 }
286822dd6ee35fa0959e7b55e659b92ea1c12f71
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby if (zfs_destroy(zhp, B_FALSE) != 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * If the destroy fails for some reason, try to remount
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * the file system so that we can use "rm -rf" to clean up
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * instead.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
286822dd6ee35fa0959e7b55e659b92ea1c12f71 (void) fprintf(stderr, gettext("zfs destroy %s failed: %s\n"),
286822dd6ee35fa0959e7b55e659b92ea1c12f71 zfs_get_name(zhp), libzfs_error_description(g_zfs));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) zfs_mount(zhp, NULL, 0);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek /*
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek * If the zone has ever been moved then the mountpoint dir will not be
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek * cleaned up by the zfs_destroy(). To handle this case try to clean
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek * it up now but don't worry if it fails, that will be normal.
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek */
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek (void) rmdir(zonepath);
d9e728a2c2e62adeef072d782e4c8a7b34e7e8e8gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) printf(gettext("The ZFS file system for this zone has been "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "destroyed.\n"));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (is_clone) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *ohp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Try to clean up the snapshot that the clone was taken from.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
99653d4ee642c6528e88224f12409a5f23060994eschrock if ((ohp = zfs_open(g_zfs, origin,
99653d4ee642c6528e88224f12409a5f23060994eschrock ZFS_TYPE_SNAPSHOT)) != NULL) {
3bb79bece53191f2cf27aa61a72ea1784a7ce700eschrock if (zfs_iter_dependents(ohp, B_TRUE, has_dependent,
3bb79bece53191f2cf27aa61a72ea1784a7ce700eschrock NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0)
842727c2f41f01b380de4f5e787d905702870f23Chris Kirby (void) zfs_destroy(ohp, B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(ohp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Return true if the path is its own zfs file system. We determine this
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * by stat-ing the path to see if it is zfs and stat-ing the parent to see
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * if it is a different fs.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekboolean_t
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekis_zonepath_zfs(char *zonepath)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int res;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char *path;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char *parent;
3f2f09c1efd66f6d2995998ea72c5df8c70c9a97dp struct statvfs64 buf1, buf2;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
3f2f09c1efd66f6d2995998ea72c5df8c70c9a97dp if (statvfs64(zonepath, &buf1) != 0)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (strcmp(buf1.f_basetype, "zfs") != 0)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if ((path = strdup(zonepath)) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek parent = dirname(path);
3f2f09c1efd66f6d2995998ea72c5df8c70c9a97dp res = statvfs64(parent, &buf2);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek free(path);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (res != 0)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (buf1.f_fsid == buf2.f_fsid)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_FALSE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (B_TRUE);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Implement the fast move of a ZFS file system by simply updating the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * mountpoint. Since it is file system already, we don't have the
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * issue of cross-file system copying.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekint
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekmove_zfs(char *zonepath, char *new_zonepath)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int ret = Z_ERR;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
99653d4ee642c6528e88224f12409a5f23060994eschrock if ((zhp = mount2zhandle(zonepath)) == NULL)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock new_zonepath) == 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Clean up the old mount point. We ignore any failure since
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * the zone is already successfully mounted on the new path.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) rmdir(zonepath);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek ret = Z_OK;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (ret);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Validate that the given dataset exists on the system, and that neither it nor
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * its children are zvols.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek *
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Note that we don't do anything with the 'zoned' property here. All
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * management is done in zoneadmd when the zone is actually rebooted. This
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * allows us to automatically set the zoned property even when a zone is
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * rebooted by the administrator.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekint
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekverify_datasets(zone_dochandle_t handle)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek int return_code = Z_OK;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek struct zone_dstab dstab;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char propbuf[ZFS_MAXPROPLEN];
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens char source[ZFS_MAX_DATASET_NAME_LEN];
990b4856d0eaada6f8140335733a1b1771ed2746lling zprop_source_t srctype;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zonecfg_setdsent(handle) != Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek /*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * TRANSLATION_NOTE
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * zfs and dataset are literals that should not be translated.
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("could not verify zfs datasets: "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "unable to enumerate datasets\n"));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
99653d4ee642c6528e88224f12409a5f23060994eschrock if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
99653d4ee642c6528e88224f12409a5f23060994eschrock (void) fprintf(stderr, gettext("could not verify zfs "
99653d4ee642c6528e88224f12409a5f23060994eschrock "dataset %s: %s\n"), dstab.zone_dataset_name,
99653d4ee642c6528e88224f12409a5f23060994eschrock libzfs_error_description(g_zfs));
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return_code = Z_ERR;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek continue;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek sizeof (propbuf), &srctype, source,
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek sizeof (source), 0) == 0 &&
990b4856d0eaada6f8140335733a1b1771ed2746lling (srctype == ZPROP_SRC_INHERITED)) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("could not verify zfs "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "dataset %s: mountpoint cannot be inherited\n"),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek dstab.zone_dataset_name);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return_code = Z_ERR;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek continue;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) zonecfg_enddsent(handle);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (return_code);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek/*
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * Verify that the ZFS dataset exists, and its mountpoint
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek * property is set to "legacy".
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek */
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekint
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinekverify_fs_zfs(struct zone_fstab *fstab)
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek{
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_handle_t *zhp;
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek char propbuf[ZFS_MAXPROPLEN];
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
99653d4ee642c6528e88224f12409a5f23060994eschrock if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special,
990b4856d0eaada6f8140335733a1b1771ed2746lling ZFS_TYPE_DATASET)) == NULL) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("could not verify fs %s: "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "could not access zfs dataset '%s'\n"),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek fstab->zone_fs_dir, fstab->zone_fs_special);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("cannot verify fs %s: "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "'%s' is not a file system\n"),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek fstab->zone_fs_dir, fstab->zone_fs_special);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek (void) fprintf(stderr, gettext("could not verify fs %s: "
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek "zfs '%s' mountpoint is not \"legacy\"\n"),
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek fstab->zone_fs_dir, fstab->zone_fs_special);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_ERR);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek }
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek zfs_close(zhp);
99653d4ee642c6528e88224f12409a5f23060994eschrock return (Z_OK);
99653d4ee642c6528e88224f12409a5f23060994eschrock}
99653d4ee642c6528e88224f12409a5f23060994eschrock
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Destroy the specified mnttab structure that was created by mnttab_dup().
0094b373ead542a342e4250eaf37854ccd3e50c0jv * NOTE: The structure's mnt_time field isn't freed.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvstatic void
0094b373ead542a342e4250eaf37854ccd3e50c0jvmnttab_destroy(struct mnttab *tabp)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(tabp != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv free(tabp->mnt_mountp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv free(tabp->mnt_special);
0094b373ead542a342e4250eaf37854ccd3e50c0jv free(tabp->mnt_fstype);
0094b373ead542a342e4250eaf37854ccd3e50c0jv free(tabp->mnt_mntopts);
0094b373ead542a342e4250eaf37854ccd3e50c0jv free(tabp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Duplicate the specified mnttab structure. The mnt_mountp and mnt_time
0094b373ead542a342e4250eaf37854ccd3e50c0jv * fields aren't duplicated. This function returns a pointer to the new mnttab
0094b373ead542a342e4250eaf37854ccd3e50c0jv * structure or NULL if an error occurred. If an error occurs, then this
0094b373ead542a342e4250eaf37854ccd3e50c0jv * function sets errno to reflect the error. mnttab structures created by
0094b373ead542a342e4250eaf37854ccd3e50c0jv * this function should be destroyed via mnttab_destroy().
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvstatic struct mnttab *
0094b373ead542a342e4250eaf37854ccd3e50c0jvmnttab_dup(const struct mnttab *srcp)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv struct mnttab *retval;
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(srcp != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv retval = (struct mnttab *)calloc(1, sizeof (*retval));
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (retval == NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv errno = ENOMEM;
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (srcp->mnt_special != NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv retval->mnt_special = strdup(srcp->mnt_special);
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (retval->mnt_special == NULL)
0094b373ead542a342e4250eaf37854ccd3e50c0jv goto err;
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (srcp->mnt_fstype != NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv retval->mnt_fstype = strdup(srcp->mnt_fstype);
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (retval->mnt_fstype == NULL)
0094b373ead542a342e4250eaf37854ccd3e50c0jv goto err;
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv retval->mnt_mntopts = (char *)malloc(MAX_MNTOPT_STR * sizeof (char));
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (retval->mnt_mntopts == NULL)
0094b373ead542a342e4250eaf37854ccd3e50c0jv goto err;
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (srcp->mnt_mntopts != NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (strlcpy(retval->mnt_mntopts, srcp->mnt_mntopts,
0094b373ead542a342e4250eaf37854ccd3e50c0jv MAX_MNTOPT_STR * sizeof (char)) >= MAX_MNTOPT_STR *
0094b373ead542a342e4250eaf37854ccd3e50c0jv sizeof (char)) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv mnttab_destroy(retval);
0094b373ead542a342e4250eaf37854ccd3e50c0jv errno = EOVERFLOW; /* similar to mount(2) behavior */
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv } else {
0094b373ead542a342e4250eaf37854ccd3e50c0jv retval->mnt_mntopts[0] = '\0';
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (retval);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jverr:
0094b373ead542a342e4250eaf37854ccd3e50c0jv mnttab_destroy(retval);
0094b373ead542a342e4250eaf37854ccd3e50c0jv errno = ENOMEM;
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Determine whether the specified ZFS dataset's mountpoint property is set
0094b373ead542a342e4250eaf37854ccd3e50c0jv * to "legacy". If the specified dataset does not have a legacy mountpoint,
0094b373ead542a342e4250eaf37854ccd3e50c0jv * then the string pointer to which the mountpoint argument points is assigned
0094b373ead542a342e4250eaf37854ccd3e50c0jv * a dynamically-allocated string containing the dataset's mountpoint
0094b373ead542a342e4250eaf37854ccd3e50c0jv * property. If the dataset's mountpoint property is "legacy" or a libzfs
0094b373ead542a342e4250eaf37854ccd3e50c0jv * error occurs, then the string pointer to which the mountpoint argument
0094b373ead542a342e4250eaf37854ccd3e50c0jv * points isn't modified.
0094b373ead542a342e4250eaf37854ccd3e50c0jv *
0094b373ead542a342e4250eaf37854ccd3e50c0jv * This function returns B_TRUE if it doesn't encounter any fatal errors.
0094b373ead542a342e4250eaf37854ccd3e50c0jv * It returns B_FALSE if it encounters a fatal error and sets errno to the
0094b373ead542a342e4250eaf37854ccd3e50c0jv * appropriate error code.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvstatic boolean_t
0094b373ead542a342e4250eaf37854ccd3e50c0jvget_zfs_non_legacy_mountpoint(const char *dataset_name, char **mountpoint)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_handle_t *zhp;
0094b373ead542a342e4250eaf37854ccd3e50c0jv char propbuf[ZFS_MAXPROPLEN];
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(dataset_name != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(mountpoint != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv if ((zhp = zfs_open(g_zfs, dataset_name, ZFS_TYPE_DATASET)) == NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv errno = EINVAL;
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (B_FALSE);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
0094b373ead542a342e4250eaf37854ccd3e50c0jv NULL, NULL, 0, 0) != 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv errno = EINVAL;
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (B_FALSE);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (strcmp(propbuf, "legacy") != 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv if ((*mountpoint = strdup(propbuf)) == NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv errno = ENOMEM;
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (B_FALSE);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (B_TRUE);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * This zonecfg_find_mounts() callback records information about mounts of
0094b373ead542a342e4250eaf37854ccd3e50c0jv * interest in a zonepath. It also tallies the number of zone
0094b373ead542a342e4250eaf37854ccd3e50c0jv * root overlay mounts and the number of unexpected mounts found.
0094b373ead542a342e4250eaf37854ccd3e50c0jv * This function outputs errors using zerror() if it finds unexpected
0094b373ead542a342e4250eaf37854ccd3e50c0jv * mounts. cookiep should point to an initialized zone_mounts_t structure.
0094b373ead542a342e4250eaf37854ccd3e50c0jv *
0094b373ead542a342e4250eaf37854ccd3e50c0jv * This function returns zero on success and a nonzero value on failure.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvstatic int
0094b373ead542a342e4250eaf37854ccd3e50c0jvzone_mounts_cb(const struct mnttab *mountp, void *cookiep)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv zone_mounts_t *mounts;
0094b373ead542a342e4250eaf37854ccd3e50c0jv const char *zone_mount_dir;
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(mountp != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(cookiep != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv mounts = (zone_mounts_t *)cookiep;
0094b373ead542a342e4250eaf37854ccd3e50c0jv zone_mount_dir = mountp->mnt_mountp + mounts->zonepath_len;
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (strcmp(zone_mount_dir, "/root") == 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Check for an overlay mount. If we already detected a /root
0094b373ead542a342e4250eaf37854ccd3e50c0jv * mount, then the current mount must be an overlay mount.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mounts->root_mnttab != NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv mounts->num_root_overlay_mounts++;
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Store the root mount's mnttab information in the
0094b373ead542a342e4250eaf37854ccd3e50c0jv * zone_mounts_t structure for future use.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if ((mounts->root_mnttab = mnttab_dup(mountp)) == NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zperror(cmd_to_str(CMD_MOVE), B_FALSE);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Determine if the filesystem is a ZFS filesystem with a
0094b373ead542a342e4250eaf37854ccd3e50c0jv * non-legacy mountpoint. If it is, then set the root
0094b373ead542a342e4250eaf37854ccd3e50c0jv * filesystem's mnttab's mnt_mountp field to a non-NULL
0094b373ead542a342e4250eaf37854ccd3e50c0jv * value, which will serve as a flag to indicate this special
0094b373ead542a342e4250eaf37854ccd3e50c0jv * condition.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (strcmp(mountp->mnt_fstype, MNTTYPE_ZFS) == 0 &&
0094b373ead542a342e4250eaf37854ccd3e50c0jv get_zfs_non_legacy_mountpoint(mountp->mnt_special,
0094b373ead542a342e4250eaf37854ccd3e50c0jv &mounts->root_mnttab->mnt_mountp) != B_TRUE) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zperror(cmd_to_str(CMD_MOVE), B_FALSE);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv } else {
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * An unexpected mount was found. Notify the user.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mounts->num_unexpected_mounts == 0)
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("These file systems are mounted on "
0094b373ead542a342e4250eaf37854ccd3e50c0jv "subdirectories of %s.\n"), mounts->zonepath);
0094b373ead542a342e4250eaf37854ccd3e50c0jv mounts->num_unexpected_mounts++;
0094b373ead542a342e4250eaf37854ccd3e50c0jv (void) zfm_print(mountp, NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Initialize the specified zone_mounts_t structure for the given zonepath.
0094b373ead542a342e4250eaf37854ccd3e50c0jv * If this function succeeds, it returns zero and the specified zone_mounts_t
0094b373ead542a342e4250eaf37854ccd3e50c0jv * structure contains information about mounts in the specified zonepath.
0094b373ead542a342e4250eaf37854ccd3e50c0jv * The function returns a nonzero value if it fails. The zone_mounts_t
0094b373ead542a342e4250eaf37854ccd3e50c0jv * structure doesn't need be destroyed via zone_mounts_destroy() if this
0094b373ead542a342e4250eaf37854ccd3e50c0jv * function fails.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvint
0094b373ead542a342e4250eaf37854ccd3e50c0jvzone_mounts_init(zone_mounts_t *mounts, const char *zonepath)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(mounts != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(zonepath != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv bzero(mounts, sizeof (*mounts));
0094b373ead542a342e4250eaf37854ccd3e50c0jv if ((mounts->zonepath = strdup(zonepath)) == NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("the process ran out of memory while checking "
0094b373ead542a342e4250eaf37854ccd3e50c0jv "for mounts in zonepath %s."), zonepath);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv mounts->zonepath_len = strlen(zonepath);
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (zonecfg_find_mounts((char *)zonepath, zone_mounts_cb, mounts) ==
0094b373ead542a342e4250eaf37854ccd3e50c0jv -1) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("an error occurred while checking for mounts "
0094b373ead542a342e4250eaf37854ccd3e50c0jv "in zonepath %s."), zonepath);
0094b373ead542a342e4250eaf37854ccd3e50c0jv zone_mounts_destroy(mounts);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Destroy the memory used by the specified zone_mounts_t structure's fields.
0094b373ead542a342e4250eaf37854ccd3e50c0jv * This function doesn't free the memory occupied by the structure itself
0094b373ead542a342e4250eaf37854ccd3e50c0jv * (i.e., it doesn't free the parameter).
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvvoid
0094b373ead542a342e4250eaf37854ccd3e50c0jvzone_mounts_destroy(zone_mounts_t *mounts)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(mounts != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv free(mounts->zonepath);
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mounts->root_mnttab != NULL)
0094b373ead542a342e4250eaf37854ccd3e50c0jv mnttab_destroy(mounts->root_mnttab);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Mount a moving zone's root filesystem (if it had a root filesystem mount
0094b373ead542a342e4250eaf37854ccd3e50c0jv * prior to the move) using the specified zonepath. mounts should refer to
0094b373ead542a342e4250eaf37854ccd3e50c0jv * the zone_mounts_t structure describing the zone's mount information.
0094b373ead542a342e4250eaf37854ccd3e50c0jv *
0094b373ead542a342e4250eaf37854ccd3e50c0jv * This function returns zero if the mount succeeds and a nonzero value
0094b373ead542a342e4250eaf37854ccd3e50c0jv * if it doesn't.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvint
0094b373ead542a342e4250eaf37854ccd3e50c0jvzone_mount_rootfs(zone_mounts_t *mounts, const char *zonepath)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv char zoneroot[MAXPATHLEN];
0094b373ead542a342e4250eaf37854ccd3e50c0jv struct mnttab *mtab;
0094b373ead542a342e4250eaf37854ccd3e50c0jv int flags;
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(mounts != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(zonepath != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * If there isn't a root filesystem, then don't do anything.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv mtab = mounts->root_mnttab;
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mtab == NULL)
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Determine the root filesystem's new mountpoint.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
0094b373ead542a342e4250eaf37854ccd3e50c0jv sizeof (zoneroot)) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("Zonepath %s is too long.\n"), zonepath);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * If the root filesystem is a non-legacy ZFS filesystem (i.e., if it's
0094b373ead542a342e4250eaf37854ccd3e50c0jv * mnt_mountp field is non-NULL), then make the filesystem's new
0094b373ead542a342e4250eaf37854ccd3e50c0jv * mount point its mountpoint property and mount the filesystem.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mtab->mnt_mountp != NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_handle_t *zhp;
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
0094b373ead542a342e4250eaf37854ccd3e50c0jv ZFS_TYPE_DATASET)) == NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("could not get ZFS handle for the zone's"
0094b373ead542a342e4250eaf37854ccd3e50c0jv " root filesystem"));
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
0094b373ead542a342e4250eaf37854ccd3e50c0jv zoneroot) != 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("could not modify zone's root "
0094b373ead542a342e4250eaf37854ccd3e50c0jv "filesystem's mountpoint property"));
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (zfs_mount(zhp, mtab->mnt_mntopts, 0) != 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("unable to mount zone root %s: %s"),
0094b373ead542a342e4250eaf37854ccd3e50c0jv zoneroot, libzfs_error_description(g_zfs));
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (zfs_prop_set(zhp,
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
0094b373ead542a342e4250eaf37854ccd3e50c0jv mtab->mnt_mountp) != 0)
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("unable to restore zone's root "
0094b373ead542a342e4250eaf37854ccd3e50c0jv "filesystem's mountpoint property"));
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * The root filesystem is either a legacy-mounted ZFS filesystem or
0094b373ead542a342e4250eaf37854ccd3e50c0jv * a non-ZFS filesystem. Use mount(2) to mount the root filesystem.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mtab->mnt_mntopts != NULL)
0094b373ead542a342e4250eaf37854ccd3e50c0jv flags = MS_OPTIONSTR;
0094b373ead542a342e4250eaf37854ccd3e50c0jv else
0094b373ead542a342e4250eaf37854ccd3e50c0jv flags = 0;
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mount(mtab->mnt_special, zoneroot, flags, mtab->mnt_fstype, NULL, 0,
0094b373ead542a342e4250eaf37854ccd3e50c0jv mtab->mnt_mntopts, MAX_MNTOPT_STR * sizeof (char)) != 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv flags = errno;
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("unable to mount zone root %s: %s"), zoneroot,
0094b373ead542a342e4250eaf37854ccd3e50c0jv strerror(flags));
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv/*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Unmount a moving zone's root filesystem (if such a mount exists) using the
0094b373ead542a342e4250eaf37854ccd3e50c0jv * specified zonepath. mounts should refer to the zone_mounts_t structure
0094b373ead542a342e4250eaf37854ccd3e50c0jv * describing the zone's mount information. If force is B_TRUE, then if the
0094b373ead542a342e4250eaf37854ccd3e50c0jv * unmount fails, then the function will try to forcibly unmount the zone's root
0094b373ead542a342e4250eaf37854ccd3e50c0jv * filesystem.
0094b373ead542a342e4250eaf37854ccd3e50c0jv *
0094b373ead542a342e4250eaf37854ccd3e50c0jv * This function returns zero if the unmount (forced or otherwise) succeeds;
0094b373ead542a342e4250eaf37854ccd3e50c0jv * otherwise, it returns a nonzero value.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jvint
0094b373ead542a342e4250eaf37854ccd3e50c0jvzone_unmount_rootfs(zone_mounts_t *mounts, const char *zonepath,
0094b373ead542a342e4250eaf37854ccd3e50c0jv boolean_t force)
0094b373ead542a342e4250eaf37854ccd3e50c0jv{
0094b373ead542a342e4250eaf37854ccd3e50c0jv char zoneroot[MAXPATHLEN];
0094b373ead542a342e4250eaf37854ccd3e50c0jv struct mnttab *mtab;
0094b373ead542a342e4250eaf37854ccd3e50c0jv int err;
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(mounts != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv assert(zonepath != NULL);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * If there isn't a root filesystem, then don't do anything.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv mtab = mounts->root_mnttab;
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mtab == NULL)
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Determine the root filesystem's mountpoint.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
0094b373ead542a342e4250eaf37854ccd3e50c0jv sizeof (zoneroot)) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("Zonepath %s is too long.\n"), zonepath);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * If the root filesystem is a non-legacy ZFS fileystem, then unmount
0094b373ead542a342e4250eaf37854ccd3e50c0jv * the filesystem via libzfs.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (mtab->mnt_mountp != NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_handle_t *zhp;
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
0094b373ead542a342e4250eaf37854ccd3e50c0jv ZFS_TYPE_DATASET)) == NULL) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("could not get ZFS handle for the zone's"
0094b373ead542a342e4250eaf37854ccd3e50c0jv " root filesystem"));
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (zfs_unmount(zhp, zoneroot, 0) != 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (force && zfs_unmount(zhp, zoneroot, MS_FORCE) ==
0094b373ead542a342e4250eaf37854ccd3e50c0jv 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("unable to unmount zone root %s: %s"),
0094b373ead542a342e4250eaf37854ccd3e50c0jv zoneroot, libzfs_error_description(g_zfs));
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv zfs_close(zhp);
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv
0094b373ead542a342e4250eaf37854ccd3e50c0jv /*
0094b373ead542a342e4250eaf37854ccd3e50c0jv * Use umount(2) to unmount the root filesystem. If this fails, then
0094b373ead542a342e4250eaf37854ccd3e50c0jv * forcibly unmount it if the force flag is set.
0094b373ead542a342e4250eaf37854ccd3e50c0jv */
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (umount(zoneroot) != 0) {
0094b373ead542a342e4250eaf37854ccd3e50c0jv if (force && umount2(zoneroot, MS_FORCE) == 0)
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv err = errno;
0094b373ead542a342e4250eaf37854ccd3e50c0jv zerror(gettext("unable to unmount zone root %s: %s"), zoneroot,
0094b373ead542a342e4250eaf37854ccd3e50c0jv strerror(err));
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (-1);
0094b373ead542a342e4250eaf37854ccd3e50c0jv }
0094b373ead542a342e4250eaf37854ccd3e50c0jv return (0);
0094b373ead542a342e4250eaf37854ccd3e50c0jv}
0094b373ead542a342e4250eaf37854ccd3e50c0jv
99653d4ee642c6528e88224f12409a5f23060994eschrockint
99653d4ee642c6528e88224f12409a5f23060994eschrockinit_zfs(void)
99653d4ee642c6528e88224f12409a5f23060994eschrock{
99653d4ee642c6528e88224f12409a5f23060994eschrock if ((g_zfs = libzfs_init()) == NULL) {
99653d4ee642c6528e88224f12409a5f23060994eschrock (void) fprintf(stderr, gettext("failed to initialize ZFS "
99653d4ee642c6528e88224f12409a5f23060994eschrock "library\n"));
99653d4ee642c6528e88224f12409a5f23060994eschrock return (Z_ERR);
99653d4ee642c6528e88224f12409a5f23060994eschrock }
99653d4ee642c6528e88224f12409a5f23060994eschrock
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek return (Z_OK);
0b5de56d26c0148ad33bb3a9201091502f24d910gjelinek}