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 = calloc(*paths_len, sizeof (char *)); 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 /* Free non-null elements of the paths array */ 1006 for (int free_idx = 0; free_idx < *paths_len; 1007 ++free_idx) { 1008 if ((*paths)[free_idx] != NULL) 1009 free((*paths)[free_idx]); 1010 } 1011 free(*paths); 1012 *paths = NULL; 1013 *paths_len = 0; 1014 return (SA_SYSTEM_ERR); 1015 } 1016 (*paths)[i] = malloc(sizeof (char) * ZFS_MAXPROPLEN); 1017 err |= sa_get_zfs_share_common(handle, fs_handle, (*paths)[i], 1018 zfsgroup); 1019 } 1020 1021 return (err); 1022 } 1023 1024 /* 1025 * Initializes only the share with the specified sharename for use with 1026 * libshare. 1027 */ 1028 int 1029 sa_get_zfs_share_for_name(sa_handle_t handle, char *groupname, 1030 const char *sharename, char *outpath) 1031 { 1032 sa_group_t zfsgroup; 1033 libzfs_handle_t *zfs_libhandle; 1034 int err; 1035 1036 if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle, 1037 &zfsgroup, &err)) != SA_OK) { 1038 return (err); 1039 } 1040 /* Not an error, this could be a legacy condition */ 1041 if (zfsgroup == NULL) 1042 return (SA_OK); 1043 1044 zfs_handle_t *fs_handle = zfs_open(zfs_libhandle, 1045 sharename + strspn(sharename, "/"), ZFS_TYPE_DATASET); 1046 if (fs_handle == NULL) 1047 return (SA_SYSTEM_ERR); 1048 1049 err = sa_get_zfs_share_common(handle, fs_handle, outpath, zfsgroup); 1050 zfs_close(fs_handle); 1051 return (err); 1052 } 1053 1054 1055 1056 #define COMMAND "/usr/sbin/zfs" 1057 1058 /* 1059 * sa_zfs_set_sharenfs(group, path, on) 1060 * 1061 * Update the "sharenfs" property on the path. If on is true, then set 1062 * to the properties on the group or "on" if no properties are 1063 * defined. Set to "off" if on is false. 1064 */ 1065 1066 int 1067 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 1068 { 1069 int ret = SA_NOT_IMPLEMENTED; 1070 char *command; 1071 1072 command = malloc(ZFS_MAXPROPLEN * 2); 1073 if (command != NULL) { 1074 char *opts = NULL; 1075 char *dataset = NULL; 1076 FILE *pfile; 1077 sa_handle_impl_t impl_handle; 1078 /* for now, NFS is always available for "zfs" */ 1079 if (on) { 1080 opts = sa_proto_legacy_format("nfs", group, 1); 1081 if (opts != NULL && strlen(opts) == 0) { 1082 free(opts); 1083 opts = strdup("on"); 1084 } 1085 } 1086 1087 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1088 assert(impl_handle != NULL); 1089 if (impl_handle != NULL) 1090 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1091 else 1092 ret = SA_SYSTEM_ERR; 1093 1094 if (dataset != NULL) { 1095 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1096 "%s set sharenfs=\"%s\" %s", COMMAND, 1097 opts != NULL ? opts : "off", dataset); 1098 pfile = popen(command, "r"); 1099 if (pfile != NULL) { 1100 ret = pclose(pfile); 1101 if (ret != 0) 1102 ret = SA_SYSTEM_ERR; 1103 } 1104 } 1105 if (opts != NULL) 1106 free(opts); 1107 if (dataset != NULL) 1108 free(dataset); 1109 free(command); 1110 } 1111 return (ret); 1112 } 1113 1114 /* 1115 * add_resources(share, opt) 1116 * 1117 * Add resource properties to those in "opt". Resources are prefixed 1118 * with name=resourcename. 1119 */ 1120 static char * 1121 add_resources(sa_share_t share, char *opt) 1122 { 1123 char *newopt = NULL; 1124 char *propstr; 1125 sa_resource_t resource; 1126 1127 newopt = strdup(opt); 1128 if (newopt == NULL) 1129 return (newopt); 1130 1131 for (resource = sa_get_share_resource(share, NULL); 1132 resource != NULL; 1133 resource = sa_get_next_resource(resource)) { 1134 char *name; 1135 size_t size; 1136 1137 name = sa_get_resource_attr(resource, "name"); 1138 if (name == NULL) { 1139 free(newopt); 1140 return (NULL); 1141 } 1142 size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 1143 newopt = calloc(1, size); 1144 if (newopt != NULL) 1145 (void) snprintf(newopt, size, "%s,name=%s", opt, name); 1146 sa_free_attr_string(name); 1147 free(opt); 1148 opt = newopt; 1149 propstr = sa_proto_legacy_format("smb", resource, 0); 1150 if (propstr == NULL) { 1151 free(opt); 1152 return (NULL); 1153 } 1154 size = strlen(propstr) + strlen(opt) + 2; 1155 newopt = calloc(1, size); 1156 if (newopt != NULL) 1157 (void) snprintf(newopt, size, "%s,%s", opt, propstr); 1158 free(opt); 1159 opt = newopt; 1160 } 1161 return (opt); 1162 } 1163 1164 /* 1165 * sa_zfs_set_sharesmb(group, path, on) 1166 * 1167 * Update the "sharesmb" property on the path. If on is true, then set 1168 * to the properties on the group or "on" if no properties are 1169 * defined. Set to "off" if on is false. 1170 */ 1171 1172 int 1173 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 1174 { 1175 int ret = SA_NOT_IMPLEMENTED; 1176 char *command; 1177 sa_share_t share; 1178 1179 /* In case SMB not enabled */ 1180 if (sa_get_optionset(group, "smb") == NULL) 1181 return (SA_NOT_SUPPORTED); 1182 1183 command = malloc(ZFS_MAXPROPLEN * 2); 1184 if (command != NULL) { 1185 char *opts = NULL; 1186 char *dataset = NULL; 1187 FILE *pfile; 1188 sa_handle_impl_t impl_handle; 1189 1190 if (on) { 1191 char *newopt; 1192 1193 share = sa_get_share(group, NULL); 1194 opts = sa_proto_legacy_format("smb", share, 1); 1195 if (opts != NULL && strlen(opts) == 0) { 1196 free(opts); 1197 opts = strdup("on"); 1198 } 1199 newopt = add_resources(opts, share); 1200 free(opts); 1201 opts = newopt; 1202 } 1203 1204 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1205 assert(impl_handle != NULL); 1206 if (impl_handle != NULL) 1207 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1208 else 1209 ret = SA_SYSTEM_ERR; 1210 1211 if (dataset != NULL) { 1212 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1213 "echo %s set sharesmb=\"%s\" %s", COMMAND, 1214 opts != NULL ? opts : "off", dataset); 1215 pfile = popen(command, "r"); 1216 if (pfile != NULL) { 1217 ret = pclose(pfile); 1218 if (ret != 0) 1219 ret = SA_SYSTEM_ERR; 1220 } 1221 } 1222 if (opts != NULL) 1223 free(opts); 1224 if (dataset != NULL) 1225 free(dataset); 1226 free(command); 1227 } 1228 return (ret); 1229 } 1230 1231 /* 1232 * sa_zfs_update(group) 1233 * 1234 * call back to ZFS to update the share if necessary. 1235 * Don't do it if it isn't a real change. 1236 */ 1237 int 1238 sa_zfs_update(sa_group_t group) 1239 { 1240 sa_optionset_t protopt; 1241 sa_group_t parent; 1242 char *command; 1243 char *optstring; 1244 int ret = SA_OK; 1245 int doupdate = 0; 1246 FILE *pfile; 1247 1248 if (sa_is_share(group)) 1249 parent = sa_get_parent_group(group); 1250 else 1251 parent = group; 1252 1253 if (parent != NULL) { 1254 command = malloc(ZFS_MAXPROPLEN * 2); 1255 if (command == NULL) 1256 return (SA_NO_MEMORY); 1257 1258 *command = '\0'; 1259 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 1260 protopt = sa_get_next_optionset(protopt)) { 1261 1262 char *proto = sa_get_optionset_attr(protopt, "type"); 1263 char *path; 1264 char *dataset = NULL; 1265 char *zfsopts = NULL; 1266 1267 if (sa_is_share(group)) { 1268 path = sa_get_share_attr((sa_share_t)group, 1269 "path"); 1270 if (path != NULL) { 1271 sa_handle_impl_t impl_handle; 1272 1273 impl_handle = sa_find_group_handle( 1274 group); 1275 if (impl_handle != NULL) 1276 dataset = get_zfs_dataset( 1277 impl_handle, path, B_FALSE); 1278 else 1279 ret = SA_SYSTEM_ERR; 1280 1281 sa_free_attr_string(path); 1282 } 1283 } else { 1284 dataset = sa_get_group_attr(group, "name"); 1285 } 1286 /* update only when there is an optstring found */ 1287 doupdate = 0; 1288 if (proto != NULL && dataset != NULL) { 1289 optstring = sa_proto_legacy_format(proto, 1290 group, 1); 1291 zfsopts = get_zfs_property(dataset, 1292 ZFS_PROP_SHARENFS); 1293 1294 if (optstring != NULL && zfsopts != NULL) { 1295 if (strcmp(optstring, zfsopts) != 0) 1296 doupdate++; 1297 } 1298 if (doupdate) { 1299 if (optstring != NULL && 1300 strlen(optstring) > 0) { 1301 (void) snprintf(command, 1302 ZFS_MAXPROPLEN * 2, 1303 "%s set share%s=%s %s", 1304 COMMAND, proto, 1305 optstring, dataset); 1306 } else { 1307 (void) snprintf(command, 1308 ZFS_MAXPROPLEN * 2, 1309 "%s set share%s=on %s", 1310 COMMAND, proto, 1311 dataset); 1312 } 1313 pfile = popen(command, "r"); 1314 if (pfile != NULL) 1315 ret = pclose(pfile); 1316 switch (ret) { 1317 default: 1318 case 1: 1319 ret = SA_SYSTEM_ERR; 1320 break; 1321 case 2: 1322 ret = SA_SYNTAX_ERR; 1323 break; 1324 case 0: 1325 break; 1326 } 1327 } 1328 if (optstring != NULL) 1329 free(optstring); 1330 if (zfsopts != NULL) 1331 free(zfsopts); 1332 } 1333 if (proto != NULL) 1334 sa_free_attr_string(proto); 1335 if (dataset != NULL) 1336 free(dataset); 1337 } 1338 free(command); 1339 } 1340 return (ret); 1341 } 1342 1343 /* 1344 * sa_group_is_zfs(group) 1345 * 1346 * Given the group, determine if the zfs attribute is set. 1347 */ 1348 1349 int 1350 sa_group_is_zfs(sa_group_t group) 1351 { 1352 char *zfs; 1353 int ret = 0; 1354 1355 zfs = sa_get_group_attr(group, "zfs"); 1356 if (zfs != NULL) { 1357 ret = 1; 1358 sa_free_attr_string(zfs); 1359 } 1360 return (ret); 1361 } 1362 1363 /* 1364 * sa_path_is_zfs(path) 1365 * 1366 * Check to see if the file system path represents is of type "zfs". 1367 */ 1368 1369 int 1370 sa_path_is_zfs(char *path) 1371 { 1372 char *fstype; 1373 int ret = 0; 1374 1375 fstype = sa_fstype(path); 1376 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 1377 ret = 1; 1378 if (fstype != NULL) 1379 sa_free_fstype(fstype); 1380 return (ret); 1381 } 1382 1383 int 1384 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1385 { 1386 char *path; 1387 1388 /* Make sure path is valid */ 1389 1390 path = sa_get_share_attr(share, "path"); 1391 if (path != NULL) { 1392 (void) memset(sh, 0, sizeof (sh)); 1393 (void) sa_fillshare(share, proto, sh); 1394 sa_free_attr_string(path); 1395 return (0); 1396 } else 1397 return (1); 1398 } 1399 1400 #define SMAX(i, j) \ 1401 if ((j) > (i)) { \ 1402 (i) = (j); \ 1403 } 1404 1405 int 1406 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 1407 void *exportdata, zfs_share_op_t operation) 1408 { 1409 libzfs_handle_t *libhandle; 1410 sa_group_t group; 1411 sa_handle_t sahandle; 1412 char *dataset; 1413 int err = EINVAL; 1414 int i, j; 1415 char newpath[MAXPATHLEN]; 1416 char *pathp; 1417 1418 /* 1419 * First find the dataset name 1420 */ 1421 if ((group = sa_get_parent_group(share)) == NULL) { 1422 return (EINVAL); 1423 } 1424 if ((sahandle = sa_find_group_handle(group)) == NULL) { 1425 return (EINVAL); 1426 } 1427 1428 /* 1429 * If get_zfs_dataset fails, see if it is a subdirectory 1430 */ 1431 1432 pathp = path; 1433 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 1434 char *p; 1435 1436 if (pathp == path) { 1437 (void) strlcpy(newpath, path, sizeof (newpath)); 1438 pathp = newpath; 1439 } 1440 1441 /* 1442 * Make sure only one leading '/' This condition came 1443 * about when using HAStoragePlus which insisted on 1444 * putting an extra leading '/' in the ZFS path 1445 * name. The problem is fixed in other areas, but this 1446 * will catch any other ways that a double slash might 1447 * get introduced. 1448 */ 1449 while (*pathp == '/' && *(pathp + 1) == '/') 1450 pathp++; 1451 1452 /* 1453 * chop off part of path, but if we are at root then 1454 * make sure path is a / 1455 */ 1456 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1457 if (pathp == p) { 1458 *(p + 1) = '\0'; /* skip over /, root case */ 1459 } else { 1460 *p = '\0'; 1461 } 1462 } else { 1463 return (EINVAL); 1464 } 1465 } 1466 1467 libhandle = libzfs_init(); 1468 if (libhandle != NULL) { 1469 char *resource_name; 1470 1471 i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1472 sh->sh_size = i; 1473 1474 j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1475 sh->sh_size += j; 1476 SMAX(i, j); 1477 1478 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1479 sh->sh_size += j; 1480 SMAX(i, j); 1481 1482 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1483 sh->sh_size += j; 1484 SMAX(i, j); 1485 1486 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1487 sh->sh_size += j; 1488 SMAX(i, j); 1489 1490 resource_name = sa_get_resource_attr(resource, "name"); 1491 1492 err = zfs_deleg_share_nfs(libhandle, dataset, path, 1493 resource_name, exportdata, sh, i, operation); 1494 if (err == SA_OK) 1495 sa_update_sharetab_ts(sahandle); 1496 else 1497 err = errno; 1498 if (resource_name) 1499 sa_free_attr_string(resource_name); 1500 1501 libzfs_fini(libhandle); 1502 } 1503 free(dataset); 1504 return (err); 1505 } 1506 1507 /* 1508 * sa_get_zfs_handle(handle) 1509 * 1510 * Given an sa_handle_t, return the libzfs_handle_t *. This is only 1511 * used internally by libzfs. Needed in order to avoid including 1512 * libshare_impl.h in libzfs. 1513 */ 1514 1515 libzfs_handle_t * 1516 sa_get_zfs_handle(sa_handle_t handle) 1517 { 1518 sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 1519 1520 return (implhandle->zfs_libhandle); 1521 } 1522 1523 /* 1524 * sa_get_zfs_info(libzfs, path, mountpoint, dataset) 1525 * 1526 * Find the ZFS dataset and mountpoint for a given path 1527 */ 1528 int 1529 sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp, 1530 char *datasetp) 1531 { 1532 get_all_cbdata_t cb = { 0 }; 1533 int i; 1534 char mountpoint[ZFS_MAXPROPLEN]; 1535 char dataset[ZFS_MAXPROPLEN]; 1536 char canmount[ZFS_MAXPROPLEN]; 1537 char *dp; 1538 int count; 1539 int ret = 0; 1540 1541 cb.cb_types = ZFS_TYPE_FILESYSTEM; 1542 1543 if (libzfs == NULL) 1544 return (0); 1545 1546 (void) zfs_iter_root(libzfs, get_one_filesystem, &cb); 1547 count = cb.cb_used; 1548 1549 qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare); 1550 for (i = 0; i < count; i++) { 1551 /* must have a mountpoint */ 1552 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT, 1553 mountpoint, sizeof (mountpoint), 1554 NULL, NULL, 0, B_FALSE) != 0) { 1555 /* no mountpoint */ 1556 continue; 1557 } 1558 1559 /* mountpoint must be a path */ 1560 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 1561 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1562 /* 1563 * Search mmttab for mountpoint 1564 */ 1565 1566 if (get_legacy_mountpoint(path, dataset, 1567 ZFS_MAXPROPLEN, mountpoint, 1568 ZFS_MAXPROPLEN) == 0) { 1569 ret = 1; 1570 break; 1571 } 1572 continue; 1573 } 1574 1575 /* canmount must be set */ 1576 canmount[0] = '\0'; 1577 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount, 1578 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 1579 strcmp(canmount, "off") == 0) 1580 continue; 1581 1582 /* 1583 * have a mountable handle but want to skip those marked none 1584 * and legacy 1585 */ 1586 if (strcmp(mountpoint, path) == 0) { 1587 dp = (char *)zfs_get_name(cb.cb_handles[i]); 1588 if (dp != NULL) { 1589 if (datasetp != NULL) 1590 (void) strcpy(datasetp, dp); 1591 if (mountpointp != NULL) 1592 (void) strcpy(mountpointp, mountpoint); 1593 ret = 1; 1594 } 1595 break; 1596 } 1597 1598 } 1599 1600 return (ret); 1601 } 1602 1603 /* 1604 * This method builds values for "sharesmb" property from the 1605 * nvlist argument. The values are returned in sharesmb_val variable. 1606 */ 1607 static int 1608 sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val) 1609 { 1610 char cur_val[MAXPATHLEN]; 1611 char *name, *val; 1612 nvpair_t *cur; 1613 int err = 0; 1614 1615 cur = nvlist_next_nvpair(nvl, NULL); 1616 while (cur != NULL) { 1617 name = nvpair_name(cur); 1618 err = nvpair_value_string(cur, &val); 1619 if ((err != 0) || (name == NULL) || (val == NULL)) 1620 return (-1); 1621 1622 (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val); 1623 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1624 1625 cur = nvlist_next_nvpair(nvl, cur); 1626 } 1627 1628 return (0); 1629 } 1630 1631 /* 1632 * This method builds values for "sharesmb" property from values 1633 * already existing on the share. The properties set via sa_zfs_sprint_new_prop 1634 * method are passed in sharesmb_val. If a existing property is already 1635 * set via sa_zfs_sprint_new_prop method, then they are not appended 1636 * to the sharesmb_val string. The returned sharesmb_val string is a combination 1637 * of new and existing values for 'sharesmb' property. 1638 */ 1639 static int 1640 sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val) 1641 { 1642 char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN]; 1643 char *token, *last, *value; 1644 1645 if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts, 1646 sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0) 1647 return (-1); 1648 1649 if (strstr(shareopts, "=") == NULL) 1650 return (0); 1651 1652 for (token = strtok_r(shareopts, ",", &last); token != NULL; 1653 token = strtok_r(NULL, ",", &last)) { 1654 value = strchr(token, '='); 1655 if (value == NULL) 1656 return (-1); 1657 *value++ = '\0'; 1658 1659 (void) snprintf(cur_val, MAXPATHLEN, "%s=", token); 1660 if (strstr(sharesmb_val, cur_val) == NULL) { 1661 (void) strlcat(cur_val, value, MAXPATHLEN); 1662 (void) strlcat(cur_val, ",", MAXPATHLEN); 1663 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN); 1664 } 1665 } 1666 1667 return (0); 1668 } 1669 1670 /* 1671 * Sets the share properties on a ZFS share. For now, this method sets only 1672 * the "sharesmb" property. 1673 * 1674 * This method includes building a comma seperated name-value string to be 1675 * set on the "sharesmb" property of a ZFS share. This name-value string is 1676 * build in 2 steps: 1677 * - New property values given as name-value pair are set first. 1678 * - Existing optionset properties, which are not part of the new properties 1679 * passed in step 1, are appended to the newly set properties. 1680 */ 1681 int 1682 sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl) 1683 { 1684 zfs_handle_t *z_fs; 1685 libzfs_handle_t *z_lib; 1686 char sharesmb_val[MAXPATHLEN]; 1687 char *dataset, *lastcomma; 1688 1689 if (nvlist_empty(nvl)) 1690 return (0); 1691 1692 if ((handle == NULL) || (path == NULL)) 1693 return (-1); 1694 1695 if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL) 1696 return (-1); 1697 1698 if ((z_lib = libzfs_init()) == NULL) { 1699 free(dataset); 1700 return (-1); 1701 } 1702 1703 z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET); 1704 if (z_fs == NULL) { 1705 free(dataset); 1706 libzfs_fini(z_lib); 1707 return (-1); 1708 } 1709 1710 bzero(sharesmb_val, MAXPATHLEN); 1711 if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) { 1712 free(dataset); 1713 zfs_close(z_fs); 1714 libzfs_fini(z_lib); 1715 return (-1); 1716 } 1717 1718 if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) { 1719 free(dataset); 1720 zfs_close(z_fs); 1721 libzfs_fini(z_lib); 1722 return (-1); 1723 } 1724 1725 lastcomma = strrchr(sharesmb_val, ','); 1726 if ((lastcomma != NULL) && (lastcomma[1] == '\0')) 1727 *lastcomma = '\0'; 1728 1729 (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB), 1730 sharesmb_val); 1731 free(dataset); 1732 zfs_close(z_fs); 1733 libzfs_fini(z_lib); 1734 1735 return (0); 1736 } 1737