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