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(group, share, mountpoint, shareopts, proto, dataset, 596 * grouperr) 597 * 598 * handle case where this is the top of a sub-group in ZFS. Pulled out 599 * of sa_get_zfs_shares for readability. We need the grouperr from the 600 * creation of the subgroup to know whether to add the public 601 * property, etc. to the specific share. 602 */ 603 static int 604 zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint, 605 char *shareopts, char *proto, char *dataset, int grouperr) 606 { 607 int err = SA_OK; 608 sa_resource_t resource; 609 uint64_t features; 610 611 set_node_attr(group, "zfs", "true"); 612 if (share == NULL) 613 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT, 614 &err, (uint64_t)SA_FEATURE_NONE); 615 if (err == SA_OK) { 616 if (strcmp(shareopts, "on") == 0) 617 shareopts = ""; 618 if (shareopts != NULL) { 619 char *options; 620 if (grouperr == SA_PROP_SHARE_ONLY) { 621 /* 622 * Some properties may only be on 623 * shares, but due to the ZFS 624 * sub-groups being artificial, we 625 * sometimes get this and have to deal 626 * with it. We do it by attempting to 627 * put it on the share. 628 */ 629 options = strdup(shareopts); 630 if (options != NULL) { 631 err = sa_parse_legacy_options(share, 632 options, proto); 633 free(options); 634 } 635 } 636 /* unmark the share's changed state */ 637 set_node_attr(share, "changed", NULL); 638 } 639 features = sa_proto_get_featureset(proto); 640 if (share != NULL && features & SA_FEATURE_RESOURCE) { 641 /* 642 * We have a share and the protocol requires 643 * that at least one resource exist (probably 644 * SMB). We need to make sure that there is at 645 * least one. 646 */ 647 resource = sa_get_share_resource(share, NULL); 648 if (resource == NULL) { 649 zfs_construct_resource(share, dataset); 650 } 651 } 652 } 653 return (err); 654 } 655 656 /* 657 * zfs_grp_error(err) 658 * 659 * Print group create error, but only once. If err is 0 do the 660 * print else don't. 661 */ 662 663 static void 664 zfs_grp_error(int err) 665 { 666 if (err == 0) { 667 /* only print error once */ 668 (void) fprintf(stderr, dgettext(TEXT_DOMAIN, 669 "Cannot create ZFS subgroup during initialization:" 670 " %s\n"), sa_errorstr(SA_SYSTEM_ERR)); 671 } 672 } 673 674 /* 675 * zfs_process_share(handle, share, mountpoint, proto, source, 676 * shareopts, sourcestr) 677 * 678 * Creates the subgroup, if necessary and adds shares and adds shares 679 * and properties. 680 */ 681 static int 682 zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share, 683 char *mountpoint, char *proto, zprop_source_t source, char *shareopts, 684 char *sourcestr, char *dataset) 685 { 686 int err = SA_OK; 687 688 if (source & ZPROP_SRC_INHERITED) { 689 err = zfs_inherited(handle, share, sourcestr, shareopts, 690 mountpoint, proto, dataset); 691 } else { 692 group = find_or_create_zfs_subgroup(handle, dataset, proto, 693 shareopts, &err); 694 if (group == NULL) { 695 static boolean_t reported_error = B_FALSE; 696 /* 697 * There is a problem, but we can't do 698 * anything about it at this point so we issue 699 * a warning and move on. 700 */ 701 zfs_grp_error(reported_error); 702 reported_error = B_TRUE; 703 } 704 set_node_attr(group, "zfs", "true"); 705 /* 706 * Add share with local opts via zfs_notinherited. 707 */ 708 err = zfs_notinherited(group, share, mountpoint, shareopts, 709 proto, dataset, err); 710 } 711 return (err); 712 } 713 714 /* 715 * sa_get_zfs_shares(handle, groupname) 716 * 717 * Walk the mnttab for all zfs mounts and determine which are 718 * shared. Find or create the appropriate group/sub-group to contain 719 * the shares. 720 * 721 * All shares are in a sub-group that will hold the properties. This 722 * allows representing the inherited property model. 723 */ 724 725 int 726 sa_get_zfs_shares(sa_handle_t handle, char *groupname) 727 { 728 sa_group_t group; 729 sa_group_t zfsgroup; 730 int legacy = 0; 731 int err; 732 zfs_handle_t **zlist; 733 char shareopts[ZFS_MAXPROPLEN]; 734 sa_share_t share; 735 zprop_source_t source; 736 char sourcestr[ZFS_MAXPROPLEN]; 737 char mountpoint[ZFS_MAXPROPLEN]; 738 size_t count = 0, i; 739 libzfs_handle_t *zfs_libhandle; 740 741 /* 742 * If we can't access libzfs, don't bother doing anything. 743 */ 744 zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle; 745 if (zfs_libhandle == NULL) 746 return (SA_SYSTEM_ERR); 747 748 zfsgroup = find_or_create_group(handle, groupname, NULL, &err); 749 if (zfsgroup == NULL) 750 return (legacy); 751 752 /* 753 * need to walk the mounted ZFS pools and datasets to 754 * find shares that are possible. 755 */ 756 get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count); 757 qsort(zlist, count, sizeof (void *), mountpoint_compare); 758 759 group = zfsgroup; 760 for (i = 0; i < count; i++) { 761 char *dataset; 762 int foundnfs = 0; 763 764 source = ZPROP_SRC_ALL; 765 /* If no mountpoint, skip. */ 766 if (zfs_prop_get(zlist[i], ZFS_PROP_MOUNTPOINT, 767 mountpoint, sizeof (mountpoint), NULL, NULL, 0, 768 B_FALSE) != 0) 769 continue; 770 771 /* 772 * zfs_get_name value must not be freed. It is just a 773 * pointer to a value in the handle. 774 */ 775 if ((dataset = (char *)zfs_get_name(zlist[i])) == NULL) 776 continue; 777 778 /* 779 * only deal with "mounted" file systems since 780 * unmounted file systems can't actually be shared. 781 */ 782 783 if (!zfs_is_mounted(zlist[i], NULL)) 784 continue; 785 786 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARENFS, shareopts, 787 sizeof (shareopts), &source, sourcestr, 788 ZFS_MAXPROPLEN, B_FALSE) == 0 && 789 strcmp(shareopts, "off") != 0) { 790 /* it is shared so add to list */ 791 err = SA_OK; 792 foundnfs = 1; 793 share = sa_find_share(handle, mountpoint); 794 if (share != NULL) { 795 /* 796 * A zfs file system had been shared 797 * through traditional methods 798 * (share/dfstab or added to a non-zfs 799 * group. Now it has been added to a 800 * ZFS group via the zfs 801 * command. Remove from previous 802 * config and setup with current 803 * options. 804 */ 805 err = sa_remove_share(share); 806 share = NULL; 807 } 808 if (err == SA_OK) { 809 err = zfs_process_share(handle, group, 810 share, mountpoint, "nfs", source, 811 shareopts, sourcestr, dataset); 812 } 813 } 814 if (zfs_prop_get(zlist[i], ZFS_PROP_SHARESMB, shareopts, 815 sizeof (shareopts), &source, sourcestr, 816 ZFS_MAXPROPLEN, B_FALSE) == 0 && 817 strcmp(shareopts, "off") != 0) { 818 /* it is shared so add to list */ 819 err = SA_OK; 820 share = sa_find_share(handle, mountpoint); 821 if (share != NULL && !foundnfs) { 822 /* 823 * A zfs file system had been shared 824 * through traditional methods 825 * (share/dfstab or added to a non-zfs 826 * group. Now it has been added to a 827 * ZFS group via the zfs 828 * command. Remove from previous 829 * config and setup with current 830 * options. 831 */ 832 err = sa_remove_share(share); 833 share = NULL; 834 } 835 if (err == SA_OK) { 836 err = zfs_process_share(handle, group, 837 share, mountpoint, "smb", source, 838 shareopts, sourcestr, dataset); 839 } 840 } 841 } 842 /* 843 * Don't need to free the "zlist" variable since it is only a 844 * pointer to a cached value that will be freed when 845 * sa_fini() is called. 846 */ 847 return (legacy); 848 } 849 850 #define COMMAND "/usr/sbin/zfs" 851 852 /* 853 * sa_zfs_set_sharenfs(group, path, on) 854 * 855 * Update the "sharenfs" property on the path. If on is true, then set 856 * to the properties on the group or "on" if no properties are 857 * defined. Set to "off" if on is false. 858 */ 859 860 int 861 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on) 862 { 863 int ret = SA_NOT_IMPLEMENTED; 864 char *command; 865 866 command = malloc(ZFS_MAXPROPLEN * 2); 867 if (command != NULL) { 868 char *opts = NULL; 869 char *dataset = NULL; 870 FILE *pfile; 871 sa_handle_impl_t impl_handle; 872 /* for now, NFS is always available for "zfs" */ 873 if (on) { 874 opts = sa_proto_legacy_format("nfs", group, 1); 875 if (opts != NULL && strlen(opts) == 0) { 876 free(opts); 877 opts = strdup("on"); 878 } 879 } 880 881 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 882 assert(impl_handle != NULL); 883 if (impl_handle != NULL) 884 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 885 else 886 ret = SA_SYSTEM_ERR; 887 888 if (dataset != NULL) { 889 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 890 "%s set sharenfs=\"%s\" %s", COMMAND, 891 opts != NULL ? opts : "off", dataset); 892 pfile = popen(command, "r"); 893 if (pfile != NULL) { 894 ret = pclose(pfile); 895 if (ret != 0) 896 ret = SA_SYSTEM_ERR; 897 } 898 } 899 if (opts != NULL) 900 free(opts); 901 if (dataset != NULL) 902 free(dataset); 903 free(command); 904 } 905 return (ret); 906 } 907 908 /* 909 * add_resources(share, opt) 910 * 911 * Add resource properties to those in "opt". Resources are prefixed 912 * with name=resourcename. 913 */ 914 static char * 915 add_resources(sa_share_t share, char *opt) 916 { 917 char *newopt = NULL; 918 char *propstr; 919 sa_resource_t resource; 920 921 newopt = strdup(opt); 922 if (newopt == NULL) 923 return (newopt); 924 925 for (resource = sa_get_share_resource(share, NULL); 926 resource != NULL; 927 resource = sa_get_next_resource(resource)) { 928 char *name; 929 size_t size; 930 931 name = sa_get_resource_attr(resource, "name"); 932 if (name == NULL) { 933 free(newopt); 934 return (NULL); 935 } 936 size = strlen(name) + strlen(opt) + sizeof ("name=") + 1; 937 newopt = calloc(1, size); 938 if (newopt != NULL) 939 (void) snprintf(newopt, size, "%s,name=%s", opt, name); 940 free(opt); 941 opt = newopt; 942 propstr = sa_proto_legacy_format("smb", resource, 0); 943 if (propstr == NULL) { 944 free(opt); 945 return (NULL); 946 } 947 size = strlen(propstr) + strlen(opt) + 2; 948 newopt = calloc(1, size); 949 if (newopt != NULL) 950 (void) snprintf(newopt, size, "%s,%s", opt, propstr); 951 free(opt); 952 opt = newopt; 953 } 954 return (opt); 955 } 956 957 /* 958 * sa_zfs_set_sharesmb(group, path, on) 959 * 960 * Update the "sharesmb" property on the path. If on is true, then set 961 * to the properties on the group or "on" if no properties are 962 * defined. Set to "off" if on is false. 963 */ 964 965 int 966 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on) 967 { 968 int ret = SA_NOT_IMPLEMENTED; 969 char *command; 970 sa_share_t share; 971 972 /* In case SMB not enabled */ 973 if (sa_get_optionset(group, "smb") == NULL) 974 return (SA_NOT_SUPPORTED); 975 976 command = malloc(ZFS_MAXPROPLEN * 2); 977 if (command != NULL) { 978 char *opts = NULL; 979 char *dataset = NULL; 980 FILE *pfile; 981 sa_handle_impl_t impl_handle; 982 983 if (on) { 984 char *newopt; 985 986 share = sa_get_share(group, NULL); 987 opts = sa_proto_legacy_format("smb", share, 1); 988 if (opts != NULL && strlen(opts) == 0) { 989 free(opts); 990 opts = strdup("on"); 991 } 992 newopt = add_resources(opts, share); 993 free(opts); 994 opts = newopt; 995 } 996 997 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 998 assert(impl_handle != NULL); 999 if (impl_handle != NULL) 1000 dataset = get_zfs_dataset(impl_handle, path, B_FALSE); 1001 else 1002 ret = SA_SYSTEM_ERR; 1003 1004 if (dataset != NULL) { 1005 (void) snprintf(command, ZFS_MAXPROPLEN * 2, 1006 "echo %s set sharesmb=\"%s\" %s", COMMAND, 1007 opts != NULL ? opts : "off", dataset); 1008 pfile = popen(command, "r"); 1009 if (pfile != NULL) { 1010 ret = pclose(pfile); 1011 if (ret != 0) 1012 ret = SA_SYSTEM_ERR; 1013 } 1014 } 1015 if (opts != NULL) 1016 free(opts); 1017 if (dataset != NULL) 1018 free(dataset); 1019 free(command); 1020 } 1021 return (ret); 1022 } 1023 1024 /* 1025 * sa_zfs_update(group) 1026 * 1027 * call back to ZFS to update the share if necessary. 1028 * Don't do it if it isn't a real change. 1029 */ 1030 int 1031 sa_zfs_update(sa_group_t group) 1032 { 1033 sa_optionset_t protopt; 1034 sa_group_t parent; 1035 char *command; 1036 char *optstring; 1037 int ret = SA_OK; 1038 int doupdate = 0; 1039 FILE *pfile; 1040 1041 if (sa_is_share(group)) 1042 parent = sa_get_parent_group(group); 1043 else 1044 parent = group; 1045 1046 if (parent != NULL) { 1047 command = malloc(ZFS_MAXPROPLEN * 2); 1048 if (command == NULL) 1049 return (SA_NO_MEMORY); 1050 1051 *command = '\0'; 1052 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL; 1053 protopt = sa_get_next_optionset(protopt)) { 1054 1055 char *proto = sa_get_optionset_attr(protopt, "type"); 1056 char *path; 1057 char *dataset = NULL; 1058 char *zfsopts = NULL; 1059 1060 if (sa_is_share(group)) { 1061 path = sa_get_share_attr((sa_share_t)group, 1062 "path"); 1063 if (path != NULL) { 1064 sa_handle_impl_t impl_handle; 1065 1066 impl_handle = sa_find_group_handle( 1067 group); 1068 if (impl_handle != NULL) 1069 dataset = get_zfs_dataset( 1070 impl_handle, path, B_FALSE); 1071 else 1072 ret = SA_SYSTEM_ERR; 1073 1074 sa_free_attr_string(path); 1075 } 1076 } else { 1077 dataset = sa_get_group_attr(group, "name"); 1078 } 1079 /* update only when there is an optstring found */ 1080 doupdate = 0; 1081 if (proto != NULL && dataset != NULL) { 1082 optstring = sa_proto_legacy_format(proto, 1083 group, 1); 1084 zfsopts = get_zfs_property(dataset, 1085 ZFS_PROP_SHARENFS); 1086 1087 if (optstring != NULL && zfsopts != NULL) { 1088 if (strcmp(optstring, zfsopts) != 0) 1089 doupdate++; 1090 } 1091 if (doupdate) { 1092 if (optstring != NULL && 1093 strlen(optstring) > 0) { 1094 (void) snprintf(command, 1095 ZFS_MAXPROPLEN * 2, 1096 "%s set sharenfs=%s %s", 1097 COMMAND, 1098 optstring, dataset); 1099 } else { 1100 (void) snprintf(command, 1101 ZFS_MAXPROPLEN * 2, 1102 "%s set sharenfs=on %s", 1103 COMMAND, 1104 dataset); 1105 } 1106 pfile = popen(command, "r"); 1107 if (pfile != NULL) 1108 ret = pclose(pfile); 1109 switch (ret) { 1110 default: 1111 case 1: 1112 ret = SA_SYSTEM_ERR; 1113 break; 1114 case 2: 1115 ret = SA_SYNTAX_ERR; 1116 break; 1117 case 0: 1118 break; 1119 } 1120 } 1121 if (optstring != NULL) 1122 free(optstring); 1123 if (zfsopts != NULL) 1124 free(zfsopts); 1125 } 1126 if (proto != NULL) 1127 sa_free_attr_string(proto); 1128 if (dataset != NULL) 1129 free(dataset); 1130 } 1131 free(command); 1132 } 1133 return (ret); 1134 } 1135 1136 /* 1137 * sa_group_is_zfs(group) 1138 * 1139 * Given the group, determine if the zfs attribute is set. 1140 */ 1141 1142 int 1143 sa_group_is_zfs(sa_group_t group) 1144 { 1145 char *zfs; 1146 int ret = 0; 1147 1148 zfs = sa_get_group_attr(group, "zfs"); 1149 if (zfs != NULL) { 1150 ret = 1; 1151 sa_free_attr_string(zfs); 1152 } 1153 return (ret); 1154 } 1155 1156 /* 1157 * sa_path_is_zfs(path) 1158 * 1159 * Check to see if the file system path represents is of type "zfs". 1160 */ 1161 1162 int 1163 sa_path_is_zfs(char *path) 1164 { 1165 char *fstype; 1166 int ret = 0; 1167 1168 fstype = sa_fstype(path); 1169 if (fstype != NULL && strcmp(fstype, "zfs") == 0) 1170 ret = 1; 1171 if (fstype != NULL) 1172 sa_free_fstype(fstype); 1173 return (ret); 1174 } 1175 1176 int 1177 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto) 1178 { 1179 char *path; 1180 1181 /* Make sure path is valid */ 1182 1183 path = sa_get_share_attr(share, "path"); 1184 if (path != NULL) { 1185 (void) memset(sh, 0, sizeof (sh)); 1186 (void) sa_fillshare(share, proto, sh); 1187 sa_free_attr_string(path); 1188 return (0); 1189 } else 1190 return (1); 1191 } 1192 1193 #define SMAX(i, j) \ 1194 if ((j) > (i)) { \ 1195 (i) = (j); \ 1196 } 1197 1198 int 1199 sa_share_zfs(sa_share_t share, char *path, share_t *sh, 1200 void *exportdata, zfs_share_op_t operation) 1201 { 1202 libzfs_handle_t *libhandle; 1203 sa_group_t group; 1204 sa_handle_t sahandle; 1205 char *dataset; 1206 int err = EINVAL; 1207 int i, j; 1208 char newpath[MAXPATHLEN]; 1209 char *pathp; 1210 1211 /* 1212 * First find the dataset name 1213 */ 1214 if ((group = sa_get_parent_group(share)) == NULL) { 1215 return (SA_SYSTEM_ERR); 1216 } 1217 if ((sahandle = sa_find_group_handle(group)) == NULL) { 1218 return (SA_SYSTEM_ERR); 1219 } 1220 1221 /* 1222 * If get_zfs_dataset fails, see if it is a subdirectory 1223 */ 1224 1225 pathp = path; 1226 while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) { 1227 char *p; 1228 1229 if (pathp == path) { 1230 (void) strlcpy(newpath, path, sizeof (newpath)); 1231 pathp = newpath; 1232 } 1233 1234 /* 1235 * chop off part of path, but if we are at root then 1236 * make sure path is a / 1237 */ 1238 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) { 1239 if (pathp == p) { 1240 *(p + 1) = '\0'; /* skip over /, root case */ 1241 } else { 1242 *p = '\0'; 1243 } 1244 } else { 1245 return (SA_SYSTEM_ERR); 1246 } 1247 } 1248 1249 libhandle = libzfs_init(); 1250 if (libhandle != NULL) { 1251 1252 i = (sh->sh_path ? strlen(sh->sh_path) : 0); 1253 sh->sh_size = i; 1254 1255 j = (sh->sh_res ? strlen(sh->sh_res) : 0); 1256 sh->sh_size += j; 1257 SMAX(i, j); 1258 1259 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0); 1260 sh->sh_size += j; 1261 SMAX(i, j); 1262 1263 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0); 1264 sh->sh_size += j; 1265 SMAX(i, j); 1266 1267 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0); 1268 sh->sh_size += j; 1269 SMAX(i, j); 1270 err = zfs_deleg_share_nfs(libhandle, dataset, path, 1271 exportdata, sh, i, operation); 1272 libzfs_fini(libhandle); 1273 } 1274 free(dataset); 1275 return (err); 1276 } 1277