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 char *options; 565 566 set_node_attr(group, "zfs", "true"); 567 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, &err); 568 if (err == SA_OK) { 569 if (strcmp(shareopts, "on") == 0) 570 shareopts = "rw"; 571 572 options = strdup(shareopts); 573 if (options != NULL) { 574 err = sa_parse_legacy_options(group, options, 575 "nfs"); 576 free(options); 577 } 578 if (err == SA_PROP_SHARE_ONLY) { 579 /* 580 * Same as above, some properties may 581 * only be on shares, but due to the 582 * ZFS sub-groups being artificial, we 583 * sometimes get this and have to deal 584 * with it. We do it by attempting to 585 * put it on the share. 586 */ 587 options = strdup(shareopts); 588 if (options != NULL) { 589 err = sa_parse_legacy_options(share, 590 options, "nfs"); 591 free(options); 592 } 593 } 594 /* Mark as the defining node of the subgroup */ 595 set_node_attr(share, "subgroup", "true"); 596 597 /* unmark the share's changed state */ 598 set_node_attr(share, "changed", NULL); 599 } 600 return (err); 601 } 602 603 /* 604 * zfs_grp_error(err) 605 * 606 * Print group create error, but only once. If err is 0 do the 607 * print else don't. 608 */ 609 610 static void 611 zfs_grp_error(int err) 612 { 613 if (err == 0) { 614 /* only print error once */ 615 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 616 "Cannot create ZFS subgroup during initialization:" 617 " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 618 } 619 } 620 621 /* 622 * sa_get_zfs_shares(handle, groupname) 623 * 624 * Walk the mnttab for all zfs mounts and determine which are 625 * shared. Find or create the appropriate group/sub-group to contain 626 * the shares. 627 * 628 * All shares are in a sub-group that will hold the properties. This 629 * allows representing the inherited property model. 630 */ 631 632 int 633 sa_get_zfs_shares(sa_handle_t handle, char *groupname) 634 { 635 sa_group_t group; 636 sa_group_t zfsgroup; 637 int legacy = 0; 638 int err; 639 zfs_handle_t **zlist; 640 char shareopts[ZFS_MAXPROPLEN]; 641 sa_share_t share; 642 zprop_source_t source; 643 char sourcestr[ZFS_MAXPROPLEN]; 644 char mountpoint[ZFS_MAXPROPLEN]; 645 size_t count = 0, i; 646 libzfs_handle_t *zfs_libhandle; 647 648 /* 649 * If we can't access libzfs, don't bother doing anything. 650 */ 651 zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 652 if (zfs_libhandle == NULL) 653 return (SA_SYSTEM_ERR); 654 655 zfsgroup = find_or_create_group(handle, groupname, "nfs", &err); 656 if (zfsgroup == NULL) 657 return (legacy); 658 659 /* 660 * need to walk the mounted ZFS pools and datasets to 661 * find shares that are possible. 662 */ 663 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 664 qsort(zlist, count, sizeof (void *), mountpoint_compare); 665 666 group = zfsgroup; 667 for (i = 0; i < count; i++) { 668 char *dataset; 669 670 source = ZPROP_SRC_ALL; 671 /* If no mountpoint, skip. */ 672 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 673 mountpoint, sizeof (mountpoint), NULL, NULL, 0, 674 B_FALSE) != 0) 675 continue; 676 677 /* 678 * zfs_get_name value must not be freed. It is just a 679 * pointer to a value in the handle. 680 */ 681 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 682 continue; 683 684 /* 685 * only deal with "mounted" file systems since 686 * unmounted file systems can't actually be shared. 687 */ 688 689 if (!zfs_is_mounted(zlist[i], NULL)) 690 continue; 691 692 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 693 sizeof (shareopts), &source, sourcestr, 694 ZFS_MAXPROPLEN, B_FALSE) == 0 && 695 strcmp(shareopts, "off") != 0) { 696 /* it is shared so add to list */ 697 share = sa_find_share(handle, mountpoint); 698 err = SA_OK; 699 if (share != NULL) { 700 /* 701 * A zfs file system had been shared 702 * through traditional methods 703 * (share/dfstab or added to a non-zfs 704 * group. Now it has been added to a 705 * ZFS group via the zfs 706 * command. Remove from previous 707 * config and setup with current 708 * options. 709 */ 710 err = sa_remove_share(share); 711 share = NULL; 712 } 713 if (err == SA_OK) { 714 if (source & ZPROP_SRC_INHERITED) { 715 err = zfs_inherited(handle, 716 share, sourcestr, 717 shareopts, mountpoint); 718 } else { 719 group = _sa_create_zfs_group( 720 zfsgroup, dataset); 721 if (group == NULL) { 722 static int err = 0; 723 /* 724 * there is a problem, 725 * but we can't do 726 * anything about it 727 * at this point so we 728 * issue a warning an 729 * move on. 730 */ 731 zfs_grp_error(err); 732 err = 1; 733 continue; 734 } 735 set_node_attr(group, "zfs", 736 "true"); 737 /* 738 * Add share with local opts via 739 * zfs_notinherited. 740 */ 741 err = zfs_notinherited(group, 742 mountpoint, shareopts); 743 } 744 } 745 } 746 } 747 /* 748 * Don't need to free the "zlist" variable since it is only a 749 * pointer to a cached value that will be freed when 750 * sa_fini() is called. 751 */ 752 return (legacy); 753 } 754 755 #define COMMAND "/usr/sbin/zfs" 756 757 /* 758 * sa_zfs_set_sharenfs(group, path, on) 759 * 760 * Update the "sharenfs" property on the path. If on is true, then set 761 * to the properties on the group or "on" if no properties are 762 * defined. Set to "off" if on is false. 763 */ 764 765 int 766 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 767 { 768 int ret = SA_NOT_IMPLEMENTED; 769 char *command; 770 771 command = malloc(ZFS_MAXPROPLEN * 2); 772 if (command != NULL) { 773 char *opts = NULL; 774 char *dataset = NULL; 775 FILE *pfile; 776 sa_handle_impl_t impl_handle; 777 /* for now, NFS is always available for "zfs" */ 778 if (on) { 779 opts = sa_proto_legacy_format("nfs", group, 1); 780 if (opts != NULL && strlen(opts) == 0) { 781 free(opts); 782 opts = strdup("on"); 783 } 784 } 785 786 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 787 assert(impl_handle != NULL); 788 if (impl_handle != NULL) 789 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 790 else 791 ret = SA_SYSTEM_ERR; 792 793 if (dataset != NULL) { 794 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 795 "%s set sharenfs=\"%s\" %s", COMMAND, 796 opts != NULL ? opts : "off", dataset); 797 pfile = popen(command, "r"); 798 if (pfile != NULL) { 799 ret = pclose(pfile); 800 if (ret != 0) 801 ret = SA_SYSTEM_ERR; 802 } 803 } 804 if (opts != NULL) 805 free(opts); 806 if (dataset != NULL) 807 free(dataset); 808 free(command); 809 } 810 return (ret); 811 } 812 813 /* 814 * sa_zfs_update(group) 815 * 816 * call back to ZFS to update the share if necessary. 817 * Don't do it if it isn't a real change. 818 */ 819 int 820 sa_zfs_update(sa_group_t group) 821 { 822 sa_optionset_t protopt; 823 sa_group_t parent; 824 char *command; 825 char *optstring; 826 int ret = SA_OK; 827 int doupdate = 0; 828 FILE *pfile; 829 830 if (sa_is_share(group)) 831 parent = sa_get_parent_group(group); 832 else 833 parent = group; 834 835 if (parent != NULL) { 836 command = malloc(ZFS_MAXPROPLEN * 2); 837 if (command == NULL) 838 return (SA_NO_MEMORY); 839 840 *command = '\0'; 841 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 842 protopt = sa_get_next_optionset(protopt)) { 843 844 char *proto = sa_get_optionset_attr(protopt, "type"); 845 char *path; 846 char *dataset = NULL; 847 char *zfsopts = NULL; 848 849 if (sa_is_share(group)) { 850 path = sa_get_share_attr((sa_share_t)group, 851 "path"); 852 if (path != NULL) { 853 sa_handle_impl_t impl_handle; 854 855 impl_handle = sa_find_group_handle( 856 group); 857 if (impl_handle != NULL) 858 dataset = get_zfs_dataset( 859 impl_handle, path, B_FALSE); 860 else 861 ret = SA_SYSTEM_ERR; 862 863 sa_free_attr_string(path); 864 } 865 } else { 866 dataset = sa_get_group_attr(group, "name"); 867 } 868 /* update only when there is an optstring found */ 869 doupdate = 0; 870 if (proto != NULL && dataset != NULL) { 871 optstring = sa_proto_legacy_format(proto, 872 group, 1); 873 zfsopts = get_zfs_property(dataset, 874 ZFS_PROP_SHARENFS); 875 876 if (optstring != NULL && zfsopts != NULL) { 877 if (strcmp(optstring, zfsopts) != 0) 878 doupdate++; 879 } 880 if (doupdate) { 881 if (optstring != NULL && 882 strlen(optstring) > 0) { 883 (void) snprintf(command, 884 ZFS_MAXPROPLEN * 2, 885 "%s set sharenfs=%s %s", 886 COMMAND, 887 optstring, dataset); 888 } else { 889 (void) snprintf(command, 890 ZFS_MAXPROPLEN * 2, 891 "%s set sharenfs=on %s", 892 COMMAND, 893 dataset); 894 } 895 pfile = popen(command, "r"); 896 if (pfile != NULL) 897 ret = pclose(pfile); 898 switch (ret) { 899 default: 900 case 1: 901 ret = SA_SYSTEM_ERR; 902 break; 903 case 2: 904 ret = SA_SYNTAX_ERR; 905 break; 906 case 0: 907 break; 908 } 909 } 910 if (optstring != NULL) 911 free(optstring); 912 if (zfsopts != NULL) 913 free(zfsopts); 914 } 915 if (proto != NULL) 916 sa_free_attr_string(proto); 917 if (dataset != NULL) 918 free(dataset); 919 } 920 free(command); 921 } 922 return (ret); 923 } 924 925 /* 926 * sa_group_is_zfs(group) 927 * 928 * Given the group, determine if the zfs attribute is set. 929 */ 930 931 int 932 sa_group_is_zfs(sa_group_t group) 933 { 934 char *zfs; 935 int ret = 0; 936 937 zfs = sa_get_group_attr(group, "zfs"); 938 if (zfs != NULL) { 939 ret = 1; 940 sa_free_attr_string(zfs); 941 } 942 return (ret); 943 } 944 945 /* 946 * sa_path_is_zfs(path) 947 * 948 * Check to see if the file system path represents is of type "zfs". 949 */ 950 951 int 952 sa_path_is_zfs(char *path) 953 { 954 char *fstype; 955 int ret = 0; 956 957 fstype = sa_fstype(path); 958 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 959 ret = 1; 960 if (fstype != NULL) 961 sa_free_fstype(fstype); 962 return (ret); 963 } 964 965 int 966 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 967 { 968 char *path; 969 970 /* Make sure path is valid */ 971 972 path = sa_get_share_attr(share, "path"); 973 if (path != NULL) { 974 (void) memset(sh, 0, sizeof (sh)); 975 (void) sa_fillshare(share, proto, sh); 976 sa_free_attr_string(path); 977 return (0); 978 } else 979 return (1); 980 } 981 982 #define SMAX(i, j) \ 983 if ((j) > (i)) { \ 984 (i) = (j); \ 985 } 986 987 int 988 sa_share_zfs(sa_share_t share, char *path, share_t *sh, 989 void *exportdata, boolean_t on) 990 { 991 libzfs_handle_t *libhandle; 992 sa_group_t group; 993 sa_handle_t sahandle; 994 char *dataset; 995 int err = EINVAL; 996 int i, j; 997 char newpath[MAXPATHLEN]; 998 char *pathp; 999 1000 /* 1001 * First find the dataset name 1002 */ 1003 if ((group = sa_get_parent_group(share)) == NULL) { 1004 return (SA_SYSTEM_ERR); 1005 } 1006 if ((sahandle = sa_find_group_handle(group)) == NULL) { 1007 return (SA_SYSTEM_ERR); 1008 } 1009 1010 /* 1011 * If get_zfs_dataset fails, see if it is a subdirectory 1012 */ 1013 1014 pathp = path; 1015 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 1016 char *p; 1017 1018 if (pathp == path) { 1019 (void) strlcpy(newpath, path, sizeof (newpath)); 1020 pathp = newpath; 1021 } 1022 1023 /* 1024 * chop off part of path, but if we are at root then 1025 * make sure path is a / 1026 */ 1027 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1028 if (pathp == p) { 1029 *(p + 1) = '\0'; /* skip over /, root case */ 1030 } else { 1031 *p = '\0'; 1032 } 1033 } else { 1034 return (SA_SYSTEM_ERR); 1035 } 1036 } 1037 1038 libhandle = libzfs_init(); 1039 if (libhandle != NULL) { 1040 1041 i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1042 sh->sh_size = i; 1043 1044 j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1045 sh->sh_size += j; 1046 SMAX(i, j); 1047 1048 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1049 sh->sh_size += j; 1050 SMAX(i, j); 1051 1052 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1053 sh->sh_size += j; 1054 SMAX(i, j); 1055 1056 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1057 sh->sh_size += j; 1058 SMAX(i, j); 1059 err = zfs_deleg_share_nfs(libhandle, dataset, path, 1060 exportdata, sh, i, on); 1061 libzfs_fini(libhandle); 1062 } 1063 free(dataset); 1064 return (err); 1065 } 1066