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