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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <libzfs.h> 30 #include <string.h> 31 #include <libshare.h> 32 #include "libshare_impl.h" 33 #include <libintl.h> 34 35 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *); 36 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 37 extern char *sa_fstype(char *); 38 extern void set_node_attr(void *, char *, char *); 39 extern int sa_is_share(void *); 40 41 /* 42 * File system specific code for ZFS. The original code was stolen 43 * from the "zfs" command and modified to better suit this library's 44 * usage. 45 */ 46 47 typedef struct get_all_cbdata { 48 zfs_handle_t **cb_handles; 49 size_t cb_alloc; 50 size_t cb_used; 51 } get_all_cbdata_t; 52 53 /* 54 * sa_zfs_init(impl_handle) 55 * 56 * Initialize an access handle into libzfs. The handle needs to stay 57 * around until sa_zfs_fini() in order to maintain the cache of 58 * mounts. 59 */ 60 61 int 62 sa_zfs_init(sa_handle_impl_t impl_handle) 63 { 64 impl_handle->zfs_libhandle = libzfs_init(); 65 if (impl_handle->zfs_libhandle != NULL) { 66 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 67 return (B_TRUE); 68 } 69 return (B_FALSE); 70 } 71 72 /* 73 * sa_zfs_fini(impl_handle) 74 * 75 * cleanup data structures and the libzfs handle used for accessing 76 * zfs file share info. 77 */ 78 79 void 80 sa_zfs_fini(sa_handle_impl_t impl_handle) 81 { 82 if (impl_handle->zfs_libhandle != NULL) { 83 libzfs_fini(impl_handle->zfs_libhandle); 84 impl_handle->zfs_libhandle = NULL; 85 if (impl_handle->zfs_list != NULL) { 86 /* 87 * contents of zfs_list were already freed by 88 * the call to libzfs_fini(). 89 */ 90 free(impl_handle->zfs_list); 91 impl_handle->zfs_list = NULL; 92 impl_handle->zfs_list_count = 0; 93 } 94 } 95 } 96 97 /* 98 * get_one_filesystem(zfs_handle_t, data) 99 * 100 * an interator function called while iterating through the ZFS 101 * root. It accumulates into an array of file system handles that can 102 * be used to derive info about those file systems. 103 */ 104 105 static int 106 get_one_filesystem(zfs_handle_t *zhp, void *data) 107 { 108 get_all_cbdata_t *cbp = data; 109 110 /* 111 * Skip any zvols 112 */ 113 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) { 114 zfs_close(zhp); 115 return (0); 116 } 117 118 if (cbp->cb_alloc == cbp->cb_used) { 119 zfs_handle_t **handles; 120 121 if (cbp->cb_alloc == 0) 122 cbp->cb_alloc = 64; 123 else 124 cbp->cb_alloc *= 2; 125 126 handles = calloc(1, cbp->cb_alloc * sizeof (void *)); 127 if (handles == NULL) { 128 return (0); 129 } 130 131 if (cbp->cb_handles) { 132 (void) memcpy(handles, cbp->cb_handles, 133 cbp->cb_used * sizeof (void *)); 134 free(cbp->cb_handles); 135 } 136 137 cbp->cb_handles = handles; 138 } 139 140 cbp->cb_handles[cbp->cb_used++] = zhp; 141 142 return (zfs_iter_filesystems(zhp, get_one_filesystem, data)); 143 } 144 145 /* 146 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 147 * 148 * iterate through all ZFS file systems starting at the root. Returns 149 * a count and an array of handle pointers. Allocating is only done 150 * once. The caller does not need to free since it will be done at 151 * sa_zfs_fini() time. 152 */ 153 154 static void 155 get_all_filesystems(sa_handle_impl_t impl_handle, 156 zfs_handle_t ***fslist, size_t *count) 157 { 158 get_all_cbdata_t cb = { 0 }; 159 160 if (impl_handle->zfs_list != NULL) { 161 *fslist = impl_handle->zfs_list; 162 *count = impl_handle->zfs_list_count; 163 return; 164 } 165 166 (void) zfs_iter_root(impl_handle->zfs_libhandle, 167 get_one_filesystem, &cb); 168 169 impl_handle->zfs_list = *fslist = cb.cb_handles; 170 impl_handle->zfs_list_count = *count = cb.cb_used; 171 } 172 173 /* 174 * mountpoint_compare(a, b) 175 * 176 * compares the mountpoint on two zfs file systems handles. 177 * returns values following strcmp() model. 178 */ 179 180 static int 181 mountpoint_compare(const void *a, const void *b) 182 { 183 zfs_handle_t **za = (zfs_handle_t **)a; 184 zfs_handle_t **zb = (zfs_handle_t **)b; 185 char mounta[MAXPATHLEN]; 186 char mountb[MAXPATHLEN]; 187 188 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 189 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 190 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 191 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 192 193 return (strcmp(mounta, mountb)); 194 } 195 196 /* 197 * get_zfs_dataset(impl_handle, path) 198 * 199 * get the name of the ZFS dataset the path is equivalent to. The 200 * dataset name is used for get/set of ZFS properties since libzfs 201 * requires a dataset to do a zfs_open(). 202 */ 203 204 static char * 205 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path) 206 { 207 size_t i, count = 0; 208 char *dataset = NULL; 209 zfs_handle_t **zlist; 210 char mountpoint[ZFS_MAXPROPLEN]; 211 char canmount[ZFS_MAXPROPLEN]; 212 213 get_all_filesystems(impl_handle, &zlist, &count); 214 qsort(zlist, count, sizeof (void *), mountpoint_compare); 215 for (i = 0; i < count; i++) { 216 /* must have a mountpoint */ 217 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 218 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 219 /* no mountpoint */ 220 continue; 221 } 222 223 /* mountpoint must be a path */ 224 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 225 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) 226 continue; 227 228 /* canmount must be set */ 229 canmount[0] = '\0'; 230 if (!zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 231 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 232 strcmp(canmount, "off") == 0) 233 continue; 234 235 /* 236 * have a mountable handle but want to skip those marked none 237 * and legacy 238 */ 239 if (strcmp(mountpoint, path) == 0) { 240 dataset = (char *)zfs_get_name(zlist[i]); 241 break; 242 } 243 244 } 245 246 if (dataset != NULL) 247 dataset = strdup(dataset); 248 249 return (dataset); 250 } 251 252 /* 253 * get_zfs_property(dataset, property) 254 * 255 * Get the file system property specified from the ZFS dataset. 256 */ 257 258 static char * 259 get_zfs_property(char *dataset, zfs_prop_t property) 260 { 261 zfs_handle_t *handle = NULL; 262 char shareopts[ZFS_MAXPROPLEN]; 263 libzfs_handle_t *libhandle; 264 265 libhandle = libzfs_init(); 266 if (libhandle != NULL) { 267 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 268 if (handle != NULL) { 269 if (zfs_prop_get(handle, property, shareopts, 270 sizeof (shareopts), NULL, NULL, 0, 271 B_FALSE) == 0) { 272 zfs_close(handle); 273 libzfs_fini(libhandle); 274 return (strdup(shareopts)); 275 } 276 zfs_close(handle); 277 } 278 libzfs_fini(libhandle); 279 } 280 return (NULL); 281 } 282 283 /* 284 * sa_zfs_is_shared(handle, path) 285 * 286 * Check to see if the ZFS path provided has the sharenfs option set 287 * or not. 288 */ 289 290 int 291 sa_zfs_is_shared(sa_handle_t sahandle, char *path) 292 { 293 int ret = 0; 294 char *dataset; 295 zfs_handle_t *handle = NULL; 296 char shareopts[ZFS_MAXPROPLEN]; 297 libzfs_handle_t *libhandle; 298 299 dataset = get_zfs_dataset((sa_handle_t)sahandle, path); 300 if (dataset != NULL) { 301 libhandle = libzfs_init(); 302 if (libhandle != NULL) { 303 handle = zfs_open(libhandle, dataset, 304 ZFS_TYPE_FILESYSTEM); 305 if (handle != NULL) { 306 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 307 shareopts, sizeof (shareopts), NULL, NULL, 308 0, B_FALSE) == 0 && 309 strcmp(shareopts, "off") != 0) { 310 ret = 1; /* it is shared */ 311 } 312 zfs_close(handle); 313 } 314 libzfs_fini(libhandle); 315 } 316 free(dataset); 317 } 318 return (ret); 319 } 320 321 /* 322 * find_or_create_group(groupname, proto, *err) 323 * 324 * While walking the ZFS tree, we need to add shares to a defined 325 * group. If the group doesn't exist, create it first, making sure it 326 * is marked as a ZFS group. 327 * 328 * Note that all ZFS shares are in a subgroup of the top level group 329 * called "zfs". 330 */ 331 332 static sa_group_t 333 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 334 { 335 sa_group_t group; 336 sa_optionset_t optionset; 337 int ret = SA_OK; 338 339 /* 340 * we check to see if the "zfs" group exists. Since this 341 * should be the top level group, we don't want the 342 * parent. This is to make sure the zfs group has been created 343 * and to created if it hasn't been. 344 */ 345 group = sa_get_group(handle, groupname); 346 if (group == NULL) { 347 group = sa_create_group(handle, groupname, &ret); 348 349 /* make sure this is flagged as a ZFS group */ 350 if (group != NULL) 351 ret = sa_set_group_attr(group, "zfs", "true"); 352 } 353 if (group != NULL) { 354 if (proto != NULL) { 355 optionset = sa_get_optionset(group, proto); 356 if (optionset == NULL) { 357 optionset = sa_create_optionset(group, proto); 358 } else { 359 char **protolist; 360 int numprotos, i; 361 numprotos = sa_get_protocols(&protolist); 362 for (i = 0; i < numprotos; i++) { 363 optionset = sa_create_optionset(group, 364 protolist[i]); 365 } 366 if (protolist != NULL) 367 free(protolist); 368 } 369 } 370 } 371 if (err != NULL) 372 *err = ret; 373 return (group); 374 } 375 376 /* 377 * find_or_create_zfs_subgroup(groupname, optstring, *err) 378 * 379 * ZFS shares will be in a subgroup of the "zfs" master group. This 380 * function looks to see if the groupname exists and returns it if it 381 * does or else creates a new one with the specified name and returns 382 * that. The "zfs" group will exist before we get here, but we make 383 * sure just in case. 384 * 385 * err must be a valid pointer. 386 */ 387 388 static sa_group_t 389 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, 390 char *optstring, int *err) 391 { 392 sa_group_t group = NULL; 393 sa_group_t zfs; 394 char *name; 395 char *options; 396 397 /* start with the top-level "zfs" group */ 398 zfs = sa_get_group(handle, "zfs"); 399 *err = SA_OK; 400 if (zfs != NULL) { 401 for (group = sa_get_sub_group(zfs); group != NULL; 402 group = sa_get_next_group(group)) { 403 name = sa_get_group_attr(group, "name"); 404 if (name != NULL && strcmp(name, groupname) == 0) { 405 /* have the group so break out of here */ 406 sa_free_attr_string(name); 407 break; 408 } 409 if (name != NULL) 410 sa_free_attr_string(name); 411 } 412 413 if (group == NULL) { 414 /* 415 * need to create the sub-group since it doesn't exist 416 */ 417 group = _sa_create_zfs_group(zfs, groupname); 418 if (group != NULL) 419 set_node_attr(group, "zfs", "true"); 420 if (strcmp(optstring, "on") == 0) 421 optstring = "rw"; 422 if (group != NULL) { 423 options = strdup(optstring); 424 if (options != NULL) { 425 *err = sa_parse_legacy_options(group, 426 options, "nfs"); 427 free(options); 428 } else { 429 *err = SA_NO_MEMORY; 430 } 431 } 432 } 433 } 434 return (group); 435 } 436 437 /* 438 * zfs_inherited(handle, source, sourcestr) 439 * 440 * handle case of inherited sharenfs. Pulled out of sa_get_zfs_shares 441 * for readability. 442 */ 443 static int 444 zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 445 char *shareopts, char *mountpoint) 446 { 447 int doshopt = 0; 448 int err = SA_OK; 449 sa_group_t group; 450 451 /* 452 * Need to find the "real" parent sub-group. It may not be 453 * mounted, but it was identified in the "sourcestr" 454 * variable. The real parent not mounted can occur if 455 * "canmount=off and sharenfs=on". 456 */ 457 group = find_or_create_zfs_subgroup(handle, sourcestr, shareopts, 458 &doshopt); 459 if (group != NULL) { 460 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 461 &err); 462 /* 463 * some options may only be on shares. If the opt 464 * string contains one of those, we put it just on the 465 * share. 466 */ 467 if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 468 char *options; 469 options = strdup(shareopts); 470 if (options != NULL) { 471 err = sa_parse_legacy_options(share, options, 472 "nfs"); 473 free(options); 474 } 475 } 476 } else { 477 err = SA_NO_MEMORY; 478 } 479 return (err); 480 } 481 482 /* 483 * zfs_notinherited() 484 * 485 * handle case where this is the top of a sub-group in ZFS. Pulled out 486 * of sa_get_zfs_shares for readability. 487 */ 488 static int 489 zfs_notinherited(sa_group_t group, char *mountpoint, char *shareopts) 490 { 491 int err = SA_OK; 492 sa_share_t share; 493 494 set_node_attr(group, "zfs", "true"); 495 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, &err); 496 if (err == SA_OK) { 497 if (strcmp(shareopts, "on") != 0) { 498 char *options; 499 options = strdup(shareopts); 500 if (options != NULL) { 501 err = sa_parse_legacy_options(group, options, 502 "nfs"); 503 free(options); 504 } 505 if (err == SA_PROP_SHARE_ONLY) { 506 /* 507 * Same as above, some properties may 508 * only be on shares, but due to the 509 * ZFS sub-groups being artificial, we 510 * sometimes get this and have to deal 511 * with it. We do it by attempting to 512 * put it on the share. 513 */ 514 options = strdup(shareopts); 515 if (options != NULL) 516 err = sa_parse_legacy_options(share, 517 options, "nfs"); 518 if (options != NULL) 519 free(options); 520 } 521 /* unmark the share's changed state */ 522 set_node_attr(share, "changed", NULL); 523 } 524 } 525 return (err); 526 } 527 528 /* 529 * zfs_grp_error(err) 530 * 531 * Print group create error, but only once. If err is 0 do the 532 * print else don't. 533 */ 534 535 static void 536 zfs_grp_error(int err) 537 { 538 if (err == 0) { 539 /* only print error once */ 540 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 541 "Cannot create ZFS subgroup during initialization:" 542 " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 543 } 544 } 545 546 /* 547 * sa_get_zfs_shares(handle, groupname) 548 * 549 * Walk the mnttab for all zfs mounts and determine which are 550 * shared. Find or create the appropriate group/sub-group to contain 551 * the shares. 552 * 553 * All shares are in a sub-group that will hold the properties. This 554 * allows representing the inherited property model. 555 */ 556 557 int 558 sa_get_zfs_shares(sa_handle_t handle, char *groupname) 559 { 560 sa_group_t group; 561 sa_group_t zfsgroup; 562 int legacy = 0; 563 int err; 564 zfs_handle_t **zlist; 565 char shareopts[ZFS_MAXPROPLEN]; 566 sa_share_t share; 567 zfs_source_t source; 568 char sourcestr[ZFS_MAXPROPLEN]; 569 char mountpoint[ZFS_MAXPROPLEN]; 570 size_t count = 0, i; 571 libzfs_handle_t *zfs_libhandle; 572 573 /* 574 * If we can't access libzfs, don't bother doing anything. 575 */ 576 zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 577 if (zfs_libhandle == NULL) 578 return (SA_SYSTEM_ERR); 579 580 zfsgroup = find_or_create_group(handle, groupname, "nfs", &err); 581 if (zfsgroup != NULL) { 582 /* 583 * need to walk the mounted ZFS pools and datasets to 584 * find shares that are possible. 585 */ 586 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 587 qsort(zlist, count, sizeof (void *), mountpoint_compare); 588 589 group = zfsgroup; 590 for (i = 0; i < count; i++) { 591 char *dataset; 592 593 source = ZFS_SRC_ALL; 594 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 595 mountpoint, sizeof (mountpoint), NULL, NULL, 0, 596 B_FALSE) != 0) { 597 /* no mountpoint */ 598 continue; 599 } 600 601 /* 602 * zfs_get_name value must not be freed. It is just a 603 * pointer to a value in the handle. 604 */ 605 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 606 continue; 607 608 /* 609 * only deal with "mounted" file systems since 610 * unmounted file systems can't actually be shared. 611 */ 612 613 if (!zfs_is_mounted(zlist[i], NULL)) 614 continue; 615 616 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 617 sizeof (shareopts), &source, sourcestr, 618 ZFS_MAXPROPLEN, B_FALSE) == 0 && 619 strcmp(shareopts, "off") != 0) { 620 /* it is shared so add to list */ 621 share = sa_find_share(handle, mountpoint); 622 err = SA_OK; 623 if (share != NULL) { 624 /* 625 * A zfs file system had been shared 626 * through traditional methods 627 * (share/dfstab or added to a non-zfs 628 * group. Now it has been added to a 629 * ZFS group via the zfs 630 * command. Remove from previous 631 * config and setup with current 632 * options. 633 */ 634 err = sa_remove_share(share); 635 share = NULL; 636 } 637 if (err == SA_OK) { 638 if (source & ZFS_SRC_INHERITED) { 639 err = zfs_inherited(handle, 640 share, sourcestr, 641 shareopts, mountpoint); 642 } else { 643 group = _sa_create_zfs_group( 644 zfsgroup, dataset); 645 if (group == NULL) { 646 static int err = 0; 647 /* 648 * there is a problem, 649 * but we can't do 650 * anything about it 651 * at this point so we 652 * issue a warning an 653 * move on. 654 */ 655 zfs_grp_error(err); 656 err = 1; 657 continue; 658 } 659 set_node_attr(group, "zfs", 660 "true"); 661 share = _sa_add_share(group, 662 mountpoint, 663 SA_SHARE_TRANSIENT, &err); 664 err = zfs_notinherited(group, 665 mountpoint, shareopts); 666 } 667 } 668 } 669 } 670 } 671 /* 672 * Don't need to free the "zlist" variable since it is only a 673 * pointer to a cached value that will be freed when 674 * sa_fini() is called. 675 */ 676 return (legacy); 677 } 678 679 #define COMMAND "/usr/sbin/zfs" 680 681 /* 682 * sa_zfs_set_sharenfs(group, path, on) 683 * 684 * Update the "sharenfs" property on the path. If on is true, then set 685 * to the properties on the group or "on" if no properties are 686 * defined. Set to "off" if on is false. 687 */ 688 689 int 690 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 691 { 692 int ret = SA_NOT_IMPLEMENTED; 693 char *command; 694 695 command = malloc(ZFS_MAXPROPLEN * 2); 696 if (command != NULL) { 697 char *opts = NULL; 698 char *dataset = NULL; 699 FILE *pfile; 700 sa_handle_impl_t impl_handle; 701 /* for now, NFS is always available for "zfs" */ 702 if (on) { 703 opts = sa_proto_legacy_format("nfs", group, 1); 704 if (opts != NULL && strlen(opts) == 0) { 705 free(opts); 706 opts = strdup("on"); 707 } 708 } 709 710 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 711 assert(impl_handle != NULL); 712 if (impl_handle != NULL) 713 dataset = get_zfs_dataset(impl_handle, path); 714 else 715 ret = SA_SYSTEM_ERR; 716 717 if (dataset != NULL) { 718 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 719 "%s set sharenfs=\"%s\" %s", COMMAND, 720 opts != NULL ? opts : "off", dataset); 721 pfile = popen(command, "r"); 722 if (pfile != NULL) { 723 ret = pclose(pfile); 724 if (ret != 0) 725 ret = SA_SYSTEM_ERR; 726 } 727 } 728 if (opts != NULL) 729 free(opts); 730 if (dataset != NULL) 731 free(dataset); 732 free(command); 733 } 734 return (ret); 735 } 736 737 /* 738 * sa_zfs_update(group) 739 * 740 * call back to ZFS to update the share if necessary. 741 * Don't do it if it isn't a real change. 742 */ 743 int 744 sa_zfs_update(sa_group_t group) 745 { 746 sa_optionset_t protopt; 747 sa_group_t parent; 748 char *command; 749 char *optstring; 750 int ret = SA_OK; 751 int doupdate = 0; 752 FILE *pfile; 753 754 if (sa_is_share(group)) 755 parent = sa_get_parent_group(group); 756 else 757 parent = group; 758 759 if (parent != NULL) { 760 command = malloc(ZFS_MAXPROPLEN * 2); 761 if (command == NULL) 762 return (SA_NO_MEMORY); 763 764 *command = '\0'; 765 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 766 protopt = sa_get_next_optionset(protopt)) { 767 768 char *proto = sa_get_optionset_attr(protopt, "type"); 769 char *path; 770 char *dataset = NULL; 771 char *zfsopts = NULL; 772 773 if (sa_is_share(group)) { 774 path = sa_get_share_attr((sa_share_t)group, 775 "path"); 776 if (path != NULL) { 777 sa_handle_impl_t impl_handle; 778 779 impl_handle = sa_find_group_handle( 780 group); 781 if (impl_handle != NULL) 782 dataset = get_zfs_dataset( 783 impl_handle, path); 784 else 785 ret = SA_SYSTEM_ERR; 786 787 sa_free_attr_string(path); 788 } 789 } else { 790 dataset = sa_get_group_attr(group, "name"); 791 } 792 /* update only when there is an optstring found */ 793 doupdate = 0; 794 if (proto != NULL && dataset != NULL) { 795 optstring = sa_proto_legacy_format(proto, 796 group, 1); 797 zfsopts = get_zfs_property(dataset, 798 ZFS_PROP_SHARENFS); 799 800 if (optstring != NULL && zfsopts != NULL) { 801 if (strcmp(optstring, zfsopts) != 0) 802 doupdate++; 803 } 804 805 if (doupdate) { 806 if (optstring != NULL && 807 strlen(optstring) > 0) { 808 (void) snprintf(command, 809 ZFS_MAXPROPLEN * 2, 810 "%s set sharenfs=%s %s" 811 COMMAND, 812 optstring, dataset); 813 } else { 814 (void) snprintf(command, 815 ZFS_MAXPROPLEN * 2, 816 "%s set sharenfs=on %s", 817 COMMAND, 818 dataset); 819 } 820 pfile = popen(command, "r"); 821 if (pfile != NULL) 822 ret = pclose(pfile); 823 switch (ret) { 824 default: 825 case 1: 826 ret = SA_SYSTEM_ERR; 827 break; 828 case 2: 829 ret = SA_SYNTAX_ERR; 830 break; 831 case 0: 832 break; 833 } 834 } 835 if (optstring != NULL) 836 free(optstring); 837 if (zfsopts != NULL) 838 free(zfsopts); 839 } 840 if (proto != NULL) 841 sa_free_attr_string(proto); 842 if (dataset != NULL) 843 free(dataset); 844 } 845 free(command); 846 } 847 return (ret); 848 } 849 850 /* 851 * sa_group_is_zfs(group) 852 * 853 * Given the group, determine if the zfs attribute is set. 854 */ 855 856 int 857 sa_group_is_zfs(sa_group_t group) 858 { 859 char *zfs; 860 int ret = 0; 861 862 zfs = sa_get_group_attr(group, "zfs"); 863 if (zfs != NULL) { 864 ret = 1; 865 sa_free_attr_string(zfs); 866 } 867 return (ret); 868 } 869 870 /* 871 * sa_path_is_zfs(path) 872 * 873 * Check to see if the file system path represents is of type "zfs". 874 */ 875 876 int 877 sa_path_is_zfs(char *path) 878 { 879 char *fstype; 880 int ret = 0; 881 882 fstype = sa_fstype(path); 883 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 884 ret = 1; 885 if (fstype != NULL) 886 sa_free_fstype(fstype); 887 return (ret); 888 } 889