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