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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 25 * Copyright (c) 2013 RackTop Systems. 26 */ 27 28 #include <stdio.h> 29 #include <libzfs.h> 30 #include <string.h> 31 #include <strings.h> 32 #include <errno.h> 33 #include <libshare.h> 34 #include "libshare_impl.h" 35 #include <libintl.h> 36 #include <sys/mnttab.h> 37 #include <sys/mntent.h> 38 39 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 40 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 41 extern char *sa_fstype(char *); 42 extern void set_node_attr(void *, char *, char *); 43 extern boolean_t sa_is_share(void *); 44 extern void sa_update_sharetab_ts(sa_handle_t); 45 46 /* 47 * File system specific code for ZFS. The original code was stolen 48 * from the "zfs" command and modified to better suit this library's 49 * usage. 50 */ 51 52 typedef struct get_all_cbdata { 53 zfs_handle_t **cb_handles; 54 size_t cb_alloc; 55 size_t cb_used; 56 uint_t cb_types; 57 } get_all_cbdata_t; 58 59 /* 60 * sa_zfs_init(handle) 61 * 62 * Initialize an access handle into libzfs. The handle needs to stay 63 * around until sa_zfs_fini() in order to maintain the cache of 64 * mounts. 65 */ 66 67 int 68 sa_zfs_init(sa_handle_t handle) 69 { 70 handle->zfs_libhandle = libzfs_init(); 71 if (handle->zfs_libhandle != NULL) { 72 libzfs_print_on_error(handle->zfs_libhandle, B_TRUE); 73 return (B_TRUE); 74 } 75 return (B_FALSE); 76 } 77 78 /* 79 * sa_zfs_fini(handle) 80 * 81 * cleanup data structures and the libzfs handle used for accessing 82 * zfs file share info. 83 */ 84 85 void 86 sa_zfs_fini(sa_handle_t handle) 87 { 88 if (handle->zfs_libhandle != NULL) { 89 if (handle->zfs_list != NULL) { 90 zfs_handle_t **zhp = handle->zfs_list; 91 size_t i; 92 93 /* 94 * Contents of zfs_list need to be freed so we 95 * don't lose ZFS handles. 96 */ 97 for (i = 0; i < handle->zfs_list_count; i++) { 98 zfs_close(zhp[i]); 99 } 100 free(handle->zfs_list); 101 handle->zfs_list = NULL; 102 handle->zfs_list_count = 0; 103 } 104 105 libzfs_fini(handle->zfs_libhandle); 106 handle->zfs_libhandle = NULL; 107 } 108 } 109 110 /* 111 * get_one_filesystem(zfs_handle_t, data) 112 * 113 * an iterator function called while iterating through the ZFS 114 * root. It accumulates into an array of file system handles that can 115 * be used to derive info about those file systems. 116 * 117 * Note that as this function is called, we close all zhp handles that 118 * are not going to be places into the cp_handles list. We don't want 119 * to close the ones we are keeping, but all others would be leaked if 120 * not closed here. 121 */ 122 123 static int 124 get_one_filesystem(zfs_handle_t *zhp, void *data) 125 { 126 get_all_cbdata_t *cbp = data; 127 zfs_type_t type = zfs_get_type(zhp); 128 129 /* 130 * Interate over any nested datasets. 131 */ 132 if (type == ZFS_TYPE_FILESYSTEM && 133 zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 134 zfs_close(zhp); 135 return (1); 136 } 137 138 /* 139 * Skip any datasets whose type does not match. 140 */ 141 if ((type & cbp->cb_types) == 0) { 142 zfs_close(zhp); 143 return (0); 144 } 145 146 if (cbp->cb_alloc == cbp->cb_used) { 147 zfs_handle_t **handles; 148 149 if (cbp->cb_alloc == 0) 150 cbp->cb_alloc = 64; 151 else 152 cbp->cb_alloc *= 2; 153 154 handles = (zfs_handle_t **)calloc(1, 155 cbp->cb_alloc * sizeof (void *)); 156 157 if (handles == NULL) { 158 zfs_close(zhp); 159 return (0); 160 } 161 if (cbp->cb_handles) { 162 bcopy(cbp->cb_handles, handles, 163 cbp->cb_used * sizeof (void *)); 164 free(cbp->cb_handles); 165 } 166 167 cbp->cb_handles = handles; 168 } 169 170 cbp->cb_handles[cbp->cb_used++] = zhp; 171 172 return (0); 173 } 174 175 /* 176 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 177 * 178 * iterate through all ZFS file systems starting at the root. Returns 179 * a count and an array of handle pointers. Allocating is only done 180 * once. The caller does not need to free since it will be done at 181 * sa_zfs_fini() time. 182 */ 183 184 static void 185 get_all_filesystems(sa_handle_t handle, 186 zfs_handle_t ***fslist, size_t *count) 187 { 188 get_all_cbdata_t cb = { 0 }; 189 cb.cb_types = ZFS_TYPE_FILESYSTEM; 190 191 if (handle->zfs_list != NULL) { 192 *fslist = handle->zfs_list; 193 *count = handle->zfs_list_count; 194 return; 195 } 196 197 (void) zfs_iter_root(handle->zfs_libhandle, 198 get_one_filesystem, &cb); 199 200 handle->zfs_list = *fslist = cb.cb_handles; 201 handle->zfs_list_count = *count = cb.cb_used; 202 } 203 204 /* 205 * mountpoint_compare(a, b) 206 * 207 * compares the mountpoint on two zfs file systems handles. 208 * returns values following strcmp() model. 209 */ 210 211 static int 212 mountpoint_compare(const void *a, const void *b) 213 { 214 zfs_handle_t **za = (zfs_handle_t **)a; 215 zfs_handle_t **zb = (zfs_handle_t **)b; 216 char mounta[MAXPATHLEN]; 217 char mountb[MAXPATHLEN]; 218 219 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 220 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 221 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 222 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 223 224 return (strcmp(mounta, mountb)); 225 } 226 227 /* 228 * return legacy mountpoint. Caller provides space for mountpoint and 229 * dataset. 230 */ 231 int 232 get_legacy_mountpoint(char *path, char *dataset, size_t dlen, 233 char *mountpoint, size_t mlen) 234 { 235 FILE *fp; 236 struct mnttab entry; 237 238 if ((fp = fopen(MNTTAB, "r")) == NULL) { 239 return (1); 240 } 241 242 while (getmntent(fp, &entry) == 0) { 243 244 if (entry.mnt_fstype == NULL || 245 strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 246 continue; 247 248 if (strcmp(entry.mnt_mountp, path) == 0) { 249 if (mlen > 0) 250 (void) strlcpy(mountpoint, entry.mnt_mountp, 251 mlen); 252 if (dlen > 0) 253 (void) strlcpy(dataset, entry.mnt_special, 254 dlen); 255 break; 256 } 257 } 258 (void) fclose(fp); 259 return (1); 260 } 261 262 /* 263 * get_zfs_dataset(handle, path) 264 * 265 * get the name of the ZFS dataset the path is equivalent to. The 266 * dataset name is used for get/set of ZFS properties since libzfs 267 * requires a dataset to do a zfs_open(). 268 */ 269 270 static char * 271 get_zfs_dataset(sa_handle_t handle, char *path, 272 boolean_t search_mnttab) 273 { 274 size_t i, count = 0; 275 char *dataset = NULL; 276 zfs_handle_t **zlist; 277 char mountpoint[ZFS_MAXPROPLEN]; 278 char canmount[ZFS_MAXPROPLEN]; 279 280 get_all_filesystems(handle, &zlist, &count); 281 qsort(zlist, count, sizeof (void *), mountpoint_compare); 282 for (i = 0; i < count; i++) { 283 /* must have a mountpoint */ 284 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 285 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 286 /* no mountpoint */ 287 continue; 288 } 289 290 /* mountpoint must be a path */ 291 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 292 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 293 /* 294 * Search mmttab for mountpoint and get dataset. 295 */ 296 297 if (search_mnttab == B_TRUE && 298 get_legacy_mountpoint(path, mountpoint, 299 sizeof (mountpoint), NULL, 0) == 0) { 300 dataset = mountpoint; 301 break; 302 } 303 continue; 304 } 305 306 /* canmount must be set */ 307 canmount[0] = '\0'; 308 if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 309 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 310 strcmp(canmount, "off") == 0) 311 continue; 312 313 /* 314 * have a mountable handle but want to skip those marked none 315 * and legacy 316 */ 317 if (strcmp(mountpoint, path) == 0) { 318 dataset = (char *)zfs_get_name(zlist[i]); 319 break; 320 } 321 322 } 323 324 if (dataset != NULL) 325 dataset = strdup(dataset); 326 327 return (dataset); 328 } 329 330 /* 331 * get_zfs_property(dataset, property) 332 * 333 * Get the file system property specified from the ZFS dataset. 334 */ 335 336 static char * 337 get_zfs_property(sa_handle_t handle, char *dataset, zfs_prop_t property) 338 { 339 zfs_handle_t *z_fs; 340 char shareopts[ZFS_MAXPROPLEN]; 341 342 z_fs = zfs_open(handle->zfs_libhandle, dataset, ZFS_TYPE_FILESYSTEM); 343 if (z_fs != NULL) { 344 if (zfs_prop_get(z_fs, property, shareopts, 345 sizeof (shareopts), NULL, NULL, 0, 346 B_FALSE) == 0) { 347 zfs_close(z_fs); 348 return (strdup(shareopts)); 349 } 350 zfs_close(z_fs); 351 } 352 return (NULL); 353 } 354 355 /* 356 * sa_zfs_is_shared(handle, path) 357 * 358 * Check to see if the ZFS path provided has the sharenfs option set 359 * or not. 360 */ 361 362 boolean_t 363 sa_zfs_is_shared(sa_handle_t handle, char *path) 364 { 365 int ret = B_FALSE; 366 char *dataset; 367 zfs_handle_t *z_fs = NULL; 368 char shareopts[ZFS_MAXPROPLEN]; 369 370 dataset = get_zfs_dataset(handle, path, B_FALSE); 371 if (dataset != NULL) { 372 z_fs = zfs_open(handle->zfs_libhandle, dataset, 373 ZFS_TYPE_FILESYSTEM); 374 if (z_fs != NULL) { 375 if (zfs_prop_get(z_fs, ZFS_PROP_SHARENFS, 376 shareopts, sizeof (shareopts), NULL, NULL, 377 0, B_FALSE) == 0 && 378 strcmp(shareopts, "off") != 0) { 379 ret = B_TRUE; /* it is shared */ 380 } 381 zfs_close(z_fs); 382 } 383 free(dataset); 384 } 385 return (ret); 386 } 387 388 /* 389 * find_or_create_group(handle, groupname, proto, *err) 390 * 391 * While walking the ZFS tree, we need to add shares to a defined 392 * group. If the group doesn't exist, create it first, making sure it 393 * is marked as a ZFS group. 394 * 395 * Note that all ZFS shares are in a subgroup of the top level group 396 * called "zfs". 397 */ 398 399 static sa_group_t 400 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 401 { 402 sa_group_t group; 403 sa_optionset_t optionset; 404 int ret = SA_OK; 405 406 /* 407 * we check to see if the "zfs" group exists. Since this 408 * should be the top level group, we don't want the 409 * parent. This is to make sure the zfs group has been created 410 * and to created if it hasn't been. 411 */ 412 group = sa_get_group(handle, groupname); 413 if (group == NULL) { 414 group = sa_create_group(handle, groupname, &ret); 415 416 /* make sure this is flagged as a ZFS group */ 417 if (group != NULL) 418 ret = sa_set_group_attr(group, "zfs", "true"); 419 } 420 if (group != NULL) { 421 if (proto != NULL) { 422 optionset = sa_get_optionset(group, proto); 423 if (optionset == NULL) 424 optionset = sa_create_optionset(group, proto); 425 } 426 } 427 if (err != NULL) 428 *err = ret; 429 return (group); 430 } 431 432 /* 433 * find_or_create_zfs_subgroup(groupname, optstring, *err) 434 * 435 * ZFS shares will be in a subgroup of the "zfs" master group. This 436 * function looks to see if the groupname exists and returns it if it 437 * does or else creates a new one with the specified name and returns 438 * that. The "zfs" group will exist before we get here, but we make 439 * sure just in case. 440 * 441 * err must be a valid pointer. 442 */ 443 444 static sa_group_t 445 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 446 char *optstring, int *err) 447 { 448 sa_group_t group = NULL; 449 sa_group_t zfs; 450 char *name; 451 char *options; 452 453 /* start with the top-level "zfs" group */ 454 zfs = sa_get_group(handle, "zfs"); 455 *err = SA_OK; 456 if (zfs != NULL) { 457 for (group = sa_get_sub_group(zfs); group != NULL; 458 group = sa_get_next_group(group)) { 459 name = sa_get_group_attr(group, "name"); 460 if (name != NULL && strcmp(name, groupname) == 0) { 461 /* have the group so break out of here */ 462 sa_free_attr_string(name); 463 break; 464 } 465 if (name != NULL) 466 sa_free_attr_string(name); 467 } 468 469 if (group == NULL) { 470 /* 471 * Need to create the sub-group since it doesn't exist 472 */ 473 group = _sa_create_zfs_group(zfs, groupname); 474 if (group == NULL) { 475 *err = SA_NO_MEMORY; 476 return (NULL); 477 } 478 set_node_attr(group, "zfs", "true"); 479 } 480 if (strcmp(optstring, "on") == 0) 481 optstring = "rw"; 482 options = strdup(optstring); 483 if (options != NULL) { 484 *err = sa_parse_legacy_options(group, options, 485 proto); 486 /* If no optionset, add one. */ 487 if (sa_get_optionset(group, proto) == NULL) 488 (void) sa_create_optionset(group, proto); 489 490 /* 491 * Do not forget to update an optionset of 492 * the parent group so that it contains 493 * all protocols its subgroups have. 494 */ 495 if (sa_get_optionset(zfs, proto) == NULL) 496 (void) sa_create_optionset(zfs, proto); 497 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 = 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(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_t 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 handle = sa_find_group_handle(group); 934 assert(handle != NULL); 935 if (handle != NULL) 936 dataset = get_zfs_dataset(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 sa_free_attr_string(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_t 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 handle = sa_find_group_handle(group); 1051 assert(handle != NULL); 1052 if (handle != NULL) 1053 dataset = get_zfs_dataset(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_t handle; 1118 1119 handle = sa_find_group_handle( 1120 group); 1121 if (handle != NULL) 1122 dataset = get_zfs_dataset( 1123 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 sa_handle_t handle; 1136 1137 optstring = sa_proto_legacy_format(proto, 1138 group, 1); 1139 handle = sa_find_group_handle(group); 1140 zfsopts = get_zfs_property(handle, dataset, 1141 ZFS_PROP_SHARENFS); 1142 1143 if (optstring != NULL && zfsopts != NULL) { 1144 if (strcmp(optstring, zfsopts) != 0) 1145 doupdate++; 1146 } 1147 if (doupdate) { 1148 if (optstring != NULL && 1149 strlen(optstring) > 0) { 1150 (void) snprintf(command, 1151 ZFS_MAXPROPLEN * 2, 1152 "%s set share%s=%s %s", 1153 COMMAND, proto, 1154 optstring, dataset); 1155 } else { 1156 (void) snprintf(command, 1157 ZFS_MAXPROPLEN * 2, 1158 "%s set share%s=on %s", 1159 COMMAND, proto, 1160 dataset); 1161 } 1162 pfile = popen(command, "r"); 1163 if (pfile != NULL) 1164 ret = pclose(pfile); 1165 switch (ret) { 1166 default: 1167 case 1: 1168 ret = SA_SYSTEM_ERR; 1169 break; 1170 case 2: 1171 ret = SA_SYNTAX_ERR; 1172 break; 1173 case 0: 1174 break; 1175 } 1176 } 1177 if (optstring != NULL) 1178 free(optstring); 1179 if (zfsopts != NULL) 1180 free(zfsopts); 1181 } 1182 if (proto != NULL) 1183 sa_free_attr_string(proto); 1184 if (dataset != NULL) 1185 free(dataset); 1186 } 1187 free(command); 1188 } 1189 return (ret); 1190 } 1191 1192 /* 1193 * sa_group_is_zfs(group) 1194 * 1195 * Given the group, determine if the zfs attribute is set. 1196 */ 1197 1198 boolean_t 1199 sa_group_is_zfs(sa_group_t group) 1200 { 1201 char *zfs; 1202 int ret = B_FALSE; 1203 1204 zfs = sa_get_group_attr(group, "zfs"); 1205 if (zfs != NULL) { 1206 ret = B_TRUE; 1207 sa_free_attr_string(zfs); 1208 } 1209 return (ret); 1210 } 1211 1212 /* 1213 * sa_path_is_zfs(path) 1214 * 1215 * Check to see if the file system path represents is of type "zfs". 1216 */ 1217 1218 boolean_t 1219 sa_path_is_zfs(char *path) 1220 { 1221 char *fstype; 1222 int ret = B_FALSE; 1223 1224 fstype = sa_fstype(path); 1225 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 1226 ret = B_TRUE; 1227 if (fstype != NULL) 1228 sa_free_fstype(fstype); 1229 return (ret); 1230 } 1231 1232 int 1233 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1234 { 1235 char *path; 1236 1237 /* Make sure path is valid */ 1238 1239 path = sa_get_share_attr(share, "path"); 1240 if (path != NULL) { 1241 (void) memset(sh, 0, sizeof (sh)); 1242 (void) sa_fillshare(share, proto, sh); 1243 sa_free_attr_string(path); 1244 return (0); 1245 } else 1246 return (1); 1247 } 1248 1249 #define SMAX(i, j) \ 1250 if ((j) > (i)) { \ 1251 (i) = (j); \ 1252 } 1253 1254 int 1255 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh, 1256 void *exportdata, zfs_share_op_t operation) 1257 { 1258 sa_group_t group; 1259 sa_handle_t handle; 1260 char *dataset; 1261 int err = EINVAL; 1262 int i, j; 1263 char newpath[MAXPATHLEN]; 1264 char *pathp; 1265 char *resource_name; 1266 1267 /* 1268 * First find the dataset name 1269 */ 1270 if ((group = sa_get_parent_group(share)) == NULL) { 1271 return (EINVAL); 1272 } 1273 if ((handle = sa_find_group_handle(group)) == NULL) { 1274 return (EINVAL); 1275 } 1276 1277 /* 1278 * If get_zfs_dataset fails, see if it is a subdirectory 1279 */ 1280 1281 pathp = path; 1282 while ((dataset = get_zfs_dataset(handle, pathp, B_TRUE)) == NULL) { 1283 char *p; 1284 1285 if (pathp == path) { 1286 (void) strlcpy(newpath, path, sizeof (newpath)); 1287 pathp = newpath; 1288 } 1289 1290 /* 1291 * Make sure only one leading '/' This condition came 1292 * about when using HAStoragePlus which insisted on 1293 * putting an extra leading '/' in the ZFS path 1294 * name. The problem is fixed in other areas, but this 1295 * will catch any other ways that a double slash might 1296 * get introduced. 1297 */ 1298 while (*pathp == '/' && *(pathp + 1) == '/') 1299 pathp++; 1300 1301 /* 1302 * chop off part of path, but if we are at root then 1303 * make sure path is a / 1304 */ 1305 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1306 if (pathp == p) { 1307 *(p + 1) = '\0'; /* skip over /, root case */ 1308 } else { 1309 *p = '\0'; 1310 } 1311 } else { 1312 return (EINVAL); 1313 } 1314 } 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(handle->zfs_libhandle, dataset, path, 1338 resource_name, exportdata, sh, i, operation); 1339 if (err == SA_OK) 1340 sa_update_sharetab_ts(handle); 1341 else 1342 err = errno; 1343 if (resource_name != NULL) 1344 sa_free_attr_string(resource_name); 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 return (handle->zfs_libhandle); 1362 } 1363 1364 /* 1365 * This method builds values for "sharesmb" property from the 1366 * nvlist argument. The values are returned in sharesmb_val variable. 1367 */ 1368 static int 1369 sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val) 1370 { 1371 char cur_val[ZFS_MAXPROPLEN]; 1372 char *name, *val; 1373 nvpair_t *cur; 1374 int err = 0; 1375 1376 cur = nvlist_next_nvpair(nvl, NULL); 1377 while (cur != NULL) { 1378 name = nvpair_name(cur); 1379 err = nvpair_value_string(cur, &val); 1380 if ((err != 0) || (name == NULL) || (val == NULL)) 1381 return (-1); 1382 1383 (void) snprintf(cur_val, ZFS_MAXPROPLEN, "%s=%s,", name, val); 1384 (void) strlcat(sharesmb_val, cur_val, ZFS_MAXPROPLEN); 1385 1386 cur = nvlist_next_nvpair(nvl, cur); 1387 } 1388 1389 return (0); 1390 } 1391 1392 /* 1393 * This method builds values for "sharesmb" property from values 1394 * already existing on the share. The properties set via sa_zfs_sprint_new_prop 1395 * method are passed in sharesmb_val. If a existing property is already 1396 * set via sa_zfs_sprint_new_prop method, then they are not appended 1397 * to the sharesmb_val string. The returned sharesmb_val string is a combination 1398 * of new and existing values for 'sharesmb' property. 1399 */ 1400 static int 1401 sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val) 1402 { 1403 char shareopts[ZFS_MAXPROPLEN], cur_val[ZFS_MAXPROPLEN]; 1404 char *token, *last, *value; 1405 1406 if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts, 1407 sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0) 1408 return (-1); 1409 1410 if (strstr(shareopts, "=") == NULL) 1411 return (0); 1412 1413 for (token = strtok_r(shareopts, ",", &last); token != NULL; 1414 token = strtok_r(NULL, ",", &last)) { 1415 value = strchr(token, '='); 1416 if (value == NULL) 1417 return (-1); 1418 *value++ = '\0'; 1419 1420 (void) snprintf(cur_val, ZFS_MAXPROPLEN, "%s=", token); 1421 if (strstr(sharesmb_val, cur_val) == NULL) { 1422 (void) strlcat(cur_val, value, ZFS_MAXPROPLEN); 1423 (void) strlcat(cur_val, ",", ZFS_MAXPROPLEN); 1424 (void) strlcat(sharesmb_val, cur_val, ZFS_MAXPROPLEN); 1425 } 1426 } 1427 1428 return (0); 1429 } 1430 1431 /* 1432 * Sets the share properties on a ZFS share. For now, this method sets only 1433 * the "sharesmb" property. 1434 * 1435 * This method includes building a comma seperated name-value string to be 1436 * set on the "sharesmb" property of a ZFS share. This name-value string is 1437 * build in 2 steps: 1438 * - New property values given as name-value pair are set first. 1439 * - Existing optionset properties, which are not part of the new properties 1440 * passed in step 1, are appended to the newly set properties. 1441 */ 1442 int 1443 sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl) 1444 { 1445 zfs_handle_t *z_fs; 1446 char sharesmb_val[ZFS_MAXPROPLEN]; 1447 char *dataset, *lastcomma; 1448 1449 if (nvlist_empty(nvl)) 1450 return (0); 1451 1452 if ((handle == NULL) || (path == NULL)) 1453 return (-1); 1454 1455 if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL) 1456 return (-1); 1457 1458 z_fs = zfs_open(handle->zfs_libhandle, dataset, ZFS_TYPE_DATASET); 1459 if (z_fs == NULL) { 1460 free(dataset); 1461 return (-1); 1462 } 1463 1464 bzero(sharesmb_val, ZFS_MAXPROPLEN); 1465 if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) { 1466 free(dataset); 1467 zfs_close(z_fs); 1468 return (-1); 1469 } 1470 1471 if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) { 1472 free(dataset); 1473 zfs_close(z_fs); 1474 return (-1); 1475 } 1476 1477 lastcomma = strrchr(sharesmb_val, ','); 1478 if ((lastcomma != NULL) && (lastcomma[1] == '\0')) 1479 *lastcomma = '\0'; 1480 1481 (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB), 1482 sharesmb_val); 1483 free(dataset); 1484 zfs_close(z_fs); 1485 1486 return (0); 1487 }