16185db85Sdougm /* 26185db85Sdougm * CDDL HEADER START 36185db85Sdougm * 46185db85Sdougm * The contents of this file are subject to the terms of the 56185db85Sdougm * Common Development and Distribution License (the "License"). 66185db85Sdougm * You may not use this file except in compliance with the License. 76185db85Sdougm * 86185db85Sdougm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96185db85Sdougm * or http://www.opensolaris.org/os/licensing. 106185db85Sdougm * See the License for the specific language governing permissions 116185db85Sdougm * and limitations under the License. 126185db85Sdougm * 136185db85Sdougm * When distributing Covered Code, include this CDDL HEADER in each 146185db85Sdougm * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156185db85Sdougm * If applicable, add the following below this CDDL HEADER, with the 166185db85Sdougm * fields enclosed by brackets "[]" replaced with your own identifying 176185db85Sdougm * information: Portions Copyright [yyyy] [name of copyright owner] 186185db85Sdougm * 196185db85Sdougm * CDDL HEADER END 206185db85Sdougm */ 216185db85Sdougm 226185db85Sdougm /* 23*148c5f43SAlan Wright * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 246185db85Sdougm */ 256185db85Sdougm 266185db85Sdougm /* 276185db85Sdougm * Share control API 286185db85Sdougm */ 296185db85Sdougm #include <stdio.h> 306185db85Sdougm #include <string.h> 316185db85Sdougm #include <ctype.h> 326185db85Sdougm #include <sys/types.h> 336185db85Sdougm #include <sys/stat.h> 34a99982a7Sdougm #include <fcntl.h> 356185db85Sdougm #include <unistd.h> 366185db85Sdougm #include <libxml/parser.h> 376185db85Sdougm #include <libxml/tree.h> 386185db85Sdougm #include "libshare.h" 396185db85Sdougm #include "libshare_impl.h" 406185db85Sdougm #include <libscf.h> 416185db85Sdougm #include "scfutil.h" 426185db85Sdougm #include <ctype.h> 436185db85Sdougm #include <libintl.h> 44549ec3ffSdougm #include <thread.h> 45549ec3ffSdougm #include <synch.h> 466185db85Sdougm 47a99982a7Sdougm #define DFS_LOCK_FILE "/etc/dfs/fstypes" 4857b448deSdougm #define SA_STRSIZE 256 /* max string size for names */ 49a99982a7Sdougm 50da6c28aaSamw /* 51da6c28aaSamw * internal object type values returned by sa_get_object_type() 52da6c28aaSamw */ 53da6c28aaSamw #define SA_TYPE_UNKNOWN 0 54da6c28aaSamw #define SA_TYPE_GROUP 1 55da6c28aaSamw #define SA_TYPE_SHARE 2 56da6c28aaSamw #define SA_TYPE_RESOURCE 3 57da6c28aaSamw #define SA_TYPE_OPTIONSET 4 58da6c28aaSamw #define SA_TYPE_ALTSPACE 5 59da6c28aaSamw 606185db85Sdougm /* 616185db85Sdougm * internal data structures 626185db85Sdougm */ 636185db85Sdougm 646185db85Sdougm extern struct sa_proto_plugin *sap_proto_list; 656185db85Sdougm 666185db85Sdougm /* current SMF/SVC repository handle */ 67549ec3ffSdougm extern void getlegacyconfig(sa_handle_t, char *, xmlNodePtr *); 68549ec3ffSdougm extern int gettransients(sa_handle_impl_t, xmlNodePtr *); 696185db85Sdougm extern char *sa_fstype(char *); 706185db85Sdougm extern int sa_is_share(void *); 71da6c28aaSamw extern int sa_is_resource(void *); 726185db85Sdougm extern ssize_t scf_max_name_len; /* defined in scfutil during initialization */ 736185db85Sdougm extern int sa_group_is_zfs(sa_group_t); 746185db85Sdougm extern int sa_path_is_zfs(char *); 756185db85Sdougm extern int sa_zfs_set_sharenfs(sa_group_t, char *, int); 76da6c28aaSamw extern int sa_zfs_set_sharesmb(sa_group_t, char *, int); 77549ec3ffSdougm extern void update_legacy_config(sa_handle_t); 786185db85Sdougm extern int issubdir(char *, char *); 7957b448deSdougm extern int sa_zfs_init(sa_handle_impl_t); 80549ec3ffSdougm extern void sa_zfs_fini(sa_handle_impl_t); 81a99982a7Sdougm extern void sablocksigs(sigset_t *); 82a99982a7Sdougm extern void saunblocksigs(sigset_t *); 83da6c28aaSamw static sa_group_t sa_get_optionset_parent(sa_optionset_t); 84da6c28aaSamw static char *get_node_attr(void *, char *); 855b6e0c46Sdougm extern void sa_update_sharetab_ts(sa_handle_t); 866185db85Sdougm 87549ec3ffSdougm /* 88549ec3ffSdougm * Data structures for finding/managing the document root to access 89549ec3ffSdougm * handle mapping. The list isn't expected to grow very large so a 90549ec3ffSdougm * simple list is acceptable. The purpose is to provide a way to start 91549ec3ffSdougm * with a group or share and find the library handle needed for 92549ec3ffSdougm * various operations. 93549ec3ffSdougm */ 94549ec3ffSdougm mutex_t sa_global_lock; 95549ec3ffSdougm struct doc2handle { 96549ec3ffSdougm struct doc2handle *next; 97549ec3ffSdougm xmlNodePtr root; 98549ec3ffSdougm sa_handle_impl_t handle; 99549ec3ffSdougm }; 100549ec3ffSdougm 101*148c5f43SAlan Wright mutex_t sa_dfstab_lock; 102*148c5f43SAlan Wright 10357b448deSdougm /* definitions used in a couple of property functions */ 10457b448deSdougm #define SA_PROP_OP_REMOVE 1 10557b448deSdougm #define SA_PROP_OP_ADD 2 10657b448deSdougm #define SA_PROP_OP_UPDATE 3 10757b448deSdougm 108549ec3ffSdougm static struct doc2handle *sa_global_handles = NULL; 1096185db85Sdougm 1106185db85Sdougm /* helper functions */ 1116185db85Sdougm 112549ec3ffSdougm /* 113549ec3ffSdougm * sa_errorstr(err) 114549ec3ffSdougm * 115549ec3ffSdougm * convert an error value to an error string 116549ec3ffSdougm */ 117549ec3ffSdougm 1186185db85Sdougm char * 1196185db85Sdougm sa_errorstr(int err) 1206185db85Sdougm { 1216185db85Sdougm static char errstr[32]; 1226185db85Sdougm char *ret = NULL; 1236185db85Sdougm 1246185db85Sdougm switch (err) { 1256185db85Sdougm case SA_OK: 12657b448deSdougm ret = dgettext(TEXT_DOMAIN, "ok"); 12757b448deSdougm break; 1286185db85Sdougm case SA_NO_SUCH_PATH: 12957b448deSdougm ret = dgettext(TEXT_DOMAIN, "path doesn't exist"); 13057b448deSdougm break; 1316185db85Sdougm case SA_NO_MEMORY: 13257b448deSdougm ret = dgettext(TEXT_DOMAIN, "no memory"); 13357b448deSdougm break; 1346185db85Sdougm case SA_DUPLICATE_NAME: 13557b448deSdougm ret = dgettext(TEXT_DOMAIN, "name in use"); 13657b448deSdougm break; 1376185db85Sdougm case SA_BAD_PATH: 13857b448deSdougm ret = dgettext(TEXT_DOMAIN, "bad path"); 13957b448deSdougm break; 1406185db85Sdougm case SA_NO_SUCH_GROUP: 14157b448deSdougm ret = dgettext(TEXT_DOMAIN, "no such group"); 14257b448deSdougm break; 1436185db85Sdougm case SA_CONFIG_ERR: 14457b448deSdougm ret = dgettext(TEXT_DOMAIN, "configuration error"); 14557b448deSdougm break; 1466185db85Sdougm case SA_SYSTEM_ERR: 14757b448deSdougm ret = dgettext(TEXT_DOMAIN, "system error"); 14857b448deSdougm break; 1496185db85Sdougm case SA_SYNTAX_ERR: 15057b448deSdougm ret = dgettext(TEXT_DOMAIN, "syntax error"); 15157b448deSdougm break; 1526185db85Sdougm case SA_NO_PERMISSION: 15357b448deSdougm ret = dgettext(TEXT_DOMAIN, "no permission"); 15457b448deSdougm break; 1556185db85Sdougm case SA_BUSY: 15657b448deSdougm ret = dgettext(TEXT_DOMAIN, "busy"); 15757b448deSdougm break; 1586185db85Sdougm case SA_NO_SUCH_PROP: 15957b448deSdougm ret = dgettext(TEXT_DOMAIN, "no such property"); 16057b448deSdougm break; 1616185db85Sdougm case SA_INVALID_NAME: 16257b448deSdougm ret = dgettext(TEXT_DOMAIN, "invalid name"); 16357b448deSdougm break; 1646185db85Sdougm case SA_INVALID_PROTOCOL: 16557b448deSdougm ret = dgettext(TEXT_DOMAIN, "invalid protocol"); 16657b448deSdougm break; 1676185db85Sdougm case SA_NOT_ALLOWED: 16857b448deSdougm ret = dgettext(TEXT_DOMAIN, "operation not allowed"); 16957b448deSdougm break; 1706185db85Sdougm case SA_BAD_VALUE: 17157b448deSdougm ret = dgettext(TEXT_DOMAIN, "bad property value"); 17257b448deSdougm break; 1736185db85Sdougm case SA_INVALID_SECURITY: 17457b448deSdougm ret = dgettext(TEXT_DOMAIN, "invalid security type"); 17557b448deSdougm break; 1766185db85Sdougm case SA_NO_SUCH_SECURITY: 17757b448deSdougm ret = dgettext(TEXT_DOMAIN, "security type not found"); 17857b448deSdougm break; 1796185db85Sdougm case SA_VALUE_CONFLICT: 18057b448deSdougm ret = dgettext(TEXT_DOMAIN, "property value conflict"); 18157b448deSdougm break; 1826185db85Sdougm case SA_NOT_IMPLEMENTED: 18357b448deSdougm ret = dgettext(TEXT_DOMAIN, "not implemented"); 18457b448deSdougm break; 1856185db85Sdougm case SA_INVALID_PATH: 18657b448deSdougm ret = dgettext(TEXT_DOMAIN, "invalid path"); 18757b448deSdougm break; 1886185db85Sdougm case SA_NOT_SUPPORTED: 18957b448deSdougm ret = dgettext(TEXT_DOMAIN, "operation not supported"); 19057b448deSdougm break; 1916185db85Sdougm case SA_PROP_SHARE_ONLY: 19257b448deSdougm ret = dgettext(TEXT_DOMAIN, "property not valid for group"); 19357b448deSdougm break; 1946185db85Sdougm case SA_NOT_SHARED: 19557b448deSdougm ret = dgettext(TEXT_DOMAIN, "not shared"); 19657b448deSdougm break; 197da6c28aaSamw case SA_NO_SUCH_RESOURCE: 198da6c28aaSamw ret = dgettext(TEXT_DOMAIN, "no such resource"); 199da6c28aaSamw break; 200da6c28aaSamw case SA_RESOURCE_REQUIRED: 201da6c28aaSamw ret = dgettext(TEXT_DOMAIN, "resource name required"); 202da6c28aaSamw break; 203da6c28aaSamw case SA_MULTIPLE_ERROR: 204da6c28aaSamw ret = dgettext(TEXT_DOMAIN, "errors from multiple protocols"); 205da6c28aaSamw break; 206da6c28aaSamw case SA_PATH_IS_SUBDIR: 207da6c28aaSamw ret = dgettext(TEXT_DOMAIN, "path is a subpath of share"); 208da6c28aaSamw break; 209da6c28aaSamw case SA_PATH_IS_PARENTDIR: 210da6c28aaSamw ret = dgettext(TEXT_DOMAIN, "path is parent of a share"); 211da6c28aaSamw break; 2124bff34e3Sthurlow case SA_NO_SECTION: 2134bff34e3Sthurlow ret = dgettext(TEXT_DOMAIN, "protocol requires a section"); 2144bff34e3Sthurlow break; 2154bff34e3Sthurlow case SA_NO_PROPERTIES: 2164bff34e3Sthurlow ret = dgettext(TEXT_DOMAIN, "properties not found"); 2174bff34e3Sthurlow break; 2184bff34e3Sthurlow case SA_NO_SUCH_SECTION: 2194bff34e3Sthurlow ret = dgettext(TEXT_DOMAIN, "section not found"); 2204bff34e3Sthurlow break; 2214bff34e3Sthurlow case SA_PASSWORD_ENC: 2224bff34e3Sthurlow ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted"); 2234bff34e3Sthurlow break; 2246185db85Sdougm default: 22557b448deSdougm (void) snprintf(errstr, sizeof (errstr), 22657b448deSdougm dgettext(TEXT_DOMAIN, "unknown %d"), err); 22757b448deSdougm ret = errstr; 2286185db85Sdougm } 2296185db85Sdougm return (ret); 2306185db85Sdougm } 2316185db85Sdougm 232549ec3ffSdougm /* 233549ec3ffSdougm * Document root to active handle mapping functions. These are only 234549ec3ffSdougm * used internally. A mutex is used to prevent access while the list 235549ec3ffSdougm * is changing. In general, the list will be relatively short - one 236549ec3ffSdougm * item per thread that has called sa_init(). 237549ec3ffSdougm */ 238549ec3ffSdougm 239549ec3ffSdougm sa_handle_impl_t 240549ec3ffSdougm get_handle_for_root(xmlNodePtr root) 241549ec3ffSdougm { 242549ec3ffSdougm struct doc2handle *item; 243549ec3ffSdougm 244549ec3ffSdougm (void) mutex_lock(&sa_global_lock); 245549ec3ffSdougm for (item = sa_global_handles; item != NULL; item = item->next) { 24657b448deSdougm if (item->root == root) 24757b448deSdougm break; 248549ec3ffSdougm } 249549ec3ffSdougm (void) mutex_unlock(&sa_global_lock); 250549ec3ffSdougm if (item != NULL) 25157b448deSdougm return (item->handle); 252549ec3ffSdougm return (NULL); 253549ec3ffSdougm } 254549ec3ffSdougm 255549ec3ffSdougm static int 256549ec3ffSdougm add_handle_for_root(xmlNodePtr root, sa_handle_impl_t handle) 257549ec3ffSdougm { 258549ec3ffSdougm struct doc2handle *item; 259549ec3ffSdougm int ret = SA_NO_MEMORY; 260549ec3ffSdougm 261549ec3ffSdougm item = (struct doc2handle *)calloc(sizeof (struct doc2handle), 1); 262549ec3ffSdougm if (item != NULL) { 26357b448deSdougm item->root = root; 26457b448deSdougm item->handle = handle; 26557b448deSdougm (void) mutex_lock(&sa_global_lock); 26657b448deSdougm item->next = sa_global_handles; 26757b448deSdougm sa_global_handles = item; 26857b448deSdougm (void) mutex_unlock(&sa_global_lock); 26957b448deSdougm ret = SA_OK; 270549ec3ffSdougm } 271549ec3ffSdougm return (ret); 272549ec3ffSdougm } 273549ec3ffSdougm 274549ec3ffSdougm /* 275549ec3ffSdougm * remove_handle_for_root(root) 276549ec3ffSdougm * 277549ec3ffSdougm * Walks the list of handles and removes the one for this "root" from 278549ec3ffSdougm * the list. It is up to the caller to free the data. 279549ec3ffSdougm */ 280549ec3ffSdougm 281549ec3ffSdougm static void 282549ec3ffSdougm remove_handle_for_root(xmlNodePtr root) 283549ec3ffSdougm { 284549ec3ffSdougm struct doc2handle *item, *prev; 285549ec3ffSdougm 286549ec3ffSdougm (void) mutex_lock(&sa_global_lock); 287549ec3ffSdougm for (prev = NULL, item = sa_global_handles; item != NULL; 28857b448deSdougm item = item->next) { 28957b448deSdougm if (item->root == root) { 29057b448deSdougm /* first in the list */ 29157b448deSdougm if (prev == NULL) 29257b448deSdougm sa_global_handles = sa_global_handles->next; 29357b448deSdougm else 29457b448deSdougm prev->next = item->next; 29557b448deSdougm /* Item is out of the list so free the list structure */ 29657b448deSdougm free(item); 29757b448deSdougm break; 298549ec3ffSdougm } 29957b448deSdougm prev = item; 300549ec3ffSdougm } 301549ec3ffSdougm (void) mutex_unlock(&sa_global_lock); 302549ec3ffSdougm } 303549ec3ffSdougm 304549ec3ffSdougm /* 305549ec3ffSdougm * sa_find_group_handle(sa_group_t group) 306549ec3ffSdougm * 307549ec3ffSdougm * Find the sa_handle_t for the configuration associated with this 308549ec3ffSdougm * group. 309549ec3ffSdougm */ 310549ec3ffSdougm sa_handle_t 311549ec3ffSdougm sa_find_group_handle(sa_group_t group) 312549ec3ffSdougm { 313549ec3ffSdougm xmlNodePtr node = (xmlNodePtr)group; 314549ec3ffSdougm sa_handle_t handle; 315549ec3ffSdougm 316549ec3ffSdougm while (node != NULL) { 31757b448deSdougm if (strcmp((char *)(node->name), "sharecfg") == 0) { 31857b448deSdougm /* have the root so get the handle */ 31957b448deSdougm handle = (sa_handle_t)get_handle_for_root(node); 32057b448deSdougm return (handle); 32157b448deSdougm } 32257b448deSdougm node = node->parent; 323549ec3ffSdougm } 324549ec3ffSdougm return (NULL); 325549ec3ffSdougm } 326549ec3ffSdougm 3276185db85Sdougm /* 3286185db85Sdougm * set_legacy_timestamp(root, path, timevalue) 3296185db85Sdougm * 3306185db85Sdougm * add the current timestamp value to the configuration for use in 3316185db85Sdougm * determining when to update the legacy files. For SMF, this 3326185db85Sdougm * property is kept in default/operation/legacy_timestamp 3336185db85Sdougm */ 3346185db85Sdougm 3356185db85Sdougm static void 3366185db85Sdougm set_legacy_timestamp(xmlNodePtr root, char *path, uint64_t tval) 3376185db85Sdougm { 3386185db85Sdougm xmlNodePtr node; 3396185db85Sdougm xmlChar *lpath = NULL; 340549ec3ffSdougm sa_handle_impl_t handle; 341549ec3ffSdougm 342549ec3ffSdougm /* Have to have a handle or else we weren't initialized. */ 343549ec3ffSdougm handle = get_handle_for_root(root); 344549ec3ffSdougm if (handle == NULL) 34557b448deSdougm return; 3466185db85Sdougm 3476185db85Sdougm for (node = root->xmlChildrenNode; node != NULL; 34857b448deSdougm node = node->next) { 34957b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"legacy") == 0) { 35057b448deSdougm /* a possible legacy node for this path */ 35157b448deSdougm lpath = xmlGetProp(node, (xmlChar *)"path"); 35257b448deSdougm if (lpath != NULL && 35357b448deSdougm xmlStrcmp(lpath, (xmlChar *)path) == 0) { 35457b448deSdougm xmlFree(lpath); 35557b448deSdougm break; 35657b448deSdougm } 35757b448deSdougm if (lpath != NULL) 35857b448deSdougm xmlFree(lpath); 3596185db85Sdougm } 3606185db85Sdougm } 3616185db85Sdougm if (node == NULL) { 36257b448deSdougm /* need to create the first legacy timestamp node */ 36357b448deSdougm node = xmlNewChild(root, NULL, (xmlChar *)"legacy", NULL); 3646185db85Sdougm } 3656185db85Sdougm if (node != NULL) { 36657b448deSdougm char tstring[32]; 36757b448deSdougm int ret; 36857b448deSdougm 36957b448deSdougm (void) snprintf(tstring, sizeof (tstring), "%lld", tval); 3704bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"timestamp", 3714bff34e3Sthurlow (xmlChar *)tstring); 3724bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path); 37357b448deSdougm /* now commit to SMF */ 37457b448deSdougm ret = sa_get_instance(handle->scfhandle, "default"); 3756185db85Sdougm if (ret == SA_OK) { 37657b448deSdougm ret = sa_start_transaction(handle->scfhandle, 37757b448deSdougm "operation"); 37857b448deSdougm if (ret == SA_OK) { 37957b448deSdougm ret = sa_set_property(handle->scfhandle, 38057b448deSdougm "legacy-timestamp", tstring); 38157b448deSdougm if (ret == SA_OK) { 38257b448deSdougm (void) sa_end_transaction( 3835b6e0c46Sdougm handle->scfhandle, handle); 38457b448deSdougm } else { 38557b448deSdougm sa_abort_transaction(handle->scfhandle); 38657b448deSdougm } 38757b448deSdougm } 3886185db85Sdougm } 3896185db85Sdougm } 3906185db85Sdougm } 3916185db85Sdougm 3926185db85Sdougm /* 3936185db85Sdougm * is_shared(share) 3946185db85Sdougm * 3956185db85Sdougm * determine if the specified share is currently shared or not. 3966185db85Sdougm */ 3976185db85Sdougm static int 3986185db85Sdougm is_shared(sa_share_t share) 3996185db85Sdougm { 4006185db85Sdougm char *shared; 4016185db85Sdougm int result = 0; /* assume not */ 4026185db85Sdougm 4036185db85Sdougm shared = sa_get_share_attr(share, "shared"); 4046185db85Sdougm if (shared != NULL) { 40557b448deSdougm if (strcmp(shared, "true") == 0) 40657b448deSdougm result = 1; 40757b448deSdougm sa_free_attr_string(shared); 4086185db85Sdougm } 4096185db85Sdougm return (result); 4106185db85Sdougm } 4116185db85Sdougm 412da6c28aaSamw /* 413da6c28aaSamw * excluded_protocol(share, proto) 414da6c28aaSamw * 415da6c28aaSamw * Returns B_TRUE if the specified protocol appears in the "exclude" 416da6c28aaSamw * property. This is used to prevent sharing special case shares 417da6c28aaSamw * (e.g. subdirs when SMB wants a subdir and NFS doesn't. B_FALSE is 418da6c28aaSamw * returned if the protocol isn't in the list. 419da6c28aaSamw */ 420da6c28aaSamw static boolean_t 421da6c28aaSamw excluded_protocol(sa_share_t share, char *proto) 422da6c28aaSamw { 423da6c28aaSamw char *protolist; 424da6c28aaSamw char *str; 425da6c28aaSamw char *token; 426da6c28aaSamw 427da6c28aaSamw protolist = sa_get_share_attr(share, "exclude"); 428da6c28aaSamw if (protolist != NULL) { 429da6c28aaSamw str = protolist; 430da6c28aaSamw while ((token = strtok(str, ",")) != NULL) { 431da6c28aaSamw if (strcmp(token, proto) == 0) { 432da6c28aaSamw sa_free_attr_string(protolist); 433da6c28aaSamw return (B_TRUE); 434da6c28aaSamw } 435da6c28aaSamw str = NULL; 436da6c28aaSamw } 437da6c28aaSamw sa_free_attr_string(protolist); 438da6c28aaSamw } 439da6c28aaSamw return (B_FALSE); 440da6c28aaSamw } 441da6c28aaSamw 4426185db85Sdougm /* 443a99982a7Sdougm * checksubdirgroup(group, newpath, strictness) 444f345c0beSdougm * 445a99982a7Sdougm * check all the specified newpath against all the paths in the 446a99982a7Sdougm * group. This is a helper function for checksubdir to make it easier 447a99982a7Sdougm * to also check ZFS subgroups. 448a99982a7Sdougm * The strictness values mean: 449f345c0beSdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 450f345c0beSdougm * SA_CHECK_STRICT == check newpath against both active shares and those 451f345c0beSdougm * stored in the repository 4526185db85Sdougm */ 4536185db85Sdougm static int 454a99982a7Sdougm checksubdirgroup(sa_group_t group, char *newpath, int strictness) 4556185db85Sdougm { 4566185db85Sdougm sa_share_t share; 457a99982a7Sdougm char *path; 458a99982a7Sdougm int issub = SA_OK; 459da6c28aaSamw int subdir; 460da6c28aaSamw int parent; 461da6c28aaSamw 462da6c28aaSamw if (newpath == NULL) 463da6c28aaSamw return (SA_INVALID_PATH); 4646185db85Sdougm 465a99982a7Sdougm for (share = sa_get_share(group, NULL); share != NULL; 466a99982a7Sdougm share = sa_get_next_share(share)) { 4676185db85Sdougm /* 4686185db85Sdougm * The original behavior of share never checked 4696185db85Sdougm * against the permanent configuration 4706185db85Sdougm * (/etc/dfs/dfstab). PIT has a number of cases where 4716185db85Sdougm * it depends on this older behavior even though it 4726185db85Sdougm * could be considered incorrect. We may tighten this 4736185db85Sdougm * up in the future. 4746185db85Sdougm */ 47557b448deSdougm if (strictness == SA_CHECK_NORMAL && !is_shared(share)) 47657b448deSdougm continue; 4776185db85Sdougm 47857b448deSdougm path = sa_get_share_attr(share, "path"); 479f345c0beSdougm /* 480f345c0beSdougm * If path is NULL, then a share is in the process of 481f345c0beSdougm * construction or someone has modified the property 482a99982a7Sdougm * group inappropriately. It should be 483a99982a7Sdougm * ignored. issubdir() comes from the original share 484a99982a7Sdougm * implementation and does the difficult part of 485a99982a7Sdougm * checking subdirectories. 486f345c0beSdougm */ 48757b448deSdougm if (path == NULL) 48857b448deSdougm continue; 489da6c28aaSamw 490da6c28aaSamw if (strcmp(path, newpath) == 0) { 49157b448deSdougm issub = SA_INVALID_PATH; 492da6c28aaSamw } else { 493da6c28aaSamw subdir = issubdir(newpath, path); 494da6c28aaSamw parent = issubdir(path, newpath); 495da6c28aaSamw if (subdir || parent) { 496da6c28aaSamw sa_free_attr_string(path); 497da6c28aaSamw path = NULL; 498da6c28aaSamw return (subdir ? 499da6c28aaSamw SA_PATH_IS_SUBDIR : SA_PATH_IS_PARENTDIR); 500da6c28aaSamw } 50157b448deSdougm } 5026185db85Sdougm sa_free_attr_string(path); 5036185db85Sdougm path = NULL; 504a99982a7Sdougm } 505a99982a7Sdougm return (issub); 506a99982a7Sdougm } 507a99982a7Sdougm 508a99982a7Sdougm /* 509a99982a7Sdougm * checksubdir(newpath, strictness) 510a99982a7Sdougm * 511a99982a7Sdougm * checksubdir determines if the specified path (newpath) is a 512a99982a7Sdougm * subdirectory of another share. It calls checksubdirgroup() to do 513a99982a7Sdougm * the complicated work. The strictness parameter determines how 514a99982a7Sdougm * strict a check to make against the path. The strictness values 515a99982a7Sdougm * mean: SA_CHECK_NORMAL == only check newpath against shares that are 516a99982a7Sdougm * active SA_CHECK_STRICT == check newpath against both active shares 517a99982a7Sdougm * and those * stored in the repository 518a99982a7Sdougm */ 519a99982a7Sdougm static int 520549ec3ffSdougm checksubdir(sa_handle_t handle, char *newpath, int strictness) 521a99982a7Sdougm { 522a99982a7Sdougm sa_group_t group; 523da6c28aaSamw int issub = SA_OK; 524a99982a7Sdougm char *path = NULL; 525a99982a7Sdougm 526da6c28aaSamw for (group = sa_get_group(handle, NULL); 527da6c28aaSamw group != NULL && issub == SA_OK; 528da6c28aaSamw group = sa_get_next_group(group)) { 52957b448deSdougm if (sa_group_is_zfs(group)) { 53057b448deSdougm sa_group_t subgroup; 53157b448deSdougm for (subgroup = sa_get_sub_group(group); 532da6c28aaSamw subgroup != NULL && issub == SA_OK; 53357b448deSdougm subgroup = sa_get_next_group(subgroup)) 53457b448deSdougm issub = checksubdirgroup(subgroup, newpath, 53557b448deSdougm strictness); 53657b448deSdougm } else { 53757b448deSdougm issub = checksubdirgroup(group, newpath, strictness); 53857b448deSdougm } 5396185db85Sdougm } 5406185db85Sdougm if (path != NULL) 54157b448deSdougm sa_free_attr_string(path); 5426185db85Sdougm return (issub); 5436185db85Sdougm } 5446185db85Sdougm 5456185db85Sdougm /* 546f345c0beSdougm * validpath(path, strictness) 5476185db85Sdougm * determine if the provided path is valid for a share. It shouldn't 5486185db85Sdougm * be a sub-dir of an already shared path or the parent directory of a 5496185db85Sdougm * share path. 5506185db85Sdougm */ 5516185db85Sdougm static int 552549ec3ffSdougm validpath(sa_handle_t handle, char *path, int strictness) 5536185db85Sdougm { 5546185db85Sdougm int error = SA_OK; 5556185db85Sdougm struct stat st; 5566185db85Sdougm sa_share_t share; 5576185db85Sdougm char *fstype; 5586185db85Sdougm 55957b448deSdougm if (*path != '/') 56057b448deSdougm return (SA_BAD_PATH); 56157b448deSdougm 5626185db85Sdougm if (stat(path, &st) < 0) { 56357b448deSdougm error = SA_NO_SUCH_PATH; 5646185db85Sdougm } else { 56557b448deSdougm share = sa_find_share(handle, path); 56657b448deSdougm if (share != NULL) 56757b448deSdougm error = SA_DUPLICATE_NAME; 56857b448deSdougm 56957b448deSdougm if (error == SA_OK) { 57057b448deSdougm /* 57157b448deSdougm * check for special case with file system 57257b448deSdougm * that might have restrictions. For now, ZFS 57357b448deSdougm * is the only case since it has its own idea 57457b448deSdougm * of how to configure shares. We do this 57557b448deSdougm * before subdir checking since things like 57657b448deSdougm * ZFS will do that for us. This should also 57757b448deSdougm * be done via plugin interface. 57857b448deSdougm */ 57957b448deSdougm fstype = sa_fstype(path); 58057b448deSdougm if (fstype != NULL && strcmp(fstype, "zfs") == 0) { 58157b448deSdougm if (sa_zfs_is_shared(handle, path)) 58257b448deSdougm error = SA_INVALID_NAME; 58357b448deSdougm } 58457b448deSdougm if (fstype != NULL) 58557b448deSdougm sa_free_fstype(fstype); 5866185db85Sdougm } 58757b448deSdougm if (error == SA_OK) 58857b448deSdougm error = checksubdir(handle, path, strictness); 5896185db85Sdougm } 5906185db85Sdougm return (error); 5916185db85Sdougm } 5926185db85Sdougm 5936185db85Sdougm /* 5946185db85Sdougm * check to see if group/share is persistent. 595da6c28aaSamw * 596da6c28aaSamw * "group" can be either an sa_group_t or an sa_share_t. (void *) 597da6c28aaSamw * works since both thse types are also void *. 598*148c5f43SAlan Wright * If the share is a ZFS share, mark it as persistent. 5996185db85Sdougm */ 600da6c28aaSamw int 601da6c28aaSamw sa_is_persistent(void *group) 6026185db85Sdougm { 6036185db85Sdougm char *type; 6046185db85Sdougm int persist = 1; 605*148c5f43SAlan Wright sa_group_t grp; 6066185db85Sdougm 607da6c28aaSamw type = sa_get_group_attr((sa_group_t)group, "type"); 608*148c5f43SAlan Wright if (type != NULL) { 609*148c5f43SAlan Wright if (strcmp(type, "transient") == 0) 610*148c5f43SAlan Wright persist = 0; 61157b448deSdougm sa_free_attr_string(type); 612*148c5f43SAlan Wright } 613*148c5f43SAlan Wright 614*148c5f43SAlan Wright grp = (sa_is_share(group)) ? sa_get_parent_group(group) : group; 615*148c5f43SAlan Wright if (sa_group_is_zfs(grp)) 616*148c5f43SAlan Wright persist = 1; 617*148c5f43SAlan Wright 6186185db85Sdougm return (persist); 6196185db85Sdougm } 6206185db85Sdougm 6216185db85Sdougm /* 6226185db85Sdougm * sa_valid_group_name(name) 6236185db85Sdougm * 6246185db85Sdougm * check that the "name" contains only valid characters and otherwise 6256185db85Sdougm * fits the required naming conventions. Valid names must start with 6266185db85Sdougm * an alphabetic and the remainder may consist of only alphanumeric 6276185db85Sdougm * plus the '-' and '_' characters. This name limitation comes from 6286185db85Sdougm * inherent limitations in SMF. 6296185db85Sdougm */ 6306185db85Sdougm 6316185db85Sdougm int 6326185db85Sdougm sa_valid_group_name(char *name) 6336185db85Sdougm { 6346185db85Sdougm int ret = 1; 6356185db85Sdougm ssize_t len; 6366185db85Sdougm 6376185db85Sdougm if (name != NULL && isalpha(*name)) { 63857b448deSdougm char c; 63957b448deSdougm len = strlen(name); 64057b448deSdougm if (len < (scf_max_name_len - sizeof ("group:"))) { 64157b448deSdougm for (c = *name++; c != '\0' && ret != 0; c = *name++) { 64257b448deSdougm if (!isalnum(c) && c != '-' && c != '_') 64357b448deSdougm ret = 0; 64457b448deSdougm } 64557b448deSdougm } else { 6466185db85Sdougm ret = 0; 6476185db85Sdougm } 6486185db85Sdougm } else { 64957b448deSdougm ret = 0; 6506185db85Sdougm } 6516185db85Sdougm return (ret); 6526185db85Sdougm } 6536185db85Sdougm 6546185db85Sdougm 6556185db85Sdougm /* 6566185db85Sdougm * is_zfs_group(group) 6576185db85Sdougm * Determine if the specified group is a ZFS sharenfs group 6586185db85Sdougm */ 6596185db85Sdougm static int 6606185db85Sdougm is_zfs_group(sa_group_t group) 6616185db85Sdougm { 6626185db85Sdougm int ret = 0; 6636185db85Sdougm xmlNodePtr parent; 6646185db85Sdougm xmlChar *zfs; 6656185db85Sdougm 66657b448deSdougm if (strcmp((char *)((xmlNodePtr)group)->name, "share") == 0) 66757b448deSdougm parent = (xmlNodePtr)sa_get_parent_group(group); 66857b448deSdougm else 66957b448deSdougm parent = (xmlNodePtr)group; 6706185db85Sdougm zfs = xmlGetProp(parent, (xmlChar *)"zfs"); 6716185db85Sdougm if (zfs != NULL) { 67257b448deSdougm xmlFree(zfs); 67357b448deSdougm ret = 1; 6746185db85Sdougm } 6756185db85Sdougm return (ret); 6766185db85Sdougm } 6776185db85Sdougm 678da6c28aaSamw /* 679da6c28aaSamw * sa_get_object_type(object) 680da6c28aaSamw * 681da6c28aaSamw * This function returns a numeric value representing the object 682da6c28aaSamw * type. This allows using simpler checks when doing type specific 683da6c28aaSamw * operations. 684da6c28aaSamw */ 685da6c28aaSamw 686da6c28aaSamw static int 687da6c28aaSamw sa_get_object_type(void *object) 688da6c28aaSamw { 689da6c28aaSamw xmlNodePtr node = (xmlNodePtr)object; 690da6c28aaSamw int type; 691da6c28aaSamw 692da6c28aaSamw if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) 693da6c28aaSamw type = SA_TYPE_GROUP; 694da6c28aaSamw else if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) 695da6c28aaSamw type = SA_TYPE_SHARE; 696da6c28aaSamw else if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 697da6c28aaSamw type = SA_TYPE_RESOURCE; 698da6c28aaSamw else if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) 699da6c28aaSamw type = SA_TYPE_OPTIONSET; 700da6c28aaSamw else if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) 701da6c28aaSamw type = SA_TYPE_ALTSPACE; 702da6c28aaSamw else 703da6c28aaSamw assert(0); 704da6c28aaSamw return (type); 705da6c28aaSamw } 706da6c28aaSamw 7076185db85Sdougm /* 7086185db85Sdougm * sa_optionset_name(optionset, oname, len, id) 7096185db85Sdougm * return the SMF name for the optionset. If id is not NULL, it 7106185db85Sdougm * will have the GUID value for a share and should be used 7116185db85Sdougm * instead of the keyword "optionset" which is used for 7126185db85Sdougm * groups. If the optionset doesn't have a protocol type 7136185db85Sdougm * associated with it, "default" is used. This shouldn't happen 7146185db85Sdougm * at this point but may be desirable in the future if there are 7156185db85Sdougm * protocol independent properties added. The name is returned in 7166185db85Sdougm * oname. 7176185db85Sdougm */ 7186185db85Sdougm 7196185db85Sdougm static int 7206185db85Sdougm sa_optionset_name(sa_optionset_t optionset, char *oname, size_t len, char *id) 7216185db85Sdougm { 7226185db85Sdougm char *proto; 723da6c28aaSamw void *parent; 724da6c28aaSamw int ptype; 7256185db85Sdougm 7266185db85Sdougm if (id == NULL) 72757b448deSdougm id = "optionset"; 7286185db85Sdougm 729da6c28aaSamw parent = sa_get_optionset_parent(optionset); 730da6c28aaSamw if (parent != NULL) { 731da6c28aaSamw ptype = sa_get_object_type(parent); 732da6c28aaSamw proto = sa_get_optionset_attr(optionset, "type"); 733da6c28aaSamw if (ptype != SA_TYPE_RESOURCE) { 734da6c28aaSamw len = snprintf(oname, len, "%s_%s", id, 735da6c28aaSamw proto ? proto : "default"); 736da6c28aaSamw } else { 737da6c28aaSamw char *index; 738da6c28aaSamw index = get_node_attr((void *)parent, "id"); 739fe1c642dSBill Krier if (index != NULL) { 740da6c28aaSamw len = snprintf(oname, len, "%s_%s_%s", id, 741da6c28aaSamw proto ? proto : "default", index); 742fe1c642dSBill Krier sa_free_attr_string(index); 743fe1c642dSBill Krier } else { 744da6c28aaSamw len = 0; 745fe1c642dSBill Krier } 746da6c28aaSamw } 7476185db85Sdougm 748da6c28aaSamw if (proto != NULL) 749da6c28aaSamw sa_free_attr_string(proto); 750da6c28aaSamw } else { 751da6c28aaSamw len = 0; 752da6c28aaSamw } 7536185db85Sdougm return (len); 7546185db85Sdougm } 7556185db85Sdougm 7566185db85Sdougm /* 7576185db85Sdougm * sa_security_name(optionset, oname, len, id) 7586185db85Sdougm * 7596185db85Sdougm * return the SMF name for the security. If id is not NULL, it will 7606185db85Sdougm * have the GUID value for a share and should be used instead of the 7616185db85Sdougm * keyword "optionset" which is used for groups. If the optionset 7626185db85Sdougm * doesn't have a protocol type associated with it, "default" is 7636185db85Sdougm * used. This shouldn't happen at this point but may be desirable in 7646185db85Sdougm * the future if there are protocol independent properties added. The 7656185db85Sdougm * name is returned in oname. The security type is also encoded into 7666185db85Sdougm * the name. In the future, this wil *be handled a bit differently. 7676185db85Sdougm */ 7686185db85Sdougm 7696185db85Sdougm static int 7706185db85Sdougm sa_security_name(sa_security_t security, char *oname, size_t len, char *id) 7716185db85Sdougm { 7726185db85Sdougm char *proto; 7736185db85Sdougm char *sectype; 7746185db85Sdougm 7756185db85Sdougm if (id == NULL) 77657b448deSdougm id = "optionset"; 7776185db85Sdougm 7786185db85Sdougm proto = sa_get_security_attr(security, "type"); 7796185db85Sdougm sectype = sa_get_security_attr(security, "sectype"); 78057b448deSdougm len = snprintf(oname, len, "%s_%s_%s", id, proto ? proto : "default", 78157b448deSdougm sectype ? sectype : "default"); 7826185db85Sdougm if (proto != NULL) 78357b448deSdougm sa_free_attr_string(proto); 7846185db85Sdougm if (sectype != NULL) 78557b448deSdougm sa_free_attr_string(sectype); 7866185db85Sdougm return (len); 7876185db85Sdougm } 7886185db85Sdougm 78957b448deSdougm /* 79057b448deSdougm * verifydefgroupopts(handle) 79157b448deSdougm * 79257b448deSdougm * Make sure a "default" group exists and has default protocols enabled. 79357b448deSdougm */ 79457b448deSdougm static void 79557b448deSdougm verifydefgroupopts(sa_handle_t handle) 79657b448deSdougm { 79757b448deSdougm sa_group_t defgrp; 79857b448deSdougm sa_optionset_t opt; 799da6c28aaSamw 80057b448deSdougm defgrp = sa_get_group(handle, "default"); 80157b448deSdougm if (defgrp != NULL) { 80257b448deSdougm opt = sa_get_optionset(defgrp, NULL); 80357b448deSdougm /* 80457b448deSdougm * NFS is the default for default group 80557b448deSdougm */ 80657b448deSdougm if (opt == NULL) 80757b448deSdougm opt = sa_create_optionset(defgrp, "nfs"); 80857b448deSdougm } 80957b448deSdougm } 81057b448deSdougm 8116185db85Sdougm /* 812f345c0beSdougm * sa_init(init_service) 8136185db85Sdougm * Initialize the API 8146185db85Sdougm * find all the shared objects 8156185db85Sdougm * init the tables with all objects 8166185db85Sdougm * read in the current configuration 8176185db85Sdougm */ 8186185db85Sdougm 81957b448deSdougm #define GETPROP(prop) scf_simple_prop_next_astring(prop) 82057b448deSdougm #define CHECKTSTAMP(st, tval) stat(SA_LEGACY_DFSTAB, &st) >= 0 && \ 82157b448deSdougm tval != TSTAMP(st.st_ctim) 82257b448deSdougm 823549ec3ffSdougm sa_handle_t 8246185db85Sdougm sa_init(int init_service) 8256185db85Sdougm { 8266185db85Sdougm struct stat st; 8276185db85Sdougm int legacy = 0; 8286185db85Sdougm uint64_t tval = 0; 829a99982a7Sdougm int lockfd; 830a99982a7Sdougm sigset_t old; 831a99982a7Sdougm int updatelegacy = B_FALSE; 832a99982a7Sdougm scf_simple_prop_t *prop; 833549ec3ffSdougm sa_handle_impl_t handle; 834549ec3ffSdougm int err; 835549ec3ffSdougm 836549ec3ffSdougm handle = calloc(sizeof (struct sa_handle_impl), 1); 8376185db85Sdougm 838549ec3ffSdougm if (handle != NULL) { 839c5f58477Sdougm /* 840c5f58477Sdougm * Get protocol specific structures, but only if this 841c5f58477Sdougm * is the only handle. 842c5f58477Sdougm */ 843c5f58477Sdougm (void) mutex_lock(&sa_global_lock); 844c5f58477Sdougm if (sa_global_handles == NULL) 845c5f58477Sdougm (void) proto_plugin_init(); 846c5f58477Sdougm (void) mutex_unlock(&sa_global_lock); 84757b448deSdougm if (init_service & SA_INIT_SHARE_API) { 848a99982a7Sdougm /* 84957b448deSdougm * initialize access into libzfs. We use this 85057b448deSdougm * when collecting info about ZFS datasets and 85157b448deSdougm * shares. 852a99982a7Sdougm */ 85357b448deSdougm if (sa_zfs_init(handle) == B_FALSE) { 85457b448deSdougm free(handle); 85589dc44ceSjose borrego (void) mutex_lock(&sa_global_lock); 85657b448deSdougm (void) proto_plugin_fini(); 85789dc44ceSjose borrego (void) mutex_unlock(&sa_global_lock); 85857b448deSdougm return (NULL); 85957b448deSdougm } 860a99982a7Sdougm /* 86157b448deSdougm * since we want to use SMF, initialize an svc handle 86257b448deSdougm * and find out what is there. 863a99982a7Sdougm */ 86457b448deSdougm handle->scfhandle = sa_scf_init(handle); 86557b448deSdougm if (handle->scfhandle != NULL) { 86657b448deSdougm /* 86757b448deSdougm * Need to lock the extraction of the 86857b448deSdougm * configuration if the dfstab file has 86957b448deSdougm * changed. Lock everything now and release if 87057b448deSdougm * not needed. Use a file that isn't being 87157b448deSdougm * manipulated by other parts of the system in 87257b448deSdougm * order to not interfere with locking. Using 87357b448deSdougm * dfstab doesn't work. 87457b448deSdougm */ 87557b448deSdougm sablocksigs(&old); 87657b448deSdougm lockfd = open(DFS_LOCK_FILE, O_RDWR); 87757b448deSdougm if (lockfd >= 0) { 87857b448deSdougm extern int errno; 87957b448deSdougm errno = 0; 88057b448deSdougm (void) lockf(lockfd, F_LOCK, 0); 881*148c5f43SAlan Wright (void) mutex_lock(&sa_dfstab_lock); 88257b448deSdougm /* 88357b448deSdougm * Check whether we are going to need 88457b448deSdougm * to merge any dfstab changes. This 88557b448deSdougm * is done by comparing the value of 88657b448deSdougm * legacy-timestamp with the current 88757b448deSdougm * st_ctim of the file. If they are 88857b448deSdougm * different, an update is needed and 88957b448deSdougm * the file must remain locked until 89057b448deSdougm * the merge is done in order to 89157b448deSdougm * prevent multiple startups from 89257b448deSdougm * changing the SMF repository at the 89357b448deSdougm * same time. The first to get the 89457b448deSdougm * lock will make any changes before 89557b448deSdougm * the others can read the repository. 89657b448deSdougm */ 89757b448deSdougm prop = scf_simple_prop_get 89857b448deSdougm (handle->scfhandle->handle, 89957b448deSdougm (const char *)SA_SVC_FMRI_BASE 90057b448deSdougm ":default", "operation", 90157b448deSdougm "legacy-timestamp"); 90257b448deSdougm if (prop != NULL) { 90357b448deSdougm char *i64; 90457b448deSdougm i64 = GETPROP(prop); 90557b448deSdougm if (i64 != NULL) 90657b448deSdougm tval = strtoull(i64, 90757b448deSdougm NULL, 0); 90857b448deSdougm if (CHECKTSTAMP(st, tval)) 90957b448deSdougm updatelegacy = B_TRUE; 91057b448deSdougm scf_simple_prop_free(prop); 91157b448deSdougm } else { 91257b448deSdougm /* 91357b448deSdougm * We haven't set the 91457b448deSdougm * timestamp before so do it. 91557b448deSdougm */ 91657b448deSdougm updatelegacy = B_TRUE; 91757b448deSdougm } 918*148c5f43SAlan Wright if (updatelegacy == B_FALSE) { 919*148c5f43SAlan Wright (void) mutex_unlock( 920*148c5f43SAlan Wright &sa_dfstab_lock); 921*148c5f43SAlan Wright (void) lockf(lockfd, F_ULOCK, 922*148c5f43SAlan Wright 0); 923*148c5f43SAlan Wright (void) close(lockfd); 924*148c5f43SAlan Wright } 9251d1813a7Sdougm 926*148c5f43SAlan Wright } 92757b448deSdougm /* 92857b448deSdougm * It is essential that the document tree and 92957b448deSdougm * the internal list of roots to handles be 93057b448deSdougm * setup before anything that might try to 93157b448deSdougm * create a new object is called. The document 93257b448deSdougm * tree is the combination of handle->doc and 93357b448deSdougm * handle->tree. This allows searches, 93457b448deSdougm * etc. when all you have is an object in the 93557b448deSdougm * tree. 93657b448deSdougm */ 93757b448deSdougm handle->doc = xmlNewDoc((xmlChar *)"1.0"); 93857b448deSdougm handle->tree = xmlNewNode(NULL, 93957b448deSdougm (xmlChar *)"sharecfg"); 94057b448deSdougm if (handle->doc != NULL && 94157b448deSdougm handle->tree != NULL) { 9424bff34e3Sthurlow (void) xmlDocSetRootElement(handle->doc, 94357b448deSdougm handle->tree); 94457b448deSdougm err = add_handle_for_root(handle->tree, 94557b448deSdougm handle); 94657b448deSdougm if (err == SA_OK) 94757b448deSdougm err = sa_get_config( 94857b448deSdougm handle->scfhandle, 9491d1813a7Sdougm handle->tree, handle); 95057b448deSdougm } else { 95157b448deSdougm if (handle->doc != NULL) 95257b448deSdougm xmlFreeDoc(handle->doc); 95357b448deSdougm if (handle->tree != NULL) 95457b448deSdougm xmlFreeNode(handle->tree); 95557b448deSdougm err = SA_NO_MEMORY; 95657b448deSdougm } 95757b448deSdougm 95857b448deSdougm saunblocksigs(&old); 95957b448deSdougm 96057b448deSdougm if (err != SA_OK) { 96157b448deSdougm /* 96257b448deSdougm * If we couldn't add the tree handle 96357b448deSdougm * to the list, then things are going 96457b448deSdougm * to fail badly. Might as well undo 96557b448deSdougm * everything now and fail the 96657b448deSdougm * sa_init(). 96757b448deSdougm */ 96857b448deSdougm sa_fini(handle); 969*148c5f43SAlan Wright if (updatelegacy == B_TRUE) { 970*148c5f43SAlan Wright (void) mutex_unlock( 971*148c5f43SAlan Wright &sa_dfstab_lock); 972*148c5f43SAlan Wright (void) lockf(lockfd, 973*148c5f43SAlan Wright F_ULOCK, 0); 974*148c5f43SAlan Wright (void) close(lockfd); 975*148c5f43SAlan Wright } 97657b448deSdougm return (NULL); 97757b448deSdougm } 9781d1813a7Sdougm 97957b448deSdougm if (tval == 0) { 98057b448deSdougm /* 98157b448deSdougm * first time so make sure 98257b448deSdougm * default is setup 98357b448deSdougm */ 98457b448deSdougm verifydefgroupopts(handle); 98557b448deSdougm } 986549ec3ffSdougm 987546405c3Sdougm if (updatelegacy == B_TRUE) { 988546405c3Sdougm sablocksigs(&old); 989546405c3Sdougm getlegacyconfig((sa_handle_t)handle, 990546405c3Sdougm SA_LEGACY_DFSTAB, &handle->tree); 991546405c3Sdougm if (stat(SA_LEGACY_DFSTAB, &st) >= 0) 992546405c3Sdougm set_legacy_timestamp( 993546405c3Sdougm handle->tree, 994546405c3Sdougm SA_LEGACY_DFSTAB, 995546405c3Sdougm TSTAMP(st.st_ctim)); 996546405c3Sdougm saunblocksigs(&old); 997546405c3Sdougm /* 998546405c3Sdougm * Safe to unlock now to allow 999546405c3Sdougm * others to run 1000546405c3Sdougm */ 1001*148c5f43SAlan Wright (void) mutex_unlock(&sa_dfstab_lock); 1002546405c3Sdougm (void) lockf(lockfd, F_ULOCK, 0); 1003546405c3Sdougm (void) close(lockfd); 1004546405c3Sdougm } 10055b6e0c46Sdougm /* Get sharetab timestamp */ 10065b6e0c46Sdougm sa_update_sharetab_ts((sa_handle_t)handle); 10075b6e0c46Sdougm 10085b6e0c46Sdougm /* Get lastupdate (transaction) timestamp */ 10095b6e0c46Sdougm prop = scf_simple_prop_get( 10105b6e0c46Sdougm handle->scfhandle->handle, 10115b6e0c46Sdougm (const char *)SA_SVC_FMRI_BASE ":default", 10125b6e0c46Sdougm "state", "lastupdate"); 10135b6e0c46Sdougm if (prop != NULL) { 10145b6e0c46Sdougm char *str; 10155b6e0c46Sdougm str = 10165b6e0c46Sdougm scf_simple_prop_next_astring(prop); 10175b6e0c46Sdougm if (str != NULL) 10185b6e0c46Sdougm handle->tstrans = 10195b6e0c46Sdougm strtoull(str, NULL, 0); 10205b6e0c46Sdougm else 10215b6e0c46Sdougm handle->tstrans = 0; 10225b6e0c46Sdougm scf_simple_prop_free(prop); 10235b6e0c46Sdougm } 1024546405c3Sdougm legacy |= sa_get_zfs_shares(handle, "zfs"); 1025546405c3Sdougm legacy |= gettransients(handle, &handle->tree); 10266185db85Sdougm } 10276185db85Sdougm } 10286185db85Sdougm } 1029549ec3ffSdougm return ((sa_handle_t)handle); 10306185db85Sdougm } 10316185db85Sdougm 10326185db85Sdougm /* 1033549ec3ffSdougm * sa_fini(handle) 10346185db85Sdougm * Uninitialize the API structures including the configuration 10351cea05afSdougm * data structures and ZFS related data. 10366185db85Sdougm */ 10376185db85Sdougm 10386185db85Sdougm void 1039549ec3ffSdougm sa_fini(sa_handle_t handle) 10406185db85Sdougm { 1041549ec3ffSdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 1042549ec3ffSdougm 1043549ec3ffSdougm if (impl_handle != NULL) { 1044549ec3ffSdougm /* 1045549ec3ffSdougm * Free the config trees and any other data structures 1046549ec3ffSdougm * used in the handle. 1047549ec3ffSdougm */ 1048549ec3ffSdougm if (impl_handle->doc != NULL) 1049549ec3ffSdougm xmlFreeDoc(impl_handle->doc); 1050549ec3ffSdougm 1051549ec3ffSdougm /* Remove and free the entry in the global list. */ 1052549ec3ffSdougm remove_handle_for_root(impl_handle->tree); 1053549ec3ffSdougm 1054549ec3ffSdougm /* 1055549ec3ffSdougm * If this was the last handle to release, unload the 1056c5f58477Sdougm * plugins that were loaded. Use a mutex in case 1057c5f58477Sdougm * another thread is reinitializing. 1058549ec3ffSdougm */ 1059c5f58477Sdougm (void) mutex_lock(&sa_global_lock); 1060549ec3ffSdougm if (sa_global_handles == NULL) 106157b448deSdougm (void) proto_plugin_fini(); 1062c5f58477Sdougm (void) mutex_unlock(&sa_global_lock); 1063549ec3ffSdougm 10640fd77660Sgwr sa_scf_fini(impl_handle->scfhandle); 10650fd77660Sgwr sa_zfs_fini(impl_handle); 10660fd77660Sgwr 10670fd77660Sgwr /* Make sure we free the handle */ 10680fd77660Sgwr free(impl_handle); 10690fd77660Sgwr 10706185db85Sdougm } 10716185db85Sdougm } 10726185db85Sdougm 10736185db85Sdougm /* 10746185db85Sdougm * sa_get_protocols(char **protocol) 10756185db85Sdougm * Get array of protocols that are supported 10766185db85Sdougm * Returns pointer to an allocated and NULL terminated 10776185db85Sdougm * array of strings. Caller must free. 10786185db85Sdougm * This really should be determined dynamically. 10796185db85Sdougm * If there aren't any defined, return -1. 10806185db85Sdougm * Use free() to return memory. 10816185db85Sdougm */ 10826185db85Sdougm 10836185db85Sdougm int 10846185db85Sdougm sa_get_protocols(char ***protocols) 10856185db85Sdougm { 10866185db85Sdougm int numproto = -1; 10876185db85Sdougm 10886185db85Sdougm if (protocols != NULL) { 108957b448deSdougm struct sa_proto_plugin *plug; 109057b448deSdougm for (numproto = 0, plug = sap_proto_list; plug != NULL; 10916185db85Sdougm plug = plug->plugin_next) { 109257b448deSdougm numproto++; 109357b448deSdougm } 109457b448deSdougm 109557b448deSdougm *protocols = calloc(numproto + 1, sizeof (char *)); 109657b448deSdougm if (*protocols != NULL) { 109757b448deSdougm int ret = 0; 109857b448deSdougm for (plug = sap_proto_list; plug != NULL; 109957b448deSdougm plug = plug->plugin_next) { 110057b448deSdougm /* faking for now */ 110157b448deSdougm (*protocols)[ret++] = 110257b448deSdougm plug->plugin_ops->sa_protocol; 110357b448deSdougm } 110457b448deSdougm } else { 110557b448deSdougm numproto = -1; 11066185db85Sdougm } 11076185db85Sdougm } 11086185db85Sdougm return (numproto); 11096185db85Sdougm } 11106185db85Sdougm 11116185db85Sdougm /* 11126185db85Sdougm * find_group_by_name(node, group) 11136185db85Sdougm * 11146185db85Sdougm * search the XML document subtree specified by node to find the group 11156185db85Sdougm * specified by group. Searching subtree allows subgroups to be 11166185db85Sdougm * searched for. 11176185db85Sdougm */ 11186185db85Sdougm 11196185db85Sdougm static xmlNodePtr 11206185db85Sdougm find_group_by_name(xmlNodePtr node, xmlChar *group) 11216185db85Sdougm { 11226185db85Sdougm xmlChar *name = NULL; 11236185db85Sdougm 11246185db85Sdougm for (node = node->xmlChildrenNode; node != NULL; 11256185db85Sdougm node = node->next) { 112657b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"group") == 0) { 112757b448deSdougm /* if no groupname, return the first found */ 112857b448deSdougm if (group == NULL) 112957b448deSdougm break; 113057b448deSdougm name = xmlGetProp(node, (xmlChar *)"name"); 113157b448deSdougm if (name != NULL && xmlStrcmp(name, group) == 0) 113257b448deSdougm break; 113357b448deSdougm if (name != NULL) { 113457b448deSdougm xmlFree(name); 113557b448deSdougm name = NULL; 113657b448deSdougm } 11376185db85Sdougm } 11386185db85Sdougm } 11396185db85Sdougm if (name != NULL) 114057b448deSdougm xmlFree(name); 11416185db85Sdougm return (node); 11426185db85Sdougm } 11436185db85Sdougm 11446185db85Sdougm /* 11456185db85Sdougm * sa_get_group(groupname) 11466185db85Sdougm * Return the "group" specified. If groupname is NULL, 11476185db85Sdougm * return the first group of the list of groups. 11486185db85Sdougm */ 11496185db85Sdougm sa_group_t 1150549ec3ffSdougm sa_get_group(sa_handle_t handle, char *groupname) 11516185db85Sdougm { 11526185db85Sdougm xmlNodePtr node = NULL; 11536185db85Sdougm char *subgroup = NULL; 11546185db85Sdougm char *group = NULL; 1155549ec3ffSdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 11566185db85Sdougm 1157549ec3ffSdougm if (impl_handle != NULL && impl_handle->tree != NULL) { 115857b448deSdougm if (groupname != NULL) { 115957b448deSdougm group = strdup(groupname); 1160a3351425Sdougm if (group != NULL) { 1161a3351425Sdougm subgroup = strchr(group, '/'); 1162a3351425Sdougm if (subgroup != NULL) 1163a3351425Sdougm *subgroup++ = '\0'; 1164a3351425Sdougm } 116557b448deSdougm } 1166a3351425Sdougm /* 1167a3351425Sdougm * We want to find the, possibly, named group. If 1168a3351425Sdougm * group is not NULL, then lookup the name. If it is 1169a3351425Sdougm * NULL, we only do the find if groupname is also 1170a3351425Sdougm * NULL. This allows lookup of the "first" group in 1171a3351425Sdougm * the internal list. 1172a3351425Sdougm */ 1173a3351425Sdougm if (group != NULL || groupname == NULL) 1174a3351425Sdougm node = find_group_by_name(impl_handle->tree, 1175a3351425Sdougm (xmlChar *)group); 1176a3351425Sdougm 117757b448deSdougm /* if a subgroup, find it before returning */ 117857b448deSdougm if (subgroup != NULL && node != NULL) 117957b448deSdougm node = find_group_by_name(node, (xmlChar *)subgroup); 11806185db85Sdougm } 11816185db85Sdougm if (node != NULL && (char *)group != NULL) 118257b448deSdougm (void) sa_get_instance(impl_handle->scfhandle, (char *)group); 11836185db85Sdougm if (group != NULL) 118457b448deSdougm free(group); 11856185db85Sdougm return ((sa_group_t)(node)); 11866185db85Sdougm } 11876185db85Sdougm 11886185db85Sdougm /* 11896185db85Sdougm * sa_get_next_group(group) 11906185db85Sdougm * Return the "next" group after the specified group from 11916185db85Sdougm * the internal group list. NULL if there are no more. 11926185db85Sdougm */ 11936185db85Sdougm sa_group_t 11946185db85Sdougm sa_get_next_group(sa_group_t group) 11956185db85Sdougm { 11966185db85Sdougm xmlNodePtr ngroup = NULL; 11976185db85Sdougm if (group != NULL) { 119857b448deSdougm for (ngroup = ((xmlNodePtr)group)->next; ngroup != NULL; 11996185db85Sdougm ngroup = ngroup->next) { 120057b448deSdougm if (xmlStrcmp(ngroup->name, (xmlChar *)"group") == 0) 120157b448deSdougm break; 120257b448deSdougm } 12036185db85Sdougm } 12046185db85Sdougm return ((sa_group_t)ngroup); 12056185db85Sdougm } 12066185db85Sdougm 12076185db85Sdougm /* 12086185db85Sdougm * sa_get_share(group, sharepath) 12096185db85Sdougm * Return the share object for the share specified. The share 12106185db85Sdougm * must be in the specified group. Return NULL if not found. 12116185db85Sdougm */ 12126185db85Sdougm sa_share_t 12136185db85Sdougm sa_get_share(sa_group_t group, char *sharepath) 12146185db85Sdougm { 12156185db85Sdougm xmlNodePtr node = NULL; 12166185db85Sdougm xmlChar *path; 12176185db85Sdougm 12186185db85Sdougm /* 12196185db85Sdougm * For future scalability, this should end up building a cache 12206185db85Sdougm * since it will get called regularly by the mountd and info 12216185db85Sdougm * services. 12226185db85Sdougm */ 12236185db85Sdougm if (group != NULL) { 122457b448deSdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 12256185db85Sdougm node = node->next) { 122657b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 122757b448deSdougm if (sharepath == NULL) { 122857b448deSdougm break; 122957b448deSdougm } else { 123057b448deSdougm /* is it the correct share? */ 123157b448deSdougm path = xmlGetProp(node, 123257b448deSdougm (xmlChar *)"path"); 123357b448deSdougm if (path != NULL && 123457b448deSdougm xmlStrcmp(path, 123557b448deSdougm (xmlChar *)sharepath) == 0) { 123657b448deSdougm xmlFree(path); 123757b448deSdougm break; 123857b448deSdougm } 123957b448deSdougm xmlFree(path); 124057b448deSdougm } 12416185db85Sdougm } 12426185db85Sdougm } 12436185db85Sdougm } 12446185db85Sdougm return ((sa_share_t)node); 12456185db85Sdougm } 12466185db85Sdougm 12476185db85Sdougm /* 12486185db85Sdougm * sa_get_next_share(share) 12496185db85Sdougm * Return the next share following the specified share 12506185db85Sdougm * from the internal list of shares. Returns NULL if there 12516185db85Sdougm * are no more shares. The list is relative to the same 12526185db85Sdougm * group. 12536185db85Sdougm */ 12546185db85Sdougm sa_share_t 12556185db85Sdougm sa_get_next_share(sa_share_t share) 12566185db85Sdougm { 12576185db85Sdougm xmlNodePtr node = NULL; 12586185db85Sdougm 12596185db85Sdougm if (share != NULL) { 126057b448deSdougm for (node = ((xmlNodePtr)share)->next; node != NULL; 12616185db85Sdougm node = node->next) { 126257b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"share") == 0) { 126357b448deSdougm break; 126457b448deSdougm } 12656185db85Sdougm } 12666185db85Sdougm } 12676185db85Sdougm return ((sa_share_t)node); 12686185db85Sdougm } 12696185db85Sdougm 12706185db85Sdougm /* 12716185db85Sdougm * _sa_get_child_node(node, type) 12726185db85Sdougm * 12736185db85Sdougm * find the child node of the specified node that has "type". This is 12746185db85Sdougm * used to implement several internal functions. 12756185db85Sdougm */ 12766185db85Sdougm 12776185db85Sdougm static xmlNodePtr 12786185db85Sdougm _sa_get_child_node(xmlNodePtr node, xmlChar *type) 12796185db85Sdougm { 12806185db85Sdougm xmlNodePtr child; 12816185db85Sdougm for (child = node->xmlChildrenNode; child != NULL; 12826185db85Sdougm child = child->next) 128357b448deSdougm if (xmlStrcmp(child->name, type) == 0) 128457b448deSdougm return (child); 12856185db85Sdougm return ((xmlNodePtr)NULL); 12866185db85Sdougm } 12876185db85Sdougm 12886185db85Sdougm /* 12896185db85Sdougm * find_share(group, path) 12906185db85Sdougm * 12916185db85Sdougm * Search all the shares in the specified group for one that has the 12926185db85Sdougm * specified path. 12936185db85Sdougm */ 12946185db85Sdougm 12956185db85Sdougm static sa_share_t 12966185db85Sdougm find_share(sa_group_t group, char *sharepath) 12976185db85Sdougm { 12986185db85Sdougm sa_share_t share; 12996185db85Sdougm char *path; 13006185db85Sdougm 13016185db85Sdougm for (share = sa_get_share(group, NULL); share != NULL; 13026185db85Sdougm share = sa_get_next_share(share)) { 130357b448deSdougm path = sa_get_share_attr(share, "path"); 130457b448deSdougm if (path != NULL && strcmp(path, sharepath) == 0) { 130557b448deSdougm sa_free_attr_string(path); 130657b448deSdougm break; 130757b448deSdougm } 130857b448deSdougm if (path != NULL) 130957b448deSdougm sa_free_attr_string(path); 13106185db85Sdougm } 13116185db85Sdougm return (share); 13126185db85Sdougm } 13136185db85Sdougm 13146185db85Sdougm /* 13156185db85Sdougm * sa_get_sub_group(group) 13166185db85Sdougm * 13176185db85Sdougm * Get the first sub-group of group. The sa_get_next_group() function 13186185db85Sdougm * can be used to get the rest. This is currently only used for ZFS 13196185db85Sdougm * sub-groups but could be used to implement a more general mechanism. 13206185db85Sdougm */ 13216185db85Sdougm 13226185db85Sdougm sa_group_t 13236185db85Sdougm sa_get_sub_group(sa_group_t group) 13246185db85Sdougm { 13256185db85Sdougm return ((sa_group_t)_sa_get_child_node((xmlNodePtr)group, 132657b448deSdougm (xmlChar *)"group")); 13276185db85Sdougm } 13286185db85Sdougm 13296185db85Sdougm /* 13306185db85Sdougm * sa_find_share(sharepath) 13316185db85Sdougm * Finds a share regardless of group. In the future, this 13326185db85Sdougm * function should utilize a cache and hash table of some kind. 13336185db85Sdougm * The current assumption is that a path will only be shared 13346185db85Sdougm * once. In the future, this may change as implementation of 13356185db85Sdougm * resource names comes into being. 13366185db85Sdougm */ 13376185db85Sdougm sa_share_t 1338549ec3ffSdougm sa_find_share(sa_handle_t handle, char *sharepath) 13396185db85Sdougm { 13406185db85Sdougm sa_group_t group; 13416185db85Sdougm sa_group_t zgroup; 13426185db85Sdougm sa_share_t share = NULL; 13436185db85Sdougm int done = 0; 13446185db85Sdougm 1345549ec3ffSdougm for (group = sa_get_group(handle, NULL); group != NULL && !done; 134657b448deSdougm group = sa_get_next_group(group)) { 134757b448deSdougm if (is_zfs_group(group)) { 134857b448deSdougm for (zgroup = 134957b448deSdougm (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 135057b448deSdougm (xmlChar *)"group"); 135157b448deSdougm zgroup != NULL; 135257b448deSdougm zgroup = sa_get_next_group(zgroup)) { 135357b448deSdougm share = find_share(zgroup, sharepath); 135457b448deSdougm if (share != NULL) 135557b448deSdougm break; 135657b448deSdougm } 135757b448deSdougm } else { 135857b448deSdougm share = find_share(group, sharepath); 13596185db85Sdougm } 136057b448deSdougm if (share != NULL) 136157b448deSdougm break; 13626185db85Sdougm } 13636185db85Sdougm return (share); 13646185db85Sdougm } 13656185db85Sdougm 13666185db85Sdougm /* 1367f345c0beSdougm * sa_check_path(group, path, strictness) 13686185db85Sdougm * 1369da6c28aaSamw * Check that path is a valid path relative to the group. Currently, 13706185db85Sdougm * we are ignoring the group and checking only the NFS rules. Later, 13716185db85Sdougm * we may want to use the group to then check against the protocols 1372f345c0beSdougm * enabled on the group. The strictness values mean: 1373f345c0beSdougm * SA_CHECK_NORMAL == only check newpath against shares that are active 1374f345c0beSdougm * SA_CHECK_STRICT == check newpath against both active shares and those 1375f345c0beSdougm * stored in the repository 13766185db85Sdougm */ 13776185db85Sdougm 13786185db85Sdougm int 1379f345c0beSdougm sa_check_path(sa_group_t group, char *path, int strictness) 13806185db85Sdougm { 1381549ec3ffSdougm sa_handle_t handle; 1382549ec3ffSdougm 1383549ec3ffSdougm handle = sa_find_group_handle(group); 13849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (handle == NULL) 13859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (SA_BAD_PATH); 13869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1387549ec3ffSdougm return (validpath(handle, path, strictness)); 13886185db85Sdougm } 13896185db85Sdougm 13906185db85Sdougm /* 1391da6c28aaSamw * mark_excluded_protos(group, share, flags) 1392da6c28aaSamw * 1393da6c28aaSamw * Walk through all the protocols enabled for the group and check to 1394da6c28aaSamw * see if the share has any of them should be in the exclude list 1395da6c28aaSamw * based on the featureset of the protocol. If there are any, add the 1396da6c28aaSamw * "exclude" property to the share. 1397da6c28aaSamw */ 1398da6c28aaSamw static void 1399da6c28aaSamw mark_excluded_protos(sa_group_t group, xmlNodePtr share, uint64_t flags) 1400da6c28aaSamw { 1401da6c28aaSamw sa_optionset_t optionset; 1402da6c28aaSamw char exclude_list[SA_STRSIZE]; 1403da6c28aaSamw char *sep = ""; 1404da6c28aaSamw 1405da6c28aaSamw exclude_list[0] = '\0'; 1406da6c28aaSamw for (optionset = sa_get_optionset(group, NULL); 1407da6c28aaSamw optionset != NULL; 1408da6c28aaSamw optionset = sa_get_next_optionset(optionset)) { 1409da6c28aaSamw char *value; 1410da6c28aaSamw uint64_t features; 1411da6c28aaSamw value = sa_get_optionset_attr(optionset, "type"); 1412da6c28aaSamw if (value == NULL) 1413da6c28aaSamw continue; 1414da6c28aaSamw features = sa_proto_get_featureset(value); 1415da6c28aaSamw if (!(features & flags)) { 1416da6c28aaSamw (void) strlcat(exclude_list, sep, 1417da6c28aaSamw sizeof (exclude_list)); 1418da6c28aaSamw (void) strlcat(exclude_list, value, 1419da6c28aaSamw sizeof (exclude_list)); 1420da6c28aaSamw sep = ","; 1421da6c28aaSamw } 1422fe1c642dSBill Krier sa_free_attr_string(value); 1423da6c28aaSamw } 1424da6c28aaSamw if (exclude_list[0] != '\0') 14254bff34e3Sthurlow (void) xmlSetProp(share, (xmlChar *)"exclude", 1426da6c28aaSamw (xmlChar *)exclude_list); 1427da6c28aaSamw } 1428da6c28aaSamw 1429da6c28aaSamw /* 1430da6c28aaSamw * get_all_features(group) 1431da6c28aaSamw * 1432da6c28aaSamw * Walk through all the protocols on the group and collect all 1433da6c28aaSamw * possible enabled features. This is the OR of all the featuresets. 1434da6c28aaSamw */ 1435da6c28aaSamw static uint64_t 1436da6c28aaSamw get_all_features(sa_group_t group) 1437da6c28aaSamw { 1438da6c28aaSamw sa_optionset_t optionset; 1439da6c28aaSamw uint64_t features = 0; 1440da6c28aaSamw 1441da6c28aaSamw for (optionset = sa_get_optionset(group, NULL); 1442da6c28aaSamw optionset != NULL; 1443da6c28aaSamw optionset = sa_get_next_optionset(optionset)) { 1444da6c28aaSamw char *value; 1445da6c28aaSamw value = sa_get_optionset_attr(optionset, "type"); 1446da6c28aaSamw if (value == NULL) 1447da6c28aaSamw continue; 1448da6c28aaSamw features |= sa_proto_get_featureset(value); 1449da6c28aaSamw sa_free_attr_string(value); 1450da6c28aaSamw } 1451da6c28aaSamw return (features); 1452da6c28aaSamw } 1453da6c28aaSamw 1454da6c28aaSamw 1455da6c28aaSamw /* 1456da6c28aaSamw * _sa_add_share(group, sharepath, persist, *error, flags) 14576185db85Sdougm * 1458da6c28aaSamw * Common code for all types of add_share. sa_add_share() is the 14596185db85Sdougm * public API, we also need to be able to do this when parsing legacy 14606185db85Sdougm * files and construction of the internal configuration while 1461da6c28aaSamw * extracting config info from SMF. "flags" indicates if some 1462da6c28aaSamw * protocols need relaxed rules while other don't. These values are 1463da6c28aaSamw * the featureset values defined in libshare.h. 14646185db85Sdougm */ 14656185db85Sdougm 14666185db85Sdougm sa_share_t 1467da6c28aaSamw _sa_add_share(sa_group_t group, char *sharepath, int persist, int *error, 1468da6c28aaSamw uint64_t flags) 14696185db85Sdougm { 14706185db85Sdougm xmlNodePtr node = NULL; 14716185db85Sdougm int err; 14726185db85Sdougm 14736185db85Sdougm err = SA_OK; /* assume success */ 14746185db85Sdougm 147557b448deSdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"share", NULL); 1476da6c28aaSamw if (node == NULL) { 1477da6c28aaSamw if (error != NULL) 1478da6c28aaSamw *error = SA_NO_MEMORY; 1479da6c28aaSamw return (node); 1480da6c28aaSamw } 1481da6c28aaSamw 14824bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath); 14834bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", 1484da6c28aaSamw persist ? (xmlChar *)"persist" : (xmlChar *)"transient"); 1485da6c28aaSamw if (flags != 0) 1486da6c28aaSamw mark_excluded_protos(group, node, flags); 1487da6c28aaSamw if (persist != SA_SHARE_TRANSIENT) { 1488da6c28aaSamw /* 1489da6c28aaSamw * persistent shares come in two flavors: SMF and 1490da6c28aaSamw * ZFS. Sort this one out based on target group and 1491da6c28aaSamw * path type. Both NFS and SMB are supported. First, 1492da6c28aaSamw * check to see if the protocol is enabled on the 1493da6c28aaSamw * subgroup and then setup the share appropriately. 1494da6c28aaSamw */ 1495da6c28aaSamw if (sa_group_is_zfs(group) && 1496da6c28aaSamw sa_path_is_zfs(sharepath)) { 1497da6c28aaSamw if (sa_get_optionset(group, "nfs") != NULL) 149857b448deSdougm err = sa_zfs_set_sharenfs(group, sharepath, 1); 1499da6c28aaSamw else if (sa_get_optionset(group, "smb") != NULL) 1500da6c28aaSamw err = sa_zfs_set_sharesmb(group, sharepath, 1); 1501da6c28aaSamw } else { 1502da6c28aaSamw sa_handle_impl_t impl_handle; 1503da6c28aaSamw impl_handle = 1504da6c28aaSamw (sa_handle_impl_t)sa_find_group_handle(group); 1505da6c28aaSamw if (impl_handle != NULL) { 1506da6c28aaSamw err = sa_commit_share(impl_handle->scfhandle, 1507da6c28aaSamw group, (sa_share_t)node); 150857b448deSdougm } else { 1509da6c28aaSamw err = SA_SYSTEM_ERR; 151057b448deSdougm } 151157b448deSdougm } 15126185db85Sdougm } 1513da6c28aaSamw if (err == SA_NO_PERMISSION && persist & SA_SHARE_PARSER) 1514da6c28aaSamw /* called by the dfstab parser so could be a show */ 1515da6c28aaSamw err = SA_OK; 1516da6c28aaSamw 1517da6c28aaSamw if (err != SA_OK) { 1518da6c28aaSamw /* 1519da6c28aaSamw * we couldn't commit to the repository so undo 1520da6c28aaSamw * our internal state to reflect reality. 1521da6c28aaSamw */ 1522da6c28aaSamw xmlUnlinkNode(node); 1523da6c28aaSamw xmlFreeNode(node); 1524da6c28aaSamw node = NULL; 1525da6c28aaSamw } 1526da6c28aaSamw 15276185db85Sdougm if (error != NULL) 152857b448deSdougm *error = err; 1529da6c28aaSamw 15306185db85Sdougm return (node); 15316185db85Sdougm } 15326185db85Sdougm 15336185db85Sdougm /* 15346185db85Sdougm * sa_add_share(group, sharepath, persist, *error) 15356185db85Sdougm * 15366185db85Sdougm * Add a new share object to the specified group. The share will 15376185db85Sdougm * have the specified sharepath and will only be constructed if 15386185db85Sdougm * it is a valid path to be shared. NULL is returned on error 15396185db85Sdougm * and a detailed error value will be returned via the error 15406185db85Sdougm * pointer. 15416185db85Sdougm */ 15426185db85Sdougm sa_share_t 15436185db85Sdougm sa_add_share(sa_group_t group, char *sharepath, int persist, int *error) 15446185db85Sdougm { 15456185db85Sdougm xmlNodePtr node = NULL; 1546f345c0beSdougm int strictness = SA_CHECK_NORMAL; 1547549ec3ffSdougm sa_handle_t handle; 1548da6c28aaSamw uint64_t special = 0; 1549da6c28aaSamw uint64_t features; 1550f345c0beSdougm 1551f345c0beSdougm /* 1552f345c0beSdougm * If the share is to be permanent, use strict checking so a 1553f345c0beSdougm * bad config doesn't get created. Transient shares only need 1554f345c0beSdougm * to check against the currently active 1555f345c0beSdougm * shares. SA_SHARE_PARSER is a modifier used internally to 1556f345c0beSdougm * indicate that we are being called by the dfstab parser and 1557f345c0beSdougm * that we need strict checking in all cases. Normally persist 1558f345c0beSdougm * is in integer value but SA_SHARE_PARSER may be or'd into 1559f345c0beSdougm * it as an override. 1560f345c0beSdougm */ 1561f345c0beSdougm if (persist & SA_SHARE_PARSER || persist == SA_SHARE_PERMANENT) 156257b448deSdougm strictness = SA_CHECK_STRICT; 15636185db85Sdougm 1564549ec3ffSdougm handle = sa_find_group_handle(group); 1565549ec3ffSdougm 1566da6c28aaSamw /* 1567da6c28aaSamw * need to determine if the share is valid. The rules are: 1568da6c28aaSamw * - The path must not already exist 1569da6c28aaSamw * - The path must not be a subdir or parent dir of an 1570da6c28aaSamw * existing path unless at least one protocol allows it. 1571da6c28aaSamw * The sub/parent check is done in sa_check_path(). 1572da6c28aaSamw */ 1573da6c28aaSamw 1574da6c28aaSamw if (sa_find_share(handle, sharepath) == NULL) { 1575da6c28aaSamw *error = sa_check_path(group, sharepath, strictness); 1576da6c28aaSamw features = get_all_features(group); 1577da6c28aaSamw switch (*error) { 1578da6c28aaSamw case SA_PATH_IS_SUBDIR: 1579da6c28aaSamw if (features & SA_FEATURE_ALLOWSUBDIRS) 1580da6c28aaSamw special |= SA_FEATURE_ALLOWSUBDIRS; 1581da6c28aaSamw break; 1582da6c28aaSamw case SA_PATH_IS_PARENTDIR: 1583da6c28aaSamw if (features & SA_FEATURE_ALLOWPARDIRS) 1584da6c28aaSamw special |= SA_FEATURE_ALLOWPARDIRS; 1585da6c28aaSamw break; 1586da6c28aaSamw } 1587da6c28aaSamw if (*error == SA_OK || special != SA_FEATURE_NONE) 1588da6c28aaSamw node = _sa_add_share(group, sharepath, persist, 1589da6c28aaSamw error, special); 1590da6c28aaSamw } else { 159157b448deSdougm *error = SA_DUPLICATE_NAME; 1592da6c28aaSamw } 15936185db85Sdougm 15946185db85Sdougm return ((sa_share_t)node); 15956185db85Sdougm } 15966185db85Sdougm 15976185db85Sdougm /* 15986185db85Sdougm * sa_enable_share(share, protocol) 15996185db85Sdougm * Enable the specified share to the specified protocol. 16006185db85Sdougm * If protocol is NULL, then all protocols. 16016185db85Sdougm */ 16026185db85Sdougm int 16036185db85Sdougm sa_enable_share(sa_share_t share, char *protocol) 16046185db85Sdougm { 16056185db85Sdougm char *sharepath; 16066185db85Sdougm struct stat st; 1607da6c28aaSamw int err = SA_OK; 1608da6c28aaSamw int ret; 16096185db85Sdougm 16106185db85Sdougm sharepath = sa_get_share_attr(share, "path"); 1611da6c28aaSamw if (sharepath == NULL) 1612da6c28aaSamw return (SA_NO_MEMORY); 16136185db85Sdougm if (stat(sharepath, &st) < 0) { 161457b448deSdougm err = SA_NO_SUCH_PATH; 16156185db85Sdougm } else { 161657b448deSdougm /* tell the server about the share */ 161757b448deSdougm if (protocol != NULL) { 1618da6c28aaSamw if (excluded_protocol(share, protocol)) 1619da6c28aaSamw goto done; 1620da6c28aaSamw 162157b448deSdougm /* lookup protocol specific handler */ 162257b448deSdougm err = sa_proto_share(protocol, share); 162357b448deSdougm if (err == SA_OK) 1624da6c28aaSamw (void) sa_set_share_attr(share, 1625da6c28aaSamw "shared", "true"); 162657b448deSdougm } else { 1627da6c28aaSamw /* Tell all protocols about the share */ 1628da6c28aaSamw sa_group_t group; 1629da6c28aaSamw sa_optionset_t optionset; 1630da6c28aaSamw 1631da6c28aaSamw group = sa_get_parent_group(share); 1632da6c28aaSamw 1633da6c28aaSamw for (optionset = sa_get_optionset(group, NULL); 1634da6c28aaSamw optionset != NULL; 1635da6c28aaSamw optionset = sa_get_next_optionset(optionset)) { 1636da6c28aaSamw char *proto; 1637da6c28aaSamw proto = sa_get_optionset_attr(optionset, 1638da6c28aaSamw "type"); 1639da6c28aaSamw if (proto != NULL) { 1640da6c28aaSamw if (!excluded_protocol(share, proto)) { 1641da6c28aaSamw ret = sa_proto_share(proto, 1642da6c28aaSamw share); 1643da6c28aaSamw if (ret != SA_OK) 1644da6c28aaSamw err = ret; 1645da6c28aaSamw } 1646da6c28aaSamw sa_free_attr_string(proto); 1647da6c28aaSamw } 1648da6c28aaSamw } 164957b448deSdougm (void) sa_set_share_attr(share, "shared", "true"); 165057b448deSdougm } 16516185db85Sdougm } 1652da6c28aaSamw done: 16536185db85Sdougm if (sharepath != NULL) 165457b448deSdougm sa_free_attr_string(sharepath); 16556185db85Sdougm return (err); 16566185db85Sdougm } 16576185db85Sdougm 16586185db85Sdougm /* 16596185db85Sdougm * sa_disable_share(share, protocol) 1660da6c28aaSamw * Disable the specified share to the specified protocol. If 1661da6c28aaSamw * protocol is NULL, then all protocols that are enabled for the 1662da6c28aaSamw * share should be disabled. 16636185db85Sdougm */ 16646185db85Sdougm int 16656185db85Sdougm sa_disable_share(sa_share_t share, char *protocol) 16666185db85Sdougm { 16676185db85Sdougm char *path; 1668da6c28aaSamw int err = SA_OK; 16696185db85Sdougm int ret = SA_OK; 16706185db85Sdougm 16716185db85Sdougm path = sa_get_share_attr(share, "path"); 16726185db85Sdougm 16736185db85Sdougm if (protocol != NULL) { 1674ecd6cf80Smarks ret = sa_proto_unshare(share, protocol, path); 16756185db85Sdougm } else { 167657b448deSdougm /* need to do all protocols */ 1677da6c28aaSamw sa_group_t group; 1678da6c28aaSamw sa_optionset_t optionset; 1679da6c28aaSamw 1680da6c28aaSamw group = sa_get_parent_group(share); 1681da6c28aaSamw 1682da6c28aaSamw /* Tell all protocols about the share */ 1683da6c28aaSamw for (optionset = sa_get_optionset(group, NULL); 1684da6c28aaSamw optionset != NULL; 1685da6c28aaSamw optionset = sa_get_next_optionset(optionset)) { 1686da6c28aaSamw char *proto; 1687da6c28aaSamw 1688da6c28aaSamw proto = sa_get_optionset_attr(optionset, "type"); 1689da6c28aaSamw if (proto != NULL) { 1690da6c28aaSamw err = sa_proto_unshare(share, proto, path); 1691da6c28aaSamw if (err != SA_OK) 1692da6c28aaSamw ret = err; 1693da6c28aaSamw sa_free_attr_string(proto); 1694da6c28aaSamw } 1695da6c28aaSamw } 16966185db85Sdougm } 16976185db85Sdougm if (ret == SA_OK) 16986185db85Sdougm (void) sa_set_share_attr(share, "shared", NULL); 16996185db85Sdougm if (path != NULL) 170057b448deSdougm sa_free_attr_string(path); 17016185db85Sdougm return (ret); 17026185db85Sdougm } 17036185db85Sdougm 17046185db85Sdougm /* 17056185db85Sdougm * sa_remove_share(share) 17066185db85Sdougm * 17076185db85Sdougm * remove the specified share from its containing group. 17086185db85Sdougm * Remove from the SMF or ZFS configuration space. 17096185db85Sdougm */ 17106185db85Sdougm 17116185db85Sdougm int 17126185db85Sdougm sa_remove_share(sa_share_t share) 17136185db85Sdougm { 17146185db85Sdougm sa_group_t group; 17156185db85Sdougm int ret = SA_OK; 17166185db85Sdougm char *type; 17176185db85Sdougm int transient = 0; 17186185db85Sdougm char *groupname; 17196185db85Sdougm char *zfs; 17206185db85Sdougm 17216185db85Sdougm type = sa_get_share_attr(share, "type"); 17226185db85Sdougm group = sa_get_parent_group(share); 17236185db85Sdougm zfs = sa_get_group_attr(group, "zfs"); 17246185db85Sdougm groupname = sa_get_group_attr(group, "name"); 17256185db85Sdougm if (type != NULL && strcmp(type, "persist") != 0) 172657b448deSdougm transient = 1; 17276185db85Sdougm if (type != NULL) 172857b448deSdougm sa_free_attr_string(type); 17296185db85Sdougm 17306185db85Sdougm /* remove the node from its group then free the memory */ 17316185db85Sdougm 17326185db85Sdougm /* 17336185db85Sdougm * need to test if "busy" 17346185db85Sdougm */ 17356185db85Sdougm /* only do SMF action if permanent */ 17366185db85Sdougm if (!transient || zfs != NULL) { 173757b448deSdougm /* remove from legacy dfstab as well as possible SMF */ 1738da6c28aaSamw ret = sa_delete_legacy(share, NULL); 173957b448deSdougm if (ret == SA_OK) { 174057b448deSdougm if (!sa_group_is_zfs(group)) { 174157b448deSdougm sa_handle_impl_t impl_handle; 174257b448deSdougm impl_handle = (sa_handle_impl_t) 174357b448deSdougm sa_find_group_handle(group); 174457b448deSdougm if (impl_handle != NULL) { 174557b448deSdougm ret = sa_delete_share( 174657b448deSdougm impl_handle->scfhandle, group, 174757b448deSdougm share); 174857b448deSdougm } else { 174957b448deSdougm ret = SA_SYSTEM_ERR; 175057b448deSdougm } 175157b448deSdougm } else { 175257b448deSdougm char *sharepath = sa_get_share_attr(share, 175357b448deSdougm "path"); 175457b448deSdougm if (sharepath != NULL) { 175557b448deSdougm ret = sa_zfs_set_sharenfs(group, 175657b448deSdougm sharepath, 0); 175757b448deSdougm sa_free_attr_string(sharepath); 175857b448deSdougm } 175957b448deSdougm } 17606185db85Sdougm } 17616185db85Sdougm } 17626185db85Sdougm if (groupname != NULL) 176357b448deSdougm sa_free_attr_string(groupname); 17646185db85Sdougm if (zfs != NULL) 176557b448deSdougm sa_free_attr_string(zfs); 17666185db85Sdougm 17676185db85Sdougm xmlUnlinkNode((xmlNodePtr)share); 17686185db85Sdougm xmlFreeNode((xmlNodePtr)share); 17696185db85Sdougm return (ret); 17706185db85Sdougm } 17716185db85Sdougm 17726185db85Sdougm /* 17736185db85Sdougm * sa_move_share(group, share) 17746185db85Sdougm * 17756185db85Sdougm * move the specified share to the specified group. Update SMF 17766185db85Sdougm * appropriately. 17776185db85Sdougm */ 17786185db85Sdougm 17796185db85Sdougm int 17806185db85Sdougm sa_move_share(sa_group_t group, sa_share_t share) 17816185db85Sdougm { 17826185db85Sdougm sa_group_t oldgroup; 17836185db85Sdougm int ret = SA_OK; 17846185db85Sdougm 17856185db85Sdougm /* remove the node from its group then free the memory */ 17866185db85Sdougm 17876185db85Sdougm oldgroup = sa_get_parent_group(share); 17886185db85Sdougm if (oldgroup != group) { 178957b448deSdougm sa_handle_impl_t impl_handle; 179057b448deSdougm xmlUnlinkNode((xmlNodePtr)share); 17916185db85Sdougm /* 179257b448deSdougm * now that the share isn't in its old group, add to 179357b448deSdougm * the new one 17946185db85Sdougm */ 17954bff34e3Sthurlow (void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share); 179657b448deSdougm /* need to deal with SMF */ 179757b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 179857b448deSdougm if (impl_handle != NULL) { 179957b448deSdougm /* 180057b448deSdougm * need to remove from old group first and then add to 180157b448deSdougm * new group. Ideally, we would do the other order but 180257b448deSdougm * need to avoid having the share in two groups at the 180357b448deSdougm * same time. 180457b448deSdougm */ 180557b448deSdougm ret = sa_delete_share(impl_handle->scfhandle, oldgroup, 180657b448deSdougm share); 180757b448deSdougm if (ret == SA_OK) 180857b448deSdougm ret = sa_commit_share(impl_handle->scfhandle, 180957b448deSdougm group, share); 181057b448deSdougm } else { 181157b448deSdougm ret = SA_SYSTEM_ERR; 181257b448deSdougm } 18136185db85Sdougm } 18146185db85Sdougm return (ret); 18156185db85Sdougm } 18166185db85Sdougm 18176185db85Sdougm /* 18186185db85Sdougm * sa_get_parent_group(share) 18196185db85Sdougm * 1820da6c28aaSamw * Return the containing group for the share. If a group was actually 18216185db85Sdougm * passed in, we don't want a parent so return NULL. 18226185db85Sdougm */ 18236185db85Sdougm 18246185db85Sdougm sa_group_t 18256185db85Sdougm sa_get_parent_group(sa_share_t share) 18266185db85Sdougm { 18276185db85Sdougm xmlNodePtr node = NULL; 18286185db85Sdougm if (share != NULL) { 182957b448deSdougm node = ((xmlNodePtr)share)->parent; 18306185db85Sdougm /* 18316185db85Sdougm * make sure parent is a group and not sharecfg since 18326185db85Sdougm * we may be cheating and passing in a group. 18336185db85Sdougm * Eventually, groups of groups might come into being. 18346185db85Sdougm */ 183557b448deSdougm if (node == NULL || 183657b448deSdougm xmlStrcmp(node->name, (xmlChar *)"sharecfg") == 0) 183757b448deSdougm node = NULL; 18386185db85Sdougm } 18396185db85Sdougm return ((sa_group_t)node); 18406185db85Sdougm } 18416185db85Sdougm 18426185db85Sdougm /* 1843549ec3ffSdougm * _sa_create_group(impl_handle, groupname) 18446185db85Sdougm * 18456185db85Sdougm * Create a group in the document. The caller will need to deal with 18466185db85Sdougm * configuration store and activation. 18476185db85Sdougm */ 18486185db85Sdougm 18496185db85Sdougm sa_group_t 1850549ec3ffSdougm _sa_create_group(sa_handle_impl_t impl_handle, char *groupname) 18516185db85Sdougm { 18526185db85Sdougm xmlNodePtr node = NULL; 18536185db85Sdougm 18546185db85Sdougm if (sa_valid_group_name(groupname)) { 185557b448deSdougm node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group", 185657b448deSdougm NULL); 185757b448deSdougm if (node != NULL) { 18584bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 185957b448deSdougm (xmlChar *)groupname); 18604bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 186157b448deSdougm (xmlChar *)"enabled"); 186257b448deSdougm } 18636185db85Sdougm } 18646185db85Sdougm return ((sa_group_t)node); 18656185db85Sdougm } 18666185db85Sdougm 18676185db85Sdougm /* 18686185db85Sdougm * _sa_create_zfs_group(group, groupname) 18696185db85Sdougm * 18706185db85Sdougm * Create a ZFS subgroup under the specified group. This may 18716185db85Sdougm * eventually form the basis of general sub-groups, but is currently 18726185db85Sdougm * restricted to ZFS. 18736185db85Sdougm */ 18746185db85Sdougm sa_group_t 18756185db85Sdougm _sa_create_zfs_group(sa_group_t group, char *groupname) 18766185db85Sdougm { 18776185db85Sdougm xmlNodePtr node = NULL; 18786185db85Sdougm 187957b448deSdougm node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL); 18806185db85Sdougm if (node != NULL) { 18814bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 18824bff34e3Sthurlow (xmlChar *)groupname); 18834bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 18844bff34e3Sthurlow (xmlChar *)"enabled"); 18856185db85Sdougm } 18866185db85Sdougm 18876185db85Sdougm return ((sa_group_t)node); 18886185db85Sdougm } 18896185db85Sdougm 18906185db85Sdougm /* 18916185db85Sdougm * sa_create_group(groupname, *error) 18926185db85Sdougm * 18936185db85Sdougm * Create a new group with groupname. Need to validate that it is a 18946185db85Sdougm * legal name for SMF and the construct the SMF service instance of 18956185db85Sdougm * svc:/network/shares/group to implement the group. All necessary 18966185db85Sdougm * operational properties must be added to the group at this point 18976185db85Sdougm * (via the SMF transaction model). 18986185db85Sdougm */ 18996185db85Sdougm sa_group_t 1900549ec3ffSdougm sa_create_group(sa_handle_t handle, char *groupname, int *error) 19016185db85Sdougm { 19026185db85Sdougm xmlNodePtr node = NULL; 19036185db85Sdougm sa_group_t group; 19046185db85Sdougm int ret; 190557b448deSdougm char rbacstr[SA_STRSIZE]; 1906549ec3ffSdougm sa_handle_impl_t impl_handle = (sa_handle_impl_t)handle; 19076185db85Sdougm 19086185db85Sdougm ret = SA_OK; 19096185db85Sdougm 1910549ec3ffSdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) { 191157b448deSdougm ret = SA_SYSTEM_ERR; 191257b448deSdougm goto err; 19136185db85Sdougm } 19146185db85Sdougm 1915549ec3ffSdougm group = sa_get_group(handle, groupname); 19166185db85Sdougm if (group != NULL) { 191757b448deSdougm ret = SA_DUPLICATE_NAME; 19186185db85Sdougm } else { 191957b448deSdougm if (sa_valid_group_name(groupname)) { 192057b448deSdougm node = xmlNewChild(impl_handle->tree, NULL, 192157b448deSdougm (xmlChar *)"group", NULL); 192257b448deSdougm if (node != NULL) { 19234bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 192457b448deSdougm (xmlChar *)groupname); 192557b448deSdougm /* default to the group being enabled */ 19264bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"state", 192757b448deSdougm (xmlChar *)"enabled"); 192857b448deSdougm ret = sa_create_instance(impl_handle->scfhandle, 192957b448deSdougm groupname); 193057b448deSdougm if (ret == SA_OK) { 193157b448deSdougm ret = sa_start_transaction( 193257b448deSdougm impl_handle->scfhandle, 193357b448deSdougm "operation"); 193457b448deSdougm } 193557b448deSdougm if (ret == SA_OK) { 193657b448deSdougm ret = sa_set_property( 193757b448deSdougm impl_handle->scfhandle, 193857b448deSdougm "state", "enabled"); 193957b448deSdougm if (ret == SA_OK) { 194057b448deSdougm ret = sa_end_transaction( 19415b6e0c46Sdougm impl_handle->scfhandle, 19425b6e0c46Sdougm impl_handle); 194357b448deSdougm } else { 194457b448deSdougm sa_abort_transaction( 194557b448deSdougm impl_handle->scfhandle); 194657b448deSdougm } 194757b448deSdougm } 194857b448deSdougm if (ret == SA_OK) { 194957b448deSdougm /* initialize the RBAC strings */ 195057b448deSdougm ret = sa_start_transaction( 195157b448deSdougm impl_handle->scfhandle, 195257b448deSdougm "general"); 195357b448deSdougm if (ret == SA_OK) { 195457b448deSdougm (void) snprintf(rbacstr, 195557b448deSdougm sizeof (rbacstr), "%s.%s", 195657b448deSdougm SA_RBAC_MANAGE, groupname); 195757b448deSdougm ret = sa_set_property( 195857b448deSdougm impl_handle->scfhandle, 19596185db85Sdougm "action_authorization", 19606185db85Sdougm rbacstr); 196157b448deSdougm } 196257b448deSdougm if (ret == SA_OK) { 196357b448deSdougm (void) snprintf(rbacstr, 196457b448deSdougm sizeof (rbacstr), "%s.%s", 196557b448deSdougm SA_RBAC_VALUE, groupname); 196657b448deSdougm ret = sa_set_property( 196757b448deSdougm impl_handle->scfhandle, 19686185db85Sdougm "value_authorization", 19696185db85Sdougm rbacstr); 197057b448deSdougm } 197157b448deSdougm if (ret == SA_OK) { 197257b448deSdougm ret = sa_end_transaction( 19735b6e0c46Sdougm impl_handle->scfhandle, 19745b6e0c46Sdougm impl_handle); 197557b448deSdougm } else { 197657b448deSdougm sa_abort_transaction( 197757b448deSdougm impl_handle->scfhandle); 197857b448deSdougm } 197957b448deSdougm } 198057b448deSdougm if (ret != SA_OK) { 198157b448deSdougm /* 198257b448deSdougm * Couldn't commit the group 198357b448deSdougm * so we need to undo 198457b448deSdougm * internally. 198557b448deSdougm */ 198657b448deSdougm xmlUnlinkNode(node); 198757b448deSdougm xmlFreeNode(node); 198857b448deSdougm node = NULL; 198957b448deSdougm } 19906185db85Sdougm } else { 199157b448deSdougm ret = SA_NO_MEMORY; 19926185db85Sdougm } 19936185db85Sdougm } else { 199457b448deSdougm ret = SA_INVALID_NAME; 19956185db85Sdougm } 19966185db85Sdougm } 19976185db85Sdougm err: 19986185db85Sdougm if (error != NULL) 199957b448deSdougm *error = ret; 20006185db85Sdougm return ((sa_group_t)node); 20016185db85Sdougm } 20026185db85Sdougm 20036185db85Sdougm /* 20046185db85Sdougm * sa_remove_group(group) 20056185db85Sdougm * 20066185db85Sdougm * Remove the specified group. This deletes from the SMF repository. 20076185db85Sdougm * All property groups and properties are removed. 20086185db85Sdougm */ 20096185db85Sdougm 20106185db85Sdougm int 20116185db85Sdougm sa_remove_group(sa_group_t group) 20126185db85Sdougm { 20136185db85Sdougm char *name; 20146185db85Sdougm int ret = SA_OK; 2015549ec3ffSdougm sa_handle_impl_t impl_handle; 20166185db85Sdougm 2017549ec3ffSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 2018549ec3ffSdougm if (impl_handle != NULL) { 201957b448deSdougm name = sa_get_group_attr(group, "name"); 202057b448deSdougm if (name != NULL) { 202157b448deSdougm ret = sa_delete_instance(impl_handle->scfhandle, name); 202257b448deSdougm sa_free_attr_string(name); 202357b448deSdougm } 202457b448deSdougm xmlUnlinkNode((xmlNodePtr)group); /* make sure unlinked */ 202557b448deSdougm xmlFreeNode((xmlNodePtr)group); /* now it is gone */ 2026549ec3ffSdougm } else { 202757b448deSdougm ret = SA_SYSTEM_ERR; 20286185db85Sdougm } 20296185db85Sdougm return (ret); 20306185db85Sdougm } 20316185db85Sdougm 20326185db85Sdougm /* 20336185db85Sdougm * sa_update_config() 20346185db85Sdougm * 20356185db85Sdougm * Used to update legacy files that need to be updated in bulk 20366185db85Sdougm * Currently, this is a placeholder and will go away in a future 20376185db85Sdougm * release. 20386185db85Sdougm */ 20396185db85Sdougm 20406185db85Sdougm int 2041549ec3ffSdougm sa_update_config(sa_handle_t handle) 20426185db85Sdougm { 20436185db85Sdougm /* 20446185db85Sdougm * do legacy files first so we can tell when they change. 20456185db85Sdougm * This will go away when we start updating individual records 20466185db85Sdougm * rather than the whole file. 20476185db85Sdougm */ 2048549ec3ffSdougm update_legacy_config(handle); 20496185db85Sdougm return (SA_OK); 20506185db85Sdougm } 20516185db85Sdougm 20526185db85Sdougm /* 20536185db85Sdougm * get_node_attr(node, tag) 20546185db85Sdougm * 2055da6c28aaSamw * Get the specified tag(attribute) if it exists on the node. This is 20566185db85Sdougm * used internally by a number of attribute oriented functions. 20576185db85Sdougm */ 20586185db85Sdougm 20596185db85Sdougm static char * 20606185db85Sdougm get_node_attr(void *nodehdl, char *tag) 20616185db85Sdougm { 20626185db85Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20636185db85Sdougm xmlChar *name = NULL; 20646185db85Sdougm 206557b448deSdougm if (node != NULL) 20666185db85Sdougm name = xmlGetProp(node, (xmlChar *)tag); 20676185db85Sdougm return ((char *)name); 20686185db85Sdougm } 20696185db85Sdougm 20706185db85Sdougm /* 2071fe1c642dSBill Krier * set_node_attr(node, tag) 20726185db85Sdougm * 2073da6c28aaSamw * Set the specified tag(attribute) to the specified value This is 20746185db85Sdougm * used internally by a number of attribute oriented functions. It 20756185db85Sdougm * doesn't update the repository, only the internal document state. 20766185db85Sdougm */ 20776185db85Sdougm 20786185db85Sdougm void 20796185db85Sdougm set_node_attr(void *nodehdl, char *tag, char *value) 20806185db85Sdougm { 20816185db85Sdougm xmlNodePtr node = (xmlNodePtr)nodehdl; 20826185db85Sdougm if (node != NULL && tag != NULL) { 208357b448deSdougm if (value != NULL) 20844bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)tag, 20854bff34e3Sthurlow (xmlChar *)value); 208657b448deSdougm else 20874bff34e3Sthurlow (void) xmlUnsetProp(node, (xmlChar *)tag); 20886185db85Sdougm } 20896185db85Sdougm } 20906185db85Sdougm 20916185db85Sdougm /* 20926185db85Sdougm * sa_get_group_attr(group, tag) 20936185db85Sdougm * 20946185db85Sdougm * Get the specied attribute, if defined, for the group. 20956185db85Sdougm */ 20966185db85Sdougm 20976185db85Sdougm char * 20986185db85Sdougm sa_get_group_attr(sa_group_t group, char *tag) 20996185db85Sdougm { 21006185db85Sdougm return (get_node_attr((void *)group, tag)); 21016185db85Sdougm } 21026185db85Sdougm 21036185db85Sdougm /* 21046185db85Sdougm * sa_set_group_attr(group, tag, value) 21056185db85Sdougm * 21066185db85Sdougm * set the specified tag/attribute on the group using value as its 21076185db85Sdougm * value. 21086185db85Sdougm * 21096185db85Sdougm * This will result in setting the property in the SMF repository as 21106185db85Sdougm * well as in the internal document. 21116185db85Sdougm */ 21126185db85Sdougm 21136185db85Sdougm int 21146185db85Sdougm sa_set_group_attr(sa_group_t group, char *tag, char *value) 21156185db85Sdougm { 21166185db85Sdougm int ret; 21176185db85Sdougm char *groupname; 2118549ec3ffSdougm sa_handle_impl_t impl_handle; 21196185db85Sdougm 2120da6c28aaSamw /* 2121da6c28aaSamw * ZFS group/subgroup doesn't need the handle so shortcut. 2122da6c28aaSamw */ 2123da6c28aaSamw if (sa_group_is_zfs(group)) { 2124da6c28aaSamw set_node_attr((void *)group, tag, value); 2125da6c28aaSamw return (SA_OK); 2126da6c28aaSamw } 2127da6c28aaSamw 2128549ec3ffSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 2129549ec3ffSdougm if (impl_handle != NULL) { 213057b448deSdougm groupname = sa_get_group_attr(group, "name"); 213157b448deSdougm ret = sa_get_instance(impl_handle->scfhandle, groupname); 2132549ec3ffSdougm if (ret == SA_OK) { 213357b448deSdougm set_node_attr((void *)group, tag, value); 213457b448deSdougm ret = sa_start_transaction(impl_handle->scfhandle, 213557b448deSdougm "operation"); 213657b448deSdougm if (ret == SA_OK) { 213757b448deSdougm ret = sa_set_property(impl_handle->scfhandle, 213857b448deSdougm tag, value); 213957b448deSdougm if (ret == SA_OK) 2140573b0c00Sdougm ret = sa_end_transaction( 21415b6e0c46Sdougm impl_handle->scfhandle, 21425b6e0c46Sdougm impl_handle); 214357b448deSdougm else 214457b448deSdougm sa_abort_transaction( 214557b448deSdougm impl_handle->scfhandle); 214657b448deSdougm } 2147573b0c00Sdougm if (ret == SA_SYSTEM_ERR) 2148573b0c00Sdougm ret = SA_NO_PERMISSION; 21496185db85Sdougm } 215057b448deSdougm if (groupname != NULL) 215157b448deSdougm sa_free_attr_string(groupname); 2152549ec3ffSdougm } else { 215357b448deSdougm ret = SA_SYSTEM_ERR; 21546185db85Sdougm } 21556185db85Sdougm return (ret); 21566185db85Sdougm } 21576185db85Sdougm 21586185db85Sdougm /* 21596185db85Sdougm * sa_get_share_attr(share, tag) 21606185db85Sdougm * 21616185db85Sdougm * Return the value of the tag/attribute set on the specified 21626185db85Sdougm * share. Returns NULL if the tag doesn't exist. 21636185db85Sdougm */ 21646185db85Sdougm 21656185db85Sdougm char * 21666185db85Sdougm sa_get_share_attr(sa_share_t share, char *tag) 21676185db85Sdougm { 21686185db85Sdougm return (get_node_attr((void *)share, tag)); 21696185db85Sdougm } 21706185db85Sdougm 21716185db85Sdougm /* 21726185db85Sdougm * _sa_set_share_description(share, description) 21736185db85Sdougm * 2174da6c28aaSamw * Add a description tag with text contents to the specified share. A 2175da6c28aaSamw * separate XML tag is used rather than a property. This can also be 2176da6c28aaSamw * used with resources. 21776185db85Sdougm */ 21786185db85Sdougm 21796185db85Sdougm xmlNodePtr 2180da6c28aaSamw _sa_set_share_description(void *share, char *content) 21816185db85Sdougm { 21826185db85Sdougm xmlNodePtr node; 218357b448deSdougm node = xmlNewChild((xmlNodePtr)share, NULL, (xmlChar *)"description", 218457b448deSdougm NULL); 21856185db85Sdougm xmlNodeSetContent(node, (xmlChar *)content); 21866185db85Sdougm return (node); 21876185db85Sdougm } 21886185db85Sdougm 21896185db85Sdougm /* 21906185db85Sdougm * sa_set_share_attr(share, tag, value) 21916185db85Sdougm * 21926185db85Sdougm * Set the share attribute specified by tag to the specified value. In 21936185db85Sdougm * the case of "resource", enforce a no duplicates in a group rule. If 21946185db85Sdougm * the share is not transient, commit the changes to the repository 21956185db85Sdougm * else just update the share internally. 21966185db85Sdougm */ 21976185db85Sdougm 21986185db85Sdougm int 21996185db85Sdougm sa_set_share_attr(sa_share_t share, char *tag, char *value) 22006185db85Sdougm { 22016185db85Sdougm sa_group_t group; 22026185db85Sdougm sa_share_t resource; 22036185db85Sdougm int ret = SA_OK; 22046185db85Sdougm 22056185db85Sdougm group = sa_get_parent_group(share); 22066185db85Sdougm 22076185db85Sdougm /* 22086185db85Sdougm * There are some attributes that may have specific 22096185db85Sdougm * restrictions on them. Initially, only "resource" has 22106185db85Sdougm * special meaning that needs to be checked. Only one instance 22116185db85Sdougm * of a resource name may exist within a group. 22126185db85Sdougm */ 22136185db85Sdougm 22146185db85Sdougm if (strcmp(tag, "resource") == 0) { 221557b448deSdougm resource = sa_get_resource(group, value); 221657b448deSdougm if (resource != share && resource != NULL) 221757b448deSdougm ret = SA_DUPLICATE_NAME; 22186185db85Sdougm } 22196185db85Sdougm if (ret == SA_OK) { 222057b448deSdougm set_node_attr((void *)share, tag, value); 222157b448deSdougm if (group != NULL) { 222257b448deSdougm char *type; 222357b448deSdougm /* we can probably optimize this some */ 222457b448deSdougm type = sa_get_share_attr(share, "type"); 222557b448deSdougm if (type == NULL || strcmp(type, "transient") != 0) { 222657b448deSdougm sa_handle_impl_t impl_handle; 222757b448deSdougm impl_handle = 222857b448deSdougm (sa_handle_impl_t)sa_find_group_handle( 222957b448deSdougm group); 223057b448deSdougm if (impl_handle != NULL) { 223157b448deSdougm ret = sa_commit_share( 223257b448deSdougm impl_handle->scfhandle, group, 223357b448deSdougm share); 223457b448deSdougm } else { 223557b448deSdougm ret = SA_SYSTEM_ERR; 223657b448deSdougm } 223757b448deSdougm } 223857b448deSdougm if (type != NULL) 223957b448deSdougm sa_free_attr_string(type); 2240549ec3ffSdougm } 22416185db85Sdougm } 22426185db85Sdougm return (ret); 22436185db85Sdougm } 22446185db85Sdougm 22456185db85Sdougm /* 22466185db85Sdougm * sa_get_property_attr(prop, tag) 22476185db85Sdougm * 22486185db85Sdougm * Get the value of the specified property attribute. Standard 22496185db85Sdougm * attributes are "type" and "value". 22506185db85Sdougm */ 22516185db85Sdougm 22526185db85Sdougm char * 22536185db85Sdougm sa_get_property_attr(sa_property_t prop, char *tag) 22546185db85Sdougm { 22556185db85Sdougm return (get_node_attr((void *)prop, tag)); 22566185db85Sdougm } 22576185db85Sdougm 22586185db85Sdougm /* 22596185db85Sdougm * sa_get_optionset_attr(prop, tag) 22606185db85Sdougm * 22616185db85Sdougm * Get the value of the specified property attribute. Standard 22626185db85Sdougm * attribute is "type". 22636185db85Sdougm */ 22646185db85Sdougm 22656185db85Sdougm char * 22666185db85Sdougm sa_get_optionset_attr(sa_property_t optionset, char *tag) 22676185db85Sdougm { 22686185db85Sdougm return (get_node_attr((void *)optionset, tag)); 22696185db85Sdougm 22706185db85Sdougm } 22716185db85Sdougm 22726185db85Sdougm /* 22736185db85Sdougm * sa_set_optionset_attr(optionset, tag, value) 22746185db85Sdougm * 22756185db85Sdougm * Set the specified attribute(tag) to the specified value on the 22766185db85Sdougm * optionset. 22776185db85Sdougm */ 22786185db85Sdougm 22796185db85Sdougm void 22806185db85Sdougm sa_set_optionset_attr(sa_group_t optionset, char *tag, char *value) 22816185db85Sdougm { 22826185db85Sdougm set_node_attr((void *)optionset, tag, value); 22836185db85Sdougm } 22846185db85Sdougm 22856185db85Sdougm /* 22866185db85Sdougm * sa_free_attr_string(string) 22876185db85Sdougm * 22886185db85Sdougm * Free the string that was returned in one of the sa_get_*_attr() 22896185db85Sdougm * functions. 22906185db85Sdougm */ 22916185db85Sdougm 22926185db85Sdougm void 22936185db85Sdougm sa_free_attr_string(char *string) 22946185db85Sdougm { 22956185db85Sdougm xmlFree((xmlChar *)string); 22966185db85Sdougm } 22976185db85Sdougm 22986185db85Sdougm /* 22996185db85Sdougm * sa_get_optionset(group, proto) 23006185db85Sdougm * 23016185db85Sdougm * Return the optionset, if it exists, that is associated with the 23026185db85Sdougm * specified protocol. 23036185db85Sdougm */ 23046185db85Sdougm 23056185db85Sdougm sa_optionset_t 23066185db85Sdougm sa_get_optionset(void *group, char *proto) 23076185db85Sdougm { 23086185db85Sdougm xmlNodePtr node; 23096185db85Sdougm xmlChar *value = NULL; 23106185db85Sdougm 23116185db85Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 231257b448deSdougm node = node->next) { 23136185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 231457b448deSdougm value = xmlGetProp(node, (xmlChar *)"type"); 231557b448deSdougm if (proto != NULL) { 231657b448deSdougm if (value != NULL && 231757b448deSdougm xmlStrcmp(value, (xmlChar *)proto) == 0) { 231857b448deSdougm break; 231957b448deSdougm } 232057b448deSdougm if (value != NULL) { 232157b448deSdougm xmlFree(value); 232257b448deSdougm value = NULL; 232357b448deSdougm } 232457b448deSdougm } else { 232557b448deSdougm break; 23266185db85Sdougm } 23276185db85Sdougm } 23286185db85Sdougm } 23296185db85Sdougm if (value != NULL) 233057b448deSdougm xmlFree(value); 23316185db85Sdougm return ((sa_optionset_t)node); 23326185db85Sdougm } 23336185db85Sdougm 23346185db85Sdougm /* 23356185db85Sdougm * sa_get_next_optionset(optionset) 23366185db85Sdougm * 23376185db85Sdougm * Return the next optionset in the group. NULL if this was the last. 23386185db85Sdougm */ 23396185db85Sdougm 23406185db85Sdougm sa_optionset_t 23416185db85Sdougm sa_get_next_optionset(sa_optionset_t optionset) 23426185db85Sdougm { 23436185db85Sdougm xmlNodePtr node; 23446185db85Sdougm 23456185db85Sdougm for (node = ((xmlNodePtr)optionset)->next; node != NULL; 234657b448deSdougm node = node->next) { 23476185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"optionset") == 0) { 23486185db85Sdougm break; 23496185db85Sdougm } 23506185db85Sdougm } 23516185db85Sdougm return ((sa_optionset_t)node); 23526185db85Sdougm } 23536185db85Sdougm 23546185db85Sdougm /* 23556185db85Sdougm * sa_get_security(group, sectype, proto) 23566185db85Sdougm * 23576185db85Sdougm * Return the security optionset. The internal name is a hold over 23586185db85Sdougm * from the implementation and will be changed before the API is 23596185db85Sdougm * finalized. This is really a named optionset that can be negotiated 23606185db85Sdougm * as a group of properties (like NFS security options). 23616185db85Sdougm */ 23626185db85Sdougm 23636185db85Sdougm sa_security_t 23646185db85Sdougm sa_get_security(sa_group_t group, char *sectype, char *proto) 23656185db85Sdougm { 23666185db85Sdougm xmlNodePtr node; 23676185db85Sdougm xmlChar *value = NULL; 23686185db85Sdougm 23696185db85Sdougm for (node = ((xmlNodePtr)group)->children; node != NULL; 237057b448deSdougm node = node->next) { 237157b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 237257b448deSdougm if (proto != NULL) { 237357b448deSdougm value = xmlGetProp(node, (xmlChar *)"type"); 237457b448deSdougm if (value == NULL || 237557b448deSdougm (value != NULL && 237657b448deSdougm xmlStrcmp(value, (xmlChar *)proto) != 0)) { 237757b448deSdougm /* it doesn't match so continue */ 237857b448deSdougm xmlFree(value); 237957b448deSdougm value = NULL; 238057b448deSdougm continue; 238157b448deSdougm } 238257b448deSdougm } 238357b448deSdougm if (value != NULL) { 238457b448deSdougm xmlFree(value); 238557b448deSdougm value = NULL; 238657b448deSdougm } 238757b448deSdougm /* potential match */ 238857b448deSdougm if (sectype != NULL) { 238957b448deSdougm value = xmlGetProp(node, (xmlChar *)"sectype"); 239057b448deSdougm if (value != NULL && 239157b448deSdougm xmlStrcmp(value, (xmlChar *)sectype) == 0) { 239257b448deSdougm break; 239357b448deSdougm } 239457b448deSdougm } else { 239557b448deSdougm break; 239657b448deSdougm } 23976185db85Sdougm } 23986185db85Sdougm if (value != NULL) { 239957b448deSdougm xmlFree(value); 240057b448deSdougm value = NULL; 24016185db85Sdougm } 24026185db85Sdougm } 24036185db85Sdougm if (value != NULL) 240457b448deSdougm xmlFree(value); 24056185db85Sdougm return ((sa_security_t)node); 24066185db85Sdougm } 24076185db85Sdougm 24086185db85Sdougm /* 24096185db85Sdougm * sa_get_next_security(security) 24106185db85Sdougm * 24116185db85Sdougm * Get the next security optionset if one exists. 24126185db85Sdougm */ 24136185db85Sdougm 24146185db85Sdougm sa_security_t 24156185db85Sdougm sa_get_next_security(sa_security_t security) 24166185db85Sdougm { 24176185db85Sdougm xmlNodePtr node; 24186185db85Sdougm 24196185db85Sdougm for (node = ((xmlNodePtr)security)->next; node != NULL; 242057b448deSdougm node = node->next) { 24216185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"security") == 0) { 24226185db85Sdougm break; 24236185db85Sdougm } 24246185db85Sdougm } 24256185db85Sdougm return ((sa_security_t)node); 24266185db85Sdougm } 24276185db85Sdougm 24286185db85Sdougm /* 24296185db85Sdougm * sa_get_property(optionset, prop) 24306185db85Sdougm * 24316185db85Sdougm * Get the property object with the name specified in prop from the 24326185db85Sdougm * optionset. 24336185db85Sdougm */ 24346185db85Sdougm 24356185db85Sdougm sa_property_t 24366185db85Sdougm sa_get_property(sa_optionset_t optionset, char *prop) 24376185db85Sdougm { 24386185db85Sdougm xmlNodePtr node = (xmlNodePtr)optionset; 24396185db85Sdougm xmlChar *value = NULL; 24406185db85Sdougm 24416185db85Sdougm if (optionset == NULL) 244257b448deSdougm return (NULL); 24436185db85Sdougm 24446185db85Sdougm for (node = node->children; node != NULL; 244557b448deSdougm node = node->next) { 244657b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 244757b448deSdougm if (prop == NULL) 244857b448deSdougm break; 244957b448deSdougm value = xmlGetProp(node, (xmlChar *)"type"); 245057b448deSdougm if (value != NULL && 245157b448deSdougm xmlStrcmp(value, (xmlChar *)prop) == 0) { 245257b448deSdougm break; 245357b448deSdougm } 245457b448deSdougm if (value != NULL) { 245557b448deSdougm xmlFree(value); 245657b448deSdougm value = NULL; 245757b448deSdougm } 24586185db85Sdougm } 24596185db85Sdougm } 24606185db85Sdougm if (value != NULL) 24616185db85Sdougm xmlFree(value); 24626185db85Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 246357b448deSdougm /* 246457b448deSdougm * avoid a non option node -- it is possible to be a 246557b448deSdougm * text node 246657b448deSdougm */ 246757b448deSdougm node = NULL; 24686185db85Sdougm } 24696185db85Sdougm return ((sa_property_t)node); 24706185db85Sdougm } 24716185db85Sdougm 24726185db85Sdougm /* 24736185db85Sdougm * sa_get_next_property(property) 24746185db85Sdougm * 24756185db85Sdougm * Get the next property following the specified property. NULL if 24766185db85Sdougm * this was the last. 24776185db85Sdougm */ 24786185db85Sdougm 24796185db85Sdougm sa_property_t 24806185db85Sdougm sa_get_next_property(sa_property_t property) 24816185db85Sdougm { 24826185db85Sdougm xmlNodePtr node; 24836185db85Sdougm 24846185db85Sdougm for (node = ((xmlNodePtr)property)->next; node != NULL; 248557b448deSdougm node = node->next) { 24866185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 24876185db85Sdougm break; 24886185db85Sdougm } 24896185db85Sdougm } 24906185db85Sdougm return ((sa_property_t)node); 24916185db85Sdougm } 24926185db85Sdougm 24936185db85Sdougm /* 24946185db85Sdougm * sa_set_share_description(share, content) 24956185db85Sdougm * 24966185db85Sdougm * Set the description of share to content. 24976185db85Sdougm */ 24986185db85Sdougm 24996185db85Sdougm int 25006185db85Sdougm sa_set_share_description(sa_share_t share, char *content) 25016185db85Sdougm { 25026185db85Sdougm xmlNodePtr node; 25036185db85Sdougm sa_group_t group; 25046185db85Sdougm int ret = SA_OK; 25056185db85Sdougm 25066185db85Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 250757b448deSdougm node = node->next) { 25086185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 25096185db85Sdougm break; 25106185db85Sdougm } 25116185db85Sdougm } 25126185db85Sdougm /* no existing description but want to add */ 25136185db85Sdougm if (node == NULL && content != NULL) { 25146185db85Sdougm /* add a description */ 251557b448deSdougm node = _sa_set_share_description(share, content); 25166185db85Sdougm } else if (node != NULL && content != NULL) { 25176185db85Sdougm /* update a description */ 25186185db85Sdougm xmlNodeSetContent(node, (xmlChar *)content); 25196185db85Sdougm } else if (node != NULL && content == NULL) { 25206185db85Sdougm /* remove an existing description */ 25216185db85Sdougm xmlUnlinkNode(node); 25226185db85Sdougm xmlFreeNode(node); 25236185db85Sdougm } 2524da6c28aaSamw group = sa_get_parent_group(share); 2525*148c5f43SAlan Wright if (group != NULL && 2526*148c5f43SAlan Wright sa_is_persistent(share) && (!sa_group_is_zfs(group))) { 252757b448deSdougm sa_handle_impl_t impl_handle; 252857b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 252957b448deSdougm if (impl_handle != NULL) { 253057b448deSdougm ret = sa_commit_share(impl_handle->scfhandle, group, 253157b448deSdougm share); 253257b448deSdougm } else { 253357b448deSdougm ret = SA_SYSTEM_ERR; 253457b448deSdougm } 2535549ec3ffSdougm } 25366185db85Sdougm return (ret); 25376185db85Sdougm } 25386185db85Sdougm 25396185db85Sdougm /* 25406185db85Sdougm * fixproblemchars(string) 25416185db85Sdougm * 25426185db85Sdougm * don't want any newline or tab characters in the text since these 25436185db85Sdougm * could break display of data and legacy file formats. 25446185db85Sdougm */ 25456185db85Sdougm static void 25466185db85Sdougm fixproblemchars(char *str) 25476185db85Sdougm { 25486185db85Sdougm int c; 25496185db85Sdougm for (c = *str; c != '\0'; c = *++str) { 255057b448deSdougm if (c == '\t' || c == '\n') 255157b448deSdougm *str = ' '; 255257b448deSdougm else if (c == '"') 255357b448deSdougm *str = '\''; 25546185db85Sdougm } 25556185db85Sdougm } 25566185db85Sdougm 25576185db85Sdougm /* 25586185db85Sdougm * sa_get_share_description(share) 25596185db85Sdougm * 25606185db85Sdougm * Return the description text for the specified share if it 25616185db85Sdougm * exists. NULL if no description exists. 25626185db85Sdougm */ 25636185db85Sdougm 25646185db85Sdougm char * 25656185db85Sdougm sa_get_share_description(sa_share_t share) 25666185db85Sdougm { 25676185db85Sdougm xmlChar *description = NULL; 25686185db85Sdougm xmlNodePtr node; 25696185db85Sdougm 25706185db85Sdougm for (node = ((xmlNodePtr)share)->children; node != NULL; 257157b448deSdougm node = node->next) { 257257b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 257357b448deSdougm break; 257457b448deSdougm } 25756185db85Sdougm } 25766185db85Sdougm if (node != NULL) { 2577da6c28aaSamw description = xmlNodeGetContent(node); 257857b448deSdougm fixproblemchars((char *)description); 25796185db85Sdougm } 25806185db85Sdougm return ((char *)description); 25816185db85Sdougm } 25826185db85Sdougm 25836185db85Sdougm /* 25846185db85Sdougm * sa_free(share_description(description) 25856185db85Sdougm * 25866185db85Sdougm * Free the description string. 25876185db85Sdougm */ 25886185db85Sdougm 25896185db85Sdougm void 25906185db85Sdougm sa_free_share_description(char *description) 25916185db85Sdougm { 25926185db85Sdougm xmlFree((xmlChar *)description); 25936185db85Sdougm } 25946185db85Sdougm 25956185db85Sdougm /* 25966185db85Sdougm * sa_create_optionset(group, proto) 25976185db85Sdougm * 25986185db85Sdougm * Create an optionset for the specified protocol in the specied 25996185db85Sdougm * group. This is manifested as a property group within SMF. 26006185db85Sdougm */ 26016185db85Sdougm 26026185db85Sdougm sa_optionset_t 26036185db85Sdougm sa_create_optionset(sa_group_t group, char *proto) 26046185db85Sdougm { 26056185db85Sdougm sa_optionset_t optionset; 26066185db85Sdougm sa_group_t parent = group; 2607da6c28aaSamw sa_share_t share = NULL; 2608da6c28aaSamw int err = SA_OK; 2609da6c28aaSamw char *id = NULL; 26106185db85Sdougm 26116185db85Sdougm optionset = sa_get_optionset(group, proto); 26126185db85Sdougm if (optionset != NULL) { 26136185db85Sdougm /* can't have a duplicate protocol */ 261457b448deSdougm optionset = NULL; 26156185db85Sdougm } else { 2616da6c28aaSamw /* 2617da6c28aaSamw * Account for resource names being slightly 2618da6c28aaSamw * different. 2619da6c28aaSamw */ 2620da6c28aaSamw if (sa_is_share(group)) { 2621da6c28aaSamw /* 2622da6c28aaSamw * Transient shares do not have an "id" so not an 2623da6c28aaSamw * error to not find one. 2624da6c28aaSamw */ 2625da6c28aaSamw id = sa_get_share_attr((sa_share_t)group, "id"); 2626da6c28aaSamw } else if (sa_is_resource(group)) { 2627da6c28aaSamw share = sa_get_resource_parent( 2628da6c28aaSamw (sa_resource_t)group); 2629da6c28aaSamw id = sa_get_resource_attr(share, "id"); 2630da6c28aaSamw 2631da6c28aaSamw /* id can be NULL if the group is transient (ZFS) */ 2632da6c28aaSamw if (id == NULL && sa_is_persistent(group)) 2633da6c28aaSamw err = SA_NO_MEMORY; 2634da6c28aaSamw } 2635da6c28aaSamw if (err == SA_NO_MEMORY) { 2636da6c28aaSamw /* 2637da6c28aaSamw * Couldn't get the id for the share or 2638da6c28aaSamw * resource. While this could be a 2639da6c28aaSamw * configuration issue, it is most likely an 2640da6c28aaSamw * out of memory. In any case, fail the create. 2641da6c28aaSamw */ 2642da6c28aaSamw return (NULL); 2643da6c28aaSamw } 2644da6c28aaSamw 264557b448deSdougm optionset = (sa_optionset_t)xmlNewChild((xmlNodePtr)group, 264657b448deSdougm NULL, (xmlChar *)"optionset", NULL); 26476185db85Sdougm /* 26486185db85Sdougm * only put to repository if on a group and we were 26496185db85Sdougm * able to create an optionset. 26506185db85Sdougm */ 265157b448deSdougm if (optionset != NULL) { 265257b448deSdougm char oname[SA_STRSIZE]; 265357b448deSdougm char *groupname; 26546185db85Sdougm 2655da6c28aaSamw /* 2656da6c28aaSamw * Need to get parent group in all cases, but also get 2657da6c28aaSamw * the share if this is a resource. 2658da6c28aaSamw */ 2659da6c28aaSamw if (sa_is_share(group)) { 266057b448deSdougm parent = sa_get_parent_group((sa_share_t)group); 2661da6c28aaSamw } else if (sa_is_resource(group)) { 2662da6c28aaSamw share = sa_get_resource_parent( 2663da6c28aaSamw (sa_resource_t)group); 2664da6c28aaSamw parent = sa_get_parent_group(share); 2665da6c28aaSamw } 26666185db85Sdougm 266757b448deSdougm sa_set_optionset_attr(optionset, "type", proto); 26686185db85Sdougm 266957b448deSdougm (void) sa_optionset_name(optionset, oname, 267057b448deSdougm sizeof (oname), id); 267157b448deSdougm groupname = sa_get_group_attr(parent, "name"); 2672da6c28aaSamw if (groupname != NULL && sa_is_persistent(group)) { 267357b448deSdougm sa_handle_impl_t impl_handle; 2674da6c28aaSamw impl_handle = 2675da6c28aaSamw (sa_handle_impl_t)sa_find_group_handle( 2676da6c28aaSamw group); 267757b448deSdougm assert(impl_handle != NULL); 267857b448deSdougm if (impl_handle != NULL) { 267957b448deSdougm (void) sa_get_instance( 2680da6c28aaSamw impl_handle->scfhandle, groupname); 268157b448deSdougm (void) sa_create_pgroup( 268257b448deSdougm impl_handle->scfhandle, oname); 268357b448deSdougm } 268457b448deSdougm } 268557b448deSdougm if (groupname != NULL) 268657b448deSdougm sa_free_attr_string(groupname); 26876185db85Sdougm } 26886185db85Sdougm } 2689da6c28aaSamw 2690da6c28aaSamw if (id != NULL) 2691da6c28aaSamw sa_free_attr_string(id); 26926185db85Sdougm return (optionset); 26936185db85Sdougm } 26946185db85Sdougm 26956185db85Sdougm /* 26966185db85Sdougm * sa_get_property_parent(property) 26976185db85Sdougm * 26986185db85Sdougm * Given a property, return the object it is a property of. This will 26996185db85Sdougm * be an optionset of some type. 27006185db85Sdougm */ 27016185db85Sdougm 27026185db85Sdougm static sa_optionset_t 27036185db85Sdougm sa_get_property_parent(sa_property_t property) 27046185db85Sdougm { 27056185db85Sdougm xmlNodePtr node = NULL; 27066185db85Sdougm 270757b448deSdougm if (property != NULL) 270857b448deSdougm node = ((xmlNodePtr)property)->parent; 27096185db85Sdougm return ((sa_optionset_t)node); 27106185db85Sdougm } 27116185db85Sdougm 27126185db85Sdougm /* 27136185db85Sdougm * sa_get_optionset_parent(optionset) 27146185db85Sdougm * 27156185db85Sdougm * Return the parent of the specified optionset. This could be a group 27166185db85Sdougm * or a share. 27176185db85Sdougm */ 27186185db85Sdougm 27196185db85Sdougm static sa_group_t 27206185db85Sdougm sa_get_optionset_parent(sa_optionset_t optionset) 27216185db85Sdougm { 27226185db85Sdougm xmlNodePtr node = NULL; 27236185db85Sdougm 272457b448deSdougm if (optionset != NULL) 272557b448deSdougm node = ((xmlNodePtr)optionset)->parent; 27266185db85Sdougm return ((sa_group_t)node); 27276185db85Sdougm } 27286185db85Sdougm 27296185db85Sdougm /* 27306185db85Sdougm * zfs_needs_update(share) 27316185db85Sdougm * 27326185db85Sdougm * In order to avoid making multiple updates to a ZFS share when 27336185db85Sdougm * setting properties, the share attribute "changed" will be set to 2734da6c28aaSamw * true when a property is added or modified. When done adding 27356185db85Sdougm * properties, we can then detect that an update is needed. We then 27366185db85Sdougm * clear the state here to detect additional changes. 27376185db85Sdougm */ 27386185db85Sdougm 27396185db85Sdougm static int 27406185db85Sdougm zfs_needs_update(sa_share_t share) 27416185db85Sdougm { 27426185db85Sdougm char *attr; 27436185db85Sdougm int result = 0; 27446185db85Sdougm 27456185db85Sdougm attr = sa_get_share_attr(share, "changed"); 27466185db85Sdougm if (attr != NULL) { 274757b448deSdougm sa_free_attr_string(attr); 27486185db85Sdougm result = 1; 27496185db85Sdougm } 27506185db85Sdougm set_node_attr((void *)share, "changed", NULL); 27516185db85Sdougm return (result); 27526185db85Sdougm } 27536185db85Sdougm 27546185db85Sdougm /* 27556185db85Sdougm * zfs_set_update(share) 27566185db85Sdougm * 27576185db85Sdougm * Set the changed attribute of the share to true. 27586185db85Sdougm */ 27596185db85Sdougm 27606185db85Sdougm static void 27616185db85Sdougm zfs_set_update(sa_share_t share) 27626185db85Sdougm { 27636185db85Sdougm set_node_attr((void *)share, "changed", "true"); 27646185db85Sdougm } 27656185db85Sdougm 27666185db85Sdougm /* 27676185db85Sdougm * sa_commit_properties(optionset, clear) 27686185db85Sdougm * 27696185db85Sdougm * Check if SMF or ZFS config and either update or abort the pending 27706185db85Sdougm * changes. 27716185db85Sdougm */ 27726185db85Sdougm 27736185db85Sdougm int 27746185db85Sdougm sa_commit_properties(sa_optionset_t optionset, int clear) 27756185db85Sdougm { 27766185db85Sdougm sa_group_t group; 27776185db85Sdougm sa_group_t parent; 27786185db85Sdougm int zfs = 0; 27796185db85Sdougm int needsupdate = 0; 27806185db85Sdougm int ret = SA_OK; 2781549ec3ffSdougm sa_handle_impl_t impl_handle; 27826185db85Sdougm 27836185db85Sdougm group = sa_get_optionset_parent(optionset); 27846185db85Sdougm if (group != NULL && (sa_is_share(group) || is_zfs_group(group))) { 278557b448deSdougm /* only update ZFS if on a share */ 278657b448deSdougm parent = sa_get_parent_group(group); 278757b448deSdougm zfs++; 278857b448deSdougm if (parent != NULL && is_zfs_group(parent)) 278957b448deSdougm needsupdate = zfs_needs_update(group); 279057b448deSdougm else 279157b448deSdougm zfs = 0; 27926185db85Sdougm } 27936185db85Sdougm if (zfs) { 279457b448deSdougm if (!clear && needsupdate) 279557b448deSdougm ret = sa_zfs_update((sa_share_t)group); 27966185db85Sdougm } else { 279757b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 279857b448deSdougm if (impl_handle != NULL) { 279957b448deSdougm if (clear) { 280057b448deSdougm (void) sa_abort_transaction( 280157b448deSdougm impl_handle->scfhandle); 280257b448deSdougm } else { 280357b448deSdougm ret = sa_end_transaction( 28045b6e0c46Sdougm impl_handle->scfhandle, impl_handle); 280557b448deSdougm } 280657b448deSdougm } else { 280757b448deSdougm ret = SA_SYSTEM_ERR; 280857b448deSdougm } 28096185db85Sdougm } 28106185db85Sdougm return (ret); 28116185db85Sdougm } 28126185db85Sdougm 28136185db85Sdougm /* 28146185db85Sdougm * sa_destroy_optionset(optionset) 28156185db85Sdougm * 2816da6c28aaSamw * Remove the optionset from its group. Update the repository to 28176185db85Sdougm * reflect this change. 28186185db85Sdougm */ 28196185db85Sdougm 28206185db85Sdougm int 28216185db85Sdougm sa_destroy_optionset(sa_optionset_t optionset) 28226185db85Sdougm { 282357b448deSdougm char name[SA_STRSIZE]; 28246185db85Sdougm int len; 28256185db85Sdougm int ret; 28266185db85Sdougm char *id = NULL; 28276185db85Sdougm sa_group_t group; 28286185db85Sdougm int ispersist = 1; 28296185db85Sdougm 28306185db85Sdougm /* now delete the prop group */ 28316185db85Sdougm group = sa_get_optionset_parent(optionset); 2832da6c28aaSamw if (group != NULL) { 2833da6c28aaSamw if (sa_is_resource(group)) { 2834da6c28aaSamw sa_resource_t resource = group; 2835da6c28aaSamw sa_share_t share = sa_get_resource_parent(resource); 2836da6c28aaSamw group = sa_get_parent_group(share); 2837da6c28aaSamw id = sa_get_share_attr(share, "id"); 2838da6c28aaSamw } else if (sa_is_share(group)) { 2839da6c28aaSamw id = sa_get_share_attr((sa_share_t)group, "id"); 2840da6c28aaSamw } 2841da6c28aaSamw ispersist = sa_is_persistent(group); 28426185db85Sdougm } 28436185db85Sdougm if (ispersist) { 284457b448deSdougm sa_handle_impl_t impl_handle; 284557b448deSdougm len = sa_optionset_name(optionset, name, sizeof (name), id); 284657b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 284757b448deSdougm if (impl_handle != NULL) { 284857b448deSdougm if (len > 0) { 284957b448deSdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 285057b448deSdougm name); 285157b448deSdougm } 285257b448deSdougm } else { 285357b448deSdougm ret = SA_SYSTEM_ERR; 2854549ec3ffSdougm } 28556185db85Sdougm } 28566185db85Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28576185db85Sdougm xmlFreeNode((xmlNodePtr)optionset); 28586185db85Sdougm if (id != NULL) 285957b448deSdougm sa_free_attr_string(id); 28606185db85Sdougm return (ret); 28616185db85Sdougm } 28626185db85Sdougm 28636185db85Sdougm /* private to the implementation */ 28646185db85Sdougm int 28656185db85Sdougm _sa_remove_optionset(sa_optionset_t optionset) 28666185db85Sdougm { 28676185db85Sdougm int ret = SA_OK; 28686185db85Sdougm 28696185db85Sdougm xmlUnlinkNode((xmlNodePtr)optionset); 28706185db85Sdougm xmlFreeNode((xmlNodePtr)optionset); 28716185db85Sdougm return (ret); 28726185db85Sdougm } 28736185db85Sdougm 28746185db85Sdougm /* 28756185db85Sdougm * sa_create_security(group, sectype, proto) 28766185db85Sdougm * 28776185db85Sdougm * Create a security optionset (one that has a type name and a 28786185db85Sdougm * proto). Security is left over from a pure NFS implementation. The 28796185db85Sdougm * naming will change in the future when the API is released. 28806185db85Sdougm */ 28816185db85Sdougm sa_security_t 28826185db85Sdougm sa_create_security(sa_group_t group, char *sectype, char *proto) 28836185db85Sdougm { 28846185db85Sdougm sa_security_t security; 28856185db85Sdougm char *id = NULL; 28866185db85Sdougm sa_group_t parent; 28876185db85Sdougm char *groupname = NULL; 28886185db85Sdougm 28896185db85Sdougm if (group != NULL && sa_is_share(group)) { 289057b448deSdougm id = sa_get_share_attr((sa_share_t)group, "id"); 289157b448deSdougm parent = sa_get_parent_group(group); 289257b448deSdougm if (parent != NULL) 289357b448deSdougm groupname = sa_get_group_attr(parent, "name"); 28946185db85Sdougm } else if (group != NULL) { 289557b448deSdougm groupname = sa_get_group_attr(group, "name"); 28966185db85Sdougm } 28976185db85Sdougm 28986185db85Sdougm security = sa_get_security(group, sectype, proto); 28996185db85Sdougm if (security != NULL) { 29006185db85Sdougm /* can't have a duplicate security option */ 29016185db85Sdougm security = NULL; 29026185db85Sdougm } else { 29036185db85Sdougm security = (sa_security_t)xmlNewChild((xmlNodePtr)group, 290457b448deSdougm NULL, (xmlChar *)"security", NULL); 29056185db85Sdougm if (security != NULL) { 290657b448deSdougm char oname[SA_STRSIZE]; 29076185db85Sdougm sa_set_security_attr(security, "type", proto); 29086185db85Sdougm 29096185db85Sdougm sa_set_security_attr(security, "sectype", sectype); 29106185db85Sdougm (void) sa_security_name(security, oname, 291157b448deSdougm sizeof (oname), id); 2912da6c28aaSamw if (groupname != NULL && sa_is_persistent(group)) { 291357b448deSdougm sa_handle_impl_t impl_handle; 291457b448deSdougm impl_handle = 291557b448deSdougm (sa_handle_impl_t)sa_find_group_handle( 291657b448deSdougm group); 291757b448deSdougm if (impl_handle != NULL) { 291857b448deSdougm (void) sa_get_instance( 291957b448deSdougm impl_handle->scfhandle, groupname); 292057b448deSdougm (void) sa_create_pgroup( 292157b448deSdougm impl_handle->scfhandle, oname); 292257b448deSdougm } 29236185db85Sdougm } 29246185db85Sdougm } 29256185db85Sdougm } 2926fe1c642dSBill Krier if (id != NULL) 2927fe1c642dSBill Krier sa_free_attr_string(id); 29286185db85Sdougm if (groupname != NULL) 292957b448deSdougm sa_free_attr_string(groupname); 29306185db85Sdougm return (security); 29316185db85Sdougm } 29326185db85Sdougm 29336185db85Sdougm /* 29346185db85Sdougm * sa_destroy_security(security) 29356185db85Sdougm * 29366185db85Sdougm * Remove the specified optionset from the document and the 29376185db85Sdougm * configuration. 29386185db85Sdougm */ 29396185db85Sdougm 29406185db85Sdougm int 29416185db85Sdougm sa_destroy_security(sa_security_t security) 29426185db85Sdougm { 294357b448deSdougm char name[SA_STRSIZE]; 29446185db85Sdougm int len; 29456185db85Sdougm int ret = SA_OK; 29466185db85Sdougm char *id = NULL; 29476185db85Sdougm sa_group_t group; 29486185db85Sdougm int iszfs = 0; 29496185db85Sdougm int ispersist = 1; 29506185db85Sdougm 29516185db85Sdougm group = sa_get_optionset_parent(security); 29526185db85Sdougm 29536185db85Sdougm if (group != NULL) 295457b448deSdougm iszfs = sa_group_is_zfs(group); 29556185db85Sdougm 29566185db85Sdougm if (group != NULL && !iszfs) { 295757b448deSdougm if (sa_is_share(group)) 2958da6c28aaSamw ispersist = sa_is_persistent(group); 295957b448deSdougm id = sa_get_share_attr((sa_share_t)group, "id"); 29606185db85Sdougm } 29616185db85Sdougm if (ispersist) { 296257b448deSdougm len = sa_security_name(security, name, sizeof (name), id); 296357b448deSdougm if (!iszfs && len > 0) { 296457b448deSdougm sa_handle_impl_t impl_handle; 296557b448deSdougm impl_handle = 296657b448deSdougm (sa_handle_impl_t)sa_find_group_handle(group); 296757b448deSdougm if (impl_handle != NULL) { 296857b448deSdougm ret = sa_delete_pgroup(impl_handle->scfhandle, 296957b448deSdougm name); 297057b448deSdougm } else { 297157b448deSdougm ret = SA_SYSTEM_ERR; 297257b448deSdougm } 2973549ec3ffSdougm } 29746185db85Sdougm } 29756185db85Sdougm xmlUnlinkNode((xmlNodePtr)security); 29766185db85Sdougm xmlFreeNode((xmlNodePtr)security); 297757b448deSdougm if (iszfs) 297857b448deSdougm ret = sa_zfs_update(group); 29796185db85Sdougm if (id != NULL) 298057b448deSdougm sa_free_attr_string(id); 29816185db85Sdougm return (ret); 29826185db85Sdougm } 29836185db85Sdougm 29846185db85Sdougm /* 29856185db85Sdougm * sa_get_security_attr(optionset, tag) 29866185db85Sdougm * 29876185db85Sdougm * Return the specified attribute value from the optionset. 29886185db85Sdougm */ 29896185db85Sdougm 29906185db85Sdougm char * 29916185db85Sdougm sa_get_security_attr(sa_property_t optionset, char *tag) 29926185db85Sdougm { 29936185db85Sdougm return (get_node_attr((void *)optionset, tag)); 29946185db85Sdougm 29956185db85Sdougm } 29966185db85Sdougm 29976185db85Sdougm /* 29986185db85Sdougm * sa_set_security_attr(optionset, tag, value) 29996185db85Sdougm * 30006185db85Sdougm * Set the optioset attribute specied by tag to the specified value. 30016185db85Sdougm */ 30026185db85Sdougm 30036185db85Sdougm void 30046185db85Sdougm sa_set_security_attr(sa_group_t optionset, char *tag, char *value) 30056185db85Sdougm { 30066185db85Sdougm set_node_attr((void *)optionset, tag, value); 30076185db85Sdougm } 30086185db85Sdougm 30096185db85Sdougm /* 30106185db85Sdougm * is_nodetype(node, type) 30116185db85Sdougm * 30126185db85Sdougm * Check to see if node is of the type specified. 30136185db85Sdougm */ 30146185db85Sdougm 30156185db85Sdougm static int 30166185db85Sdougm is_nodetype(void *node, char *type) 30176185db85Sdougm { 30186185db85Sdougm return (strcmp((char *)((xmlNodePtr)node)->name, type) == 0); 30196185db85Sdougm } 30206185db85Sdougm 302157b448deSdougm /* 302257b448deSdougm * add_or_update() 302357b448deSdougm * 302457b448deSdougm * Add or update a property. Pulled out of sa_set_prop_by_prop for 302557b448deSdougm * readability. 302657b448deSdougm */ 302757b448deSdougm static int 302857b448deSdougm add_or_update(scfutilhandle_t *scf_handle, int type, scf_value_t *value, 302957b448deSdougm scf_transaction_entry_t *entry, char *name, char *valstr) 303057b448deSdougm { 303157b448deSdougm int ret = SA_SYSTEM_ERR; 303257b448deSdougm 303357b448deSdougm if (value != NULL) { 303457b448deSdougm if (type == SA_PROP_OP_ADD) 303557b448deSdougm ret = scf_transaction_property_new(scf_handle->trans, 303657b448deSdougm entry, name, SCF_TYPE_ASTRING); 303757b448deSdougm else 303857b448deSdougm ret = scf_transaction_property_change(scf_handle->trans, 303957b448deSdougm entry, name, SCF_TYPE_ASTRING); 304057b448deSdougm if (ret == 0) { 304157b448deSdougm ret = scf_value_set_astring(value, valstr); 304257b448deSdougm if (ret == 0) 304357b448deSdougm ret = scf_entry_add_value(entry, value); 304457b448deSdougm if (ret == 0) 304557b448deSdougm return (ret); 304657b448deSdougm scf_value_destroy(value); 304757b448deSdougm } else { 304857b448deSdougm scf_entry_destroy(entry); 304957b448deSdougm } 305057b448deSdougm } 305157b448deSdougm return (SA_SYSTEM_ERR); 305257b448deSdougm } 305357b448deSdougm 30546185db85Sdougm /* 30556185db85Sdougm * sa_set_prop_by_prop(optionset, group, prop, type) 30566185db85Sdougm * 30576185db85Sdougm * Add/remove/update the specified property prop into the optionset or 30586185db85Sdougm * share. If a share, sort out which property group based on GUID. In 30596185db85Sdougm * all cases, the appropriate transaction is set (or ZFS share is 30606185db85Sdougm * marked as needing an update) 30616185db85Sdougm */ 30626185db85Sdougm 30636185db85Sdougm static int 30646185db85Sdougm sa_set_prop_by_prop(sa_optionset_t optionset, sa_group_t group, 30656185db85Sdougm sa_property_t prop, int type) 30666185db85Sdougm { 30676185db85Sdougm char *name; 30686185db85Sdougm char *valstr; 30696185db85Sdougm int ret = SA_OK; 30706185db85Sdougm scf_transaction_entry_t *entry; 30716185db85Sdougm scf_value_t *value; 30726185db85Sdougm int opttype; /* 1 == optionset, 0 == security */ 30736185db85Sdougm char *id = NULL; 30746185db85Sdougm int iszfs = 0; 30756185db85Sdougm sa_group_t parent = NULL; 3076da6c28aaSamw sa_share_t share = NULL; 3077549ec3ffSdougm sa_handle_impl_t impl_handle; 3078549ec3ffSdougm scfutilhandle_t *scf_handle; 30796185db85Sdougm 3080da6c28aaSamw if (!sa_is_persistent(group)) { 30816185db85Sdougm /* 30826185db85Sdougm * if the group/share is not persistent we don't need 30836185db85Sdougm * to do anything here 30846185db85Sdougm */ 308557b448deSdougm return (SA_OK); 30866185db85Sdougm } 3087549ec3ffSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 308857b448deSdougm if (impl_handle == NULL || impl_handle->scfhandle == NULL) 308957b448deSdougm return (SA_SYSTEM_ERR); 3090549ec3ffSdougm scf_handle = impl_handle->scfhandle; 30916185db85Sdougm name = sa_get_property_attr(prop, "type"); 30926185db85Sdougm valstr = sa_get_property_attr(prop, "value"); 30936185db85Sdougm entry = scf_entry_create(scf_handle->handle); 30946185db85Sdougm opttype = is_nodetype((void *)optionset, "optionset"); 30956185db85Sdougm 3096da6c28aaSamw /* 3097da6c28aaSamw * Check for share vs. resource since they need slightly 3098da6c28aaSamw * different treatment given the hierarchy. 3099da6c28aaSamw */ 31006185db85Sdougm if (valstr != NULL && entry != NULL) { 310157b448deSdougm if (sa_is_share(group)) { 310257b448deSdougm parent = sa_get_parent_group(group); 3103da6c28aaSamw share = (sa_share_t)group; 310457b448deSdougm if (parent != NULL) 310557b448deSdougm iszfs = is_zfs_group(parent); 3106da6c28aaSamw } else if (sa_is_resource(group)) { 3107da6c28aaSamw share = sa_get_parent_group(group); 3108da6c28aaSamw if (share != NULL) 3109da6c28aaSamw parent = sa_get_parent_group(share); 311057b448deSdougm } else { 311157b448deSdougm iszfs = is_zfs_group(group); 31126185db85Sdougm } 311357b448deSdougm if (!iszfs) { 311457b448deSdougm if (scf_handle->trans == NULL) { 311557b448deSdougm char oname[SA_STRSIZE]; 311657b448deSdougm char *groupname = NULL; 3117da6c28aaSamw if (share != NULL) { 3118da6c28aaSamw if (parent != NULL) 311957b448deSdougm groupname = 312057b448deSdougm sa_get_group_attr(parent, 312157b448deSdougm "name"); 3122da6c28aaSamw id = sa_get_share_attr( 3123da6c28aaSamw (sa_share_t)share, "id"); 3124549ec3ffSdougm } else { 312557b448deSdougm groupname = sa_get_group_attr(group, 312657b448deSdougm "name"); 31276185db85Sdougm } 312857b448deSdougm if (groupname != NULL) { 312957b448deSdougm ret = sa_get_instance(scf_handle, 313057b448deSdougm groupname); 313157b448deSdougm sa_free_attr_string(groupname); 313257b448deSdougm } 313357b448deSdougm if (opttype) 313457b448deSdougm (void) sa_optionset_name(optionset, 313557b448deSdougm oname, sizeof (oname), id); 313657b448deSdougm else 313757b448deSdougm (void) sa_security_name(optionset, 313857b448deSdougm oname, sizeof (oname), id); 313957b448deSdougm ret = sa_start_transaction(scf_handle, oname); 3140fe1c642dSBill Krier if (id != NULL) 3141fe1c642dSBill Krier sa_free_attr_string(id); 31426185db85Sdougm } 314357b448deSdougm if (ret == SA_OK) { 314457b448deSdougm switch (type) { 314557b448deSdougm case SA_PROP_OP_REMOVE: 314657b448deSdougm ret = scf_transaction_property_delete( 314757b448deSdougm scf_handle->trans, entry, name); 314857b448deSdougm break; 314957b448deSdougm case SA_PROP_OP_ADD: 315057b448deSdougm case SA_PROP_OP_UPDATE: 315157b448deSdougm value = scf_value_create( 315257b448deSdougm scf_handle->handle); 315357b448deSdougm ret = add_or_update(scf_handle, type, 315457b448deSdougm value, entry, name, valstr); 315557b448deSdougm break; 315657b448deSdougm } 315757b448deSdougm } 315857b448deSdougm } else { 315957b448deSdougm /* 316057b448deSdougm * ZFS update. The calling function would have updated 316157b448deSdougm * the internal XML structure. Just need to flag it as 316257b448deSdougm * changed for ZFS. 316357b448deSdougm */ 316457b448deSdougm zfs_set_update((sa_share_t)group); 316557b448deSdougm } 31666185db85Sdougm } 31676185db85Sdougm 31686185db85Sdougm if (name != NULL) 316957b448deSdougm sa_free_attr_string(name); 31706185db85Sdougm if (valstr != NULL) 317157b448deSdougm sa_free_attr_string(valstr); 31726185db85Sdougm else if (entry != NULL) 317357b448deSdougm scf_entry_destroy(entry); 31746185db85Sdougm 31756185db85Sdougm if (ret == -1) 317657b448deSdougm ret = SA_SYSTEM_ERR; 31776185db85Sdougm 31786185db85Sdougm return (ret); 31796185db85Sdougm } 31806185db85Sdougm 31816185db85Sdougm /* 31824bff34e3Sthurlow * sa_create_section(name, value) 31834bff34e3Sthurlow * 31844bff34e3Sthurlow * Create a new section with the specified name and extra data. 31854bff34e3Sthurlow */ 31864bff34e3Sthurlow 31874bff34e3Sthurlow sa_property_t 31884bff34e3Sthurlow sa_create_section(char *name, char *extra) 31894bff34e3Sthurlow { 31904bff34e3Sthurlow xmlNodePtr node; 31914bff34e3Sthurlow 31924bff34e3Sthurlow node = xmlNewNode(NULL, (xmlChar *)"section"); 31934bff34e3Sthurlow if (node != NULL) { 31944bff34e3Sthurlow if (name != NULL) 31954bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 31964bff34e3Sthurlow (xmlChar *)name); 31974bff34e3Sthurlow if (extra != NULL) 31984bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"extra", 31994bff34e3Sthurlow (xmlChar *)extra); 32004bff34e3Sthurlow } 32014bff34e3Sthurlow return ((sa_property_t)node); 32024bff34e3Sthurlow } 32034bff34e3Sthurlow 32044bff34e3Sthurlow void 32054bff34e3Sthurlow sa_set_section_attr(sa_property_t sect, char *name, char *value) 32064bff34e3Sthurlow { 32074bff34e3Sthurlow (void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value); 32084bff34e3Sthurlow } 32094bff34e3Sthurlow 32104bff34e3Sthurlow /* 32114bff34e3Sthurlow * sa_create_property(section, name, value) 32126185db85Sdougm * 32136185db85Sdougm * Create a new property with the specified name and value. 32146185db85Sdougm */ 32156185db85Sdougm 32166185db85Sdougm sa_property_t 32176185db85Sdougm sa_create_property(char *name, char *value) 32186185db85Sdougm { 32196185db85Sdougm xmlNodePtr node; 32206185db85Sdougm 32216185db85Sdougm node = xmlNewNode(NULL, (xmlChar *)"option"); 32226185db85Sdougm if (node != NULL) { 32234bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name); 32244bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value); 32256185db85Sdougm } 32266185db85Sdougm return ((sa_property_t)node); 32276185db85Sdougm } 32286185db85Sdougm 32296185db85Sdougm /* 32306185db85Sdougm * sa_add_property(object, property) 32316185db85Sdougm * 32326185db85Sdougm * Add the specified property to the object. Issue the appropriate 32336185db85Sdougm * transaction or mark a ZFS object as needing an update. 32346185db85Sdougm */ 32356185db85Sdougm 32366185db85Sdougm int 32376185db85Sdougm sa_add_property(void *object, sa_property_t property) 32386185db85Sdougm { 32396185db85Sdougm int ret = SA_OK; 32406185db85Sdougm sa_group_t parent; 32416185db85Sdougm sa_group_t group; 32426185db85Sdougm char *proto; 32436185db85Sdougm 32446185db85Sdougm if (property != NULL) { 32453b61b335Sdougm sa_handle_t handle; 3246687915e9Sdougm handle = sa_find_group_handle((sa_group_t)object); 32473b61b335Sdougm /* It is legitimate to not find a handle */ 3248687915e9Sdougm proto = sa_get_optionset_attr(object, "type"); 3249687915e9Sdougm if ((ret = sa_valid_property(handle, object, proto, 3250687915e9Sdougm property)) == SA_OK) { 325157b448deSdougm property = (sa_property_t)xmlAddChild( 325257b448deSdougm (xmlNodePtr)object, (xmlNodePtr)property); 325357b448deSdougm } else { 325457b448deSdougm if (proto != NULL) 325557b448deSdougm sa_free_attr_string(proto); 325657b448deSdougm return (ret); 325757b448deSdougm } 3258687915e9Sdougm if (proto != NULL) 3259687915e9Sdougm sa_free_attr_string(proto); 32606185db85Sdougm } 32616185db85Sdougm 32626185db85Sdougm 32636185db85Sdougm parent = sa_get_parent_group(object); 3264da6c28aaSamw if (!sa_is_persistent(parent)) 326557b448deSdougm return (ret); 32666185db85Sdougm 3267da6c28aaSamw if (sa_is_resource(parent)) { 3268da6c28aaSamw /* 3269da6c28aaSamw * Resources are children of share. Need to go up two 3270da6c28aaSamw * levels to find the group but the parent needs to be 3271da6c28aaSamw * the share at this point in order to get the "id". 3272da6c28aaSamw */ 3273da6c28aaSamw parent = sa_get_parent_group(parent); 327457b448deSdougm group = sa_get_parent_group(parent); 3275da6c28aaSamw } else if (sa_is_share(parent)) { 3276da6c28aaSamw group = sa_get_parent_group(parent); 3277da6c28aaSamw } else { 327857b448deSdougm group = parent; 3279da6c28aaSamw } 3280549ec3ffSdougm 328157b448deSdougm if (property == NULL) { 328257b448deSdougm ret = SA_NO_MEMORY; 328357b448deSdougm } else { 328457b448deSdougm char oname[SA_STRSIZE]; 328557b448deSdougm 328657b448deSdougm if (!is_zfs_group(group)) { 328757b448deSdougm char *id = NULL; 328857b448deSdougm sa_handle_impl_t impl_handle; 328957b448deSdougm scfutilhandle_t *scf_handle; 329057b448deSdougm 329157b448deSdougm impl_handle = (sa_handle_impl_t)sa_find_group_handle( 329257b448deSdougm group); 329357b448deSdougm if (impl_handle == NULL || 329457b448deSdougm impl_handle->scfhandle == NULL) 329557b448deSdougm ret = SA_SYSTEM_ERR; 329657b448deSdougm if (ret == SA_OK) { 329757b448deSdougm scf_handle = impl_handle->scfhandle; 329857b448deSdougm if (sa_is_share((sa_group_t)parent)) { 329957b448deSdougm id = sa_get_share_attr( 330057b448deSdougm (sa_share_t)parent, "id"); 330157b448deSdougm } 330257b448deSdougm if (scf_handle->trans == NULL) { 330357b448deSdougm if (is_nodetype(object, "optionset")) { 330457b448deSdougm (void) sa_optionset_name( 330557b448deSdougm (sa_optionset_t)object, 330657b448deSdougm oname, sizeof (oname), id); 330757b448deSdougm } else { 330857b448deSdougm (void) sa_security_name( 330957b448deSdougm (sa_optionset_t)object, 331057b448deSdougm oname, sizeof (oname), id); 331157b448deSdougm } 331257b448deSdougm ret = sa_start_transaction(scf_handle, 331357b448deSdougm oname); 331457b448deSdougm } 331557b448deSdougm if (ret == SA_OK) { 331657b448deSdougm char *name; 331757b448deSdougm char *value; 331857b448deSdougm name = sa_get_property_attr(property, 331957b448deSdougm "type"); 332057b448deSdougm value = sa_get_property_attr(property, 332157b448deSdougm "value"); 332257b448deSdougm if (name != NULL && value != NULL) { 332357b448deSdougm if (scf_handle->scf_state == 332457b448deSdougm SCH_STATE_INIT) { 332557b448deSdougm ret = sa_set_property( 332657b448deSdougm scf_handle, name, 332757b448deSdougm value); 332857b448deSdougm } 332957b448deSdougm } else { 333057b448deSdougm ret = SA_CONFIG_ERR; 333157b448deSdougm } 333257b448deSdougm if (name != NULL) 333357b448deSdougm sa_free_attr_string( 333457b448deSdougm name); 333557b448deSdougm if (value != NULL) 333657b448deSdougm sa_free_attr_string(value); 333757b448deSdougm } 333857b448deSdougm if (id != NULL) 333957b448deSdougm sa_free_attr_string(id); 334057b448deSdougm } 334157b448deSdougm } else { 334257b448deSdougm /* 334357b448deSdougm * ZFS is a special case. We do want 334457b448deSdougm * to allow editing property/security 334557b448deSdougm * lists since we can have a better 334657b448deSdougm * syntax and we also want to keep 334757b448deSdougm * things consistent when possible. 334857b448deSdougm * 334957b448deSdougm * Right now, we defer until the 335057b448deSdougm * sa_commit_properties so we can get 335157b448deSdougm * them all at once. We do need to 335257b448deSdougm * mark the share as "changed" 335357b448deSdougm */ 335457b448deSdougm zfs_set_update((sa_share_t)parent); 33556185db85Sdougm } 33566185db85Sdougm } 33576185db85Sdougm return (ret); 33586185db85Sdougm } 33596185db85Sdougm 33606185db85Sdougm /* 33616185db85Sdougm * sa_remove_property(property) 33626185db85Sdougm * 33636185db85Sdougm * Remove the specied property from its containing object. Update the 33646185db85Sdougm * repository as appropriate. 33656185db85Sdougm */ 33666185db85Sdougm 33676185db85Sdougm int 33686185db85Sdougm sa_remove_property(sa_property_t property) 33696185db85Sdougm { 33706185db85Sdougm int ret = SA_OK; 33716185db85Sdougm 33726185db85Sdougm if (property != NULL) { 33736185db85Sdougm sa_optionset_t optionset; 33746185db85Sdougm sa_group_t group; 33756185db85Sdougm optionset = sa_get_property_parent(property); 33766185db85Sdougm if (optionset != NULL) { 337757b448deSdougm group = sa_get_optionset_parent(optionset); 337857b448deSdougm if (group != NULL) { 337957b448deSdougm ret = sa_set_prop_by_prop(optionset, group, 338057b448deSdougm property, SA_PROP_OP_REMOVE); 338157b448deSdougm } 33826185db85Sdougm } 33836185db85Sdougm xmlUnlinkNode((xmlNodePtr)property); 33846185db85Sdougm xmlFreeNode((xmlNodePtr)property); 33856185db85Sdougm } else { 338657b448deSdougm ret = SA_NO_SUCH_PROP; 33876185db85Sdougm } 33886185db85Sdougm return (ret); 33896185db85Sdougm } 33906185db85Sdougm 33916185db85Sdougm /* 33926185db85Sdougm * sa_update_property(property, value) 33936185db85Sdougm * 33946185db85Sdougm * Update the specified property to the new value. If value is NULL, 33956185db85Sdougm * we currently treat this as a remove. 33966185db85Sdougm */ 33976185db85Sdougm 33986185db85Sdougm int 33996185db85Sdougm sa_update_property(sa_property_t property, char *value) 34006185db85Sdougm { 34016185db85Sdougm int ret = SA_OK; 34026185db85Sdougm if (value == NULL) { 34036185db85Sdougm return (sa_remove_property(property)); 34046185db85Sdougm } else { 34056185db85Sdougm sa_optionset_t optionset; 34066185db85Sdougm sa_group_t group; 34076185db85Sdougm set_node_attr((void *)property, "value", value); 34086185db85Sdougm optionset = sa_get_property_parent(property); 34096185db85Sdougm if (optionset != NULL) { 341057b448deSdougm group = sa_get_optionset_parent(optionset); 341157b448deSdougm if (group != NULL) { 341257b448deSdougm ret = sa_set_prop_by_prop(optionset, group, 341357b448deSdougm property, SA_PROP_OP_UPDATE); 341457b448deSdougm } 34156185db85Sdougm } else { 341657b448deSdougm ret = SA_NO_SUCH_PROP; 34176185db85Sdougm } 34186185db85Sdougm } 34196185db85Sdougm return (ret); 34206185db85Sdougm } 34216185db85Sdougm 34224bff34e3Sthurlow /* 34234bff34e3Sthurlow * sa_get_protocol_section(propset, prop) 34244bff34e3Sthurlow * 34254bff34e3Sthurlow * Get the specified protocol specific section. These are global to 34264bff34e3Sthurlow * the protocol and not specific to a group or share. 34274bff34e3Sthurlow */ 34284bff34e3Sthurlow 34294bff34e3Sthurlow sa_protocol_properties_t 34304bff34e3Sthurlow sa_get_protocol_section(sa_protocol_properties_t propset, char *section) 34314bff34e3Sthurlow { 34324bff34e3Sthurlow xmlNodePtr node = (xmlNodePtr)propset; 34334bff34e3Sthurlow xmlChar *value = NULL; 34344bff34e3Sthurlow char *proto; 34354bff34e3Sthurlow 34364bff34e3Sthurlow proto = sa_get_optionset_attr(propset, "type"); 34379c9af259SGordon Ross if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34389c9af259SGordon Ross if (proto != NULL) 34399c9af259SGordon Ross sa_free_attr_string(proto); 34404bff34e3Sthurlow return (propset); 34419c9af259SGordon Ross } 34424bff34e3Sthurlow 34434bff34e3Sthurlow for (node = node->children; node != NULL; 34444bff34e3Sthurlow node = node->next) { 34454bff34e3Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34464bff34e3Sthurlow if (section == NULL) 34474bff34e3Sthurlow break; 34484bff34e3Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34494bff34e3Sthurlow if (value != NULL && 34504bff34e3Sthurlow xmlStrcasecmp(value, (xmlChar *)section) == 0) { 34514bff34e3Sthurlow break; 34524bff34e3Sthurlow } 34534bff34e3Sthurlow if (value != NULL) { 34544bff34e3Sthurlow xmlFree(value); 34554bff34e3Sthurlow value = NULL; 34564bff34e3Sthurlow } 34574bff34e3Sthurlow } 34584bff34e3Sthurlow } 34594bff34e3Sthurlow if (value != NULL) 34604bff34e3Sthurlow xmlFree(value); 34619c9af259SGordon Ross if (proto != NULL) 34629c9af259SGordon Ross sa_free_attr_string(proto); 34634bff34e3Sthurlow if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) { 34644bff34e3Sthurlow /* 34654bff34e3Sthurlow * avoid a non option node -- it is possible to be a 34664bff34e3Sthurlow * text node 34674bff34e3Sthurlow */ 34684bff34e3Sthurlow node = NULL; 34694bff34e3Sthurlow } 34704bff34e3Sthurlow return ((sa_protocol_properties_t)node); 34714bff34e3Sthurlow } 34724bff34e3Sthurlow 34734bff34e3Sthurlow /* 34744bff34e3Sthurlow * sa_get_next_protocol_section(prop, find) 34754bff34e3Sthurlow * 34764bff34e3Sthurlow * Get the next protocol specific section in the list. 34774bff34e3Sthurlow */ 34784bff34e3Sthurlow 34794bff34e3Sthurlow sa_property_t 34804bff34e3Sthurlow sa_get_next_protocol_section(sa_property_t prop, char *find) 34814bff34e3Sthurlow { 34824bff34e3Sthurlow xmlNodePtr node; 34834bff34e3Sthurlow xmlChar *value = NULL; 34844bff34e3Sthurlow char *proto; 34854bff34e3Sthurlow 34864bff34e3Sthurlow proto = sa_get_optionset_attr(prop, "type"); 34879c9af259SGordon Ross if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) { 34889c9af259SGordon Ross if (proto != NULL) 34899c9af259SGordon Ross sa_free_attr_string(proto); 34904bff34e3Sthurlow return ((sa_property_t)NULL); 34919c9af259SGordon Ross } 34924bff34e3Sthurlow 34934bff34e3Sthurlow for (node = ((xmlNodePtr)prop)->next; node != NULL; 34944bff34e3Sthurlow node = node->next) { 34954bff34e3Sthurlow if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) { 34964bff34e3Sthurlow if (find == NULL) 34974bff34e3Sthurlow break; 34984bff34e3Sthurlow value = xmlGetProp(node, (xmlChar *)"name"); 34994bff34e3Sthurlow if (value != NULL && 35004bff34e3Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35014bff34e3Sthurlow break; 35024bff34e3Sthurlow } 35034bff34e3Sthurlow if (value != NULL) { 35044bff34e3Sthurlow xmlFree(value); 35054bff34e3Sthurlow value = NULL; 35064bff34e3Sthurlow } 35074bff34e3Sthurlow 35084bff34e3Sthurlow } 35094bff34e3Sthurlow } 35104bff34e3Sthurlow if (value != NULL) 35114bff34e3Sthurlow xmlFree(value); 35129c9af259SGordon Ross if (proto != NULL) 35139c9af259SGordon Ross sa_free_attr_string(proto); 35144bff34e3Sthurlow return ((sa_property_t)node); 35154bff34e3Sthurlow } 35164bff34e3Sthurlow 35176185db85Sdougm /* 35186185db85Sdougm * sa_get_protocol_property(propset, prop) 35196185db85Sdougm * 35206185db85Sdougm * Get the specified protocol specific property. These are global to 35216185db85Sdougm * the protocol and not specific to a group or share. 35226185db85Sdougm */ 35236185db85Sdougm 35246185db85Sdougm sa_property_t 35256185db85Sdougm sa_get_protocol_property(sa_protocol_properties_t propset, char *prop) 35266185db85Sdougm { 35276185db85Sdougm xmlNodePtr node = (xmlNodePtr)propset; 35286185db85Sdougm xmlChar *value = NULL; 35296185db85Sdougm 35304bff34e3Sthurlow if (propset == NULL) 35314bff34e3Sthurlow return (NULL); 35324bff34e3Sthurlow 35336185db85Sdougm for (node = node->children; node != NULL; 353457b448deSdougm node = node->next) { 353557b448deSdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 353657b448deSdougm if (prop == NULL) 353757b448deSdougm break; 353857b448deSdougm value = xmlGetProp(node, (xmlChar *)"type"); 353957b448deSdougm if (value != NULL && 354057b448deSdougm xmlStrcasecmp(value, (xmlChar *)prop) == 0) { 354157b448deSdougm break; 354257b448deSdougm } 354357b448deSdougm if (value != NULL) { 354457b448deSdougm xmlFree(value); 354557b448deSdougm value = NULL; 354657b448deSdougm } 35476185db85Sdougm } 35486185db85Sdougm } 35496185db85Sdougm if (value != NULL) 35506185db85Sdougm xmlFree(value); 35516185db85Sdougm if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"option") != 0) { 355257b448deSdougm /* 355357b448deSdougm * avoid a non option node -- it is possible to be a 355457b448deSdougm * text node 355557b448deSdougm */ 355657b448deSdougm node = NULL; 35576185db85Sdougm } 35586185db85Sdougm return ((sa_property_t)node); 35596185db85Sdougm } 35606185db85Sdougm 35616185db85Sdougm /* 35626185db85Sdougm * sa_get_next_protocol_property(prop) 35636185db85Sdougm * 35646185db85Sdougm * Get the next protocol specific property in the list. 35656185db85Sdougm */ 35666185db85Sdougm 35676185db85Sdougm sa_property_t 35684bff34e3Sthurlow sa_get_next_protocol_property(sa_property_t prop, char *find) 35696185db85Sdougm { 35706185db85Sdougm xmlNodePtr node; 35714bff34e3Sthurlow xmlChar *value = NULL; 35726185db85Sdougm 35736185db85Sdougm for (node = ((xmlNodePtr)prop)->next; node != NULL; 357457b448deSdougm node = node->next) { 35756185db85Sdougm if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) { 35764bff34e3Sthurlow if (find == NULL) 35774bff34e3Sthurlow break; 35784bff34e3Sthurlow value = xmlGetProp(node, (xmlChar *)"type"); 35794bff34e3Sthurlow if (value != NULL && 35804bff34e3Sthurlow xmlStrcasecmp(value, (xmlChar *)find) == 0) { 35814bff34e3Sthurlow break; 35824bff34e3Sthurlow } 35834bff34e3Sthurlow if (value != NULL) { 35844bff34e3Sthurlow xmlFree(value); 35854bff34e3Sthurlow value = NULL; 35864bff34e3Sthurlow } 35874bff34e3Sthurlow 35886185db85Sdougm } 35896185db85Sdougm } 35904bff34e3Sthurlow if (value != NULL) 35914bff34e3Sthurlow xmlFree(value); 35926185db85Sdougm return ((sa_property_t)node); 35936185db85Sdougm } 35946185db85Sdougm 35956185db85Sdougm /* 35966185db85Sdougm * sa_set_protocol_property(prop, value) 35976185db85Sdougm * 35986185db85Sdougm * Set the specified property to have the new value. The protocol 35996185db85Sdougm * specific plugin will then be called to update the property. 36006185db85Sdougm */ 36016185db85Sdougm 36026185db85Sdougm int 36034bff34e3Sthurlow sa_set_protocol_property(sa_property_t prop, char *section, char *value) 36046185db85Sdougm { 36056185db85Sdougm sa_protocol_properties_t propset; 36066185db85Sdougm char *proto; 36076185db85Sdougm int ret = SA_INVALID_PROTOCOL; 36086185db85Sdougm 36096185db85Sdougm propset = ((xmlNodePtr)prop)->parent; 36106185db85Sdougm if (propset != NULL) { 361157b448deSdougm proto = sa_get_optionset_attr(propset, "type"); 361257b448deSdougm if (proto != NULL) { 36134bff34e3Sthurlow if (section != NULL) 36144bff34e3Sthurlow set_node_attr((xmlNodePtr)prop, "section", 36154bff34e3Sthurlow section); 361657b448deSdougm set_node_attr((xmlNodePtr)prop, "value", value); 361757b448deSdougm ret = sa_proto_set_property(proto, prop); 361857b448deSdougm sa_free_attr_string(proto); 361957b448deSdougm } 36206185db85Sdougm } 36216185db85Sdougm return (ret); 36226185db85Sdougm } 36236185db85Sdougm 36246185db85Sdougm /* 36256185db85Sdougm * sa_add_protocol_property(propset, prop) 36266185db85Sdougm * 3627da6c28aaSamw * Add a new property to the protocol specific property set. 36286185db85Sdougm */ 36296185db85Sdougm 36306185db85Sdougm int 36316185db85Sdougm sa_add_protocol_property(sa_protocol_properties_t propset, sa_property_t prop) 36326185db85Sdougm { 36336185db85Sdougm xmlNodePtr node; 36346185db85Sdougm 36356185db85Sdougm /* should check for legitimacy */ 36366185db85Sdougm node = xmlAddChild((xmlNodePtr)propset, (xmlNodePtr)prop); 36376185db85Sdougm if (node != NULL) 363857b448deSdougm return (SA_OK); 36396185db85Sdougm return (SA_NO_MEMORY); 36406185db85Sdougm } 36416185db85Sdougm 36426185db85Sdougm /* 36436185db85Sdougm * sa_create_protocol_properties(proto) 36446185db85Sdougm * 3645da6c28aaSamw * Create a protocol specific property set. 36466185db85Sdougm */ 36476185db85Sdougm 36486185db85Sdougm sa_protocol_properties_t 36496185db85Sdougm sa_create_protocol_properties(char *proto) 36506185db85Sdougm { 36516185db85Sdougm xmlNodePtr node; 365257b448deSdougm 36536185db85Sdougm node = xmlNewNode(NULL, (xmlChar *)"propertyset"); 365457b448deSdougm if (node != NULL) 36554bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto); 36566185db85Sdougm return (node); 36576185db85Sdougm } 3658da6c28aaSamw 3659da6c28aaSamw /* 3660da6c28aaSamw * sa_get_share_resource(share, resource) 3661da6c28aaSamw * 3662da6c28aaSamw * Get the named resource from the share, if it exists. If resource is 3663da6c28aaSamw * NULL, get the first resource. 3664da6c28aaSamw */ 3665da6c28aaSamw 3666da6c28aaSamw sa_resource_t 3667da6c28aaSamw sa_get_share_resource(sa_share_t share, char *resource) 3668da6c28aaSamw { 3669da6c28aaSamw xmlNodePtr node = NULL; 3670da6c28aaSamw xmlChar *name; 3671da6c28aaSamw 3672da6c28aaSamw if (share != NULL) { 3673da6c28aaSamw for (node = ((xmlNodePtr)share)->children; node != NULL; 3674da6c28aaSamw node = node->next) { 3675da6c28aaSamw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) { 3676da6c28aaSamw if (resource == NULL) { 3677da6c28aaSamw /* 3678da6c28aaSamw * We are looking for the first 3679da6c28aaSamw * resource node and not a names 3680da6c28aaSamw * resource. 3681da6c28aaSamw */ 3682da6c28aaSamw break; 3683da6c28aaSamw } else { 3684da6c28aaSamw /* is it the correct share? */ 3685da6c28aaSamw name = xmlGetProp(node, 3686da6c28aaSamw (xmlChar *)"name"); 3687da6c28aaSamw if (name != NULL && 3688da6c28aaSamw xmlStrcasecmp(name, 3689da6c28aaSamw (xmlChar *)resource) == 0) { 3690da6c28aaSamw xmlFree(name); 3691da6c28aaSamw break; 3692da6c28aaSamw } 3693da6c28aaSamw xmlFree(name); 3694da6c28aaSamw } 3695da6c28aaSamw } 3696da6c28aaSamw } 3697da6c28aaSamw } 3698da6c28aaSamw return ((sa_resource_t)node); 3699da6c28aaSamw } 3700da6c28aaSamw 3701da6c28aaSamw /* 3702da6c28aaSamw * sa_get_next_resource(resource) 3703da6c28aaSamw * Return the next share following the specified share 3704da6c28aaSamw * from the internal list of shares. Returns NULL if there 3705da6c28aaSamw * are no more shares. The list is relative to the same 3706da6c28aaSamw * group. 3707da6c28aaSamw */ 3708da6c28aaSamw sa_share_t 3709da6c28aaSamw sa_get_next_resource(sa_resource_t resource) 3710da6c28aaSamw { 3711da6c28aaSamw xmlNodePtr node = NULL; 3712da6c28aaSamw 3713da6c28aaSamw if (resource != NULL) { 3714da6c28aaSamw for (node = ((xmlNodePtr)resource)->next; node != NULL; 3715da6c28aaSamw node = node->next) { 3716da6c28aaSamw if (xmlStrcmp(node->name, (xmlChar *)"resource") == 0) 3717da6c28aaSamw break; 3718da6c28aaSamw } 3719da6c28aaSamw } 3720da6c28aaSamw return ((sa_share_t)node); 3721da6c28aaSamw } 3722da6c28aaSamw 3723da6c28aaSamw /* 3724da6c28aaSamw * _sa_get_next_resource_index(share) 3725da6c28aaSamw * 3726da6c28aaSamw * get the next resource index number (one greater then current largest) 3727da6c28aaSamw */ 3728da6c28aaSamw 3729da6c28aaSamw static int 3730da6c28aaSamw _sa_get_next_resource_index(sa_share_t share) 3731da6c28aaSamw { 3732da6c28aaSamw sa_resource_t resource; 3733da6c28aaSamw int index = 0; 3734da6c28aaSamw char *id; 3735da6c28aaSamw 3736da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 3737da6c28aaSamw resource != NULL; 3738da6c28aaSamw resource = sa_get_next_resource(resource)) { 3739da6c28aaSamw id = get_node_attr((void *)resource, "id"); 3740da6c28aaSamw if (id != NULL) { 3741da6c28aaSamw int val; 3742da6c28aaSamw val = atoi(id); 3743da6c28aaSamw if (val > index) 3744da6c28aaSamw index = val; 3745da6c28aaSamw sa_free_attr_string(id); 3746da6c28aaSamw } 3747da6c28aaSamw } 3748da6c28aaSamw return (index + 1); 3749da6c28aaSamw } 3750da6c28aaSamw 3751da6c28aaSamw 3752da6c28aaSamw /* 3753da6c28aaSamw * sa_add_resource(share, resource, persist, &err) 3754da6c28aaSamw * 3755da6c28aaSamw * Adds a new resource name associated with share. The resource name 3756da6c28aaSamw * must be unique in the system and will be case insensitive (eventually). 3757da6c28aaSamw */ 3758da6c28aaSamw 3759da6c28aaSamw sa_resource_t 3760da6c28aaSamw sa_add_resource(sa_share_t share, char *resource, int persist, int *error) 3761da6c28aaSamw { 3762da6c28aaSamw xmlNodePtr node; 3763da6c28aaSamw int err = SA_OK; 3764da6c28aaSamw sa_resource_t res; 3765da6c28aaSamw sa_group_t group; 3766da6c28aaSamw sa_handle_t handle; 3767da6c28aaSamw char istring[8]; /* just big enough for an integer value */ 3768da6c28aaSamw int index; 3769da6c28aaSamw 3770da6c28aaSamw group = sa_get_parent_group(share); 3771da6c28aaSamw handle = sa_find_group_handle(group); 3772da6c28aaSamw res = sa_find_resource(handle, resource); 3773da6c28aaSamw if (res != NULL) { 3774da6c28aaSamw err = SA_DUPLICATE_NAME; 3775da6c28aaSamw res = NULL; 3776da6c28aaSamw } else { 3777da6c28aaSamw node = xmlNewChild((xmlNodePtr)share, NULL, 3778da6c28aaSamw (xmlChar *)"resource", NULL); 3779da6c28aaSamw if (node != NULL) { 37804bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"name", 3781da6c28aaSamw (xmlChar *)resource); 37824bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"type", persist ? 3783da6c28aaSamw (xmlChar *)"persist" : (xmlChar *)"transient"); 3784da6c28aaSamw if (persist != SA_SHARE_TRANSIENT) { 3785da6c28aaSamw index = _sa_get_next_resource_index(share); 3786da6c28aaSamw (void) snprintf(istring, sizeof (istring), "%d", 3787da6c28aaSamw index); 37884bff34e3Sthurlow (void) xmlSetProp(node, (xmlChar *)"id", 3789da6c28aaSamw (xmlChar *)istring); 37901f713840SDoug McCallum 37911f713840SDoug McCallum if (!sa_is_persistent((sa_group_t)share)) 37921f713840SDoug McCallum goto done; 37931f713840SDoug McCallum 37941f713840SDoug McCallum if (!sa_group_is_zfs(group)) { 3795da6c28aaSamw /* ZFS doesn't use resource names */ 3796da6c28aaSamw sa_handle_impl_t ihandle; 37971f713840SDoug McCallum 3798da6c28aaSamw ihandle = (sa_handle_impl_t) 3799da6c28aaSamw sa_find_group_handle( 3800da6c28aaSamw group); 3801da6c28aaSamw if (ihandle != NULL) 3802da6c28aaSamw err = sa_commit_share( 3803da6c28aaSamw ihandle->scfhandle, group, 3804da6c28aaSamw share); 3805da6c28aaSamw else 3806da6c28aaSamw err = SA_SYSTEM_ERR; 38071f713840SDoug McCallum } else { 38081f713840SDoug McCallum err = sa_zfs_update((sa_share_t)group); 3809da6c28aaSamw } 3810da6c28aaSamw } 3811da6c28aaSamw } 3812da6c28aaSamw } 38131f713840SDoug McCallum done: 3814da6c28aaSamw if (error != NULL) 3815da6c28aaSamw *error = err; 3816da6c28aaSamw return ((sa_resource_t)node); 3817da6c28aaSamw } 3818da6c28aaSamw 3819da6c28aaSamw /* 3820da6c28aaSamw * sa_remove_resource(resource) 3821da6c28aaSamw * 3822da6c28aaSamw * Remove the resource name from the share (and the system) 3823da6c28aaSamw */ 3824da6c28aaSamw 3825da6c28aaSamw int 3826da6c28aaSamw sa_remove_resource(sa_resource_t resource) 3827da6c28aaSamw { 3828da6c28aaSamw sa_share_t share; 3829da6c28aaSamw sa_group_t group; 3830da6c28aaSamw char *type; 3831da6c28aaSamw int ret = SA_OK; 38321f713840SDoug McCallum boolean_t transient = B_FALSE; 383355bf511dSas sa_optionset_t opt; 3834da6c28aaSamw 3835da6c28aaSamw share = sa_get_resource_parent(resource); 3836da6c28aaSamw type = sa_get_share_attr(share, "type"); 3837da6c28aaSamw group = sa_get_parent_group(share); 3838da6c28aaSamw 3839da6c28aaSamw 3840da6c28aaSamw if (type != NULL) { 3841da6c28aaSamw if (strcmp(type, "persist") != 0) 38421f713840SDoug McCallum transient = B_TRUE; 3843da6c28aaSamw sa_free_attr_string(type); 3844da6c28aaSamw } 3845da6c28aaSamw 384655bf511dSas /* Disable the resource for all protocols. */ 384755bf511dSas (void) sa_disable_resource(resource, NULL); 384855bf511dSas 384955bf511dSas /* Remove any optionsets from the resource. */ 385055bf511dSas for (opt = sa_get_optionset(resource, NULL); 385155bf511dSas opt != NULL; 385255bf511dSas opt = sa_get_next_optionset(opt)) 385355bf511dSas (void) sa_destroy_optionset(opt); 385455bf511dSas 3855da6c28aaSamw /* Remove from the share */ 3856da6c28aaSamw xmlUnlinkNode((xmlNode *)resource); 3857da6c28aaSamw xmlFreeNode((xmlNode *)resource); 3858da6c28aaSamw 3859da6c28aaSamw /* only do SMF action if permanent and not ZFS */ 38601f713840SDoug McCallum if (transient) 38611f713840SDoug McCallum return (ret); 38621f713840SDoug McCallum 38631f713840SDoug McCallum if (!sa_group_is_zfs(group)) { 3864da6c28aaSamw sa_handle_impl_t ihandle; 3865da6c28aaSamw ihandle = (sa_handle_impl_t)sa_find_group_handle(group); 3866da6c28aaSamw if (ihandle != NULL) 3867da6c28aaSamw ret = sa_commit_share(ihandle->scfhandle, group, share); 3868da6c28aaSamw else 3869da6c28aaSamw ret = SA_SYSTEM_ERR; 38701f713840SDoug McCallum } else { 38711f713840SDoug McCallum ret = sa_zfs_update((sa_share_t)group); 3872da6c28aaSamw } 3873743a77edSAlan Wright 3874da6c28aaSamw return (ret); 3875da6c28aaSamw } 3876da6c28aaSamw 3877da6c28aaSamw /* 3878743a77edSAlan Wright * proto_rename_resource(handle, group, resource, newname) 3879da6c28aaSamw * 3880da6c28aaSamw * Helper function for sa_rename_resource that notifies the protocol 3881da6c28aaSamw * of a resource name change prior to a config repository update. 3882da6c28aaSamw */ 3883da6c28aaSamw static int 3884da6c28aaSamw proto_rename_resource(sa_handle_t handle, sa_group_t group, 3885da6c28aaSamw sa_resource_t resource, char *newname) 3886da6c28aaSamw { 3887da6c28aaSamw sa_optionset_t optionset; 3888da6c28aaSamw int ret = SA_OK; 3889da6c28aaSamw int err; 3890da6c28aaSamw 3891da6c28aaSamw for (optionset = sa_get_optionset(group, NULL); 3892da6c28aaSamw optionset != NULL; 3893da6c28aaSamw optionset = sa_get_next_optionset(optionset)) { 3894da6c28aaSamw char *type; 3895da6c28aaSamw type = sa_get_optionset_attr(optionset, "type"); 3896da6c28aaSamw if (type != NULL) { 3897da6c28aaSamw err = sa_proto_rename_resource(handle, type, resource, 3898da6c28aaSamw newname); 3899da6c28aaSamw if (err != SA_OK) 3900da6c28aaSamw ret = err; 3901da6c28aaSamw sa_free_attr_string(type); 3902da6c28aaSamw } 3903da6c28aaSamw } 3904da6c28aaSamw return (ret); 3905da6c28aaSamw } 3906da6c28aaSamw 3907da6c28aaSamw /* 3908da6c28aaSamw * sa_rename_resource(resource, newname) 3909da6c28aaSamw * 3910da6c28aaSamw * Rename the resource to the new name, if it is unique. 3911da6c28aaSamw */ 3912da6c28aaSamw 3913da6c28aaSamw int 3914da6c28aaSamw sa_rename_resource(sa_resource_t resource, char *newname) 3915da6c28aaSamw { 3916da6c28aaSamw sa_share_t share; 3917da6c28aaSamw sa_group_t group = NULL; 3918da6c28aaSamw sa_resource_t target; 3919da6c28aaSamw int ret = SA_CONFIG_ERR; 3920da6c28aaSamw sa_handle_t handle = NULL; 3921da6c28aaSamw 3922da6c28aaSamw share = sa_get_resource_parent(resource); 3923da6c28aaSamw if (share == NULL) 3924da6c28aaSamw return (ret); 3925da6c28aaSamw 3926da6c28aaSamw group = sa_get_parent_group(share); 3927da6c28aaSamw if (group == NULL) 3928da6c28aaSamw return (ret); 3929da6c28aaSamw 3930da6c28aaSamw handle = (sa_handle_impl_t)sa_find_group_handle(group); 3931da6c28aaSamw if (handle == NULL) 3932da6c28aaSamw return (ret); 3933da6c28aaSamw 3934da6c28aaSamw target = sa_find_resource(handle, newname); 3935da6c28aaSamw if (target != NULL) { 3936da6c28aaSamw ret = SA_DUPLICATE_NAME; 3937da6c28aaSamw } else { 3938da6c28aaSamw /* 3939da6c28aaSamw * Everything appears to be valid at this 3940da6c28aaSamw * point. Change the name of the active share and then 3941da6c28aaSamw * update the share in the appropriate repository. 3942da6c28aaSamw */ 3943da6c28aaSamw ret = proto_rename_resource(handle, group, resource, newname); 3944da6c28aaSamw set_node_attr(resource, "name", newname); 39451f713840SDoug McCallum 39461f713840SDoug McCallum if (!sa_is_persistent((sa_group_t)share)) 39471f713840SDoug McCallum return (ret); 39481f713840SDoug McCallum 39491f713840SDoug McCallum if (!sa_group_is_zfs(group)) { 3950da6c28aaSamw sa_handle_impl_t ihandle = (sa_handle_impl_t)handle; 3951da6c28aaSamw ret = sa_commit_share(ihandle->scfhandle, group, 3952da6c28aaSamw share); 39531f713840SDoug McCallum } else { 39541f713840SDoug McCallum ret = sa_zfs_update((sa_share_t)group); 3955da6c28aaSamw } 3956da6c28aaSamw } 3957da6c28aaSamw return (ret); 3958da6c28aaSamw } 3959da6c28aaSamw 3960da6c28aaSamw /* 3961da6c28aaSamw * sa_get_resource_attr(resource, tag) 3962da6c28aaSamw * 3963da6c28aaSamw * Get the named attribute of the resource. "name" and "id" are 3964da6c28aaSamw * currently defined. NULL if tag not defined. 3965da6c28aaSamw */ 3966da6c28aaSamw 3967da6c28aaSamw char * 3968da6c28aaSamw sa_get_resource_attr(sa_resource_t resource, char *tag) 3969da6c28aaSamw { 3970da6c28aaSamw return (get_node_attr((void *)resource, tag)); 3971da6c28aaSamw } 3972da6c28aaSamw 3973da6c28aaSamw /* 3974da6c28aaSamw * sa_set_resource_attr(resource, tag, value) 3975da6c28aaSamw * 3976da6c28aaSamw * Get the named attribute of the resource. "name" and "id" are 3977da6c28aaSamw * currently defined. NULL if tag not defined. Currently we don't do 3978da6c28aaSamw * much, but additional checking may be needed in the future. 3979da6c28aaSamw */ 3980da6c28aaSamw 3981da6c28aaSamw int 3982da6c28aaSamw sa_set_resource_attr(sa_resource_t resource, char *tag, char *value) 3983da6c28aaSamw { 3984da6c28aaSamw set_node_attr((void *)resource, tag, value); 3985da6c28aaSamw return (SA_OK); 3986da6c28aaSamw } 3987da6c28aaSamw 3988da6c28aaSamw /* 3989da6c28aaSamw * sa_get_resource_parent(resource_t) 3990da6c28aaSamw * 3991da6c28aaSamw * Returns the share associated with the resource. 3992da6c28aaSamw */ 3993da6c28aaSamw 3994da6c28aaSamw sa_share_t 3995da6c28aaSamw sa_get_resource_parent(sa_resource_t resource) 3996da6c28aaSamw { 3997da6c28aaSamw sa_share_t share = NULL; 3998da6c28aaSamw 3999da6c28aaSamw if (resource != NULL) 4000da6c28aaSamw share = (sa_share_t)((xmlNodePtr)resource)->parent; 4001da6c28aaSamw return (share); 4002da6c28aaSamw } 4003da6c28aaSamw 4004da6c28aaSamw /* 4005da6c28aaSamw * find_resource(group, name) 4006da6c28aaSamw * 4007da6c28aaSamw * Find the resource within the group. 4008da6c28aaSamw */ 4009da6c28aaSamw 4010da6c28aaSamw static sa_resource_t 4011da6c28aaSamw find_resource(sa_group_t group, char *resname) 4012da6c28aaSamw { 4013da6c28aaSamw sa_share_t share; 4014da6c28aaSamw sa_resource_t resource = NULL; 4015da6c28aaSamw char *name; 4016da6c28aaSamw 4017da6c28aaSamw /* Iterate over all the shares and resources in the group. */ 4018da6c28aaSamw for (share = sa_get_share(group, NULL); 4019da6c28aaSamw share != NULL && resource == NULL; 4020da6c28aaSamw share = sa_get_next_share(share)) { 4021da6c28aaSamw for (resource = sa_get_share_resource(share, NULL); 4022da6c28aaSamw resource != NULL; 4023da6c28aaSamw resource = sa_get_next_resource(resource)) { 4024da6c28aaSamw name = sa_get_resource_attr(resource, "name"); 4025da6c28aaSamw if (name != NULL && xmlStrcasecmp((xmlChar*)name, 4026da6c28aaSamw (xmlChar*)resname) == 0) { 4027da6c28aaSamw sa_free_attr_string(name); 4028da6c28aaSamw break; 4029da6c28aaSamw } 4030da6c28aaSamw if (name != NULL) { 4031da6c28aaSamw sa_free_attr_string(name); 4032da6c28aaSamw } 4033da6c28aaSamw } 4034da6c28aaSamw } 4035da6c28aaSamw return (resource); 4036da6c28aaSamw } 4037da6c28aaSamw 4038da6c28aaSamw /* 4039da6c28aaSamw * sa_find_resource(name) 4040da6c28aaSamw * 4041da6c28aaSamw * Find the named resource in the system. 4042da6c28aaSamw */ 4043da6c28aaSamw 4044da6c28aaSamw sa_resource_t 4045da6c28aaSamw sa_find_resource(sa_handle_t handle, char *name) 4046da6c28aaSamw { 4047da6c28aaSamw sa_group_t group; 4048da6c28aaSamw sa_group_t zgroup; 4049da6c28aaSamw sa_resource_t resource = NULL; 4050da6c28aaSamw 4051da6c28aaSamw /* 4052da6c28aaSamw * Iterate over all groups and zfs subgroups and check for 4053da6c28aaSamw * resource name in them. 4054da6c28aaSamw */ 4055da6c28aaSamw for (group = sa_get_group(handle, NULL); group != NULL; 4056da6c28aaSamw group = sa_get_next_group(group)) { 4057da6c28aaSamw 4058da6c28aaSamw if (is_zfs_group(group)) { 4059da6c28aaSamw for (zgroup = 4060da6c28aaSamw (sa_group_t)_sa_get_child_node((xmlNodePtr)group, 4061da6c28aaSamw (xmlChar *)"group"); 4062da6c28aaSamw zgroup != NULL && resource == NULL; 4063da6c28aaSamw zgroup = sa_get_next_group(zgroup)) { 4064da6c28aaSamw resource = find_resource(zgroup, name); 4065da6c28aaSamw } 4066da6c28aaSamw } else { 4067da6c28aaSamw resource = find_resource(group, name); 4068da6c28aaSamw } 4069da6c28aaSamw if (resource != NULL) 4070da6c28aaSamw break; 4071da6c28aaSamw } 4072da6c28aaSamw return (resource); 4073da6c28aaSamw } 4074da6c28aaSamw 4075da6c28aaSamw /* 4076da6c28aaSamw * sa_get_resource(group, resource) 4077da6c28aaSamw * 4078da6c28aaSamw * Search all the shares in the specified group for a share with a 4079da6c28aaSamw * resource name matching the one specified. 4080da6c28aaSamw * 4081da6c28aaSamw * In the future, it may be advantageous to allow group to be NULL and 4082da6c28aaSamw * search all groups but that isn't needed at present. 4083da6c28aaSamw */ 4084da6c28aaSamw 4085da6c28aaSamw sa_resource_t 4086da6c28aaSamw sa_get_resource(sa_group_t group, char *resource) 4087da6c28aaSamw { 4088da6c28aaSamw sa_share_t share = NULL; 4089da6c28aaSamw sa_resource_t res = NULL; 4090da6c28aaSamw 4091da6c28aaSamw if (resource != NULL) { 4092da6c28aaSamw for (share = sa_get_share(group, NULL); 4093da6c28aaSamw share != NULL && res == NULL; 4094da6c28aaSamw share = sa_get_next_share(share)) { 4095da6c28aaSamw res = sa_get_share_resource(share, resource); 4096da6c28aaSamw } 4097da6c28aaSamw } 4098da6c28aaSamw return (res); 4099da6c28aaSamw } 4100da6c28aaSamw 4101f85463f2Sdougm /* 4102f85463f2Sdougm * get_protocol_list(optionset, object) 4103f85463f2Sdougm * 4104f85463f2Sdougm * Get the protocol optionset list for the object and add them as 4105f85463f2Sdougm * properties to optionset. 4106f85463f2Sdougm */ 4107f85463f2Sdougm static int 4108f85463f2Sdougm get_protocol_list(sa_optionset_t optionset, void *object) 4109f85463f2Sdougm { 4110f85463f2Sdougm sa_property_t prop; 4111f85463f2Sdougm sa_optionset_t opts; 4112f85463f2Sdougm int ret = SA_OK; 4113f85463f2Sdougm 4114f85463f2Sdougm for (opts = sa_get_optionset(object, NULL); 4115f85463f2Sdougm opts != NULL; 4116f85463f2Sdougm opts = sa_get_next_optionset(opts)) { 4117f85463f2Sdougm char *type; 4118f85463f2Sdougm type = sa_get_optionset_attr(opts, "type"); 4119f85463f2Sdougm /* 4120f85463f2Sdougm * It is possible to have a non-protocol optionset. We 4121f85463f2Sdougm * skip any of those found. 4122f85463f2Sdougm */ 4123f85463f2Sdougm if (type == NULL) 4124f85463f2Sdougm continue; 4125f85463f2Sdougm prop = sa_create_property(type, "true"); 4126f85463f2Sdougm sa_free_attr_string(type); 4127f85463f2Sdougm if (prop != NULL) 4128f85463f2Sdougm prop = (sa_property_t)xmlAddChild((xmlNodePtr)optionset, 4129f85463f2Sdougm (xmlNodePtr)prop); 4130f85463f2Sdougm /* If prop is NULL, don't bother continuing */ 4131f85463f2Sdougm if (prop == NULL) { 4132f85463f2Sdougm ret = SA_NO_MEMORY; 4133f85463f2Sdougm break; 4134f85463f2Sdougm } 4135f85463f2Sdougm } 4136f85463f2Sdougm return (ret); 4137f85463f2Sdougm } 4138f85463f2Sdougm 4139f85463f2Sdougm /* 4140f85463f2Sdougm * sa_free_protoset(optionset) 4141f85463f2Sdougm * 4142f85463f2Sdougm * Free the protocol property optionset. 4143f85463f2Sdougm */ 4144f85463f2Sdougm static void 4145f85463f2Sdougm sa_free_protoset(sa_optionset_t optionset) 4146f85463f2Sdougm { 4147f85463f2Sdougm if (optionset != NULL) { 4148f85463f2Sdougm xmlUnlinkNode((xmlNodePtr) optionset); 4149f85463f2Sdougm xmlFreeNode((xmlNodePtr) optionset); 4150f85463f2Sdougm } 4151f85463f2Sdougm } 4152f85463f2Sdougm 4153f85463f2Sdougm /* 4154f85463f2Sdougm * sa_optionset_t sa_get_active_protocols(object) 4155f85463f2Sdougm * 4156f85463f2Sdougm * Return a list of the protocols that are active for the object. 4157f85463f2Sdougm * This is currently an internal helper function, but could be 4158f85463f2Sdougm * made visible if there is enough demand for it. 4159f85463f2Sdougm * 4160f85463f2Sdougm * The function finds the parent group and extracts the protocol 4161f85463f2Sdougm * optionsets creating a new optionset with the protocols as properties. 4162f85463f2Sdougm * 4163f85463f2Sdougm * The caller must free the returned optionset. 4164f85463f2Sdougm */ 4165f85463f2Sdougm 4166f85463f2Sdougm static sa_optionset_t 4167f85463f2Sdougm sa_get_active_protocols(void *object) 4168f85463f2Sdougm { 4169f85463f2Sdougm sa_optionset_t options; 4170f85463f2Sdougm sa_share_t share = NULL; 4171f85463f2Sdougm sa_group_t group = NULL; 4172f85463f2Sdougm sa_resource_t resource = NULL; 4173f85463f2Sdougm int ret = SA_OK; 4174f85463f2Sdougm 4175f85463f2Sdougm if (object == NULL) 4176f85463f2Sdougm return (NULL); 4177f85463f2Sdougm options = (sa_optionset_t)xmlNewNode(NULL, (xmlChar *)"optionset"); 4178f85463f2Sdougm if (options == NULL) 4179f85463f2Sdougm return (NULL); 4180f85463f2Sdougm 4181f85463f2Sdougm /* 4182f85463f2Sdougm * Find the objects up the tree that might have protocols 4183f85463f2Sdougm * enabled on them. 4184f85463f2Sdougm */ 4185f85463f2Sdougm if (sa_is_resource(object)) { 4186f85463f2Sdougm resource = (sa_resource_t)object; 4187f85463f2Sdougm share = sa_get_resource_parent(resource); 4188f85463f2Sdougm group = sa_get_parent_group(share); 4189f85463f2Sdougm } else if (sa_is_share(object)) { 4190f85463f2Sdougm share = (sa_share_t)object; 4191f85463f2Sdougm group = sa_get_parent_group(share); 4192f85463f2Sdougm } else { 4193f85463f2Sdougm group = (sa_group_t)group; 4194f85463f2Sdougm } 4195f85463f2Sdougm if (resource != NULL) 4196f85463f2Sdougm ret = get_protocol_list(options, resource); 4197f85463f2Sdougm if (ret == SA_OK && share != NULL) 4198f85463f2Sdougm ret = get_protocol_list(options, share); 4199f85463f2Sdougm if (ret == SA_OK && group != NULL) 4200f85463f2Sdougm ret = get_protocol_list(options, group); 4201f85463f2Sdougm 4202f85463f2Sdougm /* 4203f85463f2Sdougm * If there was an error, we won't have a complete list so 4204f85463f2Sdougm * abandon everything. The caller will have to deal with the 4205f85463f2Sdougm * issue. 4206f85463f2Sdougm */ 4207f85463f2Sdougm if (ret != SA_OK) { 4208f85463f2Sdougm sa_free_protoset(options); 4209f85463f2Sdougm options = NULL; 4210f85463f2Sdougm } 4211f85463f2Sdougm return (options); 4212f85463f2Sdougm } 4213f85463f2Sdougm 4214da6c28aaSamw /* 4215da6c28aaSamw * sa_enable_resource, protocol) 4216da6c28aaSamw * Disable the specified share to the specified protocol. 4217da6c28aaSamw * If protocol is NULL, then all protocols. 4218da6c28aaSamw */ 4219da6c28aaSamw int 4220da6c28aaSamw sa_enable_resource(sa_resource_t resource, char *protocol) 4221da6c28aaSamw { 4222da6c28aaSamw int ret = SA_OK; 4223da6c28aaSamw 4224da6c28aaSamw if (protocol != NULL) { 4225da6c28aaSamw ret = sa_proto_share_resource(protocol, resource); 4226da6c28aaSamw } else { 4227f85463f2Sdougm sa_optionset_t protoset; 4228f85463f2Sdougm sa_property_t prop; 4229f85463f2Sdougm char *proto; 4230f85463f2Sdougm int err; 4231f85463f2Sdougm 4232da6c28aaSamw /* need to do all protocols */ 4233f85463f2Sdougm protoset = sa_get_active_protocols(resource); 4234f85463f2Sdougm if (protoset == NULL) 4235f85463f2Sdougm return (SA_NO_MEMORY); 4236f85463f2Sdougm for (prop = sa_get_property(protoset, NULL); 4237f85463f2Sdougm prop != NULL; 4238f85463f2Sdougm prop = sa_get_next_property(prop)) { 4239f85463f2Sdougm proto = sa_get_property_attr(prop, "type"); 4240f85463f2Sdougm if (proto == NULL) { 4241f85463f2Sdougm ret = SA_NO_MEMORY; 4242f85463f2Sdougm continue; 4243da6c28aaSamw } 4244f85463f2Sdougm err = sa_proto_share_resource(proto, resource); 4245f85463f2Sdougm if (err != SA_OK) 4246f85463f2Sdougm ret = err; 4247f85463f2Sdougm sa_free_attr_string(proto); 4248da6c28aaSamw } 4249f85463f2Sdougm sa_free_protoset(protoset); 4250da6c28aaSamw } 4251da6c28aaSamw if (ret == SA_OK) 4252da6c28aaSamw (void) sa_set_resource_attr(resource, "shared", NULL); 4253da6c28aaSamw 4254da6c28aaSamw return (ret); 4255da6c28aaSamw } 4256da6c28aaSamw 4257da6c28aaSamw /* 4258da6c28aaSamw * sa_disable_resource(resource, protocol) 4259da6c28aaSamw * 4260da6c28aaSamw * Disable the specified share for the specified protocol. If 4261da6c28aaSamw * protocol is NULL, then all protocols. If the underlying 4262da6c28aaSamw * protocol doesn't implement disable at the resource level, we 4263da6c28aaSamw * disable at the share level. 4264da6c28aaSamw */ 4265da6c28aaSamw int 4266da6c28aaSamw sa_disable_resource(sa_resource_t resource, char *protocol) 4267da6c28aaSamw { 4268da6c28aaSamw int ret = SA_OK; 4269da6c28aaSamw 4270da6c28aaSamw if (protocol != NULL) { 4271da6c28aaSamw ret = sa_proto_unshare_resource(protocol, resource); 4272da6c28aaSamw if (ret == SA_NOT_IMPLEMENTED) { 4273da6c28aaSamw sa_share_t parent; 4274da6c28aaSamw /* 4275da6c28aaSamw * The protocol doesn't implement unshare 4276da6c28aaSamw * resource. That implies that resource names are 4277da6c28aaSamw * simple aliases for this protocol so we need to 4278da6c28aaSamw * unshare the share. 4279da6c28aaSamw */ 4280da6c28aaSamw parent = sa_get_resource_parent(resource); 4281da6c28aaSamw if (parent != NULL) 4282da6c28aaSamw ret = sa_disable_share(parent, protocol); 4283da6c28aaSamw else 4284da6c28aaSamw ret = SA_CONFIG_ERR; 4285da6c28aaSamw } 4286da6c28aaSamw } else { 4287f85463f2Sdougm sa_optionset_t protoset; 4288f85463f2Sdougm sa_property_t prop; 4289f85463f2Sdougm char *proto; 4290f85463f2Sdougm int err; 4291f85463f2Sdougm 4292da6c28aaSamw /* need to do all protocols */ 4293f85463f2Sdougm protoset = sa_get_active_protocols(resource); 4294f85463f2Sdougm if (protoset == NULL) 4295f85463f2Sdougm return (SA_NO_MEMORY); 4296f85463f2Sdougm for (prop = sa_get_property(protoset, NULL); 4297f85463f2Sdougm prop != NULL; 4298f85463f2Sdougm prop = sa_get_next_property(prop)) { 4299f85463f2Sdougm proto = sa_get_property_attr(prop, "type"); 4300f85463f2Sdougm if (proto == NULL) { 4301f85463f2Sdougm ret = SA_NO_MEMORY; 4302f85463f2Sdougm continue; 4303da6c28aaSamw } 4304f85463f2Sdougm err = sa_proto_unshare_resource(proto, resource); 4305f85463f2Sdougm if (err == SA_NOT_SUPPORTED) { 4306f85463f2Sdougm sa_share_t parent; 4307f85463f2Sdougm parent = sa_get_resource_parent(resource); 4308f85463f2Sdougm if (parent != NULL) 4309f85463f2Sdougm err = sa_disable_share(parent, proto); 4310f85463f2Sdougm else 4311f85463f2Sdougm err = SA_CONFIG_ERR; 4312f85463f2Sdougm } 4313f85463f2Sdougm if (err != SA_OK) 4314f85463f2Sdougm ret = err; 4315f85463f2Sdougm sa_free_attr_string(proto); 4316da6c28aaSamw } 4317f85463f2Sdougm sa_free_protoset(protoset); 4318da6c28aaSamw } 4319da6c28aaSamw if (ret == SA_OK) 4320da6c28aaSamw (void) sa_set_resource_attr(resource, "shared", NULL); 4321da6c28aaSamw 4322da6c28aaSamw return (ret); 4323da6c28aaSamw } 4324da6c28aaSamw 4325da6c28aaSamw /* 4326da6c28aaSamw * sa_set_resource_description(resource, content) 4327da6c28aaSamw * 4328da6c28aaSamw * Set the description of share to content. 4329da6c28aaSamw */ 4330da6c28aaSamw 4331da6c28aaSamw int 4332da6c28aaSamw sa_set_resource_description(sa_resource_t resource, char *content) 4333da6c28aaSamw { 4334da6c28aaSamw xmlNodePtr node; 4335da6c28aaSamw sa_group_t group; 4336da6c28aaSamw sa_share_t share; 4337da6c28aaSamw int ret = SA_OK; 4338da6c28aaSamw 4339da6c28aaSamw for (node = ((xmlNodePtr)resource)->children; 4340da6c28aaSamw node != NULL; 4341da6c28aaSamw node = node->next) { 4342da6c28aaSamw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) { 4343da6c28aaSamw break; 4344da6c28aaSamw } 4345da6c28aaSamw } 4346da6c28aaSamw 4347da6c28aaSamw /* no existing description but want to add */ 4348da6c28aaSamw if (node == NULL && content != NULL) { 4349da6c28aaSamw /* add a description */ 4350da6c28aaSamw node = _sa_set_share_description(resource, content); 4351da6c28aaSamw } else if (node != NULL && content != NULL) { 4352da6c28aaSamw /* update a description */ 4353da6c28aaSamw xmlNodeSetContent(node, (xmlChar *)content); 4354da6c28aaSamw } else if (node != NULL && content == NULL) { 4355da6c28aaSamw /* remove an existing description */ 4356da6c28aaSamw xmlUnlinkNode(node); 4357da6c28aaSamw xmlFreeNode(node); 4358da6c28aaSamw } 4359*148c5f43SAlan Wright 4360da6c28aaSamw share = sa_get_resource_parent(resource); 4361da6c28aaSamw group = sa_get_parent_group(share); 4362*148c5f43SAlan Wright if (group != NULL && 4363*148c5f43SAlan Wright sa_is_persistent(share) && (!sa_group_is_zfs(group))) { 4364da6c28aaSamw sa_handle_impl_t impl_handle; 4365da6c28aaSamw impl_handle = (sa_handle_impl_t)sa_find_group_handle(group); 4366da6c28aaSamw if (impl_handle != NULL) 4367da6c28aaSamw ret = sa_commit_share(impl_handle->scfhandle, 4368da6c28aaSamw group, share); 4369da6c28aaSamw else 4370da6c28aaSamw ret = SA_SYSTEM_ERR; 4371da6c28aaSamw } 4372da6c28aaSamw return (ret); 4373da6c28aaSamw } 4374da6c28aaSamw 4375da6c28aaSamw /* 4376da6c28aaSamw * sa_get_resource_description(share) 4377da6c28aaSamw * 4378da6c28aaSamw * Return the description text for the specified share if it 4379da6c28aaSamw * exists. NULL if no description exists. 4380da6c28aaSamw */ 4381da6c28aaSamw 4382da6c28aaSamw char * 4383da6c28aaSamw sa_get_resource_description(sa_resource_t resource) 4384da6c28aaSamw { 4385da6c28aaSamw xmlChar *description = NULL; 4386da6c28aaSamw xmlNodePtr node; 4387da6c28aaSamw 4388da6c28aaSamw for (node = ((xmlNodePtr)resource)->children; node != NULL; 4389da6c28aaSamw node = node->next) { 4390da6c28aaSamw if (xmlStrcmp(node->name, (xmlChar *)"description") == 0) 4391da6c28aaSamw break; 4392da6c28aaSamw } 4393da6c28aaSamw if (node != NULL) { 4394da6c28aaSamw description = xmlNodeGetContent(node); 4395da6c28aaSamw fixproblemchars((char *)description); 4396da6c28aaSamw } 4397da6c28aaSamw return ((char *)description); 4398da6c28aaSamw } 4399