1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * Copyright (c) 2012, 2016 by Delphix. All rights reserved. 28 * Copyright 2017 RackTop Systems. 29 * Copyright 2019 Nexenta Systems, Inc. 30 */ 31 32 #include <stdio.h> 33 #include <libzfs.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <errno.h> 37 #include <zone.h> 38 #include <libshare.h> 39 #include "libshare_impl.h" 40 #include <libintl.h> 41 #include <sys/mnttab.h> 42 #include <sys/mntent.h> 43 #include <assert.h> 44 45 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 46 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 47 extern char *sa_fstype(char *); 48 extern void set_node_attr(void *, char *, char *); 49 extern int sa_is_share(void *); 50 extern void sa_update_sharetab_ts(sa_handle_t); 51 52 /* 53 * File system specific code for ZFS. The original code was stolen 54 * from the "zfs" command and modified to better suit this library's 55 * usage. 56 */ 57 58 typedef struct get_all_cbdata { 59 zfs_handle_t **cb_handles; 60 size_t cb_alloc; 61 size_t cb_used; 62 uint_t cb_types; 63 } get_all_cbdata_t; 64 65 /* 66 * sa_zfs_init(impl_handle) 67 * 68 * Initialize an access handle into libzfs. The handle needs to stay 69 * around until sa_zfs_fini() in order to maintain the cache of 70 * mounts. 71 */ 72 73 int 74 sa_zfs_init(sa_handle_impl_t impl_handle) 75 { 76 impl_handle->zfs_libhandle = libzfs_init(); 77 if (impl_handle->zfs_libhandle != NULL) { 78 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 79 return (B_TRUE); 80 } 81 return (B_FALSE); 82 } 83 84 /* 85 * sa_zfs_fini(impl_handle) 86 * 87 * cleanup data structures and the libzfs handle used for accessing 88 * zfs file share info. 89 */ 90 91 void 92 sa_zfs_fini(sa_handle_impl_t impl_handle) 93 { 94 if (impl_handle->zfs_libhandle != NULL) { 95 if (impl_handle->zfs_list != NULL) { 96 zfs_handle_t **zhp = impl_handle->zfs_list; 97 size_t i; 98 99 /* 100 * Contents of zfs_list need to be freed so we 101 * don't lose ZFS handles. 102 */ 103 for (i = 0; i < impl_handle->zfs_list_count; i++) { 104 zfs_close(zhp[i]); 105 } 106 free(impl_handle->zfs_list); 107 impl_handle->zfs_list = NULL; 108 impl_handle->zfs_list_count = 0; 109 } 110 111 libzfs_fini(impl_handle->zfs_libhandle); 112 impl_handle->zfs_libhandle = NULL; 113 } 114 } 115 116 /* 117 * get_one_filesystem(zfs_handle_t, data) 118 * 119 * an iterator function called while iterating through the ZFS 120 * root. It accumulates into an array of file system handles that can 121 * be used to derive info about those file systems. 122 * 123 * Note that as this function is called, we close all zhp handles that 124 * are not going to be places into the cp_handles list. We don't want 125 * to close the ones we are keeping, but all others would be leaked if 126 * not closed here. 127 */ 128 129 static int 130 get_one_filesystem(zfs_handle_t *zhp, void *data) 131 { 132 get_all_cbdata_t *cbp = data; 133 zfs_type_t type = zfs_get_type(zhp); 134 135 /* 136 * Interate over any nested datasets. 137 */ 138 if (type == ZFS_TYPE_FILESYSTEM && 139 zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 140 zfs_close(zhp); 141 return (1); 142 } 143 144 /* 145 * Skip any datasets whose type does not match. 146 */ 147 if ((type & cbp->cb_types) == 0) { 148 zfs_close(zhp); 149 return (0); 150 } 151 152 if (cbp->cb_alloc == cbp->cb_used) { 153 zfs_handle_t **handles; 154 155 if (cbp->cb_alloc == 0) 156 cbp->cb_alloc = 64; 157 else 158 cbp->cb_alloc *= 2; 159 160 handles = (zfs_handle_t **)calloc(1, 161 cbp->cb_alloc * sizeof (void *)); 162 163 if (handles == NULL) { 164 zfs_close(zhp); 165 return (0); 166 } 167 if (cbp->cb_handles) { 168 bcopy(cbp->cb_handles, handles, 169 cbp->cb_used * sizeof (void *)); 170 free(cbp->cb_handles); 171 } 172 173 cbp->cb_handles = handles; 174 } 175 176 cbp->cb_handles[cbp->cb_used++] = zhp; 177 178 return (0); 179 } 180 181 /* 182 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 183 * 184 * iterate through all ZFS file systems starting at the root. Returns 185 * a count and an array of handle pointers. Allocating is only done 186 * once. The caller does not need to free since it will be done at 187 * sa_zfs_fini() time. 188 */ 189 190 static void 191 get_all_filesystems(sa_handle_impl_t impl_handle, 192 zfs_handle_t ***fslist, size_t *count) 193 { 194 get_all_cbdata_t cb = { 0 }; 195 cb.cb_types = ZFS_TYPE_FILESYSTEM; 196 197 if (impl_handle->zfs_list != NULL) { 198 *fslist = impl_handle->zfs_list; 199 *count = impl_handle->zfs_list_count; 200 return; 201 } 202 203 (void) zfs_iter_root(impl_handle->zfs_libhandle, 204 get_one_filesystem, &cb); 205 206 impl_handle->zfs_list = *fslist = cb.cb_handles; 207 impl_handle->zfs_list_count = *count = cb.cb_used; 208 } 209 210 /* 211 * mountpoint_compare(a, b) 212 * 213 * compares the mountpoint on two zfs file systems handles. 214 * returns values following strcmp() model. 215 */ 216 217 static int 218 mountpoint_compare(const void *a, const void *b) 219 { 220 zfs_handle_t **za = (zfs_handle_t **)a; 221 zfs_handle_t **zb = (zfs_handle_t **)b; 222 char mounta[MAXPATHLEN]; 223 char mountb[MAXPATHLEN]; 224 225 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 226 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 227 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 228 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 229 230 return (strcmp(mounta, mountb)); 231 } 232 233 /* 234 * return legacy mountpoint. Caller provides space for mountpoint and 235 * dataset. 236 */ 237 int 238 get_legacy_mountpoint(const char *path, char *dataset, size_t dlen, 239 char *mountpoint, size_t mlen) 240 { 241 FILE *fp; 242 struct mnttab entry; 243 int rc = 1; 244 245 if ((fp = fopen(MNTTAB, "r")) == NULL) { 246 return (1); 247 } 248 249 while (getmntent(fp, &entry) == 0) { 250 251 if (entry.mnt_fstype == NULL || 252 strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 253 continue; 254 255 if (strcmp(entry.mnt_mountp, path) == 0) { 256 if (mlen > 0) 257 (void) strlcpy(mountpoint, entry.mnt_mountp, 258 mlen); 259 if (dlen > 0) 260 (void) strlcpy(dataset, entry.mnt_special, 261 dlen); 262 rc = 0; 263 break; 264 } 265 } 266 (void) fclose(fp); 267 return (rc); 268 } 269 270 271 /* 272 * Verifies that a specific zfs filesystem handle meets the criteria necessary 273 * to be used by libshare operations. See get_zfs_dataset. 274 */ 275 static char * 276 verify_zfs_handle(zfs_handle_t *hdl, const char *path, boolean_t search_mnttab) 277 { 278 char mountpoint[ZFS_MAXPROPLEN]; 279 char canmount[ZFS_MAXPROPLEN] = { 0 }; 280 /* must have a mountpoint */ 281 if (zfs_prop_get(hdl, ZFS_PROP_MOUNTPOINT, mountpoint, 282 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 283 /* no mountpoint */ 284 return (NULL); 285 } 286 287 /* mountpoint must be a path */ 288 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 289 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 290 /* 291 * Search mmttab for mountpoint and get dataset. 292 */ 293 294 if (search_mnttab == B_TRUE && 295 get_legacy_mountpoint(path, mountpoint, 296 sizeof (mountpoint), NULL, 0) == 0) { 297 return (strdup(mountpoint)); 298 } 299 return (NULL); 300 } 301 302 /* canmount must be set */ 303 if (zfs_prop_get(hdl, ZFS_PROP_CANMOUNT, canmount, 304 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 305 strcmp(canmount, "off") == 0) 306 return (NULL); 307 308 /* 309 * have a mountable handle but want to skip those marked none 310 * and legacy 311 */ 312 if (strcmp(mountpoint, path) == 0) { 313 return (strdup((char *)zfs_get_name(hdl))); 314 } 315 316 return (NULL); 317 } 318 319 /* 320 * get_zfs_dataset(impl_handle, path) 321 * 322 * get the name of the ZFS dataset the path is equivalent to. The 323 * dataset name is used for get/set of ZFS properties since libzfs 324 * requires a dataset to do a zfs_open(). 325 */ 326 327 static char * 328 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 329 boolean_t search_mnttab) 330 { 331 size_t i, count = 0; 332 zfs_handle_t **zlist; 333 char *cutpath; 334 zfs_handle_t *handle_from_path; 335 char *ret = NULL; 336 337 /* 338 * First we optimistically assume that the mount path for the filesystem 339 * is the same as the name of the filesystem (minus some number of 340 * leading slashes). If this is true, then zfs_open should properly open 341 * the filesystem. We duplicate the error checking done later in the 342 * function for consistency. If anything fails, we resort to the 343 * (extremely slow) search of all the filesystems. 344 */ 345 cutpath = path + strspn(path, "/"); 346 347 assert(impl_handle->zfs_libhandle != NULL); 348 libzfs_print_on_error(impl_handle->zfs_libhandle, B_FALSE); 349 handle_from_path = zfs_open(impl_handle->zfs_libhandle, cutpath, 350 ZFS_TYPE_FILESYSTEM); 351 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 352 if (handle_from_path != NULL) { 353 ret = verify_zfs_handle(handle_from_path, path, search_mnttab); 354 zfs_close(handle_from_path); 355 if (ret != NULL) { 356 return (ret); 357 } 358 } 359 /* 360 * Couldn't find a filesystem optimistically, check all the handles we 361 * can. 362 */ 363 get_all_filesystems(impl_handle, &zlist, &count); 364 for (i = 0; i < count; i++) { 365 assert(zlist[i]); 366 if ((ret = verify_zfs_handle(zlist[i], path, 367 search_mnttab)) != NULL) 368 return (ret); 369 } 370 371 /* Couldn't find a matching dataset */ 372 return (NULL); 373 } 374 375 /* 376 * get_zfs_property(dataset, property) 377 * 378 * Get the file system property specified from the ZFS dataset. 379 */ 380 381 static char * 382 get_zfs_property(char *dataset, zfs_prop_t property) 383 { 384 zfs_handle_t *handle = NULL; 385 char shareopts[ZFS_MAXPROPLEN]; 386 libzfs_handle_t *libhandle; 387 388 libhandle = libzfs_init(); 389 if (libhandle != NULL) { 390 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 391 if (handle != NULL) { 392 if (zfs_prop_get(handle, property, shareopts, 393 sizeof (shareopts), NULL, NULL, 0, 394 B_FALSE) == 0) { 395 zfs_close(handle); 396 libzfs_fini(libhandle); 397 return (strdup(shareopts)); 398 } 399 zfs_close(handle); 400 } 401 libzfs_fini(libhandle); 402 } 403 return (NULL); 404 } 405 406 /* 407 * sa_zfs_is_shared(handle, path) 408 * 409 * Check to see if the ZFS path provided has the sharenfs option set 410 * or not. 411 */ 412 413 int 414 sa_zfs_is_shared(sa_handle_t sahandle, char *path) 415 { 416 int ret = 0; 417 char *dataset; 418 zfs_handle_t *handle = NULL; 419 char shareopts[ZFS_MAXPROPLEN]; 420 libzfs_handle_t *libhandle; 421 422 dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 423 if (dataset != NULL) { 424 libhandle = libzfs_init(); 425 if (libhandle != NULL) { 426 handle = zfs_open(libhandle, dataset, 427 ZFS_TYPE_FILESYSTEM); 428 if (handle != NULL) { 429 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 430 shareopts, sizeof (shareopts), NULL, NULL, 431 0, B_FALSE) == 0 && 432 strcmp(shareopts, "off") != 0) { 433 ret = 1; /* it is shared */ 434 } 435 zfs_close(handle); 436 } 437 libzfs_fini(libhandle); 438 } 439 free(dataset); 440 } 441 return (ret); 442 } 443 444 /* 445 * find_or_create_group(handle, groupname, proto, *err) 446 * 447 * While walking the ZFS tree, we need to add shares to a defined 448 * group. If the group doesn't exist, create it first, making sure it 449 * is marked as a ZFS group. 450 * 451 * Note that all ZFS shares are in a subgroup of the top level group 452 * called "zfs". 453 */ 454 455 static sa_group_t 456 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 457 { 458 sa_group_t group; 459 sa_optionset_t optionset; 460 int ret = SA_OK; 461 462 /* 463 * we check to see if the "zfs" group exists. Since this 464 * should be the top level group, we don't want the 465 * parent. This is to make sure the zfs group has been created 466 * and to created if it hasn't been. 467 */ 468 group = sa_get_group(handle, groupname); 469 if (group == NULL) { 470 group = sa_create_group(handle, groupname, &ret); 471 472 /* make sure this is flagged as a ZFS group */ 473 if (group != NULL) 474 ret = sa_set_group_attr(group, "zfs", "true"); 475 } 476 if (group != NULL) { 477 if (proto != NULL) { 478 optionset = sa_get_optionset(group, proto); 479 if (optionset == NULL) 480 optionset = sa_create_optionset(group, proto); 481 } 482 } 483 if (err != NULL) 484 *err = ret; 485 return (group); 486 } 487 488 /* 489 * find_or_create_zfs_subgroup(groupname, optstring, *err) 490 * 491 * ZFS shares will be in a subgroup of the "zfs" master group. This 492 * function looks to see if the groupname exists and returns it if it 493 * does or else creates a new one with the specified name and returns 494 * that. The "zfs" group will exist before we get here, but we make 495 * sure just in case. 496 * 497 * err must be a valid pointer. 498 */ 499 500 static sa_group_t 501 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 502 char *optstring, int *err) 503 { 504 sa_group_t group = NULL; 505 sa_group_t zfs; 506 char *name; 507 char *options; 508 509 /* start with the top-level "zfs" group */ 510 zfs = sa_get_group(handle, "zfs"); 511 *err = SA_OK; 512 if (zfs != NULL) { 513 for (group = sa_get_sub_group(zfs); group != NULL; 514 group = sa_get_next_group(group)) { 515 name = sa_get_group_attr(group, "name"); 516 if (name != NULL && strcmp(name, groupname) == 0) { 517 /* have the group so break out of here */ 518 sa_free_attr_string(name); 519 break; 520 } 521 if (name != NULL) 522 sa_free_attr_string(name); 523 } 524 525 if (group == NULL) { 526 /* 527 * Need to create the sub-group since it doesn't exist 528 */ 529 group = _sa_create_zfs_group(zfs, groupname); 530 if (group == NULL) { 531 *err = SA_NO_MEMORY; 532 return (NULL); 533 } 534 set_node_attr(group, "zfs", "true"); 535 } 536 if (strcmp(optstring, "on") == 0) 537 optstring = "rw"; 538 options = strdup(optstring); 539 if (options != NULL) { 540 *err = sa_parse_legacy_options(group, options, 541 proto); 542 /* If no optionset, add one. */ 543 if (sa_get_optionset(group, proto) == NULL) 544 (void) sa_create_optionset(group, proto); 545 546 /* 547 * Do not forget to update an optionset of 548 * the parent group so that it contains 549 * all protocols its subgroups have. 550 */ 551 if (sa_get_optionset(zfs, proto) == NULL) 552 (void) sa_create_optionset(zfs, proto); 553 554 free(options); 555 } else { 556 *err = SA_NO_MEMORY; 557 } 558 } 559 return (group); 560 } 561 562 /* 563 * zfs_construct_resource(share, name, base, dataset) 564 * 565 * Add a resource to the share using name as a template. If name == 566 * NULL, then construct a name based on the dataset value. 567 * name. 568 */ 569 static void 570 zfs_construct_resource(sa_share_t share, char *dataset) 571 { 572 char buff[SA_MAX_RESOURCE_NAME + 1]; 573 int ret = SA_OK; 574 575 (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 576 sa_fix_resource_name(buff); 577 (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 578 } 579 580 /* 581 * zfs_inherited(handle, source, sourcestr) 582 * 583 * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 584 * for readability. 585 */ 586 static int 587 zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 588 char *shareopts, char *mountpoint, char *proto, char *dataset) 589 { 590 int doshopt = 0; 591 int err = SA_OK; 592 sa_group_t group; 593 sa_resource_t resource; 594 uint64_t features; 595 596 /* 597 * Need to find the "real" parent sub-group. It may not be 598 * mounted, but it was identified in the "sourcestr" 599 * variable. The real parent not mounted can occur if 600 * "canmount=off and sharenfs=on". 601 */ 602 group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 603 shareopts, &doshopt); 604 if (group != NULL) { 605 /* 606 * We may need the first share for resource 607 * prototype. We only care about it if it has a 608 * resource that sets a prefix value. 609 */ 610 if (share == NULL) 611 share = _sa_add_share(group, mountpoint, 612 SA_SHARE_TRANSIENT, &err, 613 (uint64_t)SA_FEATURE_NONE); 614 /* 615 * some options may only be on shares. If the opt 616 * string contains one of those, we put it just on the 617 * share. 618 */ 619 if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 620 char *options; 621 options = strdup(shareopts); 622 if (options != NULL) { 623 set_node_attr(share, "dataset", dataset); 624 err = sa_parse_legacy_options(share, options, 625 proto); 626 set_node_attr(share, "dataset", NULL); 627 free(options); 628 } 629 if (sa_get_optionset(group, proto) == NULL) 630 (void) sa_create_optionset(group, proto); 631 } 632 features = sa_proto_get_featureset(proto); 633 if (share != NULL && features & SA_FEATURE_RESOURCE) { 634 /* 635 * We have a share and the protocol requires 636 * that at least one resource exist (probably 637 * SMB). We need to make sure that there is at 638 * least one. 639 */ 640 resource = sa_get_share_resource(share, NULL); 641 if (resource == NULL) { 642 zfs_construct_resource(share, dataset); 643 } 644 } 645 } else { 646 err = SA_NO_MEMORY; 647 } 648 return (err); 649 } 650 651 /* 652 * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 653 * grouperr) 654 * 655 * handle case where this is the top of a sub-group in ZFS. Pulled out 656 * of sa_get_zfs_shares for readability. We need the grouperr from the 657 * creation of the subgroup to know whether to add the public 658 * property, etc. to the specific share. 659 */ 660 static int 661 zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 662 char *shareopts, char *proto, char *dataset, int grouperr) 663 { 664 int err = SA_OK; 665 sa_resource_t resource; 666 uint64_t features; 667 668 set_node_attr(group, "zfs", "true"); 669 if (share == NULL) 670 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 671 &err, (uint64_t)SA_FEATURE_NONE); 672 673 if (err != SA_OK) 674 return (err); 675 676 if (strcmp(shareopts, "on") == 0) 677 shareopts = ""; 678 if (shareopts != NULL) { 679 char *options; 680 if (grouperr == SA_PROP_SHARE_ONLY) { 681 /* 682 * Some properties may only be on shares, but 683 * due to the ZFS sub-groups being artificial, 684 * we sometimes get this and have to deal with 685 * it. We do it by attempting to put it on the 686 * share. 687 */ 688 options = strdup(shareopts); 689 if (options != NULL) { 690 err = sa_parse_legacy_options(share, 691 options, proto); 692 free(options); 693 } 694 } 695 /* Unmark the share's changed state */ 696 set_node_attr(share, "changed", NULL); 697 } 698 features = sa_proto_get_featureset(proto); 699 if (share != NULL && features & SA_FEATURE_RESOURCE) { 700 /* 701 * We have a share and the protocol requires that at 702 * least one resource exist (probably SMB). We need to 703 * make sure that there is at least one. 704 */ 705 resource = sa_get_share_resource(share, NULL); 706 if (resource == NULL) { 707 zfs_construct_resource(share, dataset); 708 } 709 } 710 return (err); 711 } 712 713 /* 714 * zfs_grp_error(err) 715 * 716 * Print group create error, but only once. If err is 0 do the 717 * print else don't. 718 */ 719 720 static void 721 zfs_grp_error(int err) 722 { 723 if (err == 0) { 724 /* only print error once */ 725 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 726 "Cannot create ZFS subgroup during initialization:" 727 " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 728 } 729 } 730 731 /* 732 * zfs_process_share(handle, share, mountpoint, proto, source, 733 * shareopts, sourcestr) 734 * 735 * Creates the subgroup, if necessary and adds shares, resources 736 * and properties. 737 */ 738 int 739 sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 740 char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 741 char *sourcestr, char *dataset) 742 { 743 int err = SA_OK; 744 745 if (source & ZPROP_SRC_INHERITED) { 746 err = zfs_inherited(handle, share, sourcestr, shareopts, 747 mountpoint, proto, dataset); 748 } else { 749 group = find_or_create_zfs_subgroup(handle, dataset, proto, 750 shareopts, &err); 751 if (group == NULL) { 752 static boolean_t reported_error = B_FALSE; 753 /* 754 * There is a problem, but we can't do 755 * anything about it at this point so we issue 756 * a warning and move on. 757 */ 758 zfs_grp_error(reported_error); 759 reported_error = B_TRUE; 760 } 761 set_node_attr(group, "zfs", "true"); 762 /* 763 * Add share with local opts via zfs_notinherited. 764 */ 765 err = zfs_notinherited(group, share, mountpoint, shareopts, 766 proto, dataset, err); 767 } 768 return (err); 769 } 770 771 /* 772 * Walk the mnttab for all zfs mounts and determine which are 773 * shared. Find or create the appropriate group/sub-group to contain 774 * the shares. 775 * 776 * All shares are in a sub-group that will hold the properties. This 777 * allows representing the inherited property model. 778 * 779 * One area of complication is if "sharenfs" is set at one level of 780 * the directory tree and "sharesmb" is set at a different level, the 781 * a sub-group must be formed at the lower level for both 782 * protocols. That is the nature of the problem in CR 6667349. 783 */ 784 static int 785 sa_get_zfs_share_common(sa_handle_t handle, zfs_handle_t *fs_handle, char *path, 786 sa_group_t zfsgroup) 787 { 788 boolean_t smb, nfs; 789 boolean_t smb_inherited, nfs_inherited; 790 char nfsshareopts[ZFS_MAXPROPLEN]; 791 char smbshareopts[ZFS_MAXPROPLEN]; 792 char nfssourcestr[ZFS_MAXPROPLEN]; 793 char smbsourcestr[ZFS_MAXPROPLEN]; 794 char mountpoint[ZFS_MAXPROPLEN]; 795 int err = SA_OK; 796 zprop_source_t source; 797 sa_share_t share; 798 char *dataset; 799 800 source = ZPROP_SRC_ALL; 801 /* If no mountpoint, skip. */ 802 if (zfs_prop_get(fs_handle, ZFS_PROP_MOUNTPOINT, 803 mountpoint, sizeof (mountpoint), NULL, NULL, 0, 804 B_FALSE) != 0) 805 return (SA_SYSTEM_ERR); 806 807 if (path != NULL) 808 (void) strncpy(path, mountpoint, sizeof (mountpoint)); 809 /* 810 * zfs_get_name value must not be freed. It is just a 811 * pointer to a value in the handle. 812 */ 813 if ((dataset = (char *)zfs_get_name(fs_handle)) == NULL) 814 return (SA_SYSTEM_ERR); 815 816 /* 817 * only deal with "mounted" file systems since 818 * unmounted file systems can't actually be shared. 819 */ 820 821 if (!zfs_is_mounted(fs_handle, NULL)) 822 return (SA_SYSTEM_ERR); 823 824 /* 825 * Ignore "zoned" datasets in global zone. 826 */ 827 if (getzoneid() == GLOBAL_ZONEID && 828 zfs_prop_get_int(fs_handle, ZFS_PROP_ZONED)) 829 return (SA_SYSTEM_ERR); 830 831 nfs = nfs_inherited = B_FALSE; 832 833 if (zfs_prop_get(fs_handle, ZFS_PROP_SHARENFS, nfsshareopts, 834 sizeof (nfsshareopts), &source, nfssourcestr, 835 ZFS_MAXPROPLEN, B_FALSE) == 0 && 836 strcmp(nfsshareopts, "off") != 0) { 837 if (source & ZPROP_SRC_INHERITED) 838 nfs_inherited = B_TRUE; 839 else 840 nfs = B_TRUE; 841 } 842 843 smb = smb_inherited = B_FALSE; 844 if (zfs_prop_get(fs_handle, ZFS_PROP_SHARESMB, smbshareopts, 845 sizeof (smbshareopts), &source, smbsourcestr, 846 ZFS_MAXPROPLEN, B_FALSE) == 0 && 847 strcmp(smbshareopts, "off") != 0) { 848 if (source & ZPROP_SRC_INHERITED) 849 smb_inherited = B_TRUE; 850 else 851 smb = B_TRUE; 852 } 853 854 /* 855 * If the mountpoint is already shared, it must be a 856 * non-ZFS share. We want to remove the share from its 857 * parent group and reshare it under ZFS. 858 */ 859 share = sa_find_share(handle, mountpoint); 860 if (share != NULL && 861 (nfs || smb || nfs_inherited || smb_inherited)) { 862 err = sa_remove_share(share); 863 share = NULL; 864 } 865 866 /* 867 * At this point, we have the information needed to 868 * determine what to do with the share. 869 * 870 * If smb or nfs is set, we have a new sub-group. 871 * If smb_inherit and/or nfs_inherit is set, then 872 * place on an existing sub-group. If both are set, 873 * the existing sub-group is the closest up the tree. 874 */ 875 if (nfs || smb) { 876 /* 877 * Non-inherited is the straightforward 878 * case. sa_zfs_process_share handles it 879 * directly. Make sure that if the "other" 880 * protocol is inherited, that we treat it as 881 * non-inherited as well. 882 */ 883 if (nfs || nfs_inherited) { 884 err = sa_zfs_process_share(handle, zfsgroup, 885 share, mountpoint, "nfs", 886 0, nfsshareopts, 887 nfssourcestr, dataset); 888 share = sa_find_share(handle, mountpoint); 889 } 890 if (smb || smb_inherited) { 891 err = sa_zfs_process_share(handle, zfsgroup, 892 share, mountpoint, "smb", 893 0, smbshareopts, 894 smbsourcestr, dataset); 895 } 896 } else if (nfs_inherited || smb_inherited) { 897 char *grpdataset; 898 /* 899 * If we only have inherited groups, it is 900 * important to find the closer of the two if 901 * the protocols are set at different 902 * levels. The closest sub-group is the one we 903 * want to work with. 904 */ 905 if (nfs_inherited && smb_inherited) { 906 if (strcmp(nfssourcestr, smbsourcestr) <= 0) 907 grpdataset = nfssourcestr; 908 else 909 grpdataset = smbsourcestr; 910 } else if (nfs_inherited) { 911 grpdataset = nfssourcestr; 912 } else if (smb_inherited) { 913 grpdataset = smbsourcestr; 914 } 915 if (nfs_inherited) { 916 err = sa_zfs_process_share(handle, zfsgroup, 917 share, mountpoint, "nfs", 918 ZPROP_SRC_INHERITED, nfsshareopts, 919 grpdataset, dataset); 920 share = sa_find_share(handle, mountpoint); 921 } 922 if (smb_inherited) { 923 err = sa_zfs_process_share(handle, zfsgroup, 924 share, mountpoint, "smb", 925 ZPROP_SRC_INHERITED, smbshareopts, 926 grpdataset, dataset); 927 } 928 } 929 return (err); 930 } 931 932 /* 933 * Handles preparing generic objects such as the libzfs handle and group for 934 * sa_get_one_zfs_share, sa_get_zfs_share_for_name, and sa_get_zfs_shares. 935 */ 936 static int 937 prep_zfs_handle_and_group(sa_handle_t handle, char *groupname, 938 libzfs_handle_t **zfs_libhandle, sa_group_t *zfsgroup, int *err) 939 { 940 /* 941 * If we can't access libzfs, don't bother doing anything. 942 */ 943 *zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 944 if (*zfs_libhandle == NULL) 945 return (SA_SYSTEM_ERR); 946 947 *zfsgroup = find_or_create_group(handle, groupname, NULL, err); 948 return (SA_OK); 949 } 950 951 /* 952 * The O.G. zfs share preparation function. This initializes all zfs shares for 953 * use with libshare. 954 */ 955 int 956 sa_get_zfs_shares(sa_handle_t handle, char *groupname) 957 { 958 sa_group_t zfsgroup; 959 zfs_handle_t **zlist; 960 size_t count = 0; 961 libzfs_handle_t *zfs_libhandle; 962 int err; 963 964 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, 965 &zfsgroup, &err)) != SA_OK) { 966 return (err); 967 } 968 /* Not an error, this could be a legacy condition */ 969 if (zfsgroup == NULL) 970 return (SA_OK); 971 972 /* 973 * need to walk the mounted ZFS pools and datasets to 974 * find shares that are possible. 975 */ 976 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 977 qsort(zlist, count, sizeof (void *), mountpoint_compare); 978 979 for (int i = 0; i < count; i++) { 980 err = sa_get_zfs_share_common(handle, zlist[i], NULL, zfsgroup); 981 } 982 /* 983 * Don't need to free the "zlist" variable since it is only a 984 * pointer to a cached value that will be freed when 985 * sa_fini() is called. 986 */ 987 return (err); 988 } 989 990 /* 991 * Initializes shares for only the dataset specified fs_handle. 992 * This is used as a performance optimization relative to sa_get_zfs_shares. 993 */ 994 int 995 sa_get_zfs_share(sa_handle_t handle, char *groupname, zfs_handle_t *fs_handle) 996 { 997 sa_group_t zfsgroup; 998 libzfs_handle_t *zfs_libhandle; 999 int err; 1000 1001 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, 1002 &zfsgroup, &err)) != SA_OK) { 1003 return (err); 1004 } 1005 /* Not an error, this could be a legacy condition */ 1006 if (zfsgroup == NULL) 1007 return (SA_OK); 1008 1009 err = sa_get_zfs_share_common(handle, fs_handle, NULL, zfsgroup); 1010 return (err); 1011 } 1012 1013 /* 1014 * Initializes only the handles specified in the sharearg for use with libshare. 1015 * This is used as a performance optimization relative to sa_get_zfs_shares. 1016 */ 1017 int 1018 sa_get_one_zfs_share(sa_handle_t handle, char *groupname, 1019 sa_init_selective_arg_t *sharearg, char ***paths, size_t *paths_len) 1020 { 1021 sa_group_t zfsgroup; 1022 libzfs_handle_t *zfs_libhandle; 1023 int err; 1024 1025 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, 1026 &zfsgroup, &err)) != SA_OK) { 1027 return (err); 1028 } 1029 /* Not an error, this could be a legacy condition */ 1030 if (zfsgroup == NULL) 1031 return (SA_OK); 1032 1033 *paths_len = sharearg->zhandle_len; 1034 *paths = calloc(*paths_len, sizeof (char *)); 1035 for (int i = 0; i < sharearg->zhandle_len; ++i) { 1036 zfs_handle_t *fs_handle = 1037 ((zfs_handle_t **)(sharearg->zhandle_arr))[i]; 1038 if (fs_handle == NULL) { 1039 /* Free non-null elements of the paths array */ 1040 for (int free_idx = 0; free_idx < *paths_len; 1041 ++free_idx) { 1042 if ((*paths)[free_idx] != NULL) 1043 free((*paths)[free_idx]); 1044 } 1045 free(*paths); 1046 *paths = NULL; 1047 *paths_len = 0; 1048 return (SA_SYSTEM_ERR); 1049 } 1050 (*paths)[i] = malloc(sizeof (char) * ZFS_MAXPROPLEN); 1051 err |= sa_get_zfs_share_common(handle, fs_handle, (*paths)[i], 1052 zfsgroup); 1053 } 1054 1055 return (err); 1056 } 1057 1058 /* 1059 * Initializes only the share with the specified sharename for use with 1060 * libshare. 1061 */ 1062 int 1063 sa_get_zfs_share_for_name(sa_handle_t handle, char *groupname, 1064 const char *sharename, char *outpath) 1065 { 1066 sa_group_t zfsgroup; 1067 libzfs_handle_t *zfs_libhandle; 1068 int err; 1069 1070 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, 1071 &zfsgroup, &err)) != SA_OK) { 1072 return (err); 1073 } 1074 /* Not an error, this could be a legacy condition */ 1075 if (zfsgroup == NULL) 1076 return (SA_OK); 1077 1078 zfs_handle_t *fs_handle = zfs_open(zfs_libhandle, 1079 sharename + strspn(sharename, "/"), ZFS_TYPE_DATASET); 1080 if (fs_handle == NULL) 1081 return (SA_SYSTEM_ERR); 1082 1083 err = sa_get_zfs_share_common(handle, fs_handle, outpath, zfsgroup); 1084 zfs_close(fs_handle); 1085 return (err); 1086 } 1087 1088 1089 1090 #define COMMAND "/usr/sbin/zfs" 1091 1092 /* 1093 * sa_zfs_set_sharenfs(group, path, on) 1094 * 1095 * Update the "sharenfs" property on the path. If on is true, then set 1096 * to the properties on the group or "on" if no properties are 1097 * defined. Set to "off" if on is false. 1098 */ 1099 1100 int 1101 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 1102 { 1103 int ret = SA_NOT_IMPLEMENTED; 1104 char *command; 1105 1106 command = malloc(ZFS_MAXPROPLEN * 2); 1107 if (command != NULL) { 1108 char *opts = NULL; 1109 char *dataset = NULL; 1110 FILE *pfile; 1111 sa_handle_impl_t impl_handle; 1112 /* for now, NFS is always available for "zfs" */ 1113 if (on) { 1114 opts = sa_proto_legacy_format("nfs", group, 1); 1115 if (opts != NULL && strlen(opts) == 0) { 1116 free(opts); 1117 opts = strdup("on"); 1118 } 1119 } 1120 1121 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1122 assert(impl_handle != NULL); 1123 if (impl_handle != NULL) 1124 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1125 else 1126 ret = SA_SYSTEM_ERR; 1127 1128 if (dataset != NULL) { 1129 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1130 "%s set sharenfs=\"%s\" %s", COMMAND, 1131 opts != NULL ? opts : "off", dataset); 1132 pfile = popen(command, "r"); 1133 if (pfile != NULL) { 1134 ret = pclose(pfile); 1135 if (ret != 0) 1136 ret = SA_SYSTEM_ERR; 1137 } 1138 } 1139 if (opts != NULL) 1140 free(opts); 1141 if (dataset != NULL) 1142 free(dataset); 1143 free(command); 1144 } 1145 return (ret); 1146 } 1147 1148 /* 1149 * add_resources(share, opt) 1150 * 1151 * Add resource properties to those in "opt". Resources are prefixed 1152 * with name=resourcename. 1153 */ 1154 static char * 1155 add_resources(sa_share_t share, char *opt) 1156 { 1157 char *newopt = NULL; 1158 char *propstr; 1159 sa_resource_t resource; 1160 1161 newopt = strdup(opt); 1162 if (newopt == NULL) 1163 return (newopt); 1164 1165 for (resource = sa_get_share_resource(share, NULL); 1166 resource != NULL; 1167 resource = sa_get_next_resource(resource)) { 1168 char *name; 1169 size_t size; 1170 1171 name = sa_get_resource_attr(resource, "name"); 1172 if (name == NULL) { 1173 free(newopt); 1174 return (NULL); 1175 } 1176 size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 1177 newopt = calloc(1, size); 1178 if (newopt != NULL) 1179 (void) snprintf(newopt, size, "%s,name=%s", opt, name); 1180 sa_free_attr_string(name); 1181 free(opt); 1182 opt = newopt; 1183 propstr = sa_proto_legacy_format("smb", resource, 0); 1184 if (propstr == NULL) { 1185 free(opt); 1186 return (NULL); 1187 } 1188 size = strlen(propstr) + strlen(opt) + 2; 1189 newopt = calloc(1, size); 1190 if (newopt != NULL) 1191 (void) snprintf(newopt, size, "%s,%s", opt, propstr); 1192 free(opt); 1193 opt = newopt; 1194 } 1195 return (opt); 1196 } 1197 1198 /* 1199 * sa_zfs_set_sharesmb(group, path, on) 1200 * 1201 * Update the "sharesmb" property on the path. If on is true, then set 1202 * to the properties on the group or "on" if no properties are 1203 * defined. Set to "off" if on is false. 1204 */ 1205 1206 int 1207 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 1208 { 1209 int ret = SA_NOT_IMPLEMENTED; 1210 char *command; 1211 sa_share_t share; 1212 1213 /* In case SMB not enabled */ 1214 if (sa_get_optionset(group, "smb") == NULL) 1215 return (SA_NOT_SUPPORTED); 1216 1217 command = malloc(ZFS_MAXPROPLEN * 2); 1218 if (command != NULL) { 1219 char *opts = NULL; 1220 char *dataset = NULL; 1221 FILE *pfile; 1222 sa_handle_impl_t impl_handle; 1223 1224 if (on) { 1225 char *newopt; 1226 1227 share = sa_get_share(group, NULL); 1228 opts = sa_proto_legacy_format("smb", share, 1); 1229 if (opts != NULL && strlen(opts) == 0) { 1230 free(opts); 1231 opts = strdup("on"); 1232 } 1233 newopt = add_resources(opts, share); 1234 free(opts); 1235 opts = newopt; 1236 } 1237 1238 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1239 assert(impl_handle != NULL); 1240 if (impl_handle != NULL) 1241 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1242 else 1243 ret = SA_SYSTEM_ERR; 1244 1245 if (dataset != NULL) { 1246 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1247 "echo %s set sharesmb=\"%s\" %s", COMMAND, 1248 opts != NULL ? opts : "off", dataset); 1249 pfile = popen(command, "r"); 1250 if (pfile != NULL) { 1251 ret = pclose(pfile); 1252 if (ret != 0) 1253 ret = SA_SYSTEM_ERR; 1254 } 1255 } 1256 if (opts != NULL) 1257 free(opts); 1258 if (dataset != NULL) 1259 free(dataset); 1260 free(command); 1261 } 1262 return (ret); 1263 } 1264 1265 /* 1266 * sa_zfs_update(group) 1267 * 1268 * call back to ZFS to update the share if necessary. 1269 * Don't do it if it isn't a real change. 1270 */ 1271 int 1272 sa_zfs_update(sa_group_t group) 1273 { 1274 sa_optionset_t protopt; 1275 sa_group_t parent; 1276 char *command; 1277 char *optstring; 1278 int ret = SA_OK; 1279 int doupdate = 0; 1280 FILE *pfile; 1281 1282 if (sa_is_share(group)) 1283 parent = sa_get_parent_group(group); 1284 else 1285 parent = group; 1286 1287 if (parent != NULL) { 1288 command = malloc(ZFS_MAXPROPLEN * 2); 1289 if (command == NULL) 1290 return (SA_NO_MEMORY); 1291 1292 *command = '\0'; 1293 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 1294 protopt = sa_get_next_optionset(protopt)) { 1295 1296 char *proto = sa_get_optionset_attr(protopt, "type"); 1297 char *path; 1298 char *dataset = NULL; 1299 char *zfsopts = NULL; 1300 1301 if (sa_is_share(group)) { 1302 path = sa_get_share_attr((sa_share_t)group, 1303 "path"); 1304 if (path != NULL) { 1305 sa_handle_impl_t impl_handle; 1306 1307 impl_handle = sa_find_group_handle( 1308 group); 1309 if (impl_handle != NULL) 1310 dataset = get_zfs_dataset( 1311 impl_handle, path, B_FALSE); 1312 else 1313 ret = SA_SYSTEM_ERR; 1314 1315 sa_free_attr_string(path); 1316 } 1317 } else { 1318 dataset = sa_get_group_attr(group, "name"); 1319 } 1320 /* update only when there is an optstring found */ 1321 doupdate = 0; 1322 if (proto != NULL && dataset != NULL) { 1323 optstring = sa_proto_legacy_format(proto, 1324 group, 1); 1325 zfsopts = get_zfs_property(dataset, 1326 ZFS_PROP_SHARENFS); 1327 1328 if (optstring != NULL && zfsopts != NULL) { 1329 if (strcmp(optstring, zfsopts) != 0) 1330 doupdate++; 1331 } 1332 if (doupdate) { 1333 if (optstring != NULL && 1334 strlen(optstring) > 0) { 1335 (void) snprintf(command, 1336 ZFS_MAXPROPLEN * 2, 1337 "%s set share%s=%s %s", 1338 COMMAND, proto, 1339 optstring, dataset); 1340 } else { 1341 (void) snprintf(command, 1342 ZFS_MAXPROPLEN * 2, 1343 "%s set share%s=on %s", 1344 COMMAND, proto, 1345 dataset); 1346 } 1347 pfile = popen(command, "r"); 1348 if (pfile != NULL) 1349 ret = pclose(pfile); 1350 switch (ret) { 1351 default: 1352 case 1: 1353 ret = SA_SYSTEM_ERR; 1354 break; 1355 case 2: 1356 ret = SA_SYNTAX_ERR; 1357 break; 1358 case 0: 1359 break; 1360 } 1361 } 1362 if (optstring != NULL) 1363 free(optstring); 1364 if (zfsopts != NULL) 1365 free(zfsopts); 1366 } 1367 if (proto != NULL) 1368 sa_free_attr_string(proto); 1369 if (dataset != NULL) 1370 free(dataset); 1371 } 1372 free(command); 1373 } 1374 return (ret); 1375 } 1376 1377 /* 1378 * sa_group_is_zfs(group) 1379 * 1380 * Given the group, determine if the zfs attribute is set. 1381 */ 1382 1383 int 1384 sa_group_is_zfs(sa_group_t group) 1385 { 1386 char *zfs; 1387 int ret = 0; 1388 1389 zfs = sa_get_group_attr(group, "zfs"); 1390 if (zfs != NULL) { 1391 ret = 1; 1392 sa_free_attr_string(zfs); 1393 } 1394 return (ret); 1395 } 1396 1397 /* 1398 * sa_path_is_zfs(path) 1399 * 1400 * Check to see if the file system path represents is of type "zfs". 1401 */ 1402 1403 int 1404 sa_path_is_zfs(char *path) 1405 { 1406 char *fstype; 1407 int ret = 0; 1408 1409 fstype = sa_fstype(path); 1410 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 1411 ret = 1; 1412 if (fstype != NULL) 1413 sa_free_fstype(fstype); 1414 return (ret); 1415 } 1416 1417 int 1418 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1419 { 1420 char *path; 1421 1422 /* Make sure path is valid */ 1423 1424 path = sa_get_share_attr(share, "path"); 1425 if (path != NULL) { 1426 (void) memset(sh, 0, sizeof (sh)); 1427 (void) sa_fillshare(share, proto, sh); 1428 sa_free_attr_string(path); 1429 return (0); 1430 } else 1431 return (1); 1432 } 1433 1434 #define SMAX(i, j) \ 1435 if ((j) > (i)) { \ 1436 (i) = (j); \ 1437 } 1438 1439 int 1440 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 1441 void *exportdata, zfs_share_op_t operation) 1442 { 1443 libzfs_handle_t *libhandle; 1444 sa_group_t group; 1445 sa_handle_t sahandle; 1446 char *dataset; 1447 int err = EINVAL; 1448 int i, j; 1449 char newpath[MAXPATHLEN]; 1450 char *pathp; 1451 1452 /* 1453 * First find the dataset name 1454 */ 1455 if ((group = sa_get_parent_group(share)) == NULL) { 1456 return (EINVAL); 1457 } 1458 if ((sahandle = sa_find_group_handle(group)) == NULL) { 1459 return (EINVAL); 1460 } 1461 1462 /* 1463 * If get_zfs_dataset fails, see if it is a subdirectory 1464 */ 1465 1466 pathp = path; 1467 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 1468 char *p; 1469 1470 if (pathp == path) { 1471 (void) strlcpy(newpath, path, sizeof (newpath)); 1472 pathp = newpath; 1473 } 1474 1475 /* 1476 * Make sure only one leading '/' This condition came 1477 * about when using HAStoragePlus which insisted on 1478 * putting an extra leading '/' in the ZFS path 1479 * name. The problem is fixed in other areas, but this 1480 * will catch any other ways that a double slash might 1481 * get introduced. 1482 */ 1483 while (*pathp == '/' && *(pathp + 1) == '/') 1484 pathp++; 1485 1486 /* 1487 * chop off part of path, but if we are at root then 1488 * make sure path is a / 1489 */ 1490 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1491 if (pathp == p) { 1492 *(p + 1) = '\0'; /* skip over /, root case */ 1493 } else { 1494 *p = '\0'; 1495 } 1496 } else { 1497 return (EINVAL); 1498 } 1499 } 1500 1501 libhandle = libzfs_init(); 1502 if (libhandle != NULL) { 1503 char *resource_name; 1504 1505 i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1506 sh->sh_size = i; 1507 1508 j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1509 sh->sh_size += j; 1510 SMAX(i, j); 1511 1512 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1513 sh->sh_size += j; 1514 SMAX(i, j); 1515 1516 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1517 sh->sh_size += j; 1518 SMAX(i, j); 1519 1520 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1521 sh->sh_size += j; 1522 SMAX(i, j); 1523 1524 resource_name = sa_get_resource_attr(resource, "name"); 1525 1526 err = zfs_deleg_share_nfs(libhandle, dataset, path, 1527 resource_name, exportdata, sh, i, operation); 1528 if (err == SA_OK) 1529 sa_update_sharetab_ts(sahandle); 1530 else 1531 err = errno; 1532 if (resource_name) 1533 sa_free_attr_string(resource_name); 1534 1535 libzfs_fini(libhandle); 1536 } 1537 free(dataset); 1538 return (err); 1539 } 1540 1541 /* 1542 * sa_get_zfs_handle(handle) 1543 * 1544 * Given an sa_handle_t, return the libzfs_handle_t *. This is only 1545 * used internally by libzfs. Needed in order to avoid including 1546 * libshare_impl.h in libzfs. 1547 */ 1548 1549 libzfs_handle_t * 1550 sa_get_zfs_handle(sa_handle_t handle) 1551 { 1552 sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 1553 1554 return (implhandle->zfs_libhandle); 1555 } 1556 1557 /* 1558 * sa_get_zfs_info(libzfs, path, mountpoint, dataset) 1559 * 1560 * Find the ZFS dataset and mountpoint for a given path 1561 */ 1562 int 1563 sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp, 1564 char *datasetp) 1565 { 1566 get_all_cbdata_t cb = { 0 }; 1567 int i; 1568 char mountpoint[ZFS_MAXPROPLEN]; 1569 char dataset[ZFS_MAXPROPLEN]; 1570 char canmount[ZFS_MAXPROPLEN]; 1571 char *dp; 1572 int count; 1573 int ret = 0; 1574 1575 cb.cb_types = ZFS_TYPE_FILESYSTEM; 1576 1577 if (libzfs == NULL) 1578 return (0); 1579 1580 (void) zfs_iter_root(libzfs, get_one_filesystem, &cb); 1581 count = cb.cb_used; 1582 1583 qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare); 1584 for (i = 0; i < count; i++) { 1585 /* must have a mountpoint */ 1586 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT, 1587 mountpoint, sizeof (mountpoint), 1588 NULL, NULL, 0, B_FALSE) != 0) { 1589 /* no mountpoint */ 1590 continue; 1591 } 1592 1593 /* mountpoint must be a path */ 1594 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 1595 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1596 /* 1597 * Search mmttab for mountpoint 1598 */ 1599 1600 if (get_legacy_mountpoint(path, dataset, 1601 ZFS_MAXPROPLEN, mountpoint, 1602 ZFS_MAXPROPLEN) == 0) { 1603 ret = 1; 1604 break; 1605 } 1606 continue; 1607 } 1608 1609 /* canmount must be set */ 1610 canmount[0] = '\0'; 1611 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount, 1612 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 1613 strcmp(canmount, "off") == 0) 1614 continue; 1615 1616 /* 1617 * have a mountable handle but want to skip those marked none 1618 * and legacy 1619 */ 1620 if (strcmp(mountpoint, path) == 0) { 1621 dp = (char *)zfs_get_name(cb.cb_handles[i]); 1622 if (dp != NULL) { 1623 if (datasetp != NULL) 1624 (void) strcpy(datasetp, dp); 1625 if (mountpointp != NULL) 1626 (void) strcpy(mountpointp, mountpoint); 1627 ret = 1; 1628 } 1629 break; 1630 } 1631 1632 } 1633 1634 return (ret); 1635 } 1636 1637 /* 1638 * This method builds values for "sharesmb" property from the 1639 * nvlist argument. The values are returned in sharesmb_val variable. 1640 */ 1641 static int 1642 sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val) 1643 { 1644 char cur_val[MAXPATHLEN]; 1645 char *name, *val; 1646 nvpair_t *cur; 1647 int err = 0; 1648 1649 cur = nvlist_next_nvpair(nvl, NULL); 1650 while (cur != NULL) { 1651 name = nvpair_name(cur); 1652 err = nvpair_value_string(cur, &val); 1653 if ((err != 0) || (name == NULL) || (val == NULL)) 1654 return (-1); 1655 1656 (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val); 1657 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1658 1659 cur = nvlist_next_nvpair(nvl, cur); 1660 } 1661 1662 return (0); 1663 } 1664 1665 /* 1666 * This method builds values for "sharesmb" property from values 1667 * already existing on the share. The properties set via sa_zfs_sprint_new_prop 1668 * method are passed in sharesmb_val. If a existing property is already 1669 * set via sa_zfs_sprint_new_prop method, then they are not appended 1670 * to the sharesmb_val string. The returned sharesmb_val string is a combination 1671 * of new and existing values for 'sharesmb' property. 1672 */ 1673 static int 1674 sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val) 1675 { 1676 char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN]; 1677 char *token, *last, *value; 1678 1679 if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts, 1680 sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0) 1681 return (-1); 1682 1683 if (strstr(shareopts, "=") == NULL) 1684 return (0); 1685 1686 for (token = strtok_r(shareopts, ",", &last); token != NULL; 1687 token = strtok_r(NULL, ",", &last)) { 1688 value = strchr(token, '='); 1689 if (value == NULL) 1690 return (-1); 1691 *value++ = '\0'; 1692 1693 (void) snprintf(cur_val, MAXPATHLEN, "%s=", token); 1694 if (strstr(sharesmb_val, cur_val) == NULL) { 1695 (void) strlcat(cur_val, value, MAXPATHLEN); 1696 (void) strlcat(cur_val, ",", MAXPATHLEN); 1697 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1698 } 1699 } 1700 1701 return (0); 1702 } 1703 1704 /* 1705 * Sets the share properties on a ZFS share. For now, this method sets only 1706 * the "sharesmb" property. 1707 * 1708 * This method includes building a comma seperated name-value string to be 1709 * set on the "sharesmb" property of a ZFS share. This name-value string is 1710 * build in 2 steps: 1711 * - New property values given as name-value pair are set first. 1712 * - Existing optionset properties, which are not part of the new properties 1713 * passed in step 1, are appended to the newly set properties. 1714 */ 1715 int 1716 sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl) 1717 { 1718 zfs_handle_t *z_fs; 1719 libzfs_handle_t *z_lib; 1720 char sharesmb_val[MAXPATHLEN]; 1721 char *dataset, *lastcomma; 1722 1723 if (nvlist_empty(nvl)) 1724 return (0); 1725 1726 if ((handle == NULL) || (path == NULL)) 1727 return (-1); 1728 1729 if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL) 1730 return (-1); 1731 1732 if ((z_lib = libzfs_init()) == NULL) { 1733 free(dataset); 1734 return (-1); 1735 } 1736 1737 z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET); 1738 if (z_fs == NULL) { 1739 free(dataset); 1740 libzfs_fini(z_lib); 1741 return (-1); 1742 } 1743 1744 bzero(sharesmb_val, MAXPATHLEN); 1745 if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) { 1746 free(dataset); 1747 zfs_close(z_fs); 1748 libzfs_fini(z_lib); 1749 return (-1); 1750 } 1751 1752 if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) { 1753 free(dataset); 1754 zfs_close(z_fs); 1755 libzfs_fini(z_lib); 1756 return (-1); 1757 } 1758 1759 lastcomma = strrchr(sharesmb_val, ','); 1760 if ((lastcomma != NULL) && (lastcomma[1] == '\0')) 1761 *lastcomma = '\0'; 1762 1763 (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB), 1764 sharesmb_val); 1765 free(dataset); 1766 zfs_close(z_fs); 1767 libzfs_fini(z_lib); 1768 1769 return (0); 1770 } 1771