1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <libzfs.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <libshare.h> 34 #include "libshare_impl.h" 35 #include <libintl.h> 36 #include <sys/mnttab.h> 37 #include <sys/mntent.h> 38 39 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t); 40 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *); 41 extern char *sa_fstype(char *); 42 extern void set_node_attr(void *, char *, char *); 43 extern int sa_is_share(void *); 44 extern void sa_update_sharetab_ts(sa_handle_t); 45 46 /* 47 * File system specific code for ZFS. The original code was stolen 48 * from the "zfs" command and modified to better suit this library's 49 * usage. 50 */ 51 52 typedef struct get_all_cbdata { 53 zfs_handle_t **cb_handles; 54 size_t cb_alloc; 55 size_t cb_used; 56 uint_t cb_types; 57 } get_all_cbdata_t; 58 59 /* 60 * sa_zfs_init(impl_handle) 61 * 62 * Initialize an access handle into libzfs. The handle needs to stay 63 * around until sa_zfs_fini() in order to maintain the cache of 64 * mounts. 65 */ 66 67 int 68 sa_zfs_init(sa_handle_impl_t impl_handle) 69 { 70 impl_handle->zfs_libhandle = libzfs_init(); 71 if (impl_handle->zfs_libhandle != NULL) { 72 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE); 73 return (B_TRUE); 74 } 75 return (B_FALSE); 76 } 77 78 /* 79 * sa_zfs_fini(impl_handle) 80 * 81 * cleanup data structures and the libzfs handle used for accessing 82 * zfs file share info. 83 */ 84 85 void 86 sa_zfs_fini(sa_handle_impl_t impl_handle) 87 { 88 if (impl_handle->zfs_libhandle != NULL) { 89 if (impl_handle->zfs_list != NULL) { 90 zfs_handle_t **zhp = impl_handle->zfs_list; 91 size_t i; 92 93 /* 94 * Contents of zfs_list need to be freed so we 95 * don't lose ZFS handles. 96 */ 97 for (i = 0; i < impl_handle->zfs_list_count; i++) { 98 zfs_close(zhp[i]); 99 } 100 free(impl_handle->zfs_list); 101 impl_handle->zfs_list = NULL; 102 impl_handle->zfs_list_count = 0; 103 } 104 105 libzfs_fini(impl_handle->zfs_libhandle); 106 impl_handle->zfs_libhandle = NULL; 107 } 108 } 109 110 /* 111 * get_one_filesystem(zfs_handle_t, data) 112 * 113 * an iterator function called while iterating through the ZFS 114 * root. It accumulates into an array of file system handles that can 115 * be used to derive info about those file systems. 116 * 117 * Note that as this function is called, we close all zhp handles that 118 * are not going to be places into the cp_handles list. We don't want 119 * to close the ones we are keeping, but all others would be leaked if 120 * not closed here. 121 */ 122 123 static int 124 get_one_filesystem(zfs_handle_t *zhp, void *data) 125 { 126 get_all_cbdata_t *cbp = data; 127 zfs_type_t type = zfs_get_type(zhp); 128 129 /* 130 * Interate over any nested datasets. 131 */ 132 if (type == ZFS_TYPE_FILESYSTEM && 133 zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) { 134 zfs_close(zhp); 135 return (1); 136 } 137 138 /* 139 * Skip any datasets whose type does not match. 140 */ 141 if ((type & cbp->cb_types) == 0) { 142 zfs_close(zhp); 143 return (0); 144 } 145 146 if (cbp->cb_alloc == cbp->cb_used) { 147 zfs_handle_t **handles; 148 149 if (cbp->cb_alloc == 0) 150 cbp->cb_alloc = 64; 151 else 152 cbp->cb_alloc *= 2; 153 154 handles = (zfs_handle_t **)calloc(1, 155 cbp->cb_alloc * sizeof (void *)); 156 157 if (handles == NULL) { 158 zfs_close(zhp); 159 return (0); 160 } 161 if (cbp->cb_handles) { 162 bcopy(cbp->cb_handles, handles, 163 cbp->cb_used * sizeof (void *)); 164 free(cbp->cb_handles); 165 } 166 167 cbp->cb_handles = handles; 168 } 169 170 cbp->cb_handles[cbp->cb_used++] = zhp; 171 172 return (0); 173 } 174 175 /* 176 * get_all_filesystems(zfs_handle_t ***fslist, size_t *count) 177 * 178 * iterate through all ZFS file systems starting at the root. Returns 179 * a count and an array of handle pointers. Allocating is only done 180 * once. The caller does not need to free since it will be done at 181 * sa_zfs_fini() time. 182 */ 183 184 static void 185 get_all_filesystems(sa_handle_impl_t impl_handle, 186 zfs_handle_t ***fslist, size_t *count) 187 { 188 get_all_cbdata_t cb = { 0 }; 189 cb.cb_types = ZFS_TYPE_FILESYSTEM; 190 191 if (impl_handle->zfs_list != NULL) { 192 *fslist = impl_handle->zfs_list; 193 *count = impl_handle->zfs_list_count; 194 return; 195 } 196 197 (void) zfs_iter_root(impl_handle->zfs_libhandle, 198 get_one_filesystem, &cb); 199 200 impl_handle->zfs_list = *fslist = cb.cb_handles; 201 impl_handle->zfs_list_count = *count = cb.cb_used; 202 } 203 204 /* 205 * mountpoint_compare(a, b) 206 * 207 * compares the mountpoint on two zfs file systems handles. 208 * returns values following strcmp() model. 209 */ 210 211 static int 212 mountpoint_compare(const void *a, const void *b) 213 { 214 zfs_handle_t **za = (zfs_handle_t **)a; 215 zfs_handle_t **zb = (zfs_handle_t **)b; 216 char mounta[MAXPATHLEN]; 217 char mountb[MAXPATHLEN]; 218 219 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta, 220 sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0); 221 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb, 222 sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0); 223 224 return (strcmp(mounta, mountb)); 225 } 226 227 /* 228 * return legacy mountpoint. Caller provides space for mountpoint. 229 */ 230 int 231 get_legacy_mountpoint(char *path, char *mountpoint, size_t len) 232 { 233 FILE *fp; 234 struct mnttab entry; 235 236 if ((fp = fopen(MNTTAB, "r")) == NULL) { 237 return (1); 238 } 239 240 while (getmntent(fp, &entry) == 0) { 241 242 if (entry.mnt_fstype == NULL || 243 strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0) 244 continue; 245 246 if (strcmp(entry.mnt_mountp, path) == 0) { 247 (void) strlcpy(mountpoint, entry.mnt_special, len); 248 (void) fclose(fp); 249 return (0); 250 } 251 } 252 (void) fclose(fp); 253 return (1); 254 } 255 256 /* 257 * get_zfs_dataset(impl_handle, path) 258 * 259 * get the name of the ZFS dataset the path is equivalent to. The 260 * dataset name is used for get/set of ZFS properties since libzfs 261 * requires a dataset to do a zfs_open(). 262 */ 263 264 static char * 265 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path, 266 boolean_t search_mnttab) 267 { 268 size_t i, count = 0; 269 char *dataset = NULL; 270 zfs_handle_t **zlist; 271 char mountpoint[ZFS_MAXPROPLEN]; 272 char canmount[ZFS_MAXPROPLEN]; 273 274 get_all_filesystems(impl_handle, &zlist, &count); 275 qsort(zlist, count, sizeof (void *), mountpoint_compare); 276 for (i = 0; i < count; i++) { 277 /* must have a mountpoint */ 278 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, mountpoint, 279 sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) { 280 /* no mountpoint */ 281 continue; 282 } 283 284 /* mountpoint must be a path */ 285 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 || 286 strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) { 287 /* 288 * Search mmttab for mountpoint 289 */ 290 291 if (search_mnttab == B_TRUE && 292 get_legacy_mountpoint(path, mountpoint, 293 sizeof (mountpoint)) == 0) { 294 dataset = mountpoint; 295 break; 296 } 297 continue; 298 } 299 300 /* canmount must be set */ 301 canmount[0] = '\0'; 302 if (zfs_prop_get(zlist[i], ZFS_PROP_CANMOUNT, canmount, 303 sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 || 304 strcmp(canmount, "off") == 0) 305 continue; 306 307 /* 308 * have a mountable handle but want to skip those marked none 309 * and legacy 310 */ 311 if (strcmp(mountpoint, path) == 0) { 312 dataset = (char *)zfs_get_name(zlist[i]); 313 break; 314 } 315 316 } 317 318 if (dataset != NULL) 319 dataset = strdup(dataset); 320 321 return (dataset); 322 } 323 324 /* 325 * get_zfs_property(dataset, property) 326 * 327 * Get the file system property specified from the ZFS dataset. 328 */ 329 330 static char * 331 get_zfs_property(char *dataset, zfs_prop_t property) 332 { 333 zfs_handle_t *handle = NULL; 334 char shareopts[ZFS_MAXPROPLEN]; 335 libzfs_handle_t *libhandle; 336 337 libhandle = libzfs_init(); 338 if (libhandle != NULL) { 339 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM); 340 if (handle != NULL) { 341 if (zfs_prop_get(handle, property, shareopts, 342 sizeof (shareopts), NULL, NULL, 0, 343 B_FALSE) == 0) { 344 zfs_close(handle); 345 libzfs_fini(libhandle); 346 return (strdup(shareopts)); 347 } 348 zfs_close(handle); 349 } 350 libzfs_fini(libhandle); 351 } 352 return (NULL); 353 } 354 355 /* 356 * sa_zfs_is_shared(handle, path) 357 * 358 * Check to see if the ZFS path provided has the sharenfs option set 359 * or not. 360 */ 361 362 int 363 sa_zfs_is_shared(sa_handle_t sahandle, char *path) 364 { 365 int ret = 0; 366 char *dataset; 367 zfs_handle_t *handle = NULL; 368 char shareopts[ZFS_MAXPROPLEN]; 369 libzfs_handle_t *libhandle; 370 371 dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE); 372 if (dataset != NULL) { 373 libhandle = libzfs_init(); 374 if (libhandle != NULL) { 375 handle = zfs_open(libhandle, dataset, 376 ZFS_TYPE_FILESYSTEM); 377 if (handle != NULL) { 378 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS, 379 shareopts, sizeof (shareopts), NULL, NULL, 380 0, B_FALSE) == 0 && 381 strcmp(shareopts, "off") != 0) { 382 ret = 1; /* it is shared */ 383 } 384 zfs_close(handle); 385 } 386 libzfs_fini(libhandle); 387 } 388 free(dataset); 389 } 390 return (ret); 391 } 392 393 /* 394 * find_or_create_group(handle, groupname, proto, *err) 395 * 396 * While walking the ZFS tree, we need to add shares to a defined 397 * group. If the group doesn't exist, create it first, making sure it 398 * is marked as a ZFS group. 399 * 400 * Note that all ZFS shares are in a subgroup of the top level group 401 * called "zfs". 402 */ 403 404 static sa_group_t 405 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err) 406 { 407 sa_group_t group; 408 sa_optionset_t optionset; 409 int ret = SA_OK; 410 411 /* 412 * we check to see if the "zfs" group exists. Since this 413 * should be the top level group, we don't want the 414 * parent. This is to make sure the zfs group has been created 415 * and to created if it hasn't been. 416 */ 417 group = sa_get_group(handle, groupname); 418 if (group == NULL) { 419 group = sa_create_group(handle, groupname, &ret); 420 421 /* make sure this is flagged as a ZFS group */ 422 if (group != NULL) 423 ret = sa_set_group_attr(group, "zfs", "true"); 424 } 425 if (group != NULL) { 426 if (proto != NULL) { 427 optionset = sa_get_optionset(group, proto); 428 if (optionset == NULL) 429 optionset = sa_create_optionset(group, proto); 430 } 431 } 432 if (err != NULL) 433 *err = ret; 434 return (group); 435 } 436 437 /* 438 * find_or_create_zfs_subgroup(groupname, optstring, *err) 439 * 440 * ZFS shares will be in a subgroup of the "zfs" master group. This 441 * function looks to see if the groupname exists and returns it if it 442 * does or else creates a new one with the specified name and returns 443 * that. The "zfs" group will exist before we get here, but we make 444 * sure just in case. 445 * 446 * err must be a valid pointer. 447 */ 448 449 static sa_group_t 450 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto, 451 char *optstring, int *err) 452 { 453 sa_group_t group = NULL; 454 sa_group_t zfs; 455 char *name; 456 char *options; 457 458 /* start with the top-level "zfs" group */ 459 zfs = sa_get_group(handle, "zfs"); 460 *err = SA_OK; 461 if (zfs != NULL) { 462 for (group = sa_get_sub_group(zfs); group != NULL; 463 group = sa_get_next_group(group)) { 464 name = sa_get_group_attr(group, "name"); 465 if (name != NULL && strcmp(name, groupname) == 0) { 466 /* have the group so break out of here */ 467 sa_free_attr_string(name); 468 break; 469 } 470 if (name != NULL) 471 sa_free_attr_string(name); 472 } 473 474 if (group == NULL) { 475 /* 476 * need to create the sub-group since it doesn't exist 477 */ 478 group = _sa_create_zfs_group(zfs, groupname); 479 if (group != NULL) 480 set_node_attr(group, "zfs", "true"); 481 if (strcmp(optstring, "on") == 0) 482 optstring = "rw"; 483 if (group != NULL) { 484 options = strdup(optstring); 485 if (options != NULL) { 486 *err = sa_parse_legacy_options(group, 487 options, proto); 488 489 /* If no optionset, add one */ 490 if (sa_get_optionset(group, proto) == 491 NULL) 492 (void) sa_create_optionset( 493 group, proto); 494 free(options); 495 } else { 496 *err = SA_NO_MEMORY; 497 } 498 } 499 } else if (proto != NULL && strcmp(proto, "smb") == 0) { 500 *err = SA_PROP_SHARE_ONLY; 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 if (err == SA_OK) { 617 if (strcmp(shareopts, "on") == 0) 618 shareopts = ""; 619 if (shareopts != NULL) { 620 char *options; 621 if (grouperr == SA_PROP_SHARE_ONLY) { 622 /* 623 * Some properties may only be on 624 * shares, but due to the ZFS 625 * sub-groups being artificial, we 626 * sometimes get this and have to deal 627 * with it. We do it by attempting to 628 * put it on the share. 629 */ 630 options = strdup(shareopts); 631 if (options != NULL) { 632 err = sa_parse_legacy_options(share, 633 options, proto); 634 free(options); 635 } 636 } 637 /* unmark the share's changed state */ 638 set_node_attr(share, "changed", NULL); 639 } 640 features = sa_proto_get_featureset(proto); 641 if (share != NULL && features & SA_FEATURE_RESOURCE) { 642 /* 643 * We have a share and the protocol requires 644 * that at least one resource exist (probably 645 * SMB). We need to make sure that there is at 646 * least one. 647 */ 648 resource = sa_get_share_resource(share, NULL); 649 if (resource == NULL) { 650 zfs_construct_resource(share, dataset); 651 } 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 726 int 727 sa_get_zfs_shares(sa_handle_t handle, char *groupname) 728 { 729 sa_group_t group; 730 sa_group_t zfsgroup; 731 int legacy = 0; 732 int err; 733 zfs_handle_t **zlist; 734 char shareopts[ZFS_MAXPROPLEN]; 735 sa_share_t share; 736 zprop_source_t source; 737 char sourcestr[ZFS_MAXPROPLEN]; 738 char mountpoint[ZFS_MAXPROPLEN]; 739 size_t count = 0, i; 740 libzfs_handle_t *zfs_libhandle; 741 742 /* 743 * If we can't access libzfs, don't bother doing anything. 744 */ 745 zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 746 if (zfs_libhandle == NULL) 747 return (SA_SYSTEM_ERR); 748 749 zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 750 if (zfsgroup == NULL) 751 return (legacy); 752 753 /* 754 * need to walk the mounted ZFS pools and datasets to 755 * find shares that are possible. 756 */ 757 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 758 qsort(zlist, count, sizeof (void *), mountpoint_compare); 759 760 group = zfsgroup; 761 for (i = 0; i < count; i++) { 762 char *dataset; 763 int foundnfs = 0; 764 765 source = ZPROP_SRC_ALL; 766 /* If no mountpoint, skip. */ 767 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 768 mountpoint, sizeof (mountpoint), NULL, NULL, 0, 769 B_FALSE) != 0) 770 continue; 771 772 /* 773 * zfs_get_name value must not be freed. It is just a 774 * pointer to a value in the handle. 775 */ 776 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 777 continue; 778 779 /* 780 * only deal with "mounted" file systems since 781 * unmounted file systems can't actually be shared. 782 */ 783 784 if (!zfs_is_mounted(zlist[i], NULL)) 785 continue; 786 787 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 788 sizeof (shareopts), &source, sourcestr, 789 ZFS_MAXPROPLEN, B_FALSE) == 0 && 790 strcmp(shareopts, "off") != 0) { 791 /* it is shared so add to list */ 792 err = SA_OK; 793 foundnfs = 1; 794 share = sa_find_share(handle, mountpoint); 795 if (share != NULL) { 796 /* 797 * A zfs file system had been shared 798 * through traditional methods 799 * (share/dfstab or added to a non-zfs 800 * group. Now it has been added to a 801 * ZFS group via the zfs 802 * command. Remove from previous 803 * config and setup with current 804 * options. 805 */ 806 err = sa_remove_share(share); 807 share = NULL; 808 } 809 if (err == SA_OK) { 810 err = sa_zfs_process_share(handle, group, 811 share, mountpoint, "nfs", source, 812 shareopts, sourcestr, dataset); 813 } 814 } 815 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, shareopts, 816 sizeof (shareopts), &source, sourcestr, 817 ZFS_MAXPROPLEN, B_FALSE) == 0 && 818 strcmp(shareopts, "off") != 0) { 819 /* it is shared so add to list */ 820 err = SA_OK; 821 share = sa_find_share(handle, mountpoint); 822 if (share != NULL && !foundnfs) { 823 /* 824 * A zfs file system had been shared 825 * through traditional methods 826 * (share/dfstab or added to a non-zfs 827 * group. Now it has been added to a 828 * ZFS group via the zfs 829 * command. Remove from previous 830 * config and setup with current 831 * options. 832 */ 833 err = sa_remove_share(share); 834 share = NULL; 835 } 836 if (err == SA_OK) { 837 err = sa_zfs_process_share(handle, group, 838 share, mountpoint, "smb", source, 839 shareopts, sourcestr, dataset); 840 } 841 } 842 } 843 /* 844 * Don't need to free the "zlist" variable since it is only a 845 * pointer to a cached value that will be freed when 846 * sa_fini() is called. 847 */ 848 return (legacy); 849 } 850 851 #define COMMAND "/usr/sbin/zfs" 852 853 /* 854 * sa_zfs_set_sharenfs(group, path, on) 855 * 856 * Update the "sharenfs" property on the path. If on is true, then set 857 * to the properties on the group or "on" if no properties are 858 * defined. Set to "off" if on is false. 859 */ 860 861 int 862 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 863 { 864 int ret = SA_NOT_IMPLEMENTED; 865 char *command; 866 867 command = malloc(ZFS_MAXPROPLEN * 2); 868 if (command != NULL) { 869 char *opts = NULL; 870 char *dataset = NULL; 871 FILE *pfile; 872 sa_handle_impl_t impl_handle; 873 /* for now, NFS is always available for "zfs" */ 874 if (on) { 875 opts = sa_proto_legacy_format("nfs", group, 1); 876 if (opts != NULL && strlen(opts) == 0) { 877 free(opts); 878 opts = strdup("on"); 879 } 880 } 881 882 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 883 assert(impl_handle != NULL); 884 if (impl_handle != NULL) 885 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 886 else 887 ret = SA_SYSTEM_ERR; 888 889 if (dataset != NULL) { 890 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 891 "%s set sharenfs=\"%s\" %s", COMMAND, 892 opts != NULL ? opts : "off", dataset); 893 pfile = popen(command, "r"); 894 if (pfile != NULL) { 895 ret = pclose(pfile); 896 if (ret != 0) 897 ret = SA_SYSTEM_ERR; 898 } 899 } 900 if (opts != NULL) 901 free(opts); 902 if (dataset != NULL) 903 free(dataset); 904 free(command); 905 } 906 return (ret); 907 } 908 909 /* 910 * add_resources(share, opt) 911 * 912 * Add resource properties to those in "opt". Resources are prefixed 913 * with name=resourcename. 914 */ 915 static char * 916 add_resources(sa_share_t share, char *opt) 917 { 918 char *newopt = NULL; 919 char *propstr; 920 sa_resource_t resource; 921 922 newopt = strdup(opt); 923 if (newopt == NULL) 924 return (newopt); 925 926 for (resource = sa_get_share_resource(share, NULL); 927 resource != NULL; 928 resource = sa_get_next_resource(resource)) { 929 char *name; 930 size_t size; 931 932 name = sa_get_resource_attr(resource, "name"); 933 if (name == NULL) { 934 free(newopt); 935 return (NULL); 936 } 937 size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 938 newopt = calloc(1, size); 939 if (newopt != NULL) 940 (void) snprintf(newopt, size, "%s,name=%s", opt, name); 941 free(opt); 942 opt = newopt; 943 propstr = sa_proto_legacy_format("smb", resource, 0); 944 if (propstr == NULL) { 945 free(opt); 946 return (NULL); 947 } 948 size = strlen(propstr) + strlen(opt) + 2; 949 newopt = calloc(1, size); 950 if (newopt != NULL) 951 (void) snprintf(newopt, size, "%s,%s", opt, propstr); 952 free(opt); 953 opt = newopt; 954 } 955 return (opt); 956 } 957 958 /* 959 * sa_zfs_set_sharesmb(group, path, on) 960 * 961 * Update the "sharesmb" property on the path. If on is true, then set 962 * to the properties on the group or "on" if no properties are 963 * defined. Set to "off" if on is false. 964 */ 965 966 int 967 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 968 { 969 int ret = SA_NOT_IMPLEMENTED; 970 char *command; 971 sa_share_t share; 972 973 /* In case SMB not enabled */ 974 if (sa_get_optionset(group, "smb") == NULL) 975 return (SA_NOT_SUPPORTED); 976 977 command = malloc(ZFS_MAXPROPLEN * 2); 978 if (command != NULL) { 979 char *opts = NULL; 980 char *dataset = NULL; 981 FILE *pfile; 982 sa_handle_impl_t impl_handle; 983 984 if (on) { 985 char *newopt; 986 987 share = sa_get_share(group, NULL); 988 opts = sa_proto_legacy_format("smb", share, 1); 989 if (opts != NULL && strlen(opts) == 0) { 990 free(opts); 991 opts = strdup("on"); 992 } 993 newopt = add_resources(opts, share); 994 free(opts); 995 opts = newopt; 996 } 997 998 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 999 assert(impl_handle != NULL); 1000 if (impl_handle != NULL) 1001 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1002 else 1003 ret = SA_SYSTEM_ERR; 1004 1005 if (dataset != NULL) { 1006 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1007 "echo %s set sharesmb=\"%s\" %s", COMMAND, 1008 opts != NULL ? opts : "off", dataset); 1009 pfile = popen(command, "r"); 1010 if (pfile != NULL) { 1011 ret = pclose(pfile); 1012 if (ret != 0) 1013 ret = SA_SYSTEM_ERR; 1014 } 1015 } 1016 if (opts != NULL) 1017 free(opts); 1018 if (dataset != NULL) 1019 free(dataset); 1020 free(command); 1021 } 1022 return (ret); 1023 } 1024 1025 /* 1026 * sa_zfs_update(group) 1027 * 1028 * call back to ZFS to update the share if necessary. 1029 * Don't do it if it isn't a real change. 1030 */ 1031 int 1032 sa_zfs_update(sa_group_t group) 1033 { 1034 sa_optionset_t protopt; 1035 sa_group_t parent; 1036 char *command; 1037 char *optstring; 1038 int ret = SA_OK; 1039 int doupdate = 0; 1040 FILE *pfile; 1041 1042 if (sa_is_share(group)) 1043 parent = sa_get_parent_group(group); 1044 else 1045 parent = group; 1046 1047 if (parent != NULL) { 1048 command = malloc(ZFS_MAXPROPLEN * 2); 1049 if (command == NULL) 1050 return (SA_NO_MEMORY); 1051 1052 *command = '\0'; 1053 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 1054 protopt = sa_get_next_optionset(protopt)) { 1055 1056 char *proto = sa_get_optionset_attr(protopt, "type"); 1057 char *path; 1058 char *dataset = NULL; 1059 char *zfsopts = NULL; 1060 1061 if (sa_is_share(group)) { 1062 path = sa_get_share_attr((sa_share_t)group, 1063 "path"); 1064 if (path != NULL) { 1065 sa_handle_impl_t impl_handle; 1066 1067 impl_handle = sa_find_group_handle( 1068 group); 1069 if (impl_handle != NULL) 1070 dataset = get_zfs_dataset( 1071 impl_handle, path, B_FALSE); 1072 else 1073 ret = SA_SYSTEM_ERR; 1074 1075 sa_free_attr_string(path); 1076 } 1077 } else { 1078 dataset = sa_get_group_attr(group, "name"); 1079 } 1080 /* update only when there is an optstring found */ 1081 doupdate = 0; 1082 if (proto != NULL && dataset != NULL) { 1083 optstring = sa_proto_legacy_format(proto, 1084 group, 1); 1085 zfsopts = get_zfs_property(dataset, 1086 ZFS_PROP_SHARENFS); 1087 1088 if (optstring != NULL && zfsopts != NULL) { 1089 if (strcmp(optstring, zfsopts) != 0) 1090 doupdate++; 1091 } 1092 if (doupdate) { 1093 if (optstring != NULL && 1094 strlen(optstring) > 0) { 1095 (void) snprintf(command, 1096 ZFS_MAXPROPLEN * 2, 1097 "%s set sharenfs=%s %s", 1098 COMMAND, 1099 optstring, dataset); 1100 } else { 1101 (void) snprintf(command, 1102 ZFS_MAXPROPLEN * 2, 1103 "%s set sharenfs=on %s", 1104 COMMAND, 1105 dataset); 1106 } 1107 pfile = popen(command, "r"); 1108 if (pfile != NULL) 1109 ret = pclose(pfile); 1110 switch (ret) { 1111 default: 1112 case 1: 1113 ret = SA_SYSTEM_ERR; 1114 break; 1115 case 2: 1116 ret = SA_SYNTAX_ERR; 1117 break; 1118 case 0: 1119 break; 1120 } 1121 } 1122 if (optstring != NULL) 1123 free(optstring); 1124 if (zfsopts != NULL) 1125 free(zfsopts); 1126 } 1127 if (proto != NULL) 1128 sa_free_attr_string(proto); 1129 if (dataset != NULL) 1130 free(dataset); 1131 } 1132 free(command); 1133 } 1134 return (ret); 1135 } 1136 1137 /* 1138 * sa_group_is_zfs(group) 1139 * 1140 * Given the group, determine if the zfs attribute is set. 1141 */ 1142 1143 int 1144 sa_group_is_zfs(sa_group_t group) 1145 { 1146 char *zfs; 1147 int ret = 0; 1148 1149 zfs = sa_get_group_attr(group, "zfs"); 1150 if (zfs != NULL) { 1151 ret = 1; 1152 sa_free_attr_string(zfs); 1153 } 1154 return (ret); 1155 } 1156 1157 /* 1158 * sa_path_is_zfs(path) 1159 * 1160 * Check to see if the file system path represents is of type "zfs". 1161 */ 1162 1163 int 1164 sa_path_is_zfs(char *path) 1165 { 1166 char *fstype; 1167 int ret = 0; 1168 1169 fstype = sa_fstype(path); 1170 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 1171 ret = 1; 1172 if (fstype != NULL) 1173 sa_free_fstype(fstype); 1174 return (ret); 1175 } 1176 1177 int 1178 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1179 { 1180 char *path; 1181 1182 /* Make sure path is valid */ 1183 1184 path = sa_get_share_attr(share, "path"); 1185 if (path != NULL) { 1186 (void) memset(sh, 0, sizeof (sh)); 1187 (void) sa_fillshare(share, proto, sh); 1188 sa_free_attr_string(path); 1189 return (0); 1190 } else 1191 return (1); 1192 } 1193 1194 #define SMAX(i, j) \ 1195 if ((j) > (i)) { \ 1196 (i) = (j); \ 1197 } 1198 1199 int 1200 sa_share_zfs(sa_share_t share, char *path, share_t *sh, 1201 void *exportdata, zfs_share_op_t operation) 1202 { 1203 libzfs_handle_t *libhandle; 1204 sa_group_t group; 1205 sa_handle_t sahandle; 1206 char *dataset; 1207 int err = EINVAL; 1208 int i, j; 1209 char newpath[MAXPATHLEN]; 1210 char *pathp; 1211 1212 /* 1213 * First find the dataset name 1214 */ 1215 if ((group = sa_get_parent_group(share)) == NULL) { 1216 return (SA_SYSTEM_ERR); 1217 } 1218 if ((sahandle = sa_find_group_handle(group)) == NULL) { 1219 return (SA_SYSTEM_ERR); 1220 } 1221 1222 /* 1223 * If get_zfs_dataset fails, see if it is a subdirectory 1224 */ 1225 1226 pathp = path; 1227 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 1228 char *p; 1229 1230 if (pathp == path) { 1231 (void) strlcpy(newpath, path, sizeof (newpath)); 1232 pathp = newpath; 1233 } 1234 1235 /* 1236 * chop off part of path, but if we are at root then 1237 * make sure path is a / 1238 */ 1239 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1240 if (pathp == p) { 1241 *(p + 1) = '\0'; /* skip over /, root case */ 1242 } else { 1243 *p = '\0'; 1244 } 1245 } else { 1246 return (SA_SYSTEM_ERR); 1247 } 1248 } 1249 1250 libhandle = libzfs_init(); 1251 if (libhandle != NULL) { 1252 1253 i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1254 sh->sh_size = i; 1255 1256 j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1257 sh->sh_size += j; 1258 SMAX(i, j); 1259 1260 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1261 sh->sh_size += j; 1262 SMAX(i, j); 1263 1264 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1265 sh->sh_size += j; 1266 SMAX(i, j); 1267 1268 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1269 sh->sh_size += j; 1270 SMAX(i, j); 1271 err = zfs_deleg_share_nfs(libhandle, dataset, path, 1272 exportdata, sh, i, operation); 1273 if (err == SA_OK) 1274 sa_update_sharetab_ts(sahandle); 1275 libzfs_fini(libhandle); 1276 } 1277 free(dataset); 1278 return (err); 1279 } 1280 1281 /* 1282 * sa_get_zfs_handle(handle) 1283 * 1284 * Given an sa_handle_t, return the libzfs_handle_t *. This is only 1285 * used internally by libzfs. Needed in order to avoid including 1286 * libshare_impl.h in libzfs. 1287 */ 1288 1289 libzfs_handle_t * 1290 sa_get_zfs_handle(sa_handle_t handle) 1291 { 1292 sa_handle_impl_t implhandle = (sa_handle_impl_t)handle; 1293 1294 return (implhandle->zfs_libhandle); 1295 } 1296