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