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.
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.
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]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
34 #include <sys/types.h>
38 #include <libxml/parser.h>
39 #include <libxml/tree.h>
41 #include "libshare_impl.h"
50 #define DFS_LOCK_FILE "/etc/dfs/fstypes"
51 #define SA_STRSIZE 256 /* max string size for names */
54 * internal object type values returned by sa_get_object_type()
56 #define SA_TYPE_UNKNOWN 0
57 #define SA_TYPE_GROUP 1
58 #define SA_TYPE_SHARE 2
59 #define SA_TYPE_RESOURCE 3
60 #define SA_TYPE_OPTIONSET 4
61 #define SA_TYPE_ALTSPACE 5
64 * internal data structures
67 extern struct sa_proto_plugin
*sap_proto_list
;
69 /* current SMF/SVC repository handle */
70 extern void getlegacyconfig(sa_handle_t
, char *, xmlNodePtr
*);
71 extern int gettransients(sa_handle_impl_t
, xmlNodePtr
*);
72 extern int get_one_transient(sa_handle_impl_t
, xmlNodePtr
*, char **, size_t);
73 extern char *sa_fstype(char *);
74 extern int sa_is_share(void *);
75 extern int sa_is_resource(void *);
76 extern ssize_t scf_max_name_len
; /* defined in scfutil during initialization */
77 extern int sa_group_is_zfs(sa_group_t
);
78 extern int sa_path_is_zfs(char *);
79 extern int sa_zfs_set_sharenfs(sa_group_t
, char *, int);
80 extern int sa_zfs_set_sharesmb(sa_group_t
, char *, int);
81 extern void update_legacy_config(sa_handle_t
);
82 extern int issubdir(char *, char *);
83 extern int sa_zfs_init(sa_handle_impl_t
);
84 extern void sa_zfs_fini(sa_handle_impl_t
);
85 extern void sablocksigs(sigset_t
*);
86 extern void saunblocksigs(sigset_t
*);
87 static sa_group_t
sa_get_optionset_parent(sa_optionset_t
);
88 static char *get_node_attr(void *, char *);
89 extern void sa_update_sharetab_ts(sa_handle_t
);
92 * Data structures for finding/managing the document root to access
93 * handle mapping. The list isn't expected to grow very large so a
94 * simple list is acceptable. The purpose is to provide a way to start
95 * with a group or share and find the library handle needed for
98 mutex_t sa_global_lock
;
100 struct doc2handle
*next
;
102 sa_handle_impl_t handle
;
105 mutex_t sa_dfstab_lock
;
107 /* definitions used in a couple of property functions */
108 #define SA_PROP_OP_REMOVE 1
109 #define SA_PROP_OP_ADD 2
110 #define SA_PROP_OP_UPDATE 3
112 static struct doc2handle
*sa_global_handles
= NULL
;
114 /* helper functions */
119 * convert an error value to an error string
125 static char errstr
[32];
130 ret
= dgettext(TEXT_DOMAIN
, "ok");
132 case SA_NO_SUCH_PATH
:
133 ret
= dgettext(TEXT_DOMAIN
, "path doesn't exist");
136 ret
= dgettext(TEXT_DOMAIN
, "no memory");
138 case SA_DUPLICATE_NAME
:
139 ret
= dgettext(TEXT_DOMAIN
, "name in use");
142 ret
= dgettext(TEXT_DOMAIN
, "bad path");
144 case SA_NO_SUCH_GROUP
:
145 ret
= dgettext(TEXT_DOMAIN
, "no such group");
148 ret
= dgettext(TEXT_DOMAIN
, "configuration error");
151 ret
= dgettext(TEXT_DOMAIN
, "system error");
154 ret
= dgettext(TEXT_DOMAIN
, "syntax error");
156 case SA_NO_PERMISSION
:
157 ret
= dgettext(TEXT_DOMAIN
, "no permission");
160 ret
= dgettext(TEXT_DOMAIN
, "busy");
162 case SA_NO_SUCH_PROP
:
163 ret
= dgettext(TEXT_DOMAIN
, "no such property");
165 case SA_INVALID_NAME
:
166 ret
= dgettext(TEXT_DOMAIN
, "invalid name");
168 case SA_INVALID_PROTOCOL
:
169 ret
= dgettext(TEXT_DOMAIN
, "invalid protocol");
172 ret
= dgettext(TEXT_DOMAIN
, "operation not allowed");
175 ret
= dgettext(TEXT_DOMAIN
, "bad property value");
177 case SA_INVALID_SECURITY
:
178 ret
= dgettext(TEXT_DOMAIN
, "invalid security type");
180 case SA_NO_SUCH_SECURITY
:
181 ret
= dgettext(TEXT_DOMAIN
, "security type not found");
183 case SA_VALUE_CONFLICT
:
184 ret
= dgettext(TEXT_DOMAIN
, "property value conflict");
186 case SA_NOT_IMPLEMENTED
:
187 ret
= dgettext(TEXT_DOMAIN
, "not implemented");
189 case SA_INVALID_PATH
:
190 ret
= dgettext(TEXT_DOMAIN
, "invalid path");
192 case SA_NOT_SUPPORTED
:
193 ret
= dgettext(TEXT_DOMAIN
, "operation not supported");
195 case SA_PROP_SHARE_ONLY
:
196 ret
= dgettext(TEXT_DOMAIN
, "property not valid for group");
199 ret
= dgettext(TEXT_DOMAIN
, "not shared");
201 case SA_NO_SUCH_RESOURCE
:
202 ret
= dgettext(TEXT_DOMAIN
, "no such resource");
204 case SA_RESOURCE_REQUIRED
:
205 ret
= dgettext(TEXT_DOMAIN
, "resource name required");
207 case SA_MULTIPLE_ERROR
:
208 ret
= dgettext(TEXT_DOMAIN
, "errors from multiple protocols");
210 case SA_PATH_IS_SUBDIR
:
211 ret
= dgettext(TEXT_DOMAIN
, "path is a subpath of share");
213 case SA_PATH_IS_PARENTDIR
:
214 ret
= dgettext(TEXT_DOMAIN
, "path is parent of a share");
217 ret
= dgettext(TEXT_DOMAIN
, "protocol requires a section");
219 case SA_NO_PROPERTIES
:
220 ret
= dgettext(TEXT_DOMAIN
, "properties not found");
222 case SA_NO_SUCH_SECTION
:
223 ret
= dgettext(TEXT_DOMAIN
, "section not found");
225 case SA_PASSWORD_ENC
:
226 ret
= dgettext(TEXT_DOMAIN
, "passwords must be encrypted");
228 case SA_SHARE_EXISTS
:
229 ret
= dgettext(TEXT_DOMAIN
, "path or file is already shared");
232 (void) snprintf(errstr
, sizeof (errstr
),
233 dgettext(TEXT_DOMAIN
, "unknown %d"), err
);
240 * Document root to active handle mapping functions. These are only
241 * used internally. A mutex is used to prevent access while the list
242 * is changing. In general, the list will be relatively short - one
243 * item per thread that has called sa_init().
247 get_handle_for_root(xmlNodePtr root
)
249 struct doc2handle
*item
;
251 (void) mutex_lock(&sa_global_lock
);
252 for (item
= sa_global_handles
; item
!= NULL
; item
= item
->next
) {
253 if (item
->root
== root
)
256 (void) mutex_unlock(&sa_global_lock
);
258 return (item
->handle
);
263 add_handle_for_root(xmlNodePtr root
, sa_handle_impl_t handle
)
265 struct doc2handle
*item
;
266 int ret
= SA_NO_MEMORY
;
268 item
= (struct doc2handle
*)calloc(sizeof (struct doc2handle
), 1);
271 item
->handle
= handle
;
272 (void) mutex_lock(&sa_global_lock
);
273 item
->next
= sa_global_handles
;
274 sa_global_handles
= item
;
275 (void) mutex_unlock(&sa_global_lock
);
282 * remove_handle_for_root(root)
284 * Walks the list of handles and removes the one for this "root" from
285 * the list. It is up to the caller to free the data.
289 remove_handle_for_root(xmlNodePtr root
)
291 struct doc2handle
*item
, *prev
;
293 (void) mutex_lock(&sa_global_lock
);
294 for (prev
= NULL
, item
= sa_global_handles
; item
!= NULL
;
296 if (item
->root
== root
) {
297 /* first in the list */
299 sa_global_handles
= sa_global_handles
->next
;
301 prev
->next
= item
->next
;
302 /* Item is out of the list so free the list structure */
308 (void) mutex_unlock(&sa_global_lock
);
312 * sa_find_group_handle(sa_group_t group)
314 * Find the sa_handle_t for the configuration associated with this
318 sa_find_group_handle(sa_group_t group
)
320 xmlNodePtr node
= (xmlNodePtr
)group
;
323 while (node
!= NULL
) {
324 if (strcmp((char *)(node
->name
), "sharecfg") == 0) {
325 /* have the root so get the handle */
326 handle
= (sa_handle_t
)get_handle_for_root(node
);
335 * set_legacy_timestamp(root, path, timevalue)
337 * add the current timestamp value to the configuration for use in
338 * determining when to update the legacy files. For SMF, this
339 * property is kept in default/operation/legacy_timestamp
343 set_legacy_timestamp(xmlNodePtr root
, char *path
, uint64_t tval
)
346 xmlChar
*lpath
= NULL
;
347 sa_handle_impl_t handle
;
349 /* Have to have a handle or else we weren't initialized. */
350 handle
= get_handle_for_root(root
);
354 for (node
= root
->xmlChildrenNode
; node
!= NULL
;
356 if (xmlStrcmp(node
->name
, (xmlChar
*)"legacy") == 0) {
357 /* a possible legacy node for this path */
358 lpath
= xmlGetProp(node
, (xmlChar
*)"path");
360 xmlStrcmp(lpath
, (xmlChar
*)path
) == 0) {
369 /* need to create the first legacy timestamp node */
370 node
= xmlNewChild(root
, NULL
, (xmlChar
*)"legacy", NULL
);
376 (void) snprintf(tstring
, sizeof (tstring
), "%lld", tval
);
377 (void) xmlSetProp(node
, (xmlChar
*)"timestamp",
379 (void) xmlSetProp(node
, (xmlChar
*)"path", (xmlChar
*)path
);
380 /* now commit to SMF */
381 ret
= sa_get_instance(handle
->scfhandle
, "default");
383 ret
= sa_start_transaction(handle
->scfhandle
,
386 ret
= sa_set_property(handle
->scfhandle
,
387 "legacy-timestamp", tstring
);
389 (void) sa_end_transaction(
390 handle
->scfhandle
, handle
);
392 sa_abort_transaction(handle
->scfhandle
);
402 * determine if the specified share is currently shared or not.
405 is_shared(sa_share_t share
)
408 int result
= 0; /* assume not */
410 shared
= sa_get_share_attr(share
, "shared");
411 if (shared
!= NULL
) {
412 if (strcmp(shared
, "true") == 0)
414 sa_free_attr_string(shared
);
420 * excluded_protocol(share, proto)
422 * Returns B_TRUE if the specified protocol appears in the "exclude"
423 * property. This is used to prevent sharing special case shares
424 * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is
425 * returned if the protocol isn't in the list.
428 excluded_protocol(sa_share_t share
, char *proto
)
434 protolist
= sa_get_share_attr(share
, "exclude");
435 if (protolist
!= NULL
) {
437 while ((token
= strtok(str
, ",")) != NULL
) {
438 if (strcmp(token
, proto
) == 0) {
439 sa_free_attr_string(protolist
);
444 sa_free_attr_string(protolist
);
450 * checksubdirgroup(group, newpath, strictness)
452 * check all the specified newpath against all the paths in the
453 * group. This is a helper function for checksubdir to make it easier
454 * to also check ZFS subgroups.
455 * The strictness values mean:
456 * SA_CHECK_NORMAL == only check newpath against shares that are active
457 * SA_CHECK_STRICT == check newpath against both active shares and those
458 * stored in the repository
461 checksubdirgroup(sa_group_t group
, char *newpath
, int strictness
)
470 return (SA_INVALID_PATH
);
472 for (share
= sa_get_share(group
, NULL
); share
!= NULL
;
473 share
= sa_get_next_share(share
)) {
475 * The original behavior of share never checked
476 * against the permanent configuration
477 * (/etc/dfs/dfstab). PIT has a number of cases where
478 * it depends on this older behavior even though it
479 * could be considered incorrect. We may tighten this
482 if (strictness
== SA_CHECK_NORMAL
&& !is_shared(share
))
485 path
= sa_get_share_attr(share
, "path");
487 * If path is NULL, then a share is in the process of
488 * construction or someone has modified the property
489 * group inappropriately. It should be
490 * ignored. issubdir() comes from the original share
491 * implementation and does the difficult part of
492 * checking subdirectories.
497 if (strcmp(path
, newpath
) == 0) {
498 issub
= SA_INVALID_PATH
;
500 subdir
= issubdir(newpath
, path
);
501 parent
= issubdir(path
, newpath
);
502 if (subdir
|| parent
) {
503 sa_free_attr_string(path
);
506 SA_PATH_IS_SUBDIR
: SA_PATH_IS_PARENTDIR
);
509 sa_free_attr_string(path
);
516 * checksubdir(newpath, strictness)
518 * checksubdir determines if the specified path (newpath) is a
519 * subdirectory of another share. It calls checksubdirgroup() to do
520 * the complicated work. The strictness parameter determines how
521 * strict a check to make against the path. The strictness values
522 * mean: SA_CHECK_NORMAL == only check newpath against shares that are
523 * active SA_CHECK_STRICT == check newpath against both active shares
524 * and those * stored in the repository
527 checksubdir(sa_handle_t handle
, char *newpath
, int strictness
)
533 for (group
= sa_get_group(handle
, NULL
);
534 group
!= NULL
&& issub
== SA_OK
;
535 group
= sa_get_next_group(group
)) {
536 if (sa_group_is_zfs(group
)) {
538 for (subgroup
= sa_get_sub_group(group
);
539 subgroup
!= NULL
&& issub
== SA_OK
;
540 subgroup
= sa_get_next_group(subgroup
))
541 issub
= checksubdirgroup(subgroup
, newpath
,
544 issub
= checksubdirgroup(group
, newpath
, strictness
);
548 sa_free_attr_string(path
);
553 * validpath(path, strictness)
554 * determine if the provided path is valid for a share. It shouldn't
555 * be a sub-dir of an already shared path or the parent directory of a
559 validpath(sa_handle_t handle
, char *path
, int strictness
)
567 return (SA_BAD_PATH
);
569 if (stat(path
, &st
) < 0) {
570 error
= SA_NO_SUCH_PATH
;
572 share
= sa_find_share(handle
, path
);
574 error
= SA_DUPLICATE_NAME
;
576 if (error
== SA_OK
) {
578 * check for special case with file system
579 * that might have restrictions. For now, ZFS
580 * is the only case since it has its own idea
581 * of how to configure shares. We do this
582 * before subdir checking since things like
583 * ZFS will do that for us. This should also
584 * be done via plugin interface.
586 fstype
= sa_fstype(path
);
587 if (fstype
!= NULL
&& strcmp(fstype
, "zfs") == 0) {
588 if (sa_zfs_is_shared(handle
, path
))
589 error
= SA_INVALID_NAME
;
592 sa_free_fstype(fstype
);
595 error
= checksubdir(handle
, path
, strictness
);
601 * check to see if group/share is persistent.
603 * "group" can be either an sa_group_t or an sa_share_t. (void *)
604 * works since both these types are also void *.
605 * If the share is a ZFS share, mark it as persistent.
608 sa_is_persistent(void *group
)
614 type
= sa_get_group_attr((sa_group_t
)group
, "type");
616 if (strcmp(type
, "transient") == 0)
618 sa_free_attr_string(type
);
621 grp
= (sa_is_share(group
)) ? sa_get_parent_group(group
) : group
;
622 if (sa_group_is_zfs(grp
))
629 * sa_valid_group_name(name)
631 * check that the "name" contains only valid characters and otherwise
632 * fits the required naming conventions. Valid names must start with
633 * an alphabetic and the remainder may consist of only alphanumeric
634 * plus the '-' and '_' characters. This name limitation comes from
635 * inherent limitations in SMF.
639 sa_valid_group_name(char *name
)
644 if (name
!= NULL
&& isalpha(*name
)) {
647 if (len
< (scf_max_name_len
- sizeof ("group:"))) {
648 for (c
= *name
++; c
!= '\0' && ret
!= 0; c
= *name
++) {
649 if (!isalnum(c
) && c
!= '-' && c
!= '_')
663 * is_zfs_group(group)
664 * Determine if the specified group is a ZFS sharenfs group
667 is_zfs_group(sa_group_t group
)
673 if (strcmp((char *)((xmlNodePtr
)group
)->name
, "share") == 0)
674 parent
= (xmlNodePtr
)sa_get_parent_group(group
);
676 parent
= (xmlNodePtr
)group
;
677 zfs
= xmlGetProp(parent
, (xmlChar
*)"zfs");
686 * sa_get_object_type(object)
688 * This function returns a numeric value representing the object
689 * type. This allows using simpler checks when doing type specific
694 sa_get_object_type(void *object
)
696 xmlNodePtr node
= (xmlNodePtr
)object
;
699 if (xmlStrcmp(node
->name
, (xmlChar
*)"group") == 0)
700 type
= SA_TYPE_GROUP
;
701 else if (xmlStrcmp(node
->name
, (xmlChar
*)"share") == 0)
702 type
= SA_TYPE_SHARE
;
703 else if (xmlStrcmp(node
->name
, (xmlChar
*)"resource") == 0)
704 type
= SA_TYPE_RESOURCE
;
705 else if (xmlStrcmp(node
->name
, (xmlChar
*)"optionset") == 0)
706 type
= SA_TYPE_OPTIONSET
;
707 else if (xmlStrcmp(node
->name
, (xmlChar
*)"security") == 0)
708 type
= SA_TYPE_ALTSPACE
;
715 * sa_optionset_name(optionset, oname, len, id)
716 * return the SMF name for the optionset. If id is not NULL, it
717 * will have the GUID value for a share and should be used
718 * instead of the keyword "optionset" which is used for
719 * groups. If the optionset doesn't have a protocol type
720 * associated with it, "default" is used. This shouldn't happen
721 * at this point but may be desirable in the future if there are
722 * protocol independent properties added. The name is returned in
727 sa_optionset_name(sa_optionset_t optionset
, char *oname
, size_t len
, char *id
)
736 parent
= sa_get_optionset_parent(optionset
);
737 if (parent
!= NULL
) {
738 ptype
= sa_get_object_type(parent
);
739 proto
= sa_get_optionset_attr(optionset
, "type");
740 if (ptype
!= SA_TYPE_RESOURCE
) {
741 len
= snprintf(oname
, len
, "%s_%s", id
,
742 proto
? proto
: "default");
745 index
= get_node_attr((void *)parent
, "id");
747 len
= snprintf(oname
, len
, "%s_%s_%s", id
,
748 proto
? proto
: "default", index
);
749 sa_free_attr_string(index
);
756 sa_free_attr_string(proto
);
764 * sa_security_name(optionset, oname, len, id)
766 * return the SMF name for the security. If id is not NULL, it will
767 * have the GUID value for a share and should be used instead of the
768 * keyword "optionset" which is used for groups. If the optionset
769 * doesn't have a protocol type associated with it, "default" is
770 * used. This shouldn't happen at this point but may be desirable in
771 * the future if there are protocol independent properties added. The
772 * name is returned in oname. The security type is also encoded into
773 * the name. In the future, this wil *be handled a bit differently.
777 sa_security_name(sa_security_t security
, char *oname
, size_t len
, char *id
)
785 proto
= sa_get_security_attr(security
, "type");
786 sectype
= sa_get_security_attr(security
, "sectype");
787 len
= snprintf(oname
, len
, "%s_%s_%s", id
, proto
? proto
: "default",
788 sectype
? sectype
: "default");
790 sa_free_attr_string(proto
);
792 sa_free_attr_string(sectype
);
797 * verifydefgroupopts(handle)
799 * Make sure a "default" group exists and has default protocols enabled.
802 verifydefgroupopts(sa_handle_t handle
)
807 defgrp
= sa_get_group(handle
, "default");
808 if (defgrp
!= NULL
) {
809 opt
= sa_get_optionset(defgrp
, NULL
);
811 * NFS is the default for default group
814 opt
= sa_create_optionset(defgrp
, "nfs");
819 * sa_init_impl(init_service, arg)
821 * find all the shared objects
822 * init the tables with all objects
823 * read in the current configuration
825 * arg is a parameter passed in whose meaning is based on the init_service.
826 * See libshare.h under API initialization.
828 #define GETPROP(prop) scf_simple_prop_next_astring(prop)
829 #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \
830 tval != TSTAMP(st.st_ctim)
832 sa_init_impl(int init_service
, void *arg
)
835 /* legacy is used for debugging only as far as I can tell */
840 int updatelegacy
= B_FALSE
;
841 scf_simple_prop_t
*prop
;
842 sa_handle_impl_t handle
;
845 handle
= calloc(sizeof (struct sa_handle_impl
), 1);
847 if (handle
!= NULL
) {
848 handle
->sa_service
= init_service
;
850 * Get protocol specific structures, but only if this
851 * is the only handle.
853 (void) mutex_lock(&sa_global_lock
);
854 if (sa_global_handles
== NULL
)
855 (void) proto_plugin_init();
856 (void) mutex_unlock(&sa_global_lock
);
857 if (init_service
& (SA_INIT_SHARE_API
|
858 SA_INIT_SHARE_API_SELECTIVE
| SA_INIT_ONE_SHARE_FROM_NAME
|
859 SA_INIT_ONE_SHARE_FROM_HANDLE
)) {
861 * initialize access into libzfs. We use this
862 * when collecting info about ZFS datasets and
865 if (sa_zfs_init(handle
) == B_FALSE
) {
867 (void) mutex_lock(&sa_global_lock
);
868 (void) proto_plugin_fini();
869 (void) mutex_unlock(&sa_global_lock
);
873 * since we want to use SMF, initialize an svc handle
874 * and find out what is there.
876 handle
->scfhandle
= sa_scf_init(handle
);
877 if (handle
->scfhandle
!= NULL
) {
879 * Need to lock the extraction of the
880 * configuration if the dfstab file has
881 * changed. Lock everything now and release if
882 * not needed. Use a file that isn't being
883 * manipulated by other parts of the system in
884 * order to not interfere with locking. Using
885 * dfstab doesn't work.
888 lockfd
= open(DFS_LOCK_FILE
, O_RDWR
);
891 (void) lockf(lockfd
, F_LOCK
, 0);
892 (void) mutex_lock(&sa_dfstab_lock
);
894 * Check whether we are going to need
895 * to merge any dfstab changes. This
896 * is done by comparing the value of
897 * legacy-timestamp with the current
898 * st_ctim of the file. If they are
899 * different, an update is needed and
900 * the file must remain locked until
901 * the merge is done in order to
902 * prevent multiple startups from
903 * changing the SMF repository at the
904 * same time. The first to get the
905 * lock will make any changes before
906 * the others can read the repository.
908 prop
= scf_simple_prop_get
909 (handle
->scfhandle
->handle
,
910 (const char *)SA_SVC_FMRI_BASE
911 ":default", "operation",
919 if (CHECKTSTAMP(st
, tval
))
920 updatelegacy
= B_TRUE
;
921 scf_simple_prop_free(prop
);
925 * timestamp before so do it.
927 updatelegacy
= B_TRUE
;
929 if (updatelegacy
== B_FALSE
) {
932 (void) lockf(lockfd
, F_ULOCK
,
934 (void) close(lockfd
);
939 * It is essential that the document tree and
940 * the internal list of roots to handles be
941 * setup before anything that might try to
942 * create a new object is called. The document
943 * tree is the combination of handle->doc and
944 * handle->tree. This allows searches,
945 * etc. when all you have is an object in the
948 handle
->doc
= xmlNewDoc((xmlChar
*)"1.0");
949 handle
->tree
= xmlNewNode(NULL
,
950 (xmlChar
*)"sharecfg");
951 if (handle
->doc
!= NULL
&&
952 handle
->tree
!= NULL
) {
953 (void) xmlDocSetRootElement(handle
->doc
,
955 err
= add_handle_for_root(handle
->tree
,
960 handle
->tree
, handle
);
962 if (handle
->doc
!= NULL
)
963 xmlFreeDoc(handle
->doc
);
964 if (handle
->tree
!= NULL
)
965 xmlFreeNode(handle
->tree
);
973 * If we couldn't add the tree handle
974 * to the list, then things are going
975 * to fail badly. Might as well undo
976 * everything now and fail the
980 if (updatelegacy
== B_TRUE
) {
985 (void) close(lockfd
);
992 * first time so make sure
995 verifydefgroupopts(handle
);
998 if (updatelegacy
== B_TRUE
) {
1000 getlegacyconfig((sa_handle_t
)handle
,
1001 SA_LEGACY_DFSTAB
, &handle
->tree
);
1002 if (stat(SA_LEGACY_DFSTAB
, &st
) >= 0)
1003 set_legacy_timestamp(
1006 TSTAMP(st
.st_ctim
));
1007 saunblocksigs(&old
);
1009 * Safe to unlock now to allow
1012 (void) mutex_unlock(&sa_dfstab_lock
);
1013 (void) lockf(lockfd
, F_ULOCK
, 0);
1014 (void) close(lockfd
);
1016 /* Get sharetab timestamp */
1017 sa_update_sharetab_ts((sa_handle_t
)handle
);
1019 /* Get lastupdate (transaction) timestamp */
1020 prop
= scf_simple_prop_get(
1021 handle
->scfhandle
->handle
,
1022 (const char *)SA_SVC_FMRI_BASE
":default",
1023 "state", "lastupdate");
1027 scf_simple_prop_next_astring(prop
);
1030 strtoull(str
, NULL
, 0);
1032 handle
->tstrans
= 0;
1033 scf_simple_prop_free(prop
);
1036 * In this conditional the library reads from
1037 * zfs and /etc/dfs/sharetab to find datasets
1038 * that must be shared. The result is a tree of
1039 * groups that are stored in the handle for
1040 * libshare to utilize later when asked to share
1041 * or unshare datasets.
1044 SA_INIT_SHARE_API_SELECTIVE
) {
1046 size_t paths_len
, i
;
1048 legacy
|= sa_get_one_zfs_share(handle
,
1050 (sa_init_selective_arg_t
*)arg
,
1051 &paths
, &paths_len
);
1052 legacy
|= get_one_transient(handle
,
1053 &handle
->tree
, paths
, paths_len
);
1054 for (i
= 0; i
< paths_len
; ++i
) {
1058 } else if (init_service
&
1059 SA_INIT_ONE_SHARE_FROM_NAME
) {
1060 char path
[ZFS_MAXPROPLEN
];
1062 char **ptr_to_path
= &ptr
;
1065 sa_get_zfs_share_for_name(handle
,
1066 "zfs", (char *)arg
, path
);
1067 legacy
|= get_one_transient(handle
,
1068 &handle
->tree
, ptr_to_path
, 1);
1069 } else if (init_service
&
1070 SA_INIT_ONE_SHARE_FROM_HANDLE
) {
1071 char path
[ZFS_MAXPROPLEN
];
1073 char **ptr_to_path
= &ptr
;
1076 sa_get_zfs_share_for_name(handle
,
1079 (zfs_handle_t
*)arg
),
1081 legacy
|= get_one_transient(handle
,
1082 &handle
->tree
, ptr_to_path
, 1);
1084 legacy
|= sa_get_zfs_shares(handle
,
1086 legacy
|= gettransients(handle
,
1092 return ((sa_handle_t
)handle
);
1096 * sa_init exists as a legacy interface, new consumers should use sa_init_arg.
1099 sa_init(int init_service
)
1101 return (sa_init_impl(init_service
, NULL
));
1105 * See libshare.h "API Initialization" section for valid values of init_service
1106 * as well as the appropriate argument type for a given init_service.
1109 sa_init_arg(int init_service
, void *arg
)
1111 return (sa_init_impl(init_service
, arg
));
1116 * Uninitialize the API structures including the configuration
1117 * data structures and ZFS related data.
1121 sa_fini(sa_handle_t handle
)
1123 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
1125 if (impl_handle
!= NULL
) {
1127 * Free the config trees and any other data structures
1128 * used in the handle.
1130 if (impl_handle
->doc
!= NULL
)
1131 xmlFreeDoc(impl_handle
->doc
);
1133 /* Remove and free the entry in the global list. */
1134 remove_handle_for_root(impl_handle
->tree
);
1137 * If this was the last handle to release, unload the
1138 * plugins that were loaded. Use a mutex in case
1139 * another thread is reinitializing.
1141 (void) mutex_lock(&sa_global_lock
);
1142 if (sa_global_handles
== NULL
)
1143 (void) proto_plugin_fini();
1144 (void) mutex_unlock(&sa_global_lock
);
1146 sa_scf_fini(impl_handle
->scfhandle
);
1147 sa_zfs_fini(impl_handle
);
1149 /* Make sure we free the handle */
1156 * sa_get_protocols(char **protocol)
1157 * Get array of protocols that are supported
1158 * Returns pointer to an allocated and NULL terminated
1159 * array of strings. Caller must free.
1160 * This really should be determined dynamically.
1161 * If there aren't any defined, return -1.
1162 * Use free() to return memory.
1166 sa_get_protocols(char ***protocols
)
1170 if (protocols
!= NULL
) {
1171 struct sa_proto_plugin
*plug
;
1172 for (numproto
= 0, plug
= sap_proto_list
; plug
!= NULL
;
1173 plug
= plug
->plugin_next
) {
1177 *protocols
= calloc(numproto
+ 1, sizeof (char *));
1178 if (*protocols
!= NULL
) {
1180 for (plug
= sap_proto_list
; plug
!= NULL
;
1181 plug
= plug
->plugin_next
) {
1182 /* faking for now */
1183 (*protocols
)[ret
++] =
1184 plug
->plugin_ops
->sa_protocol
;
1194 * find_group_by_name(node, group)
1196 * search the XML document subtree specified by node to find the group
1197 * specified by group. Searching subtree allows subgroups to be
1202 find_group_by_name(xmlNodePtr node
, xmlChar
*group
)
1204 xmlChar
*name
= NULL
;
1206 for (node
= node
->xmlChildrenNode
; node
!= NULL
;
1207 node
= node
->next
) {
1208 if (xmlStrcmp(node
->name
, (xmlChar
*)"group") == 0) {
1209 /* if no groupname, return the first found */
1212 name
= xmlGetProp(node
, (xmlChar
*)"name");
1213 if (name
!= NULL
&& xmlStrcmp(name
, group
) == 0)
1227 * sa_get_group(groupname)
1228 * Return the "group" specified. If groupname is NULL,
1229 * return the first group of the list of groups.
1232 sa_get_group(sa_handle_t handle
, char *groupname
)
1234 xmlNodePtr node
= NULL
;
1235 char *subgroup
= NULL
;
1237 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
1239 if (impl_handle
!= NULL
&& impl_handle
->tree
!= NULL
) {
1240 if (groupname
!= NULL
) {
1241 group
= strdup(groupname
);
1242 if (group
!= NULL
) {
1243 subgroup
= strchr(group
, '/');
1244 if (subgroup
!= NULL
)
1249 * We want to find the, possibly, named group. If
1250 * group is not NULL, then lookup the name. If it is
1251 * NULL, we only do the find if groupname is also
1252 * NULL. This allows lookup of the "first" group in
1253 * the internal list.
1255 if (group
!= NULL
|| groupname
== NULL
)
1256 node
= find_group_by_name(impl_handle
->tree
,
1259 /* if a subgroup, find it before returning */
1260 if (subgroup
!= NULL
&& node
!= NULL
)
1261 node
= find_group_by_name(node
, (xmlChar
*)subgroup
);
1263 if (node
!= NULL
&& (char *)group
!= NULL
)
1264 (void) sa_get_instance(impl_handle
->scfhandle
, (char *)group
);
1266 return ((sa_group_t
)(node
));
1270 * sa_get_next_group(group)
1271 * Return the "next" group after the specified group from
1272 * the internal group list. NULL if there are no more.
1275 sa_get_next_group(sa_group_t group
)
1277 xmlNodePtr ngroup
= NULL
;
1278 if (group
!= NULL
) {
1279 for (ngroup
= ((xmlNodePtr
)group
)->next
; ngroup
!= NULL
;
1280 ngroup
= ngroup
->next
) {
1281 if (xmlStrcmp(ngroup
->name
, (xmlChar
*)"group") == 0)
1285 return ((sa_group_t
)ngroup
);
1289 * sa_get_share(group, sharepath)
1290 * Return the share object for the share specified. The share
1291 * must be in the specified group. Return NULL if not found.
1294 sa_get_share(sa_group_t group
, char *sharepath
)
1296 xmlNodePtr node
= NULL
;
1300 * For future scalability, this should end up building a cache
1301 * since it will get called regularly by the mountd and info
1304 if (group
!= NULL
) {
1305 for (node
= ((xmlNodePtr
)group
)->children
; node
!= NULL
;
1306 node
= node
->next
) {
1307 if (xmlStrcmp(node
->name
, (xmlChar
*)"share") == 0) {
1308 if (sharepath
== NULL
) {
1311 /* is it the correct share? */
1312 path
= xmlGetProp(node
,
1316 (xmlChar
*)sharepath
) == 0) {
1325 return ((sa_share_t
)node
);
1329 * sa_get_next_share(share)
1330 * Return the next share following the specified share
1331 * from the internal list of shares. Returns NULL if there
1332 * are no more shares. The list is relative to the same
1336 sa_get_next_share(sa_share_t share
)
1338 xmlNodePtr node
= NULL
;
1340 if (share
!= NULL
) {
1341 for (node
= ((xmlNodePtr
)share
)->next
; node
!= NULL
;
1342 node
= node
->next
) {
1343 if (xmlStrcmp(node
->name
, (xmlChar
*)"share") == 0) {
1348 return ((sa_share_t
)node
);
1352 * _sa_get_child_node(node, type)
1354 * find the child node of the specified node that has "type". This is
1355 * used to implement several internal functions.
1359 _sa_get_child_node(xmlNodePtr node
, xmlChar
*type
)
1362 for (child
= node
->xmlChildrenNode
; child
!= NULL
;
1363 child
= child
->next
)
1364 if (xmlStrcmp(child
->name
, type
) == 0)
1366 return ((xmlNodePtr
)NULL
);
1370 * find_share(group, path)
1372 * Search all the shares in the specified group for one that has the
1377 find_share(sa_group_t group
, char *sharepath
)
1382 for (share
= sa_get_share(group
, NULL
); share
!= NULL
;
1383 share
= sa_get_next_share(share
)) {
1384 path
= sa_get_share_attr(share
, "path");
1385 if (path
!= NULL
&& strcmp(path
, sharepath
) == 0) {
1386 sa_free_attr_string(path
);
1390 sa_free_attr_string(path
);
1396 * sa_get_sub_group(group)
1398 * Get the first sub-group of group. The sa_get_next_group() function
1399 * can be used to get the rest. This is currently only used for ZFS
1400 * sub-groups but could be used to implement a more general mechanism.
1404 sa_get_sub_group(sa_group_t group
)
1406 return ((sa_group_t
)_sa_get_child_node((xmlNodePtr
)group
,
1407 (xmlChar
*)"group"));
1411 * sa_find_share(sharepath)
1412 * Finds a share regardless of group. In the future, this
1413 * function should utilize a cache and hash table of some kind.
1414 * The current assumption is that a path will only be shared
1415 * once. In the future, this may change as implementation of
1416 * resource names comes into being.
1419 sa_find_share(sa_handle_t handle
, char *sharepath
)
1423 sa_share_t share
= NULL
;
1426 for (group
= sa_get_group(handle
, NULL
); group
!= NULL
&& !done
;
1427 group
= sa_get_next_group(group
)) {
1428 if (is_zfs_group(group
)) {
1430 (sa_group_t
)_sa_get_child_node((xmlNodePtr
)group
,
1431 (xmlChar
*)"group");
1433 zgroup
= sa_get_next_group(zgroup
)) {
1434 share
= find_share(zgroup
, sharepath
);
1439 share
= find_share(group
, sharepath
);
1448 * sa_check_path(group, path, strictness)
1450 * Check that path is a valid path relative to the group. Currently,
1451 * we are ignoring the group and checking only the NFS rules. Later,
1452 * we may want to use the group to then check against the protocols
1453 * enabled on the group. The strictness values mean:
1454 * SA_CHECK_NORMAL == only check newpath against shares that are active
1455 * SA_CHECK_STRICT == check newpath against both active shares and those
1456 * stored in the repository
1460 sa_check_path(sa_group_t group
, char *path
, int strictness
)
1464 handle
= sa_find_group_handle(group
);
1466 return (SA_BAD_PATH
);
1468 return (validpath(handle
, path
, strictness
));
1472 * mark_excluded_protos(group, share, flags)
1474 * Walk through all the protocols enabled for the group and check to
1475 * see if the share has any of them should be in the exclude list
1476 * based on the featureset of the protocol. If there are any, add the
1477 * "exclude" property to the share.
1480 mark_excluded_protos(sa_group_t group
, xmlNodePtr share
, uint64_t flags
)
1482 sa_optionset_t optionset
;
1483 char exclude_list
[SA_STRSIZE
];
1486 exclude_list
[0] = '\0';
1487 for (optionset
= sa_get_optionset(group
, NULL
);
1489 optionset
= sa_get_next_optionset(optionset
)) {
1492 value
= sa_get_optionset_attr(optionset
, "type");
1495 features
= sa_proto_get_featureset(value
);
1496 if (!(features
& flags
)) {
1497 (void) strlcat(exclude_list
, sep
,
1498 sizeof (exclude_list
));
1499 (void) strlcat(exclude_list
, value
,
1500 sizeof (exclude_list
));
1503 sa_free_attr_string(value
);
1505 if (exclude_list
[0] != '\0')
1506 (void) xmlSetProp(share
, (xmlChar
*)"exclude",
1507 (xmlChar
*)exclude_list
);
1511 * get_all_features(group)
1513 * Walk through all the protocols on the group and collect all
1514 * possible enabled features. This is the OR of all the featuresets.
1517 get_all_features(sa_group_t group
)
1519 sa_optionset_t optionset
;
1520 uint64_t features
= 0;
1522 for (optionset
= sa_get_optionset(group
, NULL
);
1524 optionset
= sa_get_next_optionset(optionset
)) {
1526 value
= sa_get_optionset_attr(optionset
, "type");
1529 features
|= sa_proto_get_featureset(value
);
1530 sa_free_attr_string(value
);
1537 * _sa_add_share(group, sharepath, persist, *error, flags)
1539 * Common code for all types of add_share. sa_add_share() is the
1540 * public API, we also need to be able to do this when parsing legacy
1541 * files and construction of the internal configuration while
1542 * extracting config info from SMF. "flags" indicates if some
1543 * protocols need relaxed rules while other don't. These values are
1544 * the featureset values defined in libshare.h.
1548 _sa_add_share(sa_group_t group
, char *sharepath
, int persist
, int *error
,
1551 xmlNodePtr node
= NULL
;
1554 err
= SA_OK
; /* assume success */
1556 node
= xmlNewChild((xmlNodePtr
)group
, NULL
, (xmlChar
*)"share", NULL
);
1559 *error
= SA_NO_MEMORY
;
1563 (void) xmlSetProp(node
, (xmlChar
*)"path", (xmlChar
*)sharepath
);
1564 (void) xmlSetProp(node
, (xmlChar
*)"type",
1565 persist
? (xmlChar
*)"persist" : (xmlChar
*)"transient");
1567 mark_excluded_protos(group
, node
, flags
);
1568 if (persist
!= SA_SHARE_TRANSIENT
) {
1570 * persistent shares come in two flavors: SMF and
1571 * ZFS. Sort this one out based on target group and
1572 * path type. Both NFS and SMB are supported. First,
1573 * check to see if the protocol is enabled on the
1574 * subgroup and then setup the share appropriately.
1576 if (sa_group_is_zfs(group
) &&
1577 sa_path_is_zfs(sharepath
)) {
1578 if (sa_get_optionset(group
, "nfs") != NULL
)
1579 err
= sa_zfs_set_sharenfs(group
, sharepath
, 1);
1580 else if (sa_get_optionset(group
, "smb") != NULL
)
1581 err
= sa_zfs_set_sharesmb(group
, sharepath
, 1);
1583 sa_handle_impl_t impl_handle
;
1585 (sa_handle_impl_t
)sa_find_group_handle(group
);
1586 if (impl_handle
!= NULL
) {
1587 err
= sa_commit_share(impl_handle
->scfhandle
,
1588 group
, (sa_share_t
)node
);
1590 err
= SA_SYSTEM_ERR
;
1594 if (err
== SA_NO_PERMISSION
&& persist
& SA_SHARE_PARSER
)
1595 /* called by the dfstab parser so could be a show */
1600 * we couldn't commit to the repository so undo
1601 * our internal state to reflect reality.
1603 xmlUnlinkNode(node
);
1615 * sa_add_share(group, sharepath, persist, *error)
1617 * Add a new share object to the specified group. The share will
1618 * have the specified sharepath and will only be constructed if
1619 * it is a valid path to be shared. NULL is returned on error
1620 * and a detailed error value will be returned via the error
1624 sa_add_share(sa_group_t group
, char *sharepath
, int persist
, int *error
)
1626 xmlNodePtr node
= NULL
;
1627 int strictness
= SA_CHECK_NORMAL
;
1629 uint64_t special
= 0;
1633 * If the share is to be permanent, use strict checking so a
1634 * bad config doesn't get created. Transient shares only need
1635 * to check against the currently active
1636 * shares. SA_SHARE_PARSER is a modifier used internally to
1637 * indicate that we are being called by the dfstab parser and
1638 * that we need strict checking in all cases. Normally persist
1639 * is in integer value but SA_SHARE_PARSER may be or'd into
1640 * it as an override.
1642 if (persist
& SA_SHARE_PARSER
|| persist
== SA_SHARE_PERMANENT
)
1643 strictness
= SA_CHECK_STRICT
;
1645 handle
= sa_find_group_handle(group
);
1648 * need to determine if the share is valid. The rules are:
1649 * - The path must not already exist
1650 * - The path must not be a subdir or parent dir of an
1651 * existing path unless at least one protocol allows it.
1652 * The sub/parent check is done in sa_check_path().
1655 if (sa_find_share(handle
, sharepath
) == NULL
) {
1656 *error
= sa_check_path(group
, sharepath
, strictness
);
1657 features
= get_all_features(group
);
1659 case SA_PATH_IS_SUBDIR
:
1660 if (features
& SA_FEATURE_ALLOWSUBDIRS
)
1661 special
|= SA_FEATURE_ALLOWSUBDIRS
;
1663 case SA_PATH_IS_PARENTDIR
:
1664 if (features
& SA_FEATURE_ALLOWPARDIRS
)
1665 special
|= SA_FEATURE_ALLOWPARDIRS
;
1668 if (*error
== SA_OK
|| special
!= SA_FEATURE_NONE
)
1669 node
= _sa_add_share(group
, sharepath
, persist
,
1672 *error
= SA_DUPLICATE_NAME
;
1675 return ((sa_share_t
)node
);
1679 * sa_enable_share(share, protocol)
1680 * Enable the specified share to the specified protocol.
1681 * If protocol is NULL, then all protocols.
1684 sa_enable_share(sa_share_t share
, char *protocol
)
1691 sharepath
= sa_get_share_attr(share
, "path");
1692 if (sharepath
== NULL
)
1693 return (SA_NO_MEMORY
);
1694 if (stat(sharepath
, &st
) < 0) {
1695 err
= SA_NO_SUCH_PATH
;
1697 /* tell the server about the share */
1698 if (protocol
!= NULL
) {
1699 if (excluded_protocol(share
, protocol
))
1702 /* lookup protocol specific handler */
1703 err
= sa_proto_share(protocol
, share
);
1705 (void) sa_set_share_attr(share
,
1708 /* Tell all protocols about the share */
1710 sa_optionset_t optionset
;
1712 group
= sa_get_parent_group(share
);
1714 for (optionset
= sa_get_optionset(group
, NULL
);
1716 optionset
= sa_get_next_optionset(optionset
)) {
1718 proto
= sa_get_optionset_attr(optionset
,
1720 if (proto
!= NULL
) {
1721 if (!excluded_protocol(share
, proto
)) {
1722 ret
= sa_proto_share(proto
,
1727 sa_free_attr_string(proto
);
1730 (void) sa_set_share_attr(share
, "shared", "true");
1734 if (sharepath
!= NULL
)
1735 sa_free_attr_string(sharepath
);
1740 * sa_disable_share(share, protocol)
1741 * Disable the specified share to the specified protocol. If
1742 * protocol is NULL, then all protocols that are enabled for the
1743 * share should be disabled.
1746 sa_disable_share(sa_share_t share
, char *protocol
)
1752 path
= sa_get_share_attr(share
, "path");
1754 if (protocol
!= NULL
) {
1755 ret
= sa_proto_unshare(share
, protocol
, path
);
1757 /* need to do all protocols */
1759 sa_optionset_t optionset
;
1761 group
= sa_get_parent_group(share
);
1763 /* Tell all protocols about the share */
1764 for (optionset
= sa_get_optionset(group
, NULL
);
1766 optionset
= sa_get_next_optionset(optionset
)) {
1769 proto
= sa_get_optionset_attr(optionset
, "type");
1770 if (proto
!= NULL
) {
1771 err
= sa_proto_unshare(share
, proto
, path
);
1774 sa_free_attr_string(proto
);
1779 (void) sa_set_share_attr(share
, "shared", NULL
);
1781 sa_free_attr_string(path
);
1786 * sa_remove_share(share)
1788 * remove the specified share from its containing group.
1789 * Remove from the SMF or ZFS configuration space.
1793 sa_remove_share(sa_share_t share
)
1802 type
= sa_get_share_attr(share
, "type");
1803 group
= sa_get_parent_group(share
);
1804 zfs
= sa_get_group_attr(group
, "zfs");
1805 groupname
= sa_get_group_attr(group
, "name");
1806 if (type
!= NULL
&& strcmp(type
, "persist") != 0)
1809 sa_free_attr_string(type
);
1811 /* remove the node from its group then free the memory */
1814 * need to test if "busy"
1816 /* only do SMF action if permanent */
1817 if (!transient
|| zfs
!= NULL
) {
1818 /* remove from legacy dfstab as well as possible SMF */
1819 ret
= sa_delete_legacy(share
, NULL
);
1821 if (!sa_group_is_zfs(group
)) {
1822 sa_handle_impl_t impl_handle
;
1823 impl_handle
= (sa_handle_impl_t
)
1824 sa_find_group_handle(group
);
1825 if (impl_handle
!= NULL
) {
1826 ret
= sa_delete_share(
1827 impl_handle
->scfhandle
, group
,
1830 ret
= SA_SYSTEM_ERR
;
1833 char *sharepath
= sa_get_share_attr(share
,
1835 if (sharepath
!= NULL
) {
1836 ret
= sa_zfs_set_sharenfs(group
,
1838 sa_free_attr_string(sharepath
);
1843 if (groupname
!= NULL
)
1844 sa_free_attr_string(groupname
);
1846 sa_free_attr_string(zfs
);
1848 xmlUnlinkNode((xmlNodePtr
)share
);
1849 xmlFreeNode((xmlNodePtr
)share
);
1854 * sa_move_share(group, share)
1856 * move the specified share to the specified group. Update SMF
1861 sa_move_share(sa_group_t group
, sa_share_t share
)
1863 sa_group_t oldgroup
;
1866 /* remove the node from its group then free the memory */
1868 oldgroup
= sa_get_parent_group(share
);
1869 if (oldgroup
!= group
) {
1870 sa_handle_impl_t impl_handle
;
1871 xmlUnlinkNode((xmlNodePtr
)share
);
1873 * now that the share isn't in its old group, add to
1876 (void) xmlAddChild((xmlNodePtr
)group
, (xmlNodePtr
)share
);
1877 /* need to deal with SMF */
1878 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
1879 if (impl_handle
!= NULL
) {
1881 * need to remove from old group first and then add to
1882 * new group. Ideally, we would do the other order but
1883 * need to avoid having the share in two groups at the
1886 ret
= sa_delete_share(impl_handle
->scfhandle
, oldgroup
,
1889 ret
= sa_commit_share(impl_handle
->scfhandle
,
1892 ret
= SA_SYSTEM_ERR
;
1899 * sa_get_parent_group(share)
1901 * Return the containing group for the share. If a group was actually
1902 * passed in, we don't want a parent so return NULL.
1906 sa_get_parent_group(sa_share_t share
)
1908 xmlNodePtr node
= NULL
;
1909 if (share
!= NULL
) {
1910 node
= ((xmlNodePtr
)share
)->parent
;
1912 * make sure parent is a group and not sharecfg since
1913 * we may be cheating and passing in a group.
1914 * Eventually, groups of groups might come into being.
1917 xmlStrcmp(node
->name
, (xmlChar
*)"sharecfg") == 0)
1920 return ((sa_group_t
)node
);
1924 * _sa_create_group(impl_handle, groupname)
1926 * Create a group in the document. The caller will need to deal with
1927 * configuration store and activation.
1931 _sa_create_group(sa_handle_impl_t impl_handle
, char *groupname
)
1933 xmlNodePtr node
= NULL
;
1935 if (sa_valid_group_name(groupname
)) {
1936 node
= xmlNewChild(impl_handle
->tree
, NULL
, (xmlChar
*)"group",
1939 (void) xmlSetProp(node
, (xmlChar
*)"name",
1940 (xmlChar
*)groupname
);
1941 (void) xmlSetProp(node
, (xmlChar
*)"state",
1942 (xmlChar
*)"enabled");
1945 return ((sa_group_t
)node
);
1949 * _sa_create_zfs_group(group, groupname)
1951 * Create a ZFS subgroup under the specified group. This may
1952 * eventually form the basis of general sub-groups, but is currently
1953 * restricted to ZFS.
1956 _sa_create_zfs_group(sa_group_t group
, char *groupname
)
1958 xmlNodePtr node
= NULL
;
1960 node
= xmlNewChild((xmlNodePtr
)group
, NULL
, (xmlChar
*)"group", NULL
);
1962 (void) xmlSetProp(node
, (xmlChar
*)"name",
1963 (xmlChar
*)groupname
);
1964 (void) xmlSetProp(node
, (xmlChar
*)"state",
1965 (xmlChar
*)"enabled");
1968 return ((sa_group_t
)node
);
1972 * sa_create_group(groupname, *error)
1974 * Create a new group with groupname. Need to validate that it is a
1975 * legal name for SMF and the construct the SMF service instance of
1976 * svc:/network/shares/group to implement the group. All necessary
1977 * operational properties must be added to the group at this point
1978 * (via the SMF transaction model).
1981 sa_create_group(sa_handle_t handle
, char *groupname
, int *error
)
1983 xmlNodePtr node
= NULL
;
1986 char rbacstr
[SA_STRSIZE
];
1987 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
1991 if (impl_handle
== NULL
|| impl_handle
->scfhandle
== NULL
) {
1992 ret
= SA_SYSTEM_ERR
;
1996 group
= sa_get_group(handle
, groupname
);
1997 if (group
!= NULL
) {
1998 ret
= SA_DUPLICATE_NAME
;
2000 if (sa_valid_group_name(groupname
)) {
2001 node
= xmlNewChild(impl_handle
->tree
, NULL
,
2002 (xmlChar
*)"group", NULL
);
2004 (void) xmlSetProp(node
, (xmlChar
*)"name",
2005 (xmlChar
*)groupname
);
2006 /* default to the group being enabled */
2007 (void) xmlSetProp(node
, (xmlChar
*)"state",
2008 (xmlChar
*)"enabled");
2009 ret
= sa_create_instance(impl_handle
->scfhandle
,
2012 ret
= sa_start_transaction(
2013 impl_handle
->scfhandle
,
2017 ret
= sa_set_property(
2018 impl_handle
->scfhandle
,
2019 "state", "enabled");
2021 ret
= sa_end_transaction(
2022 impl_handle
->scfhandle
,
2025 sa_abort_transaction(
2026 impl_handle
->scfhandle
);
2030 /* initialize the RBAC strings */
2031 ret
= sa_start_transaction(
2032 impl_handle
->scfhandle
,
2035 (void) snprintf(rbacstr
,
2036 sizeof (rbacstr
), "%s.%s",
2037 SA_RBAC_MANAGE
, groupname
);
2038 ret
= sa_set_property(
2039 impl_handle
->scfhandle
,
2040 "action_authorization",
2044 (void) snprintf(rbacstr
,
2045 sizeof (rbacstr
), "%s.%s",
2046 SA_RBAC_VALUE
, groupname
);
2047 ret
= sa_set_property(
2048 impl_handle
->scfhandle
,
2049 "value_authorization",
2053 ret
= sa_end_transaction(
2054 impl_handle
->scfhandle
,
2057 sa_abort_transaction(
2058 impl_handle
->scfhandle
);
2063 * Couldn't commit the group
2064 * so we need to undo
2067 xmlUnlinkNode(node
);
2075 ret
= SA_INVALID_NAME
;
2081 return ((sa_group_t
)node
);
2085 * sa_remove_group(group)
2087 * Remove the specified group. This deletes from the SMF repository.
2088 * All property groups and properties are removed.
2092 sa_remove_group(sa_group_t group
)
2096 sa_handle_impl_t impl_handle
;
2098 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2099 if (impl_handle
!= NULL
) {
2100 name
= sa_get_group_attr(group
, "name");
2102 ret
= sa_delete_instance(impl_handle
->scfhandle
, name
);
2103 sa_free_attr_string(name
);
2105 xmlUnlinkNode((xmlNodePtr
)group
); /* make sure unlinked */
2106 xmlFreeNode((xmlNodePtr
)group
); /* now it is gone */
2108 ret
= SA_SYSTEM_ERR
;
2114 * sa_update_config()
2116 * Used to update legacy files that need to be updated in bulk
2117 * Currently, this is a placeholder and will go away in a future
2122 sa_update_config(sa_handle_t handle
)
2125 * do legacy files first so we can tell when they change.
2126 * This will go away when we start updating individual records
2127 * rather than the whole file.
2129 update_legacy_config(handle
);
2134 * get_node_attr(node, tag)
2136 * Get the specified tag(attribute) if it exists on the node. This is
2137 * used internally by a number of attribute oriented functions.
2141 get_node_attr(void *nodehdl
, char *tag
)
2143 xmlNodePtr node
= (xmlNodePtr
)nodehdl
;
2144 xmlChar
*name
= NULL
;
2147 name
= xmlGetProp(node
, (xmlChar
*)tag
);
2148 return ((char *)name
);
2152 * set_node_attr(node, tag)
2154 * Set the specified tag(attribute) to the specified value This is
2155 * used internally by a number of attribute oriented functions. It
2156 * doesn't update the repository, only the internal document state.
2160 set_node_attr(void *nodehdl
, char *tag
, char *value
)
2162 xmlNodePtr node
= (xmlNodePtr
)nodehdl
;
2163 if (node
!= NULL
&& tag
!= NULL
) {
2165 (void) xmlSetProp(node
, (xmlChar
*)tag
,
2168 (void) xmlUnsetProp(node
, (xmlChar
*)tag
);
2173 * sa_get_group_attr(group, tag)
2175 * Get the specied attribute, if defined, for the group.
2179 sa_get_group_attr(sa_group_t group
, char *tag
)
2181 return (get_node_attr((void *)group
, tag
));
2185 * sa_set_group_attr(group, tag, value)
2187 * set the specified tag/attribute on the group using value as its
2190 * This will result in setting the property in the SMF repository as
2191 * well as in the internal document.
2195 sa_set_group_attr(sa_group_t group
, char *tag
, char *value
)
2199 sa_handle_impl_t impl_handle
;
2202 * ZFS group/subgroup doesn't need the handle so shortcut.
2204 if (sa_group_is_zfs(group
)) {
2205 set_node_attr((void *)group
, tag
, value
);
2209 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2210 if (impl_handle
!= NULL
) {
2211 groupname
= sa_get_group_attr(group
, "name");
2212 ret
= sa_get_instance(impl_handle
->scfhandle
, groupname
);
2214 set_node_attr((void *)group
, tag
, value
);
2215 ret
= sa_start_transaction(impl_handle
->scfhandle
,
2218 ret
= sa_set_property(impl_handle
->scfhandle
,
2221 ret
= sa_end_transaction(
2222 impl_handle
->scfhandle
,
2225 sa_abort_transaction(
2226 impl_handle
->scfhandle
);
2228 if (ret
== SA_SYSTEM_ERR
)
2229 ret
= SA_NO_PERMISSION
;
2231 if (groupname
!= NULL
)
2232 sa_free_attr_string(groupname
);
2234 ret
= SA_SYSTEM_ERR
;
2240 * sa_get_share_attr(share, tag)
2242 * Return the value of the tag/attribute set on the specified
2243 * share. Returns NULL if the tag doesn't exist.
2247 sa_get_share_attr(sa_share_t share
, char *tag
)
2249 return (get_node_attr((void *)share
, tag
));
2253 * _sa_set_share_description(share, description)
2255 * Add a description tag with text contents to the specified share. A
2256 * separate XML tag is used rather than a property. This can also be
2257 * used with resources.
2261 _sa_set_share_description(void *share
, char *content
)
2264 node
= xmlNewChild((xmlNodePtr
)share
, NULL
, (xmlChar
*)"description",
2266 xmlNodeSetContent(node
, (xmlChar
*)content
);
2271 * sa_set_share_attr(share, tag, value)
2273 * Set the share attribute specified by tag to the specified value. In
2274 * the case of "resource", enforce a no duplicates in a group rule. If
2275 * the share is not transient, commit the changes to the repository
2276 * else just update the share internally.
2280 sa_set_share_attr(sa_share_t share
, char *tag
, char *value
)
2283 sa_share_t resource
;
2286 group
= sa_get_parent_group(share
);
2289 * There are some attributes that may have specific
2290 * restrictions on them. Initially, only "resource" has
2291 * special meaning that needs to be checked. Only one instance
2292 * of a resource name may exist within a group.
2295 if (strcmp(tag
, "resource") == 0) {
2296 resource
= sa_get_resource(group
, value
);
2297 if (resource
!= share
&& resource
!= NULL
)
2298 ret
= SA_DUPLICATE_NAME
;
2301 set_node_attr((void *)share
, tag
, value
);
2302 if (group
!= NULL
) {
2304 /* we can probably optimize this some */
2305 type
= sa_get_share_attr(share
, "type");
2306 if (type
== NULL
|| strcmp(type
, "transient") != 0) {
2307 sa_handle_impl_t impl_handle
;
2309 (sa_handle_impl_t
)sa_find_group_handle(
2311 if (impl_handle
!= NULL
) {
2312 ret
= sa_commit_share(
2313 impl_handle
->scfhandle
, group
,
2316 ret
= SA_SYSTEM_ERR
;
2320 sa_free_attr_string(type
);
2327 * sa_get_property_attr(prop, tag)
2329 * Get the value of the specified property attribute. Standard
2330 * attributes are "type" and "value".
2334 sa_get_property_attr(sa_property_t prop
, char *tag
)
2336 return (get_node_attr((void *)prop
, tag
));
2340 * sa_get_optionset_attr(prop, tag)
2342 * Get the value of the specified property attribute. Standard
2343 * attribute is "type".
2347 sa_get_optionset_attr(sa_property_t optionset
, char *tag
)
2349 return (get_node_attr((void *)optionset
, tag
));
2354 * sa_set_optionset_attr(optionset, tag, value)
2356 * Set the specified attribute(tag) to the specified value on the
2361 sa_set_optionset_attr(sa_group_t optionset
, char *tag
, char *value
)
2363 set_node_attr((void *)optionset
, tag
, value
);
2367 * sa_free_attr_string(string)
2369 * Free the string that was returned in one of the sa_get_*_attr()
2374 sa_free_attr_string(char *string
)
2376 xmlFree((xmlChar
*)string
);
2380 * sa_get_optionset(group, proto)
2382 * Return the optionset, if it exists, that is associated with the
2383 * specified protocol.
2387 sa_get_optionset(void *group
, char *proto
)
2390 xmlChar
*value
= NULL
;
2392 for (node
= ((xmlNodePtr
)group
)->children
; node
!= NULL
;
2393 node
= node
->next
) {
2394 if (xmlStrcmp(node
->name
, (xmlChar
*)"optionset") == 0) {
2395 value
= xmlGetProp(node
, (xmlChar
*)"type");
2396 if (proto
!= NULL
) {
2397 if (value
!= NULL
&&
2398 xmlStrcmp(value
, (xmlChar
*)proto
) == 0) {
2401 if (value
!= NULL
) {
2412 return ((sa_optionset_t
)node
);
2416 * sa_get_next_optionset(optionset)
2418 * Return the next optionset in the group. NULL if this was the last.
2422 sa_get_next_optionset(sa_optionset_t optionset
)
2426 for (node
= ((xmlNodePtr
)optionset
)->next
; node
!= NULL
;
2427 node
= node
->next
) {
2428 if (xmlStrcmp(node
->name
, (xmlChar
*)"optionset") == 0) {
2432 return ((sa_optionset_t
)node
);
2436 * sa_get_security(group, sectype, proto)
2438 * Return the security optionset. The internal name is a hold over
2439 * from the implementation and will be changed before the API is
2440 * finalized. This is really a named optionset that can be negotiated
2441 * as a group of properties (like NFS security options).
2445 sa_get_security(sa_group_t group
, char *sectype
, char *proto
)
2448 xmlChar
*value
= NULL
;
2450 for (node
= ((xmlNodePtr
)group
)->children
; node
!= NULL
;
2451 node
= node
->next
) {
2452 if (xmlStrcmp(node
->name
, (xmlChar
*)"security") == 0) {
2453 if (proto
!= NULL
) {
2454 value
= xmlGetProp(node
, (xmlChar
*)"type");
2455 if (value
== NULL
||
2457 xmlStrcmp(value
, (xmlChar
*)proto
) != 0)) {
2458 /* it doesn't match so continue */
2464 if (value
!= NULL
) {
2468 /* potential match */
2469 if (sectype
!= NULL
) {
2470 value
= xmlGetProp(node
, (xmlChar
*)"sectype");
2471 if (value
!= NULL
&&
2472 xmlStrcmp(value
, (xmlChar
*)sectype
) == 0) {
2479 if (value
!= NULL
) {
2486 return ((sa_security_t
)node
);
2490 * sa_get_next_security(security)
2492 * Get the next security optionset if one exists.
2496 sa_get_next_security(sa_security_t security
)
2500 for (node
= ((xmlNodePtr
)security
)->next
; node
!= NULL
;
2501 node
= node
->next
) {
2502 if (xmlStrcmp(node
->name
, (xmlChar
*)"security") == 0) {
2506 return ((sa_security_t
)node
);
2510 * sa_get_property(optionset, prop)
2512 * Get the property object with the name specified in prop from the
2517 sa_get_property(sa_optionset_t optionset
, char *prop
)
2519 xmlNodePtr node
= (xmlNodePtr
)optionset
;
2520 xmlChar
*value
= NULL
;
2522 if (optionset
== NULL
)
2525 for (node
= node
->children
; node
!= NULL
;
2526 node
= node
->next
) {
2527 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
2530 value
= xmlGetProp(node
, (xmlChar
*)"type");
2531 if (value
!= NULL
&&
2532 xmlStrcmp(value
, (xmlChar
*)prop
) == 0) {
2535 if (value
!= NULL
) {
2543 if (node
!= NULL
&& xmlStrcmp(node
->name
, (xmlChar
*)"option") != 0) {
2545 * avoid a non option node -- it is possible to be a
2550 return ((sa_property_t
)node
);
2554 * sa_get_next_property(property)
2556 * Get the next property following the specified property. NULL if
2557 * this was the last.
2561 sa_get_next_property(sa_property_t property
)
2565 for (node
= ((xmlNodePtr
)property
)->next
; node
!= NULL
;
2566 node
= node
->next
) {
2567 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
2571 return ((sa_property_t
)node
);
2575 * sa_set_share_description(share, content)
2577 * Set the description of share to content.
2581 sa_set_share_description(sa_share_t share
, char *content
)
2587 for (node
= ((xmlNodePtr
)share
)->children
; node
!= NULL
;
2588 node
= node
->next
) {
2589 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0) {
2593 /* no existing description but want to add */
2594 if (node
== NULL
&& content
!= NULL
) {
2595 /* add a description */
2596 node
= _sa_set_share_description(share
, content
);
2597 } else if (node
!= NULL
&& content
!= NULL
) {
2598 /* update a description */
2599 xmlNodeSetContent(node
, (xmlChar
*)content
);
2600 } else if (node
!= NULL
&& content
== NULL
) {
2601 /* remove an existing description */
2602 xmlUnlinkNode(node
);
2605 group
= sa_get_parent_group(share
);
2606 if (group
!= NULL
&&
2607 sa_is_persistent(share
) && (!sa_group_is_zfs(group
))) {
2608 sa_handle_impl_t impl_handle
;
2609 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2610 if (impl_handle
!= NULL
) {
2611 ret
= sa_commit_share(impl_handle
->scfhandle
, group
,
2614 ret
= SA_SYSTEM_ERR
;
2621 * fixproblemchars(string)
2623 * don't want any newline or tab characters in the text since these
2624 * could break display of data and legacy file formats.
2627 fixproblemchars(char *str
)
2630 for (c
= *str
; c
!= '\0'; c
= *++str
) {
2631 if (c
== '\t' || c
== '\n')
2639 * sa_get_share_description(share)
2641 * Return the description text for the specified share if it
2642 * exists. NULL if no description exists.
2646 sa_get_share_description(sa_share_t share
)
2648 xmlChar
*description
= NULL
;
2651 for (node
= ((xmlNodePtr
)share
)->children
; node
!= NULL
;
2652 node
= node
->next
) {
2653 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0) {
2658 description
= xmlNodeGetContent(node
);
2659 fixproblemchars((char *)description
);
2661 return ((char *)description
);
2665 * sa_free(share_description(description)
2667 * Free the description string.
2671 sa_free_share_description(char *description
)
2673 xmlFree((xmlChar
*)description
);
2677 * sa_create_optionset(group, proto)
2679 * Create an optionset for the specified protocol in the specied
2680 * group. This is manifested as a property group within SMF.
2684 sa_create_optionset(sa_group_t group
, char *proto
)
2686 sa_optionset_t optionset
;
2687 sa_group_t parent
= group
;
2688 sa_share_t share
= NULL
;
2692 optionset
= sa_get_optionset(group
, proto
);
2693 if (optionset
!= NULL
) {
2694 /* can't have a duplicate protocol */
2698 * Account for resource names being slightly
2701 if (sa_is_share(group
)) {
2703 * Transient shares do not have an "id" so not an
2704 * error to not find one.
2706 id
= sa_get_share_attr((sa_share_t
)group
, "id");
2707 } else if (sa_is_resource(group
)) {
2708 share
= sa_get_resource_parent(
2709 (sa_resource_t
)group
);
2710 id
= sa_get_resource_attr(share
, "id");
2712 /* id can be NULL if the group is transient (ZFS) */
2713 if (id
== NULL
&& sa_is_persistent(group
))
2716 if (err
== SA_NO_MEMORY
) {
2718 * Couldn't get the id for the share or
2719 * resource. While this could be a
2720 * configuration issue, it is most likely an
2721 * out of memory. In any case, fail the create.
2726 optionset
= (sa_optionset_t
)xmlNewChild((xmlNodePtr
)group
,
2727 NULL
, (xmlChar
*)"optionset", NULL
);
2729 * only put to repository if on a group and we were
2730 * able to create an optionset.
2732 if (optionset
!= NULL
) {
2733 char oname
[SA_STRSIZE
];
2737 * Need to get parent group in all cases, but also get
2738 * the share if this is a resource.
2740 if (sa_is_share(group
)) {
2741 parent
= sa_get_parent_group((sa_share_t
)group
);
2742 } else if (sa_is_resource(group
)) {
2743 share
= sa_get_resource_parent(
2744 (sa_resource_t
)group
);
2745 parent
= sa_get_parent_group(share
);
2748 sa_set_optionset_attr(optionset
, "type", proto
);
2750 (void) sa_optionset_name(optionset
, oname
,
2751 sizeof (oname
), id
);
2752 groupname
= sa_get_group_attr(parent
, "name");
2753 if (groupname
!= NULL
&& sa_is_persistent(group
)) {
2754 sa_handle_impl_t impl_handle
;
2756 (sa_handle_impl_t
)sa_find_group_handle(
2758 assert(impl_handle
!= NULL
);
2759 if (impl_handle
!= NULL
) {
2760 (void) sa_get_instance(
2761 impl_handle
->scfhandle
, groupname
);
2762 (void) sa_create_pgroup(
2763 impl_handle
->scfhandle
, oname
);
2766 if (groupname
!= NULL
)
2767 sa_free_attr_string(groupname
);
2772 sa_free_attr_string(id
);
2777 * sa_get_property_parent(property)
2779 * Given a property, return the object it is a property of. This will
2780 * be an optionset of some type.
2783 static sa_optionset_t
2784 sa_get_property_parent(sa_property_t property
)
2786 xmlNodePtr node
= NULL
;
2788 if (property
!= NULL
)
2789 node
= ((xmlNodePtr
)property
)->parent
;
2790 return ((sa_optionset_t
)node
);
2794 * sa_get_optionset_parent(optionset)
2796 * Return the parent of the specified optionset. This could be a group
2801 sa_get_optionset_parent(sa_optionset_t optionset
)
2803 xmlNodePtr node
= NULL
;
2805 if (optionset
!= NULL
)
2806 node
= ((xmlNodePtr
)optionset
)->parent
;
2807 return ((sa_group_t
)node
);
2811 * zfs_needs_update(share)
2813 * In order to avoid making multiple updates to a ZFS share when
2814 * setting properties, the share attribute "changed" will be set to
2815 * true when a property is added or modified. When done adding
2816 * properties, we can then detect that an update is needed. We then
2817 * clear the state here to detect additional changes.
2821 zfs_needs_update(sa_share_t share
)
2826 attr
= sa_get_share_attr(share
, "changed");
2828 sa_free_attr_string(attr
);
2831 set_node_attr((void *)share
, "changed", NULL
);
2836 * zfs_set_update(share)
2838 * Set the changed attribute of the share to true.
2842 zfs_set_update(sa_share_t share
)
2844 set_node_attr((void *)share
, "changed", "true");
2848 * sa_commit_properties(optionset, clear)
2850 * Check if SMF or ZFS config and either update or abort the pending
2855 sa_commit_properties(sa_optionset_t optionset
, int clear
)
2860 int needsupdate
= 0;
2862 sa_handle_impl_t impl_handle
;
2864 group
= sa_get_optionset_parent(optionset
);
2865 if (group
!= NULL
&& (sa_is_share(group
) || is_zfs_group(group
))) {
2866 /* only update ZFS if on a share */
2867 parent
= sa_get_parent_group(group
);
2869 if (parent
!= NULL
&& is_zfs_group(parent
))
2870 needsupdate
= zfs_needs_update(group
);
2875 if (!clear
&& needsupdate
)
2876 ret
= sa_zfs_update((sa_share_t
)group
);
2878 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2879 if (impl_handle
!= NULL
) {
2881 (void) sa_abort_transaction(
2882 impl_handle
->scfhandle
);
2884 ret
= sa_end_transaction(
2885 impl_handle
->scfhandle
, impl_handle
);
2888 ret
= SA_SYSTEM_ERR
;
2895 * sa_destroy_optionset(optionset)
2897 * Remove the optionset from its group. Update the repository to
2898 * reflect this change.
2902 sa_destroy_optionset(sa_optionset_t optionset
)
2904 char name
[SA_STRSIZE
];
2911 /* now delete the prop group */
2912 group
= sa_get_optionset_parent(optionset
);
2913 if (group
!= NULL
) {
2914 if (sa_is_resource(group
)) {
2915 sa_resource_t resource
= group
;
2916 sa_share_t share
= sa_get_resource_parent(resource
);
2917 group
= sa_get_parent_group(share
);
2918 id
= sa_get_share_attr(share
, "id");
2919 } else if (sa_is_share(group
)) {
2920 id
= sa_get_share_attr((sa_share_t
)group
, "id");
2922 ispersist
= sa_is_persistent(group
);
2925 sa_handle_impl_t impl_handle
;
2926 len
= sa_optionset_name(optionset
, name
, sizeof (name
), id
);
2927 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2928 if (impl_handle
!= NULL
) {
2930 ret
= sa_delete_pgroup(impl_handle
->scfhandle
,
2934 ret
= SA_SYSTEM_ERR
;
2937 xmlUnlinkNode((xmlNodePtr
)optionset
);
2938 xmlFreeNode((xmlNodePtr
)optionset
);
2940 sa_free_attr_string(id
);
2944 /* private to the implementation */
2946 _sa_remove_optionset(sa_optionset_t optionset
)
2950 xmlUnlinkNode((xmlNodePtr
)optionset
);
2951 xmlFreeNode((xmlNodePtr
)optionset
);
2956 * sa_create_security(group, sectype, proto)
2958 * Create a security optionset (one that has a type name and a
2959 * proto). Security is left over from a pure NFS implementation. The
2960 * naming will change in the future when the API is released.
2963 sa_create_security(sa_group_t group
, char *sectype
, char *proto
)
2965 sa_security_t security
;
2968 char *groupname
= NULL
;
2970 if (group
!= NULL
&& sa_is_share(group
)) {
2971 id
= sa_get_share_attr((sa_share_t
)group
, "id");
2972 parent
= sa_get_parent_group(group
);
2974 groupname
= sa_get_group_attr(parent
, "name");
2975 } else if (group
!= NULL
) {
2976 groupname
= sa_get_group_attr(group
, "name");
2979 security
= sa_get_security(group
, sectype
, proto
);
2980 if (security
!= NULL
) {
2981 /* can't have a duplicate security option */
2984 security
= (sa_security_t
)xmlNewChild((xmlNodePtr
)group
,
2985 NULL
, (xmlChar
*)"security", NULL
);
2986 if (security
!= NULL
) {
2987 char oname
[SA_STRSIZE
];
2988 sa_set_security_attr(security
, "type", proto
);
2990 sa_set_security_attr(security
, "sectype", sectype
);
2991 (void) sa_security_name(security
, oname
,
2992 sizeof (oname
), id
);
2993 if (groupname
!= NULL
&& sa_is_persistent(group
)) {
2994 sa_handle_impl_t impl_handle
;
2996 (sa_handle_impl_t
)sa_find_group_handle(
2998 if (impl_handle
!= NULL
) {
2999 (void) sa_get_instance(
3000 impl_handle
->scfhandle
, groupname
);
3001 (void) sa_create_pgroup(
3002 impl_handle
->scfhandle
, oname
);
3008 sa_free_attr_string(id
);
3009 if (groupname
!= NULL
)
3010 sa_free_attr_string(groupname
);
3015 * sa_destroy_security(security)
3017 * Remove the specified optionset from the document and the
3022 sa_destroy_security(sa_security_t security
)
3024 char name
[SA_STRSIZE
];
3032 group
= sa_get_optionset_parent(security
);
3035 iszfs
= sa_group_is_zfs(group
);
3037 if (group
!= NULL
&& !iszfs
) {
3038 if (sa_is_share(group
))
3039 ispersist
= sa_is_persistent(group
);
3040 id
= sa_get_share_attr((sa_share_t
)group
, "id");
3043 len
= sa_security_name(security
, name
, sizeof (name
), id
);
3044 if (!iszfs
&& len
> 0) {
3045 sa_handle_impl_t impl_handle
;
3047 (sa_handle_impl_t
)sa_find_group_handle(group
);
3048 if (impl_handle
!= NULL
) {
3049 ret
= sa_delete_pgroup(impl_handle
->scfhandle
,
3052 ret
= SA_SYSTEM_ERR
;
3056 xmlUnlinkNode((xmlNodePtr
)security
);
3057 xmlFreeNode((xmlNodePtr
)security
);
3059 ret
= sa_zfs_update(group
);
3061 sa_free_attr_string(id
);
3066 * sa_get_security_attr(optionset, tag)
3068 * Return the specified attribute value from the optionset.
3072 sa_get_security_attr(sa_property_t optionset
, char *tag
)
3074 return (get_node_attr((void *)optionset
, tag
));
3079 * sa_set_security_attr(optionset, tag, value)
3081 * Set the optioset attribute specied by tag to the specified value.
3085 sa_set_security_attr(sa_group_t optionset
, char *tag
, char *value
)
3087 set_node_attr((void *)optionset
, tag
, value
);
3091 * is_nodetype(node, type)
3093 * Check to see if node is of the type specified.
3097 is_nodetype(void *node
, char *type
)
3099 return (strcmp((char *)((xmlNodePtr
)node
)->name
, type
) == 0);
3105 * Add or update a property. Pulled out of sa_set_prop_by_prop for
3109 add_or_update(scfutilhandle_t
*scf_handle
, int type
, scf_value_t
*value
,
3110 scf_transaction_entry_t
*entry
, char *name
, char *valstr
)
3112 int ret
= SA_SYSTEM_ERR
;
3114 if (value
!= NULL
) {
3115 if (type
== SA_PROP_OP_ADD
)
3116 ret
= scf_transaction_property_new(scf_handle
->trans
,
3117 entry
, name
, SCF_TYPE_ASTRING
);
3119 ret
= scf_transaction_property_change(scf_handle
->trans
,
3120 entry
, name
, SCF_TYPE_ASTRING
);
3122 ret
= scf_value_set_astring(value
, valstr
);
3124 ret
= scf_entry_add_value(entry
, value
);
3127 scf_value_destroy(value
);
3129 scf_entry_destroy(entry
);
3132 return (SA_SYSTEM_ERR
);
3136 * sa_set_prop_by_prop(optionset, group, prop, type)
3138 * Add/remove/update the specified property prop into the optionset or
3139 * share. If a share, sort out which property group based on GUID. In
3140 * all cases, the appropriate transaction is set (or ZFS share is
3141 * marked as needing an update)
3145 sa_set_prop_by_prop(sa_optionset_t optionset
, sa_group_t group
,
3146 sa_property_t prop
, int type
)
3151 scf_transaction_entry_t
*entry
;
3153 int opttype
; /* 1 == optionset, 0 == security */
3156 sa_group_t parent
= NULL
;
3157 sa_share_t share
= NULL
;
3158 sa_handle_impl_t impl_handle
;
3159 scfutilhandle_t
*scf_handle
;
3161 if (!sa_is_persistent(group
)) {
3163 * if the group/share is not persistent we don't need
3164 * to do anything here
3168 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
3169 if (impl_handle
== NULL
|| impl_handle
->scfhandle
== NULL
)
3170 return (SA_SYSTEM_ERR
);
3171 scf_handle
= impl_handle
->scfhandle
;
3172 name
= sa_get_property_attr(prop
, "type");
3173 valstr
= sa_get_property_attr(prop
, "value");
3174 entry
= scf_entry_create(scf_handle
->handle
);
3175 opttype
= is_nodetype((void *)optionset
, "optionset");
3178 * Check for share vs. resource since they need slightly
3179 * different treatment given the hierarchy.
3181 if (valstr
!= NULL
&& entry
!= NULL
) {
3182 if (sa_is_share(group
)) {
3183 parent
= sa_get_parent_group(group
);
3184 share
= (sa_share_t
)group
;
3186 iszfs
= is_zfs_group(parent
);
3187 } else if (sa_is_resource(group
)) {
3188 share
= sa_get_parent_group(group
);
3190 parent
= sa_get_parent_group(share
);
3192 iszfs
= is_zfs_group(group
);
3195 if (scf_handle
->trans
== NULL
) {
3196 char oname
[SA_STRSIZE
];
3197 char *groupname
= NULL
;
3198 if (share
!= NULL
) {
3201 sa_get_group_attr(parent
,
3203 id
= sa_get_share_attr(
3204 (sa_share_t
)share
, "id");
3206 groupname
= sa_get_group_attr(group
,
3209 if (groupname
!= NULL
) {
3210 ret
= sa_get_instance(scf_handle
,
3212 sa_free_attr_string(groupname
);
3215 (void) sa_optionset_name(optionset
,
3216 oname
, sizeof (oname
), id
);
3218 (void) sa_security_name(optionset
,
3219 oname
, sizeof (oname
), id
);
3220 ret
= sa_start_transaction(scf_handle
, oname
);
3222 sa_free_attr_string(id
);
3226 case SA_PROP_OP_REMOVE
:
3227 ret
= scf_transaction_property_delete(
3228 scf_handle
->trans
, entry
, name
);
3230 case SA_PROP_OP_ADD
:
3231 case SA_PROP_OP_UPDATE
:
3232 value
= scf_value_create(
3233 scf_handle
->handle
);
3234 ret
= add_or_update(scf_handle
, type
,
3235 value
, entry
, name
, valstr
);
3241 * ZFS update. The calling function would have updated
3242 * the internal XML structure. Just need to flag it as
3245 zfs_set_update((sa_share_t
)group
);
3250 sa_free_attr_string(name
);
3252 sa_free_attr_string(valstr
);
3253 else if (entry
!= NULL
)
3254 scf_entry_destroy(entry
);
3257 ret
= SA_SYSTEM_ERR
;
3263 * sa_create_section(name, value)
3265 * Create a new section with the specified name and extra data.
3269 sa_create_section(char *name
, char *extra
)
3273 node
= xmlNewNode(NULL
, (xmlChar
*)"section");
3276 (void) xmlSetProp(node
, (xmlChar
*)"name",
3279 (void) xmlSetProp(node
, (xmlChar
*)"extra",
3282 return ((sa_property_t
)node
);
3286 sa_set_section_attr(sa_property_t sect
, char *name
, char *value
)
3288 (void) xmlSetProp(sect
, (xmlChar
*)name
, (xmlChar
*)value
);
3292 * sa_create_property(section, name, value)
3294 * Create a new property with the specified name and value.
3298 sa_create_property(char *name
, char *value
)
3302 node
= xmlNewNode(NULL
, (xmlChar
*)"option");
3304 (void) xmlSetProp(node
, (xmlChar
*)"type", (xmlChar
*)name
);
3305 (void) xmlSetProp(node
, (xmlChar
*)"value", (xmlChar
*)value
);
3307 return ((sa_property_t
)node
);
3311 * sa_add_property(object, property)
3313 * Add the specified property to the object. Issue the appropriate
3314 * transaction or mark a ZFS object as needing an update.
3318 sa_add_property(void *object
, sa_property_t property
)
3325 if (property
!= NULL
) {
3327 handle
= sa_find_group_handle((sa_group_t
)object
);
3328 /* It is legitimate to not find a handle */
3329 proto
= sa_get_optionset_attr(object
, "type");
3330 if ((ret
= sa_valid_property(handle
, object
, proto
,
3331 property
)) == SA_OK
) {
3332 property
= (sa_property_t
)xmlAddChild(
3333 (xmlNodePtr
)object
, (xmlNodePtr
)property
);
3336 sa_free_attr_string(proto
);
3340 sa_free_attr_string(proto
);
3344 parent
= sa_get_parent_group(object
);
3345 if (!sa_is_persistent(parent
))
3348 if (sa_is_resource(parent
)) {
3350 * Resources are children of share. Need to go up two
3351 * levels to find the group but the parent needs to be
3352 * the share at this point in order to get the "id".
3354 parent
= sa_get_parent_group(parent
);
3355 group
= sa_get_parent_group(parent
);
3356 } else if (sa_is_share(parent
)) {
3357 group
= sa_get_parent_group(parent
);
3362 if (property
== NULL
) {
3365 char oname
[SA_STRSIZE
];
3367 if (!is_zfs_group(group
)) {
3369 sa_handle_impl_t impl_handle
;
3370 scfutilhandle_t
*scf_handle
;
3372 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(
3374 if (impl_handle
== NULL
||
3375 impl_handle
->scfhandle
== NULL
)
3376 ret
= SA_SYSTEM_ERR
;
3378 scf_handle
= impl_handle
->scfhandle
;
3379 if (sa_is_share((sa_group_t
)parent
)) {
3380 id
= sa_get_share_attr(
3381 (sa_share_t
)parent
, "id");
3383 if (scf_handle
->trans
== NULL
) {
3384 if (is_nodetype(object
, "optionset")) {
3385 (void) sa_optionset_name(
3386 (sa_optionset_t
)object
,
3387 oname
, sizeof (oname
), id
);
3389 (void) sa_security_name(
3390 (sa_optionset_t
)object
,
3391 oname
, sizeof (oname
), id
);
3393 ret
= sa_start_transaction(scf_handle
,
3399 name
= sa_get_property_attr(property
,
3401 value
= sa_get_property_attr(property
,
3403 if (name
!= NULL
&& value
!= NULL
) {
3404 if (scf_handle
->scf_state
==
3406 ret
= sa_set_property(
3411 ret
= SA_CONFIG_ERR
;
3414 sa_free_attr_string(
3417 sa_free_attr_string(value
);
3420 sa_free_attr_string(id
);
3424 * ZFS is a special case. We do want
3425 * to allow editing property/security
3426 * lists since we can have a better
3427 * syntax and we also want to keep
3428 * things consistent when possible.
3430 * Right now, we defer until the
3431 * sa_commit_properties so we can get
3432 * them all at once. We do need to
3433 * mark the share as "changed"
3435 zfs_set_update((sa_share_t
)parent
);
3442 * sa_remove_property(property)
3444 * Remove the specied property from its containing object. Update the
3445 * repository as appropriate.
3449 sa_remove_property(sa_property_t property
)
3453 if (property
!= NULL
) {
3454 sa_optionset_t optionset
;
3456 optionset
= sa_get_property_parent(property
);
3457 if (optionset
!= NULL
) {
3458 group
= sa_get_optionset_parent(optionset
);
3459 if (group
!= NULL
) {
3460 ret
= sa_set_prop_by_prop(optionset
, group
,
3461 property
, SA_PROP_OP_REMOVE
);
3464 xmlUnlinkNode((xmlNodePtr
)property
);
3465 xmlFreeNode((xmlNodePtr
)property
);
3467 ret
= SA_NO_SUCH_PROP
;
3473 * sa_update_property(property, value)
3475 * Update the specified property to the new value. If value is NULL,
3476 * we currently treat this as a remove.
3480 sa_update_property(sa_property_t property
, char *value
)
3483 if (value
== NULL
) {
3484 return (sa_remove_property(property
));
3486 sa_optionset_t optionset
;
3488 set_node_attr((void *)property
, "value", value
);
3489 optionset
= sa_get_property_parent(property
);
3490 if (optionset
!= NULL
) {
3491 group
= sa_get_optionset_parent(optionset
);
3492 if (group
!= NULL
) {
3493 ret
= sa_set_prop_by_prop(optionset
, group
,
3494 property
, SA_PROP_OP_UPDATE
);
3497 ret
= SA_NO_SUCH_PROP
;
3504 * sa_get_protocol_section(propset, prop)
3506 * Get the specified protocol specific section. These are global to
3507 * the protocol and not specific to a group or share.
3510 sa_protocol_properties_t
3511 sa_get_protocol_section(sa_protocol_properties_t propset
, char *section
)
3513 xmlNodePtr node
= (xmlNodePtr
)propset
;
3514 xmlChar
*value
= NULL
;
3517 proto
= sa_get_optionset_attr(propset
, "type");
3518 if ((sa_proto_get_featureset(proto
) & SA_FEATURE_HAS_SECTIONS
) == 0) {
3520 sa_free_attr_string(proto
);
3524 for (node
= node
->children
; node
!= NULL
;
3525 node
= node
->next
) {
3526 if (xmlStrcmp(node
->name
, (xmlChar
*)"section") == 0) {
3527 if (section
== NULL
)
3529 value
= xmlGetProp(node
, (xmlChar
*)"name");
3530 if (value
!= NULL
&&
3531 xmlStrcasecmp(value
, (xmlChar
*)section
) == 0) {
3534 if (value
!= NULL
) {
3543 sa_free_attr_string(proto
);
3544 if (node
!= NULL
&& xmlStrcmp(node
->name
, (xmlChar
*)"section") != 0) {
3546 * avoid a non option node -- it is possible to be a
3551 return ((sa_protocol_properties_t
)node
);
3555 * sa_get_next_protocol_section(prop, find)
3557 * Get the next protocol specific section in the list.
3561 sa_get_next_protocol_section(sa_property_t prop
, char *find
)
3564 xmlChar
*value
= NULL
;
3567 proto
= sa_get_optionset_attr(prop
, "type");
3568 if ((sa_proto_get_featureset(proto
) & SA_FEATURE_HAS_SECTIONS
) == 0) {
3570 sa_free_attr_string(proto
);
3571 return ((sa_property_t
)NULL
);
3574 for (node
= ((xmlNodePtr
)prop
)->next
; node
!= NULL
;
3575 node
= node
->next
) {
3576 if (xmlStrcmp(node
->name
, (xmlChar
*)"section") == 0) {
3579 value
= xmlGetProp(node
, (xmlChar
*)"name");
3580 if (value
!= NULL
&&
3581 xmlStrcasecmp(value
, (xmlChar
*)find
) == 0) {
3584 if (value
!= NULL
) {
3594 sa_free_attr_string(proto
);
3595 return ((sa_property_t
)node
);
3599 * sa_get_protocol_property(propset, prop)
3601 * Get the specified protocol specific property. These are global to
3602 * the protocol and not specific to a group or share.
3606 sa_get_protocol_property(sa_protocol_properties_t propset
, char *prop
)
3608 xmlNodePtr node
= (xmlNodePtr
)propset
;
3609 xmlChar
*value
= NULL
;
3611 if (propset
== NULL
)
3614 for (node
= node
->children
; node
!= NULL
;
3615 node
= node
->next
) {
3616 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
3619 value
= xmlGetProp(node
, (xmlChar
*)"type");
3620 if (value
!= NULL
&&
3621 xmlStrcasecmp(value
, (xmlChar
*)prop
) == 0) {
3624 if (value
!= NULL
) {
3632 if (node
!= NULL
&& xmlStrcmp(node
->name
, (xmlChar
*)"option") != 0) {
3634 * avoid a non option node -- it is possible to be a
3639 return ((sa_property_t
)node
);
3643 * sa_get_next_protocol_property(prop)
3645 * Get the next protocol specific property in the list.
3649 sa_get_next_protocol_property(sa_property_t prop
, char *find
)
3652 xmlChar
*value
= NULL
;
3654 for (node
= ((xmlNodePtr
)prop
)->next
; node
!= NULL
;
3655 node
= node
->next
) {
3656 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
3659 value
= xmlGetProp(node
, (xmlChar
*)"type");
3660 if (value
!= NULL
&&
3661 xmlStrcasecmp(value
, (xmlChar
*)find
) == 0) {
3664 if (value
!= NULL
) {
3673 return ((sa_property_t
)node
);
3677 * sa_set_protocol_property(prop, value)
3679 * Set the specified property to have the new value. The protocol
3680 * specific plugin will then be called to update the property.
3684 sa_set_protocol_property(sa_property_t prop
, char *section
, char *value
)
3686 sa_protocol_properties_t propset
;
3688 int ret
= SA_INVALID_PROTOCOL
;
3690 propset
= ((xmlNodePtr
)prop
)->parent
;
3691 if (propset
!= NULL
) {
3692 proto
= sa_get_optionset_attr(propset
, "type");
3693 if (proto
!= NULL
) {
3694 if (section
!= NULL
)
3695 set_node_attr((xmlNodePtr
)prop
, "section",
3697 set_node_attr((xmlNodePtr
)prop
, "value", value
);
3698 ret
= sa_proto_set_property(proto
, prop
);
3699 sa_free_attr_string(proto
);
3706 * sa_add_protocol_property(propset, prop)
3708 * Add a new property to the protocol specific property set.
3712 sa_add_protocol_property(sa_protocol_properties_t propset
, sa_property_t prop
)
3716 /* should check for legitimacy */
3717 node
= xmlAddChild((xmlNodePtr
)propset
, (xmlNodePtr
)prop
);
3720 return (SA_NO_MEMORY
);
3724 * sa_create_protocol_properties(proto)
3726 * Create a protocol specific property set.
3729 sa_protocol_properties_t
3730 sa_create_protocol_properties(char *proto
)
3734 node
= xmlNewNode(NULL
, (xmlChar
*)"propertyset");
3736 (void) xmlSetProp(node
, (xmlChar
*)"type", (xmlChar
*)proto
);
3741 * sa_get_share_resource(share, resource)
3743 * Get the named resource from the share, if it exists. If resource is
3744 * NULL, get the first resource.
3748 sa_get_share_resource(sa_share_t share
, char *resource
)
3750 xmlNodePtr node
= NULL
;
3753 if (share
!= NULL
) {
3754 for (node
= ((xmlNodePtr
)share
)->children
; node
!= NULL
;
3755 node
= node
->next
) {
3756 if (xmlStrcmp(node
->name
, (xmlChar
*)"resource") == 0) {
3757 if (resource
== NULL
) {
3759 * We are looking for the first
3760 * resource node and not a names
3765 /* is it the correct share? */
3766 name
= xmlGetProp(node
,
3770 (xmlChar
*)resource
) == 0) {
3779 return ((sa_resource_t
)node
);
3783 * sa_get_next_resource(resource)
3784 * Return the next share following the specified share
3785 * from the internal list of shares. Returns NULL if there
3786 * are no more shares. The list is relative to the same
3790 sa_get_next_resource(sa_resource_t resource
)
3792 xmlNodePtr node
= NULL
;
3794 if (resource
!= NULL
) {
3795 for (node
= ((xmlNodePtr
)resource
)->next
; node
!= NULL
;
3796 node
= node
->next
) {
3797 if (xmlStrcmp(node
->name
, (xmlChar
*)"resource") == 0)
3801 return ((sa_share_t
)node
);
3805 * _sa_get_next_resource_index(share)
3807 * get the next resource index number (one greater then current largest)
3811 _sa_get_next_resource_index(sa_share_t share
)
3813 sa_resource_t resource
;
3817 for (resource
= sa_get_share_resource(share
, NULL
);
3819 resource
= sa_get_next_resource(resource
)) {
3820 id
= get_node_attr((void *)resource
, "id");
3826 sa_free_attr_string(id
);
3834 * sa_add_resource(share, resource, persist, &err)
3836 * Adds a new resource name associated with share. The resource name
3837 * must be unique in the system and will be case insensitive (eventually).
3841 sa_add_resource(sa_share_t share
, char *resource
, int persist
, int *error
)
3848 char istring
[8]; /* just big enough for an integer value */
3851 group
= sa_get_parent_group(share
);
3852 handle
= sa_find_group_handle(group
);
3853 res
= sa_find_resource(handle
, resource
);
3855 err
= SA_DUPLICATE_NAME
;
3858 node
= xmlNewChild((xmlNodePtr
)share
, NULL
,
3859 (xmlChar
*)"resource", NULL
);
3861 (void) xmlSetProp(node
, (xmlChar
*)"name",
3862 (xmlChar
*)resource
);
3863 (void) xmlSetProp(node
, (xmlChar
*)"type", persist
?
3864 (xmlChar
*)"persist" : (xmlChar
*)"transient");
3865 if (persist
!= SA_SHARE_TRANSIENT
) {
3866 index
= _sa_get_next_resource_index(share
);
3867 (void) snprintf(istring
, sizeof (istring
), "%d",
3869 (void) xmlSetProp(node
, (xmlChar
*)"id",
3870 (xmlChar
*)istring
);
3872 if (!sa_is_persistent((sa_group_t
)share
))
3875 if (!sa_group_is_zfs(group
)) {
3876 /* ZFS doesn't use resource names */
3877 sa_handle_impl_t ihandle
;
3879 ihandle
= (sa_handle_impl_t
)
3880 sa_find_group_handle(
3882 if (ihandle
!= NULL
)
3883 err
= sa_commit_share(
3884 ihandle
->scfhandle
, group
,
3887 err
= SA_SYSTEM_ERR
;
3889 err
= sa_zfs_update((sa_share_t
)group
);
3897 return ((sa_resource_t
)node
);
3901 * sa_remove_resource(resource)
3903 * Remove the resource name from the share (and the system)
3907 sa_remove_resource(sa_resource_t resource
)
3913 boolean_t transient
= B_FALSE
;
3916 share
= sa_get_resource_parent(resource
);
3917 type
= sa_get_share_attr(share
, "type");
3918 group
= sa_get_parent_group(share
);
3922 if (strcmp(type
, "persist") != 0)
3924 sa_free_attr_string(type
);
3927 /* Disable the resource for all protocols. */
3928 (void) sa_disable_resource(resource
, NULL
);
3930 /* Remove any optionsets from the resource. */
3931 for (opt
= sa_get_optionset(resource
, NULL
);
3933 opt
= sa_get_next_optionset(opt
))
3934 (void) sa_destroy_optionset(opt
);
3936 /* Remove from the share */
3937 xmlUnlinkNode((xmlNode
*)resource
);
3938 xmlFreeNode((xmlNode
*)resource
);
3940 /* only do SMF action if permanent and not ZFS */
3944 if (!sa_group_is_zfs(group
)) {
3945 sa_handle_impl_t ihandle
;
3946 ihandle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
3947 if (ihandle
!= NULL
)
3948 ret
= sa_commit_share(ihandle
->scfhandle
, group
, share
);
3950 ret
= SA_SYSTEM_ERR
;
3952 ret
= sa_zfs_update((sa_share_t
)group
);
3959 * proto_rename_resource(handle, group, resource, newname)
3961 * Helper function for sa_rename_resource that notifies the protocol
3962 * of a resource name change prior to a config repository update.
3965 proto_rename_resource(sa_handle_t handle
, sa_group_t group
,
3966 sa_resource_t resource
, char *newname
)
3968 sa_optionset_t optionset
;
3972 for (optionset
= sa_get_optionset(group
, NULL
);
3974 optionset
= sa_get_next_optionset(optionset
)) {
3976 type
= sa_get_optionset_attr(optionset
, "type");
3978 err
= sa_proto_rename_resource(handle
, type
, resource
,
3982 sa_free_attr_string(type
);
3989 * sa_rename_resource(resource, newname)
3991 * Rename the resource to the new name, if it is unique.
3995 sa_rename_resource(sa_resource_t resource
, char *newname
)
3998 sa_group_t group
= NULL
;
3999 sa_resource_t target
;
4000 int ret
= SA_CONFIG_ERR
;
4001 sa_handle_t handle
= NULL
;
4003 share
= sa_get_resource_parent(resource
);
4007 group
= sa_get_parent_group(share
);
4011 handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
4015 target
= sa_find_resource(handle
, newname
);
4016 if (target
!= NULL
) {
4017 ret
= SA_DUPLICATE_NAME
;
4020 * Everything appears to be valid at this
4021 * point. Change the name of the active share and then
4022 * update the share in the appropriate repository.
4024 ret
= proto_rename_resource(handle
, group
, resource
, newname
);
4025 set_node_attr(resource
, "name", newname
);
4027 if (!sa_is_persistent((sa_group_t
)share
))
4030 if (!sa_group_is_zfs(group
)) {
4031 sa_handle_impl_t ihandle
= (sa_handle_impl_t
)handle
;
4032 ret
= sa_commit_share(ihandle
->scfhandle
, group
,
4035 ret
= sa_zfs_update((sa_share_t
)group
);
4042 * sa_get_resource_attr(resource, tag)
4044 * Get the named attribute of the resource. "name" and "id" are
4045 * currently defined. NULL if tag not defined.
4049 sa_get_resource_attr(sa_resource_t resource
, char *tag
)
4051 return (get_node_attr((void *)resource
, tag
));
4055 * sa_set_resource_attr(resource, tag, value)
4057 * Get the named attribute of the resource. "name" and "id" are
4058 * currently defined. NULL if tag not defined. Currently we don't do
4059 * much, but additional checking may be needed in the future.
4063 sa_set_resource_attr(sa_resource_t resource
, char *tag
, char *value
)
4065 set_node_attr((void *)resource
, tag
, value
);
4070 * sa_get_resource_parent(resource_t)
4072 * Returns the share associated with the resource.
4076 sa_get_resource_parent(sa_resource_t resource
)
4078 sa_share_t share
= NULL
;
4080 if (resource
!= NULL
)
4081 share
= (sa_share_t
)((xmlNodePtr
)resource
)->parent
;
4086 * find_resource(group, name)
4088 * Find the resource within the group.
4091 static sa_resource_t
4092 find_resource(sa_group_t group
, char *resname
)
4095 sa_resource_t resource
= NULL
;
4098 /* Iterate over all the shares and resources in the group. */
4099 for (share
= sa_get_share(group
, NULL
);
4100 share
!= NULL
&& resource
== NULL
;
4101 share
= sa_get_next_share(share
)) {
4102 for (resource
= sa_get_share_resource(share
, NULL
);
4104 resource
= sa_get_next_resource(resource
)) {
4105 name
= sa_get_resource_attr(resource
, "name");
4106 if (name
!= NULL
&& xmlStrcasecmp((xmlChar
*)name
,
4107 (xmlChar
*)resname
) == 0) {
4108 sa_free_attr_string(name
);
4112 sa_free_attr_string(name
);
4120 * sa_find_resource(name)
4122 * Find the named resource in the system.
4126 sa_find_resource(sa_handle_t handle
, char *name
)
4130 sa_resource_t resource
= NULL
;
4133 * Iterate over all groups and zfs subgroups and check for
4134 * resource name in them.
4136 for (group
= sa_get_group(handle
, NULL
); group
!= NULL
;
4137 group
= sa_get_next_group(group
)) {
4139 if (is_zfs_group(group
)) {
4141 (sa_group_t
)_sa_get_child_node((xmlNodePtr
)group
,
4142 (xmlChar
*)"group");
4143 zgroup
!= NULL
&& resource
== NULL
;
4144 zgroup
= sa_get_next_group(zgroup
)) {
4145 resource
= find_resource(zgroup
, name
);
4148 resource
= find_resource(group
, name
);
4150 if (resource
!= NULL
)
4157 * sa_get_resource(group, resource)
4159 * Search all the shares in the specified group for a share with a
4160 * resource name matching the one specified.
4162 * In the future, it may be advantageous to allow group to be NULL and
4163 * search all groups but that isn't needed at present.
4167 sa_get_resource(sa_group_t group
, char *resource
)
4169 sa_share_t share
= NULL
;
4170 sa_resource_t res
= NULL
;
4172 if (resource
!= NULL
) {
4173 for (share
= sa_get_share(group
, NULL
);
4174 share
!= NULL
&& res
== NULL
;
4175 share
= sa_get_next_share(share
)) {
4176 res
= sa_get_share_resource(share
, resource
);
4183 * get_protocol_list(optionset, object)
4185 * Get the protocol optionset list for the object and add them as
4186 * properties to optionset.
4189 get_protocol_list(sa_optionset_t optionset
, void *object
)
4192 sa_optionset_t opts
;
4195 for (opts
= sa_get_optionset(object
, NULL
);
4197 opts
= sa_get_next_optionset(opts
)) {
4199 type
= sa_get_optionset_attr(opts
, "type");
4201 * It is possible to have a non-protocol optionset. We
4202 * skip any of those found.
4206 prop
= sa_create_property(type
, "true");
4207 sa_free_attr_string(type
);
4209 prop
= (sa_property_t
)xmlAddChild((xmlNodePtr
)optionset
,
4211 /* If prop is NULL, don't bother continuing */
4221 * sa_free_protoset(optionset)
4223 * Free the protocol property optionset.
4226 sa_free_protoset(sa_optionset_t optionset
)
4228 if (optionset
!= NULL
) {
4229 xmlUnlinkNode((xmlNodePtr
) optionset
);
4230 xmlFreeNode((xmlNodePtr
) optionset
);
4235 * sa_optionset_t sa_get_active_protocols(object)
4237 * Return a list of the protocols that are active for the object.
4238 * This is currently an internal helper function, but could be
4239 * made visible if there is enough demand for it.
4241 * The function finds the parent group and extracts the protocol
4242 * optionsets creating a new optionset with the protocols as properties.
4244 * The caller must free the returned optionset.
4247 static sa_optionset_t
4248 sa_get_active_protocols(void *object
)
4250 sa_optionset_t options
;
4251 sa_share_t share
= NULL
;
4252 sa_group_t group
= NULL
;
4253 sa_resource_t resource
= NULL
;
4258 options
= (sa_optionset_t
)xmlNewNode(NULL
, (xmlChar
*)"optionset");
4259 if (options
== NULL
)
4263 * Find the objects up the tree that might have protocols
4266 if (sa_is_resource(object
)) {
4267 resource
= (sa_resource_t
)object
;
4268 share
= sa_get_resource_parent(resource
);
4269 group
= sa_get_parent_group(share
);
4270 } else if (sa_is_share(object
)) {
4271 share
= (sa_share_t
)object
;
4272 group
= sa_get_parent_group(share
);
4274 group
= (sa_group_t
)group
;
4276 if (resource
!= NULL
)
4277 ret
= get_protocol_list(options
, resource
);
4278 if (ret
== SA_OK
&& share
!= NULL
)
4279 ret
= get_protocol_list(options
, share
);
4280 if (ret
== SA_OK
&& group
!= NULL
)
4281 ret
= get_protocol_list(options
, group
);
4284 * If there was an error, we won't have a complete list so
4285 * abandon everything. The caller will have to deal with the
4289 sa_free_protoset(options
);
4296 * sa_enable_resource, protocol)
4297 * Disable the specified share to the specified protocol.
4298 * If protocol is NULL, then all protocols.
4301 sa_enable_resource(sa_resource_t resource
, char *protocol
)
4305 if (protocol
!= NULL
) {
4306 ret
= sa_proto_share_resource(protocol
, resource
);
4308 sa_optionset_t protoset
;
4313 /* need to do all protocols */
4314 protoset
= sa_get_active_protocols(resource
);
4315 if (protoset
== NULL
)
4316 return (SA_NO_MEMORY
);
4317 for (prop
= sa_get_property(protoset
, NULL
);
4319 prop
= sa_get_next_property(prop
)) {
4320 proto
= sa_get_property_attr(prop
, "type");
4321 if (proto
== NULL
) {
4325 err
= sa_proto_share_resource(proto
, resource
);
4328 sa_free_attr_string(proto
);
4330 sa_free_protoset(protoset
);
4333 (void) sa_set_resource_attr(resource
, "shared", NULL
);
4339 * sa_disable_resource(resource, protocol)
4341 * Disable the specified share for the specified protocol. If
4342 * protocol is NULL, then all protocols. If the underlying
4343 * protocol doesn't implement disable at the resource level, we
4344 * disable at the share level.
4347 sa_disable_resource(sa_resource_t resource
, char *protocol
)
4351 if (protocol
!= NULL
) {
4352 ret
= sa_proto_unshare_resource(protocol
, resource
);
4353 if (ret
== SA_NOT_IMPLEMENTED
) {
4356 * The protocol doesn't implement unshare
4357 * resource. That implies that resource names are
4358 * simple aliases for this protocol so we need to
4359 * unshare the share.
4361 parent
= sa_get_resource_parent(resource
);
4363 ret
= sa_disable_share(parent
, protocol
);
4365 ret
= SA_CONFIG_ERR
;
4368 sa_optionset_t protoset
;
4373 /* need to do all protocols */
4374 protoset
= sa_get_active_protocols(resource
);
4375 if (protoset
== NULL
)
4376 return (SA_NO_MEMORY
);
4377 for (prop
= sa_get_property(protoset
, NULL
);
4379 prop
= sa_get_next_property(prop
)) {
4380 proto
= sa_get_property_attr(prop
, "type");
4381 if (proto
== NULL
) {
4385 err
= sa_proto_unshare_resource(proto
, resource
);
4386 if (err
== SA_NOT_SUPPORTED
) {
4388 parent
= sa_get_resource_parent(resource
);
4390 err
= sa_disable_share(parent
, proto
);
4392 err
= SA_CONFIG_ERR
;
4396 sa_free_attr_string(proto
);
4398 sa_free_protoset(protoset
);
4401 (void) sa_set_resource_attr(resource
, "shared", NULL
);
4407 * sa_set_resource_description(resource, content)
4409 * Set the description of share to content.
4413 sa_set_resource_description(sa_resource_t resource
, char *content
)
4420 for (node
= ((xmlNodePtr
)resource
)->children
;
4422 node
= node
->next
) {
4423 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0) {
4428 /* no existing description but want to add */
4429 if (node
== NULL
&& content
!= NULL
) {
4430 /* add a description */
4431 node
= _sa_set_share_description(resource
, content
);
4432 } else if (node
!= NULL
&& content
!= NULL
) {
4433 /* update a description */
4434 xmlNodeSetContent(node
, (xmlChar
*)content
);
4435 } else if (node
!= NULL
&& content
== NULL
) {
4436 /* remove an existing description */
4437 xmlUnlinkNode(node
);
4441 share
= sa_get_resource_parent(resource
);
4442 group
= sa_get_parent_group(share
);
4443 if (group
!= NULL
&&
4444 sa_is_persistent(share
) && (!sa_group_is_zfs(group
))) {
4445 sa_handle_impl_t impl_handle
;
4446 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
4447 if (impl_handle
!= NULL
)
4448 ret
= sa_commit_share(impl_handle
->scfhandle
,
4451 ret
= SA_SYSTEM_ERR
;
4457 * sa_get_resource_description(share)
4459 * Return the description text for the specified share if it
4460 * exists. NULL if no description exists.
4464 sa_get_resource_description(sa_resource_t resource
)
4466 xmlChar
*description
= NULL
;
4469 for (node
= ((xmlNodePtr
)resource
)->children
; node
!= NULL
;
4470 node
= node
->next
) {
4471 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0)
4475 description
= xmlNodeGetContent(node
);
4476 fixproblemchars((char *)description
);
4478 return ((char *)description
);