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