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