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