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