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 sa_free_attr_string(name); 994 free(opt); 995 opt = newopt; 996 propstr = sa_proto_legacy_format("smb", resource, 0); 997 if (propstr == NULL) { 998 free(opt); 999 return (NULL); 1000 } 1001 size = strlen(propstr) + strlen(opt) + 2; 1002 newopt = calloc(1, size); 1003 if (newopt != NULL) 1004 (void) snprintf(newopt, size, "%s,%s", opt, propstr); 1005 free(opt); 1006 opt = newopt; 1007 } 1008 return (opt); 1009 } 1010 1011 /* 1012 * sa_zfs_set_sharesmb(group, path, on) 1013 * 1014 * Update the "sharesmb" property on the path. If on is true, then set 1015 * to the properties on the group or "on" if no properties are 1016 * defined. Set to "off" if on is false. 1017 */ 1018 1019 int 1020 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 1021 { 1022 int ret = SA_NOT_IMPLEMENTED; 1023 char *command; 1024 sa_share_t share; 1025 1026 /* In case SMB not enabled */ 1027 if (sa_get_optionset(group, "smb") == NULL) 1028 return (SA_NOT_SUPPORTED); 1029 1030 command = malloc(ZFS_MAXPROPLEN * 2); 1031 if (command != NULL) { 1032 char *opts = NULL; 1033 char *dataset = NULL; 1034 FILE *pfile; 1035 sa_handle_impl_t impl_handle; 1036 1037 if (on) { 1038 char *newopt; 1039 1040 share = sa_get_share(group, NULL); 1041 opts = sa_proto_legacy_format("smb", share, 1); 1042 if (opts != NULL && strlen(opts) == 0) { 1043 free(opts); 1044 opts = strdup("on"); 1045 } 1046 newopt = add_resources(opts, share); 1047 free(opts); 1048 opts = newopt; 1049 } 1050 1051 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 1052 assert(impl_handle != NULL); 1053 if (impl_handle != NULL) 1054 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1055 else 1056 ret = SA_SYSTEM_ERR; 1057 1058 if (dataset != NULL) { 1059 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1060 "echo %s set sharesmb=\"%s\" %s", COMMAND, 1061 opts != NULL ? opts : "off", dataset); 1062 pfile = popen(command, "r"); 1063 if (pfile != NULL) { 1064 ret = pclose(pfile); 1065 if (ret != 0) 1066 ret = SA_SYSTEM_ERR; 1067 } 1068 } 1069 if (opts != NULL) 1070 free(opts); 1071 if (dataset != NULL) 1072 free(dataset); 1073 free(command); 1074 } 1075 return (ret); 1076 } 1077 1078 /* 1079 * sa_zfs_update(group) 1080 * 1081 * call back to ZFS to update the share if necessary. 1082 * Don't do it if it isn't a real change. 1083 */ 1084 int 1085 sa_zfs_update(sa_group_t group) 1086 { 1087 sa_optionset_t protopt; 1088 sa_group_t parent; 1089 char *command; 1090 char *optstring; 1091 int ret = SA_OK; 1092 int doupdate = 0; 1093 FILE *pfile; 1094 1095 if (sa_is_share(group)) 1096 parent = sa_get_parent_group(group); 1097 else 1098 parent = group; 1099 1100 if (parent != NULL) { 1101 command = malloc(ZFS_MAXPROPLEN * 2); 1102 if (command == NULL) 1103 return (SA_NO_MEMORY); 1104 1105 *command = '\0'; 1106 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 1107 protopt = sa_get_next_optionset(protopt)) { 1108 1109 char *proto = sa_get_optionset_attr(protopt, "type"); 1110 char *path; 1111 char *dataset = NULL; 1112 char *zfsopts = NULL; 1113 1114 if (sa_is_share(group)) { 1115 path = sa_get_share_attr((sa_share_t)group, 1116 "path"); 1117 if (path != NULL) { 1118 sa_handle_impl_t impl_handle; 1119 1120 impl_handle = sa_find_group_handle( 1121 group); 1122 if (impl_handle != NULL) 1123 dataset = get_zfs_dataset( 1124 impl_handle, path, B_FALSE); 1125 else 1126 ret = SA_SYSTEM_ERR; 1127 1128 sa_free_attr_string(path); 1129 } 1130 } else { 1131 dataset = sa_get_group_attr(group, "name"); 1132 } 1133 /* update only when there is an optstring found */ 1134 doupdate = 0; 1135 if (proto != NULL && dataset != NULL) { 1136 optstring = sa_proto_legacy_format(proto, 1137 group, 1); 1138 zfsopts = get_zfs_property(dataset, 1139 ZFS_PROP_SHARENFS); 1140 1141 if (optstring != NULL && zfsopts != NULL) { 1142 if (strcmp(optstring, zfsopts) != 0) 1143 doupdate++; 1144 } 1145 if (doupdate) { 1146 if (optstring != NULL && 1147 strlen(optstring) > 0) { 1148 (void) snprintf(command, 1149 ZFS_MAXPROPLEN * 2, 1150 "%s set share%s=%s %s", 1151 COMMAND, proto, 1152 optstring, dataset); 1153 } else { 1154 (void) snprintf(command, 1155 ZFS_MAXPROPLEN * 2, 1156 "%s set share%s=on %s", 1157 COMMAND, proto, 1158 dataset); 1159 } 1160 pfile = popen(command, "r"); 1161 if (pfile != NULL) 1162 ret = pclose(pfile); 1163 switch (ret) { 1164 default: 1165 case 1: 1166 ret = SA_SYSTEM_ERR; 1167 break; 1168 case 2: 1169 ret = SA_SYNTAX_ERR; 1170 break; 1171 case 0: 1172 break; 1173 } 1174 } 1175 if (optstring != NULL) 1176 free(optstring); 1177 if (zfsopts != NULL) 1178 free(zfsopts); 1179 } 1180 if (proto != NULL) 1181 sa_free_attr_string(proto); 1182 if (dataset != NULL) 1183 free(dataset); 1184 } 1185 free(command); 1186 } 1187 return (ret); 1188 } 1189 1190 /* 1191 * sa_group_is_zfs(group) 1192 * 1193 * Given the group, determine if the zfs attribute is set. 1194 */ 1195 1196 int 1197 sa_group_is_zfs(sa_group_t group) 1198 { 1199 char *zfs; 1200 int ret = 0; 1201 1202 zfs = sa_get_group_attr(group, "zfs"); 1203 if (zfs != NULL) { 1204 ret = 1; 1205 sa_free_attr_string(zfs); 1206 } 1207 return (ret); 1208 } 1209 1210 /* 1211 * sa_path_is_zfs(path) 1212 * 1213 * Check to see if the file system path represents is of type "zfs". 1214 */ 1215 1216 int 1217 sa_path_is_zfs(char *path) 1218 { 1219 char *fstype; 1220 int ret = 0; 1221 1222 fstype = sa_fstype(path); 1223 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 1224 ret = 1; 1225 if (fstype != NULL) 1226 sa_free_fstype(fstype); 1227 return (ret); 1228 } 1229 1230 int 1231 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1232 { 1233 char *path; 1234 1235 /* Make sure path is valid */ 1236 1237 path = sa_get_share_attr(share, "path"); 1238 if (path != NULL) { 1239 (void) memset(sh, 0, sizeof (sh)); 1240 (void) sa_fillshare(share, proto, sh); 1241 sa_free_attr_string(path); 1242 return (0); 1243 } else 1244 return (1); 1245 } 1246 1247 #define SMAX(i, j) \ 1248 if ((j) > (i)) { \ 1249 (i) = (j); \ 1250 } 1251 1252 int 1253 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 1254 void *exportdata, zfs_share_op_t operation) 1255 { 1256 libzfs_handle_t *libhandle; 1257 sa_group_t group; 1258 sa_handle_t sahandle; 1259 char *dataset; 1260 int err = EINVAL; 1261 int i, j; 1262 char newpath[MAXPATHLEN]; 1263 char *pathp; 1264 1265 /* 1266 * First find the dataset name 1267 */ 1268 if ((group = sa_get_parent_group(share)) == NULL) { 1269 return (EINVAL); 1270 } 1271 if ((sahandle = sa_find_group_handle(group)) == NULL) { 1272 return (EINVAL); 1273 } 1274 1275 /* 1276 * If get_zfs_dataset fails, see if it is a subdirectory 1277 */ 1278 1279 pathp = path; 1280 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 1281 char *p; 1282 1283 if (pathp == path) { 1284 (void) strlcpy(newpath, path, sizeof (newpath)); 1285 pathp = newpath; 1286 } 1287 1288 /* 1289 * Make sure only one leading '/' This condition came 1290 * about when using HAStoragePlus which insisted on 1291 * putting an extra leading '/' in the ZFS path 1292 * name. The problem is fixed in other areas, but this 1293 * will catch any other ways that a double slash might 1294 * get introduced. 1295 */ 1296 while (*pathp == '/' && *(pathp + 1) == '/') 1297 pathp++; 1298 1299 /* 1300 * chop off part of path, but if we are at root then 1301 * make sure path is a / 1302 */ 1303 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1304 if (pathp == p) { 1305 *(p + 1) = '\0'; /* skip over /, root case */ 1306 } else { 1307 *p = '\0'; 1308 } 1309 } else { 1310 return (EINVAL); 1311 } 1312 } 1313 1314 libhandle = libzfs_init(); 1315 if (libhandle != NULL) { 1316 char *resource_name; 1317 1318 i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1319 sh->sh_size = i; 1320 1321 j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1322 sh->sh_size += j; 1323 SMAX(i, j); 1324 1325 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1326 sh->sh_size += j; 1327 SMAX(i, j); 1328 1329 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1330 sh->sh_size += j; 1331 SMAX(i, j); 1332 1333 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1334 sh->sh_size += j; 1335 SMAX(i, j); 1336 1337 resource_name = sa_get_resource_attr(resource, "name"); 1338 1339 err = zfs_deleg_share_nfs(libhandle, dataset, path, 1340 resource_name, exportdata, sh, i, operation); 1341 if (err == SA_OK) 1342 sa_update_sharetab_ts(sahandle); 1343 else 1344 err = errno; 1345 if (resource_name) 1346 sa_free_attr_string(resource_name); 1347 1348 libzfs_fini(libhandle); 1349 } 1350 free(dataset); 1351 return (err); 1352 } 1353 1354 /* 1355 * sa_get_zfs_handle(handle) 1356 * 1357 * Given an sa_handle_t, return the libzfs_handle_t *. This is only 1358 * used internally by libzfs. Needed in order to avoid including 1359 * libshare_impl.h in libzfs. 1360 */ 1361 1362 libzfs_handle_t * 1363 sa_get_zfs_handle(sa_handle_t handle) 1364 { 1365 sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 1366 1367 return (implhandle->zfs_libhandle); 1368 } 1369 1370 /* 1371 * sa_get_zfs_info(libzfs, path, mountpoint, dataset) 1372 * 1373 * Find the ZFS dataset and mountpoint for a given path 1374 */ 1375 int 1376 sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp, 1377 char *datasetp) 1378 { 1379 get_all_cbdata_t cb = { 0 }; 1380 int i; 1381 char mountpoint[ZFS_MAXPROPLEN]; 1382 char dataset[ZFS_MAXPROPLEN]; 1383 char canmount[ZFS_MAXPROPLEN]; 1384 char *dp; 1385 int count; 1386 int ret = 0; 1387 1388 cb.cb_types = ZFS_TYPE_FILESYSTEM; 1389 1390 if (libzfs == NULL) 1391 return (0); 1392 1393 (void) zfs_iter_root(libzfs, get_one_filesystem, &cb); 1394 count = cb.cb_used; 1395 1396 qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare); 1397 for (i = 0; i < count; i++) { 1398 /* must have a mountpoint */ 1399 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT, 1400 mountpoint, sizeof (mountpoint), 1401 NULL, NULL, 0, B_FALSE) != 0) { 1402 /* no mountpoint */ 1403 continue; 1404 } 1405 1406 /* mountpoint must be a path */ 1407 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 1408 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 1409 /* 1410 * Search mmttab for mountpoint 1411 */ 1412 1413 if (get_legacy_mountpoint(path, dataset, 1414 ZFS_MAXPROPLEN, mountpoint, 1415 ZFS_MAXPROPLEN) == 0) { 1416 ret = 1; 1417 break; 1418 } 1419 continue; 1420 } 1421 1422 /* canmount must be set */ 1423 canmount[0] = '\0'; 1424 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount, 1425 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 1426 strcmp(canmount, "off") == 0) 1427 continue; 1428 1429 /* 1430 * have a mountable handle but want to skip those marked none 1431 * and legacy 1432 */ 1433 if (strcmp(mountpoint, path) == 0) { 1434 dp = (char *)zfs_get_name(cb.cb_handles[i]); 1435 if (dp != NULL) { 1436 if (datasetp != NULL) 1437 (void) strcpy(datasetp, dp); 1438 if (mountpointp != NULL) 1439 (void) strcpy(mountpointp, mountpoint); 1440 ret = 1; 1441 } 1442 break; 1443 } 1444 1445 } 1446 1447 return (ret); 1448 } 1449