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
);
1267 return ((sa_group_t
)(node
));
1271 * sa_get_next_group(group)
1272 * Return the "next" group after the specified group from
1273 * the internal group list. NULL if there are no more.
1276 sa_get_next_group(sa_group_t group
)
1278 xmlNodePtr ngroup
= NULL
;
1279 if (group
!= NULL
) {
1280 for (ngroup
= ((xmlNodePtr
)group
)->next
; ngroup
!= NULL
;
1281 ngroup
= ngroup
->next
) {
1282 if (xmlStrcmp(ngroup
->name
, (xmlChar
*)"group") == 0)
1286 return ((sa_group_t
)ngroup
);
1290 * sa_get_share(group, sharepath)
1291 * Return the share object for the share specified. The share
1292 * must be in the specified group. Return NULL if not found.
1295 sa_get_share(sa_group_t group
, char *sharepath
)
1297 xmlNodePtr node
= NULL
;
1301 * For future scalability, this should end up building a cache
1302 * since it will get called regularly by the mountd and info
1305 if (group
!= NULL
) {
1306 for (node
= ((xmlNodePtr
)group
)->children
; node
!= NULL
;
1307 node
= node
->next
) {
1308 if (xmlStrcmp(node
->name
, (xmlChar
*)"share") == 0) {
1309 if (sharepath
== NULL
) {
1312 /* is it the correct share? */
1313 path
= xmlGetProp(node
,
1317 (xmlChar
*)sharepath
) == 0) {
1326 return ((sa_share_t
)node
);
1330 * sa_get_next_share(share)
1331 * Return the next share following the specified share
1332 * from the internal list of shares. Returns NULL if there
1333 * are no more shares. The list is relative to the same
1337 sa_get_next_share(sa_share_t share
)
1339 xmlNodePtr node
= NULL
;
1341 if (share
!= NULL
) {
1342 for (node
= ((xmlNodePtr
)share
)->next
; node
!= NULL
;
1343 node
= node
->next
) {
1344 if (xmlStrcmp(node
->name
, (xmlChar
*)"share") == 0) {
1349 return ((sa_share_t
)node
);
1353 * _sa_get_child_node(node, type)
1355 * find the child node of the specified node that has "type". This is
1356 * used to implement several internal functions.
1360 _sa_get_child_node(xmlNodePtr node
, xmlChar
*type
)
1363 for (child
= node
->xmlChildrenNode
; child
!= NULL
;
1364 child
= child
->next
)
1365 if (xmlStrcmp(child
->name
, type
) == 0)
1367 return ((xmlNodePtr
)NULL
);
1371 * find_share(group, path)
1373 * Search all the shares in the specified group for one that has the
1378 find_share(sa_group_t group
, char *sharepath
)
1383 for (share
= sa_get_share(group
, NULL
); share
!= NULL
;
1384 share
= sa_get_next_share(share
)) {
1385 path
= sa_get_share_attr(share
, "path");
1386 if (path
!= NULL
&& strcmp(path
, sharepath
) == 0) {
1387 sa_free_attr_string(path
);
1391 sa_free_attr_string(path
);
1397 * sa_get_sub_group(group)
1399 * Get the first sub-group of group. The sa_get_next_group() function
1400 * can be used to get the rest. This is currently only used for ZFS
1401 * sub-groups but could be used to implement a more general mechanism.
1405 sa_get_sub_group(sa_group_t group
)
1407 return ((sa_group_t
)_sa_get_child_node((xmlNodePtr
)group
,
1408 (xmlChar
*)"group"));
1412 * sa_find_share(sharepath)
1413 * Finds a share regardless of group. In the future, this
1414 * function should utilize a cache and hash table of some kind.
1415 * The current assumption is that a path will only be shared
1416 * once. In the future, this may change as implementation of
1417 * resource names comes into being.
1420 sa_find_share(sa_handle_t handle
, char *sharepath
)
1424 sa_share_t share
= NULL
;
1427 for (group
= sa_get_group(handle
, NULL
); group
!= NULL
&& !done
;
1428 group
= sa_get_next_group(group
)) {
1429 if (is_zfs_group(group
)) {
1431 (sa_group_t
)_sa_get_child_node((xmlNodePtr
)group
,
1432 (xmlChar
*)"group");
1434 zgroup
= sa_get_next_group(zgroup
)) {
1435 share
= find_share(zgroup
, sharepath
);
1440 share
= find_share(group
, sharepath
);
1449 * sa_check_path(group, path, strictness)
1451 * Check that path is a valid path relative to the group. Currently,
1452 * we are ignoring the group and checking only the NFS rules. Later,
1453 * we may want to use the group to then check against the protocols
1454 * enabled on the group. The strictness values mean:
1455 * SA_CHECK_NORMAL == only check newpath against shares that are active
1456 * SA_CHECK_STRICT == check newpath against both active shares and those
1457 * stored in the repository
1461 sa_check_path(sa_group_t group
, char *path
, int strictness
)
1465 handle
= sa_find_group_handle(group
);
1467 return (SA_BAD_PATH
);
1469 return (validpath(handle
, path
, strictness
));
1473 * mark_excluded_protos(group, share, flags)
1475 * Walk through all the protocols enabled for the group and check to
1476 * see if the share has any of them should be in the exclude list
1477 * based on the featureset of the protocol. If there are any, add the
1478 * "exclude" property to the share.
1481 mark_excluded_protos(sa_group_t group
, xmlNodePtr share
, uint64_t flags
)
1483 sa_optionset_t optionset
;
1484 char exclude_list
[SA_STRSIZE
];
1487 exclude_list
[0] = '\0';
1488 for (optionset
= sa_get_optionset(group
, NULL
);
1490 optionset
= sa_get_next_optionset(optionset
)) {
1493 value
= sa_get_optionset_attr(optionset
, "type");
1496 features
= sa_proto_get_featureset(value
);
1497 if (!(features
& flags
)) {
1498 (void) strlcat(exclude_list
, sep
,
1499 sizeof (exclude_list
));
1500 (void) strlcat(exclude_list
, value
,
1501 sizeof (exclude_list
));
1504 sa_free_attr_string(value
);
1506 if (exclude_list
[0] != '\0')
1507 (void) xmlSetProp(share
, (xmlChar
*)"exclude",
1508 (xmlChar
*)exclude_list
);
1512 * get_all_features(group)
1514 * Walk through all the protocols on the group and collect all
1515 * possible enabled features. This is the OR of all the featuresets.
1518 get_all_features(sa_group_t group
)
1520 sa_optionset_t optionset
;
1521 uint64_t features
= 0;
1523 for (optionset
= sa_get_optionset(group
, NULL
);
1525 optionset
= sa_get_next_optionset(optionset
)) {
1527 value
= sa_get_optionset_attr(optionset
, "type");
1530 features
|= sa_proto_get_featureset(value
);
1531 sa_free_attr_string(value
);
1538 * _sa_add_share(group, sharepath, persist, *error, flags)
1540 * Common code for all types of add_share. sa_add_share() is the
1541 * public API, we also need to be able to do this when parsing legacy
1542 * files and construction of the internal configuration while
1543 * extracting config info from SMF. "flags" indicates if some
1544 * protocols need relaxed rules while other don't. These values are
1545 * the featureset values defined in libshare.h.
1549 _sa_add_share(sa_group_t group
, char *sharepath
, int persist
, int *error
,
1552 xmlNodePtr node
= NULL
;
1555 err
= SA_OK
; /* assume success */
1557 node
= xmlNewChild((xmlNodePtr
)group
, NULL
, (xmlChar
*)"share", NULL
);
1560 *error
= SA_NO_MEMORY
;
1564 (void) xmlSetProp(node
, (xmlChar
*)"path", (xmlChar
*)sharepath
);
1565 (void) xmlSetProp(node
, (xmlChar
*)"type",
1566 persist
? (xmlChar
*)"persist" : (xmlChar
*)"transient");
1568 mark_excluded_protos(group
, node
, flags
);
1569 if (persist
!= SA_SHARE_TRANSIENT
) {
1571 * persistent shares come in two flavors: SMF and
1572 * ZFS. Sort this one out based on target group and
1573 * path type. Both NFS and SMB are supported. First,
1574 * check to see if the protocol is enabled on the
1575 * subgroup and then setup the share appropriately.
1577 if (sa_group_is_zfs(group
) &&
1578 sa_path_is_zfs(sharepath
)) {
1579 if (sa_get_optionset(group
, "nfs") != NULL
)
1580 err
= sa_zfs_set_sharenfs(group
, sharepath
, 1);
1581 else if (sa_get_optionset(group
, "smb") != NULL
)
1582 err
= sa_zfs_set_sharesmb(group
, sharepath
, 1);
1584 sa_handle_impl_t impl_handle
;
1586 (sa_handle_impl_t
)sa_find_group_handle(group
);
1587 if (impl_handle
!= NULL
) {
1588 err
= sa_commit_share(impl_handle
->scfhandle
,
1589 group
, (sa_share_t
)node
);
1591 err
= SA_SYSTEM_ERR
;
1595 if (err
== SA_NO_PERMISSION
&& persist
& SA_SHARE_PARSER
)
1596 /* called by the dfstab parser so could be a show */
1601 * we couldn't commit to the repository so undo
1602 * our internal state to reflect reality.
1604 xmlUnlinkNode(node
);
1616 * sa_add_share(group, sharepath, persist, *error)
1618 * Add a new share object to the specified group. The share will
1619 * have the specified sharepath and will only be constructed if
1620 * it is a valid path to be shared. NULL is returned on error
1621 * and a detailed error value will be returned via the error
1625 sa_add_share(sa_group_t group
, char *sharepath
, int persist
, int *error
)
1627 xmlNodePtr node
= NULL
;
1628 int strictness
= SA_CHECK_NORMAL
;
1630 uint64_t special
= 0;
1634 * If the share is to be permanent, use strict checking so a
1635 * bad config doesn't get created. Transient shares only need
1636 * to check against the currently active
1637 * shares. SA_SHARE_PARSER is a modifier used internally to
1638 * indicate that we are being called by the dfstab parser and
1639 * that we need strict checking in all cases. Normally persist
1640 * is in integer value but SA_SHARE_PARSER may be or'd into
1641 * it as an override.
1643 if (persist
& SA_SHARE_PARSER
|| persist
== SA_SHARE_PERMANENT
)
1644 strictness
= SA_CHECK_STRICT
;
1646 handle
= sa_find_group_handle(group
);
1649 * need to determine if the share is valid. The rules are:
1650 * - The path must not already exist
1651 * - The path must not be a subdir or parent dir of an
1652 * existing path unless at least one protocol allows it.
1653 * The sub/parent check is done in sa_check_path().
1656 if (sa_find_share(handle
, sharepath
) == NULL
) {
1657 *error
= sa_check_path(group
, sharepath
, strictness
);
1658 features
= get_all_features(group
);
1660 case SA_PATH_IS_SUBDIR
:
1661 if (features
& SA_FEATURE_ALLOWSUBDIRS
)
1662 special
|= SA_FEATURE_ALLOWSUBDIRS
;
1664 case SA_PATH_IS_PARENTDIR
:
1665 if (features
& SA_FEATURE_ALLOWPARDIRS
)
1666 special
|= SA_FEATURE_ALLOWPARDIRS
;
1669 if (*error
== SA_OK
|| special
!= SA_FEATURE_NONE
)
1670 node
= _sa_add_share(group
, sharepath
, persist
,
1673 *error
= SA_DUPLICATE_NAME
;
1676 return ((sa_share_t
)node
);
1680 * sa_enable_share(share, protocol)
1681 * Enable the specified share to the specified protocol.
1682 * If protocol is NULL, then all protocols.
1685 sa_enable_share(sa_share_t share
, char *protocol
)
1692 sharepath
= sa_get_share_attr(share
, "path");
1693 if (sharepath
== NULL
)
1694 return (SA_NO_MEMORY
);
1695 if (stat(sharepath
, &st
) < 0) {
1696 err
= SA_NO_SUCH_PATH
;
1698 /* tell the server about the share */
1699 if (protocol
!= NULL
) {
1700 if (excluded_protocol(share
, protocol
))
1703 /* lookup protocol specific handler */
1704 err
= sa_proto_share(protocol
, share
);
1706 (void) sa_set_share_attr(share
,
1709 /* Tell all protocols about the share */
1711 sa_optionset_t optionset
;
1713 group
= sa_get_parent_group(share
);
1715 for (optionset
= sa_get_optionset(group
, NULL
);
1717 optionset
= sa_get_next_optionset(optionset
)) {
1719 proto
= sa_get_optionset_attr(optionset
,
1721 if (proto
!= NULL
) {
1722 if (!excluded_protocol(share
, proto
)) {
1723 ret
= sa_proto_share(proto
,
1728 sa_free_attr_string(proto
);
1731 (void) sa_set_share_attr(share
, "shared", "true");
1735 if (sharepath
!= NULL
)
1736 sa_free_attr_string(sharepath
);
1741 * sa_disable_share(share, protocol)
1742 * Disable the specified share to the specified protocol. If
1743 * protocol is NULL, then all protocols that are enabled for the
1744 * share should be disabled.
1747 sa_disable_share(sa_share_t share
, char *protocol
)
1753 path
= sa_get_share_attr(share
, "path");
1755 if (protocol
!= NULL
) {
1756 ret
= sa_proto_unshare(share
, protocol
, path
);
1758 /* need to do all protocols */
1760 sa_optionset_t optionset
;
1762 group
= sa_get_parent_group(share
);
1764 /* Tell all protocols about the share */
1765 for (optionset
= sa_get_optionset(group
, NULL
);
1767 optionset
= sa_get_next_optionset(optionset
)) {
1770 proto
= sa_get_optionset_attr(optionset
, "type");
1771 if (proto
!= NULL
) {
1772 err
= sa_proto_unshare(share
, proto
, path
);
1775 sa_free_attr_string(proto
);
1780 (void) sa_set_share_attr(share
, "shared", NULL
);
1782 sa_free_attr_string(path
);
1787 * sa_remove_share(share)
1789 * remove the specified share from its containing group.
1790 * Remove from the SMF or ZFS configuration space.
1794 sa_remove_share(sa_share_t share
)
1803 type
= sa_get_share_attr(share
, "type");
1804 group
= sa_get_parent_group(share
);
1805 zfs
= sa_get_group_attr(group
, "zfs");
1806 groupname
= sa_get_group_attr(group
, "name");
1807 if (type
!= NULL
&& strcmp(type
, "persist") != 0)
1810 sa_free_attr_string(type
);
1812 /* remove the node from its group then free the memory */
1815 * need to test if "busy"
1817 /* only do SMF action if permanent */
1818 if (!transient
|| zfs
!= NULL
) {
1819 /* remove from legacy dfstab as well as possible SMF */
1820 ret
= sa_delete_legacy(share
, NULL
);
1822 if (!sa_group_is_zfs(group
)) {
1823 sa_handle_impl_t impl_handle
;
1824 impl_handle
= (sa_handle_impl_t
)
1825 sa_find_group_handle(group
);
1826 if (impl_handle
!= NULL
) {
1827 ret
= sa_delete_share(
1828 impl_handle
->scfhandle
, group
,
1831 ret
= SA_SYSTEM_ERR
;
1834 char *sharepath
= sa_get_share_attr(share
,
1836 if (sharepath
!= NULL
) {
1837 ret
= sa_zfs_set_sharenfs(group
,
1839 sa_free_attr_string(sharepath
);
1844 if (groupname
!= NULL
)
1845 sa_free_attr_string(groupname
);
1847 sa_free_attr_string(zfs
);
1849 xmlUnlinkNode((xmlNodePtr
)share
);
1850 xmlFreeNode((xmlNodePtr
)share
);
1855 * sa_move_share(group, share)
1857 * move the specified share to the specified group. Update SMF
1862 sa_move_share(sa_group_t group
, sa_share_t share
)
1864 sa_group_t oldgroup
;
1867 /* remove the node from its group then free the memory */
1869 oldgroup
= sa_get_parent_group(share
);
1870 if (oldgroup
!= group
) {
1871 sa_handle_impl_t impl_handle
;
1872 xmlUnlinkNode((xmlNodePtr
)share
);
1874 * now that the share isn't in its old group, add to
1877 (void) xmlAddChild((xmlNodePtr
)group
, (xmlNodePtr
)share
);
1878 /* need to deal with SMF */
1879 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
1880 if (impl_handle
!= NULL
) {
1882 * need to remove from old group first and then add to
1883 * new group. Ideally, we would do the other order but
1884 * need to avoid having the share in two groups at the
1887 ret
= sa_delete_share(impl_handle
->scfhandle
, oldgroup
,
1890 ret
= sa_commit_share(impl_handle
->scfhandle
,
1893 ret
= SA_SYSTEM_ERR
;
1900 * sa_get_parent_group(share)
1902 * Return the containing group for the share. If a group was actually
1903 * passed in, we don't want a parent so return NULL.
1907 sa_get_parent_group(sa_share_t share
)
1909 xmlNodePtr node
= NULL
;
1910 if (share
!= NULL
) {
1911 node
= ((xmlNodePtr
)share
)->parent
;
1913 * make sure parent is a group and not sharecfg since
1914 * we may be cheating and passing in a group.
1915 * Eventually, groups of groups might come into being.
1918 xmlStrcmp(node
->name
, (xmlChar
*)"sharecfg") == 0)
1921 return ((sa_group_t
)node
);
1925 * _sa_create_group(impl_handle, groupname)
1927 * Create a group in the document. The caller will need to deal with
1928 * configuration store and activation.
1932 _sa_create_group(sa_handle_impl_t impl_handle
, char *groupname
)
1934 xmlNodePtr node
= NULL
;
1936 if (sa_valid_group_name(groupname
)) {
1937 node
= xmlNewChild(impl_handle
->tree
, NULL
, (xmlChar
*)"group",
1940 (void) xmlSetProp(node
, (xmlChar
*)"name",
1941 (xmlChar
*)groupname
);
1942 (void) xmlSetProp(node
, (xmlChar
*)"state",
1943 (xmlChar
*)"enabled");
1946 return ((sa_group_t
)node
);
1950 * _sa_create_zfs_group(group, groupname)
1952 * Create a ZFS subgroup under the specified group. This may
1953 * eventually form the basis of general sub-groups, but is currently
1954 * restricted to ZFS.
1957 _sa_create_zfs_group(sa_group_t group
, char *groupname
)
1959 xmlNodePtr node
= NULL
;
1961 node
= xmlNewChild((xmlNodePtr
)group
, NULL
, (xmlChar
*)"group", NULL
);
1963 (void) xmlSetProp(node
, (xmlChar
*)"name",
1964 (xmlChar
*)groupname
);
1965 (void) xmlSetProp(node
, (xmlChar
*)"state",
1966 (xmlChar
*)"enabled");
1969 return ((sa_group_t
)node
);
1973 * sa_create_group(groupname, *error)
1975 * Create a new group with groupname. Need to validate that it is a
1976 * legal name for SMF and the construct the SMF service instance of
1977 * svc:/network/shares/group to implement the group. All necessary
1978 * operational properties must be added to the group at this point
1979 * (via the SMF transaction model).
1982 sa_create_group(sa_handle_t handle
, char *groupname
, int *error
)
1984 xmlNodePtr node
= NULL
;
1987 char rbacstr
[SA_STRSIZE
];
1988 sa_handle_impl_t impl_handle
= (sa_handle_impl_t
)handle
;
1992 if (impl_handle
== NULL
|| impl_handle
->scfhandle
== NULL
) {
1993 ret
= SA_SYSTEM_ERR
;
1997 group
= sa_get_group(handle
, groupname
);
1998 if (group
!= NULL
) {
1999 ret
= SA_DUPLICATE_NAME
;
2001 if (sa_valid_group_name(groupname
)) {
2002 node
= xmlNewChild(impl_handle
->tree
, NULL
,
2003 (xmlChar
*)"group", NULL
);
2005 (void) xmlSetProp(node
, (xmlChar
*)"name",
2006 (xmlChar
*)groupname
);
2007 /* default to the group being enabled */
2008 (void) xmlSetProp(node
, (xmlChar
*)"state",
2009 (xmlChar
*)"enabled");
2010 ret
= sa_create_instance(impl_handle
->scfhandle
,
2013 ret
= sa_start_transaction(
2014 impl_handle
->scfhandle
,
2018 ret
= sa_set_property(
2019 impl_handle
->scfhandle
,
2020 "state", "enabled");
2022 ret
= sa_end_transaction(
2023 impl_handle
->scfhandle
,
2026 sa_abort_transaction(
2027 impl_handle
->scfhandle
);
2031 /* initialize the RBAC strings */
2032 ret
= sa_start_transaction(
2033 impl_handle
->scfhandle
,
2036 (void) snprintf(rbacstr
,
2037 sizeof (rbacstr
), "%s.%s",
2038 SA_RBAC_MANAGE
, groupname
);
2039 ret
= sa_set_property(
2040 impl_handle
->scfhandle
,
2041 "action_authorization",
2045 (void) snprintf(rbacstr
,
2046 sizeof (rbacstr
), "%s.%s",
2047 SA_RBAC_VALUE
, groupname
);
2048 ret
= sa_set_property(
2049 impl_handle
->scfhandle
,
2050 "value_authorization",
2054 ret
= sa_end_transaction(
2055 impl_handle
->scfhandle
,
2058 sa_abort_transaction(
2059 impl_handle
->scfhandle
);
2064 * Couldn't commit the group
2065 * so we need to undo
2068 xmlUnlinkNode(node
);
2076 ret
= SA_INVALID_NAME
;
2082 return ((sa_group_t
)node
);
2086 * sa_remove_group(group)
2088 * Remove the specified group. This deletes from the SMF repository.
2089 * All property groups and properties are removed.
2093 sa_remove_group(sa_group_t group
)
2097 sa_handle_impl_t impl_handle
;
2099 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2100 if (impl_handle
!= NULL
) {
2101 name
= sa_get_group_attr(group
, "name");
2103 ret
= sa_delete_instance(impl_handle
->scfhandle
, name
);
2104 sa_free_attr_string(name
);
2106 xmlUnlinkNode((xmlNodePtr
)group
); /* make sure unlinked */
2107 xmlFreeNode((xmlNodePtr
)group
); /* now it is gone */
2109 ret
= SA_SYSTEM_ERR
;
2115 * sa_update_config()
2117 * Used to update legacy files that need to be updated in bulk
2118 * Currently, this is a placeholder and will go away in a future
2123 sa_update_config(sa_handle_t handle
)
2126 * do legacy files first so we can tell when they change.
2127 * This will go away when we start updating individual records
2128 * rather than the whole file.
2130 update_legacy_config(handle
);
2135 * get_node_attr(node, tag)
2137 * Get the specified tag(attribute) if it exists on the node. This is
2138 * used internally by a number of attribute oriented functions.
2142 get_node_attr(void *nodehdl
, char *tag
)
2144 xmlNodePtr node
= (xmlNodePtr
)nodehdl
;
2145 xmlChar
*name
= NULL
;
2148 name
= xmlGetProp(node
, (xmlChar
*)tag
);
2149 return ((char *)name
);
2153 * set_node_attr(node, tag)
2155 * Set the specified tag(attribute) to the specified value This is
2156 * used internally by a number of attribute oriented functions. It
2157 * doesn't update the repository, only the internal document state.
2161 set_node_attr(void *nodehdl
, char *tag
, char *value
)
2163 xmlNodePtr node
= (xmlNodePtr
)nodehdl
;
2164 if (node
!= NULL
&& tag
!= NULL
) {
2166 (void) xmlSetProp(node
, (xmlChar
*)tag
,
2169 (void) xmlUnsetProp(node
, (xmlChar
*)tag
);
2174 * sa_get_group_attr(group, tag)
2176 * Get the specied attribute, if defined, for the group.
2180 sa_get_group_attr(sa_group_t group
, char *tag
)
2182 return (get_node_attr((void *)group
, tag
));
2186 * sa_set_group_attr(group, tag, value)
2188 * set the specified tag/attribute on the group using value as its
2191 * This will result in setting the property in the SMF repository as
2192 * well as in the internal document.
2196 sa_set_group_attr(sa_group_t group
, char *tag
, char *value
)
2200 sa_handle_impl_t impl_handle
;
2203 * ZFS group/subgroup doesn't need the handle so shortcut.
2205 if (sa_group_is_zfs(group
)) {
2206 set_node_attr((void *)group
, tag
, value
);
2210 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2211 if (impl_handle
!= NULL
) {
2212 groupname
= sa_get_group_attr(group
, "name");
2213 ret
= sa_get_instance(impl_handle
->scfhandle
, groupname
);
2215 set_node_attr((void *)group
, tag
, value
);
2216 ret
= sa_start_transaction(impl_handle
->scfhandle
,
2219 ret
= sa_set_property(impl_handle
->scfhandle
,
2222 ret
= sa_end_transaction(
2223 impl_handle
->scfhandle
,
2226 sa_abort_transaction(
2227 impl_handle
->scfhandle
);
2229 if (ret
== SA_SYSTEM_ERR
)
2230 ret
= SA_NO_PERMISSION
;
2232 if (groupname
!= NULL
)
2233 sa_free_attr_string(groupname
);
2235 ret
= SA_SYSTEM_ERR
;
2241 * sa_get_share_attr(share, tag)
2243 * Return the value of the tag/attribute set on the specified
2244 * share. Returns NULL if the tag doesn't exist.
2248 sa_get_share_attr(sa_share_t share
, char *tag
)
2250 return (get_node_attr((void *)share
, tag
));
2254 * _sa_set_share_description(share, description)
2256 * Add a description tag with text contents to the specified share. A
2257 * separate XML tag is used rather than a property. This can also be
2258 * used with resources.
2262 _sa_set_share_description(void *share
, char *content
)
2265 node
= xmlNewChild((xmlNodePtr
)share
, NULL
, (xmlChar
*)"description",
2267 xmlNodeSetContent(node
, (xmlChar
*)content
);
2272 * sa_set_share_attr(share, tag, value)
2274 * Set the share attribute specified by tag to the specified value. In
2275 * the case of "resource", enforce a no duplicates in a group rule. If
2276 * the share is not transient, commit the changes to the repository
2277 * else just update the share internally.
2281 sa_set_share_attr(sa_share_t share
, char *tag
, char *value
)
2284 sa_share_t resource
;
2287 group
= sa_get_parent_group(share
);
2290 * There are some attributes that may have specific
2291 * restrictions on them. Initially, only "resource" has
2292 * special meaning that needs to be checked. Only one instance
2293 * of a resource name may exist within a group.
2296 if (strcmp(tag
, "resource") == 0) {
2297 resource
= sa_get_resource(group
, value
);
2298 if (resource
!= share
&& resource
!= NULL
)
2299 ret
= SA_DUPLICATE_NAME
;
2302 set_node_attr((void *)share
, tag
, value
);
2303 if (group
!= NULL
) {
2305 /* we can probably optimize this some */
2306 type
= sa_get_share_attr(share
, "type");
2307 if (type
== NULL
|| strcmp(type
, "transient") != 0) {
2308 sa_handle_impl_t impl_handle
;
2310 (sa_handle_impl_t
)sa_find_group_handle(
2312 if (impl_handle
!= NULL
) {
2313 ret
= sa_commit_share(
2314 impl_handle
->scfhandle
, group
,
2317 ret
= SA_SYSTEM_ERR
;
2321 sa_free_attr_string(type
);
2328 * sa_get_property_attr(prop, tag)
2330 * Get the value of the specified property attribute. Standard
2331 * attributes are "type" and "value".
2335 sa_get_property_attr(sa_property_t prop
, char *tag
)
2337 return (get_node_attr((void *)prop
, tag
));
2341 * sa_get_optionset_attr(prop, tag)
2343 * Get the value of the specified property attribute. Standard
2344 * attribute is "type".
2348 sa_get_optionset_attr(sa_property_t optionset
, char *tag
)
2350 return (get_node_attr((void *)optionset
, tag
));
2355 * sa_set_optionset_attr(optionset, tag, value)
2357 * Set the specified attribute(tag) to the specified value on the
2362 sa_set_optionset_attr(sa_group_t optionset
, char *tag
, char *value
)
2364 set_node_attr((void *)optionset
, tag
, value
);
2368 * sa_free_attr_string(string)
2370 * Free the string that was returned in one of the sa_get_*_attr()
2375 sa_free_attr_string(char *string
)
2377 xmlFree((xmlChar
*)string
);
2381 * sa_get_optionset(group, proto)
2383 * Return the optionset, if it exists, that is associated with the
2384 * specified protocol.
2388 sa_get_optionset(void *group
, char *proto
)
2391 xmlChar
*value
= NULL
;
2393 for (node
= ((xmlNodePtr
)group
)->children
; node
!= NULL
;
2394 node
= node
->next
) {
2395 if (xmlStrcmp(node
->name
, (xmlChar
*)"optionset") == 0) {
2396 value
= xmlGetProp(node
, (xmlChar
*)"type");
2397 if (proto
!= NULL
) {
2398 if (value
!= NULL
&&
2399 xmlStrcmp(value
, (xmlChar
*)proto
) == 0) {
2402 if (value
!= NULL
) {
2413 return ((sa_optionset_t
)node
);
2417 * sa_get_next_optionset(optionset)
2419 * Return the next optionset in the group. NULL if this was the last.
2423 sa_get_next_optionset(sa_optionset_t optionset
)
2427 for (node
= ((xmlNodePtr
)optionset
)->next
; node
!= NULL
;
2428 node
= node
->next
) {
2429 if (xmlStrcmp(node
->name
, (xmlChar
*)"optionset") == 0) {
2433 return ((sa_optionset_t
)node
);
2437 * sa_get_security(group, sectype, proto)
2439 * Return the security optionset. The internal name is a hold over
2440 * from the implementation and will be changed before the API is
2441 * finalized. This is really a named optionset that can be negotiated
2442 * as a group of properties (like NFS security options).
2446 sa_get_security(sa_group_t group
, char *sectype
, char *proto
)
2449 xmlChar
*value
= NULL
;
2451 for (node
= ((xmlNodePtr
)group
)->children
; node
!= NULL
;
2452 node
= node
->next
) {
2453 if (xmlStrcmp(node
->name
, (xmlChar
*)"security") == 0) {
2454 if (proto
!= NULL
) {
2455 value
= xmlGetProp(node
, (xmlChar
*)"type");
2456 if (value
== NULL
||
2458 xmlStrcmp(value
, (xmlChar
*)proto
) != 0)) {
2459 /* it doesn't match so continue */
2465 if (value
!= NULL
) {
2469 /* potential match */
2470 if (sectype
!= NULL
) {
2471 value
= xmlGetProp(node
, (xmlChar
*)"sectype");
2472 if (value
!= NULL
&&
2473 xmlStrcmp(value
, (xmlChar
*)sectype
) == 0) {
2480 if (value
!= NULL
) {
2487 return ((sa_security_t
)node
);
2491 * sa_get_next_security(security)
2493 * Get the next security optionset if one exists.
2497 sa_get_next_security(sa_security_t security
)
2501 for (node
= ((xmlNodePtr
)security
)->next
; node
!= NULL
;
2502 node
= node
->next
) {
2503 if (xmlStrcmp(node
->name
, (xmlChar
*)"security") == 0) {
2507 return ((sa_security_t
)node
);
2511 * sa_get_property(optionset, prop)
2513 * Get the property object with the name specified in prop from the
2518 sa_get_property(sa_optionset_t optionset
, char *prop
)
2520 xmlNodePtr node
= (xmlNodePtr
)optionset
;
2521 xmlChar
*value
= NULL
;
2523 if (optionset
== NULL
)
2526 for (node
= node
->children
; node
!= NULL
;
2527 node
= node
->next
) {
2528 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
2531 value
= xmlGetProp(node
, (xmlChar
*)"type");
2532 if (value
!= NULL
&&
2533 xmlStrcmp(value
, (xmlChar
*)prop
) == 0) {
2536 if (value
!= NULL
) {
2544 if (node
!= NULL
&& xmlStrcmp(node
->name
, (xmlChar
*)"option") != 0) {
2546 * avoid a non option node -- it is possible to be a
2551 return ((sa_property_t
)node
);
2555 * sa_get_next_property(property)
2557 * Get the next property following the specified property. NULL if
2558 * this was the last.
2562 sa_get_next_property(sa_property_t property
)
2566 for (node
= ((xmlNodePtr
)property
)->next
; node
!= NULL
;
2567 node
= node
->next
) {
2568 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
2572 return ((sa_property_t
)node
);
2576 * sa_set_share_description(share, content)
2578 * Set the description of share to content.
2582 sa_set_share_description(sa_share_t share
, char *content
)
2588 for (node
= ((xmlNodePtr
)share
)->children
; node
!= NULL
;
2589 node
= node
->next
) {
2590 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0) {
2594 /* no existing description but want to add */
2595 if (node
== NULL
&& content
!= NULL
) {
2596 /* add a description */
2597 node
= _sa_set_share_description(share
, content
);
2598 } else if (node
!= NULL
&& content
!= NULL
) {
2599 /* update a description */
2600 xmlNodeSetContent(node
, (xmlChar
*)content
);
2601 } else if (node
!= NULL
&& content
== NULL
) {
2602 /* remove an existing description */
2603 xmlUnlinkNode(node
);
2606 group
= sa_get_parent_group(share
);
2607 if (group
!= NULL
&&
2608 sa_is_persistent(share
) && (!sa_group_is_zfs(group
))) {
2609 sa_handle_impl_t impl_handle
;
2610 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2611 if (impl_handle
!= NULL
) {
2612 ret
= sa_commit_share(impl_handle
->scfhandle
, group
,
2615 ret
= SA_SYSTEM_ERR
;
2622 * fixproblemchars(string)
2624 * don't want any newline or tab characters in the text since these
2625 * could break display of data and legacy file formats.
2628 fixproblemchars(char *str
)
2631 for (c
= *str
; c
!= '\0'; c
= *++str
) {
2632 if (c
== '\t' || c
== '\n')
2640 * sa_get_share_description(share)
2642 * Return the description text for the specified share if it
2643 * exists. NULL if no description exists.
2647 sa_get_share_description(sa_share_t share
)
2649 xmlChar
*description
= NULL
;
2652 for (node
= ((xmlNodePtr
)share
)->children
; node
!= NULL
;
2653 node
= node
->next
) {
2654 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0) {
2659 description
= xmlNodeGetContent(node
);
2660 fixproblemchars((char *)description
);
2662 return ((char *)description
);
2666 * sa_free(share_description(description)
2668 * Free the description string.
2672 sa_free_share_description(char *description
)
2674 xmlFree((xmlChar
*)description
);
2678 * sa_create_optionset(group, proto)
2680 * Create an optionset for the specified protocol in the specied
2681 * group. This is manifested as a property group within SMF.
2685 sa_create_optionset(sa_group_t group
, char *proto
)
2687 sa_optionset_t optionset
;
2688 sa_group_t parent
= group
;
2689 sa_share_t share
= NULL
;
2693 optionset
= sa_get_optionset(group
, proto
);
2694 if (optionset
!= NULL
) {
2695 /* can't have a duplicate protocol */
2699 * Account for resource names being slightly
2702 if (sa_is_share(group
)) {
2704 * Transient shares do not have an "id" so not an
2705 * error to not find one.
2707 id
= sa_get_share_attr((sa_share_t
)group
, "id");
2708 } else if (sa_is_resource(group
)) {
2709 share
= sa_get_resource_parent(
2710 (sa_resource_t
)group
);
2711 id
= sa_get_resource_attr(share
, "id");
2713 /* id can be NULL if the group is transient (ZFS) */
2714 if (id
== NULL
&& sa_is_persistent(group
))
2717 if (err
== SA_NO_MEMORY
) {
2719 * Couldn't get the id for the share or
2720 * resource. While this could be a
2721 * configuration issue, it is most likely an
2722 * out of memory. In any case, fail the create.
2727 optionset
= (sa_optionset_t
)xmlNewChild((xmlNodePtr
)group
,
2728 NULL
, (xmlChar
*)"optionset", NULL
);
2730 * only put to repository if on a group and we were
2731 * able to create an optionset.
2733 if (optionset
!= NULL
) {
2734 char oname
[SA_STRSIZE
];
2738 * Need to get parent group in all cases, but also get
2739 * the share if this is a resource.
2741 if (sa_is_share(group
)) {
2742 parent
= sa_get_parent_group((sa_share_t
)group
);
2743 } else if (sa_is_resource(group
)) {
2744 share
= sa_get_resource_parent(
2745 (sa_resource_t
)group
);
2746 parent
= sa_get_parent_group(share
);
2749 sa_set_optionset_attr(optionset
, "type", proto
);
2751 (void) sa_optionset_name(optionset
, oname
,
2752 sizeof (oname
), id
);
2753 groupname
= sa_get_group_attr(parent
, "name");
2754 if (groupname
!= NULL
&& sa_is_persistent(group
)) {
2755 sa_handle_impl_t impl_handle
;
2757 (sa_handle_impl_t
)sa_find_group_handle(
2759 assert(impl_handle
!= NULL
);
2760 if (impl_handle
!= NULL
) {
2761 (void) sa_get_instance(
2762 impl_handle
->scfhandle
, groupname
);
2763 (void) sa_create_pgroup(
2764 impl_handle
->scfhandle
, oname
);
2767 if (groupname
!= NULL
)
2768 sa_free_attr_string(groupname
);
2773 sa_free_attr_string(id
);
2778 * sa_get_property_parent(property)
2780 * Given a property, return the object it is a property of. This will
2781 * be an optionset of some type.
2784 static sa_optionset_t
2785 sa_get_property_parent(sa_property_t property
)
2787 xmlNodePtr node
= NULL
;
2789 if (property
!= NULL
)
2790 node
= ((xmlNodePtr
)property
)->parent
;
2791 return ((sa_optionset_t
)node
);
2795 * sa_get_optionset_parent(optionset)
2797 * Return the parent of the specified optionset. This could be a group
2802 sa_get_optionset_parent(sa_optionset_t optionset
)
2804 xmlNodePtr node
= NULL
;
2806 if (optionset
!= NULL
)
2807 node
= ((xmlNodePtr
)optionset
)->parent
;
2808 return ((sa_group_t
)node
);
2812 * zfs_needs_update(share)
2814 * In order to avoid making multiple updates to a ZFS share when
2815 * setting properties, the share attribute "changed" will be set to
2816 * true when a property is added or modified. When done adding
2817 * properties, we can then detect that an update is needed. We then
2818 * clear the state here to detect additional changes.
2822 zfs_needs_update(sa_share_t share
)
2827 attr
= sa_get_share_attr(share
, "changed");
2829 sa_free_attr_string(attr
);
2832 set_node_attr((void *)share
, "changed", NULL
);
2837 * zfs_set_update(share)
2839 * Set the changed attribute of the share to true.
2843 zfs_set_update(sa_share_t share
)
2845 set_node_attr((void *)share
, "changed", "true");
2849 * sa_commit_properties(optionset, clear)
2851 * Check if SMF or ZFS config and either update or abort the pending
2856 sa_commit_properties(sa_optionset_t optionset
, int clear
)
2861 int needsupdate
= 0;
2863 sa_handle_impl_t impl_handle
;
2865 group
= sa_get_optionset_parent(optionset
);
2866 if (group
!= NULL
&& (sa_is_share(group
) || is_zfs_group(group
))) {
2867 /* only update ZFS if on a share */
2868 parent
= sa_get_parent_group(group
);
2870 if (parent
!= NULL
&& is_zfs_group(parent
))
2871 needsupdate
= zfs_needs_update(group
);
2876 if (!clear
&& needsupdate
)
2877 ret
= sa_zfs_update((sa_share_t
)group
);
2879 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2880 if (impl_handle
!= NULL
) {
2882 (void) sa_abort_transaction(
2883 impl_handle
->scfhandle
);
2885 ret
= sa_end_transaction(
2886 impl_handle
->scfhandle
, impl_handle
);
2889 ret
= SA_SYSTEM_ERR
;
2896 * sa_destroy_optionset(optionset)
2898 * Remove the optionset from its group. Update the repository to
2899 * reflect this change.
2903 sa_destroy_optionset(sa_optionset_t optionset
)
2905 char name
[SA_STRSIZE
];
2912 /* now delete the prop group */
2913 group
= sa_get_optionset_parent(optionset
);
2914 if (group
!= NULL
) {
2915 if (sa_is_resource(group
)) {
2916 sa_resource_t resource
= group
;
2917 sa_share_t share
= sa_get_resource_parent(resource
);
2918 group
= sa_get_parent_group(share
);
2919 id
= sa_get_share_attr(share
, "id");
2920 } else if (sa_is_share(group
)) {
2921 id
= sa_get_share_attr((sa_share_t
)group
, "id");
2923 ispersist
= sa_is_persistent(group
);
2926 sa_handle_impl_t impl_handle
;
2927 len
= sa_optionset_name(optionset
, name
, sizeof (name
), id
);
2928 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
2929 if (impl_handle
!= NULL
) {
2931 ret
= sa_delete_pgroup(impl_handle
->scfhandle
,
2935 ret
= SA_SYSTEM_ERR
;
2938 xmlUnlinkNode((xmlNodePtr
)optionset
);
2939 xmlFreeNode((xmlNodePtr
)optionset
);
2941 sa_free_attr_string(id
);
2945 /* private to the implementation */
2947 _sa_remove_optionset(sa_optionset_t optionset
)
2951 xmlUnlinkNode((xmlNodePtr
)optionset
);
2952 xmlFreeNode((xmlNodePtr
)optionset
);
2957 * sa_create_security(group, sectype, proto)
2959 * Create a security optionset (one that has a type name and a
2960 * proto). Security is left over from a pure NFS implementation. The
2961 * naming will change in the future when the API is released.
2964 sa_create_security(sa_group_t group
, char *sectype
, char *proto
)
2966 sa_security_t security
;
2969 char *groupname
= NULL
;
2971 if (group
!= NULL
&& sa_is_share(group
)) {
2972 id
= sa_get_share_attr((sa_share_t
)group
, "id");
2973 parent
= sa_get_parent_group(group
);
2975 groupname
= sa_get_group_attr(parent
, "name");
2976 } else if (group
!= NULL
) {
2977 groupname
= sa_get_group_attr(group
, "name");
2980 security
= sa_get_security(group
, sectype
, proto
);
2981 if (security
!= NULL
) {
2982 /* can't have a duplicate security option */
2985 security
= (sa_security_t
)xmlNewChild((xmlNodePtr
)group
,
2986 NULL
, (xmlChar
*)"security", NULL
);
2987 if (security
!= NULL
) {
2988 char oname
[SA_STRSIZE
];
2989 sa_set_security_attr(security
, "type", proto
);
2991 sa_set_security_attr(security
, "sectype", sectype
);
2992 (void) sa_security_name(security
, oname
,
2993 sizeof (oname
), id
);
2994 if (groupname
!= NULL
&& sa_is_persistent(group
)) {
2995 sa_handle_impl_t impl_handle
;
2997 (sa_handle_impl_t
)sa_find_group_handle(
2999 if (impl_handle
!= NULL
) {
3000 (void) sa_get_instance(
3001 impl_handle
->scfhandle
, groupname
);
3002 (void) sa_create_pgroup(
3003 impl_handle
->scfhandle
, oname
);
3009 sa_free_attr_string(id
);
3010 if (groupname
!= NULL
)
3011 sa_free_attr_string(groupname
);
3016 * sa_destroy_security(security)
3018 * Remove the specified optionset from the document and the
3023 sa_destroy_security(sa_security_t security
)
3025 char name
[SA_STRSIZE
];
3033 group
= sa_get_optionset_parent(security
);
3036 iszfs
= sa_group_is_zfs(group
);
3038 if (group
!= NULL
&& !iszfs
) {
3039 if (sa_is_share(group
))
3040 ispersist
= sa_is_persistent(group
);
3041 id
= sa_get_share_attr((sa_share_t
)group
, "id");
3044 len
= sa_security_name(security
, name
, sizeof (name
), id
);
3045 if (!iszfs
&& len
> 0) {
3046 sa_handle_impl_t impl_handle
;
3048 (sa_handle_impl_t
)sa_find_group_handle(group
);
3049 if (impl_handle
!= NULL
) {
3050 ret
= sa_delete_pgroup(impl_handle
->scfhandle
,
3053 ret
= SA_SYSTEM_ERR
;
3057 xmlUnlinkNode((xmlNodePtr
)security
);
3058 xmlFreeNode((xmlNodePtr
)security
);
3060 ret
= sa_zfs_update(group
);
3062 sa_free_attr_string(id
);
3067 * sa_get_security_attr(optionset, tag)
3069 * Return the specified attribute value from the optionset.
3073 sa_get_security_attr(sa_property_t optionset
, char *tag
)
3075 return (get_node_attr((void *)optionset
, tag
));
3080 * sa_set_security_attr(optionset, tag, value)
3082 * Set the optioset attribute specied by tag to the specified value.
3086 sa_set_security_attr(sa_group_t optionset
, char *tag
, char *value
)
3088 set_node_attr((void *)optionset
, tag
, value
);
3092 * is_nodetype(node, type)
3094 * Check to see if node is of the type specified.
3098 is_nodetype(void *node
, char *type
)
3100 return (strcmp((char *)((xmlNodePtr
)node
)->name
, type
) == 0);
3106 * Add or update a property. Pulled out of sa_set_prop_by_prop for
3110 add_or_update(scfutilhandle_t
*scf_handle
, int type
, scf_value_t
*value
,
3111 scf_transaction_entry_t
*entry
, char *name
, char *valstr
)
3113 int ret
= SA_SYSTEM_ERR
;
3115 if (value
!= NULL
) {
3116 if (type
== SA_PROP_OP_ADD
)
3117 ret
= scf_transaction_property_new(scf_handle
->trans
,
3118 entry
, name
, SCF_TYPE_ASTRING
);
3120 ret
= scf_transaction_property_change(scf_handle
->trans
,
3121 entry
, name
, SCF_TYPE_ASTRING
);
3123 ret
= scf_value_set_astring(value
, valstr
);
3125 ret
= scf_entry_add_value(entry
, value
);
3128 scf_value_destroy(value
);
3130 scf_entry_destroy(entry
);
3133 return (SA_SYSTEM_ERR
);
3137 * sa_set_prop_by_prop(optionset, group, prop, type)
3139 * Add/remove/update the specified property prop into the optionset or
3140 * share. If a share, sort out which property group based on GUID. In
3141 * all cases, the appropriate transaction is set (or ZFS share is
3142 * marked as needing an update)
3146 sa_set_prop_by_prop(sa_optionset_t optionset
, sa_group_t group
,
3147 sa_property_t prop
, int type
)
3152 scf_transaction_entry_t
*entry
;
3154 int opttype
; /* 1 == optionset, 0 == security */
3157 sa_group_t parent
= NULL
;
3158 sa_share_t share
= NULL
;
3159 sa_handle_impl_t impl_handle
;
3160 scfutilhandle_t
*scf_handle
;
3162 if (!sa_is_persistent(group
)) {
3164 * if the group/share is not persistent we don't need
3165 * to do anything here
3169 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
3170 if (impl_handle
== NULL
|| impl_handle
->scfhandle
== NULL
)
3171 return (SA_SYSTEM_ERR
);
3172 scf_handle
= impl_handle
->scfhandle
;
3173 name
= sa_get_property_attr(prop
, "type");
3174 valstr
= sa_get_property_attr(prop
, "value");
3175 entry
= scf_entry_create(scf_handle
->handle
);
3176 opttype
= is_nodetype((void *)optionset
, "optionset");
3179 * Check for share vs. resource since they need slightly
3180 * different treatment given the hierarchy.
3182 if (valstr
!= NULL
&& entry
!= NULL
) {
3183 if (sa_is_share(group
)) {
3184 parent
= sa_get_parent_group(group
);
3185 share
= (sa_share_t
)group
;
3187 iszfs
= is_zfs_group(parent
);
3188 } else if (sa_is_resource(group
)) {
3189 share
= sa_get_parent_group(group
);
3191 parent
= sa_get_parent_group(share
);
3193 iszfs
= is_zfs_group(group
);
3196 if (scf_handle
->trans
== NULL
) {
3197 char oname
[SA_STRSIZE
];
3198 char *groupname
= NULL
;
3199 if (share
!= NULL
) {
3202 sa_get_group_attr(parent
,
3204 id
= sa_get_share_attr(
3205 (sa_share_t
)share
, "id");
3207 groupname
= sa_get_group_attr(group
,
3210 if (groupname
!= NULL
) {
3211 ret
= sa_get_instance(scf_handle
,
3213 sa_free_attr_string(groupname
);
3216 (void) sa_optionset_name(optionset
,
3217 oname
, sizeof (oname
), id
);
3219 (void) sa_security_name(optionset
,
3220 oname
, sizeof (oname
), id
);
3221 ret
= sa_start_transaction(scf_handle
, oname
);
3223 sa_free_attr_string(id
);
3227 case SA_PROP_OP_REMOVE
:
3228 ret
= scf_transaction_property_delete(
3229 scf_handle
->trans
, entry
, name
);
3231 case SA_PROP_OP_ADD
:
3232 case SA_PROP_OP_UPDATE
:
3233 value
= scf_value_create(
3234 scf_handle
->handle
);
3235 ret
= add_or_update(scf_handle
, type
,
3236 value
, entry
, name
, valstr
);
3242 * ZFS update. The calling function would have updated
3243 * the internal XML structure. Just need to flag it as
3246 zfs_set_update((sa_share_t
)group
);
3251 sa_free_attr_string(name
);
3253 sa_free_attr_string(valstr
);
3254 else if (entry
!= NULL
)
3255 scf_entry_destroy(entry
);
3258 ret
= SA_SYSTEM_ERR
;
3264 * sa_create_section(name, value)
3266 * Create a new section with the specified name and extra data.
3270 sa_create_section(char *name
, char *extra
)
3274 node
= xmlNewNode(NULL
, (xmlChar
*)"section");
3277 (void) xmlSetProp(node
, (xmlChar
*)"name",
3280 (void) xmlSetProp(node
, (xmlChar
*)"extra",
3283 return ((sa_property_t
)node
);
3287 sa_set_section_attr(sa_property_t sect
, char *name
, char *value
)
3289 (void) xmlSetProp(sect
, (xmlChar
*)name
, (xmlChar
*)value
);
3293 * sa_create_property(section, name, value)
3295 * Create a new property with the specified name and value.
3299 sa_create_property(char *name
, char *value
)
3303 node
= xmlNewNode(NULL
, (xmlChar
*)"option");
3305 (void) xmlSetProp(node
, (xmlChar
*)"type", (xmlChar
*)name
);
3306 (void) xmlSetProp(node
, (xmlChar
*)"value", (xmlChar
*)value
);
3308 return ((sa_property_t
)node
);
3312 * sa_add_property(object, property)
3314 * Add the specified property to the object. Issue the appropriate
3315 * transaction or mark a ZFS object as needing an update.
3319 sa_add_property(void *object
, sa_property_t property
)
3326 if (property
!= NULL
) {
3328 handle
= sa_find_group_handle((sa_group_t
)object
);
3329 /* It is legitimate to not find a handle */
3330 proto
= sa_get_optionset_attr(object
, "type");
3331 if ((ret
= sa_valid_property(handle
, object
, proto
,
3332 property
)) == SA_OK
) {
3333 property
= (sa_property_t
)xmlAddChild(
3334 (xmlNodePtr
)object
, (xmlNodePtr
)property
);
3337 sa_free_attr_string(proto
);
3341 sa_free_attr_string(proto
);
3345 parent
= sa_get_parent_group(object
);
3346 if (!sa_is_persistent(parent
))
3349 if (sa_is_resource(parent
)) {
3351 * Resources are children of share. Need to go up two
3352 * levels to find the group but the parent needs to be
3353 * the share at this point in order to get the "id".
3355 parent
= sa_get_parent_group(parent
);
3356 group
= sa_get_parent_group(parent
);
3357 } else if (sa_is_share(parent
)) {
3358 group
= sa_get_parent_group(parent
);
3363 if (property
== NULL
) {
3366 char oname
[SA_STRSIZE
];
3368 if (!is_zfs_group(group
)) {
3370 sa_handle_impl_t impl_handle
;
3371 scfutilhandle_t
*scf_handle
;
3373 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(
3375 if (impl_handle
== NULL
||
3376 impl_handle
->scfhandle
== NULL
)
3377 ret
= SA_SYSTEM_ERR
;
3379 scf_handle
= impl_handle
->scfhandle
;
3380 if (sa_is_share((sa_group_t
)parent
)) {
3381 id
= sa_get_share_attr(
3382 (sa_share_t
)parent
, "id");
3384 if (scf_handle
->trans
== NULL
) {
3385 if (is_nodetype(object
, "optionset")) {
3386 (void) sa_optionset_name(
3387 (sa_optionset_t
)object
,
3388 oname
, sizeof (oname
), id
);
3390 (void) sa_security_name(
3391 (sa_optionset_t
)object
,
3392 oname
, sizeof (oname
), id
);
3394 ret
= sa_start_transaction(scf_handle
,
3400 name
= sa_get_property_attr(property
,
3402 value
= sa_get_property_attr(property
,
3404 if (name
!= NULL
&& value
!= NULL
) {
3405 if (scf_handle
->scf_state
==
3407 ret
= sa_set_property(
3412 ret
= SA_CONFIG_ERR
;
3415 sa_free_attr_string(
3418 sa_free_attr_string(value
);
3421 sa_free_attr_string(id
);
3425 * ZFS is a special case. We do want
3426 * to allow editing property/security
3427 * lists since we can have a better
3428 * syntax and we also want to keep
3429 * things consistent when possible.
3431 * Right now, we defer until the
3432 * sa_commit_properties so we can get
3433 * them all at once. We do need to
3434 * mark the share as "changed"
3436 zfs_set_update((sa_share_t
)parent
);
3443 * sa_remove_property(property)
3445 * Remove the specied property from its containing object. Update the
3446 * repository as appropriate.
3450 sa_remove_property(sa_property_t property
)
3454 if (property
!= NULL
) {
3455 sa_optionset_t optionset
;
3457 optionset
= sa_get_property_parent(property
);
3458 if (optionset
!= NULL
) {
3459 group
= sa_get_optionset_parent(optionset
);
3460 if (group
!= NULL
) {
3461 ret
= sa_set_prop_by_prop(optionset
, group
,
3462 property
, SA_PROP_OP_REMOVE
);
3465 xmlUnlinkNode((xmlNodePtr
)property
);
3466 xmlFreeNode((xmlNodePtr
)property
);
3468 ret
= SA_NO_SUCH_PROP
;
3474 * sa_update_property(property, value)
3476 * Update the specified property to the new value. If value is NULL,
3477 * we currently treat this as a remove.
3481 sa_update_property(sa_property_t property
, char *value
)
3484 if (value
== NULL
) {
3485 return (sa_remove_property(property
));
3487 sa_optionset_t optionset
;
3489 set_node_attr((void *)property
, "value", value
);
3490 optionset
= sa_get_property_parent(property
);
3491 if (optionset
!= NULL
) {
3492 group
= sa_get_optionset_parent(optionset
);
3493 if (group
!= NULL
) {
3494 ret
= sa_set_prop_by_prop(optionset
, group
,
3495 property
, SA_PROP_OP_UPDATE
);
3498 ret
= SA_NO_SUCH_PROP
;
3505 * sa_get_protocol_section(propset, prop)
3507 * Get the specified protocol specific section. These are global to
3508 * the protocol and not specific to a group or share.
3511 sa_protocol_properties_t
3512 sa_get_protocol_section(sa_protocol_properties_t propset
, char *section
)
3514 xmlNodePtr node
= (xmlNodePtr
)propset
;
3515 xmlChar
*value
= NULL
;
3518 proto
= sa_get_optionset_attr(propset
, "type");
3519 if ((sa_proto_get_featureset(proto
) & SA_FEATURE_HAS_SECTIONS
) == 0) {
3521 sa_free_attr_string(proto
);
3525 for (node
= node
->children
; node
!= NULL
;
3526 node
= node
->next
) {
3527 if (xmlStrcmp(node
->name
, (xmlChar
*)"section") == 0) {
3528 if (section
== NULL
)
3530 value
= xmlGetProp(node
, (xmlChar
*)"name");
3531 if (value
!= NULL
&&
3532 xmlStrcasecmp(value
, (xmlChar
*)section
) == 0) {
3535 if (value
!= NULL
) {
3544 sa_free_attr_string(proto
);
3545 if (node
!= NULL
&& xmlStrcmp(node
->name
, (xmlChar
*)"section") != 0) {
3547 * avoid a non option node -- it is possible to be a
3552 return ((sa_protocol_properties_t
)node
);
3556 * sa_get_next_protocol_section(prop, find)
3558 * Get the next protocol specific section in the list.
3562 sa_get_next_protocol_section(sa_property_t prop
, char *find
)
3565 xmlChar
*value
= NULL
;
3568 proto
= sa_get_optionset_attr(prop
, "type");
3569 if ((sa_proto_get_featureset(proto
) & SA_FEATURE_HAS_SECTIONS
) == 0) {
3571 sa_free_attr_string(proto
);
3572 return ((sa_property_t
)NULL
);
3575 for (node
= ((xmlNodePtr
)prop
)->next
; node
!= NULL
;
3576 node
= node
->next
) {
3577 if (xmlStrcmp(node
->name
, (xmlChar
*)"section") == 0) {
3580 value
= xmlGetProp(node
, (xmlChar
*)"name");
3581 if (value
!= NULL
&&
3582 xmlStrcasecmp(value
, (xmlChar
*)find
) == 0) {
3585 if (value
!= NULL
) {
3595 sa_free_attr_string(proto
);
3596 return ((sa_property_t
)node
);
3600 * sa_get_protocol_property(propset, prop)
3602 * Get the specified protocol specific property. These are global to
3603 * the protocol and not specific to a group or share.
3607 sa_get_protocol_property(sa_protocol_properties_t propset
, char *prop
)
3609 xmlNodePtr node
= (xmlNodePtr
)propset
;
3610 xmlChar
*value
= NULL
;
3612 if (propset
== NULL
)
3615 for (node
= node
->children
; node
!= NULL
;
3616 node
= node
->next
) {
3617 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
3620 value
= xmlGetProp(node
, (xmlChar
*)"type");
3621 if (value
!= NULL
&&
3622 xmlStrcasecmp(value
, (xmlChar
*)prop
) == 0) {
3625 if (value
!= NULL
) {
3633 if (node
!= NULL
&& xmlStrcmp(node
->name
, (xmlChar
*)"option") != 0) {
3635 * avoid a non option node -- it is possible to be a
3640 return ((sa_property_t
)node
);
3644 * sa_get_next_protocol_property(prop)
3646 * Get the next protocol specific property in the list.
3650 sa_get_next_protocol_property(sa_property_t prop
, char *find
)
3653 xmlChar
*value
= NULL
;
3655 for (node
= ((xmlNodePtr
)prop
)->next
; node
!= NULL
;
3656 node
= node
->next
) {
3657 if (xmlStrcmp(node
->name
, (xmlChar
*)"option") == 0) {
3660 value
= xmlGetProp(node
, (xmlChar
*)"type");
3661 if (value
!= NULL
&&
3662 xmlStrcasecmp(value
, (xmlChar
*)find
) == 0) {
3665 if (value
!= NULL
) {
3674 return ((sa_property_t
)node
);
3678 * sa_set_protocol_property(prop, value)
3680 * Set the specified property to have the new value. The protocol
3681 * specific plugin will then be called to update the property.
3685 sa_set_protocol_property(sa_property_t prop
, char *section
, char *value
)
3687 sa_protocol_properties_t propset
;
3689 int ret
= SA_INVALID_PROTOCOL
;
3691 propset
= ((xmlNodePtr
)prop
)->parent
;
3692 if (propset
!= NULL
) {
3693 proto
= sa_get_optionset_attr(propset
, "type");
3694 if (proto
!= NULL
) {
3695 if (section
!= NULL
)
3696 set_node_attr((xmlNodePtr
)prop
, "section",
3698 set_node_attr((xmlNodePtr
)prop
, "value", value
);
3699 ret
= sa_proto_set_property(proto
, prop
);
3700 sa_free_attr_string(proto
);
3707 * sa_add_protocol_property(propset, prop)
3709 * Add a new property to the protocol specific property set.
3713 sa_add_protocol_property(sa_protocol_properties_t propset
, sa_property_t prop
)
3717 /* should check for legitimacy */
3718 node
= xmlAddChild((xmlNodePtr
)propset
, (xmlNodePtr
)prop
);
3721 return (SA_NO_MEMORY
);
3725 * sa_create_protocol_properties(proto)
3727 * Create a protocol specific property set.
3730 sa_protocol_properties_t
3731 sa_create_protocol_properties(char *proto
)
3735 node
= xmlNewNode(NULL
, (xmlChar
*)"propertyset");
3737 (void) xmlSetProp(node
, (xmlChar
*)"type", (xmlChar
*)proto
);
3742 * sa_get_share_resource(share, resource)
3744 * Get the named resource from the share, if it exists. If resource is
3745 * NULL, get the first resource.
3749 sa_get_share_resource(sa_share_t share
, char *resource
)
3751 xmlNodePtr node
= NULL
;
3754 if (share
!= NULL
) {
3755 for (node
= ((xmlNodePtr
)share
)->children
; node
!= NULL
;
3756 node
= node
->next
) {
3757 if (xmlStrcmp(node
->name
, (xmlChar
*)"resource") == 0) {
3758 if (resource
== NULL
) {
3760 * We are looking for the first
3761 * resource node and not a names
3766 /* is it the correct share? */
3767 name
= xmlGetProp(node
,
3771 (xmlChar
*)resource
) == 0) {
3780 return ((sa_resource_t
)node
);
3784 * sa_get_next_resource(resource)
3785 * Return the next share following the specified share
3786 * from the internal list of shares. Returns NULL if there
3787 * are no more shares. The list is relative to the same
3791 sa_get_next_resource(sa_resource_t resource
)
3793 xmlNodePtr node
= NULL
;
3795 if (resource
!= NULL
) {
3796 for (node
= ((xmlNodePtr
)resource
)->next
; node
!= NULL
;
3797 node
= node
->next
) {
3798 if (xmlStrcmp(node
->name
, (xmlChar
*)"resource") == 0)
3802 return ((sa_share_t
)node
);
3806 * _sa_get_next_resource_index(share)
3808 * get the next resource index number (one greater then current largest)
3812 _sa_get_next_resource_index(sa_share_t share
)
3814 sa_resource_t resource
;
3818 for (resource
= sa_get_share_resource(share
, NULL
);
3820 resource
= sa_get_next_resource(resource
)) {
3821 id
= get_node_attr((void *)resource
, "id");
3827 sa_free_attr_string(id
);
3835 * sa_add_resource(share, resource, persist, &err)
3837 * Adds a new resource name associated with share. The resource name
3838 * must be unique in the system and will be case insensitive (eventually).
3842 sa_add_resource(sa_share_t share
, char *resource
, int persist
, int *error
)
3849 char istring
[8]; /* just big enough for an integer value */
3852 group
= sa_get_parent_group(share
);
3853 handle
= sa_find_group_handle(group
);
3854 res
= sa_find_resource(handle
, resource
);
3856 err
= SA_DUPLICATE_NAME
;
3859 node
= xmlNewChild((xmlNodePtr
)share
, NULL
,
3860 (xmlChar
*)"resource", NULL
);
3862 (void) xmlSetProp(node
, (xmlChar
*)"name",
3863 (xmlChar
*)resource
);
3864 (void) xmlSetProp(node
, (xmlChar
*)"type", persist
?
3865 (xmlChar
*)"persist" : (xmlChar
*)"transient");
3866 if (persist
!= SA_SHARE_TRANSIENT
) {
3867 index
= _sa_get_next_resource_index(share
);
3868 (void) snprintf(istring
, sizeof (istring
), "%d",
3870 (void) xmlSetProp(node
, (xmlChar
*)"id",
3871 (xmlChar
*)istring
);
3873 if (!sa_is_persistent((sa_group_t
)share
))
3876 if (!sa_group_is_zfs(group
)) {
3877 /* ZFS doesn't use resource names */
3878 sa_handle_impl_t ihandle
;
3880 ihandle
= (sa_handle_impl_t
)
3881 sa_find_group_handle(
3883 if (ihandle
!= NULL
)
3884 err
= sa_commit_share(
3885 ihandle
->scfhandle
, group
,
3888 err
= SA_SYSTEM_ERR
;
3890 err
= sa_zfs_update((sa_share_t
)group
);
3898 return ((sa_resource_t
)node
);
3902 * sa_remove_resource(resource)
3904 * Remove the resource name from the share (and the system)
3908 sa_remove_resource(sa_resource_t resource
)
3914 boolean_t transient
= B_FALSE
;
3917 share
= sa_get_resource_parent(resource
);
3918 type
= sa_get_share_attr(share
, "type");
3919 group
= sa_get_parent_group(share
);
3923 if (strcmp(type
, "persist") != 0)
3925 sa_free_attr_string(type
);
3928 /* Disable the resource for all protocols. */
3929 (void) sa_disable_resource(resource
, NULL
);
3931 /* Remove any optionsets from the resource. */
3932 for (opt
= sa_get_optionset(resource
, NULL
);
3934 opt
= sa_get_next_optionset(opt
))
3935 (void) sa_destroy_optionset(opt
);
3937 /* Remove from the share */
3938 xmlUnlinkNode((xmlNode
*)resource
);
3939 xmlFreeNode((xmlNode
*)resource
);
3941 /* only do SMF action if permanent and not ZFS */
3945 if (!sa_group_is_zfs(group
)) {
3946 sa_handle_impl_t ihandle
;
3947 ihandle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
3948 if (ihandle
!= NULL
)
3949 ret
= sa_commit_share(ihandle
->scfhandle
, group
, share
);
3951 ret
= SA_SYSTEM_ERR
;
3953 ret
= sa_zfs_update((sa_share_t
)group
);
3960 * proto_rename_resource(handle, group, resource, newname)
3962 * Helper function for sa_rename_resource that notifies the protocol
3963 * of a resource name change prior to a config repository update.
3966 proto_rename_resource(sa_handle_t handle
, sa_group_t group
,
3967 sa_resource_t resource
, char *newname
)
3969 sa_optionset_t optionset
;
3973 for (optionset
= sa_get_optionset(group
, NULL
);
3975 optionset
= sa_get_next_optionset(optionset
)) {
3977 type
= sa_get_optionset_attr(optionset
, "type");
3979 err
= sa_proto_rename_resource(handle
, type
, resource
,
3983 sa_free_attr_string(type
);
3990 * sa_rename_resource(resource, newname)
3992 * Rename the resource to the new name, if it is unique.
3996 sa_rename_resource(sa_resource_t resource
, char *newname
)
3999 sa_group_t group
= NULL
;
4000 sa_resource_t target
;
4001 int ret
= SA_CONFIG_ERR
;
4002 sa_handle_t handle
= NULL
;
4004 share
= sa_get_resource_parent(resource
);
4008 group
= sa_get_parent_group(share
);
4012 handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
4016 target
= sa_find_resource(handle
, newname
);
4017 if (target
!= NULL
) {
4018 ret
= SA_DUPLICATE_NAME
;
4021 * Everything appears to be valid at this
4022 * point. Change the name of the active share and then
4023 * update the share in the appropriate repository.
4025 ret
= proto_rename_resource(handle
, group
, resource
, newname
);
4026 set_node_attr(resource
, "name", newname
);
4028 if (!sa_is_persistent((sa_group_t
)share
))
4031 if (!sa_group_is_zfs(group
)) {
4032 sa_handle_impl_t ihandle
= (sa_handle_impl_t
)handle
;
4033 ret
= sa_commit_share(ihandle
->scfhandle
, group
,
4036 ret
= sa_zfs_update((sa_share_t
)group
);
4043 * sa_get_resource_attr(resource, tag)
4045 * Get the named attribute of the resource. "name" and "id" are
4046 * currently defined. NULL if tag not defined.
4050 sa_get_resource_attr(sa_resource_t resource
, char *tag
)
4052 return (get_node_attr((void *)resource
, tag
));
4056 * sa_set_resource_attr(resource, tag, value)
4058 * Get the named attribute of the resource. "name" and "id" are
4059 * currently defined. NULL if tag not defined. Currently we don't do
4060 * much, but additional checking may be needed in the future.
4064 sa_set_resource_attr(sa_resource_t resource
, char *tag
, char *value
)
4066 set_node_attr((void *)resource
, tag
, value
);
4071 * sa_get_resource_parent(resource_t)
4073 * Returns the share associated with the resource.
4077 sa_get_resource_parent(sa_resource_t resource
)
4079 sa_share_t share
= NULL
;
4081 if (resource
!= NULL
)
4082 share
= (sa_share_t
)((xmlNodePtr
)resource
)->parent
;
4087 * find_resource(group, name)
4089 * Find the resource within the group.
4092 static sa_resource_t
4093 find_resource(sa_group_t group
, char *resname
)
4096 sa_resource_t resource
= NULL
;
4099 /* Iterate over all the shares and resources in the group. */
4100 for (share
= sa_get_share(group
, NULL
);
4101 share
!= NULL
&& resource
== NULL
;
4102 share
= sa_get_next_share(share
)) {
4103 for (resource
= sa_get_share_resource(share
, NULL
);
4105 resource
= sa_get_next_resource(resource
)) {
4106 name
= sa_get_resource_attr(resource
, "name");
4107 if (name
!= NULL
&& xmlStrcasecmp((xmlChar
*)name
,
4108 (xmlChar
*)resname
) == 0) {
4109 sa_free_attr_string(name
);
4113 sa_free_attr_string(name
);
4121 * sa_find_resource(name)
4123 * Find the named resource in the system.
4127 sa_find_resource(sa_handle_t handle
, char *name
)
4131 sa_resource_t resource
= NULL
;
4134 * Iterate over all groups and zfs subgroups and check for
4135 * resource name in them.
4137 for (group
= sa_get_group(handle
, NULL
); group
!= NULL
;
4138 group
= sa_get_next_group(group
)) {
4140 if (is_zfs_group(group
)) {
4142 (sa_group_t
)_sa_get_child_node((xmlNodePtr
)group
,
4143 (xmlChar
*)"group");
4144 zgroup
!= NULL
&& resource
== NULL
;
4145 zgroup
= sa_get_next_group(zgroup
)) {
4146 resource
= find_resource(zgroup
, name
);
4149 resource
= find_resource(group
, name
);
4151 if (resource
!= NULL
)
4158 * sa_get_resource(group, resource)
4160 * Search all the shares in the specified group for a share with a
4161 * resource name matching the one specified.
4163 * In the future, it may be advantageous to allow group to be NULL and
4164 * search all groups but that isn't needed at present.
4168 sa_get_resource(sa_group_t group
, char *resource
)
4170 sa_share_t share
= NULL
;
4171 sa_resource_t res
= NULL
;
4173 if (resource
!= NULL
) {
4174 for (share
= sa_get_share(group
, NULL
);
4175 share
!= NULL
&& res
== NULL
;
4176 share
= sa_get_next_share(share
)) {
4177 res
= sa_get_share_resource(share
, resource
);
4184 * get_protocol_list(optionset, object)
4186 * Get the protocol optionset list for the object and add them as
4187 * properties to optionset.
4190 get_protocol_list(sa_optionset_t optionset
, void *object
)
4193 sa_optionset_t opts
;
4196 for (opts
= sa_get_optionset(object
, NULL
);
4198 opts
= sa_get_next_optionset(opts
)) {
4200 type
= sa_get_optionset_attr(opts
, "type");
4202 * It is possible to have a non-protocol optionset. We
4203 * skip any of those found.
4207 prop
= sa_create_property(type
, "true");
4208 sa_free_attr_string(type
);
4210 prop
= (sa_property_t
)xmlAddChild((xmlNodePtr
)optionset
,
4212 /* If prop is NULL, don't bother continuing */
4222 * sa_free_protoset(optionset)
4224 * Free the protocol property optionset.
4227 sa_free_protoset(sa_optionset_t optionset
)
4229 if (optionset
!= NULL
) {
4230 xmlUnlinkNode((xmlNodePtr
) optionset
);
4231 xmlFreeNode((xmlNodePtr
) optionset
);
4236 * sa_optionset_t sa_get_active_protocols(object)
4238 * Return a list of the protocols that are active for the object.
4239 * This is currently an internal helper function, but could be
4240 * made visible if there is enough demand for it.
4242 * The function finds the parent group and extracts the protocol
4243 * optionsets creating a new optionset with the protocols as properties.
4245 * The caller must free the returned optionset.
4248 static sa_optionset_t
4249 sa_get_active_protocols(void *object
)
4251 sa_optionset_t options
;
4252 sa_share_t share
= NULL
;
4253 sa_group_t group
= NULL
;
4254 sa_resource_t resource
= NULL
;
4259 options
= (sa_optionset_t
)xmlNewNode(NULL
, (xmlChar
*)"optionset");
4260 if (options
== NULL
)
4264 * Find the objects up the tree that might have protocols
4267 if (sa_is_resource(object
)) {
4268 resource
= (sa_resource_t
)object
;
4269 share
= sa_get_resource_parent(resource
);
4270 group
= sa_get_parent_group(share
);
4271 } else if (sa_is_share(object
)) {
4272 share
= (sa_share_t
)object
;
4273 group
= sa_get_parent_group(share
);
4275 group
= (sa_group_t
)group
;
4277 if (resource
!= NULL
)
4278 ret
= get_protocol_list(options
, resource
);
4279 if (ret
== SA_OK
&& share
!= NULL
)
4280 ret
= get_protocol_list(options
, share
);
4281 if (ret
== SA_OK
&& group
!= NULL
)
4282 ret
= get_protocol_list(options
, group
);
4285 * If there was an error, we won't have a complete list so
4286 * abandon everything. The caller will have to deal with the
4290 sa_free_protoset(options
);
4297 * sa_enable_resource, protocol)
4298 * Disable the specified share to the specified protocol.
4299 * If protocol is NULL, then all protocols.
4302 sa_enable_resource(sa_resource_t resource
, char *protocol
)
4306 if (protocol
!= NULL
) {
4307 ret
= sa_proto_share_resource(protocol
, resource
);
4309 sa_optionset_t protoset
;
4314 /* need to do all protocols */
4315 protoset
= sa_get_active_protocols(resource
);
4316 if (protoset
== NULL
)
4317 return (SA_NO_MEMORY
);
4318 for (prop
= sa_get_property(protoset
, NULL
);
4320 prop
= sa_get_next_property(prop
)) {
4321 proto
= sa_get_property_attr(prop
, "type");
4322 if (proto
== NULL
) {
4326 err
= sa_proto_share_resource(proto
, resource
);
4329 sa_free_attr_string(proto
);
4331 sa_free_protoset(protoset
);
4334 (void) sa_set_resource_attr(resource
, "shared", NULL
);
4340 * sa_disable_resource(resource, protocol)
4342 * Disable the specified share for the specified protocol. If
4343 * protocol is NULL, then all protocols. If the underlying
4344 * protocol doesn't implement disable at the resource level, we
4345 * disable at the share level.
4348 sa_disable_resource(sa_resource_t resource
, char *protocol
)
4352 if (protocol
!= NULL
) {
4353 ret
= sa_proto_unshare_resource(protocol
, resource
);
4354 if (ret
== SA_NOT_IMPLEMENTED
) {
4357 * The protocol doesn't implement unshare
4358 * resource. That implies that resource names are
4359 * simple aliases for this protocol so we need to
4360 * unshare the share.
4362 parent
= sa_get_resource_parent(resource
);
4364 ret
= sa_disable_share(parent
, protocol
);
4366 ret
= SA_CONFIG_ERR
;
4369 sa_optionset_t protoset
;
4374 /* need to do all protocols */
4375 protoset
= sa_get_active_protocols(resource
);
4376 if (protoset
== NULL
)
4377 return (SA_NO_MEMORY
);
4378 for (prop
= sa_get_property(protoset
, NULL
);
4380 prop
= sa_get_next_property(prop
)) {
4381 proto
= sa_get_property_attr(prop
, "type");
4382 if (proto
== NULL
) {
4386 err
= sa_proto_unshare_resource(proto
, resource
);
4387 if (err
== SA_NOT_SUPPORTED
) {
4389 parent
= sa_get_resource_parent(resource
);
4391 err
= sa_disable_share(parent
, proto
);
4393 err
= SA_CONFIG_ERR
;
4397 sa_free_attr_string(proto
);
4399 sa_free_protoset(protoset
);
4402 (void) sa_set_resource_attr(resource
, "shared", NULL
);
4408 * sa_set_resource_description(resource, content)
4410 * Set the description of share to content.
4414 sa_set_resource_description(sa_resource_t resource
, char *content
)
4421 for (node
= ((xmlNodePtr
)resource
)->children
;
4423 node
= node
->next
) {
4424 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0) {
4429 /* no existing description but want to add */
4430 if (node
== NULL
&& content
!= NULL
) {
4431 /* add a description */
4432 node
= _sa_set_share_description(resource
, content
);
4433 } else if (node
!= NULL
&& content
!= NULL
) {
4434 /* update a description */
4435 xmlNodeSetContent(node
, (xmlChar
*)content
);
4436 } else if (node
!= NULL
&& content
== NULL
) {
4437 /* remove an existing description */
4438 xmlUnlinkNode(node
);
4442 share
= sa_get_resource_parent(resource
);
4443 group
= sa_get_parent_group(share
);
4444 if (group
!= NULL
&&
4445 sa_is_persistent(share
) && (!sa_group_is_zfs(group
))) {
4446 sa_handle_impl_t impl_handle
;
4447 impl_handle
= (sa_handle_impl_t
)sa_find_group_handle(group
);
4448 if (impl_handle
!= NULL
)
4449 ret
= sa_commit_share(impl_handle
->scfhandle
,
4452 ret
= SA_SYSTEM_ERR
;
4458 * sa_get_resource_description(share)
4460 * Return the description text for the specified share if it
4461 * exists. NULL if no description exists.
4465 sa_get_resource_description(sa_resource_t resource
)
4467 xmlChar
*description
= NULL
;
4470 for (node
= ((xmlNodePtr
)resource
)->children
; node
!= NULL
;
4471 node
= node
->next
) {
4472 if (xmlStrcmp(node
->name
, (xmlChar
*)"description") == 0)
4476 description
= xmlNodeGetContent(node
);
4477 fixproblemchars((char *)description
);
4479 return ((char *)description
);