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