]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libbe/be.c
trim(8): Fix a few issues reported by mandoc
[FreeBSD/FreeBSD.git] / lib / libbe / be.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/mount.h>
33 #include <sys/stat.h>
34 #include <sys/ucred.h>
35 #include <sys/queue.h>
36 #include <sys/zfs_context.h>
37 #include <sys/mntent.h>
38 #include <sys/zfs_ioctl.h>
39
40 #include <libzutil.h>
41 #include <ctype.h>
42 #include <libgen.h>
43 #include <libzfs_core.h>
44 #include <libzfs_impl.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <time.h>
48 #include <unistd.h>
49 #include <libzfsbootenv.h>
50
51 #include "be.h"
52 #include "be_impl.h"
53
54 struct promote_entry {
55         char                            name[BE_MAXPATHLEN];
56         SLIST_ENTRY(promote_entry)      link;
57 };
58
59 struct be_destroy_data {
60         libbe_handle_t                  *lbh;
61         char                            target_name[BE_MAXPATHLEN];
62         char                            *snapname;
63         SLIST_HEAD(, promote_entry)     promotelist;
64 };
65
66 #if SOON
67 static int be_create_child_noent(libbe_handle_t *lbh, const char *active,
68     const char *child_path);
69 static int be_create_child_cloned(libbe_handle_t *lbh, const char *active);
70 #endif
71
72 /* Arbitrary... should tune */
73 #define BE_SNAP_SERIAL_MAX      1024
74
75 /*
76  * Iterator function for locating the rootfs amongst the children of the
77  * zfs_be_root set by loader(8).  data is expected to be a libbe_handle_t *.
78  */
79 static int
80 be_locate_rootfs(libbe_handle_t *lbh)
81 {
82         struct statfs sfs;
83         struct mnttab entry;
84         zfs_handle_t *zfs;
85
86         /*
87          * Check first if root is ZFS; if not, we'll bail on rootfs capture.
88          * Unfortunately needed because zfs_path_to_zhandle will emit to
89          * stderr if / isn't actually a ZFS filesystem, which we'd like
90          * to avoid.
91          */
92         if (statfs("/", &sfs) == 0) {
93                 statfs2mnttab(&sfs, &entry);
94                 if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
95                         return (1);
96         } else
97                 return (1);
98         zfs = zfs_path_to_zhandle(lbh->lzh, "/", ZFS_TYPE_FILESYSTEM);
99         if (zfs == NULL)
100                 return (1);
101
102         strlcpy(lbh->rootfs, zfs_get_name(zfs), sizeof(lbh->rootfs));
103         zfs_close(zfs);
104         return (0);
105 }
106
107 /*
108  * Initializes the libbe context to operate in the root boot environment
109  * dataset, for example, zroot/ROOT.
110  */
111 libbe_handle_t *
112 libbe_init(const char *root)
113 {
114         char altroot[MAXPATHLEN];
115         libbe_handle_t *lbh;
116         char *poolname, *pos;
117         int pnamelen;
118
119         lbh = NULL;
120         poolname = pos = NULL;
121
122         if ((lbh = calloc(1, sizeof(libbe_handle_t))) == NULL)
123                 goto err;
124
125         if ((lbh->lzh = libzfs_init()) == NULL)
126                 goto err;
127
128         /*
129          * Grab rootfs, we'll work backwards from there if an optional BE root
130          * has not been passed in.
131          */
132         if (be_locate_rootfs(lbh) != 0) {
133                 if (root == NULL)
134                         goto err;
135                 *lbh->rootfs = '\0';
136         }
137         if (root == NULL) {
138                 /* Strip off the final slash from rootfs to get the be root */
139                 strlcpy(lbh->root, lbh->rootfs, sizeof(lbh->root));
140                 pos = strrchr(lbh->root, '/');
141                 if (pos == NULL)
142                         goto err;
143                 *pos = '\0';
144         } else
145                 strlcpy(lbh->root, root, sizeof(lbh->root));
146
147         if ((pos = strchr(lbh->root, '/')) == NULL)
148                 goto err;
149
150         pnamelen = pos - lbh->root;
151         poolname = malloc(pnamelen + 1);
152         if (poolname == NULL)
153                 goto err;
154
155         strlcpy(poolname, lbh->root, pnamelen + 1);
156         if ((lbh->active_phandle = zpool_open(lbh->lzh, poolname)) == NULL)
157                 goto err;
158         free(poolname);
159         poolname = NULL;
160
161         if (zpool_get_prop(lbh->active_phandle, ZPOOL_PROP_BOOTFS, lbh->bootfs,
162             sizeof(lbh->bootfs), NULL, true) != 0)
163                 goto err;
164
165         if (zpool_get_prop(lbh->active_phandle, ZPOOL_PROP_ALTROOT,
166             altroot, sizeof(altroot), NULL, true) == 0 &&
167             strcmp(altroot, "-") != 0)
168                 lbh->altroot_len = strlen(altroot);
169
170         return (lbh);
171 err:
172         if (lbh != NULL) {
173                 if (lbh->active_phandle != NULL)
174                         zpool_close(lbh->active_phandle);
175                 if (lbh->lzh != NULL)
176                         libzfs_fini(lbh->lzh);
177                 free(lbh);
178         }
179         free(poolname);
180         return (NULL);
181 }
182
183
184 /*
185  * Free memory allocated by libbe_init()
186  */
187 void
188 libbe_close(libbe_handle_t *lbh)
189 {
190
191         if (lbh->active_phandle != NULL)
192                 zpool_close(lbh->active_phandle);
193         libzfs_fini(lbh->lzh);
194         free(lbh);
195 }
196
197 /*
198  * Proxy through to libzfs for the moment.
199  */
200 void
201 be_nicenum(uint64_t num, char *buf, size_t buflen)
202 {
203
204         zfs_nicenum(num, buf, buflen);
205 }
206
207 static bool
208 be_should_promote_clones(zfs_handle_t *zfs_hdl, struct be_destroy_data *bdd)
209 {
210         char *atpos;
211
212         if (zfs_get_type(zfs_hdl) != ZFS_TYPE_SNAPSHOT)
213                 return (false);
214
215         /*
216          * If we're deleting a snapshot, we need to make sure we only promote
217          * clones that are derived from one of the snapshots we're deleting,
218          * rather than that of a snapshot we're not touching.  This keeps stuff
219          * in a consistent state, making sure that we don't error out unless
220          * we really need to.
221          */
222         if (bdd->snapname == NULL)
223                 return (true);
224
225         atpos = strchr(zfs_get_name(zfs_hdl), '@');
226         return (strcmp(atpos + 1, bdd->snapname) == 0);
227 }
228
229 /*
230  * This is executed from be_promote_dependent_clones via zfs_iter_dependents,
231  * It checks if the dependent type is a snapshot then attempts to find any
232  * clones associated with it. Any clones not related to the destroy target are
233  * added to the promote list.
234  */
235 static int
236 be_dependent_clone_cb(zfs_handle_t *zfs_hdl, void *data)
237 {
238         int err;
239         bool found;
240         char *name;
241         struct nvlist *nvl;
242         struct nvpair *nvp;
243         struct be_destroy_data *bdd;
244         struct promote_entry *entry, *newentry;
245
246         nvp = NULL;
247         err = 0;
248         bdd = (struct be_destroy_data *)data;
249
250         if (be_should_promote_clones(zfs_hdl, bdd) &&
251             (nvl = zfs_get_clones_nvl(zfs_hdl)) != NULL) {
252                 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
253                         name = nvpair_name(nvp);
254
255                         /*
256                          * Skip if the clone is equal to, or a child of, the
257                          * destroy target.
258                          */
259                         if (strncmp(name, bdd->target_name,
260                             strlen(bdd->target_name)) == 0 ||
261                             strstr(name, bdd->target_name) == name) {
262                                 continue;
263                         }
264
265                         found = false;
266                         SLIST_FOREACH(entry, &bdd->promotelist, link) {
267                                 if (strcmp(entry->name, name) == 0) {
268                                         found = true;
269                                         break;
270                                 }
271                         }
272
273                         if (found)
274                                 continue;
275
276                         newentry = malloc(sizeof(struct promote_entry));
277                         if (newentry == NULL) {
278                                 err = ENOMEM;
279                                 break;
280                         }
281
282 #define BE_COPY_NAME(entry, src)        \
283         strlcpy((entry)->name, (src), sizeof((entry)->name))
284                         if (BE_COPY_NAME(newentry, name) >=
285                             sizeof(newentry->name)) {
286                                 /* Shouldn't happen. */
287                                 free(newentry);
288                                 err = ENAMETOOLONG;
289                                 break;
290                         }
291 #undef BE_COPY_NAME
292
293                         /*
294                          * We're building up a SLIST here to make sure both that
295                          * we get the order right and so that we don't
296                          * inadvertently observe the wrong state by promoting
297                          * datasets while we're still walking the tree.  The
298                          * latter can lead to situations where we promote a BE
299                          * then effectively demote it again.
300                          */
301                         SLIST_INSERT_HEAD(&bdd->promotelist, newentry, link);
302                 }
303                 nvlist_free(nvl);
304         }
305         zfs_close(zfs_hdl);
306         return (err);
307 }
308
309 /*
310  * This is called before a destroy, so that any datasets(environments) that are
311  * dependent on this one get promoted before destroying the target.
312  */
313 static int
314 be_promote_dependent_clones(zfs_handle_t *zfs_hdl, struct be_destroy_data *bdd)
315 {
316         int err;
317         zfs_handle_t *clone;
318         struct promote_entry *entry;
319
320         snprintf(bdd->target_name, BE_MAXPATHLEN, "%s/", zfs_get_name(zfs_hdl));
321         err = zfs_iter_dependents(zfs_hdl, true, be_dependent_clone_cb, bdd);
322
323         /*
324          * Drain the list and walk away from it if we're only deleting a
325          * snapshot.
326          */
327         if (bdd->snapname != NULL && !SLIST_EMPTY(&bdd->promotelist))
328                 err = BE_ERR_HASCLONES;
329         while (!SLIST_EMPTY(&bdd->promotelist)) {
330                 entry = SLIST_FIRST(&bdd->promotelist);
331                 SLIST_REMOVE_HEAD(&bdd->promotelist, link);
332
333 #define ZFS_GRAB_CLONE()        \
334         zfs_open(bdd->lbh->lzh, entry->name, ZFS_TYPE_FILESYSTEM)
335                 /*
336                  * Just skip this part on error, we still want to clean up the
337                  * promotion list after the first error.  We'll then preserve it
338                  * all the way back.
339                  */
340                 if (err == 0 && (clone = ZFS_GRAB_CLONE()) != NULL) {
341                         err = zfs_promote(clone);
342                         if (err != 0)
343                                 err = BE_ERR_DESTROYMNT;
344                         zfs_close(clone);
345                 }
346 #undef ZFS_GRAB_CLONE
347                 free(entry);
348         }
349
350         return (err);
351 }
352
353 static int
354 be_destroy_cb(zfs_handle_t *zfs_hdl, void *data)
355 {
356         char path[BE_MAXPATHLEN];
357         struct be_destroy_data *bdd;
358         zfs_handle_t *snap;
359         int err;
360
361         bdd = (struct be_destroy_data *)data;
362         if (bdd->snapname == NULL) {
363                 err = zfs_iter_children(zfs_hdl, be_destroy_cb, data);
364                 if (err != 0)
365                         return (err);
366                 return (zfs_destroy(zfs_hdl, false));
367         }
368         /* If we're dealing with snapshots instead, delete that one alone */
369         err = zfs_iter_filesystems(zfs_hdl, be_destroy_cb, data);
370         if (err != 0)
371                 return (err);
372         /*
373          * This part is intentionally glossing over any potential errors,
374          * because there's a lot less potential for errors when we're cleaning
375          * up snapshots rather than a full deep BE.  The primary error case
376          * here being if the snapshot doesn't exist in the first place, which
377          * the caller will likely deem insignificant as long as it doesn't
378          * exist after the call.  Thus, such a missing snapshot shouldn't jam
379          * up the destruction.
380          */
381         snprintf(path, sizeof(path), "%s@%s", zfs_get_name(zfs_hdl),
382             bdd->snapname);
383         if (!zfs_dataset_exists(bdd->lbh->lzh, path, ZFS_TYPE_SNAPSHOT))
384                 return (0);
385         snap = zfs_open(bdd->lbh->lzh, path, ZFS_TYPE_SNAPSHOT);
386         if (snap != NULL)
387                 zfs_destroy(snap, false);
388         return (0);
389 }
390
391 #define BE_DESTROY_WANTORIGIN   (BE_DESTROY_ORIGIN | BE_DESTROY_AUTOORIGIN)
392 /*
393  * Destroy the boot environment or snapshot specified by the name
394  * parameter. Options are or'd together with the possible values:
395  * BE_DESTROY_FORCE : forces operation on mounted datasets
396  * BE_DESTROY_ORIGIN: destroy the origin snapshot as well
397  */
398 static int
399 be_destroy_internal(libbe_handle_t *lbh, const char *name, int options,
400     bool odestroyer)
401 {
402         struct be_destroy_data bdd;
403         char origin[BE_MAXPATHLEN], path[BE_MAXPATHLEN];
404         zfs_handle_t *fs;
405         char *snapdelim;
406         int err, force, mounted;
407         size_t rootlen;
408
409         bdd.lbh = lbh;
410         bdd.snapname = NULL;
411         SLIST_INIT(&bdd.promotelist);
412         force = options & BE_DESTROY_FORCE;
413         *origin = '\0';
414
415         be_root_concat(lbh, name, path);
416
417         if ((snapdelim = strchr(path, '@')) == NULL) {
418                 if (!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_FILESYSTEM))
419                         return (set_error(lbh, BE_ERR_NOENT));
420
421                 if (strcmp(path, lbh->rootfs) == 0 ||
422                     strcmp(path, lbh->bootfs) == 0)
423                         return (set_error(lbh, BE_ERR_DESTROYACT));
424
425                 fs = zfs_open(lbh->lzh, path, ZFS_TYPE_FILESYSTEM);
426                 if (fs == NULL)
427                         return (set_error(lbh, BE_ERR_ZFSOPEN));
428
429                 /* Don't destroy a mounted dataset unless force is specified */
430                 if ((mounted = zfs_is_mounted(fs, NULL)) != 0) {
431                         if (force) {
432                                 zfs_unmount(fs, NULL, 0);
433                         } else {
434                                 free(bdd.snapname);
435                                 return (set_error(lbh, BE_ERR_DESTROYMNT));
436                         }
437                 }
438         } else {
439                 /*
440                  * If we're initially destroying a snapshot, origin options do
441                  * not make sense.  If we're destroying the origin snapshot of
442                  * a BE, we want to maintain the options in case we need to
443                  * fake success after failing to promote.
444                  */
445                 if (!odestroyer)
446                         options &= ~BE_DESTROY_WANTORIGIN;
447                 if (!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_SNAPSHOT))
448                         return (set_error(lbh, BE_ERR_NOENT));
449
450                 bdd.snapname = strdup(snapdelim + 1);
451                 if (bdd.snapname == NULL)
452                         return (set_error(lbh, BE_ERR_NOMEM));
453                 *snapdelim = '\0';
454                 fs = zfs_open(lbh->lzh, path, ZFS_TYPE_DATASET);
455                 if (fs == NULL) {
456                         free(bdd.snapname);
457                         return (set_error(lbh, BE_ERR_ZFSOPEN));
458                 }
459         }
460
461         /*
462          * Whether we're destroying a BE or a single snapshot, we need to walk
463          * the tree of what we're going to destroy and promote everything in our
464          * path so that we can make it happen.
465          */
466         if ((err = be_promote_dependent_clones(fs, &bdd)) != 0) {
467                 free(bdd.snapname);
468
469                 /*
470                  * If we're just destroying the origin of some other dataset
471                  * we were invoked to destroy, then we just ignore
472                  * BE_ERR_HASCLONES and return success unless the caller wanted
473                  * to force the issue.
474                  */
475                 if (odestroyer && err == BE_ERR_HASCLONES &&
476                     (options & BE_DESTROY_AUTOORIGIN) != 0)
477                         return (0);
478                 return (set_error(lbh, err));
479         }
480
481         /*
482          * This was deferred until after we promote all of the derivatives so
483          * that we grab the new origin after everything's settled down.
484          */
485         if ((options & BE_DESTROY_WANTORIGIN) != 0 &&
486             zfs_prop_get(fs, ZFS_PROP_ORIGIN, origin, sizeof(origin),
487             NULL, NULL, 0, 1) != 0 &&
488             (options & BE_DESTROY_ORIGIN) != 0)
489                 return (set_error(lbh, BE_ERR_NOORIGIN));
490
491         /*
492          * If the caller wants auto-origin destruction and the origin
493          * name matches one of our automatically created snapshot names
494          * (i.e. strftime("%F-%T") with a serial at the end), then
495          * we'll set the DESTROY_ORIGIN flag and nuke it
496          * be_is_auto_snapshot_name is exported from libbe(3) so that
497          * the caller can determine if it needs to warn about the origin
498          * not being destroyed or not.
499          */
500         if ((options & BE_DESTROY_AUTOORIGIN) != 0 && *origin != '\0' &&
501             be_is_auto_snapshot_name(lbh, origin))
502                 options |= BE_DESTROY_ORIGIN;
503
504         err = be_destroy_cb(fs, &bdd);
505         zfs_close(fs);
506         free(bdd.snapname);
507         if (err != 0) {
508                 /* Children are still present or the mount is referenced */
509                 if (err == EBUSY)
510                         return (set_error(lbh, BE_ERR_DESTROYMNT));
511                 return (set_error(lbh, BE_ERR_UNKNOWN));
512         }
513
514         if ((options & BE_DESTROY_ORIGIN) == 0)
515                 return (0);
516
517         /* The origin can't possibly be shorter than the BE root */
518         rootlen = strlen(lbh->root);
519         if (*origin == '\0' || strlen(origin) <= rootlen + 1)
520                 return (set_error(lbh, BE_ERR_INVORIGIN));
521
522         /*
523          * We'll be chopping off the BE root and running this back through
524          * be_destroy, so that we properly handle the origin snapshot whether
525          * it be that of a deep BE or not.
526          */
527         if (strncmp(origin, lbh->root, rootlen) != 0 || origin[rootlen] != '/')
528                 return (0);
529
530         return (be_destroy_internal(lbh, origin + rootlen + 1,
531             options & ~BE_DESTROY_ORIGIN, true));
532 }
533
534 int
535 be_destroy(libbe_handle_t *lbh, const char *name, int options)
536 {
537
538         /*
539          * The consumer must not set both BE_DESTROY_AUTOORIGIN and
540          * BE_DESTROY_ORIGIN.  Internally, we'll set the latter from the former.
541          * The latter should imply that we must succeed at destroying the
542          * origin, or complain otherwise.
543          */
544         if ((options & BE_DESTROY_WANTORIGIN) == BE_DESTROY_WANTORIGIN)
545                 return (set_error(lbh, BE_ERR_UNKNOWN));
546         return (be_destroy_internal(lbh, name, options, false));
547 }
548
549 static void
550 be_setup_snapshot_name(libbe_handle_t *lbh, char *buf, size_t buflen)
551 {
552         time_t rawtime;
553         int len, serial;
554
555         time(&rawtime);
556         len = strlen(buf);
557         len += strftime(buf + len, buflen - len, "@%F-%T", localtime(&rawtime));
558         /* No room for serial... caller will do its best */
559         if (buflen - len < 2)
560                 return;
561
562         for (serial = 0; serial < BE_SNAP_SERIAL_MAX; ++serial) {
563                 snprintf(buf + len, buflen - len, "-%d", serial);
564                 if (!zfs_dataset_exists(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT))
565                         return;
566         }
567 }
568
569 bool
570 be_is_auto_snapshot_name(libbe_handle_t *lbh __unused, const char *name)
571 {
572         const char *snap;
573         int day, hour, minute, month, second, serial, year;
574
575         if ((snap = strchr(name, '@')) == NULL)
576                 return (false);
577         ++snap;
578         /* We'll grab the individual components and do some light validation. */
579         if (sscanf(snap, "%d-%d-%d-%d:%d:%d-%d", &year, &month, &day, &hour,
580             &minute, &second, &serial) != 7)
581                 return (false);
582         return (year >= 1970) && (month >= 1 && month <= 12) &&
583             (day >= 1 && day <= 31) && (hour >= 0 && hour <= 23) &&
584             (minute >= 0 && minute <= 59) && (second >= 0 && second <= 60) &&
585             serial >= 0;
586 }
587
588 int
589 be_snapshot(libbe_handle_t *lbh, const char *source, const char *snap_name,
590     bool recursive, char *result)
591 {
592         char buf[BE_MAXPATHLEN];
593         int err;
594
595         be_root_concat(lbh, source, buf);
596
597         if ((err = be_exists(lbh, buf)) != 0)
598                 return (set_error(lbh, err));
599
600         if (snap_name != NULL) {
601                 if (strlcat(buf, "@", sizeof(buf)) >= sizeof(buf))
602                         return (set_error(lbh, BE_ERR_INVALIDNAME));
603
604                 if (strlcat(buf, snap_name, sizeof(buf)) >= sizeof(buf))
605                         return (set_error(lbh, BE_ERR_INVALIDNAME));
606
607                 if (result != NULL)
608                         snprintf(result, BE_MAXPATHLEN, "%s@%s", source,
609                             snap_name);
610         } else {
611                 be_setup_snapshot_name(lbh, buf, sizeof(buf));
612
613                 if (result != NULL && strlcpy(result, strrchr(buf, '/') + 1,
614                     sizeof(buf)) >= sizeof(buf))
615                         return (set_error(lbh, BE_ERR_INVALIDNAME));
616         }
617         if ((err = zfs_snapshot(lbh->lzh, buf, recursive, NULL)) != 0) {
618                 switch (err) {
619                 case EZFS_INVALIDNAME:
620                         return (set_error(lbh, BE_ERR_INVALIDNAME));
621
622                 default:
623                         /*
624                          * The other errors that zfs_ioc_snapshot might return
625                          * shouldn't happen if we've set things up properly, so
626                          * we'll gloss over them and call it UNKNOWN as it will
627                          * require further triage.
628                          */
629                         if (errno == ENOTSUP)
630                                 return (set_error(lbh, BE_ERR_NOPOOL));
631                         return (set_error(lbh, BE_ERR_UNKNOWN));
632                 }
633         }
634
635         return (BE_ERR_SUCCESS);
636 }
637
638
639 /*
640  * Create the boot environment specified by the name parameter
641  */
642 int
643 be_create(libbe_handle_t *lbh, const char *name)
644 {
645         int err;
646
647         err = be_create_from_existing(lbh, name, be_active_path(lbh));
648
649         return (set_error(lbh, err));
650 }
651
652 static int
653 be_deep_clone_prop(int prop, void *cb)
654 {
655         int err;
656         struct libbe_dccb *dccb;
657         zprop_source_t src;
658         char pval[BE_MAXPATHLEN];
659         char source[BE_MAXPATHLEN];
660         char *val;
661
662         dccb = cb;
663         /* Skip some properties we don't want to touch */
664         if (prop == ZFS_PROP_CANMOUNT)
665                 return (ZPROP_CONT);
666
667         /* Don't copy readonly properties */
668         if (zfs_prop_readonly(prop))
669                 return (ZPROP_CONT);
670
671         if ((err = zfs_prop_get(dccb->zhp, prop, (char *)&pval,
672             sizeof(pval), &src, (char *)&source, sizeof(source), false)))
673                 /* Just continue if we fail to read a property */
674                 return (ZPROP_CONT);
675
676         /*
677          * Only copy locally defined or received properties.  This continues
678          * to avoid temporary/default/local properties intentionally without
679          * breaking received datasets.
680          */
681         if (src != ZPROP_SRC_LOCAL && src != ZPROP_SRC_RECEIVED)
682                 return (ZPROP_CONT);
683
684         /* Augment mountpoint with altroot, if needed */
685         val = pval;
686         if (prop == ZFS_PROP_MOUNTPOINT)
687                 val = be_mountpoint_augmented(dccb->lbh, val);
688
689         nvlist_add_string(dccb->props, zfs_prop_to_name(prop), val);
690
691         return (ZPROP_CONT);
692 }
693
694 /*
695  * Return the corresponding boot environment path for a given
696  * dataset path, the constructed path is placed in 'result'.
697  *
698  * example: say our new boot environment name is 'bootenv' and
699  *          the dataset path is 'zroot/ROOT/default/data/set'.
700  *
701  * result should produce: 'zroot/ROOT/bootenv/data/set'
702  */
703 static int
704 be_get_path(struct libbe_deep_clone *ldc, const char *dspath, char *result, int result_size)
705 {
706         char *pos;
707         char *child_dataset;
708
709         /* match the root path for the boot environments */
710         pos = strstr(dspath, ldc->lbh->root);
711
712         /* no match, different pools? */
713         if (pos == NULL)
714                 return (BE_ERR_BADPATH);
715
716         /* root path of the new boot environment */
717         snprintf(result, result_size, "%s/%s", ldc->lbh->root, ldc->bename);
718
719         /* gets us to the parent dataset, the +1 consumes a trailing slash */
720         pos += strlen(ldc->lbh->root) + 1;
721
722         /* skip the parent dataset */
723         if ((child_dataset = strchr(pos, '/')) != NULL)
724                 strlcat(result, child_dataset, result_size);
725
726         return (BE_ERR_SUCCESS);
727 }
728
729 static int
730 be_clone_cb(zfs_handle_t *ds, void *data)
731 {
732         int err;
733         char be_path[BE_MAXPATHLEN];
734         char snap_path[BE_MAXPATHLEN];
735         const char *dspath;
736         zfs_handle_t *snap_hdl;
737         nvlist_t *props;
738         struct libbe_deep_clone *ldc;
739         struct libbe_dccb dccb;
740
741         ldc = (struct libbe_deep_clone *)data;
742         dspath = zfs_get_name(ds);
743
744         snprintf(snap_path, sizeof(snap_path), "%s@%s", dspath, ldc->snapname);
745
746         /* construct the boot environment path from the dataset we're cloning */
747         if (be_get_path(ldc, dspath, be_path, sizeof(be_path)) != BE_ERR_SUCCESS)
748                 return (set_error(ldc->lbh, BE_ERR_UNKNOWN));
749
750         /* the dataset to be created (i.e. the boot environment) already exists */
751         if (zfs_dataset_exists(ldc->lbh->lzh, be_path, ZFS_TYPE_DATASET))
752                 return (set_error(ldc->lbh, BE_ERR_EXISTS));
753
754         /* no snapshot found for this dataset, silently skip it */
755         if (!zfs_dataset_exists(ldc->lbh->lzh, snap_path, ZFS_TYPE_SNAPSHOT))
756                 return (0);
757
758         if ((snap_hdl =
759             zfs_open(ldc->lbh->lzh, snap_path, ZFS_TYPE_SNAPSHOT)) == NULL)
760                 return (set_error(ldc->lbh, BE_ERR_ZFSOPEN));
761
762         nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
763         nvlist_add_string(props, "canmount", "noauto");
764
765         dccb.lbh = ldc->lbh;
766         dccb.zhp = ds;
767         dccb.props = props;
768         if (zprop_iter(be_deep_clone_prop, &dccb, B_FALSE, B_FALSE,
769             ZFS_TYPE_FILESYSTEM) == ZPROP_INVAL)
770                 return (-1);
771
772         if ((err = zfs_clone(snap_hdl, be_path, props)) != 0)
773                 return (set_error(ldc->lbh, BE_ERR_ZFSCLONE));
774
775         nvlist_free(props);
776         zfs_close(snap_hdl);
777
778         if (ldc->depth_limit == -1 || ldc->depth < ldc->depth_limit) {
779                 ldc->depth++;
780                 err = zfs_iter_filesystems(ds, be_clone_cb, ldc);
781                 ldc->depth--;
782         }
783
784         return (set_error(ldc->lbh, err));
785 }
786
787 /*
788  * Create a boot environment with a given name from a given snapshot.
789  * Snapshots can be in the format 'zroot/ROOT/default@snapshot' or
790  * 'default@snapshot'. In the latter case, 'default@snapshot' will be prepended
791  * with the root path that libbe was initailized with.
792 */
793 static int
794 be_clone(libbe_handle_t *lbh, const char *bename, const char *snapshot, int depth)
795 {
796         int err;
797         char snap_path[BE_MAXPATHLEN];
798         char *parentname, *snapname;
799         zfs_handle_t *parent_hdl;
800         struct libbe_deep_clone ldc;
801
802         /* ensure the boot environment name is valid */
803         if ((err = be_validate_name(lbh, bename)) != 0)
804                 return (set_error(lbh, err));
805
806         /*
807          * prepend the boot environment root path if we're
808          * given a partial snapshot name.
809          */
810         if ((err = be_root_concat(lbh, snapshot, snap_path)) != 0)
811                 return (set_error(lbh, err));
812
813         /* ensure the snapshot exists */
814         if ((err = be_validate_snap(lbh, snap_path)) != 0)
815                 return (set_error(lbh, err));
816
817         /* get a copy of the snapshot path so we can disect it */
818         if ((parentname = strdup(snap_path)) == NULL)
819                 return (set_error(lbh, BE_ERR_UNKNOWN));
820
821         /* split dataset name from snapshot name */
822         snapname = strchr(parentname, '@');
823         if (snapname == NULL) {
824                 free(parentname);
825                 return (set_error(lbh, BE_ERR_UNKNOWN));
826         }
827         *snapname = '\0';
828         snapname++;
829
830         /* set-up the boot environment */
831         ldc.lbh = lbh;
832         ldc.bename = bename;
833         ldc.snapname = snapname;
834         ldc.depth = 0;
835         ldc.depth_limit = depth;
836
837         /* the boot environment will be cloned from this dataset */
838         parent_hdl = zfs_open(lbh->lzh, parentname, ZFS_TYPE_DATASET);
839
840         /* create the boot environment */
841         err = be_clone_cb(parent_hdl, &ldc);
842
843         free(parentname);
844         return (set_error(lbh, err));
845 }
846
847 /*
848  * Create a boot environment from pre-existing snapshot, specifying a depth.
849  */
850 int be_create_depth(libbe_handle_t *lbh, const char *bename,
851                     const char *snap, int depth)
852 {
853         return (be_clone(lbh, bename, snap, depth));
854 }
855
856 /*
857  * Create the boot environment from pre-existing snapshot
858  */
859 int
860 be_create_from_existing_snap(libbe_handle_t *lbh, const char *bename,
861     const char *snap)
862 {
863         return (be_clone(lbh, bename, snap, -1));
864 }
865
866
867 /*
868  * Create a boot environment from an existing boot environment
869  */
870 int
871 be_create_from_existing(libbe_handle_t *lbh, const char *bename, const char *old)
872 {
873         int err;
874         char snap[BE_MAXPATHLEN];
875
876         if ((err = be_snapshot(lbh, old, NULL, true, snap)) != 0)
877                 return (set_error(lbh, err));
878
879         err = be_clone(lbh, bename, snap, -1);
880
881         return (set_error(lbh, err));
882 }
883
884
885 /*
886  * Verifies that a snapshot has a valid name, exists, and has a mountpoint of
887  * '/'. Returns BE_ERR_SUCCESS (0), upon success, or the relevant BE_ERR_* upon
888  * failure. Does not set the internal library error state.
889  */
890 int
891 be_validate_snap(libbe_handle_t *lbh, const char *snap_name)
892 {
893
894         if (strlen(snap_name) >= BE_MAXPATHLEN)
895                 return (BE_ERR_PATHLEN);
896
897         if (!zfs_name_valid(snap_name, ZFS_TYPE_SNAPSHOT))
898                 return (BE_ERR_INVALIDNAME);
899
900         if (!zfs_dataset_exists(lbh->lzh, snap_name,
901             ZFS_TYPE_SNAPSHOT))
902                 return (BE_ERR_NOENT);
903
904         return (BE_ERR_SUCCESS);
905 }
906
907
908 /*
909  * Idempotently appends the name argument to the root boot environment path
910  * and copies the resulting string into the result buffer (which is assumed
911  * to be at least BE_MAXPATHLEN characters long. Returns BE_ERR_SUCCESS upon
912  * success, BE_ERR_PATHLEN if the resulting path is longer than BE_MAXPATHLEN,
913  * or BE_ERR_INVALIDNAME if the name is a path that does not begin with
914  * zfs_be_root. Does not set internal library error state.
915  */
916 int
917 be_root_concat(libbe_handle_t *lbh, const char *name, char *result)
918 {
919         size_t name_len, root_len;
920
921         name_len = strlen(name);
922         root_len = strlen(lbh->root);
923
924         /* Act idempotently; return be name if it is already a full path */
925         if (strrchr(name, '/') != NULL) {
926                 if (strstr(name, lbh->root) != name)
927                         return (BE_ERR_INVALIDNAME);
928
929                 if (name_len >= BE_MAXPATHLEN)
930                         return (BE_ERR_PATHLEN);
931
932                 strlcpy(result, name, BE_MAXPATHLEN);
933                 return (BE_ERR_SUCCESS);
934         } else if (name_len + root_len + 1 < BE_MAXPATHLEN) {
935                 snprintf(result, BE_MAXPATHLEN, "%s/%s", lbh->root,
936                     name);
937                 return (BE_ERR_SUCCESS);
938         }
939
940         return (BE_ERR_PATHLEN);
941 }
942
943
944 /*
945  * Verifies the validity of a boot environment name (A-Za-z0-9-_.). Returns
946  * BE_ERR_SUCCESS (0) if name is valid, otherwise returns BE_ERR_INVALIDNAME
947  * or BE_ERR_PATHLEN.
948  * Does not set internal library error state.
949  */
950 int
951 be_validate_name(libbe_handle_t *lbh, const char *name)
952 {
953
954         /*
955          * Impose the additional restriction that the entire dataset name must
956          * not exceed the maximum length of a dataset, i.e. MAXNAMELEN.
957          */
958         if (strlen(lbh->root) + 1 + strlen(name) > MAXNAMELEN)
959                 return (BE_ERR_PATHLEN);
960
961         if (!zfs_name_valid(name, ZFS_TYPE_DATASET))
962                 return (BE_ERR_INVALIDNAME);
963
964         return (BE_ERR_SUCCESS);
965 }
966
967
968 /*
969  * usage
970  */
971 int
972 be_rename(libbe_handle_t *lbh, const char *old, const char *new)
973 {
974         char full_old[BE_MAXPATHLEN];
975         char full_new[BE_MAXPATHLEN];
976         zfs_handle_t *zfs_hdl;
977         int err;
978
979         /*
980          * be_validate_name is documented not to set error state, so we should
981          * do so here.
982          */
983         if ((err = be_validate_name(lbh, new)) != 0)
984                 return (set_error(lbh, err));
985         if ((err = be_root_concat(lbh, old, full_old)) != 0)
986                 return (set_error(lbh, err));
987         if ((err = be_root_concat(lbh, new, full_new)) != 0)
988                 return (set_error(lbh, err));
989
990         if (!zfs_dataset_exists(lbh->lzh, full_old, ZFS_TYPE_DATASET))
991                 return (set_error(lbh, BE_ERR_NOENT));
992
993         if (zfs_dataset_exists(lbh->lzh, full_new, ZFS_TYPE_DATASET))
994                 return (set_error(lbh, BE_ERR_EXISTS));
995
996         if ((zfs_hdl = zfs_open(lbh->lzh, full_old,
997             ZFS_TYPE_FILESYSTEM)) == NULL)
998                 return (set_error(lbh, BE_ERR_ZFSOPEN));
999
1000         /* recurse, nounmount, forceunmount */
1001         struct renameflags flags = {
1002                 .nounmount = 1,
1003         };
1004         err = zfs_rename(zfs_hdl, full_new, flags);
1005
1006         zfs_close(zfs_hdl);
1007         if (err != 0)
1008                 return (set_error(lbh, BE_ERR_UNKNOWN));
1009         return (0);
1010 }
1011
1012
1013 int
1014 be_export(libbe_handle_t *lbh, const char *bootenv, int fd)
1015 {
1016         char snap_name[BE_MAXPATHLEN];
1017         char buf[BE_MAXPATHLEN];
1018         zfs_handle_t *zfs;
1019         sendflags_t flags = { 0 };
1020         int err;
1021
1022         if ((err = be_snapshot(lbh, bootenv, NULL, true, snap_name)) != 0)
1023                 /* Use the error set by be_snapshot */
1024                 return (err);
1025
1026         be_root_concat(lbh, snap_name, buf);
1027
1028         if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL)
1029                 return (set_error(lbh, BE_ERR_ZFSOPEN));
1030
1031         err = zfs_send_one(zfs, NULL, fd, &flags, /* redactbook */ NULL);
1032         zfs_close(zfs);
1033
1034         return (err);
1035 }
1036
1037
1038 int
1039 be_import(libbe_handle_t *lbh, const char *bootenv, int fd)
1040 {
1041         char buf[BE_MAXPATHLEN];
1042         nvlist_t *props;
1043         zfs_handle_t *zfs;
1044         recvflags_t flags = { .nomount = 1 };
1045         int err;
1046
1047         be_root_concat(lbh, bootenv, buf);
1048
1049         if ((err = zfs_receive(lbh->lzh, buf, NULL, &flags, fd, NULL)) != 0) {
1050                 switch (err) {
1051                 case EINVAL:
1052                         return (set_error(lbh, BE_ERR_NOORIGIN));
1053                 case ENOENT:
1054                         return (set_error(lbh, BE_ERR_NOENT));
1055                 case EIO:
1056                         return (set_error(lbh, BE_ERR_IO));
1057                 default:
1058                         return (set_error(lbh, BE_ERR_UNKNOWN));
1059                 }
1060         }
1061
1062         if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_FILESYSTEM)) == NULL)
1063                 return (set_error(lbh, BE_ERR_ZFSOPEN));
1064
1065         nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
1066         nvlist_add_string(props, "canmount", "noauto");
1067         nvlist_add_string(props, "mountpoint", "none");
1068
1069         err = zfs_prop_set_list(zfs, props);
1070         nvlist_free(props);
1071
1072         zfs_close(zfs);
1073
1074         if (err != 0)
1075                 return (set_error(lbh, BE_ERR_UNKNOWN));
1076
1077         return (0);
1078 }
1079
1080 #if SOON
1081 static int
1082 be_create_child_noent(libbe_handle_t *lbh, const char *active,
1083     const char *child_path)
1084 {
1085         nvlist_t *props;
1086         zfs_handle_t *zfs;
1087         int err;
1088
1089         nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
1090         nvlist_add_string(props, "canmount", "noauto");
1091         nvlist_add_string(props, "mountpoint", child_path);
1092
1093         /* Create */
1094         if ((err = zfs_create(lbh->lzh, active, ZFS_TYPE_DATASET,
1095             props)) != 0) {
1096                 switch (err) {
1097                 case EZFS_EXISTS:
1098                         return (set_error(lbh, BE_ERR_EXISTS));
1099                 case EZFS_NOENT:
1100                         return (set_error(lbh, BE_ERR_NOENT));
1101                 case EZFS_BADTYPE:
1102                 case EZFS_BADVERSION:
1103                         return (set_error(lbh, BE_ERR_NOPOOL));
1104                 case EZFS_BADPROP:
1105                 default:
1106                         /* We set something up wrong, probably... */
1107                         return (set_error(lbh, BE_ERR_UNKNOWN));
1108                 }
1109         }
1110         nvlist_free(props);
1111
1112         if ((zfs = zfs_open(lbh->lzh, active, ZFS_TYPE_DATASET)) == NULL)
1113                 return (set_error(lbh, BE_ERR_ZFSOPEN));
1114
1115         /* Set props */
1116         if ((err = zfs_prop_set(zfs, "canmount", "noauto")) != 0) {
1117                 zfs_close(zfs);
1118                 /*
1119                  * Similar to other cases, this shouldn't fail unless we've
1120                  * done something wrong.  This is a new dataset that shouldn't
1121                  * have been mounted anywhere between creation and now.
1122                  */
1123                 if (err == EZFS_NOMEM)
1124                         return (set_error(lbh, BE_ERR_NOMEM));
1125                 return (set_error(lbh, BE_ERR_UNKNOWN));
1126         }
1127         zfs_close(zfs);
1128         return (BE_ERR_SUCCESS);
1129 }
1130
1131 static int
1132 be_create_child_cloned(libbe_handle_t *lbh, const char *active)
1133 {
1134         char buf[BE_MAXPATHLEN], tmp[BE_MAXPATHLEN];;
1135         zfs_handle_t *zfs;
1136         int err;
1137
1138         /* XXX TODO ? */
1139
1140         /*
1141          * Establish if the existing path is a zfs dataset or just
1142          * the subdirectory of one
1143          */
1144         strlcpy(tmp, "tmp/be_snap.XXXXX", sizeof(tmp));
1145         if (mktemp(tmp) == NULL)
1146                 return (set_error(lbh, BE_ERR_UNKNOWN));
1147
1148         be_root_concat(lbh, tmp, buf);
1149         printf("Here %s?\n", buf);
1150         if ((err = zfs_snapshot(lbh->lzh, buf, false, NULL)) != 0) {
1151                 switch (err) {
1152                 case EZFS_INVALIDNAME:
1153                         return (set_error(lbh, BE_ERR_INVALIDNAME));
1154
1155                 default:
1156                         /*
1157                          * The other errors that zfs_ioc_snapshot might return
1158                          * shouldn't happen if we've set things up properly, so
1159                          * we'll gloss over them and call it UNKNOWN as it will
1160                          * require further triage.
1161                          */
1162                         if (errno == ENOTSUP)
1163                                 return (set_error(lbh, BE_ERR_NOPOOL));
1164                         return (set_error(lbh, BE_ERR_UNKNOWN));
1165                 }
1166         }
1167
1168         /* Clone */
1169         if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL)
1170                 return (BE_ERR_ZFSOPEN);
1171
1172         if ((err = zfs_clone(zfs, active, NULL)) != 0)
1173                 /* XXX TODO correct error */
1174                 return (set_error(lbh, BE_ERR_UNKNOWN));
1175
1176         /* set props */
1177         zfs_close(zfs);
1178         return (BE_ERR_SUCCESS);
1179 }
1180
1181 int
1182 be_add_child(libbe_handle_t *lbh, const char *child_path, bool cp_if_exists)
1183 {
1184         struct stat sb;
1185         char active[BE_MAXPATHLEN], buf[BE_MAXPATHLEN];
1186         nvlist_t *props;
1187         const char *s;
1188
1189         /* Require absolute paths */
1190         if (*child_path != '/')
1191                 return (set_error(lbh, BE_ERR_BADPATH));
1192
1193         strlcpy(active, be_active_path(lbh), BE_MAXPATHLEN);
1194         strcpy(buf, active);
1195
1196         /* Create non-mountable parent dataset(s) */
1197         s = child_path;
1198         for (char *p; (p = strchr(s+1, '/')) != NULL; s = p) {
1199                 size_t len = p - s;
1200                 strncat(buf, s, len);
1201
1202                 nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP);
1203                 nvlist_add_string(props, "canmount", "off");
1204                 nvlist_add_string(props, "mountpoint", "none");
1205                 zfs_create(lbh->lzh, buf, ZFS_TYPE_DATASET, props);
1206                 nvlist_free(props);
1207         }
1208
1209         /* Path does not exist as a descendent of / yet */
1210         if (strlcat(active, child_path, BE_MAXPATHLEN) >= BE_MAXPATHLEN)
1211                 return (set_error(lbh, BE_ERR_PATHLEN));
1212
1213         if (stat(child_path, &sb) != 0) {
1214                 /* Verify that error is ENOENT */
1215                 if (errno != ENOENT)
1216                         return (set_error(lbh, BE_ERR_UNKNOWN));
1217                 return (be_create_child_noent(lbh, active, child_path));
1218         } else if (cp_if_exists)
1219                 /* Path is already a descendent of / and should be copied */
1220                 return (be_create_child_cloned(lbh, active));
1221         return (set_error(lbh, BE_ERR_EXISTS));
1222 }
1223 #endif  /* SOON */
1224
1225 /*
1226  * Deactivate old BE dataset; currently just sets canmount=noauto or
1227  * resets boot once configuration.
1228  */
1229 int
1230 be_deactivate(libbe_handle_t *lbh, const char *ds, bool temporary)
1231 {
1232         zfs_handle_t *zfs;
1233
1234         if (temporary) {
1235                 return (lzbe_set_boot_device(
1236                     zpool_get_name(lbh->active_phandle), lzbe_add, NULL));
1237         }
1238
1239         if ((zfs = zfs_open(lbh->lzh, ds, ZFS_TYPE_DATASET)) == NULL)
1240                 return (1);
1241         if (zfs_prop_set(zfs, "canmount", "noauto") != 0)
1242                 return (1);
1243         zfs_close(zfs);
1244         return (0);
1245 }
1246
1247 int
1248 be_activate(libbe_handle_t *lbh, const char *bootenv, bool temporary)
1249 {
1250         char be_path[BE_MAXPATHLEN];
1251         nvlist_t *dsprops;
1252         char *origin;
1253         zfs_handle_t *zhp;
1254         int err;
1255
1256         be_root_concat(lbh, bootenv, be_path);
1257
1258         /* Note: be_exists fails if mountpoint is not / */
1259         if ((err = be_exists(lbh, be_path)) != 0)
1260                 return (set_error(lbh, err));
1261
1262         if (temporary) {
1263                 return (lzbe_set_boot_device(
1264                     zpool_get_name(lbh->active_phandle), lzbe_add, be_path));
1265         } else {
1266                 if (be_deactivate(lbh, lbh->bootfs, false) != 0)
1267                         return (-1);
1268
1269                 /* Obtain bootenv zpool */
1270                 err = zpool_set_prop(lbh->active_phandle, "bootfs", be_path);
1271                 if (err)
1272                         return (-1);
1273
1274                 zhp = zfs_open(lbh->lzh, be_path, ZFS_TYPE_FILESYSTEM);
1275                 if (zhp == NULL)
1276                         return (-1);
1277
1278                 if (be_prop_list_alloc(&dsprops) != 0)
1279                         return (-1);
1280
1281                 if (be_get_dataset_props(lbh, be_path, dsprops) != 0) {
1282                         nvlist_free(dsprops);
1283                         return (-1);
1284                 }
1285
1286                 if (nvlist_lookup_string(dsprops, "origin", &origin) == 0)
1287                         err = zfs_promote(zhp);
1288                 nvlist_free(dsprops);
1289
1290                 zfs_close(zhp);
1291
1292                 if (err)
1293                         return (-1);
1294         }
1295
1296         return (BE_ERR_SUCCESS);
1297 }