dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libshare / common / scfutil.c
blob4b71faee5df195f89f169a66b50ca5e6940d9e0f
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* helper functions for using libscf with sharemgr */
29 #include <libscf.h>
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32 #include "libshare.h"
33 #include "libshare_impl.h"
34 #include "scfutil.h"
35 #include <string.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <uuid/uuid.h>
39 #include <sys/param.h>
40 #include <signal.h>
41 #include <sys/time.h>
42 #include <libintl.h>
44 ssize_t scf_max_name_len;
45 extern struct sa_proto_plugin *sap_proto_list;
46 extern sa_handle_impl_t get_handle_for_root(xmlNodePtr);
47 static void set_transaction_tstamp(sa_handle_impl_t);
49 * The SMF facility uses some properties that must exist. We want to
50 * skip over these when processing protocol options.
52 static char *skip_props[] = {
53 "modify_authorization",
54 "action_authorization",
55 "value_authorization",
56 NULL
60 * sa_scf_fini(handle)
62 * Must be called when done. Called with the handle allocated in
63 * sa_scf_init(), it cleans up the state and frees any SCF resources
64 * still in use. Called by sa_fini().
67 void
68 sa_scf_fini(scfutilhandle_t *handle)
70 if (handle != NULL) {
71 int unbind = 0;
72 if (handle->scope != NULL) {
73 unbind = 1;
74 scf_scope_destroy(handle->scope);
76 if (handle->instance != NULL)
77 scf_instance_destroy(handle->instance);
78 if (handle->service != NULL)
79 scf_service_destroy(handle->service);
80 if (handle->pg != NULL)
81 scf_pg_destroy(handle->pg);
82 if (handle->handle != NULL) {
83 handle->scf_state = SCH_STATE_UNINIT;
84 if (unbind)
85 (void) scf_handle_unbind(handle->handle);
86 scf_handle_destroy(handle->handle);
88 free(handle);
93 * sa_scf_init()
95 * Must be called before using any of the SCF functions. Called by
96 * sa_init() during the API setup.
99 scfutilhandle_t *
100 sa_scf_init(sa_handle_impl_t ihandle)
102 scfutilhandle_t *handle;
104 scf_max_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH);
105 if (scf_max_name_len <= 0)
106 scf_max_name_len = SA_MAX_NAME_LEN + 1;
108 handle = calloc(1, sizeof (scfutilhandle_t));
109 if (handle == NULL)
110 return (handle);
112 ihandle->scfhandle = handle;
113 handle->scf_state = SCH_STATE_INITIALIZING;
114 handle->handle = scf_handle_create(SCF_VERSION);
115 if (handle->handle == NULL) {
116 free(handle);
117 handle = NULL;
118 (void) printf("libshare could not access SMF repository: %s\n",
119 scf_strerror(scf_error()));
120 return (handle);
122 if (scf_handle_bind(handle->handle) != 0)
123 goto err;
125 handle->scope = scf_scope_create(handle->handle);
126 handle->service = scf_service_create(handle->handle);
127 handle->pg = scf_pg_create(handle->handle);
129 /* Make sure we have sufficient SMF running */
130 handle->instance = scf_instance_create(handle->handle);
131 if (handle->scope == NULL || handle->service == NULL ||
132 handle->pg == NULL || handle->instance == NULL)
133 goto err;
134 if (scf_handle_get_scope(handle->handle,
135 SCF_SCOPE_LOCAL, handle->scope) != 0)
136 goto err;
137 if (scf_scope_get_service(handle->scope,
138 SA_GROUP_SVC_NAME, handle->service) != 0)
139 goto err;
141 handle->scf_state = SCH_STATE_INIT;
142 if (sa_get_instance(handle, "default") != SA_OK) {
143 sa_group_t defgrp;
144 defgrp = sa_create_group((sa_handle_t)ihandle, "default", NULL);
145 /* Only NFS enabled for "default" group. */
146 if (defgrp != NULL)
147 (void) sa_create_optionset(defgrp, "nfs");
150 return (handle);
152 /* Error handling/unwinding */
153 err:
154 (void) sa_scf_fini(handle);
155 (void) printf("libshare SMF initialization problem: %s\n",
156 scf_strerror(scf_error()));
157 return (NULL);
161 * get_scf_limit(name)
163 * Since we use scf_limit a lot and do the same check and return the
164 * same value if it fails, implement as a function for code
165 * simplification. Basically, if name isn't found, return MAXPATHLEN
166 * (1024) so we have a reasonable default buffer size.
168 static ssize_t
169 get_scf_limit(uint32_t name)
171 ssize_t vallen;
173 vallen = scf_limit(name);
174 if (vallen == (ssize_t)-1)
175 vallen = MAXPATHLEN;
176 return (vallen);
180 * skip_property(name)
182 * Internal function to check to see if a property is an SMF magic
183 * property that needs to be skipped.
185 static int
186 skip_property(char *name)
188 int i;
190 for (i = 0; skip_props[i] != NULL; i++)
191 if (strcmp(name, skip_props[i]) == 0)
192 return (1);
193 return (0);
197 * generate_unique_sharename(sharename)
199 * Shares are represented in SMF as property groups. Due to share
200 * paths containing characters that are not allowed in SMF names and
201 * the need to be unique, we use UUIDs to construct a unique name.
204 static void
205 generate_unique_sharename(char *sharename)
207 uuid_t uuid;
209 uuid_generate(uuid);
210 (void) strcpy(sharename, "S-");
211 uuid_unparse(uuid, sharename + 2);
215 * valid_protocol(proto)
217 * Check to see if the specified protocol is a valid one for the
218 * general sharemgr facility. We determine this by checking which
219 * plugin protocols were found.
222 static int
223 valid_protocol(char *proto)
225 struct sa_proto_plugin *plugin;
226 for (plugin = sap_proto_list; plugin != NULL;
227 plugin = plugin->plugin_next)
228 if (strcmp(proto, plugin->plugin_ops->sa_protocol) == 0)
229 return (1);
230 return (0);
234 * sa_extract_pgroup(root, handle, pg, nodetype, proto, sectype)
236 * Extract the name property group and create the specified type of
237 * node on the provided group. type will be optionset or security.
240 static int
241 sa_extract_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
242 scf_propertygroup_t *pg,
243 char *nodetype, char *proto, char *sectype)
245 xmlNodePtr node;
246 scf_iter_t *iter;
247 scf_property_t *prop;
248 scf_value_t *value;
249 char *name;
250 char *valuestr;
251 ssize_t vallen;
252 int ret = SA_OK;
254 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
256 node = xmlNewChild(root, NULL, (xmlChar *)nodetype, NULL);
257 if (node == NULL)
258 return (ret);
260 if (proto != NULL)
261 (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
262 if (sectype != NULL)
263 (void) xmlSetProp(node, (xmlChar *)"sectype",
264 (xmlChar *)sectype);
266 * Have node to work with so iterate over the properties
267 * in the pg and create option sub nodes.
269 iter = scf_iter_create(handle->handle);
270 value = scf_value_create(handle->handle);
271 prop = scf_property_create(handle->handle);
272 name = malloc(scf_max_name_len);
273 valuestr = malloc(vallen);
275 * Want to iterate through the properties and add them
276 * to the base optionset.
278 if (iter == NULL || value == NULL || prop == NULL ||
279 valuestr == NULL || name == NULL) {
280 ret = SA_NO_MEMORY;
281 goto out;
283 if (scf_iter_pg_properties(iter, pg) == 0) {
284 /* Now iterate the properties in the group */
285 while (scf_iter_next_property(iter, prop) > 0) {
286 /* have a property */
287 if (scf_property_get_name(prop, name,
288 scf_max_name_len) > 0) {
289 sa_property_t saprop;
290 /* Some properties are part of the framework */
291 if (skip_property(name))
292 continue;
293 if (scf_property_get_value(prop, value) != 0)
294 continue;
295 if (scf_value_get_astring(value, valuestr,
296 vallen) < 0)
297 continue;
298 saprop = sa_create_property(name, valuestr);
299 if (saprop != NULL) {
301 * Since in SMF, don't
302 * recurse. Use xmlAddChild
303 * directly, instead.
305 (void) xmlAddChild(node,
306 (xmlNodePtr) saprop);
311 out:
312 /* cleanup to avoid memory leaks */
313 if (value != NULL)
314 scf_value_destroy(value);
315 if (iter != NULL)
316 scf_iter_destroy(iter);
317 if (prop != NULL)
318 scf_property_destroy(prop);
319 free(name);
320 free(valuestr);
322 return (ret);
326 * sa_extract_attrs(root, handle, instance)
328 * Local function to extract the actual attributes/properties from the
329 * property group of the service instance. These are the well known
330 * attributes of "state" and "zfs". If additional attributes are
331 * added, they should be added here.
334 static void
335 sa_extract_attrs(xmlNodePtr root, scfutilhandle_t *handle,
336 scf_instance_t *instance)
338 scf_property_t *prop;
339 scf_value_t *value;
340 char *valuestr;
341 ssize_t vallen;
343 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
344 prop = scf_property_create(handle->handle);
345 value = scf_value_create(handle->handle);
346 valuestr = malloc(vallen);
347 if (prop == NULL || value == NULL || valuestr == NULL ||
348 scf_instance_get_pg(instance, "operation", handle->pg) != 0) {
349 goto out;
352 * Have a property group with desired name so now get
353 * the known attributes.
355 if (scf_pg_get_property(handle->pg, "state", prop) == 0) {
356 /* Found the property so get the value */
357 if (scf_property_get_value(prop, value) == 0) {
358 if (scf_value_get_astring(value, valuestr,
359 vallen) >= 0) {
360 (void) xmlSetProp(root, (xmlChar *)"state",
361 (xmlChar *)valuestr);
365 if (scf_pg_get_property(handle->pg, "zfs", prop) == 0) {
366 /* Found the property so get the value */
367 if (scf_property_get_value(prop, value) == 0) {
368 if (scf_value_get_astring(value, valuestr,
369 vallen) > 0) {
370 (void) xmlSetProp(root, (xmlChar *)"zfs",
371 (xmlChar *)valuestr);
375 out:
376 free(valuestr);
377 if (value != NULL)
378 scf_value_destroy(value);
379 if (prop != NULL)
380 scf_property_destroy(prop);
384 * List of known share attributes.
387 static char *share_attr[] = {
388 "path",
389 "id",
390 "drive-letter",
391 "exclude",
392 NULL,
395 static int
396 is_share_attr(char *name)
398 int i;
399 for (i = 0; share_attr[i] != NULL; i++)
400 if (strcmp(name, share_attr[i]) == 0)
401 return (1);
402 return (0);
406 * _sa_make_resource(node, valuestr)
408 * Make a resource node on the share node. The valusestr will either
409 * be old format (SMF acceptable string) or new format (pretty much an
410 * arbitrary string with "nnn:" prefixing in order to persist
411 * mapping). The input valuestr will get modified in place. This is
412 * only used in SMF repository parsing. A possible third field will be
413 * a "description" string.
416 static void
417 _sa_make_resource(xmlNodePtr node, char *valuestr)
419 char *idx;
420 char *name;
421 char *description = NULL;
423 idx = valuestr;
424 name = strchr(valuestr, ':');
425 if (name == NULL) {
426 /* this is old form so give an index of "0" */
427 idx = "0";
428 name = valuestr;
429 } else {
430 /* NUL the ':' and move past it */
431 *name++ = '\0';
432 /* There could also be a description string */
433 description = strchr(name, ':');
434 if (description != NULL)
435 *description++ = '\0';
437 node = xmlNewChild(node, NULL, (xmlChar *)"resource", NULL);
438 if (node != NULL) {
439 (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)name);
440 (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)idx);
441 /* SMF values are always persistent */
442 (void) xmlSetProp(node, (xmlChar *)"type",
443 (xmlChar *)"persist");
444 if (description != NULL && strlen(description) > 0) {
445 (void) xmlNewChild(node, NULL, (xmlChar *)"description",
446 (xmlChar *)description);
453 * sa_share_from_pgroup
455 * Extract the share definition from the share property group. We do
456 * some sanity checking to avoid bad data.
458 * Since this is only constructing the internal data structures, we
459 * don't use the sa_* functions most of the time.
461 void
462 sa_share_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
463 scf_propertygroup_t *pg, char *id)
465 xmlNodePtr node;
466 char *name;
467 scf_iter_t *iter;
468 scf_property_t *prop;
469 scf_value_t *value;
470 ssize_t vallen;
471 char *valuestr;
472 int ret = SA_OK;
473 int have_path = 0;
476 * While preliminary check (starts with 'S') passed before
477 * getting here. Need to make sure it is in ID syntax
478 * (Snnnnnn). Note that shares with properties have similar
479 * pgroups.
481 vallen = strlen(id);
482 if (*id == SA_SHARE_PG_PREFIX[0] && vallen == SA_SHARE_PG_LEN) {
483 uuid_t uuid;
484 if (strncmp(id, SA_SHARE_PG_PREFIX,
485 SA_SHARE_PG_PREFIXLEN) != 0 ||
486 uuid_parse(id + 2, uuid) < 0)
487 return;
488 } else {
489 return;
492 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
494 iter = scf_iter_create(handle->handle);
495 value = scf_value_create(handle->handle);
496 prop = scf_property_create(handle->handle);
497 name = malloc(scf_max_name_len);
498 valuestr = malloc(vallen);
501 * Construct the share XML node. It is similar to sa_add_share
502 * but never changes the repository. Also, there won't be any
503 * ZFS or transient shares. Root will be the group it is
504 * associated with.
506 node = xmlNewChild(root, NULL, (xmlChar *)"share", NULL);
507 if (node != NULL) {
509 * Make sure the UUID part of the property group is
510 * stored in the share "id" property. We use this
511 * later.
513 (void) xmlSetProp(node, (xmlChar *)"id", (xmlChar *)id);
514 (void) xmlSetProp(node, (xmlChar *)"type",
515 (xmlChar *)"persist");
518 if (iter == NULL || value == NULL || prop == NULL || name == NULL)
519 goto out;
521 /* Iterate over the share pg properties */
522 if (scf_iter_pg_properties(iter, pg) != 0)
523 goto out;
525 while (scf_iter_next_property(iter, prop) > 0) {
526 ret = SA_SYSTEM_ERR; /* assume the worst */
527 if (scf_property_get_name(prop, name, scf_max_name_len) > 0) {
528 if (scf_property_get_value(prop, value) == 0) {
529 if (scf_value_get_astring(value, valuestr,
530 vallen) >= 0) {
531 ret = SA_OK;
533 } else if (strcmp(name, "resource") == 0) {
534 ret = SA_OK;
537 if (ret != SA_OK)
538 continue;
540 * Check that we have the "path" property in
541 * name. The string in name will always be nul
542 * terminated if scf_property_get_name()
543 * succeeded.
545 if (strcmp(name, "path") == 0)
546 have_path = 1;
547 if (is_share_attr(name)) {
549 * If a share attr, then simple -
550 * usually path and id name
552 (void) xmlSetProp(node, (xmlChar *)name,
553 (xmlChar *)valuestr);
554 } else if (strcmp(name, "resource") == 0) {
556 * Resource names handled differently since
557 * there can be multiple on each share. The
558 * "resource" id must be preserved since this
559 * will be used by some protocols in mapping
560 * "property spaces" to names and is always
561 * used to create SMF property groups specific
562 * to resources. CIFS needs this. The first
563 * value is present so add and then loop for
564 * any additional. Since this is new and
565 * previous values may exist, handle
566 * conversions.
568 scf_iter_t *viter;
569 viter = scf_iter_create(handle->handle);
570 if (viter != NULL &&
571 scf_iter_property_values(viter, prop) == 0) {
572 while (scf_iter_next_value(viter, value) > 0) {
573 /* Have a value so process it */
574 if (scf_value_get_ustring(value,
575 valuestr, vallen) >= 0) {
576 /* have a ustring */
577 _sa_make_resource(node,
578 valuestr);
579 } else if (scf_value_get_astring(value,
580 valuestr, vallen) >= 0) {
581 /* have an astring */
582 _sa_make_resource(node,
583 valuestr);
586 scf_iter_destroy(viter);
588 } else {
589 if (strcmp(name, "description") == 0) {
590 /* We have a description node */
591 xmlNodePtr desc;
592 desc = xmlNewChild(node, NULL,
593 (xmlChar *)"description", NULL);
594 if (desc != NULL)
595 xmlNodeSetContent(desc,
596 (xmlChar *)valuestr);
600 out:
602 * A share without a path is broken so we want to not include
603 * these. They shouldn't happen but if you kill a sharemgr in
604 * the process of creating a share, it could happen. They
605 * should be harmless. It is also possible that another
606 * sharemgr is running and in the process of creating a share.
608 if (have_path == 0 && node != NULL) {
609 xmlUnlinkNode(node);
610 xmlFreeNode(node);
612 free(name);
613 free(valuestr);
614 if (value != NULL)
615 scf_value_destroy(value);
616 if (iter != NULL)
617 scf_iter_destroy(iter);
618 if (prop != NULL)
619 scf_property_destroy(prop);
623 * find_share_by_id(shareid)
625 * Search all shares in all groups until we find the share represented
626 * by "id".
629 static sa_share_t
630 find_share_by_id(sa_handle_t handle, char *shareid)
632 sa_group_t group;
633 sa_share_t share = NULL;
634 char *id = NULL;
635 int done = 0;
637 for (group = sa_get_group(handle, NULL);
638 group != NULL && !done;
639 group = sa_get_next_group(group)) {
640 for (share = sa_get_share(group, NULL);
641 share != NULL;
642 share = sa_get_next_share(share)) {
643 id = sa_get_share_attr(share, "id");
644 if (id != NULL && strcmp(id, shareid) == 0) {
645 sa_free_attr_string(id);
646 id = NULL;
647 done++;
648 break;
650 if (id != NULL) {
651 sa_free_attr_string(id);
652 id = NULL;
656 return (share);
660 * find_resource_by_index(share, index)
662 * Search the resource records on the share for the id index.
664 static sa_resource_t
665 find_resource_by_index(sa_share_t share, char *index)
667 sa_resource_t resource;
668 sa_resource_t found = NULL;
669 char *id;
671 for (resource = sa_get_share_resource(share, NULL);
672 resource != NULL && found == NULL;
673 resource = sa_get_next_resource(resource)) {
674 id = (char *)xmlGetProp((xmlNodePtr)resource, (xmlChar *)"id");
675 if (id != NULL) {
676 if (strcmp(id, index) == 0) {
677 /* found it so save in "found" */
678 found = resource;
680 sa_free_attr_string(id);
683 return (found);
687 * sa_share_props_from_pgroup(root, handle, pg, id, sahandle)
689 * Extract share properties from the SMF property group. More sanity
690 * checks are done and the share object is created. We ignore some
691 * errors that could exist in the repository and only worry about
692 * property groups that validate in naming.
695 static int
696 sa_share_props_from_pgroup(xmlNodePtr root, scfutilhandle_t *handle,
697 scf_propertygroup_t *pg, char *id, sa_handle_t sahandle)
699 xmlNodePtr node;
700 char *name = NULL;
701 scf_iter_t *iter = NULL;
702 scf_property_t *prop = NULL;
703 scf_value_t *value = NULL;
704 ssize_t vallen;
705 char *valuestr = NULL;
706 int ret = SA_OK;
707 char *sectype = NULL;
708 char *proto;
709 sa_share_t share;
710 uuid_t uuid;
713 * While preliminary check (starts with 'S') passed before
714 * getting here. Need to make sure it is in ID syntax
715 * (Snnnnnn). Note that shares with properties have similar
716 * pgroups. If the pg name is more than SA_SHARE_PG_LEN
717 * characters, it is likely one of the protocol/security
718 * versions.
720 vallen = strlen(id);
721 if (*id != SA_SHARE_PG_PREFIX[0] || vallen <= SA_SHARE_PG_LEN) {
723 * It is ok to not have what we thought since someone might
724 * have added a name via SMF.
726 return (ret);
728 if (strncmp(id, SA_SHARE_PG_PREFIX, SA_SHARE_PG_PREFIXLEN) == 0) {
729 proto = strchr(id, '_');
730 if (proto == NULL)
731 return (ret);
732 *proto++ = '\0';
733 if (uuid_parse(id + SA_SHARE_PG_PREFIXLEN, uuid) < 0)
734 return (ret);
736 * probably a legal optionset so check a few more
737 * syntax points below.
739 if (*proto == '\0') {
740 /* not a valid proto (null) */
741 return (ret);
744 sectype = strchr(proto, '_');
745 if (sectype != NULL)
746 *sectype++ = '\0';
747 if (!valid_protocol(proto))
748 return (ret);
752 * To get here, we have a valid protocol and possibly a
753 * security. We now have to find the share that it is really
754 * associated with. The "id" portion of the pgroup name will
755 * match.
758 share = find_share_by_id(sahandle, id);
759 if (share == NULL)
760 return (SA_BAD_PATH);
762 root = (xmlNodePtr)share;
764 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
766 if (sectype == NULL)
767 node = xmlNewChild(root, NULL, (xmlChar *)"optionset", NULL);
768 else {
769 if (isdigit((int)*sectype)) {
770 sa_resource_t resource;
772 * If sectype[0] is a digit, then it is an index into
773 * the resource names. We need to find a resource
774 * record and then get the properties into an
775 * optionset. The optionset becomes the "node" and the
776 * rest is hung off of the share.
778 resource = find_resource_by_index(share, sectype);
779 if (resource != NULL) {
780 node = xmlNewChild(resource, NULL,
781 (xmlChar *)"optionset", NULL);
782 } else {
783 /* This shouldn't happen. */
784 ret = SA_SYSTEM_ERR;
785 goto out;
787 } else {
789 * If not a digit, then it is a security type
790 * (alternate option space). Security types start with
791 * an alphabetic.
793 node = xmlNewChild(root, NULL, (xmlChar *)"security",
794 NULL);
795 if (node != NULL)
796 (void) xmlSetProp(node, (xmlChar *)"sectype",
797 (xmlChar *)sectype);
800 if (node == NULL) {
801 ret = SA_NO_MEMORY;
802 goto out;
805 (void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
806 /* now find the properties */
807 iter = scf_iter_create(handle->handle);
808 value = scf_value_create(handle->handle);
809 prop = scf_property_create(handle->handle);
810 name = malloc(scf_max_name_len);
811 valuestr = malloc(vallen);
813 if (iter == NULL || value == NULL || prop == NULL || name == NULL)
814 goto out;
816 /* iterate over the share pg properties */
817 if (scf_iter_pg_properties(iter, pg) == 0) {
818 while (scf_iter_next_property(iter, prop) > 0) {
819 ret = SA_SYSTEM_ERR; /* assume the worst */
820 if (scf_property_get_name(prop, name,
821 scf_max_name_len) > 0) {
822 if (scf_property_get_value(prop, value) == 0) {
823 if (scf_value_get_astring(value,
824 valuestr, vallen) >= 0) {
825 ret = SA_OK;
828 } else {
829 ret = SA_SYSTEM_ERR;
831 if (ret == SA_OK) {
832 sa_property_t prop;
833 prop = sa_create_property(name, valuestr);
834 if (prop != NULL)
835 prop = (sa_property_t)xmlAddChild(node,
836 (xmlNodePtr)prop);
837 else
838 ret = SA_NO_MEMORY;
841 } else {
842 ret = SA_SYSTEM_ERR;
844 out:
845 if (iter != NULL)
846 scf_iter_destroy(iter);
847 if (value != NULL)
848 scf_value_destroy(value);
849 if (prop != NULL)
850 scf_property_destroy(prop);
851 free(name);
852 free(valuestr);
853 return (ret);
857 * sa_extract_group(root, handle, instance)
859 * Get the config info for this instance of a group and create the XML
860 * subtree from it.
863 static int
864 sa_extract_group(xmlNodePtr root, scfutilhandle_t *handle,
865 scf_instance_t *instance, sa_handle_t sahandle)
867 char *buff;
868 xmlNodePtr node;
869 scf_iter_t *iter;
870 char *proto;
871 char *sectype;
872 boolean_t have_shares = B_FALSE;
873 boolean_t is_default = B_FALSE;
874 boolean_t is_nfs = B_FALSE;
875 int ret = SA_OK;
876 int err;
878 buff = malloc(scf_max_name_len);
879 if (buff == NULL)
880 return (SA_NO_MEMORY);
882 iter = scf_iter_create(handle->handle);
883 if (iter == NULL) {
884 ret = SA_NO_MEMORY;
885 goto out;
888 if (scf_instance_get_name(instance, buff, scf_max_name_len) > 0) {
889 node = xmlNewChild(root, NULL, (xmlChar *)"group", NULL);
890 if (node == NULL) {
891 ret = SA_NO_MEMORY;
892 goto out;
894 (void) xmlSetProp(node, (xmlChar *)"name", (xmlChar *)buff);
895 if (strcmp(buff, "default") == 0)
896 is_default = B_TRUE;
898 sa_extract_attrs(node, handle, instance);
900 * Iterate through all the property groups
901 * looking for those with security or
902 * optionset prefixes. The names of the
903 * matching pgroups are parsed to get the
904 * protocol, and for security, the sectype.
905 * Syntax is as follows:
906 * optionset | optionset_<proto>
907 * security_default | security_<proto>_<sectype>
908 * "operation" is handled by
909 * sa_extract_attrs().
911 if (scf_iter_instance_pgs(iter, instance) != 0) {
912 ret = SA_NO_MEMORY;
913 goto out;
915 while (scf_iter_next_pg(iter, handle->pg) > 0) {
916 /* Have a pgroup so sort it out */
917 ret = scf_pg_get_name(handle->pg, buff,
918 scf_max_name_len);
919 if (ret <= 0)
920 continue;
921 is_nfs = B_FALSE;
923 if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
924 sa_share_from_pgroup(node, handle,
925 handle->pg, buff);
926 have_shares = B_TRUE;
927 } else if (strncmp(buff, "optionset", 9) == 0) {
928 char *nodetype = "optionset";
929 /* Have an optionset */
930 sectype = NULL;
931 proto = strchr(buff, '_');
932 if (proto != NULL) {
933 *proto++ = '\0';
934 sectype = strchr(proto, '_');
935 if (sectype != NULL) {
936 *sectype++ = '\0';
937 nodetype = "security";
939 is_nfs = strcmp(proto, "nfs") == 0;
940 } else if (strlen(buff) > 9) {
942 * This can only occur if
943 * someone has made changes
944 * via an SMF command. Since
945 * this would be an unknown
946 * syntax, we just ignore it.
948 continue;
951 * If the group is not "default" or is
952 * "default" and is_nfs, then extract the
953 * pgroup. If it is_default and !is_nfs,
954 * then we have an error and should remove
955 * the extraneous protocols. We don't care
956 * about errors on scf_pg_delete since we
957 * might not have permission during an
958 * extract only.
960 if (!is_default || is_nfs) {
961 ret = sa_extract_pgroup(node, handle,
962 handle->pg, nodetype, proto,
963 sectype);
964 } else {
965 err = scf_pg_delete(handle->pg);
966 if (err == 0)
967 (void) fprintf(stderr,
968 dgettext(TEXT_DOMAIN,
969 "Removed protocol \"%s\" "
970 "from group \"default\"\n"),
971 proto);
973 } else if (strncmp(buff, "security", 8) == 0) {
975 * Have a security (note that
976 * this should change in the
977 * future)
979 proto = strchr(buff, '_');
980 sectype = NULL;
981 if (proto != NULL) {
982 *proto++ = '\0';
983 sectype = strchr(proto, '_');
984 if (sectype != NULL)
985 *sectype++ = '\0';
986 if (strcmp(proto, "default") == 0)
987 proto = NULL;
989 ret = sa_extract_pgroup(node, handle,
990 handle->pg, "security", proto, sectype);
992 /* Ignore everything else */
995 * Make sure we have a valid default group.
996 * On first boot, default won't have any
997 * protocols defined and won't be enabled (but
998 * should be). "default" only has NFS enabled on it.
1000 if (is_default) {
1001 char *state = sa_get_group_attr((sa_group_t)node,
1002 "state");
1004 if (state == NULL) {
1005 /* set attribute to enabled */
1006 (void) sa_set_group_attr((sa_group_t)node,
1007 "state", "enabled");
1008 (void) sa_create_optionset((sa_group_t)node,
1009 "nfs");
1010 } else {
1011 sa_free_attr_string(state);
1014 /* Do a second pass if shares were found */
1015 if (have_shares && scf_iter_instance_pgs(iter, instance) == 0) {
1016 while (scf_iter_next_pg(iter, handle->pg) > 0) {
1018 * Have a pgroup so see if it is a
1019 * share optionset
1021 err = scf_pg_get_name(handle->pg, buff,
1022 scf_max_name_len);
1023 if (err <= 0)
1024 continue;
1025 if (buff[0] == SA_SHARE_PG_PREFIX[0]) {
1026 ret = sa_share_props_from_pgroup(node,
1027 handle, handle->pg, buff,
1028 sahandle);
1033 out:
1034 if (iter != NULL)
1035 scf_iter_destroy(iter);
1036 free(buff);
1037 return (ret);
1041 * sa_extract_defaults(root, handle, instance)
1043 * Local function to find the default properties that live in the
1044 * default instance's "operation" property group.
1047 static void
1048 sa_extract_defaults(xmlNodePtr root, scfutilhandle_t *handle,
1049 scf_instance_t *instance)
1051 xmlNodePtr node;
1052 scf_property_t *prop;
1053 scf_value_t *value;
1054 char *valuestr;
1055 ssize_t vallen;
1057 vallen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1058 prop = scf_property_create(handle->handle);
1059 value = scf_value_create(handle->handle);
1060 valuestr = malloc(vallen);
1062 if (prop == NULL || value == NULL || vallen == 0 ||
1063 scf_instance_get_pg(instance, "operation", handle->pg) != 0)
1064 goto out;
1066 if (scf_pg_get_property(handle->pg, "legacy-timestamp", prop) != 0)
1067 goto out;
1069 /* Found the property so get the value */
1070 if (scf_property_get_value(prop, value) == 0) {
1071 if (scf_value_get_astring(value, valuestr, vallen) > 0) {
1072 node = xmlNewChild(root, NULL, (xmlChar *)"legacy",
1073 NULL);
1074 if (node != NULL) {
1075 (void) xmlSetProp(node, (xmlChar *)"timestamp",
1076 (xmlChar *)valuestr);
1077 (void) xmlSetProp(node, (xmlChar *)"path",
1078 (xmlChar *)SA_LEGACY_DFSTAB);
1082 out:
1083 free(valuestr);
1084 if (value != NULL)
1085 scf_value_destroy(value);
1086 if (prop != NULL)
1087 scf_property_destroy(prop);
1092 * sa_get_config(handle, root, doc, sahandle)
1094 * Walk the SMF repository for /network/shares/group and find all the
1095 * instances. These become group names. Then add the XML structure
1096 * below the groups based on property groups and properties.
1099 sa_get_config(scfutilhandle_t *handle, xmlNodePtr root, sa_handle_t sahandle)
1101 int ret = SA_OK;
1102 scf_instance_t *instance;
1103 scf_iter_t *iter;
1104 char buff[BUFSIZ * 2];
1106 instance = scf_instance_create(handle->handle);
1107 iter = scf_iter_create(handle->handle);
1108 if (instance != NULL && iter != NULL) {
1109 if ((ret = scf_iter_service_instances(iter,
1110 handle->service)) == 0) {
1111 while ((ret = scf_iter_next_instance(iter,
1112 instance)) > 0) {
1113 if (scf_instance_get_name(instance, buff,
1114 sizeof (buff)) > 0) {
1115 if (strcmp(buff, "default") == 0)
1116 sa_extract_defaults(root,
1117 handle, instance);
1118 ret = sa_extract_group(root, handle,
1119 instance, sahandle);
1125 /* Always cleanup these */
1126 if (instance != NULL)
1127 scf_instance_destroy(instance);
1128 if (iter != NULL)
1129 scf_iter_destroy(iter);
1130 return (ret);
1134 * sa_get_instance(handle, instance)
1136 * Get the instance of the group service. This is actually the
1137 * specific group name. The instance is needed for all property and
1138 * control operations.
1142 sa_get_instance(scfutilhandle_t *handle, char *instname)
1144 if (scf_service_get_instance(handle->service, instname,
1145 handle->instance) != 0) {
1146 return (SA_NO_SUCH_GROUP);
1148 return (SA_OK);
1152 * sa_create_instance(handle, instname)
1154 * Create a new SMF service instance. There can only be one with a
1155 * given name.
1159 sa_create_instance(scfutilhandle_t *handle, char *instname)
1161 int ret = SA_OK;
1162 char instance[SA_GROUP_INST_LEN];
1163 if (scf_service_add_instance(handle->service, instname,
1164 handle->instance) != 0) {
1165 /* better error returns need to be added based on real error */
1166 if (scf_error() == SCF_ERROR_PERMISSION_DENIED)
1167 ret = SA_NO_PERMISSION;
1168 else
1169 ret = SA_DUPLICATE_NAME;
1170 } else {
1171 /* have the service created, so enable it */
1172 (void) snprintf(instance, sizeof (instance), "%s:%s",
1173 SA_SVC_FMRI_BASE, instname);
1174 (void) smf_enable_instance(instance, 0);
1176 return (ret);
1180 * sa_delete_instance(handle, instname)
1182 * When a group goes away, we also remove the service instance.
1186 sa_delete_instance(scfutilhandle_t *handle, char *instname)
1188 int ret;
1190 if (strcmp(instname, "default") == 0) {
1191 ret = SA_NO_PERMISSION;
1192 } else {
1193 if ((ret = sa_get_instance(handle, instname)) == SA_OK) {
1194 if (scf_instance_delete(handle->instance) != 0)
1195 /* need better analysis */
1196 ret = SA_NO_PERMISSION;
1199 return (ret);
1203 * sa_create_pgroup(handle, pgroup)
1205 * create a new property group
1209 sa_create_pgroup(scfutilhandle_t *handle, char *pgroup)
1211 int ret = SA_OK;
1212 int persist = 0;
1215 * Only create a handle if it doesn't exist. It is ok to exist
1216 * since the pg handle will be set as a side effect.
1218 if (handle->pg == NULL)
1219 handle->pg = scf_pg_create(handle->handle);
1222 * Special case for a non-persistent property group. This is
1223 * internal use only.
1225 if (*pgroup == '*') {
1226 persist = SCF_PG_FLAG_NONPERSISTENT;
1227 pgroup++;
1231 * If the pgroup exists, we are done. If it doesn't, then we
1232 * need to actually add one to the service instance.
1234 if (scf_instance_get_pg(handle->instance,
1235 pgroup, handle->pg) != 0) {
1237 /* Doesn't exist so create one */
1238 if (scf_instance_add_pg(handle->instance, pgroup,
1239 SCF_GROUP_APPLICATION, persist, handle->pg) != 0) {
1240 switch (scf_error()) {
1241 case SCF_ERROR_PERMISSION_DENIED:
1242 ret = SA_NO_PERMISSION;
1243 break;
1244 default:
1245 ret = SA_SYSTEM_ERR;
1246 break;
1250 return (ret);
1254 * sa_delete_pgroup(handle, pgroup)
1256 * Remove the property group from the current instance of the service,
1257 * but only if it actually exists.
1261 sa_delete_pgroup(scfutilhandle_t *handle, char *pgroup)
1263 int ret = SA_OK;
1265 * Only delete if it does exist.
1267 if (scf_instance_get_pg(handle->instance, pgroup, handle->pg) == 0) {
1268 /* does exist so delete it */
1269 if (scf_pg_delete(handle->pg) != 0)
1270 ret = SA_SYSTEM_ERR;
1271 } else {
1272 ret = SA_SYSTEM_ERR;
1274 if (ret == SA_SYSTEM_ERR &&
1275 scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1276 ret = SA_NO_PERMISSION;
1278 return (ret);
1282 * sa_start_transaction(handle, pgroup)
1284 * Start an SMF transaction so we can deal with properties. it would
1285 * be nice to not have to expose this, but we have to in order to
1286 * optimize.
1288 * Basic model is to hold the transaction in the handle and allow
1289 * property adds/deletes/updates to be added then close the
1290 * transaction (or abort). There may eventually be a need to handle
1291 * other types of transaction mechanisms but we don't do that now.
1293 * An sa_start_transaction must be followed by either an
1294 * sa_end_transaction or sa_abort_transaction before another
1295 * sa_start_transaction can be done.
1299 sa_start_transaction(scfutilhandle_t *handle, char *propgroup)
1301 int ret = SA_OK;
1303 * Lookup the property group and create it if it doesn't already
1304 * exist.
1306 if (handle == NULL)
1307 return (SA_CONFIG_ERR);
1309 if (handle->scf_state == SCH_STATE_INIT) {
1310 ret = sa_create_pgroup(handle, propgroup);
1311 if (ret == SA_OK) {
1312 handle->trans = scf_transaction_create(handle->handle);
1313 if (handle->trans != NULL) {
1314 if (scf_transaction_start(handle->trans,
1315 handle->pg) != 0) {
1316 ret = SA_SYSTEM_ERR;
1318 if (ret != SA_OK) {
1319 scf_transaction_destroy(handle->trans);
1320 handle->trans = NULL;
1322 } else {
1323 ret = SA_SYSTEM_ERR;
1327 if (ret == SA_SYSTEM_ERR &&
1328 scf_error() == SCF_ERROR_PERMISSION_DENIED) {
1329 ret = SA_NO_PERMISSION;
1331 return (ret);
1336 * sa_end_transaction(scfhandle, sahandle)
1338 * Commit the changes that were added to the transaction in the
1339 * handle. Do all necessary cleanup.
1343 sa_end_transaction(scfutilhandle_t *handle, sa_handle_impl_t sahandle)
1345 int ret = SA_OK;
1347 if (handle == NULL || handle->trans == NULL || sahandle == NULL) {
1348 ret = SA_SYSTEM_ERR;
1349 } else {
1350 if (scf_transaction_commit(handle->trans) < 0)
1351 ret = SA_SYSTEM_ERR;
1352 scf_transaction_destroy_children(handle->trans);
1353 scf_transaction_destroy(handle->trans);
1354 if (ret == SA_OK)
1355 set_transaction_tstamp(sahandle);
1356 handle->trans = NULL;
1358 return (ret);
1362 * sa_abort_transaction(handle)
1364 * Abort the changes that were added to the transaction in the
1365 * handle. Do all necessary cleanup.
1368 void
1369 sa_abort_transaction(scfutilhandle_t *handle)
1371 if (handle->trans != NULL) {
1372 scf_transaction_reset_all(handle->trans);
1373 scf_transaction_destroy_children(handle->trans);
1374 scf_transaction_destroy(handle->trans);
1375 handle->trans = NULL;
1380 * set_transaction_tstamp(sahandle)
1382 * After a successful transaction commit, update the timestamp of the
1383 * last transaction. This lets us detect changes from other processes.
1385 static void
1386 set_transaction_tstamp(sa_handle_impl_t sahandle)
1388 char tstring[32];
1389 struct timeval tv;
1390 scfutilhandle_t *scfhandle;
1392 if (sahandle == NULL || sahandle->scfhandle == NULL)
1393 return;
1395 scfhandle = sahandle->scfhandle;
1397 if (sa_get_instance(scfhandle, "default") != SA_OK)
1398 return;
1400 if (gettimeofday(&tv, NULL) != 0)
1401 return;
1403 if (sa_start_transaction(scfhandle, "*state") != SA_OK)
1404 return;
1406 sahandle->tstrans = TSTAMP((*(timestruc_t *)&tv));
1407 (void) snprintf(tstring, sizeof (tstring), "%lld", sahandle->tstrans);
1408 if (sa_set_property(sahandle->scfhandle, "lastupdate", tstring) ==
1409 SA_OK) {
1411 * While best if it succeeds, a failure doesn't cause
1412 * problems and we will ignore it anyway.
1414 (void) scf_transaction_commit(scfhandle->trans);
1415 scf_transaction_destroy_children(scfhandle->trans);
1416 scf_transaction_destroy(scfhandle->trans);
1417 } else {
1418 sa_abort_transaction(scfhandle);
1423 * sa_set_property(handle, prop, value)
1425 * Set a property transaction entry into the pending SMF transaction.
1429 sa_set_property(scfutilhandle_t *handle, char *propname, char *valstr)
1431 int ret = SA_OK;
1432 scf_value_t *value;
1433 scf_transaction_entry_t *entry;
1435 * Properties must be set in transactions and don't take
1436 * effect until the transaction has been ended/committed.
1438 value = scf_value_create(handle->handle);
1439 entry = scf_entry_create(handle->handle);
1440 if (value != NULL && entry != NULL) {
1441 if (scf_transaction_property_change(handle->trans, entry,
1442 propname, SCF_TYPE_ASTRING) == 0 ||
1443 scf_transaction_property_new(handle->trans, entry,
1444 propname, SCF_TYPE_ASTRING) == 0) {
1445 if (scf_value_set_astring(value, valstr) == 0) {
1446 if (scf_entry_add_value(entry, value) != 0) {
1447 ret = SA_SYSTEM_ERR;
1448 scf_value_destroy(value);
1450 /* The value is in the transaction */
1451 value = NULL;
1452 } else {
1453 /* Value couldn't be constructed */
1454 ret = SA_SYSTEM_ERR;
1456 /* The entry is in the transaction */
1457 entry = NULL;
1458 } else {
1459 ret = SA_SYSTEM_ERR;
1461 } else {
1462 ret = SA_SYSTEM_ERR;
1464 if (ret == SA_SYSTEM_ERR) {
1465 switch (scf_error()) {
1466 case SCF_ERROR_PERMISSION_DENIED:
1467 ret = SA_NO_PERMISSION;
1468 break;
1472 * Cleanup if there were any errors that didn't leave these
1473 * values where they would be cleaned up later.
1475 if (value != NULL)
1476 scf_value_destroy(value);
1477 if (entry != NULL)
1478 scf_entry_destroy(entry);
1479 return (ret);
1483 * check_resource(share)
1485 * Check to see if share has any persistent resources. We don't want
1486 * to save if they are all transient.
1488 static int
1489 check_resource(sa_share_t share)
1491 sa_resource_t resource;
1492 int ret = B_FALSE;
1494 for (resource = sa_get_share_resource(share, NULL);
1495 resource != NULL && ret == B_FALSE;
1496 resource = sa_get_next_resource(resource)) {
1497 char *type;
1498 type = sa_get_resource_attr(resource, "type");
1499 if (type != NULL) {
1500 if (strcmp(type, "transient") != 0) {
1501 ret = B_TRUE;
1503 sa_free_attr_string(type);
1506 return (ret);
1510 * sa_set_resource_property(handle, prop, value)
1512 * set a property transaction entry into the pending SMF
1513 * transaction. We don't want to include any transient resources
1516 static int
1517 sa_set_resource_property(scfutilhandle_t *handle, sa_share_t share)
1519 int ret = SA_OK;
1520 scf_value_t *value;
1521 scf_transaction_entry_t *entry;
1522 sa_resource_t resource;
1523 char *valstr;
1524 char *idstr;
1525 char *description;
1526 char *propstr = NULL;
1527 size_t strsize;
1529 /* don't bother if no persistent resources */
1530 if (check_resource(share) == B_FALSE)
1531 return (ret);
1534 * properties must be set in transactions and don't take
1535 * effect until the transaction has been ended/committed.
1537 entry = scf_entry_create(handle->handle);
1538 if (entry == NULL)
1539 return (SA_SYSTEM_ERR);
1541 if (scf_transaction_property_change(handle->trans, entry,
1542 "resource", SCF_TYPE_ASTRING) != 0 &&
1543 scf_transaction_property_new(handle->trans, entry,
1544 "resource", SCF_TYPE_ASTRING) != 0) {
1545 scf_entry_destroy(entry);
1546 return (SA_SYSTEM_ERR);
1549 for (resource = sa_get_share_resource(share, NULL);
1550 resource != NULL;
1551 resource = sa_get_next_resource(resource)) {
1552 value = scf_value_create(handle->handle);
1553 if (value == NULL) {
1554 ret = SA_NO_MEMORY;
1555 break;
1557 /* Get size of complete string */
1558 valstr = sa_get_resource_attr(resource, "name");
1559 idstr = sa_get_resource_attr(resource, "id");
1560 description = sa_get_resource_description(resource);
1561 strsize = (valstr != NULL) ? strlen(valstr) : 0;
1562 strsize += (idstr != NULL) ? strlen(idstr) : 0;
1563 strsize += (description != NULL) ? strlen(description) : 0;
1564 if (strsize > 0) {
1565 strsize += 3; /* add nul and ':' */
1566 propstr = (char *)malloc(strsize);
1567 if (propstr == NULL) {
1568 scf_value_destroy(value);
1569 ret = SA_NO_MEMORY;
1570 goto err;
1572 if (idstr == NULL)
1573 (void) snprintf(propstr, strsize, "%s",
1574 valstr ? valstr : "");
1575 else
1576 (void) snprintf(propstr, strsize, "%s:%s:%s",
1577 idstr, valstr ? valstr : "",
1578 description ? description : "");
1579 if (scf_value_set_astring(value, propstr) != 0) {
1580 ret = SA_SYSTEM_ERR;
1581 free(propstr);
1582 scf_value_destroy(value);
1583 break;
1585 if (scf_entry_add_value(entry, value) != 0) {
1586 ret = SA_SYSTEM_ERR;
1587 free(propstr);
1588 scf_value_destroy(value);
1589 break;
1591 /* the value is in the transaction */
1592 value = NULL;
1593 free(propstr);
1595 err:
1596 if (valstr != NULL) {
1597 sa_free_attr_string(valstr);
1598 valstr = NULL;
1600 if (idstr != NULL) {
1601 sa_free_attr_string(idstr);
1602 idstr = NULL;
1604 if (description != NULL) {
1605 sa_free_share_description(description);
1606 description = NULL;
1609 /* the entry is in the transaction */
1610 entry = NULL;
1612 if (valstr != NULL)
1613 sa_free_attr_string(valstr);
1614 if (idstr != NULL)
1615 sa_free_attr_string(idstr);
1616 if (description != NULL)
1617 sa_free_share_description(description);
1619 if (ret == SA_SYSTEM_ERR) {
1620 switch (scf_error()) {
1621 case SCF_ERROR_PERMISSION_DENIED:
1622 ret = SA_NO_PERMISSION;
1623 break;
1627 * cleanup if there were any errors that didn't leave
1628 * these values where they would be cleaned up later.
1630 if (entry != NULL)
1631 scf_entry_destroy(entry);
1633 return (ret);
1637 * sa_commit_share(handle, group, share)
1639 * Commit this share to the repository.
1640 * properties are added if they exist but can be added later.
1641 * Need to add to dfstab and sharetab, if appropriate.
1644 sa_commit_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1646 int ret = SA_OK;
1647 char *groupname;
1648 char *name;
1649 char *description;
1650 char *sharename;
1651 ssize_t proplen;
1652 char *propstring;
1655 * Don't commit in the zfs group. We do commit legacy
1656 * (default) and all other groups/shares. ZFS is handled
1657 * through the ZFS configuration rather than SMF.
1660 groupname = sa_get_group_attr(group, "name");
1661 if (groupname != NULL) {
1662 if (strcmp(groupname, "zfs") == 0) {
1664 * Adding to the ZFS group will result in the sharenfs
1665 * property being set but we don't want to do anything
1666 * SMF related at this point.
1668 sa_free_attr_string(groupname);
1669 return (ret);
1673 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1674 propstring = malloc(proplen);
1675 if (propstring == NULL)
1676 ret = SA_NO_MEMORY;
1678 if (groupname != NULL && ret == SA_OK) {
1679 ret = sa_get_instance(handle, groupname);
1680 sa_free_attr_string(groupname);
1681 groupname = NULL;
1682 sharename = sa_get_share_attr(share, "id");
1683 if (sharename == NULL) {
1684 /* slipped by */
1685 char shname[SA_SHARE_UUID_BUFLEN];
1686 generate_unique_sharename(shname);
1687 (void) xmlSetProp((xmlNodePtr)share, (xmlChar *)"id",
1688 (xmlChar *)shname);
1689 sharename = strdup(shname);
1691 if (sharename != NULL) {
1692 sigset_t old, new;
1694 * Have a share name allocated so create a pgroup for
1695 * it. It may already exist, but that is OK. In order
1696 * to avoid creating a share pgroup that doesn't have
1697 * a path property, block signals around the critical
1698 * region of creating the share pgroup and props.
1700 (void) sigprocmask(SIG_BLOCK, NULL, &new);
1701 (void) sigaddset(&new, SIGHUP);
1702 (void) sigaddset(&new, SIGINT);
1703 (void) sigaddset(&new, SIGQUIT);
1704 (void) sigaddset(&new, SIGTSTP);
1705 (void) sigprocmask(SIG_SETMASK, &new, &old);
1707 ret = sa_create_pgroup(handle, sharename);
1708 if (ret == SA_OK) {
1710 * Now start the transaction for the
1711 * properties that define this share. They may
1712 * exist so attempt to update before create.
1714 ret = sa_start_transaction(handle, sharename);
1716 if (ret == SA_OK) {
1717 name = sa_get_share_attr(share, "path");
1718 if (name != NULL) {
1720 * There needs to be a path
1721 * for a share to exist.
1723 ret = sa_set_property(handle, "path",
1724 name);
1725 sa_free_attr_string(name);
1726 } else {
1727 ret = SA_NO_MEMORY;
1730 if (ret == SA_OK) {
1731 name = sa_get_share_attr(share, "drive-letter");
1732 if (name != NULL) {
1733 /* A drive letter may exist for SMB */
1734 ret = sa_set_property(handle,
1735 "drive-letter", name);
1736 sa_free_attr_string(name);
1739 if (ret == SA_OK) {
1740 name = sa_get_share_attr(share, "exclude");
1741 if (name != NULL) {
1743 * In special cases need to
1744 * exclude proto enable.
1746 ret = sa_set_property(handle,
1747 "exclude", name);
1748 sa_free_attr_string(name);
1751 if (ret == SA_OK) {
1753 * If there are resource names, bundle them up
1754 * and save appropriately.
1756 ret = sa_set_resource_property(handle, share);
1759 if (ret == SA_OK) {
1760 description = sa_get_share_description(share);
1761 if (description != NULL) {
1762 ret = sa_set_property(handle,
1763 "description",
1764 description);
1765 sa_free_share_description(description);
1768 /* Make sure we cleanup the transaction */
1769 if (ret == SA_OK) {
1770 sa_handle_impl_t sahandle;
1771 sahandle = (sa_handle_impl_t)
1772 sa_find_group_handle(group);
1773 if (sahandle != NULL)
1774 ret = sa_end_transaction(handle,
1775 sahandle);
1776 else
1777 ret = SA_SYSTEM_ERR;
1778 } else {
1779 sa_abort_transaction(handle);
1782 (void) sigprocmask(SIG_SETMASK, &old, NULL);
1784 free(sharename);
1787 if (ret == SA_SYSTEM_ERR) {
1788 int err = scf_error();
1789 if (err == SCF_ERROR_PERMISSION_DENIED)
1790 ret = SA_NO_PERMISSION;
1792 free(propstring);
1793 if (groupname != NULL)
1794 sa_free_attr_string(groupname);
1796 return (ret);
1800 * remove_resources(handle, share, shareid)
1802 * If the share has resources, remove all of them and their
1803 * optionsets.
1805 static int
1806 remove_resources(scfutilhandle_t *handle, sa_share_t share, char *shareid)
1808 sa_resource_t resource;
1809 sa_optionset_t opt;
1810 char *proto;
1811 char *id;
1812 ssize_t proplen;
1813 char *propstring;
1814 int ret = SA_OK;
1816 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1817 propstring = malloc(proplen);
1818 if (propstring == NULL)
1819 return (SA_NO_MEMORY);
1821 for (resource = sa_get_share_resource(share, NULL);
1822 resource != NULL; resource = sa_get_next_resource(resource)) {
1823 id = sa_get_resource_attr(resource, "id");
1824 if (id == NULL)
1825 continue;
1826 for (opt = sa_get_optionset(resource, NULL);
1827 opt != NULL; opt = sa_get_next_optionset(resource)) {
1828 proto = sa_get_optionset_attr(opt, "type");
1829 if (proto != NULL) {
1830 (void) snprintf(propstring, proplen,
1831 "%s_%s_%s", shareid, proto, id);
1832 ret = sa_delete_pgroup(handle, propstring);
1833 sa_free_attr_string(proto);
1836 sa_free_attr_string(id);
1838 free(propstring);
1839 return (ret);
1843 * sa_delete_share(handle, group, share)
1845 * Remove the specified share from the group (and service instance).
1849 sa_delete_share(scfutilhandle_t *handle, sa_group_t group, sa_share_t share)
1851 int ret = SA_OK;
1852 char *groupname = NULL;
1853 char *shareid = NULL;
1854 sa_optionset_t opt;
1855 sa_security_t sec;
1856 ssize_t proplen;
1857 char *propstring;
1859 proplen = get_scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
1860 propstring = malloc(proplen);
1861 if (propstring == NULL)
1862 ret = SA_NO_MEMORY;
1864 if (ret == SA_OK) {
1865 groupname = sa_get_group_attr(group, "name");
1866 shareid = sa_get_share_attr(share, "id");
1867 if (groupname == NULL || shareid == NULL) {
1868 ret = SA_CONFIG_ERR;
1869 goto out;
1871 ret = sa_get_instance(handle, groupname);
1872 if (ret == SA_OK) {
1873 /* If a share has resources, remove them */
1874 ret = remove_resources(handle, share, shareid);
1875 /* If a share has properties, remove them */
1876 ret = sa_delete_pgroup(handle, shareid);
1877 for (opt = sa_get_optionset(share, NULL);
1878 opt != NULL;
1879 opt = sa_get_next_optionset(opt)) {
1880 char *proto;
1881 proto = sa_get_optionset_attr(opt, "type");
1882 if (proto != NULL) {
1883 (void) snprintf(propstring,
1884 proplen, "%s_%s", shareid,
1885 proto);
1886 ret = sa_delete_pgroup(handle,
1887 propstring);
1888 sa_free_attr_string(proto);
1889 } else {
1890 ret = SA_NO_MEMORY;
1894 * If a share has security/negotiable
1895 * properties, remove them.
1897 for (sec = sa_get_security(share, NULL, NULL);
1898 sec != NULL;
1899 sec = sa_get_next_security(sec)) {
1900 char *proto;
1901 char *sectype;
1902 proto = sa_get_security_attr(sec, "type");
1903 sectype = sa_get_security_attr(sec, "sectype");
1904 if (proto != NULL && sectype != NULL) {
1905 (void) snprintf(propstring, proplen,
1906 "%s_%s_%s", shareid, proto,
1907 sectype);
1908 ret = sa_delete_pgroup(handle,
1909 propstring);
1910 } else {
1911 ret = SA_NO_MEMORY;
1913 if (proto != NULL)
1914 sa_free_attr_string(proto);
1915 if (sectype != NULL)
1916 sa_free_attr_string(sectype);
1920 out:
1921 if (groupname != NULL)
1922 sa_free_attr_string(groupname);
1923 if (shareid != NULL)
1924 sa_free_attr_string(shareid);
1925 free(propstring);
1927 return (ret);