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