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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <libzfs.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <libshare.h> 32 #include "libshare_impl.h" 33 #include <libintl.h> 34 #include <sys/mnttab.h> 35 #include <sys/mntent.h> 36 37 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 38 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 39 extern char *sa_fstype(char *); 40 extern void set_node_attr(void *, char *, char *); 41 extern int sa_is_share(void *); 42 extern void sa_update_sharetab_ts(sa_handle_t); 43 44 /* 45 * File system specific code for ZFS. The original code was stolen 46 * from the "zfs" command and modified to better suit this library's 47 * usage. 48 */ 49 50 typedef struct get_all_cbdata { 51 zfs_handle_t **cb_handles; 52 size_t cb_alloc; 53 size_t cb_used; 54 uint_t cb_types; 55 } get_all_cbdata_t; 56 57 /* 58 * sa_zfs_init(impl_handle) 59 * 60 * Initialize an access handle into libzfs. The handle needs to stay 61 * around until sa_zfs_fini() in order to maintain the cache of 62 * mounts. 63 */ 64 65 int 66 sa_zfs_init(sa_handle_impl_t impl_handle) 67 { 68 impl_handle->zfs_libhandle = libzfs_init(); 69 if (impl_handle->zfs_libhandle != NULL) { 70 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 71 return (B_TRUE); 72 } 73 return (B_FALSE); 74 } 75 76 /* 77 * sa_zfs_fini(impl_handle) 78 * 79 * cleanup data structures and the libzfs handle used for accessing 80 * zfs file share info. 81 */ 82 83 void 84 sa_zfs_fini(sa_handle_impl_t impl_handle) 85 { 86 if (impl_handle->zfs_libhandle != NULL) { 87 if (impl_handle->zfs_list != NULL) { 88 zfs_handle_t **zhp = impl_handle->zfs_list; 89 size_t i; 90 91 /* 92 * Contents of zfs_list need to be freed so we 93 * don't lose ZFS handles. 94 */ 95 for (i = 0; i < impl_handle->zfs_list_count; i++) { 96 zfs_close(zhp[i]); 97 } 98 free(impl_handle->zfs_list); 99 impl_handle->zfs_list = NULL; 100 impl_handle->zfs_list_count = 0; 101 } 102 103 libzfs_fini(impl_handle->zfs_libhandle); 104 impl_handle->zfs_libhandle = NULL; 105 } 106 } 107 108 /* 109 * get_one_filesystem(zfs_handle_t, data) 110 * 111 * an iterator function called while iterating through the ZFS 112 * root. It accumulates into an array of file system handles that can 113 * be used to derive info about those file systems. 114 * 115 * Note that as this function is called, we close all zhp handles that 116 * are not going to be places into the cp_handles list. We don't want 117 * to close the ones we are keeping, but all others would be leaked if 118 * not closed here. 119 */ 120 121 static int 122 get_one_filesystem(zfs_handle_t *zhp, void *data) 123 { 124 get_all_cbdata_t *cbp = data; 125 zfs_type_t type = zfs_get_type(zhp); 126 127 /* 128 * Interate over any nested datasets. 129 */ 130 if (type == ZFS_TYPE_FILESYSTEM && 131 zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 132 zfs_close(zhp); 133 return (1); 134 } 135 136 /* 137 * Skip any datasets whose type does not match. 138 */ 139 if ((type & cbp->cb_types) == 0) { 140 zfs_close(zhp); 141 return (0); 142 } 143 144 if (cbp->cb_alloc == cbp->cb_used) { 145 zfs_handle_t **handles; 146 147 if (cbp->cb_alloc == 0) 148 cbp->cb_alloc = 64; 149 else 150 cbp->cb_alloc *= 2; 151 152 handles = (zfs_handle_t **)calloc(1, 153 cbp->cb_alloc * sizeof (void *)); 154 155 if (handles == NULL) { 156 zfs_close(zhp); 157 return (0); 158 } 159 if (cbp->cb_handles) { 160 bcopy(cbp->cb_handles, handles, 161 cbp->cb_used * sizeof (void *)); 162 free(cbp->cb_handles); 163 } 164 165 cbp->cb_handles = handles; 166 } 167 168 cbp->cb_handles[cbp->cb_used++] = zhp; 169 170 return (0); 171 } 172 173 /* 174 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 175 * 176 * iterate through all ZFS file systems starting at the root. Returns 177 * a count and an array of handle pointers. Allocating is only done 178 * once. The caller does not need to free since it will be done at 179 * sa_zfs_fini() time. 180 */ 181 182 static void 183 get_all_filesystems(sa_handle_impl_t impl_handle, 184 zfs_handle_t ***fslist, size_t *count) 185 { 186 get_all_cbdata_t cb = { 0 }; 187 cb.cb_types = ZFS_TYPE_FILESYSTEM; 188 189 if (impl_handle->zfs_list != NULL) { 190 *fslist = impl_handle->zfs_list; 191 *count = impl_handle->zfs_list_count; 192 return; 193 } 194 195 (void) zfs_iter_root(impl_handle->zfs_libhandle, 196 get_one_filesystem, &cb); 197 198 impl_handle->zfs_list = *fslist = cb.cb_handles; 199 impl_handle->zfs_list_count = *count = cb.cb_used; 200 } 201 202 /* 203 * mountpoint_compare(a, b) 204 * 205 * compares the mountpoint on two zfs file systems handles. 206 * returns values following strcmp() model. 207 */ 208 209 static int 210 mountpoint_compare(const void *a, const void *b) 211 { 212 zfs_handle_t **za = (zfs_handle_t **)a; 213 zfs_handle_t **zb = (zfs_handle_t **)b; 214 char mounta[MAXPATHLEN]; 215 char mountb[MAXPATHLEN]; 216 217 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 218 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 219 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 220 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 221 222 return (strcmp(mounta, mountb)); 223 } 224 225 /* 226 * return legacy mountpoint. Caller provides space for mountpoint. 227 */ 228 int 229 get_legacy_mountpoint(char *path, char *mountpoint, size_t len) 230 { 231 FILE *fp; 232 struct mnttab entry; 233 234 if ((fp = fopen(MNTTAB, "r")) == NULL) { 235 return (1); 236 } 237 238 while (getmntent(fp, &entry) == 0) { 239 240 if (entry.mnt_fstype == NULL || 241 strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 242 continue; 243 244 if (strcmp(entry.mnt_mountp, path) == 0) { 245 (void) strlcpy(mountpoint, entry.mnt_special, len); 246 (void) fclose(fp); 247 return (0); 248 } 249 } 250 (void) fclose(fp); 251 return (1); 252 } 253 254 /* 255 * get_zfs_dataset(impl_handle, path) 256 * 257 * get the name of the ZFS dataset the path is equivalent to. The 258 * dataset name is used for get/set of ZFS properties since libzfs 259 * requires a dataset to do a zfs_open(). 260 */ 261 262 static char * 263 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 264 boolean_t search_mnttab) 265 { 266 size_t i, count = 0; 267 char *dataset = NULL; 268 zfs_handle_t **zlist; 269 char mountpoint[ZFS_MAXPROPLEN]; 270 char canmount[ZFS_MAXPROPLEN]; 271 272 get_all_filesystems(impl_handle, &zlist, &count); 273 qsort(zlist, count, sizeof (void *), mountpoint_compare); 274 for (i = 0; i < count; i++) { 275 /* must have a mountpoint */ 276 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 277 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 278 /* no mountpoint */ 279 continue; 280 } 281 282 /* mountpoint must be a path */ 283 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 284 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 285 /* 286 * Search mmttab for mountpoint 287 */ 288 289 if (search_mnttab == B_TRUE && 290 get_legacy_mountpoint(path, mountpoint, 291 sizeof (mountpoint)) == 0) { 292 dataset = mountpoint; 293 break; 294 } 295 continue; 296 } 297 298 /* canmount must be set */ 299 canmount[0] = '\0'; 300 if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 301 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 302 strcmp(canmount, "off") == 0) 303 continue; 304 305 /* 306 * have a mountable handle but want to skip those marked none 307 * and legacy 308 */ 309 if (strcmp(mountpoint, path) == 0) { 310 dataset = (char *)zfs_get_name(zlist[i]); 311 break; 312 } 313 314 } 315 316 if (dataset != NULL) 317 dataset = strdup(dataset); 318 319 return (dataset); 320 } 321 322 /* 323 * get_zfs_property(dataset, property) 324 * 325 * Get the file system property specified from the ZFS dataset. 326 */ 327 328 static char * 329 get_zfs_property(char *dataset, zfs_prop_t property) 330 { 331 zfs_handle_t *handle = NULL; 332 char shareopts[ZFS_MAXPROPLEN]; 333 libzfs_handle_t *libhandle; 334 335 libhandle = libzfs_init(); 336 if (libhandle != NULL) { 337 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 338 if (handle != NULL) { 339 if (zfs_prop_get(handle, property, shareopts, 340 sizeof (shareopts), NULL, NULL, 0, 341 B_FALSE) == 0) { 342 zfs_close(handle); 343 libzfs_fini(libhandle); 344 return (strdup(shareopts)); 345 } 346 zfs_close(handle); 347 } 348 libzfs_fini(libhandle); 349 } 350 return (NULL); 351 } 352 353 /* 354 * sa_zfs_is_shared(handle, path) 355 * 356 * Check to see if the ZFS path provided has the sharenfs option set 357 * or not. 358 */ 359 360 int 361 sa_zfs_is_shared(sa_handle_t sahandle, char *path) 362 { 363 int ret = 0; 364 char *dataset; 365 zfs_handle_t *handle = NULL; 366 char shareopts[ZFS_MAXPROPLEN]; 367 libzfs_handle_t *libhandle; 368 369 dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 370 if (dataset != NULL) { 371 libhandle = libzfs_init(); 372 if (libhandle != NULL) { 373 handle = zfs_open(libhandle, dataset, 374 ZFS_TYPE_FILESYSTEM); 375 if (handle != NULL) { 376 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 377 shareopts, sizeof (shareopts), NULL, NULL, 378 0, B_FALSE) == 0 && 379 strcmp(shareopts, "off") != 0) { 380 ret = 1; /* it is shared */ 381 } 382 zfs_close(handle); 383 } 384 libzfs_fini(libhandle); 385 } 386 free(dataset); 387 } 388 return (ret); 389 } 390 391 /* 392 * find_or_create_group(handle, groupname, proto, *err) 393 * 394 * While walking the ZFS tree, we need to add shares to a defined 395 * group. If the group doesn't exist, create it first, making sure it 396 * is marked as a ZFS group. 397 * 398 * Note that all ZFS shares are in a subgroup of the top level group 399 * called "zfs". 400 */ 401 402 static sa_group_t 403 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 404 { 405 sa_group_t group; 406 sa_optionset_t optionset; 407 int ret = SA_OK; 408 409 /* 410 * we check to see if the "zfs" group exists. Since this 411 * should be the top level group, we don't want the 412 * parent. This is to make sure the zfs group has been created 413 * and to created if it hasn't been. 414 */ 415 group = sa_get_group(handle, groupname); 416 if (group == NULL) { 417 group = sa_create_group(handle, groupname, &ret); 418 419 /* make sure this is flagged as a ZFS group */ 420 if (group != NULL) 421 ret = sa_set_group_attr(group, "zfs", "true"); 422 } 423 if (group != NULL) { 424 if (proto != NULL) { 425 optionset = sa_get_optionset(group, proto); 426 if (optionset == NULL) 427 optionset = sa_create_optionset(group, proto); 428 } 429 } 430 if (err != NULL) 431 *err = ret; 432 return (group); 433 } 434 435 /* 436 * find_or_create_zfs_subgroup(groupname, optstring, *err) 437 * 438 * ZFS shares will be in a subgroup of the "zfs" master group. This 439 * function looks to see if the groupname exists and returns it if it 440 * does or else creates a new one with the specified name and returns 441 * that. The "zfs" group will exist before we get here, but we make 442 * sure just in case. 443 * 444 * err must be a valid pointer. 445 */ 446 447 static sa_group_t 448 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 449 char *optstring, int *err) 450 { 451 sa_group_t group = NULL; 452 sa_group_t zfs; 453 char *name; 454 char *options; 455 456 /* start with the top-level "zfs" group */ 457 zfs = sa_get_group(handle, "zfs"); 458 *err = SA_OK; 459 if (zfs != NULL) { 460 for (group = sa_get_sub_group(zfs); group != NULL; 461 group = sa_get_next_group(group)) { 462 name = sa_get_group_attr(group, "name"); 463 if (name != NULL && strcmp(name, groupname) == 0) { 464 /* have the group so break out of here */ 465 sa_free_attr_string(name); 466 break; 467 } 468 if (name != NULL) 469 sa_free_attr_string(name); 470 } 471 472 if (group == NULL) { 473 /* 474 * Need to create the sub-group since it doesn't exist 475 */ 476 group = _sa_create_zfs_group(zfs, groupname); 477 if (group == NULL) { 478 *err = SA_NO_MEMORY; 479 return (NULL); 480 } 481 set_node_attr(group, "zfs", "true"); 482 } 483 if (strcmp(optstring, "on") == 0) 484 optstring = "rw"; 485 options = strdup(optstring); 486 if (options != NULL) { 487 *err = sa_parse_legacy_options(group, options, 488 proto); 489 /* If no optionset, add one. */ 490 if (sa_get_optionset(group, proto) == NULL) 491 (void) sa_create_optionset(group, proto); 492 free(options); 493 } else { 494 *err = SA_NO_MEMORY; 495 } 496 } 497 return (group); 498 } 499 500 /* 501 * zfs_construct_resource(share, name, base, dataset) 502 * 503 * Add a resource to the share using name as a template. If name == 504 * NULL, then construct a name based on the dataset value. 505 * name. 506 */ 507 static void 508 zfs_construct_resource(sa_share_t share, char *dataset) 509 { 510 char buff[SA_MAX_RESOURCE_NAME + 1]; 511 int ret = SA_OK; 512 513 (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset); 514 sa_fix_resource_name(buff); 515 (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret); 516 } 517 518 /* 519 * zfs_inherited(handle, source, sourcestr) 520 * 521 * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares 522 * for readability. 523 */ 524 static int 525 zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr, 526 char *shareopts, char *mountpoint, char *proto, char *dataset) 527 { 528 int doshopt = 0; 529 int err = SA_OK; 530 sa_group_t group; 531 sa_resource_t resource; 532 uint64_t features; 533 534 /* 535 * Need to find the "real" parent sub-group. It may not be 536 * mounted, but it was identified in the "sourcestr" 537 * variable. The real parent not mounted can occur if 538 * "canmount=off and sharenfs=on". 539 */ 540 group = find_or_create_zfs_subgroup(handle, sourcestr, proto, 541 shareopts, &doshopt); 542 if (group != NULL) { 543 /* 544 * We may need the first share for resource 545 * prototype. We only care about it if it has a 546 * resource that sets a prefix value. 547 */ 548 if (share == NULL) 549 share = _sa_add_share(group, mountpoint, 550 SA_SHARE_TRANSIENT, &err, 551 (uint64_t)SA_FEATURE_NONE); 552 /* 553 * some options may only be on shares. If the opt 554 * string contains one of those, we put it just on the 555 * share. 556 */ 557 if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) { 558 char *options; 559 options = strdup(shareopts); 560 if (options != NULL) { 561 set_node_attr(share, "dataset", dataset); 562 err = sa_parse_legacy_options(share, options, 563 proto); 564 set_node_attr(share, "dataset", NULL); 565 free(options); 566 } 567 if (sa_get_optionset(group, proto) == NULL) 568 (void) sa_create_optionset(group, proto); 569 } 570 features = sa_proto_get_featureset(proto); 571 if (share != NULL && features & SA_FEATURE_RESOURCE) { 572 /* 573 * We have a share and the protocol requires 574 * that at least one resource exist (probably 575 * SMB). We need to make sure that there is at 576 * least one. 577 */ 578 resource = sa_get_share_resource(share, NULL); 579 if (resource == NULL) { 580 zfs_construct_resource(share, dataset); 581 } 582 } 583 } else { 584 err = SA_NO_MEMORY; 585 } 586 return (err); 587 } 588 589 /* 590 * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset, 591 * grouperr) 592 * 593 * handle case where this is the top of a sub-group in ZFS. Pulled out 594 * of sa_get_zfs_shares for readability. We need the grouperr from the 595 * creation of the subgroup to know whether to add the public 596 * property, etc. to the specific share. 597 */ 598 static int 599 zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 600 char *shareopts, char *proto, char *dataset, int grouperr) 601 { 602 int err = SA_OK; 603 sa_resource_t resource; 604 uint64_t features; 605 606 set_node_attr(group, "zfs", "true"); 607 if (share == NULL) 608 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 609 &err, (uint64_t)SA_FEATURE_NONE); 610 611 if (err != SA_OK) 612 return (err); 613 614 if (strcmp(shareopts, "on") == 0) 615 shareopts = ""; 616 if (shareopts != NULL) { 617 char *options; 618 if (grouperr == SA_PROP_SHARE_ONLY) { 619 /* 620 * Some properties may only be on shares, but 621 * due to the ZFS sub-groups being artificial, 622 * we sometimes get this and have to deal with 623 * it. We do it by attempting to put it on the 624 * share. 625 */ 626 options = strdup(shareopts); 627 if (options != NULL) { 628 err = sa_parse_legacy_options(share, 629 options, proto); 630 free(options); 631 } 632 } 633 /* Unmark the share's changed state */ 634 set_node_attr(share, "changed", NULL); 635 } 636 features = sa_proto_get_featureset(proto); 637 if (share != NULL && features & SA_FEATURE_RESOURCE) { 638 /* 639 * We have a share and the protocol requires that at 640 * least one resource exist (probably SMB). We need to 641 * make sure that there is at least one. 642 */ 643 resource = sa_get_share_resource(share, NULL); 644 if (resource == NULL) { 645 zfs_construct_resource(share, dataset); 646 } 647 } 648 return (err); 649 } 650 651 /* 652 * zfs_grp_error(err) 653 * 654 * Print group create error, but only once. If err is 0 do the 655 * print else don't. 656 */ 657 658 static void 659 zfs_grp_error(int err) 660 { 661 if (err == 0) { 662 /* only print error once */ 663 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 664 "Cannot create ZFS subgroup during initialization:" 665 " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 666 } 667 } 668 669 /* 670 * zfs_process_share(handle, share, mountpoint, proto, source, 671 * shareopts, sourcestr) 672 * 673 * Creates the subgroup, if necessary and adds shares, resources 674 * and properties. 675 */ 676 int 677 sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 678 char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 679 char *sourcestr, char *dataset) 680 { 681 int err = SA_OK; 682 683 if (source & ZPROP_SRC_INHERITED) { 684 err = zfs_inherited(handle, share, sourcestr, shareopts, 685 mountpoint, proto, dataset); 686 } else { 687 group = find_or_create_zfs_subgroup(handle, dataset, proto, 688 shareopts, &err); 689 if (group == NULL) { 690 static boolean_t reported_error = B_FALSE; 691 /* 692 * There is a problem, but we can't do 693 * anything about it at this point so we issue 694 * a warning and move on. 695 */ 696 zfs_grp_error(reported_error); 697 reported_error = B_TRUE; 698 } 699 set_node_attr(group, "zfs", "true"); 700 /* 701 * Add share with local opts via zfs_notinherited. 702 */ 703 err = zfs_notinherited(group, share, mountpoint, shareopts, 704 proto, dataset, err); 705 } 706 return (err); 707 } 708 709 /* 710 * sa_get_zfs_shares(handle, groupname) 711 * 712 * Walk the mnttab for all zfs mounts and determine which are 713 * shared. Find or create the appropriate group/sub-group to contain 714 * the shares. 715 * 716 * All shares are in a sub-group that will hold the properties. This 717 * allows representing the inherited property model. 718 * 719 * One area of complication is if "sharenfs" is set at one level of 720 * the directory tree and "sharesmb" is set at a different level, the 721 * a sub-group must be formed at the lower level for both 722 * protocols. That is the nature of the problem in CR 6667349. 723 */ 724 725 int 726 sa_get_zfs_shares(sa_handle_t handle, char *groupname) 727 { 728 sa_group_t zfsgroup; 729 boolean_t nfs; 730 boolean_t nfs_inherited; 731 boolean_t smb; 732 boolean_t smb_inherited; 733 zfs_handle_t **zlist; 734 char nfsshareopts[ZFS_MAXPROPLEN]; 735 char smbshareopts[ZFS_MAXPROPLEN]; 736 sa_share_t share; 737 zprop_source_t source; 738 char nfssourcestr[ZFS_MAXPROPLEN]; 739 char smbsourcestr[ZFS_MAXPROPLEN]; 740 char mountpoint[ZFS_MAXPROPLEN]; 741 size_t count = 0, i; 742 libzfs_handle_t *zfs_libhandle; 743 int err = SA_OK; 744 745 /* 746 * If we can't access libzfs, don't bother doing anything. 747 */ 748 zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 749 if (zfs_libhandle == NULL) 750 return (SA_SYSTEM_ERR); 751 752 zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 753 /* Not an error, this could be a legacy condition */ 754 if (zfsgroup == NULL) 755 return (SA_OK); 756 757 /* 758 * need to walk the mounted ZFS pools and datasets to 759 * find shares that are possible. 760 */ 761 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 762 qsort(zlist, count, sizeof (void *), mountpoint_compare); 763 764 for (i = 0; i < count; i++) { 765 char *dataset; 766 767 source = ZPROP_SRC_ALL; 768 /* If no mountpoint, skip. */ 769 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 770 mountpoint, sizeof (mountpoint), NULL, NULL, 0, 771 B_FALSE) != 0) 772 continue; 773 774 /* 775 * zfs_get_name value must not be freed. It is just a 776 * pointer to a value in the handle. 777 */ 778 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 779 continue; 780 781 /* 782 * only deal with "mounted" file systems since 783 * unmounted file systems can't actually be shared. 784 */ 785 786 if (!zfs_is_mounted(zlist[i], NULL)) 787 continue; 788 789 nfs = nfs_inherited = B_FALSE; 790 791 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, nfsshareopts, 792 sizeof (nfsshareopts), &source, nfssourcestr, 793 ZFS_MAXPROPLEN, B_FALSE) == 0 && 794 strcmp(nfsshareopts, "off") != 0) { 795 if (source & ZPROP_SRC_INHERITED) 796 nfs_inherited = B_TRUE; 797 else 798 nfs = B_TRUE; 799 } 800 801 smb = smb_inherited = B_FALSE; 802 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, smbshareopts, 803 sizeof (smbshareopts), &source, smbsourcestr, 804 ZFS_MAXPROPLEN, B_FALSE) == 0 && 805 strcmp(smbshareopts, "off") != 0) { 806 if (source & ZPROP_SRC_INHERITED) 807 smb_inherited = B_TRUE; 808 else 809 smb = B_TRUE; 810 } 811 812 /* 813 * If the mountpoint is already shared, it must be a 814 * non-ZFS share. We want to remove the share from its 815 * parent group and reshare it under ZFS. 816 */ 817 share = sa_find_share(handle, mountpoint); 818 if (share != NULL && 819 (nfs || smb || nfs_inherited || smb_inherited)) { 820 err = sa_remove_share(share); 821 share = NULL; 822 } 823 824 /* 825 * At this point, we have the information needed to 826 * determine what to do with the share. 827 * 828 * If smb or nfs is set, we have a new sub-group. 829 * If smb_inherit and/or nfs_inherit is set, then 830 * place on an existing sub-group. If both are set, 831 * the existing sub-group is the closest up the tree. 832 */ 833 if (nfs || smb) { 834 /* 835 * Non-inherited is the straightforward 836 * case. sa_zfs_process_share handles it 837 * directly. Make sure that if the "other" 838 * protocol is inherited, that we treat it as 839 * non-inherited as well. 840 */ 841 if (nfs || nfs_inherited) { 842 err = sa_zfs_process_share(handle, zfsgroup, 843 share, mountpoint, "nfs", 844 0, nfsshareopts, 845 nfssourcestr, dataset); 846 share = sa_find_share(handle, mountpoint); 847 } 848 if (smb || smb_inherited) { 849 err = sa_zfs_process_share(handle, zfsgroup, 850 share, mountpoint, "smb", 851 0, smbshareopts, 852 smbsourcestr, dataset); 853 } 854 } else if (nfs_inherited || smb_inherited) { 855 char *grpdataset; 856 /* 857 * If we only have inherited groups, it is 858 * important to find the closer of the two if 859 * the protocols are set at different 860 * levels. The closest sub-group is the one we 861 * want to work with. 862 */ 863 if (nfs_inherited && smb_inherited) { 864 if (strcmp(nfssourcestr, smbsourcestr) <= 0) 865 grpdataset = nfssourcestr; 866 else 867 grpdataset = smbsourcestr; 868 } else if (nfs_inherited) { 869 grpdataset = nfssourcestr; 870 } else if (smb_inherited) { 871 grpdataset = smbsourcestr; 872 } 873 if (nfs_inherited) { 874 err = sa_zfs_process_share(handle, zfsgroup, 875 share, mountpoint, "nfs", 876 ZPROP_SRC_INHERITED, nfsshareopts, 877 grpdataset, dataset); 878 share = sa_find_share(handle, mountpoint); 879 } 880 if (smb_inherited) { 881 err = sa_zfs_process_share(handle, zfsgroup, 882 share, mountpoint, "smb", 883 ZPROP_SRC_INHERITED, smbshareopts, 884 grpdataset, dataset); 885 } 886 } 887 } 888 /* 889 * Don't need to free the "zlist" variable since it is only a 890 * pointer to a cached value that will be freed when 891 * sa_fini() is called. 892 */ 893 return (err); 894 } 895 896 #define COMMAND "/usr/sbin/zfs" 897 898 /* 899 * sa_zfs_set_sharenfs(group, path, on) 900 * 901 * Update the "sharenfs" property on the path. If on is true, then set 902 * to the properties on the group or "on" if no properties are 903 * defined. Set to "off" if on is false. 904 */ 905 906 int 907 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 908 { 909 int ret = SA_NOT_IMPLEMENTED; 910 char *command; 911 912 command = malloc(ZFS_MAXPROPLEN * 2); 913 if (command != NULL) { 914 char *opts = NULL; 915 char *dataset = NULL; 916 FILE *pfile; 917 sa_handle_impl_t impl_handle; 918 /* for now, NFS is always available for "zfs" */ 919 if (on) { 920 opts = sa_proto_legacy_format("nfs", group, 1); 921 if (opts != NULL && strlen(opts) == 0) { 922 free(opts); 923 opts = strdup("on"); 924 } 925 } 926 927 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 928 assert(impl_handle != NULL); 929 if (impl_handle != NULL) 930 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 931 else 932 ret = SA_SYSTEM_ERR; 933 934 if (dataset != NULL) { 935 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 936 "%s set sharenfs=\"%s\" %s", COMMAND, 937 opts != NULL ? opts : "off", dataset); 938 pfile = popen(command, "r"); 939 if (pfile != NULL) { 940 ret = pclose(pfile); 941 if (ret != 0) 942 ret = SA_SYSTEM_ERR; 943 } 944 } 945 if (opts != NULL) 946 free(opts); 947 if (dataset != NULL) 948 free(dataset); 949 free(command); 950 } 951 return (ret); 952 } 953 954 /* 955 * add_resources(share, opt) 956 * 957 * Add resource properties to those in "opt". Resources are prefixed 958 * with name=resourcename. 959 */ 960 static char * 961 add_resources(sa_share_t share, char *opt) 962 { 963 char *newopt = NULL; 964 char *propstr; 965 sa_resource_t resource; 966 967 newopt = strdup(opt); 968 if (newopt == NULL) 969 return (newopt); 970 971 for (resource = sa_get_share_resource(share, NULL); 972 resource != NULL; 973 resource = sa_get_next_resource(resource)) { 974 char *name; 975 size_t size; 976 977 name = sa_get_resource_attr(resource, "name"); 978 if (name == NULL) { 979 free(newopt); 980 return (NULL); 981 } 982 size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 983 newopt = calloc(1, size); 984 if (newopt != NULL) 985 (void) snprintf(newopt, size, "%s,name=%s", opt, name); 986 free(opt); 987 opt = newopt; 988 propstr = sa_proto_legacy_format("smb", resource, 0); 989 if (propstr == NULL) { 990 free(opt); 991 return (NULL); 992 } 993 size = strlen(propstr) + strlen(opt) + 2; 994 newopt = calloc(1, size); 995 if (newopt != NULL) 996 (void) snprintf(newopt, size, "%s,%s", opt, propstr); 997 free(opt); 998 opt = newopt; 999 } 1000 return (opt); 1001 } 1002 1003 /* 1004 * sa_zfs_set_sharesmb(group, path, on) 1005 * 1006 * Update the "sharesmb" property on the path. If on is true, then set 1007 * to the properties on the group or "on" if no properties are 1008 * defined. Set to "off" if on is false. 1009 */ 1010 1011 int 1012 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 1013 { 1014 int ret = SA_NOT_IMPLEMENTED; 1015 char *command; 1016 sa_share_t share; 1017 1018 /* In case SMB not enabled */ 1019 if (sa_get_optionset(group, "smb") == NULL) 1020 return (SA_NOT_SUPPORTED); 1021 1022 command = malloc(ZFS_MAXPROPLEN * 2); 1023 if (command != NULL) { 1024 char *opts = NULL; 1025 char *dataset = NULL; 1026 FILE *pfile; 1027 sa_handle_impl_t impl_handle; 1028 1029 if (on) { 1030 char *newopt; 1031 1032 share = sa_get_share(group, NULL); 1033 opts = sa_proto_legacy_format("smb", share, 1); 1034 if (opts != NULL && strlen(opts) == 0) { 1035 free(opts); 1036 opts = strdup("on"); 1037 } 1038 newopt = add_resources(opts, share); 1039 free(opts); 1040 opts = newopt; 1041 } 1042 1043 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1044 assert(impl_handle != NULL); 1045 if (impl_handle != NULL) 1046 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1047 else 1048 ret = SA_SYSTEM_ERR; 1049 1050 if (dataset != NULL) { 1051 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1052 "echo %s set sharesmb=\"%s\" %s", COMMAND, 1053 opts != NULL ? opts : "off", dataset); 1054 pfile = popen(command, "r"); 1055 if (pfile != NULL) { 1056 ret = pclose(pfile); 1057 if (ret != 0) 1058 ret = SA_SYSTEM_ERR; 1059 } 1060 } 1061 if (opts != NULL) 1062 free(opts); 1063 if (dataset != NULL) 1064 free(dataset); 1065 free(command); 1066 } 1067 return (ret); 1068 } 1069 1070 /* 1071 * sa_zfs_update(group) 1072 * 1073 * call back to ZFS to update the share if necessary. 1074 * Don't do it if it isn't a real change. 1075 */ 1076 int 1077 sa_zfs_update(sa_group_t group) 1078 { 1079 sa_optionset_t protopt; 1080 sa_group_t parent; 1081 char *command; 1082 char *optstring; 1083 int ret = SA_OK; 1084 int doupdate = 0; 1085 FILE *pfile; 1086 1087 if (sa_is_share(group)) 1088 parent = sa_get_parent_group(group); 1089 else 1090 parent = group; 1091 1092 if (parent != NULL) { 1093 command = malloc(ZFS_MAXPROPLEN * 2); 1094 if (command == NULL) 1095 return (SA_NO_MEMORY); 1096 1097 *command = '\0'; 1098 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 1099 protopt = sa_get_next_optionset(protopt)) { 1100 1101 char *proto = sa_get_optionset_attr(protopt, "type"); 1102 char *path; 1103 char *dataset = NULL; 1104 char *zfsopts = NULL; 1105 1106 if (sa_is_share(group)) { 1107 path = sa_get_share_attr((sa_share_t)group, 1108 "path"); 1109 if (path != NULL) { 1110 sa_handle_impl_t impl_handle; 1111 1112 impl_handle = sa_find_group_handle( 1113 group); 1114 if (impl_handle != NULL) 1115 dataset = get_zfs_dataset( 1116 impl_handle, path, B_FALSE); 1117 else 1118 ret = SA_SYSTEM_ERR; 1119 1120 sa_free_attr_string(path); 1121 } 1122 } else { 1123 dataset = sa_get_group_attr(group, "name"); 1124 } 1125 /* update only when there is an optstring found */ 1126 doupdate = 0; 1127 if (proto != NULL && dataset != NULL) { 1128 optstring = sa_proto_legacy_format(proto, 1129 group, 1); 1130 zfsopts = get_zfs_property(dataset, 1131 ZFS_PROP_SHARENFS); 1132 1133 if (optstring != NULL && zfsopts != NULL) { 1134 if (strcmp(optstring, zfsopts) != 0) 1135 doupdate++; 1136 } 1137 if (doupdate) { 1138 if (optstring != NULL && 1139 strlen(optstring) > 0) { 1140 (void) snprintf(command, 1141 ZFS_MAXPROPLEN * 2, 1142 "%s set share%s=%s %s", 1143 COMMAND, proto, 1144 optstring, dataset); 1145 } else { 1146 (void) snprintf(command, 1147 ZFS_MAXPROPLEN * 2, 1148 "%s set share%s=on %s", 1149 COMMAND, proto, 1150 dataset); 1151 } 1152 pfile = popen(command, "r"); 1153 if (pfile != NULL) 1154 ret = pclose(pfile); 1155 switch (ret) { 1156 default: 1157 case 1: 1158 ret = SA_SYSTEM_ERR; 1159 break; 1160 case 2: 1161 ret = SA_SYNTAX_ERR; 1162 break; 1163 case 0: 1164 break; 1165 } 1166 } 1167 if (optstring != NULL) 1168 free(optstring); 1169 if (zfsopts != NULL) 1170 free(zfsopts); 1171 } 1172 if (proto != NULL) 1173 sa_free_attr_string(proto); 1174 if (dataset != NULL) 1175 free(dataset); 1176 } 1177 free(command); 1178 } 1179 return (ret); 1180 } 1181 1182 /* 1183 * sa_group_is_zfs(group) 1184 * 1185 * Given the group, determine if the zfs attribute is set. 1186 */ 1187 1188 int 1189 sa_group_is_zfs(sa_group_t group) 1190 { 1191 char *zfs; 1192 int ret = 0; 1193 1194 zfs = sa_get_group_attr(group, "zfs"); 1195 if (zfs != NULL) { 1196 ret = 1; 1197 sa_free_attr_string(zfs); 1198 } 1199 return (ret); 1200 } 1201 1202 /* 1203 * sa_path_is_zfs(path) 1204 * 1205 * Check to see if the file system path represents is of type "zfs". 1206 */ 1207 1208 int 1209 sa_path_is_zfs(char *path) 1210 { 1211 char *fstype; 1212 int ret = 0; 1213 1214 fstype = sa_fstype(path); 1215 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 1216 ret = 1; 1217 if (fstype != NULL) 1218 sa_free_fstype(fstype); 1219 return (ret); 1220 } 1221 1222 int 1223 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1224 { 1225 char *path; 1226 1227 /* Make sure path is valid */ 1228 1229 path = sa_get_share_attr(share, "path"); 1230 if (path != NULL) { 1231 (void) memset(sh, 0, sizeof (sh)); 1232 (void) sa_fillshare(share, proto, sh); 1233 sa_free_attr_string(path); 1234 return (0); 1235 } else 1236 return (1); 1237 } 1238 1239 #define SMAX(i, j) \ 1240 if ((j) > (i)) { \ 1241 (i) = (j); \ 1242 } 1243 1244 int 1245 sa_share_zfs(sa_share_t share, char *path, share_t *sh, 1246 void *exportdata, zfs_share_op_t operation) 1247 { 1248 libzfs_handle_t *libhandle; 1249 sa_group_t group; 1250 sa_handle_t sahandle; 1251 char *dataset; 1252 int err = EINVAL; 1253 int i, j; 1254 char newpath[MAXPATHLEN]; 1255 char *pathp; 1256 1257 /* 1258 * First find the dataset name 1259 */ 1260 if ((group = sa_get_parent_group(share)) == NULL) { 1261 return (SA_SYSTEM_ERR); 1262 } 1263 if ((sahandle = sa_find_group_handle(group)) == NULL) { 1264 return (SA_SYSTEM_ERR); 1265 } 1266 1267 /* 1268 * If get_zfs_dataset fails, see if it is a subdirectory 1269 */ 1270 1271 pathp = path; 1272 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 1273 char *p; 1274 1275 if (pathp == path) { 1276 (void) strlcpy(newpath, path, sizeof (newpath)); 1277 pathp = newpath; 1278 } 1279 1280 /* 1281 * Make sure only one leading '/' This condition came 1282 * about when using HAStoragePlus which insisted on 1283 * putting an extra leading '/' in the ZFS path 1284 * name. The problem is fixed in other areas, but this 1285 * will catch any other ways that a double slash might 1286 * get introduced. 1287 */ 1288 while (*pathp == '/' && *(pathp + 1) == '/') 1289 pathp++; 1290 1291 /* 1292 * chop off part of path, but if we are at root then 1293 * make sure path is a / 1294 */ 1295 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1296 if (pathp == p) { 1297 *(p + 1) = '\0'; /* skip over /, root case */ 1298 } else { 1299 *p = '\0'; 1300 } 1301 } else { 1302 return (SA_SYSTEM_ERR); 1303 } 1304 } 1305 1306 libhandle = libzfs_init(); 1307 if (libhandle != NULL) { 1308 1309 i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1310 sh->sh_size = i; 1311 1312 j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1313 sh->sh_size += j; 1314 SMAX(i, j); 1315 1316 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1317 sh->sh_size += j; 1318 SMAX(i, j); 1319 1320 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1321 sh->sh_size += j; 1322 SMAX(i, j); 1323 1324 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1325 sh->sh_size += j; 1326 SMAX(i, j); 1327 err = zfs_deleg_share_nfs(libhandle, dataset, path, 1328 exportdata, sh, i, operation); 1329 if (err == SA_OK) 1330 sa_update_sharetab_ts(sahandle); 1331 libzfs_fini(libhandle); 1332 } 1333 free(dataset); 1334 return (err); 1335 } 1336 1337 /* 1338 * sa_get_zfs_handle(handle) 1339 * 1340 * Given an sa_handle_t, return the libzfs_handle_t *. This is only 1341 * used internally by libzfs. Needed in order to avoid including 1342 * libshare_impl.h in libzfs. 1343 */ 1344 1345 libzfs_handle_t * 1346 sa_get_zfs_handle(sa_handle_t handle) 1347 { 1348 sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 1349 1350 return (implhandle->zfs_libhandle); 1351 } 1352