Print this page
4095 minor cleanup up libshare


   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  * core library for common functions across all config store types
  28  * and file systems to be exported. This includes legacy dfstab/sharetab
  29  * parsing. Need to eliminate XML where possible.
  30  */
  31 
  32 #include <stdio.h>
  33 #include <string.h>
  34 #include <ctype.h>
  35 #include <unistd.h>
  36 #include <limits.h>
  37 #include <errno.h>
  38 #include <sys/types.h>
  39 #include <sys/stat.h>
  40 #include <libxml/parser.h>
  41 #include <libxml/tree.h>
  42 #include "libshare.h"
  43 #include "libshare_impl.h"


  73 /* used internally only */
  74 typedef
  75 struct sharelist {
  76     struct sharelist *next;
  77     int   persist;
  78     char *path;
  79     char *resource;
  80     char *fstype;
  81     char *options;
  82     char *description;
  83     char *group;
  84     char *origline;
  85     int lineno;
  86 } xfs_sharelist_t;
  87 static void parse_dfstab(sa_handle_t, char *, xmlNodePtr);
  88 extern char *_sa_get_token(char *);
  89 static void dfs_free_list(xfs_sharelist_t *);
  90 /* prototypes */
  91 void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
  92 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
  93 extern sa_group_t _sa_create_group(sa_handle_impl_t, char *);
  94 static void outdfstab(FILE *, xfs_sharelist_t *);
  95 extern int _sa_remove_optionset(sa_optionset_t);
  96 extern int set_node_share(void *, char *, char *);
  97 extern void set_node_attr(void *, char *, char *);
  98 
  99 /*
 100  * sablocksigs(*sigs)
 101  *
 102  * block important signals for a critical region. Arg is a pointer to
 103  * a sigset_t that is used later for the unblock.
 104  */
 105 void
 106 sablocksigs(sigset_t *sigs)
 107 {
 108         sigset_t new;
 109 
 110         if (sigs != NULL) {
 111                 (void) sigprocmask(SIG_BLOCK, NULL, &new);
 112                 (void) sigaddset(&new, SIGHUP);
 113                 (void) sigaddset(&new, SIGINT);


 724                         if (errno == EACCES || errno == EPERM)
 725                                 ret = SA_NO_PERMISSION;
 726                         else
 727                                 ret = SA_CONFIG_ERR;
 728                 }
 729                 sa_free_attr_string(path);
 730         }
 731 out:
 732         if (persist != NULL)
 733                 sa_free_attr_string(persist);
 734         return (ret);
 735 }
 736 
 737 /*
 738  * sa_is_security(optname, proto)
 739  *
 740  * Check to see if optname is a security (named optionset) specific
 741  * property for the specified protocol.
 742  */
 743 
 744 int
 745 sa_is_security(char *optname, char *proto)
 746 {
 747         int ret = 0;
 748         if (proto != NULL)
 749                 ret = sa_proto_security_prop(proto, optname);
 750         return (ret);
 751 }
 752 
 753 /*
 754  * add_syntax_comment(root, line, err, todfstab)
 755  *
 756  * Add a comment to the document indicating a syntax error. If
 757  * todfstab is set, write it back to the dfstab file as well.
 758  */
 759 
 760 static void
 761 add_syntax_comment(xmlNodePtr root, char *line, char *err, int todfstab)
 762 {
 763         xmlNodePtr node;
 764 
 765         node = xmlNewChild(root, NULL, (xmlChar *)"error", (xmlChar *)line);
 766         if (node != NULL)
 767                 (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)err);
 768         if (todfstab)
 769                 sa_comment_line(line, err);
 770 }
 771 
 772 /*
 773  * sa_is_share(object)
 774  *
 775  * returns true of the object is of type "share".
 776  */
 777 
 778 int
 779 sa_is_share(void *object)
 780 {
 781         if (object != NULL) {
 782                 if (strcmp((char *)((xmlNodePtr)object)->name, "share") == 0)
 783                 return (1);
 784         }
 785         return (0);
 786 }
 787 /*
 788  * sa_is_resource(object)
 789  *
 790  * returns true of the object is of type "share".
 791  */
 792 
 793 int
 794 sa_is_resource(void *object)
 795 {
 796         if (object != NULL) {
 797                 if (strcmp((char *)((xmlNodePtr)object)->name, "resource") == 0)
 798                         return (1);
 799         }
 800         return (0);
 801 }
 802 
 803 /*
 804  * _sa_remove_property(property)
 805  *
 806  * remove a property only from the document.
 807  */
 808 
 809 static void
 810 _sa_remove_property(sa_property_t property)
 811 {
 812         xmlUnlinkNode((xmlNodePtr)property);
 813         xmlFreeNode((xmlNodePtr)property);
 814 }
 815 
 816 /*
 817  * _sa_create_dummy_share()
 818  *
 819  * Create a share entry suitable for parsing but not tied to any real
 820  * config tree.  Need to have a parent as well as the node to parse


1501                                  * command to abort. Since we
1502                                  * add it to the default list,
1503                                  * everything works properly
1504                                  * anyway and the library
1505                                  * doesn't need to give a
1506                                  * warning.
1507                                  */
1508                                 share = _sa_add_share(lgroup,
1509                                     tmplist->path, SA_SHARE_TRANSIENT,
1510                                     &err, (uint64_t)SA_FEATURE_NONE);
1511                         }
1512                 } else {
1513                         if (sa_zfs_is_shared(handle, tmplist->path)) {
1514                                 group = sa_get_group(handle, "zfs");
1515                                 if (group == NULL) {
1516                                         group = sa_create_group(handle,
1517                                             "zfs", &err);
1518                                         if (group == NULL &&
1519                                             err == SA_NO_PERMISSION) {
1520                                                 group = _sa_create_group(
1521                                                     (sa_handle_impl_t)
1522                                                     handle,
1523                                                     "zfs");
1524                                         }
1525                                         if (group != NULL) {
1526                                                 (void) sa_create_optionset(
1527                                                     group, tmplist->fstype);
1528                                                 (void) sa_set_group_attr(group,
1529                                                     "zfs", "true");
1530                                         }
1531                                 }
1532                                 if (group != NULL) {
1533                                         share = _sa_add_share(group,
1534                                             tmplist->path, SA_SHARE_TRANSIENT,
1535                                             &err, (uint64_t)SA_FEATURE_NONE);
1536                                 }
1537                         } else {
1538                                 share = _sa_add_share(lgroup, tmplist->path,
1539                                     SA_SHARE_TRANSIENT, &err,
1540                                     (uint64_t)SA_FEATURE_NONE);
1541                         }
1542                 }
1543                 if (share == NULL)


1558                         if (tmplist->description != NULL) {
1559                                 xmlNodePtr node;
1560                                 node = xmlNewChild((xmlNodePtr)share, NULL,
1561                                     (xmlChar *)"description", NULL);
1562                                 xmlNodeSetContent(node,
1563                                     (xmlChar *)tmplist->description);
1564                         }
1565                         legacy = 1;
1566                 }
1567         }
1568         dfs_free_list(list);
1569         return (legacy);
1570 }
1571 
1572 /*
1573  * Get the transient shares from the sharetab (or other) file.  since
1574  * these are transient, they only appear in the working file and not
1575  * in a repository.
1576  */
1577 int
1578 gettransients(sa_handle_impl_t ihandle, xmlNodePtr *root)
1579 {
1580         int legacy = 0;
1581         int numproto;
1582         char **protocols = NULL;
1583         int i;
1584 
1585         if (root != NULL) {
1586                 if (*root == NULL)
1587                         *root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
1588                 if (*root != NULL) {
1589                         legacy = parse_sharetab(ihandle);
1590                         numproto = sa_get_protocols(&protocols);
1591                         for (i = 0; i < numproto; i++)
1592                                 legacy |= sa_proto_get_transients(
1593                                     (sa_handle_t)ihandle, protocols[i]);
1594                         if (protocols != NULL)
1595                                 free(protocols);
1596                 }
1597         }
1598         return (legacy);
1599 }
1600 
1601 /*
1602  * sa_has_prop(optionset, prop)
1603  *
1604  * Is the specified property a member of the optionset?
1605  */
1606 
1607 int
1608 sa_has_prop(sa_optionset_t optionset, sa_property_t prop)
1609 {
1610         char *name;
1611         sa_property_t otherprop;
1612         int result = 0;
1613 


2072         sh->sh_fstype = NULL;
2073         if (sh->sh_opts != NULL)
2074                 free(sh->sh_opts);
2075         sh->sh_opts = NULL;
2076         if (sh->sh_descr != NULL)
2077                 free(sh->sh_descr);
2078         sh->sh_descr = NULL;
2079 }
2080 
2081 /*
2082  * sa_update_sharetab_ts(handle)
2083  *
2084  * Update the internal timestamp of when sharetab was last
2085  * changed. This needs to be public for ZFS to get at it.
2086  */
2087 
2088 void
2089 sa_update_sharetab_ts(sa_handle_t handle)
2090 {
2091         struct stat st;
2092         sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
2093 
2094         if (implhandle != NULL && stat(SA_LEGACY_SHARETAB, &st) == 0)
2095                 implhandle->tssharetab = TSTAMP(st.st_mtim);
2096 }
2097 
2098 /*
2099  * sa_update_sharetab(share, proto)
2100  *
2101  * Update the sharetab file with info from the specified share.
2102  * This could be an update or add.
2103  */
2104 
2105 int
2106 sa_update_sharetab(sa_share_t share, char *proto)
2107 {
2108         int     ret = SA_OK;
2109         share_t sh;
2110         char    *path;
2111         sa_handle_t handle;
2112 
2113         path = sa_get_share_attr(share, "path");
2114         if (path != NULL) {
2115                 (void) memset(&sh, '\0', sizeof (sh));


2158                 (void) memset(&sh, '\0', sizeof (sh));
2159                 sh.sh_path = path;
2160                 sh.sh_fstype = proto;
2161 
2162                 ret = _sharefs(SHAREFS_REMOVE, &sh);
2163                 if (handle != NULL && stat(SA_LEGACY_SHARETAB, &st) == 0)
2164                         sa_update_sharetab_ts(handle);
2165         }
2166         return (ret);
2167 }
2168 
2169 /*
2170  * sa_needs_refresh(handle)
2171  *
2172  * Returns B_TRUE if the internal cache needs to be refreshed do to a
2173  * change by another process.  B_FALSE returned otherwise.
2174  */
2175 boolean_t
2176 sa_needs_refresh(sa_handle_t handle)
2177 {
2178         sa_handle_impl_t implhandle = (sa_handle_impl_t)handle;
2179         struct stat st;
2180         char *str;
2181         uint64_t tstamp;
2182         scf_simple_prop_t *prop;
2183 
2184         if (handle == NULL)
2185                 return (B_TRUE);
2186 
2187         /*
2188          * If sharetab has changed, then there was an external
2189          * change. Check sharetab first since it is updated by ZFS as
2190          * well as sharemgr.  This is where external ZFS changes are
2191          * caught.
2192          */
2193         if (stat(SA_LEGACY_SHARETAB, &st) == 0 &&
2194             TSTAMP(st.st_mtim) != implhandle->tssharetab)
2195                 return (B_TRUE);
2196 
2197         /*
2198          * If sharetab wasn't changed, check whether there were any
2199          * SMF transactions that modified the config but didn't
2200          * initiate a share.  This is less common but does happen.
2201          */
2202         prop = scf_simple_prop_get(implhandle->scfhandle->handle,
2203             (const char *)SA_SVC_FMRI_BASE ":default", "state",
2204             "lastupdate");
2205         if (prop != NULL) {
2206                 str = scf_simple_prop_next_astring(prop);
2207                 if (str != NULL)
2208                         tstamp = strtoull(str, NULL, 0);
2209                 else
2210                         tstamp = 0;
2211                 scf_simple_prop_free(prop);
2212                 if (tstamp != implhandle->tstrans)
2213                         return (B_TRUE);
2214         }
2215 
2216         return (B_FALSE);
2217 }
2218 
2219 /*
2220  * sa_fix_resource_name(path)
2221  *
2222  * Convert invalid characters in a resource name (SMB share name)
2223  * to underscores ('_').  The list of invalid characters includes
2224  * control characters and the following:
2225  *
2226  *      " / \ [ ] : | < > + ; , ? * =
2227  *
2228  * The caller must pass a valid path.  Leading and trailing slashes
2229  * are stripped from the path before converting invalid characters.
2230  * Resource names are restricted to SA_MAX_RESOURCE_NAME characters.
2231  */
2232 void




   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  * Copyright (c) 2013 RackTop Systems.
  25  */
  26 
  27 /*
  28  * core library for common functions across all config store types
  29  * and file systems to be exported. This includes legacy dfstab/sharetab
  30  * parsing. Need to eliminate XML where possible.
  31  */
  32 
  33 #include <stdio.h>
  34 #include <string.h>
  35 #include <ctype.h>
  36 #include <unistd.h>
  37 #include <limits.h>
  38 #include <errno.h>
  39 #include <sys/types.h>
  40 #include <sys/stat.h>
  41 #include <libxml/parser.h>
  42 #include <libxml/tree.h>
  43 #include "libshare.h"
  44 #include "libshare_impl.h"


  74 /* used internally only */
  75 typedef
  76 struct sharelist {
  77     struct sharelist *next;
  78     int   persist;
  79     char *path;
  80     char *resource;
  81     char *fstype;
  82     char *options;
  83     char *description;
  84     char *group;
  85     char *origline;
  86     int lineno;
  87 } xfs_sharelist_t;
  88 static void parse_dfstab(sa_handle_t, char *, xmlNodePtr);
  89 extern char *_sa_get_token(char *);
  90 static void dfs_free_list(xfs_sharelist_t *);
  91 /* prototypes */
  92 void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *);
  93 extern sa_share_t _sa_add_share(sa_group_t, char *, int, int *, uint64_t);
  94 extern sa_group_t _sa_create_group(sa_handle_t, char *);
  95 static void outdfstab(FILE *, xfs_sharelist_t *);
  96 extern int _sa_remove_optionset(sa_optionset_t);
  97 extern int set_node_share(void *, char *, char *);
  98 extern void set_node_attr(void *, char *, char *);
  99 
 100 /*
 101  * sablocksigs(*sigs)
 102  *
 103  * block important signals for a critical region. Arg is a pointer to
 104  * a sigset_t that is used later for the unblock.
 105  */
 106 void
 107 sablocksigs(sigset_t *sigs)
 108 {
 109         sigset_t new;
 110 
 111         if (sigs != NULL) {
 112                 (void) sigprocmask(SIG_BLOCK, NULL, &new);
 113                 (void) sigaddset(&new, SIGHUP);
 114                 (void) sigaddset(&new, SIGINT);


 725                         if (errno == EACCES || errno == EPERM)
 726                                 ret = SA_NO_PERMISSION;
 727                         else
 728                                 ret = SA_CONFIG_ERR;
 729                 }
 730                 sa_free_attr_string(path);
 731         }
 732 out:
 733         if (persist != NULL)
 734                 sa_free_attr_string(persist);
 735         return (ret);
 736 }
 737 
 738 /*
 739  * sa_is_security(optname, proto)
 740  *
 741  * Check to see if optname is a security (named optionset) specific
 742  * property for the specified protocol.
 743  */
 744 
 745 boolean_t
 746 sa_is_security(char *optname, char *proto)
 747 {
 748         int ret = B_FALSE;
 749         if (proto != NULL)
 750                 ret = sa_proto_security_prop(proto, optname);
 751         return (ret);
 752 }
 753 
 754 /*
 755  * add_syntax_comment(root, line, err, todfstab)
 756  *
 757  * Add a comment to the document indicating a syntax error. If
 758  * todfstab is set, write it back to the dfstab file as well.
 759  */
 760 
 761 static void
 762 add_syntax_comment(xmlNodePtr root, char *line, char *err, int todfstab)
 763 {
 764         xmlNodePtr node;
 765 
 766         node = xmlNewChild(root, NULL, (xmlChar *)"error", (xmlChar *)line);
 767         if (node != NULL)
 768                 (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)err);
 769         if (todfstab)
 770                 sa_comment_line(line, err);
 771 }
 772 
 773 /*
 774  * sa_is_share(object)
 775  *
 776  * returns true of the object is of type "share".
 777  */
 778 
 779 boolean_t
 780 sa_is_share(void *object)
 781 {
 782         if (object != NULL) {
 783                 if (strcmp((char *)((xmlNodePtr)object)->name, "share") == 0)
 784                 return (B_TRUE);
 785         }
 786         return (B_FALSE);
 787 }
 788 /*
 789  * sa_is_resource(object)
 790  *
 791  * returns true of the object is of type "share".
 792  */
 793 
 794 boolean_t
 795 sa_is_resource(void *object)
 796 {
 797         if (object != NULL) {
 798                 if (strcmp((char *)((xmlNodePtr)object)->name, "resource") == 0)
 799                         return (B_TRUE);
 800         }
 801         return (B_FALSE);
 802 }
 803 
 804 /*
 805  * _sa_remove_property(property)
 806  *
 807  * remove a property only from the document.
 808  */
 809 
 810 static void
 811 _sa_remove_property(sa_property_t property)
 812 {
 813         xmlUnlinkNode((xmlNodePtr)property);
 814         xmlFreeNode((xmlNodePtr)property);
 815 }
 816 
 817 /*
 818  * _sa_create_dummy_share()
 819  *
 820  * Create a share entry suitable for parsing but not tied to any real
 821  * config tree.  Need to have a parent as well as the node to parse


1502                                  * command to abort. Since we
1503                                  * add it to the default list,
1504                                  * everything works properly
1505                                  * anyway and the library
1506                                  * doesn't need to give a
1507                                  * warning.
1508                                  */
1509                                 share = _sa_add_share(lgroup,
1510                                     tmplist->path, SA_SHARE_TRANSIENT,
1511                                     &err, (uint64_t)SA_FEATURE_NONE);
1512                         }
1513                 } else {
1514                         if (sa_zfs_is_shared(handle, tmplist->path)) {
1515                                 group = sa_get_group(handle, "zfs");
1516                                 if (group == NULL) {
1517                                         group = sa_create_group(handle,
1518                                             "zfs", &err);
1519                                         if (group == NULL &&
1520                                             err == SA_NO_PERMISSION) {
1521                                                 group = _sa_create_group(
1522                                                     handle, "zfs");


1523                                         }
1524                                         if (group != NULL) {
1525                                                 (void) sa_create_optionset(
1526                                                     group, tmplist->fstype);
1527                                                 (void) sa_set_group_attr(group,
1528                                                     "zfs", "true");
1529                                         }
1530                                 }
1531                                 if (group != NULL) {
1532                                         share = _sa_add_share(group,
1533                                             tmplist->path, SA_SHARE_TRANSIENT,
1534                                             &err, (uint64_t)SA_FEATURE_NONE);
1535                                 }
1536                         } else {
1537                                 share = _sa_add_share(lgroup, tmplist->path,
1538                                     SA_SHARE_TRANSIENT, &err,
1539                                     (uint64_t)SA_FEATURE_NONE);
1540                         }
1541                 }
1542                 if (share == NULL)


1557                         if (tmplist->description != NULL) {
1558                                 xmlNodePtr node;
1559                                 node = xmlNewChild((xmlNodePtr)share, NULL,
1560                                     (xmlChar *)"description", NULL);
1561                                 xmlNodeSetContent(node,
1562                                     (xmlChar *)tmplist->description);
1563                         }
1564                         legacy = 1;
1565                 }
1566         }
1567         dfs_free_list(list);
1568         return (legacy);
1569 }
1570 
1571 /*
1572  * Get the transient shares from the sharetab (or other) file.  since
1573  * these are transient, they only appear in the working file and not
1574  * in a repository.
1575  */
1576 int
1577 gettransients(sa_handle_t handle, xmlNodePtr *root)
1578 {
1579         int legacy = 0;
1580         int numproto;
1581         char **protocols = NULL;
1582         int i;
1583 
1584         if (root != NULL) {
1585                 if (*root == NULL)
1586                         *root = xmlNewNode(NULL, (xmlChar *)"sharecfg");
1587                 if (*root != NULL) {
1588                         legacy = parse_sharetab(handle);
1589                         numproto = sa_get_protocols(&protocols);
1590                         for (i = 0; i < numproto; i++)
1591                                 legacy |= sa_proto_get_transients(
1592                                     handle, protocols[i]);
1593                         if (protocols != NULL)
1594                                 free(protocols);
1595                 }
1596         }
1597         return (legacy);
1598 }
1599 
1600 /*
1601  * sa_has_prop(optionset, prop)
1602  *
1603  * Is the specified property a member of the optionset?
1604  */
1605 
1606 int
1607 sa_has_prop(sa_optionset_t optionset, sa_property_t prop)
1608 {
1609         char *name;
1610         sa_property_t otherprop;
1611         int result = 0;
1612 


2071         sh->sh_fstype = NULL;
2072         if (sh->sh_opts != NULL)
2073                 free(sh->sh_opts);
2074         sh->sh_opts = NULL;
2075         if (sh->sh_descr != NULL)
2076                 free(sh->sh_descr);
2077         sh->sh_descr = NULL;
2078 }
2079 
2080 /*
2081  * sa_update_sharetab_ts(handle)
2082  *
2083  * Update the internal timestamp of when sharetab was last
2084  * changed. This needs to be public for ZFS to get at it.
2085  */
2086 
2087 void
2088 sa_update_sharetab_ts(sa_handle_t handle)
2089 {
2090         struct stat st;

2091 
2092         if (handle != NULL && stat(SA_LEGACY_SHARETAB, &st) == 0)
2093                 handle->tssharetab = TSTAMP(st.st_mtim);
2094 }
2095 
2096 /*
2097  * sa_update_sharetab(share, proto)
2098  *
2099  * Update the sharetab file with info from the specified share.
2100  * This could be an update or add.
2101  */
2102 
2103 int
2104 sa_update_sharetab(sa_share_t share, char *proto)
2105 {
2106         int     ret = SA_OK;
2107         share_t sh;
2108         char    *path;
2109         sa_handle_t handle;
2110 
2111         path = sa_get_share_attr(share, "path");
2112         if (path != NULL) {
2113                 (void) memset(&sh, '\0', sizeof (sh));


2156                 (void) memset(&sh, '\0', sizeof (sh));
2157                 sh.sh_path = path;
2158                 sh.sh_fstype = proto;
2159 
2160                 ret = _sharefs(SHAREFS_REMOVE, &sh);
2161                 if (handle != NULL && stat(SA_LEGACY_SHARETAB, &st) == 0)
2162                         sa_update_sharetab_ts(handle);
2163         }
2164         return (ret);
2165 }
2166 
2167 /*
2168  * sa_needs_refresh(handle)
2169  *
2170  * Returns B_TRUE if the internal cache needs to be refreshed do to a
2171  * change by another process.  B_FALSE returned otherwise.
2172  */
2173 boolean_t
2174 sa_needs_refresh(sa_handle_t handle)
2175 {

2176         struct stat st;
2177         char *str;
2178         uint64_t tstamp;
2179         scf_simple_prop_t *prop;
2180 
2181         if (handle == NULL)
2182                 return (B_TRUE);
2183 
2184         /*
2185          * If sharetab has changed, then there was an external
2186          * change. Check sharetab first since it is updated by ZFS as
2187          * well as sharemgr.  This is where external ZFS changes are
2188          * caught.
2189          */
2190         if (stat(SA_LEGACY_SHARETAB, &st) == 0 &&
2191             TSTAMP(st.st_mtim) != handle->tssharetab)
2192                 return (B_TRUE);
2193 
2194         /*
2195          * If sharetab wasn't changed, check whether there were any
2196          * SMF transactions that modified the config but didn't
2197          * initiate a share.  This is less common but does happen.
2198          */
2199         prop = scf_simple_prop_get(handle->scfhandle->handle,
2200             (const char *)SA_SVC_FMRI_BASE ":default", "state",
2201             "lastupdate");
2202         if (prop != NULL) {
2203                 str = scf_simple_prop_next_astring(prop);
2204                 if (str != NULL)
2205                         tstamp = strtoull(str, NULL, 0);
2206                 else
2207                         tstamp = 0;
2208                 scf_simple_prop_free(prop);
2209                 if (tstamp != handle->tstrans)
2210                         return (B_TRUE);
2211         }
2212 
2213         return (B_FALSE);
2214 }
2215 
2216 /*
2217  * sa_fix_resource_name(path)
2218  *
2219  * Convert invalid characters in a resource name (SMB share name)
2220  * to underscores ('_').  The list of invalid characters includes
2221  * control characters and the following:
2222  *
2223  *      " / \ [ ] : | < > + ; , ? * =
2224  *
2225  * The caller must pass a valid path.  Leading and trailing slashes
2226  * are stripped from the path before converting invalid characters.
2227  * Resource names are restricted to SA_MAX_RESOURCE_NAME characters.
2228  */
2229 void