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 /* 610 * need to walk the mounted ZFS pools and datasets to 611 * find shares that are possible. 612 */ 613 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 614 qsort(zlist, count, sizeof (void *), mountpoint_compare); 615 616 group = zfsgroup; 617 for (i = 0; i < count; i++) { 618 char *dataset; 619 620 source = ZFS_SRC_ALL; 621 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 622 mountpoint, sizeof (mountpoint), NULL, NULL, 0, 623 B_FALSE) != 0) { 624 /* no mountpoint */ 625 continue; 626 } 627 628 /* 629 * zfs_get_name value must not be freed. It is just a 630 * pointer to a value in the handle. 631 */ 632 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 633 continue; 634 635 /* 636 * only deal with "mounted" file systems since 637 * unmounted file systems can't actually be shared. 638 */ 639 640 if (!zfs_is_mounted(zlist[i], NULL)) 641 continue; 642 643 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 644 sizeof (shareopts), &source, sourcestr, 645 ZFS_MAXPROPLEN, B_FALSE) == 0 && 646 strcmp(shareopts, "off") != 0) { 647 /* it is shared so add to list */ 648 share = sa_find_share(handle, mountpoint); 649 err = SA_OK; 650 if (share != NULL) { 651 /* 652 * A zfs file system had been shared 653 * through traditional methods 654 * (share/dfstab or added to a non-zfs 655 * group. Now it has been added to a 656 * ZFS group via the zfs 657 * command. Remove from previous 658 * config and setup with current 659 * options. 660 */ 661 err = sa_remove_share(share); 662 share = NULL; 663 } 664 if (err == SA_OK) { 665 if (source & ZFS_SRC_INHERITED) { 666 err = zfs_inherited(handle, 667 share, sourcestr, 668 shareopts, mountpoint); 669 } else { 670 group = _sa_create_zfs_group( 671 zfsgroup, dataset); 672 if (group == NULL) { 673 static int err = 0; 674 /* 675 * there is a problem, 676 * but we can't do 677 * anything about it 678 * at this point so we 679 * issue a warning an 680 * move on. 681 */ 682 zfs_grp_error(err); 683 err = 1; 684 continue; 685 } 686 set_node_attr(group, "zfs", 687 "true"); 688 share = _sa_add_share(group, 689 mountpoint, 690 SA_SHARE_TRANSIENT, &err); 691 err = zfs_notinherited(group, 692 mountpoint, shareopts); 693 } 694 } 695 } 696 } 697 } 698 /* 699 * Don't need to free the "zlist" variable since it is only a 700 * pointer to a cached value that will be freed when 701 * sa_fini() is called. 702 */ 703 return (legacy); 704 } 705 706 #define COMMAND "/usr/sbin/zfs" 707 708 /* 709 * sa_zfs_set_sharenfs(group, path, on) 710 * 711 * Update the "sharenfs" property on the path. If on is true, then set 712 * to the properties on the group or "on" if no properties are 713 * defined. Set to "off" if on is false. 714 */ 715 716 int 717 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 718 { 719 int ret = SA_NOT_IMPLEMENTED; 720 char *command; 721 722 command = malloc(ZFS_MAXPROPLEN * 2); 723 if (command != NULL) { 724 char *opts = NULL; 725 char *dataset = NULL; 726 FILE *pfile; 727 sa_handle_impl_t impl_handle; 728 /* for now, NFS is always available for "zfs" */ 729 if (on) { 730 opts = sa_proto_legacy_format("nfs", group, 1); 731 if (opts != NULL && strlen(opts) == 0) { 732 free(opts); 733 opts = strdup("on"); 734 } 735 } 736 737 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 738 assert(impl_handle != NULL); 739 if (impl_handle != NULL) 740 dataset = get_zfs_dataset(impl_handle, path); 741 else 742 ret = SA_SYSTEM_ERR; 743 744 if (dataset != NULL) { 745 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 746 "%s set sharenfs=\"%s\" %s", COMMAND, 747 opts != NULL ? opts : "off", dataset); 748 pfile = popen(command, "r"); 749 if (pfile != NULL) { 750 ret = pclose(pfile); 751 if (ret != 0) 752 ret = SA_SYSTEM_ERR; 753 } 754 } 755 if (opts != NULL) 756 free(opts); 757 if (dataset != NULL) 758 free(dataset); 759 free(command); 760 } 761 return (ret); 762 } 763 764 /* 765 * sa_zfs_update(group) 766 * 767 * call back to ZFS to update the share if necessary. 768 * Don't do it if it isn't a real change. 769 */ 770 int 771 sa_zfs_update(sa_group_t group) 772 { 773 sa_optionset_t protopt; 774 sa_group_t parent; 775 char *command; 776 char *optstring; 777 int ret = SA_OK; 778 int doupdate = 0; 779 FILE *pfile; 780 781 if (sa_is_share(group)) 782 parent = sa_get_parent_group(group); 783 else 784 parent = group; 785 786 if (parent != NULL) { 787 command = malloc(ZFS_MAXPROPLEN * 2); 788 if (command == NULL) 789 return (SA_NO_MEMORY); 790 791 *command = '\0'; 792 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 793 protopt = sa_get_next_optionset(protopt)) { 794 795 char *proto = sa_get_optionset_attr(protopt, "type"); 796 char *path; 797 char *dataset = NULL; 798 char *zfsopts = NULL; 799 800 if (sa_is_share(group)) { 801 path = sa_get_share_attr((sa_share_t)group, 802 "path"); 803 if (path != NULL) { 804 sa_handle_impl_t impl_handle; 805 806 impl_handle = sa_find_group_handle( 807 group); 808 if (impl_handle != NULL) 809 dataset = get_zfs_dataset( 810 impl_handle, path); 811 else 812 ret = SA_SYSTEM_ERR; 813 814 sa_free_attr_string(path); 815 } 816 } else { 817 dataset = sa_get_group_attr(group, "name"); 818 } 819 /* update only when there is an optstring found */ 820 doupdate = 0; 821 if (proto != NULL && dataset != NULL) { 822 optstring = sa_proto_legacy_format(proto, 823 group, 1); 824 zfsopts = get_zfs_property(dataset, 825 ZFS_PROP_SHARENFS); 826 827 if (optstring != NULL && zfsopts != NULL) { 828 if (strcmp(optstring, zfsopts) != 0) 829 doupdate++; 830 } 831 832 if (doupdate) { 833 if (optstring != NULL && 834 strlen(optstring) > 0) { 835 (void) snprintf(command, 836 ZFS_MAXPROPLEN * 2, 837 "%s set sharenfs=%s %s" 838 COMMAND, 839 optstring, dataset); 840 } else { 841 (void) snprintf(command, 842 ZFS_MAXPROPLEN * 2, 843 "%s set sharenfs=on %s", 844 COMMAND, 845 dataset); 846 } 847 pfile = popen(command, "r"); 848 if (pfile != NULL) 849 ret = pclose(pfile); 850 switch (ret) { 851 default: 852 case 1: 853 ret = SA_SYSTEM_ERR; 854 break; 855 case 2: 856 ret = SA_SYNTAX_ERR; 857 break; 858 case 0: 859 break; 860 } 861 } 862 if (optstring != NULL) 863 free(optstring); 864 if (zfsopts != NULL) 865 free(zfsopts); 866 } 867 if (proto != NULL) 868 sa_free_attr_string(proto); 869 if (dataset != NULL) 870 free(dataset); 871 } 872 free(command); 873 } 874 return (ret); 875 } 876 877 /* 878 * sa_group_is_zfs(group) 879 * 880 * Given the group, determine if the zfs attribute is set. 881 */ 882 883 int 884 sa_group_is_zfs(sa_group_t group) 885 { 886 char *zfs; 887 int ret = 0; 888 889 zfs = sa_get_group_attr(group, "zfs"); 890 if (zfs != NULL) { 891 ret = 1; 892 sa_free_attr_string(zfs); 893 } 894 return (ret); 895 } 896 897 /* 898 * sa_path_is_zfs(path) 899 * 900 * Check to see if the file system path represents is of type "zfs". 901 */ 902 903 int 904 sa_path_is_zfs(char *path) 905 { 906 char *fstype; 907 int ret = 0; 908 909 fstype = sa_fstype(path); 910 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 911 ret = 1; 912 if (fstype != NULL) 913 sa_free_fstype(fstype); 914 return (ret); 915 } 916