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/stat.h> 33 #include <sys/types.h> 34 35 #include <ctype.h> 36 #include <kenv.h> 37 #include <libgen.h> 38 #include <libzfs_core.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <time.h> 42 #include <unistd.h> 43 44 #include "be.h" 45 #include "be_impl.h" 46 47 #if SOON 48 static int be_create_child_noent(libbe_handle_t *lbh, const char *active, 49 const char *child_path); 50 static int be_create_child_cloned(libbe_handle_t *lbh, const char *active); 51 #endif 52 53 /* 54 * Iterator function for locating the rootfs amongst the children of the 55 * zfs_be_root set by loader(8). data is expected to be a libbe_handle_t *. 56 */ 57 static int 58 be_locate_rootfs(zfs_handle_t *chkds, void *data) 59 { 60 libbe_handle_t *lbh; 61 char *mntpoint; 62 63 lbh = (libbe_handle_t *)data; 64 if (lbh == NULL) 65 return (1); 66 67 mntpoint = NULL; 68 if (zfs_is_mounted(chkds, &mntpoint) && strcmp(mntpoint, "/") == 0) { 69 strlcpy(lbh->rootfs, zfs_get_name(chkds), BE_MAXPATHLEN + 1); 70 free(mntpoint); 71 return (1); 72 } else if(mntpoint != NULL) 73 free(mntpoint); 74 75 return (0); 76 } 77 78 /* 79 * Initializes the libbe context to operate in the root boot environment 80 * dataset, for example, zroot/ROOT. 81 */ 82 libbe_handle_t * 83 libbe_init(void) 84 { 85 struct stat sb; 86 dev_t root_dev, boot_dev; 87 libbe_handle_t *lbh; 88 zfs_handle_t *rootds; 89 char *poolname, *pos; 90 int pnamelen; 91 92 lbh = NULL; 93 poolname = pos = NULL; 94 pnamelen = 0; 95 rootds = NULL; 96 97 /* Verify that /boot and / are mounted on the same filesystem */ 98 /* TODO: use errno here?? */ 99 if (stat("/", &sb) != 0) 100 goto err; 101 102 root_dev = sb.st_dev; 103 104 if (stat("/boot", &sb) != 0) 105 goto err; 106 107 boot_dev = sb.st_dev; 108 109 if (root_dev != boot_dev) { 110 fprintf(stderr, "/ and /boot not on same device, quitting\n"); 111 goto err; 112 } 113 114 if ((lbh = calloc(1, sizeof(libbe_handle_t))) == NULL) 115 goto err; 116 117 if ((lbh->lzh = libzfs_init()) == NULL) 118 goto err; 119 120 /* Obtain path to boot environment root */ 121 if ((kenv(KENV_GET, "zfs_be_root", lbh->root, BE_MAXPATHLEN)) == -1) 122 goto err; 123 124 /* Remove leading 'zfs:' if present, otherwise use value as-is */ 125 if (strcmp(lbh->root, "zfs:") == 0) 126 strlcpy(lbh->root, strchr(lbh->root, ':') + sizeof(char), 127 BE_MAXPATHLEN + 1); 128 129 if ((pos = strchr(lbh->root, '/')) == NULL) 130 goto err; 131 132 pnamelen = pos - lbh->root; 133 poolname = malloc(pnamelen + 1); 134 if (poolname == NULL) 135 goto err; 136 137 strncpy(poolname, lbh->root, pnamelen); 138 poolname[pnamelen] = '\0'; 139 if ((lbh->active_phandle = zpool_open(lbh->lzh, poolname)) == NULL) 140 goto err; 141 142 if (zpool_get_prop(lbh->active_phandle, ZPOOL_PROP_BOOTFS, lbh->bootfs, 143 BE_MAXPATHLEN, NULL, true) != 0) 144 goto err; 145 146 /* Obtain path to boot environment rootfs (currently booted) */ 147 /* XXX Get dataset mounted at / by kenv/GUID from mountroot? */ 148 if ((rootds = zfs_open(lbh->lzh, lbh->root, ZFS_TYPE_DATASET)) == NULL) 149 goto err; 150 151 zfs_iter_filesystems(rootds, be_locate_rootfs, lbh); 152 zfs_close(rootds); 153 rootds = NULL; 154 if (*lbh->rootfs == '\0') 155 goto err; 156 157 return (lbh); 158 err: 159 if (lbh != NULL) { 160 if (lbh->active_phandle != NULL) 161 zpool_close(lbh->active_phandle); 162 if (lbh->lzh != NULL) 163 libzfs_fini(lbh->lzh); 164 free(lbh); 165 } 166 free(poolname); 167 return (NULL); 168 } 169 170 171 /* 172 * Free memory allocated by libbe_init() 173 */ 174 void 175 libbe_close(libbe_handle_t *lbh) 176 { 177 178 if (lbh->active_phandle != NULL) 179 zpool_close(lbh->active_phandle); 180 libzfs_fini(lbh->lzh); 181 free(lbh); 182 } 183 184 /* 185 * Proxy through to libzfs for the moment. 186 */ 187 void 188 be_nicenum(uint64_t num, char *buf, size_t buflen) 189 { 190 191 zfs_nicenum(num, buf, buflen); 192 } 193 194 static int 195 be_destroy_cb(zfs_handle_t *zfs_hdl, void *data) 196 { 197 int err; 198 199 if ((err = zfs_iter_children(zfs_hdl, be_destroy_cb, data)) != 0) 200 return (err); 201 if ((err = zfs_destroy(zfs_hdl, false)) != 0) 202 return (err); 203 return (0); 204 } 205 206 /* 207 * Destroy the boot environment or snapshot specified by the name 208 * parameter. Options are or'd together with the possible values: 209 * BE_DESTROY_FORCE : forces operation on mounted datasets 210 */ 211 int 212 be_destroy(libbe_handle_t *lbh, const char *name, int options) 213 { 214 zfs_handle_t *fs; 215 char path[BE_MAXPATHLEN]; 216 char *p; 217 int err, force, mounted; 218 219 p = path; 220 force = options & BE_DESTROY_FORCE; 221 err = BE_ERR_SUCCESS; 222 223 be_root_concat(lbh, name, path); 224 225 if (strchr(name, '@') == NULL) { 226 if (!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_FILESYSTEM)) 227 return (set_error(lbh, BE_ERR_NOENT)); 228 229 if (strcmp(path, lbh->rootfs) == 0) 230 return (set_error(lbh, BE_ERR_DESTROYACT)); 231 232 fs = zfs_open(lbh->lzh, p, ZFS_TYPE_FILESYSTEM); 233 } else { 234 235 if (!zfs_dataset_exists(lbh->lzh, path, ZFS_TYPE_SNAPSHOT)) 236 return (set_error(lbh, BE_ERR_NOENT)); 237 238 fs = zfs_open(lbh->lzh, p, ZFS_TYPE_SNAPSHOT); 239 } 240 241 if (fs == NULL) 242 return (set_error(lbh, BE_ERR_ZFSOPEN)); 243 244 /* Check if mounted, unmount if force is specified */ 245 if ((mounted = zfs_is_mounted(fs, NULL)) != 0) { 246 if (force) 247 zfs_unmount(fs, NULL, 0); 248 else 249 return (set_error(lbh, BE_ERR_DESTROYMNT)); 250 } 251 252 if ((err = be_destroy_cb(fs, NULL)) != 0) { 253 /* Children are still present or the mount is referenced */ 254 if (err == EBUSY) 255 return (set_error(lbh, BE_ERR_DESTROYMNT)); 256 return (set_error(lbh, BE_ERR_UNKNOWN)); 257 } 258 259 return (0); 260 } 261 262 263 int 264 be_snapshot(libbe_handle_t *lbh, const char *source, const char *snap_name, 265 bool recursive, char *result) 266 { 267 char buf[BE_MAXPATHLEN]; 268 time_t rawtime; 269 int len, err; 270 271 be_root_concat(lbh, source, buf); 272 273 if (!be_exists(lbh, buf)) 274 return (BE_ERR_NOENT); 275 276 if (snap_name != NULL) { 277 strcat(buf, "@"); 278 strcat(buf, snap_name); 279 if (result != NULL) 280 snprintf(result, BE_MAXPATHLEN, "%s@%s", source, 281 snap_name); 282 } else { 283 time(&rawtime); 284 len = strlen(buf); 285 strftime(buf + len, BE_MAXPATHLEN - len, 286 "@%F-%T", localtime(&rawtime)); 287 if (result != NULL) 288 strcpy(result, strrchr(buf, '/') + 1); 289 } 290 291 if ((err = zfs_snapshot(lbh->lzh, buf, recursive, NULL)) != 0) { 292 switch (err) { 293 case EZFS_INVALIDNAME: 294 return (set_error(lbh, BE_ERR_INVALIDNAME)); 295 296 default: 297 /* 298 * The other errors that zfs_ioc_snapshot might return 299 * shouldn't happen if we've set things up properly, so 300 * we'll gloss over them and call it UNKNOWN as it will 301 * require further triage. 302 */ 303 if (errno == ENOTSUP) 304 return (set_error(lbh, BE_ERR_NOPOOL)); 305 return (set_error(lbh, BE_ERR_UNKNOWN)); 306 } 307 } 308 309 return (BE_ERR_SUCCESS); 310 } 311 312 313 /* 314 * Create the boot environment specified by the name parameter 315 */ 316 int 317 be_create(libbe_handle_t *lbh, const char *name) 318 { 319 int err; 320 321 err = be_create_from_existing(lbh, name, be_active_path(lbh)); 322 323 return (set_error(lbh, err)); 324 } 325 326 327 static int 328 be_deep_clone_prop(int prop, void *cb) 329 { 330 int err; 331 struct libbe_dccb *dccb; 332 zprop_source_t src; 333 char pval[BE_MAXPATHLEN]; 334 char source[BE_MAXPATHLEN]; 335 336 dccb = cb; 337 /* Skip some properties we don't want to touch */ 338 if (prop == ZFS_PROP_CANMOUNT) 339 return (ZPROP_CONT); 340 341 /* Don't copy readonly properties */ 342 if (zfs_prop_readonly(prop)) 343 return (ZPROP_CONT); 344 345 if ((err = zfs_prop_get(dccb->zhp, prop, (char *)&pval, 346 sizeof(pval), &src, (char *)&source, sizeof(source), false))) 347 /* Just continue if we fail to read a property */ 348 return (ZPROP_CONT); 349 350 /* Only copy locally defined properties */ 351 if (src != ZPROP_SRC_LOCAL) 352 return (ZPROP_CONT); 353 354 nvlist_add_string(dccb->props, zfs_prop_to_name(prop), (char *)pval); 355 356 return (ZPROP_CONT); 357 } 358 359 static int 360 be_deep_clone(zfs_handle_t *ds, void *data) 361 { 362 int err; 363 char be_path[BE_MAXPATHLEN]; 364 char snap_path[BE_MAXPATHLEN]; 365 const char *dspath; 366 char *dsname; 367 zfs_handle_t *snap_hdl; 368 nvlist_t *props; 369 struct libbe_deep_clone *isdc, sdc; 370 struct libbe_dccb dccb; 371 372 isdc = (struct libbe_deep_clone *)data; 373 dspath = zfs_get_name(ds); 374 if ((dsname = strrchr(dspath, '/')) == NULL) 375 return (BE_ERR_UNKNOWN); 376 dsname++; 377 378 if (isdc->bename == NULL) 379 snprintf(be_path, sizeof(be_path), "%s/%s", isdc->be_root, dsname); 380 else 381 snprintf(be_path, sizeof(be_path), "%s/%s", isdc->be_root, isdc->bename); 382 383 snprintf(snap_path, sizeof(snap_path), "%s@%s", dspath, isdc->snapname); 384 385 if (zfs_dataset_exists(isdc->lbh->lzh, be_path, ZFS_TYPE_DATASET)) 386 return (set_error(isdc->lbh, BE_ERR_EXISTS)); 387 388 if ((snap_hdl = 389 zfs_open(isdc->lbh->lzh, snap_path, ZFS_TYPE_SNAPSHOT)) == NULL) 390 return (set_error(isdc->lbh, BE_ERR_ZFSOPEN)); 391 392 nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); 393 nvlist_add_string(props, "canmount", "noauto"); 394 395 dccb.zhp = ds; 396 dccb.props = props; 397 if (zprop_iter(be_deep_clone_prop, &dccb, B_FALSE, B_FALSE, 398 ZFS_TYPE_FILESYSTEM) == ZPROP_INVAL) 399 return (-1); 400 401 if ((err = zfs_clone(snap_hdl, be_path, props)) != 0) 402 err = BE_ERR_ZFSCLONE; 403 404 nvlist_free(props); 405 zfs_close(snap_hdl); 406 407 /* Failed to clone */ 408 if (err != BE_ERR_SUCCESS) 409 return (set_error(isdc->lbh, err)); 410 411 sdc.lbh = isdc->lbh; 412 sdc.bename = NULL; 413 sdc.snapname = isdc->snapname; 414 sdc.be_root = (char *)&be_path; 415 416 err = zfs_iter_filesystems(ds, be_deep_clone, &sdc); 417 418 return (err); 419 } 420 421 /* 422 * Create the boot environment from pre-existing snapshot 423 */ 424 int 425 be_create_from_existing_snap(libbe_handle_t *lbh, const char *name, 426 const char *snap) 427 { 428 int err; 429 char be_path[BE_MAXPATHLEN]; 430 char snap_path[BE_MAXPATHLEN]; 431 const char *bename; 432 char *parentname, *snapname; 433 zfs_handle_t *parent_hdl; 434 struct libbe_deep_clone sdc; 435 436 if ((err = be_validate_name(lbh, name)) != 0) 437 return (set_error(lbh, err)); 438 if ((err = be_root_concat(lbh, snap, snap_path)) != 0) 439 return (set_error(lbh, err)); 440 if ((err = be_validate_snap(lbh, snap_path)) != 0) 441 return (set_error(lbh, err)); 442 443 if ((err = be_root_concat(lbh, name, be_path)) != 0) 444 return (set_error(lbh, err)); 445 446 if ((bename = strrchr(name, '/')) == NULL) 447 bename = name; 448 else 449 bename++; 450 451 if ((parentname = strdup(snap_path)) == NULL) 452 return (set_error(lbh, BE_ERR_UNKNOWN)); 453 454 snapname = strchr(parentname, '@'); 455 if (snapname == NULL) { 456 free(parentname); 457 return (set_error(lbh, BE_ERR_UNKNOWN)); 458 } 459 *snapname = '\0'; 460 snapname++; 461 462 sdc.lbh = lbh; 463 sdc.bename = bename; 464 sdc.snapname = snapname; 465 sdc.be_root = lbh->root; 466 467 parent_hdl = zfs_open(lbh->lzh, parentname, ZFS_TYPE_DATASET); 468 err = be_deep_clone(parent_hdl, &sdc); 469 470 free(parentname); 471 return (set_error(lbh, err)); 472 } 473 474 475 /* 476 * Create a boot environment from an existing boot environment 477 */ 478 int 479 be_create_from_existing(libbe_handle_t *lbh, const char *name, const char *old) 480 { 481 int err; 482 char buf[BE_MAXPATHLEN]; 483 484 if ((err = be_snapshot(lbh, old, NULL, true, (char *)&buf))) 485 return (set_error(lbh, err)); 486 487 err = be_create_from_existing_snap(lbh, name, (char *)buf); 488 489 return (set_error(lbh, err)); 490 } 491 492 493 /* 494 * Verifies that a snapshot has a valid name, exists, and has a mountpoint of 495 * '/'. Returns BE_ERR_SUCCESS (0), upon success, or the relevant BE_ERR_* upon 496 * failure. Does not set the internal library error state. 497 */ 498 int 499 be_validate_snap(libbe_handle_t *lbh, const char *snap_name) 500 { 501 zfs_handle_t *zfs_hdl; 502 char buf[BE_MAXPATHLEN + 1]; 503 char *delim_pos; 504 int err = BE_ERR_SUCCESS; 505 506 if (strlen(snap_name) >= BE_MAXPATHLEN) 507 return (BE_ERR_PATHLEN); 508 509 if (!zfs_dataset_exists(lbh->lzh, snap_name, 510 ZFS_TYPE_SNAPSHOT)) 511 return (BE_ERR_NOENT); 512 513 strlcpy(buf, snap_name, BE_MAXPATHLEN + 1); 514 515 /* Find the base filesystem of the snapshot */ 516 if ((delim_pos = strchr(buf, '@')) == NULL) 517 return (BE_ERR_INVALIDNAME); 518 *delim_pos = '\0'; 519 520 if ((zfs_hdl = 521 zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL) 522 return (BE_ERR_NOORIGIN); 523 524 if ((err = zfs_prop_get(zfs_hdl, ZFS_PROP_MOUNTPOINT, buf, BE_MAXPATHLEN, 525 NULL, NULL, 0, 1)) != 0) 526 err = BE_ERR_INVORIGIN; 527 528 if ((err != 0) && (strncmp(buf, "/", BE_MAXPATHLEN) != 0)) 529 err = BE_ERR_INVORIGIN; 530 531 zfs_close(zfs_hdl); 532 533 return (err); 534 } 535 536 537 /* 538 * Idempotently appends the name argument to the root boot environment path 539 * and copies the resulting string into the result buffer (which is assumed 540 * to be at least BE_MAXPATHLEN characters long. Returns BE_ERR_SUCCESS upon 541 * success, BE_ERR_PATHLEN if the resulting path is longer than BE_MAXPATHLEN, 542 * or BE_ERR_INVALIDNAME if the name is a path that does not begin with 543 * zfs_be_root. Does not set internal library error state. 544 */ 545 int 546 be_root_concat(libbe_handle_t *lbh, const char *name, char *result) 547 { 548 size_t name_len, root_len; 549 550 name_len = strlen(name); 551 root_len = strlen(lbh->root); 552 553 /* Act idempotently; return be name if it is already a full path */ 554 if (strrchr(name, '/') != NULL) { 555 if (strstr(name, lbh->root) != name) 556 return (BE_ERR_INVALIDNAME); 557 558 if (name_len >= BE_MAXPATHLEN) 559 return (BE_ERR_PATHLEN); 560 561 strncpy(result, name, BE_MAXPATHLEN); 562 return (BE_ERR_SUCCESS); 563 } else if (name_len + root_len + 1 < BE_MAXPATHLEN) { 564 snprintf(result, BE_MAXPATHLEN, "%s/%s", lbh->root, 565 name); 566 return (BE_ERR_SUCCESS); 567 } 568 569 return (BE_ERR_PATHLEN); 570 } 571 572 573 /* 574 * Verifies the validity of a boot environment name (A-Za-z0-9-_.). Returns 575 * BE_ERR_SUCCESS (0) if name is valid, otherwise returns BE_ERR_INVALIDNAME. 576 * Does not set internal library error state. 577 */ 578 int 579 be_validate_name(libbe_handle_t *lbh __unused, const char *name) 580 { 581 for (int i = 0; *name; i++) { 582 char c = *(name++); 583 if (isalnum(c) || (c == '-') || (c == '_') || (c == '.')) 584 continue; 585 return (BE_ERR_INVALIDNAME); 586 } 587 588 return (BE_ERR_SUCCESS); 589 } 590 591 592 /* 593 * usage 594 */ 595 int 596 be_rename(libbe_handle_t *lbh, const char *old, const char *new) 597 { 598 char full_old[BE_MAXPATHLEN]; 599 char full_new[BE_MAXPATHLEN]; 600 zfs_handle_t *zfs_hdl; 601 int err; 602 603 if ((err = be_root_concat(lbh, old, full_old)) != 0) 604 return (set_error(lbh, err)); 605 if ((err = be_root_concat(lbh, new, full_new)) != 0) 606 return (set_error(lbh, err)); 607 608 if ((err = be_validate_name(lbh, new)) != 0) 609 return (err); 610 611 /* Check if old is active BE */ 612 if (strcmp(full_old, be_active_path(lbh)) == 0) 613 return (set_error(lbh, BE_ERR_MOUNTED)); 614 615 if (!zfs_dataset_exists(lbh->lzh, full_old, ZFS_TYPE_DATASET)) 616 return (set_error(lbh, BE_ERR_NOENT)); 617 618 if (zfs_dataset_exists(lbh->lzh, full_new, ZFS_TYPE_DATASET)) 619 return (set_error(lbh, BE_ERR_EXISTS)); 620 621 if ((zfs_hdl = zfs_open(lbh->lzh, full_old, 622 ZFS_TYPE_FILESYSTEM)) == NULL) 623 return (set_error(lbh, BE_ERR_ZFSOPEN)); 624 625 /* XXX TODO: Allow a force flag */ 626 if (zfs_is_mounted(zfs_hdl, NULL)) { 627 zfs_close(zfs_hdl); 628 return (set_error(lbh, BE_ERR_MOUNTED)); 629 } 630 631 /* recurse, nounmount, forceunmount */ 632 struct renameflags flags = { 0, 0, 0 }; 633 634 err = zfs_rename(zfs_hdl, NULL, full_new, flags); 635 636 zfs_close(zfs_hdl); 637 638 return (set_error(lbh, err)); 639 } 640 641 642 int 643 be_export(libbe_handle_t *lbh, const char *bootenv, int fd) 644 { 645 char snap_name[BE_MAXPATHLEN]; 646 char buf[BE_MAXPATHLEN]; 647 zfs_handle_t *zfs; 648 int err; 649 650 if ((err = be_snapshot(lbh, bootenv, NULL, true, snap_name)) != 0) 651 /* Use the error set by be_snapshot */ 652 return (err); 653 654 be_root_concat(lbh, snap_name, buf); 655 656 if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL) 657 return (set_error(lbh, BE_ERR_ZFSOPEN)); 658 659 err = zfs_send_one(zfs, NULL, fd, 0); 660 zfs_close(zfs); 661 662 return (err); 663 } 664 665 666 int 667 be_import(libbe_handle_t *lbh, const char *bootenv, int fd) 668 { 669 char buf[BE_MAXPATHLEN]; 670 time_t rawtime; 671 nvlist_t *props; 672 zfs_handle_t *zfs; 673 int err, len; 674 char nbuf[24]; 675 676 /* 677 * We don't need this to be incredibly random, just unique enough that 678 * it won't conflict with an existing dataset name. Chopping time 679 * down to 32 bits is probably good enough for this. 680 */ 681 snprintf(nbuf, 24, "tmp%u", 682 (uint32_t)(time(NULL) & 0xFFFFFFFF)); 683 if ((err = be_root_concat(lbh, nbuf, buf)) != 0) 684 /* 685 * Technically this is our problem, but we try to use short 686 * enough names that we won't run into problems except in 687 * worst-case BE root approaching MAXPATHLEN. 688 */ 689 return (set_error(lbh, BE_ERR_PATHLEN)); 690 691 time(&rawtime); 692 len = strlen(buf); 693 strftime(buf + len, BE_MAXPATHLEN - len, 694 "@%F-%T", localtime(&rawtime)); 695 696 if ((err = lzc_receive(buf, NULL, NULL, false, fd)) != 0) { 697 switch (err) { 698 case EINVAL: 699 return (set_error(lbh, BE_ERR_NOORIGIN)); 700 case ENOENT: 701 return (set_error(lbh, BE_ERR_NOENT)); 702 case EIO: 703 return (set_error(lbh, BE_ERR_IO)); 704 default: 705 return (set_error(lbh, BE_ERR_UNKNOWN)); 706 } 707 } 708 709 if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL) 710 return (set_error(lbh, BE_ERR_ZFSOPEN)); 711 712 nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); 713 nvlist_add_string(props, "canmount", "noauto"); 714 nvlist_add_string(props, "mountpoint", "/"); 715 716 be_root_concat(lbh, bootenv, buf); 717 718 err = zfs_clone(zfs, buf, props); 719 zfs_close(zfs); 720 nvlist_free(props); 721 722 if (err != 0) 723 return (set_error(lbh, BE_ERR_UNKNOWN)); 724 725 /* 726 * Finally, we open up the dataset we just cloned the snapshot so that 727 * we may promote it. This is necessary in order to clean up the ghost 728 * snapshot that doesn't need to be seen after the operation is 729 * complete. 730 */ 731 if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_DATASET)) == NULL) 732 return (set_error(lbh, BE_ERR_ZFSOPEN)); 733 734 err = zfs_promote(zfs); 735 zfs_close(zfs); 736 737 if (err != 0) 738 return (set_error(lbh, BE_ERR_UNKNOWN)); 739 740 /* Clean up the temporary snapshot */ 741 return (be_destroy(lbh, nbuf, 0)); 742 } 743 744 #if SOON 745 static int 746 be_create_child_noent(libbe_handle_t *lbh, const char *active, 747 const char *child_path) 748 { 749 nvlist_t *props; 750 zfs_handle_t *zfs; 751 int err; 752 753 nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); 754 nvlist_add_string(props, "canmount", "noauto"); 755 nvlist_add_string(props, "mountpoint", child_path); 756 757 /* Create */ 758 if ((err = zfs_create(lbh->lzh, active, ZFS_TYPE_DATASET, 759 props)) != 0) { 760 switch (err) { 761 case EZFS_EXISTS: 762 return (set_error(lbh, BE_ERR_EXISTS)); 763 case EZFS_NOENT: 764 return (set_error(lbh, BE_ERR_NOENT)); 765 case EZFS_BADTYPE: 766 case EZFS_BADVERSION: 767 return (set_error(lbh, BE_ERR_NOPOOL)); 768 case EZFS_BADPROP: 769 default: 770 /* We set something up wrong, probably... */ 771 return (set_error(lbh, BE_ERR_UNKNOWN)); 772 } 773 } 774 nvlist_free(props); 775 776 if ((zfs = zfs_open(lbh->lzh, active, ZFS_TYPE_DATASET)) == NULL) 777 return (set_error(lbh, BE_ERR_ZFSOPEN)); 778 779 /* Set props */ 780 if ((err = zfs_prop_set(zfs, "canmount", "noauto")) != 0) { 781 zfs_close(zfs); 782 /* 783 * Similar to other cases, this shouldn't fail unless we've 784 * done something wrong. This is a new dataset that shouldn't 785 * have been mounted anywhere between creation and now. 786 */ 787 if (err == EZFS_NOMEM) 788 return (set_error(lbh, BE_ERR_NOMEM)); 789 return (set_error(lbh, BE_ERR_UNKNOWN)); 790 } 791 zfs_close(zfs); 792 return (BE_ERR_SUCCESS); 793 } 794 795 static int 796 be_create_child_cloned(libbe_handle_t *lbh, const char *active) 797 { 798 char buf[BE_MAXPATHLEN], tmp[BE_MAXPATHLEN];; 799 zfs_handle_t *zfs; 800 int err; 801 802 /* XXX TODO ? */ 803 804 /* 805 * Establish if the existing path is a zfs dataset or just 806 * the subdirectory of one 807 */ 808 strlcpy(tmp, "tmp/be_snap.XXXXX", sizeof(tmp)); 809 if (mktemp(tmp) == NULL) 810 return (set_error(lbh, BE_ERR_UNKNOWN)); 811 812 be_root_concat(lbh, tmp, buf); 813 printf("Here %s?\n", buf); 814 if ((err = zfs_snapshot(lbh->lzh, buf, false, NULL)) != 0) { 815 switch (err) { 816 case EZFS_INVALIDNAME: 817 return (set_error(lbh, BE_ERR_INVALIDNAME)); 818 819 default: 820 /* 821 * The other errors that zfs_ioc_snapshot might return 822 * shouldn't happen if we've set things up properly, so 823 * we'll gloss over them and call it UNKNOWN as it will 824 * require further triage. 825 */ 826 if (errno == ENOTSUP) 827 return (set_error(lbh, BE_ERR_NOPOOL)); 828 return (set_error(lbh, BE_ERR_UNKNOWN)); 829 } 830 } 831 832 /* Clone */ 833 if ((zfs = zfs_open(lbh->lzh, buf, ZFS_TYPE_SNAPSHOT)) == NULL) 834 return (BE_ERR_ZFSOPEN); 835 836 if ((err = zfs_clone(zfs, active, NULL)) != 0) 837 /* XXX TODO correct error */ 838 return (set_error(lbh, BE_ERR_UNKNOWN)); 839 840 /* set props */ 841 zfs_close(zfs); 842 return (BE_ERR_SUCCESS); 843 } 844 845 int 846 be_add_child(libbe_handle_t *lbh, const char *child_path, bool cp_if_exists) 847 { 848 struct stat sb; 849 char active[BE_MAXPATHLEN], buf[BE_MAXPATHLEN]; 850 nvlist_t *props; 851 const char *s; 852 853 /* Require absolute paths */ 854 if (*child_path != '/') 855 return (set_error(lbh, BE_ERR_BADPATH)); 856 857 strlcpy(active, be_active_path(lbh), BE_MAXPATHLEN); 858 strcpy(buf, active); 859 860 /* Create non-mountable parent dataset(s) */ 861 s = child_path; 862 for (char *p; (p = strchr(s+1, '/')) != NULL; s = p) { 863 size_t len = p - s; 864 strncat(buf, s, len); 865 866 nvlist_alloc(&props, NV_UNIQUE_NAME, KM_SLEEP); 867 nvlist_add_string(props, "canmount", "off"); 868 nvlist_add_string(props, "mountpoint", "none"); 869 zfs_create(lbh->lzh, buf, ZFS_TYPE_DATASET, props); 870 nvlist_free(props); 871 } 872 873 /* Path does not exist as a descendent of / yet */ 874 if (strlcat(active, child_path, BE_MAXPATHLEN) >= BE_MAXPATHLEN) 875 return (set_error(lbh, BE_ERR_PATHLEN)); 876 877 if (stat(child_path, &sb) != 0) { 878 /* Verify that error is ENOENT */ 879 if (errno != ENOENT) 880 return (set_error(lbh, BE_ERR_UNKNOWN)); 881 return (be_create_child_noent(lbh, active, child_path)); 882 } else if (cp_if_exists) 883 /* Path is already a descendent of / and should be copied */ 884 return (be_create_child_cloned(lbh, active)); 885 return (set_error(lbh, BE_ERR_EXISTS)); 886 } 887 #endif /* SOON */ 888 889 static int 890 be_set_nextboot(libbe_handle_t *lbh, nvlist_t *config, uint64_t pool_guid, 891 const char *zfsdev) 892 { 893 nvlist_t **child; 894 uint64_t vdev_guid; 895 int c, children; 896 897 if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, &child, 898 &children) == 0) { 899 for (c = 0; c < children; ++c) 900 if (be_set_nextboot(lbh, child[c], pool_guid, zfsdev) != 0) 901 return (1); 902 return (0); 903 } 904 905 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_GUID, 906 &vdev_guid) != 0) { 907 return (1); 908 } 909 910 if (zpool_nextboot(lbh->lzh, pool_guid, vdev_guid, zfsdev) != 0) { 911 perror("ZFS_IOC_NEXTBOOT failed"); 912 return (1); 913 } 914 915 return (0); 916 } 917 918 919 int 920 be_activate(libbe_handle_t *lbh, const char *bootenv, bool temporary) 921 { 922 char be_path[BE_MAXPATHLEN]; 923 char buf[BE_MAXPATHLEN]; 924 uint64_t pool_guid; 925 nvlist_t *config, *vdevs; 926 int err; 927 928 be_root_concat(lbh, bootenv, be_path); 929 930 /* Note: be_exists fails if mountpoint is not / */ 931 if (!be_exists(lbh, be_path)) 932 return (BE_ERR_NOENT); 933 934 if (temporary) { 935 config = zpool_get_config(lbh->active_phandle, NULL); 936 if (config == NULL) 937 /* config should be fetchable... */ 938 return (set_error(lbh, BE_ERR_UNKNOWN)); 939 940 if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID, 941 &pool_guid) != 0) 942 /* Similarly, it shouldn't be possible */ 943 return (set_error(lbh, BE_ERR_UNKNOWN)); 944 945 /* Expected format according to zfsbootcfg(8) man */ 946 strcpy(buf, "zfs:"); 947 strcat(buf, be_path); 948 strcat(buf, ":"); 949 950 /* We have no config tree */ 951 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, 952 &vdevs) != 0) 953 return (set_error(lbh, BE_ERR_NOPOOL)); 954 955 return (be_set_nextboot(lbh, vdevs, pool_guid, buf)); 956 } else { 957 /* Obtain bootenv zpool */ 958 err = zpool_set_prop(lbh->active_phandle, "bootfs", be_path); 959 960 switch (err) { 961 case 0: 962 return (BE_ERR_SUCCESS); 963 964 default: 965 /* XXX TODO correct errors */ 966 return (-1); 967 } 968 } 969 } 970