1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  28  * Copyright 2017 RackTop Systems.
  29  * Copyright 2019 Nexenta Systems, Inc.
  30  */
  31 
  32 #include <stdio.h>
  33 #include <libzfs.h>
  34 #include <string.h>
  35 #include <strings.h>
  36 #include <errno.h>
  37 #include <zone.h>
  38 #include <libshare.h>
  39 #include "libshare_impl.h"
  40 #include <libintl.h>
  41 #include <sys/mnttab.h>
  42 #include <sys/mntent.h>
  43 #include <assert.h>
  44 
  45 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
  46 extern sa_group_t _sa_create_zfs_group(sa_group_t, char *);
  47 extern char *sa_fstype(char *);
  48 extern void set_node_attr(void *, char *, char *);
  49 extern int sa_is_share(void *);
  50 extern void sa_update_sharetab_ts(sa_handle_t);
  51 
  52 /*
  53  * File system specific code for ZFS. The original code was stolen
  54  * from the "zfs" command and modified to better suit this library's
  55  * usage.
  56  */
  57 
  58 typedef struct get_all_cbdata {
  59         zfs_handle_t    **cb_handles;
  60         size_t          cb_alloc;
  61         size_t          cb_used;
  62         uint_t          cb_types;
  63 } get_all_cbdata_t;
  64 
  65 /*
  66  * sa_zfs_init(impl_handle)
  67  *
  68  * Initialize an access handle into libzfs.  The handle needs to stay
  69  * around until sa_zfs_fini() in order to maintain the cache of
  70  * mounts.
  71  */
  72 
  73 int
  74 sa_zfs_init(sa_handle_impl_t impl_handle)
  75 {
  76         impl_handle->zfs_libhandle = libzfs_init();
  77         if (impl_handle->zfs_libhandle != NULL) {
  78                 libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
  79                 return (B_TRUE);
  80         }
  81         return (B_FALSE);
  82 }
  83 
  84 /*
  85  * sa_zfs_fini(impl_handle)
  86  *
  87  * cleanup data structures and the libzfs handle used for accessing
  88  * zfs file share info.
  89  */
  90 
  91 void
  92 sa_zfs_fini(sa_handle_impl_t impl_handle)
  93 {
  94         if (impl_handle->zfs_libhandle != NULL) {
  95                 if (impl_handle->zfs_list != NULL) {
  96                         zfs_handle_t **zhp = impl_handle->zfs_list;
  97                         size_t i;
  98 
  99                         /*
 100                          * Contents of zfs_list need to be freed so we
 101                          * don't lose ZFS handles.
 102                          */
 103                         for (i = 0; i < impl_handle->zfs_list_count; i++) {
 104                                 zfs_close(zhp[i]);
 105                         }
 106                         free(impl_handle->zfs_list);
 107                         impl_handle->zfs_list = NULL;
 108                         impl_handle->zfs_list_count = 0;
 109                 }
 110 
 111                 libzfs_fini(impl_handle->zfs_libhandle);
 112                 impl_handle->zfs_libhandle = NULL;
 113         }
 114 }
 115 
 116 /*
 117  * get_one_filesystem(zfs_handle_t, data)
 118  *
 119  * an iterator function called while iterating through the ZFS
 120  * root. It accumulates into an array of file system handles that can
 121  * be used to derive info about those file systems.
 122  *
 123  * Note that as this function is called, we close all zhp handles that
 124  * are not going to be places into the cp_handles list. We don't want
 125  * to close the ones we are keeping, but all others would be leaked if
 126  * not closed here.
 127  */
 128 
 129 static int
 130 get_one_filesystem(zfs_handle_t *zhp, void *data)
 131 {
 132         get_all_cbdata_t *cbp = data;
 133         zfs_type_t type = zfs_get_type(zhp);
 134 
 135         /*
 136          * Interate over any nested datasets.
 137          */
 138         if (type == ZFS_TYPE_FILESYSTEM &&
 139             zfs_iter_filesystems(zhp, get_one_filesystem, data) != 0) {
 140                 zfs_close(zhp);
 141                 return (1);
 142         }
 143 
 144         /*
 145          * Skip any datasets whose type does not match.
 146          */
 147         if ((type & cbp->cb_types) == 0) {
 148                 zfs_close(zhp);
 149                 return (0);
 150         }
 151 
 152         if (cbp->cb_alloc == cbp->cb_used) {
 153                 zfs_handle_t **handles;
 154 
 155                 if (cbp->cb_alloc == 0)
 156                         cbp->cb_alloc = 64;
 157                 else
 158                         cbp->cb_alloc *= 2;
 159 
 160                 handles = (zfs_handle_t **)calloc(1,
 161                     cbp->cb_alloc * sizeof (void *));
 162 
 163                 if (handles == NULL) {
 164                         zfs_close(zhp);
 165                         return (0);
 166                 }
 167                 if (cbp->cb_handles) {
 168                         bcopy(cbp->cb_handles, handles,
 169                             cbp->cb_used * sizeof (void *));
 170                         free(cbp->cb_handles);
 171                 }
 172 
 173                 cbp->cb_handles = handles;
 174         }
 175 
 176         cbp->cb_handles[cbp->cb_used++] = zhp;
 177 
 178         return (0);
 179 }
 180 
 181 /*
 182  * get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
 183  *
 184  * iterate through all ZFS file systems starting at the root. Returns
 185  * a count and an array of handle pointers. Allocating is only done
 186  * once. The caller does not need to free since it will be done at
 187  * sa_zfs_fini() time.
 188  */
 189 
 190 static void
 191 get_all_filesystems(sa_handle_impl_t impl_handle,
 192     zfs_handle_t ***fslist, size_t *count)
 193 {
 194         get_all_cbdata_t cb = { 0 };
 195         cb.cb_types = ZFS_TYPE_FILESYSTEM;
 196 
 197         if (impl_handle->zfs_list != NULL) {
 198                 *fslist = impl_handle->zfs_list;
 199                 *count = impl_handle->zfs_list_count;
 200                 return;
 201         }
 202 
 203         (void) zfs_iter_root(impl_handle->zfs_libhandle,
 204             get_one_filesystem, &cb);
 205 
 206         impl_handle->zfs_list = *fslist = cb.cb_handles;
 207         impl_handle->zfs_list_count = *count = cb.cb_used;
 208 }
 209 
 210 /*
 211  * mountpoint_compare(a, b)
 212  *
 213  * compares the mountpoint on two zfs file systems handles.
 214  * returns values following strcmp() model.
 215  */
 216 
 217 static int
 218 mountpoint_compare(const void *a, const void *b)
 219 {
 220         zfs_handle_t **za = (zfs_handle_t **)a;
 221         zfs_handle_t **zb = (zfs_handle_t **)b;
 222         char mounta[MAXPATHLEN];
 223         char mountb[MAXPATHLEN];
 224 
 225         verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
 226             sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
 227         verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
 228             sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
 229 
 230         return (strcmp(mounta, mountb));
 231 }
 232 
 233 /*
 234  * return legacy mountpoint.  Caller provides space for mountpoint and
 235  * dataset.
 236  */
 237 int
 238 get_legacy_mountpoint(const char *path, char *dataset, size_t dlen,
 239     char *mountpoint, size_t mlen)
 240 {
 241         FILE *fp;
 242         struct mnttab entry;
 243         int rc = 1;
 244 
 245         if ((fp = fopen(MNTTAB, "r")) == NULL) {
 246                 return (1);
 247         }
 248 
 249         while (getmntent(fp, &entry) == 0) {
 250 
 251                 if (entry.mnt_fstype == NULL ||
 252                     strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0)
 253                         continue;
 254 
 255                 if (strcmp(entry.mnt_mountp, path) == 0) {
 256                         if (mlen > 0)
 257                                 (void) strlcpy(mountpoint, entry.mnt_mountp,
 258                                     mlen);
 259                         if (dlen > 0)
 260                                 (void) strlcpy(dataset, entry.mnt_special,
 261                                     dlen);
 262                         rc = 0;
 263                         break;
 264                 }
 265         }
 266         (void) fclose(fp);
 267         return (rc);
 268 }
 269 
 270 
 271 /*
 272  * Verifies that a specific zfs filesystem handle meets the criteria necessary
 273  * to be used by libshare operations. See get_zfs_dataset.
 274  */
 275 static char *
 276 verify_zfs_handle(zfs_handle_t *hdl, const char *path, boolean_t search_mnttab)
 277 {
 278         char mountpoint[ZFS_MAXPROPLEN];
 279         char canmount[ZFS_MAXPROPLEN] = { 0 };
 280         /* must have a mountpoint */
 281         if (zfs_prop_get(hdl, ZFS_PROP_MOUNTPOINT, mountpoint,
 282             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) != 0) {
 283                 /* no mountpoint */
 284                 return (NULL);
 285         }
 286 
 287         /* mountpoint must be a path */
 288         if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
 289             strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
 290                 /*
 291                  * Search mmttab for mountpoint and get dataset.
 292                  */
 293 
 294                 if (search_mnttab == B_TRUE &&
 295                     get_legacy_mountpoint(path, mountpoint,
 296                     sizeof (mountpoint), NULL, 0) == 0) {
 297                         return (strdup(mountpoint));
 298                 }
 299                 return (NULL);
 300         }
 301 
 302         /* canmount must be set */
 303         if (zfs_prop_get(hdl, ZFS_PROP_CANMOUNT, canmount,
 304             sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
 305             strcmp(canmount, "off") == 0)
 306                 return (NULL);
 307 
 308         /*
 309          * have a mountable handle but want to skip those marked none
 310          * and legacy
 311          */
 312         if (strcmp(mountpoint, path) == 0) {
 313                 return (strdup((char *)zfs_get_name(hdl)));
 314         }
 315 
 316         return (NULL);
 317 }
 318 
 319 /*
 320  * get_zfs_dataset(impl_handle, path)
 321  *
 322  * get the name of the ZFS dataset the path is equivalent to.  The
 323  * dataset name is used for get/set of ZFS properties since libzfs
 324  * requires a dataset to do a zfs_open().
 325  */
 326 
 327 static char *
 328 get_zfs_dataset(sa_handle_impl_t impl_handle, char *path,
 329     boolean_t search_mnttab)
 330 {
 331         size_t i, count = 0;
 332         zfs_handle_t **zlist;
 333         char *cutpath;
 334         zfs_handle_t *handle_from_path;
 335         char *ret = NULL;
 336 
 337         /*
 338          * First we optimistically assume that the mount path for the filesystem
 339          * is the same as the name of the filesystem (minus some number of
 340          * leading slashes). If this is true, then zfs_open should properly open
 341          * the filesystem. We duplicate the error checking done later in the
 342          * function for consistency. If anything fails, we resort to the
 343          * (extremely slow) search of all the filesystems.
 344          */
 345         cutpath = path + strspn(path, "/");
 346 
 347         assert(impl_handle->zfs_libhandle != NULL);
 348         libzfs_print_on_error(impl_handle->zfs_libhandle, B_FALSE);
 349         handle_from_path = zfs_open(impl_handle->zfs_libhandle, cutpath,
 350             ZFS_TYPE_FILESYSTEM);
 351         libzfs_print_on_error(impl_handle->zfs_libhandle, B_TRUE);
 352         if (handle_from_path != NULL) {
 353                 ret = verify_zfs_handle(handle_from_path, path, search_mnttab);
 354                 zfs_close(handle_from_path);
 355                 if (ret != NULL) {
 356                         return (ret);
 357                 }
 358         }
 359         /*
 360          * Couldn't find a filesystem optimistically, check all the handles we
 361          * can.
 362          */
 363         get_all_filesystems(impl_handle, &zlist, &count);
 364         for (i = 0; i < count; i++) {
 365                 assert(zlist[i]);
 366                 if ((ret = verify_zfs_handle(zlist[i], path,
 367                     search_mnttab)) != NULL)
 368                         return (ret);
 369         }
 370 
 371         /* Couldn't find a matching dataset */
 372         return (NULL);
 373 }
 374 
 375 /*
 376  * get_zfs_property(dataset, property)
 377  *
 378  * Get the file system property specified from the ZFS dataset.
 379  */
 380 
 381 static char *
 382 get_zfs_property(char *dataset, zfs_prop_t property)
 383 {
 384         zfs_handle_t *handle = NULL;
 385         char shareopts[ZFS_MAXPROPLEN];
 386         libzfs_handle_t *libhandle;
 387 
 388         libhandle = libzfs_init();
 389         if (libhandle != NULL) {
 390                 handle = zfs_open(libhandle, dataset, ZFS_TYPE_FILESYSTEM);
 391                 if (handle != NULL) {
 392                         if (zfs_prop_get(handle, property, shareopts,
 393                             sizeof (shareopts), NULL, NULL, 0,
 394                             B_FALSE) == 0) {
 395                                 zfs_close(handle);
 396                                 libzfs_fini(libhandle);
 397                                 return (strdup(shareopts));
 398                         }
 399                         zfs_close(handle);
 400                 }
 401                 libzfs_fini(libhandle);
 402         }
 403         return (NULL);
 404 }
 405 
 406 /*
 407  * sa_zfs_is_shared(handle, path)
 408  *
 409  * Check to see if the ZFS path provided has the sharenfs option set
 410  * or not.
 411  */
 412 
 413 int
 414 sa_zfs_is_shared(sa_handle_t sahandle, char *path)
 415 {
 416         int ret = 0;
 417         char *dataset;
 418         zfs_handle_t *handle = NULL;
 419         char shareopts[ZFS_MAXPROPLEN];
 420         libzfs_handle_t *libhandle;
 421 
 422         dataset = get_zfs_dataset((sa_handle_t)sahandle, path, B_FALSE);
 423         if (dataset != NULL) {
 424                 libhandle = libzfs_init();
 425                 if (libhandle != NULL) {
 426                         handle = zfs_open(libhandle, dataset,
 427                             ZFS_TYPE_FILESYSTEM);
 428                         if (handle != NULL) {
 429                                 if (zfs_prop_get(handle, ZFS_PROP_SHARENFS,
 430                                     shareopts, sizeof (shareopts), NULL, NULL,
 431                                     0, B_FALSE) == 0 &&
 432                                     strcmp(shareopts, "off") != 0) {
 433                                         ret = 1; /* it is shared */
 434                                 }
 435                                 zfs_close(handle);
 436                         }
 437                         libzfs_fini(libhandle);
 438                 }
 439                 free(dataset);
 440         }
 441         return (ret);
 442 }
 443 
 444 /*
 445  * find_or_create_group(handle, groupname, proto, *err)
 446  *
 447  * While walking the ZFS tree, we need to add shares to a defined
 448  * group. If the group doesn't exist, create it first, making sure it
 449  * is marked as a ZFS group.
 450  *
 451  * Note that all ZFS shares are in a subgroup of the top level group
 452  * called "zfs".
 453  */
 454 
 455 static sa_group_t
 456 find_or_create_group(sa_handle_t handle, char *groupname, char *proto, int *err)
 457 {
 458         sa_group_t group;
 459         sa_optionset_t optionset;
 460         int ret = SA_OK;
 461 
 462         /*
 463          * we check to see if the "zfs" group exists. Since this
 464          * should be the top level group, we don't want the
 465          * parent. This is to make sure the zfs group has been created
 466          * and to created if it hasn't been.
 467          */
 468         group = sa_get_group(handle, groupname);
 469         if (group == NULL) {
 470                 group = sa_create_group(handle, groupname, &ret);
 471 
 472                 /* make sure this is flagged as a ZFS group */
 473                 if (group != NULL)
 474                         ret = sa_set_group_attr(group, "zfs", "true");
 475         }
 476         if (group != NULL) {
 477                 if (proto != NULL) {
 478                         optionset = sa_get_optionset(group, proto);
 479                         if (optionset == NULL)
 480                                 optionset = sa_create_optionset(group, proto);
 481                 }
 482         }
 483         if (err != NULL)
 484                 *err = ret;
 485         return (group);
 486 }
 487 
 488 /*
 489  * find_or_create_zfs_subgroup(groupname, optstring, *err)
 490  *
 491  * ZFS shares will be in a subgroup of the "zfs" master group.  This
 492  * function looks to see if the groupname exists and returns it if it
 493  * does or else creates a new one with the specified name and returns
 494  * that.  The "zfs" group will exist before we get here, but we make
 495  * sure just in case.
 496  *
 497  * err must be a valid pointer.
 498  */
 499 
 500 static sa_group_t
 501 find_or_create_zfs_subgroup(sa_handle_t handle, char *groupname, char *proto,
 502     char *optstring, int *err)
 503 {
 504         sa_group_t group = NULL;
 505         sa_group_t zfs;
 506         char *name;
 507         char *options;
 508 
 509         /* start with the top-level "zfs" group */
 510         zfs = sa_get_group(handle, "zfs");
 511         *err = SA_OK;
 512         if (zfs != NULL) {
 513                 for (group = sa_get_sub_group(zfs); group != NULL;
 514                     group = sa_get_next_group(group)) {
 515                         name = sa_get_group_attr(group, "name");
 516                         if (name != NULL && strcmp(name, groupname) == 0) {
 517                                 /* have the group so break out of here */
 518                                 sa_free_attr_string(name);
 519                                 break;
 520                         }
 521                         if (name != NULL)
 522                                 sa_free_attr_string(name);
 523                 }
 524 
 525                 if (group == NULL) {
 526                         /*
 527                          * Need to create the sub-group since it doesn't exist
 528                          */
 529                         group = _sa_create_zfs_group(zfs, groupname);
 530                         if (group == NULL) {
 531                                 *err = SA_NO_MEMORY;
 532                                 return (NULL);
 533                         }
 534                         set_node_attr(group, "zfs", "true");
 535                 }
 536                 if (strcmp(optstring, "on") == 0)
 537                         optstring = "rw";
 538                 options = strdup(optstring);
 539                 if (options != NULL) {
 540                         *err = sa_parse_legacy_options(group, options,
 541                             proto);
 542                         /* If no optionset, add one. */
 543                         if (sa_get_optionset(group, proto) == NULL)
 544                                 (void) sa_create_optionset(group, proto);
 545 
 546                         /*
 547                          * Do not forget to update an optionset of
 548                          * the parent group so that it contains
 549                          * all protocols its subgroups have.
 550                          */
 551                         if (sa_get_optionset(zfs, proto) == NULL)
 552                                 (void) sa_create_optionset(zfs, proto);
 553 
 554                         free(options);
 555                 } else {
 556                         *err = SA_NO_MEMORY;
 557                 }
 558         }
 559         return (group);
 560 }
 561 
 562 /*
 563  * zfs_construct_resource(share, name, base, dataset)
 564  *
 565  * Add a resource to the share using name as a template. If name ==
 566  * NULL, then construct a name based on the dataset value.
 567  * name.
 568  */
 569 static void
 570 zfs_construct_resource(sa_share_t share, char *dataset)
 571 {
 572         char buff[SA_MAX_RESOURCE_NAME + 1];
 573         int ret = SA_OK;
 574 
 575         (void) snprintf(buff, SA_MAX_RESOURCE_NAME, "%s", dataset);
 576         sa_fix_resource_name(buff);
 577         (void) sa_add_resource(share, buff, SA_SHARE_TRANSIENT, &ret);
 578 }
 579 
 580 /*
 581  * zfs_inherited(handle, source, sourcestr)
 582  *
 583  * handle case of inherited share{nfs,smb}. Pulled out of sa_get_zfs_shares
 584  * for readability.
 585  */
 586 static int
 587 zfs_inherited(sa_handle_t handle, sa_share_t share, char *sourcestr,
 588     char *shareopts, char *mountpoint, char *proto, char *dataset)
 589 {
 590         int doshopt = 0;
 591         int err = SA_OK;
 592         sa_group_t group;
 593         sa_resource_t resource;
 594         uint64_t features;
 595 
 596         /*
 597          * Need to find the "real" parent sub-group. It may not be
 598          * mounted, but it was identified in the "sourcestr"
 599          * variable. The real parent not mounted can occur if
 600          * "canmount=off and sharenfs=on".
 601          */
 602         group = find_or_create_zfs_subgroup(handle, sourcestr, proto,
 603             shareopts, &doshopt);
 604         if (group != NULL) {
 605                 /*
 606                  * We may need the first share for resource
 607                  * prototype. We only care about it if it has a
 608                  * resource that sets a prefix value.
 609                  */
 610                 if (share == NULL)
 611                         share = _sa_add_share(group, mountpoint,
 612                             SA_SHARE_TRANSIENT, &err,
 613                             (uint64_t)SA_FEATURE_NONE);
 614                 /*
 615                  * some options may only be on shares. If the opt
 616                  * string contains one of those, we put it just on the
 617                  * share.
 618                  */
 619                 if (share != NULL && doshopt == SA_PROP_SHARE_ONLY) {
 620                         char *options;
 621                         options = strdup(shareopts);
 622                         if (options != NULL) {
 623                                 set_node_attr(share, "dataset", dataset);
 624                                 err = sa_parse_legacy_options(share, options,
 625                                     proto);
 626                                 set_node_attr(share, "dataset", NULL);
 627                                 free(options);
 628                         }
 629                         if (sa_get_optionset(group, proto) == NULL)
 630                                 (void) sa_create_optionset(group, proto);
 631                 }
 632                 features = sa_proto_get_featureset(proto);
 633                 if (share != NULL && features & SA_FEATURE_RESOURCE) {
 634                         /*
 635                          * We have a share and the protocol requires
 636                          * that at least one resource exist (probably
 637                          * SMB). We need to make sure that there is at
 638                          * least one.
 639                          */
 640                         resource = sa_get_share_resource(share, NULL);
 641                         if (resource == NULL) {
 642                                 zfs_construct_resource(share, dataset);
 643                         }
 644                 }
 645         } else {
 646                 err = SA_NO_MEMORY;
 647         }
 648         return (err);
 649 }
 650 
 651 /*
 652  * zfs_notinherited(group, share, mountpoint, shareopts, proto, dataset,
 653  *     grouperr)
 654  *
 655  * handle case where this is the top of a sub-group in ZFS. Pulled out
 656  * of sa_get_zfs_shares for readability. We need the grouperr from the
 657  * creation of the subgroup to know whether to add the public
 658  * property, etc. to the specific share.
 659  */
 660 static int
 661 zfs_notinherited(sa_group_t group, sa_share_t share, char *mountpoint,
 662     char *shareopts, char *proto, char *dataset, int grouperr)
 663 {
 664         int err = SA_OK;
 665         sa_resource_t resource;
 666         uint64_t features;
 667 
 668         set_node_attr(group, "zfs", "true");
 669         if (share == NULL)
 670                 share = _sa_add_share(group, mountpoint, SA_SHARE_TRANSIENT,
 671                     &err, (uint64_t)SA_FEATURE_NONE);
 672 
 673         if (err != SA_OK)
 674                 return (err);
 675 
 676         if (strcmp(shareopts, "on") == 0)
 677                 shareopts = "";
 678         if (shareopts != NULL) {
 679                 char *options;
 680                 if (grouperr == SA_PROP_SHARE_ONLY) {
 681                         /*
 682                          * Some properties may only be on shares, but
 683                          * due to the ZFS sub-groups being artificial,
 684                          * we sometimes get this and have to deal with
 685                          * it. We do it by attempting to put it on the
 686                          * share.
 687                          */
 688                         options = strdup(shareopts);
 689                         if (options != NULL) {
 690                                 err = sa_parse_legacy_options(share,
 691                                     options, proto);
 692                                 free(options);
 693                         }
 694                 }
 695                 /* Unmark the share's changed state */
 696                 set_node_attr(share, "changed", NULL);
 697         }
 698         features = sa_proto_get_featureset(proto);
 699         if (share != NULL && features & SA_FEATURE_RESOURCE) {
 700                 /*
 701                  * We have a share and the protocol requires that at
 702                  * least one resource exist (probably SMB). We need to
 703                  * make sure that there is at least one.
 704                  */
 705                 resource = sa_get_share_resource(share, NULL);
 706                 if (resource == NULL) {
 707                         zfs_construct_resource(share, dataset);
 708                 }
 709         }
 710         return (err);
 711 }
 712 
 713 /*
 714  * zfs_grp_error(err)
 715  *
 716  * Print group create error, but only once. If err is 0 do the
 717  * print else don't.
 718  */
 719 
 720 static void
 721 zfs_grp_error(int err)
 722 {
 723         if (err == 0) {
 724                 /* only print error once */
 725                 (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
 726                     "Cannot create ZFS subgroup during initialization:"
 727                     " %s\n"), sa_errorstr(SA_SYSTEM_ERR));
 728         }
 729 }
 730 
 731 /*
 732  * zfs_process_share(handle, share, mountpoint, proto, source,
 733  *     shareopts, sourcestr)
 734  *
 735  * Creates the subgroup, if necessary and adds shares, resources
 736  * and properties.
 737  */
 738 int
 739 sa_zfs_process_share(sa_handle_t handle, sa_group_t group, sa_share_t share,
 740     char *mountpoint, char *proto, zprop_source_t source, char *shareopts,
 741     char *sourcestr, char *dataset)
 742 {
 743         int err = SA_OK;
 744 
 745         if (source & ZPROP_SRC_INHERITED) {
 746                 err = zfs_inherited(handle, share, sourcestr, shareopts,
 747                     mountpoint, proto, dataset);
 748         } else {
 749                 group = find_or_create_zfs_subgroup(handle, dataset, proto,
 750                     shareopts, &err);
 751                 if (group == NULL) {
 752                         static boolean_t reported_error = B_FALSE;
 753                         /*
 754                          * There is a problem, but we can't do
 755                          * anything about it at this point so we issue
 756                          * a warning and move on.
 757                          */
 758                         zfs_grp_error(reported_error);
 759                         reported_error = B_TRUE;
 760                 }
 761                 set_node_attr(group, "zfs", "true");
 762                 /*
 763                  * Add share with local opts via zfs_notinherited.
 764                  */
 765                 err = zfs_notinherited(group, share, mountpoint, shareopts,
 766                     proto, dataset, err);
 767         }
 768         return (err);
 769 }
 770 
 771 /*
 772  * Walk the mnttab for all zfs mounts and determine which are
 773  * shared. Find or create the appropriate group/sub-group to contain
 774  * the shares.
 775  *
 776  * All shares are in a sub-group that will hold the properties. This
 777  * allows representing the inherited property model.
 778  *
 779  * One area of complication is if "sharenfs" is set at one level of
 780  * the directory tree and "sharesmb" is set at a different level, the
 781  * a sub-group must be formed at the lower level for both
 782  * protocols. That is the nature of the problem in CR 6667349.
 783  */
 784 static int
 785 sa_get_zfs_share_common(sa_handle_t handle, zfs_handle_t *fs_handle, char *path,
 786     sa_group_t zfsgroup)
 787 {
 788         boolean_t smb, nfs;
 789         boolean_t smb_inherited, nfs_inherited;
 790         char nfsshareopts[ZFS_MAXPROPLEN];
 791         char smbshareopts[ZFS_MAXPROPLEN];
 792         char nfssourcestr[ZFS_MAXPROPLEN];
 793         char smbsourcestr[ZFS_MAXPROPLEN];
 794         char mountpoint[ZFS_MAXPROPLEN];
 795         int err = SA_OK;
 796         zprop_source_t source;
 797         sa_share_t share;
 798         char *dataset;
 799 
 800         source = ZPROP_SRC_ALL;
 801         /* If no mountpoint, skip. */
 802         if (zfs_prop_get(fs_handle, ZFS_PROP_MOUNTPOINT,
 803             mountpoint, sizeof (mountpoint), NULL, NULL, 0,
 804             B_FALSE) != 0)
 805                 return (SA_SYSTEM_ERR);
 806 
 807         if (path != NULL)
 808                 (void) strncpy(path, mountpoint, sizeof (mountpoint));
 809         /*
 810          * zfs_get_name value must not be freed. It is just a
 811          * pointer to a value in the handle.
 812          */
 813         if ((dataset = (char *)zfs_get_name(fs_handle)) == NULL)
 814                 return (SA_SYSTEM_ERR);
 815 
 816         /*
 817          * only deal with "mounted" file systems since
 818          * unmounted file systems can't actually be shared.
 819          */
 820 
 821         if (!zfs_is_mounted(fs_handle, NULL))
 822                 return (SA_SYSTEM_ERR);
 823 
 824         /*
 825          * Ignore "zoned" datasets in global zone.
 826          */
 827         if (getzoneid() == GLOBAL_ZONEID &&
 828             zfs_prop_get_int(fs_handle, ZFS_PROP_ZONED))
 829                 return (SA_SYSTEM_ERR);
 830 
 831         nfs = nfs_inherited = B_FALSE;
 832 
 833         if (zfs_prop_get(fs_handle, ZFS_PROP_SHARENFS, nfsshareopts,
 834             sizeof (nfsshareopts), &source, nfssourcestr,
 835             ZFS_MAXPROPLEN, B_FALSE) == 0 &&
 836             strcmp(nfsshareopts, "off") != 0) {
 837                 if (source & ZPROP_SRC_INHERITED)
 838                         nfs_inherited = B_TRUE;
 839                 else
 840                         nfs = B_TRUE;
 841         }
 842 
 843         smb = smb_inherited = B_FALSE;
 844         if (zfs_prop_get(fs_handle, ZFS_PROP_SHARESMB, smbshareopts,
 845             sizeof (smbshareopts), &source, smbsourcestr,
 846             ZFS_MAXPROPLEN, B_FALSE) == 0 &&
 847             strcmp(smbshareopts, "off") != 0) {
 848                 if (source & ZPROP_SRC_INHERITED)
 849                         smb_inherited = B_TRUE;
 850                 else
 851                         smb = B_TRUE;
 852         }
 853 
 854         /*
 855          * If the mountpoint is already shared, it must be a
 856          * non-ZFS share. We want to remove the share from its
 857          * parent group and reshare it under ZFS.
 858          */
 859         share = sa_find_share(handle, mountpoint);
 860         if (share != NULL &&
 861             (nfs || smb || nfs_inherited || smb_inherited)) {
 862                 err = sa_remove_share(share);
 863                 share = NULL;
 864         }
 865 
 866         /*
 867          * At this point, we have the information needed to
 868          * determine what to do with the share.
 869          *
 870          * If smb or nfs is set, we have a new sub-group.
 871          * If smb_inherit and/or nfs_inherit is set, then
 872          * place on an existing sub-group. If both are set,
 873          * the existing sub-group is the closest up the tree.
 874          */
 875         if (nfs || smb) {
 876                 /*
 877                  * Non-inherited is the straightforward
 878                  * case. sa_zfs_process_share handles it
 879                  * directly. Make sure that if the "other"
 880                  * protocol is inherited, that we treat it as
 881                  * non-inherited as well.
 882                  */
 883                 if (nfs || nfs_inherited) {
 884                         err = sa_zfs_process_share(handle, zfsgroup,
 885                             share, mountpoint, "nfs",
 886                             0, nfsshareopts,
 887                             nfssourcestr, dataset);
 888                         share = sa_find_share(handle, mountpoint);
 889                 }
 890                 if (smb || smb_inherited) {
 891                         err = sa_zfs_process_share(handle, zfsgroup,
 892                             share, mountpoint, "smb",
 893                             0, smbshareopts,
 894                             smbsourcestr, dataset);
 895                 }
 896         } else if (nfs_inherited || smb_inherited) {
 897                 char *grpdataset;
 898                 /*
 899                  * If we only have inherited groups, it is
 900                  * important to find the closer of the two if
 901                  * the protocols are set at different
 902                  * levels. The closest sub-group is the one we
 903                  * want to work with.
 904                  */
 905                 if (nfs_inherited && smb_inherited) {
 906                         if (strcmp(nfssourcestr, smbsourcestr) <= 0)
 907                                 grpdataset = nfssourcestr;
 908                         else
 909                                 grpdataset = smbsourcestr;
 910                 } else if (nfs_inherited) {
 911                         grpdataset = nfssourcestr;
 912                 } else if (smb_inherited) {
 913                         grpdataset = smbsourcestr;
 914                 }
 915                 if (nfs_inherited) {
 916                         err = sa_zfs_process_share(handle, zfsgroup,
 917                             share, mountpoint, "nfs",
 918                             ZPROP_SRC_INHERITED, nfsshareopts,
 919                             grpdataset, dataset);
 920                         share = sa_find_share(handle, mountpoint);
 921                 }
 922                 if (smb_inherited) {
 923                         err = sa_zfs_process_share(handle, zfsgroup,
 924                             share, mountpoint, "smb",
 925                             ZPROP_SRC_INHERITED, smbshareopts,
 926                             grpdataset, dataset);
 927                 }
 928         }
 929         return (err);
 930 }
 931 
 932 /*
 933  * Handles preparing generic objects such as the libzfs handle and group for
 934  * sa_get_one_zfs_share, sa_get_zfs_share_for_name, and sa_get_zfs_shares.
 935  */
 936 static int
 937 prep_zfs_handle_and_group(sa_handle_t handle, char *groupname,
 938     libzfs_handle_t **zfs_libhandle, sa_group_t *zfsgroup, int *err)
 939 {
 940         /*
 941          * If we can't access libzfs, don't bother doing anything.
 942          */
 943         *zfs_libhandle = ((sa_handle_impl_t)handle)->zfs_libhandle;
 944         if (*zfs_libhandle == NULL)
 945                 return (SA_SYSTEM_ERR);
 946 
 947         *zfsgroup = find_or_create_group(handle, groupname, NULL, err);
 948         return (SA_OK);
 949 }
 950 
 951 /*
 952  * The O.G. zfs share preparation function. This initializes all zfs shares for
 953  * use with libshare.
 954  */
 955 int
 956 sa_get_zfs_shares(sa_handle_t handle, char *groupname)
 957 {
 958         sa_group_t zfsgroup;
 959         zfs_handle_t **zlist;
 960         size_t count = 0;
 961         libzfs_handle_t *zfs_libhandle;
 962         int err;
 963 
 964         if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
 965             &zfsgroup, &err)) != SA_OK) {
 966                 return (err);
 967         }
 968         /* Not an error, this could be a legacy condition */
 969         if (zfsgroup == NULL)
 970                 return (SA_OK);
 971 
 972         /*
 973          * need to walk the mounted ZFS pools and datasets to
 974          * find shares that are possible.
 975          */
 976         get_all_filesystems((sa_handle_impl_t)handle, &zlist, &count);
 977         qsort(zlist, count, sizeof (void *), mountpoint_compare);
 978 
 979         for (int i = 0; i < count; i++) {
 980                 err = sa_get_zfs_share_common(handle, zlist[i], NULL, zfsgroup);
 981         }
 982         /*
 983          * Don't need to free the "zlist" variable since it is only a
 984          * pointer to a cached value that will be freed when
 985          * sa_fini() is called.
 986          */
 987         return (err);
 988 }
 989 
 990 /*
 991  * Initializes shares for only the dataset specified fs_handle.
 992  * This is used as a performance optimization relative to sa_get_zfs_shares.
 993  */
 994 int
 995 sa_get_zfs_share(sa_handle_t handle, char *groupname, zfs_handle_t *fs_handle)
 996 {
 997         sa_group_t zfsgroup;
 998         libzfs_handle_t *zfs_libhandle;
 999         int err;
1000 
1001         if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
1002             &zfsgroup, &err)) != SA_OK) {
1003                 return (err);
1004         }
1005         /* Not an error, this could be a legacy condition */
1006         if (zfsgroup == NULL)
1007                 return (SA_OK);
1008 
1009         err = sa_get_zfs_share_common(handle, fs_handle, NULL, zfsgroup);
1010         return (err);
1011 }
1012 
1013 /*
1014  * Initializes only the handles specified in the sharearg for use with libshare.
1015  * This is used as a performance optimization relative to sa_get_zfs_shares.
1016  */
1017 int
1018 sa_get_one_zfs_share(sa_handle_t handle, char *groupname,
1019     sa_init_selective_arg_t *sharearg, char ***paths, size_t *paths_len)
1020 {
1021         sa_group_t zfsgroup;
1022         libzfs_handle_t *zfs_libhandle;
1023         int err;
1024 
1025         if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
1026             &zfsgroup, &err)) != SA_OK) {
1027                 return (err);
1028         }
1029         /* Not an error, this could be a legacy condition */
1030         if (zfsgroup == NULL)
1031                 return (SA_OK);
1032 
1033         *paths_len = sharearg->zhandle_len;
1034         *paths = calloc(*paths_len, sizeof (char *));
1035         for (int i = 0; i < sharearg->zhandle_len; ++i) {
1036                 zfs_handle_t *fs_handle =
1037                     ((zfs_handle_t **)(sharearg->zhandle_arr))[i];
1038                 if (fs_handle == NULL) {
1039                         /* Free non-null elements of the paths array */
1040                         for (int free_idx = 0; free_idx < *paths_len;
1041                             ++free_idx) {
1042                                 if ((*paths)[free_idx] != NULL)
1043                                         free((*paths)[free_idx]);
1044                         }
1045                         free(*paths);
1046                         *paths = NULL;
1047                         *paths_len = 0;
1048                         return (SA_SYSTEM_ERR);
1049                 }
1050                 (*paths)[i] = malloc(sizeof (char) * ZFS_MAXPROPLEN);
1051                 err |= sa_get_zfs_share_common(handle, fs_handle, (*paths)[i],
1052                     zfsgroup);
1053         }
1054 
1055         return (err);
1056 }
1057 
1058 /*
1059  * Initializes only the share with the specified sharename for use with
1060  * libshare.
1061  */
1062 int
1063 sa_get_zfs_share_for_name(sa_handle_t handle, char *groupname,
1064     const char *sharename, char *outpath)
1065 {
1066         sa_group_t zfsgroup;
1067         libzfs_handle_t *zfs_libhandle;
1068         int err;
1069 
1070         if ((err = prep_zfs_handle_and_group(handle, groupname, &zfs_libhandle,
1071             &zfsgroup, &err)) != SA_OK) {
1072                 return (err);
1073         }
1074         /* Not an error, this could be a legacy condition */
1075         if (zfsgroup == NULL)
1076                 return (SA_OK);
1077 
1078         zfs_handle_t *fs_handle = zfs_open(zfs_libhandle,
1079             sharename + strspn(sharename, "/"), ZFS_TYPE_DATASET);
1080         if (fs_handle == NULL)
1081                 return (SA_SYSTEM_ERR);
1082 
1083         err = sa_get_zfs_share_common(handle, fs_handle, outpath, zfsgroup);
1084         zfs_close(fs_handle);
1085         return (err);
1086 }
1087 
1088 
1089 
1090 #define COMMAND         "/usr/sbin/zfs"
1091 
1092 /*
1093  * sa_zfs_set_sharenfs(group, path, on)
1094  *
1095  * Update the "sharenfs" property on the path. If on is true, then set
1096  * to the properties on the group or "on" if no properties are
1097  * defined. Set to "off" if on is false.
1098  */
1099 
1100 int
1101 sa_zfs_set_sharenfs(sa_group_t group, char *path, int on)
1102 {
1103         int ret = SA_NOT_IMPLEMENTED;
1104         char *command;
1105 
1106         command = malloc(ZFS_MAXPROPLEN * 2);
1107         if (command != NULL) {
1108                 char *opts = NULL;
1109                 char *dataset = NULL;
1110                 FILE *pfile;
1111                 sa_handle_impl_t impl_handle;
1112                 /* for now, NFS is always available for "zfs" */
1113                 if (on) {
1114                         opts = sa_proto_legacy_format("nfs", group, 1);
1115                         if (opts != NULL && strlen(opts) == 0) {
1116                                 free(opts);
1117                                 opts = strdup("on");
1118                         }
1119                 }
1120 
1121                 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1122                 assert(impl_handle != NULL);
1123                 if (impl_handle != NULL)
1124                         dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
1125                 else
1126                         ret = SA_SYSTEM_ERR;
1127 
1128                 if (dataset != NULL) {
1129                         (void) snprintf(command, ZFS_MAXPROPLEN * 2,
1130                             "%s set sharenfs=\"%s\" %s", COMMAND,
1131                             opts != NULL ? opts : "off", dataset);
1132                         pfile = popen(command, "r");
1133                         if (pfile != NULL) {
1134                                 ret = pclose(pfile);
1135                                 if (ret != 0)
1136                                         ret = SA_SYSTEM_ERR;
1137                         }
1138                 }
1139                 if (opts != NULL)
1140                         free(opts);
1141                 if (dataset != NULL)
1142                         free(dataset);
1143                 free(command);
1144         }
1145         return (ret);
1146 }
1147 
1148 /*
1149  * add_resources(share, opt)
1150  *
1151  * Add resource properties to those in "opt".  Resources are prefixed
1152  * with name=resourcename.
1153  */
1154 static char *
1155 add_resources(sa_share_t share, char *opt)
1156 {
1157         char *newopt = NULL;
1158         char *propstr;
1159         sa_resource_t resource;
1160 
1161         newopt = strdup(opt);
1162         if (newopt == NULL)
1163                 return (newopt);
1164 
1165         for (resource = sa_get_share_resource(share, NULL);
1166             resource != NULL;
1167             resource = sa_get_next_resource(resource)) {
1168                 char *name;
1169                 size_t size;
1170 
1171                 name = sa_get_resource_attr(resource, "name");
1172                 if (name == NULL) {
1173                         free(newopt);
1174                         return (NULL);
1175                 }
1176                 size = strlen(name) + strlen(opt) + sizeof ("name=") + 1;
1177                 newopt = calloc(1, size);
1178                 if (newopt != NULL)
1179                         (void) snprintf(newopt, size, "%s,name=%s", opt, name);
1180                 sa_free_attr_string(name);
1181                 free(opt);
1182                 opt = newopt;
1183                 propstr = sa_proto_legacy_format("smb", resource, 0);
1184                 if (propstr == NULL) {
1185                         free(opt);
1186                         return (NULL);
1187                 }
1188                 size = strlen(propstr) + strlen(opt) + 2;
1189                 newopt = calloc(1, size);
1190                 if (newopt != NULL)
1191                         (void) snprintf(newopt, size, "%s,%s", opt, propstr);
1192                 free(opt);
1193                 opt = newopt;
1194         }
1195         return (opt);
1196 }
1197 
1198 /*
1199  * sa_zfs_set_sharesmb(group, path, on)
1200  *
1201  * Update the "sharesmb" property on the path. If on is true, then set
1202  * to the properties on the group or "on" if no properties are
1203  * defined. Set to "off" if on is false.
1204  */
1205 
1206 int
1207 sa_zfs_set_sharesmb(sa_group_t group, char *path, int on)
1208 {
1209         int ret = SA_NOT_IMPLEMENTED;
1210         char *command;
1211         sa_share_t share;
1212 
1213         /* In case SMB not enabled */
1214         if (sa_get_optionset(group, "smb") == NULL)
1215                 return (SA_NOT_SUPPORTED);
1216 
1217         command = malloc(ZFS_MAXPROPLEN * 2);
1218         if (command != NULL) {
1219                 char *opts = NULL;
1220                 char *dataset = NULL;
1221                 FILE *pfile;
1222                 sa_handle_impl_t impl_handle;
1223 
1224                 if (on) {
1225                         char *newopt;
1226 
1227                         share = sa_get_share(group, NULL);
1228                         opts = sa_proto_legacy_format("smb", share, 1);
1229                         if (opts != NULL && strlen(opts) == 0) {
1230                                 free(opts);
1231                                 opts = strdup("on");
1232                         }
1233                         newopt = add_resources(opts, share);
1234                         free(opts);
1235                         opts = newopt;
1236                 }
1237 
1238                 impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
1239                 assert(impl_handle != NULL);
1240                 if (impl_handle != NULL)
1241                         dataset = get_zfs_dataset(impl_handle, path, B_FALSE);
1242                 else
1243                         ret = SA_SYSTEM_ERR;
1244 
1245                 if (dataset != NULL) {
1246                         (void) snprintf(command, ZFS_MAXPROPLEN * 2,
1247                             "echo %s set sharesmb=\"%s\" %s", COMMAND,
1248                             opts != NULL ? opts : "off", dataset);
1249                         pfile = popen(command, "r");
1250                         if (pfile != NULL) {
1251                                 ret = pclose(pfile);
1252                                 if (ret != 0)
1253                                         ret = SA_SYSTEM_ERR;
1254                         }
1255                 }
1256                 if (opts != NULL)
1257                         free(opts);
1258                 if (dataset != NULL)
1259                         free(dataset);
1260                 free(command);
1261         }
1262         return (ret);
1263 }
1264 
1265 /*
1266  * sa_zfs_update(group)
1267  *
1268  * call back to ZFS to update the share if necessary.
1269  * Don't do it if it isn't a real change.
1270  */
1271 int
1272 sa_zfs_update(sa_group_t group)
1273 {
1274         sa_optionset_t protopt;
1275         sa_group_t parent;
1276         char *command;
1277         char *optstring;
1278         int ret = SA_OK;
1279         int doupdate = 0;
1280         FILE *pfile;
1281 
1282         if (sa_is_share(group))
1283                 parent = sa_get_parent_group(group);
1284         else
1285                 parent = group;
1286 
1287         if (parent != NULL) {
1288                 command = malloc(ZFS_MAXPROPLEN * 2);
1289                 if (command == NULL)
1290                         return (SA_NO_MEMORY);
1291 
1292                 *command = '\0';
1293                 for (protopt = sa_get_optionset(parent, NULL); protopt != NULL;
1294                     protopt = sa_get_next_optionset(protopt)) {
1295 
1296                         char *proto = sa_get_optionset_attr(protopt, "type");
1297                         char *path;
1298                         char *dataset = NULL;
1299                         char *zfsopts = NULL;
1300 
1301                         if (sa_is_share(group)) {
1302                                 path = sa_get_share_attr((sa_share_t)group,
1303                                     "path");
1304                                 if (path != NULL) {
1305                                         sa_handle_impl_t impl_handle;
1306 
1307                                         impl_handle = sa_find_group_handle(
1308                                             group);
1309                                         if (impl_handle != NULL)
1310                                                 dataset = get_zfs_dataset(
1311                                                     impl_handle, path, B_FALSE);
1312                                         else
1313                                                 ret = SA_SYSTEM_ERR;
1314 
1315                                         sa_free_attr_string(path);
1316                                 }
1317                         } else {
1318                                 dataset = sa_get_group_attr(group, "name");
1319                         }
1320                         /* update only when there is an optstring found */
1321                         doupdate = 0;
1322                         if (proto != NULL && dataset != NULL) {
1323                                 optstring = sa_proto_legacy_format(proto,
1324                                     group, 1);
1325                                 zfsopts = get_zfs_property(dataset,
1326                                     ZFS_PROP_SHARENFS);
1327 
1328                                 if (optstring != NULL && zfsopts != NULL) {
1329                                         if (strcmp(optstring, zfsopts) != 0)
1330                                                 doupdate++;
1331                                 }
1332                                 if (doupdate) {
1333                                         if (optstring != NULL &&
1334                                             strlen(optstring) > 0) {
1335                                                 (void) snprintf(command,
1336                                                     ZFS_MAXPROPLEN * 2,
1337                                                     "%s set share%s=%s %s",
1338                                                     COMMAND, proto,
1339                                                     optstring, dataset);
1340                                         } else {
1341                                                 (void) snprintf(command,
1342                                                     ZFS_MAXPROPLEN * 2,
1343                                                     "%s set share%s=on %s",
1344                                                     COMMAND, proto,
1345                                                     dataset);
1346                                         }
1347                                         pfile = popen(command, "r");
1348                                         if (pfile != NULL)
1349                                                 ret = pclose(pfile);
1350                                         switch (ret) {
1351                                         default:
1352                                         case 1:
1353                                                 ret = SA_SYSTEM_ERR;
1354                                                 break;
1355                                         case 2:
1356                                                 ret = SA_SYNTAX_ERR;
1357                                                 break;
1358                                         case 0:
1359                                                 break;
1360                                         }
1361                                 }
1362                                 if (optstring != NULL)
1363                                         free(optstring);
1364                                 if (zfsopts != NULL)
1365                                         free(zfsopts);
1366                         }
1367                         if (proto != NULL)
1368                                 sa_free_attr_string(proto);
1369                         if (dataset != NULL)
1370                                 free(dataset);
1371                 }
1372                 free(command);
1373         }
1374         return (ret);
1375 }
1376 
1377 /*
1378  * sa_group_is_zfs(group)
1379  *
1380  * Given the group, determine if the zfs attribute is set.
1381  */
1382 
1383 int
1384 sa_group_is_zfs(sa_group_t group)
1385 {
1386         char *zfs;
1387         int ret = 0;
1388 
1389         zfs = sa_get_group_attr(group, "zfs");
1390         if (zfs != NULL) {
1391                 ret = 1;
1392                 sa_free_attr_string(zfs);
1393         }
1394         return (ret);
1395 }
1396 
1397 /*
1398  * sa_path_is_zfs(path)
1399  *
1400  * Check to see if the file system path represents is of type "zfs".
1401  */
1402 
1403 int
1404 sa_path_is_zfs(char *path)
1405 {
1406         char *fstype;
1407         int ret = 0;
1408 
1409         fstype = sa_fstype(path);
1410         if (fstype != NULL && strcmp(fstype, "zfs") == 0)
1411                 ret = 1;
1412         if (fstype != NULL)
1413                 sa_free_fstype(fstype);
1414         return (ret);
1415 }
1416 
1417 int
1418 sa_sharetab_fill_zfs(sa_share_t share, share_t *sh, char *proto)
1419 {
1420         char *path;
1421 
1422         /* Make sure path is valid */
1423 
1424         path = sa_get_share_attr(share, "path");
1425         if (path != NULL) {
1426                 (void) memset(sh, 0, sizeof (sh));
1427                 (void) sa_fillshare(share, proto, sh);
1428                 sa_free_attr_string(path);
1429                 return (0);
1430         } else
1431                 return (1);
1432 }
1433 
1434 #define SMAX(i, j)      \
1435         if ((j) > (i)) { \
1436                 (i) = (j); \
1437         }
1438 
1439 int
1440 sa_share_zfs(sa_share_t share, sa_resource_t resource, char *path, share_t *sh,
1441     void *exportdata, zfs_share_op_t operation)
1442 {
1443         libzfs_handle_t *libhandle;
1444         sa_group_t group;
1445         sa_handle_t sahandle;
1446         char *dataset;
1447         int err = EINVAL;
1448         int i, j;
1449         char newpath[MAXPATHLEN];
1450         char *pathp;
1451 
1452         /*
1453          * First find the dataset name
1454          */
1455         if ((group = sa_get_parent_group(share)) == NULL)  {
1456                 return (EINVAL);
1457         }
1458         if ((sahandle = sa_find_group_handle(group)) == NULL) {
1459                 return (EINVAL);
1460         }
1461 
1462         /*
1463          * If get_zfs_dataset fails, see if it is a subdirectory
1464          */
1465 
1466         pathp = path;
1467         while ((dataset = get_zfs_dataset(sahandle, pathp, B_TRUE)) == NULL) {
1468                 char *p;
1469 
1470                 if (pathp == path) {
1471                         (void) strlcpy(newpath, path, sizeof (newpath));
1472                         pathp = newpath;
1473                 }
1474 
1475                 /*
1476                  * Make sure only one leading '/' This condition came
1477                  * about when using HAStoragePlus which insisted on
1478                  * putting an extra leading '/' in the ZFS path
1479                  * name. The problem is fixed in other areas, but this
1480                  * will catch any other ways that a double slash might
1481                  * get introduced.
1482                  */
1483                 while (*pathp == '/' && *(pathp + 1) == '/')
1484                         pathp++;
1485 
1486                 /*
1487                  * chop off part of path, but if we are at root then
1488                  * make sure path is a /
1489                  */
1490                 if ((strlen(pathp) > 1) && (p = strrchr(pathp, '/'))) {
1491                         if (pathp == p) {
1492                                 *(p + 1) = '\0';  /* skip over /, root case */
1493                         } else {
1494                                 *p = '\0';
1495                         }
1496                 } else {
1497                         return (EINVAL);
1498                 }
1499         }
1500 
1501         libhandle = libzfs_init();
1502         if (libhandle != NULL) {
1503                 char *resource_name;
1504 
1505                 i = (sh->sh_path ? strlen(sh->sh_path) : 0);
1506                 sh->sh_size = i;
1507 
1508                 j = (sh->sh_res ? strlen(sh->sh_res) : 0);
1509                 sh->sh_size += j;
1510                 SMAX(i, j);
1511 
1512                 j = (sh->sh_fstype ? strlen(sh->sh_fstype) : 0);
1513                 sh->sh_size += j;
1514                 SMAX(i, j);
1515 
1516                 j = (sh->sh_opts ? strlen(sh->sh_opts) : 0);
1517                 sh->sh_size += j;
1518                 SMAX(i, j);
1519 
1520                 j = (sh->sh_descr ? strlen(sh->sh_descr) : 0);
1521                 sh->sh_size += j;
1522                 SMAX(i, j);
1523 
1524                 resource_name = sa_get_resource_attr(resource, "name");
1525 
1526                 err = zfs_deleg_share_nfs(libhandle, dataset, path,
1527                     resource_name, exportdata, sh, i, operation);
1528                 if (err == SA_OK)
1529                         sa_update_sharetab_ts(sahandle);
1530                 else
1531                         err = errno;
1532                 if (resource_name)
1533                         sa_free_attr_string(resource_name);
1534 
1535                 libzfs_fini(libhandle);
1536         }
1537         free(dataset);
1538         return (err);
1539 }
1540 
1541 /*
1542  * sa_get_zfs_handle(handle)
1543  *
1544  * Given an sa_handle_t, return the libzfs_handle_t *. This is only
1545  * used internally by libzfs. Needed in order to avoid including
1546  * libshare_impl.h in libzfs.
1547  */
1548 
1549 libzfs_handle_t *
1550 sa_get_zfs_handle(sa_handle_t handle)
1551 {
1552         sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
1553 
1554         return (implhandle->zfs_libhandle);
1555 }
1556 
1557 /*
1558  * sa_get_zfs_info(libzfs, path, mountpoint, dataset)
1559  *
1560  * Find the ZFS dataset and mountpoint for a given path
1561  */
1562 int
1563 sa_zfs_get_info(libzfs_handle_t *libzfs, char *path, char *mountpointp,
1564     char *datasetp)
1565 {
1566         get_all_cbdata_t cb = { 0 };
1567         int i;
1568         char mountpoint[ZFS_MAXPROPLEN];
1569         char dataset[ZFS_MAXPROPLEN];
1570         char canmount[ZFS_MAXPROPLEN];
1571         char *dp;
1572         int count;
1573         int ret = 0;
1574 
1575         cb.cb_types = ZFS_TYPE_FILESYSTEM;
1576 
1577         if (libzfs == NULL)
1578                 return (0);
1579 
1580         (void) zfs_iter_root(libzfs, get_one_filesystem, &cb);
1581         count = cb.cb_used;
1582 
1583         qsort(cb.cb_handles, count, sizeof (void *), mountpoint_compare);
1584         for (i = 0; i < count; i++) {
1585                 /* must have a mountpoint */
1586                 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_MOUNTPOINT,
1587                     mountpoint, sizeof (mountpoint),
1588                     NULL, NULL, 0, B_FALSE) != 0) {
1589                         /* no mountpoint */
1590                         continue;
1591                 }
1592 
1593                 /* mountpoint must be a path */
1594                 if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
1595                     strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
1596                         /*
1597                          * Search mmttab for mountpoint
1598                          */
1599 
1600                         if (get_legacy_mountpoint(path, dataset,
1601                             ZFS_MAXPROPLEN, mountpoint,
1602                             ZFS_MAXPROPLEN) == 0) {
1603                                 ret = 1;
1604                                 break;
1605                         }
1606                         continue;
1607                 }
1608 
1609                 /* canmount must be set */
1610                 canmount[0] = '\0';
1611                 if (zfs_prop_get(cb.cb_handles[i], ZFS_PROP_CANMOUNT, canmount,
1612                     sizeof (canmount), NULL, NULL, 0, B_FALSE) != 0 ||
1613                     strcmp(canmount, "off") == 0)
1614                         continue;
1615 
1616                 /*
1617                  * have a mountable handle but want to skip those marked none
1618                  * and legacy
1619                  */
1620                 if (strcmp(mountpoint, path) == 0) {
1621                         dp = (char *)zfs_get_name(cb.cb_handles[i]);
1622                         if (dp != NULL) {
1623                                 if (datasetp != NULL)
1624                                         (void) strcpy(datasetp, dp);
1625                                 if (mountpointp != NULL)
1626                                         (void) strcpy(mountpointp, mountpoint);
1627                                 ret = 1;
1628                         }
1629                         break;
1630                 }
1631 
1632         }
1633 
1634         return (ret);
1635 }
1636 
1637 /*
1638  * This method builds values for "sharesmb" property from the
1639  * nvlist argument. The values are returned in sharesmb_val variable.
1640  */
1641 static int
1642 sa_zfs_sprintf_new_prop(nvlist_t *nvl, char *sharesmb_val)
1643 {
1644         char cur_val[MAXPATHLEN];
1645         char *name, *val;
1646         nvpair_t *cur;
1647         int err = 0;
1648 
1649         cur = nvlist_next_nvpair(nvl, NULL);
1650         while (cur != NULL) {
1651                 name = nvpair_name(cur);
1652                 err = nvpair_value_string(cur, &val);
1653                 if ((err != 0) || (name == NULL) || (val == NULL))
1654                         return (-1);
1655 
1656                 (void) snprintf(cur_val, MAXPATHLEN, "%s=%s,", name, val);
1657                 (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1658 
1659                 cur = nvlist_next_nvpair(nvl, cur);
1660         }
1661 
1662         return (0);
1663 }
1664 
1665 /*
1666  * This method builds values for "sharesmb" property from values
1667  * already existing on the share. The properties set via sa_zfs_sprint_new_prop
1668  * method are passed in sharesmb_val. If a existing property is already
1669  * set via sa_zfs_sprint_new_prop method, then they are not appended
1670  * to the sharesmb_val string. The returned sharesmb_val string is a combination
1671  * of new and existing values for 'sharesmb' property.
1672  */
1673 static int
1674 sa_zfs_sprintf_existing_prop(zfs_handle_t *handle, char *sharesmb_val)
1675 {
1676         char shareopts[ZFS_MAXPROPLEN], cur_val[MAXPATHLEN];
1677         char *token, *last, *value;
1678 
1679         if (zfs_prop_get(handle, ZFS_PROP_SHARESMB, shareopts,
1680             sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0)
1681                 return (-1);
1682 
1683         if (strstr(shareopts, "=") == NULL)
1684                 return (0);
1685 
1686         for (token = strtok_r(shareopts, ",", &last); token != NULL;
1687             token = strtok_r(NULL, ",", &last)) {
1688                 value = strchr(token, '=');
1689                 if (value == NULL)
1690                         return (-1);
1691                 *value++ = '\0';
1692 
1693                 (void) snprintf(cur_val, MAXPATHLEN, "%s=", token);
1694                 if (strstr(sharesmb_val, cur_val) == NULL) {
1695                         (void) strlcat(cur_val, value, MAXPATHLEN);
1696                         (void) strlcat(cur_val, ",", MAXPATHLEN);
1697                         (void) strlcat(sharesmb_val, cur_val, MAXPATHLEN);
1698                 }
1699         }
1700 
1701         return (0);
1702 }
1703 
1704 /*
1705  * Sets the share properties on a ZFS share. For now, this method sets only
1706  * the "sharesmb" property.
1707  *
1708  * This method includes building a comma seperated name-value string to be
1709  * set on the "sharesmb" property of a ZFS share. This name-value string is
1710  * build in 2 steps:
1711  *    - New property values given as name-value pair are set first.
1712  *    - Existing optionset properties, which are not part of the new properties
1713  *      passed in step 1, are appended to the newly set properties.
1714  */
1715 int
1716 sa_zfs_setprop(sa_handle_t handle, char *path, nvlist_t *nvl)
1717 {
1718         zfs_handle_t *z_fs;
1719         libzfs_handle_t *z_lib;
1720         char sharesmb_val[MAXPATHLEN];
1721         char *dataset, *lastcomma;
1722 
1723         if (nvlist_empty(nvl))
1724                 return (0);
1725 
1726         if ((handle == NULL) || (path == NULL))
1727                 return (-1);
1728 
1729         if ((dataset = get_zfs_dataset(handle, path, B_FALSE)) == NULL)
1730                 return (-1);
1731 
1732         if ((z_lib = libzfs_init()) == NULL) {
1733                 free(dataset);
1734                 return (-1);
1735         }
1736 
1737         z_fs = zfs_open(z_lib, dataset, ZFS_TYPE_DATASET);
1738         if (z_fs == NULL) {
1739                 free(dataset);
1740                 libzfs_fini(z_lib);
1741                 return (-1);
1742         }
1743 
1744         bzero(sharesmb_val, MAXPATHLEN);
1745         if (sa_zfs_sprintf_new_prop(nvl, sharesmb_val) != 0) {
1746                 free(dataset);
1747                 zfs_close(z_fs);
1748                 libzfs_fini(z_lib);
1749                 return (-1);
1750         }
1751 
1752         if (sa_zfs_sprintf_existing_prop(z_fs, sharesmb_val) != 0) {
1753                 free(dataset);
1754                 zfs_close(z_fs);
1755                 libzfs_fini(z_lib);
1756                 return (-1);
1757         }
1758 
1759         lastcomma = strrchr(sharesmb_val, ',');
1760         if ((lastcomma != NULL) && (lastcomma[1] == '\0'))
1761                 *lastcomma = '\0';
1762 
1763         (void) zfs_prop_set(z_fs, zfs_prop_to_name(ZFS_PROP_SHARESMB),
1764             sharesmb_val);
1765         free(dataset);
1766         zfs_close(z_fs);
1767         libzfs_fini(z_lib);
1768 
1769         return (0);
1770 }